1*3706af42SArnaud Ysmal /*- 2*3706af42SArnaud Ysmal * Copyright (c) 2018 Stormshield 3*3706af42SArnaud Ysmal * All rights reserved. 4*3706af42SArnaud Ysmal * 5*3706af42SArnaud Ysmal * Redistribution and use in source and binary forms, with or without 6*3706af42SArnaud Ysmal * modification, are permitted provided that the following conditions 7*3706af42SArnaud Ysmal * are met: 8*3706af42SArnaud Ysmal * 1. Redistributions of source code must retain the above copyright 9*3706af42SArnaud Ysmal * notice, this list of conditions and the following disclaimer. 10*3706af42SArnaud Ysmal * 2. Redistributions in binary form must reproduce the above copyright 11*3706af42SArnaud Ysmal * notice, this list of conditions and the following disclaimer in the 12*3706af42SArnaud Ysmal * documentation and/or other materials provided with the distribution. 13*3706af42SArnaud Ysmal * 14*3706af42SArnaud Ysmal * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15*3706af42SArnaud Ysmal * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16*3706af42SArnaud Ysmal * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17*3706af42SArnaud Ysmal * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18*3706af42SArnaud Ysmal * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19*3706af42SArnaud Ysmal * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20*3706af42SArnaud Ysmal * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*3706af42SArnaud Ysmal * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22*3706af42SArnaud Ysmal * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23*3706af42SArnaud Ysmal * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24*3706af42SArnaud Ysmal * SUCH DAMAGE. 25*3706af42SArnaud Ysmal */ 26*3706af42SArnaud Ysmal 27*3706af42SArnaud Ysmal /* 28*3706af42SArnaud Ysmal * Implementation of Primary to Sideband bridge (P2SB), the documentation is available here : 29*3706af42SArnaud Ysmal * https://www.intel.com/content/dam/www/public/us/en/documents/datasheets/c620-series-chipset-datasheet.pdf 30*3706af42SArnaud Ysmal * section 36.9 P2SB Bridge. 31*3706af42SArnaud Ysmal * This device exposes a 16MB memory block, this block is composed of 256 64KB blocks called ports. 32*3706af42SArnaud Ysmal * The indexes of this array (target port ID) can be found on the Table 36-10 of the documentation. 33*3706af42SArnaud Ysmal */ 34*3706af42SArnaud Ysmal 35*3706af42SArnaud Ysmal #include <sys/param.h> 36*3706af42SArnaud Ysmal #include <sys/module.h> 37*3706af42SArnaud Ysmal #include <sys/systm.h> 38*3706af42SArnaud Ysmal #include <sys/errno.h> 39*3706af42SArnaud Ysmal #include <sys/kernel.h> 40*3706af42SArnaud Ysmal #include <sys/lock.h> 41*3706af42SArnaud Ysmal #include <sys/malloc.h> 42*3706af42SArnaud Ysmal #include <sys/mutex.h> 43*3706af42SArnaud Ysmal #include <sys/bus.h> 44*3706af42SArnaud Ysmal 45*3706af42SArnaud Ysmal #include <machine/bus.h> 46*3706af42SArnaud Ysmal #include <sys/rman.h> 47*3706af42SArnaud Ysmal #include <machine/resource.h> 48*3706af42SArnaud Ysmal 49*3706af42SArnaud Ysmal #include <dev/pci/pcivar.h> 50*3706af42SArnaud Ysmal #include <dev/pci/pcireg.h> 51*3706af42SArnaud Ysmal 52*3706af42SArnaud Ysmal #include "p2sb.h" 53*3706af42SArnaud Ysmal 54*3706af42SArnaud Ysmal #define PCI_PRODUCT_LEWISBURG_P2SB 0xa1a08086 55*3706af42SArnaud Ysmal 56*3706af42SArnaud Ysmal #define P2SB_PORT2ADDRESS_SHIFT 16 57*3706af42SArnaud Ysmal #define P2SB_PORT_ADDRESS(port) ((uint32_t)port << P2SB_PORT2ADDRESS_SHIFT) 58*3706af42SArnaud Ysmal 59*3706af42SArnaud Ysmal static const uint8_t lbg_communities[] = { 60*3706af42SArnaud Ysmal 0xAF, 0xAE, 0xAD, 0xAC, 0xAB, 0x11 61*3706af42SArnaud Ysmal }; 62*3706af42SArnaud Ysmal 63*3706af42SArnaud Ysmal /* The softc holds our per-instance data. */ 64*3706af42SArnaud Ysmal struct p2sb_softc { 65*3706af42SArnaud Ysmal device_t dev; 66*3706af42SArnaud Ysmal int rid; 67*3706af42SArnaud Ysmal struct resource *res; 68*3706af42SArnaud Ysmal struct intel_community *communities; 69*3706af42SArnaud Ysmal int ncommunities; 70*3706af42SArnaud Ysmal struct mtx mutex; 71*3706af42SArnaud Ysmal }; 72*3706af42SArnaud Ysmal 73*3706af42SArnaud Ysmal int 74*3706af42SArnaud Ysmal p2sb_get_port(device_t dev, int unit) 75*3706af42SArnaud Ysmal { 76*3706af42SArnaud Ysmal 77*3706af42SArnaud Ysmal if (unit >= nitems(lbg_communities)) 78*3706af42SArnaud Ysmal return (EINVAL); 79*3706af42SArnaud Ysmal return (lbg_communities[unit]); 80*3706af42SArnaud Ysmal } 81*3706af42SArnaud Ysmal 82*3706af42SArnaud Ysmal uint32_t 83*3706af42SArnaud Ysmal p2sb_port_read_4(device_t dev, uint8_t port, uint32_t reg) 84*3706af42SArnaud Ysmal { 85*3706af42SArnaud Ysmal struct p2sb_softc *sc; 86*3706af42SArnaud Ysmal 87*3706af42SArnaud Ysmal KASSERT(reg < (1<<P2SB_PORT2ADDRESS_SHIFT), ("register out of port")); 88*3706af42SArnaud Ysmal sc = device_get_softc(dev); 89*3706af42SArnaud Ysmal return (bus_read_4(sc->res, P2SB_PORT_ADDRESS(port) + reg)); 90*3706af42SArnaud Ysmal } 91*3706af42SArnaud Ysmal 92*3706af42SArnaud Ysmal void 93*3706af42SArnaud Ysmal p2sb_port_write_4(device_t dev, uint8_t port, uint32_t reg, uint32_t val) 94*3706af42SArnaud Ysmal { 95*3706af42SArnaud Ysmal struct p2sb_softc *sc; 96*3706af42SArnaud Ysmal 97*3706af42SArnaud Ysmal KASSERT(reg < (1<<P2SB_PORT2ADDRESS_SHIFT), ("register out of port")); 98*3706af42SArnaud Ysmal sc = device_get_softc(dev); 99*3706af42SArnaud Ysmal bus_write_4(sc->res, P2SB_PORT_ADDRESS(port) + reg, val); 100*3706af42SArnaud Ysmal } 101*3706af42SArnaud Ysmal 102*3706af42SArnaud Ysmal void 103*3706af42SArnaud Ysmal p2sb_lock(device_t dev) 104*3706af42SArnaud Ysmal { 105*3706af42SArnaud Ysmal struct p2sb_softc *sc; 106*3706af42SArnaud Ysmal 107*3706af42SArnaud Ysmal sc = device_get_softc(dev); 108*3706af42SArnaud Ysmal mtx_lock_spin(&sc->mutex); 109*3706af42SArnaud Ysmal } 110*3706af42SArnaud Ysmal 111*3706af42SArnaud Ysmal void 112*3706af42SArnaud Ysmal p2sb_unlock(device_t dev) 113*3706af42SArnaud Ysmal { 114*3706af42SArnaud Ysmal struct p2sb_softc *sc; 115*3706af42SArnaud Ysmal 116*3706af42SArnaud Ysmal sc = device_get_softc(dev); 117*3706af42SArnaud Ysmal mtx_unlock_spin(&sc->mutex); 118*3706af42SArnaud Ysmal } 119*3706af42SArnaud Ysmal 120*3706af42SArnaud Ysmal 121*3706af42SArnaud Ysmal static int 122*3706af42SArnaud Ysmal p2sb_probe(device_t dev) 123*3706af42SArnaud Ysmal { 124*3706af42SArnaud Ysmal 125*3706af42SArnaud Ysmal if (pci_get_devid(dev) == PCI_PRODUCT_LEWISBURG_P2SB) { 126*3706af42SArnaud Ysmal device_set_desc(dev, "Lewisburg P2SB"); 127*3706af42SArnaud Ysmal return (BUS_PROBE_DEFAULT); 128*3706af42SArnaud Ysmal } 129*3706af42SArnaud Ysmal return (ENXIO); 130*3706af42SArnaud Ysmal } 131*3706af42SArnaud Ysmal 132*3706af42SArnaud Ysmal /* Attach function is only called if the probe is successful. */ 133*3706af42SArnaud Ysmal 134*3706af42SArnaud Ysmal static int 135*3706af42SArnaud Ysmal p2sb_attach(device_t dev) 136*3706af42SArnaud Ysmal { 137*3706af42SArnaud Ysmal struct p2sb_softc *sc; 138*3706af42SArnaud Ysmal int i; 139*3706af42SArnaud Ysmal 140*3706af42SArnaud Ysmal sc = device_get_softc(dev); 141*3706af42SArnaud Ysmal sc->dev = dev; 142*3706af42SArnaud Ysmal sc->rid = PCIR_BAR(0); 143*3706af42SArnaud Ysmal sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->rid, RF_ACTIVE); 144*3706af42SArnaud Ysmal if (sc->res == NULL) { 145*3706af42SArnaud Ysmal device_printf(dev, "Could not allocate memory.\n"); 146*3706af42SArnaud Ysmal return (ENXIO); 147*3706af42SArnaud Ysmal } 148*3706af42SArnaud Ysmal mtx_init(&sc->mutex, device_get_nameunit(dev), NULL, MTX_SPIN); 149*3706af42SArnaud Ysmal for (i = 0; i < nitems(lbg_communities); ++i) 150*3706af42SArnaud Ysmal device_add_child(dev, "lbggpiocm", i); 151*3706af42SArnaud Ysmal 152*3706af42SArnaud Ysmal return (bus_generic_attach(dev)); 153*3706af42SArnaud Ysmal } 154*3706af42SArnaud Ysmal 155*3706af42SArnaud Ysmal /* Detach device. */ 156*3706af42SArnaud Ysmal 157*3706af42SArnaud Ysmal static int 158*3706af42SArnaud Ysmal p2sb_detach(device_t dev) 159*3706af42SArnaud Ysmal { 160*3706af42SArnaud Ysmal struct p2sb_softc *sc; 161*3706af42SArnaud Ysmal 162*3706af42SArnaud Ysmal /* Teardown the state in our softc created in our attach routine. */ 163*3706af42SArnaud Ysmal device_delete_children(dev); 164*3706af42SArnaud Ysmal sc = device_get_softc(dev); 165*3706af42SArnaud Ysmal mtx_destroy(&sc->mutex); 166*3706af42SArnaud Ysmal if (sc->res != NULL) 167*3706af42SArnaud Ysmal bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res); 168*3706af42SArnaud Ysmal return (0); 169*3706af42SArnaud Ysmal } 170*3706af42SArnaud Ysmal 171*3706af42SArnaud Ysmal /* Called during system shutdown after sync. */ 172*3706af42SArnaud Ysmal 173*3706af42SArnaud Ysmal static int 174*3706af42SArnaud Ysmal p2sb_shutdown(device_t dev) 175*3706af42SArnaud Ysmal { 176*3706af42SArnaud Ysmal 177*3706af42SArnaud Ysmal return (0); 178*3706af42SArnaud Ysmal } 179*3706af42SArnaud Ysmal 180*3706af42SArnaud Ysmal /* 181*3706af42SArnaud Ysmal * Device suspend routine. 182*3706af42SArnaud Ysmal */ 183*3706af42SArnaud Ysmal static int 184*3706af42SArnaud Ysmal p2sb_suspend(device_t dev) 185*3706af42SArnaud Ysmal { 186*3706af42SArnaud Ysmal 187*3706af42SArnaud Ysmal return (0); 188*3706af42SArnaud Ysmal } 189*3706af42SArnaud Ysmal 190*3706af42SArnaud Ysmal /* 191*3706af42SArnaud Ysmal * Device resume routine. 192*3706af42SArnaud Ysmal */ 193*3706af42SArnaud Ysmal static int 194*3706af42SArnaud Ysmal p2sb_resume(device_t dev) 195*3706af42SArnaud Ysmal { 196*3706af42SArnaud Ysmal 197*3706af42SArnaud Ysmal return (0); 198*3706af42SArnaud Ysmal } 199*3706af42SArnaud Ysmal 200*3706af42SArnaud Ysmal static device_method_t p2sb_methods[] = { 201*3706af42SArnaud Ysmal /* Device interface */ 202*3706af42SArnaud Ysmal DEVMETHOD(device_probe, p2sb_probe), 203*3706af42SArnaud Ysmal DEVMETHOD(device_attach, p2sb_attach), 204*3706af42SArnaud Ysmal DEVMETHOD(device_detach, p2sb_detach), 205*3706af42SArnaud Ysmal DEVMETHOD(device_shutdown, p2sb_shutdown), 206*3706af42SArnaud Ysmal DEVMETHOD(device_suspend, p2sb_suspend), 207*3706af42SArnaud Ysmal DEVMETHOD(device_resume, p2sb_resume), 208*3706af42SArnaud Ysmal 209*3706af42SArnaud Ysmal DEVMETHOD_END 210*3706af42SArnaud Ysmal }; 211*3706af42SArnaud Ysmal 212*3706af42SArnaud Ysmal static devclass_t p2sb_devclass; 213*3706af42SArnaud Ysmal 214*3706af42SArnaud Ysmal DEFINE_CLASS_0(p2sb, p2sb_driver, p2sb_methods, sizeof(struct p2sb_softc)); 215*3706af42SArnaud Ysmal DRIVER_MODULE(p2sb, pci, p2sb_driver, p2sb_devclass, 0, 0); 216