xref: /netbsd-src/sys/arch/x86/pci/amdnb_misc.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1 /*	$NetBSD: amdnb_misc.c,v 1.2 2012/04/16 16:07:24 cegger Exp $ */
2 /*
3  * Copyright (c) 2012 The NetBSD Foundation, Inc.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to The NetBSD Foundation
7  * by Christoph Egger.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: amdnb_misc.c,v 1.2 2012/04/16 16:07:24 cegger Exp $");
33 
34 #include <sys/param.h>
35 #include <sys/device.h>
36 
37 #include <dev/pci/pcireg.h>
38 #include <dev/pci/pcivar.h>
39 #include <dev/pci/pcidevs.h>
40 
41 static int amdnb_misc_match(device_t, cfdata_t match, void *);
42 static void amdnb_misc_attach(device_t, device_t, void *);
43 static int amdnb_misc_detach(device_t, int);
44 static int amdnb_misc_rescan(device_t, const char *, const int *);
45 static void amdnb_misc_childdet(device_t, device_t);
46 
47 struct amdnb_misc_softc {
48 	struct pci_attach_args sc_pa;
49 };
50 
51 CFATTACH_DECL3_NEW(amdnb_misc, sizeof(struct amdnb_misc_softc),
52     amdnb_misc_match, amdnb_misc_attach, amdnb_misc_detach, NULL,
53     amdnb_misc_rescan, amdnb_misc_childdet, DVF_DETACH_SHUTDOWN);
54 
55 
56 static int
57 amdnb_misc_match(device_t parent, cfdata_t match, void *aux)
58 {
59 	struct pci_attach_args *pa = aux;
60 
61 	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_AMD)
62 		return 0;
63 
64 	switch (PCI_PRODUCT(pa->pa_id)) {
65 	case PCI_PRODUCT_AMD_AMD64_MISC:
66 	case PCI_PRODUCT_AMD_AMD64_F10_MISC:
67 	case PCI_PRODUCT_AMD_AMD64_F11_MISC:
68 	case PCI_PRODUCT_AMD_F14_NB:		/* Family 12h, too */
69 	case PCI_PRODUCT_AMD_F15_MISC:
70 		break;
71 	default:
72 		return 0;
73 	}
74 
75 	return 2;	/* supercede pchb(4) */
76 }
77 
78 static int
79 amdnb_misc_search(device_t parent, cfdata_t cf, const int *locs, void *aux)
80 {
81 	device_t dev;
82 	deviter_t di;
83 	bool attach;
84 
85 	if (!config_match(parent, cf, aux))
86 		return 0;
87 
88 	attach = true;
89 
90 	/* Figure out if found child 'cf' is already attached.
91 	 * No need to attach it twice.
92 	 */
93 
94 	/* XXX: I only want to iterate over the children of *this* device.
95 	 * Can we introduce a
96 	 * deviter_first_child(&di, parent, DEVITER_F_LEAVES_ONLY)
97 	 * or even better, can we introduce a query function that returns
98 	 * if a child is already attached?
99 	 */
100 	for (dev = deviter_first(&di, DEVITER_F_LEAVES_FIRST); dev != NULL;
101 	    dev = deviter_next(&di))
102 	{
103 		if (device_parent(dev) != parent)
104 			continue;
105 		if (device_is_a(dev, cf->cf_name)) {
106 			attach = false;
107 			break;
108 		}
109 	}
110 	deviter_release(&di);
111 
112 	if (!attach)
113 		return 0;
114 
115 	config_attach_loc(parent, cf, locs, aux, NULL);
116 
117 	return 0;
118 }
119 
120 static void
121 amdnb_misc_attach(device_t parent, device_t self, void *aux)
122 {
123 	struct amdnb_misc_softc *sc = device_private(self);
124 	struct pci_attach_args *pa = aux;
125 
126 	sc->sc_pa = *pa;
127 
128 	aprint_naive("\n");
129 	aprint_normal(": AMD NB Misc Configuration\n");
130 
131 	if (!pmf_device_register(self, NULL, NULL))
132 		aprint_error_dev(self, "couldn't establish power handler\n");
133 
134 	config_search_loc(amdnb_misc_search, self, "amdnb_miscbus",
135 	    NULL, &sc->sc_pa);
136 
137 	return;
138 }
139 
140 static int
141 amdnb_misc_detach(device_t self, int flags)
142 {
143 	int rv;
144 
145 	rv = config_detach_children(self, flags);
146 	if (rv != 0)
147 		return rv;
148 
149 	pmf_device_deregister(self);
150 	return rv;
151 }
152 
153 static int
154 amdnb_misc_rescan(device_t self, const char *ifattr, const int *locators)
155 {
156 	struct amdnb_misc_softc *sc = device_private(self);
157 
158 	if (!ifattr_match(ifattr, "amdnb_miscbus"))
159 		return 0;
160 
161 	config_search_loc(amdnb_misc_search, self, ifattr,
162 	    locators, &sc->sc_pa);
163 
164 	return 0;
165 }
166 
167 static void
168 amdnb_misc_childdet(device_t self, device_t child)
169 {
170 	return;
171 }
172