Index: head/sys/mips/adm5120/adm5120_machdep.c =================================================================== --- head/sys/mips/adm5120/adm5120_machdep.c (revision 326258) +++ head/sys/mips/adm5120/adm5120_machdep.c (revision 326259) @@ -1,144 +1,146 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (C) 2007 by Oleksandr Tymoshenko. 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 ``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 HIS RELATIVES 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 MIND, 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 "opt_ddb.h" #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 #include #include #include #include #include extern int *edata; extern int *end; void platform_cpu_init() { /* Nothing special */ } static void mips_init(void) { int i; printf("entry: mips_init()\n"); bootverbose = 1; realmem = btoc(16 << 20); for (i = 0; i < 10; i++) { phys_avail[i] = 0; } /* phys_avail regions are in bytes */ phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end); phys_avail[1] = ctob(realmem); dump_avail[0] = phys_avail[0]; dump_avail[1] = phys_avail[1]; physmem = realmem; init_param1(); init_param2(physmem); mips_cpu_init(); pmap_bootstrap(); mips_proc0_init(); mutex_init(); kdb_init(); #ifdef KDB if (boothowto & RB_KDB) kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); #endif } void platform_reset(void) { __asm __volatile("li $25, 0xbfc00000"); __asm __volatile("j $25"); } void platform_start(__register_t a0 __unused, __register_t a1 __unused, __register_t a2 __unused, __register_t a3 __unused) { vm_offset_t kernend; uint64_t platform_counter_freq = 175 * 1000 * 1000; /* clear the BSS and SBSS segments */ kernend = (vm_offset_t)&end; memset(&edata, 0, kernend - (vm_offset_t)(&edata)); mips_postboot_fixup(); /* Initialize pcpu stuff */ mips_pcpu0_init(); cninit(); mips_init(); mips_timer_init_params(platform_counter_freq, 0); } Index: head/sys/mips/adm5120/adm5120reg.h =================================================================== --- head/sys/mips/adm5120/adm5120reg.h (revision 326258) +++ head/sys/mips/adm5120/adm5120reg.h (revision 326259) @@ -1,294 +1,296 @@ /* $NetBSD: adm5120reg.h,v 1.1 2007/03/20 08:52:03 dyoung Exp $ */ /*- + * SPDX-License-Identifier: BSD-3-Clause + * * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko. * 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. * 3. The names of the authors may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS * 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$ */ #ifndef _ADM5120REG_H_ #define _ADM5120REG_H_ /* Helpers from NetBSD */ /* __BIT(n): nth bit, where __BIT(0) == 0x1. */ #define __BIT(__n) \ (((__n) >= NBBY * sizeof(uintmax_t)) ? 0 : ((uintmax_t)1 << (__n))) /* __BITS(m, n): bits m through n, m < n. */ #define __BITS(__m, __n) \ ((__BIT(MAX((__m), (__n)) + 1) - 1) ^ (__BIT(MIN((__m), (__n))) - 1)) /* Last byte of physical address space. */ #define ADM5120_TOP 0x1fffffff #define ADM5120_BOTTOM 0x0 /* Flash addresses */ #define ADM5120_BASE_SRAM0 0x1fc00000 /* UARTs */ #define ADM5120_BASE_UART1 0x12800000 #define ADM5120_BASE_UART0 0x12600000 /* ICU */ #define ADM5120_BASE_ICU 0x12200000 #define ICU_STATUS_REG 0x00 #define ICU_RAW_STATUS_REG 0x04 #define ICU_ENABLE_REG 0x08 #define ICU_DISABLE_REG 0x0c #define ICU_SOFT_REG 0x10 #define ICU_MODE_REG 0x14 #define ICU_FIQ_STATUS_REG 0x18 #define ICU_TESTSRC_REG 0x1c #define ICU_SRCSEL_REG 0x20 #define ICU_LEVEL_REG 0x24 #define ICU_INT_MASK 0x3ff /* Switch */ #define ADM5120_BASE_SWITCH 0x12000000 #define SW_CODE_REG 0x00 #define CLKS_MASK 0x00300000 #define CLKS_175MHZ 0x00000000 #define CLKS_200MHZ 0x00100000 #define SW_SFTRES_REG 0x04 #define SW_MEMCONT_REG 0x1c #define SDRAM_SIZE_4MBYTES 0x0001 #define SDRAM_SIZE_8MBYTES 0x0002 #define SDRAM_SIZE_16MBYTES 0x0003 #define SDRAM_SIZE_64MBYTES 0x0004 #define SDRAM_SIZE_128MBYTES 0x0005 #define SDRAM_SIZE_MASK 0x0007 #define SRAM0_SIZE_SHIFT 8 #define SRAM1_SIZE_SHIFT 16 #define SRAM_MASK 0x0007 #define SRAM_SSIZE 0x40000 #define ADM5120_BASE_PCI_CONFDATA 0x115ffff8 #define ADM5120_BASE_PCI_CONFADDR 0x115ffff0 #define ADM5120_BASE_PCI_IO 0x11500000 #define ADM5120_BASE_PCI_MEM 0x11400000 #define ADM5120_BASE_USB 0x11200000 #define ADM5120_BASE_MPMC 0x11000000 #define ADM5120_BASE_EXTIO1 0x10e00000 #define ADM5120_BASE_EXTIO0 0x10c00000 #define ADM5120_BASE_RSVD0 0x10800000 #define ADM5120_BASE_SRAM1 0x10000000 #define _REG_READ(b, o) *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1((b) + (o))) #define SW_READ(o) _REG_READ(ADM5120_BASE_SWITCH, o) #define _REG_WRITE(b, o, v) (_REG_READ(b, o)) = (v) #define SW_WRITE(o, v) _REG_WRITE(ADM5120_BASE_SWITCH,o, v) /* USB */ /* Watchdog Timers: base address is switch controller */ #define ADM5120_WDOG0 0x00c0 #define ADM5120_WDOG1 0x00c4 #define ADM5120_WDOG0_WTTR __BIT(31) /* 0: do not reset, * 1: reset on wdog expiration */ #define ADM5120_WDOG1_WDE __BIT(31) /* 0: deactivate, * 1: drop all CPU-bound * packets, disable flow * control on all ports. */ #define ADM5120_WDOG_WTS_MASK __BITS(30, 16) /* Watchdog Timer Set: * timer expires when it * reaches WTS. Units of * 10ms. */ #define ADM5120_WDOG_RSVD __BIT(15) #define ADM5120_WDOG_WT_MASK __BITS(14, 0) /* Watchdog Timer: * counts up, write to clear. */ /* GPIO: base address is switch controller */ #define ADM5120_GPIO0 0x00b8 #define ADM5120_GPIO0_OV __BITS(31, 24) /* rw: output value */ #define ADM5120_GPIO0_OE __BITS(23, 16) /* rw: output enable, * bit[n] = 0 -> input * bit[n] = 1 -> output */ #define ADM5120_GPIO0_IV __BITS(15, 8) /* ro: input value */ #define ADM5120_GPIO0_RSVD __BITS(7, 0) /* rw: reserved */ #define ADM5120_GPIO2 0x00bc #define ADM5120_GPIO2_EW __BIT(6) /* 1: enable wait state pin, * pin GPIO[0], for GPIO[1] * or GPIO[3] Chip Select: * memory controller waits for * WAIT# inactive (high). */ #define ADM5120_GPIO2_CSX1 __BIT(5) /* 1: GPIO[3:4] act as * Chip Select for * External I/O 1 (CSX1) * and External Interrupt 1 * (INTX1), respectively. * 0: CSX1/INTX1 disabled */ #define ADM5120_GPIO2_CSX0 __BIT(4) /* 1: GPIO[1:2] act as * Chip Select for * External I/O 0 (CSX0) * and External Interrupt 0 * (INTX0), respectively. * 0: CSX0/INTX0 disabled */ /* MultiPort Memory Controller (MPMC) */ #define ADM5120_MPMC_CONTROL 0x000 #define ADM5120_MPMC_CONTROL_DWB __BIT(3) /* write 1 to * drain write * buffers. write 0 * for normal buffer * operation. */ #define ADM5120_MPMC_CONTROL_LPM __BIT(2) /* 1: activate low-power * mode. SDRAM is * still refreshed. */ #define ADM5120_MPMC_CONTROL_AM __BIT(1) /* 1: address mirror: * static memory * chip select 0 * is mapped to chip * select 1. */ #define ADM5120_MPMC_CONTROL_ME __BIT(0) /* 0: disable MPMC. * DRAM is not * refreshed. * 1: enable MPMC. */ #define ADM5120_MPMC_STATUS 0x004 #define ADM5120_MPMC_STATUS_SRA __BIT(2) /* read-only * MPMC operating mode * indication, * 1: self-refresh * acknowledge * 0: normal mode */ #define ADM5120_MPMC_STATUS_WBS __BIT(1) /* read-only * write-buffer status, * 0: buffers empty * 1: contain data */ #define ADM5120_MPMC_STATUS_BU __BIT(0) /* read-only MPMC * "busy" indication, * 0: MPMC idle * 1: MPMC is performing * memory transactions */ #define ADM5120_MPMC_SEW 0x080 #define ADM5120_MPMC_SEW_RSVD __BITS(31, 10) #define ADM5120_MPMC_SEW_EWTO __BITS(9, 0) /* timeout access after * 16 * (n + 1) clock cycles * (XXX which clock?) */ #define ADM5120_MPMC_SC(__i) (0x200 + 0x020 * (__i)) #define ADM5120_MPMC_SC_RSVD0 __BITS(31, 21) #define ADM5120_MPMC_SC_WP __BIT(20) /* 1: write protect */ #define ADM5120_MPMC_SC_BE __BIT(20) /* 1: enable write buffer */ #define ADM5120_MPMC_SC_RSVD1 __BITS(18, 9) #define ADM5120_MPMC_SC_EW __BIT(8) /* 1: enable extended wait; */ #define ADM5120_MPMC_SC_BLS __BIT(7) /* 0: byte line state pins * are active high on read, * active low on write. * * 1: byte line state pins * are active low on read and * on write. */ #define ADM5120_MPMC_SC_CCP __BIT(6) /* 0: chip select is active low, * 1: active high */ #define ADM5120_MPMC_SC_RSVD2 __BITS(5, 4) #define ADM5120_MPMC_SC_PM __BIT(3) /* 0: page mode disabled, * 1: enable asynchronous * page mode four */ #define ADM5120_MPMC_SC_RSVD3 __BIT(2) #define ADM5120_MPMC_SC_MW_MASK __BITS(1, 0) /* memory width, bits */ #define ADM5120_MPMC_SC_MW_8B __SHIFTIN(0, ADM5120_MPMC_SC_MW_MASK) #define ADM5120_MPMC_SC_MW_16B __SHIFTIN(1, ADM5120_MPMC_SC_MW_MASK) #define ADM5120_MPMC_SC_MW_32B __SHIFTIN(2, ADM5120_MPMC_SC_MW_MASK) #define ADM5120_MPMC_SC_MW_RSVD __SHIFTIN(3, ADM5120_MPMC_SC_MW_MASK) #define ADM5120_MPMC_SWW(__i) (0x204 + 0x020 * (__i)) #define ADM5120_MPMC_SWW_RSVD __BITS(31, 4) #define ADM5120_MPMC_SWW_WWE __BITS(3, 0) /* delay (n + 1) * HCLK cycles * after asserting chip select * (CS) before asserting write * enable (WE) */ #define ADM5120_MPMC_SWO(__i) (0x208 + 0x020 * (__i)) #define ADM5120_MPMC_SWO_RSVD __BITS(31, 4) #define ADM5120_MPMC_SWO_WOE __BITS(3, 0) /* delay n * HCLK cycles * after asserting chip select * before asserting output * enable (OE) */ #define ADM5120_MPMC_SWR(__i) (0x20c + 0x020 * (__i)) #define ADM5120_MPMC_SWR_RSVD __BITS(31, 5) #define ADM5120_MPMC_SWR_NMRW __BITS(4, 0) /* read wait states for * either first page-mode * access or for non-page mode * read, (n + 1) * HCLK cycles */ #define ADM5120_MPMC_SWP(__i) (0x210 + 0x020 * (__i)) #define ADM5120_MPMC_SWP_RSVD __BITS(31, 5) #define ADM5120_MPMC_SWP_WPS __BITS(4, 0) /* read wait states for * second and subsequent * page-mode read, * (n + 1) * HCLK cycles */ #define ADM5120_MPMC_SWWR(__i) (0x214 + 0x020 * (__i)) #define ADM5120_MPMC_SWWR_RSVD __BITS(31, 5) #define ADM5120_MPMC_SWWR_WWS __BITS(4, 0) /* write wait states after * the first read (??), * (n + 2) * HCLK cycles */ #define ADM5120_MPMC_SWT(__i) (0x218 + 0x020 * (__i)) #define ADM5120_MPMC_SWT_RSVD __BITS(31, 4) #define ADM5120_MPMC_SWT_WAITTURN __BITS(3, 0) /* bus turnaround time, * (n + 1) * HCLK cycles */ #endif /* _ADM5120REG_H_ */ Index: head/sys/mips/adm5120/admpci.c =================================================================== --- head/sys/mips/adm5120/admpci.c (revision 326258) +++ head/sys/mips/adm5120/admpci.c (revision 326259) @@ -1,502 +1,504 @@ /* $NetBSD: admpci.c,v 1.1 2007/03/20 08:52:02 dyoung Exp $ */ /*- + * SPDX-License-Identifier: BSD-3-Clause + * * Copyright (c) 2007 David Young. 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. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 * 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. */ /*- * Copyright (c) 2006 Itronix Inc. * All rights reserved. * * Written by Garrett D'Amore for Itronix Inc. * * 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. * 3. The name of Itronix Inc. may not be used to endorse * or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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 "pcib_if.h" #include #ifdef ADMPCI_DEBUG int admpci_debug = 1; #define ADMPCI_DPRINTF(__fmt, ...) \ do { \ if (admpci_debug) \ printf((__fmt), __VA_ARGS__); \ } while (/*CONSTCOND*/0) #else /* !ADMPCI_DEBUG */ #define ADMPCI_DPRINTF(__fmt, ...) do { } while (/*CONSTCOND*/0) #endif /* ADMPCI_DEBUG */ #define ADMPCI_TAG_BUS_MASK __BITS(23, 16) /* Bit 11 is reserved. It selects the AHB-PCI bridge. Let device 0 * be the bridge. For all other device numbers, let bit[11] == 0. */ #define ADMPCI_TAG_DEVICE_MASK __BITS(15, 11) #define ADMPCI_TAG_DEVICE_SUBMASK __BITS(15, 12) #define ADMPCI_TAG_DEVICE_BRIDGE __BIT(11) #define ADMPCI_TAG_FUNCTION_MASK __BITS(10, 8) #define ADMPCI_TAG_REGISTER_MASK __BITS(7, 0) #define ADMPCI_MAX_DEVICE struct admpci_softc { device_t sc_dev; bus_space_tag_t sc_st; /* Access to PCI config registers */ bus_space_handle_t sc_addrh; bus_space_handle_t sc_datah; int sc_busno; struct rman sc_mem_rman; struct rman sc_io_rman; struct rman sc_irq_rman; uint32_t sc_mem; uint32_t sc_io; }; static int admpci_probe(device_t dev) { return (0); } static int admpci_attach(device_t dev) { int busno = 0; struct admpci_softc *sc = device_get_softc(dev); sc->sc_dev = dev; sc->sc_busno = busno; /* Use KSEG1 to access IO ports for it is uncached */ sc->sc_io = MIPS_PHYS_TO_KSEG1(ADM5120_BASE_PCI_IO); sc->sc_io_rman.rm_type = RMAN_ARRAY; sc->sc_io_rman.rm_descr = "ADMPCI I/O Ports"; if (rman_init(&sc->sc_io_rman) != 0 || rman_manage_region(&sc->sc_io_rman, 0, 0xffff) != 0) { panic("admpci_attach: failed to set up I/O rman"); } /* Use KSEG1 to access PCI memory for it is uncached */ sc->sc_mem = MIPS_PHYS_TO_KSEG1(ADM5120_BASE_PCI_MEM); sc->sc_mem_rman.rm_type = RMAN_ARRAY; sc->sc_mem_rman.rm_descr = "ADMPCI PCI Memory"; if (rman_init(&sc->sc_mem_rman) != 0 || rman_manage_region(&sc->sc_mem_rman, sc->sc_mem, sc->sc_mem + 0x100000) != 0) { panic("admpci_attach: failed to set up memory rman"); } sc->sc_irq_rman.rm_type = RMAN_ARRAY; sc->sc_irq_rman.rm_descr = "ADMPCI PCI IRQs"; if (rman_init(&sc->sc_irq_rman) != 0 || rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0) panic("admpci_attach: failed to set up IRQ rman"); if (bus_space_map(sc->sc_st, ADM5120_BASE_PCI_CONFADDR, 4, 0, &sc->sc_addrh) != 0) { device_printf(sc->sc_dev, "unable to address space\n"); panic("bus_space_map failed"); } if (bus_space_map(sc->sc_st, ADM5120_BASE_PCI_CONFDATA, 4, 0, &sc->sc_datah) != 0) { device_printf(sc->sc_dev, "unable to address space\n"); panic("bus_space_map failed"); } device_add_child(dev, "pci", -1); return (bus_generic_attach(dev)); } static int admpci_maxslots(device_t dev) { return (PCI_SLOTMAX); } static uint32_t admpci_make_addr(int bus, int slot, int func, int reg) { return (0x80000000 | (bus << 16) | (slot << 11) | (func << 8) | reg); } static uint32_t admpci_read_config(device_t dev, int bus, int slot, int func, int reg, int bytes) { struct admpci_softc *sc = device_get_softc(dev); uint32_t data; uint32_t shift, mask; bus_addr_t addr; ADMPCI_DPRINTF("%s: sc %p tag (%x, %x, %x) reg %d\n", __func__, (void *)sc, bus, slot, func, reg); addr = admpci_make_addr(bus, slot, func, reg); ADMPCI_DPRINTF("%s: sc_addrh %p sc_datah %p addr %p\n", __func__, (void *)sc->sc_addrh, (void *)sc->sc_datah, (void *)addr); bus_space_write_4(sc->sc_io, sc->sc_addrh, 0, addr); data = bus_space_read_4(sc->sc_io, sc->sc_datah, 0); switch (reg % 4) { case 3: shift = 24; break; case 2: shift = 16; break; case 1: shift = 8; break; default: shift = 0; break; } switch (bytes) { case 1: mask = 0xff; data = (data >> shift) & mask; break; case 2: mask = 0xffff; if (reg % 4 == 0) data = data & mask; else data = (data >> 16) & mask; break; case 4: break; default: panic("%s: wrong bytes count", __func__); break; } ADMPCI_DPRINTF("%s: read 0x%x\n", __func__, data); return (data); } static void admpci_write_config(device_t dev, int bus, int slot, int func, int reg, uint32_t data, int bytes) { struct admpci_softc *sc = device_get_softc(dev); bus_addr_t addr; uint32_t reg_data; uint32_t shift, mask; ADMPCI_DPRINTF("%s: sc %p tag (%x, %x, %x) reg %d\n", __func__, (void *)sc, bus, slot, func, reg); if (bytes != 4) { reg_data = admpci_read_config(dev, bus, slot, func, reg, 4); switch (reg % 4) { case 3: shift = 24; break; case 2: shift = 16; break; case 1: shift = 8; break; default: shift = 0; break; } switch (bytes) { case 1: mask = 0xff; data = (reg_data & ~ (mask << shift)) | (data << shift); break; case 2: mask = 0xffff; if (reg % 4 == 0) data = (reg_data & ~mask) | data; else data = (reg_data & ~ (mask << shift)) | (data << shift); break; case 4: break; default: panic("%s: wrong bytes count", __func__); break; } } addr = admpci_make_addr(bus, slot, func, reg); ADMPCI_DPRINTF("%s: sc_addrh %p sc_datah %p addr %p\n", __func__, (void *)sc->sc_addrh, (void *)sc->sc_datah, (void *)addr); bus_space_write_4(sc->sc_io, sc->sc_addrh, 0, addr); bus_space_write_4(sc->sc_io, sc->sc_datah, 0, data); } static int admpci_route_interrupt(device_t pcib, device_t dev, int pin) { /* TODO: implement */ return (0); } static int admpci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { struct admpci_softc *sc = device_get_softc(dev); switch (which) { case PCIB_IVAR_DOMAIN: *result = 0; return (0); case PCIB_IVAR_BUS: *result = sc->sc_busno; return (0); } return (ENOENT); } static int admpci_write_ivar(device_t dev, device_t child, int which, uintptr_t result) { struct admpci_softc * sc = device_get_softc(dev); switch (which) { case PCIB_IVAR_BUS: sc->sc_busno = result; return (0); } return (ENOENT); } static struct resource * admpci_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { return (NULL); #if 0 struct admpci_softc *sc = device_get_softc(bus); struct resource *rv = NULL; struct rman *rm; bus_space_handle_t bh = 0; switch (type) { case SYS_RES_IRQ: rm = &sc->sc_irq_rman; break; case SYS_RES_MEMORY: rm = &sc->sc_mem_rman; bh = sc->sc_mem; break; case SYS_RES_IOPORT: rm = &sc->sc_io_rman; bh = sc->sc_io; break; default: return (NULL); } rv = rman_reserve_resource(rm, start, end, count, flags, child); if (rv == NULL) return (NULL); rman_set_rid(rv, *rid); if (type != SYS_RES_IRQ) { bh += (rman_get_start(rv)); rman_set_bustag(rv, sc->sc_st); rman_set_bushandle(rv, bh); if (flags & RF_ACTIVE) { if (bus_activate_resource(child, type, *rid, rv)) { rman_release_resource(rv); return (NULL); } } } return (rv); #endif } static int admpci_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { bus_space_handle_t p; int error; if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) { error = bus_space_map(rman_get_bustag(r), rman_get_bushandle(r), rman_get_size(r), 0, &p); if (error) return (error); rman_set_bushandle(r, p); } return (rman_activate_resource(r)); } static int admpci_setup_intr(device_t dev, device_t child, struct resource *ires, int flags, driver_filter_t *filt, driver_intr_t *handler, void *arg, void **cookiep) { #if 0 struct admpci_softc *sc = device_get_softc(dev); struct intr_event *event; int irq, error; irq = rman_get_start(ires); if (irq >= ICU_LEN || irq == 2) panic("%s: bad irq or type", __func__); event = sc->sc_eventstab[irq]; if (event == NULL) { error = intr_event_create(&event, (void *)irq, 0, (void (*)(void *))NULL, "admpci intr%d:", irq); if (error) return 0; sc->sc_eventstab[irq] = event; } intr_event_add_handler(event, device_get_nameunit(child), filt, handler, arg, intr_priority(flags), flags, cookiep); /* Enable it, set trigger mode. */ sc->sc_imask &= ~(1 << irq); sc->sc_elcr &= ~(1 << irq); admpci_set_icus(sc); #endif return (0); } static int admpci_teardown_intr(device_t dev, device_t child, struct resource *res, void *cookie) { return (intr_event_remove_handler(cookie)); } static device_method_t admpci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, admpci_probe), DEVMETHOD(device_attach, admpci_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_read_ivar, admpci_read_ivar), DEVMETHOD(bus_write_ivar, admpci_write_ivar), DEVMETHOD(bus_alloc_resource, admpci_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, admpci_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, admpci_setup_intr), DEVMETHOD(bus_teardown_intr, admpci_teardown_intr), /* pcib interface */ DEVMETHOD(pcib_maxslots, admpci_maxslots), DEVMETHOD(pcib_read_config, admpci_read_config), DEVMETHOD(pcib_write_config, admpci_write_config), DEVMETHOD(pcib_route_interrupt, admpci_route_interrupt), DEVMETHOD(pcib_request_feature, pcib_request_feature_allow), DEVMETHOD_END }; static driver_t admpci_driver = { "pcib", admpci_methods, sizeof(struct admpci_softc), }; static devclass_t admpci_devclass; DRIVER_MODULE(admpci, obio, admpci_driver, admpci_devclass, 0, 0); Index: head/sys/mips/adm5120/console.c =================================================================== --- head/sys/mips/adm5120/console.c (revision 326258) +++ head/sys/mips/adm5120/console.c (revision 326259) @@ -1,107 +1,109 @@ /* $NetBSD: uart.c,v 1.2 2007/03/23 20:05:47 dogcow Exp $ */ /*- + * SPDX-License-Identifier: BSD-3-Clause + * * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko. * 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. * 3. The names of the authors may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS * 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 static cn_probe_t uart_cnprobe; static cn_init_t uart_cninit; static cn_term_t uart_cnterm; static cn_getc_t uart_cngetc; static cn_putc_t uart_cnputc; static cn_grab_t uart_cngrab; static cn_ungrab_t uart_cnungrab; static void uart_cnprobe(struct consdev *cp) { sprintf(cp->cn_name, "uart"); cp->cn_pri = CN_NORMAL; } static void uart_cninit(struct consdev *cp) { } void uart_cnputc(struct consdev *cp, int c) { char chr; chr = c; while ((*((volatile unsigned long *)0xb2600018)) & 0x20) ; (*((volatile unsigned long *)0xb2600000)) = c; while ((*((volatile unsigned long *)0xb2600018)) & 0x20) ; } int uart_cngetc(struct consdev * cp) { while ((*((volatile unsigned long *)0xb2600018)) & 0x10) ; return (*((volatile unsigned long *)0xb2600000)) & 0xff; } static void uart_cnterm(struct consdev * cp) { } static void uart_cngrab(struct consdev *cp) { } static void uart_cnungrab(struct consdev *cp) { } CONSOLE_DRIVER(uart); Index: head/sys/mips/adm5120/if_admsw.c =================================================================== --- head/sys/mips/adm5120/if_admsw.c (revision 326258) +++ head/sys/mips/adm5120/if_admsw.c (revision 326259) @@ -1,1352 +1,1354 @@ /* $NetBSD: if_admsw.c,v 1.3 2007/04/22 19:26:25 dyoung Exp $ */ /*- + * SPDX-License-Identifier: BSD-3-Clause + * * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko. * 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. * 3. The names of the authors may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS * 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. */ /* * Copyright (c) 2001 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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. */ /* * Device driver for Alchemy Semiconductor Au1x00 Ethernet Media * Access Controller. * * TODO: * * Better Rx buffer management; we want to get new Rx buffers * to the chip more quickly than we currently do. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef INET #include #include #include #include #endif #include #include #include #include #include /* TODO: add locking */ #define ADMSW_LOCK(sc) do {} while(0); #define ADMSW_UNLOCK(sc) do {} while(0); static uint8_t vlan_matrix[SW_DEVS] = { (1 << 6) | (1 << 0), /* CPU + port0 */ (1 << 6) | (1 << 1), /* CPU + port1 */ (1 << 6) | (1 << 2), /* CPU + port2 */ (1 << 6) | (1 << 3), /* CPU + port3 */ (1 << 6) | (1 << 4), /* CPU + port4 */ (1 << 6) | (1 << 5), /* CPU + port5 */ }; /* ifnet entry points */ static void admsw_start(struct ifnet *); static void admsw_watchdog(void *); static int admsw_ioctl(struct ifnet *, u_long, caddr_t); static void admsw_init(void *); static void admsw_stop(struct ifnet *, int); static void admsw_reset(struct admsw_softc *); static void admsw_set_filter(struct admsw_softc *); static void admsw_txintr(struct admsw_softc *, int); static void admsw_rxintr(struct admsw_softc *, int); static int admsw_add_rxbuf(struct admsw_softc *, int, int); #define admsw_add_rxhbuf(sc, idx) admsw_add_rxbuf(sc, idx, 1) #define admsw_add_rxlbuf(sc, idx) admsw_add_rxbuf(sc, idx, 0) static int admsw_mediachange(struct ifnet *); static void admsw_mediastatus(struct ifnet *, struct ifmediareq *); static int admsw_intr(void *); /* bus entry points */ static int admsw_probe(device_t dev); static int admsw_attach(device_t dev); static int admsw_detach(device_t dev); static int admsw_shutdown(device_t dev); static void admsw_dma_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) { uint32_t *addr; if (error) return; KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); addr = arg; *addr = segs->ds_addr; } static void admsw_rxbuf_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, int error) { struct admsw_descsoft *ds; if (error) return; KASSERT(nseg == 1, ("too many DMA segments, %d should be 1", nseg)); ds = arg; ds->ds_nsegs = nseg; ds->ds_addr[0] = segs[0].ds_addr; ds->ds_len[0] = segs[0].ds_len; } static void admsw_mbuf_map_addr(void *arg, bus_dma_segment_t *segs, int nseg, bus_size_t mapsize, int error) { struct admsw_descsoft *ds; if (error) return; ds = arg; if((nseg != 1) && (nseg != 2)) panic("%s: nseg == %d\n", __func__, nseg); ds->ds_nsegs = nseg; ds->ds_addr[0] = segs[0].ds_addr; ds->ds_len[0] = segs[0].ds_len; if(nseg > 1) { ds->ds_addr[1] = segs[1].ds_addr; ds->ds_len[1] = segs[1].ds_len; } } static int admsw_probe(device_t dev) { device_set_desc(dev, "ADM5120 Switch Engine"); return (0); } #define REG_READ(o) bus_read_4((sc)->mem_res, (o)) #define REG_WRITE(o,v) bus_write_4((sc)->mem_res, (o),(v)) static void admsw_init_bufs(struct admsw_softc *sc) { int i; struct admsw_desc *desc; for (i = 0; i < ADMSW_NTXHDESC; i++) { if (sc->sc_txhsoft[i].ds_mbuf != NULL) { m_freem(sc->sc_txhsoft[i].ds_mbuf); sc->sc_txhsoft[i].ds_mbuf = NULL; } desc = &sc->sc_txhdescs[i]; desc->data = 0; desc->cntl = 0; desc->len = MAC_BUFLEN; desc->status = 0; ADMSW_CDTXHSYNC(sc, i, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); } sc->sc_txhdescs[ADMSW_NTXHDESC - 1].data |= ADM5120_DMA_RINGEND; ADMSW_CDTXHSYNC(sc, ADMSW_NTXHDESC - 1, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); for (i = 0; i < ADMSW_NRXHDESC; i++) { if (sc->sc_rxhsoft[i].ds_mbuf == NULL) { if (admsw_add_rxhbuf(sc, i) != 0) panic("admsw_init_bufs\n"); } else ADMSW_INIT_RXHDESC(sc, i); } for (i = 0; i < ADMSW_NTXLDESC; i++) { if (sc->sc_txlsoft[i].ds_mbuf != NULL) { m_freem(sc->sc_txlsoft[i].ds_mbuf); sc->sc_txlsoft[i].ds_mbuf = NULL; } desc = &sc->sc_txldescs[i]; desc->data = 0; desc->cntl = 0; desc->len = MAC_BUFLEN; desc->status = 0; ADMSW_CDTXLSYNC(sc, i, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); } sc->sc_txldescs[ADMSW_NTXLDESC - 1].data |= ADM5120_DMA_RINGEND; ADMSW_CDTXLSYNC(sc, ADMSW_NTXLDESC - 1, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); for (i = 0; i < ADMSW_NRXLDESC; i++) { if (sc->sc_rxlsoft[i].ds_mbuf == NULL) { if (admsw_add_rxlbuf(sc, i) != 0) panic("admsw_init_bufs\n"); } else ADMSW_INIT_RXLDESC(sc, i); } REG_WRITE(SEND_HBADDR_REG, ADMSW_CDTXHADDR(sc, 0)); REG_WRITE(SEND_LBADDR_REG, ADMSW_CDTXLADDR(sc, 0)); REG_WRITE(RECV_HBADDR_REG, ADMSW_CDRXHADDR(sc, 0)); REG_WRITE(RECV_LBADDR_REG, ADMSW_CDRXLADDR(sc, 0)); sc->sc_txfree = ADMSW_NTXLDESC; sc->sc_txnext = 0; sc->sc_txdirty = 0; sc->sc_rxptr = 0; } static void admsw_setvlan(struct admsw_softc *sc, char matrix[6]) { uint32_t i; i = matrix[0] + (matrix[1] << 8) + (matrix[2] << 16) + (matrix[3] << 24); REG_WRITE(VLAN_G1_REG, i); i = matrix[4] + (matrix[5] << 8); REG_WRITE(VLAN_G2_REG, i); } static void admsw_reset(struct admsw_softc *sc) { uint32_t wdog1; int i; REG_WRITE(PORT_CONF0_REG, REG_READ(PORT_CONF0_REG) | PORT_CONF0_DP_MASK); REG_WRITE(CPUP_CONF_REG, REG_READ(CPUP_CONF_REG) | CPUP_CONF_DCPUP); /* Wait for DMA to complete. Overkill. In 3ms, we can * send at least two entire 1500-byte packets at 10 Mb/s. */ DELAY(3000); /* The datasheet recommends that we move all PHYs to reset * state prior to software reset. */ REG_WRITE(PHY_CNTL2_REG, REG_READ(PHY_CNTL2_REG) & ~PHY_CNTL2_PHYR_MASK); /* Reset the switch. */ REG_WRITE(ADMSW_SW_RES, 0x1); DELAY(100 * 1000); REG_WRITE(ADMSW_BOOT_DONE, ADMSW_BOOT_DONE_BO); /* begin old code */ REG_WRITE(CPUP_CONF_REG, CPUP_CONF_DCPUP | CPUP_CONF_CRCP | CPUP_CONF_DUNP_MASK | CPUP_CONF_DMCP_MASK); REG_WRITE(PORT_CONF0_REG, PORT_CONF0_EMCP_MASK | PORT_CONF0_EMBP_MASK); REG_WRITE(PHY_CNTL2_REG, REG_READ(PHY_CNTL2_REG) | PHY_CNTL2_ANE_MASK | PHY_CNTL2_PHYR_MASK | PHY_CNTL2_AMDIX_MASK); REG_WRITE(PHY_CNTL3_REG, REG_READ(PHY_CNTL3_REG) | PHY_CNTL3_RNT); REG_WRITE(ADMSW_INT_MASK, INT_MASK); REG_WRITE(ADMSW_INT_ST, INT_MASK); /* * While in DDB, we stop servicing interrupts, RX ring * fills up and when free block counter falls behind FC * threshold, the switch starts to emit 802.3x PAUSE * frames. This can upset peer switches. * * Stop this from happening by disabling FC and D2 * thresholds. */ REG_WRITE(FC_TH_REG, REG_READ(FC_TH_REG) & ~(FC_TH_FCS_MASK | FC_TH_D2S_MASK)); admsw_setvlan(sc, vlan_matrix); for (i = 0; i < SW_DEVS; i++) { REG_WRITE(MAC_WT1_REG, sc->sc_enaddr[2] | (sc->sc_enaddr[3]<<8) | (sc->sc_enaddr[4]<<16) | ((sc->sc_enaddr[5]+i)<<24)); REG_WRITE(MAC_WT0_REG, (i<sc_enaddr[0]<<16) | (sc->sc_enaddr[1]<<24) | MAC_WT0_WRITE | MAC_WT0_VLANID_EN); while (!(REG_READ(MAC_WT0_REG) & MAC_WT0_WRITE_DONE)); } wdog1 = REG_READ(ADM5120_WDOG1); REG_WRITE(ADM5120_WDOG1, wdog1 & ~ADM5120_WDOG1_WDE); } static int admsw_attach(device_t dev) { uint8_t enaddr[ETHER_ADDR_LEN]; struct admsw_softc *sc = (struct admsw_softc *) device_get_softc(dev); struct ifnet *ifp; int error, i, rid; sc->sc_dev = dev; device_printf(dev, "ADM5120 Switch Engine, %d ports\n", SW_DEVS); sc->ndevs = 0; /* XXXMIPS: fix it */ enaddr[0] = 0x00; enaddr[1] = 0x0C; enaddr[2] = 0x42; enaddr[3] = 0x07; enaddr[4] = 0xB2; enaddr[5] = 0x4E; memcpy(sc->sc_enaddr, enaddr, sizeof(sc->sc_enaddr)); device_printf(sc->sc_dev, "base Ethernet address %s\n", ether_sprintf(enaddr)); callout_init(&sc->sc_watchdog, 1); rid = 0; if ((sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE)) == NULL) { device_printf(dev, "unable to allocate memory resource\n"); return (ENXIO); } /* Hook up the interrupt handler. */ rid = 0; if ((sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { device_printf(dev, "unable to allocate IRQ resource\n"); return (ENXIO); } if ((error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET, admsw_intr, NULL, sc, &sc->sc_ih)) != 0) { device_printf(dev, "WARNING: unable to register interrupt handler\n"); return (error); } /* * Allocate the control data structures, and create and load the * DMA map for it. */ if ((error = bus_dma_tag_create(NULL, 4, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, sizeof(struct admsw_control_data), 1, sizeof(struct admsw_control_data), 0, NULL, NULL, &sc->sc_control_dmat)) != 0) { device_printf(sc->sc_dev, "unable to create control data DMA map, error = %d\n", error); return (error); } if ((error = bus_dmamem_alloc(sc->sc_control_dmat, (void **)&sc->sc_control_data, BUS_DMA_NOWAIT, &sc->sc_cddmamap)) != 0) { device_printf(sc->sc_dev, "unable to allocate control data, error = %d\n", error); return (error); } if ((error = bus_dmamap_load(sc->sc_control_dmat, sc->sc_cddmamap, sc->sc_control_data, sizeof(struct admsw_control_data), admsw_dma_map_addr, &sc->sc_cddma, 0)) != 0) { device_printf(sc->sc_dev, "unable to load control data DMA map, error = %d\n", error); return (error); } /* * Create the transmit buffer DMA maps. */ if ((error = bus_dma_tag_create(NULL, 1, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MCLBYTES, 1, MCLBYTES, 0, NULL, NULL, &sc->sc_bufs_dmat)) != 0) { device_printf(sc->sc_dev, "unable to create control data DMA map, error = %d\n", error); return (error); } for (i = 0; i < ADMSW_NTXHDESC; i++) { if ((error = bus_dmamap_create(sc->sc_bufs_dmat, 0, &sc->sc_txhsoft[i].ds_dmamap)) != 0) { device_printf(sc->sc_dev, "unable to create txh DMA map %d, error = %d\n", i, error); return (error); } sc->sc_txhsoft[i].ds_mbuf = NULL; } for (i = 0; i < ADMSW_NTXLDESC; i++) { if ((error = bus_dmamap_create(sc->sc_bufs_dmat, 0, &sc->sc_txlsoft[i].ds_dmamap)) != 0) { device_printf(sc->sc_dev, "unable to create txl DMA map %d, error = %d\n", i, error); return (error); } sc->sc_txlsoft[i].ds_mbuf = NULL; } /* * Create the receive buffer DMA maps. */ for (i = 0; i < ADMSW_NRXHDESC; i++) { if ((error = bus_dmamap_create(sc->sc_bufs_dmat, 0, &sc->sc_rxhsoft[i].ds_dmamap)) != 0) { device_printf(sc->sc_dev, "unable to create rxh DMA map %d, error = %d\n", i, error); return (error); } sc->sc_rxhsoft[i].ds_mbuf = NULL; } for (i = 0; i < ADMSW_NRXLDESC; i++) { if ((error = bus_dmamap_create(sc->sc_bufs_dmat, 0, &sc->sc_rxlsoft[i].ds_dmamap)) != 0) { device_printf(sc->sc_dev, "unable to create rxl DMA map %d, error = %d\n", i, error); return (error); } sc->sc_rxlsoft[i].ds_mbuf = NULL; } admsw_init_bufs(sc); admsw_reset(sc); for (i = 0; i < SW_DEVS; i++) { ifmedia_init(&sc->sc_ifmedia[i], 0, admsw_mediachange, admsw_mediastatus); ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_10_T, 0, NULL); ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_10_T|IFM_FDX, 0, NULL); ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_100_TX, 0, NULL); ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_100_TX|IFM_FDX, 0, NULL); ifmedia_add(&sc->sc_ifmedia[i], IFM_ETHER|IFM_AUTO, 0, NULL); ifmedia_set(&sc->sc_ifmedia[i], IFM_ETHER|IFM_AUTO); ifp = sc->sc_ifnet[i] = if_alloc(IFT_ETHER); /* Setup interface parameters */ ifp->if_softc = sc; if_initname(ifp, device_get_name(dev), i); ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = admsw_ioctl; ifp->if_output = ether_output; ifp->if_start = admsw_start; ifp->if_init = admsw_init; ifp->if_mtu = ETHERMTU; ifp->if_baudrate = IF_Mbps(100); IFQ_SET_MAXLEN(&ifp->if_snd, max(ADMSW_NTXLDESC, ifqmaxlen)); ifp->if_snd.ifq_drv_maxlen = max(ADMSW_NTXLDESC, ifqmaxlen); IFQ_SET_READY(&ifp->if_snd); ifp->if_capabilities |= IFCAP_VLAN_MTU; /* Attach the interface. */ ether_ifattach(ifp, enaddr); enaddr[5]++; } /* XXX: admwdog_attach(sc); */ /* leave interrupts and cpu port disabled */ return (0); } static int admsw_detach(device_t dev) { printf("TODO: DETACH\n"); return (0); } /* * admsw_shutdown: * * Make sure the interface is stopped at reboot time. */ static int admsw_shutdown(device_t dev) { struct admsw_softc *sc; int i; sc = device_get_softc(dev); for (i = 0; i < SW_DEVS; i++) admsw_stop(sc->sc_ifnet[i], 1); return (0); } /* * admsw_start: [ifnet interface function] * * Start packet transmission on the interface. */ static void admsw_start(struct ifnet *ifp) { struct admsw_softc *sc = ifp->if_softc; struct mbuf *m0, *m; struct admsw_descsoft *ds; struct admsw_desc *desc; bus_dmamap_t dmamap; struct ether_header *eh; int error, nexttx, len, i; static int vlan = 0; /* * Loop through the send queues, setting up transmit descriptors * unitl we drain the queues, or use up all available transmit * descriptors. */ for (;;) { vlan++; if (vlan == SW_DEVS) vlan = 0; i = vlan; for (;;) { ifp = sc->sc_ifnet[i]; if ((ifp->if_drv_flags & (IFF_DRV_RUNNING|IFF_DRV_OACTIVE)) == IFF_DRV_RUNNING) { /* Grab a packet off the queue. */ IF_DEQUEUE(&ifp->if_snd, m0); if (m0 != NULL) break; } i++; if (i == SW_DEVS) i = 0; if (i == vlan) return; } vlan = i; m = NULL; /* Get a spare descriptor. */ if (sc->sc_txfree == 0) { /* No more slots left; notify upper layer. */ ifp->if_drv_flags |= IFF_DRV_OACTIVE; break; } nexttx = sc->sc_txnext; desc = &sc->sc_txldescs[nexttx]; ds = &sc->sc_txlsoft[nexttx]; dmamap = ds->ds_dmamap; /* * Load the DMA map. If this fails, the packet either * didn't fit in the alloted number of segments, or we * were short on resources. In this case, we'll copy * and try again. */ if (m0->m_pkthdr.len < ETHER_MIN_LEN || bus_dmamap_load_mbuf(sc->sc_bufs_dmat, dmamap, m0, admsw_mbuf_map_addr, ds, BUS_DMA_NOWAIT) != 0) { MGETHDR(m, M_NOWAIT, MT_DATA); if (m == NULL) { device_printf(sc->sc_dev, "unable to allocate Tx mbuf\n"); break; } if (m0->m_pkthdr.len > MHLEN) { if (!(MCLGET(m, M_NOWAIT))) { device_printf(sc->sc_dev, "unable to allocate Tx cluster\n"); m_freem(m); break; } } m->m_pkthdr.csum_flags = m0->m_pkthdr.csum_flags; m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, void *)); m->m_pkthdr.len = m->m_len = m0->m_pkthdr.len; if (m->m_pkthdr.len < ETHER_MIN_LEN) { if (M_TRAILINGSPACE(m) < ETHER_MIN_LEN - m->m_pkthdr.len) panic("admsw_start: M_TRAILINGSPACE\n"); memset(mtod(m, uint8_t *) + m->m_pkthdr.len, 0, ETHER_MIN_LEN - ETHER_CRC_LEN - m->m_pkthdr.len); m->m_pkthdr.len = m->m_len = ETHER_MIN_LEN; } error = bus_dmamap_load_mbuf(sc->sc_bufs_dmat, dmamap, m, admsw_mbuf_map_addr, ds, BUS_DMA_NOWAIT); if (error) { device_printf(sc->sc_dev, "unable to load Tx buffer, error = %d\n", error); break; } } if (m != NULL) { m_freem(m0); m0 = m; } /* * WE ARE NOW COMMITTED TO TRANSMITTING THE PACKET. */ /* Sync the DMA map. */ bus_dmamap_sync(sc->sc_bufs_dmat, dmamap, BUS_DMASYNC_PREWRITE); if (ds->ds_nsegs != 1 && ds->ds_nsegs != 2) panic("admsw_start: nsegs == %d\n", ds->ds_nsegs); desc->data = ds->ds_addr[0]; desc->len = len = ds->ds_len[0]; if (ds->ds_nsegs > 1) { len += ds->ds_len[1]; desc->cntl = ds->ds_addr[1] | ADM5120_DMA_BUF2ENABLE; } else desc->cntl = 0; desc->status = (len << ADM5120_DMA_LENSHIFT) | (1 << vlan); eh = mtod(m0, struct ether_header *); if (ntohs(eh->ether_type) == ETHERTYPE_IP && m0->m_pkthdr.csum_flags & CSUM_IP) desc->status |= ADM5120_DMA_CSUM; if (nexttx == ADMSW_NTXLDESC - 1) desc->data |= ADM5120_DMA_RINGEND; desc->data |= ADM5120_DMA_OWN; /* Sync the descriptor. */ ADMSW_CDTXLSYNC(sc, nexttx, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); REG_WRITE(SEND_TRIG_REG, 1); /* printf("send slot %d\n",nexttx); */ /* * Store a pointer to the packet so we can free it later. */ ds->ds_mbuf = m0; /* Advance the Tx pointer. */ sc->sc_txfree--; sc->sc_txnext = ADMSW_NEXTTXL(nexttx); /* Pass the packet to any BPF listeners. */ BPF_MTAP(ifp, m0); /* Set a watchdog timer in case the chip flakes out. */ sc->sc_timer = 5; } } /* * admsw_watchdog: [ifnet interface function] * * Watchdog timer handler. */ static void admsw_watchdog(void *arg) { struct admsw_softc *sc = arg; struct ifnet *ifp; int vlan; callout_reset(&sc->sc_watchdog, hz, admsw_watchdog, sc); if (sc->sc_timer == 0 || --sc->sc_timer > 0) return; /* Check if an interrupt was lost. */ if (sc->sc_txfree == ADMSW_NTXLDESC) { device_printf(sc->sc_dev, "watchdog false alarm\n"); return; } if (sc->sc_timer != 0) device_printf(sc->sc_dev, "watchdog timer is %d!\n", sc->sc_timer); admsw_txintr(sc, 0); if (sc->sc_txfree == ADMSW_NTXLDESC) { device_printf(sc->sc_dev, "tx IRQ lost (queue empty)\n"); return; } if (sc->sc_timer != 0) { device_printf(sc->sc_dev, "tx IRQ lost (timer recharged)\n"); return; } device_printf(sc->sc_dev, "device timeout, txfree = %d\n", sc->sc_txfree); for (vlan = 0; vlan < SW_DEVS; vlan++) admsw_stop(sc->sc_ifnet[vlan], 0); admsw_init(sc); ifp = sc->sc_ifnet[0]; /* Try to get more packets going. */ admsw_start(ifp); } /* * admsw_ioctl: [ifnet interface function] * * Handle control requests from the operator. */ static int admsw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct admsw_softc *sc = ifp->if_softc; struct ifdrv *ifd; int error, port; ADMSW_LOCK(sc); switch (cmd) { case SIOCSIFMEDIA: case SIOCGIFMEDIA: port = 0; while(port < SW_DEVS) if(ifp == sc->sc_ifnet[port]) break; else port++; if (port >= SW_DEVS) error = EOPNOTSUPP; else error = ifmedia_ioctl(ifp, (struct ifreq *)data, &sc->sc_ifmedia[port], cmd); break; case SIOCGDRVSPEC: case SIOCSDRVSPEC: ifd = (struct ifdrv *) data; if (ifd->ifd_cmd != 0 || ifd->ifd_len != sizeof(vlan_matrix)) { error = EINVAL; break; } if (cmd == SIOCGDRVSPEC) { error = copyout(vlan_matrix, ifd->ifd_data, sizeof(vlan_matrix)); } else { error = copyin(ifd->ifd_data, vlan_matrix, sizeof(vlan_matrix)); admsw_setvlan(sc, vlan_matrix); } break; default: error = ether_ioctl(ifp, cmd, data); if (error == ENETRESET) { /* * Multicast list has changed; set the hardware filter * accordingly. */ admsw_set_filter(sc); error = 0; } break; } /* Try to get more packets going. */ admsw_start(ifp); ADMSW_UNLOCK(sc); return (error); } /* * admsw_intr: * * Interrupt service routine. */ static int admsw_intr(void *arg) { struct admsw_softc *sc = arg; uint32_t pending; pending = REG_READ(ADMSW_INT_ST); REG_WRITE(ADMSW_INT_ST, pending); if (sc->ndevs == 0) return (FILTER_STRAY); if ((pending & ADMSW_INTR_RHD) != 0) admsw_rxintr(sc, 1); if ((pending & ADMSW_INTR_RLD) != 0) admsw_rxintr(sc, 0); if ((pending & ADMSW_INTR_SHD) != 0) admsw_txintr(sc, 1); if ((pending & ADMSW_INTR_SLD) != 0) admsw_txintr(sc, 0); return (FILTER_HANDLED); } /* * admsw_txintr: * * Helper; handle transmit interrupts. */ static void admsw_txintr(struct admsw_softc *sc, int prio) { struct ifnet *ifp; struct admsw_desc *desc; struct admsw_descsoft *ds; int i, vlan; int gotone = 0; /* printf("txintr: txdirty: %d, txfree: %d\n",sc->sc_txdirty, sc->sc_txfree); */ for (i = sc->sc_txdirty; sc->sc_txfree != ADMSW_NTXLDESC; i = ADMSW_NEXTTXL(i)) { ADMSW_CDTXLSYNC(sc, i, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); desc = &sc->sc_txldescs[i]; ds = &sc->sc_txlsoft[i]; if (desc->data & ADM5120_DMA_OWN) { ADMSW_CDTXLSYNC(sc, i, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); break; } bus_dmamap_sync(sc->sc_bufs_dmat, ds->ds_dmamap, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->sc_bufs_dmat, ds->ds_dmamap); m_freem(ds->ds_mbuf); ds->ds_mbuf = NULL; vlan = ffs(desc->status & 0x3f) - 1; if (vlan < 0 || vlan >= SW_DEVS) panic("admsw_txintr: bad vlan\n"); ifp = sc->sc_ifnet[vlan]; gotone = 1; /* printf("clear tx slot %d\n",i); */ if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); sc->sc_txfree++; } if (gotone) { sc->sc_txdirty = i; for (vlan = 0; vlan < SW_DEVS; vlan++) sc->sc_ifnet[vlan]->if_drv_flags &= ~IFF_DRV_OACTIVE; ifp = sc->sc_ifnet[0]; /* Try to queue more packets. */ admsw_start(ifp); /* * If there are no more pending transmissions, * cancel the watchdog timer. */ if (sc->sc_txfree == ADMSW_NTXLDESC) sc->sc_timer = 0; } /* printf("txintr end: txdirty: %d, txfree: %d\n",sc->sc_txdirty, sc->sc_txfree); */ } /* * admsw_rxintr: * * Helper; handle receive interrupts. */ static void admsw_rxintr(struct admsw_softc *sc, int high) { struct ifnet *ifp; struct admsw_descsoft *ds; struct mbuf *m; uint32_t stat; int i, len, port, vlan; /* printf("rxintr\n"); */ if (high) panic("admsw_rxintr: high priority packet\n"); #if 1 ADMSW_CDRXLSYNC(sc, sc->sc_rxptr, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); if ((sc->sc_rxldescs[sc->sc_rxptr].data & ADM5120_DMA_OWN) == 0) ADMSW_CDRXLSYNC(sc, sc->sc_rxptr, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); else { i = sc->sc_rxptr; do { ADMSW_CDRXLSYNC(sc, i, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); i = ADMSW_NEXTRXL(i); /* the ring is empty, just return. */ if (i == sc->sc_rxptr) return; ADMSW_CDRXLSYNC(sc, i, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); } while (sc->sc_rxldescs[i].data & ADM5120_DMA_OWN); ADMSW_CDRXLSYNC(sc, i, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); ADMSW_CDRXLSYNC(sc, sc->sc_rxptr, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); if ((sc->sc_rxldescs[sc->sc_rxptr].data & ADM5120_DMA_OWN) == 0) ADMSW_CDRXLSYNC(sc, sc->sc_rxptr, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); else { ADMSW_CDRXLSYNC(sc, sc->sc_rxptr, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); /* We've fallen behind the chip: catch it. */ #if 0 device_printf(sc->sc_dev, "RX ring resync, base=%x, work=%x, %d -> %d\n", REG_READ(RECV_LBADDR_REG), REG_READ(RECV_LWADDR_REG), sc->sc_rxptr, i); #endif sc->sc_rxptr = i; /* ADMSW_EVCNT_INCR(&sc->sc_ev_rxsync); */ } } #endif for (i = sc->sc_rxptr;; i = ADMSW_NEXTRXL(i)) { ds = &sc->sc_rxlsoft[i]; ADMSW_CDRXLSYNC(sc, i, BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); if (sc->sc_rxldescs[i].data & ADM5120_DMA_OWN) { ADMSW_CDRXLSYNC(sc, i, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); break; } /* printf("process slot %d\n",i); */ bus_dmamap_sync(sc->sc_bufs_dmat, ds->ds_dmamap, BUS_DMASYNC_POSTREAD); stat = sc->sc_rxldescs[i].status; len = (stat & ADM5120_DMA_LEN) >> ADM5120_DMA_LENSHIFT; len -= ETHER_CRC_LEN; port = (stat & ADM5120_DMA_PORTID) >> ADM5120_DMA_PORTSHIFT; for (vlan = 0; vlan < SW_DEVS; vlan++) if ((1 << port) & vlan_matrix[vlan]) break; if (vlan == SW_DEVS) vlan = 0; ifp = sc->sc_ifnet[vlan]; m = ds->ds_mbuf; if (admsw_add_rxlbuf(sc, i) != 0) { if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); ADMSW_INIT_RXLDESC(sc, i); bus_dmamap_sync(sc->sc_bufs_dmat, ds->ds_dmamap, BUS_DMASYNC_PREREAD); continue; } m->m_pkthdr.rcvif = ifp; m->m_pkthdr.len = m->m_len = len; if ((stat & ADM5120_DMA_TYPE) == ADM5120_DMA_TYPE_IP) { m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED; if (!(stat & ADM5120_DMA_CSUMFAIL)) m->m_pkthdr.csum_flags |= CSUM_IP_VALID; } BPF_MTAP(ifp, m); /* Pass it on. */ (*ifp->if_input)(ifp, m); if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); } /* Update the receive pointer. */ sc->sc_rxptr = i; } /* * admsw_init: [ifnet interface function] * * Initialize the interface. */ static void admsw_init(void *xsc) { struct admsw_softc *sc = xsc; struct ifnet *ifp; int i; for (i = 0; i < SW_DEVS; i++) { ifp = sc->sc_ifnet[i]; if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { if (sc->ndevs == 0) { admsw_init_bufs(sc); admsw_reset(sc); REG_WRITE(CPUP_CONF_REG, CPUP_CONF_CRCP | CPUP_CONF_DUNP_MASK | CPUP_CONF_DMCP_MASK); /* clear all pending interrupts */ REG_WRITE(ADMSW_INT_ST, INT_MASK); /* enable needed interrupts */ REG_WRITE(ADMSW_INT_MASK, REG_READ(ADMSW_INT_MASK) & ~(ADMSW_INTR_SHD | ADMSW_INTR_SLD | ADMSW_INTR_RHD | ADMSW_INTR_RLD | ADMSW_INTR_HDF | ADMSW_INTR_LDF)); callout_reset(&sc->sc_watchdog, hz, admsw_watchdog, sc); } sc->ndevs++; } /* mark iface as running */ ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; } /* Set the receive filter. */ admsw_set_filter(sc); } /* * admsw_stop: [ifnet interface function] * * Stop transmission on the interface. */ static void admsw_stop(struct ifnet *ifp, int disable) { struct admsw_softc *sc = ifp->if_softc; if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) return; if (--sc->ndevs == 0) { /* printf("debug: de-initializing hardware\n"); */ /* disable cpu port */ REG_WRITE(CPUP_CONF_REG, CPUP_CONF_DCPUP | CPUP_CONF_CRCP | CPUP_CONF_DUNP_MASK | CPUP_CONF_DMCP_MASK); /* XXX We should disable, then clear? --dyoung */ /* clear all pending interrupts */ REG_WRITE(ADMSW_INT_ST, INT_MASK); /* disable interrupts */ REG_WRITE(ADMSW_INT_MASK, INT_MASK); /* Cancel the watchdog timer. */ sc->sc_timer = 0; callout_stop(&sc->sc_watchdog); } /* Mark the interface as down. */ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); return; } /* * admsw_set_filter: * * Set up the receive filter. */ static void admsw_set_filter(struct admsw_softc *sc) { int i; uint32_t allmc, anymc, conf, promisc; struct ifnet *ifp; struct ifmultiaddr *ifma; /* Find which ports should be operated in promisc mode. */ allmc = anymc = promisc = 0; for (i = 0; i < SW_DEVS; i++) { ifp = sc->sc_ifnet[i]; if (ifp->if_flags & IFF_PROMISC) promisc |= vlan_matrix[i]; ifp->if_flags &= ~IFF_ALLMULTI; if_maddr_rlock(ifp); TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { if (ifma->ifma_addr->sa_family != AF_LINK) continue; anymc |= vlan_matrix[i]; } if_maddr_runlock(ifp); } conf = REG_READ(CPUP_CONF_REG); /* 1 Disable forwarding of unknown & multicast packets to * CPU on all ports. * 2 Enable forwarding of unknown & multicast packets to * CPU on ports where IFF_PROMISC or IFF_ALLMULTI is set. */ conf |= CPUP_CONF_DUNP_MASK | CPUP_CONF_DMCP_MASK; /* Enable forwarding of unknown packets to CPU on selected ports. */ conf ^= ((promisc << CPUP_CONF_DUNP_SHIFT) & CPUP_CONF_DUNP_MASK); conf ^= ((allmc << CPUP_CONF_DMCP_SHIFT) & CPUP_CONF_DMCP_MASK); conf ^= ((anymc << CPUP_CONF_DMCP_SHIFT) & CPUP_CONF_DMCP_MASK); REG_WRITE(CPUP_CONF_REG, conf); } /* * admsw_add_rxbuf: * * Add a receive buffer to the indicated descriptor. */ int admsw_add_rxbuf(struct admsw_softc *sc, int idx, int high) { struct admsw_descsoft *ds; struct mbuf *m; int error; if (high) ds = &sc->sc_rxhsoft[idx]; else ds = &sc->sc_rxlsoft[idx]; MGETHDR(m, M_NOWAIT, MT_DATA); if (m == NULL) return (ENOBUFS); if (!(MCLGET(m, M_NOWAIT))) { m_freem(m); return (ENOBUFS); } if (ds->ds_mbuf != NULL) bus_dmamap_unload(sc->sc_bufs_dmat, ds->ds_dmamap); ds->ds_mbuf = m; error = bus_dmamap_load(sc->sc_bufs_dmat, ds->ds_dmamap, m->m_ext.ext_buf, m->m_ext.ext_size, admsw_rxbuf_map_addr, ds, BUS_DMA_NOWAIT); if (error) { device_printf(sc->sc_dev, "can't load rx DMA map %d, error = %d\n", idx, error); panic("admsw_add_rxbuf"); /* XXX */ } bus_dmamap_sync(sc->sc_bufs_dmat, ds->ds_dmamap, BUS_DMASYNC_PREREAD); if (high) ADMSW_INIT_RXHDESC(sc, idx); else ADMSW_INIT_RXLDESC(sc, idx); return (0); } int admsw_mediachange(struct ifnet *ifp) { struct admsw_softc *sc = ifp->if_softc; int port = 0; struct ifmedia *ifm; int old, new, val; while(port < SW_DEVS) { if(ifp == sc->sc_ifnet[port]) break; else port++; } ifm = &sc->sc_ifmedia[port]; if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) return (EINVAL); if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO) { val = PHY_CNTL2_AUTONEG|PHY_CNTL2_100M|PHY_CNTL2_FDX; } else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_100_TX) { if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) val = PHY_CNTL2_100M|PHY_CNTL2_FDX; else val = PHY_CNTL2_100M; } else if (IFM_SUBTYPE(ifm->ifm_media) == IFM_10_T) { if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) val = PHY_CNTL2_FDX; else val = 0; } else return (EINVAL); old = REG_READ(PHY_CNTL2_REG); new = old & ~((PHY_CNTL2_AUTONEG|PHY_CNTL2_100M|PHY_CNTL2_FDX) << port); new |= (val << port); if (new != old) REG_WRITE(PHY_CNTL2_REG, new); return (0); } void admsw_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) { struct admsw_softc *sc = ifp->if_softc; int port = 0; int status; while(port < SW_DEVS) { if(ifp == sc->sc_ifnet[port]) break; else port++; } ifmr->ifm_status = IFM_AVALID; ifmr->ifm_active = IFM_ETHER; status = REG_READ(PHY_ST_REG) >> port; if ((status & PHY_ST_LINKUP) == 0) { ifmr->ifm_active |= IFM_NONE; return; } ifmr->ifm_status |= IFM_ACTIVE; ifmr->ifm_active |= (status & PHY_ST_100M) ? IFM_100_TX : IFM_10_T; if (status & PHY_ST_FDX) ifmr->ifm_active |= IFM_FDX; } static device_method_t admsw_methods[] = { /* Device interface */ DEVMETHOD(device_probe, admsw_probe), DEVMETHOD(device_attach, admsw_attach), DEVMETHOD(device_detach, admsw_detach), DEVMETHOD(device_shutdown, admsw_shutdown), { 0, 0 } }; static devclass_t admsw_devclass; static driver_t admsw_driver = { "admsw", admsw_methods, sizeof(struct admsw_softc), }; DRIVER_MODULE(admsw, obio, admsw_driver, admsw_devclass, 0, 0); MODULE_DEPEND(admsw, ether, 1, 1, 1); Index: head/sys/mips/adm5120/if_admswreg.h =================================================================== --- head/sys/mips/adm5120/if_admswreg.h (revision 326258) +++ head/sys/mips/adm5120/if_admswreg.h (revision 326259) @@ -1,678 +1,680 @@ /* $NetBSD: if_admswreg.h,v 1.1 2007/03/20 08:52:02 dyoung Exp $ */ /*- + * SPDX-License-Identifier: BSD-3-Clause + * * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko. * 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. * 3. The names of the authors may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS * 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$ */ #ifndef _IF_ADMSWREG_H_ #define _IF_ADMSWREG_H_ #define ADMSW_BOOT_DONE 0x0008 #define ADMSW_BOOT_DONE_BO __BIT(0) #define ADMSW_SW_RES 0x000c #define ADMSW_SW_RES_SWR __BITS(31, 0) #define ADMSW_INT_ST 0x00b0 #define ADMSW_INT_MASK 0x00b4 #define ADMSW_INTR_RSVD __BITS(31, 25) #define ADMSW_INTR_CPUH __BIT(24) #define ADMSW_INTR_SDE __BIT(23) #define ADMSW_INTR_RDE __BIT(22) #define ADMSW_INTR_W1TE __BIT(21) #define ADMSW_INTR_W0TE __BIT(20) #define ADMSW_INTR_MI __BIT(19) #define ADMSW_INTR_PSC __BIT(18) #define ADMSW_INTR_BCS __BIT(16) #define ADMSW_INTR_MD __BIT(15) #define ADMSW_INTR_GQF __BIT(14) #define ADMSW_INTR_CPQ __BIT(13) #define ADMSW_INTR_P5QF __BIT(11) #define ADMSW_INTR_P4QF __BIT(10) #define ADMSW_INTR_P3QF __BIT(9) #define ADMSW_INTR_P2QF __BIT(8) #define ADMSW_INTR_P1QF __BIT(7) #define ADMSW_INTR_P0QF __BIT(6) #define ADMSW_INTR_LDF __BIT(5) #define ADMSW_INTR_HDF __BIT(4) #define ADMSW_INTR_RLD __BIT(3) #define ADMSW_INTR_RHD __BIT(2) #define ADMSW_INTR_SLD __BIT(1) #define ADMSW_INTR_SHD __BIT(0) #define ADMSW_INT_FMT \ "\x10"\ "\x01SHD"\ "\x02SLD"\ "\x03RHD"\ "\x04RLD"\ "\x05HDF"\ "\x06LDF"\ "\x07P0QF"\ "\x08P1QF"\ "\x09P2QF"\ "\x0aP3QF"\ "\x0bP4QF"\ "\x0cP5QF"\ "\x0e"\ "CPQ"\ "\x0fGQF"\ "\x10MD"\ "\x11"\ "BCS"\ "\x13PSC"\ "\x14MI"\ "\x15W0TE"\ "\x16W1TE"\ "\x17RDE"\ "\x18SDE"\ "\x19"\ "CPUH" #define CODE_REG 0x0000 #define SFTREST_REG 0x0004 #define BOOT_DONE_REG 0x0008 #define GLOBAL_ST_REG 0x0010 #define PHY_ST_REG 0x0014 #define PHY_ST_LINKUP (1 << 0) #define PHY_ST_100M (1 << 8) #define PHY_ST_FDX (1 << 16) #define PORT_ST_REG 0x0018 #define MEM_CONTROL_REG 0x001C #define SW_CONF_REG 0x0020 #define CPUP_CONF_REG 0x0024 #define CPUP_CONF_DCPUP 0x00000001 #define CPUP_CONF_CRCP 0x00000002 #define CPUP_CONF_BTM 0x00000004 #define CPUP_CONF_DUNP_SHIFT 9 #define CPUP_CONF_DUNP_MASK (0x3F << CPUP_CONF_DUNP_SHIFT) #define CPUP_CONF_DMCP_SHIFT 16 #define CPUP_CONF_DMCP_MASK (0x3F << CPUP_CONF_DMCP_SHIFT) #define CPUP_CONF_DBCP_SHIFT 24 #define CPUP_CONF_DBCP_MASK (0x3F << CPUP_CONF_DBCP_SHIFT) #define PORT_CONF0_REG 0x0028 #define PORT_CONF0_DP_MASK 0x0000003F #define PORT_CONF0_EMCP_MASK 0x00003F00 #define PORT_CONF0_EMCP_SHIFT 8 #define PORT_CONF0_EMBP_MASK 0x003F0000 #define PORT_CONF0_EMBP_SHIFT 16 #define PORT_CONF1_REG 0x002C #define PORT_CONF2_REG 0x0030 #define VLAN_G1_REG 0x0040 #define VLAN_G2_REG 0x0044 #define SEND_TRIG_REG 0x0048 #define SRCH_CMD_REG 0x004C #define ADDR_ST0_REG 0x0050 #define ADDR_ST1_REG 0x0054 #define MAC_WT0_REG 0x0058 #define MAC_WT0_WRITE 0x00000001 #define MAC_WT0_WRITE_DONE 0x00000002 #define MAC_WT0_FILTER_EN 0x00000004 #define MAC_WT0_VLANID_SHIFT 3 #define MAC_WT0_VLANID_MASK 0x00000038 #define MAC_WT0_VLANID_EN 0x00000040 #define MAC_WT0_PORTMAP_MASK 0x00001F80 #define MAC_WT0_PORTMAP_SHIFT 7 #define MAC_WT0_AGE_MASK (0x7 << 13) #define MAC_WT0_AGE_STATIC (0x7 << 13) #define MAC_WT0_AGE_VALID (0x1 << 13) #define MAC_WT0_AGE_EMPTY 0 #define MAC_WT1_REG 0x005C #define BW_CNTL0_REG 0x0060 #define BW_CNTL1_REG 0x0064 #define PHY_CNTL0_REG 0x0068 #define PHY_CNTL1_REG 0x006C #define FC_TH_REG 0x0070 #define FC_TH_FCS_MASK 0x01FF0000 #define FC_TH_D2R_MASK 0x0000FF00 #define FC_TH_D2S_MASK 0x000000FF #define ADJ_PORT_TH_REG 0x0074 #define PORT_TH_REG 0x0078 #define PHY_CNTL2_REG 0x007C #define PHY_CNTL2_AUTONEG (1 << 0) #define PHY_CNTL2_ANE_MASK 0x0000001F #define PHY_CNTL2_SC_MASK 0x000003E0 #define PHY_CNTL2_SC_SHIFT 5 #define PHY_CNTL2_100M (1 << PHY_CNTL2_SC_SHIFT) #define PHY_CNTL2_DC_MASK 0x00007C00 #define PHY_CNTL2_DC_SHIFT 10 #define PHY_CNTL2_FDX (1 << PHY_CNTL2_DC_SHIFT) #define PHY_CNTL2_RFCV_MASK 0x000F8000 #define PHY_CNTL2_RFCV_SHIFT 15 #define PHY_CNTL2_PHYR_MASK 0x01F00000 #define PHY_CNTL2_PHYR_SHIFT 20 #define PHY_CNTL2_AMDIX_MASK 0x3E000000 #define PHY_CNTL2_AMDIX_SHIFT 25 #define PHY_CNTL2_RMAE 0x40000000 #define PHY_CNTL3_REG 0x0080 #define PHY_CNTL3_RNT 0x00000400 #define PRI_CNTL_REG 0x0084 #define VLAN_PRI_REG 0x0088 #define TOS_EN_REG 0x008C #define TOS_MAP0_REG 0x0090 #define TOS_MAP1_REG 0x0094 #define CUSTOM_PRI1_REG 0x0098 #define CUSTOM_PRI2_REG 0x009C #define EMPTY_CNT_REG 0x00A4 #define PORT_CNT_SEL_REG 0x00A8 #define PORT_CNT_REG 0x00AC #define INT_MASK 0x1FDEFFF #define GPIO_CONF0_REG 0x00B8 #define GPIO_CONF2_REG 0x00BC #define SWAP_IN_REG 0x00C8 #define SWAP_OUT_REG 0x00CC #define SEND_HBADDR_REG 0x00D0 #define SEND_LBADDR_REG 0x00D4 #define RECV_HBADDR_REG 0x00D8 #define RECV_LBADDR_REG 0x00DC #define SEND_HWADDR_REG 0x00E0 #define SEND_LWADDR_REG 0x00E4 #define RECV_HWADDR_REG 0x00E8 #define RECV_LWADDR_REG 0x00EC #define TIMER_INT_REG 0x00F0 #define TIMER_REG 0x00F4 #define PORT0_LED_REG 0x0100 #define PORT1_LED_REG 0x0104 #define PORT2_LED_REG 0x0108 #define PORT3_LED_REG 0x010c #define PORT4_LED_REG 0x0110 /* Hardware descriptor format */ struct admsw_desc { volatile uint32_t data; volatile uint32_t cntl; volatile uint32_t len; volatile uint32_t status; } __attribute__((__packed__, __aligned__(4))); #define ADM5120_DMA_MASK 0x01ffffff #define ADM5120_DMA_OWN 0x80000000 /* buffer owner */ #define ADM5120_DMA_RINGEND 0x10000000 /* Last in DMA ring */ #define ADM5120_DMA_BUF2ENABLE 0x80000000 #define ADM5120_DMA_PORTID 0x00007000 #define ADM5120_DMA_PORTSHIFT 12 #define ADM5120_DMA_LEN 0x07ff0000 #define ADM5120_DMA_LENSHIFT 16 #define ADM5120_DMA_TYPE 0x00000003 #define ADM5120_DMA_TYPE_IP 0x00000000 #define ADM5120_DMA_TYPE_PPPOE 0x00000001 #define ADM5120_DMA_CSUM 0x80000000 #define ADM5120_DMA_CSUMFAIL 0x00000008 #define SW_DEVS 6 #if 0 /* CODE_REG */ #define CODE_ID_MASK 0x00FFFF #define CODE_ADM5120_ID 0x5120 #define CODE_REV_MASK 0x0F0000 #define CODE_REV_SHIFT 16 #define CODE_REV_ADM5120_0 0x8 #define CODE_CLK_MASK 0x300000 #define CODE_CLK_SHIFT 20 #define CPU_CLK_175MHZ 0x0 #define CPU_CLK_200MHZ 0x1 #define CPU_CLK_225MHZ 0x2 #define CPU_CLK_250MHZ 0x3 #define CPU_SPEED_175M (175000000/2) #define CPU_SPEED_200M (200000000/2) #define CPU_SPEED_225M (225000000/2) #define CPU_SPEED_250M (250000000/2) #define CPU_NAND_BOOT 0x01000000 #define CPU_DCACHE_2K_WAY (0x1 << 25) #define CPU_DCACHE_2WAY (0x1 << 26) #define CPU_ICACHE_2K_WAY (0x1 << 27) #define CPU_ICACHE_2WAY (0x1 << 28) #define CPU_GMII_SUPPORT 0x20000000 #define CPU_PQFP_MODE (0x1 << 29) #define CPU_CACHE_LINE_SIZE 16 /* SftRest_REG */ #define SOFTWARE_RESET 0x1 /* Boot_done_REG */ #define BOOT_DONE 0x1 /* SWReset_REG */ #define SWITCH_RESET 0x1 /* Global_St_REG */ #define DATA_BUF_BIST_FAILED (0x1 << 0) #define LINK_TAB_BIST_FAILED (0x1 << 1) #define MC_TAB_BIST_FAILED (0x1 << 2) #define ADDR_TAB_BIST_FAILED (0x1 << 3) #define DCACHE_D_FAILED (0x3 << 4) #define DCACHE_T_FAILED (0x1 << 6) #define ICACHE_D_FAILED (0x3 << 7) #define ICACHE_T_FAILED (0x1 << 9) #define BIST_FAILED_MASK 0x03FF #define ALLMEM_TEST_DONE (0x1 << 10) #define SKIP_BLK_CNT_MASK 0x1FF000 #define SKIP_BLK_CNT_SHIFT 12 /* PHY_st_REG */ #define PORT_LINK_MASK 0x0000001F #define PORT_MII_LINKFAIL 0x00000020 #define PORT_SPEED_MASK 0x00001F00 #define PORT_GMII_SPD_MASK 0x00006000 #define PORT_GMII_SPD_10M 0 #define PORT_GMII_SPD_100M 0x00002000 #define PORT_GMII_SPD_1000M 0x00004000 #define PORT_DUPLEX_MASK 0x003F0000 #define PORT_FLOWCTRL_MASK 0x1F000000 #define PORT_GMII_FLOWCTRL_MASK 0x60000000 #define PORT_GMII_FC_ON 0x20000000 #define PORT_GMII_RXFC_ON 0x20000000 #define PORT_GMII_TXFC_ON 0x40000000 /* Port_st_REG */ #define PORT_SECURE_ST_MASK 0x001F #define MII_PORT_TXC_ERR 0x0080 /* Mem_control_REG */ #define SDRAM_SIZE_4MBYTES 0x0001 #define SDRAM_SIZE_8MBYTES 0x0002 #define SDRAM_SIZE_16MBYTES 0x0003 #define SDRAM_SIZE_64MBYTES 0x0004 #define SDRAM_SIZE_128MBYTES 0x0005 #define SDRAM_SIZE_MASK 0x0007 #define MEMCNTL_SDRAM1_EN (0x1 << 5) #define ROM_SIZE_DISABLE 0x0000 #define ROM_SIZE_512KBYTES 0x0001 #define ROM_SIZE_1MBYTES 0x0002 #define ROM_SIZE_2MBYTES 0x0003 #define ROM_SIZE_4MBYTES 0x0004 #define ROM_SIZE_8MBYTES 0x0005 #define ROM_SIZE_MASK 0x0007 #define ROM0_SIZE_SHIFT 8 #define ROM1_SIZE_SHIFT 16 /* SW_conf_REG */ #define SW_AGE_TIMER_MASK 0x000000F0 #define SW_AGE_TIMER_DISABLE 0x0 #define SW_AGE_TIMER_FAST 0x00000080 #define SW_AGE_TIMER_300SEC 0x00000010 #define SW_AGE_TIMER_600SEC 0x00000020 #define SW_AGE_TIMER_1200SEC 0x00000030 #define SW_AGE_TIMER_2400SEC 0x00000040 #define SW_AGE_TIMER_4800SEC 0x00000050 #define SW_AGE_TIMER_9600SEC 0x00000060 #define SW_AGE_TIMER_19200SEC 0x00000070 //#define SW_AGE_TIMER_38400SEC 0x00000070 #define SW_BC_PREV_MASK 0x00000300 #define SW_BC_PREV_DISABLE 0 #define SW_BC_PREV_64BC 0x00000100 #define SW_BC_PREV_48BC 0x00000200 #define SW_BC_PREV_32BC 0x00000300 #define SW_MAX_LEN_MASK 0x00000C00 #define SW_MAX_LEN_1536 0 #define SW_MAX_LEN_1522 0x00000800 #define SW_MAX_LEN_1518 0x00000400 #define SW_DIS_COLABT 0x00001000 #define SW_HASH_ALG_MASK 0x00006000 #define SW_HASH_ALG_DIRECT 0 #define SW_HASH_ALG_XOR48 0x00002000 #define SW_HASH_ALG_XOR32 0x00004000 #define SW_DISABLE_BACKOFF_TIMER 0x00008000 #define SW_BP_NUM_MASK 0x000F0000 #define SW_BP_NUM_SHIFT 16 #define SW_BP_MODE_MASK 0x00300000 #define SW_BP_MODE_DISABLE 0 #define SW_BP_MODE_JAM 0x00100000 #define SW_BP_MODE_JAMALL 0x00200000 #define SW_BP_MODE_CARRIER 0x00300000 #define SW_RESRV_MC_FILTER 0x00400000 #define SW_BISR_DISABLE 0x00800000 #define SW_DIS_MII_WAS_TX 0x01000000 #define SW_BISS_EN 0x02000000 #define SW_BISS_TH_MASK 0x0C000000 #define SW_BISS_TH_SHIFT 26 #define SW_REQ_LATENCY_MASK 0xF0000000 #define SW_REQ_LATENCY_SHIFT 28 /* CPUp_conf_REG */ #define SW_CPU_PORT_DISABLE 0x00000001 #define SW_PADING_CRC 0x00000002 #define SW_BRIDGE_MODE 0x00000004 #define SW_DIS_UN_SHIFT 9 #define SW_DIS_UN_MASK (0x3F << SW_DIS_UN_SHIFT) #define SW_DIS_MC_SHIFT 16 #define SW_DIS_MC_MASK (0x3F << SW_DIS_MC_SHIFT) #define SW_DIS_BC_SHIFT 24 #define SW_DIS_BC_MASK (0x3F << SW_DIS_BC_SHIFT) /* Port_conf0_REG */ #define SW_DISABLE_PORT_MASK 0x0000003F #define SW_EN_MC_MASK 0x00003F00 #define SW_EN_MC_SHIFT 8 #define SW_EN_BP_MASK 0x003F0000 #define SW_EN_BP_SHIFT 16 #define SW_EN_FC_MASK 0x3F000000 #define SW_EN_FC_SHIFT 24 /* Port_conf1_REG */ #define SW_DIS_SA_LEARN_MASK 0x0000003F #define SW_PORT_BLOCKING_MASK 0x00000FC0 #define SW_PORT_BLOCKING_SHIFT 6 #define SW_PORT_BLOCKING_ON 0x1 #define SW_PORT_BLOCKING_MODE_MASK 0x0003F000 #define SW_PORT_BLOCKING_MODE_SHIFT 12 #define SW_PORT_BLOCKING_CTRLONLY 0x1 #define SW_EN_PORT_AGE_MASK 0x03F00000 #define SW_EN_PORT_AGE_SHIFT 20 #define SW_EN_SA_SECURED_MASK 0xFC000000 #define SW_EN_SA_SECURED_SHIFT 26 /* Port_conf2_REG */ #define SW_GMII_AN_EN 0x00000001 #define SW_GMII_FORCE_SPD_MASK 0x00000006 #define SW_GMII_FORCE_SPD_10M 0 #define SW_GMII_FORCE_SPD_100M 0x2 #define SW_GMII_FORCE_SPD_1000M 0x4 #define SW_GMII_FORCE_FULL_DUPLEX 0x00000008 #define SW_GMII_FORCE_RXFC 0x00000010 #define SW_GMII_FORCE_TXFC 0x00000020 #define SW_GMII_EN 0x00000040 #define SW_GMII_REVERSE 0x00000080 #define SW_GMII_TXC_CHECK_EN 0x00000100 #define SW_LED_FLASH_TIME_MASK 0x00030000 #define SW_LED_FLASH_TIME_30MS 0 #define SW_LED_FLASH_TIME_60MS 0x00010000 #define SW_LED_FLASH_TIME_240MS 0x00020000 #define SW_LED_FLASH_TIME_480MS 0x00030000 /* Send_trig_REG */ #define SEND_TRIG_LOW 0x0001 #define SEND_TRIG_HIGH 0x0002 /* Srch_cmd_REG */ #define SW_MAC_SEARCH_START 0x000001 #define SW_MAX_SEARCH_AGAIN 0x000002 /* MAC_wt0_REG */ #define SW_MAC_WRITE 0x00000001 #define SW_MAC_WRITE_DONE 0x00000002 #define SW_MAC_FILTER_EN 0x00000004 #define SW_MAC_VLANID_SHIFT 3 #define SW_MAC_VLANID_MASK 0x00000038 #define SW_MAC_VLANID_EN 0x00000040 #define SW_MAC_PORTMAP_MASK 0x00001F80 #define SW_MAC_PORTMAP_SHIFT 7 #define SW_MAC_AGE_MASK (0x7 << 13) #define SW_MAC_AGE_STATIC (0x7 << 13) #define SW_MAC_AGE_VALID (0x1 << 13) #define SW_MAC_AGE_EMPTY 0 /* BW_cntl0_REG */ #define SW_PORT_TX_NOLIMIT 0 #define SW_PORT_TX_64K 1 #define SW_PORT_TX_128K 2 #define SW_PORT_TX_256K 3 #define SW_PORT_TX_512K 4 #define SW_PORT_TX_1M 5 #define SW_PORT_TX_4M 6 #define SW_PORT_TX_10MK 7 /* BW_cntl1_REG */ #define SW_TRAFFIC_SHAPE_IPG (0x1 << 31) /* PHY_cntl0_REG */ #define SW_PHY_ADDR_MASK 0x0000001F #define PHY_ADDR_MAX 0x1f #define SW_PHY_REG_ADDR_MASK 0x00001F00 #define SW_PHY_REG_ADDR_SHIFT 8 #define PHY_REG_ADDR_MAX 0x1f #define SW_PHY_WRITE 0x00002000 #define SW_PHY_READ 0x00004000 #define SW_PHY_WDATA_MASK 0xFFFF0000 #define SW_PHY_WDATA_SHIFT 16 /* PHY_cntl1_REG */ #define SW_PHY_WRITE_DONE 0x00000001 #define SW_PHY_READ_DONE 0x00000002 #define SW_PHY_RDATA_MASK 0xFFFF0000 #define SW_PHY_RDATA_SHIFT 16 /* FC_th_REG */ /* Adj_port_th_REG */ /* Port_th_REG */ /* PHY_cntl2_REG */ #define SW_PHY_AN_MASK 0x0000001F #define SW_PHY_SPD_MASK 0x000003E0 #define SW_PHY_SPD_SHIFT 5 #define SW_PHY_DPX_MASK 0x00007C00 #define SW_PHY_DPX_SHIFT 10 #define SW_FORCE_FC_MASK 0x000F8000 #define SW_FORCE_FC_SHIFT 15 #define SW_PHY_NORMAL_MASK 0x01F00000 #define SW_PHY_NORMAL_SHIFT 20 #define SW_PHY_AUTOMDIX_MASK 0x3E000000 #define SW_PHY_AUTOMDIX_SHIFT 25 #define SW_PHY_REC_MCCAVERAGE 0x40000000 /* PHY_cntl3_REG */ /* Pri_cntl_REG */ /* VLAN_pri_REG */ /* TOS_en_REG */ /* TOS_map0_REG */ /* TOS_map1_REG */ /* Custom_pri1_REG */ /* Custom_pri2_REG */ /* Empty_cnt_REG */ /* Port_cnt_sel_REG */ /* Port_cnt_REG */ /* SW_Int_st_REG & SW_Int_mask_REG */ #define SEND_H_DONE_INT 0x0000001 #define SEND_L_DONE_INT 0x0000002 #define RX_H_DONE_INT 0x0000004 #define RX_L_DONE_INT 0x0000008 #define RX_H_DESC_FULL_INT 0x0000010 #define RX_L_DESC_FULL_INT 0x0000020 #define PORT0_QUE_FULL_INT 0x0000040 #define PORT1_QUE_FULL_INT 0x0000080 #define PORT2_QUE_FULL_INT 0x0000100 #define PORT3_QUE_FULL_INT 0x0000200 #define PORT4_QUE_FULL_INT 0x0000400 #define PORT5_QUE_FULL_INT 0x0000800 #define CPU_QUE_FULL_INT 0x0002000 #define GLOBAL_QUE_FULL_INT 0x0004000 #define MUST_DROP_INT 0x0008000 #define BC_STORM_INT 0x0010000 #define PORT_STATUS_CHANGE_INT 0x0040000 #define INTRUDER_INT 0x0080000 #define WATCHDOG0_EXPR_INT 0x0100000 #define WATCHDOG1_EXPR_INT 0x0200000 #define RX_DESC_ERR_INT 0x0400000 #define SEND_DESC_ERR_INT 0x0800000 #define CPU_HOLD_INT 0x1000000 #define SWITCH_INT_MASK 0x1FDEFFF /* GPIO_conf0_REG */ #define GPIO0_INPUT_MODE 0x00000001 #define GPIO1_INPUT_MODE 0x00000002 #define GPIO2_INPUT_MODE 0x00000004 #define GPIO3_INPUT_MODE 0x00000008 #define GPIO4_INPUT_MODE 0x00000010 #define GPIO5_INPUT_MODE 0x00000020 #define GPIO6_INPUT_MODE 0x00000040 #define GPIO7_INPUT_MODE 0x00000080 #define GPIO0_OUTPUT_MODE 0 #define GPIO1_OUTPUT_MODE 0 #define GPIO2_OUTPUT_MODE 0 #define GPIO3_OUTPUT_MODE 0 #define GPIO4_OUTPUT_MODE 0 #define GPIO5_OUTPUT_MODE 0 #define GPIO6_OUTPUT_MODE 0 #define GPIO7_OUTPUT_MODE 0 #define GPIO0_INPUT_MASK 0x00000100 #define GPIO1_INPUT_MASK 0x00000200 #define GPIO2_INPUT_MASK 0x00000400 #define GPIO3_INPUT_MASK 0x00000800 #define GPIO4_INPUT_MASK 0x00001000 #define GPIO5_INPUT_MASK 0x00002000 #define GPIO6_INPUT_MASK 0x00004000 #define GPIO7_INPUT_MASK 0x00008000 #define GPIO0_OUTPUT_EN 0x00010000 #define GPIO1_OUTPUT_EN 0x00020000 #define GPIO2_OUTPUT_EN 0x00040000 #define GPIO3_OUTPUT_EN 0x00080000 #define GPIO4_OUTPUT_EN 0x00100000 #define GPIO5_OUTPUT_EN 0x00200000 #define GPIO6_OUTPUT_EN 0x00400000 #define GPIO7_OUTPUT_EN 0x00800000 #define GPIO_CONF0_OUTEN_MASK 0x00ff0000 #define GPIO0_OUTPUT_HI 0x01000000 #define GPIO1_OUTPUT_HI 0x02000000 #define GPIO2_OUTPUT_HI 0x04000000 #define GPIO3_OUTPUT_HI 0x08000000 #define GPIO4_OUTPUT_HI 0x10000000 #define GPIO5_OUTPUT_HI 0x20000000 #define GPIO6_OUTPUT_HI 0x40000000 #define GPIO7_OUTPUT_HI 0x80000000 #define GPIO0_OUTPUT_LOW 0 #define GPIO1_OUTPUT_LOW 0 #define GPIO2_OUTPUT_LOW 0 #define GPIO3_OUTPUT_LOW 0 #define GPIO4_OUTPUT_LOW 0 #define GPIO5_OUTPUT_LOW 0 #define GPIO6_OUTPUT_LOW 0 #define GPIO7_OUTPUT_LOW 0 /* GPIO_conf2_REG */ #define EXTIO_WAIT_EN (0x1 << 6) #define EXTIO_CS1_INT1_EN (0x1 << 5) #define EXTIO_CS0_INT0_EN (0x1 << 4) /* Timer_int_REG */ #define SW_TIMER_INT_DISABLE 0x10000 #define SW_TIMER_INT 0x1 /* Timer_REG */ #define SW_TIMER_EN 0x10000 #define SW_TIMER_MASK 0xffff #define SW_TIMER_10MS_TICKS 0x3D09 #define SW_TIMER_1MS_TICKS 0x61A #define SW_TIMER_100US_TICKS 0x9D /* Port0_LED_REG, Port1_LED_REG, Port2_LED_REG, Port3_LED_REG, Port4_LED_REG*/ #define GPIOL_INPUT_MODE 0x00 #define GPIOL_OUTPUT_FLASH 0x01 #define GPIOL_OUTPUT_LOW 0x02 #define GPIOL_OUTPUT_HIGH 0x03 #define GPIOL_LINK_LED 0x04 #define GPIOL_SPEED_LED 0x05 #define GPIOL_DUPLEX_LED 0x06 #define GPIOL_ACT_LED 0x07 #define GPIOL_COL_LED 0x08 #define GPIOL_LINK_ACT_LED 0x09 #define GPIOL_DUPLEX_COL_LED 0x0A #define GPIOL_10MLINK_ACT_LED 0x0B #define GPIOL_100MLINK_ACT_LED 0x0C #define GPIOL_CTRL_MASK 0x0F #define GPIOL_INPUT_MASK 0x7000 #define GPIOL_INPUT_0_MASK 0x1000 #define GPIOL_INPUT_1_MASK 0x2000 #define GPIOL_INPUT_2_MASK 0x4000 #define PORT_LED0_SHIFT 0 #define PORT_LED1_SHIFT 4 #define PORT_LED2_SHIFT 8 #endif #endif /* _IF_ADMSWREG_H_ */ Index: head/sys/mips/adm5120/if_admswvar.h =================================================================== --- head/sys/mips/adm5120/if_admswvar.h (revision 326258) +++ head/sys/mips/adm5120/if_admswvar.h (revision 326259) @@ -1,214 +1,216 @@ /* $NetBSD: if_admswvar.h,v 1.1 2007/03/20 08:52:02 dyoung Exp $ */ /*- + * SPDX-License-Identifier: BSD-3-Clause + * * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko. * 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. * 3. The names of the authors may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS * 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. */ #ifndef _IF_ADMSWVAR_H_ #define _IF_ADMSWVAR_H_ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef INET #include #include #include #include #endif #include #include #include #include #include #include #define MAC_BUFLEN 0x07ff #define ADMSW_NTXHDESC 4 #define ADMSW_NRXHDESC 32 #define ADMSW_NTXLDESC 32 #define ADMSW_NRXLDESC 32 #define ADMSW_NTXHDESC_MASK (ADMSW_NTXHDESC - 1) #define ADMSW_NRXHDESC_MASK (ADMSW_NRXHDESC - 1) #define ADMSW_NTXLDESC_MASK (ADMSW_NTXLDESC - 1) #define ADMSW_NRXLDESC_MASK (ADMSW_NRXLDESC - 1) #define ADMSW_NEXTTXH(x) (((x) + 1) & ADMSW_NTXHDESC_MASK) #define ADMSW_NEXTRXH(x) (((x) + 1) & ADMSW_NRXHDESC_MASK) #define ADMSW_NEXTTXL(x) (((x) + 1) & ADMSW_NTXLDESC_MASK) #define ADMSW_NEXTRXL(x) (((x) + 1) & ADMSW_NRXLDESC_MASK) #define ADMSW_IRQ 9 struct admsw_control_data { /* The transmit descriptors. */ struct admsw_desc acd_txhdescs[ADMSW_NTXHDESC]; /* The receive descriptors. */ struct admsw_desc acd_rxhdescs[ADMSW_NRXHDESC]; /* The transmit descriptors. */ struct admsw_desc acd_txldescs[ADMSW_NTXLDESC]; /* The receive descriptors. */ struct admsw_desc acd_rxldescs[ADMSW_NRXLDESC]; }; #define ADMSW_CDOFF(x) offsetof(struct admsw_control_data, x) #define ADMSW_CDTXHOFF(x) ADMSW_CDOFF(acd_txhdescs[(x)]) #define ADMSW_CDTXLOFF(x) ADMSW_CDOFF(acd_txldescs[(x)]) #define ADMSW_CDRXHOFF(x) ADMSW_CDOFF(acd_rxhdescs[(x)]) #define ADMSW_CDRXLOFF(x) ADMSW_CDOFF(acd_rxldescs[(x)]) struct admsw_descsoft { struct mbuf *ds_mbuf; bus_dmamap_t ds_dmamap; /* Up to 2 segments */ uint32_t ds_addr[2]; uint32_t ds_len[2]; uint32_t ds_nsegs; }; /* * Software state per device. */ struct admsw_softc { device_t sc_dev; /* generic device information */ uint8_t sc_enaddr[ETHER_ADDR_LEN]; bus_dma_tag_t sc_control_dmat; /* bus DMA tag for control structs*/ bus_dma_tag_t sc_bufs_dmat; /* bus DMA tag for buffers */ struct ifmedia sc_ifmedia[SW_DEVS]; int ndevs; /* number of IFF_RUNNING interfaces */ struct ifnet *sc_ifnet[SW_DEVS]; struct callout sc_watchdog; int sc_timer; /* Ethernet common data */ void *sc_ih; /* interrupt cookie */ struct resource *irq_res; struct resource *mem_res; bus_dmamap_t sc_cddmamap; /* control data DMA map */ uint32_t sc_cddma; struct admsw_control_data *sc_control_data; struct admsw_descsoft sc_txhsoft[ADMSW_NTXHDESC]; struct admsw_descsoft sc_rxhsoft[ADMSW_NRXHDESC]; struct admsw_descsoft sc_txlsoft[ADMSW_NTXLDESC]; struct admsw_descsoft sc_rxlsoft[ADMSW_NRXLDESC]; #define sc_txhdescs sc_control_data->acd_txhdescs #define sc_rxhdescs sc_control_data->acd_rxhdescs #define sc_txldescs sc_control_data->acd_txldescs #define sc_rxldescs sc_control_data->acd_rxldescs int sc_txfree; /* number of free Tx descriptors */ int sc_txnext; /* next Tx descriptor to use */ int sc_txdirty; /* first dirty Tx descriptor */ int sc_rxptr; /* next ready Rx descriptor */ }; #define ADMSW_CDTXHADDR(sc, x) ((sc)->sc_cddma + ADMSW_CDTXHOFF((x))) #define ADMSW_CDTXLADDR(sc, x) ((sc)->sc_cddma + ADMSW_CDTXLOFF((x))) #define ADMSW_CDRXHADDR(sc, x) ((sc)->sc_cddma + ADMSW_CDRXHOFF((x))) #define ADMSW_CDRXLADDR(sc, x) ((sc)->sc_cddma + ADMSW_CDRXLOFF((x))) #define ADMSW_CDTXHSYNC(sc, x, ops) \ bus_dmamap_sync((sc)->sc_control_dmat, (sc)->sc_cddmamap, (ops)) #define ADMSW_CDTXLSYNC(sc, x, ops) \ bus_dmamap_sync((sc)->sc_control_dmat, (sc)->sc_cddmamap, (ops)) #define ADMSW_CDRXHSYNC(sc, x, ops) \ bus_dmamap_sync((sc)->sc_control_dmat, (sc)->sc_cddmamap, (ops)) #define ADMSW_CDRXLSYNC(sc, x, ops) \ bus_dmamap_sync((sc)->sc_control_dmat, (sc)->sc_cddmamap, (ops)) #define ADMSW_INIT_RXHDESC(sc, x) \ do { \ struct admsw_descsoft *__ds = &(sc)->sc_rxhsoft[(x)]; \ struct admsw_desc *__desc = &(sc)->sc_rxhdescs[(x)]; \ struct mbuf *__m = __ds->ds_mbuf; \ \ __m->m_data = __m->m_ext.ext_buf + 2; \ __desc->data = __ds->ds_addr[0] + 2; \ __desc->cntl = 0; \ __desc->len = min(MCLBYTES - 2, MAC_BUFLEN - 2); \ __desc->status = 0; \ if ((x) == ADMSW_NRXHDESC - 1) \ __desc->data |= ADM5120_DMA_RINGEND; \ __desc->data |= ADM5120_DMA_OWN; \ ADMSW_CDRXHSYNC((sc), (x), BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); \ } while (0) #define ADMSW_INIT_RXLDESC(sc, x) \ do { \ struct admsw_descsoft *__ds = &(sc)->sc_rxlsoft[(x)]; \ struct admsw_desc *__desc = &(sc)->sc_rxldescs[(x)]; \ struct mbuf *__m = __ds->ds_mbuf; \ \ __m->m_data = __m->m_ext.ext_buf + 2; \ __desc->data = __ds->ds_addr[0] + 2; \ __desc->cntl = 0; \ __desc->len = min(MCLBYTES - 2, MAC_BUFLEN - 2); \ __desc->status = 0; \ if ((x) == ADMSW_NRXLDESC - 1) \ __desc->data |= ADM5120_DMA_RINGEND; \ __desc->data |= ADM5120_DMA_OWN; \ ADMSW_CDRXLSYNC((sc), (x), BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); \ } while (0) void admwdog_attach(struct admsw_softc *); #endif /* _IF_ADMSWVAR_H_ */ Index: head/sys/mips/adm5120/obio.c =================================================================== --- head/sys/mips/adm5120/obio.c (revision 326258) +++ head/sys/mips/adm5120/obio.c (revision 326259) @@ -1,540 +1,542 @@ /* $NetBSD: obio.c,v 1.11 2003/07/15 00:25:05 lukem Exp $ */ /*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright (c) 2001, 2002, 2003 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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 /* MIPS HW interrupts of IRQ/FIQ respectively */ #define ADM5120_INTR 0 #define ADM5120_FAST_INTR 1 /* Interrupt levels */ #define INTR_IRQ 0 #define INTR_FIQ 1 int irq_priorities[NIRQS] = { INTR_IRQ, /* flash */ INTR_FIQ, /* uart0 */ INTR_FIQ, /* uart1 */ INTR_IRQ, /* ahci */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* admsw */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ }; #define REG_READ(o) *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(ADM5120_BASE_ICU + (o))) #define REG_WRITE(o,v) (REG_READ(o)) = (v) static int obio_activate_resource(device_t, device_t, int, int, struct resource *); static device_t obio_add_child(device_t, u_int, const char *, int); static struct resource * obio_alloc_resource(device_t, device_t, int, int *, rman_res_t, rman_res_t, rman_res_t, u_int); static int obio_attach(device_t); static int obio_deactivate_resource(device_t, device_t, int, int, struct resource *); static struct resource_list * obio_get_resource_list(device_t, device_t); static void obio_hinted_child(device_t, const char *, int); static int obio_intr(void *); static int obio_probe(device_t); static int obio_release_resource(device_t, device_t, int, int, struct resource *); static int obio_setup_intr(device_t, device_t, struct resource *, int, driver_filter_t *, driver_intr_t *, void *, void **); static int obio_teardown_intr(device_t, device_t, struct resource *, void *); static void obio_mask_irq(void *source) { int irq; uint32_t irqmask; uint32_t reg; irq = (int)source; irqmask = 1 << irq; /* disable IRQ */ reg = REG_READ(ICU_DISABLE_REG); REG_WRITE(ICU_DISABLE_REG, (reg | irqmask)); } static void obio_unmask_irq(void *source) { int irq; uint32_t irqmask; uint32_t reg; irq = (int)source; irqmask = 1 << irq; /* disable IRQ */ reg = REG_READ(ICU_DISABLE_REG); REG_WRITE(ICU_DISABLE_REG, (reg & ~irqmask)); } static int obio_probe(device_t dev) { return (BUS_PROBE_NOWILDCARD); } static int obio_attach(device_t dev) { struct obio_softc *sc = device_get_softc(dev); int rid; sc->oba_mem_rman.rm_type = RMAN_ARRAY; sc->oba_mem_rman.rm_descr = "OBIO memeory"; if (rman_init(&sc->oba_mem_rman) != 0 || rman_manage_region(&sc->oba_mem_rman, OBIO_MEM_START, OBIO_MEM_START + OBIO_MEM_SIZE) != 0) panic("obio_attach: failed to set up I/O rman"); sc->oba_irq_rman.rm_type = RMAN_ARRAY; sc->oba_irq_rman.rm_descr = "OBIO IRQ"; if (rman_init(&sc->oba_irq_rman) != 0 || rman_manage_region(&sc->oba_irq_rman, 0, NIRQS-1) != 0) panic("obio_attach: failed to set up IRQ rman"); /* Hook up our interrupt handler. */ if ((sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, ADM5120_INTR, ADM5120_INTR, 1, RF_SHAREABLE | RF_ACTIVE)) == NULL) { device_printf(dev, "unable to allocate IRQ resource\n"); return (ENXIO); } if ((bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC, obio_intr, NULL, sc, &sc->sc_ih))) { device_printf(dev, "WARNING: unable to register interrupt handler\n"); return (ENXIO); } /* Hook up our FAST interrupt handler. */ if ((sc->sc_fast_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, ADM5120_FAST_INTR, ADM5120_FAST_INTR, 1, RF_SHAREABLE | RF_ACTIVE)) == NULL) { device_printf(dev, "unable to allocate IRQ resource\n"); return (ENXIO); } if ((bus_setup_intr(dev, sc->sc_fast_irq, INTR_TYPE_MISC, obio_intr, NULL, sc, &sc->sc_fast_ih))) { device_printf(dev, "WARNING: unable to register interrupt handler\n"); return (ENXIO); } /* disable all interrupts */ REG_WRITE(ICU_ENABLE_REG, ICU_INT_MASK); bus_generic_probe(dev); bus_enumerate_hinted_children(dev); bus_generic_attach(dev); return (0); } static struct resource * obio_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct obio_softc *sc = device_get_softc(bus); struct obio_ivar *ivar = device_get_ivars(child); struct resource *rv; struct resource_list_entry *rle; struct rman *rm; int isdefault, needactivate, passthrough; isdefault = (RMAN_IS_DEFAULT_RANGE(start, end) && count == 1); needactivate = flags & RF_ACTIVE; passthrough = (device_get_parent(child) != bus); rle = NULL; if (passthrough) return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type, rid, start, end, count, flags)); /* * If this is an allocation of the "default" range for a given RID, * and we know what the resources for this device are (ie. they aren't * maintained by a child bus), then work out the start/end values. */ if (isdefault) { rle = resource_list_find(&ivar->resources, type, *rid); if (rle == NULL) return (NULL); if (rle->res != NULL) { panic("%s: resource entry is busy", __func__); } start = rle->start; end = rle->end; count = rle->count; } switch (type) { case SYS_RES_IRQ: rm = &sc->oba_irq_rman; break; case SYS_RES_MEMORY: rm = &sc->oba_mem_rman; break; default: printf("%s: unknown resource type %d\n", __func__, type); return (0); } rv = rman_reserve_resource(rm, start, end, count, flags, child); if (rv == NULL) { printf("%s: could not reserve resource\n", __func__); return (0); } rman_set_rid(rv, *rid); if (needactivate) { if (bus_activate_resource(child, type, *rid, rv)) { printf("%s: could not activate resource\n", __func__); rman_release_resource(rv); return (0); } } return (rv); } static int obio_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { /* * If this is a memory resource, track the direct mapping * in the uncached MIPS KSEG1 segment. */ if (type == SYS_RES_MEMORY) { void *vaddr; vaddr = (void *)MIPS_PHYS_TO_KSEG1((intptr_t)rman_get_start(r)); rman_set_virtual(r, vaddr); rman_set_bustag(r, mips_bus_space_generic); rman_set_bushandle(r, (bus_space_handle_t)vaddr); } return (rman_activate_resource(r)); } static int obio_deactivate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { return (rman_deactivate_resource(r)); } static int obio_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { struct resource_list *rl; struct resource_list_entry *rle; rl = obio_get_resource_list(dev, child); if (rl == NULL) return (EINVAL); rle = resource_list_find(rl, type, rid); if (rle == NULL) return (EINVAL); rman_release_resource(r); rle->res = NULL; return (0); } static int obio_setup_intr(device_t dev, device_t child, struct resource *ires, int flags, driver_filter_t *filt, driver_intr_t *handler, void *arg, void **cookiep) { struct obio_softc *sc = device_get_softc(dev); struct intr_event *event; int irq, error, priority; uint32_t irqmask; irq = rman_get_start(ires); if (irq >= NIRQS) panic("%s: bad irq %d", __func__, irq); event = sc->sc_eventstab[irq]; if (event == NULL) { error = intr_event_create(&event, (void *)irq, 0, irq, obio_mask_irq, obio_unmask_irq, NULL, NULL, "obio intr%d:", irq); sc->sc_eventstab[irq] = event; } else panic("obio: Can't share IRQs"); intr_event_add_handler(event, device_get_nameunit(child), filt, handler, arg, intr_priority(flags), flags, cookiep); irqmask = 1 << irq; priority = irq_priorities[irq]; if (priority == INTR_FIQ) REG_WRITE(ICU_MODE_REG, REG_READ(ICU_MODE_REG) | irqmask); else REG_WRITE(ICU_MODE_REG, REG_READ(ICU_MODE_REG) & ~irqmask); /* enable */ REG_WRITE(ICU_ENABLE_REG, irqmask); obio_unmask_irq((void*)irq); return (0); } static int obio_teardown_intr(device_t dev, device_t child, struct resource *ires, void *cookie) { struct obio_softc *sc = device_get_softc(dev); int irq, result, priority; uint32_t irqmask; irq = rman_get_start(ires); if (irq >= NIRQS) panic("%s: bad irq %d", __func__, irq); if (sc->sc_eventstab[irq] == NULL) panic("Trying to teardown unoccupied IRQ"); irqmask = (1 << irq); priority = irq_priorities[irq]; if (priority == INTR_FIQ) REG_WRITE(ICU_MODE_REG, REG_READ(ICU_MODE_REG) & ~irqmask); else REG_WRITE(ICU_MODE_REG, REG_READ(ICU_MODE_REG) | irqmask); /* disable */ irqmask = REG_READ(ICU_ENABLE_REG); irqmask &= ~(1 << irq); REG_WRITE(ICU_ENABLE_REG, irqmask); result = intr_event_remove_handler(cookie); if (!result) { sc->sc_eventstab[irq] = NULL; } return (result); } static int obio_intr(void *arg) { struct obio_softc *sc = arg; struct intr_event *event; uint32_t irqstat; int irq; irqstat = REG_READ(ICU_FIQ_STATUS_REG); irqstat |= REG_READ(ICU_STATUS_REG); irq = 0; while (irqstat != 0) { if ((irqstat & 1) == 1) { event = sc->sc_eventstab[irq]; if (!event || TAILQ_EMPTY(&event->ie_handlers)) continue; /* TODO: pass frame as an argument*/ /* TODO: log stray interrupt */ intr_event_handle(event, NULL); } irq++; irqstat >>= 1; } return (FILTER_HANDLED); } static void obio_hinted_child(device_t bus, const char *dname, int dunit) { device_t child; long maddr; int msize; int irq; int result; child = BUS_ADD_CHILD(bus, 0, dname, dunit); /* * Set hard-wired resources for hinted child using * specific RIDs. */ resource_long_value(dname, dunit, "maddr", &maddr); resource_int_value(dname, dunit, "msize", &msize); result = bus_set_resource(child, SYS_RES_MEMORY, 0, maddr, msize); if (result != 0) device_printf(bus, "warning: bus_set_resource() failed\n"); if (resource_int_value(dname, dunit, "irq", &irq) == 0) { result = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1); if (result != 0) device_printf(bus, "warning: bus_set_resource() failed\n"); } } static device_t obio_add_child(device_t bus, u_int order, const char *name, int unit) { device_t child; struct obio_ivar *ivar; ivar = malloc(sizeof(struct obio_ivar), M_DEVBUF, M_WAITOK | M_ZERO); resource_list_init(&ivar->resources); child = device_add_child_ordered(bus, order, name, unit); if (child == NULL) { printf("Can't add child %s%d ordered\n", name, unit); return (0); } device_set_ivars(child, ivar); return (child); } /* * Helper routine for bus_generic_rl_get_resource/bus_generic_rl_set_resource * Provides pointer to resource_list for these routines */ static struct resource_list * obio_get_resource_list(device_t dev, device_t child) { struct obio_ivar *ivar; ivar = device_get_ivars(child); return (&(ivar->resources)); } static device_method_t obio_methods[] = { DEVMETHOD(bus_activate_resource, obio_activate_resource), DEVMETHOD(bus_add_child, obio_add_child), DEVMETHOD(bus_alloc_resource, obio_alloc_resource), DEVMETHOD(bus_deactivate_resource, obio_deactivate_resource), DEVMETHOD(bus_get_resource_list, obio_get_resource_list), DEVMETHOD(bus_hinted_child, obio_hinted_child), DEVMETHOD(bus_release_resource, obio_release_resource), DEVMETHOD(bus_setup_intr, obio_setup_intr), DEVMETHOD(bus_teardown_intr, obio_teardown_intr), DEVMETHOD(device_attach, obio_attach), DEVMETHOD(device_probe, obio_probe), DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), {0, 0}, }; static driver_t obio_driver = { "obio", obio_methods, sizeof(struct obio_softc), }; static devclass_t obio_devclass; DRIVER_MODULE(obio, nexus, obio_driver, obio_devclass, 0, 0); Index: head/sys/mips/adm5120/obiovar.h =================================================================== --- head/sys/mips/adm5120/obiovar.h (revision 326258) +++ head/sys/mips/adm5120/obiovar.h (revision 326259) @@ -1,66 +1,68 @@ /* $NetBSD: obiovar.h,v 1.4 2003/06/16 17:40:53 thorpej Exp $ */ /*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright (c) 2002, 2003 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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$ * */ #ifndef _ADM5120_OBIOVAR_H_ #define _ADM5120_OBIOVAR_H_ #include /* Number of IRQs */ #define NIRQS 32 #define OBIO_MEM_START 0x10C00000L #define OBIO_MEM_SIZE 0x1e00000 struct obio_softc { struct rman oba_mem_rman; struct rman oba_irq_rman; struct intr_event *sc_eventstab[NIRQS]; /* IRQ events structs */ struct resource *sc_irq; /* IRQ resource */ void *sc_ih; /* interrupt cookie */ struct resource *sc_fast_irq; /* IRQ resource */ void *sc_fast_ih; /* interrupt cookie */ }; struct obio_ivar { struct resource_list resources; }; #endif /* _ADM5120_OBIOVAR_H_ */ Index: head/sys/mips/adm5120/uart_bus_adm5120.c =================================================================== --- head/sys/mips/adm5120/uart_bus_adm5120.c (revision 326258) +++ head/sys/mips/adm5120/uart_bus_adm5120.c (revision 326259) @@ -1,93 +1,95 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2007 Bruce M. Simpson. * 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 * $Id$ */ /* * Skeleton of this file was based on respective code for ARM * code written by Olivier Houchard. */ /* * XXXMIPS: This file is hacked from arm/... . XXXMIPS here means this file is * experimental and was written for MIPS32 port. */ #include "opt_uart.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "uart_if.h" static int uart_adm5120_probe(device_t dev); extern struct uart_class uart_adm5120_uart_class; static device_method_t uart_adm5120_methods[] = { /* Device interface */ DEVMETHOD(device_probe, uart_adm5120_probe), DEVMETHOD(device_attach, uart_bus_attach), DEVMETHOD(device_detach, uart_bus_detach), { 0, 0 } }; static driver_t uart_adm5120_driver = { uart_driver_name, uart_adm5120_methods, sizeof(struct uart_softc), }; extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs; static int uart_adm5120_probe(device_t dev) { struct uart_softc *sc; sc = device_get_softc(dev); sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs); sc->sc_class = &uart_adm5120_uart_class; bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas)); return (uart_bus_probe(dev, 0, 0, 0, 0, 0)); } DRIVER_MODULE(uart, obio, uart_adm5120_driver, uart_devclass, 0, 0); Index: head/sys/mips/adm5120/uart_cpu_adm5120.c =================================================================== --- head/sys/mips/adm5120/uart_cpu_adm5120.c (revision 326258) +++ head/sys/mips/adm5120/uart_cpu_adm5120.c (revision 326259) @@ -1,83 +1,85 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006 Wojciech A. Koszek * 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. * * $Id$ */ /* * Skeleton of this file was based on respective code for ARM * code written by Olivier Houchard. */ /* * XXXMIPS: This file is hacked from arm/... . XXXMIPS here means this file is * experimental and was written for MIPS32 port. */ #include "opt_uart.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include extern struct uart_class uart_adm5120_uart_class; bus_space_tag_t uart_bus_space_io; bus_space_tag_t uart_bus_space_mem; int uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) { return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0); } int uart_cpu_getdev(int devtype, struct uart_devinfo *di) { di->ops = uart_getops(&uart_adm5120_uart_class); di->bas.chan = 0; di->bas.bst = mips_bus_space_generic; di->bas.regshft = 0; di->bas.rclk = 0; di->baudrate = 115200; di->databits = 8; di->stopbits = 1; di->parity = UART_PARITY_NONE; uart_bus_space_io = 0; uart_bus_space_mem = mips_bus_space_generic; di->bas.bsh = MIPS_PHYS_TO_KSEG1(ADM5120_BASE_UART0); return (0); } Index: head/sys/mips/adm5120/uart_dev_adm5120.c =================================================================== --- head/sys/mips/adm5120/uart_dev_adm5120.c (revision 326258) +++ head/sys/mips/adm5120/uart_dev_adm5120.c (revision 326259) @@ -1,480 +1,482 @@ /* $NetBSD: uart.c,v 1.2 2007/03/23 20:05:47 dogcow Exp $ */ /*- + * SPDX-License-Identifier: BSD-3-Clause + * * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko. * Copyright (c) 2007 Oleksandr Tymoshenko. * 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. * 3. The names of the authors may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS * 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 "uart_if.h" /* * Low-level UART interface. */ static int adm5120_uart_probe(struct uart_bas *bas); static void adm5120_uart_init(struct uart_bas *bas, int, int, int, int); static void adm5120_uart_term(struct uart_bas *bas); static void adm5120_uart_putc(struct uart_bas *bas, int); static int adm5120_uart_rxready(struct uart_bas *bas); static int adm5120_uart_getc(struct uart_bas *bas, struct mtx *); static struct uart_ops uart_adm5120_uart_ops = { .probe = adm5120_uart_probe, .init = adm5120_uart_init, .term = adm5120_uart_term, .putc = adm5120_uart_putc, .rxready = adm5120_uart_rxready, .getc = adm5120_uart_getc, }; static int adm5120_uart_probe(struct uart_bas *bas) { return (0); } static void adm5120_uart_init(struct uart_bas *bas, int baudrate, int databits, int stopbits, int parity) { /* TODO: Set parameters for uart, meanwhile stick with 115200N1 */ } static void adm5120_uart_term(struct uart_bas *bas) { } static void adm5120_uart_putc(struct uart_bas *bas, int c) { char chr; chr = c; while (uart_getreg(bas, UART_FR_REG) & UART_FR_TX_FIFO_FULL) ; uart_setreg(bas, UART_DR_REG, c); while (uart_getreg(bas, UART_FR_REG) & UART_FR_BUSY) ; uart_barrier(bas); } static int adm5120_uart_rxready(struct uart_bas *bas) { if (uart_getreg(bas, UART_FR_REG) & UART_FR_RX_FIFO_EMPTY) return (0); return (1); } static int adm5120_uart_getc(struct uart_bas *bas, struct mtx *hwmtx) { int c; uart_lock(hwmtx); while (uart_getreg(bas, UART_FR_REG) & UART_FR_RX_FIFO_EMPTY) { uart_unlock(hwmtx); DELAY(10); uart_lock(hwmtx); } c = uart_getreg(bas, UART_DR_REG); uart_unlock(hwmtx); return (c); } /* * High-level UART interface. */ struct adm5120_uart_softc { struct uart_softc base; }; static int adm5120_uart_bus_attach(struct uart_softc *); static int adm5120_uart_bus_detach(struct uart_softc *); static int adm5120_uart_bus_flush(struct uart_softc *, int); static int adm5120_uart_bus_getsig(struct uart_softc *); static int adm5120_uart_bus_ioctl(struct uart_softc *, int, intptr_t); static int adm5120_uart_bus_ipend(struct uart_softc *); static int adm5120_uart_bus_param(struct uart_softc *, int, int, int, int); static int adm5120_uart_bus_probe(struct uart_softc *); static int adm5120_uart_bus_receive(struct uart_softc *); static int adm5120_uart_bus_setsig(struct uart_softc *, int); static int adm5120_uart_bus_transmit(struct uart_softc *); static void adm5120_uart_bus_grab(struct uart_softc *); static void adm5120_uart_bus_ungrab(struct uart_softc *); static kobj_method_t adm5120_uart_methods[] = { KOBJMETHOD(uart_attach, adm5120_uart_bus_attach), KOBJMETHOD(uart_detach, adm5120_uart_bus_detach), KOBJMETHOD(uart_flush, adm5120_uart_bus_flush), KOBJMETHOD(uart_getsig, adm5120_uart_bus_getsig), KOBJMETHOD(uart_ioctl, adm5120_uart_bus_ioctl), KOBJMETHOD(uart_ipend, adm5120_uart_bus_ipend), KOBJMETHOD(uart_param, adm5120_uart_bus_param), KOBJMETHOD(uart_probe, adm5120_uart_bus_probe), KOBJMETHOD(uart_receive, adm5120_uart_bus_receive), KOBJMETHOD(uart_setsig, adm5120_uart_bus_setsig), KOBJMETHOD(uart_transmit, adm5120_uart_bus_transmit), KOBJMETHOD(uart_grab, adm5120_uart_bus_grab), KOBJMETHOD(uart_ungrab, adm5120_uart_bus_ungrab), { 0, 0 } }; struct uart_class uart_adm5120_uart_class = { "adm5120", adm5120_uart_methods, sizeof(struct adm5120_uart_softc), .uc_ops = &uart_adm5120_uart_ops, .uc_range = 1, /* use hinted range */ .uc_rclk = 62500000, .uc_rshift = 0 }; #define SIGCHG(c, i, s, d) \ if (c) { \ i |= (i & s) ? s : s | d; \ } else { \ i = (i & s) ? (i & ~s) | d : i; \ } /* * Disable TX interrupt. uart should be locked */ static __inline void adm5120_uart_disable_txintr(struct uart_softc *sc) { uint8_t cr; cr = uart_getreg(&sc->sc_bas, UART_CR_REG); cr &= ~UART_CR_TX_INT_EN; uart_setreg(&sc->sc_bas, UART_CR_REG, cr); } /* * Enable TX interrupt. uart should be locked */ static __inline void adm5120_uart_enable_txintr(struct uart_softc *sc) { uint8_t cr; cr = uart_getreg(&sc->sc_bas, UART_CR_REG); cr |= UART_CR_TX_INT_EN; uart_setreg(&sc->sc_bas, UART_CR_REG, cr); } static int adm5120_uart_bus_attach(struct uart_softc *sc) { struct uart_bas *bas; struct uart_devinfo *di; bas = &sc->sc_bas; if (sc->sc_sysdev != NULL) { di = sc->sc_sysdev; /* TODO: set parameters from di */ } else { /* TODO: set parameters 115200, 8N1 */ } (void)adm5120_uart_bus_getsig(sc); #if 1 /* Enable FIFO */ uart_setreg(bas, UART_LCR_H_REG, uart_getreg(bas, UART_LCR_H_REG) | UART_LCR_H_FEN); #endif /* Enable interrupts */ uart_setreg(bas, UART_CR_REG, UART_CR_PORT_EN|UART_CR_RX_INT_EN|UART_CR_RX_TIMEOUT_INT_EN| UART_CR_MODEM_STATUS_INT_EN); return (0); } static int adm5120_uart_bus_detach(struct uart_softc *sc) { return (0); } static int adm5120_uart_bus_flush(struct uart_softc *sc, int what) { return (0); } static int adm5120_uart_bus_getsig(struct uart_softc *sc) { uint32_t new, old, sig; uint8_t bes; do { old = sc->sc_hwsig; sig = old; uart_lock(sc->sc_hwmtx); bes = uart_getreg(&sc->sc_bas, UART_FR_REG); uart_unlock(sc->sc_hwmtx); SIGCHG(bes & UART_FR_CTS, sig, SER_CTS, SER_DCTS); SIGCHG(bes & UART_FR_DCD, sig, SER_DCD, SER_DDCD); SIGCHG(bes & UART_FR_DSR, sig, SER_DSR, SER_DDSR); new = sig & ~SER_MASK_DELTA; } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); return (sig); } static int adm5120_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) { struct uart_bas *bas; int baudrate, divisor, error; bas = &sc->sc_bas; error = 0; uart_lock(sc->sc_hwmtx); switch (request) { case UART_IOCTL_BREAK: /* TODO: Send BREAK */ break; case UART_IOCTL_BAUD: divisor = uart_getreg(bas, UART_LCR_M_REG); divisor = (divisor << 8) | uart_getreg(bas, UART_LCR_L_REG); baudrate = bas->rclk / 2 / (divisor + 2); *(int*)data = baudrate; break; default: error = EINVAL; break; } uart_unlock(sc->sc_hwmtx); return (error); } static int adm5120_uart_bus_ipend(struct uart_softc *sc) { struct uart_bas *bas; int ipend; uint8_t ir, fr, rsr; bas = &sc->sc_bas; ipend = 0; uart_lock(sc->sc_hwmtx); ir = uart_getreg(&sc->sc_bas, UART_IR_REG); fr = uart_getreg(&sc->sc_bas, UART_FR_REG); rsr = uart_getreg(&sc->sc_bas, UART_RSR_REG); if (ir & UART_IR_RX_INT) ipend |= SER_INT_RXREADY; if (ir & UART_IR_RX_TIMEOUT_INT) ipend |= SER_INT_RXREADY; if (ir & UART_IR_MODEM_STATUS_INT) ipend |= SER_INT_SIGCHG; if (rsr & UART_RSR_BE) ipend |= SER_INT_BREAK; if (rsr & UART_RSR_OE) ipend |= SER_INT_OVERRUN; if (fr & UART_FR_TX_FIFO_EMPTY) { if (ir & UART_IR_TX_INT) { adm5120_uart_disable_txintr(sc); ipend |= SER_INT_TXIDLE; } } if (ipend) uart_setreg(bas, UART_IR_REG, ir | UART_IR_UICR); uart_unlock(sc->sc_hwmtx); return (ipend); } static int adm5120_uart_bus_param(struct uart_softc *sc, int baudrate, int databits, int stopbits, int parity) { /* TODO: Set parameters for uart, meanwhile stick with 115200 8N1 */ return (0); } static int adm5120_uart_bus_probe(struct uart_softc *sc) { char buf[80]; int error; char ch; error = adm5120_uart_probe(&sc->sc_bas); if (error) return (error); sc->sc_rxfifosz = 16; sc->sc_txfifosz = 16; ch = sc->sc_bas.chan + 'A'; snprintf(buf, sizeof(buf), "adm5120_uart, channel %c", ch); device_set_desc_copy(sc->sc_dev, buf); return (0); } static int adm5120_uart_bus_receive(struct uart_softc *sc) { struct uart_bas *bas; int xc; uint8_t fr, rsr; bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); fr = uart_getreg(bas, UART_FR_REG); while (!(fr & UART_FR_RX_FIFO_EMPTY)) { if (uart_rx_full(sc)) { sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; break; } xc = 0; rsr = uart_getreg(bas, UART_RSR_REG); if (rsr & UART_RSR_FE) xc |= UART_STAT_FRAMERR; if (rsr & UART_RSR_PE) xc |= UART_STAT_PARERR; if (rsr & UART_RSR_OE) xc |= UART_STAT_OVERRUN; xc |= uart_getreg(bas, UART_DR_REG); uart_barrier(bas); uart_rx_put(sc, xc); if (rsr & (UART_RSR_FE | UART_RSR_PE | UART_RSR_OE)) { uart_setreg(bas, UART_ECR_REG, UART_ECR_RSR); uart_barrier(bas); } fr = uart_getreg(bas, UART_FR_REG); } /* Discard everything left in the Rx FIFO. */ while (!(fr & UART_FR_RX_FIFO_EMPTY)) { ( void)uart_getreg(bas, UART_DR_REG); uart_barrier(bas); rsr = uart_getreg(bas, UART_RSR_REG); if (rsr & (UART_RSR_FE | UART_RSR_PE | UART_RSR_OE)) { uart_setreg(bas, UART_ECR_REG, UART_ECR_RSR); uart_barrier(bas); } fr = uart_getreg(bas, UART_FR_REG); } uart_unlock(sc->sc_hwmtx); return (0); } static int adm5120_uart_bus_setsig(struct uart_softc *sc, int sig) { /* TODO: implement (?) */ return (0); } static int adm5120_uart_bus_transmit(struct uart_softc *sc) { struct uart_bas *bas; bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); sc->sc_txbusy = 1; for (int i = 0; i < sc->sc_txdatasz; i++) { if (uart_getreg(bas, UART_FR_REG) & UART_FR_TX_FIFO_FULL) break; uart_setreg(bas, UART_DR_REG, sc->sc_txbuf[i]); } /* Enable TX interrupt */ adm5120_uart_enable_txintr(sc); uart_unlock(sc->sc_hwmtx); return (0); } static void adm5120_uart_bus_grab(struct uart_softc *sc) { /* Enable interrupts - no RX_INT or RX_TIMEOUT */ uart_lock(sc->sc_hwmtx); uart_setreg(&sc->sc_bas, UART_CR_REG, UART_CR_PORT_EN | UART_CR_MODEM_STATUS_INT_EN); uart_unlock(sc->sc_hwmtx); } static void adm5120_uart_bus_ungrab(struct uart_softc *sc) { /* Enable interrupts */ uart_lock(sc->sc_hwmtx); uart_setreg(&sc->sc_bas, UART_CR_REG, UART_CR_PORT_EN|UART_CR_RX_INT_EN|UART_CR_RX_TIMEOUT_INT_EN| UART_CR_MODEM_STATUS_INT_EN); uart_unlock(sc->sc_hwmtx); } Index: head/sys/mips/adm5120/uart_dev_adm5120.h =================================================================== --- head/sys/mips/adm5120/uart_dev_adm5120.h (revision 326258) +++ head/sys/mips/adm5120/uart_dev_adm5120.h (revision 326259) @@ -1,80 +1,82 @@ /* $NetBSD: uart.h,v 1.1 2007/03/20 08:52:02 dyoung Exp $ */ /*- + * SPDX-License-Identifier: BSD-3-Clause + * * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko. * 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. * 3. The names of the authors may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS * 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$ */ #ifndef _ADMUART_H #define _ADMUART_H /* UART registers */ #define UART_DR_REG 0x00 #define UART_RSR_REG 0x04 #define UART_RSR_FE 0x01 #define UART_RSR_PE 0x02 #define UART_RSR_BE 0x04 #define UART_RSR_OE 0x08 #define UART_ECR_REG 0x04 #define UART_ECR_RSR 0x80 #define UART_LCR_H_REG 0x08 #define UART_LCR_H_FEN 0x10 #define UART_LCR_M_REG 0x0c #define UART_LCR_L_REG 0x10 #define UART_CR_REG 0x14 #define UART_CR_PORT_EN 0x01 #define UART_CR_SIREN 0x02 #define UART_CR_SIRLP 0x04 #define UART_CR_MODEM_STATUS_INT_EN 0x08 #define UART_CR_RX_INT_EN 0x10 #define UART_CR_TX_INT_EN 0x20 #define UART_CR_RX_TIMEOUT_INT_EN 0x40 #define UART_CR_LOOPBACK_EN 0x80 #define UART_FR_REG 0x18 #define UART_FR_CTS 0x01 #define UART_FR_DSR 0x02 #define UART_FR_DCD 0x04 #define UART_FR_BUSY 0x08 #define UART_FR_RX_FIFO_EMPTY 0x10 #define UART_FR_TX_FIFO_FULL 0x20 #define UART_FR_RX_FIFO_FULL 0x40 #define UART_FR_TX_FIFO_EMPTY 0x80 #define UART_IR_REG 0x1c #define UART_IR_MODEM_STATUS_INT 0x01 #define UART_IR_RX_INT 0x02 #define UART_IR_TX_INT 0x04 #define UART_IR_RX_TIMEOUT_INT 0x08 #define UART_IR_INT_MASK 0x0f #define UART_IR_UICR 0x80 #define UART_ILPR_REG 0x20 /* UART interrupts */ int uart_cnattach(void); #endif /* _ADMUART_H */ Index: head/sys/mips/alchemy/alchemy_machdep.c =================================================================== --- head/sys/mips/alchemy/alchemy_machdep.c (revision 326258) +++ head/sys/mips/alchemy/alchemy_machdep.c (revision 326259) @@ -1,148 +1,150 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (C) 2007 by Oleksandr Tymoshenko. 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 ``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 HIS RELATIVES 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 MIND, 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 "opt_ddb.h" #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 #include #include #include #include #include extern int *edata; extern int *end; void platform_cpu_init() { /* Nothing special */ } static void mips_init(void) { int i; printf("entry: mips_init()\n"); bootverbose = 1; realmem = btoc(16 << 20); for (i = 0; i < 10; i++) { phys_avail[i] = 0; } /* phys_avail regions are in bytes */ phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end); phys_avail[1] = ctob(realmem); dump_avail[0] = phys_avail[0]; dump_avail[1] = phys_avail[1]; physmem = realmem; init_param1(); init_param2(physmem); mips_cpu_init(); pmap_bootstrap(); mips_proc0_init(); mutex_init(); kdb_init(); #ifdef KDB if (boothowto & RB_KDB) kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); #endif } void platform_reset(void) { __asm __volatile("li $25, 0xbfc00000"); __asm __volatile("j $25"); } void platform_start(__register_t a0 __unused, __register_t a1 __unused, __register_t a2 __unused, __register_t a3 __unused) { vm_offset_t kernend; uint64_t platform_counter_freq = 175 * 1000 * 1000; /* clear the BSS and SBSS segments */ kernend = (vm_offset_t)&end; memset(&edata, 0, kernend - (vm_offset_t)(&edata)); mips_postboot_fixup(); /* Initialize pcpu stuff */ mips_pcpu0_init(); cninit(); mips_init(); /* Set counter_freq for tick_init_params() */ platform_counter_freq = 175 * 1000 * 1000; mips_timer_init_params(platform_counter_freq, 0); } Index: head/sys/mips/alchemy/aureg.h =================================================================== --- head/sys/mips/alchemy/aureg.h (revision 326258) +++ head/sys/mips/alchemy/aureg.h (revision 326259) @@ -1,373 +1,377 @@ /* $NetBSD: aureg.h,v 1.18 2006/10/02 06:44:00 gdamore Exp $ */ -/* +/*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright 2002 Wasabi Systems, Inc. * All rights reserved. * * Written by Simon Burge for Wasabi Systems, Inc. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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$ */ #ifndef _MIPS_ALCHEMY_AUREG_H #define _MIPS_ALCHEMY_AUREG_H /************************************************************************/ /******************** AC97 Controller registers *********************/ /************************************************************************/ #define AC97_BASE 0x10000000 /************************************************************************/ /*********************** USB Host registers *************************/ /************************************************************************/ #define USBH_BASE 0x10100000 #define AU1550_USBH_BASE 0x14020000 #define USBH_ENABLE 0x7fffc #define USBH_SIZE 0x100000 #define AU1550_USBH_ENABLE 0x7ffc #define AU1550_USBH_SIZE 0x60000 /************************************************************************/ /********************** USB Device registers ************************/ /************************************************************************/ #define USBD_BASE 0x10200000 /************************************************************************/ /************************* IRDA registers ***************************/ /************************************************************************/ #define IRDA_BASE 0x10300000 /************************************************************************/ /****************** Interrupt Controller registers ******************/ /************************************************************************/ #define IC0_BASE 0x10400000 #define IC1_BASE 0x11800000 /* * The *_READ registers read the current value of the register * The *_SET registers set to 1 all bits that are written 1 * The *_CLEAR registers clear to zero all bits that are written as 1 */ #define IC_CONFIG0_READ 0x40 /* See table below */ #define IC_CONFIG0_SET 0x40 #define IC_CONFIG0_CLEAR 0x44 #define IC_CONFIG1_READ 0x48 /* See table below */ #define IC_CONFIG1_SET 0x48 #define IC_CONFIG1_CLEAR 0x4c #define IC_CONFIG2_READ 0x50 /* See table below */ #define IC_CONFIG2_SET 0x50 #define IC_CONFIG2_CLEAR 0x54 #define IC_REQUEST0_INT 0x54 /* Show active interrupts on request 0 */ #define IC_SOURCE_READ 0x58 /* Interrupt source */ #define IC_SOURCE_SET 0x58 /* 0 - test bit used as source */ #define IC_SOURCE_CLEAR 0x5c /* 1 - peripheral/GPIO used as source */ #define IC_REQUEST1_INT 0x5c /* Show active interrupts on request 1 */ #define IC_ASSIGN_REQUEST_READ 0x60 /* Assigns the interrupt to one of the */ #define IC_ASSIGN_REQUEST_SET 0x60 /* CPU requests (0 - assign to request 1, */ #define IC_ASSIGN_REQUEST_CLEAR 0x64 /* 1 - assign to request 0) */ #define IC_WAKEUP_READ 0x68 /* Controls whether the interrupt can */ #define IC_WAKEUP_SET 0x68 /* cause a wakeup from IDLE */ #define IC_WAKEUP_CLEAR 0x6c #define IC_MASK_READ 0x70 /* Enables/Disables the interrupt */ #define IC_MASK_SET 0x70 #define IC_MASK_CLEAR 0x74 #define IC_RISING_EDGE 0x78 /* Check/clear rising edge */ #define IC_FALLING_EDGE 0x7c /* Check/clear falling edge */ #define IC_TEST_BIT 0x80 /* single bit source select */ /* * Interrupt Configuration Register Functions * * Cfg2[n] Cfg1[n] Cfg0[n] Function * 0 0 0 Interrupts Disabled * 0 0 1 Rising Edge Enabled * 0 1 0 Falling Edge Enabled * 0 1 1 Rising and Falling Edge Enabled * 1 0 0 Interrupts Disabled * 1 0 1 High Level Enabled * 1 1 0 Low Level Enabled * 1 1 1 Both Levels and Both Edges Enabled */ /************************************************************************/ /************* Programable Serial Controller registers **************/ /************************************************************************/ #define PSC0_BASE 0x11A00000 #define PSC1_BASE 0x11B00000 #define PSC2_BASE 0x10A00000 #define PSC3_BASE 0x10B00000 /************************************************************************/ /********************** Ethernet MAC registers **********************/ /************************************************************************/ #define MAC0_BASE 0x10500000 #define MAC1_BASE 0x10510000 #define MACx_SIZE 0x28 #define AU1500_MAC0_BASE 0x11500000 /* Grr, different on Au1500 */ #define AU1500_MAC1_BASE 0x11510000 /* Grr, different on Au1500 */ #define MAC0_ENABLE 0x10520000 #define MAC1_ENABLE 0x10520004 #define MACENx_SIZE 0x04 #define AU1500_MAC0_ENABLE 0x11520000 /* Grr, different on Au1500 */ #define AU1500_MAC1_ENABLE 0x11520004 /* Grr, different on Au1500 */ #define MAC0_DMA_BASE 0x14004000 #define MAC1_DMA_BASE 0x14004200 #define MACx_DMA_SIZE 0x140 /************************************************************************/ /********************** Static Bus registers ************************/ /************************************************************************/ #define STATIC_BUS_BASE 0x14001000 /************************************************************************/ /******************** Secure Digital registers **********************/ /************************************************************************/ #define SD0_BASE 0x10600000 #define SD1_BASE 0x10680000 /************************************************************************/ /************************* I^2S registers ***************************/ /************************************************************************/ #define I2S_BASE 0x11000000 /************************************************************************/ /************************** UART registers **************************/ /************************************************************************/ #define UART0_BASE 0x11100000 #define UART1_BASE 0x11200000 #define UART2_BASE 0x11300000 #define UART3_BASE 0x11400000 /************************************************************************/ /************************* SSI registers ****************************/ /************************************************************************/ #define SSI0_BASE 0x11600000 #define SSI1_BASE 0x11680000 /************************************************************************/ /************************ GPIO2 registers ***************************/ /************************************************************************/ #define GPIO_BASE 0x11900100 /************************************************************************/ /************************ GPIO2 registers ***************************/ /************************************************************************/ #define GPIO2_BASE 0x11700000 /************************************************************************/ /************************* PCI registers ****************************/ /************************************************************************/ #define PCI_BASE 0x14005000 #define PCI_HEADER 0x14005100 #define PCI_MEM_BASE 0x400000000ULL #define PCI_IO_BASE 0x500000000ULL #define PCI_CONFIG_BASE 0x600000000ULL /************************************************************************/ /*********************** PCMCIA registers ***************************/ /************************************************************************/ #define PCMCIA_BASE 0xF00000000ULL /************************************************************************/ /****************** Programmable Counter registers ******************/ /************************************************************************/ #define SYS_BASE 0x11900000 #define PC_BASE SYS_BASE #define PC_TRIM0 0x00 /* PC0 Divide (16 bits) */ #define PC_COUNTER_WRITE0 0x04 /* set PC0 */ #define PC_MATCH0_0 0x08 /* match counter & interrupt */ #define PC_MATCH1_0 0x0c /* match counter & interrupt */ #define PC_MATCH2_0 0x10 /* match counter & interrupt */ #define PC_COUNTER_CONTROL 0x14 /* Programmable Counter Control */ #define CC_E1S 0x00800000 /* Enable PC1 write status */ #define CC_T1S 0x00100000 /* Trim PC1 write status */ #define CC_M21 0x00080000 /* Match 2 of PC1 write status */ #define CC_M11 0x00040000 /* Match 1 of PC1 write status */ #define CC_M01 0x00020000 /* Match 0 of PC1 write status */ #define CC_C1S 0x00010000 /* PC1 write status */ #define CC_BP 0x00004000 /* Bypass OSC (use GPIO1) */ #define CC_EN1 0x00002000 /* Enable PC1 */ #define CC_BT1 0x00001000 /* Bypass Trim on PC1 */ #define CC_EN0 0x00000800 /* Enable PC0 */ #define CC_BT0 0x00000400 /* Bypass Trim on PC0 */ #define CC_EO 0x00000100 /* Enable Oscillator */ #define CC_E0S 0x00000080 /* Enable PC0 write status */ #define CC_32S 0x00000020 /* 32.768kHz OSC status */ #define CC_T0S 0x00000010 /* Trim PC0 write status */ #define CC_M20 0x00000008 /* Match 2 of PC0 write status */ #define CC_M10 0x00000004 /* Match 1 of PC0 write status */ #define CC_M00 0x00000002 /* Match 0 of PC0 write status */ #define CC_C0S 0x00000001 /* PC0 write status */ #define PC_COUNTER_READ_0 0x40 /* get PC0 */ #define PC_TRIM1 0x44 /* PC1 Divide (16 bits) */ #define PC_COUNTER_WRITE1 0x48 /* set PC1 */ #define PC_MATCH0_1 0x4c /* match counter & interrupt */ #define PC_MATCH1_1 0x50 /* match counter & interrupt */ #define PC_MATCH2_1 0x54 /* match counter & interrupt */ #define PC_COUNTER_READ_1 0x58 /* get PC1 */ #define PC_SIZE 0x5c /* size of register set */ #define PC_RATE 32768 /* counter rate is 32.768kHz */ /************************************************************************/ /******************* Frequency Generator Registers ******************/ /************************************************************************/ #define SYS_FREQCTRL0 (SYS_BASE + 0x20) #define SFC_FRDIV2(f) (f<<22) /* 29:22. Freq Divider 2 */ #define SFC_FE2 (1<<21) /* Freq generator output enable 2 */ #define SFC_FS2 (1<<20) /* Freq generator source 2 */ #define SFC_FRDIV1(f) (f<<12) /* 19:12. Freq Divider 1 */ #define SFC_FE1 (1<<11) /* Freq generator output enable 1 */ #define SFC_FS1 (1<<10) /* Freq generator source 1 */ #define SFC_FRDIV0(f) (f<<2) /* 9:2. Freq Divider 0 */ #define SFC_FE0 2 /* Freq generator output enable 0 */ #define SFC_FS0 1 /* Freq generator source 0 */ #define SYS_FREQCTRL1 (SYS_BASE + 0x24) #define SFC_FRDIV5(f) (f<<22) /* 29:22. Freq Divider 5 */ #define SFC_FE5 (1<<21) /* Freq generator output enable 5 */ #define SFC_FS5 (1<<20) /* Freq generator source 5 */ #define SFC_FRDIV4(f) (f<<12) /* 19:12. Freq Divider 4 */ #define SFC_FE4 (1<<11) /* Freq generator output enable 4 */ #define SFC_FS4 (1<<10) /* Freq generator source 4 */ #define SFC_FRDIV3(f) (f<<2) /* 9:2. Freq Divider 3 */ #define SFC_FE3 2 /* Freq generator output enable 3 */ #define SFC_FS3 1 /* Freq generator source 3 */ /************************************************************************/ /****************** Clock Source Control Registers ******************/ /************************************************************************/ #define SYS_CLKSRC (SYS_BASE + 0x28) #define SCS_ME1(n) (n<<27) /* EXTCLK1 Clock Mux input select */ #define SCS_ME0(n) (n<<22) /* EXTCLK0 Clock Mux input select */ #define SCS_MPC(n) (n<<17) /* PCI clock mux input select */ #define SCS_MUH(n) (n<<12) /* USB Host clock mux input select */ #define SCS_MUD(n) (n<<7) /* USB Device clock mux input select */ #define SCS_MEx_AUX 0x1 /* Aux clock */ #define SCS_MEx_FREQ0 0x2 /* FREQ0 */ #define SCS_MEx_FREQ1 0x3 /* FREQ1 */ #define SCS_MEx_FREQ2 0x4 /* FREQ2 */ #define SCS_MEx_FREQ3 0x5 /* FREQ3 */ #define SCS_MEx_FREQ4 0x6 /* FREQ4 */ #define SCS_MEx_FREQ5 0x7 /* FREQ5 */ #define SCS_DE1 (1<<26) /* EXTCLK1 clock divider select */ #define SCS_CE1 (1<<25) /* EXTCLK1 clock select */ #define SCS_DE0 (1<<21) /* EXTCLK0 clock divider select */ #define SCS_CE0 (1<<20) /* EXTCLK0 clock select */ #define SCS_DPC (1<<16) /* PCI clock divider select */ #define SCS_CPC (1<<15) /* PCI clock select */ #define SCS_DUH (1<<11) /* USB Host clock divider select */ #define SCS_CUH (1<<10) /* USB Host clock select */ #define SCS_DUD (1<<6) /* USB Device clock divider select */ #define SCS_CUD (1<<5) /* USB Device clock select */ /* * Au1550 bits, needed for PSCs. Note that some bits collide with * earlier parts. On Au1550, USB clocks (both device and host) are * shared with PSC2, and must be configured for 48MHz. DBAU1550 YAMON * does this by default. Also, EXTCLK0 is shared with PSC3. DBAU1550 * YAMON does not configure any clocks besides PSC2. */ #define SCS_MP3(n) (n<<22) /* psc3_intclock mux */ #define SCS_DP3 (1<<21) /* psc3_intclock divider */ #define SCS_CP3 (1<<20) /* psc3_intclock select */ #define SCS_MP1(n) (n<<12) /* psc1_intclock mux */ #define SCS_DP1 (1<<11) /* psc1_intclock divider */ #define SCS_CP1 (1<<10) /* psc1_intclock select */ #define SCS_MP0(n) (n<<7) /* psc0_intclock mux */ #define SCS_DP0 (1<<6) /* psc0_intclock divider */ #define SCS_CP0 (1<<5) /* psc0_intclock seelct */ #define SCS_MP2(n) (n<<2) /* psc2_intclock mux */ #define SCS_DP2 (1<<1) /* psc2_intclock divider */ #define SCS_CP2 (1<<0) /* psc2_intclock select */ /************************************************************************/ /*************************** PIN Function *****************************/ /************************************************************************/ #define SYS_PINFUNC (SYS_BASE + 0x2c) #define SPF_PSC3_MASK (7<<20) #define SPF_PSC3_AC97 (0<<17) /* select AC97/SPI */ #define SPF_PSC3_I2S (1<<17) /* select I2S */ #define SPF_PSC3_SMBUS (3<<17) /* select SMbus */ #define SPF_PSC3_GPIO (7<<17) /* select gpio215:211 */ #define SPF_PSC2_MASK (7<<17) #define SPF_PSC2_AC97 (0<<17) /* select AC97/SPI */ #define SPF_PSC2_I2S (1<<17) /* select I2S */ #define SPF_PSC2_SMBUS (3<<17) /* select SMbus */ #define SPF_PSC2_GPIO (7<<17) /* select gpio210:206*/ #define SPF_CS (1<<16) /* extclk0 or 32kHz osc */ #define SPF_USB (1<<15) /* host or device usb otg */ #define SPF_U3T (1<<14) /* uart3 tx or gpio23 */ #define SPF_U1R (1<<13) /* uart1 rx or gpio22 */ #define SPF_U1T (1<<12) /* uart1 tx or gpio21 */ #define SPF_EX1 (1<<10) /* gpio3 or extclk1 */ #define SPF_EX0 (1<<9) /* gpio2 or extclk0/32kHz osc*/ #define SPF_U3 (1<<7) /* gpio14:9 or uart3 */ #define SPF_MBSa (1<<5) /* must be set */ #define SPF_NI2 (1<<4) /* enet1 or gpio28:24 */ #define SPF_U0 (1<<3) /* uart0 or gpio20 */ #define SPF_MBSb (1<<2) /* must be set */ #define SPF_S1 (1<<1) /* gpio17 or psc1_sync1 */ #define SPF_S0 (1<<0) /* gpio16 or psc0_sync1 */ /************************************************************************/ /*************************** PLL Control *****************************/ /************************************************************************/ #define SYS_CPUPLL (SYS_BASE + 0x60) #define SYS_AUXPLL (SYS_BASE + 0x64) #endif /* _MIPS_ALCHEMY_AUREG_H */ Index: head/sys/mips/alchemy/obio.c =================================================================== --- head/sys/mips/alchemy/obio.c (revision 326258) +++ head/sys/mips/alchemy/obio.c (revision 326259) @@ -1,532 +1,534 @@ /* $NetBSD: obio.c,v 1.11 2003/07/15 00:25:05 lukem Exp $ */ /*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright (c) 2001, 2002, 2003 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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 /* MIPS HW interrupts of IRQ/FIQ respectively */ #define ADM5120_INTR 0 #define ADM5120_FAST_INTR 1 /* Interrupt levels */ #define INTR_IRQ 0 #define INTR_FIQ 1 int irq_priorities[NIRQS] = { INTR_IRQ, /* flash */ INTR_FIQ, /* uart0 */ INTR_FIQ, /* uart1 */ INTR_IRQ, /* ahci */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* admsw */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ }; #define REG_READ(o) *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(ADM5120_BASE_ICU + (o))) #define REG_WRITE(o,v) (REG_READ(o)) = (v) static int obio_activate_resource(device_t, device_t, int, int, struct resource *); static device_t obio_add_child(device_t, u_int, const char *, int); static struct resource * obio_alloc_resource(device_t, device_t, int, int *, rman_res_t, rman_res_t, rman_res_t, u_int); static int obio_attach(device_t); static int obio_deactivate_resource(device_t, device_t, int, int, struct resource *); static struct resource_list * obio_get_resource_list(device_t, device_t); static void obio_hinted_child(device_t, const char *, int); static int obio_intr(void *); static int obio_probe(device_t); static int obio_release_resource(device_t, device_t, int, int, struct resource *); static int obio_setup_intr(device_t, device_t, struct resource *, int, driver_filter_t *, driver_intr_t *, void *, void **); static int obio_teardown_intr(device_t, device_t, struct resource *, void *); static void obio_mask_irq(void *arg) { /* XXX need to write */ #if 0 unsigned int irq = (unsigned int)arg; int ip_bit, mask, mask_register; /* mask IRQ */ mask_register = ICU_IRQ_MASK_REG(irq); ip_bit = ICU_IP_BIT(irq); mask = ICU_REG_READ(mask_register); ICU_REG_WRITE(mask_register, mask | ip_bit); #endif } static void obio_unmask_irq(void *arg) { /* XXX need to write */ #if 0 unsigned int irq = (unsigned int)arg; int ip_bit, mask, mask_register; /* unmask IRQ */ mask_register = ICU_IRQ_MASK_REG(irq); ip_bit = ICU_IP_BIT(irq); mask = ICU_REG_READ(mask_register); ICU_REG_WRITE(mask_register, mask & ~ip_bit); #endif } static int obio_probe(device_t dev) { return (BUS_PROBE_NOWILDCARD); } static int obio_attach(device_t dev) { struct obio_softc *sc = device_get_softc(dev); int rid; sc->oba_mem_rman.rm_type = RMAN_ARRAY; sc->oba_mem_rman.rm_descr = "OBIO memeory"; if (rman_init(&sc->oba_mem_rman) != 0 || rman_manage_region(&sc->oba_mem_rman, OBIO_MEM_START, OBIO_MEM_START + OBIO_MEM_SIZE) != 0) panic("obio_attach: failed to set up I/O rman"); sc->oba_irq_rman.rm_type = RMAN_ARRAY; sc->oba_irq_rman.rm_descr = "OBIO IRQ"; if (rman_init(&sc->oba_irq_rman) != 0 || rman_manage_region(&sc->oba_irq_rman, 0, NIRQS-1) != 0) panic("obio_attach: failed to set up IRQ rman"); /* Hook up our interrupt handler. */ if ((sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, ADM5120_INTR, ADM5120_INTR, 1, RF_SHAREABLE | RF_ACTIVE)) == NULL) { device_printf(dev, "unable to allocate IRQ resource\n"); return (ENXIO); } if ((bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC, obio_intr, NULL, sc, &sc->sc_ih))) { device_printf(dev, "WARNING: unable to register interrupt handler\n"); return (ENXIO); } /* Hook up our FAST interrupt handler. */ if ((sc->sc_fast_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, ADM5120_FAST_INTR, ADM5120_FAST_INTR, 1, RF_SHAREABLE | RF_ACTIVE)) == NULL) { device_printf(dev, "unable to allocate IRQ resource\n"); return (ENXIO); } if ((bus_setup_intr(dev, sc->sc_fast_irq, INTR_TYPE_MISC, obio_intr, NULL, sc, &sc->sc_fast_ih))) { device_printf(dev, "WARNING: unable to register interrupt handler\n"); return (ENXIO); } /* disable all interrupts */ REG_WRITE(ICU_ENABLE_REG, ICU_INT_MASK); bus_generic_probe(dev); bus_enumerate_hinted_children(dev); bus_generic_attach(dev); return (0); } static struct resource * obio_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct obio_softc *sc = device_get_softc(bus); struct obio_ivar *ivar = device_get_ivars(child); struct resource *rv; struct resource_list_entry *rle; struct rman *rm; int isdefault, needactivate, passthrough; isdefault = (RMAN_IS_DEFAULT_RANGE(start, end) && count == 1); needactivate = flags & RF_ACTIVE; passthrough = (device_get_parent(child) != bus); rle = NULL; if (passthrough) return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type, rid, start, end, count, flags)); /* * If this is an allocation of the "default" range for a given RID, * and we know what the resources for this device are (ie. they aren't * maintained by a child bus), then work out the start/end values. */ if (isdefault) { rle = resource_list_find(&ivar->resources, type, *rid); if (rle == NULL) return (NULL); if (rle->res != NULL) { panic("%s: resource entry is busy", __func__); } start = rle->start; end = rle->end; count = rle->count; } switch (type) { case SYS_RES_IRQ: rm = &sc->oba_irq_rman; break; case SYS_RES_MEMORY: rm = &sc->oba_mem_rman; break; default: printf("%s: unknown resource type %d\n", __func__, type); return (0); } rv = rman_reserve_resource(rm, start, end, count, flags, child); if (rv == NULL) { printf("%s: could not reserve resource\n", __func__); return (0); } rman_set_rid(rv, *rid); if (needactivate) { if (bus_activate_resource(child, type, *rid, rv)) { printf("%s: could not activate resource\n", __func__); rman_release_resource(rv); return (0); } } return (rv); } static int obio_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { /* * If this is a memory resource, track the direct mapping * in the uncached MIPS KSEG1 segment. */ if (type == SYS_RES_MEMORY) { void *vaddr; vaddr = (void *)MIPS_PHYS_TO_KSEG1((intptr_t)rman_get_start(r)); rman_set_virtual(r, vaddr); rman_set_bustag(r, mips_bus_space_generic); rman_set_bushandle(r, (bus_space_handle_t)vaddr); } return (rman_activate_resource(r)); } static int obio_deactivate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { return (rman_deactivate_resource(r)); } static int obio_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { struct resource_list *rl; struct resource_list_entry *rle; rl = obio_get_resource_list(dev, child); if (rl == NULL) return (EINVAL); rle = resource_list_find(rl, type, rid); if (rle == NULL) return (EINVAL); rman_release_resource(r); rle->res = NULL; return (0); } static int obio_setup_intr(device_t dev, device_t child, struct resource *ires, int flags, driver_filter_t *filt, driver_intr_t *handler, void *arg, void **cookiep) { struct obio_softc *sc = device_get_softc(dev); struct intr_event *event; int irq, error, priority; uint32_t irqmask; irq = rman_get_start(ires); if (irq >= NIRQS) panic("%s: bad irq %d", __func__, irq); event = sc->sc_eventstab[irq]; if (event == NULL) { error = intr_event_create(&event, (void *)irq, 0, irq, obio_mask_irq, obio_unmask_irq, NULL, NULL, "obio intr%d:", irq); sc->sc_eventstab[irq] = event; } else panic("obio: Can't share IRQs"); intr_event_add_handler(event, device_get_nameunit(child), filt, handler, arg, intr_priority(flags), flags, cookiep); irqmask = 1 << irq; priority = irq_priorities[irq]; if (priority == INTR_FIQ) REG_WRITE(ICU_MODE_REG, REG_READ(ICU_MODE_REG) | irqmask); else REG_WRITE(ICU_MODE_REG, REG_READ(ICU_MODE_REG) & ~irqmask); /* enable */ REG_WRITE(ICU_ENABLE_REG, irqmask); return (0); } static int obio_teardown_intr(device_t dev, device_t child, struct resource *ires, void *cookie) { struct obio_softc *sc = device_get_softc(dev); int irq, result; uint32_t irqmask; irq = rman_get_start(ires); if (irq >= NIRQS) panic("%s: bad irq %d", __func__, irq); if (sc->sc_eventstab[irq] == NULL) panic("Trying to teardown unoccupied IRQ"); irqmask = 1 << irq; /* only used as a mask from here on */ /* disable this irq in HW */ REG_WRITE(ICU_DISABLE_REG, irqmask); result = intr_event_remove_handler(cookie); if (!result) { sc->sc_eventstab[irq] = NULL; } return (result); } static int obio_intr(void *arg) { struct obio_softc *sc = arg; struct intr_event *event; uint32_t irqstat; int irq; irqstat = REG_READ(ICU_FIQ_STATUS_REG); irqstat |= REG_READ(ICU_STATUS_REG); irq = 0; while (irqstat != 0) { if ((irqstat & 1) == 1) { event = sc->sc_eventstab[irq]; if (!event || TAILQ_EMPTY(&event->ie_handlers)) continue; /* TODO: pass frame as an argument*/ /* TODO: log stray interrupt */ intr_event_handle(event, NULL); } irq++; irqstat >>= 1; } return (FILTER_HANDLED); } static void obio_hinted_child(device_t bus, const char *dname, int dunit) { device_t child; long maddr; int msize; int irq; int result; child = BUS_ADD_CHILD(bus, 0, dname, dunit); /* * Set hard-wired resources for hinted child using * specific RIDs. */ resource_long_value(dname, dunit, "maddr", &maddr); resource_int_value(dname, dunit, "msize", &msize); result = bus_set_resource(child, SYS_RES_MEMORY, 0, maddr, msize); if (result != 0) device_printf(bus, "warning: bus_set_resource() failed\n"); if (resource_int_value(dname, dunit, "irq", &irq) == 0) { result = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1); if (result != 0) device_printf(bus, "warning: bus_set_resource() failed\n"); } } static device_t obio_add_child(device_t bus, u_int order, const char *name, int unit) { device_t child; struct obio_ivar *ivar; ivar = malloc(sizeof(struct obio_ivar), M_DEVBUF, M_WAITOK | M_ZERO); resource_list_init(&ivar->resources); child = device_add_child_ordered(bus, order, name, unit); if (child == NULL) { printf("Can't add child %s%d ordered\n", name, unit); return (0); } device_set_ivars(child, ivar); return (child); } /* * Helper routine for bus_generic_rl_get_resource/bus_generic_rl_set_resource * Provides pointer to resource_list for these routines */ static struct resource_list * obio_get_resource_list(device_t dev, device_t child) { struct obio_ivar *ivar; ivar = device_get_ivars(child); return (&(ivar->resources)); } static device_method_t obio_methods[] = { DEVMETHOD(bus_activate_resource, obio_activate_resource), DEVMETHOD(bus_add_child, obio_add_child), DEVMETHOD(bus_alloc_resource, obio_alloc_resource), DEVMETHOD(bus_deactivate_resource, obio_deactivate_resource), DEVMETHOD(bus_get_resource_list, obio_get_resource_list), DEVMETHOD(bus_hinted_child, obio_hinted_child), DEVMETHOD(bus_release_resource, obio_release_resource), DEVMETHOD(bus_setup_intr, obio_setup_intr), DEVMETHOD(bus_teardown_intr, obio_teardown_intr), DEVMETHOD(device_attach, obio_attach), DEVMETHOD(device_probe, obio_probe), DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), {0, 0}, }; static driver_t obio_driver = { "obio", obio_methods, sizeof(struct obio_softc), }; static devclass_t obio_devclass; DRIVER_MODULE(obio, nexus, obio_driver, obio_devclass, 0, 0); Index: head/sys/mips/alchemy/uart_bus_alchemy.c =================================================================== --- head/sys/mips/alchemy/uart_bus_alchemy.c (revision 326258) +++ head/sys/mips/alchemy/uart_bus_alchemy.c (revision 326259) @@ -1,87 +1,89 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2007 Bruce M. Simpson. * 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 * $Id$ */ /* * Skeleton of this file was based on respective code for ARM * code written by Olivier Houchard. */ #include "opt_uart.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "uart_if.h" static int uart_alchemy_probe(device_t dev); static device_method_t uart_alchemy_methods[] = { /* Device interface */ DEVMETHOD(device_probe, uart_alchemy_probe), DEVMETHOD(device_attach, uart_bus_attach), DEVMETHOD(device_detach, uart_bus_detach), { 0, 0 } }; static driver_t uart_alchemy_driver = { uart_driver_name, uart_alchemy_methods, sizeof(struct uart_softc), }; extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs; static int uart_alchemy_probe(device_t dev) { struct uart_softc *sc; sc = device_get_softc(dev); sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs); sc->sc_class = &uart_ns8250_class; bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas)); return (uart_bus_probe(dev, 0, 0, 0, 0, 0)); } DRIVER_MODULE(uart, obio, uart_alchemy_driver, uart_devclass, 0, 0); Index: head/sys/mips/alchemy/uart_cpu_alchemy.c =================================================================== --- head/sys/mips/alchemy/uart_cpu_alchemy.c (revision 326258) +++ head/sys/mips/alchemy/uart_cpu_alchemy.c (revision 326259) @@ -1,79 +1,81 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006 Wojciech A. Koszek * 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. * * $Id$ */ /* * Skeleton of this file was based on respective code for ARM * code written by Olivier Houchard. */ #include "opt_uart.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include bus_space_tag_t uart_bus_space_io; bus_space_tag_t uart_bus_space_mem; int uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) { return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0); } int uart_cpu_getdev(int devtype, struct uart_devinfo *di) { di->ops = uart_getops(&uart_ns8250_class); di->bas.chan = 0; di->bas.bst = mips_bus_space_generic; di->bas.regshft = 0; di->bas.rclk = 0; di->baudrate = 115200; di->databits = 8; di->stopbits = 1; di->parity = UART_PARITY_NONE; uart_bus_space_io = 0; uart_bus_space_mem = mips_bus_space_generic; di->bas.bsh = MIPS_PHYS_TO_KSEG1(UART0_BASE); return (0); } Index: head/sys/mips/atheros/apb.c =================================================================== --- head/sys/mips/atheros/apb.c (revision 326258) +++ head/sys/mips/atheros/apb.c (revision 326259) @@ -1,537 +1,539 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009, Oleksandr Tymoshenko * 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 unmodified, 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 #define APB_INTR_PMC 5 #undef APB_DEBUG #ifdef APB_DEBUG #define dprintf printf #else #define dprintf(x, arg...) #endif /* APB_DEBUG */ #define DEVTOAPB(dev) ((struct apb_ivar *) device_get_ivars(dev)) static int apb_activate_resource(device_t, device_t, int, int, struct resource *); static device_t apb_add_child(device_t, u_int, const char *, int); static struct resource * apb_alloc_resource(device_t, device_t, int, int *, rman_res_t, rman_res_t, rman_res_t, u_int); static int apb_attach(device_t); static int apb_deactivate_resource(device_t, device_t, int, int, struct resource *); static struct resource_list * apb_get_resource_list(device_t, device_t); static void apb_hinted_child(device_t, const char *, int); static int apb_filter(void *); static int apb_probe(device_t); static int apb_release_resource(device_t, device_t, int, int, struct resource *); static int apb_setup_intr(device_t, device_t, struct resource *, int, driver_filter_t *, driver_intr_t *, void *, void **); static int apb_teardown_intr(device_t, device_t, struct resource *, void *); static void apb_mask_irq(void *source) { unsigned int irq = (unsigned int)source; uint32_t reg; reg = ATH_READ_REG(AR71XX_MISC_INTR_MASK); ATH_WRITE_REG(AR71XX_MISC_INTR_MASK, reg & ~(1 << irq)); } static void apb_unmask_irq(void *source) { uint32_t reg; unsigned int irq = (unsigned int)source; reg = ATH_READ_REG(AR71XX_MISC_INTR_MASK); ATH_WRITE_REG(AR71XX_MISC_INTR_MASK, reg | (1 << irq)); } static int apb_probe(device_t dev) { return (BUS_PROBE_NOWILDCARD); } static int apb_attach(device_t dev) { struct apb_softc *sc = device_get_softc(dev); int rid = 0; device_set_desc(dev, "APB Bus bridge"); sc->apb_mem_rman.rm_type = RMAN_ARRAY; sc->apb_mem_rman.rm_descr = "APB memory window"; if (rman_init(&sc->apb_mem_rman) != 0 || rman_manage_region(&sc->apb_mem_rman, AR71XX_APB_BASE, AR71XX_APB_BASE + AR71XX_APB_SIZE - 1) != 0) panic("apb_attach: failed to set up memory rman"); sc->apb_irq_rman.rm_type = RMAN_ARRAY; sc->apb_irq_rman.rm_descr = "APB IRQ"; if (rman_init(&sc->apb_irq_rman) != 0 || rman_manage_region(&sc->apb_irq_rman, APB_IRQ_BASE, APB_IRQ_END) != 0) panic("apb_attach: failed to set up IRQ rman"); if ((sc->sc_misc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { device_printf(dev, "unable to allocate IRQ resource\n"); return (ENXIO); } if ((bus_setup_intr(dev, sc->sc_misc_irq, INTR_TYPE_MISC, apb_filter, NULL, sc, &sc->sc_misc_ih))) { device_printf(dev, "WARNING: unable to register interrupt handler\n"); return (ENXIO); } bus_generic_probe(dev); bus_enumerate_hinted_children(dev); bus_generic_attach(dev); /* * Unmask performance counter IRQ */ apb_unmask_irq((void*)APB_INTR_PMC); sc->sc_intr_counter[APB_INTR_PMC] = mips_intrcnt_create("apb irq5: pmc"); return (0); } static struct resource * apb_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct apb_softc *sc = device_get_softc(bus); struct apb_ivar *ivar = device_get_ivars(child); struct resource *rv; struct resource_list_entry *rle; struct rman *rm; int isdefault, needactivate, passthrough; isdefault = (RMAN_IS_DEFAULT_RANGE(start, end)); needactivate = flags & RF_ACTIVE; /* * Pass memory requests to nexus device */ passthrough = (device_get_parent(child) != bus); rle = NULL; dprintf("%s: entry (%p, %p, %d, %d, %p, %p, %jd, %d)\n", __func__, bus, child, type, *rid, (void *)(intptr_t)start, (void *)(intptr_t)end, count, flags); if (passthrough) return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type, rid, start, end, count, flags)); /* * If this is an allocation of the "default" range for a given RID, * and we know what the resources for this device are (ie. they aren't * maintained by a child bus), then work out the start/end values. */ if (isdefault) { rle = resource_list_find(&ivar->resources, type, *rid); if (rle == NULL) { return (NULL); } if (rle->res != NULL) { panic("%s: resource entry is busy", __func__); } start = rle->start; end = rle->end; count = rle->count; dprintf("%s: default resource (%p, %p, %ld)\n", __func__, (void *)(intptr_t)start, (void *)(intptr_t)end, count); } switch (type) { case SYS_RES_IRQ: rm = &sc->apb_irq_rman; break; case SYS_RES_MEMORY: rm = &sc->apb_mem_rman; break; default: printf("%s: unknown resource type %d\n", __func__, type); return (0); } rv = rman_reserve_resource(rm, start, end, count, flags, child); if (rv == NULL) { printf("%s: could not reserve resource\n", __func__); return (0); } rman_set_rid(rv, *rid); if (needactivate) { if (bus_activate_resource(child, type, *rid, rv)) { printf("%s: could not activate resource\n", __func__); rman_release_resource(rv); return (0); } } return (rv); } static int apb_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { /* XXX: should we mask/unmask IRQ here? */ return (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), child, type, rid, r)); } static int apb_deactivate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { /* XXX: should we mask/unmask IRQ here? */ return (BUS_DEACTIVATE_RESOURCE(device_get_parent(bus), child, type, rid, r)); } static int apb_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { struct resource_list *rl; struct resource_list_entry *rle; rl = apb_get_resource_list(dev, child); if (rl == NULL) return (EINVAL); rle = resource_list_find(rl, type, rid); if (rle == NULL) return (EINVAL); rman_release_resource(r); rle->res = NULL; return (0); } static int apb_setup_intr(device_t bus, device_t child, struct resource *ires, int flags, driver_filter_t *filt, driver_intr_t *handler, void *arg, void **cookiep) { struct apb_softc *sc = device_get_softc(bus); struct intr_event *event; int irq, error; irq = rman_get_start(ires); if (irq > APB_IRQ_END) panic("%s: bad irq %d", __func__, irq); event = sc->sc_eventstab[irq]; if (event == NULL) { error = intr_event_create(&event, (void *)irq, 0, irq, apb_mask_irq, apb_unmask_irq, NULL, NULL, "apb intr%d:", irq); if (error == 0) { sc->sc_eventstab[irq] = event; sc->sc_intr_counter[irq] = mips_intrcnt_create(event->ie_name); } else return (error); } intr_event_add_handler(event, device_get_nameunit(child), filt, handler, arg, intr_priority(flags), flags, cookiep); mips_intrcnt_setname(sc->sc_intr_counter[irq], event->ie_fullname); apb_unmask_irq((void*)irq); return (0); } static int apb_teardown_intr(device_t dev, device_t child, struct resource *ires, void *cookie) { struct apb_softc *sc = device_get_softc(dev); int irq, result; irq = rman_get_start(ires); if (irq > APB_IRQ_END) panic("%s: bad irq %d", __func__, irq); if (sc->sc_eventstab[irq] == NULL) panic("Trying to teardown unoccupied IRQ"); apb_mask_irq((void*)irq); result = intr_event_remove_handler(cookie); if (!result) sc->sc_eventstab[irq] = NULL; return (result); } static int apb_filter(void *arg) { struct apb_softc *sc = arg; struct intr_event *event; uint32_t reg, irq; struct thread *td; struct trapframe *tf; reg = ATH_READ_REG(AR71XX_MISC_INTR_STATUS); for (irq = 0; irq < APB_NIRQS; irq++) { if (reg & (1 << irq)) { switch (ar71xx_soc) { case AR71XX_SOC_AR7240: case AR71XX_SOC_AR7241: case AR71XX_SOC_AR7242: case AR71XX_SOC_AR9330: case AR71XX_SOC_AR9331: case AR71XX_SOC_AR9341: case AR71XX_SOC_AR9342: case AR71XX_SOC_AR9344: case AR71XX_SOC_QCA9533: case AR71XX_SOC_QCA9533_V2: case AR71XX_SOC_QCA9556: case AR71XX_SOC_QCA9558: /* ACK/clear the given interrupt */ ATH_WRITE_REG(AR71XX_MISC_INTR_STATUS, (1 << irq)); break; default: /* fallthrough */ break; } event = sc->sc_eventstab[irq]; /* always count interrupts; spurious or otherwise */ mips_intrcnt_inc(sc->sc_intr_counter[irq]); if (!event || TAILQ_EMPTY(&event->ie_handlers)) { if (irq == APB_INTR_PMC) { td = PCPU_GET(curthread); tf = td->td_intr_frame; if (pmc_intr) (*pmc_intr)(PCPU_GET(cpuid), tf); continue; } /* Ignore timer interrupts */ if (irq != 0 && irq != 8 && irq != 9 && irq != 10) printf("Stray APB IRQ %d\n", irq); continue; } intr_event_handle(event, PCPU_GET(curthread)->td_intr_frame); } } return (FILTER_HANDLED); } static void apb_hinted_child(device_t bus, const char *dname, int dunit) { device_t child; long maddr; int msize; int irq; int result; int mem_hints_count; child = BUS_ADD_CHILD(bus, 0, dname, dunit); /* * Set hard-wired resources for hinted child using * specific RIDs. */ mem_hints_count = 0; if (resource_long_value(dname, dunit, "maddr", &maddr) == 0) mem_hints_count++; if (resource_int_value(dname, dunit, "msize", &msize) == 0) mem_hints_count++; /* check if all info for mem resource has been provided */ if ((mem_hints_count > 0) && (mem_hints_count < 2)) { printf("Either maddr or msize hint is missing for %s%d\n", dname, dunit); } else if (mem_hints_count) { result = bus_set_resource(child, SYS_RES_MEMORY, 0, maddr, msize); if (result != 0) device_printf(bus, "warning: bus_set_resource() failed\n"); } if (resource_int_value(dname, dunit, "irq", &irq) == 0) { result = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1); if (result != 0) device_printf(bus, "warning: bus_set_resource() failed\n"); } } static device_t apb_add_child(device_t bus, u_int order, const char *name, int unit) { device_t child; struct apb_ivar *ivar; ivar = malloc(sizeof(struct apb_ivar), M_DEVBUF, M_WAITOK | M_ZERO); resource_list_init(&ivar->resources); child = device_add_child_ordered(bus, order, name, unit); if (child == NULL) { printf("Can't add child %s%d ordered\n", name, unit); return (0); } device_set_ivars(child, ivar); return (child); } /* * Helper routine for bus_generic_rl_get_resource/bus_generic_rl_set_resource * Provides pointer to resource_list for these routines */ static struct resource_list * apb_get_resource_list(device_t dev, device_t child) { struct apb_ivar *ivar; ivar = device_get_ivars(child); return (&(ivar->resources)); } static int apb_print_all_resources(device_t dev) { struct apb_ivar *ndev = DEVTOAPB(dev); struct resource_list *rl = &ndev->resources; int retval = 0; if (STAILQ_FIRST(rl)) retval += printf(" at"); retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx"); retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd"); return (retval); } static int apb_print_child(device_t bus, device_t child) { int retval = 0; retval += bus_print_child_header(bus, child); retval += apb_print_all_resources(child); if (device_get_flags(child)) retval += printf(" flags %#x", device_get_flags(child)); retval += printf(" on %s\n", device_get_nameunit(bus)); return (retval); } static device_method_t apb_methods[] = { DEVMETHOD(bus_activate_resource, apb_activate_resource), DEVMETHOD(bus_add_child, apb_add_child), DEVMETHOD(bus_alloc_resource, apb_alloc_resource), DEVMETHOD(bus_deactivate_resource, apb_deactivate_resource), DEVMETHOD(bus_get_resource_list, apb_get_resource_list), DEVMETHOD(bus_hinted_child, apb_hinted_child), DEVMETHOD(bus_release_resource, apb_release_resource), DEVMETHOD(bus_setup_intr, apb_setup_intr), DEVMETHOD(bus_teardown_intr, apb_teardown_intr), DEVMETHOD(device_attach, apb_attach), DEVMETHOD(device_probe, apb_probe), DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), DEVMETHOD(bus_print_child, apb_print_child), DEVMETHOD_END }; static driver_t apb_driver = { "apb", apb_methods, sizeof(struct apb_softc), }; static devclass_t apb_devclass; DRIVER_MODULE(apb, nexus, apb_driver, apb_devclass, 0, 0); Index: head/sys/mips/atheros/apbvar.h =================================================================== --- head/sys/mips/atheros/apbvar.h (revision 326258) +++ head/sys/mips/atheros/apbvar.h (revision 326259) @@ -1,52 +1,54 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009, Oleksandr Tymoshenko * 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 unmodified, 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$ */ #ifndef _APBVAR_H_ #define _APBVAR_H_ #define APB_IRQ_BASE 0 #define APB_IRQ_END 31 #define APB_NIRQS 32 struct apb_softc { struct rman apb_irq_rman; struct rman apb_mem_rman; /* IRQ events structs for child devices */ struct intr_event *sc_eventstab[APB_NIRQS]; mips_intrcnt_t sc_intr_counter[APB_NIRQS]; /* Resources and cookies for MIPS CPU INTs */ struct resource *sc_misc_irq; void *sc_misc_ih; }; struct apb_ivar { struct resource_list resources; }; #endif /* _APBVAR_H_ */ Index: head/sys/mips/atheros/ar71xx_bus_space_reversed.c =================================================================== --- head/sys/mips/atheros/ar71xx_bus_space_reversed.c (revision 326258) +++ head/sys/mips/atheros/ar71xx_bus_space_reversed.c (revision 326259) @@ -1,181 +1,183 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009, Oleksandr Tymoshenko * 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 unmodified, 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 static bs_r_1_proto(reversed); static bs_r_2_proto(reversed); static bs_w_1_proto(reversed); static bs_w_2_proto(reversed); /* * Bus space that handles offsets in word for 1/2 bytes read/write access. * Byte order of values is handled by device drivers itself. */ static struct bus_space bus_space_reversed = { /* cookie */ (void *) 0, /* mapping/unmapping */ generic_bs_map, generic_bs_unmap, generic_bs_subregion, /* allocation/deallocation */ NULL, NULL, /* barrier */ generic_bs_barrier, /* read (single) */ reversed_bs_r_1, reversed_bs_r_2, generic_bs_r_4, NULL, /* read multiple */ generic_bs_rm_1, generic_bs_rm_2, generic_bs_rm_4, NULL, /* read region */ generic_bs_rr_1, generic_bs_rr_2, generic_bs_rr_4, NULL, /* write (single) */ reversed_bs_w_1, reversed_bs_w_2, generic_bs_w_4, NULL, /* write multiple */ generic_bs_wm_1, generic_bs_wm_2, generic_bs_wm_4, NULL, /* write region */ NULL, generic_bs_wr_2, generic_bs_wr_4, NULL, /* set multiple */ NULL, NULL, NULL, NULL, /* set region */ NULL, generic_bs_sr_2, generic_bs_sr_4, NULL, /* copy */ NULL, generic_bs_c_2, NULL, NULL, /* read (single) stream */ generic_bs_r_1, generic_bs_r_2, generic_bs_r_4, NULL, /* read multiple stream */ generic_bs_rm_1, generic_bs_rm_2, generic_bs_rm_4, NULL, /* read region stream */ generic_bs_rr_1, generic_bs_rr_2, generic_bs_rr_4, NULL, /* write (single) stream */ generic_bs_w_1, generic_bs_w_2, generic_bs_w_4, NULL, /* write multiple stream */ generic_bs_wm_1, generic_bs_wm_2, generic_bs_wm_4, NULL, /* write region stream */ NULL, generic_bs_wr_2, generic_bs_wr_4, NULL, }; bus_space_tag_t ar71xx_bus_space_reversed = &bus_space_reversed; static uint8_t reversed_bs_r_1(void *t, bus_space_handle_t h, bus_size_t o) { return readb(h + (o &~ 3) + (3 - (o & 3))); } static void reversed_bs_w_1(void *t, bus_space_handle_t h, bus_size_t o, u_int8_t v) { writeb(h + (o &~ 3) + (3 - (o & 3)), v); } static uint16_t reversed_bs_r_2(void *t, bus_space_handle_t h, bus_size_t o) { return readw(h + (o &~ 3) + (2 - (o & 3))); } static void reversed_bs_w_2(void *t, bus_space_handle_t h, bus_size_t o, uint16_t v) { writew(h + (o &~ 3) + (2 - (o & 3)), v); } Index: head/sys/mips/atheros/ar71xx_bus_space_reversed.h =================================================================== --- head/sys/mips/atheros/ar71xx_bus_space_reversed.h (revision 326258) +++ head/sys/mips/atheros/ar71xx_bus_space_reversed.h (revision 326259) @@ -1,33 +1,37 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009, Oleksandr Tymoshenko * 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 unmodified, 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$ */ #ifndef __AR71XX_BUS_SPACE_REVERSEDH__ #define __AR71XX_BUS_SPACE_REVERSEDH__ extern bus_space_tag_t ar71xx_bus_space_reversed; #endif /* __AR71XX_BUS_SPACE_REVERSEDH__ */ Index: head/sys/mips/atheros/ar71xx_chip.c =================================================================== --- head/sys/mips/atheros/ar71xx_chip.c (revision 326258) +++ head/sys/mips/atheros/ar71xx_chip.c (revision 326259) @@ -1,337 +1,339 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Adrian Chadd * 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 "opt_ddb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* XXX these should replace the current definitions in ar71xxreg.h */ /* XXX perhaps an ar71xx_chip.h header file? */ #define AR71XX_PLL_REG_CPU_CONFIG AR71XX_PLL_CPU_BASE + 0x00 #define AR71XX_PLL_REG_SEC_CONFIG AR71XX_PLL_CPU_BASE + 0x04 #define AR71XX_PLL_REG_ETH0_INT_CLOCK AR71XX_PLL_CPU_BASE + 0x10 #define AR71XX_PLL_REG_ETH1_INT_CLOCK AR71XX_PLL_CPU_BASE + 0x14 #define AR71XX_PLL_DIV_SHIFT 3 #define AR71XX_PLL_DIV_MASK 0x1f #define AR71XX_CPU_DIV_SHIFT 16 #define AR71XX_CPU_DIV_MASK 0x3 #define AR71XX_DDR_DIV_SHIFT 18 #define AR71XX_DDR_DIV_MASK 0x3 #define AR71XX_AHB_DIV_SHIFT 20 #define AR71XX_AHB_DIV_MASK 0x7 /* XXX these shouldn't be in here - this file is a per-chip file */ /* XXX these should be in the top-level ar71xx type, not ar71xx -chip */ uint32_t u_ar71xx_cpu_freq; uint32_t u_ar71xx_ahb_freq; uint32_t u_ar71xx_ddr_freq; uint32_t u_ar71xx_uart_freq; uint32_t u_ar71xx_wdt_freq; uint32_t u_ar71xx_refclk; uint32_t u_ar71xx_mdio_freq; static void ar71xx_chip_detect_mem_size(void) { } static void ar71xx_chip_detect_sys_frequency(void) { uint32_t pll; uint32_t freq; uint32_t div; u_ar71xx_mdio_freq = u_ar71xx_refclk = AR71XX_BASE_FREQ; pll = ATH_READ_REG(AR71XX_PLL_REG_CPU_CONFIG); div = ((pll >> AR71XX_PLL_DIV_SHIFT) & AR71XX_PLL_DIV_MASK) + 1; freq = div * AR71XX_BASE_FREQ; div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1; u_ar71xx_cpu_freq = freq / div; div = ((pll >> AR71XX_DDR_DIV_SHIFT) & AR71XX_DDR_DIV_MASK) + 1; u_ar71xx_ddr_freq = freq / div; div = (((pll >> AR71XX_AHB_DIV_SHIFT) & AR71XX_AHB_DIV_MASK) + 1) * 2; u_ar71xx_ahb_freq = u_ar71xx_cpu_freq / div; u_ar71xx_wdt_freq = u_ar71xx_cpu_freq / div; u_ar71xx_uart_freq = u_ar71xx_cpu_freq / div; } /* * This does not lock the CPU whilst doing the work! */ static void ar71xx_chip_device_stop(uint32_t mask) { uint32_t reg; reg = ATH_READ_REG(AR71XX_RST_RESET); ATH_WRITE_REG(AR71XX_RST_RESET, reg | mask); } static void ar71xx_chip_device_start(uint32_t mask) { uint32_t reg; reg = ATH_READ_REG(AR71XX_RST_RESET); ATH_WRITE_REG(AR71XX_RST_RESET, reg & ~mask); } static int ar71xx_chip_device_stopped(uint32_t mask) { uint32_t reg; reg = ATH_READ_REG(AR71XX_RST_RESET); return ((reg & mask) == mask); } void ar71xx_chip_set_mii_speed(uint32_t unit, uint32_t speed) { uint32_t val, reg, ctrl; switch (unit) { case 0: reg = AR71XX_MII0_CTRL; break; case 1: reg = AR71XX_MII1_CTRL; break; default: printf("%s: invalid MII unit set for arge unit: %d\n", __func__, unit); return; } switch (speed) { case 10: ctrl = MII_CTRL_SPEED_10; break; case 100: ctrl = MII_CTRL_SPEED_100; break; case 1000: ctrl = MII_CTRL_SPEED_1000; break; default: printf("%s: invalid MII speed (%d) set for arge unit: %d\n", __func__, speed, unit); return; } val = ATH_READ_REG(reg); val &= ~(MII_CTRL_SPEED_MASK << MII_CTRL_SPEED_SHIFT); val |= (ctrl & MII_CTRL_SPEED_MASK) << MII_CTRL_SPEED_SHIFT; ATH_WRITE_REG(reg, val); } void ar71xx_chip_set_mii_if(uint32_t unit, uint32_t mii_mode) { uint32_t val, reg, mii_if; switch (unit) { case 0: reg = AR71XX_MII0_CTRL; if (mii_mode == AR71XX_MII_MODE_GMII) mii_if = MII0_CTRL_IF_GMII; else if (mii_mode == AR71XX_MII_MODE_MII) mii_if = MII0_CTRL_IF_MII; else if (mii_mode == AR71XX_MII_MODE_RGMII) mii_if = MII0_CTRL_IF_RGMII; else if (mii_mode == AR71XX_MII_MODE_RMII) mii_if = MII0_CTRL_IF_RMII; else { printf("%s: invalid MII mode (%d) for unit %d\n", __func__, mii_mode, unit); return; } break; case 1: reg = AR71XX_MII1_CTRL; if (mii_mode == AR71XX_MII_MODE_RGMII) mii_if = MII1_CTRL_IF_RGMII; else if (mii_mode == AR71XX_MII_MODE_RMII) mii_if = MII1_CTRL_IF_RMII; else { printf("%s: invalid MII mode (%d) for unit %d\n", __func__, mii_mode, unit); return; } break; default: printf("%s: invalid MII unit set for arge unit: %d\n", __func__, unit); return; } val = ATH_READ_REG(reg); val &= ~(MII_CTRL_IF_MASK << MII_CTRL_IF_SHIFT); val |= (mii_if & MII_CTRL_IF_MASK) << MII_CTRL_IF_SHIFT; ATH_WRITE_REG(reg, val); } /* Speed is either 10, 100 or 1000 */ static void ar71xx_chip_set_pll_ge(int unit, int speed, uint32_t pll) { switch (unit) { case 0: ar71xx_write_pll(AR71XX_PLL_SEC_CONFIG, AR71XX_PLL_ETH_INT0_CLK, pll, AR71XX_PLL_ETH0_SHIFT); break; case 1: ar71xx_write_pll(AR71XX_PLL_SEC_CONFIG, AR71XX_PLL_ETH_INT1_CLK, pll, AR71XX_PLL_ETH1_SHIFT); break; default: printf("%s: invalid PLL set for arge unit: %d\n", __func__, unit); return; } } static void ar71xx_chip_ddr_flush(ar71xx_flush_ddr_id_t id) { switch (id) { case AR71XX_CPU_DDR_FLUSH_GE0: ar71xx_ddr_flush(AR71XX_WB_FLUSH_GE0); break; case AR71XX_CPU_DDR_FLUSH_GE1: ar71xx_ddr_flush(AR71XX_WB_FLUSH_GE1); break; case AR71XX_CPU_DDR_FLUSH_USB: ar71xx_ddr_flush(AR71XX_WB_FLUSH_USB); break; case AR71XX_CPU_DDR_FLUSH_PCIE: ar71xx_ddr_flush(AR71XX_WB_FLUSH_PCI); break; default: printf("%s: invalid DDR flush id (%d)\n", __func__, id); break; } } static uint32_t ar71xx_chip_get_eth_pll(unsigned int mac, int speed) { uint32_t pll; switch (speed) { case 10: pll = PLL_ETH_INT_CLK_10; break; case 100: pll = PLL_ETH_INT_CLK_100; break; case 1000: pll = PLL_ETH_INT_CLK_1000; break; default: printf("%s%d: invalid speed %d\n", __func__, mac, speed); pll = 0; } return (pll); } static void ar71xx_chip_init_usb_peripheral(void) { ar71xx_device_stop(RST_RESET_USB_OHCI_DLL | RST_RESET_USB_HOST | RST_RESET_USB_PHY); DELAY(1000); ar71xx_device_start(RST_RESET_USB_OHCI_DLL | RST_RESET_USB_HOST | RST_RESET_USB_PHY); DELAY(1000); ATH_WRITE_REG(AR71XX_USB_CTRL_CONFIG, USB_CTRL_CONFIG_OHCI_DES_SWAP | USB_CTRL_CONFIG_OHCI_BUF_SWAP | USB_CTRL_CONFIG_EHCI_DES_SWAP | USB_CTRL_CONFIG_EHCI_BUF_SWAP); ATH_WRITE_REG(AR71XX_USB_CTRL_FLADJ, (32 << USB_CTRL_FLADJ_HOST_SHIFT) | (3 << USB_CTRL_FLADJ_A5_SHIFT)); DELAY(1000); } struct ar71xx_cpu_def ar71xx_chip_def = { &ar71xx_chip_detect_mem_size, &ar71xx_chip_detect_sys_frequency, &ar71xx_chip_device_stop, &ar71xx_chip_device_start, &ar71xx_chip_device_stopped, &ar71xx_chip_set_pll_ge, &ar71xx_chip_set_mii_speed, &ar71xx_chip_set_mii_if, &ar71xx_chip_get_eth_pll, &ar71xx_chip_ddr_flush, &ar71xx_chip_init_usb_peripheral, }; Index: head/sys/mips/atheros/ar71xx_chip.h =================================================================== --- head/sys/mips/atheros/ar71xx_chip.h (revision 326258) +++ head/sys/mips/atheros/ar71xx_chip.h (revision 326259) @@ -1,36 +1,38 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Adrian Chadd * 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$ */ #ifndef __AR71XX_CHIP_H__ #define __AR71XX_CHIP_H__ extern struct ar71xx_cpu_def ar71xx_chip_def; extern void ar71xx_chip_set_mii_speed(uint32_t unit, uint32_t speed); extern void ar71xx_chip_set_mii_if(uint32_t unit, uint32_t mii_if); #endif Index: head/sys/mips/atheros/ar71xx_cpudef.h =================================================================== --- head/sys/mips/atheros/ar71xx_cpudef.h (revision 326258) +++ head/sys/mips/atheros/ar71xx_cpudef.h (revision 326259) @@ -1,181 +1,183 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Adrian Chadd * 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$ */ #ifndef __AR71XX_CPUDEF_H__ #define __AR71XX_CPUDEF_H__ typedef enum { AR71XX_CPU_DDR_FLUSH_GE0, AR71XX_CPU_DDR_FLUSH_GE1, AR71XX_CPU_DDR_FLUSH_USB, AR71XX_CPU_DDR_FLUSH_PCIE, AR71XX_CPU_DDR_FLUSH_WMAC, AR71XX_CPU_DDR_FLUSH_PCIE_EP, AR71XX_CPU_DDR_FLUSH_CHECKSUM, } ar71xx_flush_ddr_id_t; struct ar71xx_cpu_def { void (* detect_mem_size) (void); void (* detect_sys_frequency) (void); void (* ar71xx_chip_device_stop) (uint32_t); void (* ar71xx_chip_device_start) (uint32_t); int (* ar71xx_chip_device_stopped) (uint32_t); void (* ar71xx_chip_set_pll_ge) (int, int, uint32_t); void (* ar71xx_chip_set_mii_speed) (uint32_t, uint32_t); void (* ar71xx_chip_set_mii_if) (uint32_t, ar71xx_mii_mode); uint32_t (* ar71xx_chip_get_eth_pll) (unsigned int, int); /* * From Linux - Handling this IRQ is a bit special. * AR71xx - AR71XX_DDR_REG_FLUSH_PCI * AR724x - AR724X_DDR_REG_FLUSH_PCIE * AR91xx - AR91XX_DDR_REG_FLUSH_WMAC * * These are set when STATUSF_IP2 is set in regiser c0. * This flush is done before the IRQ is handled to make * sure the driver correctly sees any memory updates. */ void (* ar71xx_chip_ddr_flush) (ar71xx_flush_ddr_id_t id); /* * The USB peripheral init code is subtly different for * each chip. */ void (* ar71xx_chip_init_usb_peripheral) (void); void (* ar71xx_chip_reset_ethernet_switch) (void); void (* ar71xx_chip_reset_wmac) (void); void (* ar71xx_chip_init_gmac) (void); void (* ar71xx_chip_reset_nfc) (int); void (* ar71xx_chip_gpio_out_configure) (int, uint8_t); }; extern struct ar71xx_cpu_def * ar71xx_cpu_ops; static inline void ar71xx_detect_sys_frequency(void) { ar71xx_cpu_ops->detect_sys_frequency(); } static inline void ar71xx_device_stop(uint32_t mask) { ar71xx_cpu_ops->ar71xx_chip_device_stop(mask); } static inline void ar71xx_device_start(uint32_t mask) { ar71xx_cpu_ops->ar71xx_chip_device_start(mask); } static inline int ar71xx_device_stopped(uint32_t mask) { return ar71xx_cpu_ops->ar71xx_chip_device_stopped(mask); } static inline void ar71xx_device_set_pll_ge(int unit, int speed, uint32_t pll) { ar71xx_cpu_ops->ar71xx_chip_set_pll_ge(unit, speed, pll); } static inline void ar71xx_device_set_mii_speed(int unit, int speed) { ar71xx_cpu_ops->ar71xx_chip_set_mii_speed(unit, speed); } static inline void ar71xx_device_set_mii_if(int unit, ar71xx_mii_mode mii_cfg) { ar71xx_cpu_ops->ar71xx_chip_set_mii_if(unit, mii_cfg); } static inline void ar71xx_device_flush_ddr(ar71xx_flush_ddr_id_t id) { ar71xx_cpu_ops->ar71xx_chip_ddr_flush(id); } static inline uint32_t ar71xx_device_get_eth_pll(unsigned int unit, int speed) { return (ar71xx_cpu_ops->ar71xx_chip_get_eth_pll(unit, speed)); } static inline void ar71xx_init_usb_peripheral(void) { ar71xx_cpu_ops->ar71xx_chip_init_usb_peripheral(); } static inline void ar71xx_reset_ethernet_switch(void) { if (ar71xx_cpu_ops->ar71xx_chip_reset_ethernet_switch) ar71xx_cpu_ops->ar71xx_chip_reset_ethernet_switch(); } static inline void ar71xx_reset_wmac(void) { if (ar71xx_cpu_ops->ar71xx_chip_reset_wmac) ar71xx_cpu_ops->ar71xx_chip_reset_wmac(); } static inline void ar71xx_init_gmac(void) { if (ar71xx_cpu_ops->ar71xx_chip_init_gmac) ar71xx_cpu_ops->ar71xx_chip_init_gmac(); } static inline void ar71xx_reset_nfc(int active) { if (ar71xx_cpu_ops->ar71xx_chip_reset_nfc) ar71xx_cpu_ops->ar71xx_chip_reset_nfc(active); } static inline void ar71xx_gpio_ouput_configure(int gpio, uint8_t func) { if (ar71xx_cpu_ops->ar71xx_chip_gpio_out_configure) ar71xx_cpu_ops->ar71xx_chip_gpio_out_configure(gpio, func); } /* XXX shouldn't be here! */ extern uint32_t u_ar71xx_refclk; extern uint32_t u_ar71xx_cpu_freq; extern uint32_t u_ar71xx_ahb_freq; extern uint32_t u_ar71xx_ddr_freq; extern uint32_t u_ar71xx_uart_freq; extern uint32_t u_ar71xx_wdt_freq; extern uint32_t u_ar71xx_mdio_freq; static inline uint64_t ar71xx_refclk(void) { return u_ar71xx_refclk; } static inline uint64_t ar71xx_cpu_freq(void) { return u_ar71xx_cpu_freq; } static inline uint64_t ar71xx_ahb_freq(void) { return u_ar71xx_ahb_freq; } static inline uint64_t ar71xx_ddr_freq(void) { return u_ar71xx_ddr_freq; } static inline uint64_t ar71xx_uart_freq(void) { return u_ar71xx_uart_freq; } static inline uint64_t ar71xx_wdt_freq(void) { return u_ar71xx_wdt_freq; } static inline uint64_t ar71xx_mdio_freq(void) { return u_ar71xx_mdio_freq; } #endif Index: head/sys/mips/atheros/ar71xx_ehci.c =================================================================== --- head/sys/mips/atheros/ar71xx_ehci.c (revision 326258) +++ head/sys/mips/atheros/ar71xx_ehci.c (revision 326259) @@ -1,291 +1,293 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2008 Sam Leffler. 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 ``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 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. */ /* * AR71XX attachment driver for the USB Enhanced Host Controller. */ #include __FBSDID("$FreeBSD$"); #include "opt_bus.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for stuff in ar71xx_cpudef.h */ #include #include #define EHCI_HC_DEVSTR "AR71XX Integrated USB 2.0 controller" #define EHCI_USBMODE 0x68 /* USB Device mode register */ #define EHCI_UM_CM 0x00000003 /* R/WO Controller Mode */ #define EHCI_UM_CM_HOST 0x3 /* Host Controller */ struct ar71xx_ehci_softc { ehci_softc_t base; /* storage for EHCI code */ }; static device_attach_t ar71xx_ehci_attach; static device_detach_t ar71xx_ehci_detach; bs_r_1_proto(reversed); bs_w_1_proto(reversed); static void ar71xx_ehci_post_reset(struct ehci_softc *ehci_softc) { uint32_t usbmode; /* Force HOST mode */ usbmode = EOREAD4(ehci_softc, EHCI_USBMODE_NOLPM); usbmode &= ~EHCI_UM_CM; usbmode |= EHCI_UM_CM_HOST; EOWRITE4(ehci_softc, EHCI_USBMODE_NOLPM, usbmode); } static int ar71xx_ehci_probe(device_t self) { device_set_desc(self, EHCI_HC_DEVSTR); return (BUS_PROBE_NOWILDCARD); } static void ar71xx_ehci_intr(void *arg) { /* XXX TODO: should really see if this was our interrupt.. */ ar71xx_device_flush_ddr(AR71XX_CPU_DDR_FLUSH_USB); ehci_interrupt(arg); } static int ar71xx_ehci_attach(device_t self) { struct ar71xx_ehci_softc *isc = device_get_softc(self); ehci_softc_t *sc = &isc->base; int err; int rid; /* initialise some bus fields */ sc->sc_bus.parent = self; sc->sc_bus.devices = sc->sc_devices; sc->sc_bus.devices_max = EHCI_MAX_DEVICES; sc->sc_bus.dma_bits = 32; /* get all DMA memory */ if (usb_bus_mem_alloc_all(&sc->sc_bus, USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) { return (ENOMEM); } sc->sc_bus.usbrev = USB_REV_2_0; /* NB: hints fix the memory location and irq */ rid = 0; sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!sc->sc_io_res) { device_printf(self, "Could not map memory\n"); goto error; } /* * Craft special resource for bus space ops that handle * byte-alignment of non-word addresses. */ sc->sc_io_tag = ar71xx_bus_space_reversed; sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); sc->sc_io_size = rman_get_size(sc->sc_io_res); rid = 0; sc->sc_irq_res = bus_alloc_resource_any(self, SYS_RES_IRQ, &rid, RF_ACTIVE | RF_SHAREABLE); if (sc->sc_irq_res == NULL) { device_printf(self, "Could not allocate irq\n"); goto error; } sc->sc_bus.bdev = device_add_child(self, "usbus", -1); if (!sc->sc_bus.bdev) { device_printf(self, "Could not add USB device\n"); goto error; } device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); device_set_desc(sc->sc_bus.bdev, EHCI_HC_DEVSTR); sprintf(sc->sc_vendor, "Atheros"); err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, NULL, ar71xx_ehci_intr, sc, &sc->sc_intr_hdl); if (err) { device_printf(self, "Could not setup irq, %d\n", err); sc->sc_intr_hdl = NULL; goto error; } /* * Arrange to force Host mode, select big-endian byte alignment, * and arrange to not terminate reset operations (the adapter * will ignore it if we do but might as well save a reg write). * Also, the controller has an embedded Transaction Translator * which means port speed must be read from the Port Status * register following a port enable. */ sc->sc_flags = 0; sc->sc_vendor_post_reset = ar71xx_ehci_post_reset; switch (ar71xx_soc) { case AR71XX_SOC_AR7241: case AR71XX_SOC_AR7242: case AR71XX_SOC_AR9130: case AR71XX_SOC_AR9132: case AR71XX_SOC_AR9330: case AR71XX_SOC_AR9331: case AR71XX_SOC_AR9341: case AR71XX_SOC_AR9342: case AR71XX_SOC_AR9344: case AR71XX_SOC_QCA9533: case AR71XX_SOC_QCA9533_V2: case AR71XX_SOC_QCA9556: case AR71XX_SOC_QCA9558: sc->sc_flags |= EHCI_SCFLG_TT | EHCI_SCFLG_NORESTERM; sc->sc_vendor_get_port_speed = ehci_get_port_speed_portsc; break; default: /* fallthrough */ break; } /* * ehci_reset() needs the correct offset to access the host controller * registers. The AR724x/AR913x offsets aren't 0. */ sc->sc_offs = EHCI_CAPLENGTH(EREAD4(sc, EHCI_CAPLEN_HCIVERSION)); (void) ehci_reset(sc); err = ehci_init(sc); if (!err) { err = device_probe_and_attach(sc->sc_bus.bdev); } if (err) { device_printf(self, "USB init failed err=%d\n", err); goto error; } return (0); error: ar71xx_ehci_detach(self); return (ENXIO); } static int ar71xx_ehci_detach(device_t self) { struct ar71xx_ehci_softc *isc = device_get_softc(self); ehci_softc_t *sc = &isc->base; int err; /* during module unload there are lots of children leftover */ device_delete_children(self); if (sc->sc_irq_res && sc->sc_intr_hdl) { /* * only call ehci_detach() after ehci_init() */ ehci_detach(sc); err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); if (err) /* XXX or should we panic? */ device_printf(self, "Could not tear down irq, %d\n", err); sc->sc_intr_hdl = NULL; } if (sc->sc_irq_res) { bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res); sc->sc_irq_res = NULL; } if (sc->sc_io_res) { bus_release_resource(self, SYS_RES_MEMORY, 0, sc->sc_io_res); sc->sc_io_res = NULL; } usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc); return (0); } static device_method_t ehci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ar71xx_ehci_probe), DEVMETHOD(device_attach, ar71xx_ehci_attach), DEVMETHOD(device_detach, ar71xx_ehci_detach), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD_END }; static driver_t ehci_driver = { .name = "ehci", .methods = ehci_methods, .size = sizeof(struct ar71xx_ehci_softc), }; static devclass_t ehci_devclass; DRIVER_MODULE(ehci, nexus, ehci_driver, ehci_devclass, 0, 0); DRIVER_MODULE(ehci, apb, ehci_driver, ehci_devclass, 0, 0); MODULE_DEPEND(ehci, usb, 1, 1, 1); Index: head/sys/mips/atheros/ar71xx_fixup.c =================================================================== --- head/sys/mips/atheros/ar71xx_fixup.c (revision 326258) +++ head/sys/mips/atheros/ar71xx_fixup.c (revision 326259) @@ -1,112 +1,114 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009, Oleksandr Tymoshenko * 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 unmodified, 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 "opt_ar71xx.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcib_if.h" #include #include #include #include #include #include /* * Take a copy of the EEPROM contents and squirrel it away in a firmware. * The SPI flash will eventually cease to be memory-mapped, so we need * to take a copy of this before the SPI driver initialises. */ void ar71xx_pci_slot_create_eeprom_firmware(device_t dev, u_int bus, u_int slot, u_int func, long int flash_addr, int size) { char buf[64]; uint16_t *cal_data = (uint16_t *) MIPS_PHYS_TO_KSEG1(flash_addr); void *eeprom = NULL; const struct firmware *fw = NULL; device_printf(dev, "EEPROM firmware: 0x%lx @ %d bytes\n", flash_addr, size); eeprom = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO); if (! eeprom) { device_printf(dev, "%s: malloc failed for '%s', aborting EEPROM\n", __func__, buf); return; } memcpy(eeprom, cal_data, size); /* * Generate a flash EEPROM 'firmware' from the given memory * region. Since the SPI controller will eventually * go into port-IO mode instead of memory-mapped IO * mode, a copy of the EEPROM contents is required. */ snprintf(buf, sizeof(buf), "%s.%d.bus.%d.%d.%d.eeprom_firmware", device_get_name(dev), device_get_unit(dev), bus, slot, func); fw = firmware_register(buf, eeprom, size, 1, NULL); if (fw == NULL) { device_printf(dev, "%s: firmware_register (%s) failed\n", __func__, buf); free(eeprom, M_DEVBUF); return; } device_printf(dev, "device EEPROM '%s' registered\n", buf); } Index: head/sys/mips/atheros/ar71xx_fixup.h =================================================================== --- head/sys/mips/atheros/ar71xx_fixup.h (revision 326258) +++ head/sys/mips/atheros/ar71xx_fixup.h (revision 326259) @@ -1,36 +1,38 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2012, Adrian Chadd * 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 unmodified, 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$ */ #ifndef __ATHEROS_AR71XX_FIXUP_H__ #define __ATHEROS_AR71XX_FIXUP_H__ extern void ar71xx_pci_slot_create_eeprom_firmware(device_t dev, u_int bus, u_int slot, u_int func, long int flash_addr, int size); #endif /* __ATHEROS_AR71XX_FIXUP_H__ */ Index: head/sys/mips/atheros/ar71xx_gpio.c =================================================================== --- head/sys/mips/atheros/ar71xx_gpio.c (revision 326258) +++ head/sys/mips/atheros/ar71xx_gpio.c (revision 326259) @@ -1,637 +1,639 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009, Oleksandr Tymoshenko * Copyright (c) 2009, Luiz Otavio O Souza. * 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 unmodified, 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. */ /* * GPIO driver for AR71xx */ #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 "gpio_if.h" #define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT) /* * Helpers */ static void ar71xx_gpio_function_enable(struct ar71xx_gpio_softc *sc, uint32_t mask); static void ar71xx_gpio_function_disable(struct ar71xx_gpio_softc *sc, uint32_t mask); static void ar71xx_gpio_pin_configure(struct ar71xx_gpio_softc *sc, struct gpio_pin *pin, uint32_t flags); /* * Driver stuff */ static int ar71xx_gpio_probe(device_t dev); static int ar71xx_gpio_attach(device_t dev); static int ar71xx_gpio_detach(device_t dev); static int ar71xx_gpio_filter(void *arg); static void ar71xx_gpio_intr(void *arg); /* * GPIO interface */ static device_t ar71xx_gpio_get_bus(device_t); static int ar71xx_gpio_pin_max(device_t dev, int *maxpin); static int ar71xx_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps); static int ar71xx_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags); static int ar71xx_gpio_pin_getname(device_t dev, uint32_t pin, char *name); static int ar71xx_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags); static int ar71xx_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value); static int ar71xx_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val); static int ar71xx_gpio_pin_toggle(device_t dev, uint32_t pin); /* * Enable/disable the GPIO function control space. * * This is primarily for the AR71xx, which has SPI CS1/CS2, UART, SLIC, I2S * as GPIO pin options. */ static void ar71xx_gpio_function_enable(struct ar71xx_gpio_softc *sc, uint32_t mask) { /* * XXX TODO: refactor this out into a per-chipset method. */ if (ar71xx_soc == AR71XX_SOC_AR9341 || ar71xx_soc == AR71XX_SOC_AR9342 || ar71xx_soc == AR71XX_SOC_AR9344 || ar71xx_soc == AR71XX_SOC_QCA9533 || ar71xx_soc == AR71XX_SOC_QCA9533_V2 || ar71xx_soc == AR71XX_SOC_QCA9556 || ar71xx_soc == AR71XX_SOC_QCA9558) GPIO_SET_BITS(sc, AR934X_GPIO_REG_FUNC, mask); else GPIO_SET_BITS(sc, AR71XX_GPIO_FUNCTION, mask); } static void ar71xx_gpio_function_disable(struct ar71xx_gpio_softc *sc, uint32_t mask) { /* * XXX TODO: refactor this out into a per-chipset method. */ if (ar71xx_soc == AR71XX_SOC_AR9341 || ar71xx_soc == AR71XX_SOC_AR9342 || ar71xx_soc == AR71XX_SOC_AR9344 || ar71xx_soc == AR71XX_SOC_QCA9533 || ar71xx_soc == AR71XX_SOC_QCA9533_V2 || ar71xx_soc == AR71XX_SOC_QCA9556 || ar71xx_soc == AR71XX_SOC_QCA9558) GPIO_CLEAR_BITS(sc, AR934X_GPIO_REG_FUNC, mask); else GPIO_CLEAR_BITS(sc, AR71XX_GPIO_FUNCTION, mask); } /* * On most platforms, GPIO_OE is a bitmap where the bit set * means "enable output." * * On AR934x and QCA953x, it's the opposite - the bit set means * "input enable". */ static int ar71xx_gpio_oe_is_high(void) { switch (ar71xx_soc) { case AR71XX_SOC_AR9344: case AR71XX_SOC_QCA9533: case AR71XX_SOC_QCA9533_V2: return 0; default: return 1; } } static void ar71xx_gpio_oe_set_output(struct ar71xx_gpio_softc *sc, int b) { uint32_t mask; mask = 1 << b; if (ar71xx_gpio_oe_is_high()) GPIO_SET_BITS(sc, AR71XX_GPIO_OE, mask); else GPIO_CLEAR_BITS(sc, AR71XX_GPIO_OE, mask); } static void ar71xx_gpio_oe_set_input(struct ar71xx_gpio_softc *sc, int b) { uint32_t mask; mask = 1 << b; if (ar71xx_gpio_oe_is_high()) GPIO_CLEAR_BITS(sc, AR71XX_GPIO_OE, mask); else GPIO_SET_BITS(sc, AR71XX_GPIO_OE, mask); } static void ar71xx_gpio_pin_configure(struct ar71xx_gpio_softc *sc, struct gpio_pin *pin, unsigned int flags) { /* * Manage input/output */ if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); if (flags & GPIO_PIN_OUTPUT) { pin->gp_flags |= GPIO_PIN_OUTPUT; ar71xx_gpio_oe_set_output(sc, pin->gp_pin); } else { pin->gp_flags |= GPIO_PIN_INPUT; ar71xx_gpio_oe_set_input(sc, pin->gp_pin); } } } static device_t ar71xx_gpio_get_bus(device_t dev) { struct ar71xx_gpio_softc *sc; sc = device_get_softc(dev); return (sc->busdev); } static int ar71xx_gpio_pin_max(device_t dev, int *maxpin) { switch (ar71xx_soc) { case AR71XX_SOC_AR9130: case AR71XX_SOC_AR9132: *maxpin = AR91XX_GPIO_PINS - 1; break; case AR71XX_SOC_AR7240: case AR71XX_SOC_AR7241: case AR71XX_SOC_AR7242: *maxpin = AR724X_GPIO_PINS - 1; break; case AR71XX_SOC_AR9330: case AR71XX_SOC_AR9331: *maxpin = AR933X_GPIO_COUNT - 1; break; case AR71XX_SOC_AR9341: case AR71XX_SOC_AR9342: case AR71XX_SOC_AR9344: *maxpin = AR934X_GPIO_COUNT - 1; break; case AR71XX_SOC_QCA9533: case AR71XX_SOC_QCA9533_V2: *maxpin = QCA953X_GPIO_COUNT - 1; break; case AR71XX_SOC_QCA9556: case AR71XX_SOC_QCA9558: *maxpin = QCA955X_GPIO_COUNT - 1; break; default: *maxpin = AR71XX_GPIO_PINS - 1; } return (0); } static int ar71xx_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) { struct ar71xx_gpio_softc *sc = device_get_softc(dev); int i; for (i = 0; i < sc->gpio_npins; i++) { if (sc->gpio_pins[i].gp_pin == pin) break; } if (i >= sc->gpio_npins) return (EINVAL); GPIO_LOCK(sc); *caps = sc->gpio_pins[i].gp_caps; GPIO_UNLOCK(sc); return (0); } static int ar71xx_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) { struct ar71xx_gpio_softc *sc = device_get_softc(dev); int i; for (i = 0; i < sc->gpio_npins; i++) { if (sc->gpio_pins[i].gp_pin == pin) break; } if (i >= sc->gpio_npins) return (EINVAL); GPIO_LOCK(sc); *flags = sc->gpio_pins[i].gp_flags; GPIO_UNLOCK(sc); return (0); } static int ar71xx_gpio_pin_getname(device_t dev, uint32_t pin, char *name) { struct ar71xx_gpio_softc *sc = device_get_softc(dev); int i; for (i = 0; i < sc->gpio_npins; i++) { if (sc->gpio_pins[i].gp_pin == pin) break; } if (i >= sc->gpio_npins) return (EINVAL); GPIO_LOCK(sc); memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); GPIO_UNLOCK(sc); return (0); } static int ar71xx_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) { int i; struct ar71xx_gpio_softc *sc = device_get_softc(dev); for (i = 0; i < sc->gpio_npins; i++) { if (sc->gpio_pins[i].gp_pin == pin) break; } if (i >= sc->gpio_npins) return (EINVAL); ar71xx_gpio_pin_configure(sc, &sc->gpio_pins[i], flags); return (0); } static int ar71xx_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) { struct ar71xx_gpio_softc *sc = device_get_softc(dev); int i; for (i = 0; i < sc->gpio_npins; i++) { if (sc->gpio_pins[i].gp_pin == pin) break; } if (i >= sc->gpio_npins) return (EINVAL); if (value) GPIO_WRITE(sc, AR71XX_GPIO_SET, (1 << pin)); else GPIO_WRITE(sc, AR71XX_GPIO_CLEAR, (1 << pin)); return (0); } static int ar71xx_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) { struct ar71xx_gpio_softc *sc = device_get_softc(dev); int i; for (i = 0; i < sc->gpio_npins; i++) { if (sc->gpio_pins[i].gp_pin == pin) break; } if (i >= sc->gpio_npins) return (EINVAL); *val = (GPIO_READ(sc, AR71XX_GPIO_IN) & (1 << pin)) ? 1 : 0; return (0); } static int ar71xx_gpio_pin_toggle(device_t dev, uint32_t pin) { int res, i; struct ar71xx_gpio_softc *sc = device_get_softc(dev); for (i = 0; i < sc->gpio_npins; i++) { if (sc->gpio_pins[i].gp_pin == pin) break; } if (i >= sc->gpio_npins) return (EINVAL); res = (GPIO_READ(sc, AR71XX_GPIO_IN) & (1 << pin)) ? 1 : 0; if (res) GPIO_WRITE(sc, AR71XX_GPIO_CLEAR, (1 << pin)); else GPIO_WRITE(sc, AR71XX_GPIO_SET, (1 << pin)); return (0); } static int ar71xx_gpio_filter(void *arg) { /* TODO: something useful */ return (FILTER_STRAY); } static void ar71xx_gpio_intr(void *arg) { struct ar71xx_gpio_softc *sc = arg; GPIO_LOCK(sc); /* TODO: something useful */ GPIO_UNLOCK(sc); } static int ar71xx_gpio_probe(device_t dev) { device_set_desc(dev, "Atheros AR71XX GPIO driver"); return (0); } static int ar71xx_gpio_attach(device_t dev) { struct ar71xx_gpio_softc *sc = device_get_softc(dev); int i, j, maxpin; int mask, pinon; uint32_t oe; KASSERT((device_get_unit(dev) == 0), ("ar71xx_gpio: Only one gpio module supported")); mtx_init(&sc->gpio_mtx, device_get_nameunit(dev), NULL, MTX_DEF); /* Map control/status registers. */ sc->gpio_mem_rid = 0; sc->gpio_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->gpio_mem_rid, RF_ACTIVE); if (sc->gpio_mem_res == NULL) { device_printf(dev, "couldn't map memory\n"); ar71xx_gpio_detach(dev); return (ENXIO); } if ((sc->gpio_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->gpio_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { device_printf(dev, "unable to allocate IRQ resource\n"); ar71xx_gpio_detach(dev); return (ENXIO); } if ((bus_setup_intr(dev, sc->gpio_irq_res, INTR_TYPE_MISC, ar71xx_gpio_filter, ar71xx_gpio_intr, sc, &sc->gpio_ih))) { device_printf(dev, "WARNING: unable to register interrupt handler\n"); ar71xx_gpio_detach(dev); return (ENXIO); } sc->dev = dev; /* Enable function bits that are required */ if (resource_int_value(device_get_name(dev), device_get_unit(dev), "function_set", &mask) == 0) { device_printf(dev, "function_set: 0x%x\n", mask); ar71xx_gpio_function_enable(sc, mask); } /* Disable function bits that are required */ if (resource_int_value(device_get_name(dev), device_get_unit(dev), "function_clear", &mask) == 0) { device_printf(dev, "function_clear: 0x%x\n", mask); ar71xx_gpio_function_disable(sc, mask); } /* Disable interrupts for all pins. */ GPIO_WRITE(sc, AR71XX_GPIO_INT_MASK, 0); /* Initialise all pins specified in the mask, up to the pin count */ (void) ar71xx_gpio_pin_max(dev, &maxpin); if (resource_int_value(device_get_name(dev), device_get_unit(dev), "pinmask", &mask) != 0) mask = 0; if (resource_int_value(device_get_name(dev), device_get_unit(dev), "pinon", &pinon) != 0) pinon = 0; device_printf(dev, "gpio pinmask=0x%x\n", mask); for (j = 0; j <= maxpin; j++) { if ((mask & (1 << j)) == 0) continue; sc->gpio_npins++; } /* Iniatilize the GPIO pins, keep the loader settings. */ oe = GPIO_READ(sc, AR71XX_GPIO_OE); /* * For AR934x and QCA953x, the meaning of oe is inverted; * so flip it the right way around so we can parse the GPIO * state. */ if (!ar71xx_gpio_oe_is_high()) oe = ~oe; sc->gpio_pins = malloc(sizeof(*sc->gpio_pins) * sc->gpio_npins, M_DEVBUF, M_WAITOK | M_ZERO); for (i = 0, j = 0; j <= maxpin; j++) { if ((mask & (1 << j)) == 0) continue; snprintf(sc->gpio_pins[i].gp_name, GPIOMAXNAME, "pin %d", j); sc->gpio_pins[i].gp_pin = j; sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; if (oe & (1 << j)) sc->gpio_pins[i].gp_flags = GPIO_PIN_OUTPUT; else sc->gpio_pins[i].gp_flags = GPIO_PIN_INPUT; i++; } /* Turn on the hinted pins. */ for (i = 0; i < sc->gpio_npins; i++) { j = sc->gpio_pins[i].gp_pin; if ((pinon & (1 << j)) != 0) { ar71xx_gpio_pin_setflags(dev, j, GPIO_PIN_OUTPUT); ar71xx_gpio_pin_set(dev, j, 1); } } /* * Search through the function hints, in case there's some * overrides such as LNA control. * * hint.gpio.X.func..gpiofunc= * hint.gpio.X.func..gpiomode=1 (for output, default low) */ for (i = 0; i <= maxpin; i++) { char buf[32]; int gpiofunc, gpiomode; snprintf(buf, 32, "func.%d.gpiofunc", i); if (resource_int_value(device_get_name(dev), device_get_unit(dev), buf, &gpiofunc) != 0) continue; /* Get the mode too */ snprintf(buf, 32, "func.%d.gpiomode", i); if (resource_int_value(device_get_name(dev), device_get_unit(dev), buf, &gpiomode) != 0) continue; /* We only handle mode=1 for now */ if (gpiomode != 1) continue; device_printf(dev, "%s: GPIO %d: func=%d, mode=%d\n", __func__, i, gpiofunc, gpiomode); /* Set pin value = 0, so it stays low by default */ oe = GPIO_READ(sc, AR71XX_GPIO_OUT); oe &= ~ (1 << i); GPIO_WRITE(sc, AR71XX_GPIO_OUT, oe); /* Set output */ ar71xx_gpio_oe_set_output(sc, i); /* Finally: Set the output config */ ar71xx_gpio_ouput_configure(i, gpiofunc); } sc->busdev = gpiobus_attach_bus(dev); if (sc->busdev == NULL) { ar71xx_gpio_detach(dev); return (ENXIO); } return (0); } static int ar71xx_gpio_detach(device_t dev) { struct ar71xx_gpio_softc *sc = device_get_softc(dev); KASSERT(mtx_initialized(&sc->gpio_mtx), ("gpio mutex not initialized")); gpiobus_detach_bus(dev); if (sc->gpio_ih) bus_teardown_intr(dev, sc->gpio_irq_res, sc->gpio_ih); if (sc->gpio_irq_res) bus_release_resource(dev, SYS_RES_IRQ, sc->gpio_irq_rid, sc->gpio_irq_res); if (sc->gpio_mem_res) bus_release_resource(dev, SYS_RES_MEMORY, sc->gpio_mem_rid, sc->gpio_mem_res); if (sc->gpio_pins) free(sc->gpio_pins, M_DEVBUF); mtx_destroy(&sc->gpio_mtx); return(0); } static device_method_t ar71xx_gpio_methods[] = { DEVMETHOD(device_probe, ar71xx_gpio_probe), DEVMETHOD(device_attach, ar71xx_gpio_attach), DEVMETHOD(device_detach, ar71xx_gpio_detach), /* GPIO protocol */ DEVMETHOD(gpio_get_bus, ar71xx_gpio_get_bus), DEVMETHOD(gpio_pin_max, ar71xx_gpio_pin_max), DEVMETHOD(gpio_pin_getname, ar71xx_gpio_pin_getname), DEVMETHOD(gpio_pin_getflags, ar71xx_gpio_pin_getflags), DEVMETHOD(gpio_pin_getcaps, ar71xx_gpio_pin_getcaps), DEVMETHOD(gpio_pin_setflags, ar71xx_gpio_pin_setflags), DEVMETHOD(gpio_pin_get, ar71xx_gpio_pin_get), DEVMETHOD(gpio_pin_set, ar71xx_gpio_pin_set), DEVMETHOD(gpio_pin_toggle, ar71xx_gpio_pin_toggle), {0, 0}, }; static driver_t ar71xx_gpio_driver = { "gpio", ar71xx_gpio_methods, sizeof(struct ar71xx_gpio_softc), }; static devclass_t ar71xx_gpio_devclass; DRIVER_MODULE(ar71xx_gpio, apb, ar71xx_gpio_driver, ar71xx_gpio_devclass, 0, 0); Index: head/sys/mips/atheros/ar71xx_gpiovar.h =================================================================== --- head/sys/mips/atheros/ar71xx_gpiovar.h (revision 326258) +++ head/sys/mips/atheros/ar71xx_gpiovar.h (revision 326259) @@ -1,71 +1,73 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009, Oleksandr Tymoshenko * Copyright (c) 2009, Luiz Otavio O Souza. * 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 unmodified, 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$ * */ #ifndef __AR71XX_GPIOVAR_H__ #define __AR71XX_GPIOVAR_H__ #define GPIO_LOCK(_sc) mtx_lock(&(_sc)->gpio_mtx) #define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->gpio_mtx) #define GPIO_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->gpio_mtx, MA_OWNED) /* * register space access macros */ #define GPIO_WRITE(sc, reg, val) do { \ bus_write_4(sc->gpio_mem_res, (reg), (val)); \ } while (0) #define GPIO_READ(sc, reg) bus_read_4(sc->gpio_mem_res, (reg)) #define GPIO_SET_BITS(sc, reg, bits) \ GPIO_WRITE(sc, reg, GPIO_READ(sc, (reg)) | (bits)) #define GPIO_CLEAR_BITS(sc, reg, bits) \ GPIO_WRITE(sc, reg, GPIO_READ(sc, (reg)) & ~(bits)) #define AR71XX_GPIO_PINS 12 #define AR724X_GPIO_PINS 18 #define AR91XX_GPIO_PINS 22 struct ar71xx_gpio_softc { device_t dev; device_t busdev; struct mtx gpio_mtx; struct resource *gpio_mem_res; int gpio_mem_rid; struct resource *gpio_irq_res; int gpio_irq_rid; void *gpio_ih; int gpio_npins; struct gpio_pin *gpio_pins; }; #endif /* __AR71XX_GPIOVAR_H__ */ Index: head/sys/mips/atheros/ar71xx_machdep.c =================================================================== --- head/sys/mips/atheros/ar71xx_machdep.c (revision 326258) +++ head/sys/mips/atheros/ar71xx_machdep.c (revision 326259) @@ -1,482 +1,484 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009 Oleksandr Tymoshenko * 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 "opt_ddb.h" #include "opt_ar71xx.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern char edata[], end[]; /* 4KB static data aread to keep a copy of the bootload env until the dynamic kenv is setup */ char boot1_env[4096]; /* * We get a string in from Redboot with the all the arguments together, * "foo=bar bar=baz". Split them up and save in kenv. */ static void parse_argv(char *str) { char *n, *v; while ((v = strsep(&str, " ")) != NULL) { if (*v == '\0') continue; if (*v == '-') { while (*v != '\0') { v++; switch (*v) { case 'a': boothowto |= RB_ASKNAME; break; case 'd': boothowto |= RB_KDB; break; case 'g': boothowto |= RB_GDB; break; case 's': boothowto |= RB_SINGLE; break; case 'v': boothowto |= RB_VERBOSE; break; } } } else { n = strsep(&v, "="); if (v == NULL) kern_setenv(n, "1"); else kern_setenv(n, v); } } } void platform_cpu_init() { /* Nothing special */ } void platform_reset(void) { ar71xx_device_stop(RST_RESET_FULL_CHIP); /* Wait for reset */ while(1) ; } /* * Obtain the MAC address via the Redboot environment. */ static int ar71xx_redboot_get_macaddr(void) { char *var; int count = 0, i; uint32_t macaddr[ETHER_ADDR_LEN]; uint8_t tmpmac[ETHER_ADDR_LEN]; /* * "ethaddr" is passed via envp on RedBoot platforms * "kmac" is passed via argv on RouterBOOT platforms */ if ((var = kern_getenv("ethaddr")) != NULL || (var = kern_getenv("kmac")) != NULL) { count = sscanf(var, "%x%*c%x%*c%x%*c%x%*c%x%*c%x", &macaddr[0], &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4], &macaddr[5]); if (count < 6) { memset(macaddr, 0, sizeof(macaddr)); } else { for (i = 0; i < ETHER_ADDR_LEN; i++) tmpmac[i] = macaddr[i] & 0xff; (void) ar71xx_mac_addr_init(ar71xx_board_mac_addr, tmpmac, 0, /* offset */ 0); /* is_local */ } freeenv(var); return (0); } return (-1); } #ifdef AR71XX_ENV_ROUTERBOOT /* * RouterBoot gives us the board memory in a command line argument. */ static int ar71xx_routerboot_get_mem(int argc, char **argv) { int i, board_mem; /* * Protect ourselves from garbage in registers. */ if (!MIPS_IS_VALID_PTR(argv)) return (0); for (i = 0; i < argc; i++) { if (argv[i] == NULL) continue; if (strncmp(argv[i], "mem=", 4) == 0) { if (sscanf(argv[i] + 4, "%dM", &board_mem) == 1) return (btoc(board_mem * 1024 * 1024)); } } return (0); } #endif /* * Handle initialising the MAC address from a specific EEPROM * offset. * * This is done during (very) early boot. * * hint.ar71xx.0.eeprom_mac_addr=
* hint.ar71xx.0.eeprom_mac_isascii=<0|1> */ static int ar71xx_platform_read_eeprom_mac(void) { long eeprom_mac_addr = 0; const char *mac; int i, readascii = 0; uint8_t macaddr[ETHER_ADDR_LEN]; if (resource_long_value("ar71xx", 0, "eeprom_mac_addr", &eeprom_mac_addr) != 0) return (-1); /* get a pointer to the EEPROM MAC address */ mac = (const char *) MIPS_PHYS_TO_KSEG1(eeprom_mac_addr); /* Check if it's ASCII or not */ if (resource_int_value("ar71xx", 0, "eeprom_mac_isascii", &readascii) == 0 && readascii == 1) { printf("ar71xx: Overriding MAC from EEPROM (ascii)\n"); for (i = 0; i < 6; i++) { macaddr[i] = strtol(&(mac[i*3]), NULL, 16); } } else { printf("ar71xx: Overriding MAC from EEPROM\n"); for (i = 0; i < 6; i++) { macaddr[i] = mac[i]; } } /* Set the default board MAC */ (void) ar71xx_mac_addr_init(ar71xx_board_mac_addr, macaddr, 0, /* offset */ 0); /* is_local */ printf("ar71xx: Board MAC: %6D\n", ar71xx_board_mac_addr, ":"); return (0); } /* * Populate a kenv hint for the given device based on the given * MAC address and offset. * * Returns 0 if ok, < 0 on error. */ static int ar71xx_platform_set_mac_hint(const char *dev, int unit, const uint8_t *macaddr, int offset, int islocal) { char macstr[32]; uint8_t lclmac[ETHER_ADDR_LEN]; char devstr[32]; /* Initialise the MAC address, plus/minus the offset */ if (ar71xx_mac_addr_init(lclmac, macaddr, offset, islocal) != 0) { return (-1); } /* Turn it into a string */ snprintf(macstr, 32, "%6D", lclmac, ":"); snprintf(devstr, 32, "hint.%s.%d.macaddr", dev, unit); printf(" %s => %s\n", devstr, macstr); /* Call setenv */ if (kern_setenv(devstr, macstr) != 0) { printf("%s: failed to set hint (%s => %s)\n", __func__, devstr, macstr); return (-1); } return (0); } /* * Iterate through the list of boot time hints that populate * a device MAC address hint based on the "board" MAC address. * * ar71xx_mac_map.X.devid= * ar71xx_mac_map.X.unitid= * ar71xx_mac_map.X.offset= * ar71xx_mac_map.X.is_local=<1 or 0> */ static int ar71xx_platform_check_mac_hints(void) { int i; const char *devid; int offset, is_local, unitid; for (i = 0; i < 8; i++) { if (resource_string_value("ar71xx_mac_map", i, "devid", &devid) != 0) break; if (resource_int_value("ar71xx_mac_map", i, "unitid", &unitid) != 0) break; if (resource_int_value("ar71xx_mac_map", i, "offset", &offset) != 0) break; if (resource_int_value("ar71xx_mac_map", i, "is_local", &is_local) != 0) break; printf("ar71xx: devid '%s.%d', MAC offset '%d'\n", devid, unitid, offset); (void) ar71xx_platform_set_mac_hint(devid, unitid, ar71xx_board_mac_addr, offset, is_local); } return (0); } extern char cpu_model[]; void platform_start(__register_t a0 __unused, __register_t a1 __unused, __register_t a2 __unused, __register_t a3 __unused) { uint64_t platform_counter_freq; int argc = 0, i; char **argv = NULL, **envp = NULL; vm_offset_t kernend; /* * clear the BSS and SBSS segments, this should be first call in * the function */ kernend = (vm_offset_t)&end; memset(&edata, 0, kernend - (vm_offset_t)(&edata)); mips_postboot_fixup(); /* Initialize pcpu stuff */ mips_pcpu0_init(); /* * Until some more sensible abstractions for uboot/redboot * environment handling, we have to make this a compile-time * hack. The existing code handles the uboot environment * very incorrectly so we should just ignore initialising * the relevant pointers. */ #ifndef AR71XX_ENV_UBOOT argc = a0; argv = (char**)a1; envp = (char**)a2; #endif /* * Protect ourselves from garbage in registers */ if (MIPS_IS_VALID_PTR(envp)) { for (i = 0; envp[i]; i += 2) { if (strcmp(envp[i], "memsize") == 0) realmem = btoc(strtoul(envp[i+1], NULL, 16)); else if (strcmp(envp[i], "bootverbose") == 0) bootverbose = btoc(strtoul(envp[i+1], NULL, 10)); } } bootverbose = 1; #ifdef AR71XX_ENV_ROUTERBOOT /* * RouterBoot informs the board memory as a command line argument. */ if (realmem == 0) realmem = ar71xx_routerboot_get_mem(argc, argv); #endif /* * Just wild guess. RedBoot let us down and didn't reported * memory size */ if (realmem == 0) realmem = btoc(32*1024*1024); /* * Allow build-time override in case Redboot lies * or in other situations (eg where there's u-boot) * where there isn't (yet) a convienent method of * being told how much RAM is available. * * This happens on at least the Ubiquiti LS-SR71A * board, where redboot says there's 16mb of RAM * but in fact there's 32mb. */ #if defined(AR71XX_REALMEM) realmem = btoc(AR71XX_REALMEM); #endif /* phys_avail regions are in bytes */ phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end); phys_avail[1] = ctob(realmem); dump_avail[0] = 0; dump_avail[1] = phys_avail[1]; physmem = realmem; /* * ns8250 uart code uses DELAY so ticker should be inititalized * before cninit. And tick_init_params refers to hz, so * init_param1 * should be called first. */ init_param1(); /* Detect the system type - this is needed for subsequent chipset-specific calls */ ar71xx_detect_sys_type(); ar71xx_detect_sys_frequency(); platform_counter_freq = ar71xx_cpu_freq(); mips_timer_init_params(platform_counter_freq, 1); cninit(); init_static_kenv(boot1_env, sizeof(boot1_env)); printf("CPU platform: %s\n", ar71xx_get_system_type()); printf("CPU Frequency=%d MHz\n", u_ar71xx_cpu_freq / 1000000); printf("CPU DDR Frequency=%d MHz\n", u_ar71xx_ddr_freq / 1000000); printf("CPU AHB Frequency=%d MHz\n", u_ar71xx_ahb_freq / 1000000); printf("platform frequency: %lld MHz\n", platform_counter_freq / 1000000); printf("CPU reference clock: %d MHz\n", u_ar71xx_refclk / 1000000); printf("CPU MDIO clock: %d MHz\n", u_ar71xx_mdio_freq / 1000000); printf("arguments: \n"); printf(" a0 = %08x\n", a0); printf(" a1 = %08x\n", a1); printf(" a2 = %08x\n", a2); printf(" a3 = %08x\n", a3); strcpy(cpu_model, ar71xx_get_system_type()); /* * XXX this code is very redboot specific. */ printf("Cmd line:"); if (MIPS_IS_VALID_PTR(argv)) { for (i = 0; i < argc; i++) { printf(" %s", argv[i]); parse_argv(argv[i]); } } else printf ("argv is invalid"); printf("\n"); printf("Environment:\n"); if (MIPS_IS_VALID_PTR(envp)) { for (i = 0; envp[i]; i+=2) { printf(" %s = %s\n", envp[i], envp[i+1]); kern_setenv(envp[i], envp[i+1]); } } else printf ("envp is invalid\n"); /* Platform setup */ init_param2(physmem); mips_cpu_init(); pmap_bootstrap(); mips_proc0_init(); mutex_init(); /* * Reset USB devices */ ar71xx_init_usb_peripheral(); /* * Reset internal ethernet switch, if one exists */ ar71xx_reset_ethernet_switch(); /* * Initialise the gmac driver. */ ar71xx_init_gmac(); /* Redboot if_arge MAC address is in the environment */ (void) ar71xx_redboot_get_macaddr(); /* Various other boards need things to come out of EEPROM */ (void) ar71xx_platform_read_eeprom_mac(); /* Initialise the MAC address hint map */ ar71xx_platform_check_mac_hints(); kdb_init(); #ifdef KDB if (boothowto & RB_KDB) kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); #endif } Index: head/sys/mips/atheros/ar71xx_ohci.c =================================================================== --- head/sys/mips/atheros/ar71xx_ohci.c (revision 326258) +++ head/sys/mips/atheros/ar71xx_ohci.c (revision 326259) @@ -1,220 +1,222 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009, Oleksandr Tymoshenko * 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 unmodified, 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 #include /* for stuff in ar71xx_cpudef.h */ #include static int ar71xx_ohci_attach(device_t dev); static int ar71xx_ohci_detach(device_t dev); static int ar71xx_ohci_probe(device_t dev); struct ar71xx_ohci_softc { struct ohci_softc sc_ohci; }; static int ar71xx_ohci_probe(device_t dev) { device_set_desc(dev, "AR71XX integrated OHCI controller"); return (BUS_PROBE_DEFAULT); } static void ar71xx_ohci_intr(void *arg) { /* XXX TODO: should really see if this was our interrupt.. */ ar71xx_device_flush_ddr(AR71XX_CPU_DDR_FLUSH_USB); ohci_interrupt(arg); } static int ar71xx_ohci_attach(device_t dev) { struct ar71xx_ohci_softc *sc = device_get_softc(dev); int err; int rid; /* initialise some bus fields */ sc->sc_ohci.sc_bus.parent = dev; sc->sc_ohci.sc_bus.devices = sc->sc_ohci.sc_devices; sc->sc_ohci.sc_bus.devices_max = OHCI_MAX_DEVICES; sc->sc_ohci.sc_bus.dma_bits = 32; /* get all DMA memory */ if (usb_bus_mem_alloc_all(&sc->sc_ohci.sc_bus, USB_GET_DMA_TAG(dev), &ohci_iterate_hw_softc)) { return (ENOMEM); } sc->sc_ohci.sc_dev = dev; rid = 0; sc->sc_ohci.sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (sc->sc_ohci.sc_io_res == NULL) { err = ENOMEM; goto error; } sc->sc_ohci.sc_io_tag = rman_get_bustag(sc->sc_ohci.sc_io_res); sc->sc_ohci.sc_io_hdl = rman_get_bushandle(sc->sc_ohci.sc_io_res); sc->sc_ohci.sc_io_size = rman_get_size(sc->sc_ohci.sc_io_res); rid = 0; sc->sc_ohci.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (sc->sc_ohci.sc_irq_res == NULL) { err = ENOMEM; goto error; } sc->sc_ohci.sc_bus.bdev = device_add_child(dev, "usbus", -1); if (sc->sc_ohci.sc_bus.bdev == NULL) { err = ENOMEM; goto error; } device_set_ivars(sc->sc_ohci.sc_bus.bdev, &sc->sc_ohci.sc_bus); err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, NULL, ar71xx_ohci_intr, sc, &sc->sc_ohci.sc_intr_hdl); if (err) { err = ENXIO; goto error; } strlcpy(sc->sc_ohci.sc_vendor, "Atheros", sizeof(sc->sc_ohci.sc_vendor)); bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, OHCI_CONTROL, 0); err = ohci_init(&sc->sc_ohci); if (!err) err = device_probe_and_attach(sc->sc_ohci.sc_bus.bdev); if (err) goto error; return (0); error: if (err) { ar71xx_ohci_detach(dev); return (err); } return (err); } static int ar71xx_ohci_detach(device_t dev) { struct ar71xx_ohci_softc *sc = device_get_softc(dev); /* during module unload there are lots of children leftover */ device_delete_children(dev); /* * Put the controller into reset, then disable clocks and do * the MI tear down. We have to disable the clocks/hardware * after we do the rest of the teardown. We also disable the * clocks in the opposite order we acquire them, but that * doesn't seem to be absolutely necessary. We free up the * clocks after we disable them, so the system could, in * theory, reuse them. */ bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, OHCI_CONTROL, 0); if (sc->sc_ohci.sc_intr_hdl) { bus_teardown_intr(dev, sc->sc_ohci.sc_irq_res, sc->sc_ohci.sc_intr_hdl); sc->sc_ohci.sc_intr_hdl = NULL; } if (sc->sc_ohci.sc_irq_res && sc->sc_ohci.sc_intr_hdl) { /* * only call ohci_detach() after ohci_init() */ ohci_detach(&sc->sc_ohci); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_ohci.sc_irq_res); sc->sc_ohci.sc_irq_res = NULL; } if (sc->sc_ohci.sc_io_res) { bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_ohci.sc_io_res); sc->sc_ohci.sc_io_res = NULL; sc->sc_ohci.sc_io_tag = 0; sc->sc_ohci.sc_io_hdl = 0; } usb_bus_mem_free_all(&sc->sc_ohci.sc_bus, &ohci_iterate_hw_softc); return (0); } static device_method_t ohci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ar71xx_ohci_probe), DEVMETHOD(device_attach, ar71xx_ohci_attach), DEVMETHOD(device_detach, ar71xx_ohci_detach), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD_END }; static driver_t ohci_driver = { .name = "ohci", .methods = ohci_methods, .size = sizeof(struct ar71xx_ohci_softc), }; static devclass_t ohci_devclass; DRIVER_MODULE(ohci, apb, ohci_driver, ohci_devclass, 0, 0); Index: head/sys/mips/atheros/ar71xx_pci.c =================================================================== --- head/sys/mips/atheros/ar71xx_pci.c (revision 326258) +++ head/sys/mips/atheros/ar71xx_pci.c (revision 326259) @@ -1,705 +1,707 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009, Oleksandr Tymoshenko * 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 unmodified, 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 "opt_ar71xx.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcib_if.h" #include #include #include #ifdef AR71XX_ATH_EEPROM #include #endif /* AR71XX_ATH_EEPROM */ #undef AR71XX_PCI_DEBUG #ifdef AR71XX_PCI_DEBUG #define dprintf printf #else #define dprintf(x, arg...) #endif struct mtx ar71xx_pci_mtx; MTX_SYSINIT(ar71xx_pci_mtx, &ar71xx_pci_mtx, "ar71xx PCI space mutex", MTX_SPIN); struct ar71xx_pci_softc { device_t sc_dev; int sc_busno; int sc_baseslot; struct rman sc_mem_rman; struct rman sc_irq_rman; struct intr_event *sc_eventstab[AR71XX_PCI_NIRQS]; mips_intrcnt_t sc_intr_counter[AR71XX_PCI_NIRQS]; struct resource *sc_irq; void *sc_ih; }; static int ar71xx_pci_setup_intr(device_t, device_t, struct resource *, int, driver_filter_t *, driver_intr_t *, void *, void **); static int ar71xx_pci_teardown_intr(device_t, device_t, struct resource *, void *); static int ar71xx_pci_intr(void *); static void ar71xx_pci_mask_irq(void *source) { uint32_t reg; unsigned int irq = (unsigned int)source; /* XXX is the PCI lock required here? */ reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); /* flush */ reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); ATH_WRITE_REG(AR71XX_PCI_INTR_MASK, reg & ~(1 << irq)); } static void ar71xx_pci_unmask_irq(void *source) { uint32_t reg; unsigned int irq = (unsigned int)source; /* XXX is the PCI lock required here? */ reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); ATH_WRITE_REG(AR71XX_PCI_INTR_MASK, reg | (1 << irq)); /* flush */ reg = ATH_READ_REG(AR71XX_PCI_INTR_MASK); } /* * get bitmask for bytes of interest: * 0 - we want this byte, 1 - ignore it. e.g: we read 1 byte * from register 7. Bitmask would be: 0111 */ static uint32_t ar71xx_get_bytes_to_read(int reg, int bytes) { uint32_t bytes_to_read = 0; if ((bytes % 4) == 0) bytes_to_read = 0; else if ((bytes % 4) == 1) bytes_to_read = (~(1 << (reg % 4))) & 0xf; else if ((bytes % 4) == 2) bytes_to_read = (~(3 << (reg % 4))) & 0xf; else panic("%s: wrong combination", __func__); return (bytes_to_read); } static int ar71xx_pci_check_bus_error(void) { uint32_t error, addr, has_errors = 0; mtx_assert(&ar71xx_pci_mtx, MA_OWNED); error = ATH_READ_REG(AR71XX_PCI_ERROR) & 0x3; dprintf("%s: PCI error = %02x\n", __func__, error); if (error) { addr = ATH_READ_REG(AR71XX_PCI_ERROR_ADDR); /* Do not report it yet */ #if 0 printf("PCI bus error %d at addr 0x%08x\n", error, addr); #endif ATH_WRITE_REG(AR71XX_PCI_ERROR, error); has_errors = 1; } error = ATH_READ_REG(AR71XX_PCI_AHB_ERROR) & 0x1; dprintf("%s: AHB error = %02x\n", __func__, error); if (error) { addr = ATH_READ_REG(AR71XX_PCI_AHB_ERROR_ADDR); /* Do not report it yet */ #if 0 printf("AHB bus error %d at addr 0x%08x\n", error, addr); #endif ATH_WRITE_REG(AR71XX_PCI_AHB_ERROR, error); has_errors = 1; } return (has_errors); } static uint32_t ar71xx_pci_make_addr(int bus, int slot, int func, int reg) { if (bus == 0) { return ((1 << slot) | (func << 8) | (reg & ~3)); } else { return ((bus << 16) | (slot << 11) | (func << 8) | (reg & ~3) | 1); } } static int ar71xx_pci_conf_setup(int bus, int slot, int func, int reg, int bytes, uint32_t cmd) { uint32_t addr = ar71xx_pci_make_addr(bus, slot, func, (reg & ~3)); mtx_assert(&ar71xx_pci_mtx, MA_OWNED); cmd |= (ar71xx_get_bytes_to_read(reg, bytes) << 4); ATH_WRITE_REG(AR71XX_PCI_CONF_ADDR, addr); ATH_WRITE_REG(AR71XX_PCI_CONF_CMD, cmd); dprintf("%s: tag (%x, %x, %x) %d/%d addr=%08x, cmd=%08x\n", __func__, bus, slot, func, reg, bytes, addr, cmd); return ar71xx_pci_check_bus_error(); } static uint32_t ar71xx_pci_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int bytes) { uint32_t data; uint32_t shift, mask; /* register access is 32-bit aligned */ shift = (reg & 3) * 8; /* Create a mask based on the width, post-shift */ if (bytes == 2) mask = 0xffff; else if (bytes == 1) mask = 0xff; else mask = 0xffffffff; dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot, func, reg, bytes); mtx_lock_spin(&ar71xx_pci_mtx); if (ar71xx_pci_conf_setup(bus, slot, func, reg, bytes, PCI_CONF_CMD_READ) == 0) data = ATH_READ_REG(AR71XX_PCI_CONF_READ_DATA); else data = -1; mtx_unlock_spin(&ar71xx_pci_mtx); /* get request bytes from 32-bit word */ data = (data >> shift) & mask; dprintf("%s: read 0x%x\n", __func__, data); return (data); } static void ar71xx_pci_local_write(device_t dev, uint32_t reg, uint32_t data, int bytes) { uint32_t cmd; dprintf("%s: local write reg %d(%d)\n", __func__, reg, bytes); data = data << (8*(reg % 4)); cmd = PCI_LCONF_CMD_WRITE | (reg & ~3); cmd |= (ar71xx_get_bytes_to_read(reg, bytes) << 20); mtx_lock_spin(&ar71xx_pci_mtx); ATH_WRITE_REG(AR71XX_PCI_LCONF_CMD, cmd); ATH_WRITE_REG(AR71XX_PCI_LCONF_WRITE_DATA, data); mtx_unlock_spin(&ar71xx_pci_mtx); } static void ar71xx_pci_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t data, int bytes) { dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot, func, reg, bytes); data = data << (8*(reg % 4)); mtx_lock_spin(&ar71xx_pci_mtx); if (ar71xx_pci_conf_setup(bus, slot, func, reg, bytes, PCI_CONF_CMD_WRITE) == 0) ATH_WRITE_REG(AR71XX_PCI_CONF_WRITE_DATA, data); mtx_unlock_spin(&ar71xx_pci_mtx); } #ifdef AR71XX_ATH_EEPROM /* * Some embedded boards (eg AP94) have the MAC attached via PCI but they * don't have the MAC-attached EEPROM. The register initialisation * values and calibration data are stored in the on-board flash. * This routine initialises the NIC via the EEPROM register contents * before the probe/attach routines get a go at things. */ static void ar71xx_pci_fixup(device_t dev, u_int bus, u_int slot, u_int func, long flash_addr, int len) { uint16_t *cal_data = (uint16_t *) MIPS_PHYS_TO_KSEG1(flash_addr); uint32_t reg, val, bar0; if (bootverbose) device_printf(dev, "%s: flash_addr=%lx, cal_data=%p\n", __func__, flash_addr, cal_data); /* XXX check 0xa55a */ /* Save bar(0) address - just to flush bar(0) (SoC WAR) ? */ bar0 = ar71xx_pci_read_config(dev, bus, slot, func, PCIR_BAR(0), 4); ar71xx_pci_write_config(dev, bus, slot, func, PCIR_BAR(0), AR71XX_PCI_MEM_BASE, 4); val = ar71xx_pci_read_config(dev, bus, slot, func, PCIR_COMMAND, 2); val |= (PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); ar71xx_pci_write_config(dev, bus, slot, func, PCIR_COMMAND, val, 2); cal_data += 3; while (*cal_data != 0xffff) { reg = *cal_data++; val = *cal_data++; val |= (*cal_data++) << 16; if (bootverbose) printf(" reg: %x, val=%x\n", reg, val); /* Write eeprom fixup data to device memory */ ATH_WRITE_REG(AR71XX_PCI_MEM_BASE + reg, val); DELAY(100); } val = ar71xx_pci_read_config(dev, bus, slot, func, PCIR_COMMAND, 2); val &= ~(PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); ar71xx_pci_write_config(dev, bus, slot, func, PCIR_COMMAND, val, 2); /* Write the saved bar(0) address */ ar71xx_pci_write_config(dev, bus, slot, func, PCIR_BAR(0), bar0, 4); } static void ar71xx_pci_slot_fixup(device_t dev, u_int bus, u_int slot, u_int func) { long int flash_addr; char buf[64]; int size; /* * Check whether the given slot has a hint to poke. */ if (bootverbose) device_printf(dev, "%s: checking dev %s, %d/%d/%d\n", __func__, device_get_nameunit(dev), bus, slot, func); snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_addr", bus, slot, func); if (resource_long_value(device_get_name(dev), device_get_unit(dev), buf, &flash_addr) == 0) { snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_size", bus, slot, func); if (resource_int_value(device_get_name(dev), device_get_unit(dev), buf, &size) != 0) { device_printf(dev, "%s: missing hint '%s', aborting EEPROM\n", __func__, buf); return; } device_printf(dev, "found EEPROM at 0x%lx on %d.%d.%d\n", flash_addr, bus, slot, func); ar71xx_pci_fixup(dev, bus, slot, func, flash_addr, size); ar71xx_pci_slot_create_eeprom_firmware(dev, bus, slot, func, flash_addr, size); } } #endif /* AR71XX_ATH_EEPROM */ static int ar71xx_pci_probe(device_t dev) { return (BUS_PROBE_NOWILDCARD); } static int ar71xx_pci_attach(device_t dev) { int rid = 0; struct ar71xx_pci_softc *sc = device_get_softc(dev); sc->sc_mem_rman.rm_type = RMAN_ARRAY; sc->sc_mem_rman.rm_descr = "ar71xx PCI memory window"; if (rman_init(&sc->sc_mem_rman) != 0 || rman_manage_region(&sc->sc_mem_rman, AR71XX_PCI_MEM_BASE, AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1) != 0) { panic("ar71xx_pci_attach: failed to set up I/O rman"); } sc->sc_irq_rman.rm_type = RMAN_ARRAY; sc->sc_irq_rman.rm_descr = "ar71xx PCI IRQs"; if (rman_init(&sc->sc_irq_rman) != 0 || rman_manage_region(&sc->sc_irq_rman, AR71XX_PCI_IRQ_START, AR71XX_PCI_IRQ_END) != 0) panic("ar71xx_pci_attach: failed to set up IRQ rman"); /* * Check if there is a base slot hint. Otherwise use default value. */ if (resource_int_value(device_get_name(dev), device_get_unit(dev), "baseslot", &sc->sc_baseslot) != 0) { device_printf(dev, "%s: missing hint '%s', default to AR71XX_PCI_BASE_SLOT\n", __func__, "baseslot"); sc->sc_baseslot = AR71XX_PCI_BASE_SLOT; } ATH_WRITE_REG(AR71XX_PCI_INTR_STATUS, 0); ATH_WRITE_REG(AR71XX_PCI_INTR_MASK, 0); /* Hook up our interrupt handler. */ if ((sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { device_printf(dev, "unable to allocate IRQ resource\n"); return ENXIO; } if ((bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC, ar71xx_pci_intr, NULL, sc, &sc->sc_ih))) { device_printf(dev, "WARNING: unable to register interrupt handler\n"); return ENXIO; } /* reset PCI core and PCI bus */ ar71xx_device_stop(RST_RESET_PCI_CORE | RST_RESET_PCI_BUS); DELAY(100000); ar71xx_device_start(RST_RESET_PCI_CORE | RST_RESET_PCI_BUS); DELAY(100000); /* Init PCI windows */ ATH_WRITE_REG(AR71XX_PCI_WINDOW0, PCI_WINDOW0_ADDR); ATH_WRITE_REG(AR71XX_PCI_WINDOW1, PCI_WINDOW1_ADDR); ATH_WRITE_REG(AR71XX_PCI_WINDOW2, PCI_WINDOW2_ADDR); ATH_WRITE_REG(AR71XX_PCI_WINDOW3, PCI_WINDOW3_ADDR); ATH_WRITE_REG(AR71XX_PCI_WINDOW4, PCI_WINDOW4_ADDR); ATH_WRITE_REG(AR71XX_PCI_WINDOW5, PCI_WINDOW5_ADDR); ATH_WRITE_REG(AR71XX_PCI_WINDOW6, PCI_WINDOW6_ADDR); ATH_WRITE_REG(AR71XX_PCI_WINDOW7, PCI_WINDOW7_CONF_ADDR); DELAY(100000); mtx_lock_spin(&ar71xx_pci_mtx); ar71xx_pci_check_bus_error(); mtx_unlock_spin(&ar71xx_pci_mtx); /* Fixup internal PCI bridge */ ar71xx_pci_local_write(dev, PCIR_COMMAND, PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN | PCIM_CMD_SERRESPEN | PCIM_CMD_BACKTOBACK | PCIM_CMD_PERRESPEN | PCIM_CMD_MWRICEN, 4); #ifdef AR71XX_ATH_EEPROM /* * Hard-code a check for slot 17 and 18 - these are * the two PCI slots which may have a PCI device that * requires "fixing". */ ar71xx_pci_slot_fixup(dev, 0, 17, 0); ar71xx_pci_slot_fixup(dev, 0, 18, 0); #endif /* AR71XX_ATH_EEPROM */ device_add_child(dev, "pci", -1); return (bus_generic_attach(dev)); } static int ar71xx_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { struct ar71xx_pci_softc *sc = device_get_softc(dev); switch (which) { case PCIB_IVAR_DOMAIN: *result = 0; return (0); case PCIB_IVAR_BUS: *result = sc->sc_busno; return (0); } return (ENOENT); } static int ar71xx_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t result) { struct ar71xx_pci_softc * sc = device_get_softc(dev); switch (which) { case PCIB_IVAR_BUS: sc->sc_busno = result; return (0); } return (ENOENT); } static struct resource * ar71xx_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct ar71xx_pci_softc *sc = device_get_softc(bus); struct resource *rv; struct rman *rm; switch (type) { case SYS_RES_IRQ: rm = &sc->sc_irq_rman; break; case SYS_RES_MEMORY: rm = &sc->sc_mem_rman; break; default: return (NULL); } rv = rman_reserve_resource(rm, start, end, count, flags, child); if (rv == NULL) return (NULL); rman_set_rid(rv, *rid); if (flags & RF_ACTIVE) { if (bus_activate_resource(child, type, *rid, rv)) { rman_release_resource(rv); return (NULL); } } return (rv); } static int ar71xx_pci_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { int res = (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), child, type, rid, r)); if (!res) { switch(type) { case SYS_RES_MEMORY: case SYS_RES_IOPORT: rman_set_bustag(r, ar71xx_bus_space_pcimem); break; } } return (res); } static int ar71xx_pci_setup_intr(device_t bus, device_t child, struct resource *ires, int flags, driver_filter_t *filt, driver_intr_t *handler, void *arg, void **cookiep) { struct ar71xx_pci_softc *sc = device_get_softc(bus); struct intr_event *event; int irq, error; irq = rman_get_start(ires); if (irq > AR71XX_PCI_IRQ_END) panic("%s: bad irq %d", __func__, irq); event = sc->sc_eventstab[irq]; if (event == NULL) { error = intr_event_create(&event, (void *)irq, 0, irq, ar71xx_pci_mask_irq, ar71xx_pci_unmask_irq, NULL, NULL, "pci intr%d:", irq); if (error == 0) { sc->sc_eventstab[irq] = event; sc->sc_intr_counter[irq] = mips_intrcnt_create(event->ie_name); } else return (error); } intr_event_add_handler(event, device_get_nameunit(child), filt, handler, arg, intr_priority(flags), flags, cookiep); mips_intrcnt_setname(sc->sc_intr_counter[irq], event->ie_fullname); ar71xx_pci_unmask_irq((void*)irq); return (0); } static int ar71xx_pci_teardown_intr(device_t dev, device_t child, struct resource *ires, void *cookie) { struct ar71xx_pci_softc *sc = device_get_softc(dev); int irq, result; irq = rman_get_start(ires); if (irq > AR71XX_PCI_IRQ_END) panic("%s: bad irq %d", __func__, irq); if (sc->sc_eventstab[irq] == NULL) panic("Trying to teardown unoccupied IRQ"); ar71xx_pci_mask_irq((void*)irq); result = intr_event_remove_handler(cookie); if (!result) sc->sc_eventstab[irq] = NULL; return (result); } static int ar71xx_pci_intr(void *arg) { struct ar71xx_pci_softc *sc = arg; struct intr_event *event; uint32_t reg, irq, mask; reg = ATH_READ_REG(AR71XX_PCI_INTR_STATUS); mask = ATH_READ_REG(AR71XX_PCI_INTR_MASK); /* * Handle only unmasked interrupts */ reg &= mask; for (irq = AR71XX_PCI_IRQ_START; irq <= AR71XX_PCI_IRQ_END; irq++) { if (reg & (1 << irq)) { event = sc->sc_eventstab[irq]; if (!event || TAILQ_EMPTY(&event->ie_handlers)) { /* Ignore timer interrupts */ if (irq != 0) printf("Stray IRQ %d\n", irq); continue; } /* Flush DDR FIFO for PCI/PCIe */ ar71xx_device_flush_ddr(AR71XX_CPU_DDR_FLUSH_PCIE); /* TODO: frame instead of NULL? */ intr_event_handle(event, NULL); mips_intrcnt_inc(sc->sc_intr_counter[irq]); } } return (FILTER_HANDLED); } static int ar71xx_pci_maxslots(device_t dev) { return (PCI_SLOTMAX); } static int ar71xx_pci_route_interrupt(device_t pcib, device_t device, int pin) { struct ar71xx_pci_softc *sc = device_get_softc(pcib); if (pci_get_slot(device) < sc->sc_baseslot) panic("%s: PCI slot %d is less then AR71XX_PCI_BASE_SLOT", __func__, pci_get_slot(device)); return (pci_get_slot(device) - sc->sc_baseslot); } static device_method_t ar71xx_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ar71xx_pci_probe), DEVMETHOD(device_attach, ar71xx_pci_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_read_ivar, ar71xx_pci_read_ivar), DEVMETHOD(bus_write_ivar, ar71xx_pci_write_ivar), DEVMETHOD(bus_alloc_resource, ar71xx_pci_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, ar71xx_pci_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, ar71xx_pci_setup_intr), DEVMETHOD(bus_teardown_intr, ar71xx_pci_teardown_intr), /* pcib interface */ DEVMETHOD(pcib_maxslots, ar71xx_pci_maxslots), DEVMETHOD(pcib_read_config, ar71xx_pci_read_config), DEVMETHOD(pcib_write_config, ar71xx_pci_write_config), DEVMETHOD(pcib_route_interrupt, ar71xx_pci_route_interrupt), DEVMETHOD(pcib_request_feature, pcib_request_feature_allow), DEVMETHOD_END }; static driver_t ar71xx_pci_driver = { "pcib", ar71xx_pci_methods, sizeof(struct ar71xx_pci_softc), }; static devclass_t ar71xx_pci_devclass; DRIVER_MODULE(ar71xx_pci, nexus, ar71xx_pci_driver, ar71xx_pci_devclass, 0, 0); Index: head/sys/mips/atheros/ar71xx_pci_bus_space.c =================================================================== --- head/sys/mips/atheros/ar71xx_pci_bus_space.c (revision 326258) +++ head/sys/mips/atheros/ar71xx_pci_bus_space.c (revision 326259) @@ -1,198 +1,200 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009, Oleksandr Tymoshenko * 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 unmodified, 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 static bs_r_1_s_proto(pcimem); static bs_r_2_s_proto(pcimem); static bs_r_4_s_proto(pcimem); static bs_w_1_s_proto(pcimem); static bs_w_2_s_proto(pcimem); static bs_w_4_s_proto(pcimem); /* * Bus space that handles offsets in word for 1/2 bytes read/write access. * Byte order of values is handled by device drivers itself. */ static struct bus_space bus_space_pcimem = { /* cookie */ (void *) 0, /* mapping/unmapping */ generic_bs_map, generic_bs_unmap, generic_bs_subregion, /* allocation/deallocation */ NULL, NULL, /* barrier */ generic_bs_barrier, /* read (single) */ generic_bs_r_1, generic_bs_r_2, generic_bs_r_4, NULL, /* read multiple */ generic_bs_rm_1, generic_bs_rm_2, generic_bs_rm_4, NULL, /* read region */ generic_bs_rr_1, generic_bs_rr_2, generic_bs_rr_4, NULL, /* write (single) */ generic_bs_w_1, generic_bs_w_2, generic_bs_w_4, NULL, /* write multiple */ generic_bs_wm_1, generic_bs_wm_2, generic_bs_wm_4, NULL, /* write region */ NULL, generic_bs_wr_2, generic_bs_wr_4, NULL, /* set multiple */ NULL, NULL, NULL, NULL, /* set region */ NULL, generic_bs_sr_2, generic_bs_sr_4, NULL, /* copy */ NULL, generic_bs_c_2, NULL, NULL, /* read (single) stream */ pcimem_bs_r_1_s, pcimem_bs_r_2_s, pcimem_bs_r_4_s, NULL, /* read multiple stream */ generic_bs_rm_1, generic_bs_rm_2, generic_bs_rm_4, NULL, /* read region stream */ generic_bs_rr_1, generic_bs_rr_2, generic_bs_rr_4, NULL, /* write (single) stream */ pcimem_bs_w_1_s, pcimem_bs_w_2_s, pcimem_bs_w_4_s, NULL, /* write multiple stream */ generic_bs_wm_1, generic_bs_wm_2, generic_bs_wm_4, NULL, /* write region stream */ NULL, generic_bs_wr_2, generic_bs_wr_4, NULL, }; bus_space_tag_t ar71xx_bus_space_pcimem = &bus_space_pcimem; static uint8_t pcimem_bs_r_1_s(void *t, bus_space_handle_t h, bus_size_t o) { return readb(h + (o &~ 3) + (3 - (o & 3))); } static void pcimem_bs_w_1_s(void *t, bus_space_handle_t h, bus_size_t o, u_int8_t v) { writeb(h + (o &~ 3) + (3 - (o & 3)), v); } static uint16_t pcimem_bs_r_2_s(void *t, bus_space_handle_t h, bus_size_t o) { return readw(h + (o &~ 3) + (2 - (o & 3))); } static void pcimem_bs_w_2_s(void *t, bus_space_handle_t h, bus_size_t o, uint16_t v) { writew(h + (o &~ 3) + (2 - (o & 3)), v); } static uint32_t pcimem_bs_r_4_s(void *t, bus_space_handle_t h, bus_size_t o) { return le32toh(readl(h + o)); } static void pcimem_bs_w_4_s(void *t, bus_space_handle_t h, bus_size_t o, uint32_t v) { writel(h + o, htole32(v)); } Index: head/sys/mips/atheros/ar71xx_pci_bus_space.h =================================================================== --- head/sys/mips/atheros/ar71xx_pci_bus_space.h (revision 326258) +++ head/sys/mips/atheros/ar71xx_pci_bus_space.h (revision 326259) @@ -1,33 +1,37 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009, Oleksandr Tymoshenko * 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 unmodified, 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$ */ #ifndef __AR71XX_PCI_BUS_SPACEH__ #define __AR71XX_PCI_BUS_SPACEH__ extern bus_space_tag_t ar71xx_bus_space_pcimem; #endif /* __AR71XX_PCI_BUS_SPACEH__ */ Index: head/sys/mips/atheros/ar71xx_setup.c =================================================================== --- head/sys/mips/atheros/ar71xx_setup.c (revision 326258) +++ head/sys/mips/atheros/ar71xx_setup.c (revision 326259) @@ -1,235 +1,237 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Adrian Chadd * 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 "opt_ddb.h" #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 AR71XX_SYS_TYPE_LEN 128 static char ar71xx_sys_type[AR71XX_SYS_TYPE_LEN]; enum ar71xx_soc_type ar71xx_soc; struct ar71xx_cpu_def * ar71xx_cpu_ops = NULL; void ar71xx_detect_sys_type(void) { char *chip = "????"; uint32_t id; uint32_t major; uint32_t minor; uint32_t rev = 0; id = ATH_READ_REG(AR71XX_RST_RESET_REG_REV_ID); major = id & REV_ID_MAJOR_MASK; switch (major) { case REV_ID_MAJOR_AR71XX: minor = id & AR71XX_REV_ID_MINOR_MASK; rev = id >> AR71XX_REV_ID_REVISION_SHIFT; rev &= AR71XX_REV_ID_REVISION_MASK; ar71xx_cpu_ops = &ar71xx_chip_def; switch (minor) { case AR71XX_REV_ID_MINOR_AR7130: ar71xx_soc = AR71XX_SOC_AR7130; chip = "7130"; break; case AR71XX_REV_ID_MINOR_AR7141: ar71xx_soc = AR71XX_SOC_AR7141; chip = "7141"; break; case AR71XX_REV_ID_MINOR_AR7161: ar71xx_soc = AR71XX_SOC_AR7161; chip = "7161"; break; } break; case REV_ID_MAJOR_AR7240: ar71xx_soc = AR71XX_SOC_AR7240; chip = "7240"; ar71xx_cpu_ops = &ar724x_chip_def; rev = (id & AR724X_REV_ID_REVISION_MASK); break; case REV_ID_MAJOR_AR7241: ar71xx_soc = AR71XX_SOC_AR7241; chip = "7241"; ar71xx_cpu_ops = &ar724x_chip_def; rev = (id & AR724X_REV_ID_REVISION_MASK); break; case REV_ID_MAJOR_AR7242: ar71xx_soc = AR71XX_SOC_AR7242; chip = "7242"; ar71xx_cpu_ops = &ar724x_chip_def; rev = (id & AR724X_REV_ID_REVISION_MASK); break; case REV_ID_MAJOR_AR913X: minor = id & AR91XX_REV_ID_MINOR_MASK; rev = id >> AR91XX_REV_ID_REVISION_SHIFT; rev &= AR91XX_REV_ID_REVISION_MASK; ar71xx_cpu_ops = &ar91xx_chip_def; switch (minor) { case AR91XX_REV_ID_MINOR_AR9130: ar71xx_soc = AR71XX_SOC_AR9130; chip = "9130"; break; case AR91XX_REV_ID_MINOR_AR9132: ar71xx_soc = AR71XX_SOC_AR9132; chip = "9132"; break; } break; case REV_ID_MAJOR_AR9330: minor = 0; rev = (id & AR933X_REV_ID_REVISION_MASK); chip = "9330"; ar71xx_cpu_ops = &ar933x_chip_def; ar71xx_soc = AR71XX_SOC_AR9330; break; case REV_ID_MAJOR_AR9331: minor = 1; rev = (id & AR933X_REV_ID_REVISION_MASK); chip = "9331"; ar71xx_soc = AR71XX_SOC_AR9331; ar71xx_cpu_ops = &ar933x_chip_def; break; case REV_ID_MAJOR_AR9341: minor = 0; rev = (id & AR934X_REV_ID_REVISION_MASK); chip = "9341"; ar71xx_soc = AR71XX_SOC_AR9341; ar71xx_cpu_ops = &ar934x_chip_def; break; case REV_ID_MAJOR_AR9342: minor = 0; rev = (id & AR934X_REV_ID_REVISION_MASK); chip = "9342"; ar71xx_soc = AR71XX_SOC_AR9342; ar71xx_cpu_ops = &ar934x_chip_def; break; case REV_ID_MAJOR_AR9344: minor = 0; rev = (id & AR934X_REV_ID_REVISION_MASK); chip = "9344"; ar71xx_soc = AR71XX_SOC_AR9344; ar71xx_cpu_ops = &ar934x_chip_def; break; case REV_ID_MAJOR_QCA9533: minor = 0; rev = (id & QCA953X_REV_ID_REVISION_MASK); chip = "9533"; ar71xx_soc = AR71XX_SOC_QCA9533; ar71xx_cpu_ops = &qca953x_chip_def; break; case REV_ID_MAJOR_QCA9533_V2: minor = 0; rev = (id & QCA953X_REV_ID_REVISION_MASK); chip = "9533v2"; ar71xx_soc = AR71XX_SOC_QCA9533_V2; ar71xx_cpu_ops = &qca953x_chip_def; break; case REV_ID_MAJOR_QCA9556: minor = 0; rev = (id & QCA955X_REV_ID_REVISION_MASK); chip = "9556"; ar71xx_soc = AR71XX_SOC_QCA9556; ar71xx_cpu_ops = &qca955x_chip_def; break; case REV_ID_MAJOR_QCA9558: minor = 0; rev = (id & QCA955X_REV_ID_REVISION_MASK); chip = "9558"; ar71xx_soc = AR71XX_SOC_QCA9558; ar71xx_cpu_ops = &qca955x_chip_def; break; default: panic("ar71xx: unknown chip id:0x%08x\n", id); } sprintf(ar71xx_sys_type, "Atheros AR%s rev %u", chip, rev); } const char * ar71xx_get_system_type(void) { return ar71xx_sys_type; } Index: head/sys/mips/atheros/ar71xx_setup.h =================================================================== --- head/sys/mips/atheros/ar71xx_setup.h (revision 326258) +++ head/sys/mips/atheros/ar71xx_setup.h (revision 326259) @@ -1,57 +1,59 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Adrian Chadd * 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$ */ #ifndef __AR71XX_SETUP_H__ #define __AR71XX_SETUP_H__ enum ar71xx_soc_type { AR71XX_SOC_UNKNOWN, AR71XX_SOC_AR7130, AR71XX_SOC_AR7141, AR71XX_SOC_AR7161, AR71XX_SOC_AR7240, AR71XX_SOC_AR7241, AR71XX_SOC_AR7242, AR71XX_SOC_AR9130, AR71XX_SOC_AR9132, AR71XX_SOC_AR9330, AR71XX_SOC_AR9331, AR71XX_SOC_AR9341, AR71XX_SOC_AR9342, AR71XX_SOC_AR9344, AR71XX_SOC_QCA9556, AR71XX_SOC_QCA9558, AR71XX_SOC_QCA9533, AR71XX_SOC_QCA9533_V2, }; extern enum ar71xx_soc_type ar71xx_soc; extern void ar71xx_detect_sys_type(void); extern const char *ar71xx_get_system_type(void); #endif Index: head/sys/mips/atheros/ar71xx_spi.c =================================================================== --- head/sys/mips/atheros/ar71xx_spi.c (revision 326258) +++ head/sys/mips/atheros/ar71xx_spi.c (revision 326259) @@ -1,295 +1,297 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009, Oleksandr Tymoshenko * 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 unmodified, 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 "spibus_if.h" #include #undef AR71XX_SPI_DEBUG #ifdef AR71XX_SPI_DEBUG #define dprintf printf #else #define dprintf(x, arg...) #endif /* * register space access macros */ #define SPI_BARRIER_WRITE(sc) bus_barrier((sc)->sc_mem_res, 0, 0, \ BUS_SPACE_BARRIER_WRITE) #define SPI_BARRIER_READ(sc) bus_barrier((sc)->sc_mem_res, 0, 0, \ BUS_SPACE_BARRIER_READ) #define SPI_BARRIER_RW(sc) bus_barrier((sc)->sc_mem_res, 0, 0, \ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE) #define SPI_WRITE(sc, reg, val) do { \ bus_write_4(sc->sc_mem_res, (reg), (val)); \ } while (0) #define SPI_READ(sc, reg) bus_read_4(sc->sc_mem_res, (reg)) #define SPI_SET_BITS(sc, reg, bits) \ SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) | (bits)) #define SPI_CLEAR_BITS(sc, reg, bits) \ SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) & ~(bits)) struct ar71xx_spi_softc { device_t sc_dev; struct resource *sc_mem_res; uint32_t sc_reg_ctrl; }; static int ar71xx_spi_probe(device_t dev) { device_set_desc(dev, "AR71XX SPI"); return (BUS_PROBE_NOWILDCARD); } static int ar71xx_spi_attach(device_t dev) { struct ar71xx_spi_softc *sc = device_get_softc(dev); int rid; sc->sc_dev = dev; rid = 0; sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!sc->sc_mem_res) { device_printf(dev, "Could not map memory\n"); return (ENXIO); } SPI_WRITE(sc, AR71XX_SPI_FS, 1); /* Flush out read before reading the control register */ SPI_BARRIER_WRITE(sc); sc->sc_reg_ctrl = SPI_READ(sc, AR71XX_SPI_CTRL); /* * XXX TODO: document what the SPI control register does. */ SPI_WRITE(sc, AR71XX_SPI_CTRL, 0x43); /* * Ensure the config register write has gone out before configuring * the chip select mask. */ SPI_BARRIER_WRITE(sc); SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, SPI_IO_CTRL_CSMASK); /* * .. and ensure the write has gone out before continuing. */ SPI_BARRIER_WRITE(sc); device_add_child(dev, "spibus", -1); return (bus_generic_attach(dev)); } static void ar71xx_spi_chip_activate(struct ar71xx_spi_softc *sc, int cs) { uint32_t ioctrl = SPI_IO_CTRL_CSMASK; /* * Put respective CSx to low */ ioctrl &= ~(SPI_IO_CTRL_CS0 << cs); /* * Make sure any other writes have gone out to the * device before changing the chip select line; * then ensure that it has made it out to the device * before continuing. */ SPI_BARRIER_WRITE(sc); SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, ioctrl); SPI_BARRIER_WRITE(sc); } static void ar71xx_spi_chip_deactivate(struct ar71xx_spi_softc *sc, int cs) { /* * Put all CSx to high */ SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, SPI_IO_CTRL_CSMASK); } static uint8_t ar71xx_spi_txrx(struct ar71xx_spi_softc *sc, int cs, uint8_t data) { int bit; /* CS0 */ uint32_t ioctrl = SPI_IO_CTRL_CSMASK; /* * low-level for selected CS */ ioctrl &= ~(SPI_IO_CTRL_CS0 << cs); uint32_t iod, rds; for (bit = 7; bit >=0; bit--) { if (data & (1 << bit)) iod = ioctrl | SPI_IO_CTRL_DO; else iod = ioctrl & ~SPI_IO_CTRL_DO; SPI_BARRIER_WRITE(sc); SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, iod); SPI_BARRIER_WRITE(sc); SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, iod | SPI_IO_CTRL_CLK); } /* * Provide falling edge for connected device by clear clock bit. */ SPI_BARRIER_WRITE(sc); SPI_WRITE(sc, AR71XX_SPI_IO_CTRL, iod); SPI_BARRIER_WRITE(sc); rds = SPI_READ(sc, AR71XX_SPI_RDS); return (rds & 0xff); } static int ar71xx_spi_transfer(device_t dev, device_t child, struct spi_command *cmd) { struct ar71xx_spi_softc *sc; uint32_t cs; uint8_t *buf_in, *buf_out; int i; sc = device_get_softc(dev); spibus_get_cs(child, &cs); cs &= ~SPIBUS_CS_HIGH; ar71xx_spi_chip_activate(sc, cs); KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz, ("TX/RX command sizes should be equal")); KASSERT(cmd->tx_data_sz == cmd->rx_data_sz, ("TX/RX data sizes should be equal")); /* * Transfer command */ buf_out = (uint8_t *)cmd->tx_cmd; buf_in = (uint8_t *)cmd->rx_cmd; for (i = 0; i < cmd->tx_cmd_sz; i++) buf_in[i] = ar71xx_spi_txrx(sc, cs, buf_out[i]); /* * Receive/transmit data (depends on command) */ buf_out = (uint8_t *)cmd->tx_data; buf_in = (uint8_t *)cmd->rx_data; for (i = 0; i < cmd->tx_data_sz; i++) buf_in[i] = ar71xx_spi_txrx(sc, cs, buf_out[i]); ar71xx_spi_chip_deactivate(sc, cs); return (0); } static int ar71xx_spi_detach(device_t dev) { struct ar71xx_spi_softc *sc = device_get_softc(dev); /* * Ensure any other writes to the device are finished * before we tear down the SPI device. */ SPI_BARRIER_WRITE(sc); /* * Restore the control register; ensure it has hit the * hardware before continuing. */ SPI_WRITE(sc, AR71XX_SPI_CTRL, sc->sc_reg_ctrl); SPI_BARRIER_WRITE(sc); /* * And now, put the flash back into mapped IO mode and * ensure _that_ has completed before we finish up. */ SPI_WRITE(sc, AR71XX_SPI_FS, 0); SPI_BARRIER_WRITE(sc); if (sc->sc_mem_res) bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); return (0); } static device_method_t ar71xx_spi_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ar71xx_spi_probe), DEVMETHOD(device_attach, ar71xx_spi_attach), DEVMETHOD(device_detach, ar71xx_spi_detach), DEVMETHOD(spibus_transfer, ar71xx_spi_transfer), {0, 0} }; static driver_t ar71xx_spi_driver = { "spi", ar71xx_spi_methods, sizeof(struct ar71xx_spi_softc), }; static devclass_t ar71xx_spi_devclass; DRIVER_MODULE(ar71xx_spi, nexus, ar71xx_spi_driver, ar71xx_spi_devclass, 0, 0); Index: head/sys/mips/atheros/ar71xx_wdog.c =================================================================== --- head/sys/mips/atheros/ar71xx_wdog.c (revision 326258) +++ head/sys/mips/atheros/ar71xx_wdog.c (revision 326259) @@ -1,156 +1,158 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009, Oleksandr Tymoshenko * 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 unmodified, 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. */ /* * Watchdog driver for AR71xx */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include struct ar71xx_wdog_softc { device_t dev; int armed; int reboot_from_watchdog; int debug; }; static void ar71xx_wdog_watchdog_fn(void *private, u_int cmd, int *error) { struct ar71xx_wdog_softc *sc = private; uint64_t timer_val; cmd &= WD_INTERVAL; if (sc->debug) device_printf(sc->dev, "ar71xx_wdog_watchdog_fn: cmd: %x\n", cmd); if (cmd > 0) { timer_val = (uint64_t)(1ULL << cmd) * ar71xx_ahb_freq() / 1000000000; if (sc->debug) device_printf(sc->dev, "ar71xx_wdog_watchdog_fn: programming timer: %jx\n", (uintmax_t) timer_val); /* * Load timer with large enough value to prevent spurious * reset */ ATH_WRITE_REG(AR71XX_RST_WDOG_TIMER, ar71xx_ahb_freq() * 10); ATH_WRITE_REG(AR71XX_RST_WDOG_CONTROL, RST_WDOG_ACTION_RESET); ATH_WRITE_REG(AR71XX_RST_WDOG_TIMER, (timer_val & 0xffffffff)); sc->armed = 1; *error = 0; } else { if (sc->debug) device_printf(sc->dev, "ar71xx_wdog_watchdog_fn: disarming\n"); if (sc->armed) { ATH_WRITE_REG(AR71XX_RST_WDOG_CONTROL, RST_WDOG_ACTION_NOACTION); sc->armed = 0; } } } static int ar71xx_wdog_probe(device_t dev) { device_set_desc(dev, "Atheros AR71XX watchdog timer"); return (BUS_PROBE_NOWILDCARD); } static void ar71xx_wdog_sysctl(device_t dev) { struct ar71xx_wdog_softc *sc = device_get_softc(dev); struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->dev); struct sysctl_oid *tree = device_get_sysctl_tree(sc->dev); SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "debug", CTLFLAG_RW, &sc->debug, 0, "enable watchdog debugging"); SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "armed", CTLFLAG_RD, &sc->armed, 0, "whether the watchdog is armed"); SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "reboot_from_watchdog", CTLFLAG_RD, &sc->reboot_from_watchdog, 0, "whether the system rebooted from the watchdog"); } static int ar71xx_wdog_attach(device_t dev) { struct ar71xx_wdog_softc *sc = device_get_softc(dev); /* Initialise */ sc->reboot_from_watchdog = 0; sc->armed = 0; sc->debug = 0; if (ATH_READ_REG(AR71XX_RST_WDOG_CONTROL) & RST_WDOG_LAST) { device_printf (dev, "Previous reset was due to watchdog timeout\n"); sc->reboot_from_watchdog = 1; } ATH_WRITE_REG(AR71XX_RST_WDOG_CONTROL, RST_WDOG_ACTION_NOACTION); sc->dev = dev; EVENTHANDLER_REGISTER(watchdog_list, ar71xx_wdog_watchdog_fn, sc, 0); ar71xx_wdog_sysctl(dev); return (0); } static device_method_t ar71xx_wdog_methods[] = { DEVMETHOD(device_probe, ar71xx_wdog_probe), DEVMETHOD(device_attach, ar71xx_wdog_attach), {0, 0}, }; static driver_t ar71xx_wdog_driver = { "ar71xx_wdog", ar71xx_wdog_methods, sizeof(struct ar71xx_wdog_softc), }; static devclass_t ar71xx_wdog_devclass; DRIVER_MODULE(ar71xx_wdog, nexus, ar71xx_wdog_driver, ar71xx_wdog_devclass, 0, 0); Index: head/sys/mips/atheros/ar71xxreg.h =================================================================== --- head/sys/mips/atheros/ar71xxreg.h (revision 326258) +++ head/sys/mips/atheros/ar71xxreg.h (revision 326259) @@ -1,574 +1,576 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009 Oleksandr Tymoshenko * 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$ */ #ifndef _AR71XX_REG_H_ #define _AR71XX_REG_H_ /* PCI region */ #define AR71XX_PCI_MEM_BASE 0x10000000 /* * PCI mem windows is 0x08000000 bytes long but we exclude control * region from the resource manager */ #define AR71XX_PCI_MEM_SIZE 0x07000000 #define AR71XX_PCI_IRQ_START 0 #define AR71XX_PCI_IRQ_END 2 #define AR71XX_PCI_NIRQS 3 /* * PCI devices slots are starting from this number */ #define AR71XX_PCI_BASE_SLOT 17 /* PCI config registers */ #define AR71XX_PCI_LCONF_CMD 0x17010000 #define PCI_LCONF_CMD_READ 0x00000000 #define PCI_LCONF_CMD_WRITE 0x00010000 #define AR71XX_PCI_LCONF_WRITE_DATA 0x17010004 #define AR71XX_PCI_LCONF_READ_DATA 0x17010008 #define AR71XX_PCI_CONF_ADDR 0x1701000C #define AR71XX_PCI_CONF_CMD 0x17010010 #define PCI_CONF_CMD_READ 0x0000000A #define PCI_CONF_CMD_WRITE 0x0000000B #define AR71XX_PCI_CONF_WRITE_DATA 0x17010014 #define AR71XX_PCI_CONF_READ_DATA 0x17010018 #define AR71XX_PCI_ERROR 0x1701001C #define AR71XX_PCI_ERROR_ADDR 0x17010020 #define AR71XX_PCI_AHB_ERROR 0x17010024 #define AR71XX_PCI_AHB_ERROR_ADDR 0x17010028 /* APB region */ /* * Size is not really true actual APB window size is * 0x01000000 but it should handle OHCI memory as well * because this controller's interrupt is routed through * APB. */ #define AR71XX_APB_BASE 0x18000000 #define AR71XX_APB_SIZE 0x06000000 /* DDR registers */ #define AR71XX_DDR_CONFIG 0x18000000 #define AR71XX_DDR_CONFIG2 0x18000004 #define AR71XX_DDR_MODE_REGISTER 0x18000008 #define AR71XX_DDR_EXT_MODE_REGISTER 0x1800000C #define AR71XX_DDR_CONTROL 0x18000010 #define AR71XX_DDR_REFRESH 0x18000014 #define AR71XX_DDR_RD_DATA_THIS_CYCLE 0x18000018 #define AR71XX_TAP_CONTROL0 0x1800001C #define AR71XX_TAP_CONTROL1 0x18000020 #define AR71XX_TAP_CONTROL2 0x18000024 #define AR71XX_TAP_CONTROL3 0x18000028 #define AR71XX_PCI_WINDOW0 0x1800007C #define AR71XX_PCI_WINDOW1 0x18000080 #define AR71XX_PCI_WINDOW2 0x18000084 #define AR71XX_PCI_WINDOW3 0x18000088 #define AR71XX_PCI_WINDOW4 0x1800008C #define AR71XX_PCI_WINDOW5 0x18000090 #define AR71XX_PCI_WINDOW6 0x18000094 #define AR71XX_PCI_WINDOW7 0x18000098 #define AR71XX_WB_FLUSH_GE0 0x1800009C #define AR71XX_WB_FLUSH_GE1 0x180000A0 #define AR71XX_WB_FLUSH_USB 0x180000A4 #define AR71XX_WB_FLUSH_PCI 0x180000A8 /* * Values for PCI_WINDOW_X registers */ #define PCI_WINDOW0_ADDR 0x10000000 #define PCI_WINDOW1_ADDR 0x11000000 #define PCI_WINDOW2_ADDR 0x12000000 #define PCI_WINDOW3_ADDR 0x13000000 #define PCI_WINDOW4_ADDR 0x14000000 #define PCI_WINDOW5_ADDR 0x15000000 #define PCI_WINDOW6_ADDR 0x16000000 #define PCI_WINDOW7_ADDR 0x17000000 /* This value enables acces to PCI config registers */ #define PCI_WINDOW7_CONF_ADDR 0x07000000 #define AR71XX_UART_ADDR 0x18020000 #define AR71XX_UART_THR 0x0 #define AR71XX_UART_LSR 0x14 #define AR71XX_UART_LSR_THRE (1 << 5) #define AR71XX_UART_LSR_TEMT (1 << 6) #define AR71XX_USB_CTRL_FLADJ 0x18030000 #define USB_CTRL_FLADJ_HOST_SHIFT 12 #define USB_CTRL_FLADJ_A5_SHIFT 10 #define USB_CTRL_FLADJ_A4_SHIFT 8 #define USB_CTRL_FLADJ_A3_SHIFT 6 #define USB_CTRL_FLADJ_A2_SHIFT 4 #define USB_CTRL_FLADJ_A1_SHIFT 2 #define USB_CTRL_FLADJ_A0_SHIFT 0 #define AR71XX_USB_CTRL_CONFIG 0x18030004 #define USB_CTRL_CONFIG_OHCI_DES_SWAP (1 << 19) #define USB_CTRL_CONFIG_OHCI_BUF_SWAP (1 << 18) #define USB_CTRL_CONFIG_EHCI_DES_SWAP (1 << 17) #define USB_CTRL_CONFIG_EHCI_BUF_SWAP (1 << 16) #define USB_CTRL_CONFIG_DISABLE_XTL (1 << 13) #define USB_CTRL_CONFIG_OVERRIDE_XTL (1 << 12) #define USB_CTRL_CONFIG_CLK_SEL_SHIFT 4 #define USB_CTRL_CONFIG_CLK_SEL_MASK 3 #define USB_CTRL_CONFIG_CLK_SEL_12 0 #define USB_CTRL_CONFIG_CLK_SEL_24 1 #define USB_CTRL_CONFIG_CLK_SEL_48 2 #define USB_CTRL_CONFIG_OVER_CURRENT_AS_GPIO (1 << 8) #define USB_CTRL_CONFIG_SS_SIMULATION_MODE (1 << 2) #define USB_CTRL_CONFIG_RESUME_UTMI_PLS_DIS (1 << 1) #define USB_CTRL_CONFIG_UTMI_BACKWARD_ENB (1 << 0) #define AR71XX_GPIO_BASE 0x18040000 #define AR71XX_GPIO_OE 0x00 #define AR71XX_GPIO_IN 0x04 #define AR71XX_GPIO_OUT 0x08 #define AR71XX_GPIO_SET 0x0c #define AR71XX_GPIO_CLEAR 0x10 #define AR71XX_GPIO_INT 0x14 #define AR71XX_GPIO_INT_TYPE 0x18 #define AR71XX_GPIO_INT_POLARITY 0x1c #define AR71XX_GPIO_INT_PENDING 0x20 #define AR71XX_GPIO_INT_MASK 0x24 #define AR71XX_GPIO_FUNCTION 0x28 #define GPIO_FUNC_STEREO_EN (1 << 17) #define GPIO_FUNC_SLIC_EN (1 << 16) #define GPIO_FUNC_SPI_CS2_EN (1 << 13) /* CS2 is shared with GPIO_1 */ #define GPIO_FUNC_SPI_CS1_EN (1 << 12) /* CS1 is shared with GPIO_0 */ #define GPIO_FUNC_UART_EN (1 << 8) #define GPIO_FUNC_USB_OC_EN (1 << 4) #define GPIO_FUNC_USB_CLK_EN (0) #define AR71XX_BASE_FREQ 40000000 #define AR71XX_PLL_CPU_BASE 0x18050000 #define AR71XX_PLL_CPU_CONFIG 0x18050000 #define PLL_SW_UPDATE (1U << 31) #define PLL_LOCKED (1 << 30) #define PLL_AHB_DIV_SHIFT 20 #define PLL_AHB_DIV_MASK 7 #define PLL_DDR_DIV_SEL_SHIFT 18 #define PLL_DDR_DIV_SEL_MASK 3 #define PLL_CPU_DIV_SEL_SHIFT 16 #define PLL_CPU_DIV_SEL_MASK 3 #define PLL_LOOP_BW_SHIFT 12 #define PLL_LOOP_BW_MASK 0xf #define PLL_DIV_IN_SHIFT 10 #define PLL_DIV_IN_MASK 3 #define PLL_DIV_OUT_SHIFT 8 #define PLL_DIV_OUT_MASK 3 #define PLL_FB_SHIFT 3 #define PLL_FB_MASK 0x1f #define PLL_BYPASS (1 << 1) #define PLL_POWER_DOWN (1 << 0) #define AR71XX_PLL_SEC_CONFIG 0x18050004 #define AR71XX_PLL_ETH0_SHIFT 17 #define AR71XX_PLL_ETH1_SHIFT 19 #define AR71XX_PLL_CPU_CLK_CTRL 0x18050008 #define AR71XX_PLL_ETH_INT0_CLK 0x18050010 #define AR71XX_PLL_ETH_INT1_CLK 0x18050014 #define XPLL_ETH_INT_CLK_10 0x00991099 #define XPLL_ETH_INT_CLK_100 0x00441011 #define XPLL_ETH_INT_CLK_1000 0x13110000 #define XPLL_ETH_INT_CLK_1000_GMII 0x14110000 #define PLL_ETH_INT_CLK_10 0x00991099 #define PLL_ETH_INT_CLK_100 0x00001099 #define PLL_ETH_INT_CLK_1000 0x00110000 #define AR71XX_PLL_ETH_EXT_CLK 0x18050018 #define AR71XX_PLL_PCI_CLK 0x1805001C /* Reset block */ #define AR71XX_RST_BLOCK_BASE 0x18060000 #define AR71XX_RST_WDOG_CONTROL 0x18060008 #define RST_WDOG_LAST (1U << 31) #define RST_WDOG_ACTION_MASK 3 #define RST_WDOG_ACTION_RESET 3 #define RST_WDOG_ACTION_NMI 2 #define RST_WDOG_ACTION_GP_INTR 1 #define RST_WDOG_ACTION_NOACTION 0 #define AR71XX_RST_WDOG_TIMER 0x1806000C /* * APB interrupt status and mask register and interrupt bit numbers for */ #define AR71XX_MISC_INTR_STATUS 0x18060010 #define AR71XX_MISC_INTR_MASK 0x18060014 #define MISC_INTR_TIMER 0 #define MISC_INTR_ERROR 1 #define MISC_INTR_GPIO 2 #define MISC_INTR_UART 3 #define MISC_INTR_WATCHDOG 4 #define MISC_INTR_PERF 5 #define MISC_INTR_OHCI 6 #define MISC_INTR_DMA 7 #define AR71XX_PCI_INTR_STATUS 0x18060018 #define AR71XX_PCI_INTR_MASK 0x1806001C #define PCI_INTR_CORE (1 << 4) #define AR71XX_RST_RESET 0x18060024 #define RST_RESET_FULL_CHIP (1 << 24) /* Same as pulling the reset pin */ #define RST_RESET_CPU_COLD (1 << 20) /* Cold reset */ #define RST_RESET_GE1_MAC (1 << 13) #define RST_RESET_GE1_PHY (1 << 12) #define RST_RESET_GE0_MAC (1 << 9) #define RST_RESET_GE0_PHY (1 << 8) #define RST_RESET_USB_OHCI_DLL (1 << 6) #define RST_RESET_USB_HOST (1 << 5) #define RST_RESET_USB_PHY (1 << 4) #define RST_RESET_PCI_BUS (1 << 1) #define RST_RESET_PCI_CORE (1 << 0) /* Chipset revision details */ #define AR71XX_RST_RESET_REG_REV_ID 0x18060090 #define REV_ID_MAJOR_MASK 0xfff0 #define REV_ID_MAJOR_AR71XX 0x00a0 #define REV_ID_MAJOR_AR913X 0x00b0 #define REV_ID_MAJOR_AR7240 0x00c0 #define REV_ID_MAJOR_AR7241 0x0100 #define REV_ID_MAJOR_AR7242 0x1100 /* AR71XX chipset revision details */ #define AR71XX_REV_ID_MINOR_MASK 0x3 #define AR71XX_REV_ID_MINOR_AR7130 0x0 #define AR71XX_REV_ID_MINOR_AR7141 0x1 #define AR71XX_REV_ID_MINOR_AR7161 0x2 #define AR71XX_REV_ID_REVISION_MASK 0x3 #define AR71XX_REV_ID_REVISION_SHIFT 2 /* AR724X chipset revision details */ #define AR724X_REV_ID_REVISION_MASK 0x3 /* AR91XX chipset revision details */ #define AR91XX_REV_ID_MINOR_MASK 0x3 #define AR91XX_REV_ID_MINOR_AR9130 0x0 #define AR91XX_REV_ID_MINOR_AR9132 0x1 #define AR91XX_REV_ID_REVISION_MASK 0x3 #define AR91XX_REV_ID_REVISION_SHIFT 2 typedef enum { AR71XX_MII_MODE_NONE = 0, AR71XX_MII_MODE_GMII, AR71XX_MII_MODE_MII, AR71XX_MII_MODE_RGMII, AR71XX_MII_MODE_RMII, AR71XX_MII_MODE_SGMII /* not hardware defined, though! */ } ar71xx_mii_mode; /* * AR71xx MII control region */ #define AR71XX_MII0_CTRL 0x18070000 #define MII_CTRL_SPEED_SHIFT 4 #define MII_CTRL_SPEED_MASK 3 #define MII_CTRL_SPEED_10 0 #define MII_CTRL_SPEED_100 1 #define MII_CTRL_SPEED_1000 2 #define MII_CTRL_IF_MASK 3 #define MII_CTRL_IF_SHIFT 0 #define MII0_CTRL_IF_GMII 0 #define MII0_CTRL_IF_MII 1 #define MII0_CTRL_IF_RGMII 2 #define MII0_CTRL_IF_RMII 3 #define AR71XX_MII1_CTRL 0x18070004 #define MII1_CTRL_IF_RGMII 0 #define MII1_CTRL_IF_RMII 1 /* * GigE adapters region */ #define AR71XX_MAC0_BASE 0x19000000 #define AR71XX_MAC1_BASE 0x1A000000 #define AR71XX_MAC_CFG1 0x00 #define MAC_CFG1_SOFT_RESET (1U << 31) #define MAC_CFG1_SIMUL_RESET (1 << 30) #define MAC_CFG1_MAC_RX_BLOCK_RESET (1 << 19) #define MAC_CFG1_MAC_TX_BLOCK_RESET (1 << 18) #define MAC_CFG1_RX_FUNC_RESET (1 << 17) #define MAC_CFG1_TX_FUNC_RESET (1 << 16) #define MAC_CFG1_LOOPBACK (1 << 8) #define MAC_CFG1_RXFLOW_CTRL (1 << 5) #define MAC_CFG1_TXFLOW_CTRL (1 << 4) #define MAC_CFG1_SYNC_RX (1 << 3) #define MAC_CFG1_RX_ENABLE (1 << 2) #define MAC_CFG1_SYNC_TX (1 << 1) #define MAC_CFG1_TX_ENABLE (1 << 0) #define AR71XX_MAC_CFG2 0x04 #define MAC_CFG2_PREAMBLE_LEN_MASK 0xf #define MAC_CFG2_PREAMBLE_LEN_SHIFT 12 #define MAC_CFG2_IFACE_MODE_1000 (2 << 8) #define MAC_CFG2_IFACE_MODE_10_100 (1 << 8) #define MAC_CFG2_IFACE_MODE_SHIFT 8 #define MAC_CFG2_IFACE_MODE_MASK 3 #define MAC_CFG2_HUGE_FRAME (1 << 5) #define MAC_CFG2_LENGTH_FIELD (1 << 4) #define MAC_CFG2_ENABLE_PADCRC (1 << 2) #define MAC_CFG2_ENABLE_CRC (1 << 1) #define MAC_CFG2_FULL_DUPLEX (1 << 0) #define AR71XX_MAC_IFG 0x08 #define AR71XX_MAC_HDUPLEX 0x0C #define AR71XX_MAC_MAX_FRAME_LEN 0x10 #define AR71XX_MAC_MII_CFG 0x20 #define MAC_MII_CFG_RESET (1U << 31) #define MAC_MII_CFG_SCAN_AUTO_INC (1 << 5) #define MAC_MII_CFG_PREAMBLE_SUP (1 << 4) #define MAC_MII_CFG_CLOCK_SELECT_MASK 0x7 #define MAC_MII_CFG_CLOCK_SELECT_MASK_AR933X 0xf #define MAC_MII_CFG_CLOCK_DIV_4 0 #define MAC_MII_CFG_CLOCK_DIV_6 2 #define MAC_MII_CFG_CLOCK_DIV_8 3 #define MAC_MII_CFG_CLOCK_DIV_10 4 #define MAC_MII_CFG_CLOCK_DIV_14 5 #define MAC_MII_CFG_CLOCK_DIV_20 6 #define MAC_MII_CFG_CLOCK_DIV_28 7 /* .. and the AR933x/AR934x extensions */ #define MAC_MII_CFG_CLOCK_DIV_34 8 #define MAC_MII_CFG_CLOCK_DIV_42 9 #define MAC_MII_CFG_CLOCK_DIV_50 10 #define MAC_MII_CFG_CLOCK_DIV_58 11 #define MAC_MII_CFG_CLOCK_DIV_66 12 #define MAC_MII_CFG_CLOCK_DIV_74 13 #define MAC_MII_CFG_CLOCK_DIV_82 14 #define MAC_MII_CFG_CLOCK_DIV_98 15 #define AR71XX_MAC_MII_CMD 0x24 #define MAC_MII_CMD_SCAN_CYCLE (1 << 1) #define MAC_MII_CMD_READ 1 #define MAC_MII_CMD_WRITE 0 #define AR71XX_MAC_MII_ADDR 0x28 #define MAC_MII_PHY_ADDR_SHIFT 8 #define MAC_MII_PHY_ADDR_MASK 0xff #define MAC_MII_REG_MASK 0x1f #define AR71XX_MAC_MII_CONTROL 0x2C #define MAC_MII_CONTROL_MASK 0xffff #define AR71XX_MAC_MII_STATUS 0x30 #define MAC_MII_STATUS_MASK 0xffff #define AR71XX_MAC_MII_INDICATOR 0x34 #define MAC_MII_INDICATOR_NOT_VALID (1 << 2) #define MAC_MII_INDICATOR_SCANNING (1 << 1) #define MAC_MII_INDICATOR_BUSY (1 << 0) #define AR71XX_MAC_IFCONTROL 0x38 #define MAC_IFCONTROL_SPEED (1 << 16) #define AR71XX_MAC_STA_ADDR1 0x40 #define AR71XX_MAC_STA_ADDR2 0x44 #define AR71XX_MAC_FIFO_CFG0 0x48 #define FIFO_CFG0_TX_FABRIC (1 << 4) #define FIFO_CFG0_TX_SYSTEM (1 << 3) #define FIFO_CFG0_RX_FABRIC (1 << 2) #define FIFO_CFG0_RX_SYSTEM (1 << 1) #define FIFO_CFG0_WATERMARK (1 << 0) #define FIFO_CFG0_ALL ((1 << 5) - 1) #define FIFO_CFG0_ENABLE_SHIFT 8 #define AR71XX_MAC_FIFO_CFG1 0x4C #define AR71XX_MAC_FIFO_CFG2 0x50 #define AR71XX_MAC_FIFO_TX_THRESHOLD 0x54 #define AR71XX_MAC_FIFO_RX_FILTMATCH 0x58 /* * These flags applicable both to AR71XX_MAC_FIFO_RX_FILTMASK and * to AR71XX_MAC_FIFO_RX_FILTMATCH */ #define FIFO_RX_MATCH_UNICAST (1 << 17) #define FIFO_RX_MATCH_TRUNC_FRAME (1 << 16) #define FIFO_RX_MATCH_VLAN_TAG (1 << 15) #define FIFO_RX_MATCH_UNSUP_OPCODE (1 << 14) #define FIFO_RX_MATCH_PAUSE_FRAME (1 << 13) #define FIFO_RX_MATCH_CTRL_FRAME (1 << 12) #define FIFO_RX_MATCH_LONG_EVENT (1 << 11) #define FIFO_RX_MATCH_DRIBBLE_NIBBLE (1 << 10) #define FIFO_RX_MATCH_BCAST (1 << 9) #define FIFO_RX_MATCH_MCAST (1 << 8) #define FIFO_RX_MATCH_OK (1 << 7) #define FIFO_RX_MATCH_OORANGE (1 << 6) #define FIFO_RX_MATCH_LEN_MSMTCH (1 << 5) #define FIFO_RX_MATCH_CRC_ERROR (1 << 4) #define FIFO_RX_MATCH_CODE_ERROR (1 << 3) #define FIFO_RX_MATCH_FALSE_CARRIER (1 << 2) #define FIFO_RX_MATCH_RX_DV_EVENT (1 << 1) #define FIFO_RX_MATCH_DROP_EVENT (1 << 0) /* * Exclude unicast and truncated frames from matching */ #define FIFO_RX_FILTMATCH_DEFAULT \ (FIFO_RX_MATCH_VLAN_TAG | \ FIFO_RX_MATCH_UNSUP_OPCODE | \ FIFO_RX_MATCH_PAUSE_FRAME | \ FIFO_RX_MATCH_CTRL_FRAME | \ FIFO_RX_MATCH_LONG_EVENT | \ FIFO_RX_MATCH_DRIBBLE_NIBBLE | \ FIFO_RX_MATCH_BCAST | \ FIFO_RX_MATCH_MCAST | \ FIFO_RX_MATCH_OK | \ FIFO_RX_MATCH_OORANGE | \ FIFO_RX_MATCH_LEN_MSMTCH | \ FIFO_RX_MATCH_CRC_ERROR | \ FIFO_RX_MATCH_CODE_ERROR | \ FIFO_RX_MATCH_FALSE_CARRIER | \ FIFO_RX_MATCH_RX_DV_EVENT | \ FIFO_RX_MATCH_DROP_EVENT) #define AR71XX_MAC_FIFO_RX_FILTMASK 0x5C #define FIFO_RX_MASK_BYTE_MODE (1 << 19) #define FIFO_RX_MASK_NO_SHORT_FRAME (1 << 18) #define FIFO_RX_MASK_BIT17 (1 << 17) #define FIFO_RX_MASK_BIT16 (1 << 16) #define FIFO_RX_MASK_TRUNC_FRAME (1 << 15) #define FIFO_RX_MASK_LONG_EVENT (1 << 14) #define FIFO_RX_MASK_VLAN_TAG (1 << 13) #define FIFO_RX_MASK_UNSUP_OPCODE (1 << 12) #define FIFO_RX_MASK_PAUSE_FRAME (1 << 11) #define FIFO_RX_MASK_CTRL_FRAME (1 << 10) #define FIFO_RX_MASK_DRIBBLE_NIBBLE (1 << 9) #define FIFO_RX_MASK_BCAST (1 << 8) #define FIFO_RX_MASK_MCAST (1 << 7) #define FIFO_RX_MASK_OK (1 << 6) #define FIFO_RX_MASK_OORANGE (1 << 5) #define FIFO_RX_MASK_LEN_MSMTCH (1 << 4) #define FIFO_RX_MASK_CODE_ERROR (1 << 3) #define FIFO_RX_MASK_FALSE_CARRIER (1 << 2) #define FIFO_RX_MASK_RX_DV_EVENT (1 << 1) #define FIFO_RX_MASK_DROP_EVENT (1 << 0) /* * Len. mismatch, unsup. opcode and short frmae bits excluded */ #define FIFO_RX_FILTMASK_DEFAULT \ (FIFO_RX_MASK_NO_SHORT_FRAME | \ FIFO_RX_MASK_BIT17 | \ FIFO_RX_MASK_BIT16 | \ FIFO_RX_MASK_TRUNC_FRAME | \ FIFO_RX_MASK_LONG_EVENT | \ FIFO_RX_MASK_VLAN_TAG | \ FIFO_RX_MASK_PAUSE_FRAME | \ FIFO_RX_MASK_CTRL_FRAME | \ FIFO_RX_MASK_DRIBBLE_NIBBLE | \ FIFO_RX_MASK_BCAST | \ FIFO_RX_MASK_MCAST | \ FIFO_RX_MASK_OK | \ FIFO_RX_MASK_OORANGE | \ FIFO_RX_MASK_CODE_ERROR | \ FIFO_RX_MASK_FALSE_CARRIER | \ FIFO_RX_MASK_RX_DV_EVENT | \ FIFO_RX_MASK_DROP_EVENT) #define AR71XX_MAC_FIFO_RAM0 0x60 #define AR71XX_MAC_FIFO_RAM1 0x64 #define AR71XX_MAC_FIFO_RAM2 0x68 #define AR71XX_MAC_FIFO_RAM3 0x6C #define AR71XX_MAC_FIFO_RAM4 0x70 #define AR71XX_MAC_FIFO_RAM5 0x74 #define AR71XX_MAC_FIFO_RAM6 0x78 #define AR71XX_DMA_TX_CONTROL 0x180 #define DMA_TX_CONTROL_EN (1 << 0) #define AR71XX_DMA_TX_DESC 0x184 #define AR71XX_DMA_TX_STATUS 0x188 #define DMA_TX_STATUS_PCOUNT_MASK 0xff #define DMA_TX_STATUS_PCOUNT_SHIFT 16 #define DMA_TX_STATUS_BUS_ERROR (1 << 3) #define DMA_TX_STATUS_UNDERRUN (1 << 1) #define DMA_TX_STATUS_PKT_SENT (1 << 0) #define AR71XX_DMA_RX_CONTROL 0x18C #define DMA_RX_CONTROL_EN (1 << 0) #define AR71XX_DMA_RX_DESC 0x190 #define AR71XX_DMA_RX_STATUS 0x194 #define DMA_RX_STATUS_PCOUNT_MASK 0xff #define DMA_RX_STATUS_PCOUNT_SHIFT 16 #define DMA_RX_STATUS_BUS_ERROR (1 << 3) #define DMA_RX_STATUS_OVERFLOW (1 << 2) #define DMA_RX_STATUS_PKT_RECVD (1 << 0) #define AR71XX_DMA_INTR 0x198 #define AR71XX_DMA_INTR_STATUS 0x19C #define DMA_INTR_ALL ((1 << 8) - 1) #define DMA_INTR_RX_BUS_ERROR (1 << 7) #define DMA_INTR_RX_OVERFLOW (1 << 6) #define DMA_INTR_RX_PKT_RCVD (1 << 4) #define DMA_INTR_TX_BUS_ERROR (1 << 3) #define DMA_INTR_TX_UNDERRUN (1 << 1) #define DMA_INTR_TX_PKT_SENT (1 << 0) #define AR71XX_SPI_BASE 0x1f000000 #define AR71XX_SPI_FS 0x00 #define AR71XX_SPI_CTRL 0x04 #define SPI_CTRL_REMAP_DISABLE (1 << 6) #define SPI_CTRL_CLOCK_DIVIDER_MASK ((1 << 6) - 1) #define AR71XX_SPI_IO_CTRL 0x08 #define SPI_IO_CTRL_CS2 (1 << 18) #define SPI_IO_CTRL_CS1 (1 << 17) #define SPI_IO_CTRL_CS0 (1 << 16) #define SPI_IO_CTRL_CSMASK (7 << 16) #define SPI_IO_CTRL_CLK (1 << 8) #define SPI_IO_CTRL_DO 1 #define AR71XX_SPI_RDS 0x0C #define ATH_READ_REG(reg) \ *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1((reg))) /* * Note: Don't put a flush read here; some users (eg the AR724x PCI fixup code) * requires write-only space to certain registers. Doing the read afterwards * causes things to break. */ #define ATH_WRITE_REG(reg, val) \ *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1((reg))) = (val) static inline void ar71xx_ddr_flush(uint32_t reg) { ATH_WRITE_REG(reg, 1); while ((ATH_READ_REG(reg) & 0x1)) ; ATH_WRITE_REG(reg, 1); while ((ATH_READ_REG(reg) & 0x1)) ; } static inline void ar71xx_write_pll(uint32_t cfg_reg, uint32_t pll_reg, uint32_t pll, uint32_t pll_reg_shift) { uint32_t sec_cfg; /* set PLL registers */ sec_cfg = ATH_READ_REG(cfg_reg); sec_cfg &= ~(3 << pll_reg_shift); sec_cfg |= (2 << pll_reg_shift); ATH_WRITE_REG(cfg_reg, sec_cfg); DELAY(100); ATH_WRITE_REG(pll_reg, pll); sec_cfg |= (3 << pll_reg_shift); ATH_WRITE_REG(cfg_reg, sec_cfg); DELAY(100); sec_cfg &= ~(3 << pll_reg_shift); ATH_WRITE_REG(cfg_reg, sec_cfg); DELAY(100); } #endif /* _AR71XX_REG_H_ */ Index: head/sys/mips/atheros/ar724x_chip.c =================================================================== --- head/sys/mips/atheros/ar724x_chip.c (revision 326258) +++ head/sys/mips/atheros/ar724x_chip.c (revision 326259) @@ -1,244 +1,246 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Adrian Chadd * 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 "opt_ddb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void ar724x_chip_detect_mem_size(void) { } static void ar724x_chip_detect_sys_frequency(void) { uint32_t pll; uint32_t freq; uint32_t div; u_ar71xx_mdio_freq = u_ar71xx_refclk = AR724X_BASE_FREQ; pll = ATH_READ_REG(AR724X_PLL_REG_CPU_CONFIG); div = ((pll >> AR724X_PLL_DIV_SHIFT) & AR724X_PLL_DIV_MASK); freq = div * AR724X_BASE_FREQ; div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK); freq *= div; u_ar71xx_cpu_freq = freq; div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1; u_ar71xx_ddr_freq = freq / div; div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2; u_ar71xx_ahb_freq = u_ar71xx_cpu_freq / div; u_ar71xx_wdt_freq = u_ar71xx_cpu_freq / div; u_ar71xx_uart_freq = u_ar71xx_cpu_freq / div; } static void ar724x_chip_device_stop(uint32_t mask) { uint32_t mask_inv, reg; mask_inv = mask & AR724X_RESET_MODULE_USB_OHCI_DLL; reg = ATH_READ_REG(AR724X_RESET_REG_RESET_MODULE); reg |= mask; reg &= ~mask_inv; ATH_WRITE_REG(AR724X_RESET_REG_RESET_MODULE, reg); } static void ar724x_chip_device_start(uint32_t mask) { uint32_t mask_inv, reg; mask_inv = mask & AR724X_RESET_MODULE_USB_OHCI_DLL; reg = ATH_READ_REG(AR724X_RESET_REG_RESET_MODULE); reg &= ~mask; reg |= mask_inv; ATH_WRITE_REG(AR724X_RESET_REG_RESET_MODULE, reg); } static int ar724x_chip_device_stopped(uint32_t mask) { uint32_t reg; reg = ATH_READ_REG(AR724X_RESET_REG_RESET_MODULE); return ((reg & mask) == mask); } static void ar724x_chip_set_mii_speed(uint32_t unit, uint32_t speed) { /* XXX TODO */ return; } /* * XXX TODO: set the PLL for arge0 only on AR7242. * The PLL/clock requirements are different. * * Otherwise, it's a NULL function for AR7240, AR7241 and * AR7242 arge1. */ static void ar724x_chip_set_pll_ge(int unit, int speed, uint32_t pll) { switch (unit) { case 0: /* XXX TODO */ break; case 1: /* XXX TODO */ break; default: printf("%s: invalid PLL set for arge unit: %d\n", __func__, unit); return; } } static void ar724x_chip_ddr_flush(ar71xx_flush_ddr_id_t id) { switch (id) { case AR71XX_CPU_DDR_FLUSH_GE0: ar71xx_ddr_flush(AR724X_DDR_REG_FLUSH_GE0); break; case AR71XX_CPU_DDR_FLUSH_GE1: ar71xx_ddr_flush(AR724X_DDR_REG_FLUSH_GE1); break; case AR71XX_CPU_DDR_FLUSH_USB: ar71xx_ddr_flush(AR724X_DDR_REG_FLUSH_USB); break; case AR71XX_CPU_DDR_FLUSH_PCIE: ar71xx_ddr_flush(AR724X_DDR_REG_FLUSH_PCIE); break; default: printf("%s: invalid DDR flush id (%d)\n", __func__, id); break; } } static uint32_t ar724x_chip_get_eth_pll(unsigned int mac, int speed) { return (0); } static void ar724x_chip_init_usb_peripheral(void) { switch (ar71xx_soc) { case AR71XX_SOC_AR7240: ar71xx_device_stop(AR724X_RESET_MODULE_USB_OHCI_DLL | AR724X_RESET_USB_HOST); DELAY(1000); ar71xx_device_start(AR724X_RESET_MODULE_USB_OHCI_DLL | AR724X_RESET_USB_HOST); DELAY(1000); /* * WAR for HW bug. Here it adjusts the duration * between two SOFS. */ ATH_WRITE_REG(AR71XX_USB_CTRL_FLADJ, (3 << USB_CTRL_FLADJ_A0_SHIFT)); break; case AR71XX_SOC_AR7241: case AR71XX_SOC_AR7242: ar71xx_device_start(AR724X_RESET_MODULE_USB_OHCI_DLL); DELAY(100); ar71xx_device_start(AR724X_RESET_USB_HOST); DELAY(100); ar71xx_device_start(AR724X_RESET_USB_PHY); DELAY(100); break; default: break; } } struct ar71xx_cpu_def ar724x_chip_def = { &ar724x_chip_detect_mem_size, &ar724x_chip_detect_sys_frequency, &ar724x_chip_device_stop, &ar724x_chip_device_start, &ar724x_chip_device_stopped, &ar724x_chip_set_pll_ge, &ar724x_chip_set_mii_speed, &ar71xx_chip_set_mii_if, &ar724x_chip_get_eth_pll, &ar724x_chip_ddr_flush, &ar724x_chip_init_usb_peripheral }; Index: head/sys/mips/atheros/ar724x_chip.h =================================================================== --- head/sys/mips/atheros/ar724x_chip.h (revision 326258) +++ head/sys/mips/atheros/ar724x_chip.h (revision 326259) @@ -1,34 +1,36 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Adrian Chadd * 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$ */ #ifndef __AR724X_CHIP_H__ #define __AR724X_CHIP_H__ extern struct ar71xx_cpu_def ar724x_chip_def; #endif Index: head/sys/mips/atheros/ar724x_pci.c =================================================================== --- head/sys/mips/atheros/ar724x_pci.c (revision 326258) +++ head/sys/mips/atheros/ar724x_pci.c (revision 326259) @@ -1,672 +1,674 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009, Oleksandr Tymoshenko * Copyright (c) 2011, Luiz Otavio O Souza. * 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 unmodified, 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 "opt_ar71xx.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcib_if.h" #include #include #include #include #include #ifdef AR71XX_ATH_EEPROM #include #endif /* AR71XX_ATH_EEPROM */ #undef AR724X_PCI_DEBUG #ifdef AR724X_PCI_DEBUG #define dprintf printf #else #define dprintf(x, arg...) #endif struct ar71xx_pci_softc { device_t sc_dev; int sc_busno; struct rman sc_mem_rman; struct rman sc_irq_rman; struct intr_event *sc_eventstab[AR71XX_PCI_NIRQS]; mips_intrcnt_t sc_intr_counter[AR71XX_PCI_NIRQS]; struct resource *sc_irq; void *sc_ih; }; static int ar724x_pci_setup_intr(device_t, device_t, struct resource *, int, driver_filter_t *, driver_intr_t *, void *, void **); static int ar724x_pci_teardown_intr(device_t, device_t, struct resource *, void *); static int ar724x_pci_intr(void *); static void ar724x_pci_write(uint32_t reg, uint32_t offset, uint32_t data, int bytes) { uint32_t val, mask, shift; /* Register access is 32-bit aligned */ shift = (offset & 3) * 8; if (bytes % 4) mask = (1 << (bytes * 8)) - 1; else mask = 0xffffffff; rmb(); val = ATH_READ_REG(reg + (offset & ~3)); val &= ~(mask << shift); val |= ((data & mask) << shift); ATH_WRITE_REG(reg + (offset & ~3), val); wmb(); dprintf("%s: %#x/%#x addr=%#x, data=%#x(%#x), bytes=%d\n", __func__, reg, reg + (offset & ~3), offset, data, val, bytes); } static uint32_t ar724x_pci_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int bytes) { uint32_t data, shift, mask; /* Register access is 32-bit aligned */ shift = (reg & 3) * 8; /* Create a mask based on the width, post-shift */ if (bytes == 2) mask = 0xffff; else if (bytes == 1) mask = 0xff; else mask = 0xffffffff; dprintf("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot, func, reg, bytes); rmb(); if ((bus == 0) && (slot == 0) && (func == 0)) data = ATH_READ_REG(AR724X_PCI_CFG_BASE + (reg & ~3)); else data = -1; /* Get request bytes from 32-bit word */ data = (data >> shift) & mask; dprintf("%s: read 0x%x\n", __func__, data); return (data); } static void ar724x_pci_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t data, int bytes) { dprintf("%s: tag (%x, %x, %x) reg %d(%d): %x\n", __func__, bus, slot, func, reg, bytes, data); if ((bus != 0) || (slot != 0) || (func != 0)) return; /* * WAR for BAR issue on AR7240 - We are unable to access the PCI * device space if we set the BAR with proper base address. * * However, we _do_ want to allow programming in the probe value * (0xffffffff) so the PCI code can find out how big the memory * map is for this device. Without it, it'll think the memory * map is 32 bits wide, the PCI code will then end up thinking * the register window is '0' and fail to allocate resources. * * Note: Test on AR7241/AR7242/AR9344! Those use a WAR value of * 0x1000ffff. */ if (reg == PCIR_BAR(0) && bytes == 4 && ar71xx_soc == AR71XX_SOC_AR7240 && data != 0xffffffff) ar724x_pci_write(AR724X_PCI_CFG_BASE, reg, 0xffff, bytes); else ar724x_pci_write(AR724X_PCI_CFG_BASE, reg, data, bytes); } static void ar724x_pci_mask_irq(void *source) { uint32_t reg; unsigned int irq = (unsigned int)source; /* XXX - Only one interrupt ? Only one device ? */ if (irq != AR71XX_PCI_IRQ_START) return; /* Update the interrupt mask reg */ reg = ATH_READ_REG(AR724X_PCI_INTR_MASK); ATH_WRITE_REG(AR724X_PCI_INTR_MASK, reg & ~AR724X_PCI_INTR_DEV0); /* Clear any pending interrupt */ reg = ATH_READ_REG(AR724X_PCI_INTR_STATUS); ATH_WRITE_REG(AR724X_PCI_INTR_STATUS, reg | AR724X_PCI_INTR_DEV0); } static void ar724x_pci_unmask_irq(void *source) { uint32_t reg; unsigned int irq = (unsigned int)source; /* XXX */ if (irq != AR71XX_PCI_IRQ_START) return; /* Update the interrupt mask reg */ reg = ATH_READ_REG(AR724X_PCI_INTR_MASK); ATH_WRITE_REG(AR724X_PCI_INTR_MASK, reg | AR724X_PCI_INTR_DEV0); } static int ar724x_pci_setup(device_t dev) { uint32_t reg; /* setup COMMAND register */ reg = PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN | PCIM_CMD_SERRESPEN | PCIM_CMD_BACKTOBACK | PCIM_CMD_PERRESPEN | PCIM_CMD_MWRICEN; ar724x_pci_write(AR724X_PCI_CRP_BASE, PCIR_COMMAND, reg, 2); ar724x_pci_write(AR724X_PCI_CRP_BASE, 0x20, 0x1ff01000, 4); ar724x_pci_write(AR724X_PCI_CRP_BASE, 0x24, 0x1ff01000, 4); reg = ATH_READ_REG(AR724X_PCI_RESET); if (reg != 0x7) { DELAY(100000); ATH_WRITE_REG(AR724X_PCI_RESET, 0); DELAY(100); ATH_WRITE_REG(AR724X_PCI_RESET, 4); DELAY(100000); } if (ar71xx_soc == AR71XX_SOC_AR7240) reg = AR724X_PCI_APP_LTSSM_ENABLE; else reg = 0x1ffc1; ATH_WRITE_REG(AR724X_PCI_APP, reg); /* Flush write */ (void) ATH_READ_REG(AR724X_PCI_APP); DELAY(1000); reg = ATH_READ_REG(AR724X_PCI_RESET); if ((reg & AR724X_PCI_RESET_LINK_UP) == 0) { device_printf(dev, "no PCIe controller found\n"); return (ENXIO); } if (ar71xx_soc == AR71XX_SOC_AR7241 || ar71xx_soc == AR71XX_SOC_AR7242) { reg = ATH_READ_REG(AR724X_PCI_APP); reg |= (1 << 16); ATH_WRITE_REG(AR724X_PCI_APP, reg); } return (0); } #ifdef AR71XX_ATH_EEPROM #define AR5416_EEPROM_MAGIC 0xa55a /* * XXX - This should not be here ! And this looks like Atheros (if_ath) only. */ static void ar724x_pci_fixup(device_t dev, long flash_addr, int len) { uint32_t bar0, reg, val; uint16_t *cal_data = (uint16_t *) MIPS_PHYS_TO_KSEG1(flash_addr); #if 0 if (cal_data[0] != AR5416_EEPROM_MAGIC) { device_printf(dev, "%s: Invalid calibration data from 0x%x\n", __func__, (uintptr_t) flash_addr); return; } #endif /* Save bar(0) address - just to flush bar(0) (SoC WAR) ? */ bar0 = ar724x_pci_read_config(dev, 0, 0, 0, PCIR_BAR(0), 4); /* Write temporary BAR0 to map the NIC into a fixed location */ /* XXX AR7240: 0xffff; 7241/7242/9344: 0x1000ffff */ ar724x_pci_write_config(dev, 0, 0, 0, PCIR_BAR(0), AR71XX_PCI_MEM_BASE, 4); val = ar724x_pci_read_config(dev, 0, 0, 0, PCIR_COMMAND, 2); val |= (PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); ar724x_pci_write_config(dev, 0, 0, 0, PCIR_COMMAND, val, 2); /* set pointer to first reg address */ cal_data += 3; while (*cal_data != 0xffff) { reg = *cal_data++; val = *cal_data++; val |= (*cal_data++) << 16; if (bootverbose) printf(" 0x%08x=0x%08x\n", reg, val); /* Write eeprom fixup data to device memory */ ATH_WRITE_REG(AR71XX_PCI_MEM_BASE + reg, val); DELAY(100); } val = ar724x_pci_read_config(dev, 0, 0, 0, PCIR_COMMAND, 2); val &= ~(PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN); ar724x_pci_write_config(dev, 0, 0, 0, PCIR_COMMAND, val, 2); /* Write the saved bar(0) address */ ar724x_pci_write_config(dev, 0, 0, 0, PCIR_BAR(0), bar0, 4); } #undef AR5416_EEPROM_MAGIC /* * XXX This is (mostly) duplicated with ar71xx_pci.c. * It should at some point be fixed. */ static void ar724x_pci_slot_fixup(device_t dev) { long int flash_addr; char buf[64]; int size; /* * Check whether the given slot has a hint to poke. */ if (bootverbose) device_printf(dev, "%s: checking dev %s, %d/%d/%d\n", __func__, device_get_nameunit(dev), 0, 0, 0); snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_addr", 0, 0, 0); if (resource_long_value(device_get_name(dev), device_get_unit(dev), buf, &flash_addr) == 0) { snprintf(buf, sizeof(buf), "bus.%d.%d.%d.ath_fixup_size", 0, 0, 0); if (resource_int_value(device_get_name(dev), device_get_unit(dev), buf, &size) != 0) { device_printf(dev, "%s: missing hint '%s', aborting EEPROM\n", __func__, buf); return; } device_printf(dev, "found EEPROM at 0x%lx on %d.%d.%d\n", flash_addr, 0, 0, 0); ar724x_pci_fixup(dev, flash_addr, size); ar71xx_pci_slot_create_eeprom_firmware(dev, 0, 0, 0, flash_addr, size); } } #endif /* AR71XX_ATH_EEPROM */ static int ar724x_pci_probe(device_t dev) { return (BUS_PROBE_NOWILDCARD); } static int ar724x_pci_attach(device_t dev) { struct ar71xx_pci_softc *sc = device_get_softc(dev); int rid = 0; sc->sc_mem_rman.rm_type = RMAN_ARRAY; sc->sc_mem_rman.rm_descr = "ar724x PCI memory window"; if (rman_init(&sc->sc_mem_rman) != 0 || rman_manage_region(&sc->sc_mem_rman, AR71XX_PCI_MEM_BASE, AR71XX_PCI_MEM_BASE + AR71XX_PCI_MEM_SIZE - 1) != 0) { panic("ar724x_pci_attach: failed to set up I/O rman"); } sc->sc_irq_rman.rm_type = RMAN_ARRAY; sc->sc_irq_rman.rm_descr = "ar724x PCI IRQs"; if (rman_init(&sc->sc_irq_rman) != 0 || rman_manage_region(&sc->sc_irq_rman, AR71XX_PCI_IRQ_START, AR71XX_PCI_IRQ_END) != 0) panic("ar724x_pci_attach: failed to set up IRQ rman"); /* Disable interrupts */ ATH_WRITE_REG(AR724X_PCI_INTR_STATUS, 0); ATH_WRITE_REG(AR724X_PCI_INTR_MASK, 0); /* Hook up our interrupt handler. */ if ((sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { device_printf(dev, "unable to allocate IRQ resource\n"); return (ENXIO); } if ((bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC, ar724x_pci_intr, NULL, sc, &sc->sc_ih))) { device_printf(dev, "WARNING: unable to register interrupt handler\n"); return (ENXIO); } /* Reset PCIe core and PCIe PHY */ ar71xx_device_stop(AR724X_RESET_PCIE); ar71xx_device_stop(AR724X_RESET_PCIE_PHY); ar71xx_device_stop(AR724X_RESET_PCIE_PHY_SERIAL); DELAY(100); ar71xx_device_start(AR724X_RESET_PCIE_PHY_SERIAL); DELAY(100); ar71xx_device_start(AR724X_RESET_PCIE_PHY); ar71xx_device_start(AR724X_RESET_PCIE); if (ar724x_pci_setup(dev)) return (ENXIO); #ifdef AR71XX_ATH_EEPROM ar724x_pci_slot_fixup(dev); #endif /* AR71XX_ATH_EEPROM */ /* Fixup internal PCI bridge */ ar724x_pci_write_config(dev, 0, 0, 0, PCIR_COMMAND, PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN | PCIM_CMD_SERRESPEN | PCIM_CMD_BACKTOBACK | PCIM_CMD_PERRESPEN | PCIM_CMD_MWRICEN, 2); device_add_child(dev, "pci", -1); return (bus_generic_attach(dev)); } static int ar724x_pci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { struct ar71xx_pci_softc *sc = device_get_softc(dev); switch (which) { case PCIB_IVAR_DOMAIN: *result = 0; return (0); case PCIB_IVAR_BUS: *result = sc->sc_busno; return (0); } return (ENOENT); } static int ar724x_pci_write_ivar(device_t dev, device_t child, int which, uintptr_t result) { struct ar71xx_pci_softc * sc = device_get_softc(dev); switch (which) { case PCIB_IVAR_BUS: sc->sc_busno = result; return (0); } return (ENOENT); } static struct resource * ar724x_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct ar71xx_pci_softc *sc = device_get_softc(bus); struct resource *rv; struct rman *rm; switch (type) { case SYS_RES_IRQ: rm = &sc->sc_irq_rman; break; case SYS_RES_MEMORY: rm = &sc->sc_mem_rman; break; default: return (NULL); } rv = rman_reserve_resource(rm, start, end, count, flags, child); if (rv == NULL) return (NULL); rman_set_rid(rv, *rid); if (flags & RF_ACTIVE) { if (bus_activate_resource(child, type, *rid, rv)) { rman_release_resource(rv); return (NULL); } } return (rv); } static int ar724x_pci_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { int res = (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), child, type, rid, r)); if (!res) { switch(type) { case SYS_RES_MEMORY: case SYS_RES_IOPORT: rman_set_bustag(r, ar71xx_bus_space_pcimem); break; } } return (res); } static int ar724x_pci_setup_intr(device_t bus, device_t child, struct resource *ires, int flags, driver_filter_t *filt, driver_intr_t *handler, void *arg, void **cookiep) { struct ar71xx_pci_softc *sc = device_get_softc(bus); struct intr_event *event; int irq, error; irq = rman_get_start(ires); if (irq > AR71XX_PCI_IRQ_END) panic("%s: bad irq %d", __func__, irq); event = sc->sc_eventstab[irq]; if (event == NULL) { error = intr_event_create(&event, (void *)irq, 0, irq, ar724x_pci_mask_irq, ar724x_pci_unmask_irq, NULL, NULL, "pci intr%d:", irq); if (error == 0) { sc->sc_eventstab[irq] = event; sc->sc_intr_counter[irq] = mips_intrcnt_create(event->ie_name); } else return error; } intr_event_add_handler(event, device_get_nameunit(child), filt, handler, arg, intr_priority(flags), flags, cookiep); mips_intrcnt_setname(sc->sc_intr_counter[irq], event->ie_fullname); ar724x_pci_unmask_irq((void*)irq); return (0); } static int ar724x_pci_teardown_intr(device_t dev, device_t child, struct resource *ires, void *cookie) { struct ar71xx_pci_softc *sc = device_get_softc(dev); int irq, result; irq = rman_get_start(ires); if (irq > AR71XX_PCI_IRQ_END) panic("%s: bad irq %d", __func__, irq); if (sc->sc_eventstab[irq] == NULL) panic("Trying to teardown unoccupied IRQ"); ar724x_pci_mask_irq((void*)irq); result = intr_event_remove_handler(cookie); if (!result) sc->sc_eventstab[irq] = NULL; return (result); } static int ar724x_pci_intr(void *arg) { struct ar71xx_pci_softc *sc = arg; struct intr_event *event; uint32_t reg, irq, mask; reg = ATH_READ_REG(AR724X_PCI_INTR_STATUS); mask = ATH_READ_REG(AR724X_PCI_INTR_MASK); /* * Handle only unmasked interrupts */ reg &= mask; if (reg & AR724X_PCI_INTR_DEV0) { irq = AR71XX_PCI_IRQ_START; event = sc->sc_eventstab[irq]; if (!event || TAILQ_EMPTY(&event->ie_handlers)) { printf("Stray IRQ %d\n", irq); return (FILTER_STRAY); } /* Flush pending memory transactions */ ar71xx_device_flush_ddr(AR71XX_CPU_DDR_FLUSH_PCIE); /* TODO: frame instead of NULL? */ intr_event_handle(event, NULL); mips_intrcnt_inc(sc->sc_intr_counter[irq]); } return (FILTER_HANDLED); } static int ar724x_pci_maxslots(device_t dev) { return (PCI_SLOTMAX); } static int ar724x_pci_route_interrupt(device_t pcib, device_t device, int pin) { return (pci_get_slot(device)); } static device_method_t ar724x_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ar724x_pci_probe), DEVMETHOD(device_attach, ar724x_pci_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_read_ivar, ar724x_pci_read_ivar), DEVMETHOD(bus_write_ivar, ar724x_pci_write_ivar), DEVMETHOD(bus_alloc_resource, ar724x_pci_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, ar724x_pci_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, ar724x_pci_setup_intr), DEVMETHOD(bus_teardown_intr, ar724x_pci_teardown_intr), /* pcib interface */ DEVMETHOD(pcib_maxslots, ar724x_pci_maxslots), DEVMETHOD(pcib_read_config, ar724x_pci_read_config), DEVMETHOD(pcib_write_config, ar724x_pci_write_config), DEVMETHOD(pcib_route_interrupt, ar724x_pci_route_interrupt), DEVMETHOD(pcib_request_feature, pcib_request_feature_allow), DEVMETHOD_END }; static driver_t ar724x_pci_driver = { "pcib", ar724x_pci_methods, sizeof(struct ar71xx_pci_softc), }; static devclass_t ar724x_pci_devclass; DRIVER_MODULE(ar724x_pci, nexus, ar724x_pci_driver, ar724x_pci_devclass, 0, 0); Index: head/sys/mips/atheros/ar724xreg.h =================================================================== --- head/sys/mips/atheros/ar724xreg.h (revision 326258) +++ head/sys/mips/atheros/ar724xreg.h (revision 326259) @@ -1,108 +1,110 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Adrian Chadd * 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$ */ #ifndef __AR72XX_REG_H__ #define __AR72XX_REG_H__ #define AR724X_PLL_REG_CPU_CONFIG AR71XX_PLL_CPU_BASE + 0x00 #define AR724X_PLL_REG_PCIE_CONFIG AR71XX_PLL_CPU_BASE + 0x18 #define AR724X_PLL_DIV_SHIFT 0 #define AR724X_PLL_DIV_MASK 0x3ff #define AR724X_PLL_REF_DIV_SHIFT 10 #define AR724X_PLL_REF_DIV_MASK 0xf #define AR724X_AHB_DIV_SHIFT 19 #define AR724X_AHB_DIV_MASK 0x1 #define AR724X_DDR_DIV_SHIFT 22 #define AR724X_DDR_DIV_MASK 0x3 #define AR724X_PLL_VAL_1000 0x00110000 #define AR724X_PLL_VAL_100 0x00001099 #define AR724X_PLL_VAL_10 0x00991099 #define AR724X_BASE_FREQ 5000000 #define AR724X_DDR_REG_FLUSH_GE0 (AR71XX_DDR_CONFIG + 0x7c) #define AR724X_DDR_REG_FLUSH_GE1 (AR71XX_DDR_CONFIG + 0x80) #define AR724X_DDR_REG_FLUSH_USB (AR71XX_DDR_CONFIG + 0x84) #define AR724X_DDR_REG_FLUSH_PCIE (AR71XX_DDR_CONFIG + 0x88) #define AR724X_RESET_REG_RESET_MODULE AR71XX_RST_BLOCK_BASE + 0x1c #define AR724X_RESET_USB_HOST (1 << 5) #define AR724X_RESET_USB_PHY (1 << 4) #define AR724X_RESET_MODULE_USB_OHCI_DLL (1 << 3) #define AR724X_RESET_GE1_MDIO (1 << 23) #define AR724X_RESET_GE0_MDIO (1 << 22) #define AR724X_RESET_PCIE_PHY_SERIAL (1 << 10) #define AR724X_RESET_PCIE_PHY (1 << 7) #define AR724X_RESET_PCIE (1 << 6) #define AR724X_RESET_USB_HOST (1 << 5) #define AR724X_RESET_USB_PHY (1 << 4) #define AR724X_RESET_USBSUS_OVERRIDE (1 << 3) /* XXX so USB requires different init code? -adrian */ #define AR7240_OHCI_BASE 0x1b000000 #define AR7240_OHCI_SIZE 0x01000000 #define AR724X_PCI_CRP_BASE (AR71XX_APB_BASE + 0x000C0000) #define AR724X_PCI_CRP_SIZE 0x100 #define AR724X_PCI_CFG_BASE 0x14000000 #define AR724X_PCI_CFG_SIZE 0x1000 #define AR724X_PCI_CTRL_BASE (AR71XX_APB_BASE + 0x000F0000) #define AR724X_PCI_CTRL_SIZE 0x100 /* PCI config registers - AR724X_PCI_CTRL_BASE */ #define AR724X_PCI_APP 0x180f0000 #define AR724X_PCI_APP_LTSSM_ENABLE (1 << 0) #define AR724X_PCI_RESET 0x180f0018 #define AR724X_PCI_RESET_LINK_UP (1 << 0) #define AR724X_PCI_INTR_STATUS 0x180f004c #define AR724X_PCI_INTR_MASK 0x180f0050 #define AR724X_PCI_INTR_DEV0 (1 << 14) #define AR724X_GPIO_FUNC_GE0_MII_CLK_EN (1 << 19) #define AR724X_GPIO_FUNC_SPI_EN (1 << 18) #define AR724X_GPIO_FUNC_SPI_CS_EN2 (1 << 14) #define AR724X_GPIO_FUNC_SPI_CS_EN1 (1 << 13) #define AR724X_GPIO_FUNC_CLK_OBS5_EN (1 << 12) #define AR724X_GPIO_FUNC_CLK_OBS4_EN (1 << 11) #define AR724X_GPIO_FUNC_CLK_OBS3_EN (1 << 10) #define AR724X_GPIO_FUNC_CLK_OBS2_EN (1 << 9) #define AR724X_GPIO_FUNC_CLK_OBS1_EN (1 << 8) #define AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN (1 << 7) #define AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN (1 << 6) #define AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN (1 << 5) #define AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN (1 << 4) #define AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN (1 << 3) #define AR724X_GPIO_FUNC_UART_RTS_CTS_EN (1 << 2) #define AR724X_GPIO_FUNC_UART_EN (1 << 1) #define AR724X_GPIO_FUNC_JTAG_DISABLE (1 << 0) #endif Index: head/sys/mips/atheros/ar91xx_chip.c =================================================================== --- head/sys/mips/atheros/ar91xx_chip.c (revision 326258) +++ head/sys/mips/atheros/ar91xx_chip.c (revision 326259) @@ -1,217 +1,219 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Adrian Chadd * 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 "opt_ddb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void ar91xx_chip_detect_mem_size(void) { } static void ar91xx_chip_detect_sys_frequency(void) { uint32_t pll; uint32_t freq; uint32_t div; u_ar71xx_mdio_freq = u_ar71xx_refclk = AR91XX_BASE_FREQ; pll = ATH_READ_REG(AR91XX_PLL_REG_CPU_CONFIG); div = ((pll >> AR91XX_PLL_DIV_SHIFT) & AR91XX_PLL_DIV_MASK); freq = div * AR91XX_BASE_FREQ; u_ar71xx_cpu_freq = freq; div = ((pll >> AR91XX_DDR_DIV_SHIFT) & AR91XX_DDR_DIV_MASK) + 1; u_ar71xx_ddr_freq = freq / div; div = (((pll >> AR91XX_AHB_DIV_SHIFT) & AR91XX_AHB_DIV_MASK) + 1) * 2; u_ar71xx_ahb_freq = u_ar71xx_cpu_freq / div; u_ar71xx_uart_freq = u_ar71xx_cpu_freq / div; u_ar71xx_wdt_freq = u_ar71xx_cpu_freq / div; } static void ar91xx_chip_device_stop(uint32_t mask) { uint32_t reg; reg = ATH_READ_REG(AR91XX_RESET_REG_RESET_MODULE); ATH_WRITE_REG(AR91XX_RESET_REG_RESET_MODULE, reg | mask); } static void ar91xx_chip_device_start(uint32_t mask) { uint32_t reg; reg = ATH_READ_REG(AR91XX_RESET_REG_RESET_MODULE); ATH_WRITE_REG(AR91XX_RESET_REG_RESET_MODULE, reg & ~mask); } static int ar91xx_chip_device_stopped(uint32_t mask) { uint32_t reg; reg = ATH_READ_REG(AR91XX_RESET_REG_RESET_MODULE); return ((reg & mask) == mask); } static void ar91xx_chip_set_pll_ge(int unit, int speed, uint32_t pll) { switch (unit) { case 0: ar71xx_write_pll(AR91XX_PLL_REG_ETH_CONFIG, AR91XX_PLL_REG_ETH0_INT_CLOCK, pll, AR91XX_ETH0_PLL_SHIFT); break; case 1: ar71xx_write_pll(AR91XX_PLL_REG_ETH_CONFIG, AR91XX_PLL_REG_ETH1_INT_CLOCK, pll, AR91XX_ETH1_PLL_SHIFT); break; default: printf("%s: invalid PLL set for arge unit: %d\n", __func__, unit); return; } } static void ar91xx_chip_ddr_flush(ar71xx_flush_ddr_id_t id) { switch (id) { case AR71XX_CPU_DDR_FLUSH_GE0: ar71xx_ddr_flush(AR91XX_DDR_REG_FLUSH_GE0); break; case AR71XX_CPU_DDR_FLUSH_GE1: ar71xx_ddr_flush(AR91XX_DDR_REG_FLUSH_GE1); break; case AR71XX_CPU_DDR_FLUSH_USB: ar71xx_ddr_flush(AR91XX_DDR_REG_FLUSH_USB); break; case AR71XX_CPU_DDR_FLUSH_WMAC: ar71xx_ddr_flush(AR91XX_DDR_REG_FLUSH_WMAC); break; default: printf("%s: invalid DDR flush id (%d)\n", __func__, id); break; } } static uint32_t ar91xx_chip_get_eth_pll(unsigned int mac, int speed) { uint32_t pll; switch(speed) { case 10: pll = AR91XX_PLL_VAL_10; break; case 100: pll = AR91XX_PLL_VAL_100; break; case 1000: pll = AR91XX_PLL_VAL_1000; break; default: printf("%s%d: invalid speed %d\n", __func__, mac, speed); pll = 0; } return (pll); } static void ar91xx_chip_init_usb_peripheral(void) { ar71xx_device_stop(AR91XX_RST_RESET_MODULE_USBSUS_OVERRIDE); DELAY(100); ar71xx_device_start(RST_RESET_USB_HOST); DELAY(100); ar71xx_device_start(RST_RESET_USB_PHY); DELAY(100); /* Wireless */ ar71xx_device_stop(AR91XX_RST_RESET_MODULE_AMBA2WMAC); DELAY(1000); ar71xx_device_start(AR91XX_RST_RESET_MODULE_AMBA2WMAC); DELAY(1000); } struct ar71xx_cpu_def ar91xx_chip_def = { &ar91xx_chip_detect_mem_size, &ar91xx_chip_detect_sys_frequency, &ar91xx_chip_device_stop, &ar91xx_chip_device_start, &ar91xx_chip_device_stopped, &ar91xx_chip_set_pll_ge, &ar71xx_chip_set_mii_speed, &ar71xx_chip_set_mii_if, &ar91xx_chip_get_eth_pll, &ar91xx_chip_ddr_flush, &ar91xx_chip_init_usb_peripheral, }; Index: head/sys/mips/atheros/ar91xx_chip.h =================================================================== --- head/sys/mips/atheros/ar91xx_chip.h (revision 326258) +++ head/sys/mips/atheros/ar91xx_chip.h (revision 326259) @@ -1,34 +1,36 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Adrian Chadd * 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$ */ #ifndef __AR91XX_CHIP_H__ #define __AR91XX_CHIP_H__ extern struct ar71xx_cpu_def ar91xx_chip_def; #endif Index: head/sys/mips/atheros/ar91xxreg.h =================================================================== --- head/sys/mips/atheros/ar91xxreg.h (revision 326258) +++ head/sys/mips/atheros/ar91xxreg.h (revision 326259) @@ -1,84 +1,86 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Adrian Chadd * 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$ */ #ifndef __AR91XX_REG_H__ #define __AR91XX_REG_H__ #define AR91XX_BASE_FREQ 5000000 /* reset block */ #define AR91XX_RESET_REG_RESET_MODULE AR71XX_RST_BLOCK_BASE + 0x1c #define AR91XX_RST_RESET_MODULE_USBSUS_OVERRIDE (1 << 10) #define AR91XX_RST_RESET_MODULE_AMBA2WMAC (1 << 22) /* PLL block */ #define AR91XX_PLL_REG_CPU_CONFIG AR71XX_PLL_CPU_BASE + 0x00 #define AR91XX_PLL_REG_ETH_CONFIG AR71XX_PLL_CPU_BASE + 0x04 #define AR91XX_PLL_REG_ETH0_INT_CLOCK AR71XX_PLL_CPU_BASE + 0x14 #define AR91XX_PLL_REG_ETH1_INT_CLOCK AR71XX_PLL_CPU_BASE + 0x18 #define AR91XX_PLL_DIV_SHIFT 0 #define AR91XX_PLL_DIV_MASK 0x3ff #define AR91XX_DDR_DIV_SHIFT 22 #define AR91XX_DDR_DIV_MASK 0x3 #define AR91XX_AHB_DIV_SHIFT 19 #define AR91XX_AHB_DIV_MASK 0x1 #define AR91XX_ETH0_PLL_SHIFT 20 #define AR91XX_ETH1_PLL_SHIFT 22 #define AR91XX_PLL_VAL_1000 0x1a000000 #define AR91XX_PLL_VAL_100 0x13000a44 #define AR91XX_PLL_VAL_10 0x00441099 /* DDR block */ #define AR91XX_DDR_CTRLBASE (AR71XX_APB_BASE + 0) #define AR91XX_DDR_CTRL_SIZE 0x10000 #define AR91XX_DDR_REG_FLUSH_GE0 AR91XX_DDR_CTRLBASE + 0x7c #define AR91XX_DDR_REG_FLUSH_GE1 AR91XX_DDR_CTRLBASE + 0x80 #define AR91XX_DDR_REG_FLUSH_USB AR91XX_DDR_CTRLBASE + 0x84 #define AR91XX_DDR_REG_FLUSH_WMAC AR91XX_DDR_CTRLBASE + 0x88 /* WMAC stuff */ #define AR91XX_WMAC_BASE (AR71XX_APB_BASE + 0x000C0000) #define AR91XX_WMAC_SIZE 0x30000 /* GPIO stuff */ #define AR91XX_GPIO_FUNC_WMAC_LED_EN (1 << 22) #define AR91XX_GPIO_FUNC_EXP_PORT_CS_EN (1 << 21) #define AR91XX_GPIO_FUNC_I2S_REFCLKEN (1 << 20) #define AR91XX_GPIO_FUNC_I2S_MCKEN (1 << 19) #define AR91XX_GPIO_FUNC_I2S1_EN (1 << 18) #define AR91XX_GPIO_FUNC_I2S0_EN (1 << 17) #define AR91XX_GPIO_FUNC_SLIC_EN (1 << 16) #define AR91XX_GPIO_FUNC_UART_RTSCTS_EN (1 << 9) #define AR91XX_GPIO_FUNC_UART_EN (1 << 8) #define AR91XX_GPIO_FUNC_USB_CLK_EN (1 << 4) #endif Index: head/sys/mips/atheros/ar933x_chip.c =================================================================== --- head/sys/mips/atheros/ar933x_chip.c (revision 326258) +++ head/sys/mips/atheros/ar933x_chip.c (revision 326259) @@ -1,356 +1,358 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2012 Adrian Chadd * 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 "opt_ddb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void ar933x_chip_detect_mem_size(void) { } static void ar933x_chip_detect_sys_frequency(void) { uint32_t clock_ctrl; uint32_t cpu_config; uint32_t freq; uint32_t t; t = ATH_READ_REG(AR933X_RESET_REG_BOOTSTRAP); if (t & AR933X_BOOTSTRAP_REF_CLK_40) u_ar71xx_refclk = (40 * 1000 * 1000); else u_ar71xx_refclk = (25 * 1000 * 1000); clock_ctrl = ATH_READ_REG(AR933X_PLL_CLOCK_CTRL_REG); if (clock_ctrl & AR933X_PLL_CLOCK_CTRL_BYPASS) { u_ar71xx_cpu_freq = u_ar71xx_refclk; u_ar71xx_ahb_freq = u_ar71xx_refclk; u_ar71xx_ddr_freq = u_ar71xx_refclk; } else { cpu_config = ATH_READ_REG(AR933X_PLL_CPU_CONFIG_REG); t = (cpu_config >> AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT) & AR933X_PLL_CPU_CONFIG_REFDIV_MASK; freq = u_ar71xx_refclk / t; t = (cpu_config >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT) & AR933X_PLL_CPU_CONFIG_NINT_MASK; freq *= t; t = (cpu_config >> AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT) & AR933X_PLL_CPU_CONFIG_OUTDIV_MASK; if (t == 0) t = 1; freq >>= t; t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT) & AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK) + 1; u_ar71xx_cpu_freq = freq / t; t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT) & AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK) + 1; u_ar71xx_ddr_freq = freq / t; t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT) & AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK) + 1; u_ar71xx_ahb_freq = freq / t; } /* * On the AR933x, the UART frequency is the reference clock, * not the AHB bus clock. */ u_ar71xx_uart_freq = u_ar71xx_refclk; /* * XXX TODO: check whether the mdio frequency is always the * refclock frequency, or whether it's variable like on the * AR934x. */ u_ar71xx_mdio_freq = u_ar71xx_refclk; /* * XXX check what the watchdog frequency should be? */ u_ar71xx_wdt_freq = u_ar71xx_ahb_freq; } static void ar933x_chip_device_stop(uint32_t mask) { uint32_t reg; reg = ATH_READ_REG(AR933X_RESET_REG_RESET_MODULE); ATH_WRITE_REG(AR933X_RESET_REG_RESET_MODULE, reg | mask); } static void ar933x_chip_device_start(uint32_t mask) { uint32_t reg; reg = ATH_READ_REG(AR933X_RESET_REG_RESET_MODULE); ATH_WRITE_REG(AR933X_RESET_REG_RESET_MODULE, reg & ~mask); } static int ar933x_chip_device_stopped(uint32_t mask) { uint32_t reg; reg = ATH_READ_REG(AR933X_RESET_REG_RESET_MODULE); return ((reg & mask) == mask); } static void ar933x_chip_set_mii_speed(uint32_t unit, uint32_t speed) { /* XXX TODO */ return; } /* * XXX TODO !! */ static void ar933x_chip_set_pll_ge(int unit, int speed, uint32_t pll) { switch (unit) { case 0: /* XXX TODO */ break; case 1: /* XXX TODO */ break; default: printf("%s: invalid PLL set for arge unit: %d\n", __func__, unit); return; } } static void ar933x_chip_ddr_flush(ar71xx_flush_ddr_id_t id) { switch (id) { case AR71XX_CPU_DDR_FLUSH_GE0: ar71xx_ddr_flush(AR933X_DDR_REG_FLUSH_GE0); break; case AR71XX_CPU_DDR_FLUSH_GE1: ar71xx_ddr_flush(AR933X_DDR_REG_FLUSH_GE1); break; case AR71XX_CPU_DDR_FLUSH_USB: ar71xx_ddr_flush(AR933X_DDR_REG_FLUSH_USB); break; case AR71XX_CPU_DDR_FLUSH_WMAC: ar71xx_ddr_flush(AR933X_DDR_REG_FLUSH_WMAC); break; default: printf("%s: invalid DDR flush id (%d)\n", __func__, id); break; } } static uint32_t ar933x_chip_get_eth_pll(unsigned int mac, int speed) { uint32_t pll; switch (speed) { case 10: pll = AR933X_PLL_VAL_10; break; case 100: pll = AR933X_PLL_VAL_100; break; case 1000: pll = AR933X_PLL_VAL_1000; break; default: printf("%s%d: invalid speed %d\n", __func__, mac, speed); pll = 0; } return (pll); } static void ar933x_chip_init_usb_peripheral(void) { ar71xx_device_stop(AR933X_RESET_USBSUS_OVERRIDE); DELAY(100); ar71xx_device_start(AR933X_RESET_USB_HOST); DELAY(100); ar71xx_device_start(AR933X_RESET_USB_PHY); DELAY(100); } static void ar933x_configure_gmac(uint32_t gmac_cfg) { uint32_t reg; reg = ATH_READ_REG(AR933X_GMAC_REG_ETH_CFG); /* * The relevant bits here include: * * + AR933X_ETH_CFG_SW_PHY_SWAP * + AR933X_ETH_CFG_SW_PHY_ADDR_SWAP * * There are other things; look at what openwrt exposes so * it can be correctly exposed. * * TODO: what about ethernet switch support? How's that work? */ if (bootverbose) printf("%s: GMAC config was 0x%08x\n", __func__, reg); reg &= ~(AR933X_ETH_CFG_SW_PHY_SWAP | AR933X_ETH_CFG_SW_PHY_ADDR_SWAP); reg |= gmac_cfg; if (bootverbose) printf("%s: GMAC setting is 0x%08x; register is now 0x%08x\n", __func__, gmac_cfg, reg); ATH_WRITE_REG(AR933X_GMAC_REG_ETH_CFG, reg); } static void ar933x_chip_init_gmac(void) { int val; uint32_t gmac_cfg = 0; /* * These two bits need a bit better explanation. * * The default configuration in the hardware is to map both * ports to the internal switch. * * Here, GE0 == arge0, GE1 == arge1. * * The internal switch has: * + 5 MAC ports, MAC0->MAC4. * + 5 PHY ports, PHY0->PHY4, * + MAC0 connects to GE1; * + GE0 connects to PHY4; * + The other mappings are MAC1->PHY0, MAC2->PHY1 .. MAC4->PHY3. * * The GE1 port is linked in via 1000MBit/full, supplying what is * normally the 'WAN' switch ports. * * The switch is connected the MDIO bus on GE1. It looks like * a normal AR7240 on-board switch. * * The GE0 port is connected via MII to PHY4, and can operate in * 10/100mbit, full/half duplex. Ie, you can speak to PHY4 on * the MDIO bus and everything will simply 'work'. * * So far so good. This looks just like an AR7240 SoC. * * However, some configurations will just expose one or two * physical ports. In this case, some configuration bits can * be set to tweak this. * * + CFG_SW_PHY_ADDR_SWAP swaps PHY port 0 with PHY port 4. * Ie, GE0's PHY shows up as PHY 0. So if there's only * one physical port, there's no need to involve the * switch framework - it can just show up as a default, * normal single PHY. * * + CFG_SW_PHY_SWAP swaps the internal switch connection * between PHY0 and PHY4. Ie, PHY4 connects to MAc1, * PHY0 connects to GE0. */ if ((resource_int_value("ar933x_gmac", 0, "override_phy", &val) == 0) && (val == 0)) return; if ((resource_int_value("ar933x_gmac", 0, "swap_phy", &val) == 0) && (val == 1)) gmac_cfg |= AR933X_ETH_CFG_SW_PHY_SWAP; if ((resource_int_value("ar933x_gmac", 0, "swap_phy_addr", &val) == 0) && (val == 1)) gmac_cfg |= AR933X_ETH_CFG_SW_PHY_ADDR_SWAP; ar933x_configure_gmac(gmac_cfg); } struct ar71xx_cpu_def ar933x_chip_def = { &ar933x_chip_detect_mem_size, &ar933x_chip_detect_sys_frequency, &ar933x_chip_device_stop, &ar933x_chip_device_start, &ar933x_chip_device_stopped, &ar933x_chip_set_pll_ge, &ar933x_chip_set_mii_speed, &ar71xx_chip_set_mii_if, &ar933x_chip_get_eth_pll, &ar933x_chip_ddr_flush, &ar933x_chip_init_usb_peripheral, NULL, NULL, &ar933x_chip_init_gmac, }; Index: head/sys/mips/atheros/ar933x_chip.h =================================================================== --- head/sys/mips/atheros/ar933x_chip.h (revision 326258) +++ head/sys/mips/atheros/ar933x_chip.h (revision 326259) @@ -1,34 +1,36 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2012 Adrian Chadd * 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$ */ #ifndef __AR933X_CHIP_H__ #define __AR933X_CHIP_H__ extern struct ar71xx_cpu_def ar933x_chip_def; #endif Index: head/sys/mips/atheros/ar933x_uart.h =================================================================== --- head/sys/mips/atheros/ar933x_uart.h (revision 326258) +++ head/sys/mips/atheros/ar933x_uart.h (revision 326259) @@ -1,91 +1,93 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2012 Adrian Chadd * 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$ */ /* * Atheros AR933x SoC UART registers */ #ifndef __AR933X_UART_H__ #define __AR933X_UART_H__ #define AR933X_UART_REGS_SIZE 20 #define AR933X_UART_FIFO_SIZE 16 #define AR933X_UART_DATA_REG 0x00 #define AR933X_UART_CS_REG 0x04 #define AR933X_UART_CLOCK_REG 0x08 #define AR933X_UART_INT_REG 0x0c #define AR933X_UART_INT_EN_REG 0x10 #define AR933X_UART_DATA_TX_RX_MASK 0xff #define AR933X_UART_DATA_RX_CSR (1 << 8) #define AR933X_UART_DATA_TX_CSR (1 << 9) #define AR933X_UART_CS_PARITY_S 0 #define AR933X_UART_CS_PARITY_M 0x3 #define AR933X_UART_CS_PARITY_NONE 0 #define AR933X_UART_CS_PARITY_ODD 1 #define AR933X_UART_CS_PARITY_EVEN 2 #define AR933X_UART_CS_IF_MODE_S 2 #define AR933X_UART_CS_IF_MODE_M 0x3 #define AR933X_UART_CS_IF_MODE_NONE 0 #define AR933X_UART_CS_IF_MODE_DTE 1 #define AR933X_UART_CS_IF_MODE_DCE 2 #define AR933X_UART_CS_FLOW_CTRL_S 4 #define AR933X_UART_CS_FLOW_CTRL_M 0x3 #define AR933X_UART_CS_DMA_EN (1 << 6) #define AR933X_UART_CS_TX_READY_ORIDE (1 << 7) #define AR933X_UART_CS_RX_READY_ORIDE (1 << 8) #define AR933X_UART_CS_TX_READY (1 << 9) #define AR933X_UART_CS_RX_BREAK (1 << 10) #define AR933X_UART_CS_TX_BREAK (1 << 11) #define AR933X_UART_CS_HOST_INT (1 << 12) #define AR933X_UART_CS_HOST_INT_EN (1 << 13) #define AR933X_UART_CS_TX_BUSY (1 << 14) #define AR933X_UART_CS_RX_BUSY (1 << 15) #define AR933X_UART_CLOCK_SCALE_M 0xff #define AR933X_UART_CLOCK_SCALE_S 16 #define AR933X_UART_CLOCK_STEP_M 0xffff #define AR933X_UART_CLOCK_STEP_S 0 #define AR933X_UART_MAX_SCALE 0xff #define AR933X_UART_MAX_STEP 0xffff #define AR933X_UART_INT_RX_VALID (1 << 0) #define AR933X_UART_INT_TX_READY (1 << 1) #define AR933X_UART_INT_RX_FRAMING_ERR (1 << 2) #define AR933X_UART_INT_RX_OFLOW_ERR (1 << 3) #define AR933X_UART_INT_TX_OFLOW_ERR (1 << 4) #define AR933X_UART_INT_RX_PARITY_ERR (1 << 5) #define AR933X_UART_INT_RX_BREAK_ON (1 << 6) #define AR933X_UART_INT_RX_BREAK_OFF (1 << 7) #define AR933X_UART_INT_RX_FULL (1 << 8) #define AR933X_UART_INT_TX_EMPTY (1 << 9) #define AR933X_UART_INT_ALLINTS 0x3ff #endif /* __AR933X_UART_H__ */ Index: head/sys/mips/atheros/ar933xreg.h =================================================================== --- head/sys/mips/atheros/ar933xreg.h (revision 326258) +++ head/sys/mips/atheros/ar933xreg.h (revision 326259) @@ -1,100 +1,102 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2012 Adrian Chadd * 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$ */ #ifndef __AR93XX_REG_H__ #define __AR93XX_REG_H__ #define REV_ID_MAJOR_AR9330 0x0110 #define REV_ID_MAJOR_AR9331 0x1110 #define AR933X_REV_ID_REVISION_MASK 0x3 #define AR933X_GPIO_COUNT 30 #define AR933X_UART_BASE (AR71XX_APB_BASE + 0x00020000) #define AR933X_UART_SIZE 0x14 #define AR933X_GMAC_BASE (AR71XX_APB_BASE + 0x00070000) #define AR933X_GMAC_SIZE 0x04 #define AR933X_GMAC_REG_ETH_CFG (AR933X_GMAC_BASE + 0x00) #define AR933X_ETH_CFG_RGMII_GE0 (1 << 0) #define AR933X_ETH_CFG_MII_GE0 (1 << 1) #define AR933X_ETH_CFG_GMII_GE0 (1 << 2) #define AR933X_ETH_CFG_MII_GE0_MASTER (1 << 3) #define AR933X_ETH_CFG_MII_GE0_SLAVE (1 << 4) #define AR933X_ETH_CFG_MII_GE0_ERR_EN (1 << 5) #define AR933X_ETH_CFG_SW_PHY_SWAP (1 << 7) #define AR933X_ETH_CFG_SW_PHY_ADDR_SWAP (1 << 8) #define AR933X_ETH_CFG_RMII_GE0 (1 << 9) #define AR933X_ETH_CFG_RMII_GE0_SPD_10 0 #define AR933X_ETH_CFG_RMII_GE0_SPD_100 (1 << 10) #define AR933X_WMAC_BASE (AR71XX_APB_BASE + 0x00100000) #define AR933X_WMAC_SIZE 0x20000 #define AR933X_EHCI_BASE 0x1b000000 #define AR933X_EHCI_SIZE 0x1000 #define AR933X_DDR_REG_FLUSH_GE0 (AR71XX_APB_BASE + 0x7c) #define AR933X_DDR_REG_FLUSH_GE1 (AR71XX_APB_BASE + 0x80) #define AR933X_DDR_REG_FLUSH_USB (AR71XX_APB_BASE + 0x84) #define AR933X_DDR_REG_FLUSH_WMAC (AR71XX_APB_BASE + 0x88) #define AR933X_PLL_CPU_CONFIG_REG (AR71XX_PLL_CPU_BASE + 0x00) #define AR933X_PLL_CLOCK_CTRL_REG (AR71XX_PLL_CPU_BASE + 0x08) #define AR933X_PLL_CPU_CONFIG_NINT_SHIFT 10 #define AR933X_PLL_CPU_CONFIG_NINT_MASK 0x3f #define AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT 16 #define AR933X_PLL_CPU_CONFIG_REFDIV_MASK 0x1f #define AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT 23 #define AR933X_PLL_CPU_CONFIG_OUTDIV_MASK 0x7 #define AR933X_PLL_CLOCK_CTRL_BYPASS (1 << 2) #define AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT 5 #define AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK 0x3 #define AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT 10 #define AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK 0x3 #define AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT 15 #define AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK 0x7 #define AR933X_RESET_REG_RESET_MODULE (AR71XX_RST_BLOCK_BASE + 0x1c) #define AR933X_RESET_REG_BOOTSTRAP (AR71XX_RST_BLOCK_BASE + 0xac) #define AR933X_RESET_WMAC (1 << 11) #define AR933X_RESET_USB_HOST (1 << 5) #define AR933X_RESET_USB_PHY (1 << 4) #define AR933X_RESET_USBSUS_OVERRIDE (1 << 3) #define AR933X_BOOTSTRAP_REF_CLK_40 (1 << 0) #define AR933X_PLL_VAL_1000 0x00110000 #define AR933X_PLL_VAL_100 0x00001099 #define AR933X_PLL_VAL_10 0x00991099 #endif /* __AR93XX_REG_H__ */ Index: head/sys/mips/atheros/ar934x_chip.c =================================================================== --- head/sys/mips/atheros/ar934x_chip.c (revision 326258) +++ head/sys/mips/atheros/ar934x_chip.c (revision 326259) @@ -1,474 +1,476 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2013 Adrian Chadd * 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 "opt_ddb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static void ar934x_chip_detect_mem_size(void) { } static uint32_t ar934x_get_pll_freq(uint32_t ref, uint32_t ref_div, uint32_t nint, uint32_t nfrac, uint32_t frac, uint32_t out_div) { uint64_t t; uint32_t ret; t = u_ar71xx_refclk; t *= nint; t = t / ref_div; ret = t; t = u_ar71xx_refclk; t *= nfrac; t = t / (ref_div * frac); ret += t; ret /= (1 << out_div); return (ret); } static void ar934x_chip_detect_sys_frequency(void) { uint32_t pll, out_div, ref_div, nint, nfrac, frac, clk_ctrl, postdiv; uint32_t cpu_pll, ddr_pll; uint32_t bootstrap; uint32_t reg; bootstrap = ATH_READ_REG(AR934X_RESET_REG_BOOTSTRAP); if (bootstrap & AR934X_BOOTSTRAP_REF_CLK_40) u_ar71xx_refclk = 40 * 1000 * 1000; else u_ar71xx_refclk = 25 * 1000 * 1000; pll = ATH_READ_REG(AR934X_SRIF_CPU_DPLL2_REG); if (pll & AR934X_SRIF_DPLL2_LOCAL_PLL) { out_div = (pll >> AR934X_SRIF_DPLL2_OUTDIV_SHIFT) & AR934X_SRIF_DPLL2_OUTDIV_MASK; pll = ATH_READ_REG(AR934X_SRIF_CPU_DPLL1_REG); nint = (pll >> AR934X_SRIF_DPLL1_NINT_SHIFT) & AR934X_SRIF_DPLL1_NINT_MASK; nfrac = pll & AR934X_SRIF_DPLL1_NFRAC_MASK; ref_div = (pll >> AR934X_SRIF_DPLL1_REFDIV_SHIFT) & AR934X_SRIF_DPLL1_REFDIV_MASK; frac = 1 << 18; } else { pll = ATH_READ_REG(AR934X_PLL_CPU_CONFIG_REG); out_div = (pll >> AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT) & AR934X_PLL_CPU_CONFIG_OUTDIV_MASK; ref_div = (pll >> AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT) & AR934X_PLL_CPU_CONFIG_REFDIV_MASK; nint = (pll >> AR934X_PLL_CPU_CONFIG_NINT_SHIFT) & AR934X_PLL_CPU_CONFIG_NINT_MASK; nfrac = (pll >> AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT) & AR934X_PLL_CPU_CONFIG_NFRAC_MASK; frac = 1 << 6; } cpu_pll = ar934x_get_pll_freq(u_ar71xx_refclk, ref_div, nint, nfrac, frac, out_div); pll = ATH_READ_REG(AR934X_SRIF_DDR_DPLL2_REG); if (pll & AR934X_SRIF_DPLL2_LOCAL_PLL) { out_div = (pll >> AR934X_SRIF_DPLL2_OUTDIV_SHIFT) & AR934X_SRIF_DPLL2_OUTDIV_MASK; pll = ATH_READ_REG(AR934X_SRIF_DDR_DPLL1_REG); nint = (pll >> AR934X_SRIF_DPLL1_NINT_SHIFT) & AR934X_SRIF_DPLL1_NINT_MASK; nfrac = pll & AR934X_SRIF_DPLL1_NFRAC_MASK; ref_div = (pll >> AR934X_SRIF_DPLL1_REFDIV_SHIFT) & AR934X_SRIF_DPLL1_REFDIV_MASK; frac = 1 << 18; } else { pll = ATH_READ_REG(AR934X_PLL_DDR_CONFIG_REG); out_div = (pll >> AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT) & AR934X_PLL_DDR_CONFIG_OUTDIV_MASK; ref_div = (pll >> AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT) & AR934X_PLL_DDR_CONFIG_REFDIV_MASK; nint = (pll >> AR934X_PLL_DDR_CONFIG_NINT_SHIFT) & AR934X_PLL_DDR_CONFIG_NINT_MASK; nfrac = (pll >> AR934X_PLL_DDR_CONFIG_NFRAC_SHIFT) & AR934X_PLL_DDR_CONFIG_NFRAC_MASK; frac = 1 << 10; } ddr_pll = ar934x_get_pll_freq(u_ar71xx_refclk, ref_div, nint, nfrac, frac, out_div); clk_ctrl = ATH_READ_REG(AR934X_PLL_CPU_DDR_CLK_CTRL_REG); postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_SHIFT) & AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_MASK; if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_PLL_BYPASS) u_ar71xx_cpu_freq = u_ar71xx_refclk; else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_CPUCLK_FROM_CPUPLL) u_ar71xx_cpu_freq = cpu_pll / (postdiv + 1); else u_ar71xx_cpu_freq = ddr_pll / (postdiv + 1); postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_SHIFT) & AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_MASK; if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_PLL_BYPASS) u_ar71xx_ddr_freq = u_ar71xx_refclk; else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_DDRCLK_FROM_DDRPLL) u_ar71xx_ddr_freq = ddr_pll / (postdiv + 1); else u_ar71xx_ddr_freq = cpu_pll / (postdiv + 1); postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_SHIFT) & AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_MASK; if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_PLL_BYPASS) u_ar71xx_ahb_freq = u_ar71xx_refclk; else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL) u_ar71xx_ahb_freq = ddr_pll / (postdiv + 1); else u_ar71xx_ahb_freq = cpu_pll / (postdiv + 1); u_ar71xx_wdt_freq = u_ar71xx_refclk; u_ar71xx_uart_freq = u_ar71xx_refclk; /* * Next, fetch reference clock speed for MDIO bus. */ reg = ATH_READ_REG(AR934X_PLL_SWITCH_CLOCK_CONTROL_REG); if (reg & AR934X_PLL_SWITCH_CLOCK_CONTROL_MDIO_CLK_SEL) { printf("%s: mdio=100MHz\n", __func__); u_ar71xx_mdio_freq = (100 * 1000 * 1000); } else { printf("%s: mdio=%d Hz\n", __func__, u_ar71xx_refclk); u_ar71xx_mdio_freq = u_ar71xx_refclk; } } static void ar934x_chip_device_stop(uint32_t mask) { uint32_t reg; reg = ATH_READ_REG(AR934X_RESET_REG_RESET_MODULE); ATH_WRITE_REG(AR934X_RESET_REG_RESET_MODULE, reg | mask); } static void ar934x_chip_device_start(uint32_t mask) { uint32_t reg; reg = ATH_READ_REG(AR934X_RESET_REG_RESET_MODULE); ATH_WRITE_REG(AR934X_RESET_REG_RESET_MODULE, reg & ~mask); } static int ar934x_chip_device_stopped(uint32_t mask) { uint32_t reg; reg = ATH_READ_REG(AR934X_RESET_REG_RESET_MODULE); return ((reg & mask) == mask); } static void ar934x_chip_set_mii_speed(uint32_t unit, uint32_t speed) { /* XXX TODO */ return; } /* * XXX TODO !! */ static void ar934x_chip_set_pll_ge(int unit, int speed, uint32_t pll) { switch (unit) { case 0: ATH_WRITE_REG(AR934X_PLL_ETH_XMII_CONTROL_REG, pll); break; case 1: /* XXX nothing */ break; default: printf("%s: invalid PLL set for arge unit: %d\n", __func__, unit); return; } } static void ar934x_chip_ddr_flush(ar71xx_flush_ddr_id_t id) { switch (id) { case AR71XX_CPU_DDR_FLUSH_GE0: ar71xx_ddr_flush(AR934X_DDR_REG_FLUSH_GE0); break; case AR71XX_CPU_DDR_FLUSH_GE1: ar71xx_ddr_flush(AR934X_DDR_REG_FLUSH_GE1); break; case AR71XX_CPU_DDR_FLUSH_USB: ar71xx_ddr_flush(AR934X_DDR_REG_FLUSH_USB); break; case AR71XX_CPU_DDR_FLUSH_PCIE: ar71xx_ddr_flush(AR934X_DDR_REG_FLUSH_PCIE); break; case AR71XX_CPU_DDR_FLUSH_WMAC: ar71xx_ddr_flush(AR934X_DDR_REG_FLUSH_WMAC); break; default: printf("%s: invalid DDR flush id (%d)\n", __func__, id); break; } } static uint32_t ar934x_chip_get_eth_pll(unsigned int mac, int speed) { uint32_t pll; switch (speed) { case 10: pll = AR934X_PLL_VAL_10; break; case 100: pll = AR934X_PLL_VAL_100; break; case 1000: pll = AR934X_PLL_VAL_1000; break; default: printf("%s%d: invalid speed %d\n", __func__, mac, speed); pll = 0; } return (pll); } static void ar934x_chip_reset_ethernet_switch(void) { ar71xx_device_stop(AR934X_RESET_ETH_SWITCH); DELAY(100); ar71xx_device_start(AR934X_RESET_ETH_SWITCH); DELAY(100); ar71xx_device_stop(AR934X_RESET_ETH_SWITCH_ANALOG); DELAY(100); ar71xx_device_start(AR934X_RESET_ETH_SWITCH_ANALOG); DELAY(100); } static void ar934x_configure_gmac(uint32_t gmac_cfg) { uint32_t reg; reg = ATH_READ_REG(AR934X_GMAC_REG_ETH_CFG); printf("%s: ETH_CFG=0x%08x\n", __func__, reg); reg &= ~(AR934X_ETH_CFG_RGMII_GMAC0 | AR934X_ETH_CFG_MII_GMAC0 | AR934X_ETH_CFG_MII_GMAC0 | AR934X_ETH_CFG_SW_ONLY_MODE | AR934X_ETH_CFG_SW_PHY_SWAP); reg |= gmac_cfg; ATH_WRITE_REG(AR934X_GMAC_REG_ETH_CFG, reg); } static void ar934x_chip_init_usb_peripheral(void) { uint32_t reg; reg = ATH_READ_REG(AR934X_RESET_REG_BOOTSTRAP); if (reg & AR934X_BOOTSTRAP_USB_MODE_DEVICE) return; ar71xx_device_stop(AR934X_RESET_USBSUS_OVERRIDE); DELAY(100); ar71xx_device_start(AR934X_RESET_USB_PHY); DELAY(100); ar71xx_device_start(AR934X_RESET_USB_PHY_ANALOG); DELAY(100); ar71xx_device_start(AR934X_RESET_USB_HOST); DELAY(100); } static void ar934x_chip_set_mii_if(uint32_t unit, uint32_t mii_mode) { /* * XXX ! * * Nothing to see here; although gmac0 can have its * MII configuration changed, the register values * are slightly different. */ } /* * XXX TODO: fetch default MII divider configuration */ static void ar934x_chip_reset_wmac(void) { /* XXX TODO */ } static void ar934x_chip_init_gmac(void) { long gmac_cfg; if (resource_long_value("ar934x_gmac", 0, "gmac_cfg", &gmac_cfg) == 0) { printf("%s: gmac_cfg=0x%08lx\n", __func__, (long) gmac_cfg); ar934x_configure_gmac((uint32_t) gmac_cfg); } } /* * Reset the NAND Flash Controller. * * + active=1 means "make it active". * + active=0 means "make it inactive". */ static void ar934x_chip_reset_nfc(int active) { if (active) { ar71xx_device_start(AR934X_RESET_NANDF); DELAY(100); ar71xx_device_start(AR934X_RESET_ETH_SWITCH_ANALOG); DELAY(250); } else { ar71xx_device_stop(AR934X_RESET_ETH_SWITCH_ANALOG); DELAY(250); ar71xx_device_stop(AR934X_RESET_NANDF); DELAY(100); } } /* * Configure the GPIO output mux setup. * * The AR934x introduced an output mux which allowed * certain functions to be configured on any pin. * Specifically, the switch PHY link LEDs and * WMAC external RX LNA switches are not limited to * a specific GPIO pin. */ static void ar934x_chip_gpio_output_configure(int gpio, uint8_t func) { uint32_t reg, s; uint32_t t; if (gpio > AR934X_GPIO_COUNT) return; reg = AR934X_GPIO_REG_OUT_FUNC0 + rounddown(gpio, 4); s = 8 * (gpio % 4); /* read-modify-write */ t = ATH_READ_REG(AR71XX_GPIO_BASE + reg); t &= ~(0xff << s); t |= func << s; ATH_WRITE_REG(AR71XX_GPIO_BASE + reg, t); /* flush write */ ATH_READ_REG(AR71XX_GPIO_BASE + reg); } struct ar71xx_cpu_def ar934x_chip_def = { &ar934x_chip_detect_mem_size, &ar934x_chip_detect_sys_frequency, &ar934x_chip_device_stop, &ar934x_chip_device_start, &ar934x_chip_device_stopped, &ar934x_chip_set_pll_ge, &ar934x_chip_set_mii_speed, &ar934x_chip_set_mii_if, &ar934x_chip_get_eth_pll, &ar934x_chip_ddr_flush, &ar934x_chip_init_usb_peripheral, &ar934x_chip_reset_ethernet_switch, &ar934x_chip_reset_wmac, &ar934x_chip_init_gmac, &ar934x_chip_reset_nfc, &ar934x_chip_gpio_output_configure, }; Index: head/sys/mips/atheros/ar934x_chip.h =================================================================== --- head/sys/mips/atheros/ar934x_chip.h (revision 326258) +++ head/sys/mips/atheros/ar934x_chip.h (revision 326259) @@ -1,34 +1,36 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2013 Adrian Chadd * 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$ */ #ifndef __AR934X_CHIP_H__ #define __AR934X_CHIP_H__ extern struct ar71xx_cpu_def ar934x_chip_def; #endif Index: head/sys/mips/atheros/ar934xreg.h =================================================================== --- head/sys/mips/atheros/ar934xreg.h (revision 326258) +++ head/sys/mips/atheros/ar934xreg.h (revision 326259) @@ -1,239 +1,241 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2013 Adrian Chadd * 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$ */ #ifndef __AR934X_REG_H__ #define __AR934X_REG_H__ #define AR934X_GMAC_BASE (AR71XX_APB_BASE + 0x00070000) #define AR934X_GMAC_SIZE 0x14 #define AR934X_WMAC_BASE (AR71XX_APB_BASE + 0x00100000) #define AR934X_WMAC_SIZE 0x20000 #define AR934X_EHCI_BASE 0x1b000000 #define AR934X_EHCI_SIZE 0x200 #define AR934X_SRIF_BASE (AR71XX_APB_BASE + 0x00116000) #define AR934X_SRIF_SIZE 0x1000 /* AR934x GMAC configuration */ #define AR934X_GMAC_REG_ETH_CFG (AR934X_GMAC_BASE + 0x00) #define AR934X_ETH_CFG_RGMII_GMAC0 (1 << 0) #define AR934X_ETH_CFG_MII_GMAC0 (1 << 1) #define AR934X_ETH_CFG_GMII_GMAC0 (1 << 2) #define AR934X_ETH_CFG_MII_GMAC0_MASTER (1 << 3) #define AR934X_ETH_CFG_MII_GMAC0_SLAVE (1 << 4) #define AR934X_ETH_CFG_MII_GMAC0_ERR_EN (1 << 5) #define AR934X_ETH_CFG_SW_ONLY_MODE (1 << 6) #define AR934X_ETH_CFG_SW_PHY_SWAP (1 << 7) #define AR934X_ETH_CFG_SW_APB_ACCESS (1 << 9) #define AR934X_ETH_CFG_RMII_GMAC0 (1 << 10) #define AR933X_ETH_CFG_MII_CNTL_SPEED (1 << 11) #define AR934X_ETH_CFG_RMII_GMAC0_MASTER (1 << 12) #define AR934X_ETH_CFG_SW_ACC_MSB_FIRST (1 << 13) #define AR934X_DDR_REG_FLUSH_GE0 (AR71XX_APB_BASE + 0x9c) #define AR934X_DDR_REG_FLUSH_GE1 (AR71XX_APB_BASE + 0xa0) #define AR934X_DDR_REG_FLUSH_USB (AR71XX_APB_BASE + 0xa4) #define AR934X_DDR_REG_FLUSH_PCIE (AR71XX_APB_BASE + 0xa8) #define AR934X_DDR_REG_FLUSH_WMAC (AR71XX_APB_BASE + 0xac) #define AR934X_PLL_CPU_CONFIG_REG (AR71XX_PLL_CPU_BASE + 0x00) #define AR934X_PLL_DDR_CONFIG_REG (AR71XX_PLL_CPU_BASE + 0x04) #define AR934X_PLL_CPU_DDR_CLK_CTRL_REG (AR71XX_PLL_CPU_BASE + 0x08) #define AR934X_PLL_SWITCH_CLOCK_CONTROL_REG (AR71XX_PLL_CPU_BASE + 0x24) #define AR934X_PLL_SWITCH_CLOCK_CONTROL_MDIO_CLK_SEL (1 << 6) #define AR934X_PLL_ETH_XMII_CONTROL_REG (AR71XX_PLL_CPU_BASE + 0x2c) #define AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT 0 #define AR934X_PLL_CPU_CONFIG_NFRAC_MASK 0x3f #define AR934X_PLL_CPU_CONFIG_NINT_SHIFT 6 #define AR934X_PLL_CPU_CONFIG_NINT_MASK 0x3f #define AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT 12 #define AR934X_PLL_CPU_CONFIG_REFDIV_MASK 0x1f #define AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT 19 #define AR934X_PLL_CPU_CONFIG_OUTDIV_MASK 0x3 #define AR934X_PLL_DDR_CONFIG_NFRAC_SHIFT 0 #define AR934X_PLL_DDR_CONFIG_NFRAC_MASK 0x3ff #define AR934X_PLL_DDR_CONFIG_NINT_SHIFT 10 #define AR934X_PLL_DDR_CONFIG_NINT_MASK 0x3f #define AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT 16 #define AR934X_PLL_DDR_CONFIG_REFDIV_MASK 0x1f #define AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT 23 #define AR934X_PLL_DDR_CONFIG_OUTDIV_MASK 0x7 #define AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_PLL_BYPASS (1 << 2) #define AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_PLL_BYPASS (1 << 3) #define AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_PLL_BYPASS (1 << 4) #define AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_SHIFT 5 #define AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_MASK 0x1f #define AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_SHIFT 10 #define AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_MASK 0x1f #define AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_SHIFT 15 #define AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_MASK 0x1f #define AR934X_PLL_CPU_DDR_CLK_CTRL_CPUCLK_FROM_CPUPLL (1 << 20) #define AR934X_PLL_CPU_DDR_CLK_CTRL_DDRCLK_FROM_DDRPLL (1 << 21) #define AR934X_PLL_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL (1 << 24) #define AR934X_RESET_REG_RESET_MODULE (AR71XX_RST_BLOCK_BASE + 0x1c) #define AR934X_RESET_REG_BOOTSTRAP (AR71XX_RST_BLOCK_BASE + 0xb0) #define AR934X_RESET_REG_PCIE_WMAC_INT_STATUS (AR71XX_RST_BLOCK_BASE + 0xac) #define AR934X_RESET_HOST (1U << 31) #define AR934X_RESET_SLIC (1 << 30) #define AR934X_RESET_HDMA (1 << 29) #define AR934X_RESET_EXTERNAL (1 << 28) #define AR934X_RESET_RTC (1 << 27) #define AR934X_RESET_PCIE_EP_INT (1 << 26) #define AR934X_RESET_CHKSUM_ACC (1 << 25) #define AR934X_RESET_FULL_CHIP (1 << 24) #define AR934X_RESET_GE1_MDIO (1 << 23) #define AR934X_RESET_GE0_MDIO (1 << 22) #define AR934X_RESET_CPU_NMI (1 << 21) #define AR934X_RESET_CPU_COLD (1 << 20) #define AR934X_RESET_HOST_RESET_INT (1 << 19) #define AR934X_RESET_PCIE_EP (1 << 18) #define AR934X_RESET_UART1 (1 << 17) #define AR934X_RESET_DDR (1 << 16) #define AR934X_RESET_USB_PHY_PLL_PWD_EXT (1 << 15) #define AR934X_RESET_NANDF (1 << 14) #define AR934X_RESET_GE1_MAC (1 << 13) #define AR934X_RESET_ETH_SWITCH_ANALOG (1 << 12) #define AR934X_RESET_USB_PHY_ANALOG (1 << 11) #define AR934X_RESET_HOST_DMA_INT (1 << 10) #define AR934X_RESET_GE0_MAC (1 << 9) #define AR934X_RESET_ETH_SWITCH (1 << 8) #define AR934X_RESET_PCIE_PHY (1 << 7) #define AR934X_RESET_PCIE (1 << 6) #define AR934X_RESET_USB_HOST (1 << 5) #define AR934X_RESET_USB_PHY (1 << 4) #define AR934X_RESET_USBSUS_OVERRIDE (1 << 3) #define AR934X_RESET_LUT (1 << 2) #define AR934X_RESET_MBOX (1 << 1) #define AR934X_RESET_I2S (1 << 0) #define AR934X_BOOTSTRAP_SW_OPTION8 (1 << 23) #define AR934X_BOOTSTRAP_SW_OPTION7 (1 << 22) #define AR934X_BOOTSTRAP_SW_OPTION6 (1 << 21) #define AR934X_BOOTSTRAP_SW_OPTION5 (1 << 20) #define AR934X_BOOTSTRAP_SW_OPTION4 (1 << 19) #define AR934X_BOOTSTRAP_SW_OPTION3 (1 << 18) #define AR934X_BOOTSTRAP_SW_OPTION2 (1 << 17) #define AR934X_BOOTSTRAP_SW_OPTION1 (1 << 16) #define AR934X_BOOTSTRAP_USB_MODE_DEVICE (1 << 7) #define AR934X_BOOTSTRAP_PCIE_RC (1 << 6) #define AR934X_BOOTSTRAP_EJTAG_MODE (1 << 5) #define AR934X_BOOTSTRAP_REF_CLK_40 (1 << 4) #define AR934X_BOOTSTRAP_BOOT_FROM_SPI (1 << 2) #define AR934X_BOOTSTRAP_SDRAM_DISABLED (1 << 1) #define AR934X_BOOTSTRAP_DDR1 (1 << 0) #define AR934X_PCIE_WMAC_INT_WMAC_MISC (1 << 0) #define AR934X_PCIE_WMAC_INT_WMAC_TX (1 << 1) #define AR934X_PCIE_WMAC_INT_WMAC_RXLP (1 << 2) #define AR934X_PCIE_WMAC_INT_WMAC_RXHP (1 << 3) #define AR934X_PCIE_WMAC_INT_PCIE_RC (1 << 4) #define AR934X_PCIE_WMAC_INT_PCIE_RC0 (1 << 5) #define AR934X_PCIE_WMAC_INT_PCIE_RC1 (1 << 6) #define AR934X_PCIE_WMAC_INT_PCIE_RC2 (1 << 7) #define AR934X_PCIE_WMAC_INT_PCIE_RC3 (1 << 8) #define AR934X_PCIE_WMAC_INT_WMAC_ALL \ (AR934X_PCIE_WMAC_INT_WMAC_MISC | AR934X_PCIE_WMAC_INT_WMAC_TX | \ AR934X_PCIE_WMAC_INT_WMAC_RXLP | AR934X_PCIE_WMAC_INT_WMAC_RXHP) #define AR934X_PCIE_WMAC_INT_PCIE_ALL \ (AR934X_PCIE_WMAC_INT_PCIE_RC | AR934X_PCIE_WMAC_INT_PCIE_RC0 | \ AR934X_PCIE_WMAC_INT_PCIE_RC1 | AR934X_PCIE_WMAC_INT_PCIE_RC2 | \ AR934X_PCIE_WMAC_INT_PCIE_RC3) #define REV_ID_MAJOR_AR9341 0x0120 #define REV_ID_MAJOR_AR9342 0x1120 #define REV_ID_MAJOR_AR9344 0x2120 #define AR934X_REV_ID_REVISION_MASK 0xf /* * GPIO block */ #define AR934X_GPIO_REG_OUT_FUNC0 0x2c #define AR934X_GPIO_REG_OUT_FUNC1 0x30 #define AR934X_GPIO_REG_OUT_FUNC2 0x34 #define AR934X_GPIO_REG_OUT_FUNC3 0x38 #define AR934X_GPIO_REG_OUT_FUNC4 0x3c #define AR934X_GPIO_REG_OUT_FUNC5 0x40 #define AR934X_GPIO_REG_FUNC 0x6c #define AR934X_GPIO_COUNT 23 /* GPIO functions */ #define AR934X_GPIO_FUNC_CLK_OBS7_EN (1 << 9) #define AR934X_GPIO_FUNC_CLK_OBS6_EN (1 << 8) #define AR934X_GPIO_FUNC_CLK_OBS5_EN (1 << 7) #define AR934X_GPIO_FUNC_CLK_OBS4_EN (1 << 6) #define AR934X_GPIO_FUNC_CLK_OBS3_EN (1 << 5) #define AR934X_GPIO_FUNC_CLK_OBS2_EN (1 << 4) #define AR934X_GPIO_FUNC_CLK_OBS1_EN (1 << 3) #define AR934X_GPIO_FUNC_CLK_OBS0_EN (1 << 2) #define AR934X_GPIO_FUNC_JTAG_DISABLE (1 << 1) /* GPIO MUX output function: AR934X_GPIO_REG_OUT_FUNCx */ #define AR934X_GPIO_OUT_GPIO 0 /* I'm a GPIO */ #define AR934X_GPIO_OUT_SPI_CS1 7 /* I'm SPI CS1 */ #define AR934X_GPIO_OUT_LED_LINK0 41 /* I'm switch phy link0 */ #define AR934X_GPIO_OUT_LED_LINK1 42 #define AR934X_GPIO_OUT_LED_LINK2 43 #define AR934X_GPIO_OUT_LED_LINK3 44 #define AR934X_GPIO_OUT_LED_LINK4 45 #define AR934X_GPIO_OUT_EXT_LNA0 46 /* I'm WMAC EXT LNA chain 0 */ #define AR934X_GPIO_OUT_EXT_LNA1 47 /* I'm WMAC EXT LNA chain 1 */ /* * SRIF block */ #define AR934X_SRIF_CPU_DPLL1_REG (AR934X_SRIF_BASE + 0x1c0) #define AR934X_SRIF_CPU_DPLL2_REG (AR934X_SRIF_BASE + 0x1c4) #define AR934X_SRIF_CPU_DPLL3_REG (AR934X_SRIF_BASE + 0x1c8) #define AR934X_SRIF_DDR_DPLL1_REG (AR934X_SRIF_BASE + 0x240) #define AR934X_SRIF_DDR_DPLL2_REG (AR934X_SRIF_BASE + 0x244) #define AR934X_SRIF_DDR_DPLL3_REG (AR934X_SRIF_BASE + 0x248) #define AR934X_SRIF_DPLL1_REFDIV_SHIFT 27 #define AR934X_SRIF_DPLL1_REFDIV_MASK 0x1f #define AR934X_SRIF_DPLL1_NINT_SHIFT 18 #define AR934X_SRIF_DPLL1_NINT_MASK 0x1ff #define AR934X_SRIF_DPLL1_NFRAC_MASK 0x0003ffff #define AR934X_SRIF_DPLL2_LOCAL_PLL (1 << 30) #define AR934X_SRIF_DPLL2_OUTDIV_SHIFT 13 #define AR934X_SRIF_DPLL2_OUTDIV_MASK 0x7 /* XXX verify! */ #define AR934X_PLL_VAL_1000 0x16000000 #define AR934X_PLL_VAL_100 0x00000101 #define AR934X_PLL_VAL_10 0x00001616 #endif /* __AR934X_REG_H__ */ Index: head/sys/mips/atheros/if_arge.c =================================================================== --- head/sys/mips/atheros/if_arge.c (revision 326258) +++ head/sys/mips/atheros/if_arge.c (revision 326259) @@ -1,2737 +1,2739 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009, Oleksandr Tymoshenko * 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 unmodified, 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$"); /* * AR71XX gigabit ethernet driver */ #ifdef HAVE_KERNEL_OPTION_HEADERS #include "opt_device_polling.h" #endif #include "opt_arge.h" #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 "opt_arge.h" #if defined(ARGE_MDIO) #include #include #include "mdio_if.h" #endif MODULE_DEPEND(arge, ether, 1, 1, 1); MODULE_DEPEND(arge, miibus, 1, 1, 1); MODULE_VERSION(arge, 1); #include "miibus_if.h" #include #include #include /* XXX tsk! */ #include /* XXX tsk! */ #include /* XXX tsk! */ #include #include #include #include typedef enum { ARGE_DBG_MII = 0x00000001, ARGE_DBG_INTR = 0x00000002, ARGE_DBG_TX = 0x00000004, ARGE_DBG_RX = 0x00000008, ARGE_DBG_ERR = 0x00000010, ARGE_DBG_RESET = 0x00000020, ARGE_DBG_PLL = 0x00000040, ARGE_DBG_ANY = 0xffffffff, } arge_debug_flags; static const char * arge_miicfg_str[] = { "NONE", "GMII", "MII", "RGMII", "RMII", "SGMII" }; #ifdef ARGE_DEBUG #define ARGEDEBUG(_sc, _m, ...) \ do { \ if (((_m) & (_sc)->arge_debug) || ((_m) == ARGE_DBG_ANY)) \ device_printf((_sc)->arge_dev, __VA_ARGS__); \ } while (0) #else #define ARGEDEBUG(_sc, _m, ...) #endif static int arge_attach(device_t); static int arge_detach(device_t); static void arge_flush_ddr(struct arge_softc *); static int arge_ifmedia_upd(struct ifnet *); static void arge_ifmedia_sts(struct ifnet *, struct ifmediareq *); static int arge_ioctl(struct ifnet *, u_long, caddr_t); static void arge_init(void *); static void arge_init_locked(struct arge_softc *); static void arge_link_task(void *, int); static void arge_update_link_locked(struct arge_softc *sc); static void arge_set_pll(struct arge_softc *, int, int); static int arge_miibus_readreg(device_t, int, int); static void arge_miibus_statchg(device_t); static int arge_miibus_writereg(device_t, int, int, int); static int arge_probe(device_t); static void arge_reset_dma(struct arge_softc *); static int arge_resume(device_t); static int arge_rx_ring_init(struct arge_softc *); static void arge_rx_ring_free(struct arge_softc *sc); static int arge_tx_ring_init(struct arge_softc *); static void arge_tx_ring_free(struct arge_softc *); #ifdef DEVICE_POLLING static int arge_poll(struct ifnet *, enum poll_cmd, int); #endif static int arge_shutdown(device_t); static void arge_start(struct ifnet *); static void arge_start_locked(struct ifnet *); static void arge_stop(struct arge_softc *); static int arge_suspend(device_t); static int arge_rx_locked(struct arge_softc *); static void arge_tx_locked(struct arge_softc *); static void arge_intr(void *); static int arge_intr_filter(void *); static void arge_tick(void *); static void arge_hinted_child(device_t bus, const char *dname, int dunit); /* * ifmedia callbacks for multiPHY MAC */ void arge_multiphy_mediastatus(struct ifnet *, struct ifmediareq *); int arge_multiphy_mediachange(struct ifnet *); static void arge_dmamap_cb(void *, bus_dma_segment_t *, int, int); static int arge_dma_alloc(struct arge_softc *); static void arge_dma_free(struct arge_softc *); static int arge_newbuf(struct arge_softc *, int); static __inline void arge_fixup_rx(struct mbuf *); static device_method_t arge_methods[] = { /* Device interface */ DEVMETHOD(device_probe, arge_probe), DEVMETHOD(device_attach, arge_attach), DEVMETHOD(device_detach, arge_detach), DEVMETHOD(device_suspend, arge_suspend), DEVMETHOD(device_resume, arge_resume), DEVMETHOD(device_shutdown, arge_shutdown), /* MII interface */ DEVMETHOD(miibus_readreg, arge_miibus_readreg), DEVMETHOD(miibus_writereg, arge_miibus_writereg), DEVMETHOD(miibus_statchg, arge_miibus_statchg), /* bus interface */ DEVMETHOD(bus_add_child, device_add_child_ordered), DEVMETHOD(bus_hinted_child, arge_hinted_child), DEVMETHOD_END }; static driver_t arge_driver = { "arge", arge_methods, sizeof(struct arge_softc) }; static devclass_t arge_devclass; DRIVER_MODULE(arge, nexus, arge_driver, arge_devclass, 0, 0); DRIVER_MODULE(miibus, arge, miibus_driver, miibus_devclass, 0, 0); #if defined(ARGE_MDIO) static int argemdio_probe(device_t); static int argemdio_attach(device_t); static int argemdio_detach(device_t); /* * Declare an additional, separate driver for accessing the MDIO bus. */ static device_method_t argemdio_methods[] = { /* Device interface */ DEVMETHOD(device_probe, argemdio_probe), DEVMETHOD(device_attach, argemdio_attach), DEVMETHOD(device_detach, argemdio_detach), /* bus interface */ DEVMETHOD(bus_add_child, device_add_child_ordered), /* MDIO access */ DEVMETHOD(mdio_readreg, arge_miibus_readreg), DEVMETHOD(mdio_writereg, arge_miibus_writereg), }; DEFINE_CLASS_0(argemdio, argemdio_driver, argemdio_methods, sizeof(struct arge_softc)); static devclass_t argemdio_devclass; DRIVER_MODULE(miiproxy, arge, miiproxy_driver, miiproxy_devclass, 0, 0); DRIVER_MODULE(argemdio, nexus, argemdio_driver, argemdio_devclass, 0, 0); DRIVER_MODULE(mdio, argemdio, mdio_driver, mdio_devclass, 0, 0); #endif static struct mtx miibus_mtx; MTX_SYSINIT(miibus_mtx, &miibus_mtx, "arge mii lock", MTX_DEF); /* * Flushes all * * XXX this needs to be done at interrupt time! Grr! */ static void arge_flush_ddr(struct arge_softc *sc) { switch (sc->arge_mac_unit) { case 0: ar71xx_device_flush_ddr(AR71XX_CPU_DDR_FLUSH_GE0); break; case 1: ar71xx_device_flush_ddr(AR71XX_CPU_DDR_FLUSH_GE1); break; default: device_printf(sc->arge_dev, "%s: unknown unit (%d)\n", __func__, sc->arge_mac_unit); break; } } static int arge_probe(device_t dev) { device_set_desc(dev, "Atheros AR71xx built-in ethernet interface"); return (BUS_PROBE_NOWILDCARD); } #ifdef ARGE_DEBUG static void arge_attach_intr_sysctl(device_t dev, struct sysctl_oid_list *parent) { struct arge_softc *sc = device_get_softc(dev); struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); struct sysctl_oid *tree = device_get_sysctl_tree(dev); struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); char sn[8]; int i; tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "intr", CTLFLAG_RD, NULL, "Interrupt statistics"); child = SYSCTL_CHILDREN(tree); for (i = 0; i < 32; i++) { snprintf(sn, sizeof(sn), "%d", i); SYSCTL_ADD_UINT(ctx, child, OID_AUTO, sn, CTLFLAG_RD, &sc->intr_stats.count[i], 0, ""); } } #endif static void arge_attach_sysctl(device_t dev) { struct arge_softc *sc = device_get_softc(dev); struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); struct sysctl_oid *tree = device_get_sysctl_tree(dev); #ifdef ARGE_DEBUG SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "debug", CTLFLAG_RW, &sc->arge_debug, 0, "arge interface debugging flags"); arge_attach_intr_sysctl(dev, SYSCTL_CHILDREN(tree)); #endif SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tx_pkts_aligned", CTLFLAG_RW, &sc->stats.tx_pkts_aligned, 0, "number of TX aligned packets"); SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tx_pkts_unaligned", CTLFLAG_RW, &sc->stats.tx_pkts_unaligned, 0, "number of TX unaligned packets"); SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tx_pkts_unaligned_start", CTLFLAG_RW, &sc->stats.tx_pkts_unaligned_start, 0, "number of TX unaligned packets (start)"); SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tx_pkts_unaligned_len", CTLFLAG_RW, &sc->stats.tx_pkts_unaligned_len, 0, "number of TX unaligned packets (len)"); SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tx_pkts_nosegs", CTLFLAG_RW, &sc->stats.tx_pkts_nosegs, 0, "number of TX packets fail with no ring slots avail"); SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "intr_stray_filter", CTLFLAG_RW, &sc->stats.intr_stray, 0, "number of stray interrupts (filter)"); SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "intr_stray_intr", CTLFLAG_RW, &sc->stats.intr_stray2, 0, "number of stray interrupts (intr)"); SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "intr_ok", CTLFLAG_RW, &sc->stats.intr_ok, 0, "number of OK interrupts"); #ifdef ARGE_DEBUG SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tx_prod", CTLFLAG_RW, &sc->arge_cdata.arge_tx_prod, 0, ""); SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tx_cons", CTLFLAG_RW, &sc->arge_cdata.arge_tx_cons, 0, ""); SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "tx_cnt", CTLFLAG_RW, &sc->arge_cdata.arge_tx_cnt, 0, ""); #endif } static void arge_reset_mac(struct arge_softc *sc) { uint32_t reg; uint32_t reset_reg; ARGEDEBUG(sc, ARGE_DBG_RESET, "%s called\n", __func__); /* Step 1. Soft-reset MAC */ ARGE_SET_BITS(sc, AR71XX_MAC_CFG1, MAC_CFG1_SOFT_RESET); DELAY(20); /* Step 2. Punt the MAC core from the central reset register */ /* * XXX TODO: migrate this (and other) chip specific stuff into * a chipdef method. */ if (sc->arge_mac_unit == 0) { reset_reg = RST_RESET_GE0_MAC; } else { reset_reg = RST_RESET_GE1_MAC; } /* * AR934x (and later) also needs the MDIO block reset. * XXX should methodize this! */ if (ar71xx_soc == AR71XX_SOC_AR9341 || ar71xx_soc == AR71XX_SOC_AR9342 || ar71xx_soc == AR71XX_SOC_AR9344) { if (sc->arge_mac_unit == 0) { reset_reg |= AR934X_RESET_GE0_MDIO; } else { reset_reg |= AR934X_RESET_GE1_MDIO; } } if (ar71xx_soc == AR71XX_SOC_QCA9556 || ar71xx_soc == AR71XX_SOC_QCA9558) { if (sc->arge_mac_unit == 0) { reset_reg |= QCA955X_RESET_GE0_MDIO; } else { reset_reg |= QCA955X_RESET_GE1_MDIO; } } if (ar71xx_soc == AR71XX_SOC_QCA9533 || ar71xx_soc == AR71XX_SOC_QCA9533_V2) { if (sc->arge_mac_unit == 0) { reset_reg |= QCA953X_RESET_GE0_MDIO; } else { reset_reg |= QCA953X_RESET_GE1_MDIO; } } ar71xx_device_stop(reset_reg); DELAY(100); ar71xx_device_start(reset_reg); /* Step 3. Reconfigure MAC block */ ARGE_WRITE(sc, AR71XX_MAC_CFG1, MAC_CFG1_SYNC_RX | MAC_CFG1_RX_ENABLE | MAC_CFG1_SYNC_TX | MAC_CFG1_TX_ENABLE); reg = ARGE_READ(sc, AR71XX_MAC_CFG2); reg |= MAC_CFG2_ENABLE_PADCRC | MAC_CFG2_LENGTH_FIELD ; ARGE_WRITE(sc, AR71XX_MAC_CFG2, reg); ARGE_WRITE(sc, AR71XX_MAC_MAX_FRAME_LEN, 1536); } /* * These values map to the divisor values programmed into * AR71XX_MAC_MII_CFG. * * The index of each value corresponds to the divisor section * value in AR71XX_MAC_MII_CFG (ie, table[0] means '0' in * AR71XX_MAC_MII_CFG, table[1] means '1', etc.) */ static const uint32_t ar71xx_mdio_div_table[] = { 4, 4, 6, 8, 10, 14, 20, 28, }; static const uint32_t ar7240_mdio_div_table[] = { 2, 2, 4, 6, 8, 12, 18, 26, 32, 40, 48, 56, 62, 70, 78, 96, }; static const uint32_t ar933x_mdio_div_table[] = { 4, 4, 6, 8, 10, 14, 20, 28, 34, 42, 50, 58, 66, 74, 82, 98, }; /* * Lookup the divisor to use based on the given frequency. * * Returns the divisor to use, or -ve on error. */ static int arge_mdio_get_divider(struct arge_softc *sc, unsigned long mdio_clock) { unsigned long ref_clock, t; const uint32_t *table; int ndivs; int i; /* * This is the base MDIO frequency on the SoC. * The dividers .. well, divide. Duh. */ ref_clock = ar71xx_mdio_freq(); /* * If either clock is undefined, just tell the * caller to fall through to the defaults. */ if (ref_clock == 0 || mdio_clock == 0) return (-EINVAL); /* * Pick the correct table! */ switch (ar71xx_soc) { case AR71XX_SOC_AR9330: case AR71XX_SOC_AR9331: case AR71XX_SOC_AR9341: case AR71XX_SOC_AR9342: case AR71XX_SOC_AR9344: case AR71XX_SOC_QCA9533: case AR71XX_SOC_QCA9533_V2: case AR71XX_SOC_QCA9556: case AR71XX_SOC_QCA9558: table = ar933x_mdio_div_table; ndivs = nitems(ar933x_mdio_div_table); break; case AR71XX_SOC_AR7240: case AR71XX_SOC_AR7241: case AR71XX_SOC_AR7242: table = ar7240_mdio_div_table; ndivs = nitems(ar7240_mdio_div_table); break; default: table = ar71xx_mdio_div_table; ndivs = nitems(ar71xx_mdio_div_table); } /* * Now, walk through the list and find the first divisor * that falls under the target MDIO frequency. * * The divisors go up, but the corresponding frequencies * are actually decreasing. */ for (i = 0; i < ndivs; i++) { t = ref_clock / table[i]; if (t <= mdio_clock) { return (i); } } ARGEDEBUG(sc, ARGE_DBG_RESET, "No divider found; MDIO=%lu Hz; target=%lu Hz\n", ref_clock, mdio_clock); return (-ENOENT); } /* * Fetch the MDIO bus clock rate. * * For now, the default is DIV_28 for everything * bar AR934x, which will be DIV_58. * * It will definitely need updating to take into account * the MDIO bus core clock rate and the target clock * rate for the chip. */ static uint32_t arge_fetch_mdiobus_clock_rate(struct arge_softc *sc) { int mdio_freq, div; /* * Is the MDIO frequency defined? If so, find a divisor that * makes reasonable sense. Don't overshoot the frequency. */ if (resource_int_value(device_get_name(sc->arge_dev), device_get_unit(sc->arge_dev), "mdio_freq", &mdio_freq) == 0) { sc->arge_mdiofreq = mdio_freq; div = arge_mdio_get_divider(sc, sc->arge_mdiofreq); if (bootverbose) device_printf(sc->arge_dev, "%s: mdio ref freq=%llu Hz, target freq=%llu Hz," " divisor index=%d\n", __func__, (unsigned long long) ar71xx_mdio_freq(), (unsigned long long) mdio_freq, div); if (div >= 0) return (div); } /* * Default value(s). * * XXX obviously these need .. fixing. * * From Linux/OpenWRT: * * + 7240? DIV_6 * + Builtin-switch port and not 934x? DIV_10 * + Not built-in switch port and 934x? DIV_58 * + .. else DIV_28. */ switch (ar71xx_soc) { case AR71XX_SOC_AR9341: case AR71XX_SOC_AR9342: case AR71XX_SOC_AR9344: case AR71XX_SOC_QCA9533: case AR71XX_SOC_QCA9533_V2: case AR71XX_SOC_QCA9556: case AR71XX_SOC_QCA9558: return (MAC_MII_CFG_CLOCK_DIV_58); break; default: return (MAC_MII_CFG_CLOCK_DIV_28); } } static void arge_reset_miibus(struct arge_softc *sc) { uint32_t mdio_div; mdio_div = arge_fetch_mdiobus_clock_rate(sc); /* * XXX AR934x and later; should we be also resetting the * MDIO block(s) using the reset register block? */ /* Reset MII bus; program in the default divisor */ ARGE_WRITE(sc, AR71XX_MAC_MII_CFG, MAC_MII_CFG_RESET | mdio_div); DELAY(100); ARGE_WRITE(sc, AR71XX_MAC_MII_CFG, mdio_div); DELAY(100); } static void arge_fetch_pll_config(struct arge_softc *sc) { long int val; if (resource_long_value(device_get_name(sc->arge_dev), device_get_unit(sc->arge_dev), "pll_10", &val) == 0) { sc->arge_pllcfg.pll_10 = val; device_printf(sc->arge_dev, "%s: pll_10 = 0x%x\n", __func__, (int) val); } if (resource_long_value(device_get_name(sc->arge_dev), device_get_unit(sc->arge_dev), "pll_100", &val) == 0) { sc->arge_pllcfg.pll_100 = val; device_printf(sc->arge_dev, "%s: pll_100 = 0x%x\n", __func__, (int) val); } if (resource_long_value(device_get_name(sc->arge_dev), device_get_unit(sc->arge_dev), "pll_1000", &val) == 0) { sc->arge_pllcfg.pll_1000 = val; device_printf(sc->arge_dev, "%s: pll_1000 = 0x%x\n", __func__, (int) val); } } static int arge_attach(device_t dev) { struct ifnet *ifp; struct arge_softc *sc; int error = 0, rid, i; uint32_t hint; long eeprom_mac_addr = 0; int miicfg = 0; int readascii = 0; int local_mac = 0; uint8_t local_macaddr[ETHER_ADDR_LEN]; char * local_macstr; char devid_str[32]; int count; sc = device_get_softc(dev); sc->arge_dev = dev; sc->arge_mac_unit = device_get_unit(dev); /* * See if there's a "board" MAC address hint available for * this particular device. * * This is in the environment - it'd be nice to use the resource_*() * routines, but at the moment the system is booting, the resource hints * are set to the 'static' map so they're not pulling from kenv. */ snprintf(devid_str, 32, "hint.%s.%d.macaddr", device_get_name(dev), device_get_unit(dev)); if ((local_macstr = kern_getenv(devid_str)) != NULL) { uint32_t tmpmac[ETHER_ADDR_LEN]; /* Have a MAC address; should use it */ device_printf(dev, "Overriding MAC address from environment: '%s'\n", local_macstr); /* Extract out the MAC address */ /* XXX this should all be a generic method */ count = sscanf(local_macstr, "%x%*c%x%*c%x%*c%x%*c%x%*c%x", &tmpmac[0], &tmpmac[1], &tmpmac[2], &tmpmac[3], &tmpmac[4], &tmpmac[5]); if (count == 6) { /* Valid! */ local_mac = 1; for (i = 0; i < ETHER_ADDR_LEN; i++) local_macaddr[i] = tmpmac[i]; } /* Done! */ freeenv(local_macstr); local_macstr = NULL; } /* * Hardware workarounds. */ switch (ar71xx_soc) { case AR71XX_SOC_AR9330: case AR71XX_SOC_AR9331: case AR71XX_SOC_AR9341: case AR71XX_SOC_AR9342: case AR71XX_SOC_AR9344: case AR71XX_SOC_QCA9533: case AR71XX_SOC_QCA9533_V2: case AR71XX_SOC_QCA9556: case AR71XX_SOC_QCA9558: /* Arbitrary alignment */ sc->arge_hw_flags |= ARGE_HW_FLG_TX_DESC_ALIGN_1BYTE; sc->arge_hw_flags |= ARGE_HW_FLG_RX_DESC_ALIGN_1BYTE; break; default: sc->arge_hw_flags |= ARGE_HW_FLG_TX_DESC_ALIGN_4BYTE; sc->arge_hw_flags |= ARGE_HW_FLG_RX_DESC_ALIGN_4BYTE; break; } /* * Some units (eg the TP-Link WR-1043ND) do not have a convenient * EEPROM location to read the ethernet MAC address from. * OpenWRT simply snaffles it from a fixed location. * * Since multiple units seem to use this feature, include * a method of setting the MAC address based on an flash location * in CPU address space. * * Some vendors have decided to store the mac address as a literal * string of 18 characters in xx:xx:xx:xx:xx:xx format instead of * an array of numbers. Expose a hint to turn on this conversion * feature via strtol() */ if (local_mac == 0 && resource_long_value(device_get_name(dev), device_get_unit(dev), "eeprommac", &eeprom_mac_addr) == 0) { local_mac = 1; int i; const char *mac = (const char *) MIPS_PHYS_TO_KSEG1(eeprom_mac_addr); device_printf(dev, "Overriding MAC from EEPROM\n"); if (resource_int_value(device_get_name(dev), device_get_unit(dev), "readascii", &readascii) == 0) { device_printf(dev, "Vendor stores MAC in ASCII format\n"); for (i = 0; i < 6; i++) { local_macaddr[i] = strtol(&(mac[i*3]), NULL, 16); } } else { for (i = 0; i < 6; i++) { local_macaddr[i] = mac[i]; } } } KASSERT(((sc->arge_mac_unit == 0) || (sc->arge_mac_unit == 1)), ("if_arge: Only MAC0 and MAC1 supported")); /* * Fetch the PLL configuration. */ arge_fetch_pll_config(sc); /* * Get the MII configuration, if applicable. */ if (resource_int_value(device_get_name(dev), device_get_unit(dev), "miimode", &miicfg) == 0) { /* XXX bounds check? */ device_printf(dev, "%s: overriding MII mode to '%s'\n", __func__, arge_miicfg_str[miicfg]); sc->arge_miicfg = miicfg; } /* * Get which PHY of 5 available we should use for this unit */ if (resource_int_value(device_get_name(dev), device_get_unit(dev), "phymask", &sc->arge_phymask) != 0) { /* * Use port 4 (WAN) for GE0. For any other port use * its PHY the same as its unit number */ if (sc->arge_mac_unit == 0) sc->arge_phymask = (1 << 4); else /* Use all phys up to 4 */ sc->arge_phymask = (1 << 4) - 1; device_printf(dev, "No PHY specified, using mask %d\n", sc->arge_phymask); } /* * Get default/hard-coded media & duplex mode. */ if (resource_int_value(device_get_name(dev), device_get_unit(dev), "media", &hint) != 0) hint = 0; if (hint == 1000) sc->arge_media_type = IFM_1000_T; else if (hint == 100) sc->arge_media_type = IFM_100_TX; else if (hint == 10) sc->arge_media_type = IFM_10_T; else sc->arge_media_type = 0; if (resource_int_value(device_get_name(dev), device_get_unit(dev), "fduplex", &hint) != 0) hint = 1; if (hint) sc->arge_duplex_mode = IFM_FDX; else sc->arge_duplex_mode = 0; mtx_init(&sc->arge_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF); callout_init_mtx(&sc->arge_stat_callout, &sc->arge_mtx, 0); TASK_INIT(&sc->arge_link_task, 0, arge_link_task, sc); /* Map control/status registers. */ sc->arge_rid = 0; sc->arge_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->arge_rid, RF_ACTIVE | RF_SHAREABLE); if (sc->arge_res == NULL) { device_printf(dev, "couldn't map memory\n"); error = ENXIO; goto fail; } /* Allocate interrupts */ rid = 0; sc->arge_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); if (sc->arge_irq == NULL) { device_printf(dev, "couldn't map interrupt\n"); error = ENXIO; goto fail; } /* Allocate ifnet structure. */ ifp = sc->arge_ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { device_printf(dev, "couldn't allocate ifnet structure\n"); error = ENOSPC; goto fail; } ifp->if_softc = sc; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = arge_ioctl; ifp->if_start = arge_start; ifp->if_init = arge_init; sc->arge_if_flags = ifp->if_flags; /* XXX: add real size */ IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen); ifp->if_snd.ifq_maxlen = ifqmaxlen; IFQ_SET_READY(&ifp->if_snd); /* Tell the upper layer(s) we support long frames. */ ifp->if_capabilities |= IFCAP_VLAN_MTU; ifp->if_capenable = ifp->if_capabilities; #ifdef DEVICE_POLLING ifp->if_capabilities |= IFCAP_POLLING; #endif /* If there's a local mac defined, copy that in */ if (local_mac == 1) { (void) ar71xx_mac_addr_init(sc->arge_eaddr, local_macaddr, 0, 0); } else { /* * No MAC address configured. Generate the random one. */ if (bootverbose) device_printf(dev, "Generating random ethernet address.\n"); (void) ar71xx_mac_addr_random_init(sc->arge_eaddr); } if (arge_dma_alloc(sc) != 0) { error = ENXIO; goto fail; } /* * Don't do this for the MDIO bus case - it's already done * as part of the MDIO bus attachment. * * XXX TODO: if we don't do this, we don't ever release the MAC * from reset and we can't use the port. Now, if we define ARGE_MDIO * but we /don't/ define two MDIO busses, then we can't actually * use both MACs. */ #if !defined(ARGE_MDIO) /* Initialize the MAC block */ arge_reset_mac(sc); arge_reset_miibus(sc); #endif /* Configure MII mode, just for convienence */ if (sc->arge_miicfg != 0) ar71xx_device_set_mii_if(sc->arge_mac_unit, sc->arge_miicfg); /* * Set all Ethernet address registers to the same initial values * set all four addresses to 66-88-aa-cc-dd-ee */ ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR1, (sc->arge_eaddr[2] << 24) | (sc->arge_eaddr[3] << 16) | (sc->arge_eaddr[4] << 8) | sc->arge_eaddr[5]); ARGE_WRITE(sc, AR71XX_MAC_STA_ADDR2, (sc->arge_eaddr[0] << 8) | sc->arge_eaddr[1]); ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG0, FIFO_CFG0_ALL << FIFO_CFG0_ENABLE_SHIFT); /* * SoC specific bits. */ switch (ar71xx_soc) { case AR71XX_SOC_AR7240: case AR71XX_SOC_AR7241: case AR71XX_SOC_AR7242: case AR71XX_SOC_AR9330: case AR71XX_SOC_AR9331: case AR71XX_SOC_AR9341: case AR71XX_SOC_AR9342: case AR71XX_SOC_AR9344: case AR71XX_SOC_QCA9533: case AR71XX_SOC_QCA9533_V2: case AR71XX_SOC_QCA9556: case AR71XX_SOC_QCA9558: ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG1, 0x0010ffff); ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG2, 0x015500aa); break; /* AR71xx, AR913x */ default: ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG1, 0x0fff0000); ARGE_WRITE(sc, AR71XX_MAC_FIFO_CFG2, 0x00001fff); } ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMATCH, FIFO_RX_FILTMATCH_DEFAULT); ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMASK, FIFO_RX_FILTMASK_DEFAULT); #if defined(ARGE_MDIO) sc->arge_miiproxy = mii_attach_proxy(sc->arge_dev); #endif device_printf(sc->arge_dev, "finishing attachment, phymask %04x" ", proxy %s \n", sc->arge_phymask, sc->arge_miiproxy == NULL ? "null" : "set"); for (i = 0; i < ARGE_NPHY; i++) { if (((1 << i) & sc->arge_phymask) != 0) { error = mii_attach(sc->arge_miiproxy != NULL ? sc->arge_miiproxy : sc->arge_dev, &sc->arge_miibus, sc->arge_ifp, arge_ifmedia_upd, arge_ifmedia_sts, BMSR_DEFCAPMASK, i, MII_OFFSET_ANY, 0); if (error != 0) { device_printf(sc->arge_dev, "unable to attach" " PHY %d: %d\n", i, error); goto fail; } } } if (sc->arge_miibus == NULL) { /* no PHY, so use hard-coded values */ ifmedia_init(&sc->arge_ifmedia, 0, arge_multiphy_mediachange, arge_multiphy_mediastatus); ifmedia_add(&sc->arge_ifmedia, IFM_ETHER | sc->arge_media_type | sc->arge_duplex_mode, 0, NULL); ifmedia_set(&sc->arge_ifmedia, IFM_ETHER | sc->arge_media_type | sc->arge_duplex_mode); arge_set_pll(sc, sc->arge_media_type, sc->arge_duplex_mode); } /* Call MI attach routine. */ ether_ifattach(sc->arge_ifp, sc->arge_eaddr); /* Hook interrupt last to avoid having to lock softc */ error = bus_setup_intr(sc->arge_dev, sc->arge_irq, INTR_TYPE_NET | INTR_MPSAFE, arge_intr_filter, arge_intr, sc, &sc->arge_intrhand); if (error) { device_printf(sc->arge_dev, "couldn't set up irq\n"); ether_ifdetach(sc->arge_ifp); goto fail; } /* setup sysctl variables */ arge_attach_sysctl(sc->arge_dev); fail: if (error) arge_detach(dev); return (error); } static int arge_detach(device_t dev) { struct arge_softc *sc = device_get_softc(dev); struct ifnet *ifp = sc->arge_ifp; KASSERT(mtx_initialized(&sc->arge_mtx), ("arge mutex not initialized")); /* These should only be active if attach succeeded */ if (device_is_attached(dev)) { ARGE_LOCK(sc); sc->arge_detach = 1; #ifdef DEVICE_POLLING if (ifp->if_capenable & IFCAP_POLLING) ether_poll_deregister(ifp); #endif arge_stop(sc); ARGE_UNLOCK(sc); taskqueue_drain(taskqueue_swi, &sc->arge_link_task); ether_ifdetach(ifp); } if (sc->arge_miibus) device_delete_child(dev, sc->arge_miibus); if (sc->arge_miiproxy) device_delete_child(dev, sc->arge_miiproxy); bus_generic_detach(dev); if (sc->arge_intrhand) bus_teardown_intr(dev, sc->arge_irq, sc->arge_intrhand); if (sc->arge_res) bus_release_resource(dev, SYS_RES_MEMORY, sc->arge_rid, sc->arge_res); if (ifp) if_free(ifp); arge_dma_free(sc); mtx_destroy(&sc->arge_mtx); return (0); } static int arge_suspend(device_t dev) { panic("%s", __func__); return 0; } static int arge_resume(device_t dev) { panic("%s", __func__); return 0; } static int arge_shutdown(device_t dev) { struct arge_softc *sc; sc = device_get_softc(dev); ARGE_LOCK(sc); arge_stop(sc); ARGE_UNLOCK(sc); return (0); } static void arge_hinted_child(device_t bus, const char *dname, int dunit) { BUS_ADD_CHILD(bus, 0, dname, dunit); device_printf(bus, "hinted child %s%d\n", dname, dunit); } static int arge_mdio_busy(struct arge_softc *sc) { int i,result; for (i = 0; i < ARGE_MII_TIMEOUT; i++) { DELAY(5); ARGE_MDIO_BARRIER_READ(sc); result = ARGE_MDIO_READ(sc, AR71XX_MAC_MII_INDICATOR); if (! result) return (0); DELAY(5); } return (-1); } static int arge_miibus_readreg(device_t dev, int phy, int reg) { struct arge_softc * sc = device_get_softc(dev); int result; uint32_t addr = (phy << MAC_MII_PHY_ADDR_SHIFT) | (reg & MAC_MII_REG_MASK); mtx_lock(&miibus_mtx); ARGE_MDIO_BARRIER_RW(sc); ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_CMD, MAC_MII_CMD_WRITE); ARGE_MDIO_BARRIER_WRITE(sc); ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_ADDR, addr); ARGE_MDIO_BARRIER_WRITE(sc); ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_CMD, MAC_MII_CMD_READ); if (arge_mdio_busy(sc) != 0) { mtx_unlock(&miibus_mtx); ARGEDEBUG(sc, ARGE_DBG_ANY, "%s timedout\n", __func__); /* XXX: return ERRNO istead? */ return (-1); } ARGE_MDIO_BARRIER_READ(sc); result = ARGE_MDIO_READ(sc, AR71XX_MAC_MII_STATUS) & MAC_MII_STATUS_MASK; ARGE_MDIO_BARRIER_RW(sc); ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_CMD, MAC_MII_CMD_WRITE); mtx_unlock(&miibus_mtx); ARGEDEBUG(sc, ARGE_DBG_MII, "%s: phy=%d, reg=%02x, value[%08x]=%04x\n", __func__, phy, reg, addr, result); return (result); } static int arge_miibus_writereg(device_t dev, int phy, int reg, int data) { struct arge_softc * sc = device_get_softc(dev); uint32_t addr = (phy << MAC_MII_PHY_ADDR_SHIFT) | (reg & MAC_MII_REG_MASK); ARGEDEBUG(sc, ARGE_DBG_MII, "%s: phy=%d, reg=%02x, value=%04x\n", __func__, phy, reg, data); mtx_lock(&miibus_mtx); ARGE_MDIO_BARRIER_RW(sc); ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_ADDR, addr); ARGE_MDIO_BARRIER_WRITE(sc); ARGE_MDIO_WRITE(sc, AR71XX_MAC_MII_CONTROL, data); ARGE_MDIO_BARRIER_WRITE(sc); if (arge_mdio_busy(sc) != 0) { mtx_unlock(&miibus_mtx); ARGEDEBUG(sc, ARGE_DBG_ANY, "%s timedout\n", __func__); /* XXX: return ERRNO istead? */ return (-1); } mtx_unlock(&miibus_mtx); return (0); } static void arge_miibus_statchg(device_t dev) { struct arge_softc *sc; sc = device_get_softc(dev); taskqueue_enqueue(taskqueue_swi, &sc->arge_link_task); } static void arge_link_task(void *arg, int pending) { struct arge_softc *sc; sc = (struct arge_softc *)arg; ARGE_LOCK(sc); arge_update_link_locked(sc); ARGE_UNLOCK(sc); } static void arge_update_link_locked(struct arge_softc *sc) { struct mii_data *mii; struct ifnet *ifp; uint32_t media, duplex; mii = device_get_softc(sc->arge_miibus); ifp = sc->arge_ifp; if (mii == NULL || ifp == NULL || (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { return; } /* * If we have a static media type configured, then * use that. Some PHY configurations (eg QCA955x -> AR8327) * use a static speed/duplex between the SoC and switch, * even though the front-facing PHY speed changes. */ if (sc->arge_media_type != 0) { ARGEDEBUG(sc, ARGE_DBG_MII, "%s: fixed; media=%d, duplex=%d\n", __func__, sc->arge_media_type, sc->arge_duplex_mode); if (mii->mii_media_status & IFM_ACTIVE) { sc->arge_link_status = 1; } else { sc->arge_link_status = 0; } arge_set_pll(sc, sc->arge_media_type, sc->arge_duplex_mode); } if (mii->mii_media_status & IFM_ACTIVE) { media = IFM_SUBTYPE(mii->mii_media_active); if (media != IFM_NONE) { sc->arge_link_status = 1; duplex = mii->mii_media_active & IFM_GMASK; ARGEDEBUG(sc, ARGE_DBG_MII, "%s: media=%d, duplex=%d\n", __func__, media, duplex); arge_set_pll(sc, media, duplex); } } else { sc->arge_link_status = 0; } } static void arge_set_pll(struct arge_softc *sc, int media, int duplex) { uint32_t cfg, ifcontrol, rx_filtmask; uint32_t fifo_tx, pll; int if_speed; /* * XXX Verify - is this valid for all chips? * QCA955x (and likely some of the earlier chips!) define * this as nibble mode and byte mode, and those have to do * with the interface type (MII/SMII versus GMII/RGMII.) */ ARGEDEBUG(sc, ARGE_DBG_PLL, "set_pll(%04x, %s)\n", media, duplex == IFM_FDX ? "full" : "half"); cfg = ARGE_READ(sc, AR71XX_MAC_CFG2); cfg &= ~(MAC_CFG2_IFACE_MODE_1000 | MAC_CFG2_IFACE_MODE_10_100 | MAC_CFG2_FULL_DUPLEX); if (duplex == IFM_FDX) cfg |= MAC_CFG2_FULL_DUPLEX; ifcontrol = ARGE_READ(sc, AR71XX_MAC_IFCONTROL); ifcontrol &= ~MAC_IFCONTROL_SPEED; rx_filtmask = ARGE_READ(sc, AR71XX_MAC_FIFO_RX_FILTMASK); rx_filtmask &= ~FIFO_RX_MASK_BYTE_MODE; switch(media) { case IFM_10_T: cfg |= MAC_CFG2_IFACE_MODE_10_100; if_speed = 10; break; case IFM_100_TX: cfg |= MAC_CFG2_IFACE_MODE_10_100; ifcontrol |= MAC_IFCONTROL_SPEED; if_speed = 100; break; case IFM_1000_T: case IFM_1000_SX: cfg |= MAC_CFG2_IFACE_MODE_1000; rx_filtmask |= FIFO_RX_MASK_BYTE_MODE; if_speed = 1000; break; default: if_speed = 100; device_printf(sc->arge_dev, "Unknown media %d\n", media); } ARGEDEBUG(sc, ARGE_DBG_PLL, "%s: if_speed=%d\n", __func__, if_speed); switch (ar71xx_soc) { case AR71XX_SOC_AR7240: case AR71XX_SOC_AR7241: case AR71XX_SOC_AR7242: case AR71XX_SOC_AR9330: case AR71XX_SOC_AR9331: case AR71XX_SOC_AR9341: case AR71XX_SOC_AR9342: case AR71XX_SOC_AR9344: case AR71XX_SOC_QCA9533: case AR71XX_SOC_QCA9533_V2: case AR71XX_SOC_QCA9556: case AR71XX_SOC_QCA9558: fifo_tx = 0x01f00140; break; case AR71XX_SOC_AR9130: case AR71XX_SOC_AR9132: fifo_tx = 0x00780fff; break; /* AR71xx */ default: fifo_tx = 0x008001ff; } ARGE_WRITE(sc, AR71XX_MAC_CFG2, cfg); ARGE_WRITE(sc, AR71XX_MAC_IFCONTROL, ifcontrol); ARGE_WRITE(sc, AR71XX_MAC_FIFO_RX_FILTMASK, rx_filtmask); ARGE_WRITE(sc, AR71XX_MAC_FIFO_TX_THRESHOLD, fifo_tx); /* fetch PLL registers */ pll = ar71xx_device_get_eth_pll(sc->arge_mac_unit, if_speed); ARGEDEBUG(sc, ARGE_DBG_PLL, "%s: pll=0x%x\n", __func__, pll); /* Override if required by platform data */ if (if_speed == 10 && sc->arge_pllcfg.pll_10 != 0) pll = sc->arge_pllcfg.pll_10; else if (if_speed == 100 && sc->arge_pllcfg.pll_100 != 0) pll = sc->arge_pllcfg.pll_100; else if (if_speed == 1000 && sc->arge_pllcfg.pll_1000 != 0) pll = sc->arge_pllcfg.pll_1000; ARGEDEBUG(sc, ARGE_DBG_PLL, "%s: final pll=0x%x\n", __func__, pll); /* XXX ensure pll != 0 */ ar71xx_device_set_pll_ge(sc->arge_mac_unit, if_speed, pll); /* set MII registers */ /* * This was introduced to match what the Linux ag71xx ethernet * driver does. For the AR71xx case, it does set the port * MII speed. However, if this is done, non-gigabit speeds * are not at all reliable when speaking via RGMII through * 'bridge' PHY port that's pretending to be a local PHY. * * Until that gets root caused, and until an AR71xx + normal * PHY board is tested, leave this disabled. */ #if 0 ar71xx_device_set_mii_speed(sc->arge_mac_unit, if_speed); #endif } static void arge_reset_dma(struct arge_softc *sc) { ARGEDEBUG(sc, ARGE_DBG_RESET, "%s: called\n", __func__); ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, 0); ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL, 0); ARGE_WRITE(sc, AR71XX_DMA_RX_DESC, 0); ARGE_WRITE(sc, AR71XX_DMA_TX_DESC, 0); /* Clear all possible RX interrupts */ while(ARGE_READ(sc, AR71XX_DMA_RX_STATUS) & DMA_RX_STATUS_PKT_RECVD) ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_PKT_RECVD); /* * Clear all possible TX interrupts */ while(ARGE_READ(sc, AR71XX_DMA_TX_STATUS) & DMA_TX_STATUS_PKT_SENT) ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_PKT_SENT); /* * Now Rx/Tx errors */ ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_BUS_ERROR | DMA_RX_STATUS_OVERFLOW); ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_BUS_ERROR | DMA_TX_STATUS_UNDERRUN); /* * Force a DDR flush so any pending data is properly * flushed to RAM before underlying buffers are freed. */ arge_flush_ddr(sc); } static void arge_init(void *xsc) { struct arge_softc *sc = xsc; ARGE_LOCK(sc); arge_init_locked(sc); ARGE_UNLOCK(sc); } static void arge_init_locked(struct arge_softc *sc) { struct ifnet *ifp = sc->arge_ifp; struct mii_data *mii; ARGE_LOCK_ASSERT(sc); if ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING)) return; /* Init circular RX list. */ if (arge_rx_ring_init(sc) != 0) { device_printf(sc->arge_dev, "initialization failed: no memory for rx buffers\n"); arge_stop(sc); return; } /* Init tx descriptors. */ arge_tx_ring_init(sc); arge_reset_dma(sc); if (sc->arge_miibus) { mii = device_get_softc(sc->arge_miibus); mii_mediachg(mii); } else { /* * Sun always shines over multiPHY interface */ sc->arge_link_status = 1; } ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; if (sc->arge_miibus) { callout_reset(&sc->arge_stat_callout, hz, arge_tick, sc); arge_update_link_locked(sc); } ARGE_WRITE(sc, AR71XX_DMA_TX_DESC, ARGE_TX_RING_ADDR(sc, 0)); ARGE_WRITE(sc, AR71XX_DMA_RX_DESC, ARGE_RX_RING_ADDR(sc, 0)); /* Start listening */ ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, DMA_RX_CONTROL_EN); /* Enable interrupts */ ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL); } /* * Return whether the mbuf chain is correctly aligned * for the arge TX engine. * * All the MACs have a length requirement: any non-final * fragment (ie, descriptor with MORE bit set) needs to have * a length divisible by 4. * * The AR71xx, AR913x require the start address also be * DWORD aligned. The later MACs don't. */ static int arge_mbuf_chain_is_tx_aligned(struct arge_softc *sc, struct mbuf *m0) { struct mbuf *m; for (m = m0; m != NULL; m = m->m_next) { /* * Only do this for chips that require it. */ if ((sc->arge_hw_flags & ARGE_HW_FLG_TX_DESC_ALIGN_4BYTE) && (mtod(m, intptr_t) & 3) != 0) { sc->stats.tx_pkts_unaligned_start++; return 0; } /* * All chips have this requirement for length. */ if ((m->m_next != NULL) && ((m->m_len & 0x03) != 0)) { sc->stats.tx_pkts_unaligned_len++; return 0; } } return 1; } /* * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data * pointers to the fragment pointers. */ static int arge_encap(struct arge_softc *sc, struct mbuf **m_head) { struct arge_txdesc *txd; struct arge_desc *desc, *prev_desc; bus_dma_segment_t txsegs[ARGE_MAXFRAGS]; int error, i, nsegs, prod, prev_prod; struct mbuf *m; ARGE_LOCK_ASSERT(sc); /* * Fix mbuf chain based on hardware alignment constraints. */ m = *m_head; if (! arge_mbuf_chain_is_tx_aligned(sc, m)) { sc->stats.tx_pkts_unaligned++; m = m_defrag(*m_head, M_NOWAIT); if (m == NULL) { m_freem(*m_head); *m_head = NULL; return (ENOBUFS); } *m_head = m; } else sc->stats.tx_pkts_aligned++; prod = sc->arge_cdata.arge_tx_prod; txd = &sc->arge_cdata.arge_txdesc[prod]; error = bus_dmamap_load_mbuf_sg(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT); if (error == EFBIG) { panic("EFBIG"); } else if (error != 0) return (error); if (nsegs == 0) { m_freem(*m_head); *m_head = NULL; return (EIO); } /* Check number of available descriptors. */ if (sc->arge_cdata.arge_tx_cnt + nsegs >= (ARGE_TX_RING_COUNT - 2)) { bus_dmamap_unload(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap); sc->stats.tx_pkts_nosegs++; return (ENOBUFS); } txd->tx_m = *m_head; bus_dmamap_sync(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap, BUS_DMASYNC_PREWRITE); /* * Make a list of descriptors for this packet. DMA controller will * walk through it while arge_link is not zero. * * Since we're in a endless circular buffer, ensure that * the first descriptor in a multi-descriptor ring is always * set to EMPTY, then un-do it when we're done populating. */ prev_prod = prod; desc = prev_desc = NULL; for (i = 0; i < nsegs; i++) { uint32_t tmp; desc = &sc->arge_rdata.arge_tx_ring[prod]; /* * Set DESC_EMPTY so the hardware (hopefully) stops at this * point. We don't want it to start transmitting descriptors * before we've finished fleshing this out. */ tmp = ARGE_DMASIZE(txsegs[i].ds_len); if (i == 0) tmp |= ARGE_DESC_EMPTY; desc->packet_ctrl = tmp; /* XXX Note: only relevant for older MACs; but check length! */ if ((sc->arge_hw_flags & ARGE_HW_FLG_TX_DESC_ALIGN_4BYTE) && (txsegs[i].ds_addr & 3)) panic("TX packet address unaligned\n"); desc->packet_addr = txsegs[i].ds_addr; /* link with previous descriptor */ if (prev_desc) prev_desc->packet_ctrl |= ARGE_DESC_MORE; sc->arge_cdata.arge_tx_cnt++; prev_desc = desc; ARGE_INC(prod, ARGE_TX_RING_COUNT); } /* Update producer index. */ sc->arge_cdata.arge_tx_prod = prod; /* * The descriptors are updated, so enable the first one. */ desc = &sc->arge_rdata.arge_tx_ring[prev_prod]; desc->packet_ctrl &= ~ ARGE_DESC_EMPTY; /* Sync descriptors. */ bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag, sc->arge_cdata.arge_tx_ring_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); /* Flush writes */ ARGE_BARRIER_WRITE(sc); /* Start transmitting */ ARGEDEBUG(sc, ARGE_DBG_TX, "%s: setting DMA_TX_CONTROL_EN\n", __func__); ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL, DMA_TX_CONTROL_EN); return (0); } static void arge_start(struct ifnet *ifp) { struct arge_softc *sc; sc = ifp->if_softc; ARGE_LOCK(sc); arge_start_locked(ifp); ARGE_UNLOCK(sc); } static void arge_start_locked(struct ifnet *ifp) { struct arge_softc *sc; struct mbuf *m_head; int enq = 0; sc = ifp->if_softc; ARGE_LOCK_ASSERT(sc); ARGEDEBUG(sc, ARGE_DBG_TX, "%s: beginning\n", __func__); if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING || sc->arge_link_status == 0 ) return; /* * Before we go any further, check whether we're already full. * The below check errors out immediately if the ring is full * and never gets a chance to set this flag. Although it's * likely never needed, this at least avoids an unexpected * situation. */ if (sc->arge_cdata.arge_tx_cnt >= ARGE_TX_RING_COUNT - 2) { ifp->if_drv_flags |= IFF_DRV_OACTIVE; ARGEDEBUG(sc, ARGE_DBG_ERR, "%s: tx_cnt %d >= max %d; setting IFF_DRV_OACTIVE\n", __func__, sc->arge_cdata.arge_tx_cnt, ARGE_TX_RING_COUNT - 2); return; } arge_flush_ddr(sc); for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) && sc->arge_cdata.arge_tx_cnt < ARGE_TX_RING_COUNT - 2; ) { IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); if (m_head == NULL) break; /* * Pack the data into the transmit ring. */ if (arge_encap(sc, &m_head)) { if (m_head == NULL) break; IFQ_DRV_PREPEND(&ifp->if_snd, m_head); ifp->if_drv_flags |= IFF_DRV_OACTIVE; break; } enq++; /* * If there's a BPF listener, bounce a copy of this frame * to him. */ ETHER_BPF_MTAP(ifp, m_head); } ARGEDEBUG(sc, ARGE_DBG_TX, "%s: finished; queued %d packets\n", __func__, enq); } static void arge_stop(struct arge_softc *sc) { struct ifnet *ifp; ARGE_LOCK_ASSERT(sc); ifp = sc->arge_ifp; ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); if (sc->arge_miibus) callout_stop(&sc->arge_stat_callout); /* mask out interrupts */ ARGE_WRITE(sc, AR71XX_DMA_INTR, 0); arge_reset_dma(sc); /* Flush FIFO and free any existing mbufs */ arge_flush_ddr(sc); arge_rx_ring_free(sc); arge_tx_ring_free(sc); } static int arge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) { struct arge_softc *sc = ifp->if_softc; struct ifreq *ifr = (struct ifreq *) data; struct mii_data *mii; int error; #ifdef DEVICE_POLLING int mask; #endif switch (command) { case SIOCSIFFLAGS: ARGE_LOCK(sc); if ((ifp->if_flags & IFF_UP) != 0) { if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { if (((ifp->if_flags ^ sc->arge_if_flags) & (IFF_PROMISC | IFF_ALLMULTI)) != 0) { /* XXX: handle promisc & multi flags */ } } else { if (!sc->arge_detach) arge_init_locked(sc); } } else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { ifp->if_drv_flags &= ~IFF_DRV_RUNNING; arge_stop(sc); } sc->arge_if_flags = ifp->if_flags; ARGE_UNLOCK(sc); error = 0; break; case SIOCADDMULTI: case SIOCDELMULTI: /* XXX: implement SIOCDELMULTI */ error = 0; break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: if (sc->arge_miibus) { mii = device_get_softc(sc->arge_miibus); error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); } else error = ifmedia_ioctl(ifp, ifr, &sc->arge_ifmedia, command); break; case SIOCSIFCAP: /* XXX: Check other capabilities */ #ifdef DEVICE_POLLING mask = ifp->if_capenable ^ ifr->ifr_reqcap; if (mask & IFCAP_POLLING) { if (ifr->ifr_reqcap & IFCAP_POLLING) { ARGE_WRITE(sc, AR71XX_DMA_INTR, 0); error = ether_poll_register(arge_poll, ifp); if (error) return error; ARGE_LOCK(sc); ifp->if_capenable |= IFCAP_POLLING; ARGE_UNLOCK(sc); } else { ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL); error = ether_poll_deregister(ifp); ARGE_LOCK(sc); ifp->if_capenable &= ~IFCAP_POLLING; ARGE_UNLOCK(sc); } } error = 0; break; #endif default: error = ether_ioctl(ifp, command, data); break; } return (error); } /* * Set media options. */ static int arge_ifmedia_upd(struct ifnet *ifp) { struct arge_softc *sc; struct mii_data *mii; struct mii_softc *miisc; int error; sc = ifp->if_softc; ARGE_LOCK(sc); mii = device_get_softc(sc->arge_miibus); LIST_FOREACH(miisc, &mii->mii_phys, mii_list) PHY_RESET(miisc); error = mii_mediachg(mii); ARGE_UNLOCK(sc); return (error); } /* * Report current media status. */ static void arge_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) { struct arge_softc *sc = ifp->if_softc; struct mii_data *mii; mii = device_get_softc(sc->arge_miibus); ARGE_LOCK(sc); mii_pollstat(mii); ifmr->ifm_active = mii->mii_media_active; ifmr->ifm_status = mii->mii_media_status; ARGE_UNLOCK(sc); } struct arge_dmamap_arg { bus_addr_t arge_busaddr; }; static void arge_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) { struct arge_dmamap_arg *ctx; if (error != 0) return; ctx = arg; ctx->arge_busaddr = segs[0].ds_addr; } static int arge_dma_alloc(struct arge_softc *sc) { struct arge_dmamap_arg ctx; struct arge_txdesc *txd; struct arge_rxdesc *rxd; int error, i; int arge_tx_align, arge_rx_align; /* Assume 4 byte alignment by default */ arge_tx_align = 4; arge_rx_align = 4; if (sc->arge_hw_flags & ARGE_HW_FLG_TX_DESC_ALIGN_1BYTE) arge_tx_align = 1; if (sc->arge_hw_flags & ARGE_HW_FLG_RX_DESC_ALIGN_1BYTE) arge_rx_align = 1; /* Create parent DMA tag. */ error = bus_dma_tag_create( bus_get_dma_tag(sc->arge_dev), /* parent */ 1, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 0, /* nsegments */ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->arge_cdata.arge_parent_tag); if (error != 0) { device_printf(sc->arge_dev, "failed to create parent DMA tag\n"); goto fail; } /* Create tag for Tx ring. */ error = bus_dma_tag_create( sc->arge_cdata.arge_parent_tag, /* parent */ ARGE_RING_ALIGN, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ ARGE_TX_DMA_SIZE, /* maxsize */ 1, /* nsegments */ ARGE_TX_DMA_SIZE, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->arge_cdata.arge_tx_ring_tag); if (error != 0) { device_printf(sc->arge_dev, "failed to create Tx ring DMA tag\n"); goto fail; } /* Create tag for Rx ring. */ error = bus_dma_tag_create( sc->arge_cdata.arge_parent_tag, /* parent */ ARGE_RING_ALIGN, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ ARGE_RX_DMA_SIZE, /* maxsize */ 1, /* nsegments */ ARGE_RX_DMA_SIZE, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->arge_cdata.arge_rx_ring_tag); if (error != 0) { device_printf(sc->arge_dev, "failed to create Rx ring DMA tag\n"); goto fail; } /* Create tag for Tx buffers. */ error = bus_dma_tag_create( sc->arge_cdata.arge_parent_tag, /* parent */ arge_tx_align, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ MCLBYTES * ARGE_MAXFRAGS, /* maxsize */ ARGE_MAXFRAGS, /* nsegments */ MCLBYTES, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->arge_cdata.arge_tx_tag); if (error != 0) { device_printf(sc->arge_dev, "failed to create Tx DMA tag\n"); goto fail; } /* Create tag for Rx buffers. */ error = bus_dma_tag_create( sc->arge_cdata.arge_parent_tag, /* parent */ arge_rx_align, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ MCLBYTES, /* maxsize */ ARGE_MAXFRAGS, /* nsegments */ MCLBYTES, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->arge_cdata.arge_rx_tag); if (error != 0) { device_printf(sc->arge_dev, "failed to create Rx DMA tag\n"); goto fail; } /* Allocate DMA'able memory and load the DMA map for Tx ring. */ error = bus_dmamem_alloc(sc->arge_cdata.arge_tx_ring_tag, (void **)&sc->arge_rdata.arge_tx_ring, BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->arge_cdata.arge_tx_ring_map); if (error != 0) { device_printf(sc->arge_dev, "failed to allocate DMA'able memory for Tx ring\n"); goto fail; } ctx.arge_busaddr = 0; error = bus_dmamap_load(sc->arge_cdata.arge_tx_ring_tag, sc->arge_cdata.arge_tx_ring_map, sc->arge_rdata.arge_tx_ring, ARGE_TX_DMA_SIZE, arge_dmamap_cb, &ctx, 0); if (error != 0 || ctx.arge_busaddr == 0) { device_printf(sc->arge_dev, "failed to load DMA'able memory for Tx ring\n"); goto fail; } sc->arge_rdata.arge_tx_ring_paddr = ctx.arge_busaddr; /* Allocate DMA'able memory and load the DMA map for Rx ring. */ error = bus_dmamem_alloc(sc->arge_cdata.arge_rx_ring_tag, (void **)&sc->arge_rdata.arge_rx_ring, BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->arge_cdata.arge_rx_ring_map); if (error != 0) { device_printf(sc->arge_dev, "failed to allocate DMA'able memory for Rx ring\n"); goto fail; } ctx.arge_busaddr = 0; error = bus_dmamap_load(sc->arge_cdata.arge_rx_ring_tag, sc->arge_cdata.arge_rx_ring_map, sc->arge_rdata.arge_rx_ring, ARGE_RX_DMA_SIZE, arge_dmamap_cb, &ctx, 0); if (error != 0 || ctx.arge_busaddr == 0) { device_printf(sc->arge_dev, "failed to load DMA'able memory for Rx ring\n"); goto fail; } sc->arge_rdata.arge_rx_ring_paddr = ctx.arge_busaddr; /* Create DMA maps for Tx buffers. */ for (i = 0; i < ARGE_TX_RING_COUNT; i++) { txd = &sc->arge_cdata.arge_txdesc[i]; txd->tx_m = NULL; txd->tx_dmamap = NULL; error = bus_dmamap_create(sc->arge_cdata.arge_tx_tag, 0, &txd->tx_dmamap); if (error != 0) { device_printf(sc->arge_dev, "failed to create Tx dmamap\n"); goto fail; } } /* Create DMA maps for Rx buffers. */ if ((error = bus_dmamap_create(sc->arge_cdata.arge_rx_tag, 0, &sc->arge_cdata.arge_rx_sparemap)) != 0) { device_printf(sc->arge_dev, "failed to create spare Rx dmamap\n"); goto fail; } for (i = 0; i < ARGE_RX_RING_COUNT; i++) { rxd = &sc->arge_cdata.arge_rxdesc[i]; rxd->rx_m = NULL; rxd->rx_dmamap = NULL; error = bus_dmamap_create(sc->arge_cdata.arge_rx_tag, 0, &rxd->rx_dmamap); if (error != 0) { device_printf(sc->arge_dev, "failed to create Rx dmamap\n"); goto fail; } } fail: return (error); } static void arge_dma_free(struct arge_softc *sc) { struct arge_txdesc *txd; struct arge_rxdesc *rxd; int i; /* Tx ring. */ if (sc->arge_cdata.arge_tx_ring_tag) { if (sc->arge_rdata.arge_tx_ring_paddr) bus_dmamap_unload(sc->arge_cdata.arge_tx_ring_tag, sc->arge_cdata.arge_tx_ring_map); if (sc->arge_rdata.arge_tx_ring) bus_dmamem_free(sc->arge_cdata.arge_tx_ring_tag, sc->arge_rdata.arge_tx_ring, sc->arge_cdata.arge_tx_ring_map); sc->arge_rdata.arge_tx_ring = NULL; sc->arge_rdata.arge_tx_ring_paddr = 0; bus_dma_tag_destroy(sc->arge_cdata.arge_tx_ring_tag); sc->arge_cdata.arge_tx_ring_tag = NULL; } /* Rx ring. */ if (sc->arge_cdata.arge_rx_ring_tag) { if (sc->arge_rdata.arge_rx_ring_paddr) bus_dmamap_unload(sc->arge_cdata.arge_rx_ring_tag, sc->arge_cdata.arge_rx_ring_map); if (sc->arge_rdata.arge_rx_ring) bus_dmamem_free(sc->arge_cdata.arge_rx_ring_tag, sc->arge_rdata.arge_rx_ring, sc->arge_cdata.arge_rx_ring_map); sc->arge_rdata.arge_rx_ring = NULL; sc->arge_rdata.arge_rx_ring_paddr = 0; bus_dma_tag_destroy(sc->arge_cdata.arge_rx_ring_tag); sc->arge_cdata.arge_rx_ring_tag = NULL; } /* Tx buffers. */ if (sc->arge_cdata.arge_tx_tag) { for (i = 0; i < ARGE_TX_RING_COUNT; i++) { txd = &sc->arge_cdata.arge_txdesc[i]; if (txd->tx_dmamap) { bus_dmamap_destroy(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap); txd->tx_dmamap = NULL; } } bus_dma_tag_destroy(sc->arge_cdata.arge_tx_tag); sc->arge_cdata.arge_tx_tag = NULL; } /* Rx buffers. */ if (sc->arge_cdata.arge_rx_tag) { for (i = 0; i < ARGE_RX_RING_COUNT; i++) { rxd = &sc->arge_cdata.arge_rxdesc[i]; if (rxd->rx_dmamap) { bus_dmamap_destroy(sc->arge_cdata.arge_rx_tag, rxd->rx_dmamap); rxd->rx_dmamap = NULL; } } if (sc->arge_cdata.arge_rx_sparemap) { bus_dmamap_destroy(sc->arge_cdata.arge_rx_tag, sc->arge_cdata.arge_rx_sparemap); sc->arge_cdata.arge_rx_sparemap = 0; } bus_dma_tag_destroy(sc->arge_cdata.arge_rx_tag); sc->arge_cdata.arge_rx_tag = NULL; } if (sc->arge_cdata.arge_parent_tag) { bus_dma_tag_destroy(sc->arge_cdata.arge_parent_tag); sc->arge_cdata.arge_parent_tag = NULL; } } /* * Initialize the transmit descriptors. */ static int arge_tx_ring_init(struct arge_softc *sc) { struct arge_ring_data *rd; struct arge_txdesc *txd; bus_addr_t addr; int i; sc->arge_cdata.arge_tx_prod = 0; sc->arge_cdata.arge_tx_cons = 0; sc->arge_cdata.arge_tx_cnt = 0; rd = &sc->arge_rdata; bzero(rd->arge_tx_ring, sizeof(*rd->arge_tx_ring)); for (i = 0; i < ARGE_TX_RING_COUNT; i++) { if (i == ARGE_TX_RING_COUNT - 1) addr = ARGE_TX_RING_ADDR(sc, 0); else addr = ARGE_TX_RING_ADDR(sc, i + 1); rd->arge_tx_ring[i].packet_ctrl = ARGE_DESC_EMPTY; rd->arge_tx_ring[i].next_desc = addr; txd = &sc->arge_cdata.arge_txdesc[i]; txd->tx_m = NULL; } bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag, sc->arge_cdata.arge_tx_ring_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); return (0); } /* * Free the Tx ring, unload any pending dma transaction and free the mbuf. */ static void arge_tx_ring_free(struct arge_softc *sc) { struct arge_txdesc *txd; int i; /* Free the Tx buffers. */ for (i = 0; i < ARGE_TX_RING_COUNT; i++) { txd = &sc->arge_cdata.arge_txdesc[i]; if (txd->tx_dmamap) { bus_dmamap_sync(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap); } if (txd->tx_m) m_freem(txd->tx_m); txd->tx_m = NULL; } } /* * Initialize the RX descriptors and allocate mbufs for them. Note that * we arrange the descriptors in a closed ring, so that the last descriptor * points back to the first. */ static int arge_rx_ring_init(struct arge_softc *sc) { struct arge_ring_data *rd; struct arge_rxdesc *rxd; bus_addr_t addr; int i; sc->arge_cdata.arge_rx_cons = 0; rd = &sc->arge_rdata; bzero(rd->arge_rx_ring, sizeof(*rd->arge_rx_ring)); for (i = 0; i < ARGE_RX_RING_COUNT; i++) { rxd = &sc->arge_cdata.arge_rxdesc[i]; if (rxd->rx_m != NULL) { device_printf(sc->arge_dev, "%s: ring[%d] rx_m wasn't free?\n", __func__, i); } rxd->rx_m = NULL; rxd->desc = &rd->arge_rx_ring[i]; if (i == ARGE_RX_RING_COUNT - 1) addr = ARGE_RX_RING_ADDR(sc, 0); else addr = ARGE_RX_RING_ADDR(sc, i + 1); rd->arge_rx_ring[i].next_desc = addr; if (arge_newbuf(sc, i) != 0) { return (ENOBUFS); } } bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag, sc->arge_cdata.arge_rx_ring_map, BUS_DMASYNC_PREWRITE); return (0); } /* * Free all the buffers in the RX ring. * * TODO: ensure that DMA is disabled and no pending DMA * is lurking in the FIFO. */ static void arge_rx_ring_free(struct arge_softc *sc) { int i; struct arge_rxdesc *rxd; ARGE_LOCK_ASSERT(sc); for (i = 0; i < ARGE_RX_RING_COUNT; i++) { rxd = &sc->arge_cdata.arge_rxdesc[i]; /* Unmap the mbuf */ if (rxd->rx_m != NULL) { bus_dmamap_unload(sc->arge_cdata.arge_rx_tag, rxd->rx_dmamap); m_free(rxd->rx_m); rxd->rx_m = NULL; } } } /* * Initialize an RX descriptor and attach an MBUF cluster. */ static int arge_newbuf(struct arge_softc *sc, int idx) { struct arge_desc *desc; struct arge_rxdesc *rxd; struct mbuf *m; bus_dma_segment_t segs[1]; bus_dmamap_t map; int nsegs; /* XXX TODO: should just allocate an explicit 2KiB buffer */ m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (m == NULL) return (ENOBUFS); m->m_len = m->m_pkthdr.len = MCLBYTES; /* * Add extra space to "adjust" (copy) the packet back to be aligned * for purposes of IPv4/IPv6 header contents. */ if (sc->arge_hw_flags & ARGE_HW_FLG_RX_DESC_ALIGN_4BYTE) m_adj(m, sizeof(uint64_t)); /* * If it's a 1-byte aligned buffer, then just offset it two bytes * and that will give us a hopefully correctly DWORD aligned * L3 payload - and we won't have to undo it afterwards. */ else if (sc->arge_hw_flags & ARGE_HW_FLG_RX_DESC_ALIGN_1BYTE) m_adj(m, sizeof(uint16_t)); if (bus_dmamap_load_mbuf_sg(sc->arge_cdata.arge_rx_tag, sc->arge_cdata.arge_rx_sparemap, m, segs, &nsegs, 0) != 0) { m_freem(m); return (ENOBUFS); } KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); rxd = &sc->arge_cdata.arge_rxdesc[idx]; if (rxd->rx_m != NULL) { bus_dmamap_unload(sc->arge_cdata.arge_rx_tag, rxd->rx_dmamap); } map = rxd->rx_dmamap; rxd->rx_dmamap = sc->arge_cdata.arge_rx_sparemap; sc->arge_cdata.arge_rx_sparemap = map; rxd->rx_m = m; desc = rxd->desc; if ((sc->arge_hw_flags & ARGE_HW_FLG_RX_DESC_ALIGN_4BYTE) && segs[0].ds_addr & 3) panic("RX packet address unaligned"); desc->packet_addr = segs[0].ds_addr; desc->packet_ctrl = ARGE_DESC_EMPTY | ARGE_DMASIZE(segs[0].ds_len); bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag, sc->arge_cdata.arge_rx_ring_map, BUS_DMASYNC_PREWRITE); return (0); } /* * Move the data backwards 16 bits to (hopefully!) ensure the * IPv4/IPv6 payload is aligned. * * This is required for earlier hardware where the RX path * requires DWORD aligned buffers. */ static __inline void arge_fixup_rx(struct mbuf *m) { int i; uint16_t *src, *dst; src = mtod(m, uint16_t *); dst = src - 1; for (i = 0; i < m->m_len / sizeof(uint16_t); i++) { *dst++ = *src++; } if (m->m_len % sizeof(uint16_t)) *(uint8_t *)dst = *(uint8_t *)src; m->m_data -= ETHER_ALIGN; } #ifdef DEVICE_POLLING static int arge_poll(struct ifnet *ifp, enum poll_cmd cmd, int count) { struct arge_softc *sc = ifp->if_softc; int rx_npkts = 0; if (ifp->if_drv_flags & IFF_DRV_RUNNING) { ARGE_LOCK(sc); arge_tx_locked(sc); rx_npkts = arge_rx_locked(sc); ARGE_UNLOCK(sc); } return (rx_npkts); } #endif /* DEVICE_POLLING */ static void arge_tx_locked(struct arge_softc *sc) { struct arge_txdesc *txd; struct arge_desc *cur_tx; struct ifnet *ifp; uint32_t ctrl; int cons, prod; ARGE_LOCK_ASSERT(sc); cons = sc->arge_cdata.arge_tx_cons; prod = sc->arge_cdata.arge_tx_prod; ARGEDEBUG(sc, ARGE_DBG_TX, "%s: cons=%d, prod=%d\n", __func__, cons, prod); if (cons == prod) return; bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag, sc->arge_cdata.arge_tx_ring_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); ifp = sc->arge_ifp; /* * Go through our tx list and free mbufs for those * frames that have been transmitted. */ for (; cons != prod; ARGE_INC(cons, ARGE_TX_RING_COUNT)) { cur_tx = &sc->arge_rdata.arge_tx_ring[cons]; ctrl = cur_tx->packet_ctrl; /* Check if descriptor has "finished" flag */ if ((ctrl & ARGE_DESC_EMPTY) == 0) break; ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_PKT_SENT); sc->arge_cdata.arge_tx_cnt--; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; txd = &sc->arge_cdata.arge_txdesc[cons]; if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); bus_dmamap_sync(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->arge_cdata.arge_tx_tag, txd->tx_dmamap); /* Free only if it's first descriptor in list */ if (txd->tx_m) m_freem(txd->tx_m); txd->tx_m = NULL; /* reset descriptor */ cur_tx->packet_addr = 0; } sc->arge_cdata.arge_tx_cons = cons; bus_dmamap_sync(sc->arge_cdata.arge_tx_ring_tag, sc->arge_cdata.arge_tx_ring_map, BUS_DMASYNC_PREWRITE); } static int arge_rx_locked(struct arge_softc *sc) { struct arge_rxdesc *rxd; struct ifnet *ifp = sc->arge_ifp; int cons, prog, packet_len, i; struct arge_desc *cur_rx; struct mbuf *m; int rx_npkts = 0; ARGE_LOCK_ASSERT(sc); cons = sc->arge_cdata.arge_rx_cons; bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag, sc->arge_cdata.arge_rx_ring_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); for (prog = 0; prog < ARGE_RX_RING_COUNT; ARGE_INC(cons, ARGE_RX_RING_COUNT)) { cur_rx = &sc->arge_rdata.arge_rx_ring[cons]; rxd = &sc->arge_cdata.arge_rxdesc[cons]; m = rxd->rx_m; if ((cur_rx->packet_ctrl & ARGE_DESC_EMPTY) != 0) break; ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_PKT_RECVD); prog++; packet_len = ARGE_DMASIZE(cur_rx->packet_ctrl); bus_dmamap_sync(sc->arge_cdata.arge_rx_tag, rxd->rx_dmamap, BUS_DMASYNC_POSTREAD); m = rxd->rx_m; /* * If the MAC requires 4 byte alignment then the RX setup * routine will have pre-offset things; so un-offset it here. */ if (sc->arge_hw_flags & ARGE_HW_FLG_RX_DESC_ALIGN_4BYTE) arge_fixup_rx(m); m->m_pkthdr.rcvif = ifp; /* Skip 4 bytes of CRC */ m->m_pkthdr.len = m->m_len = packet_len - ETHER_CRC_LEN; if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); rx_npkts++; ARGE_UNLOCK(sc); (*ifp->if_input)(ifp, m); ARGE_LOCK(sc); cur_rx->packet_addr = 0; } if (prog > 0) { i = sc->arge_cdata.arge_rx_cons; for (; prog > 0 ; prog--) { if (arge_newbuf(sc, i) != 0) { device_printf(sc->arge_dev, "Failed to allocate buffer\n"); break; } ARGE_INC(i, ARGE_RX_RING_COUNT); } bus_dmamap_sync(sc->arge_cdata.arge_rx_ring_tag, sc->arge_cdata.arge_rx_ring_map, BUS_DMASYNC_PREWRITE); sc->arge_cdata.arge_rx_cons = cons; } return (rx_npkts); } static int arge_intr_filter(void *arg) { struct arge_softc *sc = arg; uint32_t status, ints; status = ARGE_READ(sc, AR71XX_DMA_INTR_STATUS); ints = ARGE_READ(sc, AR71XX_DMA_INTR); ARGEDEBUG(sc, ARGE_DBG_INTR, "int mask(filter) = %b\n", ints, "\20\10RX_BUS_ERROR\7RX_OVERFLOW\5RX_PKT_RCVD" "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT"); ARGEDEBUG(sc, ARGE_DBG_INTR, "status(filter) = %b\n", status, "\20\10RX_BUS_ERROR\7RX_OVERFLOW\5RX_PKT_RCVD" "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT"); if (status & DMA_INTR_ALL) { sc->arge_intr_status |= status; ARGE_WRITE(sc, AR71XX_DMA_INTR, 0); sc->stats.intr_ok++; return (FILTER_SCHEDULE_THREAD); } sc->arge_intr_status = 0; sc->stats.intr_stray++; return (FILTER_STRAY); } static void arge_intr(void *arg) { struct arge_softc *sc = arg; uint32_t status; struct ifnet *ifp = sc->arge_ifp; #ifdef ARGE_DEBUG int i; #endif status = ARGE_READ(sc, AR71XX_DMA_INTR_STATUS); status |= sc->arge_intr_status; ARGEDEBUG(sc, ARGE_DBG_INTR, "int status(intr) = %b\n", status, "\20\10\7RX_OVERFLOW\5RX_PKT_RCVD" "\4TX_BUS_ERROR\2TX_UNDERRUN\1TX_PKT_SENT"); /* * Is it our interrupt at all? */ if (status == 0) { sc->stats.intr_stray2++; return; } #ifdef ARGE_DEBUG for (i = 0; i < 32; i++) { if (status & (1U << i)) { sc->intr_stats.count[i]++; } } #endif if (status & DMA_INTR_RX_BUS_ERROR) { ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_BUS_ERROR); device_printf(sc->arge_dev, "RX bus error"); return; } if (status & DMA_INTR_TX_BUS_ERROR) { ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_BUS_ERROR); device_printf(sc->arge_dev, "TX bus error"); return; } ARGE_LOCK(sc); arge_flush_ddr(sc); if (status & DMA_INTR_RX_PKT_RCVD) arge_rx_locked(sc); /* * RX overrun disables the receiver. * Clear indication and re-enable rx. */ if ( status & DMA_INTR_RX_OVERFLOW) { ARGE_WRITE(sc, AR71XX_DMA_RX_STATUS, DMA_RX_STATUS_OVERFLOW); ARGE_WRITE(sc, AR71XX_DMA_RX_CONTROL, DMA_RX_CONTROL_EN); sc->stats.rx_overflow++; } if (status & DMA_INTR_TX_PKT_SENT) arge_tx_locked(sc); /* * Underrun turns off TX. Clear underrun indication. * If there's anything left in the ring, reactivate the tx. */ if (status & DMA_INTR_TX_UNDERRUN) { ARGE_WRITE(sc, AR71XX_DMA_TX_STATUS, DMA_TX_STATUS_UNDERRUN); sc->stats.tx_underflow++; ARGEDEBUG(sc, ARGE_DBG_TX, "%s: TX underrun; tx_cnt=%d\n", __func__, sc->arge_cdata.arge_tx_cnt); if (sc->arge_cdata.arge_tx_cnt > 0 ) { ARGE_WRITE(sc, AR71XX_DMA_TX_CONTROL, DMA_TX_CONTROL_EN); } } /* * If we've finished TXing and there's space for more packets * to be queued for TX, do so. Otherwise we may end up in a * situation where the interface send queue was filled * whilst the hardware queue was full, then the hardware * queue was drained by the interface send queue wasn't, * and thus if_start() is never called to kick-start * the send process (and all subsequent packets are simply * discarded. * * XXX TODO: make sure that the hardware deals nicely * with the possibility of the queue being enabled above * after a TX underrun, then having the hardware queue added * to below. */ if (status & (DMA_INTR_TX_PKT_SENT | DMA_INTR_TX_UNDERRUN) && (ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) { if (!IFQ_IS_EMPTY(&ifp->if_snd)) arge_start_locked(ifp); } /* * We handled all bits, clear status */ sc->arge_intr_status = 0; ARGE_UNLOCK(sc); /* * re-enable all interrupts */ ARGE_WRITE(sc, AR71XX_DMA_INTR, DMA_INTR_ALL); } static void arge_tick(void *xsc) { struct arge_softc *sc = xsc; struct mii_data *mii; ARGE_LOCK_ASSERT(sc); if (sc->arge_miibus) { mii = device_get_softc(sc->arge_miibus); mii_tick(mii); callout_reset(&sc->arge_stat_callout, hz, arge_tick, sc); } } int arge_multiphy_mediachange(struct ifnet *ifp) { struct arge_softc *sc = ifp->if_softc; struct ifmedia *ifm = &sc->arge_ifmedia; struct ifmedia_entry *ife = ifm->ifm_cur; if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) return (EINVAL); if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { device_printf(sc->arge_dev, "AUTO is not supported for multiphy MAC"); return (EINVAL); } /* * Ignore everything */ return (0); } void arge_multiphy_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) { struct arge_softc *sc = ifp->if_softc; ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; ifmr->ifm_active = IFM_ETHER | sc->arge_media_type | sc->arge_duplex_mode; } #if defined(ARGE_MDIO) static int argemdio_probe(device_t dev) { device_set_desc(dev, "Atheros AR71xx built-in ethernet interface, MDIO controller"); return (0); } static int argemdio_attach(device_t dev) { struct arge_softc *sc; int error = 0; #ifdef ARGE_DEBUG struct sysctl_ctx_list *ctx; struct sysctl_oid *tree; #endif sc = device_get_softc(dev); sc->arge_dev = dev; sc->arge_mac_unit = device_get_unit(dev); sc->arge_rid = 0; sc->arge_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->arge_rid, RF_ACTIVE | RF_SHAREABLE); if (sc->arge_res == NULL) { device_printf(dev, "couldn't map memory\n"); error = ENXIO; goto fail; } #ifdef ARGE_DEBUG ctx = device_get_sysctl_ctx(dev); tree = device_get_sysctl_tree(dev); SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "debug", CTLFLAG_RW, &sc->arge_debug, 0, "argemdio interface debugging flags"); #endif /* Reset MAC - required for AR71xx MDIO to successfully occur */ arge_reset_mac(sc); /* Reset MII bus */ arge_reset_miibus(sc); bus_generic_probe(dev); bus_enumerate_hinted_children(dev); error = bus_generic_attach(dev); fail: return (error); } static int argemdio_detach(device_t dev) { return (0); } #endif Index: head/sys/mips/atheros/if_argevar.h =================================================================== --- head/sys/mips/atheros/if_argevar.h (revision 326258) +++ head/sys/mips/atheros/if_argevar.h (revision 326259) @@ -1,220 +1,222 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009, Oleksandr Tymoshenko * 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 unmodified, 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$ */ #ifndef __IF_ARGEVAR_H__ #define __IF_ARGEVAR_H__ #define ARGE_NPHY 32 #define ARGE_TX_RING_COUNT 128 #define ARGE_RX_RING_COUNT 128 #define ARGE_RX_DMA_SIZE ARGE_RX_RING_COUNT * sizeof(struct arge_desc) #define ARGE_TX_DMA_SIZE ARGE_TX_RING_COUNT * sizeof(struct arge_desc) #define ARGE_MAXFRAGS 8 #define ARGE_RING_ALIGN sizeof(struct arge_desc) #define ARGE_RX_ALIGN_4BYTE sizeof(uint32_t) #define ARGE_RX_ALIGN_1BYTE sizeof(char) #define ARGE_TX_ALIGN_4BYTE sizeof(uint32_t) #define ARGE_TX_ALIGN_1BYTE sizeof(char) #define ARGE_MAXFRAGS 8 #define ARGE_TX_RING_ADDR(sc, i) \ ((sc)->arge_rdata.arge_tx_ring_paddr + sizeof(struct arge_desc) * (i)) #define ARGE_RX_RING_ADDR(sc, i) \ ((sc)->arge_rdata.arge_rx_ring_paddr + sizeof(struct arge_desc) * (i)) #define ARGE_INC(x,y) (x) = (((x) + 1) % y) #define ARGE_MII_TIMEOUT 1000 #define ARGE_LOCK(_sc) mtx_lock(&(_sc)->arge_mtx) #define ARGE_UNLOCK(_sc) mtx_unlock(&(_sc)->arge_mtx) #define ARGE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->arge_mtx, MA_OWNED) /* * register space access macros */ #define ARGE_BARRIER_READ(sc) bus_barrier(sc->arge_res, 0, 0, \ BUS_SPACE_BARRIER_READ) #define ARGE_BARRIER_WRITE(sc) bus_barrier(sc->arge_res, 0, 0, \ BUS_SPACE_BARRIER_WRITE) #define ARGE_BARRIER_RW(sc) bus_barrier(sc->arge_res, 0, 0, \ BUS_SPACE_BARRIER_READ | \ BUS_SPACE_BARRIER_WRITE) #define ARGE_WRITE(sc, reg, val) do { \ bus_write_4(sc->arge_res, (reg), (val)); \ ARGE_BARRIER_WRITE((sc)); \ ARGE_READ((sc), (reg)); \ } while (0) #define ARGE_READ(sc, reg) bus_read_4(sc->arge_res, (reg)) #define ARGE_SET_BITS(sc, reg, bits) \ ARGE_WRITE(sc, reg, ARGE_READ(sc, (reg)) | (bits)) #define ARGE_CLEAR_BITS(sc, reg, bits) \ ARGE_WRITE(sc, reg, ARGE_READ(sc, (reg)) & ~(bits)) /* * The linux driver code for the MDIO bus does a read-after-write * which seems to be required on MIPS74k platforms for correct * behaviour. * * So, ARGE_WRITE() does the write + barrier, and the following * ARGE_READ() seems to flush the thing all the way through the device * FIFO(s) before we continue issuing MDIO bus updates. */ #define ARGE_MDIO_WRITE(_sc, _reg, _val) \ ARGE_WRITE((_sc), (_reg), (_val)) #define ARGE_MDIO_READ(_sc, _reg) \ ARGE_READ((_sc), (_reg)) #define ARGE_MDIO_BARRIER_READ(_sc) ARGE_BARRIER_READ(_sc) #define ARGE_MDIO_BARRIER_WRITE(_sc) ARGE_BARRIER_WRITE(_sc) #define ARGE_MDIO_BARRIER_RW(_sc) ARGE_BARRIER_RW(_sc) #define ARGE_DESC_EMPTY (1U << 31) #define ARGE_DESC_MORE (1 << 24) #define ARGE_DESC_SIZE_MASK ((1 << 12) - 1) #define ARGE_DMASIZE(len) ((len) & ARGE_DESC_SIZE_MASK) struct arge_desc { uint32_t packet_addr; uint32_t packet_ctrl; uint32_t next_desc; uint32_t padding; }; struct arge_txdesc { struct mbuf *tx_m; bus_dmamap_t tx_dmamap; }; struct arge_rxdesc { struct mbuf *rx_m; bus_dmamap_t rx_dmamap; struct arge_desc *desc; }; struct arge_chain_data { bus_dma_tag_t arge_parent_tag; bus_dma_tag_t arge_tx_tag; struct arge_txdesc arge_txdesc[ARGE_TX_RING_COUNT]; bus_dma_tag_t arge_rx_tag; struct arge_rxdesc arge_rxdesc[ARGE_RX_RING_COUNT]; bus_dma_tag_t arge_tx_ring_tag; bus_dma_tag_t arge_rx_ring_tag; bus_dmamap_t arge_tx_ring_map; bus_dmamap_t arge_rx_ring_map; bus_dmamap_t arge_rx_sparemap; int arge_tx_prod; int arge_tx_cons; int arge_tx_cnt; int arge_rx_cons; }; struct arge_ring_data { struct arge_desc *arge_rx_ring; struct arge_desc *arge_tx_ring; bus_addr_t arge_rx_ring_paddr; bus_addr_t arge_tx_ring_paddr; }; /* * Allow PLL values to be overridden. */ struct arge_pll_data { uint32_t pll_10; uint32_t pll_100; uint32_t pll_1000; }; /* * Hardware specific behaviours. */ /* * Older chips support 4 byte only transmit and receive * addresses. * * Later chips support arbitrary TX and later later, * arbitrary RX addresses. */ #define ARGE_HW_FLG_TX_DESC_ALIGN_4BYTE 0x00000001 #define ARGE_HW_FLG_RX_DESC_ALIGN_4BYTE 0x00000002 #define ARGE_HW_FLG_TX_DESC_ALIGN_1BYTE 0x00000004 #define ARGE_HW_FLG_RX_DESC_ALIGN_1BYTE 0x00000008 struct arge_softc { struct ifnet *arge_ifp; /* interface info */ device_t arge_dev; struct ifmedia arge_ifmedia; /* * Media & duples settings for multiPHY MAC */ uint32_t arge_media_type; uint32_t arge_duplex_mode; uint32_t arge_phymask; uint8_t arge_eaddr[ETHER_ADDR_LEN]; struct resource *arge_res; int arge_rid; struct resource *arge_irq; void *arge_intrhand; device_t arge_miibus; device_t arge_miiproxy; ar71xx_mii_mode arge_miicfg; struct arge_pll_data arge_pllcfg; bus_dma_tag_t arge_parent_tag; bus_dma_tag_t arge_tag; struct mtx arge_mtx; struct callout arge_stat_callout; struct task arge_link_task; struct arge_chain_data arge_cdata; struct arge_ring_data arge_rdata; int arge_link_status; int arge_detach; uint32_t arge_intr_status; int arge_mac_unit; int arge_if_flags; uint32_t arge_hw_flags; uint32_t arge_debug; uint32_t arge_mdiofreq; struct { uint32_t tx_pkts_unaligned; uint32_t tx_pkts_unaligned_start; uint32_t tx_pkts_unaligned_len; uint32_t tx_pkts_nosegs; uint32_t tx_pkts_aligned; uint32_t rx_overflow; uint32_t tx_underflow; uint32_t intr_stray; uint32_t intr_stray2; uint32_t intr_ok; } stats; struct { uint32_t count[32]; } intr_stats; }; #endif /* __IF_ARGEVAR_H__ */ Index: head/sys/mips/atheros/pcf2123_rtc.c =================================================================== --- head/sys/mips/atheros/pcf2123_rtc.c (revision 326258) +++ head/sys/mips/atheros/pcf2123_rtc.c (revision 326259) @@ -1,204 +1,206 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010, Oleksandr Tymoshenko * 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 unmodified, 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 "spibus_if.h" #include "clock_if.h" #define YEAR_BASE 1970 #define PCF2123_DELAY 50 struct pcf2123_rtc_softc { device_t dev; }; static int pcf2123_rtc_probe(device_t dev); static int pcf2123_rtc_attach(device_t dev); static int pcf2123_rtc_gettime(device_t dev, struct timespec *ts); static int pcf2123_rtc_settime(device_t dev, struct timespec *ts); static int pcf2123_rtc_probe(device_t dev) { device_set_desc(dev, "PCF2123 SPI RTC"); return (0); } static int pcf2123_rtc_attach(device_t dev) { struct pcf2123_rtc_softc *sc; struct spi_command cmd; unsigned char rxBuf[3]; unsigned char txBuf[3]; int err; sc = device_get_softc(dev); sc->dev = dev; clock_register(dev, 1000000); memset(&cmd, 0, sizeof(cmd)); memset(rxBuf, 0, sizeof(rxBuf)); memset(txBuf, 0, sizeof(txBuf)); /* Make sure Ctrl1 and Ctrl2 are zeroes */ txBuf[0] = PCF2123_WRITE(PCF2123_REG_CTRL1); cmd.rx_cmd = rxBuf; cmd.tx_cmd = txBuf; cmd.rx_cmd_sz = sizeof(rxBuf); cmd.tx_cmd_sz = sizeof(txBuf); err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &cmd); DELAY(PCF2123_DELAY); return (0); } static int pcf2123_rtc_gettime(device_t dev, struct timespec *ts) { struct clocktime ct; struct spi_command cmd; unsigned char rxTimedate[8]; unsigned char txTimedate[8]; int err; memset(&cmd, 0, sizeof(cmd)); memset(rxTimedate, 0, sizeof(rxTimedate)); memset(txTimedate, 0, sizeof(txTimedate)); /* * Counter is stopped when access to time registers is in progress * So there is no need to stop/start counter */ /* Start reading from seconds */ txTimedate[0] = PCF2123_READ(PCF2123_REG_SECONDS); cmd.rx_cmd = rxTimedate; cmd.tx_cmd = txTimedate; cmd.rx_cmd_sz = sizeof(rxTimedate); cmd.tx_cmd_sz = sizeof(txTimedate); err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &cmd); DELAY(PCF2123_DELAY); ct.nsec = 0; ct.sec = FROMBCD(rxTimedate[1] & 0x7f); ct.min = FROMBCD(rxTimedate[2] & 0x7f); ct.hour = FROMBCD(rxTimedate[3] & 0x3f); ct.dow = FROMBCD(rxTimedate[5] & 0x3f); ct.day = FROMBCD(rxTimedate[4] & 0x3f); ct.mon = FROMBCD(rxTimedate[6] & 0x1f); ct.year = YEAR_BASE + FROMBCD(rxTimedate[7]); return (clock_ct_to_ts(&ct, ts)); } static int pcf2123_rtc_settime(device_t dev, struct timespec *ts) { struct clocktime ct; struct pcf2123_rtc_softc *sc; struct spi_command cmd; unsigned char rxTimedate[8]; unsigned char txTimedate[8]; int err; sc = device_get_softc(dev); /* Resolution: 1 sec */ if (ts->tv_nsec >= 500000000) ts->tv_sec++; ts->tv_nsec = 0; clock_ts_to_ct(ts, &ct); memset(&cmd, 0, sizeof(cmd)); memset(rxTimedate, 0, sizeof(rxTimedate)); memset(txTimedate, 0, sizeof(txTimedate)); /* Start reading from seconds */ cmd.rx_cmd = rxTimedate; cmd.tx_cmd = txTimedate; cmd.rx_cmd_sz = sizeof(rxTimedate); cmd.tx_cmd_sz = sizeof(txTimedate); /* * Counter is stopped when access to time registers is in progress * So there is no need to stop/start counter */ txTimedate[0] = PCF2123_WRITE(PCF2123_REG_SECONDS); txTimedate[1] = TOBCD(ct.sec); txTimedate[2] = TOBCD(ct.min); txTimedate[3] = TOBCD(ct.hour); txTimedate[4] = TOBCD(ct.day); txTimedate[5] = TOBCD(ct.dow); txTimedate[6] = TOBCD(ct.mon); txTimedate[7] = TOBCD(ct.year - YEAR_BASE); err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &cmd); DELAY(PCF2123_DELAY); return (err); } static device_method_t pcf2123_rtc_methods[] = { DEVMETHOD(device_probe, pcf2123_rtc_probe), DEVMETHOD(device_attach, pcf2123_rtc_attach), DEVMETHOD(clock_gettime, pcf2123_rtc_gettime), DEVMETHOD(clock_settime, pcf2123_rtc_settime), { 0, 0 }, }; static driver_t pcf2123_rtc_driver = { "rtc", pcf2123_rtc_methods, sizeof(struct pcf2123_rtc_softc), }; static devclass_t pcf2123_rtc_devclass; DRIVER_MODULE(pcf2123_rtc, spibus, pcf2123_rtc_driver, pcf2123_rtc_devclass, 0, 0); Index: head/sys/mips/atheros/pcf2123reg.h =================================================================== --- head/sys/mips/atheros/pcf2123reg.h (revision 326258) +++ head/sys/mips/atheros/pcf2123reg.h (revision 326259) @@ -1,67 +1,69 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009, Oleksandr Tymoshenko * 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 unmodified, 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$ */ #ifndef __PCF2123REG_H__ #define __PCF2123REG_H__ /* Control and status */ #define PCF2123_REG_CTRL1 0x0 #define PCF2123_REG_CTRL2 0x1 /* Time and date */ #define PCF2123_REG_SECONDS 0x2 #define PCF2123_REG_MINUTES 0x3 #define PCF2123_REG_HOURS 0x4 #define PCF2123_REG_DAYS 0x5 #define PCF2123_REG_WEEKDAYS 0x6 #define PCF2123_REG_MONTHS 0x7 #define PCF2123_REG_YEARS 0x8 /* Alarm registers */ #define PCF2123_REG_MINUTE_ALARM 0x9 #define PCF2123_REG_HOUR_ALARM 0xA #define PCF2123_REG_DAY_ALARM 0xB #define PCF2123_REG_WEEKDAY_ALARM 0xC /* Offset */ #define PCF2123_REG_OFFSET 0xD /* Timer */ #define PCF2123_REG_TIMER_CLKOUT 0xE #define PCF2123_REG_COUNTDOWN_TIMER 0xF /* Commands */ #define PCF2123_CMD_READ (1 << 7) #define PCF2123_CMD_WRITE (0 << 7) #define PCF2123_READ(reg) (PCF2123_CMD_READ | (1 << 4) | (reg)) #define PCF2123_WRITE(reg) (PCF2123_CMD_WRITE | (1 << 4) | (reg)) #endif /* __PCF2123REG_H__ */ Index: head/sys/mips/atheros/uart_bus_ar71xx.c =================================================================== --- head/sys/mips/atheros/uart_bus_ar71xx.c (revision 326258) +++ head/sys/mips/atheros/uart_bus_ar71xx.c (revision 326259) @@ -1,106 +1,108 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009, Oleksandr Tymoshenko * 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 */ #include "opt_uart.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include "uart_if.h" static int uart_ar71xx_probe(device_t dev); extern struct uart_class uart_ar71xx_uart_class; static device_method_t uart_ar71xx_methods[] = { /* Device interface */ DEVMETHOD(device_probe, uart_ar71xx_probe), DEVMETHOD(device_attach, uart_bus_attach), DEVMETHOD(device_detach, uart_bus_detach), { 0, 0 } }; static driver_t uart_ar71xx_driver = { uart_driver_name, uart_ar71xx_methods, sizeof(struct uart_softc), }; extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs; static int uart_ar71xx_probe(device_t dev) { struct uart_softc *sc; uint64_t freq; freq = ar71xx_uart_freq(); sc = device_get_softc(dev); sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs); sc->sc_class = &uart_ns8250_class; bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas)); sc->sc_sysdev->bas.regshft = 2; sc->sc_sysdev->bas.bst = mips_bus_space_generic; sc->sc_sysdev->bas.bsh = MIPS_PHYS_TO_KSEG1(AR71XX_UART_ADDR) + 3; sc->sc_bas.regshft = 2; sc->sc_bas.bst = mips_bus_space_generic; sc->sc_bas.bsh = MIPS_PHYS_TO_KSEG1(AR71XX_UART_ADDR) + 3; return (uart_bus_probe(dev, 2, 0, freq, 0, 0)); } #ifdef EARLY_PRINTF static void ar71xx_early_putc(int c) { int i; for (i = 0; i < 1000; i++) { if (ATH_READ_REG(AR71XX_UART_ADDR + AR71XX_UART_LSR) & AR71XX_UART_LSR_THRE) break; } ATH_WRITE_REG(AR71XX_UART_ADDR + AR71XX_UART_THR, (c & 0xff)); } early_putc_t *early_putc = ar71xx_early_putc; #endif DRIVER_MODULE(uart, apb, uart_ar71xx_driver, uart_devclass, 0, 0); Index: head/sys/mips/atheros/uart_bus_ar933x.c =================================================================== --- head/sys/mips/atheros/uart_bus_ar933x.c (revision 326258) +++ head/sys/mips/atheros/uart_bus_ar933x.c (revision 326259) @@ -1,115 +1,117 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2012, Adrian Chadd * 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 */ #include "opt_uart.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef EARLY_PRINTF #include #endif #include "uart_if.h" static int uart_ar933x_probe(device_t dev); extern struct uart_class uart_ar933x_uart_class; static device_method_t uart_ar933x_methods[] = { /* Device interface */ DEVMETHOD(device_probe, uart_ar933x_probe), DEVMETHOD(device_attach, uart_bus_attach), DEVMETHOD(device_detach, uart_bus_detach), { 0, 0 } }; static driver_t uart_ar933x_driver = { uart_driver_name, uart_ar933x_methods, sizeof(struct uart_softc), }; extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs; static int uart_ar933x_probe(device_t dev) { struct uart_softc *sc; uint64_t freq; freq = ar71xx_uart_freq(); sc = device_get_softc(dev); sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs); sc->sc_class = &uart_ar933x_class; bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas)); sc->sc_sysdev->bas.regshft = 0; sc->sc_sysdev->bas.bst = mips_bus_space_generic; sc->sc_sysdev->bas.bsh = MIPS_PHYS_TO_KSEG1(AR71XX_UART_ADDR); sc->sc_bas.regshft = 0; sc->sc_bas.bst = mips_bus_space_generic; sc->sc_bas.bsh = MIPS_PHYS_TO_KSEG1(AR71XX_UART_ADDR); return (uart_bus_probe(dev, 2, 0, freq, 0, 0)); } /* * Assume the UART is setup by the bootloader and just echo that. */ #if defined(EARLY_PRINTF) static void ar933x_early_putc(int c) { int i = 1000; /* Wait until FIFO is clear */ while ((i > 0) && (ATH_READ_REG(AR71XX_UART_ADDR + AR933X_UART_CS_REG) & AR933X_UART_CS_TX_BUSY)) i--; /* Write it out */ ATH_WRITE_REG(AR71XX_UART_ADDR + AR933X_UART_DATA_REG, (c & 0xff)| AR933X_UART_DATA_TX_CSR); } early_putc_t *early_putc = ar933x_early_putc; #endif /* EARLY_PRINTF */ DRIVER_MODULE(uart, apb, uart_ar933x_driver, uart_devclass, 0, 0); Index: head/sys/mips/atheros/uart_cpu_ar71xx.c =================================================================== --- head/sys/mips/atheros/uart_cpu_ar71xx.c (revision 326258) +++ head/sys/mips/atheros/uart_cpu_ar71xx.c (revision 326259) @@ -1,76 +1,78 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009 Oleksandr Tymoshenko * 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 "opt_uart.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include bus_space_tag_t uart_bus_space_io; bus_space_tag_t uart_bus_space_mem; int uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) { return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0); } int uart_cpu_getdev(int devtype, struct uart_devinfo *di) { uint64_t freq; freq = ar71xx_uart_freq(); di->ops = uart_getops(&uart_ns8250_class); di->bas.chan = 0; di->bas.bst = ar71xx_bus_space_reversed; di->bas.regshft = 2; di->bas.rclk = freq; di->baudrate = 115200; di->databits = 8; di->stopbits = 1; di->parity = UART_PARITY_NONE; uart_bus_space_io = NULL; uart_bus_space_mem = ar71xx_bus_space_reversed; di->bas.bsh = MIPS_PHYS_TO_KSEG1(AR71XX_UART_ADDR); return (0); } Index: head/sys/mips/atheros/uart_cpu_ar933x.c =================================================================== --- head/sys/mips/atheros/uart_cpu_ar933x.c (revision 326258) +++ head/sys/mips/atheros/uart_cpu_ar933x.c (revision 326259) @@ -1,78 +1,80 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2012 Adrian Chadd * 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 "opt_uart.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include bus_space_tag_t uart_bus_space_io; bus_space_tag_t uart_bus_space_mem; int uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) { return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0); } int uart_cpu_getdev(int devtype, struct uart_devinfo *di) { uint64_t freq; freq = ar71xx_uart_freq(); di->ops = uart_getops(&uart_ar933x_class); di->bas.chan = 0; di->bas.bst = ar71xx_bus_space_reversed; di->bas.regshft = 0; /* We'll do "correct" dword addressing here */ di->bas.rclk = freq; di->baudrate = 115200; di->databits = 8; di->stopbits = 1; di->parity = UART_PARITY_NONE; uart_bus_space_io = NULL; uart_bus_space_mem = ar71xx_bus_space_reversed; di->bas.bsh = MIPS_PHYS_TO_KSEG1(AR71XX_UART_ADDR); return (0); } Index: head/sys/mips/atheros/uart_dev_ar933x.c =================================================================== --- head/sys/mips/atheros/uart_dev_ar933x.c (revision 326258) +++ head/sys/mips/atheros/uart_dev_ar933x.c (revision 326259) @@ -1,738 +1,740 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2013 Adrian Chadd * 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 ``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 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 "uart_if.h" /* * Default system clock is 25MHz; see ar933x_chip.c for how * the startup process determines whether it's 25MHz or 40MHz. */ #define DEFAULT_RCLK (25 * 1000 * 1000) #define ar933x_getreg(bas, reg) \ bus_space_read_4((bas)->bst, (bas)->bsh, reg) #define ar933x_setreg(bas, reg, value) \ bus_space_write_4((bas)->bst, (bas)->bsh, reg, value) static int ar933x_drain(struct uart_bas *bas, int what) { int limit; if (what & UART_DRAIN_TRANSMITTER) { limit = 10*1024; /* Loop over until the TX FIFO shows entirely clear */ while (--limit) { if ((ar933x_getreg(bas, AR933X_UART_CS_REG) & AR933X_UART_CS_TX_BUSY) == 0) break; } if (limit == 0) { return (EIO); } } if (what & UART_DRAIN_RECEIVER) { limit=10*4096; while (--limit) { /* XXX duplicated from ar933x_getc() */ /* XXX TODO: refactor! */ /* If there's nothing to read, stop! */ if ((ar933x_getreg(bas, AR933X_UART_DATA_REG) & AR933X_UART_DATA_RX_CSR) == 0) { break; } /* Read the top of the RX FIFO */ (void) ar933x_getreg(bas, AR933X_UART_DATA_REG); /* Remove that entry from said RX FIFO */ ar933x_setreg(bas, AR933X_UART_DATA_REG, AR933X_UART_DATA_RX_CSR); uart_barrier(bas); DELAY(2); } if (limit == 0) { return (EIO); } } return (0); } /* * Calculate the baud from the given chip configuration parameters. */ static unsigned long ar933x_uart_get_baud(unsigned int clk, unsigned int scale, unsigned int step) { uint64_t t; uint32_t div; div = (2 << 16) * (scale + 1); t = clk; t *= step; t += (div / 2); t = t / div; return (t); } /* * Calculate the scale/step with the lowest possible deviation from * the target baudrate. */ static void ar933x_uart_get_scale_step(struct uart_bas *bas, unsigned int baud, unsigned int *scale, unsigned int *step) { unsigned int tscale; uint32_t clk; long min_diff; clk = bas->rclk; *scale = 0; *step = 0; min_diff = baud; for (tscale = 0; tscale < AR933X_UART_MAX_SCALE; tscale++) { uint64_t tstep; int diff; tstep = baud * (tscale + 1); tstep *= (2 << 16); tstep = tstep / clk; if (tstep > AR933X_UART_MAX_STEP) break; diff = abs(ar933x_uart_get_baud(clk, tscale, tstep) - baud); if (diff < min_diff) { min_diff = diff; *scale = tscale; *step = tstep; } } } static int ar933x_param(struct uart_bas *bas, int baudrate, int databits, int stopbits, int parity) { /* UART always 8 bits */ /* UART always 1 stop bit */ /* UART parity is controllable by bits 0:1, ignore for now */ /* Set baudrate if required. */ if (baudrate > 0) { uint32_t clock_scale, clock_step; /* Find the best fit for the given baud rate */ ar933x_uart_get_scale_step(bas, baudrate, &clock_scale, &clock_step); /* * Program the clock register in its entirety - no need * for Read-Modify-Write. */ ar933x_setreg(bas, AR933X_UART_CLOCK_REG, ((clock_scale & AR933X_UART_CLOCK_SCALE_M) << AR933X_UART_CLOCK_SCALE_S) | (clock_step & AR933X_UART_CLOCK_STEP_M)); } uart_barrier(bas); return (0); } /* * Low-level UART interface. */ static int ar933x_probe(struct uart_bas *bas); static void ar933x_init(struct uart_bas *bas, int, int, int, int); static void ar933x_term(struct uart_bas *bas); static void ar933x_putc(struct uart_bas *bas, int); static int ar933x_rxready(struct uart_bas *bas); static int ar933x_getc(struct uart_bas *bas, struct mtx *); static struct uart_ops uart_ar933x_ops = { .probe = ar933x_probe, .init = ar933x_init, .term = ar933x_term, .putc = ar933x_putc, .rxready = ar933x_rxready, .getc = ar933x_getc, }; static int ar933x_probe(struct uart_bas *bas) { /* We always know this will be here */ return (0); } static void ar933x_init(struct uart_bas *bas, int baudrate, int databits, int stopbits, int parity) { uint32_t reg; /* Setup default parameters */ ar933x_param(bas, baudrate, databits, stopbits, parity); /* XXX Force enable UART in case it was disabled */ /* Disable all interrupts */ ar933x_setreg(bas, AR933X_UART_INT_EN_REG, 0x00000000); /* Disable the host interrupt */ reg = ar933x_getreg(bas, AR933X_UART_CS_REG); reg &= ~AR933X_UART_CS_HOST_INT_EN; ar933x_setreg(bas, AR933X_UART_CS_REG, reg); uart_barrier(bas); /* XXX Set RTS/DTR? */ } /* * Detach from console. */ static void ar933x_term(struct uart_bas *bas) { /* XXX TODO */ } static void ar933x_putc(struct uart_bas *bas, int c) { int limit; limit = 250000; /* Wait for space in the TX FIFO */ while ( ((ar933x_getreg(bas, AR933X_UART_DATA_REG) & AR933X_UART_DATA_TX_CSR) == 0) && --limit) DELAY(4); /* Write the actual byte */ ar933x_setreg(bas, AR933X_UART_DATA_REG, (c & 0xff) | AR933X_UART_DATA_TX_CSR); } static int ar933x_rxready(struct uart_bas *bas) { /* Wait for a character to come ready */ return (!!(ar933x_getreg(bas, AR933X_UART_DATA_REG) & AR933X_UART_DATA_RX_CSR)); } static int ar933x_getc(struct uart_bas *bas, struct mtx *hwmtx) { int c; uart_lock(hwmtx); /* Wait for a character to come ready */ while ((ar933x_getreg(bas, AR933X_UART_DATA_REG) & AR933X_UART_DATA_RX_CSR) == 0) { uart_unlock(hwmtx); DELAY(4); uart_lock(hwmtx); } /* Read the top of the RX FIFO */ c = ar933x_getreg(bas, AR933X_UART_DATA_REG) & 0xff; /* Remove that entry from said RX FIFO */ ar933x_setreg(bas, AR933X_UART_DATA_REG, AR933X_UART_DATA_RX_CSR); uart_unlock(hwmtx); return (c); } /* * High-level UART interface. */ struct ar933x_softc { struct uart_softc base; uint32_t u_ier; }; static int ar933x_bus_attach(struct uart_softc *); static int ar933x_bus_detach(struct uart_softc *); static int ar933x_bus_flush(struct uart_softc *, int); static int ar933x_bus_getsig(struct uart_softc *); static int ar933x_bus_ioctl(struct uart_softc *, int, intptr_t); static int ar933x_bus_ipend(struct uart_softc *); static int ar933x_bus_param(struct uart_softc *, int, int, int, int); static int ar933x_bus_probe(struct uart_softc *); static int ar933x_bus_receive(struct uart_softc *); static int ar933x_bus_setsig(struct uart_softc *, int); static int ar933x_bus_transmit(struct uart_softc *); static void ar933x_bus_grab(struct uart_softc *); static void ar933x_bus_ungrab(struct uart_softc *); static kobj_method_t ar933x_methods[] = { KOBJMETHOD(uart_attach, ar933x_bus_attach), KOBJMETHOD(uart_detach, ar933x_bus_detach), KOBJMETHOD(uart_flush, ar933x_bus_flush), KOBJMETHOD(uart_getsig, ar933x_bus_getsig), KOBJMETHOD(uart_ioctl, ar933x_bus_ioctl), KOBJMETHOD(uart_ipend, ar933x_bus_ipend), KOBJMETHOD(uart_param, ar933x_bus_param), KOBJMETHOD(uart_probe, ar933x_bus_probe), KOBJMETHOD(uart_receive, ar933x_bus_receive), KOBJMETHOD(uart_setsig, ar933x_bus_setsig), KOBJMETHOD(uart_transmit, ar933x_bus_transmit), KOBJMETHOD(uart_grab, ar933x_bus_grab), KOBJMETHOD(uart_ungrab, ar933x_bus_ungrab), { 0, 0 } }; struct uart_class uart_ar933x_class = { "ar933x", ar933x_methods, sizeof(struct ar933x_softc), .uc_ops = &uart_ar933x_ops, .uc_range = 8, .uc_rclk = DEFAULT_RCLK, .uc_rshift = 0 }; #define SIGCHG(c, i, s, d) \ if (c) { \ i |= (i & s) ? s : s | d; \ } else { \ i = (i & s) ? (i & ~s) | d : i; \ } static int ar933x_bus_attach(struct uart_softc *sc) { struct ar933x_softc *u = (struct ar933x_softc *)sc; struct uart_bas *bas = &sc->sc_bas; uint32_t reg; /* XXX TODO: flush transmitter */ /* * Setup initial interrupt notifications. * * XXX for now, just RX FIFO valid. * Later on (when they're handled), also handle * RX errors/overflow. */ u->u_ier = AR933X_UART_INT_RX_VALID; /* Enable RX interrupts to kick-start things */ ar933x_setreg(bas, AR933X_UART_INT_EN_REG, u->u_ier); /* Enable the host interrupt now */ reg = ar933x_getreg(bas, AR933X_UART_CS_REG); reg |= AR933X_UART_CS_HOST_INT_EN; ar933x_setreg(bas, AR933X_UART_CS_REG, reg); return (0); } static int ar933x_bus_detach(struct uart_softc *sc) { struct uart_bas *bas = &sc->sc_bas; uint32_t reg; /* Disable all interrupts */ ar933x_setreg(bas, AR933X_UART_INT_EN_REG, 0x00000000); /* Disable the host interrupt */ reg = ar933x_getreg(bas, AR933X_UART_CS_REG); reg &= ~AR933X_UART_CS_HOST_INT_EN; ar933x_setreg(bas, AR933X_UART_CS_REG, reg); uart_barrier(bas); return (0); } static int ar933x_bus_flush(struct uart_softc *sc, int what) { struct uart_bas *bas; bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); ar933x_drain(bas, what); uart_unlock(sc->sc_hwmtx); return (0); } static int ar933x_bus_getsig(struct uart_softc *sc) { uint32_t sig = sc->sc_hwsig; /* * For now, let's just return that DSR/DCD/CTS is asserted. */ SIGCHG(1, sig, SER_DSR, SER_DDSR); SIGCHG(1, sig, SER_CTS, SER_DCTS); SIGCHG(1, sig, SER_DCD, SER_DDCD); SIGCHG(1, sig, SER_RI, SER_DRI); sc->sc_hwsig = sig & ~SER_MASK_DELTA; return (sig); } /* * XXX TODO: actually implement the rest of this! */ static int ar933x_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) { int error = 0; /* XXX lock */ switch (request) { case UART_IOCTL_BREAK: case UART_IOCTL_IFLOW: case UART_IOCTL_OFLOW: break; case UART_IOCTL_BAUD: *(int*)data = 115200; break; default: error = EINVAL; break; } /* XXX unlock */ return (error); } /* * Bus interrupt handler. * * For now, system interrupts are disabled. * So this is just called from a callout in uart_core.c * to poll various state. */ static int ar933x_bus_ipend(struct uart_softc *sc) { struct ar933x_softc *u = (struct ar933x_softc *)sc; struct uart_bas *bas = &sc->sc_bas; int ipend = 0; uint32_t isr; uart_lock(sc->sc_hwmtx); /* * Fetch/ACK the ISR status. */ isr = ar933x_getreg(bas, AR933X_UART_INT_REG); ar933x_setreg(bas, AR933X_UART_INT_REG, isr); uart_barrier(bas); /* * RX ready - notify upper layer. */ if (isr & AR933X_UART_INT_RX_VALID) { ipend |= SER_INT_RXREADY; } /* * If we get this interrupt, we should disable * it from the interrupt mask and inform the uart * driver appropriately. * * We can't keep setting SER_INT_TXIDLE or SER_INT_SIGCHG * all the time or IO stops working. So we will always * clear this interrupt if we get it, then we only signal * the upper layer if we were doing active TX in the * first place. * * Also, the name is misleading. This actually means * "the FIFO is almost empty." So if we just write some * more data to the FIFO without checking whether it can * take said data, we'll overflow the thing. * * Unfortunately the FreeBSD uart device has no concept of * partial UART writes - it expects that the whole buffer * is written to the hardware. Thus for now, ar933x_bus_transmit() * will wait for the FIFO to finish draining before it pushes * more frames into it. */ if (isr & AR933X_UART_INT_TX_EMPTY) { /* * Update u_ier to disable TX notifications; update hardware */ u->u_ier &= ~AR933X_UART_INT_TX_EMPTY; ar933x_setreg(bas, AR933X_UART_INT_EN_REG, u->u_ier); uart_barrier(bas); } /* * Only signal TX idle if we're not busy transmitting. * * XXX I never get _out_ of txbusy? Debug that! */ if (sc->sc_txbusy) { if (isr & AR933X_UART_INT_TX_EMPTY) { ipend |= SER_INT_TXIDLE; } else { ipend |= SER_INT_SIGCHG; } } uart_unlock(sc->sc_hwmtx); return (ipend); } static int ar933x_bus_param(struct uart_softc *sc, int baudrate, int databits, int stopbits, int parity) { struct uart_bas *bas; int error; bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); error = ar933x_param(bas, baudrate, databits, stopbits, parity); uart_unlock(sc->sc_hwmtx); return (error); } static int ar933x_bus_probe(struct uart_softc *sc) { struct uart_bas *bas; int error; bas = &sc->sc_bas; error = ar933x_probe(bas); if (error) return (error); /* Reset FIFOs. */ ar933x_drain(bas, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER); /* XXX TODO: actually find out what the FIFO depth is! */ sc->sc_rxfifosz = 16; sc->sc_txfifosz = 16; return (0); } static int ar933x_bus_receive(struct uart_softc *sc) { struct uart_bas *bas = &sc->sc_bas; int xc; uart_lock(sc->sc_hwmtx); /* Loop over until we are full, or no data is available */ while (ar933x_rxready(bas)) { if (uart_rx_full(sc)) { sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; break; } /* Read the top of the RX FIFO */ xc = ar933x_getreg(bas, AR933X_UART_DATA_REG) & 0xff; /* Remove that entry from said RX FIFO */ ar933x_setreg(bas, AR933X_UART_DATA_REG, AR933X_UART_DATA_RX_CSR); uart_barrier(bas); /* XXX frame, parity error */ uart_rx_put(sc, xc); } /* * XXX TODO: Discard everything left in the Rx FIFO? * XXX only if we've hit an overrun condition? */ uart_unlock(sc->sc_hwmtx); return (0); } static int ar933x_bus_setsig(struct uart_softc *sc, int sig) { #if 0 struct ar933x_softc *ns8250 = (struct ar933x_softc*)sc; struct uart_bas *bas; uint32_t new, old; bas = &sc->sc_bas; do { old = sc->sc_hwsig; new = old; if (sig & SER_DDTR) { SIGCHG(sig & SER_DTR, new, SER_DTR, SER_DDTR); } if (sig & SER_DRTS) { SIGCHG(sig & SER_RTS, new, SER_RTS, SER_DRTS); } } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); uart_lock(sc->sc_hwmtx); ns8250->mcr &= ~(MCR_DTR|MCR_RTS); if (new & SER_DTR) ns8250->mcr |= MCR_DTR; if (new & SER_RTS) ns8250->mcr |= MCR_RTS; uart_setreg(bas, REG_MCR, ns8250->mcr); uart_barrier(bas); uart_unlock(sc->sc_hwmtx); #endif return (0); } /* * Write the current transmit buffer to the TX FIFO. * * Unfortunately the FreeBSD uart device has no concept of * partial UART writes - it expects that the whole buffer * is written to the hardware. Thus for now, this will wait for * the FIFO to finish draining before it pushes more frames into it. * * If non-blocking operation is truely needed here, either * the FreeBSD uart device will need to handle partial writes * in xxx_bus_transmit(), or we'll need to do TX FIFO buffering * of our own here. */ static int ar933x_bus_transmit(struct uart_softc *sc) { struct uart_bas *bas = &sc->sc_bas; struct ar933x_softc *u = (struct ar933x_softc *)sc; int i; uart_lock(sc->sc_hwmtx); /* Wait for the FIFO to be clear - see above */ while (ar933x_getreg(bas, AR933X_UART_CS_REG) & AR933X_UART_CS_TX_BUSY) ; /* * Write some data! */ for (i = 0; i < sc->sc_txdatasz; i++) { /* Write the TX data */ ar933x_setreg(bas, AR933X_UART_DATA_REG, (sc->sc_txbuf[i] & 0xff) | AR933X_UART_DATA_TX_CSR); uart_barrier(bas); } /* * Now that we're transmitting, get interrupt notification * when the FIFO is (almost) empty - see above. */ u->u_ier |= AR933X_UART_INT_TX_EMPTY; ar933x_setreg(bas, AR933X_UART_INT_EN_REG, u->u_ier); uart_barrier(bas); /* * Inform the upper layer that we are presently transmitting * data to the hardware; this will be cleared when the * TXIDLE interrupt occurs. */ sc->sc_txbusy = 1; uart_unlock(sc->sc_hwmtx); return (0); } static void ar933x_bus_grab(struct uart_softc *sc) { struct uart_bas *bas = &sc->sc_bas; uint32_t reg; /* Disable the host interrupt now */ uart_lock(sc->sc_hwmtx); reg = ar933x_getreg(bas, AR933X_UART_CS_REG); reg &= ~AR933X_UART_CS_HOST_INT_EN; ar933x_setreg(bas, AR933X_UART_CS_REG, reg); uart_unlock(sc->sc_hwmtx); } static void ar933x_bus_ungrab(struct uart_softc *sc) { struct uart_bas *bas = &sc->sc_bas; uint32_t reg; /* Enable the host interrupt now */ uart_lock(sc->sc_hwmtx); reg = ar933x_getreg(bas, AR933X_UART_CS_REG); reg |= AR933X_UART_CS_HOST_INT_EN; ar933x_setreg(bas, AR933X_UART_CS_REG, reg); uart_unlock(sc->sc_hwmtx); } Index: head/sys/mips/atheros/uart_dev_ar933x.h =================================================================== --- head/sys/mips/atheros/uart_dev_ar933x.h (revision 326258) +++ head/sys/mips/atheros/uart_dev_ar933x.h (revision 326259) @@ -1,33 +1,35 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2013 Adrian Chadd * 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 ``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 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$ */ #ifndef __UART_DEV_AR933X__ #define __UART_DEV_AR933X__ extern struct uart_class uart_ar933x_class; #endif Index: head/sys/mips/beri/beri_machdep.c =================================================================== --- head/sys/mips/beri/beri_machdep.c (revision 326258) +++ head/sys/mips/beri/beri_machdep.c (revision 326259) @@ -1,275 +1,277 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006 Wojciech A. Koszek * Copyright (c) 2012-2014 Robert N. M. Watson * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) * ("CTSRD"), as part of the DARPA CRASH research programme. * * 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 "opt_ddb.h" #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef FDT #include #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include extern int *edata; extern int *end; void platform_cpu_init() { /* Nothing special */ } static void mips_init(void) { int i; #ifdef FDT struct mem_region mr[FDT_MEM_REGIONS]; uint64_t val; int mr_cnt; int j; #endif for (i = 0; i < 10; i++) { phys_avail[i] = 0; } /* phys_avail regions are in bytes */ phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end); phys_avail[1] = ctob(realmem); dump_avail[0] = phys_avail[0]; dump_avail[1] = phys_avail[1]; physmem = realmem; #ifdef FDT if (fdt_get_mem_regions(mr, &mr_cnt, &val) == 0) { physmem = btoc(val); KASSERT((phys_avail[0] >= mr[0].mr_start) && \ (phys_avail[0] < (mr[0].mr_start + mr[0].mr_size)), ("First region is not within FDT memory range")); /* Limit size of the first region */ phys_avail[1] = (mr[0].mr_start + MIN(mr[0].mr_size, ctob(realmem))); dump_avail[1] = phys_avail[1]; /* Add the rest of regions */ for (i = 1, j = 2; i < mr_cnt; i++, j+=2) { phys_avail[j] = mr[i].mr_start; phys_avail[j+1] = (mr[i].mr_start + mr[i].mr_size); dump_avail[j] = phys_avail[j]; dump_avail[j+1] = phys_avail[j+1]; } } #endif init_param1(); init_param2(physmem); mips_cpu_init(); pmap_bootstrap(); mips_proc0_init(); mutex_init(); kdb_init(); #ifdef KDB if (boothowto & RB_KDB) kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); #endif } /* * Perform a board-level soft-reset. */ void platform_reset(void) { /* XXX SMP will likely require us to do more. */ __asm__ __volatile__( "mfc0 $k0, $12\n\t" "li $k1, 0x00100000\n\t" "or $k0, $k0, $k1\n\t" "mtc0 $k0, $12\n"); for( ; ; ) __asm__ __volatile("wait"); } void platform_start(__register_t a0, __register_t a1, __register_t a2, __register_t a3) { struct bootinfo *bootinfop; vm_offset_t kernend; uint64_t platform_counter_freq; int argc = a0; char **argv = (char **)a1; char **envp = (char **)a2; long memsize; #ifdef FDT vm_offset_t dtbp; void *kmdp; #endif int i; /* clear the BSS and SBSS segments */ kernend = (vm_offset_t)&end; memset(&edata, 0, kernend - (vm_offset_t)(&edata)); mips_postboot_fixup(); mips_pcpu0_init(); /* * Over time, we've changed out boot-time binary interface for the * kernel. Miniboot simply provides a 'memsize' in a3, whereas the * FreeBSD boot loader provides a 'bootinfo *' in a3. While slightly * grody, we support both here by detecting 'pointer-like' values in * a3 and assuming physical memory can never be that back. * * XXXRW: Pull more values than memsize out of bootinfop -- e.g., * module information. */ if (a3 >= 0x9800000000000000ULL) { bootinfop = (void *)a3; memsize = bootinfop->bi_memsize; preload_metadata = (caddr_t)bootinfop->bi_modulep; } else { bootinfop = NULL; memsize = a3; } #ifdef FDT /* * Find the dtb passed in by the boot loader (currently fictional). */ kmdp = preload_search_by_type("elf kernel"); dtbp = MD_FETCH(kmdp, MODINFOMD_DTBP, vm_offset_t); #if defined(FDT_DTB_STATIC) /* * In case the device tree blob was not retrieved (from metadata) try * to use the statically embedded one. */ if (dtbp == (vm_offset_t)NULL) dtbp = (vm_offset_t)&fdt_static_dtb; #else #error "Non-static FDT not yet supported on BERI" #endif if (OF_install(OFW_FDT, 0) == FALSE) while (1); if (OF_init((void *)dtbp) != 0) while (1); /* * Configure more boot-time parameters passed in by loader. */ boothowto = MD_FETCH(kmdp, MODINFOMD_HOWTO, int); init_static_kenv(MD_FETCH(kmdp, MODINFOMD_ENVP, char *), 0); /* * Get bootargs from FDT if specified. */ ofw_parse_bootargs(); #endif /* * XXXRW: We have no way to compare wallclock time to cycle rate on * BERI, so for now assume we run at the MALTA default (100MHz). */ platform_counter_freq = MIPS_DEFAULT_HZ; mips_timer_early_init(platform_counter_freq); cninit(); printf("entry: platform_start()\n"); bootverbose = 1; if (bootverbose) { printf("cmd line: "); for (i = 0; i < argc; i++) printf("%s ", argv[i]); printf("\n"); printf("envp:\n"); for (i = 0; envp[i]; i += 2) printf("\t%s = %s\n", envp[i], envp[i+1]); if (bootinfop != NULL) printf("bootinfo found at %p\n", bootinfop); printf("memsize = %p\n", (void *)memsize); } realmem = btoc(memsize); mips_init(); mips_timer_init_params(platform_counter_freq, 0); } Index: head/sys/mips/beri/beri_pic.c =================================================================== --- head/sys/mips/beri/beri_pic.c (revision 326258) +++ head/sys/mips/beri/beri_pic.c (revision 326259) @@ -1,368 +1,370 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2017 Ruslan Bukin * Copyright (c) 2013 SRI International * All rights reserved. * * This software was developed by SRI International and the University of * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) * ("CTSRD"), as part of the DARPA CRASH research programme. * * 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 "opt_platform.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #ifdef SMP #include #endif #include #include #include #include #include "pic_if.h" #define BP_NUM_HARD_IRQS 5 #define BP_NUM_IRQS 32 /* We use hard irqs 15-31 as soft */ #define BP_FIRST_SOFT 16 #define BP_CFG_IRQ_S 0 #define BP_CFG_IRQ_M (0xf << BP_CFG_IRQ_S) #define BP_CFG_TID_S 8 #define BP_CFG_TID_M (0x7FFFFF << BP_CFG_TID_S) #define BP_CFG_ENABLE (1 << 31) enum { BP_CFG, BP_IP_READ, BP_IP_SET, BP_IP_CLEAR }; struct beripic_softc; struct beri_pic_isrc { struct intr_irqsrc isrc; u_int irq; uint32_t mips_hard_irq; }; struct hirq { uint32_t irq; struct beripic_softc *sc; }; struct beripic_softc { device_t dev; uint32_t nirqs; struct beri_pic_isrc irqs[BP_NUM_IRQS]; struct resource *res[4 + BP_NUM_HARD_IRQS]; void *ih[BP_NUM_HARD_IRQS]; struct hirq hirq[BP_NUM_HARD_IRQS]; uint8_t mips_hard_irq_idx; }; static struct resource_spec beri_pic_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { SYS_RES_MEMORY, 1, RF_ACTIVE }, { SYS_RES_MEMORY, 2, RF_ACTIVE }, { SYS_RES_MEMORY, 3, RF_ACTIVE }, { SYS_RES_IRQ, 0, RF_ACTIVE }, { SYS_RES_IRQ, 1, RF_ACTIVE }, { SYS_RES_IRQ, 2, RF_ACTIVE }, { SYS_RES_IRQ, 3, RF_ACTIVE }, { SYS_RES_IRQ, 4, RF_ACTIVE }, { -1, 0 } }; static int beri_pic_intr(void *arg) { struct beripic_softc *sc; struct intr_irqsrc *isrc; struct hirq *h; uint64_t intr; uint64_t reg; int i; h = arg; sc = h->sc; intr = bus_read_8(sc->res[BP_IP_READ], 0); while ((i = fls(intr)) != 0) { i--; intr &= ~(1u << i); isrc = &sc->irqs[i].isrc; reg = bus_read_8(sc->res[BP_CFG], i * 8); if ((reg & BP_CFG_IRQ_M) != h->irq) { continue; } if ((reg & (BP_CFG_ENABLE)) == 0) { continue; } if (intr_isrc_dispatch(isrc, curthread->td_intr_frame) != 0) { device_printf(sc->dev, "Stray interrupt %u detected\n", i); } bus_write_8(sc->res[BP_IP_CLEAR], 0, (1 << i)); } return (FILTER_HANDLED); } static int beripic_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (!ofw_bus_is_compatible(dev, "sri-cambridge,beri-pic")) return (ENXIO); device_set_desc(dev, "BERI Programmable Interrupt Controller"); return (BUS_PROBE_DEFAULT); } static int beripic_attach(device_t dev) { struct beripic_softc *sc; struct beri_pic_isrc *pic_isrc; const char *name; struct intr_irqsrc *isrc; intptr_t xref; uint32_t unit; int err; int i; sc = device_get_softc(dev); sc->dev = dev; if (bus_alloc_resources(dev, beri_pic_spec, sc->res)) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); } xref = OF_xref_from_node(ofw_bus_get_node(dev)); name = device_get_nameunit(dev); unit = device_get_unit(dev); sc->nirqs = BP_NUM_IRQS; for (i = 0; i < sc->nirqs; i++) { sc->irqs[i].irq = i; isrc = &sc->irqs[i].isrc; /* Assign mips hard irq number. */ pic_isrc = (struct beri_pic_isrc *)isrc; pic_isrc->mips_hard_irq = sc->mips_hard_irq_idx++; /* Last IRQ is used for IPIs. */ if (sc->mips_hard_irq_idx >= (BP_NUM_HARD_IRQS - 1)) { sc->mips_hard_irq_idx = 0; } err = intr_isrc_register(isrc, sc->dev, 0, "pic%d,%d", unit, i); bus_write_8(sc->res[BP_CFG], i * 8, 0); } /* * Now, when everything is initialized, it's right time to * register interrupt controller to interrupt framefork. */ if (intr_pic_register(dev, xref) == NULL) { device_printf(dev, "could not register PIC\n"); return (ENXIO); } /* Last IRQ is used for IPIs. */ for (i = 0; i < (BP_NUM_HARD_IRQS - 1); i++) { sc->hirq[i].sc = sc; sc->hirq[i].irq = i; if (bus_setup_intr(dev, sc->res[4+i], INTR_TYPE_CLK, beri_pic_intr, NULL, &sc->hirq[i], sc->ih[i])) { device_printf(dev, "could not setup irq handler\n"); intr_pic_deregister(dev, xref); return (ENXIO); } } return (0); } static void beri_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc) { struct beri_pic_isrc *pic_isrc; struct beripic_softc *sc; uint64_t reg; sc = device_get_softc(dev); pic_isrc = (struct beri_pic_isrc *)isrc; reg = BP_CFG_ENABLE; reg |= (pic_isrc->mips_hard_irq << BP_CFG_IRQ_S); bus_write_8(sc->res[BP_CFG], pic_isrc->irq * 8, reg); } static void beri_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc) { struct beri_pic_isrc *pic_isrc; struct beripic_softc *sc; uint64_t reg; sc = device_get_softc(dev); pic_isrc = (struct beri_pic_isrc *)isrc; reg = bus_read_8(sc->res[BP_CFG], pic_isrc->irq * 8); reg &= ~BP_CFG_ENABLE; bus_write_8(sc->res[BP_CFG], pic_isrc->irq * 8, reg); } static int beri_pic_map_intr(device_t dev, struct intr_map_data *data, struct intr_irqsrc **isrcp) { struct beripic_softc *sc; struct intr_map_data_fdt *daf; uint32_t irq; sc = device_get_softc(dev); daf = (struct intr_map_data_fdt *)data; if (data == NULL || data->type != INTR_MAP_DATA_FDT || daf->ncells != 1 || daf->cells[0] >= sc->nirqs) return (EINVAL); irq = daf->cells[0]; *isrcp = &sc->irqs[irq].isrc; return (0); } static void beri_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc) { beri_pic_enable_intr(dev, isrc); } static void beri_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) { beri_pic_disable_intr(dev, isrc); } #ifdef SMP void beripic_setup_ipi(device_t dev, u_int tid, u_int ipi_irq) { struct beripic_softc *sc; uint64_t reg; sc = device_get_softc(dev); reg = (BP_CFG_ENABLE); reg |= (ipi_irq << BP_CFG_IRQ_S); reg |= (tid << BP_CFG_TID_S); bus_write_8(sc->res[BP_CFG], ((BP_FIRST_SOFT + tid) * 8), reg); } void beripic_send_ipi(device_t dev, u_int tid) { struct beripic_softc *sc; uint64_t bit; sc = device_get_softc(dev); bit = (BP_FIRST_SOFT + tid); KASSERT(bit < BP_NUM_IRQS, ("tid (%d) to large\n", tid)); bus_write_8(sc->res[BP_IP_SET], 0x0, (1 << bit)); } void beripic_clear_ipi(device_t dev, u_int tid) { struct beripic_softc *sc; uint64_t bit; sc = device_get_softc(dev); bit = (BP_FIRST_SOFT + tid); KASSERT(bit < BP_NUM_IRQS, ("tid (%d) to large\n", tid)); bus_write_8(sc->res[BP_IP_CLEAR], 0x0, (1 << bit)); } #endif static device_method_t beripic_fdt_methods[] = { /* Device interface */ DEVMETHOD(device_probe, beripic_probe), DEVMETHOD(device_attach, beripic_attach), /* Interrupt controller interface */ DEVMETHOD(pic_enable_intr, beri_pic_enable_intr), DEVMETHOD(pic_disable_intr, beri_pic_disable_intr), DEVMETHOD(pic_map_intr, beri_pic_map_intr), DEVMETHOD(pic_post_ithread, beri_pic_post_ithread), DEVMETHOD(pic_pre_ithread, beri_pic_pre_ithread), DEVMETHOD_END }; devclass_t beripic_devclass; static driver_t beripic_driver = { "beripic", beripic_fdt_methods, sizeof(struct beripic_softc) }; EARLY_DRIVER_MODULE(beripic, ofwbus, beripic_driver, beripic_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); Index: head/sys/mips/cavium/ciu.c =================================================================== --- head/sys/mips/cavium/ciu.c (revision 326258) +++ head/sys/mips/cavium/ciu.c (revision 326259) @@ -1,487 +1,489 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include /* * This bus sits between devices/buses and nexus and handles CIU interrupts * and passes everything else through. It should really be a nexus subclass * or something, but for now this will be sufficient. */ #define CIU_IRQ_HARD (0) #define CIU_IRQ_EN0_BEGIN OCTEON_IRQ_WORKQ0 #define CIU_IRQ_EN0_END OCTEON_IRQ_BOOTDMA #define CIU_IRQ_EN0_COUNT ((CIU_IRQ_EN0_END - CIU_IRQ_EN0_BEGIN) + 1) #define CIU_IRQ_EN1_BEGIN OCTEON_IRQ_WDOG0 #define CIU_IRQ_EN1_END OCTEON_IRQ_DFM #define CIU_IRQ_EN1_COUNT ((CIU_IRQ_EN1_END - CIU_IRQ_EN1_BEGIN) + 1) struct ciu_softc { struct rman irq_rman; struct resource *ciu_irq; }; static mips_intrcnt_t ciu_en0_intrcnt[CIU_IRQ_EN0_COUNT]; static mips_intrcnt_t ciu_en1_intrcnt[CIU_IRQ_EN1_COUNT]; static struct intr_event *ciu_en0_intr_events[CIU_IRQ_EN0_COUNT]; static struct intr_event *ciu_en1_intr_events[CIU_IRQ_EN1_COUNT]; static int ciu_probe(device_t); static int ciu_attach(device_t); static struct resource *ciu_alloc_resource(device_t, device_t, int, int *, rman_res_t, rman_res_t, rman_res_t, u_int); static int ciu_setup_intr(device_t, device_t, struct resource *, int, driver_filter_t *, driver_intr_t *, void *, void **); static int ciu_teardown_intr(device_t, device_t, struct resource *, void *); static int ciu_bind_intr(device_t, device_t, struct resource *, int); static int ciu_describe_intr(device_t, device_t, struct resource *, void *, const char *); static void ciu_hinted_child(device_t, const char *, int); static void ciu_en0_intr_mask(void *); static void ciu_en0_intr_unmask(void *); #ifdef SMP static int ciu_en0_intr_bind(void *, int); #endif static void ciu_en1_intr_mask(void *); static void ciu_en1_intr_unmask(void *); #ifdef SMP static int ciu_en1_intr_bind(void *, int); #endif static int ciu_intr(void *); static int ciu_probe(device_t dev) { if (device_get_unit(dev) != 0) return (ENXIO); device_set_desc(dev, "Cavium Octeon Central Interrupt Unit"); return (BUS_PROBE_NOWILDCARD); } static int ciu_attach(device_t dev) { char name[MAXCOMLEN + 1]; struct ciu_softc *sc; unsigned i; int error; int rid; sc = device_get_softc(dev); rid = 0; sc->ciu_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, CIU_IRQ_HARD, CIU_IRQ_HARD, 1, RF_ACTIVE); if (sc->ciu_irq == NULL) { device_printf(dev, "could not allocate irq%d\n", CIU_IRQ_HARD); return (ENXIO); } error = bus_setup_intr(dev, sc->ciu_irq, INTR_TYPE_MISC, ciu_intr, NULL, sc, NULL); if (error != 0) { device_printf(dev, "bus_setup_intr failed: %d\n", error); return (error); } sc->irq_rman.rm_type = RMAN_ARRAY; sc->irq_rman.rm_descr = "CIU IRQ"; error = rman_init(&sc->irq_rman); if (error != 0) return (error); /* * We have two contiguous IRQ regions, use a single rman. */ error = rman_manage_region(&sc->irq_rman, CIU_IRQ_EN0_BEGIN, CIU_IRQ_EN1_END); if (error != 0) return (error); for (i = 0; i < CIU_IRQ_EN0_COUNT; i++) { snprintf(name, sizeof name, "int%d:", i + CIU_IRQ_EN0_BEGIN); ciu_en0_intrcnt[i] = mips_intrcnt_create(name); } for (i = 0; i < CIU_IRQ_EN1_COUNT; i++) { snprintf(name, sizeof name, "int%d:", i + CIU_IRQ_EN1_BEGIN); ciu_en1_intrcnt[i] = mips_intrcnt_create(name); } bus_generic_probe(dev); bus_generic_attach(dev); return (0); } static struct resource * ciu_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct resource *res; struct ciu_softc *sc; sc = device_get_softc(bus); switch (type) { case SYS_RES_IRQ: break; default: return (bus_alloc_resource(device_get_parent(bus), type, rid, start, end, count, flags)); } /* * One interrupt at a time for now. */ if (start != end) return (NULL); res = rman_reserve_resource(&sc->irq_rman, start, end, count, flags, child); if (res != NULL) return (res); return (NULL); } static int ciu_setup_intr(device_t bus, device_t child, struct resource *res, int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg, void **cookiep) { struct intr_event *event, **eventp; void (*mask_func)(void *); void (*unmask_func)(void *); int (*bind_func)(void *, int); mips_intrcnt_t intrcnt; int error; int irq; irq = rman_get_start(res); if (irq <= CIU_IRQ_EN0_END) { eventp = &ciu_en0_intr_events[irq - CIU_IRQ_EN0_BEGIN]; intrcnt = ciu_en0_intrcnt[irq - CIU_IRQ_EN0_BEGIN]; mask_func = ciu_en0_intr_mask; unmask_func = ciu_en0_intr_unmask; #ifdef SMP bind_func = ciu_en0_intr_bind; #endif } else { eventp = &ciu_en1_intr_events[irq - CIU_IRQ_EN1_BEGIN]; intrcnt = ciu_en1_intrcnt[irq - CIU_IRQ_EN1_BEGIN]; mask_func = ciu_en1_intr_mask; unmask_func = ciu_en1_intr_unmask; #ifdef SMP bind_func = ciu_en1_intr_bind; #endif } #if !defined(SMP) bind_func = NULL; #endif if ((event = *eventp) == NULL) { error = intr_event_create(eventp, (void *)(uintptr_t)irq, 0, irq, mask_func, unmask_func, NULL, bind_func, "int%d", irq); if (error != 0) return (error); event = *eventp; unmask_func((void *)(uintptr_t)irq); } intr_event_add_handler(event, device_get_nameunit(child), filter, intr, arg, intr_priority(flags), flags, cookiep); mips_intrcnt_setname(intrcnt, event->ie_fullname); return (0); } static int ciu_teardown_intr(device_t bus, device_t child, struct resource *res, void *cookie) { int error; error = intr_event_remove_handler(cookie); if (error != 0) return (error); return (0); } #ifdef SMP static int ciu_bind_intr(device_t bus, device_t child, struct resource *res, int cpu) { struct intr_event *event; int irq; irq = rman_get_start(res); if (irq <= CIU_IRQ_EN0_END) event = ciu_en0_intr_events[irq - CIU_IRQ_EN0_BEGIN]; else event = ciu_en1_intr_events[irq - CIU_IRQ_EN1_BEGIN]; return (intr_event_bind(event, cpu)); } #endif static int ciu_describe_intr(device_t bus, device_t child, struct resource *res, void *cookie, const char *descr) { struct intr_event *event; mips_intrcnt_t intrcnt; int error; int irq; irq = rman_get_start(res); if (irq <= CIU_IRQ_EN0_END) { event = ciu_en0_intr_events[irq - CIU_IRQ_EN0_BEGIN]; intrcnt = ciu_en0_intrcnt[irq - CIU_IRQ_EN0_BEGIN]; } else { event = ciu_en1_intr_events[irq - CIU_IRQ_EN1_BEGIN]; intrcnt = ciu_en1_intrcnt[irq - CIU_IRQ_EN1_BEGIN]; } error = intr_event_describe_handler(event, cookie, descr); if (error != 0) return (error); mips_intrcnt_setname(intrcnt, event->ie_fullname); return (0); } static void ciu_hinted_child(device_t bus, const char *dname, int dunit) { BUS_ADD_CHILD(bus, 0, dname, dunit); } static void ciu_en0_intr_mask(void *arg) { uint64_t mask; int irq; irq = (uintptr_t)arg; mask = cvmx_read_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2)); mask &= ~(1ull << (irq - CIU_IRQ_EN0_BEGIN)); cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2), mask); } static void ciu_en0_intr_unmask(void *arg) { uint64_t mask; int irq; irq = (uintptr_t)arg; mask = cvmx_read_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2)); mask |= 1ull << (irq - CIU_IRQ_EN0_BEGIN); cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2), mask); } #ifdef SMP static int ciu_en0_intr_bind(void *arg, int target) { uint64_t mask; int core; int irq; irq = (uintptr_t)arg; CPU_FOREACH(core) { mask = cvmx_read_csr(CVMX_CIU_INTX_EN0(core*2)); if (core == target) mask |= 1ull << (irq - CIU_IRQ_EN0_BEGIN); else mask &= ~(1ull << (irq - CIU_IRQ_EN0_BEGIN)); cvmx_write_csr(CVMX_CIU_INTX_EN0(core*2), mask); } return (0); } #endif static void ciu_en1_intr_mask(void *arg) { uint64_t mask; int irq; irq = (uintptr_t)arg; mask = cvmx_read_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2)); mask &= ~(1ull << (irq - CIU_IRQ_EN1_BEGIN)); cvmx_write_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2), mask); } static void ciu_en1_intr_unmask(void *arg) { uint64_t mask; int irq; irq = (uintptr_t)arg; mask = cvmx_read_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2)); mask |= 1ull << (irq - CIU_IRQ_EN1_BEGIN); cvmx_write_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2), mask); } #ifdef SMP static int ciu_en1_intr_bind(void *arg, int target) { uint64_t mask; int core; int irq; irq = (uintptr_t)arg; CPU_FOREACH(core) { mask = cvmx_read_csr(CVMX_CIU_INTX_EN1(core*2)); if (core == target) mask |= 1ull << (irq - CIU_IRQ_EN1_BEGIN); else mask &= ~(1ull << (irq - CIU_IRQ_EN1_BEGIN)); cvmx_write_csr(CVMX_CIU_INTX_EN1(core*2), mask); } return (0); } #endif static int ciu_intr(void *arg) { struct ciu_softc *sc; uint64_t en0_sum, en1_sum; uint64_t en0_mask, en1_mask; int irq_index; int error; sc = arg; (void)sc; en0_sum = cvmx_read_csr(CVMX_CIU_INTX_SUM0(cvmx_get_core_num()*2)); en1_sum = cvmx_read_csr(CVMX_CIU_INT_SUM1); en0_mask = cvmx_read_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2)); en1_mask = cvmx_read_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2)); en0_sum &= en0_mask; en1_sum &= en1_mask; if (en0_sum == 0 && en1_sum == 0) return (FILTER_STRAY); for (irq_index = 0; en0_sum != 0; irq_index++, en0_sum >>= 1) { if ((en0_sum & 1) == 0) continue; mips_intrcnt_inc(ciu_en0_intrcnt[irq_index]); error = intr_event_handle(ciu_en0_intr_events[irq_index], NULL); if (error != 0) printf("%s: stray en0 irq%d\n", __func__, irq_index); } for (irq_index = 0; en1_sum != 0; irq_index++, en1_sum >>= 1) { if ((en1_sum & 1) == 0) continue; mips_intrcnt_inc(ciu_en1_intrcnt[irq_index]); error = intr_event_handle(ciu_en1_intr_events[irq_index], NULL); if (error != 0) printf("%s: stray en1 irq%d\n", __func__, irq_index); } return (FILTER_HANDLED); } static device_method_t ciu_methods[] = { DEVMETHOD(device_probe, ciu_probe), DEVMETHOD(device_attach, ciu_attach), DEVMETHOD(bus_alloc_resource, ciu_alloc_resource), DEVMETHOD(bus_activate_resource,bus_generic_activate_resource), DEVMETHOD(bus_setup_intr, ciu_setup_intr), DEVMETHOD(bus_teardown_intr, ciu_teardown_intr), #ifdef SMP DEVMETHOD(bus_bind_intr, ciu_bind_intr), #endif DEVMETHOD(bus_describe_intr, ciu_describe_intr), DEVMETHOD(bus_add_child, bus_generic_add_child), DEVMETHOD(bus_hinted_child, ciu_hinted_child), { 0, 0 } }; static driver_t ciu_driver = { "ciu", ciu_methods, sizeof(struct ciu_softc), }; static devclass_t ciu_devclass; DRIVER_MODULE(ciu, nexus, ciu_driver, ciu_devclass, 0, 0); Index: head/sys/mips/cavium/cryptocteon/cavium_crypto.c =================================================================== --- head/sys/mips/cavium/cryptocteon/cavium_crypto.c (revision 326258) +++ head/sys/mips/cavium/cryptocteon/cavium_crypto.c (revision 326259) @@ -1,2136 +1,2138 @@ /* * vim:sw=4 ts=8 */ -/* +/*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright (c) 2009 David McCullough * * Copyright (c) 2003-2007 Cavium Networks (support@cavium.com). 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Cavium Networks * 4. Cavium Networks' name may not be used to endorse or promote products * derived from this software without specific prior written permission. * * This Software, including technical data, may be subject to U.S. export * control laws, including the U.S. Export Administration Act and its * associated regulations, and may be subject to export or import regulations * in other countries. You warrant that You will comply strictly in all * respects with all such regulations and acknowledge that you have the * responsibility to obtain licenses to export, re-export or import the * Software. * * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" AND * WITH ALL FAULTS AND CAVIUM MAKES NO PROMISES, REPRESENTATIONS OR WARRANTIES, * EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO THE * SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. */ /****************************************************************************/ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include /****************************************************************************/ #define IOV_INIT(iov, ptr, idx, len) \ do { \ (idx) = 0; \ (ptr) = (iov)[(idx)].iov_base; \ (len) = (iov)[(idx)].iov_len; \ } while (0) /* * XXX * It would be better if this were an IOV_READ/IOV_WRITE macro instead so * that we could detect overflow before it happens rather than right after, * which is especially bad since there is usually no IOV_CONSUME after the * final read or write. */ #define IOV_CONSUME(iov, ptr, idx, len) \ do { \ if ((len) > sizeof *(ptr)) { \ (len) -= sizeof *(ptr); \ (ptr)++; \ } else { \ if ((len) != sizeof *(ptr)) \ panic("%s: went past end of iovec.", __func__); \ (idx)++; \ (ptr) = (iov)[(idx)].iov_base; \ (len) = (iov)[(idx)].iov_len; \ } \ } while (0) #define ESP_HEADER_LENGTH 8 #define DES_CBC_IV_LENGTH 8 #define AES_CBC_IV_LENGTH 16 #define ESP_HMAC_LEN 12 #define ESP_HEADER_LENGTH 8 #define DES_CBC_IV_LENGTH 8 /****************************************************************************/ #define CVM_LOAD_SHA_UNIT(dat, next) { \ if (next == 0) { \ next = 1; \ CVMX_MT_HSH_DAT (dat, 0); \ } else if (next == 1) { \ next = 2; \ CVMX_MT_HSH_DAT (dat, 1); \ } else if (next == 2) { \ next = 3; \ CVMX_MT_HSH_DAT (dat, 2); \ } else if (next == 3) { \ next = 4; \ CVMX_MT_HSH_DAT (dat, 3); \ } else if (next == 4) { \ next = 5; \ CVMX_MT_HSH_DAT (dat, 4); \ } else if (next == 5) { \ next = 6; \ CVMX_MT_HSH_DAT (dat, 5); \ } else if (next == 6) { \ next = 7; \ CVMX_MT_HSH_DAT (dat, 6); \ } else { \ CVMX_MT_HSH_STARTSHA (dat); \ next = 0; \ } \ } #define CVM_LOAD2_SHA_UNIT(dat1, dat2, next) { \ if (next == 0) { \ CVMX_MT_HSH_DAT (dat1, 0); \ CVMX_MT_HSH_DAT (dat2, 1); \ next = 2; \ } else if (next == 1) { \ CVMX_MT_HSH_DAT (dat1, 1); \ CVMX_MT_HSH_DAT (dat2, 2); \ next = 3; \ } else if (next == 2) { \ CVMX_MT_HSH_DAT (dat1, 2); \ CVMX_MT_HSH_DAT (dat2, 3); \ next = 4; \ } else if (next == 3) { \ CVMX_MT_HSH_DAT (dat1, 3); \ CVMX_MT_HSH_DAT (dat2, 4); \ next = 5; \ } else if (next == 4) { \ CVMX_MT_HSH_DAT (dat1, 4); \ CVMX_MT_HSH_DAT (dat2, 5); \ next = 6; \ } else if (next == 5) { \ CVMX_MT_HSH_DAT (dat1, 5); \ CVMX_MT_HSH_DAT (dat2, 6); \ next = 7; \ } else if (next == 6) { \ CVMX_MT_HSH_DAT (dat1, 6); \ CVMX_MT_HSH_STARTSHA (dat2); \ next = 0; \ } else { \ CVMX_MT_HSH_STARTSHA (dat1); \ CVMX_MT_HSH_DAT (dat2, 0); \ next = 1; \ } \ } /****************************************************************************/ #define CVM_LOAD_MD5_UNIT(dat, next) { \ if (next == 0) { \ next = 1; \ CVMX_MT_HSH_DAT (dat, 0); \ } else if (next == 1) { \ next = 2; \ CVMX_MT_HSH_DAT (dat, 1); \ } else if (next == 2) { \ next = 3; \ CVMX_MT_HSH_DAT (dat, 2); \ } else if (next == 3) { \ next = 4; \ CVMX_MT_HSH_DAT (dat, 3); \ } else if (next == 4) { \ next = 5; \ CVMX_MT_HSH_DAT (dat, 4); \ } else if (next == 5) { \ next = 6; \ CVMX_MT_HSH_DAT (dat, 5); \ } else if (next == 6) { \ next = 7; \ CVMX_MT_HSH_DAT (dat, 6); \ } else { \ CVMX_MT_HSH_STARTMD5 (dat); \ next = 0; \ } \ } #define CVM_LOAD2_MD5_UNIT(dat1, dat2, next) { \ if (next == 0) { \ CVMX_MT_HSH_DAT (dat1, 0); \ CVMX_MT_HSH_DAT (dat2, 1); \ next = 2; \ } else if (next == 1) { \ CVMX_MT_HSH_DAT (dat1, 1); \ CVMX_MT_HSH_DAT (dat2, 2); \ next = 3; \ } else if (next == 2) { \ CVMX_MT_HSH_DAT (dat1, 2); \ CVMX_MT_HSH_DAT (dat2, 3); \ next = 4; \ } else if (next == 3) { \ CVMX_MT_HSH_DAT (dat1, 3); \ CVMX_MT_HSH_DAT (dat2, 4); \ next = 5; \ } else if (next == 4) { \ CVMX_MT_HSH_DAT (dat1, 4); \ CVMX_MT_HSH_DAT (dat2, 5); \ next = 6; \ } else if (next == 5) { \ CVMX_MT_HSH_DAT (dat1, 5); \ CVMX_MT_HSH_DAT (dat2, 6); \ next = 7; \ } else if (next == 6) { \ CVMX_MT_HSH_DAT (dat1, 6); \ CVMX_MT_HSH_STARTMD5 (dat2); \ next = 0; \ } else { \ CVMX_MT_HSH_STARTMD5 (dat1); \ CVMX_MT_HSH_DAT (dat2, 0); \ next = 1; \ } \ } /****************************************************************************/ void octo_calc_hash(uint8_t auth, unsigned char *key, uint64_t *inner, uint64_t *outer) { uint8_t hash_key[64]; uint64_t *key1; register uint64_t xor1 = 0x3636363636363636ULL; register uint64_t xor2 = 0x5c5c5c5c5c5c5c5cULL; dprintf("%s()\n", __func__); memset(hash_key, 0, sizeof(hash_key)); memcpy(hash_key, (uint8_t *) key, (auth ? 20 : 16)); key1 = (uint64_t *) hash_key; if (auth) { CVMX_MT_HSH_IV(0x67452301EFCDAB89ULL, 0); CVMX_MT_HSH_IV(0x98BADCFE10325476ULL, 1); CVMX_MT_HSH_IV(0xC3D2E1F000000000ULL, 2); } else { CVMX_MT_HSH_IV(0x0123456789ABCDEFULL, 0); CVMX_MT_HSH_IV(0xFEDCBA9876543210ULL, 1); } CVMX_MT_HSH_DAT((*key1 ^ xor1), 0); key1++; CVMX_MT_HSH_DAT((*key1 ^ xor1), 1); key1++; CVMX_MT_HSH_DAT((*key1 ^ xor1), 2); key1++; CVMX_MT_HSH_DAT((*key1 ^ xor1), 3); key1++; CVMX_MT_HSH_DAT((*key1 ^ xor1), 4); key1++; CVMX_MT_HSH_DAT((*key1 ^ xor1), 5); key1++; CVMX_MT_HSH_DAT((*key1 ^ xor1), 6); key1++; if (auth) CVMX_MT_HSH_STARTSHA((*key1 ^ xor1)); else CVMX_MT_HSH_STARTMD5((*key1 ^ xor1)); CVMX_MF_HSH_IV(inner[0], 0); CVMX_MF_HSH_IV(inner[1], 1); if (auth) { inner[2] = 0; CVMX_MF_HSH_IV(((uint64_t *) inner)[2], 2); } memset(hash_key, 0, sizeof(hash_key)); memcpy(hash_key, (uint8_t *) key, (auth ? 20 : 16)); key1 = (uint64_t *) hash_key; if (auth) { CVMX_MT_HSH_IV(0x67452301EFCDAB89ULL, 0); CVMX_MT_HSH_IV(0x98BADCFE10325476ULL, 1); CVMX_MT_HSH_IV(0xC3D2E1F000000000ULL, 2); } else { CVMX_MT_HSH_IV(0x0123456789ABCDEFULL, 0); CVMX_MT_HSH_IV(0xFEDCBA9876543210ULL, 1); } CVMX_MT_HSH_DAT((*key1 ^ xor2), 0); key1++; CVMX_MT_HSH_DAT((*key1 ^ xor2), 1); key1++; CVMX_MT_HSH_DAT((*key1 ^ xor2), 2); key1++; CVMX_MT_HSH_DAT((*key1 ^ xor2), 3); key1++; CVMX_MT_HSH_DAT((*key1 ^ xor2), 4); key1++; CVMX_MT_HSH_DAT((*key1 ^ xor2), 5); key1++; CVMX_MT_HSH_DAT((*key1 ^ xor2), 6); key1++; if (auth) CVMX_MT_HSH_STARTSHA((*key1 ^ xor2)); else CVMX_MT_HSH_STARTMD5((*key1 ^ xor2)); CVMX_MF_HSH_IV(outer[0], 0); CVMX_MF_HSH_IV(outer[1], 1); if (auth) { outer[2] = 0; CVMX_MF_HSH_IV(outer[2], 2); } return; } /****************************************************************************/ /* DES functions */ int octo_des_cbc_encrypt( struct octo_sess *od, struct iovec *iov, size_t iovcnt, size_t iovlen, int auth_off, int auth_len, int crypt_off, int crypt_len, int icv_off, uint8_t *ivp) { uint64_t *data; int data_i, data_l; dprintf("%s()\n", __func__); if (__predict_false(od == NULL || iov==NULL || iovlen==0 || ivp==NULL || (crypt_off & 0x7) || (crypt_off + crypt_len > iovlen))) { dprintf("%s: Bad parameters od=%p iov=%p iovlen=%jd " "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " "icv_off=%d ivp=%p\n", __func__, od, iov, iovlen, auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); return -EINVAL; } IOV_INIT(iov, data, data_i, data_l); CVMX_PREFETCH0(ivp); CVMX_PREFETCH0(od->octo_enckey); /* load 3DES Key */ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0); if (od->octo_encklen == 24) { CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[1], 1); CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[2], 2); } else if (od->octo_encklen == 8) { CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1); CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2); } else { dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen); return -EINVAL; } CVMX_MT_3DES_IV(* (uint64_t *) ivp); while (crypt_off > 0) { IOV_CONSUME(iov, data, data_i, data_l); crypt_off -= 8; } while (crypt_len > 0) { CVMX_MT_3DES_ENC_CBC(*data); CVMX_MF_3DES_RESULT(*data); IOV_CONSUME(iov, data, data_i, data_l); crypt_len -= 8; } return 0; } int octo_des_cbc_decrypt( struct octo_sess *od, struct iovec *iov, size_t iovcnt, size_t iovlen, int auth_off, int auth_len, int crypt_off, int crypt_len, int icv_off, uint8_t *ivp) { uint64_t *data; int data_i, data_l; dprintf("%s()\n", __func__); if (__predict_false(od == NULL || iov==NULL || iovlen==0 || ivp==NULL || (crypt_off & 0x7) || (crypt_off + crypt_len > iovlen))) { dprintf("%s: Bad parameters od=%p iov=%p iovlen=%jd " "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " "icv_off=%d ivp=%p\n", __func__, od, iov, iovlen, auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); return -EINVAL; } IOV_INIT(iov, data, data_i, data_l); CVMX_PREFETCH0(ivp); CVMX_PREFETCH0(od->octo_enckey); /* load 3DES Key */ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0); if (od->octo_encklen == 24) { CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[1], 1); CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[2], 2); } else if (od->octo_encklen == 8) { CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1); CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2); } else { dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen); return -EINVAL; } CVMX_MT_3DES_IV(* (uint64_t *) ivp); while (crypt_off > 0) { IOV_CONSUME(iov, data, data_i, data_l); crypt_off -= 8; } while (crypt_len > 0) { CVMX_MT_3DES_DEC_CBC(*data); CVMX_MF_3DES_RESULT(*data); IOV_CONSUME(iov, data, data_i, data_l); crypt_len -= 8; } return 0; } /****************************************************************************/ /* AES functions */ int octo_aes_cbc_encrypt( struct octo_sess *od, struct iovec *iov, size_t iovcnt, size_t iovlen, int auth_off, int auth_len, int crypt_off, int crypt_len, int icv_off, uint8_t *ivp) { uint64_t *data, *pdata; int data_i, data_l; dprintf("%s()\n", __func__); if (__predict_false(od == NULL || iov==NULL || iovlen==0 || ivp==NULL || (crypt_off & 0x7) || (crypt_off + crypt_len > iovlen))) { dprintf("%s: Bad parameters od=%p iov=%p iovlen=%jd " "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " "icv_off=%d ivp=%p\n", __func__, od, iov, iovlen, auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); return -EINVAL; } IOV_INIT(iov, data, data_i, data_l); CVMX_PREFETCH0(ivp); CVMX_PREFETCH0(od->octo_enckey); /* load AES Key */ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0); CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1); if (od->octo_encklen == 16) { CVMX_MT_AES_KEY(0x0, 2); CVMX_MT_AES_KEY(0x0, 3); } else if (od->octo_encklen == 24) { CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); CVMX_MT_AES_KEY(0x0, 3); } else if (od->octo_encklen == 32) { CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3); } else { dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen); return -EINVAL; } CVMX_MT_AES_KEYLENGTH(od->octo_encklen / 8 - 1); CVMX_MT_AES_IV(((uint64_t *) ivp)[0], 0); CVMX_MT_AES_IV(((uint64_t *) ivp)[1], 1); while (crypt_off > 0) { IOV_CONSUME(iov, data, data_i, data_l); crypt_off -= 8; } while (crypt_len > 0) { pdata = data; CVMX_MT_AES_ENC_CBC0(*data); IOV_CONSUME(iov, data, data_i, data_l); CVMX_MT_AES_ENC_CBC1(*data); CVMX_MF_AES_RESULT(*pdata, 0); CVMX_MF_AES_RESULT(*data, 1); IOV_CONSUME(iov, data, data_i, data_l); crypt_len -= 16; } return 0; } int octo_aes_cbc_decrypt( struct octo_sess *od, struct iovec *iov, size_t iovcnt, size_t iovlen, int auth_off, int auth_len, int crypt_off, int crypt_len, int icv_off, uint8_t *ivp) { uint64_t *data, *pdata; int data_i, data_l; dprintf("%s()\n", __func__); if (__predict_false(od == NULL || iov==NULL || iovlen==0 || ivp==NULL || (crypt_off & 0x7) || (crypt_off + crypt_len > iovlen))) { dprintf("%s: Bad parameters od=%p iov=%p iovlen=%jd " "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " "icv_off=%d ivp=%p\n", __func__, od, iov, iovlen, auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); return -EINVAL; } IOV_INIT(iov, data, data_i, data_l); CVMX_PREFETCH0(ivp); CVMX_PREFETCH0(od->octo_enckey); /* load AES Key */ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0); CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1); if (od->octo_encklen == 16) { CVMX_MT_AES_KEY(0x0, 2); CVMX_MT_AES_KEY(0x0, 3); } else if (od->octo_encklen == 24) { CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); CVMX_MT_AES_KEY(0x0, 3); } else if (od->octo_encklen == 32) { CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3); } else { dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen); return -EINVAL; } CVMX_MT_AES_KEYLENGTH(od->octo_encklen / 8 - 1); CVMX_MT_AES_IV(((uint64_t *) ivp)[0], 0); CVMX_MT_AES_IV(((uint64_t *) ivp)[1], 1); while (crypt_off > 0) { IOV_CONSUME(iov, data, data_i, data_l); crypt_off -= 8; } while (crypt_len > 0) { pdata = data; CVMX_MT_AES_DEC_CBC0(*data); IOV_CONSUME(iov, data, data_i, data_l); CVMX_MT_AES_DEC_CBC1(*data); CVMX_MF_AES_RESULT(*pdata, 0); CVMX_MF_AES_RESULT(*data, 1); IOV_CONSUME(iov, data, data_i, data_l); crypt_len -= 16; } return 0; } /****************************************************************************/ /* MD5 */ int octo_null_md5_encrypt( struct octo_sess *od, struct iovec *iov, size_t iovcnt, size_t iovlen, int auth_off, int auth_len, int crypt_off, int crypt_len, int icv_off, uint8_t *ivp) { int next = 0; uint64_t *data; uint64_t tmp1, tmp2; int data_i, data_l, alen = auth_len; dprintf("%s()\n", __func__); if (__predict_false(od == NULL || iov==NULL || iovlen==0 || (auth_off & 0x7) || (auth_off + auth_len > iovlen))) { dprintf("%s: Bad parameters od=%p iov=%p iovlen=%jd " "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " "icv_off=%d ivp=%p\n", __func__, od, iov, iovlen, auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); return -EINVAL; } IOV_INIT(iov, data, data_i, data_l); /* Load MD5 IV */ CVMX_MT_HSH_IV(od->octo_hminner[0], 0); CVMX_MT_HSH_IV(od->octo_hminner[1], 1); while (auth_off > 0) { IOV_CONSUME(iov, data, data_i, data_l); auth_off -= 8; } while (auth_len > 0) { CVM_LOAD_MD5_UNIT(*data, next); auth_len -= 8; IOV_CONSUME(iov, data, data_i, data_l); } /* finish the hash */ CVMX_PREFETCH0(od->octo_hmouter); #if 0 if (__predict_false(inplen)) { uint64_t tmp = 0; uint8_t *p = (uint8_t *) & tmp; p[inplen] = 0x80; do { inplen--; p[inplen] = ((uint8_t *) data)[inplen]; } while (inplen); CVM_LOAD_MD5_UNIT(tmp, next); } else { CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); } #else CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); #endif /* Finish Inner hash */ while (next != 7) { CVM_LOAD_MD5_UNIT(((uint64_t) 0x0ULL), next); } CVMX_ES64(tmp1, ((alen + 64) << 3)); CVM_LOAD_MD5_UNIT(tmp1, next); /* Get the inner hash of HMAC */ CVMX_MF_HSH_IV(tmp1, 0); CVMX_MF_HSH_IV(tmp2, 1); /* Initialize hash unit */ CVMX_MT_HSH_IV(od->octo_hmouter[0], 0); CVMX_MT_HSH_IV(od->octo_hmouter[1], 1); CVMX_MT_HSH_DAT(tmp1, 0); CVMX_MT_HSH_DAT(tmp2, 1); CVMX_MT_HSH_DAT(0x8000000000000000ULL, 2); CVMX_MT_HSH_DATZ(3); CVMX_MT_HSH_DATZ(4); CVMX_MT_HSH_DATZ(5); CVMX_MT_HSH_DATZ(6); CVMX_ES64(tmp1, ((64 + 16) << 3)); CVMX_MT_HSH_STARTMD5(tmp1); /* save the HMAC */ IOV_INIT(iov, data, data_i, data_l); while (icv_off > 0) { IOV_CONSUME(iov, data, data_i, data_l); icv_off -= 8; } CVMX_MF_HSH_IV(*data, 0); IOV_CONSUME(iov, data, data_i, data_l); CVMX_MF_HSH_IV(tmp1, 1); *(uint32_t *)data = (uint32_t) (tmp1 >> 32); return 0; } /****************************************************************************/ /* SHA1 */ int octo_null_sha1_encrypt( struct octo_sess *od, struct iovec *iov, size_t iovcnt, size_t iovlen, int auth_off, int auth_len, int crypt_off, int crypt_len, int icv_off, uint8_t *ivp) { int next = 0; uint64_t *data; uint64_t tmp1, tmp2, tmp3; int data_i, data_l, alen = auth_len; dprintf("%s()\n", __func__); if (__predict_false(od == NULL || iov==NULL || iovlen==0 || (auth_off & 0x7) || (auth_off + auth_len > iovlen))) { dprintf("%s: Bad parameters od=%p iov=%p iovlen=%jd " "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " "icv_off=%d ivp=%p\n", __func__, od, iov, iovlen, auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); return -EINVAL; } IOV_INIT(iov, data, data_i, data_l); /* Load SHA1 IV */ CVMX_MT_HSH_IV(od->octo_hminner[0], 0); CVMX_MT_HSH_IV(od->octo_hminner[1], 1); CVMX_MT_HSH_IV(od->octo_hminner[2], 2); while (auth_off > 0) { IOV_CONSUME(iov, data, data_i, data_l); auth_off -= 8; } while (auth_len > 0) { CVM_LOAD_SHA_UNIT(*data, next); auth_len -= 8; IOV_CONSUME(iov, data, data_i, data_l); } /* finish the hash */ CVMX_PREFETCH0(od->octo_hmouter); #if 0 if (__predict_false(inplen)) { uint64_t tmp = 0; uint8_t *p = (uint8_t *) & tmp; p[inplen] = 0x80; do { inplen--; p[inplen] = ((uint8_t *) data)[inplen]; } while (inplen); CVM_LOAD_MD5_UNIT(tmp, next); } else { CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); } #else CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next); #endif /* Finish Inner hash */ while (next != 7) { CVM_LOAD_SHA_UNIT(((uint64_t) 0x0ULL), next); } CVM_LOAD_SHA_UNIT((uint64_t) ((alen + 64) << 3), next); /* Get the inner hash of HMAC */ CVMX_MF_HSH_IV(tmp1, 0); CVMX_MF_HSH_IV(tmp2, 1); tmp3 = 0; CVMX_MF_HSH_IV(tmp3, 2); /* Initialize hash unit */ CVMX_MT_HSH_IV(od->octo_hmouter[0], 0); CVMX_MT_HSH_IV(od->octo_hmouter[1], 1); CVMX_MT_HSH_IV(od->octo_hmouter[2], 2); CVMX_MT_HSH_DAT(tmp1, 0); CVMX_MT_HSH_DAT(tmp2, 1); tmp3 |= 0x0000000080000000; CVMX_MT_HSH_DAT(tmp3, 2); CVMX_MT_HSH_DATZ(3); CVMX_MT_HSH_DATZ(4); CVMX_MT_HSH_DATZ(5); CVMX_MT_HSH_DATZ(6); CVMX_MT_HSH_STARTSHA((uint64_t) ((64 + 20) << 3)); /* save the HMAC */ IOV_INIT(iov, data, data_i, data_l); while (icv_off > 0) { IOV_CONSUME(iov, data, data_i, data_l); icv_off -= 8; } CVMX_MF_HSH_IV(*data, 0); IOV_CONSUME(iov, data, data_i, data_l); CVMX_MF_HSH_IV(tmp1, 1); *(uint32_t *)data = (uint32_t) (tmp1 >> 32); return 0; } /****************************************************************************/ /* DES MD5 */ int octo_des_cbc_md5_encrypt( struct octo_sess *od, struct iovec *iov, size_t iovcnt, size_t iovlen, int auth_off, int auth_len, int crypt_off, int crypt_len, int icv_off, uint8_t *ivp) { int next = 0; union { uint32_t data32[2]; uint64_t data64[1]; } mydata; uint64_t *data = &mydata.data64[0]; uint32_t *data32; uint64_t tmp1, tmp2; int data_i, data_l, alen = auth_len; dprintf("%s()\n", __func__); if (__predict_false(od == NULL || iov==NULL || iovlen==0 || ivp==NULL || (crypt_off & 0x3) || (crypt_off + crypt_len > iovlen) || (crypt_len & 0x7) || (auth_len & 0x7) || (auth_off & 0x3) || (auth_off + auth_len > iovlen))) { dprintf("%s: Bad parameters od=%p iov=%p iovlen=%jd " "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " "icv_off=%d ivp=%p\n", __func__, od, iov, iovlen, auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); return -EINVAL; } IOV_INIT(iov, data32, data_i, data_l); CVMX_PREFETCH0(ivp); CVMX_PREFETCH0(od->octo_enckey); /* load 3DES Key */ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0); if (od->octo_encklen == 24) { CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[1], 1); CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[2], 2); } else if (od->octo_encklen == 8) { CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1); CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2); } else { dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen); return -EINVAL; } CVMX_MT_3DES_IV(* (uint64_t *) ivp); /* Load MD5 IV */ CVMX_MT_HSH_IV(od->octo_hminner[0], 0); CVMX_MT_HSH_IV(od->octo_hminner[1], 1); while (crypt_off > 0 && auth_off > 0) { IOV_CONSUME(iov, data32, data_i, data_l); crypt_off -= 4; auth_off -= 4; } while (crypt_len > 0 || auth_len > 0) { uint32_t *first = data32; mydata.data32[0] = *first; IOV_CONSUME(iov, data32, data_i, data_l); mydata.data32[1] = *data32; if (crypt_off <= 0) { if (crypt_len > 0) { CVMX_MT_3DES_ENC_CBC(*data); CVMX_MF_3DES_RESULT(*data); crypt_len -= 8; } } else crypt_off -= 8; if (auth_off <= 0) { if (auth_len > 0) { CVM_LOAD_MD5_UNIT(*data, next); auth_len -= 8; } } else auth_off -= 8; *first = mydata.data32[0]; *data32 = mydata.data32[1]; IOV_CONSUME(iov, data32, data_i, data_l); } /* finish the hash */ CVMX_PREFETCH0(od->octo_hmouter); #if 0 if (__predict_false(inplen)) { uint64_t tmp = 0; uint8_t *p = (uint8_t *) & tmp; p[inplen] = 0x80; do { inplen--; p[inplen] = ((uint8_t *) data)[inplen]; } while (inplen); CVM_LOAD_MD5_UNIT(tmp, next); } else { CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); } #else CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); #endif /* Finish Inner hash */ while (next != 7) { CVM_LOAD_MD5_UNIT(((uint64_t) 0x0ULL), next); } CVMX_ES64(tmp1, ((alen + 64) << 3)); CVM_LOAD_MD5_UNIT(tmp1, next); /* Get the inner hash of HMAC */ CVMX_MF_HSH_IV(tmp1, 0); CVMX_MF_HSH_IV(tmp2, 1); /* Initialize hash unit */ CVMX_MT_HSH_IV(od->octo_hmouter[0], 0); CVMX_MT_HSH_IV(od->octo_hmouter[1], 1); CVMX_MT_HSH_DAT(tmp1, 0); CVMX_MT_HSH_DAT(tmp2, 1); CVMX_MT_HSH_DAT(0x8000000000000000ULL, 2); CVMX_MT_HSH_DATZ(3); CVMX_MT_HSH_DATZ(4); CVMX_MT_HSH_DATZ(5); CVMX_MT_HSH_DATZ(6); CVMX_ES64(tmp1, ((64 + 16) << 3)); CVMX_MT_HSH_STARTMD5(tmp1); /* save the HMAC */ IOV_INIT(iov, data32, data_i, data_l); while (icv_off > 0) { IOV_CONSUME(iov, data32, data_i, data_l); icv_off -= 4; } CVMX_MF_HSH_IV(tmp1, 0); *data32 = (uint32_t) (tmp1 >> 32); IOV_CONSUME(iov, data32, data_i, data_l); *data32 = (uint32_t) tmp1; IOV_CONSUME(iov, data32, data_i, data_l); CVMX_MF_HSH_IV(tmp1, 1); *data32 = (uint32_t) (tmp1 >> 32); return 0; } int octo_des_cbc_md5_decrypt( struct octo_sess *od, struct iovec *iov, size_t iovcnt, size_t iovlen, int auth_off, int auth_len, int crypt_off, int crypt_len, int icv_off, uint8_t *ivp) { int next = 0; union { uint32_t data32[2]; uint64_t data64[1]; } mydata; uint64_t *data = &mydata.data64[0]; uint32_t *data32; uint64_t tmp1, tmp2; int data_i, data_l, alen = auth_len; dprintf("%s()\n", __func__); if (__predict_false(od == NULL || iov==NULL || iovlen==0 || ivp==NULL || (crypt_off & 0x3) || (crypt_off + crypt_len > iovlen) || (crypt_len & 0x7) || (auth_len & 0x7) || (auth_off & 0x3) || (auth_off + auth_len > iovlen))) { dprintf("%s: Bad parameters od=%p iov=%p iovlen=%jd " "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " "icv_off=%d ivp=%p\n", __func__, od, iov, iovlen, auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); return -EINVAL; } IOV_INIT(iov, data32, data_i, data_l); CVMX_PREFETCH0(ivp); CVMX_PREFETCH0(od->octo_enckey); /* load 3DES Key */ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0); if (od->octo_encklen == 24) { CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[1], 1); CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[2], 2); } else if (od->octo_encklen == 8) { CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1); CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2); } else { dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen); return -EINVAL; } CVMX_MT_3DES_IV(* (uint64_t *) ivp); /* Load MD5 IV */ CVMX_MT_HSH_IV(od->octo_hminner[0], 0); CVMX_MT_HSH_IV(od->octo_hminner[1], 1); while (crypt_off > 0 && auth_off > 0) { IOV_CONSUME(iov, data32, data_i, data_l); crypt_off -= 4; auth_off -= 4; } while (crypt_len > 0 || auth_len > 0) { uint32_t *first = data32; mydata.data32[0] = *first; IOV_CONSUME(iov, data32, data_i, data_l); mydata.data32[1] = *data32; if (auth_off <= 0) { if (auth_len > 0) { CVM_LOAD_MD5_UNIT(*data, next); auth_len -= 8; } } else auth_off -= 8; if (crypt_off <= 0) { if (crypt_len > 0) { CVMX_MT_3DES_DEC_CBC(*data); CVMX_MF_3DES_RESULT(*data); crypt_len -= 8; } } else crypt_off -= 8; *first = mydata.data32[0]; *data32 = mydata.data32[1]; IOV_CONSUME(iov, data32, data_i, data_l); } /* finish the hash */ CVMX_PREFETCH0(od->octo_hmouter); #if 0 if (__predict_false(inplen)) { uint64_t tmp = 0; uint8_t *p = (uint8_t *) & tmp; p[inplen] = 0x80; do { inplen--; p[inplen] = ((uint8_t *) data)[inplen]; } while (inplen); CVM_LOAD_MD5_UNIT(tmp, next); } else { CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); } #else CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); #endif /* Finish Inner hash */ while (next != 7) { CVM_LOAD_MD5_UNIT(((uint64_t) 0x0ULL), next); } CVMX_ES64(tmp1, ((alen + 64) << 3)); CVM_LOAD_MD5_UNIT(tmp1, next); /* Get the inner hash of HMAC */ CVMX_MF_HSH_IV(tmp1, 0); CVMX_MF_HSH_IV(tmp2, 1); /* Initialize hash unit */ CVMX_MT_HSH_IV(od->octo_hmouter[0], 0); CVMX_MT_HSH_IV(od->octo_hmouter[1], 1); CVMX_MT_HSH_DAT(tmp1, 0); CVMX_MT_HSH_DAT(tmp2, 1); CVMX_MT_HSH_DAT(0x8000000000000000ULL, 2); CVMX_MT_HSH_DATZ(3); CVMX_MT_HSH_DATZ(4); CVMX_MT_HSH_DATZ(5); CVMX_MT_HSH_DATZ(6); CVMX_ES64(tmp1, ((64 + 16) << 3)); CVMX_MT_HSH_STARTMD5(tmp1); /* save the HMAC */ IOV_INIT(iov, data32, data_i, data_l); while (icv_off > 0) { IOV_CONSUME(iov, data32, data_i, data_l); icv_off -= 4; } CVMX_MF_HSH_IV(tmp1, 0); *data32 = (uint32_t) (tmp1 >> 32); IOV_CONSUME(iov, data32, data_i, data_l); *data32 = (uint32_t) tmp1; IOV_CONSUME(iov, data32, data_i, data_l); CVMX_MF_HSH_IV(tmp1, 1); *data32 = (uint32_t) (tmp1 >> 32); return 0; } /****************************************************************************/ /* DES SHA */ int octo_des_cbc_sha1_encrypt( struct octo_sess *od, struct iovec *iov, size_t iovcnt, size_t iovlen, int auth_off, int auth_len, int crypt_off, int crypt_len, int icv_off, uint8_t *ivp) { int next = 0; union { uint32_t data32[2]; uint64_t data64[1]; } mydata; uint64_t *data = &mydata.data64[0]; uint32_t *data32; uint64_t tmp1, tmp2, tmp3; int data_i, data_l, alen = auth_len; dprintf("%s()\n", __func__); if (__predict_false(od == NULL || iov==NULL || iovlen==0 || ivp==NULL || (crypt_off & 0x3) || (crypt_off + crypt_len > iovlen) || (crypt_len & 0x7) || (auth_len & 0x7) || (auth_off & 0x3) || (auth_off + auth_len > iovlen))) { dprintf("%s: Bad parameters od=%p iov=%p iovlen=%jd " "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " "icv_off=%d ivp=%p\n", __func__, od, iov, iovlen, auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); return -EINVAL; } IOV_INIT(iov, data32, data_i, data_l); CVMX_PREFETCH0(ivp); CVMX_PREFETCH0(od->octo_enckey); /* load 3DES Key */ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0); if (od->octo_encklen == 24) { CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[1], 1); CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[2], 2); } else if (od->octo_encklen == 8) { CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1); CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2); } else { dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen); return -EINVAL; } CVMX_MT_3DES_IV(* (uint64_t *) ivp); /* Load SHA1 IV */ CVMX_MT_HSH_IV(od->octo_hminner[0], 0); CVMX_MT_HSH_IV(od->octo_hminner[1], 1); CVMX_MT_HSH_IV(od->octo_hminner[2], 2); while (crypt_off > 0 && auth_off > 0) { IOV_CONSUME(iov, data32, data_i, data_l); crypt_off -= 4; auth_off -= 4; } while (crypt_len > 0 || auth_len > 0) { uint32_t *first = data32; mydata.data32[0] = *first; IOV_CONSUME(iov, data32, data_i, data_l); mydata.data32[1] = *data32; if (crypt_off <= 0) { if (crypt_len > 0) { CVMX_MT_3DES_ENC_CBC(*data); CVMX_MF_3DES_RESULT(*data); crypt_len -= 8; } } else crypt_off -= 8; if (auth_off <= 0) { if (auth_len > 0) { CVM_LOAD_SHA_UNIT(*data, next); auth_len -= 8; } } else auth_off -= 8; *first = mydata.data32[0]; *data32 = mydata.data32[1]; IOV_CONSUME(iov, data32, data_i, data_l); } /* finish the hash */ CVMX_PREFETCH0(od->octo_hmouter); #if 0 if (__predict_false(inplen)) { uint64_t tmp = 0; uint8_t *p = (uint8_t *) & tmp; p[inplen] = 0x80; do { inplen--; p[inplen] = ((uint8_t *) data)[inplen]; } while (inplen); CVM_LOAD_SHA_UNIT(tmp, next); } else { CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next); } #else CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next); #endif /* Finish Inner hash */ while (next != 7) { CVM_LOAD_SHA_UNIT(((uint64_t) 0x0ULL), next); } CVM_LOAD_SHA_UNIT((uint64_t) ((alen + 64) << 3), next); /* Get the inner hash of HMAC */ CVMX_MF_HSH_IV(tmp1, 0); CVMX_MF_HSH_IV(tmp2, 1); tmp3 = 0; CVMX_MF_HSH_IV(tmp3, 2); /* Initialize hash unit */ CVMX_MT_HSH_IV(od->octo_hmouter[0], 0); CVMX_MT_HSH_IV(od->octo_hmouter[1], 1); CVMX_MT_HSH_IV(od->octo_hmouter[2], 2); CVMX_MT_HSH_DAT(tmp1, 0); CVMX_MT_HSH_DAT(tmp2, 1); tmp3 |= 0x0000000080000000; CVMX_MT_HSH_DAT(tmp3, 2); CVMX_MT_HSH_DATZ(3); CVMX_MT_HSH_DATZ(4); CVMX_MT_HSH_DATZ(5); CVMX_MT_HSH_DATZ(6); CVMX_MT_HSH_STARTSHA((uint64_t) ((64 + 20) << 3)); /* save the HMAC */ IOV_INIT(iov, data32, data_i, data_l); while (icv_off > 0) { IOV_CONSUME(iov, data32, data_i, data_l); icv_off -= 4; } CVMX_MF_HSH_IV(tmp1, 0); *data32 = (uint32_t) (tmp1 >> 32); IOV_CONSUME(iov, data32, data_i, data_l); *data32 = (uint32_t) tmp1; IOV_CONSUME(iov, data32, data_i, data_l); CVMX_MF_HSH_IV(tmp1, 1); *data32 = (uint32_t) (tmp1 >> 32); return 0; } int octo_des_cbc_sha1_decrypt( struct octo_sess *od, struct iovec *iov, size_t iovcnt, size_t iovlen, int auth_off, int auth_len, int crypt_off, int crypt_len, int icv_off, uint8_t *ivp) { int next = 0; union { uint32_t data32[2]; uint64_t data64[1]; } mydata; uint64_t *data = &mydata.data64[0]; uint32_t *data32; uint64_t tmp1, tmp2, tmp3; int data_i, data_l, alen = auth_len; dprintf("%s()\n", __func__); if (__predict_false(od == NULL || iov==NULL || iovlen==0 || ivp==NULL || (crypt_off & 0x3) || (crypt_off + crypt_len > iovlen) || (crypt_len & 0x7) || (auth_len & 0x7) || (auth_off & 0x3) || (auth_off + auth_len > iovlen))) { dprintf("%s: Bad parameters od=%p iov=%p iovlen=%jd " "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " "icv_off=%d ivp=%p\n", __func__, od, iov, iovlen, auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); return -EINVAL; } IOV_INIT(iov, data32, data_i, data_l); CVMX_PREFETCH0(ivp); CVMX_PREFETCH0(od->octo_enckey); /* load 3DES Key */ CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 0); if (od->octo_encklen == 24) { CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[1], 1); CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[2], 2); } else if (od->octo_encklen == 8) { CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 1); CVMX_MT_3DES_KEY(((uint64_t *) od->octo_enckey)[0], 2); } else { dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen); return -EINVAL; } CVMX_MT_3DES_IV(* (uint64_t *) ivp); /* Load SHA1 IV */ CVMX_MT_HSH_IV(od->octo_hminner[0], 0); CVMX_MT_HSH_IV(od->octo_hminner[1], 1); CVMX_MT_HSH_IV(od->octo_hminner[2], 2); while (crypt_off > 0 && auth_off > 0) { IOV_CONSUME(iov, data32, data_i, data_l); crypt_off -= 4; auth_off -= 4; } while (crypt_len > 0 || auth_len > 0) { uint32_t *first = data32; mydata.data32[0] = *first; IOV_CONSUME(iov, data32, data_i, data_l); mydata.data32[1] = *data32; if (auth_off <= 0) { if (auth_len > 0) { CVM_LOAD_SHA_UNIT(*data, next); auth_len -= 8; } } else auth_off -= 8; if (crypt_off <= 0) { if (crypt_len > 0) { CVMX_MT_3DES_DEC_CBC(*data); CVMX_MF_3DES_RESULT(*data); crypt_len -= 8; } } else crypt_off -= 8; *first = mydata.data32[0]; *data32 = mydata.data32[1]; IOV_CONSUME(iov, data32, data_i, data_l); } /* finish the hash */ CVMX_PREFETCH0(od->octo_hmouter); #if 0 if (__predict_false(inplen)) { uint64_t tmp = 0; uint8_t *p = (uint8_t *) & tmp; p[inplen] = 0x80; do { inplen--; p[inplen] = ((uint8_t *) data)[inplen]; } while (inplen); CVM_LOAD_SHA_UNIT(tmp, next); } else { CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next); } #else CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next); #endif /* Finish Inner hash */ while (next != 7) { CVM_LOAD_SHA_UNIT(((uint64_t) 0x0ULL), next); } CVM_LOAD_SHA_UNIT((uint64_t) ((alen + 64) << 3), next); /* Get the inner hash of HMAC */ CVMX_MF_HSH_IV(tmp1, 0); CVMX_MF_HSH_IV(tmp2, 1); tmp3 = 0; CVMX_MF_HSH_IV(tmp3, 2); /* Initialize hash unit */ CVMX_MT_HSH_IV(od->octo_hmouter[0], 0); CVMX_MT_HSH_IV(od->octo_hmouter[1], 1); CVMX_MT_HSH_IV(od->octo_hmouter[2], 2); CVMX_MT_HSH_DAT(tmp1, 0); CVMX_MT_HSH_DAT(tmp2, 1); tmp3 |= 0x0000000080000000; CVMX_MT_HSH_DAT(tmp3, 2); CVMX_MT_HSH_DATZ(3); CVMX_MT_HSH_DATZ(4); CVMX_MT_HSH_DATZ(5); CVMX_MT_HSH_DATZ(6); CVMX_MT_HSH_STARTSHA((uint64_t) ((64 + 20) << 3)); /* save the HMAC */ IOV_INIT(iov, data32, data_i, data_l); while (icv_off > 0) { IOV_CONSUME(iov, data32, data_i, data_l); icv_off -= 4; } CVMX_MF_HSH_IV(tmp1, 0); *data32 = (uint32_t) (tmp1 >> 32); IOV_CONSUME(iov, data32, data_i, data_l); *data32 = (uint32_t) tmp1; IOV_CONSUME(iov, data32, data_i, data_l); CVMX_MF_HSH_IV(tmp1, 1); *data32 = (uint32_t) (tmp1 >> 32); return 0; } /****************************************************************************/ /* AES MD5 */ int octo_aes_cbc_md5_encrypt( struct octo_sess *od, struct iovec *iov, size_t iovcnt, size_t iovlen, int auth_off, int auth_len, int crypt_off, int crypt_len, int icv_off, uint8_t *ivp) { int next = 0; union { uint32_t data32[2]; uint64_t data64[1]; } mydata[2]; uint64_t *pdata = &mydata[0].data64[0]; uint64_t *data = &mydata[1].data64[0]; uint32_t *data32; uint64_t tmp1, tmp2; int data_i, data_l, alen = auth_len; dprintf("%s()\n", __func__); if (__predict_false(od == NULL || iov==NULL || iovlen==0 || ivp==NULL || (crypt_off & 0x3) || (crypt_off + crypt_len > iovlen) || (crypt_len & 0x7) || (auth_len & 0x7) || (auth_off & 0x3) || (auth_off + auth_len > iovlen))) { dprintf("%s: Bad parameters od=%p iov=%p iovlen=%jd " "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " "icv_off=%d ivp=%p\n", __func__, od, iov, iovlen, auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); return -EINVAL; } IOV_INIT(iov, data32, data_i, data_l); CVMX_PREFETCH0(ivp); CVMX_PREFETCH0(od->octo_enckey); /* load AES Key */ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0); CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1); if (od->octo_encklen == 16) { CVMX_MT_AES_KEY(0x0, 2); CVMX_MT_AES_KEY(0x0, 3); } else if (od->octo_encklen == 24) { CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); CVMX_MT_AES_KEY(0x0, 3); } else if (od->octo_encklen == 32) { CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3); } else { dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen); return -EINVAL; } CVMX_MT_AES_KEYLENGTH(od->octo_encklen / 8 - 1); CVMX_MT_AES_IV(((uint64_t *) ivp)[0], 0); CVMX_MT_AES_IV(((uint64_t *) ivp)[1], 1); /* Load MD5 IV */ CVMX_MT_HSH_IV(od->octo_hminner[0], 0); CVMX_MT_HSH_IV(od->octo_hminner[1], 1); while (crypt_off > 0 && auth_off > 0) { IOV_CONSUME(iov, data32, data_i, data_l); crypt_off -= 4; auth_off -= 4; } while (crypt_len > 0 || auth_len > 0) { uint32_t *pdata32[3]; pdata32[0] = data32; mydata[0].data32[0] = *data32; IOV_CONSUME(iov, data32, data_i, data_l); pdata32[1] = data32; mydata[0].data32[1] = *data32; IOV_CONSUME(iov, data32, data_i, data_l); pdata32[2] = data32; mydata[1].data32[0] = *data32; IOV_CONSUME(iov, data32, data_i, data_l); mydata[1].data32[1] = *data32; if (crypt_off <= 0) { if (crypt_len > 0) { CVMX_MT_AES_ENC_CBC0(*pdata); CVMX_MT_AES_ENC_CBC1(*data); CVMX_MF_AES_RESULT(*pdata, 0); CVMX_MF_AES_RESULT(*data, 1); crypt_len -= 16; } } else crypt_off -= 16; if (auth_off <= 0) { if (auth_len > 0) { CVM_LOAD_MD5_UNIT(*pdata, next); CVM_LOAD_MD5_UNIT(*data, next); auth_len -= 16; } } else auth_off -= 16; *pdata32[0] = mydata[0].data32[0]; *pdata32[1] = mydata[0].data32[1]; *pdata32[2] = mydata[1].data32[0]; *data32 = mydata[1].data32[1]; IOV_CONSUME(iov, data32, data_i, data_l); } /* finish the hash */ CVMX_PREFETCH0(od->octo_hmouter); #if 0 if (__predict_false(inplen)) { uint64_t tmp = 0; uint8_t *p = (uint8_t *) & tmp; p[inplen] = 0x80; do { inplen--; p[inplen] = ((uint8_t *) data)[inplen]; } while (inplen); CVM_LOAD_MD5_UNIT(tmp, next); } else { CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); } #else CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); #endif /* Finish Inner hash */ while (next != 7) { CVM_LOAD_MD5_UNIT(((uint64_t) 0x0ULL), next); } CVMX_ES64(tmp1, ((alen + 64) << 3)); CVM_LOAD_MD5_UNIT(tmp1, next); /* Get the inner hash of HMAC */ CVMX_MF_HSH_IV(tmp1, 0); CVMX_MF_HSH_IV(tmp2, 1); /* Initialize hash unit */ CVMX_MT_HSH_IV(od->octo_hmouter[0], 0); CVMX_MT_HSH_IV(od->octo_hmouter[1], 1); CVMX_MT_HSH_DAT(tmp1, 0); CVMX_MT_HSH_DAT(tmp2, 1); CVMX_MT_HSH_DAT(0x8000000000000000ULL, 2); CVMX_MT_HSH_DATZ(3); CVMX_MT_HSH_DATZ(4); CVMX_MT_HSH_DATZ(5); CVMX_MT_HSH_DATZ(6); CVMX_ES64(tmp1, ((64 + 16) << 3)); CVMX_MT_HSH_STARTMD5(tmp1); /* save the HMAC */ IOV_INIT(iov, data32, data_i, data_l); while (icv_off > 0) { IOV_CONSUME(iov, data32, data_i, data_l); icv_off -= 4; } CVMX_MF_HSH_IV(tmp1, 0); *data32 = (uint32_t) (tmp1 >> 32); IOV_CONSUME(iov, data32, data_i, data_l); *data32 = (uint32_t) tmp1; IOV_CONSUME(iov, data32, data_i, data_l); CVMX_MF_HSH_IV(tmp1, 1); *data32 = (uint32_t) (tmp1 >> 32); return 0; } int octo_aes_cbc_md5_decrypt( struct octo_sess *od, struct iovec *iov, size_t iovcnt, size_t iovlen, int auth_off, int auth_len, int crypt_off, int crypt_len, int icv_off, uint8_t *ivp) { int next = 0; union { uint32_t data32[2]; uint64_t data64[1]; } mydata[2]; uint64_t *pdata = &mydata[0].data64[0]; uint64_t *data = &mydata[1].data64[0]; uint32_t *data32; uint64_t tmp1, tmp2; int data_i, data_l, alen = auth_len; dprintf("%s()\n", __func__); if (__predict_false(od == NULL || iov==NULL || iovlen==0 || ivp==NULL || (crypt_off & 0x3) || (crypt_off + crypt_len > iovlen) || (crypt_len & 0x7) || (auth_len & 0x7) || (auth_off & 0x3) || (auth_off + auth_len > iovlen))) { dprintf("%s: Bad parameters od=%p iov=%p iovlen=%jd " "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " "icv_off=%d ivp=%p\n", __func__, od, iov, iovlen, auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); return -EINVAL; } IOV_INIT(iov, data32, data_i, data_l); CVMX_PREFETCH0(ivp); CVMX_PREFETCH0(od->octo_enckey); /* load AES Key */ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0); CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1); if (od->octo_encklen == 16) { CVMX_MT_AES_KEY(0x0, 2); CVMX_MT_AES_KEY(0x0, 3); } else if (od->octo_encklen == 24) { CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); CVMX_MT_AES_KEY(0x0, 3); } else if (od->octo_encklen == 32) { CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3); } else { dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen); return -EINVAL; } CVMX_MT_AES_KEYLENGTH(od->octo_encklen / 8 - 1); CVMX_MT_AES_IV(((uint64_t *) ivp)[0], 0); CVMX_MT_AES_IV(((uint64_t *) ivp)[1], 1); /* Load MD5 IV */ CVMX_MT_HSH_IV(od->octo_hminner[0], 0); CVMX_MT_HSH_IV(od->octo_hminner[1], 1); while (crypt_off > 0 && auth_off > 0) { IOV_CONSUME(iov, data32, data_i, data_l); crypt_off -= 4; auth_off -= 4; } while (crypt_len > 0 || auth_len > 0) { uint32_t *pdata32[3]; pdata32[0] = data32; mydata[0].data32[0] = *data32; IOV_CONSUME(iov, data32, data_i, data_l); pdata32[1] = data32; mydata[0].data32[1] = *data32; IOV_CONSUME(iov, data32, data_i, data_l); pdata32[2] = data32; mydata[1].data32[0] = *data32; IOV_CONSUME(iov, data32, data_i, data_l); mydata[1].data32[1] = *data32; if (auth_off <= 0) { if (auth_len > 0) { CVM_LOAD_MD5_UNIT(*pdata, next); CVM_LOAD_MD5_UNIT(*data, next); auth_len -= 16; } } else auth_off -= 16; if (crypt_off <= 0) { if (crypt_len > 0) { CVMX_MT_AES_DEC_CBC0(*pdata); CVMX_MT_AES_DEC_CBC1(*data); CVMX_MF_AES_RESULT(*pdata, 0); CVMX_MF_AES_RESULT(*data, 1); crypt_len -= 16; } } else crypt_off -= 16; *pdata32[0] = mydata[0].data32[0]; *pdata32[1] = mydata[0].data32[1]; *pdata32[2] = mydata[1].data32[0]; *data32 = mydata[1].data32[1]; IOV_CONSUME(iov, data32, data_i, data_l); } /* finish the hash */ CVMX_PREFETCH0(od->octo_hmouter); #if 0 if (__predict_false(inplen)) { uint64_t tmp = 0; uint8_t *p = (uint8_t *) & tmp; p[inplen] = 0x80; do { inplen--; p[inplen] = ((uint8_t *) data)[inplen]; } while (inplen); CVM_LOAD_MD5_UNIT(tmp, next); } else { CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); } #else CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); #endif /* Finish Inner hash */ while (next != 7) { CVM_LOAD_MD5_UNIT(((uint64_t) 0x0ULL), next); } CVMX_ES64(tmp1, ((alen + 64) << 3)); CVM_LOAD_MD5_UNIT(tmp1, next); /* Get the inner hash of HMAC */ CVMX_MF_HSH_IV(tmp1, 0); CVMX_MF_HSH_IV(tmp2, 1); /* Initialize hash unit */ CVMX_MT_HSH_IV(od->octo_hmouter[0], 0); CVMX_MT_HSH_IV(od->octo_hmouter[1], 1); CVMX_MT_HSH_DAT(tmp1, 0); CVMX_MT_HSH_DAT(tmp2, 1); CVMX_MT_HSH_DAT(0x8000000000000000ULL, 2); CVMX_MT_HSH_DATZ(3); CVMX_MT_HSH_DATZ(4); CVMX_MT_HSH_DATZ(5); CVMX_MT_HSH_DATZ(6); CVMX_ES64(tmp1, ((64 + 16) << 3)); CVMX_MT_HSH_STARTMD5(tmp1); /* save the HMAC */ IOV_INIT(iov, data32, data_i, data_l); while (icv_off > 0) { IOV_CONSUME(iov, data32, data_i, data_l); icv_off -= 4; } CVMX_MF_HSH_IV(tmp1, 0); *data32 = (uint32_t) (tmp1 >> 32); IOV_CONSUME(iov, data32, data_i, data_l); *data32 = (uint32_t) tmp1; IOV_CONSUME(iov, data32, data_i, data_l); CVMX_MF_HSH_IV(tmp1, 1); *data32 = (uint32_t) (tmp1 >> 32); return 0; } /****************************************************************************/ /* AES SHA1 */ int octo_aes_cbc_sha1_encrypt( struct octo_sess *od, struct iovec *iov, size_t iovcnt, size_t iovlen, int auth_off, int auth_len, int crypt_off, int crypt_len, int icv_off, uint8_t *ivp) { int next = 0; union { uint32_t data32[2]; uint64_t data64[1]; } mydata[2]; uint64_t *pdata = &mydata[0].data64[0]; uint64_t *data = &mydata[1].data64[0]; uint32_t *data32; uint64_t tmp1, tmp2, tmp3; int data_i, data_l, alen = auth_len; dprintf("%s()\n", __func__); if (__predict_false(od == NULL || iov==NULL || iovlen==0 || ivp==NULL || (crypt_off & 0x3) || (crypt_off + crypt_len > iovlen) || (crypt_len & 0x7) || (auth_len & 0x7) || (auth_off & 0x3) || (auth_off + auth_len > iovlen))) { dprintf("%s: Bad parameters od=%p iov=%p iovlen=%jd " "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " "icv_off=%d ivp=%p\n", __func__, od, iov, iovlen, auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); return -EINVAL; } IOV_INIT(iov, data32, data_i, data_l); CVMX_PREFETCH0(ivp); CVMX_PREFETCH0(od->octo_enckey); /* load AES Key */ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0); CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1); if (od->octo_encklen == 16) { CVMX_MT_AES_KEY(0x0, 2); CVMX_MT_AES_KEY(0x0, 3); } else if (od->octo_encklen == 24) { CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); CVMX_MT_AES_KEY(0x0, 3); } else if (od->octo_encklen == 32) { CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3); } else { dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen); return -EINVAL; } CVMX_MT_AES_KEYLENGTH(od->octo_encklen / 8 - 1); CVMX_MT_AES_IV(((uint64_t *) ivp)[0], 0); CVMX_MT_AES_IV(((uint64_t *) ivp)[1], 1); /* Load SHA IV */ CVMX_MT_HSH_IV(od->octo_hminner[0], 0); CVMX_MT_HSH_IV(od->octo_hminner[1], 1); CVMX_MT_HSH_IV(od->octo_hminner[2], 2); while (crypt_off > 0 && auth_off > 0) { IOV_CONSUME(iov, data32, data_i, data_l); crypt_off -= 4; auth_off -= 4; } while (crypt_len > 0 || auth_len > 0) { uint32_t *pdata32[3]; pdata32[0] = data32; mydata[0].data32[0] = *data32; IOV_CONSUME(iov, data32, data_i, data_l); pdata32[1] = data32; mydata[0].data32[1] = *data32; IOV_CONSUME(iov, data32, data_i, data_l); pdata32[2] = data32; mydata[1].data32[0] = *data32; IOV_CONSUME(iov, data32, data_i, data_l); mydata[1].data32[1] = *data32; if (crypt_off <= 0) { if (crypt_len > 0) { CVMX_MT_AES_ENC_CBC0(*pdata); CVMX_MT_AES_ENC_CBC1(*data); CVMX_MF_AES_RESULT(*pdata, 0); CVMX_MF_AES_RESULT(*data, 1); crypt_len -= 16; } } else crypt_off -= 16; if (auth_off <= 0) { if (auth_len > 0) { CVM_LOAD_SHA_UNIT(*pdata, next); CVM_LOAD_SHA_UNIT(*data, next); auth_len -= 16; } } else auth_off -= 16; *pdata32[0] = mydata[0].data32[0]; *pdata32[1] = mydata[0].data32[1]; *pdata32[2] = mydata[1].data32[0]; *data32 = mydata[1].data32[1]; IOV_CONSUME(iov, data32, data_i, data_l); } /* finish the hash */ CVMX_PREFETCH0(od->octo_hmouter); #if 0 if (__predict_false(inplen)) { uint64_t tmp = 0; uint8_t *p = (uint8_t *) & tmp; p[inplen] = 0x80; do { inplen--; p[inplen] = ((uint8_t *) data)[inplen]; } while (inplen); CVM_LOAD_SHA_UNIT(tmp, next); } else { CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next); } #else CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next); #endif /* Finish Inner hash */ while (next != 7) { CVM_LOAD_SHA_UNIT(((uint64_t) 0x0ULL), next); } CVM_LOAD_SHA_UNIT((uint64_t) ((alen + 64) << 3), next); /* Get the inner hash of HMAC */ CVMX_MF_HSH_IV(tmp1, 0); CVMX_MF_HSH_IV(tmp2, 1); tmp3 = 0; CVMX_MF_HSH_IV(tmp3, 2); /* Initialize hash unit */ CVMX_MT_HSH_IV(od->octo_hmouter[0], 0); CVMX_MT_HSH_IV(od->octo_hmouter[1], 1); CVMX_MT_HSH_IV(od->octo_hmouter[2], 2); CVMX_MT_HSH_DAT(tmp1, 0); CVMX_MT_HSH_DAT(tmp2, 1); tmp3 |= 0x0000000080000000; CVMX_MT_HSH_DAT(tmp3, 2); CVMX_MT_HSH_DATZ(3); CVMX_MT_HSH_DATZ(4); CVMX_MT_HSH_DATZ(5); CVMX_MT_HSH_DATZ(6); CVMX_MT_HSH_STARTSHA((uint64_t) ((64 + 20) << 3)); /* finish the hash */ CVMX_PREFETCH0(od->octo_hmouter); #if 0 if (__predict_false(inplen)) { uint64_t tmp = 0; uint8_t *p = (uint8_t *) & tmp; p[inplen] = 0x80; do { inplen--; p[inplen] = ((uint8_t *) data)[inplen]; } while (inplen); CVM_LOAD_MD5_UNIT(tmp, next); } else { CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); } #else CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); #endif /* save the HMAC */ IOV_INIT(iov, data32, data_i, data_l); while (icv_off > 0) { IOV_CONSUME(iov, data32, data_i, data_l); icv_off -= 4; } CVMX_MF_HSH_IV(tmp1, 0); *data32 = (uint32_t) (tmp1 >> 32); IOV_CONSUME(iov, data32, data_i, data_l); *data32 = (uint32_t) tmp1; IOV_CONSUME(iov, data32, data_i, data_l); CVMX_MF_HSH_IV(tmp1, 1); *data32 = (uint32_t) (tmp1 >> 32); return 0; } int octo_aes_cbc_sha1_decrypt( struct octo_sess *od, struct iovec *iov, size_t iovcnt, size_t iovlen, int auth_off, int auth_len, int crypt_off, int crypt_len, int icv_off, uint8_t *ivp) { int next = 0; union { uint32_t data32[2]; uint64_t data64[1]; } mydata[2]; uint64_t *pdata = &mydata[0].data64[0]; uint64_t *data = &mydata[1].data64[0]; uint32_t *data32; uint64_t tmp1, tmp2, tmp3; int data_i, data_l, alen = auth_len; dprintf("%s()\n", __func__); if (__predict_false(od == NULL || iov==NULL || iovlen==0 || ivp==NULL || (crypt_off & 0x3) || (crypt_off + crypt_len > iovlen) || (crypt_len & 0x7) || (auth_len & 0x7) || (auth_off & 0x3) || (auth_off + auth_len > iovlen))) { dprintf("%s: Bad parameters od=%p iov=%p iovlen=%jd " "auth_off=%d auth_len=%d crypt_off=%d crypt_len=%d " "icv_off=%d ivp=%p\n", __func__, od, iov, iovlen, auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp); return -EINVAL; } IOV_INIT(iov, data32, data_i, data_l); CVMX_PREFETCH0(ivp); CVMX_PREFETCH0(od->octo_enckey); /* load AES Key */ CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[0], 0); CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[1], 1); if (od->octo_encklen == 16) { CVMX_MT_AES_KEY(0x0, 2); CVMX_MT_AES_KEY(0x0, 3); } else if (od->octo_encklen == 24) { CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); CVMX_MT_AES_KEY(0x0, 3); } else if (od->octo_encklen == 32) { CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[2], 2); CVMX_MT_AES_KEY(((uint64_t *) od->octo_enckey)[3], 3); } else { dprintf("%s: Bad key length %d\n", __func__, od->octo_encklen); return -EINVAL; } CVMX_MT_AES_KEYLENGTH(od->octo_encklen / 8 - 1); CVMX_MT_AES_IV(((uint64_t *) ivp)[0], 0); CVMX_MT_AES_IV(((uint64_t *) ivp)[1], 1); /* Load MD5 IV */ CVMX_MT_HSH_IV(od->octo_hminner[0], 0); CVMX_MT_HSH_IV(od->octo_hminner[1], 1); CVMX_MT_HSH_IV(od->octo_hminner[2], 2); while (crypt_off > 0 && auth_off > 0) { IOV_CONSUME(iov, data32, data_i, data_l); crypt_off -= 4; auth_off -= 4; } while (crypt_len > 0 || auth_len > 0) { uint32_t *pdata32[3]; pdata32[0] = data32; mydata[0].data32[0] = *data32; IOV_CONSUME(iov, data32, data_i, data_l); pdata32[1] = data32; mydata[0].data32[1] = *data32; IOV_CONSUME(iov, data32, data_i, data_l); pdata32[2] = data32; mydata[1].data32[0] = *data32; IOV_CONSUME(iov, data32, data_i, data_l); mydata[1].data32[1] = *data32; if (auth_off <= 0) { if (auth_len > 0) { CVM_LOAD_SHA_UNIT(*pdata, next); CVM_LOAD_SHA_UNIT(*data, next); auth_len -= 16; } } else auth_off -= 16; if (crypt_off <= 0) { if (crypt_len > 0) { CVMX_MT_AES_DEC_CBC0(*pdata); CVMX_MT_AES_DEC_CBC1(*data); CVMX_MF_AES_RESULT(*pdata, 0); CVMX_MF_AES_RESULT(*data, 1); crypt_len -= 16; } } else crypt_off -= 16; *pdata32[0] = mydata[0].data32[0]; *pdata32[1] = mydata[0].data32[1]; *pdata32[2] = mydata[1].data32[0]; *data32 = mydata[1].data32[1]; IOV_CONSUME(iov, data32, data_i, data_l); } /* finish the hash */ CVMX_PREFETCH0(od->octo_hmouter); #if 0 if (__predict_false(inplen)) { uint64_t tmp = 0; uint8_t *p = (uint8_t *) & tmp; p[inplen] = 0x80; do { inplen--; p[inplen] = ((uint8_t *) data)[inplen]; } while (inplen); CVM_LOAD_SHA_UNIT(tmp, next); } else { CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next); } #else CVM_LOAD_SHA_UNIT(0x8000000000000000ULL, next); #endif /* Finish Inner hash */ while (next != 7) { CVM_LOAD_SHA_UNIT(((uint64_t) 0x0ULL), next); } CVM_LOAD_SHA_UNIT((uint64_t) ((alen + 64) << 3), next); /* Get the inner hash of HMAC */ CVMX_MF_HSH_IV(tmp1, 0); CVMX_MF_HSH_IV(tmp2, 1); tmp3 = 0; CVMX_MF_HSH_IV(tmp3, 2); /* Initialize hash unit */ CVMX_MT_HSH_IV(od->octo_hmouter[0], 0); CVMX_MT_HSH_IV(od->octo_hmouter[1], 1); CVMX_MT_HSH_IV(od->octo_hmouter[2], 2); CVMX_MT_HSH_DAT(tmp1, 0); CVMX_MT_HSH_DAT(tmp2, 1); tmp3 |= 0x0000000080000000; CVMX_MT_HSH_DAT(tmp3, 2); CVMX_MT_HSH_DATZ(3); CVMX_MT_HSH_DATZ(4); CVMX_MT_HSH_DATZ(5); CVMX_MT_HSH_DATZ(6); CVMX_MT_HSH_STARTSHA((uint64_t) ((64 + 20) << 3)); /* finish the hash */ CVMX_PREFETCH0(od->octo_hmouter); #if 0 if (__predict_false(inplen)) { uint64_t tmp = 0; uint8_t *p = (uint8_t *) & tmp; p[inplen] = 0x80; do { inplen--; p[inplen] = ((uint8_t *) data)[inplen]; } while (inplen); CVM_LOAD_MD5_UNIT(tmp, next); } else { CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); } #else CVM_LOAD_MD5_UNIT(0x8000000000000000ULL, next); #endif /* save the HMAC */ IOV_INIT(iov, data32, data_i, data_l); while (icv_off > 0) { IOV_CONSUME(iov, data32, data_i, data_l); icv_off -= 4; } CVMX_MF_HSH_IV(tmp1, 0); *data32 = (uint32_t) (tmp1 >> 32); IOV_CONSUME(iov, data32, data_i, data_l); *data32 = (uint32_t) tmp1; IOV_CONSUME(iov, data32, data_i, data_l); CVMX_MF_HSH_IV(tmp1, 1); *data32 = (uint32_t) (tmp1 >> 32); return 0; } /****************************************************************************/ Index: head/sys/mips/cavium/if_octm.c =================================================================== --- head/sys/mips/cavium/if_octm.c (revision 326258) +++ head/sys/mips/cavium/if_octm.c (revision 326259) @@ -1,538 +1,540 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010-2011 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$ */ /* * Cavium Octeon management port Ethernet devices. */ #include "opt_inet.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef INET #include #include #endif #include #include #include struct octm_softc { struct ifnet *sc_ifp; device_t sc_dev; unsigned sc_port; int sc_flags; struct ifmedia sc_ifmedia; struct resource *sc_intr; void *sc_intr_cookie; }; static void octm_identify(driver_t *, device_t); static int octm_probe(device_t); static int octm_attach(device_t); static int octm_detach(device_t); static int octm_shutdown(device_t); static void octm_init(void *); static int octm_transmit(struct ifnet *, struct mbuf *); static int octm_medchange(struct ifnet *); static void octm_medstat(struct ifnet *, struct ifmediareq *); static int octm_ioctl(struct ifnet *, u_long, caddr_t); static void octm_rx_intr(void *); static device_method_t octm_methods[] = { /* Device interface */ DEVMETHOD(device_identify, octm_identify), DEVMETHOD(device_probe, octm_probe), DEVMETHOD(device_attach, octm_attach), DEVMETHOD(device_detach, octm_detach), DEVMETHOD(device_shutdown, octm_shutdown), { 0, 0 } }; static driver_t octm_driver = { "octm", octm_methods, sizeof (struct octm_softc), }; static devclass_t octm_devclass; DRIVER_MODULE(octm, ciu, octm_driver, octm_devclass, 0, 0); static void octm_identify(driver_t *drv, device_t parent) { unsigned i; if (!octeon_has_feature(OCTEON_FEATURE_MGMT_PORT)) return; for (i = 0; i < CVMX_MGMT_PORT_NUM_PORTS; i++) BUS_ADD_CHILD(parent, 0, "octm", i); } static int octm_probe(device_t dev) { cvmx_mgmt_port_result_t result; result = cvmx_mgmt_port_initialize(device_get_unit(dev)); switch (result) { case CVMX_MGMT_PORT_SUCCESS: break; case CVMX_MGMT_PORT_NO_MEMORY: return (ENOBUFS); case CVMX_MGMT_PORT_INVALID_PARAM: return (ENXIO); case CVMX_MGMT_PORT_INIT_ERROR: return (EIO); } device_set_desc(dev, "Cavium Octeon Management Ethernet"); return (0); } static int octm_attach(device_t dev) { struct ifnet *ifp; struct octm_softc *sc; cvmx_mixx_irhwm_t mixx_irhwm; cvmx_mixx_intena_t mixx_intena; uint64_t mac; int error; int irq; int rid; sc = device_get_softc(dev); sc->sc_dev = dev; sc->sc_port = device_get_unit(dev); switch (sc->sc_port) { case 0: irq = OCTEON_IRQ_MII; break; case 1: irq = OCTEON_IRQ_MII1; break; default: device_printf(dev, "unsupported management port %u.\n", sc->sc_port); return (ENXIO); } /* * Set MAC address for this management port. */ mac = 0; memcpy((u_int8_t *)&mac + 2, cvmx_sysinfo_get()->mac_addr_base, 6); mac += sc->sc_port; cvmx_mgmt_port_set_mac(sc->sc_port, mac); /* No watermark for input ring. */ mixx_irhwm.u64 = 0; cvmx_write_csr(CVMX_MIXX_IRHWM(sc->sc_port), mixx_irhwm.u64); /* Enable input ring interrupts. */ mixx_intena.u64 = 0; mixx_intena.s.ithena = 1; cvmx_write_csr(CVMX_MIXX_INTENA(sc->sc_port), mixx_intena.u64); /* Allocate and establish interrupt. */ rid = 0; sc->sc_intr = bus_alloc_resource(sc->sc_dev, SYS_RES_IRQ, &rid, irq, irq, 1, RF_ACTIVE); if (sc->sc_intr == NULL) { device_printf(dev, "unable to allocate IRQ.\n"); return (ENXIO); } error = bus_setup_intr(sc->sc_dev, sc->sc_intr, INTR_TYPE_NET, NULL, octm_rx_intr, sc, &sc->sc_intr_cookie); if (error != 0) { device_printf(dev, "unable to setup interrupt.\n"); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_intr); return (ENXIO); } bus_describe_intr(sc->sc_dev, sc->sc_intr, sc->sc_intr_cookie, "rx"); /* XXX Possibly should enable TX interrupts. */ ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { device_printf(dev, "cannot allocate ifnet.\n"); bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_intr); return (ENOMEM); } if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_mtu = ETHERMTU; ifp->if_init = octm_init; ifp->if_softc = sc; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_ALLMULTI; ifp->if_ioctl = octm_ioctl; sc->sc_ifp = ifp; sc->sc_flags = ifp->if_flags; ifmedia_init(&sc->sc_ifmedia, 0, octm_medchange, octm_medstat); ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL); ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO); ether_ifattach(ifp, (const u_int8_t *)&mac + 2); ifp->if_transmit = octm_transmit; ifp->if_hdrlen = sizeof(struct ether_vlan_header); ifp->if_capabilities = IFCAP_VLAN_MTU; ifp->if_capenable = ifp->if_capabilities; IFQ_SET_MAXLEN(&ifp->if_snd, CVMX_MGMT_PORT_NUM_TX_BUFFERS); ifp->if_snd.ifq_drv_maxlen = CVMX_MGMT_PORT_NUM_TX_BUFFERS; IFQ_SET_READY(&ifp->if_snd); return (bus_generic_attach(dev)); } static int octm_detach(device_t dev) { struct octm_softc *sc; cvmx_mgmt_port_result_t result; sc = device_get_softc(dev); result = cvmx_mgmt_port_initialize(sc->sc_port); switch (result) { case CVMX_MGMT_PORT_SUCCESS: break; case CVMX_MGMT_PORT_NO_MEMORY: return (ENOBUFS); case CVMX_MGMT_PORT_INVALID_PARAM: return (ENXIO); case CVMX_MGMT_PORT_INIT_ERROR: return (EIO); } bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_intr); /* XXX Incomplete. */ return (0); } static int octm_shutdown(device_t dev) { return (octm_detach(dev)); } static void octm_init(void *arg) { struct ifnet *ifp; struct octm_softc *sc; cvmx_mgmt_port_netdevice_flags_t flags; uint64_t mac; sc = arg; ifp = sc->sc_ifp; if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { cvmx_mgmt_port_disable(sc->sc_port); ifp->if_drv_flags &= ~IFF_DRV_RUNNING; } /* * NB: * MAC must be set before allmulti and promisc below, as * cvmx_mgmt_port_set_mac will always enable the CAM, and turning on * promiscuous mode only works with the CAM disabled. */ mac = 0; memcpy((u_int8_t *)&mac + 2, IF_LLADDR(ifp), 6); cvmx_mgmt_port_set_mac(sc->sc_port, mac); /* * This is done unconditionally, rather than only if sc_flags have * changed because of set_mac's effect on the CAM noted above. */ flags = 0; if ((ifp->if_flags & IFF_ALLMULTI) != 0) flags |= CVMX_IFF_ALLMULTI; if ((ifp->if_flags & IFF_PROMISC) != 0) flags |= CVMX_IFF_PROMISC; cvmx_mgmt_port_set_multicast_list(sc->sc_port, flags); /* XXX link state? */ if ((ifp->if_flags & IFF_UP) != 0) cvmx_mgmt_port_enable(sc->sc_port); ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; } static int octm_transmit(struct ifnet *ifp, struct mbuf *m) { struct octm_softc *sc; cvmx_mgmt_port_result_t result; sc = ifp->if_softc; if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING) { m_freem(m); return (0); } result = cvmx_mgmt_port_sendm(sc->sc_port, m); if (result == CVMX_MGMT_PORT_SUCCESS) { ETHER_BPF_MTAP(ifp, m); if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len); } else if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); m_freem(m); switch (result) { case CVMX_MGMT_PORT_SUCCESS: return (0); case CVMX_MGMT_PORT_NO_MEMORY: return (ENOBUFS); case CVMX_MGMT_PORT_INVALID_PARAM: return (ENXIO); case CVMX_MGMT_PORT_INIT_ERROR: return (EIO); default: return (EDOOFUS); } } static int octm_medchange(struct ifnet *ifp) { return (ENOTSUP); } static void octm_medstat(struct ifnet *ifp, struct ifmediareq *ifm) { struct octm_softc *sc; cvmx_helper_link_info_t link_info; sc = ifp->if_softc; ifm->ifm_status = IFM_AVALID; ifm->ifm_active = IFT_ETHER; link_info = cvmx_mgmt_port_link_get(sc->sc_port); if (!link_info.s.link_up) return; ifm->ifm_status |= IFM_ACTIVE; switch (link_info.s.speed) { case 10: ifm->ifm_active |= IFM_10_T; break; case 100: ifm->ifm_active |= IFM_100_TX; break; case 1000: ifm->ifm_active |= IFM_1000_T; break; case 10000: ifm->ifm_active |= IFM_10G_T; break; } if (link_info.s.full_duplex) ifm->ifm_active |= IFM_FDX; else ifm->ifm_active |= IFM_HDX; } static int octm_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { struct octm_softc *sc; struct ifreq *ifr; #ifdef INET struct ifaddr *ifa; #endif int error; sc = ifp->if_softc; ifr = (struct ifreq *)data; #ifdef INET ifa = (struct ifaddr *)data; #endif switch (cmd) { case SIOCSIFADDR: #ifdef INET /* * Avoid reinitialization unless it's necessary. */ if (ifa->ifa_addr->sa_family == AF_INET) { ifp->if_flags |= IFF_UP; if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) octm_init(sc); arp_ifinit(ifp, ifa); return (0); } #endif error = ether_ioctl(ifp, cmd, data); if (error != 0) return (error); return (0); case SIOCSIFFLAGS: if (ifp->if_flags == sc->sc_flags) return (0); if ((ifp->if_flags & IFF_UP) != 0) { octm_init(sc); } else { if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { cvmx_mgmt_port_disable(sc->sc_port); ifp->if_drv_flags &= ~IFF_DRV_RUNNING; } } sc->sc_flags = ifp->if_flags; return (0); case SIOCSIFCAP: /* * Just change the capabilities in software, currently none * require reprogramming hardware, they just toggle whether we * make use of already-present facilities in software. */ ifp->if_capenable = ifr->ifr_reqcap; return (0); case SIOCSIFMTU: cvmx_mgmt_port_set_max_packet_size(sc->sc_port, ifr->ifr_mtu + ifp->if_hdrlen); return (0); case SIOCSIFMEDIA: case SIOCGIFMEDIA: error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd); if (error != 0) return (error); return (0); default: error = ether_ioctl(ifp, cmd, data); if (error != 0) return (error); return (0); } } static void octm_rx_intr(void *arg) { struct octm_softc *sc = arg; cvmx_mixx_isr_t mixx_isr; int len; mixx_isr.u64 = cvmx_read_csr(CVMX_MIXX_ISR(sc->sc_port)); if (!mixx_isr.s.irthresh) { device_printf(sc->sc_dev, "stray interrupt.\n"); return; } for (;;) { struct mbuf *m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (m == NULL) { device_printf(sc->sc_dev, "no memory for receive mbuf.\n"); return; } len = cvmx_mgmt_port_receive(sc->sc_port, MCLBYTES, m->m_data); if (len > 0) { m->m_pkthdr.rcvif = sc->sc_ifp; m->m_pkthdr.len = m->m_len = len; if_inc_counter(sc->sc_ifp, IFCOUNTER_IPACKETS, 1); (*sc->sc_ifp->if_input)(sc->sc_ifp, m); continue; } m_freem(m); if (len == 0) break; if_inc_counter(sc->sc_ifp, IFCOUNTER_IERRORS, 1); } /* Acknowledge interrupts. */ cvmx_write_csr(CVMX_MIXX_ISR(sc->sc_port), mixx_isr.u64); cvmx_read_csr(CVMX_MIXX_ISR(sc->sc_port)); } Index: head/sys/mips/cavium/obio.c =================================================================== --- head/sys/mips/cavium/obio.c (revision 326258) +++ head/sys/mips/cavium/obio.c (revision 326259) @@ -1,207 +1,209 @@ /* $NetBSD: obio.c,v 1.11 2003/07/15 00:25:05 lukem Exp $ */ /*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright (c) 2001, 2002, 2003 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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. */ /* * On-board device autoconfiguration support for Cavium OCTEON 1 family of * SoC devices. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include extern struct bus_space octeon_uart_tag; static void obio_identify(driver_t *, device_t); static int obio_probe(device_t); static int obio_attach(device_t); static void obio_identify(driver_t *drv, device_t parent) { BUS_ADD_CHILD(parent, 0, "obio", 0); } static int obio_probe(device_t dev) { if (device_get_unit(dev) != 0) return (ENXIO); return (0); } static int obio_attach(device_t dev) { struct obio_softc *sc = device_get_softc(dev); sc->oba_st = mips_bus_space_generic; /* * XXX * Here and elsewhere using RBR as a base address because it kind of * is, but that feels pretty sloppy. Should consider adding a define * that's more semantic, at least. */ sc->oba_addr = CVMX_MIO_UARTX_RBR(0); sc->oba_size = 0x10000; sc->oba_rman.rm_type = RMAN_ARRAY; sc->oba_rman.rm_descr = "OBIO I/O"; if (rman_init(&sc->oba_rman) != 0 || rman_manage_region(&sc->oba_rman, sc->oba_addr, sc->oba_addr + sc->oba_size) != 0) panic("obio_attach: failed to set up I/O rman"); sc->oba_irq_rman.rm_type = RMAN_ARRAY; sc->oba_irq_rman.rm_descr = "OBIO IRQ"; /* * This module is intended for UART purposes only and * manages IRQs for UART0 and UART1. */ if (rman_init(&sc->oba_irq_rman) != 0 || rman_manage_region(&sc->oba_irq_rman, OCTEON_IRQ_UART0, OCTEON_IRQ_UART1) != 0) panic("obio_attach: failed to set up IRQ rman"); device_add_child(dev, "uart", 1); /* Setup Uart-1 first. */ device_add_child(dev, "uart", 0); /* Uart-0 next. So it is first in console list */ bus_generic_probe(dev); bus_generic_attach(dev); return (0); } static struct resource * obio_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct resource *rv; struct rman *rm; bus_space_tag_t bt = 0; bus_space_handle_t bh = 0; struct obio_softc *sc = device_get_softc(bus); switch (type) { case SYS_RES_IRQ: switch (device_get_unit(child)) { case 0: start = end = OCTEON_IRQ_UART0; break; case 1: start = end = OCTEON_IRQ_UART1; break; default: return (NULL); } rm = &sc->oba_irq_rman; break; case SYS_RES_MEMORY: return (NULL); case SYS_RES_IOPORT: rm = &sc->oba_rman; bt = &octeon_uart_tag; bh = CVMX_MIO_UARTX_RBR(device_get_unit(child)); start = bh; break; default: return (NULL); } rv = rman_reserve_resource(rm, start, end, count, flags, child); if (rv == NULL) { return (NULL); } if (type == SYS_RES_IRQ) { return (rv); } rman_set_rid(rv, *rid); rman_set_bustag(rv, bt); rman_set_bushandle(rv, bh); if (0) { if (bus_activate_resource(child, type, *rid, rv)) { rman_release_resource(rv); return (NULL); } } return (rv); } static int obio_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { return (0); } static device_method_t obio_methods[] = { /* Device methods */ DEVMETHOD(device_identify, obio_identify), DEVMETHOD(device_probe, obio_probe), DEVMETHOD(device_attach, obio_attach), /* Bus methods */ DEVMETHOD(bus_alloc_resource, obio_alloc_resource), DEVMETHOD(bus_activate_resource,obio_activate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_add_child, bus_generic_add_child), {0, 0}, }; static driver_t obio_driver = { "obio", obio_methods, sizeof(struct obio_softc), }; static devclass_t obio_devclass; DRIVER_MODULE(obio, ciu, obio_driver, obio_devclass, 0, 0); Index: head/sys/mips/cavium/obiovar.h =================================================================== --- head/sys/mips/cavium/obiovar.h (revision 326258) +++ head/sys/mips/cavium/obiovar.h (revision 326259) @@ -1,55 +1,57 @@ /* $NetBSD: obiovar.h,v 1.4 2003/06/16 17:40:53 thorpej Exp $ */ /*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright (c) 2002, 2003 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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$ * */ #ifndef _OCTEON_OBIOVAR_H_ #define _OCTEON_OBIOVAR_H_ #include struct obio_softc { bus_space_tag_t oba_st; /* bus space tag */ bus_addr_t oba_addr; /* address of device */ bus_size_t oba_size; /* size of device */ struct rman oba_rman; struct rman oba_irq_rman; }; #endif /* _OCTEON_OBIOVAR_H_ */ Index: head/sys/mips/cavium/octe/ethernet-mv88e61xx.c =================================================================== --- head/sys/mips/cavium/octe/ethernet-mv88e61xx.c (revision 326258) +++ head/sys/mips/cavium/octe/ethernet-mv88e61xx.c (revision 326259) @@ -1,128 +1,130 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 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$ */ /* * Interface to the Marvell 88E61XX SMI/MDIO. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include "wrapper-cvmx-includes.h" #include "ethernet-headers.h" #define MV88E61XX_SMI_REG_CMD 0x00 /* Indirect command register. */ #define MV88E61XX_SMI_CMD_BUSY 0x8000 /* Busy bit. */ #define MV88E61XX_SMI_CMD_22 0x1000 /* Clause 22 (default 45.) */ #define MV88E61XX_SMI_CMD_READ 0x0800 /* Read command. */ #define MV88E61XX_SMI_CMD_WRITE 0x0400 /* Write command. */ #define MV88E61XX_SMI_CMD_PHY(phy) (((phy) & 0x1f) << 5) #define MV88E61XX_SMI_CMD_REG(reg) ((reg) & 0x1f) #define MV88E61XX_SMI_REG_DAT 0x01 /* Indirect data register. */ static int cvm_oct_mv88e61xx_smi_read(struct ifnet *, int, int); static void cvm_oct_mv88e61xx_smi_write(struct ifnet *, int, int, int); static int cvm_oct_mv88e61xx_smi_wait(struct ifnet *); int cvm_oct_mv88e61xx_setup_device(struct ifnet *ifp) { cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; priv->mdio_read = cvm_oct_mv88e61xx_smi_read; priv->mdio_write = cvm_oct_mv88e61xx_smi_write; priv->phy_device = "mv88e61xxphy"; return (0); } static int cvm_oct_mv88e61xx_smi_read(struct ifnet *ifp, int phy_id, int location) { cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; int error; error = cvm_oct_mv88e61xx_smi_wait(ifp); if (error != 0) return (0); cvm_oct_mdio_write(ifp, priv->phy_id, MV88E61XX_SMI_REG_CMD, MV88E61XX_SMI_CMD_BUSY | MV88E61XX_SMI_CMD_22 | MV88E61XX_SMI_CMD_READ | MV88E61XX_SMI_CMD_PHY(phy_id) | MV88E61XX_SMI_CMD_REG(location)); error = cvm_oct_mv88e61xx_smi_wait(ifp); if (error != 0) return (0); return (cvm_oct_mdio_read(ifp, priv->phy_id, MV88E61XX_SMI_REG_DAT)); } static void cvm_oct_mv88e61xx_smi_write(struct ifnet *ifp, int phy_id, int location, int val) { cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; cvm_oct_mv88e61xx_smi_wait(ifp); cvm_oct_mdio_write(ifp, priv->phy_id, MV88E61XX_SMI_REG_DAT, val); cvm_oct_mdio_write(ifp, priv->phy_id, MV88E61XX_SMI_REG_CMD, MV88E61XX_SMI_CMD_BUSY | MV88E61XX_SMI_CMD_22 | MV88E61XX_SMI_CMD_WRITE | MV88E61XX_SMI_CMD_PHY(phy_id) | MV88E61XX_SMI_CMD_REG(location)); cvm_oct_mv88e61xx_smi_wait(ifp); } static int cvm_oct_mv88e61xx_smi_wait(struct ifnet *ifp) { cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc; uint16_t cmd; unsigned i; for (i = 0; i < 10000; i++) { cmd = cvm_oct_mdio_read(ifp, priv->phy_id, MV88E61XX_SMI_REG_CMD); if ((cmd & MV88E61XX_SMI_CMD_BUSY) == 0) return (0); } return (ETIMEDOUT); } Index: head/sys/mips/cavium/octe/ethernet-mv88e61xx.h =================================================================== --- head/sys/mips/cavium/octe/ethernet-mv88e61xx.h (revision 326258) +++ head/sys/mips/cavium/octe/ethernet-mv88e61xx.h (revision 326259) @@ -1,34 +1,36 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 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$ */ #ifndef _CAVIUM_OCTE_ETHERNET_MV88E61XX_H_ #define _CAVIUM_OCTE_ETHERNET_MV88E61XX_H_ int cvm_oct_mv88e61xx_setup_device(struct ifnet *ifp); #endif /* !_CAVIUM_OCTE_ETHERNET_MV88E61XX_H_ */ Index: head/sys/mips/cavium/octe/mv88e61xxphy.c =================================================================== --- head/sys/mips/cavium/octe/mv88e61xxphy.c (revision 326258) +++ head/sys/mips/cavium/octe/mv88e61xxphy.c (revision 326259) @@ -1,630 +1,632 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 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 __FBSDID("$FreeBSD$"); /* * Driver for the Marvell 88E61xx family of switch PHYs */ #include #include #include #include #include #include #include #include #include #include #include #include "miibus_if.h" #include "mv88e61xxphyreg.h" struct mv88e61xxphy_softc; struct mv88e61xxphy_port_softc { struct mv88e61xxphy_softc *sc_switch; unsigned sc_port; unsigned sc_domain; unsigned sc_vlan; unsigned sc_priority; unsigned sc_flags; }; #define MV88E61XXPHY_PORT_FLAG_VTU_UPDATE (0x0001) struct mv88e61xxphy_softc { device_t sc_dev; struct mv88e61xxphy_port_softc sc_ports[MV88E61XX_PORTS]; }; enum mv88e61xxphy_vtu_membership_type { MV88E61XXPHY_VTU_UNMODIFIED, MV88E61XXPHY_VTU_UNTAGGED, MV88E61XXPHY_VTU_TAGGED, MV88E61XXPHY_VTU_DISCARDED, }; enum mv88e61xxphy_sysctl_link_type { MV88E61XXPHY_LINK_SYSCTL_DUPLEX, MV88E61XXPHY_LINK_SYSCTL_LINK, MV88E61XXPHY_LINK_SYSCTL_MEDIA, }; enum mv88e61xxphy_sysctl_port_type { MV88E61XXPHY_PORT_SYSCTL_DOMAIN, MV88E61XXPHY_PORT_SYSCTL_VLAN, MV88E61XXPHY_PORT_SYSCTL_PRIORITY, }; /* * Register access macros. */ #define MV88E61XX_READ(sc, phy, reg) \ MIIBUS_READREG(device_get_parent((sc)->sc_dev), (phy), (reg)) #define MV88E61XX_WRITE(sc, phy, reg, val) \ MIIBUS_WRITEREG(device_get_parent((sc)->sc_dev), (phy), (reg), (val)) #define MV88E61XX_READ_PORT(psc, reg) \ MV88E61XX_READ((psc)->sc_switch, MV88E61XX_PORT((psc)->sc_port), (reg)) #define MV88E61XX_WRITE_PORT(psc, reg, val) \ MV88E61XX_WRITE((psc)->sc_switch, MV88E61XX_PORT((psc)->sc_port), (reg), (val)) static int mv88e61xxphy_probe(device_t); static int mv88e61xxphy_attach(device_t); static void mv88e61xxphy_init(struct mv88e61xxphy_softc *); static void mv88e61xxphy_init_port(struct mv88e61xxphy_port_softc *); static void mv88e61xxphy_init_vtu(struct mv88e61xxphy_softc *); static int mv88e61xxphy_sysctl_link_proc(SYSCTL_HANDLER_ARGS); static int mv88e61xxphy_sysctl_port_proc(SYSCTL_HANDLER_ARGS); static void mv88e61xxphy_vtu_load(struct mv88e61xxphy_softc *, uint16_t); static void mv88e61xxphy_vtu_set_membership(struct mv88e61xxphy_softc *, unsigned, enum mv88e61xxphy_vtu_membership_type); static void mv88e61xxphy_vtu_wait(struct mv88e61xxphy_softc *); static int mv88e61xxphy_probe(device_t dev) { uint16_t val; val = MIIBUS_READREG(device_get_parent(dev), MV88E61XX_PORT(0), MV88E61XX_PORT_REVISION); switch (val >> 4) { case 0x121: device_set_desc(dev, "Marvell Link Street 88E6123 3-Port Gigabit Switch"); return (0); case 0x161: device_set_desc(dev, "Marvell Link Street 88E6161 6-Port Gigabit Switch"); return (0); case 0x165: device_set_desc(dev, "Marvell Link Street 88E6161 6-Port Advanced Gigabit Switch"); return (0); default: return (ENXIO); } } static int mv88e61xxphy_attach(device_t dev) { char portbuf[] = "N"; struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); struct sysctl_oid *tree = device_get_sysctl_tree(dev); struct sysctl_oid_list *child = SYSCTL_CHILDREN(tree); struct sysctl_oid *port_node, *portN_node; struct sysctl_oid_list *port_tree, *portN_tree; struct mv88e61xxphy_softc *sc; unsigned port; sc = device_get_softc(dev); sc->sc_dev = dev; /* * Initialize port softcs. */ for (port = 0; port < MV88E61XX_PORTS; port++) { struct mv88e61xxphy_port_softc *psc; psc = &sc->sc_ports[port]; psc->sc_switch = sc; psc->sc_port = port; psc->sc_domain = 0; /* One broadcast domain by default. */ psc->sc_vlan = port + 1; /* Tag VLANs by default. */ psc->sc_priority = 0; /* No default special priority. */ psc->sc_flags = 0; } /* * Add per-port sysctl tree/handlers. */ port_node = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "port", CTLFLAG_RD, NULL, "Switch Ports"); port_tree = SYSCTL_CHILDREN(port_node); for (port = 0; port < MV88E61XX_PORTS; port++) { struct mv88e61xxphy_port_softc *psc; psc = &sc->sc_ports[port]; portbuf[0] = '0' + port; portN_node = SYSCTL_ADD_NODE(ctx, port_tree, OID_AUTO, portbuf, CTLFLAG_RD, NULL, "Switch Port"); portN_tree = SYSCTL_CHILDREN(portN_node); SYSCTL_ADD_PROC(ctx, portN_tree, OID_AUTO, "duplex", CTLFLAG_RD | CTLTYPE_INT, psc, MV88E61XXPHY_LINK_SYSCTL_DUPLEX, mv88e61xxphy_sysctl_link_proc, "IU", "Media duplex status (0 = half duplex; 1 = full duplex)"); SYSCTL_ADD_PROC(ctx, portN_tree, OID_AUTO, "link", CTLFLAG_RD | CTLTYPE_INT, psc, MV88E61XXPHY_LINK_SYSCTL_LINK, mv88e61xxphy_sysctl_link_proc, "IU", "Link status (0 = down; 1 = up)"); SYSCTL_ADD_PROC(ctx, portN_tree, OID_AUTO, "media", CTLFLAG_RD | CTLTYPE_INT, psc, MV88E61XXPHY_LINK_SYSCTL_MEDIA, mv88e61xxphy_sysctl_link_proc, "IU", "Media speed (0 = unknown; 10 = 10Mbps; 100 = 100Mbps; 1000 = 1Gbps)"); SYSCTL_ADD_PROC(ctx, portN_tree, OID_AUTO, "domain", CTLFLAG_RW | CTLTYPE_INT, psc, MV88E61XXPHY_PORT_SYSCTL_DOMAIN, mv88e61xxphy_sysctl_port_proc, "IU", "Broadcast domain (ports can only talk to other ports in the same domain)"); SYSCTL_ADD_PROC(ctx, portN_tree, OID_AUTO, "vlan", CTLFLAG_RW | CTLTYPE_INT, psc, MV88E61XXPHY_PORT_SYSCTL_VLAN, mv88e61xxphy_sysctl_port_proc, "IU", "Tag packets from/for this port with a given VLAN."); SYSCTL_ADD_PROC(ctx, portN_tree, OID_AUTO, "priority", CTLFLAG_RW | CTLTYPE_INT, psc, MV88E61XXPHY_PORT_SYSCTL_PRIORITY, mv88e61xxphy_sysctl_port_proc, "IU", "Default packet priority for this port."); } mv88e61xxphy_init(sc); return (0); } static void mv88e61xxphy_init(struct mv88e61xxphy_softc *sc) { unsigned port; uint16_t val; unsigned i; /* Disable all ports. */ for (port = 0; port < MV88E61XX_PORTS; port++) { struct mv88e61xxphy_port_softc *psc; psc = &sc->sc_ports[port]; val = MV88E61XX_READ_PORT(psc, MV88E61XX_PORT_CONTROL); val &= ~0x3; MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_CONTROL, val); } DELAY(2000); /* Reset the switch. */ MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_CONTROL, 0xc400); for (i = 0; i < 100; i++) { val = MV88E61XX_READ(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_STATUS); if ((val & 0xc800) == 0xc800) break; DELAY(10); } if (i == 100) { device_printf(sc->sc_dev, "%s: switch reset timed out.\n", __func__); return; } /* Disable PPU. */ MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_CONTROL, 0x0000); /* Configure host port and send monitor frames to it. */ MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_MONITOR, (MV88E61XX_HOST_PORT << 12) | (MV88E61XX_HOST_PORT << 8) | (MV88E61XX_HOST_PORT << 4)); /* Disable remote management. */ MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_REMOTE_MGMT, 0x0000); /* Send all specifically-addressed frames to the host port. */ MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL2, MV88E61XX_GLOBAL2_MANAGE_2X, 0xffff); MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL2, MV88E61XX_GLOBAL2_MANAGE_0X, 0xffff); /* Remove provider-supplied tag and use it for switching. */ MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL2, MV88E61XX_GLOBAL2_CONTROL2, MV88E61XX_GLOBAL2_CONTROL2_REMOVE_PTAG); /* Configure all ports. */ for (port = 0; port < MV88E61XX_PORTS; port++) { struct mv88e61xxphy_port_softc *psc; psc = &sc->sc_ports[port]; mv88e61xxphy_init_port(psc); } /* Reprogram VLAN table (VTU.) */ mv88e61xxphy_init_vtu(sc); /* Enable all ports. */ for (port = 0; port < MV88E61XX_PORTS; port++) { struct mv88e61xxphy_port_softc *psc; psc = &sc->sc_ports[port]; val = MV88E61XX_READ_PORT(psc, MV88E61XX_PORT_CONTROL); val |= 0x3; MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_CONTROL, val); } } static void mv88e61xxphy_init_port(struct mv88e61xxphy_port_softc *psc) { struct mv88e61xxphy_softc *sc; unsigned allow_mask; sc = psc->sc_switch; /* Set media type and flow control. */ if (psc->sc_port != MV88E61XX_HOST_PORT) { /* Don't force any media type or flow control. */ MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_FORCE_MAC, 0x0003); } else { /* Make CPU port 1G FDX. */ MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_FORCE_MAC, 0x003e); } /* Don't limit flow control pauses. */ MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_PAUSE_CONTROL, 0x0000); /* Set various port functions per Linux. */ if (psc->sc_port != MV88E61XX_HOST_PORT) { MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_CONTROL, 0x04bc); } else { /* * Send frames for unknown unicast and multicast groups to * host, too. */ MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_CONTROL, 0x063f); } if (psc->sc_port != MV88E61XX_HOST_PORT) { /* Disable trunking. */ MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_CONTROL2, 0x0000); } else { /* Disable trunking and send learn messages to host. */ MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_CONTROL2, 0x8000); } /* * Port-based VLAN map; isolates MAC tables and forces ports to talk * only to the host. * * Always allow the host to send to all ports and allow all ports to * send to the host. */ if (psc->sc_port != MV88E61XX_HOST_PORT) { allow_mask = 1 << MV88E61XX_HOST_PORT; } else { allow_mask = (1 << MV88E61XX_PORTS) - 1; allow_mask &= ~(1 << MV88E61XX_HOST_PORT); } MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_VLAN_MAP, (psc->sc_domain << 12) | allow_mask); /* VLAN tagging. Set default priority and VLAN tag (or none.) */ MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_VLAN, (psc->sc_priority << 14) | psc->sc_vlan); if (psc->sc_port == MV88E61XX_HOST_PORT) { /* Set provider ingress tag. */ MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_PROVIDER_PROTO, ETHERTYPE_VLAN); /* Set provider egress tag. */ MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_ETHER_PROTO, ETHERTYPE_VLAN); /* Use secure 802.1q mode and accept only tagged frames. */ MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_FILTER, MV88E61XX_PORT_FILTER_MAP_DEST | MV88E61XX_PORT_FILTER_8021Q_SECURE | MV88E61XX_PORT_FILTER_DISCARD_UNTAGGED); } else { /* Don't allow tagged frames. */ MV88E61XX_WRITE_PORT(psc, MV88E61XX_PORT_FILTER, MV88E61XX_PORT_FILTER_MAP_DEST | MV88E61XX_PORT_FILTER_DISCARD_TAGGED); } } static void mv88e61xxphy_init_vtu(struct mv88e61xxphy_softc *sc) { unsigned port; /* * Start flush of the VTU. */ mv88e61xxphy_vtu_wait(sc); MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_VTU_OP, MV88E61XX_GLOBAL_VTU_OP_BUSY | MV88E61XX_GLOBAL_VTU_OP_OP_FLUSH); /* * Queue each port's VLAN to be programmed. */ for (port = 0; port < MV88E61XX_PORTS; port++) { struct mv88e61xxphy_port_softc *psc; psc = &sc->sc_ports[port]; psc->sc_flags &= ~MV88E61XXPHY_PORT_FLAG_VTU_UPDATE; if (psc->sc_vlan == 0) continue; psc->sc_flags |= MV88E61XXPHY_PORT_FLAG_VTU_UPDATE; } /* * Program each VLAN that is in use. */ for (port = 0; port < MV88E61XX_PORTS; port++) { struct mv88e61xxphy_port_softc *psc; psc = &sc->sc_ports[port]; if ((psc->sc_flags & MV88E61XXPHY_PORT_FLAG_VTU_UPDATE) == 0) continue; mv88e61xxphy_vtu_load(sc, psc->sc_vlan); } /* * Wait for last pending VTU operation to complete. */ mv88e61xxphy_vtu_wait(sc); } static int mv88e61xxphy_sysctl_link_proc(SYSCTL_HANDLER_ARGS) { struct mv88e61xxphy_port_softc *psc = arg1; enum mv88e61xxphy_sysctl_link_type type = arg2; uint16_t val; unsigned out; val = MV88E61XX_READ_PORT(psc, MV88E61XX_PORT_STATUS); switch (type) { case MV88E61XXPHY_LINK_SYSCTL_DUPLEX: if ((val & MV88E61XX_PORT_STATUS_DUPLEX) != 0) out = 1; else out = 0; break; case MV88E61XXPHY_LINK_SYSCTL_LINK: if ((val & MV88E61XX_PORT_STATUS_LINK) != 0) out = 1; else out = 0; break; case MV88E61XXPHY_LINK_SYSCTL_MEDIA: switch (val & MV88E61XX_PORT_STATUS_MEDIA) { case MV88E61XX_PORT_STATUS_MEDIA_10M: out = 10; break; case MV88E61XX_PORT_STATUS_MEDIA_100M: out = 100; break; case MV88E61XX_PORT_STATUS_MEDIA_1G: out = 1000; break; default: out = 0; break; } break; default: return (EINVAL); } return (sysctl_handle_int(oidp, NULL, out, req)); } static int mv88e61xxphy_sysctl_port_proc(SYSCTL_HANDLER_ARGS) { struct mv88e61xxphy_port_softc *psc = arg1; enum mv88e61xxphy_sysctl_port_type type = arg2; struct mv88e61xxphy_softc *sc = psc->sc_switch; unsigned max, val, *valp; int error; switch (type) { case MV88E61XXPHY_PORT_SYSCTL_DOMAIN: valp = &psc->sc_domain; max = 0xf; break; case MV88E61XXPHY_PORT_SYSCTL_VLAN: valp = &psc->sc_vlan; max = 0x1000; break; case MV88E61XXPHY_PORT_SYSCTL_PRIORITY: valp = &psc->sc_priority; max = 3; break; default: return (EINVAL); } val = *valp; error = sysctl_handle_int(oidp, &val, 0, req); if (error != 0 || req->newptr == NULL) return (error); /* Bounds check value. */ if (val >= max) return (EINVAL); /* Reinitialize switch with new value. */ *valp = val; mv88e61xxphy_init(sc); return (0); } static void mv88e61xxphy_vtu_load(struct mv88e61xxphy_softc *sc, uint16_t vid) { unsigned port; /* * Wait for previous operation to complete. */ mv88e61xxphy_vtu_wait(sc); /* * Set VID. */ MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_VTU_VID, MV88E61XX_GLOBAL_VTU_VID_VALID | vid); /* * Add ports to this VTU. */ for (port = 0; port < MV88E61XX_PORTS; port++) { struct mv88e61xxphy_port_softc *psc; psc = &sc->sc_ports[port]; if (psc->sc_vlan == vid) { /* * Send this port its VLAN traffic untagged. */ psc->sc_flags &= ~MV88E61XXPHY_PORT_FLAG_VTU_UPDATE; mv88e61xxphy_vtu_set_membership(sc, port, MV88E61XXPHY_VTU_UNTAGGED); } else if (psc->sc_port == MV88E61XX_HOST_PORT) { /* * The host sees all VLANs tagged. */ mv88e61xxphy_vtu_set_membership(sc, port, MV88E61XXPHY_VTU_TAGGED); } else { /* * This port isn't on this VLAN. */ mv88e61xxphy_vtu_set_membership(sc, port, MV88E61XXPHY_VTU_DISCARDED); } } /* * Start adding this entry. */ MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_VTU_OP, MV88E61XX_GLOBAL_VTU_OP_BUSY | MV88E61XX_GLOBAL_VTU_OP_OP_VTU_LOAD); } static void mv88e61xxphy_vtu_set_membership(struct mv88e61xxphy_softc *sc, unsigned port, enum mv88e61xxphy_vtu_membership_type type) { unsigned shift, reg; uint16_t bits; uint16_t val; switch (type) { case MV88E61XXPHY_VTU_UNMODIFIED: bits = 0; break; case MV88E61XXPHY_VTU_UNTAGGED: bits = 1; break; case MV88E61XXPHY_VTU_TAGGED: bits = 2; break; case MV88E61XXPHY_VTU_DISCARDED: bits = 3; break; default: return; } if (port < 4) { reg = MV88E61XX_GLOBAL_VTU_DATA_P0P3; shift = port * 4; } else { reg = MV88E61XX_GLOBAL_VTU_DATA_P4P5; shift = (port - 4) * 4; } val = MV88E61XX_READ(sc, MV88E61XX_GLOBAL, reg); val |= bits << shift; MV88E61XX_WRITE(sc, MV88E61XX_GLOBAL, reg, val); } static void mv88e61xxphy_vtu_wait(struct mv88e61xxphy_softc *sc) { uint16_t val; for (;;) { val = MV88E61XX_READ(sc, MV88E61XX_GLOBAL, MV88E61XX_GLOBAL_VTU_OP); if ((val & MV88E61XX_GLOBAL_VTU_OP_BUSY) == 0) return; } } static device_method_t mv88e61xxphy_methods[] = { /* device interface */ DEVMETHOD(device_probe, mv88e61xxphy_probe), DEVMETHOD(device_attach, mv88e61xxphy_attach), DEVMETHOD(device_detach, bus_generic_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), { 0, 0 } }; static devclass_t mv88e61xxphy_devclass; static driver_t mv88e61xxphy_driver = { "mv88e61xxphy", mv88e61xxphy_methods, sizeof(struct mv88e61xxphy_softc) }; DRIVER_MODULE(mv88e61xxphy, octe, mv88e61xxphy_driver, mv88e61xxphy_devclass, 0, 0); Index: head/sys/mips/cavium/octe/mv88e61xxphyreg.h =================================================================== --- head/sys/mips/cavium/octe/mv88e61xxphyreg.h (revision 326258) +++ head/sys/mips/cavium/octe/mv88e61xxphyreg.h (revision 326259) @@ -1,149 +1,151 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 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$ */ /* * Register definitions for Marvell MV88E61XX * * Note that names and definitions were gleaned from Linux and U-Boot patches * released by Marvell, often by looking at contextual use of the registers * involved, and may not be representative of the full functionality of those * registers and are certainly not an exhaustive enumeration of registers. * * For an exhaustive enumeration of registers, check out the QD-DSDT package * included in the Marvell ARM Feroceon Board Support Package for Linux. */ #ifndef _MIPS_CAVIUM_OCTE_MV88E61XXPHYREG_H_ #define _MIPS_CAVIUM_OCTE_MV88E61XXPHYREG_H_ /* * Port addresses & per-port registers. */ #define MV88E61XX_PORT(x) (0x10 + (x)) #define MV88E61XX_HOST_PORT (5) #define MV88E61XX_PORTS (6) #define MV88E61XX_PORT_STATUS (0x00) #define MV88E61XX_PORT_FORCE_MAC (0x01) #define MV88E61XX_PORT_PAUSE_CONTROL (0x02) #define MV88E61XX_PORT_REVISION (0x03) #define MV88E61XX_PORT_CONTROL (0x04) #define MV88E61XX_PORT_CONTROL2 (0x05) #define MV88E61XX_PORT_VLAN_MAP (0x06) #define MV88E61XX_PORT_VLAN (0x07) #define MV88E61XX_PORT_FILTER (0x08) #define MV88E61XX_PORT_EGRESS_CONTROL (0x09) #define MV88E61XX_PORT_EGRESS_CONTROL2 (0x0a) #define MV88E61XX_PORT_PORT_LEARN (0x0b) #define MV88E61XX_PORT_ATU_CONTROL (0x0c) #define MV88E61XX_PORT_PRIORITY_CONTROL (0x0d) #define MV88E61XX_PORT_ETHER_PROTO (0x0f) #define MV88E61XX_PORT_PROVIDER_PROTO (0x1a) #define MV88E61XX_PORT_PRIORITY_MAP (0x18) #define MV88E61XX_PORT_PRIORITY_MAP2 (0x19) /* * Fields and values in each register. */ #define MV88E61XX_PORT_STATUS_MEDIA (0x0300) #define MV88E61XX_PORT_STATUS_MEDIA_10M (0x0000) #define MV88E61XX_PORT_STATUS_MEDIA_100M (0x0100) #define MV88E61XX_PORT_STATUS_MEDIA_1G (0x0200) #define MV88E61XX_PORT_STATUS_DUPLEX (0x0400) #define MV88E61XX_PORT_STATUS_LINK (0x0800) #define MV88E61XX_PORT_STATUS_FC (0x8000) #define MV88E61XX_PORT_CONTROL_DOUBLE_TAG (0x0200) #define MV88E61XX_PORT_FILTER_MAP_DEST (0x0080) #define MV88E61XX_PORT_FILTER_DISCARD_UNTAGGED (0x0100) #define MV88E61XX_PORT_FILTER_DISCARD_TAGGED (0x0200) #define MV88E61XX_PORT_FILTER_8021Q_MODE (0x0c00) #define MV88E61XX_PORT_FILTER_8021Q_DISABLED (0x0000) #define MV88E61XX_PORT_FILTER_8021Q_FALLBACK (0x0400) #define MV88E61XX_PORT_FILTER_8021Q_CHECK (0x0800) #define MV88E61XX_PORT_FILTER_8021Q_SECURE (0x0c00) /* * Global address & global registers. */ #define MV88E61XX_GLOBAL (0x1b) #define MV88E61XX_GLOBAL_STATUS (0x00) #define MV88E61XX_GLOBAL_CONTROL (0x04) #define MV88E61XX_GLOBAL_VTU_OP (0x05) #define MV88E61XX_GLOBAL_VTU_VID (0x06) #define MV88E61XX_GLOBAL_VTU_DATA_P0P3 (0x07) #define MV88E61XX_GLOBAL_VTU_DATA_P4P5 (0x08) #define MV88E61XX_GLOBAL_ATU_CONTROL (0x0a) #define MV88E61XX_GLOBAL_PRIORITY_MAP (0x18) #define MV88E61XX_GLOBAL_MONITOR (0x1a) #define MV88E61XX_GLOBAL_REMOTE_MGMT (0x1c) #define MV88E61XX_GLOBAL_STATS (0x1d) /* * Fields and values in each register. */ #define MV88E61XX_GLOBAL_VTU_OP_BUSY (0x8000) #define MV88E61XX_GLOBAL_VTU_OP_OP (0x7000) #define MV88E61XX_GLOBAL_VTU_OP_OP_FLUSH (0x1000) #define MV88E61XX_GLOBAL_VTU_OP_OP_VTU_LOAD (0x3000) #define MV88E61XX_GLOBAL_VTU_VID_VALID (0x1000) /* * Second global address & second global registers. */ #define MV88E61XX_GLOBAL2 (0x1c) #define MV88E61XX_GLOBAL2_MANAGE_2X (0x02) #define MV88E61XX_GLOBAL2_MANAGE_0X (0x03) #define MV88E61XX_GLOBAL2_CONTROL2 (0x05) #define MV88E61XX_GLOBAL2_TRUNK_MASK (0x07) #define MV88E61XX_GLOBAL2_TRUNK_MAP (0x08) #define MV88E61XX_GLOBAL2_RATELIMIT (0x09) #define MV88E61XX_GLOBAL2_VLAN_CONTROL (0x0b) #define MV88E61XX_GLOBAL2_MAC_ADDRESS (0x0d) /* * Fields and values in each register. */ #define MV88E61XX_GLOBAL2_CONTROL2_DOUBLE_USE (0x8000) #define MV88E61XX_GLOBAL2_CONTROL2_LOOP_PREVENT (0x4000) #define MV88E61XX_GLOBAL2_CONTROL2_FLOW_MESSAGE (0x2000) #define MV88E61XX_GLOBAL2_CONTROL2_FLOOD_BC (0x1000) #define MV88E61XX_GLOBAL2_CONTROL2_REMOVE_PTAG (0x0800) #define MV88E61XX_GLOBAL2_CONTROL2_AGE_INT (0x0400) #define MV88E61XX_GLOBAL2_CONTROL2_FLOW_TAG (0x0200) #define MV88E61XX_GLOBAL2_CONTROL2_ALWAYS_VTU (0x0100) #define MV88E61XX_GLOBAL2_CONTROL2_FORCE_FC_PRI (0x0080) #define MV88E61XX_GLOBAL2_CONTROL2_FC_PRI (0x0070) #define MV88E61XX_GLOBAL2_CONTROL2_MGMT_TO_HOST (0x0008) #define MV88E61XX_GLOBAL2_CONTROL2_MGMT_PRI (0x0007) #endif /* !_MIPS_CAVIUM_OCTE_MV88E61XXPHYREG_H_ */ Index: head/sys/mips/cavium/octe/octe.c =================================================================== --- head/sys/mips/cavium/octe/octe.c (revision 326258) +++ head/sys/mips/cavium/octe/octe.c (revision 326259) @@ -1,491 +1,493 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 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$ */ /* * Cavium Octeon Ethernet devices. * * XXX This file should be moved to if_octe.c * XXX The driver may have sufficient locking but we need locking to protect * the interfaces presented here, right? */ #include "opt_inet.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef INET #include #include #endif #include #include #include "wrapper-cvmx-includes.h" #include "cavium-ethernet.h" #include "ethernet-common.h" #include "ethernet-defines.h" #include "ethernet-mdio.h" #include "ethernet-tx.h" #include "miibus_if.h" #define OCTE_TX_LOCK(priv) mtx_lock(&(priv)->tx_mtx) #define OCTE_TX_UNLOCK(priv) mtx_unlock(&(priv)->tx_mtx) static int octe_probe(device_t); static int octe_attach(device_t); static int octe_detach(device_t); static int octe_shutdown(device_t); static int octe_miibus_readreg(device_t, int, int); static int octe_miibus_writereg(device_t, int, int, int); static void octe_init(void *); static void octe_stop(void *); static int octe_transmit(struct ifnet *, struct mbuf *); static int octe_mii_medchange(struct ifnet *); static void octe_mii_medstat(struct ifnet *, struct ifmediareq *); static int octe_medchange(struct ifnet *); static void octe_medstat(struct ifnet *, struct ifmediareq *); static int octe_ioctl(struct ifnet *, u_long, caddr_t); static device_method_t octe_methods[] = { /* Device interface */ DEVMETHOD(device_probe, octe_probe), DEVMETHOD(device_attach, octe_attach), DEVMETHOD(device_detach, octe_detach), DEVMETHOD(device_shutdown, octe_shutdown), /* MII interface */ DEVMETHOD(miibus_readreg, octe_miibus_readreg), DEVMETHOD(miibus_writereg, octe_miibus_writereg), { 0, 0 } }; static driver_t octe_driver = { "octe", octe_methods, sizeof (cvm_oct_private_t), }; static devclass_t octe_devclass; DRIVER_MODULE(octe, octebus, octe_driver, octe_devclass, 0, 0); DRIVER_MODULE(miibus, octe, miibus_driver, miibus_devclass, 0, 0); static int octe_probe(device_t dev) { return (0); } static int octe_attach(device_t dev) { struct ifnet *ifp; cvm_oct_private_t *priv; device_t child; unsigned qos; int error; priv = device_get_softc(dev); ifp = priv->ifp; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); if (priv->phy_id != -1) { if (priv->phy_device == NULL) { error = mii_attach(dev, &priv->miibus, ifp, octe_mii_medchange, octe_mii_medstat, BMSR_DEFCAPMASK, priv->phy_id, MII_OFFSET_ANY, 0); if (error != 0) device_printf(dev, "attaching PHYs failed\n"); } else { child = device_add_child(dev, priv->phy_device, -1); if (child == NULL) device_printf(dev, "missing phy %u device %s\n", priv->phy_id, priv->phy_device); } } if (priv->miibus == NULL) { ifmedia_init(&priv->media, 0, octe_medchange, octe_medstat); ifmedia_add(&priv->media, IFM_ETHER | IFM_AUTO, 0, NULL); ifmedia_set(&priv->media, IFM_ETHER | IFM_AUTO); } /* * XXX * We don't support programming the multicast filter right now, although it * ought to be easy enough. (Presumably it's just a matter of putting * multicast addresses in the CAM?) */ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_ALLMULTI; ifp->if_init = octe_init; ifp->if_ioctl = octe_ioctl; priv->if_flags = ifp->if_flags; mtx_init(&priv->tx_mtx, ifp->if_xname, "octe tx send queue", MTX_DEF); for (qos = 0; qos < 16; qos++) { mtx_init(&priv->tx_free_queue[qos].ifq_mtx, ifp->if_xname, "octe tx free queue", MTX_DEF); IFQ_SET_MAXLEN(&priv->tx_free_queue[qos], MAX_OUT_QUEUE_DEPTH); } ether_ifattach(ifp, priv->mac); ifp->if_transmit = octe_transmit; ifp->if_hdrlen = sizeof(struct ether_vlan_header); ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_HWCSUM; ifp->if_capenable = ifp->if_capabilities; ifp->if_hwassist = CSUM_TCP | CSUM_UDP; OCTE_TX_LOCK(priv); IFQ_SET_MAXLEN(&ifp->if_snd, MAX_OUT_QUEUE_DEPTH); ifp->if_snd.ifq_drv_maxlen = MAX_OUT_QUEUE_DEPTH; IFQ_SET_READY(&ifp->if_snd); OCTE_TX_UNLOCK(priv); return (bus_generic_attach(dev)); } static int octe_detach(device_t dev) { return (0); } static int octe_shutdown(device_t dev) { return (octe_detach(dev)); } static int octe_miibus_readreg(device_t dev, int phy, int reg) { cvm_oct_private_t *priv; priv = device_get_softc(dev); /* * Try interface-specific MII routine. */ if (priv->mdio_read != NULL) return (priv->mdio_read(priv->ifp, phy, reg)); /* * Try generic MII routine. */ KASSERT(phy == priv->phy_id, ("read from phy %u but our phy is %u", phy, priv->phy_id)); return (cvm_oct_mdio_read(priv->ifp, phy, reg)); } static int octe_miibus_writereg(device_t dev, int phy, int reg, int val) { cvm_oct_private_t *priv; priv = device_get_softc(dev); /* * Try interface-specific MII routine. */ if (priv->mdio_write != NULL) { priv->mdio_write(priv->ifp, phy, reg, val); return (0); } /* * Try generic MII routine. */ KASSERT(phy == priv->phy_id, ("write to phy %u but our phy is %u", phy, priv->phy_id)); cvm_oct_mdio_write(priv->ifp, phy, reg, val); return (0); } static void octe_init(void *arg) { struct ifnet *ifp; cvm_oct_private_t *priv; priv = arg; ifp = priv->ifp; if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) octe_stop(priv); if (priv->open != NULL) priv->open(ifp); if (((ifp->if_flags ^ priv->if_flags) & (IFF_ALLMULTI | IFF_MULTICAST | IFF_PROMISC)) != 0) cvm_oct_common_set_multicast_list(ifp); cvm_oct_common_set_mac_address(ifp, IF_LLADDR(ifp)); cvm_oct_common_poll(ifp); if (priv->miibus != NULL) mii_mediachg(device_get_softc(priv->miibus)); ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; } static void octe_stop(void *arg) { struct ifnet *ifp; cvm_oct_private_t *priv; priv = arg; ifp = priv->ifp; if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) return; if (priv->stop != NULL) priv->stop(ifp); ifp->if_drv_flags &= ~IFF_DRV_RUNNING; } static int octe_transmit(struct ifnet *ifp, struct mbuf *m) { cvm_oct_private_t *priv; priv = ifp->if_softc; if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING) { m_freem(m); return (0); } return (cvm_oct_xmit(m, ifp)); } static int octe_mii_medchange(struct ifnet *ifp) { cvm_oct_private_t *priv; struct mii_data *mii; struct mii_softc *miisc; priv = ifp->if_softc; mii = device_get_softc(priv->miibus); LIST_FOREACH(miisc, &mii->mii_phys, mii_list) PHY_RESET(miisc); mii_mediachg(mii); return (0); } static void octe_mii_medstat(struct ifnet *ifp, struct ifmediareq *ifm) { cvm_oct_private_t *priv; struct mii_data *mii; priv = ifp->if_softc; mii = device_get_softc(priv->miibus); mii_pollstat(mii); ifm->ifm_active = mii->mii_media_active; ifm->ifm_status = mii->mii_media_status; } static int octe_medchange(struct ifnet *ifp) { return (ENOTSUP); } static void octe_medstat(struct ifnet *ifp, struct ifmediareq *ifm) { cvm_oct_private_t *priv; cvmx_helper_link_info_t link_info; priv = ifp->if_softc; ifm->ifm_status = IFM_AVALID; ifm->ifm_active = IFT_ETHER; if (priv->poll == NULL) return; priv->poll(ifp); link_info.u64 = priv->link_info; if (!link_info.s.link_up) return; ifm->ifm_status |= IFM_ACTIVE; switch (link_info.s.speed) { case 10: ifm->ifm_active |= IFM_10_T; break; case 100: ifm->ifm_active |= IFM_100_TX; break; case 1000: ifm->ifm_active |= IFM_1000_T; break; case 10000: ifm->ifm_active |= IFM_10G_T; break; } if (link_info.s.full_duplex) ifm->ifm_active |= IFM_FDX; else ifm->ifm_active |= IFM_HDX; } static int octe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { cvm_oct_private_t *priv; struct mii_data *mii; struct ifreq *ifr; #ifdef INET struct ifaddr *ifa; #endif int error; priv = ifp->if_softc; ifr = (struct ifreq *)data; #ifdef INET ifa = (struct ifaddr *)data; #endif switch (cmd) { case SIOCSIFADDR: #ifdef INET /* * Avoid reinitialization unless it's necessary. */ if (ifa->ifa_addr->sa_family == AF_INET) { ifp->if_flags |= IFF_UP; if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) octe_init(priv); arp_ifinit(ifp, ifa); return (0); } #endif error = ether_ioctl(ifp, cmd, data); if (error != 0) return (error); return (0); case SIOCSIFFLAGS: if (ifp->if_flags == priv->if_flags) return (0); if ((ifp->if_flags & IFF_UP) != 0) { if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) octe_init(priv); } else { if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) octe_stop(priv); } priv->if_flags = ifp->if_flags; return (0); case SIOCSIFCAP: /* * Just change the capabilities in software, currently none * require reprogramming hardware, they just toggle whether we * make use of already-present facilities in software. */ ifp->if_capenable = ifr->ifr_reqcap; return (0); case SIOCSIFMTU: error = cvm_oct_common_change_mtu(ifp, ifr->ifr_mtu); if (error != 0) return (EINVAL); return (0); case SIOCSIFMEDIA: case SIOCGIFMEDIA: if (priv->miibus != NULL) { mii = device_get_softc(priv->miibus); error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd); if (error != 0) return (error); return (0); } error = ifmedia_ioctl(ifp, ifr, &priv->media, cmd); if (error != 0) return (error); return (0); default: error = ether_ioctl(ifp, cmd, data); if (error != 0) return (error); return (0); } } Index: head/sys/mips/cavium/octe/octebus.c =================================================================== --- head/sys/mips/cavium/octe/octebus.c (revision 326258) +++ head/sys/mips/cavium/octe/octebus.c (revision 326259) @@ -1,123 +1,125 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 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$ */ /* * Cavium Octeon Ethernet pseudo-bus attachment. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ethernet-common.h" #include "octebusvar.h" static void octebus_identify(driver_t *drv, device_t parent); static int octebus_probe(device_t dev); static int octebus_attach(device_t dev); static int octebus_detach(device_t dev); static int octebus_shutdown(device_t dev); static device_method_t octebus_methods[] = { /* Device interface */ DEVMETHOD(device_identify, octebus_identify), DEVMETHOD(device_probe, octebus_probe), DEVMETHOD(device_attach, octebus_attach), DEVMETHOD(device_detach, octebus_detach), DEVMETHOD(device_shutdown, octebus_shutdown), /* Bus interface. */ DEVMETHOD(bus_add_child, bus_generic_add_child), { 0, 0 } }; static driver_t octebus_driver = { "octebus", octebus_methods, sizeof (struct octebus_softc), }; static devclass_t octebus_devclass; DRIVER_MODULE(octebus, ciu, octebus_driver, octebus_devclass, 0, 0); static void octebus_identify(driver_t *drv, device_t parent) { BUS_ADD_CHILD(parent, 0, "octebus", 0); } static int octebus_probe(device_t dev) { if (device_get_unit(dev) != 0) return (ENXIO); device_set_desc(dev, "Cavium Octeon Ethernet pseudo-bus"); return (0); } static int octebus_attach(device_t dev) { struct octebus_softc *sc; int rv; sc = device_get_softc(dev); sc->sc_dev = dev; rv = cvm_oct_init_module(dev); if (rv != 0) return (ENXIO); return (0); } static int octebus_detach(device_t dev) { cvm_oct_cleanup_module(dev); return (0); } static int octebus_shutdown(device_t dev) { return (octebus_detach(dev)); } Index: head/sys/mips/cavium/octe/octebusvar.h =================================================================== --- head/sys/mips/cavium/octe/octebusvar.h (revision 326258) +++ head/sys/mips/cavium/octe/octebusvar.h (revision 326259) @@ -1,42 +1,44 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 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$ */ #ifndef _CAVIUM_OCTE_OCTEBUSVAR_H_ #define _CAVIUM_OCTE_OCTEBUSVAR_H_ struct octebus_softc { device_t sc_dev; struct resource *sc_rx_irq; void *sc_rx_intr_cookie; struct resource *sc_rgmii_irq; struct resource *sc_spi_irq; }; #endif /* !_CAVIUM_OCTE_OCTEBUSVAR_H_ */ Index: head/sys/mips/cavium/octeon_cop2.h =================================================================== --- head/sys/mips/cavium/octeon_cop2.h (revision 326258) +++ head/sys/mips/cavium/octeon_cop2.h (revision 326259) @@ -1,210 +1,212 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2011, Oleksandr Tymoshenko * 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 unmodified, 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$ * */ #ifndef __OCTEON_COP2_H__ #define __OCTEON_COP2_H__ /* * COP2 registers of interest */ #define COP2_CRC_IV 0x201 #define COP2_CRC_IV_SET COP2_CRC_IV #define COP2_CRC_LENGTH 0x202 #define COP2_CRC_LENGTH_SET 0x1202 #define COP2_CRC_POLY 0x200 #define COP2_CRC_POLY_SET 0x4200 #define COP2_LLM_DAT0 0x402 #define COP2_LLM_DAT0_SET COP2_LLM_DAT0 #define COP2_LLM_DAT1 0x40A #define COP2_LLM_DAT1_SET COP2_LLM_DAT1 #define COP2_3DES_IV 0x084 #define COP2_3DES_IV_SET COP2_3DES_IV #define COP2_3DES_KEY0 0x080 #define COP2_3DES_KEY0_SET COP2_3DES_KEY0 #define COP2_3DES_KEY1 0x081 #define COP2_3DES_KEY1_SET COP2_3DES_KEY1 #define COP2_3DES_KEY2 0x082 #define COP2_3DES_KEY2_SET COP2_3DES_KEY2 #define COP2_3DES_RESULT 0x088 #define COP2_3DES_RESULT_SET 0x098 #define COP2_AES_INP0 0x111 #define COP2_AES_INP0_SET COP2_AES_INP0 #define COP2_AES_IV0 0x102 #define COP2_AES_IV0_SET COP2_AES_IV0 #define COP2_AES_IV1 0x103 #define COP2_AES_IV1_SET COP2_AES_IV1 #define COP2_AES_KEY0 0x104 #define COP2_AES_KEY0_SET COP2_AES_KEY0 #define COP2_AES_KEY1 0x105 #define COP2_AES_KEY1_SET COP2_AES_KEY1 #define COP2_AES_KEY2 0x106 #define COP2_AES_KEY2_SET COP2_AES_KEY2 #define COP2_AES_KEY3 0x107 #define COP2_AES_KEY3_SET COP2_AES_KEY3 #define COP2_AES_KEYLEN 0x110 #define COP2_AES_KEYLEN_SET COP2_AES_KEYLEN #define COP2_AES_RESULT0 0x100 #define COP2_AES_RESULT0_SET COP2_AES_RESULT0 #define COP2_AES_RESULT1 0x101 #define COP2_AES_RESULT1_SET COP2_AES_RESULT1 #define COP2_HSH_DATW0 0x240 #define COP2_HSH_DATW0_SET COP2_HSH_DATW0 #define COP2_HSH_DATW1 0x241 #define COP2_HSH_DATW1_SET COP2_HSH_DATW1 #define COP2_HSH_DATW2 0x242 #define COP2_HSH_DATW2_SET COP2_HSH_DATW2 #define COP2_HSH_DATW3 0x243 #define COP2_HSH_DATW3_SET COP2_HSH_DATW3 #define COP2_HSH_DATW4 0x244 #define COP2_HSH_DATW4_SET COP2_HSH_DATW4 #define COP2_HSH_DATW5 0x245 #define COP2_HSH_DATW5_SET COP2_HSH_DATW5 #define COP2_HSH_DATW6 0x246 #define COP2_HSH_DATW6_SET COP2_HSH_DATW6 #define COP2_HSH_DATW7 0x247 #define COP2_HSH_DATW7_SET COP2_HSH_DATW7 #define COP2_HSH_DATW8 0x248 #define COP2_HSH_DATW8_SET COP2_HSH_DATW8 #define COP2_HSH_DATW9 0x249 #define COP2_HSH_DATW9_SET COP2_HSH_DATW9 #define COP2_HSH_DATW10 0x24A #define COP2_HSH_DATW10_SET COP2_HSH_DATW10 #define COP2_HSH_DATW11 0x24B #define COP2_HSH_DATW11_SET COP2_HSH_DATW11 #define COP2_HSH_DATW12 0x24C #define COP2_HSH_DATW12_SET COP2_HSH_DATW12 #define COP2_HSH_DATW13 0x24D #define COP2_HSH_DATW13_SET COP2_HSH_DATW13 #define COP2_HSH_DATW14 0x24E #define COP2_HSH_DATW14_SET COP2_HSH_DATW14 #define COP2_HSH_IVW0 0x250 #define COP2_HSH_IVW0_SET COP2_HSH_IVW0 #define COP2_HSH_IVW1 0x251 #define COP2_HSH_IVW1_SET COP2_HSH_IVW1 #define COP2_HSH_IVW2 0x252 #define COP2_HSH_IVW2_SET COP2_HSH_IVW2 #define COP2_HSH_IVW3 0x253 #define COP2_HSH_IVW3_SET COP2_HSH_IVW3 #define COP2_HSH_IVW4 0x254 #define COP2_HSH_IVW4_SET COP2_HSH_IVW4 #define COP2_HSH_IVW5 0x255 #define COP2_HSH_IVW5_SET COP2_HSH_IVW5 #define COP2_HSH_IVW6 0x256 #define COP2_HSH_IVW6_SET COP2_HSH_IVW6 #define COP2_HSH_IVW7 0x257 #define COP2_HSH_IVW7_SET COP2_HSH_IVW7 #define COP2_GFM_MULT0 0x258 #define COP2_GFM_MULT0_SET COP2_GFM_MULT0 #define COP2_GFM_MULT1 0x259 #define COP2_GFM_MULT1_SET COP2_GFM_MULT1 #define COP2_GFM_POLY 0x25E #define COP2_GFM_POLY_SET COP2_GFM_POLY #define COP2_GFM_RESULT0 0x25A #define COP2_GFM_RESULT0_SET COP2_GFM_RESULT0 #define COP2_GFM_RESULT1 0x25B #define COP2_GFM_RESULT1_SET COP2_GFM_RESULT1 #define COP2_HSH_DATW0_PASS1 0x040 #define COP2_HSH_DATW0_PASS1_SET COP2_HSH_DATW0_PASS1 #define COP2_HSH_DATW1_PASS1 0x041 #define COP2_HSH_DATW1_PASS1_SET COP2_HSH_DATW1_PASS1 #define COP2_HSH_DATW2_PASS1 0x042 #define COP2_HSH_DATW2_PASS1_SET COP2_HSH_DATW2_PASS1 #define COP2_HSH_DATW3_PASS1 0x043 #define COP2_HSH_DATW3_PASS1_SET COP2_HSH_DATW3_PASS1 #define COP2_HSH_DATW4_PASS1 0x044 #define COP2_HSH_DATW4_PASS1_SET COP2_HSH_DATW4_PASS1 #define COP2_HSH_DATW5_PASS1 0x045 #define COP2_HSH_DATW5_PASS1_SET COP2_HSH_DATW5_PASS1 #define COP2_HSH_DATW6_PASS1 0x046 #define COP2_HSH_DATW6_PASS1_SET COP2_HSH_DATW6_PASS1 #define COP2_HSH_IVW0_PASS1 0x048 #define COP2_HSH_IVW0_PASS1_SET COP2_HSH_IVW0_PASS1 #define COP2_HSH_IVW1_PASS1 0x049 #define COP2_HSH_IVW1_PASS1_SET COP2_HSH_IVW1_PASS1 #define COP2_HSH_IVW2_PASS1 0x04A #define COP2_HSH_IVW2_PASS1_SET COP2_HSH_IVW2_PASS1 #ifndef LOCORE struct octeon_cop2_state { /* 3DES */ /* 0x0084 */ unsigned long _3des_iv; /* 0x0080..0x0082 */ unsigned long _3des_key[3]; /* 0x0088, set: 0x0098 */ unsigned long _3des_result; /* AES */ /* 0x0111 */ unsigned long aes_inp0; /* 0x0102..0x0103 */ unsigned long aes_iv[2]; /* 0x0104..0x0107 */ unsigned long aes_key[4]; /* 0x0110 */ unsigned long aes_keylen; /* 0x0100..0x0101 */ unsigned long aes_result[2]; /* CRC */ /* 0x0201 */ unsigned long crc_iv; /* 0x0202, set: 0x1202 */ unsigned long crc_length; /* 0x0200, set: 0x4200 */ unsigned long crc_poly; /* Low-latency memory stuff */ /* 0x0402, 0x040A */ unsigned long llm_dat[2]; /* SHA & MD5 */ /* 0x0240..0x024E */ unsigned long hsh_datw[15]; /* 0x0250..0x0257 */ unsigned long hsh_ivw[8]; /* GFM */ /* 0x0258..0x0259 */ unsigned long gfm_mult[2]; /* 0x025E */ unsigned long gfm_poly; /* 0x025A..0x025B */ unsigned long gfm_result[2]; }; /* Prototypes */ void octeon_cop2_save(struct octeon_cop2_state *); void octeon_cop2_restore(struct octeon_cop2_state *); #endif /* LOCORE */ #endif /* __OCTEON_COP2_H__ */ Index: head/sys/mips/cavium/octeon_gpio.c =================================================================== --- head/sys/mips/cavium/octeon_gpio.c (revision 326258) +++ head/sys/mips/cavium/octeon_gpio.c (revision 326259) @@ -1,506 +1,508 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2011, Oleksandr Tymoshenko * 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 unmodified, 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. */ /* * GPIO driver for Cavium Octeon */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gpio_if.h" #define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT) struct octeon_gpio_pin { const char *name; int pin; int flags; }; /* * on CAP100 GPIO 7 is "Factory defaults" button * */ static struct octeon_gpio_pin octeon_gpio_pins[] = { { "F/D", 7, GPIO_PIN_INPUT}, { NULL, 0, 0}, }; /* * Helpers */ static void octeon_gpio_pin_configure(struct octeon_gpio_softc *sc, struct gpio_pin *pin, uint32_t flags); /* * Driver stuff */ static void octeon_gpio_identify(driver_t *, device_t); static int octeon_gpio_probe(device_t dev); static int octeon_gpio_attach(device_t dev); static int octeon_gpio_detach(device_t dev); static int octeon_gpio_filter(void *arg); static void octeon_gpio_intr(void *arg); /* * GPIO interface */ static device_t octeon_gpio_get_bus(device_t); static int octeon_gpio_pin_max(device_t dev, int *maxpin); static int octeon_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps); static int octeon_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags); static int octeon_gpio_pin_getname(device_t dev, uint32_t pin, char *name); static int octeon_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags); static int octeon_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value); static int octeon_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val); static int octeon_gpio_pin_toggle(device_t dev, uint32_t pin); static void octeon_gpio_pin_configure(struct octeon_gpio_softc *sc, struct gpio_pin *pin, unsigned int flags) { uint32_t mask; cvmx_gpio_bit_cfgx_t gpio_cfgx; mask = 1 << pin->gp_pin; GPIO_LOCK(sc); /* * Manage input/output */ if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(pin->gp_pin)); pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); if (flags & GPIO_PIN_OUTPUT) { pin->gp_flags |= GPIO_PIN_OUTPUT; gpio_cfgx.s.tx_oe = 1; } else { pin->gp_flags |= GPIO_PIN_INPUT; gpio_cfgx.s.tx_oe = 0; } if (flags & GPIO_PIN_INVIN) gpio_cfgx.s.rx_xor = 1; else gpio_cfgx.s.rx_xor = 0; cvmx_write_csr(CVMX_GPIO_BIT_CFGX(pin->gp_pin), gpio_cfgx.u64); } GPIO_UNLOCK(sc); } static device_t octeon_gpio_get_bus(device_t dev) { struct octeon_gpio_softc *sc; sc = device_get_softc(dev); return (sc->busdev); } static int octeon_gpio_pin_max(device_t dev, int *maxpin) { *maxpin = OCTEON_GPIO_PINS - 1; return (0); } static int octeon_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) { struct octeon_gpio_softc *sc = device_get_softc(dev); int i; for (i = 0; i < sc->gpio_npins; i++) { if (sc->gpio_pins[i].gp_pin == pin) break; } if (i >= sc->gpio_npins) return (EINVAL); GPIO_LOCK(sc); *caps = sc->gpio_pins[i].gp_caps; GPIO_UNLOCK(sc); return (0); } static int octeon_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) { struct octeon_gpio_softc *sc = device_get_softc(dev); int i; for (i = 0; i < sc->gpio_npins; i++) { if (sc->gpio_pins[i].gp_pin == pin) break; } if (i >= sc->gpio_npins) return (EINVAL); GPIO_LOCK(sc); *flags = sc->gpio_pins[i].gp_flags; GPIO_UNLOCK(sc); return (0); } static int octeon_gpio_pin_getname(device_t dev, uint32_t pin, char *name) { struct octeon_gpio_softc *sc = device_get_softc(dev); int i; for (i = 0; i < sc->gpio_npins; i++) { if (sc->gpio_pins[i].gp_pin == pin) break; } if (i >= sc->gpio_npins) return (EINVAL); GPIO_LOCK(sc); memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); GPIO_UNLOCK(sc); return (0); } static int octeon_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) { int i; struct octeon_gpio_softc *sc = device_get_softc(dev); for (i = 0; i < sc->gpio_npins; i++) { if (sc->gpio_pins[i].gp_pin == pin) break; } if (i >= sc->gpio_npins) return (EINVAL); octeon_gpio_pin_configure(sc, &sc->gpio_pins[i], flags); return (0); } static int octeon_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) { struct octeon_gpio_softc *sc = device_get_softc(dev); int i; for (i = 0; i < sc->gpio_npins; i++) { if (sc->gpio_pins[i].gp_pin == pin) break; } if (i >= sc->gpio_npins) return (EINVAL); GPIO_LOCK(sc); if (value) cvmx_gpio_set(1 << pin); else cvmx_gpio_clear(1 << pin); GPIO_UNLOCK(sc); return (0); } static int octeon_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) { struct octeon_gpio_softc *sc = device_get_softc(dev); int i; uint64_t state; for (i = 0; i < sc->gpio_npins; i++) { if (sc->gpio_pins[i].gp_pin == pin) break; } if (i >= sc->gpio_npins) return (EINVAL); GPIO_LOCK(sc); state = cvmx_gpio_read(); *val = (state & (1 << pin)) ? 1 : 0; GPIO_UNLOCK(sc); return (0); } static int octeon_gpio_pin_toggle(device_t dev, uint32_t pin) { int i; uint64_t state; struct octeon_gpio_softc *sc = device_get_softc(dev); for (i = 0; i < sc->gpio_npins; i++) { if (sc->gpio_pins[i].gp_pin == pin) break; } if (i >= sc->gpio_npins) return (EINVAL); GPIO_LOCK(sc); /* * XXX: Need to check if read returns actual state of output * pins or we need to keep this information by ourself */ state = cvmx_gpio_read(); if (state & (1 << pin)) cvmx_gpio_clear(1 << pin); else cvmx_gpio_set(1 << pin); GPIO_UNLOCK(sc); return (0); } static int octeon_gpio_filter(void *arg) { cvmx_gpio_bit_cfgx_t gpio_cfgx; void **cookie = arg; struct octeon_gpio_softc *sc = *cookie; long int irq = (cookie - sc->gpio_intr_cookies); if ((irq < 0) || (irq >= OCTEON_GPIO_IRQS)) return (FILTER_STRAY); gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(irq)); /* Clear rising edge detector */ if (gpio_cfgx.s.int_type == OCTEON_GPIO_IRQ_EDGE) cvmx_gpio_interrupt_clear(1 << irq); /* disable interrupt */ gpio_cfgx.s.int_en = 0; cvmx_write_csr(CVMX_GPIO_BIT_CFGX(irq), gpio_cfgx.u64); return (FILTER_SCHEDULE_THREAD); } static void octeon_gpio_intr(void *arg) { cvmx_gpio_bit_cfgx_t gpio_cfgx; void **cookie = arg; struct octeon_gpio_softc *sc = *cookie; long int irq = (cookie - sc->gpio_intr_cookies); if ((irq < 0) || (irq >= OCTEON_GPIO_IRQS)) { printf("%s: invalid GPIO IRQ: %ld\n", __func__, irq); return; } GPIO_LOCK(sc); gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(irq)); /* disable interrupt */ gpio_cfgx.s.int_en = 1; cvmx_write_csr(CVMX_GPIO_BIT_CFGX(irq), gpio_cfgx.u64); /* TODO: notify bus here or something */ printf("GPIO IRQ for pin %ld\n", irq); GPIO_UNLOCK(sc); } static void octeon_gpio_identify(driver_t *drv, device_t parent) { BUS_ADD_CHILD(parent, 0, "gpio", 0); } static int octeon_gpio_probe(device_t dev) { device_set_desc(dev, "Cavium Octeon GPIO driver"); return (0); } static int octeon_gpio_attach(device_t dev) { struct octeon_gpio_softc *sc = device_get_softc(dev); struct octeon_gpio_pin *pinp; cvmx_gpio_bit_cfgx_t gpio_cfgx; int i; KASSERT((device_get_unit(dev) == 0), ("octeon_gpio: Only one gpio module supported")); mtx_init(&sc->gpio_mtx, device_get_nameunit(dev), NULL, MTX_DEF); for ( i = 0; i < OCTEON_GPIO_IRQS; i++) { if ((sc->gpio_irq_res[i] = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->gpio_irq_rid[i], OCTEON_IRQ_GPIO0 + i, OCTEON_IRQ_GPIO0 + i, 1, RF_SHAREABLE | RF_ACTIVE)) == NULL) { device_printf(dev, "unable to allocate IRQ resource\n"); octeon_gpio_detach(dev); return (ENXIO); } sc->gpio_intr_cookies[i] = sc; if ((bus_setup_intr(dev, sc->gpio_irq_res[i], INTR_TYPE_MISC, octeon_gpio_filter, octeon_gpio_intr, &(sc->gpio_intr_cookies[i]), &sc->gpio_ih[i]))) { device_printf(dev, "WARNING: unable to register interrupt handler\n"); octeon_gpio_detach(dev); return (ENXIO); } } sc->dev = dev; /* Configure all pins as input */ /* disable interrupts for all pins */ pinp = octeon_gpio_pins; i = 0; while (pinp->name) { strncpy(sc->gpio_pins[i].gp_name, pinp->name, GPIOMAXNAME); sc->gpio_pins[i].gp_pin = pinp->pin; sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; sc->gpio_pins[i].gp_flags = 0; octeon_gpio_pin_configure(sc, &sc->gpio_pins[i], pinp->flags); pinp++; i++; } sc->gpio_npins = i; #if 0 /* * Sample: how to enable edge-triggered interrupt * for GPIO pin */ gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(7)); gpio_cfgx.s.int_en = 1; gpio_cfgx.s.int_type = OCTEON_GPIO_IRQ_EDGE; cvmx_write_csr(CVMX_GPIO_BIT_CFGX(7), gpio_cfgx.u64); #endif if (bootverbose) { for (i = 0; i < 16; i++) { gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(i)); device_printf(dev, "[pin%d] output=%d, invinput=%d, intr=%d, intr_type=%s\n", i, gpio_cfgx.s.tx_oe, gpio_cfgx.s.rx_xor, gpio_cfgx.s.int_en, gpio_cfgx.s.int_type ? "rising edge" : "level"); } } sc->busdev = gpiobus_attach_bus(dev); if (sc->busdev == NULL) { octeon_gpio_detach(dev); return (ENXIO); } return (0); } static int octeon_gpio_detach(device_t dev) { struct octeon_gpio_softc *sc = device_get_softc(dev); int i; KASSERT(mtx_initialized(&sc->gpio_mtx), ("gpio mutex not initialized")); for ( i = 0; i < OCTEON_GPIO_IRQS; i++) { if (sc->gpio_ih[i]) bus_teardown_intr(dev, sc->gpio_irq_res[i], sc->gpio_ih[i]); if (sc->gpio_irq_res[i]) bus_release_resource(dev, SYS_RES_IRQ, sc->gpio_irq_rid[i], sc->gpio_irq_res[i]); } gpiobus_detach_bus(dev); mtx_destroy(&sc->gpio_mtx); return(0); } static device_method_t octeon_gpio_methods[] = { DEVMETHOD(device_identify, octeon_gpio_identify), DEVMETHOD(device_probe, octeon_gpio_probe), DEVMETHOD(device_attach, octeon_gpio_attach), DEVMETHOD(device_detach, octeon_gpio_detach), /* GPIO protocol */ DEVMETHOD(gpio_get_bus, octeon_gpio_get_bus), DEVMETHOD(gpio_pin_max, octeon_gpio_pin_max), DEVMETHOD(gpio_pin_getname, octeon_gpio_pin_getname), DEVMETHOD(gpio_pin_getflags, octeon_gpio_pin_getflags), DEVMETHOD(gpio_pin_getcaps, octeon_gpio_pin_getcaps), DEVMETHOD(gpio_pin_setflags, octeon_gpio_pin_setflags), DEVMETHOD(gpio_pin_get, octeon_gpio_pin_get), DEVMETHOD(gpio_pin_set, octeon_gpio_pin_set), DEVMETHOD(gpio_pin_toggle, octeon_gpio_pin_toggle), {0, 0}, }; static driver_t octeon_gpio_driver = { "gpio", octeon_gpio_methods, sizeof(struct octeon_gpio_softc), }; static devclass_t octeon_gpio_devclass; DRIVER_MODULE(octeon_gpio, ciu, octeon_gpio_driver, octeon_gpio_devclass, 0, 0); Index: head/sys/mips/cavium/octeon_gpiovar.h =================================================================== --- head/sys/mips/cavium/octeon_gpiovar.h (revision 326258) +++ head/sys/mips/cavium/octeon_gpiovar.h (revision 326259) @@ -1,56 +1,58 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2011, Oleksandr Tymoshenko * 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 unmodified, 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$ * */ #ifndef __OCTEON_GPIOVAR_H__ #define __OCTEON_GPIOVAR_H__ #define GPIO_LOCK(_sc) mtx_lock(&(_sc)->gpio_mtx) #define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->gpio_mtx) #define GPIO_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->gpio_mtx, MA_OWNED) #define OCTEON_GPIO_IRQ_LEVEL 0 #define OCTEON_GPIO_IRQ_EDGE 1 #define OCTEON_GPIO_PINS 24 #define OCTEON_GPIO_IRQS 16 struct octeon_gpio_softc { device_t dev; device_t busdev; struct mtx gpio_mtx; struct resource *gpio_irq_res[OCTEON_GPIO_IRQS]; int gpio_irq_rid[OCTEON_GPIO_IRQS]; void *gpio_ih[OCTEON_GPIO_IRQS]; void *gpio_intr_cookies[OCTEON_GPIO_IRQS]; int gpio_npins; struct gpio_pin gpio_pins[OCTEON_GPIO_PINS]; }; #endif /* __OCTEON_GPIOVAR_H__ */ Index: head/sys/mips/cavium/octeon_machdep.c =================================================================== --- head/sys/mips/cavium/octeon_machdep.c (revision 326258) +++ head/sys/mips/cavium/octeon_machdep.c (revision 326259) @@ -1,719 +1,721 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006 Wojciech A. Koszek * 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 __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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(__mips_n64) #define MAX_APP_DESC_ADDR 0xffffffffafffffff #else #define MAX_APP_DESC_ADDR 0xafffffff #endif struct octeon_feature_description { octeon_feature_t ofd_feature; const char *ofd_string; }; extern int *end; extern char cpu_model[]; extern char cpu_board[]; static char octeon_kenv[0x2000]; static const struct octeon_feature_description octeon_feature_descriptions[] = { { OCTEON_FEATURE_SAAD, "SAAD" }, { OCTEON_FEATURE_ZIP, "ZIP" }, { OCTEON_FEATURE_CRYPTO, "CRYPTO" }, { OCTEON_FEATURE_DORM_CRYPTO, "DORM_CRYPTO" }, { OCTEON_FEATURE_PCIE, "PCIE" }, { OCTEON_FEATURE_SRIO, "SRIO" }, { OCTEON_FEATURE_KEY_MEMORY, "KEY_MEMORY" }, { OCTEON_FEATURE_LED_CONTROLLER, "LED_CONTROLLER" }, { OCTEON_FEATURE_TRA, "TRA" }, { OCTEON_FEATURE_MGMT_PORT, "MGMT_PORT" }, { OCTEON_FEATURE_RAID, "RAID" }, { OCTEON_FEATURE_USB, "USB" }, { OCTEON_FEATURE_NO_WPTR, "NO_WPTR" }, { OCTEON_FEATURE_DFA, "DFA" }, { OCTEON_FEATURE_MDIO_CLAUSE_45, "MDIO_CLAUSE_45" }, { OCTEON_FEATURE_NPEI, "NPEI" }, { OCTEON_FEATURE_ILK, "ILK" }, { OCTEON_FEATURE_HFA, "HFA" }, { OCTEON_FEATURE_DFM, "DFM" }, { OCTEON_FEATURE_CIU2, "CIU2" }, { OCTEON_FEATURE_DICI_MODE, "DICI_MODE" }, { OCTEON_FEATURE_BIT_EXTRACTOR, "BIT_EXTRACTOR" }, { OCTEON_FEATURE_NAND, "NAND" }, { OCTEON_FEATURE_MMC, "MMC" }, { OCTEON_FEATURE_PKND, "PKND" }, { OCTEON_FEATURE_CN68XX_WQE, "CN68XX_WQE" }, { 0, NULL } }; static uint64_t octeon_get_ticks(void); static unsigned octeon_get_timecount(struct timecounter *tc); static void octeon_boot_params_init(register_t ptr); static void octeon_init_kenv(register_t ptr); static struct timecounter octeon_timecounter = { octeon_get_timecount, /* get_timecount */ 0, /* no poll_pps */ 0xffffffffu, /* octeon_mask */ 0, /* frequency */ "Octeon", /* name */ 900, /* quality (adjusted in code) */ }; void platform_cpu_init() { /* Nothing special yet */ } /* * Perform a board-level soft-reset. */ void platform_reset(void) { cvmx_write_csr(CVMX_CIU_SOFT_RST, 1); } /* * octeon_debug_symbol * * Does nothing. * Used to mark the point for simulator to begin tracing */ void octeon_debug_symbol(void) { } /* * octeon_ciu_reset * * Shutdown all CIU to IP2, IP3 mappings */ void octeon_ciu_reset(void) { uint64_t cvmctl; /* Disable all CIU interrupts by default */ cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2), 0); cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2+1), 0); cvmx_write_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2), 0); cvmx_write_csr(CVMX_CIU_INTX_EN1(cvmx_get_core_num()*2+1), 0); #ifdef SMP /* Enable the MBOX interrupts. */ cvmx_write_csr(CVMX_CIU_INTX_EN0(cvmx_get_core_num()*2+1), (1ull << (OCTEON_IRQ_MBOX0 - 8)) | (1ull << (OCTEON_IRQ_MBOX1 - 8))); #endif /* * Move the Performance Counter interrupt to OCTEON_PMC_IRQ */ cvmctl = mips_rd_cvmctl(); cvmctl &= ~(7 << 7); cvmctl |= (OCTEON_PMC_IRQ + 2) << 7; mips_wr_cvmctl(cvmctl); } static void octeon_memory_init(void) { vm_paddr_t phys_end; int64_t addr; unsigned i, j; phys_end = round_page(MIPS_KSEG0_TO_PHYS((vm_offset_t)&end)); if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) { /* Simulator we limit to 96 meg */ phys_avail[0] = phys_end; phys_avail[1] = 96 << 20; dump_avail[0] = phys_avail[0]; dump_avail[1] = phys_avail[1]; realmem = physmem = btoc(phys_avail[1] - phys_avail[0]); return; } /* * Allocate memory from bootmem 1MB at a time and merge * adjacent entries. */ i = 0; while (i < PHYS_AVAIL_ENTRIES) { /* * If there is less than 2MB of memory available in 128-byte * blocks, do not steal any more memory. We need to leave some * memory for the command queues to be allocated out of. */ if (cvmx_bootmem_available_mem(128) < 2 << 20) break; addr = cvmx_bootmem_phy_alloc(1 << 20, phys_end, ~(vm_paddr_t)0, PAGE_SIZE, 0); if (addr == -1) break; /* * The SDK needs to be able to easily map any memory that might * come to it e.g. in the form of an mbuf. Because on !n64 we * can't direct-map some addresses and we don't want to manage * temporary mappings within the SDK, don't feed memory that * can't be direct-mapped to the kernel. */ #if !defined(__mips_n64) if (!MIPS_DIRECT_MAPPABLE(addr + (1 << 20) - 1)) continue; #endif physmem += btoc(1 << 20); if (i > 0 && phys_avail[i - 1] == addr) { phys_avail[i - 1] += 1 << 20; continue; } phys_avail[i + 0] = addr; phys_avail[i + 1] = addr + (1 << 20); i += 2; } for (j = 0; j < i; j++) dump_avail[j] = phys_avail[j]; realmem = physmem; } void platform_start(__register_t a0, __register_t a1, __register_t a2 __unused, __register_t a3) { const struct octeon_feature_description *ofd; uint64_t platform_counter_freq; int rv; mips_postboot_fixup(); /* * Initialize boot parameters so that we can determine things like * which console we shoud use, etc. */ octeon_boot_params_init(a3); /* Initialize pcpu stuff */ mips_pcpu0_init(); mips_timer_early_init(cvmx_sysinfo_get()->cpu_clock_hz); /* Initialize console. */ cninit(); /* * Display information about the CPU. */ #if !defined(OCTEON_MODEL) printf("Using runtime CPU model checks.\n"); #else printf("Compiled for CPU model: " __XSTRING(OCTEON_MODEL) "\n"); #endif strcpy(cpu_model, octeon_model_get_string(cvmx_get_proc_id())); printf("CPU Model: %s\n", cpu_model); printf("CPU clock: %uMHz Core Mask: %#x\n", cvmx_sysinfo_get()->cpu_clock_hz / 1000000, cvmx_sysinfo_get()->core_mask); rv = octeon_model_version_check(cvmx_get_proc_id()); if (rv == -1) panic("%s: kernel not compatible with this processor.", __func__); /* * Display information about the board. */ #if defined(OCTEON_BOARD_CAPK_0100ND) strcpy(cpu_board, "CAPK-0100ND"); if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_CN3010_EVB_HS5) { panic("Compiled for %s, but board type is %s.", cpu_board, cvmx_board_type_to_string(cvmx_sysinfo_get()->board_type)); } #else strcpy(cpu_board, cvmx_board_type_to_string(cvmx_sysinfo_get()->board_type)); #endif printf("Board: %s\n", cpu_board); printf("Board Type: %u Revision: %u/%u\n", cvmx_sysinfo_get()->board_type, cvmx_sysinfo_get()->board_rev_major, cvmx_sysinfo_get()->board_rev_minor); printf("Serial number: %s\n", cvmx_sysinfo_get()->board_serial_number); /* * Additional on-chip hardware/settings. * * XXX Display PCI host/target? What else? */ printf("MAC address base: %6D (%u configured)\n", cvmx_sysinfo_get()->mac_addr_base, ":", cvmx_sysinfo_get()->mac_addr_count); octeon_ciu_reset(); /* * Convert U-Boot 'bootoctlinux' loader command line arguments into * boot flags and kernel environment variables. */ bootverbose = 1; octeon_init_kenv(a3); /* * For some reason on the cn38xx simulator ebase register is set to * 0x80001000 at bootup time. Move it back to the default, but * when we move to having support for multiple executives, we need * to rethink this. */ mips_wr_ebase(0x80000000); octeon_memory_init(); init_param1(); init_param2(physmem); mips_cpu_init(); pmap_bootstrap(); mips_proc0_init(); mutex_init(); kdb_init(); #ifdef KDB if (boothowto & RB_KDB) kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); #endif cpu_clock = cvmx_sysinfo_get()->cpu_clock_hz; platform_counter_freq = cpu_clock; octeon_timecounter.tc_frequency = cpu_clock; platform_timecounter = &octeon_timecounter; mips_timer_init_params(platform_counter_freq, 0); set_cputicker(octeon_get_ticks, cpu_clock, 0); #ifdef SMP /* * Clear any pending IPIs. */ cvmx_write_csr(CVMX_CIU_MBOX_CLRX(0), 0xffffffff); #endif printf("Octeon SDK: %s\n", OCTEON_SDK_VERSION_STRING); printf("Available Octeon features:"); for (ofd = octeon_feature_descriptions; ofd->ofd_string != NULL; ofd++) if (octeon_has_feature(ofd->ofd_feature)) printf(" %s", ofd->ofd_string); printf("\n"); } static uint64_t octeon_get_ticks(void) { uint64_t cvmcount; CVMX_MF_CYCLE(cvmcount); return (cvmcount); } static unsigned octeon_get_timecount(struct timecounter *tc) { return ((unsigned)octeon_get_ticks()); } static int sysctl_machdep_led_display(SYSCTL_HANDLER_ARGS) { size_t buflen; char buf[9]; int error; if (req->newptr == NULL) return (EINVAL); if (cvmx_sysinfo_get()->led_display_base_addr == 0) return (ENODEV); /* * Revision 1.x of the EBT3000 only supports 4 characters, but * other devices support 8. */ if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBT3000 && cvmx_sysinfo_get()->board_rev_major == 1) buflen = 4; else buflen = 8; if (req->newlen > buflen) return (E2BIG); error = SYSCTL_IN(req, buf, req->newlen); if (error != 0) return (error); buf[req->newlen] = '\0'; ebt3000_str_write(buf); return (0); } SYSCTL_PROC(_machdep, OID_AUTO, led_display, CTLTYPE_STRING | CTLFLAG_WR, NULL, 0, sysctl_machdep_led_display, "A", "String to display on LED display"); void cvmx_dvprintf(const char *fmt, va_list ap) { if (!bootverbose) return; vprintf(fmt, ap); } void cvmx_dprintf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); cvmx_dvprintf(fmt, ap); va_end(ap); } /** * version of printf that works better in exception context. * * @param format * * XXX If this function weren't in cvmx-interrupt.c, we'd use the SDK version. */ void cvmx_safe_printf(const char *format, ...) { char buffer[256]; char *ptr = buffer; int count; va_list args; va_start(args, format); #ifndef __U_BOOT__ count = vsnprintf(buffer, sizeof(buffer), format, args); #else count = vsprintf(buffer, format, args); #endif va_end(args); while (count-- > 0) { cvmx_uart_lsr_t lsrval; /* Spin until there is room */ do { lsrval.u64 = cvmx_read_csr(CVMX_MIO_UARTX_LSR(0)); #if !defined(CONFIG_OCTEON_SIM_SPEED) if (lsrval.s.temt == 0) cvmx_wait(10000); /* Just to reduce the load on the system */ #endif } while (lsrval.s.temt == 0); if (*ptr == '\n') cvmx_write_csr(CVMX_MIO_UARTX_THR(0), '\r'); cvmx_write_csr(CVMX_MIO_UARTX_THR(0), *ptr++); } } /* impSTART: This stuff should move back into the Cavium SDK */ /* **************************************************************************************** * * APP/BOOT DESCRIPTOR STUFF * **************************************************************************************** */ /* Define the struct that is initialized by the bootloader used by the * startup code. * * Copyright (c) 2004, 2005, 2006 Cavium Networks. * * The authors hereby grant permission to use, copy, modify, distribute, * and license this software and its documentation for any purpose, provided * that existing copyright notices are retained in all copies and that this * notice is included verbatim in any distributions. No written agreement, * license, or royalty fee is required for any of the authorized uses. * Modifications to this software may be copyrighted by their authors * and need not follow the licensing terms described here, provided that * the new terms are clearly indicated on the first page of each file where * they apply. */ #define OCTEON_CURRENT_DESC_VERSION 6 #define OCTEON_ARGV_MAX_ARGS (64) #define OCTOEN_SERIAL_LEN 20 typedef struct { /* Start of block referenced by assembly code - do not change! */ uint32_t desc_version; uint32_t desc_size; uint64_t stack_top; uint64_t heap_base; uint64_t heap_end; uint64_t entry_point; /* Only used by bootloader */ uint64_t desc_vaddr; /* End of This block referenced by assembly code - do not change! */ uint32_t exception_base_addr; uint32_t stack_size; uint32_t heap_size; uint32_t argc; /* Argc count for application */ uint32_t argv[OCTEON_ARGV_MAX_ARGS]; uint32_t flags; uint32_t core_mask; uint32_t dram_size; /**< DRAM size in megabyes */ uint32_t phy_mem_desc_addr; /**< physical address of free memory descriptor block*/ uint32_t debugger_flags_base_addr; /**< used to pass flags from app to debugger */ uint32_t eclock_hz; /**< CPU clock speed, in hz */ uint32_t dclock_hz; /**< DRAM clock speed, in hz */ uint32_t spi_clock_hz; /**< SPI4 clock in hz */ uint16_t board_type; uint8_t board_rev_major; uint8_t board_rev_minor; uint16_t chip_type; uint8_t chip_rev_major; uint8_t chip_rev_minor; char board_serial_number[OCTOEN_SERIAL_LEN]; uint8_t mac_addr_base[6]; uint8_t mac_addr_count; uint64_t cvmx_desc_vaddr; } octeon_boot_descriptor_t; static cvmx_bootinfo_t * octeon_process_app_desc_ver_6(octeon_boot_descriptor_t *app_desc_ptr) { cvmx_bootinfo_t *octeon_bootinfo; /* XXX Why is 0x00000000ffffffffULL a bad value? */ if (app_desc_ptr->cvmx_desc_vaddr == 0 || app_desc_ptr->cvmx_desc_vaddr == 0xfffffffful) { cvmx_safe_printf("Bad octeon_bootinfo %#jx\n", (uintmax_t)app_desc_ptr->cvmx_desc_vaddr); return (NULL); } octeon_bootinfo = cvmx_phys_to_ptr(app_desc_ptr->cvmx_desc_vaddr); if (octeon_bootinfo->major_version != 1) { cvmx_safe_printf("Incompatible CVMX descriptor from bootloader: %d.%d %p\n", (int) octeon_bootinfo->major_version, (int) octeon_bootinfo->minor_version, octeon_bootinfo); return (NULL); } cvmx_sysinfo_minimal_initialize(octeon_bootinfo->phy_mem_desc_addr, octeon_bootinfo->board_type, octeon_bootinfo->board_rev_major, octeon_bootinfo->board_rev_minor, octeon_bootinfo->eclock_hz); memcpy(cvmx_sysinfo_get()->mac_addr_base, octeon_bootinfo->mac_addr_base, 6); cvmx_sysinfo_get()->mac_addr_count = octeon_bootinfo->mac_addr_count; cvmx_sysinfo_get()->compact_flash_common_base_addr = octeon_bootinfo->compact_flash_common_base_addr; cvmx_sysinfo_get()->compact_flash_attribute_base_addr = octeon_bootinfo->compact_flash_attribute_base_addr; cvmx_sysinfo_get()->core_mask = octeon_bootinfo->core_mask; cvmx_sysinfo_get()->led_display_base_addr = octeon_bootinfo->led_display_base_addr; memcpy(cvmx_sysinfo_get()->board_serial_number, octeon_bootinfo->board_serial_number, sizeof cvmx_sysinfo_get()->board_serial_number); return (octeon_bootinfo); } static void octeon_boot_params_init(register_t ptr) { octeon_boot_descriptor_t *app_desc_ptr; cvmx_bootinfo_t *octeon_bootinfo; if (ptr == 0 || ptr >= MAX_APP_DESC_ADDR) { cvmx_safe_printf("app descriptor passed at invalid address %#jx\n", (uintmax_t)ptr); platform_reset(); } app_desc_ptr = (octeon_boot_descriptor_t *)(intptr_t)ptr; if (app_desc_ptr->desc_version < 6) { cvmx_safe_printf("Your boot code is too old to be supported.\n"); platform_reset(); } octeon_bootinfo = octeon_process_app_desc_ver_6(app_desc_ptr); if (octeon_bootinfo == NULL) { cvmx_safe_printf("Could not parse boot descriptor.\n"); platform_reset(); } if (cvmx_sysinfo_get()->led_display_base_addr != 0) { /* * Revision 1.x of the EBT3000 only supports 4 characters, but * other devices support 8. */ if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_EBT3000 && cvmx_sysinfo_get()->board_rev_major == 1) ebt3000_str_write("FBSD"); else ebt3000_str_write("FreeBSD!"); } if (cvmx_sysinfo_get()->phy_mem_desc_addr == (uint64_t)0) { cvmx_safe_printf("Your boot loader did not supply a memory descriptor.\n"); platform_reset(); } cvmx_bootmem_init(cvmx_sysinfo_get()->phy_mem_desc_addr); octeon_feature_init(); __cvmx_helper_cfg_init(); } /* impEND: This stuff should move back into the Cavium SDK */ static void boothowto_parse(const char *v) { if ((v == NULL) || (*v != '-')) return; while (*v != '\0') { v++; switch (*v) { case 'a': boothowto |= RB_ASKNAME; break; case 'C': boothowto |= RB_CDROM; break; case 'd': boothowto |= RB_KDB; break; case 'D': boothowto |= RB_MULTIPLE; break; case 'm': boothowto |= RB_MUTE; break; case 'g': boothowto |= RB_GDB; break; case 'h': boothowto |= RB_SERIAL; break; case 'p': boothowto |= RB_PAUSE; break; case 'r': boothowto |= RB_DFLTROOT; break; case 's': boothowto |= RB_SINGLE; break; case 'v': boothowto |= RB_VERBOSE; break; } } } /* * The boot loader command line may specify kernel environment variables or * applicable boot flags of boot(8). */ static void octeon_init_kenv(register_t ptr) { int i; char *n; char *v; octeon_boot_descriptor_t *app_desc_ptr; app_desc_ptr = (octeon_boot_descriptor_t *)(intptr_t)ptr; memset(octeon_kenv, 0, sizeof(octeon_kenv)); init_static_kenv(octeon_kenv, sizeof(octeon_kenv)); for (i = 0; i < app_desc_ptr->argc; i++) { v = cvmx_phys_to_ptr(app_desc_ptr->argv[i]); if (v == NULL) continue; if (*v == '-') { boothowto_parse(v); continue; } n = strsep(&v, "="); if (v == NULL) kern_setenv(n, "1"); else kern_setenv(n, v); } } Index: head/sys/mips/cavium/octeon_mp.c =================================================================== --- head/sys/mips/cavium/octeon_mp.c (revision 326258) +++ head/sys/mips/cavium/octeon_mp.c (revision 326259) @@ -1,154 +1,156 @@ /*- + * 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include unsigned octeon_ap_boot = ~0; void platform_ipi_send(int cpuid) { cvmx_write_csr(CVMX_CIU_MBOX_SETX(cpuid), 1); mips_wbflush(); } void platform_ipi_clear(void) { uint64_t action; action = cvmx_read_csr(CVMX_CIU_MBOX_CLRX(PCPU_GET(cpuid))); KASSERT(action == 1, ("unexpected IPIs: %#jx", (uintmax_t)action)); cvmx_write_csr(CVMX_CIU_MBOX_CLRX(PCPU_GET(cpuid)), action); } int platform_ipi_hardintr_num(void) { return (1); } int platform_ipi_softintr_num(void) { return (-1); } void platform_init_ap(int cpuid) { unsigned ciu_int_mask, clock_int_mask, ipi_int_mask; /* * Set the exception base. */ mips_wr_ebase(0x80000000); /* * Clear any pending IPIs. */ cvmx_write_csr(CVMX_CIU_MBOX_CLRX(cpuid), 0xffffffff); /* * Set up interrupts. */ octeon_ciu_reset(); /* * Unmask the clock, ipi and ciu interrupts. */ ciu_int_mask = hard_int_mask(0); clock_int_mask = hard_int_mask(5); ipi_int_mask = hard_int_mask(platform_ipi_hardintr_num()); set_intr_mask(ciu_int_mask | clock_int_mask | ipi_int_mask); mips_wbflush(); } void platform_cpu_mask(cpuset_t *mask) { uint64_t core_mask = cvmx_sysinfo_get()->core_mask; uint64_t i, m; CPU_ZERO(mask); for (i = 0, m = 1 ; i < MAXCPU; i++, m <<= 1) if (core_mask & m) CPU_SET(i, mask); } struct cpu_group * platform_smp_topo(void) { return (smp_topo_none()); } int platform_start_ap(int cpuid) { uint64_t cores_in_reset; /* * Release the core if it is in reset, and let it rev up a bit. * The real synchronization happens below via octeon_ap_boot. */ cores_in_reset = cvmx_read_csr(CVMX_CIU_PP_RST); if (cores_in_reset & (1ULL << cpuid)) { if (bootverbose) printf ("AP #%d still in reset\n", cpuid); cores_in_reset &= ~(1ULL << cpuid); cvmx_write_csr(CVMX_CIU_PP_RST, (uint64_t)(cores_in_reset)); DELAY(2000); /* Give it a moment to start */ } if (atomic_cmpset_32(&octeon_ap_boot, ~0, cpuid) == 0) return (-1); for (;;) { DELAY(1000); if (atomic_cmpset_32(&octeon_ap_boot, 0, ~0) != 0) return (0); printf("Waiting for cpu%d to start\n", cpuid); } } Index: head/sys/mips/cavium/octeon_pci_console.c =================================================================== --- head/sys/mips/cavium/octeon_pci_console.c (revision 326258) +++ head/sys/mips/cavium/octeon_pci_console.c (revision 326259) @@ -1,236 +1,238 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2012 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #ifdef OCTEON_VENDOR_RADISYS #define OPCIC_FLAG_RSYS (0x00000001) #define OPCIC_RSYS_FIFO_SIZE (0x2000) #endif struct opcic_softc { unsigned sc_flags; uint64_t sc_base_addr; }; static struct opcic_softc opcic_instance; static cn_probe_t opcic_cnprobe; static cn_init_t opcic_cninit; static cn_term_t opcic_cnterm; static cn_getc_t opcic_cngetc; static cn_putc_t opcic_cnputc; static cn_grab_t opcic_cngrab; static cn_ungrab_t opcic_cnungrab; #ifdef OCTEON_VENDOR_RADISYS static int opcic_rsys_cngetc(struct opcic_softc *); static void opcic_rsys_cnputc(struct opcic_softc *, int); #endif CONSOLE_DRIVER(opcic); static void opcic_cnprobe(struct consdev *cp) { const struct cvmx_bootmem_named_block_desc *pci_console_block; struct opcic_softc *sc; sc = &opcic_instance; sc->sc_flags = 0; sc->sc_base_addr = 0; cp->cn_pri = CN_DEAD; switch (cvmx_sysinfo_get()->board_type) { #ifdef OCTEON_VENDOR_RADISYS case CVMX_BOARD_TYPE_CUST_RADISYS_RSYS4GBE: pci_console_block = cvmx_bootmem_find_named_block("rsys_gbl_memory"); if (pci_console_block != NULL) { sc->sc_flags |= OPCIC_FLAG_RSYS; sc->sc_base_addr = pci_console_block->base_addr; break; } #endif default: pci_console_block = cvmx_bootmem_find_named_block(OCTEON_PCI_CONSOLE_BLOCK_NAME); if (pci_console_block == NULL) return; sc->sc_base_addr = pci_console_block->base_addr; break; } cp->cn_arg = sc; snprintf(cp->cn_name, sizeof cp->cn_name, "opcic@%p", cp->cn_arg); cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL; } static void opcic_cninit(struct consdev *cp) { (void)cp; } static void opcic_cnterm(struct consdev *cp) { (void)cp; } static int opcic_cngetc(struct consdev *cp) { struct opcic_softc *sc; char ch; int rv; sc = cp->cn_arg; #ifdef OCTEON_VENDOR_RADISYS if ((sc->sc_flags & OPCIC_FLAG_RSYS) != 0) return (opcic_rsys_cngetc(sc)); #endif rv = octeon_pci_console_read(sc->sc_base_addr, 0, &ch, 1, OCT_PCI_CON_FLAG_NONBLOCK); if (rv != 1) return (-1); return (ch); } static void opcic_cnputc(struct consdev *cp, int c) { struct opcic_softc *sc; char ch; int rv; sc = cp->cn_arg; ch = c; #ifdef OCTEON_VENDOR_RADISYS if ((sc->sc_flags & OPCIC_FLAG_RSYS) != 0) { opcic_rsys_cnputc(sc, c); return; } #endif rv = octeon_pci_console_write(sc->sc_base_addr, 0, &ch, 1, 0); if (rv == -1) panic("%s: octeon_pci_console_write failed.", __func__); } static void opcic_cngrab(struct consdev *cp) { (void)cp; } static void opcic_cnungrab(struct consdev *cp) { (void)cp; } #ifdef OCTEON_VENDOR_RADISYS static int opcic_rsys_cngetc(struct opcic_softc *sc) { uint64_t gbl_base; uint64_t console_base; uint64_t console_rbuf; uint64_t console_rcnt[2]; uint16_t rcnt[2]; uint16_t roff; int c; gbl_base = CVMX_ADD_IO_SEG(sc->sc_base_addr); console_base = gbl_base + 0x10; console_rbuf = console_base + 0x2018; console_rcnt[0] = console_base + 0x08; console_rcnt[1] = console_base + 0x0a; /* Check if there is anything new in the FIFO. */ rcnt[0] = cvmx_read64_uint16(console_rcnt[0]); rcnt[1] = cvmx_read64_uint16(console_rcnt[1]); if (rcnt[0] == rcnt[1]) return (-1); /* Get first new character in the FIFO. */ if (rcnt[0] != 0) roff = rcnt[0] - 1; else roff = OPCIC_RSYS_FIFO_SIZE - 1; c = cvmx_read64_uint8(console_rbuf + roff); /* Advance FIFO. */ rcnt[1] = (rcnt[1] + 1) % OPCIC_RSYS_FIFO_SIZE; cvmx_write64_uint16(console_rcnt[1], rcnt[1]); return (c); } static void opcic_rsys_cnputc(struct opcic_softc *sc, int c) { uint64_t gbl_base; uint64_t console_base; uint64_t console_wbuf; uint64_t console_wcnt; uint16_t wcnt; gbl_base = CVMX_ADD_IO_SEG(sc->sc_base_addr); console_base = gbl_base + 0x10; console_wbuf = console_base + 0x0018; console_wcnt = console_base + 0x0c; /* Append character to FIFO. */ wcnt = cvmx_read64_uint16(console_wcnt) % OPCIC_RSYS_FIFO_SIZE; cvmx_write64_uint8(console_wbuf + wcnt, (uint8_t)c); cvmx_write64_uint16(console_wcnt, wcnt + 1); } #endif Index: head/sys/mips/cavium/octeon_pmc.c =================================================================== --- head/sys/mips/cavium/octeon_pmc.c (revision 326258) +++ head/sys/mips/cavium/octeon_pmc.c (revision 326259) @@ -1,130 +1,132 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2012 Oleksandr Tymoshenko * 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct octeon_pmc_softc { struct rman irq_rman; struct resource *octeon_pmc_irq; }; static void octeon_pmc_identify(driver_t *, device_t); static int octeon_pmc_probe(device_t); static int octeon_pmc_attach(device_t); static int octeon_pmc_intr(void *); static void octeon_pmc_identify(driver_t *drv, device_t parent) { if (octeon_has_feature(OCTEON_FEATURE_USB)) BUS_ADD_CHILD(parent, 0, "pmc", 0); } static int octeon_pmc_probe(device_t dev) { if (device_get_unit(dev) != 0) return (ENXIO); device_set_desc(dev, "Cavium Octeon Performance Counters"); return (BUS_PROBE_NOWILDCARD); } static int octeon_pmc_attach(device_t dev) { struct octeon_pmc_softc *sc; int error; int rid; sc = device_get_softc(dev); rid = 0; sc->octeon_pmc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, OCTEON_PMC_IRQ, OCTEON_PMC_IRQ, 1, RF_ACTIVE); if (sc->octeon_pmc_irq == NULL) { device_printf(dev, "could not allocate irq%d\n", OCTEON_PMC_IRQ); return (ENXIO); } error = bus_setup_intr(dev, sc->octeon_pmc_irq, INTR_TYPE_MISC, octeon_pmc_intr, NULL, sc, NULL); if (error != 0) { device_printf(dev, "bus_setup_intr failed: %d\n", error); return (error); } return (0); } static int octeon_pmc_intr(void *arg) { struct trapframe *tf = PCPU_GET(curthread)->td_intr_frame; if (pmc_intr) (*pmc_intr)(PCPU_GET(cpuid), tf); return (FILTER_HANDLED); } static device_method_t octeon_pmc_methods[] = { DEVMETHOD(device_identify, octeon_pmc_identify), DEVMETHOD(device_probe, octeon_pmc_probe), DEVMETHOD(device_attach, octeon_pmc_attach), { 0, 0 } }; static driver_t octeon_pmc_driver = { "pmc", octeon_pmc_methods, sizeof(struct octeon_pmc_softc), }; static devclass_t octeon_pmc_devclass; DRIVER_MODULE(octeon_pmc, nexus, octeon_pmc_driver, octeon_pmc_devclass, 0, 0); Index: head/sys/mips/cavium/octeon_rnd.c =================================================================== --- head/sys/mips/cavium/octeon_rnd.c (revision 326258) +++ head/sys/mips/cavium/octeon_rnd.c (revision 326259) @@ -1,133 +1,135 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #define OCTEON_RND_WORDS 2 struct octeon_rnd_softc { uint64_t sc_entropy[OCTEON_RND_WORDS]; struct callout sc_callout; }; static void octeon_rnd_identify(driver_t *drv, device_t parent); static int octeon_rnd_attach(device_t dev); static int octeon_rnd_probe(device_t dev); static int octeon_rnd_detach(device_t dev); static void octeon_rnd_harvest(void *); static device_method_t octeon_rnd_methods[] = { /* Device interface */ DEVMETHOD(device_identify, octeon_rnd_identify), DEVMETHOD(device_probe, octeon_rnd_probe), DEVMETHOD(device_attach, octeon_rnd_attach), DEVMETHOD(device_detach, octeon_rnd_detach), { 0, 0 } }; static driver_t octeon_rnd_driver = { "rnd", octeon_rnd_methods, sizeof (struct octeon_rnd_softc) }; static devclass_t octeon_rnd_devclass; DRIVER_MODULE(rnd, nexus, octeon_rnd_driver, octeon_rnd_devclass, 0, 0); static void octeon_rnd_identify(driver_t *drv, device_t parent) { BUS_ADD_CHILD(parent, 0, "rnd", 0); } static int octeon_rnd_probe(device_t dev) { if (device_get_unit(dev) != 0) return (ENXIO); device_set_desc(dev, "Cavium Octeon Random Number Generator"); return (BUS_PROBE_NOWILDCARD); } static int octeon_rnd_attach(device_t dev) { struct octeon_rnd_softc *sc; sc = device_get_softc(dev); callout_init(&sc->sc_callout, 1); callout_reset(&sc->sc_callout, hz * 5, octeon_rnd_harvest, sc); cvmx_rng_enable(); return (0); } static int octeon_rnd_detach(device_t dev) { struct octeon_rnd_softc *sc; sc = device_get_softc(dev); callout_stop(&sc->sc_callout); return (0); } static void octeon_rnd_harvest(void *arg) { struct octeon_rnd_softc *sc; unsigned i; sc = arg; for (i = 0; i < OCTEON_RND_WORDS; i++) sc->sc_entropy[i] = cvmx_rng_get_random64(); /* MarkM: FIX!! Check that this does not swamp the harvester! */ random_harvest_queue(sc->sc_entropy, sizeof sc->sc_entropy, (sizeof(sc->sc_entropy)*8)/2, RANDOM_PURE_OCTEON); callout_reset(&sc->sc_callout, hz * 5, octeon_rnd_harvest, sc); } Index: head/sys/mips/cavium/octeon_rtc.c =================================================================== --- head/sys/mips/cavium/octeon_rtc.c (revision 326258) +++ head/sys/mips/cavium/octeon_rtc.c (revision 326259) @@ -1,130 +1,132 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include "clock_if.h" static int octeon_rtc_attach(device_t dev); static int octeon_rtc_probe(device_t dev); static int octeon_rtc_settime(device_t dev, struct timespec *ts); static int octeon_rtc_gettime(device_t dev, struct timespec *ts); static device_method_t octeon_rtc_methods[] = { /* Device interface */ DEVMETHOD(device_probe, octeon_rtc_probe), DEVMETHOD(device_attach, octeon_rtc_attach), /* clock interface */ DEVMETHOD(clock_gettime, octeon_rtc_gettime), DEVMETHOD(clock_settime, octeon_rtc_settime), { 0, 0 } }; static driver_t octeon_rtc_driver = { "rtc", octeon_rtc_methods, 0 }; static devclass_t octeon_rtc_devclass; DRIVER_MODULE(rtc, nexus, octeon_rtc_driver, octeon_rtc_devclass, 0, 0); static int octeon_rtc_probe(device_t dev) { cvmx_rtc_options_t supported; if (device_get_unit(dev) != 0) return (ENXIO); supported = cvmx_rtc_supported(); if (supported == 0) return (ENXIO); device_set_desc(dev, "Cavium Octeon Realtime Clock"); return (BUS_PROBE_NOWILDCARD); } static int octeon_rtc_attach(device_t dev) { cvmx_rtc_options_t supported; supported = cvmx_rtc_supported(); if ((supported & CVMX_RTC_READ) == 0) return (ENXIO); clock_register(dev, 1000000); return (0); } static int octeon_rtc_settime(device_t dev, struct timespec *ts) { cvmx_rtc_options_t supported; uint32_t status; supported = cvmx_rtc_supported(); if ((supported & CVMX_RTC_WRITE) == 0) return (ENOTSUP); status = cvmx_rtc_write(ts->tv_sec); if (status != 0) return (EINVAL); return (0); } static int octeon_rtc_gettime(device_t dev, struct timespec *ts) { uint32_t secs; secs = cvmx_rtc_read(); if (secs == 0) return (ENOTSUP); ts->tv_sec = secs; ts->tv_nsec = 0; return (0); } Index: head/sys/mips/cavium/octeon_wdog.c =================================================================== --- head/sys/mips/cavium/octeon_wdog.c (revision 326258) +++ head/sys/mips/cavium/octeon_wdog.c (revision 326259) @@ -1,275 +1,277 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009, Oleksandr Tymoshenko * Copyright (c) 2010-2011, 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 unmodified, 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. */ /* * Watchdog driver for Cavium Octeon */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #define DEFAULT_TIMER_VAL 65535 struct octeon_wdog_softc { device_t sc_dev; struct octeon_wdog_core_softc { int csc_core; struct resource *csc_intr; void *csc_intr_cookie; } sc_cores[MAXCPU]; int sc_armed; int sc_debug; }; extern void octeon_wdog_nmi_handler(void); void octeon_wdog_nmi(void); static void octeon_watchdog_arm_core(int); static void octeon_watchdog_disarm_core(int); static int octeon_wdog_attach(device_t); static void octeon_wdog_identify(driver_t *, device_t); static int octeon_wdog_intr(void *); static int octeon_wdog_probe(device_t); static void octeon_wdog_setup(struct octeon_wdog_softc *, int); static void octeon_wdog_sysctl(device_t); static void octeon_wdog_watchdog_fn(void *, u_int, int *); void octeon_wdog_nmi(void) { int core; core = cvmx_get_core_num(); printf("cpu%u: NMI detected\n", core); printf("cpu%u: Exception PC: %p\n", core, (void *)mips_rd_excpc()); printf("cpu%u: status %#x cause %#x\n", core, mips_rd_status(), mips_rd_cause()); /* * This is the end * Beautiful friend * * Just wait for Soft Reset to come and take us */ for (;;) continue; } static void octeon_watchdog_arm_core(int core) { cvmx_ciu_wdogx_t ciu_wdog; /* Poke it! */ cvmx_write_csr(CVMX_CIU_PP_POKEX(core), 1); /* * XXX * Perhaps if KDB is enabled, we should use mode=2 and drop into the * debugger on NMI? * * XXX * Timer should be calculated based on CPU frquency */ ciu_wdog.u64 = 0; ciu_wdog.s.len = DEFAULT_TIMER_VAL; ciu_wdog.s.mode = 3; cvmx_write_csr(CVMX_CIU_WDOGX(core), ciu_wdog.u64); } static void octeon_watchdog_disarm_core(int core) { cvmx_write_csr(CVMX_CIU_WDOGX(core), 0); } static void octeon_wdog_watchdog_fn(void *private, u_int cmd, int *error) { struct octeon_wdog_softc *sc = private; int core; cmd &= WD_INTERVAL; if (sc->sc_debug) device_printf(sc->sc_dev, "%s: cmd: %x\n", __func__, cmd); if (cmd > 0) { CPU_FOREACH(core) octeon_watchdog_arm_core(core); sc->sc_armed = 1; *error = 0; } else { if (sc->sc_armed) { CPU_FOREACH(core) octeon_watchdog_disarm_core(core); sc->sc_armed = 0; } } } static void octeon_wdog_sysctl(device_t dev) { struct octeon_wdog_softc *sc = device_get_softc(dev); struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "debug", CTLFLAG_RW, &sc->sc_debug, 0, "enable watchdog debugging"); SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "armed", CTLFLAG_RD, &sc->sc_armed, 0, "whether the watchdog is armed"); } static void octeon_wdog_setup(struct octeon_wdog_softc *sc, int core) { struct octeon_wdog_core_softc *csc; int rid, error; csc = &sc->sc_cores[core]; csc->csc_core = core; /* Interrupt part */ rid = 0; csc->csc_intr = bus_alloc_resource(sc->sc_dev, SYS_RES_IRQ, &rid, OCTEON_IRQ_WDOG0 + core, OCTEON_IRQ_WDOG0 + core, 1, RF_ACTIVE); if (csc->csc_intr == NULL) panic("%s: bus_alloc_resource for core %u failed", __func__, core); error = bus_setup_intr(sc->sc_dev, csc->csc_intr, INTR_TYPE_MISC, octeon_wdog_intr, NULL, csc, &csc->csc_intr_cookie); if (error != 0) panic("%s: bus_setup_intr for core %u: %d", __func__, core, error); bus_bind_intr(sc->sc_dev, csc->csc_intr, core); bus_describe_intr(sc->sc_dev, csc->csc_intr, csc->csc_intr_cookie, "cpu%u", core); if (sc->sc_armed) { /* Armed by default. */ octeon_watchdog_arm_core(core); } else { /* Disarmed by default. */ octeon_watchdog_disarm_core(core); } } static int octeon_wdog_intr(void *arg) { struct octeon_wdog_core_softc *csc = arg; KASSERT(csc->csc_core == cvmx_get_core_num(), ("got watchdog interrupt for core %u on core %u.", csc->csc_core, cvmx_get_core_num())); (void)csc; /* Poke it! */ cvmx_write_csr(CVMX_CIU_PP_POKEX(cvmx_get_core_num()), 1); return (FILTER_HANDLED); } static int octeon_wdog_probe(device_t dev) { device_set_desc(dev, "Cavium Octeon watchdog timer"); return (0); } static int octeon_wdog_attach(device_t dev) { struct octeon_wdog_softc *sc = device_get_softc(dev); uint64_t *nmi_handler = (uint64_t*)octeon_wdog_nmi_handler; int core, i; /* Initialise */ sc->sc_armed = 0; /* XXX Ought to be a tunable / config option. */ sc->sc_debug = 0; sc->sc_dev = dev; EVENTHANDLER_REGISTER(watchdog_list, octeon_wdog_watchdog_fn, sc, 0); octeon_wdog_sysctl(dev); for (i = 0; i < 16; i++) { cvmx_write_csr(CVMX_MIO_BOOT_LOC_ADR, i * 8); cvmx_write_csr(CVMX_MIO_BOOT_LOC_DAT, nmi_handler[i]); } cvmx_write_csr(CVMX_MIO_BOOT_LOC_CFGX(0), 0x81fc0000); CPU_FOREACH(core) octeon_wdog_setup(sc, core); return (0); } static void octeon_wdog_identify(driver_t *drv, device_t parent) { BUS_ADD_CHILD(parent, 0, "owdog", 0); } static device_method_t octeon_wdog_methods[] = { DEVMETHOD(device_identify, octeon_wdog_identify), DEVMETHOD(device_probe, octeon_wdog_probe), DEVMETHOD(device_attach, octeon_wdog_attach), {0, 0}, }; static driver_t octeon_wdog_driver = { "owdog", octeon_wdog_methods, sizeof(struct octeon_wdog_softc), }; static devclass_t octeon_wdog_devclass; DRIVER_MODULE(owdog, ciu, octeon_wdog_driver, octeon_wdog_devclass, 0, 0); Index: head/sys/mips/cavium/octopci.c =================================================================== --- head/sys/mips/cavium/octopci.c (revision 326258) +++ head/sys/mips/cavium/octopci.c (revision 326259) @@ -1,992 +1,994 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010-2011 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 __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 "pcib_if.h" #define NPI_WRITE(addr, value) cvmx_write64_uint32((addr) ^ 4, (value)) #define NPI_READ(addr) cvmx_read64_uint32((addr) ^ 4) struct octopci_softc { device_t sc_dev; unsigned sc_domain; unsigned sc_bus; bus_addr_t sc_io_base; unsigned sc_io_next; struct rman sc_io; bus_addr_t sc_mem1_base; unsigned sc_mem1_next; struct rman sc_mem1; }; static void octopci_identify(driver_t *, device_t); static int octopci_probe(device_t); static int octopci_attach(device_t); static int octopci_read_ivar(device_t, device_t, int, uintptr_t *); static struct resource *octopci_alloc_resource(device_t, device_t, int, int *, rman_res_t, rman_res_t, rman_res_t, u_int); static int octopci_activate_resource(device_t, device_t, int, int, struct resource *); static int octopci_maxslots(device_t); static uint32_t octopci_read_config(device_t, u_int, u_int, u_int, u_int, int); static void octopci_write_config(device_t, u_int, u_int, u_int, u_int, uint32_t, int); static int octopci_route_interrupt(device_t, device_t, int); static unsigned octopci_init_bar(device_t, unsigned, unsigned, unsigned, unsigned, uint8_t *); static unsigned octopci_init_device(device_t, unsigned, unsigned, unsigned, unsigned); static unsigned octopci_init_bus(device_t, unsigned); static void octopci_init_pci(device_t); static uint64_t octopci_cs_addr(unsigned, unsigned, unsigned, unsigned); static void octopci_identify(driver_t *drv, device_t parent) { BUS_ADD_CHILD(parent, 0, "pcib", 0); if (octeon_has_feature(OCTEON_FEATURE_PCIE)) BUS_ADD_CHILD(parent, 0, "pcib", 1); } static int octopci_probe(device_t dev) { if (octeon_has_feature(OCTEON_FEATURE_PCIE)) { device_set_desc(dev, "Cavium Octeon PCIe bridge"); return (0); } /* Check whether we are a PCI host. */ if ((cvmx_sysinfo_get()->bootloader_config_flags & CVMX_BOOTINFO_CFG_FLAG_PCI_HOST) == 0) return (ENXIO); if (device_get_unit(dev) != 0) return (ENXIO); device_set_desc(dev, "Cavium Octeon PCI bridge"); return (0); } static int octopci_attach(device_t dev) { struct octopci_softc *sc; unsigned subbus; int error; sc = device_get_softc(dev); sc->sc_dev = dev; if (octeon_has_feature(OCTEON_FEATURE_PCIE)) { sc->sc_domain = device_get_unit(dev); error = cvmx_pcie_rc_initialize(sc->sc_domain); if (error != 0) { device_printf(dev, "Failed to put PCIe bus in host mode.\n"); return (ENXIO); } /* * In RC mode, the Simple Executive programs the first bus to * be numbered as bus 1, because some IDT bridges used in * Octeon systems object to being attached to bus 0. */ sc->sc_bus = 1; sc->sc_io_base = CVMX_ADD_IO_SEG(cvmx_pcie_get_io_base_address(sc->sc_domain)); sc->sc_io.rm_descr = "Cavium Octeon PCIe I/O Ports"; sc->sc_mem1_base = CVMX_ADD_IO_SEG(cvmx_pcie_get_mem_base_address(sc->sc_domain)); sc->sc_mem1.rm_descr = "Cavium Octeon PCIe Memory"; } else { octopci_init_pci(dev); sc->sc_domain = 0; sc->sc_bus = 0; sc->sc_io_base = CVMX_ADDR_DID(CVMX_FULL_DID(CVMX_OCT_DID_PCI, CVMX_OCT_SUBDID_PCI_IO)); sc->sc_io.rm_descr = "Cavium Octeon PCI I/O Ports"; sc->sc_mem1_base = CVMX_ADDR_DID(CVMX_FULL_DID(CVMX_OCT_DID_PCI, CVMX_OCT_SUBDID_PCI_MEM1)); sc->sc_mem1.rm_descr = "Cavium Octeon PCI Memory"; } sc->sc_io.rm_type = RMAN_ARRAY; error = rman_init(&sc->sc_io); if (error != 0) return (error); error = rman_manage_region(&sc->sc_io, CVMX_OCT_PCI_IO_BASE, CVMX_OCT_PCI_IO_BASE + CVMX_OCT_PCI_IO_SIZE); if (error != 0) return (error); sc->sc_mem1.rm_type = RMAN_ARRAY; error = rman_init(&sc->sc_mem1); if (error != 0) return (error); error = rman_manage_region(&sc->sc_mem1, CVMX_OCT_PCI_MEM1_BASE, CVMX_OCT_PCI_MEM1_BASE + CVMX_OCT_PCI_MEM1_SIZE); if (error != 0) return (error); /* * Next offsets for resource allocation in octopci_init_bar. */ sc->sc_io_next = 0; sc->sc_mem1_next = 0; /* * Configure devices. */ octopci_write_config(dev, sc->sc_bus, 0, 0, PCIR_SUBBUS_1, 0xff, 1); subbus = octopci_init_bus(dev, sc->sc_bus); octopci_write_config(dev, sc->sc_bus, 0, 0, PCIR_SUBBUS_1, subbus, 1); device_add_child(dev, "pci", -1); return (bus_generic_attach(dev)); } static int octopci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { struct octopci_softc *sc; sc = device_get_softc(dev); switch (which) { case PCIB_IVAR_DOMAIN: *result = sc->sc_domain; return (0); case PCIB_IVAR_BUS: *result = sc->sc_bus; return (0); } return (ENOENT); } static struct resource * octopci_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct octopci_softc *sc; struct resource *res; struct rman *rm; int error; sc = device_get_softc(bus); switch (type) { case SYS_RES_IRQ: res = bus_generic_alloc_resource(bus, child, type, rid, start, end, count, flags); if (res != NULL) return (res); return (NULL); case SYS_RES_MEMORY: rm = &sc->sc_mem1; break; case SYS_RES_IOPORT: rm = &sc->sc_io; break; default: return (NULL); } res = rman_reserve_resource(rm, start, end, count, flags, child); if (res == NULL) return (NULL); rman_set_rid(res, *rid); rman_set_bustag(res, octopci_bus_space); switch (type) { case SYS_RES_MEMORY: rman_set_bushandle(res, sc->sc_mem1_base + rman_get_start(res)); break; case SYS_RES_IOPORT: rman_set_bushandle(res, sc->sc_io_base + rman_get_start(res)); #if __mips_n64 rman_set_virtual(res, (void *)rman_get_bushandle(res)); #else /* * XXX * We can't access ports via a 32-bit pointer. */ rman_set_virtual(res, NULL); #endif break; } if ((flags & RF_ACTIVE) != 0) { error = bus_activate_resource(child, type, *rid, res); if (error != 0) { rman_release_resource(res); return (NULL); } } return (res); } static int octopci_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *res) { bus_space_handle_t bh; int error; switch (type) { case SYS_RES_IRQ: error = bus_generic_activate_resource(bus, child, type, rid, res); if (error != 0) return (error); return (0); case SYS_RES_MEMORY: case SYS_RES_IOPORT: error = bus_space_map(rman_get_bustag(res), rman_get_bushandle(res), rman_get_size(res), 0, &bh); if (error != 0) return (error); rman_set_bushandle(res, bh); break; default: return (ENXIO); } error = rman_activate_resource(res); if (error != 0) return (error); return (0); } static int octopci_maxslots(device_t dev) { return (PCI_SLOTMAX); } static uint32_t octopci_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int bytes) { struct octopci_softc *sc; uint64_t addr; uint32_t data; sc = device_get_softc(dev); if (octeon_has_feature(OCTEON_FEATURE_PCIE)) { if (bus == 0 && slot == 0 && func == 0) return ((uint32_t)-1); switch (bytes) { case 4: return (cvmx_pcie_config_read32(sc->sc_domain, bus, slot, func, reg)); case 2: return (cvmx_pcie_config_read16(sc->sc_domain, bus, slot, func, reg)); case 1: return (cvmx_pcie_config_read8(sc->sc_domain, bus, slot, func, reg)); default: return ((uint32_t)-1); } } addr = octopci_cs_addr(bus, slot, func, reg); switch (bytes) { case 4: data = le32toh(cvmx_read64_uint32(addr)); return (data); case 2: data = le16toh(cvmx_read64_uint16(addr)); return (data); case 1: data = cvmx_read64_uint8(addr); return (data); default: return ((uint32_t)-1); } } static void octopci_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t data, int bytes) { struct octopci_softc *sc; uint64_t addr; sc = device_get_softc(dev); if (octeon_has_feature(OCTEON_FEATURE_PCIE)) { switch (bytes) { case 4: cvmx_pcie_config_write32(sc->sc_domain, bus, slot, func, reg, data); return; case 2: cvmx_pcie_config_write16(sc->sc_domain, bus, slot, func, reg, data); return; case 1: cvmx_pcie_config_write8(sc->sc_domain, bus, slot, func, reg, data); return; default: return; } } addr = octopci_cs_addr(bus, slot, func, reg); switch (bytes) { case 4: cvmx_write64_uint32(addr, htole32(data)); return; case 2: cvmx_write64_uint16(addr, htole16(data)); return; case 1: cvmx_write64_uint8(addr, data); return; default: return; } } static int octopci_route_interrupt(device_t dev, device_t child, int pin) { struct octopci_softc *sc; unsigned bus, slot, func; unsigned irq; sc = device_get_softc(dev); if (octeon_has_feature(OCTEON_FEATURE_PCIE)) return (OCTEON_IRQ_PCI_INT0 + pin - 1); bus = pci_get_bus(child); slot = pci_get_slot(child); func = pci_get_function(child); /* * Board types we have to know at compile-time. */ #if defined(OCTEON_BOARD_CAPK_0100ND) if (bus == 0 && slot == 12 && func == 0) return (OCTEON_IRQ_PCI_INT2); #endif /* * For board types we can determine at runtime. */ switch (cvmx_sysinfo_get()->board_type) { #if defined(OCTEON_VENDOR_LANNER) case CVMX_BOARD_TYPE_CUST_LANNER_MR955: return (OCTEON_IRQ_PCI_INT0 + pin - 1); case CVMX_BOARD_TYPE_CUST_LANNER_MR320: if (slot < 32) { if (slot == 3 || slot == 9) irq = pin; else irq = pin - 1; return (OCTEON_IRQ_PCI_INT0 + (irq & 3)); } break; #endif default: break; } irq = slot + pin - 3; return (OCTEON_IRQ_PCI_INT0 + (irq & 3)); } static unsigned octopci_init_bar(device_t dev, unsigned b, unsigned s, unsigned f, unsigned barnum, uint8_t *commandp) { struct octopci_softc *sc; uint64_t bar; unsigned size; int barsize; sc = device_get_softc(dev); octopci_write_config(dev, b, s, f, PCIR_BAR(barnum), 0xffffffff, 4); bar = octopci_read_config(dev, b, s, f, PCIR_BAR(barnum), 4); if (bar == 0) { /* Bar not implemented; got to next bar. */ return (barnum + 1); } if (PCI_BAR_IO(bar)) { size = ~(bar & PCIM_BAR_IO_BASE) + 1; sc->sc_io_next = roundup2(sc->sc_io_next, size); if (sc->sc_io_next + size > CVMX_OCT_PCI_IO_SIZE) { device_printf(dev, "%02x.%02x:%02x: no ports for BAR%u.\n", b, s, f, barnum); return (barnum + 1); } octopci_write_config(dev, b, s, f, PCIR_BAR(barnum), CVMX_OCT_PCI_IO_BASE + sc->sc_io_next, 4); sc->sc_io_next += size; /* * Enable I/O ports. */ *commandp |= PCIM_CMD_PORTEN; return (barnum + 1); } else { if (PCIR_BAR(barnum) == PCIR_BIOS) { /* * ROM BAR is always 32-bit. */ barsize = 1; } else { switch (bar & PCIM_BAR_MEM_TYPE) { case PCIM_BAR_MEM_64: /* * XXX * High 32 bits are all zeroes for now. */ octopci_write_config(dev, b, s, f, PCIR_BAR(barnum + 1), 0, 4); barsize = 2; break; default: barsize = 1; break; } } size = ~(bar & (uint32_t)PCIM_BAR_MEM_BASE) + 1; sc->sc_mem1_next = roundup2(sc->sc_mem1_next, size); if (sc->sc_mem1_next + size > CVMX_OCT_PCI_MEM1_SIZE) { device_printf(dev, "%02x.%02x:%02x: no memory for BAR%u.\n", b, s, f, barnum); return (barnum + barsize); } octopci_write_config(dev, b, s, f, PCIR_BAR(barnum), CVMX_OCT_PCI_MEM1_BASE + sc->sc_mem1_next, 4); sc->sc_mem1_next += size; /* * Enable memory access. */ *commandp |= PCIM_CMD_MEMEN; return (barnum + barsize); } } static unsigned octopci_init_device(device_t dev, unsigned b, unsigned s, unsigned f, unsigned secbus) { unsigned barnum, bars; uint8_t brctl; uint8_t class, subclass; uint8_t command; uint8_t hdrtype; /* Read header type (again.) */ hdrtype = octopci_read_config(dev, b, s, f, PCIR_HDRTYPE, 1); /* * Disable memory and I/O while programming BARs. */ command = octopci_read_config(dev, b, s, f, PCIR_COMMAND, 1); command &= ~(PCIM_CMD_MEMEN | PCIM_CMD_PORTEN); octopci_write_config(dev, b, s, f, PCIR_COMMAND, command, 1); DELAY(10000); /* Program BARs. */ switch (hdrtype & PCIM_HDRTYPE) { case PCIM_HDRTYPE_NORMAL: bars = 6; break; case PCIM_HDRTYPE_BRIDGE: bars = 2; break; case PCIM_HDRTYPE_CARDBUS: bars = 0; break; default: device_printf(dev, "%02x.%02x:%02x: invalid header type %#x\n", b, s, f, hdrtype); return (secbus); } barnum = 0; while (barnum < bars) barnum = octopci_init_bar(dev, b, s, f, barnum, &command); /* Enable bus mastering. */ command |= PCIM_CMD_BUSMASTEREN; /* Enable whatever facilities the BARs require. */ octopci_write_config(dev, b, s, f, PCIR_COMMAND, command, 1); DELAY(10000); /* * Set cache line size. On Octeon it should be 128 bytes, * but according to Linux some Intel bridges have trouble * with values over 64 bytes, so use 64 bytes. */ octopci_write_config(dev, b, s, f, PCIR_CACHELNSZ, 16, 1); /* Set latency timer. */ octopci_write_config(dev, b, s, f, PCIR_LATTIMER, 48, 1); /* Board-specific or device-specific fixups and workarounds. */ switch (cvmx_sysinfo_get()->board_type) { #if defined(OCTEON_VENDOR_LANNER) case CVMX_BOARD_TYPE_CUST_LANNER_MR955: if (b == 1 && s == 7 && f == 0) { bus_addr_t busaddr, unitbusaddr; uint32_t bar; uint32_t tmp; unsigned unit; /* * Set Tx DMA power. */ bar = octopci_read_config(dev, b, s, f, PCIR_BAR(3), 4); busaddr = CVMX_ADDR_DID(CVMX_FULL_DID(CVMX_OCT_DID_PCI, CVMX_OCT_SUBDID_PCI_MEM1)); busaddr += (bar & (uint32_t)PCIM_BAR_MEM_BASE); for (unit = 0; unit < 4; unit++) { unitbusaddr = busaddr + 0x430 + (unit << 8); tmp = le32toh(cvmx_read64_uint32(unitbusaddr)); tmp &= ~0x700; tmp |= 0x300; cvmx_write64_uint32(unitbusaddr, htole32(tmp)); } } break; #endif default: break; } /* Configure PCI-PCI bridges. */ class = octopci_read_config(dev, b, s, f, PCIR_CLASS, 1); if (class != PCIC_BRIDGE) return (secbus); subclass = octopci_read_config(dev, b, s, f, PCIR_SUBCLASS, 1); if (subclass != PCIS_BRIDGE_PCI) return (secbus); /* Enable memory and I/O access. */ command |= PCIM_CMD_MEMEN | PCIM_CMD_PORTEN; octopci_write_config(dev, b, s, f, PCIR_COMMAND, command, 1); /* Enable errors and parity checking. Do a bus reset. */ brctl = octopci_read_config(dev, b, s, f, PCIR_BRIDGECTL_1, 1); brctl |= PCIB_BCR_PERR_ENABLE | PCIB_BCR_SERR_ENABLE; /* Perform a secondary bus reset. */ brctl |= PCIB_BCR_SECBUS_RESET; octopci_write_config(dev, b, s, f, PCIR_BRIDGECTL_1, brctl, 1); DELAY(100000); brctl &= ~PCIB_BCR_SECBUS_RESET; octopci_write_config(dev, b, s, f, PCIR_BRIDGECTL_1, brctl, 1); secbus++; /* Program memory and I/O ranges. */ octopci_write_config(dev, b, s, f, PCIR_MEMBASE_1, CVMX_OCT_PCI_MEM1_BASE >> 16, 2); octopci_write_config(dev, b, s, f, PCIR_MEMLIMIT_1, (CVMX_OCT_PCI_MEM1_BASE + CVMX_OCT_PCI_MEM1_SIZE - 1) >> 16, 2); octopci_write_config(dev, b, s, f, PCIR_IOBASEL_1, CVMX_OCT_PCI_IO_BASE >> 8, 1); octopci_write_config(dev, b, s, f, PCIR_IOBASEH_1, CVMX_OCT_PCI_IO_BASE >> 16, 2); octopci_write_config(dev, b, s, f, PCIR_IOLIMITL_1, (CVMX_OCT_PCI_IO_BASE + CVMX_OCT_PCI_IO_SIZE - 1) >> 8, 1); octopci_write_config(dev, b, s, f, PCIR_IOLIMITH_1, (CVMX_OCT_PCI_IO_BASE + CVMX_OCT_PCI_IO_SIZE - 1) >> 16, 2); /* Program prefetchable memory decoder. */ /* XXX */ /* Probe secondary/subordinate buses. */ octopci_write_config(dev, b, s, f, PCIR_PRIBUS_1, b, 1); octopci_write_config(dev, b, s, f, PCIR_SECBUS_1, secbus, 1); octopci_write_config(dev, b, s, f, PCIR_SUBBUS_1, 0xff, 1); /* Perform a secondary bus reset. */ brctl |= PCIB_BCR_SECBUS_RESET; octopci_write_config(dev, b, s, f, PCIR_BRIDGECTL_1, brctl, 1); DELAY(100000); brctl &= ~PCIB_BCR_SECBUS_RESET; octopci_write_config(dev, b, s, f, PCIR_BRIDGECTL_1, brctl, 1); /* Give the bus time to settle now before reading configspace. */ DELAY(100000); secbus = octopci_init_bus(dev, secbus); octopci_write_config(dev, b, s, f, PCIR_SUBBUS_1, secbus, 1); return (secbus); } static unsigned octopci_init_bus(device_t dev, unsigned b) { unsigned s, f; uint8_t hdrtype; unsigned secbus; secbus = b; for (s = 0; s <= PCI_SLOTMAX; s++) { for (f = 0; f <= PCI_FUNCMAX; f++) { hdrtype = octopci_read_config(dev, b, s, f, PCIR_HDRTYPE, 1); if (hdrtype == 0xff) { if (f == 0) break; /* Next slot. */ continue; /* Next function. */ } secbus = octopci_init_device(dev, b, s, f, secbus); if (f == 0 && (hdrtype & PCIM_MFDEV) == 0) break; /* Next slot. */ } } return (secbus); } static uint64_t octopci_cs_addr(unsigned bus, unsigned slot, unsigned func, unsigned reg) { octeon_pci_config_space_address_t pci_addr; pci_addr.u64 = 0; pci_addr.s.upper = 2; pci_addr.s.io = 1; pci_addr.s.did = 3; pci_addr.s.subdid = CVMX_OCT_SUBDID_PCI_CFG; pci_addr.s.endian_swap = 1; pci_addr.s.bus = bus; pci_addr.s.dev = slot; pci_addr.s.func = func; pci_addr.s.reg = reg; return (pci_addr.u64); } static void octopci_init_pci(device_t dev) { cvmx_npi_mem_access_subid_t npi_mem_access_subid; cvmx_npi_pci_int_arb_cfg_t npi_pci_int_arb_cfg; cvmx_npi_ctl_status_t npi_ctl_status; cvmx_pci_ctl_status_2_t pci_ctl_status_2; cvmx_pci_cfg56_t pci_cfg56; cvmx_pci_cfg22_t pci_cfg22; cvmx_pci_cfg16_t pci_cfg16; cvmx_pci_cfg19_t pci_cfg19; cvmx_pci_cfg01_t pci_cfg01; unsigned i; /* * Reset the PCI bus. */ cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x1); cvmx_read_csr(CVMX_CIU_SOFT_PRST); DELAY(2000); npi_ctl_status.u64 = 0; npi_ctl_status.s.max_word = 1; npi_ctl_status.s.timer = 1; cvmx_write_csr(CVMX_NPI_CTL_STATUS, npi_ctl_status.u64); /* * Set host mode. */ switch (cvmx_sysinfo_get()->board_type) { #if defined(OCTEON_VENDOR_LANNER) case CVMX_BOARD_TYPE_CUST_LANNER_MR320: case CVMX_BOARD_TYPE_CUST_LANNER_MR955: /* 32-bit PCI-X */ cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x0); break; #endif default: /* 64-bit PCI-X */ cvmx_write_csr(CVMX_CIU_SOFT_PRST, 0x4); break; } cvmx_read_csr(CVMX_CIU_SOFT_PRST); DELAY(2000); /* * Enable BARs and configure big BAR mode. */ pci_ctl_status_2.u32 = 0; pci_ctl_status_2.s.bb1_hole = 5; /* 256MB hole in BAR1 */ pci_ctl_status_2.s.bb1_siz = 1; /* BAR1 is 2GB */ pci_ctl_status_2.s.bb_ca = 1; /* Bypass cache for big BAR */ pci_ctl_status_2.s.bb_es = 1; /* Do big BAR byte-swapping */ pci_ctl_status_2.s.bb1 = 1; /* BAR1 is big */ pci_ctl_status_2.s.bb0 = 1; /* BAR0 is big */ pci_ctl_status_2.s.bar2pres = 1; /* BAR2 present */ pci_ctl_status_2.s.pmo_amod = 1; /* Round-robin priority */ pci_ctl_status_2.s.tsr_hwm = 1; pci_ctl_status_2.s.bar2_enb = 1; /* Enable BAR2 */ pci_ctl_status_2.s.bar2_esx = 1; /* Do BAR2 byte-swapping */ pci_ctl_status_2.s.bar2_cax = 1; /* Bypass cache for BAR2 */ NPI_WRITE(CVMX_NPI_PCI_CTL_STATUS_2, pci_ctl_status_2.u32); DELAY(2000); pci_ctl_status_2.u32 = NPI_READ(CVMX_NPI_PCI_CTL_STATUS_2); device_printf(dev, "%u-bit PCI%s bus.\n", pci_ctl_status_2.s.ap_64ad ? 64 : 32, pci_ctl_status_2.s.ap_pcix ? "-X" : ""); /* * Set up transaction splitting, etc., parameters. */ pci_cfg19.u32 = 0; pci_cfg19.s.mrbcm = 1; if (pci_ctl_status_2.s.ap_pcix) { pci_cfg19.s.mdrrmc = 0; pci_cfg19.s.tdomc = 4; } else { pci_cfg19.s.mdrrmc = 2; pci_cfg19.s.tdomc = 1; } NPI_WRITE(CVMX_NPI_PCI_CFG19, pci_cfg19.u32); NPI_READ(CVMX_NPI_PCI_CFG19); /* * Set up PCI error handling and memory access. */ pci_cfg01.u32 = 0; pci_cfg01.s.fbbe = 1; pci_cfg01.s.see = 1; pci_cfg01.s.pee = 1; pci_cfg01.s.me = 1; pci_cfg01.s.msae = 1; if (pci_ctl_status_2.s.ap_pcix) { pci_cfg01.s.fbb = 0; } else { pci_cfg01.s.fbb = 1; } NPI_WRITE(CVMX_NPI_PCI_CFG01, pci_cfg01.u32); NPI_READ(CVMX_NPI_PCI_CFG01); /* * Enable the Octeon bus arbiter. */ npi_pci_int_arb_cfg.u64 = 0; npi_pci_int_arb_cfg.s.en = 1; cvmx_write_csr(CVMX_NPI_PCI_INT_ARB_CFG, npi_pci_int_arb_cfg.u64); /* * Disable master latency timer. */ pci_cfg16.u32 = 0; pci_cfg16.s.mltd = 1; NPI_WRITE(CVMX_NPI_PCI_CFG16, pci_cfg16.u32); NPI_READ(CVMX_NPI_PCI_CFG16); /* * Configure master arbiter. */ pci_cfg22.u32 = 0; pci_cfg22.s.flush = 1; pci_cfg22.s.mrv = 255; NPI_WRITE(CVMX_NPI_PCI_CFG22, pci_cfg22.u32); NPI_READ(CVMX_NPI_PCI_CFG22); /* * Set up PCI-X capabilities. */ if (pci_ctl_status_2.s.ap_pcix) { pci_cfg56.u32 = 0; pci_cfg56.s.most = 3; pci_cfg56.s.roe = 1; /* Enable relaxed ordering */ pci_cfg56.s.dpere = 1; pci_cfg56.s.ncp = 0xe8; pci_cfg56.s.pxcid = 7; NPI_WRITE(CVMX_NPI_PCI_CFG56, pci_cfg56.u32); NPI_READ(CVMX_NPI_PCI_CFG56); } NPI_WRITE(CVMX_NPI_PCI_READ_CMD_6, 0x22); NPI_READ(CVMX_NPI_PCI_READ_CMD_6); NPI_WRITE(CVMX_NPI_PCI_READ_CMD_C, 0x33); NPI_READ(CVMX_NPI_PCI_READ_CMD_C); NPI_WRITE(CVMX_NPI_PCI_READ_CMD_E, 0x33); NPI_READ(CVMX_NPI_PCI_READ_CMD_E); /* * Configure MEM1 sub-DID access. */ npi_mem_access_subid.u64 = 0; npi_mem_access_subid.s.esr = 1; /* Byte-swap on read */ npi_mem_access_subid.s.esw = 1; /* Byte-swap on write */ switch (cvmx_sysinfo_get()->board_type) { #if defined(OCTEON_VENDOR_LANNER) case CVMX_BOARD_TYPE_CUST_LANNER_MR955: npi_mem_access_subid.s.shortl = 1; break; #endif default: break; } cvmx_write_csr(CVMX_NPI_MEM_ACCESS_SUBID3, npi_mem_access_subid.u64); /* * Configure BAR2. Linux says this has to come first. */ NPI_WRITE(CVMX_NPI_PCI_CFG08, 0x00000000); NPI_READ(CVMX_NPI_PCI_CFG08); NPI_WRITE(CVMX_NPI_PCI_CFG09, 0x00000080); NPI_READ(CVMX_NPI_PCI_CFG09); /* * Disable BAR1 IndexX. */ for (i = 0; i < 32; i++) { NPI_WRITE(CVMX_NPI_PCI_BAR1_INDEXX(i), 0); NPI_READ(CVMX_NPI_PCI_BAR1_INDEXX(i)); } /* * Configure BAR0 and BAR1. */ NPI_WRITE(CVMX_NPI_PCI_CFG04, 0x00000000); NPI_READ(CVMX_NPI_PCI_CFG04); NPI_WRITE(CVMX_NPI_PCI_CFG05, 0x00000000); NPI_READ(CVMX_NPI_PCI_CFG05); NPI_WRITE(CVMX_NPI_PCI_CFG06, 0x80000000); NPI_READ(CVMX_NPI_PCI_CFG06); NPI_WRITE(CVMX_NPI_PCI_CFG07, 0x00000000); NPI_READ(CVMX_NPI_PCI_CFG07); /* * Clear PCI interrupts. */ cvmx_write_csr(CVMX_NPI_PCI_INT_SUM2, 0xffffffffffffffffull); } static device_method_t octopci_methods[] = { /* Device interface */ DEVMETHOD(device_identify, octopci_identify), DEVMETHOD(device_probe, octopci_probe), DEVMETHOD(device_attach, octopci_attach), /* Bus interface */ DEVMETHOD(bus_read_ivar, octopci_read_ivar), DEVMETHOD(bus_alloc_resource, octopci_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource,octopci_activate_resource), DEVMETHOD(bus_deactivate_resource,bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_add_child, bus_generic_add_child), /* pcib interface */ DEVMETHOD(pcib_maxslots, octopci_maxslots), DEVMETHOD(pcib_read_config, octopci_read_config), DEVMETHOD(pcib_write_config, octopci_write_config), DEVMETHOD(pcib_route_interrupt, octopci_route_interrupt), DEVMETHOD(pcib_request_feature, pcib_request_feature_allow), DEVMETHOD_END }; static driver_t octopci_driver = { "pcib", octopci_methods, sizeof(struct octopci_softc), }; static devclass_t octopci_devclass; DRIVER_MODULE(octopci, ciu, octopci_driver, octopci_devclass, 0, 0); Index: head/sys/mips/cavium/octopci_bus_space.c =================================================================== --- head/sys/mips/cavium/octopci_bus_space.c (revision 326258) +++ head/sys/mips/cavium/octopci_bus_space.c (revision 326259) @@ -1,575 +1,577 @@ /* $NetBSD: bus.h,v 1.12 1997/10/01 08:25:15 fvdl Exp $ */ /*- * $Id: bus.h,v 1.6 2007/08/09 11:23:32 katta Exp $ * + * SPDX-License-Identifier: BSD-2-Clause-NetBSD AND BSD-4-Clause + * * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. */ /* * Copyright (c) 1996 Charles M. Hannum. All rights reserved. * Copyright (c) 1996 Christopher G. Demetriou. 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Christopher G. Demetriou * for the NetBSD Project. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. * * from: src/sys/alpha/include/bus.h,v 1.5 1999/08/28 00:38:40 peter * $FreeBSD$ */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static struct bus_space octopci_space = { /* cookie */ (void *) 0, /* mapping/unmapping */ octopci_bs_map, octopci_bs_unmap, octopci_bs_subregion, /* allocation/deallocation */ NULL, NULL, /* barrier */ octopci_bs_barrier, /* read (single) */ octopci_bs_r_1, octopci_bs_r_2, octopci_bs_r_4, NULL, /* read multiple */ octopci_bs_rm_1, octopci_bs_rm_2, octopci_bs_rm_4, NULL, /* read region */ octopci_bs_rr_1, octopci_bs_rr_2, octopci_bs_rr_4, NULL, /* write (single) */ octopci_bs_w_1, octopci_bs_w_2, octopci_bs_w_4, NULL, /* write multiple */ octopci_bs_wm_1, octopci_bs_wm_2, octopci_bs_wm_4, NULL, /* write region */ NULL, octopci_bs_wr_2, octopci_bs_wr_4, NULL, /* set multiple */ NULL, NULL, NULL, NULL, /* set region */ NULL, octopci_bs_sr_2, octopci_bs_sr_4, NULL, /* copy */ NULL, octopci_bs_c_2, NULL, NULL, /* read (single) stream */ octopci_bs_r_1, octopci_bs_r_2, octopci_bs_r_4, NULL, /* read multiple stream */ octopci_bs_rm_1, octopci_bs_rm_2, octopci_bs_rm_4, NULL, /* read region stream */ octopci_bs_rr_1, octopci_bs_rr_2, octopci_bs_rr_4, NULL, /* write (single) stream */ octopci_bs_w_1, octopci_bs_w_2, octopci_bs_w_4, NULL, /* write multiple stream */ octopci_bs_wm_1, octopci_bs_wm_2, octopci_bs_wm_4, NULL, /* write region stream */ NULL, octopci_bs_wr_2, octopci_bs_wr_4, NULL, }; #define rd8(a) cvmx_read64_uint8(a) #define rd16(a) le16toh(cvmx_read64_uint16(a)) #define rd32(a) le32toh(cvmx_read64_uint32(a)) #define wr8(a, v) cvmx_write64_uint8(a, v) #define wr16(a, v) cvmx_write64_uint16(a, htole16(v)) #define wr32(a, v) cvmx_write64_uint32(a, htole32(v)) /* octopci bus_space tag */ bus_space_tag_t octopci_bus_space = &octopci_space; int octopci_bs_map(void *t __unused, bus_addr_t addr, bus_size_t size __unused, int flags __unused, bus_space_handle_t *bshp) { *bshp = addr; return (0); } void octopci_bs_unmap(void *t __unused, bus_space_handle_t bh __unused, bus_size_t size __unused) { /* Do nothing */ } int octopci_bs_subregion(void *t __unused, bus_space_handle_t handle, bus_size_t offset, bus_size_t size __unused, bus_space_handle_t *bshp) { *bshp = handle + offset; return (0); } uint8_t octopci_bs_r_1(void *t, bus_space_handle_t handle, bus_size_t offset) { return (rd8(handle + offset)); } uint16_t octopci_bs_r_2(void *t, bus_space_handle_t handle, bus_size_t offset) { return (rd16(handle + offset)); } uint32_t octopci_bs_r_4(void *t, bus_space_handle_t handle, bus_size_t offset) { return (rd32(handle + offset)); } void octopci_bs_rm_1(void *t, bus_space_handle_t bsh, bus_size_t offset, uint8_t *addr, size_t count) { while (count--) *addr++ = rd8(bsh + offset); } void octopci_bs_rm_2(void *t, bus_space_handle_t bsh, bus_size_t offset, uint16_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) *addr++ = rd16(baddr); } void octopci_bs_rm_4(void *t, bus_space_handle_t bsh, bus_size_t offset, uint32_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) *addr++ = rd32(baddr); } /* * Read `count' 1, 2, 4, or 8 byte quantities from bus space * described by tag/handle and starting at `offset' and copy into * buffer provided. */ void octopci_bs_rr_1(void *t, bus_space_handle_t bsh, bus_size_t offset, uint8_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { *addr++ = rd8(baddr); baddr += 1; } } void octopci_bs_rr_2(void *t, bus_space_handle_t bsh, bus_size_t offset, uint16_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { *addr++ = rd16(baddr); baddr += 2; } } void octopci_bs_rr_4(void *t, bus_space_handle_t bsh, bus_size_t offset, uint32_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { *addr++ = rd32(baddr); baddr += 4; } } /* * Write the 1, 2, 4, or 8 byte value `value' to bus space * described by tag/handle/offset. */ void octopci_bs_w_1(void *t, bus_space_handle_t bsh, bus_size_t offset, uint8_t value) { wr8(bsh + offset, value); } void octopci_bs_w_2(void *t, bus_space_handle_t bsh, bus_size_t offset, uint16_t value) { wr16(bsh + offset, value); } void octopci_bs_w_4(void *t, bus_space_handle_t bsh, bus_size_t offset, uint32_t value) { wr32(bsh + offset, value); } /* * Write `count' 1, 2, 4, or 8 byte quantities from the buffer * provided to bus space described by tag/handle/offset. */ void octopci_bs_wm_1(void *t, bus_space_handle_t bsh, bus_size_t offset, const uint8_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) wr8(baddr, *addr++); } void octopci_bs_wm_2(void *t, bus_space_handle_t bsh, bus_size_t offset, const uint16_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) wr16(baddr, *addr++); } void octopci_bs_wm_4(void *t, bus_space_handle_t bsh, bus_size_t offset, const uint32_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) wr32(baddr, *addr++); } /* * Write `count' 1, 2, 4, or 8 byte quantities from the buffer provided * to bus space described by tag/handle starting at `offset'. */ void octopci_bs_wr_1(void *t, bus_space_handle_t bsh, bus_size_t offset, const uint8_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { wr8(baddr, *addr++); baddr += 1; } } void octopci_bs_wr_2(void *t, bus_space_handle_t bsh, bus_size_t offset, const uint16_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { wr16(baddr, *addr++); baddr += 2; } } void octopci_bs_wr_4(void *t, bus_space_handle_t bsh, bus_size_t offset, const uint32_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { wr32(baddr, *addr++); baddr += 4; } } /* * Write the 1, 2, 4, or 8 byte value `val' to bus space described * by tag/handle/offset `count' times. */ void octopci_bs_sm_1(void *t, bus_space_handle_t bsh, bus_size_t offset, uint8_t value, size_t count) { bus_addr_t addr = bsh + offset; while (count--) wr8(addr, value); } void octopci_bs_sm_2(void *t, bus_space_handle_t bsh, bus_size_t offset, uint16_t value, size_t count) { bus_addr_t addr = bsh + offset; while (count--) wr16(addr, value); } void octopci_bs_sm_4(void *t, bus_space_handle_t bsh, bus_size_t offset, uint32_t value, size_t count) { bus_addr_t addr = bsh + offset; while (count--) wr32(addr, value); } /* * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described * by tag/handle starting at `offset'. */ void octopci_bs_sr_1(void *t, bus_space_handle_t bsh, bus_size_t offset, uint8_t value, size_t count) { bus_addr_t addr = bsh + offset; for (; count != 0; count--, addr++) wr8(addr, value); } void octopci_bs_sr_2(void *t, bus_space_handle_t bsh, bus_size_t offset, uint16_t value, size_t count) { bus_addr_t addr = bsh + offset; for (; count != 0; count--, addr += 2) wr16(addr, value); } void octopci_bs_sr_4(void *t, bus_space_handle_t bsh, bus_size_t offset, uint32_t value, size_t count) { bus_addr_t addr = bsh + offset; for (; count != 0; count--, addr += 4) wr32(addr, value); } /* * Copy `count' 1, 2, 4, or 8 byte values from bus space starting * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2. */ void octopci_bs_c_1(void *t, bus_space_handle_t bsh1, bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, size_t count) { bus_addr_t addr1 = bsh1 + off1; bus_addr_t addr2 = bsh2 + off2; if (addr1 >= addr2) { /* src after dest: copy forward */ for (; count != 0; count--, addr1++, addr2++) wr8(addr2, rd8(addr1)); } else { /* dest after src: copy backwards */ for (addr1 += (count - 1), addr2 += (count - 1); count != 0; count--, addr1--, addr2--) wr8(addr2, rd8(addr1)); } } void octopci_bs_c_2(void *t, bus_space_handle_t bsh1, bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, size_t count) { bus_addr_t addr1 = bsh1 + off1; bus_addr_t addr2 = bsh2 + off2; if (addr1 >= addr2) { /* src after dest: copy forward */ for (; count != 0; count--, addr1 += 2, addr2 += 2) wr16(addr2, rd16(addr1)); } else { /* dest after src: copy backwards */ for (addr1 += 2 * (count - 1), addr2 += 2 * (count - 1); count != 0; count--, addr1 -= 2, addr2 -= 2) wr16(addr2, rd16(addr1)); } } void octopci_bs_c_4(void *t, bus_space_handle_t bsh1, bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, size_t count) { bus_addr_t addr1 = bsh1 + off1; bus_addr_t addr2 = bsh2 + off2; if (addr1 >= addr2) { /* src after dest: copy forward */ for (; count != 0; count--, addr1 += 4, addr2 += 4) wr32(addr2, rd32(addr1)); } else { /* dest after src: copy backwards */ for (addr1 += 4 * (count - 1), addr2 += 4 * (count - 1); count != 0; count--, addr1 -= 4, addr2 -= 4) wr32(addr2, rd32(addr1)); } } void octopci_bs_barrier(void *t __unused, bus_space_handle_t bsh __unused, bus_size_t offset __unused, bus_size_t len __unused, int flags) { #if 0 if (flags & BUS_SPACE_BARRIER_WRITE) mips_dcache_wbinv_all(); #endif } Index: head/sys/mips/cavium/octopcivar.h =================================================================== --- head/sys/mips/cavium/octopcivar.h (revision 326258) +++ head/sys/mips/cavium/octopcivar.h (revision 326259) @@ -1,35 +1,37 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 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$ */ #ifndef _MIPS_CAVIUM_OCTOPCIVAR_H #define _MIPS_CAVIUM_OCTOPCIVAR_H DECLARE_BUS_SPACE_PROTOTYPES(octopci); extern bus_space_tag_t octopci_bus_space; #endif /* !_MIPS_CAVIUM_OCTOPCIVAR_H */ Index: head/sys/mips/cavium/uart_bus_octeonusart.c =================================================================== --- head/sys/mips/cavium/uart_bus_octeonusart.c (revision 326258) +++ head/sys/mips/cavium/uart_bus_octeonusart.c (revision 326259) @@ -1,111 +1,113 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006 Wojciech A. Koszek * 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 * $Id$ */ /* * Skeleton of this file was based on respective code for ARM * code written by Olivier Houchard. */ /* * XXXMIPS: This file is hacked from arm/... . XXXMIPS here means this file is * experimental and was written for MIPS32 port. */ #include "opt_uart.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "uart_if.h" extern struct uart_class uart_oct16550_class; static int uart_octeon_probe(device_t dev); static device_method_t uart_octeon_methods[] = { /* Device interface */ DEVMETHOD(device_probe, uart_octeon_probe), DEVMETHOD(device_attach, uart_bus_attach), DEVMETHOD(device_detach, uart_bus_detach), {0, 0} }; static driver_t uart_octeon_driver = { uart_driver_name, uart_octeon_methods, sizeof(struct uart_softc), }; extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs; static int uart_octeon_probe(device_t dev) { struct uart_softc *sc; int unit; unit = device_get_unit(dev); sc = device_get_softc(dev); sc->sc_class = &uart_oct16550_class; /* * We inherit the settings from the systme console. Note, the bst * bad bus_space_map are bogus here, but obio doesn't yet support * them, it seems. */ sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs); bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas)); sc->sc_bas.bst = uart_bus_space_mem; /* * XXX * RBR isn't really a great base address. */ if (bus_space_map(sc->sc_bas.bst, CVMX_MIO_UARTX_RBR(0), uart_getrange(sc->sc_class), 0, &sc->sc_bas.bsh) != 0) return (ENXIO); return (uart_bus_probe(dev, sc->sc_bas.regshft, 0, 0, 0, unit)); } DRIVER_MODULE(uart, obio, uart_octeon_driver, uart_devclass, 0, 0); Index: head/sys/mips/cavium/uart_cpu_octeonusart.c =================================================================== --- head/sys/mips/cavium/uart_cpu_octeonusart.c (revision 326258) +++ head/sys/mips/cavium/uart_cpu_octeonusart.c (revision 326259) @@ -1,174 +1,176 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009 M. Warner Losh * Copyright (c) 2006 Wojciech A. Koszek * 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. * * $Id$ */ #include "opt_uart.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include bus_space_tag_t uart_bus_space_io; bus_space_tag_t uart_bus_space_mem; /* * Specailized uart bus space. We present a 1 apart byte oriented * bus to the outside world, but internally translate to/from the 8-apart * 64-bit word bus that's on the octeon. We only support simple read/write * in this space. Everything else is undefined. */ static uint8_t ou_bs_r_1(void *t, bus_space_handle_t handle, bus_size_t offset) { return (cvmx_read64_uint64(handle + offset)); } static uint16_t ou_bs_r_2(void *t, bus_space_handle_t handle, bus_size_t offset) { return (cvmx_read64_uint64(handle + offset)); } static uint32_t ou_bs_r_4(void *t, bus_space_handle_t handle, bus_size_t offset) { return (cvmx_read64_uint64(handle + offset)); } static uint64_t ou_bs_r_8(void *t, bus_space_handle_t handle, bus_size_t offset) { return (cvmx_read64_uint64(handle + offset)); } static void ou_bs_w_1(void *t, bus_space_handle_t bsh, bus_size_t offset, uint8_t value) { cvmx_write64_uint64(bsh + offset, value); } static void ou_bs_w_2(void *t, bus_space_handle_t bsh, bus_size_t offset, uint16_t value) { cvmx_write64_uint64(bsh + offset, value); } static void ou_bs_w_4(void *t, bus_space_handle_t bsh, bus_size_t offset, uint32_t value) { cvmx_write64_uint64(bsh + offset, value); } static void ou_bs_w_8(void *t, bus_space_handle_t bsh, bus_size_t offset, uint64_t value) { cvmx_write64_uint64(bsh + offset, value); } struct bus_space octeon_uart_tag = { .bs_map = generic_bs_map, .bs_unmap = generic_bs_unmap, .bs_subregion = generic_bs_subregion, .bs_barrier = generic_bs_barrier, .bs_r_1 = ou_bs_r_1, .bs_r_2 = ou_bs_r_2, .bs_r_4 = ou_bs_r_4, .bs_r_8 = ou_bs_r_8, .bs_w_1 = ou_bs_w_1, .bs_w_2 = ou_bs_w_2, .bs_w_4 = ou_bs_w_4, .bs_w_8 = ou_bs_w_8, }; extern struct uart_class uart_oct16550_class; int uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) { return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0); } int uart_cpu_getdev(int devtype, struct uart_devinfo *di) { struct uart_class *class = &uart_oct16550_class; /* * These fields need to be setup corretly for uart_getenv to * work in all cases. */ uart_bus_space_io = NULL; /* No io map for this device */ uart_bus_space_mem = &octeon_uart_tag; di->bas.bst = uart_bus_space_mem; /* * If env specification for UART exists it takes precedence: * hw.uart.console="mm:0xf1012000" or similar */ if (uart_getenv(devtype, di, class) == 0) return (0); /* * Fallback to UART0 for console. */ di->ops = uart_getops(class); di->bas.chan = 0; /* XXX */ if (bus_space_map(di->bas.bst, CVMX_MIO_UARTX_RBR(0), uart_getrange(class), 0, &di->bas.bsh) != 0) return (ENXIO); di->bas.regshft = 3; di->bas.rclk = 0; di->baudrate = 115200; di->databits = 8; di->stopbits = 1; di->parity = UART_PARITY_NONE; return (0); } Index: head/sys/mips/cavium/uart_dev_oct16550.c =================================================================== --- head/sys/mips/cavium/uart_dev_oct16550.c (revision 326258) +++ head/sys/mips/cavium/uart_dev_oct16550.c (revision 326259) @@ -1,848 +1,850 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-2-Clause + * * Copyright (c) 2003 Marcel Moolenaar * 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 ``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 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. */ /* * uart_dev_oct16550.c * * Derived from uart_dev_ns8250.c * * 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 ``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 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 "uart_if.h" /* * Clear pending interrupts. THRE is cleared by reading IIR. Data * that may have been received gets lost here. */ static void oct16550_clrint (struct uart_bas *bas) { uint8_t iir; iir = uart_getreg(bas, REG_IIR); while ((iir & IIR_NOPEND) == 0) { iir &= IIR_IMASK; if (iir == IIR_RLS) (void)uart_getreg(bas, REG_LSR); else if (iir == IIR_RXRDY || iir == IIR_RXTOUT) (void)uart_getreg(bas, REG_DATA); else if (iir == IIR_MLSC) (void)uart_getreg(bas, REG_MSR); else if (iir == IIR_BUSY) (void) uart_getreg(bas, REG_USR); uart_barrier(bas); iir = uart_getreg(bas, REG_IIR); } } static int delay_changed = 1; static int oct16550_delay (struct uart_bas *bas) { int divisor; u_char lcr; static int delay = 0; if (!delay_changed) return delay; delay_changed = 0; lcr = uart_getreg(bas, REG_LCR); uart_setreg(bas, REG_LCR, lcr | LCR_DLAB); uart_barrier(bas); divisor = uart_getreg(bas, REG_DLL) | (uart_getreg(bas, REG_DLH) << 8); uart_barrier(bas); uart_setreg(bas, REG_LCR, lcr); uart_barrier(bas); if(!bas->rclk) return 10; /* return an approx delay value */ /* 1/10th the time to transmit 1 character (estimate). */ if (divisor <= 134) return (16000000 * divisor / bas->rclk); return (16000 * divisor / (bas->rclk / 1000)); } static int oct16550_divisor (int rclk, int baudrate) { int actual_baud, divisor; int error; if (baudrate == 0) return (0); divisor = (rclk / (baudrate << 3) + 1) >> 1; if (divisor == 0 || divisor >= 65536) return (0); actual_baud = rclk / (divisor << 4); /* 10 times error in percent: */ error = ((actual_baud - baudrate) * 2000 / baudrate + 1) >> 1; /* 3.0% maximum error tolerance: */ if (error < -30 || error > 30) return (0); return (divisor); } static int oct16550_drain (struct uart_bas *bas, int what) { int delay, limit; delay = oct16550_delay(bas); if (what & UART_DRAIN_TRANSMITTER) { /* * Pick an arbitrary high limit to avoid getting stuck in * an infinite loop when the hardware is broken. Make the * limit high enough to handle large FIFOs. */ limit = 10*10*10*1024; while ((uart_getreg(bas, REG_LSR) & LSR_TEMT) == 0 && --limit) DELAY(delay); if (limit == 0) { /* printf("oct16550: transmitter appears stuck... "); */ return (0); } } if (what & UART_DRAIN_RECEIVER) { /* * Pick an arbitrary high limit to avoid getting stuck in * an infinite loop when the hardware is broken. Make the * limit high enough to handle large FIFOs and integrated * UARTs. The HP rx2600 for example has 3 UARTs on the * management board that tend to get a lot of data send * to it when the UART is first activated. */ limit=10*4096; while ((uart_getreg(bas, REG_LSR) & LSR_RXRDY) && --limit) { (void)uart_getreg(bas, REG_DATA); uart_barrier(bas); DELAY(delay << 2); } if (limit == 0) { /* printf("oct16550: receiver appears broken... "); */ return (EIO); } } return (0); } /* * We can only flush UARTs with FIFOs. UARTs without FIFOs should be * drained. WARNING: this function clobbers the FIFO setting! */ static void oct16550_flush (struct uart_bas *bas, int what) { uint8_t fcr; fcr = FCR_ENABLE; if (what & UART_FLUSH_TRANSMITTER) fcr |= FCR_XMT_RST; if (what & UART_FLUSH_RECEIVER) fcr |= FCR_RCV_RST; uart_setreg(bas, REG_FCR, fcr); uart_barrier(bas); } static int oct16550_param (struct uart_bas *bas, int baudrate, int databits, int stopbits, int parity) { int divisor; uint8_t lcr; lcr = 0; if (databits >= 8) lcr |= LCR_8BITS; else if (databits == 7) lcr |= LCR_7BITS; else if (databits == 6) lcr |= LCR_6BITS; else lcr |= LCR_5BITS; if (stopbits > 1) lcr |= LCR_STOPB; lcr |= parity << 3; /* Set baudrate. */ if (baudrate > 0) { divisor = oct16550_divisor(bas->rclk, baudrate); if (divisor == 0) return (EINVAL); uart_setreg(bas, REG_LCR, lcr | LCR_DLAB); uart_barrier(bas); uart_setreg(bas, REG_DLL, divisor & 0xff); uart_setreg(bas, REG_DLH, (divisor >> 8) & 0xff); uart_barrier(bas); delay_changed = 1; } /* Set LCR and clear DLAB. */ uart_setreg(bas, REG_LCR, lcr); uart_barrier(bas); return (0); } /* * Low-level UART interface. */ static int oct16550_probe(struct uart_bas *bas); static void oct16550_init(struct uart_bas *bas, int, int, int, int); static void oct16550_term(struct uart_bas *bas); static void oct16550_putc(struct uart_bas *bas, int); static int oct16550_rxready(struct uart_bas *bas); static int oct16550_getc(struct uart_bas *bas, struct mtx *); struct uart_ops uart_oct16550_ops = { .probe = oct16550_probe, .init = oct16550_init, .term = oct16550_term, .putc = oct16550_putc, .rxready = oct16550_rxready, .getc = oct16550_getc, }; static int oct16550_probe (struct uart_bas *bas) { u_char val; /* Check known 0 bits that don't depend on DLAB. */ val = uart_getreg(bas, REG_IIR); if (val & 0x30) return (ENXIO); val = uart_getreg(bas, REG_MCR); if (val & 0xc0) return (ENXIO); val = uart_getreg(bas, REG_USR); if (val & 0xe0) return (ENXIO); return (0); } static void oct16550_init (struct uart_bas *bas, int baudrate, int databits, int stopbits, int parity) { u_char ier; oct16550_param(bas, baudrate, databits, stopbits, parity); /* Disable all interrupt sources. */ ier = uart_getreg(bas, REG_IER) & 0x0; uart_setreg(bas, REG_IER, ier); uart_barrier(bas); /* Disable the FIFO (if present). */ // uart_setreg(bas, REG_FCR, 0); uart_barrier(bas); /* Set RTS & DTR. */ uart_setreg(bas, REG_MCR, MCR_RTS | MCR_DTR); uart_barrier(bas); oct16550_clrint(bas); } static void oct16550_term (struct uart_bas *bas) { /* Clear RTS & DTR. */ uart_setreg(bas, REG_MCR, 0); uart_barrier(bas); } static inline void oct16550_wait_txhr_empty (struct uart_bas *bas, int limit, int delay) { while (((uart_getreg(bas, REG_LSR) & LSR_THRE) == 0) && ((uart_getreg(bas, REG_USR) & USR_TXFIFO_NOTFULL) == 0)) DELAY(delay); } static void oct16550_putc (struct uart_bas *bas, int c) { int delay; /* 1/10th the time to transmit 1 character (estimate). */ delay = oct16550_delay(bas); oct16550_wait_txhr_empty(bas, 100, delay); uart_setreg(bas, REG_DATA, c); uart_barrier(bas); oct16550_wait_txhr_empty(bas, 100, delay); } static int oct16550_rxready (struct uart_bas *bas) { return ((uart_getreg(bas, REG_LSR) & LSR_RXRDY) != 0 ? 1 : 0); } static int oct16550_getc (struct uart_bas *bas, struct mtx *hwmtx) { int c, delay; uart_lock(hwmtx); /* 1/10th the time to transmit 1 character (estimate). */ delay = oct16550_delay(bas); while ((uart_getreg(bas, REG_LSR) & LSR_RXRDY) == 0) { uart_unlock(hwmtx); DELAY(delay); uart_lock(hwmtx); } c = uart_getreg(bas, REG_DATA); uart_unlock(hwmtx); return (c); } /* * High-level UART interface. */ struct oct16550_softc { struct uart_softc base; uint8_t fcr; uint8_t ier; uint8_t mcr; }; static int oct16550_bus_attach(struct uart_softc *); static int oct16550_bus_detach(struct uart_softc *); static int oct16550_bus_flush(struct uart_softc *, int); static int oct16550_bus_getsig(struct uart_softc *); static int oct16550_bus_ioctl(struct uart_softc *, int, intptr_t); static int oct16550_bus_ipend(struct uart_softc *); static int oct16550_bus_param(struct uart_softc *, int, int, int, int); static int oct16550_bus_probe(struct uart_softc *); static int oct16550_bus_receive(struct uart_softc *); static int oct16550_bus_setsig(struct uart_softc *, int); static int oct16550_bus_transmit(struct uart_softc *); static void oct16550_bus_grab(struct uart_softc *); static void oct16550_bus_ungrab(struct uart_softc *); static kobj_method_t oct16550_methods[] = { KOBJMETHOD(uart_attach, oct16550_bus_attach), KOBJMETHOD(uart_detach, oct16550_bus_detach), KOBJMETHOD(uart_flush, oct16550_bus_flush), KOBJMETHOD(uart_getsig, oct16550_bus_getsig), KOBJMETHOD(uart_ioctl, oct16550_bus_ioctl), KOBJMETHOD(uart_ipend, oct16550_bus_ipend), KOBJMETHOD(uart_param, oct16550_bus_param), KOBJMETHOD(uart_probe, oct16550_bus_probe), KOBJMETHOD(uart_receive, oct16550_bus_receive), KOBJMETHOD(uart_setsig, oct16550_bus_setsig), KOBJMETHOD(uart_transmit, oct16550_bus_transmit), KOBJMETHOD(uart_grab, oct16550_bus_grab), KOBJMETHOD(uart_ungrab, oct16550_bus_ungrab), { 0, 0 } }; struct uart_class uart_oct16550_class = { "oct16550 class", oct16550_methods, sizeof(struct oct16550_softc), .uc_ops = &uart_oct16550_ops, .uc_range = 8 << 3, .uc_rclk = 0, .uc_rshift = 0 }; #define SIGCHG(c, i, s, d) \ if (c) { \ i |= (i & s) ? s : s | d; \ } else { \ i = (i & s) ? (i & ~s) | d : i; \ } static int oct16550_bus_attach (struct uart_softc *sc) { struct oct16550_softc *oct16550 = (struct oct16550_softc*)sc; struct uart_bas *bas; int unit; unit = device_get_unit(sc->sc_dev); bas = &sc->sc_bas; oct16550_drain(bas, UART_DRAIN_TRANSMITTER); oct16550->mcr = uart_getreg(bas, REG_MCR); oct16550->fcr = FCR_ENABLE | FCR_RX_HIGH; uart_setreg(bas, REG_FCR, oct16550->fcr); uart_barrier(bas); oct16550_bus_flush(sc, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER); if (oct16550->mcr & MCR_DTR) sc->sc_hwsig |= SER_DTR; if (oct16550->mcr & MCR_RTS) sc->sc_hwsig |= SER_RTS; oct16550_bus_getsig(sc); oct16550_clrint(bas); oct16550->ier = uart_getreg(bas, REG_IER) & 0xf0; oct16550->ier |= IER_EMSC | IER_ERLS | IER_ERXRDY; uart_setreg(bas, REG_IER, oct16550->ier); uart_barrier(bas); return (0); } static int oct16550_bus_detach (struct uart_softc *sc) { struct uart_bas *bas; u_char ier; bas = &sc->sc_bas; ier = uart_getreg(bas, REG_IER) & 0xf0; uart_setreg(bas, REG_IER, ier); uart_barrier(bas); oct16550_clrint(bas); return (0); } static int oct16550_bus_flush (struct uart_softc *sc, int what) { struct oct16550_softc *oct16550 = (struct oct16550_softc*)sc; struct uart_bas *bas; int error; bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); if (sc->sc_rxfifosz > 1) { oct16550_flush(bas, what); uart_setreg(bas, REG_FCR, oct16550->fcr); uart_barrier(bas); error = 0; } else error = oct16550_drain(bas, what); uart_unlock(sc->sc_hwmtx); return (error); } static int oct16550_bus_getsig (struct uart_softc *sc) { uint32_t new, old, sig; uint8_t msr; do { old = sc->sc_hwsig; sig = old; uart_lock(sc->sc_hwmtx); msr = uart_getreg(&sc->sc_bas, REG_MSR); uart_unlock(sc->sc_hwmtx); SIGCHG(msr & MSR_DSR, sig, SER_DSR, SER_DDSR); SIGCHG(msr & MSR_CTS, sig, SER_CTS, SER_DCTS); SIGCHG(msr & MSR_DCD, sig, SER_DCD, SER_DDCD); SIGCHG(msr & MSR_RI, sig, SER_RI, SER_DRI); new = sig & ~SER_MASK_DELTA; } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); return (sig); } static int oct16550_bus_ioctl (struct uart_softc *sc, int request, intptr_t data) { struct uart_bas *bas; int baudrate, divisor, error; uint8_t efr, lcr; bas = &sc->sc_bas; error = 0; uart_lock(sc->sc_hwmtx); switch (request) { case UART_IOCTL_BREAK: lcr = uart_getreg(bas, REG_LCR); if (data) lcr |= LCR_SBREAK; else lcr &= ~LCR_SBREAK; uart_setreg(bas, REG_LCR, lcr); uart_barrier(bas); break; case UART_IOCTL_IFLOW: lcr = uart_getreg(bas, REG_LCR); uart_barrier(bas); uart_setreg(bas, REG_LCR, 0xbf); uart_barrier(bas); efr = uart_getreg(bas, REG_EFR); if (data) efr |= EFR_RTS; else efr &= ~EFR_RTS; uart_setreg(bas, REG_EFR, efr); uart_barrier(bas); uart_setreg(bas, REG_LCR, lcr); uart_barrier(bas); break; case UART_IOCTL_OFLOW: lcr = uart_getreg(bas, REG_LCR); uart_barrier(bas); uart_setreg(bas, REG_LCR, 0xbf); uart_barrier(bas); efr = uart_getreg(bas, REG_EFR); if (data) efr |= EFR_CTS; else efr &= ~EFR_CTS; uart_setreg(bas, REG_EFR, efr); uart_barrier(bas); uart_setreg(bas, REG_LCR, lcr); uart_barrier(bas); break; case UART_IOCTL_BAUD: lcr = uart_getreg(bas, REG_LCR); uart_setreg(bas, REG_LCR, lcr | LCR_DLAB); uart_barrier(bas); divisor = uart_getreg(bas, REG_DLL) | (uart_getreg(bas, REG_DLH) << 8); uart_barrier(bas); uart_setreg(bas, REG_LCR, lcr); uart_barrier(bas); baudrate = (divisor > 0) ? bas->rclk / divisor / 16 : 0; delay_changed = 1; if (baudrate > 0) *(int*)data = baudrate; else error = ENXIO; break; default: error = EINVAL; break; } uart_unlock(sc->sc_hwmtx); return (error); } static int oct16550_bus_ipend(struct uart_softc *sc) { struct uart_bas *bas; int ipend = 0; uint8_t iir, lsr; bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); iir = uart_getreg(bas, REG_IIR) & IIR_IMASK; if (iir != IIR_NOPEND) { if (iir == IIR_RLS) { lsr = uart_getreg(bas, REG_LSR); if (lsr & LSR_OE) ipend |= SER_INT_OVERRUN; if (lsr & LSR_BI) ipend |= SER_INT_BREAK; if (lsr & LSR_RXRDY) ipend |= SER_INT_RXREADY; } else if (iir == IIR_RXRDY) { ipend |= SER_INT_RXREADY; } else if (iir == IIR_RXTOUT) { ipend |= SER_INT_RXREADY; } else if (iir == IIR_TXRDY) { ipend |= SER_INT_TXIDLE; } else if (iir == IIR_MLSC) { ipend |= SER_INT_SIGCHG; } else if (iir == IIR_BUSY) { (void) uart_getreg(bas, REG_USR); } } uart_unlock(sc->sc_hwmtx); return (ipend); } static int oct16550_bus_param (struct uart_softc *sc, int baudrate, int databits, int stopbits, int parity) { struct uart_bas *bas; int error; bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); error = oct16550_param(bas, baudrate, databits, stopbits, parity); uart_unlock(sc->sc_hwmtx); return (error); } static int oct16550_bus_probe (struct uart_softc *sc) { struct uart_bas *bas; int error; bas = &sc->sc_bas; bas->rclk = uart_oct16550_class.uc_rclk = cvmx_clock_get_rate(CVMX_CLOCK_SCLK); error = oct16550_probe(bas); if (error) { return (error); } uart_setreg(bas, REG_MCR, (MCR_DTR | MCR_RTS)); /* * Enable FIFOs. And check that the UART has them. If not, we're * done. Since this is the first time we enable the FIFOs, we reset * them. */ oct16550_drain(bas, UART_DRAIN_TRANSMITTER); #define ENABLE_OCTEON_FIFO 1 #ifdef ENABLE_OCTEON_FIFO uart_setreg(bas, REG_FCR, FCR_ENABLE | FCR_XMT_RST | FCR_RCV_RST); #endif uart_barrier(bas); oct16550_flush(bas, UART_FLUSH_RECEIVER|UART_FLUSH_TRANSMITTER); if (device_get_unit(sc->sc_dev)) { device_set_desc(sc->sc_dev, "Octeon-16550 channel 1"); } else { device_set_desc(sc->sc_dev, "Octeon-16550 channel 0"); } #ifdef ENABLE_OCTEON_FIFO sc->sc_rxfifosz = 64; sc->sc_txfifosz = 64; #else sc->sc_rxfifosz = 1; sc->sc_txfifosz = 1; #endif #if 0 /* * XXX there are some issues related to hardware flow control and * it's likely that uart(4) is the cause. This basicly needs more * investigation, but we avoid using for hardware flow control * until then. */ /* 16650s or higher have automatic flow control. */ if (sc->sc_rxfifosz > 16) { sc->sc_hwiflow = 1; sc->sc_hwoflow = 1; } #endif return (0); } static int oct16550_bus_receive (struct uart_softc *sc) { struct uart_bas *bas; int xc; uint8_t lsr; bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); lsr = uart_getreg(bas, REG_LSR); while (lsr & LSR_RXRDY) { if (uart_rx_full(sc)) { sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; break; } xc = uart_getreg(bas, REG_DATA); if (lsr & LSR_FE) xc |= UART_STAT_FRAMERR; if (lsr & LSR_PE) xc |= UART_STAT_PARERR; uart_rx_put(sc, xc); lsr = uart_getreg(bas, REG_LSR); } /* Discard everything left in the Rx FIFO. */ /* * First do a dummy read/discard anyway, in case the UART was lying to us. * This problem was seen on board, when IIR said RBR, but LSR said no RXRDY * Results in a stuck ipend loop. */ (void)uart_getreg(bas, REG_DATA); while (lsr & LSR_RXRDY) { (void)uart_getreg(bas, REG_DATA); uart_barrier(bas); lsr = uart_getreg(bas, REG_LSR); } uart_unlock(sc->sc_hwmtx); return (0); } static int oct16550_bus_setsig (struct uart_softc *sc, int sig) { struct oct16550_softc *oct16550 = (struct oct16550_softc*)sc; struct uart_bas *bas; uint32_t new, old; bas = &sc->sc_bas; do { old = sc->sc_hwsig; new = old; if (sig & SER_DDTR) { SIGCHG(sig & SER_DTR, new, SER_DTR, SER_DDTR); } if (sig & SER_DRTS) { SIGCHG(sig & SER_RTS, new, SER_RTS, SER_DRTS); } } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); uart_lock(sc->sc_hwmtx); oct16550->mcr &= ~(MCR_DTR|MCR_RTS); if (new & SER_DTR) oct16550->mcr |= MCR_DTR; if (new & SER_RTS) oct16550->mcr |= MCR_RTS; uart_setreg(bas, REG_MCR, oct16550->mcr); uart_barrier(bas); uart_unlock(sc->sc_hwmtx); return (0); } static int oct16550_bus_transmit (struct uart_softc *sc) { struct oct16550_softc *oct16550 = (struct oct16550_softc*)sc; struct uart_bas *bas; int i; bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); #ifdef NO_UART_INTERRUPTS for (i = 0; i < sc->sc_txdatasz; i++) { oct16550_putc(bas, sc->sc_txbuf[i]); } #else oct16550_wait_txhr_empty(bas, 100, oct16550_delay(bas)); uart_setreg(bas, REG_IER, oct16550->ier | IER_ETXRDY); uart_barrier(bas); for (i = 0; i < sc->sc_txdatasz; i++) { uart_setreg(bas, REG_DATA, sc->sc_txbuf[i]); uart_barrier(bas); } sc->sc_txbusy = 1; #endif uart_unlock(sc->sc_hwmtx); return (0); } static void oct16550_bus_grab(struct uart_softc *sc) { struct uart_bas *bas = &sc->sc_bas; /* * turn off all interrupts to enter polling mode. Leave the * saved mask alone. We'll restore whatever it was in ungrab. * All pending interupt signals are reset when IER is set to 0. */ uart_lock(sc->sc_hwmtx); uart_setreg(bas, REG_IER, 0); uart_barrier(bas); uart_unlock(sc->sc_hwmtx); } static void oct16550_bus_ungrab(struct uart_softc *sc) { struct oct16550_softc *oct16550 = (struct oct16550_softc*)sc; struct uart_bas *bas = &sc->sc_bas; /* * Restore previous interrupt mask */ uart_lock(sc->sc_hwmtx); uart_setreg(bas, REG_IER, oct16550->ier); uart_barrier(bas); uart_unlock(sc->sc_hwmtx); } Index: head/sys/mips/cavium/usb/octusb.c =================================================================== --- head/sys/mips/cavium/usb/octusb.c (revision 326258) +++ head/sys/mips/cavium/usb/octusb.c (revision 326259) @@ -1,1944 +1,1946 @@ #include __FBSDID("$FreeBSD$"); /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Hans Petter Selasky. 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. */ /* * This file contains the driver for Octeon Executive Library USB * Controller driver API. */ /* TODO: The root HUB port callback is not yet implemented. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define USB_DEBUG_VAR octusbdebug #include #include #include #include #include #include #include #include #include #include #include #include #include #define OCTUSB_BUS2SC(bus) \ ((struct octusb_softc *)(((uint8_t *)(bus)) - \ ((uint8_t *)&(((struct octusb_softc *)0)->sc_bus)))) #ifdef USB_DEBUG static int octusbdebug = 0; static SYSCTL_NODE(_hw_usb, OID_AUTO, octusb, CTLFLAG_RW, 0, "OCTUSB"); SYSCTL_INT(_hw_usb_octusb, OID_AUTO, debug, CTLFLAG_RWTUN, &octusbdebug, 0, "OCTUSB debug level"); #endif struct octusb_std_temp { octusb_cmd_t *func; struct octusb_td *td; struct octusb_td *td_next; struct usb_page_cache *pc; uint32_t offset; uint32_t len; uint8_t short_pkt; uint8_t setup_alt_next; }; extern struct usb_bus_methods octusb_bus_methods; extern struct usb_pipe_methods octusb_device_bulk_methods; extern struct usb_pipe_methods octusb_device_ctrl_methods; extern struct usb_pipe_methods octusb_device_intr_methods; extern struct usb_pipe_methods octusb_device_isoc_methods; static void octusb_standard_done(struct usb_xfer *); static void octusb_device_done(struct usb_xfer *, usb_error_t); static void octusb_timeout(void *); static void octusb_do_poll(struct usb_bus *); static cvmx_usb_speed_t octusb_convert_speed(enum usb_dev_speed speed) { ; /* indent fix */ switch (speed) { case USB_SPEED_HIGH: return (CVMX_USB_SPEED_HIGH); case USB_SPEED_FULL: return (CVMX_USB_SPEED_FULL); default: return (CVMX_USB_SPEED_LOW); } } static cvmx_usb_transfer_t octusb_convert_ep_type(uint8_t ep_type) { ; /* indent fix */ switch (ep_type & UE_XFERTYPE) { case UE_CONTROL: return (CVMX_USB_TRANSFER_CONTROL); case UE_INTERRUPT: return (CVMX_USB_TRANSFER_INTERRUPT); case UE_ISOCHRONOUS: return (CVMX_USB_TRANSFER_ISOCHRONOUS); case UE_BULK: return (CVMX_USB_TRANSFER_BULK); default: return (0); /* should not happen */ } } static uint8_t octusb_host_alloc_endpoint(struct octusb_td *td) { struct octusb_softc *sc; int ep_handle; if (td->qh->fixup_pending) return (1); /* busy */ if (td->qh->ep_allocated) return (0); /* success */ /* get softc */ sc = td->qh->sc; ep_handle = cvmx_usb_open_pipe( &sc->sc_port[td->qh->root_port_index].state, 0, td->qh->dev_addr, td->qh->ep_num & UE_ADDR, octusb_convert_speed(td->qh->dev_speed), td->qh->max_packet_size, octusb_convert_ep_type(td->qh->ep_type), (td->qh->ep_num & UE_DIR_IN) ? CVMX_USB_DIRECTION_IN : CVMX_USB_DIRECTION_OUT, td->qh->ep_interval, (td->qh->dev_speed == USB_SPEED_HIGH) ? td->qh->ep_mult : 0, td->qh->hs_hub_addr, td->qh->hs_hub_port); if (ep_handle < 0) { DPRINTFN(1, "cvmx_usb_open_pipe failed: %d\n", ep_handle); return (1); /* busy */ } cvmx_usb_set_toggle( &sc->sc_port[td->qh->root_port_index].state, ep_handle, td->qh->ep_toggle_next); td->qh->fixup_handle = -1; td->qh->fixup_complete = 0; td->qh->fixup_len = 0; td->qh->fixup_off = 0; td->qh->fixup_pending = 0; td->qh->fixup_actlen = 0; td->qh->ep_handle = ep_handle; td->qh->ep_allocated = 1; return (0); /* success */ } static void octusb_host_free_endpoint(struct octusb_td *td) { struct octusb_softc *sc; if (td->qh->ep_allocated == 0) return; /* get softc */ sc = td->qh->sc; if (td->qh->fixup_handle >= 0) { /* cancel, if any */ cvmx_usb_cancel(&sc->sc_port[td->qh->root_port_index].state, td->qh->ep_handle, td->qh->fixup_handle); } cvmx_usb_close_pipe(&sc->sc_port[td->qh->root_port_index].state, td->qh->ep_handle); td->qh->ep_allocated = 0; } static void octusb_complete_cb(cvmx_usb_state_t *state, cvmx_usb_callback_t reason, cvmx_usb_complete_t status, int pipe_handle, int submit_handle, int bytes_transferred, void *user_data) { struct octusb_td *td; if (reason != CVMX_USB_CALLBACK_TRANSFER_COMPLETE) return; td = user_data; td->qh->fixup_complete = 1; td->qh->fixup_pending = 0; td->qh->fixup_actlen = bytes_transferred; td->qh->fixup_handle = -1; switch (status) { case CVMX_USB_COMPLETE_SUCCESS: case CVMX_USB_COMPLETE_SHORT: td->error_any = 0; td->error_stall = 0; break; case CVMX_USB_COMPLETE_STALL: td->error_stall = 1; td->error_any = 1; break; default: td->error_any = 1; break; } } static uint8_t octusb_host_control_header_tx(struct octusb_td *td) { int status; /* allocate endpoint and check pending */ if (octusb_host_alloc_endpoint(td)) return (1); /* busy */ /* check error */ if (td->error_any) return (0); /* done */ if (td->qh->fixup_complete != 0) { /* clear complete flag */ td->qh->fixup_complete = 0; /* flush data */ usb_pc_cpu_invalidate(td->qh->fixup_pc); return (0); /* done */ } /* verify length */ if (td->remainder != 8) { td->error_any = 1; return (0); /* done */ } usbd_copy_out(td->pc, td->offset, td->qh->fixup_buf, 8); /* update offset and remainder */ td->offset += 8; td->remainder -= 8; /* setup data length and offset */ td->qh->fixup_len = UGETW(td->qh->fixup_buf + 6); td->qh->fixup_off = 0; if (td->qh->fixup_len > (OCTUSB_MAX_FIXUP - 8)) { td->error_any = 1; return (0); /* done */ } /* do control IN request */ if (td->qh->fixup_buf[0] & UE_DIR_IN) { struct octusb_softc *sc; /* get softc */ sc = td->qh->sc; /* flush data */ usb_pc_cpu_flush(td->qh->fixup_pc); status = cvmx_usb_submit_control( &sc->sc_port[td->qh->root_port_index].state, td->qh->ep_handle, td->qh->fixup_phys, td->qh->fixup_phys + 8, td->qh->fixup_len, &octusb_complete_cb, td); /* check status */ if (status < 0) { td->error_any = 1; return (0); /* done */ } td->qh->fixup_handle = status; td->qh->fixup_pending = 1; td->qh->fixup_complete = 0; return (1); /* busy */ } return (0); /* done */ } static uint8_t octusb_host_control_data_tx(struct octusb_td *td) { uint32_t rem; /* allocate endpoint and check pending */ if (octusb_host_alloc_endpoint(td)) return (1); /* busy */ /* check error */ if (td->error_any) return (0); /* done */ rem = td->qh->fixup_len - td->qh->fixup_off; if (td->remainder > rem) { td->error_any = 1; DPRINTFN(1, "Excess setup transmit data\n"); return (0); /* done */ } usbd_copy_out(td->pc, td->offset, td->qh->fixup_buf + td->qh->fixup_off + 8, td->remainder); td->offset += td->remainder; td->qh->fixup_off += td->remainder; td->remainder = 0; return (0); /* done */ } static uint8_t octusb_host_control_data_rx(struct octusb_td *td) { uint32_t rem; /* allocate endpoint and check pending */ if (octusb_host_alloc_endpoint(td)) return (1); /* busy */ /* check error */ if (td->error_any) return (0); /* done */ /* copy data from buffer */ rem = td->qh->fixup_actlen - td->qh->fixup_off; if (rem > td->remainder) rem = td->remainder; usbd_copy_in(td->pc, td->offset, td->qh->fixup_buf + td->qh->fixup_off + 8, rem); td->offset += rem; td->remainder -= rem; td->qh->fixup_off += rem; return (0); /* done */ } static uint8_t octusb_host_control_status_tx(struct octusb_td *td) { int status; /* allocate endpoint and check pending */ if (octusb_host_alloc_endpoint(td)) return (1); /* busy */ /* check error */ if (td->error_any) return (0); /* done */ if (td->qh->fixup_complete != 0) { /* clear complete flag */ td->qh->fixup_complete = 0; /* done */ return (0); } /* do control IN request */ if (!(td->qh->fixup_buf[0] & UE_DIR_IN)) { struct octusb_softc *sc; /* get softc */ sc = td->qh->sc; /* flush data */ usb_pc_cpu_flush(td->qh->fixup_pc); /* start USB transfer */ status = cvmx_usb_submit_control( &sc->sc_port[td->qh->root_port_index].state, td->qh->ep_handle, td->qh->fixup_phys, td->qh->fixup_phys + 8, td->qh->fixup_len, &octusb_complete_cb, td); /* check status */ if (status < 0) { td->error_any = 1; return (0); /* done */ } td->qh->fixup_handle = status; td->qh->fixup_pending = 1; td->qh->fixup_complete = 0; return (1); /* busy */ } return (0); /* done */ } static uint8_t octusb_non_control_data_tx(struct octusb_td *td) { struct octusb_softc *sc; uint32_t rem; int status; /* allocate endpoint and check pending */ if (octusb_host_alloc_endpoint(td)) return (1); /* busy */ /* check error */ if (td->error_any) return (0); /* done */ if ((td->qh->fixup_complete != 0) && ((td->qh->ep_type & UE_XFERTYPE) == UE_ISOCHRONOUS)) { td->qh->fixup_complete = 0; return (0); /* done */ } /* check complete */ if (td->remainder == 0) { if (td->short_pkt) return (0); /* complete */ /* else need to send a zero length packet */ rem = 0; td->short_pkt = 1; } else { /* get maximum length */ rem = OCTUSB_MAX_FIXUP % td->qh->max_frame_size; rem = OCTUSB_MAX_FIXUP - rem; if (rem == 0) { /* should not happen */ DPRINTFN(1, "Fixup buffer is too small\n"); td->error_any = 1; return (0); /* done */ } /* get minimum length */ if (rem > td->remainder) { rem = td->remainder; if ((rem == 0) || (rem % td->qh->max_frame_size)) td->short_pkt = 1; } /* copy data into fixup buffer */ usbd_copy_out(td->pc, td->offset, td->qh->fixup_buf, rem); /* flush data */ usb_pc_cpu_flush(td->qh->fixup_pc); /* pre-increment TX buffer offset */ td->offset += rem; td->remainder -= rem; } /* get softc */ sc = td->qh->sc; switch (td->qh->ep_type & UE_XFERTYPE) { case UE_ISOCHRONOUS: td->qh->iso_pkt.offset = 0; td->qh->iso_pkt.length = rem; td->qh->iso_pkt.status = 0; /* start USB transfer */ status = cvmx_usb_submit_isochronous(&sc->sc_port[td->qh->root_port_index].state, td->qh->ep_handle, 1, CVMX_USB_ISOCHRONOUS_FLAGS_ALLOW_SHORT | CVMX_USB_ISOCHRONOUS_FLAGS_ASAP, 1, &td->qh->iso_pkt, td->qh->fixup_phys, rem, &octusb_complete_cb, td); break; case UE_BULK: /* start USB transfer */ status = cvmx_usb_submit_bulk(&sc->sc_port[td->qh->root_port_index].state, td->qh->ep_handle, td->qh->fixup_phys, rem, &octusb_complete_cb, td); break; case UE_INTERRUPT: /* start USB transfer (interrupt or interrupt) */ status = cvmx_usb_submit_interrupt(&sc->sc_port[td->qh->root_port_index].state, td->qh->ep_handle, td->qh->fixup_phys, rem, &octusb_complete_cb, td); break; default: status = -1; break; } /* check status */ if (status < 0) { td->error_any = 1; return (0); /* done */ } td->qh->fixup_handle = status; td->qh->fixup_len = rem; td->qh->fixup_pending = 1; td->qh->fixup_complete = 0; return (1); /* busy */ } static uint8_t octusb_non_control_data_rx(struct octusb_td *td) { struct octusb_softc *sc; uint32_t rem; int status; uint8_t got_short; /* allocate endpoint and check pending */ if (octusb_host_alloc_endpoint(td)) return (1); /* busy */ /* check error */ if (td->error_any) return (0); /* done */ got_short = 0; if (td->qh->fixup_complete != 0) { /* invalidate data */ usb_pc_cpu_invalidate(td->qh->fixup_pc); rem = td->qh->fixup_actlen; /* verify transfer length */ if (rem != td->qh->fixup_len) { if (rem < td->qh->fixup_len) { /* we have a short packet */ td->short_pkt = 1; got_short = 1; } else { /* invalid USB packet */ td->error_any = 1; return (0); /* we are complete */ } } /* copy data into fixup buffer */ usbd_copy_in(td->pc, td->offset, td->qh->fixup_buf, rem); /* post-increment RX buffer offset */ td->offset += rem; td->remainder -= rem; td->qh->fixup_complete = 0; if ((td->qh->ep_type & UE_XFERTYPE) == UE_ISOCHRONOUS) return (0); /* done */ } /* check if we are complete */ if ((td->remainder == 0) || got_short) { if (td->short_pkt) { /* we are complete */ return (0); } /* else need to receive a zero length packet */ rem = 0; td->short_pkt = 1; } else { /* get maximum length */ rem = OCTUSB_MAX_FIXUP % td->qh->max_frame_size; rem = OCTUSB_MAX_FIXUP - rem; if (rem == 0) { /* should not happen */ DPRINTFN(1, "Fixup buffer is too small\n"); td->error_any = 1; return (0); /* done */ } /* get minimum length */ if (rem > td->remainder) rem = td->remainder; } /* invalidate data */ usb_pc_cpu_invalidate(td->qh->fixup_pc); /* get softc */ sc = td->qh->sc; switch (td->qh->ep_type & UE_XFERTYPE) { case UE_ISOCHRONOUS: td->qh->iso_pkt.offset = 0; td->qh->iso_pkt.length = rem; td->qh->iso_pkt.status = 0; /* start USB transfer */ status = cvmx_usb_submit_isochronous(&sc->sc_port[td->qh->root_port_index].state, td->qh->ep_handle, 1, CVMX_USB_ISOCHRONOUS_FLAGS_ALLOW_SHORT | CVMX_USB_ISOCHRONOUS_FLAGS_ASAP, 1, &td->qh->iso_pkt, td->qh->fixup_phys, rem, &octusb_complete_cb, td); break; case UE_BULK: /* start USB transfer */ status = cvmx_usb_submit_bulk(&sc->sc_port[td->qh->root_port_index].state, td->qh->ep_handle, td->qh->fixup_phys, rem, &octusb_complete_cb, td); break; case UE_INTERRUPT: /* start USB transfer */ status = cvmx_usb_submit_interrupt(&sc->sc_port[td->qh->root_port_index].state, td->qh->ep_handle, td->qh->fixup_phys, rem, &octusb_complete_cb, td); break; default: status = -1; break; } /* check status */ if (status < 0) { td->error_any = 1; return (0); /* done */ } td->qh->fixup_handle = status; td->qh->fixup_len = rem; td->qh->fixup_pending = 1; td->qh->fixup_complete = 0; return (1); /* busy */ } static uint8_t octusb_xfer_do_fifo(struct usb_xfer *xfer) { struct octusb_td *td; DPRINTFN(8, "\n"); td = xfer->td_transfer_cache; while (1) { if ((td->func) (td)) { /* operation in progress */ break; } if (((void *)td) == xfer->td_transfer_last) { goto done; } if (td->error_any) { goto done; } else if (td->remainder > 0) { /* * We had a short transfer. If there is no * alternate next, stop processing ! */ if (td->alt_next == 0) goto done; } /* * Fetch the next transfer descriptor and transfer * some flags to the next transfer descriptor */ td = td->obj_next; xfer->td_transfer_cache = td; } return (1); /* not complete */ done: /* compute all actual lengths */ octusb_standard_done(xfer); return (0); /* complete */ } static usb_error_t octusb_standard_done_sub(struct usb_xfer *xfer) { struct octusb_td *td; uint32_t len; usb_error_t error; DPRINTFN(8, "\n"); td = xfer->td_transfer_cache; do { len = td->remainder; if (xfer->aframes != xfer->nframes) { /* * Verify the length and subtract * the remainder from "frlengths[]": */ if (len > xfer->frlengths[xfer->aframes]) { td->error_any = 1; } else { xfer->frlengths[xfer->aframes] -= len; } } /* Check for transfer error */ if (td->error_any) { /* the transfer is finished */ error = td->error_stall ? USB_ERR_STALLED : USB_ERR_IOERROR; td = NULL; break; } /* Check for short transfer */ if (len > 0) { if (xfer->flags_int.short_frames_ok) { /* follow alt next */ if (td->alt_next) { td = td->obj_next; } else { td = NULL; } } else { /* the transfer is finished */ td = NULL; } error = 0; break; } td = td->obj_next; /* this USB frame is complete */ error = 0; break; } while (0); /* update transfer cache */ xfer->td_transfer_cache = td; return (error); } static void octusb_standard_done(struct usb_xfer *xfer) { struct octusb_softc *sc; struct octusb_qh *qh; usb_error_t error = 0; DPRINTFN(12, "xfer=%p endpoint=%p transfer done\n", xfer, xfer->endpoint); /* reset scanner */ xfer->td_transfer_cache = xfer->td_transfer_first; if (xfer->flags_int.control_xfr) { if (xfer->flags_int.control_hdr) error = octusb_standard_done_sub(xfer); xfer->aframes = 1; if (xfer->td_transfer_cache == NULL) goto done; } while (xfer->aframes != xfer->nframes) { error = octusb_standard_done_sub(xfer); xfer->aframes++; if (xfer->td_transfer_cache == NULL) goto done; } if (xfer->flags_int.control_xfr && !xfer->flags_int.control_act) error = octusb_standard_done_sub(xfer); done: /* update data toggle */ qh = xfer->qh_start[0]; sc = qh->sc; xfer->endpoint->toggle_next = cvmx_usb_get_toggle( &sc->sc_port[qh->root_port_index].state, qh->ep_handle) ? 1 : 0; octusb_device_done(xfer, error); } static void octusb_interrupt_poll(struct octusb_softc *sc) { struct usb_xfer *xfer; uint8_t x; /* poll all ports */ for (x = 0; x != sc->sc_noport; x++) cvmx_usb_poll(&sc->sc_port[x].state); repeat: TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { if (!octusb_xfer_do_fifo(xfer)) { /* queue has been modified */ goto repeat; } } } static void octusb_start_standard_chain(struct usb_xfer *xfer) { DPRINTFN(8, "\n"); /* poll one time */ if (octusb_xfer_do_fifo(xfer)) { /* put transfer on interrupt queue */ usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); /* start timeout, if any */ if (xfer->timeout != 0) { usbd_transfer_timeout_ms(xfer, &octusb_timeout, xfer->timeout); } } } void octusb_iterate_hw_softc(struct usb_bus *bus, usb_bus_mem_sub_cb_t *cb) { } usb_error_t octusb_init(struct octusb_softc *sc) { cvmx_usb_initialize_flags_t flags; int status; uint8_t x; /* flush all cache into memory */ usb_bus_mem_flush_all(&sc->sc_bus, &octusb_iterate_hw_softc); /* set up the bus struct */ sc->sc_bus.methods = &octusb_bus_methods; /* get number of ports */ sc->sc_noport = cvmx_usb_get_num_ports(); /* check number of ports */ if (sc->sc_noport > OCTUSB_MAX_PORTS) sc->sc_noport = OCTUSB_MAX_PORTS; /* set USB revision */ sc->sc_bus.usbrev = USB_REV_2_0; /* flags for port initialization */ flags = CVMX_USB_INITIALIZE_FLAGS_CLOCK_AUTO; #ifdef USB_DEBUG if (octusbdebug > 100) flags |= CVMX_USB_INITIALIZE_FLAGS_DEBUG_ALL; #endif USB_BUS_LOCK(&sc->sc_bus); /* setup all ports */ for (x = 0; x != sc->sc_noport; x++) { status = cvmx_usb_initialize(&sc->sc_port[x].state, x, flags); if (status < 0) sc->sc_port[x].disabled = 1; } USB_BUS_UNLOCK(&sc->sc_bus); /* catch lost interrupts */ octusb_do_poll(&sc->sc_bus); return (0); } usb_error_t octusb_uninit(struct octusb_softc *sc) { uint8_t x; USB_BUS_LOCK(&sc->sc_bus); for (x = 0; x != sc->sc_noport; x++) { if (sc->sc_port[x].disabled == 0) cvmx_usb_shutdown(&sc->sc_port[x].state); } USB_BUS_UNLOCK(&sc->sc_bus); return (0); } static void octusb_suspend(struct octusb_softc *sc) { /* TODO */ } static void octusb_resume(struct octusb_softc *sc) { /* TODO */ } /*------------------------------------------------------------------------* * octusb_interrupt - OCTUSB interrupt handler *------------------------------------------------------------------------*/ void octusb_interrupt(struct octusb_softc *sc) { USB_BUS_LOCK(&sc->sc_bus); DPRINTFN(16, "real interrupt\n"); /* poll all the USB transfers */ octusb_interrupt_poll(sc); USB_BUS_UNLOCK(&sc->sc_bus); } /*------------------------------------------------------------------------* * octusb_timeout - OCTUSB transfer timeout handler *------------------------------------------------------------------------*/ static void octusb_timeout(void *arg) { struct usb_xfer *xfer = arg; DPRINTF("xfer=%p\n", xfer); USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); /* transfer is transferred */ octusb_device_done(xfer, USB_ERR_TIMEOUT); } /*------------------------------------------------------------------------* * octusb_do_poll - OCTUSB poll transfers *------------------------------------------------------------------------*/ static void octusb_do_poll(struct usb_bus *bus) { struct octusb_softc *sc = OCTUSB_BUS2SC(bus); USB_BUS_LOCK(&sc->sc_bus); octusb_interrupt_poll(sc); USB_BUS_UNLOCK(&sc->sc_bus); } static void octusb_setup_standard_chain_sub(struct octusb_std_temp *temp) { struct octusb_td *td; /* get current Transfer Descriptor */ td = temp->td_next; temp->td = td; /* prepare for next TD */ temp->td_next = td->obj_next; /* fill out the Transfer Descriptor */ td->func = temp->func; td->pc = temp->pc; td->offset = temp->offset; td->remainder = temp->len; td->error_any = 0; td->error_stall = 0; td->short_pkt = temp->short_pkt; td->alt_next = temp->setup_alt_next; } static void octusb_setup_standard_chain(struct usb_xfer *xfer) { struct octusb_std_temp temp; struct octusb_td *td; uint32_t x; DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n", xfer->address, UE_GET_ADDR(xfer->endpointno), xfer->sumlen, usbd_get_speed(xfer->xroot->udev)); /* setup starting point */ td = xfer->td_start[0]; xfer->td_transfer_first = td; xfer->td_transfer_cache = td; temp.td = NULL; temp.td_next = td; temp.setup_alt_next = xfer->flags_int.short_frames_ok; temp.offset = 0; /* check if we should prepend a setup message */ if (xfer->flags_int.control_xfr) { if (xfer->flags_int.control_hdr) { temp.func = &octusb_host_control_header_tx; temp.len = xfer->frlengths[0]; temp.pc = xfer->frbuffers + 0; temp.short_pkt = temp.len ? 1 : 0; /* check for last frame */ if (xfer->nframes == 1) { /* * no STATUS stage yet, SETUP is * last */ if (xfer->flags_int.control_act) temp.setup_alt_next = 0; } octusb_setup_standard_chain_sub(&temp); } x = 1; } else { x = 0; } if (x != xfer->nframes) { if (xfer->endpointno & UE_DIR_IN) { if (xfer->flags_int.control_xfr) temp.func = &octusb_host_control_data_rx; else temp.func = &octusb_non_control_data_rx; } else { if (xfer->flags_int.control_xfr) temp.func = &octusb_host_control_data_tx; else temp.func = &octusb_non_control_data_tx; } /* setup "pc" pointer */ temp.pc = xfer->frbuffers + x; } while (x != xfer->nframes) { /* DATA0 or DATA1 message */ temp.len = xfer->frlengths[x]; x++; if (x == xfer->nframes) { if (xfer->flags_int.control_xfr) { /* no STATUS stage yet, DATA is last */ if (xfer->flags_int.control_act) temp.setup_alt_next = 0; } else { temp.setup_alt_next = 0; } } if (temp.len == 0) { /* make sure that we send an USB packet */ temp.short_pkt = 0; } else { /* regular data transfer */ temp.short_pkt = (xfer->flags.force_short_xfer) ? 0 : 1; } octusb_setup_standard_chain_sub(&temp); if (xfer->flags_int.isochronous_xfr) { /* get next data offset */ temp.offset += temp.len; } else { /* get next Page Cache pointer */ temp.pc = xfer->frbuffers + x; } } /* check if we should append a status stage */ if (xfer->flags_int.control_xfr && !xfer->flags_int.control_act) { temp.func = &octusb_host_control_status_tx; temp.len = 0; temp.pc = NULL; temp.short_pkt = 0; temp.setup_alt_next = 0; octusb_setup_standard_chain_sub(&temp); } /* must have at least one frame! */ td = temp.td; xfer->td_transfer_last = td; /* properly setup QH */ td->qh->ep_allocated = 0; td->qh->ep_toggle_next = xfer->endpoint->toggle_next ? 1 : 0; } /*------------------------------------------------------------------------* * octusb_device_done - OCTUSB transfers done code * * NOTE: This function can be called more than one time in a row. *------------------------------------------------------------------------*/ static void octusb_device_done(struct usb_xfer *xfer, usb_error_t error) { USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); DPRINTFN(2, "xfer=%p, endpoint=%p, error=%d\n", xfer, xfer->endpoint, error); /* * 1) Free any endpoints. * 2) Control transfers can be split and we should not re-open * the data pipe between transactions unless there is an error. */ if ((xfer->flags_int.control_act == 0) || (error != 0)) { struct octusb_td *td; td = xfer->td_start[0]; octusb_host_free_endpoint(td); } /* dequeue transfer and start next transfer */ usbd_transfer_done(xfer, error); } /*------------------------------------------------------------------------* * octusb bulk support *------------------------------------------------------------------------*/ static void octusb_device_bulk_open(struct usb_xfer *xfer) { return; } static void octusb_device_bulk_close(struct usb_xfer *xfer) { octusb_device_done(xfer, USB_ERR_CANCELLED); } static void octusb_device_bulk_enter(struct usb_xfer *xfer) { return; } static void octusb_device_bulk_start(struct usb_xfer *xfer) { /* setup TDs */ octusb_setup_standard_chain(xfer); octusb_start_standard_chain(xfer); } struct usb_pipe_methods octusb_device_bulk_methods = { .open = octusb_device_bulk_open, .close = octusb_device_bulk_close, .enter = octusb_device_bulk_enter, .start = octusb_device_bulk_start, }; /*------------------------------------------------------------------------* * octusb control support *------------------------------------------------------------------------*/ static void octusb_device_ctrl_open(struct usb_xfer *xfer) { return; } static void octusb_device_ctrl_close(struct usb_xfer *xfer) { octusb_device_done(xfer, USB_ERR_CANCELLED); } static void octusb_device_ctrl_enter(struct usb_xfer *xfer) { return; } static void octusb_device_ctrl_start(struct usb_xfer *xfer) { /* setup TDs */ octusb_setup_standard_chain(xfer); octusb_start_standard_chain(xfer); } struct usb_pipe_methods octusb_device_ctrl_methods = { .open = octusb_device_ctrl_open, .close = octusb_device_ctrl_close, .enter = octusb_device_ctrl_enter, .start = octusb_device_ctrl_start, }; /*------------------------------------------------------------------------* * octusb interrupt support *------------------------------------------------------------------------*/ static void octusb_device_intr_open(struct usb_xfer *xfer) { return; } static void octusb_device_intr_close(struct usb_xfer *xfer) { octusb_device_done(xfer, USB_ERR_CANCELLED); } static void octusb_device_intr_enter(struct usb_xfer *xfer) { return; } static void octusb_device_intr_start(struct usb_xfer *xfer) { /* setup TDs */ octusb_setup_standard_chain(xfer); octusb_start_standard_chain(xfer); } struct usb_pipe_methods octusb_device_intr_methods = { .open = octusb_device_intr_open, .close = octusb_device_intr_close, .enter = octusb_device_intr_enter, .start = octusb_device_intr_start, }; /*------------------------------------------------------------------------* * octusb isochronous support *------------------------------------------------------------------------*/ static void octusb_device_isoc_open(struct usb_xfer *xfer) { return; } static void octusb_device_isoc_close(struct usb_xfer *xfer) { octusb_device_done(xfer, USB_ERR_CANCELLED); } static void octusb_device_isoc_enter(struct usb_xfer *xfer) { struct octusb_softc *sc = OCTUSB_BUS2SC(xfer->xroot->bus); uint32_t temp; uint32_t frame_count; uint32_t fs_frames; DPRINTFN(5, "xfer=%p next=%d nframes=%d\n", xfer, xfer->endpoint->isoc_next, xfer->nframes); /* get the current frame index */ frame_count = cvmx_usb_get_frame_number( &sc->sc_port[xfer->xroot->udev->port_index].state); /* * check if the frame index is within the window where the frames * will be inserted */ temp = (frame_count - xfer->endpoint->isoc_next) & 0x7FF; if (usbd_get_speed(xfer->xroot->udev) == USB_SPEED_HIGH) { fs_frames = (xfer->nframes + 7) / 8; } else { fs_frames = xfer->nframes; } if ((xfer->endpoint->is_synced == 0) || (temp < fs_frames)) { /* * If there is data underflow or the pipe queue is * empty we schedule the transfer a few frames ahead * of the current frame position. Else two isochronous * transfers might overlap. */ xfer->endpoint->isoc_next = (frame_count + 3) & 0x7FF; xfer->endpoint->is_synced = 1; DPRINTFN(2, "start next=%d\n", xfer->endpoint->isoc_next); } /* * compute how many milliseconds the insertion is ahead of the * current frame position: */ temp = (xfer->endpoint->isoc_next - frame_count) & 0x7FF; /* * pre-compute when the isochronous transfer will be finished: */ xfer->isoc_time_complete = usb_isoc_time_expand(&sc->sc_bus, frame_count) + temp + fs_frames; /* compute frame number for next insertion */ xfer->endpoint->isoc_next += fs_frames; } static void octusb_device_isoc_start(struct usb_xfer *xfer) { /* setup TDs */ octusb_setup_standard_chain(xfer); octusb_start_standard_chain(xfer); } struct usb_pipe_methods octusb_device_isoc_methods = { .open = octusb_device_isoc_open, .close = octusb_device_isoc_close, .enter = octusb_device_isoc_enter, .start = octusb_device_isoc_start, }; /*------------------------------------------------------------------------* * OCTUSB root HUB support *------------------------------------------------------------------------* * Simulate a hardware HUB by handling all the necessary requests. *------------------------------------------------------------------------*/ static const struct usb_device_descriptor octusb_devd = { .bLength = sizeof(octusb_devd), .bDescriptorType = UDESC_DEVICE, .bcdUSB = {0x00, 0x02}, .bDeviceClass = UDCLASS_HUB, .bDeviceSubClass = UDSUBCLASS_HUB, .bDeviceProtocol = UDPROTO_FSHUB, .bMaxPacketSize = 64, .idVendor = {0}, .idProduct = {0}, .bcdDevice = {0x00, 0x01}, .iManufacturer = 1, .iProduct = 2, .iSerialNumber = 0, .bNumConfigurations = 1, }; static const struct usb_device_qualifier octusb_odevd = { .bLength = sizeof(octusb_odevd), .bDescriptorType = UDESC_DEVICE_QUALIFIER, .bcdUSB = {0x00, 0x02}, .bDeviceClass = UDCLASS_HUB, .bDeviceSubClass = UDSUBCLASS_HUB, .bDeviceProtocol = UDPROTO_FSHUB, .bMaxPacketSize0 = 0, .bNumConfigurations = 0, .bReserved = 0, }; static const struct octusb_config_desc octusb_confd = { .confd = { .bLength = sizeof(struct usb_config_descriptor), .bDescriptorType = UDESC_CONFIG, .wTotalLength[0] = sizeof(octusb_confd), .bNumInterface = 1, .bConfigurationValue = 1, .iConfiguration = 0, .bmAttributes = UC_SELF_POWERED, .bMaxPower = 0 /* max power */ }, .ifcd = { .bLength = sizeof(struct usb_interface_descriptor), .bDescriptorType = UDESC_INTERFACE, .bNumEndpoints = 1, .bInterfaceClass = UICLASS_HUB, .bInterfaceSubClass = UISUBCLASS_HUB, .bInterfaceProtocol = UIPROTO_FSHUB, }, .endpd = { .bLength = sizeof(struct usb_endpoint_descriptor), .bDescriptorType = UDESC_ENDPOINT, .bEndpointAddress = UE_DIR_IN | OCTUSB_INTR_ENDPT, .bmAttributes = UE_INTERRUPT, .wMaxPacketSize[0] = 8, /* max packet (63 ports) */ .bInterval = 255, }, }; static const struct usb_hub_descriptor_min octusb_hubd = { .bDescLength = sizeof(octusb_hubd), .bDescriptorType = UDESC_HUB, .bNbrPorts = 2, .wHubCharacteristics = {UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL, 0}, .bPwrOn2PwrGood = 50, .bHubContrCurrent = 0, .DeviceRemovable = {0x00}, /* all ports are removable */ }; static usb_error_t octusb_roothub_exec(struct usb_device *udev, struct usb_device_request *req, const void **pptr, uint16_t *plength) { struct octusb_softc *sc = OCTUSB_BUS2SC(udev->bus); const void *ptr; const char *str_ptr; uint16_t value; uint16_t index; uint16_t status; uint16_t change; uint16_t len; usb_error_t err; cvmx_usb_port_status_t usb_port_status; USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); /* XXX disable power save mode, hence it is not supported */ udev->power_mode = USB_POWER_MODE_ON; /* buffer reset */ ptr = (const void *)&sc->sc_hub_desc.temp; len = 0; err = 0; value = UGETW(req->wValue); index = UGETW(req->wIndex); DPRINTFN(3, "type=0x%02x request=0x%02x wLen=0x%04x " "wValue=0x%04x wIndex=0x%04x\n", req->bmRequestType, req->bRequest, UGETW(req->wLength), value, index); #define C(x,y) ((x) | ((y) << 8)) switch (C(req->bRequest, req->bmRequestType)) { case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): break; case C(UR_GET_CONFIG, UT_READ_DEVICE): len = 1; sc->sc_hub_desc.temp[0] = sc->sc_conf; break; case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): switch (value >> 8) { case UDESC_DEVICE: if ((value & 0xff) != 0) { err = USB_ERR_IOERROR; goto done; } len = sizeof(octusb_devd); ptr = (const void *)&octusb_devd; break; case UDESC_DEVICE_QUALIFIER: if ((value & 0xff) != 0) { err = USB_ERR_IOERROR; goto done; } len = sizeof(octusb_odevd); ptr = (const void *)&octusb_odevd; break; case UDESC_CONFIG: if ((value & 0xff) != 0) { err = USB_ERR_IOERROR; goto done; } len = sizeof(octusb_confd); ptr = (const void *)&octusb_confd; break; case UDESC_STRING: switch (value & 0xff) { case 0: /* Language table */ str_ptr = "\001"; break; case 1: /* Vendor */ str_ptr = "Cavium Networks"; break; case 2: /* Product */ str_ptr = "OCTUSB Root HUB"; break; default: str_ptr = ""; break; } len = usb_make_str_desc(sc->sc_hub_desc.temp, sizeof(sc->sc_hub_desc.temp), str_ptr); break; default: err = USB_ERR_IOERROR; goto done; } break; case C(UR_GET_INTERFACE, UT_READ_INTERFACE): len = 1; sc->sc_hub_desc.temp[0] = 0; break; case C(UR_GET_STATUS, UT_READ_DEVICE): len = 2; USETW(sc->sc_hub_desc.stat.wStatus, UDS_SELF_POWERED); break; case C(UR_GET_STATUS, UT_READ_INTERFACE): case C(UR_GET_STATUS, UT_READ_ENDPOINT): len = 2; USETW(sc->sc_hub_desc.stat.wStatus, 0); break; case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): if (value >= OCTUSB_MAX_DEVICES) { err = USB_ERR_IOERROR; goto done; } sc->sc_addr = value; break; case C(UR_SET_CONFIG, UT_WRITE_DEVICE): if ((value != 0) && (value != 1)) { err = USB_ERR_IOERROR; goto done; } sc->sc_conf = value; break; case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE): break; case C(UR_SET_FEATURE, UT_WRITE_DEVICE): case C(UR_SET_FEATURE, UT_WRITE_INTERFACE): case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT): err = USB_ERR_IOERROR; goto done; case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): break; case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT): break; /* Hub requests */ case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE): break; case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): DPRINTFN(4, "UR_CLEAR_PORT_FEATURE " "port=%d feature=%d\n", index, value); if ((index < 1) || (index > sc->sc_noport) || sc->sc_port[index - 1].disabled) { err = USB_ERR_IOERROR; goto done; } index--; switch (value) { case UHF_PORT_ENABLE: cvmx_usb_disable(&sc->sc_port[index].state); break; case UHF_PORT_SUSPEND: case UHF_PORT_RESET: break; case UHF_C_PORT_CONNECTION: cvmx_usb_set_status(&sc->sc_port[index].state, cvmx_usb_get_status(&sc->sc_port[index].state)); break; case UHF_C_PORT_ENABLE: cvmx_usb_set_status(&sc->sc_port[index].state, cvmx_usb_get_status(&sc->sc_port[index].state)); break; case UHF_C_PORT_OVER_CURRENT: cvmx_usb_set_status(&sc->sc_port[index].state, cvmx_usb_get_status(&sc->sc_port[index].state)); break; case UHF_C_PORT_RESET: sc->sc_isreset = 0; goto done; case UHF_C_PORT_SUSPEND: break; case UHF_PORT_CONNECTION: case UHF_PORT_OVER_CURRENT: case UHF_PORT_POWER: case UHF_PORT_LOW_SPEED: default: err = USB_ERR_IOERROR; goto done; } break; case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): if ((value & 0xff) != 0) { err = USB_ERR_IOERROR; goto done; } sc->sc_hubd = octusb_hubd; sc->sc_hubd.bNbrPorts = sc->sc_noport; len = sizeof(sc->sc_hubd); ptr = (const void *)&sc->sc_hubd; break; case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): len = 16; memset(sc->sc_hub_desc.temp, 0, 16); break; case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): if ((index < 1) || (index > sc->sc_noport) || sc->sc_port[index - 1].disabled) { err = USB_ERR_IOERROR; goto done; } index--; usb_port_status = cvmx_usb_get_status(&sc->sc_port[index].state); status = change = 0; if (usb_port_status.connected) status |= UPS_CURRENT_CONNECT_STATUS; if (usb_port_status.port_enabled) status |= UPS_PORT_ENABLED; if (usb_port_status.port_over_current) status |= UPS_OVERCURRENT_INDICATOR; if (usb_port_status.port_powered) status |= UPS_PORT_POWER; switch (usb_port_status.port_speed) { case CVMX_USB_SPEED_HIGH: status |= UPS_HIGH_SPEED; break; case CVMX_USB_SPEED_FULL: break; default: status |= UPS_LOW_SPEED; break; } if (usb_port_status.connect_change) change |= UPS_C_CONNECT_STATUS; if (sc->sc_isreset) change |= UPS_C_PORT_RESET; USETW(sc->sc_hub_desc.ps.wPortStatus, status); USETW(sc->sc_hub_desc.ps.wPortChange, change); len = sizeof(sc->sc_hub_desc.ps); break; case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): err = USB_ERR_IOERROR; goto done; case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): break; case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): if ((index < 1) || (index > sc->sc_noport) || sc->sc_port[index - 1].disabled) { err = USB_ERR_IOERROR; goto done; } index--; switch (value) { case UHF_PORT_ENABLE: break; case UHF_PORT_RESET: cvmx_usb_disable(&sc->sc_port[index].state); if (cvmx_usb_enable(&sc->sc_port[index].state)) { err = USB_ERR_IOERROR; goto done; } sc->sc_isreset = 1; goto done; case UHF_PORT_POWER: /* pretend we turned on power */ goto done; case UHF_PORT_SUSPEND: case UHF_C_PORT_CONNECTION: case UHF_C_PORT_ENABLE: case UHF_C_PORT_OVER_CURRENT: case UHF_PORT_CONNECTION: case UHF_PORT_OVER_CURRENT: case UHF_PORT_LOW_SPEED: case UHF_C_PORT_SUSPEND: case UHF_C_PORT_RESET: default: err = USB_ERR_IOERROR; goto done; } break; default: err = USB_ERR_IOERROR; goto done; } done: *plength = len; *pptr = ptr; return (err); } static void octusb_xfer_setup(struct usb_setup_params *parm) { struct usb_page_search page_info; struct usb_page_cache *pc; struct octusb_softc *sc; struct octusb_qh *qh; struct usb_xfer *xfer; struct usb_device *hub; void *last_obj; uint32_t n; uint32_t ntd; sc = OCTUSB_BUS2SC(parm->udev->bus); xfer = parm->curr_xfer; qh = NULL; /* * NOTE: This driver does not use any of the parameters that * are computed from the following values. Just set some * reasonable dummies: */ parm->hc_max_packet_size = 0x400; parm->hc_max_packet_count = 3; parm->hc_max_frame_size = 0xC00; usbd_transfer_setup_sub(parm); if (parm->err) return; /* Allocate a queue head */ if (usbd_transfer_setup_sub_malloc( parm, &pc, sizeof(struct octusb_qh), USB_HOST_ALIGN, 1)) { parm->err = USB_ERR_NOMEM; return; } if (parm->buf) { usbd_get_page(pc, 0, &page_info); qh = page_info.buffer; /* fill out QH */ qh->sc = OCTUSB_BUS2SC(xfer->xroot->bus); qh->max_frame_size = xfer->max_frame_size; qh->max_packet_size = xfer->max_packet_size; qh->ep_num = xfer->endpointno; qh->ep_type = xfer->endpoint->edesc->bmAttributes; qh->dev_addr = xfer->address; qh->dev_speed = usbd_get_speed(xfer->xroot->udev); qh->root_port_index = xfer->xroot->udev->port_index; /* We need Octeon USB HUB's port index, not the local port */ hub = xfer->xroot->udev->parent_hub; while(hub && hub->parent_hub) { qh->root_port_index = hub->port_index; hub = hub->parent_hub; } switch (xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE) { case UE_INTERRUPT: if (usbd_get_speed(xfer->xroot->udev) == USB_SPEED_HIGH) qh->ep_interval = xfer->interval * 8; else qh->ep_interval = xfer->interval * 1; break; case UE_ISOCHRONOUS: qh->ep_interval = 1 << xfer->fps_shift; break; default: qh->ep_interval = 0; break; } qh->ep_mult = xfer->max_packet_count & 3; qh->hs_hub_addr = xfer->xroot->udev->hs_hub_addr; qh->hs_hub_port = xfer->xroot->udev->hs_port_no; } xfer->qh_start[0] = qh; /* Allocate a fixup buffer */ if (usbd_transfer_setup_sub_malloc( parm, &pc, OCTUSB_MAX_FIXUP, OCTUSB_MAX_FIXUP, 1)) { parm->err = USB_ERR_NOMEM; return; } if (parm->buf) { usbd_get_page(pc, 0, &page_info); qh->fixup_phys = page_info.physaddr; qh->fixup_pc = pc; qh->fixup_buf = page_info.buffer; } /* Allocate transfer descriptors */ last_obj = NULL; ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC */ ; if (usbd_transfer_setup_sub_malloc( parm, &pc, sizeof(struct octusb_td), USB_HOST_ALIGN, ntd)) { parm->err = USB_ERR_NOMEM; return; } if (parm->buf) { for (n = 0; n != ntd; n++) { struct octusb_td *td; usbd_get_page(pc + n, 0, &page_info); td = page_info.buffer; td->qh = qh; td->obj_next = last_obj; last_obj = td; } } xfer->td_start[0] = last_obj; } static void octusb_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc, struct usb_endpoint *ep) { struct octusb_softc *sc = OCTUSB_BUS2SC(udev->bus); DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d (%d)\n", ep, udev->address, edesc->bEndpointAddress, udev->flags.usb_mode, sc->sc_addr); if (udev->device_index != sc->sc_addr) { switch (edesc->bmAttributes & UE_XFERTYPE) { case UE_CONTROL: ep->methods = &octusb_device_ctrl_methods; break; case UE_INTERRUPT: ep->methods = &octusb_device_intr_methods; break; case UE_ISOCHRONOUS: if (udev->speed != USB_SPEED_LOW) ep->methods = &octusb_device_isoc_methods; break; case UE_BULK: ep->methods = &octusb_device_bulk_methods; break; default: /* do nothing */ break; } } } static void octusb_xfer_unsetup(struct usb_xfer *xfer) { DPRINTF("Nothing to do.\n"); } static void octusb_get_dma_delay(struct usb_device *udev, uint32_t *pus) { /* DMA delay - wait until any use of memory is finished */ *pus = (2125); /* microseconds */ } static void octusb_device_resume(struct usb_device *udev) { DPRINTF("Nothing to do.\n"); } static void octusb_device_suspend(struct usb_device *udev) { DPRINTF("Nothing to do.\n"); } static void octusb_set_hw_power(struct usb_bus *bus) { DPRINTF("Nothing to do.\n"); } static void octusb_set_hw_power_sleep(struct usb_bus *bus, uint32_t state) { struct octusb_softc *sc = OCTUSB_BUS2SC(bus); switch (state) { case USB_HW_POWER_SUSPEND: octusb_suspend(sc); break; case USB_HW_POWER_SHUTDOWN: octusb_uninit(sc); break; case USB_HW_POWER_RESUME: octusb_resume(sc); break; default: break; } } struct usb_bus_methods octusb_bus_methods = { .endpoint_init = octusb_ep_init, .xfer_setup = octusb_xfer_setup, .xfer_unsetup = octusb_xfer_unsetup, .get_dma_delay = octusb_get_dma_delay, .device_resume = octusb_device_resume, .device_suspend = octusb_device_suspend, .set_hw_power = octusb_set_hw_power, .set_hw_power_sleep = octusb_set_hw_power_sleep, .roothub_exec = octusb_roothub_exec, .xfer_poll = octusb_do_poll, }; Index: head/sys/mips/cavium/usb/octusb.h =================================================================== --- head/sys/mips/cavium/usb/octusb.h (revision 326258) +++ head/sys/mips/cavium/usb/octusb.h (revision 326259) @@ -1,138 +1,140 @@ /* $FreeBSD$ */ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Hans Petter Selasky. 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. */ #ifndef _OCTUSB_H_ #define _OCTUSB_H_ #define OCTUSB_MAX_DEVICES MIN(USB_MAX_DEVICES, 64) #define OCTUSB_MAX_PORTS 2 /* hardcoded */ #define OCTUSB_MAX_FIXUP 4096 /* bytes */ #define OCTUSB_INTR_ENDPT 0x01 struct octusb_qh; struct octusb_td; struct octusb_softc; typedef uint8_t (octusb_cmd_t)(struct octusb_td *td); struct octusb_td { struct octusb_qh *qh; struct octusb_td *obj_next; struct usb_page_cache *pc; octusb_cmd_t *func; uint32_t remainder; uint32_t offset; uint8_t error_any:1; uint8_t error_stall:1; uint8_t short_pkt:1; uint8_t alt_next:1; uint8_t reserved:4; }; struct octusb_qh { uint64_t fixup_phys; struct octusb_softc *sc; struct usb_page_cache *fixup_pc; uint8_t *fixup_buf; cvmx_usb_iso_packet_t iso_pkt; uint32_t fixup_off; uint16_t max_frame_size; uint16_t max_packet_size; uint16_t fixup_actlen; uint16_t fixup_len; uint16_t ep_interval; uint8_t dev_addr; uint8_t dev_speed; uint8_t ep_allocated; uint8_t ep_mult; uint8_t ep_num; uint8_t ep_type; uint8_t ep_toggle_next; uint8_t root_port_index; uint8_t fixup_complete; uint8_t fixup_pending; uint8_t hs_hub_addr; uint8_t hs_hub_port; int fixup_handle; int ep_handle; }; struct octusb_config_desc { struct usb_config_descriptor confd; struct usb_interface_descriptor ifcd; struct usb_endpoint_descriptor endpd; } __packed; union octusb_hub_desc { struct usb_status stat; struct usb_port_status ps; uint8_t temp[128]; }; struct octusb_port { cvmx_usb_state_t state; uint8_t disabled; }; struct octusb_softc { struct usb_bus sc_bus; /* base device */ union octusb_hub_desc sc_hub_desc; struct usb_device *sc_devices[OCTUSB_MAX_DEVICES]; struct resource *sc_irq_res[OCTUSB_MAX_PORTS]; void *sc_intr_hdl[OCTUSB_MAX_PORTS]; struct octusb_port sc_port[OCTUSB_MAX_PORTS]; device_t sc_dev; struct usb_hub_descriptor_min sc_hubd; uint8_t sc_noport; /* number of ports */ uint8_t sc_addr; /* device address */ uint8_t sc_conf; /* device configuration */ uint8_t sc_isreset; /* set if current port is reset */ uint8_t sc_hub_idata[1]; }; usb_bus_mem_cb_t octusb_iterate_hw_softc; usb_error_t octusb_init(struct octusb_softc *); usb_error_t octusb_uninit(struct octusb_softc *); void octusb_interrupt(struct octusb_softc *); #endif /* _OCTUSB_H_ */ Index: head/sys/mips/cavium/usb/octusb_octeon.c =================================================================== --- head/sys/mips/cavium/usb/octusb_octeon.c (revision 326258) +++ head/sys/mips/cavium/usb/octusb_octeon.c (revision 326259) @@ -1,217 +1,219 @@ #include __FBSDID("$FreeBSD$"); /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2007-2008 Hans Petter Selasky. 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 #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 MEM_RID 0 static device_identify_t octusb_octeon_identify; static device_probe_t octusb_octeon_probe; static device_attach_t octusb_octeon_attach; static device_detach_t octusb_octeon_detach; struct octusb_octeon_softc { struct octusb_softc sc_dci; /* must be first */ }; static void octusb_octeon_identify(driver_t *drv, device_t parent) { if (octeon_has_feature(OCTEON_FEATURE_USB)) BUS_ADD_CHILD(parent, 0, "octusb", 0); } static int octusb_octeon_probe(device_t dev) { device_set_desc(dev, "Cavium Octeon USB controller"); return (0); } static int octusb_octeon_attach(device_t dev) { struct octusb_octeon_softc *sc = device_get_softc(dev); int err; int rid; int nports; int i; /* setup controller interface softc */ /* initialise some bus fields */ sc->sc_dci.sc_bus.parent = dev; sc->sc_dci.sc_bus.devices = sc->sc_dci.sc_devices; sc->sc_dci.sc_bus.devices_max = OCTUSB_MAX_DEVICES; sc->sc_dci.sc_bus.dma_bits = 32; /* get all DMA memory */ if (usb_bus_mem_alloc_all(&sc->sc_dci.sc_bus, USB_GET_DMA_TAG(dev), NULL)) { return (ENOMEM); } nports = cvmx_usb_get_num_ports(); if (nports > OCTUSB_MAX_PORTS) panic("octusb: too many USB ports %d", nports); for (i = 0; i < nports; i++) { rid = 0; sc->sc_dci.sc_irq_res[i] = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, OCTEON_IRQ_USB0 + i, OCTEON_IRQ_USB0 + i, 1, RF_ACTIVE); if (!(sc->sc_dci.sc_irq_res[i])) { goto error; } #if (__FreeBSD_version >= 700031) err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res[i], INTR_TYPE_BIO | INTR_MPSAFE, NULL, (driver_intr_t *)octusb_interrupt, sc, &sc->sc_dci.sc_intr_hdl[i]); #else err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res[i], INTR_TYPE_BIO | INTR_MPSAFE, (driver_intr_t *)octusb_interrupt, sc, &sc->sc_dci.sc_intr_hdl[i]); #endif if (err) { sc->sc_dci.sc_intr_hdl[i] = NULL; goto error; } } sc->sc_dci.sc_bus.bdev = device_add_child(dev, "usbus", -1); if (!(sc->sc_dci.sc_bus.bdev)) { goto error; } device_set_ivars(sc->sc_dci.sc_bus.bdev, &sc->sc_dci.sc_bus); err = octusb_init(&sc->sc_dci); if (!err) { err = device_probe_and_attach(sc->sc_dci.sc_bus.bdev); } if (err) { goto error; } return (0); error: octusb_octeon_detach(dev); return (ENXIO); } static int octusb_octeon_detach(device_t dev) { struct octusb_octeon_softc *sc = device_get_softc(dev); int err; int nports; int i; /* during module unload there are lots of children leftover */ device_delete_children(dev); if (sc->sc_dci.sc_irq_res[0] && sc->sc_dci.sc_intr_hdl[0]) /* * only call octusb_octeon_uninit() after octusb_octeon_init() */ octusb_uninit(&sc->sc_dci); nports = cvmx_usb_get_num_ports(); if (nports > OCTUSB_MAX_PORTS) panic("octusb: too many USB ports %d", nports); for (i = 0; i < nports; i++) { if (sc->sc_dci.sc_irq_res[0] && sc->sc_dci.sc_intr_hdl[0]) { err = bus_teardown_intr(dev, sc->sc_dci.sc_irq_res[i], sc->sc_dci.sc_intr_hdl[i]); sc->sc_dci.sc_intr_hdl[i] = NULL; } if (sc->sc_dci.sc_irq_res) { bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_dci.sc_irq_res[i]); sc->sc_dci.sc_irq_res[i] = NULL; } } usb_bus_mem_free_all(&sc->sc_dci.sc_bus, NULL); return (0); } static device_method_t octusb_octeon_methods[] = { /* Device interface */ DEVMETHOD(device_identify, octusb_octeon_identify), DEVMETHOD(device_probe, octusb_octeon_probe), DEVMETHOD(device_attach, octusb_octeon_attach), DEVMETHOD(device_detach, octusb_octeon_detach), DEVMETHOD(device_resume, bus_generic_resume), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD_END }; static driver_t octusb_octeon_driver = { .name = "octusb", .methods = octusb_octeon_methods, .size = sizeof(struct octusb_octeon_softc), }; static devclass_t octusb_octeon_devclass; DRIVER_MODULE(octusb, ciu, octusb_octeon_driver, octusb_octeon_devclass, 0, 0); Index: head/sys/mips/gxemul/gxemul_machdep.c =================================================================== --- head/sys/mips/gxemul/gxemul_machdep.c (revision 326258) +++ head/sys/mips/gxemul/gxemul_machdep.c (revision 326259) @@ -1,245 +1,247 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006 Wojciech A. Koszek * 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 "opt_ddb.h" #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 #ifdef SMP #include #include #endif #include extern int *edata; extern int *end; void platform_cpu_init() { /* Nothing special */ } static void mips_init(void) { int i; for (i = 0; i < 10; i++) { phys_avail[i] = 0; } /* phys_avail regions are in bytes */ phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end); phys_avail[1] = ctob(realmem); dump_avail[0] = phys_avail[0]; dump_avail[1] = phys_avail[1]; physmem = realmem; init_param1(); init_param2(physmem); mips_cpu_init(); pmap_bootstrap(); mips_proc0_init(); mutex_init(); kdb_init(); #ifdef KDB if (boothowto & RB_KDB) kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); #endif } /* * Perform a board-level soft-reset. * * XXXRW: Does gxemul have a moral equivalent to board-level reset? */ void platform_reset(void) { panic("%s: not yet", __func__); } void platform_start(__register_t a0, __register_t a1, __register_t a2, __register_t a3) { vm_offset_t kernend; uint64_t platform_counter_freq; int argc = a0; char **argv = (char **)a1; char **envp = (char **)a2; int i; /* clear the BSS and SBSS segments */ kernend = (vm_offset_t)&end; memset(&edata, 0, kernend - (vm_offset_t)(&edata)); mips_postboot_fixup(); mips_pcpu0_init(); /* * XXXRW: Support for the gxemul real-time clock required in order to * usefully determine our emulated timer frequency. Go with something * classic as the default in the mean time. */ platform_counter_freq = MIPS_DEFAULT_HZ; mips_timer_early_init(platform_counter_freq); cninit(); printf("entry: platform_start()\n"); bootverbose = 1; if (bootverbose) { printf("cmd line: "); for (i = 0; i < argc; i++) printf("%s ", argv[i]); printf("\n"); if (envp != NULL) { printf("envp:\n"); for (i = 0; envp[i]; i += 2) printf("\t%s = %s\n", envp[i], envp[i+1]); } else { printf("no envp.\n"); } } realmem = btoc(GXEMUL_MP_DEV_READ(GXEMUL_MP_DEV_MEMORY)); mips_init(); mips_timer_init_params(platform_counter_freq, 0); } #ifdef SMP void platform_ipi_send(int cpuid) { GXEMUL_MP_DEV_WRITE(GXEMUL_MP_DEV_IPI_ONE, (1 << 16) | cpuid); } void platform_ipi_clear(void) { GXEMUL_MP_DEV_WRITE(GXEMUL_MP_DEV_IPI_READ, 0); } int platform_ipi_hardintr_num(void) { return (GXEMUL_MP_DEV_IPI_INTERRUPT - 2); } int platform_ipi_softintr_num(void) { return (-1); } struct cpu_group * platform_smp_topo(void) { return (smp_topo_none()); } void platform_init_ap(int cpuid) { int ipi_int_mask, clock_int_mask; /* * Unmask the clock and ipi interrupts. */ clock_int_mask = hard_int_mask(5); ipi_int_mask = hard_int_mask(platform_ipi_hardintr_num()); set_intr_mask(ipi_int_mask | clock_int_mask); } void platform_cpu_mask(cpuset_t *mask) { unsigned i, n; n = GXEMUL_MP_DEV_READ(GXEMUL_MP_DEV_NCPUS); CPU_ZERO(mask); for (i = 0; i < n; i++) CPU_SET(i, mask); } int platform_processor_id(void) { return (GXEMUL_MP_DEV_READ(GXEMUL_MP_DEV_WHOAMI)); } int platform_start_ap(int cpuid) { GXEMUL_MP_DEV_WRITE(GXEMUL_MP_DEV_STARTADDR, (intptr_t)mpentry); GXEMUL_MP_DEV_WRITE(GXEMUL_MP_DEV_START, cpuid); return (0); } #endif /* SMP */ Index: head/sys/mips/gxemul/mpreg.h =================================================================== --- head/sys/mips/gxemul/mpreg.h (revision 326258) +++ head/sys/mips/gxemul/mpreg.h (revision 326259) @@ -1,62 +1,64 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2004-2012 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$ */ #ifndef _MIPS_GXEMUL_MPREG_H_ #define _MIPS_GXEMUL_MPREG_H_ #define GXEMUL_MP_DEV_BASE 0x11000000 #define GXEMUL_MP_DEV_WHOAMI 0x0000 #define GXEMUL_MP_DEV_NCPUS 0x0010 #define GXEMUL_MP_DEV_START 0x0020 #define GXEMUL_MP_DEV_STARTADDR 0x0030 #define GXEMUL_MP_DEV_STACK 0x0070 #define GXEMUL_MP_DEV_RANDOM 0x0080 #define GXEMUL_MP_DEV_MEMORY 0x0090 #define GXEMUL_MP_DEV_IPI_ONE 0x00a0 #define GXEMUL_MP_DEV_IPI_MANY 0x00b0 #define GXEMUL_MP_DEV_IPI_READ 0x00c0 #define GXEMUL_MP_DEV_CYCLES 0x00d0 #ifdef _LP64 #define GXEMUL_MP_DEV_FUNCTION(f) \ (volatile uint64_t *)MIPS_PHYS_TO_DIRECT_UNCACHED(GXEMUL_MP_DEV_BASE + (f)) #define GXEMUL_MP_DEV_READ(f) \ (volatile uint64_t)*GXEMUL_MP_DEV_FUNCTION(f) #else #define GXEMUL_MP_DEV_FUNCTION(f) \ (volatile uint32_t *)MIPS_PHYS_TO_DIRECT_UNCACHED(GXEMUL_MP_DEV_BASE + (f)) #define GXEMUL_MP_DEV_READ(f) \ (volatile uint32_t)*GXEMUL_MP_DEV_FUNCTION(f) #endif #define GXEMUL_MP_DEV_WRITE(f, v) \ *GXEMUL_MP_DEV_FUNCTION(f) = (v) #define GXEMUL_MP_DEV_IPI_INTERRUPT (6) #endif /* !_MIPS_GXEMUL_MPREG_H */ Index: head/sys/mips/idt/idt_machdep.c =================================================================== --- head/sys/mips/idt/idt_machdep.c (revision 326258) +++ head/sys/mips/idt/idt_machdep.c (revision 326259) @@ -1,178 +1,180 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (C) 2007 by Oleksandr Tymoshenko. 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 ``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 HIS RELATIVES 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 MIND, 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. * * $Id: $ * */ #include __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #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 #include #include #include #include #include extern int *edata; extern int *end; void platform_cpu_init() { /* Nothing special */ } void platform_reset(void) { volatile unsigned int * p = (void *)0xb8008000; /* * TODO: we should take care of TLB stuff here. Otherwise * board does not boots properly next time */ /* Write 0x8000_0001 to the Reset register */ *p = 0x80000001; __asm __volatile("li $25, 0xbfc00000"); __asm __volatile("j $25"); } void platform_start(__register_t a0, __register_t a1, __register_t a2 __unused, __register_t a3 __unused) { uint64_t platform_counter_freq; vm_offset_t kernend; int argc = a0; char **argv = (char **)a1; int i, mem; /* clear the BSS and SBSS segments */ kernend = (vm_offset_t)&end; memset(&edata, 0, kernend - (vm_offset_t)(&edata)); mips_postboot_fixup(); /* Initialize pcpu stuff */ mips_pcpu0_init(); /* * Looking for mem=XXM argument */ mem = 0; /* Just something to start with */ for (i=0; i < argc; i++) { if (strncmp(argv[i], "mem=", 4) == 0) { mem = strtol(argv[i] + 4, NULL, 0); break; } } bootverbose = 1; if (mem > 0) realmem = btoc(mem << 20); else realmem = btoc(32 << 20); for (i = 0; i < 10; i++) { phys_avail[i] = 0; } /* phys_avail regions are in bytes */ phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end); phys_avail[1] = ctob(realmem); dump_avail[0] = phys_avail[0]; dump_avail[1] = phys_avail[1]; physmem = realmem; /* * ns8250 uart code uses DELAY so ticker should be inititalized * before cninit. And tick_init_params refers to hz, so * init_param1 * should be called first. */ init_param1(); /* TODO: parse argc,argv */ platform_counter_freq = 330000000UL; mips_timer_init_params(platform_counter_freq, 1); cninit(); /* Panic here, after cninit */ if (mem == 0) panic("No mem=XX parameter in arguments"); printf("cmd line: "); for (i=0; i < argc; i++) printf("%s ", argv[i]); printf("\n"); init_param2(physmem); mips_cpu_init(); pmap_bootstrap(); mips_proc0_init(); mutex_init(); kdb_init(); #ifdef KDB if (boothowto & RB_KDB) kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); #endif } Index: head/sys/mips/idt/idtpci.c =================================================================== --- head/sys/mips/idt/idtpci.c (revision 326258) +++ head/sys/mips/idt/idtpci.c (revision 326259) @@ -1,557 +1,559 @@ /* $NetBSD: idtpci.c,v 1.1 2007/03/20 08:52:02 dyoung Exp $ */ /*- + * SPDX-License-Identifier: BSD-3-Clause + * * Copyright (c) 2007 David Young. * Copyright (c) 2007 Oleskandr Tymoshenko. 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. * 3. The name of the author may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 * 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. */ /*- * Copyright (c) 2006 Itronix Inc. * All rights reserved. * * Written by Garrett D'Amore for Itronix Inc. * * 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. * 3. The name of Itronix Inc. may not be used to endorse * or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``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 ITRONIX INC. 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 "pcib_if.h" #include #ifdef IDTPCI_DEBUG int idtpci_debug = 1; #define IDTPCI_DPRINTF(__fmt, ...) \ do { \ if (idtpci_debug) \ printf((__fmt), __VA_ARGS__); \ } while (/*CONSTCOND*/0) #else /* !IDTPCI_DEBUG */ #define IDTPCI_DPRINTF(__fmt, ...) do { } while (/*CONSTCOND*/0) #endif /* IDTPCI_DEBUG */ #define IDTPCI_TAG_BUS_MASK 0x007f0000 #define IDTPCI_TAG_DEVICE_MASK 0x00007800 #define IDTPCI_TAG_FUNCTION_MASK 0x00000300 #define IDTPCI_TAG_REGISTER_MASK 0x0000007c #define IDTPCI_MAX_DEVICE #define REG_READ(o) *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(IDT_BASE_PCI + (o))) #define REG_WRITE(o,v) (REG_READ(o)) = (v) unsigned int korina_fixup[24] = { 0x00000157, 0x00000000, 0x00003c04, 0x00000008, 0x18800001, 0x18000001, 0x48000008, 0x00000000, 0x00000000, 0x00000000, 0x011d0214, 0x00000000, 0x00000000, 0x00000000, 0x38080101, 0x00008080, 0x00000d6e, 0x00000000, 0x00000051, 0x00000000, 0x00000055, 0x18000000, 0x00000000, 0x00000000 }; struct idtpci_softc { device_t sc_dev; int sc_busno; struct rman sc_mem_rman[2]; struct rman sc_io_rman[2]; struct rman sc_irq_rman; }; static uint32_t idtpci_make_addr(int bus, int slot, int func, int reg) { return 0x80000000 | (bus << 16) | (slot << 11) | (func << 8) | reg; } static int idtpci_probe(device_t dev) { return (0); } static int idtpci_attach(device_t dev) { int busno = 0; struct idtpci_softc *sc = device_get_softc(dev); unsigned int pci_data, force_endianess = 0; int i; bus_addr_t addr; sc->sc_dev = dev; sc->sc_busno = busno; /* TODO: Check for host mode */ /* Enabled PCI, IG mode, EAP mode */ REG_WRITE(IDT_PCI_CNTL, IDT_PCI_CNTL_IGM | IDT_PCI_CNTL_EAP | IDT_PCI_CNTL_EN); /* Wait while "Reset in progress bit" set */ while(1) { pci_data = REG_READ(IDT_PCI_STATUS); if((pci_data & IDT_PCI_STATUS_RIP) == 0) break; } /* Reset status register */ REG_WRITE(IDT_PCI_STATUS, 0); /* Mask interrupts related to status register */ REG_WRITE(IDT_PCI_STATUS_MASK, 0xffffffff); /* Disable PCI decoupled access */ REG_WRITE(IDT_PCI_DAC, 0); /* Zero status and mask DA interrupts */ REG_WRITE(IDT_PCI_DAS, 0); REG_WRITE(IDT_PCI_DASM, 0x7f); /* Init PCI messaging unit */ /* Disable messaging interrupts */ REG_WRITE(IDT_PCI_IIC, 0); REG_WRITE(IDT_PCI_IIM, 0xffffffff); REG_WRITE(IDT_PCI_OIC, 0); REG_WRITE(IDT_PCI_OIM, 0); #ifdef __MIPSEB__ force_endianess = IDT_PCI_LBA_FE; #endif /* LBA0 -- memory window */ REG_WRITE(IDT_PCI_LBA0, IDT_PCIMEM0_BASE); REG_WRITE(IDT_PCI_LBA0_MAP, IDT_PCIMEM0_BASE); REG_WRITE(IDT_PCI_LBA0_CNTL, IDT_PCI_LBA_SIZE_16MB | force_endianess); pci_data = REG_READ(IDT_PCI_LBA0_CNTL); /* LBA1 -- memory window */ REG_WRITE(IDT_PCI_LBA1, IDT_PCIMEM1_BASE); REG_WRITE(IDT_PCI_LBA1_MAP, IDT_PCIMEM1_BASE); REG_WRITE(IDT_PCI_LBA1_CNTL, IDT_PCI_LBA_SIZE_256MB | force_endianess); pci_data = REG_READ(IDT_PCI_LBA1_CNTL); /* LBA2 -- IO window */ REG_WRITE(IDT_PCI_LBA2, IDT_PCIMEM2_BASE); REG_WRITE(IDT_PCI_LBA2_MAP, IDT_PCIMEM2_BASE); REG_WRITE(IDT_PCI_LBA2_CNTL, IDT_PCI_LBA_SIZE_4MB | IDT_PCI_LBA_MSI | force_endianess); pci_data = REG_READ(IDT_PCI_LBA2_CNTL); /* LBA3 -- IO window */ REG_WRITE(IDT_PCI_LBA3, IDT_PCIMEM3_BASE); REG_WRITE(IDT_PCI_LBA3_MAP, IDT_PCIMEM3_BASE); REG_WRITE(IDT_PCI_LBA3_CNTL, IDT_PCI_LBA_SIZE_1MB | IDT_PCI_LBA_MSI | force_endianess); pci_data = REG_READ(IDT_PCI_LBA3_CNTL); pci_data = REG_READ(IDT_PCI_CNTL) & ~IDT_PCI_CNTL_TNR; REG_WRITE(IDT_PCI_CNTL, pci_data); pci_data = REG_READ(IDT_PCI_CNTL); /* Rewrite Target Control register with default values */ REG_WRITE(IDT_PCI_TC, (IDT_PCI_TC_DTIMER << 8) | IDT_PCI_TC_RTIMER); /* Perform Korina fixup */ addr = idtpci_make_addr(0, 0, 0, 4); for (i = 0; i < 24; i++) { REG_WRITE(IDT_PCI_CFG_ADDR, addr); REG_WRITE(IDT_PCI_CFG_DATA, korina_fixup[i]); __asm__ volatile ("sync"); REG_WRITE(IDT_PCI_CFG_ADDR, 0); REG_WRITE(IDT_PCI_CFG_DATA, 0); addr += 4; } /* Use KSEG1 to access IO ports for it is uncached */ sc->sc_io_rman[0].rm_type = RMAN_ARRAY; sc->sc_io_rman[0].rm_descr = "IDTPCI I/O Ports window 1"; if (rman_init(&sc->sc_io_rman[0]) != 0 || rman_manage_region(&sc->sc_io_rman[0], IDT_PCIMEM2_BASE, IDT_PCIMEM2_BASE + IDT_PCIMEM2_SIZE - 1) != 0) { panic("idtpci_attach: failed to set up I/O rman"); } sc->sc_io_rman[1].rm_type = RMAN_ARRAY; sc->sc_io_rman[1].rm_descr = "IDTPCI I/O Ports window 2"; if (rman_init(&sc->sc_io_rman[1]) != 0 || rman_manage_region(&sc->sc_io_rman[1], IDT_PCIMEM3_BASE, IDT_PCIMEM3_BASE + IDT_PCIMEM3_SIZE - 1) != 0) { panic("idtpci_attach: failed to set up I/O rman"); } /* Use KSEG1 to access PCI memory for it is uncached */ sc->sc_mem_rman[0].rm_type = RMAN_ARRAY; sc->sc_mem_rman[0].rm_descr = "IDTPCI PCI Memory window 1"; if (rman_init(&sc->sc_mem_rman[0]) != 0 || rman_manage_region(&sc->sc_mem_rman[0], IDT_PCIMEM0_BASE, IDT_PCIMEM0_BASE + IDT_PCIMEM0_SIZE) != 0) { panic("idtpci_attach: failed to set up memory rman"); } sc->sc_mem_rman[1].rm_type = RMAN_ARRAY; sc->sc_mem_rman[1].rm_descr = "IDTPCI PCI Memory window 2"; if (rman_init(&sc->sc_mem_rman[1]) != 0 || rman_manage_region(&sc->sc_mem_rman[1], IDT_PCIMEM1_BASE, IDT_PCIMEM1_BASE + IDT_PCIMEM1_SIZE) != 0) { panic("idtpci_attach: failed to set up memory rman"); } sc->sc_irq_rman.rm_type = RMAN_ARRAY; sc->sc_irq_rman.rm_descr = "IDTPCI PCI IRQs"; if (rman_init(&sc->sc_irq_rman) != 0 || rman_manage_region(&sc->sc_irq_rman, PCI_IRQ_BASE, PCI_IRQ_END) != 0) panic("idtpci_attach: failed to set up IRQ rman"); device_add_child(dev, "pci", -1); return (bus_generic_attach(dev)); } static int idtpci_maxslots(device_t dev) { return (PCI_SLOTMAX); } static uint32_t idtpci_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int bytes) { uint32_t data; uint32_t shift, mask; bus_addr_t addr; IDTPCI_DPRINTF("%s: tag (%x, %x, %x) reg %d(%d)\n", __func__, bus, slot, func, reg, bytes); addr = idtpci_make_addr(bus, slot, func, reg); REG_WRITE(IDT_PCI_CFG_ADDR, addr); data = REG_READ(IDT_PCI_CFG_DATA); switch (reg % 4) { case 3: shift = 24; break; case 2: shift = 16; break; case 1: shift = 8; break; default: shift = 0; break; } switch (bytes) { case 1: mask = 0xff; data = (data >> shift) & mask; break; case 2: mask = 0xffff; if (reg % 4 == 0) data = data & mask; else data = (data >> 16) & mask; break; case 4: break; default: panic("%s: wrong bytes count", __func__); break; } __asm__ volatile ("sync"); IDTPCI_DPRINTF("%s: read 0x%x\n", __func__, data); return (data); } static void idtpci_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t data, int bytes) { bus_addr_t addr; uint32_t reg_data; uint32_t shift, mask; IDTPCI_DPRINTF("%s: tag (%x, %x, %x) reg %d(%d) data %08x\n", __func__, bus, slot, func, reg, bytes, data); if (bytes != 4) { reg_data = idtpci_read_config(dev, bus, slot, func, reg, 4); switch (reg % 4) { case 3: shift = 24; break; case 2: shift = 16; break; case 1: shift = 8; break; default: shift = 0; break; } switch (bytes) { case 1: mask = 0xff; data = (reg_data & ~ (mask << shift)) | (data << shift); break; case 2: mask = 0xffff; if (reg % 4 == 0) data = (reg_data & ~mask) | data; else data = (reg_data & ~ (mask << shift)) | (data << shift); break; case 4: break; default: panic("%s: wrong bytes count", __func__); break; } } addr = idtpci_make_addr(bus, slot, func, reg); REG_WRITE(IDT_PCI_CFG_ADDR, addr); REG_WRITE(IDT_PCI_CFG_DATA, data); __asm__ volatile ("sync"); REG_WRITE(IDT_PCI_CFG_ADDR, 0); REG_WRITE(IDT_PCI_CFG_DATA, 0); } static int idtpci_route_interrupt(device_t pcib, device_t device, int pin) { static int idt_pci_table[2][12] = { { 0, 0, 2, 3, 2, 3, 0, 0, 0, 0, 0, 1 }, { 0, 0, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3 } }; int dev, bus, irq; dev = pci_get_slot(device); bus = pci_get_bus(device); if (bootverbose) device_printf(pcib, "routing pin %d for %s\n", pin, device_get_nameunit(device)); if (bus >= 0 && bus <= 1 && dev >= 0 && dev <= 11) { irq = IP_IRQ(6, idt_pci_table[bus][dev] + 4); if (bootverbose) printf("idtpci: %d/%d/%d -> IRQ%d\n", pci_get_bus(device), dev, pci_get_function(device), irq); return (irq); } else printf("idtpci: no mapping for %d/%d/%d\n", pci_get_bus(device), dev, pci_get_function(device)); return (-1); } static int idtpci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { struct idtpci_softc *sc = device_get_softc(dev); switch (which) { case PCIB_IVAR_DOMAIN: *result = 0; return (0); case PCIB_IVAR_BUS: *result = sc->sc_busno; return (0); } return (ENOENT); } static int idtpci_write_ivar(device_t dev, device_t child, int which, uintptr_t result) { struct idtpci_softc * sc = device_get_softc(dev); switch (which) { case PCIB_IVAR_BUS: sc->sc_busno = result; return (0); } return (ENOENT); } static struct resource * idtpci_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct idtpci_softc *sc = device_get_softc(bus); struct resource *rv = NULL; struct rman *rm1, *rm2; switch (type) { case SYS_RES_IRQ: rm1 = &sc->sc_irq_rman; rm2 = NULL; break; case SYS_RES_MEMORY: rm1 = &sc->sc_mem_rman[0]; rm2 = &sc->sc_mem_rman[1]; break; case SYS_RES_IOPORT: rm1 = &sc->sc_io_rman[0]; rm2 = &sc->sc_io_rman[1]; break; default: return (NULL); } rv = rman_reserve_resource(rm1, start, end, count, flags, child); /* Try second window if it exists */ if ((rv == NULL) && (rm2 != NULL)) rv = rman_reserve_resource(rm2, start, end, count, flags, child); if (rv == NULL) return (NULL); rman_set_rid(rv, *rid); if (flags & RF_ACTIVE) { if (bus_activate_resource(child, type, *rid, rv)) { rman_release_resource(rv); return (NULL); } } return (rv); } static int idtpci_teardown_intr(device_t dev, device_t child, struct resource *res, void *cookie) { return (intr_event_remove_handler(cookie)); } static device_method_t idtpci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, idtpci_probe), DEVMETHOD(device_attach, idtpci_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_read_ivar, idtpci_read_ivar), DEVMETHOD(bus_write_ivar, idtpci_write_ivar), DEVMETHOD(bus_alloc_resource, idtpci_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, idtpci_teardown_intr), /* pcib interface */ DEVMETHOD(pcib_maxslots, idtpci_maxslots), DEVMETHOD(pcib_read_config, idtpci_read_config), DEVMETHOD(pcib_write_config, idtpci_write_config), DEVMETHOD(pcib_route_interrupt, idtpci_route_interrupt), DEVMETHOD(pcib_request_feature, pcib_request_feature_allow), DEVMETHOD_END }; static driver_t idtpci_driver = { "pcib", idtpci_methods, sizeof(struct idtpci_softc), }; static devclass_t idtpci_devclass; DRIVER_MODULE(idtpci, obio, idtpci_driver, idtpci_devclass, 0, 0); Index: head/sys/mips/idt/idtreg.h =================================================================== --- head/sys/mips/idt/idtreg.h (revision 326258) +++ head/sys/mips/idt/idtreg.h (revision 326259) @@ -1,153 +1,155 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (C) 2007 by Oleksandr Tymoshenko. 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 ``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 HIS RELATIVES 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 MIND, 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$ * */ #ifndef __IDTREG_H__ #define __IDTREG_H__ /* Interrupt controller */ #define IDT_BASE_ICU 0x18038000 #define ICU_IPEND2 0x00 #define ICU_ITEST2 0x04 #define ICU_IMASK2 0x08 #define ICU_IPEND3 0x0C #define ICU_ITEST3 0x10 #define ICU_IMASK3 0x14 #define ICU_IPEND4 0x18 #define ICU_ITEST4 0x1c #define ICU_IMASK4 0x20 #define ICU_IPEND5 0x24 #define ICU_ITEST5 0x28 #define ICU_IMASK5 0x2c #define ICU_IPEND6 0x30 #define ICU_ITEST6 0x34 #define ICU_IMASK6 0x38 #define ICU_NMIPS 0x3c #define IDT_BASE_GPIO 0x18050000 #define GPIO_FUNC 0x00 #define GPIO_CFG 0x04 #define GPIO_DATA 0x08 #define GPIO_ILEVEL 0x0C #define GPIO_ISTAT 0x10 #define GPIO_NMIEN 0x14 #define IDT_BASE_UART0 0x18058000 /* PCI controller */ #define IDT_BASE_PCI 0x18080000 #define IDT_PCI_CNTL 0x00 #define IDT_PCI_CNTL_EN 0x001 #define IDT_PCI_CNTL_TNR 0x002 #define IDT_PCI_CNTL_SCE 0x004 #define IDT_PCI_CNTL_IEN 0x008 #define IDT_PCI_CNTL_AAA 0x010 #define IDT_PCI_CNTL_EAP 0x020 #define IDT_PCI_CNTL_IGM 0x200 #define IDT_PCI_STATUS 0x04 #define IDT_PCI_STATUS_RIP 0x20000 #define IDT_PCI_STATUS_MASK 0x08 #define IDT_PCI_CFG_ADDR 0x0C #define IDT_PCI_CFG_DATA 0x10 /* LBA stuff */ #define IDT_PCI_LBA0 0x14 #define IDT_PCI_LBA0_CNTL 0x18 #define IDT_PCI_LBA_MSI 0x01 #define IDT_PCI_LBA_SIZE_1MB (0x14 << 2) #define IDT_PCI_LBA_SIZE_2MB (0x15 << 2) #define IDT_PCI_LBA_SIZE_4MB (0x16 << 2) #define IDT_PCI_LBA_SIZE_8MB (0x17 << 2) #define IDT_PCI_LBA_SIZE_16MB (0x18 << 2) #define IDT_PCI_LBA_SIZE_32MB (0x19 << 2) #define IDT_PCI_LBA_SIZE_64MB (0x1A << 2) #define IDT_PCI_LBA_SIZE_128MB (0x1B << 2) #define IDT_PCI_LBA_SIZE_256MB (0x1C << 2) #define IDT_PCI_LBA_FE 0x80 #define IDT_PCI_LBA_RT 0x100 #define IDT_PCI_LBA0_MAP 0x1C #define IDT_PCI_LBA1 0x20 #define IDT_PCI_LBA1_CNTL 0x24 #define IDT_PCI_LBA1_MAP 0x28 #define IDT_PCI_LBA2 0x2C #define IDT_PCI_LBA2_CNTL 0x30 #define IDT_PCI_LBA2_MAP 0x34 #define IDT_PCI_LBA3 0x38 #define IDT_PCI_LBA3_CNTL 0x3C #define IDT_PCI_LBA3_MAP 0x40 /* decoupled registers */ #define IDT_PCI_DAC 0x44 #define IDT_PCI_DAS 0x48 #define IDT_PCI_DASM 0x4C #define IDT_PCI_TC 0x5C #define IDT_PCI_TC_RTIMER 0x10 #define IDT_PCI_TC_DTIMER 0x08 /* Messaging unit of PCI controller */ #define IDT_PCI_IIC 0x8024 #define IDT_PCI_IIM 0x8028 #define IDT_PCI_OIC 0x8030 #define IDT_PCI_OIM 0x8034 /* PCI-related stuff */ #define IDT_PCIMEM0_BASE 0x50000000 #define IDT_PCIMEM0_SIZE 0x01000000 #define IDT_PCIMEM1_BASE 0x60000000 #define IDT_PCIMEM1_SIZE 0x10000000 #define IDT_PCIMEM2_BASE 0x18C00000 #define IDT_PCIMEM2_SIZE 0x00400000 #define IDT_PCIMEM3_BASE 0x18800000 #define IDT_PCIMEM3_SIZE 0x00100000 /* Interrupts-related stuff */ #define IRQ_BASE 8 /* Convert pair to IRQ number */ #define IP_IRQ(IPbit, offset) ((IPbit - 2) * 32 + (offset) + IRQ_BASE) /* The last one available IRQ */ #define IRQ_END IP_IRQ(6, 31) #define ICU_GROUP_REG_OFFSET 0x0C #define ICU_IP(irq) (((irq) - IRQ_BASE) & 0x1f) #define ICU_IP_BIT(irq) (1 << ICU_IP(irq)) #define ICU_GROUP(irq) (((irq) - IRQ_BASE) >> 5) #define ICU_GROUP_MASK_REG(group) \ (ICU_IMASK2 + ((((group) - 2) * ICU_GROUP_REG_OFFSET))) #define ICU_GROUP_IPEND_REG(group) \ (ICU_IPEND2 + ((((group) - 2) * ICU_GROUP_REG_OFFSET))) #define ICU_IRQ_MASK_REG(irq) \ (ICU_IMASK2 + ((ICU_GROUP(irq) * ICU_GROUP_REG_OFFSET))) #define ICU_IRQ_IPEND_REG(irq) \ (ICU_IPEND2 + ((ICU_GROUP(irq) * ICU_GROUP_REG_OFFSET))) #define PCI_IRQ_BASE IP_IRQ(6, 4) #define PCI_IRQ_END IP_IRQ(6, 7) #endif /* __IDTREG_H__ */ Index: head/sys/mips/idt/if_kr.c =================================================================== --- head/sys/mips/idt/if_kr.c (revision 326258) +++ head/sys/mips/idt/if_kr.c (revision 326259) @@ -1,1611 +1,1613 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (C) 2007 * Oleksandr Tymoshenko . 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 ``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 HIS RELATIVES 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 MIND, 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. * * $Id: $ * */ #include __FBSDID("$FreeBSD$"); /* * RC32434 Ethernet interface driver */ #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 MODULE_DEPEND(kr, ether, 1, 1, 1); MODULE_DEPEND(kr, miibus, 1, 1, 1); #include "miibus_if.h" #include #define KR_DEBUG static int kr_attach(device_t); static int kr_detach(device_t); static int kr_ifmedia_upd(struct ifnet *); static void kr_ifmedia_sts(struct ifnet *, struct ifmediareq *); static int kr_ioctl(struct ifnet *, u_long, caddr_t); static void kr_init(void *); static void kr_init_locked(struct kr_softc *); static void kr_link_task(void *, int); static int kr_miibus_readreg(device_t, int, int); static void kr_miibus_statchg(device_t); static int kr_miibus_writereg(device_t, int, int, int); static int kr_probe(device_t); static void kr_reset(struct kr_softc *); static int kr_resume(device_t); static int kr_rx_ring_init(struct kr_softc *); static int kr_tx_ring_init(struct kr_softc *); static int kr_shutdown(device_t); static void kr_start(struct ifnet *); static void kr_start_locked(struct ifnet *); static void kr_stop(struct kr_softc *); static int kr_suspend(device_t); static void kr_rx(struct kr_softc *); static void kr_tx(struct kr_softc *); static void kr_rx_intr(void *); static void kr_tx_intr(void *); static void kr_rx_und_intr(void *); static void kr_tx_ovr_intr(void *); static void kr_tick(void *); static void kr_dmamap_cb(void *, bus_dma_segment_t *, int, int); static int kr_dma_alloc(struct kr_softc *); static void kr_dma_free(struct kr_softc *); static int kr_newbuf(struct kr_softc *, int); static __inline void kr_fixup_rx(struct mbuf *); static device_method_t kr_methods[] = { /* Device interface */ DEVMETHOD(device_probe, kr_probe), DEVMETHOD(device_attach, kr_attach), DEVMETHOD(device_detach, kr_detach), DEVMETHOD(device_suspend, kr_suspend), DEVMETHOD(device_resume, kr_resume), DEVMETHOD(device_shutdown, kr_shutdown), /* MII interface */ DEVMETHOD(miibus_readreg, kr_miibus_readreg), DEVMETHOD(miibus_writereg, kr_miibus_writereg), DEVMETHOD(miibus_statchg, kr_miibus_statchg), DEVMETHOD_END }; static driver_t kr_driver = { "kr", kr_methods, sizeof(struct kr_softc) }; static devclass_t kr_devclass; DRIVER_MODULE(kr, obio, kr_driver, kr_devclass, 0, 0); DRIVER_MODULE(miibus, kr, miibus_driver, miibus_devclass, 0, 0); static int kr_probe(device_t dev) { device_set_desc(dev, "RC32434 Ethernet interface"); return (0); } static int kr_attach(device_t dev) { uint8_t eaddr[ETHER_ADDR_LEN]; struct ifnet *ifp; struct kr_softc *sc; int error = 0, rid; int unit; sc = device_get_softc(dev); unit = device_get_unit(dev); sc->kr_dev = dev; mtx_init(&sc->kr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF); callout_init_mtx(&sc->kr_stat_callout, &sc->kr_mtx, 0); TASK_INIT(&sc->kr_link_task, 0, kr_link_task, sc); pci_enable_busmaster(dev); /* Map control/status registers. */ sc->kr_rid = 0; sc->kr_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->kr_rid, RF_ACTIVE); if (sc->kr_res == NULL) { device_printf(dev, "couldn't map memory\n"); error = ENXIO; goto fail; } sc->kr_btag = rman_get_bustag(sc->kr_res); sc->kr_bhandle = rman_get_bushandle(sc->kr_res); /* Allocate interrupts */ rid = 0; sc->kr_rx_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, KR_RX_IRQ, KR_RX_IRQ, 1, RF_SHAREABLE | RF_ACTIVE); if (sc->kr_rx_irq == NULL) { device_printf(dev, "couldn't map rx interrupt\n"); error = ENXIO; goto fail; } rid = 0; sc->kr_tx_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, KR_TX_IRQ, KR_TX_IRQ, 1, RF_SHAREABLE | RF_ACTIVE); if (sc->kr_tx_irq == NULL) { device_printf(dev, "couldn't map tx interrupt\n"); error = ENXIO; goto fail; } rid = 0; sc->kr_rx_und_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, KR_RX_UND_IRQ, KR_RX_UND_IRQ, 1, RF_SHAREABLE | RF_ACTIVE); if (sc->kr_rx_und_irq == NULL) { device_printf(dev, "couldn't map rx underrun interrupt\n"); error = ENXIO; goto fail; } rid = 0; sc->kr_tx_ovr_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, KR_TX_OVR_IRQ, KR_TX_OVR_IRQ, 1, RF_SHAREABLE | RF_ACTIVE); if (sc->kr_tx_ovr_irq == NULL) { device_printf(dev, "couldn't map tx overrun interrupt\n"); error = ENXIO; goto fail; } /* Allocate ifnet structure. */ ifp = sc->kr_ifp = if_alloc(IFT_ETHER); if (ifp == NULL) { device_printf(dev, "couldn't allocate ifnet structure\n"); error = ENOSPC; goto fail; } ifp->if_softc = sc; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = kr_ioctl; ifp->if_start = kr_start; ifp->if_init = kr_init; /* XXX: add real size */ IFQ_SET_MAXLEN(&ifp->if_snd, 9); ifp->if_snd.ifq_maxlen = 9; IFQ_SET_READY(&ifp->if_snd); ifp->if_capenable = ifp->if_capabilities; eaddr[0] = 0x00; eaddr[1] = 0x0C; eaddr[2] = 0x42; eaddr[3] = 0x09; eaddr[4] = 0x5E; eaddr[5] = 0x6B; if (kr_dma_alloc(sc) != 0) { error = ENXIO; goto fail; } /* TODO: calculate prescale */ CSR_WRITE_4(sc, KR_ETHMCP, (165000000 / (1250000 + 1)) & ~1); CSR_WRITE_4(sc, KR_MIIMCFG, KR_MIIMCFG_R); DELAY(1000); CSR_WRITE_4(sc, KR_MIIMCFG, 0); /* Do MII setup. */ error = mii_attach(dev, &sc->kr_miibus, ifp, kr_ifmedia_upd, kr_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0); if (error != 0) { device_printf(dev, "attaching PHYs failed\n"); goto fail; } /* Call MI attach routine. */ ether_ifattach(ifp, eaddr); /* Hook interrupt last to avoid having to lock softc */ error = bus_setup_intr(dev, sc->kr_rx_irq, INTR_TYPE_NET | INTR_MPSAFE, NULL, kr_rx_intr, sc, &sc->kr_rx_intrhand); if (error) { device_printf(dev, "couldn't set up rx irq\n"); ether_ifdetach(ifp); goto fail; } error = bus_setup_intr(dev, sc->kr_tx_irq, INTR_TYPE_NET | INTR_MPSAFE, NULL, kr_tx_intr, sc, &sc->kr_tx_intrhand); if (error) { device_printf(dev, "couldn't set up tx irq\n"); ether_ifdetach(ifp); goto fail; } error = bus_setup_intr(dev, sc->kr_rx_und_irq, INTR_TYPE_NET | INTR_MPSAFE, NULL, kr_rx_und_intr, sc, &sc->kr_rx_und_intrhand); if (error) { device_printf(dev, "couldn't set up rx underrun irq\n"); ether_ifdetach(ifp); goto fail; } error = bus_setup_intr(dev, sc->kr_tx_ovr_irq, INTR_TYPE_NET | INTR_MPSAFE, NULL, kr_tx_ovr_intr, sc, &sc->kr_tx_ovr_intrhand); if (error) { device_printf(dev, "couldn't set up tx overrun irq\n"); ether_ifdetach(ifp); goto fail; } fail: if (error) kr_detach(dev); return (error); } static int kr_detach(device_t dev) { struct kr_softc *sc = device_get_softc(dev); struct ifnet *ifp = sc->kr_ifp; KASSERT(mtx_initialized(&sc->kr_mtx), ("vr mutex not initialized")); /* These should only be active if attach succeeded */ if (device_is_attached(dev)) { KR_LOCK(sc); sc->kr_detach = 1; kr_stop(sc); KR_UNLOCK(sc); taskqueue_drain(taskqueue_swi, &sc->kr_link_task); ether_ifdetach(ifp); } if (sc->kr_miibus) device_delete_child(dev, sc->kr_miibus); bus_generic_detach(dev); if (sc->kr_rx_intrhand) bus_teardown_intr(dev, sc->kr_rx_irq, sc->kr_rx_intrhand); if (sc->kr_rx_irq) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->kr_rx_irq); if (sc->kr_tx_intrhand) bus_teardown_intr(dev, sc->kr_tx_irq, sc->kr_tx_intrhand); if (sc->kr_tx_irq) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->kr_tx_irq); if (sc->kr_rx_und_intrhand) bus_teardown_intr(dev, sc->kr_rx_und_irq, sc->kr_rx_und_intrhand); if (sc->kr_rx_und_irq) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->kr_rx_und_irq); if (sc->kr_tx_ovr_intrhand) bus_teardown_intr(dev, sc->kr_tx_ovr_irq, sc->kr_tx_ovr_intrhand); if (sc->kr_tx_ovr_irq) bus_release_resource(dev, SYS_RES_IRQ, 0, sc->kr_tx_ovr_irq); if (sc->kr_res) bus_release_resource(dev, SYS_RES_MEMORY, sc->kr_rid, sc->kr_res); if (ifp) if_free(ifp); kr_dma_free(sc); mtx_destroy(&sc->kr_mtx); return (0); } static int kr_suspend(device_t dev) { panic("%s", __func__); return 0; } static int kr_resume(device_t dev) { panic("%s", __func__); return 0; } static int kr_shutdown(device_t dev) { struct kr_softc *sc; sc = device_get_softc(dev); KR_LOCK(sc); kr_stop(sc); KR_UNLOCK(sc); return (0); } static int kr_miibus_readreg(device_t dev, int phy, int reg) { struct kr_softc * sc = device_get_softc(dev); int i, result; i = KR_MII_TIMEOUT; while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i) i--; if (i == 0) device_printf(dev, "phy mii is busy %d:%d\n", phy, reg); CSR_WRITE_4(sc, KR_MIIMADDR, (phy << 8) | reg); i = KR_MII_TIMEOUT; while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i) i--; if (i == 0) device_printf(dev, "phy mii is busy %d:%d\n", phy, reg); CSR_WRITE_4(sc, KR_MIIMCMD, KR_MIIMCMD_RD); i = KR_MII_TIMEOUT; while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i) i--; if (i == 0) device_printf(dev, "phy mii read is timed out %d:%d\n", phy, reg); if (CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_NV) printf("phy mii readreg failed %d:%d: data not valid\n", phy, reg); result = CSR_READ_4(sc , KR_MIIMRDD); CSR_WRITE_4(sc, KR_MIIMCMD, 0); return (result); } static int kr_miibus_writereg(device_t dev, int phy, int reg, int data) { struct kr_softc * sc = device_get_softc(dev); int i; i = KR_MII_TIMEOUT; while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i) i--; if (i == 0) device_printf(dev, "phy mii is busy %d:%d\n", phy, reg); CSR_WRITE_4(sc, KR_MIIMADDR, (phy << 8) | reg); i = KR_MII_TIMEOUT; while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i) i--; if (i == 0) device_printf(dev, "phy mii is busy %d:%d\n", phy, reg); CSR_WRITE_4(sc, KR_MIIMWTD, data); i = KR_MII_TIMEOUT; while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i) i--; if (i == 0) device_printf(dev, "phy mii is busy %d:%d\n", phy, reg); return (0); } static void kr_miibus_statchg(device_t dev) { struct kr_softc *sc; sc = device_get_softc(dev); taskqueue_enqueue(taskqueue_swi, &sc->kr_link_task); } static void kr_link_task(void *arg, int pending) { struct kr_softc *sc; struct mii_data *mii; struct ifnet *ifp; /* int lfdx, mfdx; */ sc = (struct kr_softc *)arg; KR_LOCK(sc); mii = device_get_softc(sc->kr_miibus); ifp = sc->kr_ifp; if (mii == NULL || ifp == NULL || (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { KR_UNLOCK(sc); return; } if (mii->mii_media_status & IFM_ACTIVE) { if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) sc->kr_link_status = 1; } else sc->kr_link_status = 0; KR_UNLOCK(sc); } static void kr_reset(struct kr_softc *sc) { int i; CSR_WRITE_4(sc, KR_ETHINTFC, 0); for (i = 0; i < KR_TIMEOUT; i++) { DELAY(10); if (!(CSR_READ_4(sc, KR_ETHINTFC) & ETH_INTFC_RIP)) break; } if (i == KR_TIMEOUT) device_printf(sc->kr_dev, "reset time out\n"); } static void kr_init(void *xsc) { struct kr_softc *sc = xsc; KR_LOCK(sc); kr_init_locked(sc); KR_UNLOCK(sc); } static void kr_init_locked(struct kr_softc *sc) { struct ifnet *ifp = sc->kr_ifp; struct mii_data *mii; KR_LOCK_ASSERT(sc); mii = device_get_softc(sc->kr_miibus); kr_stop(sc); kr_reset(sc); CSR_WRITE_4(sc, KR_ETHINTFC, ETH_INTFC_EN); /* Init circular RX list. */ if (kr_rx_ring_init(sc) != 0) { device_printf(sc->kr_dev, "initialization failed: no memory for rx buffers\n"); kr_stop(sc); return; } /* Init tx descriptors. */ kr_tx_ring_init(sc); KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_S, 0); KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_NDPTR, 0); KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_DPTR, sc->kr_rdata.kr_rx_ring_paddr); KR_DMA_CLEARBITS_REG(KR_DMA_RXCHAN, DMA_SM, DMA_SM_H | DMA_SM_E | DMA_SM_D) ; KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_S, 0); KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_NDPTR, 0); KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_DPTR, 0); KR_DMA_CLEARBITS_REG(KR_DMA_TXCHAN, DMA_SM, DMA_SM_F | DMA_SM_E); /* Accept only packets destined for THIS Ethernet device address */ CSR_WRITE_4(sc, KR_ETHARC, 1); /* * Set all Ethernet address registers to the same initial values * set all four addresses to 66-88-aa-cc-dd-ee */ CSR_WRITE_4(sc, KR_ETHSAL0, 0x42095E6B); CSR_WRITE_4(sc, KR_ETHSAH0, 0x0000000C); CSR_WRITE_4(sc, KR_ETHSAL1, 0x42095E6B); CSR_WRITE_4(sc, KR_ETHSAH1, 0x0000000C); CSR_WRITE_4(sc, KR_ETHSAL2, 0x42095E6B); CSR_WRITE_4(sc, KR_ETHSAH2, 0x0000000C); CSR_WRITE_4(sc, KR_ETHSAL3, 0x42095E6B); CSR_WRITE_4(sc, KR_ETHSAH3, 0x0000000C); CSR_WRITE_4(sc, KR_ETHMAC2, KR_ETH_MAC2_PEN | KR_ETH_MAC2_CEN | KR_ETH_MAC2_FD); CSR_WRITE_4(sc, KR_ETHIPGT, KR_ETHIPGT_FULL_DUPLEX); CSR_WRITE_4(sc, KR_ETHIPGR, 0x12); /* minimum value */ CSR_WRITE_4(sc, KR_MIIMCFG, KR_MIIMCFG_R); DELAY(1000); CSR_WRITE_4(sc, KR_MIIMCFG, 0); /* TODO: calculate prescale */ CSR_WRITE_4(sc, KR_ETHMCP, (165000000 / (1250000 + 1)) & ~1); /* FIFO Tx threshold level */ CSR_WRITE_4(sc, KR_ETHFIFOTT, 0x30); CSR_WRITE_4(sc, KR_ETHMAC1, KR_ETH_MAC1_RE); sc->kr_link_status = 0; mii_mediachg(mii); ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; callout_reset(&sc->kr_stat_callout, hz, kr_tick, sc); } static void kr_start(struct ifnet *ifp) { struct kr_softc *sc; sc = ifp->if_softc; KR_LOCK(sc); kr_start_locked(ifp); KR_UNLOCK(sc); } /* * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data * pointers to the fragment pointers. */ static int kr_encap(struct kr_softc *sc, struct mbuf **m_head) { struct kr_txdesc *txd; struct kr_desc *desc, *prev_desc; bus_dma_segment_t txsegs[KR_MAXFRAGS]; uint32_t link_addr; int error, i, nsegs, prod, si, prev_prod; KR_LOCK_ASSERT(sc); prod = sc->kr_cdata.kr_tx_prod; txd = &sc->kr_cdata.kr_txdesc[prod]; error = bus_dmamap_load_mbuf_sg(sc->kr_cdata.kr_tx_tag, txd->tx_dmamap, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT); if (error == EFBIG) { panic("EFBIG"); } else if (error != 0) return (error); if (nsegs == 0) { m_freem(*m_head); *m_head = NULL; return (EIO); } /* Check number of available descriptors. */ if (sc->kr_cdata.kr_tx_cnt + nsegs >= (KR_TX_RING_CNT - 1)) { bus_dmamap_unload(sc->kr_cdata.kr_tx_tag, txd->tx_dmamap); return (ENOBUFS); } txd->tx_m = *m_head; bus_dmamap_sync(sc->kr_cdata.kr_tx_tag, txd->tx_dmamap, BUS_DMASYNC_PREWRITE); si = prod; /* * Make a list of descriptors for this packet. DMA controller will * walk through it while kr_link is not zero. The last one should * have COF flag set, to pickup next chain from NDPTR */ prev_prod = prod; desc = prev_desc = NULL; for (i = 0; i < nsegs; i++) { desc = &sc->kr_rdata.kr_tx_ring[prod]; desc->kr_ctl = KR_DMASIZE(txsegs[i].ds_len) | KR_CTL_IOF; if (i == 0) desc->kr_devcs = KR_DMATX_DEVCS_FD; desc->kr_ca = txsegs[i].ds_addr; desc->kr_link = 0; /* link with previous descriptor */ if (prev_desc) prev_desc->kr_link = KR_TX_RING_ADDR(sc, prod); sc->kr_cdata.kr_tx_cnt++; prev_desc = desc; KR_INC(prod, KR_TX_RING_CNT); } /* * Set COF for last descriptor and mark last fragment with LD flag */ if (desc) { desc->kr_ctl |= KR_CTL_COF; desc->kr_devcs |= KR_DMATX_DEVCS_LD; } /* Update producer index. */ sc->kr_cdata.kr_tx_prod = prod; /* Sync descriptors. */ bus_dmamap_sync(sc->kr_cdata.kr_tx_ring_tag, sc->kr_cdata.kr_tx_ring_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); /* Start transmitting */ /* Check if new list is queued in NDPTR */ if (KR_DMA_READ_REG(KR_DMA_TXCHAN, DMA_NDPTR) == 0) { /* NDPTR is not busy - start new list */ KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_NDPTR, KR_TX_RING_ADDR(sc, si)); } else { link_addr = KR_TX_RING_ADDR(sc, si); /* Get previous descriptor */ si = (si + KR_TX_RING_CNT - 1) % KR_TX_RING_CNT; desc = &sc->kr_rdata.kr_tx_ring[si]; desc->kr_link = link_addr; } return (0); } static void kr_start_locked(struct ifnet *ifp) { struct kr_softc *sc; struct mbuf *m_head; int enq; sc = ifp->if_softc; KR_LOCK_ASSERT(sc); if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING || sc->kr_link_status == 0 ) return; for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) && sc->kr_cdata.kr_tx_cnt < KR_TX_RING_CNT - 2; ) { IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head); if (m_head == NULL) break; /* * Pack the data into the transmit ring. If we * don't have room, set the OACTIVE flag and wait * for the NIC to drain the ring. */ if (kr_encap(sc, &m_head)) { if (m_head == NULL) break; IFQ_DRV_PREPEND(&ifp->if_snd, m_head); ifp->if_drv_flags |= IFF_DRV_OACTIVE; break; } enq++; /* * If there's a BPF listener, bounce a copy of this frame * to him. */ ETHER_BPF_MTAP(ifp, m_head); } } static void kr_stop(struct kr_softc *sc) { struct ifnet *ifp; KR_LOCK_ASSERT(sc); ifp = sc->kr_ifp; ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); callout_stop(&sc->kr_stat_callout); /* mask out RX interrupts */ KR_DMA_SETBITS_REG(KR_DMA_RXCHAN, DMA_SM, DMA_SM_D | DMA_SM_H | DMA_SM_E); /* mask out TX interrupts */ KR_DMA_SETBITS_REG(KR_DMA_TXCHAN, DMA_SM, DMA_SM_F | DMA_SM_E); /* Abort RX DMA transactions */ if (KR_DMA_READ_REG(KR_DMA_RXCHAN, DMA_C) & DMA_C_R) { /* Set ABORT bit if trunsuction is in progress */ KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_C, DMA_C_ABORT); /* XXX: Add timeout */ while ((KR_DMA_READ_REG(KR_DMA_RXCHAN, DMA_S) & DMA_S_H) == 0) DELAY(10); KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_S, 0); } KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_DPTR, 0); KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_NDPTR, 0); /* Abort TX DMA transactions */ if (KR_DMA_READ_REG(KR_DMA_TXCHAN, DMA_C) & DMA_C_R) { /* Set ABORT bit if trunsuction is in progress */ KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_C, DMA_C_ABORT); /* XXX: Add timeout */ while ((KR_DMA_READ_REG(KR_DMA_TXCHAN, DMA_S) & DMA_S_H) == 0) DELAY(10); KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_S, 0); } KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_DPTR, 0); KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_NDPTR, 0); CSR_WRITE_4(sc, KR_ETHINTFC, 0); } static int kr_ioctl(struct ifnet *ifp, u_long command, caddr_t data) { struct kr_softc *sc = ifp->if_softc; struct ifreq *ifr = (struct ifreq *) data; struct mii_data *mii; int error; switch (command) { case SIOCSIFFLAGS: #if 0 KR_LOCK(sc); if (ifp->if_flags & IFF_UP) { if (ifp->if_drv_flags & IFF_DRV_RUNNING) { if ((ifp->if_flags ^ sc->kr_if_flags) & (IFF_PROMISC | IFF_ALLMULTI)) kr_set_filter(sc); } else { if (sc->kr_detach == 0) kr_init_locked(sc); } } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) kr_stop(sc); } sc->kr_if_flags = ifp->if_flags; KR_UNLOCK(sc); #endif error = 0; break; case SIOCADDMULTI: case SIOCDELMULTI: #if 0 KR_LOCK(sc); kr_set_filter(sc); KR_UNLOCK(sc); #endif error = 0; break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: mii = device_get_softc(sc->kr_miibus); error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); break; case SIOCSIFCAP: error = 0; #if 0 mask = ifr->ifr_reqcap ^ ifp->if_capenable; if ((mask & IFCAP_HWCSUM) != 0) { ifp->if_capenable ^= IFCAP_HWCSUM; if ((IFCAP_HWCSUM & ifp->if_capenable) && (IFCAP_HWCSUM & ifp->if_capabilities)) ifp->if_hwassist = KR_CSUM_FEATURES; else ifp->if_hwassist = 0; } if ((mask & IFCAP_VLAN_HWTAGGING) != 0) { ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; if (IFCAP_VLAN_HWTAGGING & ifp->if_capenable && IFCAP_VLAN_HWTAGGING & ifp->if_capabilities && ifp->if_drv_flags & IFF_DRV_RUNNING) { KR_LOCK(sc); kr_vlan_setup(sc); KR_UNLOCK(sc); } } VLAN_CAPABILITIES(ifp); #endif break; default: error = ether_ioctl(ifp, command, data); break; } return (error); } /* * Set media options. */ static int kr_ifmedia_upd(struct ifnet *ifp) { struct kr_softc *sc; struct mii_data *mii; struct mii_softc *miisc; int error; sc = ifp->if_softc; KR_LOCK(sc); mii = device_get_softc(sc->kr_miibus); LIST_FOREACH(miisc, &mii->mii_phys, mii_list) PHY_RESET(miisc); error = mii_mediachg(mii); KR_UNLOCK(sc); return (error); } /* * Report current media status. */ static void kr_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) { struct kr_softc *sc = ifp->if_softc; struct mii_data *mii; mii = device_get_softc(sc->kr_miibus); KR_LOCK(sc); mii_pollstat(mii); ifmr->ifm_active = mii->mii_media_active; ifmr->ifm_status = mii->mii_media_status; KR_UNLOCK(sc); } struct kr_dmamap_arg { bus_addr_t kr_busaddr; }; static void kr_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) { struct kr_dmamap_arg *ctx; if (error != 0) return; ctx = arg; ctx->kr_busaddr = segs[0].ds_addr; } static int kr_dma_alloc(struct kr_softc *sc) { struct kr_dmamap_arg ctx; struct kr_txdesc *txd; struct kr_rxdesc *rxd; int error, i; /* Create parent DMA tag. */ error = bus_dma_tag_create( bus_get_dma_tag(sc->kr_dev), /* parent */ 1, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ BUS_SPACE_MAXSIZE_32BIT, /* maxsize */ 0, /* nsegments */ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->kr_cdata.kr_parent_tag); if (error != 0) { device_printf(sc->kr_dev, "failed to create parent DMA tag\n"); goto fail; } /* Create tag for Tx ring. */ error = bus_dma_tag_create( sc->kr_cdata.kr_parent_tag, /* parent */ KR_RING_ALIGN, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ KR_TX_RING_SIZE, /* maxsize */ 1, /* nsegments */ KR_TX_RING_SIZE, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->kr_cdata.kr_tx_ring_tag); if (error != 0) { device_printf(sc->kr_dev, "failed to create Tx ring DMA tag\n"); goto fail; } /* Create tag for Rx ring. */ error = bus_dma_tag_create( sc->kr_cdata.kr_parent_tag, /* parent */ KR_RING_ALIGN, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ KR_RX_RING_SIZE, /* maxsize */ 1, /* nsegments */ KR_RX_RING_SIZE, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->kr_cdata.kr_rx_ring_tag); if (error != 0) { device_printf(sc->kr_dev, "failed to create Rx ring DMA tag\n"); goto fail; } /* Create tag for Tx buffers. */ error = bus_dma_tag_create( sc->kr_cdata.kr_parent_tag, /* parent */ sizeof(uint32_t), 0, /* alignment, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ MCLBYTES * KR_MAXFRAGS, /* maxsize */ KR_MAXFRAGS, /* nsegments */ MCLBYTES, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->kr_cdata.kr_tx_tag); if (error != 0) { device_printf(sc->kr_dev, "failed to create Tx DMA tag\n"); goto fail; } /* Create tag for Rx buffers. */ error = bus_dma_tag_create( sc->kr_cdata.kr_parent_tag, /* parent */ KR_RX_ALIGN, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ MCLBYTES, /* maxsize */ 1, /* nsegments */ MCLBYTES, /* maxsegsize */ 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->kr_cdata.kr_rx_tag); if (error != 0) { device_printf(sc->kr_dev, "failed to create Rx DMA tag\n"); goto fail; } /* Allocate DMA'able memory and load the DMA map for Tx ring. */ error = bus_dmamem_alloc(sc->kr_cdata.kr_tx_ring_tag, (void **)&sc->kr_rdata.kr_tx_ring, BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->kr_cdata.kr_tx_ring_map); if (error != 0) { device_printf(sc->kr_dev, "failed to allocate DMA'able memory for Tx ring\n"); goto fail; } ctx.kr_busaddr = 0; error = bus_dmamap_load(sc->kr_cdata.kr_tx_ring_tag, sc->kr_cdata.kr_tx_ring_map, sc->kr_rdata.kr_tx_ring, KR_TX_RING_SIZE, kr_dmamap_cb, &ctx, 0); if (error != 0 || ctx.kr_busaddr == 0) { device_printf(sc->kr_dev, "failed to load DMA'able memory for Tx ring\n"); goto fail; } sc->kr_rdata.kr_tx_ring_paddr = ctx.kr_busaddr; /* Allocate DMA'able memory and load the DMA map for Rx ring. */ error = bus_dmamem_alloc(sc->kr_cdata.kr_rx_ring_tag, (void **)&sc->kr_rdata.kr_rx_ring, BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->kr_cdata.kr_rx_ring_map); if (error != 0) { device_printf(sc->kr_dev, "failed to allocate DMA'able memory for Rx ring\n"); goto fail; } ctx.kr_busaddr = 0; error = bus_dmamap_load(sc->kr_cdata.kr_rx_ring_tag, sc->kr_cdata.kr_rx_ring_map, sc->kr_rdata.kr_rx_ring, KR_RX_RING_SIZE, kr_dmamap_cb, &ctx, 0); if (error != 0 || ctx.kr_busaddr == 0) { device_printf(sc->kr_dev, "failed to load DMA'able memory for Rx ring\n"); goto fail; } sc->kr_rdata.kr_rx_ring_paddr = ctx.kr_busaddr; /* Create DMA maps for Tx buffers. */ for (i = 0; i < KR_TX_RING_CNT; i++) { txd = &sc->kr_cdata.kr_txdesc[i]; txd->tx_m = NULL; txd->tx_dmamap = NULL; error = bus_dmamap_create(sc->kr_cdata.kr_tx_tag, 0, &txd->tx_dmamap); if (error != 0) { device_printf(sc->kr_dev, "failed to create Tx dmamap\n"); goto fail; } } /* Create DMA maps for Rx buffers. */ if ((error = bus_dmamap_create(sc->kr_cdata.kr_rx_tag, 0, &sc->kr_cdata.kr_rx_sparemap)) != 0) { device_printf(sc->kr_dev, "failed to create spare Rx dmamap\n"); goto fail; } for (i = 0; i < KR_RX_RING_CNT; i++) { rxd = &sc->kr_cdata.kr_rxdesc[i]; rxd->rx_m = NULL; rxd->rx_dmamap = NULL; error = bus_dmamap_create(sc->kr_cdata.kr_rx_tag, 0, &rxd->rx_dmamap); if (error != 0) { device_printf(sc->kr_dev, "failed to create Rx dmamap\n"); goto fail; } } fail: return (error); } static void kr_dma_free(struct kr_softc *sc) { struct kr_txdesc *txd; struct kr_rxdesc *rxd; int i; /* Tx ring. */ if (sc->kr_cdata.kr_tx_ring_tag) { if (sc->kr_rdata.kr_tx_ring_paddr) bus_dmamap_unload(sc->kr_cdata.kr_tx_ring_tag, sc->kr_cdata.kr_tx_ring_map); if (sc->kr_rdata.kr_tx_ring) bus_dmamem_free(sc->kr_cdata.kr_tx_ring_tag, sc->kr_rdata.kr_tx_ring, sc->kr_cdata.kr_tx_ring_map); sc->kr_rdata.kr_tx_ring = NULL; sc->kr_rdata.kr_tx_ring_paddr = 0; bus_dma_tag_destroy(sc->kr_cdata.kr_tx_ring_tag); sc->kr_cdata.kr_tx_ring_tag = NULL; } /* Rx ring. */ if (sc->kr_cdata.kr_rx_ring_tag) { if (sc->kr_rdata.kr_rx_ring_paddr) bus_dmamap_unload(sc->kr_cdata.kr_rx_ring_tag, sc->kr_cdata.kr_rx_ring_map); if (sc->kr_rdata.kr_rx_ring) bus_dmamem_free(sc->kr_cdata.kr_rx_ring_tag, sc->kr_rdata.kr_rx_ring, sc->kr_cdata.kr_rx_ring_map); sc->kr_rdata.kr_rx_ring = NULL; sc->kr_rdata.kr_rx_ring_paddr = 0; bus_dma_tag_destroy(sc->kr_cdata.kr_rx_ring_tag); sc->kr_cdata.kr_rx_ring_tag = NULL; } /* Tx buffers. */ if (sc->kr_cdata.kr_tx_tag) { for (i = 0; i < KR_TX_RING_CNT; i++) { txd = &sc->kr_cdata.kr_txdesc[i]; if (txd->tx_dmamap) { bus_dmamap_destroy(sc->kr_cdata.kr_tx_tag, txd->tx_dmamap); txd->tx_dmamap = NULL; } } bus_dma_tag_destroy(sc->kr_cdata.kr_tx_tag); sc->kr_cdata.kr_tx_tag = NULL; } /* Rx buffers. */ if (sc->kr_cdata.kr_rx_tag) { for (i = 0; i < KR_RX_RING_CNT; i++) { rxd = &sc->kr_cdata.kr_rxdesc[i]; if (rxd->rx_dmamap) { bus_dmamap_destroy(sc->kr_cdata.kr_rx_tag, rxd->rx_dmamap); rxd->rx_dmamap = NULL; } } if (sc->kr_cdata.kr_rx_sparemap) { bus_dmamap_destroy(sc->kr_cdata.kr_rx_tag, sc->kr_cdata.kr_rx_sparemap); sc->kr_cdata.kr_rx_sparemap = 0; } bus_dma_tag_destroy(sc->kr_cdata.kr_rx_tag); sc->kr_cdata.kr_rx_tag = NULL; } if (sc->kr_cdata.kr_parent_tag) { bus_dma_tag_destroy(sc->kr_cdata.kr_parent_tag); sc->kr_cdata.kr_parent_tag = NULL; } } /* * Initialize the transmit descriptors. */ static int kr_tx_ring_init(struct kr_softc *sc) { struct kr_ring_data *rd; struct kr_txdesc *txd; bus_addr_t addr; int i; sc->kr_cdata.kr_tx_prod = 0; sc->kr_cdata.kr_tx_cons = 0; sc->kr_cdata.kr_tx_cnt = 0; sc->kr_cdata.kr_tx_pkts = 0; rd = &sc->kr_rdata; bzero(rd->kr_tx_ring, KR_TX_RING_SIZE); for (i = 0; i < KR_TX_RING_CNT; i++) { if (i == KR_TX_RING_CNT - 1) addr = KR_TX_RING_ADDR(sc, 0); else addr = KR_TX_RING_ADDR(sc, i + 1); rd->kr_tx_ring[i].kr_ctl = KR_CTL_IOF; rd->kr_tx_ring[i].kr_ca = 0; rd->kr_tx_ring[i].kr_devcs = 0; rd->kr_tx_ring[i].kr_link = 0; txd = &sc->kr_cdata.kr_txdesc[i]; txd->tx_m = NULL; } bus_dmamap_sync(sc->kr_cdata.kr_tx_ring_tag, sc->kr_cdata.kr_tx_ring_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); return (0); } /* * Initialize the RX descriptors and allocate mbufs for them. Note that * we arrange the descriptors in a closed ring, so that the last descriptor * points back to the first. */ static int kr_rx_ring_init(struct kr_softc *sc) { struct kr_ring_data *rd; struct kr_rxdesc *rxd; bus_addr_t addr; int i; sc->kr_cdata.kr_rx_cons = 0; rd = &sc->kr_rdata; bzero(rd->kr_rx_ring, KR_RX_RING_SIZE); for (i = 0; i < KR_RX_RING_CNT; i++) { rxd = &sc->kr_cdata.kr_rxdesc[i]; rxd->rx_m = NULL; rxd->desc = &rd->kr_rx_ring[i]; if (i == KR_RX_RING_CNT - 1) addr = KR_RX_RING_ADDR(sc, 0); else addr = KR_RX_RING_ADDR(sc, i + 1); rd->kr_rx_ring[i].kr_ctl = KR_CTL_IOD; if (i == KR_RX_RING_CNT - 1) rd->kr_rx_ring[i].kr_ctl |= KR_CTL_COD; rd->kr_rx_ring[i].kr_devcs = 0; rd->kr_rx_ring[i].kr_ca = 0; rd->kr_rx_ring[i].kr_link = addr; if (kr_newbuf(sc, i) != 0) return (ENOBUFS); } bus_dmamap_sync(sc->kr_cdata.kr_rx_ring_tag, sc->kr_cdata.kr_rx_ring_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); return (0); } /* * Initialize an RX descriptor and attach an MBUF cluster. */ static int kr_newbuf(struct kr_softc *sc, int idx) { struct kr_desc *desc; struct kr_rxdesc *rxd; struct mbuf *m; bus_dma_segment_t segs[1]; bus_dmamap_t map; int nsegs; m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); if (m == NULL) return (ENOBUFS); m->m_len = m->m_pkthdr.len = MCLBYTES; m_adj(m, sizeof(uint64_t)); if (bus_dmamap_load_mbuf_sg(sc->kr_cdata.kr_rx_tag, sc->kr_cdata.kr_rx_sparemap, m, segs, &nsegs, 0) != 0) { m_freem(m); return (ENOBUFS); } KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); rxd = &sc->kr_cdata.kr_rxdesc[idx]; if (rxd->rx_m != NULL) { bus_dmamap_sync(sc->kr_cdata.kr_rx_tag, rxd->rx_dmamap, BUS_DMASYNC_POSTREAD); bus_dmamap_unload(sc->kr_cdata.kr_rx_tag, rxd->rx_dmamap); } map = rxd->rx_dmamap; rxd->rx_dmamap = sc->kr_cdata.kr_rx_sparemap; sc->kr_cdata.kr_rx_sparemap = map; bus_dmamap_sync(sc->kr_cdata.kr_rx_tag, rxd->rx_dmamap, BUS_DMASYNC_PREREAD); rxd->rx_m = m; desc = rxd->desc; desc->kr_ca = segs[0].ds_addr; desc->kr_ctl |= KR_DMASIZE(segs[0].ds_len); rxd->saved_ca = desc->kr_ca ; rxd->saved_ctl = desc->kr_ctl ; return (0); } static __inline void kr_fixup_rx(struct mbuf *m) { int i; uint16_t *src, *dst; src = mtod(m, uint16_t *); dst = src - 1; for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++) *dst++ = *src++; m->m_data -= ETHER_ALIGN; } static void kr_tx(struct kr_softc *sc) { struct kr_txdesc *txd; struct kr_desc *cur_tx; struct ifnet *ifp; uint32_t ctl, devcs; int cons, prod; KR_LOCK_ASSERT(sc); cons = sc->kr_cdata.kr_tx_cons; prod = sc->kr_cdata.kr_tx_prod; if (cons == prod) return; bus_dmamap_sync(sc->kr_cdata.kr_tx_ring_tag, sc->kr_cdata.kr_tx_ring_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); ifp = sc->kr_ifp; /* * Go through our tx list and free mbufs for those * frames that have been transmitted. */ for (; cons != prod; KR_INC(cons, KR_TX_RING_CNT)) { cur_tx = &sc->kr_rdata.kr_tx_ring[cons]; ctl = cur_tx->kr_ctl; devcs = cur_tx->kr_devcs; /* Check if descriptor has "finished" flag */ if ((ctl & KR_CTL_F) == 0) break; sc->kr_cdata.kr_tx_cnt--; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; txd = &sc->kr_cdata.kr_txdesc[cons]; if (devcs & KR_DMATX_DEVCS_TOK) if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); else { if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); /* collisions: medium busy, late collision */ if ((devcs & KR_DMATX_DEVCS_EC) || (devcs & KR_DMATX_DEVCS_LC)) if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 1); } bus_dmamap_sync(sc->kr_cdata.kr_tx_tag, txd->tx_dmamap, BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->kr_cdata.kr_tx_tag, txd->tx_dmamap); /* Free only if it's first descriptor in list */ if (txd->tx_m) m_freem(txd->tx_m); txd->tx_m = NULL; /* reset descriptor */ cur_tx->kr_ctl = KR_CTL_IOF; cur_tx->kr_devcs = 0; cur_tx->kr_ca = 0; cur_tx->kr_link = 0; } sc->kr_cdata.kr_tx_cons = cons; bus_dmamap_sync(sc->kr_cdata.kr_tx_ring_tag, sc->kr_cdata.kr_tx_ring_map, BUS_DMASYNC_PREWRITE); } static void kr_rx(struct kr_softc *sc) { struct kr_rxdesc *rxd; struct ifnet *ifp = sc->kr_ifp; int cons, prog, packet_len, count, error; struct kr_desc *cur_rx; struct mbuf *m; KR_LOCK_ASSERT(sc); cons = sc->kr_cdata.kr_rx_cons; bus_dmamap_sync(sc->kr_cdata.kr_rx_ring_tag, sc->kr_cdata.kr_rx_ring_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); for (prog = 0; prog < KR_RX_RING_CNT; KR_INC(cons, KR_RX_RING_CNT)) { cur_rx = &sc->kr_rdata.kr_rx_ring[cons]; rxd = &sc->kr_cdata.kr_rxdesc[cons]; m = rxd->rx_m; if ((cur_rx->kr_ctl & KR_CTL_D) == 0) break; prog++; packet_len = KR_PKTSIZE(cur_rx->kr_devcs); count = m->m_len - KR_DMASIZE(cur_rx->kr_ctl); /* Assume it's error */ error = 1; if (packet_len != count) if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); else if (count < 64) if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); else if ((cur_rx->kr_devcs & KR_DMARX_DEVCS_LD) == 0) if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); else if ((cur_rx->kr_devcs & KR_DMARX_DEVCS_ROK) != 0) { error = 0; bus_dmamap_sync(sc->kr_cdata.kr_rx_tag, rxd->rx_dmamap, BUS_DMASYNC_PREREAD); m = rxd->rx_m; kr_fixup_rx(m); m->m_pkthdr.rcvif = ifp; /* Skip 4 bytes of CRC */ m->m_pkthdr.len = m->m_len = packet_len - ETHER_CRC_LEN; if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); KR_UNLOCK(sc); (*ifp->if_input)(ifp, m); KR_LOCK(sc); } if (error) { /* Restore CONTROL and CA values, reset DEVCS */ cur_rx->kr_ctl = rxd->saved_ctl; cur_rx->kr_ca = rxd->saved_ca; cur_rx->kr_devcs = 0; } else { /* Reinit descriptor */ cur_rx->kr_ctl = KR_CTL_IOD; if (cons == KR_RX_RING_CNT - 1) cur_rx->kr_ctl |= KR_CTL_COD; cur_rx->kr_devcs = 0; cur_rx->kr_ca = 0; if (kr_newbuf(sc, cons) != 0) { device_printf(sc->kr_dev, "Failed to allocate buffer\n"); break; } } bus_dmamap_sync(sc->kr_cdata.kr_rx_ring_tag, sc->kr_cdata.kr_rx_ring_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); } if (prog > 0) { sc->kr_cdata.kr_rx_cons = cons; bus_dmamap_sync(sc->kr_cdata.kr_rx_ring_tag, sc->kr_cdata.kr_rx_ring_map, BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); } } static void kr_rx_intr(void *arg) { struct kr_softc *sc = arg; uint32_t status; KR_LOCK(sc); /* mask out interrupts */ KR_DMA_SETBITS_REG(KR_DMA_RXCHAN, DMA_SM, DMA_SM_D | DMA_SM_H | DMA_SM_E); status = KR_DMA_READ_REG(KR_DMA_RXCHAN, DMA_S); if (status & (DMA_S_D | DMA_S_E | DMA_S_H)) { kr_rx(sc); if (status & DMA_S_E) device_printf(sc->kr_dev, "RX DMA error\n"); } /* Reread status */ status = KR_DMA_READ_REG(KR_DMA_RXCHAN, DMA_S); /* restart DMA RX if it has been halted */ if (status & DMA_S_H) { KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_DPTR, KR_RX_RING_ADDR(sc, sc->kr_cdata.kr_rx_cons)); } KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_S, ~status); /* Enable F, H, E interrupts */ KR_DMA_CLEARBITS_REG(KR_DMA_RXCHAN, DMA_SM, DMA_SM_D | DMA_SM_H | DMA_SM_E); KR_UNLOCK(sc); } static void kr_tx_intr(void *arg) { struct kr_softc *sc = arg; uint32_t status; KR_LOCK(sc); /* mask out interrupts */ KR_DMA_SETBITS_REG(KR_DMA_TXCHAN, DMA_SM, DMA_SM_F | DMA_SM_E); status = KR_DMA_READ_REG(KR_DMA_TXCHAN, DMA_S); if (status & (DMA_S_F | DMA_S_E)) { kr_tx(sc); if (status & DMA_S_E) device_printf(sc->kr_dev, "DMA error\n"); } KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_S, ~status); /* Enable F, E interrupts */ KR_DMA_CLEARBITS_REG(KR_DMA_TXCHAN, DMA_SM, DMA_SM_F | DMA_SM_E); KR_UNLOCK(sc); } static void kr_rx_und_intr(void *arg) { panic("interrupt: %s\n", __func__); } static void kr_tx_ovr_intr(void *arg) { panic("interrupt: %s\n", __func__); } static void kr_tick(void *xsc) { struct kr_softc *sc = xsc; struct mii_data *mii; KR_LOCK_ASSERT(sc); mii = device_get_softc(sc->kr_miibus); mii_tick(mii); callout_reset(&sc->kr_stat_callout, hz, kr_tick, sc); } Index: head/sys/mips/idt/if_krreg.h =================================================================== --- head/sys/mips/idt/if_krreg.h (revision 326258) +++ head/sys/mips/idt/if_krreg.h (revision 326259) @@ -1,284 +1,286 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (C) 2007 * Oleksandr Tymoshenko . 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 ``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 HIS RELATIVES 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 MIND, 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$ * */ #ifndef __IF_KRREG_H__ #define __IF_KRREG_H__ #define KR_ETHINTFC 0x0000 /* Ethernet interface control */ #define ETH_INTFC_EN 0x0001 #define ETH_INTFC_RIP 0x0004 #define ETH_INTFC_EN 0x0001 #define KR_ETHFIFOTT 0x0004 /* Ethernet FIFO transmit threshold */ #define KR_ETHARC 0x0008 /* Ethernet address recognition control */ #define KR_ETHHASH0 0x000C /* Ethernet hash table 0 */ #define KR_ETHHASH1 0x0010 /* Ethernet hash table 1 */ #define KR_ETHPFS 0x0024 /* Ethernet pause frame status */ #define KR_ETHMCP 0x0028 /* Ethernet management clock prescalar */ #define KR_ETHSAL0 0x0100 /* Ethernet station address 0 low */ #define KR_ETHSAH0 0x0104 /* Ethernet station address 0 high */ #define KR_ETHSAL1 0x0108 /* Ethernet station address 1 low */ #define KR_ETHSAH1 0x010C /* Ethernet station address 1 high */ #define KR_ETHSAL2 0x0110 /* Ethernet station address 2 low */ #define KR_ETHSAH2 0x0114 /* Ethernet station address 2 high */ #define KR_ETHSAL3 0x0118 /* Ethernet station address 3 low */ #define KR_ETHSAH3 0x011C /* Ethernet station address 3 high */ #define KR_ETHRBC 0x0120 /* Ethernet receive byte count */ #define KR_ETHRPC 0x0124 /* Ethernet receive packet count */ #define KR_ETHRUPC 0x0128 /* Ethernet receive undersized packet cnt */ #define KR_ETHRFC 0x012C /* Ethernet receive fragment count */ #define KR_ETHTBC 0x0130 /* Ethernet transmit byte count */ #define KR_ETHGPF 0x0134 /* Ethernet generate pause frame */ #define KR_ETHMAC1 0x0200 /* Ethernet MAC configuration 1 */ #define KR_ETH_MAC1_RE 0x01 #define KR_ETH_MAC1_PAF 0x02 #define KR_ETH_MAC1_MR 0x80 #define KR_ETHMAC2 0x0204 /* Ethernet MAC configuration 2 */ #define KR_ETH_MAC2_FD 0x01 #define KR_ETH_MAC2_FLC 0x02 #define KR_ETH_MAC2_HFE 0x04 #define KR_ETH_MAC2_DC 0x08 #define KR_ETH_MAC2_CEN 0x10 #define KR_ETH_MAC2_PEN 0x20 #define KR_ETH_MAC2_VPE 0x08 #define KR_ETHIPGT 0x0208 /* Ethernet back-to-back inter-packet gap */ #define KR_ETHIPGR 0x020C /* Ethernet non back-to-back inter-packet gap */ #define KR_ETHCLRT 0x0210 /* Ethernet collision window retry */ #define KR_ETHMAXF 0x0214 /* Ethernet maximum frame length */ #define KR_ETHMTEST 0x021C /* Ethernet MAC test */ #define KR_MIIMCFG 0x0220 /* MII management configuration */ #define KR_MIIMCFG_R 0x8000 #define KR_MIIMCMD 0x0224 /* MII management command */ #define KR_MIIMCMD_RD 0x01 #define KR_MIIMCMD_SCN 0x02 #define KR_MIIMADDR 0x0228 /* MII management address */ #define KR_MIIMWTD 0x022C /* MII management write data */ #define KR_MIIMRDD 0x0230 /* MII management read data */ #define KR_MIIMIND 0x0234 /* MII management indicators */ #define KR_MIIMIND_BSY 0x1 #define KR_MIIMIND_SCN 0x2 #define KR_MIIMIND_NV 0x4 #define KR_ETHCFSA0 0x0240 /* Ethernet control frame station address 0 */ #define KR_ETHCFSA1 0x0244 /* Ethernet control frame station address 1 */ #define KR_ETHCFSA2 0x0248 /* Ethernet control frame station address 2 */ #define KR_ETHIPGT_HALF_DUPLEX 0x12 #define KR_ETHIPGT_FULL_DUPLEX 0x15 #define KR_TIMEOUT 0xf000 #define KR_MII_TIMEOUT 0xf000 #define KR_RX_IRQ 40 #define KR_TX_IRQ 41 #define KR_RX_UND_IRQ 42 #define KR_TX_OVR_IRQ 43 #define RC32434_DMA_BASE_ADDR MIPS_PHYS_TO_KSEG1(0x18040000) #define DMA_C 0x00 #define DMA_C_R 0x01 #define DMA_C_ABORT 0x10 #define DMA_S 0x04 #define DMA_S_F 0x01 #define DMA_S_D 0x02 #define DMA_S_C 0x04 #define DMA_S_E 0x08 #define DMA_S_H 0x10 #define DMA_SM 0x08 #define DMA_SM_F 0x01 #define DMA_SM_D 0x02 #define DMA_SM_C 0x04 #define DMA_SM_E 0x08 #define DMA_SM_H 0x10 #define DMA_DPTR 0x0C #define DMA_NDPTR 0x10 #define RC32434_DMA_CHAN_SIZE 0x14 #define KR_DMA_RXCHAN 0 #define KR_DMA_TXCHAN 1 #define KR_DMA_READ_REG(chan, reg) \ (*(volatile uint32_t *) \ (RC32434_DMA_BASE_ADDR + chan * RC32434_DMA_CHAN_SIZE + reg)) #define KR_DMA_WRITE_REG(chan, reg, val) \ ((*(volatile uint32_t *) \ (RC32434_DMA_BASE_ADDR + chan * RC32434_DMA_CHAN_SIZE + reg)) = val) #define KR_DMA_SETBITS_REG(chan, reg, bits) \ KR_DMA_WRITE_REG((chan), (reg), KR_DMA_READ_REG((chan), (reg)) | (bits)) #define KR_DMA_CLEARBITS_REG(chan, reg, bits) \ KR_DMA_WRITE_REG((chan), (reg), \ KR_DMA_READ_REG((chan), (reg)) & ~(bits)) struct kr_desc { uint32_t kr_ctl; uint32_t kr_ca; uint32_t kr_devcs; uint32_t kr_link; }; #define KR_DMASIZE(len) ((len) & ((1 << 18)-1)) #define KR_PKTSIZE(len) ((len & 0xffff0000) >> 16) #define KR_CTL_COF 0x02000000 #define KR_CTL_COD 0x04000000 #define KR_CTL_IOF 0x08000000 #define KR_CTL_IOD 0x10000000 #define KR_CTL_T 0x20000000 #define KR_CTL_D 0x40000000 #define KR_CTL_F 0x80000000 #define KR_DMARX_DEVCS_RSV 0x00000001 #define KR_DMARX_DEVCS_LD 0x00000002 #define KR_DMARX_DEVCS_ROK 0x00000004 #define KR_DMARX_DEVCS_FM 0x00000008 #define KR_DMARX_DEVCS_MP 0x00000010 #define KR_DMARX_DEVCS_BP 0x00000020 #define KR_DMARX_DEVCS_VLT 0x00000040 #define KR_DMARX_DEVCS_CF 0x00000080 #define KR_DMARX_DEVCS_OVR 0x00000100 #define KR_DMARX_DEVCS_CRC 0x00000200 #define KR_DMARX_DEVCS_CV 0x00000400 #define KR_DMARX_DEVCS_DB 0x00000800 #define KR_DMARX_DEVCS_LE 0x00001000 #define KR_DMARX_DEVCS_LOR 0x00002000 #define KR_DMARX_DEVCS_CES 0x00004000 #define KR_DMATX_DEVCS_FD 0x00000001 #define KR_DMATX_DEVCS_LD 0x00000002 #define KR_DMATX_DEVCS_OEN 0x00000004 #define KR_DMATX_DEVCS_PEN 0x00000008 #define KR_DMATX_DEVCS_CEN 0x00000010 #define KR_DMATX_DEVCS_HEN 0x00000020 #define KR_DMATX_DEVCS_TOK 0x00000040 #define KR_DMATX_DEVCS_MP 0x00000080 #define KR_DMATX_DEVCS_BP 0x00000100 #define KR_DMATX_DEVCS_UND 0x00000200 #define KR_DMATX_DEVCS_OF 0x00000400 #define KR_DMATX_DEVCS_ED 0x00000800 #define KR_DMATX_DEVCS_EC 0x00001000 #define KR_DMATX_DEVCS_LC 0x00002000 #define KR_DMATX_DEVCS_TD 0x00004000 #define KR_DMATX_DEVCS_CRC 0x00008000 #define KR_DMATX_DEVCS_LE 0x00010000 #define KR_RX_RING_CNT 128 #define KR_TX_RING_CNT 128 #define KR_TX_RING_SIZE sizeof(struct kr_desc) * KR_TX_RING_CNT #define KR_RX_RING_SIZE sizeof(struct kr_desc) * KR_RX_RING_CNT #define KR_RING_ALIGN sizeof(struct kr_desc) #define KR_RX_ALIGN sizeof(uint32_t) #define KR_MAXFRAGS 8 #define KR_TX_INTR_THRESH 8 #define KR_TX_RING_ADDR(sc, i) \ ((sc)->kr_rdata.kr_tx_ring_paddr + sizeof(struct kr_desc) * (i)) #define KR_RX_RING_ADDR(sc, i) \ ((sc)->kr_rdata.kr_rx_ring_paddr + sizeof(struct kr_desc) * (i)) #define KR_INC(x,y) (x) = (((x) + 1) % y) struct kr_txdesc { struct mbuf *tx_m; bus_dmamap_t tx_dmamap; }; struct kr_rxdesc { struct mbuf *rx_m; bus_dmamap_t rx_dmamap; struct kr_desc *desc; /* Use this values on error instead of allocating new mbuf */ uint32_t saved_ctl, saved_ca; }; struct kr_chain_data { bus_dma_tag_t kr_parent_tag; bus_dma_tag_t kr_tx_tag; struct kr_txdesc kr_txdesc[KR_TX_RING_CNT]; bus_dma_tag_t kr_rx_tag; struct kr_rxdesc kr_rxdesc[KR_RX_RING_CNT]; bus_dma_tag_t kr_tx_ring_tag; bus_dma_tag_t kr_rx_ring_tag; bus_dmamap_t kr_tx_ring_map; bus_dmamap_t kr_rx_ring_map; bus_dmamap_t kr_rx_sparemap; int kr_tx_pkts; int kr_tx_prod; int kr_tx_cons; int kr_tx_cnt; int kr_rx_cons; }; struct kr_ring_data { struct kr_desc *kr_rx_ring; struct kr_desc *kr_tx_ring; bus_addr_t kr_rx_ring_paddr; bus_addr_t kr_tx_ring_paddr; }; struct kr_softc { struct ifnet *kr_ifp; /* interface info */ bus_space_handle_t kr_bhandle; /* bus space handle */ bus_space_tag_t kr_btag; /* bus space tag */ device_t kr_dev; struct resource *kr_res; int kr_rid; struct resource *kr_rx_irq; void *kr_rx_intrhand; struct resource *kr_tx_irq; void *kr_tx_intrhand; struct resource *kr_rx_und_irq; void *kr_rx_und_intrhand; struct resource *kr_tx_ovr_irq; void *kr_tx_ovr_intrhand; device_t kr_miibus; bus_dma_tag_t kr_parent_tag; bus_dma_tag_t kr_tag; struct mtx kr_mtx; struct callout kr_stat_callout; struct task kr_link_task; struct kr_chain_data kr_cdata; struct kr_ring_data kr_rdata; int kr_link_status; int kr_detach; }; #define KR_LOCK(_sc) mtx_lock(&(_sc)->kr_mtx) #define KR_UNLOCK(_sc) mtx_unlock(&(_sc)->kr_mtx) #define KR_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->kr_mtx, MA_OWNED) /* * register space access macros */ #define CSR_WRITE_4(sc, reg, val) \ bus_space_write_4(sc->kr_btag, sc->kr_bhandle, reg, val) #define CSR_READ_4(sc, reg) \ bus_space_read_4(sc->kr_btag, sc->kr_bhandle, reg) #endif /* __IF_KRREG_H__ */ Index: head/sys/mips/idt/obio.c =================================================================== --- head/sys/mips/idt/obio.c (revision 326258) +++ head/sys/mips/idt/obio.c (revision 326259) @@ -1,482 +1,484 @@ /*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright (c) 2007, Oleksandr Tymoshenko * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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 #define ICU_REG_READ(o) \ *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(IDT_BASE_ICU + (o))) #define ICU_REG_WRITE(o,v) (ICU_REG_READ(o)) = (v) #define GPIO_REG_READ(o) \ *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(IDT_BASE_GPIO + (o))) #define GPIO_REG_WRITE(o,v) (GPIO_REG_READ(o)) = (v) static int obio_activate_resource(device_t, device_t, int, int, struct resource *); static device_t obio_add_child(device_t, u_int, const char *, int); static struct resource * obio_alloc_resource(device_t, device_t, int, int *, rman_res_t, rman_res_t, rman_res_t, u_int); static int obio_attach(device_t); static int obio_deactivate_resource(device_t, device_t, int, int, struct resource *); static struct resource_list * obio_get_resource_list(device_t, device_t); static void obio_hinted_child(device_t, const char *, int); static int obio_intr(void *); static int obio_probe(device_t); static int obio_release_resource(device_t, device_t, int, int, struct resource *); static int obio_setup_intr(device_t, device_t, struct resource *, int, driver_filter_t *, driver_intr_t *, void *, void **); static int obio_teardown_intr(device_t, device_t, struct resource *, void *); static void obio_mask_irq(void *arg) { unsigned int irq = (unsigned int)arg; int ip_bit, mask, mask_register; /* mask IRQ */ mask_register = ICU_IRQ_MASK_REG(irq); ip_bit = ICU_IP_BIT(irq); mask = ICU_REG_READ(mask_register); ICU_REG_WRITE(mask_register, mask | ip_bit); } static void obio_unmask_irq(void *arg) { unsigned int irq = (unsigned int)arg; int ip_bit, mask, mask_register; /* unmask IRQ */ mask_register = ICU_IRQ_MASK_REG(irq); ip_bit = ICU_IP_BIT(irq); mask = ICU_REG_READ(mask_register); ICU_REG_WRITE(mask_register, mask & ~ip_bit); } static int obio_probe(device_t dev) { return (BUS_PROBE_NOWILDCARD); } static int obio_attach(device_t dev) { struct obio_softc *sc = device_get_softc(dev); int rid, irq; sc->oba_mem_rman.rm_type = RMAN_ARRAY; sc->oba_mem_rman.rm_descr = "OBIO memeory"; if (rman_init(&sc->oba_mem_rman) != 0 || rman_manage_region(&sc->oba_mem_rman, OBIO_MEM_START, OBIO_MEM_START + OBIO_MEM_SIZE) != 0) panic("obio_attach: failed to set up I/O rman"); sc->oba_irq_rman.rm_type = RMAN_ARRAY; sc->oba_irq_rman.rm_descr = "OBIO IRQ"; if (rman_init(&sc->oba_irq_rman) != 0 || rman_manage_region(&sc->oba_irq_rman, IRQ_BASE, IRQ_END) != 0) panic("obio_attach: failed to set up IRQ rman"); /* Hook up our interrupt handlers. We should handle IRQ0..IRQ4*/ for(irq = 0; irq < 5; irq++) { if ((sc->sc_irq[irq] = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq, irq, 1, RF_SHAREABLE | RF_ACTIVE)) == NULL) { device_printf(dev, "unable to allocate IRQ resource\n"); return (ENXIO); } if ((bus_setup_intr(dev, sc->sc_irq[irq], INTR_TYPE_MISC, obio_intr, NULL, sc, &sc->sc_ih[irq]))) { device_printf(dev, "WARNING: unable to register interrupt handler\n"); return (ENXIO); } } bus_generic_probe(dev); bus_enumerate_hinted_children(dev); bus_generic_attach(dev); return (0); } static struct resource * obio_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct obio_softc *sc = device_get_softc(bus); struct obio_ivar *ivar = device_get_ivars(child); struct resource *rv; struct resource_list_entry *rle; struct rman *rm; int isdefault, needactivate, passthrough; isdefault = (RMAN_IS_DEFAULT_RANGE(start, end)); needactivate = flags & RF_ACTIVE; passthrough = (device_get_parent(child) != bus); rle = NULL; if (passthrough) return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type, rid, start, end, count, flags)); /* * If this is an allocation of the "default" range for a given RID, * and we know what the resources for this device are (ie. they aren't * maintained by a child bus), then work out the start/end values. */ if (isdefault) { rle = resource_list_find(&ivar->resources, type, *rid); if (rle == NULL) return (NULL); if (rle->res != NULL) { panic("%s: resource entry is busy", __func__); } start = rle->start; end = rle->end; count = rle->count; } switch (type) { case SYS_RES_IRQ: rm = &sc->oba_irq_rman; break; case SYS_RES_MEMORY: rm = &sc->oba_mem_rman; break; default: printf("%s: unknown resource type %d\n", __func__, type); return (0); } rv = rman_reserve_resource(rm, start, end, count, flags, child); if (rv == NULL) { printf("%s: could not reserve resource\n", __func__); return (0); } rman_set_rid(rv, *rid); if (needactivate) { if (bus_activate_resource(child, type, *rid, rv)) { printf("%s: could not activate resource\n", __func__); rman_release_resource(rv); return (0); } } return (rv); } static int obio_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { /* XXX: should we mask/unmask IRQ here? */ return (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), child, type, rid, r)); } static int obio_deactivate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { /* XXX: should we mask/unmask IRQ here? */ return (BUS_DEACTIVATE_RESOURCE(device_get_parent(bus), child, type, rid, r)); } static int obio_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { struct resource_list *rl; struct resource_list_entry *rle; rl = obio_get_resource_list(dev, child); if (rl == NULL) return (EINVAL); rle = resource_list_find(rl, type, rid); if (rle == NULL) return (EINVAL); rman_release_resource(r); rle->res = NULL; return (0); } static int obio_setup_intr(device_t dev, device_t child, struct resource *ires, int flags, driver_filter_t *filt, driver_intr_t *handler, void *arg, void **cookiep) { struct obio_softc *sc = device_get_softc(dev); struct intr_event *event; int irq, ip_bit, error, mask, mask_register; irq = rman_get_start(ires); if (irq >= NIRQS) panic("%s: bad irq %d", __func__, irq); event = sc->sc_eventstab[irq]; if (event == NULL) { error = intr_event_create(&event, (void *)irq, 0, irq, obio_mask_irq, obio_unmask_irq, NULL, NULL, "obio intr%d:", irq); sc->sc_eventstab[irq] = event; } intr_event_add_handler(event, device_get_nameunit(child), filt, handler, arg, intr_priority(flags), flags, cookiep); /* unmask IRQ */ mask_register = ICU_IRQ_MASK_REG(irq); ip_bit = ICU_IP_BIT(irq); mask = ICU_REG_READ(mask_register); ICU_REG_WRITE(mask_register, mask & ~ip_bit); return (0); } static int obio_teardown_intr(device_t dev, device_t child, struct resource *ires, void *cookie) { struct obio_softc *sc = device_get_softc(dev); int irq, result; uint32_t mask_register, mask, ip_bit; irq = rman_get_start(ires); if (irq >= NIRQS) panic("%s: bad irq %d", __func__, irq); if (sc->sc_eventstab[irq] == NULL) panic("Trying to teardown unoccupied IRQ"); /* mask IRQ */ mask_register = ICU_IRQ_MASK_REG(irq); ip_bit = ICU_IP_BIT(irq); mask = ICU_REG_READ(mask_register); ICU_REG_WRITE(mask_register, mask | ip_bit); result = intr_event_remove_handler(cookie); if (!result) sc->sc_eventstab[irq] = NULL; return (result); } static int obio_intr(void *arg) { struct obio_softc *sc = arg; struct intr_event *event; uint32_t irqstat, ipend, imask, xpend; int irq, thread, group, i; irqstat = 0; irq = 0; for (group = 2; group <= 6; group++) { ipend = ICU_REG_READ(ICU_GROUP_IPEND_REG(group)); imask = ICU_REG_READ(ICU_GROUP_MASK_REG(group)); xpend = ipend; ipend &= ~imask; while ((i = fls(xpend)) != 0) { xpend &= ~(1 << (i - 1)); irq = IP_IRQ(group, i - 1); } while ((i = fls(ipend)) != 0) { ipend &= ~(1 << (i - 1)); irq = IP_IRQ(group, i - 1); event = sc->sc_eventstab[irq]; thread = 0; if (!event || TAILQ_EMPTY(&event->ie_handlers)) { /* TODO: Log stray IRQs */ continue; } /* TODO: frame instead of NULL? */ intr_event_handle(event, NULL); /* XXX: Log stray IRQs */ } } #if 0 ipend = ICU_REG_READ(ICU_IPEND2); printf("ipend2 = %08x!\n", ipend); ipend = ICU_REG_READ(ICU_IPEND3); printf("ipend3 = %08x!\n", ipend); ipend = ICU_REG_READ(ICU_IPEND4); printf("ipend4 = %08x!\n", ipend); ipend = ICU_REG_READ(ICU_IPEND5); printf("ipend5 = %08x!\n", ipend); ipend = ICU_REG_READ(ICU_IPEND6); printf("ipend6 = %08x!\n", ipend); #endif while (irqstat != 0) { if ((irqstat & 1) == 1) { } irq++; irqstat >>= 1; } return (FILTER_HANDLED); } static void obio_hinted_child(device_t bus, const char *dname, int dunit) { device_t child; long maddr; int msize; int irq; int result; child = BUS_ADD_CHILD(bus, 0, dname, dunit); /* * Set hard-wired resources for hinted child using * specific RIDs. */ resource_long_value(dname, dunit, "maddr", &maddr); resource_int_value(dname, dunit, "msize", &msize); result = bus_set_resource(child, SYS_RES_MEMORY, 0, maddr, msize); if (result != 0) device_printf(bus, "warning: bus_set_resource() failed\n"); if (resource_int_value(dname, dunit, "irq", &irq) == 0) { result = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1); if (result != 0) device_printf(bus, "warning: bus_set_resource() failed\n"); } } static device_t obio_add_child(device_t bus, u_int order, const char *name, int unit) { device_t child; struct obio_ivar *ivar; ivar = malloc(sizeof(struct obio_ivar), M_DEVBUF, M_WAITOK | M_ZERO); resource_list_init(&ivar->resources); child = device_add_child_ordered(bus, order, name, unit); if (child == NULL) { printf("Can't add child %s%d ordered\n", name, unit); return (0); } device_set_ivars(child, ivar); return (child); } /* * Helper routine for bus_generic_rl_get_resource/bus_generic_rl_set_resource * Provides pointer to resource_list for these routines */ static struct resource_list * obio_get_resource_list(device_t dev, device_t child) { struct obio_ivar *ivar; ivar = device_get_ivars(child); return (&(ivar->resources)); } static device_method_t obio_methods[] = { DEVMETHOD(bus_activate_resource, obio_activate_resource), DEVMETHOD(bus_add_child, obio_add_child), DEVMETHOD(bus_alloc_resource, obio_alloc_resource), DEVMETHOD(bus_deactivate_resource, obio_deactivate_resource), DEVMETHOD(bus_get_resource_list, obio_get_resource_list), DEVMETHOD(bus_hinted_child, obio_hinted_child), DEVMETHOD(bus_release_resource, obio_release_resource), DEVMETHOD(bus_setup_intr, obio_setup_intr), DEVMETHOD(bus_teardown_intr, obio_teardown_intr), DEVMETHOD(device_attach, obio_attach), DEVMETHOD(device_probe, obio_probe), DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), {0, 0}, }; static driver_t obio_driver = { "obio", obio_methods, sizeof(struct obio_softc), }; static devclass_t obio_devclass; DRIVER_MODULE(obio, nexus, obio_driver, obio_devclass, 0, 0); Index: head/sys/mips/idt/obiovar.h =================================================================== --- head/sys/mips/idt/obiovar.h (revision 326258) +++ head/sys/mips/idt/obiovar.h (revision 326259) @@ -1,67 +1,69 @@ /* $NetBSD: obiovar.h,v 1.4 2003/06/16 17:40:53 thorpej Exp $ */ /*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright (c) 2002, 2003 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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$ * */ #ifndef _ADM5120_OBIOVAR_H_ #define _ADM5120_OBIOVAR_H_ #include /* Number of controller's IRQs */ #define NIRQS 32*5 /* Number of CPU IRQ lines */ #define MIPS_IRQS 5 #define OBIO_MEM_START 0x18000000L #define OBIO_MEM_SIZE 0x200000 struct obio_softc { struct rman oba_mem_rman; struct rman oba_irq_rman; struct intr_event *sc_eventstab[NIRQS]; /* IRQ events structs */ struct resource *sc_irq[MIPS_IRQS]; /* IRQ resource */ void *sc_ih[MIPS_IRQS]; /* interrupt cookie */ }; struct obio_ivar { struct resource_list resources; }; #endif /* _ADM5120_OBIOVAR_H_ */ Index: head/sys/mips/idt/uart_bus_rc32434.c =================================================================== --- head/sys/mips/idt/uart_bus_rc32434.c (revision 326258) +++ head/sys/mips/idt/uart_bus_rc32434.c (revision 326259) @@ -1,100 +1,102 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2007 Bruce M. Simpson. * 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 * $Id$ */ /* * Skeleton of this file was based on respective code for ARM * code written by Olivier Houchard. */ /* * XXXMIPS: This file is hacked from arm/... . XXXMIPS here means this file is * experimental and was written for MIPS32 port. */ #include "opt_uart.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "uart_if.h" static int uart_rc32434_probe(device_t dev); extern struct uart_class uart_rc32434_uart_class; static device_method_t uart_rc32434_methods[] = { /* Device interface */ DEVMETHOD(device_probe, uart_rc32434_probe), DEVMETHOD(device_attach, uart_bus_attach), DEVMETHOD(device_detach, uart_bus_detach), { 0, 0 } }; static driver_t uart_rc32434_driver = { uart_driver_name, uart_rc32434_methods, sizeof(struct uart_softc), }; extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs; static int uart_rc32434_probe(device_t dev) { struct uart_softc *sc; sc = device_get_softc(dev); sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs); sc->sc_class = &uart_ns8250_class; bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas)); sc->sc_sysdev->bas.regshft = 2; sc->sc_sysdev->bas.bst = mips_bus_space_generic; sc->sc_sysdev->bas.bsh = MIPS_PHYS_TO_KSEG1(IDT_BASE_UART0); sc->sc_bas.regshft = 2; sc->sc_bas.bst = mips_bus_space_generic; sc->sc_bas.bsh = MIPS_PHYS_TO_KSEG1(IDT_BASE_UART0); return (uart_bus_probe(dev, 2, 0, 330000000UL/2, 0, 0)); } DRIVER_MODULE(uart, obio, uart_rc32434_driver, uart_devclass, 0, 0); Index: head/sys/mips/idt/uart_cpu_rc32434.c =================================================================== --- head/sys/mips/idt/uart_cpu_rc32434.c (revision 326258) +++ head/sys/mips/idt/uart_cpu_rc32434.c (revision 326259) @@ -1,85 +1,87 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006 Wojciech A. Koszek * 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. * * $Id$ */ /* * Skeleton of this file was based on respective code for ARM * code written by Olivier Houchard. */ /* * XXXMIPS: This file is hacked from arm/... . XXXMIPS here means this file is * experimental and was written for MIPS32 port. */ #include "opt_uart.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include extern struct uart_class uart_rc32434_uart_class; bus_space_tag_t uart_bus_space_io; bus_space_tag_t uart_bus_space_mem; int uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) { return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0); } int uart_cpu_getdev(int devtype, struct uart_devinfo *di) { uint32_t maddr; if (resource_int_value("uart", 0, "maddr", &maddr) != 0 || maddr == 0) return (ENXIO); /* Got it. Fill in the instance and return it. */ di->ops = uart_getops(&uart_ns8250_class); di->bas.chan = 0; di->bas.bst = mips_bus_space_generic; di->bas.regshft = 2; di->bas.rclk = 330000000UL/2; /* IPbus clock */ di->baudrate = 115200; di->databits = 8; di->stopbits = 1; di->parity = UART_PARITY_NONE; uart_bus_space_io = 0; uart_bus_space_mem = mips_bus_space_generic; di->bas.bsh = MIPS_PHYS_TO_KSEG1(maddr); return (0); } Index: head/sys/mips/include/_bus.h =================================================================== --- head/sys/mips/include/_bus.h (revision 326258) +++ head/sys/mips/include/_bus.h (revision 326259) @@ -1,50 +1,52 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2005 M. Warner Losh. * 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, * without modification, immediately at the beginning of the file. * 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. * * from: src/sys/i386/include/_bus.h,v 1.1 2005/04/18 21:45:33 imp * $FreeBSD$ */ #ifndef MIPS_INCLUDE__BUS_H #define MIPS_INCLUDE__BUS_H /* * Bus address and size types */ #if defined(CPU_CNMIPS) && !defined(__mips_n64) typedef uint64_t bus_addr_t; #else typedef uintptr_t bus_addr_t; #endif typedef uintptr_t bus_size_t; /* * Access methods for bus resources and address space. */ typedef struct bus_space *bus_space_tag_t; typedef bus_addr_t bus_space_handle_t; #endif /* MIPS_INCLUDE__BUS_H */ Index: head/sys/mips/include/_inttypes.h =================================================================== --- head/sys/mips/include/_inttypes.h (revision 326258) +++ head/sys/mips/include/_inttypes.h (revision 326259) @@ -1,222 +1,224 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-NetBSD + * * Copyright (c) 2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Klaus Klein. * * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. * * From: $NetBSD: int_fmtio.h,v 1.2 2001/04/26 16:25:21 kleink Exp $ * from: src/sys/i386/include/_inttypes.h,v 1.2 2002/06/30 05:48:02 mike * $FreeBSD$ */ #ifndef _MACHINE_INTTYPES_H_ #define _MACHINE_INTTYPES_H_ /* * Macros for format specifiers. */ #ifdef __mips_n64 #define __PRI64 "l" #define __PRIptr "l" #else #define __PRI64 "ll" #define __PRIptr #endif /* fprintf(3) macros for signed integers. */ #define PRId8 "d" /* int8_t */ #define PRId16 "d" /* int16_t */ #define PRId32 "d" /* int32_t */ #define PRId64 __PRI64"d" /* int64_t */ #define PRIdLEAST8 "d" /* int_least8_t */ #define PRIdLEAST16 "d" /* int_least16_t */ #define PRIdLEAST32 "d" /* int_least32_t */ #define PRIdLEAST64 __PRI64"d" /* int_least64_t */ #define PRIdFAST8 "d" /* int_fast8_t */ #define PRIdFAST16 "d" /* int_fast16_t */ #define PRIdFAST32 "d" /* int_fast32_t */ #define PRIdFAST64 __PRI64"d" /* int_fast64_t */ #define PRIdMAX "jd" /* intmax_t */ #define PRIdPTR __PRIptr"d" /* intptr_t */ #define PRIi8 "i" /* int8_t */ #define PRIi16 "i" /* int16_t */ #define PRIi32 "i" /* int32_t */ #define PRIi64 __PRI64"i" /* int64_t */ #define PRIiLEAST8 "i" /* int_least8_t */ #define PRIiLEAST16 "i" /* int_least16_t */ #define PRIiLEAST32 "i" /* int_least32_t */ #define PRIiLEAST64 __PRI64"i" /* int_least64_t */ #define PRIiFAST8 "i" /* int_fast8_t */ #define PRIiFAST16 "i" /* int_fast16_t */ #define PRIiFAST32 "i" /* int_fast32_t */ #define PRIiFAST64 __PRI64"i" /* int_fast64_t */ #define PRIiMAX "ji" /* intmax_t */ #define PRIiPTR __PRIptr"i" /* intptr_t */ /* fprintf(3) macros for unsigned integers. */ #define PRIo8 "o" /* uint8_t */ #define PRIo16 "o" /* uint16_t */ #define PRIo32 "o" /* uint32_t */ #define PRIo64 __PRI64"o" /* uint64_t */ #define PRIoLEAST8 "o" /* uint_least8_t */ #define PRIoLEAST16 "o" /* uint_least16_t */ #define PRIoLEAST32 "o" /* uint_least32_t */ #define PRIoLEAST64 __PRI64"o" /* uint_least64_t */ #define PRIoFAST8 "o" /* uint_fast8_t */ #define PRIoFAST16 "o" /* uint_fast16_t */ #define PRIoFAST32 "o" /* uint_fast32_t */ #define PRIoFAST64 __PRI64"o" /* uint_fast64_t */ #define PRIoMAX "jo" /* uintmax_t */ #define PRIoPTR __PRIptr"o" /* uintptr_t */ #define PRIu8 "u" /* uint8_t */ #define PRIu16 "u" /* uint16_t */ #define PRIu32 "u" /* uint32_t */ #define PRIu64 __PRI64"u" /* uint64_t */ #define PRIuLEAST8 "u" /* uint_least8_t */ #define PRIuLEAST16 "u" /* uint_least16_t */ #define PRIuLEAST32 "u" /* uint_least32_t */ #define PRIuLEAST64 __PRI64"u" /* uint_least64_t */ #define PRIuFAST8 "u" /* uint_fast8_t */ #define PRIuFAST16 "u" /* uint_fast16_t */ #define PRIuFAST32 "u" /* uint_fast32_t */ #define PRIuFAST64 __PRI64"u" /* uint_fast64_t */ #define PRIuMAX "ju" /* uintmax_t */ #define PRIuPTR __PRIptr"u" /* uintptr_t */ #define PRIx8 "x" /* uint8_t */ #define PRIx16 "x" /* uint16_t */ #define PRIx32 "x" /* uint32_t */ #define PRIx64 __PRI64"x" /* uint64_t */ #define PRIxLEAST8 "x" /* uint_least8_t */ #define PRIxLEAST16 "x" /* uint_least16_t */ #define PRIxLEAST32 "x" /* uint_least32_t */ #define PRIxLEAST64 __PRI64"x" /* uint_least64_t */ #define PRIxFAST8 "x" /* uint_fast8_t */ #define PRIxFAST16 "x" /* uint_fast16_t */ #define PRIxFAST32 "x" /* uint_fast32_t */ #define PRIxFAST64 __PRI64"x" /* uint_fast64_t */ #define PRIxMAX "jx" /* uintmax_t */ #define PRIxPTR __PRIptr"x" /* uintptr_t */ #define PRIX8 "X" /* uint8_t */ #define PRIX16 "X" /* uint16_t */ #define PRIX32 "X" /* uint32_t */ #define PRIX64 __PRI64"X" /* uint64_t */ #define PRIXLEAST8 "X" /* uint_least8_t */ #define PRIXLEAST16 "X" /* uint_least16_t */ #define PRIXLEAST32 "X" /* uint_least32_t */ #define PRIXLEAST64 __PRI64"X" /* uint_least64_t */ #define PRIXFAST8 "X" /* uint_fast8_t */ #define PRIXFAST16 "X" /* uint_fast16_t */ #define PRIXFAST32 "X" /* uint_fast32_t */ #define PRIXFAST64 __PRI64"X" /* uint_fast64_t */ #define PRIXMAX "jX" /* uintmax_t */ #define PRIXPTR __PRIptr"X" /* uintptr_t */ /* fscanf(3) macros for signed integers. */ #define SCNd8 "hhd" /* int8_t */ #define SCNd16 "hd" /* int16_t */ #define SCNd32 "d" /* int32_t */ #define SCNd64 __PRI64"d" /* int64_t */ #define SCNdLEAST8 "hhd" /* int_least8_t */ #define SCNdLEAST16 "hd" /* int_least16_t */ #define SCNdLEAST32 "d" /* int_least32_t */ #define SCNdLEAST64 __PRI64"d" /* int_least64_t */ #define SCNdFAST8 "d" /* int_fast8_t */ #define SCNdFAST16 "d" /* int_fast16_t */ #define SCNdFAST32 "d" /* int_fast32_t */ #define SCNdFAST64 __PRI64"d" /* int_fast64_t */ #define SCNdMAX "jd" /* intmax_t */ #define SCNdPTR __PRIptr"d" /* intptr_t */ #define SCNi8 "hhi" /* int8_t */ #define SCNi16 "hi" /* int16_t */ #define SCNi32 "i" /* int32_t */ #define SCNi64 __PRI64"i" /* int64_t */ #define SCNiLEAST8 "hhi" /* int_least8_t */ #define SCNiLEAST16 "hi" /* int_least16_t */ #define SCNiLEAST32 "i" /* int_least32_t */ #define SCNiLEAST64 __PRI64"i" /* int_least64_t */ #define SCNiFAST8 "i" /* int_fast8_t */ #define SCNiFAST16 "i" /* int_fast16_t */ #define SCNiFAST32 "i" /* int_fast32_t */ #define SCNiFAST64 __PRI64"i" /* int_fast64_t */ #define SCNiMAX "ji" /* intmax_t */ #define SCNiPTR __PRIptr"i" /* intptr_t */ /* fscanf(3) macros for unsigned integers. */ #define SCNo8 "hho" /* uint8_t */ #define SCNo16 "ho" /* uint16_t */ #define SCNo32 "o" /* uint32_t */ #define SCNo64 __PRI64"o" /* uint64_t */ #define SCNoLEAST8 "hho" /* uint_least8_t */ #define SCNoLEAST16 "ho" /* uint_least16_t */ #define SCNoLEAST32 "o" /* uint_least32_t */ #define SCNoLEAST64 __PRI64"o" /* uint_least64_t */ #define SCNoFAST8 "o" /* uint_fast8_t */ #define SCNoFAST16 "o" /* uint_fast16_t */ #define SCNoFAST32 "o" /* uint_fast32_t */ #define SCNoFAST64 __PRI64"o" /* uint_fast64_t */ #define SCNoMAX "jo" /* uintmax_t */ #define SCNoPTR __PRIptr"o" /* uintptr_t */ #define SCNu8 "hhu" /* uint8_t */ #define SCNu16 "hu" /* uint16_t */ #define SCNu32 "u" /* uint32_t */ #define SCNu64 __PRI64"u" /* uint64_t */ #define SCNuLEAST8 "hhu" /* uint_least8_t */ #define SCNuLEAST16 "hu" /* uint_least16_t */ #define SCNuLEAST32 "u" /* uint_least32_t */ #define SCNuLEAST64 __PRI64"u" /* uint_least64_t */ #define SCNuFAST8 "u" /* uint_fast8_t */ #define SCNuFAST16 "u" /* uint_fast16_t */ #define SCNuFAST32 "u" /* uint_fast32_t */ #define SCNuFAST64 __PRI64"u" /* uint_fast64_t */ #define SCNuMAX "ju" /* uintmax_t */ #define SCNuPTR __PRIptr"u" /* uintptr_t */ #define SCNx8 "hhx" /* uint8_t */ #define SCNx16 "hx" /* uint16_t */ #define SCNx32 "x" /* uint32_t */ #define SCNx64 __PRI64"x" /* uint64_t */ #define SCNxLEAST8 "hhx" /* uint_least8_t */ #define SCNxLEAST16 "hx" /* uint_least16_t */ #define SCNxLEAST32 "x" /* uint_least32_t */ #define SCNxLEAST64 __PRI64"x" /* uint_least64_t */ #define SCNxFAST8 "x" /* uint_fast8_t */ #define SCNxFAST16 "x" /* uint_fast16_t */ #define SCNxFAST32 "x" /* uint_fast32_t */ #define SCNxFAST64 __PRI64"x" /* uint_fast64_t */ #define SCNxMAX "jx" /* uintmax_t */ #define SCNxPTR __PRIptr"x" /* uintptr_t */ #endif /* !_MACHINE_INTTYPES_H_ */ Index: head/sys/mips/include/_stdint.h =================================================================== --- head/sys/mips/include/_stdint.h (revision 326258) +++ head/sys/mips/include/_stdint.h (revision 326259) @@ -1,197 +1,199 @@ /*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright (c) 2001, 2002 Mike Barcroft * Copyright (c) 2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Klaus Klein. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. * * from: src/sys/i386/include/_stdint.h,v 1.2 2004/05/18 16:04:57 stefanf * $FreeBSD$ */ #ifndef _MACHINE__STDINT_H_ #define _MACHINE__STDINT_H_ #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) #define INT8_C(c) (c) #define INT16_C(c) (c) #define INT32_C(c) (c) #define UINT8_C(c) (c) #define UINT16_C(c) (c) #define UINT32_C(c) (c ## U) #ifdef __mips_n64 #define INT64_C(c) (c ## L) #define UINT64_C(c) (c ## UL) #else #define INT64_C(c) (c ## LL) #define UINT64_C(c) (c ## ULL) #endif #define INTMAX_C(c) INT64_C(c) #define UINTMAX_C(c) UINT64_C(c) #endif /* !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) */ #if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) #ifndef __INT64_C #ifdef __mips_n64 #define __INT64_C(c) (c ## L) #define __UINT64_C(c) (c ## UL) #else #define __INT64_C(c) (c ## LL) #define __UINT64_C(c) (c ## ULL) #endif #endif /* * ISO/IEC 9899:1999 * 7.18.2.1 Limits of exact-width integer types */ /* Minimum values of exact-width signed integer types. */ #define INT8_MIN (-0x7f-1) #define INT16_MIN (-0x7fff-1) #define INT32_MIN (-0x7fffffff-1) #define INT64_MIN (-__INT64_C(0x7fffffffffffffff)-1) /* Maximum values of exact-width signed integer types. */ #define INT8_MAX 0x7f #define INT16_MAX 0x7fff #define INT32_MAX 0x7fffffff #define INT64_MAX __INT64_C(0x7fffffffffffffff) /* Maximum values of exact-width unsigned integer types. */ #define UINT8_MAX 0xff #define UINT16_MAX 0xffff #define UINT32_MAX 0xffffffff #define UINT64_MAX __UINT64_C(0xffffffffffffffff) /* * ISO/IEC 9899:1999 * 7.18.2.2 Limits of minimum-width integer types */ /* Minimum values of minimum-width signed integer types. */ #define INT_LEAST8_MIN INT8_MIN #define INT_LEAST16_MIN INT16_MIN #define INT_LEAST32_MIN INT32_MIN #define INT_LEAST64_MIN INT64_MIN /* Maximum values of minimum-width signed integer types. */ #define INT_LEAST8_MAX INT8_MAX #define INT_LEAST16_MAX INT16_MAX #define INT_LEAST32_MAX INT32_MAX #define INT_LEAST64_MAX INT64_MAX /* Maximum values of minimum-width unsigned integer types. */ #define UINT_LEAST8_MAX UINT8_MAX #define UINT_LEAST16_MAX UINT16_MAX #define UINT_LEAST32_MAX UINT32_MAX #define UINT_LEAST64_MAX UINT64_MAX /* * ISO/IEC 9899:1999 * 7.18.2.3 Limits of fastest minimum-width integer types */ /* Minimum values of fastest minimum-width signed integer types. */ #define INT_FAST8_MIN INT32_MIN #define INT_FAST16_MIN INT32_MIN #define INT_FAST32_MIN INT32_MIN #define INT_FAST64_MIN INT64_MIN /* Maximum values of fastest minimum-width signed integer types. */ #define INT_FAST8_MAX INT32_MAX #define INT_FAST16_MAX INT32_MAX #define INT_FAST32_MAX INT32_MAX #define INT_FAST64_MAX INT64_MAX /* Maximum values of fastest minimum-width unsigned integer types. */ #define UINT_FAST8_MAX UINT32_MAX #define UINT_FAST16_MAX UINT32_MAX #define UINT_FAST32_MAX UINT32_MAX #define UINT_FAST64_MAX UINT64_MAX /* * ISO/IEC 9899:1999 * 7.18.2.4 Limits of integer types capable of holding object pointers */ #ifdef __mips_n64 #define INTPTR_MIN INT64_MIN #define INTPTR_MAX INT64_MAX #define UINTPTR_MAX UINT64_MAX #else #define INTPTR_MIN INT32_MIN #define INTPTR_MAX INT32_MAX #define UINTPTR_MAX UINT32_MAX #endif /* * ISO/IEC 9899:1999 * 7.18.2.5 Limits of greatest-width integer types */ #define INTMAX_MIN INT64_MIN #define INTMAX_MAX INT64_MAX #define UINTMAX_MAX UINT64_MAX /* * ISO/IEC 9899:1999 * 7.18.3 Limits of other integer types */ #ifdef __mips_n64 /* Limits of ptrdiff_t. */ #define PTRDIFF_MIN INT64_MIN #define PTRDIFF_MAX INT64_MAX /* Limit of size_t. */ #define SIZE_MAX UINT64_MAX #else /* Limits of ptrdiff_t. */ #define PTRDIFF_MIN INT32_MIN #define PTRDIFF_MAX INT32_MAX /* Limit of size_t. */ #define SIZE_MAX UINT32_MAX #endif /* Limits of sig_atomic_t. */ #define SIG_ATOMIC_MIN INT32_MIN #define SIG_ATOMIC_MAX INT32_MAX /* Limits of wint_t. */ #define WINT_MIN INT32_MIN #define WINT_MAX INT32_MAX #endif /* !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) */ #endif /* !_MACHINE__STDINT_H_ */ Index: head/sys/mips/include/atomic.h =================================================================== --- head/sys/mips/include/atomic.h (revision 326258) +++ head/sys/mips/include/atomic.h (revision 326259) @@ -1,771 +1,773 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 1998 Doug Rabson * 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. * * from: src/sys/alpha/include/atomic.h,v 1.21.2.3 2005/10/06 18:12:05 jhb * $FreeBSD$ */ #ifndef _MACHINE_ATOMIC_H_ #define _MACHINE_ATOMIC_H_ #ifndef _SYS_CDEFS_H_ #error this file needs sys/cdefs.h as a prerequisite #endif /* * Note: All the 64-bit atomic operations are only atomic when running * in 64-bit mode. It is assumed that code compiled for n32 and n64 * fits into this definition and no further safeties are needed. * * It is also assumed that the add, subtract and other arithmetic is * done on numbers not pointers. The special rules for n32 pointers * do not have atomic operations defined for them, but generally shouldn't * need atomic operations. */ #ifndef __MIPS_PLATFORM_SYNC_NOPS #define __MIPS_PLATFORM_SYNC_NOPS "" #endif static __inline void mips_sync(void) { __asm __volatile (".set noreorder\n" "\tsync\n" __MIPS_PLATFORM_SYNC_NOPS ".set reorder\n" : : : "memory"); } #define mb() mips_sync() #define wmb() mips_sync() #define rmb() mips_sync() /* * Various simple arithmetic on memory which is atomic in the presence * of interrupts and SMP safe. */ void atomic_set_8(__volatile uint8_t *, uint8_t); void atomic_clear_8(__volatile uint8_t *, uint8_t); void atomic_add_8(__volatile uint8_t *, uint8_t); void atomic_subtract_8(__volatile uint8_t *, uint8_t); void atomic_set_16(__volatile uint16_t *, uint16_t); void atomic_clear_16(__volatile uint16_t *, uint16_t); void atomic_add_16(__volatile uint16_t *, uint16_t); void atomic_subtract_16(__volatile uint16_t *, uint16_t); static __inline void atomic_set_32(__volatile uint32_t *p, uint32_t v) { uint32_t temp; __asm __volatile ( "1:\tll %0, %3\n\t" /* load old value */ "or %0, %2, %0\n\t" /* calculate new value */ "sc %0, %1\n\t" /* attempt to store */ "beqz %0, 1b\n\t" /* spin if failed */ : "=&r" (temp), "=m" (*p) : "r" (v), "m" (*p) : "memory"); } static __inline void atomic_clear_32(__volatile uint32_t *p, uint32_t v) { uint32_t temp; v = ~v; __asm __volatile ( "1:\tll %0, %3\n\t" /* load old value */ "and %0, %2, %0\n\t" /* calculate new value */ "sc %0, %1\n\t" /* attempt to store */ "beqz %0, 1b\n\t" /* spin if failed */ : "=&r" (temp), "=m" (*p) : "r" (v), "m" (*p) : "memory"); } static __inline void atomic_add_32(__volatile uint32_t *p, uint32_t v) { uint32_t temp; __asm __volatile ( "1:\tll %0, %3\n\t" /* load old value */ "addu %0, %2, %0\n\t" /* calculate new value */ "sc %0, %1\n\t" /* attempt to store */ "beqz %0, 1b\n\t" /* spin if failed */ : "=&r" (temp), "=m" (*p) : "r" (v), "m" (*p) : "memory"); } static __inline void atomic_subtract_32(__volatile uint32_t *p, uint32_t v) { uint32_t temp; __asm __volatile ( "1:\tll %0, %3\n\t" /* load old value */ "subu %0, %2\n\t" /* calculate new value */ "sc %0, %1\n\t" /* attempt to store */ "beqz %0, 1b\n\t" /* spin if failed */ : "=&r" (temp), "=m" (*p) : "r" (v), "m" (*p) : "memory"); } static __inline uint32_t atomic_readandclear_32(__volatile uint32_t *addr) { uint32_t result,temp; __asm __volatile ( "1:\tll %0,%3\n\t" /* load current value, asserting lock */ "li %1,0\n\t" /* value to store */ "sc %1,%2\n\t" /* attempt to store */ "beqz %1, 1b\n\t" /* if the store failed, spin */ : "=&r"(result), "=&r"(temp), "=m" (*addr) : "m" (*addr) : "memory"); return result; } static __inline uint32_t atomic_readandset_32(__volatile uint32_t *addr, uint32_t value) { uint32_t result,temp; __asm __volatile ( "1:\tll %0,%3\n\t" /* load current value, asserting lock */ "or %1,$0,%4\n\t" "sc %1,%2\n\t" /* attempt to store */ "beqz %1, 1b\n\t" /* if the store failed, spin */ : "=&r"(result), "=&r"(temp), "=m" (*addr) : "m" (*addr), "r" (value) : "memory"); return result; } #if defined(__mips_n64) || defined(__mips_n32) static __inline void atomic_set_64(__volatile uint64_t *p, uint64_t v) { uint64_t temp; __asm __volatile ( "1:\n\t" "lld %0, %3\n\t" /* load old value */ "or %0, %2, %0\n\t" /* calculate new value */ "scd %0, %1\n\t" /* attempt to store */ "beqz %0, 1b\n\t" /* spin if failed */ : "=&r" (temp), "=m" (*p) : "r" (v), "m" (*p) : "memory"); } static __inline void atomic_clear_64(__volatile uint64_t *p, uint64_t v) { uint64_t temp; v = ~v; __asm __volatile ( "1:\n\t" "lld %0, %3\n\t" /* load old value */ "and %0, %2, %0\n\t" /* calculate new value */ "scd %0, %1\n\t" /* attempt to store */ "beqz %0, 1b\n\t" /* spin if failed */ : "=&r" (temp), "=m" (*p) : "r" (v), "m" (*p) : "memory"); } static __inline void atomic_add_64(__volatile uint64_t *p, uint64_t v) { uint64_t temp; __asm __volatile ( "1:\n\t" "lld %0, %3\n\t" /* load old value */ "daddu %0, %2, %0\n\t" /* calculate new value */ "scd %0, %1\n\t" /* attempt to store */ "beqz %0, 1b\n\t" /* spin if failed */ : "=&r" (temp), "=m" (*p) : "r" (v), "m" (*p) : "memory"); } static __inline void atomic_subtract_64(__volatile uint64_t *p, uint64_t v) { uint64_t temp; __asm __volatile ( "1:\n\t" "lld %0, %3\n\t" /* load old value */ "dsubu %0, %2\n\t" /* calculate new value */ "scd %0, %1\n\t" /* attempt to store */ "beqz %0, 1b\n\t" /* spin if failed */ : "=&r" (temp), "=m" (*p) : "r" (v), "m" (*p) : "memory"); } static __inline uint64_t atomic_readandclear_64(__volatile uint64_t *addr) { uint64_t result,temp; __asm __volatile ( "1:\n\t" "lld %0, %3\n\t" /* load old value */ "li %1, 0\n\t" /* value to store */ "scd %1, %2\n\t" /* attempt to store */ "beqz %1, 1b\n\t" /* if the store failed, spin */ : "=&r"(result), "=&r"(temp), "=m" (*addr) : "m" (*addr) : "memory"); return result; } static __inline uint64_t atomic_readandset_64(__volatile uint64_t *addr, uint64_t value) { uint64_t result,temp; __asm __volatile ( "1:\n\t" "lld %0,%3\n\t" /* Load old value*/ "or %1,$0,%4\n\t" "scd %1,%2\n\t" /* attempt to store */ "beqz %1, 1b\n\t" /* if the store failed, spin */ : "=&r"(result), "=&r"(temp), "=m" (*addr) : "m" (*addr), "r" (value) : "memory"); return result; } #endif #define ATOMIC_ACQ_REL(NAME, WIDTH) \ static __inline void \ atomic_##NAME##_acq_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\ { \ atomic_##NAME##_##WIDTH(p, v); \ mips_sync(); \ } \ \ static __inline void \ atomic_##NAME##_rel_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\ { \ mips_sync(); \ atomic_##NAME##_##WIDTH(p, v); \ } /* Variants of simple arithmetic with memory barriers. */ ATOMIC_ACQ_REL(set, 8) ATOMIC_ACQ_REL(clear, 8) ATOMIC_ACQ_REL(add, 8) ATOMIC_ACQ_REL(subtract, 8) ATOMIC_ACQ_REL(set, 16) ATOMIC_ACQ_REL(clear, 16) ATOMIC_ACQ_REL(add, 16) ATOMIC_ACQ_REL(subtract, 16) ATOMIC_ACQ_REL(set, 32) ATOMIC_ACQ_REL(clear, 32) ATOMIC_ACQ_REL(add, 32) ATOMIC_ACQ_REL(subtract, 32) #if defined(__mips_n64) || defined(__mips_n32) ATOMIC_ACQ_REL(set, 64) ATOMIC_ACQ_REL(clear, 64) ATOMIC_ACQ_REL(add, 64) ATOMIC_ACQ_REL(subtract, 64) #endif #undef ATOMIC_ACQ_REL /* * We assume that a = b will do atomic loads and stores. */ #define ATOMIC_STORE_LOAD(WIDTH) \ static __inline uint##WIDTH##_t \ atomic_load_acq_##WIDTH(__volatile uint##WIDTH##_t *p) \ { \ uint##WIDTH##_t v; \ \ v = *p; \ mips_sync(); \ return (v); \ } \ \ static __inline void \ atomic_store_rel_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\ { \ mips_sync(); \ *p = v; \ } ATOMIC_STORE_LOAD(32) ATOMIC_STORE_LOAD(64) #if !defined(__mips_n64) && !defined(__mips_n32) void atomic_store_64(__volatile uint64_t *, uint64_t *); void atomic_load_64(__volatile uint64_t *, uint64_t *); #else static __inline void atomic_store_64(__volatile uint64_t *p, uint64_t *v) { *p = *v; } static __inline void atomic_load_64(__volatile uint64_t *p, uint64_t *v) { *v = *p; } #endif #undef ATOMIC_STORE_LOAD /* * Atomically compare the value stored at *p with cmpval and if the * two values are equal, update the value of *p with newval. Returns * zero if the compare failed, nonzero otherwise. */ static __inline uint32_t atomic_cmpset_32(__volatile uint32_t *p, uint32_t cmpval, uint32_t newval) { uint32_t ret; __asm __volatile ( "1:\tll %0, %4\n\t" /* load old value */ "bne %0, %2, 2f\n\t" /* compare */ "move %0, %3\n\t" /* value to store */ "sc %0, %1\n\t" /* attempt to store */ "beqz %0, 1b\n\t" /* if it failed, spin */ "j 3f\n\t" "2:\n\t" "li %0, 0\n\t" "3:\n" : "=&r" (ret), "=m" (*p) : "r" (cmpval), "r" (newval), "m" (*p) : "memory"); return ret; } /* * Atomically compare the value stored at *p with cmpval and if the * two values are equal, update the value of *p with newval. Returns * zero if the compare failed, nonzero otherwise. */ static __inline uint32_t atomic_cmpset_acq_32(__volatile uint32_t *p, uint32_t cmpval, uint32_t newval) { int retval; retval = atomic_cmpset_32(p, cmpval, newval); mips_sync(); return (retval); } static __inline uint32_t atomic_cmpset_rel_32(__volatile uint32_t *p, uint32_t cmpval, uint32_t newval) { mips_sync(); return (atomic_cmpset_32(p, cmpval, newval)); } static __inline uint32_t atomic_fcmpset_32(__volatile uint32_t *p, uint32_t *cmpval, uint32_t newval) { uint32_t ret; __asm __volatile ( "1:\n\t" "ll %0, %1\n\t" /* load old value */ "bne %0, %4, 2f\n\t" /* compare */ "move %0, %3\n\t" /* value to store */ "sc %0, %1\n\t" /* attempt to store */ "beqz %0, 1b\n\t" /* if it failed, spin */ "j 3f\n\t" "2:\n\t" "sw %0, %2\n\t" /* save old value */ "li %0, 0\n\t" "3:\n" : "=&r" (ret), "+m" (*p), "=m" (*cmpval) : "r" (newval), "r" (*cmpval) : "memory"); return ret; } static __inline uint32_t atomic_fcmpset_acq_32(__volatile uint32_t *p, uint32_t *cmpval, uint32_t newval) { int retval; retval = atomic_fcmpset_32(p, cmpval, newval); mips_sync(); return (retval); } static __inline uint32_t atomic_fcmpset_rel_32(__volatile uint32_t *p, uint32_t *cmpval, uint32_t newval) { mips_sync(); return (atomic_fcmpset_32(p, cmpval, newval)); } /* * Atomically add the value of v to the integer pointed to by p and return * the previous value of *p. */ static __inline uint32_t atomic_fetchadd_32(__volatile uint32_t *p, uint32_t v) { uint32_t value, temp; __asm __volatile ( "1:\tll %0, %1\n\t" /* load old value */ "addu %2, %3, %0\n\t" /* calculate new value */ "sc %2, %1\n\t" /* attempt to store */ "beqz %2, 1b\n\t" /* spin if failed */ : "=&r" (value), "=m" (*p), "=&r" (temp) : "r" (v), "m" (*p)); return (value); } #if defined(__mips_n64) || defined(__mips_n32) /* * Atomically compare the value stored at *p with cmpval and if the * two values are equal, update the value of *p with newval. Returns * zero if the compare failed, nonzero otherwise. */ static __inline uint64_t atomic_cmpset_64(__volatile uint64_t *p, uint64_t cmpval, uint64_t newval) { uint64_t ret; __asm __volatile ( "1:\n\t" "lld %0, %4\n\t" /* load old value */ "bne %0, %2, 2f\n\t" /* compare */ "move %0, %3\n\t" /* value to store */ "scd %0, %1\n\t" /* attempt to store */ "beqz %0, 1b\n\t" /* if it failed, spin */ "j 3f\n\t" "2:\n\t" "li %0, 0\n\t" "3:\n" : "=&r" (ret), "=m" (*p) : "r" (cmpval), "r" (newval), "m" (*p) : "memory"); return ret; } /* * Atomically compare the value stored at *p with cmpval and if the * two values are equal, update the value of *p with newval. Returns * zero if the compare failed, nonzero otherwise. */ static __inline uint64_t atomic_cmpset_acq_64(__volatile uint64_t *p, uint64_t cmpval, uint64_t newval) { int retval; retval = atomic_cmpset_64(p, cmpval, newval); mips_sync(); return (retval); } static __inline uint64_t atomic_cmpset_rel_64(__volatile uint64_t *p, uint64_t cmpval, uint64_t newval) { mips_sync(); return (atomic_cmpset_64(p, cmpval, newval)); } static __inline uint32_t atomic_fcmpset_64(__volatile uint64_t *p, uint64_t *cmpval, uint64_t newval) { uint32_t ret; __asm __volatile ( "1:\n\t" "lld %0, %1\n\t" /* load old value */ "bne %0, %4, 2f\n\t" /* compare */ "move %0, %3\n\t" /* value to store */ "scd %0, %1\n\t" /* attempt to store */ "beqz %0, 1b\n\t" /* if it failed, spin */ "j 3f\n\t" "2:\n\t" "sd %0, %2\n\t" /* save old value */ "li %0, 0\n\t" "3:\n" : "=&r" (ret), "+m" (*p), "=m" (*cmpval) : "r" (newval), "r" (*cmpval) : "memory"); return ret; } static __inline uint64_t atomic_fcmpset_acq_64(__volatile uint64_t *p, uint64_t *cmpval, uint64_t newval) { int retval; retval = atomic_fcmpset_64(p, cmpval, newval); mips_sync(); return (retval); } static __inline uint64_t atomic_fcmpset_rel_64(__volatile uint64_t *p, uint64_t *cmpval, uint64_t newval) { mips_sync(); return (atomic_fcmpset_64(p, cmpval, newval)); } /* * Atomically add the value of v to the integer pointed to by p and return * the previous value of *p. */ static __inline uint64_t atomic_fetchadd_64(__volatile uint64_t *p, uint64_t v) { uint64_t value, temp; __asm __volatile ( "1:\n\t" "lld %0, %1\n\t" /* load old value */ "daddu %2, %3, %0\n\t" /* calculate new value */ "scd %2, %1\n\t" /* attempt to store */ "beqz %2, 1b\n\t" /* spin if failed */ : "=&r" (value), "=m" (*p), "=&r" (temp) : "r" (v), "m" (*p)); return (value); } #endif static __inline void atomic_thread_fence_acq(void) { mips_sync(); } static __inline void atomic_thread_fence_rel(void) { mips_sync(); } static __inline void atomic_thread_fence_acq_rel(void) { mips_sync(); } static __inline void atomic_thread_fence_seq_cst(void) { mips_sync(); } /* Operations on chars. */ #define atomic_set_char atomic_set_8 #define atomic_set_acq_char atomic_set_acq_8 #define atomic_set_rel_char atomic_set_rel_8 #define atomic_clear_char atomic_clear_8 #define atomic_clear_acq_char atomic_clear_acq_8 #define atomic_clear_rel_char atomic_clear_rel_8 #define atomic_add_char atomic_add_8 #define atomic_add_acq_char atomic_add_acq_8 #define atomic_add_rel_char atomic_add_rel_8 #define atomic_subtract_char atomic_subtract_8 #define atomic_subtract_acq_char atomic_subtract_acq_8 #define atomic_subtract_rel_char atomic_subtract_rel_8 /* Operations on shorts. */ #define atomic_set_short atomic_set_16 #define atomic_set_acq_short atomic_set_acq_16 #define atomic_set_rel_short atomic_set_rel_16 #define atomic_clear_short atomic_clear_16 #define atomic_clear_acq_short atomic_clear_acq_16 #define atomic_clear_rel_short atomic_clear_rel_16 #define atomic_add_short atomic_add_16 #define atomic_add_acq_short atomic_add_acq_16 #define atomic_add_rel_short atomic_add_rel_16 #define atomic_subtract_short atomic_subtract_16 #define atomic_subtract_acq_short atomic_subtract_acq_16 #define atomic_subtract_rel_short atomic_subtract_rel_16 /* Operations on ints. */ #define atomic_set_int atomic_set_32 #define atomic_set_acq_int atomic_set_acq_32 #define atomic_set_rel_int atomic_set_rel_32 #define atomic_clear_int atomic_clear_32 #define atomic_clear_acq_int atomic_clear_acq_32 #define atomic_clear_rel_int atomic_clear_rel_32 #define atomic_add_int atomic_add_32 #define atomic_add_acq_int atomic_add_acq_32 #define atomic_add_rel_int atomic_add_rel_32 #define atomic_subtract_int atomic_subtract_32 #define atomic_subtract_acq_int atomic_subtract_acq_32 #define atomic_subtract_rel_int atomic_subtract_rel_32 #define atomic_cmpset_int atomic_cmpset_32 #define atomic_cmpset_acq_int atomic_cmpset_acq_32 #define atomic_cmpset_rel_int atomic_cmpset_rel_32 #define atomic_fcmpset_int atomic_fcmpset_32 #define atomic_fcmpset_acq_int atomic_fcmpset_acq_32 #define atomic_fcmpset_rel_int atomic_fcmpset_rel_32 #define atomic_load_acq_int atomic_load_acq_32 #define atomic_store_rel_int atomic_store_rel_32 #define atomic_readandclear_int atomic_readandclear_32 #define atomic_readandset_int atomic_readandset_32 #define atomic_fetchadd_int atomic_fetchadd_32 /* * I think the following is right, even for n32. For n32 the pointers * are still 32-bits, so we need to operate on them as 32-bit quantities, * even though they are sign extended in operation. For longs, there's * no question because they are always 32-bits. */ #ifdef __mips_n64 /* Operations on longs. */ #define atomic_set_long atomic_set_64 #define atomic_set_acq_long atomic_set_acq_64 #define atomic_set_rel_long atomic_set_rel_64 #define atomic_clear_long atomic_clear_64 #define atomic_clear_acq_long atomic_clear_acq_64 #define atomic_clear_rel_long atomic_clear_rel_64 #define atomic_add_long atomic_add_64 #define atomic_add_acq_long atomic_add_acq_64 #define atomic_add_rel_long atomic_add_rel_64 #define atomic_subtract_long atomic_subtract_64 #define atomic_subtract_acq_long atomic_subtract_acq_64 #define atomic_subtract_rel_long atomic_subtract_rel_64 #define atomic_cmpset_long atomic_cmpset_64 #define atomic_cmpset_acq_long atomic_cmpset_acq_64 #define atomic_cmpset_rel_long atomic_cmpset_rel_64 #define atomic_fcmpset_long atomic_fcmpset_64 #define atomic_fcmpset_acq_long atomic_fcmpset_acq_64 #define atomic_fcmpset_rel_long atomic_fcmpset_rel_64 #define atomic_load_acq_long atomic_load_acq_64 #define atomic_store_rel_long atomic_store_rel_64 #define atomic_fetchadd_long atomic_fetchadd_64 #define atomic_readandclear_long atomic_readandclear_64 #else /* !__mips_n64 */ /* Operations on longs. */ #define atomic_set_long(p, v) \ atomic_set_32((volatile u_int *)(p), (u_int)(v)) #define atomic_set_acq_long(p, v) \ atomic_set_acq_32((volatile u_int *)(p), (u_int)(v)) #define atomic_set_rel_long(p, v) \ atomic_set_rel_32((volatile u_int *)(p), (u_int)(v)) #define atomic_clear_long(p, v) \ atomic_clear_32((volatile u_int *)(p), (u_int)(v)) #define atomic_clear_acq_long(p, v) \ atomic_clear_acq_32((volatile u_int *)(p), (u_int)(v)) #define atomic_clear_rel_long(p, v) \ atomic_clear_rel_32((volatile u_int *)(p), (u_int)(v)) #define atomic_add_long(p, v) \ atomic_add_32((volatile u_int *)(p), (u_int)(v)) #define atomic_add_acq_long(p, v) \ atomic_add_32((volatile u_int *)(p), (u_int)(v)) #define atomic_add_rel_long(p, v) \ atomic_add_32((volatile u_int *)(p), (u_int)(v)) #define atomic_subtract_long(p, v) \ atomic_subtract_32((volatile u_int *)(p), (u_int)(v)) #define atomic_subtract_acq_long(p, v) \ atomic_subtract_acq_32((volatile u_int *)(p), (u_int)(v)) #define atomic_subtract_rel_long(p, v) \ atomic_subtract_rel_32((volatile u_int *)(p), (u_int)(v)) #define atomic_cmpset_long(p, cmpval, newval) \ atomic_cmpset_32((volatile u_int *)(p), (u_int)(cmpval), \ (u_int)(newval)) #define atomic_cmpset_acq_long(p, cmpval, newval) \ atomic_cmpset_acq_32((volatile u_int *)(p), (u_int)(cmpval), \ (u_int)(newval)) #define atomic_cmpset_rel_long(p, cmpval, newval) \ atomic_cmpset_rel_32((volatile u_int *)(p), (u_int)(cmpval), \ (u_int)(newval)) #define atomic_fcmpset_long(p, cmpval, newval) \ atomic_fcmpset_32((volatile u_int *)(p), (u_int *)(cmpval), \ (u_int)(newval)) #define atomic_fcmpset_acq_long(p, cmpval, newval) \ atomic_fcmpset_acq_32((volatile u_int *)(p), (u_int *)(cmpval), \ (u_int)(newval)) #define atomic_fcmpset_rel_long(p, cmpval, newval) \ atomic_fcmpset_rel_32((volatile u_int *)(p), (u_int *)(cmpval), \ (u_int)(newval)) #define atomic_load_acq_long(p) \ (u_long)atomic_load_acq_32((volatile u_int *)(p)) #define atomic_store_rel_long(p, v) \ atomic_store_rel_32((volatile u_int *)(p), (u_int)(v)) #define atomic_fetchadd_long(p, v) \ atomic_fetchadd_32((volatile u_int *)(p), (u_int)(v)) #define atomic_readandclear_long(p) \ atomic_readandclear_32((volatile u_int *)(p)) #endif /* __mips_n64 */ /* Operations on pointers. */ #define atomic_set_ptr atomic_set_long #define atomic_set_acq_ptr atomic_set_acq_long #define atomic_set_rel_ptr atomic_set_rel_long #define atomic_clear_ptr atomic_clear_long #define atomic_clear_acq_ptr atomic_clear_acq_long #define atomic_clear_rel_ptr atomic_clear_rel_long #define atomic_add_ptr atomic_add_long #define atomic_add_acq_ptr atomic_add_acq_long #define atomic_add_rel_ptr atomic_add_rel_long #define atomic_subtract_ptr atomic_subtract_long #define atomic_subtract_acq_ptr atomic_subtract_acq_long #define atomic_subtract_rel_ptr atomic_subtract_rel_long #define atomic_cmpset_ptr atomic_cmpset_long #define atomic_cmpset_acq_ptr atomic_cmpset_acq_long #define atomic_cmpset_rel_ptr atomic_cmpset_rel_long #define atomic_fcmpset_ptr atomic_fcmpset_long #define atomic_fcmpset_acq_ptr atomic_fcmpset_acq_long #define atomic_fcmpset_rel_ptr atomic_fcmpset_rel_long #define atomic_load_acq_ptr atomic_load_acq_long #define atomic_store_rel_ptr atomic_store_rel_long #define atomic_readandclear_ptr atomic_readandclear_long #endif /* ! _MACHINE_ATOMIC_H_ */ Index: head/sys/mips/include/bootinfo.h =================================================================== --- head/sys/mips/include/bootinfo.h (revision 326258) +++ head/sys/mips/include/bootinfo.h (revision 326259) @@ -1,85 +1,87 @@ /*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright (c) 2013 Robert N. M. Watson * Copyright (C) 1994 by Rodney W. Grimes, Milwaukie, Oregon 97222 * 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 as * the first lines of this file unmodified. * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Rodney W. Grimes. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY RODNEY W. GRIMES ``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 RODNEY W. GRIMES 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$ */ #ifndef _MACHINE_BOOTINFO_H_ #define _MACHINE_BOOTINFO_H_ /* Only change the version number if you break compatibility. */ #define BOOTINFO_VERSION 2 #define MIPS_BOOTINFO_MAGIC 0xCDEACDEA #if defined(__mips_n32) || defined(__mips_n64) typedef uint64_t bi_ptr_t; #else typedef uint32_t bi_ptr_t; #endif /* * A zero bootinfo field often means that there is no info available. * Flags are used to indicate the validity of fields where zero is a * normal value. */ struct bootinfo { /* bootinfo meta-data. */ uint32_t bi_version; uint32_t bi_size; /* bootinfo contents. */ uint64_t bi_boot2opts; /* boot2 flags to loader. */ bi_ptr_t bi_kernelname; /* Pointer to name. */ bi_ptr_t bi_nfs_diskless;/* Pointer to NFS data. */ bi_ptr_t bi_dtb; /* Pointer to dtb. */ bi_ptr_t bi_memsize; /* Physical memory size in bytes. */ bi_ptr_t bi_modulep; /* Preloaded modules. */ bi_ptr_t bi_boot_dev_type; /* Boot-device type. */ bi_ptr_t bi_boot_dev_unitptr; /* Boot-device unit/pointer. */ }; /* * Possible boot-device types passed from boot2 to loader, loader to kernel. * In most cases, the object pointed to will hold a filesystem; one exception * is BOOTINFO_DEV_TYPE_DRAM, which points to a pre-loaded object (e.g., * loader, kernel). */ #define BOOTINFO_DEV_TYPE_DRAM 0 /* DRAM loader/kernel (ptr). */ #define BOOTINFO_DEV_TYPE_CFI 1 /* CFI flash (unit). */ #define BOOTINFO_DEV_TYPE_SDCARD 2 /* SD card (unit). */ #ifdef _KERNEL extern struct bootinfo bootinfo; #endif #endif /* !_MACHINE_BOOTINFO_H_ */ Index: head/sys/mips/include/bus.h =================================================================== --- head/sys/mips/include/bus.h (revision 326258) +++ head/sys/mips/include/bus.h (revision 326259) @@ -1,734 +1,736 @@ /* $NetBSD: bus.h,v 1.11 2003/07/28 17:35:54 thorpej Exp $ */ /*- + * SPDX-License-Identifier: BSD-2-Clause-NetBSD AND BSD-4-Clause + * * Copyright (c) 1996, 1997, 1998, 2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. */ /*- * Copyright (c) 1996 Charles M. Hannum. All rights reserved. * Copyright (c) 1996 Christopher G. Demetriou. 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Christopher G. Demetriou * for the NetBSD Project. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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$ */ #ifndef _MACHINE_BUS_H_ #define _MACHINE_BUS_H_ #include struct bus_space { /* cookie */ void *bs_cookie; /* mapping/unmapping */ int (*bs_map) (void *, bus_addr_t, bus_size_t, int, bus_space_handle_t *); void (*bs_unmap) (void *, bus_space_handle_t, bus_size_t); int (*bs_subregion) (void *, bus_space_handle_t, bus_size_t, bus_size_t, bus_space_handle_t *); /* allocation/deallocation */ int (*bs_alloc) (void *, bus_addr_t, bus_addr_t, bus_size_t, bus_size_t, bus_size_t, int, bus_addr_t *, bus_space_handle_t *); void (*bs_free) (void *, bus_space_handle_t, bus_size_t); /* get kernel virtual address */ /* barrier */ void (*bs_barrier) (void *, bus_space_handle_t, bus_size_t, bus_size_t, int); /* read (single) */ u_int8_t (*bs_r_1) (void *, bus_space_handle_t, bus_size_t); u_int16_t (*bs_r_2) (void *, bus_space_handle_t, bus_size_t); u_int32_t (*bs_r_4) (void *, bus_space_handle_t, bus_size_t); u_int64_t (*bs_r_8) (void *, bus_space_handle_t, bus_size_t); /* read multiple */ void (*bs_rm_1) (void *, bus_space_handle_t, bus_size_t, u_int8_t *, bus_size_t); void (*bs_rm_2) (void *, bus_space_handle_t, bus_size_t, u_int16_t *, bus_size_t); void (*bs_rm_4) (void *, bus_space_handle_t, bus_size_t, u_int32_t *, bus_size_t); void (*bs_rm_8) (void *, bus_space_handle_t, bus_size_t, u_int64_t *, bus_size_t); /* read region */ void (*bs_rr_1) (void *, bus_space_handle_t, bus_size_t, u_int8_t *, bus_size_t); void (*bs_rr_2) (void *, bus_space_handle_t, bus_size_t, u_int16_t *, bus_size_t); void (*bs_rr_4) (void *, bus_space_handle_t, bus_size_t, u_int32_t *, bus_size_t); void (*bs_rr_8) (void *, bus_space_handle_t, bus_size_t, u_int64_t *, bus_size_t); /* write (single) */ void (*bs_w_1) (void *, bus_space_handle_t, bus_size_t, u_int8_t); void (*bs_w_2) (void *, bus_space_handle_t, bus_size_t, u_int16_t); void (*bs_w_4) (void *, bus_space_handle_t, bus_size_t, u_int32_t); void (*bs_w_8) (void *, bus_space_handle_t, bus_size_t, u_int64_t); /* write multiple */ void (*bs_wm_1) (void *, bus_space_handle_t, bus_size_t, const u_int8_t *, bus_size_t); void (*bs_wm_2) (void *, bus_space_handle_t, bus_size_t, const u_int16_t *, bus_size_t); void (*bs_wm_4) (void *, bus_space_handle_t, bus_size_t, const u_int32_t *, bus_size_t); void (*bs_wm_8) (void *, bus_space_handle_t, bus_size_t, const u_int64_t *, bus_size_t); /* write region */ void (*bs_wr_1) (void *, bus_space_handle_t, bus_size_t, const u_int8_t *, bus_size_t); void (*bs_wr_2) (void *, bus_space_handle_t, bus_size_t, const u_int16_t *, bus_size_t); void (*bs_wr_4) (void *, bus_space_handle_t, bus_size_t, const u_int32_t *, bus_size_t); void (*bs_wr_8) (void *, bus_space_handle_t, bus_size_t, const u_int64_t *, bus_size_t); /* set multiple */ void (*bs_sm_1) (void *, bus_space_handle_t, bus_size_t, u_int8_t, bus_size_t); void (*bs_sm_2) (void *, bus_space_handle_t, bus_size_t, u_int16_t, bus_size_t); void (*bs_sm_4) (void *, bus_space_handle_t, bus_size_t, u_int32_t, bus_size_t); void (*bs_sm_8) (void *, bus_space_handle_t, bus_size_t, u_int64_t, bus_size_t); /* set region */ void (*bs_sr_1) (void *, bus_space_handle_t, bus_size_t, u_int8_t, bus_size_t); void (*bs_sr_2) (void *, bus_space_handle_t, bus_size_t, u_int16_t, bus_size_t); void (*bs_sr_4) (void *, bus_space_handle_t, bus_size_t, u_int32_t, bus_size_t); void (*bs_sr_8) (void *, bus_space_handle_t, bus_size_t, u_int64_t, bus_size_t); /* copy */ void (*bs_c_1) (void *, bus_space_handle_t, bus_size_t, bus_space_handle_t, bus_size_t, bus_size_t); void (*bs_c_2) (void *, bus_space_handle_t, bus_size_t, bus_space_handle_t, bus_size_t, bus_size_t); void (*bs_c_4) (void *, bus_space_handle_t, bus_size_t, bus_space_handle_t, bus_size_t, bus_size_t); void (*bs_c_8) (void *, bus_space_handle_t, bus_size_t, bus_space_handle_t, bus_size_t, bus_size_t); /* read stream (single) */ u_int8_t (*bs_r_1_s) (void *, bus_space_handle_t, bus_size_t); u_int16_t (*bs_r_2_s) (void *, bus_space_handle_t, bus_size_t); u_int32_t (*bs_r_4_s) (void *, bus_space_handle_t, bus_size_t); u_int64_t (*bs_r_8_s) (void *, bus_space_handle_t, bus_size_t); /* read multiple stream */ void (*bs_rm_1_s) (void *, bus_space_handle_t, bus_size_t, u_int8_t *, bus_size_t); void (*bs_rm_2_s) (void *, bus_space_handle_t, bus_size_t, u_int16_t *, bus_size_t); void (*bs_rm_4_s) (void *, bus_space_handle_t, bus_size_t, u_int32_t *, bus_size_t); void (*bs_rm_8_s) (void *, bus_space_handle_t, bus_size_t, u_int64_t *, bus_size_t); /* read region stream */ void (*bs_rr_1_s) (void *, bus_space_handle_t, bus_size_t, u_int8_t *, bus_size_t); void (*bs_rr_2_s) (void *, bus_space_handle_t, bus_size_t, u_int16_t *, bus_size_t); void (*bs_rr_4_s) (void *, bus_space_handle_t, bus_size_t, u_int32_t *, bus_size_t); void (*bs_rr_8_s) (void *, bus_space_handle_t, bus_size_t, u_int64_t *, bus_size_t); /* write stream (single) */ void (*bs_w_1_s) (void *, bus_space_handle_t, bus_size_t, u_int8_t); void (*bs_w_2_s) (void *, bus_space_handle_t, bus_size_t, u_int16_t); void (*bs_w_4_s) (void *, bus_space_handle_t, bus_size_t, u_int32_t); void (*bs_w_8_s) (void *, bus_space_handle_t, bus_size_t, u_int64_t); /* write multiple stream */ void (*bs_wm_1_s) (void *, bus_space_handle_t, bus_size_t, const u_int8_t *, bus_size_t); void (*bs_wm_2_s) (void *, bus_space_handle_t, bus_size_t, const u_int16_t *, bus_size_t); void (*bs_wm_4_s) (void *, bus_space_handle_t, bus_size_t, const u_int32_t *, bus_size_t); void (*bs_wm_8_s) (void *, bus_space_handle_t, bus_size_t, const u_int64_t *, bus_size_t); /* write region stream */ void (*bs_wr_1_s) (void *, bus_space_handle_t, bus_size_t, const u_int8_t *, bus_size_t); void (*bs_wr_2_s) (void *, bus_space_handle_t, bus_size_t, const u_int16_t *, bus_size_t); void (*bs_wr_4_s) (void *, bus_space_handle_t, bus_size_t, const u_int32_t *, bus_size_t); void (*bs_wr_8_s) (void *, bus_space_handle_t, bus_size_t, const u_int64_t *, bus_size_t); }; /* * Utility macros; INTERNAL USE ONLY. */ #define __bs_c(a,b) __CONCAT(a,b) #define __bs_opname(op,size) __bs_c(__bs_c(__bs_c(bs_,op),_),size) #define __bs_rs(sz, t, h, o) \ (*(t)->__bs_opname(r,sz))((t)->bs_cookie, h, o) #define __bs_ws(sz, t, h, o, v) \ (*(t)->__bs_opname(w,sz))((t)->bs_cookie, h, o, v) #define __bs_nonsingle(type, sz, t, h, o, a, c) \ (*(t)->__bs_opname(type,sz))((t)->bs_cookie, h, o, a, c) #define __bs_set(type, sz, t, h, o, v, c) \ (*(t)->__bs_opname(type,sz))((t)->bs_cookie, h, o, v, c) #define __bs_copy(sz, t, h1, o1, h2, o2, cnt) \ (*(t)->__bs_opname(c,sz))((t)->bs_cookie, h1, o1, h2, o2, cnt) #define __bs_opname_s(op,size) __bs_c(__bs_c(__bs_c(__bs_c(bs_,op),_),size),_s) #define __bs_rs_s(sz, t, h, o) \ (*(t)->__bs_opname_s(r,sz))((t)->bs_cookie, h, o) #define __bs_ws_s(sz, t, h, o, v) \ (*(t)->__bs_opname_s(w,sz))((t)->bs_cookie, h, o, v) #define __bs_nonsingle_s(type, sz, t, h, o, a, c) \ (*(t)->__bs_opname_s(type,sz))((t)->bs_cookie, h, o, a, c) /* * Mapping and unmapping operations. */ #define bus_space_map(t, a, s, c, hp) \ (*(t)->bs_map)((t)->bs_cookie, (a), (s), (c), (hp)) #define bus_space_unmap(t, h, s) \ (*(t)->bs_unmap)((t)->bs_cookie, (h), (s)) #define bus_space_subregion(t, h, o, s, hp) \ (*(t)->bs_subregion)((t)->bs_cookie, (h), (o), (s), (hp)) /* * Allocation and deallocation operations. */ #define bus_space_alloc(t, rs, re, s, a, b, c, ap, hp) \ (*(t)->bs_alloc)((t)->bs_cookie, (rs), (re), (s), (a), (b), \ (c), (ap), (hp)) #define bus_space_free(t, h, s) \ (*(t)->bs_free)((t)->bs_cookie, (h), (s)) /* * Bus barrier operations. */ #define bus_space_barrier(t, h, o, l, f) \ (*(t)->bs_barrier)((t)->bs_cookie, (h), (o), (l), (f)) #define BUS_SPACE_BARRIER_READ 0x01 #define BUS_SPACE_BARRIER_WRITE 0x02 /* * Bus read (single) operations. */ #define bus_space_read_1(t, h, o) __bs_rs(1,(t),(h),(o)) #define bus_space_read_2(t, h, o) __bs_rs(2,(t),(h),(o)) #define bus_space_read_4(t, h, o) __bs_rs(4,(t),(h),(o)) #define bus_space_read_8(t, h, o) __bs_rs(8,(t),(h),(o)) #define bus_space_read_stream_1(t, h, o) __bs_rs_s(1,(t), (h), (o)) #define bus_space_read_stream_2(t, h, o) __bs_rs_s(2,(t), (h), (o)) #define bus_space_read_stream_4(t, h, o) __bs_rs_s(4,(t), (h), (o)) #define bus_space_read_stream_8(t, h, o) __bs_rs_s(8,8,(t),(h),(o)) /* * Bus read multiple operations. */ #define bus_space_read_multi_1(t, h, o, a, c) \ __bs_nonsingle(rm,1,(t),(h),(o),(a),(c)) #define bus_space_read_multi_2(t, h, o, a, c) \ __bs_nonsingle(rm,2,(t),(h),(o),(a),(c)) #define bus_space_read_multi_4(t, h, o, a, c) \ __bs_nonsingle(rm,4,(t),(h),(o),(a),(c)) #define bus_space_read_multi_8(t, h, o, a, c) \ __bs_nonsingle(rm,8,(t),(h),(o),(a),(c)) #define bus_space_read_multi_stream_1(t, h, o, a, c) \ __bs_nonsingle_s(rm,1,(t),(h),(o),(a),(c)) #define bus_space_read_multi_stream_2(t, h, o, a, c) \ __bs_nonsingle_s(rm,2,(t),(h),(o),(a),(c)) #define bus_space_read_multi_stream_4(t, h, o, a, c) \ __bs_nonsingle_s(rm,4,(t),(h),(o),(a),(c)) #define bus_space_read_multi_stream_8(t, h, o, a, c) \ __bs_nonsingle_s(rm,8,(t),(h),(o),(a),(c)) /* * Bus read region operations. */ #define bus_space_read_region_1(t, h, o, a, c) \ __bs_nonsingle(rr,1,(t),(h),(o),(a),(c)) #define bus_space_read_region_2(t, h, o, a, c) \ __bs_nonsingle(rr,2,(t),(h),(o),(a),(c)) #define bus_space_read_region_4(t, h, o, a, c) \ __bs_nonsingle(rr,4,(t),(h),(o),(a),(c)) #define bus_space_read_region_8(t, h, o, a, c) \ __bs_nonsingle(rr,8,(t),(h),(o),(a),(c)) #define bus_space_read_region_stream_1(t, h, o, a, c) \ __bs_nonsingle_s(rr,1,(t),(h),(o),(a),(c)) #define bus_space_read_region_stream_2(t, h, o, a, c) \ __bs_nonsingle_s(rr,2,(t),(h),(o),(a),(c)) #define bus_space_read_region_stream_4(t, h, o, a, c) \ __bs_nonsingle_s(rr,4,(t),(h),(o),(a),(c)) #define bus_space_read_region_stream_8(t, h, o, a, c) \ __bs_nonsingle_s(rr,8,(t),(h),(o),(a),(c)) /* * Bus write (single) operations. */ #define bus_space_write_1(t, h, o, v) __bs_ws(1,(t),(h),(o),(v)) #define bus_space_write_2(t, h, o, v) __bs_ws(2,(t),(h),(o),(v)) #define bus_space_write_4(t, h, o, v) __bs_ws(4,(t),(h),(o),(v)) #define bus_space_write_8(t, h, o, v) __bs_ws(8,(t),(h),(o),(v)) #define bus_space_write_stream_1(t, h, o, v) __bs_ws_s(1,(t),(h),(o),(v)) #define bus_space_write_stream_2(t, h, o, v) __bs_ws_s(2,(t),(h),(o),(v)) #define bus_space_write_stream_4(t, h, o, v) __bs_ws_s(4,(t),(h),(o),(v)) #define bus_space_write_stream_8(t, h, o, v) __bs_ws_s(8,(t),(h),(o),(v)) /* * Bus write multiple operations. */ #define bus_space_write_multi_1(t, h, o, a, c) \ __bs_nonsingle(wm,1,(t),(h),(o),(a),(c)) #define bus_space_write_multi_2(t, h, o, a, c) \ __bs_nonsingle(wm,2,(t),(h),(o),(a),(c)) #define bus_space_write_multi_4(t, h, o, a, c) \ __bs_nonsingle(wm,4,(t),(h),(o),(a),(c)) #define bus_space_write_multi_8(t, h, o, a, c) \ __bs_nonsingle(wm,8,(t),(h),(o),(a),(c)) #define bus_space_write_multi_stream_1(t, h, o, a, c) \ __bs_nonsingle_s(wm,1,(t),(h),(o),(a),(c)) #define bus_space_write_multi_stream_2(t, h, o, a, c) \ __bs_nonsingle_s(wm,2,(t),(h),(o),(a),(c)) #define bus_space_write_multi_stream_4(t, h, o, a, c) \ __bs_nonsingle_s(wm,4,(t),(h),(o),(a),(c)) #define bus_space_write_multi_stream_8(t, h, o, a, c) \ __bs_nonsingle_s(wm,8,(t),(h),(o),(a),(c)) /* * Bus write region operations. */ #define bus_space_write_region_1(t, h, o, a, c) \ __bs_nonsingle(wr,1,(t),(h),(o),(a),(c)) #define bus_space_write_region_2(t, h, o, a, c) \ __bs_nonsingle(wr,2,(t),(h),(o),(a),(c)) #define bus_space_write_region_4(t, h, o, a, c) \ __bs_nonsingle(wr,4,(t),(h),(o),(a),(c)) #define bus_space_write_region_8(t, h, o, a, c) \ __bs_nonsingle(wr,8,(t),(h),(o),(a),(c)) #define bus_space_write_region_stream_1(t, h, o, a, c) \ __bs_nonsingle_s(wr,1,(t),(h),(o),(a),(c)) #define bus_space_write_region_stream_2(t, h, o, a, c) \ __bs_nonsingle_s(wr,2,(t),(h),(o),(a),(c)) #define bus_space_write_region_stream_4(t, h, o, a, c) \ __bs_nonsingle_s(wr,4,(t),(h),(o),(a),(c)) #define bus_space_write_region_stream_8(t, h, o, a, c) \ __bs_nonsingle_s(wr,8,(t),(h),(o),(a),(c)) /* * Set multiple operations. */ #define bus_space_set_multi_1(t, h, o, v, c) \ __bs_set(sm,1,(t),(h),(o),(v),(c)) #define bus_space_set_multi_2(t, h, o, v, c) \ __bs_set(sm,2,(t),(h),(o),(v),(c)) #define bus_space_set_multi_4(t, h, o, v, c) \ __bs_set(sm,4,(t),(h),(o),(v),(c)) #define bus_space_set_multi_8(t, h, o, v, c) \ __bs_set(sm,8,(t),(h),(o),(v),(c)) /* * Set region operations. */ #define bus_space_set_region_1(t, h, o, v, c) \ __bs_set(sr,1,(t),(h),(o),(v),(c)) #define bus_space_set_region_2(t, h, o, v, c) \ __bs_set(sr,2,(t),(h),(o),(v),(c)) #define bus_space_set_region_4(t, h, o, v, c) \ __bs_set(sr,4,(t),(h),(o),(v),(c)) #define bus_space_set_region_8(t, h, o, v, c) \ __bs_set(sr,8,(t),(h),(o),(v),(c)) /* * Copy operations. */ #define bus_space_copy_region_1(t, h1, o1, h2, o2, c) \ __bs_copy(1, t, h1, o1, h2, o2, c) #define bus_space_copy_region_2(t, h1, o1, h2, o2, c) \ __bs_copy(2, t, h1, o1, h2, o2, c) #define bus_space_copy_region_4(t, h1, o1, h2, o2, c) \ __bs_copy(4, t, h1, o1, h2, o2, c) #define bus_space_copy_region_8(t, h1, o1, h2, o2, c) \ __bs_copy(8, t, h1, o1, h2, o2, c) /* * Macros to provide prototypes for all the functions used in the * bus_space structure */ #define bs_map_proto(f) \ int __bs_c(f,_bs_map) (void *t, bus_addr_t addr, \ bus_size_t size, int cacheable, bus_space_handle_t *bshp); #define bs_unmap_proto(f) \ void __bs_c(f,_bs_unmap) (void *t, bus_space_handle_t bsh, \ bus_size_t size); #define bs_subregion_proto(f) \ int __bs_c(f,_bs_subregion) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, bus_size_t size, \ bus_space_handle_t *nbshp); #define bs_alloc_proto(f) \ int __bs_c(f,_bs_alloc) (void *t, bus_addr_t rstart, \ bus_addr_t rend, bus_size_t size, bus_size_t align, \ bus_size_t boundary, int cacheable, bus_addr_t *addrp, \ bus_space_handle_t *bshp); #define bs_free_proto(f) \ void __bs_c(f,_bs_free) (void *t, bus_space_handle_t bsh, \ bus_size_t size); #define bs_barrier_proto(f) \ void __bs_c(f,_bs_barrier) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, bus_size_t len, int flags); #define bs_r_1_proto(f) \ u_int8_t __bs_c(f,_bs_r_1) (void *t, bus_space_handle_t bsh, \ bus_size_t offset); #define bs_r_2_proto(f) \ u_int16_t __bs_c(f,_bs_r_2) (void *t, bus_space_handle_t bsh, \ bus_size_t offset); #define bs_r_4_proto(f) \ u_int32_t __bs_c(f,_bs_r_4) (void *t, bus_space_handle_t bsh, \ bus_size_t offset); #define bs_r_8_proto(f) \ u_int64_t __bs_c(f,_bs_r_8) (void *t, bus_space_handle_t bsh, \ bus_size_t offset); #define bs_r_1_s_proto(f) \ u_int8_t __bs_c(f,_bs_r_1_s) (void *t, bus_space_handle_t bsh, \ bus_size_t offset); #define bs_r_2_s_proto(f) \ u_int16_t __bs_c(f,_bs_r_2_s) (void *t, bus_space_handle_t bsh, \ bus_size_t offset); #define bs_r_4_s_proto(f) \ u_int32_t __bs_c(f,_bs_r_4_s) (void *t, bus_space_handle_t bsh, \ bus_size_t offset); #define bs_w_1_proto(f) \ void __bs_c(f,_bs_w_1) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int8_t value); #define bs_w_2_proto(f) \ void __bs_c(f,_bs_w_2) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int16_t value); #define bs_w_4_proto(f) \ void __bs_c(f,_bs_w_4) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int32_t value); #define bs_w_8_proto(f) \ void __bs_c(f,_bs_w_8) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int64_t value); #define bs_w_1_s_proto(f) \ void __bs_c(f,_bs_w_1_s) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int8_t value); #define bs_w_2_s_proto(f) \ void __bs_c(f,_bs_w_2_s) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int16_t value); #define bs_w_4_s_proto(f) \ void __bs_c(f,_bs_w_4_s) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int32_t value); #define bs_rm_1_proto(f) \ void __bs_c(f,_bs_rm_1) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int8_t *addr, bus_size_t count); #define bs_rm_2_proto(f) \ void __bs_c(f,_bs_rm_2) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int16_t *addr, bus_size_t count); #define bs_rm_4_proto(f) \ void __bs_c(f,_bs_rm_4) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int32_t *addr, bus_size_t count); #define bs_rm_8_proto(f) \ void __bs_c(f,_bs_rm_8) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int64_t *addr, bus_size_t count); #define bs_wm_1_proto(f) \ void __bs_c(f,_bs_wm_1) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, const u_int8_t *addr, bus_size_t count); #define bs_wm_2_proto(f) \ void __bs_c(f,_bs_wm_2) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, const u_int16_t *addr, bus_size_t count); #define bs_wm_4_proto(f) \ void __bs_c(f,_bs_wm_4) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, const u_int32_t *addr, bus_size_t count); #define bs_wm_8_proto(f) \ void __bs_c(f,_bs_wm_8) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, const u_int64_t *addr, bus_size_t count); #define bs_rr_1_proto(f) \ void __bs_c(f, _bs_rr_1) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int8_t *addr, bus_size_t count); #define bs_rr_2_proto(f) \ void __bs_c(f, _bs_rr_2) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int16_t *addr, bus_size_t count); #define bs_rr_4_proto(f) \ void __bs_c(f, _bs_rr_4) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int32_t *addr, bus_size_t count); #define bs_rr_8_proto(f) \ void __bs_c(f, _bs_rr_8) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int64_t *addr, bus_size_t count); #define bs_wr_1_proto(f) \ void __bs_c(f, _bs_wr_1) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, const u_int8_t *addr, bus_size_t count); #define bs_wr_2_proto(f) \ void __bs_c(f, _bs_wr_2) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, const u_int16_t *addr, bus_size_t count); #define bs_wr_4_proto(f) \ void __bs_c(f, _bs_wr_4) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, const u_int32_t *addr, bus_size_t count); #define bs_wr_8_proto(f) \ void __bs_c(f, _bs_wr_8) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, const u_int64_t *addr, bus_size_t count); #define bs_sm_1_proto(f) \ void __bs_c(f,_bs_sm_1) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int8_t value, bus_size_t count); #define bs_sm_2_proto(f) \ void __bs_c(f,_bs_sm_2) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int16_t value, bus_size_t count); #define bs_sm_4_proto(f) \ void __bs_c(f,_bs_sm_4) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int32_t value, bus_size_t count); #define bs_sm_8_proto(f) \ void __bs_c(f,_bs_sm_8) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int64_t value, bus_size_t count); #define bs_sr_1_proto(f) \ void __bs_c(f,_bs_sr_1) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int8_t value, bus_size_t count); #define bs_sr_2_proto(f) \ void __bs_c(f,_bs_sr_2) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int16_t value, bus_size_t count); #define bs_sr_4_proto(f) \ void __bs_c(f,_bs_sr_4) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int32_t value, bus_size_t count); #define bs_sr_8_proto(f) \ void __bs_c(f,_bs_sr_8) (void *t, bus_space_handle_t bsh, \ bus_size_t offset, u_int64_t value, bus_size_t count); #define bs_c_1_proto(f) \ void __bs_c(f,_bs_c_1) (void *t, bus_space_handle_t bsh1, \ bus_size_t offset1, bus_space_handle_t bsh2, \ bus_size_t offset2, bus_size_t count); #define bs_c_2_proto(f) \ void __bs_c(f,_bs_c_2) (void *t, bus_space_handle_t bsh1, \ bus_size_t offset1, bus_space_handle_t bsh2, \ bus_size_t offset2, bus_size_t count); #define bs_c_4_proto(f) \ void __bs_c(f,_bs_c_4) (void *t, bus_space_handle_t bsh1, \ bus_size_t offset1, bus_space_handle_t bsh2, \ bus_size_t offset2, bus_size_t count); #define bs_c_8_proto(f) \ void __bs_c(f,_bs_c_8) (void *t, bus_space_handle_t bsh1, \ bus_size_t offset1, bus_space_handle_t bsh2, \ bus_size_t offset2, bus_size_t count); #define DECLARE_BUS_SPACE_PROTOTYPES(f) \ bs_map_proto(f); \ bs_unmap_proto(f); \ bs_subregion_proto(f); \ bs_alloc_proto(f); \ bs_free_proto(f); \ bs_barrier_proto(f); \ bs_r_1_proto(f); \ bs_r_2_proto(f); \ bs_r_4_proto(f); \ bs_r_8_proto(f); \ bs_r_1_s_proto(f); \ bs_r_2_s_proto(f); \ bs_r_4_s_proto(f); \ bs_w_1_proto(f); \ bs_w_2_proto(f); \ bs_w_4_proto(f); \ bs_w_8_proto(f); \ bs_w_1_s_proto(f); \ bs_w_2_s_proto(f); \ bs_w_4_s_proto(f); \ bs_rm_1_proto(f); \ bs_rm_2_proto(f); \ bs_rm_4_proto(f); \ bs_rm_8_proto(f); \ bs_wm_1_proto(f); \ bs_wm_2_proto(f); \ bs_wm_4_proto(f); \ bs_wm_8_proto(f); \ bs_rr_1_proto(f); \ bs_rr_2_proto(f); \ bs_rr_4_proto(f); \ bs_rr_8_proto(f); \ bs_wr_1_proto(f); \ bs_wr_2_proto(f); \ bs_wr_4_proto(f); \ bs_wr_8_proto(f); \ bs_sm_1_proto(f); \ bs_sm_2_proto(f); \ bs_sm_4_proto(f); \ bs_sm_8_proto(f); \ bs_sr_1_proto(f); \ bs_sr_2_proto(f); \ bs_sr_4_proto(f); \ bs_sr_8_proto(f); \ bs_c_1_proto(f); \ bs_c_2_proto(f); \ bs_c_4_proto(f); \ bs_c_8_proto(f); #define BUS_SPACE_ALIGNED_POINTER(p, t) ALIGNED_POINTER(p, t) #define BUS_SPACE_MAXADDR_24BIT 0xFFFFFF #define BUS_SPACE_MAXSIZE_24BIT 0xFFFFFF #define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFF #define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFF #if defined(__mips_n64) #define BUS_SPACE_MAXADDR 0xFFFFFFFFFFFFFFFFUL #define BUS_SPACE_MAXSIZE 0xFFFFFFFFFFFFFFFFUL #else #define BUS_SPACE_MAXADDR 0xFFFFFFFFUL #define BUS_SPACE_MAXSIZE 0xFFFFFFFFUL #endif #define BUS_SPACE_UNRESTRICTED (~0) /* * declare generic bus space, it suits all needs in */ DECLARE_BUS_SPACE_PROTOTYPES(generic); extern bus_space_tag_t mips_bus_space_generic; /* Special bus space for RMI processors */ #if defined(CPU_RMI) || defined (CPU_NLM) extern bus_space_tag_t rmi_bus_space; extern bus_space_tag_t rmi_pci_bus_space; extern bus_space_tag_t rmi_uart_bus_space; #endif #include #endif /* _MACHINE_BUS_H_ */ Index: head/sys/mips/include/bus_dma.h =================================================================== --- head/sys/mips/include/bus_dma.h (revision 326258) +++ head/sys/mips/include/bus_dma.h (revision 326259) @@ -1,35 +1,37 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2005 Scott Long * 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$ */ #ifndef _MIPS_BUS_DMA_H_ #define _MIPS_BUS_DMA_H_ #include #include #endif /* _MIPS_BUS_DMA_H_ */ Index: head/sys/mips/include/cache.h =================================================================== --- head/sys/mips/include/cache.h (revision 326258) +++ head/sys/mips/include/cache.h (revision 326259) @@ -1,224 +1,226 @@ /* $NetBSD: cache.h,v 1.6 2003/02/17 11:35:01 simonb Exp $ */ -/* +/*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright 2001 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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$ */ #ifndef _MACHINE_CACHE_H_ #define _MACHINE_CACHE_H_ /* * Cache operations. * * We define the following primitives: * * --- Instruction cache synchronization (mandatory): * * icache_sync_all Synchronize I-cache * * icache_sync_range Synchronize I-cache range * * icache_sync_range_index (index ops) * * --- Primary data cache (mandatory): * * pdcache_wbinv_all Write-back Invalidate primary D-cache * * pdcache_wbinv_range Write-back Invalidate primary D-cache range * * pdcache_wbinv_range_index (index ops) * * pdcache_inv_range Invalidate primary D-cache range * * pdcache_wb_range Write-back primary D-cache range * * --- Secondary data cache (optional): * * sdcache_wbinv_all Write-back Invalidate secondary D-cache * * sdcache_wbinv_range Write-back Invalidate secondary D-cache range * * sdcache_wbinv_range_index (index ops) * * sdcache_inv_range Invalidate secondary D-cache range * * sdcache_wb_range Write-back secondary D-cache range * * There are some rules that must be followed: * * I-cache Synch (all or range): * The goal is to synchronize the instruction stream, * so you may need to write-back dirty data cache * blocks first. If a range is requested, and you * can't synchronize just a range, you have to hit * the whole thing. * * D-cache Write-back Invalidate range: * If you can't WB-Inv a range, you must WB-Inv the * entire D-cache. * * D-cache Invalidate: * If you can't Inv the D-cache without doing a * Write-back, YOU MUST PANIC. This is to catch * errors in calling code. Callers must be aware * of this scenario, and must handle it appropriately * (consider the bus_dma(9) operations). * * D-cache Write-back: * If you can't Write-back without doing an invalidate, * that's fine. Then treat this as a WB-Inv. Skipping * the invalidate is merely an optimization. * * All operations: * Valid virtual addresses must be passed to the * cache operation. * * Finally, these primitives are grouped together in reasonable * ways. For all operations described here, first the primary * cache is frobbed, then the secondary cache frobbed, if the * operation for the secondary cache exists. * * mips_icache_sync_all Synchronize I-cache * * mips_icache_sync_range Synchronize I-cache range * * mips_icache_sync_range_index (index ops) * * mips_dcache_wbinv_all Write-back Invalidate D-cache * * mips_dcache_wbinv_range Write-back Invalidate D-cache range * * mips_dcache_wbinv_range_index (index ops) * * mips_dcache_inv_range Invalidate D-cache range * * mips_dcache_wb_range Write-back D-cache range */ struct mips_cache_ops { void (*mco_icache_sync_all)(void); void (*mco_icache_sync_range)(vm_offset_t, vm_size_t); void (*mco_icache_sync_range_index)(vm_offset_t, vm_size_t); void (*mco_pdcache_wbinv_all)(void); void (*mco_pdcache_wbinv_range)(vm_offset_t, vm_size_t); void (*mco_pdcache_wbinv_range_index)(vm_offset_t, vm_size_t); void (*mco_pdcache_inv_range)(vm_offset_t, vm_size_t); void (*mco_pdcache_wb_range)(vm_offset_t, vm_size_t); /* These are called only by the (mipsNN) icache functions. */ void (*mco_intern_pdcache_wbinv_all)(void); void (*mco_intern_pdcache_wbinv_range_index)(vm_offset_t, vm_size_t); void (*mco_intern_pdcache_wb_range)(vm_offset_t, vm_size_t); void (*mco_sdcache_wbinv_all)(void); void (*mco_sdcache_wbinv_range)(vm_offset_t, vm_size_t); void (*mco_sdcache_wbinv_range_index)(vm_offset_t, vm_size_t); void (*mco_sdcache_inv_range)(vm_offset_t, vm_size_t); void (*mco_sdcache_wb_range)(vm_offset_t, vm_size_t); /* These are called only by the (mipsNN) icache functions. */ void (*mco_intern_sdcache_wbinv_all)(void); void (*mco_intern_sdcache_wbinv_range_index)(vm_offset_t, vm_size_t); void (*mco_intern_sdcache_wb_range)(vm_offset_t, vm_size_t); }; extern struct mips_cache_ops mips_cache_ops; /* PRIMARY CACHE VARIABLES */ extern int mips_picache_linesize; extern int mips_pdcache_linesize; extern int mips_sdcache_linesize; extern int mips_dcache_max_linesize; #define __mco_noargs(prefix, x) \ do { \ (*mips_cache_ops.mco_ ## prefix ## p ## x )(); \ if (*mips_cache_ops.mco_ ## prefix ## s ## x ) \ (*mips_cache_ops.mco_ ## prefix ## s ## x )(); \ } while (/*CONSTCOND*/0) #define __mco_2args(prefix, x, a, b) \ do { \ (*mips_cache_ops.mco_ ## prefix ## p ## x )((a), (b)); \ if (*mips_cache_ops.mco_ ## prefix ## s ## x ) \ (*mips_cache_ops.mco_ ## prefix ## s ## x )((a), (b)); \ } while (/*CONSTCOND*/0) #define mips_icache_sync_all() \ (*mips_cache_ops.mco_icache_sync_all)() #define mips_icache_sync_range(v, s) \ (*mips_cache_ops.mco_icache_sync_range)((v), (s)) #define mips_icache_sync_range_index(v, s) \ (*mips_cache_ops.mco_icache_sync_range_index)((v), (s)) #define mips_dcache_wbinv_all() \ __mco_noargs(, dcache_wbinv_all) #define mips_dcache_wbinv_range(v, s) \ __mco_2args(, dcache_wbinv_range, (v), (s)) #define mips_dcache_wbinv_range_index(v, s) \ __mco_2args(, dcache_wbinv_range_index, (v), (s)) #define mips_dcache_inv_range(v, s) \ __mco_2args(, dcache_inv_range, (v), (s)) #define mips_dcache_wb_range(v, s) \ __mco_2args(, dcache_wb_range, (v), (s)) /* * Private D-cache functions only called from (currently only the * mipsNN) I-cache functions. */ #define mips_intern_dcache_wbinv_all() \ __mco_noargs(intern_, dcache_wbinv_all) #define mips_intern_dcache_wbinv_range_index(v, s) \ __mco_2args(intern_, dcache_wbinv_range_index, (v), (s)) #define mips_intern_dcache_wb_range(v, s) \ __mco_2args(intern_, dcache_wb_range, (v), (s)) /* forward declaration */ struct mips_cpuinfo; void mips_config_cache(struct mips_cpuinfo *); #include #endif /* _MACHINE_CACHE_H_ */ Index: head/sys/mips/include/cache_mipsNN.h =================================================================== --- head/sys/mips/include/cache_mipsNN.h (revision 326258) +++ head/sys/mips/include/cache_mipsNN.h (revision 326259) @@ -1,92 +1,94 @@ /* $NetBSD: cache_mipsNN.h,v 1.4 2003/02/17 11:35:02 simonb Exp $ */ -/* +/*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright 2002 Wasabi Systems, Inc. * All rights reserved. * * Written by Simon Burge for Wasabi Systems, Inc. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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$ */ #ifndef _MACHINE_CACHE_MIPSNN_H_ #define _MACHINE_CACHE_MIPSNN_H_ void mipsNN_cache_init(struct mips_cpuinfo *); void mipsNN_icache_sync_all_16(void); void mipsNN_icache_sync_all_32(void); void mipsNN_icache_sync_all_64(void); void mipsNN_icache_sync_all_128(void); void mipsNN_icache_sync_range_16(vm_offset_t, vm_size_t); void mipsNN_icache_sync_range_32(vm_offset_t, vm_size_t); void mipsNN_icache_sync_range_64(vm_offset_t, vm_size_t); void mipsNN_icache_sync_range_128(vm_offset_t, vm_size_t); void mipsNN_icache_sync_range_index_16(vm_offset_t, vm_size_t); void mipsNN_icache_sync_range_index_32(vm_offset_t, vm_size_t); void mipsNN_icache_sync_range_index_64(vm_offset_t, vm_size_t); void mipsNN_icache_sync_range_index_128(vm_offset_t, vm_size_t); void mipsNN_pdcache_wbinv_all_16(void); void mipsNN_pdcache_wbinv_all_32(void); void mipsNN_pdcache_wbinv_all_64(void); void mipsNN_pdcache_wbinv_all_128(void); void mipsNN_pdcache_wbinv_range_16(vm_offset_t, vm_size_t); void mipsNN_pdcache_wbinv_range_32(vm_offset_t, vm_size_t); void mipsNN_pdcache_wbinv_range_64(vm_offset_t, vm_size_t); void mipsNN_pdcache_wbinv_range_128(vm_offset_t, vm_size_t); void mipsNN_pdcache_wbinv_range_index_16(vm_offset_t, vm_size_t); void mipsNN_pdcache_wbinv_range_index_32(vm_offset_t, vm_size_t); void mipsNN_pdcache_wbinv_range_index_64(vm_offset_t, vm_size_t); void mipsNN_pdcache_wbinv_range_index_128(vm_offset_t, vm_size_t); void mipsNN_pdcache_inv_range_16(vm_offset_t, vm_size_t); void mipsNN_pdcache_inv_range_32(vm_offset_t, vm_size_t); void mipsNN_pdcache_inv_range_64(vm_offset_t, vm_size_t); void mipsNN_pdcache_inv_range_128(vm_offset_t, vm_size_t); void mipsNN_pdcache_wb_range_16(vm_offset_t, vm_size_t); void mipsNN_pdcache_wb_range_32(vm_offset_t, vm_size_t); void mipsNN_pdcache_wb_range_64(vm_offset_t, vm_size_t); void mipsNN_pdcache_wb_range_128(vm_offset_t, vm_size_t); void mipsNN_sdcache_wbinv_all_32(void); void mipsNN_sdcache_wbinv_all_64(void); void mipsNN_sdcache_wbinv_all_128(void); void mipsNN_sdcache_wbinv_range_32(vm_offset_t, vm_size_t); void mipsNN_sdcache_wbinv_range_64(vm_offset_t, vm_size_t); void mipsNN_sdcache_wbinv_range_128(vm_offset_t, vm_size_t); void mipsNN_sdcache_wbinv_range_index_32(vm_offset_t, vm_size_t); void mipsNN_sdcache_wbinv_range_index_64(vm_offset_t, vm_size_t); void mipsNN_sdcache_wbinv_range_index_128(vm_offset_t, vm_size_t); void mipsNN_sdcache_inv_range_32(vm_offset_t, vm_size_t); void mipsNN_sdcache_inv_range_64(vm_offset_t, vm_size_t); void mipsNN_sdcache_inv_range_128(vm_offset_t, vm_size_t); void mipsNN_sdcache_wb_range_32(vm_offset_t, vm_size_t); void mipsNN_sdcache_wb_range_64(vm_offset_t, vm_size_t); void mipsNN_sdcache_wb_range_128(vm_offset_t, vm_size_t); #endif /* _MACHINE_CACHE_MIPSNN_H_ */ Index: head/sys/mips/include/cache_r4k.h =================================================================== --- head/sys/mips/include/cache_r4k.h (revision 326258) +++ head/sys/mips/include/cache_r4k.h (revision 326259) @@ -1,434 +1,436 @@ /* $NetBSD: cache_r4k.h,v 1.10 2003/03/08 04:43:26 rafal Exp $ */ -/* +/*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright 2001 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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$ */ /* * Cache definitions/operations for R4000-style caches. */ #define CACHE_R4K_I 0 #define CACHE_R4K_D 1 #define CACHE_R4K_SI 2 #define CACHE_R4K_SD 3 #define CACHEOP_R4K_INDEX_INV (0 << 2) /* I, SI */ #define CACHEOP_R4K_INDEX_WB_INV (0 << 2) /* D, SD */ #define CACHEOP_R4K_INDEX_LOAD_TAG (1 << 2) /* all */ #define CACHEOP_R4K_INDEX_STORE_TAG (2 << 2) /* all */ #define CACHEOP_R4K_CREATE_DIRTY_EXCL (3 << 2) /* D, SD */ #define CACHEOP_R4K_HIT_INV (4 << 2) /* all */ #define CACHEOP_R4K_HIT_WB_INV (5 << 2) /* D, SD */ #define CACHEOP_R4K_FILL (5 << 2) /* I */ #define CACHEOP_R4K_HIT_WB (6 << 2) /* I, D, SD */ #define CACHEOP_R4K_HIT_SET_VIRTUAL (7 << 2) /* SI, SD */ #if !defined(LOCORE) /* * cache_r4k_op_line: * * Perform the specified cache operation on a single line. */ #define cache_op_r4k_line(va, op) \ do { \ __asm __volatile( \ ".set noreorder \n\t" \ "cache %1, 0(%0) \n\t" \ ".set reorder" \ : \ : "r" (va), "i" (op) \ : "memory"); \ } while (/*CONSTCOND*/0) /* * cache_r4k_op_8lines_16: * * Perform the specified cache operation on 8 16-byte cache lines. */ #define cache_r4k_op_8lines_16(va, op) \ do { \ __asm __volatile( \ ".set noreorder \n\t" \ "cache %1, 0x00(%0); cache %1, 0x10(%0) \n\t" \ "cache %1, 0x20(%0); cache %1, 0x30(%0) \n\t" \ "cache %1, 0x40(%0); cache %1, 0x50(%0) \n\t" \ "cache %1, 0x60(%0); cache %1, 0x70(%0) \n\t" \ ".set reorder" \ : \ : "r" (va), "i" (op) \ : "memory"); \ } while (/*CONSTCOND*/0) /* * cache_r4k_op_8lines_32: * * Perform the specified cache operation on 8 32-byte cache lines. */ #define cache_r4k_op_8lines_32(va, op) \ do { \ __asm __volatile( \ ".set noreorder \n\t" \ "cache %1, 0x00(%0); cache %1, 0x20(%0) \n\t" \ "cache %1, 0x40(%0); cache %1, 0x60(%0) \n\t" \ "cache %1, 0x80(%0); cache %1, 0xa0(%0) \n\t" \ "cache %1, 0xc0(%0); cache %1, 0xe0(%0) \n\t" \ ".set reorder" \ : \ : "r" (va), "i" (op) \ : "memory"); \ } while (/*CONSTCOND*/0) /* * cache_r4k_op_8lines_64: * * Perform the specified cache operation on 8 64-byte cache lines. */ #define cache_r4k_op_8lines_64(va, op) \ do { \ __asm __volatile( \ ".set noreorder \n\t" \ "cache %1, 0x000(%0); cache %1, 0x040(%0) \n\t" \ "cache %1, 0x080(%0); cache %1, 0x0c0(%0) \n\t" \ "cache %1, 0x100(%0); cache %1, 0x140(%0) \n\t" \ "cache %1, 0x180(%0); cache %1, 0x1c0(%0) \n\t" \ ".set reorder" \ : \ : "r" (va), "i" (op) \ : "memory"); \ } while (/*CONSTCOND*/0) /* * cache_r4k_op_32lines_16: * * Perform the specified cache operation on 32 16-byte * cache lines. */ #define cache_r4k_op_32lines_16(va, op) \ do { \ __asm __volatile( \ ".set noreorder \n\t" \ "cache %1, 0x000(%0); cache %1, 0x010(%0); \n\t" \ "cache %1, 0x020(%0); cache %1, 0x030(%0); \n\t" \ "cache %1, 0x040(%0); cache %1, 0x050(%0); \n\t" \ "cache %1, 0x060(%0); cache %1, 0x070(%0); \n\t" \ "cache %1, 0x080(%0); cache %1, 0x090(%0); \n\t" \ "cache %1, 0x0a0(%0); cache %1, 0x0b0(%0); \n\t" \ "cache %1, 0x0c0(%0); cache %1, 0x0d0(%0); \n\t" \ "cache %1, 0x0e0(%0); cache %1, 0x0f0(%0); \n\t" \ "cache %1, 0x100(%0); cache %1, 0x110(%0); \n\t" \ "cache %1, 0x120(%0); cache %1, 0x130(%0); \n\t" \ "cache %1, 0x140(%0); cache %1, 0x150(%0); \n\t" \ "cache %1, 0x160(%0); cache %1, 0x170(%0); \n\t" \ "cache %1, 0x180(%0); cache %1, 0x190(%0); \n\t" \ "cache %1, 0x1a0(%0); cache %1, 0x1b0(%0); \n\t" \ "cache %1, 0x1c0(%0); cache %1, 0x1d0(%0); \n\t" \ "cache %1, 0x1e0(%0); cache %1, 0x1f0(%0); \n\t" \ ".set reorder" \ : \ : "r" (va), "i" (op) \ : "memory"); \ } while (/*CONSTCOND*/0) /* * cache_r4k_op_32lines_32: * * Perform the specified cache operation on 32 32-byte * cache lines. */ #define cache_r4k_op_32lines_32(va, op) \ do { \ __asm __volatile( \ ".set noreorder \n\t" \ "cache %1, 0x000(%0); cache %1, 0x020(%0); \n\t" \ "cache %1, 0x040(%0); cache %1, 0x060(%0); \n\t" \ "cache %1, 0x080(%0); cache %1, 0x0a0(%0); \n\t" \ "cache %1, 0x0c0(%0); cache %1, 0x0e0(%0); \n\t" \ "cache %1, 0x100(%0); cache %1, 0x120(%0); \n\t" \ "cache %1, 0x140(%0); cache %1, 0x160(%0); \n\t" \ "cache %1, 0x180(%0); cache %1, 0x1a0(%0); \n\t" \ "cache %1, 0x1c0(%0); cache %1, 0x1e0(%0); \n\t" \ "cache %1, 0x200(%0); cache %1, 0x220(%0); \n\t" \ "cache %1, 0x240(%0); cache %1, 0x260(%0); \n\t" \ "cache %1, 0x280(%0); cache %1, 0x2a0(%0); \n\t" \ "cache %1, 0x2c0(%0); cache %1, 0x2e0(%0); \n\t" \ "cache %1, 0x300(%0); cache %1, 0x320(%0); \n\t" \ "cache %1, 0x340(%0); cache %1, 0x360(%0); \n\t" \ "cache %1, 0x380(%0); cache %1, 0x3a0(%0); \n\t" \ "cache %1, 0x3c0(%0); cache %1, 0x3e0(%0); \n\t" \ ".set reorder" \ : \ : "r" (va), "i" (op) \ : "memory"); \ } while (/*CONSTCOND*/0) /* * cache_r4k_op_32lines_64: * * Perform the specified cache operation on 32 64-byte * cache lines. */ #define cache_r4k_op_32lines_64(va, op) \ do { \ __asm __volatile( \ ".set noreorder \n\t" \ "cache %1, 0x000(%0); cache %1, 0x040(%0); \n\t" \ "cache %1, 0x080(%0); cache %1, 0x0c0(%0); \n\t" \ "cache %1, 0x100(%0); cache %1, 0x140(%0); \n\t" \ "cache %1, 0x180(%0); cache %1, 0x1c0(%0); \n\t" \ "cache %1, 0x200(%0); cache %1, 0x240(%0); \n\t" \ "cache %1, 0x280(%0); cache %1, 0x2c0(%0); \n\t" \ "cache %1, 0x300(%0); cache %1, 0x340(%0); \n\t" \ "cache %1, 0x380(%0); cache %1, 0x3c0(%0); \n\t" \ "cache %1, 0x400(%0); cache %1, 0x440(%0); \n\t" \ "cache %1, 0x480(%0); cache %1, 0x4c0(%0); \n\t" \ "cache %1, 0x500(%0); cache %1, 0x540(%0); \n\t" \ "cache %1, 0x580(%0); cache %1, 0x5c0(%0); \n\t" \ "cache %1, 0x600(%0); cache %1, 0x640(%0); \n\t" \ "cache %1, 0x680(%0); cache %1, 0x6c0(%0); \n\t" \ "cache %1, 0x700(%0); cache %1, 0x740(%0); \n\t" \ "cache %1, 0x780(%0); cache %1, 0x7c0(%0); \n\t" \ ".set reorder" \ : \ : "r" (va), "i" (op) \ : "memory"); \ } while (/*CONSTCOND*/0) /* * cache_r4k_op_32lines_128: * * Perform the specified cache operation on 32 128-byte * cache lines. */ #define cache_r4k_op_32lines_128(va, op) \ do { \ __asm __volatile( \ ".set noreorder \n\t" \ "cache %1, 0x0000(%0); cache %1, 0x0080(%0); \n\t" \ "cache %1, 0x0100(%0); cache %1, 0x0180(%0); \n\t" \ "cache %1, 0x0200(%0); cache %1, 0x0280(%0); \n\t" \ "cache %1, 0x0300(%0); cache %1, 0x0380(%0); \n\t" \ "cache %1, 0x0400(%0); cache %1, 0x0480(%0); \n\t" \ "cache %1, 0x0500(%0); cache %1, 0x0580(%0); \n\t" \ "cache %1, 0x0600(%0); cache %1, 0x0680(%0); \n\t" \ "cache %1, 0x0700(%0); cache %1, 0x0780(%0); \n\t" \ "cache %1, 0x0800(%0); cache %1, 0x0880(%0); \n\t" \ "cache %1, 0x0900(%0); cache %1, 0x0980(%0); \n\t" \ "cache %1, 0x0a00(%0); cache %1, 0x0a80(%0); \n\t" \ "cache %1, 0x0b00(%0); cache %1, 0x0b80(%0); \n\t" \ "cache %1, 0x0c00(%0); cache %1, 0x0c80(%0); \n\t" \ "cache %1, 0x0d00(%0); cache %1, 0x0d80(%0); \n\t" \ "cache %1, 0x0e00(%0); cache %1, 0x0e80(%0); \n\t" \ "cache %1, 0x0f00(%0); cache %1, 0x0f80(%0); \n\t" \ ".set reorder" \ : \ : "r" (va), "i" (op) \ : "memory"); \ } while (/*CONSTCOND*/0) /* * cache_r4k_op_16lines_16_2way: * * Perform the specified cache operation on 16 16-byte * cache lines, 2-ways. */ #define cache_r4k_op_16lines_16_2way(va1, va2, op) \ do { \ __asm __volatile( \ ".set noreorder \n\t" \ "cache %2, 0x000(%0); cache %2, 0x000(%1); \n\t" \ "cache %2, 0x010(%0); cache %2, 0x010(%1); \n\t" \ "cache %2, 0x020(%0); cache %2, 0x020(%1); \n\t" \ "cache %2, 0x030(%0); cache %2, 0x030(%1); \n\t" \ "cache %2, 0x040(%0); cache %2, 0x040(%1); \n\t" \ "cache %2, 0x050(%0); cache %2, 0x050(%1); \n\t" \ "cache %2, 0x060(%0); cache %2, 0x060(%1); \n\t" \ "cache %2, 0x070(%0); cache %2, 0x070(%1); \n\t" \ "cache %2, 0x080(%0); cache %2, 0x080(%1); \n\t" \ "cache %2, 0x090(%0); cache %2, 0x090(%1); \n\t" \ "cache %2, 0x0a0(%0); cache %2, 0x0a0(%1); \n\t" \ "cache %2, 0x0b0(%0); cache %2, 0x0b0(%1); \n\t" \ "cache %2, 0x0c0(%0); cache %2, 0x0c0(%1); \n\t" \ "cache %2, 0x0d0(%0); cache %2, 0x0d0(%1); \n\t" \ "cache %2, 0x0e0(%0); cache %2, 0x0e0(%1); \n\t" \ "cache %2, 0x0f0(%0); cache %2, 0x0f0(%1); \n\t" \ ".set reorder" \ : \ : "r" (va1), "r" (va2), "i" (op) \ : "memory"); \ } while (/*CONSTCOND*/0) /* * cache_r4k_op_16lines_32_2way: * * Perform the specified cache operation on 16 32-byte * cache lines, 2-ways. */ #define cache_r4k_op_16lines_32_2way(va1, va2, op) \ do { \ __asm __volatile( \ ".set noreorder \n\t" \ "cache %2, 0x000(%0); cache %2, 0x000(%1); \n\t" \ "cache %2, 0x020(%0); cache %2, 0x020(%1); \n\t" \ "cache %2, 0x040(%0); cache %2, 0x040(%1); \n\t" \ "cache %2, 0x060(%0); cache %2, 0x060(%1); \n\t" \ "cache %2, 0x080(%0); cache %2, 0x080(%1); \n\t" \ "cache %2, 0x0a0(%0); cache %2, 0x0a0(%1); \n\t" \ "cache %2, 0x0c0(%0); cache %2, 0x0c0(%1); \n\t" \ "cache %2, 0x0e0(%0); cache %2, 0x0e0(%1); \n\t" \ "cache %2, 0x100(%0); cache %2, 0x100(%1); \n\t" \ "cache %2, 0x120(%0); cache %2, 0x120(%1); \n\t" \ "cache %2, 0x140(%0); cache %2, 0x140(%1); \n\t" \ "cache %2, 0x160(%0); cache %2, 0x160(%1); \n\t" \ "cache %2, 0x180(%0); cache %2, 0x180(%1); \n\t" \ "cache %2, 0x1a0(%0); cache %2, 0x1a0(%1); \n\t" \ "cache %2, 0x1c0(%0); cache %2, 0x1c0(%1); \n\t" \ "cache %2, 0x1e0(%0); cache %2, 0x1e0(%1); \n\t" \ ".set reorder" \ : \ : "r" (va1), "r" (va2), "i" (op) \ : "memory"); \ } while (/*CONSTCOND*/0) /* * cache_r4k_op_8lines_16_4way: * * Perform the specified cache operation on 8 16-byte * cache lines, 4-ways. */ #define cache_r4k_op_8lines_16_4way(va1, va2, va3, va4, op) \ do { \ __asm __volatile( \ ".set noreorder \n\t" \ "cache %4, 0x000(%0); cache %4, 0x000(%1); \n\t" \ "cache %4, 0x000(%2); cache %4, 0x000(%3); \n\t" \ "cache %4, 0x010(%0); cache %4, 0x010(%1); \n\t" \ "cache %4, 0x010(%2); cache %4, 0x010(%3); \n\t" \ "cache %4, 0x020(%0); cache %4, 0x020(%1); \n\t" \ "cache %4, 0x020(%2); cache %4, 0x020(%3); \n\t" \ "cache %4, 0x030(%0); cache %4, 0x030(%1); \n\t" \ "cache %4, 0x030(%2); cache %4, 0x030(%3); \n\t" \ "cache %4, 0x040(%0); cache %4, 0x040(%1); \n\t" \ "cache %4, 0x040(%2); cache %4, 0x040(%3); \n\t" \ "cache %4, 0x050(%0); cache %4, 0x050(%1); \n\t" \ "cache %4, 0x050(%2); cache %4, 0x050(%3); \n\t" \ "cache %4, 0x060(%0); cache %4, 0x060(%1); \n\t" \ "cache %4, 0x060(%2); cache %4, 0x060(%3); \n\t" \ "cache %4, 0x070(%0); cache %4, 0x070(%1); \n\t" \ "cache %4, 0x070(%2); cache %4, 0x070(%3); \n\t" \ ".set reorder" \ : \ : "r" (va1), "r" (va2), "r" (va3), "r" (va4), "i" (op) \ : "memory"); \ } while (/*CONSTCOND*/0) /* * cache_r4k_op_8lines_32_4way: * * Perform the specified cache operation on 8 32-byte * cache lines, 4-ways. */ #define cache_r4k_op_8lines_32_4way(va1, va2, va3, va4, op) \ do { \ __asm __volatile( \ ".set noreorder \n\t" \ "cache %4, 0x000(%0); cache %4, 0x000(%1); \n\t" \ "cache %4, 0x000(%2); cache %4, 0x000(%3); \n\t" \ "cache %4, 0x020(%0); cache %4, 0x020(%1); \n\t" \ "cache %4, 0x020(%2); cache %4, 0x020(%3); \n\t" \ "cache %4, 0x040(%0); cache %4, 0x040(%1); \n\t" \ "cache %4, 0x040(%2); cache %4, 0x040(%3); \n\t" \ "cache %4, 0x060(%0); cache %4, 0x060(%1); \n\t" \ "cache %4, 0x060(%2); cache %4, 0x060(%3); \n\t" \ "cache %4, 0x080(%0); cache %4, 0x080(%1); \n\t" \ "cache %4, 0x080(%2); cache %4, 0x080(%3); \n\t" \ "cache %4, 0x0a0(%0); cache %4, 0x0a0(%1); \n\t" \ "cache %4, 0x0a0(%2); cache %4, 0x0a0(%3); \n\t" \ "cache %4, 0x0c0(%0); cache %4, 0x0c0(%1); \n\t" \ "cache %4, 0x0c0(%2); cache %4, 0x0c0(%3); \n\t" \ "cache %4, 0x0e0(%0); cache %4, 0x0e0(%1); \n\t" \ "cache %4, 0x0e0(%2); cache %4, 0x0e0(%3); \n\t" \ ".set reorder" \ : \ : "r" (va1), "r" (va2), "r" (va3), "r" (va4), "i" (op) \ : "memory"); \ } while (/*CONSTCOND*/0) void r4k_icache_sync_all_16(void); void r4k_icache_sync_range_16(vm_paddr_t, vm_size_t); void r4k_icache_sync_range_index_16(vm_paddr_t, vm_size_t); void r4k_icache_sync_all_32(void); void r4k_icache_sync_range_32(vm_paddr_t, vm_size_t); void r4k_icache_sync_range_index_32(vm_paddr_t, vm_size_t); void r4k_pdcache_wbinv_all_16(void); void r4k_pdcache_wbinv_range_16(vm_paddr_t, vm_size_t); void r4k_pdcache_wbinv_range_index_16(vm_paddr_t, vm_size_t); void r4k_pdcache_inv_range_16(vm_paddr_t, vm_size_t); void r4k_pdcache_wb_range_16(vm_paddr_t, vm_size_t); void r4k_pdcache_wbinv_all_32(void); void r4k_pdcache_wbinv_range_32(vm_paddr_t, vm_size_t); void r4k_pdcache_wbinv_range_index_32(vm_paddr_t, vm_size_t); void r4k_pdcache_inv_range_32(vm_paddr_t, vm_size_t); void r4k_pdcache_wb_range_32(vm_paddr_t, vm_size_t); void r4k_sdcache_wbinv_all_32(void); void r4k_sdcache_wbinv_range_32(vm_paddr_t, vm_size_t); void r4k_sdcache_wbinv_range_index_32(vm_paddr_t, vm_size_t); void r4k_sdcache_inv_range_32(vm_paddr_t, vm_size_t); void r4k_sdcache_wb_range_32(vm_paddr_t, vm_size_t); void r4k_sdcache_wbinv_all_128(void); void r4k_sdcache_wbinv_range_128(vm_paddr_t, vm_size_t); void r4k_sdcache_wbinv_range_index_128(vm_paddr_t, vm_size_t); void r4k_sdcache_inv_range_128(vm_paddr_t, vm_size_t); void r4k_sdcache_wb_range_128(vm_paddr_t, vm_size_t); void r4k_sdcache_wbinv_all_generic(void); void r4k_sdcache_wbinv_range_generic(vm_paddr_t, vm_size_t); void r4k_sdcache_wbinv_range_index_generic(vm_paddr_t, vm_size_t); void r4k_sdcache_inv_range_generic(vm_paddr_t, vm_size_t); void r4k_sdcache_wb_range_generic(vm_paddr_t, vm_size_t); #endif /* !LOCORE */ Index: head/sys/mips/include/counter.h =================================================================== --- head/sys/mips/include/counter.h (revision 326258) +++ head/sys/mips/include/counter.h (revision 326259) @@ -1,96 +1,98 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2012 Konstantin Belousov * 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$ */ #ifndef __MACHINE_COUNTER_H__ #define __MACHINE_COUNTER_H__ #include #ifdef INVARIANTS #include #endif #define EARLY_COUNTER &((struct pcpu *)pcpu_space)->pc_early_dummy_counter #define counter_enter() critical_enter() #define counter_exit() critical_exit() #ifdef IN_SUBR_COUNTER_C /* XXXKIB non-atomic 64bit read on 32bit */ static inline uint64_t counter_u64_read_one(uint64_t *p, int cpu) { return (*(uint64_t *)((char *)p + sizeof(struct pcpu) * cpu)); } static inline uint64_t counter_u64_fetch_inline(uint64_t *p) { uint64_t r; int i; r = 0; for (i = 0; i < mp_ncpus; i++) r += counter_u64_read_one((uint64_t *)p, i); return (r); } /* XXXKIB non-atomic 64bit store on 32bit, might interrupt increment */ static void counter_u64_zero_one_cpu(void *arg) { *((uint64_t *)((char *)arg + sizeof(struct pcpu) * PCPU_GET(cpuid))) = 0; } static inline void counter_u64_zero_inline(counter_u64_t c) { smp_rendezvous(smp_no_rendezvous_barrier, counter_u64_zero_one_cpu, smp_no_rendezvous_barrier, c); } #endif #define counter_u64_add_protected(c, inc) do { \ CRITICAL_ASSERT(curthread); \ *(uint64_t *)zpcpu_get(c) += (inc); \ } while (0) static inline void counter_u64_add(counter_u64_t c, int64_t inc) { counter_enter(); counter_u64_add_protected(c, inc); counter_exit(); } #endif /* ! __MACHINE_COUNTER_H__ */ Index: head/sys/mips/include/cpufunc.h =================================================================== --- head/sys/mips/include/cpufunc.h (revision 326258) +++ head/sys/mips/include/cpufunc.h (revision 326259) @@ -1,394 +1,396 @@ /* $OpenBSD: pio.h,v 1.2 1998/09/15 10:50:12 pefo Exp $ */ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-4-Clause + * * Copyright (c) 2002-2004 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. */ /* * Copyright (c) 1995-1999 Per Fogelstrom. 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Per Fogelstrom. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. * * JNPR: cpufunc.h,v 1.5 2007/08/09 11:23:32 katta * $FreeBSD$ */ #ifndef _MACHINE_CPUFUNC_H_ #define _MACHINE_CPUFUNC_H_ #include #include /* * These functions are required by user-land atomi ops */ static __inline void mips_barrier(void) { #if defined(CPU_CNMIPS) || defined(CPU_RMI) || defined(CPU_NLM) __compiler_membar(); #else __asm __volatile (".set noreorder\n\t" "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t" ".set reorder\n\t" : : : "memory"); #endif } static __inline void mips_cp0_sync(void) { __asm __volatile (__XSTRING(COP0_SYNC)); } static __inline void mips_wbflush(void) { #if defined(CPU_CNMIPS) __asm __volatile (".set noreorder\n\t" "syncw\n\t" ".set reorder\n" : : : "memory"); #else __asm __volatile ("sync" : : : "memory"); mips_barrier(); #endif } #ifdef _KERNEL /* * XXX * It would be nice to add variants that read/write register_t, to avoid some * ABI checks. */ #if defined(__mips_n32) || defined(__mips_n64) #define MIPS_RW64_COP0(n,r) \ static __inline uint64_t \ mips_rd_ ## n (void) \ { \ int v0; \ __asm __volatile ("dmfc0 %[v0], $"__XSTRING(r)";" \ : [v0] "=&r"(v0)); \ mips_barrier(); \ return (v0); \ } \ static __inline void \ mips_wr_ ## n (uint64_t a0) \ { \ __asm __volatile ("dmtc0 %[a0], $"__XSTRING(r)";" \ __XSTRING(COP0_SYNC)";" \ "nop;" \ "nop;" \ : \ : [a0] "r"(a0)); \ mips_barrier(); \ } struct __hack #define MIPS_RW64_COP0_SEL(n,r,s) \ static __inline uint64_t \ mips_rd_ ## n(void) \ { \ int v0; \ __asm __volatile ("dmfc0 %[v0], $"__XSTRING(r)", "__XSTRING(s)";" \ : [v0] "=&r"(v0)); \ mips_barrier(); \ return (v0); \ } \ static __inline void \ mips_wr_ ## n(uint64_t a0) \ { \ __asm __volatile ("dmtc0 %[a0], $"__XSTRING(r)", "__XSTRING(s)";" \ __XSTRING(COP0_SYNC)";" \ : \ : [a0] "r"(a0)); \ mips_barrier(); \ } struct __hack #if defined(__mips_n64) MIPS_RW64_COP0(excpc, MIPS_COP_0_EXC_PC); MIPS_RW64_COP0(entryhi, MIPS_COP_0_TLB_HI); MIPS_RW64_COP0(pagemask, MIPS_COP_0_TLB_PG_MASK); MIPS_RW64_COP0_SEL(userlocal, MIPS_COP_0_USERLOCAL, 2); #ifdef CPU_CNMIPS MIPS_RW64_COP0_SEL(cvmcount, MIPS_COP_0_COUNT, 6); MIPS_RW64_COP0_SEL(cvmctl, MIPS_COP_0_COUNT, 7); MIPS_RW64_COP0_SEL(cvmmemctl, MIPS_COP_0_COMPARE, 7); MIPS_RW64_COP0_SEL(icache_err, MIPS_COP_0_CACHE_ERR, 0); MIPS_RW64_COP0_SEL(dcache_err, MIPS_COP_0_CACHE_ERR, 1); #endif #endif #if defined(__mips_n64) || defined(__mips_n32) /* PHYSADDR_64_BIT */ MIPS_RW64_COP0(entrylo0, MIPS_COP_0_TLB_LO0); MIPS_RW64_COP0(entrylo1, MIPS_COP_0_TLB_LO1); #endif MIPS_RW64_COP0(xcontext, MIPS_COP_0_TLB_XCONTEXT); #undef MIPS_RW64_COP0 #undef MIPS_RW64_COP0_SEL #endif #define MIPS_RW32_COP0(n,r) \ static __inline uint32_t \ mips_rd_ ## n (void) \ { \ int v0; \ __asm __volatile ("mfc0 %[v0], $"__XSTRING(r)";" \ : [v0] "=&r"(v0)); \ mips_barrier(); \ return (v0); \ } \ static __inline void \ mips_wr_ ## n (uint32_t a0) \ { \ __asm __volatile ("mtc0 %[a0], $"__XSTRING(r)";" \ __XSTRING(COP0_SYNC)";" \ "nop;" \ "nop;" \ : \ : [a0] "r"(a0)); \ mips_barrier(); \ } struct __hack #define MIPS_RW32_COP0_SEL(n,r,s) \ static __inline uint32_t \ mips_rd_ ## n(void) \ { \ int v0; \ __asm __volatile ("mfc0 %[v0], $"__XSTRING(r)", "__XSTRING(s)";" \ : [v0] "=&r"(v0)); \ mips_barrier(); \ return (v0); \ } \ static __inline void \ mips_wr_ ## n(uint32_t a0) \ { \ __asm __volatile ("mtc0 %[a0], $"__XSTRING(r)", "__XSTRING(s)";" \ __XSTRING(COP0_SYNC)";" \ "nop;" \ "nop;" \ : \ : [a0] "r"(a0)); \ mips_barrier(); \ } struct __hack #ifdef CPU_CNMIPS static __inline void mips_sync_icache (void) { __asm __volatile ( ".set push\n" ".set mips64\n" ".word 0x041f0000\n" /* xxx ICACHE */ "nop\n" ".set pop\n" : : ); } #endif MIPS_RW32_COP0(compare, MIPS_COP_0_COMPARE); MIPS_RW32_COP0(config, MIPS_COP_0_CONFIG); MIPS_RW32_COP0_SEL(config1, MIPS_COP_0_CONFIG, 1); MIPS_RW32_COP0_SEL(config2, MIPS_COP_0_CONFIG, 2); MIPS_RW32_COP0_SEL(config3, MIPS_COP_0_CONFIG, 3); #ifdef CPU_CNMIPS MIPS_RW32_COP0_SEL(config4, MIPS_COP_0_CONFIG, 4); #endif #ifdef BERI_LARGE_TLB MIPS_RW32_COP0_SEL(config5, MIPS_COP_0_CONFIG, 5); #endif #if defined(CPU_NLM) || defined(BERI_LARGE_TLB) MIPS_RW32_COP0_SEL(config6, MIPS_COP_0_CONFIG, 6); #endif #if defined(CPU_NLM) || defined(CPU_MIPS1004K) || defined (CPU_MIPS74K) || \ defined(CPU_MIPS24K) MIPS_RW32_COP0_SEL(config7, MIPS_COP_0_CONFIG, 7); #endif MIPS_RW32_COP0(count, MIPS_COP_0_COUNT); MIPS_RW32_COP0(index, MIPS_COP_0_TLB_INDEX); MIPS_RW32_COP0(wired, MIPS_COP_0_TLB_WIRED); MIPS_RW32_COP0(cause, MIPS_COP_0_CAUSE); #if !defined(__mips_n64) MIPS_RW32_COP0(excpc, MIPS_COP_0_EXC_PC); #endif MIPS_RW32_COP0(status, MIPS_COP_0_STATUS); MIPS_RW32_COP0_SEL(cmgcrbase, 15, 3); /* XXX: Some of these registers are specific to MIPS32. */ #if !defined(__mips_n64) MIPS_RW32_COP0(entryhi, MIPS_COP_0_TLB_HI); MIPS_RW32_COP0(pagemask, MIPS_COP_0_TLB_PG_MASK); MIPS_RW32_COP0_SEL(userlocal, MIPS_COP_0_USERLOCAL, 2); #endif #ifdef CPU_NLM MIPS_RW32_COP0_SEL(pagegrain, MIPS_COP_0_TLB_PG_MASK, 1); #endif #if !defined(__mips_n64) && !defined(__mips_n32) /* !PHYSADDR_64_BIT */ MIPS_RW32_COP0(entrylo0, MIPS_COP_0_TLB_LO0); MIPS_RW32_COP0(entrylo1, MIPS_COP_0_TLB_LO1); #endif MIPS_RW32_COP0(prid, MIPS_COP_0_PRID); /* XXX 64-bit? */ MIPS_RW32_COP0_SEL(ebase, MIPS_COP_0_PRID, 1); #if defined(CPU_MIPS24K) || defined(CPU_MIPS34K) || \ defined(CPU_MIPS74K) || defined(CPU_MIPS1004K) || \ defined(CPU_MIPS1074K) || defined(CPU_INTERAPTIV) || \ defined(CPU_PROAPTIV) /* MIPS32/64 r2 intctl */ MIPS_RW32_COP0_SEL(intctl, MIPS_COP_0_INTCTL, 1); #endif #ifdef CPU_XBURST MIPS_RW32_COP0_SEL(xburst_mbox0, MIPS_COP_0_XBURST_MBOX, 0); MIPS_RW32_COP0_SEL(xburst_mbox1, MIPS_COP_0_XBURST_MBOX, 1); MIPS_RW32_COP0_SEL(xburst_core_ctl, MIPS_COP_0_XBURST_C12, 2); MIPS_RW32_COP0_SEL(xburst_core_sts, MIPS_COP_0_XBURST_C12, 3); MIPS_RW32_COP0_SEL(xburst_reim, MIPS_COP_0_XBURST_C12, 4); #endif MIPS_RW32_COP0(watchlo, MIPS_COP_0_WATCH_LO); MIPS_RW32_COP0_SEL(watchlo1, MIPS_COP_0_WATCH_LO, 1); MIPS_RW32_COP0_SEL(watchlo2, MIPS_COP_0_WATCH_LO, 2); MIPS_RW32_COP0_SEL(watchlo3, MIPS_COP_0_WATCH_LO, 3); MIPS_RW32_COP0(watchhi, MIPS_COP_0_WATCH_HI); MIPS_RW32_COP0_SEL(watchhi1, MIPS_COP_0_WATCH_HI, 1); MIPS_RW32_COP0_SEL(watchhi2, MIPS_COP_0_WATCH_HI, 2); MIPS_RW32_COP0_SEL(watchhi3, MIPS_COP_0_WATCH_HI, 3); MIPS_RW32_COP0_SEL(perfcnt0, MIPS_COP_0_PERFCNT, 0); MIPS_RW32_COP0_SEL(perfcnt1, MIPS_COP_0_PERFCNT, 1); MIPS_RW32_COP0_SEL(perfcnt2, MIPS_COP_0_PERFCNT, 2); MIPS_RW32_COP0_SEL(perfcnt3, MIPS_COP_0_PERFCNT, 3); MIPS_RW32_COP0(hwrena, MIPS_COP_0_HWRENA); #undef MIPS_RW32_COP0 #undef MIPS_RW32_COP0_SEL static __inline register_t intr_disable(void) { register_t s; s = mips_rd_status(); mips_wr_status(s & ~MIPS_SR_INT_IE); return (s & MIPS_SR_INT_IE); } static __inline register_t intr_enable(void) { register_t s; s = mips_rd_status(); mips_wr_status(s | MIPS_SR_INT_IE); return (s); } static __inline void intr_restore(register_t ie) { if (ie == MIPS_SR_INT_IE) { intr_enable(); } } static __inline uint32_t set_intr_mask(uint32_t mask) { uint32_t ostatus; ostatus = mips_rd_status(); mask = (ostatus & ~MIPS_SR_INT_MASK) | (mask & MIPS_SR_INT_MASK); mips_wr_status(mask); return (ostatus); } static __inline uint32_t get_intr_mask(void) { return (mips_rd_status() & MIPS_SR_INT_MASK); } static __inline void breakpoint(void) { __asm __volatile ("break"); } #if defined(__GNUC__) && !defined(__mips_o32) #define mips3_ld(a) (*(const volatile uint64_t *)(a)) #define mips3_sd(a, v) (*(volatile uint64_t *)(a) = (v)) #else uint64_t mips3_ld(volatile uint64_t *va); void mips3_sd(volatile uint64_t *, uint64_t); #endif /* __GNUC__ */ #endif /* _KERNEL */ #define readb(va) (*(volatile uint8_t *) (va)) #define readw(va) (*(volatile uint16_t *) (va)) #define readl(va) (*(volatile uint32_t *) (va)) #if defined(__GNUC__) && !defined(__mips_o32) #define readq(a) (*(volatile uint64_t *)(a)) #endif #define writeb(va, d) (*(volatile uint8_t *) (va) = (d)) #define writew(va, d) (*(volatile uint16_t *) (va) = (d)) #define writel(va, d) (*(volatile uint32_t *) (va) = (d)) #if defined(__GNUC__) && !defined(__mips_o32) #define writeq(va, d) (*(volatile uint64_t *) (va) = (d)) #endif #endif /* !_MACHINE_CPUFUNC_H_ */ Index: head/sys/mips/include/db_machdep.h =================================================================== --- head/sys/mips/include/db_machdep.h (revision 326258) +++ head/sys/mips/include/db_machdep.h (revision 326259) @@ -1,95 +1,97 @@ /* $OpenBSD: db_machdep.h,v 1.2 1998/09/15 10:50:12 pefo Exp $ */ -/* +/*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright (c) 1998 Per Fogelstrom, Opsycon AB * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed under OpenBSD by * Per Fogelstrom, Opsycon AB, Sweden. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. * * JNPR: db_machdep.h,v 1.7 2006/10/16 12:30:34 katta * $FreeBSD$ */ #ifndef _MIPS_DB_MACHDEP_H_ #define _MIPS_DB_MACHDEP_H_ #include #include #include typedef struct trapframe db_regs_t; extern db_regs_t ddb_regs; /* register state */ typedef vm_offset_t db_addr_t; /* address - unsigned */ typedef register_t db_expr_t; /* expression - signed */ #if BYTE_ORDER == _BIG_ENDIAN #define BYTE_MSF (1) #endif #define SOFTWARE_SSTEP /* Need software single step */ #define SOFTWARE_SSTEP_EMUL /* next_instr_address() emulates 100% */ db_addr_t next_instr_address(db_addr_t, boolean_t); #define BKPT_SIZE (4) #define BKPT_SET(ins) (MIPS_BREAK_DDB) #define DB_VALID_BREAKPOINT(addr) (((addr) & 3) == 0) #define IS_BREAKPOINT_TRAP(type, code) ((type) == T_BREAK) #define IS_WATCHPOINT_TRAP(type, code) (0) /* XXX mips3 watchpoint */ #define PC_REGS() ((db_addr_t)kdb_thrctx->pcb_regs.pc) #define BKPT_SKIP \ do { \ if((db_get_value(kdb_frame->pc, sizeof(int), FALSE) & \ ~MIPS_BREAK_VAL_MASK) == MIPS_BREAK_INSTR) { \ kdb_frame->pc += BKPT_SIZE; \ kdb_thrctx->pcb_regs.pc += BKPT_SIZE; \ } \ } while (0); /* * Test of instructions to see class. */ #define IT_CALL 0x01 #define IT_BRANCH 0x02 #define IT_LOAD 0x03 #define IT_STORE 0x04 #define inst_branch(i) (db_inst_type(i) == IT_BRANCH) #define inst_trap_return(i) ((i) & 0) #define inst_call(i) (db_inst_type(i) == IT_CALL) #define inst_return(i) ((i) == 0x03e00008) #define inst_load(i) (db_inst_type(i) == IT_LOAD) #define inst_store(i) (db_inst_type(i) == IT_STORE) int db_inst_type(int); db_addr_t branch_taken(int inst, db_addr_t pc); int32_t kdbpeek(int *); int64_t kdbpeekd(int *); #endif /* !_MIPS_DB_MACHDEP_H_ */ Index: head/sys/mips/include/elf.h =================================================================== --- head/sys/mips/include/elf.h (revision 326258) +++ head/sys/mips/include/elf.h (revision 326259) @@ -1,264 +1,266 @@ -/* +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-2-Clause-NetBSD + * * Copyright (c) 2013 M. Warner Losh. 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$ */ /*- * Copyright (c) 2013 The NetBSD Foundation, Inc. * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. * * See below starting with the line with $NetBSD...$ for code this applies to. */ #ifndef __MIPS_ELF_H #define __MIPS_ELF_H /* FreeBSD specific bits - derived from FreeBSD specific files and changes to old elf.h */ /* * Define __ELF_WORD_SIZE based on the ABI, if not defined yet. This sets * the proper defaults when we're not trying to do 32-bit on 64-bit systems. * We include both 32 and 64 bit versions so we can support multiple ABIs. */ #ifndef __ELF_WORD_SIZE #if defined(__mips_n64) #define __ELF_WORD_SIZE 64 #else #define __ELF_WORD_SIZE 32 #endif #endif #include #include #include #define ELF_ARCH EM_MIPS #define ELF_ARCH32 EM_MIPS #define ELF_MACHINE_OK(x) ((x) == ELF_ARCH) /* Define "machine" characteristics */ #if __ELF_WORD_SIZE == 32 #define ELF_TARG_CLASS ELFCLASS32 #else #define ELF_TARG_CLASS ELFCLASS64 #endif #ifdef __MIPSEB__ #define ELF_TARG_DATA ELFDATA2MSB #else #define ELF_TARG_DATA ELFDATA2LSB #endif #define ELF_TARG_MACH EM_MIPS #define ELF_TARG_VER 1 /* * Auxiliary vector entries for passing information to the interpreter. * * The i386 supplement to the SVR4 ABI specification names this "auxv_t", * but POSIX lays claim to all symbols ending with "_t". */ typedef struct { /* Auxiliary vector entry on initial stack */ int a_type; /* Entry type. */ union { int a_val; /* Integer value. */ void *a_ptr; /* Address. */ void (*a_fcn)(void); /* Function pointer (not used). */ } a_un; } Elf32_Auxinfo; typedef struct { /* Auxiliary vector entry on initial stack */ long a_type; /* Entry type. */ union { long a_val; /* Integer value. */ void *a_ptr; /* Address. */ void (*a_fcn)(void); /* Function pointer (not used). */ } a_un; } Elf64_Auxinfo; __ElfType(Auxinfo); /* Values for a_type. */ #define AT_NULL 0 /* Terminates the vector. */ #define AT_IGNORE 1 /* Ignored entry. */ #define AT_EXECFD 2 /* File descriptor of program to load. */ #define AT_PHDR 3 /* Program header of program already loaded. */ #define AT_PHENT 4 /* Size of each program header entry. */ #define AT_PHNUM 5 /* Number of program header entries. */ #define AT_PAGESZ 6 /* Page size in bytes. */ #define AT_BASE 7 /* Interpreter's base address. */ #define AT_FLAGS 8 /* Flags (unused for i386). */ #define AT_ENTRY 9 /* Where interpreter should transfer control. */ #define AT_NOTELF 10 /* Program is not ELF ?? */ #define AT_UID 11 /* Real uid. */ #define AT_EUID 12 /* Effective uid. */ #define AT_GID 13 /* Real gid. */ #define AT_EGID 14 /* Effective gid. */ #define AT_EXECPATH 15 /* Path to the executable. */ #define AT_CANARY 16 /* Canary for SSP */ #define AT_CANARYLEN 17 /* Length of the canary. */ #define AT_OSRELDATE 18 /* OSRELDATE. */ #define AT_NCPUS 19 /* Number of CPUs. */ #define AT_PAGESIZES 20 /* Pagesizes. */ #define AT_PAGESIZESLEN 21 /* Number of pagesizes. */ #define AT_TIMEKEEP 22 /* Pointer to timehands. */ #define AT_STACKPROT 23 /* Initial stack protection. */ #define AT_EHDRFLAGS 24 /* e_flags field from elf hdr */ #define AT_HWCAP 25 /* CPU feature flags. */ #define AT_HWCAP2 26 /* CPU feature flags 2. */ #define AT_COUNT 27 /* Count of defined aux entry types. */ #define ET_DYN_LOAD_ADDR 0x0120000 /* * Constant to mark start of symtab/strtab saved by trampoline */ #define SYMTAB_MAGIC 0x64656267 /* from NetBSD's sys/mips/include/elf_machdep.h $NetBSD: elf_machdep.h,v 1.18 2013/05/23 21:39:49 christos Exp $ */ /* mips relocs. */ #define R_MIPS_NONE 0 #define R_MIPS_16 1 #define R_MIPS_32 2 #define R_MIPS_REL32 3 #define R_MIPS_REL R_MIPS_REL32 #define R_MIPS_26 4 #define R_MIPS_HI16 5 /* high 16 bits of symbol value */ #define R_MIPS_LO16 6 /* low 16 bits of symbol value */ #define R_MIPS_GPREL16 7 /* GP-relative reference */ #define R_MIPS_LITERAL 8 /* Reference to literal section */ #define R_MIPS_GOT16 9 /* Reference to global offset table */ #define R_MIPS_GOT R_MIPS_GOT16 #define R_MIPS_PC16 10 /* 16 bit PC relative reference */ #define R_MIPS_CALL16 11 /* 16 bit call thru glbl offset tbl */ #define R_MIPS_CALL R_MIPS_CALL16 #define R_MIPS_GPREL32 12 /* 13, 14, 15 are not defined at this point. */ #define R_MIPS_UNUSED1 13 #define R_MIPS_UNUSED2 14 #define R_MIPS_UNUSED3 15 /* * The remaining relocs are apparently part of the 64-bit Irix ELF ABI. */ #define R_MIPS_SHIFT5 16 #define R_MIPS_SHIFT6 17 #define R_MIPS_64 18 #define R_MIPS_GOT_DISP 19 #define R_MIPS_GOT_PAGE 20 #define R_MIPS_GOT_OFST 21 #define R_MIPS_GOT_HI16 22 #define R_MIPS_GOT_LO16 23 #define R_MIPS_SUB 24 #define R_MIPS_INSERT_A 25 #define R_MIPS_INSERT_B 26 #define R_MIPS_DELETE 27 #define R_MIPS_HIGHER 28 #define R_MIPS_HIGHEST 29 #define R_MIPS_CALL_HI16 30 #define R_MIPS_CALL_LO16 31 #define R_MIPS_SCN_DISP 32 #define R_MIPS_REL16 33 #define R_MIPS_ADD_IMMEDIATE 34 #define R_MIPS_PJUMP 35 #define R_MIPS_RELGOT 36 #define R_MIPS_JALR 37 /* TLS relocations */ #define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */ #define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */ #define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */ #define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */ #define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */ #define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */ #define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */ #define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */ #define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */ #define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */ #define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */ #define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */ #define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */ #define R_MIPS_max 51 #define R_TYPE(name) __CONCAT(R_MIPS_,name) #define R_MIPS16_min 100 #define R_MIPS16_26 100 #define R_MIPS16_GPREL 101 #define R_MIPS16_GOT16 102 #define R_MIPS16_CALL16 103 #define R_MIPS16_HI16 104 #define R_MIPS16_LO16 105 #define R_MIPS16_max 106 #define R_MIPS_COPY 126 #define R_MIPS_JUMP_SLOT 127 /* * ELF Flags */ #define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code */ #define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code */ #define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code */ #define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code */ #define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code */ #define EF_MIPS_ARCH_32 0x50000000 /* -mips32 code */ #define EF_MIPS_ARCH_64 0x60000000 /* -mips64 code */ #define EF_MIPS_ARCH_32R2 0x70000000 /* -mips32r2 code */ #define EF_MIPS_ARCH_64R2 0x80000000 /* -mips64r2 code */ #define EF_MIPS_ABI 0x0000f000 #define EF_MIPS_ABI_O32 0x00001000 #define EF_MIPS_ABI_O64 0x00002000 #define EF_MIPS_ABI_EABI32 0x00003000 #define EF_MIPS_ABI_EABI64 0x00004000 #endif /* __MIPS_ELF_H */ Index: head/sys/mips/include/fdt.h =================================================================== --- head/sys/mips/include/fdt.h (revision 326258) +++ head/sys/mips/include/fdt.h (revision 326259) @@ -1,46 +1,48 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 The FreeBSD Foundation * All rights reserved. * * This software was developed by Semihalf under sponsorship from * the FreeBSD Foundation. * * 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$ */ #ifndef _MACHINE_FDT_H_ #define _MACHINE_FDT_H_ #include /* * Bus space tag. XXX endianess info needs to be derived from the blob. */ #if defined(CPU_RMI) || defined(CPU_NLM) #define fdtbus_bs_tag rmi_uart_bus_space #else #define fdtbus_bs_tag mips_bus_space_generic #endif #endif /* _MACHINE_FDT_H_ */ Index: head/sys/mips/include/frame.h =================================================================== --- head/sys/mips/include/frame.h (revision 326258) +++ head/sys/mips/include/frame.h (revision 326259) @@ -1,140 +1,142 @@ /* $OpenBSD: frame.h,v 1.3 1998/09/15 10:50:12 pefo Exp $ */ /*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright (c) 1998 Per Fogelstrom, Opsycon AB * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed under OpenBSD by * Per Fogelstrom, Opsycon AB, Sweden. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. * * JNPR: frame.h,v 1.6.2.1 2007/09/10 08:14:57 girish * $FreeBSD$ * */ #ifndef _MACHINE_FRAME_H_ #define _MACHINE_FRAME_H_ /* Note: This must also match regnum.h and regdef.h */ struct trapframe { register_t zero; register_t ast; register_t v0; register_t v1; register_t a0; register_t a1; register_t a2; register_t a3; #if defined(__mips_n32) || defined(__mips_n64) register_t a4; register_t a5; register_t a6; register_t a7; register_t t0; register_t t1; register_t t2; register_t t3; #else register_t t0; register_t t1; register_t t2; register_t t3; register_t t4; register_t t5; register_t t6; register_t t7; #endif register_t s0; register_t s1; register_t s2; register_t s3; register_t s4; register_t s5; register_t s6; register_t s7; register_t t8; register_t t9; register_t k0; register_t k1; register_t gp; register_t sp; register_t s8; register_t ra; register_t sr; register_t mullo; register_t mulhi; register_t badvaddr; register_t cause; register_t pc; /* * FREEBSD_DEVELOPERS_FIXME: * Include any other registers which are CPU-Specific and * need to be part of the frame here. * * Also, be sure this matches what is defined in regnum.h */ register_t ic; /* RM7k and RM9k specific */ register_t dummy; /* Alignment for 32-bit case */ /* From here and on, only saved user processes. */ f_register_t f0; f_register_t f1; f_register_t f2; f_register_t f3; f_register_t f4; f_register_t f5; f_register_t f6; f_register_t f7; f_register_t f8; f_register_t f9; f_register_t f10; f_register_t f11; f_register_t f12; f_register_t f13; f_register_t f14; f_register_t f15; f_register_t f16; f_register_t f17; f_register_t f18; f_register_t f19; f_register_t f20; f_register_t f21; f_register_t f22; f_register_t f23; f_register_t f24; f_register_t f25; f_register_t f26; f_register_t f27; f_register_t f28; f_register_t f29; f_register_t f30; f_register_t f31; register_t fsr; register_t fir; }; #endif /* !_MACHINE_FRAME_H_ */ Index: head/sys/mips/include/gdb_machdep.h =================================================================== --- head/sys/mips/include/gdb_machdep.h (revision 326258) +++ head/sys/mips/include/gdb_machdep.h (revision 326259) @@ -1,56 +1,58 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2004 Marcel Moolenaar * 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 ``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 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. * * from: src/sys/alpha/include/gdb_machdep.h,v 1.3 2005/01/05 20:05:50 imp * JNPR: gdb_machdep.h,v 1.1 2007/08/09 12:25:25 katta * $FreeBSD$ */ #ifndef _MACHINE_GDB_MACHDEP_H_ #define _MACHINE_GDB_MACHDEP_H_ #define GDB_BUFSZ 600 #define GDB_NREGS 90 #define GDB_REG_PC 37 static __inline size_t gdb_cpu_regsz(int regnum) { return (sizeof(long)); } static __inline int gdb_cpu_query(void) { return (0); } void *gdb_cpu_getreg(int, size_t *); void gdb_cpu_setreg(int, void *); int gdb_cpu_signal(int, int); #endif /* !_MACHINE_GDB_MACHDEP_H_ */ Index: head/sys/mips/include/hwfunc.h =================================================================== --- head/sys/mips/include/hwfunc.h (revision 326258) +++ head/sys/mips/include/hwfunc.h (revision 326259) @@ -1,102 +1,104 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2004 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$ */ #ifndef _MACHINE_HWFUNC_H_ #define _MACHINE_HWFUNC_H_ #include struct timecounter; /* * Hooks downward into platform functionality. */ void platform_reset(void); void platform_start(__register_t, __register_t, __register_t, __register_t); /* For clocks and ticks and such */ void platform_initclocks(void); uint64_t platform_get_frequency(void); unsigned platform_get_timecount(struct timecounter *); /* For hardware specific CPU initialization */ void platform_cpu_init(void); #ifdef SMP /* * Spin up the AP so that it starts executing MP bootstrap entry point: mpentry * * Returns 0 on sucess and non-zero on failure. */ int platform_start_ap(int processor_id); /* * Platform-specific initialization that needs to be done when an AP starts * running. This function is called from the MP bootstrap code in mpboot.S */ void platform_init_ap(int processor_id); /* * Return a plaform-specific interrrupt number that is used to deliver IPIs. * * This hardware interrupt is used to deliver IPIs exclusively and must * not be used for any other interrupt source. */ int platform_ipi_hardintr_num(void); int platform_ipi_softintr_num(void); /* * Trigger a IPI interrupt on 'cpuid'. */ void platform_ipi_send(int cpuid); /* * Quiesce the IPI interrupt source on the current cpu. */ void platform_ipi_clear(void); /* * Return the processor id. * * Note that this function is called in early boot when stack is not available. */ extern int platform_processor_id(void); /* * Return the cpumask of available processors. */ extern void platform_cpu_mask(cpuset_t *mask); /* * Return the topology of processors on this platform */ struct cpu_group *platform_smp_topo(void); #endif /* SMP */ #endif /* !_MACHINE_HWFUNC_H_ */ Index: head/sys/mips/include/intr_machdep.h =================================================================== --- head/sys/mips/include/intr_machdep.h (revision 326258) +++ head/sys/mips/include/intr_machdep.h (revision 326259) @@ -1,76 +1,78 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2004 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$ */ #ifndef _MACHINE_INTR_MACHDEP_H_ #define _MACHINE_INTR_MACHDEP_H_ #include #include #if defined(CPU_RMI) || defined(CPU_NLM) #define XLR_MAX_INTR 64 #else #define NHARD_IRQS 6 #define NSOFT_IRQS 2 #endif struct trapframe; void cpu_init_interrupts(void); void cpu_establish_hardintr(const char *, driver_filter_t *, driver_intr_t *, void *, int, int, void **); void cpu_establish_softintr(const char *, driver_filter_t *, void (*)(void*), void *, int, int, void **); void cpu_intr(struct trapframe *); /* * Allow a platform to override the default hard interrupt mask and unmask * functions. The 'arg' can be cast safely to an 'int' and holds the mips * hard interrupt number to mask or unmask. */ typedef void (*cpu_intr_mask_t)(void *arg); typedef void (*cpu_intr_unmask_t)(void *arg); void cpu_set_hardintr_mask_func(cpu_intr_mask_t func); void cpu_set_hardintr_unmask_func(cpu_intr_unmask_t func); /* * Opaque datatype that represents intr counter */ typedef unsigned long* mips_intrcnt_t; mips_intrcnt_t mips_intrcnt_create(const char *); void mips_intrcnt_setname(mips_intrcnt_t, const char *); static __inline void mips_intrcnt_inc(mips_intrcnt_t counter) { if (counter) atomic_add_long(counter, 1); VM_CNT_INC(v_intr); } #endif /* !_MACHINE_INTR_MACHDEP_H_ */ Index: head/sys/mips/include/kdb.h =================================================================== --- head/sys/mips/include/kdb.h (revision 326258) +++ head/sys/mips/include/kdb.h (revision 326259) @@ -1,56 +1,58 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2004 Marcel Moolenaar * 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 ``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 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. * * from: src/sys/alpha/include/kdb.h,v 1.2 2005/01/05 20:05:50 imp * $FreeBSD$ */ #ifndef _MACHINE_KDB_H_ #define _MACHINE_KDB_H_ #include #define KDB_STOPPEDPCB(pc) &stoppcbs[pc->pc_cpuid] static __inline void kdb_cpu_clear_singlestep(void) { } static __inline void kdb_cpu_set_singlestep(void) { } static __inline void kdb_cpu_trap(int vector, int _) { } static __inline void kdb_cpu_sync_icache(unsigned char *addr, size_t size) { } #endif /* _MACHINE_KDB_H_ */ Index: head/sys/mips/include/memdev.h =================================================================== --- head/sys/mips/include/memdev.h (revision 326258) +++ head/sys/mips/include/memdev.h (revision 326259) @@ -1,41 +1,43 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2004 Mark R V Murray * 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 * in this position and unchanged. * 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 AUTHORS ``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 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. * * from: src/sys/alpha/include/memdev.h,v 1.2 2004/08/01 18:51:44 markm * $FreeBSD$ */ #ifndef _MACHINE_MEMDEV_H_ #define _MACHINE_MEMDEV_H_ #define CDEV_MINOR_MEM 0 #define CDEV_MINOR_KMEM 1 d_open_t memopen; d_read_t memrw; #define memioctl (d_ioctl_t *)NULL d_mmap_t memmmap; #endif /* _MACHINE_MEMDEV_H_ */ Index: head/sys/mips/include/metadata.h =================================================================== --- head/sys/mips/include/metadata.h (revision 326258) +++ head/sys/mips/include/metadata.h (revision 326259) @@ -1,35 +1,37 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003 Peter Wemm * 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$ */ #ifndef _MACHINE_METADATA_H_ #define _MACHINE_METADATA_H_ #define MODINFOMD_SMAP 0x1001 #define MODINFOMD_DTBP 0x1002 #endif /* !_MACHINE_METADATA_H_ */ Index: head/sys/mips/include/minidump.h =================================================================== --- head/sys/mips/include/minidump.h (revision 326258) +++ head/sys/mips/include/minidump.h (revision 326259) @@ -1,46 +1,48 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006 Peter Wemm * 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 ``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 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$ */ #ifndef _MACHINE_MINIDUMP_H_ #define _MACHINE_MINIDUMP_H_ 1 #define MINIDUMP_MAGIC "minidump FreeBSD/mips" #define MINIDUMP_VERSION 1 struct minidumphdr { char magic[24]; uint32_t version; uint32_t msgbufsize; uint32_t bitmapsize; uint32_t ptesize; uint64_t kernbase; uint64_t dmapbase; uint64_t dmapend; }; #endif /* _MACHINE_MINIDUMP_H_ */ Index: head/sys/mips/include/octeon_cop2.h =================================================================== --- head/sys/mips/include/octeon_cop2.h (revision 326258) +++ head/sys/mips/include/octeon_cop2.h (revision 326259) @@ -1,215 +1,217 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2011, Oleksandr Tymoshenko * 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 unmodified, 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$ * */ #ifndef __OCTEON_COP2_H__ #define __OCTEON_COP2_H__ /* * COP2 registers of interest */ #define COP2_CRC_IV 0x201 #define COP2_CRC_IV_SET COP2_CRC_IV #define COP2_CRC_LENGTH 0x202 #define COP2_CRC_LENGTH_SET 0x1202 #define COP2_CRC_POLY 0x200 #define COP2_CRC_POLY_SET 0x4200 #define COP2_LLM_DAT0 0x402 #define COP2_LLM_DAT0_SET COP2_LLM_DAT0 #define COP2_LLM_DAT1 0x40A #define COP2_LLM_DAT1_SET COP2_LLM_DAT1 #define COP2_3DES_IV 0x084 #define COP2_3DES_IV_SET COP2_3DES_IV #define COP2_3DES_KEY0 0x080 #define COP2_3DES_KEY0_SET COP2_3DES_KEY0 #define COP2_3DES_KEY1 0x081 #define COP2_3DES_KEY1_SET COP2_3DES_KEY1 #define COP2_3DES_KEY2 0x082 #define COP2_3DES_KEY2_SET COP2_3DES_KEY2 #define COP2_3DES_RESULT 0x088 #define COP2_3DES_RESULT_SET 0x098 #define COP2_AES_INP0 0x111 #define COP2_AES_INP0_SET COP2_AES_INP0 #define COP2_AES_IV0 0x102 #define COP2_AES_IV0_SET COP2_AES_IV0 #define COP2_AES_IV1 0x103 #define COP2_AES_IV1_SET COP2_AES_IV1 #define COP2_AES_KEY0 0x104 #define COP2_AES_KEY0_SET COP2_AES_KEY0 #define COP2_AES_KEY1 0x105 #define COP2_AES_KEY1_SET COP2_AES_KEY1 #define COP2_AES_KEY2 0x106 #define COP2_AES_KEY2_SET COP2_AES_KEY2 #define COP2_AES_KEY3 0x107 #define COP2_AES_KEY3_SET COP2_AES_KEY3 #define COP2_AES_KEYLEN 0x110 #define COP2_AES_KEYLEN_SET COP2_AES_KEYLEN #define COP2_AES_RESULT0 0x100 #define COP2_AES_RESULT0_SET COP2_AES_RESULT0 #define COP2_AES_RESULT1 0x101 #define COP2_AES_RESULT1_SET COP2_AES_RESULT1 #define COP2_HSH_DATW0 0x240 #define COP2_HSH_DATW0_SET COP2_HSH_DATW0 #define COP2_HSH_DATW1 0x241 #define COP2_HSH_DATW1_SET COP2_HSH_DATW1 #define COP2_HSH_DATW2 0x242 #define COP2_HSH_DATW2_SET COP2_HSH_DATW2 #define COP2_HSH_DATW3 0x243 #define COP2_HSH_DATW3_SET COP2_HSH_DATW3 #define COP2_HSH_DATW4 0x244 #define COP2_HSH_DATW4_SET COP2_HSH_DATW4 #define COP2_HSH_DATW5 0x245 #define COP2_HSH_DATW5_SET COP2_HSH_DATW5 #define COP2_HSH_DATW6 0x246 #define COP2_HSH_DATW6_SET COP2_HSH_DATW6 #define COP2_HSH_DATW7 0x247 #define COP2_HSH_DATW7_SET COP2_HSH_DATW7 #define COP2_HSH_DATW8 0x248 #define COP2_HSH_DATW8_SET COP2_HSH_DATW8 #define COP2_HSH_DATW9 0x249 #define COP2_HSH_DATW9_SET COP2_HSH_DATW9 #define COP2_HSH_DATW10 0x24A #define COP2_HSH_DATW10_SET COP2_HSH_DATW10 #define COP2_HSH_DATW11 0x24B #define COP2_HSH_DATW11_SET COP2_HSH_DATW11 #define COP2_HSH_DATW12 0x24C #define COP2_HSH_DATW12_SET COP2_HSH_DATW12 #define COP2_HSH_DATW13 0x24D #define COP2_HSH_DATW13_SET COP2_HSH_DATW13 #define COP2_HSH_DATW14 0x24E #define COP2_HSH_DATW14_SET COP2_HSH_DATW14 #define COP2_HSH_IVW0 0x250 #define COP2_HSH_IVW0_SET COP2_HSH_IVW0 #define COP2_HSH_IVW1 0x251 #define COP2_HSH_IVW1_SET COP2_HSH_IVW1 #define COP2_HSH_IVW2 0x252 #define COP2_HSH_IVW2_SET COP2_HSH_IVW2 #define COP2_HSH_IVW3 0x253 #define COP2_HSH_IVW3_SET COP2_HSH_IVW3 #define COP2_HSH_IVW4 0x254 #define COP2_HSH_IVW4_SET COP2_HSH_IVW4 #define COP2_HSH_IVW5 0x255 #define COP2_HSH_IVW5_SET COP2_HSH_IVW5 #define COP2_HSH_IVW6 0x256 #define COP2_HSH_IVW6_SET COP2_HSH_IVW6 #define COP2_HSH_IVW7 0x257 #define COP2_HSH_IVW7_SET COP2_HSH_IVW7 #define COP2_GFM_MULT0 0x258 #define COP2_GFM_MULT0_SET COP2_GFM_MULT0 #define COP2_GFM_MULT1 0x259 #define COP2_GFM_MULT1_SET COP2_GFM_MULT1 #define COP2_GFM_POLY 0x25E #define COP2_GFM_POLY_SET COP2_GFM_POLY #define COP2_GFM_RESULT0 0x25A #define COP2_GFM_RESULT0_SET COP2_GFM_RESULT0 #define COP2_GFM_RESULT1 0x25B #define COP2_GFM_RESULT1_SET COP2_GFM_RESULT1 #define COP2_HSH_DATW0_PASS1 0x040 #define COP2_HSH_DATW0_PASS1_SET COP2_HSH_DATW0_PASS1 #define COP2_HSH_DATW1_PASS1 0x041 #define COP2_HSH_DATW1_PASS1_SET COP2_HSH_DATW1_PASS1 #define COP2_HSH_DATW2_PASS1 0x042 #define COP2_HSH_DATW2_PASS1_SET COP2_HSH_DATW2_PASS1 #define COP2_HSH_DATW3_PASS1 0x043 #define COP2_HSH_DATW3_PASS1_SET COP2_HSH_DATW3_PASS1 #define COP2_HSH_DATW4_PASS1 0x044 #define COP2_HSH_DATW4_PASS1_SET COP2_HSH_DATW4_PASS1 #define COP2_HSH_DATW5_PASS1 0x045 #define COP2_HSH_DATW5_PASS1_SET COP2_HSH_DATW5_PASS1 #define COP2_HSH_DATW6_PASS1 0x046 #define COP2_HSH_DATW6_PASS1_SET COP2_HSH_DATW6_PASS1 #define COP2_HSH_IVW0_PASS1 0x048 #define COP2_HSH_IVW0_PASS1_SET COP2_HSH_IVW0_PASS1 #define COP2_HSH_IVW1_PASS1 0x049 #define COP2_HSH_IVW1_PASS1_SET COP2_HSH_IVW1_PASS1 #define COP2_HSH_IVW2_PASS1 0x04A #define COP2_HSH_IVW2_PASS1_SET COP2_HSH_IVW2_PASS1 #ifndef LOCORE struct octeon_cop2_state { /* 3DES */ /* 0x0084 */ unsigned long _3des_iv; /* 0x0080..0x0082 */ unsigned long _3des_key[3]; /* 0x0088, set: 0x0098 */ unsigned long _3des_result; /* AES */ /* 0x0111 */ unsigned long aes_inp0; /* 0x0102..0x0103 */ unsigned long aes_iv[2]; /* 0x0104..0x0107 */ unsigned long aes_key[4]; /* 0x0110 */ unsigned long aes_keylen; /* 0x0100..0x0101 */ unsigned long aes_result[2]; /* CRC */ /* 0x0201 */ unsigned long crc_iv; /* 0x0202, set: 0x1202 */ unsigned long crc_length; /* 0x0200, set: 0x4200 */ unsigned long crc_poly; /* Low-latency memory stuff */ /* 0x0402, 0x040A */ unsigned long llm_dat[2]; /* SHA & MD5 */ /* 0x0240..0x024E */ unsigned long hsh_datw[15]; /* 0x0250..0x0257 */ unsigned long hsh_ivw[8]; /* GFM */ /* 0x0258..0x0259 */ unsigned long gfm_mult[2]; /* 0x025E */ unsigned long gfm_poly; /* 0x025A..0x025B */ unsigned long gfm_result[2]; }; /* Prototypes */ struct octeon_cop2_state* octeon_cop2_alloc_ctx(void); void octeon_cop2_free_ctx(struct octeon_cop2_state *); /* * Save/restore part */ void octeon_cop2_save(struct octeon_cop2_state *); void octeon_cop2_restore(struct octeon_cop2_state *); #endif /* LOCORE */ #endif /* __OCTEON_COP2_H__ */ Index: head/sys/mips/include/ofw_machdep.h =================================================================== --- head/sys/mips/include/ofw_machdep.h (revision 326258) +++ head/sys/mips/include/ofw_machdep.h (revision 326259) @@ -1,45 +1,47 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2001 by Thomas Moestl . * 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 ``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$ */ #ifndef _MACHINE_OFW_MACHDEP_H_ #define _MACHINE_OFW_MACHDEP_H_ #include #include #include #include typedef uint32_t cell_t; struct mem_region { vm_offset_t mr_start; vm_size_t mr_size; }; void OF_getetheraddr(device_t dev, u_char *addr); void OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *)); #endif /* _MACHINE_OFW_MACHDEP_H_ */ Index: head/sys/mips/include/pcpu.h =================================================================== --- head/sys/mips/include/pcpu.h (revision 326258) +++ head/sys/mips/include/pcpu.h (revision 326259) @@ -1,92 +1,94 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 1999 Luoqi Chen * Copyright (c) Peter Wemm * 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. * * from: src/sys/alpha/include/pcpu.h,v 1.15 2004/11/05 19:16:44 jhb * $FreeBSD$ */ #ifndef _MACHINE_PCPU_H_ #define _MACHINE_PCPU_H_ #include #include #define PCPU_MD_COMMON_FIELDS \ pd_entry_t *pc_segbase; /* curthread segbase */ \ struct pmap *pc_curpmap; /* pmap of curthread */ \ u_int32_t pc_next_asid; /* next ASID to alloc */ \ u_int32_t pc_asid_generation; /* current ASID generation */ \ u_int pc_pending_ipis; /* IPIs pending to this CPU */ \ struct pcpu *pc_self; /* globally-uniqe self pointer */ #ifdef __mips_n64 #define PCPU_MD_MIPS64_FIELDS \ PCPU_MD_COMMON_FIELDS \ char __pad[245] #else #define PCPU_MD_MIPS32_FIELDS \ PCPU_MD_COMMON_FIELDS \ char __pad[125] #endif #ifdef __mips_n64 #define PCPU_MD_FIELDS PCPU_MD_MIPS64_FIELDS #else #define PCPU_MD_FIELDS PCPU_MD_MIPS32_FIELDS #endif #ifdef _KERNEL extern char pcpu_space[MAXCPU][PAGE_SIZE * 2]; #define PCPU_ADDR(cpu) (struct pcpu *)(pcpu_space[(cpu)]) extern struct pcpu *pcpup; #define PCPUP pcpup /* * Since we use a wired TLB entry to map the same VA to a different * physical page for each CPU, get_pcpu() must use the pc_self * field to obtain a globally-unique pointer. */ #define get_pcpu() (PCPUP->pc_self) #define PCPU_ADD(member, value) (PCPUP->pc_ ## member += (value)) #define PCPU_GET(member) (PCPUP->pc_ ## member) #define PCPU_INC(member) PCPU_ADD(member, 1) #define PCPU_PTR(member) (&PCPUP->pc_ ## member) #define PCPU_SET(member,value) (PCPUP->pc_ ## member = (value)) #define PCPU_LAZY_INC(member) (++PCPUP->pc_ ## member) #ifdef SMP /* * Instantiate the wired TLB entry at PCPU_TLB_ENTRY to map 'pcpu' at 'pcpup'. */ void mips_pcpu_tlb_init(struct pcpu *pcpu); #endif #endif /* _KERNEL */ #endif /* !_MACHINE_PCPU_H_ */ Index: head/sys/mips/include/pte.h =================================================================== --- head/sys/mips/include/pte.h (revision 326258) +++ head/sys/mips/include/pte.h (revision 326259) @@ -1,207 +1,209 @@ /*- + * 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$ */ #ifndef _MACHINE_PTE_H_ #define _MACHINE_PTE_H_ #ifndef _LOCORE #if defined(__mips_n64) || defined(__mips_n32) /* PHYSADDR_64_BIT */ typedef uint64_t pt_entry_t; #else typedef uint32_t pt_entry_t; #endif typedef pt_entry_t *pd_entry_t; #endif /* * TLB and PTE management. Most things operate within the context of * EntryLo0,1, and begin with TLBLO_. Things which work with EntryHi * start with TLBHI_. PTE bits begin with PTE_. * * Note that we use the same size VM and TLB pages. */ #define TLB_PAGE_SHIFT (PAGE_SHIFT) #define TLB_PAGE_SIZE (1 << TLB_PAGE_SHIFT) #define TLB_PAGE_MASK (TLB_PAGE_SIZE - 1) /* * TLB PageMask register. Has mask bits set above the default, 4K, page mask. */ #define TLBMASK_SHIFT (13) #define TLBMASK_MASK ((PAGE_MASK >> TLBMASK_SHIFT) << TLBMASK_SHIFT) /* * FreeBSD/mips page-table entries take a near-identical format to MIPS TLB * entries, each consisting of two 32-bit or 64-bit values ("EntryHi" and * "EntryLo"). MIPS4k and MIPS64 both define certain bits in TLB entries as * reserved, and these must be zero-filled by software. We overload these * bits in PTE entries to hold PTE_ flags such as RO, W, and MANAGED. * However, we must mask these out when writing to TLB entries to ensure that * they do not become visible to hardware -- especially on MIPS64r2 which has * an extended physical memory space. * * When using n64 and n32, shift software-defined bits into the MIPS64r2 * reserved range, which runs from bit 55 ... 63. In other configurations * (32-bit MIPS4k and compatible), shift them out to bits 29 ... 31. * * NOTE: This means that for 32-bit use of CP0, we aren't able to set the top * bit of PFN to a non-zero value, as software is using it! This physical * memory size limit may not be sufficiently enforced elsewhere. */ #if defined(__mips_n64) || defined(__mips_n32) /* PHYSADDR_64_BIT */ #define TLBLO_SWBITS_SHIFT (55) #define TLBLO_SWBITS_CLEAR_SHIFT (9) #define TLBLO_PFN_MASK 0x3FFFFFFC0ULL #else #define TLBLO_SWBITS_SHIFT (29) #define TLBLO_SWBITS_CLEAR_SHIFT (3) #define TLBLO_PFN_MASK (0x1FFFFFC0) #endif #define TLBLO_PFN_SHIFT (6) #define TLBLO_SWBITS_MASK ((pt_entry_t)0x7 << TLBLO_SWBITS_SHIFT) #define TLBLO_PA_TO_PFN(pa) ((((pa) >> TLB_PAGE_SHIFT) << TLBLO_PFN_SHIFT) & TLBLO_PFN_MASK) #define TLBLO_PFN_TO_PA(pfn) ((vm_paddr_t)((pfn) >> TLBLO_PFN_SHIFT) << TLB_PAGE_SHIFT) #define TLBLO_PTE_TO_PFN(pte) ((pte) & TLBLO_PFN_MASK) #define TLBLO_PTE_TO_PA(pte) (TLBLO_PFN_TO_PA(TLBLO_PTE_TO_PFN((pte)))) /* * XXX This comment is not correct for anything more modern than R4K. * * VPN for EntryHi register. Upper two bits select user, supervisor, * or kernel. Bits 61 to 40 copy bit 63. VPN2 is bits 39 and down to * as low as 13, down to PAGE_SHIFT, to index 2 TLB pages*. From bit 12 * to bit 8 there is a 5-bit 0 field. Low byte is ASID. * * XXX This comment is not correct for FreeBSD. * Note that in FreeBSD, we map 2 TLB pages is equal to 1 VM page. */ #define TLBHI_ASID_MASK (0xff) #if defined(__mips_n64) #define TLBHI_R_SHIFT 62 #define TLBHI_R_USER (0x00UL << TLBHI_R_SHIFT) #define TLBHI_R_SUPERVISOR (0x01UL << TLBHI_R_SHIFT) #define TLBHI_R_KERNEL (0x03UL << TLBHI_R_SHIFT) #define TLBHI_R_MASK (0x03UL << TLBHI_R_SHIFT) #define TLBHI_VA_R(va) ((va) & TLBHI_R_MASK) #define TLBHI_FILL_SHIFT 40 #define TLBHI_VPN2_SHIFT (TLB_PAGE_SHIFT + 1) #define TLBHI_VPN2_MASK (((~((1UL << TLBHI_VPN2_SHIFT) - 1)) << (63 - TLBHI_FILL_SHIFT)) >> (63 - TLBHI_FILL_SHIFT)) #define TLBHI_VA_TO_VPN2(va) ((va) & TLBHI_VPN2_MASK) #define TLBHI_ENTRY(va, asid) ((TLBHI_VA_R((va))) /* Region. */ | \ (TLBHI_VA_TO_VPN2((va))) /* VPN2. */ | \ ((asid) & TLBHI_ASID_MASK)) #else /* !defined(__mips_n64) */ #define TLBHI_PAGE_MASK (2 * PAGE_SIZE - 1) #define TLBHI_ENTRY(va, asid) (((va) & ~TLBHI_PAGE_MASK) | ((asid) & TLBHI_ASID_MASK)) #endif /* defined(__mips_n64) */ /* * TLB flags managed in hardware: * C: Cache attribute. * D: Dirty bit. This means a page is writable. It is not * set at first, and a write is trapped, and the dirty * bit is set. See also PTE_RO. * V: Valid bit. Obvious, isn't it? * G: Global bit. This means that this mapping is present * in EVERY address space, and to ignore the ASID when * it is matched. */ #define PTE_C(attr) ((attr & 0x07) << 3) #define PTE_C_MASK (PTE_C(0x07)) #define PTE_C_UNCACHED (PTE_C(MIPS_CCA_UNCACHED)) #define PTE_C_CACHE (PTE_C(MIPS_CCA_CACHED)) #define PTE_C_WC (PTE_C(MIPS_CCA_WC)) #define PTE_D 0x04 #define PTE_V 0x02 #define PTE_G 0x01 /* * VM flags managed in software: * RO: Read only. Never set PTE_D on this page, and don't * listen to requests to write to it. * W: Wired. ??? * MANAGED:Managed. This PTE maps a managed page. * * These bits should not be written into the TLB, so must first be masked out * explicitly in C, or using CLEAR_PTE_SWBITS() in assembly. */ #define PTE_RO ((pt_entry_t)0x01 << TLBLO_SWBITS_SHIFT) #define PTE_W ((pt_entry_t)0x02 << TLBLO_SWBITS_SHIFT) #define PTE_MANAGED ((pt_entry_t)0x04 << TLBLO_SWBITS_SHIFT) /* * PTE management functions for bits defined above. */ #define pte_clear(pte, bit) (*(pte) &= ~(bit)) #define pte_set(pte, bit) (*(pte) |= (bit)) #define pte_test(pte, bit) ((*(pte) & (bit)) == (bit)) #define pte_cache_bits(pte) ((*(pte) >> 3) & 0x07) /* Assembly support for PTE access*/ #ifdef LOCORE #if defined(__mips_n64) || defined(__mips_n32) /* PHYSADDR_64_BIT */ #define PTESHIFT 3 #define PTE2MASK 0xff0 /* for the 2-page lo0/lo1 */ #define PTEMASK 0xff8 #define PTESIZE 8 #define PTE_L ld #define PTE_MTC0 dmtc0 #define CLEAR_PTE_SWBITS(pr) #else #define PTESHIFT 2 #define PTE2MASK 0xff8 /* for the 2-page lo0/lo1 */ #define PTEMASK 0xffc #define PTESIZE 4 #define PTE_L lw #define PTE_MTC0 mtc0 #define CLEAR_PTE_SWBITS(r) LONG_SLL r, TLBLO_SWBITS_CLEAR_SHIFT; LONG_SRL r, TLBLO_SWBITS_CLEAR_SHIFT /* remove swbits */ #endif /* defined(__mips_n64) || defined(__mips_n32) */ #if defined(__mips_n64) #define PTRSHIFT 3 #define PDEPTRMASK 0xff8 #else #define PTRSHIFT 2 #define PDEPTRMASK 0xffc #endif #endif /* LOCORE */ /* PageMask Register (CP0 Register 5, Select 0) Values */ #define MIPS3_PGMASK_MASKX 0x00001800 #define MIPS3_PGMASK_4K 0x00000000 #define MIPS3_PGMASK_16K 0x00006000 #define MIPS3_PGMASK_64K 0x0001e000 #define MIPS3_PGMASK_256K 0x0007e000 #define MIPS3_PGMASK_1M 0x001fe000 #define MIPS3_PGMASK_4M 0x007fe000 #define MIPS3_PGMASK_16M 0x01ffe000 #define MIPS3_PGMASK_64M 0x07ffe000 #define MIPS3_PGMASK_256M 0x1fffe000 #endif /* !_MACHINE_PTE_H_ */ Index: head/sys/mips/include/runq.h =================================================================== --- head/sys/mips/include/runq.h (revision 326258) +++ head/sys/mips/include/runq.h (revision 326259) @@ -1,60 +1,62 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2001 Jake Burkholder * 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. * * from: src/sys/i386/include/runq.h,v 1.3 2005/01/06 22:18:15 imp * $FreeBSD$ */ #ifndef _MACHINE_RUNQ_H_ #define _MACHINE_RUNQ_H_ #ifdef __mips_n64 #define RQB_LEN (1) /* Number of priority status words. */ #define RQB_L2BPW (6) /* Log2(sizeof(rqb_word_t) * NBBY)). */ #else #define RQB_LEN (2) /* Number of priority status words. */ #define RQB_L2BPW (5) /* Log2(sizeof(rqb_word_t) * NBBY)). */ #endif #define RQB_BPW (1<> RQB_L2BPW) #ifdef __mips_n64 #define RQB_FFS(word) (ffsl(word) - 1) #else #define RQB_FFS(word) (ffs(word) - 1) #endif /* * Type of run queue status word. */ #ifdef __mips_n64 typedef u_int64_t rqb_word_t; #else typedef u_int32_t rqb_word_t; #endif #endif Index: head/sys/mips/include/sc_machdep.h =================================================================== --- head/sys/mips/include/sc_machdep.h (revision 326258) +++ head/sys/mips/include/sc_machdep.h (revision 326259) @@ -1,71 +1,73 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003 Jake Burkholder. * 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$ */ #ifndef _MACHINE_SC_MACHDEP_H_ #define _MACHINE_SC_MACHDEP_H_ /* Color attributes for foreground text */ #define FG_BLACK 0x0 #define FG_BLUE 0x1 #define FG_GREEN 0x2 #define FG_CYAN 0x3 #define FG_RED 0x4 #define FG_MAGENTA 0x5 #define FG_BROWN 0x6 #define FG_LIGHTGREY 0x7 /* aka white */ #define FG_DARKGREY 0x8 #define FG_LIGHTBLUE 0x9 #define FG_LIGHTGREEN 0xa #define FG_LIGHTCYAN 0xb #define FG_LIGHTRED 0xc #define FG_LIGHTMAGENTA 0xd #define FG_YELLOW 0xe #define FG_WHITE 0xf /* aka bright white */ #define FG_BLINK 0x80 /* Color attributes for text background */ #define BG_BLACK 0x00 #define BG_BLUE 0x10 #define BG_GREEN 0x20 #define BG_CYAN 0x30 #define BG_RED 0x40 #define BG_MAGENTA 0x50 #define BG_BROWN 0x60 #define BG_LIGHTGREY 0x70 #define BG_DARKGREY 0x80 #define BG_LIGHTBLUE 0x90 #define BG_LIGHTGREEN 0xa0 #define BG_LIGHTCYAN 0xb0 #define BG_LIGHTRED 0xc0 #define BG_LIGHTMAGENTA 0xd0 #define BG_YELLOW 0xe0 #define BG_WHITE 0xf0 #endif /* !_MACHINE_SC_MACHDEP_H_ */ Index: head/sys/mips/include/sf_buf.h =================================================================== --- head/sys/mips/include/sf_buf.h (revision 326258) +++ head/sys/mips/include/sf_buf.h (revision 326259) @@ -1,69 +1,71 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003 Alan L. Cox * 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$ */ #ifndef _MACHINE_SF_BUF_H_ #define _MACHINE_SF_BUF_H_ #ifdef __mips_n64 /* In 64 bit the whole memory is directly mapped */ static inline vm_offset_t sf_buf_kva(struct sf_buf *sf) { vm_page_t m; m = (vm_page_t)sf; return (MIPS_PHYS_TO_DIRECT(VM_PAGE_TO_PHYS(m))); } static inline struct vm_page * sf_buf_page(struct sf_buf *sf) { return ((vm_page_t)sf); } #else /* !__mips_n64 */ static inline void sf_buf_map(struct sf_buf *sf, int flags) { pmap_qenter(sf->kva, &sf->m, 1); } static inline int sf_buf_unmap(struct sf_buf *sf) { pmap_qremove(sf->kva, 1); return (1); } #endif /* __mips_n64 */ #endif /* !_MACHINE_SF_BUF_H_ */ Index: head/sys/mips/include/sigframe.h =================================================================== --- head/sys/mips/include/sigframe.h (revision 326258) +++ head/sys/mips/include/sigframe.h (revision 326259) @@ -1,67 +1,69 @@ /*- + * SPDX-License-Identifier: BSD-3-Clause + * * Copyright (c) 1999 Marcel Moolenaar * 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 * in this position and unchanged. * 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. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. * * from: src/sys/alpha/include/sigframe.h,v 1.1 1999/09/29 15:06:26 marcel * from: sigframe.h,v 1.1 2006/08/07 05:38:57 katta * $FreeBSD$ */ #ifndef _MACHINE_SIGFRAME_H_ #define _MACHINE_SIGFRAME_H_ #if defined(_KERNEL) && !defined(KLD_MODULE) && !defined(_STANDALONE) #include "opt_compat.h" #endif /* * WARNING: code in locore.s assumes the layout shown for sf_signum * thru sf_addr so... don't alter them! */ struct sigframe { register_t sf_signum; register_t sf_siginfo; /* code or pointer to sf_si */ register_t sf_ucontext; /* points to sf_uc */ register_t sf_addr; /* undocumented 4th arg */ ucontext_t sf_uc; /* = *sf_ucontext */ siginfo_t sf_si; /* = *sf_siginfo (SA_SIGINFO case) */ unsigned long __spare__[2]; }; #if (defined(__mips_n32) || defined(__mips_n64)) && defined(COMPAT_FREEBSD32) #include struct sigframe32 { int32_t sf_signum; int32_t sf_siginfo; /* code or pointer to sf_si */ int32_t sf_ucontext; /* points to sf_uc */ int32_t sf_addr; /* undocumented 4th arg */ ucontext32_t sf_uc; /* = *sf_ucontext */ struct siginfo32 sf_si; /* = *sf_siginfo (SA_SIGINFO case) */ uint32_t __spare__[2]; }; #endif #endif /* !_MACHINE_SIGFRAME_H_ */ Index: head/sys/mips/include/tlb.h =================================================================== --- head/sys/mips/include/tlb.h (revision 326258) +++ head/sys/mips/include/tlb.h (revision 326259) @@ -1,60 +1,62 @@ /*- + * 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$ */ #ifndef _MACHINE_TLB_H_ #define _MACHINE_TLB_H_ /* * The first TLB entry that write random hits. * TLB entry 0 maps the kernel stack of the currently running thread * TLB entry 1 maps the pcpu area of processor (only for SMP builds) */ #define KSTACK_TLB_ENTRY 0 #ifdef SMP #define PCPU_TLB_ENTRY 1 #define VMWIRED_ENTRIES 2 #else #define VMWIRED_ENTRIES 1 #endif /* SMP */ /* * The number of process id entries. */ #define VMNUM_PIDS 256 extern int num_tlbentries; void tlb_insert_wired(unsigned, vm_offset_t, pt_entry_t, pt_entry_t); void tlb_invalidate_address(struct pmap *, vm_offset_t); void tlb_invalidate_all(void); void tlb_invalidate_all_user(struct pmap *); void tlb_invalidate_range(struct pmap *, vm_offset_t, vm_offset_t); void tlb_save(void); void tlb_update(struct pmap *, vm_offset_t, pt_entry_t); #endif /* !_MACHINE_TLB_H_ */ Index: head/sys/mips/include/tls.h =================================================================== --- head/sys/mips/include/tls.h (revision 326258) +++ head/sys/mips/include/tls.h (revision 326259) @@ -1,55 +1,57 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2012 Oleksandr Tymoshenko * 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, * without modification, immediately at the beginning of the file. * 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$ * */ #ifndef __MIPS_TLS_H__ #define __MIPS_TLS_H__ #if defined(_KERNEL) && !defined(KLD_MODULE) && !defined(_STANDALONE) #include "opt_compat.h" #endif /* * TLS parameters */ #define TLS_TP_OFFSET 0x7000 #define TLS_DTP_OFFSET 0x8000 #ifdef __mips_n64 #define TLS_TCB_SIZE 16 #ifdef COMPAT_FREEBSD32 #define TLS_TCB_SIZE32 8 #endif #else #define TLS_TCB_SIZE 8 #endif #endif /* __MIPS_TLS_H__ */ Index: head/sys/mips/include/vdso.h =================================================================== --- head/sys/mips/include/vdso.h (revision 326258) +++ head/sys/mips/include/vdso.h (revision 326259) @@ -1,41 +1,43 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright 2012 Konstantin Belousov . * 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 ``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 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$ */ #ifndef _MIPS_VDSO_H #define _MIPS_VDSO_H #define VDSO_TIMEHANDS_MD \ uint32_t th_res[8]; #ifdef _KERNEL #ifdef COMPAT_FREEBSD32 #define VDSO_TIMEHANDS_MD32 VDSO_TIMEHANDS_MD #endif #endif #endif Index: head/sys/mips/include/vm.h =================================================================== --- head/sys/mips/include/vm.h (revision 326258) +++ head/sys/mips/include/vm.h (revision 326259) @@ -1,42 +1,44 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009 Alan L. Cox * 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$ */ #ifndef _MACHINE_VM_H_ #define _MACHINE_VM_H_ #include /* Memory attributes. */ #define VM_MEMATTR_UNCACHEABLE ((vm_memattr_t)MIPS_CCA_UNCACHED) #define VM_MEMATTR_WRITE_BACK ((vm_memattr_t)MIPS_CCA_CACHED) #define VM_MEMATTR_DEFAULT VM_MEMATTR_WRITE_BACK #ifdef MIPS_CCA_WC #define VM_MEMATTR_WRITE_COMBINING ((vm_memattr_t)MIPS_CCA_WC) #endif #endif /* !_MACHINE_VM_H_ */ Index: head/sys/mips/malta/gt.c =================================================================== --- head/sys/mips/malta/gt.c (revision 326258) +++ head/sys/mips/malta/gt.c (revision 326259) @@ -1,130 +1,132 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2005 Olivier Houchard. 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 ``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 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 static int gt_probe(device_t dev) { device_set_desc(dev, "GT64120 chip"); return (BUS_PROBE_NOWILDCARD); } static void gt_identify(driver_t *drv, device_t parent) { BUS_ADD_CHILD(parent, 0, "gt", 0); } static int gt_attach(device_t dev) { struct gt_softc *sc = device_get_softc(dev); sc->dev = dev; device_add_child(dev, "pcib", 0); bus_generic_probe(dev); bus_generic_attach(dev); return (0); } static struct resource * gt_alloc_resource(device_t dev, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, type, rid, start, end, count, flags)); } static int gt_setup_intr(device_t dev, device_t child, struct resource *ires, int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep) { return BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags, filt, intr, arg, cookiep); } static int gt_teardown_intr(device_t dev, device_t child, struct resource *res, void *cookie) { return (BUS_TEARDOWN_INTR(device_get_parent(dev), child, res, cookie)); } static int gt_activate_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { return (BUS_ACTIVATE_RESOURCE(device_get_parent(dev), child, type, rid, r)); } static device_method_t gt_methods[] = { DEVMETHOD(device_probe, gt_probe), DEVMETHOD(device_identify, gt_identify), DEVMETHOD(device_attach, gt_attach), DEVMETHOD(bus_setup_intr, gt_setup_intr), DEVMETHOD(bus_teardown_intr, gt_teardown_intr), DEVMETHOD(bus_alloc_resource, gt_alloc_resource), DEVMETHOD(bus_activate_resource, gt_activate_resource), DEVMETHOD_END }; static driver_t gt_driver = { "gt", gt_methods, sizeof(struct gt_softc), }; static devclass_t gt_devclass; DRIVER_MODULE(gt, nexus, gt_driver, gt_devclass, 0, 0); Index: head/sys/mips/malta/gt_pci.c =================================================================== --- head/sys/mips/malta/gt_pci.c (revision 326258) +++ head/sys/mips/malta/gt_pci.c (revision 326259) @@ -1,774 +1,776 @@ /* $NetBSD: gt_pci.c,v 1.4 2003/07/15 00:24:54 lukem Exp $ */ /*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright (c) 2001, 2002 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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. */ /* * PCI configuration support for gt I/O Processor chip. */ #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 "pcib_if.h" #include #define ICU_LEN 16 /* number of ISA IRQs */ /* * XXX: These defines are from NetBSD's . Respective file * from FreeBSD src tree lacks some definitions. */ #define PIC_OCW1 1 #define PIC_OCW2 0 #define PIC_OCW3 0 #define OCW2_SELECT 0 #define OCW2_ILS(x) ((x) << 0) /* interrupt level select */ #define OCW3_POLL_IRQ(x) ((x) & 0x7f) #define OCW3_POLL_PENDING (1U << 7) /* * Galileo controller's registers are LE so convert to then * to/from native byte order. We rely on boot loader or emulator * to set "swap bytes" configuration correctly for us */ #define GT_PCI_DATA(v) htole32((v)) #define GT_HOST_DATA(v) le32toh((v)) struct gt_pci_softc; struct gt_pci_intr_cookie { int irq; struct gt_pci_softc *sc; }; struct gt_pci_softc { device_t sc_dev; bus_space_tag_t sc_st; bus_space_handle_t sc_ioh_icu1; bus_space_handle_t sc_ioh_icu2; bus_space_handle_t sc_ioh_elcr; int sc_busno; struct rman sc_mem_rman; struct rman sc_io_rman; struct rman sc_irq_rman; unsigned long sc_mem; bus_space_handle_t sc_io; struct resource *sc_irq; struct intr_event *sc_eventstab[ICU_LEN]; struct gt_pci_intr_cookie sc_intr_cookies[ICU_LEN]; uint16_t sc_imask; uint16_t sc_elcr; uint16_t sc_reserved; void *sc_ih; }; static void gt_pci_set_icus(struct gt_pci_softc *); static int gt_pci_intr(void *v); static int gt_pci_probe(device_t); static int gt_pci_attach(device_t); static int gt_pci_activate_resource(device_t, device_t, int, int, struct resource *); static int gt_pci_setup_intr(device_t, device_t, struct resource *, int, driver_filter_t *, driver_intr_t *, void *, void **); static int gt_pci_teardown_intr(device_t, device_t, struct resource *, void*); static int gt_pci_maxslots(device_t ); static int gt_pci_conf_setup(struct gt_pci_softc *, int, int, int, int, uint32_t *); static uint32_t gt_pci_read_config(device_t, u_int, u_int, u_int, u_int, int); static void gt_pci_write_config(device_t, u_int, u_int, u_int, u_int, uint32_t, int); static int gt_pci_route_interrupt(device_t pcib, device_t dev, int pin); static struct resource * gt_pci_alloc_resource(device_t, device_t, int, int *, rman_res_t, rman_res_t, rman_res_t, u_int); static void gt_pci_mask_irq(void *source) { struct gt_pci_intr_cookie *cookie = source; struct gt_pci_softc *sc = cookie->sc; int irq = cookie->irq; sc->sc_imask |= (1 << irq); sc->sc_elcr |= (1 << irq); gt_pci_set_icus(sc); } static void gt_pci_unmask_irq(void *source) { struct gt_pci_intr_cookie *cookie = source; struct gt_pci_softc *sc = cookie->sc; int irq = cookie->irq; /* Enable it, set trigger mode. */ sc->sc_imask &= ~(1 << irq); sc->sc_elcr &= ~(1 << irq); gt_pci_set_icus(sc); } static void gt_pci_set_icus(struct gt_pci_softc *sc) { /* Enable the cascade IRQ (2) if 8-15 is enabled. */ if ((sc->sc_imask & 0xff00) != 0xff00) sc->sc_imask &= ~(1U << 2); else sc->sc_imask |= (1U << 2); bus_space_write_1(sc->sc_st, sc->sc_ioh_icu1, PIC_OCW1, sc->sc_imask & 0xff); bus_space_write_1(sc->sc_st, sc->sc_ioh_icu2, PIC_OCW1, (sc->sc_imask >> 8) & 0xff); bus_space_write_1(sc->sc_st, sc->sc_ioh_elcr, 0, sc->sc_elcr & 0xff); bus_space_write_1(sc->sc_st, sc->sc_ioh_elcr, 1, (sc->sc_elcr >> 8) & 0xff); } static int gt_pci_intr(void *v) { struct gt_pci_softc *sc = v; struct intr_event *event; int irq; for (;;) { bus_space_write_1(sc->sc_st, sc->sc_ioh_icu1, PIC_OCW3, OCW3_SEL | OCW3_P); irq = bus_space_read_1(sc->sc_st, sc->sc_ioh_icu1, PIC_OCW3); if ((irq & OCW3_POLL_PENDING) == 0) { return FILTER_HANDLED; } irq = OCW3_POLL_IRQ(irq); if (irq == 2) { bus_space_write_1(sc->sc_st, sc->sc_ioh_icu2, PIC_OCW3, OCW3_SEL | OCW3_P); irq = bus_space_read_1(sc->sc_st, sc->sc_ioh_icu2, PIC_OCW3); if (irq & OCW3_POLL_PENDING) irq = OCW3_POLL_IRQ(irq) + 8; else irq = 2; } event = sc->sc_eventstab[irq]; if (!event || TAILQ_EMPTY(&event->ie_handlers)) continue; /* TODO: frame instead of NULL? */ intr_event_handle(event, NULL); /* XXX: Log stray IRQs */ /* Send a specific EOI to the 8259. */ if (irq > 7) { bus_space_write_1(sc->sc_st, sc->sc_ioh_icu2, PIC_OCW2, OCW2_SELECT | OCW2_EOI | OCW2_SL | OCW2_ILS(irq & 7)); irq = 2; } bus_space_write_1(sc->sc_st, sc->sc_ioh_icu1, PIC_OCW2, OCW2_SELECT | OCW2_EOI | OCW2_SL | OCW2_ILS(irq)); } return FILTER_HANDLED; } static int gt_pci_probe(device_t dev) { device_set_desc(dev, "GT64120 PCI bridge"); return (0); } static int gt_pci_attach(device_t dev) { uint32_t busno; struct gt_pci_softc *sc = device_get_softc(dev); int rid; busno = 0; sc->sc_dev = dev; sc->sc_busno = busno; sc->sc_st = mips_bus_space_generic; /* Use KSEG1 to access IO ports for it is uncached */ sc->sc_io = MALTA_PCI0_IO_BASE; sc->sc_io_rman.rm_type = RMAN_ARRAY; sc->sc_io_rman.rm_descr = "GT64120 PCI I/O Ports"; /* * First 256 bytes are ISA's registers: e.g. i8259's * So do not use them for general purpose PCI I/O window */ if (rman_init(&sc->sc_io_rman) != 0 || rman_manage_region(&sc->sc_io_rman, 0x100, 0xffff) != 0) { panic("gt_pci_attach: failed to set up I/O rman"); } /* Use KSEG1 to access PCI memory for it is uncached */ sc->sc_mem = MALTA_PCIMEM1_BASE; sc->sc_mem_rman.rm_type = RMAN_ARRAY; sc->sc_mem_rman.rm_descr = "GT64120 PCI Memory"; if (rman_init(&sc->sc_mem_rman) != 0 || rman_manage_region(&sc->sc_mem_rman, sc->sc_mem, sc->sc_mem + MALTA_PCIMEM1_SIZE) != 0) { panic("gt_pci_attach: failed to set up memory rman"); } sc->sc_irq_rman.rm_type = RMAN_ARRAY; sc->sc_irq_rman.rm_descr = "GT64120 PCI IRQs"; if (rman_init(&sc->sc_irq_rman) != 0 || rman_manage_region(&sc->sc_irq_rman, 1, 31) != 0) panic("gt_pci_attach: failed to set up IRQ rman"); /* * Map the PIC/ELCR registers. */ #if 0 if (bus_space_map(sc->sc_st, 0x4d0, 2, 0, &sc->sc_ioh_elcr) != 0) device_printf(dev, "unable to map ELCR registers\n"); if (bus_space_map(sc->sc_st, IO_ICU1, 2, 0, &sc->sc_ioh_icu1) != 0) device_printf(dev, "unable to map ICU1 registers\n"); if (bus_space_map(sc->sc_st, IO_ICU2, 2, 0, &sc->sc_ioh_icu2) != 0) device_printf(dev, "unable to map ICU2 registers\n"); #else sc->sc_ioh_elcr = MIPS_PHYS_TO_KSEG1(sc->sc_io + 0x4d0); sc->sc_ioh_icu1 = MIPS_PHYS_TO_KSEG1(sc->sc_io + IO_ICU1); sc->sc_ioh_icu2 = MIPS_PHYS_TO_KSEG1(sc->sc_io + IO_ICU2); #endif /* All interrupts default to "masked off". */ sc->sc_imask = 0xffff; /* All interrupts default to edge-triggered. */ sc->sc_elcr = 0; /* * Initialize the 8259s. */ /* reset, program device, 4 bytes */ bus_space_write_1(sc->sc_st, sc->sc_ioh_icu1, 0, ICW1_RESET | ICW1_IC4); /* * XXX: values from NetBSD's */ bus_space_write_1(sc->sc_st, sc->sc_ioh_icu1, 1, 0/*XXX*/); bus_space_write_1(sc->sc_st, sc->sc_ioh_icu1, 1, 1 << 2); bus_space_write_1(sc->sc_st, sc->sc_ioh_icu1, 1, ICW4_8086); /* mask all interrupts */ bus_space_write_1(sc->sc_st, sc->sc_ioh_icu1, 1, sc->sc_imask & 0xff); /* enable special mask mode */ bus_space_write_1(sc->sc_st, sc->sc_ioh_icu1, 0, OCW3_SEL | OCW3_ESMM | OCW3_SMM); /* read IRR by default */ bus_space_write_1(sc->sc_st, sc->sc_ioh_icu1, 0, OCW3_SEL | OCW3_RR); /* reset, program device, 4 bytes */ bus_space_write_1(sc->sc_st, sc->sc_ioh_icu2, 0, ICW1_RESET | ICW1_IC4); bus_space_write_1(sc->sc_st, sc->sc_ioh_icu2, 1, 0/*XXX*/); bus_space_write_1(sc->sc_st, sc->sc_ioh_icu2, 1, 1 << 2); bus_space_write_1(sc->sc_st, sc->sc_ioh_icu2, 1, ICW4_8086); /* mask all interrupts */ bus_space_write_1(sc->sc_st, sc->sc_ioh_icu2, 1, sc->sc_imask & 0xff); /* enable special mask mode */ bus_space_write_1(sc->sc_st, sc->sc_ioh_icu2, 0, OCW3_SEL | OCW3_ESMM | OCW3_SMM); /* read IRR by default */ bus_space_write_1(sc->sc_st, sc->sc_ioh_icu2, 0, OCW3_SEL | OCW3_RR); /* * Default all interrupts to edge-triggered. */ bus_space_write_1(sc->sc_st, sc->sc_ioh_elcr, 0, sc->sc_elcr & 0xff); bus_space_write_1(sc->sc_st, sc->sc_ioh_elcr, 1, (sc->sc_elcr >> 8) & 0xff); /* * Some ISA interrupts are reserved for devices that * we know are hard-wired to certain IRQs. */ sc->sc_reserved = (1U << 0) | /* timer */ (1U << 1) | /* keyboard controller (keyboard) */ (1U << 2) | /* PIC cascade */ (1U << 3) | /* COM 2 */ (1U << 4) | /* COM 1 */ (1U << 6) | /* floppy */ (1U << 7) | /* centronics */ (1U << 8) | /* RTC */ (1U << 9) | /* I2C */ (1U << 12) | /* keyboard controller (mouse) */ (1U << 14) | /* IDE primary */ (1U << 15); /* IDE secondary */ /* Hook up our interrupt handler. */ if ((sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, MALTA_SOUTHBRIDGE_INTR, MALTA_SOUTHBRIDGE_INTR, 1, RF_SHAREABLE | RF_ACTIVE)) == NULL) { device_printf(dev, "unable to allocate IRQ resource\n"); return ENXIO; } if ((bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC, gt_pci_intr, NULL, sc, &sc->sc_ih))) { device_printf(dev, "WARNING: unable to register interrupt handler\n"); return ENXIO; } /* Initialize memory and i/o rmans. */ device_add_child(dev, "pci", -1); return (bus_generic_attach(dev)); } static int gt_pci_maxslots(device_t dev) { return (PCI_SLOTMAX); } static int gt_pci_conf_setup(struct gt_pci_softc *sc, int bus, int slot, int func, int reg, uint32_t *addr) { *addr = (bus << 16) | (slot << 11) | (func << 8) | reg; return (0); } static uint32_t gt_pci_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, int bytes) { struct gt_pci_softc *sc = device_get_softc(dev); uint32_t data; uint32_t addr; uint32_t shift, mask; if (gt_pci_conf_setup(sc, bus, slot, func, reg & ~3, &addr)) return (uint32_t)(-1); /* Clear cause register bits. */ GT_REGVAL(GT_INTR_CAUSE) = GT_PCI_DATA(0); GT_REGVAL(GT_PCI0_CFG_ADDR) = GT_PCI_DATA((1U << 31) | addr); /* * Galileo system controller is special */ if ((bus == 0) && (slot == 0)) data = GT_PCI_DATA(GT_REGVAL(GT_PCI0_CFG_DATA)); else data = GT_REGVAL(GT_PCI0_CFG_DATA); /* Check for master abort. */ if (GT_HOST_DATA(GT_REGVAL(GT_INTR_CAUSE)) & (GTIC_MASABORT0 | GTIC_TARABORT0)) data = (uint32_t) -1; switch(reg % 4) { case 3: shift = 24; break; case 2: shift = 16; break; case 1: shift = 8; break; default: shift = 0; break; } switch(bytes) { case 1: mask = 0xff; data = (data >> shift) & mask; break; case 2: mask = 0xffff; if(reg % 4 == 0) data = data & mask; else data = (data >> 16) & mask; break; case 4: break; default: panic("gt_pci_readconfig: wrong bytes count"); break; } #if 0 printf("PCICONF_READ(%02x:%02x.%02x[%04x] -> %02x(%d)\n", bus, slot, func, reg, data, bytes); #endif return (data); } static void gt_pci_write_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, uint32_t data, int bytes) { struct gt_pci_softc *sc = device_get_softc(dev); uint32_t addr; uint32_t reg_data; uint32_t shift, mask; if(bytes != 4) { reg_data = gt_pci_read_config(dev, bus, slot, func, reg, 4); shift = 8 * (reg & 3); switch(bytes) { case 1: mask = 0xff; data = (reg_data & ~ (mask << shift)) | (data << shift); break; case 2: mask = 0xffff; if(reg % 4 == 0) data = (reg_data & ~mask) | data; else data = (reg_data & ~ (mask << shift)) | (data << shift); break; case 4: break; default: panic("gt_pci_readconfig: wrong bytes count"); break; } } if (gt_pci_conf_setup(sc, bus, slot, func, reg & ~3, &addr)) return; /* The galileo has problems accessing device 31. */ if (bus == 0 && slot == 31) return; /* XXX: no support for bus > 0 yet */ if (bus > 0) return; /* Clear cause register bits. */ GT_REGVAL(GT_INTR_CAUSE) = GT_PCI_DATA(0); GT_REGVAL(GT_PCI0_CFG_ADDR) = GT_PCI_DATA((1U << 31) | addr); /* * Galileo system controller is special */ if ((bus == 0) && (slot == 0)) GT_REGVAL(GT_PCI0_CFG_DATA) = GT_PCI_DATA(data); else GT_REGVAL(GT_PCI0_CFG_DATA) = data; #if 0 printf("PCICONF_WRITE(%02x:%02x.%02x[%04x] -> %02x(%d)\n", bus, slot, func, reg, data, bytes); #endif } static int gt_pci_route_interrupt(device_t pcib, device_t dev, int pin) { int bus; int device; int func; /* struct gt_pci_softc *sc = device_get_softc(pcib); */ bus = pci_get_bus(dev); device = pci_get_slot(dev); func = pci_get_function(dev); /* * XXXMIPS: We need routing logic. This is just a stub . */ switch (device) { case 9: /* * PIIX4 IDE adapter. HW IRQ0 */ return 0; case 11: /* Ethernet */ return 10; default: device_printf(pcib, "no IRQ mapping for %d/%d/%d/%d\n", bus, device, func, pin); } return (0); } static int gt_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { struct gt_pci_softc *sc = device_get_softc(dev); switch (which) { case PCIB_IVAR_DOMAIN: *result = 0; return (0); case PCIB_IVAR_BUS: *result = sc->sc_busno; return (0); } return (ENOENT); } static int gt_write_ivar(device_t dev, device_t child, int which, uintptr_t result) { struct gt_pci_softc * sc = device_get_softc(dev); switch (which) { case PCIB_IVAR_BUS: sc->sc_busno = result; return (0); } return (ENOENT); } static struct resource * gt_pci_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct gt_pci_softc *sc = device_get_softc(bus); struct resource *rv = NULL; struct rman *rm; bus_space_handle_t bh = 0; switch (type) { case SYS_RES_IRQ: rm = &sc->sc_irq_rman; break; case SYS_RES_MEMORY: rm = &sc->sc_mem_rman; bh = sc->sc_mem; break; case SYS_RES_IOPORT: rm = &sc->sc_io_rman; bh = sc->sc_io; break; default: return (NULL); } rv = rman_reserve_resource(rm, start, end, count, flags, child); if (rv == NULL) return (NULL); rman_set_rid(rv, *rid); if (type != SYS_RES_IRQ) { bh += (rman_get_start(rv)); rman_set_bustag(rv, gt_pci_bus_space); rman_set_bushandle(rv, bh); if (flags & RF_ACTIVE) { if (bus_activate_resource(child, type, *rid, rv)) { rman_release_resource(rv); return (NULL); } } } return (rv); } static int gt_pci_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { bus_space_handle_t p; int error; if ((type == SYS_RES_MEMORY) || (type == SYS_RES_IOPORT)) { error = bus_space_map(rman_get_bustag(r), rman_get_bushandle(r), rman_get_size(r), 0, &p); if (error) return (error); rman_set_bushandle(r, p); } return (rman_activate_resource(r)); } static int gt_pci_setup_intr(device_t dev, device_t child, struct resource *ires, int flags, driver_filter_t *filt, driver_intr_t *handler, void *arg, void **cookiep) { struct gt_pci_softc *sc = device_get_softc(dev); struct intr_event *event; int irq, error; irq = rman_get_start(ires); if (irq >= ICU_LEN || irq == 2) panic("%s: bad irq or type", __func__); event = sc->sc_eventstab[irq]; sc->sc_intr_cookies[irq].irq = irq; sc->sc_intr_cookies[irq].sc = sc; if (event == NULL) { error = intr_event_create(&event, (void *)&sc->sc_intr_cookies[irq], 0, irq, gt_pci_mask_irq, gt_pci_unmask_irq, NULL, NULL, "gt_pci intr%d:", irq); if (error) return 0; sc->sc_eventstab[irq] = event; } intr_event_add_handler(event, device_get_nameunit(child), filt, handler, arg, intr_priority(flags), flags, cookiep); gt_pci_unmask_irq((void *)&sc->sc_intr_cookies[irq]); return 0; } static int gt_pci_teardown_intr(device_t dev, device_t child, struct resource *res, void *cookie) { struct gt_pci_softc *sc = device_get_softc(dev); int irq; irq = rman_get_start(res); gt_pci_mask_irq((void *)&sc->sc_intr_cookies[irq]); return (intr_event_remove_handler(cookie)); } static device_method_t gt_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, gt_pci_probe), DEVMETHOD(device_attach, gt_pci_attach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_read_ivar, gt_read_ivar), DEVMETHOD(bus_write_ivar, gt_write_ivar), DEVMETHOD(bus_alloc_resource, gt_pci_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, gt_pci_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, gt_pci_setup_intr), DEVMETHOD(bus_teardown_intr, gt_pci_teardown_intr), /* pcib interface */ DEVMETHOD(pcib_maxslots, gt_pci_maxslots), DEVMETHOD(pcib_read_config, gt_pci_read_config), DEVMETHOD(pcib_write_config, gt_pci_write_config), DEVMETHOD(pcib_route_interrupt, gt_pci_route_interrupt), DEVMETHOD(pcib_request_feature, pcib_request_feature_allow), DEVMETHOD_END }; static driver_t gt_pci_driver = { "pcib", gt_pci_methods, sizeof(struct gt_pci_softc), }; static devclass_t gt_pci_devclass; DRIVER_MODULE(gt_pci, gt, gt_pci_driver, gt_pci_devclass, 0, 0); Index: head/sys/mips/malta/gt_pci_bus_space.c =================================================================== --- head/sys/mips/malta/gt_pci_bus_space.c (revision 326258) +++ head/sys/mips/malta/gt_pci_bus_space.c (revision 326259) @@ -1,409 +1,411 @@ /* $NetBSD: bus.h,v 1.12 1997/10/01 08:25:15 fvdl Exp $ */ /*- * $Id: bus.h,v 1.6 2007/08/09 11:23:32 katta Exp $ * + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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. */ /* * Copyright (c) 1996 Charles M. Hannum. All rights reserved. * Copyright (c) 1996 Christopher G. Demetriou. 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Christopher G. Demetriou * for the NetBSD Project. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. * * from: src/sys/alpha/include/bus.h,v 1.5 1999/08/28 00:38:40 peter * $FreeBSD$ */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include static bs_r_2_proto(gt_pci); static bs_r_4_proto(gt_pci); static bs_w_2_proto(gt_pci); static bs_w_4_proto(gt_pci); static bs_rm_2_proto(gt_pci); static bs_rm_4_proto(gt_pci); static bs_wm_2_proto(gt_pci); static bs_wm_4_proto(gt_pci); static bs_rr_2_proto(gt_pci); static bs_rr_4_proto(gt_pci); static bs_wr_2_proto(gt_pci); static bs_wr_4_proto(gt_pci); static bs_sm_2_proto(gt_pci); static bs_sm_4_proto(gt_pci); static bs_sr_2_proto(gt_pci); static bs_sr_4_proto(gt_pci); static struct bus_space gt_pci_space = { /* cookie */ .bs_cookie = (void *) 0, /* mapping/unmapping */ .bs_map = generic_bs_map, .bs_unmap = generic_bs_unmap, .bs_subregion = generic_bs_subregion, /* allocation/deallocation */ .bs_alloc = generic_bs_alloc, .bs_free = generic_bs_free, /* barrier */ .bs_barrier = generic_bs_barrier, /* read (single) */ .bs_r_1 = generic_bs_r_1, .bs_r_2 = gt_pci_bs_r_2, .bs_r_4 = gt_pci_bs_r_4, .bs_r_8 = NULL, /* read multiple */ .bs_rm_1 = generic_bs_rm_1, .bs_rm_2 = gt_pci_bs_rm_2, .bs_rm_4 = gt_pci_bs_rm_4, .bs_rm_8 = NULL, /* read region */ .bs_rr_1 = generic_bs_rr_1, .bs_rr_2 = gt_pci_bs_rr_2, .bs_rr_4 = gt_pci_bs_rr_4, .bs_rr_8 = NULL, /* write (single) */ .bs_w_1 = generic_bs_w_1, .bs_w_2 = gt_pci_bs_w_2, .bs_w_4 = gt_pci_bs_w_4, .bs_w_8 = NULL, /* write multiple */ .bs_wm_1 = generic_bs_wm_1, .bs_wm_2 = gt_pci_bs_wm_2, .bs_wm_4 = gt_pci_bs_wm_4, .bs_wm_8 = NULL, /* write region */ .bs_wr_1 = generic_bs_wr_1, .bs_wr_2 = gt_pci_bs_wr_2, .bs_wr_4 = gt_pci_bs_wr_4, .bs_wr_8 = NULL, /* set multiple */ .bs_sm_1 = generic_bs_sm_1, .bs_sm_2 = gt_pci_bs_sm_2, .bs_sm_4 = gt_pci_bs_sm_4, .bs_sm_8 = NULL, /* set region */ .bs_sr_1 = generic_bs_sr_1, .bs_sr_2 = gt_pci_bs_sr_2, .bs_sr_4 = gt_pci_bs_sr_4, .bs_sr_8 = NULL, /* copy */ .bs_c_1 = generic_bs_c_1, .bs_c_2 = generic_bs_c_2, .bs_c_4 = generic_bs_c_4, .bs_c_8 = NULL, /* read (single) stream */ .bs_r_1_s = generic_bs_r_1, .bs_r_2_s = generic_bs_r_2, .bs_r_4_s = generic_bs_r_4, .bs_r_8_s = NULL, /* read multiple stream */ .bs_rm_1_s = generic_bs_rm_1, .bs_rm_2_s = generic_bs_rm_2, .bs_rm_4_s = generic_bs_rm_4, .bs_rm_8_s = NULL, /* read region stream */ .bs_rr_1_s = generic_bs_rr_1, .bs_rr_2_s = generic_bs_rr_2, .bs_rr_4_s = generic_bs_rr_4, .bs_rr_8_s = NULL, /* write (single) stream */ .bs_w_1_s = generic_bs_w_1, .bs_w_2_s = generic_bs_w_2, .bs_w_4_s = generic_bs_w_4, .bs_w_8_s = NULL, /* write multiple stream */ .bs_wm_1_s = generic_bs_wm_1, .bs_wm_2_s = generic_bs_wm_2, .bs_wm_4_s = generic_bs_wm_4, .bs_wm_8_s = NULL, /* write region stream */ .bs_wr_1_s = generic_bs_wr_1, .bs_wr_2_s = generic_bs_wr_2, .bs_wr_4_s = generic_bs_wr_4, .bs_wr_8_s = NULL, }; #define rd16(a) le16toh(readw(a)) #define rd32(a) le32toh(readl(a)) #define wr16(a, v) writew(a, htole16(v)) #define wr32(a, v) writel(a, htole32(v)) /* generic bus_space tag */ bus_space_tag_t gt_pci_bus_space = >_pci_space; uint16_t gt_pci_bs_r_2(void *t, bus_space_handle_t handle, bus_size_t offset) { return (rd16(handle + offset)); } uint32_t gt_pci_bs_r_4(void *t, bus_space_handle_t handle, bus_size_t offset) { return (rd32(handle + offset)); } void gt_pci_bs_rm_2(void *t, bus_space_handle_t bsh, bus_size_t offset, uint16_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) *addr++ = rd16(baddr); } void gt_pci_bs_rm_4(void *t, bus_space_handle_t bsh, bus_size_t offset, uint32_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) *addr++ = rd32(baddr); } /* * Read `count' 2 or 4 byte quantities from bus space * described by tag/handle and starting at `offset' and copy into * buffer provided. */ void gt_pci_bs_rr_2(void *t, bus_space_handle_t bsh, bus_size_t offset, uint16_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { *addr++ = rd16(baddr); baddr += 2; } } void gt_pci_bs_rr_4(void *t, bus_space_handle_t bsh, bus_size_t offset, uint32_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { *addr++ = rd32(baddr); baddr += 4; } } /* * Write the 2 or 4 byte value `value' to bus space * described by tag/handle/offset. */ void gt_pci_bs_w_2(void *t, bus_space_handle_t bsh, bus_size_t offset, uint16_t value) { wr16(bsh + offset, value); } void gt_pci_bs_w_4(void *t, bus_space_handle_t bsh, bus_size_t offset, uint32_t value) { wr32(bsh + offset, value); } /* * Write `count' 2 or 4 byte quantities from the buffer * provided to bus space described by tag/handle/offset. */ void gt_pci_bs_wm_2(void *t, bus_space_handle_t bsh, bus_size_t offset, const uint16_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) wr16(baddr, *addr++); } void gt_pci_bs_wm_4(void *t, bus_space_handle_t bsh, bus_size_t offset, const uint32_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) wr32(baddr, *addr++); } /* * Write `count' 2 or 4 byte quantities from the buffer provided * to bus space described by tag/handle starting at `offset'. */ void gt_pci_bs_wr_2(void *t, bus_space_handle_t bsh, bus_size_t offset, const uint16_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { wr16(baddr, *addr++); baddr += 2; } } void gt_pci_bs_wr_4(void *t, bus_space_handle_t bsh, bus_size_t offset, const uint32_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { wr32(baddr, *addr++); baddr += 4; } } /* * Write the 2 or 4 byte value `val' to bus space described * by tag/handle/offset `count' times. */ void gt_pci_bs_sm_2(void *t, bus_space_handle_t bsh, bus_size_t offset, uint16_t value, size_t count) { bus_addr_t addr = bsh + offset; while (count--) wr16(addr, value); } void gt_pci_bs_sm_4(void *t, bus_space_handle_t bsh, bus_size_t offset, uint32_t value, size_t count) { bus_addr_t addr = bsh + offset; while (count--) wr32(addr, value); } /* * Write `count' 2 or 4 byte value `val' to bus space described * by tag/handle starting at `offset'. */ void gt_pci_bs_sr_2(void *t, bus_space_handle_t bsh, bus_size_t offset, uint16_t value, size_t count) { bus_addr_t addr = bsh + offset; for (; count != 0; count--, addr += 2) wr16(addr, value); } void gt_pci_bs_sr_4(void *t, bus_space_handle_t bsh, bus_size_t offset, uint32_t value, size_t count) { bus_addr_t addr = bsh + offset; for (; count != 0; count--, addr += 4) wr32(addr, value); } Index: head/sys/mips/malta/gt_pci_bus_space.h =================================================================== --- head/sys/mips/malta/gt_pci_bus_space.h (revision 326258) +++ head/sys/mips/malta/gt_pci_bus_space.h (revision 326259) @@ -1,36 +1,38 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-NetBSD + * * Copyright (c) 2009, Oleksandr Tymoshenko * 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 unmodified, 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$ * */ #ifndef __GT_PCI_BUS_SPACEH__ #define __GT_PCI_BUS_SPACEH__ extern bus_space_tag_t gt_pci_bus_space; #endif /* __GT_PCI_BUS_SPACEH__ */ Index: head/sys/mips/malta/gtreg.h =================================================================== --- head/sys/mips/malta/gtreg.h (revision 326258) +++ head/sys/mips/malta/gtreg.h (revision 326259) @@ -1,119 +1,121 @@ /* $NetBSD: gtreg.h,v 1.2 2005/12/24 20:07:03 perry Exp $ */ /*- + * SPDX-License-Identifier: BSD-2-Clause-NetBSD + * * Copyright (c) 1997, 1998, 2001 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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$ */ #define GT_REGVAL(x) *((volatile u_int32_t *) \ (MIPS_PHYS_TO_KSEG1(MALTA_CORECTRL_BASE + (x)))) /* CPU Configuration Register Map */ #define GT_CPU_INT 0x000 #define GT_MULTIGT 0x120 /* CPU Address Decode Register Map */ /* CPU Error Report Register Map */ /* CPU Sync Barrier Register Map */ /* SDRAM and Device Address Decode Register Map */ /* SDRAM Configuration Register Map */ /* SDRAM Parameters Register Map */ /* ECC Register Map */ /* Device Parameters Register Map */ /* DMA Record Register Map */ /* DMA Arbiter Register Map */ /* Timer/Counter Register Map */ //#define GT_TC_0 0x850 //#define GT_TC_1 0x854 //#define GT_TC_2 0x858 //#define GT_TC_3 0x85c //#define GT_TC_CONTROL 0x864 /* PCI Internal Register Map */ #define GT_PCI0_CFG_ADDR 0xcf8 #define GT_PCI0_CFG_DATA 0xcfc #define GT_PCI0_INTR_ACK 0xc34 /* Interrupts Register Map */ #define GT_INTR_CAUSE 0xc18 #define GTIC_INTSUM 0x00000001 #define GTIC_MEMOUT 0x00000002 #define GTIC_DMAOUT 0x00000004 #define GTIC_CPUOUT 0x00000008 #define GTIC_DMA0COMP 0x00000010 #define GTIC_DMA1COMP 0x00000020 #define GTIC_DMA2COMP 0x00000040 #define GTIC_DMA3COMP 0x00000080 #define GTIC_T0EXP 0x00000100 #define GTIC_T1EXP 0x00000200 #define GTIC_T2EXP 0x00000400 #define GTIC_T3EXP 0x00000800 #define GTIC_MASRDERR0 0x00001000 #define GTIC_SLVWRERR0 0x00002000 #define GTIC_MASWRERR0 0x00004000 #define GTIC_SLVRDERR0 0x00008000 #define GTIC_ADDRERR0 0x00010000 #define GTIC_MEMERR 0x00020000 #define GTIC_MASABORT0 0x00040000 #define GTIC_TARABORT0 0x00080000 #define GTIC_RETRYCNT0 0x00100000 #define GTIC_PMCINT_0 0x00200000 #define GTIC_CPUINT 0x0c300000 #define GTIC_PCINT 0xc3000000 #define GTIC_CPUINTSUM 0x40000000 #define GTIC_PCIINTSUM 0x80000000 /* PCI Configuration Register Map */ //#define GT_PCICONFIGBASE 0 //#define GT_PCIDID BONITO(GT_PCICONFIGBASE + 0x00) //#define GT_PCICMD BONITO(GT_PCICONFIGBASE + 0x04) //#define GT_PCICLASS BONITO(GT_PCICONFIGBASE + 0x08) //#define GT_PCILTIMER BONITO(GT_PCICONFIGBASE + 0x0c) //#define GT_PCIBASE0 BONITO(GT_PCICONFIGBASE + 0x10) //#define GT_PCIBASE1 BONITO(GT_PCICONFIGBASE + 0x14) //#define GT_PCIBASE2 BONITO(GT_PCICONFIGBASE + 0x18) //#define GT_PCIEXPRBASE BONITO(GT_PCICONFIGBASE + 0x30) //#define GT_PCIINT BONITO(GT_PCICONFIGBASE + 0x3c) /* PCI Configuration, Function 1, Register Map */ /* I2O Support Register Map */ Index: head/sys/mips/malta/gtvar.h =================================================================== --- head/sys/mips/malta/gtvar.h (revision 326258) +++ head/sys/mips/malta/gtvar.h (revision 326259) @@ -1,36 +1,38 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2005 Olivier Houchard. 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 ``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 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$ */ #ifndef _GTVAR_H_ #define _GTVAR_H_ #include struct gt_softc { device_t dev; }; #endif /* _GTVAR_H_ */ Index: head/sys/mips/malta/malta_machdep.c =================================================================== --- head/sys/mips/malta/malta_machdep.c (revision 326258) +++ head/sys/mips/malta/malta_machdep.c (revision 326259) @@ -1,358 +1,360 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006 Wojciech A. Koszek * 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 __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #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 #ifdef TICK_USE_YAMON_FREQ #include #endif #ifdef TICK_USE_MALTA_RTC #include #include #include #endif #include extern int *edata; extern int *end; void lcd_init(void); void lcd_puts(char *); void malta_reset(void); /* * Temporary boot environment used at startup. */ static char boot1_env[4096]; /* * Offsets to MALTA LCD characters. */ static int malta_lcd_offs[] = { MALTA_ASCIIPOS0, MALTA_ASCIIPOS1, MALTA_ASCIIPOS2, MALTA_ASCIIPOS3, MALTA_ASCIIPOS4, MALTA_ASCIIPOS5, MALTA_ASCIIPOS6, MALTA_ASCIIPOS7 }; void platform_cpu_init() { /* Nothing special */ } /* * Put character to Malta LCD at given position. */ static void malta_lcd_putc(int pos, char c) { void *addr; char *ch; if (pos < 0 || pos > 7) return; addr = (void *)(MALTA_ASCII_BASE + malta_lcd_offs[pos]); ch = (char *)MIPS_PHYS_TO_KSEG0(addr); *ch = c; } /* * Print given string on LCD. */ static void malta_lcd_print(char *str) { int i; if (str == NULL) return; for (i = 0; *str != '\0'; i++, str++) malta_lcd_putc(i, *str); } void lcd_init(void) { malta_lcd_print("FreeBSD_"); } void lcd_puts(char *s) { malta_lcd_print(s); } #ifdef TICK_USE_MALTA_RTC static __inline uint8_t rtcin(uint8_t addr) { *((volatile uint8_t *) MIPS_PHYS_TO_KSEG1(MALTA_PCI0_ADDR(MALTA_RTCADR))) = addr; return (*((volatile uint8_t *) MIPS_PHYS_TO_KSEG1(MALTA_PCI0_ADDR(MALTA_RTCDAT)))); } static __inline void writertc(uint8_t addr, uint8_t val) { *((volatile uint8_t *) MIPS_PHYS_TO_KSEG1(MALTA_PCI0_ADDR(MALTA_RTCADR))) = addr; *((volatile uint8_t *) MIPS_PHYS_TO_KSEG1(MALTA_PCI0_ADDR(MALTA_RTCDAT))) = val; } #endif static void mips_init(unsigned long memsize, uint64_t ememsize) { int i; for (i = 0; i < PHYS_AVAIL_ENTRIES; i++) { phys_avail[i] = 0; } /* * memsize is the amount of RAM available below 256MB. * ememsize is the total amount of RAM available. * * The second bank starts at 0x90000000. */ /* phys_avail regions are in bytes */ phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end); phys_avail[1] = memsize; dump_avail[0] = 0; dump_avail[1] = phys_avail[1]; /* Only specify the extended region if it's set */ if (ememsize > memsize) { phys_avail[2] = 0x90000000; phys_avail[3] = 0x90000000 + (ememsize - memsize); dump_avail[2] = phys_avail[2]; dump_avail[3] = phys_avail[3]; } /* XXX realmem assigned in the caller of mips_init() */ physmem = realmem; init_param1(); init_param2(physmem); mips_cpu_init(); pmap_bootstrap(); mips_proc0_init(); mutex_init(); kdb_init(); #ifdef KDB if (boothowto & RB_KDB) kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); #endif } /* * Perform a board-level soft-reset. * Note that this is not emulated by gxemul. */ void platform_reset(void) { char *c; c = (char *)MIPS_PHYS_TO_KSEG0(MALTA_SOFTRES); *c = MALTA_GORESET; } static uint64_t malta_cpu_freq(void) { uint64_t platform_counter_freq = 0; #if defined(TICK_USE_YAMON_FREQ) /* * If we are running on a board which uses YAMON firmware, * then query CPU pipeline clock from the syscon object. * If unsuccessful, use hard-coded default. */ platform_counter_freq = yamon_getcpufreq(); #elif defined(TICK_USE_MALTA_RTC) /* * If we are running on a board with the MC146818 RTC, * use it to determine CPU pipeline clock frequency. */ u_int64_t counterval[2]; /* Set RTC to binary mode. */ writertc(RTC_STATUSB, (rtcin(RTC_STATUSB) | RTCSB_BCD)); /* Busy-wait for falling edge of RTC update. */ while (((rtcin(RTC_STATUSA) & RTCSA_TUP) == 0)) ; while (((rtcin(RTC_STATUSA)& RTCSA_TUP) != 0)) ; counterval[0] = mips_rd_count(); /* Busy-wait for falling edge of RTC update. */ while (((rtcin(RTC_STATUSA) & RTCSA_TUP) == 0)) ; while (((rtcin(RTC_STATUSA)& RTCSA_TUP) != 0)) ; counterval[1] = mips_rd_count(); platform_counter_freq = counterval[1] - counterval[0]; #endif if (platform_counter_freq == 0) platform_counter_freq = MIPS_DEFAULT_HZ; return (platform_counter_freq); } void platform_start(__register_t a0, __register_t a1, __register_t a2, __register_t a3) { vm_offset_t kernend; uint64_t platform_counter_freq; int argc = a0; int32_t *argv = (int32_t*)a1; int32_t *envp = (int32_t*)a2; unsigned int memsize = a3; uint64_t ememsize = 0; int i; /* clear the BSS and SBSS segments */ kernend = (vm_offset_t)&end; memset(&edata, 0, kernend - (vm_offset_t)(&edata)); mips_postboot_fixup(); mips_pcpu0_init(); platform_counter_freq = malta_cpu_freq(); mips_timer_early_init(platform_counter_freq); init_static_kenv(boot1_env, sizeof(boot1_env)); cninit(); printf("entry: platform_start()\n"); bootverbose = 1; /* * YAMON uses 32bit pointers to strings so * convert them to proper type manually */ if (bootverbose) { printf("cmd line: "); for (i = 0; i < argc; i++) printf("%s ", (char*)(intptr_t)argv[i]); printf("\n"); } if (bootverbose) printf("envp:\n"); /* * Parse the environment for things like ememsize. */ for (i = 0; envp[i]; i += 2) { const char *a, *v; a = (char *)(intptr_t)envp[i]; v = (char *)(intptr_t)envp[i+1]; if (bootverbose) printf("\t%s = %s\n", a, v); if (strcmp(a, "ememsize") == 0) { ememsize = strtoul(v, NULL, 0); } } if (bootverbose) { printf("memsize = %llu (0x%08x)\n", (unsigned long long) memsize, memsize); printf("ememsize = %llu\n", (unsigned long long) ememsize); } /* * For <= 256MB RAM amounts, ememsize should equal memsize. * For > 256MB RAM amounts it's the total RAM available; * split between two banks. * * XXX TODO: just push realmem assignment into mips_init() ? */ realmem = btoc(ememsize); mips_init(memsize, ememsize); mips_timer_init_params(platform_counter_freq, 0); } Index: head/sys/mips/malta/maltareg.h =================================================================== --- head/sys/mips/malta/maltareg.h (revision 326258) +++ head/sys/mips/malta/maltareg.h (revision 326259) @@ -1,243 +1,245 @@ /* $NetBSD: maltareg.h,v 1.1 2002/03/07 14:44:04 simonb Exp $ */ -/* +/*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright 2002 Wasabi Systems, Inc. * All rights reserved. * * Written by Simon Burge for Wasabi Systems, Inc. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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$ */ /* Memory Map 0000.0000 * 128MB Typically SDRAM (on Core Board) 0800.0000 * 256MB Typically PCI 1800.0000 * 62MB Typically PCI 1be0.0000 * 2MB Typically System controller's internal registers 1c00.0000 * 32MB Typically not used 1e00.0000 4MB Monitor Flash 1e40.0000 12MB reserved 1f00.0000 12MB Switches LEDs ASCII display Soft reset FPGA revision number CBUS UART (tty2) General Purpose I/O I2C controller 1f10.0000 * 11MB Typically System Controller specific 1fc0.0000 4MB Maps to Monitor Flash 1fd0.0000 * 3MB Typically System Controller specific * depends on implementation of the Core Board and of software */ /* CPU interrupts NMI South Bridge or NMI button 0 South Bridge INTR 1 South Bridge SMI 2 CBUS UART (tty2) 3 COREHI (Core Card) 4 CORELO (Core Card) 5 Not used, driven inactive (typically CPU internal timer interrupt IRQ mapping (as used by YAMON) 0 Timer South Bridge 1 Keyboard SuperIO 2 Reserved by South Bridge (for cascading) 3 UART (tty1) SuperIO 4 UART (tty0) SuperIO 5 Not used 6 Floppy Disk SuperIO 7 Parallel Port SuperIO 8 Real Time Clock South Bridge 9 I2C bus South Bridge 10 PCI A,B,eth PCI slot 1..4, Ethernet 11 PCI C,audio PCI slot 1..4, Audio, USB (South Bridge) PCI D,USB 12 Mouse SuperIO 13 Reserved by South Bridge 14 Primary IDE Primary IDE slot 15 Secondary IDE Secondary IDE slot/Compact flash connector */ #define MALTA_SYSTEMRAM_BASE 0x00000000ul /* System RAM: */ #define MALTA_SYSTEMRAM_SIZE 0x08000000 /* 128 MByte */ #define MALTA_PCIMEM1_BASE 0x08000000ul /* PCI 1 memory: */ #define MALTA_PCIMEM1_SIZE 0x08000000 /* 128 MByte */ #define MALTA_PCIMEM2_BASE 0x10000000ul /* PCI 2 memory: */ #define MALTA_PCIMEM2_SIZE 0x08000000 /* 128 MByte */ #define MALTA_PCIMEM3_BASE 0x18000000ul /* PCI 3 memory */ #define MALTA_PCIMEM3_SIZE 0x03e00000 /* 62 MByte */ #define MALTA_CORECTRL_BASE 0x1be00000ul /* Core control: */ #define MALTA_CORECTRL_SIZE 0x00200000 /* 2 MByte */ #define MALTA_RESERVED_BASE1 0x1c000000ul /* Reserved: */ #define MALTA_RESERVED_SIZE1 0x02000000 /* 32 MByte */ #define MALTA_MONITORFLASH_BASE 0x1e000000ul /* Monitor Flash: */ #define MALTA_MONITORFLASH_SIZE 0x003e0000 /* 4 MByte */ #define MALTA_MONITORFLASH_SECTORSIZE 0x00010000 /* Sect. = 64 KB */ #define MALTA_FILEFLASH_BASE 0x1e3e0000ul /* File Flash (for monitor): */ #define MALTA_FILEFLASH_SIZE 0x00020000 /* 128 KByte */ #define MALTA_FILEFLASH_SECTORSIZE 0x00010000 /* Sect. = 64 KB */ #define MALTA_RESERVED_BASE2 0x1e400000ul /* Reserved: */ #define MALTA_RESERVED_SIZE2 0x00c00000 /* 12 MByte */ #define MALTA_FPGA_BASE 0x1f000000ul /* FPGA: */ #define MALTA_FPGA_SIZE 0x00c00000 /* 12 MByte */ #define MALTA_NMISTATUS (MALTA_FPGA_BASE + 0x24) #define MALTA_NMI_SB 0x2 /* Pending NMI from the South Bridge */ #define MALTA_NMI_ONNMI 0x1 /* Pending NMI from the ON/NMI push button */ #define MALTA_NMIACK (MALTA_FPGA_BASE + 0x104) #define MALTA_NMIACK_ONNMI 0x1 /* Write 1 to acknowledge ON/NMI */ #define MALTA_SWITCH (MALTA_FPGA_BASE + 0x200) #define MALTA_SWITCH_MASK 0xff /* settings of DIP switch S2 */ #define MALTA_STATUS (MALTA_FPGA_BASE + 0x208) #define MALTA_ST_MFWR 0x10 /* Monitor Flash is write protected (JP1) */ #define MALTA_S54 0x08 /* switch S5-4 - set YAMON factory default mode */ #define MALTA_S53 0x04 /* switch S5-3 */ #define MALTA_BIGEND 0x02 /* switch S5-2 - big endian mode */ #define MALTA_JMPRS (MALTA_FPGA_BASE + 0x210) #define MALTA_JMPRS_PCICLK 0x1c /* PCI clock frequency */ #define MALTA_JMPRS_EELOCK 0x02 /* I2C EEPROM is write protected */ #define MALTA_LEDBAR (MALTA_FPGA_BASE + 0x408) #define MALTA_ASCIIWORD (MALTA_FPGA_BASE + 0x410) #define MALTA_ASCII_BASE (MALTA_FPGA_BASE + 0x418) #define MALTA_ASCIIPOS0 0x00 #define MALTA_ASCIIPOS1 0x08 #define MALTA_ASCIIPOS2 0x10 #define MALTA_ASCIIPOS3 0x18 #define MALTA_ASCIIPOS4 0x20 #define MALTA_ASCIIPOS5 0x28 #define MALTA_ASCIIPOS6 0x30 #define MALTA_ASCIIPOS7 0x38 #define MALTA_SOFTRES (MALTA_FPGA_BASE + 0x500) #define MALTA_GORESET 0x42 /* write this to MALTA_SOFTRES for board reset */ /* * BRKRES is the number of milliseconds before a "break" on tty will * trigger a reset. A value of 0 will disable the reset. */ #define MALTA_BRKRES (MALTA_FPGA_BASE + 0x508) #define MALTA_BRKRES_MASK 0xff #define MALTA_CBUSUART (MALTA_FPGA_BASE + 0x900) /* 16C550C UART, 8 bit registers on 8 byte boundaries */ /* RXTX 0x00 */ /* INTEN 0x08 */ /* IIFIFO 0x10 */ /* LCTRL 0x18 */ /* MCTRL 0x20 */ /* LSTAT 0x28 */ /* MSTAT 0x30 */ /* SCRATCH 0x38 */ #define MALTA_CBUSUART_INTR 2 #define MALTA_GPIO_BASE (MALTA_FPGA_BASE + 0xa00) #define MALTA_GPOUT 0x0 #define MALTA_GPINP 0x8 #define MALTA_I2C_BASE (MALTA_FPGA_BASE + 0xb00) #define MALTA_I2CINP 0x00 #define MALTA_I2COE 0x08 #define MALTA_I2COUT 0x10 #define MALTA_I2CSEL 0x18 #define MALTA_BOOTROM_BASE 0x1fc00000ul /* Boot ROM: */ #define MALTA_BOOTROM_SIZE 0x00400000 /* 4 MByte */ #define MALTA_REVISION 0x1fc00010ul #define MALTA_REV_FPGRV 0xff0000 /* CBUS FPGA revision */ #define MALTA_REV_CORID 0x00fc00 /* Core Board ID */ #define MALTA_REV_CORRV 0x000300 /* Core Board Revision */ #define MALTA_REV_PROID 0x0000f0 /* Product ID */ #define MALTA_REV_PRORV 0x00000f /* Product Revision */ /* PCI definitions */ #define MALTA_SOUTHBRIDGE_INTR 0 #define MALTA_PCI0_IO_BASE MALTA_PCIMEM3_BASE #define MALTA_PCI0_ADDR( addr ) (MALTA_PCI0_IO_BASE + (addr)) #define MALTA_RTCADR 0x70 // MALTA_PCI_IO_ADDR8(0x70) #define MALTA_RTCDAT 0x71 // MALTA_PCI_IO_ADDR8(0x71) #define MALTA_SMSC_COM1_ADR 0x3f8 #define MALTA_SMSC_COM2_ADR 0x2f8 #define MALTA_UART0ADR MALTA_PCI0_ADDR(MALTA_SMSC_COM1_ADR) #define MALTA_UART1ADR MALTA_SMSC_COM2_ADR // MALTA_PCI0_ADDR(MALTA_SMSC_COM2_ADR) #define MALTA_SMSC_1284_ADR 0x378 #define MALTA_1284ADR MALTA_SMSC_1284_ADR // MALTA_PCI0_ADDR(MALTA_SMSC_1284_ADR) #define MALTA_SMSC_FDD_ADR 0x3f0 #define MALTA_FDDADR MALTA_SMSC_FDD_ADR // MALTA_PCI0_ADDR(MALTA_SMSC_FDD_ADR) #define MALTA_SMSC_KYBD_ADR 0x60 /* Fixed 0x60, 0x64 */ #define MALTA_KYBDADR MALTA_SMSC_KYBD_ADR // MALTA_PCI0_ADDR(MALTA_SMSC_KYBD_ADR) #define MALTA_SMSC_MOUSE_ADR MALTA_SMSC_KYBD_ADR #define MALTA_MOUSEADR MALTA_KYBDADR #define MALTA_DMA_PCI_PCIBASE 0x00000000UL #define MALTA_DMA_PCI_PHYSBASE 0x00000000UL #define MALTA_DMA_PCI_SIZE (256 * 1024 * 1024) #define MALTA_DMA_ISA_PCIBASE 0x00800000UL #define MALTA_DMA_ISA_PHYSBASE 0x00000000UL #define MALTA_DMA_ISA_SIZE (8 * 1024 * 1024) #ifndef _LOCORE void led_bar(uint8_t); void led_display_word(uint32_t); void led_display_str(const char *); void led_display_char(int, uint8_t); #endif Index: head/sys/mips/malta/obio.c =================================================================== --- head/sys/mips/malta/obio.c (revision 326258) +++ head/sys/mips/malta/obio.c (revision 326259) @@ -1,183 +1,185 @@ /* $NetBSD: obio.c,v 1.11 2003/07/15 00:25:05 lukem Exp $ */ /*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright (c) 2001, 2002, 2003 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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. */ /* * On-board device autoconfiguration support for Intel IQ80321 * evaluation boards. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include int obio_probe(device_t); int obio_attach(device_t); /* * A bit tricky and hackish. Since we need OBIO to rely * on PCI we make it pseudo-pci device. But there should * be only one such device, so we use this static flag * to prevent false positives on every real PCI device probe. */ static int have_one = 0; int obio_probe(device_t dev) { if (!have_one) { have_one = 1; return 0; } return (ENXIO); } int obio_attach(device_t dev) { struct obio_softc *sc = device_get_softc(dev); sc->oba_st = mips_bus_space_generic; sc->oba_addr = MIPS_PHYS_TO_KSEG1(MALTA_UART0ADR); sc->oba_size = MALTA_PCIMEM3_SIZE; sc->oba_rman.rm_type = RMAN_ARRAY; sc->oba_rman.rm_descr = "OBIO I/O"; if (rman_init(&sc->oba_rman) != 0 || rman_manage_region(&sc->oba_rman, sc->oba_addr, sc->oba_addr + sc->oba_size) != 0) panic("obio_attach: failed to set up I/O rman"); sc->oba_irq_rman.rm_type = RMAN_ARRAY; sc->oba_irq_rman.rm_descr = "OBIO IRQ"; /* * This module is intended for UART purposes only and * it's IRQ is 4 */ if (rman_init(&sc->oba_irq_rman) != 0 || rman_manage_region(&sc->oba_irq_rman, 4, 4) != 0) panic("obio_attach: failed to set up IRQ rman"); device_add_child(dev, "uart", 0); bus_generic_probe(dev); bus_generic_attach(dev); return (0); } static struct resource * obio_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct resource *rv; struct rman *rm; bus_space_tag_t bt = 0; bus_space_handle_t bh = 0; struct obio_softc *sc = device_get_softc(bus); switch (type) { case SYS_RES_IRQ: rm = &sc->oba_irq_rman; break; case SYS_RES_MEMORY: return (NULL); case SYS_RES_IOPORT: rm = &sc->oba_rman; bt = sc->oba_st; bh = sc->oba_addr; start = bh; break; default: return (NULL); } rv = rman_reserve_resource(rm, start, end, count, flags, child); if (rv == NULL) return (NULL); if (type == SYS_RES_IRQ) return (rv); rman_set_rid(rv, *rid); rman_set_bustag(rv, bt); rman_set_bushandle(rv, bh); if (0) { if (bus_activate_resource(child, type, *rid, rv)) { rman_release_resource(rv); return (NULL); } } return (rv); } static int obio_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { return (0); } static device_method_t obio_methods[] = { DEVMETHOD(device_probe, obio_probe), DEVMETHOD(device_attach, obio_attach), DEVMETHOD(bus_alloc_resource, obio_alloc_resource), DEVMETHOD(bus_activate_resource, obio_activate_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), {0, 0}, }; static driver_t obio_driver = { "obio", obio_methods, sizeof(struct obio_softc), }; static devclass_t obio_devclass; DRIVER_MODULE(obio, pci, obio_driver, obio_devclass, 0, 0); Index: head/sys/mips/malta/obiovar.h =================================================================== --- head/sys/mips/malta/obiovar.h (revision 326258) +++ head/sys/mips/malta/obiovar.h (revision 326259) @@ -1,58 +1,60 @@ /* $NetBSD: obiovar.h,v 1.4 2003/06/16 17:40:53 thorpej Exp $ */ /*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright (c) 2002, 2003 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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$ * */ #ifndef _MALTA_OBIOVAR_H_ #define _MALTA_OBIOVAR_H_ #include struct obio_softc { bus_space_tag_t oba_st; /* bus space tag */ bus_addr_t oba_addr; /* address of device */ bus_size_t oba_size; /* size of device */ int oba_width; /* bus width */ int oba_irq; /* XINT interrupt bit # */ struct rman oba_rman; struct rman oba_irq_rman; }; extern struct bus_space obio_bs_tag; #endif /* _MALTA_OBIOVAR_H_ */ Index: head/sys/mips/malta/uart_bus_maltausart.c =================================================================== --- head/sys/mips/malta/uart_bus_maltausart.c (revision 326258) +++ head/sys/mips/malta/uart_bus_maltausart.c (revision 326259) @@ -1,91 +1,93 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006 Wojciech A. Koszek * 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 * $Id$ */ /* * Skeleton of this file was based on respective code for ARM * code written by Olivier Houchard. */ #include "opt_uart.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "uart_if.h" static int uart_malta_probe(device_t dev); extern struct uart_class malta_uart_class; static device_method_t uart_malta_methods[] = { /* Device interface */ DEVMETHOD(device_probe, uart_malta_probe), DEVMETHOD(device_attach, uart_bus_attach), DEVMETHOD(device_detach, uart_bus_detach), { 0, 0 } }; static driver_t uart_malta_driver = { uart_driver_name, uart_malta_methods, sizeof(struct uart_softc), }; extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs; static int uart_malta_probe(device_t dev) { struct uart_softc *sc; sc = device_get_softc(dev); sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs); sc->sc_class = &uart_ns8250_class; bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas)); sc->sc_sysdev->bas.bst = mips_bus_space_generic; sc->sc_sysdev->bas.bsh = MIPS_PHYS_TO_KSEG1(MALTA_UART0ADR); sc->sc_bas.bst = mips_bus_space_generic; sc->sc_bas.bsh = MIPS_PHYS_TO_KSEG1(MALTA_UART0ADR); return(uart_bus_probe(dev, 0, 0, 0, 0, 0)); } DRIVER_MODULE(uart, obio, uart_malta_driver, uart_devclass, 0, 0); Index: head/sys/mips/malta/uart_cpu_maltausart.c =================================================================== --- head/sys/mips/malta/uart_cpu_maltausart.c (revision 326258) +++ head/sys/mips/malta/uart_cpu_maltausart.c (revision 326259) @@ -1,78 +1,80 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006 Wojciech A. Koszek * 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. * * $Id$ */ /* * Skeleton of this file was based on respective code for ARM * code written by Olivier Houchard. */ #include "opt_uart.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include bus_space_tag_t uart_bus_space_io; bus_space_tag_t uart_bus_space_mem; extern struct uart_ops malta_usart_ops; extern struct bus_space malta_bs_tag; int uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) { return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0); } int uart_cpu_getdev(int devtype, struct uart_devinfo *di) { di->ops = uart_getops(&uart_ns8250_class); di->bas.chan = 0; di->bas.bst = mips_bus_space_generic; di->bas.bsh = MIPS_PHYS_TO_KSEG1(MALTA_UART0ADR); di->bas.regshft = 0; di->bas.rclk = 0; di->baudrate = 0; /* retain the baudrate configured by YAMON */ di->databits = 8; di->stopbits = 1; di->parity = UART_PARITY_NONE; uart_bus_space_io = NULL; uart_bus_space_mem = mips_bus_space_generic; return (0); } Index: head/sys/mips/malta/yamon.c =================================================================== --- head/sys/mips/malta/yamon.c (revision 326258) +++ head/sys/mips/malta/yamon.c (revision 326259) @@ -1,66 +1,68 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006-2008 Bruce M. Simpson * 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, * without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * 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 char * yamon_getenv(char *name) { char *value; yamon_env_t *p; value = NULL; for (p = *fenvp; p->name != NULL; ++p) { if (!strcmp(name, p->name)) { value = p->value; break; } } return (value); } uint32_t yamon_getcpufreq(void) { uint32_t freq; int ret; freq = 0; ret = YAMON_SYSCON_READ(SYSCON_BOARD_CPU_CLOCK_FREQ_ID, &freq, sizeof(freq)); if (ret != 0) freq = 0; return (freq); } Index: head/sys/mips/malta/yamon.h =================================================================== --- head/sys/mips/malta/yamon.h (revision 326258) +++ head/sys/mips/malta/yamon.h (revision 326259) @@ -1,93 +1,95 @@ /*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright 2002 Wasabi Systems, Inc. * All rights reserved. * * Written by Simon Burge for Wasabi Systems, Inc. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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$ */ #ifndef _MALTA_YAMON_H_ #define _MALTA_YAMON_H_ #define YAMON_FUNCTION_BASE 0x1fc00500ul #define YAMON_PRINT_COUNT_OFS (YAMON_FUNCTION_BASE + 0x04) #define YAMON_EXIT_OFS (YAMON_FUNCTION_BASE + 0x20) #define YAMON_FLUSH_CACHE_OFS (YAMON_FUNCTION_BASE + 0x2c) #define YAMON_PRINT_OFS (YAMON_FUNCTION_BASE + 0x34) #define YAMON_REG_CPU_ISR_OFS (YAMON_FUNCTION_BASE + 0x38) #define YAMON_DEREG_CPU_ISR_OFS (YAMON_FUNCTION_BASE + 0x3c) #define YAMON_REG_IC_ISR_OFS (YAMON_FUNCTION_BASE + 0x40) #define YAMON_DEREG_IC_ISR_OFS (YAMON_FUNCTION_BASE + 0x44) #define YAMON_REG_ESR_OFS (YAMON_FUNCTION_BASE + 0x48) #define YAMON_DEREG_ESR_OFS (YAMON_FUNCTION_BASE + 0x4c) #define YAMON_GETCHAR_OFS (YAMON_FUNCTION_BASE + 0x50) #define YAMON_SYSCON_READ_OFS (YAMON_FUNCTION_BASE + 0x54) #define YAMON_FUNC(ofs) ((long)(*(int32_t *)(MIPS_PHYS_TO_KSEG0(ofs)))) typedef void (*t_yamon_print_count)(uint32_t port, char *s, uint32_t count); #define YAMON_PRINT_COUNT(s, count) \ ((t_yamon_print_count)(YAMON_FUNC(YAMON_PRINT_COUNT_OFS)))(0, s, count) typedef void (*t_yamon_exit)(uint32_t rc); #define YAMON_EXIT(rc) ((t_yamon_exit)(YAMON_FUNC(YAMON_EXIT_OFS)))(rc) typedef void (*t_yamon_print)(uint32_t port, const char *s); #define YAMON_PRINT(s) ((t_yamon_print)(YAMON_FUNC(YAMON_PRINT_OFS)))(0, s) typedef int (*t_yamon_getchar)(uint32_t port, char *ch); #define YAMON_GETCHAR(ch) \ ((t_yamon_getchar)(YAMON_FUNC(YAMON_GETCHAR_OFS)))(0, ch) typedef int t_yamon_syscon_id; typedef int (*t_yamon_syscon_read)(t_yamon_syscon_id id, void *param, uint32_t size); #define YAMON_SYSCON_READ(id, param, size) \ ((t_yamon_syscon_read)(YAMON_FUNC(YAMON_SYSCON_READ_OFS))) \ (id, param, size) typedef struct { char *name; char *value; } yamon_env_t; #define SYSCON_BOARD_CPU_CLOCK_FREQ_ID 34 /* UINT32 */ #define SYSCON_BOARD_BUS_CLOCK_FREQ_ID 35 /* UINT32 */ #define SYSCON_BOARD_PCI_FREQ_KHZ_ID 36 /* UINT32 */ char* yamon_getenv(char *name); uint32_t yamon_getcpufreq(void); extern yamon_env_t *fenvp[]; #endif /* _MALTA_YAMON_H_ */ Index: head/sys/mips/mips/bus_space_generic.c =================================================================== --- head/sys/mips/mips/bus_space_generic.c (revision 326258) +++ head/sys/mips/mips/bus_space_generic.c (revision 326259) @@ -1,750 +1,752 @@ /* $NetBSD: bus.h,v 1.12 1997/10/01 08:25:15 fvdl Exp $ */ /*- * $Id: bus.h,v 1.6 2007/08/09 11:23:32 katta Exp $ * + * SPDX-License-Identifier: BSD-2-Clause-NetBSD AND BSD-4-Clause + * * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. */ /* * Copyright (c) 1996 Charles M. Hannum. All rights reserved. * Copyright (c) 1996 Christopher G. Demetriou. 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Christopher G. Demetriou * for the NetBSD Project. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. * * from: src/sys/alpha/include/bus.h,v 1.5 1999/08/28 00:38:40 peter * $FreeBSD$ */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include static struct bus_space generic_space = { /* cookie */ .bs_cookie = (void *) 0, /* mapping/unmapping */ .bs_map = generic_bs_map, .bs_unmap = generic_bs_unmap, .bs_subregion = generic_bs_subregion, /* allocation/deallocation */ .bs_alloc = generic_bs_alloc, .bs_free = generic_bs_free, /* barrier */ .bs_barrier = generic_bs_barrier, /* read (single) */ .bs_r_1 = generic_bs_r_1, .bs_r_2 = generic_bs_r_2, .bs_r_4 = generic_bs_r_4, .bs_r_8 = generic_bs_r_8, /* read multiple */ .bs_rm_1 = generic_bs_rm_1, .bs_rm_2 = generic_bs_rm_2, .bs_rm_4 = generic_bs_rm_4, .bs_rm_8 = generic_bs_rm_8, /* read region */ .bs_rr_1 = generic_bs_rr_1, .bs_rr_2 = generic_bs_rr_2, .bs_rr_4 = generic_bs_rr_4, .bs_rr_8 = generic_bs_rr_8, /* write (single) */ .bs_w_1 = generic_bs_w_1, .bs_w_2 = generic_bs_w_2, .bs_w_4 = generic_bs_w_4, .bs_w_8 = generic_bs_w_8, /* write multiple */ .bs_wm_1 = generic_bs_wm_1, .bs_wm_2 = generic_bs_wm_2, .bs_wm_4 = generic_bs_wm_4, .bs_wm_8 = generic_bs_wm_8, /* write region */ .bs_wr_1 = generic_bs_wr_1, .bs_wr_2 = generic_bs_wr_2, .bs_wr_4 = generic_bs_wr_4, .bs_wr_8 = generic_bs_wr_8, /* set multiple */ .bs_sm_1 = generic_bs_sm_1, .bs_sm_2 = generic_bs_sm_2, .bs_sm_4 = generic_bs_sm_4, .bs_sm_8 = generic_bs_sm_8, /* set region */ .bs_sr_1 = generic_bs_sr_1, .bs_sr_2 = generic_bs_sr_2, .bs_sr_4 = generic_bs_sr_4, .bs_sr_8 = generic_bs_sr_8, /* copy */ .bs_c_1 = generic_bs_c_1, .bs_c_2 = generic_bs_c_2, .bs_c_4 = generic_bs_c_4, .bs_c_8 = generic_bs_c_8, /* read (single) stream */ .bs_r_1_s = generic_bs_r_1, .bs_r_2_s = generic_bs_r_2, .bs_r_4_s = generic_bs_r_4, .bs_r_8_s = generic_bs_r_8, /* read multiple stream */ .bs_rm_1_s = generic_bs_rm_1, .bs_rm_2_s = generic_bs_rm_2, .bs_rm_4_s = generic_bs_rm_4, .bs_rm_8_s = generic_bs_rm_8, /* read region stream */ .bs_rr_1_s = generic_bs_rr_1, .bs_rr_2_s = generic_bs_rr_2, .bs_rr_4_s = generic_bs_rr_4, .bs_rr_8_s = generic_bs_rr_8, /* write (single) stream */ .bs_w_1_s = generic_bs_w_1, .bs_w_2_s = generic_bs_w_2, .bs_w_4_s = generic_bs_w_4, .bs_w_8_s = generic_bs_w_8, /* write multiple stream */ .bs_wm_1_s = generic_bs_wm_1, .bs_wm_2_s = generic_bs_wm_2, .bs_wm_4_s = generic_bs_wm_4, .bs_wm_8_s = generic_bs_wm_8, /* write region stream */ .bs_wr_1_s = generic_bs_wr_1, .bs_wr_2_s = generic_bs_wr_2, .bs_wr_4_s = generic_bs_wr_4, .bs_wr_8_s = generic_bs_wr_8, }; /* Ultra-gross kludge */ #if defined(CPU_CNMIPS) && (defined(__mips_n32) || defined(__mips_o32)) #include #define rd8(a) cvmx_read64_uint8(a) #define rd16(a) cvmx_read64_uint16(a) #define rd32(a) cvmx_read64_uint32(a) #define rd64(a) cvmx_read64_uint64(a) #define wr8(a, v) cvmx_write64_uint8(a, v) #define wr16(a, v) cvmx_write64_uint16(a, v) #define wr32(a, v) cvmx_write64_uint32(a, v) #define wr64(a, v) cvmx_write64_uint64(a, v) #elif defined(CPU_SB1) && _BYTE_ORDER == _BIG_ENDIAN #include #define rd8(a) sb_big_endian_read8(a) #define rd16(a) sb_big_endian_read16(a) #define rd32(a) sb_big_endian_read32(a) #define wr8(a, v) sb_big_endian_write8(a, v) #define wr16(a, v) sb_big_endian_write16(a, v) #define wr32(a, v) sb_big_endian_write32(a, v) #else #define rd8(a) readb(a) #define rd16(a) readw(a) #define rd32(a) readl(a) #ifdef readq #define rd64(a) readq((a)) #endif #define wr8(a, v) writeb(a, v) #define wr16(a, v) writew(a, v) #define wr32(a, v) writel(a, v) #ifdef writeq #define wr64(a, v) writeq(a, v) #endif #endif /* generic bus_space tag */ bus_space_tag_t mips_bus_space_generic = &generic_space; int generic_bs_map(void *t __unused, bus_addr_t addr, bus_size_t size, int flags __unused, bus_space_handle_t *bshp) { *bshp = (bus_space_handle_t)pmap_mapdev((vm_paddr_t)addr, (vm_size_t)size); return (0); } void generic_bs_unmap(void *t __unused, bus_space_handle_t bh, bus_size_t size) { pmap_unmapdev((vm_offset_t)bh, (vm_size_t)size); } int generic_bs_subregion(void *t __unused, bus_space_handle_t handle, bus_size_t offset, bus_size_t size __unused, bus_space_handle_t *bshp) { *bshp = handle + offset; return (0); } int generic_bs_alloc(void *t, bus_addr_t rstart, bus_addr_t rend, bus_size_t size, bus_size_t alignment, bus_size_t boundary, int flags, bus_addr_t *bpap, bus_space_handle_t *bshp) { panic("%s: not implemented", __func__); } void generic_bs_free(void *t, bus_space_handle_t bsh, bus_size_t size) { panic("%s: not implemented", __func__); } uint8_t generic_bs_r_1(void *t, bus_space_handle_t handle, bus_size_t offset) { return (rd8(handle + offset)); } uint16_t generic_bs_r_2(void *t, bus_space_handle_t handle, bus_size_t offset) { return (rd16(handle + offset)); } uint32_t generic_bs_r_4(void *t, bus_space_handle_t handle, bus_size_t offset) { return (rd32(handle + offset)); } uint64_t generic_bs_r_8(void *t, bus_space_handle_t handle, bus_size_t offset) { #ifdef rd64 return(rd64(handle + offset)); #else panic("%s: not implemented", __func__); #endif } void generic_bs_rm_1(void *t, bus_space_handle_t bsh, bus_size_t offset, uint8_t *addr, size_t count) { while (count--) *addr++ = rd8(bsh + offset); } void generic_bs_rm_2(void *t, bus_space_handle_t bsh, bus_size_t offset, uint16_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) *addr++ = rd16(baddr); } void generic_bs_rm_4(void *t, bus_space_handle_t bsh, bus_size_t offset, uint32_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) *addr++ = rd32(baddr); } void generic_bs_rm_8(void *t, bus_space_handle_t bsh, bus_size_t offset, uint64_t *addr, size_t count) { #ifdef rd64 bus_addr_t baddr = bsh + offset; while (count--) *addr++ = rd64(baddr); #else panic("%s: not implemented", __func__); #endif } /* * Read `count' 1, 2, 4, or 8 byte quantities from bus space * described by tag/handle and starting at `offset' and copy into * buffer provided. */ void generic_bs_rr_1(void *t, bus_space_handle_t bsh, bus_size_t offset, uint8_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { *addr++ = rd8(baddr); baddr += 1; } } void generic_bs_rr_2(void *t, bus_space_handle_t bsh, bus_size_t offset, uint16_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { *addr++ = rd16(baddr); baddr += 2; } } void generic_bs_rr_4(void *t, bus_space_handle_t bsh, bus_size_t offset, uint32_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { *addr++ = rd32(baddr); baddr += 4; } } void generic_bs_rr_8(void *t, bus_space_handle_t bsh, bus_size_t offset, uint64_t *addr, size_t count) { #ifdef rd64 bus_addr_t baddr = bsh + offset; while (count--) { *addr++ = rd64(baddr); baddr += 8; } #else panic("%s: not implemented", __func__); #endif } /* * Write the 1, 2, 4, or 8 byte value `value' to bus space * described by tag/handle/offset. */ void generic_bs_w_1(void *t, bus_space_handle_t bsh, bus_size_t offset, uint8_t value) { wr8(bsh + offset, value); } void generic_bs_w_2(void *t, bus_space_handle_t bsh, bus_size_t offset, uint16_t value) { wr16(bsh + offset, value); } void generic_bs_w_4(void *t, bus_space_handle_t bsh, bus_size_t offset, uint32_t value) { wr32(bsh + offset, value); } void generic_bs_w_8(void *t, bus_space_handle_t bsh, bus_size_t offset, uint64_t value) { #ifdef wr64 wr64(bsh + offset, value); #else panic("%s: not implemented", __func__); #endif } /* * Write `count' 1, 2, 4, or 8 byte quantities from the buffer * provided to bus space described by tag/handle/offset. */ void generic_bs_wm_1(void *t, bus_space_handle_t bsh, bus_size_t offset, const uint8_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) wr8(baddr, *addr++); } void generic_bs_wm_2(void *t, bus_space_handle_t bsh, bus_size_t offset, const uint16_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) wr16(baddr, *addr++); } void generic_bs_wm_4(void *t, bus_space_handle_t bsh, bus_size_t offset, const uint32_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) wr32(baddr, *addr++); } void generic_bs_wm_8(void *t, bus_space_handle_t bsh, bus_size_t offset, const uint64_t *addr, size_t count) { #ifdef wr64 bus_addr_t baddr = bsh + offset; while (count--) wr64(baddr, *addr++); #else panic("%s: not implemented", __func__); #endif } /* * Write `count' 1, 2, 4, or 8 byte quantities from the buffer provided * to bus space described by tag/handle starting at `offset'. */ void generic_bs_wr_1(void *t, bus_space_handle_t bsh, bus_size_t offset, const uint8_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { wr8(baddr, *addr++); baddr += 1; } } void generic_bs_wr_2(void *t, bus_space_handle_t bsh, bus_size_t offset, const uint16_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { wr16(baddr, *addr++); baddr += 2; } } void generic_bs_wr_4(void *t, bus_space_handle_t bsh, bus_size_t offset, const uint32_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { wr32(baddr, *addr++); baddr += 4; } } void generic_bs_wr_8(void *t, bus_space_handle_t bsh, bus_size_t offset, const uint64_t *addr, size_t count) { #ifdef wr64 bus_addr_t baddr = bsh + offset; while (count--) { wr64(baddr, *addr++); baddr += 8; } #else panic("%s: not implemented", __func__); #endif } /* * Write the 1, 2, 4, or 8 byte value `val' to bus space described * by tag/handle/offset `count' times. */ void generic_bs_sm_1(void *t, bus_space_handle_t bsh, bus_size_t offset, uint8_t value, size_t count) { bus_addr_t addr = bsh + offset; while (count--) wr8(addr, value); } void generic_bs_sm_2(void *t, bus_space_handle_t bsh, bus_size_t offset, uint16_t value, size_t count) { bus_addr_t addr = bsh + offset; while (count--) wr16(addr, value); } void generic_bs_sm_4(void *t, bus_space_handle_t bsh, bus_size_t offset, uint32_t value, size_t count) { bus_addr_t addr = bsh + offset; while (count--) wr32(addr, value); } void generic_bs_sm_8(void *t, bus_space_handle_t bsh, bus_size_t offset, uint64_t value, size_t count) { #ifdef wr64 bus_addr_t addr = bsh + offset; while (count--) wr64(addr, value); #else panic("%s: not implemented", __func__); #endif } /* * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described * by tag/handle starting at `offset'. */ void generic_bs_sr_1(void *t, bus_space_handle_t bsh, bus_size_t offset, uint8_t value, size_t count) { bus_addr_t addr = bsh + offset; for (; count != 0; count--, addr++) wr8(addr, value); } void generic_bs_sr_2(void *t, bus_space_handle_t bsh, bus_size_t offset, uint16_t value, size_t count) { bus_addr_t addr = bsh + offset; for (; count != 0; count--, addr += 2) wr16(addr, value); } void generic_bs_sr_4(void *t, bus_space_handle_t bsh, bus_size_t offset, uint32_t value, size_t count) { bus_addr_t addr = bsh + offset; for (; count != 0; count--, addr += 4) wr32(addr, value); } void generic_bs_sr_8(void *t, bus_space_handle_t bsh, bus_size_t offset, uint64_t value, size_t count) { #ifdef wr64 bus_addr_t addr = bsh + offset; for (; count != 0; count--, addr += 8) wr64(addr, value); #else panic("%s: not implemented", __func__); #endif } /* * Copy `count' 1, 2, 4, or 8 byte values from bus space starting * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2. */ void generic_bs_c_1(void *t, bus_space_handle_t bsh1, bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, size_t count) { bus_addr_t addr1 = bsh1 + off1; bus_addr_t addr2 = bsh2 + off2; if (addr1 >= addr2) { /* src after dest: copy forward */ for (; count != 0; count--, addr1++, addr2++) wr8(addr2, rd8(addr1)); } else { /* dest after src: copy backwards */ for (addr1 += (count - 1), addr2 += (count - 1); count != 0; count--, addr1--, addr2--) wr8(addr2, rd8(addr1)); } } void generic_bs_c_2(void *t, bus_space_handle_t bsh1, bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, size_t count) { bus_addr_t addr1 = bsh1 + off1; bus_addr_t addr2 = bsh2 + off2; if (addr1 >= addr2) { /* src after dest: copy forward */ for (; count != 0; count--, addr1 += 2, addr2 += 2) wr16(addr2, rd16(addr1)); } else { /* dest after src: copy backwards */ for (addr1 += 2 * (count - 1), addr2 += 2 * (count - 1); count != 0; count--, addr1 -= 2, addr2 -= 2) wr16(addr2, rd16(addr1)); } } void generic_bs_c_4(void *t, bus_space_handle_t bsh1, bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, size_t count) { bus_addr_t addr1 = bsh1 + off1; bus_addr_t addr2 = bsh2 + off2; if (addr1 >= addr2) { /* src after dest: copy forward */ for (; count != 0; count--, addr1 += 4, addr2 += 4) wr32(addr2, rd32(addr1)); } else { /* dest after src: copy backwards */ for (addr1 += 4 * (count - 1), addr2 += 4 * (count - 1); count != 0; count--, addr1 -= 4, addr2 -= 4) wr32(addr2, rd32(addr1)); } } void generic_bs_c_8(void *t, bus_space_handle_t bsh1, bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, size_t count) { #if defined(rd64) && defined(wr64) bus_addr_t addr1 = bsh1 + off1; bus_addr_t addr2 = bsh2 + off2; if (addr1 >= addr2) { /* src after dest: copy forward */ for (; count != 0; count--, addr1 += 8, addr2 += 8) wr64(addr2, rd64(addr1)); } else { /* dest after src: copy backwards */ for (addr1 += 8 * (count - 1), addr2 += 8 * (count - 1); count != 0; count--, addr1 -= 8, addr2 -= 8) wr64(addr2, rd64(addr1)); } #else panic("%s: not implemented", __func__); #endif } void generic_bs_barrier(void *t __unused, bus_space_handle_t bsh __unused, bus_size_t offset __unused, bus_size_t len __unused, int flags) { #if 0 if (flags & BUS_SPACE_BARRIER_WRITE) mips_dcache_wbinv_all(); #endif if (flags & BUS_SPACE_BARRIER_READ) rmb(); if (flags & BUS_SPACE_BARRIER_WRITE) wmb(); } Index: head/sys/mips/mips/busdma_machdep.c =================================================================== --- head/sys/mips/mips/busdma_machdep.c (revision 326258) +++ head/sys/mips/mips/busdma_machdep.c (revision 326259) @@ -1,1516 +1,1518 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006 Oleksandr Tymoshenko * 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, * without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * 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. * * From i386/busdma_machdep.c,v 1.26 2002/04/19 22:58:09 alfred */ #include __FBSDID("$FreeBSD$"); /* * MIPS bus dma support routines */ #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 MAX_BPAGES 64 #define BUS_DMA_COULD_BOUNCE BUS_DMA_BUS3 #define BUS_DMA_MIN_ALLOC_COMP BUS_DMA_BUS4 /* * On XBurst cores from Ingenic, cache-line writeback is local * only, unless accompanied by invalidation. Invalidations force * dirty line writeout and invalidation requests forwarded to * other cores if other cores have the cache line dirty. */ #if defined(SMP) && defined(CPU_XBURST) #define BUS_DMA_FORCE_WBINV #endif struct bounce_zone; struct bus_dma_tag { bus_dma_tag_t parent; bus_size_t alignment; bus_addr_t boundary; bus_addr_t lowaddr; bus_addr_t highaddr; bus_dma_filter_t *filter; void *filterarg; bus_size_t maxsize; u_int nsegments; bus_size_t maxsegsz; int flags; int ref_count; int map_count; bus_dma_lock_t *lockfunc; void *lockfuncarg; bus_dma_segment_t *segments; struct bounce_zone *bounce_zone; }; struct bounce_page { vm_offset_t vaddr; /* kva of bounce buffer */ vm_offset_t vaddr_nocache; /* kva of bounce buffer uncached */ bus_addr_t busaddr; /* Physical address */ vm_offset_t datavaddr; /* kva of client data */ bus_addr_t dataaddr; /* client physical address */ bus_size_t datacount; /* client data count */ STAILQ_ENTRY(bounce_page) links; }; struct sync_list { vm_offset_t vaddr; /* kva of bounce buffer */ bus_addr_t busaddr; /* Physical address */ bus_size_t datacount; /* client data count */ }; int busdma_swi_pending; struct bounce_zone { STAILQ_ENTRY(bounce_zone) links; STAILQ_HEAD(bp_list, bounce_page) bounce_page_list; int total_bpages; int free_bpages; int reserved_bpages; int active_bpages; int total_bounced; int total_deferred; int map_count; bus_size_t alignment; bus_addr_t lowaddr; char zoneid[8]; char lowaddrid[20]; struct sysctl_ctx_list sysctl_tree; struct sysctl_oid *sysctl_tree_top; }; static struct mtx bounce_lock; static int total_bpages; static int busdma_zonecount; static STAILQ_HEAD(, bounce_zone) bounce_zone_list; static SYSCTL_NODE(_hw, OID_AUTO, busdma, CTLFLAG_RD, 0, "Busdma parameters"); SYSCTL_INT(_hw_busdma, OID_AUTO, total_bpages, CTLFLAG_RD, &total_bpages, 0, "Total bounce pages"); #define DMAMAP_UNCACHEABLE 0x08 #define DMAMAP_CACHE_ALIGNED 0x10 struct bus_dmamap { struct bp_list bpages; int pagesneeded; int pagesreserved; bus_dma_tag_t dmat; struct memdesc mem; int flags; void *origbuffer; void *allocbuffer; TAILQ_ENTRY(bus_dmamap) freelist; STAILQ_ENTRY(bus_dmamap) links; bus_dmamap_callback_t *callback; void *callback_arg; int sync_count; struct sync_list *slist; }; static STAILQ_HEAD(, bus_dmamap) bounce_map_waitinglist; static STAILQ_HEAD(, bus_dmamap) bounce_map_callbacklist; static void init_bounce_pages(void *dummy); static int alloc_bounce_zone(bus_dma_tag_t dmat); static int alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages); static int reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map, int commit); static bus_addr_t add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, vm_offset_t vaddr, bus_addr_t addr, bus_size_t size); static void free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage); /* Default tag, as most drivers provide no parent tag. */ bus_dma_tag_t mips_root_dma_tag; static uma_zone_t dmamap_zone; /* Cache of struct bus_dmamap items */ static busdma_bufalloc_t coherent_allocator; /* Cache of coherent buffers */ static busdma_bufalloc_t standard_allocator; /* Cache of standard buffers */ MALLOC_DEFINE(M_BUSDMA, "busdma", "busdma metadata"); MALLOC_DEFINE(M_BOUNCE, "bounce", "busdma bounce pages"); /* * This is the ctor function passed to uma_zcreate() for the pool of dma maps. * It'll need platform-specific changes if this code is copied. */ static int dmamap_ctor(void *mem, int size, void *arg, int flags) { bus_dmamap_t map; bus_dma_tag_t dmat; map = (bus_dmamap_t)mem; dmat = (bus_dma_tag_t)arg; dmat->map_count++; map->dmat = dmat; map->flags = 0; map->slist = NULL; map->allocbuffer = NULL; map->sync_count = 0; STAILQ_INIT(&map->bpages); return (0); } /* * This is the dtor function passed to uma_zcreate() for the pool of dma maps. * It may need platform-specific changes if this code is copied . */ static void dmamap_dtor(void *mem, int size, void *arg) { bus_dmamap_t map; map = (bus_dmamap_t)mem; map->dmat->map_count--; } static void busdma_init(void *dummy) { /* Create a cache of maps for bus_dmamap_create(). */ dmamap_zone = uma_zcreate("dma maps", sizeof(struct bus_dmamap), dmamap_ctor, dmamap_dtor, NULL, NULL, UMA_ALIGN_PTR, 0); /* Create a cache of buffers in standard (cacheable) memory. */ standard_allocator = busdma_bufalloc_create("buffer", mips_dcache_max_linesize, /* minimum_alignment */ NULL, /* uma_alloc func */ NULL, /* uma_free func */ 0); /* uma_zcreate_flags */ /* * Create a cache of buffers in uncacheable memory, to implement the * BUS_DMA_COHERENT flag. */ coherent_allocator = busdma_bufalloc_create("coherent", mips_dcache_max_linesize, /* minimum_alignment */ busdma_bufalloc_alloc_uncacheable, busdma_bufalloc_free_uncacheable, 0); /* uma_zcreate_flags */ } SYSINIT(busdma, SI_SUB_KMEM, SI_ORDER_FOURTH, busdma_init, NULL); /* * Return true if a match is made. * * To find a match walk the chain of bus_dma_tag_t's looking for 'paddr'. * * If paddr is within the bounds of the dma tag then call the filter callback * to check for a match, if there is no filter callback then assume a match. */ static int run_filter(bus_dma_tag_t dmat, bus_addr_t paddr) { int retval; retval = 0; do { if (((paddr > dmat->lowaddr && paddr <= dmat->highaddr) || ((paddr & (dmat->alignment - 1)) != 0)) && (dmat->filter == NULL || (*dmat->filter)(dmat->filterarg, paddr) != 0)) retval = 1; dmat = dmat->parent; } while (retval == 0 && dmat != NULL); return (retval); } /* * Check to see if the specified page is in an allowed DMA range. */ static __inline int _bus_dma_can_bounce(vm_offset_t lowaddr, vm_offset_t highaddr) { int i; for (i = 0; phys_avail[i] && phys_avail[i + 1]; i += 2) { if ((lowaddr >= phys_avail[i] && lowaddr <= phys_avail[i + 1]) || (lowaddr < phys_avail[i] && highaddr > phys_avail[i])) return (1); } return (0); } /* * Convenience function for manipulating driver locks from busdma (during * busdma_swi, for example). Drivers that don't provide their own locks * should specify &Giant to dmat->lockfuncarg. Drivers that use their own * non-mutex locking scheme don't have to use this at all. */ void busdma_lock_mutex(void *arg, bus_dma_lock_op_t op) { struct mtx *dmtx; dmtx = (struct mtx *)arg; switch (op) { case BUS_DMA_LOCK: mtx_lock(dmtx); break; case BUS_DMA_UNLOCK: mtx_unlock(dmtx); break; default: panic("Unknown operation 0x%x for busdma_lock_mutex!", op); } } /* * dflt_lock should never get called. It gets put into the dma tag when * lockfunc == NULL, which is only valid if the maps that are associated * with the tag are meant to never be defered. * XXX Should have a way to identify which driver is responsible here. */ static void dflt_lock(void *arg, bus_dma_lock_op_t op) { #ifdef INVARIANTS panic("driver error: busdma dflt_lock called"); #else printf("DRIVER_ERROR: busdma dflt_lock called\n"); #endif } static __inline bus_dmamap_t _busdma_alloc_dmamap(bus_dma_tag_t dmat) { struct sync_list *slist; bus_dmamap_t map; slist = malloc(sizeof(*slist) * dmat->nsegments, M_BUSDMA, M_NOWAIT); if (slist == NULL) return (NULL); map = uma_zalloc_arg(dmamap_zone, dmat, M_NOWAIT); if (map != NULL) map->slist = slist; else free(slist, M_BUSDMA); return (map); } static __inline void _busdma_free_dmamap(bus_dmamap_t map) { free(map->slist, M_BUSDMA); uma_zfree(dmamap_zone, map); } /* * Allocate a device specific dma_tag. */ #define SEG_NB 1024 int bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, bus_addr_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr, bus_dma_filter_t *filter, void *filterarg, bus_size_t maxsize, int nsegments, bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc, void *lockfuncarg, bus_dma_tag_t *dmat) { bus_dma_tag_t newtag; int error = 0; /* Return a NULL tag on failure */ *dmat = NULL; if (!parent) parent = mips_root_dma_tag; newtag = (bus_dma_tag_t)malloc(sizeof(*newtag), M_BUSDMA, M_NOWAIT); if (newtag == NULL) { CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d", __func__, newtag, 0, error); return (ENOMEM); } newtag->parent = parent; newtag->alignment = alignment; newtag->boundary = boundary; newtag->lowaddr = trunc_page((vm_offset_t)lowaddr) + (PAGE_SIZE - 1); newtag->highaddr = trunc_page((vm_offset_t)highaddr) + (PAGE_SIZE - 1); newtag->filter = filter; newtag->filterarg = filterarg; newtag->maxsize = maxsize; newtag->nsegments = nsegments; newtag->maxsegsz = maxsegsz; newtag->flags = flags; if (cpuinfo.cache_coherent_dma) newtag->flags |= BUS_DMA_COHERENT; newtag->ref_count = 1; /* Count ourself */ newtag->map_count = 0; if (lockfunc != NULL) { newtag->lockfunc = lockfunc; newtag->lockfuncarg = lockfuncarg; } else { newtag->lockfunc = dflt_lock; newtag->lockfuncarg = NULL; } newtag->segments = NULL; /* * Take into account any restrictions imposed by our parent tag */ if (parent != NULL) { newtag->lowaddr = MIN(parent->lowaddr, newtag->lowaddr); newtag->highaddr = MAX(parent->highaddr, newtag->highaddr); if (newtag->boundary == 0) newtag->boundary = parent->boundary; else if (parent->boundary != 0) newtag->boundary = MIN(parent->boundary, newtag->boundary); if ((newtag->filter != NULL) || ((parent->flags & BUS_DMA_COULD_BOUNCE) != 0)) newtag->flags |= BUS_DMA_COULD_BOUNCE; if (newtag->filter == NULL) { /* * Short circuit looking at our parent directly * since we have encapsulated all of its information */ newtag->filter = parent->filter; newtag->filterarg = parent->filterarg; newtag->parent = parent->parent; } if (newtag->parent != NULL) atomic_add_int(&parent->ref_count, 1); } if (_bus_dma_can_bounce(newtag->lowaddr, newtag->highaddr) || newtag->alignment > 1) newtag->flags |= BUS_DMA_COULD_BOUNCE; if (((newtag->flags & BUS_DMA_COULD_BOUNCE) != 0) && (flags & BUS_DMA_ALLOCNOW) != 0) { struct bounce_zone *bz; /* Must bounce */ if ((error = alloc_bounce_zone(newtag)) != 0) { free(newtag, M_BUSDMA); return (error); } bz = newtag->bounce_zone; if (ptoa(bz->total_bpages) < maxsize) { int pages; pages = atop(maxsize) - bz->total_bpages; /* Add pages to our bounce pool */ if (alloc_bounce_pages(newtag, pages) < pages) error = ENOMEM; } /* Performed initial allocation */ newtag->flags |= BUS_DMA_MIN_ALLOC_COMP; } else newtag->bounce_zone = NULL; if (error != 0) free(newtag, M_BUSDMA); else *dmat = newtag; CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d", __func__, newtag, (newtag != NULL ? newtag->flags : 0), error); return (error); } int bus_dma_tag_destroy(bus_dma_tag_t dmat) { #ifdef KTR bus_dma_tag_t dmat_copy = dmat; #endif if (dmat != NULL) { if (dmat->map_count != 0) return (EBUSY); while (dmat != NULL) { bus_dma_tag_t parent; parent = dmat->parent; atomic_subtract_int(&dmat->ref_count, 1); if (dmat->ref_count == 0) { if (dmat->segments != NULL) free(dmat->segments, M_BUSDMA); free(dmat, M_BUSDMA); /* * Last reference count, so * release our reference * count on our parent. */ dmat = parent; } else dmat = NULL; } } CTR2(KTR_BUSDMA, "%s tag %p", __func__, dmat_copy); return (0); } #include /* * Allocate a handle for mapping from kva/uva/physical * address space into bus device space. */ int bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp) { bus_dmamap_t newmap; int error = 0; if (dmat->segments == NULL) { dmat->segments = (bus_dma_segment_t *)malloc( sizeof(bus_dma_segment_t) * dmat->nsegments, M_BUSDMA, M_NOWAIT); if (dmat->segments == NULL) { CTR3(KTR_BUSDMA, "%s: tag %p error %d", __func__, dmat, ENOMEM); return (ENOMEM); } } newmap = _busdma_alloc_dmamap(dmat); if (newmap == NULL) { CTR3(KTR_BUSDMA, "%s: tag %p error %d", __func__, dmat, ENOMEM); return (ENOMEM); } *mapp = newmap; /* * Bouncing might be required if the driver asks for an active * exclusion region, a data alignment that is stricter than 1, and/or * an active address boundary. */ if (dmat->flags & BUS_DMA_COULD_BOUNCE) { /* Must bounce */ struct bounce_zone *bz; int maxpages; if (dmat->bounce_zone == NULL) { if ((error = alloc_bounce_zone(dmat)) != 0) { _busdma_free_dmamap(newmap); *mapp = NULL; return (error); } } bz = dmat->bounce_zone; /* Initialize the new map */ STAILQ_INIT(&((*mapp)->bpages)); /* * Attempt to add pages to our pool on a per-instance * basis up to a sane limit. */ maxpages = MAX_BPAGES; if ((dmat->flags & BUS_DMA_MIN_ALLOC_COMP) == 0 || (bz->map_count > 0 && bz->total_bpages < maxpages)) { int pages; pages = MAX(atop(dmat->maxsize), 1); pages = MIN(maxpages - bz->total_bpages, pages); pages = MAX(pages, 1); if (alloc_bounce_pages(dmat, pages) < pages) error = ENOMEM; if ((dmat->flags & BUS_DMA_MIN_ALLOC_COMP) == 0) { if (error == 0) dmat->flags |= BUS_DMA_MIN_ALLOC_COMP; } else { error = 0; } } bz->map_count++; } CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", __func__, dmat, dmat->flags, error); return (0); } /* * Destroy a handle for mapping from kva/uva/physical * address space into bus device space. */ int bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map) { if (STAILQ_FIRST(&map->bpages) != NULL || map->sync_count != 0) { CTR3(KTR_BUSDMA, "%s: tag %p error %d", __func__, dmat, EBUSY); return (EBUSY); } if (dmat->bounce_zone) dmat->bounce_zone->map_count--; _busdma_free_dmamap(map); CTR2(KTR_BUSDMA, "%s: tag %p error 0", __func__, dmat); return (0); } /* * Allocate a piece of memory that can be efficiently mapped into * bus device space based on the constraints lited in the dma tag. * A dmamap to for use with dmamap_load is also allocated. */ int bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddrp, int flags, bus_dmamap_t *mapp) { bus_dmamap_t newmap = NULL; busdma_bufalloc_t ba; struct busdma_bufzone *bufzone; vm_memattr_t memattr; void *vaddr; int mflags; if (flags & BUS_DMA_NOWAIT) mflags = M_NOWAIT; else mflags = M_WAITOK; if (dmat->segments == NULL) { dmat->segments = (bus_dma_segment_t *)malloc( sizeof(bus_dma_segment_t) * dmat->nsegments, M_BUSDMA, mflags); if (dmat->segments == NULL) { CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", __func__, dmat, dmat->flags, ENOMEM); return (ENOMEM); } } newmap = _busdma_alloc_dmamap(dmat); if (newmap == NULL) { CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", __func__, dmat, dmat->flags, ENOMEM); return (ENOMEM); } /* * If all the memory is coherent with DMA then we don't need to * do anything special for a coherent mapping request. */ if (dmat->flags & BUS_DMA_COHERENT) flags &= ~BUS_DMA_COHERENT; if (flags & BUS_DMA_COHERENT) { memattr = VM_MEMATTR_UNCACHEABLE; ba = coherent_allocator; newmap->flags |= DMAMAP_UNCACHEABLE; } else { memattr = VM_MEMATTR_DEFAULT; ba = standard_allocator; } /* All buffers we allocate are cache-aligned. */ newmap->flags |= DMAMAP_CACHE_ALIGNED; if (flags & BUS_DMA_ZERO) mflags |= M_ZERO; /* * Try to find a bufzone in the allocator that holds a cache of buffers * of the right size for this request. If the buffer is too big to be * held in the allocator cache, this returns NULL. */ bufzone = busdma_bufalloc_findzone(ba, dmat->maxsize); /* * Allocate the buffer from the uma(9) allocator if... * - It's small enough to be in the allocator (bufzone not NULL). * - The alignment constraint isn't larger than the allocation size * (the allocator aligns buffers to their size boundaries). * - There's no need to handle lowaddr/highaddr exclusion zones. * else allocate non-contiguous pages if... * - The page count that could get allocated doesn't exceed * nsegments also when the maximum segment size is less * than PAGE_SIZE. * - The alignment constraint isn't larger than a page boundary. * - There are no boundary-crossing constraints. * else allocate a block of contiguous pages because one or more of the * constraints is something that only the contig allocator can fulfill. */ if (bufzone != NULL && dmat->alignment <= bufzone->size && !_bus_dma_can_bounce(dmat->lowaddr, dmat->highaddr)) { vaddr = uma_zalloc(bufzone->umazone, mflags); } else if (dmat->nsegments >= howmany(dmat->maxsize, MIN(dmat->maxsegsz, PAGE_SIZE)) && dmat->alignment <= PAGE_SIZE && (dmat->boundary % PAGE_SIZE) == 0) { vaddr = (void *)kmem_alloc_attr(kernel_arena, dmat->maxsize, mflags, 0, dmat->lowaddr, memattr); } else { vaddr = (void *)kmem_alloc_contig(kernel_arena, dmat->maxsize, mflags, 0, dmat->lowaddr, dmat->alignment, dmat->boundary, memattr); } if (vaddr == NULL) { _busdma_free_dmamap(newmap); newmap = NULL; } else { newmap->sync_count = 0; } *vaddrp = vaddr; *mapp = newmap; return (vaddr == NULL ? ENOMEM : 0); } /* * Free a piece of memory and it's allocated dmamap, that was allocated * via bus_dmamem_alloc. Make the same choice for free/contigfree. */ void bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map) { struct busdma_bufzone *bufzone; busdma_bufalloc_t ba; if (map->flags & DMAMAP_UNCACHEABLE) ba = coherent_allocator; else ba = standard_allocator; free(map->slist, M_BUSDMA); uma_zfree(dmamap_zone, map); bufzone = busdma_bufalloc_findzone(ba, dmat->maxsize); if (bufzone != NULL && dmat->alignment <= bufzone->size && !_bus_dma_can_bounce(dmat->lowaddr, dmat->highaddr)) uma_zfree(bufzone->umazone, vaddr); else kmem_free(kernel_arena, (vm_offset_t)vaddr, dmat->maxsize); CTR3(KTR_BUSDMA, "%s: tag %p flags 0x%x", __func__, dmat, dmat->flags); } static void _bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf, bus_size_t buflen, int flags) { bus_addr_t curaddr; bus_size_t sgsize; if (map->pagesneeded == 0) { CTR3(KTR_BUSDMA, "lowaddr= %d, boundary= %d, alignment= %d", dmat->lowaddr, dmat->boundary, dmat->alignment); CTR2(KTR_BUSDMA, "map= %p, pagesneeded= %d", map, map->pagesneeded); /* * Count the number of bounce pages * needed in order to complete this transfer */ curaddr = buf; while (buflen != 0) { sgsize = MIN(buflen, dmat->maxsegsz); if (run_filter(dmat, curaddr) != 0) { sgsize = MIN(sgsize, PAGE_SIZE); map->pagesneeded++; } curaddr += sgsize; buflen -= sgsize; } CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded); } } static void _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, pmap_t pmap, void *buf, bus_size_t buflen, int flags) { vm_offset_t vaddr; vm_offset_t vendaddr; bus_addr_t paddr; if (map->pagesneeded == 0) { CTR3(KTR_BUSDMA, "lowaddr= %d, boundary= %d, alignment= %d", dmat->lowaddr, dmat->boundary, dmat->alignment); CTR2(KTR_BUSDMA, "map= %p, pagesneeded= %d", map, map->pagesneeded); /* * Count the number of bounce pages * needed in order to complete this transfer */ vaddr = (vm_offset_t)buf; vendaddr = (vm_offset_t)buf + buflen; while (vaddr < vendaddr) { bus_size_t sg_len; KASSERT(kernel_pmap == pmap, ("pmap is not kernel pmap")); sg_len = PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK); paddr = pmap_kextract(vaddr); if (((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) && run_filter(dmat, paddr) != 0) { sg_len = roundup2(sg_len, dmat->alignment); map->pagesneeded++; } vaddr += sg_len; } CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded); } } static int _bus_dmamap_reserve_pages(bus_dma_tag_t dmat, bus_dmamap_t map,int flags) { /* Reserve Necessary Bounce Pages */ mtx_lock(&bounce_lock); if (flags & BUS_DMA_NOWAIT) { if (reserve_bounce_pages(dmat, map, 0) != 0) { mtx_unlock(&bounce_lock); return (ENOMEM); } } else { if (reserve_bounce_pages(dmat, map, 1) != 0) { /* Queue us for resources */ STAILQ_INSERT_TAIL(&bounce_map_waitinglist, map, links); mtx_unlock(&bounce_lock); return (EINPROGRESS); } } mtx_unlock(&bounce_lock); return (0); } /* * Add a single contiguous physical range to the segment list. */ static int _bus_dmamap_addseg(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t curaddr, bus_size_t sgsize, bus_dma_segment_t *segs, int *segp) { bus_addr_t baddr, bmask; int seg; /* * Make sure we don't cross any boundaries. */ bmask = ~(dmat->boundary - 1); if (dmat->boundary > 0) { baddr = (curaddr + dmat->boundary) & bmask; if (sgsize > (baddr - curaddr)) sgsize = (baddr - curaddr); } /* * Insert chunk into a segment, coalescing with * the previous segment if possible. */ seg = *segp; if (seg >= 0 && curaddr == segs[seg].ds_addr + segs[seg].ds_len && (segs[seg].ds_len + sgsize) <= dmat->maxsegsz && (dmat->boundary == 0 || (segs[seg].ds_addr & bmask) == (curaddr & bmask))) { segs[seg].ds_len += sgsize; } else { if (++seg >= dmat->nsegments) return (0); segs[seg].ds_addr = curaddr; segs[seg].ds_len = sgsize; } *segp = seg; return (sgsize); } /* * Utility function to load a physical buffer. segp contains * the starting segment on entrace, and the ending segment on exit. */ int _bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf, bus_size_t buflen, int flags, bus_dma_segment_t *segs, int *segp) { bus_addr_t curaddr; bus_size_t sgsize; int error; if (segs == NULL) segs = dmat->segments; if ((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) { _bus_dmamap_count_phys(dmat, map, buf, buflen, flags); if (map->pagesneeded != 0) { error = _bus_dmamap_reserve_pages(dmat, map, flags); if (error) return (error); } } while (buflen > 0) { curaddr = buf; sgsize = MIN(buflen, dmat->maxsegsz); if (((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) && map->pagesneeded != 0 && run_filter(dmat, curaddr)) { sgsize = MIN(sgsize, PAGE_SIZE); curaddr = add_bounce_page(dmat, map, 0, curaddr, sgsize); } sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs, segp); if (sgsize == 0) break; buf += sgsize; buflen -= sgsize; } /* * Did we fit? */ if (buflen != 0) { bus_dmamap_unload(dmat, map); return (EFBIG); /* XXX better return value here? */ } return (0); } int _bus_dmamap_load_ma(bus_dma_tag_t dmat, bus_dmamap_t map, struct vm_page **ma, bus_size_t tlen, int ma_offs, int flags, bus_dma_segment_t *segs, int *segp) { return (bus_dmamap_load_ma_triv(dmat, map, ma, tlen, ma_offs, flags, segs, segp)); } /* * Utility function to load a linear buffer. segp contains * the starting segment on entrance, and the ending segment on exit. * first indicates if this is the first invocation of this function. */ int _bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, bus_size_t buflen, struct pmap *pmap, int flags, bus_dma_segment_t *segs, int *segp) { bus_size_t sgsize; bus_addr_t curaddr; struct sync_list *sl; vm_offset_t vaddr = (vm_offset_t)buf; int error = 0; if (segs == NULL) segs = dmat->segments; if ((flags & BUS_DMA_LOAD_MBUF) != 0) map->flags |= DMAMAP_CACHE_ALIGNED; if ((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) { _bus_dmamap_count_pages(dmat, map, pmap, buf, buflen, flags); if (map->pagesneeded != 0) { error = _bus_dmamap_reserve_pages(dmat, map, flags); if (error) return (error); } } CTR3(KTR_BUSDMA, "lowaddr= %d boundary= %d, " "alignment= %d", dmat->lowaddr, dmat->boundary, dmat->alignment); while (buflen > 0) { /* * Get the physical address for this segment. * * XXX Don't support checking for coherent mappings * XXX in user address space. */ KASSERT(kernel_pmap == pmap, ("pmap is not kernel pmap")); curaddr = pmap_kextract(vaddr); /* * Compute the segment size, and adjust counts. */ sgsize = PAGE_SIZE - ((u_long)curaddr & PAGE_MASK); if (sgsize > dmat->maxsegsz) sgsize = dmat->maxsegsz; if (buflen < sgsize) sgsize = buflen; if (((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) && map->pagesneeded != 0 && run_filter(dmat, curaddr)) { curaddr = add_bounce_page(dmat, map, vaddr, curaddr, sgsize); } else { sl = &map->slist[map->sync_count - 1]; if (map->sync_count == 0 || vaddr != sl->vaddr + sl->datacount) { if (++map->sync_count > dmat->nsegments) goto cleanup; sl++; sl->vaddr = vaddr; sl->datacount = sgsize; sl->busaddr = curaddr; } else sl->datacount += sgsize; } sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs, segp); if (sgsize == 0) break; vaddr += sgsize; buflen -= sgsize; } cleanup: /* * Did we fit? */ if (buflen != 0) { bus_dmamap_unload(dmat, map); error = EFBIG; /* XXX better return value here? */ } return (error); } void _bus_dmamap_waitok(bus_dma_tag_t dmat, bus_dmamap_t map, struct memdesc *mem, bus_dmamap_callback_t *callback, void *callback_arg) { KASSERT(dmat != NULL, ("dmatag is NULL")); KASSERT(map != NULL, ("dmamap is NULL")); map->mem = *mem; map->callback = callback; map->callback_arg = callback_arg; } bus_dma_segment_t * _bus_dmamap_complete(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dma_segment_t *segs, int nsegs, int error) { if (segs == NULL) segs = dmat->segments; return (segs); } /* * Release the mapping held by map. */ void bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map) { struct bounce_page *bpage; while ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) { STAILQ_REMOVE_HEAD(&map->bpages, links); free_bounce_page(dmat, bpage); } map->sync_count = 0; return; } static void bus_dmamap_sync_buf(vm_offset_t buf, int len, bus_dmasync_op_t op, int aligned) { char tmp_cl[mips_dcache_max_linesize], tmp_clend[mips_dcache_max_linesize]; vm_offset_t buf_cl, buf_clend; vm_size_t size_cl, size_clend; int cache_linesize_mask = mips_dcache_max_linesize - 1; /* * dcache invalidation operates on cache line aligned addresses * and could modify areas of memory that share the same cache line * at the beginning and the ending of the buffer. In order to * prevent a data loss we save these chunks in temporary buffer * before invalidation and restore them afer it. * * If the aligned flag is set the buffer is either an mbuf or came from * our allocator caches. In both cases they are always sized and * aligned to cacheline boundaries, so we can skip preserving nearby * data if a transfer appears to overlap cachelines. An mbuf in * particular will usually appear to be overlapped because of offsetting * within the buffer to align the L3 headers, but we know that the bytes * preceeding that offset are part of the same mbuf memory and are not * unrelated adjacent data (and a rule of mbuf handling is that the cpu * is not allowed to touch the mbuf while dma is in progress, including * header fields). */ if (aligned) { size_cl = 0; size_clend = 0; } else { buf_cl = buf & ~cache_linesize_mask; size_cl = buf & cache_linesize_mask; buf_clend = buf + len; size_clend = (mips_dcache_max_linesize - (buf_clend & cache_linesize_mask)) & cache_linesize_mask; } switch (op) { case BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE: case BUS_DMASYNC_POSTREAD: /* * Save buffers that might be modified by invalidation */ if (size_cl) memcpy (tmp_cl, (void*)buf_cl, size_cl); if (size_clend) memcpy (tmp_clend, (void*)buf_clend, size_clend); mips_dcache_inv_range(buf, len); /* * Restore them */ if (size_cl) memcpy ((void*)buf_cl, tmp_cl, size_cl); if (size_clend) memcpy ((void*)buf_clend, tmp_clend, size_clend); /* * Copies above have brought corresponding memory * cache lines back into dirty state. Write them back * out and invalidate affected cache lines again if * necessary. */ if (size_cl) mips_dcache_wbinv_range(buf_cl, size_cl); if (size_clend && (size_cl == 0 || buf_clend - buf_cl > mips_dcache_max_linesize)) mips_dcache_wbinv_range(buf_clend, size_clend); break; case BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE: mips_dcache_wbinv_range(buf, len); break; case BUS_DMASYNC_PREREAD: /* * Save buffers that might be modified by invalidation */ if (size_cl) memcpy (tmp_cl, (void *)buf_cl, size_cl); if (size_clend) memcpy (tmp_clend, (void *)buf_clend, size_clend); mips_dcache_inv_range(buf, len); /* * Restore them */ if (size_cl) memcpy ((void *)buf_cl, tmp_cl, size_cl); if (size_clend) memcpy ((void *)buf_clend, tmp_clend, size_clend); /* * Copies above have brought corresponding memory * cache lines back into dirty state. Write them back * out and invalidate affected cache lines again if * necessary. */ if (size_cl) mips_dcache_wbinv_range(buf_cl, size_cl); if (size_clend && (size_cl == 0 || buf_clend - buf_cl > mips_dcache_max_linesize)) mips_dcache_wbinv_range(buf_clend, size_clend); break; case BUS_DMASYNC_PREWRITE: #ifdef BUS_DMA_FORCE_WBINV mips_dcache_wbinv_range(buf, len); #else mips_dcache_wb_range(buf, len); #endif break; } } static void _bus_dmamap_sync_bp(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op) { struct bounce_page *bpage; STAILQ_FOREACH(bpage, &map->bpages, links) { if (op & BUS_DMASYNC_PREWRITE) { if (bpage->datavaddr != 0) bcopy((void *)bpage->datavaddr, (void *)(bpage->vaddr_nocache != 0 ? bpage->vaddr_nocache : bpage->vaddr), bpage->datacount); else physcopyout(bpage->dataaddr, (void *)(bpage->vaddr_nocache != 0 ? bpage->vaddr_nocache : bpage->vaddr), bpage->datacount); if (bpage->vaddr_nocache == 0) { #ifdef BUS_DMA_FORCE_WBINV mips_dcache_wbinv_range(bpage->vaddr, bpage->datacount); #else mips_dcache_wb_range(bpage->vaddr, bpage->datacount); #endif } dmat->bounce_zone->total_bounced++; } if (op & BUS_DMASYNC_POSTREAD) { if (bpage->vaddr_nocache == 0) { mips_dcache_inv_range(bpage->vaddr, bpage->datacount); } if (bpage->datavaddr != 0) bcopy((void *)(bpage->vaddr_nocache != 0 ? bpage->vaddr_nocache : bpage->vaddr), (void *)bpage->datavaddr, bpage->datacount); else physcopyin((void *)(bpage->vaddr_nocache != 0 ? bpage->vaddr_nocache : bpage->vaddr), bpage->dataaddr, bpage->datacount); dmat->bounce_zone->total_bounced++; } } } void bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op) { struct sync_list *sl, *end; int aligned; if (op == BUS_DMASYNC_POSTWRITE) return; if (STAILQ_FIRST(&map->bpages)) _bus_dmamap_sync_bp(dmat, map, op); if ((dmat->flags & BUS_DMA_COHERENT) || (map->flags & DMAMAP_UNCACHEABLE)) { if (op & BUS_DMASYNC_PREWRITE) mips_sync(); return; } aligned = (map->flags & DMAMAP_CACHE_ALIGNED) ? 1 : 0; CTR3(KTR_BUSDMA, "%s: op %x flags %x", __func__, op, map->flags); if (map->sync_count) { end = &map->slist[map->sync_count]; for (sl = &map->slist[0]; sl != end; sl++) bus_dmamap_sync_buf(sl->vaddr, sl->datacount, op, aligned); } } static void init_bounce_pages(void *dummy __unused) { total_bpages = 0; STAILQ_INIT(&bounce_zone_list); STAILQ_INIT(&bounce_map_waitinglist); STAILQ_INIT(&bounce_map_callbacklist); mtx_init(&bounce_lock, "bounce pages lock", NULL, MTX_DEF); } SYSINIT(bpages, SI_SUB_LOCK, SI_ORDER_ANY, init_bounce_pages, NULL); static struct sysctl_ctx_list * busdma_sysctl_tree(struct bounce_zone *bz) { return (&bz->sysctl_tree); } static struct sysctl_oid * busdma_sysctl_tree_top(struct bounce_zone *bz) { return (bz->sysctl_tree_top); } static int alloc_bounce_zone(bus_dma_tag_t dmat) { struct bounce_zone *bz; /* Check to see if we already have a suitable zone */ STAILQ_FOREACH(bz, &bounce_zone_list, links) { if ((dmat->alignment <= bz->alignment) && (dmat->lowaddr >= bz->lowaddr)) { dmat->bounce_zone = bz; return (0); } } if ((bz = (struct bounce_zone *)malloc(sizeof(*bz), M_BUSDMA, M_NOWAIT | M_ZERO)) == NULL) return (ENOMEM); STAILQ_INIT(&bz->bounce_page_list); bz->free_bpages = 0; bz->reserved_bpages = 0; bz->active_bpages = 0; bz->lowaddr = dmat->lowaddr; bz->alignment = MAX(dmat->alignment, PAGE_SIZE); bz->map_count = 0; snprintf(bz->zoneid, 8, "zone%d", busdma_zonecount); busdma_zonecount++; snprintf(bz->lowaddrid, 18, "%#jx", (uintmax_t)bz->lowaddr); STAILQ_INSERT_TAIL(&bounce_zone_list, bz, links); dmat->bounce_zone = bz; sysctl_ctx_init(&bz->sysctl_tree); bz->sysctl_tree_top = SYSCTL_ADD_NODE(&bz->sysctl_tree, SYSCTL_STATIC_CHILDREN(_hw_busdma), OID_AUTO, bz->zoneid, CTLFLAG_RD, 0, ""); if (bz->sysctl_tree_top == NULL) { sysctl_ctx_free(&bz->sysctl_tree); return (0); /* XXX error code? */ } SYSCTL_ADD_INT(busdma_sysctl_tree(bz), SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, "total_bpages", CTLFLAG_RD, &bz->total_bpages, 0, "Total bounce pages"); SYSCTL_ADD_INT(busdma_sysctl_tree(bz), SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, "free_bpages", CTLFLAG_RD, &bz->free_bpages, 0, "Free bounce pages"); SYSCTL_ADD_INT(busdma_sysctl_tree(bz), SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, "reserved_bpages", CTLFLAG_RD, &bz->reserved_bpages, 0, "Reserved bounce pages"); SYSCTL_ADD_INT(busdma_sysctl_tree(bz), SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, "active_bpages", CTLFLAG_RD, &bz->active_bpages, 0, "Active bounce pages"); SYSCTL_ADD_INT(busdma_sysctl_tree(bz), SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, "total_bounced", CTLFLAG_RD, &bz->total_bounced, 0, "Total bounce requests"); SYSCTL_ADD_INT(busdma_sysctl_tree(bz), SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, "total_deferred", CTLFLAG_RD, &bz->total_deferred, 0, "Total bounce requests that were deferred"); SYSCTL_ADD_STRING(busdma_sysctl_tree(bz), SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, "lowaddr", CTLFLAG_RD, bz->lowaddrid, 0, ""); SYSCTL_ADD_UAUTO(busdma_sysctl_tree(bz), SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, "alignment", CTLFLAG_RD, &bz->alignment, ""); return (0); } static int alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages) { struct bounce_zone *bz; int count; bz = dmat->bounce_zone; count = 0; while (numpages > 0) { struct bounce_page *bpage; bpage = (struct bounce_page *)malloc(sizeof(*bpage), M_BUSDMA, M_NOWAIT | M_ZERO); if (bpage == NULL) break; bpage->vaddr = (vm_offset_t)contigmalloc(PAGE_SIZE, M_BOUNCE, M_NOWAIT, 0ul, bz->lowaddr, PAGE_SIZE, 0); if (bpage->vaddr == 0) { free(bpage, M_BUSDMA); break; } bpage->busaddr = pmap_kextract(bpage->vaddr); bpage->vaddr_nocache = (vm_offset_t)pmap_mapdev(bpage->busaddr, PAGE_SIZE); mtx_lock(&bounce_lock); STAILQ_INSERT_TAIL(&bz->bounce_page_list, bpage, links); total_bpages++; bz->total_bpages++; bz->free_bpages++; mtx_unlock(&bounce_lock); count++; numpages--; } return (count); } static int reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map, int commit) { struct bounce_zone *bz; int pages; mtx_assert(&bounce_lock, MA_OWNED); bz = dmat->bounce_zone; pages = MIN(bz->free_bpages, map->pagesneeded - map->pagesreserved); if (commit == 0 && map->pagesneeded > (map->pagesreserved + pages)) return (map->pagesneeded - (map->pagesreserved + pages)); bz->free_bpages -= pages; bz->reserved_bpages += pages; map->pagesreserved += pages; pages = map->pagesneeded - map->pagesreserved; return (pages); } static bus_addr_t add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, vm_offset_t vaddr, bus_addr_t addr, bus_size_t size) { struct bounce_zone *bz; struct bounce_page *bpage; KASSERT(dmat->bounce_zone != NULL, ("no bounce zone in dma tag")); KASSERT(map != NULL, ("add_bounce_page: bad map %p", map)); bz = dmat->bounce_zone; if (map->pagesneeded == 0) panic("add_bounce_page: map doesn't need any pages"); map->pagesneeded--; if (map->pagesreserved == 0) panic("add_bounce_page: map doesn't need any pages"); map->pagesreserved--; mtx_lock(&bounce_lock); bpage = STAILQ_FIRST(&bz->bounce_page_list); if (bpage == NULL) panic("add_bounce_page: free page list is empty"); STAILQ_REMOVE_HEAD(&bz->bounce_page_list, links); bz->reserved_bpages--; bz->active_bpages++; mtx_unlock(&bounce_lock); if (dmat->flags & BUS_DMA_KEEP_PG_OFFSET) { /* Page offset needs to be preserved. */ bpage->vaddr |= addr & PAGE_MASK; bpage->busaddr |= addr & PAGE_MASK; } bpage->datavaddr = vaddr; bpage->dataaddr = addr; bpage->datacount = size; STAILQ_INSERT_TAIL(&(map->bpages), bpage, links); return (bpage->busaddr); } static void free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage) { struct bus_dmamap *map; struct bounce_zone *bz; bz = dmat->bounce_zone; bpage->datavaddr = 0; bpage->datacount = 0; if (dmat->flags & BUS_DMA_KEEP_PG_OFFSET) { /* * Reset the bounce page to start at offset 0. Other uses * of this bounce page may need to store a full page of * data and/or assume it starts on a page boundary. */ bpage->vaddr &= ~PAGE_MASK; bpage->busaddr &= ~PAGE_MASK; } mtx_lock(&bounce_lock); STAILQ_INSERT_HEAD(&bz->bounce_page_list, bpage, links); bz->free_bpages++; bz->active_bpages--; if ((map = STAILQ_FIRST(&bounce_map_waitinglist)) != NULL) { if (reserve_bounce_pages(map->dmat, map, 1) == 0) { STAILQ_REMOVE_HEAD(&bounce_map_waitinglist, links); STAILQ_INSERT_TAIL(&bounce_map_callbacklist, map, links); busdma_swi_pending = 1; bz->total_deferred++; swi_sched(vm_ih, 0); } } mtx_unlock(&bounce_lock); } void busdma_swi(void) { bus_dma_tag_t dmat; struct bus_dmamap *map; mtx_lock(&bounce_lock); while ((map = STAILQ_FIRST(&bounce_map_callbacklist)) != NULL) { STAILQ_REMOVE_HEAD(&bounce_map_callbacklist, links); mtx_unlock(&bounce_lock); dmat = map->dmat; (dmat->lockfunc)(dmat->lockfuncarg, BUS_DMA_LOCK); bus_dmamap_load_mem(map->dmat, map, &map->mem, map->callback, map->callback_arg, BUS_DMA_WAITOK); (dmat->lockfunc)(dmat->lockfuncarg, BUS_DMA_UNLOCK); mtx_lock(&bounce_lock); } mtx_unlock(&bounce_lock); } Index: head/sys/mips/mips/cache.c =================================================================== --- head/sys/mips/mips/cache.c (revision 326258) +++ head/sys/mips/mips/cache.c (revision 326259) @@ -1,331 +1,333 @@ /* $NetBSD: cache.c,v 1.33 2005/12/24 23:24:01 perry Exp $ */ /*- + * SPDX-License-Identifier: BSD-4-Clause AND BSD-3-Clause + * * Copyright 2001, 2002 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe and Simon Burge for Wasabi Systems, Inc. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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. */ /*- * Copyright 2000, 2001 * Broadcom Corporation. All rights reserved. * * This software is furnished under license and may be used and copied only * in accordance with the following terms and conditions. Subject to these * conditions, you may download, copy, install, use, modify and distribute * modified or unmodified copies of this software in source and/or binary * form. No title or ownership is transferred hereby. * * 1) Any source code used, modified or distributed must reproduce and * retain this copyright notice and list of conditions as they appear in * the source file. * * 2) No right is granted to use any trade name, trademark, or logo of * Broadcom Corporation. The "Broadcom Corporation" name may not be * used to endorse or promote products derived from this software * without the prior written permission of Broadcom Corporation. * * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM BE LIABLE * FOR ANY DAMAGES WHATSOEVER, AND IN PARTICULAR, BROADCOM SHALL NOT BE * LIABLE FOR 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), EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include struct mips_cache_ops mips_cache_ops; #if defined(MIPS_DISABLE_L1_CACHE) || defined(CPU_RMI) || defined(CPU_NLM) static void cache_noop(vm_offset_t va, vm_size_t size) { } #endif void mips_config_cache(struct mips_cpuinfo * cpuinfo) { switch (cpuinfo->l1.ic_linesize) { case 16: mips_cache_ops.mco_icache_sync_all = mipsNN_icache_sync_all_16; mips_cache_ops.mco_icache_sync_range = mipsNN_icache_sync_range_16; mips_cache_ops.mco_icache_sync_range_index = mipsNN_icache_sync_range_index_16; break; case 32: mips_cache_ops.mco_icache_sync_all = mipsNN_icache_sync_all_32; mips_cache_ops.mco_icache_sync_range = mipsNN_icache_sync_range_32; mips_cache_ops.mco_icache_sync_range_index = mipsNN_icache_sync_range_index_32; break; case 64: mips_cache_ops.mco_icache_sync_all = mipsNN_icache_sync_all_64; mips_cache_ops.mco_icache_sync_range = mipsNN_icache_sync_range_64; mips_cache_ops.mco_icache_sync_range_index = mipsNN_icache_sync_range_index_64; break; case 128: mips_cache_ops.mco_icache_sync_all = mipsNN_icache_sync_all_128; mips_cache_ops.mco_icache_sync_range = mipsNN_icache_sync_range_128; mips_cache_ops.mco_icache_sync_range_index = mipsNN_icache_sync_range_index_128; break; #ifdef MIPS_DISABLE_L1_CACHE case 0: mips_cache_ops.mco_icache_sync_all = (void (*)(void))cache_noop; mips_cache_ops.mco_icache_sync_range = cache_noop; mips_cache_ops.mco_icache_sync_range_index = cache_noop; break; #endif default: panic("no Icache ops for %d byte lines", cpuinfo->l1.ic_linesize); } switch (cpuinfo->l1.dc_linesize) { case 16: mips_cache_ops.mco_pdcache_wbinv_all = mips_cache_ops.mco_intern_pdcache_wbinv_all = mipsNN_pdcache_wbinv_all_16; mips_cache_ops.mco_pdcache_wbinv_range = mipsNN_pdcache_wbinv_range_16; mips_cache_ops.mco_pdcache_wbinv_range_index = mips_cache_ops.mco_intern_pdcache_wbinv_range_index = mipsNN_pdcache_wbinv_range_index_16; mips_cache_ops.mco_pdcache_inv_range = mipsNN_pdcache_inv_range_16; mips_cache_ops.mco_pdcache_wb_range = mips_cache_ops.mco_intern_pdcache_wb_range = mipsNN_pdcache_wb_range_16; break; case 32: mips_cache_ops.mco_pdcache_wbinv_all = mips_cache_ops.mco_intern_pdcache_wbinv_all = mipsNN_pdcache_wbinv_all_32; #if defined(CPU_RMI) || defined(CPU_NLM) mips_cache_ops.mco_pdcache_wbinv_range = cache_noop; #else mips_cache_ops.mco_pdcache_wbinv_range = mipsNN_pdcache_wbinv_range_32; #endif #if defined(CPU_RMI) || defined(CPU_NLM) mips_cache_ops.mco_pdcache_wbinv_range_index = mips_cache_ops.mco_intern_pdcache_wbinv_range_index = cache_noop; mips_cache_ops.mco_pdcache_inv_range = cache_noop; #else mips_cache_ops.mco_pdcache_wbinv_range_index = mips_cache_ops.mco_intern_pdcache_wbinv_range_index = mipsNN_pdcache_wbinv_range_index_32; mips_cache_ops.mco_pdcache_inv_range = mipsNN_pdcache_inv_range_32; #endif #if defined(CPU_RMI) || defined(CPU_NLM) mips_cache_ops.mco_pdcache_wb_range = mips_cache_ops.mco_intern_pdcache_wb_range = cache_noop; #else mips_cache_ops.mco_pdcache_wb_range = mips_cache_ops.mco_intern_pdcache_wb_range = mipsNN_pdcache_wb_range_32; #endif break; case 64: mips_cache_ops.mco_pdcache_wbinv_all = mips_cache_ops.mco_intern_pdcache_wbinv_all = mipsNN_pdcache_wbinv_all_64; mips_cache_ops.mco_pdcache_wbinv_range = mipsNN_pdcache_wbinv_range_64; mips_cache_ops.mco_pdcache_wbinv_range_index = mips_cache_ops.mco_intern_pdcache_wbinv_range_index = mipsNN_pdcache_wbinv_range_index_64; mips_cache_ops.mco_pdcache_inv_range = mipsNN_pdcache_inv_range_64; mips_cache_ops.mco_pdcache_wb_range = mips_cache_ops.mco_intern_pdcache_wb_range = mipsNN_pdcache_wb_range_64; break; case 128: mips_cache_ops.mco_pdcache_wbinv_all = mips_cache_ops.mco_intern_pdcache_wbinv_all = mipsNN_pdcache_wbinv_all_128; mips_cache_ops.mco_pdcache_wbinv_range = mipsNN_pdcache_wbinv_range_128; mips_cache_ops.mco_pdcache_wbinv_range_index = mips_cache_ops.mco_intern_pdcache_wbinv_range_index = mipsNN_pdcache_wbinv_range_index_128; mips_cache_ops.mco_pdcache_inv_range = mipsNN_pdcache_inv_range_128; mips_cache_ops.mco_pdcache_wb_range = mips_cache_ops.mco_intern_pdcache_wb_range = mipsNN_pdcache_wb_range_128; break; #ifdef MIPS_DISABLE_L1_CACHE case 0: mips_cache_ops.mco_pdcache_wbinv_all = mips_cache_ops.mco_intern_pdcache_wbinv_all = (void (*)(void))cache_noop; mips_cache_ops.mco_pdcache_wbinv_range = cache_noop; mips_cache_ops.mco_pdcache_wbinv_range_index = cache_noop; mips_cache_ops.mco_intern_pdcache_wbinv_range_index = cache_noop; mips_cache_ops.mco_pdcache_inv_range = cache_noop; mips_cache_ops.mco_pdcache_wb_range = cache_noop; mips_cache_ops.mco_intern_pdcache_wb_range = cache_noop; break; #endif default: panic("no Dcache ops for %d byte lines", cpuinfo->l1.dc_linesize); } mipsNN_cache_init(cpuinfo); #if 0 if (mips_cpu_flags & (CPU_MIPS_D_CACHE_COHERENT | CPU_MIPS_I_D_CACHE_COHERENT)) { #ifdef CACHE_DEBUG printf(" Dcache is coherent\n"); #endif mips_cache_ops.mco_pdcache_wbinv_all = (void (*)(void))cache_noop; mips_cache_ops.mco_pdcache_wbinv_range = cache_noop; mips_cache_ops.mco_pdcache_wbinv_range_index = cache_noop; mips_cache_ops.mco_pdcache_inv_range = cache_noop; mips_cache_ops.mco_pdcache_wb_range = cache_noop; } if (mips_cpu_flags & CPU_MIPS_I_D_CACHE_COHERENT) { #ifdef CACHE_DEBUG printf(" Icache is coherent against Dcache\n"); #endif mips_cache_ops.mco_intern_pdcache_wbinv_all = (void (*)(void))cache_noop; mips_cache_ops.mco_intern_pdcache_wbinv_range_index = cache_noop; mips_cache_ops.mco_intern_pdcache_wb_range = cache_noop; } #endif /* Check that all cache ops are set up. */ /* must have primary Icache */ if (cpuinfo->l1.ic_size) { if (!mips_cache_ops.mco_icache_sync_all) panic("no icache_sync_all cache op"); if (!mips_cache_ops.mco_icache_sync_range) panic("no icache_sync_range cache op"); if (!mips_cache_ops.mco_icache_sync_range_index) panic("no icache_sync_range_index cache op"); } /* must have primary Dcache */ if (cpuinfo->l1.dc_size) { if (!mips_cache_ops.mco_pdcache_wbinv_all) panic("no pdcache_wbinv_all"); if (!mips_cache_ops.mco_pdcache_wbinv_range) panic("no pdcache_wbinv_range"); if (!mips_cache_ops.mco_pdcache_wbinv_range_index) panic("no pdcache_wbinv_range_index"); if (!mips_cache_ops.mco_pdcache_inv_range) panic("no pdcache_inv_range"); if (!mips_cache_ops.mco_pdcache_wb_range) panic("no pdcache_wb_range"); } /* L2 data cache */ if (!cpuinfo->l2.dc_size) { /* No L2 found, ignore */ return; } switch (cpuinfo->l2.dc_linesize) { case 32: mips_cache_ops.mco_sdcache_wbinv_all = mipsNN_sdcache_wbinv_all_32; mips_cache_ops.mco_sdcache_wbinv_range = mipsNN_sdcache_wbinv_range_32; mips_cache_ops.mco_sdcache_wbinv_range_index = mipsNN_sdcache_wbinv_range_index_32; mips_cache_ops.mco_sdcache_inv_range = mipsNN_sdcache_inv_range_32; mips_cache_ops.mco_sdcache_wb_range = mipsNN_sdcache_wb_range_32; break; case 64: mips_cache_ops.mco_sdcache_wbinv_all = mipsNN_sdcache_wbinv_all_64; mips_cache_ops.mco_sdcache_wbinv_range = mipsNN_sdcache_wbinv_range_64; mips_cache_ops.mco_sdcache_wbinv_range_index = mipsNN_sdcache_wbinv_range_index_64; mips_cache_ops.mco_sdcache_inv_range = mipsNN_sdcache_inv_range_64; mips_cache_ops.mco_sdcache_wb_range = mipsNN_sdcache_wb_range_64; break; case 128: mips_cache_ops.mco_sdcache_wbinv_all = mipsNN_sdcache_wbinv_all_128; mips_cache_ops.mco_sdcache_wbinv_range = mipsNN_sdcache_wbinv_range_128; mips_cache_ops.mco_sdcache_wbinv_range_index = mipsNN_sdcache_wbinv_range_index_128; mips_cache_ops.mco_sdcache_inv_range = mipsNN_sdcache_inv_range_128; mips_cache_ops.mco_sdcache_wb_range = mipsNN_sdcache_wb_range_128; break; default: #ifdef CACHE_DEBUG printf(" no sdcache ops for %d byte lines", cpuinfo->l2.dc_linesize); #endif break; } } Index: head/sys/mips/mips/cache_mipsNN.c =================================================================== --- head/sys/mips/mips/cache_mipsNN.c (revision 326258) +++ head/sys/mips/mips/cache_mipsNN.c (revision 326259) @@ -1,1382 +1,1384 @@ /* $NetBSD: cache_mipsNN.c,v 1.10 2005/12/24 20:07:19 perry Exp $ */ /* + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright 2001 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe and Simon Burge for Wasabi Systems, Inc. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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 #define round_line16(x) (((x) + 15) & ~15) #define trunc_line16(x) ((x) & ~15) #define round_line32(x) (((x) + 31) & ~31) #define trunc_line32(x) ((x) & ~31) #define round_line64(x) (((x) + 63) & ~63) #define trunc_line64(x) ((x) & ~63) #define round_line128(x) (((x) + 127) & ~127) #define trunc_line128(x) ((x) & ~127) #if defined(CPU_NLM) static __inline void xlp_sync(void) { __asm __volatile ( ".set push \n" ".set noreorder \n" ".set mips64 \n" "dla $8, 1f \n" "/* jr.hb $8 */ \n" ".word 0x1000408 \n" "nop \n" "1: nop \n" ".set pop \n" : : : "$8"); } #endif #if defined(SB1250_PASS1) #define SYNC __asm volatile("sync; sync") #elif defined(CPU_NLM) #define SYNC xlp_sync() #else #define SYNC __asm volatile("sync") #endif #if defined(CPU_CNMIPS) #define SYNCI mips_sync_icache(); #elif defined(CPU_NLM) #define SYNCI xlp_sync() #else #define SYNCI #endif /* * Exported variables for consumers like bus_dma code */ int mips_picache_linesize; int mips_pdcache_linesize; int mips_sdcache_linesize; int mips_dcache_max_linesize; static int picache_size; static int picache_stride; static int picache_loopcount; static int picache_way_mask; static int pdcache_size; static int pdcache_stride; static int pdcache_loopcount; static int pdcache_way_mask; static int sdcache_size; static int sdcache_stride; static int sdcache_loopcount; static int sdcache_way_mask; void mipsNN_cache_init(struct mips_cpuinfo * cpuinfo) { int flush_multiple_lines_per_way; flush_multiple_lines_per_way = cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_linesize * cpuinfo->l1.ic_linesize > PAGE_SIZE; if (cpuinfo->icache_virtual) { /* * With a virtual Icache we don't need to flush * multiples of the page size with index ops; we just * need to flush one pages' worth. */ flush_multiple_lines_per_way = 0; } if (flush_multiple_lines_per_way) { picache_stride = PAGE_SIZE; picache_loopcount = (cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_linesize / PAGE_SIZE) * cpuinfo->l1.ic_nways; } else { picache_stride = cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_linesize; picache_loopcount = cpuinfo->l1.ic_nways; } if (cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_linesize < PAGE_SIZE) { pdcache_stride = cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_linesize; pdcache_loopcount = cpuinfo->l1.dc_nways; } else { pdcache_stride = PAGE_SIZE; pdcache_loopcount = (cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_linesize / PAGE_SIZE) * cpuinfo->l1.dc_nways; } mips_picache_linesize = cpuinfo->l1.ic_linesize; mips_pdcache_linesize = cpuinfo->l1.dc_linesize; picache_size = cpuinfo->l1.ic_size; picache_way_mask = cpuinfo->l1.ic_nways - 1; pdcache_size = cpuinfo->l1.dc_size; pdcache_way_mask = cpuinfo->l1.dc_nways - 1; sdcache_stride = cpuinfo->l2.dc_nsets * cpuinfo->l2.dc_linesize; sdcache_loopcount = cpuinfo->l2.dc_nways; sdcache_size = cpuinfo->l2.dc_size; sdcache_way_mask = cpuinfo->l2.dc_nways - 1; mips_sdcache_linesize = cpuinfo->l2.dc_linesize; mips_dcache_max_linesize = MAX(mips_pdcache_linesize, mips_sdcache_linesize); #define CACHE_DEBUG #ifdef CACHE_DEBUG printf("Cache info:\n"); if (cpuinfo->icache_virtual) printf(" icache is virtual\n"); printf(" picache_stride = %d\n", picache_stride); printf(" picache_loopcount = %d\n", picache_loopcount); printf(" pdcache_stride = %d\n", pdcache_stride); printf(" pdcache_loopcount = %d\n", pdcache_loopcount); printf(" max line size = %d\n", mips_dcache_max_linesize); #endif } void mipsNN_icache_sync_all_16(void) { vm_offset_t va, eva; va = MIPS_PHYS_TO_KSEG0(0); eva = va + picache_size; /* * Since we're hitting the whole thing, we don't have to * worry about the N different "ways". */ mips_intern_dcache_wbinv_all(); while (va < eva) { cache_r4k_op_32lines_16(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += (32 * 16); } SYNC; } void mipsNN_icache_sync_all_32(void) { vm_offset_t va, eva; va = MIPS_PHYS_TO_KSEG0(0); eva = va + picache_size; /* * Since we're hitting the whole thing, we don't have to * worry about the N different "ways". */ mips_intern_dcache_wbinv_all(); while (va < eva) { cache_r4k_op_32lines_32(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += (32 * 32); } SYNC; } void mipsNN_icache_sync_all_64(void) { vm_offset_t va, eva; va = MIPS_PHYS_TO_KSEG0(0); eva = va + picache_size; /* * Since we're hitting the whole thing, we don't have to * worry about the N different "ways". */ mips_intern_dcache_wbinv_all(); while (va < eva) { cache_r4k_op_32lines_64(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += (32 * 64); } SYNC; } void mipsNN_icache_sync_range_16(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line16(va + size); va = trunc_line16(va); mips_intern_dcache_wb_range(va, (eva - va)); while ((eva - va) >= (32 * 16)) { cache_r4k_op_32lines_16(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); va += (32 * 16); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); va += 16; } SYNC; } void mipsNN_icache_sync_range_32(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line32(va + size); va = trunc_line32(va); mips_intern_dcache_wb_range(va, (eva - va)); while ((eva - va) >= (32 * 32)) { cache_r4k_op_32lines_32(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); va += (32 * 32); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); va += 32; } SYNC; } void mipsNN_icache_sync_range_64(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line64(va + size); va = trunc_line64(va); mips_intern_dcache_wb_range(va, (eva - va)); while ((eva - va) >= (32 * 64)) { cache_r4k_op_32lines_64(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); va += (32 * 64); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); va += 64; } SYNC; } void mipsNN_icache_sync_range_index_16(vm_offset_t va, vm_size_t size) { vm_offset_t eva, tmpva; int i, stride, loopcount; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & picache_way_mask); eva = round_line16(va + size); va = trunc_line16(va); /* * GCC generates better code in the loops if we reference local * copies of these global variables. */ stride = picache_stride; loopcount = picache_loopcount; mips_intern_dcache_wbinv_range_index(va, (eva - va)); while ((eva - va) >= (8 * 16)) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_r4k_op_8lines_16(tmpva, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += 8 * 16; } while (va < eva) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_op_r4k_line(tmpva, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += 16; } } void mipsNN_icache_sync_range_index_32(vm_offset_t va, vm_size_t size) { vm_offset_t eva, tmpva; int i, stride, loopcount; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & picache_way_mask); eva = round_line32(va + size); va = trunc_line32(va); /* * GCC generates better code in the loops if we reference local * copies of these global variables. */ stride = picache_stride; loopcount = picache_loopcount; mips_intern_dcache_wbinv_range_index(va, (eva - va)); while ((eva - va) >= (8 * 32)) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_r4k_op_8lines_32(tmpva, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += 8 * 32; } while (va < eva) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_op_r4k_line(tmpva, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += 32; } } void mipsNN_icache_sync_range_index_64(vm_offset_t va, vm_size_t size) { vm_offset_t eva, tmpva; int i, stride, loopcount; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & picache_way_mask); eva = round_line64(va + size); va = trunc_line64(va); /* * GCC generates better code in the loops if we reference local * copies of these global variables. */ stride = picache_stride; loopcount = picache_loopcount; mips_intern_dcache_wbinv_range_index(va, (eva - va)); while ((eva - va) >= (8 * 64)) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_r4k_op_8lines_64(tmpva, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += 8 * 64; } while (va < eva) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_op_r4k_line(tmpva, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += 64; } } void mipsNN_pdcache_wbinv_all_16(void) { vm_offset_t va, eva; va = MIPS_PHYS_TO_KSEG0(0); eva = va + pdcache_size; /* * Since we're hitting the whole thing, we don't have to * worry about the N different "ways". */ while (va < eva) { cache_r4k_op_32lines_16(va, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += (32 * 16); } SYNC; } void mipsNN_pdcache_wbinv_all_32(void) { vm_offset_t va, eva; va = MIPS_PHYS_TO_KSEG0(0); eva = va + pdcache_size; /* * Since we're hitting the whole thing, we don't have to * worry about the N different "ways". */ while (va < eva) { cache_r4k_op_32lines_32(va, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += (32 * 32); } SYNC; } void mipsNN_pdcache_wbinv_all_64(void) { vm_offset_t va, eva; va = MIPS_PHYS_TO_KSEG0(0); eva = va + pdcache_size; /* * Since we're hitting the whole thing, we don't have to * worry about the N different "ways". */ while (va < eva) { cache_r4k_op_32lines_64(va, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += (32 * 64); } SYNC; } void mipsNN_pdcache_wbinv_range_16(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line16(va + size); va = trunc_line16(va); while ((eva - va) >= (32 * 16)) { cache_r4k_op_32lines_16(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); va += (32 * 16); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); va += 16; } SYNC; } void mipsNN_pdcache_wbinv_range_32(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line32(va + size); va = trunc_line32(va); while ((eva - va) >= (32 * 32)) { cache_r4k_op_32lines_32(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); va += (32 * 32); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); va += 32; } SYNC; } void mipsNN_pdcache_wbinv_range_64(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line64(va + size); va = trunc_line64(va); while ((eva - va) >= (32 * 64)) { cache_r4k_op_32lines_64(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); va += (32 * 64); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); va += 64; } SYNC; } void mipsNN_pdcache_wbinv_range_index_16(vm_offset_t va, vm_size_t size) { vm_offset_t eva, tmpva; int i, stride, loopcount; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & pdcache_way_mask); eva = round_line16(va + size); va = trunc_line16(va); /* * GCC generates better code in the loops if we reference local * copies of these global variables. */ stride = pdcache_stride; loopcount = pdcache_loopcount; while ((eva - va) >= (8 * 16)) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_r4k_op_8lines_16(tmpva, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += 8 * 16; } while (va < eva) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_op_r4k_line(tmpva, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += 16; } } void mipsNN_pdcache_wbinv_range_index_32(vm_offset_t va, vm_size_t size) { vm_offset_t eva, tmpva; int i, stride, loopcount; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & pdcache_way_mask); eva = round_line32(va + size); va = trunc_line32(va); /* * GCC generates better code in the loops if we reference local * copies of these global variables. */ stride = pdcache_stride; loopcount = pdcache_loopcount; while ((eva - va) >= (8 * 32)) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_r4k_op_8lines_32(tmpva, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += 8 * 32; } while (va < eva) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_op_r4k_line(tmpva, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += 32; } } void mipsNN_pdcache_wbinv_range_index_64(vm_offset_t va, vm_size_t size) { vm_offset_t eva, tmpva; int i, stride, loopcount; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & pdcache_way_mask); eva = round_line64(va + size); va = trunc_line64(va); /* * GCC generates better code in the loops if we reference local * copies of these global variables. */ stride = pdcache_stride; loopcount = pdcache_loopcount; while ((eva - va) >= (8 * 64)) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_r4k_op_8lines_64(tmpva, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += 8 * 64; } while (va < eva) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_op_r4k_line(tmpva, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += 64; } } void mipsNN_pdcache_inv_range_16(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line16(va + size); va = trunc_line16(va); while ((eva - va) >= (32 * 16)) { cache_r4k_op_32lines_16(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); va += (32 * 16); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); va += 16; } SYNC; } void mipsNN_pdcache_inv_range_32(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line32(va + size); va = trunc_line32(va); while ((eva - va) >= (32 * 32)) { cache_r4k_op_32lines_32(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); va += (32 * 32); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); va += 32; } SYNC; } void mipsNN_pdcache_inv_range_64(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line64(va + size); va = trunc_line64(va); while ((eva - va) >= (32 * 64)) { cache_r4k_op_32lines_64(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); va += (32 * 64); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); va += 64; } SYNC; } void mipsNN_pdcache_wb_range_16(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line16(va + size); va = trunc_line16(va); while ((eva - va) >= (32 * 16)) { cache_r4k_op_32lines_16(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); va += (32 * 16); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); va += 16; } SYNC; } void mipsNN_pdcache_wb_range_32(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line32(va + size); va = trunc_line32(va); while ((eva - va) >= (32 * 32)) { cache_r4k_op_32lines_32(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); va += (32 * 32); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); va += 32; } SYNC; } void mipsNN_pdcache_wb_range_64(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line64(va + size); va = trunc_line64(va); while ((eva - va) >= (32 * 64)) { cache_r4k_op_32lines_64(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); va += (32 * 64); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); va += 64; } SYNC; } #ifdef CPU_CNMIPS void mipsNN_icache_sync_all_128(void) { SYNCI } void mipsNN_icache_sync_range_128(vm_offset_t va, vm_size_t size) { SYNC; } void mipsNN_icache_sync_range_index_128(vm_offset_t va, vm_size_t size) { } void mipsNN_pdcache_wbinv_all_128(void) { } void mipsNN_pdcache_wbinv_range_128(vm_offset_t va, vm_size_t size) { SYNC; } void mipsNN_pdcache_wbinv_range_index_128(vm_offset_t va, vm_size_t size) { } void mipsNN_pdcache_inv_range_128(vm_offset_t va, vm_size_t size) { } void mipsNN_pdcache_wb_range_128(vm_offset_t va, vm_size_t size) { SYNC; } #else void mipsNN_icache_sync_all_128(void) { vm_offset_t va, eva; va = MIPS_PHYS_TO_KSEG0(0); eva = va + picache_size; /* * Since we're hitting the whole thing, we don't have to * worry about the N different "ways". */ mips_intern_dcache_wbinv_all(); while (va < eva) { cache_r4k_op_32lines_128(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += (32 * 128); } SYNC; } void mipsNN_icache_sync_range_128(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line128(va + size); va = trunc_line128(va); mips_intern_dcache_wb_range(va, (eva - va)); while ((eva - va) >= (32 * 128)) { cache_r4k_op_32lines_128(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); va += (32 * 128); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); va += 128; } SYNC; } void mipsNN_icache_sync_range_index_128(vm_offset_t va, vm_size_t size) { vm_offset_t eva, tmpva; int i, stride, loopcount; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & picache_way_mask); eva = round_line128(va + size); va = trunc_line128(va); /* * GCC generates better code in the loops if we reference local * copies of these global variables. */ stride = picache_stride; loopcount = picache_loopcount; mips_intern_dcache_wbinv_range_index(va, (eva - va)); while ((eva - va) >= (32 * 128)) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_r4k_op_32lines_128(tmpva, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += 32 * 128; } while (va < eva) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_op_r4k_line(tmpva, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += 128; } } void mipsNN_pdcache_wbinv_all_128(void) { vm_offset_t va, eva; va = MIPS_PHYS_TO_KSEG0(0); eva = va + pdcache_size; /* * Since we're hitting the whole thing, we don't have to * worry about the N different "ways". */ while (va < eva) { cache_r4k_op_32lines_128(va, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += (32 * 128); } SYNC; } void mipsNN_pdcache_wbinv_range_128(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line128(va + size); va = trunc_line128(va); while ((eva - va) >= (32 * 128)) { cache_r4k_op_32lines_128(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); va += (32 * 128); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); va += 128; } SYNC; } void mipsNN_pdcache_wbinv_range_index_128(vm_offset_t va, vm_size_t size) { vm_offset_t eva, tmpva; int i, stride, loopcount; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & pdcache_way_mask); eva = round_line128(va + size); va = trunc_line128(va); /* * GCC generates better code in the loops if we reference local * copies of these global variables. */ stride = pdcache_stride; loopcount = pdcache_loopcount; while ((eva - va) >= (32 * 128)) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_r4k_op_32lines_128(tmpva, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += 32 * 128; } while (va < eva) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_op_r4k_line(tmpva, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += 128; } } void mipsNN_pdcache_inv_range_128(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line128(va + size); va = trunc_line128(va); while ((eva - va) >= (32 * 128)) { cache_r4k_op_32lines_128(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); va += (32 * 128); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); va += 128; } SYNC; } void mipsNN_pdcache_wb_range_128(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line128(va + size); va = trunc_line128(va); while ((eva - va) >= (32 * 128)) { cache_r4k_op_32lines_128(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); va += (32 * 128); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); va += 128; } SYNC; } #endif void mipsNN_sdcache_wbinv_all_32(void) { vm_offset_t va = MIPS_PHYS_TO_KSEG0(0); vm_offset_t eva = va + sdcache_size; while (va < eva) { cache_r4k_op_32lines_32(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); va += (32 * 32); } } void mipsNN_sdcache_wbinv_all_64(void) { vm_offset_t va = MIPS_PHYS_TO_KSEG0(0); vm_offset_t eva = va + sdcache_size; while (va < eva) { cache_r4k_op_32lines_64(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); va += (32 * 64); } } void mipsNN_sdcache_wbinv_range_32(vm_offset_t va, vm_size_t size) { vm_offset_t eva = round_line32(va + size); va = trunc_line32(va); while ((eva - va) >= (32 * 32)) { cache_r4k_op_32lines_32(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB_INV); va += (32 * 32); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB_INV); va += 32; } } void mipsNN_sdcache_wbinv_range_64(vm_offset_t va, vm_size_t size) { vm_offset_t eva = round_line64(va + size); va = trunc_line64(va); while ((eva - va) >= (32 * 64)) { cache_r4k_op_32lines_64(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB_INV); va += (32 * 64); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB_INV); va += 64; } } void mipsNN_sdcache_wbinv_range_index_32(vm_offset_t va, vm_size_t size) { vm_offset_t eva; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & (sdcache_size - 1)); eva = round_line32(va + size); va = trunc_line32(va); while ((eva - va) >= (32 * 32)) { cache_r4k_op_32lines_32(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); va += (32 * 32); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); va += 32; } } void mipsNN_sdcache_wbinv_range_index_64(vm_offset_t va, vm_size_t size) { vm_offset_t eva; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & (sdcache_size - 1)); eva = round_line64(va + size); va = trunc_line64(va); while ((eva - va) >= (32 * 64)) { cache_r4k_op_32lines_64(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); va += (32 * 64); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); va += 64; } } void mipsNN_sdcache_inv_range_32(vm_offset_t va, vm_size_t size) { vm_offset_t eva = round_line32(va + size); va = trunc_line32(va); while ((eva - va) >= (32 * 32)) { cache_r4k_op_32lines_32(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_INV); va += (32 * 32); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_INV); va += 32; } } void mipsNN_sdcache_inv_range_64(vm_offset_t va, vm_size_t size) { vm_offset_t eva = round_line64(va + size); va = trunc_line64(va); while ((eva - va) >= (32 * 64)) { cache_r4k_op_32lines_64(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_INV); va += (32 * 64); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_INV); va += 64; } } void mipsNN_sdcache_wb_range_32(vm_offset_t va, vm_size_t size) { vm_offset_t eva = round_line32(va + size); va = trunc_line32(va); while ((eva - va) >= (32 * 32)) { cache_r4k_op_32lines_32(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB); va += (32 * 32); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB); va += 32; } } void mipsNN_sdcache_wb_range_64(vm_offset_t va, vm_size_t size) { vm_offset_t eva = round_line64(va + size); va = trunc_line64(va); while ((eva - va) >= (32 * 64)) { cache_r4k_op_32lines_64(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB); va += (32 * 64); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB); va += 64; } } void mipsNN_sdcache_wbinv_all_128(void) { vm_offset_t va = MIPS_PHYS_TO_KSEG0(0); vm_offset_t eva = va + sdcache_size; while (va < eva) { cache_r4k_op_32lines_128(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); va += (32 * 128); } } void mipsNN_sdcache_wbinv_range_128(vm_offset_t va, vm_size_t size) { vm_offset_t eva = round_line128(va + size); va = trunc_line128(va); while ((eva - va) >= (32 * 128)) { cache_r4k_op_32lines_128(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB_INV); va += (32 * 128); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB_INV); va += 128; } } void mipsNN_sdcache_wbinv_range_index_128(vm_offset_t va, vm_size_t size) { vm_offset_t eva; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & (sdcache_size - 1)); eva = round_line128(va + size); va = trunc_line128(va); while ((eva - va) >= (32 * 128)) { cache_r4k_op_32lines_128(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); va += (32 * 128); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); va += 128; } } void mipsNN_sdcache_inv_range_128(vm_offset_t va, vm_size_t size) { vm_offset_t eva = round_line128(va + size); va = trunc_line128(va); while ((eva - va) >= (32 * 128)) { cache_r4k_op_32lines_128(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_INV); va += (32 * 128); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_INV); va += 128; } } void mipsNN_sdcache_wb_range_128(vm_offset_t va, vm_size_t size) { vm_offset_t eva = round_line128(va + size); va = trunc_line128(va); while ((eva - va) >= (32 * 128)) { cache_r4k_op_32lines_128(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB); va += (32 * 128); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB); va += 128; } } Index: head/sys/mips/mips/cpu.c =================================================================== --- head/sys/mips/mips/cpu.c (revision 326258) +++ head/sys/mips/mips/cpu.c (revision 326259) @@ -1,636 +1,638 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2004 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. * */ #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 #if defined(CPU_CNMIPS) #include #include #endif static void cpu_identify(void); struct mips_cpuinfo cpuinfo; #define _ENCODE_INSN(a,b,c,d,e) \ ((uint32_t)(((a) << 26)|((b) << 21)|((c) << 16)|((d) << 11)|(e))) #if defined(__mips_n64) # define _LOAD_T0_MDTLS_A1 \ _ENCODE_INSN(OP_LD, A1, T0, 0, offsetof(struct thread, td_md.md_tls)) # define _LOAD_T0_MDTLS_TCV_OFFSET_A1 \ _ENCODE_INSN(OP_LD, A1, T1, 0, \ offsetof(struct thread, td_md.md_tls_tcb_offset)) # define _ADDU_V0_T0_T1 \ _ENCODE_INSN(0, T0, T1, V0, OP_DADDU) #else /* mips 32 */ # define _LOAD_T0_MDTLS_A1 \ _ENCODE_INSN(OP_LW, A1, T0, 0, offsetof(struct thread, td_md.md_tls)) # define _LOAD_T0_MDTLS_TCV_OFFSET_A1 \ _ENCODE_INSN(OP_LW, A1, T1, 0, \ offsetof(struct thread, td_md.md_tls_tcb_offset)) # define _ADDU_V0_T0_T1 \ _ENCODE_INSN(0, T0, T1, V0, OP_ADDU) #endif /* ! __mips_n64 */ #if defined(__mips_n64) || defined(__mips_n32) # define _MTC0_V0_USERLOCAL \ _ENCODE_INSN(OP_COP0, OP_DMT, V0, 4, 2) #else /* mips o32 */ # define _MTC0_V0_USERLOCAL \ _ENCODE_INSN(OP_COP0, OP_MT, V0, 4, 2) #endif /* ! (__mips_n64 || __mipsn32) */ #define _JR_RA _ENCODE_INSN(OP_SPECIAL, RA, 0, 0, OP_JR) #define _NOP 0 /* * Patch cpu_switch() by removing the UserLocal register code at the end. * For MIPS hardware that don't support UserLocal Register Implementation * we remove the instructions that update this register which may cause a * reserved instruction exception in the kernel. */ static void remove_userlocal_code(uint32_t *cpu_switch_code) { uint32_t *instructp; for (instructp = cpu_switch_code;; instructp++) { if (instructp[0] == _JR_RA) panic("%s: Unable to patch cpu_switch().", __func__); if (instructp[0] == _LOAD_T0_MDTLS_A1 && instructp[1] == _LOAD_T0_MDTLS_TCV_OFFSET_A1 && instructp[2] == _ADDU_V0_T0_T1 && instructp[3] == _MTC0_V0_USERLOCAL) { instructp[0] = _JR_RA; instructp[1] = _NOP; break; } } } /* * Attempt to identify the MIPS CPU as much as possible. * * XXX: Assumes the CPU is MIPS{32,64}{,r2} compliant. * XXX: For now, skip config register selections 2 and 3 * as we don't currently use L2/L3 cache or additional * MIPS32 processor features. */ static void mips_get_identity(struct mips_cpuinfo *cpuinfo) { u_int32_t prid; u_int32_t cfg0; u_int32_t cfg1; u_int32_t cfg2; u_int32_t cfg3; #if defined(CPU_CNMIPS) u_int32_t cfg4; #endif u_int32_t tmp; memset(cpuinfo, 0, sizeof(struct mips_cpuinfo)); /* Read and store the PrID ID for CPU identification. */ prid = mips_rd_prid(); cpuinfo->cpu_vendor = MIPS_PRID_CID(prid); cpuinfo->cpu_rev = MIPS_PRID_REV(prid); cpuinfo->cpu_impl = MIPS_PRID_IMPL(prid); /* Read config register selection 0 to learn TLB type. */ cfg0 = mips_rd_config(); cpuinfo->tlb_type = ((cfg0 & MIPS_CONFIG0_MT_MASK) >> MIPS_CONFIG0_MT_SHIFT); cpuinfo->icache_virtual = cfg0 & MIPS_CONFIG0_VI; /* If config register selection 1 does not exist, return. */ if (!(cfg0 & MIPS_CONFIG0_M)) return; /* Learn TLB size and L1 cache geometry. */ cfg1 = mips_rd_config1(); /* Get the Config2 and Config3 registers as well. */ cfg2 = 0; cfg3 = 0; if (cfg1 & MIPS_CONFIG1_M) { cfg2 = mips_rd_config2(); if (cfg2 & MIPS_CONFIG2_M) cfg3 = mips_rd_config3(); } /* Save FP implementation revision if FP is present. */ if (cfg1 & MIPS_CONFIG1_FP) cpuinfo->fpu_id = MipsFPID(); /* Check to see if UserLocal register is implemented. */ if (cfg3 & MIPS_CONFIG3_ULR) { /* UserLocal register is implemented, enable it. */ cpuinfo->userlocal_reg = true; tmp = mips_rd_hwrena(); mips_wr_hwrena(tmp | MIPS_HWRENA_UL); } else { /* * UserLocal register is not implemented. Patch * cpu_switch() and remove unsupported code. */ cpuinfo->userlocal_reg = false; remove_userlocal_code((uint32_t *)cpu_switch); } #if defined(CPU_NLM) /* Account for Extended TLB entries in XLP */ tmp = mips_rd_config6(); cpuinfo->tlb_nentries = ((tmp >> 16) & 0xffff) + 1; #elif defined(BERI_LARGE_TLB) /* Check if we support extended TLB entries and if so activate. */ tmp = mips_rd_config5(); #define BERI_CP5_LTLB_SUPPORTED 0x1 if (tmp & BERI_CP5_LTLB_SUPPORTED) { /* See how many extra TLB entries we have. */ tmp = mips_rd_config6(); cpuinfo->tlb_nentries = (tmp >> 16) + 1; /* Activate the extended entries. */ mips_wr_config6(tmp|0x4); } else #endif #if !defined(CPU_NLM) cpuinfo->tlb_nentries = ((cfg1 & MIPS_CONFIG1_TLBSZ_MASK) >> MIPS_CONFIG1_TLBSZ_SHIFT) + 1; #endif #if defined(CPU_CNMIPS) /* Add extended TLB size information from config4. */ cfg4 = mips_rd_config4(); if ((cfg4 & MIPS_CONFIG4_MMUEXTDEF) == MIPS_CONFIG4_MMUEXTDEF_MMUSIZEEXT) cpuinfo->tlb_nentries += (cfg4 & MIPS_CONFIG4_MMUSIZEEXT) * 0x40; #endif /* L1 instruction cache. */ #ifdef MIPS_DISABLE_L1_CACHE cpuinfo->l1.ic_linesize = 0; #else tmp = (cfg1 & MIPS_CONFIG1_IL_MASK) >> MIPS_CONFIG1_IL_SHIFT; if (tmp != 0) { cpuinfo->l1.ic_linesize = 1 << (tmp + 1); cpuinfo->l1.ic_nways = (((cfg1 & MIPS_CONFIG1_IA_MASK) >> MIPS_CONFIG1_IA_SHIFT)) + 1; cpuinfo->l1.ic_nsets = 1 << (((cfg1 & MIPS_CONFIG1_IS_MASK) >> MIPS_CONFIG1_IS_SHIFT) + 6); } #endif /* L1 data cache. */ #ifdef MIPS_DISABLE_L1_CACHE cpuinfo->l1.dc_linesize = 0; #else #ifndef CPU_CNMIPS tmp = (cfg1 & MIPS_CONFIG1_DL_MASK) >> MIPS_CONFIG1_DL_SHIFT; if (tmp != 0) { cpuinfo->l1.dc_linesize = 1 << (tmp + 1); cpuinfo->l1.dc_nways = (((cfg1 & MIPS_CONFIG1_DA_MASK) >> MIPS_CONFIG1_DA_SHIFT)) + 1; cpuinfo->l1.dc_nsets = 1 << (((cfg1 & MIPS_CONFIG1_DS_MASK) >> MIPS_CONFIG1_DS_SHIFT) + 6); } #else /* * Some Octeon cache configuration parameters are by model family, not * config1. */ if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) { /* Octeon and Octeon XL. */ cpuinfo->l1.dc_nsets = 1; cpuinfo->l1.dc_nways = 64; } else if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) { /* Octeon Plus. */ cpuinfo->l1.dc_nsets = 2; cpuinfo->l1.dc_nways = 64; } else if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { /* Octeon II. */ cpuinfo->l1.dc_nsets = 8; cpuinfo->l1.dc_nways = 32; cpuinfo->l1.ic_nsets = 8; cpuinfo->l1.ic_nways = 37; } else { panic("%s: unsupported Cavium Networks CPU.", __func__); } /* All Octeon models use 128 byte line size. */ cpuinfo->l1.dc_linesize = 128; #endif #endif cpuinfo->l1.ic_size = cpuinfo->l1.ic_linesize * cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_nways; cpuinfo->l1.dc_size = cpuinfo->l1.dc_linesize * cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_nways; /* * Probe PageMask register to see what sizes of pages are supported * by writing all one's and then reading it back. */ mips_wr_pagemask(~0); cpuinfo->tlb_pgmask = mips_rd_pagemask(); mips_wr_pagemask(MIPS3_PGMASK_4K); #ifndef CPU_CNMIPS /* L2 cache */ if (!(cfg1 & MIPS_CONFIG_CM)) { /* We don't have valid cfg2 register */ return; } cfg2 = mips_rd_config2(); tmp = (cfg2 >> MIPS_CONFIG2_SL_SHIFT) & MIPS_CONFIG2_SL_MASK; if (0 < tmp && tmp <= 7) cpuinfo->l2.dc_linesize = 2 << tmp; tmp = (cfg2 >> MIPS_CONFIG2_SS_SHIFT) & MIPS_CONFIG2_SS_MASK; if (0 <= tmp && tmp <= 7) cpuinfo->l2.dc_nsets = 64 << tmp; tmp = (cfg2 >> MIPS_CONFIG2_SA_SHIFT) & MIPS_CONFIG2_SA_MASK; if (0 <= tmp && tmp <= 7) cpuinfo->l2.dc_nways = tmp + 1; cpuinfo->l2.dc_size = cpuinfo->l2.dc_linesize * cpuinfo->l2.dc_nsets * cpuinfo->l2.dc_nways; #endif } void mips_cpu_init(void) { platform_cpu_init(); mips_get_identity(&cpuinfo); num_tlbentries = cpuinfo.tlb_nentries; mips_wr_wired(0); tlb_invalidate_all(); mips_wr_wired(VMWIRED_ENTRIES); mips_config_cache(&cpuinfo); mips_vector_init(); mips_icache_sync_all(); mips_dcache_wbinv_all(); /* Print some info about CPU */ cpu_identify(); } static void cpu_identify(void) { uint32_t cfg0, cfg1, cfg2, cfg3; #if defined(CPU_MIPS1004K) || defined (CPU_MIPS74K) || defined (CPU_MIPS24K) uint32_t cfg7; #endif printf("cpu%d: ", 0); /* XXX per-cpu */ switch (cpuinfo.cpu_vendor) { case MIPS_PRID_CID_MTI: printf("MIPS Technologies"); break; case MIPS_PRID_CID_BROADCOM: case MIPS_PRID_CID_SIBYTE: printf("Broadcom"); break; case MIPS_PRID_CID_ALCHEMY: printf("AMD"); break; case MIPS_PRID_CID_SANDCRAFT: printf("Sandcraft"); break; case MIPS_PRID_CID_PHILIPS: printf("Philips"); break; case MIPS_PRID_CID_TOSHIBA: printf("Toshiba"); break; case MIPS_PRID_CID_LSI: printf("LSI"); break; case MIPS_PRID_CID_LEXRA: printf("Lexra"); break; case MIPS_PRID_CID_RMI: printf("RMI"); break; case MIPS_PRID_CID_CAVIUM: printf("Cavium"); break; case MIPS_PRID_CID_INGENIC: case MIPS_PRID_CID_INGENIC2: printf("Ingenic XBurst"); break; case MIPS_PRID_CID_PREHISTORIC: default: printf("Unknown cid %#x", cpuinfo.cpu_vendor); break; } printf(" processor v%d.%d\n", cpuinfo.cpu_rev, cpuinfo.cpu_impl); printf(" MMU: "); if (cpuinfo.tlb_type == MIPS_MMU_NONE) { printf("none present\n"); } else { if (cpuinfo.tlb_type == MIPS_MMU_TLB) { printf("Standard TLB"); } else if (cpuinfo.tlb_type == MIPS_MMU_BAT) { printf("Standard BAT"); } else if (cpuinfo.tlb_type == MIPS_MMU_FIXED) { printf("Fixed mapping"); } printf(", %d entries ", cpuinfo.tlb_nentries); } if (cpuinfo.tlb_pgmask) { printf("("); if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_MASKX) printf("1K "); printf("4K "); if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_16K) printf("16K "); if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_64K) printf("64K "); if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_256K) printf("256K "); if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_1M) printf("1M "); if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_16M) printf("16M "); if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_64M) printf("64M "); if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_256M) printf("256M "); printf("pg sizes)"); } printf("\n"); printf(" L1 i-cache: "); if (cpuinfo.l1.ic_linesize == 0) { printf("disabled"); } else { if (cpuinfo.l1.ic_nways == 1) { printf("direct-mapped with"); } else { printf ("%d ways of", cpuinfo.l1.ic_nways); } printf(" %d sets, %d bytes per line\n", cpuinfo.l1.ic_nsets, cpuinfo.l1.ic_linesize); } printf(" L1 d-cache: "); if (cpuinfo.l1.dc_linesize == 0) { printf("disabled"); } else { if (cpuinfo.l1.dc_nways == 1) { printf("direct-mapped with"); } else { printf ("%d ways of", cpuinfo.l1.dc_nways); } printf(" %d sets, %d bytes per line\n", cpuinfo.l1.dc_nsets, cpuinfo.l1.dc_linesize); } printf(" L2 cache: "); if (cpuinfo.l2.dc_linesize == 0) { printf("disabled\n"); } else { printf("%d ways of %d sets, %d bytes per line, " "%d KiB total size\n", cpuinfo.l2.dc_nways, cpuinfo.l2.dc_nsets, cpuinfo.l2.dc_linesize, cpuinfo.l2.dc_size / 1024); } cfg0 = mips_rd_config(); /* If config register selection 1 does not exist, exit. */ if (!(cfg0 & MIPS_CONFIG_CM)) return; cfg1 = mips_rd_config1(); printf(" Config1=0x%b\n", cfg1, "\20\7COP2\6MDMX\5PerfCount\4WatchRegs\3MIPS16\2EJTAG\1FPU"); if (cpuinfo.fpu_id != 0) printf(" FPU ID=0x%b\n", cpuinfo.fpu_id, "\020" "\020S" "\021D" "\022PS" "\0233D" "\024W" "\025L" "\026F64" "\0272008" "\034UFRP"); /* If config register selection 2 does not exist, exit. */ if (!(cfg1 & MIPS_CONFIG_CM)) return; cfg2 = mips_rd_config2(); /* * Config2 contains no useful information other then Config3 * existence flag */ printf(" Config2=0x%08x\n", cfg2); /* If config register selection 3 does not exist, exit. */ if (!(cfg2 & MIPS_CONFIG_CM)) return; cfg3 = mips_rd_config3(); /* Print Config3 if it contains any useful info */ if (cfg3 & ~(0x80000000)) printf(" Config3=0x%b\n", cfg3, "\20\16ULRI\2SmartMIPS\1TraceLogic"); #if defined(CPU_MIPS1004K) || defined (CPU_MIPS74K) || defined (CPU_MIPS24K) cfg7 = mips_rd_config7(); printf(" Config7=0x%b\n", cfg7, "\20\40WII\21AR"); #endif } static struct rman cpu_hardirq_rman; static devclass_t cpu_devclass; /* * Device methods */ static int cpu_probe(device_t); static int cpu_attach(device_t); static struct resource *cpu_alloc_resource(device_t, device_t, int, int *, rman_res_t, rman_res_t, rman_res_t, u_int); static int cpu_setup_intr(device_t, device_t, struct resource *, int, driver_filter_t *f, driver_intr_t *, void *, void **); static device_method_t cpu_methods[] = { /* Device interface */ DEVMETHOD(device_probe, cpu_probe), DEVMETHOD(device_attach, cpu_attach), DEVMETHOD(device_detach, bus_generic_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), /* Bus interface */ DEVMETHOD(bus_alloc_resource, cpu_alloc_resource), DEVMETHOD(bus_setup_intr, cpu_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), { 0, 0 } }; static driver_t cpu_driver = { "cpu", cpu_methods, 1 }; static int cpu_probe(device_t dev) { return (0); } static int cpu_attach(device_t dev) { int error; #ifdef notyet device_t clock; #endif cpu_hardirq_rman.rm_start = 0; cpu_hardirq_rman.rm_end = 5; cpu_hardirq_rman.rm_type = RMAN_ARRAY; cpu_hardirq_rman.rm_descr = "CPU Hard Interrupts"; error = rman_init(&cpu_hardirq_rman); if (error != 0) { device_printf(dev, "failed to initialize irq resources\n"); return (error); } /* XXX rman_manage_all. */ error = rman_manage_region(&cpu_hardirq_rman, cpu_hardirq_rman.rm_start, cpu_hardirq_rman.rm_end); if (error != 0) { device_printf(dev, "failed to manage irq resources\n"); return (error); } if (device_get_unit(dev) != 0) panic("can't attach more cpus"); device_set_desc(dev, "MIPS32 processor"); #ifdef notyet clock = device_add_child(dev, "clock", device_get_unit(dev)); if (clock == NULL) device_printf(dev, "clock failed to attach"); #endif return (bus_generic_attach(dev)); } static struct resource * cpu_alloc_resource(device_t dev, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct resource *res; if (type != SYS_RES_IRQ) return (NULL); res = rman_reserve_resource(&cpu_hardirq_rman, start, end, count, 0, child); return (res); } static int cpu_setup_intr(device_t dev, device_t child, struct resource *res, int flags, driver_filter_t *filt, driver_intr_t *handler, void *arg, void **cookiep) { int error; int intr; error = rman_activate_resource(res); if (error != 0) { device_printf(child, "could not activate irq\n"); return (error); } intr = rman_get_start(res); cpu_establish_hardintr(device_get_nameunit(child), filt, handler, arg, intr, flags, cookiep); device_printf(child, "established CPU interrupt %d\n", intr); return (0); } DRIVER_MODULE(cpu, root, cpu_driver, cpu_devclass, 0, 0); Index: head/sys/mips/mips/db_interface.c =================================================================== --- head/sys/mips/mips/db_interface.c (revision 326258) +++ head/sys/mips/mips/db_interface.c (revision 326259) @@ -1,348 +1,350 @@ /* $OpenBSD: db_machdep.c,v 1.2 1998/09/15 10:50:13 pefo Exp $ */ /*- + * SPDX-License-Identifier: BSD-4-Clause + * * Copyright (c) 1998 Per Fogelstrom, Opsycon AB * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed under OpenBSD by * Per Fogelstrom, Opsycon AB, Sweden. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. * * JNPR: db_interface.c,v 1.6.2.1 2007/08/29 12:24:49 girish */ #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 static db_varfcn_t db_frame; #define DB_OFFSET(x) (db_expr_t *)offsetof(struct trapframe, x) struct db_variable db_regs[] = { { "at", DB_OFFSET(ast), db_frame }, { "v0", DB_OFFSET(v0), db_frame }, { "v1", DB_OFFSET(v1), db_frame }, { "a0", DB_OFFSET(a0), db_frame }, { "a1", DB_OFFSET(a1), db_frame }, { "a2", DB_OFFSET(a2), db_frame }, { "a3", DB_OFFSET(a3), db_frame }, #if defined(__mips_n32) || defined(__mips_n64) { "a4", DB_OFFSET(a4), db_frame }, { "a5", DB_OFFSET(a5), db_frame }, { "a6", DB_OFFSET(a6), db_frame }, { "a7", DB_OFFSET(a7), db_frame }, { "t0", DB_OFFSET(t0), db_frame }, { "t1", DB_OFFSET(t1), db_frame }, { "t2", DB_OFFSET(t2), db_frame }, { "t3", DB_OFFSET(t3), db_frame }, #else { "t0", DB_OFFSET(t0), db_frame }, { "t1", DB_OFFSET(t1), db_frame }, { "t2", DB_OFFSET(t2), db_frame }, { "t3", DB_OFFSET(t3), db_frame }, { "t4", DB_OFFSET(t4), db_frame }, { "t5", DB_OFFSET(t5), db_frame }, { "t6", DB_OFFSET(t6), db_frame }, { "t7", DB_OFFSET(t7), db_frame }, #endif { "s0", DB_OFFSET(s0), db_frame }, { "s1", DB_OFFSET(s1), db_frame }, { "s2", DB_OFFSET(s2), db_frame }, { "s3", DB_OFFSET(s3), db_frame }, { "s4", DB_OFFSET(s4), db_frame }, { "s5", DB_OFFSET(s5), db_frame }, { "s6", DB_OFFSET(s6), db_frame }, { "s7", DB_OFFSET(s7), db_frame }, { "t8", DB_OFFSET(t8), db_frame }, { "t9", DB_OFFSET(t9), db_frame }, { "k0", DB_OFFSET(k0), db_frame }, { "k1", DB_OFFSET(k1), db_frame }, { "gp", DB_OFFSET(gp), db_frame }, { "sp", DB_OFFSET(sp), db_frame }, { "s8", DB_OFFSET(s8), db_frame }, { "ra", DB_OFFSET(ra), db_frame }, { "sr", DB_OFFSET(sr), db_frame }, { "lo", DB_OFFSET(mullo), db_frame }, { "hi", DB_OFFSET(mulhi), db_frame }, { "bad", DB_OFFSET(badvaddr), db_frame }, { "cs", DB_OFFSET(cause), db_frame }, { "pc", DB_OFFSET(pc), db_frame }, }; struct db_variable *db_eregs = db_regs + nitems(db_regs); int (*do_db_log_stack_trace_cmd)(char *); static int db_frame(struct db_variable *vp, db_expr_t *valuep, int op) { register_t *reg; if (kdb_frame == NULL) return (0); reg = (register_t *)((uintptr_t)kdb_frame + (size_t)(intptr_t)vp->valuep); if (op == DB_VAR_GET) *valuep = *reg; else *reg = *valuep; return (1); } int db_read_bytes(vm_offset_t addr, size_t size, char *data) { jmp_buf jb; void *prev_jb; int ret; prev_jb = kdb_jmpbuf(jb); ret = setjmp(jb); if (ret == 0) { /* * 'addr' could be a memory-mapped I/O address. Try to * do atomic load/store in unit of size requested. */ if ((size == 2 || size == 4 || size == 8) && ((addr & (size -1)) == 0) && (((vm_offset_t)data & (size -1)) == 0)) { switch (size) { case 2: *(uint16_t *)data = *(uint16_t *)addr; break; case 4: *(uint32_t *)data = *(uint32_t *)addr; break; case 8: atomic_load_64((volatile u_int64_t *)addr, (u_int64_t *)data); break; } } else { char *src; src = (char *)addr; while (size-- > 0) *data++ = *src++; } } (void)kdb_jmpbuf(prev_jb); return (ret); } int db_write_bytes(vm_offset_t addr, size_t size, char *data) { int ret; jmp_buf jb; void *prev_jb; prev_jb = kdb_jmpbuf(jb); ret = setjmp(jb); if (ret == 0) { /* * 'addr' could be a memory-mapped I/O address. Try to * do atomic load/store in unit of size requested. */ if ((size == 2 || size == 4 || size == 8) && ((addr & (size -1)) == 0) && (((vm_offset_t)data & (size -1)) == 0)) { switch (size) { case 2: *(uint16_t *)addr = *(uint16_t *)data; break; case 4: *(uint32_t *)addr = *(uint32_t *)data; break; case 8: atomic_store_64((volatile u_int64_t *)addr, (u_int64_t *)data); break; } } else { char *dst; size_t len = size; dst = (char *)addr; while (len-- > 0) *dst++ = *data++; } mips_icache_sync_range((db_addr_t) addr, size); mips_dcache_wbinv_range((db_addr_t) addr, size); } (void)kdb_jmpbuf(prev_jb); return (ret); } /* * To do a single step ddb needs to know the next address * that we will get to. It means that we need to find out * both the address for a branch taken and for not taken, NOT! :-) * MipsEmulateBranch will do the job to find out _exactly_ which * address we will end up at so the 'dual bp' method is not * requiered. */ db_addr_t next_instr_address(db_addr_t pc, boolean_t bd) { db_addr_t next; next = (db_addr_t)MipsEmulateBranch(kdb_frame, pc, 0, 0); return (next); } /* * Decode instruction and figure out type. */ int db_inst_type(int ins) { InstFmt inst; int ityp = 0; inst.word = ins; switch ((int)inst.JType.op) { case OP_SPECIAL: switch ((int)inst.RType.func) { case OP_JR: ityp = IT_BRANCH; break; case OP_JALR: case OP_SYSCALL: ityp = IT_CALL; break; } break; case OP_BCOND: switch ((int)inst.IType.rt) { case OP_BLTZ: case OP_BLTZL: case OP_BGEZ: case OP_BGEZL: ityp = IT_BRANCH; break; case OP_BLTZAL: case OP_BLTZALL: case OP_BGEZAL: case OP_BGEZALL: ityp = IT_CALL; break; } break; case OP_JAL: ityp = IT_CALL; break; case OP_J: case OP_BEQ: case OP_BEQL: case OP_BNE: case OP_BNEL: case OP_BLEZ: case OP_BLEZL: case OP_BGTZ: case OP_BGTZL: ityp = IT_BRANCH; break; case OP_COP1: switch (inst.RType.rs) { case OP_BCx: case OP_BCy: ityp = IT_BRANCH; break; } break; case OP_LB: case OP_LH: case OP_LW: case OP_LD: case OP_LBU: case OP_LHU: case OP_LWU: case OP_LWC1: ityp = IT_LOAD; break; case OP_SB: case OP_SH: case OP_SW: case OP_SD: case OP_SWC1: ityp = IT_STORE; break; } return (ityp); } /* * Return the next pc if the given branch is taken. * MachEmulateBranch() runs analysis for branch delay slot. */ db_addr_t branch_taken(int inst, db_addr_t pc) { db_addr_t ra; register_t fpucsr; /* TBD: when is fsr set */ fpucsr = (curthread) ? curthread->td_pcb->pcb_regs.fsr : 0; ra = (db_addr_t)MipsEmulateBranch(kdb_frame, pc, fpucsr, 0); return (ra); } Index: head/sys/mips/mips/db_trace.c =================================================================== --- head/sys/mips/mips/db_trace.c (revision 326258) +++ head/sys/mips/mips/db_trace.c (revision 326259) @@ -1,451 +1,453 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2004-2005, Juniper Networks, Inc. * 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. * * JNPR: db_trace.c,v 1.8 2007/08/09 11:23:32 katta */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern char _locore[]; extern char _locoreEnd[]; extern char edata[]; /* * A function using a stack frame has the following instruction as the first * one: [d]addiu sp,sp,- * * We make use of this to detect starting address of a function. This works * better than using 'j ra' instruction to signify end of the previous * function (for e.g. functions like boot() or panic() do not actually * emit a 'j ra' instruction). * * XXX the abi does not require that the addiu instruction be the first one. */ #define MIPS_START_OF_FUNCTION(ins) ((((ins) & 0xffff8000) == 0x27bd8000) \ || (((ins) & 0xffff8000) == 0x67bd8000)) /* * MIPS ABI 3.0 requires that all functions return using the 'j ra' instruction * * XXX gcc doesn't do this for functions with __noreturn__ attribute. */ #define MIPS_END_OF_FUNCTION(ins) ((ins) == 0x03e00008) #if defined(__mips_n64) # define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \ ((vm_offset_t)(reg) >= MIPS_XKPHYS_START)) #else # define MIPS_IS_VALID_KERNELADDR(reg) ((((reg) & 3) == 0) && \ ((vm_offset_t)(reg) >= MIPS_KSEG0_START)) #endif static void stacktrace_subr(register_t pc, register_t sp, register_t ra) { InstFmt i; /* * Arrays for a0..a3 registers and flags if content * of these registers is valid, e.g. obtained from the stack */ int valid_args[4]; register_t args[4]; register_t va, subr, cause, badvaddr; unsigned instr, mask; unsigned int frames = 0; int more, stksize, j; register_t next_ra; bool trapframe; /* Jump here when done with a frame, to start a new one */ loop: /* * Invalidate arguments values */ valid_args[0] = 0; valid_args[1] = 0; valid_args[2] = 0; valid_args[3] = 0; next_ra = 0; stksize = 0; subr = 0; trapframe = false; if (frames++ > 100) { db_printf("\nstackframe count exceeded\n"); return; } /* Check for bad SP: could foul up next frame. */ if (!MIPS_IS_VALID_KERNELADDR(sp)) { db_printf("SP 0x%jx: not in kernel\n", (uintmax_t)sp); ra = 0; subr = 0; goto done; } #define Between(x, y, z) \ ( ((x) <= (y)) && ((y) < (z)) ) #define pcBetween(a,b) \ Between((uintptr_t)a, pc, (uintptr_t)b) /* * Check for current PC in exception handler code that don't have a * preceding "j ra" at the tail of the preceding function. Depends * on relative ordering of functions in exception.S, swtch.S. */ if (pcBetween(MipsKernGenException, MipsUserGenException)) { subr = (uintptr_t)MipsKernGenException; trapframe = true; } else if (pcBetween(MipsUserGenException, MipsKernIntr)) subr = (uintptr_t)MipsUserGenException; else if (pcBetween(MipsKernIntr, MipsUserIntr)) { subr = (uintptr_t)MipsKernIntr; trapframe = true; } else if (pcBetween(MipsUserIntr, MipsTLBInvalidException)) subr = (uintptr_t)MipsUserIntr; else if (pcBetween(MipsTLBInvalidException, MipsTLBMissException)) { subr = (uintptr_t)MipsTLBInvalidException; if (pc == (uintptr_t)MipsKStackOverflow) trapframe = true; } else if (pcBetween(fork_trampoline, savectx)) subr = (uintptr_t)fork_trampoline; else if (pcBetween(savectx, cpu_throw)) subr = (uintptr_t)savectx; else if (pcBetween(cpu_throw, cpu_switch)) subr = (uintptr_t)cpu_throw; else if (pcBetween(cpu_switch, MipsSwitchFPState)) subr = (uintptr_t)cpu_switch; else if (pcBetween(_locore, _locoreEnd)) { subr = (uintptr_t)_locore; ra = 0; goto done; } /* Check for bad PC. */ if (!MIPS_IS_VALID_KERNELADDR(pc)) { db_printf("PC 0x%jx: not in kernel\n", (uintmax_t)pc); ra = 0; goto done; } /* * For a trapframe, skip to the output and afterwards pull the * previous registers out of the trapframe instead of decoding * the function prologue. */ if (trapframe) goto done; /* * Find the beginning of the current subroutine by scanning * backwards from the current PC for the end of the previous * subroutine. */ if (!subr) { va = pc - sizeof(int); while (1) { instr = kdbpeek((int *)va); if (MIPS_START_OF_FUNCTION(instr)) break; if (MIPS_END_OF_FUNCTION(instr)) { /* skip over branch-delay slot instruction */ va += 2 * sizeof(int); break; } va -= sizeof(int); } /* skip over nulls which might separate .o files */ while ((instr = kdbpeek((int *)va)) == 0) va += sizeof(int); subr = va; } /* scan forwards to find stack size and any saved registers */ stksize = 0; more = 3; mask = 0; for (va = subr; more; va += sizeof(int), more = (more == 3) ? 3 : more - 1) { /* stop if hit our current position */ if (va >= pc) break; instr = kdbpeek((int *)va); i.word = instr; switch (i.JType.op) { case OP_SPECIAL: switch (i.RType.func) { case OP_JR: case OP_JALR: more = 2; /* stop after next instruction */ break; case OP_SYSCALL: case OP_BREAK: more = 1; /* stop now */ } break; case OP_BCOND: case OP_J: case OP_JAL: case OP_BEQ: case OP_BNE: case OP_BLEZ: case OP_BGTZ: more = 2; /* stop after next instruction */ break; case OP_COP0: case OP_COP1: case OP_COP2: case OP_COP3: switch (i.RType.rs) { case OP_BCx: case OP_BCy: more = 2; /* stop after next instruction */ } break; case OP_SW: /* look for saved registers on the stack */ if (i.IType.rs != 29) break; /* * only restore the first one except RA for * MipsKernGenException case */ if (mask & (1 << i.IType.rt)) { if (subr == (uintptr_t)MipsKernGenException && i.IType.rt == 31) next_ra = kdbpeek((int *)(sp + (short)i.IType.imm)); break; } mask |= (1 << i.IType.rt); switch (i.IType.rt) { case 4:/* a0 */ args[0] = kdbpeek((int *)(sp + (short)i.IType.imm)); valid_args[0] = 1; break; case 5:/* a1 */ args[1] = kdbpeek((int *)(sp + (short)i.IType.imm)); valid_args[1] = 1; break; case 6:/* a2 */ args[2] = kdbpeek((int *)(sp + (short)i.IType.imm)); valid_args[2] = 1; break; case 7:/* a3 */ args[3] = kdbpeek((int *)(sp + (short)i.IType.imm)); valid_args[3] = 1; break; case 31: /* ra */ ra = kdbpeek((int *)(sp + (short)i.IType.imm)); } break; case OP_SD: /* look for saved registers on the stack */ if (i.IType.rs != 29) break; /* only restore the first one */ if (mask & (1 << i.IType.rt)) break; mask |= (1 << i.IType.rt); switch (i.IType.rt) { case 4:/* a0 */ args[0] = kdbpeekd((int *)(sp + (short)i.IType.imm)); valid_args[0] = 1; break; case 5:/* a1 */ args[1] = kdbpeekd((int *)(sp + (short)i.IType.imm)); valid_args[1] = 1; break; case 6:/* a2 */ args[2] = kdbpeekd((int *)(sp + (short)i.IType.imm)); valid_args[2] = 1; break; case 7:/* a3 */ args[3] = kdbpeekd((int *)(sp + (short)i.IType.imm)); valid_args[3] = 1; break; case 31: /* ra */ ra = kdbpeekd((int *)(sp + (short)i.IType.imm)); } break; case OP_ADDI: case OP_ADDIU: case OP_DADDI: case OP_DADDIU: /* look for stack pointer adjustment */ if (i.IType.rs != 29 || i.IType.rt != 29) break; stksize = -((short)i.IType.imm); } } done: db_printsym(pc, DB_STGY_PROC); db_printf(" ("); for (j = 0; j < 4; j ++) { if (j > 0) db_printf(","); if (valid_args[j]) db_printf("%jx", (uintmax_t)(u_register_t)args[j]); else db_printf("?"); } db_printf(") ra %jx sp %jx sz %d\n", (uintmax_t)(u_register_t) ra, (uintmax_t)(u_register_t) sp, stksize); if (trapframe) { #define TF_REG(base, reg) ((base) + CALLFRAME_SIZ + ((reg) * SZREG)) #if defined(__mips_n64) || defined(__mips_n32) pc = kdbpeekd((int *)TF_REG(sp, PC)); ra = kdbpeekd((int *)TF_REG(sp, RA)); sp = kdbpeekd((int *)TF_REG(sp, SP)); cause = kdbpeekd((int *)TF_REG(sp, CAUSE)); badvaddr = kdbpeekd((int *)TF_REG(sp, BADVADDR)); #else pc = kdbpeek((int *)TF_REG(sp, PC)); ra = kdbpeek((int *)TF_REG(sp, RA)); sp = kdbpeek((int *)TF_REG(sp, SP)); cause = kdbpeek((int *)TF_REG(sp, CAUSE)); badvaddr = kdbpeek((int *)TF_REG(sp, BADVADDR)); #endif #undef TF_REG db_printf("--- exception, cause %jx badvaddr %jx ---\n", (uintmax_t)cause, (uintmax_t)badvaddr); goto loop; } else if (ra) { if (pc == ra && stksize == 0) db_printf("stacktrace: loop!\n"); else { pc = ra; sp += stksize; ra = next_ra; goto loop; } } } int db_md_set_watchpoint(db_expr_t addr, db_expr_t size) { return(0); } int db_md_clr_watchpoint(db_expr_t addr, db_expr_t size) { return(0); } void db_md_list_watchpoints() { } void db_trace_self(void) { register_t pc, ra, sp; sp = (register_t)(intptr_t)__builtin_frame_address(0); ra = (register_t)(intptr_t)__builtin_return_address(0); __asm __volatile( "jal 99f\n" "nop\n" "99:\n" "move %0, $31\n" /* get ra */ "move $31, %1\n" /* restore ra */ : "=r" (pc) : "r" (ra)); stacktrace_subr(pc, sp, ra); return; } int db_trace_thread(struct thread *thr, int count) { register_t pc, ra, sp; struct pcb *ctx; ctx = kdb_thr_ctx(thr); sp = (register_t)ctx->pcb_context[PCB_REG_SP]; pc = (register_t)ctx->pcb_context[PCB_REG_PC]; ra = (register_t)ctx->pcb_context[PCB_REG_RA]; stacktrace_subr(pc, sp, ra); return (0); } void db_show_mdpcpu(struct pcpu *pc) { db_printf("ipis = 0x%x\n", pc->pc_pending_ipis); db_printf("next ASID = %d\n", pc->pc_next_asid); db_printf("GENID = %d\n", pc->pc_asid_generation); return; } Index: head/sys/mips/mips/dump_machdep.c =================================================================== --- head/sys/mips/mips/dump_machdep.c (revision 326258) +++ head/sys/mips/mips/dump_machdep.c (revision 326259) @@ -1,56 +1,58 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2002 Marcel Moolenaar * 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 ``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 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 int do_minidump = 1; SYSCTL_INT(_debug, OID_AUTO, minidump, CTLFLAG_RWTUN, &do_minidump, 0, "Enable mini crash dumps"); void dumpsys_wbinv_all(void) { /* Make sure we write coherent datas. */ mips_dcache_wbinv_all(); } void dumpsys_map_chunk(vm_paddr_t pa, size_t chunk __unused, void **va) { *va = (void *)(intptr_t)pa; } Index: head/sys/mips/mips/elf_machdep.c =================================================================== --- head/sys/mips/mips/elf_machdep.c (revision 326258) +++ head/sys/mips/mips/elf_machdep.c (revision 326259) @@ -1,545 +1,547 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright 1996-1998 John D. Polstra. * 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 ``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 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. * * from: src/sys/i386/i386/elf_machdep.c,v 1.20 2004/08/11 02:35:05 marcel */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __mips_n64 struct sysentvec elf64_freebsd_sysvec = { .sv_size = SYS_MAXSYSCALL, .sv_table = sysent, .sv_mask = 0, .sv_errsize = 0, .sv_errtbl = NULL, .sv_transtrap = NULL, .sv_fixup = __elfN(freebsd_fixup), .sv_sendsig = sendsig, .sv_sigcode = sigcode, .sv_szsigcode = &szsigcode, .sv_name = "FreeBSD ELF64", .sv_coredump = __elfN(coredump), .sv_imgact_try = NULL, .sv_minsigstksz = MINSIGSTKSZ, .sv_pagesize = PAGE_SIZE, .sv_minuser = VM_MIN_ADDRESS, .sv_maxuser = VM_MAXUSER_ADDRESS, .sv_usrstack = USRSTACK, .sv_psstrings = PS_STRINGS, .sv_stackprot = VM_PROT_ALL, .sv_copyout_strings = exec_copyout_strings, .sv_setregs = exec_setregs, .sv_fixlimit = NULL, .sv_maxssiz = NULL, .sv_flags = SV_ABI_FREEBSD | SV_LP64, .sv_set_syscall_retval = cpu_set_syscall_retval, .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = syscallnames, .sv_schedtail = NULL, .sv_thread_detach = NULL, .sv_trap = NULL, }; static Elf64_Brandinfo freebsd_brand_info = { .brand = ELFOSABI_FREEBSD, .machine = EM_MIPS, .compat_3_brand = "FreeBSD", .emul_path = NULL, .interp_path = "/libexec/ld-elf.so.1", .sysvec = &elf64_freebsd_sysvec, .interp_newpath = NULL, .brand_note = &elf64_freebsd_brandnote, .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE }; SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_ANY, (sysinit_cfunc_t) elf64_insert_brand_entry, &freebsd_brand_info); void elf64_dump_thread(struct thread *td __unused, void *dst __unused, size_t *off __unused) { } #else struct sysentvec elf32_freebsd_sysvec = { .sv_size = SYS_MAXSYSCALL, .sv_table = sysent, .sv_mask = 0, .sv_errsize = 0, .sv_errtbl = NULL, .sv_transtrap = NULL, .sv_fixup = __elfN(freebsd_fixup), .sv_sendsig = sendsig, .sv_sigcode = sigcode, .sv_szsigcode = &szsigcode, .sv_name = "FreeBSD ELF32", .sv_coredump = __elfN(coredump), .sv_imgact_try = NULL, .sv_minsigstksz = MINSIGSTKSZ, .sv_pagesize = PAGE_SIZE, .sv_minuser = VM_MIN_ADDRESS, .sv_maxuser = VM_MAXUSER_ADDRESS, .sv_usrstack = USRSTACK, .sv_psstrings = PS_STRINGS, .sv_stackprot = VM_PROT_ALL, .sv_copyout_strings = exec_copyout_strings, .sv_setregs = exec_setregs, .sv_fixlimit = NULL, .sv_maxssiz = NULL, .sv_flags = SV_ABI_FREEBSD | SV_ILP32, .sv_set_syscall_retval = cpu_set_syscall_retval, .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = syscallnames, .sv_schedtail = NULL, .sv_thread_detach = NULL, .sv_trap = NULL, }; static Elf32_Brandinfo freebsd_brand_info = { .brand = ELFOSABI_FREEBSD, .machine = EM_MIPS, .compat_3_brand = "FreeBSD", .emul_path = NULL, .interp_path = "/libexec/ld-elf.so.1", .sysvec = &elf32_freebsd_sysvec, .interp_newpath = NULL, .brand_note = &elf32_freebsd_brandnote, .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE }; SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_FIRST, (sysinit_cfunc_t) elf32_insert_brand_entry, &freebsd_brand_info); void elf32_dump_thread(struct thread *td __unused, void *dst __unused, size_t *off __unused) { } #endif /* * The following MIPS relocation code for tracking multiple * consecutive HI32/LO32 entries is because of the following: * * https://dmz-portal.mips.com/wiki/MIPS_relocation_types * * === * * + R_MIPS_HI16 * * An R_MIPS_HI16 must be followed eventually by an associated R_MIPS_LO16 * relocation record in the same SHT_REL section. The contents of the two * fields to be relocated are combined to form a full 32-bit addend AHL. * An R_MIPS_LO16 entry which does not immediately follow a R_MIPS_HI16 is * combined with the most recent one encountered, i.e. multiple R_MIPS_LO16 * entries may be associated with a single R_MIPS_HI16. Use of these * relocation types in a SHT_REL section is discouraged and may be * forbidden to avoid this complication. * * A GNU extension allows multiple R_MIPS_HI16 records to share the same * R_MIPS_LO16 relocation record(s). The association works like this within * a single relocation section: * * + From the beginning of the section moving to the end of the section, * until R_MIPS_LO16 is not found each found R_MIPS_HI16 relocation will * be associated with the first R_MIPS_LO16. * * + Until another R_MIPS_HI16 record is found all found R_MIPS_LO16 * relocations found are associated with the last R_MIPS_HI16. * * === * * This is so gcc can do dead code detection/removal without having to * generate HI/LO pairs even if one of them would be deleted. * * So, the summary is: * * + A HI16 entry must occur before any LO16 entries; * + Multiple consecutive HI16 RELA entries need to be buffered until the * first LO16 RELA entry occurs - and then all HI16 RELA relocations use * the offset in the LOW16 RELA for calculating their offsets; * + The last HI16 RELA entry before a LO16 RELA entry is used (the AHL) * for the first subsequent LO16 calculation; * + If multiple consecutive LO16 RELA entries occur, only the first * LO16 RELA entry triggers an update of buffered HI16 RELA entries; * any subsequent LO16 RELA entry before another HI16 RELA entry will * not cause any further updates to the HI16 RELA entries. * * Additionally, flush out any outstanding HI16 entries that don't have * a LO16 entry in case some garbage entries are left in the file. */ struct mips_tmp_reloc; struct mips_tmp_reloc { struct mips_tmp_reloc *next; Elf_Addr ahl; Elf32_Addr *where_hi16; }; static struct mips_tmp_reloc *ml = NULL; /* * Add a temporary relocation (ie, a HI16 reloc type.) */ static int mips_tmp_reloc_add(Elf_Addr ahl, Elf32_Addr *where_hi16) { struct mips_tmp_reloc *r; r = malloc(sizeof(struct mips_tmp_reloc), M_TEMP, M_NOWAIT); if (r == NULL) { printf("%s: failed to malloc\n", __func__); return (0); } r->ahl = ahl; r->where_hi16 = where_hi16; r->next = ml; ml = r; return (1); } /* * Flush the temporary relocation list. * * This should be done after a file is completely loaded * so no stale relocations exist to confuse the next * load. */ static void mips_tmp_reloc_flush(void) { struct mips_tmp_reloc *r, *rn; r = ml; ml = NULL; while (r != NULL) { rn = r->next; free(r, M_TEMP); r = rn; } } /* * Get an entry from the reloc list; or NULL if we've run out. */ static struct mips_tmp_reloc * mips_tmp_reloc_get(void) { struct mips_tmp_reloc *r; r = ml; if (r == NULL) return (NULL); ml = ml->next; return (r); } /* * Free a relocation entry. */ static void mips_tmp_reloc_free(struct mips_tmp_reloc *r) { free(r, M_TEMP); } /* Process one elf relocation with addend. */ static int elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, int type, int local, elf_lookup_fn lookup) { Elf32_Addr *where = (Elf32_Addr *)NULL; Elf_Addr addr; Elf_Addr addend = (Elf_Addr)0; Elf_Word rtype = (Elf_Word)0, symidx; struct mips_tmp_reloc *r; const Elf_Rel *rel = NULL; const Elf_Rela *rela = NULL; int error; /* Store the last seen ahl from a HI16 for LO16 processing */ static Elf_Addr last_ahl; switch (type) { case ELF_RELOC_REL: rel = (const Elf_Rel *)data; where = (Elf32_Addr *) (relocbase + rel->r_offset); rtype = ELF_R_TYPE(rel->r_info); symidx = ELF_R_SYM(rel->r_info); switch (rtype) { case R_MIPS_64: addend = *(Elf64_Addr *)where; break; default: addend = *where; break; } break; case ELF_RELOC_RELA: rela = (const Elf_Rela *)data; where = (Elf32_Addr *) (relocbase + rela->r_offset); addend = rela->r_addend; rtype = ELF_R_TYPE(rela->r_info); symidx = ELF_R_SYM(rela->r_info); break; default: panic("unknown reloc type %d\n", type); } switch (rtype) { case R_MIPS_NONE: /* none */ break; case R_MIPS_32: /* S + A */ error = lookup(lf, symidx, 1, &addr); if (error != 0) return (-1); addr += addend; if (*where != addr) *where = (Elf32_Addr)addr; break; case R_MIPS_26: /* ((A << 2) | (P & 0xf0000000) + S) >> 2 */ error = lookup(lf, symidx, 1, &addr); if (error != 0) return (-1); addend &= 0x03ffffff; /* * Addendum for .rela R_MIPS_26 is not shifted right */ if (rela == NULL) addend <<= 2; addr += ((Elf_Addr)where & 0xf0000000) | addend; addr >>= 2; *where &= ~0x03ffffff; *where |= addr & 0x03ffffff; break; case R_MIPS_64: /* S + A */ error = lookup(lf, symidx, 1, &addr); if (error != 0) return (-1); addr += addend; if (*(Elf64_Addr*)where != addr) *(Elf64_Addr*)where = addr; break; /* * Handle the two GNU extension cases: * * + Multiple HI16s followed by a LO16, and * + A HI16 followed by multiple LO16s. * * The former is tricky - the HI16 relocations need * to be buffered until a LO16 occurs, at which point * each HI16 is replayed against the LO16 relocation entry * (with the relevant overflow information.) * * The latter should be easy to handle - when the * first LO16 is seen, write out and flush the * HI16 buffer. Any subsequent LO16 entries will * find a blank relocation buffer. * */ case R_MIPS_HI16: /* ((AHL + S) - ((short)(AHL + S)) >> 16 */ if (rela != NULL) { error = lookup(lf, symidx, 1, &addr); if (error != 0) return (-1); addr += addend; *where &= 0xffff0000; *where |= ((((long long) addr + 0x8000LL) >> 16) & 0xffff); } else { /* * Add a temporary relocation to the list; * will pop it off / free the list when * we've found a suitable HI16. */ if (mips_tmp_reloc_add(addend << 16, where) == 0) return (-1); /* * Track the last seen HI16 AHL for use by * the first LO16 AHL calculation. * * The assumption is any intermediary deleted * LO16's were optimised out, so the last * HI16 before the LO16 is the "true" relocation * entry to use for that LO16 write. */ last_ahl = addend << 16; } break; case R_MIPS_LO16: /* AHL + S */ if (rela != NULL) { error = lookup(lf, symidx, 1, &addr); if (error != 0) return (-1); addr += addend; *where &= 0xffff0000; *where |= addr & 0xffff; } else { Elf_Addr tmp_ahl; Elf_Addr tmp_addend; tmp_ahl = last_ahl + (int16_t) addend; error = lookup(lf, symidx, 1, &addr); if (error != 0) return (-1); tmp_addend = addend & 0xffff0000; /* Use the last seen ahl for calculating addend */ tmp_addend |= (uint16_t)(tmp_ahl + addr); *where = tmp_addend; /* * This logic implements the "we saw multiple HI16 * before a LO16" assignment /and/ "we saw multiple * LO16s". * * Multiple LO16s will be handled as a blank * relocation list. * * Multple HI16's are iterated over here. */ while ((r = mips_tmp_reloc_get()) != NULL) { Elf_Addr rahl; /* * We have the ahl from the HI16 entry, so * offset it by the 16 bits of the low ahl. */ rahl = r->ahl; rahl += (int16_t) addend; tmp_addend = *(r->where_hi16); tmp_addend &= 0xffff0000; tmp_addend |= ((rahl + addr) - (int16_t)(rahl + addr)) >> 16; *(r->where_hi16) = tmp_addend; mips_tmp_reloc_free(r); } } break; case R_MIPS_HIGHER: /* %higher(A+S) */ error = lookup(lf, symidx, 1, &addr); if (error != 0) return (-1); addr += addend; *where &= 0xffff0000; *where |= (((long long)addr + 0x80008000LL) >> 32) & 0xffff; break; case R_MIPS_HIGHEST: /* %highest(A+S) */ error = lookup(lf, symidx, 1, &addr); if (error != 0) return (-1); addr += addend; *where &= 0xffff0000; *where |= (((long long)addr + 0x800080008000LL) >> 48) & 0xffff; break; default: printf("kldload: unexpected relocation type %d\n", rtype); return (-1); } return(0); } int elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type, elf_lookup_fn lookup) { return (elf_reloc_internal(lf, relocbase, data, type, 0, lookup)); } int elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data, int type, elf_lookup_fn lookup) { return (elf_reloc_internal(lf, relocbase, data, type, 1, lookup)); } int elf_cpu_load_file(linker_file_t lf __unused) { /* * Sync the I and D caches to make sure our relocations are visible. */ mips_icache_sync_all(); /* Flush outstanding relocations */ mips_tmp_reloc_flush(); return (0); } int elf_cpu_unload_file(linker_file_t lf __unused) { return (0); } Index: head/sys/mips/mips/elf_trampoline.c =================================================================== --- head/sys/mips/mips/elf_trampoline.c (revision 326258) +++ head/sys/mips/mips/elf_trampoline.c (revision 326259) @@ -1,224 +1,226 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2005 Olivier Houchard. 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 ``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 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 #if ELFSIZE == 64 #include #else #include #endif /* * Since we are compiled outside of the normal kernel build process, we * need to include opt_global.h manually. */ #include "opt_global.h" #include #include #include #include #ifndef KERNNAME #error Kernel name not provided #endif extern char kernel_start[]; extern char kernel_end[]; static __inline void * memcpy(void *dst, const void *src, size_t len) { const char *s = src; char *d = dst; while (len) { if (0 && len >= 4 && !((vm_offset_t)d & 3) && !((vm_offset_t)s & 3)) { *(uint32_t *)d = *(uint32_t *)s; s += 4; d += 4; len -= 4; } else { *d++ = *s++; len--; } } return (dst); } static __inline void bzero(void *addr, size_t count) { char *tmp = (char *)addr; while (count > 0) { if (count >= 4 && !((vm_offset_t)tmp & 3)) { *(uint32_t *)tmp = 0; tmp += 4; count -= 4; } else { *tmp = 0; tmp++; count--; } } } /* * Convert number to pointer, truncate on 64->32 case, sign extend * in 32->64 case */ #define mkptr(x) ((void *)(intptr_t)(int)(x)) /* * Relocate PT_LOAD segements of kernel ELF image to their respective * virtual addresses and return entry point */ void * load_kernel(void * kstart) { #if ELFSIZE == 64 Elf64_Ehdr *eh; Elf64_Phdr phdr[64] /* XXX */; Elf64_Shdr shdr[64] /* XXX */; #else Elf32_Ehdr *eh; Elf32_Phdr phdr[64] /* XXX */; Elf32_Shdr shdr[64] /* XXX */; #endif int i, j; void *entry_point; vm_offset_t loadend = 0; intptr_t lastaddr; int symtabindex = -1; int symstrindex = -1; Elf_Size tmp; #if ELFSIZE == 64 eh = (Elf64_Ehdr *)kstart; #else eh = (Elf32_Ehdr *)kstart; #endif entry_point = mkptr(eh->e_entry); memcpy(phdr, (void *)(kstart + eh->e_phoff), eh->e_phnum * sizeof(phdr[0])); memcpy(shdr, (void *)(kstart + eh->e_shoff), sizeof(*shdr) * eh->e_shnum); if (eh->e_shnum * eh->e_shentsize != 0 && eh->e_shoff != 0) { for (i = 0; i < eh->e_shnum; i++) { if (shdr[i].sh_type == SHT_SYMTAB) { /* * XXX: check if .symtab is in PT_LOAD? */ if (shdr[i].sh_offset != 0 && shdr[i].sh_size != 0) { symtabindex = i; symstrindex = shdr[i].sh_link; } } } } /* * Copy loadable segments */ for (i = 0; i < eh->e_phnum; i++) { volatile char c; if (phdr[i].p_type != PT_LOAD) continue; memcpy(mkptr(phdr[i].p_vaddr), (void*)(kstart + phdr[i].p_offset), phdr[i].p_filesz); /* Clean space from oversized segments, eg: bss. */ if (phdr[i].p_filesz < phdr[i].p_memsz) bzero(mkptr(phdr[i].p_vaddr + phdr[i].p_filesz), phdr[i].p_memsz - phdr[i].p_filesz); if (loadend < phdr[i].p_vaddr + phdr[i].p_memsz) loadend = phdr[i].p_vaddr + phdr[i].p_memsz; } /* Now grab the symbol tables. */ lastaddr = (intptr_t)(int)loadend; if (symtabindex >= 0 && symstrindex >= 0) { tmp = SYMTAB_MAGIC; memcpy((void *)lastaddr, &tmp, sizeof(tmp)); lastaddr += sizeof(Elf_Size); tmp = shdr[symtabindex].sh_size + shdr[symstrindex].sh_size + 2*sizeof(Elf_Size); memcpy((void *)lastaddr, &tmp, sizeof(tmp)); lastaddr += sizeof(Elf_Size); /* .symtab size */ tmp = shdr[symtabindex].sh_size; memcpy((void *)lastaddr, &tmp, sizeof(tmp)); lastaddr += sizeof(shdr[symtabindex].sh_size); /* .symtab data */ memcpy((void*)lastaddr, shdr[symtabindex].sh_offset + kstart, shdr[symtabindex].sh_size); lastaddr += shdr[symtabindex].sh_size; /* .strtab size */ tmp = shdr[symstrindex].sh_size; memcpy((void *)lastaddr, &tmp, sizeof(tmp)); lastaddr += sizeof(shdr[symstrindex].sh_size); /* .strtab data */ memcpy((void*)lastaddr, shdr[symstrindex].sh_offset + kstart, shdr[symstrindex].sh_size); } else { /* Do not take any chances */ tmp = 0; memcpy((void *)lastaddr, &tmp, sizeof(tmp)); } return entry_point; } void _startC(register_t a0, register_t a1, register_t a2, register_t a3) { unsigned int * code; int i; void (*entry_point)(register_t, register_t, register_t, register_t); /* * Relocate segment to the predefined memory location * Most likely it will be KSEG0/KSEG1 address */ entry_point = load_kernel(kernel_start); /* Pass saved registers to original _start */ entry_point(a0, a1, a2, a3); } Index: head/sys/mips/mips/freebsd32_machdep.c =================================================================== --- head/sys/mips/mips/freebsd32_machdep.c (revision 326258) +++ head/sys/mips/mips/freebsd32_machdep.c (revision 326259) @@ -1,493 +1,495 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2012 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$ */ /* * Based on nwhitehorn's COMPAT_FREEBSD32 support code for PowerPC64. */ #include "opt_compat.h" #define __ELF_WORD_SIZE 32 #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 static void freebsd32_exec_setregs(struct thread *, struct image_params *, u_long); static int get_mcontext32(struct thread *, mcontext32_t *, int); static int set_mcontext32(struct thread *, mcontext32_t *); static void freebsd32_sendsig(sig_t, ksiginfo_t *, sigset_t *); extern const char *freebsd32_syscallnames[]; struct sysentvec elf32_freebsd_sysvec = { .sv_size = SYS_MAXSYSCALL, .sv_table = freebsd32_sysent, .sv_mask = 0, .sv_errsize = 0, .sv_errtbl = NULL, .sv_transtrap = NULL, .sv_fixup = __elfN(freebsd_fixup), .sv_sendsig = freebsd32_sendsig, .sv_sigcode = sigcode32, .sv_szsigcode = &szsigcode32, .sv_name = "FreeBSD ELF32", .sv_coredump = __elfN(coredump), .sv_imgact_try = NULL, .sv_minsigstksz = MINSIGSTKSZ, .sv_pagesize = PAGE_SIZE, .sv_minuser = VM_MIN_ADDRESS, .sv_maxuser = ((vm_offset_t)0x80000000), .sv_usrstack = FREEBSD32_USRSTACK, .sv_psstrings = FREEBSD32_PS_STRINGS, .sv_stackprot = VM_PROT_ALL, .sv_copyout_strings = freebsd32_copyout_strings, .sv_setregs = freebsd32_exec_setregs, .sv_fixlimit = NULL, .sv_maxssiz = NULL, .sv_flags = SV_ABI_FREEBSD | SV_ILP32, .sv_set_syscall_retval = cpu_set_syscall_retval, .sv_fetch_syscall_args = cpu_fetch_syscall_args, .sv_syscallnames = freebsd32_syscallnames, .sv_schedtail = NULL, .sv_thread_detach = NULL, .sv_trap = NULL, }; INIT_SYSENTVEC(elf32_sysvec, &elf32_freebsd_sysvec); static Elf32_Brandinfo freebsd_brand_info = { .brand = ELFOSABI_FREEBSD, .machine = EM_MIPS, .compat_3_brand = "FreeBSD", .emul_path = NULL, .interp_path = "/libexec/ld-elf.so.1", .sysvec = &elf32_freebsd_sysvec, .interp_newpath = "/libexec/ld-elf32.so.1", .brand_note = &elf32_freebsd_brandnote, .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE }; SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_FIRST, (sysinit_cfunc_t) elf32_insert_brand_entry, &freebsd_brand_info); static void freebsd32_exec_setregs(struct thread *td, struct image_params *imgp, u_long stack) { exec_setregs(td, imgp, stack); /* * See comment in exec_setregs about running 32-bit binaries with 64-bit * registers. */ td->td_frame->sp -= 65536; /* * Clear extended address space bit for userland. */ td->td_frame->sr &= ~MIPS_SR_UX; td->td_md.md_tls_tcb_offset = TLS_TP_OFFSET + TLS_TCB_SIZE32; } int set_regs32(struct thread *td, struct reg32 *regs) { struct reg r; unsigned i; for (i = 0; i < NUMSAVEREGS; i++) r.r_regs[i] = regs->r_regs[i]; return (set_regs(td, &r)); } int fill_regs32(struct thread *td, struct reg32 *regs) { struct reg r; unsigned i; int error; error = fill_regs(td, &r); if (error != 0) return (error); for (i = 0; i < NUMSAVEREGS; i++) regs->r_regs[i] = r.r_regs[i]; return (0); } int set_fpregs32(struct thread *td, struct fpreg32 *fpregs) { struct fpreg fp; unsigned i; for (i = 0; i < NUMFPREGS; i++) fp.r_regs[i] = fpregs->r_regs[i]; return (set_fpregs(td, &fp)); } int fill_fpregs32(struct thread *td, struct fpreg32 *fpregs) { struct fpreg fp; unsigned i; int error; error = fill_fpregs(td, &fp); if (error != 0) return (error); for (i = 0; i < NUMFPREGS; i++) fpregs->r_regs[i] = fp.r_regs[i]; return (0); } static int get_mcontext32(struct thread *td, mcontext32_t *mcp, int flags) { mcontext_t mcp64; unsigned i; int error; error = get_mcontext(td, &mcp64, flags); if (error != 0) return (error); mcp->mc_onstack = mcp64.mc_onstack; mcp->mc_pc = mcp64.mc_pc; for (i = 0; i < 32; i++) mcp->mc_regs[i] = mcp64.mc_regs[i]; mcp->sr = mcp64.sr; mcp->mullo = mcp64.mullo; mcp->mulhi = mcp64.mulhi; mcp->mc_fpused = mcp64.mc_fpused; for (i = 0; i < 33; i++) mcp->mc_fpregs[i] = mcp64.mc_fpregs[i]; mcp->mc_fpc_eir = mcp64.mc_fpc_eir; mcp->mc_tls = (int32_t)(intptr_t)mcp64.mc_tls; return (0); } static int set_mcontext32(struct thread *td, mcontext32_t *mcp) { mcontext_t mcp64; unsigned i; mcp64.mc_onstack = mcp->mc_onstack; mcp64.mc_pc = mcp->mc_pc; for (i = 0; i < 32; i++) mcp64.mc_regs[i] = mcp->mc_regs[i]; mcp64.sr = mcp->sr; mcp64.mullo = mcp->mullo; mcp64.mulhi = mcp->mulhi; mcp64.mc_fpused = mcp->mc_fpused; for (i = 0; i < 33; i++) mcp64.mc_fpregs[i] = mcp->mc_fpregs[i]; mcp64.mc_fpc_eir = mcp->mc_fpc_eir; mcp64.mc_tls = (void *)(intptr_t)mcp->mc_tls; return (set_mcontext(td, &mcp64)); } int freebsd32_sigreturn(struct thread *td, struct freebsd32_sigreturn_args *uap) { ucontext32_t uc; int error; CTR2(KTR_SIG, "sigreturn: td=%p ucp=%p", td, uap->sigcntxp); if (copyin(uap->sigcntxp, &uc, sizeof(uc)) != 0) { CTR1(KTR_SIG, "sigreturn: efault td=%p", td); return (EFAULT); } error = set_mcontext32(td, &uc.uc_mcontext); if (error != 0) return (error); kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0); #if 0 CTR3(KTR_SIG, "sigreturn: return td=%p pc=%#x sp=%#x", td, uc.uc_mcontext.mc_srr0, uc.uc_mcontext.mc_gpr[1]); #endif return (EJUSTRETURN); } /* * The first two fields of a ucontext_t are the signal mask and the machine * context. The next field is uc_link; we want to avoid destroying the link * when copying out contexts. */ #define UC32_COPY_SIZE offsetof(ucontext32_t, uc_link) int freebsd32_getcontext(struct thread *td, struct freebsd32_getcontext_args *uap) { ucontext32_t uc; int ret; if (uap->ucp == NULL) ret = EINVAL; else { get_mcontext32(td, &uc.uc_mcontext, GET_MC_CLEAR_RET); PROC_LOCK(td->td_proc); uc.uc_sigmask = td->td_sigmask; PROC_UNLOCK(td->td_proc); ret = copyout(&uc, uap->ucp, UC32_COPY_SIZE); } return (ret); } int freebsd32_setcontext(struct thread *td, struct freebsd32_setcontext_args *uap) { ucontext32_t uc; int ret; if (uap->ucp == NULL) ret = EINVAL; else { ret = copyin(uap->ucp, &uc, UC32_COPY_SIZE); if (ret == 0) { ret = set_mcontext32(td, &uc.uc_mcontext); if (ret == 0) { kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0); } } } return (ret == 0 ? EJUSTRETURN : ret); } int freebsd32_swapcontext(struct thread *td, struct freebsd32_swapcontext_args *uap) { ucontext32_t uc; int ret; if (uap->oucp == NULL || uap->ucp == NULL) ret = EINVAL; else { get_mcontext32(td, &uc.uc_mcontext, GET_MC_CLEAR_RET); PROC_LOCK(td->td_proc); uc.uc_sigmask = td->td_sigmask; PROC_UNLOCK(td->td_proc); ret = copyout(&uc, uap->oucp, UC32_COPY_SIZE); if (ret == 0) { ret = copyin(uap->ucp, &uc, UC32_COPY_SIZE); if (ret == 0) { ret = set_mcontext32(td, &uc.uc_mcontext); if (ret == 0) { kern_sigprocmask(td, SIG_SETMASK, &uc.uc_sigmask, NULL, 0); } } } } return (ret == 0 ? EJUSTRETURN : ret); } #define UCONTEXT_MAGIC 0xACEDBADE /* * Send an interrupt to process. * * Stack is set up to allow sigcode stored * at top to call routine, followed by kcall * to sigreturn routine below. After sigreturn * resets the signal mask, the stack, and the * frame pointer, it returns to the user * specified pc, psl. */ static void freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) { struct proc *p; struct thread *td; struct fpreg32 fpregs; struct reg32 regs; struct sigacts *psp; struct sigframe32 sf, *sfp; int sig; int oonstack; unsigned i; td = curthread; p = td->td_proc; PROC_LOCK_ASSERT(p, MA_OWNED); sig = ksi->ksi_signo; psp = p->p_sigacts; mtx_assert(&psp->ps_mtx, MA_OWNED); fill_regs32(td, ®s); oonstack = sigonstack(td->td_frame->sp); /* save user context */ bzero(&sf, sizeof sf); sf.sf_uc.uc_sigmask = *mask; sf.sf_uc.uc_stack.ss_sp = (int32_t)(intptr_t)td->td_sigstk.ss_sp; sf.sf_uc.uc_stack.ss_size = td->td_sigstk.ss_size; sf.sf_uc.uc_stack.ss_flags = td->td_sigstk.ss_flags; sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; sf.sf_uc.uc_mcontext.mc_pc = regs.r_regs[PC]; sf.sf_uc.uc_mcontext.mullo = regs.r_regs[MULLO]; sf.sf_uc.uc_mcontext.mulhi = regs.r_regs[MULHI]; sf.sf_uc.uc_mcontext.mc_tls = (int32_t)(intptr_t)td->td_md.md_tls; sf.sf_uc.uc_mcontext.mc_regs[0] = UCONTEXT_MAGIC; /* magic number */ for (i = 1; i < 32; i++) sf.sf_uc.uc_mcontext.mc_regs[i] = regs.r_regs[i]; sf.sf_uc.uc_mcontext.mc_fpused = td->td_md.md_flags & MDTD_FPUSED; if (sf.sf_uc.uc_mcontext.mc_fpused) { /* if FPU has current state, save it first */ if (td == PCPU_GET(fpcurthread)) MipsSaveCurFPState(td); fill_fpregs32(td, &fpregs); for (i = 0; i < 33; i++) sf.sf_uc.uc_mcontext.mc_fpregs[i] = fpregs.r_regs[i]; } /* Allocate and validate space for the signal handler context. */ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { sfp = (struct sigframe32 *)(((uintptr_t)td->td_sigstk.ss_sp + td->td_sigstk.ss_size - sizeof(struct sigframe32)) & ~(sizeof(__int64_t) - 1)); } else sfp = (struct sigframe32 *)((vm_offset_t)(td->td_frame->sp - sizeof(struct sigframe32)) & ~(sizeof(__int64_t) - 1)); /* Build the argument list for the signal handler. */ td->td_frame->a0 = sig; td->td_frame->a2 = (register_t)(intptr_t)&sfp->sf_uc; if (SIGISMEMBER(psp->ps_siginfo, sig)) { /* Signal handler installed with SA_SIGINFO. */ td->td_frame->a1 = (register_t)(intptr_t)&sfp->sf_si; /* sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; */ /* fill siginfo structure */ sf.sf_si.si_signo = sig; sf.sf_si.si_code = ksi->ksi_code; sf.sf_si.si_addr = td->td_frame->badvaddr; } else { /* Old FreeBSD-style arguments. */ td->td_frame->a1 = ksi->ksi_code; td->td_frame->a3 = td->td_frame->badvaddr; /* sf.sf_ahu.sf_handler = catcher; */ } mtx_unlock(&psp->ps_mtx); PROC_UNLOCK(p); /* * Copy the sigframe out to the user's stack. */ if (copyout(&sf, sfp, sizeof(struct sigframe32)) != 0) { /* * Something is wrong with the stack pointer. * ...Kill the process. */ PROC_LOCK(p); sigexit(td, SIGILL); } td->td_frame->pc = (register_t)(intptr_t)catcher; td->td_frame->t9 = (register_t)(intptr_t)catcher; td->td_frame->sp = (register_t)(intptr_t)sfp; /* * Signal trampoline code is at base of user stack. */ td->td_frame->ra = (register_t)(intptr_t)FREEBSD32_PS_STRINGS - *(p->p_sysent->sv_szsigcode); PROC_LOCK(p); mtx_lock(&psp->ps_mtx); } int freebsd32_sysarch(struct thread *td, struct freebsd32_sysarch_args *uap) { int error; int32_t tlsbase; switch (uap->op) { case MIPS_SET_TLS: td->td_md.md_tls = (void *)(intptr_t)uap->parms; return (0); case MIPS_GET_TLS: tlsbase = (int32_t)(intptr_t)td->td_md.md_tls; error = copyout(&tlsbase, uap->parms, sizeof(tlsbase)); return (error); default: break; } return (EINVAL); } void elf32_dump_thread(struct thread *td __unused, void *dst __unused, size_t *off __unused) { } Index: head/sys/mips/mips/gdb_machdep.c =================================================================== --- head/sys/mips/mips/gdb_machdep.c (revision 326258) +++ head/sys/mips/mips/gdb_machdep.c (revision 326259) @@ -1,189 +1,191 @@ /* $NetBSD: kgdb_machdep.c,v 1.11 2005/12/24 22:45:35 perry Exp $ */ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-2-Clause-NetBSD + * * Copyright (c) 2004 Marcel Moolenaar * 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 AUTHORS ``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 AUTHORS 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. */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, * NASA Ames Research Center. * * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. */ /* * Copyright (c) 1996 Matthias Pfaller. * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Matthias Pfaller. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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. * * JNPR: gdb_machdep.c,v 1.1 2007/08/09 12:25:25 katta * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include void * gdb_cpu_getreg(int regnum, size_t *regsz) { *regsz = gdb_cpu_regsz(regnum); if (kdb_thread == curthread) { register_t *zero_ptr = &kdb_frame->zero; return zero_ptr + regnum; } switch (regnum) { /* * S0..S7 */ case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: return (&kdb_thrctx->pcb_context[PCB_REG_S0 + regnum - 16]); case 28: return (&kdb_thrctx->pcb_context[PCB_REG_GP]); case 29: return (&kdb_thrctx->pcb_context[PCB_REG_SP]); case 30: return (&kdb_thrctx->pcb_context[PCB_REG_S8]); case 31: return (&kdb_thrctx->pcb_context[PCB_REG_RA]); case 37: return (&kdb_thrctx->pcb_context[PCB_REG_PC]); } return (NULL); } void gdb_cpu_setreg(int regnum, void *val) { switch (regnum) { case GDB_REG_PC: kdb_thrctx->pcb_context[10] = *(register_t *)val; if (kdb_thread == curthread) kdb_frame->pc = *(register_t *)val; } } int gdb_cpu_signal(int entry, int code) { switch (entry) { case T_TLB_MOD: case T_TLB_MOD+T_USER: case T_TLB_LD_MISS: case T_TLB_ST_MISS: case T_TLB_LD_MISS+T_USER: case T_TLB_ST_MISS+T_USER: case T_ADDR_ERR_LD: /* misaligned access */ case T_ADDR_ERR_ST: /* misaligned access */ case T_BUS_ERR_LD_ST: /* BERR asserted to CPU */ case T_ADDR_ERR_LD+T_USER: /* misaligned or kseg access */ case T_ADDR_ERR_ST+T_USER: /* misaligned or kseg access */ case T_BUS_ERR_IFETCH+T_USER: /* BERR asserted to CPU */ case T_BUS_ERR_LD_ST+T_USER: /* BERR asserted to CPU */ return (SIGSEGV); case T_BREAK: case T_BREAK+T_USER: return (SIGTRAP); case T_RES_INST+T_USER: case T_COP_UNUSABLE+T_USER: return (SIGILL); case T_FPE+T_USER: case T_OVFLOW+T_USER: return (SIGFPE); default: return (SIGEMT); } } Index: head/sys/mips/mips/intr_machdep.c =================================================================== --- head/sys/mips/mips/intr_machdep.c (revision 326258) +++ head/sys/mips/mips/intr_machdep.c (revision 326259) @@ -1,278 +1,280 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006 Oleksandr Tymoshenko * Copyright (c) 2002-2004 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, * without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * 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 "opt_hwpmc_hooks.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static struct intr_event *hardintr_events[NHARD_IRQS]; static struct intr_event *softintr_events[NSOFT_IRQS]; static mips_intrcnt_t mips_intr_counters[NSOFT_IRQS + NHARD_IRQS]; static int intrcnt_index; static cpu_intr_mask_t hardintr_mask_func; static cpu_intr_unmask_t hardintr_unmask_func; mips_intrcnt_t mips_intrcnt_create(const char* name) { mips_intrcnt_t counter = &intrcnt[intrcnt_index++]; mips_intrcnt_setname(counter, name); return counter; } void mips_intrcnt_setname(mips_intrcnt_t counter, const char *name) { int idx = counter - intrcnt; KASSERT(counter != NULL, ("mips_intrcnt_setname: NULL counter")); snprintf(intrnames + (MAXCOMLEN + 1) * idx, MAXCOMLEN + 1, "%-*s", MAXCOMLEN, name); } static void mips_mask_hard_irq(void *source) { uintptr_t irq = (uintptr_t)source; mips_wr_status(mips_rd_status() & ~(((1 << irq) << 8) << 2)); } static void mips_unmask_hard_irq(void *source) { uintptr_t irq = (uintptr_t)source; mips_wr_status(mips_rd_status() | (((1 << irq) << 8) << 2)); } static void mips_mask_soft_irq(void *source) { uintptr_t irq = (uintptr_t)source; mips_wr_status(mips_rd_status() & ~((1 << irq) << 8)); } static void mips_unmask_soft_irq(void *source) { uintptr_t irq = (uintptr_t)source; mips_wr_status(mips_rd_status() | ((1 << irq) << 8)); } /* * Perform initialization of interrupts prior to setting * handlings */ void cpu_init_interrupts() { int i; char name[MAXCOMLEN + 1]; /* * Initialize all available vectors so spare IRQ * would show up in systat output */ for (i = 0; i < NSOFT_IRQS; i++) { snprintf(name, MAXCOMLEN + 1, "sint%d:", i); mips_intr_counters[i] = mips_intrcnt_create(name); } for (i = 0; i < NHARD_IRQS; i++) { snprintf(name, MAXCOMLEN + 1, "int%d:", i); mips_intr_counters[NSOFT_IRQS + i] = mips_intrcnt_create(name); } } void cpu_set_hardintr_mask_func(cpu_intr_mask_t func) { hardintr_mask_func = func; } void cpu_set_hardintr_unmask_func(cpu_intr_unmask_t func) { hardintr_unmask_func = func; } void cpu_establish_hardintr(const char *name, driver_filter_t *filt, void (*handler)(void*), void *arg, int irq, int flags, void **cookiep) { struct intr_event *event; int error; /* * We have 6 levels, but thats 0 - 5 (not including 6) */ if (irq < 0 || irq >= NHARD_IRQS) panic("%s called for unknown hard intr %d", __func__, irq); if (hardintr_mask_func == NULL) hardintr_mask_func = mips_mask_hard_irq; if (hardintr_unmask_func == NULL) hardintr_unmask_func = mips_unmask_hard_irq; event = hardintr_events[irq]; if (event == NULL) { error = intr_event_create(&event, (void *)(uintptr_t)irq, 0, irq, hardintr_mask_func, hardintr_unmask_func, NULL, NULL, "int%d", irq); if (error) return; hardintr_events[irq] = event; mips_unmask_hard_irq((void*)(uintptr_t)irq); } intr_event_add_handler(event, name, filt, handler, arg, intr_priority(flags), flags, cookiep); mips_intrcnt_setname(mips_intr_counters[NSOFT_IRQS + irq], event->ie_fullname); } void cpu_establish_softintr(const char *name, driver_filter_t *filt, void (*handler)(void*), void *arg, int irq, int flags, void **cookiep) { struct intr_event *event; int error; #if 0 printf("Establish SOFT IRQ %d: filt %p handler %p arg %p\n", irq, filt, handler, arg); #endif if (irq < 0 || irq > NSOFT_IRQS) panic("%s called for unknown hard intr %d", __func__, irq); event = softintr_events[irq]; if (event == NULL) { error = intr_event_create(&event, (void *)(uintptr_t)irq, 0, irq, mips_mask_soft_irq, mips_unmask_soft_irq, NULL, NULL, "sint%d:", irq); if (error) return; softintr_events[irq] = event; mips_unmask_soft_irq((void*)(uintptr_t)irq); } intr_event_add_handler(event, name, filt, handler, arg, intr_priority(flags), flags, cookiep); mips_intrcnt_setname(mips_intr_counters[irq], event->ie_fullname); } void cpu_intr(struct trapframe *tf) { struct intr_event *event; register_t cause, status; int hard, i, intr; critical_enter(); cause = mips_rd_cause(); status = mips_rd_status(); intr = (cause & MIPS_INT_MASK) >> 8; /* * Do not handle masked interrupts. They were masked by * pre_ithread function (mips_mask_XXX_intr) and will be * unmasked once ithread is through with handler */ intr &= (status & MIPS_INT_MASK) >> 8; while ((i = fls(intr)) != 0) { intr &= ~(1 << (i - 1)); switch (i) { case 1: case 2: /* Software interrupt. */ i--; /* Get a 0-offset interrupt. */ hard = 0; event = softintr_events[i]; mips_intrcnt_inc(mips_intr_counters[i]); break; default: /* Hardware interrupt. */ i -= 2; /* Trim software interrupt bits. */ i--; /* Get a 0-offset interrupt. */ hard = 1; event = hardintr_events[i]; mips_intrcnt_inc(mips_intr_counters[NSOFT_IRQS + i]); break; } if (!event || TAILQ_EMPTY(&event->ie_handlers)) { printf("stray %s interrupt %d\n", hard ? "hard" : "soft", i); continue; } if (intr_event_handle(event, tf) != 0) { printf("stray %s interrupt %d\n", hard ? "hard" : "soft", i); } } KASSERT(i == 0, ("all interrupts handled")); critical_exit(); #ifdef HWPMC_HOOKS if (pmc_hook && (PCPU_GET(curthread)->td_pflags & TDP_CALLCHAIN)) pmc_hook(PCPU_GET(curthread), PMC_FN_USER_CALLCHAIN, tf); #endif } Index: head/sys/mips/mips/libkern_machdep.c =================================================================== --- head/sys/mips/mips/libkern_machdep.c (revision 326258) +++ head/sys/mips/mips/libkern_machdep.c (revision 326259) @@ -1,39 +1,41 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2012 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 libkern support routines for 64-bit operations when building o32 * kernels. */ #if defined(__mips_o32) #include #include #include #include #include #endif Index: head/sys/mips/mips/minidump_machdep.c =================================================================== --- head/sys/mips/mips/minidump_machdep.c (revision 326258) +++ head/sys/mips/mips/minidump_machdep.c (revision 326259) @@ -1,354 +1,356 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Oleksandr Tymoshenko * Copyright (c) 2008 Semihalf, Grzegorz Bernacki * 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 ``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 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. * * from: FreeBSD: src/sys/arm/arm/minidump_machdep.c v214223 */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include CTASSERT(sizeof(struct kerneldumpheader) == 512); uint32_t *vm_page_dump; int vm_page_dump_size; static struct kerneldumpheader kdh; /* Handle chunked writes. */ static uint64_t counter, progress, dumpsize; /* Just auxiliary bufffer */ static char tmpbuffer[PAGE_SIZE]; extern pd_entry_t *kernel_segmap; CTASSERT(sizeof(*vm_page_dump) == 4); static int is_dumpable(vm_paddr_t pa) { vm_page_t m; int i; if ((m = vm_phys_paddr_to_vm_page(pa)) != NULL) return ((m->flags & PG_NODUMP) == 0); for (i = 0; dump_avail[i] != 0 || dump_avail[i + 1] != 0; i += 2) { if (pa >= dump_avail[i] && pa < dump_avail[i + 1]) return (1); } return (0); } void dump_add_page(vm_paddr_t pa) { int idx, bit; pa >>= PAGE_SHIFT; idx = pa >> 5; /* 2^5 = 32 */ bit = pa & 31; atomic_set_int(&vm_page_dump[idx], 1ul << bit); } void dump_drop_page(vm_paddr_t pa) { int idx, bit; pa >>= PAGE_SHIFT; idx = pa >> 5; /* 2^5 = 32 */ bit = pa & 31; atomic_clear_int(&vm_page_dump[idx], 1ul << bit); } static struct { int min_per; int max_per; int visited; } progress_track[10] = { { 0, 10, 0}, { 10, 20, 0}, { 20, 30, 0}, { 30, 40, 0}, { 40, 50, 0}, { 50, 60, 0}, { 60, 70, 0}, { 70, 80, 0}, { 80, 90, 0}, { 90, 100, 0} }; static void report_progress(uint64_t progress, uint64_t dumpsize) { int sofar, i; sofar = 100 - ((progress * 100) / dumpsize); for (i = 0; i < nitems(progress_track); i++) { if (sofar < progress_track[i].min_per || sofar > progress_track[i].max_per) continue; if (progress_track[i].visited) return; progress_track[i].visited = 1; printf("..%d%%", sofar); return; } } static int write_buffer(struct dumperinfo *di, char *ptr, size_t sz) { size_t len; int error, c; u_int maxdumpsz; maxdumpsz = di->maxiosize; if (maxdumpsz == 0) /* seatbelt */ maxdumpsz = PAGE_SIZE; error = 0; while (sz) { len = min(maxdumpsz, sz); counter += len; progress -= len; if (counter >> 22) { report_progress(progress, dumpsize); counter &= (1<<22) - 1; } wdog_kern_pat(WD_LASTVAL); if (ptr) { error = dump_append(di, ptr, 0, len); if (error) return (error); ptr += len; sz -= len; } else { panic("pa is not supported"); } /* Check for user abort. */ c = cncheckc(); if (c == 0x03) return (ECANCELED); if (c != -1) printf(" (CTRL-C to abort) "); } return (0); } int minidumpsys(struct dumperinfo *di) { struct minidumphdr mdhdr; uint32_t ptesize; uint32_t bits; vm_paddr_t pa; vm_offset_t prev_pte = 0; uint32_t count = 0; vm_offset_t va; pt_entry_t *pte; int i, bit, error; void *dump_va; /* Flush cache */ mips_dcache_wbinv_all(); counter = 0; /* Walk page table pages, set bits in vm_page_dump */ ptesize = 0; for (va = VM_MIN_KERNEL_ADDRESS; va < kernel_vm_end; va += NBPDR) { ptesize += PAGE_SIZE; pte = pmap_pte(kernel_pmap, va); KASSERT(pte != NULL, ("pte for %jx is NULL", (uintmax_t)va)); for (i = 0; i < NPTEPG; i++) { if (pte_test(&pte[i], PTE_V)) { pa = TLBLO_PTE_TO_PA(pte[i]); if (is_dumpable(pa)) dump_add_page(pa); } } } /* * Now mark pages from 0 to phys_avail[0], that's where kernel * and pages allocated by pmap_steal reside */ for (pa = 0; pa < phys_avail[0]; pa += PAGE_SIZE) { if (is_dumpable(pa)) dump_add_page(pa); } /* Calculate dump size. */ dumpsize = ptesize; dumpsize += round_page(msgbufp->msg_size); dumpsize += round_page(vm_page_dump_size); for (i = 0; i < vm_page_dump_size / sizeof(*vm_page_dump); i++) { bits = vm_page_dump[i]; while (bits) { bit = ffs(bits) - 1; pa = (((uint64_t)i * sizeof(*vm_page_dump) * NBBY) + bit) * PAGE_SIZE; /* Clear out undumpable pages now if needed */ if (is_dumpable(pa)) dumpsize += PAGE_SIZE; else dump_drop_page(pa); bits &= ~(1ul << bit); } } dumpsize += PAGE_SIZE; progress = dumpsize; /* Initialize mdhdr */ bzero(&mdhdr, sizeof(mdhdr)); strcpy(mdhdr.magic, MINIDUMP_MAGIC); mdhdr.version = MINIDUMP_VERSION; mdhdr.msgbufsize = msgbufp->msg_size; mdhdr.bitmapsize = vm_page_dump_size; mdhdr.ptesize = ptesize; mdhdr.kernbase = VM_MIN_KERNEL_ADDRESS; dump_init_header(di, &kdh, KERNELDUMPMAGIC, KERNELDUMP_MIPS_VERSION, dumpsize); printf("Dumping %llu out of %ju MB:", (long long)dumpsize >> 20, ptoa((uintmax_t)physmem) / 1048576); error = dump_start(di, &kdh); if (error != 0) goto fail; /* Dump my header */ bzero(tmpbuffer, sizeof(tmpbuffer)); bcopy(&mdhdr, tmpbuffer, sizeof(mdhdr)); error = write_buffer(di, tmpbuffer, PAGE_SIZE); if (error) goto fail; /* Dump msgbuf up front */ error = write_buffer(di, (char *)msgbufp->msg_ptr, round_page(msgbufp->msg_size)); if (error) goto fail; /* Dump bitmap */ error = write_buffer(di, (char *)vm_page_dump, round_page(vm_page_dump_size)); if (error) goto fail; /* Dump kernel page table pages */ for (va = VM_MIN_KERNEL_ADDRESS; va < kernel_vm_end; va += NBPDR) { pte = pmap_pte(kernel_pmap, va); KASSERT(pte != NULL, ("pte for %jx is NULL", (uintmax_t)va)); if (!count) { prev_pte = (vm_offset_t)pte; count++; } else { if ((vm_offset_t)pte == (prev_pte + count * PAGE_SIZE)) count++; else { error = write_buffer(di, (char*)prev_pte, count * PAGE_SIZE); if (error) goto fail; count = 1; prev_pte = (vm_offset_t)pte; } } } if (count) { error = write_buffer(di, (char*)prev_pte, count * PAGE_SIZE); if (error) goto fail; count = 0; prev_pte = 0; } /* Dump memory chunks page by page*/ for (i = 0; i < vm_page_dump_size / sizeof(*vm_page_dump); i++) { bits = vm_page_dump[i]; while (bits) { bit = ffs(bits) - 1; pa = (((uint64_t)i * sizeof(*vm_page_dump) * NBBY) + bit) * PAGE_SIZE; dump_va = pmap_kenter_temporary(pa, 0); error = write_buffer(di, dump_va, PAGE_SIZE); if (error) goto fail; pmap_kenter_temporary_free(pa); bits &= ~(1ul << bit); } } error = dump_finish(di, &kdh); if (error != 0) goto fail; printf("\nDump complete\n"); return (0); fail: if (error < 0) error = -error; if (error == ECANCELED) printf("\nDump aborted\n"); else if (error == E2BIG || error == ENOSPC) printf("\nDump failed. Partition too small.\n"); else printf("\n** DUMP FAILED (ERROR %d) **\n", error); return (error); } Index: head/sys/mips/mips/mp_machdep.c =================================================================== --- head/sys/mips/mips/mp_machdep.c (revision 326258) +++ head/sys/mips/mips/mp_machdep.c (revision 326259) @@ -1,364 +1,366 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009 Neelkanth Natu * 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 #include #include #include #include #include #include struct pcb stoppcbs[MAXCPU]; static void *dpcpu; static struct mtx ap_boot_mtx; static volatile int aps_ready; static volatile int mp_naps; static void ipi_send(struct pcpu *pc, int ipi) { CTR3(KTR_SMP, "%s: cpu=%d, ipi=%x", __func__, pc->pc_cpuid, ipi); atomic_set_32(&pc->pc_pending_ipis, ipi); platform_ipi_send(pc->pc_cpuid); CTR1(KTR_SMP, "%s: sent", __func__); } void ipi_all_but_self(int ipi) { cpuset_t other_cpus; other_cpus = all_cpus; CPU_CLR(PCPU_GET(cpuid), &other_cpus); ipi_selected(other_cpus, ipi); } /* Send an IPI to a set of cpus. */ void ipi_selected(cpuset_t cpus, int ipi) { struct pcpu *pc; STAILQ_FOREACH(pc, &cpuhead, pc_allcpu) { if (CPU_ISSET(pc->pc_cpuid, &cpus)) { CTR3(KTR_SMP, "%s: pc: %p, ipi: %x\n", __func__, pc, ipi); ipi_send(pc, ipi); } } } /* Send an IPI to a specific CPU. */ void ipi_cpu(int cpu, u_int ipi) { CTR3(KTR_SMP, "%s: cpu: %d, ipi: %x\n", __func__, cpu, ipi); ipi_send(cpuid_to_pcpu[cpu], ipi); } /* * Handle an IPI sent to this processor. */ static int mips_ipi_handler(void *arg) { u_int cpu, ipi, ipi_bitmap; int bit; cpu = PCPU_GET(cpuid); platform_ipi_clear(); /* quiesce the pending ipi interrupt */ ipi_bitmap = atomic_readandclear_int(PCPU_PTR(pending_ipis)); if (ipi_bitmap == 0) return (FILTER_STRAY); CTR1(KTR_SMP, "smp_handle_ipi(), ipi_bitmap=%x", ipi_bitmap); while ((bit = ffs(ipi_bitmap))) { bit = bit - 1; ipi = 1 << bit; ipi_bitmap &= ~ipi; switch (ipi) { case IPI_RENDEZVOUS: CTR0(KTR_SMP, "IPI_RENDEZVOUS"); smp_rendezvous_action(); break; case IPI_AST: CTR0(KTR_SMP, "IPI_AST"); break; case IPI_STOP: /* * IPI_STOP_HARD is mapped to IPI_STOP so it is not * necessary to add it in the switch. */ CTR0(KTR_SMP, "IPI_STOP or IPI_STOP_HARD"); savectx(&stoppcbs[cpu]); tlb_save(); /* Indicate we are stopped */ CPU_SET_ATOMIC(cpu, &stopped_cpus); /* Wait for restart */ while (!CPU_ISSET(cpu, &started_cpus)) cpu_spinwait(); CPU_CLR_ATOMIC(cpu, &started_cpus); CPU_CLR_ATOMIC(cpu, &stopped_cpus); CTR0(KTR_SMP, "IPI_STOP (restart)"); break; case IPI_PREEMPT: CTR1(KTR_SMP, "%s: IPI_PREEMPT", __func__); sched_preempt(curthread); break; case IPI_HARDCLOCK: CTR1(KTR_SMP, "%s: IPI_HARDCLOCK", __func__); hardclockintr(); break; default: panic("Unknown IPI 0x%0x on cpu %d", ipi, curcpu); } } return (FILTER_HANDLED); } static int start_ap(int cpuid) { int cpus, ms; cpus = mp_naps; dpcpu = (void *)kmem_malloc(kernel_arena, DPCPU_SIZE, M_WAITOK | M_ZERO); mips_sync(); if (platform_start_ap(cpuid) != 0) return (-1); /* could not start AP */ for (ms = 0; ms < 5000; ++ms) { if (mp_naps > cpus) return (0); /* success */ else DELAY(1000); } return (-2); /* timeout initializing AP */ } void cpu_mp_setmaxid(void) { cpuset_t cpumask; int cpu, last; platform_cpu_mask(&cpumask); mp_ncpus = 0; last = 1; while ((cpu = CPU_FFS(&cpumask)) != 0) { last = cpu; cpu--; CPU_CLR(cpu, &cpumask); mp_ncpus++; } if (mp_ncpus <= 0) mp_ncpus = 1; mp_maxid = min(last, MAXCPU) - 1; } void cpu_mp_announce(void) { /* NOTHING */ } struct cpu_group * cpu_topo(void) { return (platform_smp_topo()); } int cpu_mp_probe(void) { return (mp_ncpus > 1); } void cpu_mp_start(void) { int error, cpuid; cpuset_t cpumask; mtx_init(&ap_boot_mtx, "ap boot", NULL, MTX_SPIN); CPU_ZERO(&all_cpus); platform_cpu_mask(&cpumask); while (!CPU_EMPTY(&cpumask)) { cpuid = CPU_FFS(&cpumask) - 1; CPU_CLR(cpuid, &cpumask); if (cpuid >= MAXCPU) { printf("cpu_mp_start: ignoring AP #%d.\n", cpuid); continue; } if (cpuid != platform_processor_id()) { if ((error = start_ap(cpuid)) != 0) { printf("AP #%d failed to start: %d\n", cpuid, error); continue; } if (bootverbose) printf("AP #%d started!\n", cpuid); } CPU_SET(cpuid, &all_cpus); } } void smp_init_secondary(u_int32_t cpuid) { /* TLB */ mips_wr_wired(0); tlb_invalidate_all(); mips_wr_wired(VMWIRED_ENTRIES); /* * We assume that the L1 cache on the APs is identical to the one * on the BSP. */ mips_dcache_wbinv_all(); mips_icache_sync_all(); mips_sync(); mips_wr_entryhi(0); pcpu_init(PCPU_ADDR(cpuid), cpuid, sizeof(struct pcpu)); dpcpu_init(dpcpu, cpuid); /* The AP has initialized successfully - allow the BSP to proceed */ ++mp_naps; /* Spin until the BSP is ready to release the APs */ while (!aps_ready) ; /* Initialize curthread. */ KASSERT(PCPU_GET(idlethread) != NULL, ("no idle thread")); PCPU_SET(curthread, PCPU_GET(idlethread)); mtx_lock_spin(&ap_boot_mtx); smp_cpus++; CTR1(KTR_SMP, "SMP: AP CPU #%d launched", PCPU_GET(cpuid)); if (bootverbose) printf("SMP: AP CPU #%d launched.\n", PCPU_GET(cpuid)); if (smp_cpus == mp_ncpus) { atomic_store_rel_int(&smp_started, 1); } mtx_unlock_spin(&ap_boot_mtx); while (smp_started == 0) ; /* nothing */ /* Start per-CPU event timers. */ cpu_initclocks_ap(); /* enter the scheduler */ sched_throw(NULL); panic("scheduler returned us to %s", __func__); /* NOTREACHED */ } static void release_aps(void *dummy __unused) { int ipi_irq; if (mp_ncpus == 1) return; /* * IPI handler */ ipi_irq = platform_ipi_hardintr_num(); if (ipi_irq != -1) { cpu_establish_hardintr("ipi", mips_ipi_handler, NULL, NULL, ipi_irq, INTR_TYPE_MISC | INTR_EXCL, NULL); } else { ipi_irq = platform_ipi_softintr_num(); cpu_establish_softintr("ipi", mips_ipi_handler, NULL, NULL, ipi_irq, INTR_TYPE_MISC | INTR_EXCL, NULL); } atomic_store_rel_int(&aps_ready, 1); while (smp_started == 0) ; /* nothing */ } SYSINIT(start_aps, SI_SUB_SMP, SI_ORDER_FIRST, release_aps, NULL); Index: head/sys/mips/mips/octeon_cop2.c =================================================================== --- head/sys/mips/mips/octeon_cop2.c (revision 326258) +++ head/sys/mips/mips/octeon_cop2.c (revision 326259) @@ -1,62 +1,64 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2011, Oleksandr Tymoshenko * 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 unmodified, 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 static uma_zone_t ctxzone; static void octeon_cop2_init(void* dummy) { printf("Create COP2 context zone\n"); ctxzone = uma_zcreate("COP2 context", sizeof(struct octeon_cop2_state), NULL, NULL, NULL, NULL, 8, 0); } struct octeon_cop2_state * octeon_cop2_alloc_ctx() { return uma_zalloc(ctxzone, M_NOWAIT); } void octeon_cop2_free_ctx(struct octeon_cop2_state *ctx) { uma_zfree(ctxzone, ctx); } SYSINIT(octeon_cop2, SI_SUB_CPU, SI_ORDER_FIRST, octeon_cop2_init, NULL); Index: head/sys/mips/mips/ptrace_machdep.c =================================================================== --- head/sys/mips/mips/ptrace_machdep.c (revision 326258) +++ head/sys/mips/mips/ptrace_machdep.c (revision 326259) @@ -1,37 +1,39 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009 M. Warner Losh. * 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. * */ #if 0 #include __FBSDID("$FreeBSD$"); /* * This file is a place holder for MIPS. Some models of MIPS may need special * functions here, but for now nothing is needed. The MI parts of ptrace * suffice. */ #endif Index: head/sys/mips/mips/sc_machdep.c =================================================================== --- head/sys/mips/mips/sc_machdep.c (revision 326258) +++ head/sys/mips/mips/sc_machdep.c (revision 326259) @@ -1,87 +1,89 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003 Jake Burkholder. * 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 static sc_softc_t sc_softcs[8]; int sc_get_cons_priority(int *unit, int *flags) { *unit = 0; *flags = 0; return (CN_INTERNAL); } int sc_max_unit(void) { return (1); } sc_softc_t * sc_get_softc(int unit, int flags) { sc_softc_t *sc; if (unit < 0) return (NULL); sc = &sc_softcs[unit]; sc->unit = unit; if ((sc->flags & SC_INIT_DONE) == 0) { sc->keyboard = -1; sc->adapter = -1; sc->cursor_char = SC_CURSOR_CHAR; sc->mouse_char = SC_MOUSE_CHAR; } return (sc); } void sc_get_bios_values(bios_values_t *values) { } int sc_tone(int hz) { return (0); } Index: head/sys/mips/mips/stack_machdep.c =================================================================== --- head/sys/mips/mips/stack_machdep.c (revision 326258) +++ head/sys/mips/mips/stack_machdep.c (revision 326259) @@ -1,161 +1,163 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2005 Antoine Brodin * 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 static u_register_t stack_register_fetch(u_register_t sp, u_register_t stack_pos) { u_register_t * stack = ((u_register_t *)(intptr_t)sp + (size_t)stack_pos/sizeof(u_register_t)); return *stack; } static void stack_capture(struct stack *st, u_register_t pc, u_register_t sp) { u_register_t ra = 0, i, stacksize; short ra_stack_pos = 0; InstFmt insn; stack_zero(st); for (;;) { stacksize = 0; if (pc <= (u_register_t)(intptr_t)btext) break; for (i = pc; i >= (u_register_t)(intptr_t)btext; i -= sizeof (insn)) { bcopy((void *)(intptr_t)i, &insn, sizeof insn); switch (insn.IType.op) { case OP_ADDI: case OP_ADDIU: case OP_DADDI: case OP_DADDIU: if (insn.IType.rs != SP || insn.IType.rt != SP) break; stacksize = -(short)insn.IType.imm; break; case OP_SW: case OP_SD: if (insn.IType.rs != SP || insn.IType.rt != RA) break; ra_stack_pos = (short)insn.IType.imm; break; default: break; } if (stacksize) break; } if (stack_put(st, pc) == -1) break; for (i = pc; !ra; i += sizeof (insn)) { bcopy((void *)(intptr_t)i, &insn, sizeof insn); switch (insn.IType.op) { case OP_SPECIAL: if (insn.RType.func == OP_JR) { if (ra >= (u_register_t)(intptr_t)btext) break; if (insn.RType.rs != RA) break; ra = stack_register_fetch(sp, ra_stack_pos); if (!ra) goto done; ra -= 8; } break; default: break; } /* eret */ if (insn.word == 0x42000018) goto done; } if (pc == ra && stacksize == 0) break; sp += stacksize; pc = ra; ra = 0; } done: return; } void stack_save_td(struct stack *st, struct thread *td) { u_register_t pc, sp; if (TD_IS_SWAPPED(td)) panic("stack_save_td: swapped"); if (TD_IS_RUNNING(td)) panic("stack_save_td: running"); pc = td->td_pcb->pcb_regs.pc; sp = td->td_pcb->pcb_regs.sp; stack_capture(st, pc, sp); } int stack_save_td_running(struct stack *st, struct thread *td) { return (EOPNOTSUPP); } void stack_save(struct stack *st) { u_register_t pc, sp; if (curthread == NULL) panic("stack_save: curthread == NULL"); pc = curthread->td_pcb->pcb_regs.pc; sp = curthread->td_pcb->pcb_regs.sp; stack_capture(st, pc, sp); } Index: head/sys/mips/mips/stdatomic.c =================================================================== --- head/sys/mips/mips/stdatomic.c (revision 326258) +++ head/sys/mips/mips/stdatomic.c (revision 326259) @@ -1,413 +1,415 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2013 Ed Schouten * All rights reserved. * * Copyright (c) 1998 Doug Rabson * 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 #ifndef _KERNEL #include #endif /* _KERNEL */ #if defined(__SYNC_ATOMICS) /* * Memory barriers. * * It turns out __sync_synchronize() does not emit any code when used * with GCC 4.2. Implement our own version that does work reliably. * * Although __sync_lock_test_and_set() should only perform an acquire * barrier, make it do a full barrier like the other functions. This * should make 's atomic_exchange_explicit() work reliably. */ static inline void do_sync(void) { __asm volatile ( #if !defined(_KERNEL) || defined(SMP) ".set noreorder\n" "\tsync\n" "\tnop\n" "\tnop\n" "\tnop\n" "\tnop\n" "\tnop\n" "\tnop\n" "\tnop\n" "\tnop\n" ".set reorder\n" #else /* _KERNEL && !SMP */ "" #endif /* !KERNEL || SMP */ : : : "memory"); } typedef union { uint8_t v8[4]; uint32_t v32; } reg_t; /* * Given a memory address pointing to an 8-bit or 16-bit integer, return * the address of the 32-bit word containing it. */ static inline uint32_t * round_to_word(void *ptr) { return ((uint32_t *)((intptr_t)ptr & ~3)); } /* * Utility functions for loading and storing 8-bit and 16-bit integers * in 32-bit words at an offset corresponding with the location of the * atomic variable. */ static inline void put_1(reg_t *r, const uint8_t *offset_ptr, uint8_t val) { size_t offset; offset = (intptr_t)offset_ptr & 3; r->v8[offset] = val; } static inline uint8_t get_1(const reg_t *r, const uint8_t *offset_ptr) { size_t offset; offset = (intptr_t)offset_ptr & 3; return (r->v8[offset]); } static inline void put_2(reg_t *r, const uint16_t *offset_ptr, uint16_t val) { size_t offset; union { uint16_t in; uint8_t out[2]; } bytes; offset = (intptr_t)offset_ptr & 3; bytes.in = val; r->v8[offset] = bytes.out[0]; r->v8[offset + 1] = bytes.out[1]; } static inline uint16_t get_2(const reg_t *r, const uint16_t *offset_ptr) { size_t offset; union { uint8_t in[2]; uint16_t out; } bytes; offset = (intptr_t)offset_ptr & 3; bytes.in[0] = r->v8[offset]; bytes.in[1] = r->v8[offset + 1]; return (bytes.out); } /* * 8-bit and 16-bit routines. * * These operations are not natively supported by the CPU, so we use * some shifting and bitmasking on top of the 32-bit instructions. */ #define EMIT_LOCK_TEST_AND_SET_N(N, uintN_t) \ uintN_t \ __sync_lock_test_and_set_##N(uintN_t *mem, uintN_t val) \ { \ uint32_t *mem32; \ reg_t val32, negmask, old; \ uint32_t temp; \ \ mem32 = round_to_word(mem); \ val32.v32 = 0x00000000; \ put_##N(&val32, mem, val); \ negmask.v32 = 0xffffffff; \ put_##N(&negmask, mem, 0); \ \ do_sync(); \ __asm volatile ( \ "1:" \ "\tll %0, %5\n" /* Load old value. */ \ "\tand %2, %4, %0\n" /* Remove the old value. */ \ "\tor %2, %3\n" /* Put in the new value. */ \ "\tsc %2, %1\n" /* Attempt to store. */ \ "\tbeqz %2, 1b\n" /* Spin if failed. */ \ : "=&r" (old.v32), "=m" (*mem32), "=&r" (temp) \ : "r" (val32.v32), "r" (negmask.v32), "m" (*mem32)); \ return (get_##N(&old, mem)); \ } EMIT_LOCK_TEST_AND_SET_N(1, uint8_t) EMIT_LOCK_TEST_AND_SET_N(2, uint16_t) #define EMIT_VAL_COMPARE_AND_SWAP_N(N, uintN_t) \ uintN_t \ __sync_val_compare_and_swap_##N(uintN_t *mem, uintN_t expected, \ uintN_t desired) \ { \ uint32_t *mem32; \ reg_t expected32, desired32, posmask, old; \ uint32_t negmask, temp; \ \ mem32 = round_to_word(mem); \ expected32.v32 = 0x00000000; \ put_##N(&expected32, mem, expected); \ desired32.v32 = 0x00000000; \ put_##N(&desired32, mem, desired); \ posmask.v32 = 0x00000000; \ put_##N(&posmask, mem, ~0); \ negmask = ~posmask.v32; \ \ do_sync(); \ __asm volatile ( \ "1:" \ "\tll %0, %7\n" /* Load old value. */ \ "\tand %2, %5, %0\n" /* Isolate the old value. */ \ "\tbne %2, %3, 2f\n" /* Compare to expected value. */\ "\tand %2, %6, %0\n" /* Remove the old value. */ \ "\tor %2, %4\n" /* Put in the new value. */ \ "\tsc %2, %1\n" /* Attempt to store. */ \ "\tbeqz %2, 1b\n" /* Spin if failed. */ \ "2:" \ : "=&r" (old), "=m" (*mem32), "=&r" (temp) \ : "r" (expected32.v32), "r" (desired32.v32), \ "r" (posmask.v32), "r" (negmask), "m" (*mem32)); \ return (get_##N(&old, mem)); \ } EMIT_VAL_COMPARE_AND_SWAP_N(1, uint8_t) EMIT_VAL_COMPARE_AND_SWAP_N(2, uint16_t) #define EMIT_ARITHMETIC_FETCH_AND_OP_N(N, uintN_t, name, op) \ uintN_t \ __sync_##name##_##N(uintN_t *mem, uintN_t val) \ { \ uint32_t *mem32; \ reg_t val32, posmask, old; \ uint32_t negmask, temp1, temp2; \ \ mem32 = round_to_word(mem); \ val32.v32 = 0x00000000; \ put_##N(&val32, mem, val); \ posmask.v32 = 0x00000000; \ put_##N(&posmask, mem, ~0); \ negmask = ~posmask.v32; \ \ do_sync(); \ __asm volatile ( \ "1:" \ "\tll %0, %7\n" /* Load old value. */ \ "\t"op" %2, %0, %4\n" /* Calculate new value. */ \ "\tand %2, %5\n" /* Isolate the new value. */ \ "\tand %3, %6, %0\n" /* Remove the old value. */ \ "\tor %2, %3\n" /* Put in the new value. */ \ "\tsc %2, %1\n" /* Attempt to store. */ \ "\tbeqz %2, 1b\n" /* Spin if failed. */ \ : "=&r" (old.v32), "=m" (*mem32), "=&r" (temp1), \ "=&r" (temp2) \ : "r" (val32.v32), "r" (posmask.v32), "r" (negmask), \ "m" (*mem32)); \ return (get_##N(&old, mem)); \ } EMIT_ARITHMETIC_FETCH_AND_OP_N(1, uint8_t, fetch_and_add, "addu") EMIT_ARITHMETIC_FETCH_AND_OP_N(1, uint8_t, fetch_and_sub, "subu") EMIT_ARITHMETIC_FETCH_AND_OP_N(2, uint16_t, fetch_and_add, "addu") EMIT_ARITHMETIC_FETCH_AND_OP_N(2, uint16_t, fetch_and_sub, "subu") #define EMIT_BITWISE_FETCH_AND_OP_N(N, uintN_t, name, op, idempotence) \ uintN_t \ __sync_##name##_##N(uintN_t *mem, uintN_t val) \ { \ uint32_t *mem32; \ reg_t val32, old; \ uint32_t temp; \ \ mem32 = round_to_word(mem); \ val32.v32 = idempotence ? 0xffffffff : 0x00000000; \ put_##N(&val32, mem, val); \ \ do_sync(); \ __asm volatile ( \ "1:" \ "\tll %0, %4\n" /* Load old value. */ \ "\t"op" %2, %3, %0\n" /* Calculate new value. */ \ "\tsc %2, %1\n" /* Attempt to store. */ \ "\tbeqz %2, 1b\n" /* Spin if failed. */ \ : "=&r" (old.v32), "=m" (*mem32), "=&r" (temp) \ : "r" (val32.v32), "m" (*mem32)); \ return (get_##N(&old, mem)); \ } EMIT_BITWISE_FETCH_AND_OP_N(1, uint8_t, fetch_and_and, "and", 1) EMIT_BITWISE_FETCH_AND_OP_N(1, uint8_t, fetch_and_or, "or", 0) EMIT_BITWISE_FETCH_AND_OP_N(1, uint8_t, fetch_and_xor, "xor", 0) EMIT_BITWISE_FETCH_AND_OP_N(2, uint16_t, fetch_and_and, "and", 1) EMIT_BITWISE_FETCH_AND_OP_N(2, uint16_t, fetch_and_or, "or", 0) EMIT_BITWISE_FETCH_AND_OP_N(2, uint16_t, fetch_and_xor, "xor", 0) /* * 32-bit routines. */ static __inline uint32_t do_compare_and_swap_4(uint32_t *mem, uint32_t expected, uint32_t desired) { uint32_t old, temp; do_sync(); __asm volatile ( "1:" "\tll %0, %5\n" /* Load old value. */ "\tbne %0, %3, 2f\n" /* Compare to expected value. */ "\tmove %2, %4\n" /* Value to store. */ "\tsc %2, %1\n" /* Attempt to store. */ "\tbeqz %2, 1b\n" /* Spin if failed. */ "2:" : "=&r" (old), "=m" (*mem), "=&r" (temp) : "r" (expected), "r" (desired), "m" (*mem)); return (old); } uint32_t __sync_val_compare_and_swap_4(uint32_t *mem, uint32_t expected, uint32_t desired) { return (do_compare_and_swap_4(mem, expected, desired)); } bool __sync_bool_compare_and_swap_4(uint32_t *mem, uint32_t expected, uint32_t desired) { return (do_compare_and_swap_4(mem, expected, desired) == desired); } #define EMIT_FETCH_AND_OP_4(name, op) \ uint32_t \ __sync_##name##_4(uint32_t *mem, uint32_t val) \ { \ uint32_t old, temp; \ \ do_sync(); \ __asm volatile ( \ "1:" \ "\tll %0, %4\n" /* Load old value. */ \ "\t"op"\n" /* Calculate new value. */ \ "\tsc %2, %1\n" /* Attempt to store. */ \ "\tbeqz %2, 1b\n" /* Spin if failed. */ \ : "=&r" (old), "=m" (*mem), "=&r" (temp) \ : "r" (val), "m" (*mem)); \ return (old); \ } EMIT_FETCH_AND_OP_4(lock_test_and_set, "move %2, %3") EMIT_FETCH_AND_OP_4(fetch_and_add, "addu %2, %0, %3") EMIT_FETCH_AND_OP_4(fetch_and_and, "and %2, %0, %3") EMIT_FETCH_AND_OP_4(fetch_and_or, "or %2, %0, %3") EMIT_FETCH_AND_OP_4(fetch_and_sub, "subu %2, %0, %3") EMIT_FETCH_AND_OP_4(fetch_and_xor, "xor %2, %0, %3") /* * 64-bit routines. * * Note: All the 64-bit atomic operations are only atomic when running * in 64-bit mode. It is assumed that code compiled for n32 and n64 fits * into this definition and no further safeties are needed. */ #if defined(__mips_n32) || defined(__mips_n64) uint64_t __sync_val_compare_and_swap_8(uint64_t *mem, uint64_t expected, uint64_t desired) { uint64_t old, temp; do_sync(); __asm volatile ( "1:" "\tlld %0, %5\n" /* Load old value. */ "\tbne %0, %3, 2f\n" /* Compare to expected value. */ "\tmove %2, %4\n" /* Value to store. */ "\tscd %2, %1\n" /* Attempt to store. */ "\tbeqz %2, 1b\n" /* Spin if failed. */ "2:" : "=&r" (old), "=m" (*mem), "=&r" (temp) : "r" (expected), "r" (desired), "m" (*mem)); return (old); } #define EMIT_FETCH_AND_OP_8(name, op) \ uint64_t \ __sync_##name##_8(uint64_t *mem, uint64_t val) \ { \ uint64_t old, temp; \ \ do_sync(); \ __asm volatile ( \ "1:" \ "\tlld %0, %4\n" /* Load old value. */ \ "\t"op"\n" /* Calculate new value. */ \ "\tscd %2, %1\n" /* Attempt to store. */ \ "\tbeqz %2, 1b\n" /* Spin if failed. */ \ : "=&r" (old), "=m" (*mem), "=&r" (temp) \ : "r" (val), "m" (*mem)); \ return (old); \ } EMIT_FETCH_AND_OP_8(lock_test_and_set, "move %2, %3") EMIT_FETCH_AND_OP_8(fetch_and_add, "daddu %2, %0, %3") EMIT_FETCH_AND_OP_8(fetch_and_and, "and %2, %0, %3") EMIT_FETCH_AND_OP_8(fetch_and_or, "or %2, %0, %3") EMIT_FETCH_AND_OP_8(fetch_and_sub, "dsubu %2, %0, %3") EMIT_FETCH_AND_OP_8(fetch_and_xor, "xor %2, %0, %3") #endif /* __mips_n32 || __mips_n64 */ #endif /* __SYNC_ATOMICS */ Index: head/sys/mips/mips/tick.c =================================================================== --- head/sys/mips/mips/tick.c (revision 326258) +++ head/sys/mips/mips/tick.c (revision 326259) @@ -1,398 +1,400 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006-2007 Bruce M. Simpson. * Copyright (c) 2003-2004 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. */ /* * Simple driver for the 32-bit interval counter built in to all * MIPS32 CPUs. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef INTRNG #include #endif uint64_t counter_freq; struct timecounter *platform_timecounter; static DPCPU_DEFINE(uint32_t, cycles_per_tick); static uint32_t cycles_per_usec; static DPCPU_DEFINE(volatile uint32_t, counter_upper); static DPCPU_DEFINE(volatile uint32_t, counter_lower_last); static DPCPU_DEFINE(uint32_t, compare_ticks); static DPCPU_DEFINE(uint32_t, lost_ticks); struct clock_softc { int intr_rid; struct resource *intr_res; void *intr_handler; struct timecounter tc; struct eventtimer et; }; static struct clock_softc *softc; /* * Device methods */ static int clock_probe(device_t); static void clock_identify(driver_t *, device_t); static int clock_attach(device_t); static unsigned counter_get_timecount(struct timecounter *tc); void mips_timer_early_init(uint64_t clock_hz) { /* Initialize clock early so that we can use DELAY sooner */ counter_freq = clock_hz; cycles_per_usec = (clock_hz / (1000 * 1000)); } void platform_initclocks(void) { if (platform_timecounter != NULL) tc_init(platform_timecounter); } static uint64_t tick_ticker(void) { uint64_t ret; uint32_t ticktock; uint32_t t_lower_last, t_upper; /* * Disable preemption because we are working with cpu specific data. */ critical_enter(); /* * Note that even though preemption is disabled, interrupts are * still enabled. In particular there is a race with clock_intr() * reading the values of 'counter_upper' and 'counter_lower_last'. * * XXX this depends on clock_intr() being executed periodically * so that 'counter_upper' and 'counter_lower_last' are not stale. */ do { t_upper = DPCPU_GET(counter_upper); t_lower_last = DPCPU_GET(counter_lower_last); } while (t_upper != DPCPU_GET(counter_upper)); ticktock = mips_rd_count(); critical_exit(); /* COUNT register wrapped around */ if (ticktock < t_lower_last) t_upper++; ret = ((uint64_t)t_upper << 32) | ticktock; return (ret); } void mips_timer_init_params(uint64_t platform_counter_freq, int double_count) { /* * XXX: Do not use printf here: uart code 8250 may use DELAY so this * function should be called before cninit. */ counter_freq = platform_counter_freq; /* * XXX: Some MIPS32 cores update the Count register only every two * pipeline cycles. * We know this because of status registers in CP0, make it automatic. */ if (double_count != 0) counter_freq /= 2; cycles_per_usec = counter_freq / (1 * 1000 * 1000); set_cputicker(tick_ticker, counter_freq, 1); } static int sysctl_machdep_counter_freq(SYSCTL_HANDLER_ARGS) { int error; uint64_t freq; if (softc == NULL) return (EOPNOTSUPP); freq = counter_freq; error = sysctl_handle_64(oidp, &freq, sizeof(freq), req); if (error == 0 && req->newptr != NULL) { counter_freq = freq; softc->et.et_frequency = counter_freq; softc->tc.tc_frequency = counter_freq; } return (error); } SYSCTL_PROC(_machdep, OID_AUTO, counter_freq, CTLTYPE_U64 | CTLFLAG_RW, NULL, 0, sysctl_machdep_counter_freq, "QU", "Timecounter frequency in Hz"); static unsigned counter_get_timecount(struct timecounter *tc) { return (mips_rd_count()); } /* * Wait for about n microseconds (at least!). */ void DELAY(int n) { uint32_t cur, last, delta, usecs; /* * This works by polling the timer and counting the number of * microseconds that go by. */ last = mips_rd_count(); delta = usecs = 0; while (n > usecs) { cur = mips_rd_count(); /* Check to see if the timer has wrapped around. */ if (cur < last) delta += cur + (0xffffffff - last) + 1; else delta += cur - last; last = cur; if (delta >= cycles_per_usec) { usecs += delta / cycles_per_usec; delta %= cycles_per_usec; } } } static int clock_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { uint32_t fdiv, div, next; if (period != 0) { div = (et->et_frequency * period) >> 32; } else div = 0; if (first != 0) fdiv = (et->et_frequency * first) >> 32; else fdiv = div; DPCPU_SET(cycles_per_tick, div); next = mips_rd_count() + fdiv; DPCPU_SET(compare_ticks, next); mips_wr_compare(next); return (0); } static int clock_stop(struct eventtimer *et) { DPCPU_SET(cycles_per_tick, 0); mips_wr_compare(0xffffffff); return (0); } /* * Device section of file below */ static int clock_intr(void *arg) { struct clock_softc *sc = (struct clock_softc *)arg; uint32_t cycles_per_tick; uint32_t count, compare_last, compare_next, lost_ticks; cycles_per_tick = DPCPU_GET(cycles_per_tick); /* * Set next clock edge. */ count = mips_rd_count(); compare_last = DPCPU_GET(compare_ticks); if (cycles_per_tick > 0) { compare_next = count + cycles_per_tick; DPCPU_SET(compare_ticks, compare_next); mips_wr_compare(compare_next); } else /* In one-shot mode timer should be stopped after the event. */ mips_wr_compare(0xffffffff); /* COUNT register wrapped around */ if (count < DPCPU_GET(counter_lower_last)) { DPCPU_SET(counter_upper, DPCPU_GET(counter_upper) + 1); } DPCPU_SET(counter_lower_last, count); if (cycles_per_tick > 0) { /* * Account for the "lost time" between when the timer interrupt * fired and when 'clock_intr' actually started executing. */ lost_ticks = DPCPU_GET(lost_ticks); lost_ticks += count - compare_last; /* * If the COUNT and COMPARE registers are no longer in sync * then make up some reasonable value for the 'lost_ticks'. * * This could happen, for e.g., after we resume normal * operations after exiting the debugger. */ if (lost_ticks > 2 * cycles_per_tick) lost_ticks = cycles_per_tick; while (lost_ticks >= cycles_per_tick) { if (sc->et.et_active) sc->et.et_event_cb(&sc->et, sc->et.et_arg); lost_ticks -= cycles_per_tick; } DPCPU_SET(lost_ticks, lost_ticks); } if (sc->et.et_active) sc->et.et_event_cb(&sc->et, sc->et.et_arg); return (FILTER_HANDLED); } static int clock_probe(device_t dev) { device_set_desc(dev, "Generic MIPS32 ticker"); return (BUS_PROBE_NOWILDCARD); } static void clock_identify(driver_t * drv, device_t parent) { BUS_ADD_CHILD(parent, 0, "clock", 0); } static int clock_attach(device_t dev) { struct clock_softc *sc; #ifndef INTRNG int error; #endif if (device_get_unit(dev) != 0) panic("can't attach more clocks"); softc = sc = device_get_softc(dev); #ifdef INTRNG cpu_establish_hardintr("clock", clock_intr, NULL, sc, 5, INTR_TYPE_CLK, NULL); #else sc->intr_rid = 0; sc->intr_res = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->intr_rid, 5, 5, 1, RF_ACTIVE); if (sc->intr_res == NULL) { device_printf(dev, "failed to allocate irq\n"); return (ENXIO); } error = bus_setup_intr(dev, sc->intr_res, INTR_TYPE_CLK, clock_intr, NULL, sc, &sc->intr_handler); if (error != 0) { device_printf(dev, "bus_setup_intr returned %d\n", error); return (error); } #endif sc->tc.tc_get_timecount = counter_get_timecount; sc->tc.tc_counter_mask = 0xffffffff; sc->tc.tc_frequency = counter_freq; sc->tc.tc_name = "MIPS32"; sc->tc.tc_quality = 800; sc->tc.tc_priv = sc; tc_init(&sc->tc); sc->et.et_name = "MIPS32"; sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU; sc->et.et_quality = 800; sc->et.et_frequency = counter_freq; sc->et.et_min_period = 0x00004000LLU; /* To be safe. */ sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; sc->et.et_start = clock_start; sc->et.et_stop = clock_stop; sc->et.et_priv = sc; et_register(&sc->et); return (0); } static device_method_t clock_methods[] = { /* Device interface */ DEVMETHOD(device_probe, clock_probe), DEVMETHOD(device_identify, clock_identify), DEVMETHOD(device_attach, clock_attach), DEVMETHOD(device_detach, bus_generic_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), {0, 0} }; static driver_t clock_driver = { "clock", clock_methods, sizeof(struct clock_softc), }; static devclass_t clock_devclass; DRIVER_MODULE(clock, nexus, clock_driver, clock_devclass, 0, 0); Index: head/sys/mips/mips/tlb.c =================================================================== --- head/sys/mips/mips/tlb.c (revision 326258) +++ head/sys/mips/mips/tlb.c (revision 326259) @@ -1,387 +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) { 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: head/sys/mips/mips/uma_machdep.c =================================================================== --- head/sys/mips/mips/uma_machdep.c (revision 326258) +++ head/sys/mips/mips/uma_machdep.c (revision 326259) @@ -1,96 +1,98 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003 Alan L. Cox * 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 void * uma_small_alloc(uma_zone_t zone, vm_size_t bytes, u_int8_t *flags, int wait) { vm_paddr_t pa; vm_page_t m; int pflags; void *va; *flags = UMA_SLAB_PRIV; pflags = malloc2vm_flags(wait) | VM_ALLOC_WIRED; #ifndef __mips_n64 pflags &= ~(VM_ALLOC_WAITOK | VM_ALLOC_WAITFAIL); pflags |= VM_ALLOC_NOWAIT; #endif for (;;) { m = vm_page_alloc_freelist(VM_FREELIST_DIRECT, pflags); #ifndef __mips_n64 if (m == NULL && vm_page_reclaim_contig(pflags, 1, 0, MIPS_KSEG0_LARGEST_PHYS, PAGE_SIZE, 0)) continue; #endif if (m == NULL) { if (wait & M_NOWAIT) return (NULL); else VM_WAIT; } else break; } pa = VM_PAGE_TO_PHYS(m); if ((wait & M_NODUMP) == 0) dump_add_page(pa); va = (void *)MIPS_PHYS_TO_DIRECT(pa); if ((wait & M_ZERO) && (m->flags & PG_ZERO) == 0) bzero(va, PAGE_SIZE); return (va); } void uma_small_free(void *mem, vm_size_t size, u_int8_t flags) { vm_page_t m; vm_paddr_t pa; pa = MIPS_DIRECT_TO_PHYS((vm_offset_t)mem); dump_drop_page(pa); m = PHYS_TO_VM_PAGE(pa); m->wire_count--; vm_page_free(m); atomic_subtract_int(&vm_cnt.v_wire_count, 1); } Index: head/sys/mips/nlm/board.c =================================================================== --- head/sys/mips/nlm/board.c (revision 326258) +++ head/sys/mips/nlm/board.c (revision 326259) @@ -1,537 +1,539 @@ /*- + * 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 static uint8_t board_eeprom_buf[EEPROM_SIZE]; static int board_eeprom_set; struct xlp_board_info xlp_board_info; struct vfbid_tbl { int vfbid; int dest_vc; }; /* XXXJC : this should be derived from msg thread mask */ static struct vfbid_tbl nlm_vfbid[] = { /* NULL FBID should map to cpu0 to detect NAE send msg errors */ {127, 0}, /* NAE <-> NAE mappings */ {51, 1019}, {50, 1018}, {49, 1017}, {48, 1016}, {47, 1015}, {46, 1014}, {45, 1013}, {44, 1012}, {43, 1011}, {42, 1010}, {41, 1009}, {40, 1008}, {39, 1007}, {38, 1006}, {37, 1005}, {36, 1004}, {35, 1003}, {34, 1002}, {33, 1001}, {32, 1000}, /* NAE <-> CPU mappings, freeback got to vc 3 of each thread */ {31, 127}, {30, 123}, {29, 119}, {28, 115}, {27, 111}, {26, 107}, {25, 103}, {24, 99}, {23, 95}, {22, 91}, {21, 87}, {20, 83}, {19, 79}, {18, 75}, {17, 71}, {16, 67}, {15, 63}, {14, 59}, {13, 55}, {12, 51}, {11, 47}, {10, 43}, { 9, 39}, { 8, 35}, { 7, 31}, { 6, 27}, { 5, 23}, { 4, 19}, { 3, 15}, { 2, 11}, { 1, 7}, { 0, 3}, }; static struct vfbid_tbl nlm3xx_vfbid[] = { /* NULL FBID should map to cpu0 to detect NAE send msg errors */ {127, 0}, /* NAE <-> NAE mappings */ {39, 503}, {38, 502}, {37, 501}, {36, 500}, {35, 499}, {34, 498}, {33, 497}, {32, 496}, /* NAE <-> CPU mappings, freeback got to vc 3 of each thread */ {31, 127}, {30, 123}, {29, 119}, {28, 115}, {27, 111}, {26, 107}, {25, 103}, {24, 99}, {23, 95}, {22, 91}, {21, 87}, {20, 83}, {19, 79}, {18, 75}, {17, 71}, {16, 67}, {15, 63}, {14, 59}, {13, 55}, {12, 51}, {11, 47}, {10, 43}, { 9, 39}, { 8, 35}, { 7, 31}, { 6, 27}, { 5, 23}, { 4, 19}, { 3, 15}, { 2, 11}, { 1, 7}, { 0, 3}, }; int nlm_get_vfbid_mapping(int vfbid) { int i, nentries; struct vfbid_tbl *p; if (nlm_is_xlp3xx()) { nentries = nitems(nlm3xx_vfbid); p = nlm3xx_vfbid; } else { nentries = nitems(nlm_vfbid); p = nlm_vfbid; } for (i = 0; i < nentries; i++) { if (p[i].vfbid == vfbid) return (p[i].dest_vc); } return (-1); } int nlm_get_poe_distvec(int vec, uint32_t *distvec) { if (vec != 0) return (-1); /* we support just vec 0 */ nlm_calc_poe_distvec(xlp_msg_thread_mask, 0, 0, 0, 0x1 << XLPGE_RX_VC, distvec); return (0); } /* * All our knowledge of chip and board that cannot be detected by probing * at run-time goes here */ void xlpge_get_macaddr(uint8_t *macaddr) { if (board_eeprom_set == 0) { /* No luck, take some reasonable value */ macaddr[0] = 0x00; macaddr[1] = 0x0f; macaddr[2] = 0x30; macaddr[3] = 0x20; macaddr[4] = 0x0d; macaddr[5] = 0x5b; } else memcpy(macaddr, &board_eeprom_buf[EEPROM_MACADDR_OFFSET], ETHER_ADDR_LEN); } static void nlm_setup_port_defaults(struct xlp_port_ivars *p) { p->loopback_mode = 0; p->num_channels = 1; p->free_desc_sizes = 2048; p->vlan_pri_en = 0; p->hw_parser_en = 1; p->ieee1588_userval = 0; p->ieee1588_ptpoff = 0; p->ieee1588_tmr1 = 0; p->ieee1588_tmr2 = 0; p->ieee1588_tmr3 = 0; p->ieee1588_inc_intg = 0; p->ieee1588_inc_den = 1; p->ieee1588_inc_num = 1; if (nlm_is_xlp3xx()) { p->stg2_fifo_size = XLP3XX_STG2_FIFO_SZ; p->eh_fifo_size = XLP3XX_EH_FIFO_SZ; p->frout_fifo_size = XLP3XX_FROUT_FIFO_SZ; p->ms_fifo_size = XLP3XX_MS_FIFO_SZ; p->pkt_fifo_size = XLP3XX_PKT_FIFO_SZ; p->pktlen_fifo_size = XLP3XX_PKTLEN_FIFO_SZ; p->max_stg2_offset = XLP3XX_MAX_STG2_OFFSET; p->max_eh_offset = XLP3XX_MAX_EH_OFFSET; p->max_frout_offset = XLP3XX_MAX_FREE_OUT_OFFSET; p->max_ms_offset = XLP3XX_MAX_MS_OFFSET; p->max_pmem_offset = XLP3XX_MAX_PMEM_OFFSET; p->stg1_2_credit = XLP3XX_STG1_2_CREDIT; p->stg2_eh_credit = XLP3XX_STG2_EH_CREDIT; p->stg2_frout_credit = XLP3XX_STG2_FROUT_CREDIT; p->stg2_ms_credit = XLP3XX_STG2_MS_CREDIT; } else { p->stg2_fifo_size = XLP8XX_STG2_FIFO_SZ; p->eh_fifo_size = XLP8XX_EH_FIFO_SZ; p->frout_fifo_size = XLP8XX_FROUT_FIFO_SZ; p->ms_fifo_size = XLP8XX_MS_FIFO_SZ; p->pkt_fifo_size = XLP8XX_PKT_FIFO_SZ; p->pktlen_fifo_size = XLP8XX_PKTLEN_FIFO_SZ; p->max_stg2_offset = XLP8XX_MAX_STG2_OFFSET; p->max_eh_offset = XLP8XX_MAX_EH_OFFSET; p->max_frout_offset = XLP8XX_MAX_FREE_OUT_OFFSET; p->max_ms_offset = XLP8XX_MAX_MS_OFFSET; p->max_pmem_offset = XLP8XX_MAX_PMEM_OFFSET; p->stg1_2_credit = XLP8XX_STG1_2_CREDIT; p->stg2_eh_credit = XLP8XX_STG2_EH_CREDIT; p->stg2_frout_credit = XLP8XX_STG2_FROUT_CREDIT; p->stg2_ms_credit = XLP8XX_STG2_MS_CREDIT; } switch (p->type) { case SGMIIC: p->num_free_descs = 52; p->iface_fifo_size = 13; p->rxbuf_size = 128; p->rx_slots_reqd = SGMII_CAL_SLOTS; p->tx_slots_reqd = SGMII_CAL_SLOTS; if (nlm_is_xlp3xx()) p->pseq_fifo_size = 30; else p->pseq_fifo_size = 62; break; case ILC: p->num_free_descs = 150; p->rxbuf_size = 944; p->rx_slots_reqd = IL8_CAL_SLOTS; p->tx_slots_reqd = IL8_CAL_SLOTS; p->pseq_fifo_size = 225; p->iface_fifo_size = 55; break; case XAUIC: default: p->num_free_descs = 150; p->rxbuf_size = 944; p->rx_slots_reqd = XAUI_CAL_SLOTS; p->tx_slots_reqd = XAUI_CAL_SLOTS; if (nlm_is_xlp3xx()) { p->pseq_fifo_size = 120; p->iface_fifo_size = 52; } else { p->pseq_fifo_size = 225; p->iface_fifo_size = 55; } break; } } /* XLP 8XX evaluation boards have the following phy-addr * assignment. There are two external mdio buses in XLP -- * bus 0 and bus 1. The management ports (16 and 17) are * on mdio bus 0 while blocks/complexes[0 to 3] are all * on mdio bus 1. The phy_addr on bus 0 (mgmt ports 16 * and 17) match the port numbers. * These are the details: * block port phy_addr mdio_bus * ==================================== * 0 0 4 1 * 0 1 7 1 * 0 2 6 1 * 0 3 5 1 * 1 0 8 1 * 1 1 11 1 * 1 2 10 1 * 1 3 9 1 * 2 0 0 1 * 2 1 3 1 * 2 2 2 1 * 2 3 1 1 * 3 0 12 1 * 3 1 15 1 * 3 2 14 1 * 3 3 13 1 * * 4 0 16 0 * 4 1 17 0 * * The XLP 3XX evaluation boards have the following phy-addr * assignments. * block port phy_addr mdio_bus * ==================================== * 0 0 4 0 * 0 1 7 0 * 0 2 6 0 * 0 3 5 0 * 1 0 8 0 * 1 1 11 0 * 1 2 10 0 * 1 3 9 0 */ static void nlm_board_get_phyaddr(int block, int port, int *phyaddr) { switch (block) { case 0: switch (port) { case 0: *phyaddr = 4; break; case 1: *phyaddr = 7; break; case 2: *phyaddr = 6; break; case 3: *phyaddr = 5; break; } break; case 1: switch (port) { case 0: *phyaddr = 8; break; case 1: *phyaddr = 11; break; case 2: *phyaddr = 10; break; case 3: *phyaddr = 9; break; } break; case 2: switch (port) { case 0: *phyaddr = 0; break; case 1: *phyaddr = 3; break; case 2: *phyaddr = 2; break; case 3: *phyaddr = 1; break; } break; case 3: switch (port) { case 0: *phyaddr = 12; break; case 1: *phyaddr = 15; break; case 2: *phyaddr = 14; break; case 3: *phyaddr = 13; break; } break; case 4: switch (port) { /* management SGMII */ case 0: *phyaddr = 16; break; case 1: *phyaddr = 17; break; } break; } } static void nlm_print_processor_info(void) { uint32_t procid; int prid, rev; char *chip, *revstr; procid = mips_rd_prid(); prid = (procid >> 8) & 0xff; rev = procid & 0xff; switch (prid) { case CHIP_PROCESSOR_ID_XLP_8XX: chip = "XLP 832"; break; case CHIP_PROCESSOR_ID_XLP_3XX: chip = "XLP 3xx"; break; case CHIP_PROCESSOR_ID_XLP_432: case CHIP_PROCESSOR_ID_XLP_416: chip = "XLP 4xx"; break; default: chip = "XLP ?xx"; break; } switch (rev) { case 0: revstr = "A0"; break; case 1: revstr = "A1"; break; case 2: revstr = "A2"; break; case 3: revstr = "B0"; break; case 4: revstr = "B1"; break; default: revstr = "??"; break; } printf("Processor info:\n"); printf(" Netlogic %s %s [%x]\n", chip, revstr, procid); } /* * All our knowledge of chip and board that cannot be detected by probing * at run-time goes here */ static int nlm_setup_xlp_board(int node) { struct xlp_board_info *boardp; struct xlp_node_info *nodep; struct xlp_nae_ivars *naep; struct xlp_block_ivars *blockp; struct xlp_port_ivars *portp; uint64_t cpldbase, nae_pcibase; int block, port, rv, dbtype, usecpld = 0, evp = 0, svp = 0; uint8_t *b; /* start with a clean slate */ boardp = &xlp_board_info; if (boardp->nodemask == 0) memset(boardp, 0, sizeof(xlp_board_info)); boardp->nodemask |= (1 << node); nlm_print_processor_info(); b = board_eeprom_buf; rv = nlm_board_eeprom_read(node, EEPROM_I2CBUS, EEPROM_I2CADDR, 0, b, EEPROM_SIZE); if (rv == 0) { board_eeprom_set = 1; printf("Board info (EEPROM on i2c@%d at %#X):\n", EEPROM_I2CBUS, EEPROM_I2CADDR); printf(" Model: %7.7s %2.2s\n", &b[16], &b[24]); printf(" Serial #: %3.3s-%2.2s\n", &b[27], &b[31]); printf(" MAC addr: %02x:%02x:%02x:%02x:%02x:%02x\n", b[2], b[3], b[4], b[5], b[6], b[7]); } else printf("Board Info: Error on EEPROM read (i2c@%d %#X).\n", EEPROM_I2CBUS, EEPROM_I2CADDR); nae_pcibase = nlm_get_nae_pcibase(node); nodep = &boardp->nodes[node]; naep = &nodep->nae_ivars; naep->node = node; /* frequency at which network block runs */ naep->freq = 500; /* CRC16 polynomial used for flow table generation */ naep->flow_crc_poly = 0xffff; naep->hw_parser_en = 1; naep->prepad_en = 1; naep->prepad_size = 3; /* size in 16 byte units */ naep->ieee_1588_en = 1; naep->ilmask = 0x0; /* set this based on daughter card */ naep->xauimask = 0x0; /* set this based on daughter card */ naep->sgmiimask = 0x0; /* set this based on daughter card */ naep->nblocks = nae_num_complex(nae_pcibase); if (strncmp(&b[16], "PCIE", 4) == 0) { usecpld = 0; /* XLP PCIe card */ /* Broadcom's XLP PCIe card has the following * blocks fixed. * blk 0-XAUI, 1-XAUI, 4-SGMII(one port) */ naep->blockmask = 0x13; } else if (strncmp(&b[16], "MB-EVP", 6) == 0) { usecpld = 1; /* XLP non-PCIe card which has CPLD */ evp = 1; naep->blockmask = (1 << naep->nblocks) - 1; } else if ((strncmp(&b[16], "MB-S", 4) == 0) || (strncmp(&b[16], "MB_S", 4) == 0)) { usecpld = 1; /* XLP non-PCIe card which has CPLD */ svp = 1; /* 3xx chip reports one block extra which is a bug */ naep->nblocks = naep->nblocks - 1; naep->blockmask = (1 << naep->nblocks) - 1; } else { printf("ERROR!!! Board type:%7s didn't match any board" " type we support\n", &b[16]); return (-1); } cpldbase = nlm_board_cpld_base(node, XLP_EVB_CPLD_CHIPSELECT); /* pretty print network config */ printf("Network config"); if (usecpld) printf("(from CPLD@%d):\n", XLP_EVB_CPLD_CHIPSELECT); else printf("(defaults):\n"); printf(" NAE@%d Blocks: ", node); for (block = 0; block < naep->nblocks; block++) { char *s = "???"; if ((naep->blockmask & (1 << block)) == 0) continue; blockp = &naep->block_ivars[block]; blockp->block = block; if (usecpld) dbtype = nlm_board_cpld_dboard_type(cpldbase, block); else dbtype = DCARD_XAUI; /* default XAUI */ /* XLP PCIe cards */ if ((!evp && !svp) && ((block == 2) || (block == 3))) dbtype = DCARD_NOT_PRSNT; if (block == 4) { /* management block 4 on 8xx or XLP PCIe */ blockp->type = SGMIIC; if (evp) blockp->portmask = 0x3; else blockp->portmask = 0x1; naep->sgmiimask |= (1 << block); } else { switch (dbtype) { case DCARD_ILAKEN: blockp->type = ILC; blockp->portmask = 0x1; naep->ilmask |= (1 << block); break; case DCARD_SGMII: blockp->type = SGMIIC; blockp->portmask = 0xf; naep->sgmiimask |= (1 << block); break; case DCARD_XAUI: blockp->type = XAUIC; blockp->portmask = 0x1; naep->xauimask |= (1 << block); break; default: /* DCARD_NOT_PRSNT */ blockp->type = UNKNOWN; blockp->portmask = 0; break; } } if (blockp->type != UNKNOWN) { for (port = 0; port < PORTS_PER_CMPLX; port++) { if ((blockp->portmask & (1 << port)) == 0) continue; portp = &blockp->port_ivars[port]; nlm_board_get_phyaddr(block, port, &portp->phy_addr); if (svp || (block == 4)) portp->mdio_bus = 0; else portp->mdio_bus = 1; portp->port = port; portp->block = block; portp->node = node; portp->type = blockp->type; nlm_setup_port_defaults(portp); } } switch (blockp->type) { case SGMIIC : s = "SGMII"; break; case XAUIC : s = "XAUI"; break; case ILC : s = "IL"; break; } printf(" [%d %s]", block, s); } printf("\n"); return (0); } int nlm_board_info_setup(void) { if (nlm_setup_xlp_board(0) != 0) return (-1); return (0); } Index: head/sys/mips/nlm/board.h =================================================================== --- head/sys/mips/nlm/board.h (revision 326258) +++ head/sys/mips/nlm/board.h (revision 326259) @@ -1,157 +1,159 @@ /*- + * 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 * $FreeBSD$ */ #ifndef __NLM_BOARD_H__ #define __NLM_BOARD_H__ #define XLP_NAE_NBLOCKS 5 #define XLP_NAE_NPORTS 4 /* * EVP board EEPROM info */ #define EEPROM_I2CBUS 1 #define EEPROM_I2CADDR 0xAE #define EEPROM_SIZE 48 #define EEPROM_MACADDR_OFFSET 2 /* used if there is no FDT */ #define BOARD_CONSOLE_SPEED 115200 #define BOARD_CONSOLE_UART 0 /* * EVP board CPLD chip select and daughter card info field */ #define XLP_EVB_CPLD_CHIPSELECT 2 #define DCARD_ILAKEN 0x0 #define DCARD_SGMII 0x1 #define DCARD_XAUI 0x2 #define DCARD_NOT_PRSNT 0x3 #if !defined(LOCORE) && !defined(__ASSEMBLY__) /* * NAE configuration */ struct xlp_port_ivars { int port; int block; int node; int type; int phy_addr; int mdio_bus; int loopback_mode; int num_channels; int free_desc_sizes; int num_free_descs; int pseq_fifo_size; int iface_fifo_size; int rxbuf_size; int rx_slots_reqd; int tx_slots_reqd; int vlan_pri_en; int stg2_fifo_size; int eh_fifo_size; int frout_fifo_size; int ms_fifo_size; int pkt_fifo_size; int pktlen_fifo_size; int max_stg2_offset; int max_eh_offset; int max_frout_offset; int max_ms_offset; int max_pmem_offset; int stg1_2_credit; int stg2_eh_credit; int stg2_frout_credit; int stg2_ms_credit; int hw_parser_en; u_int ieee1588_inc_intg; u_int ieee1588_inc_den; u_int ieee1588_inc_num; uint64_t ieee1588_userval; uint64_t ieee1588_ptpoff; uint64_t ieee1588_tmr1; uint64_t ieee1588_tmr2; uint64_t ieee1588_tmr3; }; struct xlp_block_ivars { int block; int type; u_int portmask; struct xlp_port_ivars port_ivars[XLP_NAE_NPORTS]; }; struct xlp_nae_ivars { int node; int nblocks; u_int blockmask; u_int ilmask; u_int xauimask; u_int sgmiimask; int freq; u_int flow_crc_poly; u_int hw_parser_en; u_int prepad_en; u_int prepad_size; /* size in 16 byte units */ u_int ieee_1588_en; struct xlp_block_ivars block_ivars[XLP_NAE_NBLOCKS]; }; struct xlp_board_info { u_int nodemask; struct xlp_node_info { struct xlp_nae_ivars nae_ivars; } nodes[XLP_MAX_NODES]; }; extern struct xlp_board_info xlp_board_info; /* Network configuration */ int nlm_get_vfbid_mapping(int); int nlm_get_poe_distvec(int vec, uint32_t *distvec); void xlpge_get_macaddr(uint8_t *macaddr); int nlm_board_info_setup(void); /* EEPROM & CPLD */ int nlm_board_eeprom_read(int node, int i2cbus, int addr, int offs, uint8_t *buf,int sz); uint64_t nlm_board_cpld_base(int node, int chipselect); int nlm_board_cpld_majorversion(uint64_t cpldbase); int nlm_board_cpld_minorversion(uint64_t cpldbase); void nlm_board_cpld_reset(uint64_t cpldbase); int nlm_board_cpld_dboard_type(uint64_t cpldbase, int slot); #endif #endif Index: head/sys/mips/nlm/board_cpld.c =================================================================== --- head/sys/mips/nlm/board_cpld.c (revision 326258) +++ head/sys/mips/nlm/board_cpld.c (revision 326259) @@ -1,113 +1,115 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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 #define CPLD_REVISION 0x0 #define CPLD_RESET 0x1 #define CPLD_CTRL 0x2 #define CPLD_RSVD 0x3 #define CPLD_PWR_CTRL 0x4 #define CPLD_MISC 0x5 #define CPLD_CTRL_STATUS 0x6 #define CPLD_PWR_INTR_STATUS 0x7 #define CPLD_DATA 0x8 static __inline int nlm_cpld_read(uint64_t base, int reg) { uint16_t val; val = *(volatile uint16_t *)(long)(base + reg * 2); return le16toh(val); } static __inline void nlm_cpld_write(uint64_t base, int reg, uint16_t data) { data = htole16(data); *(volatile uint16_t *)(long)(base + reg * 2) = data; } int nlm_board_cpld_majorversion(uint64_t base) { return (nlm_cpld_read(base, CPLD_REVISION) >> 8); } int nlm_board_cpld_minorversion(uint64_t base) { return (nlm_cpld_read(base, CPLD_REVISION) & 0xff); } uint64_t nlm_board_cpld_base(int node, int chipselect) { uint64_t gbubase, cpld_phys; gbubase = nlm_get_gbu_regbase(node); cpld_phys = nlm_read_gbu_reg(gbubase, GBU_CS_BASEADDR(chipselect)); return (MIPS_PHYS_TO_KSEG1(cpld_phys << 8)); } void nlm_board_cpld_reset(uint64_t base) { nlm_cpld_write(base, CPLD_RESET, 1 << 15); for(;;) __asm __volatile("wait"); } /* get daughter board type */ int nlm_board_cpld_dboard_type(uint64_t base, int slot) { uint16_t val; int shift = 0; switch (slot) { case 0: shift = 0; break; case 1: shift = 4; break; case 2: shift = 2; break; case 3: shift = 6; break; } val = nlm_cpld_read(base, CPLD_CTRL_STATUS) >> shift; return (val & 0x3); } Index: head/sys/mips/nlm/board_eeprom.c =================================================================== --- head/sys/mips/nlm/board_eeprom.c (revision 326258) +++ head/sys/mips/nlm/board_eeprom.c (revision 326259) @@ -1,172 +1,174 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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 /* needed by board.h */ #include /* * We have to read the EEPROM in early boot (now only for MAC addr) * but later for board information. Use simple polled mode driver * for I2C */ #define oc_read_reg(reg) nlm_read_reg(eeprom_i2c_base, reg) #define oc_write_reg(reg, val) nlm_write_reg(eeprom_i2c_base, reg, val) static uint64_t eeprom_i2c_base; static int oc_wait_on_status(uint8_t bit) { int tries = I2C_TIMEOUT; uint8_t status; do { status = oc_read_reg(OC_I2C_STATUS_REG); } while ((status & bit) != 0 && --tries > 0); return (tries == 0 ? -1: 0); } static int oc_rd_cmd(uint8_t cmd) { uint8_t data; oc_write_reg(OC_I2C_CMD_REG, cmd); if (oc_wait_on_status(OC_STATUS_TIP) < 0) return (-1); data = oc_read_reg(OC_I2C_DATA_REG); return (data); } static int oc_wr_cmd(uint8_t data, uint8_t cmd) { oc_write_reg(OC_I2C_DATA_REG, data); oc_write_reg(OC_I2C_CMD_REG, cmd); if (oc_wait_on_status(OC_STATUS_TIP) < 0) return (-1); return (0); } int nlm_board_eeprom_read(int node, int bus, int addr, int offs, uint8_t *buf, int sz) { int rd, i; char *err = NULL; eeprom_i2c_base = nlm_pcicfg_base(XLP_IO_I2C_OFFSET(node, bus)) + XLP_IO_PCI_HDRSZ; if (oc_wait_on_status(OC_STATUS_BUSY) < 0) { err = "Not idle"; goto err_exit; } /* write start */ if (oc_wr_cmd(addr, OC_COMMAND_START)) { err = "I2C write start failed."; goto err_exit; } if (oc_read_reg(OC_I2C_STATUS_REG) & OC_STATUS_NACK) { err = "No ack after start"; goto err_exit_stop; } if (oc_read_reg(OC_I2C_STATUS_REG) & OC_STATUS_AL) { err = "I2C Bus Arbitration Lost"; goto err_exit_stop; } /* Write offset */ if (oc_wr_cmd(offs, OC_COMMAND_WRITE)) { err = "I2C write slave offset failed."; goto err_exit_stop; } if (oc_read_reg(OC_I2C_STATUS_REG) & OC_STATUS_NACK) { err = "No ack after write"; goto err_exit_stop; } /* read start */ if (oc_wr_cmd(addr | 1, OC_COMMAND_START)) { err = "I2C read start failed."; goto err_exit_stop; } if (oc_read_reg(OC_I2C_STATUS_REG) & OC_STATUS_NACK) { err = "No ack after read start"; goto err_exit_stop; } for (i = 0; i < sz - 1; i++) { if ((rd = oc_rd_cmd(OC_COMMAND_READ)) < 0) { err = "I2C read data byte failed."; goto err_exit_stop; } buf[i] = rd; } /* last byte */ if ((rd = oc_rd_cmd(OC_COMMAND_RDNACK)) < 0) { err = "I2C read last data byte failed."; goto err_exit_stop; } buf[sz - 1] = rd; err_exit_stop: oc_write_reg(OC_I2C_CMD_REG, OC_COMMAND_STOP); if (oc_wait_on_status(OC_STATUS_BUSY) < 0) printf("%s: stop failed", __func__); err_exit: if (err) { printf("%s: Failed (%s)\n", __func__, err); return (-1); } return (0); } Index: head/sys/mips/nlm/bus_space_rmi.c =================================================================== --- head/sys/mips/nlm/bus_space_rmi.c (revision 326258) +++ head/sys/mips/nlm/bus_space_rmi.c (revision 326259) @@ -1,772 +1,774 @@ /* + * 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 static int rmi_bus_space_map(void *t, bus_addr_t addr, bus_size_t size, int flags, bus_space_handle_t *bshp); static void rmi_bus_space_unmap(void *t, bus_space_handle_t bsh, bus_size_t size); static int rmi_bus_space_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset, bus_size_t size, bus_space_handle_t *nbshp); static u_int8_t rmi_bus_space_read_1(void *t, bus_space_handle_t handle, bus_size_t offset); static u_int16_t rmi_bus_space_read_2(void *t, bus_space_handle_t handle, bus_size_t offset); static u_int32_t rmi_bus_space_read_4(void *t, bus_space_handle_t handle, bus_size_t offset); static void rmi_bus_space_read_multi_1(void *t, bus_space_handle_t handle, bus_size_t offset, u_int8_t *addr, size_t count); static void rmi_bus_space_read_multi_2(void *t, bus_space_handle_t handle, bus_size_t offset, u_int16_t *addr, size_t count); static void rmi_bus_space_read_multi_4(void *t, bus_space_handle_t handle, bus_size_t offset, u_int32_t *addr, size_t count); static void rmi_bus_space_read_region_1(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int8_t *addr, size_t count); static void rmi_bus_space_read_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int16_t *addr, size_t count); static void rmi_bus_space_read_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int32_t *addr, size_t count); static void rmi_bus_space_write_1(void *t, bus_space_handle_t handle, bus_size_t offset, u_int8_t value); static void rmi_bus_space_write_2(void *t, bus_space_handle_t handle, bus_size_t offset, u_int16_t value); static void rmi_bus_space_write_4(void *t, bus_space_handle_t handle, bus_size_t offset, u_int32_t value); static void rmi_bus_space_write_multi_1(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int8_t *addr, size_t count); static void rmi_bus_space_write_multi_2(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int16_t *addr, size_t count); static void rmi_bus_space_write_multi_4(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int32_t *addr, size_t count); static void rmi_bus_space_write_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, const u_int16_t *addr, size_t count); static void rmi_bus_space_write_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, const u_int32_t *addr, size_t count); static void rmi_bus_space_set_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int16_t value, size_t count); static void rmi_bus_space_set_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int32_t value, size_t count); static void rmi_bus_space_barrier(void *tag __unused, bus_space_handle_t bsh __unused, bus_size_t offset __unused, bus_size_t len __unused, int flags); static void rmi_bus_space_copy_region_2(void *t, bus_space_handle_t bsh1, bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, size_t count); u_int8_t rmi_bus_space_read_stream_1(void *t, bus_space_handle_t handle, bus_size_t offset); static u_int16_t rmi_bus_space_read_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset); static u_int32_t rmi_bus_space_read_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset); static void rmi_bus_space_read_multi_stream_1(void *t, bus_space_handle_t handle, bus_size_t offset, u_int8_t *addr, size_t count); static void rmi_bus_space_read_multi_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset, u_int16_t *addr, size_t count); static void rmi_bus_space_read_multi_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset, u_int32_t *addr, size_t count); void rmi_bus_space_write_stream_1(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int8_t value); static void rmi_bus_space_write_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset, u_int16_t value); static void rmi_bus_space_write_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset, u_int32_t value); static void rmi_bus_space_write_multi_stream_1(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int8_t *addr, size_t count); static void rmi_bus_space_write_multi_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int16_t *addr, size_t count); static void rmi_bus_space_write_multi_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int32_t *addr, size_t count); #define TODO() printf("XLP bus space: '%s' unimplemented\n", __func__) static struct bus_space local_rmi_bus_space = { /* cookie */ (void *)0, /* mapping/unmapping */ rmi_bus_space_map, rmi_bus_space_unmap, rmi_bus_space_subregion, /* allocation/deallocation */ NULL, NULL, /* barrier */ rmi_bus_space_barrier, /* read (single) */ rmi_bus_space_read_1, rmi_bus_space_read_2, rmi_bus_space_read_4, NULL, /* read multiple */ rmi_bus_space_read_multi_1, rmi_bus_space_read_multi_2, rmi_bus_space_read_multi_4, NULL, /* read region */ rmi_bus_space_read_region_1, rmi_bus_space_read_region_2, rmi_bus_space_read_region_4, NULL, /* write (single) */ rmi_bus_space_write_1, rmi_bus_space_write_2, rmi_bus_space_write_4, NULL, /* write multiple */ rmi_bus_space_write_multi_1, rmi_bus_space_write_multi_2, rmi_bus_space_write_multi_4, NULL, /* write region */ NULL, rmi_bus_space_write_region_2, rmi_bus_space_write_region_4, NULL, /* set multiple */ NULL, NULL, NULL, NULL, /* set region */ NULL, rmi_bus_space_set_region_2, rmi_bus_space_set_region_4, NULL, /* copy */ NULL, rmi_bus_space_copy_region_2, NULL, NULL, /* read (single) stream */ rmi_bus_space_read_stream_1, rmi_bus_space_read_stream_2, rmi_bus_space_read_stream_4, NULL, /* read multiple stream */ rmi_bus_space_read_multi_stream_1, rmi_bus_space_read_multi_stream_2, rmi_bus_space_read_multi_stream_4, NULL, /* read region stream */ rmi_bus_space_read_region_1, rmi_bus_space_read_region_2, rmi_bus_space_read_region_4, NULL, /* write (single) stream */ rmi_bus_space_write_stream_1, rmi_bus_space_write_stream_2, rmi_bus_space_write_stream_4, NULL, /* write multiple stream */ rmi_bus_space_write_multi_stream_1, rmi_bus_space_write_multi_stream_2, rmi_bus_space_write_multi_stream_4, NULL, /* write region stream */ NULL, rmi_bus_space_write_region_2, rmi_bus_space_write_region_4, NULL, }; /* generic bus_space tag */ bus_space_tag_t rmi_bus_space = &local_rmi_bus_space; /* * Map a region of device bus space into CPU virtual address space. */ static int rmi_bus_space_map(void *t __unused, bus_addr_t addr, bus_size_t size __unused, int flags __unused, bus_space_handle_t *bshp) { *bshp = MIPS_PHYS_TO_DIRECT_UNCACHED(addr); return (0); } /* * Unmap a region of device bus space. */ static void rmi_bus_space_unmap(void *t __unused, bus_space_handle_t bsh __unused, bus_size_t size __unused) { } /* * Get a new handle for a subregion of an already-mapped area of bus space. */ static int rmi_bus_space_subregion(void *t __unused, bus_space_handle_t bsh, bus_size_t offset, bus_size_t size __unused, bus_space_handle_t *nbshp) { *nbshp = bsh + offset; return (0); } /* * Read a 1, 2, 4, or 8 byte quantity from bus space * described by tag/handle/offset. */ static u_int8_t rmi_bus_space_read_1(void *tag, bus_space_handle_t handle, bus_size_t offset) { return (u_int8_t) (*(volatile u_int8_t *)(handle + offset)); } static u_int16_t rmi_bus_space_read_2(void *tag, bus_space_handle_t handle, bus_size_t offset) { return (u_int16_t)(*(volatile u_int16_t *)(handle + offset)); } static u_int32_t rmi_bus_space_read_4(void *tag, bus_space_handle_t handle, bus_size_t offset) { return (*(volatile u_int32_t *)(handle + offset)); } /* * Read `count' 1, 2, 4, or 8 byte quantities from bus space * described by tag/handle/offset and copy into buffer provided. */ static void rmi_bus_space_read_multi_1(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int8_t *addr, size_t count) { TODO(); } static void rmi_bus_space_read_multi_2(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int16_t *addr, size_t count) { TODO(); } static void rmi_bus_space_read_multi_4(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int32_t *addr, size_t count) { TODO(); } /* * Write the 1, 2, 4, or 8 byte value `value' to bus space * described by tag/handle/offset. */ static void rmi_bus_space_write_1(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int8_t value) { *(volatile u_int8_t *)(handle + offset) = value; } static void rmi_bus_space_write_2(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int16_t value) { *(volatile u_int16_t *)(handle + offset) = value; } static void rmi_bus_space_write_4(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int32_t value) { *(volatile u_int32_t *)(handle + offset) = value; } /* * Write `count' 1, 2, 4, or 8 byte quantities from the buffer * provided to bus space described by tag/handle/offset. */ static void rmi_bus_space_write_multi_1(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int8_t *addr, size_t count) { TODO(); } static void rmi_bus_space_write_multi_2(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int16_t *addr, size_t count) { TODO(); } static void rmi_bus_space_write_multi_4(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int32_t *addr, size_t count) { TODO(); } /* * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described * by tag/handle starting at `offset'. */ static void rmi_bus_space_set_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int16_t value, size_t count) { bus_addr_t addr = bsh + offset; for (; count != 0; count--, addr += 2) (*(volatile u_int32_t *)(addr)) = value; } static void rmi_bus_space_set_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int32_t value, size_t count) { bus_addr_t addr = bsh + offset; for (; count != 0; count--, addr += 4) (*(volatile u_int32_t *)(addr)) = value; } /* * Copy `count' 1, 2, 4, or 8 byte values from bus space starting * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2. */ static void rmi_bus_space_copy_region_2(void *t, bus_space_handle_t bsh1, bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, size_t count) { printf("bus_space_copy_region_2 - unimplemented\n"); } /* * Read `count' 1, 2, 4, or 8 byte quantities from bus space * described by tag/handle/offset and copy into buffer provided. */ u_int8_t rmi_bus_space_read_stream_1(void *t, bus_space_handle_t handle, bus_size_t offset) { return *((volatile u_int8_t *)(handle + offset)); } static u_int16_t rmi_bus_space_read_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset) { return *(volatile u_int16_t *)(handle + offset); } static u_int32_t rmi_bus_space_read_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset) { return (*(volatile u_int32_t *)(handle + offset)); } static void rmi_bus_space_read_multi_stream_1(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int8_t *addr, size_t count) { TODO(); } static void rmi_bus_space_read_multi_stream_2(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int16_t *addr, size_t count) { TODO(); } static void rmi_bus_space_read_multi_stream_4(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int32_t *addr, size_t count) { TODO(); } /* * Read `count' 1, 2, 4, or 8 byte quantities from bus space * described by tag/handle and starting at `offset' and copy into * buffer provided. */ void rmi_bus_space_read_region_1(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int8_t *addr, size_t count) { TODO(); } void rmi_bus_space_read_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int16_t *addr, size_t count) { TODO(); } void rmi_bus_space_read_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int32_t *addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { *addr++ = (*(volatile u_int32_t *)(baddr)); baddr += 4; } } void rmi_bus_space_write_stream_1(void *t, bus_space_handle_t handle, bus_size_t offset, u_int8_t value) { TODO(); } static void rmi_bus_space_write_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset, u_int16_t value) { TODO(); } static void rmi_bus_space_write_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset, u_int32_t value) { TODO(); } static void rmi_bus_space_write_multi_stream_1(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int8_t *addr, size_t count) { TODO(); } static void rmi_bus_space_write_multi_stream_2(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int16_t *addr, size_t count) { TODO(); } static void rmi_bus_space_write_multi_stream_4(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int32_t *addr, size_t count) { TODO(); } void rmi_bus_space_write_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, const u_int16_t *addr, size_t count) { TODO(); } void rmi_bus_space_write_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, const u_int32_t *addr, size_t count) { TODO(); } static void rmi_bus_space_barrier(void *tag __unused, bus_space_handle_t bsh __unused, bus_size_t offset __unused, bus_size_t len __unused, int flags) { } /* * need a special bus space for this, because the Netlogic SoC * UART allows only 32 bit access to its registers */ static u_int8_t rmi_uart_bus_space_read_1(void *tag, bus_space_handle_t handle, bus_size_t offset) { return (u_int8_t)(*(volatile u_int32_t *)(handle + offset)); } static void rmi_uart_bus_space_write_1(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int8_t value) { *(volatile u_int32_t *)(handle + offset) = value; } static struct bus_space local_rmi_uart_bus_space = { /* cookie */ (void *)0, /* mapping/unmapping */ rmi_bus_space_map, rmi_bus_space_unmap, rmi_bus_space_subregion, /* allocation/deallocation */ NULL, NULL, /* barrier */ rmi_bus_space_barrier, /* read (single) */ rmi_uart_bus_space_read_1, NULL, NULL, NULL, /* read multiple */ NULL, NULL, NULL, NULL, /* read region */ NULL, NULL, NULL, NULL, /* write (single) */ rmi_uart_bus_space_write_1, NULL, NULL, NULL, /* write multiple */ NULL, NULL, NULL, NULL, /* write region */ NULL, NULL, NULL, NULL, /* set multiple */ NULL, NULL, NULL, NULL, /* set region */ NULL, NULL, NULL, NULL, /* copy */ NULL, NULL, NULL, NULL, /* read (single) stream */ NULL, NULL, NULL, NULL, /* read multiple stream */ NULL, NULL, NULL, NULL, /* read region stream */ NULL, NULL, NULL, NULL, /* write (single) stream */ NULL, NULL, NULL, NULL, /* write multiple stream */ NULL, NULL, NULL, NULL, /* write region stream */ NULL, NULL, NULL, NULL, }; /* generic bus_space tag */ bus_space_tag_t rmi_uart_bus_space = &local_rmi_uart_bus_space; Index: head/sys/mips/nlm/bus_space_rmi_pci.c =================================================================== --- head/sys/mips/nlm/bus_space_rmi_pci.c (revision 326258) +++ head/sys/mips/nlm/bus_space_rmi_pci.c (revision 326259) @@ -1,771 +1,773 @@ /*- + * 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 static int rmi_pci_bus_space_map(void *t, bus_addr_t addr, bus_size_t size, int flags, bus_space_handle_t * bshp); static void rmi_pci_bus_space_unmap(void *t, bus_space_handle_t bsh, bus_size_t size); static int rmi_pci_bus_space_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset, bus_size_t size, bus_space_handle_t * nbshp); static u_int8_t rmi_pci_bus_space_read_1(void *t, bus_space_handle_t handle, bus_size_t offset); static u_int16_t rmi_pci_bus_space_read_2(void *t, bus_space_handle_t handle, bus_size_t offset); static u_int32_t rmi_pci_bus_space_read_4(void *t, bus_space_handle_t handle, bus_size_t offset); static void rmi_pci_bus_space_read_multi_1(void *t, bus_space_handle_t handle, bus_size_t offset, u_int8_t * addr, size_t count); static void rmi_pci_bus_space_read_multi_2(void *t, bus_space_handle_t handle, bus_size_t offset, u_int16_t * addr, size_t count); static void rmi_pci_bus_space_read_multi_4(void *t, bus_space_handle_t handle, bus_size_t offset, u_int32_t * addr, size_t count); static void rmi_pci_bus_space_read_region_1(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int8_t * addr, size_t count); static void rmi_pci_bus_space_read_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int16_t * addr, size_t count); static void rmi_pci_bus_space_read_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int32_t * addr, size_t count); static void rmi_pci_bus_space_write_1(void *t, bus_space_handle_t handle, bus_size_t offset, u_int8_t value); static void rmi_pci_bus_space_write_2(void *t, bus_space_handle_t handle, bus_size_t offset, u_int16_t value); static void rmi_pci_bus_space_write_4(void *t, bus_space_handle_t handle, bus_size_t offset, u_int32_t value); static void rmi_pci_bus_space_write_multi_1(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int8_t * addr, size_t count); static void rmi_pci_bus_space_write_multi_2(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int16_t * addr, size_t count); static void rmi_pci_bus_space_write_multi_4(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int32_t * addr, size_t count); static void rmi_pci_bus_space_write_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, const u_int16_t * addr, size_t count); static void rmi_pci_bus_space_write_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, const u_int32_t * addr, size_t count); static void rmi_pci_bus_space_set_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int16_t value, size_t count); static void rmi_pci_bus_space_set_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int32_t value, size_t count); static void rmi_pci_bus_space_barrier(void *tag __unused, bus_space_handle_t bsh __unused, bus_size_t offset __unused, bus_size_t len __unused, int flags); static void rmi_pci_bus_space_copy_region_2(void *t, bus_space_handle_t bsh1, bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, size_t count); u_int8_t rmi_pci_bus_space_read_stream_1(void *t, bus_space_handle_t handle, bus_size_t offset); static u_int16_t rmi_pci_bus_space_read_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset); static u_int32_t rmi_pci_bus_space_read_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset); static void rmi_pci_bus_space_read_multi_stream_1(void *t, bus_space_handle_t handle, bus_size_t offset, u_int8_t * addr, size_t count); static void rmi_pci_bus_space_read_multi_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset, u_int16_t * addr, size_t count); static void rmi_pci_bus_space_read_multi_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset, u_int32_t * addr, size_t count); void rmi_pci_bus_space_write_stream_1(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int8_t value); static void rmi_pci_bus_space_write_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset, u_int16_t value); static void rmi_pci_bus_space_write_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset, u_int32_t value); static void rmi_pci_bus_space_write_multi_stream_1(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int8_t * addr, size_t count); static void rmi_pci_bus_space_write_multi_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int16_t * addr, size_t count); static void rmi_pci_bus_space_write_multi_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int32_t * addr, size_t count); #define TODO() printf("XLR memory bus space function '%s' unimplemented\n", __func__) static struct bus_space local_rmi_pci_bus_space = { /* cookie */ (void *)0, /* mapping/unmapping */ rmi_pci_bus_space_map, rmi_pci_bus_space_unmap, rmi_pci_bus_space_subregion, /* allocation/deallocation */ NULL, NULL, /* barrier */ rmi_pci_bus_space_barrier, /* read (single) */ rmi_pci_bus_space_read_1, rmi_pci_bus_space_read_2, rmi_pci_bus_space_read_4, NULL, /* read multiple */ rmi_pci_bus_space_read_multi_1, rmi_pci_bus_space_read_multi_2, rmi_pci_bus_space_read_multi_4, NULL, /* read region */ rmi_pci_bus_space_read_region_1, rmi_pci_bus_space_read_region_2, rmi_pci_bus_space_read_region_4, NULL, /* write (single) */ rmi_pci_bus_space_write_1, rmi_pci_bus_space_write_2, rmi_pci_bus_space_write_4, NULL, /* write multiple */ rmi_pci_bus_space_write_multi_1, rmi_pci_bus_space_write_multi_2, rmi_pci_bus_space_write_multi_4, NULL, /* write region */ NULL, rmi_pci_bus_space_write_region_2, rmi_pci_bus_space_write_region_4, NULL, /* set multiple */ NULL, NULL, NULL, NULL, /* set region */ NULL, rmi_pci_bus_space_set_region_2, rmi_pci_bus_space_set_region_4, NULL, /* copy */ NULL, rmi_pci_bus_space_copy_region_2, NULL, NULL, /* read (single) stream */ rmi_pci_bus_space_read_stream_1, rmi_pci_bus_space_read_stream_2, rmi_pci_bus_space_read_stream_4, NULL, /* read multiple stream */ rmi_pci_bus_space_read_multi_stream_1, rmi_pci_bus_space_read_multi_stream_2, rmi_pci_bus_space_read_multi_stream_4, NULL, /* read region stream */ rmi_pci_bus_space_read_region_1, rmi_pci_bus_space_read_region_2, rmi_pci_bus_space_read_region_4, NULL, /* write (single) stream */ rmi_pci_bus_space_write_stream_1, rmi_pci_bus_space_write_stream_2, rmi_pci_bus_space_write_stream_4, NULL, /* write multiple stream */ rmi_pci_bus_space_write_multi_stream_1, rmi_pci_bus_space_write_multi_stream_2, rmi_pci_bus_space_write_multi_stream_4, NULL, /* write region stream */ NULL, rmi_pci_bus_space_write_region_2, rmi_pci_bus_space_write_region_4, NULL, }; /* generic bus_space tag */ bus_space_tag_t rmi_pci_bus_space = &local_rmi_pci_bus_space; /* * Map a region of device bus space into CPU virtual address space. */ static int rmi_pci_bus_space_map(void *t __unused, bus_addr_t addr, bus_size_t size __unused, int flags __unused, bus_space_handle_t * bshp) { *bshp = addr; return (0); } /* * Unmap a region of device bus space. */ static void rmi_pci_bus_space_unmap(void *t __unused, bus_space_handle_t bsh __unused, bus_size_t size __unused) { } /* * Get a new handle for a subregion of an already-mapped area of bus space. */ static int rmi_pci_bus_space_subregion(void *t __unused, bus_space_handle_t bsh, bus_size_t offset, bus_size_t size __unused, bus_space_handle_t * nbshp) { *nbshp = bsh + offset; return (0); } /* * Read a 1, 2, 4, or 8 byte quantity from bus space * described by tag/handle/offset. */ static u_int8_t rmi_pci_bus_space_read_1(void *tag, bus_space_handle_t handle, bus_size_t offset) { return (u_int8_t) (*(volatile u_int8_t *)(handle + offset)); } static u_int16_t rmi_pci_bus_space_read_2(void *tag, bus_space_handle_t handle, bus_size_t offset) { u_int16_t value; value = *(volatile u_int16_t *)(handle + offset); return bswap16(value); } static u_int32_t rmi_pci_bus_space_read_4(void *tag, bus_space_handle_t handle, bus_size_t offset) { uint32_t value; value = *(volatile u_int32_t *)(handle + offset); return bswap32(value); } /* * Read `count' 1, 2, 4, or 8 byte quantities from bus space * described by tag/handle/offset and copy into buffer provided. */ static void rmi_pci_bus_space_read_multi_1(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int8_t * addr, size_t count) { while (count--) { *addr = *(volatile u_int8_t *)(handle + offset); addr++; } } static void rmi_pci_bus_space_read_multi_2(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int16_t * addr, size_t count) { while (count--) { *addr = *(volatile u_int16_t *)(handle + offset); *addr = bswap16(*addr); addr++; } } static void rmi_pci_bus_space_read_multi_4(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int32_t * addr, size_t count) { while (count--) { *addr = *(volatile u_int32_t *)(handle + offset); *addr = bswap32(*addr); addr++; } } /* * Write the 1, 2, 4, or 8 byte value `value' to bus space * described by tag/handle/offset. */ static void rmi_pci_bus_space_write_1(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int8_t value) { mips_sync(); *(volatile u_int8_t *)(handle + offset) = value; } static void rmi_pci_bus_space_write_2(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int16_t value) { mips_sync(); *(volatile u_int16_t *)(handle + offset) = bswap16(value); } static void rmi_pci_bus_space_write_4(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int32_t value) { mips_sync(); *(volatile u_int32_t *)(handle + offset) = bswap32(value); } /* * Write `count' 1, 2, 4, or 8 byte quantities from the buffer * provided to bus space described by tag/handle/offset. */ static void rmi_pci_bus_space_write_multi_1(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int8_t * addr, size_t count) { mips_sync(); while (count--) { (*(volatile u_int8_t *)(handle + offset)) = *addr; addr++; } } static void rmi_pci_bus_space_write_multi_2(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int16_t * addr, size_t count) { mips_sync(); while (count--) { (*(volatile u_int16_t *)(handle + offset)) = bswap16(*addr); addr++; } } static void rmi_pci_bus_space_write_multi_4(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int32_t * addr, size_t count) { mips_sync(); while (count--) { (*(volatile u_int32_t *)(handle + offset)) = bswap32(*addr); addr++; } } /* * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described * by tag/handle starting at `offset'. */ static void rmi_pci_bus_space_set_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int16_t value, size_t count) { bus_addr_t addr = bsh + offset; for (; count != 0; count--, addr += 2) (*(volatile u_int16_t *)(addr)) = value; } static void rmi_pci_bus_space_set_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int32_t value, size_t count) { bus_addr_t addr = bsh + offset; for (; count != 0; count--, addr += 4) (*(volatile u_int32_t *)(addr)) = value; } /* * Copy `count' 1, 2, 4, or 8 byte values from bus space starting * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2. */ static void rmi_pci_bus_space_copy_region_2(void *t, bus_space_handle_t bsh1, bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, size_t count) { TODO(); } /* * Read `count' 1, 2, 4, or 8 byte quantities from bus space * described by tag/handle/offset and copy into buffer provided. */ u_int8_t rmi_pci_bus_space_read_stream_1(void *t, bus_space_handle_t handle, bus_size_t offset) { return *((volatile u_int8_t *)(handle + offset)); } static u_int16_t rmi_pci_bus_space_read_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset) { return *(volatile u_int16_t *)(handle + offset); } static u_int32_t rmi_pci_bus_space_read_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset) { return (*(volatile u_int32_t *)(handle + offset)); } static void rmi_pci_bus_space_read_multi_stream_1(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int8_t * addr, size_t count) { while (count--) { *addr = (*(volatile u_int8_t *)(handle + offset)); addr++; } } static void rmi_pci_bus_space_read_multi_stream_2(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int16_t * addr, size_t count) { while (count--) { *addr = (*(volatile u_int16_t *)(handle + offset)); addr++; } } static void rmi_pci_bus_space_read_multi_stream_4(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int32_t * addr, size_t count) { while (count--) { *addr = (*(volatile u_int32_t *)(handle + offset)); addr++; } } /* * Read `count' 1, 2, 4, or 8 byte quantities from bus space * described by tag/handle and starting at `offset' and copy into * buffer provided. */ void rmi_pci_bus_space_read_region_1(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int8_t * addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { *addr++ = (*(volatile u_int8_t *)(baddr)); baddr += 1; } } void rmi_pci_bus_space_read_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int16_t * addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { *addr++ = (*(volatile u_int16_t *)(baddr)); baddr += 2; } } void rmi_pci_bus_space_read_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int32_t * addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { *addr++ = (*(volatile u_int32_t *)(baddr)); baddr += 4; } } void rmi_pci_bus_space_write_stream_1(void *t, bus_space_handle_t handle, bus_size_t offset, u_int8_t value) { mips_sync(); *(volatile u_int8_t *)(handle + offset) = value; } static void rmi_pci_bus_space_write_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset, u_int16_t value) { mips_sync(); *(volatile u_int16_t *)(handle + offset) = value; } static void rmi_pci_bus_space_write_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset, u_int32_t value) { mips_sync(); *(volatile u_int32_t *)(handle + offset) = value; } static void rmi_pci_bus_space_write_multi_stream_1(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int8_t * addr, size_t count) { mips_sync(); while (count--) { (*(volatile u_int8_t *)(handle + offset)) = *addr; addr++; } } static void rmi_pci_bus_space_write_multi_stream_2(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int16_t * addr, size_t count) { mips_sync(); while (count--) { (*(volatile u_int16_t *)(handle + offset)) = *addr; addr++; } } static void rmi_pci_bus_space_write_multi_stream_4(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int32_t * addr, size_t count) { mips_sync(); while (count--) { (*(volatile u_int32_t *)(handle + offset)) = *addr; addr++; } } void rmi_pci_bus_space_write_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, const u_int16_t * addr, size_t count) { bus_addr_t baddr = (bus_addr_t) bsh + offset; while (count--) { (*(volatile u_int16_t *)(baddr)) = *addr; addr++; baddr += 2; } } void rmi_pci_bus_space_write_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, const u_int32_t * addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { (*(volatile u_int32_t *)(baddr)) = *addr; addr++; baddr += 4; } } static void rmi_pci_bus_space_barrier(void *tag __unused, bus_space_handle_t bsh __unused, bus_size_t offset __unused, bus_size_t len __unused, int flags) { } Index: head/sys/mips/nlm/clock.h =================================================================== --- head/sys/mips/nlm/clock.h (revision 326258) +++ head/sys/mips/nlm/clock.h (revision 326259) @@ -1,42 +1,44 @@ /*- + * 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 * $FreeBSD$ */ #ifndef _RMI_CLOCK_H_ #define _RMI_CLOCK_H_ #define XLP_PIC_HZ 133000000U #define XLP_CPU_HZ (nlm_cpu_frequency) void count_compare_clockhandler(struct trapframe *); void pic_hardclockhandler(struct trapframe *); void pic_timecounthandler(struct trapframe *); #endif /* _RMI_CLOCK_H_ */ Index: head/sys/mips/nlm/cms.c =================================================================== --- head/sys/mips/nlm/cms.c (revision 326258) +++ head/sys/mips/nlm/cms.c (revision 326259) @@ -1,496 +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) { 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: head/sys/mips/nlm/dev/net/mdio.c =================================================================== --- head/sys/mips/nlm/dev/net/mdio.c (revision 326258) +++ head/sys/mips/nlm/dev/net/mdio.c (revision 326259) @@ -1,333 +1,335 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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 /* Internal MDIO READ/WRITE Routines */ int nlm_int_gmac_mdio_read(uint64_t nae_base, int bus, int block, int intf_type, int phyaddr, int regidx) { uint32_t mdio_ld_cmd; uint32_t ctrlval; ctrlval = INT_MDIO_CTRL_SMP | (phyaddr << INT_MDIO_CTRL_PHYADDR_POS) | (regidx << INT_MDIO_CTRL_DEVTYPE_POS) | (2 << INT_MDIO_CTRL_OP_POS) | (1 << INT_MDIO_CTRL_ST_POS) | (7 << INT_MDIO_CTRL_XDIV_POS) | (2 << INT_MDIO_CTRL_TA_POS) | (2 << INT_MDIO_CTRL_MIIM_POS) | (1 << INT_MDIO_CTRL_MCDIV_POS); mdio_ld_cmd = nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4))); if (mdio_ld_cmd & INT_MDIO_CTRL_CMD_LOAD) { nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus*4)), (mdio_ld_cmd & ~INT_MDIO_CTRL_CMD_LOAD)); } nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)), ctrlval); /* Toggle Load Cmd Bit */ nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)), ctrlval | (1 << INT_MDIO_CTRL_LOAD_POS)); /* poll master busy bit until it is not busy */ while(nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_RD_STAT + bus * 4))) & INT_MDIO_STAT_MBSY) { } nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)), ctrlval); /* Read the data back */ return nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_RD_STAT + bus * 4))); } /* Internal MDIO WRITE Routines */ int nlm_int_gmac_mdio_write(uint64_t nae_base, int bus, int block, int intf_type, int phyaddr, int regidx, uint16_t val) { uint32_t mdio_ld_cmd; uint32_t ctrlval; ctrlval = INT_MDIO_CTRL_SMP | (phyaddr << INT_MDIO_CTRL_PHYADDR_POS) | (regidx << INT_MDIO_CTRL_DEVTYPE_POS) | (1 << INT_MDIO_CTRL_OP_POS) | (1 << INT_MDIO_CTRL_ST_POS) | (7 << INT_MDIO_CTRL_XDIV_POS) | (2 << INT_MDIO_CTRL_TA_POS) | (1 << INT_MDIO_CTRL_MIIM_POS) | (1 << INT_MDIO_CTRL_MCDIV_POS); mdio_ld_cmd = nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4))); if (mdio_ld_cmd & INT_MDIO_CTRL_CMD_LOAD) { nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus*4)), (mdio_ld_cmd & ~INT_MDIO_CTRL_CMD_LOAD)); } /* load data into ctrl data reg */ nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL_DATA + bus * 4)), val); nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)), ctrlval); nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)), ctrlval | (1 << INT_MDIO_CTRL_LOAD_POS)); /* poll master busy bit until it is not busy */ while(nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_RD_STAT + bus * 4))) & INT_MDIO_STAT_MBSY) { } nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)), ctrlval); return (0); } int nlm_int_gmac_mdio_reset(uint64_t nae_base, int bus, int block, int intf_type) { uint32_t val; val = (7 << INT_MDIO_CTRL_XDIV_POS) | (1 << INT_MDIO_CTRL_MCDIV_POS) | (INT_MDIO_CTRL_SMP); nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)), val | INT_MDIO_CTRL_RST); nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (INT_MDIO_CTRL + bus * 4)), val); return (0); } /* * nae_gmac_mdio_read - Read sgmii phy register * * Input parameters: * bus - bus number, nae has two external gmac bus: 0 and 1 * phyaddr - PHY's address * regidx - index of register to read * * Return value: * value read (16 bits), or 0xffffffff if an error occurred. */ int nlm_gmac_mdio_read(uint64_t nae_base, int bus, int block, int intf_type, int phyaddr, int regidx) { uint32_t mdio_ld_cmd; uint32_t ctrlval; mdio_ld_cmd = nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL + bus * 4))); if (mdio_ld_cmd & EXT_G_MDIO_CMD_LCD) { nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)), (mdio_ld_cmd & ~EXT_G_MDIO_CMD_LCD)); while(nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_RD_STAT + bus * 4))) & EXT_G_MDIO_STAT_MBSY); } ctrlval = EXT_G_MDIO_CMD_SP | (phyaddr << EXT_G_MDIO_PHYADDR_POS) | (regidx << EXT_G_MDIO_REGADDR_POS); if (nlm_is_xlp8xx_ax() || nlm_is_xlp8xx_b0() || nlm_is_xlp3xx_ax()) ctrlval |= EXT_G_MDIO_DIV; else ctrlval |= EXT_G_MDIO_DIV_WITH_HW_DIV64; nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)), ctrlval); nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)), ctrlval | (1<<18)); DELAY(1000); /* poll master busy bit until it is not busy */ while(nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_RD_STAT + bus * 4))) & EXT_G_MDIO_STAT_MBSY); nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)), ctrlval); /* Read the data back */ return nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_RD_STAT + bus * 4))); } /* * nae_gmac_mdio_write -Write sgmac mii PHY register. * * Input parameters: * bus - bus number, nae has two external gmac bus: 0 and 1 * phyaddr - PHY to use * regidx - register within the PHY * val - data to write to register * * Return value: * 0 - success */ int nlm_gmac_mdio_write(uint64_t nae_base, int bus, int block, int intf_type, int phyaddr, int regidx, uint16_t val) { uint32_t mdio_ld_cmd; uint32_t ctrlval; mdio_ld_cmd = nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL + bus * 4))); if (mdio_ld_cmd & EXT_G_MDIO_CMD_LCD) { nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)), (mdio_ld_cmd & ~EXT_G_MDIO_CMD_LCD)); while(nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_RD_STAT + bus * 4))) & EXT_G_MDIO_STAT_MBSY); } /* load data into ctrl data reg */ nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL_DATA+bus*4)), val); ctrlval = EXT_G_MDIO_CMD_SP | (phyaddr << EXT_G_MDIO_PHYADDR_POS) | (regidx << EXT_G_MDIO_REGADDR_POS); if (nlm_is_xlp8xx_ax() || nlm_is_xlp8xx_b0() || nlm_is_xlp3xx_ax()) ctrlval |= EXT_G_MDIO_DIV; else ctrlval |= EXT_G_MDIO_DIV_WITH_HW_DIV64; nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)), ctrlval); nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)), ctrlval | EXT_G_MDIO_CMD_LCD); DELAY(1000); /* poll master busy bit until it is not busy */ while(nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_RD_STAT + bus * 4))) & EXT_G_MDIO_STAT_MBSY); nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4)), ctrlval); return (0); } /* * nae_gmac_mdio_reset -Reset sgmii mdio module. * * Input parameters: * bus - bus number, nae has two external gmac bus: 0 and 1 * * Return value: * 0 - success */ int nlm_gmac_mdio_reset(uint64_t nae_base, int bus, int block, int intf_type) { uint32_t ctrlval; ctrlval = nlm_read_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL+bus*4))); if (nlm_is_xlp8xx_ax() || nlm_is_xlp8xx_b0() || nlm_is_xlp3xx_ax()) ctrlval |= EXT_G_MDIO_DIV; else ctrlval |= EXT_G_MDIO_DIV_WITH_HW_DIV64; nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL + bus * 4)), EXT_G_MDIO_MMRST | ctrlval); nlm_write_nae_reg(nae_base, NAE_REG(block, intf_type, (EXT_G0_MDIO_CTRL + bus * 4)), ctrlval); return (0); } /* * nlm_mdio_reset_all : reset all internal and external MDIO */ void nlm_mdio_reset_all(uint64_t nae_base) { /* reset internal MDIO */ nlm_int_gmac_mdio_reset(nae_base, 0, BLOCK_7, LANE_CFG); /* reset external MDIO */ nlm_gmac_mdio_reset(nae_base, 0, BLOCK_7, LANE_CFG); nlm_gmac_mdio_reset(nae_base, 1, BLOCK_7, LANE_CFG); } Index: head/sys/mips/nlm/dev/net/nae.c =================================================================== --- head/sys/mips/nlm/dev/net/nae.c (revision 326258) +++ head/sys/mips/nlm/dev/net/nae.c (revision 326259) @@ -1,1454 +1,1456 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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 void nlm_nae_flush_free_fifo(uint64_t nae_base, int nblocks) { uint32_t data, fifo_mask; fifo_mask = (1 << (4 * nblocks)) - 1; nlm_write_nae_reg(nae_base, NAE_RX_FREE_FIFO_POP, fifo_mask); do { data = nlm_read_nae_reg(nae_base, NAE_RX_FREE_FIFO_POP); } while (data != fifo_mask); nlm_write_nae_reg(nae_base, NAE_RX_FREE_FIFO_POP, 0); } void nlm_program_nae_parser_seq_fifo(uint64_t nae_base, int maxports, struct nae_port_config *cfg) { uint32_t val; int start = 0, size, i; for (i = 0; i < maxports; i++) { size = cfg[i].pseq_fifo_size; val = (((size & 0x1fff) << 17) | ((start & 0xfff) << 5) | (i & 0x1f)); nlm_write_nae_reg(nae_base, NAE_PARSER_SEQ_FIFO_CFG, val); start += size; } } void nlm_setup_rx_cal_cfg(uint64_t nae_base, int total_num_ports, struct nae_port_config *cfg) { int rx_slots = 0, port; int cal_len, cal = 0, last_free = 0; uint32_t val; for (port = 0; port < total_num_ports; port++) { if (cfg[port].rx_slots_reqd) rx_slots += cfg[port].rx_slots_reqd; if (rx_slots > MAX_CAL_SLOTS) { rx_slots = MAX_CAL_SLOTS; break; } } cal_len = rx_slots - 1; do { if (cal >= MAX_CAL_SLOTS) break; last_free = cal; for (port = 0; port < total_num_ports; port++) { if (cfg[port].rx_slots_reqd > 0) { val = (cal_len << 16) | (port << 8) | cal; nlm_write_nae_reg(nae_base, NAE_RX_IF_SLOT_CAL, val); cal++; cfg[port].rx_slots_reqd--; } } if (last_free == cal) break; } while (1); } void nlm_setup_tx_cal_cfg(uint64_t nae_base, int total_num_ports, struct nae_port_config *cfg) { int tx_slots = 0, port; int cal = 0, last_free = 0; uint32_t val; for (port = 0; port < total_num_ports; port++) { if (cfg[port].tx_slots_reqd) tx_slots += cfg[port].tx_slots_reqd; if (tx_slots > MAX_CAL_SLOTS) { tx_slots = MAX_CAL_SLOTS; break; } } nlm_write_nae_reg(nae_base, NAE_EGR_NIOR_CAL_LEN_REG, tx_slots - 1); do { if (cal >= MAX_CAL_SLOTS) break; last_free = cal; for (port = 0; port < total_num_ports; port++) { if (cfg[port].tx_slots_reqd > 0) { val = (port << 7) | (cal << 1) | 1; nlm_write_nae_reg(nae_base, NAE_EGR_NIOR_CRDT_CAL_PROG, val); cal++; cfg[port].tx_slots_reqd--; } } if (last_free == cal) break; } while (1); } void nlm_deflate_frin_fifo_carving(uint64_t nae_base, int total_num_ports) { const int minimum_size = 8; uint32_t value; int intf, start; for (intf = 0; intf < total_num_ports; intf++) { start = minimum_size * intf; value = (minimum_size << 20) | (start << 8) | (intf); nlm_write_nae_reg(nae_base, NAE_FREE_IN_FIFO_CFG, value); } } void nlm_reset_nae(int node) { uint64_t sysbase; uint64_t nae_base; uint64_t nae_pcibase; uint32_t rx_config; uint32_t bar0; int reset_bit; sysbase = nlm_get_sys_regbase(node); nae_base = nlm_get_nae_regbase(node); nae_pcibase = nlm_get_nae_pcibase(node); bar0 = nlm_read_pci_reg(nae_pcibase, XLP_PCI_CFGREG4); #if BYTE_ORDER == LITTLE_ENDIAN if (nlm_is_xlp8xx_ax()) { uint8_t val; /* membar fixup */ val = (bar0 >> 24) & 0xff; bar0 = (val << 24) | (val << 16) | (val << 8) | val; } #endif if (nlm_is_xlp3xx()) reset_bit = 6; else reset_bit = 9; /* Reset NAE */ nlm_write_sys_reg(sysbase, SYS_RESET, (1 << reset_bit)); /* XXXJC - 1s delay here may be too high */ DELAY(1000000); nlm_write_sys_reg(sysbase, SYS_RESET, (0 << reset_bit)); DELAY(1000000); rx_config = nlm_read_nae_reg(nae_base, NAE_RX_CONFIG); nlm_write_pci_reg(nae_pcibase, XLP_PCI_CFGREG4, bar0); } void nlm_setup_poe_class_config(uint64_t nae_base, int max_poe_classes, int num_contexts, int *poe_cl_tbl) { uint32_t val; int i, max_poe_class_ctxt_tbl_sz; max_poe_class_ctxt_tbl_sz = num_contexts/max_poe_classes; for (i = 0; i < max_poe_class_ctxt_tbl_sz; i++) { val = (poe_cl_tbl[(i/max_poe_classes) & 0x7] << 8) | i; nlm_write_nae_reg(nae_base, NAE_POE_CLASS_SETUP_CFG, val); } } void nlm_setup_vfbid_mapping(uint64_t nae_base) { uint32_t val; int dest_vc, vfbid; /* 127 is max vfbid */ for (vfbid = 127; vfbid >= 0; vfbid--) { dest_vc = nlm_get_vfbid_mapping(vfbid); if (dest_vc < 0) continue; val = (dest_vc << 16) | (vfbid << 4) | 1; nlm_write_nae_reg(nae_base, NAE_VFBID_DESTMAP_CMD, val); } } void nlm_setup_flow_crc_poly(uint64_t nae_base, uint32_t poly) { nlm_write_nae_reg(nae_base, NAE_FLOW_CRC16_POLY_CFG, poly); } void nlm_setup_iface_fifo_cfg(uint64_t nae_base, int maxports, struct nae_port_config *cfg) { uint32_t reg; int fifo_xoff_thresh = 12; int i, size; int cur_iface_start = 0; for (i = 0; i < maxports; i++) { size = cfg[i].iface_fifo_size; reg = ((fifo_xoff_thresh << 25) | ((size & 0x1ff) << 16) | ((cur_iface_start & 0xff) << 8) | (i & 0x1f)); nlm_write_nae_reg(nae_base, NAE_IFACE_FIFO_CFG, reg); cur_iface_start += size; } } void nlm_setup_rx_base_config(uint64_t nae_base, int maxports, struct nae_port_config *cfg) { int base = 0; uint32_t val; int i; int id; for (i = 0; i < (maxports/2); i++) { id = 0x12 + i; /* RX_IF_BASE_CONFIG0 */ val = (base & 0x3ff); base += cfg[(i * 2)].num_channels; val |= ((base & 0x3ff) << 16); base += cfg[(i * 2) + 1].num_channels; nlm_write_nae_reg(nae_base, NAE_REG(7, 0, id), val); } } void nlm_setup_rx_buf_config(uint64_t nae_base, int maxports, struct nae_port_config *cfg) { uint32_t val; int i, sz, k; int context = 0; int base = 0; for (i = 0; i < maxports; i++) { if (cfg[i].type == UNKNOWN) continue; for (k = 0; k < cfg[i].num_channels; k++) { /* write index (context num) */ nlm_write_nae_reg(nae_base, NAE_RXBUF_BASE_DPTH_ADDR, (context+k)); /* write value (rx buf sizes) */ sz = cfg[i].rxbuf_size; val = 0x80000000 | ((base << 2) & 0x3fff); /* base */ val |= (((sz << 2) & 0x3fff) << 16); /* size */ nlm_write_nae_reg(nae_base, NAE_RXBUF_BASE_DPTH, val); nlm_write_nae_reg(nae_base, NAE_RXBUF_BASE_DPTH, (0x7fffffff & val)); base += sz; } context += cfg[i].num_channels; } } void nlm_setup_freein_fifo_cfg(uint64_t nae_base, struct nae_port_config *cfg) { int size, i; uint32_t reg; int start = 0, maxbufpool; if (nlm_is_xlp8xx()) maxbufpool = MAX_FREE_FIFO_POOL_8XX; else maxbufpool = MAX_FREE_FIFO_POOL_3XX; for (i = 0; i < maxbufpool; i++) { /* Each entry represents 2 descs; hence division by 2 */ size = (cfg[i].num_free_descs / 2); if (size == 0) size = 8; reg = ((size & 0x3ff ) << 20) | /* fcSize */ ((start & 0x1ff) << 8) | /* fcStart */ (i & 0x1f); nlm_write_nae_reg(nae_base, NAE_FREE_IN_FIFO_CFG, reg); start += size; } } /* XXX function name */ int nlm_get_flow_mask(int num_ports) { const int max_bits = 5; /* upto 32 ports */ int i; /* Compute the number of bits to needed to * represent all the ports */ for (i = 0; i < max_bits; i++) { if (num_ports <= (2 << i)) return (i + 1); } return (max_bits); } void nlm_program_flow_cfg(uint64_t nae_base, int port, uint32_t cur_flow_base, uint32_t flow_mask) { uint32_t val; val = (cur_flow_base << 16) | port; val |= ((flow_mask & 0x1f) << 8); nlm_write_nae_reg(nae_base, NAE_FLOW_BASEMASK_CFG, val); } void xlp_ax_nae_lane_reset_txpll(uint64_t nae_base, int block, int lane_ctrl, int mode) { uint32_t val = 0, saved_data; int rext_sel = 0; val = PHY_LANE_CTRL_RST | PHY_LANE_CTRL_PWRDOWN | (mode << PHY_LANE_CTRL_PHYMODE_POS); /* set comma bypass for XAUI */ if (mode != PHYMODE_SGMII) val |= PHY_LANE_CTRL_BPC_XAUI; nlm_write_nae_reg(nae_base, NAE_REG(block, PHY, lane_ctrl), val); if (lane_ctrl != 4) { rext_sel = (1 << 23); if (mode != PHYMODE_SGMII) rext_sel |= PHY_LANE_CTRL_BPC_XAUI; val = nlm_read_nae_reg(nae_base, NAE_REG(block, PHY, lane_ctrl)); val &= ~PHY_LANE_CTRL_RST; val |= rext_sel; /* Resetting PMA for non-zero lanes */ nlm_write_nae_reg(nae_base, NAE_REG(block, PHY, lane_ctrl), val); DELAY(20000); /* 20 ms delay, XXXJC: needed? */ val |= PHY_LANE_CTRL_RST; nlm_write_nae_reg(nae_base, NAE_REG(block, PHY, lane_ctrl), val); val = 0; } /* Come out of reset for TXPLL */ saved_data = nlm_read_nae_reg(nae_base, NAE_REG(block, PHY, lane_ctrl)) & 0xFFC00000; nlm_write_nae_reg(nae_base, NAE_REG(block, PHY, lane_ctrl), (0x66 << PHY_LANE_CTRL_ADDR_POS) | PHY_LANE_CTRL_CMD_READ | PHY_LANE_CTRL_CMD_START | PHY_LANE_CTRL_RST | rext_sel | val ); while (((val = nlm_read_nae_reg(nae_base, NAE_REG(block, PHY, lane_ctrl))) & PHY_LANE_CTRL_CMD_PENDING)); val &= 0xFF; /* set bit[4] to 0 */ val &= ~(1 << 4); nlm_write_nae_reg(nae_base, NAE_REG(block, PHY, lane_ctrl), (0x66 << PHY_LANE_CTRL_ADDR_POS) | PHY_LANE_CTRL_CMD_WRITE | PHY_LANE_CTRL_CMD_START | (0x0 << 19) /* (0x4 << 19) */ | rext_sel | saved_data | val ); /* re-do */ nlm_write_nae_reg(nae_base, NAE_REG(block, PHY, lane_ctrl), (0x66 << PHY_LANE_CTRL_ADDR_POS) | PHY_LANE_CTRL_CMD_WRITE | PHY_LANE_CTRL_CMD_START | (0x0 << 19) /* (0x4 << 19) */ | rext_sel | saved_data | val ); while (!((val = nlm_read_nae_reg(nae_base, NAE_REG(block, PHY, (lane_ctrl - PHY_LANE_0_CTRL)))) & PHY_LANE_STAT_PCR)); /* Clear the Power Down bit */ val = nlm_read_nae_reg(nae_base, NAE_REG(block, PHY, lane_ctrl)); val &= ~((1 << 29) | (0x7ffff)); nlm_write_nae_reg(nae_base, NAE_REG(block, PHY, lane_ctrl), (rext_sel | val)); } void xlp_nae_lane_reset_txpll(uint64_t nae_base, int block, int lane_ctrl, int mode) { uint32_t val = 0; int rext_sel = 0; if (lane_ctrl != 4) rext_sel = (1 << 23); val = nlm_read_nae_reg(nae_base, NAE_REG(block, PHY, lane_ctrl)); /* set comma bypass for XAUI */ if (mode != PHYMODE_SGMII) val |= PHY_LANE_CTRL_BPC_XAUI; val |= 0x100000; val |= (mode << PHY_LANE_CTRL_PHYMODE_POS); val &= ~(0x20000); nlm_write_nae_reg(nae_base, NAE_REG(block, PHY, lane_ctrl), val); val = nlm_read_nae_reg(nae_base, NAE_REG(block, PHY, lane_ctrl)); val |= 0x40000000; nlm_write_nae_reg(nae_base, NAE_REG(block, PHY, lane_ctrl), val); /* clear the power down bit */ val = nlm_read_nae_reg(nae_base, NAE_REG(block, PHY, lane_ctrl)); val &= ~( (1 << 29) | (0x7ffff)); nlm_write_nae_reg(nae_base, NAE_REG(block, PHY, lane_ctrl), rext_sel | val); } void xlp_nae_config_lane_gmac(uint64_t nae_base, int cplx_mask) { int block, lane_ctrl; int cplx_lane_enable; int lane_enable = 0; cplx_lane_enable = LM_SGMII | (LM_SGMII << 4) | (LM_SGMII << 8) | (LM_SGMII << 12); /* Lane mode progamming */ block = 7; /* Complexes 0, 1 */ if (cplx_mask & 0x1) lane_enable |= cplx_lane_enable; if (cplx_mask & 0x2) lane_enable |= (cplx_lane_enable << 16); if (lane_enable) { nlm_write_nae_reg(nae_base, NAE_REG(block, LANE_CFG, LANE_CFG_CPLX_0_1), lane_enable); lane_enable = 0; } /* Complexes 2 3 */ if (cplx_mask & 0x4) lane_enable |= cplx_lane_enable; if (cplx_mask & 0x8) lane_enable |= (cplx_lane_enable << 16); nlm_write_nae_reg(nae_base, NAE_REG(block, LANE_CFG, LANE_CFG_CPLX_2_3), lane_enable); /* complex 4 */ /* XXXJC : fix duplicate code */ if (cplx_mask & 0x10) { nlm_write_nae_reg(nae_base, NAE_REG(block, LANE_CFG, LANE_CFG_CPLX_4), ((LM_SGMII << 4) | LM_SGMII)); for (lane_ctrl = PHY_LANE_0_CTRL; lane_ctrl <= PHY_LANE_1_CTRL; lane_ctrl++) { if (!nlm_is_xlp8xx_ax()) xlp_nae_lane_reset_txpll(nae_base, 4, lane_ctrl, PHYMODE_SGMII); else xlp_ax_nae_lane_reset_txpll(nae_base, 4, lane_ctrl, PHYMODE_SGMII); } } for (block = 0; block < 4; block++) { if ((cplx_mask & (1 << block)) == 0) continue; for (lane_ctrl = PHY_LANE_0_CTRL; lane_ctrl <= PHY_LANE_3_CTRL; lane_ctrl++) { if (!nlm_is_xlp8xx_ax()) xlp_nae_lane_reset_txpll(nae_base, block, lane_ctrl, PHYMODE_SGMII); else xlp_ax_nae_lane_reset_txpll(nae_base, block, lane_ctrl, PHYMODE_SGMII); } } } void config_egress_fifo_carvings(uint64_t nae_base, int hwport, int start_ctxt, int num_ctxts, int max_ctxts, struct nae_port_config *cfg) { static uint32_t cur_start[6] = {0, 0, 0, 0, 0, 0}; uint32_t data = 0; uint32_t start = 0, size, offset; int i, limit; limit = start_ctxt + num_ctxts; /* Stage 2 FIFO */ start = cur_start[0]; for (i = start_ctxt; i < limit; i++) { size = cfg[hwport].stg2_fifo_size / max_ctxts; if (size) offset = size - 1; else offset = size; if (offset > cfg[hwport].max_stg2_offset) offset = cfg[hwport].max_stg2_offset; data = offset << 23 | start << 11 | i << 1 | 1; nlm_write_nae_reg(nae_base, NAE_STG2_PMEM_PROG, data); start += size; } cur_start[0] = start; /* EH FIFO */ start = cur_start[1]; for (i = start_ctxt; i < limit; i++) { size = cfg[hwport].eh_fifo_size / max_ctxts; if (size) offset = size - 1; else offset = size ; if (offset > cfg[hwport].max_eh_offset) offset = cfg[hwport].max_eh_offset; data = offset << 23 | start << 11 | i << 1 | 1; nlm_write_nae_reg(nae_base, NAE_EH_PMEM_PROG, data); start += size; } cur_start[1] = start; /* FROUT FIFO */ start = cur_start[2]; for (i = start_ctxt; i < limit; i++) { size = cfg[hwport].frout_fifo_size / max_ctxts; if (size) offset = size - 1; else offset = size ; if (offset > cfg[hwport].max_frout_offset) offset = cfg[hwport].max_frout_offset; data = offset << 23 | start << 11 | i << 1 | 1; nlm_write_nae_reg(nae_base, NAE_FREE_PMEM_PROG, data); start += size; } cur_start[2] = start; /* MS FIFO */ start = cur_start[3]; for (i = start_ctxt; i < limit; i++) { size = cfg[hwport].ms_fifo_size / max_ctxts; if (size) offset = size - 1; else offset = size ; if (offset > cfg[hwport].max_ms_offset) offset = cfg[hwport].max_ms_offset; data = offset << 22 | /* FIXME in PRM */ start << 11 | i << 1 | 1; nlm_write_nae_reg(nae_base, NAE_STR_PMEM_CMD, data); start += size; } cur_start[3] = start; /* PKT FIFO */ start = cur_start[4]; for (i = start_ctxt; i < limit; i++) { size = cfg[hwport].pkt_fifo_size / max_ctxts; if (size) offset = size - 1; else offset = size ; if (offset > cfg[hwport].max_pmem_offset) offset = cfg[hwport].max_pmem_offset; nlm_write_nae_reg(nae_base, NAE_TX_PKT_PMEM_CMD1, offset); data = start << 11 | i << 1 | 1; nlm_write_nae_reg(nae_base, NAE_TX_PKT_PMEM_CMD0, data); start += size; } cur_start[4] = start; /* PKT LEN FIFO */ start = cur_start[5]; for (i = start_ctxt; i < limit; i++) { size = cfg[hwport].pktlen_fifo_size / max_ctxts; if (size) offset = size - 1; else offset = size ; data = offset << 22 | start << 11 | i << 1 | 1; nlm_write_nae_reg(nae_base, NAE_TX_PKTLEN_PMEM_CMD, data); start += size; } cur_start[5] = start; } void config_egress_fifo_credits(uint64_t nae_base, int hwport, int start_ctxt, int num_ctxts, int max_ctxts, struct nae_port_config *cfg) { uint32_t data, credit, max_credit; int i, limit; limit = start_ctxt + num_ctxts; /* Stage1 -> Stage2 */ max_credit = cfg[hwport].max_stg2_offset + 1; for (i = start_ctxt; i < limit; i++) { credit = cfg[hwport].stg1_2_credit / max_ctxts; if (credit > max_credit) credit = max_credit; data = credit << 16 | i << 4 | 1; nlm_write_nae_reg(nae_base, NAE_STG1_STG2CRDT_CMD, data); } /* Stage2 -> EH */ max_credit = cfg[hwport].max_eh_offset + 1; for (i = start_ctxt; i < limit; i++) { credit = cfg[hwport].stg2_eh_credit / max_ctxts; if (credit > max_credit) credit = max_credit; data = credit << 16 | i << 4 | 1; nlm_write_nae_reg(nae_base, NAE_STG2_EHCRDT_CMD, data); } /* Stage2 -> Frout */ max_credit = cfg[hwport].max_frout_offset + 1; for (i = start_ctxt; i < limit; i++) { credit = cfg[hwport].stg2_frout_credit / max_ctxts; if (credit > max_credit) credit = max_credit; data = credit << 16 | i << 4 | 1; nlm_write_nae_reg(nae_base, NAE_EH_FREECRDT_CMD, data); } /* Stage2 -> MS */ max_credit = cfg[hwport].max_ms_offset + 1; for (i = start_ctxt; i < limit; i++) { credit = cfg[hwport].stg2_ms_credit / max_ctxts; if (credit > max_credit) credit = max_credit; data = credit << 16 | i << 4 | 1; nlm_write_nae_reg(nae_base, NAE_STG2_STRCRDT_CMD, data); } } void nlm_config_freein_fifo_uniq_cfg(uint64_t nae_base, int port, int nblock_free_desc) { uint32_t val; int size_in_clines; size_in_clines = (nblock_free_desc / NAE_CACHELINE_SIZE); val = (size_in_clines << 8) | (port & 0x1f); nlm_write_nae_reg(nae_base, NAE_FREEIN_FIFO_UNIQ_SZ_CFG, val); } /* XXXJC: redundant, see ucore_spray_config() */ void nlm_config_ucore_iface_mask_cfg(uint64_t nae_base, int port, int nblock_ucore_mask) { uint32_t val; val = ( 0x1U << 31) | ((nblock_ucore_mask & 0xffff) << 8) | (port & 0x1f); nlm_write_nae_reg(nae_base, NAE_UCORE_IFACEMASK_CFG, val); } int nlm_nae_init_netior(uint64_t nae_base, int nblocks) { uint32_t ctrl1, ctrl2, ctrl3; if (nblocks == 5) ctrl3 = 0x07 << 18; else ctrl3 = 0; switch (nblocks) { case 2: ctrl1 = 0xff; ctrl2 = 0x0707; break; case 4: case 5: ctrl1 = 0xfffff; ctrl2 = 0x07070707; break; default: printf("WARNING: unsupported blocks %d\n", nblocks); return (-1); } nlm_write_nae_reg(nae_base, NAE_LANE_CFG_SOFTRESET, 0); nlm_write_nae_reg(nae_base, NAE_NETIOR_MISC_CTRL3, ctrl3); nlm_write_nae_reg(nae_base, NAE_NETIOR_MISC_CTRL2, ctrl2); nlm_write_nae_reg(nae_base, NAE_NETIOR_MISC_CTRL1, ctrl1); nlm_write_nae_reg(nae_base, NAE_NETIOR_MISC_CTRL1, 0x0); return (0); } void nlm_nae_init_ingress(uint64_t nae_base, uint32_t desc_size) { uint32_t rx_cfg; uint32_t parser_threshold = 384; rx_cfg = nlm_read_nae_reg(nae_base, NAE_RX_CONFIG); rx_cfg &= ~(0x3 << 1); /* reset max message size */ rx_cfg &= ~(0xff << 4); /* clear freein desc cluster size */ rx_cfg &= ~(0x3f << 24); /* reset rx status mask */ /*XXX: why not 7f */ rx_cfg |= 1; /* rx enable */ rx_cfg |= (0x0 << 1); /* max message size */ rx_cfg |= (0x43 & 0x7f) << 24; /* rx status mask */ rx_cfg |= ((desc_size / 64) & 0xff) << 4; /* freein desc cluster size */ nlm_write_nae_reg(nae_base, NAE_RX_CONFIG, rx_cfg); nlm_write_nae_reg(nae_base, NAE_PARSER_CONFIG, (parser_threshold & 0x3ff) | (((parser_threshold / desc_size) + 1) & 0xff) << 12 | (((parser_threshold / 64) % desc_size) & 0xff) << 20); /*nlm_write_nae_reg(nae_base, NAE_RX_FREE_FIFO_THRESH, 33);*/ } void nlm_nae_init_egress(uint64_t nae_base) { uint32_t tx_cfg; tx_cfg = nlm_read_nae_reg(nae_base, NAE_TX_CONFIG); if (!nlm_is_xlp8xx_ax()) { nlm_write_nae_reg(nae_base, NAE_TX_CONFIG, tx_cfg | 0x1 | /* tx enable */ 0x2 | /* tx ace */ 0x4 | /* tx compatible */ (1 << 3)); } else { nlm_write_nae_reg(nae_base, NAE_TX_CONFIG, tx_cfg | 0x1 | /* tx enable */ 0x2); /* tx ace */ } } uint32_t ucore_spray_config(uint32_t interface, uint32_t ucore_mask, int cmd) { return ((cmd & 0x1) << 31) | ((ucore_mask & 0xffff) << 8) | (interface & 0x1f); } void nlm_nae_init_ucore(uint64_t nae_base, int if_num, u_int ucore_mask) { uint32_t ucfg; ucfg = ucore_spray_config(if_num, ucore_mask, 1); /* 1 : write */ nlm_write_nae_reg(nae_base, NAE_UCORE_IFACEMASK_CFG, ucfg); } uint64_t nae_tx_desc(u_int type, u_int rdex, u_int fbid, u_int len, uint64_t addr) { return ((uint64_t)type << 62) | ((uint64_t)rdex << 61) | ((uint64_t)fbid << 54) | ((uint64_t)len << 40) | addr; } void nlm_setup_l2type(uint64_t nae_base, int hwport, uint32_t l2extlen, uint32_t l2extoff, uint32_t extra_hdrsize, uint32_t proto_offset, uint32_t fixed_hdroff, uint32_t l2proto) { uint32_t val; val = ((l2extlen & 0x3f) << 26) | ((l2extoff & 0x3f) << 20) | ((extra_hdrsize & 0x3f) << 14) | ((proto_offset & 0x3f) << 8) | ((fixed_hdroff & 0x3f) << 2) | (l2proto & 0x3); nlm_write_nae_reg(nae_base, (NAE_L2_TYPE_PORT0 + hwport), val); } void nlm_setup_l3ctable_mask(uint64_t nae_base, int hwport, uint32_t ptmask, uint32_t l3portmask) { uint32_t val; val = ((ptmask & 0x1) << 6) | ((l3portmask & 0x1) << 5) | (hwport & 0x1f); nlm_write_nae_reg(nae_base, NAE_L3_CTABLE_MASK0, val); } void nlm_setup_l3ctable_even(uint64_t nae_base, int entry, uint32_t l3hdroff, uint32_t ipcsum_en, uint32_t l4protooff, uint32_t l2proto, uint32_t eth_type) { uint32_t val; val = ((l3hdroff & 0x3f) << 26) | ((l4protooff & 0x3f) << 20) | ((ipcsum_en & 0x1) << 18) | ((l2proto & 0x3) << 16) | (eth_type & 0xffff); nlm_write_nae_reg(nae_base, (NAE_L3CTABLE0 + (entry * 2)), val); } void nlm_setup_l3ctable_odd(uint64_t nae_base, int entry, uint32_t l3off0, uint32_t l3len0, uint32_t l3off1, uint32_t l3len1, uint32_t l3off2, uint32_t l3len2) { uint32_t val; val = ((l3off0 & 0x3f) << 26) | ((l3len0 & 0x1f) << 21) | ((l3off1 & 0x3f) << 15) | ((l3len1 & 0x1f) << 10) | ((l3off2 & 0x3f) << 4) | (l3len2 & 0xf); nlm_write_nae_reg(nae_base, (NAE_L3CTABLE0 + ((entry * 2) + 1)), val); } void nlm_setup_l4ctable_even(uint64_t nae_base, int entry, uint32_t im, uint32_t l3cm, uint32_t l4pm, uint32_t port, uint32_t l3camaddr, uint32_t l4proto) { uint32_t val; val = ((im & 0x1) << 19) | ((l3cm & 0x1) << 18) | ((l4pm & 0x1) << 17) | ((port & 0x1f) << 12) | ((l3camaddr & 0xf) << 8) | (l4proto & 0xff); nlm_write_nae_reg(nae_base, (NAE_L4CTABLE0 + (entry * 2)), val); } void nlm_setup_l4ctable_odd(uint64_t nae_base, int entry, uint32_t l4off0, uint32_t l4len0, uint32_t l4off1, uint32_t l4len1) { uint32_t val; val = ((l4off0 & 0x3f) << 21) | ((l4len0 & 0xf) << 17) | ((l4off1 & 0x3f) << 11) | (l4len1 & 0xf); nlm_write_nae_reg(nae_base, (NAE_L4CTABLE0 + ((entry * 2) + 1)), val); } void nlm_enable_hardware_parser(uint64_t nae_base) { uint32_t val; val = nlm_read_nae_reg(nae_base, NAE_RX_CONFIG); val |= (1 << 12); /* hardware parser enable */ nlm_write_nae_reg(nae_base, NAE_RX_CONFIG, val); /*********************************************** * program L3 CAM table ***********************************************/ /* * entry-0 is ipv4 MPLS type 1 label */ /* l3hdroff = 4 bytes, ether_type = 0x8847 for MPLS_type1 */ nlm_setup_l3ctable_even(nae_base, 0, 4, 1, 9, 1, 0x8847); /* l3off0 (8 bytes) -> l3len0 (1 byte) := ip proto * l3off1 (12 bytes) -> l3len1 (4 bytes) := src ip * l3off2 (16 bytes) -> l3len2 (4 bytes) := dst ip */ nlm_setup_l3ctable_odd(nae_base, 0, 9, 1, 12, 4, 16, 4); /* * entry-1 is for ethernet IPv4 packets */ nlm_setup_l3ctable_even(nae_base, 1, 0, 1, 9, 1, 0x0800); /* l3off0 (8 bytes) -> l3len0 (1 byte) := ip proto * l3off1 (12 bytes) -> l3len1 (4 bytes) := src ip * l3off2 (16 bytes) -> l3len2 (4 bytes) := dst ip */ nlm_setup_l3ctable_odd(nae_base, 1, 9, 1, 12, 4, 16, 4); /* * entry-2 is for ethernet IPv6 packets */ nlm_setup_l3ctable_even(nae_base, 2, 0, 1, 6, 1, 0x86dd); /* l3off0 (6 bytes) -> l3len0 (1 byte) := next header (ip proto) * l3off1 (8 bytes) -> l3len1 (16 bytes) := src ip * l3off2 (24 bytes) -> l3len2 (16 bytes) := dst ip */ nlm_setup_l3ctable_odd(nae_base, 2, 6, 1, 8, 16, 24, 16); /* * entry-3 is for ethernet ARP packets */ nlm_setup_l3ctable_even(nae_base, 3, 0, 0, 9, 1, 0x0806); /* extract 30 bytes from packet start */ nlm_setup_l3ctable_odd(nae_base, 3, 0, 30, 0, 0, 0, 0); /* * entry-4 is for ethernet FCoE packets */ nlm_setup_l3ctable_even(nae_base, 4, 0, 0, 9, 1, 0x8906); /* FCoE packet consists of 4 byte start-of-frame, * and 24 bytes of frame header, followed by * 64 bytes of optional-header (ESP, network..), * 2048 bytes of payload, 36 bytes of optional * "fill bytes" or ESP trailer, 4 bytes of CRC, * and 4 bytes of end-of-frame * We extract the first 4 + 24 = 28 bytes */ nlm_setup_l3ctable_odd(nae_base, 4, 0, 28, 0, 0, 0, 0); /* * entry-5 is for vlan tagged frames (0x8100) */ nlm_setup_l3ctable_even(nae_base, 5, 0, 0, 9, 1, 0x8100); /* we extract 31 bytes from the payload */ nlm_setup_l3ctable_odd(nae_base, 5, 0, 31, 0, 0, 0, 0); /* * entry-6 is for ieee 802.1ad provider bridging * tagged frames (0x88a8) */ nlm_setup_l3ctable_even(nae_base, 6, 0, 0, 9, 1, 0x88a8); /* we extract 31 bytes from the payload */ nlm_setup_l3ctable_odd(nae_base, 6, 0, 31, 0, 0, 0, 0); /* * entry-7 is for Cisco's Q-in-Q tagged frames (0x9100) */ nlm_setup_l3ctable_even(nae_base, 7, 0, 0, 9, 1, 0x9100); /* we extract 31 bytes from the payload */ nlm_setup_l3ctable_odd(nae_base, 7, 0, 31, 0, 0, 0, 0); /* * entry-8 is for Ethernet Jumbo frames (0x8870) */ nlm_setup_l3ctable_even(nae_base, 8, 0, 0, 9, 1, 0x8870); /* we extract 31 bytes from the payload */ nlm_setup_l3ctable_odd(nae_base, 8, 0, 31, 0, 0, 0, 0); /* * entry-9 is for MPLS Multicast frames (0x8848) */ nlm_setup_l3ctable_even(nae_base, 9, 0, 0, 9, 1, 0x8848); /* we extract 31 bytes from the payload */ nlm_setup_l3ctable_odd(nae_base, 9, 0, 31, 0, 0, 0, 0); /* * entry-10 is for IEEE 802.1ae MAC Security frames (0x88e5) */ nlm_setup_l3ctable_even(nae_base, 10, 0, 0, 9, 1, 0x88e5); /* we extract 31 bytes from the payload */ nlm_setup_l3ctable_odd(nae_base, 10, 0, 31, 0, 0, 0, 0); /* * entry-11 is for PTP frames (0x88f7) */ nlm_setup_l3ctable_even(nae_base, 11, 0, 0, 9, 1, 0x88f7); /* PTP messages can be sent as UDP messages over * IPv4 or IPv6; and as a raw ethernet message * with ethertype 0x88f7. The message contents * are the same for UDP or ethernet based encapsulations * The header is 34 bytes long, and we extract * it all out. */ nlm_setup_l3ctable_odd(nae_base, 11, 0, 31, 31, 2, 0, 0); /* * entry-12 is for ethernet Link Control Protocol (LCP) * used with PPPoE */ nlm_setup_l3ctable_even(nae_base, 12, 0, 0, 9, 1, 0xc021); /* LCP packet consists of 1 byte of code, 1 byte of * identifier and two bytes of length followed by * data (upto length bytes). * We extract 4 bytes from start of packet */ nlm_setup_l3ctable_odd(nae_base, 12, 0, 4, 0, 0, 0, 0); /* * entry-13 is for ethernet Link Quality Report (0xc025) * used with PPPoE */ nlm_setup_l3ctable_even(nae_base, 13, 0, 0, 9, 1, 0xc025); /* We extract 31 bytes from packet start */ nlm_setup_l3ctable_odd(nae_base, 13, 0, 31, 0, 0, 0, 0); /* * entry-14 is for PPPoE Session (0x8864) */ nlm_setup_l3ctable_even(nae_base, 14, 0, 0, 9, 1, 0x8864); /* We extract 31 bytes from packet start */ nlm_setup_l3ctable_odd(nae_base, 14, 0, 31, 0, 0, 0, 0); /* * entry-15 - default entry */ nlm_setup_l3ctable_even(nae_base, 15, 0, 0, 0, 0, 0x0000); /* We extract 31 bytes from packet start */ nlm_setup_l3ctable_odd(nae_base, 15, 0, 31, 0, 0, 0, 0); /*********************************************** * program L4 CAM table ***********************************************/ /* * entry-0 - tcp packets (0x6) */ nlm_setup_l4ctable_even(nae_base, 0, 0, 0, 1, 0, 0, 0x6); /* tcp header is 20 bytes without tcp options * We extract 20 bytes from tcp start */ nlm_setup_l4ctable_odd(nae_base, 0, 0, 15, 15, 5); /* * entry-1 - udp packets (0x11) */ nlm_setup_l4ctable_even(nae_base, 1, 0, 0, 1, 0, 0, 0x11); /* udp header is 8 bytes in size. * We extract 8 bytes from udp start */ nlm_setup_l4ctable_odd(nae_base, 1, 0, 8, 0, 0); /* * entry-2 - sctp packets (0x84) */ nlm_setup_l4ctable_even(nae_base, 2, 0, 0, 1, 0, 0, 0x84); /* sctp packets have a 12 byte generic header * and various chunks. * We extract 12 bytes from sctp start */ nlm_setup_l4ctable_odd(nae_base, 2, 0, 12, 0, 0); /* * entry-3 - RDP packets (0x1b) */ nlm_setup_l4ctable_even(nae_base, 3, 0, 0, 1, 0, 0, 0x1b); /* RDP packets have 18 bytes of generic header * before variable header starts. * We extract 18 bytes from rdp start */ nlm_setup_l4ctable_odd(nae_base, 3, 0, 15, 15, 3); /* * entry-4 - DCCP packets (0x21) */ nlm_setup_l4ctable_even(nae_base, 4, 0, 0, 1, 0, 0, 0x21); /* DCCP has two types of generic headers of * sizes 16 bytes and 12 bytes if X = 1. * We extract 16 bytes from dccp start */ nlm_setup_l4ctable_odd(nae_base, 4, 0, 15, 15, 1); /* * entry-5 - ipv6 encapsulated in ipv4 packets (0x29) */ nlm_setup_l4ctable_even(nae_base, 5, 0, 0, 1, 0, 0, 0x29); /* ipv4 header is 20 bytes excluding IP options. * We extract 20 bytes from IPv4 start */ nlm_setup_l4ctable_odd(nae_base, 5, 0, 15, 15, 5); /* * entry-6 - ip in ip encapsulation packets (0x04) */ nlm_setup_l4ctable_even(nae_base, 6, 0, 0, 1, 0, 0, 0x04); /* ipv4 header is 20 bytes excluding IP options. * We extract 20 bytes from ipv4 start */ nlm_setup_l4ctable_odd(nae_base, 6, 0, 15, 15, 5); /* * entry-7 - default entry (0x0) */ nlm_setup_l4ctable_even(nae_base, 7, 0, 0, 1, 0, 0, 0x0); /* We extract 20 bytes from packet start */ nlm_setup_l4ctable_odd(nae_base, 7, 0, 15, 15, 5); } void nlm_enable_hardware_parser_per_port(uint64_t nae_base, int block, int port) { int hwport = (block * 4) + (port & 0x3); /* program L2 and L3 header extraction for each port */ /* enable ethernet L2 mode on port */ nlm_setup_l2type(nae_base, hwport, 0, 0, 0, 0, 0, 1); /* l2proto and ethtype included in l3cam */ nlm_setup_l3ctable_mask(nae_base, hwport, 1, 0); } void nlm_prepad_enable(uint64_t nae_base, int size) { uint32_t val; val = nlm_read_nae_reg(nae_base, NAE_RX_CONFIG); val |= (1 << 13); /* prepad enable */ val |= ((size & 0x3) << 22); /* prepad size */ nlm_write_nae_reg(nae_base, NAE_RX_CONFIG, val); } void nlm_setup_1588_timer(uint64_t nae_base, struct nae_port_config *cfg) { uint32_t hi, lo, val; hi = cfg[0].ieee1588_userval >> 32; lo = cfg[0].ieee1588_userval & 0xffffffff; nlm_write_nae_reg(nae_base, NAE_1588_PTP_USER_VALUE_HI, hi); nlm_write_nae_reg(nae_base, NAE_1588_PTP_USER_VALUE_LO, lo); hi = cfg[0].ieee1588_ptpoff >> 32; lo = cfg[0].ieee1588_ptpoff & 0xffffffff; nlm_write_nae_reg(nae_base, NAE_1588_PTP_OFFSET_HI, hi); nlm_write_nae_reg(nae_base, NAE_1588_PTP_OFFSET_LO, lo); hi = cfg[0].ieee1588_tmr1 >> 32; lo = cfg[0].ieee1588_tmr1 & 0xffffffff; nlm_write_nae_reg(nae_base, NAE_1588_PTP_TMR1_HI, hi); nlm_write_nae_reg(nae_base, NAE_1588_PTP_TMR1_LO, lo); hi = cfg[0].ieee1588_tmr2 >> 32; lo = cfg[0].ieee1588_tmr2 & 0xffffffff; nlm_write_nae_reg(nae_base, NAE_1588_PTP_TMR2_HI, hi); nlm_write_nae_reg(nae_base, NAE_1588_PTP_TMR2_LO, lo); hi = cfg[0].ieee1588_tmr3 >> 32; lo = cfg[0].ieee1588_tmr3 & 0xffffffff; nlm_write_nae_reg(nae_base, NAE_1588_PTP_TMR3_HI, hi); nlm_write_nae_reg(nae_base, NAE_1588_PTP_TMR3_LO, lo); nlm_write_nae_reg(nae_base, NAE_1588_PTP_INC_INTG, cfg[0].ieee1588_inc_intg); nlm_write_nae_reg(nae_base, NAE_1588_PTP_INC_NUM, cfg[0].ieee1588_inc_num); nlm_write_nae_reg(nae_base, NAE_1588_PTP_INC_DEN, cfg[0].ieee1588_inc_den); val = nlm_read_nae_reg(nae_base, NAE_1588_PTP_CONTROL); /* set and clear freq_mul = 1 */ nlm_write_nae_reg(nae_base, NAE_1588_PTP_CONTROL, val | (0x1 << 1)); nlm_write_nae_reg(nae_base, NAE_1588_PTP_CONTROL, val); /* set and clear load_user_val = 1 */ nlm_write_nae_reg(nae_base, NAE_1588_PTP_CONTROL, val | (0x1 << 6)); nlm_write_nae_reg(nae_base, NAE_1588_PTP_CONTROL, val); } void nlm_mac_enable(uint64_t nae_base, int nblock, int port_type, int port) { uint32_t mac_cfg1, xaui_cfg; uint32_t netwk_inf; int iface = port & 0x3; switch(port_type) { case SGMIIC: netwk_inf = nlm_read_nae_reg(nae_base, SGMII_NET_IFACE_CTRL(nblock, iface)); nlm_write_nae_reg(nae_base, SGMII_NET_IFACE_CTRL(nblock, iface), netwk_inf | (1 << 2)); /* enable tx */ mac_cfg1 = nlm_read_nae_reg(nae_base, SGMII_MAC_CONF1(nblock, iface)); nlm_write_nae_reg(nae_base, SGMII_MAC_CONF1(nblock, iface), mac_cfg1 | (1 << 2) | /* rx enable */ 1); /* tx enable */ break; case XAUIC: xaui_cfg = nlm_read_nae_reg(nae_base, XAUI_CONFIG1(nblock)); nlm_write_nae_reg(nae_base, XAUI_CONFIG1(nblock), xaui_cfg | XAUI_CONFIG_TFEN | XAUI_CONFIG_RFEN); break; case ILC: break; } } void nlm_mac_disable(uint64_t nae_base, int nblock, int port_type, int port) { uint32_t mac_cfg1, xaui_cfg; uint32_t netwk_inf; int iface = port & 0x3; switch(port_type) { case SGMIIC: mac_cfg1 = nlm_read_nae_reg(nae_base, SGMII_MAC_CONF1(nblock, iface)); nlm_write_nae_reg(nae_base, SGMII_MAC_CONF1(nblock, iface), mac_cfg1 & ~((1 << 2) | /* rx enable */ 1)); /* tx enable */ netwk_inf = nlm_read_nae_reg(nae_base, SGMII_NET_IFACE_CTRL(nblock, iface)); nlm_write_nae_reg(nae_base, SGMII_NET_IFACE_CTRL(nblock, iface), netwk_inf & ~(1 << 2)); /* enable tx */ break; case XAUIC: xaui_cfg = nlm_read_nae_reg(nae_base, XAUI_CONFIG1(nblock)); nlm_write_nae_reg(nae_base, XAUI_CONFIG1(nblock), xaui_cfg & ~(XAUI_CONFIG_TFEN | XAUI_CONFIG_RFEN)); break; case ILC: break; } } /* * Set IOR credits for the ports in ifmask to valmask */ static void nlm_nae_set_ior_credit(uint64_t nae_base, uint32_t ifmask, uint32_t valmask) { uint32_t tx_config, tx_ior_credit; tx_ior_credit = nlm_read_nae_reg(nae_base, NAE_TX_IORCRDT_INIT); tx_ior_credit &= ~ifmask; tx_ior_credit |= valmask; nlm_write_nae_reg(nae_base, NAE_TX_IORCRDT_INIT, tx_ior_credit); tx_config = nlm_read_nae_reg(nae_base, NAE_TX_CONFIG); /* need to toggle these bits for credits to be loaded */ nlm_write_nae_reg(nae_base, NAE_TX_CONFIG, tx_config | (TXINITIORCR(ifmask))); nlm_write_nae_reg(nae_base, NAE_TX_CONFIG, tx_config & ~(TXINITIORCR(ifmask))); } int nlm_nae_open_if(uint64_t nae_base, int nblock, int port_type, int port, uint32_t desc_size) { uint32_t netwk_inf; uint32_t mac_cfg1, netior_ctrl3; int iface, iface_ctrl_reg, iface_ctrl3_reg, conf1_reg, conf2_reg; switch (port_type) { case XAUIC: netwk_inf = nlm_read_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL1(nblock)); netwk_inf |= (1 << NETIOR_XGMAC_STATS_CLR_POS); nlm_write_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL1(nblock), netwk_inf); nlm_nae_set_ior_credit(nae_base, 0xf << port, 0xf << port); break; case ILC: nlm_nae_set_ior_credit(nae_base, 0xff << port, 0xff << port); break; case SGMIIC: nlm_nae_set_ior_credit(nae_base, 0x1 << port, 0); /* * XXXJC: split this and merge to sgmii.c * some of this is duplicated from there. */ /* init phy id to access internal PCS */ iface = port & 0x3; iface_ctrl_reg = SGMII_NET_IFACE_CTRL(nblock, iface); conf1_reg = SGMII_MAC_CONF1(nblock, iface); conf2_reg = SGMII_MAC_CONF2(nblock, iface); netwk_inf = nlm_read_nae_reg(nae_base, iface_ctrl_reg); netwk_inf &= 0x7ffffff; netwk_inf |= (port << 27); nlm_write_nae_reg(nae_base, iface_ctrl_reg, netwk_inf); /* Sofreset sgmii port - set bit 11 to 0 */ netwk_inf &= 0xfffff7ff; nlm_write_nae_reg(nae_base, iface_ctrl_reg, netwk_inf); /* Reset Gmac */ mac_cfg1 = nlm_read_nae_reg(nae_base, conf1_reg); nlm_write_nae_reg(nae_base, conf1_reg, mac_cfg1 | (1U << 31) | /* soft reset */ (1 << 2) | /* rx enable */ (1)); /* tx enable */ /* default to 1G */ nlm_write_nae_reg(nae_base, conf2_reg, (0x7 << 12) | /* interface preamble length */ (0x2 << 8) | /* interface mode */ (0x1 << 2) | /* pad crc enable */ (0x1)); /* full duplex */ /* clear gmac reset */ mac_cfg1 = nlm_read_nae_reg(nae_base, conf1_reg); nlm_write_nae_reg(nae_base, conf1_reg, mac_cfg1 & ~(1U << 31)); /* clear speed debug bit */ iface_ctrl3_reg = SGMII_NET_IFACE_CTRL3(nblock, iface); netior_ctrl3 = nlm_read_nae_reg(nae_base, iface_ctrl3_reg); nlm_write_nae_reg(nae_base, iface_ctrl3_reg, netior_ctrl3 & ~(1 << 6)); /* disable TX, RX for now */ mac_cfg1 = nlm_read_nae_reg(nae_base, conf1_reg); nlm_write_nae_reg(nae_base, conf1_reg, mac_cfg1 & ~(0x5)); netwk_inf = nlm_read_nae_reg(nae_base, iface_ctrl_reg); nlm_write_nae_reg(nae_base, iface_ctrl_reg, netwk_inf & ~(0x1 << 2)); /* clear stats counters */ netwk_inf = nlm_read_nae_reg(nae_base, iface_ctrl_reg); nlm_write_nae_reg(nae_base, iface_ctrl_reg, netwk_inf | (1 << 15)); /* enable stats counters */ netwk_inf = nlm_read_nae_reg(nae_base, iface_ctrl_reg); nlm_write_nae_reg(nae_base, iface_ctrl_reg, (netwk_inf & ~(1 << 15)) | (1 << 16)); /* flow control? */ mac_cfg1 = nlm_read_nae_reg(nae_base, conf1_reg); nlm_write_nae_reg(nae_base, conf1_reg, mac_cfg1 | (0x3 << 4)); break; } nlm_nae_init_ingress(nae_base, desc_size); nlm_nae_init_egress(nae_base); return (0); } Index: head/sys/mips/nlm/dev/net/sgmii.c =================================================================== --- head/sys/mips/nlm/dev/net/sgmii.c (revision 326258) +++ head/sys/mips/nlm/dev/net/sgmii.c (revision 326259) @@ -1,209 +1,211 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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 void nlm_configure_sgmii_interface(uint64_t nae_base, int block, int port, int mtu, int loopback) { uint32_t data1, data2; /* Apply a soft reset */ data1 = (0x1 << 31); /* soft reset */ if (loopback) data1 |= (0x01 << 8); data1 |= (0x01 << 2); /* Rx enable */ data1 |= 0x01; /* Tx enable */ nlm_write_nae_reg(nae_base, NAE_REG(block, port, MAC_CONF1), data1); data2 = (0x7 << 12) | /* pre-amble length=7 */ (0x2 << 8) | /* byteMode */ 0x1; /* fullDuplex */ nlm_write_nae_reg(nae_base, NAE_REG(block, port, MAC_CONF2), data2); /* Remove a soft reset */ data1 &= ~(0x01 << 31); nlm_write_nae_reg(nae_base, NAE_REG(block, port, MAC_CONF1), data1); /* setup sgmii max frame length */ nlm_write_nae_reg(nae_base, SGMII_MAX_FRAME(block, port), mtu); } void nlm_sgmii_pcs_init(uint64_t nae_base, uint32_t cplx_mask) { xlp_nae_config_lane_gmac(nae_base, cplx_mask); } void nlm_nae_setup_mac(uint64_t nae_base, int nblock, int iface, int reset, int rx_en, int tx_en, int speed, int duplex) { uint32_t mac_cfg1, mac_cfg2, netwk_inf; mac_cfg1 = nlm_read_nae_reg(nae_base, SGMII_MAC_CONF1(nblock,iface)); mac_cfg2 = nlm_read_nae_reg(nae_base, SGMII_MAC_CONF2(nblock,iface)); netwk_inf = nlm_read_nae_reg(nae_base, SGMII_NET_IFACE_CTRL(nblock, iface)); mac_cfg1 &= ~(0x1 << 31); /* remove reset */ mac_cfg1 &= ~(0x1 << 2); /* remove rx */ mac_cfg1 &= ~(0x1); /* remove tx */ mac_cfg2 &= ~(0x3 << 8); /* remove interface mode bits */ mac_cfg2 &= ~(0x1); /* remove duplex */ netwk_inf &= ~(0x1 << 2); /* remove tx */ netwk_inf &= ~(0x3); /* remove speed */ switch (speed) { case NLM_SGMII_SPEED_10: netwk_inf |= 0x0; /* 2.5 Mhz clock for 10 Mbps */ mac_cfg2 |= (0x1 << 8); /* enable 10/100 Mbps */ break; case NLM_SGMII_SPEED_100: netwk_inf |= 0x1; /* 25 Mhz clock for 100 Mbps */ mac_cfg2 |= (0x1 << 8); /* enable 10/100 Mbps */ break; default: /* make it as 1G */ netwk_inf |= 0x2; /* 125 Mhz clock for 1G */ mac_cfg2 |= (0x2 << 8); /* enable 1G */ break; } if (reset) mac_cfg1 |= (0x1 << 31); /* set reset */ if (rx_en) mac_cfg1 |= (0x1 << 2); /* set rx */ nlm_write_nae_reg(nae_base, SGMII_NET_IFACE_CTRL(nblock, iface), netwk_inf); if (tx_en) { mac_cfg1 |= 0x1; /* set tx */ netwk_inf |= (0x1 << 2); /* set tx */ } switch (duplex) { case NLM_SGMII_DUPLEX_HALF: /* duplexity is already set to half duplex */ break; default: mac_cfg2 |= 0x1; /* set full duplex */ } nlm_write_nae_reg(nae_base, SGMII_MAC_CONF1(nblock, iface), mac_cfg1); nlm_write_nae_reg(nae_base, SGMII_MAC_CONF2(nblock, iface), mac_cfg2); nlm_write_nae_reg(nae_base, SGMII_NET_IFACE_CTRL(nblock, iface), netwk_inf); } void nlm_nae_setup_rx_mode_sgmii(uint64_t base, int nblock, int iface, int port_type, int broadcast_en, int multicast_en, int pause_en, int promisc_en) { uint32_t val; /* bit[17] of vlan_typefilter - allows packet matching in MAC. * When DA filtering is disabled, this bit and bit[16] should * be zero. * bit[16] of vlan_typefilter - Allows hash matching to be used * for DA filtering. When DA filtering is disabled, this bit and * bit[17] should be zero. * Both bits have to be set only if you want to turn on both * features / modes. */ if (promisc_en == 1) { val = nlm_read_nae_reg(base, SGMII_NETIOR_VLANTYPE_FILTER(nblock, iface)); val &= (~(0x3 << 16)); nlm_write_nae_reg(base, SGMII_NETIOR_VLANTYPE_FILTER(nblock, iface), val); } else { val = nlm_read_nae_reg(base, SGMII_NETIOR_VLANTYPE_FILTER(nblock, iface)); val |= (0x1 << 17); nlm_write_nae_reg(base, SGMII_NETIOR_VLANTYPE_FILTER(nblock, iface), val); } val = ((broadcast_en & 0x1) << 10) | ((pause_en & 0x1) << 9) | ((multicast_en & 0x1) << 8) | ((promisc_en & 0x1) << 7) | /* unicast_enable - enables promisc mode */ 1; /* MAC address is always valid */ nlm_write_nae_reg(base, SGMII_MAC_FILTER_CONFIG(nblock, iface), val); } void nlm_nae_setup_mac_addr_sgmii(uint64_t base, int nblock, int iface, int port_type, uint8_t *mac_addr) { nlm_write_nae_reg(base, SGMII_MAC_ADDR0_LO(nblock, iface), (mac_addr[5] << 24) | (mac_addr[4] << 16) | (mac_addr[3] << 8) | mac_addr[2]); nlm_write_nae_reg(base, SGMII_MAC_ADDR0_HI(nblock, iface), (mac_addr[1] << 24) | (mac_addr[0] << 16)); nlm_write_nae_reg(base, SGMII_MAC_ADDR_MASK0_LO(nblock, iface), 0xffffffff); nlm_write_nae_reg(base, SGMII_MAC_ADDR_MASK0_HI(nblock, iface), 0xffffffff); nlm_nae_setup_rx_mode_sgmii(base, nblock, iface, SGMIIC, 1, /* broadcast enabled */ 1, /* multicast enabled */ 0, /* do not accept pause frames */ 0 /* promisc mode disabled */ ); } Index: head/sys/mips/nlm/dev/net/ucore/ucore.h =================================================================== --- head/sys/mips/nlm/dev/net/ucore/ucore.h (revision 326258) +++ head/sys/mips/nlm/dev/net/ucore/ucore.h (revision 326259) @@ -1,352 +1,354 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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$ */ #ifndef __NLM_UCORE_H__ #define __NLM_UCORE_H__ /* Microcode registers */ #define UCORE_OUTBUF_DONE 0x8000 #define UCORE_RX_PKT_RDY 0x8004 #define UCORE_RX_PKT_INFO 0x8008 #define UCORE_CAM0 0x800c #define UCORE_CAM1 0x8010 #define UCORE_CAM2 0x8014 #define UCORE_CAM3 0x8018 #define UCORE_CAM_RESULT 0x801c #define UCORE_CSUMINFO 0x8020 #define UCORE_CRCINFO 0x8024 #define UCORE_CRCPOS 0x8028 #define UCORE_FR_FIFOEMPTY 0x802c #define UCORE_PKT_DISTR 0x8030 #define PACKET_MEMORY 0xFFE00 #define PACKET_DATA_OFFSET 64 #define SHARED_SCRATCH_MEM 0x18000 /* Distribution mode */ #define VAL_PDM(x) (((x) & 0x7) << 0) /* Dest distribution or distribution list */ #define VAL_DEST(x) (((x) & 0x3ff) << 8) #define VAL_PDL(x) (((x) & 0xf) << 4) /*output buffer done*/ #define VAL_FSV(x) (x << 19) #define VAL_FFS(x) (x << 14) #define FWD_DEST_ONLY 1 #define FWD_ENQ_DIST_VEC 2 #define FWD_ENQ_DEST 3 #define FWD_DIST_VEC 4 #define FWD_ENQ_DIST_VEC_SER 6 #define FWD_ENQ_DEST_SER 7 #define USE_HASH_DST (1 << 20) static __inline unsigned int nlm_read_ucore_reg(int reg) { volatile unsigned int *addr = (volatile void *)reg; return (*addr); } static __inline void nlm_write_ucore_reg(int reg, unsigned int val) { volatile unsigned int *addr = (volatile void *)reg; *addr = val; } #define NLM_DEFINE_UCORE(name, reg) \ static __inline unsigned int \ nlm_read_ucore_##name(void) \ { \ return nlm_read_ucore_reg(reg); \ } \ \ static __inline void \ nlm_write_ucore_##name(unsigned int v) \ { \ nlm_write_ucore_reg(reg, v); \ } struct __hack NLM_DEFINE_UCORE(obufdone, UCORE_OUTBUF_DONE); NLM_DEFINE_UCORE(rxpktrdy, UCORE_RX_PKT_RDY); NLM_DEFINE_UCORE(rxpktinfo, UCORE_RX_PKT_INFO); NLM_DEFINE_UCORE(cam0, UCORE_CAM0); NLM_DEFINE_UCORE(cam1, UCORE_CAM1); NLM_DEFINE_UCORE(cam2, UCORE_CAM2); NLM_DEFINE_UCORE(cam3, UCORE_CAM3); NLM_DEFINE_UCORE(camresult, UCORE_CAM_RESULT); NLM_DEFINE_UCORE(csuminfo, UCORE_CSUMINFO); NLM_DEFINE_UCORE(crcinfo, UCORE_CRCINFO); NLM_DEFINE_UCORE(crcpos, UCORE_CRCPOS); NLM_DEFINE_UCORE(freefifo_empty, UCORE_FR_FIFOEMPTY); NLM_DEFINE_UCORE(pktdistr, UCORE_PKT_DISTR); /* * l3cachelines - number of cache lines to allocate into l3 * fsv - 0 : use interface-id for selecting the free fifo pool * 1 : use free fifo pool selected by FFS field * ffs - selects which free fifo pool to use to take a free fifo * prepad_en - If this field is set to 1, part or all of the * 64 byte prepad seen by micro engines, is written * infront of every packet. * prepad_ovride - If this field is 1, the ucore system uses * prepad configuration defined in this register, * 0 means that it uses the configuration defined * in NAE RX_CONFIG register * prepad_size - number of 16 byte words in the 64-byte prepad * seen by micro engines and dma'ed to memory as * pkt prepad. This field is meaningful only if * prepad_en and prepad_ovride is set. * 0 : 1 word * 1 : 2 words * 2 : 3 words * 3 : 4 words * prepad[0-3]: writing 0 to this means that the 1st 16 byte offset * of prepad in micro engine, gets setup as prepad0/1/2/3. * prepad word. * 1 : means 2nd 16 byte chunk in prepad0/1/2/3 * 2 : means 3rd 16 byte chunk in prepad0/1/2/3 * 3 : means 4rth 16 byte chunk in prepad0/1/2/3 * pkt_discard - packet will be discarded if this is set to 1 * rd5 - value (single bit) to be inserted in bit 5, the unclassified * pkt bit of receive descriptor. If this bit is set, HPRE bit * should also be set in ucore_rxpktready register */ static __inline__ void nlm_ucore_pkt_done(int l3cachelines, int fsv, int ffs, int prepad_en, int prepad_ovride, int prepad_size, int prepad0, int prepad1, int prepad2, int prepad3, int pkt_discard, int rd5) { unsigned int val = 0; val |= ((l3cachelines & 0xfff) << 20); val |= ((fsv & 0x1) << 19); val |= ((ffs & 0x1f) << 14); val |= ((prepad_en & 0x1) << 3); val |= ((prepad_ovride & 0x1) << 2); val |= ((prepad_size & 0x3) << 12); val |= ((prepad0 & 0x3) << 4); val |= ((prepad1 & 0x3) << 6); val |= ((prepad2 & 0x3) << 8); val |= ((prepad3 & 0x3) << 10); val |= ((pkt_discard & 0x1) << 1); val |= ((rd5 & 0x1) << 0); nlm_write_ucore_obufdone(val); } /* Get the class full vector field from POE. * The POE maintains a threshold for each class. * A bit in this field will be set corresponding to the class approaching * class full status. */ static __inline__ int nlm_ucore_get_rxpkt_poeclassfullvec(unsigned int pktrdy) { return ((pktrdy >> 24) & 0xff); } /* This function returns 1 if the hardware parser extraction process * resulted in an error. Else, returns 0. */ static __inline__ int nlm_ucore_get_rxpkt_hwparsererr(unsigned int pktrdy) { return ((pktrdy >> 23) & 0x1); } /* This function returns the context number assigned to incoming * packet */ static __inline__ int nlm_ucore_get_rxpkt_context(unsigned int pktrdy) { return ((pktrdy >> 13) & 0x3ff); } /* this function returns the channel number of incoming packet, * and applies only to interlaken. */ static __inline__ int nlm_ucore_get_rxpkt_channel(unsigned int pktrdy) { return ((pktrdy >> 5) & 0xff); } /* This function returns the interface number on which the pkt * was received */ static __inline__ int nlm_ucore_get_rxpkt_interface(unsigned int pktrdy) { return (pktrdy & 0x1f); } /* This function returns 1 if end of packet (EOP) is set in * packet data. */ static __inline__ int nlm_ucore_get_rxpkt_eop(unsigned int rxpkt_info) { return ((rxpkt_info >> 9) & 0x1); } /* This function returns packet length of received pkt */ static __inline__ int nlm_ucore_get_rxpktlen(unsigned int rxpkt_info) { return (rxpkt_info & 0x1ff); } /* this function sets up the ucore TCAM keys. */ static __inline__ void nlm_ucore_setup_camkey(unsigned int cam_key0, unsigned int cam_key1, unsigned int cam_key2, unsigned int cam_key3) { nlm_write_ucore_cam0(cam_key0); nlm_write_ucore_cam1(cam_key1); nlm_write_ucore_cam2(cam_key2); nlm_write_ucore_cam3(cam_key3); } /* This function checks if the cam result is valid or not. * If valid, it returns the result, else it returns 0. */ static __inline__ int nlm_ucore_get_cam_result(unsigned int cam_result) { if (((cam_result >> 15) & 0x1) == 1) /* valid result */ return (cam_result & 0x3fff); return 0; } /* This function sets up the csum in ucore. * iphdr_start - defines the start of ip header (to check - is this byte * position???) * iphdr_len - This field is auto filled by h/w parser if zero, else * the value defined will be used. */ static __inline__ void nlm_ucore_csum_setup(int iphdr_start, int iphdr_len) { unsigned int val = 0; val |= ((iphdr_len & 0xff) << 8); val |= (iphdr_len & 0xff); nlm_write_ucore_csuminfo(val); } /* crcpos - position of crc in pkt. If crc position is within startcrc and * endcrc, zero out these bytes in the packet before computing crc. This * field is not needed for FCoE. * cps - If 1, uses the polynomial in RX_CRC_POLY1 of NAE register. * if 0, uses the polynomial in RX_CRC_POLY0 of NAE register. * fcoe - If this is 1, crc calculation starts from 'startCRC' and the CRC * engine ends calculation before the last byte. * cbm - if 1, enables crc byte mirroring, where bits within a byte will get * reversed (mirrored) during calculation of crc. * cfi - If 1, performs a final inversion of crc before comarison is done during * pkt reception. * startcrc - This field is always required for both FCoE and SCTP crc. * endcrc - This information needs to be setup only for SCTP. For FCoE this * information is provided by hardware. * valid - if set to 1, CRC status is placed into bit 2 of rx descriptor * if set to 0, TCP checksum status is placed into bit 2 of rx descriptor * keysize - defines the number of bytes in the pre-pad that contains the key */ static __inline__ void nlm_ucore_crc_setup(int crcpos, int cps, int cfi, int cbm, int fcoe, int keysize, int valid, int startcrc, int endcrc) { unsigned int val = 0; val |= ((cfi & 0x1) << 20); val |= ((cbm & 0x1) << 19); val |= ((fcoe & 0x1) << 18); val |= ((cps & 0x1) << 16); val |= (crcpos & 0xffff); nlm_write_ucore_crcpos(val); val = 0; val |= ((keysize & 0x3f) << 25); val |= ((valid & 0x1) << 24); val |= ((endcrc & 0xffff) << 8); val |= (startcrc & 0xff); nlm_write_ucore_crcinfo(val); } /* This function returns a fifo empty vector, where each bit provides * the status of a fifo pool, where if the pool is empty the bit gets * set to 1. */ static __inline__ int nlm_ucore_get_fifoempty(unsigned int fifoempty) { return (fifoempty & 0xfffff); } /* This function controls how POE will distribute the packet. * pdm - is the packet distribution mode, where * 0x0 - means packet distribution mode is not used * 0x1 - means forwarding based on destination only (no enqueue) * 0x2 - means forwarding based on FID and distr vector (enqueue) * 0x3 - means forwarding based on dest and FID (enqueue) * 0x4 - means forwarding based on distr vec (no enqueue) * 0x6 - means forward based on FID (enqueue), distr vec and serial mode * 0x7 - means forward based on FID (enqueue), dest and serial mode * mc3 - If 1, then the 3 most significant bits of distribution list are taken * from context->class_table * pdl - poe distribution list * dest - fixed destination setup * hash - if 1, use hash based destination */ static __inline__ void nlm_ucore_setup_poepktdistr(int pdm, int mc3, int pdl, int dest, int hash) { unsigned int val = 0; val |= ((hash & 0x1) << 20); val |= ((dest & 0xfff) << 8); val |= ((pdl & 0xf) << 4); val |= ((mc3 & 0x1) << 3); val |= (pdm & 0x7); nlm_write_ucore_pktdistr(val); } #endif Index: head/sys/mips/nlm/dev/net/ucore/ucore_app.c =================================================================== --- head/sys/mips/nlm/dev/net/ucore/ucore_app.c (revision 326258) +++ head/sys/mips/nlm/dev/net/ucore/ucore_app.c (revision 326259) @@ -1,48 +1,50 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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 "ucore.h" int main(void) { unsigned int pktrdy; int num_cachelines = 1518 / 64 ; /* pktsize / L3 cacheline size */ /* Spray packets to using distribution vector */ while (1) { pktrdy = nlm_read_ucore_rxpktrdy(); nlm_ucore_setup_poepktdistr(FWD_DIST_VEC, 0, 0, 0, 0); nlm_ucore_pkt_done(num_cachelines, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } return (0); } Index: head/sys/mips/nlm/dev/net/xaui.c =================================================================== --- head/sys/mips/nlm/dev/net/xaui.c (revision 326258) +++ head/sys/mips/nlm/dev/net/xaui.c (revision 326259) @@ -1,249 +1,251 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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 void nlm_xaui_pcs_init(uint64_t nae_base, int xaui_cplx_mask) { int block, lane_ctrl, reg; int cplx_lane_enable; int lane_enable = 0; uint32_t regval; cplx_lane_enable = LM_XAUI | (LM_XAUI << 4) | (LM_XAUI << 8) | (LM_XAUI << 12); if (xaui_cplx_mask == 0) return; /* write 0x2 to enable SGMII for all lane */ block = 7; if (xaui_cplx_mask & 0x3) { /* Complexes 0, 1 */ lane_enable = nlm_read_nae_reg(nae_base, NAE_REG(block, LANE_CFG, LANE_CFG_CPLX_0_1)); if (xaui_cplx_mask & 0x1) { /* Complex 0 */ lane_enable &= ~(0xFFFF); lane_enable |= cplx_lane_enable; } if (xaui_cplx_mask & 0x2) { /* Complex 1 */ lane_enable &= ~(0xFFFF<<16); lane_enable |= (cplx_lane_enable << 16); } nlm_write_nae_reg(nae_base, NAE_REG(block, LANE_CFG, LANE_CFG_CPLX_0_1), lane_enable); } lane_enable = 0; if (xaui_cplx_mask & 0xc) { /* Complexes 2, 3 */ lane_enable = nlm_read_nae_reg(nae_base, NAE_REG(block, LANE_CFG, LANE_CFG_CPLX_2_3)); if (xaui_cplx_mask & 0x4) { /* Complex 2 */ lane_enable &= ~(0xFFFF); lane_enable |= cplx_lane_enable; } if (xaui_cplx_mask & 0x8) { /* Complex 3 */ lane_enable &= ~(0xFFFF<<16); lane_enable |= (cplx_lane_enable << 16); } nlm_write_nae_reg(nae_base, NAE_REG(block, LANE_CFG, LANE_CFG_CPLX_2_3), lane_enable); } /* Bring txpll out of reset */ for (block = 0; block < 4; block++) { if ((xaui_cplx_mask & (1 << block)) == 0) continue; for (lane_ctrl = PHY_LANE_0_CTRL; lane_ctrl <= PHY_LANE_3_CTRL; lane_ctrl++) { if (!nlm_is_xlp8xx_ax()) xlp_nae_lane_reset_txpll(nae_base, block, lane_ctrl, PHYMODE_XAUI); else xlp_ax_nae_lane_reset_txpll(nae_base, block, lane_ctrl, PHYMODE_XAUI); } } /* Wait for Rx & TX clock stable */ for (block = 0; block < 4; block++) { if ((xaui_cplx_mask & (1 << block)) == 0) continue; for (lane_ctrl = PHY_LANE_0_CTRL; lane_ctrl <= PHY_LANE_3_CTRL; lane_ctrl++) { reg = NAE_REG(block, PHY, lane_ctrl - 4); /* Wait for TX clock to be set */ do { regval = nlm_read_nae_reg(nae_base, reg); } while ((regval & LANE_TX_CLK) == 0); /* Wait for RX clock to be set */ do { regval = nlm_read_nae_reg(nae_base, reg); } while ((regval & LANE_RX_CLK) == 0); /* Wait for XAUI Lane fault to be cleared */ do { regval = nlm_read_nae_reg(nae_base, reg); } while ((regval & XAUI_LANE_FAULT) != 0); } } } void nlm_nae_setup_rx_mode_xaui(uint64_t base, int nblock, int iface, int port_type, int broadcast_en, int multicast_en, int pause_en, int promisc_en) { uint32_t val; val = ((broadcast_en & 0x1) << 10) | ((pause_en & 0x1) << 9) | ((multicast_en & 0x1) << 8) | ((promisc_en & 0x1) << 7) | /* unicast_enable - enables promisc mode */ 1; /* MAC address is always valid */ nlm_write_nae_reg(base, XAUI_MAC_FILTER_CFG(nblock), val); } void nlm_nae_setup_mac_addr_xaui(uint64_t base, int nblock, int iface, int port_type, unsigned char *mac_addr) { nlm_write_nae_reg(base, XAUI_MAC_ADDR0_LO(nblock), (mac_addr[5] << 24) | (mac_addr[4] << 16) | (mac_addr[3] << 8) | mac_addr[2]); nlm_write_nae_reg(base, XAUI_MAC_ADDR0_HI(nblock), (mac_addr[1] << 24) | (mac_addr[0] << 16)); nlm_write_nae_reg(base, XAUI_MAC_ADDR_MASK0_LO(nblock), 0xffffffff); nlm_write_nae_reg(base, XAUI_MAC_ADDR_MASK0_HI(nblock), 0xffffffff); nlm_nae_setup_rx_mode_xaui(base, nblock, iface, XAUIC, 1, /* broadcast enabled */ 1, /* multicast enabled */ 0, /* do not accept pause frames */ 0 /* promisc mode disabled */ ); } void nlm_config_xaui_mtu(uint64_t nae_base, int nblock, int max_tx_frame_sz, int max_rx_frame_sz) { uint32_t tx_words = max_tx_frame_sz >> 2; /* max_tx_frame_sz / 4 */ /* write max frame length */ nlm_write_nae_reg(nae_base, XAUI_MAX_FRAME_LEN(nblock), ((tx_words & 0x3ff) << 16) | (max_rx_frame_sz & 0xffff)); } void nlm_config_xaui(uint64_t nae_base, int nblock, int max_tx_frame_sz, int max_rx_frame_sz, int vlan_pri_en) { uint32_t val; val = nlm_read_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL1(nblock)); val &= ~(0x1 << 11); /* clear soft reset */ nlm_write_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL1(nblock), val); val = nlm_read_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL1(nblock)); val &= ~(0x3 << 11); /* clear soft reset and hard reset */ nlm_write_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL1(nblock), val); nlm_write_nae_reg(nae_base, XAUI_CONFIG0(nblock), 0xffffffff); nlm_write_nae_reg(nae_base, XAUI_CONFIG0(nblock), 0); /* Enable tx/rx frame */ val = 0x000010A8; val |= XAUI_CONFIG_LENCHK; val |= XAUI_CONFIG_GENFCS; val |= XAUI_CONFIG_PAD_64; nlm_write_nae_reg(nae_base, XAUI_CONFIG1(nblock), val); /* write max frame length */ nlm_config_xaui_mtu(nae_base, nblock, max_tx_frame_sz, max_rx_frame_sz); /* set stats counter */ val = nlm_read_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL1(nblock)); val |= (0x1 << NETIOR_XGMAC_VLAN_DC_POS); val |= (0x1 << NETIOR_XGMAC_STATS_EN_POS); if (vlan_pri_en) { val |= (0x1 << NETIOR_XGMAC_TX_PFC_EN_POS); val |= (0x1 << NETIOR_XGMAC_RX_PFC_EN_POS); val |= (0x1 << NETIOR_XGMAC_TX_PAUSE_POS); } else { val &= ~(0x1 << NETIOR_XGMAC_TX_PFC_EN_POS); val |= (0x1 << NETIOR_XGMAC_TX_PAUSE_POS); } nlm_write_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL1(nblock), val); /* configure on / off timer */ if (vlan_pri_en) val = 0xF1230000; /* PFC mode, offtimer = 0xf123, ontimer = 0 */ else val = 0x0000F123; /* link level FC mode, offtimer = 0xf123 */ nlm_write_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL2(nblock), val); /* set xaui tx threshold */ val = nlm_read_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL3(nblock)); val &= ~(0x1f << 10); val |= ~(15 << 10); nlm_write_nae_reg(nae_base, XAUI_NETIOR_XGMAC_CTRL3(nblock), val); } Index: head/sys/mips/nlm/dev/net/xlpge.c =================================================================== --- head/sys/mips/nlm/dev/net/xlpge.c (revision 326258) +++ head/sys/mips/nlm/dev/net/xlpge.c (revision 326259) @@ -1,1541 +1,1543 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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 #define __RMAN_RESOURCE_VISIBLE #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 /* for DELAY */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "miidevs.h" #include #include "miibus_if.h" #include #include /*#define XLP_DRIVER_LOOPBACK*/ static struct nae_port_config nae_port_config[64]; int poe_cl_tbl[MAX_POE_CLASSES] = { 0x0, 0x249249, 0x492492, 0x6db6db, 0x924924, 0xb6db6d, 0xdb6db6, 0xffffff }; /* #define DUMP_PACKET */ static uint64_t nlm_paddr_ld(uint64_t paddr) { uint64_t xkaddr = 0x9800000000000000 | paddr; return (nlm_load_dword_daddr(xkaddr)); } struct nlm_xlp_portdata ifp_ports[64]; static uma_zone_t nl_tx_desc_zone; /* This implementation will register the following tree of device * registration: * pcibus * | * xlpnae (1 instance - virtual entity) * | * xlpge * (18 sgmii / 4 xaui / 2 interlaken instances) * | * miibus */ static int nlm_xlpnae_probe(device_t); static int nlm_xlpnae_attach(device_t); static int nlm_xlpnae_detach(device_t); static int nlm_xlpnae_suspend(device_t); static int nlm_xlpnae_resume(device_t); static int nlm_xlpnae_shutdown(device_t); static device_method_t nlm_xlpnae_methods[] = { /* Methods from the device interface */ DEVMETHOD(device_probe, nlm_xlpnae_probe), DEVMETHOD(device_attach, nlm_xlpnae_attach), DEVMETHOD(device_detach, nlm_xlpnae_detach), DEVMETHOD(device_suspend, nlm_xlpnae_suspend), DEVMETHOD(device_resume, nlm_xlpnae_resume), DEVMETHOD(device_shutdown, nlm_xlpnae_shutdown), DEVMETHOD(bus_driver_added, bus_generic_driver_added), DEVMETHOD_END }; static driver_t nlm_xlpnae_driver = { "xlpnae", nlm_xlpnae_methods, sizeof(struct nlm_xlpnae_softc) }; static devclass_t nlm_xlpnae_devclass; static int nlm_xlpge_probe(device_t); static int nlm_xlpge_attach(device_t); static int nlm_xlpge_detach(device_t); static int nlm_xlpge_suspend(device_t); static int nlm_xlpge_resume(device_t); static int nlm_xlpge_shutdown(device_t); /* mii override functions */ static int nlm_xlpge_mii_read(device_t, int, int); static int nlm_xlpge_mii_write(device_t, int, int, int); static void nlm_xlpge_mii_statchg(device_t); static device_method_t nlm_xlpge_methods[] = { /* Methods from the device interface */ DEVMETHOD(device_probe, nlm_xlpge_probe), DEVMETHOD(device_attach, nlm_xlpge_attach), DEVMETHOD(device_detach, nlm_xlpge_detach), DEVMETHOD(device_suspend, nlm_xlpge_suspend), DEVMETHOD(device_resume, nlm_xlpge_resume), DEVMETHOD(device_shutdown, nlm_xlpge_shutdown), /* Methods from the nexus bus needed for explicitly * probing children when driver is loaded as a kernel module */ DEVMETHOD(miibus_readreg, nlm_xlpge_mii_read), DEVMETHOD(miibus_writereg, nlm_xlpge_mii_write), DEVMETHOD(miibus_statchg, nlm_xlpge_mii_statchg), /* Terminate method list */ DEVMETHOD_END }; static driver_t nlm_xlpge_driver = { "xlpge", nlm_xlpge_methods, sizeof(struct nlm_xlpge_softc) }; static devclass_t nlm_xlpge_devclass; DRIVER_MODULE(xlpnae, pci, nlm_xlpnae_driver, nlm_xlpnae_devclass, 0, 0); DRIVER_MODULE(xlpge, xlpnae, nlm_xlpge_driver, nlm_xlpge_devclass, 0, 0); DRIVER_MODULE(miibus, xlpge, miibus_driver, miibus_devclass, 0, 0); MODULE_DEPEND(pci, xlpnae, 1, 1, 1); MODULE_DEPEND(xlpnae, xlpge, 1, 1, 1); MODULE_DEPEND(xlpge, ether, 1, 1, 1); MODULE_DEPEND(xlpge, miibus, 1, 1, 1); #define SGMII_RCV_CONTEXT_WIDTH 8 /* prototypes */ static void nlm_xlpge_msgring_handler(int vc, int size, int code, int srcid, struct nlm_fmn_msg *msg, void *data); static void nlm_xlpge_submit_rx_free_desc(struct nlm_xlpge_softc *sc, int num); static void nlm_xlpge_init(void *addr); static void nlm_xlpge_port_disable(struct nlm_xlpge_softc *sc); static void nlm_xlpge_port_enable(struct nlm_xlpge_softc *sc); /* globals */ int dbg_on = 1; int cntx2port[524]; static __inline void atomic_incr_long(unsigned long *addr) { atomic_add_long(addr, 1); } /* * xlpnae driver implementation */ static int nlm_xlpnae_probe(device_t dev) { if (pci_get_vendor(dev) != PCI_VENDOR_NETLOGIC || pci_get_device(dev) != PCI_DEVICE_ID_NLM_NAE) return (ENXIO); return (BUS_PROBE_DEFAULT); } static void nlm_xlpnae_print_frin_desc_carving(struct nlm_xlpnae_softc *sc) { int intf; uint32_t value; int start, size; /* XXXJC: use max_ports instead of 20 ? */ for (intf = 0; intf < 20; intf++) { nlm_write_nae_reg(sc->base, NAE_FREE_IN_FIFO_CFG, (0x80000000 | intf)); value = nlm_read_nae_reg(sc->base, NAE_FREE_IN_FIFO_CFG); size = 2 * ((value >> 20) & 0x3ff); start = 2 * ((value >> 8) & 0x1ff); } } static void nlm_config_egress(struct nlm_xlpnae_softc *sc, int nblock, int context_base, int hwport, int max_channels) { int offset, num_channels; uint32_t data; num_channels = sc->portcfg[hwport].num_channels; data = (2048 << 12) | (hwport << 4) | 1; nlm_write_nae_reg(sc->base, NAE_TX_IF_BURSTMAX_CMD, data); data = ((context_base + num_channels - 1) << 22) | (context_base << 12) | (hwport << 4) | 1; nlm_write_nae_reg(sc->base, NAE_TX_DDR_ACTVLIST_CMD, data); config_egress_fifo_carvings(sc->base, hwport, context_base, num_channels, max_channels, sc->portcfg); config_egress_fifo_credits(sc->base, hwport, context_base, num_channels, max_channels, sc->portcfg); data = nlm_read_nae_reg(sc->base, NAE_DMA_TX_CREDIT_TH); data |= (1 << 25) | (1 << 24); nlm_write_nae_reg(sc->base, NAE_DMA_TX_CREDIT_TH, data); for (offset = 0; offset < num_channels; offset++) { nlm_write_nae_reg(sc->base, NAE_TX_SCHED_MAP_CMD1, NAE_DRR_QUANTA); data = (hwport << 15) | ((context_base + offset) << 5); if (sc->cmplx_type[nblock] == ILC) data |= (offset << 20); nlm_write_nae_reg(sc->base, NAE_TX_SCHED_MAP_CMD0, data | 1); nlm_write_nae_reg(sc->base, NAE_TX_SCHED_MAP_CMD0, data); } } static int xlpnae_get_maxchannels(struct nlm_xlpnae_softc *sc) { int maxchans = 0; int i; for (i = 0; i < sc->max_ports; i++) { if (sc->portcfg[i].type == UNKNOWN) continue; maxchans += sc->portcfg[i].num_channels; } return (maxchans); } static void nlm_setup_interface(struct nlm_xlpnae_softc *sc, int nblock, int port, uint32_t cur_flow_base, uint32_t flow_mask, int max_channels, int context) { uint64_t nae_base = sc->base; int mtu = 1536; /* XXXJC: don't hard code */ uint32_t ucore_mask; if (sc->cmplx_type[nblock] == XAUIC) nlm_config_xaui(nae_base, nblock, mtu, mtu, sc->portcfg[port].vlan_pri_en); nlm_config_freein_fifo_uniq_cfg(nae_base, port, sc->portcfg[port].free_desc_sizes); nlm_config_ucore_iface_mask_cfg(nae_base, port, sc->portcfg[port].ucore_mask); nlm_program_flow_cfg(nae_base, port, cur_flow_base, flow_mask); if (sc->cmplx_type[nblock] == SGMIIC) nlm_configure_sgmii_interface(nae_base, nblock, port, mtu, 0); nlm_config_egress(sc, nblock, context, port, max_channels); nlm_nae_init_netior(nae_base, sc->nblocks); nlm_nae_open_if(nae_base, nblock, sc->cmplx_type[nblock], port, sc->portcfg[port].free_desc_sizes); /* XXXJC: check mask calculation */ ucore_mask = (1 << sc->nucores) - 1; nlm_nae_init_ucore(nae_base, port, ucore_mask); } static void nlm_setup_interfaces(struct nlm_xlpnae_softc *sc) { uint64_t nae_base; uint32_t cur_slot, cur_slot_base; uint32_t cur_flow_base, port, flow_mask; int max_channels; int i, context; cur_slot = 0; cur_slot_base = 0; cur_flow_base = 0; nae_base = sc->base; flow_mask = nlm_get_flow_mask(sc->total_num_ports); /* calculate max_channels */ max_channels = xlpnae_get_maxchannels(sc); port = 0; context = 0; for (i = 0; i < sc->max_ports; i++) { if (sc->portcfg[i].type == UNKNOWN) continue; nlm_setup_interface(sc, sc->portcfg[i].block, i, cur_flow_base, flow_mask, max_channels, context); cur_flow_base += sc->per_port_num_flows; context += sc->portcfg[i].num_channels; } } static void nlm_xlpnae_init(int node, struct nlm_xlpnae_softc *sc) { uint64_t nae_base; uint32_t ucoremask = 0; uint32_t val; int i; nae_base = sc->base; nlm_nae_flush_free_fifo(nae_base, sc->nblocks); nlm_deflate_frin_fifo_carving(nae_base, sc->max_ports); nlm_reset_nae(node); for (i = 0; i < sc->nucores; i++) /* XXXJC: code repeated below */ ucoremask |= (0x1 << i); printf("Loading 0x%x ucores with microcode\n", ucoremask); nlm_ucore_load_all(nae_base, ucoremask, 1); val = nlm_set_device_frequency(node, DFS_DEVICE_NAE, sc->freq); printf("Setup NAE frequency to %dMHz\n", val); nlm_mdio_reset_all(nae_base); printf("Initialze SGMII PCS for blocks 0x%x\n", sc->sgmiimask); nlm_sgmii_pcs_init(nae_base, sc->sgmiimask); printf("Initialze XAUI PCS for blocks 0x%x\n", sc->xauimask); nlm_xaui_pcs_init(nae_base, sc->xauimask); /* clear NETIOR soft reset */ nlm_write_nae_reg(nae_base, NAE_LANE_CFG_SOFTRESET, 0x0); /* Disable RX enable bit in RX_CONFIG */ val = nlm_read_nae_reg(nae_base, NAE_RX_CONFIG); val &= 0xfffffffe; nlm_write_nae_reg(nae_base, NAE_RX_CONFIG, val); if (nlm_is_xlp8xx_ax() == 0) { val = nlm_read_nae_reg(nae_base, NAE_TX_CONFIG); val &= ~(1 << 3); nlm_write_nae_reg(nae_base, NAE_TX_CONFIG, val); } nlm_setup_poe_class_config(nae_base, MAX_POE_CLASSES, sc->ncontexts, poe_cl_tbl); nlm_setup_vfbid_mapping(nae_base); nlm_setup_flow_crc_poly(nae_base, sc->flow_crc_poly); nlm_setup_rx_cal_cfg(nae_base, sc->max_ports, sc->portcfg); /* note: xlp8xx Ax does not have Tx Calendering */ if (!nlm_is_xlp8xx_ax()) nlm_setup_tx_cal_cfg(nae_base, sc->max_ports, sc->portcfg); nlm_setup_interfaces(sc); nlm_config_poe(sc->poe_base, sc->poedv_base); if (sc->hw_parser_en) nlm_enable_hardware_parser(nae_base); if (sc->prepad_en) nlm_prepad_enable(nae_base, sc->prepad_size); if (sc->ieee_1588_en) nlm_setup_1588_timer(sc->base, sc->portcfg); } static void nlm_xlpnae_update_pde(void *dummy __unused) { struct nlm_xlpnae_softc *sc; uint32_t dv[NUM_WORDS_PER_DV]; device_t dev; int vec; dev = devclass_get_device(devclass_find("xlpnae"), 0); sc = device_get_softc(dev); nlm_write_poe_reg(sc->poe_base, POE_DISTR_EN, 0); for (vec = 0; vec < NUM_DIST_VEC; vec++) { if (nlm_get_poe_distvec(vec, dv) != 0) continue; nlm_write_poe_distvec(sc->poedv_base, vec, dv); } nlm_write_poe_reg(sc->poe_base, POE_DISTR_EN, 1); } SYSINIT(nlm_xlpnae_update_pde, SI_SUB_SMP, SI_ORDER_ANY, nlm_xlpnae_update_pde, NULL); /* configuration common for sgmii, xaui, ilaken goes here */ static void nlm_setup_portcfg(struct nlm_xlpnae_softc *sc, struct xlp_nae_ivars *naep, int block, int port) { int i; uint32_t ucore_mask = 0; struct xlp_block_ivars *bp; struct xlp_port_ivars *p; bp = &(naep->block_ivars[block]); p = &(bp->port_ivars[port & 0x3]); sc->portcfg[port].node = p->node; sc->portcfg[port].block = p->block; sc->portcfg[port].port = p->port; sc->portcfg[port].type = p->type; sc->portcfg[port].mdio_bus = p->mdio_bus; sc->portcfg[port].phy_addr = p->phy_addr; sc->portcfg[port].loopback_mode = p->loopback_mode; sc->portcfg[port].num_channels = p->num_channels; if (p->free_desc_sizes != MCLBYTES) { printf("[%d, %d] Error: free_desc_sizes %d != %d\n", block, port, p->free_desc_sizes, MCLBYTES); return; } sc->portcfg[port].free_desc_sizes = p->free_desc_sizes; for (i = 0; i < sc->nucores; i++) /* XXXJC: configure this */ ucore_mask |= (0x1 << i); sc->portcfg[port].ucore_mask = ucore_mask; sc->portcfg[port].vlan_pri_en = p->vlan_pri_en; sc->portcfg[port].num_free_descs = p->num_free_descs; sc->portcfg[port].iface_fifo_size = p->iface_fifo_size; sc->portcfg[port].rxbuf_size = p->rxbuf_size; sc->portcfg[port].rx_slots_reqd = p->rx_slots_reqd; sc->portcfg[port].tx_slots_reqd = p->tx_slots_reqd; sc->portcfg[port].pseq_fifo_size = p->pseq_fifo_size; sc->portcfg[port].stg2_fifo_size = p->stg2_fifo_size; sc->portcfg[port].eh_fifo_size = p->eh_fifo_size; sc->portcfg[port].frout_fifo_size = p->frout_fifo_size; sc->portcfg[port].ms_fifo_size = p->ms_fifo_size; sc->portcfg[port].pkt_fifo_size = p->pkt_fifo_size; sc->portcfg[port].pktlen_fifo_size = p->pktlen_fifo_size; sc->portcfg[port].max_stg2_offset = p->max_stg2_offset; sc->portcfg[port].max_eh_offset = p->max_eh_offset; sc->portcfg[port].max_frout_offset = p->max_frout_offset; sc->portcfg[port].max_ms_offset = p->max_ms_offset; sc->portcfg[port].max_pmem_offset = p->max_pmem_offset; sc->portcfg[port].stg1_2_credit = p->stg1_2_credit; sc->portcfg[port].stg2_eh_credit = p->stg2_eh_credit; sc->portcfg[port].stg2_frout_credit = p->stg2_frout_credit; sc->portcfg[port].stg2_ms_credit = p->stg2_ms_credit; sc->portcfg[port].ieee1588_inc_intg = p->ieee1588_inc_intg; sc->portcfg[port].ieee1588_inc_den = p->ieee1588_inc_den; sc->portcfg[port].ieee1588_inc_num = p->ieee1588_inc_num; sc->portcfg[port].ieee1588_userval = p->ieee1588_userval; sc->portcfg[port].ieee1588_ptpoff = p->ieee1588_ptpoff; sc->portcfg[port].ieee1588_tmr1 = p->ieee1588_tmr1; sc->portcfg[port].ieee1588_tmr2 = p->ieee1588_tmr2; sc->portcfg[port].ieee1588_tmr3 = p->ieee1588_tmr3; sc->total_free_desc += sc->portcfg[port].free_desc_sizes; sc->total_num_ports++; } static int nlm_xlpnae_attach(device_t dev) { struct xlp_nae_ivars *nae_ivars; struct nlm_xlpnae_softc *sc; device_t tmpd; uint32_t dv[NUM_WORDS_PER_DV]; int port, i, j, nchan, nblock, node, qstart, qnum; int offset, context, txq_base, rxvcbase; uint64_t poe_pcibase, nae_pcibase; node = pci_get_slot(dev) / 8; nae_ivars = &xlp_board_info.nodes[node].nae_ivars; sc = device_get_softc(dev); sc->xlpnae_dev = dev; sc->node = nae_ivars->node; sc->base = nlm_get_nae_regbase(sc->node); sc->poe_base = nlm_get_poe_regbase(sc->node); sc->poedv_base = nlm_get_poedv_regbase(sc->node); sc->portcfg = nae_port_config; sc->blockmask = nae_ivars->blockmask; sc->ilmask = nae_ivars->ilmask; sc->xauimask = nae_ivars->xauimask; sc->sgmiimask = nae_ivars->sgmiimask; sc->nblocks = nae_ivars->nblocks; sc->freq = nae_ivars->freq; /* flow table generation is done by CRC16 polynomial */ sc->flow_crc_poly = nae_ivars->flow_crc_poly; sc->hw_parser_en = nae_ivars->hw_parser_en; sc->prepad_en = nae_ivars->prepad_en; sc->prepad_size = nae_ivars->prepad_size; sc->ieee_1588_en = nae_ivars->ieee_1588_en; nae_pcibase = nlm_get_nae_pcibase(sc->node); sc->ncontexts = nlm_read_reg(nae_pcibase, XLP_PCI_DEVINFO_REG5); sc->nucores = nlm_num_uengines(nae_pcibase); for (nblock = 0; nblock < sc->nblocks; nblock++) { sc->cmplx_type[nblock] = nae_ivars->block_ivars[nblock].type; sc->portmask[nblock] = nae_ivars->block_ivars[nblock].portmask; } for (i = 0; i < sc->ncontexts; i++) cntx2port[i] = 18; /* 18 is an invalid port */ if (sc->nblocks == 5) sc->max_ports = 18; /* 8xx has a block 4 with 2 ports */ else sc->max_ports = sc->nblocks * PORTS_PER_CMPLX; for (i = 0; i < sc->max_ports; i++) sc->portcfg[i].type = UNKNOWN; /* Port Not Present */ /* * Now setup all internal fifo carvings based on * total number of ports in the system */ sc->total_free_desc = 0; sc->total_num_ports = 0; port = 0; context = 0; txq_base = nlm_qidstart(nae_pcibase); rxvcbase = txq_base + sc->ncontexts; for (i = 0; i < sc->nblocks; i++) { uint32_t portmask; if ((nae_ivars->blockmask & (1 << i)) == 0) { port += 4; continue; } portmask = nae_ivars->block_ivars[i].portmask; for (j = 0; j < PORTS_PER_CMPLX; j++, port++) { if ((portmask & (1 << j)) == 0) continue; nlm_setup_portcfg(sc, nae_ivars, i, port); nchan = sc->portcfg[port].num_channels; for (offset = 0; offset < nchan; offset++) cntx2port[context + offset] = port; sc->portcfg[port].txq = txq_base + context; sc->portcfg[port].rxfreeq = rxvcbase + port; context += nchan; } } poe_pcibase = nlm_get_poe_pcibase(sc->node); sc->per_port_num_flows = nlm_poe_max_flows(poe_pcibase) / sc->total_num_ports; /* zone for P2P descriptors */ nl_tx_desc_zone = uma_zcreate("NL Tx Desc", sizeof(struct xlpge_tx_desc), NULL, NULL, NULL, NULL, NAE_CACHELINE_SIZE, 0); /* NAE FMN messages have CMS src station id's in the * range of qstart to qnum. */ qstart = nlm_qidstart(nae_pcibase); qnum = nlm_qnum(nae_pcibase); if (register_msgring_handler(qstart, qstart + qnum - 1, nlm_xlpge_msgring_handler, sc)) { panic("Couldn't register NAE msgring handler\n"); } /* POE FMN messages have CMS src station id's in the * range of qstart to qnum. */ qstart = nlm_qidstart(poe_pcibase); qnum = nlm_qnum(poe_pcibase); if (register_msgring_handler(qstart, qstart + qnum - 1, nlm_xlpge_msgring_handler, sc)) { panic("Couldn't register POE msgring handler\n"); } nlm_xlpnae_init(node, sc); for (i = 0; i < sc->max_ports; i++) { char desc[32]; int block, port; if (sc->portcfg[i].type == UNKNOWN) continue; block = sc->portcfg[i].block; port = sc->portcfg[i].port; tmpd = device_add_child(dev, "xlpge", i); device_set_ivars(tmpd, &(nae_ivars->block_ivars[block].port_ivars[port])); sprintf(desc, "XLP NAE Port %d,%d", block, port); device_set_desc_copy(tmpd, desc); } nlm_setup_iface_fifo_cfg(sc->base, sc->max_ports, sc->portcfg); nlm_setup_rx_base_config(sc->base, sc->max_ports, sc->portcfg); nlm_setup_rx_buf_config(sc->base, sc->max_ports, sc->portcfg); nlm_setup_freein_fifo_cfg(sc->base, sc->portcfg); nlm_program_nae_parser_seq_fifo(sc->base, sc->max_ports, sc->portcfg); nlm_xlpnae_print_frin_desc_carving(sc); bus_generic_probe(dev); bus_generic_attach(dev); /* * Enable only boot cpu at this point, full distribution comes * only after SMP is started */ nlm_write_poe_reg(sc->poe_base, POE_DISTR_EN, 0); nlm_calc_poe_distvec(0x1, 0, 0, 0, 0x1 << XLPGE_RX_VC, dv); nlm_write_poe_distvec(sc->poedv_base, 0, dv); nlm_write_poe_reg(sc->poe_base, POE_DISTR_EN, 1); return (0); } static int nlm_xlpnae_detach(device_t dev) { /* TODO - free zone here */ return (0); } static int nlm_xlpnae_suspend(device_t dev) { return (0); } static int nlm_xlpnae_resume(device_t dev) { return (0); } static int nlm_xlpnae_shutdown(device_t dev) { return (0); } /* * xlpge driver implementation */ static void nlm_xlpge_mac_set_rx_mode(struct nlm_xlpge_softc *sc) { if (sc->if_flags & IFF_PROMISC) { if (sc->type == SGMIIC) nlm_nae_setup_rx_mode_sgmii(sc->base_addr, sc->block, sc->port, sc->type, 1 /* broadcast */, 1/* multicast */, 0 /* pause */, 1 /* promisc */); else nlm_nae_setup_rx_mode_xaui(sc->base_addr, sc->block, sc->port, sc->type, 1 /* broadcast */, 1/* multicast */, 0 /* pause */, 1 /* promisc */); } else { if (sc->type == SGMIIC) nlm_nae_setup_rx_mode_sgmii(sc->base_addr, sc->block, sc->port, sc->type, 1 /* broadcast */, 1/* multicast */, 0 /* pause */, 0 /* promisc */); else nlm_nae_setup_rx_mode_xaui(sc->base_addr, sc->block, sc->port, sc->type, 1 /* broadcast */, 1/* multicast */, 0 /* pause */, 0 /* promisc */); } } static int nlm_xlpge_ioctl(struct ifnet *ifp, u_long command, caddr_t data) { struct mii_data *mii; struct nlm_xlpge_softc *sc; struct ifreq *ifr; int error; sc = ifp->if_softc; error = 0; ifr = (struct ifreq *)data; switch (command) { case SIOCSIFFLAGS: XLPGE_LOCK(sc); sc->if_flags = ifp->if_flags; if (ifp->if_flags & IFF_UP) { if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) nlm_xlpge_init(sc); else nlm_xlpge_port_enable(sc); nlm_xlpge_mac_set_rx_mode(sc); sc->link = NLM_LINK_UP; } else { if (ifp->if_drv_flags & IFF_DRV_RUNNING) nlm_xlpge_port_disable(sc); sc->link = NLM_LINK_DOWN; } XLPGE_UNLOCK(sc); error = 0; break; case SIOCGIFMEDIA: case SIOCSIFMEDIA: if (sc->mii_bus != NULL) { mii = device_get_softc(sc->mii_bus); error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command); } break; default: error = ether_ioctl(ifp, command, data); break; } return (error); } static int xlpge_tx(struct ifnet *ifp, struct mbuf *mbuf_chain) { struct nlm_fmn_msg msg; struct xlpge_tx_desc *p2p; struct nlm_xlpge_softc *sc; struct mbuf *m; vm_paddr_t paddr; int fbid, dst, pos, err; int ret = 0, tx_msgstatus, retries; err = 0; if (mbuf_chain == NULL) return (0); sc = ifp->if_softc; p2p = NULL; if (!(ifp->if_drv_flags & IFF_DRV_RUNNING) || ifp->if_drv_flags & IFF_DRV_OACTIVE) { err = ENXIO; goto fail; } /* free a few in coming messages on the fb vc */ xlp_handle_msg_vc(1 << XLPGE_FB_VC, 2); /* vfb id table is setup to map cpu to vc 3 of the cpu */ fbid = nlm_cpuid(); dst = sc->txq; pos = 0; p2p = uma_zalloc(nl_tx_desc_zone, M_NOWAIT); if (p2p == NULL) { printf("alloc fail\n"); err = ENOBUFS; goto fail; } for (m = mbuf_chain; m != NULL; m = m->m_next) { vm_offset_t buf = (vm_offset_t) m->m_data; int len = m->m_len; int frag_sz; uint64_t desc; /*printf("m_data = %p len %d\n", m->m_data, len); */ while (len) { if (pos == XLP_NTXFRAGS - 3) { device_printf(sc->xlpge_dev, "packet defrag %d\n", m_length(mbuf_chain, NULL)); err = ENOBUFS; /* TODO fix error */ goto fail; } paddr = vtophys(buf); frag_sz = PAGE_SIZE - (buf & PAGE_MASK); if (len < frag_sz) frag_sz = len; desc = nae_tx_desc(P2D_NEOP, 0, 127, frag_sz, paddr); p2p->frag[pos] = htobe64(desc); pos++; len -= frag_sz; buf += frag_sz; } } KASSERT(pos != 0, ("Zero-length mbuf chain?\n")); /* Make the last one P2D EOP */ p2p->frag[pos-1] |= htobe64((uint64_t)P2D_EOP << 62); /* stash useful pointers in the desc */ p2p->frag[XLP_NTXFRAGS-3] = 0xf00bad; p2p->frag[XLP_NTXFRAGS-2] = (uintptr_t)p2p; p2p->frag[XLP_NTXFRAGS-1] = (uintptr_t)mbuf_chain; paddr = vtophys(p2p); msg.msg[0] = nae_tx_desc(P2P, 0, fbid, pos, paddr); for (retries = 16; retries > 0; retries--) { ret = nlm_fmn_msgsend(dst, 1, FMN_SWCODE_NAE, &msg); if (ret == 0) return (0); } fail: if (ret != 0) { tx_msgstatus = nlm_read_c2_txmsgstatus(); if ((tx_msgstatus >> 24) & 0x1) device_printf(sc->xlpge_dev, "Transmit queue full - "); if ((tx_msgstatus >> 3) & 0x1) device_printf(sc->xlpge_dev, "ECC error - "); if ((tx_msgstatus >> 2) & 0x1) device_printf(sc->xlpge_dev, "Pending Sync - "); if ((tx_msgstatus >> 1) & 0x1) device_printf(sc->xlpge_dev, "Insufficient input queue credits - "); if (tx_msgstatus & 0x1) device_printf(sc->xlpge_dev, "Insufficient output queue credits - "); } device_printf(sc->xlpge_dev, "Send failed! err = %d\n", err); if (p2p) uma_zfree(nl_tx_desc_zone, p2p); m_freem(mbuf_chain); if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1); return (err); } static int nlm_xlpge_gmac_config_speed(struct nlm_xlpge_softc *sc) { struct mii_data *mii; if (sc->type == XAUIC || sc->type == ILC) return (0); if (sc->mii_bus) { mii = device_get_softc(sc->mii_bus); mii_pollstat(mii); } return (0); } static void nlm_xlpge_port_disable(struct nlm_xlpge_softc *sc) { struct ifnet *ifp; ifp = sc->xlpge_if; ifp->if_drv_flags &= ~IFF_DRV_RUNNING; callout_stop(&sc->xlpge_callout); nlm_mac_disable(sc->base_addr, sc->block, sc->type, sc->port); } static void nlm_mii_pollstat(void *arg) { struct nlm_xlpge_softc *sc = (struct nlm_xlpge_softc *)arg; struct mii_data *mii = NULL; if (sc->mii_bus) { mii = device_get_softc(sc->mii_bus); KASSERT(mii != NULL, ("mii ptr is NULL")); mii_pollstat(mii); callout_reset(&sc->xlpge_callout, hz, nlm_mii_pollstat, sc); } } static void nlm_xlpge_port_enable(struct nlm_xlpge_softc *sc) { if ((sc->type != SGMIIC) && (sc->type != XAUIC)) return; nlm_mac_enable(sc->base_addr, sc->block, sc->type, sc->port); nlm_mii_pollstat((void *)sc); } static void nlm_xlpge_init(void *addr) { struct nlm_xlpge_softc *sc; struct ifnet *ifp; struct mii_data *mii = NULL; sc = (struct nlm_xlpge_softc *)addr; ifp = sc->xlpge_if; if (ifp->if_drv_flags & IFF_DRV_RUNNING) return; if (sc->mii_bus) { mii = device_get_softc(sc->mii_bus); mii_mediachg(mii); } nlm_xlpge_gmac_config_speed(sc); ifp->if_drv_flags |= IFF_DRV_RUNNING; ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; nlm_xlpge_port_enable(sc); /* start the callout */ callout_reset(&sc->xlpge_callout, hz, nlm_mii_pollstat, sc); } /* * Read the MAC address from FDT or board eeprom. */ static void xlpge_read_mac_addr(struct nlm_xlpge_softc *sc) { xlpge_get_macaddr(sc->dev_addr); /* last octet is port specific */ sc->dev_addr[5] += (sc->block * 4) + sc->port; if (sc->type == SGMIIC) nlm_nae_setup_mac_addr_sgmii(sc->base_addr, sc->block, sc->port, sc->type, sc->dev_addr); else if (sc->type == XAUIC) nlm_nae_setup_mac_addr_xaui(sc->base_addr, sc->block, sc->port, sc->type, sc->dev_addr); } static int xlpge_mediachange(struct ifnet *ifp) { return (0); } static void xlpge_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) { struct nlm_xlpge_softc *sc; struct mii_data *md; md = NULL; sc = ifp->if_softc; if (sc->mii_bus) md = device_get_softc(sc->mii_bus); ifmr->ifm_status = IFM_AVALID; ifmr->ifm_active = IFM_ETHER; if (sc->link == NLM_LINK_DOWN) return; if (md != NULL) ifmr->ifm_active = md->mii_media.ifm_cur->ifm_media; ifmr->ifm_status |= IFM_ACTIVE; } static int nlm_xlpge_ifinit(struct nlm_xlpge_softc *sc) { struct ifnet *ifp; device_t dev; int port = sc->block * 4 + sc->port; dev = sc->xlpge_dev; ifp = sc->xlpge_if = if_alloc(IFT_ETHER); /*(sc->network_sc)->ifp_ports[port].xlpge_if = ifp;*/ ifp_ports[port].xlpge_if = ifp; if (ifp == NULL) { device_printf(dev, "cannot if_alloc()\n"); return (ENOSPC); } ifp->if_softc = sc; if_initname(ifp, device_get_name(dev), device_get_unit(dev)); ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; sc->if_flags = ifp->if_flags; /*ifp->if_capabilities = IFCAP_TXCSUM | IFCAP_VLAN_HWTAGGING;*/ ifp->if_capabilities = 0; ifp->if_capenable = ifp->if_capabilities; ifp->if_ioctl = nlm_xlpge_ioctl; ifp->if_init = nlm_xlpge_init ; ifp->if_hwassist = 0; ifp->if_snd.ifq_drv_maxlen = NLM_XLPGE_TXQ_SIZE; /* TODO: make this a sysint */ IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); IFQ_SET_READY(&ifp->if_snd); ifmedia_init(&sc->xlpge_mii.mii_media, 0, xlpge_mediachange, xlpge_mediastatus); ifmedia_add(&sc->xlpge_mii.mii_media, IFM_ETHER | IFM_AUTO, 0, NULL); ifmedia_set(&sc->xlpge_mii.mii_media, IFM_ETHER | IFM_AUTO); sc->xlpge_mii.mii_media.ifm_media = sc->xlpge_mii.mii_media.ifm_cur->ifm_media; xlpge_read_mac_addr(sc); ether_ifattach(ifp, sc->dev_addr); /* override if_transmit : per ifnet(9), do it after if_attach */ ifp->if_transmit = xlpge_tx; return (0); } static int nlm_xlpge_probe(device_t dev) { return (BUS_PROBE_DEFAULT); } static void * get_buf(void) { struct mbuf *m_new; uint64_t *md; #ifdef INVARIANTS vm_paddr_t temp1, temp2; #endif if ((m_new = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR)) == NULL) return (NULL); m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; KASSERT(((uintptr_t)m_new->m_data & (NAE_CACHELINE_SIZE - 1)) == 0, ("m_new->m_data is not cacheline aligned")); md = (uint64_t *)m_new->m_data; md[0] = (intptr_t)m_new; /* Back Ptr */ md[1] = 0xf00bad; m_adj(m_new, NAE_CACHELINE_SIZE); #ifdef INVARIANTS temp1 = vtophys((vm_offset_t) m_new->m_data); temp2 = vtophys((vm_offset_t) m_new->m_data + 1536); KASSERT((temp1 + 1536) == temp2, ("Alloced buffer is not contiguous")); #endif return ((void *)m_new->m_data); } static void nlm_xlpge_mii_init(device_t dev, struct nlm_xlpge_softc *sc) { int error; error = mii_attach(dev, &sc->mii_bus, sc->xlpge_if, xlpge_mediachange, xlpge_mediastatus, BMSR_DEFCAPMASK, sc->phy_addr, MII_OFFSET_ANY, 0); if (error) { device_printf(dev, "attaching PHYs failed\n"); sc->mii_bus = NULL; } if (sc->mii_bus != NULL) { /* enable MDIO interrupts in the PHY */ /* XXXJC: TODO */ } } static int xlpge_stats_sysctl(SYSCTL_HANDLER_ARGS) { struct nlm_xlpge_softc *sc; uint32_t val; int reg, field; sc = arg1; field = arg2; reg = SGMII_STATS_MLR(sc->block, sc->port) + field; val = nlm_read_nae_reg(sc->base_addr, reg); return (sysctl_handle_int(oidp, &val, 0, req)); } static void nlm_xlpge_setup_stats_sysctl(device_t dev, struct nlm_xlpge_softc *sc) { struct sysctl_ctx_list *ctx; struct sysctl_oid_list *child; struct sysctl_oid *tree; ctx = device_get_sysctl_ctx(dev); tree = device_get_sysctl_tree(dev); child = SYSCTL_CHILDREN(tree); #define XLPGE_STAT(name, offset, desc) \ SYSCTL_ADD_PROC(ctx, child, OID_AUTO, name, \ CTLTYPE_UINT | CTLFLAG_RD, sc, offset, \ xlpge_stats_sysctl, "IU", desc) XLPGE_STAT("tr127", nlm_sgmii_stats_tr127, "TxRx 64 - 127 Bytes"); XLPGE_STAT("tr255", nlm_sgmii_stats_tr255, "TxRx 128 - 255 Bytes"); XLPGE_STAT("tr511", nlm_sgmii_stats_tr511, "TxRx 256 - 511 Bytes"); XLPGE_STAT("tr1k", nlm_sgmii_stats_tr1k, "TxRx 512 - 1023 Bytes"); XLPGE_STAT("trmax", nlm_sgmii_stats_trmax, "TxRx 1024 - 1518 Bytes"); XLPGE_STAT("trmgv", nlm_sgmii_stats_trmgv, "TxRx 1519 - 1522 Bytes"); XLPGE_STAT("rbyt", nlm_sgmii_stats_rbyt, "Rx Bytes"); XLPGE_STAT("rpkt", nlm_sgmii_stats_rpkt, "Rx Packets"); XLPGE_STAT("rfcs", nlm_sgmii_stats_rfcs, "Rx FCS Error"); XLPGE_STAT("rmca", nlm_sgmii_stats_rmca, "Rx Multicast Packets"); XLPGE_STAT("rbca", nlm_sgmii_stats_rbca, "Rx Broadcast Packets"); XLPGE_STAT("rxcf", nlm_sgmii_stats_rxcf, "Rx Control Frames"); XLPGE_STAT("rxpf", nlm_sgmii_stats_rxpf, "Rx Pause Frames"); XLPGE_STAT("rxuo", nlm_sgmii_stats_rxuo, "Rx Unknown Opcode"); XLPGE_STAT("raln", nlm_sgmii_stats_raln, "Rx Alignment Errors"); XLPGE_STAT("rflr", nlm_sgmii_stats_rflr, "Rx Framelength Errors"); XLPGE_STAT("rcde", nlm_sgmii_stats_rcde, "Rx Code Errors"); XLPGE_STAT("rcse", nlm_sgmii_stats_rcse, "Rx Carrier Sense Errors"); XLPGE_STAT("rund", nlm_sgmii_stats_rund, "Rx Undersize Packet Errors"); XLPGE_STAT("rovr", nlm_sgmii_stats_rovr, "Rx Oversize Packet Errors"); XLPGE_STAT("rfrg", nlm_sgmii_stats_rfrg, "Rx Fragments"); XLPGE_STAT("rjbr", nlm_sgmii_stats_rjbr, "Rx Jabber"); XLPGE_STAT("tbyt", nlm_sgmii_stats_tbyt, "Tx Bytes"); XLPGE_STAT("tpkt", nlm_sgmii_stats_tpkt, "Tx Packets"); XLPGE_STAT("tmca", nlm_sgmii_stats_tmca, "Tx Multicast Packets"); XLPGE_STAT("tbca", nlm_sgmii_stats_tbca, "Tx Broadcast Packets"); XLPGE_STAT("txpf", nlm_sgmii_stats_txpf, "Tx Pause Frame"); XLPGE_STAT("tdfr", nlm_sgmii_stats_tdfr, "Tx Deferral Packets"); XLPGE_STAT("tedf", nlm_sgmii_stats_tedf, "Tx Excessive Deferral Pkts"); XLPGE_STAT("tscl", nlm_sgmii_stats_tscl, "Tx Single Collisions"); XLPGE_STAT("tmcl", nlm_sgmii_stats_tmcl, "Tx Multiple Collisions"); XLPGE_STAT("tlcl", nlm_sgmii_stats_tlcl, "Tx Late Collision Pkts"); XLPGE_STAT("txcl", nlm_sgmii_stats_txcl, "Tx Excessive Collisions"); XLPGE_STAT("tncl", nlm_sgmii_stats_tncl, "Tx Total Collisions"); XLPGE_STAT("tjbr", nlm_sgmii_stats_tjbr, "Tx Jabber Frames"); XLPGE_STAT("tfcs", nlm_sgmii_stats_tfcs, "Tx FCS Errors"); XLPGE_STAT("txcf", nlm_sgmii_stats_txcf, "Tx Control Frames"); XLPGE_STAT("tovr", nlm_sgmii_stats_tovr, "Tx Oversize Frames"); XLPGE_STAT("tund", nlm_sgmii_stats_tund, "Tx Undersize Frames"); XLPGE_STAT("tfrg", nlm_sgmii_stats_tfrg, "Tx Fragments"); #undef XLPGE_STAT } static int nlm_xlpge_attach(device_t dev) { struct xlp_port_ivars *pv; struct nlm_xlpge_softc *sc; int port; pv = device_get_ivars(dev); sc = device_get_softc(dev); sc->xlpge_dev = dev; sc->mii_bus = NULL; sc->block = pv->block; sc->node = pv->node; sc->port = pv->port; sc->type = pv->type; sc->xlpge_if = NULL; sc->phy_addr = pv->phy_addr; sc->mdio_bus = pv->mdio_bus; sc->portcfg = nae_port_config; sc->hw_parser_en = pv->hw_parser_en; /* default settings */ sc->speed = NLM_SGMII_SPEED_10; sc->duplexity = NLM_SGMII_DUPLEX_FULL; sc->link = NLM_LINK_DOWN; sc->flowctrl = NLM_FLOWCTRL_DISABLED; sc->network_sc = device_get_softc(device_get_parent(dev)); sc->base_addr = sc->network_sc->base; sc->prepad_en = sc->network_sc->prepad_en; sc->prepad_size = sc->network_sc->prepad_size; callout_init(&sc->xlpge_callout, 1); XLPGE_LOCK_INIT(sc, device_get_nameunit(dev)); port = (sc->block*4)+sc->port; sc->nfree_desc = nae_port_config[port].num_free_descs; sc->txq = nae_port_config[port].txq; sc->rxfreeq = nae_port_config[port].rxfreeq; nlm_xlpge_submit_rx_free_desc(sc, sc->nfree_desc); if (sc->hw_parser_en) nlm_enable_hardware_parser_per_port(sc->base_addr, sc->block, sc->port); nlm_xlpge_ifinit(sc); ifp_ports[port].xlpge_sc = sc; nlm_xlpge_mii_init(dev, sc); nlm_xlpge_setup_stats_sysctl(dev, sc); return (0); } static int nlm_xlpge_detach(device_t dev) { return (0); } static int nlm_xlpge_suspend(device_t dev) { return (0); } static int nlm_xlpge_resume(device_t dev) { return (0); } static int nlm_xlpge_shutdown(device_t dev) { return (0); } /* * miibus function with custom implementation */ static int nlm_xlpge_mii_read(device_t dev, int phyaddr, int regidx) { struct nlm_xlpge_softc *sc; int val; sc = device_get_softc(dev); if (sc->type == SGMIIC) val = nlm_gmac_mdio_read(sc->base_addr, sc->mdio_bus, BLOCK_7, LANE_CFG, phyaddr, regidx); else val = 0xffff; return (val); } static int nlm_xlpge_mii_write(device_t dev, int phyaddr, int regidx, int val) { struct nlm_xlpge_softc *sc; sc = device_get_softc(dev); if (sc->type == SGMIIC) nlm_gmac_mdio_write(sc->base_addr, sc->mdio_bus, BLOCK_7, LANE_CFG, phyaddr, regidx, val); return (0); } static void nlm_xlpge_mii_statchg(device_t dev) { struct nlm_xlpge_softc *sc; struct mii_data *mii; char *speed, *duplexity; sc = device_get_softc(dev); if (sc->mii_bus == NULL) return; mii = device_get_softc(sc->mii_bus); if (mii->mii_media_status & IFM_ACTIVE) { if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T) { sc->speed = NLM_SGMII_SPEED_10; speed = "10Mbps"; } else if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) { sc->speed = NLM_SGMII_SPEED_100; speed = "100Mbps"; } else { /* default to 1G */ sc->speed = NLM_SGMII_SPEED_1000; speed = "1Gbps"; } if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) { sc->duplexity = NLM_SGMII_DUPLEX_FULL; duplexity = "full"; } else { sc->duplexity = NLM_SGMII_DUPLEX_HALF; duplexity = "half"; } printf("Port [%d, %d] setup with speed=%s duplex=%s\n", sc->block, sc->port, speed, duplexity); nlm_nae_setup_mac(sc->base_addr, sc->block, sc->port, 0, 1, 1, sc->speed, sc->duplexity); } } /* * xlpge support function implementations */ static void nlm_xlpge_release_mbuf(uint64_t paddr) { uint64_t mag, desc, mbuf; paddr += (XLP_NTXFRAGS - 3) * sizeof(uint64_t); mag = nlm_paddr_ld(paddr); desc = nlm_paddr_ld(paddr + sizeof(uint64_t)); mbuf = nlm_paddr_ld(paddr + 2 * sizeof(uint64_t)); if (mag != 0xf00bad) { /* somebody else packet Error - FIXME in intialization */ printf("cpu %d: ERR Tx packet paddr %jx, mag %jx, desc %jx mbuf %jx\n", nlm_cpuid(), (uintmax_t)paddr, (uintmax_t)mag, (intmax_t)desc, (uintmax_t)mbuf); return; } m_freem((struct mbuf *)(uintptr_t)mbuf); uma_zfree(nl_tx_desc_zone, (void *)(uintptr_t)desc); } static void nlm_xlpge_rx(struct nlm_xlpge_softc *sc, int port, vm_paddr_t paddr, int len) { struct ifnet *ifp; struct mbuf *m; vm_offset_t temp; unsigned long mag; int prepad_size; ifp = sc->xlpge_if; temp = nlm_paddr_ld(paddr - NAE_CACHELINE_SIZE); mag = nlm_paddr_ld(paddr - NAE_CACHELINE_SIZE + sizeof(uint64_t)); m = (struct mbuf *)(intptr_t)temp; if (mag != 0xf00bad) { /* somebody else packet Error - FIXME in intialization */ printf("cpu %d: ERR Rx packet paddr %jx, temp %p, mag %lx\n", nlm_cpuid(), (uintmax_t)paddr, (void *)temp, mag); return; } m->m_pkthdr.rcvif = ifp; #ifdef DUMP_PACKET { int i = 0, j = 64; unsigned char *buf = (char *)m->m_data; printf("(cpu_%d: nlge_rx, !RX_COPY) Rx Packet: length=%d\n", nlm_cpuid(), len); if (len < j) j = len; if (sc->prepad_en) j += ((sc->prepad_size + 1) * 16); for (i = 0; i < j; i++) { if (i && (i % 16) == 0) printf("\n"); printf("%02x ", buf[i]); } printf("\n"); } #endif if (sc->prepad_en) { prepad_size = ((sc->prepad_size + 1) * 16); m->m_data += prepad_size; m->m_pkthdr.len = m->m_len = (len - prepad_size); } else m->m_pkthdr.len = m->m_len = len; if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); #ifdef XLP_DRIVER_LOOPBACK if (port == 16 || port == 17) (*ifp->if_input)(ifp, m); else xlpge_tx(ifp, m); #else (*ifp->if_input)(ifp, m); #endif } void nlm_xlpge_submit_rx_free_desc(struct nlm_xlpge_softc *sc, int num) { int i, size, ret, n; struct nlm_fmn_msg msg; void *ptr; for(i = 0; i < num; i++) { memset(&msg, 0, sizeof(msg)); ptr = get_buf(); if (!ptr) { device_printf(sc->xlpge_dev, "Cannot allocate mbuf\n"); break; } msg.msg[0] = vtophys(ptr); if (msg.msg[0] == 0) { printf("Bad ptr for %p\n", ptr); break; } size = 1; n = 0; while (1) { /* on success returns 1, else 0 */ ret = nlm_fmn_msgsend(sc->rxfreeq, size, 0, &msg); if (ret == 0) break; if (n++ > 10000) { printf("Too many credit fails for send free desc\n"); break; } } } } void nlm_xlpge_msgring_handler(int vc, int size, int code, int src_id, struct nlm_fmn_msg *msg, void *data) { uint64_t phys_addr; struct nlm_xlpnae_softc *sc; struct nlm_xlpge_softc *xlpge_sc; struct ifnet *ifp; uint32_t context; uint32_t port = 0; uint32_t length; sc = (struct nlm_xlpnae_softc *)data; KASSERT(sc != NULL, ("Null sc in msgring handler")); if (size == 1) { /* process transmit complete */ phys_addr = msg->msg[0] & 0xffffffffffULL; /* context is SGMII_RCV_CONTEXT_NUM + three bit vlan type * or vlan priority */ context = (msg->msg[0] >> 40) & 0x3fff; port = cntx2port[context]; if (port >= XLP_MAX_PORTS) { printf("%s:%d Bad port %d (context=%d)\n", __func__, __LINE__, port, context); return; } ifp = ifp_ports[port].xlpge_if; xlpge_sc = ifp_ports[port].xlpge_sc; nlm_xlpge_release_mbuf(phys_addr); if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); } else if (size > 1) { /* Recieve packet */ phys_addr = msg->msg[1] & 0xffffffffc0ULL; length = (msg->msg[1] >> 40) & 0x3fff; length -= MAC_CRC_LEN; /* context is SGMII_RCV_CONTEXT_NUM + three bit vlan type * or vlan priority */ context = (msg->msg[1] >> 54) & 0x3ff; port = cntx2port[context]; if (port >= XLP_MAX_PORTS) { printf("%s:%d Bad port %d (context=%d)\n", __func__, __LINE__, port, context); return; } ifp = ifp_ports[port].xlpge_if; xlpge_sc = ifp_ports[port].xlpge_sc; nlm_xlpge_rx(xlpge_sc, port, phys_addr, length); /* return back a free descriptor to NA */ nlm_xlpge_submit_rx_free_desc(xlpge_sc, 1); } } Index: head/sys/mips/nlm/dev/net/xlpge.h =================================================================== --- head/sys/mips/nlm/dev/net/xlpge.h (revision 326258) +++ head/sys/mips/nlm/dev/net/xlpge.h (revision 326259) @@ -1,138 +1,140 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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$ */ #ifndef __XLPGE_H__ #define __XLPGE_H__ #define NLM_XLPGE_TXQ_SIZE 1024 #define MAC_CRC_LEN 4 enum xlpge_link_state { NLM_LINK_DOWN, NLM_LINK_UP }; enum xlpge_floctrl_status { NLM_FLOWCTRL_DISABLED, NLM_FLOWCTRL_ENABLED }; struct nlm_xlp_portdata { struct ifnet *xlpge_if; struct nlm_xlpge_softc *xlpge_sc; }; struct nlm_xlpnae_softc { device_t xlpnae_dev; int node; /* XLP Node id */ uint64_t base; /* NAE IO base */ uint64_t poe_base; /* POE IO base */ uint64_t poedv_base; /* POE distribution vec IO base */ int freq; /* frequency of nae block */ int flow_crc_poly; /* Flow CRC16 polynomial */ int total_free_desc; /* total for node */ int max_ports; int total_num_ports; int per_port_num_flows; u_int nucores; u_int nblocks; u_int num_complex; u_int ncontexts; /* Ingress side parameters */ u_int num_desc; /* no of descriptors in each packet */ u_int parser_threshold;/* threshold of entries above which */ /* the parser sequencer is scheduled */ /* NetIOR configs */ u_int cmplx_type[8]; /* XXXJC: redundant? */ struct nae_port_config *portcfg; u_int blockmask; u_int portmask[XLP_NAE_NBLOCKS]; u_int ilmask; u_int xauimask; u_int sgmiimask; u_int hw_parser_en; u_int prepad_en; u_int prepad_size; u_int driver_mode; u_int ieee_1588_en; }; struct nlm_xlpge_softc { struct ifnet *xlpge_if; /* should be first member */ /* see - mii.c:miibus_attach() */ device_t xlpge_dev; device_t mii_bus; struct nlm_xlpnae_softc *network_sc; uint64_t base_addr; /* NAE IO base */ int node; /* node id (quickread) */ int block; /* network block id (quickread) */ int port; /* port id - among the 18 in XLP */ int type; /* port type - see xlp_gmac_port_types */ int valid; /* boolean: valid port or not */ struct mii_data xlpge_mii; int nfree_desc; /* No of free descriptors sent to port */ int phy_addr; /* PHY id for the interface */ int speed; /* Port speed */ int duplexity; /* Port duplexity */ int link; /* Port link status */ int flowctrl; /* Port flow control setting */ unsigned char dev_addr[ETHER_ADDR_LEN]; struct mtx sc_lock; int if_flags; struct nae_port_config *portcfg; struct callout xlpge_callout; int mdio_bus; int txq; int rxfreeq; int hw_parser_en; int prepad_en; int prepad_size; }; #define XLP_NTXFRAGS 16 #define NULL_VFBID 127 struct xlpge_tx_desc { uint64_t frag[XLP_NTXFRAGS]; }; #define XLPGE_LOCK_INIT(_sc, _name) \ mtx_init(&(_sc)->sc_lock, _name, MTX_NETWORK_LOCK, MTX_DEF) #define XLPGE_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_lock) #define XLPGE_LOCK(_sc) mtx_lock(&(_sc)->sc_lock) #define XLPGE_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_lock) #define XLPGE_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_lock, MA_OWNED) #endif Index: head/sys/mips/nlm/dev/sec/nlmrsa.c =================================================================== --- head/sys/mips/nlm/dev/sec/nlmrsa.c (revision 326258) +++ head/sys/mips/nlm/dev/sec/nlmrsa.c (revision 326259) @@ -1,555 +1,557 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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 #include #include #include #include "cryptodev_if.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef NLM_RSA_DEBUG static void print_krp_params(struct cryptkop *krp); #endif static int xlp_rsa_init(struct xlp_rsa_softc *sc, int node); static int xlp_rsa_newsession(device_t , uint32_t *, struct cryptoini *); static int xlp_rsa_freesession(device_t , uint64_t); static int xlp_rsa_kprocess(device_t , struct cryptkop *, int); static int xlp_get_rsa_opsize(struct xlp_rsa_command *cmd, unsigned int bits); static void xlp_free_cmd_params(struct xlp_rsa_command *cmd); static int xlp_rsa_inp2hwformat(uint8_t *src, uint8_t *dst, uint32_t paramsize, uint8_t result); static int xlp_rsa_probe(device_t); static int xlp_rsa_attach(device_t); static int xlp_rsa_detach(device_t); static device_method_t xlp_rsa_methods[] = { /* device interface */ DEVMETHOD(device_probe, xlp_rsa_probe), DEVMETHOD(device_attach, xlp_rsa_attach), DEVMETHOD(device_detach, xlp_rsa_detach), /* bus interface */ DEVMETHOD(bus_print_child, bus_generic_print_child), DEVMETHOD(bus_driver_added, bus_generic_driver_added), /* crypto device methods */ DEVMETHOD(cryptodev_newsession, xlp_rsa_newsession), DEVMETHOD(cryptodev_freesession, xlp_rsa_freesession), DEVMETHOD(cryptodev_kprocess, xlp_rsa_kprocess), DEVMETHOD_END }; static driver_t xlp_rsa_driver = { "nlmrsa", xlp_rsa_methods, sizeof(struct xlp_rsa_softc) }; static devclass_t xlp_rsa_devclass; DRIVER_MODULE(nlmrsa, pci, xlp_rsa_driver, xlp_rsa_devclass, 0, 0); MODULE_DEPEND(nlmrsa, crypto, 1, 1, 1); #ifdef NLM_RSA_DEBUG static void print_krp_params(struct cryptkop *krp) { int i; printf("krp->krp_op :%d\n", krp->krp_op); printf("krp->krp_status :%d\n", krp->krp_status); printf("krp->krp_iparams:%d\n", krp->krp_iparams); printf("krp->krp_oparams:%d\n", krp->krp_oparams); for (i = 0; i < krp->krp_iparams + krp->krp_oparams; i++) { printf("krp->krp_param[%d].crp_p :0x%llx\n", i, (unsigned long long)krp->krp_param[i].crp_p); printf("krp->krp_param[%d].crp_nbits :%d\n", i, krp->krp_param[i].crp_nbits); printf("krp->krp_param[%d].crp_nbytes :%d\n", i, howmany(krp->krp_param[i].crp_nbits, 8)); } } #endif static int xlp_rsa_init(struct xlp_rsa_softc *sc, int node) { struct xlp_rsa_command *cmd = NULL; uint32_t fbvc, dstvc, endsel, regval; struct nlm_fmn_msg m; int err, ret, i; uint64_t base; /* Register interrupt handler for the RSA/ECC CMS messages */ if (register_msgring_handler(sc->rsaecc_vc_start, sc->rsaecc_vc_end, nlm_xlprsaecc_msgring_handler, sc) != 0) { err = -1; printf("Couldn't register rsa/ecc msgring handler\n"); goto errout; } fbvc = nlm_cpuid() * 4 + XLPGE_FB_VC; /* Do the CMS credit initialization */ /* Currently it is configured by default to 50 when kernel comes up */ #if BYTE_ORDER == LITTLE_ENDIAN for (i = 0; i < nitems(nlm_rsa_ucode_data); i++) nlm_rsa_ucode_data[i] = htobe64(nlm_rsa_ucode_data[i]); #endif for (dstvc = sc->rsaecc_vc_start; dstvc <= sc->rsaecc_vc_end; dstvc++) { cmd = malloc(sizeof(struct xlp_rsa_command), M_DEVBUF, M_NOWAIT | M_ZERO); KASSERT(cmd != NULL, ("%s:cmd is NULL\n", __func__)); cmd->rsasrc = contigmalloc(sizeof(nlm_rsa_ucode_data), M_DEVBUF, (M_WAITOK | M_ZERO), 0UL /* low address */, -1UL /* high address */, XLP_L2L3_CACHELINE_SIZE /* alignment */, 0UL /* boundary */); KASSERT(cmd->rsasrc != NULL, ("%s:cmd->rsasrc is NULL\n", __func__)); memcpy(cmd->rsasrc, nlm_rsa_ucode_data, sizeof(nlm_rsa_ucode_data)); m.msg[0] = nlm_crypto_form_rsa_ecc_fmn_entry0(1, 0x70, 0, vtophys(cmd->rsasrc)); m.msg[1] = nlm_crypto_form_rsa_ecc_fmn_entry1(0, 1, fbvc, vtophys(cmd->rsasrc)); /* Software scratch pad */ m.msg[2] = (uintptr_t)cmd; m.msg[3] = 0; ret = nlm_fmn_msgsend(dstvc, 3, FMN_SWCODE_RSA, &m); if (ret != 0) { err = -1; printf("%s: msgsnd failed (%x)\n", __func__, ret); goto errout; } } /* Configure so that all VCs send request to all RSA pipes */ base = nlm_get_rsa_regbase(node); if (nlm_is_xlp3xx()) { endsel = 1; regval = 0xFFFF; } else { endsel = 3; regval = 0x07FFFFFF; } for (i = 0; i < endsel; i++) nlm_write_rsa_reg(base, RSA_ENG_SEL_0 + i, regval); return (0); errout: xlp_free_cmd_params(cmd); return (err); } /* This function is called from an interrupt handler */ void nlm_xlprsaecc_msgring_handler(int vc, int size, int code, int src_id, struct nlm_fmn_msg *msg, void *data) { struct xlp_rsa_command *cmd; struct xlp_rsa_softc *sc; struct crparam *outparam; int ostart; KASSERT(code == FMN_SWCODE_RSA, ("%s: bad code = %d, expected code = %d\n", __func__, code, FMN_SWCODE_RSA)); sc = data; KASSERT(src_id >= sc->rsaecc_vc_start && src_id <= sc->rsaecc_vc_end, ("%s: bad src_id = %d, expect %d - %d\n", __func__, src_id, sc->rsaecc_vc_start, sc->rsaecc_vc_end)); cmd = (struct xlp_rsa_command *)(uintptr_t)msg->msg[1]; KASSERT(cmd != NULL, ("%s:cmd not received properly\n", __func__)); if (RSA_ERROR(msg->msg[0]) != 0) { printf("%s: Message rcv msg0 %llx msg1 %llx err %x \n", __func__, (unsigned long long)msg->msg[0], (unsigned long long)msg->msg[1], (int)RSA_ERROR(msg->msg[0])); cmd->krp->krp_status = EBADMSG; } if (cmd->krp != NULL) { ostart = cmd->krp->krp_iparams; outparam = &cmd->krp->krp_param[ostart]; xlp_rsa_inp2hwformat(cmd->rsasrc + cmd->rsaopsize * ostart, outparam->crp_p, howmany(outparam->crp_nbits, 8), 1); crypto_kdone(cmd->krp); } xlp_free_cmd_params(cmd); } static int xlp_rsa_probe(device_t dev) { struct xlp_rsa_softc *sc; if (pci_get_vendor(dev) == PCI_VENDOR_NETLOGIC && pci_get_device(dev) == PCI_DEVICE_ID_NLM_RSA) { sc = device_get_softc(dev); return (BUS_PROBE_DEFAULT); } return (ENXIO); } /* * Attach an interface that successfully probed. */ static int xlp_rsa_attach(device_t dev) { struct xlp_rsa_softc *sc = device_get_softc(dev); uint64_t base; int qstart, qnum; int freq, node; sc->sc_dev = dev; node = nlm_get_device_node(pci_get_slot(dev)); freq = nlm_set_device_frequency(node, DFS_DEVICE_RSA, 250); if (bootverbose) device_printf(dev, "RSA Freq: %dMHz\n", freq); if (pci_get_device(dev) == PCI_DEVICE_ID_NLM_RSA) { device_set_desc(dev, "XLP RSA/ECC Accelerator"); if ((sc->sc_cid = crypto_get_driverid(dev, CRYPTOCAP_F_HARDWARE)) < 0) { printf("xlp_rsaecc-err:couldn't get the driver id\n"); goto error_exit; } if (crypto_kregister(sc->sc_cid, CRK_MOD_EXP, 0) != 0) goto error_exit; base = nlm_get_rsa_pcibase(node); qstart = nlm_qidstart(base); qnum = nlm_qnum(base); sc->rsaecc_vc_start = qstart; sc->rsaecc_vc_end = qstart + qnum - 1; } if (xlp_rsa_init(sc, node) != 0) goto error_exit; device_printf(dev, "RSA Initialization complete!\n"); return (0); error_exit: return (ENXIO); } /* * Detach an interface that successfully probed. */ static int xlp_rsa_detach(device_t dev) { return (0); } /* * Allocate a new 'session' and return an encoded session id. 'sidp' * contains our registration id, and should contain an encoded session * id on successful allocation. */ static int xlp_rsa_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri) { struct xlp_rsa_softc *sc = device_get_softc(dev); struct xlp_rsa_session *ses = NULL; int sesn; if (sidp == NULL || cri == NULL || sc == NULL) return (EINVAL); if (sc->sc_sessions == NULL) { ses = sc->sc_sessions = malloc(sizeof(struct xlp_rsa_session), M_DEVBUF, M_NOWAIT); if (ses == NULL) return (ENOMEM); sesn = 0; sc->sc_nsessions = 1; } else { for (sesn = 0; sesn < sc->sc_nsessions; sesn++) { if (!sc->sc_sessions[sesn].hs_used) { ses = &sc->sc_sessions[sesn]; break; } } if (ses == NULL) { sesn = sc->sc_nsessions; ses = malloc((sesn + 1) * sizeof(*ses), M_DEVBUF, M_NOWAIT); if (ses == NULL) return (ENOMEM); bcopy(sc->sc_sessions, ses, sesn * sizeof(*ses)); bzero(sc->sc_sessions, sesn * sizeof(*ses)); free(sc->sc_sessions, M_DEVBUF); sc->sc_sessions = ses; ses = &sc->sc_sessions[sesn]; sc->sc_nsessions++; } } bzero(ses, sizeof(*ses)); ses->sessionid = sesn; ses->hs_used = 1; *sidp = XLP_RSA_SID(device_get_unit(sc->sc_dev), sesn); return (0); } /* * Deallocate a session. * XXX this routine should run a zero'd mac/encrypt key into context ram. * XXX to blow away any keys already stored there. */ static int xlp_rsa_freesession(device_t dev, u_int64_t tid) { struct xlp_rsa_softc *sc = device_get_softc(dev); int session; u_int32_t sid = CRYPTO_SESID2LID(tid); if (sc == NULL) return (EINVAL); session = XLP_RSA_SESSION(sid); if (session >= sc->sc_nsessions) return (EINVAL); sc->sc_sessions[session].hs_used = 0; return (0); } static void xlp_free_cmd_params(struct xlp_rsa_command *cmd) { if (cmd == NULL) return; if (cmd->rsasrc != NULL) { if (cmd->krp == NULL) /* Micro code load */ contigfree(cmd->rsasrc, sizeof(nlm_rsa_ucode_data), M_DEVBUF); else free(cmd->rsasrc, M_DEVBUF); } free(cmd, M_DEVBUF); } static int xlp_get_rsa_opsize(struct xlp_rsa_command *cmd, unsigned int bits) { if (bits == 0 || bits > 8192) return (-1); /* XLP hardware expects always a fixed size with unused bytes * zeroed out in the input data */ if (bits <= 512) { cmd->rsatype = 0x40; cmd->rsaopsize = 64; } else if (bits <= 1024) { cmd->rsatype = 0x41; cmd->rsaopsize = 128; } else if (bits <= 2048) { cmd->rsatype = 0x42; cmd->rsaopsize = 256; } else if (bits <= 4096) { cmd->rsatype = 0x43; cmd->rsaopsize = 512; } else if (bits <= 8192) { cmd->rsatype = 0x44; cmd->rsaopsize = 1024; } return (0); } static int xlp_rsa_inp2hwformat(uint8_t *src, uint8_t *dst, uint32_t paramsize, uint8_t result) { uint32_t pdwords, pbytes; int i, j, k; pdwords = paramsize / 8; pbytes = paramsize % 8; for (i = 0, k = 0; i < pdwords; i++) { /* copy dwords of inp/hw to hw/out format */ for (j = 7; j >= 0; j--, k++) dst[i * 8 + j] = src[k]; } if (pbytes) { if (result == 0) { /* copy rem bytes of input data to hw format */ for (j = 7; k < paramsize; j--, k++) dst[i * 8 + j] = src[k]; } else { /* copy rem bytes of hw data to exp output format */ for (j = 7; k < paramsize; j--, k++) dst[k] = src[i * 8 + j]; } } return (0); } static int nlm_crypto_complete_rsa_request(struct xlp_rsa_softc *sc, struct xlp_rsa_command *cmd) { unsigned int fbvc; struct nlm_fmn_msg m; int ret; fbvc = nlm_cpuid() * 4 + XLPGE_FB_VC; m.msg[0] = nlm_crypto_form_rsa_ecc_fmn_entry0(1, cmd->rsatype, cmd->rsafn, vtophys(cmd->rsasrc)); m.msg[1] = nlm_crypto_form_rsa_ecc_fmn_entry1(0, 1, fbvc, vtophys(cmd->rsasrc + cmd->rsaopsize * cmd->krp->krp_iparams)); /* Software scratch pad */ m.msg[2] = (uintptr_t)cmd; m.msg[3] = 0; /* Send the message to rsa engine vc */ ret = nlm_fmn_msgsend(sc->rsaecc_vc_start, 3, FMN_SWCODE_RSA, &m); if (ret != 0) { #ifdef NLM_SEC_DEBUG printf("%s: msgsnd failed (%x)\n", __func__, ret); #endif return (ERESTART); } return (0); } static int xlp_rsa_kprocess(device_t dev, struct cryptkop *krp, int hint) { struct xlp_rsa_softc *sc = device_get_softc(dev); struct xlp_rsa_command *cmd; struct crparam *kp; int err, i; if (krp == NULL || krp->krp_callback == NULL) return (EINVAL); cmd = malloc(sizeof(struct xlp_rsa_command), M_DEVBUF, M_NOWAIT | M_ZERO); KASSERT(cmd != NULL, ("%s:cmd is NULL\n", __func__)); cmd->krp = krp; #ifdef NLM_RSA_DEBUG print_krp_params(krp); #endif err = EOPNOTSUPP; switch (krp->krp_op) { case CRK_MOD_EXP: if (krp->krp_iparams == 3 && krp->krp_oparams == 1) break; goto errout; default: device_printf(dev, "Op:%d not yet supported\n", krp->krp_op); goto errout; } err = xlp_get_rsa_opsize(cmd, krp->krp_param[krp->krp_iparams - 1].crp_nbits); if (err != 0) { err = EINVAL; goto errout; } cmd->rsafn = 0; /* Mod Exp */ cmd->rsasrc = malloc( cmd->rsaopsize * (krp->krp_iparams + krp->krp_oparams), M_DEVBUF, M_NOWAIT | M_ZERO); if (cmd->rsasrc == NULL) { err = ENOMEM; goto errout; } for (i = 0, kp = krp->krp_param; i < krp->krp_iparams; i++, kp++) { KASSERT(kp->crp_nbits != 0, ("%s: parameter[%d]'s length is zero\n", __func__, i)); xlp_rsa_inp2hwformat(kp->crp_p, cmd->rsasrc + i * cmd->rsaopsize, howmany(kp->crp_nbits, 8), 0); } err = nlm_crypto_complete_rsa_request(sc, cmd); if (err != 0) goto errout; return (0); errout: xlp_free_cmd_params(cmd); krp->krp_status = err; crypto_kdone(krp); return (err); } Index: head/sys/mips/nlm/dev/sec/nlmrsalib.h =================================================================== --- head/sys/mips/nlm/dev/sec/nlmrsalib.h (revision 326258) +++ head/sys/mips/nlm/dev/sec/nlmrsalib.h (revision 326259) @@ -1,70 +1,72 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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$ */ #ifndef _NLMRSALIB_H_ #define _NLMRSALIB_H_ #define XLP_RSA_SESSION(sid) ((sid) & 0x000007ff) #define XLP_RSA_SID(crd,ses) (((crd) << 28) | ((ses) & 0x7ff)) #define RSA_ERROR(msg0) (((msg0) >> 53) & 0x1f) struct xlp_rsa_session { uint32_t sessionid; int hs_used; }; struct xlp_rsa_command { uint16_t session_num; struct xlp_rsa_session *ses; struct cryptkop *krp; uint8_t *rsasrc; uint32_t rsaopsize; uint32_t rsatype; uint32_t rsafn; }; /* * Holds data specific to nlm security accelerators */ struct xlp_rsa_softc { device_t sc_dev; /* device backpointer */ uint64_t rsa_base; int sc_cid; struct xlp_rsa_session *sc_sessions; int sc_nsessions; int rsaecc_vc_start; int rsaecc_vc_end; }; void nlm_xlprsaecc_msgring_handler(int vc, int size, int code, int src_id, struct nlm_fmn_msg *msg, void *data); #endif /* _NLMRSALIB_H_ */ Index: head/sys/mips/nlm/dev/sec/nlmsec.c =================================================================== --- head/sys/mips/nlm/dev/sec/nlmsec.c (revision 326258) +++ head/sys/mips/nlm/dev/sec/nlmsec.c (revision 326259) @@ -1,850 +1,852 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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 #include #include #include "cryptodev_if.h" #include #include #include #include #include #include #include #include #include #include #include #include unsigned int creditleft; void xlp_sec_print_data(struct cryptop *crp); static int xlp_sec_init(struct xlp_sec_softc *sc); static int xlp_sec_newsession(device_t , uint32_t *, struct cryptoini *); static int xlp_sec_freesession(device_t , uint64_t); static int xlp_sec_process(device_t , struct cryptop *, int); static int xlp_copyiv(struct xlp_sec_softc *, struct xlp_sec_command *, struct cryptodesc *enccrd); static int xlp_get_nsegs(struct cryptop *, unsigned int *); static int xlp_alloc_cmd_params(struct xlp_sec_command *, unsigned int); static void xlp_free_cmd_params(struct xlp_sec_command *); static int xlp_sec_probe(device_t); static int xlp_sec_attach(device_t); static int xlp_sec_detach(device_t); static device_method_t xlp_sec_methods[] = { /* device interface */ DEVMETHOD(device_probe, xlp_sec_probe), DEVMETHOD(device_attach, xlp_sec_attach), DEVMETHOD(device_detach, xlp_sec_detach), /* bus interface */ DEVMETHOD(bus_print_child, bus_generic_print_child), DEVMETHOD(bus_driver_added, bus_generic_driver_added), /* crypto device methods */ DEVMETHOD(cryptodev_newsession, xlp_sec_newsession), DEVMETHOD(cryptodev_freesession,xlp_sec_freesession), DEVMETHOD(cryptodev_process, xlp_sec_process), DEVMETHOD_END }; static driver_t xlp_sec_driver = { "nlmsec", xlp_sec_methods, sizeof(struct xlp_sec_softc) }; static devclass_t xlp_sec_devclass; DRIVER_MODULE(nlmsec, pci, xlp_sec_driver, xlp_sec_devclass, 0, 0); MODULE_DEPEND(nlmsec, crypto, 1, 1, 1); void nlm_xlpsec_msgring_handler(int vc, int size, int code, int src_id, struct nlm_fmn_msg *msg, void *data); #ifdef NLM_SEC_DEBUG #define extract_bits(x, bitshift, bitcnt) \ (((unsigned long long)x >> bitshift) & ((1ULL << bitcnt) - 1)) void print_crypto_params(struct xlp_sec_command *cmd, struct nlm_fmn_msg m) { unsigned long long msg0,msg1,msg2,msg3,msg4,msg5,msg6,msg7,msg8; msg0 = cmd->ctrlp->desc0; msg1 = cmd->paramp->desc0; msg2 = cmd->paramp->desc1; msg3 = cmd->paramp->desc2; msg4 = cmd->paramp->desc3; msg5 = cmd->paramp->segment[0][0]; msg6 = cmd->paramp->segment[0][1]; msg7 = m.msg[0]; msg8 = m.msg[1]; printf("msg0 %llx msg1 %llx msg2 %llx msg3 %llx msg4 %llx msg5 %llx" "msg6 %llx msg7 %llx msg8 %llx\n", msg0, msg1, msg2, msg3, msg4, msg5, msg6, msg7, msg8); printf("c0: hmac %d htype %d hmode %d ctype %d cmode %d arc4 %x\n", (unsigned int)extract_bits(msg0, 61, 1), (unsigned int)extract_bits(msg0, 52, 8), (unsigned int)extract_bits(msg0, 43, 8), (unsigned int)extract_bits(msg0, 34, 8), (unsigned int)extract_bits(msg0, 25, 8), (unsigned int)extract_bits(msg0, 0, 23)); printf("p0: tls %d hsrc %d hl3 %d enc %d ivl %d hd %llx\n", (unsigned int)extract_bits(msg1, 63, 1), (unsigned int)extract_bits(msg1,62,1), (unsigned int)extract_bits(msg1,60,1), (unsigned int)extract_bits(msg1,59,1), (unsigned int)extract_bits(msg1,41,16), extract_bits(msg1,0,40)); printf("p1: clen %u hl %u\n", (unsigned int)extract_bits(msg2, 32, 32), (unsigned int)extract_bits(msg2,0,32)); printf("p2: ivoff %d cbit %d coff %d hbit %d hclb %d hoff %d\n", (unsigned int)extract_bits(msg3, 45, 17), (unsigned int)extract_bits(msg3, 42,3), (unsigned int)extract_bits(msg3, 22,16), (unsigned int)extract_bits(msg3, 19,3), (unsigned int)extract_bits(msg3, 18,1), (unsigned int)extract_bits(msg3, 0, 16)); printf("p3: desfbid %d tlen %d arc4 %x hmacpad %d\n", (unsigned int)extract_bits(msg4, 48,16), (unsigned int)extract_bits(msg4,11,16), (unsigned int)extract_bits(msg4,6,3), (unsigned int)extract_bits(msg4,5,1)); printf("p4: sflen %d sddr %llx \n", (unsigned int)extract_bits(msg5, 48, 16),extract_bits(msg5, 0, 40)); printf("p5: dflen %d cl3 %d cclob %d cdest %llx \n", (unsigned int)extract_bits(msg6, 48, 16), (unsigned int)extract_bits(msg6, 46, 1), (unsigned int)extract_bits(msg6, 41, 1), extract_bits(msg6, 0, 40)); printf("fmn0: fbid %d dfrlen %d dfrv %d cklen %d cdescaddr %llx\n", (unsigned int)extract_bits(msg7, 48, 16), (unsigned int)extract_bits(msg7,46,2), (unsigned int)extract_bits(msg7,45,1), (unsigned int)extract_bits(msg7,40,5), (extract_bits(msg7,0,34)<< 6)); printf("fmn1: arc4 %d hklen %d pdesclen %d pktdescad %llx\n", (unsigned int)extract_bits(msg8, 63, 1), (unsigned int)extract_bits(msg8,56,5), (unsigned int)extract_bits(msg8,43,12), (extract_bits(msg8,0,34) << 6)); return; } void xlp_sec_print_data(struct cryptop *crp) { int i, key_len; struct cryptodesc *crp_desc; printf("session id = 0x%llx, crp_ilen = %d, crp_olen=%d \n", crp->crp_sid, crp->crp_ilen, crp->crp_olen); printf("crp_flags = 0x%x\n", crp->crp_flags); printf("crp buf:\n"); for (i = 0; i < crp->crp_ilen; i++) { printf("%c ", crp->crp_buf[i]); if (i % 10 == 0) printf("\n"); } printf("\n"); printf("****************** desc ****************\n"); crp_desc = crp->crp_desc; printf("crd_skip=%d, crd_len=%d, crd_flags=0x%x, crd_alg=%d\n", crp_desc->crd_skip, crp_desc->crd_len, crp_desc->crd_flags, crp_desc->crd_alg); key_len = crp_desc->crd_klen / 8; printf("key(%d) :\n", key_len); for (i = 0; i < key_len; i++) printf("%d", crp_desc->crd_key[i]); printf("\n"); printf(" IV : \n"); for (i = 0; i < EALG_MAX_BLOCK_LEN; i++) printf("%d", crp_desc->crd_iv[i]); printf("\n"); printf("crd_next=%p\n", crp_desc->crd_next); return; } void print_cmd(struct xlp_sec_command *cmd) { printf("session_num :%d\n",cmd->session_num); printf("crp :0x%x\n",(uint32_t)cmd->crp); printf("enccrd :0x%x\n",(uint32_t)cmd->enccrd); printf("maccrd :0x%x\n",(uint32_t)cmd->maccrd); printf("ses :%d\n",(uint32_t)cmd->ses); printf("ctrlp :0x%x\n",(uint32_t)cmd->ctrlp); printf("paramp :0x%x\n",(uint32_t)cmd->paramp); printf("hashdest :0x%x\n",(uint32_t)cmd->hashdest); printf("hashsrc :%d\n",cmd->hashsrc); printf("hmacpad :%d\n",cmd->hmacpad); printf("hashoff :%d\n",cmd->hashoff); printf("hashlen :%d\n",cmd->hashlen); printf("cipheroff :%d\n",cmd->cipheroff); printf("cipherlen :%d\n",cmd->cipherlen); printf("ivoff :%d\n",cmd->ivoff); printf("ivlen :%d\n",cmd->ivlen); printf("hashalg :%d\n",cmd->hashalg); printf("hashmode :%d\n",cmd->hashmode); printf("cipheralg :%d\n",cmd->cipheralg); printf("ciphermode :%d\n",cmd->ciphermode); printf("nsegs :%d\n",cmd->nsegs); printf("hash_dst_len :%d\n",cmd->hash_dst_len); } #endif /* NLM_SEC_DEBUG */ static int xlp_sec_init(struct xlp_sec_softc *sc) { /* Register interrupt handler for the SEC CMS messages */ if (register_msgring_handler(sc->sec_vc_start, sc->sec_vc_end, nlm_xlpsec_msgring_handler, sc) != 0) { printf("Couldn't register sec msgring handler\n"); return (-1); } /* Do the CMS credit initialization */ /* Currently it is configured by default to 50 when kernel comes up */ return (0); } /* This function is called from an interrupt handler */ void nlm_xlpsec_msgring_handler(int vc, int size, int code, int src_id, struct nlm_fmn_msg *msg, void *data) { struct xlp_sec_command *cmd = NULL; struct xlp_sec_softc *sc = NULL; struct cryptodesc *crd = NULL; unsigned int ivlen = 0; KASSERT(code == FMN_SWCODE_CRYPTO, ("%s: bad code = %d, expected code = %d\n", __FUNCTION__, code, FMN_SWCODE_CRYPTO)); sc = (struct xlp_sec_softc *)data; KASSERT(src_id >= sc->sec_vc_start && src_id <= sc->sec_vc_end, ("%s: bad src_id = %d, expect %d - %d\n", __FUNCTION__, src_id, sc->sec_vc_start, sc->sec_vc_end)); cmd = (struct xlp_sec_command *)(uintptr_t)msg->msg[0]; KASSERT(cmd != NULL && cmd->crp != NULL, ("%s :cmd not received properly\n",__FUNCTION__)); KASSERT(CRYPTO_ERROR(msg->msg[1]) == 0, ("%s: Message rcv msg0 %llx msg1 %llx err %x \n", __FUNCTION__, (unsigned long long)msg->msg[0], (unsigned long long)msg->msg[1], (int)CRYPTO_ERROR(msg->msg[1]))); crd = cmd->enccrd; /* Copy the last 8 or 16 bytes to the session iv, so that in few * cases this will be used as IV for the next request */ if (crd != NULL) { if ((crd->crd_alg == CRYPTO_DES_CBC || crd->crd_alg == CRYPTO_3DES_CBC || crd->crd_alg == CRYPTO_AES_CBC) && (crd->crd_flags & CRD_F_ENCRYPT)) { ivlen = ((crd->crd_alg == CRYPTO_AES_CBC) ? XLP_SEC_AES_IV_LENGTH : XLP_SEC_DES_IV_LENGTH); crypto_copydata(cmd->crp->crp_flags, cmd->crp->crp_buf, crd->crd_skip + crd->crd_len - ivlen, ivlen, sc->sc_sessions[cmd->session_num].ses_iv); } } /* If there are not enough credits to send, then send request * will fail with ERESTART and the driver will be blocked until it is * unblocked here after knowing that there are sufficient credits to * send the request again. */ if (sc->sc_needwakeup) { atomic_add_int(&creditleft, sc->sec_msgsz); if (creditleft >= (NLM_CRYPTO_LEFT_REQS)) { crypto_unblock(sc->sc_cid, sc->sc_needwakeup); sc->sc_needwakeup &= (~(CRYPTO_SYMQ | CRYPTO_ASYMQ)); } } if(cmd->maccrd) { crypto_copyback(cmd->crp->crp_flags, cmd->crp->crp_buf, cmd->maccrd->crd_inject, cmd->hash_dst_len, cmd->hashdest); } /* This indicates completion of the crypto operation */ crypto_done(cmd->crp); xlp_free_cmd_params(cmd); return; } static int xlp_sec_probe(device_t dev) { struct xlp_sec_softc *sc; if (pci_get_vendor(dev) == PCI_VENDOR_NETLOGIC && pci_get_device(dev) == PCI_DEVICE_ID_NLM_SAE) { sc = device_get_softc(dev); return (BUS_PROBE_DEFAULT); } return (ENXIO); } /* * Attach an interface that successfully probed. */ static int xlp_sec_attach(device_t dev) { struct xlp_sec_softc *sc = device_get_softc(dev); uint64_t base; int qstart, qnum; int freq, node; sc->sc_dev = dev; node = nlm_get_device_node(pci_get_slot(dev)); freq = nlm_set_device_frequency(node, DFS_DEVICE_SAE, 250); if (bootverbose) device_printf(dev, "SAE Freq: %dMHz\n", freq); if(pci_get_device(dev) == PCI_DEVICE_ID_NLM_SAE) { device_set_desc(dev, "XLP Security Accelerator"); sc->sc_cid = crypto_get_driverid(dev, CRYPTOCAP_F_HARDWARE); if (sc->sc_cid < 0) { printf("xlp_sec - error : could not get the driver" " id\n"); goto error_exit; } if (crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0) != 0) printf("register failed for CRYPTO_DES_CBC\n"); if (crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0) != 0) printf("register failed for CRYPTO_3DES_CBC\n"); if (crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0) != 0) printf("register failed for CRYPTO_AES_CBC\n"); if (crypto_register(sc->sc_cid, CRYPTO_ARC4, 0, 0) != 0) printf("register failed for CRYPTO_ARC4\n"); if (crypto_register(sc->sc_cid, CRYPTO_MD5, 0, 0) != 0) printf("register failed for CRYPTO_MD5\n"); if (crypto_register(sc->sc_cid, CRYPTO_SHA1, 0, 0) != 0) printf("register failed for CRYPTO_SHA1\n"); if (crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0) != 0) printf("register failed for CRYPTO_MD5_HMAC\n"); if (crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0) != 0) printf("register failed for CRYPTO_SHA1_HMAC\n"); base = nlm_get_sec_pcibase(node); qstart = nlm_qidstart(base); qnum = nlm_qnum(base); sc->sec_vc_start = qstart; sc->sec_vc_end = qstart + qnum - 1; } if (xlp_sec_init(sc) != 0) goto error_exit; if (bootverbose) device_printf(dev, "SEC Initialization complete!\n"); return (0); error_exit: return (ENXIO); } /* * Detach an interface that successfully probed. */ static int xlp_sec_detach(device_t dev) { return (0); } /* * Allocate a new 'session' and return an encoded session id. 'sidp' * contains our registration id, and should contain an encoded session * id on successful allocation. */ static int xlp_sec_newsession(device_t dev, u_int32_t *sidp, struct cryptoini *cri) { struct cryptoini *c; struct xlp_sec_softc *sc = device_get_softc(dev); int mac = 0, cry = 0, sesn; struct xlp_sec_session *ses = NULL; struct xlp_sec_command *cmd = NULL; if (sidp == NULL || cri == NULL || sc == NULL) return (EINVAL); if (sc->sc_sessions == NULL) { ses = sc->sc_sessions = malloc(sizeof(struct xlp_sec_session), M_DEVBUF, M_NOWAIT); if (ses == NULL) return (ENOMEM); sesn = 0; sc->sc_nsessions = 1; } else { for (sesn = 0; sesn < sc->sc_nsessions; sesn++) { if (!sc->sc_sessions[sesn].hs_used) { ses = &sc->sc_sessions[sesn]; break; } } if (ses == NULL) { sesn = sc->sc_nsessions; ses = malloc((sesn + 1)*sizeof(struct xlp_sec_session), M_DEVBUF, M_NOWAIT); if (ses == NULL) return (ENOMEM); bcopy(sc->sc_sessions, ses, sesn * sizeof(*ses)); bzero(sc->sc_sessions, sesn * sizeof(*ses)); free(sc->sc_sessions, M_DEVBUF); sc->sc_sessions = ses; ses = &sc->sc_sessions[sesn]; sc->sc_nsessions++; } } bzero(ses, sizeof(*ses)); ses->sessionid = sesn; cmd = &ses->cmd; ses->hs_used = 1; for (c = cri; c != NULL; c = c->cri_next) { switch (c->cri_alg) { case CRYPTO_MD5: case CRYPTO_SHA1: case CRYPTO_MD5_HMAC: case CRYPTO_SHA1_HMAC: if (mac) return (EINVAL); mac = 1; ses->hs_mlen = c->cri_mlen; if (ses->hs_mlen == 0) { switch (c->cri_alg) { case CRYPTO_MD5: case CRYPTO_MD5_HMAC: ses->hs_mlen = 16; break; case CRYPTO_SHA1: case CRYPTO_SHA1_HMAC: ses->hs_mlen = 20; break; } } break; case CRYPTO_DES_CBC: case CRYPTO_3DES_CBC: case CRYPTO_AES_CBC: /* XXX this may read fewer, does it matter? */ read_random(ses->ses_iv, c->cri_alg == CRYPTO_AES_CBC ? XLP_SEC_AES_IV_LENGTH : XLP_SEC_DES_IV_LENGTH); /* FALLTHROUGH */ case CRYPTO_ARC4: if (cry) return (EINVAL); cry = 1; break; default: return (EINVAL); } } if (mac == 0 && cry == 0) return (EINVAL); cmd->hash_dst_len = ses->hs_mlen; *sidp = XLP_SEC_SID(device_get_unit(sc->sc_dev), sesn); return (0); } /* * Deallocate a session. * XXX this routine should run a zero'd mac/encrypt key into context ram. * XXX to blow away any keys already stored there. */ static int xlp_sec_freesession(device_t dev, u_int64_t tid) { struct xlp_sec_softc *sc = device_get_softc(dev); int session; u_int32_t sid = CRYPTO_SESID2LID(tid); if (sc == NULL) return (EINVAL); session = XLP_SEC_SESSION(sid); if (session >= sc->sc_nsessions) return (EINVAL); sc->sc_sessions[session].hs_used = 0; return (0); } static int xlp_copyiv(struct xlp_sec_softc *sc, struct xlp_sec_command *cmd, struct cryptodesc *enccrd) { unsigned int ivlen = 0; int session; struct cryptop *crp = NULL; crp = cmd->crp; session = cmd->session_num; if (enccrd->crd_alg != CRYPTO_ARC4) { ivlen = ((enccrd->crd_alg == CRYPTO_AES_CBC) ? XLP_SEC_AES_IV_LENGTH : XLP_SEC_DES_IV_LENGTH); if (enccrd->crd_flags & CRD_F_ENCRYPT) { if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) { bcopy(enccrd->crd_iv, cmd->iv, ivlen); } else { bcopy(sc->sc_sessions[session].ses_iv, cmd->iv, ivlen); } if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) { crypto_copyback(crp->crp_flags, crp->crp_buf, enccrd->crd_inject, ivlen, cmd->iv); } } else { if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) { bcopy(enccrd->crd_iv, cmd->iv, ivlen); } else { crypto_copydata(crp->crp_flags, crp->crp_buf, enccrd->crd_inject, ivlen, cmd->iv); } } } return (0); } static int xlp_get_nsegs(struct cryptop *crp, unsigned int *nsegs) { if (crp->crp_flags & CRYPTO_F_IMBUF) { struct mbuf *m = NULL; m = (struct mbuf *)crp->crp_buf; while (m != NULL) { *nsegs += NLM_CRYPTO_NUM_SEGS_REQD(m->m_len); m = m->m_next; } } else if (crp->crp_flags & CRYPTO_F_IOV) { struct uio *uio = NULL; struct iovec *iov = NULL; int iol = 0; uio = (struct uio *)crp->crp_buf; iov = (struct iovec *)uio->uio_iov; iol = uio->uio_iovcnt; while (iol > 0) { *nsegs += NLM_CRYPTO_NUM_SEGS_REQD(iov->iov_len); iol--; iov++; } } else { *nsegs = NLM_CRYPTO_NUM_SEGS_REQD(crp->crp_ilen); } return (0); } static int xlp_alloc_cmd_params(struct xlp_sec_command *cmd, unsigned int nsegs) { int err = 0; if(cmd == NULL) { err = EINVAL; goto error; } if ((cmd->ctrlp = malloc(sizeof(struct nlm_crypto_pkt_ctrl), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) { err = ENOMEM; goto error; } if (((uintptr_t)cmd->ctrlp & (XLP_L2L3_CACHELINE_SIZE - 1))) { err = EINVAL; goto error; } /* (nsegs - 1) because one seg is part of the structure already */ if ((cmd->paramp = malloc(sizeof(struct nlm_crypto_pkt_param) + (16 * (nsegs - 1)), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) { err = ENOMEM; goto error; } if (((uintptr_t)cmd->paramp & (XLP_L2L3_CACHELINE_SIZE - 1))) { err = EINVAL; goto error; } if ((cmd->iv = malloc(EALG_MAX_BLOCK_LEN, M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) { err = ENOMEM; goto error; } if ((cmd->hashdest = malloc(HASH_MAX_LEN, M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) { err = ENOMEM; goto error; } error: return (err); } static void xlp_free_cmd_params(struct xlp_sec_command *cmd) { if (cmd->ctrlp != NULL) free(cmd->ctrlp, M_DEVBUF); if (cmd->paramp != NULL) free(cmd->paramp, M_DEVBUF); if (cmd->iv != NULL) free(cmd->iv, M_DEVBUF); if (cmd->hashdest != NULL) free(cmd->hashdest, M_DEVBUF); if (cmd != NULL) free(cmd, M_DEVBUF); return; } static int xlp_sec_process(device_t dev, struct cryptop *crp, int hint) { struct xlp_sec_softc *sc = device_get_softc(dev); struct xlp_sec_command *cmd = NULL; int session, err = -1, ret = 0; struct cryptodesc *crd1, *crd2; struct xlp_sec_session *ses; unsigned int nsegs = 0; if (crp == NULL || crp->crp_callback == NULL) { return (EINVAL); } session = XLP_SEC_SESSION(crp->crp_sid); if (sc == NULL || session >= sc->sc_nsessions) { err = EINVAL; goto errout; } ses = &sc->sc_sessions[session]; if ((cmd = malloc(sizeof(struct xlp_sec_command), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) { err = ENOMEM; goto errout; } cmd->crp = crp; cmd->session_num = session; cmd->hash_dst_len = ses->hs_mlen; if ((crd1 = crp->crp_desc) == NULL) { err = EINVAL; goto errout; } crd2 = crd1->crd_next; if ((ret = xlp_get_nsegs(crp, &nsegs)) != 0) { err = EINVAL; goto errout; } if (((crd1 != NULL) && (crd1->crd_flags & CRD_F_IV_EXPLICIT)) || ((crd2 != NULL) && (crd2->crd_flags & CRD_F_IV_EXPLICIT))) { /* Since IV is given as separate segment to avoid copy */ nsegs += 1; } cmd->nsegs = nsegs; if ((err = xlp_alloc_cmd_params(cmd, nsegs)) != 0) goto errout; if ((crd1 != NULL) && (crd2 == NULL)) { if (crd1->crd_alg == CRYPTO_DES_CBC || crd1->crd_alg == CRYPTO_3DES_CBC || crd1->crd_alg == CRYPTO_AES_CBC || crd1->crd_alg == CRYPTO_ARC4) { cmd->enccrd = crd1; cmd->maccrd = NULL; if ((ret = nlm_get_cipher_param(cmd)) != 0) { err = EINVAL; goto errout; } if (crd1->crd_flags & CRD_F_IV_EXPLICIT) cmd->cipheroff = cmd->ivlen; else cmd->cipheroff = cmd->enccrd->crd_skip; cmd->cipherlen = cmd->enccrd->crd_len; if (crd1->crd_flags & CRD_F_IV_PRESENT) cmd->ivoff = 0; else cmd->ivoff = cmd->enccrd->crd_inject; if ((err = xlp_copyiv(sc, cmd, cmd->enccrd)) != 0) goto errout; if ((err = nlm_crypto_do_cipher(sc, cmd)) != 0) goto errout; } else if (crd1->crd_alg == CRYPTO_MD5_HMAC || crd1->crd_alg == CRYPTO_SHA1_HMAC || crd1->crd_alg == CRYPTO_SHA1 || crd1->crd_alg == CRYPTO_MD5) { cmd->enccrd = NULL; cmd->maccrd = crd1; if ((ret = nlm_get_digest_param(cmd)) != 0) { err = EINVAL; goto errout; } cmd->hashoff = cmd->maccrd->crd_skip; cmd->hashlen = cmd->maccrd->crd_len; cmd->hmacpad = 0; cmd->hashsrc = 0; if ((err = nlm_crypto_do_digest(sc, cmd)) != 0) goto errout; } else { err = EINVAL; goto errout; } } else if( (crd1 != NULL) && (crd2 != NULL) ) { if ((crd1->crd_alg == CRYPTO_MD5_HMAC || crd1->crd_alg == CRYPTO_SHA1_HMAC || crd1->crd_alg == CRYPTO_MD5 || crd1->crd_alg == CRYPTO_SHA1) && (crd2->crd_alg == CRYPTO_DES_CBC || crd2->crd_alg == CRYPTO_3DES_CBC || crd2->crd_alg == CRYPTO_AES_CBC || crd2->crd_alg == CRYPTO_ARC4)) { cmd->maccrd = crd1; cmd->enccrd = crd2; } else if ((crd1->crd_alg == CRYPTO_DES_CBC || crd1->crd_alg == CRYPTO_ARC4 || crd1->crd_alg == CRYPTO_3DES_CBC || crd1->crd_alg == CRYPTO_AES_CBC) && (crd2->crd_alg == CRYPTO_MD5_HMAC || crd2->crd_alg == CRYPTO_SHA1_HMAC || crd2->crd_alg == CRYPTO_MD5 || crd2->crd_alg == CRYPTO_SHA1)) { cmd->enccrd = crd1; cmd->maccrd = crd2; } else { err = EINVAL; goto errout; } if ((ret = nlm_get_cipher_param(cmd)) != 0) { err = EINVAL; goto errout; } if ((ret = nlm_get_digest_param(cmd)) != 0) { err = EINVAL; goto errout; } cmd->ivoff = cmd->enccrd->crd_inject; cmd->hashoff = cmd->maccrd->crd_skip; cmd->hashlen = cmd->maccrd->crd_len; cmd->hmacpad = 0; if (cmd->enccrd->crd_flags & CRD_F_ENCRYPT) cmd->hashsrc = 1; else cmd->hashsrc = 0; cmd->cipheroff = cmd->enccrd->crd_skip; cmd->cipherlen = cmd->enccrd->crd_len; if ((err = xlp_copyiv(sc, cmd, cmd->enccrd)) != 0) goto errout; if ((err = nlm_crypto_do_cipher_digest(sc, cmd)) != 0) goto errout; } else { err = EINVAL; goto errout; } return (0); errout: xlp_free_cmd_params(cmd); if (err == ERESTART) { sc->sc_needwakeup |= CRYPTO_SYMQ; creditleft = 0; return (err); } crp->crp_etype = err; crypto_done(crp); return (err); } Index: head/sys/mips/nlm/dev/sec/nlmseclib.c =================================================================== --- head/sys/mips/nlm/dev/sec/nlmseclib.c (revision 326258) +++ head/sys/mips/nlm/dev/sec/nlmseclib.c (revision 326259) @@ -1,307 +1,309 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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 #include #include #include #include #include #include static int nlm_crypto_complete_sec_request(struct xlp_sec_softc *sc, struct xlp_sec_command *cmd) { unsigned int fbvc; struct nlm_fmn_msg m; int ret; fbvc = nlm_cpuid() / CMS_MAX_VCPU_VC; m.msg[0] = m.msg[1] = m.msg[2] = m.msg[3] = 0; m.msg[0] = nlm_crypto_form_pkt_fmn_entry0(fbvc, 0, 0, cmd->ctrlp->cipherkeylen, vtophys(cmd->ctrlp)); m.msg[1] = nlm_crypto_form_pkt_fmn_entry1(0, cmd->ctrlp->hashkeylen, NLM_CRYPTO_PKT_DESC_SIZE(cmd->nsegs), vtophys(cmd->paramp)); /* Software scratch pad */ m.msg[2] = (uintptr_t)cmd; sc->sec_msgsz = 3; /* Send the message to sec/rsa engine vc */ ret = nlm_fmn_msgsend(sc->sec_vc_start, sc->sec_msgsz, FMN_SWCODE_CRYPTO, &m); if (ret != 0) { #ifdef NLM_SEC_DEBUG printf("%s: msgsnd failed (%x)\n", __func__, ret); #endif return (ERESTART); } return (0); } int nlm_crypto_form_srcdst_segs(struct xlp_sec_command *cmd) { unsigned int srcseg = 0, dstseg = 0; struct cryptodesc *cipdesc = NULL; struct cryptop *crp = NULL; crp = cmd->crp; cipdesc = cmd->enccrd; if (cipdesc != NULL) { /* IV is given as ONE segment to avoid copy */ if (cipdesc->crd_flags & CRD_F_IV_EXPLICIT) { srcseg = nlm_crypto_fill_src_seg(cmd->paramp, srcseg, cmd->iv, cmd->ivlen); dstseg = nlm_crypto_fill_dst_seg(cmd->paramp, dstseg, cmd->iv, cmd->ivlen); } } if (crp->crp_flags & CRYPTO_F_IMBUF) { struct mbuf *m = NULL; m = (struct mbuf *)crp->crp_buf; while (m != NULL) { srcseg = nlm_crypto_fill_src_seg(cmd->paramp, srcseg, mtod(m,caddr_t), m->m_len); if (cipdesc != NULL) { dstseg = nlm_crypto_fill_dst_seg(cmd->paramp, dstseg, mtod(m,caddr_t), m->m_len); } m = m->m_next; } } else if (crp->crp_flags & CRYPTO_F_IOV) { struct uio *uio = NULL; struct iovec *iov = NULL; int iol = 0; uio = (struct uio *)crp->crp_buf; iov = (struct iovec *)uio->uio_iov; iol = uio->uio_iovcnt; while (iol > 0) { srcseg = nlm_crypto_fill_src_seg(cmd->paramp, srcseg, (caddr_t)iov->iov_base, iov->iov_len); if (cipdesc != NULL) { dstseg = nlm_crypto_fill_dst_seg(cmd->paramp, dstseg, (caddr_t)iov->iov_base, iov->iov_len); } iov++; iol--; } } else { srcseg = nlm_crypto_fill_src_seg(cmd->paramp, srcseg, ((caddr_t)crp->crp_buf), crp->crp_ilen); if (cipdesc != NULL) { dstseg = nlm_crypto_fill_dst_seg(cmd->paramp, dstseg, ((caddr_t)crp->crp_buf), crp->crp_ilen); } } return (0); } int nlm_crypto_do_cipher(struct xlp_sec_softc *sc, struct xlp_sec_command *cmd) { struct cryptodesc *cipdesc = NULL; unsigned char *cipkey = NULL; int ret = 0; cipdesc = cmd->enccrd; cipkey = (unsigned char *)cipdesc->crd_key; if (cmd->cipheralg == NLM_CIPHER_3DES) { if (!(cipdesc->crd_flags & CRD_F_ENCRYPT)) { uint64_t *k, *tkey; k = (uint64_t *)cipdesc->crd_key; tkey = (uint64_t *)cmd->des3key; tkey[2] = k[0]; tkey[1] = k[1]; tkey[0] = k[2]; cipkey = (unsigned char *)tkey; } } nlm_crypto_fill_pkt_ctrl(cmd->ctrlp, 0, NLM_HASH_BYPASS, 0, cmd->cipheralg, cmd->ciphermode, cipkey, (cipdesc->crd_klen >> 3), NULL, 0); nlm_crypto_fill_cipher_pkt_param(cmd->ctrlp, cmd->paramp, (cipdesc->crd_flags & CRD_F_ENCRYPT) ? 1 : 0, cmd->ivoff, cmd->ivlen, cmd->cipheroff, cmd->cipherlen); nlm_crypto_form_srcdst_segs(cmd); ret = nlm_crypto_complete_sec_request(sc, cmd); return (ret); } int nlm_crypto_do_digest(struct xlp_sec_softc *sc, struct xlp_sec_command *cmd) { struct cryptodesc *digdesc = NULL; int ret=0; digdesc = cmd->maccrd; nlm_crypto_fill_pkt_ctrl(cmd->ctrlp, (digdesc->crd_klen) ? 1 : 0, cmd->hashalg, cmd->hashmode, NLM_CIPHER_BYPASS, 0, NULL, 0, digdesc->crd_key, digdesc->crd_klen >> 3); nlm_crypto_fill_auth_pkt_param(cmd->ctrlp, cmd->paramp, cmd->hashoff, cmd->hashlen, cmd->hmacpad, (unsigned char *)cmd->hashdest); nlm_crypto_form_srcdst_segs(cmd); ret = nlm_crypto_complete_sec_request(sc, cmd); return (ret); } int nlm_crypto_do_cipher_digest(struct xlp_sec_softc *sc, struct xlp_sec_command *cmd) { struct cryptodesc *cipdesc=NULL, *digdesc=NULL; unsigned char *cipkey = NULL; int ret=0; cipdesc = cmd->enccrd; digdesc = cmd->maccrd; cipkey = (unsigned char *)cipdesc->crd_key; if (cmd->cipheralg == NLM_CIPHER_3DES) { if (!(cipdesc->crd_flags & CRD_F_ENCRYPT)) { uint64_t *k, *tkey; k = (uint64_t *)cipdesc->crd_key; tkey = (uint64_t *)cmd->des3key; tkey[2] = k[0]; tkey[1] = k[1]; tkey[0] = k[2]; cipkey = (unsigned char *)tkey; } } nlm_crypto_fill_pkt_ctrl(cmd->ctrlp, (digdesc->crd_klen) ? 1 : 0, cmd->hashalg, cmd->hashmode, cmd->cipheralg, cmd->ciphermode, cipkey, (cipdesc->crd_klen >> 3), digdesc->crd_key, (digdesc->crd_klen >> 3)); nlm_crypto_fill_cipher_auth_pkt_param(cmd->ctrlp, cmd->paramp, (cipdesc->crd_flags & CRD_F_ENCRYPT) ? 1 : 0, cmd->hashsrc, cmd->ivoff, cmd->ivlen, cmd->hashoff, cmd->hashlen, cmd->hmacpad, cmd->cipheroff, cmd->cipherlen, (unsigned char *)cmd->hashdest); nlm_crypto_form_srcdst_segs(cmd); ret = nlm_crypto_complete_sec_request(sc, cmd); return (ret); } int nlm_get_digest_param(struct xlp_sec_command *cmd) { switch(cmd->maccrd->crd_alg) { case CRYPTO_MD5: cmd->hashalg = NLM_HASH_MD5; cmd->hashmode = NLM_HASH_MODE_SHA1; break; case CRYPTO_SHA1: cmd->hashalg = NLM_HASH_SHA; cmd->hashmode = NLM_HASH_MODE_SHA1; break; case CRYPTO_MD5_HMAC: cmd->hashalg = NLM_HASH_MD5; cmd->hashmode = NLM_HASH_MODE_SHA1; break; case CRYPTO_SHA1_HMAC: cmd->hashalg = NLM_HASH_SHA; cmd->hashmode = NLM_HASH_MODE_SHA1; break; default: /* Not supported */ return (-1); } return (0); } int nlm_get_cipher_param(struct xlp_sec_command *cmd) { switch(cmd->enccrd->crd_alg) { case CRYPTO_DES_CBC: cmd->cipheralg = NLM_CIPHER_DES; cmd->ciphermode = NLM_CIPHER_MODE_CBC; cmd->ivlen = XLP_SEC_DES_IV_LENGTH; break; case CRYPTO_3DES_CBC: cmd->cipheralg = NLM_CIPHER_3DES; cmd->ciphermode = NLM_CIPHER_MODE_CBC; cmd->ivlen = XLP_SEC_DES_IV_LENGTH; break; case CRYPTO_AES_CBC: cmd->cipheralg = NLM_CIPHER_AES128; cmd->ciphermode = NLM_CIPHER_MODE_CBC; cmd->ivlen = XLP_SEC_AES_IV_LENGTH; break; case CRYPTO_ARC4: cmd->cipheralg = NLM_CIPHER_ARC4; cmd->ciphermode = NLM_CIPHER_MODE_ECB; cmd->ivlen = XLP_SEC_ARC4_IV_LENGTH; break; default: /* Not supported */ return (-1); } return (0); } Index: head/sys/mips/nlm/dev/sec/nlmseclib.h =================================================================== --- head/sys/mips/nlm/dev/sec/nlmseclib.h (revision 326258) +++ head/sys/mips/nlm/dev/sec/nlmseclib.h (revision 326259) @@ -1,157 +1,159 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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$ */ #ifndef _NLMSECLIB_H_ #define _NLMSECLIB_H_ /* * Cryptographic parameter definitions */ #define XLP_SEC_DES_KEY_LENGTH 8 /* Bytes */ #define XLP_SEC_3DES_KEY_LENGTH 24 /* Bytes */ #define XLP_SEC_AES128_KEY_LENGTH 16 /* Bytes */ #define XLP_SEC_AES192_KEY_LENGTH 24 /* Bytes */ #define XLP_SEC_AES256_KEY_LENGTH 32 /* Bytes */ #define XLP_SEC_AES128F8_KEY_LENGTH 32 /* Bytes */ #define XLP_SEC_AES192F8_KEY_LENGTH 48 /* Bytes */ #define XLP_SEC_AES256F8_KEY_LENGTH 64 /* Bytes */ #define XLP_SEC_KASUMI_F8_KEY_LENGTH 16 /* Bytes */ #define XLP_SEC_MAX_CRYPT_KEY_LENGTH XLP_SEC_AES256F8_KEY_LENGTH #define XLP_SEC_DES_IV_LENGTH 8 /* Bytes */ #define XLP_SEC_AES_IV_LENGTH 16 /* Bytes */ #define XLP_SEC_ARC4_IV_LENGTH 0 /* Bytes */ #define XLP_SEC_KASUMI_F8_IV_LENGTH 16 /* Bytes */ #define XLP_SEC_MAX_IV_LENGTH 16 /* Bytes */ #define XLP_SEC_IV_LENGTH_BYTES 8 /* Bytes */ #define XLP_SEC_AES_BLOCK_SIZE 16 /* Bytes */ #define XLP_SEC_DES_BLOCK_SIZE 8 /* Bytes */ #define XLP_SEC_3DES_BLOCK_SIZE 8 /* Bytes */ #define XLP_SEC_MD5_BLOCK_SIZE 64 /* Bytes */ #define XLP_SEC_SHA1_BLOCK_SIZE 64 /* Bytes */ #define XLP_SEC_SHA256_BLOCK_SIZE 64 /* Bytes */ #define XLP_SEC_SHA384_BLOCK_SIZE 128 /* Bytes */ #define XLP_SEC_SHA512_BLOCK_SIZE 128 /* Bytes */ #define XLP_SEC_GCM_BLOCK_SIZE 16 /* XXX: Bytes */ #define XLP_SEC_KASUMI_F9_BLOCK_SIZE 16 /* XXX: Bytes */ #define XLP_SEC_MAX_BLOCK_SIZE 64 /* Max of MD5/SHA */ #define XLP_SEC_MD5_LENGTH 16 /* Bytes */ #define XLP_SEC_SHA1_LENGTH 20 /* Bytes */ #define XLP_SEC_SHA256_LENGTH 32 /* Bytes */ #define XLP_SEC_SHA384_LENGTH 64 /* Bytes */ #define XLP_SEC_SHA512_LENGTH 64 /* Bytes */ #define XLP_SEC_GCM_LENGTH 16 /* Bytes */ #define XLP_SEC_KASUMI_F9_LENGTH 16 /* Bytes */ #define XLP_SEC_KASUMI_F9_RESULT_LENGTH 4 /* Bytes */ #define XLP_SEC_HMAC_LENGTH 64 /* Max of MD5/SHA/SHA256 */ #define XLP_SEC_MAX_AUTH_KEY_LENGTH XLP_SEC_SHA512_BLOCK_SIZE #define XLP_SEC_MAX_RC4_STATE_SIZE 264 /* char s[256], int i, int j */ #define XLP_SEC_SESSION(sid) ((sid) & 0x000007ff) #define XLP_SEC_SID(crd,ses) (((crd) << 28) | ((ses) & 0x7ff)) #define CRYPTO_ERROR(msg1) ((unsigned int)msg1) #define NLM_CRYPTO_LEFT_REQS (CMS_DEFAULT_CREDIT/2) #define NLM_CRYPTO_NUM_SEGS_REQD(__bufsize) \ ((__bufsize + NLM_CRYPTO_MAX_SEG_LEN - 1) / NLM_CRYPTO_MAX_SEG_LEN) #define NLM_CRYPTO_PKT_DESC_SIZE(nsegs) (32 + (nsegs * 16)) extern unsigned int creditleft; struct xlp_sec_command { uint16_t session_num; struct cryptop *crp; struct cryptodesc *enccrd, *maccrd; struct xlp_sec_session *ses; struct nlm_crypto_pkt_ctrl *ctrlp; struct nlm_crypto_pkt_param *paramp; void *iv; uint8_t des3key[24]; uint8_t *hashdest; uint8_t hashsrc; uint8_t hmacpad; uint32_t hashoff; uint32_t hashlen; uint32_t cipheroff; uint32_t cipherlen; uint32_t ivoff; uint32_t ivlen; uint32_t hashalg; uint32_t hashmode; uint32_t cipheralg; uint32_t ciphermode; uint32_t nsegs; uint32_t hash_dst_len; /* used to store hash alg dst size */ }; struct xlp_sec_session { uint32_t sessionid; int hs_used; int hs_mlen; uint8_t ses_iv[EALG_MAX_BLOCK_LEN]; struct xlp_sec_command cmd; }; /* * Holds data specific to nlm security accelerators */ struct xlp_sec_softc { device_t sc_dev; /* device backpointer */ uint64_t sec_base; int32_t sc_cid; struct xlp_sec_session *sc_sessions; int sc_nsessions; int sc_needwakeup; uint32_t sec_vc_start; uint32_t sec_vc_end; uint32_t sec_msgsz; }; #ifdef NLM_SEC_DEBUG void print_crypto_params(struct xlp_sec_command *cmd, struct nlm_fmn_msg m); void xlp_sec_print_data(struct cryptop *crp); void print_cmd(struct xlp_sec_command *cmd); #endif int nlm_crypto_form_srcdst_segs(struct xlp_sec_command *cmd); int nlm_crypto_do_cipher(struct xlp_sec_softc *sc, struct xlp_sec_command *cmd); int nlm_crypto_do_digest(struct xlp_sec_softc *sc, struct xlp_sec_command *cmd); int nlm_crypto_do_cipher_digest(struct xlp_sec_softc *sc, struct xlp_sec_command *cmd); int nlm_get_digest_param(struct xlp_sec_command *cmd); int nlm_get_cipher_param(struct xlp_sec_command *cmd); #endif /* _NLMSECLIB_H_ */ Index: head/sys/mips/nlm/dev/sec/rsa_ucode.h =================================================================== --- head/sys/mips/nlm/dev/sec/rsa_ucode.h (revision 326258) +++ head/sys/mips/nlm/dev/sec/rsa_ucode.h (revision 326259) @@ -1,956 +1,958 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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$ */ #ifndef _NLM_HAL_RSA_UCODE_H #define _NLM_HAL_RSA_UCODE_H static uint64_t nlm_rsa_ucode_data [] = { 0x0000000000000000ULL, 0x00000000503840ecULL, 0x00000001903800ecULL, 0x00000002c03820ecULL, 0x0000003760000044ULL, 0x0000000000000014ULL, 0x000000071000000cULL, 0x00000007d000010cULL, 0x0000001b80000c0cULL, 0x00000000e03fc0ecULL, 0x00000001103fc1ecULL, 0x00000001403f42ecULL, 0x00000001403fc4ecULL, 0x0000003760000044ULL, 0x000000001800003cULL, 0x0000000d8000030cULL, 0x0000000630000044ULL, 0x000000002800003cULL, 0x0000000ef000030cULL, 0x0000000630000044ULL, 0x00000000503fc23cULL, 0x00000000a03fc33cULL, 0x00000001403fc43cULL, 0x00000010c000030cULL, 0x0000000630000044ULL, 0x0000000000000014ULL, 0x000000071000000cULL, 0x0000001c1000070cULL, 0x0000002500000d0cULL, 0x00000027c0000e0cULL, 0x0000002d60000f0cULL, 0x00000002603f00ecULL, 0x00000002603f82ecULL, 0x00000002803f83ecULL, 0x00000002803f04ecULL, 0x00000002a03f06ecULL, 0x00000002a03f88ecULL, 0x0000003760000044ULL, 0x000000086000010cULL, 0x00000003f0000044ULL, 0x00000008d000010cULL, 0x00000004b0000044ULL, 0x00000008d000010cULL, 0x0000000570000044ULL, 0x000000000000001cULL, 0x000000076000000cULL, 0x0000001c1000070cULL, 0x0000002690000d0cULL, 0x0000002990000e0cULL, 0x0000002e10000f0cULL, 0x00000003903f20ecULL, 0x00000003903fa2ecULL, 0x00000003b03fa3ecULL, 0x00000003b03f24ecULL, 0x00000003d03f26ecULL, 0x00000003d03fa8ecULL, 0x0000003760000044ULL, 0x000000096000010cULL, 0x00000003f0000044ULL, 0x0000000a0000010cULL, 0x00000004b0000044ULL, 0x0000000a0000010cULL, 0x0000000570000044ULL, 0x000000000800003cULL, 0x0000000af000020cULL, 0x0000000bc000030cULL, 0x000000129000040cULL, 0x000000178000050cULL, 0x000000191000060cULL, 0x0000001ff000080cULL, 0x000000205000090cULL, 0x00000022c0000a0cULL, 0x00000020b0000b0cULL, 0x0000001ac0000c0cULL, 0x0000000680000044ULL, 0x000000001000003cULL, 0x0000000b5000020cULL, 0x0000000c5000030cULL, 0x000000137000040cULL, 0x00000017e000050cULL, 0x000000197000060cULL, 0x000000200000080cULL, 0x000000206000090cULL, 0x0000002340000a0cULL, 0x0000002110000b0cULL, 0x0000001b10000c0cULL, 0x0000000680000044ULL, 0x000000001800003cULL, 0x0000000b5000020cULL, 0x0000000d8000030cULL, 0x000000154000040cULL, 0x000000187000050cULL, 0x0000001a0000060cULL, 0x000000202000080cULL, 0x000000208000090cULL, 0x0000002410000a0cULL, 0x00000021c0000b0cULL, 0x0000001b80000c0cULL, 0x0000000680000044ULL, 0x000000000000000aULL, 0x0000000000000024ULL, 0x0000002ed01f80e4ULL, 0x00000030101f81e4ULL, 0x0000003760000044ULL, 0x000000000000000aULL, 0x0000000000000024ULL, 0x00000030d01f00e4ULL, 0x00000030d01f82e4ULL, 0x00000034801f83e4ULL, 0x00000035401e04e4ULL, 0x00000037101f88e4ULL, 0x00000035401f89e4ULL, 0x0000003760000044ULL, 0x0000000000000074ULL, 0x0000000f0000008cULL, 0x00000008000000a4ULL, 0x000000080400007bULL, 0x00000000000000c4ULL, 0x0000000000000074ULL, 0x0000000c000000a4ULL, 0x0000000004004071ULL, 0x0000000b0000008cULL, 0x00000008000000a4ULL, 0x000000080400007bULL, 0x00000000000000c4ULL, 0x000000034c0b4091ULL, 0x0000000b040b0093ULL, 0x0000000000000000ULL, 0x0000000004000802ULL, 0x00000002c88b0021ULL, 0x0000000a828b0423ULL, 0x00000010000000a4ULL, 0x000000081000006cULL, 0x00000000000000c4ULL, 0x000000004c0b4091ULL, 0x00000008000000a4ULL, 0x0000000002000402ULL, 0x000000004a8b0021ULL, 0x00000010000000a4ULL, 0x000000089000006cULL, 0x00000000000000c4ULL, 0x000000034c0b4091ULL, 0x0000000b040b0093ULL, 0x00000008000000a4ULL, 0x0000000002000402ULL, 0x00000002c88b0021ULL, 0x0000000a828b0423ULL, 0x00000010000000a4ULL, 0x000000091000006cULL, 0x00000000000000c4ULL, 0x000000004c0b4091ULL, 0x00000008000000a4ULL, 0x0000000002000402ULL, 0x000000004a8b0021ULL, 0x00000010000000a4ULL, 0x0000000990000064ULL, 0x000000004a8b0021ULL, 0x0000000000898611ULL, 0x0000000c000000a4ULL, 0x00000000000000c4ULL, 0x000000034c0b4091ULL, 0x0000000b040b0093ULL, 0x00000008000000a4ULL, 0x0000000002000402ULL, 0x00000002c88b0021ULL, 0x0000000a828b0423ULL, 0x00000010000000a4ULL, 0x0000000a40000064ULL, 0x0000000088800021ULL, 0x0000000880800423ULL, 0x00000000001004a1ULL, 0x0000000c000000a4ULL, 0x00000002c88b0061ULL, 0x0000000a808b0463ULL, 0x00000000000000c4ULL, 0x00000000058f0011ULL, 0x0000000001860002ULL, 0x00000010000000a4ULL, 0x00000000000000ccULL, 0x000000004d8f0021ULL, 0x0000000b10000044ULL, 0x00000007058f0013ULL, 0x0000000001860002ULL, 0x00000010000000a4ULL, 0x00000000000000ccULL, 0x000000034c0f0021ULL, 0x0000000b058f0423ULL, 0x0000000b70000044ULL, 0x0000000000180001ULL, 0x000000000b600031ULL, 0x00000008000000a4ULL, 0x0000000004800041ULL, 0x00000008000000a4ULL, 0x0000000007c03f41ULL, 0x00000000440ac491ULL, 0x00000004000000a4ULL, 0x00000000000000c4ULL, 0x0000000010180001ULL, 0x0000000088a00031ULL, 0x00000002c3430431ULL, 0x00000004000000a4ULL, 0x0000000204938041ULL, 0x00000008000000a4ULL, 0x000000012c002b41ULL, 0x0000000117982861ULL, 0x0000000088a03631ULL, 0x00000002c3430c31ULL, 0x00000004000000a4ULL, 0x0000000204938041ULL, 0x00000008000000a4ULL, 0x000000012c002b41ULL, 0x0000000347cb2861ULL, 0x000000034c09f691ULL, 0x00000003040a8491ULL, 0x0000000000000000ULL, 0x00000000000000c4ULL, 0x0000000010180001ULL, 0x0000000088a00031ULL, 0x00000002c0830431ULL, 0x0000000283430431ULL, 0x000000080000009cULL, 0x0000000204938041ULL, 0x00000008000000a4ULL, 0x000000012c002b41ULL, 0x0000000104202861ULL, 0x0000000117d82861ULL, 0x0000000088a02f31ULL, 0x00000002c0833c31ULL, 0x0000002283430c3bULL, 0x0000000000000000ULL, 0x0000000204938041ULL, 0x00000008000000a4ULL, 0x000000012c002b41ULL, 0x00000003442b2861ULL, 0x0000000307cb2861ULL, 0x000000034c09ef91ULL, 0x000000030409bc91ULL, 0x00000003040a8491ULL, 0x00000000000000c4ULL, 0x0000000010180001ULL, 0x0000000088a00031ULL, 0x00000002c0830431ULL, 0x0000000280830431ULL, 0x0000000280c30431ULL, 0x0000000004900041ULL, 0x0000000283430531ULL, 0x0000000a00038007ULL, 0x0000000000000000ULL, 0x000000012c002b41ULL, 0x0000000344202861ULL, 0x0000001304032863ULL, 0x0000000317db2861ULL, 0x00000000b8a02b31ULL, 0x00000002c0832831ULL, 0x0000000280832831ULL, 0x0000000280c33c31ULL, 0x0000000004900041ULL, 0x0000002e83430d3bULL, 0x0000000200038000ULL, 0x0000000000000000ULL, 0x000000012c002b41ULL, 0x00000003442b2861ULL, 0x00000013040b2863ULL, 0x0000000307cb2861ULL, 0x000000037c09eb91ULL, 0x000000130409a893ULL, 0x000000030409bc91ULL, 0x00000003040a849dULL, 0x0000000010180001ULL, 0x0000000088a00031ULL, 0x00000002c0830431ULL, 0x0000000280830431ULL, 0x0000000280c30431ULL, 0x0000000004900041ULL, 0x0000000280830531ULL, 0x0000001e80830433ULL, 0x0000000283430431ULL, 0x0000000b2c03ab67ULL, 0x0000000344202861ULL, 0x0000001304032863ULL, 0x0000000317db2861ULL, 0x00000002b8a3ab31ULL, 0x00000002c0832831ULL, 0x0000000280832831ULL, 0x0000000280c32831ULL, 0x0000000004900041ULL, 0x0000000280832931ULL, 0x0000001e80832833ULL, 0x0000002e83430c3bULL, 0x000000032c03ab61ULL, 0x00000003442b2861ULL, 0x00000013040b2863ULL, 0x0000000307cb2861ULL, 0x000000037c09eb91ULL, 0x000000130409a893ULL, 0x000000030409bc91ULL, 0x00000003040a849dULL, 0x0000000000140001ULL, 0x0000004000140001ULL, 0x000000000b600061ULL, 0x000000400b600061ULL, 0x00000004000000a4ULL, 0x0000000004800041ULL, 0x0000004004800041ULL, 0x00000004000000a4ULL, 0x0000000007c03f41ULL, 0x0000004007c03f41ULL, 0x00000000440ac591ULL, 0x00000040440ac591ULL, 0x0000000000000000ULL, 0x00000000000000c4ULL, 0x0000000010140001ULL, 0x0000004010140001ULL, 0x0000000088e00061ULL, 0x0000004088e00061ULL, 0x00000002c3430561ULL, 0x00000042c3430561ULL, 0x0000000204938041ULL, 0x0000004204938041ULL, 0x00000004000000a4ULL, 0x000000012c402b41ULL, 0x000000412c402b41ULL, 0x0000000117f42961ULL, 0x0000004117f42961ULL, 0x0000000088e03f61ULL, 0x0000004088e03f61ULL, 0x00000002c3430d61ULL, 0x00000042c3430d61ULL, 0x0000000204938041ULL, 0x0000004204938041ULL, 0x00000004000000a4ULL, 0x000000012c402b41ULL, 0x000000412c402b41ULL, 0x0000000347eb2961ULL, 0x0000004347eb2961ULL, 0x000000034c7dff91ULL, 0x000000434c7dff91ULL, 0x00000003040a0591ULL, 0x00000043040a0591ULL, 0x00000000000000c4ULL, 0x0000000010140001ULL, 0x0000004010140001ULL, 0x0000000088e00061ULL, 0x0000004088e00061ULL, 0x00000002c0c30561ULL, 0x00000042c0c30561ULL, 0x0000000004900041ULL, 0x0000004004900041ULL, 0x0000000283430561ULL, 0x0000004283430561ULL, 0x0000000b2c43ab47ULL, 0x000000432c43ab41ULL, 0x0000000344602961ULL, 0x0000004344602961ULL, 0x0000000317d72961ULL, 0x0000004317d72961ULL, 0x00000002b8e3ab61ULL, 0x00000042b8e3ab61ULL, 0x00000002c0c32961ULL, 0x00000042c0c32961ULL, 0x0000000004900041ULL, 0x0000004004900041ULL, 0x0000000283430d61ULL, 0x0000007683430d6bULL, 0x000000032c43ab41ULL, 0x000000432c43ab41ULL, 0x00000003446b2961ULL, 0x00000043446b2961ULL, 0x0000000307cb2961ULL, 0x0000004307cb2961ULL, 0x000000037c7de791ULL, 0x000000437c7de791ULL, 0x0000000304499d91ULL, 0x0000004304499d91ULL, 0x00000003040a0591ULL, 0x00000043040a059dULL, 0x0000000048840011ULL, 0x00000000028b3691ULL, 0x000000000e09c691ULL, 0x000000000c09c691ULL, 0x0000000000000000ULL, 0x00000000000000c4ULL, 0x00000000c8840011ULL, 0x0000000212ab3691ULL, 0x0000000080800411ULL, 0x0000000002cb3691ULL, 0x000000034c29ef91ULL, 0x0000000006098491ULL, 0x000000034c09ef91ULL, 0x0000000004098491ULL, 0x00000000000000c4ULL, 0x00000000e8840011ULL, 0x0000000210ab3a91ULL, 0x0000000880800415ULL, 0x00000006128b3699ULL, 0x000000034c29eb91ULL, 0x0000000f0409a893ULL, 0x0000000026098891ULL, 0x000000034c09eb91ULL, 0x0000000f0409a893ULL, 0x000000000409849dULL, 0x0000000048841011ULL, 0x00000000068b7691ULL, 0x000000000e099611ULL, 0x000000000c098611ULL, 0x0000000000000000ULL, 0x00000000000000c4ULL, 0x00000000c8840011ULL, 0x0000000216ab7691ULL, 0x0000000080801411ULL, 0x0000000006cb3691ULL, 0x000000034c29af11ULL, 0x0000000006099411ULL, 0x000000034c09af11ULL, 0x0000000004098411ULL, 0x00000000000000c4ULL, 0x00000000e8840011ULL, 0x0000000214ab7a91ULL, 0x0000000c80800415ULL, 0x00000006168b3699ULL, 0x0000000080801411ULL, 0x00000002168b3691ULL, 0x000000034c29ab11ULL, 0x0000000f0409a813ULL, 0x0000000026099811ULL, 0x000000034c09ab11ULL, 0x0000000f0409a813ULL, 0x000000000409841dULL, 0x0000000c000000d4ULL, 0x0000000000000000ULL, 0x000000004a801011ULL, 0x000000000e004691ULL, 0x000000000009800dULL, 0x0000000c000000d4ULL, 0x000000004a801011ULL, 0x000000018c004691ULL, 0x0000000000800411ULL, 0x0000000006003691ULL, 0x0000000200098001ULL, 0x000000000009800dULL, 0x0000000c000000d4ULL, 0x000000004a801011ULL, 0x000000018c004691ULL, 0x0000000c00800415ULL, 0x0000000584003699ULL, 0x0000000000800411ULL, 0x0000000006003691ULL, 0x0000000a00098003ULL, 0x000000000009800dULL, 0x000000200000302aULL, 0x00000000000e0012ULL, 0x0000000000100211ULL, 0x0000000002000002ULL, 0x00000006000b0003ULL, 0x0000000000000000ULL, 0x00000000000000ccULL, 0x0000000006000302ULL, 0x00000002810b0011ULL, 0x0000000a808b0013ULL, 0x0000000002010002ULL, 0x00000006108b0093ULL, 0x0000000002800002ULL, 0x00000007040b0013ULL, 0x0000000006800002ULL, 0x00000007040b0013ULL, 0x0000000003000002ULL, 0x0000000000090101ULL, 0x0000000200098001ULL, 0x0000000a000b0003ULL, 0x0000000007000302ULL, 0x0000000400890015ULL, 0x0000000784098019ULL, 0x0000000007800002ULL, 0x0000000000090001ULL, 0x0000000000098101ULL, 0x0000001dd000006cULL, 0x000000280300060aULL, 0x0000000000000000ULL, 0x0000000000000e02ULL, 0x0000000001000011ULL, 0x00000010000000a4ULL, 0x0000001dc0000064ULL, 0x0000000000000f02ULL, 0x0000000001000011ULL, 0x0000000002000602ULL, 0x0000000680890013ULL, 0x0000000002806002ULL, 0x0000000004000011ULL, 0x000000031489f691ULL, 0x0000000804000415ULL, 0x000000071489b699ULL, 0x0000000006000e02ULL, 0x0000000680890013ULL, 0x0000000006800e02ULL, 0x0000000680898013ULL, 0x0000002c0300540aULL, 0x0000000007800012ULL, 0x00000000000b8000ULL, 0x000000000700cd42ULL, 0x0000000000800011ULL, 0x000000029489f691ULL, 0x0000000800800415ULL, 0x000000069489b699ULL, 0x000000200000e02aULL, 0x00000000000000fcULL, 0x0000000c000000a4ULL, 0x0000001dc0000064ULL, 0x000000240000c02aULL, 0x0000000002000012ULL, 0x0000000600090003ULL, 0x00000000000000c4ULL, 0x000000001680409dULL, 0x0000000014804091ULL, 0x000000001680049dULL, 0x0000000014804091ULL, 0x0000000014800491ULL, 0x000000001680049dULL, 0x000000001680419dULL, 0x0000000014804191ULL, 0x000000001680049dULL, 0x0000000014804191ULL, 0x0000000014800491ULL, 0x000000001680049dULL, 0x0000000000800011ULL, 0x00000000068b5691ULL, 0x0000000004098611ULL, 0x000000000700dc22ULL, 0x0000000000800011ULL, 0x0000000296cb569dULL, 0x0000000000800011ULL, 0x0000000294ab7691ULL, 0x0000000000801411ULL, 0x00000000068b3691ULL, 0x000000034409af11ULL, 0x0000000004098411ULL, 0x000000000700dc22ULL, 0x0000000000800011ULL, 0x00000002948b7691ULL, 0x0000000000801411ULL, 0x0000000296cb369dULL, 0x0000000000800011ULL, 0x0000000294ab7691ULL, 0x0000000000800411ULL, 0x00000002948b3691ULL, 0x0000000000801411ULL, 0x00000000068b3a91ULL, 0x000000034409ab11ULL, 0x000000030409a411ULL, 0x0000000004098411ULL, 0x000000000700dc22ULL, 0x0000000000800011ULL, 0x00000002948b7691ULL, 0x0000000000800411ULL, 0x00000002948b3691ULL, 0x0000000000801411ULL, 0x0000000296cb369dULL, 0x0000000001000011ULL, 0x0000000006098611ULL, 0x0000000000000000ULL, 0x0000000007000e02ULL, 0x0000000000888061ULL, 0x0000000003000602ULL, 0x0000000000888061ULL, 0x00000000000984edULL, 0x0000000001000011ULL, 0x0000000b8409b615ULL, 0x0000000400800419ULL, 0x000000000609b611ULL, 0x0000000007000e02ULL, 0x0000000080800061ULL, 0x0000000200cb0461ULL, 0x00000000000b8000ULL, 0x0000000003000602ULL, 0x0000000080800061ULL, 0x0000000200cb0461ULL, 0x00000000000b8001ULL, 0x00000000000985edULL, 0x0000000001000011ULL, 0x0000000b8409b615ULL, 0x0000000400800419ULL, 0x000000000609b611ULL, 0x0000000007000e02ULL, 0x0000000080800061ULL, 0x00000002808b0461ULL, 0x0000000200cb0461ULL, 0x00000000000b8000ULL, 0x0000000003000602ULL, 0x0000000080800061ULL, 0x00000002808b0461ULL, 0x0000000200cb0461ULL, 0x00000000000b8001ULL, 0x00000000000985edULL, 0x0000000002800002ULL, 0x000000500220220aULL, 0x000000140606550aULL, 0x000000140606c50aULL, 0x0000000002a01202ULL, 0x000000500680100aULL, 0x000000140286550aULL, 0x000000000300d502ULL, 0x000000500220340aULL, 0x000000140306660aULL, 0x000000140686c40aULL, 0x000000140206660aULL, 0x000000000600dd02ULL, 0x000000500720550aULL, 0x0000001806064c0aULL, 0x000000180306c60aULL, 0x0000000002001102ULL, 0x000000500020c50aULL, 0x000000000600e402ULL, 0x000000500220440aULL, 0x000000140606cc0aULL, 0x000000000320d602ULL, 0x000000500100e50aULL, 0x000000180086c60aULL, 0x00000000000000c4ULL, 0x0000000002000002ULL, 0x0000005002a0210aULL, 0x000000140280540aULL, 0x0000000003005502ULL, 0x000000500620200aULL, 0x000000140680c50aULL, 0x0000000002004402ULL, 0x0000005003a0cc0aULL, 0x0000000002a03702ULL, 0x000000500700c50aULL, 0x000000140280650aULL, 0x000000140280e50aULL, 0x000000000000c502ULL, 0x000000500120c70aULL, 0x000000000200c402ULL, 0x0000005000a0d50aULL, 0x0000000000000000ULL, 0x000000140080410aULL, 0x00000000000000c4ULL, 0x0000000006009202ULL, 0x000000500220a10aULL, 0x0000001806064c0aULL, 0x0000000002808202ULL, 0x0000005006a0a00aULL, 0x000000180706d50aULL, 0x000000000320cc02ULL, 0x000000500280ee0aULL, 0x0000000006a0d502ULL, 0x000000500780a20aULL, 0x000000140386dd0aULL, 0x000000000300f602ULL, 0x0000005002a0e50aULL, 0x000000180306560aULL, 0x0000000000000000ULL, 0x000000180306760aULL, 0x0000001806866d0aULL, 0x000000000380f502ULL, 0x0000005007a0450aULL, 0x000000300281070aULL, 0x000000200000502aULL, 0x00000000000000fcULL, 0x0000000c000000a4ULL, 0x0000002bc000006cULL, 0x000000000600dc02ULL, 0x000000500020e60aULL, 0x000000180086fc0aULL, 0x000000140107170aULL, 0x00000000000000c4ULL, 0x000000000200a102ULL, 0x000000500620920aULL, 0x000000140600c40aULL, 0x000000000200a002ULL, 0x0000005006a0820aULL, 0x000000140680d40aULL, 0x000000140200dc0aULL, 0x000000000700a202ULL, 0x0000005002a0dd0aULL, 0x000000000300c402ULL, 0x0000005003a0350aULL, 0x0000000000000000ULL, 0x000000140300670aULL, 0x000000000380d502ULL, 0x0000005007a0e60aULL, 0x0000000000000000ULL, 0x0000001407807f0aULL, 0x000000000380d102ULL, 0x000000500320c00aULL, 0x0000000000000000ULL, 0x000000140380760aULL, 0x0000000003007502ULL, 0x0000005002a0d50aULL, 0x000000000200f402ULL, 0x0000005003a0e50aULL, 0x000000300281070aULL, 0x000000200000502aULL, 0x00000000000000fcULL, 0x0000000c000000a4ULL, 0x0000002bc000006cULL, 0x000000000000df02ULL, 0x0000005000a0a60aULL, 0x000000140101170aULL, 0x000000140080410aULL, 0x00000000000000c4ULL, 0x000000300281020aULL, 0x0000003006810a0aULL, 0x0000003006010c0aULL, 0x000000200000202aULL, 0x00000000000000fcULL, 0x0000000c000000a4ULL, 0x0000002d1000006cULL, 0x000000200000a02aULL, 0x00000000000000fcULL, 0x0000000c000000a4ULL, 0x0000002d5000006cULL, 0x000000200000c02aULL, 0x00000000000000fcULL, 0x0000000c000000a4ULL, 0x0000002cd0000064ULL, 0x00000034000000d4ULL, 0x00000000000000c4ULL, 0x0000000001000002ULL, 0x00000006000b0003ULL, 0x0000000000000000ULL, 0x00000000000000c4ULL, 0x000000140001180aULL, 0x000000140081190aULL, 0x0000001401011a0aULL, 0x00000000000000c4ULL, 0x00000000000000c4ULL, 0x0000000001810302ULL, 0x0000005005a10b0aULL, 0x0000000002000002ULL, 0x000000500620110aULL, 0x000000140206340aULL, 0x000000180606cb0aULL, 0x0000000002000402ULL, 0x0000005006210c0aULL, 0x000000140206c40aULL, 0x000000300201040aULL, 0x00000000000000c4ULL, 0x0000000002801002ULL, 0x0000005005a10b0aULL, 0x000000140286b50aULL, 0x000000140186300aULL, 0x0000000002000002ULL, 0x000000500620110aULL, 0x000000140606c50aULL, 0x0000000002003402ULL, 0x0000005006210c0aULL, 0x000000140206c40aULL, 0x000000300201040aULL, 0x00000000000000c4ULL, 0x000000040400000aULL, 0x000000000000002cULL, 0x0000000c0000800eULL, 0x0000000c0400880aULL, 0x000000080000007cULL, 0x0000000004000002ULL, 0x00000006808b0013ULL, 0x0000000000000034ULL, 0x0000000000000002ULL, 0x0000002ff000005cULL, 0x0000002f4000004cULL, 0x00000002000b0101ULL, 0x0000000a000b0003ULL, 0x0000003760000044ULL, 0x0000000000000034ULL, 0x0000000c0000000aULL, 0x0000002ff0000054ULL, 0x0000000c0000800aULL, 0x0000002fb000004cULL, 0x0000003640000044ULL, 0x0000000c0000800aULL, 0x000000040400000aULL, 0x000000000000002cULL, 0x0000000c0000800eULL, 0x0000000c0400880aULL, 0x000000080000007cULL, 0x000000040400000aULL, 0x000000000000002cULL, 0x0000000c0000800eULL, 0x0000000c0400880aULL, 0x000000080000007cULL, 0x0000003640000044ULL, 0x000000080180000aULL, 0x0000000001820002ULL, 0x00000007040b0013ULL, 0x000000040200000aULL, 0x000000000000002cULL, 0x0000000c0180430eULL, 0x0000000c0200440aULL, 0x000000080000007cULL, 0x0000000001010002ULL, 0x00000006108b0093ULL, 0x0000000005010002ULL, 0x00000006108b0093ULL, 0x0000000000000000ULL, 0x00000032e01f80e4ULL, 0x00000034401f81e4ULL, 0x00000034601f82e4ULL, 0x0000000c0181020aULL, 0x0000000c0181030aULL, 0x0000001c000000d4ULL, 0x0000000000004002ULL, 0x0000005000a0410aULL, 0x0000000001004202ULL, 0x000000500021000aULL, 0x0000000000810102ULL, 0x000000500121020aULL, 0x000000200000202aULL, 0x00000000000000fcULL, 0x0000000c000000a4ULL, 0x0000000000000002ULL, 0x0000000600098003ULL, 0x0000000000810002ULL, 0x0000000610898093ULL, 0x0000003760000044ULL, 0x0000000004000002ULL, 0x00000006808b0013ULL, 0x0000000004800102ULL, 0x00000006808b0013ULL, 0x0000000005000202ULL, 0x00000006808b0013ULL, 0x0000000000000034ULL, 0x0000000000000002ULL, 0x000000342000005cULL, 0x000000334000004cULL, 0x0000001000000084ULL, 0x00000006000b0009ULL, 0x00000002000b0101ULL, 0x0000002000000084ULL, 0x00000006000b0009ULL, 0x0000003760000044ULL, 0x0000000000000034ULL, 0x00000034000000d4ULL, 0x0000003420000054ULL, 0x00000038000000d4ULL, 0x00000033e000004cULL, 0x00000031d0000044ULL, 0x00000038000000d4ULL, 0x00000031d0000044ULL, 0x00000034000000d4ULL, 0x00000031d0000044ULL, 0x000000080180000aULL, 0x0000000001820002ULL, 0x00000007040b0013ULL, 0x0000000005840002ULL, 0x00000007040b0013ULL, 0x0000003c000000d4ULL, 0x00000004000000a4ULL, 0x000000200000402aULL, 0x0000000000000012ULL, 0x00000000000b0001ULL, 0x0000000000098101ULL, 0x0000003760000044ULL, 0x000000040200000aULL, 0x000000000000002cULL, 0x0000000c0000400eULL, 0x0000000c0200440aULL, 0x000000080000007cULL, 0x00000036c01f87e4ULL, 0x00000036401f89e4ULL, 0x000000040200000aULL, 0x000000000000002cULL, 0x0000000c0400480eULL, 0x0000000c0200440aULL, 0x000000080000007cULL, 0x00000036a01f86e4ULL, 0x000000080180000aULL, 0x00000036601f84e4ULL, 0x00000036801f85e4ULL, 0x000000300001000aULL, 0x0000003760000044ULL, 0x000000140006800aULL, 0x0000003640000044ULL, 0x000000180006800aULL, 0x0000003640000044ULL, 0x0000000c0000800aULL, 0x0000003640000044ULL, 0x0000000c0181080aULL, 0x0000001c000000d4ULL, 0x00000004000000a4ULL, 0x0000000c0000400aULL, 0x0000003640000044ULL, 0x0000000c0181000aULL, 0x0000001c000000d4ULL, 0x00000004000000a4ULL, 0x000000140001140aULL, 0x0000003640000044ULL, 0x0000000c000000a4ULL, 0x0000000000000044ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL, }; #endif /* _NLM_HAL_RSA_UCODE_H_ */ Index: head/sys/mips/nlm/hal/bridge.h =================================================================== --- head/sys/mips/nlm/hal/bridge.h (revision 326258) +++ head/sys/mips/nlm/hal/bridge.h (revision 326259) @@ -1,184 +1,186 @@ /*- + * 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 * $FreeBSD$ */ #ifndef __NLM_HAL_BRIDGE_H__ #define __NLM_HAL_BRIDGE_H__ /** * @file_name mio.h * @author Netlogic Microsystems * @brief Basic definitions of XLP memory and io subsystem */ /* * BRIDGE specific registers * * These registers start after the PCIe header, which has 0x40 * standard entries */ #define BRIDGE_MODE 0x00 #define BRIDGE_PCI_CFG_BASE 0x01 #define BRIDGE_PCI_CFG_LIMIT 0x02 #define BRIDGE_PCIE_CFG_BASE 0x03 #define BRIDGE_PCIE_CFG_LIMIT 0x04 #define BRIDGE_BUSNUM_BAR0 0x05 #define BRIDGE_BUSNUM_BAR1 0x06 #define BRIDGE_BUSNUM_BAR2 0x07 #define BRIDGE_BUSNUM_BAR3 0x08 #define BRIDGE_BUSNUM_BAR4 0x09 #define BRIDGE_BUSNUM_BAR5 0x0a #define BRIDGE_BUSNUM_BAR6 0x0b #define BRIDGE_FLASH_BAR0 0x0c #define BRIDGE_FLASH_BAR1 0x0d #define BRIDGE_FLASH_BAR2 0x0e #define BRIDGE_FLASH_BAR3 0x0f #define BRIDGE_FLASH_LIMIT0 0x10 #define BRIDGE_FLASH_LIMIT1 0x11 #define BRIDGE_FLASH_LIMIT2 0x12 #define BRIDGE_FLASH_LIMIT3 0x13 #define BRIDGE_DRAM_BAR(i) (0x14 + (i)) #define BRIDGE_DRAM_BAR0 0x14 #define BRIDGE_DRAM_BAR1 0x15 #define BRIDGE_DRAM_BAR2 0x16 #define BRIDGE_DRAM_BAR3 0x17 #define BRIDGE_DRAM_BAR4 0x18 #define BRIDGE_DRAM_BAR5 0x19 #define BRIDGE_DRAM_BAR6 0x1a #define BRIDGE_DRAM_BAR7 0x1b #define BRIDGE_DRAM_LIMIT(i) (0x1c + (i)) #define BRIDGE_DRAM_LIMIT0 0x1c #define BRIDGE_DRAM_LIMIT1 0x1d #define BRIDGE_DRAM_LIMIT2 0x1e #define BRIDGE_DRAM_LIMIT3 0x1f #define BRIDGE_DRAM_LIMIT4 0x20 #define BRIDGE_DRAM_LIMIT5 0x21 #define BRIDGE_DRAM_LIMIT6 0x22 #define BRIDGE_DRAM_LIMIT7 0x23 #define BRIDGE_DRAM_NODE_TRANSLN0 0x24 #define BRIDGE_DRAM_NODE_TRANSLN1 0x25 #define BRIDGE_DRAM_NODE_TRANSLN2 0x26 #define BRIDGE_DRAM_NODE_TRANSLN3 0x27 #define BRIDGE_DRAM_NODE_TRANSLN4 0x28 #define BRIDGE_DRAM_NODE_TRANSLN5 0x29 #define BRIDGE_DRAM_NODE_TRANSLN6 0x2a #define BRIDGE_DRAM_NODE_TRANSLN7 0x2b #define BRIDGE_DRAM_CHNL_TRANSLN0 0x2c #define BRIDGE_DRAM_CHNL_TRANSLN1 0x2d #define BRIDGE_DRAM_CHNL_TRANSLN2 0x2e #define BRIDGE_DRAM_CHNL_TRANSLN3 0x2f #define BRIDGE_DRAM_CHNL_TRANSLN4 0x30 #define BRIDGE_DRAM_CHNL_TRANSLN5 0x31 #define BRIDGE_DRAM_CHNL_TRANSLN6 0x32 #define BRIDGE_DRAM_CHNL_TRANSLN7 0x33 #define BRIDGE_PCIEMEM_BASE0 0x34 #define BRIDGE_PCIEMEM_BASE1 0x35 #define BRIDGE_PCIEMEM_BASE2 0x36 #define BRIDGE_PCIEMEM_BASE3 0x37 #define BRIDGE_PCIEMEM_LIMIT0 0x38 #define BRIDGE_PCIEMEM_LIMIT1 0x39 #define BRIDGE_PCIEMEM_LIMIT2 0x3a #define BRIDGE_PCIEMEM_LIMIT3 0x3b #define BRIDGE_PCIEIO_BASE0 0x3c #define BRIDGE_PCIEIO_BASE1 0x3d #define BRIDGE_PCIEIO_BASE2 0x3e #define BRIDGE_PCIEIO_BASE3 0x3f #define BRIDGE_PCIEIO_LIMIT0 0x40 #define BRIDGE_PCIEIO_LIMIT1 0x41 #define BRIDGE_PCIEIO_LIMIT2 0x42 #define BRIDGE_PCIEIO_LIMIT3 0x43 #define BRIDGE_PCIEMEM_BASE4 0x44 #define BRIDGE_PCIEMEM_BASE5 0x45 #define BRIDGE_PCIEMEM_BASE6 0x46 #define BRIDGE_PCIEMEM_LIMIT4 0x47 #define BRIDGE_PCIEMEM_LIMIT5 0x48 #define BRIDGE_PCIEMEM_LIMIT6 0x49 #define BRIDGE_PCIEIO_BASE4 0x4a #define BRIDGE_PCIEIO_BASE5 0x4b #define BRIDGE_PCIEIO_BASE6 0x4c #define BRIDGE_PCIEIO_LIMIT4 0x4d #define BRIDGE_PCIEIO_LIMIT5 0x4e #define BRIDGE_PCIEIO_LIMIT6 0x4f #define BRIDGE_NBU_EVENT_CNT_CTL 0x50 #define BRIDGE_EVNTCTR1_LOW 0x51 #define BRIDGE_EVNTCTR1_HI 0x52 #define BRIDGE_EVNT_CNT_CTL2 0x53 #define BRIDGE_EVNTCTR2_LOW 0x54 #define BRIDGE_EVNTCTR2_HI 0x55 #define BRIDGE_TRACEBUF_MATCH0 0x56 #define BRIDGE_TRACEBUF_MATCH1 0x57 #define BRIDGE_TRACEBUF_MATCH_LOW 0x58 #define BRIDGE_TRACEBUF_MATCH_HI 0x59 #define BRIDGE_TRACEBUF_CTRL 0x5a #define BRIDGE_TRACEBUF_INIT 0x5b #define BRIDGE_TRACEBUF_ACCESS 0x5c #define BRIDGE_TRACEBUF_READ_DATA0 0x5d #define BRIDGE_TRACEBUF_READ_DATA1 0x5d #define BRIDGE_TRACEBUF_READ_DATA2 0x5f #define BRIDGE_TRACEBUF_READ_DATA3 0x60 #define BRIDGE_TRACEBUF_STATUS 0x61 #define BRIDGE_ADDRESS_ERROR0 0x62 #define BRIDGE_ADDRESS_ERROR1 0x63 #define BRIDGE_ADDRESS_ERROR2 0x64 #define BRIDGE_TAG_ECC_ADDR_ERROR0 0x65 #define BRIDGE_TAG_ECC_ADDR_ERROR1 0x66 #define BRIDGE_TAG_ECC_ADDR_ERROR2 0x67 #define BRIDGE_LINE_FLUSH0 0x68 #define BRIDGE_LINE_FLUSH1 0x69 #define BRIDGE_NODE_ID 0x6a #define BRIDGE_ERROR_INTERRUPT_EN 0x6b #define BRIDGE_PCIE0_WEIGHT 0x2c0 #define BRIDGE_PCIE1_WEIGHT 0x2c1 #define BRIDGE_PCIE2_WEIGHT 0x2c2 #define BRIDGE_PCIE3_WEIGHT 0x2c3 #define BRIDGE_USB_WEIGHT 0x2c4 #define BRIDGE_NET_WEIGHT 0x2c5 #define BRIDGE_POE_WEIGHT 0x2c6 #define BRIDGE_CMS_WEIGHT 0x2c7 #define BRIDGE_DMAENG_WEIGHT 0x2c8 #define BRIDGE_SEC_WEIGHT 0x2c9 #define BRIDGE_COMP_WEIGHT 0x2ca #define BRIDGE_GIO_WEIGHT 0x2cb #define BRIDGE_FLASH_WEIGHT 0x2cc #if !defined(LOCORE) && !defined(__ASSEMBLY__) #define nlm_read_bridge_reg(b, r) nlm_read_reg(b, r) #define nlm_write_bridge_reg(b, r, v) nlm_write_reg(b, r, v) #define nlm_get_bridge_pcibase(node) \ nlm_pcicfg_base(XLP_IO_BRIDGE_OFFSET(node)) #define nlm_get_bridge_regbase(node) \ (nlm_get_bridge_pcibase(node) + XLP_IO_PCI_HDRSZ) #endif #endif Index: head/sys/mips/nlm/hal/cop2.h =================================================================== --- head/sys/mips/nlm/hal/cop2.h (revision 326258) +++ head/sys/mips/nlm/hal/cop2.h (revision 326259) @@ -1,302 +1,304 @@ /*- + * 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 * $FreeBSD$ */ #ifndef __NLM_HAL_COP2_H__ #define __NLM_HAL_COP2_H__ #define COP2_TX_BUF 0 #define COP2_RX_BUF 1 #define COP2_TXMSGSTATUS 2 #define COP2_RXMSGSTATUS 3 #define COP2_MSGSTATUS1 4 #define COP2_MSGCONFIG 5 #define COP2_MSGERROR 6 #define CROSSTHR_POPQ_EN 0x01 #define VC0_POPQ_EN 0x02 #define VC1_POPQ_EN 0x04 #define VC2_POPQ_EN 0x08 #define VC3_POPQ_EN 0x10 #define ALL_VC_POPQ_EN 0x1E #define ALL_VC_CT_POPQ_EN 0x1F struct nlm_fmn_msg { uint64_t msg[4]; }; #define NLM_DEFINE_COP2_ACCESSORS32(name, reg, sel) \ static inline uint32_t nlm_read_c2_##name(void) \ { \ uint32_t __rv; \ __asm__ __volatile__ ( \ ".set push\n" \ ".set noreorder\n" \ ".set mips64\n" \ "mfc2 %0, $%1, %2\n" \ ".set pop\n" \ : "=r" (__rv) \ : "i" (reg), "i" (sel)); \ return __rv; \ } \ \ static inline void nlm_write_c2_##name(uint32_t val) \ { \ __asm__ __volatile__( \ ".set push\n" \ ".set noreorder\n" \ ".set mips64\n" \ "mtc2 %0, $%1, %2\n" \ ".set pop\n" \ : : "r" (val), "i" (reg), "i" (sel)); \ } struct __hack #if (__mips == 64) #define NLM_DEFINE_COP2_ACCESSORS64(name, reg, sel) \ static inline uint64_t nlm_read_c2_##name(void) \ { \ uint64_t __rv; \ __asm__ __volatile__ ( \ ".set push\n" \ ".set noreorder\n" \ ".set mips64\n" \ "dmfc2 %0, $%1, %2\n" \ ".set pop\n" \ : "=r" (__rv) \ : "i" (reg), "i" (sel)); \ return __rv; \ } \ \ static inline void nlm_write_c2_##name(uint64_t val) \ { \ __asm__ __volatile__ ( \ ".set push\n" \ ".set noreorder\n" \ ".set mips64\n" \ "dmtc2 %0, $%1, %2\n" \ ".set pop\n" \ : : "r" (val), "i" (reg), "i" (sel)); \ } struct __hack #else #define NLM_DEFINE_COP2_ACCESSORS64(name, reg, sel) \ static inline uint64_t nlm_read_c2_##name(void) \ { \ uint32_t __high, __low; \ __asm__ __volatile__ ( \ ".set push\n" \ ".set noreorder\n" \ ".set mips64\n" \ "dmfc2 $8, $%2, %3\n" \ "dsra32 %0, $8, 0\n" \ "sll %1, $8, 0\n" \ ".set pop\n" \ : "=r"(__high), "=r"(__low) \ : "i"(reg), "i"(sel) \ : "$8"); \ \ return ((uint64_t)__high << 32) | __low; \ } \ \ static inline void nlm_write_c2_##name(uint64_t val) \ { \ uint32_t __high = val >> 32; \ uint32_t __low = val & 0xffffffff; \ __asm__ __volatile__ ( \ ".set push\n" \ ".set noreorder\n" \ ".set mips64\n" \ "dsll32 $8, %1, 0\n" \ "dsll32 $9, %0, 0\n" \ "dsrl32 $8, $8, 0\n" \ "or $8, $8, $9\n" \ "dmtc2 $8, $%2, %3\n" \ ".set pop\n" \ : : "r"(__high), "r"(__low), "i"(reg), "i"(sel) \ : "$8", "$9"); \ } struct __hack #endif NLM_DEFINE_COP2_ACCESSORS64(txbuf0, COP2_TX_BUF, 0); NLM_DEFINE_COP2_ACCESSORS64(txbuf1, COP2_TX_BUF, 1); NLM_DEFINE_COP2_ACCESSORS64(txbuf2, COP2_TX_BUF, 2); NLM_DEFINE_COP2_ACCESSORS64(txbuf3, COP2_TX_BUF, 3); NLM_DEFINE_COP2_ACCESSORS64(rxbuf0, COP2_RX_BUF, 0); NLM_DEFINE_COP2_ACCESSORS64(rxbuf1, COP2_RX_BUF, 1); NLM_DEFINE_COP2_ACCESSORS64(rxbuf2, COP2_RX_BUF, 2); NLM_DEFINE_COP2_ACCESSORS64(rxbuf3, COP2_RX_BUF, 3); NLM_DEFINE_COP2_ACCESSORS32(txmsgstatus, COP2_TXMSGSTATUS, 0); NLM_DEFINE_COP2_ACCESSORS32(rxmsgstatus, COP2_RXMSGSTATUS, 0); NLM_DEFINE_COP2_ACCESSORS32(msgstatus1, COP2_MSGSTATUS1, 0); NLM_DEFINE_COP2_ACCESSORS32(msgconfig, COP2_MSGCONFIG, 0); NLM_DEFINE_COP2_ACCESSORS32(msgerror0, COP2_MSGERROR, 0); NLM_DEFINE_COP2_ACCESSORS32(msgerror1, COP2_MSGERROR, 1); NLM_DEFINE_COP2_ACCESSORS32(msgerror2, COP2_MSGERROR, 2); NLM_DEFINE_COP2_ACCESSORS32(msgerror3, COP2_MSGERROR, 3); /* successful completion returns 1, else 0 */ static inline int nlm_msgsend(int val) { int result; __asm__ volatile ( ".set push\n" ".set noreorder\n" ".set mips64\n" "move $8, %1\n" "sync\n" "/* msgsnds $9, $8 */\n" ".word 0x4a084801\n" "move %0, $9\n" ".set pop\n" : "=r" (result) : "r" (val) : "$8", "$9"); return result; } static inline int nlm_msgld(int vc) { int val; __asm__ volatile ( ".set push\n" ".set noreorder\n" ".set mips64\n" "move $8, %1\n" "/* msgld $9, $8 */\n" ".word 0x4a084802\n" "move %0, $9\n" ".set pop\n" : "=r" (val) : "r" (vc) : "$8", "$9"); return val; } static inline void nlm_msgwait(int vc) { __asm__ volatile ( ".set push\n" ".set noreorder\n" ".set mips64\n" "move $8, %0\n" "/* msgwait $8 */\n" ".word 0x4a080003\n" ".set pop\n" : : "r" (vc) : "$8"); } static inline int nlm_fmn_msgsend(int dstid, int size, int swcode, struct nlm_fmn_msg *m) { uint32_t flags, status; int rv; size -= 1; flags = nlm_save_flags_cop2(); switch (size) { case 3: nlm_write_c2_txbuf3(m->msg[3]); case 2: nlm_write_c2_txbuf2(m->msg[2]); case 1: nlm_write_c2_txbuf1(m->msg[1]); case 0: nlm_write_c2_txbuf0(m->msg[0]); } dstid |= ((swcode << 24) | (size << 16)); status = nlm_msgsend(dstid); rv = !status; if (rv != 0) rv = nlm_read_c2_txmsgstatus(); nlm_restore_flags(flags); return rv; } static inline int nlm_fmn_msgrcv(int vc, int *srcid, int *size, int *code, struct nlm_fmn_msg *m) { uint32_t status; uint32_t msg_status, flags; int tmp_sz, rv; flags = nlm_save_flags_cop2(); status = nlm_msgld(vc); /* will return 0, if error */ rv = !status; if (rv == 0) { msg_status = nlm_read_c2_rxmsgstatus(); *size = ((msg_status >> 26) & 0x3) + 1; *code = (msg_status >> 18) & 0xff; *srcid = (msg_status >> 4) & 0xfff; tmp_sz = *size - 1; switch (tmp_sz) { case 3: m->msg[3] = nlm_read_c2_rxbuf3(); case 2: m->msg[2] = nlm_read_c2_rxbuf2(); case 1: m->msg[1] = nlm_read_c2_rxbuf1(); case 0: m->msg[0] = nlm_read_c2_rxbuf0(); } } nlm_restore_flags(flags); return rv; } static inline void nlm_fmn_cpu_init(int int_vec, int ecc_en, int v0pe, int v1pe, int v2pe, int v3pe) { uint32_t val = nlm_read_c2_msgconfig(); /* Note: in XLP PRM 0.8.1, the int_vec bits are un-documented * in msgconfig register of cop2. * As per chip/cpu RTL, [16:20] bits consist of int_vec. */ val |= (((int_vec & 0x1f) << 16) | ((ecc_en & 0x1) << 8) | ((v3pe & 0x1) << 4) | ((v2pe & 0x1) << 3) | ((v1pe & 0x1) << 2) | ((v0pe & 0x1) << 1)); nlm_write_c2_msgconfig(val); } #endif Index: head/sys/mips/nlm/hal/cpucontrol.h =================================================================== --- head/sys/mips/nlm/hal/cpucontrol.h (revision 326258) +++ head/sys/mips/nlm/hal/cpucontrol.h (revision 326259) @@ -1,194 +1,196 @@ /*- + * 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 * $FreeBSD$ */ #ifndef __NLM_HAL_CPUCONTROL_H__ #define __NLM_HAL_CPUCONTROL_H__ #define CPU_BLOCKID_IFU 0 #define CPU_BLOCKID_ICU 1 #define CPU_BLOCKID_IEU 2 #define CPU_BLOCKID_LSU 3 #define CPU_BLOCKID_MMU 4 #define CPU_BLOCKID_PRF 5 #define CPU_BLOCKID_SCH 7 #define CPU_BLOCKID_SCU 8 #define CPU_BLOCKID_FPU 9 #define CPU_BLOCKID_MAP 10 #define LSU_DEFEATURE 0x304 #define LSU_DEBUG_ADDR 0x305 #define LSU_DEBUG_DATA0 0x306 #define LSU_CERRLOG_REGID 0x09 #define SCHED_DEFEATURE 0x700 /* Offsets of interest from the 'MAP' Block */ #define MAP_THREADMODE 0x00 #define MAP_EXT_EBASE_ENABLE 0x04 #define MAP_CCDI_CONFIG 0x08 #define MAP_THRD0_CCDI_STATUS 0x0c #define MAP_THRD1_CCDI_STATUS 0x10 #define MAP_THRD2_CCDI_STATUS 0x14 #define MAP_THRD3_CCDI_STATUS 0x18 #define MAP_THRD0_DEBUG_MODE 0x1c #define MAP_THRD1_DEBUG_MODE 0x20 #define MAP_THRD2_DEBUG_MODE 0x24 #define MAP_THRD3_DEBUG_MODE 0x28 #define MAP_MISC_STATE 0x60 #define MAP_DEBUG_READ_CTL 0x64 #define MAP_DEBUG_READ_REG0 0x68 #define MAP_DEBUG_READ_REG1 0x6c #define MMU_SETUP 0x400 #define MMU_LFSRSEED 0x401 #define MMU_HPW_NUM_PAGE_LVL 0x410 #define MMU_PGWKR_PGDBASE 0x411 #define MMU_PGWKR_PGDSHFT 0x412 #define MMU_PGWKR_PGDMASK 0x413 #define MMU_PGWKR_PUDSHFT 0x414 #define MMU_PGWKR_PUDMASK 0x415 #define MMU_PGWKR_PMDSHFT 0x416 #define MMU_PGWKR_PMDMASK 0x417 #define MMU_PGWKR_PTESHFT 0x418 #define MMU_PGWKR_PTEMASK 0x419 #if !defined(LOCORE) && !defined(__ASSEMBLY__) #if defined(__mips_n64) || defined(__mips_n32) static __inline uint64_t nlm_mfcr(uint32_t reg) { uint64_t res; __asm__ __volatile__( ".set push\n\t" ".set noreorder\n\t" "move $9, %1\n\t" ".word 0x71280018\n\t" /* mfcr $8, $9 */ "move %0, $8\n\t" ".set pop\n" : "=r" (res) : "r"(reg) : "$8", "$9" ); return (res); } static __inline void nlm_mtcr(uint32_t reg, uint64_t value) { __asm__ __volatile__( ".set push\n\t" ".set noreorder\n\t" "move $8, %0\n" "move $9, %1\n" ".word 0x71280019\n" /* mtcr $8, $9 */ ".set pop\n" : : "r" (value), "r" (reg) : "$8", "$9" ); } #else /* !(defined(__mips_n64) || defined(__mips_n32)) */ static __inline__ uint64_t nlm_mfcr(uint32_t reg) { uint32_t hi, lo; __asm__ __volatile__ ( ".set push\n" ".set mips64\n" "move $8, %2\n" ".word 0x71090018\n" "nop \n" "dsra32 %0, $9, 0\n" "sll %1, $9, 0\n" ".set pop\n" : "=r"(hi), "=r"(lo) : "r"(reg) : "$8", "$9"); return (((uint64_t)hi) << 32) | lo; } static __inline__ void nlm_mtcr(uint32_t reg, uint64_t val) { uint32_t hi, lo; hi = val >> 32; lo = val & 0xffffffff; __asm__ __volatile__ ( ".set push\n" ".set mips64\n" "move $9, %0\n" "dsll32 $9, %1, 0\n" "dsll32 $8, %0, 0\n" "dsrl32 $9, $9, 0\n" "or $9, $9, $8\n" "move $8, %2\n" ".word 0x71090019\n" "nop \n" ".set pop\n" : :"r"(hi), "r"(lo), "r"(reg) : "$8", "$9"); } #endif /* (defined(__mips_n64) || defined(__mips_n32)) */ /* hashindex_en = 1 to enable hash mode, hashindex_en=0 to disable * global_mode = 1 to enable global mode, global_mode=0 to disable * clk_gating = 0 to enable clock gating, clk_gating=1 to disable */ static __inline__ void nlm_mmu_setup(int hashindex_en, int global_mode, int clk_gating) { uint32_t mmusetup = 0; mmusetup |= (hashindex_en << 13); mmusetup |= (clk_gating << 3); mmusetup |= (global_mode << 0); nlm_mtcr(MMU_SETUP, mmusetup); } static __inline__ void nlm_mmu_lfsr_seed (int thr0_seed, int thr1_seed, int thr2_seed, int thr3_seed) { uint32_t seed = nlm_mfcr(MMU_LFSRSEED); seed |= ((thr3_seed & 0x7f) << 23); seed |= ((thr2_seed & 0x7f) << 16); seed |= ((thr1_seed & 0x7f) << 7); seed |= ((thr0_seed & 0x7f) << 0); nlm_mtcr(MMU_LFSRSEED, seed); } #endif /* __ASSEMBLY__ */ #endif /* __NLM_CPUCONTROL_H__ */ Index: head/sys/mips/nlm/hal/fmn.c =================================================================== --- head/sys/mips/nlm/hal/fmn.c (revision 326258) +++ head/sys/mips/nlm/hal/fmn.c (revision 326259) @@ -1,354 +1,356 @@ /*- + * 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 /* XLP can take upto 16K of FMN messages per hardware queue, as spill. * But, configuring all 16K causes the total spill memory to required * to blow upto 192MB for single chip configuration, and 768MB in four * chip configuration. Hence for now, we will setup the per queue spill * as 1K FMN messages. With this, the total spill memory needed for 1024 * hardware queues (with 12bytes per single entry FMN message) becomes * (1*1024)*12*1024queues = 12MB. For the four chip config, the memory * needed = 12 * 4 = 48MB. */ uint64_t nlm_cms_spill_total_messages = 1 * 1024; /* On a XLP832, we have the following FMN stations: * CPU stations: 8 * PCIE0 stations: 1 * PCIE1 stations: 1 * PCIE2 stations: 1 * PCIE3 stations: 1 * GDX stations: 1 * CRYPTO stations: 1 * RSA stations: 1 * CMP stations: 1 * POE stations: 1 * NAE stations: 1 * ================== * Total : 18 stations per chip * * For all 4 nodes, there are 18*4 = 72 FMN stations */ uint32_t nlm_cms_total_stations = 18 * 4 /*xlp_num_nodes*/; /** * Takes inputs as node, queue_size and maximum number of queues. * Calculates the base, start & end and returns the same for a * defined qid. * * The output queues are maintained in the internal output buffer * which is a on-chip SRAM structure. For the actial hardware * internal implementation, It is a structure which consists * of eight banks of 4096-entry x message-width SRAMs. The SRAM * implementation is designed to run at 1GHz with a 1-cycle read/write * access. A read/write transaction can be initiated for each bank * every cycle for a total of eight accesses per cycle. Successive * entries of the same output queue are placed in successive banks. * This is done to spread different read & write accesses to same/different * output queue over as many different banks as possible so that they * can be scheduled concurrently. Spreading the accesses to as many banks * as possible to maximize the concurrency internally is important for * achieving the desired peak throughput. This is done by h/w implementation * itself. * * Output queues are allocated from this internal output buffer by * software. The total capacity of the output buffer is 32K-entry. * Each output queue can be sized from 32-entry to 1024-entry in * increments of 32-entry. This is done by specifying a Start & a * End pointer: pointers to the first & last 32-entry chunks allocated * to the output queue. * * To optimize the storage required for 1024 OQ pointers, the upper 5-bits * are shared by the Start & the End pointer. The side-effect of this * optimization is that an OQ can't cross a 1024-entry boundary. Also, the * lower 5-bits don't need to be specified in the Start & the End pointer * as the allocation is in increments of 32-entries. * * Queue occupancy is tracked by a Head & a Tail pointer. Tail pointer * indicates the location to which next entry will be written & Head * pointer indicates the location from which next entry will be read. When * these pointers reach the top of the allocated space (indicated by the * End pointer), they are reset to the bottom of the allocated space * (indicated by the Start pointer). * * Output queue pointer information: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * 14 10 9 5 4 0 * ------------------ * | base ptr | * ------------------ * ---------------- * | start ptr | * ---------------- * ---------------- * | end ptr | * ---------------- * ------------------------------------ * | head ptr | * ------------------------------------ * ------------------------------------ * | tail ptr | * ------------------------------------ * Note: * A total of 1024 segments can sit on one software-visible "bank" * of internal SRAM. Each segment contains 32 entries. Also note * that sw-visible "banks" are not the same as the actual internal * 8-bank implementation of hardware. It is an optimization of * internal access. * */ void nlm_cms_setup_credits(uint64_t base, int destid, int srcid, int credit) { uint64_t val; val = (((uint64_t)credit << 24) | (destid << 12) | (srcid << 0)); nlm_write_cms_reg(base, CMS_OUTPUTQ_CREDIT_CFG, val); } /* * base - CMS module base address for this node. * qid - is the output queue id otherwise called as vc id * spill_base - is the 40-bit physical address of spill memory. Must be 4KB aligned. * nsegs - No of segments where a "1" indicates 4KB. Spill size must be * a multiple of 4KB. */ int nlm_cms_alloc_spill_q(uint64_t base, int qid, uint64_t spill_base, int nsegs) { uint64_t queue_config; uint32_t spill_start; if (nsegs > CMS_MAX_SPILL_SEGMENTS_PER_QUEUE) { return 1; } queue_config = nlm_read_cms_reg(base,(CMS_OUTPUTQ_CONFIG(qid))); spill_start = ((spill_base >> 12) & 0x3F); /* Spill configuration */ queue_config = (((uint64_t)CMS_SPILL_ENA << 62) | (((spill_base >> 18) & 0x3FFFFF) << 27) | (spill_start + nsegs - 1) << 21 | (spill_start << 15)); nlm_write_cms_reg(base,(CMS_OUTPUTQ_CONFIG(qid)),queue_config); return 0; } uint64_t nlm_cms_get_onchip_queue (uint64_t base, int qid) { return nlm_read_cms_reg(base, CMS_OUTPUTQ_CONFIG(qid)); } void nlm_cms_set_onchip_queue (uint64_t base, int qid, uint64_t val) { uint64_t rdval; rdval = nlm_read_cms_reg(base, CMS_OUTPUTQ_CONFIG(qid)); rdval |= val; nlm_write_cms_reg(base, CMS_OUTPUTQ_CONFIG(qid), rdval); } void nlm_cms_per_queue_level_intr(uint64_t base, int qid, int sub_type, int intr_val) { uint64_t val; val = nlm_read_cms_reg(base, CMS_OUTPUTQ_CONFIG(qid)); val &= ~((0x7ULL << 56) | (0x3ULL << 54)); val |= (((uint64_t)sub_type<<54) | ((uint64_t)intr_val<<56)); nlm_write_cms_reg(base, CMS_OUTPUTQ_CONFIG(qid), val); } void nlm_cms_per_queue_timer_intr(uint64_t base, int qid, int sub_type, int intr_val) { uint64_t val; val = nlm_read_cms_reg(base, CMS_OUTPUTQ_CONFIG(qid)); val &= ~((0x7ULL << 51) | (0x3ULL << 49)); val |= (((uint64_t)sub_type<<49) | ((uint64_t)intr_val<<51)); nlm_write_cms_reg(base, CMS_OUTPUTQ_CONFIG(qid), val); } /* returns 1 if interrupt has been generated for this output queue */ int nlm_cms_outputq_intr_check(uint64_t base, int qid) { uint64_t val; val = nlm_read_cms_reg(base, CMS_OUTPUTQ_CONFIG(qid)); return ((val >> 59) & 0x1); } void nlm_cms_outputq_clr_intr(uint64_t base, int qid) { uint64_t val; val = nlm_read_cms_reg(base, CMS_OUTPUTQ_CONFIG(qid)); val |= (1ULL<<59); nlm_write_cms_reg(base, CMS_OUTPUTQ_CONFIG(qid), val); } void nlm_cms_illegal_dst_error_intr(uint64_t base, int en) { uint64_t val; val = nlm_read_cms_reg(base, CMS_MSG_CONFIG); val |= (en<<8); nlm_write_cms_reg(base, CMS_MSG_CONFIG, val); } void nlm_cms_timeout_error_intr(uint64_t base, int en) { uint64_t val; val = nlm_read_cms_reg(base, CMS_MSG_CONFIG); val |= (en<<7); nlm_write_cms_reg(base, CMS_MSG_CONFIG, val); } void nlm_cms_biu_error_resp_intr(uint64_t base, int en) { uint64_t val; val = nlm_read_cms_reg(base, CMS_MSG_CONFIG); val |= (en<<6); nlm_write_cms_reg(base, CMS_MSG_CONFIG, val); } void nlm_cms_spill_uncorrectable_ecc_error_intr(uint64_t base, int en) { uint64_t val; val = nlm_read_cms_reg(base, CMS_MSG_CONFIG); val |= (en<<5) | (en<<3); nlm_write_cms_reg(base, CMS_MSG_CONFIG, val); } void nlm_cms_spill_correctable_ecc_error_intr(uint64_t base, int en) { uint64_t val; val = nlm_read_cms_reg(base, CMS_MSG_CONFIG); val |= (en<<4) | (en<<2); nlm_write_cms_reg(base, CMS_MSG_CONFIG, val); } void nlm_cms_outputq_uncorrectable_ecc_error_intr(uint64_t base, int en) { uint64_t val; val = nlm_read_cms_reg(base, CMS_MSG_CONFIG); val |= (en<<1); nlm_write_cms_reg(base, CMS_MSG_CONFIG, val); } void nlm_cms_outputq_correctable_ecc_error_intr(uint64_t base, int en) { uint64_t val; val = nlm_read_cms_reg(base, CMS_MSG_CONFIG); val |= (en<<0); nlm_write_cms_reg(base, CMS_MSG_CONFIG, val); } uint64_t nlm_cms_network_error_status(uint64_t base) { return nlm_read_cms_reg(base, CMS_MSG_ERR); } int nlm_cms_get_net_error_code(uint64_t err) { return ((err >> 12) & 0xf); } int nlm_cms_get_net_error_syndrome(uint64_t err) { return ((err >> 32) & 0x1ff); } int nlm_cms_get_net_error_ramindex(uint64_t err) { return ((err >> 44) & 0x7fff); } int nlm_cms_get_net_error_outputq(uint64_t err) { return ((err >> 16) & 0xfff); } /*========================= FMN Tracing related APIs ================*/ void nlm_cms_trace_setup(uint64_t base, int en, uint64_t trace_base, uint64_t trace_limit, int match_dstid_en, int dst_id, int match_srcid_en, int src_id, int wrap) { uint64_t val; nlm_write_cms_reg(base, CMS_TRACE_BASE_ADDR, trace_base); nlm_write_cms_reg(base, CMS_TRACE_LIMIT_ADDR, trace_limit); val = nlm_read_cms_reg(base, CMS_TRACE_CONFIG); val |= (((uint64_t)match_dstid_en << 39) | ((dst_id & 0xfff) << 24) | (match_srcid_en << 23) | ((src_id & 0xfff) << 8) | (wrap << 1) | (en << 0)); nlm_write_cms_reg(base, CMS_MSG_CONFIG, val); } void nlm_cms_endian_byte_swap (uint64_t base, int en) { nlm_write_cms_reg(base, CMS_MSG_ENDIAN_SWAP, en); } Index: head/sys/mips/nlm/hal/fmn.h =================================================================== --- head/sys/mips/nlm/hal/fmn.h (revision 326258) +++ head/sys/mips/nlm/hal/fmn.h (revision 326259) @@ -1,245 +1,247 @@ /*- + * 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 * $FreeBSD$ */ #ifndef __NLM_FMNV2_H__ #define __NLM_FMNV2_H__ /** * @file_name fmn.h * @author Netlogic Microsystems * @brief HAL for Fast message network V2 */ /* FMN configuration registers */ #define CMS_OUTPUTQ_CONFIG(i) ((i)*2) #define CMS_MAX_OUTPUTQ 1024 #define CMS_OUTPUTQ_CREDIT_CFG (0x2000/4) #define CMS_MSG_CONFIG (0x2008/4) #define CMS_MSG_ERR (0x2010/4) #define CMS_TRACE_CONFIG (0x2018/4) #define CMS_TRACE_BASE_ADDR (0x2020/4) #define CMS_TRACE_LIMIT_ADDR (0x2028/4) #define CMS_TRACE_CURRENT_ADDR (0x2030/4) #define CMS_MSG_ENDIAN_SWAP (0x2038/4) #define CMS_CPU_PUSHQ(node, core, thread, vc) \ (((node)<<10) | ((core)<<4) | ((thread)<<2) | ((vc)<<0)) #define CMS_POPQ(node, queue) (((node)<<10) | (queue)) #define CMS_IO_PUSHQ(node, queue) (((node)<<10) | (queue)) #define CMS_POPQ_QID(i) (128+(i)) /* FMN Level Interrupt Type */ #define CMS_LVL_INTR_DISABLE 0 #define CMS_LVL_LOW_WATERMARK 1 #define CMS_LVL_HI_WATERMARK 2 /* FMN Level interrupt trigger values */ #define CMS_QUEUE_NON_EMPTY 0 #define CMS_QUEUE_QUARTER_FULL 1 #define CMS_QUEUE_HALF_FULL 2 #define CMS_QUEUE_THREE_QUARTER_FULL 3 #define CMS_QUEUE_FULL 4 /* FMN Timer Interrupt Type */ #define CMS_TIMER_INTR_DISABLE 0 #define CMS_TIMER_CONSUMER 1 #define CMS_TIMER_PRODUCER 1 /* FMN timer interrupt trigger values */ #define CMS_TWO_POW_EIGHT_CYCLES 0 #define CMS_TWO_POW_TEN_CYCLES 1 #define CMS_TWO_POW_TWELVE_CYCLES 2 #define CMS_TWO_POW_FOURTEEN_CYCLES 3 #define CMS_TWO_POW_SIXTEEN_CYCLES 4 #define CMS_TWO_POW_EIGHTTEEN_CYCLES 5 #define CMS_TWO_POW_TWENTY_CYCLES 6 #define CMS_TWO_POW_TWENTYTWO_CYCLES 7 #define CMS_QUEUE_ENA 1ULL #define CMS_QUEUE_DIS 0 #define CMS_SPILL_ENA 1ULL #define CMS_SPILL_DIS 0 #define CMS_MAX_VCPU_VC 4 /* Each XLP chip can hold upto 32K messages on the chip itself */ #define CMS_ON_CHIP_MESG_SPACE (32*1024) #define CMS_MAX_ONCHIP_SEGMENTS 1024 #define CMS_MAX_SPILL_SEGMENTS_PER_QUEUE 64 /* FMN Network error */ #define CMS_ILLEGAL_DST_ERROR 0x100 #define CMS_BIU_TIMEOUT_ERROR 0x080 #define CMS_BIU_ERROR 0x040 #define CMS_SPILL_FILL_UNCORRECT_ECC_ERROR 0x020 #define CMS_SPILL_FILL_CORRECT_ECC_ERROR 0x010 #define CMS_SPILL_UNCORRECT_ECC_ERROR 0x008 #define CMS_SPILL_CORRECT_ECC_ERROR 0x004 #define CMS_OUTPUTQ_UNCORRECT_ECC_ERROR 0x002 #define CMS_OUTPUTQ_CORRECT_ECC_ERROR 0x001 /* worst case, a single entry message consists of a 4 byte header * and an 8-byte entry = 12 bytes in total */ #define CMS_SINGLE_ENTRY_MSG_SIZE 12 /* total spill memory needed for one FMN queue */ #define CMS_PER_QUEUE_SPILL_MEM(spilltotmsgs) \ ((spilltotmsgs) * (CMS_SINGLE_ENTRY_MSG_SIZE)) /* FMN Src station id's */ #define CMS_CPU0_SRC_STID (0 << 4) #define CMS_CPU1_SRC_STID (1 << 4) #define CMS_CPU2_SRC_STID (2 << 4) #define CMS_CPU3_SRC_STID (3 << 4) #define CMS_CPU4_SRC_STID (4 << 4) #define CMS_CPU5_SRC_STID (5 << 4) #define CMS_CPU6_SRC_STID (6 << 4) #define CMS_CPU7_SRC_STID (7 << 4) #define CMS_PCIE0_SRC_STID 256 #define CMS_PCIE1_SRC_STID 258 #define CMS_PCIE2_SRC_STID 260 #define CMS_PCIE3_SRC_STID 262 #define CMS_DTE_SRC_STID 264 #define CMS_RSA_ECC_SRC_STID 272 #define CMS_CRYPTO_SRC_STID 281 #define CMS_CMP_SRC_STID 298 #define CMS_POE_SRC_STID 384 #define CMS_NAE_SRC_STID 476 /* POPQ related defines */ #define CMS_POPQID_START 128 #define CMS_POPQID_END 255 #define CMS_INT_RCVD 0x800000000000000ULL #define nlm_read_cms_reg(b, r) nlm_read_reg64_xkphys(b,r) #define nlm_write_cms_reg(b, r, v) nlm_write_reg64_xkphys(b,r,v) #define nlm_get_cms_pcibase(node) \ nlm_pcicfg_base(XLP_IO_CMS_OFFSET(node)) #define nlm_get_cms_regbase(node) \ nlm_xkphys_map_pcibar0(nlm_get_cms_pcibase(node)) #define XLP_CMS_ON_CHIP_PER_QUEUE_SPACE(node) \ ((XLP_CMS_ON_CHIP_MESG_SPACE)/ \ (nlm_read_reg(nlm_pcibase_cms(node), \ XLP_PCI_DEVINFO_REG0)) /* total spill memory needed */ #define XLP_CMS_TOTAL_SPILL_MEM(node, spilltotmsgs) \ ((XLP_CMS_PER_QUEUE_SPILL_MEM(spilltotmsgs)) * \ (nlm_read_reg(nlm_pcibase_cms(node), \ XLP_PCI_DEVINFO_REG0)) #define CMS_TOTAL_QUEUE_SIZE(node, spilltotmsgs) \ ((spilltotmsgs) + (CMS_ON_CHIP_PER_QUEUE_SPACE(node))) enum fmn_swcode { FMN_SWCODE_CPU0=1, FMN_SWCODE_CPU1, FMN_SWCODE_CPU2, FMN_SWCODE_CPU3, FMN_SWCODE_CPU4, FMN_SWCODE_CPU5, FMN_SWCODE_CPU6, FMN_SWCODE_CPU7, FMN_SWCODE_CPU8, FMN_SWCODE_CPU9, FMN_SWCODE_CPU10, FMN_SWCODE_CPU11, FMN_SWCODE_CPU12, FMN_SWCODE_CPU13, FMN_SWCODE_CPU14, FMN_SWCODE_CPU15, FMN_SWCODE_CPU16, FMN_SWCODE_CPU17, FMN_SWCODE_CPU18, FMN_SWCODE_CPU19, FMN_SWCODE_CPU20, FMN_SWCODE_CPU21, FMN_SWCODE_CPU22, FMN_SWCODE_CPU23, FMN_SWCODE_CPU24, FMN_SWCODE_CPU25, FMN_SWCODE_CPU26, FMN_SWCODE_CPU27, FMN_SWCODE_CPU28, FMN_SWCODE_CPU29, FMN_SWCODE_CPU30, FMN_SWCODE_CPU31, FMN_SWCODE_CPU32, FMN_SWCODE_PCIE0, FMN_SWCODE_PCIE1, FMN_SWCODE_PCIE2, FMN_SWCODE_PCIE3, FMN_SWCODE_DTE, FMN_SWCODE_CRYPTO, FMN_SWCODE_RSA, FMN_SWCODE_CMP, FMN_SWCODE_POE, FMN_SWCODE_NAE, }; extern uint64_t nlm_cms_spill_total_messages; extern uint32_t nlm_cms_total_stations; extern uint64_t cms_base_addr(int node); extern int nlm_cms_verify_credit_config (int spill_en, int tot_credit); extern int nlm_cms_get_oc_space(int qsize, int max_queues, int qid, int *ocbase, int *ocstart, int *ocend); extern void nlm_cms_setup_credits (uint64_t base, int destid, int srcid, int credit); extern int nlm_cms_config_onchip_queue (uint64_t base, uint64_t cms_spill_base, int qid, int spill_en); extern void nlm_cms_default_setup(int node, uint64_t spill_base, int spill_en, int popq_en); extern uint64_t nlm_cms_get_onchip_queue (uint64_t base, int qid); extern void nlm_cms_set_onchip_queue (uint64_t base, int qid, uint64_t val); extern void nlm_cms_per_queue_level_intr(uint64_t base, int qid, int sub_type, int intr_val); extern void nlm_cms_level_intr(int node, int sub_type, int intr_val); extern void nlm_cms_per_queue_timer_intr(uint64_t base, int qid, int sub_type, int intr_val); extern void nlm_cms_timer_intr(int node, int en, int sub_type, int intr_val); extern int nlm_cms_outputq_intr_check(uint64_t base, int qid); extern void nlm_cms_outputq_clr_intr(uint64_t base, int qid); extern void nlm_cms_illegal_dst_error_intr(uint64_t base, int en); extern void nlm_cms_timeout_error_intr(uint64_t base, int en); extern void nlm_cms_biu_error_resp_intr(uint64_t base, int en); extern void nlm_cms_spill_uncorrectable_ecc_error_intr(uint64_t base, int en); extern void nlm_cms_spill_correctable_ecc_error_intr(uint64_t base, int en); extern void nlm_cms_outputq_uncorrectable_ecc_error_intr(uint64_t base, int en); extern void nlm_cms_outputq_correctable_ecc_error_intr(uint64_t base, int en); extern uint64_t nlm_cms_network_error_status(uint64_t base); extern int nlm_cms_get_net_error_code(uint64_t err); extern int nlm_cms_get_net_error_syndrome(uint64_t err); extern int nlm_cms_get_net_error_ramindex(uint64_t err); extern int nlm_cms_get_net_error_outputq(uint64_t err); extern void nlm_cms_trace_setup(uint64_t base, int en, uint64_t trace_base, uint64_t trace_limit, int match_dstid_en, int dst_id, int match_srcid_en, int src_id, int wrap); extern void nlm_cms_endian_byte_swap (uint64_t base, int en); extern uint8_t xlp_msg_send(uint8_t vc, uint8_t size); extern int nlm_cms_alloc_spill_q(uint64_t base, int qid, uint64_t spill_base, int nsegs); extern int nlm_cms_alloc_onchip_q(uint64_t base, int qid, int nsegs); #endif Index: head/sys/mips/nlm/hal/gbu.h =================================================================== --- head/sys/mips/nlm/hal/gbu.h (revision 326258) +++ head/sys/mips/nlm/hal/gbu.h (revision 326259) @@ -1,100 +1,102 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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$ */ #ifndef _NLM_HAL_GBU_H__ #define _NLM_HAL_GBU_H__ /* Global Bus Unit (GBU) for flash Specific registers */ #define GBU_CS_BASEADDR(cs) (0x0+cs) #define GBU_CS0_BASEADDR 0x0 #define GBU_CS1_BASEADDR 0x1 #define GBU_CS2_BASEADDR 0x2 #define GBU_CS3_BASEADDR 0x3 #define GBU_CS4_BASEADDR 0x4 #define GBU_CS5_BASEADDR 0x5 #define GBU_CS6_BASEADDR 0x6 #define GBU_CS7_BASEADDR 0x7 #define GBU_CS_BASELIMIT(cs) (0x8+cs) #define GBU_CS0_BASELIMIT 0x8 #define GBU_CS1_BASELIMIT 0x9 #define GBU_CS2_BASELIMIT 0xa #define GBU_CS3_BASELIMIT 0xb #define GBU_CS4_BASELIMIT 0xc #define GBU_CS5_BASELIMIT 0xd #define GBU_CS6_BASELIMIT 0xe #define GBU_CS7_BASELIMIT 0xf #define GBU_CS_DEVPARAM(cs) (0x10+cs) #define GBU_CS0_DEVPARAM 0x10 #define GBU_CS1_DEVPARAM 0x11 #define GBU_CS2_DEVPARAM 0x12 #define GBU_CS3_DEVPARAM 0x13 #define GBU_CS4_DEVPARAM 0x14 #define GBU_CS5_DEVPARAM 0x15 #define GBU_CS6_DEVPARAM 0x16 #define GBU_CS7_DEVPARAM 0x17 #define GBU_CS_DEVTIME0(cs) (0x18+cs) #define GBU_CS0_DEVTIME0 0x18 #define GBU_CS1_DEVTIME0 0x1a #define GBU_CS2_DEVTIME0 0x1c #define GBU_CS3_DEVTIME0 0x1e #define GBU_CS4_DEVTIME0 0x20 #define GBU_CS5_DEVTIME0 0x22 #define GBU_CS6_DEVTIME0 0x24 #define GBU_CS7_DEVTIME0 0x26 #define GBU_CS_DEVTIME1(cs) (0x19+cs) #define GBU_CS0_DEVTIME1 0x19 #define GBU_CS1_DEVTIME1 0x1b #define GBU_CS2_DEVTIME1 0x1d #define GBU_CS3_DEVTIME1 0x1f #define GBU_CS4_DEVTIME1 0x21 #define GBU_CS5_DEVTIME1 0x23 #define GBU_CS6_DEVTIME1 0x25 #define GBU_CS7_DEVTIME1 0x27 #define GBU_SYSCTRL 0x28 #define GBU_BYTESWAP 0x29 #define GBU_DI_TIMEOUT_VAL 0x2d #define GBU_INTSTAT 0x2e #define GBU_INTEN 0x2f #define GBU_STATUS 0x30 #define GBU_ERRLOG0 0x2a #define GBU_ERRLOG1 0x2b #define GBU_ERRLOG2 0x2c #if !defined(LOCORE) && !defined(__ASSEMBLY__) #define nlm_read_gbu_reg(b, r) nlm_read_reg(b, r) #define nlm_write_gbu_reg(b, r, v) nlm_write_reg(b, r, v) #define nlm_get_gbu_pcibase(node) \ nlm_pcicfg_base(XLP_IO_NOR_OFFSET(node)) #define nlm_get_gbu_regbase(node) \ (nlm_get_gbu_pcibase(node) + XLP_IO_PCI_HDRSZ) #endif /* !LOCORE && !__ASSEMBLY__ */ #endif /* _NLM_HAL_GBU_H__ */ Index: head/sys/mips/nlm/hal/haldefs.h =================================================================== --- head/sys/mips/nlm/hal/haldefs.h (revision 326258) +++ head/sys/mips/nlm/hal/haldefs.h (revision 326259) @@ -1,437 +1,439 @@ /*- + * 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 * $FreeBSD$ */ #ifndef __NLM_HAL_MMIO_H__ #define __NLM_HAL_MMIO_H__ /* * This file contains platform specific memory mapped IO implementation * and will provide a way to read 32/64 bit memory mapped registers in * all ABIs */ /* * For o32 compilation, we have to disable interrupts and enable KX bit to * access 64 bit addresses or data. * * We need to disable interrupts because we save just the lower 32 bits of * registers in interrupt handling. So if we get hit by an interrupt while * using the upper 32 bits of a register, we lose. */ static inline uint32_t nlm_save_flags_kx(void) { uint32_t sr = mips_rd_status(); mips_wr_status((sr & ~MIPS_SR_INT_IE) | MIPS_SR_KX); return (sr); } static inline uint32_t nlm_save_flags_cop2(void) { uint32_t sr = mips_rd_status(); mips_wr_status((sr & ~MIPS_SR_INT_IE) | MIPS_SR_COP_2_BIT); return (sr); } static inline void nlm_restore_flags(uint32_t sr) { mips_wr_status(sr); } static inline uint32_t nlm_load_word(uint64_t addr) { volatile uint32_t *p = (volatile uint32_t *)(long)addr; return *p; } static inline void nlm_store_word(uint64_t addr, uint32_t val) { volatile uint32_t *p = (volatile uint32_t *)(long)addr; *p = val; } #if defined(__mips_n64) || defined(__mips_n32) static inline uint64_t nlm_load_dword(volatile uint64_t addr) { volatile uint64_t *p = (volatile uint64_t *)(long)addr; return *p; } static inline void nlm_store_dword(volatile uint64_t addr, uint64_t val) { volatile uint64_t *p = (volatile uint64_t *)(long)addr; *p = val; } #else /* o32 */ static inline uint64_t nlm_load_dword(uint64_t addr) { volatile uint64_t *p = (volatile uint64_t *)(long)addr; uint32_t valhi, vallo, sr; sr = nlm_save_flags_kx(); __asm__ __volatile__( ".set push\n\t" ".set mips64\n\t" "ld $8, 0(%2)\n\t" "dsra32 %0, $8, 0\n\t" "sll %1, $8, 0\n\t" ".set pop\n" : "=r"(valhi), "=r"(vallo) : "r"(p) : "$8"); nlm_restore_flags(sr); return ((uint64_t)valhi << 32) | vallo; } static inline void nlm_store_dword(uint64_t addr, uint64_t val) { volatile uint64_t *p = (volatile uint64_t *)(long)addr; uint32_t valhi, vallo, sr; valhi = val >> 32; vallo = val & 0xffffffff; sr = nlm_save_flags_kx(); __asm__ __volatile__( ".set push\n\t" ".set mips64\n\t" "dsll32 $8, %1, 0\n\t" "dsll32 $9, %2, 0\n\t" /* get rid of the */ "dsrl32 $9, $9, 0\n\t" /* sign extend */ "or $9, $9, $8\n\t" "sd $9, 0(%0)\n\t" ".set pop\n" : : "r"(p), "r"(valhi), "r"(vallo) : "$8", "$9", "memory"); nlm_restore_flags(sr); } #endif #if defined(__mips_n64) static inline uint64_t nlm_load_word_daddr(uint64_t addr) { volatile uint32_t *p = (volatile uint32_t *)(long)addr; return *p; } static inline void nlm_store_word_daddr(uint64_t addr, uint32_t val) { volatile uint32_t *p = (volatile uint32_t *)(long)addr; *p = val; } static inline uint64_t nlm_load_dword_daddr(uint64_t addr) { volatile uint64_t *p = (volatile uint64_t *)(long)addr; return *p; } static inline void nlm_store_dword_daddr(uint64_t addr, uint64_t val) { volatile uint64_t *p = (volatile uint64_t *)(long)addr; *p = val; } #elif defined(__mips_n32) static inline uint64_t nlm_load_word_daddr(uint64_t addr) { uint32_t val; __asm__ __volatile__( ".set push\n\t" ".set mips64\n\t" "lw %0, 0(%1)\n\t" ".set pop\n" : "=r"(val) : "r"(addr)); return val; } static inline void nlm_store_word_daddr(uint64_t addr, uint32_t val) { __asm__ __volatile__( ".set push\n\t" ".set mips64\n\t" "sw %0, 0(%1)\n\t" ".set pop\n" : : "r"(val), "r"(addr) : "memory"); } static inline uint64_t nlm_load_dword_daddr(uint64_t addr) { uint64_t val; __asm__ __volatile__( ".set push\n\t" ".set mips64\n\t" "ld %0, 0(%1)\n\t" ".set pop\n" : "=r"(val) : "r"(addr)); return val; } static inline void nlm_store_dword_daddr(uint64_t addr, uint64_t val) { __asm__ __volatile__( ".set push\n\t" ".set mips64\n\t" "sd %0, 0(%1)\n\t" ".set pop\n" : : "r"(val), "r"(addr) : "memory"); } #else /* o32 */ static inline uint64_t nlm_load_word_daddr(uint64_t addr) { uint32_t val, addrhi, addrlo, sr; addrhi = addr >> 32; addrlo = addr & 0xffffffff; sr = nlm_save_flags_kx(); __asm__ __volatile__( ".set push\n\t" ".set mips64\n\t" "dsll32 $8, %1, 0\n\t" "dsll32 $9, %2, 0\n\t" "dsrl32 $9, $9, 0\n\t" "or $9, $9, $8\n\t" "lw %0, 0($9)\n\t" ".set pop\n" : "=r"(val) : "r"(addrhi), "r"(addrlo) : "$8", "$9"); nlm_restore_flags(sr); return val; } static inline void nlm_store_word_daddr(uint64_t addr, uint32_t val) { uint32_t addrhi, addrlo, sr; addrhi = addr >> 32; addrlo = addr & 0xffffffff; sr = nlm_save_flags_kx(); __asm__ __volatile__( ".set push\n\t" ".set mips64\n\t" "dsll32 $8, %1, 0\n\t" "dsll32 $9, %2, 0\n\t" "dsrl32 $9, $9, 0\n\t" "or $9, $9, $8\n\t" "sw %0, 0($9)\n\t" ".set pop\n" : : "r"(val), "r"(addrhi), "r"(addrlo) : "$8", "$9", "memory"); nlm_restore_flags(sr); } static inline uint64_t nlm_load_dword_daddr(uint64_t addr) { uint32_t addrh, addrl, sr; uint32_t valh, vall; addrh = addr >> 32; addrl = addr & 0xffffffff; sr = nlm_save_flags_kx(); __asm__ __volatile__( ".set push\n\t" ".set mips64\n\t" "dsll32 $8, %2, 0\n\t" "dsll32 $9, %3, 0\n\t" "dsrl32 $9, $9, 0\n\t" "or $9, $9, $8\n\t" "ld $8, 0($9)\n\t" "dsra32 %0, $8, 0\n\t" "sll %1, $8, 0\n\t" ".set pop\n" : "=r"(valh), "=r"(vall) : "r"(addrh), "r"(addrl) : "$8", "$9"); nlm_restore_flags(sr); return ((uint64_t)valh << 32) | vall; } static inline void nlm_store_dword_daddr(uint64_t addr, uint64_t val) { uint32_t addrh, addrl, sr; uint32_t valh, vall; addrh = addr >> 32; addrl = addr & 0xffffffff; valh = val >> 32; vall = val & 0xffffffff; sr = nlm_save_flags_kx(); __asm__ __volatile__( ".set push\n\t" ".set mips64\n\t" "dsll32 $8, %2, 0\n\t" "dsll32 $9, %3, 0\n\t" "dsrl32 $9, $9, 0\n\t" "or $9, $9, $8\n\t" "dsll32 $8, %0, 0\n\t" "dsll32 $10, %1, 0\n\t" "dsrl32 $10, $10, 0\n\t" "or $8, $8, $10\n\t" "sd $8, 0($9)\n\t" ".set pop\n" : : "r"(valh), "r"(vall), "r"(addrh), "r"(addrl) : "$8", "$9", "memory"); nlm_restore_flags(sr); } #endif /* __mips_n64 */ static inline uint32_t nlm_read_reg(uint64_t base, uint32_t reg) { volatile uint32_t *addr = (volatile uint32_t *)(long)base + reg; return *addr; } static inline void nlm_write_reg(uint64_t base, uint32_t reg, uint32_t val) { volatile uint32_t *addr = (volatile uint32_t *)(long)base + reg; *addr = val; } static inline uint64_t nlm_read_reg64(uint64_t base, uint32_t reg) { uint64_t addr = base + (reg >> 1) * sizeof(uint64_t); return nlm_load_dword(addr); } static inline void nlm_write_reg64(uint64_t base, uint32_t reg, uint64_t val) { uint64_t addr = base + (reg >> 1) * sizeof(uint64_t); return nlm_store_dword(addr, val); } /* * Routines to store 32/64 bit values to 64 bit addresses, * used when going thru XKPHYS to access registers */ static inline uint32_t nlm_read_reg_xkphys(uint64_t base, uint32_t reg) { uint64_t addr = base + reg * sizeof(uint32_t); return nlm_load_word_daddr(addr); } static inline void nlm_write_reg_xkphys(uint64_t base, uint32_t reg, uint32_t val) { uint64_t addr = base + reg * sizeof(uint32_t); return nlm_store_word_daddr(addr, val); } static inline uint64_t nlm_read_reg64_xkphys(uint64_t base, uint32_t reg) { uint64_t addr = base + (reg >> 1) * sizeof(uint64_t); return nlm_load_dword_daddr(addr); } static inline void nlm_write_reg64_xkphys(uint64_t base, uint32_t reg, uint64_t val) { uint64_t addr = base + (reg >> 1) * sizeof(uint64_t); return nlm_store_dword_daddr(addr, val); } /* Location where IO base is mapped */ extern uint64_t xlp_io_base; static inline uint64_t nlm_pcicfg_base(uint32_t devoffset) { return xlp_io_base + devoffset; } static inline uint64_t nlm_xkphys_map_pcibar0(uint64_t pcibase) { uint64_t paddr; paddr = nlm_read_reg(pcibase, 0x4) & ~0xfu; return (uint64_t)0x9000000000000000 | paddr; } #endif Index: head/sys/mips/nlm/hal/interlaken.h =================================================================== --- head/sys/mips/nlm/hal/interlaken.h (revision 326258) +++ head/sys/mips/nlm/hal/interlaken.h (revision 326259) @@ -1,70 +1,72 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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$ */ #ifndef __NLM_ILAKEN_H__ #define __NLM_ILAKEN_H__ /** * @file_name interlaken.h * @author Netlogic Microsystems * @brief Basic definitions of XLP ILAKEN ports */ #define ILK_TX_CONTROL(block) NAE_REG(block, 5, 0x00) #define ILK_TX_RATE_LIMIT(block) NAE_REG(block, 5, 0x01) #define ILK_TX_META_CTRL(block) NAE_REG(block, 5, 0x02) #define ILK_RX_CTRL(block) NAE_REG(block, 5, 0x03) #define ILK_RX_STATUS1(block) NAE_REG(block, 5, 0x04) #define ILK_RX_STATUS2(block) NAE_REG(block, 5, 0x05) #define ILK_GENERAL_CTRL1(block) NAE_REG(block, 5, 0x06) #define ILK_STATUS3(block) NAE_REG(block, 5, 0x07) #define ILK_RX_FC_TMAP0(block) NAE_REG(block, 5, 0x08) #define ILK_RX_FC_TMAP1(block) NAE_REG(block, 5, 0x09) #define ILK_RX_FC_TMAP2(block) NAE_REG(block, 5, 0x0a) #define ILK_RX_FC_TMAP3(block) NAE_REG(block, 5, 0x0b) #define ILK_RX_FC_TMAP4(block) NAE_REG(block, 5, 0x0c) #define ILK_RX_FC_TADDR(block) NAE_REG(block, 5, 0x0d) #define ILK_GENERAL_CTRL2(block) NAE_REG(block, 5, 0x0e) #define ILK_GENERAL_CTRL3(block) NAE_REG(block, 5, 0x0f) #define ILK_SMALL_COUNT0(block) NAE_REG(block, 5, 0x10) #define ILK_SMALL_COUNT1(block) NAE_REG(block, 5, 0x11) #define ILK_SMALL_COUNT2(block) NAE_REG(block, 5, 0x12) #define ILK_SMALL_COUNT3(block) NAE_REG(block, 5, 0x13) #define ILK_SMALL_COUNT4(block) NAE_REG(block, 5, 0x14) #define ILK_SMALL_COUNT5(block) NAE_REG(block, 5, 0x15) #define ILK_SMALL_COUNT6(block) NAE_REG(block, 5, 0x16) #define ILK_SMALL_COUNT7(block) NAE_REG(block, 5, 0x17) #define ILK_MID_COUNT0(block) NAE_REG(block, 5, 0x18) #define ILK_MID_COUNT1(block) NAE_REG(block, 5, 0x19) #define ILK_LARGE_COUNT0(block) NAE_REG(block, 5, 0x1a) #define ILK_LARGE_COUNT1(block) NAE_REG(block, 5, 0x1b) #define ILK_LARGE_COUNT_H0(block) NAE_REG(block, 5, 0x1c) #define ILK_LARGE_COUNT_H1(block) NAE_REG(block, 5, 0x1d) #endif Index: head/sys/mips/nlm/hal/iomap.h =================================================================== --- head/sys/mips/nlm/hal/iomap.h (revision 326258) +++ head/sys/mips/nlm/hal/iomap.h (revision 326259) @@ -1,206 +1,208 @@ /*- + * 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 * $FreeBSD$ */ #ifndef __NLM_HAL_IOMAP_H__ #define __NLM_HAL_IOMAP_H__ #define XLP_DEFAULT_IO_BASE 0x18000000 #define NMI_BASE 0xbfc00000 #define XLP_IO_CLK 133333333 #define XLP_L2L3_CACHELINE_SIZE 64 #define XLP_PCIE_CFG_SIZE 0x1000 /* 4K */ #define XLP_PCIE_DEV_BLK_SIZE (8 * XLP_PCIE_CFG_SIZE) #define XLP_PCIE_BUS_BLK_SIZE (256 * XLP_PCIE_DEV_BLK_SIZE) #define XLP_IO_SIZE (64 << 20) /* ECFG space size */ #define XLP_IO_PCI_HDRSZ 0x100 #define XLP_IO_DEV(node, dev) ((dev) + (node) * 8) #define XLP_HDR_OFFSET(node, bus, dev, fn) (((bus) << 20) | \ ((XLP_IO_DEV(node, dev)) << 15) | ((fn) << 12)) #define XLP_IO_BRIDGE_OFFSET(node) XLP_HDR_OFFSET(node, 0, 0, 0) /* coherent inter chip */ #define XLP_IO_CIC0_OFFSET(node) XLP_HDR_OFFSET(node, 0, 0, 1) #define XLP_IO_CIC1_OFFSET(node) XLP_HDR_OFFSET(node, 0, 0, 2) #define XLP_IO_CIC2_OFFSET(node) XLP_HDR_OFFSET(node, 0, 0, 3) #define XLP_IO_PIC_OFFSET(node) XLP_HDR_OFFSET(node, 0, 0, 4) #define XLP_IO_PCIE_OFFSET(node, i) XLP_HDR_OFFSET(node, 0, 1, i) #define XLP_IO_PCIE0_OFFSET(node) XLP_HDR_OFFSET(node, 0, 1, 0) #define XLP_IO_PCIE1_OFFSET(node) XLP_HDR_OFFSET(node, 0, 1, 1) #define XLP_IO_PCIE2_OFFSET(node) XLP_HDR_OFFSET(node, 0, 1, 2) #define XLP_IO_PCIE3_OFFSET(node) XLP_HDR_OFFSET(node, 0, 1, 3) #define XLP_IO_USB_OFFSET(node, i) XLP_HDR_OFFSET(node, 0, 2, i) #define XLP_IO_USB_EHCI0_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 0) #define XLP_IO_USB_OHCI0_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 1) #define XLP_IO_USB_OHCI1_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 2) #define XLP_IO_USB_EHCI1_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 3) #define XLP_IO_USB_OHCI2_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 4) #define XLP_IO_USB_OHCI3_OFFSET(node) XLP_HDR_OFFSET(node, 0, 2, 5) #define XLP_IO_NAE_OFFSET(node) XLP_HDR_OFFSET(node, 0, 3, 0) #define XLP_IO_POE_OFFSET(node) XLP_HDR_OFFSET(node, 0, 3, 1) #define XLP_IO_SATA_OFFSET(node) XLP_HDR_OFFSET(node, 0, 3, 2) #define XLP_IO_CMS_OFFSET(node) XLP_HDR_OFFSET(node, 0, 4, 0) #define XLP_IO_DMA_OFFSET(node) XLP_HDR_OFFSET(node, 0, 5, 0) #define XLP_IO_SEC_OFFSET(node) XLP_HDR_OFFSET(node, 0, 5, 1) #define XLP_IO_RSA_OFFSET(node) XLP_HDR_OFFSET(node, 0, 5, 2) #define XLP_IO_CMP_OFFSET(node) XLP_HDR_OFFSET(node, 0, 5, 3) #define XLP_IO_SRIO_OFFSET(node) XLP_HDR_OFFSET(node, 0, 5, 4) #define XLP_IO_REGEX_OFFSET(node) XLP_HDR_OFFSET(node, 0, 5, 5) #define XLP_IO_UART_OFFSET(node, i) XLP_HDR_OFFSET(node, 0, 6, i) #define XLP_IO_UART0_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 0) #define XLP_IO_UART1_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 1) #define XLP_IO_I2C_OFFSET(node, i) XLP_HDR_OFFSET(node, 0, 6, 2 + i) #define XLP_IO_I2C0_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 2) #define XLP_IO_I2C1_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 3) #define XLP_IO_GPIO_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 4) /* system management */ #define XLP_IO_SYS_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 5) #define XLP_IO_JTAG_OFFSET(node) XLP_HDR_OFFSET(node, 0, 6, 6) #define XLP_IO_NOR_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 0) #define XLP_IO_NAND_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 1) #define XLP_IO_SPI_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 2) /* SD flash */ #define XLP_IO_SD_OFFSET(node) XLP_HDR_OFFSET(node, 0, 7, 3) #define XLP_IO_MMC_OFFSET(node, slot) \ ((XLP_IO_SD_OFFSET(node))+(slot*0x100)+XLP_IO_PCI_HDRSZ) /* PCI config header register id's */ #define XLP_PCI_CFGREG0 0x00 #define XLP_PCI_CFGREG1 0x01 #define XLP_PCI_CFGREG2 0x02 #define XLP_PCI_CFGREG3 0x03 #define XLP_PCI_CFGREG4 0x04 #define XLP_PCI_CFGREG5 0x05 #define XLP_PCI_DEVINFO_REG0 0x30 #define XLP_PCI_DEVINFO_REG1 0x31 #define XLP_PCI_DEVINFO_REG2 0x32 #define XLP_PCI_DEVINFO_REG3 0x33 #define XLP_PCI_DEVINFO_REG4 0x34 #define XLP_PCI_DEVINFO_REG5 0x35 #define XLP_PCI_DEVINFO_REG6 0x36 #define XLP_PCI_DEVINFO_REG7 0x37 #define XLP_PCI_DEVSCRATCH_REG0 0x38 #define XLP_PCI_DEVSCRATCH_REG1 0x39 #define XLP_PCI_DEVSCRATCH_REG2 0x3a #define XLP_PCI_DEVSCRATCH_REG3 0x3b #define XLP_PCI_MSGSTN_REG 0x3c #define XLP_PCI_IRTINFO_REG 0x3d #define XLP_PCI_UCODEINFO_REG 0x3e #define XLP_PCI_SBB_WT_REG 0x3f /* PCI IDs for SoC device */ #define PCI_VENDOR_NETLOGIC 0x184e #define PCI_DEVICE_ID_NLM_ROOT 0x1001 #define PCI_DEVICE_ID_NLM_ICI 0x1002 #define PCI_DEVICE_ID_NLM_PIC 0x1003 #define PCI_DEVICE_ID_NLM_PCIE 0x1004 #define PCI_DEVICE_ID_NLM_EHCI 0x1007 #define PCI_DEVICE_ID_NLM_ILK 0x1008 #define PCI_DEVICE_ID_NLM_NAE 0x1009 #define PCI_DEVICE_ID_NLM_POE 0x100A #define PCI_DEVICE_ID_NLM_FMN 0x100B #define PCI_DEVICE_ID_NLM_RAID 0x100D #define PCI_DEVICE_ID_NLM_SAE 0x100D #define PCI_DEVICE_ID_NLM_RSA 0x100E #define PCI_DEVICE_ID_NLM_CMP 0x100F #define PCI_DEVICE_ID_NLM_UART 0x1010 #define PCI_DEVICE_ID_NLM_I2C 0x1011 #define PCI_DEVICE_ID_NLM_NOR 0x1015 #define PCI_DEVICE_ID_NLM_NAND 0x1016 #define PCI_DEVICE_ID_NLM_MMC 0x1018 #if !defined(LOCORE) && !defined(__ASSEMBLY__) #define nlm_read_pci_reg(b, r) nlm_read_reg(b, r) #define nlm_write_pci_reg(b, r, v) nlm_write_reg(b, r, v) extern uint64_t xlp_sys_base; extern uint64_t xlp_pic_base; static __inline__ int nlm_dev_exists(uint32_t devoffset) { uint64_t pcibase = nlm_pcicfg_base(devoffset); return (nlm_read_reg(pcibase, XLP_PCI_CFGREG0) != 0xffffffff); } static __inline__ int nlm_qidstart(uint64_t pcibase) { return (nlm_read_reg(pcibase, XLP_PCI_MSGSTN_REG) & 0xffff); } static __inline__ int nlm_qnum(uint64_t pcibase) { return (nlm_read_reg(pcibase, XLP_PCI_MSGSTN_REG) >> 16); } static __inline__ int nlm_irtstart(uint64_t pcibase) { return (nlm_read_reg(pcibase, XLP_PCI_IRTINFO_REG) & 0xffff); } static __inline__ int nlm_irtnum(uint64_t pcibase) { return (nlm_read_reg(pcibase, XLP_PCI_IRTINFO_REG) >> 16); } static __inline__ int nlm_num_uengines(uint64_t pcibase) { return nlm_read_reg(pcibase, XLP_PCI_UCODEINFO_REG); } /* * Find node on which a given Soc device is located. * input is the pci device (slot) number. */ static __inline__ int nlm_get_device_node(int device) { return (device / 8); } #endif /* !LOCORE or !__ASSEMBLY */ #endif /* __NLM_HAL_IOMAP_H__ */ Index: head/sys/mips/nlm/hal/mdio.h =================================================================== --- head/sys/mips/nlm/hal/mdio.h (revision 326258) +++ head/sys/mips/nlm/hal/mdio.h (revision 326259) @@ -1,106 +1,108 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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$ */ #ifndef __NLM_MDIO_H__ #define __NLM_MDIO_H__ /** * @file_name mdio.h * @author Netlogic Microsystems * @brief Access functions for XLP MDIO */ #define INT_MDIO_CTRL 0x19 #define INT_MDIO_CTRL_DATA 0x1A #define INT_MDIO_RD_STAT 0x1B #define INT_MDIO_LINK_STAT 0x1C #define EXT_G0_MDIO_CTRL 0x1D #define EXT_G1_MDIO_CTRL 0x21 #define EXT_G0_MDIO_CTRL_DATA 0x1E #define EXT_G1_MDIO_CTRL_DATA 0x22 #define EXT_G0_MDIO_LINK_STAT 0x20 #define EXT_G1_MDIO_LINK_STAT 0x24 #define EXT_G0_MDIO_RD_STAT 0x1F #define EXT_G1_MDIO_RD_STAT 0x23 #define INT_MDIO_CTRL_ST_POS 0 #define INT_MDIO_CTRL_OP_POS 2 #define INT_MDIO_CTRL_PHYADDR_POS 4 #define INT_MDIO_CTRL_DEVTYPE_POS 9 #define INT_MDIO_CTRL_TA_POS 14 #define INT_MDIO_CTRL_MIIM_POS 16 #define INT_MDIO_CTRL_LOAD_POS 19 #define INT_MDIO_CTRL_XDIV_POS 21 #define INT_MDIO_CTRL_MCDIV_POS 28 #define INT_MDIO_CTRL_RST 0x40000000 #define INT_MDIO_CTRL_SMP 0x00100000 #define INT_MDIO_CTRL_CMD_LOAD 0x00080000 #define INT_MDIO_RD_STAT_MASK 0x0000FFFF #define INT_MDIO_STAT_LFV 0x00010000 #define INT_MDIO_STAT_SC 0x00020000 #define INT_MDIO_STAT_SM 0x00040000 #define INT_MDIO_STAT_MIILFS 0x00080000 #define INT_MDIO_STAT_MBSY 0x00100000 #define EXT_G_MDIO_CLOCK_DIV_4 0 #define EXT_G_MDIO_CLOCK_DIV_2 1 #define EXT_G_MDIO_CLOCK_DIV_1 2 #define EXT_G_MDIO_REGADDR_POS 5 #define EXT_G_MDIO_PHYADDR_POS 10 #define EXT_G_MDIO_CMD_SP 0x00008000 #define EXT_G_MDIO_CMD_PSIA 0x00010000 #define EXT_G_MDIO_CMD_LCD 0x00020000 #define EXT_G_MDIO_CMD_RDS 0x00040000 #define EXT_G_MDIO_CMD_SC 0x00080000 #define EXT_G_MDIO_MMRST 0x00100000 #define EXT_G_MDIO_DIV 0x0000001E #define EXT_G_MDIO_DIV_WITH_HW_DIV64 0x00000010 #define EXT_G_MDIO_RD_STAT_MASK 0x0000FFFF #define EXT_G_MDIO_STAT_LFV 0x00010000 #define EXT_G_MDIO_STAT_SC 0x00020000 #define EXT_G_MDIO_STAT_SM 0x00040000 #define EXT_G_MDIO_STAT_MIILFS 0x00080000 #define EXT_G_MDIO_STAT_MBSY 0x80000000 #define MDIO_OP_CMD_READ 0x10 #define MDIO_OP_CMD_WRITE 0x01 #if !defined(LOCORE) && !defined(__ASSEMBLY__) int nlm_int_gmac_mdio_read(uint64_t, int, int, int, int, int); int nlm_int_gmac_mdio_write(uint64_t, int, int, int, int, int, uint16_t); int nlm_int_gmac_mdio_reset(uint64_t, int, int, int); int nlm_gmac_mdio_read(uint64_t, int, int, int, int, int); int nlm_gmac_mdio_write(uint64_t, int, int, int, int, int, uint16_t); int nlm_gmac_mdio_reset(uint64_t, int, int, int); void nlm_mdio_reset_all(uint64_t); #endif /* !(LOCORE) && !(__ASSEMBLY__) */ #endif Index: head/sys/mips/nlm/hal/mips-extns.h =================================================================== --- head/sys/mips/nlm/hal/mips-extns.h (revision 326258) +++ head/sys/mips/nlm/hal/mips-extns.h (revision 326259) @@ -1,274 +1,276 @@ /*- + * 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 * $FreeBSD$ */ #ifndef __NLM_MIPS_EXTNS_H__ #define __NLM_MIPS_EXTNS_H__ #if !defined(LOCORE) && !defined(__ASSEMBLY__) static __inline__ int32_t nlm_swapw(int32_t *loc, int32_t val) { int32_t oldval = 0; __asm__ __volatile__ ( ".set push\n" ".set noreorder\n" "move $9, %2\n" "move $8, %3\n" ".word 0x71280014\n" /* "swapw $8, $9\n" */ "move %1, $8\n" ".set pop\n" : "+m" (*loc), "=r" (oldval) : "r" (loc), "r" (val) : "$8", "$9" ); return oldval; } static __inline__ uint32_t nlm_swapwu(int32_t *loc, uint32_t val) { uint32_t oldval; __asm__ __volatile__ ( ".set push\n" ".set noreorder\n" "move $9, %2\n" "move $8, %3\n" ".word 0x71280015\n" /* "swapwu $8, $9\n" */ "move %1, $8\n" ".set pop\n" : "+m" (*loc), "=r" (oldval) : "r" (loc), "r" (val) : "$8", "$9" ); return oldval; } #if (__mips == 64) static __inline__ uint64_t nlm_swapd(int32_t *loc, uint64_t val) { uint64_t oldval; __asm__ __volatile__ ( ".set push\n" ".set noreorder\n" "move $9, %2\n" "move $8, %3\n" ".word 0x71280014\n" /* "swapw $8, $9\n" */ "move %1, $8\n" ".set pop\n" : "+m" (*loc), "=r" (oldval) : "r" (loc), "r" (val) : "$8", "$9" ); return oldval; } #endif /* * Atomic increment a unsigned int */ static __inline unsigned int nlm_ldaddwu(unsigned int value, unsigned int *addr) { __asm__ __volatile__( ".set push\n" ".set noreorder\n" "move $8, %2\n" "move $9, %3\n" ".word 0x71280011\n" /* ldaddwu $8, $9 */ "move %0, $8\n" ".set pop\n" : "=&r"(value), "+m"(*addr) : "0"(value), "r" ((unsigned long)addr) : "$8", "$9"); return (value); } /* * 32 bit read write for c0 */ #define read_c0_register32(reg, sel) \ ({ \ uint32_t __rv; \ __asm__ __volatile__( \ ".set push\n\t" \ ".set mips32\n\t" \ "mfc0 %0, $%1, %2\n\t" \ ".set pop\n" \ : "=r" (__rv) : "i" (reg), "i" (sel) ); \ __rv; \ }) #define write_c0_register32(reg, sel, value) \ __asm__ __volatile__( \ ".set push\n\t" \ ".set mips32\n\t" \ "mtc0 %0, $%1, %2\n\t" \ ".set pop\n" \ : : "r" (value), "i" (reg), "i" (sel) ); #if defined(__mips_n64) || defined(__mips_n32) /* * On 64 bit compilation, the operations are simple */ #define read_c0_register64(reg, sel) \ ({ \ uint64_t __rv; \ __asm__ __volatile__( \ ".set push\n\t" \ ".set mips64\n\t" \ "dmfc0 %0, $%1, %2\n\t" \ ".set pop\n" \ : "=r" (__rv) : "i" (reg), "i" (sel) ); \ __rv; \ }) #define write_c0_register64(reg, sel, value) \ __asm__ __volatile__( \ ".set push\n\t" \ ".set mips64\n\t" \ "dmtc0 %0, $%1, %2\n\t" \ ".set pop\n" \ : : "r" (value), "i" (reg), "i" (sel) ); #else /* ! (defined(__mips_n64) || defined(__mips_n32)) */ /* * 32 bit compilation, 64 bit values has to split */ #define read_c0_register64(reg, sel) \ ({ \ uint32_t __high, __low; \ __asm__ __volatile__( \ ".set push\n\t" \ ".set noreorder\n\t" \ ".set mips64\n\t" \ "dmfc0 $8, $%2, %3\n\t" \ "dsra32 %0, $8, 0\n\t" \ "sll %1, $8, 0\n\t" \ ".set pop\n" \ : "=r"(__high), "=r"(__low): "i"(reg), "i"(sel) \ : "$8"); \ ((uint64_t)__high << 32) | __low; \ }) #define write_c0_register64(reg, sel, value) \ do { \ uint32_t __high = value >> 32; \ uint32_t __low = value & 0xffffffff; \ __asm__ __volatile__( \ ".set push\n\t" \ ".set noreorder\n\t" \ ".set mips64\n\t" \ "dsll32 $8, %1, 0\n\t" \ "dsll32 $9, %0, 0\n\t" \ "dsrl32 $8, $8, 0\n\t" \ "or $8, $8, $9\n\t" \ "dmtc0 $8, $%2, %3\n\t" \ ".set pop" \ :: "r"(__high), "r"(__low), "i"(reg), "i"(sel) \ :"$8", "$9"); \ } while(0) #endif /* functions to write to and read from the extended * cp0 registers. * EIRR : Extended Interrupt Request Register * cp0 register 9 sel 6 * bits 0...7 are same as cause register 8...15 * EIMR : Extended Interrupt Mask Register * cp0 register 9 sel 7 * bits 0...7 are same as status register 8...15 */ static __inline uint64_t nlm_read_c0_eirr(void) { return (read_c0_register64(9, 6)); } static __inline void nlm_write_c0_eirr(uint64_t val) { write_c0_register64(9, 6, val); } static __inline uint64_t nlm_read_c0_eimr(void) { return (read_c0_register64(9, 7)); } static __inline void nlm_write_c0_eimr(uint64_t val) { write_c0_register64(9, 7, val); } static __inline__ uint32_t nlm_read_c0_ebase(void) { return (read_c0_register32(15, 1)); } static __inline__ int nlm_nodeid(void) { return (nlm_read_c0_ebase() >> 5) & 0x3; } static __inline__ int nlm_cpuid(void) { return nlm_read_c0_ebase() & 0x1f; } static __inline__ int nlm_threadid(void) { return nlm_read_c0_ebase() & 0x3; } static __inline__ int nlm_coreid(void) { return (nlm_read_c0_ebase() >> 2) & 0x7; } #endif #define XLP_MAX_NODES 4 #define XLP_MAX_CORES 8 #define XLP_MAX_THREADS 4 #endif Index: head/sys/mips/nlm/hal/mmu.h =================================================================== --- head/sys/mips/nlm/hal/mmu.h (revision 326258) +++ head/sys/mips/nlm/hal/mmu.h (revision 326259) @@ -1,165 +1,167 @@ /*- + * 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 * $FreeBSD$ */ #ifndef __XLP_MMU_H__ #define __XLP_MMU_H__ #include static __inline__ uint32_t nlm_read_c0_config6(void) { uint32_t rv; __asm__ __volatile__ ( ".set push\n" ".set mips64\n" "mfc0 %0, $16, 6\n" ".set pop\n" : "=r" (rv)); return rv; } static __inline__ void nlm_write_c0_config6(uint32_t value) { __asm__ __volatile__ ( ".set push\n" ".set mips64\n" "mtc0 %0, $16, 6\n" ".set pop\n" : : "r" (value)); } static __inline__ uint32_t nlm_read_c0_config7(void) { uint32_t rv; __asm__ __volatile__ ( ".set push\n" ".set mips64\n" "mfc0 %0, $16, 7\n" ".set pop\n" : "=r" (rv)); return rv; } static __inline__ void nlm_write_c0_config7(uint32_t value) { __asm__ __volatile__ ( ".set push\n" ".set mips64\n" "mtc0 %0, $16, 7\n" ".set pop\n" : : "r" (value)); } /** * On power on reset, XLP comes up with 64 TLBs. * Large-variable-tlb's (ELVT) and extended TLB is disabled. * Enabling large-variable-tlb's sets up the standard * TLB size from 64 to 128 TLBs. * Enabling fixed TLB (EFT) sets up an additional 2048 tlbs. * ELVT + EFT = 128 + 2048 = 2176 TLB entries. * threads 64-entry-standard-tlb 128-entry-standard-tlb * per std-tlb-only| std+EFT | std-tlb-only| std+EFT * core | | | * -------------------------------------------------------- * 1 64 64+2048 128 128+2048 * 2 64 64+1024 64 64+1024 * 4 32 32+512 32 32+512 * * 1(G) 64 64+2048 128 128+2048 * 2(G) 128 128+2048 128 128+2048 * 4(G) 128 128+2048 128 128+2048 * (G) = Global mode */ /* en = 1 to enable * en = 0 to disable */ static __inline__ void nlm_large_variable_tlb_en (int en) { unsigned int val; val = nlm_read_c0_config6(); val |= (en << 5); nlm_write_c0_config6(val); return; } /* en = 1 to enable * en = 0 to disable */ static __inline__ void nlm_pagewalker_en(int en) { unsigned int val; val = nlm_read_c0_config6(); val |= (en << 3); nlm_write_c0_config6(val); return; } /* en = 1 to enable * en = 0 to disable */ static __inline__ void nlm_extended_tlb_en(int en) { unsigned int val; val = nlm_read_c0_config6(); val |= (en << 2); nlm_write_c0_config6(val); return; } static __inline__ int nlm_get_num_combined_tlbs(void) { return (((nlm_read_c0_config6() >> 16) & 0xffff) + 1); } /* get number of variable TLB entries */ static __inline__ int nlm_get_num_vtlbs(void) { return (((nlm_read_c0_config6() >> 6) & 0x3ff) + 1); } static __inline__ void nlm_setup_extended_pagemask(int mask) { nlm_write_c0_config7(mask); } #endif Index: head/sys/mips/nlm/hal/nae.h =================================================================== --- head/sys/mips/nlm/hal/nae.h (revision 326258) +++ head/sys/mips/nlm/hal/nae.h (revision 326259) @@ -1,656 +1,658 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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$ */ #ifndef __NLM_NAE_H__ #define __NLM_NAE_H__ /** * @file_name nae.h * @author Netlogic Microsystems * @brief Basic definitions of XLP Networt Accelerator Engine */ /* NAE specific registers */ #define NAE_REG(blk, intf, reg) (((blk) << 11) | ((intf) << 7) | (reg)) /* ingress path registers */ #define NAE_RX_CONFIG NAE_REG(7, 0, 0x10) #define NAE_RX_IF_BASE_CONFIG0 NAE_REG(7, 0, 0x12) #define NAE_RX_IF_BASE_CONFIG1 NAE_REG(7, 0, 0x13) #define NAE_RX_IF_BASE_CONFIG2 NAE_REG(7, 0, 0x14) #define NAE_RX_IF_BASE_CONFIG3 NAE_REG(7, 0, 0x15) #define NAE_RX_IF_BASE_CONFIG4 NAE_REG(7, 0, 0x16) #define NAE_RX_IF_BASE_CONFIG5 NAE_REG(7, 0, 0x17) #define NAE_RX_IF_BASE_CONFIG6 NAE_REG(7, 0, 0x18) #define NAE_RX_IF_BASE_CONFIG7 NAE_REG(7, 0, 0x19) #define NAE_RX_IF_BASE_CONFIG8 NAE_REG(7, 0, 0x1a) #define NAE_RX_IF_BASE_CONFIG9 NAE_REG(7, 0, 0x1b) #define NAE_RX_IF_VEC_VALID NAE_REG(7, 0, 0x1c) #define NAE_RX_IF_SLOT_CAL NAE_REG(7, 0, 0x1d) #define NAE_PARSER_CONFIG NAE_REG(7, 0, 0x1e) #define NAE_PARSER_SEQ_FIFO_CFG NAE_REG(7, 0, 0x1f) #define NAE_FREE_IN_FIFO_CFG NAE_REG(7, 0, 0x20) #define NAE_RXBUF_BASE_DPTH_ADDR NAE_REG(7, 0, 0x21) #define NAE_RXBUF_BASE_DPTH NAE_REG(7, 0, 0x22) #define NAE_RX_UCORE_CFG NAE_REG(7, 0, 0x23) #define NAE_RX_UCORE_CAM_MASK0 NAE_REG(7, 0, 0x24) #define NAE_RX_UCORE_CAM_MASK1 NAE_REG(7, 0, 0x25) #define NAE_RX_UCORE_CAM_MASK2 NAE_REG(7, 0, 0x26) #define NAE_RX_UCORE_CAM_MASK3 NAE_REG(7, 0, 0x27) #define NAE_FREEIN_FIFO_UNIQ_SZ_CFG NAE_REG(7, 0, 0x28) #define NAE_RX_CRC_POLY0_CFG NAE_REG(7, 0, 0x2a) #define NAE_RX_CRC_POLY1_CFG NAE_REG(7, 0, 0x2b) #define NAE_FREE_SPILL0_MEM_CFG NAE_REG(7, 0, 0x2c) #define NAE_FREE_SPILL1_MEM_CFG NAE_REG(7, 0, 0x2d) #define NAE_FREEFIFO_THRESH_CFG NAE_REG(7, 0, 0x2e) #define NAE_FLOW_CRC16_POLY_CFG NAE_REG(7, 0, 0x2f) #define NAE_EGR_NIOR_CAL_LEN_REG NAE_REG(7, 0, 0x4e) #define NAE_EGR_NIOR_CRDT_CAL_PROG NAE_REG(7, 0, 0x52) #define NAE_TEST NAE_REG(7, 0, 0x5f) #define NAE_BIU_TIMEOUT_CFG NAE_REG(7, 0, 0x60) #define NAE_BIU_CFG NAE_REG(7, 0, 0x61) #define NAE_RX_FREE_FIFO_POP NAE_REG(7, 0, 0x62) #define NAE_RX_DSBL_ECC NAE_REG(7, 0, 0x63) #define NAE_FLOW_BASEMASK_CFG NAE_REG(7, 0, 0x80) #define NAE_POE_CLASS_SETUP_CFG NAE_REG(7, 0, 0x81) #define NAE_UCORE_IFACEMASK_CFG NAE_REG(7, 0, 0x82) #define NAE_RXBUF_XOFFON_THRESH NAE_REG(7, 0, 0x83) #define NAE_FLOW_TABLE1_CFG NAE_REG(7, 0, 0x84) #define NAE_FLOW_TABLE2_CFG NAE_REG(7, 0, 0x85) #define NAE_FLOW_TABLE3_CFG NAE_REG(7, 0, 0x86) #define NAE_RX_FREE_FIFO_THRESH NAE_REG(7, 0, 0x87) #define NAE_RX_PARSER_UNCLA NAE_REG(7, 0, 0x88) #define NAE_RX_BUF_INTR_THRESH NAE_REG(7, 0, 0x89) #define NAE_IFACE_FIFO_CFG NAE_REG(7, 0, 0x8a) #define NAE_PARSER_SEQ_FIFO_THRESH_CFG NAE_REG(7, 0, 0x8b) #define NAE_RX_ERRINJ_CTRL0 NAE_REG(7, 0, 0x8c) #define NAE_RX_ERRINJ_CTRL1 NAE_REG(7, 0, 0x8d) #define NAE_RX_ERR_LATCH0 NAE_REG(7, 0, 0x8e) #define NAE_RX_ERR_LATCH1 NAE_REG(7, 0, 0x8f) #define NAE_RX_PERF_CTR_CFG NAE_REG(7, 0, 0xa0) #define NAE_RX_PERF_CTR_VAL NAE_REG(7, 0, 0xa1) /* NAE hardware parser registers */ #define NAE_L2_TYPE_PORT0 NAE_REG(7, 0, 0x210) #define NAE_L2_TYPE_PORT1 NAE_REG(7, 0, 0x211) #define NAE_L2_TYPE_PORT2 NAE_REG(7, 0, 0x212) #define NAE_L2_TYPE_PORT3 NAE_REG(7, 0, 0x213) #define NAE_L2_TYPE_PORT4 NAE_REG(7, 0, 0x214) #define NAE_L2_TYPE_PORT5 NAE_REG(7, 0, 0x215) #define NAE_L2_TYPE_PORT6 NAE_REG(7, 0, 0x216) #define NAE_L2_TYPE_PORT7 NAE_REG(7, 0, 0x217) #define NAE_L2_TYPE_PORT8 NAE_REG(7, 0, 0x218) #define NAE_L2_TYPE_PORT9 NAE_REG(7, 0, 0x219) #define NAE_L2_TYPE_PORT10 NAE_REG(7, 0, 0x21a) #define NAE_L2_TYPE_PORT11 NAE_REG(7, 0, 0x21b) #define NAE_L2_TYPE_PORT12 NAE_REG(7, 0, 0x21c) #define NAE_L2_TYPE_PORT13 NAE_REG(7, 0, 0x21d) #define NAE_L2_TYPE_PORT14 NAE_REG(7, 0, 0x21e) #define NAE_L2_TYPE_PORT15 NAE_REG(7, 0, 0x21f) #define NAE_L2_TYPE_PORT16 NAE_REG(7, 0, 0x220) #define NAE_L2_TYPE_PORT17 NAE_REG(7, 0, 0x221) #define NAE_L2_TYPE_PORT18 NAE_REG(7, 0, 0x222) #define NAE_L2_TYPE_PORT19 NAE_REG(7, 0, 0x223) #define NAE_L3_CTABLE_MASK0 NAE_REG(7, 0, 0x22c) #define NAE_L3_CTABLE_MASK1 NAE_REG(7, 0, 0x22d) #define NAE_L3_CTABLE_MASK2 NAE_REG(7, 0, 0x22e) #define NAE_L3_CTABLE_MASK3 NAE_REG(7, 0, 0x22f) #define NAE_L3CTABLE0 NAE_REG(7, 0, 0x230) #define NAE_L3CTABLE1 NAE_REG(7, 0, 0x231) #define NAE_L3CTABLE2 NAE_REG(7, 0, 0x232) #define NAE_L3CTABLE3 NAE_REG(7, 0, 0x233) #define NAE_L3CTABLE4 NAE_REG(7, 0, 0x234) #define NAE_L3CTABLE5 NAE_REG(7, 0, 0x235) #define NAE_L3CTABLE6 NAE_REG(7, 0, 0x236) #define NAE_L3CTABLE7 NAE_REG(7, 0, 0x237) #define NAE_L3CTABLE8 NAE_REG(7, 0, 0x238) #define NAE_L3CTABLE9 NAE_REG(7, 0, 0x239) #define NAE_L3CTABLE10 NAE_REG(7, 0, 0x23a) #define NAE_L3CTABLE11 NAE_REG(7, 0, 0x23b) #define NAE_L3CTABLE12 NAE_REG(7, 0, 0x23c) #define NAE_L3CTABLE13 NAE_REG(7, 0, 0x23d) #define NAE_L3CTABLE14 NAE_REG(7, 0, 0x23e) #define NAE_L3CTABLE15 NAE_REG(7, 0, 0x23f) #define NAE_L4CTABLE0 NAE_REG(7, 0, 0x250) #define NAE_L4CTABLE1 NAE_REG(7, 0, 0x251) #define NAE_L4CTABLE2 NAE_REG(7, 0, 0x252) #define NAE_L4CTABLE3 NAE_REG(7, 0, 0x253) #define NAE_L4CTABLE4 NAE_REG(7, 0, 0x254) #define NAE_L4CTABLE5 NAE_REG(7, 0, 0x255) #define NAE_L4CTABLE6 NAE_REG(7, 0, 0x256) #define NAE_L4CTABLE7 NAE_REG(7, 0, 0x257) #define NAE_IPV6_EXT_HEADER0 NAE_REG(7, 0, 0x260) #define NAE_IPV6_EXT_HEADER1 NAE_REG(7, 0, 0x261) #define NAE_VLAN_TYPES01 NAE_REG(7, 0, 0x262) #define NAE_VLAN_TYPES23 NAE_REG(7, 0, 0x263) /* NAE Egress path registers */ #define NAE_TX_CONFIG NAE_REG(7, 0, 0x11) #define NAE_DMA_TX_CREDIT_TH NAE_REG(7, 0, 0x29) #define NAE_STG1_STG2CRDT_CMD NAE_REG(7, 0, 0x30) #define NAE_STG2_EHCRDT_CMD NAE_REG(7, 0, 0x32) #define NAE_EH_FREECRDT_CMD NAE_REG(7, 0, 0x34) #define NAE_STG2_STRCRDT_CMD NAE_REG(7, 0, 0x36) #define NAE_TXFIFO_IFACEMAP_CMD NAE_REG(7, 0, 0x38) #define NAE_VFBID_DESTMAP_CMD NAE_REG(7, 0, 0x3a) #define NAE_STG1_PMEM_PROG NAE_REG(7, 0, 0x3c) #define NAE_STG2_PMEM_PROG NAE_REG(7, 0, 0x3e) #define NAE_EH_PMEM_PROG NAE_REG(7, 0, 0x40) #define NAE_FREE_PMEM_PROG NAE_REG(7, 0, 0x42) #define NAE_TX_DDR_ACTVLIST_CMD NAE_REG(7, 0, 0x44) #define NAE_TX_IF_BURSTMAX_CMD NAE_REG(7, 0, 0x46) #define NAE_TX_IF_ENABLE_CMD NAE_REG(7, 0, 0x48) #define NAE_TX_PKTLEN_PMEM_CMD NAE_REG(7, 0, 0x4a) #define NAE_TX_SCHED_MAP_CMD0 NAE_REG(7, 0, 0x4c) #define NAE_TX_SCHED_MAP_CMD1 NAE_REG(7, 0, 0x4d) #define NAE_TX_PKT_PMEM_CMD0 NAE_REG(7, 0, 0x50) #define NAE_TX_PKT_PMEM_CMD1 NAE_REG(7, 0, 0x51) #define NAE_TX_SCHED_CTRL NAE_REG(7, 0, 0x53) #define NAE_TX_CRC_POLY0 NAE_REG(7, 0, 0x54) #define NAE_TX_CRC_POLY1 NAE_REG(7, 0, 0x55) #define NAE_TX_CRC_POLY2 NAE_REG(7, 0, 0x56) #define NAE_TX_CRC_POLY3 NAE_REG(7, 0, 0x57) #define NAE_STR_PMEM_CMD NAE_REG(7, 0, 0x58) #define NAE_TX_IORCRDT_INIT NAE_REG(7, 0, 0x59) #define NAE_TX_DSBL_ECC NAE_REG(7, 0, 0x5a) #define NAE_TX_IORCRDT_IGNORE NAE_REG(7, 0, 0x5b) #define NAE_IF0_1588_TMSTMP_HI NAE_REG(7, 0, 0x300) #define NAE_IF1_1588_TMSTMP_HI NAE_REG(7, 0, 0x302) #define NAE_IF2_1588_TMSTMP_HI NAE_REG(7, 0, 0x304) #define NAE_IF3_1588_TMSTMP_HI NAE_REG(7, 0, 0x306) #define NAE_IF4_1588_TMSTMP_HI NAE_REG(7, 0, 0x308) #define NAE_IF5_1588_TMSTMP_HI NAE_REG(7, 0, 0x30a) #define NAE_IF6_1588_TMSTMP_HI NAE_REG(7, 0, 0x30c) #define NAE_IF7_1588_TMSTMP_HI NAE_REG(7, 0, 0x30e) #define NAE_IF8_1588_TMSTMP_HI NAE_REG(7, 0, 0x310) #define NAE_IF9_1588_TMSTMP_HI NAE_REG(7, 0, 0x312) #define NAE_IF10_1588_TMSTMP_HI NAE_REG(7, 0, 0x314) #define NAE_IF11_1588_TMSTMP_HI NAE_REG(7, 0, 0x316) #define NAE_IF12_1588_TMSTMP_HI NAE_REG(7, 0, 0x318) #define NAE_IF13_1588_TMSTMP_HI NAE_REG(7, 0, 0x31a) #define NAE_IF14_1588_TMSTMP_HI NAE_REG(7, 0, 0x31c) #define NAE_IF15_1588_TMSTMP_HI NAE_REG(7, 0, 0x31e) #define NAE_IF16_1588_TMSTMP_HI NAE_REG(7, 0, 0x320) #define NAE_IF17_1588_TMSTMP_HI NAE_REG(7, 0, 0x322) #define NAE_IF18_1588_TMSTMP_HI NAE_REG(7, 0, 0x324) #define NAE_IF19_1588_TMSTMP_HI NAE_REG(7, 0, 0x326) #define NAE_IF0_1588_TMSTMP_LO NAE_REG(7, 0, 0x301) #define NAE_IF1_1588_TMSTMP_LO NAE_REG(7, 0, 0x303) #define NAE_IF2_1588_TMSTMP_LO NAE_REG(7, 0, 0x305) #define NAE_IF3_1588_TMSTMP_LO NAE_REG(7, 0, 0x307) #define NAE_IF4_1588_TMSTMP_LO NAE_REG(7, 0, 0x309) #define NAE_IF5_1588_TMSTMP_LO NAE_REG(7, 0, 0x30b) #define NAE_IF6_1588_TMSTMP_LO NAE_REG(7, 0, 0x30d) #define NAE_IF7_1588_TMSTMP_LO NAE_REG(7, 0, 0x30f) #define NAE_IF8_1588_TMSTMP_LO NAE_REG(7, 0, 0x311) #define NAE_IF9_1588_TMSTMP_LO NAE_REG(7, 0, 0x313) #define NAE_IF10_1588_TMSTMP_LO NAE_REG(7, 0, 0x315) #define NAE_IF11_1588_TMSTMP_LO NAE_REG(7, 0, 0x317) #define NAE_IF12_1588_TMSTMP_LO NAE_REG(7, 0, 0x319) #define NAE_IF13_1588_TMSTMP_LO NAE_REG(7, 0, 0x31b) #define NAE_IF14_1588_TMSTMP_LO NAE_REG(7, 0, 0x31d) #define NAE_IF15_1588_TMSTMP_LO NAE_REG(7, 0, 0x31f) #define NAE_IF16_1588_TMSTMP_LO NAE_REG(7, 0, 0x321) #define NAE_IF17_1588_TMSTMP_LO NAE_REG(7, 0, 0x323) #define NAE_IF18_1588_TMSTMP_LO NAE_REG(7, 0, 0x325) #define NAE_IF19_1588_TMSTMP_LO NAE_REG(7, 0, 0x327) #define NAE_TX_EL0 NAE_REG(7, 0, 0x328) #define NAE_TX_EL1 NAE_REG(7, 0, 0x329) #define NAE_EIC0 NAE_REG(7, 0, 0x32a) #define NAE_EIC1 NAE_REG(7, 0, 0x32b) #define NAE_STG1_STG2CRDT_STATUS NAE_REG(7, 0, 0x32c) #define NAE_STG2_EHCRDT_STATUS NAE_REG(7, 0, 0x32d) #define NAE_STG2_FREECRDT_STATUS NAE_REG(7, 0, 0x32e) #define NAE_STG2_STRCRDT_STATUS NAE_REG(7, 0, 0x32f) #define NAE_TX_PERF_CNTR_INTR_STATUS NAE_REG(7, 0, 0x330) #define NAE_TX_PERF_CNTR_ROLL_STATUS NAE_REG(7, 0, 0x331) #define NAE_TX_PERF_CNTR0 NAE_REG(7, 0, 0x332) #define NAE_TX_PERF_CNTR1 NAE_REG(7, 0, 0x334) #define NAE_TX_PERF_CNTR2 NAE_REG(7, 0, 0x336) #define NAE_TX_PERF_CNTR3 NAE_REG(7, 0, 0x338) #define NAE_TX_PERF_CNTR4 NAE_REG(7, 0, 0x33a) #define NAE_TX_PERF_CNTR0_CTL NAE_REG(7, 0, 0x333) #define NAE_TX_PERF_CNTR1_CTL NAE_REG(7, 0, 0x335) #define NAE_TX_PERF_CNTR2_CTL NAE_REG(7, 0, 0x337) #define NAE_TX_PERF_CNTR3_CTL NAE_REG(7, 0, 0x339) #define NAE_TX_PERF_CNTR4_CTL NAE_REG(7, 0, 0x33b) #define NAE_VFBID_DESTMAP_STATUS NAE_REG(7, 0, 0x380) #define NAE_STG2_PMEM_STATUS NAE_REG(7, 0, 0x381) #define NAE_EH_PMEM_STATUS NAE_REG(7, 0, 0x382) #define NAE_FREE_PMEM_STATUS NAE_REG(7, 0, 0x383) #define NAE_TX_DDR_ACTVLIST_STATUS NAE_REG(7, 0, 0x384) #define NAE_TX_IF_BURSTMAX_STATUS NAE_REG(7, 0, 0x385) #define NAE_TX_PKTLEN_PMEM_STATUS NAE_REG(7, 0, 0x386) #define NAE_TX_SCHED_MAP_STATUS0 NAE_REG(7, 0, 0x387) #define NAE_TX_SCHED_MAP_STATUS1 NAE_REG(7, 0, 0x388) #define NAE_TX_PKT_PMEM_STATUS NAE_REG(7, 0, 0x389) #define NAE_STR_PMEM_STATUS NAE_REG(7, 0, 0x38a) /* Network interface interrupt registers */ #define NAE_NET_IF0_INTR_STAT NAE_REG(7, 0, 0x280) #define NAE_NET_IF1_INTR_STAT NAE_REG(7, 0, 0x282) #define NAE_NET_IF2_INTR_STAT NAE_REG(7, 0, 0x284) #define NAE_NET_IF3_INTR_STAT NAE_REG(7, 0, 0x286) #define NAE_NET_IF4_INTR_STAT NAE_REG(7, 0, 0x288) #define NAE_NET_IF5_INTR_STAT NAE_REG(7, 0, 0x28a) #define NAE_NET_IF6_INTR_STAT NAE_REG(7, 0, 0x28c) #define NAE_NET_IF7_INTR_STAT NAE_REG(7, 0, 0x28e) #define NAE_NET_IF8_INTR_STAT NAE_REG(7, 0, 0x290) #define NAE_NET_IF9_INTR_STAT NAE_REG(7, 0, 0x292) #define NAE_NET_IF10_INTR_STAT NAE_REG(7, 0, 0x294) #define NAE_NET_IF11_INTR_STAT NAE_REG(7, 0, 0x296) #define NAE_NET_IF12_INTR_STAT NAE_REG(7, 0, 0x298) #define NAE_NET_IF13_INTR_STAT NAE_REG(7, 0, 0x29a) #define NAE_NET_IF14_INTR_STAT NAE_REG(7, 0, 0x29c) #define NAE_NET_IF15_INTR_STAT NAE_REG(7, 0, 0x29e) #define NAE_NET_IF16_INTR_STAT NAE_REG(7, 0, 0x2a0) #define NAE_NET_IF17_INTR_STAT NAE_REG(7, 0, 0x2a2) #define NAE_NET_IF18_INTR_STAT NAE_REG(7, 0, 0x2a4) #define NAE_NET_IF19_INTR_STAT NAE_REG(7, 0, 0x2a6) #define NAE_NET_IF0_INTR_MASK NAE_REG(7, 0, 0x281) #define NAE_NET_IF1_INTR_MASK NAE_REG(7, 0, 0x283) #define NAE_NET_IF2_INTR_MASK NAE_REG(7, 0, 0x285) #define NAE_NET_IF3_INTR_MASK NAE_REG(7, 0, 0x287) #define NAE_NET_IF4_INTR_MASK NAE_REG(7, 0, 0x289) #define NAE_NET_IF5_INTR_MASK NAE_REG(7, 0, 0x28b) #define NAE_NET_IF6_INTR_MASK NAE_REG(7, 0, 0x28d) #define NAE_NET_IF7_INTR_MASK NAE_REG(7, 0, 0x28f) #define NAE_NET_IF8_INTR_MASK NAE_REG(7, 0, 0x291) #define NAE_NET_IF9_INTR_MASK NAE_REG(7, 0, 0x293) #define NAE_NET_IF10_INTR_MASK NAE_REG(7, 0, 0x295) #define NAE_NET_IF11_INTR_MASK NAE_REG(7, 0, 0x297) #define NAE_NET_IF12_INTR_MASK NAE_REG(7, 0, 0x299) #define NAE_NET_IF13_INTR_MASK NAE_REG(7, 0, 0x29b) #define NAE_NET_IF14_INTR_MASK NAE_REG(7, 0, 0x29d) #define NAE_NET_IF15_INTR_MASK NAE_REG(7, 0, 0x29f) #define NAE_NET_IF16_INTR_MASK NAE_REG(7, 0, 0x2a1) #define NAE_NET_IF17_INTR_MASK NAE_REG(7, 0, 0x2a3) #define NAE_NET_IF18_INTR_MASK NAE_REG(7, 0, 0x2a5) #define NAE_NET_IF19_INTR_MASK NAE_REG(7, 0, 0x2a7) #define NAE_COMMON0_INTR_STAT NAE_REG(7, 0, 0x2a8) #define NAE_COMMON0_INTR_MASK NAE_REG(7, 0, 0x2a9) #define NAE_COMMON1_INTR_STAT NAE_REG(7, 0, 0x2aa) #define NAE_COMMON1_INTR_MASK NAE_REG(7, 0, 0x2ab) /* Network Interface Low-block Registers */ #define NAE_PHY_LANE0_STATUS(block) NAE_REG(block, 0xe, 0) #define NAE_PHY_LANE1_STATUS(block) NAE_REG(block, 0xe, 1) #define NAE_PHY_LANE2_STATUS(block) NAE_REG(block, 0xe, 2) #define NAE_PHY_LANE3_STATUS(block) NAE_REG(block, 0xe, 3) #define NAE_PHY_LANE0_CTRL(block) NAE_REG(block, 0xe, 4) #define NAE_PHY_LANE1_CTRL(block) NAE_REG(block, 0xe, 5) #define NAE_PHY_LANE2_CTRL(block) NAE_REG(block, 0xe, 6) #define NAE_PHY_LANE3_CTRL(block) NAE_REG(block, 0xe, 7) /* Network interface Top-block registers */ #define NAE_LANE_CFG_CPLX_0_1 NAE_REG(7, 0, 0x780) #define NAE_LANE_CFG_CPLX_2_3 NAE_REG(7, 0, 0x781) #define NAE_LANE_CFG_CPLX_4 NAE_REG(7, 0, 0x782) #define NAE_LANE_CFG_SOFTRESET NAE_REG(7, 0, 0x783) #define NAE_1588_PTP_OFFSET_HI NAE_REG(7, 0, 0x784) #define NAE_1588_PTP_OFFSET_LO NAE_REG(7, 0, 0x785) #define NAE_1588_PTP_INC_DEN NAE_REG(7, 0, 0x786) #define NAE_1588_PTP_INC_NUM NAE_REG(7, 0, 0x787) #define NAE_1588_PTP_INC_INTG NAE_REG(7, 0, 0x788) #define NAE_1588_PTP_CONTROL NAE_REG(7, 0, 0x789) #define NAE_1588_PTP_STATUS NAE_REG(7, 0, 0x78a) #define NAE_1588_PTP_USER_VALUE_HI NAE_REG(7, 0, 0x78b) #define NAE_1588_PTP_USER_VALUE_LO NAE_REG(7, 0, 0x78c) #define NAE_1588_PTP_TMR1_HI NAE_REG(7, 0, 0x78d) #define NAE_1588_PTP_TMR1_LO NAE_REG(7, 0, 0x78e) #define NAE_1588_PTP_TMR2_HI NAE_REG(7, 0, 0x78f) #define NAE_1588_PTP_TMR2_LO NAE_REG(7, 0, 0x790) #define NAE_1588_PTP_TMR3_HI NAE_REG(7, 0, 0x791) #define NAE_1588_PTP_TMR3_LO NAE_REG(7, 0, 0x792) #define NAE_TX_FC_CAL_IDX_TBL_CTRL NAE_REG(7, 0, 0x793) #define NAE_TX_FC_CAL_TBL_CTRL NAE_REG(7, 0, 0x794) #define NAE_TX_FC_CAL_TBL_DATA0 NAE_REG(7, 0, 0x795) #define NAE_TX_FC_CAL_TBL_DATA1 NAE_REG(7, 0, 0x796) #define NAE_TX_FC_CAL_TBL_DATA2 NAE_REG(7, 0, 0x797) #define NAE_TX_FC_CAL_TBL_DATA3 NAE_REG(7, 0, 0x798) #define NAE_INT_MDIO_CTRL NAE_REG(7, 0, 0x799) #define NAE_INT_MDIO_CTRL_DATA NAE_REG(7, 0, 0x79a) #define NAE_INT_MDIO_RD_STAT NAE_REG(7, 0, 0x79b) #define NAE_INT_MDIO_LINK_STAT NAE_REG(7, 0, 0x79c) #define NAE_EXT_G0_MDIO_CTRL NAE_REG(7, 0, 0x79d) #define NAE_EXT_G1_MDIO_CTRL NAE_REG(7, 0, 0x7a1) #define NAE_EXT_G0_MDIO_CTRL_DATA NAE_REG(7, 0, 0x79e) #define NAE_EXT_G1_MDIO_CTRL_DATA NAE_REG(7, 0, 0x7a2) #define NAE_EXT_G0_MDIO_RD_STAT NAE_REG(7, 0, 0x79f) #define NAE_EXT_G1_MDIO_RD_STAT NAE_REG(7, 0, 0x7a3) #define NAE_EXT_G0_MDIO_LINK_STAT NAE_REG(7, 0, 0x7a0) #define NAE_EXT_G1_MDIO_LINK_STAT NAE_REG(7, 0, 0x7a4) #define NAE_EXT_XG0_MDIO_CTRL NAE_REG(7, 0, 0x7a5) #define NAE_EXT_XG1_MDIO_CTRL NAE_REG(7, 0, 0x7a9) #define NAE_EXT_XG0_MDIO_CTRL_DATA NAE_REG(7, 0, 0x7a6) #define NAE_EXT_XG1_MDIO_CTRL_DATA NAE_REG(7, 0, 0x7aa) #define NAE_EXT_XG0_MDIO_RD_STAT NAE_REG(7, 0, 0x7a7) #define NAE_EXT_XG1_MDIO_RD_STAT NAE_REG(7, 0, 0x7ab) #define NAE_EXT_XG0_MDIO_LINK_STAT NAE_REG(7, 0, 0x7a8) #define NAE_EXT_XG1_MDIO_LINK_STAT NAE_REG(7, 0, 0x7ac) #define NAE_GMAC_FC_SLOT0 NAE_REG(7, 0, 0x7ad) #define NAE_GMAC_FC_SLOT1 NAE_REG(7, 0, 0x7ae) #define NAE_GMAC_FC_SLOT2 NAE_REG(7, 0, 0x7af) #define NAE_GMAC_FC_SLOT3 NAE_REG(7, 0, 0x7b0) #define NAE_NETIOR_NTB_SLOT NAE_REG(7, 0, 0x7b1) #define NAE_NETIOR_MISC_CTRL0 NAE_REG(7, 0, 0x7b2) #define NAE_NETIOR_INT0 NAE_REG(7, 0, 0x7b3) #define NAE_NETIOR_INT0_MASK NAE_REG(7, 0, 0x7b4) #define NAE_NETIOR_INT1 NAE_REG(7, 0, 0x7b5) #define NAE_NETIOR_INT1_MASK NAE_REG(7, 0, 0x7b6) #define NAE_GMAC_PFC_REPEAT NAE_REG(7, 0, 0x7b7) #define NAE_XGMAC_PFC_REPEAT NAE_REG(7, 0, 0x7b8) #define NAE_NETIOR_MISC_CTRL1 NAE_REG(7, 0, 0x7b9) #define NAE_NETIOR_MISC_CTRL2 NAE_REG(7, 0, 0x7ba) #define NAE_NETIOR_INT2 NAE_REG(7, 0, 0x7bb) #define NAE_NETIOR_INT2_MASK NAE_REG(7, 0, 0x7bc) #define NAE_NETIOR_MISC_CTRL3 NAE_REG(7, 0, 0x7bd) /* Network interface lane configuration registers */ #define NAE_LANE_CFG_MISCREG1 NAE_REG(7, 0xf, 0x39) #define NAE_LANE_CFG_MISCREG2 NAE_REG(7, 0xf, 0x3A) /* Network interface soft reset register */ #define NAE_SOFT_RESET NAE_REG(7, 0xf, 3) /* ucore instruction/shared CAM RAM access */ #define NAE_UCORE_SHARED_RAM_OFFSET 0x10000 #define PORTS_PER_CMPLX 4 #define NAE_CACHELINE_SIZE 64 #define PHY_LANE_0_CTRL 4 #define PHY_LANE_1_CTRL 5 #define PHY_LANE_2_CTRL 6 #define PHY_LANE_3_CTRL 7 #define PHY_LANE_STAT_SRCS 0x00000001 #define PHY_LANE_STAT_STD 0x00000010 #define PHY_LANE_STAT_SFEA 0x00000020 #define PHY_LANE_STAT_STCS 0x00000040 #define PHY_LANE_STAT_SPC 0x00000200 #define PHY_LANE_STAT_XLF 0x00000400 #define PHY_LANE_STAT_PCR 0x00000800 #define PHY_LANE_CTRL_DATA_POS 0 #define PHY_LANE_CTRL_ADDR_POS 8 #define PHY_LANE_CTRL_CMD_READ 0x00010000 #define PHY_LANE_CTRL_CMD_WRITE 0x00000000 #define PHY_LANE_CTRL_CMD_START 0x00020000 #define PHY_LANE_CTRL_CMD_PENDING 0x00040000 #define PHY_LANE_CTRL_ALL 0x00200000 #define PHY_LANE_CTRL_FAST_INIT 0x00400000 #define PHY_LANE_CTRL_REXSEL_POS 23 #define PHY_LANE_CTRL_PHYMODE_POS 25 #define PHY_LANE_CTRL_PWRDOWN 0x20000000 #define PHY_LANE_CTRL_RST 0x40000000 #define PHY_LANE_CTRL_RST_XAUI 0xc0000000 #define PHY_LANE_CTRL_BPC_XAUI 0x80000000 #define LANE_CFG_CPLX_0_1 0x0 #define LANE_CFG_CPLX_2_3 0x1 #define LANE_CFG_CPLX_4 0x2 #define MAC_CONF1 0x0 #define MAC_CONF2 0x1 #define MAX_FRM 0x4 #define NETIOR_GMAC_CTRL1 0x7F #define NETIOR_GMAC_CTRL2 0x7E #define NETIOR_GMAC_CTRL3 0x7C #define SGMII_CAL_SLOTS 3 #define XAUI_CAL_SLOTS 13 #define IL8_CAL_SLOTS 26 #define IL4_CAL_SLOTS 10 #define NAE_DRR_QUANTA 2048 #define XLP3XX_STG2_FIFO_SZ 512 #define XLP3XX_EH_FIFO_SZ 512 #define XLP3XX_FROUT_FIFO_SZ 512 #define XLP3XX_MS_FIFO_SZ 512 #define XLP3XX_PKT_FIFO_SZ 8192 #define XLP3XX_PKTLEN_FIFO_SZ 512 #define XLP3XX_MAX_STG2_OFFSET 0x7F #define XLP3XX_MAX_EH_OFFSET 0x1f #define XLP3XX_MAX_FREE_OUT_OFFSET 0x1f #define XLP3XX_MAX_MS_OFFSET 0xF #define XLP3XX_MAX_PMEM_OFFSET 0x7FE #define XLP3XX_STG1_2_CREDIT XLP3XX_STG2_FIFO_SZ #define XLP3XX_STG2_EH_CREDIT XLP3XX_EH_FIFO_SZ #define XLP3XX_STG2_FROUT_CREDIT XLP3XX_FROUT_FIFO_SZ #define XLP3XX_STG2_MS_CREDIT XLP3XX_MS_FIFO_SZ #define XLP8XX_STG2_FIFO_SZ 2048 #define XLP8XX_EH_FIFO_SZ 4096 #define XLP8XX_FROUT_FIFO_SZ 4096 #define XLP8XX_MS_FIFO_SZ 2048 #define XLP8XX_PKT_FIFO_SZ 16384 #define XLP8XX_PKTLEN_FIFO_SZ 2048 #define XLP8XX_MAX_STG2_OFFSET 0x7F #define XLP8XX_MAX_EH_OFFSET 0x7F #define XLP8XX_MAX_FREE_OUT_OFFSET 0x7F #define XLP8XX_MAX_MS_OFFSET 0x1F #define XLP8XX_MAX_PMEM_OFFSET 0x7FE #define XLP8XX_STG1_2_CREDIT XLP8XX_STG2_FIFO_SZ #define XLP8XX_STG2_EH_CREDIT XLP8XX_EH_FIFO_SZ #define XLP8XX_STG2_FROUT_CREDIT XLP8XX_FROUT_FIFO_SZ #define XLP8XX_STG2_MS_CREDIT XLP8XX_MS_FIFO_SZ #define MAX_CAL_SLOTS 64 #define XLP_MAX_PORTS 18 #define XLP_STORM_MAX_PORTS 8 #define MAX_FREE_FIFO_POOL_8XX 20 #define MAX_FREE_FIFO_POOL_3XX 9 #if !defined(LOCORE) && !defined(__ASSEMBLY__) #define nlm_read_nae_reg(b, r) nlm_read_reg_xkphys(b, r) #define nlm_write_nae_reg(b, r, v) nlm_write_reg_xkphys(b, r, v) #define nlm_get_nae_pcibase(node) \ nlm_pcicfg_base(XLP_IO_NAE_OFFSET(node)) #define nlm_get_nae_regbase(node) \ nlm_xkphys_map_pcibar0(nlm_get_nae_pcibase(node)) #define MAX_POE_CLASSES 8 #define MAX_POE_CLASS_CTXT_TBL_SZ ((NUM_CONTEXTS / MAX_POE_CLASSES) + 1) #define TXINITIORCR(x) (((x) & 0x7ffff) << 8) enum XLPNAE_TX_TYPE { P2D_NEOP = 0, P2P, P2D_EOP, MSC }; enum nblock_type { UNKNOWN = 0, /* DONT MAKE IT NON-ZERO */ SGMIIC = 1, XAUIC = 2, ILC = 3 }; enum nae_interface_type { GMAC_0 = 0, GMAC_1, GMAC_2, GMAC_3, XGMAC, INTERLAKEN, PHY = 0xE, LANE_CFG = 0xF, }; enum { LM_UNCONNECTED = 0, LM_SGMII = 1, LM_XAUI = 2, LM_IL = 3, }; enum nae_block { BLOCK_0 = 0, BLOCK_1, BLOCK_2, BLOCK_3, BLOCK_4, BLOCK_5, BLOCK_6, BLOCK_7, }; enum { PHYMODE_NONE = 0, PHYMODE_HS_SGMII = 1, PHYMODE_XAUI = 1, PHYMODE_SGMII = 2, PHYMODE_IL = 3, }; static __inline int nae_num_complex(uint64_t nae_pcibase) { return (nlm_read_reg(nae_pcibase, XLP_PCI_DEVINFO_REG0) & 0xff); } static __inline int nae_num_context(uint64_t nae_pcibase) { return (nlm_read_reg(nae_pcibase, XLP_PCI_DEVINFO_REG5)); } /* per port config structure */ struct nae_port_config { int node; /* node id (quickread) */ int block; /* network block id (quickread) */ int port; /* port id - among the 18 in XLP */ int type; /* port type - see xlp_gmac_port_types */ int mdio_bus; int phy_addr; int num_channels; int num_free_descs; int free_desc_sizes; int ucore_mask; int loopback_mode; /* is complex is in loopback? */ uint32_t freein_spill_size; /* Freein spill size for each port */ uint32_t free_fifo_size; /* (512entries x 2desc/entry)1024desc */ uint32_t iface_fifo_size;/* 256 entries x 64B/entry = 16KB */ uint32_t pseq_fifo_size; /* 1024 entries - 1 pktlen/entry */ uint32_t rxbuf_size; /* 4096 entries x 64B = 256KB */ uint32_t rx_if_base_config; uint32_t rx_slots_reqd; uint32_t tx_slots_reqd; uint32_t stg2_fifo_size; uint32_t eh_fifo_size; uint32_t frout_fifo_size; uint32_t ms_fifo_size; uint32_t pkt_fifo_size; uint32_t pktlen_fifo_size; uint32_t max_stg2_offset; uint32_t max_eh_offset; uint32_t max_frout_offset; uint32_t max_ms_offset; uint32_t max_pmem_offset; uint32_t stg1_2_credit; uint32_t stg2_eh_credit; uint32_t stg2_frout_credit; uint32_t stg2_ms_credit; uint32_t vlan_pri_en; uint32_t txq; uint32_t rxfreeq; uint32_t ieee1588_inc_intg; uint32_t ieee1588_inc_den; uint32_t ieee1588_inc_num; uint64_t ieee1588_userval; uint64_t ieee1588_ptpoff; uint64_t ieee1588_tmr1; uint64_t ieee1588_tmr2; uint64_t ieee1588_tmr3; }; void nlm_nae_flush_free_fifo(uint64_t nae_base, int nblocks); void nlm_program_nae_parser_seq_fifo(uint64_t, int, struct nae_port_config *); void nlm_setup_rx_cal_cfg(uint64_t, int, struct nae_port_config *); void nlm_setup_tx_cal_cfg(uint64_t, int, struct nae_port_config *cfg); void nlm_deflate_frin_fifo_carving(uint64_t, int); void nlm_reset_nae(int); int nlm_set_nae_frequency(int, int); void nlm_setup_poe_class_config(uint64_t nae_base, int max_poe_classes, int num_contexts, int *poe_cl_tbl); void nlm_setup_vfbid_mapping(uint64_t); void nlm_setup_flow_crc_poly(uint64_t, uint32_t); void nlm_setup_iface_fifo_cfg(uint64_t, int, struct nae_port_config *); void nlm_setup_rx_base_config(uint64_t, int, struct nae_port_config *); void nlm_setup_rx_buf_config(uint64_t, int, struct nae_port_config *); void nlm_setup_freein_fifo_cfg(uint64_t, struct nae_port_config *); int nlm_get_flow_mask(int); void nlm_program_flow_cfg(uint64_t, int, uint32_t, uint32_t); void xlp_ax_nae_lane_reset_txpll(uint64_t, int, int, int); void xlp_nae_lane_reset_txpll(uint64_t, int, int, int); void xlp_nae_config_lane_gmac(uint64_t, int); void config_egress_fifo_carvings(uint64_t, int, int, int, int, struct nae_port_config *); void config_egress_fifo_credits(uint64_t, int, int, int, int, struct nae_port_config *); void nlm_config_freein_fifo_uniq_cfg(uint64_t, int, int); void nlm_config_ucore_iface_mask_cfg(uint64_t, int, int); int nlm_nae_init_netior(uint64_t nae_base, int nblocks); void nlm_nae_init_ingress(uint64_t, uint32_t); void nlm_nae_init_egress(uint64_t); uint32_t ucore_spray_config(uint32_t, uint32_t, int); void nlm_nae_init_ucore(uint64_t nae_base, int if_num, uint32_t ucore_mask); int nlm_nae_open_if(uint64_t, int, int, int, uint32_t); void nlm_mac_enable(uint64_t, int, int, int); void nlm_mac_disable(uint64_t, int, int, int); uint64_t nae_tx_desc(u_int, u_int, u_int, u_int, uint64_t); void nlm_setup_l2type(uint64_t, int, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); void nlm_setup_l3ctable_mask(uint64_t, int, uint32_t, uint32_t); void nlm_setup_l3ctable_even(uint64_t, int, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); void nlm_setup_l3ctable_odd(uint64_t, int, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); void nlm_setup_l4ctable_even(uint64_t, int, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, uint32_t); void nlm_setup_l4ctable_odd(uint64_t, int, uint32_t, uint32_t, uint32_t, uint32_t); void nlm_enable_hardware_parser(uint64_t); void nlm_enable_hardware_parser_per_port(uint64_t, int, int); void nlm_prepad_enable(uint64_t, int); void nlm_setup_1588_timer(uint64_t, struct nae_port_config *); #endif /* !(LOCORE) && !(__ASSEMBLY__) */ #endif Index: head/sys/mips/nlm/hal/nlm_hal.c =================================================================== --- head/sys/mips/nlm/hal/nlm_hal.c (revision 326258) +++ head/sys/mips/nlm/hal/nlm_hal.c (revision 326259) @@ -1,112 +1,114 @@ /*- + * 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 uint32_t xlp_get_cpu_frequency(int node, int core) { uint64_t sysbase = nlm_get_sys_regbase(node); unsigned int pll_divf, pll_divr, dfs_div, ext_div; unsigned int rstval, dfsval; rstval = nlm_read_sys_reg(sysbase, SYS_POWER_ON_RESET_CFG); dfsval = nlm_read_sys_reg(sysbase, SYS_CORE_DFS_DIV_VALUE); pll_divf = ((rstval >> 10) & 0x7f) + 1; pll_divr = ((rstval >> 8) & 0x3) + 1; if (!nlm_is_xlp8xx_ax()) ext_div = ((rstval >> 30) & 0x3) + 1; else ext_div = 1; dfs_div = ((dfsval >> (core << 2)) & 0xf) + 1; return ((800000000ULL * pll_divf)/(3 * pll_divr * ext_div * dfs_div)); } static u_int nlm_get_device_frequency(uint64_t sysbase, int devtype) { uint32_t pllctrl, dfsdiv, spf, spr, div_val; int extra_div; pllctrl = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL); if (devtype <= 7) div_val = nlm_read_sys_reg(sysbase, SYS_DFS_DIV_VALUE0); else { devtype -= 8; div_val = nlm_read_sys_reg(sysbase, SYS_DFS_DIV_VALUE1); } dfsdiv = ((div_val >> (devtype << 2)) & 0xf) + 1; spf = (pllctrl >> 3 & 0x7f) + 1; spr = (pllctrl >> 1 & 0x03) + 1; if (devtype == DFS_DEVICE_NAE && !nlm_is_xlp8xx_ax()) extra_div = 2; else extra_div = 1; return ((400 * spf) / (3 * extra_div * spr * dfsdiv)); } int nlm_set_device_frequency(int node, int devtype, int frequency) { uint64_t sysbase; u_int cur_freq; int dec_div; sysbase = nlm_get_sys_regbase(node); cur_freq = nlm_get_device_frequency(sysbase, devtype); if (cur_freq < (frequency - 5)) dec_div = 1; else dec_div = 0; for(;;) { if ((cur_freq >= (frequency - 5)) && (cur_freq <= frequency)) break; if (dec_div) nlm_write_sys_reg(sysbase, SYS_DFS_DIV_DEC_CTRL, (1 << devtype)); else nlm_write_sys_reg(sysbase, SYS_DFS_DIV_INC_CTRL, (1 << devtype)); cur_freq = nlm_get_device_frequency(sysbase, devtype); } return (nlm_get_device_frequency(sysbase, devtype)); } Index: head/sys/mips/nlm/hal/nlmsaelib.h =================================================================== --- head/sys/mips/nlm/hal/nlmsaelib.h (revision 326258) +++ head/sys/mips/nlm/hal/nlmsaelib.h (revision 326259) @@ -1,605 +1,607 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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$ */ #ifndef _NLM_HAL_CRYPTO_H_ #define _NLM_HAL_CRYPTO_H_ #define SAE_CFG_REG 0x00 #define SAE_ENG_SEL_0 0x01 #define SAE_ENG_SEL_1 0x02 #define SAE_ENG_SEL_2 0x03 #define SAE_ENG_SEL_3 0x04 #define SAE_ENG_SEL_4 0x05 #define SAE_ENG_SEL_5 0x06 #define SAE_ENG_SEL_6 0x07 #define SAE_ENG_SEL_7 0x08 #define RSA_CFG_REG 0x00 #define RSA_ENG_SEL_0 0x01 #define RSA_ENG_SEL_1 0x02 #define RSA_ENG_SEL_2 0x03 #define nlm_read_sec_reg(b, r) nlm_read_reg(b, r) #define nlm_write_sec_reg(b, r, v) nlm_write_reg(b, r, v) #define nlm_get_sec_pcibase(node) nlm_pcicfg_base(XLP_IO_SEC_OFFSET(node)) #define nlm_get_sec_regbase(node) \ (nlm_get_sec_pcibase(node) + XLP_IO_PCI_HDRSZ) #define nlm_read_rsa_reg(b, r) nlm_read_reg(b, r) #define nlm_write_rsa_reg(b, r, v) nlm_write_reg(b, r, v) #define nlm_get_rsa_pcibase(node) nlm_pcicfg_base(XLP_IO_RSA_OFFSET(node)) #define nlm_get_rsa_regbase(node) \ (nlm_get_rsa_pcibase(node) + XLP_IO_PCI_HDRSZ) #define nlm_pcibase_sec(node) nlm_pcicfg_base(XLP_IO_SEC_OFFSET(node)) #define nlm_qidstart_sec(node) nlm_qidstart_kseg(nlm_pcibase_sec(node)) #define nlm_qnum_sec(node) nlm_qnum_kseg(nlm_pcibase_sec(node)) /* * Since buffer allocation for crypto at kernel is done as malloc, each * segment size is given as page size which is 4K by default */ #define NLM_CRYPTO_MAX_SEG_LEN PAGE_SIZE #define MAX_KEY_LEN_IN_DW 20 #define left_shift64(x, bitshift, numofbits) \ ((uint64_t)(x) << (bitshift)) #define left_shift64_mask(x, bitshift, numofbits) \ (((uint64_t)(x) & ((1ULL << (numofbits)) - 1)) << (bitshift)) /** * @brief cipher algorithms * @ingroup crypto */ enum nlm_cipher_algo { NLM_CIPHER_BYPASS = 0, NLM_CIPHER_DES = 1, NLM_CIPHER_3DES = 2, NLM_CIPHER_AES128 = 3, NLM_CIPHER_AES192 = 4, NLM_CIPHER_AES256 = 5, NLM_CIPHER_ARC4 = 6, NLM_CIPHER_KASUMI_F8 = 7, NLM_CIPHER_SNOW3G_F8 = 8, NLM_CIPHER_CAMELLIA128 = 9, NLM_CIPHER_CAMELLIA192 = 0xA, NLM_CIPHER_CAMELLIA256 = 0xB, NLM_CIPHER_MAX = 0xC, }; /** * @brief cipher modes * @ingroup crypto */ enum nlm_cipher_mode { NLM_CIPHER_MODE_ECB = 0, NLM_CIPHER_MODE_CBC = 1, NLM_CIPHER_MODE_CFB = 2, NLM_CIPHER_MODE_OFB = 3, NLM_CIPHER_MODE_CTR = 4, NLM_CIPHER_MODE_AES_F8 = 5, NLM_CIPHER_MODE_GCM = 6, NLM_CIPHER_MODE_CCM = 7, NLM_CIPHER_MODE_UNDEFINED1 = 8, NLM_CIPHER_MODE_UNDEFINED2 = 9, NLM_CIPHER_MODE_LRW = 0xA, NLM_CIPHER_MODE_XTS = 0xB, NLM_CIPHER_MODE_MAX = 0xC, }; /** * @brief hash algorithms * @ingroup crypto */ enum nlm_hash_algo { NLM_HASH_BYPASS = 0, NLM_HASH_MD5 = 1, NLM_HASH_SHA = 2, NLM_HASH_UNDEFINED = 3, NLM_HASH_AES128 = 4, NLM_HASH_AES192 = 5, NLM_HASH_AES256 = 6, NLM_HASH_KASUMI_F9 = 7, NLM_HASH_SNOW3G_F9 = 8, NLM_HASH_CAMELLIA128 = 9, NLM_HASH_CAMELLIA192 = 0xA, NLM_HASH_CAMELLIA256 = 0xB, NLM_HASH_GHASH = 0xC, NLM_HASH_MAX = 0xD }; /** * @brief hash modes * @ingroup crypto */ enum nlm_hash_mode { NLM_HASH_MODE_SHA1 = 0, /* Only SHA */ NLM_HASH_MODE_SHA224 = 1, /* Only SHA */ NLM_HASH_MODE_SHA256 = 2, /* Only SHA */ NLM_HASH_MODE_SHA384 = 3, /* Only SHA */ NLM_HASH_MODE_SHA512 = 4, /* Only SHA */ NLM_HASH_MODE_CMAC = 5, /* AES and Camellia */ NLM_HASH_MODE_XCBC = 6, /* AES and Camellia */ NLM_HASH_MODE_CBC_MAC = 7, /* AES and Camellia */ NLM_HASH_MODE_CCM = 8, /* AES */ NLM_HASH_MODE_GCM = 9, /* AES */ NLM_HASH_MODE_MAX = 0xA, }; /** * @brief crypto control descriptor, should be cache aligned * @ingroup crypto */ struct nlm_crypto_pkt_ctrl { uint64_t desc0; /* combination of cipher and hash keys */ uint64_t key[MAX_KEY_LEN_IN_DW]; uint32_t cipherkeylen; uint32_t hashkeylen; uint32_t taglen; }; /** * @brief crypto packet descriptor, should be cache aligned * @ingroup crypto */ struct nlm_crypto_pkt_param { uint64_t desc0; uint64_t desc1; uint64_t desc2; uint64_t desc3; uint64_t segment[1][2]; }; static __inline__ uint64_t nlm_crypto_form_rsa_ecc_fmn_entry0(unsigned int l3alloc, unsigned int type, unsigned int func, uint64_t srcaddr) { return (left_shift64(l3alloc, 61, 1) | left_shift64(type, 46, 7) | left_shift64(func, 40, 6) | left_shift64(srcaddr, 0, 40)); } static __inline__ uint64_t nlm_crypto_form_rsa_ecc_fmn_entry1(unsigned int dstclobber, unsigned int l3alloc, unsigned int fbvc, uint64_t dstaddr) { return (left_shift64(dstclobber, 62, 1) | left_shift64(l3alloc, 61, 1) | left_shift64(fbvc, 40, 12) | left_shift64(dstaddr, 0, 40)); } /** * @brief Generate cypto control descriptor * @ingroup crypto * hmac : 1 for hash with hmac * hashalg, see hash_alg enums * hashmode, see hash_mode enums * cipherhalg, see cipher_alg enums * ciphermode, see cipher_mode enums * arc4_cipherkeylen : length of arc4 cipher key, 0 is interpreted as 32 * arc4_keyinit : * cfbmask : cipher text for feedback, * 0(1 bit), 1(2 bits), 2(4 bits), 3(8 bits), 4(16bits), 5(32 bits), * 6(64 bits), 7(128 bits) */ static __inline__ uint64_t nlm_crypto_form_pkt_ctrl_desc(unsigned int hmac, unsigned int hashalg, unsigned int hashmode, unsigned int cipheralg, unsigned int ciphermode, unsigned int arc4_cipherkeylen, unsigned int arc4_keyinit, unsigned int cfbmask) { return (left_shift64(hmac, 61, 1) | left_shift64(hashalg, 52, 8) | left_shift64(hashmode, 43, 8) | left_shift64(cipheralg, 34, 8) | left_shift64(ciphermode, 25, 8) | left_shift64(arc4_cipherkeylen, 18, 5) | left_shift64(arc4_keyinit, 17, 1) | left_shift64(cfbmask, 0, 3)); } /** * @brief Generate cypto packet descriptor 0 * @ingroup crypto * tls : 1 (tls enabled) 0(tls disabled) * hash_source : 1 (encrypted data is sent to the auth engine) * 0 (plain data is sent to the auth engine) * hashout_l3alloc : 1 (auth output is transited through l3 cache) * encrypt : 1 (for encrypt) 0 (for decrypt) * ivlen : iv length in bytes * hashdst_addr : hash out physical address, byte aligned */ static __inline__ uint64_t nlm_crypto_form_pkt_desc0(unsigned int tls, unsigned int hash_source, unsigned int hashout_l3alloc, unsigned int encrypt, unsigned int ivlen, uint64_t hashdst_addr) { return (left_shift64(tls, 63, 1) | left_shift64(hash_source, 62, 1) | left_shift64(hashout_l3alloc, 60, 1) | left_shift64(encrypt, 59, 1) | left_shift64_mask((ivlen - 1), 41, 16) | left_shift64(hashdst_addr, 0, 40)); } /** * @brief Generate cypto packet descriptor 1 * @ingroup crypto * cipherlen : cipher length in bytes * hashlen : hash length in bytes */ static __inline__ uint64_t nlm_crypto_form_pkt_desc1(unsigned int cipherlen, unsigned int hashlen) { return (left_shift64_mask((cipherlen - 1), 32, 32) | left_shift64_mask((hashlen - 1), 0, 32)); } /** * @brief Generate cypto packet descriptor 2 * @ingroup crypto * ivoff : iv offset, offset from start of src data addr * ciperbit_cnt : number of valid bits in the last input byte to the cipher, * 0 (8 bits), 1 (1 bit)..7 (7 bits) * cipheroff : cipher offset, offset from start of src data addr * hashbit_cnt : number of valid bits in the last input byte to the auth * 0 (8 bits), 1 (1 bit)..7 (7 bits) * hashclobber : 1 (hash output will be written as multiples of cachelines, no * read modify write) * hashoff : hash offset, offset from start of src data addr */ static __inline__ uint64_t nlm_crypto_form_pkt_desc2(unsigned int ivoff, unsigned int cipherbit_cnt, unsigned int cipheroff, unsigned int hashbit_cnt, unsigned int hashclobber, unsigned int hashoff) { return (left_shift64(ivoff , 45, 16) | left_shift64(cipherbit_cnt, 42, 3) | left_shift64(cipheroff, 22, 16) | left_shift64(hashbit_cnt, 19, 3) | left_shift64(hashclobber, 18, 1) | left_shift64(hashoff, 0, 16)); } /** * @brief Generate cypto packet descriptor 3 * @ingroup crypto * designer_vc : designer freeback fmn destination id * taglen : length in bits of the tag generated by the auth engine * md5 (128 bits), sha1 (160), sha224 (224), sha384 (384), * sha512 (512), Kasumi (32), snow3g (32), gcm (128) * hmacpad : 1 if hmac padding is already done */ static __inline__ uint64_t nlm_crypto_form_pkt_desc3(unsigned int designer_vc, unsigned int taglen, unsigned int arc4_state_save_l3, unsigned int arc4_save_state, unsigned int hmacpad) { return (left_shift64(designer_vc, 48, 16) | left_shift64(taglen, 11, 16) | left_shift64(arc4_state_save_l3, 8, 1) | left_shift64(arc4_save_state, 6, 1) | left_shift64(hmacpad, 5, 1)); } /** * @brief Generate cypto packet descriptor 4 * @ingroup crypto * srcfraglen : length of the source fragment(header + data + tail) in bytes * srcfragaddr : physical address of the srouce fragment */ static __inline__ uint64_t nlm_crypto_form_pkt_desc4(uint64_t srcfraglen, unsigned int srcfragaddr ) { return (left_shift64_mask((srcfraglen - 1), 48, 16) | left_shift64(srcfragaddr, 0, 40)); } /** * @brief Generate cypto packet descriptor 5 * @ingroup crypto * dstfraglen : length of the dst fragment(header + data + tail) in bytes * chipherout_l3alloc : 1(cipher output is transited through l3 cache) * cipherclobber : 1 (cipher output will be written as multiples of cachelines, * no read modify write) * chiperdst_addr : physical address of the cipher destination address */ static __inline__ uint64_t nlm_crypto_form_pkt_desc5(unsigned int dstfraglen, unsigned int cipherout_l3alloc, unsigned int cipherclobber, uint64_t cipherdst_addr) { return (left_shift64_mask((dstfraglen - 1), 48, 16) | left_shift64(cipherout_l3alloc, 46, 1) | left_shift64(cipherclobber, 41, 1) | left_shift64(cipherdst_addr, 0, 40)); } /** * @brief Generate crypto packet fmn message entry 0 * @ingroup crypto * freeback_vc: freeback response destination address * designer_fblen : Designer freeback length, 1 - 4 * designerdesc_valid : designer desc valid or not * cipher_keylen : cipher key length in bytes * ctrldesc_addr : physicall address of the control descriptor */ static __inline__ uint64_t nlm_crypto_form_pkt_fmn_entry0(unsigned int freeback_vc, unsigned int designer_fblen, unsigned int designerdesc_valid, unsigned int cipher_keylen, uint64_t cntldesc_addr) { return (left_shift64(freeback_vc, 48, 16) | left_shift64_mask(designer_fblen - 1, 46, 2) | left_shift64(designerdesc_valid, 45, 1) | left_shift64_mask(((cipher_keylen + 7) >> 3), 40, 5) | left_shift64(cntldesc_addr >> 6, 0, 34)); } /** * @brief Generate crypto packet fmn message entry 1 * @ingroup crypto * arc4load_state : 1 if load state required 0 otherwise * hash_keylen : hash key length in bytes * pktdesc_size : packet descriptor size in bytes * pktdesc_addr : physicall address of the packet descriptor */ static __inline__ uint64_t nlm_crypto_form_pkt_fmn_entry1(unsigned int arc4load_state, unsigned int hash_keylen, unsigned int pktdesc_size, uint64_t pktdesc_addr) { return (left_shift64(arc4load_state, 63, 1) | left_shift64_mask(((hash_keylen + 7) >> 3), 56, 5) | left_shift64_mask(((pktdesc_size >> 4) - 1), 43, 12) | left_shift64(pktdesc_addr >> 6, 0, 34)); } static __inline__ int nlm_crypto_get_hklen_taglen(enum nlm_hash_algo hashalg, enum nlm_hash_mode hashmode, unsigned int *taglen, unsigned int *hklen) { if (hashalg == NLM_HASH_MD5) { *taglen = 128; *hklen = 64; } else if (hashalg == NLM_HASH_SHA) { switch (hashmode) { case NLM_HASH_MODE_SHA1: *taglen = 160; *hklen = 64; break; case NLM_HASH_MODE_SHA224: *taglen = 224; *hklen = 64; break; case NLM_HASH_MODE_SHA256: *taglen = 256; *hklen = 64; break; case NLM_HASH_MODE_SHA384: *taglen = 384; *hklen = 128; break; case NLM_HASH_MODE_SHA512: *taglen = 512; *hklen = 128; break; default: printf("Error : invalid shaid (%s)\n", __func__); return (-1); } } else if (hashalg == NLM_HASH_KASUMI_F9) { *taglen = 32; *hklen = 0; } else if (hashalg == NLM_HASH_SNOW3G_F9) { *taglen = 32; *hklen = 0; } else if (hashmode == NLM_HASH_MODE_XCBC) { *taglen = 128; *hklen = 0; } else if (hashmode == NLM_HASH_MODE_GCM) { *taglen = 128; *hklen = 0; } else if (hashalg == NLM_HASH_BYPASS) { *taglen = 0; *hklen = 0; } else { printf("Error:Hash alg/mode not found\n"); return (-1); } /* TODO : Add remaining cases */ return (0); } /** * @brief Generate fill cryto control info structure * @ingroup crypto * hmac : 1 for hash with hmac * hashalg: see above, hash_alg enums * hashmode: see above, hash_mode enums * cipherhalg: see above, cipher_alg enums * ciphermode: see above, cipher_mode enums * */ static __inline__ int nlm_crypto_fill_pkt_ctrl(struct nlm_crypto_pkt_ctrl *ctrl, unsigned int hmac, enum nlm_hash_algo hashalg, enum nlm_hash_mode hashmode, enum nlm_cipher_algo cipheralg, enum nlm_cipher_mode ciphermode, unsigned char *cipherkey, unsigned int cipherkeylen, unsigned char *hashkey, unsigned int hashkeylen) { unsigned int taglen = 0, hklen = 0; ctrl->desc0 = nlm_crypto_form_pkt_ctrl_desc(hmac, hashalg, hashmode, cipheralg, ciphermode, 0, 0, 0); memset(ctrl->key, 0, sizeof(ctrl->key)); if (cipherkey) memcpy(ctrl->key, cipherkey, cipherkeylen); if (hashkey) memcpy((unsigned char *)&ctrl->key[(cipherkeylen + 7) / 8], hashkey, hashkeylen); if (nlm_crypto_get_hklen_taglen(hashalg, hashmode, &taglen, &hklen) < 0) return (-1); ctrl->cipherkeylen = cipherkeylen; ctrl->hashkeylen = hklen; ctrl->taglen = taglen; /* TODO : add the invalid checks and return error */ return (0); } /** * @brief Top level function for generation pkt desc 0 to 3 for cipher auth * @ingroup crypto * ctrl : pointer to control structure * param : pointer to the param structure * encrypt : 1(for encrypt) 0(for decrypt) * hash_source : 1(encrypted data is sent to the auth engine) 0(plain data is * sent to the auth engine) * ivoff : iv offset from start of data * ivlen : iv length in bytes * hashoff : hash offset from start of data * hashlen : hash length in bytes * hmacpad : hmac padding required or not, 1 if already padded * cipheroff : cipher offset from start of data * cipherlen : cipher length in bytes * hashdst_addr : hash destination physical address */ static __inline__ void nlm_crypto_fill_cipher_auth_pkt_param(struct nlm_crypto_pkt_ctrl *ctrl, struct nlm_crypto_pkt_param *param, unsigned int encrypt, unsigned int hash_source, unsigned int ivoff, unsigned int ivlen, unsigned int hashoff, unsigned int hashlen, unsigned int hmacpad, unsigned int cipheroff, unsigned int cipherlen, unsigned char *hashdst_addr) { param->desc0 = nlm_crypto_form_pkt_desc0(0, hash_source, 1, encrypt, ivlen, vtophys(hashdst_addr)); param->desc1 = nlm_crypto_form_pkt_desc1(cipherlen, hashlen); param->desc2 = nlm_crypto_form_pkt_desc2(ivoff, 0, cipheroff, 0, 0, hashoff); param->desc3 = nlm_crypto_form_pkt_desc3(0, ctrl->taglen, 0, 0, hmacpad); } /** * @brief Top level function for generation pkt desc 0 to 3 for cipher operation * @ingroup crypto * ctrl : pointer to control structure * param : pointer to the param structure * encrypt : 1(for encrypt) 0(for decrypt) * ivoff : iv offset from start of data * ivlen : iv length in bytes * cipheroff : cipher offset from start of data * cipherlen : cipher length in bytes */ static __inline__ void nlm_crypto_fill_cipher_pkt_param(struct nlm_crypto_pkt_ctrl *ctrl, struct nlm_crypto_pkt_param *param, unsigned int encrypt, unsigned int ivoff, unsigned int ivlen, unsigned int cipheroff, unsigned int cipherlen) { param->desc0 = nlm_crypto_form_pkt_desc0(0, 0, 0, encrypt, ivlen, 0ULL); param->desc1 = nlm_crypto_form_pkt_desc1(cipherlen, 1); param->desc2 = nlm_crypto_form_pkt_desc2(ivoff, 0, cipheroff, 0, 0, 0); param->desc3 = nlm_crypto_form_pkt_desc3(0, ctrl->taglen, 0, 0, 0); } /** * @brief Top level function for generation pkt desc 0 to 3 for auth operation * @ingroup crypto * ctrl : pointer to control structure * param : pointer to the param structure * hashoff : hash offset from start of data * hashlen : hash length in bytes * hmacpad : hmac padding required or not, 1 if already padded * hashdst_addr : hash destination physical address */ static __inline__ void nlm_crypto_fill_auth_pkt_param(struct nlm_crypto_pkt_ctrl *ctrl, struct nlm_crypto_pkt_param *param, unsigned int hashoff, unsigned int hashlen, unsigned int hmacpad, unsigned char *hashdst_addr) { param->desc0 = nlm_crypto_form_pkt_desc0(0, 0, 1, 0, 1, vtophys(hashdst_addr)); param->desc1 = nlm_crypto_form_pkt_desc1(1, hashlen); param->desc2 = nlm_crypto_form_pkt_desc2(0, 0, 0, 0, 0, hashoff); param->desc3 = nlm_crypto_form_pkt_desc3(0, ctrl->taglen, 0, 0, hmacpad); } static __inline__ unsigned int nlm_crypto_fill_src_seg(struct nlm_crypto_pkt_param *param, int seg, unsigned char *input, unsigned int inlen) { unsigned off = 0, len = 0; unsigned int remlen = inlen; for (; remlen > 0;) { len = remlen > NLM_CRYPTO_MAX_SEG_LEN ? NLM_CRYPTO_MAX_SEG_LEN : remlen; param->segment[seg][0] = nlm_crypto_form_pkt_desc4(len, vtophys(input + off)); remlen -= len; off += len; seg++; } return (seg); } static __inline__ unsigned int nlm_crypto_fill_dst_seg(struct nlm_crypto_pkt_param *param, int seg, unsigned char *output, unsigned int outlen) { unsigned off = 0, len = 0; unsigned int remlen = outlen; for (; remlen > 0;) { len = remlen > NLM_CRYPTO_MAX_SEG_LEN ? NLM_CRYPTO_MAX_SEG_LEN : remlen; param->segment[seg][1] = nlm_crypto_form_pkt_desc5(len, 1, 0, vtophys(output + off)); remlen -= len; off += len; seg++; } return (seg); } #endif Index: head/sys/mips/nlm/hal/pcibus.h =================================================================== --- head/sys/mips/nlm/hal/pcibus.h (revision 326258) +++ head/sys/mips/nlm/hal/pcibus.h (revision 326259) @@ -1,121 +1,123 @@ /*- + * 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 * $FreeBSD$ */ #ifndef __XLP_PCIBUS_H__ #define __XLP_PCIBUS_H__ #define MSI_MIPS_ADDR_BASE 0xfee00000 /* MSI support */ #define MSI_MIPS_ADDR_DEST 0x000ff000 #define MSI_MIPS_ADDR_RH 0x00000008 #define MSI_MIPS_ADDR_RH_OFF 0x00000000 #define MSI_MIPS_ADDR_RH_ON 0x00000008 #define MSI_MIPS_ADDR_DM 0x00000004 #define MSI_MIPS_ADDR_DM_PHYSICAL 0x00000000 #define MSI_MIPS_ADDR_DM_LOGICAL 0x00000004 /* Fields in data for Intel MSI messages. */ #define MSI_MIPS_DATA_TRGRMOD 0x00008000 /* Trigger mode */ #define MSI_MIPS_DATA_TRGREDG 0x00000000 /* edge */ #define MSI_MIPS_DATA_TRGRLVL 0x00008000 /* level */ #define MSI_MIPS_DATA_LEVEL 0x00004000 /* Polarity. */ #define MSI_MIPS_DATA_DEASSERT 0x00000000 #define MSI_MIPS_DATA_ASSERT 0x00004000 #define MSI_MIPS_DATA_DELMOD 0x00000700 /* Delivery Mode */ #define MSI_MIPS_DATA_DELFIXED 0x00000000 /* fixed */ #define MSI_MIPS_DATA_DELLOPRI 0x00000100 /* lowest priority */ #define MSI_MIPS_DATA_INTVEC 0x000000ff /* PCIE Memory and IO regions */ #define PCIE_MEM_BASE 0xd0000000ULL #define PCIE_MEM_LIMIT 0xdfffffffULL #define PCIE_IO_BASE 0x14000000ULL #define PCIE_IO_LIMIT 0x15ffffffULL #define PCIE_BRIDGE_CMD 0x1 #define PCIE_BRIDGE_MSI_CAP 0x14 #define PCIE_BRIDGE_MSI_ADDRL 0x15 #define PCIE_BRIDGE_MSI_ADDRH 0x16 #define PCIE_BRIDGE_MSI_DATA 0x17 /* XLP Global PCIE configuration space registers */ #define PCIE_BYTE_SWAP_MEM_BASE 0x247 #define PCIE_BYTE_SWAP_MEM_LIM 0x248 #define PCIE_BYTE_SWAP_IO_BASE 0x249 #define PCIE_BYTE_SWAP_IO_LIM 0x24A #define PCIE_MSI_STATUS 0x25A #define PCIE_MSI_EN 0x25B #define PCIE_INT_EN0 0x261 /* PCIE_MSI_EN */ #define PCIE_MSI_VECTOR_INT_EN 0xFFFFFFFF /* PCIE_INT_EN0 */ #define PCIE_MSI_INT_EN (1 << 9) /* XXXJC: Ax workaround */ #define PCIE_LINK0_IRT 78 #if !defined(LOCORE) && !defined(__ASSEMBLY__) #define nlm_read_pcie_reg(b, r) nlm_read_reg(b, r) #define nlm_write_pcie_reg(b, r, v) nlm_write_reg(b, r, v) #define nlm_get_pcie_base(node, inst) \ nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node, inst)) #define nlm_get_pcie_regbase(node, inst) \ (nlm_get_pcie_base(node, inst) + XLP_IO_PCI_HDRSZ) static __inline int xlp_pcie_link_irt(int link) { if ((link < 0) || (link > 3)) return (-1); return (PCIE_LINK0_IRT + link); } /* * Build Intel MSI message and data values from a source. AMD64 systems * seem to be compatible, so we use the same function for both. */ #define MIPS_MSI_ADDR(cpu) \ (MSI_MIPS_ADDR_BASE | (cpu) << 12 | \ MSI_MIPS_ADDR_RH_OFF | MSI_MIPS_ADDR_DM_PHYSICAL) #define MIPS_MSI_DATA(irq) \ (MSI_MIPS_DATA_TRGRLVL | MSI_MIPS_DATA_DELFIXED | \ MSI_MIPS_DATA_ASSERT | (irq)) #endif #endif /* __XLP_PCIBUS_H__ */ Index: head/sys/mips/nlm/hal/pic.h =================================================================== --- head/sys/mips/nlm/hal/pic.h (revision 326258) +++ head/sys/mips/nlm/hal/pic.h (revision 326259) @@ -1,311 +1,313 @@ /*- + * 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 * $FreeBSD$ */ #ifndef _NLM_HAL_PIC_H #define _NLM_HAL_PIC_H /* PIC Specific registers */ #define PIC_CTRL 0x00 /* PIC control register defines */ #define PIC_CTRL_ITV 32 /* interrupt timeout value */ #define PIC_CTRL_ICI 19 /* ICI interrupt timeout enable */ #define PIC_CTRL_ITE 18 /* interrupt timeout enable */ #define PIC_CTRL_STE 10 /* system timer interrupt enable */ #define PIC_CTRL_WWR1 8 /* watchdog 1 wraparound count for reset */ #define PIC_CTRL_WWR0 6 /* watchdog 0 wraparound count for reset */ #define PIC_CTRL_WWN1 4 /* watchdog 1 wraparound count for NMI */ #define PIC_CTRL_WWN0 2 /* watchdog 0 wraparound count for NMI */ #define PIC_CTRL_WTE 0 /* watchdog timer enable */ /* PIC Status register defines */ #define PIC_ICI_STATUS 33 /* ICI interrupt timeout status */ #define PIC_ITE_STATUS 32 /* interrupt timeout status */ #define PIC_STS_STATUS 4 /* System timer interrupt status */ #define PIC_WNS_STATUS 2 /* NMI status for watchdog timers */ #define PIC_WIS_STATUS 0 /* Interrupt status for watchdog timers */ /* PIC IPI control register offsets */ #define PIC_IPICTRL_NMI 32 #define PIC_IPICTRL_RIV 20 /* received interrupt vector */ #define PIC_IPICTRL_IDB 16 /* interrupt destination base */ #define PIC_IPICTRL_DTE 0 /* interrupt destination thread enables */ /* PIC IRT register offsets */ #define PIC_IRT_ENABLE 31 #define PIC_IRT_NMI 29 #define PIC_IRT_SCH 28 /* Scheduling scheme */ #define PIC_IRT_RVEC 20 /* Interrupt receive vectors */ #define PIC_IRT_DT 19 /* Destination type */ #define PIC_IRT_DB 16 /* Destination base */ #define PIC_IRT_DTE 0 /* Destination thread enables */ #define PIC_BYTESWAP 0x02 #define PIC_STATUS 0x04 #define PIC_INTR_TIMEOUT 0x06 #define PIC_ICI0_INTR_TIMEOUT 0x08 #define PIC_ICI1_INTR_TIMEOUT 0x0a #define PIC_ICI2_INTR_TIMEOUT 0x0c #define PIC_IPI_CTL 0x0e #define PIC_INT_ACK 0x10 #define PIC_INT_PENDING0 0x12 #define PIC_INT_PENDING1 0x14 #define PIC_INT_PENDING2 0x16 #define PIC_WDOG0_MAXVAL 0x18 #define PIC_WDOG0_COUNT 0x1a #define PIC_WDOG0_ENABLE0 0x1c #define PIC_WDOG0_ENABLE1 0x1e #define PIC_WDOG0_BEATCMD 0x20 #define PIC_WDOG0_BEAT0 0x22 #define PIC_WDOG0_BEAT1 0x24 #define PIC_WDOG1_MAXVAL 0x26 #define PIC_WDOG1_COUNT 0x28 #define PIC_WDOG1_ENABLE0 0x2a #define PIC_WDOG1_ENABLE1 0x2c #define PIC_WDOG1_BEATCMD 0x2e #define PIC_WDOG1_BEAT0 0x30 #define PIC_WDOG1_BEAT1 0x32 #define PIC_WDOG_MAXVAL(i) (PIC_WDOG0_MAXVAL + ((i) ? 7 : 0)) #define PIC_WDOG_COUNT(i) (PIC_WDOG0_COUNT + ((i) ? 7 : 0)) #define PIC_WDOG_ENABLE0(i) (PIC_WDOG0_ENABLE0 + ((i) ? 7 : 0)) #define PIC_WDOG_ENABLE1(i) (PIC_WDOG0_ENABLE1 + ((i) ? 7 : 0)) #define PIC_WDOG_BEATCMD(i) (PIC_WDOG0_BEATCMD + ((i) ? 7 : 0)) #define PIC_WDOG_BEAT0(i) (PIC_WDOG0_BEAT0 + ((i) ? 7 : 0)) #define PIC_WDOG_BEAT1(i) (PIC_WDOG0_BEAT1 + ((i) ? 7 : 0)) #define PIC_TIMER0_MAXVAL 0x34 #define PIC_TIMER1_MAXVAL 0x36 #define PIC_TIMER2_MAXVAL 0x38 #define PIC_TIMER3_MAXVAL 0x3a #define PIC_TIMER4_MAXVAL 0x3c #define PIC_TIMER5_MAXVAL 0x3e #define PIC_TIMER6_MAXVAL 0x40 #define PIC_TIMER7_MAXVAL 0x42 #define PIC_TIMER_MAXVAL(i) (PIC_TIMER0_MAXVAL + ((i) * 2)) #define PIC_TIMER0_COUNT 0x44 #define PIC_TIMER1_COUNT 0x46 #define PIC_TIMER2_COUNT 0x48 #define PIC_TIMER3_COUNT 0x4a #define PIC_TIMER4_COUNT 0x4c #define PIC_TIMER5_COUNT 0x4e #define PIC_TIMER6_COUNT 0x50 #define PIC_TIMER7_COUNT 0x52 #define PIC_TIMER_COUNT(i) (PIC_TIMER0_COUNT + ((i) * 2)) #define PIC_ITE0_N0_N1 0x54 #define PIC_ITE1_N0_N1 0x58 #define PIC_ITE2_N0_N1 0x5c #define PIC_ITE3_N0_N1 0x60 #define PIC_ITE4_N0_N1 0x64 #define PIC_ITE5_N0_N1 0x68 #define PIC_ITE6_N0_N1 0x6c #define PIC_ITE7_N0_N1 0x70 #define PIC_ITE_N0_N1(i) (PIC_ITE0_N0_N1 + ((i) * 4)) #define PIC_ITE0_N2_N3 0x56 #define PIC_ITE1_N2_N3 0x5a #define PIC_ITE2_N2_N3 0x5e #define PIC_ITE3_N2_N3 0x62 #define PIC_ITE4_N2_N3 0x66 #define PIC_ITE5_N2_N3 0x6a #define PIC_ITE6_N2_N3 0x6e #define PIC_ITE7_N2_N3 0x72 #define PIC_ITE_N2_N3(i) (PIC_ITE0_N2_N3 + ((i) * 4)) #define PIC_IRT0 0x74 #define PIC_IRT(i) (PIC_IRT0 + ((i) * 2)) #define TIMER_CYCLES_MAXVAL 0xffffffffffffffffULL /* * IRT Map */ #define PIC_IRT_WD_0_INDEX 0 #define PIC_IRT_WD_1_INDEX 1 #define PIC_IRT_WD_NMI_0_INDEX 2 #define PIC_IRT_WD_NMI_1_INDEX 3 #define PIC_IRT_TIMER_0_INDEX 4 #define PIC_IRT_TIMER_1_INDEX 5 #define PIC_IRT_TIMER_2_INDEX 6 #define PIC_IRT_TIMER_3_INDEX 7 #define PIC_IRT_TIMER_4_INDEX 8 #define PIC_IRT_TIMER_5_INDEX 9 #define PIC_IRT_TIMER_6_INDEX 10 #define PIC_IRT_TIMER_7_INDEX 11 #define PIC_IRT_CLOCK_INDEX PIC_IRT_TIMER_7_INDEX #define PIC_IRT_TIMER_INDEX(num) ((num) + PIC_IRT_TIMER_0_INDEX) #define PIC_CLOCK_TIMER 7 #if !defined(LOCORE) && !defined(__ASSEMBLY__) /* * Misc */ #define PIC_IRT_VALID 1 #define PIC_LOCAL_SCHEDULING 1 #define PIC_GLOBAL_SCHEDULING 0 #define nlm_read_pic_reg(b, r) nlm_read_reg64(b, r) #define nlm_write_pic_reg(b, r, v) nlm_write_reg64(b, r, v) #define nlm_get_pic_pcibase(node) nlm_pcicfg_base(XLP_IO_PIC_OFFSET(node)) #define nlm_get_pic_regbase(node) (nlm_get_pic_pcibase(node) + XLP_IO_PCI_HDRSZ) /* IRT and h/w interrupt routines */ static inline int nlm_pic_read_irt(uint64_t base, int irt_index) { return nlm_read_pic_reg(base, PIC_IRT(irt_index)); } static inline void nlm_pic_send_ipi(uint64_t base, int cpu, int vec, int nmi) { uint64_t ipi; int node, ncpu; node = cpu / 32; ncpu = cpu & 0x1f; ipi = ((uint64_t)nmi << 31) | (vec << 20) | (node << 17) | (1 << (cpu & 0xf)); if (ncpu > 15) ipi |= 0x10000; /* Setting bit 16 to select cpus 16-31 */ nlm_write_pic_reg(base, PIC_IPI_CTL, ipi); } static inline uint64_t nlm_pic_read_control(uint64_t base) { return nlm_read_pic_reg(base, PIC_CTRL); } static inline void nlm_pic_write_control(uint64_t base, uint64_t control) { nlm_write_pic_reg(base, PIC_CTRL, control); } static inline void nlm_pic_update_control(uint64_t base, uint64_t control) { uint64_t val; val = nlm_read_pic_reg(base, PIC_CTRL); nlm_write_pic_reg(base, PIC_CTRL, control | val); } static inline void nlm_pic_ack(uint64_t base, int irt_num) { nlm_write_pic_reg(base, PIC_INT_ACK, irt_num); /* Ack the Status register for Watchdog & System timers */ if (irt_num < 12) nlm_write_pic_reg(base, PIC_STATUS, (1 << irt_num)); } static inline void nlm_set_irt_to_cpu(uint64_t base, int irt, int cpu) { uint64_t val; val = nlm_read_pic_reg(base, PIC_IRT(irt)); val |= cpu & 0xf; if (cpu > 15) val |= 1 << 16; nlm_write_pic_reg(base, PIC_IRT(irt), val); } static inline void nlm_pic_write_irt(uint64_t base, int irt_num, int en, int nmi, int sch, int vec, int dt, int db, int dte) { uint64_t val; val = (((uint64_t)en & 0x1) << 31) | ((nmi & 0x1) << 29) | ((sch & 0x1) << 28) | ((vec & 0x3f) << 20) | ((dt & 0x1) << 19) | ((db & 0x7) << 16) | (dte & 0xffff); nlm_write_pic_reg(base, PIC_IRT(irt_num), val); } static inline void nlm_pic_write_irt_direct(uint64_t base, int irt_num, int en, int nmi, int sch, int vec, int cpu) { nlm_pic_write_irt(base, irt_num, en, nmi, sch, vec, 1, (cpu >> 4), /* thread group */ 1 << (cpu & 0xf)); /* thread mask */ } static inline uint64_t nlm_pic_read_timer(uint64_t base, int timer) { return nlm_read_pic_reg(base, PIC_TIMER_COUNT(timer)); } static inline void nlm_pic_write_timer(uint64_t base, int timer, uint64_t value) { nlm_write_pic_reg(base, PIC_TIMER_COUNT(timer), value); } static inline void nlm_pic_set_timer(uint64_t base, int timer, uint64_t value, int irq, int cpu) { uint64_t pic_ctrl; int en, nmi; en = nmi = 0; if (irq > 0) en = 1; else if (irq < 0) { en = nmi = 1; irq = -irq; } nlm_write_pic_reg(base, PIC_TIMER_MAXVAL(timer), value); nlm_pic_write_irt_direct(base, PIC_IRT_TIMER_INDEX(timer), en, nmi, 0, irq, cpu); /* enable the timer */ pic_ctrl = nlm_read_pic_reg(base, PIC_CTRL); pic_ctrl |= (1 << (PIC_CTRL_STE + timer)); nlm_write_pic_reg(base, PIC_CTRL, pic_ctrl); } #endif /* __ASSEMBLY__ */ #endif /* _NLM_HAL_PIC_H */ Index: head/sys/mips/nlm/hal/poe.h =================================================================== --- head/sys/mips/nlm/hal/poe.h (revision 326258) +++ head/sys/mips/nlm/hal/poe.h (revision 326259) @@ -1,352 +1,354 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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$ */ #ifndef __NLM_POE_H__ #define __NLM_POE_H__ /** * @file_name poe.h * @author Netlogic Microsystems * @brief Basic definitions of XLP Packet Order Engine */ /* POE specific registers */ #define POE_CL0_ENQ_SPILL_BASE_LO 0x0 #define POE_CL1_ENQ_SPILL_BASE_LO 0x2 #define POE_CL2_ENQ_SPILL_BASE_LO 0x4 #define POE_CL3_ENQ_SPILL_BASE_LO 0x6 #define POE_CL4_ENQ_SPILL_BASE_LO 0x8 #define POE_CL5_ENQ_SPILL_BASE_LO 0xa #define POE_CL6_ENQ_SPILL_BASE_LO 0xc #define POE_CL7_ENQ_SPILL_BASE_LO 0xe #define POE_CL0_ENQ_SPILL_BASE_HI 0x1 #define POE_CL1_ENQ_SPILL_BASE_HI 0x3 #define POE_CL2_ENQ_SPILL_BASE_HI 0x5 #define POE_CL3_ENQ_SPILL_BASE_HI 0x7 #define POE_CL4_ENQ_SPILL_BASE_HI 0x9 #define POE_CL5_ENQ_SPILL_BASE_HI 0xb #define POE_CL6_ENQ_SPILL_BASE_HI 0xd #define POE_CL7_ENQ_SPILL_BASE_HI 0xf #define POE_CL0_DEQ_SPILL_BASE_LO 0x10 #define POE_CL1_DEQ_SPILL_BASE_LO 0x12 #define POE_CL2_DEQ_SPILL_BASE_LO 0x14 #define POE_CL3_DEQ_SPILL_BASE_LO 0x16 #define POE_CL4_DEQ_SPILL_BASE_LO 0x18 #define POE_CL5_DEQ_SPILL_BASE_LO 0x1a #define POE_CL6_DEQ_SPILL_BASE_LO 0x1c #define POE_CL7_DEQ_SPILL_BASE_LO 0x1e #define POE_CL0_DEQ_SPILL_BASE_HI 0x11 #define POE_CL1_DEQ_SPILL_BASE_HI 0x13 #define POE_CL2_DEQ_SPILL_BASE_HI 0x15 #define POE_CL3_DEQ_SPILL_BASE_HI 0x17 #define POE_CL4_DEQ_SPILL_BASE_HI 0x19 #define POE_CL5_DEQ_SPILL_BASE_HI 0x1b #define POE_CL6_DEQ_SPILL_BASE_HI 0x1d #define POE_CL7_DEQ_SPILL_BASE_HI 0x1f #define POE_MSG_STORAGE_BASE_ADDR_LO 0x20 #define POE_MSG_STORAGE_BASE_ADDR_HI 0x21 #define POE_FBP_BASE_ADDR_LO 0x22 #define POE_FBP_BASE_ADDR_HI 0x23 #define POE_CL0_ENQ_SPILL_MAXLINE_LO 0x24 #define POE_CL1_ENQ_SPILL_MAXLINE_LO 0x25 #define POE_CL2_ENQ_SPILL_MAXLINE_LO 0x26 #define POE_CL3_ENQ_SPILL_MAXLINE_LO 0x27 #define POE_CL4_ENQ_SPILL_MAXLINE_LO 0x28 #define POE_CL5_ENQ_SPILL_MAXLINE_LO 0x29 #define POE_CL6_ENQ_SPILL_MAXLINE_LO 0x2a #define POE_CL7_ENQ_SPILL_MAXLINE_LO 0x2b #define POE_CL0_ENQ_SPILL_MAXLINE_HI 0x2c #define POE_CL1_ENQ_SPILL_MAXLINE_HI 0x2d #define POE_CL2_ENQ_SPILL_MAXLINE_HI 0x2e #define POE_CL3_ENQ_SPILL_MAXLINE_HI 0x2f #define POE_CL4_ENQ_SPILL_MAXLINE_HI 0x30 #define POE_CL5_ENQ_SPILL_MAXLINE_HI 0x31 #define POE_CL6_ENQ_SPILL_MAXLINE_HI 0x32 #define POE_CL7_ENQ_SPILL_MAXLINE_HI 0x33 #define POE_MAX_FLOW_MSG0 0x40 #define POE_MAX_FLOW_MSG1 0x41 #define POE_MAX_FLOW_MSG2 0x42 #define POE_MAX_FLOW_MSG3 0x43 #define POE_MAX_FLOW_MSG4 0x44 #define POE_MAX_FLOW_MSG5 0x45 #define POE_MAX_FLOW_MSG6 0x46 #define POE_MAX_FLOW_MSG7 0x47 #define POE_MAX_MSG_CL0 0x48 #define POE_MAX_MSG_CL1 0x49 #define POE_MAX_MSG_CL2 0x4a #define POE_MAX_MSG_CL3 0x4b #define POE_MAX_MSG_CL4 0x4c #define POE_MAX_MSG_CL5 0x4d #define POE_MAX_MSG_CL6 0x4e #define POE_MAX_MSG_CL7 0x4f #define POE_MAX_LOC_BUF_STG_CL0 0x50 #define POE_MAX_LOC_BUF_STG_CL1 0x51 #define POE_MAX_LOC_BUF_STG_CL2 0x52 #define POE_MAX_LOC_BUF_STG_CL3 0x53 #define POE_MAX_LOC_BUF_STG_CL4 0x54 #define POE_MAX_LOC_BUF_STG_CL5 0x55 #define POE_MAX_LOC_BUF_STG_CL6 0x56 #define POE_MAX_LOC_BUF_STG_CL7 0x57 #define POE_ENQ_MSG_COUNT0_SIZE 0x58 #define POE_ENQ_MSG_COUNT1_SIZE 0x59 #define POE_ENQ_MSG_COUNT2_SIZE 0x5a #define POE_ENQ_MSG_COUNT3_SIZE 0x5b #define POE_ENQ_MSG_COUNT4_SIZE 0x5c #define POE_ENQ_MSG_COUNT5_SIZE 0x5d #define POE_ENQ_MSG_COUNT6_SIZE 0x5e #define POE_ENQ_MSG_COUNT7_SIZE 0x5f #define POE_ERR_MSG_DESCRIP_LO0 0x60 #define POE_ERR_MSG_DESCRIP_LO1 0x62 #define POE_ERR_MSG_DESCRIP_LO2 0x64 #define POE_ERR_MSG_DESCRIP_LO3 0x66 #define POE_ERR_MSG_DESCRIP_HI0 0x61 #define POE_ERR_MSG_DESCRIP_HI1 0x63 #define POE_ERR_MSG_DESCRIP_HI2 0x65 #define POE_ERR_MSG_DESCRIP_HI3 0x67 #define POE_OOO_MSG_CNT_LO 0x68 #define POE_IN_ORDER_MSG_CNT_LO 0x69 #define POE_LOC_BUF_STOR_CNT_LO 0x6a #define POE_EXT_BUF_STOR_CNT_LO 0x6b #define POE_LOC_BUF_ALLOC_CNT_LO 0x6c #define POE_EXT_BUF_ALLOC_CNT_LO 0x6d #define POE_OOO_MSG_CNT_HI 0x6e #define POE_IN_ORDER_MSG_CNT_HI 0x6f #define POE_LOC_BUF_STOR_CNT_HI 0x70 #define POE_EXT_BUF_STOR_CNT_HI 0x71 #define POE_LOC_BUF_ALLOC_CNT_HI 0x72 #define POE_EXT_BUF_ALLOC_CNT_HI 0x73 #define POE_MODE_ERR_FLOW_ID 0x74 #define POE_STATISTICS_ENABLE 0x75 #define POE_MAX_SIZE_FLOW 0x76 #define POE_MAX_SIZE 0x77 #define POE_FBP_SP 0x78 #define POE_FBP_SP_EN 0x79 #define POE_LOC_ALLOC_EN 0x7a #define POE_EXT_ALLOC_EN 0x7b #define POE_DISTR_0_DROP_CNT 0xc0 #define POE_DISTR_1_DROP_CNT 0xc1 #define POE_DISTR_2_DROP_CNT 0xc2 #define POE_DISTR_3_DROP_CNT 0xc3 #define POE_DISTR_4_DROP_CNT 0xc4 #define POE_DISTR_5_DROP_CNT 0xc5 #define POE_DISTR_6_DROP_CNT 0xc6 #define POE_DISTR_7_DROP_CNT 0xc7 #define POE_DISTR_8_DROP_CNT 0xc8 #define POE_DISTR_9_DROP_CNT 0xc9 #define POE_DISTR_10_DROP_CNT 0xca #define POE_DISTR_11_DROP_CNT 0xcb #define POE_DISTR_12_DROP_CNT 0xcc #define POE_DISTR_13_DROP_CNT 0xcd #define POE_DISTR_14_DROP_CNT 0xce #define POE_DISTR_15_DROP_CNT 0xcf #define POE_CLASS_0_DROP_CNT 0xd0 #define POE_CLASS_1_DROP_CNT 0xd1 #define POE_CLASS_2_DROP_CNT 0xd2 #define POE_CLASS_3_DROP_CNT 0xd3 #define POE_CLASS_4_DROP_CNT 0xd4 #define POE_CLASS_5_DROP_CNT 0xd5 #define POE_CLASS_6_DROP_CNT 0xd6 #define POE_CLASS_7_DROP_CNT 0xd7 #define POE_DISTR_C0_DROP_CNT 0xd8 #define POE_DISTR_C1_DROP_CNT 0xd9 #define POE_DISTR_C2_DROP_CNT 0xda #define POE_DISTR_C3_DROP_CNT 0xdb #define POE_DISTR_C4_DROP_CNT 0xdc #define POE_DISTR_C5_DROP_CNT 0xdd #define POE_DISTR_C6_DROP_CNT 0xde #define POE_DISTR_C7_DROP_CNT 0xdf #define POE_CPU_DROP_CNT 0xe0 #define POE_MAX_FLOW_DROP_CNT 0xe1 #define POE_INTERRUPT_VEC 0x140 #define POE_INTERRUPT_MASK 0x141 #define POE_FATALERR_MASK 0x142 #define POE_IDI_CFG 0x143 #define POE_TIMEOUT_VALUE 0x144 #define POE_CACHE_ALLOC_EN 0x145 #define POE_FBP_ECC_ERR_CNT 0x146 #define POE_MSG_STRG_ECC_ERR_CNT 0x147 #define POE_FID_INFO_ECC_ERR_CNT 0x148 #define POE_MSG_INFO_ECC_ERR_CNT 0x149 #define POE_LL_ECC_ERR_CNT 0x14a #define POE_SIZE_ECC_ERR_CNT 0x14b #define POE_FMN_TXCR_ECC_ERR_CNT 0x14c #define POE_ENQ_INSPIL_ECC_ERR_CNT 0x14d #define POE_ENQ_OUTSPIL_ECC_ERR_CNT 0x14e #define POE_DEQ_OUTSPIL_ECC_ERR_CNT 0x14f #define POE_ENQ_MSG_SENT 0x150 #define POE_ENQ_MSG_CNT 0x151 #define POE_FID_RDATA 0x152 #define POE_FID_WDATA 0x153 #define POE_FID_CMD 0x154 #define POE_FID_ADDR 0x155 #define POE_MSG_INFO_CMD 0x156 #define POE_MSG_INFO_ADDR 0x157 #define POE_MSG_INFO_RDATA 0x158 #define POE_LL_CMD 0x159 #define POE_LL_ADDR 0x15a #define POE_LL_RDATA 0x15b #define POE_MSG_STG_CMD 0x15c #define POE_MSG_STG_ADDR 0x15d #define POE_MSG_STG_RDATA 0x15e #define POE_DISTR_THRESHOLD_0 0x1c0 #define POE_DISTR_THRESHOLD_1 0x1c1 #define POE_DISTR_THRESHOLD_2 0x1c2 #define POE_DISTR_THRESHOLD_3 0x1c3 #define POE_DISTR_THRESHOLD_4 0x1c4 #define POE_DISTR_THRESHOLD(i) (0x1c0 + (i)) #define POE_DISTR_EN 0x1c5 #define POE_ENQ_SPILL_THOLD 0x1c8 #define POE_DEQ_SPILL_THOLD 0x1c9 #define POE_DEQ_SPILL_TIMER 0x1ca #define POE_DISTR_CLASS_DROP_EN 0x1cb #define POE_DISTR_VEC_DROP_EN 0x1cc #define POE_DISTR_DROP_TIMER 0x1cd #define POE_ERROR_LOG_W0 0x1ce #define POE_ERROR_LOG_W1 0x1cf #define POE_ERROR_LOG_W2 0x1d0 #define POE_ERR_INJ_CTRL0 0x1d1 #define POE_TX_TIMER 0x1d4 #define NUM_DIST_VEC 16 #define NUM_WORDS_PER_DV 16 #define MAX_DV_TBL_ENTRIES (NUM_DIST_VEC * NUM_WORDS_PER_DV) #define POE_DIST_THRESHOLD_VAL 0xa /* * POE distribution vectors * * Each vector is 512 bit with msb indicating vc 512 and lsb indicating vc 0 * 512-bit-vector is specified as 16 32-bit words. * Left most word has the vc range 511-479 right most word has vc range 31 - 0 * Each word has the MSB select higer vc number and LSB select lower vc num */ #define POE_DISTVECT_BASE 0x100 #define POE_DISTVECT(vec) (POE_DISTVECT_BASE + 16 * (vec)) #define POE_DISTVECT_OFFSET(node,cpu) (4 * (3 - (node)) + (3 - (cpu)/8)) #define POE_DISTVECT_SHIFT(node,cpu) (((cpu) % 8 ) * 4) #if !defined(LOCORE) && !defined(__ASSEMBLY__) #define nlm_read_poe_reg(b, r) nlm_read_reg(b, r) #define nlm_write_poe_reg(b, r, v) nlm_write_reg(b, r, v) #define nlm_read_poedv_reg(b, r) nlm_read_reg_xkphys(b, r) #define nlm_write_poedv_reg(b, r, v) nlm_write_reg_xkphys(b, r, v) #define nlm_get_poe_pcibase(node) \ nlm_pcicfg_base(XLP_IO_POE_OFFSET(node)) #define nlm_get_poe_regbase(node) \ (nlm_get_poe_pcibase(node) + XLP_IO_PCI_HDRSZ) #define nlm_get_poedv_regbase(node) \ nlm_xkphys_map_pcibar0(nlm_get_poe_pcibase(node)) static __inline int nlm_poe_max_flows(uint64_t poe_pcibase) { return (nlm_read_reg(poe_pcibase, XLP_PCI_DEVINFO_REG0)); } /* * Helper function, calculate the distribution vector * cm0, cm1, cm2, cm3 : CPU masks for nodes 0..3 * thr_vcmask: destination VCs for a thread */ static __inline void nlm_calc_poe_distvec(uint32_t cm0, uint32_t cm1, uint32_t cm2, uint32_t cm3, uint32_t thr_vcmask, uint32_t *distvec) { uint32_t cpumask = 0, val; int i, cpu, node, startcpu, index; thr_vcmask &= 0xf; for (node = 0; node < XLP_MAX_NODES; node++) { switch (node) { case 0: cpumask = cm0; break; case 1: cpumask = cm1; break; case 2: cpumask = cm2; break; case 3: cpumask = cm3; break; } for (i = 0; i < 4; i++) { val = 0; startcpu = 31 - i * 8; for (cpu = startcpu; cpu >= startcpu - 7; cpu--) { val <<= 4; if (cpumask & (1U << cpu)) val |= thr_vcmask; } index = POE_DISTVECT_OFFSET(node, startcpu); distvec[index] = val; } } } static __inline int nlm_write_poe_distvec(uint64_t poedv_base, int vec, uint32_t *distvec) { uint32_t reg; int i; if (vec < 0 || vec >= NUM_DIST_VEC) return (-1); for (i = 0; i < NUM_WORDS_PER_DV; i++) { reg = POE_DISTVECT(vec) + i; nlm_write_poedv_reg(poedv_base, reg, distvec[i]); } return (0); } static __inline void nlm_config_poe(uint64_t poe_base, uint64_t poedv_base) { uint32_t zerodv[NUM_WORDS_PER_DV]; int i; /* First disable distribution vector logic */ nlm_write_poe_reg(poe_base, POE_DISTR_EN, 0); memset(zerodv, 0, sizeof(zerodv)); for (i = 0; i < NUM_DIST_VEC; i++) nlm_write_poe_distvec(poedv_base, i, zerodv); /* set the threshold */ for (i = 0; i < 5; i++) nlm_write_poe_reg(poe_base, POE_DISTR_THRESHOLD(i), POE_DIST_THRESHOLD_VAL); nlm_write_poe_reg(poe_base, POE_DISTR_EN, 1); /* always enable local message store */ nlm_write_poe_reg(poe_base, POE_LOC_ALLOC_EN, 1); nlm_write_poe_reg(poe_base, POE_TX_TIMER, 0x3); } #endif /* !(LOCORE) && !(__ASSEMBLY__) */ #endif Index: head/sys/mips/nlm/hal/sgmii.h =================================================================== --- head/sys/mips/nlm/hal/sgmii.h (revision 326258) +++ head/sys/mips/nlm/hal/sgmii.h (revision 326259) @@ -1,217 +1,219 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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$ */ #ifndef __NLM_SGMII_H__ #define __NLM_SGMII_H__ /** * @file_name sgmii.h * @author Netlogic Microsystems * @brief Basic definitions of XLP SGMII ports */ #define SGMII_MAC_CONF1(block, i) NAE_REG(block, i, 0x00) #define SGMII_MAC_CONF2(block, i) NAE_REG(block, i, 0x01) #define SGMII_IPG_IFG(block, i) NAE_REG(block, i, 0x02) #define SGMII_HLF_DUP(block, i) NAE_REG(block, i, 0x03) #define SGMII_MAX_FRAME(block, i) NAE_REG(block, i, 0x04) #define SGMII_TEST(block, i) NAE_REG(block, i, 0x07) #define SGMII_MIIM_CONF(block, i) NAE_REG(block, i, 0x08) #define SGMII_MIIM_CMD(block, i) NAE_REG(block, i, 0x09) #define SGMII_MIIM_ADDR(block, i) NAE_REG(block, i, 0x0a) #define SGMII_MIIM_CTRL(block, i) NAE_REG(block, i, 0x0b) #define SGMII_MIIM_STAT(block, i) NAE_REG(block, i, 0x0c) #define SGMII_MIIM_IND(block, i) NAE_REG(block, i, 0x0d) #define SGMII_IO_CTRL(block, i) NAE_REG(block, i, 0x0e) #define SGMII_IO_STAT(block, i) NAE_REG(block, i, 0x0f) #define SGMII_STATS_MLR(block, i) NAE_REG(block, i, 0x1f) #define SGMII_STATS_TR64(block, i) NAE_REG(block, i, 0x20) #define SGMII_STATS_TR127(block, i) NAE_REG(block, i, 0x21) #define SGMII_STATS_TR255(block, i) NAE_REG(block, i, 0x22) #define SGMII_STATS_TR511(block, i) NAE_REG(block, i, 0x23) #define SGMII_STATS_TR1K(block, i) NAE_REG(block, i, 0x24) #define SGMII_STATS_TRMAX(block, i) NAE_REG(block, i, 0x25) #define SGMII_STATS_TRMGV(block, i) NAE_REG(block, i, 0x26) #define SGMII_STATS_RBYT(block, i) NAE_REG(block, i, 0x27) #define SGMII_STATS_RPKT(block, i) NAE_REG(block, i, 0x28) #define SGMII_STATS_RFCS(block, i) NAE_REG(block, i, 0x29) #define SGMII_STATS_RMCA(block, i) NAE_REG(block, i, 0x2a) #define SGMII_STATS_RBCA(block, i) NAE_REG(block, i, 0x2b) #define SGMII_STATS_RXCF(block, i) NAE_REG(block, i, 0x2c) #define SGMII_STATS_RXPF(block, i) NAE_REG(block, i, 0x2d) #define SGMII_STATS_RXUO(block, i) NAE_REG(block, i, 0x2e) #define SGMII_STATS_RALN(block, i) NAE_REG(block, i, 0x2f) #define SGMII_STATS_RFLR(block, i) NAE_REG(block, i, 0x30) #define SGMII_STATS_RCDE(block, i) NAE_REG(block, i, 0x31) #define SGMII_STATS_RCSE(block, i) NAE_REG(block, i, 0x32) #define SGMII_STATS_RUND(block, i) NAE_REG(block, i, 0x33) #define SGMII_STATS_ROVR(block, i) NAE_REG(block, i, 0x34) #define SGMII_STATS_RFRG(block, i) NAE_REG(block, i, 0x35) #define SGMII_STATS_RJBR(block, i) NAE_REG(block, i, 0x36) #define SGMII_STATS_TBYT(block, i) NAE_REG(block, i, 0x38) #define SGMII_STATS_TPKT(block, i) NAE_REG(block, i, 0x39) #define SGMII_STATS_TMCA(block, i) NAE_REG(block, i, 0x3a) #define SGMII_STATS_TBCA(block, i) NAE_REG(block, i, 0x3b) #define SGMII_STATS_TXPF(block, i) NAE_REG(block, i, 0x3c) #define SGMII_STATS_TDFR(block, i) NAE_REG(block, i, 0x3d) #define SGMII_STATS_TEDF(block, i) NAE_REG(block, i, 0x3e) #define SGMII_STATS_TSCL(block, i) NAE_REG(block, i, 0x3f) #define SGMII_STATS_TMCL(block, i) NAE_REG(block, i, 0x40) #define SGMII_STATS_TLCL(block, i) NAE_REG(block, i, 0x41) #define SGMII_STATS_TXCL(block, i) NAE_REG(block, i, 0x42) #define SGMII_STATS_TNCL(block, i) NAE_REG(block, i, 0x43) #define SGMII_STATS_TJBR(block, i) NAE_REG(block, i, 0x46) #define SGMII_STATS_TFCS(block, i) NAE_REG(block, i, 0x47) #define SGMII_STATS_TXCF(block, i) NAE_REG(block, i, 0x48) #define SGMII_STATS_TOVR(block, i) NAE_REG(block, i, 0x49) #define SGMII_STATS_TUND(block, i) NAE_REG(block, i, 0x4a) #define SGMII_STATS_TFRG(block, i) NAE_REG(block, i, 0x4b) #define SGMII_STATS_CAR1(block, i) NAE_REG(block, i, 0x4c) #define SGMII_STATS_CAR2(block, i) NAE_REG(block, i, 0x4d) #define SGMII_STATS_CAM1(block, i) NAE_REG(block, i, 0x4e) #define SGMII_STATS_CAM2(block, i) NAE_REG(block, i, 0x4f) #define SGMII_MAC_ADDR0_LO(block, i) NAE_REG(block, i, 0x50) #define SGMII_MAC_ADDR0_HI(block, i) NAE_REG(block, i, 0x51) #define SGMII_MAC_ADDR1_LO(block, i) NAE_REG(block, i, 0x52) #define SGMII_MAC_ADDR1_HI(block, i) NAE_REG(block, i, 0x53) #define SGMII_MAC_ADDR2_LO(block, i) NAE_REG(block, i, 0x54) #define SGMII_MAC_ADDR2_HI(block, i) NAE_REG(block, i, 0x55) #define SGMII_MAC_ADDR3_LO(block, i) NAE_REG(block, i, 0x56) #define SGMII_MAC_ADDR3_HI(block, i) NAE_REG(block, i, 0x57) #define SGMII_MAC_ADDR_MASK0_LO(block, i) NAE_REG(block, i, 0x58) #define SGMII_MAC_ADDR_MASK0_HI(block, i) NAE_REG(block, i, 0x59) #define SGMII_MAC_ADDR_MASK1_LO(block, i) NAE_REG(block, i, 0x5a) #define SGMII_MAC_ADDR_MASK1_HI(block, i) NAE_REG(block, i, 0x5b) #define SGMII_MAC_FILTER_CONFIG(block, i) NAE_REG(block, i, 0x5c) #define SGMII_HASHTBL_VEC_B31_0(block, i) NAE_REG(block, i, 0x60) #define SGMII_HASHTBL_VEC_B63_32(block, i) NAE_REG(block, i, 0x61) #define SGMII_HASHTBL_VEC_B95_64(block, i) NAE_REG(block, i, 0x62) #define SGMII_HASHTBL_VEC_B127_96(block, i) NAE_REG(block, i, 0x63) #define SGMII_HASHTBL_VEC_B159_128(block, i) NAE_REG(block, i, 0x64) #define SGMII_HASHTBL_VEC_B191_160(block, i) NAE_REG(block, i, 0x65) #define SGMII_HASHTBL_VEC_B223_192(block, i) NAE_REG(block, i, 0x66) #define SGMII_HASHTBL_VEC_B255_224(block, i) NAE_REG(block, i, 0x67) #define SGMII_HASHTBL_VEC_B287_256(block, i) NAE_REG(block, i, 0x68) #define SGMII_HASHTBL_VEC_B319_288(block, i) NAE_REG(block, i, 0x69) #define SGMII_HASHTBL_VEC_B351_320(block, i) NAE_REG(block, i, 0x6a) #define SGMII_HASHTBL_VEC_B383_352(block, i) NAE_REG(block, i, 0x6b) #define SGMII_HASHTBL_VEC_B415_384(block, i) NAE_REG(block, i, 0x6c) #define SGMII_HASHTBL_VEC_B447_416(block, i) NAE_REG(block, i, 0x6d) #define SGMII_HASHTBL_VEC_B479_448(block, i) NAE_REG(block, i, 0x6e) #define SGMII_HASHTBL_VEC_B511_480(block, i) NAE_REG(block, i, 0x6f) #define SGMII_NETIOR_VLANTYPE_FILTER(block, i) NAE_REG(block, i, 0x76) #define SGMII_NETIOR_RXDROP_CNTR(block, i) NAE_REG(block, i, 0x77) #define SGMII_NETIOR_PAUSE_QUANTAMULT(block, i) NAE_REG(block, i, 0x78) #define SGMII_NETIOR_MAC_CTRL_OPCODE(block, i) NAE_REG(block, i, 0x79) #define SGMII_NETIOR_MAC_DA_H(block, i) NAE_REG(block, i, 0x7a) #define SGMII_NETIOR_MAC_DA_L(block, i) NAE_REG(block, i, 0x7b) #define SGMII_NET_IFACE_CTRL3(block, i) NAE_REG(block, i, 0x7c) #define SGMII_NETIOR_GMAC_STAT(block, i) NAE_REG(block, i, 0x7d) #define SGMII_NET_IFACE_CTRL2(block, i) NAE_REG(block, i, 0x7e) #define SGMII_NET_IFACE_CTRL(block, i) NAE_REG(block, i, 0x7f) #if !defined(LOCORE) && !defined(__ASSEMBLY__) /* speed */ enum nlm_sgmii_speed { NLM_SGMII_SPEED_10, NLM_SGMII_SPEED_100, NLM_SGMII_SPEED_1000, NLM_SGMII_SPEED_RSVD }; /* duplexity */ enum nlm_sgmii_duplex_mode { NLM_SGMII_DUPLEX_AUTO, NLM_SGMII_DUPLEX_HALF, NLM_SGMII_DUPLEX_FULL }; /* stats */ enum { nlm_sgmii_stats_mlr, nlm_sgmii_stats_tr64, nlm_sgmii_stats_tr127, nlm_sgmii_stats_tr255, nlm_sgmii_stats_tr511, nlm_sgmii_stats_tr1k, nlm_sgmii_stats_trmax, nlm_sgmii_stats_trmgv, nlm_sgmii_stats_rbyt, nlm_sgmii_stats_rpkt, nlm_sgmii_stats_rfcs, nlm_sgmii_stats_rmca, nlm_sgmii_stats_rbca, nlm_sgmii_stats_rxcf, nlm_sgmii_stats_rxpf, nlm_sgmii_stats_rxuo, nlm_sgmii_stats_raln, nlm_sgmii_stats_rflr, nlm_sgmii_stats_rcde, nlm_sgmii_stats_rcse, nlm_sgmii_stats_rund, nlm_sgmii_stats_rovr, nlm_sgmii_stats_rfrg, nlm_sgmii_stats_rjbr, nlm_sgmii_stats_rdummy, /* not used */ nlm_sgmii_stats_tbyt, nlm_sgmii_stats_tpkt, nlm_sgmii_stats_tmca, nlm_sgmii_stats_tbca, nlm_sgmii_stats_txpf, nlm_sgmii_stats_tdfr, nlm_sgmii_stats_tedf, nlm_sgmii_stats_tscl, nlm_sgmii_stats_tmcl, nlm_sgmii_stats_tlcl, nlm_sgmii_stats_txcl, nlm_sgmii_stats_tncl, nlm_sgmii_stats_tjbr, nlm_sgmii_stats_tfcs, nlm_sgmii_stats_txcf, nlm_sgmii_stats_tovr, nlm_sgmii_stats_tund, nlm_sgmii_stats_tfrg, nlm_sgmii_stats_car1, nlm_sgmii_stats_car2, nlm_sgmii_stats_cam1, nlm_sgmii_stats_cam2 }; void nlm_configure_sgmii_interface(uint64_t, int, int, int, int); void nlm_sgmii_pcs_init(uint64_t, uint32_t); void nlm_nae_setup_mac(uint64_t, int, int, int, int, int, int, int); void nlm_nae_setup_rx_mode_sgmii(uint64_t, int, int, int, int, int, int, int); void nlm_nae_setup_mac_addr_sgmii(uint64_t, int, int, int, uint8_t *); #endif /* !(LOCORE) && !(__ASSEMBLY__) */ #endif Index: head/sys/mips/nlm/hal/sys.h =================================================================== --- head/sys/mips/nlm/hal/sys.h (revision 326258) +++ head/sys/mips/nlm/hal/sys.h (revision 326259) @@ -1,159 +1,161 @@ /*- + * 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 * $FreeBSD$ */ #ifndef __NLM_HAL_SYS_H__ #define __NLM_HAL_SYS_H__ /** * @file_name sys.h * @author Netlogic Microsystems * @brief HAL for System configuration registers */ #define SYS_CHIP_RESET 0x00 #define SYS_POWER_ON_RESET_CFG 0x01 #define SYS_EFUSE_DEVICE_CFG_STATUS0 0x02 #define SYS_EFUSE_DEVICE_CFG_STATUS1 0x03 #define SYS_EFUSE_DEVICE_CFG_STATUS2 0x04 #define SYS_EFUSE_DEVICE_CFG3 0x05 #define SYS_EFUSE_DEVICE_CFG4 0x06 #define SYS_EFUSE_DEVICE_CFG5 0x07 #define SYS_EFUSE_DEVICE_CFG6 0x08 #define SYS_EFUSE_DEVICE_CFG7 0x09 #define SYS_PLL_CTRL 0x0a #define SYS_CPU_RESET 0x0b #define SYS_CPU_NONCOHERENT_MODE 0x0d #define SYS_CORE_DFS_DIS_CTRL 0x0e #define SYS_CORE_DFS_RST_CTRL 0x0f #define SYS_CORE_DFS_BYP_CTRL 0x10 #define SYS_CORE_DFS_PHA_CTRL 0x11 #define SYS_CORE_DFS_DIV_INC_CTRL 0x12 #define SYS_CORE_DFS_DIV_DEC_CTRL 0x13 #define SYS_CORE_DFS_DIV_VALUE 0x14 #define SYS_RESET 0x15 #define SYS_DFS_DIS_CTRL 0x16 #define SYS_DFS_RST_CTRL 0x17 #define SYS_DFS_BYP_CTRL 0x18 #define SYS_DFS_DIV_INC_CTRL 0x19 #define SYS_DFS_DIV_DEC_CTRL 0x1a #define SYS_DFS_DIV_VALUE0 0x1b #define SYS_DFS_DIV_VALUE1 0x1c #define SYS_SENSE_AMP_DLY 0x1d #define SYS_SOC_SENSE_AMP_DLY 0x1e #define SYS_CTRL0 0x1f #define SYS_CTRL1 0x20 #define SYS_TIMEOUT_BS1 0x21 #define SYS_BYTE_SWAP 0x22 #define SYS_VRM_VID 0x23 #define SYS_PWR_RAM_CMD 0x24 #define SYS_PWR_RAM_ADDR 0x25 #define SYS_PWR_RAM_DATA0 0x26 #define SYS_PWR_RAM_DATA1 0x27 #define SYS_PWR_RAM_DATA2 0x28 #define SYS_PWR_UCODE 0x29 #define SYS_CPU0_PWR_STATUS 0x2a #define SYS_CPU1_PWR_STATUS 0x2b #define SYS_CPU2_PWR_STATUS 0x2c #define SYS_CPU3_PWR_STATUS 0x2d #define SYS_CPU4_PWR_STATUS 0x2e #define SYS_CPU5_PWR_STATUS 0x2f #define SYS_CPU6_PWR_STATUS 0x30 #define SYS_CPU7_PWR_STATUS 0x31 #define SYS_STATUS 0x32 #define SYS_INT_POL 0x33 #define SYS_INT_TYPE 0x34 #define SYS_INT_STATUS 0x35 #define SYS_INT_MASK0 0x36 #define SYS_INT_MASK1 0x37 #define SYS_UCO_S_ECC 0x38 #define SYS_UCO_M_ECC 0x39 #define SYS_UCO_ADDR 0x3a #define SYS_PLL_DFS_BYP_CTRL 0x3a /* Bx stepping */ #define SYS_UCO_INSTR 0x3b #define SYS_MEM_BIST0 0x3c #define SYS_MEM_BIST1 0x3d #define SYS_PLL_DFS_DIV_VALUE 0x3d /* Bx stepping */ #define SYS_MEM_BIST2 0x3e #define SYS_MEM_BIST3 0x3f #define SYS_MEM_BIST4 0x40 #define SYS_MEM_BIST5 0x41 #define SYS_MEM_BIST6 0x42 #define SYS_MEM_BIST7 0x43 #define SYS_MEM_BIST8 0x44 #define SYS_MEM_BIST9 0x45 #define SYS_MEM_BIST10 0x46 #define SYS_MEM_BIST11 0x47 #define SYS_MEM_BIST12 0x48 #define SYS_SCRTCH0 0x49 #define SYS_SCRTCH1 0x4a #define SYS_SCRTCH2 0x4b #define SYS_SCRTCH3 0x4c #if !defined(LOCORE) && !defined(__ASSEMBLY__) #define nlm_read_sys_reg(b, r) nlm_read_reg(b, r) #define nlm_write_sys_reg(b, r, v) nlm_write_reg(b, r, v) #define nlm_get_sys_pcibase(node) nlm_pcicfg_base(XLP_IO_SYS_OFFSET(node)) #define nlm_get_sys_regbase(node) (nlm_get_sys_pcibase(node) + XLP_IO_PCI_HDRSZ) enum { /* Don't change order and it must start from zero */ DFS_DEVICE_NAE = 0, DFS_DEVICE_SAE, DFS_DEVICE_RSA, DFS_DEVICE_DTRE, DFS_DEVICE_CMP, DFS_DEVICE_KBP, DFS_DEVICE_DMC, DFS_DEVICE_NAND, DFS_DEVICE_MMC, DFS_DEVICE_NOR, DFS_DEVICE_CORE, DFS_DEVICE_REGEX_SLOW, DFS_DEVICE_REGEX_FAST, DFS_DEVICE_SATA, INVALID_DFS_DEVICE = 0xFF }; static __inline void nlm_sys_enable_block(uint64_t sys_base, int block) { uint32_t dfsdis, mask; mask = 1 << block; dfsdis = nlm_read_sys_reg(sys_base, SYS_DFS_DIS_CTRL); if ((dfsdis & mask) == 0) return; /* already enabled, nothing to do */ dfsdis &= ~mask; nlm_write_sys_reg(sys_base, SYS_DFS_DIS_CTRL, dfsdis); } #endif #endif Index: head/sys/mips/nlm/hal/uart.h =================================================================== --- head/sys/mips/nlm/hal/uart.h (revision 326258) +++ head/sys/mips/nlm/hal/uart.h (revision 326259) @@ -1,188 +1,190 @@ /*- + * 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 * $FreeBSD$ */ #ifndef __XLP_HAL_UART_H__ #define __XLP_HAL_UART_H__ /* UART Specific registers */ #define UART_RX_DATA 0x00 #define UART_TX_DATA 0x00 #define UART_INT_EN 0x01 #define UART_INT_ID 0x02 #define UART_FIFO_CTL 0x02 #define UART_LINE_CTL 0x03 #define UART_MODEM_CTL 0x04 #define UART_LINE_STS 0x05 #define UART_MODEM_STS 0x06 #define UART_DIVISOR0 0x00 #define UART_DIVISOR1 0x01 #define BASE_BAUD (XLP_IO_CLK/16) #define BAUD_DIVISOR(baud) (BASE_BAUD / baud) /* LCR mask values */ #define LCR_5BITS 0x00 #define LCR_6BITS 0x01 #define LCR_7BITS 0x02 #define LCR_8BITS 0x03 #define LCR_STOPB 0x04 #define LCR_PENAB 0x08 #define LCR_PODD 0x00 #define LCR_PEVEN 0x10 #define LCR_PONE 0x20 #define LCR_PZERO 0x30 #define LCR_SBREAK 0x40 #define LCR_EFR_ENABLE 0xbf #define LCR_DLAB 0x80 /* MCR mask values */ #define MCR_DTR 0x01 #define MCR_RTS 0x02 #define MCR_DRS 0x04 #define MCR_IE 0x08 #define MCR_LOOPBACK 0x10 /* FCR mask values */ #define FCR_RCV_RST 0x02 #define FCR_XMT_RST 0x04 #define FCR_RX_LOW 0x00 #define FCR_RX_MEDL 0x40 #define FCR_RX_MEDH 0x80 #define FCR_RX_HIGH 0xc0 /* IER mask values */ #define IER_ERXRDY 0x1 #define IER_ETXRDY 0x2 #define IER_ERLS 0x4 #define IER_EMSC 0x8 #if !defined(LOCORE) && !defined(__ASSEMBLY__) #define nlm_read_uart_reg(b, r) nlm_read_reg(b, r) #define nlm_write_uart_reg(b, r, v) nlm_write_reg(b, r, v) #define nlm_get_uart_pcibase(node, inst) \ nlm_pcicfg_base(XLP_IO_UART_OFFSET(node, inst)) #define nlm_get_uart_regbase(node, inst) \ (nlm_get_uart_pcibase(node, inst) + XLP_IO_PCI_HDRSZ) static inline void nlm_uart_set_baudrate(uint64_t base, int baud) { uint32_t lcr; lcr = nlm_read_uart_reg(base, UART_LINE_CTL); /* enable divisor register, and write baud values */ nlm_write_uart_reg(base, UART_LINE_CTL, lcr | (1 << 7)); nlm_write_uart_reg(base, UART_DIVISOR0, (BAUD_DIVISOR(baud) & 0xff)); nlm_write_uart_reg(base, UART_DIVISOR1, ((BAUD_DIVISOR(baud) >> 8) & 0xff)); /* restore default lcr */ nlm_write_uart_reg(base, UART_LINE_CTL, lcr); } static inline void nlm_uart_outbyte(uint64_t base, char c) { uint32_t lsr; for (;;) { lsr = nlm_read_uart_reg(base, UART_LINE_STS); if (lsr & 0x20) break; } nlm_write_uart_reg(base, UART_TX_DATA, (int)c); } static inline char nlm_uart_inbyte(uint64_t base) { int data, lsr; for (;;) { lsr = nlm_read_uart_reg(base, UART_LINE_STS); if (lsr & 0x80) { /* parity/frame/break-error - push a zero */ data = 0; break; } if (lsr & 0x01) { /* Rx data */ data = nlm_read_uart_reg(base, UART_RX_DATA); break; } } return (char)data; } static inline int nlm_uart_init(uint64_t base, int baud, int databits, int stopbits, int parity, int int_en, int loopback) { uint32_t lcr; lcr = 0; if (databits >= 8) lcr |= LCR_8BITS; else if (databits == 7) lcr |= LCR_7BITS; else if (databits == 6) lcr |= LCR_6BITS; else lcr |= LCR_5BITS; if (stopbits > 1) lcr |= LCR_STOPB; lcr |= parity << 3; /* setup default lcr */ nlm_write_uart_reg(base, UART_LINE_CTL, lcr); /* Reset the FIFOs */ nlm_write_uart_reg(base, UART_LINE_CTL, FCR_RCV_RST | FCR_XMT_RST); nlm_uart_set_baudrate(base, baud); if (loopback) nlm_write_uart_reg(base, UART_MODEM_CTL, 0x1f); if (int_en) nlm_write_uart_reg(base, UART_INT_EN, IER_ERXRDY | IER_ETXRDY); return 0; } #endif /* !LOCORE && !__ASSEMBLY__ */ #endif /* __XLP_HAL_UART_H__ */ Index: head/sys/mips/nlm/hal/ucore_loader.h =================================================================== --- head/sys/mips/nlm/hal/ucore_loader.h (revision 326258) +++ head/sys/mips/nlm/hal/ucore_loader.h (revision 326259) @@ -1,141 +1,143 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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$ */ #ifndef __NLM_UCORE_LOADER_H__ #define __NLM_UCORE_LOADER_H__ /** * @file_name ucore_loader.h * @author Netlogic Microsystems * @brief Ucore loader API header */ #define CODE_SIZE_PER_UCORE (4 << 10) static __inline__ void nlm_ucore_load_image(uint64_t nae_base, int ucore) { uint64_t addr = nae_base + NAE_UCORE_SHARED_RAM_OFFSET + (ucore * CODE_SIZE_PER_UCORE); uint32_t *p = (uint32_t *)ucore_app_bin; int i, size; size = sizeof(ucore_app_bin)/sizeof(uint32_t); for (i = 0; i < size; i++, addr += 4) nlm_store_word_daddr(addr, htobe32(p[i])); /* add a 'nop' if number of instructions are odd */ if (size & 0x1) nlm_store_word_daddr(addr, 0x0); } static __inline int nlm_ucore_write_sharedmem(uint64_t nae_base, int index, uint32_t data) { uint32_t ucore_cfg; uint64_t addr = nae_base + NAE_UCORE_SHARED_RAM_OFFSET; if (index > 128) return (-1); ucore_cfg = nlm_read_nae_reg(nae_base, NAE_RX_UCORE_CFG); /* set iram to zero */ nlm_write_nae_reg(nae_base, NAE_RX_UCORE_CFG, (ucore_cfg & ~(0x1 << 7))); nlm_store_word_daddr(addr + (index * 4), data); /* restore ucore config */ nlm_write_nae_reg(nae_base, NAE_RX_UCORE_CFG, ucore_cfg); return (0); } static __inline uint32_t nlm_ucore_read_sharedmem(uint64_t nae_base, int index) { uint64_t addr = nae_base + NAE_UCORE_SHARED_RAM_OFFSET; uint32_t ucore_cfg, val; ucore_cfg = nlm_read_nae_reg(nae_base, NAE_RX_UCORE_CFG); /* set iram to zero */ nlm_write_nae_reg(nae_base, NAE_RX_UCORE_CFG, (ucore_cfg & ~(0x1 << 7))); val = nlm_load_word_daddr(addr + (index * 4)); /* restore ucore config */ nlm_write_nae_reg(nae_base, NAE_RX_UCORE_CFG, ucore_cfg); return val; } static __inline__ int nlm_ucore_load_all(uint64_t nae_base, uint32_t ucore_mask, int nae_reset_done) { int i, count = 0; uint32_t mask; uint32_t ucore_cfg = 0; mask = ucore_mask & 0xffff; /* Stop all ucores */ if (nae_reset_done == 0) { /* Skip the Ucore reset if NAE reset is done */ ucore_cfg = nlm_read_nae_reg(nae_base, NAE_RX_UCORE_CFG); nlm_write_nae_reg(nae_base, NAE_RX_UCORE_CFG, ucore_cfg | (1 << 24)); /* poll for ucore to get in to a wait state */ do { ucore_cfg = nlm_read_nae_reg(nae_base, NAE_RX_UCORE_CFG); } while ((ucore_cfg & (1 << 25)) == 0); } for (i = 0; i < sizeof(ucore_mask) * NBBY; i++) { if ((mask & (1 << i)) == 0) continue; nlm_ucore_load_image(nae_base, i); count++; } /* Enable per-domain ucores */ ucore_cfg = nlm_read_nae_reg(nae_base, NAE_RX_UCORE_CFG); /* write one to reset bits to put the ucores in reset */ ucore_cfg = ucore_cfg | (((mask) & 0xffff) << 8); nlm_write_nae_reg(nae_base, NAE_RX_UCORE_CFG, ucore_cfg); /* write zero to reset bits to pull them out of reset */ ucore_cfg = ucore_cfg & (~(((mask) & 0xffff) << 8)) & ~(1 << 24); nlm_write_nae_reg(nae_base, NAE_RX_UCORE_CFG, ucore_cfg); return (count); } #endif Index: head/sys/mips/nlm/hal/usb.h =================================================================== --- head/sys/mips/nlm/hal/usb.h (revision 326258) +++ head/sys/mips/nlm/hal/usb.h (revision 326259) @@ -1,59 +1,61 @@ /*- + * 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 * $FreeBSD$ */ #ifndef __NLM_USB_H__ #define __NLM_USB_H__ #define USB_CTL_0 0x01 #define USB_PHY_0 0x0A #define USB_PHY_RESET 0x01 #define USB_PHY_PORT_RESET_0 0x10 #define USB_PHY_PORT_RESET_1 0x20 #define USB_CONTROLLER_RESET 0x01 #define USB_INT_STATUS 0x0E #define USB_INT_EN 0x0F #define USB_PHY_INTERRUPT_EN 0x01 #define USB_OHCI_INTERRUPT_EN 0x02 #define USB_OHCI_INTERRUPT1_EN 0x04 #define USB_OHCI_INTERRUPT2_EN 0x08 #define USB_CTRL_INTERRUPT_EN 0x10 #if !defined(LOCORE) && !defined(__ASSEMBLY__) #define nlm_read_usb_reg(b, r) nlm_read_reg(b,r) #define nlm_write_usb_reg(b, r, v) nlm_write_reg(b,r,v) #define nlm_get_usb_pcibase(node, inst) nlm_pcicfg_base(XLP_IO_USB_OFFSET(node, inst)) #define nlm_get_usb_hcd_base(node, inst) nlm_xkphys_map_pcibar0(nlm_get_usb_pcibase(node, inst)) #define nlm_get_usb_regbase(node, inst) (nlm_get_usb_pcibase(node, inst) + XLP_IO_PCI_HDRSZ) #endif #endif Index: head/sys/mips/nlm/hal/xaui.h =================================================================== --- head/sys/mips/nlm/hal/xaui.h (revision 326258) +++ head/sys/mips/nlm/hal/xaui.h (revision 326259) @@ -1,193 +1,195 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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$ */ #ifndef __NLM_XAUI_H__ #define __NLM_XAUI_H__ /** * @file_name xaui.h * @author Netlogic Microsystems * @brief Basic definitions of XLP XAUI ports */ #define XAUI_CONFIG0(block) NAE_REG(block, 4, 0x00) #define XAUI_CONFIG1(block) NAE_REG(block, 4, 0x01) #define XAUI_CONFIG2(block) NAE_REG(block, 4, 0x02) #define XAUI_CONFIG3(block) NAE_REG(block, 4, 0x03) /* #define XAUI_MAC_ADDR0_LO(block) NAE_REG(block, 4, 0x04) #define XAUI_MAC_ADDR0_HI(block) NAE_REG(block, 4, 0x05) */ #define XAUI_MAX_FRAME_LEN(block) NAE_REG(block, 4, 0x08) #define XAUI_REVISION_LVL(block) NAE_REG(block, 4, 0x0b) #define XAUI_MII_MGMT_CMD(block) NAE_REG(block, 4, 0x10) #define XAUI_MII_MGMT_FIELD(block) NAE_REG(block, 4, 0x11) #define XAUI_MII_MGMT_CFG(block) NAE_REG(block, 4, 0x12) #define XAUI_MIIM_LINK_FALL_VEC(block) NAE_REG(block, 4, 0x13) #define XAUI_MII_MGMT_IND(block) NAE_REG(block, 4, 0x14) #define XAUI_STATS_MLR(block) NAE_REG(block, 4, 0x1f) #define XAUI_STATS_TR64(block) NAE_REG(block, 4, 0x20) #define XAUI_STATS_TR127(block) NAE_REG(block, 4, 0x21) #define XAUI_STATS_TR255(block) NAE_REG(block, 4, 0x22) #define XAUI_STATS_TR511(block) NAE_REG(block, 4, 0x23) #define XAUI_STATS_TR1K(block) NAE_REG(block, 4, 0x24) #define XAUI_STATS_TRMAX(block) NAE_REG(block, 4, 0x25) #define XAUI_STATS_TRMGV(block) NAE_REG(block, 4, 0x26) #define XAUI_STATS_RBYT(block) NAE_REG(block, 4, 0x27) #define XAUI_STATS_RPKT(block) NAE_REG(block, 4, 0x28) #define XAUI_STATS_RFCS(block) NAE_REG(block, 4, 0x29) #define XAUI_STATS_RMCA(block) NAE_REG(block, 4, 0x2a) #define XAUI_STATS_RBCA(block) NAE_REG(block, 4, 0x2b) #define XAUI_STATS_RXCF(block) NAE_REG(block, 4, 0x2c) #define XAUI_STATS_RXPF(block) NAE_REG(block, 4, 0x2d) #define XAUI_STATS_RXUO(block) NAE_REG(block, 4, 0x2e) #define XAUI_STATS_RALN(block) NAE_REG(block, 4, 0x2f) #define XAUI_STATS_RFLR(block) NAE_REG(block, 4, 0x30) #define XAUI_STATS_RCDE(block) NAE_REG(block, 4, 0x31) #define XAUI_STATS_RCSE(block) NAE_REG(block, 4, 0x32) #define XAUI_STATS_RUND(block) NAE_REG(block, 4, 0x33) #define XAUI_STATS_ROVR(block) NAE_REG(block, 4, 0x34) #define XAUI_STATS_RFRG(block) NAE_REG(block, 4, 0x35) #define XAUI_STATS_RJBR(block) NAE_REG(block, 4, 0x36) #define XAUI_STATS_TBYT(block) NAE_REG(block, 4, 0x38) #define XAUI_STATS_TPKT(block) NAE_REG(block, 4, 0x39) #define XAUI_STATS_TMCA(block) NAE_REG(block, 4, 0x3a) #define XAUI_STATS_TBCA(block) NAE_REG(block, 4, 0x3b) #define XAUI_STATS_TXPF(block) NAE_REG(block, 4, 0x3c) #define XAUI_STATS_TDFR(block) NAE_REG(block, 4, 0x3d) #define XAUI_STATS_TEDF(block) NAE_REG(block, 4, 0x3e) #define XAUI_STATS_TSCL(block) NAE_REG(block, 4, 0x3f) #define XAUI_STATS_TMCL(block) NAE_REG(block, 4, 0x40) #define XAUI_STATS_TLCL(block) NAE_REG(block, 4, 0x41) #define XAUI_STATS_TXCL(block) NAE_REG(block, 4, 0x42) #define XAUI_STATS_TNCL(block) NAE_REG(block, 4, 0x43) #define XAUI_STATS_TJBR(block) NAE_REG(block, 4, 0x46) #define XAUI_STATS_TFCS(block) NAE_REG(block, 4, 0x47) #define XAUI_STATS_TXCF(block) NAE_REG(block, 4, 0x48) #define XAUI_STATS_TOVR(block) NAE_REG(block, 4, 0x49) #define XAUI_STATS_TUND(block) NAE_REG(block, 4, 0x4a) #define XAUI_STATS_TFRG(block) NAE_REG(block, 4, 0x4b) #define XAUI_STATS_CAR1(block) NAE_REG(block, 4, 0x4c) #define XAUI_STATS_CAR2(block) NAE_REG(block, 4, 0x4d) #define XAUI_STATS_CAM1(block) NAE_REG(block, 4, 0x4e) #define XAUI_STATS_CAM2(block) NAE_REG(block, 4, 0x4f) #define XAUI_MAC_ADDR0_LO(block) NAE_REG(block, 4, 0x50) #define XAUI_MAC_ADDR0_HI(block) NAE_REG(block, 4, 0x51) #define XAUI_MAC_ADDR1_LO(block) NAE_REG(block, 4, 0x52) #define XAUI_MAC_ADDR1_HI(block) NAE_REG(block, 4, 0x53) #define XAUI_MAC_ADDR2_LO(block) NAE_REG(block, 4, 0x54) #define XAUI_MAC_ADDR2_HI(block) NAE_REG(block, 4, 0x55) #define XAUI_MAC_ADDR3_LO(block) NAE_REG(block, 4, 0x56) #define XAUI_MAC_ADDR3_HI(block) NAE_REG(block, 4, 0x57) #define XAUI_MAC_ADDR_MASK0_LO(block) NAE_REG(block, 4, 0x58) #define XAUI_MAC_ADDR_MASK0_HI(block) NAE_REG(block, 4, 0x59) #define XAUI_MAC_ADDR_MASK1_LO(block) NAE_REG(block, 4, 0x5a) #define XAUI_MAC_ADDR_MASK1_HI(block) NAE_REG(block, 4, 0x5b) #define XAUI_MAC_FILTER_CFG(block) NAE_REG(block, 4, 0x5c) #define XAUI_HASHTBL_VEC_B31_0(block) NAE_REG(block, 4, 0x60) #define XAUI_HASHTBL_VEC_B63_32(block) NAE_REG(block, 4, 0x61) #define XAUI_HASHTBL_VEC_B95_64(block) NAE_REG(block, 4, 0x62) #define XAUI_HASHTBL_VEC_B127_96(block) NAE_REG(block, 4, 0x63) #define XAUI_HASHTBL_VEC_B159_128(block) NAE_REG(block, 4, 0x64) #define XAUI_HASHTBL_VEC_B191_160(block) NAE_REG(block, 4, 0x65) #define XAUI_HASHTBL_VEC_B223_192(block) NAE_REG(block, 4, 0x66) #define XAUI_HASHTBL_VEC_B255_224(block) NAE_REG(block, 4, 0x67) #define XAUI_HASHTBL_VEC_B287_256(block) NAE_REG(block, 4, 0x68) #define XAUI_HASHTBL_VEC_B319_288(block) NAE_REG(block, 4, 0x69) #define XAUI_HASHTBL_VEC_B351_320(block) NAE_REG(block, 4, 0x6a) #define XAUI_HASHTBL_VEC_B383_352(block) NAE_REG(block, 4, 0x6b) #define XAUI_HASHTBL_VEC_B415_384(block) NAE_REG(block, 4, 0x6c) #define XAUI_HASHTBL_VEC_B447_416(block) NAE_REG(block, 4, 0x6d) #define XAUI_HASHTBL_VEC_B479_448(block) NAE_REG(block, 4, 0x6e) #define XAUI_HASHTBL_VEC_B511_480(block) NAE_REG(block, 4, 0x6f) #define XAUI_NETIOR_XGMAC_MISC0(block) NAE_REG(block, 4, 0x76) #define XAUI_NETIOR_RX_ABORT_DROP_COUNT(block) NAE_REG(block, 4, 0x77) #define XAUI_NETIOR_MACCTRL_PAUSE_QUANTA(block) NAE_REG(block, 4, 0x78) #define XAUI_NETIOR_MACCTRL_OPCODE(block) NAE_REG(block, 4, 0x79) #define XAUI_NETIOR_MAC_DA_H(block) NAE_REG(block, 4, 0x7a) #define XAUI_NETIOR_MAC_DA_L(block) NAE_REG(block, 4, 0x7b) #define XAUI_NETIOR_XGMAC_STAT(block) NAE_REG(block, 4, 0x7c) #define XAUI_NETIOR_XGMAC_CTRL3(block) NAE_REG(block, 4, 0x7d) #define XAUI_NETIOR_XGMAC_CTRL2(block) NAE_REG(block, 4, 0x7e) #define XAUI_NETIOR_XGMAC_CTRL1(block) NAE_REG(block, 4, 0x7f) #define LANE_RX_CLK (1 << 0) #define LANE_TX_CLK (1 << 6) #define XAUI_LANE_FAULT 0x400 #define XAUI_CONFIG_0 0 #define XAUI_CONFIG_MACRST 0x80000000 #define XAUI_CONFIG_RSTRCTL 0x00400000 #define XAUI_CONFIG_RSTRFN 0x00200000 #define XAUI_CONFIG_RSTTCTL 0x00040000 #define XAUI_CONFIG_RSTTFN 0x00020000 #define XAUI_CONFIG_RSTMIIM 0x00010000 #define XAUI_CONFIG_1 1 #define XAUI_CONFIG_TCTLEN 0x80000000 #define XAUI_CONFIG_TFEN 0x40000000 #define XAUI_CONFIG_RCTLEN 0x20000000 #define XAUI_CONFIG_RFEN 0x10000000 #define XAUI_CONFIG_DRPLT64 0x00000020 #define XAUI_CONFIG_LENCHK 0x00000008 #define XAUI_CONFIG_GENFCS 0x00000004 #define XAUI_CONFIG_PAD_0 0x00000000 #define XAUI_CONFIG_PAD_64 0x00000001 #define XAUI_CONFIG_PAD_COND 0x00000002 #define XAUI_CONFIG_PAD_68 0x00000003 #define XAUI_PHY_CTRL_1 0x00 #define NETIOR_XGMAC_CTRL1 0x7F #define NETIOR_XGMAC_CTRL3 0x7D #define NETIOR_XGMAC_VLAN_DC_POS 28 #define NETIOR_XGMAC_PHYADDR_POS 23 #define NETIOR_XGMAC_DEVID_POS 18 #define NETIOR_XGMAC_STATS_EN_POS 17 #define NETIOR_XGMAC_TX_PFC_EN_POS 14 #define NETIOR_XGMAC_RX_PFC_EN_POS 13 #define NETIOR_XGMAC_SOFT_RST_POS 11 #define NETIOR_XGMAC_TX_PAUSE_POS 10 #define NETIOR_XGMAC_STATS_CLR_POS 16 #if !defined(LOCORE) && !defined(__ASSEMBLY__) void nlm_xaui_pcs_init(uint64_t, int); void nlm_nae_setup_rx_mode_xaui(uint64_t, int, int, int, int, int, int, int); void nlm_nae_setup_mac_addr_xaui(uint64_t, int, int, int, unsigned char *); void nlm_config_xaui_mtu(uint64_t, int, int, int); void nlm_config_xaui(uint64_t, int, int, int, int); #endif /* !(LOCORE) && !(__ASSEMBLY__) */ #endif Index: head/sys/mips/nlm/interrupt.h =================================================================== --- head/sys/mips/nlm/interrupt.h (revision 326258) +++ head/sys/mips/nlm/interrupt.h (revision 326259) @@ -1,74 +1,76 @@ /*- + * 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 * $FreeBSD$ */ #ifndef _RMI_INTERRUPT_H_ #define _RMI_INTERRUPT_H_ /* Defines for the IRQ numbers */ #define IRQ_IPI 41 /* 8-39 are used by PIC interrupts */ #define IRQ_MSGRING 6 #define IRQ_TIMER 7 #define PIC_IRQ_BASE 8 #define PIC_IRT_LAST_IRQ 39 #define XLP_IRQ_IS_PICINTR(irq) ((irq) >= PIC_IRQ_BASE && \ (irq) <= PIC_IRT_LAST_IRQ) #define PIC_UART_0_IRQ 17 #define PIC_UART_1_IRQ 18 #define PIC_PCIE_0_IRQ 19 #define PIC_PCIE_1_IRQ 20 #define PIC_PCIE_2_IRQ 21 #define PIC_PCIE_3_IRQ 22 #define PIC_PCIE_IRQ(l) (PIC_PCIE_0_IRQ + (l)) #define PIC_USB_0_IRQ 23 #define PIC_USB_1_IRQ 24 #define PIC_USB_2_IRQ 25 #define PIC_USB_3_IRQ 26 #define PIC_USB_4_IRQ 27 #define PIC_USB_IRQ(n) (PIC_USB_0_IRQ + (n)) #define PIC_MMC_IRQ 29 #define PIC_I2C_0_IRQ 30 #define PIC_I2C_1_IRQ 31 #define PIC_I2C_IRQ(n) (PIC_I2C_0_IRQ + (n)) /* * XLR needs custom pre and post handlers for PCI/PCI-e interrupts * XXX: maybe follow i386 intsrc model */ void xlp_enable_irq(int irq); void xlp_set_bus_ack(int irq, void (*ack)(int, void *), void *arg); #endif /* _RMI_INTERRUPT_H_ */ Index: head/sys/mips/nlm/intr_machdep.c =================================================================== --- head/sys/mips/nlm/intr_machdep.c (revision 326258) +++ head/sys/mips/nlm/intr_machdep.c (revision 326259) @@ -1,340 +1,342 @@ /*- + * 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 struct xlp_intrsrc { void (*bus_ack)(int, void *); /* Additional ack */ void *bus_ack_arg; /* arg for additional ack */ struct intr_event *ie; /* event corresponding to intr */ int irq; int irt; }; static struct xlp_intrsrc xlp_interrupts[XLR_MAX_INTR]; static mips_intrcnt_t mips_intr_counters[XLR_MAX_INTR]; static int intrcnt_index; int xlp_irq_to_irt(int irq) { uint32_t offset; switch (irq) { case PIC_UART_0_IRQ: case PIC_UART_1_IRQ: offset = XLP_IO_UART_OFFSET(0, irq - PIC_UART_0_IRQ); return (xlp_socdev_irt(offset)); case PIC_PCIE_0_IRQ: case PIC_PCIE_1_IRQ: case PIC_PCIE_2_IRQ: case PIC_PCIE_3_IRQ: offset = XLP_IO_PCIE_OFFSET(0, irq - PIC_PCIE_0_IRQ); return (xlp_socdev_irt(offset)); case PIC_USB_0_IRQ: case PIC_USB_1_IRQ: case PIC_USB_2_IRQ: case PIC_USB_3_IRQ: case PIC_USB_4_IRQ: offset = XLP_IO_USB_OFFSET(0, irq - PIC_USB_0_IRQ); return (xlp_socdev_irt(offset)); case PIC_I2C_0_IRQ: case PIC_I2C_1_IRQ: offset = XLP_IO_I2C0_OFFSET(0); return (xlp_socdev_irt(offset) + irq - PIC_I2C_0_IRQ); default: printf("ERROR: %s: unknown irq %d\n", __func__, irq); return (-1); } } void xlp_enable_irq(int irq) { uint64_t eimr; eimr = nlm_read_c0_eimr(); nlm_write_c0_eimr(eimr | (1ULL << irq)); } void cpu_establish_softintr(const char *name, driver_filter_t * filt, void (*handler) (void *), void *arg, int irq, int flags, void **cookiep) { panic("Soft interrupts unsupported!\n"); } static void xlp_post_filter(void *source) { struct xlp_intrsrc *src = source; if (src->bus_ack) src->bus_ack(src->irq, src->bus_ack_arg); nlm_pic_ack(xlp_pic_base, src->irt); } static void xlp_pre_ithread(void *source) { struct xlp_intrsrc *src = source; if (src->bus_ack) src->bus_ack(src->irq, src->bus_ack_arg); } static void xlp_post_ithread(void *source) { struct xlp_intrsrc *src = source; nlm_pic_ack(xlp_pic_base, src->irt); } void xlp_set_bus_ack(int irq, void (*ack)(int, void *), void *arg) { struct xlp_intrsrc *src; KASSERT(irq > 0 && irq <= XLR_MAX_INTR, ("%s called for bad hard intr %d", __func__, irq)); /* no locking needed - this will called early in boot */ src = &xlp_interrupts[irq]; KASSERT(src->ie != NULL, ("%s called after IRQ enable for %d.", __func__, irq)); src->bus_ack_arg = arg; src->bus_ack = ack; } void cpu_establish_hardintr(const char *name, driver_filter_t * filt, void (*handler) (void *), void *arg, int irq, int flags, void **cookiep) { struct intr_event *ie; /* descriptor for the IRQ */ struct xlp_intrsrc *src = NULL; int errcode; KASSERT(irq > 0 && irq <= XLR_MAX_INTR , ("%s called for bad hard intr %d", __func__, irq)); /* * Locking - not needed now, because we do this only on * startup from CPU0 */ src = &xlp_interrupts[irq]; ie = src->ie; if (ie == NULL) { /* * PIC based interrupts need ack in PIC, and some SoC * components need additional acks (e.g. PCI) */ if (XLP_IRQ_IS_PICINTR(irq)) errcode = intr_event_create(&ie, src, 0, irq, xlp_pre_ithread, xlp_post_ithread, xlp_post_filter, NULL, "hard intr%d:", irq); else { if (filt == NULL) panic("Unsupported non filter percpu intr %d", irq); errcode = intr_event_create(&ie, src, 0, irq, NULL, NULL, NULL, NULL, "hard intr%d:", irq); } if (errcode) { printf("Could not create event for intr %d\n", irq); return; } src->irq = irq; src->ie = ie; } if (XLP_IRQ_IS_PICINTR(irq)) { /* Set all irqs to CPU 0 for now */ src->irt = xlp_irq_to_irt(irq); nlm_pic_write_irt_direct(xlp_pic_base, src->irt, 1, 0, PIC_LOCAL_SCHEDULING, irq, 0); } intr_event_add_handler(ie, name, filt, handler, arg, intr_priority(flags), flags, cookiep); xlp_enable_irq(irq); } void cpu_intr(struct trapframe *tf) { struct intr_event *ie; uint64_t eirr, eimr; int i; critical_enter(); /* find a list of enabled interrupts */ eirr = nlm_read_c0_eirr(); eimr = nlm_read_c0_eimr(); eirr &= eimr; if (eirr == 0) { critical_exit(); return; } /* * No need to clear the EIRR here as the handler writes to * compare which ACKs the interrupt. */ if (eirr & (1 << IRQ_TIMER)) { intr_event_handle(xlp_interrupts[IRQ_TIMER].ie, tf); critical_exit(); return; } /* FIXME sched pin >? LOCK>? */ for (i = sizeof(eirr) * 8 - 1; i >= 0; i--) { if ((eirr & (1ULL << i)) == 0) continue; ie = xlp_interrupts[i].ie; /* Don't account special IRQs */ switch (i) { case IRQ_IPI: case IRQ_MSGRING: break; default: mips_intrcnt_inc(mips_intr_counters[i]); } /* Ack the IRQ on the CPU */ nlm_write_c0_eirr(1ULL << i); if (intr_event_handle(ie, tf) != 0) { printf("stray interrupt %d\n", i); } } critical_exit(); } void mips_intrcnt_setname(mips_intrcnt_t counter, const char *name) { int idx = counter - intrcnt; KASSERT(counter != NULL, ("mips_intrcnt_setname: NULL counter")); snprintf(intrnames + (MAXCOMLEN + 1) * idx, MAXCOMLEN + 1, "%-*s", MAXCOMLEN, name); } mips_intrcnt_t mips_intrcnt_create(const char* name) { mips_intrcnt_t counter = &intrcnt[intrcnt_index++]; mips_intrcnt_setname(counter, name); return counter; } void cpu_init_interrupts() { int i; char name[MAXCOMLEN + 1]; /* * Initialize all available vectors so spare IRQ * would show up in systat output */ for (i = 0; i < XLR_MAX_INTR; i++) { snprintf(name, MAXCOMLEN + 1, "int%d:", i); mips_intr_counters[i] = mips_intrcnt_create(name); } } static int xlp_pic_probe(device_t); static int xlp_pic_attach(device_t); static int xlp_pic_probe(device_t dev) { if (!ofw_bus_is_compatible(dev, "netlogic,xlp-pic")) return (ENXIO); device_set_desc(dev, "XLP PIC"); return (0); } static int xlp_pic_attach(device_t dev) { return (0); } static device_method_t xlp_pic_methods[] = { DEVMETHOD(device_probe, xlp_pic_probe), DEVMETHOD(device_attach, xlp_pic_attach), DEVMETHOD_END }; static driver_t xlp_pic_driver = { "xlp_pic", xlp_pic_methods, 1, /* no softc */ }; static devclass_t xlp_pic_devclass; DRIVER_MODULE(xlp_pic, simplebus, xlp_pic_driver, xlp_pic_devclass, 0, 0); Index: head/sys/mips/nlm/msgring.h =================================================================== --- head/sys/mips/nlm/msgring.h (revision 326258) +++ head/sys/mips/nlm/msgring.h (revision 326259) @@ -1,52 +1,54 @@ /*- + * 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 * $FreeBSD$ */ #ifndef _NLM_MSGRING_H #define _NLM_MSGRING_H #define CMS_DEFAULT_CREDIT 50 /* * packets are sent to VC 0 of a thread * freebacks are sent to VC 3 of a thread */ #define XLPGE_RX_VC 0 #define XLPGE_FB_VC 3 extern uint32_t xlp_msg_thread_mask; struct nlm_fmn_msg; typedef void (*msgring_handler)(int, int, int, int, struct nlm_fmn_msg *, void *); int register_msgring_handler(int startb, int endb, msgring_handler action, void *arg); int xlp_handle_msg_vc(u_int vcmask, int max_msgs); void xlp_msgring_cpu_init(int, int, int); void xlp_cms_enable_intr(int , int , int , int); #endif /* _NLM_MSGRING_H */ Index: head/sys/mips/nlm/tick.c =================================================================== --- head/sys/mips/nlm/tick.c (revision 326258) +++ head/sys/mips/nlm/tick.c (revision 326259) @@ -1,383 +1,385 @@ /*- + * 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 */ /* * Simple driver for the 32-bit interval counter built in to all * MIPS32 CPUs. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include uint64_t counter_freq; struct timecounter *platform_timecounter; static DPCPU_DEFINE(uint32_t, cycles_per_tick); static uint32_t cycles_per_usec; static DPCPU_DEFINE(volatile uint32_t, counter_upper); static DPCPU_DEFINE(volatile uint32_t, counter_lower_last); static DPCPU_DEFINE(uint32_t, compare_ticks); static DPCPU_DEFINE(uint32_t, lost_ticks); struct clock_softc { int intr_rid; struct resource *intr_res; void *intr_handler; struct timecounter tc; struct eventtimer et; }; static struct clock_softc *softc; /* * Device methods */ static int clock_probe(device_t); static void clock_identify(driver_t *, device_t); static int clock_attach(device_t); static unsigned counter_get_timecount(struct timecounter *tc); void mips_timer_early_init(uint64_t clock_hz) { /* Initialize clock early so that we can use DELAY sooner */ counter_freq = clock_hz; cycles_per_usec = (clock_hz / (1000 * 1000)); } void platform_initclocks(void) { if (platform_timecounter != NULL) tc_init(platform_timecounter); } static uint64_t tick_ticker(void) { uint64_t ret; uint32_t ticktock; uint32_t t_lower_last, t_upper; /* * Disable preemption because we are working with cpu specific data. */ critical_enter(); /* * Note that even though preemption is disabled, interrupts are * still enabled. In particular there is a race with clock_intr() * reading the values of 'counter_upper' and 'counter_lower_last'. * * XXX this depends on clock_intr() being executed periodically * so that 'counter_upper' and 'counter_lower_last' are not stale. */ do { t_upper = DPCPU_GET(counter_upper); t_lower_last = DPCPU_GET(counter_lower_last); } while (t_upper != DPCPU_GET(counter_upper)); ticktock = mips_rd_count(); critical_exit(); /* COUNT register wrapped around */ if (ticktock < t_lower_last) t_upper++; ret = ((uint64_t)t_upper << 32) | ticktock; return (ret); } void mips_timer_init_params(uint64_t platform_counter_freq, int double_count) { /* * XXX: Do not use printf here: uart code 8250 may use DELAY so this * function should be called before cninit. */ counter_freq = platform_counter_freq; /* * XXX: Some MIPS32 cores update the Count register only every two * pipeline cycles. * We know this because of status registers in CP0, make it automatic. */ if (double_count != 0) counter_freq /= 2; cycles_per_usec = counter_freq / (1 * 1000 * 1000); set_cputicker(tick_ticker, counter_freq, 1); } static int sysctl_machdep_counter_freq(SYSCTL_HANDLER_ARGS) { int error; uint64_t freq; if (softc == NULL) return (EOPNOTSUPP); freq = counter_freq; error = sysctl_handle_64(oidp, &freq, sizeof(freq), req); if (error == 0 && req->newptr != NULL) { counter_freq = freq; softc->et.et_frequency = counter_freq; softc->tc.tc_frequency = counter_freq; } return (error); } SYSCTL_PROC(_machdep, OID_AUTO, counter_freq, CTLTYPE_U64 | CTLFLAG_RW, NULL, 0, sysctl_machdep_counter_freq, "QU", "Timecounter frequency in Hz"); static unsigned counter_get_timecount(struct timecounter *tc) { return (mips_rd_count()); } /* * Wait for about n microseconds (at least!). */ void DELAY(int n) { uint32_t cur, last, delta, usecs; /* * This works by polling the timer and counting the number of * microseconds that go by. */ last = mips_rd_count(); delta = usecs = 0; while (n > usecs) { cur = mips_rd_count(); /* Check to see if the timer has wrapped around. */ if (cur < last) delta += cur + (0xffffffff - last) + 1; else delta += cur - last; last = cur; if (delta >= cycles_per_usec) { usecs += delta / cycles_per_usec; delta %= cycles_per_usec; } } } static int clock_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { uint32_t fdiv, div, next; if (period != 0) div = (et->et_frequency * period) >> 32; else div = 0; if (first != 0) fdiv = (et->et_frequency * first) >> 32; else fdiv = div; DPCPU_SET(cycles_per_tick, div); next = mips_rd_count() + fdiv; DPCPU_SET(compare_ticks, next); mips_wr_compare(next); return (0); } static int clock_stop(struct eventtimer *et) { DPCPU_SET(cycles_per_tick, 0); mips_wr_compare(0xffffffff); return (0); } /* * Device section of file below */ static int clock_intr(void *arg) { struct clock_softc *sc = (struct clock_softc *)arg; uint32_t cycles_per_tick; uint32_t count, compare_last, compare_next, lost_ticks; cycles_per_tick = DPCPU_GET(cycles_per_tick); /* * Set next clock edge. */ count = mips_rd_count(); compare_last = DPCPU_GET(compare_ticks); if (cycles_per_tick > 0) { compare_next = count + cycles_per_tick; DPCPU_SET(compare_ticks, compare_next); mips_wr_compare(compare_next); } else /* In one-shot mode timer should be stopped after the event. */ mips_wr_compare(0xffffffff); /* COUNT register wrapped around */ if (count < DPCPU_GET(counter_lower_last)) { DPCPU_SET(counter_upper, DPCPU_GET(counter_upper) + 1); } DPCPU_SET(counter_lower_last, count); if (cycles_per_tick > 0) { /* * Account for the "lost time" between when the timer interrupt * fired and when 'clock_intr' actually started executing. */ lost_ticks = DPCPU_GET(lost_ticks); lost_ticks += count - compare_last; /* * If the COUNT and COMPARE registers are no longer in sync * then make up some reasonable value for the 'lost_ticks'. * * This could happen, for e.g., after we resume normal * operations after exiting the debugger. */ if (lost_ticks > 2 * cycles_per_tick) lost_ticks = cycles_per_tick; while (lost_ticks >= cycles_per_tick) { if (sc->et.et_active) sc->et.et_event_cb(&sc->et, sc->et.et_arg); lost_ticks -= cycles_per_tick; } DPCPU_SET(lost_ticks, lost_ticks); } if (sc->et.et_active) sc->et.et_event_cb(&sc->et, sc->et.et_arg); return (FILTER_HANDLED); } static int clock_probe(device_t dev) { device_set_desc(dev, "Generic MIPS32 ticker"); return (BUS_PROBE_NOWILDCARD); } static void clock_identify(driver_t * drv, device_t parent) { BUS_ADD_CHILD(parent, 0, "clock", 0); } static int clock_attach(device_t dev) { struct clock_softc *sc; if (device_get_unit(dev) != 0) panic("can't attach more clocks"); softc = sc = device_get_softc(dev); cpu_establish_hardintr("compare", clock_intr, NULL, sc, IRQ_TIMER, INTR_TYPE_CLK, &sc->intr_handler); sc->tc.tc_get_timecount = counter_get_timecount; sc->tc.tc_counter_mask = 0xffffffff; sc->tc.tc_frequency = counter_freq; sc->tc.tc_name = "MIPS32"; sc->tc.tc_quality = 800; sc->tc.tc_priv = sc; tc_init(&sc->tc); sc->et.et_name = "MIPS32"; #if 0 sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU; #endif sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_PERCPU; sc->et.et_quality = 800; sc->et.et_frequency = counter_freq; sc->et.et_min_period = 0x00004000LLU; /* To be safe. */ sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; sc->et.et_start = clock_start; sc->et.et_stop = clock_stop; sc->et.et_priv = sc; et_register(&sc->et); return (0); } static device_method_t clock_methods[] = { /* Device interface */ DEVMETHOD(device_probe, clock_probe), DEVMETHOD(device_identify, clock_identify), DEVMETHOD(device_attach, clock_attach), DEVMETHOD(device_detach, bus_generic_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), {0, 0} }; static driver_t clock_driver = { "clock", clock_methods, sizeof(struct clock_softc), }; static devclass_t clock_devclass; DRIVER_MODULE(clock, nexus, clock_driver, clock_devclass, 0, 0); Index: head/sys/mips/nlm/uart_cpu_xlp.c =================================================================== --- head/sys/mips/nlm/uart_cpu_xlp.c (revision 326258) +++ head/sys/mips/nlm/uart_cpu_xlp.c (revision 326259) @@ -1,95 +1,97 @@ /*- + * 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 */ /* * Skeleton of this file was based on respective code for ARM * code written by Olivier Houchard. */ /* * XLRMIPS: This file is hacked from arm/... */ #include "opt_platform.h" #ifndef FDT /* use FDT uart when fdt is enable */ #include "opt_uart.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include bus_space_tag_t uart_bus_space_io; bus_space_tag_t uart_bus_space_mem; int uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) { return (b1->bsh == b2->bsh && b1->bst == b2->bst); } int uart_cpu_getdev(int devtype, struct uart_devinfo *di) { di->ops = uart_getops(&uart_ns8250_class); di->bas.chan = 0; di->bas.bst = rmi_uart_bus_space; di->bas.bsh = nlm_get_uart_regbase(0, BOARD_CONSOLE_UART); di->bas.regshft = 2; /* divisor = rclk / (baudrate * 16); */ di->bas.rclk = XLP_IO_CLK; di->baudrate = BOARD_CONSOLE_SPEED; di->databits = 8; di->stopbits = 1; di->parity = UART_PARITY_NONE; uart_bus_space_io = NULL; uart_bus_space_mem = rmi_uart_bus_space; return (0); } #endif Index: head/sys/mips/nlm/usb_init.c =================================================================== --- head/sys/mips/nlm/usb_init.c (revision 326258) +++ head/sys/mips/nlm/usb_init.c (revision 326259) @@ -1,91 +1,93 @@ /*- + * 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; 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: head/sys/mips/nlm/xlp.h =================================================================== --- head/sys/mips/nlm/xlp.h (revision 326258) +++ head/sys/mips/nlm/xlp.h (revision 326259) @@ -1,137 +1,139 @@ /*- + * 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 * $FreeBSD$ */ #ifndef __NLM_XLP_H__ #define __NLM_XLP_H__ #include #include /* XLP 8xx/4xx A0, A1, A2 CPU COP0 PRIDs */ #define CHIP_PROCESSOR_ID_XLP_8XX 0x10 #define CHIP_PROCESSOR_ID_XLP_3XX 0x11 #define CHIP_PROCESSOR_ID_XLP_416 0x94 #define CHIP_PROCESSOR_ID_XLP_432 0x14 /* Revision id's */ #define XLP_REVISION_A0 0x00 #define XLP_REVISION_A1 0x01 #define XLP_REVISION_A2 0x02 #define XLP_REVISION_B0 0x03 #define XLP_REVISION_B1 0x04 #ifndef LOCORE /* * FreeBSD can be started with few threads and cores turned off, * so have a hardware thread id to FreeBSD cpuid mapping. */ extern int xlp_ncores; extern int xlp_threads_per_core; extern uint32_t xlp_hw_thread_mask; extern int xlp_cpuid_to_hwtid[]; extern int xlp_hwtid_to_cpuid[]; #ifdef SMP extern void xlp_enable_threads(int code); #endif uint32_t xlp_get_cpu_frequency(int node, int core); int nlm_set_device_frequency(int node, int devtype, int frequency); int xlp_irq_to_irt(int irq); static __inline int nlm_processor_id(void) { return ((mips_rd_prid() >> 8) & 0xff); } static __inline int nlm_is_xlp3xx(void) { return (nlm_processor_id() == CHIP_PROCESSOR_ID_XLP_3XX); } static __inline int nlm_is_xlp3xx_ax(void) { uint32_t procid = mips_rd_prid(); int prid = (procid >> 8) & 0xff; int rev = procid & 0xff; return (prid == CHIP_PROCESSOR_ID_XLP_3XX && rev < XLP_REVISION_B0); } static __inline int nlm_is_xlp4xx(void) { int prid = nlm_processor_id(); return (prid == CHIP_PROCESSOR_ID_XLP_432 || prid == CHIP_PROCESSOR_ID_XLP_416); } static __inline int nlm_is_xlp8xx(void) { int prid = nlm_processor_id(); return (prid == CHIP_PROCESSOR_ID_XLP_8XX || prid == CHIP_PROCESSOR_ID_XLP_432 || prid == CHIP_PROCESSOR_ID_XLP_416); } static __inline int nlm_is_xlp8xx_ax(void) { uint32_t procid = mips_rd_prid(); int prid = (procid >> 8) & 0xff; int rev = procid & 0xff; return ((prid == CHIP_PROCESSOR_ID_XLP_8XX || prid == CHIP_PROCESSOR_ID_XLP_432 || prid == CHIP_PROCESSOR_ID_XLP_416) && (rev < XLP_REVISION_B0)); } static __inline int nlm_is_xlp8xx_b0(void) { uint32_t procid = mips_rd_prid(); int prid = (procid >> 8) & 0xff; int rev = procid & 0xff; return ((prid == CHIP_PROCESSOR_ID_XLP_8XX || prid == CHIP_PROCESSOR_ID_XLP_432 || prid == CHIP_PROCESSOR_ID_XLP_416) && rev == XLP_REVISION_B0); } static __inline int xlp_socdev_irt(uint32_t offset) { uint64_t base; base = nlm_pcicfg_base(offset); return (nlm_irtstart(base)); } #endif /* LOCORE */ #endif /* __NLM_XLP_H__ */ Index: head/sys/mips/nlm/xlp_machdep.c =================================================================== --- head/sys/mips/nlm/xlp_machdep.c (revision 326258) +++ head/sys/mips/nlm/xlp_machdep.c (revision 326259) @@ -1,741 +1,743 @@ /*- + * 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 "opt_ddb.h" #include "opt_platform.h" #include #include #include #include #include #include #include #include #include #include #include #include /* cinit() */ #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 #include #include #include #include #include #ifdef FDT #include #include #endif /* 4KB static data aread to keep a copy of the bootload env until the dynamic kenv is setup */ char boot1_env[4096]; uint64_t xlp_cpu_frequency; uint64_t xlp_io_base = MIPS_PHYS_TO_DIRECT_UNCACHED(XLP_DEFAULT_IO_BASE); int xlp_ncores; int xlp_threads_per_core; uint32_t xlp_hw_thread_mask; int xlp_cpuid_to_hwtid[MAXCPU]; int xlp_hwtid_to_cpuid[MAXCPU]; uint64_t xlp_pic_base; static int xlp_mmuval; extern uint32_t _end; extern char XLPResetEntry[], XLPResetEntryEnd[]; static void xlp_setup_core(void) { uint64_t reg; reg = nlm_mfcr(LSU_DEFEATURE); /* Enable Unaligned and L2HPE */ reg |= (1 << 30) | (1 << 23); /* * Experimental : Enable SUE * Speculative Unmap Enable. Enable speculative L2 cache request for * unmapped access. */ reg |= (1ull << 31); /* Clear S1RCM - A0 errata */ reg &= ~0xeull; nlm_mtcr(LSU_DEFEATURE, reg); reg = nlm_mfcr(SCHED_DEFEATURE); /* Experimental: Disable BRU accepting ALU ops - A0 errata */ reg |= (1 << 24); nlm_mtcr(SCHED_DEFEATURE, reg); } static void xlp_setup_mmu(void) { uint32_t pagegrain; if (nlm_threadid() == 0) { nlm_setup_extended_pagemask(0); nlm_large_variable_tlb_en(1); nlm_extended_tlb_en(1); nlm_mmu_setup(0, 0, 0); } /* Enable no-read, no-exec, large-physical-address */ pagegrain = mips_rd_pagegrain(); pagegrain |= (1U << 31) | /* RIE */ (1 << 30) | /* XIE */ (1 << 29); /* ELPA */ mips_wr_pagegrain(pagegrain); } static void xlp_enable_blocks(void) { uint64_t sysbase; int i; for (i = 0; i < XLP_MAX_NODES; i++) { if (!nlm_dev_exists(XLP_IO_SYS_OFFSET(i))) continue; sysbase = nlm_get_sys_regbase(i); nlm_sys_enable_block(sysbase, DFS_DEVICE_RSA); } } static void xlp_parse_mmu_options(void) { uint64_t sysbase; uint32_t cpu_map = xlp_hw_thread_mask; uint32_t core0_thr_mask, core_thr_mask, cpu_rst_mask; int i, j, k; #ifdef SMP if (cpu_map == 0) cpu_map = 0xffffffff; #else /* Uniprocessor! */ if (cpu_map == 0) cpu_map = 0x1; else if (cpu_map != 0x1) { printf("WARNING: Starting uniprocessor kernel on cpumask [0x%lx]!\n" "WARNING: Other CPUs will be unused.\n", (u_long)cpu_map); cpu_map = 0x1; } #endif xlp_ncores = 1; core0_thr_mask = cpu_map & 0xf; switch (core0_thr_mask) { case 1: xlp_threads_per_core = 1; xlp_mmuval = 0; break; case 3: xlp_threads_per_core = 2; xlp_mmuval = 2; break; case 0xf: xlp_threads_per_core = 4; xlp_mmuval = 3; break; default: goto unsupp; } /* Try to find the enabled cores from SYS block */ sysbase = nlm_get_sys_regbase(0); cpu_rst_mask = nlm_read_sys_reg(sysbase, SYS_CPU_RESET) & 0xff; /* XLP 416 does not report this correctly, fix */ if (nlm_processor_id() == CHIP_PROCESSOR_ID_XLP_416) cpu_rst_mask = 0xe; /* Take out cores which do not exist on chip */ for (i = 1; i < XLP_MAX_CORES; i++) { if ((cpu_rst_mask & (1 << i)) == 0) cpu_map &= ~(0xfu << (4 * i)); } /* Verify other cores' CPU masks */ for (i = 1; i < XLP_MAX_CORES; i++) { core_thr_mask = (cpu_map >> (4 * i)) & 0xf; if (core_thr_mask == 0) continue; if (core_thr_mask != core0_thr_mask) goto unsupp; xlp_ncores++; } xlp_hw_thread_mask = cpu_map; /* setup hardware processor id to cpu id mapping */ for (i = 0; i< MAXCPU; i++) xlp_cpuid_to_hwtid[i] = xlp_hwtid_to_cpuid[i] = -1; for (i = 0, k = 0; i < XLP_MAX_CORES; i++) { if (((cpu_map >> (i * 4)) & 0xf) == 0) continue; for (j = 0; j < xlp_threads_per_core; j++) { xlp_cpuid_to_hwtid[k] = i * 4 + j; xlp_hwtid_to_cpuid[i * 4 + j] = k; k++; } } return; unsupp: printf("ERROR : Unsupported CPU mask [use 1,2 or 4 threads per core].\n" "\tcore0 thread mask [%lx], boot cpu mask [%lx].\n", (u_long)core0_thr_mask, (u_long)cpu_map); panic("Invalid CPU mask - halting.\n"); return; } /* Parse cmd line args as env - copied from ar71xx */ static void xlp_parse_bootargs(char *cmdline) { char *n, *v; while ((v = strsep(&cmdline, " \n")) != NULL) { if (*v == '\0') continue; if (*v == '-') { while (*v != '\0') { v++; switch (*v) { case 'a': boothowto |= RB_ASKNAME; break; case 'd': boothowto |= RB_KDB; break; case 'g': boothowto |= RB_GDB; break; case 's': boothowto |= RB_SINGLE; break; case 'v': boothowto |= RB_VERBOSE; break; } } } else { n = strsep(&v, "="); if (v == NULL) kern_setenv(n, "1"); else kern_setenv(n, v); } } } #ifdef FDT static void xlp_bootargs_init(__register_t arg) { char buf[2048]; /* early stack is big enough */ void *dtbp; phandle_t chosen; ihandle_t mask; dtbp = (void *)(intptr_t)arg; #if defined(FDT_DTB_STATIC) /* * In case the device tree blob was not passed as argument try * to use the statically embedded one. */ if (dtbp == NULL) dtbp = &fdt_static_dtb; #endif if (OF_install(OFW_FDT, 0) == FALSE) while (1); if (OF_init((void *)dtbp) != 0) while (1); OF_interpret("perform-fixup", 0); chosen = OF_finddevice("/chosen"); if (OF_getprop(chosen, "cpumask", &mask, sizeof(mask)) != -1) { xlp_hw_thread_mask = mask; } if (OF_getprop(chosen, "bootargs", buf, sizeof(buf)) != -1) xlp_parse_bootargs(buf); } #else /* * arg is a pointer to the environment block, the format of the block is * a=xyz\0b=pqr\0\0 */ static void xlp_bootargs_init(__register_t arg) { char buf[2048]; /* early stack is big enough */ char *p, *v, *n; uint32_t mask; /* * provide backward compat for passing cpu mask as arg */ if (arg & 1) { xlp_hw_thread_mask = arg; return; } p = (void *)(intptr_t)arg; while (*p != '\0') { strlcpy(buf, p, sizeof(buf)); v = buf; n = strsep(&v, "="); if (v == NULL) kern_setenv(n, "1"); else kern_setenv(n, v); p += strlen(p) + 1; } /* CPU mask can be passed thru env */ if (getenv_uint("cpumask", &mask) != 0) xlp_hw_thread_mask = mask; /* command line argument */ v = kern_getenv("bootargs"); if (v != NULL) { strlcpy(buf, v, sizeof(buf)); xlp_parse_bootargs(buf); freeenv(v); } } #endif static void mips_init(void) { init_param1(); init_param2(physmem); mips_cpu_init(); cpuinfo.cache_coherent_dma = TRUE; pmap_bootstrap(); mips_proc0_init(); mutex_init(); #ifdef DDB kdb_init(); if (boothowto & RB_KDB) { kdb_enter("Boot flags requested debugger", NULL); } #endif } unsigned int platform_get_timecount(struct timecounter *tc __unused) { uint64_t count = nlm_pic_read_timer(xlp_pic_base, PIC_CLOCK_TIMER); return (unsigned int)~count; } static void xlp_pic_init(void) { struct timecounter pic_timecounter = { platform_get_timecount, /* get_timecount */ 0, /* no poll_pps */ ~0U, /* counter_mask */ XLP_IO_CLK, /* frequency */ "XLRPIC", /* name */ 2000, /* quality (adjusted in code) */ }; int i; int maxirt; xlp_pic_base = nlm_get_pic_regbase(0); /* TOOD: Add other nodes */ maxirt = nlm_read_reg(nlm_get_pic_pcibase(nlm_nodeid()), XLP_PCI_DEVINFO_REG0); printf("Initializing PIC...@%jx %d IRTs\n", (uintmax_t)xlp_pic_base, maxirt); /* Bind all PIC irqs to cpu 0 */ for (i = 0; i < maxirt; i++) nlm_pic_write_irt(xlp_pic_base, i, 0, 0, 1, 0, 1, 0, 0x1); nlm_pic_set_timer(xlp_pic_base, PIC_CLOCK_TIMER, ~0ULL, 0, 0); platform_timecounter = &pic_timecounter; } #if defined(__mips_n32) || defined(__mips_n64) /* PHYSADDR_64_BIT */ #ifdef XLP_SIM #define XLP_MEM_LIM 0x200000000ULL #else #define XLP_MEM_LIM 0x10000000000ULL #endif #else #define XLP_MEM_LIM 0xfffff000UL #endif static vm_paddr_t xlp_mem_excl[] = { 0, 0, /* for kernel image region, see xlp_mem_init */ 0x0c000000, 0x14000000, /* uboot area, cms queue and other stuff */ 0x1fc00000, 0x1fd00000, /* reset vec */ 0x1e000000, 0x1e200000, /* poe buffers */ }; static int mem_exclude_add(vm_paddr_t *avail, vm_paddr_t mstart, vm_paddr_t mend) { int i, pos; pos = 0; for (i = 0; i < nitems(xlp_mem_excl); i += 2) { if (mstart > xlp_mem_excl[i + 1]) continue; if (mstart < xlp_mem_excl[i]) { avail[pos++] = mstart; if (mend < xlp_mem_excl[i]) avail[pos++] = mend; else avail[pos++] = xlp_mem_excl[i]; } mstart = xlp_mem_excl[i + 1]; if (mend <= mstart) break; } if (mstart < mend) { avail[pos++] = mstart; avail[pos++] = mend; } return (pos); } static void xlp_mem_init(void) { vm_paddr_t physsz, tmp; uint64_t bridgebase, base, lim, val; int i, j, k, n; /* update kernel image area in exclude regions */ tmp = (vm_paddr_t)MIPS_KSEG0_TO_PHYS(&_end); tmp = round_page(tmp) + 0x20000; /* round up */ xlp_mem_excl[1] = tmp; printf("Memory (from DRAM BARs):\n"); bridgebase = nlm_get_bridge_regbase(0); /* TODO: Add other nodes */ physsz = 0; for (i = 0, j = 0; i < 8; i++) { val = nlm_read_bridge_reg(bridgebase, BRIDGE_DRAM_BAR(i)); val = (val >> 12) & 0xfffff; base = val << 20; val = nlm_read_bridge_reg(bridgebase, BRIDGE_DRAM_LIMIT(i)); val = (val >> 12) & 0xfffff; if (val == 0) /* BAR not enabled */ continue; lim = (val + 1) << 20; printf(" BAR %d: %#jx - %#jx : ", i, (intmax_t)base, (intmax_t)lim); if (lim <= base) { printf("\tskipped - malformed %#jx -> %#jx\n", (intmax_t)base, (intmax_t)lim); continue; } else if (base >= XLP_MEM_LIM) { printf(" skipped - outside usable limit %#jx.\n", (intmax_t)XLP_MEM_LIM); continue; } else if (lim >= XLP_MEM_LIM) { lim = XLP_MEM_LIM; printf(" truncated to %#jx.\n", (intmax_t)XLP_MEM_LIM); } else printf(" usable\n"); /* exclude unusable regions from BAR and add rest */ n = mem_exclude_add(&phys_avail[j], base, lim); for (k = j; k < j + n; k += 2) { physsz += phys_avail[k + 1] - phys_avail[k]; printf("\tMem[%d]: %#jx - %#jx\n", k/2, (intmax_t)phys_avail[k], (intmax_t)phys_avail[k+1]); } j = k; } /* setup final entry with 0 */ phys_avail[j] = phys_avail[j + 1] = 0; /* copy phys_avail to dump_avail */ for (i = 0; i <= j + 1; i++) dump_avail[i] = phys_avail[i]; realmem = physmem = btoc(physsz); } void platform_start(__register_t a0 __unused, __register_t a1 __unused, __register_t a2 __unused, __register_t a3 __unused) { /* Initialize pcpu stuff */ mips_pcpu0_init(); /* initialize console so that we have printf */ boothowto |= (RB_SERIAL | RB_MULTIPLE); /* Use multiple consoles */ init_static_kenv(boot1_env, sizeof(boot1_env)); xlp_bootargs_init(a0); /* clockrate used by delay, so initialize it here */ xlp_cpu_frequency = xlp_get_cpu_frequency(0, 0); cpu_clock = xlp_cpu_frequency / 1000000; mips_timer_early_init(xlp_cpu_frequency); /* Init console please */ cninit(); /* Early core init and fixes for errata */ xlp_setup_core(); xlp_parse_mmu_options(); xlp_mem_init(); bcopy(XLPResetEntry, (void *)MIPS_RESET_EXC_VEC, XLPResetEntryEnd - XLPResetEntry); #ifdef SMP /* * We will enable the other threads in core 0 here * so that the TLB and cache info is correct when * mips_init runs */ xlp_enable_threads(xlp_mmuval); #endif /* setup for the startup core */ xlp_setup_mmu(); xlp_enable_blocks(); /* Read/Guess/setup board information */ nlm_board_info_setup(); /* MIPS generic init */ mips_init(); /* * XLP specific post initialization * initialize other on chip stuff */ xlp_pic_init(); mips_timer_init_params(xlp_cpu_frequency, 0); } void platform_cpu_init() { } void platform_reset(void) { uint64_t sysbase = nlm_get_sys_regbase(0); nlm_write_sys_reg(sysbase, SYS_CHIP_RESET, 1); for( ; ; ) __asm __volatile("wait"); } #ifdef SMP /* * XLP threads are started simultaneously when we enable threads, this will * ensure that the threads are blocked in platform_init_ap, until they are * ready to proceed to smp_init_secondary() */ static volatile int thr_unblock[4]; int platform_start_ap(int cpuid) { uint32_t coremask, val; uint64_t sysbase = nlm_get_sys_regbase(0); int hwtid = xlp_cpuid_to_hwtid[cpuid]; int core, thr; core = hwtid / 4; thr = hwtid % 4; if (thr == 0) { /* First thread in core, do core wake up */ coremask = 1u << core; /* Enable core clock */ val = nlm_read_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL); val &= ~coremask; nlm_write_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL, val); /* Remove CPU Reset */ val = nlm_read_sys_reg(sysbase, SYS_CPU_RESET); val &= ~coremask & 0xff; nlm_write_sys_reg(sysbase, SYS_CPU_RESET, val); if (bootverbose) printf("Waking up core %d ...", core); /* Poll for CPU to mark itself coherent */ do { val = nlm_read_sys_reg(sysbase, SYS_CPU_NONCOHERENT_MODE); } while ((val & coremask) != 0); if (bootverbose) printf("Done\n"); } else { /* otherwise release the threads stuck in platform_init_ap */ thr_unblock[thr] = 1; } return (0); } void platform_init_ap(int cpuid) { uint32_t stat; int thr; /* The first thread has to setup the MMU and enable other threads */ thr = nlm_threadid(); if (thr == 0) { xlp_setup_core(); xlp_enable_threads(xlp_mmuval); } else { /* * FIXME busy wait here eats too many cycles, especially * in the core 0 while bootup */ while (thr_unblock[thr] == 0) __asm__ __volatile__ ("nop;nop;nop;nop"); thr_unblock[thr] = 0; } xlp_setup_mmu(); stat = mips_rd_status(); KASSERT((stat & MIPS_SR_INT_IE) == 0, ("Interrupts enabled in %s!", __func__)); stat |= MIPS_SR_COP_2_BIT | MIPS_SR_COP_0_BIT; mips_wr_status(stat); nlm_write_c0_eimr(0ull); xlp_enable_irq(IRQ_IPI); xlp_enable_irq(IRQ_TIMER); xlp_enable_irq(IRQ_MSGRING); return; } int platform_ipi_hardintr_num(void) { return (IRQ_IPI); } int platform_ipi_softintr_num(void) { return (-1); } void platform_ipi_send(int cpuid) { nlm_pic_send_ipi(xlp_pic_base, xlp_cpuid_to_hwtid[cpuid], platform_ipi_hardintr_num(), 0); } void platform_ipi_clear(void) { } int platform_processor_id(void) { return (xlp_hwtid_to_cpuid[nlm_cpuid()]); } void platform_cpu_mask(cpuset_t *mask) { int i, s; CPU_ZERO(mask); s = xlp_ncores * xlp_threads_per_core; for (i = 0; i < s; i++) CPU_SET(i, mask); } struct cpu_group * platform_smp_topo() { return (smp_topo_2level(CG_SHARE_L2, xlp_ncores, CG_SHARE_L1, xlp_threads_per_core, CG_FLAG_THREAD)); } #endif Index: head/sys/mips/nlm/xlp_pci.c =================================================================== --- head/sys/mips/nlm/xlp_pci.c (revision 326258) +++ head/sys/mips/nlm/xlp_pci.c (revision 326259) @@ -1,577 +1,579 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2003-2012 Broadcom Corporation * 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 BROADCOM ``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 BROADCOM 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcib_if.h" #include #include "pci_if.h" static int xlp_pci_attach(device_t dev) { struct pci_devinfo *dinfo; device_t pcib; int maxslots, s, f, pcifunchigh, irq; int busno, node, devoffset; uint16_t devid; uint8_t hdrtype; /* * The on-chip devices are on a bus that is almost, but not * quite, completely like PCI. Add those things by hand. */ pcib = device_get_parent(dev); busno = pcib_get_bus(dev); maxslots = PCIB_MAXSLOTS(pcib); for (s = 0; s <= maxslots; s++) { pcifunchigh = 0; f = 0; hdrtype = PCIB_READ_CONFIG(pcib, busno, s, f, PCIR_HDRTYPE, 1); if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) continue; if (hdrtype & PCIM_MFDEV) pcifunchigh = PCI_FUNCMAX; node = s / 8; for (f = 0; f <= pcifunchigh; f++) { devoffset = XLP_HDR_OFFSET(node, 0, s % 8, f); if (!nlm_dev_exists(devoffset)) continue; /* Find if there is a desc for the SoC device */ devid = PCIB_READ_CONFIG(pcib, busno, s, f, PCIR_DEVICE, 2); /* Skip devices that don't have a proper PCI header */ switch (devid) { case PCI_DEVICE_ID_NLM_ICI: case PCI_DEVICE_ID_NLM_PIC: case PCI_DEVICE_ID_NLM_FMN: case PCI_DEVICE_ID_NLM_UART: case PCI_DEVICE_ID_NLM_I2C: case PCI_DEVICE_ID_NLM_NOR: case PCI_DEVICE_ID_NLM_MMC: continue; case PCI_DEVICE_ID_NLM_EHCI: irq = PIC_USB_IRQ(f); PCIB_WRITE_CONFIG(pcib, busno, s, f, XLP_PCI_DEVSCRATCH_REG0 << 2, (1 << 8) | irq, 4); } dinfo = pci_read_device(pcib, dev, pcib_get_domain(dev), busno, s, f); pci_add_child(dev, dinfo); } } return (bus_generic_attach(dev)); } static int xlp_pci_probe(device_t dev) { device_t pcib; pcib = device_get_parent(dev); /* * Only the top level bus has SoC devices, leave the rest to * Generic PCI code */ if (strcmp(device_get_nameunit(pcib), "pcib0") != 0) return (ENXIO); device_set_desc(dev, "XLP SoCbus"); return (BUS_PROBE_DEFAULT); } static devclass_t pci_devclass; static device_method_t xlp_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, xlp_pci_probe), DEVMETHOD(device_attach, xlp_pci_attach), DEVMETHOD(bus_rescan, bus_null_rescan), DEVMETHOD_END }; DEFINE_CLASS_1(pci, xlp_pci_driver, xlp_pci_methods, sizeof(struct pci_softc), pci_driver); DRIVER_MODULE(xlp_pci, pcib, xlp_pci_driver, pci_devclass, 0, 0); static int xlp_pcib_probe(device_t dev) { if (ofw_bus_is_compatible(dev, "netlogic,xlp-pci")) { device_set_desc(dev, "XLP PCI bus"); return (BUS_PROBE_DEFAULT); } return (ENXIO); } static int xlp_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { switch (which) { case PCIB_IVAR_DOMAIN: *result = 0; return (0); case PCIB_IVAR_BUS: *result = 0; return (0); } return (ENOENT); } static int xlp_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t result) { switch (which) { case PCIB_IVAR_DOMAIN: return (EINVAL); case PCIB_IVAR_BUS: return (EINVAL); } return (ENOENT); } static int xlp_pcib_maxslots(device_t dev) { return (PCI_SLOTMAX); } static u_int32_t xlp_pcib_read_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, int width) { uint32_t data = 0; uint64_t cfgaddr; int regindex = reg/sizeof(uint32_t); cfgaddr = nlm_pcicfg_base(XLP_HDR_OFFSET(0, b, s, f)); if ((width == 2) && (reg & 1)) return 0xFFFFFFFF; else if ((width == 4) && (reg & 3)) return 0xFFFFFFFF; /* * The intline and int pin of SoC devices are DOA, except * for bridges (slot %8 == 1). * use the values we stashed in a writable PCI scratch reg. */ if (b == 0 && regindex == 0xf && s % 8 > 1) regindex = XLP_PCI_DEVSCRATCH_REG0; data = nlm_read_pci_reg(cfgaddr, regindex); if (width == 1) return ((data >> ((reg & 3) << 3)) & 0xff); else if (width == 2) return ((data >> ((reg & 3) << 3)) & 0xffff); else return (data); } static void xlp_pcib_write_config(device_t dev, u_int b, u_int s, u_int f, u_int reg, u_int32_t val, int width) { uint64_t cfgaddr; uint32_t data = 0; int regindex = reg / sizeof(uint32_t); cfgaddr = nlm_pcicfg_base(XLP_HDR_OFFSET(0, b, s, f)); if ((width == 2) && (reg & 1)) return; else if ((width == 4) && (reg & 3)) return; if (width == 1) { data = nlm_read_pci_reg(cfgaddr, regindex); data = (data & ~(0xff << ((reg & 3) << 3))) | (val << ((reg & 3) << 3)); } else if (width == 2) { data = nlm_read_pci_reg(cfgaddr, regindex); data = (data & ~(0xffff << ((reg & 3) << 3))) | (val << ((reg & 3) << 3)); } else { data = val; } /* * use shadow reg for intpin/intline which are dead */ if (b == 0 && regindex == 0xf && s % 8 > 1) regindex = XLP_PCI_DEVSCRATCH_REG0; nlm_write_pci_reg(cfgaddr, regindex, data); } /* * Enable byte swap in hardware when compiled big-endian. * Programs a link's PCIe SWAP regions from the link's IO and MEM address * ranges. */ static void xlp_pcib_hardware_swap_enable(int node, int link) { #if BYTE_ORDER == BIG_ENDIAN uint64_t bbase, linkpcibase; uint32_t bar; int pcieoffset; pcieoffset = XLP_IO_PCIE_OFFSET(node, link); if (!nlm_dev_exists(pcieoffset)) return; bbase = nlm_get_bridge_regbase(node); linkpcibase = nlm_pcicfg_base(pcieoffset); bar = nlm_read_bridge_reg(bbase, BRIDGE_PCIEMEM_BASE0 + link); nlm_write_pci_reg(linkpcibase, PCIE_BYTE_SWAP_MEM_BASE, bar); bar = nlm_read_bridge_reg(bbase, BRIDGE_PCIEMEM_LIMIT0 + link); nlm_write_pci_reg(linkpcibase, PCIE_BYTE_SWAP_MEM_LIM, bar | 0xFFF); bar = nlm_read_bridge_reg(bbase, BRIDGE_PCIEIO_BASE0 + link); nlm_write_pci_reg(linkpcibase, PCIE_BYTE_SWAP_IO_BASE, bar); bar = nlm_read_bridge_reg(bbase, BRIDGE_PCIEIO_LIMIT0 + link); nlm_write_pci_reg(linkpcibase, PCIE_BYTE_SWAP_IO_LIM, bar | 0xFFF); #endif } static int xlp_pcib_attach(device_t dev) { int node, link; /* enable hardware swap on all nodes/links */ for (node = 0; node < XLP_MAX_NODES; node++) for (link = 0; link < 4; link++) xlp_pcib_hardware_swap_enable(node, link); device_add_child(dev, "pci", -1); bus_generic_attach(dev); return (0); } /* * XLS PCIe can have upto 4 links, and each link has its on IRQ * Find the link on which the device is on */ static int xlp_pcie_link(device_t pcib, device_t dev) { device_t parent, tmp; /* find the lane on which the slot is connected to */ tmp = dev; while (1) { parent = device_get_parent(tmp); if (parent == NULL || parent == pcib) { device_printf(dev, "Cannot find parent bus\n"); return (-1); } if (strcmp(device_get_nameunit(parent), "pci0") == 0) break; tmp = parent; } return (pci_get_function(tmp)); } static int xlp_alloc_msi(device_t pcib, device_t dev, int count, int maxcount, int *irqs) { int i, link; /* * Each link has 32 MSIs that can be allocated, but for now * we only support one device per link. * msi_alloc() equivalent is needed when we start supporting * bridges on the PCIe link. */ link = xlp_pcie_link(pcib, dev); if (link == -1) return (ENXIO); /* * encode the irq so that we know it is a MSI interrupt when we * setup interrupts */ for (i = 0; i < count; i++) irqs[i] = 64 + link * 32 + i; return (0); } static int xlp_release_msi(device_t pcib, device_t dev, int count, int *irqs) { return (0); } static int xlp_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, uint32_t *data) { int link; if (irq < 64) { device_printf(dev, "%s: map_msi for irq %d - ignored", device_get_nameunit(pcib), irq); return (ENXIO); } link = (irq - 64) / 32; *addr = MIPS_MSI_ADDR(0); *data = MIPS_MSI_DATA(PIC_PCIE_IRQ(link)); return (0); } static void bridge_pcie_ack(int irq, void *arg) { uint32_t node,reg; uint64_t base; node = nlm_nodeid(); reg = PCIE_MSI_STATUS; switch (irq) { case PIC_PCIE_0_IRQ: base = nlm_pcicfg_base(XLP_IO_PCIE0_OFFSET(node)); break; case PIC_PCIE_1_IRQ: base = nlm_pcicfg_base(XLP_IO_PCIE1_OFFSET(node)); break; case PIC_PCIE_2_IRQ: base = nlm_pcicfg_base(XLP_IO_PCIE2_OFFSET(node)); break; case PIC_PCIE_3_IRQ: base = nlm_pcicfg_base(XLP_IO_PCIE3_OFFSET(node)); break; default: return; } nlm_write_pci_reg(base, reg, 0xFFFFFFFF); return; } static int mips_platform_pcib_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep) { int error = 0; int xlpirq; error = rman_activate_resource(irq); if (error) return error; if (rman_get_start(irq) != rman_get_end(irq)) { device_printf(dev, "Interrupt allocation %ju != %ju\n", rman_get_start(irq), rman_get_end(irq)); return (EINVAL); } xlpirq = rman_get_start(irq); if (xlpirq == 0) return (0); if (strcmp(device_get_name(dev), "pcib") != 0) return (0); /* * temporary hack for MSI, we support just one device per * link, and assign the link interrupt to the device interrupt */ if (xlpirq >= 64) { int node, val, link; uint64_t base; xlpirq -= 64; if (xlpirq % 32 != 0) return (0); node = nlm_nodeid(); link = xlpirq / 32; base = nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node,link)); /* MSI Interrupt Vector enable at bridge's configuration */ nlm_write_pci_reg(base, PCIE_MSI_EN, PCIE_MSI_VECTOR_INT_EN); val = nlm_read_pci_reg(base, PCIE_INT_EN0); /* MSI Interrupt enable at bridge's configuration */ nlm_write_pci_reg(base, PCIE_INT_EN0, (val | PCIE_MSI_INT_EN)); /* legacy interrupt disable at bridge */ val = nlm_read_pci_reg(base, PCIE_BRIDGE_CMD); nlm_write_pci_reg(base, PCIE_BRIDGE_CMD, (val | PCIM_CMD_INTxDIS)); /* MSI address update at bridge */ nlm_write_pci_reg(base, PCIE_BRIDGE_MSI_ADDRL, MSI_MIPS_ADDR_BASE); nlm_write_pci_reg(base, PCIE_BRIDGE_MSI_ADDRH, 0); val = nlm_read_pci_reg(base, PCIE_BRIDGE_MSI_CAP); /* MSI capability enable at bridge */ nlm_write_pci_reg(base, PCIE_BRIDGE_MSI_CAP, (val | (PCIM_MSICTRL_MSI_ENABLE << 16) | (PCIM_MSICTRL_MMC_32 << 16))); xlpirq = PIC_PCIE_IRQ(link); } /* if it is for real PCIe, we need to ack at bridge too */ if (xlpirq >= PIC_PCIE_IRQ(0) && xlpirq <= PIC_PCIE_IRQ(3)) xlp_set_bus_ack(xlpirq, bridge_pcie_ack, NULL); cpu_establish_hardintr(device_get_name(child), filt, intr, arg, xlpirq, flags, cookiep); return (0); } static int mips_platform_pcib_teardown_intr(device_t dev, device_t child, struct resource *irq, void *cookie) { if (strcmp(device_get_name(child), "pci") == 0) { /* if needed reprogram the pic to clear pcix related entry */ device_printf(dev, "teardown intr\n"); } return (bus_generic_teardown_intr(dev, child, irq, cookie)); } static int mips_pcib_route_interrupt(device_t bus, device_t dev, int pin) { int f, d; /* * Validate requested pin number. */ if ((pin < 1) || (pin > 4)) return (255); if (pci_get_bus(dev) == 0 && pci_get_vendor(dev) == PCI_VENDOR_NETLOGIC) { f = pci_get_function(dev); d = pci_get_slot(dev) % 8; /* * For PCIe links, return link IRT, for other SoC devices * get the IRT from its PCIe header */ if (d == 1) return (PIC_PCIE_IRQ(f)); else return (255); /* use intline, don't reroute */ } else { /* Regular PCI devices */ return (PIC_PCIE_IRQ(xlp_pcie_link(bus, dev))); } } static device_method_t xlp_pcib_methods[] = { /* Device interface */ DEVMETHOD(device_probe, xlp_pcib_probe), DEVMETHOD(device_attach, xlp_pcib_attach), /* Bus interface */ DEVMETHOD(bus_read_ivar, xlp_pcib_read_ivar), DEVMETHOD(bus_write_ivar, xlp_pcib_write_ivar), DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_setup_intr, mips_platform_pcib_setup_intr), DEVMETHOD(bus_teardown_intr, mips_platform_pcib_teardown_intr), /* pcib interface */ DEVMETHOD(pcib_maxslots, xlp_pcib_maxslots), DEVMETHOD(pcib_read_config, xlp_pcib_read_config), DEVMETHOD(pcib_write_config, xlp_pcib_write_config), DEVMETHOD(pcib_route_interrupt, mips_pcib_route_interrupt), DEVMETHOD(pcib_request_feature, pcib_request_feature_allow), DEVMETHOD(pcib_alloc_msi, xlp_alloc_msi), DEVMETHOD(pcib_release_msi, xlp_release_msi), DEVMETHOD(pcib_map_msi, xlp_map_msi), DEVMETHOD_END }; static driver_t xlp_pcib_driver = { "pcib", xlp_pcib_methods, 1, /* no softc */ }; static devclass_t pcib_devclass; DRIVER_MODULE(xlp_pcib, simplebus, xlp_pcib_driver, pcib_devclass, 0, 0); Index: head/sys/mips/rmi/board.c =================================================================== --- head/sys/mips/rmi/board.c (revision 326258) +++ head/sys/mips/rmi/board.c (revision 326259) @@ -1,593 +1,595 @@ /********************************************************************* + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * * Copyright 2003-2006 Raza Microelectronics, Inc. (RMI). 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 Raza Microelectronics, Inc. ``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 RMI 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. * * *****************************RMI_2**********************************/ #include /* RCS ID & Copyright macro defns */ __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #define XLR_I2C_RTC_ADDR 0xd0 #define XLR_I2C_EEPROM_ADDR 0xa0 #define XLR_I2C_TEMPSENSOR_ADDR 0x98 #define XLR_I2C_ATX8_TEMPSENSOR_ADDR 0x9a struct stn_cc *xlr_core_cc_configs[] = { &cc_table_cpu_0, &cc_table_cpu_1, &cc_table_cpu_2, &cc_table_cpu_3, &cc_table_cpu_4, &cc_table_cpu_5, &cc_table_cpu_6, &cc_table_cpu_7}; struct stn_cc *xls_core_cc_configs[] = { &xls_cc_table_cpu_0, &xls_cc_table_cpu_1, &xls_cc_table_cpu_2, &xls_cc_table_cpu_3 }; struct xlr_board_info xlr_board_info; static int xlr_pcmcia_present(void) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_GPIO_OFFSET); uint32_t resetconf; resetconf = xlr_read_reg(mmio, 21); return ((resetconf & 0x4000) != 0); } static void xlr_chip_specific_overrides(struct xlr_board_info* board) { struct xlr_gmac_block_t *blk0, *blk1, *blk2; uint32_t chipid; uint32_t revision; blk0 = &board->gmac_block[0]; blk1 = &board->gmac_block[1]; blk2 = &board->gmac_block[2]; chipid = xlr_processor_id(); revision = xlr_revision(); if (revision == 0x04) { /* B2 */ switch (chipid) { case 0x07: /* XLR 508 */ case 0x08: /* XLR 516 */ case 0x09: /* XLR 532 */ /* NA[12] not available */ memset(blk1, 0, sizeof(*blk1)); memset(blk2, 0, sizeof(*blk2)); break; case 0x06: /* XLR 308 */ /* NA0 has 3 ports */ blk0->gmac_port[3].valid = 0; blk0->num_ports--; /* NA[12] not available */ memset(blk1, 0, sizeof(*blk1)); memset(blk2, 0, sizeof(*blk2)); break; default: break; } } else if (revision == 0x91) { /* C4 */ switch (chipid) { case 0x0B: /* XLR 508 */ case 0x0A: /* XLR 516 */ case 0x08: /* XLR 532 */ /* NA[12] not available */ memset(blk1, 0, sizeof(*blk1)); memset(blk2, 0, sizeof(*blk2)); break; case 0x0F: /* XLR 308 */ /* NA0 has 3 ports */ blk0->gmac_port[3].valid = 0; blk0->num_ports--; /* NA[12] not available */ memset(blk1, 0, sizeof(*blk1)); memset(blk2, 0, sizeof(*blk2)); break; default: break; } } else { /* other pre-production silicon */ switch (chipid) { /* XLR 5xx */ case 0x0B: case 0x0A: case 0x07: case 0x08: case 0x09: /* NA[12] not available */ memset(blk1, 0, sizeof(*blk1)); memset(blk2, 0, sizeof(*blk2)); break; /* XLR 3xx */ case 0x0F: case 0x06: /* NA0 has 3 ports */ blk0->gmac_port[3].valid = 0; blk0->num_ports--; /* NA[12] not available */ memset(blk1, 0, sizeof(*blk1)); memset(blk2, 0, sizeof(*blk2)); break; default: break; } } } static void xlr_board_specific_overrides(struct xlr_board_info* board) { struct xlr_gmac_block_t *blk1, *blk2; blk1 = &board->gmac_block[1]; blk2 = &board->gmac_block[2]; switch (xlr_boot1_info.board_major_version) { case RMI_XLR_BOARD_ARIZONA_I: /* ATX-I has SPI-4, not XGMAC */ blk1->type = XLR_SPI4; blk1->enabled = 0; /* nlge does not support SPI-4 */ blk2->type = XLR_SPI4; blk2->enabled = 0; break; case RMI_XLR_BOARD_ARIZONA_II: /* XGMII_A --> VSC7281, XGMII_B --> VSC7281 */ blk1->enabled = 1; blk1->num_ports = 1; blk1->gmac_port[0].valid = 1; blk2->enabled = 1; blk2->num_ports = 1; blk2->gmac_port[0].valid = 1; default: break; } } static int quad0_xaui(void) { xlr_reg_t *gpio_mmio = (unsigned int *)(DEFAULT_XLR_IO_BASE + XLR_IO_GPIO_OFFSET); uint32_t bit24; bit24 = (xlr_read_reg(gpio_mmio, 0x15) >> 24) & 0x1; return (bit24); } static int quad1_xaui(void) { xlr_reg_t *gpio_mmio = (unsigned int *)(DEFAULT_XLR_IO_BASE + XLR_IO_GPIO_OFFSET); uint32_t bit25; bit25 = (xlr_read_reg(gpio_mmio, 0x15) >> 25) & 0x1; return (bit25); } static void xls_chip_specific_overrides(struct xlr_board_info* board) { struct xlr_gmac_block_t *blk0, *blk1; uint32_t chipid; blk0 = &board->gmac_block[0]; blk1 = &board->gmac_block[1]; chipid = xlr_processor_id(); switch (chipid) { case 0x8E: /* XLS208 */ case 0x8F: /* XLS204 */ /* NA1 is not available */ memset(blk1, 0, sizeof(*blk1)); break; case 0xCE: /* XLS108 */ case 0xCF: /* XLS104 */ /* NA0 has 3 ports */ blk0->gmac_port[3].valid = 0; blk0->num_ports--; /* NA1 is not available */ memset(blk1, 0, sizeof(*blk1)); break; default: break; } } static void xls_board_specific_overrides(struct xlr_board_info* board) { struct xlr_gmac_block_t *blk0, *blk1; int i; struct xlr_i2c_dev_t* iic_blk; blk0 = &board->gmac_block[0]; blk1 = &board->gmac_block[1]; switch (xlr_boot1_info.board_major_version) { case RMI_XLR_BOARD_ARIZONA_VI: blk0->mode = XLR_PORT0_RGMII; blk0->gmac_port[0].type = XLR_RGMII; blk0->gmac_port[0].phy_addr = 0; blk0->gmac_port[0].mii_addr = XLR_IO_GMAC_4_OFFSET; /* Because of the Octal PHY, SGMII Quad1 is MII is also bound * to the PHY attached to SGMII0_MDC/MDIO/MDINT. */ for (i = 0; i < 4; i++) { blk1->gmac_port[i].mii_addr = XLR_IO_GMAC_0_OFFSET; blk1->gmac_port[i].serdes_addr = XLR_IO_GMAC_0_OFFSET; } blk1->gmac_port[1].mii_addr = XLR_IO_GMAC_0_OFFSET; blk1->gmac_port[2].mii_addr = XLR_IO_GMAC_0_OFFSET; blk1->gmac_port[3].mii_addr = XLR_IO_GMAC_0_OFFSET; blk1->gmac_port[1].serdes_addr = XLR_IO_GMAC_0_OFFSET; blk1->gmac_port[2].serdes_addr = XLR_IO_GMAC_0_OFFSET; blk1->gmac_port[3].serdes_addr = XLR_IO_GMAC_0_OFFSET; /* RGMII MDIO interrupt is thru NA1 and SGMII MDIO * interrupts for ports in blk1 are from NA0 */ blk0->gmac_port[0].mdint_id = 1; blk1->gmac_port[0].mdint_id = 0; blk1->gmac_port[1].mdint_id = 0; blk1->gmac_port[2].mdint_id = 0; blk1->gmac_port[3].mdint_id = 0; /* If we have a 4xx lite chip, don't enable the * GMACs which are disabled in hardware */ if (xlr_is_xls4xx_lite()) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_GPIO_OFFSET); uint32_t tmp; /* Port 6 & 7 are not enabled on the condor 4xx, figure * this out from the GPIO fuse bank */ tmp = xlr_read_reg(mmio, 35); if ((tmp & (3 << 28)) != 0) { blk1->enabled = 0x3; blk1->gmac_port[2].valid = 0; blk1->gmac_port[3].valid = 0; blk1->num_ports = 2; } } break; case RMI_XLR_BOARD_ARIZONA_VIII: iic_blk = &xlr_board_info.xlr_i2c_device[I2C_THERMAL]; if (iic_blk->enabled) { iic_blk->addr = XLR_I2C_ATX8_TEMPSENSOR_ADDR; } if (blk1->enabled) { /* There is just one Octal PHY on the board and it is * connected to the MII interface for NA Quad 0. */ for (i = 0; i < 4; i++) { blk1->gmac_port[i].mii_addr = XLR_IO_GMAC_0_OFFSET; blk1->gmac_port[i].mdint_id = 0; } } break; case RMI_XLR_BOARD_ARIZONA_XI: case RMI_XLR_BOARD_ARIZONA_XII: if (quad0_xaui()) { /* GMAC ports 0-3 are set to XAUI */ /* only GMAC0 is active i.e, the 0-th port on this quad. * Disable all the other 7 possible ports. */ for (i = 1; i < MAX_NA_PORTS; i++) { memset(&blk0->gmac_port[i], 0, sizeof(blk0->gmac_port[i])); } /* Setup for XAUI on N/w Acc0: gmac0 */ blk0->type = XLR_XGMAC; blk0->mode = XLR_XAUI; blk0->num_ports = 1; blk0->gmac_port[0].type = XLR_XAUI; blk1->gmac_port[0].phy_addr = 16; blk0->gmac_port[0].tx_bucket_id = blk0->station_txbase; /* Other addresses etc need not be modified as XAUI_0 * shares its addresses with SGMII GMAC_0, which was * set in the caller. */ } else { blk0->num_ports = 1; /* only 1 RGMII port */ blk0->mode = XLR_PORT0_RGMII; blk0->gmac_port[0].type = XLR_RGMII; blk0->gmac_port[0].phy_addr = 0; blk0->gmac_port[0].mii_addr = XLR_IO_GMAC_0_OFFSET; } if (quad1_xaui()) { /* GMAC ports 4-7 are used for XAUI */ /* only GMAC4 is active i.e, the 0-th port on this quad. * Disable all the other 7 possible ports. */ for (i = 1; i < MAX_NA_PORTS; i++) { memset(&blk1->gmac_port[i], 0, sizeof(blk1->gmac_port[i])); } /* Setup for XAUI on N/w Acc1: gmac4 */ blk1->type = XLR_XGMAC; blk1->mode = XLR_XAUI; blk1->num_ports = 1; /* XAUI and SGMII ports share FMN buckets on N/w Acc 1; so, station_txbase, station_rfr need not be patched up. */ blk1->gmac_port[0].type = XLR_XAUI; blk1->gmac_port[0].phy_addr = 16; blk1->gmac_port[0].tx_bucket_id = blk1->station_txbase; /* Other addresses etc need not be modified as XAUI_1 * shares its addresses with SGMII GMAC_4, which was * set in the caller. */ } break; default: break; } } /* * All our knowledge of chip and board that cannot be detected by probing * at run-time goes here */ int xlr_board_info_setup() { struct xlr_gmac_block_t *blk0, *blk1, *blk2; struct xlr_i2c_dev_t* iic_blk; int i; /* This setup code is long'ish because the same base driver * (if_nlge.c) is used for different: * - CPUs (XLR/XLS) * - boards (for each CPU, multiple board configs are possible * and available). * * At the time of writing, there are atleast 12 boards, 4 with XLR * and 8 with XLS. This means that the base driver needs to work with * 12 different configurations, with varying levels of differences. * To accomodate the different configs, the xlr_board_info struct * has various attributes for paramters that could be different. * These attributes are setup here and can be used directly in the * base driver. * It was seen that the setup code is not entirely trivial and * it is possible to organize it in different ways. In the following, * we choose an approach that sacrifices code-compactness/speed for * readability. This is because configuration code executes once * per reboot and hence has a minimal performance impact. * On the other hand, driver debugging/enhancements require * that different engineers can quickly comprehend the setup * sequence. Hence, readability is seen as the key requirement for * this code. It is for the reader to decide how much of this * requirement is met with the current code organization !! * * The initialization is organized thus: * * if (CPU is XLS) { * // initialize per XLS architecture * // default inits (per chip spec) * // chip-specific overrides * // board-specific overrides * } else if (CPU is XLR) { * // initialize per XLR architecture * // default inits (per chip spec) * // chip-specific overrides * // board-specific overrides * } * * For each CPU family, all the default initializations * are done for a fully-loaded device of that family. * This configuration is then adjusted for the actual * chip id. This is followed up with board specific * overrides. */ /* start with a clean slate */ memset(&xlr_board_info, 0, sizeof(xlr_board_info)); xlr_board_info.ata = xlr_pcmcia_present(); blk0 = &xlr_board_info.gmac_block[0]; blk1 = &xlr_board_info.gmac_block[1]; blk2 = &xlr_board_info.gmac_block[2]; iic_blk = xlr_board_info.xlr_i2c_device; iic_blk[I2C_RTC].enabled = 1; iic_blk[I2C_RTC].addr = XLR_I2C_RTC_ADDR; iic_blk[I2C_THERMAL].enabled = 1; iic_blk[I2C_THERMAL].addr = XLR_I2C_TEMPSENSOR_ADDR; iic_blk[I2C_EEPROM].enabled = 1; iic_blk[I2C_EEPROM].addr = XLR_I2C_EEPROM_ADDR; if (xlr_is_xls()) { xlr_board_info.is_xls = 1; xlr_board_info.nr_cpus = 8; xlr_board_info.usb = 1; /* Board version 8 has NAND flash */ xlr_board_info.cfi = (xlr_boot1_info.board_major_version != RMI_XLR_BOARD_ARIZONA_VIII); xlr_board_info.pci_irq = 0; xlr_board_info.credit_configs = xls_core_cc_configs; xlr_board_info.bucket_sizes = &xls_bucket_sizes; xlr_board_info.gmacports = MAX_NA_PORTS; /* ---------------- Network Acc 0 ---------------- */ blk0->type = XLR_GMAC; blk0->enabled = 0xf; blk0->credit_config = &xls_cc_table_gmac0; blk0->station_id = MSGRNG_STNID_GMAC; blk0->station_txbase = MSGRNG_STNID_GMACTX0; blk0->station_rfr = MSGRNG_STNID_GMACRFR_0; blk0->mode = XLR_SGMII; blk0->baseaddr = XLR_IO_GMAC_0_OFFSET; blk0->baseirq = PIC_GMAC_0_IRQ; blk0->baseinst = 0; /* By default, assume SGMII is setup. But this can change based on board-specific or setting-specific info. */ for (i = 0; i < 4; i++) { blk0->gmac_port[i].valid = 1; blk0->gmac_port[i].instance = i + blk0->baseinst; blk0->gmac_port[i].type = XLR_SGMII; blk0->gmac_port[i].phy_addr = i + 16; blk0->gmac_port[i].tx_bucket_id = blk0->station_txbase + i; blk0->gmac_port[i].mdint_id = 0; blk0->num_ports++; blk0->gmac_port[i].base_addr = XLR_IO_GMAC_0_OFFSET + i * 0x1000; blk0->gmac_port[i].mii_addr = XLR_IO_GMAC_0_OFFSET; blk0->gmac_port[i].pcs_addr = XLR_IO_GMAC_0_OFFSET; blk0->gmac_port[i].serdes_addr = XLR_IO_GMAC_0_OFFSET; } /* ---------------- Network Acc 1 ---------------- */ blk1->type = XLR_GMAC; blk1->enabled = 0xf; blk1->credit_config = &xls_cc_table_gmac1; blk1->station_id = MSGRNG_STNID_GMAC1; blk1->station_txbase = MSGRNG_STNID_GMAC1_TX0; blk1->station_rfr = MSGRNG_STNID_GMAC1_FR_0; blk1->mode = XLR_SGMII; blk1->baseaddr = XLR_IO_GMAC_4_OFFSET; blk1->baseirq = PIC_XGS_0_IRQ; blk1->baseinst = 4; for (i = 0; i < 4; i++) { blk1->gmac_port[i].valid = 1; blk1->gmac_port[i].instance = i + blk1->baseinst; blk1->gmac_port[i].type = XLR_SGMII; blk1->gmac_port[i].phy_addr = i + 20; blk1->gmac_port[i].tx_bucket_id = blk1->station_txbase + i; blk1->gmac_port[i].mdint_id = 1; blk1->num_ports++; blk1->gmac_port[i].base_addr = XLR_IO_GMAC_4_OFFSET + i * 0x1000; blk1->gmac_port[i].mii_addr = XLR_IO_GMAC_4_OFFSET; blk1->gmac_port[i].pcs_addr = XLR_IO_GMAC_4_OFFSET; blk1->gmac_port[i].serdes_addr = XLR_IO_GMAC_0_OFFSET; } /* ---------------- Network Acc 2 ---------------- */ xlr_board_info.gmac_block[2].enabled = 0; /* disabled on XLS */ xls_chip_specific_overrides(&xlr_board_info); xls_board_specific_overrides(&xlr_board_info); } else { /* XLR */ xlr_board_info.is_xls = 0; xlr_board_info.nr_cpus = 32; xlr_board_info.usb = 0; xlr_board_info.cfi = 1; xlr_board_info.pci_irq = 0; xlr_board_info.credit_configs = xlr_core_cc_configs; xlr_board_info.bucket_sizes = &bucket_sizes; xlr_board_info.gmacports = 4; /* ---------------- GMAC0 ---------------- */ blk0->type = XLR_GMAC; blk0->enabled = 0xf; blk0->credit_config = &cc_table_gmac; blk0->station_id = MSGRNG_STNID_GMAC; blk0->station_txbase = MSGRNG_STNID_GMACTX0; blk0->station_rfr = MSGRNG_STNID_GMACRFR_0; blk0->mode = XLR_RGMII; blk0->baseaddr = XLR_IO_GMAC_0_OFFSET; blk0->baseirq = PIC_GMAC_0_IRQ; blk0->baseinst = 0; /* first, do the common/easy stuff for all the ports */ for (i = 0; i < 4; i++) { blk0->gmac_port[i].valid = 1; blk0->gmac_port[i].instance = i + blk0->baseinst; blk0->gmac_port[i].type = XLR_RGMII; blk0->gmac_port[i].phy_addr = i; blk0->gmac_port[i].tx_bucket_id = blk0->station_txbase + i; blk0->gmac_port[i].mdint_id = 0; blk0->gmac_port[i].base_addr = XLR_IO_GMAC_0_OFFSET + i * 0x1000; blk0->gmac_port[i].mii_addr = XLR_IO_GMAC_0_OFFSET; /* RGMII ports, no PCS/SERDES */ blk0->num_ports++; } /* ---------------- XGMAC0 ---------------- */ blk1->type = XLR_XGMAC; blk1->mode = XLR_XGMII; blk1->enabled = 0; blk1->credit_config = &cc_table_xgs_0; blk1->station_txbase = MSGRNG_STNID_XGS0_TX; blk1->station_rfr = MSGRNG_STNID_XMAC0RFR; blk1->station_id = MSGRNG_STNID_XGS0FR; blk1->baseaddr = XLR_IO_XGMAC_0_OFFSET; blk1->baseirq = PIC_XGS_0_IRQ; blk1->baseinst = 4; blk1->gmac_port[0].type = XLR_XGMII; blk1->gmac_port[0].instance = 0; blk1->gmac_port[0].phy_addr = 0; blk1->gmac_port[0].base_addr = XLR_IO_XGMAC_0_OFFSET; blk1->gmac_port[0].mii_addr = XLR_IO_XGMAC_0_OFFSET; blk1->gmac_port[0].tx_bucket_id = blk1->station_txbase; blk1->gmac_port[0].mdint_id = 1; /* ---------------- XGMAC1 ---------------- */ blk2->type = XLR_XGMAC; blk2->mode = XLR_XGMII; blk2->enabled = 0; blk2->credit_config = &cc_table_xgs_1; blk2->station_txbase = MSGRNG_STNID_XGS1_TX; blk2->station_rfr = MSGRNG_STNID_XMAC1RFR; blk2->station_id = MSGRNG_STNID_XGS1FR; blk2->baseaddr = XLR_IO_XGMAC_1_OFFSET; blk2->baseirq = PIC_XGS_1_IRQ; blk2->baseinst = 5; blk2->gmac_port[0].type = XLR_XGMII; blk2->gmac_port[0].instance = 0; blk2->gmac_port[0].phy_addr = 0; blk2->gmac_port[0].base_addr = XLR_IO_XGMAC_1_OFFSET; blk2->gmac_port[0].mii_addr = XLR_IO_XGMAC_1_OFFSET; blk2->gmac_port[0].tx_bucket_id = blk2->station_txbase; blk2->gmac_port[0].mdint_id = 2; /* Done with default setup. Now handle chip and board-specific variations. */ xlr_chip_specific_overrides(&xlr_board_info); xlr_board_specific_overrides(&xlr_board_info); } return 0; } Index: head/sys/mips/rmi/bus_space_rmi.c =================================================================== --- head/sys/mips/rmi/bus_space_rmi.c (revision 326258) +++ head/sys/mips/rmi/bus_space_rmi.c (revision 326259) @@ -1,686 +1,688 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009 RMI Corporation * 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include static int rmi_bus_space_map(void *t, bus_addr_t addr, bus_size_t size, int flags, bus_space_handle_t * bshp); static void rmi_bus_space_unmap(void *t, bus_space_handle_t bsh, bus_size_t size); static int rmi_bus_space_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset, bus_size_t size, bus_space_handle_t * nbshp); static u_int8_t rmi_bus_space_read_1(void *t, bus_space_handle_t handle, bus_size_t offset); static u_int16_t rmi_bus_space_read_2(void *t, bus_space_handle_t handle, bus_size_t offset); static u_int32_t rmi_bus_space_read_4(void *t, bus_space_handle_t handle, bus_size_t offset); static void rmi_bus_space_read_multi_1(void *t, bus_space_handle_t handle, bus_size_t offset, u_int8_t * addr, size_t count); static void rmi_bus_space_read_multi_2(void *t, bus_space_handle_t handle, bus_size_t offset, u_int16_t * addr, size_t count); static void rmi_bus_space_read_multi_4(void *t, bus_space_handle_t handle, bus_size_t offset, u_int32_t * addr, size_t count); static void rmi_bus_space_read_region_1(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int8_t * addr, size_t count); static void rmi_bus_space_read_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int16_t * addr, size_t count); static void rmi_bus_space_read_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int32_t * addr, size_t count); static void rmi_bus_space_write_1(void *t, bus_space_handle_t handle, bus_size_t offset, u_int8_t value); static void rmi_bus_space_write_2(void *t, bus_space_handle_t handle, bus_size_t offset, u_int16_t value); static void rmi_bus_space_write_4(void *t, bus_space_handle_t handle, bus_size_t offset, u_int32_t value); static void rmi_bus_space_write_multi_1(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int8_t * addr, size_t count); static void rmi_bus_space_write_multi_2(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int16_t * addr, size_t count); static void rmi_bus_space_write_multi_4(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int32_t * addr, size_t count); static void rmi_bus_space_write_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, const u_int16_t * addr, size_t count); static void rmi_bus_space_write_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, const u_int32_t * addr, size_t count); static void rmi_bus_space_set_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int16_t value, size_t count); static void rmi_bus_space_set_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int32_t value, size_t count); static void rmi_bus_space_barrier(void *tag __unused, bus_space_handle_t bsh __unused, bus_size_t offset __unused, bus_size_t len __unused, int flags); static void rmi_bus_space_copy_region_2(void *t, bus_space_handle_t bsh1, bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, size_t count); u_int8_t rmi_bus_space_read_stream_1(void *t, bus_space_handle_t handle, bus_size_t offset); static u_int16_t rmi_bus_space_read_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset); static u_int32_t rmi_bus_space_read_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset); static void rmi_bus_space_read_multi_stream_1(void *t, bus_space_handle_t handle, bus_size_t offset, u_int8_t * addr, size_t count); static void rmi_bus_space_read_multi_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset, u_int16_t * addr, size_t count); static void rmi_bus_space_read_multi_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset, u_int32_t * addr, size_t count); void rmi_bus_space_write_stream_1(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int8_t value); static void rmi_bus_space_write_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset, u_int16_t value); static void rmi_bus_space_write_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset, u_int32_t value); static void rmi_bus_space_write_multi_stream_1(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int8_t * addr, size_t count); static void rmi_bus_space_write_multi_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int16_t * addr, size_t count); static void rmi_bus_space_write_multi_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int32_t * addr, size_t count); #define TODO() printf("XLR memory bus space function '%s' unimplemented\n", __func__) static struct bus_space local_rmi_bus_space = { /* cookie */ (void *)0, /* mapping/unmapping */ rmi_bus_space_map, rmi_bus_space_unmap, rmi_bus_space_subregion, /* allocation/deallocation */ NULL, NULL, /* barrier */ rmi_bus_space_barrier, /* read (single) */ rmi_bus_space_read_1, rmi_bus_space_read_2, rmi_bus_space_read_4, NULL, /* read multiple */ rmi_bus_space_read_multi_1, rmi_bus_space_read_multi_2, rmi_bus_space_read_multi_4, NULL, /* read region */ rmi_bus_space_read_region_1, rmi_bus_space_read_region_2, rmi_bus_space_read_region_4, NULL, /* write (single) */ rmi_bus_space_write_1, rmi_bus_space_write_2, rmi_bus_space_write_4, NULL, /* write multiple */ rmi_bus_space_write_multi_1, rmi_bus_space_write_multi_2, rmi_bus_space_write_multi_4, NULL, /* write region */ NULL, rmi_bus_space_write_region_2, rmi_bus_space_write_region_4, NULL, /* set multiple */ NULL, NULL, NULL, NULL, /* set region */ NULL, rmi_bus_space_set_region_2, rmi_bus_space_set_region_4, NULL, /* copy */ NULL, rmi_bus_space_copy_region_2, NULL, NULL, /* read (single) stream */ rmi_bus_space_read_stream_1, rmi_bus_space_read_stream_2, rmi_bus_space_read_stream_4, NULL, /* read multiple stream */ rmi_bus_space_read_multi_stream_1, rmi_bus_space_read_multi_stream_2, rmi_bus_space_read_multi_stream_4, NULL, /* read region stream */ rmi_bus_space_read_region_1, rmi_bus_space_read_region_2, rmi_bus_space_read_region_4, NULL, /* write (single) stream */ rmi_bus_space_write_stream_1, rmi_bus_space_write_stream_2, rmi_bus_space_write_stream_4, NULL, /* write multiple stream */ rmi_bus_space_write_multi_stream_1, rmi_bus_space_write_multi_stream_2, rmi_bus_space_write_multi_stream_4, NULL, /* write region stream */ NULL, rmi_bus_space_write_region_2, rmi_bus_space_write_region_4, NULL, }; /* generic bus_space tag */ bus_space_tag_t rmi_bus_space = &local_rmi_bus_space; /* * Map a region of device bus space into CPU virtual address space. */ static int rmi_bus_space_map(void *t __unused, bus_addr_t addr, bus_size_t size __unused, int flags __unused, bus_space_handle_t * bshp) { *bshp = addr; return (0); } /* * Unmap a region of device bus space. */ static void rmi_bus_space_unmap(void *t __unused, bus_space_handle_t bsh __unused, bus_size_t size __unused) { } /* * Get a new handle for a subregion of an already-mapped area of bus space. */ static int rmi_bus_space_subregion(void *t __unused, bus_space_handle_t bsh, bus_size_t offset, bus_size_t size __unused, bus_space_handle_t * nbshp) { *nbshp = bsh + offset; return (0); } /* * Read a 1, 2, 4, or 8 byte quantity from bus space * described by tag/handle/offset. */ static u_int8_t rmi_bus_space_read_1(void *tag, bus_space_handle_t handle, bus_size_t offset) { return (u_int8_t) (*(volatile u_int32_t *)(handle + offset)); } static u_int16_t rmi_bus_space_read_2(void *tag, bus_space_handle_t handle, bus_size_t offset) { return (u_int16_t)(*(volatile u_int32_t *)(handle + offset)); } static u_int32_t rmi_bus_space_read_4(void *tag, bus_space_handle_t handle, bus_size_t offset) { return (*(volatile u_int32_t *)(handle + offset)); } /* * Read `count' 1, 2, 4, or 8 byte quantities from bus space * described by tag/handle/offset and copy into buffer provided. */ static void rmi_bus_space_read_multi_1(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int8_t * addr, size_t count) { TODO(); } static void rmi_bus_space_read_multi_2(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int16_t * addr, size_t count) { TODO(); } static void rmi_bus_space_read_multi_4(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int32_t * addr, size_t count) { TODO(); } /* * Write the 1, 2, 4, or 8 byte value `value' to bus space * described by tag/handle/offset. */ static void rmi_bus_space_write_1(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int8_t value) { *(volatile u_int32_t *)(handle + offset) = (u_int32_t)value; } static void rmi_bus_space_write_2(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int16_t value) { *(volatile u_int32_t *)(handle + offset) = (u_int32_t)value; } static void rmi_bus_space_write_4(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int32_t value) { *(volatile u_int32_t *)(handle + offset) = value; } /* * Write `count' 1, 2, 4, or 8 byte quantities from the buffer * provided to bus space described by tag/handle/offset. */ static void rmi_bus_space_write_multi_1(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int8_t * addr, size_t count) { TODO(); } static void rmi_bus_space_write_multi_2(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int16_t * addr, size_t count) { TODO(); } static void rmi_bus_space_write_multi_4(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int32_t * addr, size_t count) { TODO(); } /* * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described * by tag/handle starting at `offset'. */ static void rmi_bus_space_set_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int16_t value, size_t count) { bus_addr_t addr = bsh + offset; for (; count != 0; count--, addr += 2) (*(volatile u_int32_t *)(addr)) = value; } static void rmi_bus_space_set_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int32_t value, size_t count) { bus_addr_t addr = bsh + offset; for (; count != 0; count--, addr += 4) (*(volatile u_int32_t *)(addr)) = value; } /* * Copy `count' 1, 2, 4, or 8 byte values from bus space starting * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2. */ static void rmi_bus_space_copy_region_2(void *t, bus_space_handle_t bsh1, bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, size_t count) { printf("bus_space_copy_region_2 - unimplemented\n"); } /* * Read `count' 1, 2, 4, or 8 byte quantities from bus space * described by tag/handle/offset and copy into buffer provided. */ u_int8_t rmi_bus_space_read_stream_1(void *t, bus_space_handle_t handle, bus_size_t offset) { return *((volatile u_int8_t *)(handle + offset)); } static u_int16_t rmi_bus_space_read_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset) { return *(volatile u_int16_t *)(handle + offset); } static u_int32_t rmi_bus_space_read_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset) { return (*(volatile u_int32_t *)(handle + offset)); } static void rmi_bus_space_read_multi_stream_1(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int8_t * addr, size_t count) { TODO(); } static void rmi_bus_space_read_multi_stream_2(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int16_t * addr, size_t count) { TODO(); } static void rmi_bus_space_read_multi_stream_4(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int32_t * addr, size_t count) { TODO(); } /* * Read `count' 1, 2, 4, or 8 byte quantities from bus space * described by tag/handle and starting at `offset' and copy into * buffer provided. */ void rmi_bus_space_read_region_1(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int8_t * addr, size_t count) { TODO(); } void rmi_bus_space_read_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int16_t * addr, size_t count) { TODO(); } void rmi_bus_space_read_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int32_t * addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { *addr++ = (*(volatile u_int32_t *)(baddr)); baddr += 4; } } void rmi_bus_space_write_stream_1(void *t, bus_space_handle_t handle, bus_size_t offset, u_int8_t value) { TODO(); } static void rmi_bus_space_write_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset, u_int16_t value) { TODO(); } static void rmi_bus_space_write_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset, u_int32_t value) { TODO(); } static void rmi_bus_space_write_multi_stream_1(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int8_t * addr, size_t count) { TODO(); } static void rmi_bus_space_write_multi_stream_2(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int16_t * addr, size_t count) { TODO(); } static void rmi_bus_space_write_multi_stream_4(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int32_t * addr, size_t count) { TODO(); } void rmi_bus_space_write_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, const u_int16_t * addr, size_t count) { TODO(); } void rmi_bus_space_write_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, const u_int32_t * addr, size_t count) { TODO(); } static void rmi_bus_space_barrier(void *tag __unused, bus_space_handle_t bsh __unused, bus_size_t offset __unused, bus_size_t len __unused, int flags) { } Index: head/sys/mips/rmi/bus_space_rmi_pci.c =================================================================== --- head/sys/mips/rmi/bus_space_rmi_pci.c (revision 326258) +++ head/sys/mips/rmi/bus_space_rmi_pci.c (revision 326259) @@ -1,761 +1,763 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009 RMI Corporation * 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include static int rmi_pci_bus_space_map(void *t, bus_addr_t addr, bus_size_t size, int flags, bus_space_handle_t * bshp); static void rmi_pci_bus_space_unmap(void *t, bus_space_handle_t bsh, bus_size_t size); static int rmi_pci_bus_space_subregion(void *t, bus_space_handle_t bsh, bus_size_t offset, bus_size_t size, bus_space_handle_t * nbshp); static u_int8_t rmi_pci_bus_space_read_1(void *t, bus_space_handle_t handle, bus_size_t offset); static u_int16_t rmi_pci_bus_space_read_2(void *t, bus_space_handle_t handle, bus_size_t offset); static u_int32_t rmi_pci_bus_space_read_4(void *t, bus_space_handle_t handle, bus_size_t offset); static void rmi_pci_bus_space_read_multi_1(void *t, bus_space_handle_t handle, bus_size_t offset, u_int8_t * addr, size_t count); static void rmi_pci_bus_space_read_multi_2(void *t, bus_space_handle_t handle, bus_size_t offset, u_int16_t * addr, size_t count); static void rmi_pci_bus_space_read_multi_4(void *t, bus_space_handle_t handle, bus_size_t offset, u_int32_t * addr, size_t count); static void rmi_pci_bus_space_read_region_1(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int8_t * addr, size_t count); static void rmi_pci_bus_space_read_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int16_t * addr, size_t count); static void rmi_pci_bus_space_read_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int32_t * addr, size_t count); static void rmi_pci_bus_space_write_1(void *t, bus_space_handle_t handle, bus_size_t offset, u_int8_t value); static void rmi_pci_bus_space_write_2(void *t, bus_space_handle_t handle, bus_size_t offset, u_int16_t value); static void rmi_pci_bus_space_write_4(void *t, bus_space_handle_t handle, bus_size_t offset, u_int32_t value); static void rmi_pci_bus_space_write_multi_1(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int8_t * addr, size_t count); static void rmi_pci_bus_space_write_multi_2(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int16_t * addr, size_t count); static void rmi_pci_bus_space_write_multi_4(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int32_t * addr, size_t count); static void rmi_pci_bus_space_write_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, const u_int16_t * addr, size_t count); static void rmi_pci_bus_space_write_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, const u_int32_t * addr, size_t count); static void rmi_pci_bus_space_set_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int16_t value, size_t count); static void rmi_pci_bus_space_set_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int32_t value, size_t count); static void rmi_pci_bus_space_barrier(void *tag __unused, bus_space_handle_t bsh __unused, bus_size_t offset __unused, bus_size_t len __unused, int flags); static void rmi_pci_bus_space_copy_region_2(void *t, bus_space_handle_t bsh1, bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, size_t count); u_int8_t rmi_pci_bus_space_read_stream_1(void *t, bus_space_handle_t handle, bus_size_t offset); static u_int16_t rmi_pci_bus_space_read_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset); static u_int32_t rmi_pci_bus_space_read_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset); static void rmi_pci_bus_space_read_multi_stream_1(void *t, bus_space_handle_t handle, bus_size_t offset, u_int8_t * addr, size_t count); static void rmi_pci_bus_space_read_multi_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset, u_int16_t * addr, size_t count); static void rmi_pci_bus_space_read_multi_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset, u_int32_t * addr, size_t count); void rmi_pci_bus_space_write_stream_1(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int8_t value); static void rmi_pci_bus_space_write_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset, u_int16_t value); static void rmi_pci_bus_space_write_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset, u_int32_t value); static void rmi_pci_bus_space_write_multi_stream_1(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int8_t * addr, size_t count); static void rmi_pci_bus_space_write_multi_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int16_t * addr, size_t count); static void rmi_pci_bus_space_write_multi_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset, const u_int32_t * addr, size_t count); #define TODO() printf("XLR memory bus space function '%s' unimplemented\n", __func__) static struct bus_space local_rmi_pci_bus_space = { /* cookie */ (void *)0, /* mapping/unmapping */ rmi_pci_bus_space_map, rmi_pci_bus_space_unmap, rmi_pci_bus_space_subregion, /* allocation/deallocation */ NULL, NULL, /* barrier */ rmi_pci_bus_space_barrier, /* read (single) */ rmi_pci_bus_space_read_1, rmi_pci_bus_space_read_2, rmi_pci_bus_space_read_4, NULL, /* read multiple */ rmi_pci_bus_space_read_multi_1, rmi_pci_bus_space_read_multi_2, rmi_pci_bus_space_read_multi_4, NULL, /* read region */ rmi_pci_bus_space_read_region_1, rmi_pci_bus_space_read_region_2, rmi_pci_bus_space_read_region_4, NULL, /* write (single) */ rmi_pci_bus_space_write_1, rmi_pci_bus_space_write_2, rmi_pci_bus_space_write_4, NULL, /* write multiple */ rmi_pci_bus_space_write_multi_1, rmi_pci_bus_space_write_multi_2, rmi_pci_bus_space_write_multi_4, NULL, /* write region */ NULL, rmi_pci_bus_space_write_region_2, rmi_pci_bus_space_write_region_4, NULL, /* set multiple */ NULL, NULL, NULL, NULL, /* set region */ NULL, rmi_pci_bus_space_set_region_2, rmi_pci_bus_space_set_region_4, NULL, /* copy */ NULL, rmi_pci_bus_space_copy_region_2, NULL, NULL, /* read (single) stream */ rmi_pci_bus_space_read_stream_1, rmi_pci_bus_space_read_stream_2, rmi_pci_bus_space_read_stream_4, NULL, /* read multiple stream */ rmi_pci_bus_space_read_multi_stream_1, rmi_pci_bus_space_read_multi_stream_2, rmi_pci_bus_space_read_multi_stream_4, NULL, /* read region stream */ rmi_pci_bus_space_read_region_1, rmi_pci_bus_space_read_region_2, rmi_pci_bus_space_read_region_4, NULL, /* write (single) stream */ rmi_pci_bus_space_write_stream_1, rmi_pci_bus_space_write_stream_2, rmi_pci_bus_space_write_stream_4, NULL, /* write multiple stream */ rmi_pci_bus_space_write_multi_stream_1, rmi_pci_bus_space_write_multi_stream_2, rmi_pci_bus_space_write_multi_stream_4, NULL, /* write region stream */ NULL, rmi_pci_bus_space_write_region_2, rmi_pci_bus_space_write_region_4, NULL, }; /* generic bus_space tag */ bus_space_tag_t rmi_pci_bus_space = &local_rmi_pci_bus_space; /* * Map a region of device bus space into CPU virtual address space. */ static int rmi_pci_bus_space_map(void *t __unused, bus_addr_t addr, bus_size_t size __unused, int flags __unused, bus_space_handle_t * bshp) { *bshp = addr; return (0); } /* * Unmap a region of device bus space. */ static void rmi_pci_bus_space_unmap(void *t __unused, bus_space_handle_t bsh __unused, bus_size_t size __unused) { } /* * Get a new handle for a subregion of an already-mapped area of bus space. */ static int rmi_pci_bus_space_subregion(void *t __unused, bus_space_handle_t bsh, bus_size_t offset, bus_size_t size __unused, bus_space_handle_t * nbshp) { *nbshp = bsh + offset; return (0); } /* * Read a 1, 2, 4, or 8 byte quantity from bus space * described by tag/handle/offset. */ static u_int8_t rmi_pci_bus_space_read_1(void *tag, bus_space_handle_t handle, bus_size_t offset) { return (u_int8_t) (*(volatile u_int8_t *)(handle + offset)); } static u_int16_t rmi_pci_bus_space_read_2(void *tag, bus_space_handle_t handle, bus_size_t offset) { return bswap16((u_int16_t) (*(volatile u_int16_t *)(handle + offset))); } static u_int32_t rmi_pci_bus_space_read_4(void *tag, bus_space_handle_t handle, bus_size_t offset) { return bswap32((*(volatile u_int32_t *)(handle + offset))); } /* * Read `count' 1, 2, 4, or 8 byte quantities from bus space * described by tag/handle/offset and copy into buffer provided. */ static void rmi_pci_bus_space_read_multi_1(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int8_t * addr, size_t count) { while (count--) { *addr = (*(volatile u_int8_t *)(handle + offset)); addr++; } } static void rmi_pci_bus_space_read_multi_2(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int16_t * addr, size_t count) { while (count--) { *addr = *(volatile u_int16_t *)(handle + offset); *addr = bswap16(*addr); addr++; } } static void rmi_pci_bus_space_read_multi_4(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int32_t * addr, size_t count) { while (count--) { *addr = *(volatile u_int32_t *)(handle + offset); *addr = bswap32(*addr); addr++; } } /* * Write the 1, 2, 4, or 8 byte value `value' to bus space * described by tag/handle/offset. */ static void rmi_pci_bus_space_write_1(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int8_t value) { mips_sync(); *(volatile u_int8_t *)(handle + offset) = value; } static void rmi_pci_bus_space_write_2(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int16_t value) { mips_sync(); *(volatile u_int16_t *)(handle + offset) = bswap16(value); } static void rmi_pci_bus_space_write_4(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int32_t value) { mips_sync(); *(volatile u_int32_t *)(handle + offset) = bswap32(value); } /* * Write `count' 1, 2, 4, or 8 byte quantities from the buffer * provided to bus space described by tag/handle/offset. */ static void rmi_pci_bus_space_write_multi_1(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int8_t * addr, size_t count) { mips_sync(); while (count--) { (*(volatile u_int8_t *)(handle + offset)) = *addr; addr++; } } static void rmi_pci_bus_space_write_multi_2(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int16_t * addr, size_t count) { mips_sync(); while (count--) { (*(volatile u_int16_t *)(handle + offset)) = bswap16(*addr); addr++; } } static void rmi_pci_bus_space_write_multi_4(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int32_t * addr, size_t count) { mips_sync(); while (count--) { (*(volatile u_int32_t *)(handle + offset)) = bswap32(*addr); addr++; } } /* * Write `count' 1, 2, 4, or 8 byte value `val' to bus space described * by tag/handle starting at `offset'. */ static void rmi_pci_bus_space_set_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int16_t value, size_t count) { bus_addr_t addr = bsh + offset; for (; count != 0; count--, addr += 2) (*(volatile u_int16_t *)(addr)) = value; } static void rmi_pci_bus_space_set_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int32_t value, size_t count) { bus_addr_t addr = bsh + offset; for (; count != 0; count--, addr += 4) (*(volatile u_int32_t *)(addr)) = value; } /* * Copy `count' 1, 2, 4, or 8 byte values from bus space starting * at tag/bsh1/off1 to bus space starting at tag/bsh2/off2. */ static void rmi_pci_bus_space_copy_region_2(void *t, bus_space_handle_t bsh1, bus_size_t off1, bus_space_handle_t bsh2, bus_size_t off2, size_t count) { TODO(); } /* * Read `count' 1, 2, 4, or 8 byte quantities from bus space * described by tag/handle/offset and copy into buffer provided. */ u_int8_t rmi_pci_bus_space_read_stream_1(void *t, bus_space_handle_t handle, bus_size_t offset) { return *((volatile u_int8_t *)(handle + offset)); } static u_int16_t rmi_pci_bus_space_read_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset) { return *(volatile u_int16_t *)(handle + offset); } static u_int32_t rmi_pci_bus_space_read_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset) { return (*(volatile u_int32_t *)(handle + offset)); } static void rmi_pci_bus_space_read_multi_stream_1(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int8_t * addr, size_t count) { while (count--) { *addr = (*(volatile u_int8_t *)(handle + offset)); addr++; } } static void rmi_pci_bus_space_read_multi_stream_2(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int16_t * addr, size_t count) { while (count--) { *addr = (*(volatile u_int16_t *)(handle + offset)); addr++; } } static void rmi_pci_bus_space_read_multi_stream_4(void *tag, bus_space_handle_t handle, bus_size_t offset, u_int32_t * addr, size_t count) { while (count--) { *addr = (*(volatile u_int32_t *)(handle + offset)); addr++; } } /* * Read `count' 1, 2, 4, or 8 byte quantities from bus space * described by tag/handle and starting at `offset' and copy into * buffer provided. */ void rmi_pci_bus_space_read_region_1(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int8_t * addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { *addr++ = (*(volatile u_int8_t *)(baddr)); baddr += 1; } } void rmi_pci_bus_space_read_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int16_t * addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { *addr++ = (*(volatile u_int16_t *)(baddr)); baddr += 2; } } void rmi_pci_bus_space_read_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, u_int32_t * addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { *addr++ = (*(volatile u_int32_t *)(baddr)); baddr += 4; } } void rmi_pci_bus_space_write_stream_1(void *t, bus_space_handle_t handle, bus_size_t offset, u_int8_t value) { mips_sync(); *(volatile u_int8_t *)(handle + offset) = value; } static void rmi_pci_bus_space_write_stream_2(void *t, bus_space_handle_t handle, bus_size_t offset, u_int16_t value) { mips_sync(); *(volatile u_int16_t *)(handle + offset) = value; } static void rmi_pci_bus_space_write_stream_4(void *t, bus_space_handle_t handle, bus_size_t offset, u_int32_t value) { mips_sync(); *(volatile u_int32_t *)(handle + offset) = value; } static void rmi_pci_bus_space_write_multi_stream_1(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int8_t * addr, size_t count) { mips_sync(); while (count--) { (*(volatile u_int8_t *)(handle + offset)) = *addr; addr++; } } static void rmi_pci_bus_space_write_multi_stream_2(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int16_t * addr, size_t count) { mips_sync(); while (count--) { (*(volatile u_int16_t *)(handle + offset)) = *addr; addr++; } } static void rmi_pci_bus_space_write_multi_stream_4(void *tag, bus_space_handle_t handle, bus_size_t offset, const u_int32_t * addr, size_t count) { mips_sync(); while (count--) { (*(volatile u_int32_t *)(handle + offset)) = *addr; addr++; } } void rmi_pci_bus_space_write_region_2(void *t, bus_space_handle_t bsh, bus_size_t offset, const u_int16_t * addr, size_t count) { bus_addr_t baddr = (bus_addr_t) bsh + offset; while (count--) { (*(volatile u_int16_t *)(baddr)) = *addr; addr++; baddr += 2; } } void rmi_pci_bus_space_write_region_4(void *t, bus_space_handle_t bsh, bus_size_t offset, const u_int32_t * addr, size_t count) { bus_addr_t baddr = bsh + offset; while (count--) { (*(volatile u_int32_t *)(baddr)) = *addr; addr++; baddr += 4; } } static void rmi_pci_bus_space_barrier(void *tag __unused, bus_space_handle_t bsh __unused, bus_size_t offset __unused, bus_size_t len __unused, int flags) { } Index: head/sys/mips/rmi/intr_machdep.c =================================================================== --- head/sys/mips/rmi/intr_machdep.c (revision 326258) +++ head/sys/mips/rmi/intr_machdep.c (revision 326259) @@ -1,249 +1,251 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006-2009 RMI Corporation * Copyright (c) 2002-2004 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, * without modification, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * 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 xlr_intrsrc { void (*busack)(int); /* Additional ack */ struct intr_event *ie; /* event corresponding to intr */ int irq; }; static struct xlr_intrsrc xlr_interrupts[XLR_MAX_INTR]; static mips_intrcnt_t mips_intr_counters[XLR_MAX_INTR]; static int intrcnt_index; void xlr_enable_irq(int irq) { uint64_t eimr; eimr = read_c0_eimr64(); write_c0_eimr64(eimr | (1ULL << irq)); } void cpu_establish_softintr(const char *name, driver_filter_t * filt, void (*handler) (void *), void *arg, int irq, int flags, void **cookiep) { panic("Soft interrupts unsupported!\n"); } void cpu_establish_hardintr(const char *name, driver_filter_t * filt, void (*handler) (void *), void *arg, int irq, int flags, void **cookiep) { xlr_establish_intr(name, filt, handler, arg, irq, flags, cookiep, NULL); } static void xlr_post_filter(void *source) { struct xlr_intrsrc *src = source; if (src->busack) src->busack(src->irq); pic_ack(PIC_IRQ_TO_INTR(src->irq)); } static void xlr_pre_ithread(void *source) { struct xlr_intrsrc *src = source; if (src->busack) src->busack(src->irq); } static void xlr_post_ithread(void *source) { struct xlr_intrsrc *src = source; pic_ack(PIC_IRQ_TO_INTR(src->irq)); } void xlr_establish_intr(const char *name, driver_filter_t filt, driver_intr_t handler, void *arg, int irq, int flags, void **cookiep, void (*busack)(int)) { struct intr_event *ie; /* descriptor for the IRQ */ struct xlr_intrsrc *src = NULL; int errcode; if (irq < 0 || irq > XLR_MAX_INTR) panic("%s called for unknown hard intr %d", __func__, irq); /* * FIXME locking - not needed now, because we do this only on * startup from CPU0 */ src = &xlr_interrupts[irq]; ie = src->ie; if (ie == NULL) { /* * PIC based interrupts need ack in PIC, and some SoC * components need additional acks (e.g. PCI) */ if (PIC_IRQ_IS_PICINTR(irq)) errcode = intr_event_create(&ie, src, 0, irq, xlr_pre_ithread, xlr_post_ithread, xlr_post_filter, NULL, "hard intr%d:", irq); else { if (filt == NULL) panic("Not supported - non filter percpu intr"); errcode = intr_event_create(&ie, src, 0, irq, NULL, NULL, NULL, NULL, "hard intr%d:", irq); } if (errcode) { printf("Could not create event for intr %d\n", irq); return; } src->irq = irq; src->busack = busack; src->ie = ie; } intr_event_add_handler(ie, name, filt, handler, arg, intr_priority(flags), flags, cookiep); xlr_enable_irq(irq); } void cpu_intr(struct trapframe *tf) { struct intr_event *ie; uint64_t eirr, eimr; int i; critical_enter(); /* find a list of enabled interrupts */ eirr = read_c0_eirr64(); eimr = read_c0_eimr64(); eirr &= eimr; if (eirr == 0) { critical_exit(); return; } /* * No need to clear the EIRR here as the handler writes to * compare which ACKs the interrupt. */ if (eirr & (1 << IRQ_TIMER)) { intr_event_handle(xlr_interrupts[IRQ_TIMER].ie, tf); critical_exit(); return; } /* FIXME sched pin >? LOCK>? */ for (i = sizeof(eirr) * 8 - 1; i >= 0; i--) { if ((eirr & (1ULL << i)) == 0) continue; ie = xlr_interrupts[i].ie; /* Don't account special IRQs */ switch (i) { case IRQ_IPI: case IRQ_MSGRING: break; default: mips_intrcnt_inc(mips_intr_counters[i]); } /* Ack the IRQ on the CPU */ write_c0_eirr64(1ULL << i); if (intr_event_handle(ie, tf) != 0) { printf("stray interrupt %d\n", i); } } critical_exit(); } void mips_intrcnt_setname(mips_intrcnt_t counter, const char *name) { int idx = counter - intrcnt; KASSERT(counter != NULL, ("mips_intrcnt_setname: NULL counter")); snprintf(intrnames + (MAXCOMLEN + 1) * idx, MAXCOMLEN + 1, "%-*s", MAXCOMLEN, name); } mips_intrcnt_t mips_intrcnt_create(const char* name) { mips_intrcnt_t counter = &intrcnt[intrcnt_index++]; mips_intrcnt_setname(counter, name); return counter; } void cpu_init_interrupts() { int i; char name[MAXCOMLEN + 1]; /* * Initialize all available vectors so spare IRQ * would show up in systat output */ for (i = 0; i < XLR_MAX_INTR; i++) { snprintf(name, MAXCOMLEN + 1, "int%d:", i); mips_intr_counters[i] = mips_intrcnt_create(name); } } Index: head/sys/mips/rmi/pcibus.h =================================================================== --- head/sys/mips/rmi/pcibus.h (revision 326258) +++ head/sys/mips/rmi/pcibus.h (revision 326259) @@ -1,35 +1,37 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 1998 Doug Rabson * 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$ */ #define DEFAULT_PCI_CONFIG_BASE 0x18000000 #define MSI_MIPS_ADDR_BASE 0xfee00000 #define PCIE_LINK0_MSI_STATUS 0x90 #define PCIE_LINK1_MSI_STATUS 0x94 #define PCIE_LINK2_MSI_STATUS 0x190 #define PCIE_LINK3_MSI_STATUS 0x194 Index: head/sys/mips/rmi/tick.c =================================================================== --- head/sys/mips/rmi/tick.c (revision 326258) +++ head/sys/mips/rmi/tick.c (revision 326259) @@ -1,377 +1,379 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006-2007 Bruce M. Simpson. * Copyright (c) 2003-2004 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. */ /* * Simple driver for the 32-bit interval counter built in to all * MIPS32 CPUs. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include uint64_t counter_freq; struct timecounter *platform_timecounter; static DPCPU_DEFINE(uint32_t, cycles_per_tick); static uint32_t cycles_per_usec; static DPCPU_DEFINE(volatile uint32_t, counter_upper); static DPCPU_DEFINE(volatile uint32_t, counter_lower_last); static DPCPU_DEFINE(uint32_t, compare_ticks); static DPCPU_DEFINE(uint32_t, lost_ticks); struct clock_softc { int intr_rid; struct resource *intr_res; void *intr_handler; struct timecounter tc; struct eventtimer et; }; static struct clock_softc *softc; /* * Device methods */ static int clock_probe(device_t); static void clock_identify(driver_t *, device_t); static int clock_attach(device_t); static unsigned counter_get_timecount(struct timecounter *tc); void mips_timer_early_init(uint64_t clock_hz) { /* Initialize clock early so that we can use DELAY sooner */ counter_freq = clock_hz; cycles_per_usec = (clock_hz / (1000 * 1000)); } void platform_initclocks(void) { if (platform_timecounter != NULL) tc_init(platform_timecounter); } static uint64_t tick_ticker(void) { uint64_t ret; uint32_t ticktock; uint32_t t_lower_last, t_upper; /* * Disable preemption because we are working with cpu specific data. */ critical_enter(); /* * Note that even though preemption is disabled, interrupts are * still enabled. In particular there is a race with clock_intr() * reading the values of 'counter_upper' and 'counter_lower_last'. * * XXX this depends on clock_intr() being executed periodically * so that 'counter_upper' and 'counter_lower_last' are not stale. */ do { t_upper = DPCPU_GET(counter_upper); t_lower_last = DPCPU_GET(counter_lower_last); } while (t_upper != DPCPU_GET(counter_upper)); ticktock = mips_rd_count(); critical_exit(); /* COUNT register wrapped around */ if (ticktock < t_lower_last) t_upper++; ret = ((uint64_t)t_upper << 32) | ticktock; return (ret); } void mips_timer_init_params(uint64_t platform_counter_freq, int double_count) { /* * XXX: Do not use printf here: uart code 8250 may use DELAY so this * function should be called before cninit. */ counter_freq = platform_counter_freq; /* * XXX: Some MIPS32 cores update the Count register only every two * pipeline cycles. * We know this because of status registers in CP0, make it automatic. */ if (double_count != 0) counter_freq /= 2; cycles_per_usec = counter_freq / (1 * 1000 * 1000); set_cputicker(tick_ticker, counter_freq, 1); } static int sysctl_machdep_counter_freq(SYSCTL_HANDLER_ARGS) { int error; uint64_t freq; if (softc == NULL) return (EOPNOTSUPP); freq = counter_freq; error = sysctl_handle_64(oidp, &freq, sizeof(freq), req); if (error == 0 && req->newptr != NULL) { counter_freq = freq; softc->et.et_frequency = counter_freq; softc->tc.tc_frequency = counter_freq; } return (error); } SYSCTL_PROC(_machdep, OID_AUTO, counter_freq, CTLTYPE_U64 | CTLFLAG_RW, NULL, 0, sysctl_machdep_counter_freq, "QU", "Timecounter frequency in Hz"); static unsigned counter_get_timecount(struct timecounter *tc) { return (mips_rd_count()); } /* * Wait for about n microseconds (at least!). */ void DELAY(int n) { uint32_t cur, last, delta, usecs; /* * This works by polling the timer and counting the number of * microseconds that go by. */ last = mips_rd_count(); delta = usecs = 0; while (n > usecs) { cur = mips_rd_count(); /* Check to see if the timer has wrapped around. */ if (cur < last) delta += cur + (0xffffffff - last) + 1; else delta += cur - last; last = cur; if (delta >= cycles_per_usec) { usecs += delta / cycles_per_usec; delta %= cycles_per_usec; } } } static int clock_start(struct eventtimer *et, sbintime_t first, sbintime_t period) { uint32_t fdiv, div, next; if (period != 0) div = (et->et_frequency * period) >> 32; else div = 0; if (first != 0) fdiv = (et->et_frequency * first) >> 32; else fdiv = div; DPCPU_SET(cycles_per_tick, div); next = mips_rd_count() + fdiv; DPCPU_SET(compare_ticks, next); mips_wr_compare(next); return (0); } static int clock_stop(struct eventtimer *et) { DPCPU_SET(cycles_per_tick, 0); mips_wr_compare(0xffffffff); return (0); } /* * Device section of file below */ static int clock_intr(void *arg) { struct clock_softc *sc = (struct clock_softc *)arg; uint32_t cycles_per_tick; uint32_t count, compare_last, compare_next, lost_ticks; cycles_per_tick = DPCPU_GET(cycles_per_tick); /* * Set next clock edge. */ count = mips_rd_count(); compare_last = DPCPU_GET(compare_ticks); if (cycles_per_tick > 0) { compare_next = count + cycles_per_tick; DPCPU_SET(compare_ticks, compare_next); mips_wr_compare(compare_next); } else /* In one-shot mode timer should be stopped after the event. */ mips_wr_compare(0xffffffff); /* COUNT register wrapped around */ if (count < DPCPU_GET(counter_lower_last)) { DPCPU_SET(counter_upper, DPCPU_GET(counter_upper) + 1); } DPCPU_SET(counter_lower_last, count); if (cycles_per_tick > 0) { /* * Account for the "lost time" between when the timer interrupt * fired and when 'clock_intr' actually started executing. */ lost_ticks = DPCPU_GET(lost_ticks); lost_ticks += count - compare_last; /* * If the COUNT and COMPARE registers are no longer in sync * then make up some reasonable value for the 'lost_ticks'. * * This could happen, for e.g., after we resume normal * operations after exiting the debugger. */ if (lost_ticks > 2 * cycles_per_tick) lost_ticks = cycles_per_tick; while (lost_ticks >= cycles_per_tick) { if (sc->et.et_active) sc->et.et_event_cb(&sc->et, sc->et.et_arg); lost_ticks -= cycles_per_tick; } DPCPU_SET(lost_ticks, lost_ticks); } if (sc->et.et_active) sc->et.et_event_cb(&sc->et, sc->et.et_arg); return (FILTER_HANDLED); } static int clock_probe(device_t dev) { device_set_desc(dev, "Generic MIPS32 ticker"); return (BUS_PROBE_NOWILDCARD); } static void clock_identify(driver_t * drv, device_t parent) { BUS_ADD_CHILD(parent, 0, "clock", 0); } static int clock_attach(device_t dev) { struct clock_softc *sc; if (device_get_unit(dev) != 0) panic("can't attach more clocks"); softc = sc = device_get_softc(dev); cpu_establish_hardintr("compare", clock_intr, NULL, sc, IRQ_TIMER, INTR_TYPE_CLK, &sc->intr_handler); sc->tc.tc_get_timecount = counter_get_timecount; sc->tc.tc_counter_mask = 0xffffffff; sc->tc.tc_frequency = counter_freq; sc->tc.tc_name = "MIPS32"; sc->tc.tc_quality = 800; sc->tc.tc_priv = sc; tc_init(&sc->tc); sc->et.et_name = "MIPS32"; sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU; sc->et.et_quality = 800; sc->et.et_frequency = counter_freq; sc->et.et_min_period = 0x00004000LLU; /* To be safe. */ sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; sc->et.et_start = clock_start; sc->et.et_stop = clock_stop; sc->et.et_priv = sc; et_register(&sc->et); return (0); } static device_method_t clock_methods[] = { /* Device interface */ DEVMETHOD(device_probe, clock_probe), DEVMETHOD(device_identify, clock_identify), DEVMETHOD(device_attach, clock_attach), DEVMETHOD(device_detach, bus_generic_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), {0, 0} }; static driver_t clock_driver = { "clock", clock_methods, sizeof(struct clock_softc), }; static devclass_t clock_devclass; DRIVER_MODULE(clock, nexus, clock_driver, clock_devclass, 0, 0); Index: head/sys/mips/rmi/uart_bus_xlr_iodi.c =================================================================== --- head/sys/mips/rmi/uart_bus_xlr_iodi.c (revision 326258) +++ head/sys/mips/rmi/uart_bus_xlr_iodi.c (revision 326259) @@ -1,80 +1,82 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006 Raza Microelectronics * 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 ``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 static int uart_iodi_probe(device_t dev); static device_method_t uart_iodi_methods[] = { /* Device interface */ DEVMETHOD(device_probe, uart_iodi_probe), DEVMETHOD(device_attach, uart_bus_attach), DEVMETHOD(device_detach, uart_bus_detach), {0, 0} }; static driver_t uart_iodi_driver = { uart_driver_name, uart_iodi_methods, sizeof(struct uart_softc), }; extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs; static int uart_iodi_probe(device_t dev) { struct uart_softc *sc; sc = device_get_softc(dev); sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs); sc->sc_class = &uart_ns8250_class; bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas)); sc->sc_sysdev->bas.bst = rmi_bus_space; sc->sc_sysdev->bas.bsh = MIPS_PHYS_TO_KSEG1(XLR_UART0ADDR); sc->sc_bas.bst = rmi_bus_space; sc->sc_bas.bsh = MIPS_PHYS_TO_KSEG1(XLR_UART0ADDR); /* regshft = 2, rclk = 66000000, rid = 0, chan = 0 */ return (uart_bus_probe(dev, 2, 0, 66000000, 0, 0)); } DRIVER_MODULE(uart, iodi, uart_iodi_driver, uart_devclass, 0, 0); Index: head/sys/mips/rmi/uart_cpu_mips_xlr.c =================================================================== --- head/sys/mips/rmi/uart_cpu_mips_xlr.c (revision 326258) +++ head/sys/mips/rmi/uart_cpu_mips_xlr.c (revision 326259) @@ -1,84 +1,86 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006 Wojciech A. Koszek * 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. * * $Id: uart_cpu_mips_xlr.c,v 1.5 2008-07-16 20:22:39 jayachandranc Exp $ */ /* * Skeleton of this file was based on respective code for ARM * code written by Olivier Houchard. */ /* * XLRMIPS: This file is hacked from arm/... */ #include "opt_uart.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include bus_space_tag_t uart_bus_space_io; bus_space_tag_t uart_bus_space_mem; int uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) { return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0); } int uart_cpu_getdev(int devtype, struct uart_devinfo *di) { di->ops = uart_getops(&uart_ns8250_class); di->bas.chan = 0; di->bas.bst = rmi_bus_space; di->bas.bsh = MIPS_PHYS_TO_KSEG1(XLR_UART0ADDR); di->bas.regshft = 2; /* divisor = rclk / (baudrate * 16); */ di->bas.rclk = 66000000; di->baudrate = 0; di->databits = 8; di->stopbits = 1; di->parity = UART_PARITY_NONE; uart_bus_space_io = NULL; uart_bus_space_mem = rmi_bus_space; return (0); } Index: head/sys/mips/rmi/xlr_machdep.c =================================================================== --- head/sys/mips/rmi/xlr_machdep.c (revision 326258) +++ head/sys/mips/rmi/xlr_machdep.c (revision 326259) @@ -1,624 +1,626 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006-2009 RMI Corporation * Copyright (c) 2002-2004 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. * */ #include __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include #include #include #include #include #include #include #include #include #include #include #include /* cinit() */ #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 void mpwait(void); unsigned long xlr_io_base = (unsigned long)(DEFAULT_XLR_IO_BASE); /* 4KB static data aread to keep a copy of the bootload env until the dynamic kenv is setup */ char boot1_env[4096]; int rmi_spin_mutex_safe=0; struct mtx xlr_pic_lock; /* * Parameters from boot loader */ struct boot1_info xlr_boot1_info; int xlr_run_mode; int xlr_argc; int32_t *xlr_argv, *xlr_envp; uint64_t cpu_mask_info; uint32_t xlr_online_cpumask; uint32_t xlr_core_cpu_mask = 0x1; /* Core 0 thread 0 is always there */ int xlr_shtlb_enabled; int xlr_ncores; int xlr_threads_per_core; uint32_t xlr_hw_thread_mask; int xlr_cpuid_to_hwtid[MAXCPU]; int xlr_hwtid_to_cpuid[MAXCPU]; static void xlr_setup_mmu_split(void) { uint64_t mmu_setup; int val = 0; if (xlr_threads_per_core == 4 && xlr_shtlb_enabled == 0) return; /* no change from boot setup */ switch (xlr_threads_per_core) { case 1: val = 0; break; case 2: val = 2; break; case 4: val = 3; break; } mmu_setup = read_xlr_ctrl_register(4, 0); mmu_setup = mmu_setup & ~0x06; mmu_setup |= (val << 1); /* turn on global mode */ if (xlr_shtlb_enabled) mmu_setup |= 0x01; write_xlr_ctrl_register(4, 0, mmu_setup); } static void xlr_parse_mmu_options(void) { #ifdef notyet char *hw_env, *start, *end; #endif uint32_t cpu_map; uint8_t core0_thr_mask, core_thr_mask; int i, j, k; /* First check for the shared TLB setup */ xlr_shtlb_enabled = 0; #ifdef notyet /* * We don't support sharing TLB per core - TODO */ xlr_shtlb_enabled = 0; if ((hw_env = kern_getenv("xlr.shtlb")) != NULL) { start = hw_env; tmp = strtoul(start, &end, 0); if (start != end) xlr_shtlb_enabled = (tmp != 0); else printf("Bad value for xlr.shtlb [%s]\n", hw_env); freeenv(hw_env); } #endif /* * XLR supports splitting the 64 TLB entries across one, two or four * threads (split mode). XLR also allows the 64 TLB entries to be shared * across all threads in the core using a global flag (shared TLB mode). * We will support 1/2/4 threads in split mode or shared mode. * */ xlr_ncores = 1; cpu_map = xlr_boot1_info.cpu_online_map; #ifndef SMP /* Uniprocessor! */ if (cpu_map != 0x1) { printf("WARNING: Starting uniprocessor kernel on cpumask [0x%lx]!\n" "WARNING: Other CPUs will be unused.\n", (u_long)cpu_map); cpu_map = 0x1; } #endif core0_thr_mask = cpu_map & 0xf; switch (core0_thr_mask) { case 1: xlr_threads_per_core = 1; break; case 3: xlr_threads_per_core = 2; break; case 0xf: xlr_threads_per_core = 4; break; default: goto unsupp; } /* Verify other cores CPU masks */ for (i = 1; i < XLR_MAX_CORES; i++) { core_thr_mask = (cpu_map >> (i*4)) & 0xf; if (core_thr_mask) { if (core_thr_mask != core0_thr_mask) goto unsupp; xlr_ncores++; } } xlr_hw_thread_mask = cpu_map; /* setup hardware processor id to cpu id mapping */ for (i = 0; i< MAXCPU; i++) xlr_cpuid_to_hwtid[i] = xlr_hwtid_to_cpuid [i] = -1; for (i = 0, k = 0; i < XLR_MAX_CORES; i++) { if (((cpu_map >> (i*4)) & 0xf) == 0) continue; for (j = 0; j < xlr_threads_per_core; j++) { xlr_cpuid_to_hwtid[k] = i*4 + j; xlr_hwtid_to_cpuid[i*4 + j] = k; k++; } } /* setup for the startup core */ xlr_setup_mmu_split(); return; unsupp: printf("ERROR : Unsupported CPU mask [use 1,2 or 4 threads per core].\n" "\tcore0 thread mask [%lx], boot cpu mask [%lx]\n" "\tUsing default, 16 TLB entries per CPU, split mode\n", (u_long)core0_thr_mask, (u_long)cpu_map); panic("Invalid CPU mask - halting.\n"); return; } static void xlr_set_boot_flags(void) { char *p; p = kern_getenv("bootflags"); if (p == NULL) p = kern_getenv("boot_flags"); /* old style */ if (p == NULL) return; for (; p && *p != '\0'; p++) { switch (*p) { case 'd': case 'D': boothowto |= RB_KDB; break; case 'g': case 'G': boothowto |= RB_GDB; break; case 'v': case 'V': boothowto |= RB_VERBOSE; break; case 's': /* single-user (default, supported for sanity) */ case 'S': boothowto |= RB_SINGLE; break; default: printf("Unrecognized boot flag '%c'.\n", *p); break; } } freeenv(p); return; } extern uint32_t _end; static void mips_init(void) { init_param1(); init_param2(physmem); mips_cpu_init(); cpuinfo.cache_coherent_dma = TRUE; pmap_bootstrap(); #ifdef DDB kdb_init(); if (boothowto & RB_KDB) { kdb_enter("Boot flags requested debugger", NULL); } #endif mips_proc0_init(); mutex_init(); } u_int platform_get_timecount(struct timecounter *tc __unused) { return (0xffffffffU - pic_timer_count32(PIC_CLOCK_TIMER)); } static void xlr_pic_init(void) { struct timecounter pic_timecounter = { platform_get_timecount, /* get_timecount */ 0, /* no poll_pps */ ~0U, /* counter_mask */ PIC_TIMER_HZ, /* frequency */ "XLRPIC", /* name */ 2000, /* quality (adjusted in code) */ }; xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_PIC_OFFSET); int i, irq; write_c0_eimr64(0ULL); mtx_init(&xlr_pic_lock, "pic", NULL, MTX_SPIN); xlr_write_reg(mmio, PIC_CTRL, 0); /* Initialize all IRT entries */ for (i = 0; i < PIC_NUM_IRTS; i++) { irq = PIC_INTR_TO_IRQ(i); /* * Disable all IRTs. Set defaults (local scheduling, high * polarity, level * triggered, and CPU irq) */ xlr_write_reg(mmio, PIC_IRT_1(i), (1 << 30) | (1 << 6) | irq); /* Bind all PIC irqs to cpu 0 */ xlr_write_reg(mmio, PIC_IRT_0(i), 0x01); } /* Setup timer 7 of PIC as a timestamp, no interrupts */ pic_init_timer(PIC_CLOCK_TIMER); pic_set_timer(PIC_CLOCK_TIMER, ~UINT64_C(0)); platform_timecounter = &pic_timecounter; } static void xlr_mem_init(void) { struct xlr_boot1_mem_map *boot_map; vm_size_t physsz = 0; int i, j; /* get physical memory info from boot loader */ boot_map = (struct xlr_boot1_mem_map *) (unsigned long)xlr_boot1_info.psb_mem_map; for (i = 0, j = 0; i < boot_map->num_entries; i++, j += 2) { if (boot_map->physmem_map[i].type != BOOT1_MEM_RAM) continue; if (j == 14) { printf("*** ERROR *** memory map too large ***\n"); break; } if (j == 0) { /* start after kernel end */ phys_avail[0] = (vm_paddr_t) MIPS_KSEG0_TO_PHYS(&_end) + 0x20000; /* boot loader start */ /* HACK to Use bootloaders memory region */ if (boot_map->physmem_map[0].size == 0x0c000000) { boot_map->physmem_map[0].size = 0x0ff00000; } phys_avail[1] = boot_map->physmem_map[0].addr + boot_map->physmem_map[0].size; printf("First segment: addr:%#jx -> %#jx \n", (uintmax_t)phys_avail[0], (uintmax_t)phys_avail[1]); dump_avail[0] = phys_avail[0]; dump_avail[1] = phys_avail[1]; } else { #if !defined(__mips_n64) && !defined(__mips_n32) /* !PHYSADDR_64_BIT */ /* * In 32 bit physical address mode we cannot use * mem > 0xffffffff */ if (boot_map->physmem_map[i].addr > 0xfffff000U) { printf("Memory: start %#jx size %#jx ignored" "(>4GB)\n", (intmax_t)boot_map->physmem_map[i].addr, (intmax_t)boot_map->physmem_map[i].size); continue; } if (boot_map->physmem_map[i].addr + boot_map->physmem_map[i].size > 0xfffff000U) { boot_map->physmem_map[i].size = 0xfffff000U - boot_map->physmem_map[i].addr; printf("Memory: start %#jx limited to 4GB\n", (intmax_t)boot_map->physmem_map[i].addr); } #endif /* !PHYSADDR_64_BIT */ phys_avail[j] = (vm_paddr_t) boot_map->physmem_map[i].addr; phys_avail[j + 1] = phys_avail[j] + boot_map->physmem_map[i].size; printf("Next segment : addr:%#jx -> %#jx\n", (uintmax_t)phys_avail[j], (uintmax_t)phys_avail[j+1]); } dump_avail[j] = phys_avail[j]; dump_avail[j+1] = phys_avail[j+1]; physsz += boot_map->physmem_map[i].size; } phys_avail[j] = phys_avail[j + 1] = 0; realmem = physmem = btoc(physsz); } void platform_start(__register_t a0 __unused, __register_t a1 __unused, __register_t a2 __unused, __register_t a3 __unused) { int i; #ifdef SMP uint32_t tmp; void (*wakeup) (void *, void *, unsigned int); #endif /* Save boot loader and other stuff from scratch regs */ xlr_boot1_info = *(struct boot1_info *)(intptr_t)(int)read_c0_register32(MIPS_COP_0_OSSCRATCH, 0); cpu_mask_info = read_c0_register64(MIPS_COP_0_OSSCRATCH, 1); xlr_online_cpumask = read_c0_register32(MIPS_COP_0_OSSCRATCH, 2); xlr_run_mode = read_c0_register32(MIPS_COP_0_OSSCRATCH, 3); xlr_argc = read_c0_register32(MIPS_COP_0_OSSCRATCH, 4); /* * argv and envp are passed in array of 32bit pointers */ xlr_argv = (int32_t *)(intptr_t)(int)read_c0_register32(MIPS_COP_0_OSSCRATCH, 5); xlr_envp = (int32_t *)(intptr_t)(int)read_c0_register32(MIPS_COP_0_OSSCRATCH, 6); /* Initialize pcpu stuff */ mips_pcpu0_init(); /* initialize console so that we have printf */ boothowto |= (RB_SERIAL | RB_MULTIPLE); /* Use multiple consoles */ /* clockrate used by delay, so initialize it here */ cpu_clock = xlr_boot1_info.cpu_frequency / 1000000; /* * Note the time counter on CPU0 runs not at system clock speed, but * at PIC time counter speed (which is returned by * platform_get_frequency(). Thus we do not use * xlr_boot1_info.cpu_frequency here. */ mips_timer_early_init(xlr_boot1_info.cpu_frequency); /* Init console please */ cninit(); init_static_kenv(boot1_env, sizeof(boot1_env)); printf("Environment (from %d args):\n", xlr_argc - 1); if (xlr_argc == 1) printf("\tNone\n"); for (i = 1; i < xlr_argc; i++) { char *n, *arg; arg = (char *)(intptr_t)xlr_argv[i]; printf("\t%s\n", arg); n = strsep(&arg, "="); if (arg == NULL) kern_setenv(n, "1"); else kern_setenv(n, arg); } xlr_set_boot_flags(); xlr_parse_mmu_options(); xlr_mem_init(); /* Set up hz, among others. */ mips_init(); #ifdef SMP /* * If thread 0 of any core is not available then mark whole core as * not available */ tmp = xlr_boot1_info.cpu_online_map; for (i = 4; i < MAXCPU; i += 4) { if ((tmp & (0xf << i)) && !(tmp & (0x1 << i))) { /* * Oops.. thread 0 is not available. Disable whole * core */ tmp = tmp & ~(0xf << i); printf("WARNING: Core %d is disabled because thread 0" " of this core is not enabled.\n", i / 4); } } xlr_boot1_info.cpu_online_map = tmp; /* Wakeup Other cpus, and put them in bsd park code. */ wakeup = ((void (*) (void *, void *, unsigned int)) (unsigned long)(xlr_boot1_info.wakeup)); printf("Waking up CPUs 0x%jx.\n", (intmax_t)xlr_boot1_info.cpu_online_map & ~(0x1U)); if (xlr_boot1_info.cpu_online_map & ~(0x1U)) wakeup(mpwait, 0, (unsigned int)xlr_boot1_info.cpu_online_map); #endif /* xlr specific post initialization */ /* initialize other on chip stuff */ xlr_board_info_setup(); xlr_msgring_config(); xlr_pic_init(); xlr_msgring_cpu_init(); mips_timer_init_params(xlr_boot1_info.cpu_frequency, 0); printf("Platform specific startup now completes\n"); } void platform_cpu_init() { } void platform_reset(void) { xlr_reg_t *mmio = xlr_io_mmio(XLR_IO_GPIO_OFFSET); /* write 1 to GPIO software reset register */ xlr_write_reg(mmio, 8, 1); } #ifdef SMP int xlr_ap_release[MAXCPU]; int platform_start_ap(int cpuid) { int hwid = xlr_cpuid_to_hwtid[cpuid]; if (xlr_boot1_info.cpu_online_map & (1< __FBSDID("$FreeBSD$"); #include "opt_bus.h" #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 static device_attach_t ehci_xls_attach; static device_detach_t ehci_xls_detach; static const char *xlr_usb_dev_desc = "RMI XLR USB 2.0 controller"; static const char *xlr_vendor_desc = "RMI Corp"; static int ehci_xls_probe(device_t self) { /* TODO see if usb is enabled on the board */ device_set_desc(self, xlr_usb_dev_desc); return BUS_PROBE_DEFAULT; } static int ehci_xls_attach(device_t self) { ehci_softc_t *sc = device_get_softc(self); int err; int rid; sc->sc_bus.parent = self; sc->sc_bus.devices = sc->sc_devices; sc->sc_bus.devices_max = EHCI_MAX_DEVICES; sc->sc_bus.dma_bits = 32; /* get all DMA memory */ if (usb_bus_mem_alloc_all(&sc->sc_bus, USB_GET_DMA_TAG(self), &ehci_iterate_hw_softc)) { return (ENOMEM); } rid = 0; sc->sc_io_res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!sc->sc_io_res) { device_printf(self, "Could not map memory\n"); goto error; } sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); printf("IO Resource tag %lx, hdl %lx, size %lx\n", (u_long)sc->sc_io_tag, (u_long)sc->sc_io_hdl, (u_long)sc->sc_io_size); rid = 0; sc->sc_irq_res = bus_alloc_resource(self, SYS_RES_IRQ, &rid, PIC_USB_IRQ, PIC_USB_IRQ, 1, RF_SHAREABLE | RF_ACTIVE); if (sc->sc_irq_res == NULL) { device_printf(self, "Could not allocate irq\n"); goto error; } sc->sc_bus.bdev = device_add_child(self, "usbus", -1); if (!sc->sc_bus.bdev) { device_printf(self, "Could not add USB device\n"); goto error; } device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); device_set_desc(sc->sc_bus.bdev, xlr_usb_dev_desc); strlcpy(sc->sc_vendor, xlr_vendor_desc, sizeof(sc->sc_vendor)); err = bus_setup_intr(self, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, NULL, (driver_intr_t *) ehci_interrupt, sc, &sc->sc_intr_hdl); if (err) { device_printf(self, "Could not setup irq, %d\n", err); sc->sc_intr_hdl = NULL; goto error; } err = ehci_init(sc); if (err) { device_printf(self, "USB init failed err=%d\n", err); goto error; } err = device_probe_and_attach(sc->sc_bus.bdev); if (err) { device_printf(self, "USB probe and attach failed err=%d\n", err); goto error; } return (0); error: ehci_xls_detach(self); return (ENXIO); } static int ehci_xls_detach(device_t self) { ehci_softc_t *sc = device_get_softc(self); int err; /* during module unload there are lots of children leftover */ device_delete_children(self); if (sc->sc_irq_res && sc->sc_intr_hdl) { ehci_detach(sc); err = bus_teardown_intr(self, sc->sc_irq_res, sc->sc_intr_hdl); if (err) device_printf(self, "Could not tear down irq, %d\n", err); sc->sc_intr_hdl = 0; } if (sc->sc_irq_res) { bus_release_resource(self, SYS_RES_IRQ, 0, sc->sc_irq_res); sc->sc_irq_res = NULL; } if (sc->sc_io_res) { bus_release_resource(self, SYS_RES_MEMORY, 0, sc->sc_io_res); sc->sc_io_res = NULL; sc->sc_io_tag = 0; sc->sc_io_hdl = 0; } usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc); return (0); } static device_method_t ehci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ehci_xls_probe), DEVMETHOD(device_attach, ehci_xls_attach), DEVMETHOD(device_detach, ehci_xls_detach), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD_END }; static driver_t ehci_driver = { .name = "ehci", .methods = ehci_methods, .size = sizeof(struct ehci_softc), }; static devclass_t ehci_devclass; DRIVER_MODULE(ehci, iodi, ehci_driver, ehci_devclass, 0, 0); MODULE_DEPEND(ehci, usb, 1, 1, 1); Index: head/sys/mips/rt305x/obio.c =================================================================== --- head/sys/mips/rt305x/obio.c (revision 326258) +++ head/sys/mips/rt305x/obio.c (revision 326259) @@ -1,632 +1,634 @@ /* $NetBSD: obio.c,v 1.11 2003/07/15 00:25:05 lukem Exp $ */ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2001, 2002, 2003 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * 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 WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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 /* MIPS HW interrupts of IRQ/FIQ respectively */ #define RT305X_INTR 0 #define RT305X_FAST_INTR 1 /* Interrupt levels */ #define INTR_IRQ 0 #define INTR_FIQ 1 int irq_priorities[NIRQS] = { INTR_IRQ, /* SYSCTL */ INTR_FIQ, /* TIMER0 */ INTR_FIQ, /* WDTIMER */ INTR_IRQ, /* Illegal Access */ INTR_IRQ, /* PCM */ INTR_IRQ, /* UART */ INTR_IRQ, /* GPIO */ INTR_FIQ, /* GDMA */ INTR_IRQ, /* NAND */ INTR_IRQ, /* Perfomance Counter */ INTR_IRQ, /* I2S */ INTR_IRQ, /* unknown */ INTR_IRQ, /* UARTLITE */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* EtherNet Switch */ INTR_FIQ, /* OTG */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ INTR_IRQ, /* unknown */ }; #define REG_READ(o) *((volatile uint32_t *)MIPS_PHYS_TO_KSEG1(INTCTL_BASE + (o))) #define REG_WRITE(o,v) (REG_READ(o)) = (v) static int obio_activate_resource(device_t, device_t, int, int, struct resource *); static device_t obio_add_child(device_t, u_int, const char *, int); static struct resource * obio_alloc_resource(device_t, device_t, int, int *, rman_res_t, rman_res_t, rman_res_t, u_int); static int obio_attach(device_t); static int obio_deactivate_resource(device_t, device_t, int, int, struct resource *); static struct resource_list * obio_get_resource_list(device_t, device_t); static void obio_add_res_child(device_t, const char *, int, long, int, int); static void obio_hinted_child(device_t, const char *, int); static int obio_intr(void *); static int obio_probe(device_t); static int obio_release_resource(device_t, device_t, int, int, struct resource *); static int obio_setup_intr(device_t, device_t, struct resource *, int, driver_filter_t *, driver_intr_t *, void *, void **); static int obio_teardown_intr(device_t, device_t, struct resource *, void *); static void obio_mask_irq(void *source) { int irq; uint32_t irqmask; irq = (int)source; irqmask = 1 << irq; /* disable IRQ */ rt305x_ic_set(IC_INT_DIS, irqmask); } static void obio_unmask_irq(void *source) { int irq; uint32_t irqmask; irq = (int)source; irqmask = 1 << irq; /* enable IRQ */ rt305x_ic_set(IC_INT_ENA, irqmask); } static int obio_probe(device_t dev) { return (BUS_PROBE_NOWILDCARD); } static int obio_attach(device_t dev) { struct obio_softc *sc = device_get_softc(dev); int rid; sc->oba_mem_rman.rm_type = RMAN_ARRAY; sc->oba_mem_rman.rm_descr = "OBIO memory"; if (rman_init(&sc->oba_mem_rman) != 0 || rman_manage_region(&sc->oba_mem_rman, OBIO_MEM_START, OBIO_MEM_END) != 0) panic("obio_attach: failed to set up I/O rman"); sc->oba_irq_rman.rm_type = RMAN_ARRAY; sc->oba_irq_rman.rm_descr = "OBIO IRQ"; if (rman_init(&sc->oba_irq_rman) != 0 || rman_manage_region(&sc->oba_irq_rman, 0, NIRQS-1) != 0) panic("obio_attach: failed to set up IRQ rman"); /* Hook up our interrupt handler. */ if ((sc->sc_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, RT305X_INTR, RT305X_INTR, 1, RF_SHAREABLE | RF_ACTIVE)) == NULL) { device_printf(dev, "unable to allocate IRQ resource\n"); return (ENXIO); } if ((bus_setup_intr(dev, sc->sc_irq, INTR_TYPE_MISC, obio_intr, NULL, sc, &sc->sc_ih))) { device_printf(dev, "WARNING: unable to register interrupt handler\n"); return (ENXIO); } /* Hook up our FAST interrupt handler. */ if ((sc->sc_fast_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, RT305X_FAST_INTR, RT305X_FAST_INTR, 1, RF_SHAREABLE | RF_ACTIVE)) == NULL) { device_printf(dev, "unable to allocate IRQ resource\n"); return (ENXIO); } if ((bus_setup_intr(dev, sc->sc_fast_irq, INTR_TYPE_MISC, obio_intr, NULL, sc, &sc->sc_fast_ih))) { device_printf(dev, "WARNING: unable to register interrupt handler\n"); return (ENXIO); } /* disable all interrupts */ rt305x_ic_set(IC_INT_DIS, IC_INT_MASK|IC_LINE_GLOBAL); bus_generic_probe(dev); obio_add_res_child(dev, "rt305x_sysctl", 0, SYSCTL_BASE, (SYSCTL_END - SYSCTL_BASE + 1), IC_SYSCTL); obio_add_res_child(dev, "rt305x_ic", 0, INTCTL_BASE, (INTCTL_END - INTCTL_BASE + 1), -1); #ifdef notyet obio_add_res_child(dev, "timer",0, TIMER_BASE, (TIMER_END - TIMER_BASE + 1), IC_TIMER0); obio_add_res_child(dev, "rt305x_memc", 0, MEMCTRL_BASE, (MEMCTRL_END - MEMCTRL_BASE + 1), -1); obio_add_res_child(dev, "pcm", 0, PCM_BASE, (PCM_END - PCM_BASE + 1), IC_PCM); #endif obio_add_res_child(dev, "uart", 0, UART_BASE, (UART_END - UART_BASE + 1), IC_UART); obio_add_res_child(dev, "gpio", 0, PIO_BASE, (PIO_END - PIO_BASE + 1), IC_PIO); #ifdef notyet obio_add_res_child(dev, "rt305x_dma", 0, GDMA_BASE, (GDMA_END - GDMA_BASE + 1), IC_DMA); obio_add_res_child(dev, "rt305x_nandc", 0, NANDFC_BASE, (NANDFC_END - NANDFC_BASE + 1), IC_NAND); obio_add_res_child(dev, "i2c", 0, I2C_BASE, (I2C_END - I2C_BASE + 1), -1); obio_add_res_child(dev, "i2s", 0, I2S_BASE, (I2S_END - I2S_BASE + 1), IC_I2S); #endif obio_add_res_child(dev, "spi", 0, SPI_BASE, (SPI_END - SPI_BASE + 1), -1); obio_add_res_child(dev, "uart", 1, UARTLITE_BASE, (UARTLITE_END - UARTLITE_BASE + 1), IC_UARTLITE); #if !defined(RT5350) && !defined(MT7620) obio_add_res_child(dev, "cfi", 0, FLASH_BASE, (FLASH_END - FLASH_BASE + 1), -1); obio_add_res_child(dev, "dwcotg", 0, USB_OTG_BASE, (USB_OTG_END - USB_OTG_BASE + 1), IC_OTG); #else obio_add_res_child(dev, "ehci", 0, USB_OTG_BASE, (USB_OTG_END - USB_OTG_BASE + 1), IC_OTG); obio_add_res_child(dev, "ohci", 0, USB_OHCI_BASE, (USB_OHCI_END - USB_OHCI_BASE + 1), IC_OTG); #endif obio_add_res_child(dev, "switch", 0, ETHSW_BASE, (ETHSW_END - ETHSW_BASE + 1), IC_ETHSW); bus_enumerate_hinted_children(dev); bus_generic_attach(dev); /* enable IC */ rt305x_ic_set(IC_INT_ENA, IC_LINE_GLOBAL); return (0); } static struct resource * obio_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct obio_softc *sc = device_get_softc(bus); struct obio_ivar *ivar = device_get_ivars(child); struct resource *rv; struct resource_list_entry *rle; struct rman *rm; int isdefault, needactivate, passthrough; isdefault = (RMAN_IS_DEFAULT_RANGE(start, end) && count == 1); needactivate = flags & RF_ACTIVE; passthrough = (device_get_parent(child) != bus); rle = NULL; if (passthrough) return (BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type, rid, start, end, count, flags)); /* * If this is an allocation of the "default" range for a given RID, * and we know what the resources for this device are (ie. they aren't * maintained by a child bus), then work out the start/end values. */ if (isdefault) { rle = resource_list_find(&ivar->resources, type, *rid); if (rle == NULL) return (NULL); if (rle->res != NULL) { panic("%s: resource entry is busy", __func__); } start = rle->start; end = rle->end; count = rle->count; } switch (type) { case SYS_RES_IRQ: rm = &sc->oba_irq_rman; break; case SYS_RES_MEMORY: rm = &sc->oba_mem_rman; break; default: printf("%s: unknown resource type %d\n", __func__, type); return (0); } rv = rman_reserve_resource(rm, start, end, count, flags, child); if (rv == NULL) { printf("%s: could not reserve resource\n", __func__); return (0); } rman_set_rid(rv, *rid); if (needactivate) { if (bus_activate_resource(child, type, *rid, rv)) { printf("%s: could not activate resource\n", __func__); rman_release_resource(rv); return (0); } } return (rv); } static int obio_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { /* * If this is a memory resource, track the direct mapping * in the uncached MIPS KSEG1 segment. */ if (type == SYS_RES_MEMORY) { void *vaddr; vaddr = (void *)MIPS_PHYS_TO_KSEG1((intptr_t)rman_get_start(r)); rman_set_virtual(r, vaddr); rman_set_bustag(r, mips_bus_space_generic); rman_set_bushandle(r, (bus_space_handle_t)vaddr); } return (rman_activate_resource(r)); } static int obio_deactivate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { return (rman_deactivate_resource(r)); } static int obio_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { struct resource_list *rl; struct resource_list_entry *rle; rl = obio_get_resource_list(dev, child); if (rl == NULL) return (EINVAL); rle = resource_list_find(rl, type, rid); if (rle == NULL) return (EINVAL); rman_release_resource(r); rle->res = NULL; return (0); } static int obio_setup_intr(device_t dev, device_t child, struct resource *ires, int flags, driver_filter_t *filt, driver_intr_t *handler, void *arg, void **cookiep) { struct obio_softc *sc = device_get_softc(dev); struct intr_event *event; int irq, error, priority; uint32_t irqmask; irq = rman_get_start(ires); if (irq >= NIRQS) panic("%s: bad irq %d", __func__, irq); event = sc->sc_eventstab[irq]; if (event == NULL) { error = intr_event_create(&event, (void *)irq, 0, irq, obio_mask_irq, obio_unmask_irq, NULL, NULL, "obio intr%d:", irq); sc->sc_eventstab[irq] = event; } else panic("obio: Can't share IRQs"); intr_event_add_handler(event, device_get_nameunit(child), filt, handler, arg, intr_priority(flags), flags, cookiep); irqmask = 1 << irq; priority = irq_priorities[irq]; if (priority == INTR_FIQ) rt305x_ic_set(IC_INTTYPE, rt305x_ic_get(IC_INTTYPE) | irqmask); else rt305x_ic_set(IC_INTTYPE, rt305x_ic_get(IC_INTTYPE) & ~irqmask); /* enable */ obio_unmask_irq((void*)irq); return (0); } static int obio_teardown_intr(device_t dev, device_t child, struct resource *ires, void *cookie) { struct obio_softc *sc = device_get_softc(dev); int irq, result, priority; uint32_t irqmask; irq = rman_get_start(ires); if (irq >= NIRQS) panic("%s: bad irq %d", __func__, irq); if (sc->sc_eventstab[irq] == NULL) panic("Trying to teardown unoccupied IRQ"); irqmask = (1 << irq); priority = irq_priorities[irq]; if (priority == INTR_FIQ) rt305x_ic_set(IC_INTTYPE, rt305x_ic_get(IC_INTTYPE) & ~irqmask); else rt305x_ic_set(IC_INTTYPE, rt305x_ic_get(IC_INTTYPE) | irqmask); /* disable */ obio_mask_irq((void*)irq); result = intr_event_remove_handler(cookie); if (!result) { sc->sc_eventstab[irq] = NULL; } return (result); } static int obio_intr(void *arg) { struct obio_softc *sc = arg; struct intr_event *event; uint32_t irqstat; int irq; irqstat = rt305x_ic_get(IC_IRQ0STAT); irqstat |= rt305x_ic_get(IC_IRQ1STAT); irq = 0; while (irqstat != 0) { if ((irqstat & 1) == 1) { event = sc->sc_eventstab[irq]; if (!event || TAILQ_EMPTY(&event->ie_handlers)) continue; /* TODO: pass frame as an argument*/ /* TODO: log stray interrupt */ intr_event_handle(event, NULL); } irq++; irqstat >>= 1; } return (FILTER_HANDLED); } static void obio_add_res_child(device_t bus, const char *dname, int dunit, long maddr, int msize, int irq) { device_t child; int result; child = BUS_ADD_CHILD(bus, 0, dname, dunit); result = bus_set_resource(child, SYS_RES_MEMORY, 0, maddr, msize); if (result != 0) device_printf(bus, "warning: bus_set_resource() failed\n"); if (irq != -1) { result = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1); if (result != 0) device_printf(bus, "warning: bus_set_resource() failed\n"); } } static void obio_hinted_child(device_t bus, const char *dname, int dunit) { long maddr; int msize; int irq; /* * Set hard-wired resources for hinted child using * specific RIDs. */ resource_long_value(dname, dunit, "maddr", &maddr); resource_int_value(dname, dunit, "msize", &msize); if (resource_int_value(dname, dunit, "irq", &irq) == 0) irq = -1; obio_add_res_child(bus, dname, dunit, maddr, msize, irq); } static device_t obio_add_child(device_t bus, u_int order, const char *name, int unit) { device_t child; struct obio_ivar *ivar; ivar = malloc(sizeof(struct obio_ivar), M_DEVBUF, M_WAITOK | M_ZERO); resource_list_init(&ivar->resources); child = device_add_child_ordered(bus, order, name, unit); if (child == NULL) { printf("Can't add child %s%d ordered\n", name, unit); return (0); } device_set_ivars(child, ivar); return (child); } /* * Helper routine for bus_generic_rl_get_resource/bus_generic_rl_set_resource * Provides pointer to resource_list for these routines */ static struct resource_list * obio_get_resource_list(device_t dev, device_t child) { struct obio_ivar *ivar; ivar = device_get_ivars(child); return (&(ivar->resources)); } static int obio_print_all_resources(device_t dev) { struct obio_ivar *ivar = device_get_ivars(dev); struct resource_list *rl = &ivar->resources; int retval = 0; if (STAILQ_FIRST(rl)) retval += printf(" at"); retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx"); retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd"); return (retval); } static int obio_print_child(device_t bus, device_t child) { int retval = 0; retval += bus_print_child_header(bus, child); retval += obio_print_all_resources(child); if (device_get_flags(child)) retval += printf(" flags %#x", device_get_flags(child)); retval += printf(" on %s\n", device_get_nameunit(bus)); return (retval); } static device_method_t obio_methods[] = { DEVMETHOD(bus_activate_resource, obio_activate_resource), DEVMETHOD(bus_add_child, obio_add_child), DEVMETHOD(bus_alloc_resource, obio_alloc_resource), DEVMETHOD(bus_deactivate_resource, obio_deactivate_resource), DEVMETHOD(bus_get_resource_list, obio_get_resource_list), DEVMETHOD(bus_hinted_child, obio_hinted_child), DEVMETHOD(bus_print_child, obio_print_child), DEVMETHOD(bus_release_resource, obio_release_resource), DEVMETHOD(bus_setup_intr, obio_setup_intr), DEVMETHOD(bus_teardown_intr, obio_teardown_intr), DEVMETHOD(device_attach, obio_attach), DEVMETHOD(device_probe, obio_probe), DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), {0, 0}, }; static driver_t obio_driver = { "obio", obio_methods, sizeof(struct obio_softc), }; static devclass_t obio_devclass; DRIVER_MODULE(obio, nexus, obio_driver, obio_devclass, 0, 0); Index: head/sys/mips/rt305x/obiovar.h =================================================================== --- head/sys/mips/rt305x/obiovar.h (revision 326258) +++ head/sys/mips/rt305x/obiovar.h (revision 326259) @@ -1,58 +1,60 @@ /* $NetBSD: obiovar.h,v 1.4 2003/06/16 17:40:53 thorpej Exp $ */ /*- + * SPDX-License-Identifier: BSD-2-Clause-NetBSD + * * Copyright (c) 2002, 2003 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * 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 WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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$ * */ #ifndef _RT305X_OBIOVAR_H_ #define _RT305X_OBIOVAR_H_ #include /* Number of IRQs */ #define NIRQS 32 struct obio_softc { struct rman oba_mem_rman; struct rman oba_irq_rman; struct rman oba_gpio_rman; struct intr_event *sc_eventstab[NIRQS]; /* IRQ events structs */ struct resource *sc_irq; /* IRQ resource */ void *sc_ih; /* interrupt cookie */ struct resource *sc_fast_irq; /* IRQ resource */ void *sc_fast_ih; /* interrupt cookie */ }; struct obio_ivar { struct resource_list resources; }; #endif /* _RT305X_OBIOVAR_H_ */ Index: head/sys/mips/rt305x/rt305x_dotg.c =================================================================== --- head/sys/mips/rt305x/rt305x_dotg.c (revision 326258) +++ head/sys/mips/rt305x/rt305x_dotg.c (revision 326259) @@ -1,231 +1,233 @@ #include __FBSDID("$FreeBSD$"); /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2015 Stanislav Galabov. All rights reserved. * Copyright (c) 2010,2011 Aleksandr Rybalko. All rights reserved. * Copyright (c) 2007-2008 Hans Petter Selasky. 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 #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 MEM_RID 0 static device_probe_t dotg_obio_probe; static device_attach_t dotg_obio_attach; static device_detach_t dotg_obio_detach; static int dotg_obio_probe(device_t dev) { device_set_desc(dev, "DWC like USB OTG controller"); return (0); } static int dotg_obio_attach(device_t dev) { struct dwc_otg_softc *sc = device_get_softc(dev); uint32_t tmp; int err, rid; /* setup controller interface softc */ /* initialise some bus fields */ sc->sc_mode = DWC_MODE_HOST; sc->sc_bus.parent = dev; sc->sc_bus.devices = sc->sc_devices; sc->sc_bus.devices_max = DWC_OTG_MAX_DEVICES; sc->sc_bus.dma_bits = 32; /* get all DMA memory */ if (usb_bus_mem_alloc_all(&sc->sc_bus, USB_GET_DMA_TAG(dev), NULL)) { printf("No mem\n"); return (ENOMEM); } rid = 0; sc->sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (!(sc->sc_io_res)) { printf("Can`t alloc MEM\n"); goto error; } sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); sc->sc_io_size = rman_get_size(sc->sc_io_res); rid = 0; sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_ACTIVE); if (!(sc->sc_irq_res)) { printf("Can`t alloc IRQ\n"); goto error; } sc->sc_bus.bdev = device_add_child(dev, "usbus", -1); if (!(sc->sc_bus.bdev)) { printf("Can`t add usbus\n"); goto error; } device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); #if (__FreeBSD_version >= 700031) err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_TTY | INTR_MPSAFE, dwc_otg_filter_interrupt, dwc_otg_interrupt, sc, &sc->sc_intr_hdl); #else #error error err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,(driver_intr_t*)dwc_otg_interrupt, sc, &sc->sc_intr_hdl); #endif if (err) { sc->sc_intr_hdl = NULL; printf("Can`t set IRQ handle\n"); goto error; } /* Run clock for OTG core */ rt305x_sysctl_set(SYSCTL_CLKCFG1, rt305x_sysctl_get(SYSCTL_CLKCFG1) | SYSCTL_CLKCFG1_OTG_CLK_EN); tmp = rt305x_sysctl_get(SYSCTL_RSTCTRL); rt305x_sysctl_set(SYSCTL_RSTCTRL, tmp | SYSCTL_RSTCTRL_OTG); DELAY(100); /* * Docs say that RSTCTRL bits for RT305x are W1C, so there should * be no need for the below, but who really knows? */ // rt305x_sysctl_set(SYSCTL_RSTCTRL, tmp & ~SYSCTL_RSTCTRL_OTG); // DELAY(100); err = dwc_otg_init(sc); if (err) printf("dotg_init fail\n"); if (!err) { err = device_probe_and_attach(sc->sc_bus.bdev); if (err) printf("device_probe_and_attach fail %d\n", err); } if (err) { goto error; } return (0); error: dotg_obio_detach(dev); return (ENXIO); } static int dotg_obio_detach(device_t dev) { struct dwc_otg_softc *sc = device_get_softc(dev); int err; /* during module unload there are lots of children leftover */ device_delete_children(dev); if (sc->sc_irq_res && sc->sc_intr_hdl) { /* * only call dotg_obio_uninit() after dotg_obio_init() */ dwc_otg_uninit(sc); /* Stop OTG clock */ rt305x_sysctl_set(SYSCTL_CLKCFG1, rt305x_sysctl_get(SYSCTL_CLKCFG1) & ~SYSCTL_CLKCFG1_OTG_CLK_EN); err = bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intr_hdl); sc->sc_intr_hdl = NULL; } if (sc->sc_irq_res) { bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); sc->sc_irq_res = NULL; } if (sc->sc_io_res) { bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_io_res); sc->sc_io_res = NULL; } usb_bus_mem_free_all(&sc->sc_bus, NULL); return (0); } static device_method_t dotg_obio_methods[] = { /* Device interface */ DEVMETHOD(device_probe, dotg_obio_probe), DEVMETHOD(device_attach, dotg_obio_attach), DEVMETHOD(device_detach, dotg_obio_detach), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD_END }; static driver_t dotg_obio_driver = { .name = "dwcotg", .methods = dotg_obio_methods, .size = sizeof(struct dwc_otg_softc), }; static devclass_t dotg_obio_devclass; DRIVER_MODULE(dwcotg, obio, dotg_obio_driver, dotg_obio_devclass, 0, 0); Index: head/sys/mips/rt305x/rt305x_gpio.c =================================================================== --- head/sys/mips/rt305x/rt305x_gpio.c (revision 326258) +++ head/sys/mips/rt305x/rt305x_gpio.c (revision 326259) @@ -1,626 +1,628 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010-2011, Aleksandr Rybalko * Copyright (c) 2009, Oleksandr Tymoshenko * Copyright (c) 2009, Luiz Otavio O Souza. * 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 unmodified, 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. */ /* * GPIO driver for RT305X SoC. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gpio_if.h" #ifdef notyet #define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_INVIN | \ GPIO_PIN_INVOUT | GPIO_PIN_REPORT ) #else #define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_INVIN | \ GPIO_PIN_INVOUT ) #endif /* * Helpers */ static void rt305x_gpio_pin_configure(struct rt305x_gpio_softc *sc, struct gpio_pin *pin, uint32_t flags); /* * Driver stuff */ static int rt305x_gpio_probe(device_t dev); static int rt305x_gpio_attach(device_t dev); static int rt305x_gpio_detach(device_t dev); static int rt305x_gpio_intr(void *arg); int rt305x_get_int_mask (device_t); void rt305x_set_int_mask (device_t, uint32_t); int rt305x_get_int_status(device_t); void rt305x_set_int_status(device_t, uint32_t); /* * GPIO interface */ static device_t rt305x_gpio_get_bus(device_t); static int rt305x_gpio_pin_max(device_t dev, int *maxpin); static int rt305x_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps); static int rt305x_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags); static int rt305x_gpio_pin_getname(device_t dev, uint32_t pin, char *name); static int rt305x_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags); static int rt305x_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value); static int rt305x_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val); static int rt305x_gpio_pin_toggle(device_t dev, uint32_t pin); static void rt305x_gpio_pin_configure(struct rt305x_gpio_softc *sc, struct gpio_pin *pin, unsigned int flags) { GPIO_LOCK(sc); /* * Manage input/output */ if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); if (flags & GPIO_PIN_OUTPUT) { pin->gp_flags |= GPIO_PIN_OUTPUT; GPIO_BIT_SET(sc, pin->gp_pin, DIR); } else { pin->gp_flags |= GPIO_PIN_INPUT; GPIO_BIT_CLR(sc, pin->gp_pin, DIR); } } if (flags & GPIO_PIN_INVOUT) { pin->gp_flags |= GPIO_PIN_INVOUT; GPIO_BIT_SET(sc, pin->gp_pin, POL); } else { pin->gp_flags &= ~GPIO_PIN_INVOUT; GPIO_BIT_CLR(sc, pin->gp_pin, POL); } if (flags & GPIO_PIN_INVIN) { pin->gp_flags |= GPIO_PIN_INVIN; GPIO_BIT_SET(sc, pin->gp_pin, POL); } else { pin->gp_flags &= ~GPIO_PIN_INVIN; GPIO_BIT_CLR(sc, pin->gp_pin, POL); } #ifdef notyet /* Enable interrupt bits for rising/falling transitions */ if (flags & GPIO_PIN_REPORT) { pin->gp_flags |= GPIO_PIN_REPORT; GPIO_BIT_SET(sc, pin->gp_pin, RENA); GPIO_BIT_SET(sc, pin->gp_pin, FENA); device_printf(sc->dev, "Will report interrupt on pin %d\n", pin->gp_pin); } else { pin->gp_flags &= ~GPIO_PIN_REPORT; GPIO_BIT_CLR(sc, pin->gp_pin, RENA); GPIO_BIT_CLR(sc, pin->gp_pin, FENA); } #else /* Disable generating interrupts for now */ GPIO_BIT_CLR(sc, pin->gp_pin, RENA); GPIO_BIT_CLR(sc, pin->gp_pin, FENA); #endif GPIO_UNLOCK(sc); } static device_t rt305x_gpio_get_bus(device_t dev) { struct rt305x_gpio_softc *sc; sc = device_get_softc(dev); return (sc->busdev); } static int rt305x_gpio_pin_max(device_t dev, int *maxpin) { *maxpin = NGPIO - 1; return (0); } static int rt305x_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) { struct rt305x_gpio_softc *sc = device_get_softc(dev); int i; for (i = 0; i < sc->gpio_npins; i++) { if (sc->gpio_pins[i].gp_pin == pin) break; } if (i >= sc->gpio_npins) return (EINVAL); GPIO_LOCK(sc); *caps = sc->gpio_pins[i].gp_caps; GPIO_UNLOCK(sc); return (0); } static int rt305x_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) { struct rt305x_gpio_softc *sc = device_get_softc(dev); int i; for (i = 0; i < sc->gpio_npins; i++) { if (sc->gpio_pins[i].gp_pin == pin) break; } if (i >= sc->gpio_npins) return (EINVAL); GPIO_LOCK(sc); *flags = sc->gpio_pins[i].gp_flags; GPIO_UNLOCK(sc); return (0); } static int rt305x_gpio_pin_getname(device_t dev, uint32_t pin, char *name) { struct rt305x_gpio_softc *sc = device_get_softc(dev); int i; for (i = 0; i < sc->gpio_npins; i++) { if (sc->gpio_pins[i].gp_pin == pin) break; } if (i >= sc->gpio_npins) return (EINVAL); GPIO_LOCK(sc); memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); GPIO_UNLOCK(sc); return (0); } static int rt305x_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) { int i; struct rt305x_gpio_softc *sc = device_get_softc(dev); for (i = 0; i < sc->gpio_npins; i++) { if (sc->gpio_pins[i].gp_pin == pin) break; } if (i >= sc->gpio_npins) return (EINVAL); rt305x_gpio_pin_configure(sc, &sc->gpio_pins[i], flags); return (0); } static int rt305x_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) { struct rt305x_gpio_softc *sc = device_get_softc(dev); int i; for (i = 0; i < sc->gpio_npins; i++) { if (sc->gpio_pins[i].gp_pin == pin) break; } if (i >= sc->gpio_npins) return (EINVAL); GPIO_LOCK(sc); if (value) GPIO_BIT_SET(sc, i, DATA); else GPIO_BIT_CLR(sc, i, DATA); GPIO_UNLOCK(sc); return (0); } static int rt305x_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) { struct rt305x_gpio_softc *sc = device_get_softc(dev); int i; for (i = 0; i < sc->gpio_npins; i++) { if (sc->gpio_pins[i].gp_pin == pin) break; } if (i >= sc->gpio_npins) return (EINVAL); GPIO_LOCK(sc); *val = GPIO_BIT_GET(sc, i, DATA); GPIO_UNLOCK(sc); return (0); } static int rt305x_gpio_pin_toggle(device_t dev, uint32_t pin) { int i; struct rt305x_gpio_softc *sc = device_get_softc(dev); for (i = 0; i < sc->gpio_npins; i++) { if (sc->gpio_pins[i].gp_pin == pin) break; } if (i >= sc->gpio_npins) return (EINVAL); GPIO_LOCK(sc); GPIO_BIT_SET(sc, i, TOG); GPIO_UNLOCK(sc); return (0); } static int rt305x_gpio_intr(void *arg) { struct rt305x_gpio_softc *sc = arg; #ifdef notyet uint32_t i; #endif uint64_t input, value; #ifdef notyet uint64_t reset_pin; char notify[16]; char pinname[6]; #endif /* Read all reported pins */ input = GPIO_READ_ALL(sc, INT); /* Clear int status */ GPIO_WRITE_ALL(sc, INT, input); /* Clear report for OUTs */ input &= ~GPIO_READ_ALL(sc, DIR); value = input & GPIO_READ_ALL(sc, DATA); if (!input) goto intr_done; #ifdef notyet /* if reset_gpio and this pin is input */ if (sc->reset_gpio >= 0 && (input & (1 << sc->reset_gpio))) { /* get reset_gpio pin value */ reset_pin = (value & (1 << sc->reset_gpio))?1:0; if ( sc->reset_gpio_last != reset_pin ) { /* * if now reset is high, check how long * and do reset if less than 2 seconds */ if ( reset_pin && (time_uptime - sc->reset_gpio_ontime) < 2 ) shutdown_nice(0); sc->reset_gpio_last = reset_pin; sc->reset_gpio_ontime = time_uptime; } } for ( i = 0; i < NGPIO; i ++ ) { /* Next if output pin */ if ( !(( input >> i) & 1) ) continue; if ( (((value & input) >> i) & 1) != sc->gpio_pins[i].gp_last ) { /* !system=GPIO subsystem=pin7 type=PIN_HIGH period=3 */ snprintf(notify , sizeof(notify ), "period=%d", (uint32_t)time_uptime - sc->gpio_pins[i].gp_time); snprintf(pinname, sizeof(pinname), "pin%02d", i); devctl_notify("GPIO", pinname, (((value & input) >> i) & 1)?"PIN_HIGH":"PIN_LOW", notify); printf("GPIO[%s] %s %s\n", pinname, (((value & input) >> i) & 1)?"PIN_HIGH":"PIN_LOW", notify); sc->gpio_pins[i].gp_last = ((value & input) >> i) & 1; sc->gpio_pins[i].gp_time = time_uptime; } } #endif intr_done: return (FILTER_HANDLED); } static int rt305x_gpio_probe(device_t dev) { device_set_desc(dev, "RT305X GPIO driver"); return (0); } static uint64_t rt305x_gpio_init(device_t dev) { uint64_t avl = ~0ULL; uint32_t gmode = rt305x_sysctl_get(SYSCTL_GPIOMODE); if (!(gmode & SYSCTL_GPIOMODE_RGMII_GPIO_MODE)) avl &= ~RGMII_GPIO_MODE_MASK; if (!(gmode & SYSCTL_GPIOMODE_SDRAM_GPIO_MODE)) avl &= ~SDRAM_GPIO_MODE_MASK; if (!(gmode & SYSCTL_GPIOMODE_MDIO_GPIO_MODE)) avl &= ~MDIO_GPIO_MODE_MASK; if (!(gmode & SYSCTL_GPIOMODE_JTAG_GPIO_MODE)) avl &= ~JTAG_GPIO_MODE_MASK; if (!(gmode & SYSCTL_GPIOMODE_UARTL_GPIO_MODE)) avl &= ~UARTL_GPIO_MODE_MASK; if (!(gmode & SYSCTL_GPIOMODE_SPI_GPIO_MODE)) avl &= ~SPI_GPIO_MODE_MASK; if (!(gmode & SYSCTL_GPIOMODE_I2C_GPIO_MODE)) avl &= ~I2C_GPIO_MODE_MASK; if ((gmode & SYSCTL_GPIOMODE_UARTF_SHARE_MODE_GPIO) != SYSCTL_GPIOMODE_UARTF_SHARE_MODE_GPIO) avl &= ~I2C_GPIO_MODE_MASK; /* D-Link DAP-1350 Board have * MDIO_GPIO_MODE * UARTF_GPIO_MODE * SPI_GPIO_MODE * I2C_GPIO_MODE * So we have * 00000001 10000000 01111111 11111110 */ return (avl); } #define DAP1350_RESET_GPIO 10 static int rt305x_gpio_attach(device_t dev) { struct rt305x_gpio_softc *sc = device_get_softc(dev); int i; uint64_t avlpins = 0; sc->reset_gpio = DAP1350_RESET_GPIO; KASSERT((device_get_unit(dev) == 0), ("rt305x_gpio_gpio: Only one gpio module supported")); mtx_init(&sc->gpio_mtx, device_get_nameunit(dev), NULL, MTX_DEF); /* Map control/status registers. */ sc->gpio_mem_rid = 0; sc->gpio_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->gpio_mem_rid, RF_ACTIVE); if (sc->gpio_mem_res == NULL) { device_printf(dev, "couldn't map memory\n"); rt305x_gpio_detach(dev); return (ENXIO); } if ((sc->gpio_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->gpio_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { device_printf(dev, "unable to allocate IRQ resource\n"); rt305x_gpio_detach(dev); return (ENXIO); } if ((bus_setup_intr(dev, sc->gpio_irq_res, INTR_TYPE_MISC, /* rt305x_gpio_filter, */ rt305x_gpio_intr, NULL, sc, &sc->gpio_ih))) { device_printf(dev, "WARNING: unable to register interrupt handler\n"); rt305x_gpio_detach(dev); return (ENXIO); } sc->dev = dev; avlpins = rt305x_gpio_init(dev); /* Configure all pins as input */ /* disable interrupts for all pins */ /* TODO */ sc->gpio_npins = NGPIO; resource_int_value(device_get_name(dev), device_get_unit(dev), "pins", &sc->gpio_npins); for (i = 0; i < sc->gpio_npins; i++) { sc->gpio_pins[i].gp_pin = i; sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; sc->gpio_pins[i].gp_flags = 0; } /* Setup reset pin interrupt */ if (TUNABLE_INT_FETCH("reset_gpio", &sc->reset_gpio)) { device_printf(dev, "\tHinted reset_gpio %d\n", sc->reset_gpio); } #ifdef notyet if (sc->reset_gpio != -1) { rt305x_gpio_pin_setflags(dev, sc->reset_gpio, GPIO_PIN_INPUT|GPIO_PIN_INVOUT| GPIO_PIN_INVOUT|GPIO_PIN_REPORT); device_printf(dev, "\tUse reset_gpio %d\n", sc->reset_gpio); } #else if (sc->reset_gpio != -1) { rt305x_gpio_pin_setflags(dev, sc->reset_gpio, GPIO_PIN_INPUT|GPIO_PIN_INVOUT); device_printf(dev, "\tUse reset_gpio %d\n", sc->reset_gpio); } #endif sc->busdev = gpiobus_attach_bus(dev); if (sc->busdev == NULL) { rt305x_gpio_detach(dev); return (ENXIO); } return (0); } static int rt305x_gpio_detach(device_t dev) { struct rt305x_gpio_softc *sc = device_get_softc(dev); KASSERT(mtx_initialized(&sc->gpio_mtx), ("gpio mutex not initialized")); gpiobus_detach_bus(dev); if (sc->gpio_ih) bus_teardown_intr(dev, sc->gpio_irq_res, sc->gpio_ih); if (sc->gpio_irq_res) bus_release_resource(dev, SYS_RES_IRQ, sc->gpio_irq_rid, sc->gpio_irq_res); if (sc->gpio_mem_res) bus_release_resource(dev, SYS_RES_MEMORY, sc->gpio_mem_rid, sc->gpio_mem_res); mtx_destroy(&sc->gpio_mtx); return(0); } #ifdef notyet static struct resource * rt305x_gpio_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct obio_softc *sc = device_get_softc(bus); struct resource *rv; struct rman *rm; switch (type) { case SYS_RES_GPIO: rm = &sc->gpio_rman; break; default: printf("%s: unknown resource type %d\n", __func__, type); return (0); } rv = rman_reserve_resource(rm, start, end, count, flags, child); if (rv == NULL) { printf("%s: could not reserve resource\n", __func__); return (0); } rman_set_rid(rv, *rid); return (rv); } static int rt305x_gpio_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { return (rman_activate_resource(r)); } static int rt305x_gpio_deactivate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { return (rman_deactivate_resource(r)); } static int rt305x_gpio_release_resource(device_t dev, device_t child, int type, int rid, struct resource *r) { rman_release_resource(r); return (0); } #endif static device_method_t rt305x_gpio_methods[] = { DEVMETHOD(device_probe, rt305x_gpio_probe), DEVMETHOD(device_attach, rt305x_gpio_attach), DEVMETHOD(device_detach, rt305x_gpio_detach), /* GPIO protocol */ DEVMETHOD(gpio_get_bus, rt305x_gpio_get_bus), DEVMETHOD(gpio_pin_max, rt305x_gpio_pin_max), DEVMETHOD(gpio_pin_getname, rt305x_gpio_pin_getname), DEVMETHOD(gpio_pin_getflags, rt305x_gpio_pin_getflags), DEVMETHOD(gpio_pin_getcaps, rt305x_gpio_pin_getcaps), DEVMETHOD(gpio_pin_setflags, rt305x_gpio_pin_setflags), DEVMETHOD(gpio_pin_get, rt305x_gpio_pin_get), DEVMETHOD(gpio_pin_set, rt305x_gpio_pin_set), DEVMETHOD(gpio_pin_toggle, rt305x_gpio_pin_toggle), {0, 0}, }; static driver_t rt305x_gpio_driver = { "gpio", rt305x_gpio_methods, sizeof(struct rt305x_gpio_softc), }; static devclass_t rt305x_gpio_devclass; DRIVER_MODULE(rt305x_gpio, obio, rt305x_gpio_driver, rt305x_gpio_devclass, 0, 0); Index: head/sys/mips/rt305x/rt305x_gpio.h =================================================================== --- head/sys/mips/rt305x/rt305x_gpio.h (revision 326258) +++ head/sys/mips/rt305x/rt305x_gpio.h (revision 326259) @@ -1,111 +1,113 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Aleksandr Rybalko. * 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$ */ #ifndef _RT305X_GPIO_H_ #define _RT305X_GPIO_H_ #define NGPIO 52 #define RGMII_GPIO_MODE_MASK (0x0fffULL<<40) #define SDRAM_GPIO_MODE_MASK (0xffffULL<<24) #define MDIO_GPIO_MODE_MASK (0x0003ULL<<22) #define JTAG_GPIO_MODE_MASK (0x001fULL<<17) #define UARTL_GPIO_MODE_MASK (0x0003ULL<<15) #define UARTF_GPIO_MODE_MASK (0x00ffULL<<7) #define SPI_GPIO_MODE_MASK (0x000fULL<<3) #define I2C_GPIO_MODE_MASK (0x0003ULL<<1) #define GPIO23_00_INT 0x00 /* Programmed I/O Int Status */ #define GPIO23_00_EDGE 0x04 /* Programmed I/O Edge Status */ #define GPIO23_00_RENA 0x08 /* Programmed I/O Int on Rising */ #define GPIO23_00_FENA 0x0C /* Programmed I/O Int on Falling */ #define GPIO23_00_DATA 0x20 /* Programmed I/O Data */ #define GPIO23_00_DIR 0x24 /* Programmed I/O Direction */ #define GPIO23_00_POL 0x28 /* Programmed I/O Pin Polarity */ #define GPIO23_00_SET 0x2C /* Set PIO Data Bit */ #define GPIO23_00_RESET 0x30 /* Clear PIO Data bit */ #define GPIO23_00_TOG 0x34 /* Toggle PIO Data bit */ #define GPIO39_24_INT 0x38 #define GPIO39_24_EDGE 0x3c #define GPIO39_24_RENA 0x40 #define GPIO39_24_FENA 0x44 #define GPIO39_24_DATA 0x48 #define GPIO39_24_DIR 0x4c #define GPIO39_24_POL 0x50 #define GPIO39_24_SET 0x54 #define GPIO39_24_RESET 0x58 #define GPIO39_24_TOG 0x5c #define GPIO51_40_INT 0x60 #define GPIO51_40_EDGE 0x64 #define GPIO51_40_RENA 0x68 #define GPIO51_40_FENA 0x6C #define GPIO51_40_DATA 0x70 #define GPIO51_40_DIR 0x74 #define GPIO51_40_POL 0x78 #define GPIO51_40_SET 0x7C #define GPIO51_40_RESET 0x80 #define GPIO51_40_TOG 0x84 #define GPIO_REG(g, n) \ ((g<24)?(GPIO23_00_##n):(g<40)?(GPIO39_24_##n):(GPIO51_40_##n)) #define GPIO_MASK(g) \ ((g<24)?(1<gpio_mem_res, GPIO_REG(g, n)) #define GPIO_WRITE(r, g, n, v) \ bus_write_4(r->gpio_mem_res, GPIO_REG(g, n), v) #define GPIO_READ_ALL(r, n) \ (((uint64_t)bus_read_4(r->gpio_mem_res, GPIO23_00_##n)) | \ (((uint64_t)bus_read_4(r->gpio_mem_res, GPIO39_24_##n)) << 24) |\ (((uint64_t)bus_read_4(r->gpio_mem_res, GPIO51_40_##n)) << 40)) #define GPIO_WRITE_ALL(r, n, v) \ {bus_write_4(r->gpio_mem_res,GPIO23_00_##n, v &0x00ffffff);\ bus_write_4(r->gpio_mem_res, GPIO39_24_##n, (v>>24)&0x0000ffff);\ bus_write_4(r->gpio_mem_res, GPIO51_40_##n, (v>>40)&0x00000fff);} #define GPIO_BIT_CLR(r, g, n) \ bus_write_4(r->gpio_mem_res, GPIO_REG(g, n), \ bus_read_4(r->gpio_mem_res, GPIO_REG(g, n)) & ~GPIO_MASK(g)) #define GPIO_BIT_SET(r, g, n) \ bus_write_4(r->gpio_mem_res, GPIO_REG(g, n), \ bus_read_4(r->gpio_mem_res, GPIO_REG(g, n)) | GPIO_MASK(g)) #define GPIO_BIT_GET(r, g, n) \ ((bus_read_4(r->gpio_mem_res, GPIO_REG(g, n)) >> \ GPIO_BIT_SHIFT(g)) & 1) #define GPIO_LOCK(_sc) mtx_lock(&(_sc)->gpio_mtx) #define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->gpio_mtx) #define GPIO_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->gpio_mtx, MA_OWNED) #endif /* _RT305X_GPIO_H_ */ Index: head/sys/mips/rt305x/rt305x_gpiovar.h =================================================================== --- head/sys/mips/rt305x/rt305x_gpiovar.h (revision 326258) +++ head/sys/mips/rt305x/rt305x_gpiovar.h (revision 326259) @@ -1,49 +1,51 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Aleksandr Rybalko. * 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$ */ #ifndef _RT305X_GPIOVAR_H_ #define _RT305X_GPIOVAR_H_ struct rt305x_gpio_softc { device_t dev; device_t busdev; struct mtx gpio_mtx; struct resource *gpio_mem_res; int gpio_mem_rid; struct resource *gpio_irq_res; int gpio_irq_rid; void *gpio_ih; int gpio_npins; struct gpio_pin gpio_pins[NGPIO]; int reset_gpio; int reset_gpio_last; time_t reset_gpio_ontime; }; #endif /* _RT305X_GPIOVAR_H_ */ Index: head/sys/mips/rt305x/rt305x_ic.c =================================================================== --- head/sys/mips/rt305x/rt305x_ic.c (revision 326258) +++ head/sys/mips/rt305x/rt305x_ic.c (revision 326259) @@ -1,141 +1,143 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Aleksandr Rybalko. * 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 static int rt305x_ic_probe(device_t); static int rt305x_ic_attach(device_t); static int rt305x_ic_detach(device_t); static struct rt305x_ic_softc *rt305x_ic_softc = NULL; static int rt305x_ic_probe(device_t dev) { device_set_desc(dev, "RT305X Interrupt Controller driver"); return (0); } static int rt305x_ic_attach(device_t dev) { struct rt305x_ic_softc *sc = device_get_softc(dev); int error = 0; KASSERT((device_get_unit(dev) == 0), ("rt305x_ic: Only one Interrupt Controller module supported")); if (rt305x_ic_softc != NULL) return (ENXIO); rt305x_ic_softc = sc; /* Map control/status registers. */ sc->mem_rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, RF_ACTIVE); if (sc->mem_res == NULL) { device_printf(dev, "couldn't map memory\n"); error = ENXIO; rt305x_ic_detach(dev); return(error); } return (bus_generic_attach(dev)); } static int rt305x_ic_detach(device_t dev) { struct rt305x_ic_softc *sc = device_get_softc(dev); bus_generic_detach(dev); if (sc->mem_res) bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res); return(0); } uint32_t rt305x_ic_get(uint32_t reg) { struct rt305x_ic_softc *sc = rt305x_ic_softc; if (!sc) return (0); return (bus_read_4(sc->mem_res, reg)); } void rt305x_ic_set(uint32_t reg, uint32_t val) { struct rt305x_ic_softc *sc = rt305x_ic_softc; if (!sc) return; bus_write_4(sc->mem_res, reg, val); return; } static device_method_t rt305x_ic_methods[] = { DEVMETHOD(device_probe, rt305x_ic_probe), DEVMETHOD(device_attach, rt305x_ic_attach), DEVMETHOD(device_detach, rt305x_ic_detach), {0, 0}, }; static driver_t rt305x_ic_driver = { "rt305x_ic", rt305x_ic_methods, sizeof(struct rt305x_ic_softc), }; static devclass_t rt305x_ic_devclass; DRIVER_MODULE(rt305x_ic, obio, rt305x_ic_driver, rt305x_ic_devclass, 0, 0); Index: head/sys/mips/rt305x/rt305x_icvar.h =================================================================== --- head/sys/mips/rt305x/rt305x_icvar.h (revision 326258) +++ head/sys/mips/rt305x/rt305x_icvar.h (revision 326259) @@ -1,42 +1,44 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Aleksandr Rybalko. * 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$ */ #ifndef _RT305X_ICVAR_H_ #define _RT305X_ICVAR_H_ struct rt305x_ic_softc { device_t dev; struct resource *mem_res; int mem_rid; }; uint32_t rt305x_ic_get(uint32_t); void rt305x_ic_set(uint32_t, uint32_t); #endif /* _RT305X_ICVAR_H_ */ Index: head/sys/mips/rt305x/rt305x_machdep.c =================================================================== --- head/sys/mips/rt305x/rt305x_machdep.c (revision 326258) +++ head/sys/mips/rt305x/rt305x_machdep.c (revision 326259) @@ -1,207 +1,209 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (C) 2010-2011 by Aleksandr Rybalko. All rights reserved. * Copyright (C) 2007 by Oleksandr Tymoshenko. 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 ``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 HIS RELATIVES 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 MIND, 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 "opt_ddb.h" #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 #include #include #include #include #include #include #include extern int *edata; extern int *end; static char boot1_env[0x1000]; void platform_cpu_init() { /* Nothing special */ } static void mips_init(void) { int i; char *memsize; printf("entry: mips_init()\n"); if ((memsize = kern_getenv("memsize")) != NULL) realmem = btoc(strtol(memsize, NULL, 0) << 20); else realmem = btoc(32 << 20); bootverbose = 1; for (i = 0; i < 10; i++) { phys_avail[i] = 0; } /* phys_avail regions are in bytes */ dump_avail[0] = phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end); dump_avail[1] = phys_avail[1] = ctob(realmem); physmem = realmem; init_param1(); init_param2(physmem); mips_cpu_init(); pmap_bootstrap(); mips_proc0_init(); mutex_init(); kdb_init(); #ifdef KDB if (boothowto & RB_KDB) kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); #endif } void platform_reset(void) { #if !defined(MT7620) && !defined(RT5350) __asm __volatile("li $25, 0xbf000000"); __asm __volatile("j $25"); #else rt305x_sysctl_set(SYSCTL_RSTCTRL, 1); while (1); #endif } void platform_start(__register_t a0 __unused, __register_t a1 __unused, __register_t a2 __unused, __register_t a3 __unused) { vm_offset_t kernend; uint64_t platform_counter_freq = PLATFORM_COUNTER_FREQ; int i; int argc = a0; char **argv = (char **)MIPS_PHYS_TO_KSEG0(a1); char **envp = (char **)MIPS_PHYS_TO_KSEG0(a2); /* clear the BSS and SBSS segments */ kernend = (vm_offset_t)&end; memset(&edata, 0, kernend - (vm_offset_t)(&edata)); mips_postboot_fixup(); /* Initialize pcpu stuff */ mips_pcpu0_init(); mips_timer_early_init(platform_counter_freq / 2); /* initialize console so that we have printf */ boothowto |= (RB_SERIAL | RB_MULTIPLE); /* Use multiple consoles */ boothowto |= (RB_VERBOSE); cninit(); init_static_kenv(boot1_env, sizeof(boot1_env)); printf("U-Boot args (from %d args):\n", argc - 1); if (argc == 1) printf("\tNone\n"); for (i = 1; i < argc; i++) { char *n = "argv ", *arg; if (i > 99) break; if (argv[i]) { arg = (char *)(intptr_t)MIPS_PHYS_TO_KSEG0(argv[i]); printf("\targv[%d] = %s\n", i, arg); sprintf(n, "argv%d", i); kern_setenv(n, arg); } } printf("Environment:\n"); for (i = 0; envp[i] && MIPS_IS_VALID_PTR(envp[i]); i++) { char *n, *arg; arg = (char *)(intptr_t)MIPS_PHYS_TO_KSEG0(envp[i]); if (! MIPS_IS_VALID_PTR(arg)) continue; printf("\t%s\n", arg); n = strsep(&arg, "="); if (arg == NULL) kern_setenv(n, "1"); else kern_setenv(n, arg); } mips_init(); mips_timer_init_params(platform_counter_freq, 1); } Index: head/sys/mips/rt305x/rt305x_sysctl.c =================================================================== --- head/sys/mips/rt305x/rt305x_sysctl.c (revision 326258) +++ head/sys/mips/rt305x/rt305x_sysctl.c (revision 326259) @@ -1,242 +1,244 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Aleksandr Rybalko. * 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 static int rt305x_sysctl_probe(device_t); static int rt305x_sysctl_attach(device_t); static int rt305x_sysctl_detach(device_t); static struct rt305x_sysctl_softc *rt305x_sysctl_softc = NULL; static void rt305x_sysctl_dump_config(device_t dev) { uint32_t val; #define DUMPREG(r) \ val = rt305x_sysctl_get(r); printf(" " #r "=%#08x\n", val) val = rt305x_sysctl_get(SYSCTL_CHIPID0_3); printf("\tChip ID: \"%c%c%c%c", (val >> 0 ) & 0xff, (val >> 8 ) & 0xff, (val >> 16) & 0xff, (val >> 24) & 0xff); val = rt305x_sysctl_get(SYSCTL_CHIPID4_7); printf("%c%c%c%c\"\n", (val >> 0 ) & 0xff, (val >> 8 ) & 0xff, (val >> 16) & 0xff, (val >> 24) & 0xff); DUMPREG(SYSCTL_SYSCFG); #if !defined(RT5350) && !defined(MT7620) if ( val & SYSCTL_SYSCFG_INIC_EE_SDRAM) printf("\tGet SDRAM config from EEPROM\n"); if ( val & SYSCTL_SYSCFG_INIC_8MB_SDRAM) printf("\tBootstrap flag is set\n"); printf("\tGE0 mode %u\n", ((val & SYSCTL_SYSCFG_GE0_MODE_MASK) >> SYSCTL_SYSCFG_GE0_MODE_SHIFT)); if ( val & SYSCTL_SYSCFG_BOOT_ADDR_1F00) printf("\tBoot from 0x1f000000\n"); if ( val & SYSCTL_SYSCFG_BYPASS_PLL) printf("\tBypass PLL\n"); if ( val & SYSCTL_SYSCFG_BIG_ENDIAN) printf("\tBig Endian\n"); if ( val & SYSCTL_SYSCFG_CPU_CLK_SEL_384MHZ) printf("\tClock is 384MHz\n"); printf("\tBoot from %u\n", ((val & SYSCTL_SYSCFG_BOOT_FROM_MASK) >> SYSCTL_SYSCFG_BOOT_FROM_SHIFT)); printf("\tBootstrap test code %u\n", ((val & SYSCTL_SYSCFG_TEST_CODE_MASK) >> SYSCTL_SYSCFG_TEST_CODE_SHIFT)); printf("\tSRAM_CS mode %u\n", ((val & SYSCTL_SYSCFG_SRAM_CS_MODE_MASK) >> SYSCTL_SYSCFG_SRAM_CS_MODE_SHIFT)); printf("\t%umA SDRAM_CLK driving\n", (val & SYSCTL_SYSCFG_SDRAM_CLK_DRV)?12:8); DUMPREG(SYSCTL_CLKCFG0); printf("\tSDRAM_CLK_SKEW %uns\n", (val >> 30) & 0x03); DUMPREG(SYSCTL_CLKCFG1); if ( val & SYSCTL_CLKCFG1_PBUS_DIV_CLK_BY2) printf("\tPbus clock is 1/2 of System clock\n"); if ( val & SYSCTL_CLKCFG1_OTG_CLK_EN) printf("\tUSB OTG clock is enabled\n"); if ( val & SYSCTL_CLKCFG1_I2S_CLK_EN) printf("\tI2S clock is enabled\n"); printf("\tI2S clock is %s\n", (val & SYSCTL_CLKCFG1_I2S_CLK_SEL_EXT)? "external":"internal 15.625MHz"); printf("\tI2S clock divider %u\n", ((val & SYSCTL_CLKCFG1_I2S_CLK_DIV_MASK) >> SYSCTL_CLKCFG1_I2S_CLK_DIV_SHIFT)); if ( val & SYSCTL_CLKCFG1_PCM_CLK_EN) printf("\tPCM clock is enabled\n"); printf("\tPCM clock is %s\n", (val & SYSCTL_CLKCFG1_PCM_CLK_SEL_EXT)? "external":"internal 15.625MHz"); printf("\tPCM clock divider %u\n", ((val & SYSCTL_CLKCFG1_PCM_CLK_DIV_MASK) >> SYSCTL_CLKCFG1_PCM_CLK_DIV_SHIFT)); DUMPREG(SYSCTL_GPIOMODE); #endif #undef DUMPREG return; } static int rt305x_sysctl_probe(device_t dev) { device_set_desc(dev, "RT305X System Control driver"); return (0); } static int rt305x_sysctl_attach(device_t dev) { struct rt305x_sysctl_softc *sc = device_get_softc(dev); int error = 0; KASSERT((device_get_unit(dev) == 0), ("rt305x_sysctl: Only one sysctl module supported")); if (rt305x_sysctl_softc != NULL) return (ENXIO); rt305x_sysctl_softc = sc; /* Map control/status registers. */ sc->mem_rid = 0; sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, RF_ACTIVE); if (sc->mem_res == NULL) { device_printf(dev, "couldn't map memory\n"); error = ENXIO; rt305x_sysctl_detach(dev); return(error); } #ifdef notyet sc->irq_rid = 0; if ((sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { device_printf(dev, "unable to allocate IRQ resource\n"); return (ENXIO); } if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC, rt305x_sysctl_intr, NULL, sc, &sc->sysctl_ih))) { device_printf(dev, "WARNING: unable to register interrupt handler\n"); return (ENXIO); } #endif rt305x_sysctl_dump_config(dev); return (bus_generic_attach(dev)); } static int rt305x_sysctl_detach(device_t dev) { struct rt305x_sysctl_softc *sc = device_get_softc(dev); bus_generic_detach(dev); if (sc->mem_res) bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res); #ifdef notyet if (sc->irq_res) bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, sc->irq_res); #endif return(0); } #ifdef notyet static int rt305x_sysctl_intr(void *arg) { return (FILTER_HANDLED); } #endif uint32_t rt305x_sysctl_get(uint32_t reg) { struct rt305x_sysctl_softc *sc = rt305x_sysctl_softc; return (bus_read_4(sc->mem_res, reg)); } void rt305x_sysctl_set(uint32_t reg, uint32_t val) { struct rt305x_sysctl_softc *sc = rt305x_sysctl_softc; bus_write_4(sc->mem_res, reg, val); return; } static device_method_t rt305x_sysctl_methods[] = { DEVMETHOD(device_probe, rt305x_sysctl_probe), DEVMETHOD(device_attach, rt305x_sysctl_attach), DEVMETHOD(device_detach, rt305x_sysctl_detach), {0, 0}, }; static driver_t rt305x_sysctl_driver = { "rt305x_sysctl", rt305x_sysctl_methods, sizeof(struct rt305x_sysctl_softc), }; static devclass_t rt305x_sysctl_devclass; DRIVER_MODULE(rt305x_sysctl, obio, rt305x_sysctl_driver, rt305x_sysctl_devclass, 0, 0); Index: head/sys/mips/rt305x/rt305x_sysctlvar.h =================================================================== --- head/sys/mips/rt305x/rt305x_sysctlvar.h (revision 326258) +++ head/sys/mips/rt305x/rt305x_sysctlvar.h (revision 326259) @@ -1,45 +1,47 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Aleksandr Rybalko. * 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$ */ #ifndef _RT305X_SYSCTLVAR_H_ #define _RT305X_SYSCTLVAR_H_ struct rt305x_sysctl_softc { device_t dev; struct resource *mem_res; int mem_rid; struct resource *irq_res; int irq_rid; int sysctl_ih; }; uint32_t rt305x_sysctl_get(uint32_t); void rt305x_sysctl_set(uint32_t, uint32_t); #endif /* _RT305X_SYSCTLVAR_H_ */ Index: head/sys/mips/rt305x/rt305xreg.h =================================================================== --- head/sys/mips/rt305x/rt305xreg.h (revision 326258) +++ head/sys/mips/rt305x/rt305xreg.h (revision 326259) @@ -1,532 +1,534 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2015 Stanislav Galabov. * Copyright (c) 2010 Aleksandr Rybalko. * 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$ */ #ifndef _RT305XREG_H_ #define _RT305XREG_H_ #include "opt_rt305x.h" #ifdef RT3052F #define PLATFORM_COUNTER_FREQ (384 * 1000 * 1000) #endif #ifdef RT3050F #define PLATFORM_COUNTER_FREQ (320 * 1000 * 1000) #endif #ifdef MT7620 #define PLATFORM_COUNTER_FREQ (580 * 1000 * 1000) #endif #ifdef RT5350 #define PLATFORM_COUNTER_FREQ (360 * 1000 * 1000) #endif #ifndef PLATFORM_COUNTER_FREQ #error "No platform selected" #endif #ifndef MT7620 #define SYSTEM_CLOCK (PLATFORM_COUNTER_FREQ/3) #define SDRAM_BASE 0x00000000 #define SDRAM_END 0x03FFFFFF #define SYSCTL_BASE 0x10000000 #define SYSCTL_END 0x100000FF #define TIMER_BASE 0x10000100 #define TIMER_END 0x100001FF #define INTCTL_BASE 0x10000200 #define INTCTL_END 0x100002FF #define MEMCTRL_BASE 0x10000300 #define MEMCTRL_END 0x100003FF /* SDRAM & Flash/SRAM */ #ifndef RT5350 #define PCM_BASE 0x10000400 #define PCM_END 0x100004FF #else #define PCM_BASE 0x10002000 #define PCM_END 0x100027FF #endif #define UART_BASE 0x10000500 #define UART_END 0x100005FF #define PIO_BASE 0x10000600 #define PIO_END 0x100006FF #ifndef RT5350 #define GDMA_BASE 0x10000700 #define GDMA_END 0x100007FF /* Generic DMA */ #define NANDFC_BASE 0x10000800 #define NANDFC_END 0x100008FF /* NAND Flash Controller */ #else #define GDMA_BASE 0x10002800 #define GDMA_END 0x10002FFF #endif #define I2C_BASE 0x10000900 #define I2C_END 0x100009FF #define I2S_BASE 0x10000A00 #define I2S_END 0x10000AFF #define SPI_BASE 0x10000B00 #define SPI_END 0x10000BFF #define UARTLITE_BASE 0x10000C00 #define UARTLITE_END 0x10000CFF #define FRENG_BASE 0x10100000 #define FRENG_END 0x1010FFFF /* Frame Engine */ #define ETHSW_BASE 0x10110000 #define ETHSW_END 0x10117FFF /* Ethernet Switch */ #define ROM_BASE 0x10118000 #define ROM_END 0x10119FFF #define WLAN_BASE 0x10180000 #define WLAN_END 0x101BFFFF /* 802.11n MAC/BBP */ #ifndef RT5350 #define USB_OTG_BASE 0x101C0000 #define USB_OTG_END 0x101FFFFF #else #define USB_OTG_BASE 0x101C0000 #define USB_OTG_END 0x101C0FFF #define USB_OHCI_BASE 0x101C1000 #define USB_OHCI_END 0x101C1FFF #endif #define EMEM_BASE 0x1B000000 #define EMEM_END 0x1BFFFFFF /* External SRAM/Flash */ #ifdef RT5350 #define BOOT_ROM_BASE 0x1C000000 #define BOOT_ROM_END 0x1C003FFF #endif #ifndef RT5350 #define FLASH_BASE 0x1F000000 #define FLASH_END 0x1FFFFFFF /* Flash window */ #endif #define OBIO_MEM_BASE SYSCTL_BASE #define OBIO_MEM_START OBIO_MEM_BASE #ifndef RT5350 #define OBIO_MEM_END FLASH_END #else #define OBIO_MEM_END BOOT_ROM_END #endif #else /* MT7620 */ #define SYSTEM_CLOCK (40 * 1000 * 1000) #define SDRAM_BASE 0x00000000 #define SDRAM_END 0x0FFFFFFF #define SYSCTL_BASE 0x10000000 #define SYSCTL_END 0x100000FF #define TIMER_BASE 0x10000100 #define TIMER_END 0x100001FF #define INTCTL_BASE 0x10000200 #define INTCTL_END 0x100002FF #define MEMCTRL_BASE 0x10000300 #define MEMCTRL_END 0x100003FF /* SDRAM & Flash/SRAM */ #define PCM_BASE 0x10002000 #define PCM_END 0x100027FF #define UART_BASE 0x10000500 #define UART_END 0x100005FF #define PIO_BASE 0x10000600 #define PIO_END 0x100006FF #define GDMA_BASE 0x10002800 #define GDMA_END 0x10002FFF /* Generic DMA */ #define NANDFC_BASE 0x10000800 #define NANDFC_END 0x100008FF /* NAND Flash Controller */ #define I2C_BASE 0x10000900 #define I2C_END 0x100009FF #define I2S_BASE 0x10000A00 #define I2S_END 0x10000AFF #define SPI_BASE 0x10000B00 #define SPI_END 0x10000BFF #define UARTLITE_BASE 0x10000C00 #define UARTLITE_END 0x10000CFF #define FRENG_BASE 0x10100000 #define FRENG_END 0x1010FFFF /* Frame Engine */ #define ETHSW_BASE 0x10110000 #define ETHSW_END 0x10117FFF /* Ethernet Switch */ #define ROM_BASE 0x10118000 #define ROM_END 0x1011FFFF #define WLAN_BASE 0x10180000 #define WLAN_END 0x101BFFFF /* 802.11n MAC/BBP */ #define USB_OTG_BASE 0x101C0000 #define USB_OTG_END 0x101C0FFF #define USB_OHCI_BASE 0x101C1000 #define USB_OHCI_END 0x101C1FFF #define PCIE_BASE 0x10140000 #define PCIE_END 0x1017FFFF #define SDHC_BASE 0x10130000 #define SDHC_END 0x10133FFF #define PCIE_IO_BASE 0x10160000 #define PCIE_IO_END 0x1016FFFF #define PCIE_MEM_BASE 0x20000000 #define PCIE_MEM_END 0x2FFFFFFF // TODO: fix below mappings? #define EMEM_BASE 0x1B000000 #define EMEM_END 0x1BFFFFFF /* External SRAM/Flash */ #define FLASH_BASE 0x1F000000 #define FLASH_END 0x1FFFFFFF /* Flash window */ #define OBIO_MEM_BASE SYSCTL_BASE #define OBIO_MEM_START OBIO_MEM_BASE #define OBIO_MEM_END FLASH_END #endif /* System Control */ #define SYSCTL_CHIPID0_3 0x00 #define SYSCTL_CHIPID4_7 0x04 #ifdef RT5350 #define SYSCTL_REVID 0x0C #endif #define SYSCTL_SYSCFG 0x10 #if !defined(RT5350) && !defined(MT7620) #define SYSCTL_SYSCFG_INIC_EE_SDRAM (1<<29) #define SYSCTL_SYSCFG_INIC_8MB_SDRAM (1<<28) #define SYSCTL_SYSCFG_GE0_MODE_MASK 0x03000000 #define SYSCTL_SYSCFG_GE0_MODE_SHIFT 24 #define SYSCTL_SYSCFG_GE0_MODE_RGMII 0 /* RGMII Mode */ #define SYSCTL_SYSCFG_GE0_MODE_MII 1 /* MII Mode */ #define SYSCTL_SYSCFG_GE0_MODE_REV_MII 2 /*Reversed MII Mode*/ #define SYSCTL_SYSCFG_BOOT_ADDR_1F00 (1<<22) #define SYSCTL_SYSCFG_BYPASS_PLL (1<<21) #define SYSCTL_SYSCFG_BIG_ENDIAN (1<<20) #define SYSCTL_SYSCFG_CPU_CLK_SEL_384MHZ (1<<18) #define SYSCTL_SYSCFG_BOOT_FROM_MASK 0x00030000 #define SYSCTL_SYSCFG_BOOT_FROM_SHIFT 16 #define SYSCTL_SYSCFG_BOOT_FROM_FLASH16 0 #define SYSCTL_SYSCFG_BOOT_FROM_FLASH8 1 #define SYSCTL_SYSCFG_BOOT_FROM_NANDFLASH 2 #define SYSCTL_SYSCFG_BOOT_FROM_ROM 3 #define SYSCTL_SYSCFG_TEST_CODE_MASK 0x0000ff00 #define SYSCTL_SYSCFG_TEST_CODE_SHIFT 8 #define SYSCTL_SYSCFG_SRAM_CS_MODE_MASK 0x0000000c #define SYSCTL_SYSCFG_SRAM_CS_MODE_SHIFT 2 #define SYSCTL_SYSCFG_SRAM_CS_MODE_SRAM 0 #define SYSCTL_SYSCFG_SRAM_CS_MODE_WDOG_RST 1 #define SYSCTL_SYSCFG_SRAM_CS_MODE_BT_COEX 2 #define SYSCTL_SYSCFG_SDRAM_CLK_DRV (1<<0) /* 8mA/12mA */ #endif #ifdef RT5350 #define SYSCTL1_SYSCFG_PULL_EN (1<<26) #define SYSCTL1_SYSCFG_SDR_PAD_DRV_MASK 0x0700000 #define SYSCTL1_SYSCFG_SDR_PAD_DRV_SHIFT 20 #define SYSCTL1_SYSCFG_SDR_PAD_DRV_0 0 #define SYSCTL1_SYSCFG_SDR_PAD_DRV_1 1 #define SYSCTL1_SYSCFG_SDR_PAD_DRV_2 2 #endif #define SYSCTL_SYSCFG1 0x14 #define SYSCTL_SYSCFG1_USB0_HOST_MODE (1 << 10) #define SYSCTL_TESTSTAT 0x18 #define SYSCTL_TESTSTAT2 0x1C #define SYSCTL_CLKCFG0 0x2C #define SYSCTL_CLKCFG0_SDRAM_CLK_SKEW_MASK 0xc0000000 #define SYSCTL_CLKCFG0_SDRAM_CLK_SKEW_SHIFT 30 #define SYSCTL_CLKCFG0_SDRAM_CLK_SKEW_ZERO_DELAY 0 #define SYSCTL_CLKCFG0_SDRAM_CLK_SKEW_1NS_DELAY 1 #define SYSCTL_CLKCFG0_SDRAM_CLK_SKEW_2NS_DELAY 2 #define SYSCTL_CLKCFG0_SDRAM_CLK_SKEW_3NS_DELAY 3 #define SYSCTL_CLKCFG1 0x30 #if !defined(RT5350) #define SYSCTL_CLKCFG1_PBUS_DIV_CLK_BY2 (1<<30) #define SYSCTL_CLKCFG1_UPHY0_CLK_EN (1<<25) #define SYSCTL_CLKCFG1_UPHY1_CLK_EN (1<<22) #define SYSCTL_CLKCFG1_OTG_CLK_EN (1<<18) #define SYSCTL_CLKCFG1_I2S_CLK_EN (1<<15) #define SYSCTL_CLKCFG1_I2S_CLK_SEL_EXT (1<<14) #define SYSCTL_CLKCFG1_I2S_CLK_DIV_MASK 0x00003f00 #define SYSCTL_CLKCFG1_I2S_CLK_DIV_SHIFT 8 #define SYSCTL_CLKCFG1_PCM_CLK_EN (1<<7) #define SYSCTL_CLKCFG1_PCM_CLK_SEL_EXT (1<<6) #define SYSCTL_CLKCFG1_PCM_CLK_DIV_MASK 0x0000003f #define SYSCTL_CLKCFG1_PCM_CLK_DIV_SHIFT 0 #endif #ifdef RT5350 #define SYSCTL_CLKCFG1_SYSTICK_EN (1<<29) #define SYSCTL_CLKCFG1_PDMA_CSR_CLK_GATE_BYP (1<<23) #define SYSCTL_CLKCFG1_UPHY0_CLK_EN (1<<18) #endif #define SYSCTL_RSTCTRL 0x34 #define SYSCTL_RSTCTRL_ETHSW (1<<23) #if !defined(MT7620) && !defined(RT5350) #define SYSCTL_RSTCTRL_OTG (1<<22) #else #define SYSCTL_RSTCTRL_UPHY0 (1<<25) #define SYSCTL_RSTCTRL_UPHY1 (1<<22) #endif #define SYSCTL_RSTCTRL_FRENG (1<<21) #define SYSCTL_RSTCTRL_WLAN (1<<20) #define SYSCTL_RSTCTRL_UARTL (1<<19) #define SYSCTL_RSTCTRL_SPI (1<<18) #define SYSCTL_RSTCTRL_I2S (1<<17) #define SYSCTL_RSTCTRL_I2C (1<<16) #define SYSCTL_RSTCTRL_DMA (1<<14) #define SYSCTL_RSTCTRL_PIO (1<<13) #define SYSCTL_RSTCTRL_UART (1<<12) #define SYSCTL_RSTCTRL_PCM (1<<11) #define SYSCTL_RSTCTRL_MC (1<<10) #define SYSCTL_RSTCTRL_INTC (1<<9) #define SYSCTL_RSTCTRL_TIMER (1<<8) #define SYSCTL_RSTCTRL_SYS (1<<0) #define SYSCTL_RSTSTAT 0x38 #define SYSCTL_RSTSTAT_SWCPURST (1<<3) #define SYSCTL_RSTSTAT_SWSYSRST (1<<2) #define SYSCTL_RSTSTAT_WDRST (1<<1) #define SYSCTL_GPIOMODE 0x60 #define SYSCTL_GPIOMODE_RGMII_GPIO_MODE (1<<9) #define SYSCTL_GPIOMODE_SDRAM_GPIO_MODE (1<<8) #define SYSCTL_GPIOMODE_MDIO_GPIO_MODE (1<<7) #define SYSCTL_GPIOMODE_JTAG_GPIO_MODE (1<<6) #define SYSCTL_GPIOMODE_UARTL_GPIO_MODE (1<<5) #define SYSCTL_GPIOMODE_UARTF_SHARE_MODE_UARTF (0<<2) #define SYSCTL_GPIOMODE_UARTF_SHARE_MODE_PCM_UARTF (1<<2) #define SYSCTL_GPIOMODE_UARTF_SHARE_MODE_PCM_I2S (2<<2) #define SYSCTL_GPIOMODE_UARTF_SHARE_MODE_I2S_UARTF (3<<2) #define SYSCTL_GPIOMODE_UARTF_SHARE_MODE_PCM_GPIO (4<<2) #define SYSCTL_GPIOMODE_UARTF_SHARE_MODE_GPIO_UARTF (5<<2) #define SYSCTL_GPIOMODE_UARTF_SHARE_MODE_GPIO_I2S (6<<2) #define SYSCTL_GPIOMODE_UARTF_SHARE_MODE_GPIO (7<<2) #define SYSCTL_GPIOMODE_SPI_GPIO_MODE (1<<1) #define SYSCTL_GPIOMODE_I2C_GPIO_MODE (1<<0) #define SYSCTL_MEMO0 0x68 #define SYSCTL_MEMO1 0x6C #define SYSCTL_PPLL_CFG1 0x9C #define SYSCTL_PPLL_DRV 0xA0 /* Timer */ #define TIMER_TMRSTAT 0x00 #define TIMER_TMRSTAT_TMR1RST (1<<5) #define TIMER_TMRSTAT_TMR0RST (1<<4) #define TIMER_TMRSTAT_TMR1INT (1<<1) #define TIMER_TMRSTAT_TMR0INT (1<<0) #define TIMER_TMR0LOAD 0x10 #define TIMER_TMR0VAL 0x14 #define TIMER_TMR0CTL 0x18 #define TIMER_TMR1LOAD 0x20 #define TIMER_TMR1VAL 0x24 #define TIMER_TMR1CTL 0x28 #define TIMER_TMRLOAD_TMR0LOAD_MASK 0xffff #define TIMER_TMRVAL_TMR0VAL_MASK 0xffff #define TIMER_TMRCTL_ENABLE (1<<7) #define TIMER_TMRCTL_MODE_MASK 0x00000030 #define TIMER_TMRCTL_MODE_SHIFT 4 #define TIMER_TMRCTL_MODE_FREE 0 #define TIMER_TMRCTL_MODE_PERIODIC 1 #define TIMER_TMRCTL_MODE_TIMOUT 2 #define TIMER_TMRCTL_MODE_TIMOUT3 3 #define TIMER_TMRCTL_PRESCALE_MASK 0x0000000f #define TIMER_TMRCTL_PRESCALE_SHIFT 0 #define TIMER_TMRCTL_PRESCALE_NONE 0 #define TIMER_TMRCTL_PRESCALE_BY_4 1 #define TIMER_TMRCTL_PRESCALE_BY_8 2 #define TIMER_TMRCTL_PRESCALE_BY_16 3 #define TIMER_TMRCTL_PRESCALE_BY_32 4 #define TIMER_TMRCTL_PRESCALE_BY_64 5 #define TIMER_TMRCTL_PRESCALE_BY_128 6 #define TIMER_TMRCTL_PRESCALE_BY_256 7 #define TIMER_TMRCTL_PRESCALE_BY_512 8 #define TIMER_TMRCTL_PRESCALE_BY_1K 9 #define TIMER_TMRCTL_PRESCALE_BY_2K 10 #define TIMER_TMRCTL_PRESCALE_BY_4K 11 #define TIMER_TMRCTL_PRESCALE_BY_8K 12 #define TIMER_TMRCTL_PRESCALE_BY_16K 13 #define TIMER_TMRCTL_PRESCALE_BY_32K 14 #define TIMER_TMRCTL_PRESCALE_BY_64K 15 /* Interrupt Controller */ #define IC_IRQ0STAT 0x00 #define IC_IRQ1STAT 0x04 #define IC_INTTYPE 0x20 #define IC_INTRAW 0x30 #define IC_INT_ENA 0x34 #define IC_INT_DIS 0x38 #define IC_OTG 18 #define IC_ETHSW 17 #define IC_R2P 15 #define IC_SDHC 14 #define IC_UARTLITE 12 #define IC_SPI 11 #define IC_I2S 10 #define IC_PERFC 9 #define IC_NAND 8 #define IC_DMA 7 #define IC_PIO 6 #define IC_UART 5 #define IC_PCM 4 #define IC_ILL_ACCESS 3 #define IC_WDTIMER 2 #define IC_TIMER0 1 #define IC_SYSCTL 0 #define IC_LINE_GLOBAL (1<<31) /* Only for DIS/ENA regs */ #define IC_LINE_OTG (1<<18) #define IC_LINE_ETHSW (1<<17) #define IC_LINE_UARTLITE (1<<12) #define IC_LINE_I2S (1<<10) #define IC_LINE_PERFC (1<<9) #define IC_LINE_NAND (1<<8) #define IC_LINE_DMA (1<<7) #define IC_LINE_PIO (1<<6) #define IC_LINE_UART (1<<5) #define IC_LINE_PCM (1<<4) #define IC_LINE_ILL_ACCESS (1<<3) #define IC_LINE_WDTIMER (1<<2) #define IC_LINE_TIMER0 (1<<1) #define IC_LINE_SYSCTL (1<<0) #define IC_INT_MASK 0x000617ff /* GPIO */ #define GPIO23_00_INT 0x00 /* Programmed I/O Int Status */ #define GPIO23_00_EDGE 0x04 /* Programmed I/O Edge Status */ #define GPIO23_00_RENA 0x08 /* Programmed I/O Int on Rising */ #define GPIO23_00_FENA 0x0C /* Programmed I/O Int on Falling */ #define GPIO23_00_DATA 0x20 /* Programmed I/O Data */ #define GPIO23_00_DIR 0x24 /* Programmed I/O Direction */ #define GPIO23_00_POL 0x28 /* Programmed I/O Pin Polarity */ #define GPIO23_00_SET 0x2C /* Set PIO Data Bit */ #define GPIO23_00_RESET 0x30 /* Clear PIO Data bit */ #define GPIO23_00_TOG 0x34 /* Toggle PIO Data bit */ #define GPIO39_24_INT 0x38 #define GPIO39_24_EDGE 0x3c #define GPIO39_24_RENA 0x40 #define GPIO39_24_FENA 0x44 #define GPIO39_24_DATA 0x48 #define GPIO39_24_DIR 0x4c #define GPIO39_24_POL 0x50 #define GPIO39_24_SET 0x54 #define GPIO39_24_RESET 0x58 #define GPIO39_24_TOG 0x5c #define GPIO51_40_INT 0x60 #define GPIO51_40_EDGE 0x64 #define GPIO51_40_RENA 0x68 #define GPIO51_40_FENA 0x6C #define GPIO51_40_DATA 0x70 #define GPIO51_40_DIR 0x74 #define GPIO51_40_POL 0x78 #define GPIO51_40_SET 0x7C #define GPIO51_40_RESET 0x80 #define GPIO51_40_TOG 0x84 #define GDMA_CHANNEL_REQ0 0 #define GDMA_CHANNEL_REQ1 1 /* (NAND-flash) */ #define GDMA_CHANNEL_REQ2 2 /* (I2S) */ #define GDMA_CHANNEL_REQ3 3 /* (PCM0-RX) */ #define GDMA_CHANNEL_REQ4 4 /* (PCM1-RX) */ #define GDMA_CHANNEL_REQ5 5 /* (PCM0-TX) */ #define GDMA_CHANNEL_REQ6 6 /* (PCM1-TX) */ #define GDMA_CHANNEL_REQ7 7 #define GDMA_CHANNEL_MEM 8 /* Generic DMA Controller */ /* GDMA Channel n Source Address */ #define GDMASA(n) (0x00 + 0x10*n) /* GDMA Channel n Destination Address */ #define GDMADA(n) (0x04 + 0x10*n) /* GDMA Channel n Control Register 0 */ #define GDMACT0(n) (0x08 + 0x10*n) #define GDMACT0_TR_COUNT_MASK 0x0fff0000 #define GDMACT0_TR_COUNT_SHIFT 16 #define GDMACT0_SRC_CHAN_SHIFT 12 #define GDMACT0_SRC_CHAN_MASK 0x0000f000 #define GDMACT0_DST_CHAN_SHIFT 8 #define GDMACT0_DST_CHAN_MASK 0x00000f00 #define GDMACT0_SRC_BURST_MODE (1<<7) #define GDMACT0_DST_BURST_MODE (1<<6) #define GDMACT0_BURST_SIZE_SHIFT 3 #define GDMACT0_BURST_SIZE_MASK 0x00000038 #define GDMACT0_BURST_SIZE_1 0 #define GDMACT0_BURST_SIZE_2 1 #define GDMACT0_BURST_SIZE_4 2 #define GDMACT0_BURST_SIZE_8 3 #define GDMACT0_BURST_SIZE_16 4 #define GDMACT0_DONE_INT_EN (1<<2) #define GDMACT0_CHAN_EN (1<<1) /* * In software mode, the data transfer will start when the Channel Enable bit * is set. * In hardware mode, the data transfer will start when the DMA Request is * asserted. */ #define GDMACT0_SWMODE (1<<0) /* SPI controller interface */ #define RT305X_SPISTAT 0x00 /* SPIBUSY is alias for SPIBUSY, because SPISTAT have only BUSY bit*/ #define RT305X_SPIBUSY RT305X_SPISTAT #define RT305X_SPICFG 0x10 #define MSBFIRST (1<<8) #define SPICLKPOL (1<<6) #define CAPT_ON_CLK_FALL (1<<5) #define TX_ON_CLK_FALL (1<<4) #define HIZSPI (1<<3) /* Set SPI pins to Tri-state */ #define SPI_CLK_SHIFT 0 /* SPI clock divide control */ #define SPI_CLK_MASK 0x00000007 #define SPI_CLK_DIV2 0 #define SPI_CLK_DIV4 1 #define SPI_CLK_DIV8 2 #define SPI_CLK_DIV16 3 #define SPI_CLK_DIV32 4 #define SPI_CLK_DIV64 5 #define SPI_CLK_DIV128 6 #define SPI_CLK_DISABLED 7 #define RT305X_SPICTL 0x14 #define HIZSMOSI (1<<3) #define START_WRITE (1<<2) #define START_READ (1<<1) #define CS_HIGH (1<<0) #define RT305X_SPIDATA 0x20 #define SPIDATA_MASK 0x000000ff #define RT305X_SPI_WRITE 1 #define RT305X_SPI_READ 0 #endif /* _RT305XREG_H_ */ Index: head/sys/mips/rt305x/rt_swreg.h =================================================================== --- head/sys/mips/rt305x/rt_swreg.h (revision 326258) +++ head/sys/mips/rt305x/rt_swreg.h (revision 326259) @@ -1,160 +1,162 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Aleksandr Rybalko. * 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$ */ #ifndef _RT_SWREG_H_ #define _RT_SWREG_H_ /* XXX: must move to config */ #define RT3052F #define RT_SW_BASE 0x10110000 #define RT_SW_ISR 0x00 #define WATCHDOG1_TMR_EXPIRED (1<<29) #define WATCHDOG0_TMR_EXPIRED (1<<28) #define HAS_INTRUDER (1<<27) #define PORT_ST_CHG (1<<26) #define BC_STORM (1<<25) #define MUST_DROP_LAN (1<<24) #define GLOBAL_QUE_FULL (1<<23) #define LAN_QUE_FULL6 (1<<20) #define LAN_QUE_FULL5 (1<<19) #define LAN_QUE_FULL4 (1<<18) #define LAN_QUE_FULL3 (1<<17) #define LAN_QUE_FULL2 (1<<16) #define LAN_QUE_FULL1 (1<<15) #define LAN_QUE_FULL0 (1<<14) #define RT_SW_IMR 0x04 #define RT_SW_FCT0 0x08 #define RT_SW_FCT1 0x0c #define RT_SW_PFC0 0x10 #define RT_SW_PFC1 0x14 #define RT_SW_PFC2 0x18 #define RT_SW_GQS0 0x1c #define RT_SW_GQS1 0x20 #define RT_SW_ATS 0x24 #define RT_SW_ATS0 0x28 #define RT_SW_ATS1 0x2c #define RT_SW_ATS2 0x30 #define RT_SW_WMAD0 0x34 #define RT_SW_WMAD1 0x38 #define RT_SW_WMAD2 0x3c #define RT_SW_PVIDC0 0x40 #define RT_SW_PVIDC1 0x44 #define RT_SW_PVIDC2 0x48 #define RT_SW_PVIDC3 0x4c #define RT_SW_VID0 0x50 #define RT_SW_VID1 0x54 #define RT_SW_VID2 0x58 #define RT_SW_VID3 0x5c #define RT_SW_VID4 0x60 #define RT_SW_VID5 0x64 #define RT_SW_VID6 0x68 #define RT_SW_VID7 0x6c #define RT_SW_VMSC0 0x70 #define RT_SW_VMSC1 0x74 #define RT_SW_VMSC2 0x78 #define RT_SW_VMSC3 0x7c #define RT_SW_POA 0x80 #define RT_SW_FPA 0x84 #define RT_SW_PTS 0x88 #define RT_SW_SOCPC 0x8c #define RT_SW_POC0 0x90 #define RT_SW_POC1 0x94 #define RT_SW_POC2 0x98 #define RT_SW_SGC 0x9c #define RT_SW_STRT 0xa0 #define RT_SW_LEDP0 0xa4 #define RT_SW_LEDP1 0xa8 #define RT_SW_LEDP2 0xac #define RT_SW_LEDP3 0xb0 #define RT_SW_LEDP4 0xb4 #define RT_SW_WDTR 0xb8 #define RT_SW_DES 0xbc #define RT_SW_PCR0 0xc0 #define RT_SW_PCR1 0xc4 #define RT_SW_FPA 0xc8 #define RT_SW_FCT2 0xcc #define RT_SW_QSS0 0xd0 #define RT_SW_QSS1 0xd4 #define RT_SW_DEC 0xd8 #define BRIDGE_IPG_SHIFT 24 #define DEBUG_SW_PORT_SEL_SHIFT 3 #define DEBUG_SW_PORT_SEL_MASK 0x00000038 #define RT_SW_MTI 0xdc #define SKIP_BLOCKS_SHIFT 7 #define SKIP_BLOCKS_MASK 0x0000ff80 #define SW_RAM_TEST_DONE (1<<6) #define AT_RAM_TEST_DONE (1<<5) #define AT_RAM_TEST_FAIL (1<<4) #define LK_RAM_TEST_DONE (1<<3) #define LK_RAM_TEST_FAIL (1<<2) #define DT_RAM_TEST_DONE (1<<1) #define DT_RAM_TEST_FAIL (1<<0) #define RT_SW_PPC 0xe0 #define SW2FE_CNT_SHIFT 16 #define FE2SW_CNT_SHIFT 0 #define RT_SW_SGC2 0xe4 #define FE2SW_WL_FC_EN (1<<30) #define LAN_PMAP_P0_IS_LAN (1<<24) #define LAN_PMAP_P1_IS_LAN (1<<25) #define LAN_PMAP_P2_IS_LAN (1<<26) #define LAN_PMAP_P3_IS_LAN (1<<27) #define LAN_PMAP_P4_IS_LAN (1<<28) #define LAN_PMAP_P5_IS_LAN (1<<29) /* Transmit CPU TPID(810x) port bit map */ #define TX_CPU_TPID_BIT_MAP_SHIFT 16 #define TX_CPU_TPID_BIT_MAP_MASK 0x007f0000 #define ARBITER_LAN_EN (1<<11) #define CPU_TPID_EN (1<<10) #define P0_DOUBLE_TAG_EN (1<<0) #define P1_DOUBLE_TAG_EN (1<<1) #define P2_DOUBLE_TAG_EN (1<<2) #define P3_DOUBLE_TAG_EN (1<<3) #define P4_DOUBLE_TAG_EN (1<<4) #define P5_DOUBLE_TAG_EN (1<<5) #define RT_SW_P0PC 0xe8 #define RT_SW_P1PC 0xec #define RT_SW_P2PC 0xf0 #define RT_SW_P3PC 0xf4 #define RT_SW_P4PC 0xf8 #define RT_SW_P5PC 0xfc #define BAD_PCOUNT_SHIFT 16 #define BAD_PCOUNT_MASK 0xffff0000 #define GOOD_PCOUNT_SHIFT 0 #define GOOD_PCOUNT_MASK 0x0000ffff #endif /* _RT_SWREG_H_ */ Index: head/sys/mips/rt305x/uart_bus_rt305x.c =================================================================== --- head/sys/mips/rt305x/uart_bus_rt305x.c (revision 326258) +++ head/sys/mips/rt305x/uart_bus_rt305x.c (revision 326259) @@ -1,94 +1,96 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2007 Bruce M. Simpson. * 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 * $Id$ */ /* * Skeleton of this file was based on respective code for ARM * code written by Olivier Houchard. */ /* * XXXMIPS: This file is hacked from arm/... . XXXMIPS here means this file is * experimental and was written for MIPS32 port. */ #include "opt_uart.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "uart_if.h" static int uart_rt305x_probe(device_t dev); extern struct uart_class uart_rt305x_uart_class; static device_method_t uart_rt305x_methods[] = { /* Device interface */ DEVMETHOD(device_probe, uart_rt305x_probe), DEVMETHOD(device_attach, uart_bus_attach), DEVMETHOD(device_detach, uart_bus_detach), { 0, 0 } }; static driver_t uart_rt305x_driver = { uart_driver_name, uart_rt305x_methods, sizeof(struct uart_softc), }; static int uart_rt305x_probe(device_t dev) { struct uart_softc *sc; sc = device_get_softc(dev); sc->sc_class = &uart_rt305x_uart_class; sc->sc_bas.regshft = 2; sc->sc_bas.bst = mips_bus_space_generic; sc->sc_bas.bsh = MIPS_PHYS_TO_KSEG1(device_get_unit(dev)?UARTLITE_BASE:UART_BASE); return (uart_bus_probe(dev, 2, 0, SYSTEM_CLOCK, 0, 0)); } DRIVER_MODULE(uart, obio, uart_rt305x_driver, uart_devclass, 0, 0); Index: head/sys/mips/rt305x/uart_cpu_rt305x.c =================================================================== --- head/sys/mips/rt305x/uart_cpu_rt305x.c (revision 326258) +++ head/sys/mips/rt305x/uart_cpu_rt305x.c (revision 326259) @@ -1,86 +1,88 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2006 Wojciech A. Koszek * 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. * * $Id$ */ /* * Skeleton of this file was based on respective code for ARM * code written by Olivier Houchard. */ /* * XXXMIPS: This file is hacked from arm/... . XXXMIPS here means this file is * experimental and was written for MIPS32 port. */ #include "opt_uart.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include extern struct uart_class uart_rt305x_uart_class; bus_space_tag_t uart_bus_space_io; bus_space_tag_t uart_bus_space_mem; int uart_cpu_eqres(struct uart_bas *b1, struct uart_bas *b2) { return ((b1->bsh == b2->bsh && b1->bst == b2->bst) ? 1 : 0); } int uart_cpu_getdev(int devtype, struct uart_devinfo *di) { di->ops = uart_getops(&uart_rt305x_uart_class); di->bas.chan = 0; di->bas.bst = mips_bus_space_generic; di->bas.regshft = 2; di->bas.rclk = SYSTEM_CLOCK; di->baudrate = 115200; di->databits = 8; di->stopbits = 1; di->parity = UART_PARITY_NONE; uart_bus_space_io = NULL; uart_bus_space_mem = mips_bus_space_generic; #ifdef RT305X_USE_UART di->bas.bsh = MIPS_PHYS_TO_KSEG1(UART_BASE); #else di->bas.bsh = MIPS_PHYS_TO_KSEG1(UARTLITE_BASE); #endif return (0); } Index: head/sys/mips/rt305x/uart_dev_rt305x.c =================================================================== --- head/sys/mips/rt305x/uart_dev_rt305x.c (revision 326258) +++ head/sys/mips/rt305x/uart_dev_rt305x.c (revision 326259) @@ -1,533 +1,535 @@ /* $NetBSD: uart.c,v 1.2 2007/03/23 20:05:47 dogcow Exp $ */ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Aleksandr Rybalko. * Copyright (c) 2007 Ruslan Ermilov and Vsevolod Lobko. * Copyright (c) 2007 Oleksandr Tymoshenko. * 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 AUTHORS ``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 AUTHORS * 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 "opt_ddb.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "uart_if.h" /* * Low-level UART interface. */ static int rt305x_uart_probe(struct uart_bas *bas); static void rt305x_uart_init(struct uart_bas *bas, int, int, int, int); static void rt305x_uart_term(struct uart_bas *bas); static void rt305x_uart_putc(struct uart_bas *bas, int); static int rt305x_uart_rxready(struct uart_bas *bas); static int rt305x_uart_getc(struct uart_bas *bas, struct mtx *); static struct uart_ops uart_rt305x_uart_ops = { .probe = rt305x_uart_probe, .init = rt305x_uart_init, .term = rt305x_uart_term, .putc = rt305x_uart_putc, .rxready = rt305x_uart_rxready, .getc = rt305x_uart_getc, }; static int uart_output = 1; SYSCTL_INT(_kern, OID_AUTO, uart_output, CTLFLAG_RWTUN, &uart_output, 0, "UART output enabled."); static int rt305x_uart_probe(struct uart_bas *bas) { return (0); } static void rt305x_uart_init(struct uart_bas *bas, int baudrate, int databits, int stopbits, int parity) { #ifdef notyet /* CLKDIV = 384000000/ 3/ 16/ br */ /* for 384MHz CLKDIV = 8000000 / baudrate; */ switch (databits) { case 5: databits = UART_LCR_5B; break; case 6: databits = UART_LCR_6B; break; case 7: databits = UART_LCR_7B; break; case 8: databits = UART_LCR_8B; break; default: /* Unsupported */ return; } switch (parity) { case UART_PARITY_EVEN: parity = (UART_LCR_PEN|UART_LCR_EVEN); break; case UART_PARITY_NONE: parity = (UART_LCR_PEN); break; case UART_PARITY_ODD: parity = 0; break; /* Unsupported */ default: return; } uart_setreg(bas, UART_CDDL_REG, 8000000/baudrate); uart_barrier(bas); uart_setreg(bas, UART_LCR_REG, databits | (stopbits==1?0:4) | parity); uart_barrier(bas); #endif } static void rt305x_uart_term(struct uart_bas *bas) { uart_setreg(bas, UART_MCR_REG, 0); uart_barrier(bas); } static void rt305x_uart_putc(struct uart_bas *bas, int c) { char chr; if (!uart_output) return; chr = c; while (!(uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE)); uart_setreg(bas, UART_TX_REG, c); uart_barrier(bas); while (!(uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE)); } static int rt305x_uart_rxready(struct uart_bas *bas) { #ifdef notyet if (uart_getreg(bas, UART_LSR_REG) & UART_LSR_DR) return (1); return (0); #else return (1); #endif } static int rt305x_uart_getc(struct uart_bas *bas, struct mtx *hwmtx) { int c; uart_lock(hwmtx); while (!(uart_getreg(bas, UART_LSR_REG) & UART_LSR_DR)) { uart_unlock(hwmtx); DELAY(10); uart_lock(hwmtx); } c = uart_getreg(bas, UART_RX_REG); uart_unlock(hwmtx); return (c); } /* * High-level UART interface. */ struct rt305x_uart_softc { struct uart_softc base; }; static int rt305x_uart_bus_attach(struct uart_softc *); static int rt305x_uart_bus_detach(struct uart_softc *); static int rt305x_uart_bus_flush(struct uart_softc *, int); static int rt305x_uart_bus_getsig(struct uart_softc *); static int rt305x_uart_bus_ioctl(struct uart_softc *, int, intptr_t); static int rt305x_uart_bus_ipend(struct uart_softc *); static int rt305x_uart_bus_param(struct uart_softc *, int, int, int, int); static int rt305x_uart_bus_probe(struct uart_softc *); static int rt305x_uart_bus_receive(struct uart_softc *); static int rt305x_uart_bus_setsig(struct uart_softc *, int); static int rt305x_uart_bus_transmit(struct uart_softc *); static void rt305x_uart_bus_grab(struct uart_softc *); static void rt305x_uart_bus_ungrab(struct uart_softc *); static kobj_method_t rt305x_uart_methods[] = { KOBJMETHOD(uart_attach, rt305x_uart_bus_attach), KOBJMETHOD(uart_detach, rt305x_uart_bus_detach), KOBJMETHOD(uart_flush, rt305x_uart_bus_flush), KOBJMETHOD(uart_getsig, rt305x_uart_bus_getsig), KOBJMETHOD(uart_ioctl, rt305x_uart_bus_ioctl), KOBJMETHOD(uart_ipend, rt305x_uart_bus_ipend), KOBJMETHOD(uart_param, rt305x_uart_bus_param), KOBJMETHOD(uart_probe, rt305x_uart_bus_probe), KOBJMETHOD(uart_receive, rt305x_uart_bus_receive), KOBJMETHOD(uart_setsig, rt305x_uart_bus_setsig), KOBJMETHOD(uart_transmit, rt305x_uart_bus_transmit), KOBJMETHOD(uart_grab, rt305x_uart_bus_grab), KOBJMETHOD(uart_ungrab, rt305x_uart_bus_ungrab), { 0, 0 } }; struct uart_class uart_rt305x_uart_class = { "rt305x", rt305x_uart_methods, sizeof(struct rt305x_uart_softc), .uc_ops = &uart_rt305x_uart_ops, .uc_range = 1, /* use hinted range */ .uc_rclk = SYSTEM_CLOCK, .uc_rshift = 0 }; #define SIGCHG(c, i, s, d) \ if (c) { \ i |= (i & s) ? s : s | d; \ } else { \ i = (i & s) ? (i & ~s) | d : i; \ } /* * Disable TX interrupt. uart should be locked */ static __inline void rt305x_uart_disable_txintr(struct uart_softc *sc) { struct uart_bas *bas = &sc->sc_bas; uint8_t cr; cr = uart_getreg(bas, UART_IER_REG); cr &= ~UART_IER_ETBEI; uart_setreg(bas, UART_IER_REG, cr); uart_barrier(bas); } /* * Enable TX interrupt. uart should be locked */ static __inline void rt305x_uart_enable_txintr(struct uart_softc *sc) { struct uart_bas *bas = &sc->sc_bas; uint8_t cr; cr = uart_getreg(bas, UART_IER_REG); cr |= UART_IER_ETBEI; uart_setreg(bas, UART_IER_REG, cr); uart_barrier(bas); } static int rt305x_uart_bus_attach(struct uart_softc *sc) { struct uart_bas *bas; struct uart_devinfo *di; bas = &sc->sc_bas; if (sc->sc_sysdev != NULL) { di = sc->sc_sysdev; rt305x_uart_init(bas, di->baudrate, di->databits, di->stopbits, di->parity); } else { rt305x_uart_init(bas, 115200, 8, 1, 0); } (void)rt305x_uart_bus_getsig(sc); /* Enable FIFO */ uart_setreg(bas, UART_FCR_REG, uart_getreg(bas, UART_FCR_REG) | UART_FCR_FIFOEN | UART_FCR_TXTGR_1 | UART_FCR_RXTGR_1); uart_barrier(bas); /* Enable interrupts */ uart_setreg(bas, UART_IER_REG, UART_IER_EDSSI | UART_IER_ELSI | UART_IER_ERBFI); uart_barrier(bas); return (0); } static int rt305x_uart_bus_detach(struct uart_softc *sc) { return (0); } static int rt305x_uart_bus_flush(struct uart_softc *sc, int what) { struct uart_bas *bas = &sc->sc_bas; uint32_t fcr = uart_getreg(bas, UART_FCR_REG); if (what & UART_FLUSH_TRANSMITTER) { uart_setreg(bas, UART_FCR_REG, fcr|UART_FCR_TXRST); uart_barrier(bas); } if (what & UART_FLUSH_RECEIVER) { uart_setreg(bas, UART_FCR_REG, fcr|UART_FCR_RXRST); uart_barrier(bas); } uart_setreg(bas, UART_FCR_REG, fcr); uart_barrier(bas); return (0); } static int rt305x_uart_bus_getsig(struct uart_softc *sc) { uint32_t new, old, sig; uint8_t bes; do { old = sc->sc_hwsig; sig = old; uart_lock(sc->sc_hwmtx); bes = uart_getreg(&sc->sc_bas, UART_MSR_REG); uart_unlock(sc->sc_hwmtx); /* XXX: chip can show delta */ SIGCHG(bes & UART_MSR_CTS, sig, SER_CTS, SER_DCTS); SIGCHG(bes & UART_MSR_DCD, sig, SER_DCD, SER_DDCD); SIGCHG(bes & UART_MSR_DSR, sig, SER_DSR, SER_DDSR); new = sig & ~SER_MASK_DELTA; } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); return (sig); } static int rt305x_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) { struct uart_bas *bas; int baudrate, divisor, error; bas = &sc->sc_bas; error = 0; uart_lock(sc->sc_hwmtx); switch (request) { case UART_IOCTL_BREAK: /* TODO: Send BREAK */ break; case UART_IOCTL_BAUD: divisor = uart_getreg(bas, UART_CDDL_REG); baudrate = bas->rclk / (divisor * 16); *(int*)data = baudrate; break; default: error = EINVAL; break; } uart_unlock(sc->sc_hwmtx); return (error); } static int rt305x_uart_bus_ipend(struct uart_softc *sc) { struct uart_bas *bas; int ipend; uint8_t iir, lsr, msr; bas = &sc->sc_bas; ipend = 0; uart_lock(sc->sc_hwmtx); iir = uart_getreg(&sc->sc_bas, UART_IIR_REG); lsr = uart_getreg(&sc->sc_bas, UART_LSR_REG); uart_setreg(&sc->sc_bas, UART_LSR_REG, lsr); msr = uart_getreg(&sc->sc_bas, UART_MSR_REG); uart_setreg(&sc->sc_bas, UART_MSR_REG, msr); if (iir & UART_IIR_INTP) { uart_unlock(sc->sc_hwmtx); return (0); } switch ((iir >> 1) & 0x07) { case UART_IIR_ID_THRE: ipend |= SER_INT_TXIDLE; break; case UART_IIR_ID_DR2: rt305x_uart_bus_flush(sc, UART_FLUSH_RECEIVER); /* passthrough */ case UART_IIR_ID_DR: ipend |= SER_INT_RXREADY; break; case UART_IIR_ID_MST: case UART_IIR_ID_LINESTATUS: ipend |= SER_INT_SIGCHG; if (lsr & UART_LSR_BI) { ipend |= SER_INT_BREAK; #ifdef KDB breakpoint(); #endif } if (lsr & UART_LSR_OE) ipend |= SER_INT_OVERRUN; break; default: /* XXX: maybe return error here */ break; } uart_unlock(sc->sc_hwmtx); return (ipend); } static int rt305x_uart_bus_param(struct uart_softc *sc, int baudrate, int databits, int stopbits, int parity) { uart_lock(sc->sc_hwmtx); rt305x_uart_init(&sc->sc_bas, baudrate, databits, stopbits, parity); uart_unlock(sc->sc_hwmtx); return (0); } static int rt305x_uart_bus_probe(struct uart_softc *sc) { char buf[80]; int error; error = rt305x_uart_probe(&sc->sc_bas); if (error) return (error); sc->sc_rxfifosz = 16; sc->sc_txfifosz = 16; snprintf(buf, sizeof(buf), "rt305x_uart"); device_set_desc_copy(sc->sc_dev, buf); return (0); } static int rt305x_uart_bus_receive(struct uart_softc *sc) { struct uart_bas *bas; int xc; uint8_t lsr; bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); lsr = uart_getreg(bas, UART_LSR_REG); while ((lsr & UART_LSR_DR)) { if (uart_rx_full(sc)) { sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; break; } xc = 0; xc = uart_getreg(bas, UART_RX_REG); if (lsr & UART_LSR_FE) xc |= UART_STAT_FRAMERR; if (lsr & UART_LSR_PE) xc |= UART_STAT_PARERR; if (lsr & UART_LSR_OE) xc |= UART_STAT_OVERRUN; uart_barrier(bas); uart_rx_put(sc, xc); lsr = uart_getreg(bas, UART_LSR_REG); } uart_unlock(sc->sc_hwmtx); return (0); } static int rt305x_uart_bus_setsig(struct uart_softc *sc, int sig) { /* TODO: implement (?) */ return (0); } static int rt305x_uart_bus_transmit(struct uart_softc *sc) { struct uart_bas *bas = &sc->sc_bas; int i; if (!uart_output) return (0); bas = &sc->sc_bas; uart_lock(sc->sc_hwmtx); while ((uart_getreg(bas, UART_LSR_REG) & UART_LSR_THRE) == 0) ; rt305x_uart_enable_txintr(sc); for (i = 0; i < sc->sc_txdatasz; i++) { uart_setreg(bas, UART_TX_REG, sc->sc_txbuf[i]); uart_barrier(bas); } sc->sc_txbusy = 1; uart_unlock(sc->sc_hwmtx); return (0); } static void rt305x_uart_bus_grab(struct uart_softc *sc) { struct uart_bas *bas = &sc->sc_bas; /* disable interrupts -- XXX not sure which one is RX, so kill them all */ uart_lock(sc->sc_hwmtx); uart_setreg(bas, UART_IER_REG, 0); uart_barrier(bas); uart_unlock(sc->sc_hwmtx); } static void rt305x_uart_bus_ungrab(struct uart_softc *sc) { struct uart_bas *bas = &sc->sc_bas; /* Enable interrupts */ uart_lock(sc->sc_hwmtx); uart_setreg(bas, UART_IER_REG, UART_IER_EDSSI | UART_IER_ELSI | UART_IER_ERBFI); uart_barrier(bas); uart_unlock(sc->sc_hwmtx); } Index: head/sys/mips/rt305x/uart_dev_rt305x.h =================================================================== --- head/sys/mips/rt305x/uart_dev_rt305x.h (revision 326258) +++ head/sys/mips/rt305x/uart_dev_rt305x.h (revision 326259) @@ -1,126 +1,128 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Aleksandr Rybalko. * 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. * 3. The names of the authors may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS * 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$ */ #ifndef _RT305XUART_H #define _RT305XUART_H #undef uart_getreg #undef uart_setreg #define uart_getreg(bas, reg) \ bus_space_read_4((bas)->bst, (bas)->bsh, reg) #define uart_setreg(bas, reg, value) \ bus_space_write_4((bas)->bst, (bas)->bsh, reg, value) /* UART registers */ #define UART_RX_REG 0x00 #define UART_TX_REG 0x04 #define UART_IER_REG 0x08 #define UART_IER_EDSSI (1<<3) /* Only full UART */ #define UART_IER_ELSI (1<<2) #define UART_IER_ETBEI (1<<1) #define UART_IER_ERBFI (1<<0) #define UART_IIR_REG 0x0c #define UART_IIR_RXFIFO (1<<7) #define UART_IIR_TXFIFO (1<<6) #define UART_IIR_ID_MST 0 #define UART_IIR_ID_THRE 1 #define UART_IIR_ID_DR 2 #define UART_IIR_ID_LINESTATUS 3 #define UART_IIR_ID_DR2 6 #define UART_IIR_ID_SHIFT 1 #define UART_IIR_ID_MASK 0x0000000e #define UART_IIR_INTP (1<<0) #define UART_FCR_REG 0x10 #define UART_FCR_RXTGR_1 (0<<6) #define UART_FCR_RXTGR_4 (1<<6) #define UART_FCR_RXTGR_8 (2<<6) #define UART_FCR_RXTGR_12 (3<<6) #define UART_FCR_TXTGR_1 (0<<4) #define UART_FCR_TXTGR_4 (1<<4) #define UART_FCR_TXTGR_8 (2<<4) #define UART_FCR_TXTGR_12 (3<<4) #define UART_FCR_DMA (1<<3) #define UART_FCR_TXRST (1<<2) #define UART_FCR_RXRST (1<<1) #define UART_FCR_FIFOEN (1<<0) #define UART_LCR_REG 0x14 #define UART_LCR_DLAB (1<<7) #define UART_LCR_BRK (1<<6) #define UART_LCR_FPAR (1<<5) #define UART_LCR_EVEN (1<<4) #define UART_LCR_PEN (1<<3) #define UART_LCR_STB_15 (1<<2) #define UART_LCR_5B 0 #define UART_LCR_6B 1 #define UART_LCR_7B 2 #define UART_LCR_8B 3 #define UART_MCR_REG 0x18 #define UART_MCR_LOOP (1<<4) #define UART_MCR_OUT2_L (1<<3) /* Only full UART */ #define UART_MCR_OUT1_L (1<<2) /* Only full UART */ #define UART_MCR_RTS_L (1<<1) /* Only full UART */ #define UART_MCR_DTR_L (1<<0) /* Only full UART */ #define UART_LSR_REG 0x1c #define UART_LSR_ERINF (1<<7) #define UART_LSR_TEMT (1<<6) #define UART_LSR_THRE (1<<5) #define UART_LSR_BI (1<<4) #define UART_LSR_FE (1<<3) #define UART_LSR_PE (1<<2) #define UART_LSR_OE (1<<1) #define UART_LSR_DR (1<<0) #define UART_MSR_REG 0x20 /* Only full UART */ #define UART_MSR_DCD (1<<7) /* Only full UART */ #define UART_MSR_RI (1<<6) /* Only full UART */ #define UART_MSR_DSR (1<<5) /* Only full UART */ #define UART_MSR_CTS (1<<4) /* Only full UART */ #define UART_MSR_DDCD (1<<3) /* Only full UART */ #define UART_MSR_TERI (1<<2) /* Only full UART */ #define UART_MSR_DDSR (1<<1) /* Only full UART */ #define UART_MSR_DCTS (1<<0) /* Only full UART */ #define UART_CDDL_REG 0x28 #define UART_CDDLL_REG 0x2c #define UART_CDDLH_REG 0x30 #define UART_IFCTL_REG 0x34 #define UART_IFCTL_IFCTL (1<<0) int uart_cnattach(void); #endif /* _RT305XUART_H */ Index: head/sys/mips/sibyte/ata_zbbus.c =================================================================== --- head/sys/mips/sibyte/ata_zbbus.c (revision 326258) +++ head/sys/mips/sibyte/ata_zbbus.c (revision 326259) @@ -1,170 +1,172 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009 Neelkanth Natu * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include __FBSDID("$FreeBSD$"); static int ata_zbbus_probe(device_t dev) { return (ata_probe(dev)); } static int ata_zbbus_attach(device_t dev) { int i, rid, regshift, regoffset; struct ata_channel *ch; struct resource *io; ch = device_get_softc(dev); if (ch->attached) return (0); ch->attached = 1; rid = 0; io = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); if (io == NULL) return (ENXIO); /* * SWARM needs an address shift of 5 when accessing ATA registers. * * For e.g. an access to register 4 actually needs an address * of (4 << 5) to be output on the generic bus. */ regshift = 5; resource_int_value(device_get_name(dev), device_get_unit(dev), "regshift", ®shift); if (regshift && bootverbose) device_printf(dev, "using a register shift of %d\n", regshift); regoffset = 0x1F0; resource_int_value(device_get_name(dev), device_get_unit(dev), "regoffset", ®offset); if (regoffset && bootverbose) { device_printf(dev, "using a register offset of 0x%0x\n", regoffset); } /* setup the ata register addresses */ for (i = ATA_DATA; i <= ATA_COMMAND; ++i) { ch->r_io[i].res = io; ch->r_io[i].offset = (regoffset + i) << regshift; } ch->r_io[ATA_CONTROL].res = io; ch->r_io[ATA_CONTROL].offset = (regoffset + ATA_CTLOFFSET) << regshift; ch->r_io[ATA_IDX_ADDR].res = io; /* XXX what is this used for */ ata_default_registers(dev); /* initialize softc for this channel */ ch->unit = 0; ch->flags |= ATA_USE_16BIT; ata_generic_hw(dev); return (ata_attach(dev)); } static int ata_zbbus_detach(device_t dev) { int error; struct ata_channel *ch = device_get_softc(dev); if (!ch->attached) return (0); ch->attached = 0; error = ata_detach(dev); bus_release_resource(dev, SYS_RES_MEMORY, 0, ch->r_io[ATA_IDX_ADDR].res); return (error); } static int ata_zbbus_suspend(device_t dev) { struct ata_channel *ch = device_get_softc(dev); if (!ch->attached) return (0); return (ata_suspend(dev)); } static int ata_zbbus_resume(device_t dev) { struct ata_channel *ch = device_get_softc(dev); if (!ch->attached) return (0); return (ata_resume(dev)); } static device_method_t ata_zbbus_methods[] = { /* device interface */ DEVMETHOD(device_probe, ata_zbbus_probe), DEVMETHOD(device_attach, ata_zbbus_attach), DEVMETHOD(device_detach, ata_zbbus_detach), DEVMETHOD(device_suspend, ata_zbbus_suspend), DEVMETHOD(device_resume, ata_zbbus_resume), { 0, 0 } }; static driver_t ata_zbbus_driver = { "ata", ata_zbbus_methods, sizeof(struct ata_channel) }; DRIVER_MODULE(ata, zbbus, ata_zbbus_driver, ata_devclass, 0, 0); Index: head/sys/mips/sibyte/sb_bus_space.h =================================================================== --- head/sys/mips/sibyte/sb_bus_space.h (revision 326258) +++ head/sys/mips/sibyte/sb_bus_space.h (revision 326259) @@ -1,43 +1,45 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2010 Neelkanth Natu * 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$ */ #ifndef _SB_BUS_SPACE_H_ #define _SB_BUS_SPACE_H_ #include #if _BYTE_ORDER == _BIG_ENDIAN uint8_t sb_big_endian_read8(bus_addr_t addr); uint16_t sb_big_endian_read16(bus_addr_t addr); uint32_t sb_big_endian_read32(bus_addr_t addr); void sb_big_endian_write8(bus_addr_t addr, uint8_t val); void sb_big_endian_write16(bus_addr_t addr, uint16_t val); void sb_big_endian_write32(bus_addr_t addr, uint32_t val); #endif #endif Index: head/sys/mips/sibyte/sb_machdep.c =================================================================== --- head/sys/mips/sibyte/sb_machdep.c (revision 326258) +++ head/sys/mips/sibyte/sb_machdep.c (revision 326259) @@ -1,439 +1,441 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2007 Bruce M. Simpson. * 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 "opt_ddb.h" #include "opt_kdb.h" #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 #include #include #include #include #include #include #ifdef SMP #include #include #endif #ifdef CFE #include #endif #include "sb_scd.h" #ifdef DDB #ifndef KDB #error KDB must be enabled in order for DDB to work! #endif #endif #ifdef CFE_ENV extern void cfe_env_init(void); #endif extern int *edata; extern int *end; extern char MipsTLBMiss[], MipsTLBMissEnd[]; void platform_cpu_init() { /* Nothing special */ } static void sb_intr_init(int cpuid) { int intrnum, intsrc; /* * Disable all sources to the interrupt mapper and setup the mapping * between an interrupt source and the mips hard interrupt number. */ for (intsrc = 0; intsrc < NUM_INTSRC; ++intsrc) { intrnum = sb_route_intsrc(intsrc); sb_disable_intsrc(cpuid, intsrc); sb_write_intmap(cpuid, intsrc, intrnum); #ifdef SMP /* * Set up the mailbox interrupt mapping. * * The mailbox interrupt is "special" in that it is not shared * with any other interrupt source. */ if (intsrc == INTSRC_MAILBOX3) { intrnum = platform_ipi_hardintr_num(); sb_write_intmap(cpuid, INTSRC_MAILBOX3, intrnum); sb_enable_intsrc(cpuid, INTSRC_MAILBOX3); } #endif } } static void mips_init(void) { int i, j, cfe_mem_idx, tmp; uint64_t maxmem; #ifdef CFE_ENV cfe_env_init(); #endif TUNABLE_INT_FETCH("boothowto", &boothowto); if (boothowto & RB_VERBOSE) bootverbose++; #ifdef MAXMEM tmp = MAXMEM; #else tmp = 0; #endif TUNABLE_INT_FETCH("hw.physmem", &tmp); maxmem = (uint64_t)tmp * 1024; /* * XXX * If we used vm_paddr_t consistently in pmap, etc., we could * use 64-bit page numbers on !n64 systems, too, like i386 * does with PAE. */ #if !defined(__mips_n64) if (maxmem == 0 || maxmem > 0xffffffff) maxmem = 0xffffffff; #endif #ifdef CFE /* * Query DRAM memory map from CFE. */ physmem = 0; cfe_mem_idx = 0; for (i = 0; i < 10; i += 2) { int result; uint64_t addr, len, type; result = cfe_enummem(cfe_mem_idx++, 0, &addr, &len, &type); if (result < 0) { phys_avail[i] = phys_avail[i + 1] = 0; break; } KASSERT(type == CFE_MI_AVAILABLE, ("CFE DRAM region is not available?")); if (bootverbose) printf("cfe_enummem: 0x%016jx/%ju.\n", addr, len); if (maxmem != 0) { if (addr >= maxmem) { printf("Ignoring %ju bytes of memory at 0x%jx " "that is above maxmem %dMB\n", len, addr, (int)(maxmem / (1024 * 1024))); continue; } if (addr + len > maxmem) { printf("Ignoring %ju bytes of memory " "that is above maxmem %dMB\n", (addr + len) - maxmem, (int)(maxmem / (1024 * 1024))); len = maxmem - addr; } } phys_avail[i] = addr; if (i == 0 && addr == 0) { /* * If this is the first physical memory segment probed * from CFE, omit the region at the start of physical * memory where the kernel has been loaded. */ phys_avail[i] += MIPS_KSEG0_TO_PHYS(kernel_kseg0_end); } phys_avail[i + 1] = addr + len; physmem += len; } realmem = btoc(physmem); #endif for (j = 0; j < i; j++) dump_avail[j] = phys_avail[j]; physmem = realmem; init_param1(); init_param2(physmem); mips_cpu_init(); /* * Sibyte has a L1 data cache coherent with DMA. This includes * on-chip network interfaces as well as PCI/HyperTransport bus * masters. */ cpuinfo.cache_coherent_dma = TRUE; /* * XXX * The kernel is running in 32-bit mode but the CFE is running in * 64-bit mode. So the SR_KX bit in the status register is turned * on by the CFE every time we call into it - for e.g. CFE_CONSOLE. * * This means that if get a TLB miss for any address above 0xc0000000 * and the SR_KX bit is set then we will end up in the XTLB exception * vector. * * For now work around this by copying the TLB exception handling * code to the XTLB exception vector. */ { bcopy(MipsTLBMiss, (void *)MIPS_XTLB_MISS_EXC_VEC, MipsTLBMissEnd - MipsTLBMiss); mips_icache_sync_all(); mips_dcache_wbinv_all(); } pmap_bootstrap(); mips_proc0_init(); mutex_init(); kdb_init(); #ifdef KDB if (boothowto & RB_KDB) kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); #endif } void platform_reset(void) { /* * XXX SMP * XXX flush data caches */ sb_system_reset(); } static void kseg0_map_coherent(void) { uint32_t config; const int CFG_K0_COHERENT = 5; config = mips_rd_config(); config &= ~MIPS_CONFIG_K0_MASK; config |= CFG_K0_COHERENT; mips_wr_config(config); } #ifdef SMP void platform_ipi_send(int cpuid) { KASSERT(cpuid == 0 || cpuid == 1, ("platform_ipi_send: invalid cpuid %d", cpuid)); sb_set_mailbox(cpuid, 1ULL); } void platform_ipi_clear(void) { int cpuid; cpuid = PCPU_GET(cpuid); sb_clear_mailbox(cpuid, 1ULL); } int platform_ipi_hardintr_num(void) { return (4); } int platform_ipi_softintr_num(void) { return (-1); } struct cpu_group * platform_smp_topo(void) { return (smp_topo_none()); } void platform_init_ap(int cpuid) { int ipi_int_mask, clock_int_mask; KASSERT(cpuid == 1, ("AP has an invalid cpu id %d", cpuid)); /* * Make sure that kseg0 is mapped cacheable-coherent */ kseg0_map_coherent(); sb_intr_init(cpuid); /* * Unmask the clock and ipi interrupts. */ clock_int_mask = hard_int_mask(5); ipi_int_mask = hard_int_mask(platform_ipi_hardintr_num()); set_intr_mask(ipi_int_mask | clock_int_mask); } int platform_start_ap(int cpuid) { #ifdef CFE int error; if ((error = cfe_cpu_start(cpuid, mpentry, 0, 0, 0))) { printf("cfe_cpu_start error: %d\n", error); return (-1); } else { return (0); } #else return (-1); #endif /* CFE */ } #endif /* SMP */ static u_int sb_get_timecount(struct timecounter *tc) { return ((u_int)sb_zbbus_cycle_count()); } static void sb_timecounter_init(void) { static struct timecounter sb_timecounter = { sb_get_timecount, NULL, ~0u, 0, "sibyte_zbbus_counter", 2000 }; /* * The ZBbus cycle counter runs at half the cpu frequency. */ sb_timecounter.tc_frequency = sb_cpu_speed() / 2; platform_timecounter = &sb_timecounter; } void platform_start(__register_t a0, __register_t a1, __register_t a2, __register_t a3) { /* * Make sure that kseg0 is mapped cacheable-coherent */ kseg0_map_coherent(); /* clear the BSS and SBSS segments */ memset(&edata, 0, (vm_offset_t)&end - (vm_offset_t)&edata); mips_postboot_fixup(); sb_intr_init(0); sb_timecounter_init(); /* Initialize pcpu stuff */ mips_pcpu0_init(); #ifdef CFE /* * Initialize CFE firmware trampolines before * we initialize the low-level console. * * CFE passes the following values in registers: * a0: firmware handle * a2: firmware entry point * a3: entry point seal */ if (a3 == CFE_EPTSEAL) cfe_init(a0, a2); #endif cninit(); mips_init(); mips_timer_init_params(sb_cpu_speed(), 0); } Index: head/sys/mips/sibyte/sb_scd.c =================================================================== --- head/sys/mips/sibyte/sb_scd.c (revision 326258) +++ head/sys/mips/sibyte/sb_scd.c (revision 326259) @@ -1,306 +1,308 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009 Neelkanth Natu * 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 "sb_scd.h" /* * We compile a 32-bit kernel to run on the SB-1 processor which is a 64-bit * processor. It has some registers that must be accessed using 64-bit load * and store instructions. * * We use the mips_ld() and mips_sd() functions to do this for us. */ #define sb_store64(addr, val) mips3_sd((uint64_t *)(uintptr_t)(addr), (val)) #define sb_load64(addr) mips3_ld((uint64_t *)(uintptr_t)(addr)) /* * System Control and Debug (SCD) unit on the Sibyte ZBbus. */ /* * Extract the value starting at bit position 'b' for 'n' bits from 'x'. */ #define GET_VAL_64(x, b, n) (((x) >> (b)) & ((1ULL << (n)) - 1)) #define SYSREV_ADDR MIPS_PHYS_TO_KSEG1(0x10020000) #define SYSREV_NUM_PROCESSORS(x) GET_VAL_64((x), 24, 4) #define SYSCFG_ADDR MIPS_PHYS_TO_KSEG1(0x10020008) #define SYSCFG_PLLDIV(x) GET_VAL_64((x), 7, 5) #define ZBBUS_CYCLE_COUNT_ADDR MIPS_PHYS_TO_KSEG1(0x10030000) #define INTSRC_MASK_ADDR(cpu) \ (MIPS_PHYS_TO_KSEG1(0x10020028) | ((cpu) << 13)) #define INTSRC_MAP_ADDR(cpu, intsrc) \ (MIPS_PHYS_TO_KSEG1(0x10020200) | ((cpu) << 13)) + (intsrc * 8) #define MAILBOX_SET_ADDR(cpu) \ (MIPS_PHYS_TO_KSEG1(0x100200C8) | ((cpu) << 13)) #define MAILBOX_CLEAR_ADDR(cpu) \ (MIPS_PHYS_TO_KSEG1(0x100200D0) | ((cpu) << 13)) static uint64_t sb_read_syscfg(void) { return (sb_load64(SYSCFG_ADDR)); } static void sb_write_syscfg(uint64_t val) { sb_store64(SYSCFG_ADDR, val); } uint64_t sb_zbbus_cycle_count(void) { return (sb_load64(ZBBUS_CYCLE_COUNT_ADDR)); } uint64_t sb_cpu_speed(void) { int plldiv; const uint64_t MHZ = 1000000; plldiv = SYSCFG_PLLDIV(sb_read_syscfg()); if (plldiv == 0) { printf("PLL_DIV is 0 - assuming 6 (300MHz).\n"); plldiv = 6; } return (plldiv * 50 * MHZ); } void sb_system_reset(void) { uint64_t syscfg; const uint64_t SYSTEM_RESET = 1ULL << 60; const uint64_t EXT_RESET = 1ULL << 59; const uint64_t SOFT_RESET = 1ULL << 58; syscfg = sb_read_syscfg(); syscfg &= ~SOFT_RESET; syscfg |= SYSTEM_RESET | EXT_RESET; sb_write_syscfg(syscfg); } void sb_disable_intsrc(int cpu, int src) { int regaddr; uint64_t val; regaddr = INTSRC_MASK_ADDR(cpu); val = sb_load64(regaddr); val |= 1ULL << src; sb_store64(regaddr, val); } void sb_enable_intsrc(int cpu, int src) { int regaddr; uint64_t val; regaddr = INTSRC_MASK_ADDR(cpu); val = sb_load64(regaddr); val &= ~(1ULL << src); sb_store64(regaddr, val); } void sb_write_intsrc_mask(int cpu, uint64_t val) { int regaddr; regaddr = INTSRC_MASK_ADDR(cpu); sb_store64(regaddr, val); } uint64_t sb_read_intsrc_mask(int cpu) { int regaddr; uint64_t val; regaddr = INTSRC_MASK_ADDR(cpu); val = sb_load64(regaddr); return (val); } void sb_write_intmap(int cpu, int intsrc, int intrnum) { int regaddr; regaddr = INTSRC_MAP_ADDR(cpu, intsrc); sb_store64(regaddr, intrnum); } int sb_read_intmap(int cpu, int intsrc) { int regaddr; regaddr = INTSRC_MAP_ADDR(cpu, intsrc); return (sb_load64(regaddr) & 0x7); } int sb_route_intsrc(int intsrc) { int intrnum; KASSERT(intsrc >= 0 && intsrc < NUM_INTSRC, ("Invalid interrupt source number (%d)", intsrc)); /* * Interrupt 5 is used by sources internal to the CPU (e.g. timer). * Use a deterministic mapping for the remaining sources. */ #ifdef SMP KASSERT(platform_ipi_hardintr_num() == 4, ("Unexpected interrupt number used for IPI")); intrnum = intsrc % 4; #else intrnum = intsrc % 5; #endif return (intrnum); } #ifdef SMP static uint64_t sb_read_sysrev(void) { return (sb_load64(SYSREV_ADDR)); } void sb_set_mailbox(int cpu, uint64_t val) { int regaddr; regaddr = MAILBOX_SET_ADDR(cpu); sb_store64(regaddr, val); } void sb_clear_mailbox(int cpu, uint64_t val) { int regaddr; regaddr = MAILBOX_CLEAR_ADDR(cpu); sb_store64(regaddr, val); } void platform_cpu_mask(cpuset_t *mask) { int i, s; CPU_ZERO(mask); s = SYSREV_NUM_PROCESSORS(sb_read_sysrev()); for (i = 0; i < s; i++) CPU_SET(i, mask); } #endif /* SMP */ #define SCD_PHYSADDR 0x10000000 #define SCD_SIZE 0x00060000 static int scd_probe(device_t dev) { device_set_desc(dev, "Broadcom/Sibyte System Control and Debug"); return (0); } static int scd_attach(device_t dev) { int rid; struct resource *res; if (bootverbose) device_printf(dev, "attached.\n"); rid = 0; res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, SCD_PHYSADDR, SCD_PHYSADDR + SCD_SIZE - 1, SCD_SIZE, 0); if (res == NULL) panic("Cannot allocate resource for system control and debug."); return (0); } static device_method_t scd_methods[] ={ /* Device interface */ DEVMETHOD(device_probe, scd_probe), DEVMETHOD(device_attach, scd_attach), DEVMETHOD(device_detach, bus_generic_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), { 0, 0 } }; static driver_t scd_driver = { "scd", scd_methods }; static devclass_t scd_devclass; DRIVER_MODULE(scd, zbbus, scd_driver, scd_devclass, 0, 0); Index: head/sys/mips/sibyte/sb_scd.h =================================================================== --- head/sys/mips/sibyte/sb_scd.h (revision 326258) +++ head/sys/mips/sibyte/sb_scd.h (revision 326259) @@ -1,52 +1,54 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009 Neelkanth Natu * 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$ */ #ifndef _SB_SCD_H_ #define _SB_SCD_H_ #define NUM_INTSRC 64 /* total number of interrupt sources */ uint64_t sb_zbbus_cycle_count(void); uint64_t sb_cpu_speed(void); void sb_system_reset(void); int sb_route_intsrc(int src); void sb_enable_intsrc(int cpu, int src); void sb_disable_intsrc(int cpu, int src); uint64_t sb_read_intsrc_mask(int cpu); void sb_write_intsrc_mask(int cpu, uint64_t mask); void sb_write_intmap(int cpu, int intsrc, int intrnum); int sb_read_intmap(int cpu, int intsrc); #ifdef SMP #define INTSRC_MAILBOX3 29 void sb_set_mailbox(int cpuid, uint64_t val); void sb_clear_mailbox(int cpuid, uint64_t val); #endif #endif /* _SB_SCD_H_ */ Index: head/sys/mips/sibyte/sb_zbbus.c =================================================================== --- head/sys/mips/sibyte/sb_zbbus.c (revision 326258) +++ head/sys/mips/sibyte/sb_zbbus.c (revision 326259) @@ -1,462 +1,464 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009 Neelkanth Natu * 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 "sb_scd.h" static MALLOC_DEFINE(M_INTMAP, "sb1250 intmap", "Sibyte 1250 Interrupt Mapper"); static struct mtx zbbus_intr_mtx; MTX_SYSINIT(zbbus_intr_mtx, &zbbus_intr_mtx, "zbbus_intr_mask/unmask lock", MTX_SPIN); /* * This array holds the mapping between a MIPS hard interrupt and the * interrupt sources that feed into that it. */ static uint64_t hardint_to_intsrc_mask[NHARD_IRQS]; struct sb_intmap { int intsrc; /* interrupt mapper register number (0 - 63) */ int hardint; /* cpu interrupt from 0 to NHARD_IRQS - 1 */ /* * The device that the interrupt belongs to. Note that multiple * devices may share an interrupt. For e.g. PCI_INT_x lines. * * The device 'dev' in combination with the 'rid' uniquely * identify this interrupt source. */ device_t dev; int rid; SLIST_ENTRY(sb_intmap) next; }; static SLIST_HEAD(, sb_intmap) sb_intmap_head; static struct sb_intmap * sb_intmap_lookup(int intrnum, device_t dev, int rid) { struct sb_intmap *map; SLIST_FOREACH(map, &sb_intmap_head, next) { if (dev == map->dev && rid == map->rid && intrnum == map->hardint) break; } return (map); } /* * Keep track of which (dev,rid,hardint) tuple is using the interrupt source. * * We don't actually unmask the interrupt source until the device calls * a bus_setup_intr() on the resource. */ static void sb_intmap_add(int intrnum, device_t dev, int rid, int intsrc) { struct sb_intmap *map; KASSERT(intrnum >= 0 && intrnum < NHARD_IRQS, ("intrnum is out of range: %d", intrnum)); map = sb_intmap_lookup(intrnum, dev, rid); if (map) { KASSERT(intsrc == map->intsrc, ("%s%d allocating SYS_RES_IRQ resource with rid %d " "with a different intsrc (%d versus %d)", device_get_name(dev), device_get_unit(dev), rid, intsrc, map->intsrc)); return; } map = malloc(sizeof(*map), M_INTMAP, M_WAITOK | M_ZERO); map->intsrc = intsrc; map->hardint = intrnum; map->dev = dev; map->rid = rid; SLIST_INSERT_HEAD(&sb_intmap_head, map, next); } static void sb_intmap_activate(int intrnum, device_t dev, int rid) { struct sb_intmap *map; KASSERT(intrnum >= 0 && intrnum < NHARD_IRQS, ("intrnum is out of range: %d", intrnum)); map = sb_intmap_lookup(intrnum, dev, rid); if (map) { /* * Deliver all interrupts to CPU0. */ mtx_lock_spin(&zbbus_intr_mtx); hardint_to_intsrc_mask[intrnum] |= 1ULL << map->intsrc; sb_enable_intsrc(0, map->intsrc); mtx_unlock_spin(&zbbus_intr_mtx); } else { /* * In zbbus_setup_intr() we blindly call sb_intmap_activate() * for every interrupt activation that comes our way. * * We might end up here if we did not "hijack" the SYS_RES_IRQ * resource in zbbus_alloc_resource(). */ printf("sb_intmap_activate: unable to activate interrupt %d " "for device %s%d rid %d.\n", intrnum, device_get_name(dev), device_get_unit(dev), rid); } } /* * Replace the default interrupt mask and unmask routines in intr_machdep.c * with routines that are SMP-friendly. In contrast to the default mask/unmask * routines in intr_machdep.c these routines do not change the SR.int_mask bits. * * Instead they use the interrupt mapper to either mask or unmask all * interrupt sources feeding into a particular interrupt line of the processor. * * This means that these routines have an identical effect irrespective of * which cpu is executing them. This is important because the ithread may * be scheduled to run on either of the cpus. */ static void zbbus_intr_mask(void *arg) { uint64_t mask; int irq; irq = (uintptr_t)arg; mtx_lock_spin(&zbbus_intr_mtx); mask = sb_read_intsrc_mask(0); mask |= hardint_to_intsrc_mask[irq]; sb_write_intsrc_mask(0, mask); mtx_unlock_spin(&zbbus_intr_mtx); } static void zbbus_intr_unmask(void *arg) { uint64_t mask; int irq; irq = (uintptr_t)arg; mtx_lock_spin(&zbbus_intr_mtx); mask = sb_read_intsrc_mask(0); mask &= ~hardint_to_intsrc_mask[irq]; sb_write_intsrc_mask(0, mask); mtx_unlock_spin(&zbbus_intr_mtx); } struct zbbus_devinfo { struct resource_list resources; }; static MALLOC_DEFINE(M_ZBBUSDEV, "zbbusdev", "zbbusdev"); static int zbbus_probe(device_t dev) { device_set_desc(dev, "Broadcom/Sibyte ZBbus"); return (BUS_PROBE_NOWILDCARD); } static int zbbus_attach(device_t dev) { if (bootverbose) { device_printf(dev, "attached.\n"); } cpu_set_hardintr_mask_func(zbbus_intr_mask); cpu_set_hardintr_unmask_func(zbbus_intr_unmask); bus_generic_probe(dev); bus_enumerate_hinted_children(dev); bus_generic_attach(dev); return (0); } static void zbbus_hinted_child(device_t bus, const char *dname, int dunit) { device_t child; long maddr, msize; int err, irq; if (resource_disabled(dname, dunit)) return; child = BUS_ADD_CHILD(bus, 0, dname, dunit); if (child == NULL) { panic("zbbus: could not add child %s unit %d\n", dname, dunit); } if (bootverbose) device_printf(bus, "Adding hinted child %s%d\n", dname, dunit); /* * Assign any pre-defined resources to the child. */ if (resource_long_value(dname, dunit, "msize", &msize) == 0 && resource_long_value(dname, dunit, "maddr", &maddr) == 0) { if (bootverbose) { device_printf(bus, "Assigning memory resource " "0x%0lx/%ld to child %s%d\n", maddr, msize, dname, dunit); } err = bus_set_resource(child, SYS_RES_MEMORY, 0, maddr, msize); if (err) { device_printf(bus, "Unable to set memory resource " "0x%0lx/%ld for child %s%d: %d\n", maddr, msize, dname, dunit, err); } } if (resource_int_value(dname, dunit, "irq", &irq) == 0) { if (bootverbose) { device_printf(bus, "Assigning irq resource %d to " "child %s%d\n", irq, dname, dunit); } err = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1); if (err) { device_printf(bus, "Unable to set irq resource %d" "for child %s%d: %d\n", irq, dname, dunit, err); } } } static struct resource * zbbus_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct resource *res; int intrnum, intsrc, isdefault; struct resource_list *rl; struct resource_list_entry *rle; struct zbbus_devinfo *dinfo; isdefault = (RMAN_IS_DEFAULT_RANGE(start, end) && count == 1); /* * Our direct child is asking for a default resource allocation. */ if (device_get_parent(child) == bus) { dinfo = device_get_ivars(child); rl = &dinfo->resources; rle = resource_list_find(rl, type, *rid); if (rle) { if (rle->res) panic("zbbus_alloc_resource: resource is busy"); if (isdefault) { start = rle->start; count = ulmax(count, rle->count); end = ulmax(rle->end, start + count - 1); } } else { if (isdefault) { /* * Our child is requesting a default * resource allocation but we don't have the * 'type/rid' tuple in the resource list. * * We have to fail the resource allocation. */ return (NULL); } else { /* * The child is requesting a non-default * resource. We just pass the request up * to our parent. If the resource allocation * succeeds we will create a resource list * entry corresponding to that resource. */ } } } else { rl = NULL; rle = NULL; } /* * nexus doesn't know about the interrupt mapper and only wants to * see the hard irq numbers [0-6]. We translate from the interrupt * source presented to the mapper to the interrupt number presented * to the cpu. */ if ((count == 1) && (type == SYS_RES_IRQ)) { intsrc = start; intrnum = sb_route_intsrc(intsrc); start = end = intrnum; } else { intsrc = -1; /* satisfy gcc */ intrnum = -1; } res = bus_generic_alloc_resource(bus, child, type, rid, start, end, count, flags); /* * Keep track of the input into the interrupt mapper that maps * to the resource allocated by 'child' with resource id 'rid'. * * If we don't record the mapping here then we won't be able to * locate the interrupt source when bus_setup_intr(child,rid) is * called. */ if (res != NULL && intrnum != -1) sb_intmap_add(intrnum, child, rman_get_rid(res), intsrc); /* * If a non-default resource allocation by our child was successful * then keep track of the resource in the resource list associated * with the child. */ if (res != NULL && rle == NULL && device_get_parent(child) == bus) { resource_list_add(rl, type, *rid, start, end, count); rle = resource_list_find(rl, type, *rid); if (rle == NULL) panic("zbbus_alloc_resource: cannot find resource"); } if (rle != NULL) { KASSERT(device_get_parent(child) == bus, ("rle should be NULL for passthru device")); rle->res = res; if (rle->res) { rle->start = rman_get_start(rle->res); rle->end = rman_get_end(rle->res); rle->count = count; } } return (res); } static int zbbus_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, driver_filter_t *filter, driver_intr_t *intr, void *arg, void **cookiep) { int error; error = bus_generic_setup_intr(dev, child, irq, flags, filter, intr, arg, cookiep); if (error == 0) sb_intmap_activate(rman_get_start(irq), child, rman_get_rid(irq)); return (error); } static device_t zbbus_add_child(device_t bus, u_int order, const char *name, int unit) { device_t child; struct zbbus_devinfo *dinfo; child = device_add_child_ordered(bus, order, name, unit); if (child != NULL) { dinfo = malloc(sizeof(struct zbbus_devinfo), M_ZBBUSDEV, M_WAITOK | M_ZERO); resource_list_init(&dinfo->resources); device_set_ivars(child, dinfo); } return (child); } static struct resource_list * zbbus_get_resource_list(device_t dev, device_t child) { struct zbbus_devinfo *dinfo = device_get_ivars(child); return (&dinfo->resources); } static device_method_t zbbus_methods[] ={ /* Device interface */ DEVMETHOD(device_probe, zbbus_probe), DEVMETHOD(device_attach, zbbus_attach), DEVMETHOD(device_detach, bus_generic_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_alloc_resource, zbbus_alloc_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_release_resource, bus_generic_release_resource), DEVMETHOD(bus_get_resource_list,zbbus_get_resource_list), DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource), DEVMETHOD(bus_setup_intr, zbbus_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_add_child, zbbus_add_child), DEVMETHOD(bus_hinted_child, zbbus_hinted_child), { 0, 0 } }; static driver_t zbbus_driver = { "zbbus", zbbus_methods }; static devclass_t zbbus_devclass; DRIVER_MODULE(zbbus, nexus, zbbus_driver, zbbus_devclass, 0, 0); Index: head/sys/mips/sibyte/sb_zbpci.c =================================================================== --- head/sys/mips/sibyte/sb_zbpci.c (revision 326258) +++ head/sys/mips/sibyte/sb_zbpci.c (revision 326259) @@ -1,543 +1,545 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2009 Neelkanth Natu * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pcib_if.h" #include "sb_bus_space.h" #include "sb_scd.h" __FBSDID("$FreeBSD$"); static struct { vm_offset_t vaddr; vm_paddr_t paddr; } zbpci_config_space[MAXCPU]; static const vm_paddr_t CFG_PADDR_BASE = 0xFE000000; static const u_long PCI_IOSPACE_ADDR = 0xFC000000; static const u_long PCI_IOSPACE_SIZE = 0x02000000; #define PCI_MATCH_BYTE_LANES_START 0x40000000 #define PCI_MATCH_BYTE_LANES_END 0x5FFFFFFF #define PCI_MATCH_BYTE_LANES_SIZE 0x20000000 #define PCI_MATCH_BIT_LANES_MASK (1 << 29) #define PCI_MATCH_BIT_LANES_START 0x60000000 #define PCI_MATCH_BIT_LANES_END 0x7FFFFFFF #define PCI_MATCH_BIT_LANES_SIZE 0x20000000 static struct rman port_rman; static int zbpci_probe(device_t dev) { device_set_desc(dev, "Broadcom/Sibyte PCI I/O Bridge"); return (0); } static int zbpci_attach(device_t dev) { int n, rid, size; vm_offset_t va; struct resource *res; /* * Reserve the physical memory window used to map PCI I/O space. */ rid = 0; res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, PCI_IOSPACE_ADDR, PCI_IOSPACE_ADDR + PCI_IOSPACE_SIZE - 1, PCI_IOSPACE_SIZE, 0); if (res == NULL) panic("Cannot allocate resource for PCI I/O space mapping."); port_rman.rm_start = 0; port_rman.rm_end = PCI_IOSPACE_SIZE - 1; port_rman.rm_type = RMAN_ARRAY; port_rman.rm_descr = "PCI I/O ports"; if (rman_init(&port_rman) != 0 || rman_manage_region(&port_rman, 0, PCI_IOSPACE_SIZE - 1) != 0) panic("%s: port_rman", __func__); /* * Reserve the physical memory that is used to read/write to the * pci config space but don't activate it. We are using a page worth * of KVA as a window over this region. */ rid = 1; size = (PCI_BUSMAX + 1) * (PCI_SLOTMAX + 1) * (PCI_FUNCMAX + 1) * 256; res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, CFG_PADDR_BASE, CFG_PADDR_BASE + size - 1, size, 0); if (res == NULL) panic("Cannot allocate resource for config space accesses."); /* * Allocate the entire "match bit lanes" address space. */ #if _BYTE_ORDER == _BIG_ENDIAN rid = 2; res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, PCI_MATCH_BIT_LANES_START, PCI_MATCH_BIT_LANES_END, PCI_MATCH_BIT_LANES_SIZE, 0); if (res == NULL) panic("Cannot allocate resource for pci match bit lanes."); #endif /* _BYTE_ORDER ==_BIG_ENDIAN */ /* * Allocate KVA for accessing PCI config space. */ va = kva_alloc(PAGE_SIZE * mp_ncpus); if (va == 0) { device_printf(dev, "Cannot allocate virtual addresses for " "config space access.\n"); return (ENOMEM); } for (n = 0; n < mp_ncpus; ++n) zbpci_config_space[n].vaddr = va + n * PAGE_SIZE; /* * Sibyte has the PCI bus hierarchy rooted at bus 0 and HT-PCI * hierarchy rooted at bus 1. */ if (device_add_child(dev, "pci", 0) == NULL) panic("zbpci_attach: could not add pci bus 0.\n"); if (device_add_child(dev, "pci", 1) == NULL) panic("zbpci_attach: could not add pci bus 1.\n"); if (bootverbose) device_printf(dev, "attached.\n"); return (bus_generic_attach(dev)); } static struct resource * zbpci_alloc_resource(device_t bus, device_t child, int type, int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) { struct resource *res; /* * Handle PCI I/O port resources here and pass everything else to nexus. */ if (type != SYS_RES_IOPORT) { res = bus_generic_alloc_resource(bus, child, type, rid, start, end, count, flags); return (res); } res = rman_reserve_resource(&port_rman, start, end, count, flags, child); if (res == NULL) return (NULL); rman_set_rid(res, *rid); /* Activate the resource is requested */ if (flags & RF_ACTIVE) { if (bus_activate_resource(child, type, *rid, res) != 0) { rman_release_resource(res); return (NULL); } } return (res); } static int zbpci_activate_resource(device_t bus, device_t child, int type, int rid, struct resource *res) { int error; void *vaddr; u_long orig_paddr, paddr, psize; paddr = rman_get_start(res); psize = rman_get_size(res); orig_paddr = paddr; #if _BYTE_ORDER == _BIG_ENDIAN /* * The CFE allocates PCI memory resources that map to the * "match byte lanes" address space. This address space works * best for DMA transfers because it does not do any automatic * byte swaps when data crosses the pci-cpu interface. * * This also makes it sub-optimal for accesses to PCI device * registers because it exposes the little-endian nature of * the PCI bus to the big-endian CPU. The Sibyte has another * address window called the "match bit lanes" window which * automatically swaps bytes when data crosses the pci-cpu * interface. * * We "assume" that any bus_space memory accesses done by the * CPU to a PCI device are register/configuration accesses and * are done through the "match bit lanes" window. Any DMA * transfers will continue to be through the "match byte lanes" * window because the PCI BAR registers will not be changed. */ if (type == SYS_RES_MEMORY) { if (paddr >= PCI_MATCH_BYTE_LANES_START && paddr + psize - 1 <= PCI_MATCH_BYTE_LANES_END) { paddr |= PCI_MATCH_BIT_LANES_MASK; rman_set_start(res, paddr); rman_set_end(res, paddr + psize - 1); } } #endif if (type != SYS_RES_IOPORT) { error = bus_generic_activate_resource(bus, child, type, rid, res); #if _BYTE_ORDER == _BIG_ENDIAN if (type == SYS_RES_MEMORY) { rman_set_start(res, orig_paddr); rman_set_end(res, orig_paddr + psize - 1); } #endif return (error); } /* * Map the I/O space resource through the memory window starting * at PCI_IOSPACE_ADDR. */ vaddr = pmap_mapdev(paddr + PCI_IOSPACE_ADDR, psize); rman_set_virtual(res, vaddr); rman_set_bustag(res, mips_bus_space_generic); rman_set_bushandle(res, (bus_space_handle_t)vaddr); return (rman_activate_resource(res)); } static int zbpci_release_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { int error; if (type != SYS_RES_IOPORT) return (bus_generic_release_resource(bus, child, type, rid, r)); if (rman_get_flags(r) & RF_ACTIVE) { error = bus_deactivate_resource(child, type, rid, r); if (error) return (error); } return (rman_release_resource(r)); } static int zbpci_deactivate_resource(device_t bus, device_t child, int type, int rid, struct resource *r) { vm_offset_t va; if (type != SYS_RES_IOPORT) { return (bus_generic_deactivate_resource(bus, child, type, rid, r)); } va = (vm_offset_t)rman_get_virtual(r); pmap_unmapdev(va, rman_get_size(r)); return (rman_deactivate_resource(r)); } static int zbpci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) { switch (which) { case PCIB_IVAR_DOMAIN: *result = 0; /* single PCI domain */ return (0); case PCIB_IVAR_BUS: *result = device_get_unit(child); /* PCI bus 0 or 1 */ return (0); default: return (ENOENT); } } /* * We rely on the CFE to have configured the intline correctly to point to * one of PCI-A/PCI-B/PCI-C/PCI-D in the interupt mapper. */ static int zbpci_route_interrupt(device_t pcib, device_t dev, int pin) { return (PCI_INVALID_IRQ); } /* * This function is expected to be called in a critical section since it * changes the per-cpu pci config space va-to-pa mappings. */ static vm_offset_t zbpci_config_space_va(int bus, int slot, int func, int reg, int bytes) { int cpu; vm_offset_t va_page; vm_paddr_t pa, pa_page; if (bus <= PCI_BUSMAX && slot <= PCI_SLOTMAX && func <= PCI_FUNCMAX && reg <= PCI_REGMAX && (bytes == 1 || bytes == 2 || bytes == 4) && ((reg & (bytes - 1)) == 0)) { cpu = PCPU_GET(cpuid); va_page = zbpci_config_space[cpu].vaddr; pa = CFG_PADDR_BASE | (bus << 16) | (slot << 11) | (func << 8) | reg; #if _BYTE_ORDER == _BIG_ENDIAN pa = pa ^ (4 - bytes); #endif pa_page = rounddown2(pa, PAGE_SIZE); if (zbpci_config_space[cpu].paddr != pa_page) { pmap_kremove(va_page); pmap_kenter_attr(va_page, pa_page, PTE_C_UNCACHED); zbpci_config_space[cpu].paddr = pa_page; } return (va_page + (pa - pa_page)); } else { return (0); } } static uint32_t zbpci_read_config(device_t dev, u_int b, u_int s, u_int f, u_int r, int w) { uint32_t data; vm_offset_t va; critical_enter(); va = zbpci_config_space_va(b, s, f, r, w); if (va == 0) { panic("zbpci_read_config: invalid %d/%d/%d[%d] %d\n", b, s, f, r, w); } switch (w) { case 4: data = *(uint32_t *)va; break; case 2: data = *(uint16_t *)va; break; case 1: data = *(uint8_t *)va; break; default: panic("zbpci_read_config: invalid width %d\n", w); } critical_exit(); return (data); } static void zbpci_write_config(device_t d, u_int b, u_int s, u_int f, u_int r, uint32_t data, int w) { vm_offset_t va; critical_enter(); va = zbpci_config_space_va(b, s, f, r, w); if (va == 0) { panic("zbpci_write_config: invalid %d/%d/%d[%d] %d/%d\n", b, s, f, r, data, w); } switch (w) { case 4: *(uint32_t *)va = data; break; case 2: *(uint16_t *)va = data; break; case 1: *(uint8_t *)va = data; break; default: panic("zbpci_write_config: invalid width %d\n", w); } critical_exit(); } static device_method_t zbpci_methods[] ={ /* Device interface */ DEVMETHOD(device_probe, zbpci_probe), DEVMETHOD(device_attach, zbpci_attach), DEVMETHOD(device_detach, bus_generic_detach), DEVMETHOD(device_shutdown, bus_generic_shutdown), DEVMETHOD(device_suspend, bus_generic_suspend), DEVMETHOD(device_resume, bus_generic_resume), /* Bus interface */ DEVMETHOD(bus_read_ivar, zbpci_read_ivar), DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), DEVMETHOD(bus_alloc_resource, zbpci_alloc_resource), DEVMETHOD(bus_activate_resource, zbpci_activate_resource), DEVMETHOD(bus_deactivate_resource, zbpci_deactivate_resource), DEVMETHOD(bus_release_resource, zbpci_release_resource), DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), DEVMETHOD(bus_add_child, bus_generic_add_child), /* pcib interface */ DEVMETHOD(pcib_maxslots, pcib_maxslots), DEVMETHOD(pcib_read_config, zbpci_read_config), DEVMETHOD(pcib_write_config, zbpci_write_config), DEVMETHOD(pcib_route_interrupt, zbpci_route_interrupt), DEVMETHOD(pcib_request_feature, pcib_request_feature_allow), { 0, 0 } }; /* * The "zbpci" class inherits from the "pcib" base class. Therefore in * addition to drivers that belong to the "zbpci" class we will also * consider drivers belonging to the "pcib" when probing children of * "zbpci". */ DEFINE_CLASS_1(zbpci, zbpci_driver, zbpci_methods, 0, pcib_driver); static devclass_t zbpci_devclass; DRIVER_MODULE(zbpci, zbbus, zbpci_driver, zbpci_devclass, 0, 0); /* * Big endian bus space routines */ #if _BYTE_ORDER == _BIG_ENDIAN /* * The CPU correctly deals with the big-endian to little-endian swap if * we are accessing 4 bytes at a time. However if we want to read 1 or 2 * bytes then we need to fudge the address generated by the CPU such that * it generates the right byte enables on the PCI bus. */ static bus_addr_t sb_match_bit_lane_addr(bus_addr_t addr, int bytes) { vm_offset_t pa; pa = vtophys(addr); if (pa >= PCI_MATCH_BIT_LANES_START && pa <= PCI_MATCH_BIT_LANES_END) return (addr ^ (4 - bytes)); else return (addr); } uint8_t sb_big_endian_read8(bus_addr_t addr) { bus_addr_t addr2; addr2 = sb_match_bit_lane_addr(addr, 1); return (readb(addr2)); } uint16_t sb_big_endian_read16(bus_addr_t addr) { bus_addr_t addr2; addr2 = sb_match_bit_lane_addr(addr, 2); return (readw(addr2)); } uint32_t sb_big_endian_read32(bus_addr_t addr) { bus_addr_t addr2; addr2 = sb_match_bit_lane_addr(addr, 4); return (readl(addr2)); } void sb_big_endian_write8(bus_addr_t addr, uint8_t val) { bus_addr_t addr2; addr2 = sb_match_bit_lane_addr(addr, 1); writeb(addr2, val); } void sb_big_endian_write16(bus_addr_t addr, uint16_t val) { bus_addr_t addr2; addr2 = sb_match_bit_lane_addr(addr, 2); writew(addr2, val); } void sb_big_endian_write32(bus_addr_t addr, uint32_t val) { bus_addr_t addr2; addr2 = sb_match_bit_lane_addr(addr, 4); writel(addr2, val); } #endif /* _BIG_ENDIAN */