1*c7fb772bSthorpej /* $NetBSD: amdnb_misc.c,v 1.5 2021/08/07 16:19:07 thorpej Exp $ */
2c42e0053Scegger /*
3c42e0053Scegger * Copyright (c) 2012 The NetBSD Foundation, Inc.
4c42e0053Scegger * All rights reserved.
5c42e0053Scegger *
6c42e0053Scegger * This code is derived from software contributed to The NetBSD Foundation
7c42e0053Scegger * by Christoph Egger.
8c42e0053Scegger *
9c42e0053Scegger * Redistribution and use in source and binary forms, with or without
10c42e0053Scegger * modification, are permitted provided that the following conditions
11c42e0053Scegger * are met:
12c42e0053Scegger * 1. Redistributions of source code must retain the above copyright
13c42e0053Scegger * notice, this list of conditions and the following disclaimer.
14c42e0053Scegger * 2. Redistributions in binary form must reproduce the above copyright
15c42e0053Scegger * notice, this list of conditions and the following disclaimer in the
16c42e0053Scegger * documentation and/or other materials provided with the distribution.
17c42e0053Scegger *
18c42e0053Scegger * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19c42e0053Scegger * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20c42e0053Scegger * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21c42e0053Scegger * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22c42e0053Scegger * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23c42e0053Scegger * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24c42e0053Scegger * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25c42e0053Scegger * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26c42e0053Scegger * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27c42e0053Scegger * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28c42e0053Scegger * POSSIBILITY OF SUCH DAMAGE.
29c42e0053Scegger */
30c42e0053Scegger
31c42e0053Scegger #include <sys/cdefs.h>
32*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: amdnb_misc.c,v 1.5 2021/08/07 16:19:07 thorpej Exp $");
33c42e0053Scegger
34c42e0053Scegger #include <sys/param.h>
35c42e0053Scegger #include <sys/device.h>
36c42e0053Scegger
37c42e0053Scegger #include <dev/pci/pcireg.h>
38c42e0053Scegger #include <dev/pci/pcivar.h>
39c42e0053Scegger #include <dev/pci/pcidevs.h>
40c42e0053Scegger
41c42e0053Scegger static int amdnb_misc_match(device_t, cfdata_t match, void *);
42c42e0053Scegger static void amdnb_misc_attach(device_t, device_t, void *);
43c42e0053Scegger static int amdnb_misc_detach(device_t, int);
4490a8e71dScegger static int amdnb_misc_rescan(device_t, const char *, const int *);
4590a8e71dScegger static void amdnb_misc_childdet(device_t, device_t);
46c42e0053Scegger
4790a8e71dScegger struct amdnb_misc_softc {
4890a8e71dScegger struct pci_attach_args sc_pa;
4990a8e71dScegger };
5090a8e71dScegger
5190a8e71dScegger CFATTACH_DECL3_NEW(amdnb_misc, sizeof(struct amdnb_misc_softc),
5290a8e71dScegger amdnb_misc_match, amdnb_misc_attach, amdnb_misc_detach, NULL,
5390a8e71dScegger amdnb_misc_rescan, amdnb_misc_childdet, DVF_DETACH_SHUTDOWN);
54c42e0053Scegger
55c42e0053Scegger
56c42e0053Scegger static int
amdnb_misc_match(device_t parent,cfdata_t match,void * aux)57c42e0053Scegger amdnb_misc_match(device_t parent, cfdata_t match, void *aux)
58c42e0053Scegger {
59c42e0053Scegger struct pci_attach_args *pa = aux;
60c42e0053Scegger
61c42e0053Scegger if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_AMD)
62c42e0053Scegger return 0;
63c42e0053Scegger
64c42e0053Scegger switch (PCI_PRODUCT(pa->pa_id)) {
65c42e0053Scegger case PCI_PRODUCT_AMD_AMD64_MISC:
66c42e0053Scegger case PCI_PRODUCT_AMD_AMD64_F10_MISC:
67c42e0053Scegger case PCI_PRODUCT_AMD_AMD64_F11_MISC:
68c42e0053Scegger case PCI_PRODUCT_AMD_F14_NB: /* Family 12h, too */
69c42e0053Scegger case PCI_PRODUCT_AMD_F15_MISC:
70867d63b1Sis case PCI_PRODUCT_AMD_F16_NB:
71867d63b1Sis case PCI_PRODUCT_AMD_F16_30_NB:
72c42e0053Scegger break;
73c42e0053Scegger default:
74c42e0053Scegger return 0;
75c42e0053Scegger }
76c42e0053Scegger
77c42e0053Scegger return 2; /* supercede pchb(4) */
78c42e0053Scegger }
79c42e0053Scegger
80c42e0053Scegger static int
amdnb_misc_search(device_t parent,cfdata_t cf,const int * locs,void * aux)81c42e0053Scegger amdnb_misc_search(device_t parent, cfdata_t cf, const int *locs, void *aux)
82c42e0053Scegger {
8390a8e71dScegger device_t dev;
8490a8e71dScegger deviter_t di;
8590a8e71dScegger bool attach;
8690a8e71dScegger
872685996bSthorpej if (!config_probe(parent, cf, aux))
8890a8e71dScegger return 0;
8990a8e71dScegger
9090a8e71dScegger attach = true;
9190a8e71dScegger
9290a8e71dScegger /* Figure out if found child 'cf' is already attached.
9390a8e71dScegger * No need to attach it twice.
9490a8e71dScegger */
9590a8e71dScegger
9690a8e71dScegger /* XXX: I only want to iterate over the children of *this* device.
9790a8e71dScegger * Can we introduce a
9890a8e71dScegger * deviter_first_child(&di, parent, DEVITER_F_LEAVES_ONLY)
9990a8e71dScegger * or even better, can we introduce a query function that returns
10090a8e71dScegger * if a child is already attached?
10190a8e71dScegger */
10290a8e71dScegger for (dev = deviter_first(&di, DEVITER_F_LEAVES_FIRST); dev != NULL;
10390a8e71dScegger dev = deviter_next(&di))
10490a8e71dScegger {
10590a8e71dScegger if (device_parent(dev) != parent)
10690a8e71dScegger continue;
10790a8e71dScegger if (device_is_a(dev, cf->cf_name)) {
10890a8e71dScegger attach = false;
10990a8e71dScegger break;
11090a8e71dScegger }
11190a8e71dScegger }
11290a8e71dScegger deviter_release(&di);
11390a8e71dScegger
11490a8e71dScegger if (!attach)
11590a8e71dScegger return 0;
11690a8e71dScegger
117*c7fb772bSthorpej config_attach(parent, cf, aux, NULL, CFARGS_NONE);
118c42e0053Scegger
119c42e0053Scegger return 0;
120c42e0053Scegger }
121c42e0053Scegger
122c42e0053Scegger static void
amdnb_misc_attach(device_t parent,device_t self,void * aux)123c42e0053Scegger amdnb_misc_attach(device_t parent, device_t self, void *aux)
124c42e0053Scegger {
12590a8e71dScegger struct amdnb_misc_softc *sc = device_private(self);
12690a8e71dScegger struct pci_attach_args *pa = aux;
12790a8e71dScegger
12890a8e71dScegger sc->sc_pa = *pa;
12990a8e71dScegger
130c42e0053Scegger aprint_naive("\n");
131c42e0053Scegger aprint_normal(": AMD NB Misc Configuration\n");
132c42e0053Scegger
133c42e0053Scegger if (!pmf_device_register(self, NULL, NULL))
134c42e0053Scegger aprint_error_dev(self, "couldn't establish power handler\n");
135c42e0053Scegger
1362685996bSthorpej config_search(self, &sc->sc_pa,
137*c7fb772bSthorpej CFARGS(.search = amdnb_misc_search));
13890a8e71dScegger
139c42e0053Scegger return;
140c42e0053Scegger }
141c42e0053Scegger
142c42e0053Scegger static int
amdnb_misc_detach(device_t self,int flags)143c42e0053Scegger amdnb_misc_detach(device_t self, int flags)
144c42e0053Scegger {
145c42e0053Scegger int rv;
146c42e0053Scegger
147c42e0053Scegger rv = config_detach_children(self, flags);
148c42e0053Scegger if (rv != 0)
149c42e0053Scegger return rv;
150c42e0053Scegger
151c42e0053Scegger pmf_device_deregister(self);
152c42e0053Scegger return rv;
153c42e0053Scegger }
15490a8e71dScegger
15590a8e71dScegger static int
amdnb_misc_rescan(device_t self,const char * ifattr,const int * locators)15690a8e71dScegger amdnb_misc_rescan(device_t self, const char *ifattr, const int *locators)
15790a8e71dScegger {
15890a8e71dScegger struct amdnb_misc_softc *sc = device_private(self);
15990a8e71dScegger
1602685996bSthorpej config_search(self, &sc->sc_pa,
161*c7fb772bSthorpej CFARGS(.search = amdnb_misc_search));
16290a8e71dScegger
16390a8e71dScegger return 0;
16490a8e71dScegger }
16590a8e71dScegger
16690a8e71dScegger static void
amdnb_misc_childdet(device_t self,device_t child)16790a8e71dScegger amdnb_misc_childdet(device_t self, device_t child)
16890a8e71dScegger {
16990a8e71dScegger return;
17090a8e71dScegger }
171