13f51d888SZbigniew Bodek /* 23f51d888SZbigniew Bodek * Copyright (C) 2016 Cavium Inc. 33f51d888SZbigniew Bodek * All rights reserved. 43f51d888SZbigniew Bodek * 53f51d888SZbigniew Bodek * Developed by Semihalf. 63f51d888SZbigniew Bodek * 73f51d888SZbigniew Bodek * Redistribution and use in source and binary forms, with or without 83f51d888SZbigniew Bodek * modification, are permitted provided that the following conditions 93f51d888SZbigniew Bodek * are met: 103f51d888SZbigniew Bodek * 1. Redistributions of source code must retain the above copyright 113f51d888SZbigniew Bodek * notice, this list of conditions and the following disclaimer. 123f51d888SZbigniew Bodek * 2. Redistributions in binary form must reproduce the above copyright 133f51d888SZbigniew Bodek * notice, this list of conditions and the following disclaimer in the 143f51d888SZbigniew Bodek * documentation and/or other materials provided with the distribution. 153f51d888SZbigniew Bodek * 163f51d888SZbigniew Bodek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 173f51d888SZbigniew Bodek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 183f51d888SZbigniew Bodek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 193f51d888SZbigniew Bodek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 203f51d888SZbigniew Bodek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 213f51d888SZbigniew Bodek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 223f51d888SZbigniew Bodek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 233f51d888SZbigniew Bodek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 243f51d888SZbigniew Bodek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 253f51d888SZbigniew Bodek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 263f51d888SZbigniew Bodek * SUCH DAMAGE. 273f51d888SZbigniew Bodek */ 283f51d888SZbigniew Bodek #include "opt_platform.h" 293f51d888SZbigniew Bodek 303f51d888SZbigniew Bodek #include <sys/param.h> 313f51d888SZbigniew Bodek #include <sys/systm.h> 323f51d888SZbigniew Bodek #include <sys/bus.h> 333f51d888SZbigniew Bodek #include <sys/kernel.h> 343f51d888SZbigniew Bodek #include <sys/module.h> 353f51d888SZbigniew Bodek #include <sys/resource.h> 363f51d888SZbigniew Bodek #include <sys/rman.h> 373f51d888SZbigniew Bodek #include <sys/socket.h> 383f51d888SZbigniew Bodek #include <sys/queue.h> 393f51d888SZbigniew Bodek 403f51d888SZbigniew Bodek #include <dev/ofw/ofw_bus.h> 413f51d888SZbigniew Bodek #include <dev/ofw/ofw_bus_subr.h> 423f51d888SZbigniew Bodek #include <dev/fdt/simplebus.h> 433f51d888SZbigniew Bodek 443f51d888SZbigniew Bodek #include <machine/bus.h> 453f51d888SZbigniew Bodek #include <machine/resource.h> 463f51d888SZbigniew Bodek 473f51d888SZbigniew Bodek static MALLOC_DEFINE(M_MRMLB, "MRML bridge", "Cavium MRML bridge"); 483f51d888SZbigniew Bodek 493f51d888SZbigniew Bodek static device_probe_t mrmlb_fdt_probe; 503f51d888SZbigniew Bodek static device_attach_t mrmlb_fdt_attach; 513f51d888SZbigniew Bodek 523f51d888SZbigniew Bodek static struct resource * mrmlb_ofw_bus_alloc_res(device_t, device_t, int, int *, 533f51d888SZbigniew Bodek rman_res_t, rman_res_t, rman_res_t, u_int); 543f51d888SZbigniew Bodek 553f51d888SZbigniew Bodek static const struct ofw_bus_devinfo * mrmlb_ofw_get_devinfo(device_t, device_t); 563f51d888SZbigniew Bodek 573f51d888SZbigniew Bodek static device_method_t mrmlbus_fdt_methods[] = { 583f51d888SZbigniew Bodek /* Device interface */ 593f51d888SZbigniew Bodek DEVMETHOD(device_probe, mrmlb_fdt_probe), 603f51d888SZbigniew Bodek DEVMETHOD(device_attach, mrmlb_fdt_attach), 613f51d888SZbigniew Bodek 623f51d888SZbigniew Bodek /* Bus interface */ 633f51d888SZbigniew Bodek DEVMETHOD(bus_alloc_resource, mrmlb_ofw_bus_alloc_res), 643f51d888SZbigniew Bodek DEVMETHOD(bus_release_resource, bus_generic_release_resource), 653f51d888SZbigniew Bodek DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 663f51d888SZbigniew Bodek 673f51d888SZbigniew Bodek /* ofw_bus interface */ 683f51d888SZbigniew Bodek DEVMETHOD(ofw_bus_get_devinfo, mrmlb_ofw_get_devinfo), 693f51d888SZbigniew Bodek DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 703f51d888SZbigniew Bodek DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 713f51d888SZbigniew Bodek DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 723f51d888SZbigniew Bodek DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 733f51d888SZbigniew Bodek DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 743f51d888SZbigniew Bodek 753f51d888SZbigniew Bodek DEVMETHOD_END 763f51d888SZbigniew Bodek }; 773f51d888SZbigniew Bodek 783f51d888SZbigniew Bodek DEFINE_CLASS_0(mrmlbus, mrmlbus_fdt_driver, mrmlbus_fdt_methods, 793f51d888SZbigniew Bodek sizeof(struct simplebus_softc)); 803f51d888SZbigniew Bodek 8194412ad7SJohn Baldwin EARLY_DRIVER_MODULE(mrmlbus, pcib, mrmlbus_fdt_driver, 0, 0, 823f51d888SZbigniew Bodek BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 83f4aafb9eSWojciech Macek MODULE_VERSION(mrmlbus, 1); 843f51d888SZbigniew Bodek 853f51d888SZbigniew Bodek static int mrmlb_ofw_fill_ranges(phandle_t, struct simplebus_softc *); 863f51d888SZbigniew Bodek static int mrmlb_ofw_bus_attach(device_t); 873f51d888SZbigniew Bodek 883f51d888SZbigniew Bodek static int 893f51d888SZbigniew Bodek mrmlb_fdt_probe(device_t dev) 903f51d888SZbigniew Bodek { 913f51d888SZbigniew Bodek 923f51d888SZbigniew Bodek if (!ofw_bus_status_okay(dev)) 933f51d888SZbigniew Bodek return (ENXIO); 943f51d888SZbigniew Bodek 953f51d888SZbigniew Bodek if (!ofw_bus_is_compatible(dev, "cavium,thunder-8890-mrml-bridge")) 963f51d888SZbigniew Bodek return (ENXIO); 973f51d888SZbigniew Bodek 983f51d888SZbigniew Bodek device_set_desc(dev, "Cavium ThunderX MRML bridge"); 993f51d888SZbigniew Bodek return (BUS_PROBE_SPECIFIC); 1003f51d888SZbigniew Bodek } 1013f51d888SZbigniew Bodek 1023f51d888SZbigniew Bodek static int 1033f51d888SZbigniew Bodek mrmlb_fdt_attach(device_t dev) 1043f51d888SZbigniew Bodek { 1053f51d888SZbigniew Bodek int err; 1063f51d888SZbigniew Bodek 1073f51d888SZbigniew Bodek err = mrmlb_ofw_bus_attach(dev); 1083f51d888SZbigniew Bodek if (err != 0) 1093f51d888SZbigniew Bodek return (err); 1103f51d888SZbigniew Bodek 1113f51d888SZbigniew Bodek return (bus_generic_attach(dev)); 1123f51d888SZbigniew Bodek } 1133f51d888SZbigniew Bodek 1143f51d888SZbigniew Bodek /* OFW bus interface */ 1153f51d888SZbigniew Bodek struct mrmlb_ofw_devinfo { 1163f51d888SZbigniew Bodek struct ofw_bus_devinfo di_dinfo; 1173f51d888SZbigniew Bodek struct resource_list di_rl; 1183f51d888SZbigniew Bodek }; 1193f51d888SZbigniew Bodek 1203f51d888SZbigniew Bodek static const struct ofw_bus_devinfo * 1213f51d888SZbigniew Bodek mrmlb_ofw_get_devinfo(device_t bus __unused, device_t child) 1223f51d888SZbigniew Bodek { 1233f51d888SZbigniew Bodek struct mrmlb_ofw_devinfo *di; 1243f51d888SZbigniew Bodek 1253f51d888SZbigniew Bodek di = device_get_ivars(child); 1263f51d888SZbigniew Bodek return (&di->di_dinfo); 1273f51d888SZbigniew Bodek } 1283f51d888SZbigniew Bodek 1293f51d888SZbigniew Bodek static struct resource * 1303f51d888SZbigniew Bodek mrmlb_ofw_bus_alloc_res(device_t bus, device_t child, int type, int *rid, 1313f51d888SZbigniew Bodek rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 1323f51d888SZbigniew Bodek { 1333f51d888SZbigniew Bodek struct simplebus_softc *sc; 1343f51d888SZbigniew Bodek struct mrmlb_ofw_devinfo *di; 1353f51d888SZbigniew Bodek struct resource_list_entry *rle; 1363f51d888SZbigniew Bodek int i; 1373f51d888SZbigniew Bodek 1387915adb5SJustin Hibbits if (RMAN_IS_DEFAULT_RANGE(start, end)) { 1393f51d888SZbigniew Bodek if ((di = device_get_ivars(child)) == NULL) 1403f51d888SZbigniew Bodek return (NULL); 1413f51d888SZbigniew Bodek if (type == SYS_RES_IOPORT) 1423f51d888SZbigniew Bodek type = SYS_RES_MEMORY; 1433f51d888SZbigniew Bodek 1443f51d888SZbigniew Bodek /* Find defaults for this rid */ 1453f51d888SZbigniew Bodek rle = resource_list_find(&di->di_rl, type, *rid); 1463f51d888SZbigniew Bodek if (rle == NULL) 1473f51d888SZbigniew Bodek return (NULL); 1483f51d888SZbigniew Bodek 1493f51d888SZbigniew Bodek start = rle->start; 1503f51d888SZbigniew Bodek end = rle->end; 1513f51d888SZbigniew Bodek count = rle->count; 1523f51d888SZbigniew Bodek } 1533f51d888SZbigniew Bodek 1543f51d888SZbigniew Bodek sc = device_get_softc(bus); 1553f51d888SZbigniew Bodek 1563f51d888SZbigniew Bodek if (type == SYS_RES_MEMORY) { 1573f51d888SZbigniew Bodek /* Remap through ranges property */ 1583f51d888SZbigniew Bodek for (i = 0; i < sc->nranges; i++) { 1593f51d888SZbigniew Bodek if (start >= sc->ranges[i].bus && end < 1603f51d888SZbigniew Bodek sc->ranges[i].bus + sc->ranges[i].size) { 1613f51d888SZbigniew Bodek start -= sc->ranges[i].bus; 1623f51d888SZbigniew Bodek start += sc->ranges[i].host; 1633f51d888SZbigniew Bodek end -= sc->ranges[i].bus; 1643f51d888SZbigniew Bodek end += sc->ranges[i].host; 1653f51d888SZbigniew Bodek break; 1663f51d888SZbigniew Bodek } 1673f51d888SZbigniew Bodek } 1683f51d888SZbigniew Bodek 1693f51d888SZbigniew Bodek if (i == sc->nranges && sc->nranges != 0) { 1703f51d888SZbigniew Bodek device_printf(bus, "Could not map resource " 1713f51d888SZbigniew Bodek "%#lx-%#lx\n", start, end); 1723f51d888SZbigniew Bodek return (NULL); 1733f51d888SZbigniew Bodek } 1743f51d888SZbigniew Bodek } 1753f51d888SZbigniew Bodek 1763f51d888SZbigniew Bodek return (bus_generic_alloc_resource(bus, child, type, rid, start, end, 1773f51d888SZbigniew Bodek count, flags)); 1783f51d888SZbigniew Bodek } 1793f51d888SZbigniew Bodek 1803f51d888SZbigniew Bodek /* Helper functions */ 1813f51d888SZbigniew Bodek 1823f51d888SZbigniew Bodek static int 1833f51d888SZbigniew Bodek mrmlb_ofw_fill_ranges(phandle_t node, struct simplebus_softc *sc) 1843f51d888SZbigniew Bodek { 1853f51d888SZbigniew Bodek int host_address_cells; 1863f51d888SZbigniew Bodek cell_t *base_ranges; 1873f51d888SZbigniew Bodek ssize_t nbase_ranges; 1883f51d888SZbigniew Bodek int err; 1893f51d888SZbigniew Bodek int i, j, k; 1903f51d888SZbigniew Bodek 1913f51d888SZbigniew Bodek err = OF_searchencprop(OF_parent(node), "#address-cells", 1923f51d888SZbigniew Bodek &host_address_cells, sizeof(host_address_cells)); 1933f51d888SZbigniew Bodek if (err <= 0) 1943f51d888SZbigniew Bodek return (-1); 1953f51d888SZbigniew Bodek 1963f51d888SZbigniew Bodek nbase_ranges = OF_getproplen(node, "ranges"); 1973f51d888SZbigniew Bodek if (nbase_ranges < 0) 1983f51d888SZbigniew Bodek return (-1); 1993f51d888SZbigniew Bodek sc->nranges = nbase_ranges / sizeof(cell_t) / 2003f51d888SZbigniew Bodek (sc->acells + host_address_cells + sc->scells); 2013f51d888SZbigniew Bodek if (sc->nranges == 0) 2023f51d888SZbigniew Bodek return (0); 2033f51d888SZbigniew Bodek 2043f51d888SZbigniew Bodek sc->ranges = malloc(sc->nranges * sizeof(sc->ranges[0]), 2053f51d888SZbigniew Bodek M_MRMLB, M_WAITOK); 2063f51d888SZbigniew Bodek base_ranges = malloc(nbase_ranges, M_MRMLB, M_WAITOK); 2073f51d888SZbigniew Bodek OF_getencprop(node, "ranges", base_ranges, nbase_ranges); 2083f51d888SZbigniew Bodek 2093f51d888SZbigniew Bodek for (i = 0, j = 0; i < sc->nranges; i++) { 2103f51d888SZbigniew Bodek sc->ranges[i].bus = 0; 2113f51d888SZbigniew Bodek for (k = 0; k < sc->acells; k++) { 2123f51d888SZbigniew Bodek sc->ranges[i].bus <<= 32; 2133f51d888SZbigniew Bodek sc->ranges[i].bus |= base_ranges[j++]; 2143f51d888SZbigniew Bodek } 2153f51d888SZbigniew Bodek sc->ranges[i].host = 0; 2163f51d888SZbigniew Bodek for (k = 0; k < host_address_cells; k++) { 2173f51d888SZbigniew Bodek sc->ranges[i].host <<= 32; 2183f51d888SZbigniew Bodek sc->ranges[i].host |= base_ranges[j++]; 2193f51d888SZbigniew Bodek } 2203f51d888SZbigniew Bodek sc->ranges[i].size = 0; 2213f51d888SZbigniew Bodek for (k = 0; k < sc->scells; k++) { 2223f51d888SZbigniew Bodek sc->ranges[i].size <<= 32; 2233f51d888SZbigniew Bodek sc->ranges[i].size |= base_ranges[j++]; 2243f51d888SZbigniew Bodek } 2253f51d888SZbigniew Bodek } 2263f51d888SZbigniew Bodek 2273f51d888SZbigniew Bodek free(base_ranges, M_MRMLB); 2283f51d888SZbigniew Bodek return (sc->nranges); 2293f51d888SZbigniew Bodek } 2303f51d888SZbigniew Bodek 2313f51d888SZbigniew Bodek static int 2323f51d888SZbigniew Bodek mrmlb_ofw_bus_attach(device_t dev) 2333f51d888SZbigniew Bodek { 2343f51d888SZbigniew Bodek struct simplebus_softc *sc; 2353f51d888SZbigniew Bodek struct mrmlb_ofw_devinfo *di; 2363f51d888SZbigniew Bodek device_t child; 2373f51d888SZbigniew Bodek phandle_t parent, node; 2383f51d888SZbigniew Bodek 2393f51d888SZbigniew Bodek parent = ofw_bus_get_node(dev); 2403f51d888SZbigniew Bodek simplebus_init(dev, parent); 2413f51d888SZbigniew Bodek 2423f51d888SZbigniew Bodek sc = device_get_softc(dev); 2433f51d888SZbigniew Bodek 2443f51d888SZbigniew Bodek if (mrmlb_ofw_fill_ranges(parent, sc) < 0) { 2453f51d888SZbigniew Bodek device_printf(dev, "could not get ranges\n"); 2463f51d888SZbigniew Bodek return (ENXIO); 2473f51d888SZbigniew Bodek } 2483f51d888SZbigniew Bodek /* Iterate through all bus subordinates */ 2493f51d888SZbigniew Bodek for (node = OF_child(parent); node > 0; node = OF_peer(node)) { 2503f51d888SZbigniew Bodek /* Allocate and populate devinfo. */ 2513f51d888SZbigniew Bodek di = malloc(sizeof(*di), M_MRMLB, M_WAITOK | M_ZERO); 2523f51d888SZbigniew Bodek if (ofw_bus_gen_setup_devinfo(&di->di_dinfo, node) != 0) { 2533f51d888SZbigniew Bodek free(di, M_MRMLB); 2543f51d888SZbigniew Bodek continue; 2553f51d888SZbigniew Bodek } 2563f51d888SZbigniew Bodek 2573f51d888SZbigniew Bodek /* Initialize and populate resource list. */ 2583f51d888SZbigniew Bodek resource_list_init(&di->di_rl); 2593f51d888SZbigniew Bodek ofw_bus_reg_to_rl(dev, node, sc->acells, sc->scells, 2603f51d888SZbigniew Bodek &di->di_rl); 2613f51d888SZbigniew Bodek ofw_bus_intr_to_rl(dev, node, &di->di_rl, NULL); 2623f51d888SZbigniew Bodek 2633f51d888SZbigniew Bodek /* Add newbus device for this FDT node */ 264*5b56413dSWarner Losh child = device_add_child(dev, NULL, DEVICE_UNIT_ANY); 2653f51d888SZbigniew Bodek if (child == NULL) { 2663f51d888SZbigniew Bodek resource_list_free(&di->di_rl); 2673f51d888SZbigniew Bodek ofw_bus_gen_destroy_devinfo(&di->di_dinfo); 2683f51d888SZbigniew Bodek free(di, M_MRMLB); 2693f51d888SZbigniew Bodek continue; 2703f51d888SZbigniew Bodek } 2713f51d888SZbigniew Bodek 2723f51d888SZbigniew Bodek device_set_ivars(child, di); 2733f51d888SZbigniew Bodek } 2743f51d888SZbigniew Bodek 2753f51d888SZbigniew Bodek return (0); 2763f51d888SZbigniew Bodek } 277