Home | History | Annotate | Line # | Download | only in pci
pci_machdep.c revision 1.1.2.1
      1 /*	$NetBSD: pci_machdep.c,v 1.1.2.1 2007/05/08 19:53:02 garbled Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
      5  * Copyright (c) 1994 Charles M. Hannum.  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  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *	This product includes software developed by Charles M. Hannum.
     18  * 4. The name of the author may not be used to endorse or promote products
     19  *    derived from this software without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31  */
     32 
     33 /*
     34  * Machine-specific functions for PCI autoconfiguration.
     35  *
     36  * On PCs, there are two methods of generating PCI configuration cycles.
     37  * We try to detect the appropriate mechanism for this machine and set
     38  * up a few function pointers to access the correct method directly.
     39  *
     40  * The configuration method can be hard-coded in the config file by
     41  * using `options PCI_CONF_MODE=N', where `N' is the configuration mode
     42  * as defined section 3.6.4.1, `Generating Configuration Cycles'.
     43  */
     44 
     45 #include <sys/cdefs.h>
     46 __KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.1.2.1 2007/05/08 19:53:02 garbled Exp $");
     47 
     48 #include <sys/types.h>
     49 #include <sys/param.h>
     50 #include <sys/device.h>
     51 #include <sys/errno.h>
     52 #include <sys/extent.h>
     53 #include <sys/malloc.h>
     54 #include <sys/queue.h>
     55 #include <sys/systm.h>
     56 #include <sys/time.h>
     57 #include <machine/pcb.h>
     58 
     59 #include <uvm/uvm.h>
     60 
     61 #define _POWERPC_BUS_DMA_PRIVATE
     62 #include <machine/bus.h>
     63 #include <machine/pio.h>
     64 #include <machine/intr.h>
     65 
     66 #include <dev/ic/cpc700reg.h>
     67 #include <machine/pmppc.h>
     68 
     69 #include <dev/pci/pcivar.h>
     70 #include <dev/pci/pcireg.h>
     71 #include <dev/pci/pciconf.h>
     72 
     73 /*
     74  * Address conversion as seen from a PCI master.
     75  * XXX Shouldn't use 0x80000000, the actual value
     76  * should come from the BAR.
     77  */
     78 #define PHYS_TO_PCI_MEM(x)	((x) + 0x80000000)
     79 #define PCI_MEM_TO_PHYS(x)	((x) - 0x80000000)
     80 
     81 static bus_addr_t phys_to_pci(bus_dma_tag_t, bus_addr_t);
     82 static bus_addr_t pci_to_phys(bus_dma_tag_t, bus_addr_t);
     83 
     84 struct powerpc_bus_dma_tag pci_bus_dma_tag = {
     85 	0,			/* _bounce_thresh */
     86 	_bus_dmamap_create,
     87 	_bus_dmamap_destroy,
     88 	_bus_dmamap_load,
     89 	_bus_dmamap_load_mbuf,
     90 	_bus_dmamap_load_uio,
     91 	_bus_dmamap_load_raw,
     92 	_bus_dmamap_unload,
     93 	NULL,			/* _dmamap_sync */
     94 	_bus_dmamem_alloc,
     95 	_bus_dmamem_free,
     96 	_bus_dmamem_map,
     97 	_bus_dmamem_unmap,
     98 	_bus_dmamem_mmap,
     99 	phys_to_pci,
    100 	pci_to_phys,
    101 };
    102 
    103 static bus_addr_t
    104 phys_to_pci(bus_dma_tag_t t, bus_addr_t a)
    105 {
    106 	return PHYS_TO_PCI_MEM(a);
    107 }
    108 
    109 static bus_addr_t pci_to_phys(bus_dma_tag_t t, bus_addr_t a)
    110 {
    111 	return PCI_MEM_TO_PHYS(a);
    112 }
    113 
    114 void
    115 pci_attach_hook(struct device *parent, struct device *self,
    116 		struct pcibus_attach_args *pba)
    117 {
    118 }
    119 
    120 int
    121 pci_bus_maxdevs(pci_chipset_tag_t pc, int busno)
    122 {
    123 
    124 	/*
    125 	 * Bus number is irrelevant.  Configuration Mechanism 1 is in
    126 	 * use, can have devices 0-32 (i.e. the `normal' range).
    127 	 */
    128 	return (32);
    129 }
    130 
    131 pcitag_t
    132 pci_make_tag(pci_chipset_tag_t pc, int bus, int device, int function)
    133 {
    134 	pcitag_t tag;
    135 
    136 	if (bus >= 256 || device >= 32 || function >= 8)
    137 		panic("pci_make_tag: bad request");
    138 
    139 	tag = CPC_PCI_CONFIG_ENABLE |
    140 		    (bus << 16) | (device << 11) | (function << 8);
    141 	return (tag);
    142 }
    143 
    144 void
    145 pci_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, int *bp, int *dp, int *fp)
    146 {
    147 
    148 	if (bp != NULL)
    149 		*bp = (tag >> 16) & 0xff;
    150 	if (dp != NULL)
    151 		*dp = (tag >> 11) & 0x1f;
    152 	if (fp != NULL)
    153 		*fp = (tag >> 8) & 0x7;
    154 }
    155 
    156 #define SP_PCI(tag, reg) ((tag) | (reg))
    157 
    158 pcireg_t
    159 pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
    160 {
    161 	pcireg_t data;
    162 	struct faultbuf env, *oldfault;
    163 
    164 	oldfault = curpcb->pcb_onfault;
    165 	if (setfault(&env)) {
    166 		curpcb->pcb_onfault = oldfault;
    167 		return 0;
    168 	}
    169 
    170 /*printf("pci_conf_read %x %x\n", tag, reg);*/
    171 	out32rb(CPC_PCICFGADR, SP_PCI(tag, reg));
    172 	data = in32rb(CPC_PCICFGDATA);
    173 	/*out32rb(CPC_PCICFGADR, 0);*/
    174 
    175 	curpcb->pcb_onfault = oldfault;
    176 	return data;
    177 }
    178 
    179 void
    180 pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data)
    181 {
    182 	struct faultbuf env, *oldfault;
    183 
    184 	oldfault = curpcb->pcb_onfault;
    185 	if (setfault(&env)) {
    186 		curpcb->pcb_onfault = oldfault;
    187 		return;
    188 	}
    189 
    190 /*printf("pci_conf_write %x %x %x\n", tag, reg, data);*/
    191 	out32rb(CPC_PCICFGADR, SP_PCI(tag, reg));
    192 	out32rb(CPC_PCICFGDATA, data);
    193 	/*out32rb(CPC_PCICFGADR, 0);*/
    194 	curpcb->pcb_onfault = oldfault;
    195 }
    196 
    197 int
    198 pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
    199 {
    200 	int	pin = pa->pa_intrpin;
    201 	int	line = pa->pa_intrline;
    202 
    203 	if (pin == 0) {
    204 		/* No IRQ used. */
    205 		goto bad;
    206 	}
    207 
    208 	if (pin > 4) {
    209 		printf("pci_intr_map: bad interrupt pin %d\n", pin);
    210 		goto bad;
    211 	}
    212 
    213 	if (line == 255) {
    214 		printf("pci_intr_map: no mapping for pin %c\n", '@' + pin);
    215 		goto bad;
    216 	}
    217 	/*printf("pci_intr_map pin=%d line=%d\n", pin, line);*/
    218 
    219 	switch (line & 3) {	/* XXX what should this be? */
    220 	case 0: *ihp = PMPPC_I_BPMC_INTA; break;
    221 	case 1: *ihp = PMPPC_I_BPMC_INTB; break;
    222 	case 2: *ihp = PMPPC_I_BPMC_INTC; break;
    223 	case 3: *ihp = PMPPC_I_BPMC_INTD; break;
    224 	}
    225 	return 0;
    226 
    227 bad:
    228 	*ihp = -1;
    229 	return 1;
    230 }
    231 
    232 const char *
    233 pci_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih)
    234 {
    235 	static char irqstr[8];		/* 4 + 2 + NULL + sanity */
    236 
    237 	if (ih < 0 || ih >= ICU_LEN)
    238 		panic("pci_intr_string: bogus handle 0x%x", ih);
    239 
    240 	sprintf(irqstr, "irq %d", ih);
    241 	return (irqstr);
    242 
    243 }
    244 
    245 const struct evcnt *
    246 pci_intr_evcnt(pci_chipset_tag_t pc, pci_intr_handle_t ih)
    247 {
    248 
    249 	/* XXX for now, no evcnt parent reported */
    250 	return NULL;
    251 }
    252 
    253 void *
    254 pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int level,
    255 		   int (*func)(void *), void *arg)
    256 {
    257 	/*
    258 	 * ih is the value assigned in pci_intr_map(), above.
    259 	 */
    260 	return intr_establish(ih, IST_LEVEL, level, func, arg);
    261 }
    262 
    263 void
    264 pci_intr_disestablish(pci_chipset_tag_t pc, void *cookie)
    265 {
    266 	intr_disestablish(cookie);
    267 }
    268 
    269 void
    270 pci_conf_interrupt(pci_chipset_tag_t pc, int bus, int dev, int pin, int swiz,
    271     int *iline)
    272 {
    273 	int line;
    274 
    275 	line = (swiz + dev) & 3;
    276 	/* XXX UGLY UGLY, figure out the real interrupt mapping */
    277 	if (bus==3&&dev==2&&pin==1&&swiz==3) line=2;
    278 /*
    279 	printf("pci_conf_interrupt: bus=%d dev=%d pin=%d swiz=%d => line=%d\n",
    280 		bus, dev, pin, swiz, line);
    281 */
    282 	*iline = line;
    283 }
    284