1 /*-
2 * Copyright (c) 1994-2000
3 * Paul Richards. All rights reserved.
4 *
5 * PC-98 port by Chiharu Shibata & FreeBSD(98) porting team.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer,
12 * verbatim and that no modifications are made prior to this
13 * point in the file.
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 * 3. The name Paul Richards may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY PAUL RICHARDS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL PAUL RICHARDS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * from: FreeBSD: src/sys/dev/lnc/if_lnc_cbus.c,v 1.12 2005/11/12 19:14:21
33 */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/bus.h>
41 #include <sys/endian.h>
42 #include <sys/kernel.h>
43 #include <sys/lock.h>
44 #include <sys/module.h>
45 #include <sys/mutex.h>
46 #include <sys/resource.h>
47 #include <sys/rman.h>
48 #include <sys/socket.h>
49
50 #include <net/ethernet.h>
51 #include <net/if.h>
52 #include <net/if_media.h>
53
54 #include <machine/bus.h>
55 #include <machine/resource.h>
56
57 #include <isa/isavar.h>
58
59 #include <dev/le/lancereg.h>
60 #include <dev/le/lancevar.h>
61 #include <dev/le/am7990var.h>
62
63 #define LE_CBUS_MEMSIZE (16*1024)
64 #define CNET98S_IOSIZE 32
65 #define CNET98S_RDP 0x10
66 #define CNET98S_RAP 0x12
67 #define CNET98S_RESET 0x14
68 #define CNET98S_BDP 0x16
69
70 struct le_cbus_softc {
71 struct am7990_softc sc_am7990; /* glue to MI code */
72
73 struct resource *sc_rres;
74
75 struct resource *sc_ires;
76 void *sc_ih;
77
78 bus_dma_tag_t sc_pdmat;
79 bus_dma_tag_t sc_dmat;
80 bus_dmamap_t sc_dmam;
81 };
82
83 static device_probe_t le_cbus_probe;
84 static device_attach_t le_cbus_attach;
85 static device_detach_t le_cbus_detach;
86 static device_resume_t le_cbus_resume;
87 static device_suspend_t le_cbus_suspend;
88
89 static device_method_t le_cbus_methods[] = {
90 /* Device interface */
91 DEVMETHOD(device_probe, le_cbus_probe),
92 DEVMETHOD(device_attach, le_cbus_attach),
93 DEVMETHOD(device_detach, le_cbus_detach),
94 /* We can just use the suspend method here. */
95 DEVMETHOD(device_shutdown, le_cbus_suspend),
96 DEVMETHOD(device_suspend, le_cbus_suspend),
97 DEVMETHOD(device_resume, le_cbus_resume),
98
99 { 0, 0 }
100 };
101
102 DEFINE_CLASS_0(le, le_cbus_driver, le_cbus_methods, sizeof(struct le_cbus_softc));
103 DRIVER_MODULE(le, isa, le_cbus_driver, le_devclass, 0, 0);
104 MODULE_DEPEND(le, ether, 1, 1, 1);
105
106 static bus_addr_t le_ioaddr_cnet98s[CNET98S_IOSIZE] = {
107 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007,
108 0x008, 0x009, 0x00a, 0x00b, 0x00c, 0x00d, 0x00e, 0x00f,
109 0x400, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407,
110 0x408, 0x409, 0x40a, 0x40b, 0x40c, 0x40d, 0x40e, 0x40f,
111 };
112
113 static void le_cbus_wrbcr(struct lance_softc *, uint16_t, uint16_t);
114 #ifdef LEDEBUG
115 static uint16_t le_cbus_rdbcr(struct lance_softc *, uint16_t);
116 #endif
117 static void le_cbus_wrcsr(struct lance_softc *, uint16_t, uint16_t);
118 static uint16_t le_cbus_rdcsr(struct lance_softc *, uint16_t);
119 static void le_cbus_hwreset(struct lance_softc *);
120 static bus_dmamap_callback_t le_cbus_dma_callback;
121
122 static void
123 le_cbus_wrbcr(struct lance_softc *sc, uint16_t port, uint16_t val)
124 {
125 struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
126
127 bus_write_2(lesc->sc_rres, CNET98S_RAP, port);
128 bus_barrier(lesc->sc_rres, CNET98S_RAP, 2, BUS_SPACE_BARRIER_WRITE);
129 bus_write_2(lesc->sc_rres, CNET98S_BDP, val);
130 }
131
132 #ifdef LEDEBUG
133 static uint16_t
134 le_cbus_rdbcr(struct lance_softc *sc, uint16_t port)
135 {
136 struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
137
138 bus_write_2(lesc->sc_rres, CNET98S_RAP, port);
139 bus_barrier(lesc->sc_rres, CNET98S_RAP, 2, BUS_SPACE_BARRIER_WRITE);
140 return (bus_read_2(lesc->sc_rres, CNET98S_BDP));
141 }
142 #endif
143
144 static void
145 le_cbus_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val)
146 {
147 struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
148
149 bus_write_2(lesc->sc_rres, CNET98S_RAP, port);
150 bus_barrier(lesc->sc_rres, CNET98S_RAP, 2, BUS_SPACE_BARRIER_WRITE);
151 bus_write_2(lesc->sc_rres, CNET98S_RDP, val);
152 }
153
154 static uint16_t
155 le_cbus_rdcsr(struct lance_softc *sc, uint16_t port)
156 {
157 struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
158
159 bus_write_2(lesc->sc_rres, CNET98S_RAP, port);
160 bus_barrier(lesc->sc_rres, CNET98S_RAP, 2, BUS_SPACE_BARRIER_WRITE);
161 return (bus_read_2(lesc->sc_rres, CNET98S_RDP));
162 }
163
164 static void
165 le_cbus_hwreset(struct lance_softc *sc)
166 {
167 struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
168
169 /*
170 * NB: These are Contec C-NET(98)S only.
171 */
172
173 /* Reset the chip. */
174 bus_write_2(lesc->sc_rres, CNET98S_RESET,
175 bus_read_2(lesc->sc_rres, CNET98S_RESET));
176 DELAY(500);
177
178 /* ISA bus configuration */
179 /* ISACSR0 - set Master Mode Read Active time to 300ns. */
180 le_cbus_wrbcr(sc, LE_BCR0, 0x0006);
181 /* ISACSR1 - set Master Mode Write Active time to 300ns. */
182 le_cbus_wrbcr(sc, LE_BCR1, 0x0006);
183 #ifdef LEDEBUG
184 device_printf(dev, "ISACSR2=0x%x\n", le_cbus_rdbcr(sc, LE_BCR2));
185 #endif
186 /* ISACSR5 - LED1 */
187 le_cbus_wrbcr(sc, LE_BCR5, LE_B4_PSE | LE_B4_XMTE);
188 /* ISACSR6 - LED2 */
189 le_cbus_wrbcr(sc, LE_BCR6, LE_B4_PSE | LE_B4_RCVE);
190 /* ISACSR7 - LED3 */
191 le_cbus_wrbcr(sc, LE_BCR7, LE_B4_PSE | LE_B4_COLE);
192 }
193
194 static void
195 le_cbus_dma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
196 {
197 struct lance_softc *sc = (struct lance_softc *)xsc;
198
199 if (error != 0)
200 return;
201 KASSERT(nsegs == 1, ("%s: bad DMA segment count", __func__));
202 sc->sc_addr = segs[0].ds_addr;
203 }
204
205 static int
206 le_cbus_probe(device_t dev)
207 {
208 struct le_cbus_softc *lesc;
209 struct lance_softc *sc;
210 int error, i;
211
212 /*
213 * Skip PnP devices as some wedge when trying to probe them as
214 * C-NET(98)S.
215 */
216 if (isa_get_vendorid(dev))
217 return (ENXIO);
218
219 lesc = device_get_softc(dev);
220 sc = &lesc->sc_am7990.lsc;
221
222 i = 0;
223 lesc->sc_rres = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &i,
224 le_ioaddr_cnet98s, CNET98S_IOSIZE, RF_ACTIVE);
225 if (lesc->sc_rres == NULL)
226 return (ENXIO);
227 isa_load_resourcev(lesc->sc_rres, le_ioaddr_cnet98s, CNET98S_IOSIZE);
228
229 /* Reset the chip. */
230 bus_write_2(lesc->sc_rres, CNET98S_RESET,
231 bus_read_2(lesc->sc_rres, CNET98S_RESET));
232 DELAY(500);
233
234 /* Stop the chip and put it in a known state. */
235 le_cbus_wrcsr(sc, LE_CSR0, LE_C0_STOP);
236 DELAY(100);
237 if (le_cbus_rdcsr(sc, LE_CSR0) != LE_C0_STOP) {
238 error = ENXIO;
239 goto fail;
240 }
241 le_cbus_wrcsr(sc, LE_CSR3, 0);
242 device_set_desc(dev, "C-NET(98)S");
243 error = BUS_PROBE_DEFAULT;
244
245 fail:
246 bus_release_resource(dev, SYS_RES_IOPORT,
247 rman_get_rid(lesc->sc_rres), lesc->sc_rres);
248 return (error);
249 }
250
251 static int
252 le_cbus_attach(device_t dev)
253 {
254 struct le_cbus_softc *lesc;
255 struct lance_softc *sc;
256 int error, i;
257
258 lesc = device_get_softc(dev);
259 sc = &lesc->sc_am7990.lsc;
260
261 LE_LOCK_INIT(sc, device_get_nameunit(dev));
262
263 i = 0;
264 lesc->sc_rres = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &i,
265 le_ioaddr_cnet98s, CNET98S_IOSIZE, RF_ACTIVE);
266 if (lesc->sc_rres == NULL) {
267 device_printf(dev, "cannot allocate registers\n");
268 error = ENXIO;
269 goto fail_mtx;
270 }
271 isa_load_resourcev(lesc->sc_rres, le_ioaddr_cnet98s, CNET98S_IOSIZE);
272
273 i = 0;
274 if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
275 &i, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
276 device_printf(dev, "cannot allocate interrupt\n");
277 error = ENXIO;
278 goto fail_rres;
279 }
280
281 error = bus_dma_tag_create(
282 bus_get_dma_tag(dev), /* parent */
283 1, 0, /* alignment, boundary */
284 BUS_SPACE_MAXADDR_24BIT, /* lowaddr */
285 BUS_SPACE_MAXADDR, /* highaddr */
286 NULL, NULL, /* filter, filterarg */
287 BUS_SPACE_MAXSIZE_32BIT, /* maxsize */
288 0, /* nsegments */
289 BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
290 0, /* flags */
291 NULL, NULL, /* lockfunc, lockarg */
292 &lesc->sc_pdmat);
293 if (error != 0) {
294 device_printf(dev, "cannot allocate parent DMA tag\n");
295 goto fail_ires;
296 }
297
298 sc->sc_memsize = LE_CBUS_MEMSIZE;
299 /*
300 * For Am79C90, Am79C961 and Am79C961A the init block must be 2-byte
301 * aligned and the ring descriptors must be 8-byte aligned.
302 */
303 error = bus_dma_tag_create(
304 lesc->sc_pdmat, /* parent */
305 8, 0, /* alignment, boundary */
306 BUS_SPACE_MAXADDR_24BIT, /* lowaddr */
307 BUS_SPACE_MAXADDR, /* highaddr */
308 NULL, NULL, /* filter, filterarg */
309 sc->sc_memsize, /* maxsize */
310 1, /* nsegments */
311 sc->sc_memsize, /* maxsegsize */
312 0, /* flags */
313 NULL, NULL, /* lockfunc, lockarg */
314 &lesc->sc_dmat);
315 if (error != 0) {
316 device_printf(dev, "cannot allocate buffer DMA tag\n");
317 goto fail_pdtag;
318 }
319
320 error = bus_dmamem_alloc(lesc->sc_dmat, (void **)&sc->sc_mem,
321 BUS_DMA_WAITOK | BUS_DMA_COHERENT, &lesc->sc_dmam);
322 if (error != 0) {
323 device_printf(dev, "cannot allocate DMA buffer memory\n");
324 goto fail_dtag;
325 }
326
327 sc->sc_addr = 0;
328 error = bus_dmamap_load(lesc->sc_dmat, lesc->sc_dmam, sc->sc_mem,
329 sc->sc_memsize, le_cbus_dma_callback, sc, 0);
330 if (error != 0 || sc->sc_addr == 0) {
331 device_printf(dev, "cannot load DMA buffer map\n");
332 goto fail_dmem;
333 }
334
335 sc->sc_flags = 0;
336 sc->sc_conf3 = 0;
337
338 /*
339 * Extract the physical MAC address from the ROM.
340 */
341 for (i = 0; i < sizeof(sc->sc_enaddr); i++)
342 sc->sc_enaddr[i] = bus_read_1(lesc->sc_rres, i * 2);
343
344 sc->sc_copytodesc = lance_copytobuf_contig;
345 sc->sc_copyfromdesc = lance_copyfrombuf_contig;
346 sc->sc_copytobuf = lance_copytobuf_contig;
347 sc->sc_copyfrombuf = lance_copyfrombuf_contig;
348 sc->sc_zerobuf = lance_zerobuf_contig;
349
350 sc->sc_rdcsr = le_cbus_rdcsr;
351 sc->sc_wrcsr = le_cbus_wrcsr;
352 sc->sc_hwreset = le_cbus_hwreset;
353 sc->sc_hwinit = NULL;
354 sc->sc_hwintr = NULL;
355 sc->sc_nocarrier = NULL;
356 sc->sc_mediachange = NULL;
357 sc->sc_mediastatus = NULL;
358 sc->sc_supmedia = NULL;
359
360 error = am7990_config(&lesc->sc_am7990, device_get_name(dev),
361 device_get_unit(dev));
362 if (error != 0) {
363 device_printf(dev, "cannot attach Am7990\n");
364 goto fail_dmap;
365 }
366
367 error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE,
368 NULL, am7990_intr, sc, &lesc->sc_ih);
369 if (error != 0) {
370 device_printf(dev, "cannot set up interrupt\n");
371 goto fail_am7990;
372 }
373
374 return (0);
375
376 fail_am7990:
377 am7990_detach(&lesc->sc_am7990);
378 fail_dmap:
379 bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
380 fail_dmem:
381 bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
382 fail_dtag:
383 bus_dma_tag_destroy(lesc->sc_dmat);
384 fail_pdtag:
385 bus_dma_tag_destroy(lesc->sc_pdmat);
386 fail_ires:
387 bus_release_resource(dev, SYS_RES_IRQ,
388 rman_get_rid(lesc->sc_ires), lesc->sc_ires);
389 fail_rres:
390 bus_release_resource(dev, SYS_RES_IOPORT,
391 rman_get_rid(lesc->sc_rres), lesc->sc_rres);
392 fail_mtx:
393 LE_LOCK_DESTROY(sc);
394 return (error);
395 }
396
397 static int
398 le_cbus_detach(device_t dev)
399 {
400 struct le_cbus_softc *lesc;
401 struct lance_softc *sc;
402
403 lesc = device_get_softc(dev);
404 sc = &lesc->sc_am7990.lsc;
405
406 bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih);
407 am7990_detach(&lesc->sc_am7990);
408 bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
409 bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
410 bus_dma_tag_destroy(lesc->sc_dmat);
411 bus_dma_tag_destroy(lesc->sc_pdmat);
412 bus_release_resource(dev, SYS_RES_IRQ,
413 rman_get_rid(lesc->sc_ires), lesc->sc_ires);
414 bus_release_resource(dev, SYS_RES_IOPORT,
415 rman_get_rid(lesc->sc_rres), lesc->sc_rres);
416 LE_LOCK_DESTROY(sc);
417
418 return (0);
419 }
420
421 static int
422 le_cbus_suspend(device_t dev)
423 {
424 struct le_cbus_softc *lesc;
425
426 lesc = device_get_softc(dev);
427
428 lance_suspend(&lesc->sc_am7990.lsc);
429
430 return (0);
431 }
432
433 static int
434 le_cbus_resume(device_t dev)
435 {
436 struct le_cbus_softc *lesc;
437
438 lesc = device_get_softc(dev);
439
440 lance_resume(&lesc->sc_am7990.lsc);
441
442 return (0);
443 }
Cache object: f716480f6f815e23baaffe8193ee6f08
|