]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/dev/le/if_le_cbus.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / dev / le / if_le_cbus.c
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 }