11.5Sthorpej/*	$NetBSD: amdnb_misc.c,v 1.5 2021/08/07 16:19:07 thorpej Exp $ */
21.1Scegger/*
31.1Scegger * Copyright (c) 2012 The NetBSD Foundation, Inc.
41.1Scegger * All rights reserved.
51.1Scegger *
61.1Scegger * This code is derived from software contributed to The NetBSD Foundation
71.1Scegger * by Christoph Egger.
81.1Scegger *
91.1Scegger * Redistribution and use in source and binary forms, with or without
101.1Scegger * modification, are permitted provided that the following conditions
111.1Scegger * are met:
121.1Scegger * 1. Redistributions of source code must retain the above copyright
131.1Scegger *    notice, this list of conditions and the following disclaimer.
141.1Scegger * 2. Redistributions in binary form must reproduce the above copyright
151.1Scegger *    notice, this list of conditions and the following disclaimer in the
161.1Scegger *    documentation and/or other materials provided with the distribution.
171.1Scegger *
181.1Scegger * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
191.1Scegger * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
201.1Scegger * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
211.1Scegger * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
221.1Scegger * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
231.1Scegger * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
241.1Scegger * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
251.1Scegger * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
261.1Scegger * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
271.1Scegger * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
281.1Scegger * POSSIBILITY OF SUCH DAMAGE.
291.1Scegger */
301.1Scegger
311.1Scegger#include <sys/cdefs.h>
321.5Sthorpej__KERNEL_RCSID(0, "$NetBSD: amdnb_misc.c,v 1.5 2021/08/07 16:19:07 thorpej Exp $");
331.1Scegger
341.1Scegger#include <sys/param.h>
351.1Scegger#include <sys/device.h>
361.1Scegger
371.1Scegger#include <dev/pci/pcireg.h>
381.1Scegger#include <dev/pci/pcivar.h>
391.1Scegger#include <dev/pci/pcidevs.h>
401.1Scegger
411.1Sceggerstatic int amdnb_misc_match(device_t, cfdata_t match, void *);
421.1Sceggerstatic void amdnb_misc_attach(device_t, device_t, void *);
431.1Sceggerstatic int amdnb_misc_detach(device_t, int);
441.2Sceggerstatic int amdnb_misc_rescan(device_t, const char *, const int *);
451.2Sceggerstatic void amdnb_misc_childdet(device_t, device_t);
461.1Scegger
471.2Sceggerstruct amdnb_misc_softc {
481.2Scegger	struct pci_attach_args sc_pa;
491.2Scegger};
501.2Scegger
511.2SceggerCFATTACH_DECL3_NEW(amdnb_misc, sizeof(struct amdnb_misc_softc),
521.2Scegger    amdnb_misc_match, amdnb_misc_attach, amdnb_misc_detach, NULL,
531.2Scegger    amdnb_misc_rescan, amdnb_misc_childdet, DVF_DETACH_SHUTDOWN);
541.1Scegger
551.1Scegger
561.1Sceggerstatic int
571.1Sceggeramdnb_misc_match(device_t parent, cfdata_t match, void *aux)
581.1Scegger{
591.1Scegger	struct pci_attach_args *pa = aux;
601.1Scegger
611.1Scegger	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_AMD)
621.1Scegger		return 0;
631.1Scegger
641.1Scegger	switch (PCI_PRODUCT(pa->pa_id)) {
651.1Scegger	case PCI_PRODUCT_AMD_AMD64_MISC:
661.1Scegger	case PCI_PRODUCT_AMD_AMD64_F10_MISC:
671.1Scegger	case PCI_PRODUCT_AMD_AMD64_F11_MISC:
681.1Scegger	case PCI_PRODUCT_AMD_F14_NB:		/* Family 12h, too */
691.1Scegger	case PCI_PRODUCT_AMD_F15_MISC:
701.3Sis	case PCI_PRODUCT_AMD_F16_NB:
711.3Sis	case PCI_PRODUCT_AMD_F16_30_NB:
721.1Scegger		break;
731.1Scegger	default:
741.1Scegger		return 0;
751.1Scegger	}
761.1Scegger
771.1Scegger	return 2;	/* supercede pchb(4) */
781.1Scegger}
791.1Scegger
801.1Sceggerstatic int
811.1Sceggeramdnb_misc_search(device_t parent, cfdata_t cf, const int *locs, void *aux)
821.1Scegger{
831.2Scegger	device_t dev;
841.2Scegger	deviter_t di;
851.2Scegger	bool attach;
861.2Scegger
871.4Sthorpej	if (!config_probe(parent, cf, aux))
881.2Scegger		return 0;
891.2Scegger
901.2Scegger	attach = true;
911.2Scegger
921.2Scegger	/* Figure out if found child 'cf' is already attached.
931.2Scegger	 * No need to attach it twice.
941.2Scegger	 */
951.2Scegger
961.2Scegger	/* XXX: I only want to iterate over the children of *this* device.
971.2Scegger	 * Can we introduce a
981.2Scegger	 * deviter_first_child(&di, parent, DEVITER_F_LEAVES_ONLY)
991.2Scegger	 * or even better, can we introduce a query function that returns
1001.2Scegger	 * if a child is already attached?
1011.2Scegger	 */
1021.2Scegger	for (dev = deviter_first(&di, DEVITER_F_LEAVES_FIRST); dev != NULL;
1031.2Scegger	    dev = deviter_next(&di))
1041.2Scegger	{
1051.2Scegger		if (device_parent(dev) != parent)
1061.2Scegger			continue;
1071.2Scegger		if (device_is_a(dev, cf->cf_name)) {
1081.2Scegger			attach = false;
1091.2Scegger			break;
1101.2Scegger		}
1111.2Scegger	}
1121.2Scegger	deviter_release(&di);
1131.2Scegger
1141.2Scegger	if (!attach)
1151.2Scegger		return 0;
1161.2Scegger
1171.5Sthorpej	config_attach(parent, cf, aux, NULL, CFARGS_NONE);
1181.1Scegger
1191.1Scegger	return 0;
1201.1Scegger}
1211.1Scegger
1221.1Sceggerstatic void
1231.1Sceggeramdnb_misc_attach(device_t parent, device_t self, void *aux)
1241.1Scegger{
1251.2Scegger	struct amdnb_misc_softc *sc = device_private(self);
1261.2Scegger	struct pci_attach_args *pa = aux;
1271.2Scegger
1281.2Scegger	sc->sc_pa = *pa;
1291.2Scegger
1301.1Scegger	aprint_naive("\n");
1311.1Scegger	aprint_normal(": AMD NB Misc Configuration\n");
1321.1Scegger
1331.1Scegger	if (!pmf_device_register(self, NULL, NULL))
1341.1Scegger		aprint_error_dev(self, "couldn't establish power handler\n");
1351.1Scegger
1361.4Sthorpej	config_search(self, &sc->sc_pa,
1371.5Sthorpej	    CFARGS(.search = amdnb_misc_search));
1381.2Scegger
1391.1Scegger	return;
1401.1Scegger}
1411.1Scegger
1421.1Sceggerstatic int
1431.1Sceggeramdnb_misc_detach(device_t self, int flags)
1441.1Scegger{
1451.1Scegger	int rv;
1461.1Scegger
1471.1Scegger	rv = config_detach_children(self, flags);
1481.1Scegger	if (rv != 0)
1491.1Scegger		return rv;
1501.1Scegger
1511.1Scegger	pmf_device_deregister(self);
1521.1Scegger	return rv;
1531.1Scegger}
1541.2Scegger
1551.2Sceggerstatic int
1561.2Sceggeramdnb_misc_rescan(device_t self, const char *ifattr, const int *locators)
1571.2Scegger{
1581.2Scegger	struct amdnb_misc_softc *sc = device_private(self);
1591.2Scegger
1601.4Sthorpej	config_search(self, &sc->sc_pa,
1611.5Sthorpej	    CFARGS(.search = amdnb_misc_search));
1621.2Scegger
1631.2Scegger	return 0;
1641.2Scegger}
1651.2Scegger
1661.2Sceggerstatic void
1671.2Sceggeramdnb_misc_childdet(device_t self, device_t child)
1681.2Scegger{
1691.2Scegger	return;
1701.2Scegger}
171