if_cs_ofisa.c revision 1.26 1 /* $NetBSD: if_cs_ofisa.c,v 1.26 2015/04/13 16:33:24 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 1998 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 of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: if_cs_ofisa.c,v 1.26 2015/04/13 16:33:24 riastradh Exp $");
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/socket.h>
39 #include <sys/device.h>
40 #include <sys/malloc.h>
41
42 #include <sys/rndsource.h>
43
44 #include <net/if.h>
45 #include <net/if_ether.h>
46 #include <net/if_media.h>
47 #ifdef INET
48 #include <netinet/in.h>
49 #include <netinet/if_inarp.h>
50 #endif
51
52 #include <sys/bus.h>
53 #include <sys/intr.h>
54
55 #include <dev/ofw/openfirm.h>
56 #include <dev/isa/isavar.h>
57 #include <dev/ofisa/ofisavar.h>
58
59 #include <dev/ic/cs89x0reg.h>
60 #include <dev/ic/cs89x0var.h>
61 #include <dev/isa/cs89x0isavar.h>
62
63 static int cs_ofisa_match(device_t, cfdata_t, void *);
64 static void cs_ofisa_attach(device_t, device_t, void *);
65
66 CFATTACH_DECL_NEW(cs_ofisa, sizeof(struct cs_softc_isa),
67 cs_ofisa_match, cs_ofisa_attach, NULL, NULL);
68
69 int
70 cs_ofisa_match(device_t parent, cfdata_t cf, void *aux)
71 {
72 struct ofisa_attach_args *aa = aux;
73 static const char *const compatible_strings[] = {
74 "CRUS,CS8900",
75 /* XXX CS8920, CS8920M? */
76 /* XXX PNP names? */
77 NULL,
78 };
79 int rv = 0;
80
81 if (of_compatible(aa->oba.oba_phandle, compatible_strings) != -1)
82 rv = 5;
83 #ifdef _CS_OFISA_MD_MATCH
84 if (rv == 0)
85 rv = cs_ofisa_md_match(parent, cf, aux);
86 #endif
87 return (rv);
88 }
89
90 void
91 cs_ofisa_attach(device_t parent, device_t self, void *aux)
92 {
93 struct cs_softc_isa *isc = device_private(self);
94 struct cs_softc *sc = &isc->sc_cs;
95 struct ofisa_attach_args *aa = aux;
96 struct ofisa_reg_desc reg[2];
97 struct ofisa_intr_desc intr;
98 struct ofisa_dma_desc dma;
99 int i, n, *media, nmedia, defmedia;
100 bus_addr_t io_addr, mem_addr;
101 char *model = NULL;
102 const char *message = NULL;
103 u_int8_t enaddr[6];
104
105 sc->sc_dev = self;
106 isc->sc_ic = aa->ic;
107 sc->sc_iot = aa->iot;
108 sc->sc_memt = aa->memt;
109
110 /*
111 * We're living on an OFW. We have to ask the OFW what our
112 * registers and interrupts properties look like.
113 *
114 * We expect:
115 *
116 * 1 i/o register region
117 * 0 or 1 memory region
118 * 1 interrupt
119 * 0 or 1 DMA channel
120 */
121
122 io_addr = mem_addr = -1;
123
124 n = ofisa_reg_get(aa->oba.oba_phandle, reg, 2);
125 #ifdef _CS_OFISA_MD_REG_FIXUP
126 n = cs_ofisa_md_reg_fixup(parent, self, aux, reg, 2, n);
127 #endif
128 if (n < 1 || n > 2) {
129 printf(": error getting register data\n");
130 return;
131 }
132
133 for (i = 0; i < n; i++) {
134 if (reg[i].type == OFISA_REG_TYPE_IO) {
135 if (io_addr != (bus_addr_t) -1) {
136 printf(": multiple I/O regions\n");
137 return;
138 }
139 if (reg[i].len != CS8900_IOSIZE) {
140 printf(": weird register size (%lu, expected %d)\n",
141 (unsigned long)reg[i].len, CS8900_IOSIZE);
142 return;
143 }
144 io_addr = reg[i].addr;
145 } else {
146 if (mem_addr != (bus_addr_t) -1) {
147 printf(": multiple memory regions\n");
148 return;
149 }
150 if (reg[i].len != CS8900_MEMSIZE) {
151 printf(": weird register size (%lu, expected %d)\n",
152 (unsigned long)reg[i].len, CS8900_MEMSIZE);
153 return;
154 }
155 mem_addr = reg[i].addr;
156 }
157 }
158
159 n = ofisa_intr_get(aa->oba.oba_phandle, &intr, 1);
160 #ifdef _CS_OFISA_MD_INTR_FIXUP
161 n = cs_ofisa_md_intr_fixup(parent, self, aux, &intr, 1, n);
162 #endif
163 if (n != 1) {
164 printf(": error getting interrupt data\n");
165 return;
166 }
167 sc->sc_irq = intr.irq;
168
169 if (CS8900_IRQ_ISVALID(sc->sc_irq) == 0) {
170 printf(": invalid IRQ %d\n", sc->sc_irq);
171 return;
172 }
173
174 isc->sc_drq = -1;
175 n = ofisa_dma_get(aa->oba.oba_phandle, &dma, 1);
176 #ifdef _CS_OFISA_MD_DMA_FIXUP
177 n = cs_ofisa_md_dma_fixup(parent, self, aux, &dma, 1, n);
178 #endif
179 if (n == 1)
180 isc->sc_drq = dma.drq;
181
182 if (io_addr == (bus_addr_t) -1) {
183 printf(": no I/O space\n");
184 return;
185 }
186 if (bus_space_map(sc->sc_iot, io_addr, CS8900_IOSIZE, 0,
187 &sc->sc_ioh)) {
188 printf(": unable to map register space\n");
189 return;
190 }
191
192 if (mem_addr != (bus_addr_t) -1) {
193 if (bus_space_map(sc->sc_memt, mem_addr, CS8900_MEMSIZE, 0,
194 &sc->sc_memh)) {
195 message = "unable to map memory space";
196 } else {
197 sc->sc_cfgflags |= CFGFLG_MEM_MODE;
198 sc->sc_pktpgaddr = mem_addr;
199 }
200 }
201
202 /* Dig MAC address out of the firmware. */
203 if (OF_getprop(aa->oba.oba_phandle, "mac-address", enaddr,
204 sizeof(enaddr)) < 0) {
205 printf(": unable to get Ethernet address\n");
206 return;
207 }
208
209 /* Dig media out of the firmware. */
210 media = of_network_decode_media(aa->oba.oba_phandle, &nmedia,
211 &defmedia);
212 #ifdef _CS_OFISA_MD_MEDIA_FIXUP
213 media = cs_ofisa_md_media_fixup(parent, self, aux, media, &nmedia,
214 &defmedia);
215 #endif
216 if (media == NULL) {
217 printf(": unable to get media information\n");
218 return;
219 }
220
221 n = OF_getproplen(aa->oba.oba_phandle, "model");
222 if (n > 0) {
223 model = alloca(n);
224 if (OF_getprop(aa->oba.oba_phandle, "model", model, n) != n)
225 model = NULL; /* Safe; alloca is on-stack */
226 }
227 if (model != NULL)
228 printf(": %s\n", model);
229 else
230 printf("\n");
231
232 if (message != NULL)
233 printf("%s: %s\n", device_xname(self), message);
234
235 if (defmedia == -1) {
236 aprint_error_dev(self, "unable to get default media\n");
237 defmedia = media[0]; /* XXX What to do? */
238 }
239
240 sc->sc_ih = isa_intr_establish(isc->sc_ic, sc->sc_irq, intr.share,
241 IPL_NET, cs_intr, sc);
242 if (sc->sc_ih == NULL) {
243 aprint_error_dev(self, "unable to establish interrupt\n");
244 return;
245 }
246
247 #ifdef _CS_OFISA_MD_CFGFLAGS_FIXUP
248 sc->sc_cfgflags |= cs_ofisa_md_cfgflags_fixup(parent, self, aux);
249 #endif
250
251 sc->sc_dma_chipinit = cs_isa_dma_chipinit;
252 sc->sc_dma_attach = cs_isa_dma_attach;
253 sc->sc_dma_process_rx = cs_process_rx_dma;
254
255 cs_attach(sc, enaddr, media, nmedia, defmedia);
256
257 /* This is malloc'd. */
258 free(media, M_DEVBUF);
259 }
260