| David S. Miller | 16ce82d | 2007-04-26 21:08:21 -0700 | [diff] [blame] | 1 | /* pci_sabre.c: Sabre specific PCI controller support. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2 | * | 
| David S. Miller | 16ce82d | 2007-04-26 21:08:21 -0700 | [diff] [blame] | 3 | * Copyright (C) 1997, 1998, 1999, 2007 David S. Miller (davem@davemloft.net) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 4 | * Copyright (C) 1998, 1999 Eddie C. Dost   (ecd@skynet.be) | 
|  | 5 | * Copyright (C) 1999 Jakub Jelinek   (jakub@redhat.com) | 
|  | 6 | */ | 
|  | 7 |  | 
|  | 8 | #include <linux/kernel.h> | 
|  | 9 | #include <linux/types.h> | 
|  | 10 | #include <linux/pci.h> | 
|  | 11 | #include <linux/init.h> | 
|  | 12 | #include <linux/slab.h> | 
|  | 13 | #include <linux/interrupt.h> | 
| Stephen Rothwell | 764f257 | 2008-08-07 15:33:36 -0700 | [diff] [blame] | 14 | #include <linux/of_device.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 15 |  | 
|  | 16 | #include <asm/apb.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 17 | #include <asm/iommu.h> | 
|  | 18 | #include <asm/irq.h> | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 19 | #include <asm/prom.h> | 
| David S. Miller | 87395fc | 2008-09-10 04:13:10 -0700 | [diff] [blame] | 20 | #include <asm/upa.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 21 |  | 
|  | 22 | #include "pci_impl.h" | 
|  | 23 | #include "iommu_common.h" | 
| David S. Miller | a21cff3 | 2008-09-10 03:07:03 -0700 | [diff] [blame] | 24 | #include "psycho_common.h" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 25 |  | 
| David S. Miller | edbe805 | 2008-08-30 03:14:01 -0700 | [diff] [blame] | 26 | #define DRIVER_NAME	"sabre" | 
|  | 27 | #define PFX		DRIVER_NAME ": " | 
|  | 28 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 29 | /* SABRE PCI controller register offsets and definitions. */ | 
|  | 30 | #define SABRE_UE_AFSR		0x0030UL | 
|  | 31 | #define  SABRE_UEAFSR_PDRD	 0x4000000000000000UL	/* Primary PCI DMA Read */ | 
|  | 32 | #define  SABRE_UEAFSR_PDWR	 0x2000000000000000UL	/* Primary PCI DMA Write */ | 
|  | 33 | #define  SABRE_UEAFSR_SDRD	 0x0800000000000000UL	/* Secondary PCI DMA Read */ | 
|  | 34 | #define  SABRE_UEAFSR_SDWR	 0x0400000000000000UL	/* Secondary PCI DMA Write */ | 
|  | 35 | #define  SABRE_UEAFSR_SDTE	 0x0200000000000000UL	/* Secondary DMA Translation Error */ | 
|  | 36 | #define  SABRE_UEAFSR_PDTE	 0x0100000000000000UL	/* Primary DMA Translation Error */ | 
|  | 37 | #define  SABRE_UEAFSR_BMSK	 0x0000ffff00000000UL	/* Bytemask */ | 
|  | 38 | #define  SABRE_UEAFSR_OFF	 0x00000000e0000000UL	/* Offset (AFAR bits [5:3] */ | 
|  | 39 | #define  SABRE_UEAFSR_BLK	 0x0000000000800000UL	/* Was block operation */ | 
|  | 40 | #define SABRE_UECE_AFAR		0x0038UL | 
|  | 41 | #define SABRE_CE_AFSR		0x0040UL | 
|  | 42 | #define  SABRE_CEAFSR_PDRD	 0x4000000000000000UL	/* Primary PCI DMA Read */ | 
|  | 43 | #define  SABRE_CEAFSR_PDWR	 0x2000000000000000UL	/* Primary PCI DMA Write */ | 
|  | 44 | #define  SABRE_CEAFSR_SDRD	 0x0800000000000000UL	/* Secondary PCI DMA Read */ | 
|  | 45 | #define  SABRE_CEAFSR_SDWR	 0x0400000000000000UL	/* Secondary PCI DMA Write */ | 
|  | 46 | #define  SABRE_CEAFSR_ESYND	 0x00ff000000000000UL	/* ECC Syndrome */ | 
|  | 47 | #define  SABRE_CEAFSR_BMSK	 0x0000ffff00000000UL	/* Bytemask */ | 
|  | 48 | #define  SABRE_CEAFSR_OFF	 0x00000000e0000000UL	/* Offset */ | 
|  | 49 | #define  SABRE_CEAFSR_BLK	 0x0000000000800000UL	/* Was block operation */ | 
|  | 50 | #define SABRE_UECE_AFAR_ALIAS	0x0048UL	/* Aliases to 0x0038 */ | 
|  | 51 | #define SABRE_IOMMU_CONTROL	0x0200UL | 
|  | 52 | #define  SABRE_IOMMUCTRL_ERRSTS	 0x0000000006000000UL	/* Error status bits */ | 
|  | 53 | #define  SABRE_IOMMUCTRL_ERR	 0x0000000001000000UL	/* Error present in IOTLB */ | 
|  | 54 | #define  SABRE_IOMMUCTRL_LCKEN	 0x0000000000800000UL	/* IOTLB lock enable */ | 
|  | 55 | #define  SABRE_IOMMUCTRL_LCKPTR	 0x0000000000780000UL	/* IOTLB lock pointer */ | 
|  | 56 | #define  SABRE_IOMMUCTRL_TSBSZ	 0x0000000000070000UL	/* TSB Size */ | 
|  | 57 | #define  SABRE_IOMMU_TSBSZ_1K   0x0000000000000000 | 
|  | 58 | #define  SABRE_IOMMU_TSBSZ_2K   0x0000000000010000 | 
|  | 59 | #define  SABRE_IOMMU_TSBSZ_4K   0x0000000000020000 | 
|  | 60 | #define  SABRE_IOMMU_TSBSZ_8K   0x0000000000030000 | 
|  | 61 | #define  SABRE_IOMMU_TSBSZ_16K  0x0000000000040000 | 
|  | 62 | #define  SABRE_IOMMU_TSBSZ_32K  0x0000000000050000 | 
|  | 63 | #define  SABRE_IOMMU_TSBSZ_64K  0x0000000000060000 | 
|  | 64 | #define  SABRE_IOMMU_TSBSZ_128K 0x0000000000070000 | 
|  | 65 | #define  SABRE_IOMMUCTRL_TBWSZ	 0x0000000000000004UL	/* TSB assumed page size */ | 
|  | 66 | #define  SABRE_IOMMUCTRL_DENAB	 0x0000000000000002UL	/* Diagnostic Mode Enable */ | 
|  | 67 | #define  SABRE_IOMMUCTRL_ENAB	 0x0000000000000001UL	/* IOMMU Enable */ | 
|  | 68 | #define SABRE_IOMMU_TSBBASE	0x0208UL | 
|  | 69 | #define SABRE_IOMMU_FLUSH	0x0210UL | 
|  | 70 | #define SABRE_IMAP_A_SLOT0	0x0c00UL | 
|  | 71 | #define SABRE_IMAP_B_SLOT0	0x0c20UL | 
|  | 72 | #define SABRE_IMAP_SCSI		0x1000UL | 
|  | 73 | #define SABRE_IMAP_ETH		0x1008UL | 
|  | 74 | #define SABRE_IMAP_BPP		0x1010UL | 
|  | 75 | #define SABRE_IMAP_AU_REC	0x1018UL | 
|  | 76 | #define SABRE_IMAP_AU_PLAY	0x1020UL | 
|  | 77 | #define SABRE_IMAP_PFAIL	0x1028UL | 
|  | 78 | #define SABRE_IMAP_KMS		0x1030UL | 
|  | 79 | #define SABRE_IMAP_FLPY		0x1038UL | 
|  | 80 | #define SABRE_IMAP_SHW		0x1040UL | 
|  | 81 | #define SABRE_IMAP_KBD		0x1048UL | 
|  | 82 | #define SABRE_IMAP_MS		0x1050UL | 
|  | 83 | #define SABRE_IMAP_SER		0x1058UL | 
|  | 84 | #define SABRE_IMAP_UE		0x1070UL | 
|  | 85 | #define SABRE_IMAP_CE		0x1078UL | 
|  | 86 | #define SABRE_IMAP_PCIERR	0x1080UL | 
|  | 87 | #define SABRE_IMAP_GFX		0x1098UL | 
|  | 88 | #define SABRE_IMAP_EUPA		0x10a0UL | 
|  | 89 | #define SABRE_ICLR_A_SLOT0	0x1400UL | 
|  | 90 | #define SABRE_ICLR_B_SLOT0	0x1480UL | 
|  | 91 | #define SABRE_ICLR_SCSI		0x1800UL | 
|  | 92 | #define SABRE_ICLR_ETH		0x1808UL | 
|  | 93 | #define SABRE_ICLR_BPP		0x1810UL | 
|  | 94 | #define SABRE_ICLR_AU_REC	0x1818UL | 
|  | 95 | #define SABRE_ICLR_AU_PLAY	0x1820UL | 
|  | 96 | #define SABRE_ICLR_PFAIL	0x1828UL | 
|  | 97 | #define SABRE_ICLR_KMS		0x1830UL | 
|  | 98 | #define SABRE_ICLR_FLPY		0x1838UL | 
|  | 99 | #define SABRE_ICLR_SHW		0x1840UL | 
|  | 100 | #define SABRE_ICLR_KBD		0x1848UL | 
|  | 101 | #define SABRE_ICLR_MS		0x1850UL | 
|  | 102 | #define SABRE_ICLR_SER		0x1858UL | 
|  | 103 | #define SABRE_ICLR_UE		0x1870UL | 
|  | 104 | #define SABRE_ICLR_CE		0x1878UL | 
|  | 105 | #define SABRE_ICLR_PCIERR	0x1880UL | 
|  | 106 | #define SABRE_WRSYNC		0x1c20UL | 
|  | 107 | #define SABRE_PCICTRL		0x2000UL | 
|  | 108 | #define  SABRE_PCICTRL_MRLEN	 0x0000001000000000UL	/* Use MemoryReadLine for block loads/stores */ | 
|  | 109 | #define  SABRE_PCICTRL_SERR	 0x0000000400000000UL	/* Set when SERR asserted on PCI bus */ | 
|  | 110 | #define  SABRE_PCICTRL_ARBPARK	 0x0000000000200000UL	/* Bus Parking 0=Ultra-IIi 1=prev-bus-owner */ | 
|  | 111 | #define  SABRE_PCICTRL_CPUPRIO	 0x0000000000100000UL	/* Ultra-IIi granted every other bus cycle */ | 
|  | 112 | #define  SABRE_PCICTRL_ARBPRIO	 0x00000000000f0000UL	/* Slot which is granted every other bus cycle */ | 
|  | 113 | #define  SABRE_PCICTRL_ERREN	 0x0000000000000100UL	/* PCI Error Interrupt Enable */ | 
|  | 114 | #define  SABRE_PCICTRL_RTRYWE	 0x0000000000000080UL	/* DMA Flow Control 0=wait-if-possible 1=retry */ | 
|  | 115 | #define  SABRE_PCICTRL_AEN	 0x000000000000000fUL	/* Slot PCI arbitration enables */ | 
|  | 116 | #define SABRE_PIOAFSR		0x2010UL | 
|  | 117 | #define  SABRE_PIOAFSR_PMA	 0x8000000000000000UL	/* Primary Master Abort */ | 
|  | 118 | #define  SABRE_PIOAFSR_PTA	 0x4000000000000000UL	/* Primary Target Abort */ | 
|  | 119 | #define  SABRE_PIOAFSR_PRTRY	 0x2000000000000000UL	/* Primary Excessive Retries */ | 
|  | 120 | #define  SABRE_PIOAFSR_PPERR	 0x1000000000000000UL	/* Primary Parity Error */ | 
|  | 121 | #define  SABRE_PIOAFSR_SMA	 0x0800000000000000UL	/* Secondary Master Abort */ | 
|  | 122 | #define  SABRE_PIOAFSR_STA	 0x0400000000000000UL	/* Secondary Target Abort */ | 
|  | 123 | #define  SABRE_PIOAFSR_SRTRY	 0x0200000000000000UL	/* Secondary Excessive Retries */ | 
|  | 124 | #define  SABRE_PIOAFSR_SPERR	 0x0100000000000000UL	/* Secondary Parity Error */ | 
|  | 125 | #define  SABRE_PIOAFSR_BMSK	 0x0000ffff00000000UL	/* Byte Mask */ | 
|  | 126 | #define  SABRE_PIOAFSR_BLK	 0x0000000080000000UL	/* Was Block Operation */ | 
|  | 127 | #define SABRE_PIOAFAR		0x2018UL | 
|  | 128 | #define SABRE_PCIDIAG		0x2020UL | 
|  | 129 | #define  SABRE_PCIDIAG_DRTRY	 0x0000000000000040UL	/* Disable PIO Retry Limit */ | 
|  | 130 | #define  SABRE_PCIDIAG_IPAPAR	 0x0000000000000008UL	/* Invert PIO Address Parity */ | 
|  | 131 | #define  SABRE_PCIDIAG_IPDPAR	 0x0000000000000004UL	/* Invert PIO Data Parity */ | 
|  | 132 | #define  SABRE_PCIDIAG_IDDPAR	 0x0000000000000002UL	/* Invert DMA Data Parity */ | 
|  | 133 | #define  SABRE_PCIDIAG_ELPBK	 0x0000000000000001UL	/* Loopback Enable - not supported */ | 
|  | 134 | #define SABRE_PCITASR		0x2028UL | 
|  | 135 | #define  SABRE_PCITASR_EF	 0x0000000000000080UL	/* Respond to 0xe0000000-0xffffffff */ | 
|  | 136 | #define  SABRE_PCITASR_CD	 0x0000000000000040UL	/* Respond to 0xc0000000-0xdfffffff */ | 
|  | 137 | #define  SABRE_PCITASR_AB	 0x0000000000000020UL	/* Respond to 0xa0000000-0xbfffffff */ | 
|  | 138 | #define  SABRE_PCITASR_89	 0x0000000000000010UL	/* Respond to 0x80000000-0x9fffffff */ | 
|  | 139 | #define  SABRE_PCITASR_67	 0x0000000000000008UL	/* Respond to 0x60000000-0x7fffffff */ | 
|  | 140 | #define  SABRE_PCITASR_45	 0x0000000000000004UL	/* Respond to 0x40000000-0x5fffffff */ | 
|  | 141 | #define  SABRE_PCITASR_23	 0x0000000000000002UL	/* Respond to 0x20000000-0x3fffffff */ | 
|  | 142 | #define  SABRE_PCITASR_01	 0x0000000000000001UL	/* Respond to 0x00000000-0x1fffffff */ | 
|  | 143 | #define SABRE_PIOBUF_DIAG	0x5000UL | 
|  | 144 | #define SABRE_DMABUF_DIAGLO	0x5100UL | 
|  | 145 | #define SABRE_DMABUF_DIAGHI	0x51c0UL | 
|  | 146 | #define SABRE_IMAP_GFX_ALIAS	0x6000UL	/* Aliases to 0x1098 */ | 
|  | 147 | #define SABRE_IMAP_EUPA_ALIAS	0x8000UL	/* Aliases to 0x10a0 */ | 
|  | 148 | #define SABRE_IOMMU_VADIAG	0xa400UL | 
|  | 149 | #define SABRE_IOMMU_TCDIAG	0xa408UL | 
|  | 150 | #define SABRE_IOMMU_TAG		0xa580UL | 
|  | 151 | #define  SABRE_IOMMUTAG_ERRSTS	 0x0000000001800000UL	/* Error status bits */ | 
|  | 152 | #define  SABRE_IOMMUTAG_ERR	 0x0000000000400000UL	/* Error present */ | 
|  | 153 | #define  SABRE_IOMMUTAG_WRITE	 0x0000000000200000UL	/* Page is writable */ | 
|  | 154 | #define  SABRE_IOMMUTAG_STREAM	 0x0000000000100000UL	/* Streamable bit - unused */ | 
|  | 155 | #define  SABRE_IOMMUTAG_SIZE	 0x0000000000080000UL	/* 0=8k 1=16k */ | 
|  | 156 | #define  SABRE_IOMMUTAG_VPN	 0x000000000007ffffUL	/* Virtual Page Number [31:13] */ | 
|  | 157 | #define SABRE_IOMMU_DATA	0xa600UL | 
|  | 158 | #define SABRE_IOMMUDATA_VALID	 0x0000000040000000UL	/* Valid */ | 
|  | 159 | #define SABRE_IOMMUDATA_USED	 0x0000000020000000UL	/* Used (for LRU algorithm) */ | 
|  | 160 | #define SABRE_IOMMUDATA_CACHE	 0x0000000010000000UL	/* Cacheable */ | 
|  | 161 | #define SABRE_IOMMUDATA_PPN	 0x00000000001fffffUL	/* Physical Page Number [33:13] */ | 
|  | 162 | #define SABRE_PCI_IRQSTATE	0xa800UL | 
|  | 163 | #define SABRE_OBIO_IRQSTATE	0xa808UL | 
|  | 164 | #define SABRE_FFBCFG		0xf000UL | 
|  | 165 | #define  SABRE_FFBCFG_SPRQS	 0x000000000f000000	/* Slave P_RQST queue size */ | 
|  | 166 | #define  SABRE_FFBCFG_ONEREAD	 0x0000000000004000	/* Slave supports one outstanding read */ | 
|  | 167 | #define SABRE_MCCTRL0		0xf010UL | 
|  | 168 | #define  SABRE_MCCTRL0_RENAB	 0x0000000080000000	/* Refresh Enable */ | 
|  | 169 | #define  SABRE_MCCTRL0_EENAB	 0x0000000010000000	/* Enable all ECC functions */ | 
|  | 170 | #define  SABRE_MCCTRL0_11BIT	 0x0000000000001000	/* Enable 11-bit column addressing */ | 
|  | 171 | #define  SABRE_MCCTRL0_DPP	 0x0000000000000f00	/* DIMM Pair Present Bits */ | 
|  | 172 | #define  SABRE_MCCTRL0_RINTVL	 0x00000000000000ff	/* Refresh Interval */ | 
|  | 173 | #define SABRE_MCCTRL1		0xf018UL | 
|  | 174 | #define  SABRE_MCCTRL1_AMDC	 0x0000000038000000	/* Advance Memdata Clock */ | 
|  | 175 | #define  SABRE_MCCTRL1_ARDC	 0x0000000007000000	/* Advance DRAM Read Data Clock */ | 
|  | 176 | #define  SABRE_MCCTRL1_CSR	 0x0000000000e00000	/* CAS to RAS delay for CBR refresh */ | 
|  | 177 | #define  SABRE_MCCTRL1_CASRW	 0x00000000001c0000	/* CAS length for read/write */ | 
|  | 178 | #define  SABRE_MCCTRL1_RCD	 0x0000000000038000	/* RAS to CAS delay */ | 
|  | 179 | #define  SABRE_MCCTRL1_CP	 0x0000000000007000	/* CAS Precharge */ | 
|  | 180 | #define  SABRE_MCCTRL1_RP	 0x0000000000000e00	/* RAS Precharge */ | 
|  | 181 | #define  SABRE_MCCTRL1_RAS	 0x00000000000001c0	/* Length of RAS for refresh */ | 
|  | 182 | #define  SABRE_MCCTRL1_CASRW2	 0x0000000000000038	/* Must be same as CASRW */ | 
|  | 183 | #define  SABRE_MCCTRL1_RSC	 0x0000000000000007	/* RAS after CAS hold time */ | 
|  | 184 | #define SABRE_RESETCTRL		0xf020UL | 
|  | 185 |  | 
|  | 186 | #define SABRE_CONFIGSPACE	0x001000000UL | 
|  | 187 | #define SABRE_IOSPACE		0x002000000UL | 
|  | 188 | #define SABRE_IOSPACE_SIZE	0x000ffffffUL | 
|  | 189 | #define SABRE_MEMSPACE		0x100000000UL | 
|  | 190 | #define SABRE_MEMSPACE_SIZE	0x07fffffffUL | 
|  | 191 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 192 | static int hummingbird_p; | 
|  | 193 | static struct pci_bus *sabre_root_bus; | 
|  | 194 |  | 
| Al Viro | 6d24c8d | 2006-10-08 08:23:28 -0400 | [diff] [blame] | 195 | static irqreturn_t sabre_ue_intr(int irq, void *dev_id) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 196 | { | 
| David S. Miller | 6c108f1 | 2007-05-07 23:49:01 -0700 | [diff] [blame] | 197 | struct pci_pbm_info *pbm = dev_id; | 
|  | 198 | unsigned long afsr_reg = pbm->controller_regs + SABRE_UE_AFSR; | 
|  | 199 | unsigned long afar_reg = pbm->controller_regs + SABRE_UECE_AFAR; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 200 | unsigned long afsr, afar, error_bits; | 
|  | 201 | int reported; | 
|  | 202 |  | 
|  | 203 | /* Latch uncorrectable error status. */ | 
| David S. Miller | 87395fc | 2008-09-10 04:13:10 -0700 | [diff] [blame] | 204 | afar = upa_readq(afar_reg); | 
|  | 205 | afsr = upa_readq(afsr_reg); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 206 |  | 
|  | 207 | /* Clear the primary/secondary error status bits. */ | 
|  | 208 | error_bits = afsr & | 
|  | 209 | (SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR | | 
|  | 210 | SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR | | 
|  | 211 | SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE); | 
|  | 212 | if (!error_bits) | 
|  | 213 | return IRQ_NONE; | 
| David S. Miller | 87395fc | 2008-09-10 04:13:10 -0700 | [diff] [blame] | 214 | upa_writeq(error_bits, afsr_reg); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 215 |  | 
|  | 216 | /* Log the error. */ | 
| David S. Miller | 6c108f1 | 2007-05-07 23:49:01 -0700 | [diff] [blame] | 217 | printk("%s: Uncorrectable Error, primary error type[%s%s]\n", | 
|  | 218 | pbm->name, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 219 | ((error_bits & SABRE_UEAFSR_PDRD) ? | 
|  | 220 | "DMA Read" : | 
|  | 221 | ((error_bits & SABRE_UEAFSR_PDWR) ? | 
|  | 222 | "DMA Write" : "???")), | 
|  | 223 | ((error_bits & SABRE_UEAFSR_PDTE) ? | 
|  | 224 | ":Translation Error" : "")); | 
| David S. Miller | 6c108f1 | 2007-05-07 23:49:01 -0700 | [diff] [blame] | 225 | printk("%s: bytemask[%04lx] dword_offset[%lx] was_block(%d)\n", | 
|  | 226 | pbm->name, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 227 | (afsr & SABRE_UEAFSR_BMSK) >> 32UL, | 
|  | 228 | (afsr & SABRE_UEAFSR_OFF) >> 29UL, | 
|  | 229 | ((afsr & SABRE_UEAFSR_BLK) ? 1 : 0)); | 
| David S. Miller | 6c108f1 | 2007-05-07 23:49:01 -0700 | [diff] [blame] | 230 | printk("%s: UE AFAR [%016lx]\n", pbm->name, afar); | 
|  | 231 | printk("%s: UE Secondary errors [", pbm->name); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 232 | reported = 0; | 
|  | 233 | if (afsr & SABRE_UEAFSR_SDRD) { | 
|  | 234 | reported++; | 
|  | 235 | printk("(DMA Read)"); | 
|  | 236 | } | 
|  | 237 | if (afsr & SABRE_UEAFSR_SDWR) { | 
|  | 238 | reported++; | 
|  | 239 | printk("(DMA Write)"); | 
|  | 240 | } | 
|  | 241 | if (afsr & SABRE_UEAFSR_SDTE) { | 
|  | 242 | reported++; | 
|  | 243 | printk("(Translation Error)"); | 
|  | 244 | } | 
|  | 245 | if (!reported) | 
|  | 246 | printk("(none)"); | 
|  | 247 | printk("]\n"); | 
|  | 248 |  | 
|  | 249 | /* Interrogate IOMMU for error status. */ | 
| David S. Miller | e6e0037 | 2008-09-10 03:52:51 -0700 | [diff] [blame] | 250 | psycho_check_iommu_error(pbm, afsr, afar, UE_ERR); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 251 |  | 
|  | 252 | return IRQ_HANDLED; | 
|  | 253 | } | 
|  | 254 |  | 
| Al Viro | 6d24c8d | 2006-10-08 08:23:28 -0400 | [diff] [blame] | 255 | static irqreturn_t sabre_ce_intr(int irq, void *dev_id) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 256 | { | 
| David S. Miller | 6c108f1 | 2007-05-07 23:49:01 -0700 | [diff] [blame] | 257 | struct pci_pbm_info *pbm = dev_id; | 
|  | 258 | unsigned long afsr_reg = pbm->controller_regs + SABRE_CE_AFSR; | 
|  | 259 | unsigned long afar_reg = pbm->controller_regs + SABRE_UECE_AFAR; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 260 | unsigned long afsr, afar, error_bits; | 
|  | 261 | int reported; | 
|  | 262 |  | 
|  | 263 | /* Latch error status. */ | 
| David S. Miller | 87395fc | 2008-09-10 04:13:10 -0700 | [diff] [blame] | 264 | afar = upa_readq(afar_reg); | 
|  | 265 | afsr = upa_readq(afsr_reg); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 266 |  | 
|  | 267 | /* Clear primary/secondary error status bits. */ | 
|  | 268 | error_bits = afsr & | 
|  | 269 | (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR | | 
|  | 270 | SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR); | 
|  | 271 | if (!error_bits) | 
|  | 272 | return IRQ_NONE; | 
| David S. Miller | 87395fc | 2008-09-10 04:13:10 -0700 | [diff] [blame] | 273 | upa_writeq(error_bits, afsr_reg); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 274 |  | 
|  | 275 | /* Log the error. */ | 
| David S. Miller | 6c108f1 | 2007-05-07 23:49:01 -0700 | [diff] [blame] | 276 | printk("%s: Correctable Error, primary error type[%s]\n", | 
|  | 277 | pbm->name, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 278 | ((error_bits & SABRE_CEAFSR_PDRD) ? | 
|  | 279 | "DMA Read" : | 
|  | 280 | ((error_bits & SABRE_CEAFSR_PDWR) ? | 
|  | 281 | "DMA Write" : "???"))); | 
|  | 282 |  | 
|  | 283 | /* XXX Use syndrome and afar to print out module string just like | 
|  | 284 | * XXX UDB CE trap handler does... -DaveM | 
|  | 285 | */ | 
| David S. Miller | 6c108f1 | 2007-05-07 23:49:01 -0700 | [diff] [blame] | 286 | printk("%s: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] " | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 287 | "was_block(%d)\n", | 
| David S. Miller | 6c108f1 | 2007-05-07 23:49:01 -0700 | [diff] [blame] | 288 | pbm->name, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 289 | (afsr & SABRE_CEAFSR_ESYND) >> 48UL, | 
|  | 290 | (afsr & SABRE_CEAFSR_BMSK) >> 32UL, | 
|  | 291 | (afsr & SABRE_CEAFSR_OFF) >> 29UL, | 
|  | 292 | ((afsr & SABRE_CEAFSR_BLK) ? 1 : 0)); | 
| David S. Miller | 6c108f1 | 2007-05-07 23:49:01 -0700 | [diff] [blame] | 293 | printk("%s: CE AFAR [%016lx]\n", pbm->name, afar); | 
|  | 294 | printk("%s: CE Secondary errors [", pbm->name); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 295 | reported = 0; | 
|  | 296 | if (afsr & SABRE_CEAFSR_SDRD) { | 
|  | 297 | reported++; | 
|  | 298 | printk("(DMA Read)"); | 
|  | 299 | } | 
|  | 300 | if (afsr & SABRE_CEAFSR_SDWR) { | 
|  | 301 | reported++; | 
|  | 302 | printk("(DMA Write)"); | 
|  | 303 | } | 
|  | 304 | if (!reported) | 
|  | 305 | printk("(none)"); | 
|  | 306 | printk("]\n"); | 
|  | 307 |  | 
|  | 308 | return IRQ_HANDLED; | 
|  | 309 | } | 
|  | 310 |  | 
| David S. Miller | 34768bc | 2007-05-07 23:06:27 -0700 | [diff] [blame] | 311 | static void sabre_register_error_handlers(struct pci_pbm_info *pbm) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 312 | { | 
| David S. Miller | 22fecba | 2008-09-10 00:19:28 -0700 | [diff] [blame] | 313 | struct device_node *dp = pbm->op->node; | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 314 | struct of_device *op; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 315 | unsigned long base = pbm->controller_regs; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 316 | u64 tmp; | 
| David S. Miller | af80318 | 2007-05-08 17:23:31 -0700 | [diff] [blame] | 317 | int err; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 318 |  | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 319 | if (pbm->chip_type == PBM_CHIP_TYPE_SABRE) | 
|  | 320 | dp = dp->parent; | 
|  | 321 |  | 
|  | 322 | op = of_find_device_by_node(dp); | 
|  | 323 | if (!op) | 
|  | 324 | return; | 
|  | 325 |  | 
|  | 326 | /* Sabre/Hummingbird IRQ property layout is: | 
|  | 327 | * 0: PCI ERR | 
|  | 328 | * 1: UE ERR | 
|  | 329 | * 2: CE ERR | 
|  | 330 | * 3: POWER FAIL | 
|  | 331 | */ | 
|  | 332 | if (op->num_irqs < 4) | 
|  | 333 | return; | 
|  | 334 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 335 | /* We clear the error bits in the appropriate AFSR before | 
|  | 336 | * registering the handler so that we don't get spurious | 
|  | 337 | * interrupts. | 
|  | 338 | */ | 
| David S. Miller | 87395fc | 2008-09-10 04:13:10 -0700 | [diff] [blame] | 339 | upa_writeq((SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR | | 
|  | 340 | SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR | | 
|  | 341 | SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE), | 
|  | 342 | base + SABRE_UE_AFSR); | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 343 |  | 
| David S. Miller | af80318 | 2007-05-08 17:23:31 -0700 | [diff] [blame] | 344 | err = request_irq(op->irqs[1], sabre_ue_intr, 0, "SABRE_UE", pbm); | 
|  | 345 | if (err) | 
|  | 346 | printk(KERN_WARNING "%s: Couldn't register UE, err=%d.\n", | 
|  | 347 | pbm->name, err); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 348 |  | 
| David S. Miller | 87395fc | 2008-09-10 04:13:10 -0700 | [diff] [blame] | 349 | upa_writeq((SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR | | 
|  | 350 | SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR), | 
|  | 351 | base + SABRE_CE_AFSR); | 
|  | 352 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 353 |  | 
| David S. Miller | af80318 | 2007-05-08 17:23:31 -0700 | [diff] [blame] | 354 | err = request_irq(op->irqs[2], sabre_ce_intr, 0, "SABRE_CE", pbm); | 
|  | 355 | if (err) | 
|  | 356 | printk(KERN_WARNING "%s: Couldn't register CE, err=%d.\n", | 
|  | 357 | pbm->name, err); | 
| David S. Miller | e6e0037 | 2008-09-10 03:52:51 -0700 | [diff] [blame] | 358 | err = request_irq(op->irqs[0], psycho_pcierr_intr, 0, | 
| David S. Miller | af80318 | 2007-05-08 17:23:31 -0700 | [diff] [blame] | 359 | "SABRE_PCIERR", pbm); | 
|  | 360 | if (err) | 
|  | 361 | printk(KERN_WARNING "%s: Couldn't register PCIERR, err=%d.\n", | 
|  | 362 | pbm->name, err); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 363 |  | 
| David S. Miller | 87395fc | 2008-09-10 04:13:10 -0700 | [diff] [blame] | 364 | tmp = upa_readq(base + SABRE_PCICTRL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 365 | tmp |= SABRE_PCICTRL_ERREN; | 
| David S. Miller | 87395fc | 2008-09-10 04:13:10 -0700 | [diff] [blame] | 366 | upa_writeq(tmp, base + SABRE_PCICTRL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 367 | } | 
|  | 368 |  | 
| David S. Miller | 34768bc | 2007-05-07 23:06:27 -0700 | [diff] [blame] | 369 | static void apb_init(struct pci_bus *sabre_bus) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 370 | { | 
|  | 371 | struct pci_dev *pdev; | 
|  | 372 |  | 
|  | 373 | list_for_each_entry(pdev, &sabre_bus->devices, bus_list) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 374 | if (pdev->vendor == PCI_VENDOR_ID_SUN && | 
|  | 375 | pdev->device == PCI_DEVICE_ID_SUN_SIMBA) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 376 | u16 word16; | 
|  | 377 |  | 
| David S. Miller | 01f94c4 | 2007-03-04 12:53:19 -0800 | [diff] [blame] | 378 | pci_read_config_word(pdev, PCI_COMMAND, &word16); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 379 | word16 |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | | 
|  | 380 | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | | 
|  | 381 | PCI_COMMAND_IO; | 
| David S. Miller | 01f94c4 | 2007-03-04 12:53:19 -0800 | [diff] [blame] | 382 | pci_write_config_word(pdev, PCI_COMMAND, word16); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 383 |  | 
|  | 384 | /* Status register bits are "write 1 to clear". */ | 
| David S. Miller | 01f94c4 | 2007-03-04 12:53:19 -0800 | [diff] [blame] | 385 | pci_write_config_word(pdev, PCI_STATUS, 0xffff); | 
|  | 386 | pci_write_config_word(pdev, PCI_SEC_STATUS, 0xffff); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 387 |  | 
|  | 388 | /* Use a primary/seconday latency timer value | 
|  | 389 | * of 64. | 
|  | 390 | */ | 
| David S. Miller | 01f94c4 | 2007-03-04 12:53:19 -0800 | [diff] [blame] | 391 | pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); | 
|  | 392 | pci_write_config_byte(pdev, PCI_SEC_LATENCY_TIMER, 64); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 393 |  | 
|  | 394 | /* Enable reporting/forwarding of master aborts, | 
|  | 395 | * parity, and SERR. | 
|  | 396 | */ | 
| David S. Miller | 01f94c4 | 2007-03-04 12:53:19 -0800 | [diff] [blame] | 397 | pci_write_config_byte(pdev, PCI_BRIDGE_CONTROL, | 
|  | 398 | (PCI_BRIDGE_CTL_PARITY | | 
|  | 399 | PCI_BRIDGE_CTL_SERR | | 
|  | 400 | PCI_BRIDGE_CTL_MASTER_ABORT)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 401 | } | 
|  | 402 | } | 
|  | 403 | } | 
|  | 404 |  | 
| David S. Miller | 9a2ed5c | 2009-04-07 01:03:58 -0700 | [diff] [blame] | 405 | static void __devinit sabre_scan_bus(struct pci_pbm_info *pbm, | 
|  | 406 | struct device *parent) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 407 | { | 
|  | 408 | static int once; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 409 |  | 
|  | 410 | /* The APB bridge speaks to the Sabre host PCI bridge | 
|  | 411 | * at 66Mhz, but the front side of APB runs at 33Mhz | 
|  | 412 | * for both segments. | 
| David S. Miller | 321566c | 2007-06-06 14:03:08 -0700 | [diff] [blame] | 413 | * | 
|  | 414 | * Hummingbird systems do not use APB, so they run | 
|  | 415 | * at 66MHZ. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 416 | */ | 
| David S. Miller | 321566c | 2007-06-06 14:03:08 -0700 | [diff] [blame] | 417 | if (hummingbird_p) | 
|  | 418 | pbm->is_66mhz_capable = 1; | 
|  | 419 | else | 
|  | 420 | pbm->is_66mhz_capable = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 421 |  | 
|  | 422 | /* This driver has not been verified to handle | 
|  | 423 | * multiple SABREs yet, so trap this. | 
|  | 424 | * | 
|  | 425 | * Also note that the SABRE host bridge is hardwired | 
|  | 426 | * to live at bus 0. | 
|  | 427 | */ | 
|  | 428 | if (once != 0) { | 
| David S. Miller | edbe805 | 2008-08-30 03:14:01 -0700 | [diff] [blame] | 429 | printk(KERN_ERR PFX "Multiple controllers unsupported.\n"); | 
|  | 430 | return; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 431 | } | 
|  | 432 | once++; | 
|  | 433 |  | 
| David S. Miller | e822358a | 2008-09-01 18:32:22 -0700 | [diff] [blame] | 434 | pbm->pci_bus = pci_scan_one_pbm(pbm, parent); | 
| David S. Miller | 321566c | 2007-06-06 14:03:08 -0700 | [diff] [blame] | 435 | if (!pbm->pci_bus) | 
| David S. Miller | a2fb23a | 2007-02-28 23:35:04 -0800 | [diff] [blame] | 436 | return; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 437 |  | 
| David S. Miller | 321566c | 2007-06-06 14:03:08 -0700 | [diff] [blame] | 438 | sabre_root_bus = pbm->pci_bus; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 439 |  | 
| David S. Miller | 321566c | 2007-06-06 14:03:08 -0700 | [diff] [blame] | 440 | apb_init(pbm->pci_bus); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 441 |  | 
| David S. Miller | 34768bc | 2007-05-07 23:06:27 -0700 | [diff] [blame] | 442 | sabre_register_error_handlers(pbm); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 443 | } | 
|  | 444 |  | 
| David S. Miller | 9a2ed5c | 2009-04-07 01:03:58 -0700 | [diff] [blame] | 445 | static void __devinit sabre_pbm_init(struct pci_pbm_info *pbm, | 
|  | 446 | struct of_device *op) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 447 | { | 
| David S. Miller | 1c03a55 | 2008-09-10 03:15:56 -0700 | [diff] [blame] | 448 | psycho_pbm_init_common(pbm, op, "SABRE", PBM_CHIP_TYPE_SABRE); | 
| David S. Miller | e6e0037 | 2008-09-10 03:52:51 -0700 | [diff] [blame] | 449 | pbm->pci_afsr = pbm->controller_regs + SABRE_PIOAFSR; | 
|  | 450 | pbm->pci_afar = pbm->controller_regs + SABRE_PIOAFAR; | 
|  | 451 | pbm->pci_csr = pbm->controller_regs + SABRE_PCICTRL; | 
| David S. Miller | e822358a | 2008-09-01 18:32:22 -0700 | [diff] [blame] | 452 | sabre_scan_bus(pbm, &op->dev); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 453 | } | 
|  | 454 |  | 
| David S. Miller | edbe805 | 2008-08-30 03:14:01 -0700 | [diff] [blame] | 455 | static int __devinit sabre_probe(struct of_device *op, | 
|  | 456 | const struct of_device_id *match) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 457 | { | 
| David S. Miller | a165b42 | 2007-03-29 01:50:16 -0700 | [diff] [blame] | 458 | const struct linux_prom64_registers *pr_regs; | 
| David S. Miller | edbe805 | 2008-08-30 03:14:01 -0700 | [diff] [blame] | 459 | struct device_node *dp = op->node; | 
| David S. Miller | 28113a9 | 2007-05-08 00:19:02 -0700 | [diff] [blame] | 460 | struct pci_pbm_info *pbm; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 461 | u32 upa_portid, dma_mask; | 
| David S. Miller | edbe805 | 2008-08-30 03:14:01 -0700 | [diff] [blame] | 462 | struct iommu *iommu; | 
|  | 463 | int tsbsize, err; | 
|  | 464 | const u32 *vdma; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 465 | u64 clear_irq; | 
|  | 466 |  | 
| David S. Miller | edbe805 | 2008-08-30 03:14:01 -0700 | [diff] [blame] | 467 | hummingbird_p = (match->data != NULL); | 
|  | 468 | if (!hummingbird_p) { | 
|  | 469 | struct device_node *cpu_dp; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 470 |  | 
| David S. Miller | edbe805 | 2008-08-30 03:14:01 -0700 | [diff] [blame] | 471 | /* Of course, Sun has to encode things a thousand | 
|  | 472 | * different ways, inconsistently. | 
|  | 473 | */ | 
|  | 474 | for_each_node_by_type(cpu_dp, "cpu") { | 
|  | 475 | if (!strcmp(cpu_dp->name, "SUNW,UltraSPARC-IIe")) | 
|  | 476 | hummingbird_p = 1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 477 | } | 
|  | 478 | } | 
|  | 479 |  | 
| David S. Miller | edbe805 | 2008-08-30 03:14:01 -0700 | [diff] [blame] | 480 | err = -ENOMEM; | 
| David S. Miller | d3ae4b5 | 2008-09-09 23:54:02 -0700 | [diff] [blame] | 481 | pbm = kzalloc(sizeof(*pbm), GFP_KERNEL); | 
|  | 482 | if (!pbm) { | 
|  | 483 | printk(KERN_ERR PFX "Cannot allocate pci_pbm_info.\n"); | 
| David S. Miller | d7472c3 | 2008-08-31 01:33:52 -0700 | [diff] [blame] | 484 | goto out_err; | 
| David S. Miller | edbe805 | 2008-08-30 03:14:01 -0700 | [diff] [blame] | 485 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 486 |  | 
| David S. Miller | d3ae4b5 | 2008-09-09 23:54:02 -0700 | [diff] [blame] | 487 | iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); | 
| David S. Miller | edbe805 | 2008-08-30 03:14:01 -0700 | [diff] [blame] | 488 | if (!iommu) { | 
|  | 489 | printk(KERN_ERR PFX "Cannot allocate PBM iommu.\n"); | 
| David S. Miller | d7472c3 | 2008-08-31 01:33:52 -0700 | [diff] [blame] | 490 | goto out_free_controller; | 
| David S. Miller | edbe805 | 2008-08-30 03:14:01 -0700 | [diff] [blame] | 491 | } | 
|  | 492 |  | 
| David S. Miller | 28113a9 | 2007-05-08 00:19:02 -0700 | [diff] [blame] | 493 | pbm->iommu = iommu; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 494 |  | 
| David S. Miller | 01f94c4 | 2007-03-04 12:53:19 -0800 | [diff] [blame] | 495 | upa_portid = of_getintprop_default(dp, "upa-portid", 0xff); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 496 |  | 
| David S. Miller | 28113a9 | 2007-05-08 00:19:02 -0700 | [diff] [blame] | 497 | pbm->portid = upa_portid; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 498 |  | 
|  | 499 | /* | 
|  | 500 | * Map in SABRE register set and report the presence of this SABRE. | 
|  | 501 | */ | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 502 |  | 
| David S. Miller | 01f94c4 | 2007-03-04 12:53:19 -0800 | [diff] [blame] | 503 | pr_regs = of_get_property(dp, "reg", NULL); | 
| David S. Miller | edbe805 | 2008-08-30 03:14:01 -0700 | [diff] [blame] | 504 | err = -ENODEV; | 
|  | 505 | if (!pr_regs) { | 
|  | 506 | printk(KERN_ERR PFX "No reg property\n"); | 
| David S. Miller | d7472c3 | 2008-08-31 01:33:52 -0700 | [diff] [blame] | 507 | goto out_free_iommu; | 
| David S. Miller | edbe805 | 2008-08-30 03:14:01 -0700 | [diff] [blame] | 508 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 509 |  | 
|  | 510 | /* | 
|  | 511 | * First REG in property is base of entire SABRE register space. | 
|  | 512 | */ | 
| David S. Miller | 28113a9 | 2007-05-08 00:19:02 -0700 | [diff] [blame] | 513 | pbm->controller_regs = pr_regs[0].phys_addr; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 514 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 515 | /* Clear interrupts */ | 
|  | 516 |  | 
|  | 517 | /* PCI first */ | 
|  | 518 | for (clear_irq = SABRE_ICLR_A_SLOT0; clear_irq < SABRE_ICLR_B_SLOT0 + 0x80; clear_irq += 8) | 
| David S. Miller | 87395fc | 2008-09-10 04:13:10 -0700 | [diff] [blame] | 519 | upa_writeq(0x0UL, pbm->controller_regs + clear_irq); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 520 |  | 
|  | 521 | /* Then OBIO */ | 
|  | 522 | for (clear_irq = SABRE_ICLR_SCSI; clear_irq < SABRE_ICLR_SCSI + 0x80; clear_irq += 8) | 
| David S. Miller | 87395fc | 2008-09-10 04:13:10 -0700 | [diff] [blame] | 523 | upa_writeq(0x0UL, pbm->controller_regs + clear_irq); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 524 |  | 
|  | 525 | /* Error interrupts are enabled later after the bus scan. */ | 
| David S. Miller | 87395fc | 2008-09-10 04:13:10 -0700 | [diff] [blame] | 526 | upa_writeq((SABRE_PCICTRL_MRLEN   | SABRE_PCICTRL_SERR | | 
|  | 527 | SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN), | 
|  | 528 | pbm->controller_regs + SABRE_PCICTRL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 529 |  | 
|  | 530 | /* Now map in PCI config space for entire SABRE. */ | 
| David S. Miller | d3ae4b5 | 2008-09-09 23:54:02 -0700 | [diff] [blame] | 531 | pbm->config_space = pbm->controller_regs + SABRE_CONFIGSPACE; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 532 |  | 
| David S. Miller | 01f94c4 | 2007-03-04 12:53:19 -0800 | [diff] [blame] | 533 | vdma = of_get_property(dp, "virtual-dma", NULL); | 
| David S. Miller | edbe805 | 2008-08-30 03:14:01 -0700 | [diff] [blame] | 534 | if (!vdma) { | 
|  | 535 | printk(KERN_ERR PFX "No virtual-dma property\n"); | 
| David S. Miller | d7472c3 | 2008-08-31 01:33:52 -0700 | [diff] [blame] | 536 | goto out_free_iommu; | 
| David S. Miller | edbe805 | 2008-08-30 03:14:01 -0700 | [diff] [blame] | 537 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 538 |  | 
|  | 539 | dma_mask = vdma[0]; | 
|  | 540 | switch(vdma[1]) { | 
|  | 541 | case 0x20000000: | 
|  | 542 | dma_mask |= 0x1fffffff; | 
|  | 543 | tsbsize = 64; | 
|  | 544 | break; | 
|  | 545 | case 0x40000000: | 
|  | 546 | dma_mask |= 0x3fffffff; | 
|  | 547 | tsbsize = 128; | 
|  | 548 | break; | 
|  | 549 |  | 
|  | 550 | case 0x80000000: | 
|  | 551 | dma_mask |= 0x7fffffff; | 
|  | 552 | tsbsize = 128; | 
|  | 553 | break; | 
|  | 554 | default: | 
| David S. Miller | edbe805 | 2008-08-30 03:14:01 -0700 | [diff] [blame] | 555 | printk(KERN_ERR PFX "Strange virtual-dma size.\n"); | 
| David S. Miller | d7472c3 | 2008-08-31 01:33:52 -0700 | [diff] [blame] | 556 | goto out_free_iommu; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 557 | } | 
|  | 558 |  | 
| David S. Miller | a21cff3 | 2008-09-10 03:07:03 -0700 | [diff] [blame] | 559 | err = psycho_iommu_init(pbm, tsbsize, vdma[0], dma_mask, SABRE_WRSYNC); | 
| David S. Miller | edbe805 | 2008-08-30 03:14:01 -0700 | [diff] [blame] | 560 | if (err) | 
| David S. Miller | d7472c3 | 2008-08-31 01:33:52 -0700 | [diff] [blame] | 561 | goto out_free_iommu; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 562 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 563 | /* | 
|  | 564 | * Look for APB underneath. | 
|  | 565 | */ | 
| David S. Miller | d3ae4b5 | 2008-09-09 23:54:02 -0700 | [diff] [blame] | 566 | sabre_pbm_init(pbm, op); | 
|  | 567 |  | 
|  | 568 | pbm->next = pci_pbm_root; | 
|  | 569 | pci_pbm_root = pbm; | 
|  | 570 |  | 
|  | 571 | dev_set_drvdata(&op->dev, pbm); | 
|  | 572 |  | 
| David S. Miller | edbe805 | 2008-08-30 03:14:01 -0700 | [diff] [blame] | 573 | return 0; | 
| David S. Miller | ad7ad57 | 2007-07-27 22:39:14 -0700 | [diff] [blame] | 574 |  | 
| David S. Miller | d7472c3 | 2008-08-31 01:33:52 -0700 | [diff] [blame] | 575 | out_free_iommu: | 
| David S. Miller | d3ae4b5 | 2008-09-09 23:54:02 -0700 | [diff] [blame] | 576 | kfree(pbm->iommu); | 
| David S. Miller | d7472c3 | 2008-08-31 01:33:52 -0700 | [diff] [blame] | 577 |  | 
|  | 578 | out_free_controller: | 
| David S. Miller | d3ae4b5 | 2008-09-09 23:54:02 -0700 | [diff] [blame] | 579 | kfree(pbm); | 
| David S. Miller | d7472c3 | 2008-08-31 01:33:52 -0700 | [diff] [blame] | 580 |  | 
|  | 581 | out_err: | 
| David S. Miller | edbe805 | 2008-08-30 03:14:01 -0700 | [diff] [blame] | 582 | return err; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 583 | } | 
| David S. Miller | edbe805 | 2008-08-30 03:14:01 -0700 | [diff] [blame] | 584 |  | 
| David S. Miller | fd09831 | 2008-08-31 01:23:17 -0700 | [diff] [blame] | 585 | static struct of_device_id __initdata sabre_match[] = { | 
| David S. Miller | edbe805 | 2008-08-30 03:14:01 -0700 | [diff] [blame] | 586 | { | 
|  | 587 | .name = "pci", | 
|  | 588 | .compatible = "pci108e,a001", | 
|  | 589 | .data = (void *) 1, | 
|  | 590 | }, | 
|  | 591 | { | 
|  | 592 | .name = "pci", | 
|  | 593 | .compatible = "pci108e,a000", | 
|  | 594 | }, | 
|  | 595 | {}, | 
|  | 596 | }; | 
|  | 597 |  | 
|  | 598 | static struct of_platform_driver sabre_driver = { | 
|  | 599 | .name		= DRIVER_NAME, | 
|  | 600 | .match_table	= sabre_match, | 
|  | 601 | .probe		= sabre_probe, | 
|  | 602 | }; | 
|  | 603 |  | 
|  | 604 | static int __init sabre_init(void) | 
|  | 605 | { | 
|  | 606 | return of_register_driver(&sabre_driver, &of_bus_type); | 
|  | 607 | } | 
|  | 608 |  | 
|  | 609 | subsys_initcall(sabre_init); |