cia_pci.c revision 1.25
197403Sobrien/* $NetBSD: cia_pci.c,v 1.25 2000/06/29 08:58:46 mrg Exp $ */ 297403Sobrien 397403Sobrien/* 497403Sobrien * Copyright (c) 1995, 1996 Carnegie-Mellon University. 597403Sobrien * All rights reserved. 697403Sobrien * 797403Sobrien * Author: Chris G. Demetriou 897403Sobrien * 997403Sobrien * Permission to use, copy, modify and distribute this software and 1097403Sobrien * its documentation is hereby granted, provided that both the copyright 1197403Sobrien * notice and this permission notice appear in all copies of the 1297403Sobrien * software, derivative works or modified versions, and any portions 1397403Sobrien * thereof, and that both notices appear in supporting documentation. 1497403Sobrien * 1597403Sobrien * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 1697403Sobrien * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 1797403Sobrien * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 1897403Sobrien * 1997403Sobrien * Carnegie Mellon requests users of this software to return to 2097403Sobrien * 2197403Sobrien * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 2297403Sobrien * School of Computer Science 2397403Sobrien * Carnegie Mellon University 2497403Sobrien * Pittsburgh PA 15213-3890 2597403Sobrien * 2697403Sobrien * any improvements or extensions that they make and grant Carnegie the 2797403Sobrien * rights to redistribute these changes. 2897403Sobrien */ 2997403Sobrien 3097403Sobrien#include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 3197403Sobrien 3297403Sobrien__KERNEL_RCSID(0, "$NetBSD: cia_pci.c,v 1.25 2000/06/29 08:58:46 mrg Exp $"); 3397403Sobrien 3497403Sobrien#include <sys/param.h> 3597403Sobrien#include <sys/systm.h> 3697403Sobrien#include <sys/kernel.h> 3797403Sobrien#include <sys/device.h> 3897403Sobrien 3997403Sobrien#include <uvm/uvm_extern.h> 4097403Sobrien 4197403Sobrien#include <dev/pci/pcireg.h> 4297403Sobrien#include <dev/pci/pcivar.h> 4397403Sobrien#include <alpha/pci/ciareg.h> 4497403Sobrien#include <alpha/pci/ciavar.h> 4597403Sobrien 4697403Sobrienvoid cia_attach_hook __P((struct device *, struct device *, 4797403Sobrien struct pcibus_attach_args *)); 4897403Sobrienint cia_bus_maxdevs __P((void *, int)); 4997403Sobrienpcitag_t cia_make_tag __P((void *, int, int, int)); 5097403Sobrienvoid cia_decompose_tag __P((void *, pcitag_t, int *, int *, 5197403Sobrien int *)); 5297403Sobrienpcireg_t cia_conf_read __P((void *, pcitag_t, int)); 5397403Sobrienvoid cia_conf_write __P((void *, pcitag_t, int, pcireg_t)); 5497403Sobrien 5597403Sobrienvoid 5697403Sobriencia_pci_init(pc, v) 5797403Sobrien pci_chipset_tag_t pc; 5897403Sobrien void *v; 5997403Sobrien{ 6097403Sobrien 6197403Sobrien pc->pc_conf_v = v; 6297403Sobrien pc->pc_attach_hook = cia_attach_hook; 6397403Sobrien pc->pc_bus_maxdevs = cia_bus_maxdevs; 6497403Sobrien pc->pc_make_tag = cia_make_tag; 6597403Sobrien pc->pc_decompose_tag = cia_decompose_tag; 6697403Sobrien pc->pc_conf_read = cia_conf_read; 6797403Sobrien pc->pc_conf_write = cia_conf_write; 6897403Sobrien} 6997403Sobrien 7097403Sobrienvoid 7197403Sobriencia_attach_hook(parent, self, pba) 7297403Sobrien struct device *parent, *self; 7397403Sobrien struct pcibus_attach_args *pba; 7497403Sobrien{ 7597403Sobrien} 7697403Sobrien 7797403Sobrienint 7897403Sobriencia_bus_maxdevs(cpv, busno) 7997403Sobrien void *cpv; 8097403Sobrien int busno; 8197403Sobrien{ 8297403Sobrien 8397403Sobrien return 32; 8497403Sobrien} 8597403Sobrien 8697403Sobrienpcitag_t 8797403Sobriencia_make_tag(cpv, b, d, f) 8897403Sobrien void *cpv; 8997403Sobrien int b, d, f; 9097403Sobrien{ 9197403Sobrien 9297403Sobrien return (b << 16) | (d << 11) | (f << 8); 9397403Sobrien} 9497403Sobrien 9597403Sobrienvoid 9697403Sobriencia_decompose_tag(cpv, tag, bp, dp, fp) 9797403Sobrien void *cpv; 9897403Sobrien pcitag_t tag; 9997403Sobrien int *bp, *dp, *fp; 10097403Sobrien{ 10197403Sobrien 10297403Sobrien if (bp != NULL) 10397403Sobrien *bp = (tag >> 16) & 0xff; 10497403Sobrien if (dp != NULL) 10597403Sobrien *dp = (tag >> 11) & 0x1f; 10697403Sobrien if (fp != NULL) 10797403Sobrien *fp = (tag >> 8) & 0x7; 10897403Sobrien} 10997403Sobrien 11097403Sobrienpcireg_t 11197403Sobriencia_conf_read(cpv, tag, offset) 11297403Sobrien void *cpv; 11397403Sobrien pcitag_t tag; 11497403Sobrien int offset; 11597403Sobrien{ 11697403Sobrien struct cia_config *ccp = cpv; 11797403Sobrien pcireg_t *datap, data; 11897403Sobrien int s, secondary, ba; 11997403Sobrien u_int32_t old_cfg, errbits; 12097403Sobrien 12197403Sobrien#ifdef __GNUC__ 12297403Sobrien s = 0; /* XXX gcc -Wuninitialized */ 12397403Sobrien old_cfg = 0; /* XXX gcc -Wuninitialized */ 12497403Sobrien#endif 12597403Sobrien 12697403Sobrien /* 12797403Sobrien * Some (apparently-common) revisions of EB164 and AlphaStation 12897403Sobrien * firmware do the Wrong thing with PCI master and target aborts, 12997403Sobrien * which are caused by accesing the configuration space of devices 13097403Sobrien * that don't exist (for example). 13197403Sobrien * 13297403Sobrien * To work around this, we clear the CIA error register's PCI 13397403Sobrien * master and target abort bits before touching PCI configuration 13497403Sobrien * space and check it afterwards. If it indicates a master or target 13597403Sobrien * abort, the device wasn't there so we return 0xffffffff. 13697403Sobrien */ 13797403Sobrien REGVAL(CIA_CSR_CIA_ERR) = CIA_ERR_RCVD_MAS_ABT|CIA_ERR_RCVD_TAR_ABT; 13897403Sobrien alpha_mb(); 13997403Sobrien alpha_pal_draina(); 14097403Sobrien 14197403Sobrien /* secondary if bus # != 0 */ 14297403Sobrien alpha_pci_decompose_tag(&ccp->cc_pc, tag, &secondary, 0, 0); 14397403Sobrien if (secondary) { 14497403Sobrien s = splhigh(); 14597403Sobrien old_cfg = REGVAL(CIA_CSR_CFG); 14697403Sobrien alpha_mb(); 14797403Sobrien REGVAL(CIA_CSR_CFG) = old_cfg | 0x1; 14897403Sobrien alpha_mb(); 14997403Sobrien } 15097403Sobrien 15197403Sobrien /* 15297403Sobrien * We just inline the BWX support, since this is the only 15397403Sobrien * difference between BWX and swiz for config space. 15497403Sobrien */ 15597403Sobrien if (ccp->cc_flags & CCF_PCI_USE_BWX) { 15697403Sobrien if (secondary) { 15797403Sobrien datap = 15897403Sobrien (pcireg_t *)ALPHA_PHYS_TO_K0SEG(CIA_EV56_BWCONF1 | 15997403Sobrien tag | (offset & ~0x03)); 16097403Sobrien } else { 16197403Sobrien datap = 16297403Sobrien (pcireg_t *)ALPHA_PHYS_TO_K0SEG(CIA_EV56_BWCONF0 | 16397403Sobrien tag | (offset & ~0x03)); 16497403Sobrien } 16597403Sobrien } else { 16697403Sobrien datap = (pcireg_t *)ALPHA_PHYS_TO_K0SEG(CIA_PCI_CONF | 16797403Sobrien tag << 5UL | /* XXX */ 16897403Sobrien (offset & ~0x03) << 5 | /* XXX */ 16997403Sobrien 0 << 5 | /* XXX */ 17097403Sobrien 0x3 << 3); /* XXX */ 17197403Sobrien } 17297403Sobrien data = (pcireg_t)-1; 17397403Sobrien alpha_mb(); 17497403Sobrien if (!(ba = badaddr(datap, sizeof *datap))) 17597403Sobrien data = *datap; 17697403Sobrien alpha_mb(); 17797403Sobrien alpha_mb(); 17897403Sobrien 17997403Sobrien if (secondary) { 18097403Sobrien alpha_mb(); 18197403Sobrien REGVAL(CIA_CSR_CFG) = old_cfg; 18297403Sobrien alpha_mb(); 18397403Sobrien splx(s); 18497403Sobrien } 18597403Sobrien 18697403Sobrien alpha_pal_draina(); 18797403Sobrien alpha_mb(); 18897403Sobrien errbits = REGVAL(CIA_CSR_CIA_ERR); 18997403Sobrien if (errbits & (CIA_ERR_RCVD_MAS_ABT|CIA_ERR_RCVD_TAR_ABT)) { 19097403Sobrien ba = 1; 19197403Sobrien data = 0xffffffff; 19297403Sobrien } 19397403Sobrien 19497403Sobrien if (errbits) { 19597403Sobrien REGVAL(CIA_CSR_CIA_ERR) = errbits; 19697403Sobrien alpha_mb(); 19797403Sobrien alpha_pal_draina(); 19897403Sobrien } 19997403Sobrien 20097403Sobrien#if 0 20197403Sobrien printf("cia_conf_read: tag 0x%lx, reg 0x%lx -> %x @ %p%s\n", tag, reg, 20297403Sobrien data, datap, ba ? " (badaddr)" : ""); 20397403Sobrien#endif 20497403Sobrien 20597403Sobrien return data; 20697403Sobrien} 20797403Sobrien 20897403Sobrienvoid 20997403Sobriencia_conf_write(cpv, tag, offset, data) 21097403Sobrien void *cpv; 21197403Sobrien pcitag_t tag; 21297403Sobrien int offset; 21397403Sobrien pcireg_t data; 21497403Sobrien{ 21597403Sobrien struct cia_config *ccp = cpv; 21697403Sobrien pcireg_t *datap; 21797403Sobrien int s, secondary; 21897403Sobrien u_int32_t old_cfg; 21997403Sobrien 22097403Sobrien#ifdef __GNUC__ 22197403Sobrien s = 0; /* XXX gcc -Wuninitialized */ 22297403Sobrien old_cfg = 0; /* XXX gcc -Wuninitialized */ 22397403Sobrien#endif 22497403Sobrien 22597403Sobrien /* secondary if bus # != 0 */ 22697403Sobrien alpha_pci_decompose_tag(&ccp->cc_pc, tag, &secondary, 0, 0); 22797403Sobrien if (secondary) { 22897403Sobrien s = splhigh(); 22997403Sobrien old_cfg = REGVAL(CIA_CSR_CFG); 23097403Sobrien alpha_mb(); 23197403Sobrien REGVAL(CIA_CSR_CFG) = old_cfg | 0x1; 23297403Sobrien alpha_mb(); 23397403Sobrien } 23497403Sobrien 23597403Sobrien /* 23697403Sobrien * We just inline the BWX support, since this is the only 23797403Sobrien * difference between BWX and swiz for config space. 23897403Sobrien */ 23997403Sobrien if (ccp->cc_flags & CCF_PCI_USE_BWX) { 24097403Sobrien if (secondary) { 24197403Sobrien datap = 24297403Sobrien (pcireg_t *)ALPHA_PHYS_TO_K0SEG(CIA_EV56_BWCONF1 | 24397403Sobrien tag | (offset & ~0x03)); 24497403Sobrien } else { 24597403Sobrien datap = 24697403Sobrien (pcireg_t *)ALPHA_PHYS_TO_K0SEG(CIA_EV56_BWCONF0 | 24797403Sobrien tag | (offset & ~0x03)); 24897403Sobrien } 24997403Sobrien } else { 25097403Sobrien datap = (pcireg_t *)ALPHA_PHYS_TO_K0SEG(CIA_PCI_CONF | 25197403Sobrien tag << 5UL | /* XXX */ 25297403Sobrien (offset & ~0x03) << 5 | /* XXX */ 25397403Sobrien 0 << 5 | /* XXX */ 25497403Sobrien 0x3 << 3); /* XXX */ 25597403Sobrien } 25697403Sobrien alpha_mb(); 25797403Sobrien *datap = data; 25897403Sobrien alpha_mb(); 25997403Sobrien alpha_mb(); 26097403Sobrien 26197403Sobrien if (secondary) { 26297403Sobrien alpha_mb(); 26397403Sobrien REGVAL(CIA_CSR_CFG) = old_cfg; 26497403Sobrien alpha_mb(); 26597403Sobrien splx(s); 26697403Sobrien } 26797403Sobrien 26897403Sobrien#if 0 26997403Sobrien printf("cia_conf_write: tag 0x%lx, reg 0x%lx -> 0x%x @ %p\n", tag, 27097403Sobrien reg, data, datap); 27197403Sobrien#endif 27297403Sobrien} 27397403Sobrien