if_ntwoc_pci.c revision 1.1
1/*	$Id: if_ntwoc_pci.c,v 1.1 1998/07/26 03:28:28 explorer Exp $	*/
2
3/*
4 * Copyright (c) 1998 Vixie Enterprises
5 * All rights reserved.
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 *
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of Vixie Enterprises nor the names
17 *    of its contributors may be used to endorse or promote products derived
18 *    from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY VIXIE ENTERPRISES AND
21 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
22 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED.  IN NO EVENT SHALL VIXIE ENTERPRISES OR
25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * This software has been written for Vixie Enterprises by Michael Graff
35 * <explorer@flame.org>.  To learn more about Vixie Enterprises, see
36 * ``http://www.vix.com''.
37 */
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/device.h>
42#include <sys/mbuf.h>
43#include <sys/socket.h>
44
45#include <net/if.h>
46
47#include <machine/cpu.h>
48#include <machine/bus.h>
49#include <machine/intr.h>
50
51#include <dev/pci/pcivar.h>
52#include <dev/pci/pcireg.h>
53#include <dev/pci/pcidevs.h>
54
55#include <dev/ic/hd64570reg.h>
56#include <dev/ic/hd64570var.h>
57
58#include <dev/pci/if_ntwoc_pcireg.h>
59
60#if 0
61#define NTWO_DEBUG
62#endif
63
64#ifdef NTWO_DEBUG
65#define NTWO_DPRINTF(x) printf x
66#else
67#define NTWO_DPRINTF(x)
68#endif
69
70/*
71 * Card specific config register location
72 */
73#define PCI_CBMA_ASIC	0x10	/* Configuration Base Memory Address */
74#define PCI_CBMA_SCA	0x18
75
76struct ntwoc_pci_softc {
77	/* Generic device stuff */
78	struct device sc_dev;		/* Common to all devices */
79
80	/* PCI chipset glue */
81	pci_intr_handle_t *sc_ih;	/* Interrupt handler */
82	pci_chipset_tag_t sc_sr;	/* PCI chipset handle */
83
84	bus_space_tag_t sc_asic_iot;	/* space cookie (for ASIC) */
85	bus_space_handle_t sc_asic_ioh;	/* bus space handle (for ASIC) */
86
87	struct sca_softc sc_sca;	/* the SCA itself */
88};
89
90static  int ntwoc_pci_match __P((struct device *, struct cfdata *, void *));
91static  void ntwoc_pci_attach __P((struct device *, struct device *, void *));
92
93static	int ntwoc_intr __P((void *));
94static	void ntwoc_shutdown __P((void *sc));
95static	void ntwoc_dtr_callback __P((void *, int, int));
96
97struct cfattach ntwoc_pci_ca = {
98  sizeof(struct ntwoc_pci_softc), ntwoc_pci_match, ntwoc_pci_attach,
99};
100
101/*
102 * Names for daughter card types.  These match the NTWOC_DB_* defines.
103 */
104char *ntwoc_db_names[] = {
105	"V.35", "Unknown 0x01", "Test", "Unknown 0x03",
106	"RS232", "Unknown 0x05", "RS422", "None"
107};
108
109static int
110ntwoc_pci_match(struct device *parent, struct cfdata *match, void *aux)
111{
112	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
113
114	if ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_RISCOM)
115	    && (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_RISCOM_N2))
116		return 1;
117
118	return 0;
119}
120
121static void
122ntwoc_pci_attach(struct device *parent, struct device *self, void *aux)
123{
124	struct ntwoc_pci_softc *sc = (void *)self;
125	struct pci_attach_args *pa = aux;
126	struct sca_softc *sca = &sc->sc_sca;
127	pci_intr_handle_t ih;
128	const char *intrstr;
129	pcireg_t csr;
130	u_int16_t frontend_cr;
131	u_int16_t db0, db1;
132	u_int numports;
133
134	printf(": N2 Serial Interface\n");
135
136	/*
137	 * Map in the ASIC configuration space
138	 */
139	if (pci_mapreg_map(pa, PCI_CBMA_ASIC, PCI_MAPREG_TYPE_MEM, 0,
140			   &sc->sc_asic_iot, &sc->sc_asic_ioh, NULL, NULL)) {
141		printf("%s: Can't map register space (ASIC)\n",
142		       sc->sc_dev.dv_xname);
143		return;
144	}
145	/*
146	 * Map in the serial controller configuration space
147	 */
148	if (pci_mapreg_map(pa, PCI_CBMA_SCA, PCI_MAPREG_TYPE_MEM, 0,
149			   &sca->sc_iot, &sca->sc_ioh, NULL, NULL)) {
150		printf("%s: Can't map register space (SCA)\n",
151		       sc->sc_dev.dv_xname);
152		return;
153	}
154
155	/*
156	 * Enable the card
157	 */
158	csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
159	pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, csr);
160
161	/*
162	 * Map and establish the interrupt
163	 */
164	if (pci_intr_map(pa->pa_pc, pa->pa_intrtag, pa->pa_intrpin,
165			 pa->pa_intrline, &ih)) {
166		printf("%s: couldn't map interrupt\n", sc->sc_dev.dv_xname);
167		return;
168	}
169	intrstr = pci_intr_string(pa->pa_pc, ih);
170	sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_NET, ntwoc_intr, sc);
171	if (sc->sc_ih == NULL) {
172		printf("%s: couldn't establish interrupt",
173		       sc->sc_dev.dv_xname);
174		if (intrstr != NULL)
175			printf(" at %s", intrstr);
176		printf("\n");
177		return;
178	}
179	printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
180
181	/*
182	 * Perform total black magic.  This is not only extremely
183	 * disgusting, but it should be explained a lot more in the
184	 * card's documentation.
185	 *
186	 * From what I gather, this does nothing more than configure the
187	 * PCI to ISA translator ASIC the N2pci card uses.
188	 *
189	 * From the FreeBSD driver:
190	 * offset
191	 *  0x00 - Map Range    - Mem-mapped to locate anywhere
192	 *  0x04 - Re-Map       - PCI address decode enable
193	 *  0x18 - Bus Region   - 32-bit bus, ready enable
194	 *  0x1c - Master Range - include all 16 MB
195	 *  0x20 - Master RAM   - Map SCA Base at 0
196	 *  0x28 - Master Remap - direct master memory enable
197	 *  0x68 - Interrupt    - Enable interrupt (0 to disable)
198	 */
199	bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh,
200			  0x00, 0xfffff000);
201	bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh,
202			  0x04, 1);
203	bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh,
204			  0x18, 0x40030043);
205	bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh,
206			  0x1c, 0xff000000);
207	bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh,
208			  0x20, 0);
209	bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh,
210			  0x28, 0xe9);
211	bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh,
212			  0x68, 0x10900);
213
214	/*
215	 * pass the dma tag to the SCA
216	 */
217	sca->sc_dmat = pa->pa_dmat;
218
219	/*
220	 * Read the configuration information off the daughter card.
221	 */
222	frontend_cr = bus_space_read_2(sca->sc_iot, sca->sc_ioh, NTWOC_FECR);
223	NTWO_DPRINTF(("%s: frontend_cr = 0x%04x\n",
224		      sc->sc_dev.dv_xname, frontend_cr));
225
226	db0 = (frontend_cr & NTWOC_FECR_ID0) >> NTWOC_FECR_ID0_SHIFT;
227	db1 = (frontend_cr & NTWOC_FECR_ID1) >> NTWOC_FECR_ID1_SHIFT;
228
229	/*
230	 * Port 1 HAS to be present.  If it isn't, don't attach anything.
231	 */
232	if (db0 == NTWOC_FE_ID_NONE) {
233		printf("%s: no ports available\n", sc->sc_dev.dv_xname);
234		return;
235	}
236
237	/*
238	 * Port 1 is present.  Now, check to see if port 2 is also
239	 * present.
240	 */
241	numports = 1;
242	if (db1 != NTWOC_FE_ID_NONE)
243		numports++;
244
245	printf("%s: %d port%s\n", sc->sc_dev.dv_xname, numports,
246	       (numports > 1 ? "s" : ""));
247	printf("%s: port 0 interface card: %s\n", sc->sc_dev.dv_xname,
248	       ntwoc_db_names[db0]);
249	if (numports > 1)
250		printf("%s: port 1 interface card: %s\n", sc->sc_dev.dv_xname,
251		       ntwoc_db_names[db1]);
252
253	/*
254	 * enable the RS422 tristate transmit
255	 * diable clock output (use receiver clock for both)
256	 */
257	frontend_cr |= (NTWOC_FECR_TE0 | NTWOC_FECR_TE1);
258	frontend_cr &= ~(NTWOC_FECR_ETC0 | NTWOC_FECR_ETC1);
259	bus_space_write_2(sc->sc_sca.sc_iot, sc->sc_sca.sc_ioh,
260			  NTWOC_FECR, frontend_cr);
261
262	/*
263	 * initialize the SCA.  This will allocate DMAable memory based
264	 * on the number of ports we passed in, the size of each
265	 * buffer, and the number of buffers per port.
266	 */
267	sca->parent = &sc->sc_dev;
268	sca->dtr_callback = ntwoc_dtr_callback;
269	sca->dtr_aux = sc;
270	sca_init(sca, numports);
271
272	/*
273	 * always initialize port 0, since we have to have found it to
274	 * get this far.  If we have two ports, attach the second
275	 * as well.
276	 */
277	sca_port_attach(sca, 0);
278	if (numports == 2)
279		sca_port_attach(sca, 1);
280
281	/*
282	 * Add shutdown hook so that DMA is disabled prior to reboot. Not
283	 * doing do could allow DMA to corrupt kernel memory during the
284	 * reboot before the driver initializes.
285	 */
286	shutdownhook_establish(ntwoc_shutdown, sc);
287}
288
289static int
290ntwoc_intr(void *arg)
291{
292	struct ntwoc_pci_softc *sc = (struct ntwoc_pci_softc *)arg;
293
294	return sca_hardintr(&sc->sc_sca);
295}
296
297/*
298 * shut down interrupts and DMA, so we don't trash the kernel on warm
299 * boot.  Also, lower DTR on each port and disable card interrupts.
300 */
301static void
302ntwoc_shutdown(void *aux)
303{
304	struct ntwoc_pci_softc *sc = aux;
305	u_int16_t fecr;
306
307	/*
308	 * shut down the SCA ports
309	 */
310	sca_shutdown(&sc->sc_sca);
311
312	/*
313	 * disable interupts for the whole card.  Black magic, see comment
314	 * above.
315	 */
316	bus_space_write_4(sc->sc_asic_iot, sc->sc_asic_ioh,
317			  0x68, 0x10900);
318
319	/*
320	 * lower DTR on both ports
321	 */
322	fecr = bus_space_read_2(sc->sc_sca.sc_iot,
323				sc->sc_sca.sc_ioh, NTWOC_FECR);
324	fecr |= (NTWOC_FECR_DTR0 | NTWOC_FECR_DTR1);
325	bus_space_write_2(sc->sc_sca.sc_iot, sc->sc_sca.sc_ioh,
326			  NTWOC_FECR, fecr);
327}
328
329static void
330ntwoc_dtr_callback(void *aux, int port, int state)
331{
332	struct ntwoc_pci_softc *sc = aux;
333	u_int16_t fecr;
334
335	fecr = bus_space_read_2(sc->sc_sca.sc_iot,
336				sc->sc_sca.sc_ioh, NTWOC_FECR);
337
338	NTWO_DPRINTF(("port == %d, state == %d, old fecr:  0x%04x\n",
339		       port, state, fecr));
340
341	if (port == 0) {
342		if (state == 0)
343			fecr |= NTWOC_FECR_DTR0;
344		else
345			fecr &= ~NTWOC_FECR_DTR0;
346	} else {
347		if (state == 0)
348			fecr |= NTWOC_FECR_DTR1;
349		else
350			fecr &= ~NTWOC_FECR_DTR1;
351	}
352
353	NTWO_DPRINTF(("new fecr:  0x%04x\n", fecr));
354
355	bus_space_write_2(sc->sc_sca.sc_iot, sc->sc_sca.sc_ioh,
356			  NTWOC_FECR, fecr);
357}
358