1907f50feSConrad Meyer /*- 25b505170SConrad Meyer * Copyright (c) 2017-2020 Conrad Meyer <cem@FreeBSD.org> 3907f50feSConrad Meyer * All rights reserved. 4907f50feSConrad Meyer * 5907f50feSConrad Meyer * Redistribution and use in source and binary forms, with or without 6907f50feSConrad Meyer * modification, are permitted provided that the following conditions 7907f50feSConrad Meyer * are met: 8907f50feSConrad Meyer * 1. Redistributions of source code must retain the above copyright 9907f50feSConrad Meyer * notice, this list of conditions and the following disclaimer. 10907f50feSConrad Meyer * 2. Redistributions in binary form must reproduce the above copyright 11907f50feSConrad Meyer * notice, this list of conditions and the following disclaimer in the 12907f50feSConrad Meyer * documentation and/or other materials provided with the distribution. 13907f50feSConrad Meyer * 14907f50feSConrad Meyer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15907f50feSConrad Meyer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16907f50feSConrad Meyer * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17907f50feSConrad Meyer * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 18907f50feSConrad Meyer * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19907f50feSConrad Meyer * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20907f50feSConrad Meyer * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21907f50feSConrad Meyer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22907f50feSConrad Meyer * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 23907f50feSConrad Meyer * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24907f50feSConrad Meyer * POSSIBILITY OF SUCH DAMAGE. 25907f50feSConrad Meyer */ 26907f50feSConrad Meyer 27907f50feSConrad Meyer /* 28e49ec461SConrad Meyer * Driver for the AMD Family 15h and 17h CPU System Management Network. 29907f50feSConrad Meyer */ 30907f50feSConrad Meyer 31907f50feSConrad Meyer #include <sys/param.h> 32907f50feSConrad Meyer #include <sys/bus.h> 33907f50feSConrad Meyer #include <sys/conf.h> 34907f50feSConrad Meyer #include <sys/lock.h> 35907f50feSConrad Meyer #include <sys/kernel.h> 36907f50feSConrad Meyer #include <sys/module.h> 37907f50feSConrad Meyer #include <sys/mutex.h> 38907f50feSConrad Meyer #include <sys/sysctl.h> 39907f50feSConrad Meyer #include <sys/systm.h> 40907f50feSConrad Meyer 41907f50feSConrad Meyer #include <machine/cpufunc.h> 429d49c422SConrad Meyer #include <machine/cputypes.h> 43907f50feSConrad Meyer #include <machine/md_var.h> 44907f50feSConrad Meyer #include <machine/specialreg.h> 45907f50feSConrad Meyer 46907f50feSConrad Meyer #include <dev/pci/pcivar.h> 47907f50feSConrad Meyer #include <x86/pci_cfgreg.h> 48907f50feSConrad Meyer 49907f50feSConrad Meyer #include <dev/amdsmn/amdsmn.h> 50907f50feSConrad Meyer 51e49ec461SConrad Meyer #define F15H_SMN_ADDR_REG 0xb8 52e49ec461SConrad Meyer #define F15H_SMN_DATA_REG 0xbc 53e49ec461SConrad Meyer #define F17H_SMN_ADDR_REG 0x60 54e49ec461SConrad Meyer #define F17H_SMN_DATA_REG 0x64 55907f50feSConrad Meyer 56e49ec461SConrad Meyer #define PCI_DEVICE_ID_AMD_15H_M60H_ROOT 0x1576 579d49c422SConrad Meyer #define PCI_DEVICE_ID_AMD_17H_ROOT 0x1450 589d49c422SConrad Meyer #define PCI_DEVICE_ID_AMD_17H_M10H_ROOT 0x15d0 59ea6189d3SConrad Meyer #define PCI_DEVICE_ID_AMD_17H_M30H_ROOT 0x1480 /* Also M70H, F19H M00H/M20H */ 607aa6eeb2SSimon Wells #define PCI_DEVICE_ID_AMD_17H_M60H_ROOT 0x1630 /* Also F19H M50H */ 6151c69c86SXin LI #define PCI_DEVICE_ID_AMD_19H_M10H_ROOT 0x14a4 62a76e28d1SMatthias Lanter #define PCI_DEVICE_ID_AMD_19H_M40H_ROOT 0x14b5 63*a9a71513SSimon Wells #define PCI_DEVICE_ID_AMD_19H_M60H_ROOT 0x14d8 /* Also F1AH M40H */ 64ef3f8aa0SOliver Fromme #define PCI_DEVICE_ID_AMD_19H_M70H_ROOT 0x14e8 659d49c422SConrad Meyer 66e49ec461SConrad Meyer struct pciid; 67907f50feSConrad Meyer struct amdsmn_softc { 68907f50feSConrad Meyer struct mtx smn_lock; 69e49ec461SConrad Meyer const struct pciid *smn_pciid; 70907f50feSConrad Meyer }; 71907f50feSConrad Meyer 72e49ec461SConrad Meyer static const struct pciid { 739d49c422SConrad Meyer uint16_t amdsmn_vendorid; 749d49c422SConrad Meyer uint16_t amdsmn_deviceid; 75e49ec461SConrad Meyer uint8_t amdsmn_addr_reg; 76e49ec461SConrad Meyer uint8_t amdsmn_data_reg; 77907f50feSConrad Meyer } amdsmn_ids[] = { 78e49ec461SConrad Meyer { 79e49ec461SConrad Meyer .amdsmn_vendorid = CPU_VENDOR_AMD, 80e49ec461SConrad Meyer .amdsmn_deviceid = PCI_DEVICE_ID_AMD_15H_M60H_ROOT, 81e49ec461SConrad Meyer .amdsmn_addr_reg = F15H_SMN_ADDR_REG, 82e49ec461SConrad Meyer .amdsmn_data_reg = F15H_SMN_DATA_REG, 83e49ec461SConrad Meyer }, 84e49ec461SConrad Meyer { 85e49ec461SConrad Meyer .amdsmn_vendorid = CPU_VENDOR_AMD, 86e49ec461SConrad Meyer .amdsmn_deviceid = PCI_DEVICE_ID_AMD_17H_ROOT, 87e49ec461SConrad Meyer .amdsmn_addr_reg = F17H_SMN_ADDR_REG, 88e49ec461SConrad Meyer .amdsmn_data_reg = F17H_SMN_DATA_REG, 89e49ec461SConrad Meyer }, 90e49ec461SConrad Meyer { 91e49ec461SConrad Meyer .amdsmn_vendorid = CPU_VENDOR_AMD, 92e49ec461SConrad Meyer .amdsmn_deviceid = PCI_DEVICE_ID_AMD_17H_M10H_ROOT, 93e49ec461SConrad Meyer .amdsmn_addr_reg = F17H_SMN_ADDR_REG, 94e49ec461SConrad Meyer .amdsmn_data_reg = F17H_SMN_DATA_REG, 95e49ec461SConrad Meyer }, 9685dbddbeSConrad Meyer { 9785dbddbeSConrad Meyer .amdsmn_vendorid = CPU_VENDOR_AMD, 9885dbddbeSConrad Meyer .amdsmn_deviceid = PCI_DEVICE_ID_AMD_17H_M30H_ROOT, 9985dbddbeSConrad Meyer .amdsmn_addr_reg = F17H_SMN_ADDR_REG, 10085dbddbeSConrad Meyer .amdsmn_data_reg = F17H_SMN_DATA_REG, 10185dbddbeSConrad Meyer }, 1025b505170SConrad Meyer { 1035b505170SConrad Meyer .amdsmn_vendorid = CPU_VENDOR_AMD, 1045b505170SConrad Meyer .amdsmn_deviceid = PCI_DEVICE_ID_AMD_17H_M60H_ROOT, 1055b505170SConrad Meyer .amdsmn_addr_reg = F17H_SMN_ADDR_REG, 1065b505170SConrad Meyer .amdsmn_data_reg = F17H_SMN_DATA_REG, 1075b505170SConrad Meyer }, 108323a94afSAkio Morita { 109323a94afSAkio Morita .amdsmn_vendorid = CPU_VENDOR_AMD, 11051c69c86SXin LI .amdsmn_deviceid = PCI_DEVICE_ID_AMD_19H_M10H_ROOT, 11151c69c86SXin LI .amdsmn_addr_reg = F17H_SMN_ADDR_REG, 11251c69c86SXin LI .amdsmn_data_reg = F17H_SMN_DATA_REG, 11351c69c86SXin LI }, 11451c69c86SXin LI { 11551c69c86SXin LI .amdsmn_vendorid = CPU_VENDOR_AMD, 116a76e28d1SMatthias Lanter .amdsmn_deviceid = PCI_DEVICE_ID_AMD_19H_M40H_ROOT, 117a76e28d1SMatthias Lanter .amdsmn_addr_reg = F17H_SMN_ADDR_REG, 118a76e28d1SMatthias Lanter .amdsmn_data_reg = F17H_SMN_DATA_REG, 119a76e28d1SMatthias Lanter }, 120a76e28d1SMatthias Lanter { 121a76e28d1SMatthias Lanter .amdsmn_vendorid = CPU_VENDOR_AMD, 122323a94afSAkio Morita .amdsmn_deviceid = PCI_DEVICE_ID_AMD_19H_M60H_ROOT, 123323a94afSAkio Morita .amdsmn_addr_reg = F17H_SMN_ADDR_REG, 124323a94afSAkio Morita .amdsmn_data_reg = F17H_SMN_DATA_REG, 125323a94afSAkio Morita }, 126ef3f8aa0SOliver Fromme { 127ef3f8aa0SOliver Fromme .amdsmn_vendorid = CPU_VENDOR_AMD, 128ef3f8aa0SOliver Fromme .amdsmn_deviceid = PCI_DEVICE_ID_AMD_19H_M70H_ROOT, 129ef3f8aa0SOliver Fromme .amdsmn_addr_reg = F17H_SMN_ADDR_REG, 130ef3f8aa0SOliver Fromme .amdsmn_data_reg = F17H_SMN_DATA_REG, 131ef3f8aa0SOliver Fromme }, 132907f50feSConrad Meyer }; 133907f50feSConrad Meyer 134907f50feSConrad Meyer /* 135907f50feSConrad Meyer * Device methods. 136907f50feSConrad Meyer */ 137907f50feSConrad Meyer static void amdsmn_identify(driver_t *driver, device_t parent); 138907f50feSConrad Meyer static int amdsmn_probe(device_t dev); 139907f50feSConrad Meyer static int amdsmn_attach(device_t dev); 140907f50feSConrad Meyer static int amdsmn_detach(device_t dev); 141907f50feSConrad Meyer 142907f50feSConrad Meyer static device_method_t amdsmn_methods[] = { 143907f50feSConrad Meyer /* Device interface */ 144907f50feSConrad Meyer DEVMETHOD(device_identify, amdsmn_identify), 145907f50feSConrad Meyer DEVMETHOD(device_probe, amdsmn_probe), 146907f50feSConrad Meyer DEVMETHOD(device_attach, amdsmn_attach), 147907f50feSConrad Meyer DEVMETHOD(device_detach, amdsmn_detach), 148907f50feSConrad Meyer DEVMETHOD_END 149907f50feSConrad Meyer }; 150907f50feSConrad Meyer 151907f50feSConrad Meyer static driver_t amdsmn_driver = { 152907f50feSConrad Meyer "amdsmn", 153907f50feSConrad Meyer amdsmn_methods, 154907f50feSConrad Meyer sizeof(struct amdsmn_softc), 155907f50feSConrad Meyer }; 156907f50feSConrad Meyer 15783a273efSJohn Baldwin DRIVER_MODULE(amdsmn, hostb, amdsmn_driver, NULL, NULL); 158907f50feSConrad Meyer MODULE_VERSION(amdsmn, 1); 1599d49c422SConrad Meyer MODULE_PNP_INFO("U16:vendor;U16:device", pci, amdsmn, amdsmn_ids, 160329e817fSWarner Losh nitems(amdsmn_ids)); 161907f50feSConrad Meyer 1621b93938aSConrad Meyer static bool 163e49ec461SConrad Meyer amdsmn_match(device_t parent, const struct pciid **pciid_out) 164907f50feSConrad Meyer { 1659d49c422SConrad Meyer uint16_t vendor, device; 166907f50feSConrad Meyer size_t i; 167907f50feSConrad Meyer 1689d49c422SConrad Meyer vendor = pci_get_vendor(parent); 1699d49c422SConrad Meyer device = pci_get_device(parent); 1709d49c422SConrad Meyer 171e49ec461SConrad Meyer for (i = 0; i < nitems(amdsmn_ids); i++) { 1729d49c422SConrad Meyer if (vendor == amdsmn_ids[i].amdsmn_vendorid && 173e49ec461SConrad Meyer device == amdsmn_ids[i].amdsmn_deviceid) { 174e49ec461SConrad Meyer if (pciid_out != NULL) 175e49ec461SConrad Meyer *pciid_out = &amdsmn_ids[i]; 1761b93938aSConrad Meyer return (true); 177e49ec461SConrad Meyer } 178e49ec461SConrad Meyer } 1791b93938aSConrad Meyer return (false); 1801b93938aSConrad Meyer } 181907f50feSConrad Meyer 1821b93938aSConrad Meyer static void 1831b93938aSConrad Meyer amdsmn_identify(driver_t *driver, device_t parent) 1841b93938aSConrad Meyer { 1851b93938aSConrad Meyer device_t child; 1861b93938aSConrad Meyer 1871b93938aSConrad Meyer /* Make sure we're not being doubly invoked. */ 1881b93938aSConrad Meyer if (device_find_child(parent, "amdsmn", -1) != NULL) 1891b93938aSConrad Meyer return; 190e49ec461SConrad Meyer if (!amdsmn_match(parent, NULL)) 191907f50feSConrad Meyer return; 192907f50feSConrad Meyer 1935b56413dSWarner Losh child = device_add_child(parent, "amdsmn", DEVICE_UNIT_ANY); 194907f50feSConrad Meyer if (child == NULL) 195907f50feSConrad Meyer device_printf(parent, "add amdsmn child failed\n"); 196907f50feSConrad Meyer } 197907f50feSConrad Meyer 198907f50feSConrad Meyer static int 199907f50feSConrad Meyer amdsmn_probe(device_t dev) 200907f50feSConrad Meyer { 201907f50feSConrad Meyer uint32_t family; 202907f50feSConrad Meyer 203907f50feSConrad Meyer if (resource_disabled("amdsmn", 0)) 204907f50feSConrad Meyer return (ENXIO); 205e49ec461SConrad Meyer if (!amdsmn_match(device_get_parent(dev), NULL)) 2061b93938aSConrad Meyer return (ENXIO); 207907f50feSConrad Meyer 208907f50feSConrad Meyer family = CPUID_TO_FAMILY(cpu_id); 209907f50feSConrad Meyer 210907f50feSConrad Meyer switch (family) { 211e49ec461SConrad Meyer case 0x15: 212907f50feSConrad Meyer case 0x17: 213ea6189d3SConrad Meyer case 0x19: 214*a9a71513SSimon Wells case 0x1a: 215907f50feSConrad Meyer break; 216907f50feSConrad Meyer default: 217907f50feSConrad Meyer return (ENXIO); 218907f50feSConrad Meyer } 21948ef9cffSMark Johnston device_set_descf(dev, "AMD Family %xh System Management Network", 220e49ec461SConrad Meyer family); 221907f50feSConrad Meyer 222907f50feSConrad Meyer return (BUS_PROBE_GENERIC); 223907f50feSConrad Meyer } 224907f50feSConrad Meyer 225907f50feSConrad Meyer static int 226907f50feSConrad Meyer amdsmn_attach(device_t dev) 227907f50feSConrad Meyer { 228907f50feSConrad Meyer struct amdsmn_softc *sc = device_get_softc(dev); 229907f50feSConrad Meyer 230e49ec461SConrad Meyer if (!amdsmn_match(device_get_parent(dev), &sc->smn_pciid)) 231e49ec461SConrad Meyer return (ENXIO); 232e49ec461SConrad Meyer 233907f50feSConrad Meyer mtx_init(&sc->smn_lock, "SMN mtx", "SMN", MTX_DEF); 234907f50feSConrad Meyer return (0); 235907f50feSConrad Meyer } 236907f50feSConrad Meyer 237907f50feSConrad Meyer int 238907f50feSConrad Meyer amdsmn_detach(device_t dev) 239907f50feSConrad Meyer { 240907f50feSConrad Meyer struct amdsmn_softc *sc = device_get_softc(dev); 241907f50feSConrad Meyer 242907f50feSConrad Meyer mtx_destroy(&sc->smn_lock); 243907f50feSConrad Meyer return (0); 244907f50feSConrad Meyer } 245907f50feSConrad Meyer 246907f50feSConrad Meyer int 247907f50feSConrad Meyer amdsmn_read(device_t dev, uint32_t addr, uint32_t *value) 248907f50feSConrad Meyer { 249907f50feSConrad Meyer struct amdsmn_softc *sc = device_get_softc(dev); 250907f50feSConrad Meyer device_t parent; 251907f50feSConrad Meyer 252907f50feSConrad Meyer parent = device_get_parent(dev); 253907f50feSConrad Meyer 254907f50feSConrad Meyer mtx_lock(&sc->smn_lock); 255e49ec461SConrad Meyer pci_write_config(parent, sc->smn_pciid->amdsmn_addr_reg, addr, 4); 256e49ec461SConrad Meyer *value = pci_read_config(parent, sc->smn_pciid->amdsmn_data_reg, 4); 257907f50feSConrad Meyer mtx_unlock(&sc->smn_lock); 258907f50feSConrad Meyer 259907f50feSConrad Meyer return (0); 260907f50feSConrad Meyer } 261907f50feSConrad Meyer 262907f50feSConrad Meyer int 263907f50feSConrad Meyer amdsmn_write(device_t dev, uint32_t addr, uint32_t value) 264907f50feSConrad Meyer { 265907f50feSConrad Meyer struct amdsmn_softc *sc = device_get_softc(dev); 266907f50feSConrad Meyer device_t parent; 267907f50feSConrad Meyer 268907f50feSConrad Meyer parent = device_get_parent(dev); 269907f50feSConrad Meyer 270907f50feSConrad Meyer mtx_lock(&sc->smn_lock); 271e49ec461SConrad Meyer pci_write_config(parent, sc->smn_pciid->amdsmn_addr_reg, addr, 4); 272e49ec461SConrad Meyer pci_write_config(parent, sc->smn_pciid->amdsmn_data_reg, value, 4); 273907f50feSConrad Meyer mtx_unlock(&sc->smn_lock); 274907f50feSConrad Meyer 275907f50feSConrad Meyer return (0); 276907f50feSConrad Meyer } 277