1 | /* $NetBSD: if_sf_pci.c,v 1.21 2016/07/07 06:55:41 msaitoh Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2001 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Jason R. Thorpe. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * PCI bus front-end for the Adaptec AIC-6915 (``Starfire'') |
34 | * 10/100 Ethernet controller. |
35 | */ |
36 | |
37 | #include <sys/cdefs.h> |
38 | __KERNEL_RCSID(0, "$NetBSD: if_sf_pci.c,v 1.21 2016/07/07 06:55:41 msaitoh Exp $" ); |
39 | |
40 | #include <sys/param.h> |
41 | #include <sys/systm.h> |
42 | #include <sys/mbuf.h> |
43 | #include <sys/malloc.h> |
44 | #include <sys/kernel.h> |
45 | #include <sys/socket.h> |
46 | #include <sys/ioctl.h> |
47 | #include <sys/errno.h> |
48 | #include <sys/device.h> |
49 | |
50 | #include <net/if.h> |
51 | #include <net/if_dl.h> |
52 | #include <net/if_media.h> |
53 | #include <net/if_ether.h> |
54 | |
55 | #include <sys/bus.h> |
56 | #include <sys/intr.h> |
57 | |
58 | #include <dev/mii/miivar.h> |
59 | |
60 | #include <dev/ic/aic6915reg.h> |
61 | #include <dev/ic/aic6915var.h> |
62 | |
63 | #include <dev/pci/pcireg.h> |
64 | #include <dev/pci/pcivar.h> |
65 | #include <dev/pci/pcidevs.h> |
66 | |
67 | struct sf_pci_softc { |
68 | struct sf_softc sc_starfire; /* read Starfire softc */ |
69 | |
70 | /* PCI-specific goo. */ |
71 | void *sc_ih; /* interrupt handle */ |
72 | }; |
73 | |
74 | static int sf_pci_match(device_t, cfdata_t, void *); |
75 | static void sf_pci_attach(device_t, device_t, void *); |
76 | |
77 | CFATTACH_DECL_NEW(sf_pci, sizeof(struct sf_pci_softc), |
78 | sf_pci_match, sf_pci_attach, NULL, NULL); |
79 | |
80 | struct sf_pci_product { |
81 | uint32_t spp_vendor; /* PCI vendor ID */ |
82 | uint32_t spp_product; /* PCI product ID */ |
83 | const char *spp_name; /* product name */ |
84 | const struct sf_pci_product *spp_subsys; /* subsystm IDs */ |
85 | }; |
86 | |
87 | static const struct sf_pci_product sf_subsys_adaptec[] = { |
88 | /* ANA-62011 (rev 0) Single port 10/100 64-bit */ |
89 | { PCI_VENDOR_ADP, 0x0008, |
90 | "ANA-62011 (rev 0) 10/100 Ethernet" , NULL }, |
91 | |
92 | /* ANA-62011 (rev 1) Single port 10/100 64-bit */ |
93 | { PCI_VENDOR_ADP, 0x0009, |
94 | "ANA-62011 (rev 1) 10/100 Ethernet" , NULL }, |
95 | |
96 | /* ANA-62022 Dual port 10/100 64-bit */ |
97 | { PCI_VENDOR_ADP, 0x0010, |
98 | "ANA-62022 10/100 Ethernet" , NULL }, |
99 | |
100 | /* ANA-62044 (rev 0) Quad port 10/100 64-bit */ |
101 | { PCI_VENDOR_ADP, 0x0018, |
102 | "ANA-62044 (rev 0) 10/100 Ethernet" , NULL }, |
103 | |
104 | /* ANA-62044 (rev 1) Quad port 10/100 64-bit */ |
105 | { PCI_VENDOR_ADP, 0x0019, |
106 | "ANA-62044 (rev 1) 10/100 Ethernet" , NULL }, |
107 | |
108 | /* ANA-62020 Single port 100baseFX 64-bit */ |
109 | { PCI_VENDOR_ADP, 0x0020, |
110 | "ANA-62020 100baseFX Ethernet" , NULL }, |
111 | |
112 | /* ANA-69011 Single port 10/100 32-bit */ |
113 | { PCI_VENDOR_ADP, 0x0028, |
114 | "ANA-69011 10/100 Ethernet" , NULL }, |
115 | |
116 | { 0, 0, |
117 | NULL, NULL }, |
118 | }; |
119 | |
120 | static const struct sf_pci_product sf_pci_products[] = { |
121 | { PCI_VENDOR_ADP, PCI_PRODUCT_ADP_AIC6915, |
122 | "AIC-6915 10/100 Ethernet" , sf_subsys_adaptec }, |
123 | |
124 | { 0, 0, |
125 | NULL, NULL }, |
126 | }; |
127 | |
128 | static const struct sf_pci_product * |
129 | sf_pci_lookup(const struct pci_attach_args *pa) |
130 | { |
131 | const struct sf_pci_product *spp, *subspp; |
132 | pcireg_t subsysid; |
133 | |
134 | for (spp = sf_pci_products; spp->spp_name != NULL; spp++) { |
135 | if (PCI_VENDOR(pa->pa_id) == spp->spp_vendor && |
136 | PCI_PRODUCT(pa->pa_id) == spp->spp_product) { |
137 | subsysid = pci_conf_read(pa->pa_pc, pa->pa_tag, |
138 | PCI_SUBSYS_ID_REG); |
139 | for (subspp = spp->spp_subsys; |
140 | subspp->spp_name != NULL; subspp++) { |
141 | if (PCI_VENDOR(subsysid) == |
142 | subspp->spp_vendor || |
143 | PCI_PRODUCT(subsysid) == |
144 | subspp->spp_product) { |
145 | return (subspp); |
146 | } |
147 | } |
148 | return (spp); |
149 | } |
150 | } |
151 | |
152 | return (NULL); |
153 | } |
154 | |
155 | static int |
156 | sf_pci_match(device_t parent, cfdata_t match, void *aux) |
157 | { |
158 | struct pci_attach_args *pa = aux; |
159 | |
160 | if (sf_pci_lookup(pa) != NULL) |
161 | return (1); |
162 | |
163 | return (0); |
164 | } |
165 | |
166 | static void |
167 | sf_pci_attach(device_t parent, device_t self, void *aux) |
168 | { |
169 | struct sf_pci_softc *psc = device_private(self); |
170 | struct sf_softc *sc = &psc->sc_starfire; |
171 | struct pci_attach_args *pa = aux; |
172 | pci_intr_handle_t ih; |
173 | const char *intrstr = NULL; |
174 | const struct sf_pci_product *spp; |
175 | bus_space_tag_t iot, memt; |
176 | bus_space_handle_t ioh, memh; |
177 | pcireg_t reg; |
178 | int error, ioh_valid, memh_valid; |
179 | char intrbuf[PCI_INTRSTR_LEN]; |
180 | |
181 | sc->sc_dev = self; |
182 | spp = sf_pci_lookup(pa); |
183 | if (spp == NULL) { |
184 | printf("\n" ); |
185 | panic("sf_pci_attach: impossible" ); |
186 | } |
187 | |
188 | printf(": %s, rev. %d\n" , spp->spp_name, PCI_REVISION(pa->pa_class)); |
189 | |
190 | /* power up chip */ |
191 | if ((error = pci_activate(pa->pa_pc, pa->pa_tag, self, NULL)) && |
192 | error != EOPNOTSUPP) { |
193 | aprint_error_dev(self, "cannot activate %d\n" , error); |
194 | return; |
195 | } |
196 | |
197 | /* |
198 | * Map the device. |
199 | */ |
200 | reg = pci_mapreg_type(pa->pa_pc, pa->pa_tag, SF_PCI_MEMBA); |
201 | switch (reg) { |
202 | case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT: |
203 | case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT: |
204 | memh_valid = (pci_mapreg_map(pa, SF_PCI_MEMBA, |
205 | reg, 0, &memt, &memh, NULL, NULL) == 0); |
206 | break; |
207 | default: |
208 | memh_valid = 0; |
209 | } |
210 | |
211 | ioh_valid = (pci_mapreg_map(pa, |
212 | (reg == (PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT)) ? |
213 | SF_PCI_IOBA : SF_PCI_IOBA - 0x04, |
214 | PCI_MAPREG_TYPE_IO, 0, &iot, &ioh, NULL, NULL) == 0); |
215 | |
216 | if (memh_valid) { |
217 | sc->sc_st = memt; |
218 | sc->sc_sh = memh; |
219 | sc->sc_iomapped = 0; |
220 | } else if (ioh_valid) { |
221 | sc->sc_st = iot; |
222 | sc->sc_sh = ioh; |
223 | sc->sc_iomapped = 1; |
224 | } else { |
225 | aprint_error_dev(self, "unable to map device registers\n" ); |
226 | return; |
227 | } |
228 | |
229 | sc->sc_dmat = pa->pa_dmat; |
230 | |
231 | /* Make sure bus mastering is enabled. */ |
232 | pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, |
233 | pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG) | |
234 | PCI_COMMAND_MASTER_ENABLE); |
235 | |
236 | /* |
237 | * Map and establish our interrupt. |
238 | */ |
239 | if (pci_intr_map(pa, &ih)) { |
240 | aprint_error_dev(self, "unable to map interrupt\n" ); |
241 | return; |
242 | } |
243 | intrstr = pci_intr_string(pa->pa_pc, ih, intrbuf, sizeof(intrbuf)); |
244 | psc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET, sf_intr, sc); |
245 | if (psc->sc_ih == NULL) { |
246 | aprint_error_dev(self, "unable to establish interrupt" ); |
247 | if (intrstr != NULL) |
248 | aprint_error(" at %s" , intrstr); |
249 | aprint_error("\n" ); |
250 | return; |
251 | } |
252 | aprint_normal_dev(self, "interrupting at %s\n" , intrstr); |
253 | |
254 | /* |
255 | * Finish off the attach. |
256 | */ |
257 | sf_attach(sc); |
258 | } |
259 | |