if_le_cbus.c revision 158829
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: head/sys/dev/le/if_le_cbus.c 158829 2006-05-22 13:43:36Z nyan $");
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	    NULL,			/* 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	    BUS_DMA_WAITOK,		/* 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	    BUS_DMA_WAITOK,		/* 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	    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}
452