📄 pci_psycho.c
字号:
/* $Id: pci_psycho.c,v 1.17 2000/09/21 06:25:14 anton Exp $ * pci_psycho.c: PSYCHO/U2P specific PCI controller support. * * Copyright (C) 1997, 1998, 1999 David S. Miller (davem@caipfs.rutgers.edu) * Copyright (C) 1998, 1999 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com) */#include <linux/kernel.h>#include <linux/types.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/malloc.h>#include <asm/pbm.h>#include <asm/iommu.h>#include <asm/irq.h>#include <asm/starfire.h>#include "pci_impl.h"/* All PSYCHO registers are 64-bits. The following accessor * routines are how they are accessed. The REG parameter * is a physical address. */#define psycho_read(__reg) \({ u64 __ret; \ __asm__ __volatile__("ldxa [%1] %2, %0" \ : "=r" (__ret) \ : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ : "memory"); \ __ret; \})#define psycho_write(__reg, __val) \ __asm__ __volatile__("stxa %0, [%1] %2" \ : /* no outputs */ \ : "r" (__val), "r" (__reg), \ "i" (ASI_PHYS_BYPASS_EC_E))/* Misc. PSYCHO PCI controller register offsets and definitions. */#define PSYCHO_CONTROL 0x0010UL#define PSYCHO_CONTROL_IMPL 0xf000000000000000 /* Implementation of this PSYCHO*/#define PSYCHO_CONTROL_VER 0x0f00000000000000 /* Version of this PSYCHO */#define PSYCHO_CONTROL_MID 0x00f8000000000000 /* UPA Module ID of PSYCHO */#define PSYCHO_CONTROL_IGN 0x0007c00000000000 /* Interrupt Group Number */#define PSYCHO_CONTROL_RESV 0x00003ffffffffff0 /* Reserved */#define PSYCHO_CONTROL_APCKEN 0x0000000000000008 /* Address Parity Check Enable */#define PSYCHO_CONTROL_APERR 0x0000000000000004 /* Incoming System Addr Parerr */#define PSYCHO_CONTROL_IAP 0x0000000000000002 /* Invert UPA Parity */#define PSYCHO_CONTROL_MODE 0x0000000000000001 /* PSYCHO clock mode */#define PSYCHO_PCIA_CTRL 0x2000UL#define PSYCHO_PCIB_CTRL 0x4000UL#define PSYCHO_PCICTRL_RESV1 0xfffffff000000000 /* Reserved */#define PSYCHO_PCICTRL_SBH_ERR 0x0000000800000000 /* Streaming byte hole error */#define PSYCHO_PCICTRL_SERR 0x0000000400000000 /* SERR signal asserted */#define PSYCHO_PCICTRL_SPEED 0x0000000200000000 /* PCI speed (1 is U2P clock) */#define PSYCHO_PCICTRL_RESV2 0x00000001ffc00000 /* Reserved */#define PSYCHO_PCICTRL_ARB_PARK 0x0000000000200000 /* PCI arbitration parking */#define PSYCHO_PCICTRL_RESV3 0x00000000001ff800 /* Reserved */#define PSYCHO_PCICTRL_SBH_INT 0x0000000000000400 /* Streaming byte hole int enab */#define PSYCHO_PCICTRL_WEN 0x0000000000000200 /* Power Mgmt Wake Enable */#define PSYCHO_PCICTRL_EEN 0x0000000000000100 /* PCI Error Interrupt Enable */#define PSYCHO_PCICTRL_RESV4 0x00000000000000c0 /* Reserved */#define PSYCHO_PCICTRL_AEN 0x000000000000003f /* PCI DVMA Arbitration Enable *//* U2P Programmer's Manual, page 13-55, configuration space * address format: * * 32 24 23 16 15 11 10 8 7 2 1 0 * --------------------------------------------------------- * |0 0 0 0 0 0 0 0 1| bus | device | function | reg | 0 0 | * --------------------------------------------------------- */#define PSYCHO_CONFIG_BASE(PBM) \ ((PBM)->parent->config_space | (1UL << 24))#define PSYCHO_CONFIG_ENCODE(BUS, DEVFN, REG) \ (((unsigned long)(BUS) << 16) | \ ((unsigned long)(DEVFN) << 8) | \ ((unsigned long)(REG)))static void *psycho_pci_config_mkaddr(struct pci_pbm_info *pbm, unsigned char bus, unsigned int devfn, int where){ if (!pbm) return NULL; return (void *) (PSYCHO_CONFIG_BASE(pbm) | PSYCHO_CONFIG_ENCODE(bus, devfn, where));}static int psycho_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) > 8) || ((pbm == &pbm->parent->pbm_A) && (bus == pbm->pci_first_busno) && PCI_SLOT(devfn) > 8));}/* PSYCHO PCI configuration space accessors. */static int psycho_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 = psycho_pci_config_mkaddr(pbm, bus, devfn, where); if (!addr) return PCIBIOS_SUCCESSFUL; if (psycho_out_of_range(pbm, bus, devfn)) return PCIBIOS_SUCCESSFUL; pci_config_read8(addr, value); return PCIBIOS_SUCCESSFUL;}static int psycho_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 = psycho_pci_config_mkaddr(pbm, bus, devfn, where); if (!addr) return PCIBIOS_SUCCESSFUL; if (psycho_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 psycho_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 = psycho_pci_config_mkaddr(pbm, bus, devfn, where); if (!addr) return PCIBIOS_SUCCESSFUL; if (psycho_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 psycho_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 = psycho_pci_config_mkaddr(pbm, bus, devfn, where); if (!addr) return PCIBIOS_SUCCESSFUL; if (psycho_out_of_range(pbm, bus, devfn)) return PCIBIOS_SUCCESSFUL; pci_config_write8(addr, value); return PCIBIOS_SUCCESSFUL;}static int psycho_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 = psycho_pci_config_mkaddr(pbm, bus, devfn, where); if (!addr) return PCIBIOS_SUCCESSFUL; if (psycho_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 psycho_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 = psycho_pci_config_mkaddr(pbm, bus, devfn, where); if (!addr) return PCIBIOS_SUCCESSFUL; if (psycho_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 psycho_ops = { psycho_read_byte, psycho_read_word, psycho_read_dword, psycho_write_byte, psycho_write_word, psycho_write_dword};/* PSYCHO interrupt mapping support. */#define PSYCHO_IMAP_A_SLOT0 0x0c00UL#define PSYCHO_IMAP_B_SLOT0 0x0c20ULstatic unsigned long psycho_pcislot_imap_offset(unsigned long ino){ unsigned int bus = (ino & 0x10) >> 4; unsigned int slot = (ino & 0x0c) >> 2; if (bus == 0) return PSYCHO_IMAP_A_SLOT0 + (slot * 8); else return PSYCHO_IMAP_B_SLOT0 + (slot * 8);}#define PSYCHO_IMAP_SCSI 0x1000UL#define PSYCHO_IMAP_ETH 0x1008UL#define PSYCHO_IMAP_BPP 0x1010UL#define PSYCHO_IMAP_AU_REC 0x1018UL#define PSYCHO_IMAP_AU_PLAY 0x1020UL#define PSYCHO_IMAP_PFAIL 0x1028UL#define PSYCHO_IMAP_KMS 0x1030UL#define PSYCHO_IMAP_FLPY 0x1038UL#define PSYCHO_IMAP_SHW 0x1040UL#define PSYCHO_IMAP_KBD 0x1048UL#define PSYCHO_IMAP_MS 0x1050UL#define PSYCHO_IMAP_SER 0x1058UL#define PSYCHO_IMAP_TIM0 0x1060UL#define PSYCHO_IMAP_TIM1 0x1068UL#define PSYCHO_IMAP_UE 0x1070UL#define PSYCHO_IMAP_CE 0x1078UL#define PSYCHO_IMAP_A_ERR 0x1080UL#define PSYCHO_IMAP_B_ERR 0x1088UL#define PSYCHO_IMAP_PMGMT 0x1090UL#define PSYCHO_IMAP_GFX 0x1098UL#define PSYCHO_IMAP_EUPA 0x10a0ULstatic unsigned long __onboard_imap_off[] = {/*0x20*/ PSYCHO_IMAP_SCSI,/*0x21*/ PSYCHO_IMAP_ETH,/*0x22*/ PSYCHO_IMAP_BPP,/*0x23*/ PSYCHO_IMAP_AU_REC,/*0x24*/ PSYCHO_IMAP_AU_PLAY,/*0x25*/ PSYCHO_IMAP_PFAIL,/*0x26*/ PSYCHO_IMAP_KMS,/*0x27*/ PSYCHO_IMAP_FLPY,/*0x28*/ PSYCHO_IMAP_SHW,/*0x29*/ PSYCHO_IMAP_KBD,/*0x2a*/ PSYCHO_IMAP_MS,/*0x2b*/ PSYCHO_IMAP_SER,/*0x2c*/ PSYCHO_IMAP_TIM0,/*0x2d*/ PSYCHO_IMAP_TIM1,/*0x2e*/ PSYCHO_IMAP_UE,/*0x2f*/ PSYCHO_IMAP_CE,/*0x30*/ PSYCHO_IMAP_A_ERR,/*0x31*/ PSYCHO_IMAP_B_ERR,/*0x32*/ PSYCHO_IMAP_PMGMT};#define PSYCHO_ONBOARD_IRQ_BASE 0x20#define PSYCHO_ONBOARD_IRQ_LAST 0x32#define psycho_onboard_imap_offset(__ino) \ __onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE]#define PSYCHO_ICLR_A_SLOT0 0x1400UL#define PSYCHO_ICLR_SCSI 0x1800UL#define psycho_iclr_offset(ino) \ ((ino & 0x20) ? (PSYCHO_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ (PSYCHO_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3)))/* PCI PSYCHO INO number to Sparc PIL level. */static unsigned char psycho_pil_table[] = {/*0x00*/0, 0, 0, 0, /* PCI A slot 0 Int A, B, C, D *//*0x04*/0, 0, 0, 0, /* PCI A slot 1 Int A, B, C, D *//*0x08*/0, 0, 0, 0, /* PCI A slot 2 Int A, B, C, D *//*0x0c*/0, 0, 0, 0, /* PCI A slot 3 Int A, B, C, D *//*0x10*/0, 0, 0, 0, /* PCI B slot 0 Int A, B, C, D *//*0x14*/0, 0, 0, 0, /* PCI B slot 1 Int A, B, C, D *//*0x18*/0, 0, 0, 0, /* PCI B slot 2 Int A, B, C, D *//*0x1c*/0, 0, 0, 0, /* PCI B slot 3 Int A, B, C, D *//*0x20*/3, /* SCSI *//*0x21*/5, /* Ethernet *//*0x22*/8, /* Parallel Port *//*0x23*/13, /* Audio Record *//*0x24*/14, /* Audio Playback *//*0x25*/15, /* PowerFail *//*0x26*/3, /* second SCSI *//*0x27*/11, /* Floppy *//*0x28*/2, /* Spare Hardware *//*0x29*/9, /* Keyboard *//*0x2a*/4, /* Mouse *//*0x2b*/12, /* Serial *//*0x2c*/10, /* Timer 0 *//*0x2d*/11, /* Timer 1 *//*0x2e*/15, /* Uncorrectable ECC *//*0x2f*/15, /* Correctable ECC *//*0x30*/15, /* PCI Bus A Error *//*0x31*/15, /* PCI Bus B Error *//*0x32*/1, /* Power Management */};static int __init psycho_ino_to_pil(struct pci_dev *pdev, unsigned int ino){ int ret; ret = psycho_pil_table[ino]; if (ret == 0 && pdev == NULL) { ret = 1; } else if (ret == 0) { switch ((pdev->class >> 16) & 0x0f) { case PCI_BASE_CLASS_STORAGE: ret = 4; case PCI_BASE_CLASS_NETWORK: ret = 6; case PCI_BASE_CLASS_DISPLAY: ret = 9; case PCI_BASE_CLASS_MULTIMEDIA: case PCI_BASE_CLASS_MEMORY: case PCI_BASE_CLASS_BRIDGE: ret = 10; default: ret = 1; }; } return ret;}static unsigned int __init psycho_irq_build(struct pci_controller_info *p, struct pci_dev *pdev, unsigned int ino){ struct ino_bucket *bucket; unsigned long imap, iclr; unsigned long imap_off, iclr_off; int pil, inofixup = 0; ino &= PCI_IRQ_INO; if (ino < PSYCHO_ONBOARD_IRQ_BASE) { /* PCI slot */ imap_off = psycho_pcislot_imap_offset(ino); } else { /* Onboard device */ if (ino > PSYCHO_ONBOARD_IRQ_LAST) { prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino); prom_halt();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -