source: libbsdport/bsd_eth_drivers/if_le/if_le_cbus.c @ a8bf95d

B_20100615baselibbsdport-4-10-branch
Last change on this file since a8bf95d was a8bf95d, checked in by Till Straumann <strauman@…>, on Apr 22, 2009 at 10:06:58 PM
  • importing updated version from SLAC as of 20090422
  • Property mode set to 100644
File size: 13.0 KB
Line 
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: src/sys/dev/le/if_le_cbus.c,v 1.5 2007/02/23 12:18:45 piso Exp $");
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
70struct 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
87static device_probe_t le_cbus_probe;
88static device_attach_t le_cbus_attach;
89static device_detach_t le_cbus_detach;
90static device_resume_t le_cbus_resume;
91static device_suspend_t le_cbus_suspend;
92
93static 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
106DEFINE_CLASS_0(le, le_cbus_driver, le_cbus_methods, sizeof(struct le_cbus_softc));
107DRIVER_MODULE(le, isa, le_cbus_driver, le_devclass, 0, 0);
108MODULE_DEPEND(le, ether, 1, 1, 1);
109
110static 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
117static void le_cbus_wrbcr(struct lance_softc *, uint16_t, uint16_t);
118#ifdef LEDEBUG
119static uint16_t le_cbus_rdbcr(struct lance_softc *, uint16_t);
120#endif
121static void le_cbus_wrcsr(struct lance_softc *, uint16_t, uint16_t);
122static uint16_t le_cbus_rdcsr(struct lance_softc *, uint16_t);
123static void le_cbus_hwreset(struct lance_softc *);
124static bus_dmamap_callback_t le_cbus_dma_callback;
125
126static void
127le_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
138static uint16_t
139le_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
150static void
151le_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
161static uint16_t
162le_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
172static void
173le_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
202static void
203le_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
213static int
214le_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
260static int
261le_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
407static int
408le_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
429static int
430le_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
441static int
442le_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}
Note: See TracBrowser for help on using the repository browser.