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 | |