]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/le/if_le_cbus.c
This commit was generated by cvs2svn to compensate for changes in r171831,
[FreeBSD/FreeBSD.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         int                     sc_rrid;
74         struct resource         *sc_rres;
75         bus_space_tag_t         sc_regt;
76         bus_space_handle_t      sc_regh;
77
78         int                     sc_irid;
79         struct resource         *sc_ires;
80         void                    *sc_ih;
81
82         bus_dma_tag_t           sc_pdmat;
83         bus_dma_tag_t           sc_dmat;
84         bus_dmamap_t            sc_dmam;
85 };
86
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;
92
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),
102
103         { 0, 0 }
104 };
105
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);
109
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,
115 };
116
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;
125
126 static void
127 le_cbus_wrbcr(struct lance_softc *sc, uint16_t port, uint16_t val)
128 {
129         struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
130
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);
135 }
136
137 #ifdef LEDEBUG
138 static uint16_t
139 le_cbus_rdbcr(struct lance_softc *sc, uint16_t port)
140 {
141         struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
142
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));
147 }
148 #endif
149
150 static void
151 le_cbus_wrcsr(struct lance_softc *sc, uint16_t port, uint16_t val)
152 {
153         struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
154
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);
159 }
160
161 static uint16_t
162 le_cbus_rdcsr(struct lance_softc *sc, uint16_t port)
163 {
164         struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
165
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));
170 }
171
172 static void
173 le_cbus_hwreset(struct lance_softc *sc)
174 {
175         struct le_cbus_softc *lesc = (struct le_cbus_softc *)sc;
176
177         /*
178          * NB: These are Contec C-NET(98)S only.
179          */
180
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);
185
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);
200 }
201
202 static void
203 le_cbus_dma_callback(void *xsc, bus_dma_segment_t *segs, int nsegs, int error)
204 {
205         struct lance_softc *sc = (struct lance_softc *)xsc;
206
207         if (error != 0)
208                 return;
209         KASSERT(nsegs == 1, ("%s: bad DMA segment count", __func__));
210         sc->sc_addr = segs[0].ds_addr;
211 }
212
213 static int
214 le_cbus_probe(device_t dev)
215 {
216         struct le_cbus_softc *lesc;
217         struct lance_softc *sc;
218         int error;
219
220         /*
221          * Skip PnP devices as some wedge when trying to probe them as
222          * C-NET(98)S.
223          */
224         if (isa_get_vendorid(dev))
225                 return (ENXIO);
226
227         lesc = device_get_softc(dev);
228         sc = &lesc->sc_am7990.lsc;
229
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);
238
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);
243
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;
250         }
251         le_cbus_wrcsr(sc, LE_CSR3, 0);
252         device_set_desc(dev, "C-NET(98)S");
253         error = BUS_PROBE_DEFAULT;
254
255  fail:
256         bus_release_resource(dev, SYS_RES_IOPORT, lesc->sc_rrid, lesc->sc_rres);
257         return (error);
258 }
259
260 static int
261 le_cbus_attach(device_t dev)
262 {
263         struct le_cbus_softc *lesc;
264         struct lance_softc *sc;
265         int error, i;
266
267         lesc = device_get_softc(dev);
268         sc = &lesc->sc_am7990.lsc;
269
270         LE_LOCK_INIT(sc, device_get_nameunit(dev));
271
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;
279         }
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);
283
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;
290         }
291
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;
307         }
308
309         sc->sc_memsize = LE_CBUS_MEMSIZE;
310         /*
311          * For Am79C90, Am79C961 and Am79C961A the init block must be 2-byte
312          * aligned and the ring descriptors must be 8-byte aligned.
313          */
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;
329         }
330
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;
336         }
337
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;
344         }
345
346         sc->sc_flags = 0;
347         sc->sc_conf3 = 0;
348
349         /*
350          * Extract the physical MAC address from the ROM.
351          */
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);
355
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;
361
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;
371
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;
377         }
378
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;
384         }
385
386         return (0);
387
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);
405 }
406
407 static int
408 le_cbus_detach(device_t dev)
409 {
410         struct le_cbus_softc *lesc;
411         struct lance_softc *sc;
412
413         lesc = device_get_softc(dev);
414         sc = &lesc->sc_am7990.lsc;
415
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);
425
426         return (0);
427 }
428
429 static int
430 le_cbus_suspend(device_t dev)
431 {
432         struct le_cbus_softc *lesc;
433
434         lesc = device_get_softc(dev);
435
436         lance_suspend(&lesc->sc_am7990.lsc);
437
438         return (0);
439 }
440
441 static int
442 le_cbus_resume(device_t dev)
443 {
444         struct le_cbus_softc *lesc;
445
446         lesc = device_get_softc(dev);
447
448         lance_resume(&lesc->sc_am7990.lsc);
449
450         return (0);
451 }