if_fea.c revision 49360
1/*-
2 * Copyright (c) 1995, 1996 Matt Thomas <matt@3am-software.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. The name of the author may not be used to endorse or promote products
11 *    derived from this software withough specific prior written permission
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * $Id: if_fea.c,v 1.16 1999/07/31 00:43:48 mdodd Exp $
25 */
26
27/*
28 * DEC PDQ FDDI Controller
29 *
30 *	This module support the DEFEA EISA FDDI Controller.
31 */
32
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/kernel.h>
36#include <sys/socket.h>
37
38#include <net/if.h>
39#include <net/if_arp.h>
40
41#include <sys/module.h>
42#include <sys/bus.h>
43#include <machine/bus.h>
44#include <machine/resource.h>
45#include <sys/rman.h>
46#include <i386/eisa/eisaconf.h>
47#include <dev/pdq/pdqvar.h>
48#include <dev/pdq/pdqreg.h>
49
50static void		pdq_eisa_subprobe	__P((pdq_bus_t, u_int32_t, u_int32_t *, u_int32_t *, u_int32_t *));
51static void		pdq_eisa_devinit	__P((pdq_softc_t *));
52static const char *	pdq_eisa_match		__P((eisa_id_t));
53static int 		pdq_eisa_probe		__P((device_t));
54static int		pdq_eisa_attach		__P((device_t));
55void			pdq_eisa_intr		__P((void *));
56static int		pdq_eisa_shutdown	__P((device_t));
57
58#define	DEFEA_IRQS			0x0000FBA9U
59
60#define	DEFEA_INTRENABLE		0x8	/* level interrupt */
61#define	DEFEA_DECODE_IRQ(n)		((DEFEA_IRQS >> ((n) << 2)) & 0x0f)
62
63#define EISA_DEVICE_ID_DEC_DEC3001	0x10a33001
64#define EISA_DEVICE_ID_DEC_DEC3002	0x10a33002
65#define EISA_DEVICE_ID_DEC_DEC3003	0x10a33003
66#define EISA_DEVICE_ID_DEC_DEC3004	0x10a33004
67
68static void
69pdq_eisa_subprobe(bc, iobase, maddr, msize, irq)
70	pdq_bus_t	bc;
71	u_int32_t	iobase;
72	u_int32_t	*maddr;
73	u_int32_t	*msize;
74	u_int32_t	*irq;
75{
76	if (irq != NULL)
77		*irq = DEFEA_DECODE_IRQ(PDQ_OS_IORD_8(bc, iobase, PDQ_EISA_IO_CONFIG_STAT_0) & 3);
78	*maddr = (PDQ_OS_IORD_8(bc, iobase, PDQ_EISA_MEM_ADD_CMP_0) << 8)
79		 | (PDQ_OS_IORD_8(bc, iobase, PDQ_EISA_MEM_ADD_CMP_1) << 16);
80	*msize = (PDQ_OS_IORD_8(bc, iobase, PDQ_EISA_MEM_ADD_MASK_0) + 4) << 8;
81
82	return;
83}
84
85static void
86pdq_eisa_devinit (sc)
87	pdq_softc_t	*sc;
88{
89	pdq_uint8_t	data;
90
91	/*
92	 * Do the standard initialization for the DEFEA registers.
93	 */
94	PDQ_OS_IOWR_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_FUNCTION_CTRL, 0x23);
95	PDQ_OS_IOWR_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_IO_CMP_1_1, (sc->sc_iobase >> 8) & 0xF0);
96	PDQ_OS_IOWR_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_IO_CMP_0_1, (sc->sc_iobase >> 8) & 0xF0);
97	PDQ_OS_IOWR_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_SLOT_CTRL, 0x01);
98	data = PDQ_OS_IORD_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_BURST_HOLDOFF);
99#if defined(PDQ_IOMAPPED)
100	PDQ_OS_IOWR_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_BURST_HOLDOFF, data & ~1);
101#else
102	PDQ_OS_IOWR_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_BURST_HOLDOFF, data | 1);
103#endif
104	data = PDQ_OS_IORD_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_IO_CONFIG_STAT_0);
105	PDQ_OS_IOWR_8(sc->sc_bc, sc->sc_iobase, PDQ_EISA_IO_CONFIG_STAT_0, data | DEFEA_INTRENABLE);
106
107	return;
108}
109
110static const char *
111pdq_eisa_match (type)
112	eisa_id_t	type;
113{
114	switch (type) {
115		case EISA_DEVICE_ID_DEC_DEC3001:
116		case EISA_DEVICE_ID_DEC_DEC3002:
117		case EISA_DEVICE_ID_DEC_DEC3003:
118		case EISA_DEVICE_ID_DEC_DEC3004:
119			return ("DEC FDDIcontroller/EISA Adapter");
120			break;
121		 default:
122			break;
123	}
124	return (NULL);
125}
126
127static int
128pdq_eisa_probe (dev)
129	device_t	dev;
130{
131	const char	*desc;
132	u_int32_t	iobase;
133	u_int32_t	irq;
134	u_int32_t	maddr;
135	u_int32_t	msize;
136
137	u_int32_t	eisa_id = eisa_get_id(dev);;
138
139	desc = pdq_eisa_match(eisa_id);
140	if (!desc) {
141		return (ENXIO);
142	}
143
144	device_set_desc(dev, desc);
145
146	iobase = eisa_get_slot(dev) * EISA_SLOT_SIZE;
147	pdq_eisa_subprobe(PDQ_BUS_EISA, iobase, &maddr, &msize, &irq);
148
149	eisa_add_iospace(dev, iobase, 0x200, RESVADDR_NONE);
150	eisa_add_mspace(dev, maddr, msize, RESVADDR_NONE);
151	eisa_add_intr(dev, irq, EISA_TRIGGER_LEVEL);
152
153	return (0);
154}
155
156void
157pdq_eisa_intr(xdev)
158	void		*xdev;
159{
160	device_t	dev = (device_t) xdev;
161	pdq_softc_t	*sc = device_get_softc(dev);
162	(void) pdq_interrupt(sc->sc_pdq);
163
164	return;
165}
166
167static int
168pdq_eisa_attach (dev)
169	device_t		dev;
170{
171	pdq_softc_t		*sc = device_get_softc(dev);
172	struct resource		*io = 0;
173	struct resource		*irq = 0;
174	struct resource		*mspace = 0;
175	int			rid;
176	void			*ih;
177	u_int32_t		m_addr, m_size;
178
179	rid = 0;
180	io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
181				0, ~0, 1, RF_ACTIVE);
182
183	if (!io) {
184		device_printf(dev, "No I/O space?!\n");
185		goto bad;
186	}
187
188	rid = 0;
189	mspace = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
190				    0, ~0, 1, RF_ACTIVE);
191
192	if (!mspace) {
193		device_printf(dev, "No memory space?!\n");
194		goto bad;
195	}
196
197	rid = 0;
198	irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
199				 0, ~0, 1, RF_ACTIVE);
200
201	if (!irq) {
202		device_printf(dev, "No, irq?!\n");
203		goto bad;
204	}
205
206	m_addr = rman_get_start(mspace);
207 	m_size = (rman_get_end(mspace) - rman_get_start(mspace)) + 1;
208
209	sc->sc_iobase = (pdq_bus_ioport_t) rman_get_start(io);
210	sc->sc_membase = (pdq_bus_memaddr_t) pmap_mapdev(m_addr, m_size);
211	sc->sc_if.if_name = "fea";
212	sc->sc_if.if_unit = device_get_unit(dev);
213
214	pdq_eisa_devinit(sc);
215	sc->sc_pdq = pdq_initialize(PDQ_BUS_EISA, sc->sc_membase,
216				    sc->sc_if.if_name, sc->sc_if.if_unit,
217				    (void *) sc, PDQ_DEFEA);
218	if (sc->sc_pdq == NULL) {
219		device_printf(dev, "initialization failed\n");
220		goto bad;
221	}
222
223	if (bus_setup_intr(dev, irq, INTR_TYPE_NET, pdq_eisa_intr, dev, &ih)) {
224		goto bad;
225	}
226
227	bcopy((caddr_t) sc->sc_pdq->pdq_hwaddr.lanaddr_bytes, sc->sc_ac.ac_enaddr, 6);
228	pdq_ifattach(sc, NULL);
229
230	return (0);
231
232bad:
233	if (io)
234		bus_release_resource(dev, SYS_RES_IOPORT, 0, io);
235	if (irq)
236		bus_release_resource(dev, SYS_RES_IRQ, 0, irq);
237	if (mspace)
238		bus_release_resource(dev, SYS_RES_MEMORY, 0, mspace);
239
240	return (-1);
241}
242
243static int
244pdq_eisa_shutdown(dev)
245	device_t	dev;
246{
247	pdq_softc_t	*sc = device_get_softc(dev);
248
249	pdq_hwreset(sc->sc_pdq);
250
251	return (0);
252}
253
254static device_method_t pdq_eisa_methods[] = {
255	DEVMETHOD(device_probe,		pdq_eisa_probe),
256	DEVMETHOD(device_attach,	pdq_eisa_attach),
257	DEVMETHOD(device_shutdown,      pdq_eisa_shutdown),
258
259	{ 0, 0 }
260};
261
262static driver_t pdq_eisa_driver = {
263	"fea",
264	pdq_eisa_methods,
265	sizeof(pdq_softc_t),
266};
267
268static devclass_t pdq_devclass;
269
270DRIVER_MODULE(pdq, eisa, pdq_eisa_driver, pdq_devclass, 0, 0);
271