1/* $NetBSD: dwlpx.c,v 1.37 2011/06/14 15:34:22 matt Exp $ */
2
3/*
4 * Copyright (c) 1997 by Matthew Jacob
5 * NASA AMES Research Center.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice immediately at the beginning of the file, without modification,
13 *    this list of conditions, and the following disclaimer.
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 of the author 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 THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
24 * 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
33#include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
34
35__KERNEL_RCSID(0, "$NetBSD: dwlpx.c,v 1.37 2011/06/14 15:34:22 matt Exp $");
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/kernel.h>
40#include <sys/device.h>
41
42#include <machine/autoconf.h>
43
44#include <dev/pci/pcireg.h>
45#include <dev/pci/pcivar.h>
46
47#include <alpha/tlsb/tlsbreg.h>
48#include <alpha/tlsb/kftxxvar.h>
49#include <alpha/tlsb/kftxxreg.h>
50#include <alpha/pci/dwlpxreg.h>
51#include <alpha/pci/dwlpxvar.h>
52#include <alpha/pci/pci_kn8ae.h>
53
54#define	KV(_addr)	((void *)ALPHA_PHYS_TO_K0SEG((_addr)))
55#define	DWLPX_SYSBASE(sc)	\
56	    ((((unsigned long)((sc)->dwlpx_node - 4))	<< 36) |	\
57	     (((unsigned long) (sc)->dwlpx_hosenum)	<< 34) |	\
58	     (1LL					<< 39))
59#define	DWLPX_SYSBASE1(node, hosenum)	\
60	    ((((unsigned long)(node - 4))	<< 36) |	\
61	     (((unsigned long) hosenum)	        << 34) |	\
62	     (1LL					<< 39))
63
64
65static int	dwlpxmatch(device_t, cfdata_t, void *);
66static void	dwlpxattach(device_t, device_t, void *);
67
68CFATTACH_DECL_NEW(dwlpx, sizeof(struct dwlpx_softc),
69    dwlpxmatch, dwlpxattach, NULL, NULL);
70
71extern struct cfdriver dwlpx_cd;
72
73void	dwlpx_errintr(void *, u_long vec);
74
75static int
76dwlpxmatch(device_t parent, cfdata_t cf, void *aux)
77{
78	struct kft_dev_attach_args *ka = aux;
79	unsigned long ls;
80	uint32_t ctl;
81
82	if (strcmp(ka->ka_name, dwlpx_cd.cd_name) != 0)
83		return (0);
84
85	ls = DWLPX_SYSBASE1(ka->ka_node, ka->ka_hosenum);
86
87	/*
88	 * Probe the first HPC to make sure this really is a dwlpx and
89	 * nothing else.
90	 */
91	if (badaddr(KV(PCIA_CTL(1) + ls), sizeof (ctl)) != 0) {
92		/*
93		 * If we are here something went wrong. One reason
94		 * could be that this is a dwlma and not a dwlpx.
95		 *
96		 * We can not clear potential illegal CSR errors here
97		 * since it is unknown hardware.
98		 */
99		return (0);
100	}
101
102	return (1);
103}
104
105static void
106dwlpxattach(device_t parent, device_t self, void *aux)
107{
108	static int once = 0;
109	struct dwlpx_softc *sc = device_private(self);
110	struct dwlpx_config *ccp = &sc->dwlpx_cc;
111	struct kft_dev_attach_args *ka = aux;
112	struct pcibus_attach_args pba;
113	uint32_t pcia_present;
114
115	sc->dwlpx_dev = self;
116	sc->dwlpx_node = ka->ka_node;
117	sc->dwlpx_dtype = ka->ka_dtype;
118	sc->dwlpx_hosenum = ka->ka_hosenum;
119
120	dwlpx_init(sc);
121	dwlpx_dma_init(ccp);
122
123	pcia_present = REGVAL(PCIA_PRESENT + ccp->cc_sysbase);
124	aprint_normal(": PCIA rev. %d, STD I/O %spresent, %dK S/G entries\n",
125	    (pcia_present >> PCIA_PRESENT_REVSHIFT) & PCIA_PRESENT_REVMASK,
126	    (pcia_present & PCIA_PRESENT_STDIO) == 0 ? "not " : "",
127	    sc->dwlpx_sgmapsz == DWLPX_SG128K ? 128 : 32);
128
129#if 0
130	{
131		int hpc, slot, slotval;
132		const char *str;
133		for (hpc = 0; hpc < sc->dwlpx_nhpc; hpc++) {
134			for (slot = 0; slot < 4; slot++) {
135				slotval = (pcia_present >>
136				    PCIA_PRESENT_SLOTSHIFT(hpc, slot)) &
137				    PCIA_PRESENT_SLOT_MASK;
138				if (slotval == PCIA_PRESENT_SLOT_NONE)
139					continue;
140				switch (slotval) {
141				case PCIA_PRESENT_SLOT_25W:
142					str = "25";
143					break;
144				case PCIA_PRESENT_SLOT_15W:
145					str = "15";
146					break;
147				case PCIA_PRESENT_SLOW_7W:
148				default:		/* XXX gcc */
149					str = "7.5";
150					break;
151				}
152				aprint_normal_dev(sc->dwlpx_dev,
153				    "hpc %d slot %d: %s watt module\n",
154				    hpc, slot, str);
155			}
156		}
157	}
158#endif
159
160	if (once == 0) {
161		/*
162		 * Set up interrupts
163		 */
164		pci_kn8ae_pickintr(&sc->dwlpx_cc, 1);
165		once++;
166	} else {
167		pci_kn8ae_pickintr(&sc->dwlpx_cc, 0);
168	}
169
170	/*
171	 * Attach PCI bus
172	 */
173	pba.pba_iot = &sc->dwlpx_cc.cc_iot;
174	pba.pba_memt = &sc->dwlpx_cc.cc_memt;
175	pba.pba_dmat =	/* start with direct, may change... */
176	    alphabus_dma_get_tag(&sc->dwlpx_cc.cc_dmat_direct, ALPHA_BUS_PCI);
177	pba.pba_dmat64 = NULL;
178	pba.pba_pc = &sc->dwlpx_cc.cc_pc;
179	pba.pba_bus = 0;
180	pba.pba_bridgetag = NULL;
181	pba.pba_flags = PCI_FLAGS_IO_OKAY | PCI_FLAGS_MEM_OKAY |
182	    PCI_FLAGS_MRL_OKAY | PCI_FLAGS_MRM_OKAY | PCI_FLAGS_MWI_OKAY;
183	config_found_ia(self, "pcibus", &pba, pcibusprint);
184}
185
186void
187dwlpx_init(struct dwlpx_softc *sc)
188{
189	uint32_t ctl;
190	struct dwlpx_config *ccp = &sc->dwlpx_cc;
191	unsigned long vec, ls = DWLPX_SYSBASE(sc);
192	int i;
193
194	if (ccp->cc_initted == 0) {
195		/*
196		 * On reads, you get a fault if you read a nonexisted HPC.
197		 * We know the internal KFTIA hose (hose 0) has only 2 HPCs,
198		 * but we can also actually probe for HPCs.
199		 * Assume at least one.
200		 */
201		for (sc->dwlpx_nhpc = 1; sc->dwlpx_nhpc < NHPC;
202		    sc->dwlpx_nhpc++) {
203			if (badaddr(KV(PCIA_CTL(sc->dwlpx_nhpc) + ls),
204			    sizeof (ctl)) != 0) {
205				break;
206			}
207		}
208		if (sc->dwlpx_nhpc != NHPC) {
209			/* clear (potential) Illegal CSR Address Error */
210			REGVAL(PCIA_ERR(0) + DWLPX_SYSBASE(sc)) =
211				PCIA_ERR_ALLERR;
212		}
213
214		dwlpx_bus_io_init(&ccp->cc_iot, ccp);
215		dwlpx_bus_mem_init(&ccp->cc_memt, ccp);
216	}
217	dwlpx_pci_init(&ccp->cc_pc, ccp);
218	ccp->cc_sc = sc;
219
220	/*
221	 * Establish a precalculated base for convenience's sake.
222	 */
223	ccp->cc_sysbase = ls;
224
225	/*
226	 * If there are only 2 HPCs, then the 'present' register is not
227	 * implemented, so there will only ever be 32K SG entries. Otherwise
228	 * any revision greater than zero will have 128K entries.
229	 */
230	ctl = REGVAL(PCIA_PRESENT + ccp->cc_sysbase);
231	if (sc->dwlpx_nhpc == 2) {
232		sc->dwlpx_sgmapsz = DWLPX_SG32K;
233#if 0
234	/*
235	 * As of 2/25/98- When I enable SG128K, and then have to flip
236	 * TBIT below, I get bad SGRAM errors. We'll fix this later
237	 * if this gets important.
238	 */
239	} else if ((ctl >> PCIA_PRESENT_REVSHIFT) & PCIA_PRESENT_REVMASK) {
240		sc->dwlpx_sgmapsz = DWLPX_SG128K;
241#endif
242	} else {
243		sc->dwlpx_sgmapsz = DWLPX_SG32K;
244	}
245
246	/*
247	 * Set up interrupt stuff for this DWLPX.
248	 *
249	 * Note that all PCI interrupt pins are disabled at this time.
250	 *
251	 * Do this even for all HPCs- even for the nonexistent
252	 * one on hose zero of a KFTIA.
253	 */
254	vec = scb_alloc(dwlpx_errintr, sc);
255	if (vec == SCB_ALLOC_FAILED)
256		panic("%s: unable to allocate error vector",
257		    device_xname(sc->dwlpx_dev));
258	aprint_normal_dev(sc->dwlpx_dev, "error interrupt at vector 0x%lx\n",
259	    vec);
260	for (i = 0; i < NHPC; i++) {
261		REGVAL(PCIA_IMASK(i) + ccp->cc_sysbase) = DWLPX_IMASK_DFLT;
262		REGVAL(PCIA_ERRVEC(i) + ccp->cc_sysbase) = vec;
263	}
264
265	/*
266	 * Establish HAE values, as well as make sure of sanity elsewhere.
267	 */
268	for (i = 0; i < sc->dwlpx_nhpc; i++) {
269		ctl = REGVAL(PCIA_CTL(i) + ccp->cc_sysbase);
270		ctl &= 0x0fffffff;
271		ctl &= ~(PCIA_CTL_MHAE(0x1f) | PCIA_CTL_IHAE(0x1f));
272		/*
273		 * I originally also had it or'ing in 3, which makes no sense.
274		 */
275
276		ctl |= PCIA_CTL_RMMENA | PCIA_CTL_RMMARB;
277
278		/*
279		 * Only valid if we're attached to a KFTIA or a KTHA.
280		 */
281		ctl |= PCIA_CTL_3UP;
282
283		ctl |= PCIA_CTL_CUTENA;
284
285		/*
286		 * Fit in appropriate S/G Map Ram size.
287		 */
288		if (sc->dwlpx_sgmapsz == DWLPX_SG32K)
289			ctl |= PCIA_CTL_SG32K;
290		else if (sc->dwlpx_sgmapsz == DWLPX_SG128K)
291			ctl |= PCIA_CTL_SG128K;
292		else
293			ctl |= PCIA_CTL_SG32K;
294
295		REGVAL(PCIA_CTL(i) + ccp->cc_sysbase) = ctl;
296	}
297	/*
298	 * Enable TBIT if required
299	 */
300	if (sc->dwlpx_sgmapsz == DWLPX_SG128K)
301		REGVAL(PCIA_TBIT + ccp->cc_sysbase) = 1;
302	alpha_mb();
303	ccp->cc_initted = 1;
304}
305
306void
307dwlpx_errintr(void *arg, unsigned long vec)
308{
309	struct dwlpx_softc *sc = arg;
310	struct dwlpx_config *ccp = &sc->dwlpx_cc;
311	int i;
312	struct {
313		uint32_t err;
314		uint32_t addr;
315	} hpcs[NHPC];
316
317	for (i = 0; i < sc->dwlpx_nhpc; i++) {
318		hpcs[i].err = REGVAL(PCIA_ERR(i) + ccp->cc_sysbase);
319		hpcs[i].addr = REGVAL(PCIA_FADR(i) + ccp->cc_sysbase);
320	}
321	aprint_error_dev(sc->dwlpx_dev, "node %d hose %d error interrupt\n",
322	    sc->dwlpx_node, sc->dwlpx_hosenum);
323
324	for (i = 0; i < sc->dwlpx_nhpc; i++) {
325		if ((hpcs[i].err & PCIA_ERR_ERROR) == 0)
326			continue;
327		aprint_error("\tHPC %d: ERR=0x%08x; DMA %s Memory, "
328			"Failing Address 0x%x\n",
329			i, hpcs[i].err, hpcs[i].addr & 0x1? "write to" :
330			"read from", hpcs[i].addr & ~3);
331		if (hpcs[i].err & PCIA_ERR_SERR_L)
332			aprint_error("\t       PCI device asserted SERR_L\n");
333		if (hpcs[i].err & PCIA_ERR_ILAT)
334			aprint_error("\t       Incremental Latency Exceeded\n");
335		if (hpcs[i].err & PCIA_ERR_SGPRTY)
336			aprint_error("\t       CPU access of SG RAM Parity Error\n");
337		if (hpcs[i].err & PCIA_ERR_ILLCSR)
338			aprint_error("\t       Illegal CSR Address Error\n");
339		if (hpcs[i].err & PCIA_ERR_PCINXM)
340			aprint_error("\t       Nonexistent PCI Address Error\n");
341		if (hpcs[i].err & PCIA_ERR_DSCERR)
342			aprint_error("\t       PCI Target Disconnect Error\n");
343		if (hpcs[i].err & PCIA_ERR_ABRT)
344			aprint_error("\t       PCI Target Abort Error\n");
345		if (hpcs[i].err & PCIA_ERR_WPRTY)
346			aprint_error("\t       PCI Write Parity Error\n");
347		if (hpcs[i].err & PCIA_ERR_DPERR)
348			aprint_error("\t       PCI Data Parity Error\n");
349		if (hpcs[i].err & PCIA_ERR_APERR)
350			aprint_error("\t       PCI Address Parity Error\n");
351		if (hpcs[i].err & PCIA_ERR_DFLT)
352			aprint_error("\t       SG Map RAM Invalid Entry Error\n");
353		if (hpcs[i].err & PCIA_ERR_DPRTY)
354			aprint_error("\t       DMA access of SG RAM Parity Error\n");
355		if (hpcs[i].err & PCIA_ERR_DRPERR)
356			aprint_error("\t       DMA Read Return Parity Error\n");
357		if (hpcs[i].err & PCIA_ERR_MABRT)
358			aprint_error("\t       PCI Master Abort Error\n");
359		if (hpcs[i].err & PCIA_ERR_CPRTY)
360			aprint_error("\t       CSR Parity Error\n");
361		if (hpcs[i].err & PCIA_ERR_COVR)
362			aprint_error("\t       CSR Overrun Error\n");
363		if (hpcs[i].err & PCIA_ERR_MBPERR)
364			aprint_error("\t       Mailbox Parity Error\n");
365		if (hpcs[i].err & PCIA_ERR_MBILI)
366			aprint_error("\t       Mailbox Illegal Length Error\n");
367		REGVAL(PCIA_ERR(i) + ccp->cc_sysbase) = hpcs[i].err;
368	}
369}
370