Ignore machine-check MSRs
[freebsd-src/fkvm-freebsd.git] / sys / dev / le / if_le_cbus.c
blob18026bd97e516f50bed8dbd6e3c0b23573aabec4
1 /*-
2 * Copyright (c) 1994-2000
3 * Paul Richards. All rights reserved.
5 * PC-98 port by Chiharu Shibata & FreeBSD(98) porting team.
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.
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.
32 * from: FreeBSD: src/sys/dev/lnc/if_lnc_cbus.c,v 1.12 2005/11/12 19:14:21
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
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>
50 #include <net/ethernet.h>
51 #include <net/if.h>
52 #include <net/if_media.h>
54 #include <machine/bus.h>
55 #include <machine/resource.h>
57 #include <isa/isavar.h>
59 #include <dev/le/lancereg.h>
60 #include <dev/le/lancevar.h>
61 #include <dev/le/am7990var.h>
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
70 struct le_cbus_softc {
71 struct am7990_softc sc_am7990; /* glue to MI code */
73 int sc_rrid;
74 struct resource *sc_rres;
75 bus_space_tag_t sc_regt;
76 bus_space_handle_t sc_regh;
78 int sc_irid;
79 struct resource *sc_ires;
80 void *sc_ih;
82 bus_dma_tag_t sc_pdmat;
83 bus_dma_tag_t sc_dmat;
84 bus_dmamap_t sc_dmam;
87 static device_probe_t le_cbus_probe;
88 static device_attach_t le_cbus_attach;
89 static device_detach_t le_cbus_detach;
90 static device_resume_t le_cbus_resume;
91 static device_suspend_t le_cbus_suspend;
93 static device_method_t le_cbus_methods[] = {
94 /* Device interface */
95 DEVMETHOD(device_probe, le_cbus_probe),
96 DEVMETHOD(device_attach, le_cbus_attach),
97 DEVMETHOD(device_detach, le_cbus_detach),
98 /* We can just use the suspend method here. */
99 DEVMETHOD(device_shutdown, le_cbus_suspend),
100 DEVMETHOD(device_suspend, le_cbus_suspend),
101 DEVMETHOD(device_resume, le_cbus_resume),
103 { 0, 0 }
106 DEFINE_CLASS_0(le, le_cbus_driver, le_cbus_methods, sizeof(struct le_cbus_softc));
107 DRIVER_MODULE(le, isa, le_cbus_driver, le_devclass, 0, 0);
108 MODULE_DEPEND(le, ether, 1, 1, 1);
110 static bus_addr_t le_ioaddr_cnet98s[CNET98S_IOSIZE] = {
111 0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007,
112 0x008, 0x009, 0x00a, 0x00b, 0x00c, 0x00d, 0x00e, 0x00f,
113 0x400, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407,
114 0x408, 0x409, 0x40a, 0x40b, 0x40c, 0x40d, 0x40e, 0x40f,
117 static void le_cbus_wrbcr(struct lance_softc *, uint16_t, uint16_t);
118 #ifdef LEDEBUG
119 static uint16_t le_cbus_rdbcr(struct lance_softc *, uint16_t);
120 #endif
121 static void le_cbus_wrcsr(struct lance_softc *, uint16_t, uint16_t);
122 static uint16_t le_cbus_rdcsr(struct lance_softc *, uint16_t);
123 static void le_cbus_hwreset(struct lance_softc *);
124 static bus_dmamap_callback_t le_cbus_dma_callback;
126 static void
127 le_cbus_wrbcr(struct lance_softc *sc, uint16_t port, uint16_t val)
129 struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
131 bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, port);
132 bus_space_barrier(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, 2,
133 BUS_SPACE_BARRIER_WRITE);
134 bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_BDP, val);
137 #ifdef LEDEBUG
138 static uint16_t
139 le_cbus_rdbcr(struct lance_softc *sc, uint16_t port)
141 struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
143 bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, port);
144 bus_space_barrier(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, 2,
145 BUS_SPACE_BARRIER_WRITE);
146 return (bus_space_read_2(lesc->sc_regt, lesc->sc_regh, CNET98S_BDP));
148 #endif
150 static void
151 le_cbus_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val)
153 struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
155 bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, port);
156 bus_space_barrier(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, 2,
157 BUS_SPACE_BARRIER_WRITE);
158 bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RDP, val);
161 static uint16_t
162 le_cbus_rdcsr(struct lance_softc *sc, uint16_t port)
164 struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
166 bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, port);
167 bus_space_barrier(lesc->sc_regt, lesc->sc_regh, CNET98S_RAP, 2,
168 BUS_SPACE_BARRIER_WRITE);
169 return (bus_space_read_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RDP));
172 static void
173 le_cbus_hwreset(struct lance_softc *sc)
175 struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
178 * NB: These are Contec C-NET(98)S only.
181 /* Reset the chip. */
182 bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RESET,
183 bus_space_read_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RESET));
184 DELAY(500);
186 /* ISA bus configuration */
187 /* ISACSR0 - set Master Mode Read Active time to 300ns. */
188 le_cbus_wrbcr(sc, LE_BCR0, 0x0006);
189 /* ISACSR1 - set Master Mode Write Active time to 300ns. */
190 le_cbus_wrbcr(sc, LE_BCR1, 0x0006);
191 #ifdef LEDEBUG
192 device_printf(dev, "ISACSR2=0x%x\n", le_cbus_rdbcr(sc, LE_BCR2));
193 #endif
194 /* ISACSR5 - LED1 */
195 le_cbus_wrbcr(sc, LE_BCR5, LE_B4_PSE | LE_B4_XMTE);
196 /* ISACSR6 - LED2 */
197 le_cbus_wrbcr(sc, LE_BCR6, LE_B4_PSE | LE_B4_RCVE);
198 /* ISACSR7 - LED3 */
199 le_cbus_wrbcr(sc, LE_BCR7, LE_B4_PSE | LE_B4_COLE);
202 static void
203 le_cbus_dma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
205 struct lance_softc *sc = (struct lance_softc *)xsc;
207 if (error != 0)
208 return;
209 KASSERT(nsegs == 1, ("%s: bad DMA segment count", __func__));
210 sc->sc_addr = segs[0].ds_addr;
213 static int
214 le_cbus_probe(device_t dev)
216 struct le_cbus_softc *lesc;
217 struct lance_softc *sc;
218 int error;
221 * Skip PnP devices as some wedge when trying to probe them as
222 * C-NET(98)S.
224 if (isa_get_vendorid(dev))
225 return (ENXIO);
227 lesc = device_get_softc(dev);
228 sc = &lesc->sc_am7990.lsc;
230 lesc->sc_rrid = 0;
231 lesc->sc_rres = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &lesc->sc_rrid,
232 le_ioaddr_cnet98s, CNET98S_IOSIZE, RF_ACTIVE);
233 if (lesc->sc_rres == NULL)
234 return (ENXIO);
235 isa_load_resourcev(lesc->sc_rres, le_ioaddr_cnet98s, CNET98S_IOSIZE);
236 lesc->sc_regt = rman_get_bustag(lesc->sc_rres);
237 lesc->sc_regh = rman_get_bushandle(lesc->sc_rres);
239 /* Reset the chip. */
240 bus_space_write_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RESET,
241 bus_space_read_2(lesc->sc_regt, lesc->sc_regh, CNET98S_RESET));
242 DELAY(500);
244 /* Stop the chip and put it in a known state. */
245 le_cbus_wrcsr(sc, LE_CSR0, LE_C0_STOP);
246 DELAY(100);
247 if (le_cbus_rdcsr(sc, LE_CSR0) != LE_C0_STOP) {
248 error = ENXIO;
249 goto fail;
251 le_cbus_wrcsr(sc, LE_CSR3, 0);
252 device_set_desc(dev, "C-NET(98)S");
253 error = BUS_PROBE_DEFAULT;
255 fail:
256 bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres);
257 return (error);
260 static int
261 le_cbus_attach(device_t dev)
263 struct le_cbus_softc *lesc;
264 struct lance_softc *sc;
265 int error, i;
267 lesc = device_get_softc(dev);
268 sc = &lesc->sc_am7990.lsc;
270 LE_LOCK_INIT(sc, device_get_nameunit(dev));
272 lesc->sc_rrid = 0;
273 lesc->sc_rres = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &lesc->sc_rrid,
274 le_ioaddr_cnet98s, CNET98S_IOSIZE, RF_ACTIVE);
275 if (lesc->sc_rres == NULL) {
276 device_printf(dev, "cannot allocate registers\n");
277 error = ENXIO;
278 goto fail_mtx;
280 isa_load_resourcev(lesc->sc_rres, le_ioaddr_cnet98s, CNET98S_IOSIZE);
281 lesc->sc_regt = rman_get_bustag(lesc->sc_rres);
282 lesc->sc_regh = rman_get_bushandle(lesc->sc_rres);
284 lesc->sc_irid = 0;
285 if ((lesc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
286 &lesc->sc_irid, RF_SHAREABLE | RF_ACTIVE)) == NULL) {
287 device_printf(dev, "cannot allocate interrupt\n");
288 error = ENXIO;
289 goto fail_rres;
292 error = bus_dma_tag_create(
293 bus_get_dma_tag(dev), /* parent */
294 1, 0, /* alignment, boundary */
295 BUS_SPACE_MAXADDR_24BIT, /* lowaddr */
296 BUS_SPACE_MAXADDR, /* highaddr */
297 NULL, NULL, /* filter, filterarg */
298 BUS_SPACE_MAXSIZE_32BIT, /* maxsize */
299 0, /* nsegments */
300 BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */
301 0, /* flags */
302 NULL, NULL, /* lockfunc, lockarg */
303 &lesc->sc_pdmat);
304 if (error != 0) {
305 device_printf(dev, "cannot allocate parent DMA tag\n");
306 goto fail_ires;
309 sc->sc_memsize = LE_CBUS_MEMSIZE;
311 * For Am79C90, Am79C961 and Am79C961A the init block must be 2-byte
312 * aligned and the ring descriptors must be 8-byte aligned.
314 error = bus_dma_tag_create(
315 lesc->sc_pdmat, /* parent */
316 8, 0, /* alignment, boundary */
317 BUS_SPACE_MAXADDR_24BIT, /* lowaddr */
318 BUS_SPACE_MAXADDR, /* highaddr */
319 NULL, NULL, /* filter, filterarg */
320 sc->sc_memsize, /* maxsize */
321 1, /* nsegments */
322 sc->sc_memsize, /* maxsegsize */
323 0, /* flags */
324 NULL, NULL, /* lockfunc, lockarg */
325 &lesc->sc_dmat);
326 if (error != 0) {
327 device_printf(dev, "cannot allocate buffer DMA tag\n");
328 goto fail_pdtag;
331 error = bus_dmamem_alloc(lesc->sc_dmat, (void **)&sc->sc_mem,
332 BUS_DMA_WAITOK | BUS_DMA_COHERENT, &lesc->sc_dmam);
333 if (error != 0) {
334 device_printf(dev, "cannot allocate DMA buffer memory\n");
335 goto fail_dtag;
338 sc->sc_addr = 0;
339 error = bus_dmamap_load(lesc->sc_dmat, lesc->sc_dmam, sc->sc_mem,
340 sc->sc_memsize, le_cbus_dma_callback, sc, 0);
341 if (error != 0 || sc->sc_addr == 0) {
342 device_printf(dev, "cannot load DMA buffer map\n");
343 goto fail_dmem;
346 sc->sc_flags = 0;
347 sc->sc_conf3 = 0;
350 * Extract the physical MAC address from the ROM.
352 for (i = 0; i < sizeof(sc->sc_enaddr); i++)
353 sc->sc_enaddr[i] = bus_space_read_1(lesc->sc_regt,
354 lesc->sc_regh, i * 2);
356 sc->sc_copytodesc = lance_copytobuf_contig;
357 sc->sc_copyfromdesc = lance_copyfrombuf_contig;
358 sc->sc_copytobuf = lance_copytobuf_contig;
359 sc->sc_copyfrombuf = lance_copyfrombuf_contig;
360 sc->sc_zerobuf = lance_zerobuf_contig;
362 sc->sc_rdcsr = le_cbus_rdcsr;
363 sc->sc_wrcsr = le_cbus_wrcsr;
364 sc->sc_hwreset = le_cbus_hwreset;
365 sc->sc_hwinit = NULL;
366 sc->sc_hwintr = NULL;
367 sc->sc_nocarrier = NULL;
368 sc->sc_mediachange = NULL;
369 sc->sc_mediastatus = NULL;
370 sc->sc_supmedia = NULL;
372 error = am7990_config(&lesc->sc_am7990, device_get_name(dev),
373 device_get_unit(dev));
374 if (error != 0) {
375 device_printf(dev, "cannot attach Am7990\n");
376 goto fail_dmap;
379 error = bus_setup_intr(dev, lesc->sc_ires, INTR_TYPE_NET | INTR_MPSAFE,
380 NULL, am7990_intr, sc, &lesc->sc_ih);
381 if (error != 0) {
382 device_printf(dev, "cannot set up interrupt\n");
383 goto fail_am7990;
386 return (0);
388 fail_am7990:
389 am7990_detach(&lesc->sc_am7990);
390 fail_dmap:
391 bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
392 fail_dmem:
393 bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
394 fail_dtag:
395 bus_dma_tag_destroy(lesc->sc_dmat);
396 fail_pdtag:
397 bus_dma_tag_destroy(lesc->sc_pdmat);
398 fail_ires:
399 bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires);
400 fail_rres:
401 bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres);
402 fail_mtx:
403 LE_LOCK_DESTROY(sc);
404 return (error);
407 static int
408 le_cbus_detach(device_t dev)
410 struct le_cbus_softc *lesc;
411 struct lance_softc *sc;
413 lesc = device_get_softc(dev);
414 sc = &lesc->sc_am7990.lsc;
416 bus_teardown_intr(dev, lesc->sc_ires, lesc->sc_ih);
417 am7990_detach(&lesc->sc_am7990);
418 bus_dmamap_unload(lesc->sc_dmat, lesc->sc_dmam);
419 bus_dmamem_free(lesc->sc_dmat, sc->sc_mem, lesc->sc_dmam);
420 bus_dma_tag_destroy(lesc->sc_dmat);
421 bus_dma_tag_destroy(lesc->sc_pdmat);
422 bus_release_resource(dev, SYS_RES_IRQ, lesc->sc_irid, lesc->sc_ires);
423 bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres);
424 LE_LOCK_DESTROY(sc);
426 return (0);
429 static int
430 le_cbus_suspend(device_t dev)
432 struct le_cbus_softc *lesc;
434 lesc = device_get_softc(dev);
436 lance_suspend(&lesc->sc_am7990.lsc);
438 return (0);
441 static int
442 le_cbus_resume(device_t dev)
444 struct le_cbus_softc *lesc;
446 lesc = device_get_softc(dev);
448 lance_resume(&lesc->sc_am7990.lsc);
450 return (0);