1/*	$NetBSD: pci_mace.c,v 1.13 2011/07/01 18:53:47 dyoung Exp $	*/
2
3/*
4 * Copyright (c) 2001,2003 Christopher Sekiya
5 * Copyright (c) 2000 Soren S. Jorvang
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, 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. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *          This product includes software developed for the
19 *          NetBSD Project.  See http://www.NetBSD.org/ for
20 *          information about NetBSD.
21 * 4. The name of the author may not be used to endorse or promote products
22 *    derived from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36#include <sys/cdefs.h>
37__KERNEL_RCSID(0, "$NetBSD: pci_mace.c,v 1.13 2011/07/01 18:53:47 dyoung Exp $");
38
39#include "opt_pci.h"
40#include "pci.h"
41
42#include <sys/param.h>
43#include <sys/device.h>
44#include <sys/systm.h>
45
46#include <machine/cpu.h>
47#include <machine/locore.h>
48#include <machine/autoconf.h>
49#include <machine/vmparam.h>
50#include <sys/bus.h>
51#include <machine/machtype.h>
52
53#include <mips/cache.h>
54
55#include <dev/pci/pcivar.h>
56#include <dev/pci/pcireg.h>
57#include <dev/pci/pcidevs.h>
58
59#include <sys/extent.h>
60#include <sys/malloc.h>
61#include <dev/pci/pciconf.h>
62
63#include <sgimips/mace/macereg.h>
64#include <sgimips/mace/macevar.h>
65
66#include <sgimips/mace/pcireg_mace.h>
67
68struct macepci_softc {
69	struct device sc_dev;
70
71	struct sgimips_pci_chipset sc_pc;
72};
73
74static int	macepci_match(struct device *, struct cfdata *, void *);
75static void	macepci_attach(struct device *, struct device *, void *);
76static int	macepci_bus_maxdevs(pci_chipset_tag_t, int);
77static pcireg_t	macepci_conf_read(pci_chipset_tag_t, pcitag_t, int);
78static void	macepci_conf_write(pci_chipset_tag_t, pcitag_t, int, pcireg_t);
79static int	macepci_intr_map(const struct pci_attach_args *,
80		    pci_intr_handle_t *);
81static const char *
82		macepci_intr_string(pci_chipset_tag_t, pci_intr_handle_t);
83static int	macepci_intr(void *);
84
85CFATTACH_DECL(macepci, sizeof(struct macepci_softc),
86    macepci_match, macepci_attach, NULL, NULL);
87
88static int
89macepci_match(struct device *parent, struct cfdata *match, void *aux)
90{
91
92	return (1);
93}
94
95static void
96macepci_attach(struct device *parent, struct device *self, void *aux)
97{
98	struct macepci_softc *sc = (struct macepci_softc *)self;
99	pci_chipset_tag_t pc = &sc->sc_pc;
100	struct mace_attach_args *maa = aux;
101	struct pcibus_attach_args pba;
102	u_int32_t control;
103	int rev;
104
105	if (bus_space_subregion(maa->maa_st, maa->maa_sh,
106	    maa->maa_offset, 0, &pc->ioh) )
107		panic("macepci_attach: couldn't map");
108
109	pc->iot = maa->maa_st;
110
111	rev = bus_space_read_4(pc->iot, pc->ioh, MACEPCI_REVISION);
112	printf(": rev %d\n", rev);
113
114	pc->pc_bus_maxdevs = macepci_bus_maxdevs;
115	pc->pc_conf_read = macepci_conf_read;
116	pc->pc_conf_write = macepci_conf_write;
117	pc->pc_intr_map = macepci_intr_map;
118	pc->pc_intr_string = macepci_intr_string;
119	pc->intr_establish = mace_intr_establish;
120	pc->intr_disestablish = mace_intr_disestablish;
121
122	bus_space_write_4(pc->iot, pc->ioh, MACE_PCI_ERROR_ADDR, 0);
123	bus_space_write_4(pc->iot, pc->ioh, MACE_PCI_ERROR_FLAGS, 0);
124
125	/* Turn on PCI error interrupts */
126	bus_space_write_4(pc->iot, pc->ioh, MACE_PCI_CONTROL,
127	    MACE_PCI_CONTROL_SERR_ENA |
128	    MACE_PCI_CONTROL_PARITY_ERR |
129	    MACE_PCI_CONTROL_PARK_LIU |
130	    MACE_PCI_CONTROL_OVERRUN_INT |
131	    MACE_PCI_CONTROL_PARITY_INT |
132	    MACE_PCI_CONTROL_SERR_INT |
133	    MACE_PCI_CONTROL_IT_INT |
134	    MACE_PCI_CONTROL_RE_INT |
135	    MACE_PCI_CONTROL_DPED_INT |
136	    MACE_PCI_CONTROL_TAR_INT |
137	    MACE_PCI_CONTROL_MAR_INT);
138
139	/*
140	 * Enable all MACE PCI interrupts. They will be masked by
141	 * the CRIME code.
142	 */
143	control = bus_space_read_4(pc->iot, pc->ioh, MACEPCI_CONTROL);
144	control |= CONTROL_INT_MASK;
145	bus_space_write_4(pc->iot, pc->ioh, MACEPCI_CONTROL, control);
146
147#if NPCI > 0
148	pc->pc_ioext = extent_create("macepciio", 0x00001000, 0x01ffffff,
149	    NULL, 0, EX_NOWAIT);
150	pc->pc_memext = extent_create("macepcimem", 0x80100000, 0x81ffffff,
151	    NULL, 0, EX_NOWAIT);
152	pci_configure_bus(pc, pc->pc_ioext, pc->pc_memext, NULL, 0,
153	    mips_cache_info.mci_dcache_align);
154	memset(&pba, 0, sizeof pba);
155/*XXX*/	pba.pba_iot = SGIMIPS_BUS_SPACE_IO;
156/*XXX*/	pba.pba_memt = SGIMIPS_BUS_SPACE_MEM;
157	pba.pba_dmat = &pci_bus_dma_tag;
158	pba.pba_dmat64 = NULL;
159	pba.pba_bus = 0;
160	pba.pba_bridgetag = NULL;
161	pba.pba_flags = PCI_FLAGS_IO_OKAY | PCI_FLAGS_MEM_OKAY |
162	    PCI_FLAGS_MRL_OKAY | PCI_FLAGS_MRM_OKAY | PCI_FLAGS_MWI_OKAY;
163	pba.pba_pc = pc;
164
165#ifdef MACEPCI_IO_WAS_BUGGY
166	if (rev == 0)
167		pba.pba_flags &= ~PCI_FLAGS_IO_OKAY;		/* Buggy? */
168#endif
169
170	cpu_intr_establish(maa->maa_intr, IPL_NONE, macepci_intr, sc);
171
172	config_found_ia(self, "pcibus", &pba, pcibusprint);
173#endif
174}
175
176int
177macepci_bus_maxdevs(pci_chipset_tag_t pc, int busno)
178{
179
180	if (busno == 0)
181		return 5;	/* 2 on-board SCSI chips, slots 0, 1 and 2 */
182	else
183		return 0;	/* XXX */
184}
185
186pcireg_t
187macepci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
188{
189	pcireg_t data;
190
191	bus_space_write_4(pc->iot, pc->ioh, MACE_PCI_CONFIG_ADDR, (tag | reg));
192	data = bus_space_read_4(pc->iot, pc->ioh, MACE_PCI_CONFIG_DATA);
193	bus_space_write_4(pc->iot, pc->ioh, MACE_PCI_CONFIG_ADDR, 0);
194
195	return data;
196}
197
198void
199macepci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data)
200{
201	/* XXX O2 soren */
202	if (tag == 0)
203		return;
204
205	bus_space_write_4(pc->iot, pc->ioh, MACE_PCI_CONFIG_ADDR, (tag | reg));
206	bus_space_write_4(pc->iot, pc->ioh, MACE_PCI_CONFIG_DATA, data);
207	bus_space_write_4(pc->iot, pc->ioh, MACE_PCI_CONFIG_ADDR, 0);
208}
209
210int
211macepci_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp)
212{
213	pci_chipset_tag_t pc = pa->pa_pc;
214	pcitag_t intrtag = pa->pa_intrtag;
215	int pin = pa->pa_intrpin;
216	int bus, dev, func, start;
217
218	pci_decompose_tag(pc, intrtag, &bus, &dev, &func);
219
220	if (dev < 3 && pin != PCI_INTERRUPT_PIN_A)
221		panic("SCSI0 and SCSI1 must be hardwired!");
222
223	switch (pin) {
224	default:
225	case PCI_INTERRUPT_PIN_NONE:
226		return -1;
227
228	case PCI_INTERRUPT_PIN_A:
229		/*
230		 * Each of SCSI{0,1}, & slots 0 - 2 has dedicated interrupt
231		 * for pin A?
232		 */
233		*ihp = dev + 7;
234		return 0;
235
236	case PCI_INTERRUPT_PIN_B:
237		start = 0;
238		break;
239	case PCI_INTERRUPT_PIN_C:
240		start = 1;
241		break;
242	case PCI_INTERRUPT_PIN_D:
243		start = 2;
244		break;
245	}
246
247	/* Pins B,C,D are mapped to PCI_SHARED0 - PCI_SHARED2 interrupts */
248	*ihp = 13 /* PCI_SHARED0 */ + (start + dev - 3) % 3;
249	return 0;
250}
251
252const char *
253macepci_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih)
254{
255	static char irqstr[32];
256
257	sprintf(irqstr, "crime interrupt %d", ih);
258	return irqstr;
259}
260
261
262/*
263 * Handle PCI error interrupts.
264 */
265int
266macepci_intr(void *arg)
267{
268	struct macepci_softc *sc = (struct macepci_softc *)arg;
269	pci_chipset_tag_t pc = &sc->sc_pc;
270	u_int32_t error, address;
271
272	error = bus_space_read_4(pc->iot, pc->ioh, MACE_PCI_ERROR_FLAGS);
273	address = bus_space_read_4(pc->iot, pc->ioh, MACE_PCI_ERROR_ADDR);
274	while (error & 0xffc00000) {
275		if (error & MACE_PERR_MASTER_ABORT) {
276			/*
277			 * this seems to be a more-or-less normal error
278			 * condition (e.g., "pcictl pci0 list" generates
279			 * a _lot_ of these errors, so no message for now
280			 * while I figure out if I missed a trick somewhere.
281			 */
282			error &= ~MACE_PERR_MASTER_ABORT;
283			bus_space_write_4(pc->iot, pc->ioh,
284			    MACE_PCI_ERROR_FLAGS, error);
285		}
286
287		if (error & MACE_PERR_TARGET_ABORT) {
288			printf("mace: target abort at %x\n", address);
289			error &= ~MACE_PERR_TARGET_ABORT;
290			bus_space_write_4(pc->iot, pc->ioh,
291			    MACE_PCI_ERROR_FLAGS, error);
292		}
293
294		if (error & MACE_PERR_DATA_PARITY_ERR) {
295			printf("mace: parity error at %x\n", address);
296			error &= ~MACE_PERR_DATA_PARITY_ERR;
297			bus_space_write_4(pc->iot, pc->ioh,
298			    MACE_PCI_ERROR_FLAGS, error);
299		}
300
301		if (error & MACE_PERR_RETRY_ERR) {
302			printf("mace: retry error at %x\n", address);
303			error &= ~MACE_PERR_RETRY_ERR;
304			bus_space_write_4(pc->iot, pc->ioh,
305			    MACE_PCI_ERROR_FLAGS, error);
306		}
307
308		if (error & MACE_PERR_ILLEGAL_CMD) {
309			printf("mace: illegal command at %x\n", address);
310			error &= ~MACE_PERR_ILLEGAL_CMD;
311			bus_space_write_4(pc->iot, pc->ioh,
312			    MACE_PCI_ERROR_FLAGS, error);
313		}
314
315		if (error & MACE_PERR_SYSTEM_ERR) {
316			printf("mace: system error at %x\n", address);
317			error &= ~MACE_PERR_SYSTEM_ERR;
318			bus_space_write_4(pc->iot, pc->ioh,
319			    MACE_PCI_ERROR_FLAGS, error);
320		}
321
322		if (error & MACE_PERR_INTERRUPT_TEST) {
323			printf("mace: interrupt test at %x\n", address);
324			error &= ~MACE_PERR_INTERRUPT_TEST;
325			bus_space_write_4(pc->iot, pc->ioh,
326			    MACE_PCI_ERROR_FLAGS, error);
327		}
328
329		if (error & MACE_PERR_PARITY_ERR) {
330			printf("mace: parity error at %x\n", address);
331			error &= ~MACE_PERR_PARITY_ERR;
332			bus_space_write_4(pc->iot, pc->ioh,
333			    MACE_PCI_ERROR_FLAGS, error);
334		}
335
336		if (error & MACE_PERR_RSVD) {
337			printf("mace: reserved condition at %x\n", address);
338			error &= ~MACE_PERR_RSVD;
339			bus_space_write_4(pc->iot, pc->ioh,
340			    MACE_PCI_ERROR_FLAGS, error);
341		}
342
343		if (error & MACE_PERR_OVERRUN) {
344			printf("mace: overrun at %x\n", address);
345			error &= ~MACE_PERR_OVERRUN;
346			bus_space_write_4(pc->iot, pc->ioh,
347			    MACE_PCI_ERROR_FLAGS, error);
348		}
349	}
350	return 0;
351}
352