1*ea402bb6Smsaitoh /* $NetBSD: amdsmn.c,v 1.18 2024/10/17 14:02:40 msaitoh Exp $ */ 23a74451dSchristos 33a74451dSchristos /*- 4f90792d2Ssimonb * Copyright (c) 2017, 2019 Conrad Meyer <cem@FreeBSD.org> 53a74451dSchristos * All rights reserved. 63a74451dSchristos * 73a74451dSchristos * NetBSD port by Ian Clark <mrrooster@gmail.com> 83a74451dSchristos * 93a74451dSchristos * Redistribution and use in source and binary forms, with or without 103a74451dSchristos * modification, are permitted provided that the following conditions 113a74451dSchristos * are met: 123a74451dSchristos * 1. Redistributions of source code must retain the above copyright 133a74451dSchristos * notice, this list of conditions and the following disclaimer. 143a74451dSchristos * 2. Redistributions in binary form must reproduce the above copyright 153a74451dSchristos * notice, this list of conditions and the following disclaimer in the 163a74451dSchristos * documentation and/or other materials provided with the distribution. 173a74451dSchristos * 183a74451dSchristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 193a74451dSchristos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 203a74451dSchristos * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 213a74451dSchristos * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 223a74451dSchristos * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 233a74451dSchristos * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 243a74451dSchristos * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 253a74451dSchristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 263a74451dSchristos * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 273a74451dSchristos * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 283a74451dSchristos * POSSIBILITY OF SUCH DAMAGE. 293a74451dSchristos */ 303a74451dSchristos 313a74451dSchristos #include <sys/cdefs.h> 32*ea402bb6Smsaitoh __KERNEL_RCSID(0, "$NetBSD: amdsmn.c,v 1.18 2024/10/17 14:02:40 msaitoh Exp $ "); 333a74451dSchristos 343a74451dSchristos /* 35f90792d2Ssimonb * Driver for the AMD Family 15h (model 60+) and 17h CPU 36f90792d2Ssimonb * System Management Network. 373a74451dSchristos */ 383a74451dSchristos 393a74451dSchristos #include <sys/param.h> 403a74451dSchristos #include <sys/device.h> 413a74451dSchristos #include <sys/errno.h> 423a74451dSchristos #include <sys/mutex.h> 433a74451dSchristos #include <sys/systm.h> 443a74451dSchristos #include <sys/cpu.h> 45a63689b9Spgoyette #include <sys/module.h> 463a74451dSchristos 473a74451dSchristos #include <machine/specialreg.h> 483a74451dSchristos 493a74451dSchristos #include <dev/pci/pcireg.h> 503a74451dSchristos #include <dev/pci/pcivar.h> 513a74451dSchristos #include <dev/pci/pcidevs.h> 523a74451dSchristos 533a74451dSchristos #include "amdsmn.h" 54a63689b9Spgoyette #include "ioconf.h" 553a74451dSchristos 56f90792d2Ssimonb #define F15H_SMN_ADDR_REG 0xb8 57f90792d2Ssimonb #define F15H_SMN_DATA_REG 0xbc 58f90792d2Ssimonb #define F17H_SMN_ADDR_REG 0x60 59f90792d2Ssimonb #define F17H_SMN_DATA_REG 0x64 603a74451dSchristos 613a74451dSchristos struct amdsmn_softc { 623a74451dSchristos kmutex_t smn_lock; 63f90792d2Ssimonb uint8_t smn_addr_reg; 64f90792d2Ssimonb uint8_t smn_data_reg; 653a74451dSchristos struct pci_attach_args pa; 663a74451dSchristos pci_chipset_tag_t pc; 673a74451dSchristos pcitag_t pcitag; 683a74451dSchristos }; 693a74451dSchristos 7036bfd4aaSmsaitoh static const struct pciid { 7136bfd4aaSmsaitoh uint16_t amdsmn_deviceid; 72f90792d2Ssimonb uint8_t amdsmn_addr_reg; 73f90792d2Ssimonb uint8_t amdsmn_data_reg; 7436bfd4aaSmsaitoh } amdsmn_ids[] = { 75f90792d2Ssimonb { 76da271569Smsaitoh .amdsmn_deviceid = PCI_PRODUCT_AMD_F15_6X_RC, 77f90792d2Ssimonb .amdsmn_addr_reg = F15H_SMN_ADDR_REG, 78f90792d2Ssimonb .amdsmn_data_reg = F15H_SMN_DATA_REG, 79f90792d2Ssimonb }, 80f90792d2Ssimonb { 81f90792d2Ssimonb .amdsmn_deviceid = PCI_PRODUCT_AMD_F17_RC, 82f90792d2Ssimonb .amdsmn_addr_reg = F17H_SMN_ADDR_REG, 83f90792d2Ssimonb .amdsmn_data_reg = F17H_SMN_DATA_REG, 84f90792d2Ssimonb }, 85f90792d2Ssimonb { 86f90792d2Ssimonb .amdsmn_deviceid = PCI_PRODUCT_AMD_F17_1X_RC, 87f90792d2Ssimonb .amdsmn_addr_reg = F17H_SMN_ADDR_REG, 88f90792d2Ssimonb .amdsmn_data_reg = F17H_SMN_DATA_REG, 89f90792d2Ssimonb }, 90f90792d2Ssimonb { 9108e27227Smsaitoh .amdsmn_deviceid = PCI_PRODUCT_AMD_F17_6X_RC, 9208e27227Smsaitoh .amdsmn_addr_reg = F17H_SMN_ADDR_REG, 9308e27227Smsaitoh .amdsmn_data_reg = F17H_SMN_DATA_REG, 9408e27227Smsaitoh }, 9508e27227Smsaitoh { 9697018bdaSmsaitoh .amdsmn_deviceid = PCI_PRODUCT_AMD_F17_7X_RC, /* or F19_0X */ 9797018bdaSmsaitoh .amdsmn_addr_reg = F17H_SMN_ADDR_REG, 9897018bdaSmsaitoh .amdsmn_data_reg = F17H_SMN_DATA_REG, 9997018bdaSmsaitoh }, 10097018bdaSmsaitoh { 10197018bdaSmsaitoh .amdsmn_deviceid = PCI_PRODUCT_AMD_F17_AX_RC, /* or F19_4X */ 10297018bdaSmsaitoh .amdsmn_addr_reg = F17H_SMN_ADDR_REG, 10397018bdaSmsaitoh .amdsmn_data_reg = F17H_SMN_DATA_REG, 10497018bdaSmsaitoh }, 10597018bdaSmsaitoh { 10697018bdaSmsaitoh .amdsmn_deviceid = PCI_PRODUCT_AMD_F19_1X_RC, 107f90792d2Ssimonb .amdsmn_addr_reg = F17H_SMN_ADDR_REG, 108f90792d2Ssimonb .amdsmn_data_reg = F17H_SMN_DATA_REG, 109f90792d2Ssimonb }, 11008e27227Smsaitoh { 11108e27227Smsaitoh .amdsmn_deviceid = PCI_PRODUCT_AMD_F19_6X_RC, 11208e27227Smsaitoh .amdsmn_addr_reg = F17H_SMN_ADDR_REG, 11308e27227Smsaitoh .amdsmn_data_reg = F17H_SMN_DATA_REG, 11408e27227Smsaitoh }, 1151b9c9e4eSmsaitoh { 1161b9c9e4eSmsaitoh .amdsmn_deviceid = PCI_PRODUCT_AMD_F19_7X_RC, 1171b9c9e4eSmsaitoh .amdsmn_addr_reg = F17H_SMN_ADDR_REG, 1181b9c9e4eSmsaitoh .amdsmn_data_reg = F17H_SMN_DATA_REG, 1191b9c9e4eSmsaitoh }, 120*ea402bb6Smsaitoh { 121*ea402bb6Smsaitoh .amdsmn_deviceid = PCI_PRODUCT_AMD_F1A_0X_RC, 122*ea402bb6Smsaitoh .amdsmn_addr_reg = F17H_SMN_ADDR_REG, 123*ea402bb6Smsaitoh .amdsmn_data_reg = F17H_SMN_DATA_REG, 124*ea402bb6Smsaitoh }, 12536bfd4aaSmsaitoh }; 12636bfd4aaSmsaitoh 1273a74451dSchristos static int amdsmn_match(device_t, cfdata_t, void *); 1283a74451dSchristos static void amdsmn_attach(device_t, device_t, void *); 129a63689b9Spgoyette static int amdsmn_rescan(device_t, const char *, const int *); 1303a74451dSchristos static int amdsmn_detach(device_t, int); 1313a74451dSchristos static int amdsmn_misc_search(device_t, cfdata_t, const int *, void *); 1323a74451dSchristos 133a63689b9Spgoyette CFATTACH_DECL3_NEW(amdsmn, sizeof(struct amdsmn_softc), amdsmn_match, 134a63689b9Spgoyette amdsmn_attach, amdsmn_detach, NULL, amdsmn_rescan, NULL, 0); 1353a74451dSchristos 1363a74451dSchristos static int 1373a74451dSchristos amdsmn_match(device_t parent, cfdata_t match, void *aux) 1383a74451dSchristos { 1393a74451dSchristos struct pci_attach_args *pa = aux; 1406a4a55b0Ssimonb size_t i; 1413a74451dSchristos 14236bfd4aaSmsaitoh if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_AMD) 14336bfd4aaSmsaitoh return 0; 14436bfd4aaSmsaitoh 14536bfd4aaSmsaitoh for (i = 0; i < __arraycount(amdsmn_ids); i++) 14636bfd4aaSmsaitoh if (PCI_PRODUCT(pa->pa_id) == amdsmn_ids[i].amdsmn_deviceid) 14736bfd4aaSmsaitoh return 2; 14836bfd4aaSmsaitoh 14936bfd4aaSmsaitoh return 0; 1503a74451dSchristos } 1513a74451dSchristos 1523a74451dSchristos static int 1533a74451dSchristos amdsmn_misc_search(device_t parent, cfdata_t cf, const int *locs, void *aux) 1543a74451dSchristos { 1552685996bSthorpej if (config_probe(parent, cf, aux)) 1562685996bSthorpej config_attach(parent, cf, aux, NULL, 157c7fb772bSthorpej CFARGS(.locators = locs)); 1583a74451dSchristos 1593a74451dSchristos return 0; 1603a74451dSchristos } 1613a74451dSchristos 1623a74451dSchristos static void 1633a74451dSchristos amdsmn_attach(device_t parent, device_t self, void *aux) 1643a74451dSchristos { 1653a74451dSchristos struct amdsmn_softc *sc = device_private(self); 1663a74451dSchristos struct pci_attach_args *pa = aux; 167991d71a7Sjoerg size_t i; 1683a74451dSchristos 1693a74451dSchristos mutex_init(&sc->smn_lock, MUTEX_DEFAULT, IPL_NONE); 1703a74451dSchristos sc->pa = *pa; 1713a74451dSchristos sc->pc = pa->pa_pc; 1723a74451dSchristos sc->pcitag = pa->pa_tag; 173f90792d2Ssimonb 174f90792d2Ssimonb for (i = 0; i < __arraycount(amdsmn_ids); i++) 175f90792d2Ssimonb if (PCI_PRODUCT(pa->pa_id) == amdsmn_ids[i].amdsmn_deviceid) { 176f90792d2Ssimonb sc->smn_addr_reg = amdsmn_ids[i].amdsmn_addr_reg; 177f90792d2Ssimonb sc->smn_data_reg = amdsmn_ids[i].amdsmn_data_reg; 178f90792d2Ssimonb } 179f90792d2Ssimonb 180f90792d2Ssimonb // aprint_normal(": AMD Family 17h System Management Network\n"); 181f90792d2Ssimonb aprint_normal(": AMD System Management Network\n"); 18222a97c46Sreinoud 18322a97c46Sreinoud pmf_device_register(self, NULL, NULL); 1842685996bSthorpej amdsmn_rescan(self, NULL, NULL); 185a63689b9Spgoyette } 186a63689b9Spgoyette 187a63689b9Spgoyette static int 1882685996bSthorpej amdsmn_rescan(device_t self, const char *ifattr, const int *locators) 189a63689b9Spgoyette { 190a63689b9Spgoyette struct amdsmn_softc *sc = device_private(self); 191a63689b9Spgoyette 1922685996bSthorpej config_search(self, &sc->pa, 193c7fb772bSthorpej CFARGS(.search = amdsmn_misc_search)); 194a63689b9Spgoyette 195a63689b9Spgoyette return 0; 1963a74451dSchristos } 1973a74451dSchristos 1983a74451dSchristos static int 1993a74451dSchristos amdsmn_detach(device_t self, int flags) 2003a74451dSchristos { 2013a74451dSchristos struct amdsmn_softc *sc = device_private(self); 2023a74451dSchristos 20322a97c46Sreinoud pmf_device_deregister(self); 20422a97c46Sreinoud 2053a74451dSchristos mutex_destroy(&sc->smn_lock); 2063a74451dSchristos aprint_normal_dev(self,"detach!\n"); 2073a74451dSchristos 2083a74451dSchristos return 0; 2093a74451dSchristos } 2103a74451dSchristos 2113a74451dSchristos int 2123a74451dSchristos amdsmn_read(device_t dev, uint32_t addr, uint32_t *value) 2133a74451dSchristos { 2143a74451dSchristos struct amdsmn_softc *sc = device_private(dev); 2153a74451dSchristos 2163a74451dSchristos mutex_enter(&sc->smn_lock); 217f90792d2Ssimonb pci_conf_write(sc->pc, sc->pcitag, sc->smn_addr_reg, addr); 218f90792d2Ssimonb *value = pci_conf_read(sc->pc, sc->pcitag, sc->smn_data_reg); 2193a74451dSchristos mutex_exit(&sc->smn_lock); 2203a74451dSchristos 2213a74451dSchristos return 0; 2223a74451dSchristos } 2233a74451dSchristos 2243a74451dSchristos int 2253a74451dSchristos amdsmn_write(device_t dev, uint32_t addr, uint32_t value) 2263a74451dSchristos { 2273a74451dSchristos struct amdsmn_softc *sc = device_private(dev); 2283a74451dSchristos 2293a74451dSchristos mutex_enter(&sc->smn_lock); 230f90792d2Ssimonb pci_conf_write(sc->pc, sc->pcitag, sc->smn_addr_reg, addr); 231f90792d2Ssimonb pci_conf_write(sc->pc, sc->pcitag, sc->smn_data_reg, value); 2323a74451dSchristos mutex_exit(&sc->smn_lock); 2333a74451dSchristos 2343a74451dSchristos return 0; 2353a74451dSchristos } 236a63689b9Spgoyette 237a63689b9Spgoyette MODULE(MODULE_CLASS_DRIVER, amdsmn, "pci"); 238a63689b9Spgoyette 239a63689b9Spgoyette #ifdef _MODULE 240a63689b9Spgoyette #include "ioconf.c" 241a63689b9Spgoyette #endif 242a63689b9Spgoyette 243a63689b9Spgoyette static int 244a63689b9Spgoyette amdsmn_modcmd(modcmd_t cmd, void *opaque) 245a63689b9Spgoyette { 246a63689b9Spgoyette int error = 0; 247a63689b9Spgoyette 248a63689b9Spgoyette #ifdef _MODULE 249a63689b9Spgoyette switch (cmd) { 250a63689b9Spgoyette case MODULE_CMD_INIT: 251a63689b9Spgoyette error = config_init_component(cfdriver_ioconf_amdsmn, 252a63689b9Spgoyette cfattach_ioconf_amdsmn, cfdata_ioconf_amdsmn); 253a63689b9Spgoyette break; 254a63689b9Spgoyette case MODULE_CMD_FINI: 255a63689b9Spgoyette error = config_fini_component(cfdriver_ioconf_amdsmn, 256a63689b9Spgoyette cfattach_ioconf_amdsmn, cfdata_ioconf_amdsmn); 257a63689b9Spgoyette break; 258a63689b9Spgoyette default: 259a63689b9Spgoyette error = ENOTTY; 260a63689b9Spgoyette break; 261a63689b9Spgoyette } 262a63689b9Spgoyette #endif 263a63689b9Spgoyette 264a63689b9Spgoyette return error; 265a63689b9Spgoyette } 266a63689b9Spgoyette 267