⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pci_schizo.c

📁 microwindows移植到S3C44B0的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* $Id: pci_schizo.c,v 1.23.2.2 2002/03/11 07:55:24 davem Exp $ * pci_schizo.c: SCHIZO specific PCI controller support. * * Copyright (C) 2001 David S. Miller (davem@redhat.com) */#include <linux/kernel.h>#include <linux/types.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/slab.h>#include <asm/pbm.h>#include <asm/iommu.h>#include <asm/irq.h>#include <asm/upa.h>#include "pci_impl.h"#include "iommu_common.h"/* All SCHIZO registers are 64-bits.  The following accessor * routines are how they are accessed.  The REG parameter * is a physical address. */#define schizo_read(__reg) \({	u64 __ret; \	__asm__ __volatile__("ldxa [%1] %2, %0" \			     : "=r" (__ret) \			     : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \			     : "memory"); \	__ret; \})#define schizo_write(__reg, __val) \	__asm__ __volatile__("stxa %0, [%1] %2" \			     : /* no outputs */ \			     : "r" (__val), "r" (__reg), \			       "i" (ASI_PHYS_BYPASS_EC_E) \			     : "memory")/* This is a convention that at least Excalibur and Merlin * follow.  I suppose the SCHIZO used in Starcat and friends * will do similar. * * The only way I could see this changing is if the newlink * block requires more space in Schizo's address space than * they predicted, thus requiring an address space reorg when * the newer Schizo is taped out. * * These offsets look weird because I keep in p->controller_regs * the second PROM register property minus 0x10000 which is the * base of the Safari and UPA64S registers of SCHIZO. */#define SCHIZO_PBM_A_REGS_OFF	(0x600000UL - 0x400000UL)#define SCHIZO_PBM_B_REGS_OFF	(0x700000UL - 0x400000UL)/* Streaming buffer control register. */#define SCHIZO_STRBUF_CTRL_LPTR    0x00000000000000f0UL /* LRU Lock Pointer */#define SCHIZO_STRBUF_CTRL_LENAB   0x0000000000000008UL /* LRU Lock Enable */#define SCHIZO_STRBUF_CTRL_RRDIS   0x0000000000000004UL /* Rerun Disable */#define SCHIZO_STRBUF_CTRL_DENAB   0x0000000000000002UL /* Diagnostic Mode Enable */#define SCHIZO_STRBUF_CTRL_ENAB    0x0000000000000001UL /* Streaming Buffer Enable *//* IOMMU control register. */#define SCHIZO_IOMMU_CTRL_RESV     0xfffffffff9000000 /* Reserved                      */#define SCHIZO_IOMMU_CTRL_XLTESTAT 0x0000000006000000 /* Translation Error Status      */#define SCHIZO_IOMMU_CTRL_XLTEERR  0x0000000001000000 /* Translation Error encountered */#define SCHIZO_IOMMU_CTRL_LCKEN    0x0000000000800000 /* Enable translation locking    */#define SCHIZO_IOMMU_CTRL_LCKPTR   0x0000000000780000 /* Translation lock pointer      */#define SCHIZO_IOMMU_CTRL_TSBSZ    0x0000000000070000 /* TSB Size                      */#define SCHIZO_IOMMU_TSBSZ_1K      0x0000000000000000 /* TSB Table 1024 8-byte entries */#define SCHIZO_IOMMU_TSBSZ_2K      0x0000000000010000 /* TSB Table 2048 8-byte entries */#define SCHIZO_IOMMU_TSBSZ_4K      0x0000000000020000 /* TSB Table 4096 8-byte entries */#define SCHIZO_IOMMU_TSBSZ_8K      0x0000000000030000 /* TSB Table 8192 8-byte entries */#define SCHIZO_IOMMU_TSBSZ_16K     0x0000000000040000 /* TSB Table 16k 8-byte entries  */#define SCHIZO_IOMMU_TSBSZ_32K     0x0000000000050000 /* TSB Table 32k 8-byte entries  */#define SCHIZO_IOMMU_TSBSZ_64K     0x0000000000060000 /* TSB Table 64k 8-byte entries  */#define SCHIZO_IOMMU_TSBSZ_128K    0x0000000000070000 /* TSB Table 128k 8-byte entries */#define SCHIZO_IOMMU_CTRL_RESV2    0x000000000000fff8 /* Reserved                      */#define SCHIZO_IOMMU_CTRL_TBWSZ    0x0000000000000004 /* Assumed page size, 0=8k 1=64k */#define SCHIZO_IOMMU_CTRL_DENAB    0x0000000000000002 /* Diagnostic mode enable        */#define SCHIZO_IOMMU_CTRL_ENAB     0x0000000000000001 /* IOMMU Enable                  *//* Schizo config space address format is nearly identical to * that of PSYCHO: * *  32             24 23 16 15    11 10       8 7   2  1 0 * --------------------------------------------------------- * |0 0 0 0 0 0 0 0 0| bus | device | function | reg | 0 0 | * --------------------------------------------------------- */#define SCHIZO_CONFIG_BASE(PBM)	((PBM)->config_space)#define SCHIZO_CONFIG_ENCODE(BUS, DEVFN, REG)	\	(((unsigned long)(BUS)   << 16) |	\	 ((unsigned long)(DEVFN) << 8)  |	\	 ((unsigned long)(REG)))static void *schizo_pci_config_mkaddr(struct pci_pbm_info *pbm,				      unsigned char bus,				      unsigned int devfn,				      int where){	if (!pbm)		return NULL;	return (void *)		(SCHIZO_CONFIG_BASE(pbm) |		 SCHIZO_CONFIG_ENCODE(bus, devfn, where));}/* 4 slots on pbm A, and 6 slots on pbm B.  In both cases * slot 0 is the SCHIZO host bridge itself. */static int schizo_out_of_range(struct pci_pbm_info *pbm,			       unsigned char bus,			       unsigned char devfn){	return ((pbm->parent == 0) ||		((pbm == &pbm->parent->pbm_B) &&		 (bus == pbm->pci_first_busno) &&		 PCI_SLOT(devfn) > 6) ||		((pbm == &pbm->parent->pbm_A) &&		 (bus == pbm->pci_first_busno) &&		 PCI_SLOT(devfn) > 4));}/* SCHIZO PCI configuration space accessors. */static int schizo_read_byte(struct pci_dev *dev, int where, u8 *value){	struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];	unsigned char bus = dev->bus->number;	unsigned int devfn = dev->devfn;	u8 *addr;	*value = 0xff;	addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);	if (!addr)		return PCIBIOS_SUCCESSFUL;	if (schizo_out_of_range(pbm, bus, devfn))		return PCIBIOS_SUCCESSFUL;	pci_config_read8(addr, value);	return PCIBIOS_SUCCESSFUL;}static int schizo_read_word(struct pci_dev *dev, int where, u16 *value){	struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];	unsigned char bus = dev->bus->number;	unsigned int devfn = dev->devfn;	u16 *addr;	*value = 0xffff;	addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);	if (!addr)		return PCIBIOS_SUCCESSFUL;	if (schizo_out_of_range(pbm, bus, devfn))		return PCIBIOS_SUCCESSFUL;	if (where & 0x01) {		printk("pcibios_read_config_word: misaligned reg [%x]\n",		       where);		return PCIBIOS_SUCCESSFUL;	}	pci_config_read16(addr, value);	return PCIBIOS_SUCCESSFUL;}static int schizo_read_dword(struct pci_dev *dev, int where, u32 *value){	struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];	unsigned char bus = dev->bus->number;	unsigned int devfn = dev->devfn;	u32 *addr;	*value = 0xffffffff;	addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);	if (!addr)		return PCIBIOS_SUCCESSFUL;	if (schizo_out_of_range(pbm, bus, devfn))		return PCIBIOS_SUCCESSFUL;	if (where & 0x03) {		printk("pcibios_read_config_dword: misaligned reg [%x]\n",		       where);		return PCIBIOS_SUCCESSFUL;	}	pci_config_read32(addr, value);	return PCIBIOS_SUCCESSFUL;}static int schizo_write_byte(struct pci_dev *dev, int where, u8 value){	struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];	unsigned char bus = dev->bus->number;	unsigned int devfn = dev->devfn;	u8 *addr;	addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);	if (!addr)		return PCIBIOS_SUCCESSFUL;	if (schizo_out_of_range(pbm, bus, devfn))		return PCIBIOS_SUCCESSFUL;	pci_config_write8(addr, value);	return PCIBIOS_SUCCESSFUL;}static int schizo_write_word(struct pci_dev *dev, int where, u16 value){	struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];	unsigned char bus = dev->bus->number;	unsigned int devfn = dev->devfn;	u16 *addr;	addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);	if (!addr)		return PCIBIOS_SUCCESSFUL;	if (schizo_out_of_range(pbm, bus, devfn))		return PCIBIOS_SUCCESSFUL;	if (where & 0x01) {		printk("pcibios_write_config_word: misaligned reg [%x]\n",		       where);		return PCIBIOS_SUCCESSFUL;	}	pci_config_write16(addr, value);	return PCIBIOS_SUCCESSFUL;}static int schizo_write_dword(struct pci_dev *dev, int where, u32 value){	struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];	unsigned char bus = dev->bus->number;	unsigned int devfn = dev->devfn;	u32 *addr;	addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where);	if (!addr)		return PCIBIOS_SUCCESSFUL;	if (schizo_out_of_range(pbm, bus, devfn))		return PCIBIOS_SUCCESSFUL;	if (where & 0x03) {		printk("pcibios_write_config_dword: misaligned reg [%x]\n",		       where);		return PCIBIOS_SUCCESSFUL;	}	pci_config_write32(addr, value);	return PCIBIOS_SUCCESSFUL;}static struct pci_ops schizo_ops = {	schizo_read_byte,	schizo_read_word,	schizo_read_dword,	schizo_write_byte,	schizo_write_word,	schizo_write_dword};/* SCHIZO interrupt mapping support.  Unlike Psycho, for this controller the * imap/iclr registers are per-PBM. */#define SCHIZO_IMAP_BASE	0x1000UL#define SCHIZO_ICLR_BASE	0x1400ULstatic unsigned long schizo_imap_offset(unsigned long ino){	return SCHIZO_IMAP_BASE + (ino * 8UL);}static unsigned long schizo_iclr_offset(unsigned long ino){	return SCHIZO_ICLR_BASE + (ino * 8UL);}/* PCI SCHIZO INO number to Sparc PIL level.  This table only matters for * INOs which will not have an associated PCI device struct, ie. onboard * EBUS devices and PCI controller internal error interrupts. */static unsigned char schizo_pil_table[] = {/*0x00*/0, 0, 0, 0,	/* PCI slot 0  Int A, B, C, D	*//*0x04*/0, 0, 0, 0,	/* PCI slot 1  Int A, B, C, D	*//*0x08*/0, 0, 0, 0,	/* PCI slot 2  Int A, B, C, D	*//*0x0c*/0, 0, 0, 0,	/* PCI slot 3  Int A, B, C, D	*//*0x10*/0, 0, 0, 0,	/* PCI slot 4  Int A, B, C, D	*//*0x14*/0, 0, 0, 0,	/* PCI slot 5  Int A, B, C, D	*//*0x18*/4,		/* SCSI				*//*0x19*/4,		/* second SCSI			*//*0x1a*/0,		/* UNKNOWN			*//*0x1b*/0,		/* UNKNOWN			*//*0x1c*/8,		/* Parallel			*//*0x1d*/5,		/* Ethernet			*//*0x1e*/8,		/* Firewire-1394		*//*0x1f*/9,		/* USB				*//*0x20*/13,		/* Audio Record			*//*0x21*/14,		/* Audio Playback		*//*0x22*/12,		/* Serial			*//*0x23*/4,		/* EBUS I2C 			*//*0x24*/10,		/* RTC Clock			*//*0x25*/11,		/* Floppy			*//*0x26*/0,		/* UNKNOWN			*//*0x27*/0,		/* UNKNOWN			*//*0x28*/0,		/* UNKNOWN			*//*0x29*/0,		/* UNKNOWN			*//*0x2a*/10,		/* UPA 1			*//*0x2b*/10,		/* UPA 2			*//*0x2c*/0,		/* UNKNOWN			*//*0x2d*/0,		/* UNKNOWN			*//*0x2e*/0,		/* UNKNOWN			*//*0x2f*/0,		/* UNKNOWN			*//*0x30*/15,		/* Uncorrectable ECC		*//*0x31*/15,		/* Correctable ECC		*//*0x32*/15,		/* PCI Bus A Error		*//*0x33*/15,		/* PCI Bus B Error		*//*0x34*/15,		/* Safari Bus Error		*//*0x35*/0,		/* Reserved			*//*0x36*/0,		/* Reserved			*//*0x37*/0,		/* Reserved			*//*0x38*/0,		/* Reserved for NewLink		*//*0x39*/0,		/* Reserved for NewLink		*//*0x3a*/0,		/* Reserved for NewLink		*//*0x3b*/0,		/* Reserved for NewLink		*//*0x3c*/0,		/* Reserved for NewLink		*//*0x3d*/0,		/* Reserved for NewLink		*//*0x3e*/0,		/* Reserved for NewLink		*//*0x3f*/0,		/* Reserved for NewLink		*/};static int __init schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino){	int ret;	if (pdev &&	    pdev->vendor == PCI_VENDOR_ID_SUN &&	    pdev->device == PCI_DEVICE_ID_SUN_RIO_USB)		return 9;	ret = schizo_pil_table[ino];	if (ret == 0 && pdev == NULL) {		ret = 4;	} else if (ret == 0) {		switch ((pdev->class >> 16) & 0xff) {		case PCI_BASE_CLASS_STORAGE:			ret = 4;			break;		case PCI_BASE_CLASS_NETWORK:			ret = 6;			break;		case PCI_BASE_CLASS_DISPLAY:			ret = 9;			break;		case PCI_BASE_CLASS_MULTIMEDIA:		case PCI_BASE_CLASS_MEMORY:		case PCI_BASE_CLASS_BRIDGE:		case PCI_BASE_CLASS_SERIAL:			ret = 10;			break;		default:			ret = 4;			break;		};	}	return ret;}static unsigned int __init schizo_irq_build(struct pci_pbm_info *pbm,					    struct pci_dev *pdev,					    unsigned int ino){	struct pci_controller_info *p = pbm->parent;	struct ino_bucket *bucket;	unsigned long imap, iclr, pbm_off;	unsigned long imap_off, iclr_off;	int pil;	if (pbm == &p->pbm_A)		pbm_off = SCHIZO_PBM_A_REGS_OFF;	else		pbm_off = SCHIZO_PBM_B_REGS_OFF;	ino &= PCI_IRQ_INO;	imap_off = schizo_imap_offset(ino);	/* Now build the IRQ bucket. */	pil = schizo_ino_to_pil(pdev, ino);	if (PIL_RESERVED(pil))		BUG();	imap = p->controller_regs + pbm_off + imap_off;	imap += 4;	iclr_off = schizo_iclr_offset(ino);	iclr = p->controller_regs + pbm_off + iclr_off;	iclr += 4;	/* On Schizo, no inofixup occurs.  This is because each	 * INO has it's own IMAP register.  On Psycho and Sabre	 * there is only one IMAP register for each PCI slot even	 * though four different INOs can be generated by each	 * PCI slot.	 */	bucket = __bucket(build_irq(pil, 0, iclr, imap));	bucket->flags |= IBF_PCI;	return __irq(bucket);}/* SCHIZO error handling support. */enum schizo_error_type {	UE_ERR, CE_ERR, PCI_ERR, SAFARI_ERR};static spinlock_t stc_buf_lock = SPIN_LOCK_UNLOCKED;static unsigned long stc_error_buf[128];static unsigned long stc_tag_buf[16];static unsigned long stc_line_buf[16];static void schizo_clear_other_err_intr(int irq){	struct ino_bucket *bucket = __bucket(irq);	unsigned long iclr = bucket->iclr;	iclr += (SCHIZO_PBM_B_REGS_OFF - SCHIZO_PBM_A_REGS_OFF);	upa_writel(ICLR_IDLE, iclr);}#define SCHIZO_STC_ERR	0xb800UL /* --> 0xba00 */#define SCHIZO_STC_TAG	0xba00UL /* --> 0xba80 */#define SCHIZO_STC_LINE	0xbb00UL /* --> 0xbb80 */#define SCHIZO_STCERR_WRITE	0x2UL#define SCHIZO_STCERR_READ	0x1UL#define SCHIZO_STCTAG_PPN	0x3fffffff00000000UL#define SCHIZO_STCTAG_VPN	0x00000000ffffe000UL#define SCHIZO_STCTAG_VALID	0x8000000000000000UL#define SCHIZO_STCTAG_READ	0x4000000000000000UL#define SCHIZO_STCLINE_LINDX	0x0000000007800000UL#define SCHIZO_STCLINE_SPTR	0x000000000007e000UL#define SCHIZO_STCLINE_LADDR	0x0000000000001fc0UL#define SCHIZO_STCLINE_EPTR	0x000000000000003fUL#define SCHIZO_STCLINE_VALID	0x0000000000600000UL#define SCHIZO_STCLINE_FOFN	0x0000000000180000ULstatic void __schizo_check_stc_error_pbm(struct pci_pbm_info *pbm,					 enum schizo_error_type type){	struct pci_controller_info *p = pbm->parent;	struct pci_strbuf *strbuf = &pbm->stc;	unsigned long regbase = p->controller_regs;	unsigned long err_base, tag_base, line_base;	u64 control;	char pbm_name = (pbm == &p->pbm_A ? 'A' : 'B');	int i;	if (pbm == &p->pbm_A)		regbase += SCHIZO_PBM_A_REGS_OFF;	else		regbase += SCHIZO_PBM_B_REGS_OFF;	err_base = regbase + SCHIZO_STC_ERR;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -