| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* $Id: pci_schizo.c,v 1.24 2002/01/23 11:27:32 davem Exp $ | 
|  | 2 | * pci_schizo.c: SCHIZO/TOMATILLO specific PCI controller support. | 
|  | 3 | * | 
|  | 4 | * Copyright (C) 2001, 2002, 2003 David S. Miller (davem@redhat.com) | 
|  | 5 | */ | 
|  | 6 |  | 
|  | 7 | #include <linux/kernel.h> | 
|  | 8 | #include <linux/types.h> | 
|  | 9 | #include <linux/pci.h> | 
|  | 10 | #include <linux/init.h> | 
|  | 11 | #include <linux/slab.h> | 
|  | 12 | #include <linux/interrupt.h> | 
|  | 13 |  | 
|  | 14 | #include <asm/pbm.h> | 
|  | 15 | #include <asm/iommu.h> | 
|  | 16 | #include <asm/irq.h> | 
|  | 17 | #include <asm/upa.h> | 
| David S. Miller | bb6743f | 2005-07-04 13:26:04 -0700 | [diff] [blame] | 18 | #include <asm/pstate.h> | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 19 | #include <asm/prom.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 20 |  | 
|  | 21 | #include "pci_impl.h" | 
|  | 22 | #include "iommu_common.h" | 
|  | 23 |  | 
|  | 24 | /* All SCHIZO registers are 64-bits.  The following accessor | 
|  | 25 | * routines are how they are accessed.  The REG parameter | 
|  | 26 | * is a physical address. | 
|  | 27 | */ | 
|  | 28 | #define schizo_read(__reg) \ | 
|  | 29 | ({	u64 __ret; \ | 
|  | 30 | __asm__ __volatile__("ldxa [%1] %2, %0" \ | 
|  | 31 | : "=r" (__ret) \ | 
|  | 32 | : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ | 
|  | 33 | : "memory"); \ | 
|  | 34 | __ret; \ | 
|  | 35 | }) | 
|  | 36 | #define schizo_write(__reg, __val) \ | 
|  | 37 | __asm__ __volatile__("stxa %0, [%1] %2" \ | 
|  | 38 | : /* no outputs */ \ | 
|  | 39 | : "r" (__val), "r" (__reg), \ | 
|  | 40 | "i" (ASI_PHYS_BYPASS_EC_E) \ | 
|  | 41 | : "memory") | 
|  | 42 |  | 
|  | 43 | /* This is a convention that at least Excalibur and Merlin | 
|  | 44 | * follow.  I suppose the SCHIZO used in Starcat and friends | 
|  | 45 | * will do similar. | 
|  | 46 | * | 
|  | 47 | * The only way I could see this changing is if the newlink | 
|  | 48 | * block requires more space in Schizo's address space than | 
|  | 49 | * they predicted, thus requiring an address space reorg when | 
|  | 50 | * the newer Schizo is taped out. | 
|  | 51 | */ | 
|  | 52 |  | 
|  | 53 | /* Streaming buffer control register. */ | 
|  | 54 | #define SCHIZO_STRBUF_CTRL_LPTR    0x00000000000000f0UL /* LRU Lock Pointer */ | 
|  | 55 | #define SCHIZO_STRBUF_CTRL_LENAB   0x0000000000000008UL /* LRU Lock Enable */ | 
|  | 56 | #define SCHIZO_STRBUF_CTRL_RRDIS   0x0000000000000004UL /* Rerun Disable */ | 
|  | 57 | #define SCHIZO_STRBUF_CTRL_DENAB   0x0000000000000002UL /* Diagnostic Mode Enable */ | 
|  | 58 | #define SCHIZO_STRBUF_CTRL_ENAB    0x0000000000000001UL /* Streaming Buffer Enable */ | 
|  | 59 |  | 
|  | 60 | /* IOMMU control register. */ | 
|  | 61 | #define SCHIZO_IOMMU_CTRL_RESV     0xfffffffff9000000UL /* Reserved                      */ | 
|  | 62 | #define SCHIZO_IOMMU_CTRL_XLTESTAT 0x0000000006000000UL /* Translation Error Status      */ | 
|  | 63 | #define SCHIZO_IOMMU_CTRL_XLTEERR  0x0000000001000000UL /* Translation Error encountered */ | 
|  | 64 | #define SCHIZO_IOMMU_CTRL_LCKEN    0x0000000000800000UL /* Enable translation locking    */ | 
|  | 65 | #define SCHIZO_IOMMU_CTRL_LCKPTR   0x0000000000780000UL /* Translation lock pointer      */ | 
|  | 66 | #define SCHIZO_IOMMU_CTRL_TSBSZ    0x0000000000070000UL /* TSB Size                      */ | 
|  | 67 | #define SCHIZO_IOMMU_TSBSZ_1K      0x0000000000000000UL /* TSB Table 1024 8-byte entries */ | 
|  | 68 | #define SCHIZO_IOMMU_TSBSZ_2K      0x0000000000010000UL /* TSB Table 2048 8-byte entries */ | 
|  | 69 | #define SCHIZO_IOMMU_TSBSZ_4K      0x0000000000020000UL /* TSB Table 4096 8-byte entries */ | 
|  | 70 | #define SCHIZO_IOMMU_TSBSZ_8K      0x0000000000030000UL /* TSB Table 8192 8-byte entries */ | 
|  | 71 | #define SCHIZO_IOMMU_TSBSZ_16K     0x0000000000040000UL /* TSB Table 16k 8-byte entries  */ | 
|  | 72 | #define SCHIZO_IOMMU_TSBSZ_32K     0x0000000000050000UL /* TSB Table 32k 8-byte entries  */ | 
|  | 73 | #define SCHIZO_IOMMU_TSBSZ_64K     0x0000000000060000UL /* TSB Table 64k 8-byte entries  */ | 
|  | 74 | #define SCHIZO_IOMMU_TSBSZ_128K    0x0000000000070000UL /* TSB Table 128k 8-byte entries */ | 
|  | 75 | #define SCHIZO_IOMMU_CTRL_RESV2    0x000000000000fff8UL /* Reserved                      */ | 
|  | 76 | #define SCHIZO_IOMMU_CTRL_TBWSZ    0x0000000000000004UL /* Assumed page size, 0=8k 1=64k */ | 
|  | 77 | #define SCHIZO_IOMMU_CTRL_DENAB    0x0000000000000002UL /* Diagnostic mode enable        */ | 
|  | 78 | #define SCHIZO_IOMMU_CTRL_ENAB     0x0000000000000001UL /* IOMMU Enable                  */ | 
|  | 79 |  | 
|  | 80 | /* Schizo config space address format is nearly identical to | 
|  | 81 | * that of PSYCHO: | 
|  | 82 | * | 
|  | 83 | *  32             24 23 16 15    11 10       8 7   2  1 0 | 
|  | 84 | * --------------------------------------------------------- | 
|  | 85 | * |0 0 0 0 0 0 0 0 0| bus | device | function | reg | 0 0 | | 
|  | 86 | * --------------------------------------------------------- | 
|  | 87 | */ | 
|  | 88 | #define SCHIZO_CONFIG_BASE(PBM)	((PBM)->config_space) | 
|  | 89 | #define SCHIZO_CONFIG_ENCODE(BUS, DEVFN, REG)	\ | 
|  | 90 | (((unsigned long)(BUS)   << 16) |	\ | 
|  | 91 | ((unsigned long)(DEVFN) << 8)  |	\ | 
|  | 92 | ((unsigned long)(REG))) | 
|  | 93 |  | 
|  | 94 | static void *schizo_pci_config_mkaddr(struct pci_pbm_info *pbm, | 
|  | 95 | unsigned char bus, | 
|  | 96 | unsigned int devfn, | 
|  | 97 | int where) | 
|  | 98 | { | 
|  | 99 | if (!pbm) | 
|  | 100 | return NULL; | 
|  | 101 | bus -= pbm->pci_first_busno; | 
|  | 102 | return (void *) | 
|  | 103 | (SCHIZO_CONFIG_BASE(pbm) | | 
|  | 104 | SCHIZO_CONFIG_ENCODE(bus, devfn, where)); | 
|  | 105 | } | 
|  | 106 |  | 
|  | 107 | /* Just make sure the bus number is in range.  */ | 
|  | 108 | static int schizo_out_of_range(struct pci_pbm_info *pbm, | 
|  | 109 | unsigned char bus, | 
|  | 110 | unsigned char devfn) | 
|  | 111 | { | 
|  | 112 | if (bus < pbm->pci_first_busno || | 
|  | 113 | bus > pbm->pci_last_busno) | 
|  | 114 | return 1; | 
|  | 115 | return 0; | 
|  | 116 | } | 
|  | 117 |  | 
|  | 118 | /* SCHIZO PCI configuration space accessors. */ | 
|  | 119 |  | 
|  | 120 | static int schizo_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, | 
|  | 121 | int where, int size, u32 *value) | 
|  | 122 | { | 
|  | 123 | struct pci_pbm_info *pbm = bus_dev->sysdata; | 
|  | 124 | unsigned char bus = bus_dev->number; | 
|  | 125 | u32 *addr; | 
|  | 126 | u16 tmp16; | 
|  | 127 | u8 tmp8; | 
|  | 128 |  | 
|  | 129 | switch (size) { | 
|  | 130 | case 1: | 
|  | 131 | *value = 0xff; | 
|  | 132 | break; | 
|  | 133 | case 2: | 
|  | 134 | *value = 0xffff; | 
|  | 135 | break; | 
|  | 136 | case 4: | 
|  | 137 | *value = 0xffffffff; | 
|  | 138 | break; | 
|  | 139 | } | 
|  | 140 |  | 
|  | 141 | addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where); | 
|  | 142 | if (!addr) | 
|  | 143 | return PCIBIOS_SUCCESSFUL; | 
|  | 144 |  | 
|  | 145 | if (schizo_out_of_range(pbm, bus, devfn)) | 
|  | 146 | return PCIBIOS_SUCCESSFUL; | 
|  | 147 | switch (size) { | 
|  | 148 | case 1: | 
|  | 149 | pci_config_read8((u8 *)addr, &tmp8); | 
|  | 150 | *value = tmp8; | 
|  | 151 | break; | 
|  | 152 |  | 
|  | 153 | case 2: | 
|  | 154 | if (where & 0x01) { | 
|  | 155 | printk("pci_read_config_word: misaligned reg [%x]\n", | 
|  | 156 | where); | 
|  | 157 | return PCIBIOS_SUCCESSFUL; | 
|  | 158 | } | 
|  | 159 | pci_config_read16((u16 *)addr, &tmp16); | 
|  | 160 | *value = tmp16; | 
|  | 161 | break; | 
|  | 162 |  | 
|  | 163 | case 4: | 
|  | 164 | if (where & 0x03) { | 
|  | 165 | printk("pci_read_config_dword: misaligned reg [%x]\n", | 
|  | 166 | where); | 
|  | 167 | return PCIBIOS_SUCCESSFUL; | 
|  | 168 | } | 
|  | 169 | pci_config_read32(addr, value); | 
|  | 170 | break; | 
|  | 171 | } | 
|  | 172 | return PCIBIOS_SUCCESSFUL; | 
|  | 173 | } | 
|  | 174 |  | 
|  | 175 | static int schizo_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, | 
|  | 176 | int where, int size, u32 value) | 
|  | 177 | { | 
|  | 178 | struct pci_pbm_info *pbm = bus_dev->sysdata; | 
|  | 179 | unsigned char bus = bus_dev->number; | 
|  | 180 | u32 *addr; | 
|  | 181 |  | 
|  | 182 | addr = schizo_pci_config_mkaddr(pbm, bus, devfn, where); | 
|  | 183 | if (!addr) | 
|  | 184 | return PCIBIOS_SUCCESSFUL; | 
|  | 185 |  | 
|  | 186 | if (schizo_out_of_range(pbm, bus, devfn)) | 
|  | 187 | return PCIBIOS_SUCCESSFUL; | 
|  | 188 |  | 
|  | 189 | switch (size) { | 
|  | 190 | case 1: | 
|  | 191 | pci_config_write8((u8 *)addr, value); | 
|  | 192 | break; | 
|  | 193 |  | 
|  | 194 | case 2: | 
|  | 195 | if (where & 0x01) { | 
|  | 196 | printk("pci_write_config_word: misaligned reg [%x]\n", | 
|  | 197 | where); | 
|  | 198 | return PCIBIOS_SUCCESSFUL; | 
|  | 199 | } | 
|  | 200 | pci_config_write16((u16 *)addr, value); | 
|  | 201 | break; | 
|  | 202 |  | 
|  | 203 | case 4: | 
|  | 204 | if (where & 0x03) { | 
|  | 205 | printk("pci_write_config_dword: misaligned reg [%x]\n", | 
|  | 206 | where); | 
|  | 207 | return PCIBIOS_SUCCESSFUL; | 
|  | 208 | } | 
|  | 209 |  | 
|  | 210 | pci_config_write32(addr, value); | 
|  | 211 | } | 
|  | 212 | return PCIBIOS_SUCCESSFUL; | 
|  | 213 | } | 
|  | 214 |  | 
|  | 215 | static struct pci_ops schizo_ops = { | 
|  | 216 | .read =		schizo_read_pci_cfg, | 
|  | 217 | .write =	schizo_write_pci_cfg, | 
|  | 218 | }; | 
|  | 219 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 220 | /* SCHIZO error handling support. */ | 
|  | 221 | enum schizo_error_type { | 
|  | 222 | UE_ERR, CE_ERR, PCI_ERR, SAFARI_ERR | 
|  | 223 | }; | 
|  | 224 |  | 
|  | 225 | static DEFINE_SPINLOCK(stc_buf_lock); | 
|  | 226 | static unsigned long stc_error_buf[128]; | 
|  | 227 | static unsigned long stc_tag_buf[16]; | 
|  | 228 | static unsigned long stc_line_buf[16]; | 
|  | 229 |  | 
|  | 230 | #define SCHIZO_UE_INO		0x30 /* Uncorrectable ECC error */ | 
|  | 231 | #define SCHIZO_CE_INO		0x31 /* Correctable ECC error */ | 
|  | 232 | #define SCHIZO_PCIERR_A_INO	0x32 /* PBM A PCI bus error */ | 
|  | 233 | #define SCHIZO_PCIERR_B_INO	0x33 /* PBM B PCI bus error */ | 
|  | 234 | #define SCHIZO_SERR_INO		0x34 /* Safari interface error */ | 
|  | 235 |  | 
|  | 236 | struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino) | 
|  | 237 | { | 
|  | 238 | ino &= IMAP_INO; | 
|  | 239 | if (p->pbm_A.ino_bitmap & (1UL << ino)) | 
|  | 240 | return &p->pbm_A; | 
|  | 241 | if (p->pbm_B.ino_bitmap & (1UL << ino)) | 
|  | 242 | return &p->pbm_B; | 
|  | 243 |  | 
|  | 244 | printk("PCI%d: No ino_bitmap entry for ino[%x], bitmaps " | 
|  | 245 | "PBM_A[%016lx] PBM_B[%016lx]", | 
|  | 246 | p->index, ino, | 
|  | 247 | p->pbm_A.ino_bitmap, | 
|  | 248 | p->pbm_B.ino_bitmap); | 
|  | 249 | printk("PCI%d: Using PBM_A, report this problem immediately.\n", | 
|  | 250 | p->index); | 
|  | 251 |  | 
|  | 252 | return &p->pbm_A; | 
|  | 253 | } | 
|  | 254 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 255 | #define SCHIZO_STC_ERR	0xb800UL /* --> 0xba00 */ | 
|  | 256 | #define SCHIZO_STC_TAG	0xba00UL /* --> 0xba80 */ | 
|  | 257 | #define SCHIZO_STC_LINE	0xbb00UL /* --> 0xbb80 */ | 
|  | 258 |  | 
|  | 259 | #define SCHIZO_STCERR_WRITE	0x2UL | 
|  | 260 | #define SCHIZO_STCERR_READ	0x1UL | 
|  | 261 |  | 
|  | 262 | #define SCHIZO_STCTAG_PPN	0x3fffffff00000000UL | 
|  | 263 | #define SCHIZO_STCTAG_VPN	0x00000000ffffe000UL | 
|  | 264 | #define SCHIZO_STCTAG_VALID	0x8000000000000000UL | 
|  | 265 | #define SCHIZO_STCTAG_READ	0x4000000000000000UL | 
|  | 266 |  | 
|  | 267 | #define SCHIZO_STCLINE_LINDX	0x0000000007800000UL | 
|  | 268 | #define SCHIZO_STCLINE_SPTR	0x000000000007e000UL | 
|  | 269 | #define SCHIZO_STCLINE_LADDR	0x0000000000001fc0UL | 
|  | 270 | #define SCHIZO_STCLINE_EPTR	0x000000000000003fUL | 
|  | 271 | #define SCHIZO_STCLINE_VALID	0x0000000000600000UL | 
|  | 272 | #define SCHIZO_STCLINE_FOFN	0x0000000000180000UL | 
|  | 273 |  | 
|  | 274 | static void __schizo_check_stc_error_pbm(struct pci_pbm_info *pbm, | 
|  | 275 | enum schizo_error_type type) | 
|  | 276 | { | 
|  | 277 | struct pci_strbuf *strbuf = &pbm->stc; | 
|  | 278 | unsigned long regbase = pbm->pbm_regs; | 
|  | 279 | unsigned long err_base, tag_base, line_base; | 
|  | 280 | u64 control; | 
|  | 281 | int i; | 
|  | 282 |  | 
|  | 283 | err_base = regbase + SCHIZO_STC_ERR; | 
|  | 284 | tag_base = regbase + SCHIZO_STC_TAG; | 
|  | 285 | line_base = regbase + SCHIZO_STC_LINE; | 
|  | 286 |  | 
|  | 287 | spin_lock(&stc_buf_lock); | 
|  | 288 |  | 
|  | 289 | /* This is __REALLY__ dangerous.  When we put the | 
|  | 290 | * streaming buffer into diagnostic mode to probe | 
|  | 291 | * it's tags and error status, we _must_ clear all | 
|  | 292 | * of the line tag valid bits before re-enabling | 
|  | 293 | * the streaming buffer.  If any dirty data lives | 
|  | 294 | * in the STC when we do this, we will end up | 
|  | 295 | * invalidating it before it has a chance to reach | 
|  | 296 | * main memory. | 
|  | 297 | */ | 
|  | 298 | control = schizo_read(strbuf->strbuf_control); | 
|  | 299 | schizo_write(strbuf->strbuf_control, | 
|  | 300 | (control | SCHIZO_STRBUF_CTRL_DENAB)); | 
|  | 301 | for (i = 0; i < 128; i++) { | 
|  | 302 | unsigned long val; | 
|  | 303 |  | 
|  | 304 | val = schizo_read(err_base + (i * 8UL)); | 
|  | 305 | schizo_write(err_base + (i * 8UL), 0UL); | 
|  | 306 | stc_error_buf[i] = val; | 
|  | 307 | } | 
|  | 308 | for (i = 0; i < 16; i++) { | 
|  | 309 | stc_tag_buf[i] = schizo_read(tag_base + (i * 8UL)); | 
|  | 310 | stc_line_buf[i] = schizo_read(line_base + (i * 8UL)); | 
|  | 311 | schizo_write(tag_base + (i * 8UL), 0UL); | 
|  | 312 | schizo_write(line_base + (i * 8UL), 0UL); | 
|  | 313 | } | 
|  | 314 |  | 
|  | 315 | /* OK, state is logged, exit diagnostic mode. */ | 
|  | 316 | schizo_write(strbuf->strbuf_control, control); | 
|  | 317 |  | 
|  | 318 | for (i = 0; i < 16; i++) { | 
|  | 319 | int j, saw_error, first, last; | 
|  | 320 |  | 
|  | 321 | saw_error = 0; | 
|  | 322 | first = i * 8; | 
|  | 323 | last = first + 8; | 
|  | 324 | for (j = first; j < last; j++) { | 
|  | 325 | unsigned long errval = stc_error_buf[j]; | 
|  | 326 | if (errval != 0) { | 
|  | 327 | saw_error++; | 
|  | 328 | printk("%s: STC_ERR(%d)[wr(%d)rd(%d)]\n", | 
|  | 329 | pbm->name, | 
|  | 330 | j, | 
|  | 331 | (errval & SCHIZO_STCERR_WRITE) ? 1 : 0, | 
|  | 332 | (errval & SCHIZO_STCERR_READ) ? 1 : 0); | 
|  | 333 | } | 
|  | 334 | } | 
|  | 335 | if (saw_error != 0) { | 
|  | 336 | unsigned long tagval = stc_tag_buf[i]; | 
|  | 337 | unsigned long lineval = stc_line_buf[i]; | 
|  | 338 | printk("%s: STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)R(%d)]\n", | 
|  | 339 | pbm->name, | 
|  | 340 | i, | 
|  | 341 | ((tagval & SCHIZO_STCTAG_PPN) >> 19UL), | 
|  | 342 | (tagval & SCHIZO_STCTAG_VPN), | 
|  | 343 | ((tagval & SCHIZO_STCTAG_VALID) ? 1 : 0), | 
|  | 344 | ((tagval & SCHIZO_STCTAG_READ) ? 1 : 0)); | 
|  | 345 |  | 
|  | 346 | /* XXX Should spit out per-bank error information... -DaveM */ | 
|  | 347 | printk("%s: STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)" | 
|  | 348 | "V(%d)FOFN(%d)]\n", | 
|  | 349 | pbm->name, | 
|  | 350 | i, | 
|  | 351 | ((lineval & SCHIZO_STCLINE_LINDX) >> 23UL), | 
|  | 352 | ((lineval & SCHIZO_STCLINE_SPTR) >> 13UL), | 
|  | 353 | ((lineval & SCHIZO_STCLINE_LADDR) >> 6UL), | 
|  | 354 | ((lineval & SCHIZO_STCLINE_EPTR) >> 0UL), | 
|  | 355 | ((lineval & SCHIZO_STCLINE_VALID) ? 1 : 0), | 
|  | 356 | ((lineval & SCHIZO_STCLINE_FOFN) ? 1 : 0)); | 
|  | 357 | } | 
|  | 358 | } | 
|  | 359 |  | 
|  | 360 | spin_unlock(&stc_buf_lock); | 
|  | 361 | } | 
|  | 362 |  | 
|  | 363 | /* IOMMU is per-PBM in Schizo, so interrogate both for anonymous | 
|  | 364 | * controller level errors. | 
|  | 365 | */ | 
|  | 366 |  | 
|  | 367 | #define SCHIZO_IOMMU_TAG	0xa580UL | 
|  | 368 | #define SCHIZO_IOMMU_DATA	0xa600UL | 
|  | 369 |  | 
|  | 370 | #define SCHIZO_IOMMU_TAG_CTXT	0x0000001ffe000000UL | 
|  | 371 | #define SCHIZO_IOMMU_TAG_ERRSTS	0x0000000001800000UL | 
|  | 372 | #define SCHIZO_IOMMU_TAG_ERR	0x0000000000400000UL | 
|  | 373 | #define SCHIZO_IOMMU_TAG_WRITE	0x0000000000200000UL | 
|  | 374 | #define SCHIZO_IOMMU_TAG_STREAM	0x0000000000100000UL | 
|  | 375 | #define SCHIZO_IOMMU_TAG_SIZE	0x0000000000080000UL | 
|  | 376 | #define SCHIZO_IOMMU_TAG_VPAGE	0x000000000007ffffUL | 
|  | 377 |  | 
|  | 378 | #define SCHIZO_IOMMU_DATA_VALID	0x0000000100000000UL | 
|  | 379 | #define SCHIZO_IOMMU_DATA_CACHE	0x0000000040000000UL | 
|  | 380 | #define SCHIZO_IOMMU_DATA_PPAGE	0x000000003fffffffUL | 
|  | 381 |  | 
|  | 382 | static void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm, | 
|  | 383 | enum schizo_error_type type) | 
|  | 384 | { | 
|  | 385 | struct pci_iommu *iommu = pbm->iommu; | 
|  | 386 | unsigned long iommu_tag[16]; | 
|  | 387 | unsigned long iommu_data[16]; | 
|  | 388 | unsigned long flags; | 
|  | 389 | u64 control; | 
|  | 390 | int i; | 
|  | 391 |  | 
|  | 392 | spin_lock_irqsave(&iommu->lock, flags); | 
|  | 393 | control = schizo_read(iommu->iommu_control); | 
|  | 394 | if (control & SCHIZO_IOMMU_CTRL_XLTEERR) { | 
|  | 395 | unsigned long base; | 
|  | 396 | char *type_string; | 
|  | 397 |  | 
|  | 398 | /* Clear the error encountered bit. */ | 
|  | 399 | control &= ~SCHIZO_IOMMU_CTRL_XLTEERR; | 
|  | 400 | schizo_write(iommu->iommu_control, control); | 
|  | 401 |  | 
|  | 402 | switch((control & SCHIZO_IOMMU_CTRL_XLTESTAT) >> 25UL) { | 
|  | 403 | case 0: | 
|  | 404 | type_string = "Protection Error"; | 
|  | 405 | break; | 
|  | 406 | case 1: | 
|  | 407 | type_string = "Invalid Error"; | 
|  | 408 | break; | 
|  | 409 | case 2: | 
|  | 410 | type_string = "TimeOut Error"; | 
|  | 411 | break; | 
|  | 412 | case 3: | 
|  | 413 | default: | 
|  | 414 | type_string = "ECC Error"; | 
|  | 415 | break; | 
|  | 416 | }; | 
|  | 417 | printk("%s: IOMMU Error, type[%s]\n", | 
|  | 418 | pbm->name, type_string); | 
|  | 419 |  | 
|  | 420 | /* Put the IOMMU into diagnostic mode and probe | 
|  | 421 | * it's TLB for entries with error status. | 
|  | 422 | * | 
|  | 423 | * It is very possible for another DVMA to occur | 
|  | 424 | * while we do this probe, and corrupt the system | 
|  | 425 | * further.  But we are so screwed at this point | 
|  | 426 | * that we are likely to crash hard anyways, so | 
|  | 427 | * get as much diagnostic information to the | 
|  | 428 | * console as we can. | 
|  | 429 | */ | 
|  | 430 | schizo_write(iommu->iommu_control, | 
|  | 431 | control | SCHIZO_IOMMU_CTRL_DENAB); | 
|  | 432 |  | 
|  | 433 | base = pbm->pbm_regs; | 
|  | 434 |  | 
|  | 435 | for (i = 0; i < 16; i++) { | 
|  | 436 | iommu_tag[i] = | 
|  | 437 | schizo_read(base + SCHIZO_IOMMU_TAG + (i * 8UL)); | 
|  | 438 | iommu_data[i] = | 
|  | 439 | schizo_read(base + SCHIZO_IOMMU_DATA + (i * 8UL)); | 
|  | 440 |  | 
|  | 441 | /* Now clear out the entry. */ | 
|  | 442 | schizo_write(base + SCHIZO_IOMMU_TAG + (i * 8UL), 0); | 
|  | 443 | schizo_write(base + SCHIZO_IOMMU_DATA + (i * 8UL), 0); | 
|  | 444 | } | 
|  | 445 |  | 
|  | 446 | /* Leave diagnostic mode. */ | 
|  | 447 | schizo_write(iommu->iommu_control, control); | 
|  | 448 |  | 
|  | 449 | for (i = 0; i < 16; i++) { | 
|  | 450 | unsigned long tag, data; | 
|  | 451 |  | 
|  | 452 | tag = iommu_tag[i]; | 
|  | 453 | if (!(tag & SCHIZO_IOMMU_TAG_ERR)) | 
|  | 454 | continue; | 
|  | 455 |  | 
|  | 456 | data = iommu_data[i]; | 
|  | 457 | switch((tag & SCHIZO_IOMMU_TAG_ERRSTS) >> 23UL) { | 
|  | 458 | case 0: | 
|  | 459 | type_string = "Protection Error"; | 
|  | 460 | break; | 
|  | 461 | case 1: | 
|  | 462 | type_string = "Invalid Error"; | 
|  | 463 | break; | 
|  | 464 | case 2: | 
|  | 465 | type_string = "TimeOut Error"; | 
|  | 466 | break; | 
|  | 467 | case 3: | 
|  | 468 | default: | 
|  | 469 | type_string = "ECC Error"; | 
|  | 470 | break; | 
|  | 471 | }; | 
|  | 472 | printk("%s: IOMMU TAG(%d)[error(%s) ctx(%x) wr(%d) str(%d) " | 
|  | 473 | "sz(%dK) vpg(%08lx)]\n", | 
|  | 474 | pbm->name, i, type_string, | 
|  | 475 | (int)((tag & SCHIZO_IOMMU_TAG_CTXT) >> 25UL), | 
|  | 476 | ((tag & SCHIZO_IOMMU_TAG_WRITE) ? 1 : 0), | 
|  | 477 | ((tag & SCHIZO_IOMMU_TAG_STREAM) ? 1 : 0), | 
|  | 478 | ((tag & SCHIZO_IOMMU_TAG_SIZE) ? 64 : 8), | 
|  | 479 | (tag & SCHIZO_IOMMU_TAG_VPAGE) << IOMMU_PAGE_SHIFT); | 
|  | 480 | printk("%s: IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n", | 
|  | 481 | pbm->name, i, | 
|  | 482 | ((data & SCHIZO_IOMMU_DATA_VALID) ? 1 : 0), | 
|  | 483 | ((data & SCHIZO_IOMMU_DATA_CACHE) ? 1 : 0), | 
|  | 484 | (data & SCHIZO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT); | 
|  | 485 | } | 
|  | 486 | } | 
|  | 487 | if (pbm->stc.strbuf_enabled) | 
|  | 488 | __schizo_check_stc_error_pbm(pbm, type); | 
|  | 489 | spin_unlock_irqrestore(&iommu->lock, flags); | 
|  | 490 | } | 
|  | 491 |  | 
|  | 492 | static void schizo_check_iommu_error(struct pci_controller_info *p, | 
|  | 493 | enum schizo_error_type type) | 
|  | 494 | { | 
|  | 495 | schizo_check_iommu_error_pbm(&p->pbm_A, type); | 
|  | 496 | schizo_check_iommu_error_pbm(&p->pbm_B, type); | 
|  | 497 | } | 
|  | 498 |  | 
|  | 499 | /* Uncorrectable ECC error status gathering. */ | 
|  | 500 | #define SCHIZO_UE_AFSR	0x10030UL | 
|  | 501 | #define SCHIZO_UE_AFAR	0x10038UL | 
|  | 502 |  | 
|  | 503 | #define SCHIZO_UEAFSR_PPIO	0x8000000000000000UL /* Safari */ | 
|  | 504 | #define SCHIZO_UEAFSR_PDRD	0x4000000000000000UL /* Safari/Tomatillo */ | 
|  | 505 | #define SCHIZO_UEAFSR_PDWR	0x2000000000000000UL /* Safari */ | 
|  | 506 | #define SCHIZO_UEAFSR_SPIO	0x1000000000000000UL /* Safari */ | 
|  | 507 | #define SCHIZO_UEAFSR_SDMA	0x0800000000000000UL /* Safari/Tomatillo */ | 
|  | 508 | #define SCHIZO_UEAFSR_ERRPNDG	0x0300000000000000UL /* Safari */ | 
|  | 509 | #define SCHIZO_UEAFSR_BMSK	0x000003ff00000000UL /* Safari */ | 
|  | 510 | #define SCHIZO_UEAFSR_QOFF	0x00000000c0000000UL /* Safari/Tomatillo */ | 
|  | 511 | #define SCHIZO_UEAFSR_AID	0x000000001f000000UL /* Safari/Tomatillo */ | 
|  | 512 | #define SCHIZO_UEAFSR_PARTIAL	0x0000000000800000UL /* Safari */ | 
|  | 513 | #define SCHIZO_UEAFSR_OWNEDIN	0x0000000000400000UL /* Safari */ | 
|  | 514 | #define SCHIZO_UEAFSR_MTAGSYND	0x00000000000f0000UL /* Safari */ | 
|  | 515 | #define SCHIZO_UEAFSR_MTAG	0x000000000000e000UL /* Safari */ | 
|  | 516 | #define SCHIZO_UEAFSR_ECCSYND	0x00000000000001ffUL /* Safari */ | 
|  | 517 |  | 
| Al Viro | 6d24c8d | 2006-10-08 08:23:28 -0400 | [diff] [blame] | 518 | static irqreturn_t schizo_ue_intr(int irq, void *dev_id) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 519 | { | 
|  | 520 | struct pci_controller_info *p = dev_id; | 
|  | 521 | unsigned long afsr_reg = p->pbm_B.controller_regs + SCHIZO_UE_AFSR; | 
|  | 522 | unsigned long afar_reg = p->pbm_B.controller_regs + SCHIZO_UE_AFAR; | 
|  | 523 | unsigned long afsr, afar, error_bits; | 
|  | 524 | int reported, limit; | 
|  | 525 |  | 
|  | 526 | /* Latch uncorrectable error status. */ | 
|  | 527 | afar = schizo_read(afar_reg); | 
|  | 528 |  | 
|  | 529 | /* If either of the error pending bits are set in the | 
|  | 530 | * AFSR, the error status is being actively updated by | 
|  | 531 | * the hardware and we must re-read to get a clean value. | 
|  | 532 | */ | 
|  | 533 | limit = 1000; | 
|  | 534 | do { | 
|  | 535 | afsr = schizo_read(afsr_reg); | 
|  | 536 | } while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit); | 
|  | 537 |  | 
|  | 538 | /* Clear the primary/secondary error status bits. */ | 
|  | 539 | error_bits = afsr & | 
|  | 540 | (SCHIZO_UEAFSR_PPIO | SCHIZO_UEAFSR_PDRD | SCHIZO_UEAFSR_PDWR | | 
|  | 541 | SCHIZO_UEAFSR_SPIO | SCHIZO_UEAFSR_SDMA); | 
|  | 542 | if (!error_bits) | 
|  | 543 | return IRQ_NONE; | 
|  | 544 | schizo_write(afsr_reg, error_bits); | 
|  | 545 |  | 
|  | 546 | /* Log the error. */ | 
|  | 547 | printk("PCI%d: Uncorrectable Error, primary error type[%s]\n", | 
|  | 548 | p->index, | 
|  | 549 | (((error_bits & SCHIZO_UEAFSR_PPIO) ? | 
|  | 550 | "PIO" : | 
|  | 551 | ((error_bits & SCHIZO_UEAFSR_PDRD) ? | 
|  | 552 | "DMA Read" : | 
|  | 553 | ((error_bits & SCHIZO_UEAFSR_PDWR) ? | 
|  | 554 | "DMA Write" : "???"))))); | 
|  | 555 | printk("PCI%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n", | 
|  | 556 | p->index, | 
|  | 557 | (afsr & SCHIZO_UEAFSR_BMSK) >> 32UL, | 
|  | 558 | (afsr & SCHIZO_UEAFSR_QOFF) >> 30UL, | 
|  | 559 | (afsr & SCHIZO_UEAFSR_AID) >> 24UL); | 
|  | 560 | printk("PCI%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n", | 
|  | 561 | p->index, | 
|  | 562 | (afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0, | 
|  | 563 | (afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0, | 
|  | 564 | (afsr & SCHIZO_UEAFSR_MTAG) >> 13UL, | 
|  | 565 | (afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL, | 
|  | 566 | (afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL); | 
|  | 567 | printk("PCI%d: UE AFAR [%016lx]\n", p->index, afar); | 
|  | 568 | printk("PCI%d: UE Secondary errors [", p->index); | 
|  | 569 | reported = 0; | 
|  | 570 | if (afsr & SCHIZO_UEAFSR_SPIO) { | 
|  | 571 | reported++; | 
|  | 572 | printk("(PIO)"); | 
|  | 573 | } | 
|  | 574 | if (afsr & SCHIZO_UEAFSR_SDMA) { | 
|  | 575 | reported++; | 
|  | 576 | printk("(DMA)"); | 
|  | 577 | } | 
|  | 578 | if (!reported) | 
|  | 579 | printk("(none)"); | 
|  | 580 | printk("]\n"); | 
|  | 581 |  | 
|  | 582 | /* Interrogate IOMMU for error status. */ | 
|  | 583 | schizo_check_iommu_error(p, UE_ERR); | 
|  | 584 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 585 | return IRQ_HANDLED; | 
|  | 586 | } | 
|  | 587 |  | 
|  | 588 | #define SCHIZO_CE_AFSR	0x10040UL | 
|  | 589 | #define SCHIZO_CE_AFAR	0x10048UL | 
|  | 590 |  | 
|  | 591 | #define SCHIZO_CEAFSR_PPIO	0x8000000000000000UL | 
|  | 592 | #define SCHIZO_CEAFSR_PDRD	0x4000000000000000UL | 
|  | 593 | #define SCHIZO_CEAFSR_PDWR	0x2000000000000000UL | 
|  | 594 | #define SCHIZO_CEAFSR_SPIO	0x1000000000000000UL | 
|  | 595 | #define SCHIZO_CEAFSR_SDMA	0x0800000000000000UL | 
|  | 596 | #define SCHIZO_CEAFSR_ERRPNDG	0x0300000000000000UL | 
|  | 597 | #define SCHIZO_CEAFSR_BMSK	0x000003ff00000000UL | 
|  | 598 | #define SCHIZO_CEAFSR_QOFF	0x00000000c0000000UL | 
|  | 599 | #define SCHIZO_CEAFSR_AID	0x000000001f000000UL | 
|  | 600 | #define SCHIZO_CEAFSR_PARTIAL	0x0000000000800000UL | 
|  | 601 | #define SCHIZO_CEAFSR_OWNEDIN	0x0000000000400000UL | 
|  | 602 | #define SCHIZO_CEAFSR_MTAGSYND	0x00000000000f0000UL | 
|  | 603 | #define SCHIZO_CEAFSR_MTAG	0x000000000000e000UL | 
|  | 604 | #define SCHIZO_CEAFSR_ECCSYND	0x00000000000001ffUL | 
|  | 605 |  | 
| Al Viro | 6d24c8d | 2006-10-08 08:23:28 -0400 | [diff] [blame] | 606 | static irqreturn_t schizo_ce_intr(int irq, void *dev_id) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 607 | { | 
|  | 608 | struct pci_controller_info *p = dev_id; | 
|  | 609 | unsigned long afsr_reg = p->pbm_B.controller_regs + SCHIZO_CE_AFSR; | 
|  | 610 | unsigned long afar_reg = p->pbm_B.controller_regs + SCHIZO_CE_AFAR; | 
|  | 611 | unsigned long afsr, afar, error_bits; | 
|  | 612 | int reported, limit; | 
|  | 613 |  | 
|  | 614 | /* Latch error status. */ | 
|  | 615 | afar = schizo_read(afar_reg); | 
|  | 616 |  | 
|  | 617 | /* If either of the error pending bits are set in the | 
|  | 618 | * AFSR, the error status is being actively updated by | 
|  | 619 | * the hardware and we must re-read to get a clean value. | 
|  | 620 | */ | 
|  | 621 | limit = 1000; | 
|  | 622 | do { | 
|  | 623 | afsr = schizo_read(afsr_reg); | 
|  | 624 | } while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit); | 
|  | 625 |  | 
|  | 626 | /* Clear primary/secondary error status bits. */ | 
|  | 627 | error_bits = afsr & | 
|  | 628 | (SCHIZO_CEAFSR_PPIO | SCHIZO_CEAFSR_PDRD | SCHIZO_CEAFSR_PDWR | | 
|  | 629 | SCHIZO_CEAFSR_SPIO | SCHIZO_CEAFSR_SDMA); | 
|  | 630 | if (!error_bits) | 
|  | 631 | return IRQ_NONE; | 
|  | 632 | schizo_write(afsr_reg, error_bits); | 
|  | 633 |  | 
|  | 634 | /* Log the error. */ | 
|  | 635 | printk("PCI%d: Correctable Error, primary error type[%s]\n", | 
|  | 636 | p->index, | 
|  | 637 | (((error_bits & SCHIZO_CEAFSR_PPIO) ? | 
|  | 638 | "PIO" : | 
|  | 639 | ((error_bits & SCHIZO_CEAFSR_PDRD) ? | 
|  | 640 | "DMA Read" : | 
|  | 641 | ((error_bits & SCHIZO_CEAFSR_PDWR) ? | 
|  | 642 | "DMA Write" : "???"))))); | 
|  | 643 |  | 
|  | 644 | /* XXX Use syndrome and afar to print out module string just like | 
|  | 645 | * XXX UDB CE trap handler does... -DaveM | 
|  | 646 | */ | 
|  | 647 | printk("PCI%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n", | 
|  | 648 | p->index, | 
|  | 649 | (afsr & SCHIZO_UEAFSR_BMSK) >> 32UL, | 
|  | 650 | (afsr & SCHIZO_UEAFSR_QOFF) >> 30UL, | 
|  | 651 | (afsr & SCHIZO_UEAFSR_AID) >> 24UL); | 
|  | 652 | printk("PCI%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n", | 
|  | 653 | p->index, | 
|  | 654 | (afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0, | 
|  | 655 | (afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0, | 
|  | 656 | (afsr & SCHIZO_UEAFSR_MTAG) >> 13UL, | 
|  | 657 | (afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL, | 
|  | 658 | (afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL); | 
|  | 659 | printk("PCI%d: CE AFAR [%016lx]\n", p->index, afar); | 
|  | 660 | printk("PCI%d: CE Secondary errors [", p->index); | 
|  | 661 | reported = 0; | 
|  | 662 | if (afsr & SCHIZO_CEAFSR_SPIO) { | 
|  | 663 | reported++; | 
|  | 664 | printk("(PIO)"); | 
|  | 665 | } | 
|  | 666 | if (afsr & SCHIZO_CEAFSR_SDMA) { | 
|  | 667 | reported++; | 
|  | 668 | printk("(DMA)"); | 
|  | 669 | } | 
|  | 670 | if (!reported) | 
|  | 671 | printk("(none)"); | 
|  | 672 | printk("]\n"); | 
|  | 673 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 674 | return IRQ_HANDLED; | 
|  | 675 | } | 
|  | 676 |  | 
|  | 677 | #define SCHIZO_PCI_AFSR	0x2010UL | 
|  | 678 | #define SCHIZO_PCI_AFAR	0x2018UL | 
|  | 679 |  | 
|  | 680 | #define SCHIZO_PCIAFSR_PMA	0x8000000000000000UL /* Schizo/Tomatillo */ | 
|  | 681 | #define SCHIZO_PCIAFSR_PTA	0x4000000000000000UL /* Schizo/Tomatillo */ | 
|  | 682 | #define SCHIZO_PCIAFSR_PRTRY	0x2000000000000000UL /* Schizo/Tomatillo */ | 
|  | 683 | #define SCHIZO_PCIAFSR_PPERR	0x1000000000000000UL /* Schizo/Tomatillo */ | 
|  | 684 | #define SCHIZO_PCIAFSR_PTTO	0x0800000000000000UL /* Schizo/Tomatillo */ | 
|  | 685 | #define SCHIZO_PCIAFSR_PUNUS	0x0400000000000000UL /* Schizo */ | 
|  | 686 | #define SCHIZO_PCIAFSR_SMA	0x0200000000000000UL /* Schizo/Tomatillo */ | 
|  | 687 | #define SCHIZO_PCIAFSR_STA	0x0100000000000000UL /* Schizo/Tomatillo */ | 
|  | 688 | #define SCHIZO_PCIAFSR_SRTRY	0x0080000000000000UL /* Schizo/Tomatillo */ | 
|  | 689 | #define SCHIZO_PCIAFSR_SPERR	0x0040000000000000UL /* Schizo/Tomatillo */ | 
|  | 690 | #define SCHIZO_PCIAFSR_STTO	0x0020000000000000UL /* Schizo/Tomatillo */ | 
|  | 691 | #define SCHIZO_PCIAFSR_SUNUS	0x0010000000000000UL /* Schizo */ | 
|  | 692 | #define SCHIZO_PCIAFSR_BMSK	0x000003ff00000000UL /* Schizo/Tomatillo */ | 
|  | 693 | #define SCHIZO_PCIAFSR_BLK	0x0000000080000000UL /* Schizo/Tomatillo */ | 
|  | 694 | #define SCHIZO_PCIAFSR_CFG	0x0000000040000000UL /* Schizo/Tomatillo */ | 
|  | 695 | #define SCHIZO_PCIAFSR_MEM	0x0000000020000000UL /* Schizo/Tomatillo */ | 
|  | 696 | #define SCHIZO_PCIAFSR_IO	0x0000000010000000UL /* Schizo/Tomatillo */ | 
|  | 697 |  | 
|  | 698 | #define SCHIZO_PCI_CTRL		(0x2000UL) | 
|  | 699 | #define SCHIZO_PCICTRL_BUS_UNUS	(1UL << 63UL) /* Safari */ | 
| David S. Miller | 9fba62a | 2005-07-04 14:53:33 -0700 | [diff] [blame] | 700 | #define SCHIZO_PCICTRL_DTO_INT	(1UL << 61UL) /* Tomatillo */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 701 | #define SCHIZO_PCICTRL_ARB_PRIO (0x1ff << 52UL) /* Tomatillo */ | 
|  | 702 | #define SCHIZO_PCICTRL_ESLCK	(1UL << 51UL) /* Safari */ | 
|  | 703 | #define SCHIZO_PCICTRL_ERRSLOT	(7UL << 48UL) /* Safari */ | 
|  | 704 | #define SCHIZO_PCICTRL_TTO_ERR	(1UL << 38UL) /* Safari/Tomatillo */ | 
|  | 705 | #define SCHIZO_PCICTRL_RTRY_ERR	(1UL << 37UL) /* Safari/Tomatillo */ | 
|  | 706 | #define SCHIZO_PCICTRL_DTO_ERR	(1UL << 36UL) /* Safari/Tomatillo */ | 
|  | 707 | #define SCHIZO_PCICTRL_SBH_ERR	(1UL << 35UL) /* Safari */ | 
|  | 708 | #define SCHIZO_PCICTRL_SERR	(1UL << 34UL) /* Safari/Tomatillo */ | 
|  | 709 | #define SCHIZO_PCICTRL_PCISPD	(1UL << 33UL) /* Safari */ | 
|  | 710 | #define SCHIZO_PCICTRL_MRM_PREF	(1UL << 30UL) /* Tomatillo */ | 
|  | 711 | #define SCHIZO_PCICTRL_RDO_PREF	(1UL << 29UL) /* Tomatillo */ | 
|  | 712 | #define SCHIZO_PCICTRL_RDL_PREF	(1UL << 28UL) /* Tomatillo */ | 
|  | 713 | #define SCHIZO_PCICTRL_PTO	(3UL << 24UL) /* Safari/Tomatillo */ | 
|  | 714 | #define SCHIZO_PCICTRL_PTO_SHIFT 24UL | 
|  | 715 | #define SCHIZO_PCICTRL_TRWSW	(7UL << 21UL) /* Tomatillo */ | 
|  | 716 | #define SCHIZO_PCICTRL_F_TGT_A	(1UL << 20UL) /* Tomatillo */ | 
|  | 717 | #define SCHIZO_PCICTRL_S_DTO_INT (1UL << 19UL) /* Safari */ | 
|  | 718 | #define SCHIZO_PCICTRL_F_TGT_RT	(1UL << 19UL) /* Tomatillo */ | 
|  | 719 | #define SCHIZO_PCICTRL_SBH_INT	(1UL << 18UL) /* Safari */ | 
|  | 720 | #define SCHIZO_PCICTRL_T_DTO_INT (1UL << 18UL) /* Tomatillo */ | 
|  | 721 | #define SCHIZO_PCICTRL_EEN	(1UL << 17UL) /* Safari/Tomatillo */ | 
|  | 722 | #define SCHIZO_PCICTRL_PARK	(1UL << 16UL) /* Safari/Tomatillo */ | 
|  | 723 | #define SCHIZO_PCICTRL_PCIRST	(1UL <<  8UL) /* Safari */ | 
|  | 724 | #define SCHIZO_PCICTRL_ARB_S	(0x3fUL << 0UL) /* Safari */ | 
|  | 725 | #define SCHIZO_PCICTRL_ARB_T	(0xffUL << 0UL) /* Tomatillo */ | 
|  | 726 |  | 
|  | 727 | static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm) | 
|  | 728 | { | 
|  | 729 | unsigned long csr_reg, csr, csr_error_bits; | 
|  | 730 | irqreturn_t ret = IRQ_NONE; | 
|  | 731 | u16 stat; | 
|  | 732 |  | 
|  | 733 | csr_reg = pbm->pbm_regs + SCHIZO_PCI_CTRL; | 
|  | 734 | csr = schizo_read(csr_reg); | 
|  | 735 | csr_error_bits = | 
|  | 736 | csr & (SCHIZO_PCICTRL_BUS_UNUS | | 
|  | 737 | SCHIZO_PCICTRL_TTO_ERR | | 
|  | 738 | SCHIZO_PCICTRL_RTRY_ERR | | 
|  | 739 | SCHIZO_PCICTRL_DTO_ERR | | 
|  | 740 | SCHIZO_PCICTRL_SBH_ERR | | 
|  | 741 | SCHIZO_PCICTRL_SERR); | 
|  | 742 | if (csr_error_bits) { | 
|  | 743 | /* Clear the errors.  */ | 
|  | 744 | schizo_write(csr_reg, csr); | 
|  | 745 |  | 
|  | 746 | /* Log 'em.  */ | 
|  | 747 | if (csr_error_bits & SCHIZO_PCICTRL_BUS_UNUS) | 
|  | 748 | printk("%s: Bus unusable error asserted.\n", | 
|  | 749 | pbm->name); | 
|  | 750 | if (csr_error_bits & SCHIZO_PCICTRL_TTO_ERR) | 
|  | 751 | printk("%s: PCI TRDY# timeout error asserted.\n", | 
|  | 752 | pbm->name); | 
|  | 753 | if (csr_error_bits & SCHIZO_PCICTRL_RTRY_ERR) | 
|  | 754 | printk("%s: PCI excessive retry error asserted.\n", | 
|  | 755 | pbm->name); | 
|  | 756 | if (csr_error_bits & SCHIZO_PCICTRL_DTO_ERR) | 
|  | 757 | printk("%s: PCI discard timeout error asserted.\n", | 
|  | 758 | pbm->name); | 
|  | 759 | if (csr_error_bits & SCHIZO_PCICTRL_SBH_ERR) | 
|  | 760 | printk("%s: PCI streaming byte hole error asserted.\n", | 
|  | 761 | pbm->name); | 
|  | 762 | if (csr_error_bits & SCHIZO_PCICTRL_SERR) | 
|  | 763 | printk("%s: PCI SERR signal asserted.\n", | 
|  | 764 | pbm->name); | 
|  | 765 | ret = IRQ_HANDLED; | 
|  | 766 | } | 
|  | 767 | pci_read_config_word(pbm->pci_bus->self, PCI_STATUS, &stat); | 
|  | 768 | if (stat & (PCI_STATUS_PARITY | | 
|  | 769 | PCI_STATUS_SIG_TARGET_ABORT | | 
|  | 770 | PCI_STATUS_REC_TARGET_ABORT | | 
|  | 771 | PCI_STATUS_REC_MASTER_ABORT | | 
|  | 772 | PCI_STATUS_SIG_SYSTEM_ERROR)) { | 
|  | 773 | printk("%s: PCI bus error, PCI_STATUS[%04x]\n", | 
|  | 774 | pbm->name, stat); | 
|  | 775 | pci_write_config_word(pbm->pci_bus->self, PCI_STATUS, 0xffff); | 
|  | 776 | ret = IRQ_HANDLED; | 
|  | 777 | } | 
|  | 778 | return ret; | 
|  | 779 | } | 
|  | 780 |  | 
| Al Viro | 6d24c8d | 2006-10-08 08:23:28 -0400 | [diff] [blame] | 781 | static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 782 | { | 
|  | 783 | struct pci_pbm_info *pbm = dev_id; | 
|  | 784 | struct pci_controller_info *p = pbm->parent; | 
|  | 785 | unsigned long afsr_reg, afar_reg, base; | 
|  | 786 | unsigned long afsr, afar, error_bits; | 
|  | 787 | int reported; | 
|  | 788 |  | 
|  | 789 | base = pbm->pbm_regs; | 
|  | 790 |  | 
|  | 791 | afsr_reg = base + SCHIZO_PCI_AFSR; | 
|  | 792 | afar_reg = base + SCHIZO_PCI_AFAR; | 
|  | 793 |  | 
|  | 794 | /* Latch error status. */ | 
|  | 795 | afar = schizo_read(afar_reg); | 
|  | 796 | afsr = schizo_read(afsr_reg); | 
|  | 797 |  | 
|  | 798 | /* Clear primary/secondary error status bits. */ | 
|  | 799 | error_bits = afsr & | 
|  | 800 | (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA | | 
|  | 801 | SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR | | 
|  | 802 | SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS | | 
|  | 803 | SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA | | 
|  | 804 | SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR | | 
|  | 805 | SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS); | 
|  | 806 | if (!error_bits) | 
|  | 807 | return schizo_pcierr_intr_other(pbm); | 
|  | 808 | schizo_write(afsr_reg, error_bits); | 
|  | 809 |  | 
|  | 810 | /* Log the error. */ | 
|  | 811 | printk("%s: PCI Error, primary error type[%s]\n", | 
|  | 812 | pbm->name, | 
|  | 813 | (((error_bits & SCHIZO_PCIAFSR_PMA) ? | 
|  | 814 | "Master Abort" : | 
|  | 815 | ((error_bits & SCHIZO_PCIAFSR_PTA) ? | 
|  | 816 | "Target Abort" : | 
|  | 817 | ((error_bits & SCHIZO_PCIAFSR_PRTRY) ? | 
|  | 818 | "Excessive Retries" : | 
|  | 819 | ((error_bits & SCHIZO_PCIAFSR_PPERR) ? | 
|  | 820 | "Parity Error" : | 
|  | 821 | ((error_bits & SCHIZO_PCIAFSR_PTTO) ? | 
|  | 822 | "Timeout" : | 
|  | 823 | ((error_bits & SCHIZO_PCIAFSR_PUNUS) ? | 
|  | 824 | "Bus Unusable" : "???")))))))); | 
|  | 825 | printk("%s: bytemask[%04lx] was_block(%d) space(%s)\n", | 
|  | 826 | pbm->name, | 
|  | 827 | (afsr & SCHIZO_PCIAFSR_BMSK) >> 32UL, | 
|  | 828 | (afsr & SCHIZO_PCIAFSR_BLK) ? 1 : 0, | 
|  | 829 | ((afsr & SCHIZO_PCIAFSR_CFG) ? | 
|  | 830 | "Config" : | 
|  | 831 | ((afsr & SCHIZO_PCIAFSR_MEM) ? | 
|  | 832 | "Memory" : | 
|  | 833 | ((afsr & SCHIZO_PCIAFSR_IO) ? | 
|  | 834 | "I/O" : "???")))); | 
|  | 835 | printk("%s: PCI AFAR [%016lx]\n", | 
|  | 836 | pbm->name, afar); | 
|  | 837 | printk("%s: PCI Secondary errors [", | 
|  | 838 | pbm->name); | 
|  | 839 | reported = 0; | 
|  | 840 | if (afsr & SCHIZO_PCIAFSR_SMA) { | 
|  | 841 | reported++; | 
|  | 842 | printk("(Master Abort)"); | 
|  | 843 | } | 
|  | 844 | if (afsr & SCHIZO_PCIAFSR_STA) { | 
|  | 845 | reported++; | 
|  | 846 | printk("(Target Abort)"); | 
|  | 847 | } | 
|  | 848 | if (afsr & SCHIZO_PCIAFSR_SRTRY) { | 
|  | 849 | reported++; | 
|  | 850 | printk("(Excessive Retries)"); | 
|  | 851 | } | 
|  | 852 | if (afsr & SCHIZO_PCIAFSR_SPERR) { | 
|  | 853 | reported++; | 
|  | 854 | printk("(Parity Error)"); | 
|  | 855 | } | 
|  | 856 | if (afsr & SCHIZO_PCIAFSR_STTO) { | 
|  | 857 | reported++; | 
|  | 858 | printk("(Timeout)"); | 
|  | 859 | } | 
|  | 860 | if (afsr & SCHIZO_PCIAFSR_SUNUS) { | 
|  | 861 | reported++; | 
|  | 862 | printk("(Bus Unusable)"); | 
|  | 863 | } | 
|  | 864 | if (!reported) | 
|  | 865 | printk("(none)"); | 
|  | 866 | printk("]\n"); | 
|  | 867 |  | 
|  | 868 | /* For the error types shown, scan PBM's PCI bus for devices | 
|  | 869 | * which have logged that error type. | 
|  | 870 | */ | 
|  | 871 |  | 
|  | 872 | /* If we see a Target Abort, this could be the result of an | 
|  | 873 | * IOMMU translation error of some sort.  It is extremely | 
|  | 874 | * useful to log this information as usually it indicates | 
|  | 875 | * a bug in the IOMMU support code or a PCI device driver. | 
|  | 876 | */ | 
|  | 877 | if (error_bits & (SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_STA)) { | 
|  | 878 | schizo_check_iommu_error(p, PCI_ERR); | 
|  | 879 | pci_scan_for_target_abort(p, pbm, pbm->pci_bus); | 
|  | 880 | } | 
|  | 881 | if (error_bits & (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_SMA)) | 
|  | 882 | pci_scan_for_master_abort(p, pbm, pbm->pci_bus); | 
|  | 883 |  | 
|  | 884 | /* For excessive retries, PSYCHO/PBM will abort the device | 
|  | 885 | * and there is no way to specifically check for excessive | 
|  | 886 | * retries in the config space status registers.  So what | 
|  | 887 | * we hope is that we'll catch it via the master/target | 
|  | 888 | * abort events. | 
|  | 889 | */ | 
|  | 890 |  | 
|  | 891 | if (error_bits & (SCHIZO_PCIAFSR_PPERR | SCHIZO_PCIAFSR_SPERR)) | 
|  | 892 | pci_scan_for_parity_error(p, pbm, pbm->pci_bus); | 
|  | 893 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 894 | return IRQ_HANDLED; | 
|  | 895 | } | 
|  | 896 |  | 
|  | 897 | #define SCHIZO_SAFARI_ERRLOG	0x10018UL | 
|  | 898 |  | 
|  | 899 | #define SAFARI_ERRLOG_ERROUT	0x8000000000000000UL | 
|  | 900 |  | 
|  | 901 | #define BUS_ERROR_BADCMD	0x4000000000000000UL /* Schizo/Tomatillo */ | 
|  | 902 | #define BUS_ERROR_SSMDIS	0x2000000000000000UL /* Safari */ | 
|  | 903 | #define BUS_ERROR_BADMA		0x1000000000000000UL /* Safari */ | 
|  | 904 | #define BUS_ERROR_BADMB		0x0800000000000000UL /* Safari */ | 
|  | 905 | #define BUS_ERROR_BADMC		0x0400000000000000UL /* Safari */ | 
|  | 906 | #define BUS_ERROR_SNOOP_GR	0x0000000000200000UL /* Tomatillo */ | 
|  | 907 | #define BUS_ERROR_SNOOP_PCI	0x0000000000100000UL /* Tomatillo */ | 
|  | 908 | #define BUS_ERROR_SNOOP_RD	0x0000000000080000UL /* Tomatillo */ | 
|  | 909 | #define BUS_ERROR_SNOOP_RDS	0x0000000000020000UL /* Tomatillo */ | 
|  | 910 | #define BUS_ERROR_SNOOP_RDSA	0x0000000000010000UL /* Tomatillo */ | 
|  | 911 | #define BUS_ERROR_SNOOP_OWN	0x0000000000008000UL /* Tomatillo */ | 
|  | 912 | #define BUS_ERROR_SNOOP_RDO	0x0000000000004000UL /* Tomatillo */ | 
|  | 913 | #define BUS_ERROR_CPU1PS	0x0000000000002000UL /* Safari */ | 
|  | 914 | #define BUS_ERROR_WDATA_PERR	0x0000000000002000UL /* Tomatillo */ | 
|  | 915 | #define BUS_ERROR_CPU1PB	0x0000000000001000UL /* Safari */ | 
|  | 916 | #define BUS_ERROR_CTRL_PERR	0x0000000000001000UL /* Tomatillo */ | 
|  | 917 | #define BUS_ERROR_CPU0PS	0x0000000000000800UL /* Safari */ | 
|  | 918 | #define BUS_ERROR_SNOOP_ERR	0x0000000000000800UL /* Tomatillo */ | 
|  | 919 | #define BUS_ERROR_CPU0PB	0x0000000000000400UL /* Safari */ | 
|  | 920 | #define BUS_ERROR_JBUS_ILL_B	0x0000000000000400UL /* Tomatillo */ | 
|  | 921 | #define BUS_ERROR_CIQTO		0x0000000000000200UL /* Safari */ | 
|  | 922 | #define BUS_ERROR_LPQTO		0x0000000000000100UL /* Safari */ | 
|  | 923 | #define BUS_ERROR_JBUS_ILL_C	0x0000000000000100UL /* Tomatillo */ | 
|  | 924 | #define BUS_ERROR_SFPQTO	0x0000000000000080UL /* Safari */ | 
|  | 925 | #define BUS_ERROR_UFPQTO	0x0000000000000040UL /* Safari */ | 
|  | 926 | #define BUS_ERROR_RD_PERR	0x0000000000000040UL /* Tomatillo */ | 
|  | 927 | #define BUS_ERROR_APERR		0x0000000000000020UL /* Safari/Tomatillo */ | 
|  | 928 | #define BUS_ERROR_UNMAP		0x0000000000000010UL /* Safari/Tomatillo */ | 
|  | 929 | #define BUS_ERROR_BUSERR	0x0000000000000004UL /* Safari/Tomatillo */ | 
|  | 930 | #define BUS_ERROR_TIMEOUT	0x0000000000000002UL /* Safari/Tomatillo */ | 
|  | 931 | #define BUS_ERROR_ILL		0x0000000000000001UL /* Safari */ | 
|  | 932 |  | 
|  | 933 | /* We only expect UNMAP errors here.  The rest of the Safari errors | 
|  | 934 | * are marked fatal and thus cause a system reset. | 
|  | 935 | */ | 
| Al Viro | 6d24c8d | 2006-10-08 08:23:28 -0400 | [diff] [blame] | 936 | static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 937 | { | 
|  | 938 | struct pci_controller_info *p = dev_id; | 
|  | 939 | u64 errlog; | 
|  | 940 |  | 
|  | 941 | errlog = schizo_read(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRLOG); | 
|  | 942 | schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRLOG, | 
|  | 943 | errlog & ~(SAFARI_ERRLOG_ERROUT)); | 
|  | 944 |  | 
|  | 945 | if (!(errlog & BUS_ERROR_UNMAP)) { | 
|  | 946 | printk("PCI%d: Unexpected Safari/JBUS error interrupt, errlog[%016lx]\n", | 
|  | 947 | p->index, errlog); | 
|  | 948 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 949 | return IRQ_HANDLED; | 
|  | 950 | } | 
|  | 951 |  | 
|  | 952 | printk("PCI%d: Safari/JBUS interrupt, UNMAPPED error, interrogating IOMMUs.\n", | 
|  | 953 | p->index); | 
|  | 954 | schizo_check_iommu_error(p, SAFARI_ERR); | 
|  | 955 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 956 | return IRQ_HANDLED; | 
|  | 957 | } | 
|  | 958 |  | 
|  | 959 | /* Nearly identical to PSYCHO equivalents... */ | 
|  | 960 | #define SCHIZO_ECC_CTRL		0x10020UL | 
|  | 961 | #define  SCHIZO_ECCCTRL_EE	 0x8000000000000000UL /* Enable ECC Checking */ | 
|  | 962 | #define  SCHIZO_ECCCTRL_UE	 0x4000000000000000UL /* Enable UE Interrupts */ | 
|  | 963 | #define  SCHIZO_ECCCTRL_CE	 0x2000000000000000UL /* Enable CE INterrupts */ | 
|  | 964 |  | 
|  | 965 | #define SCHIZO_SAFARI_ERRCTRL	0x10008UL | 
|  | 966 | #define  SCHIZO_SAFERRCTRL_EN	 0x8000000000000000UL | 
|  | 967 | #define SCHIZO_SAFARI_IRQCTRL	0x10010UL | 
|  | 968 | #define  SCHIZO_SAFIRQCTRL_EN	 0x8000000000000000UL | 
|  | 969 |  | 
|  | 970 | /* How the Tomatillo IRQs are routed around is pure guesswork here. | 
|  | 971 | * | 
|  | 972 | * All the Tomatillo devices I see in prtconf dumps seem to have only | 
|  | 973 | * a single PCI bus unit attached to it.  It would seem they are seperate | 
|  | 974 | * devices because their PortID (ie. JBUS ID) values are all different | 
|  | 975 | * and thus the registers are mapped to totally different locations. | 
|  | 976 | * | 
|  | 977 | * However, two Tomatillo's look "similar" in that the only difference | 
|  | 978 | * in their PortID is the lowest bit. | 
|  | 979 | * | 
|  | 980 | * So if we were to ignore this lower bit, it certainly looks like two | 
|  | 981 | * PCI bus units of the same Tomatillo.  I still have not really | 
|  | 982 | * figured this out... | 
|  | 983 | */ | 
| David S. Miller | 085ae41 | 2005-08-08 13:19:08 -0700 | [diff] [blame] | 984 | static void tomatillo_register_error_handlers(struct pci_controller_info *p) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 985 | { | 
|  | 986 | struct pci_pbm_info *pbm; | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 987 | struct of_device *op; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 988 | u64 tmp, err_mask, err_no_mask; | 
|  | 989 |  | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 990 | /* Tomatillo IRQ property layout is: | 
|  | 991 | * 0: PCIERR | 
|  | 992 | * 1: UE ERR | 
|  | 993 | * 2: CE ERR | 
|  | 994 | * 3: SERR | 
|  | 995 | * 4: POWER FAIL? | 
|  | 996 | */ | 
|  | 997 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 998 | pbm = pbm_for_ino(p, SCHIZO_UE_INO); | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 999 | op = of_find_device_by_node(pbm->prom_node); | 
|  | 1000 | if (op) | 
| Thomas Gleixner | d356d7f | 2006-07-01 19:29:26 -0700 | [diff] [blame] | 1001 | request_irq(op->irqs[1], schizo_ue_intr, IRQF_SHARED, | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 1002 | "TOMATILLO_UE", p); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1003 |  | 
|  | 1004 | pbm = pbm_for_ino(p, SCHIZO_CE_INO); | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 1005 | op = of_find_device_by_node(pbm->prom_node); | 
|  | 1006 | if (op) | 
| Thomas Gleixner | d356d7f | 2006-07-01 19:29:26 -0700 | [diff] [blame] | 1007 | request_irq(op->irqs[2], schizo_ce_intr, IRQF_SHARED, | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 1008 | "TOMATILLO CE", p); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1009 |  | 
|  | 1010 | pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO); | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 1011 | op = of_find_device_by_node(pbm->prom_node); | 
|  | 1012 | if (op) | 
| Thomas Gleixner | d356d7f | 2006-07-01 19:29:26 -0700 | [diff] [blame] | 1013 | request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED, | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 1014 | "TOMATILLO PCIERR-A", pbm); | 
|  | 1015 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1016 |  | 
|  | 1017 | pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO); | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 1018 | op = of_find_device_by_node(pbm->prom_node); | 
|  | 1019 | if (op) | 
| Thomas Gleixner | d356d7f | 2006-07-01 19:29:26 -0700 | [diff] [blame] | 1020 | request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED, | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 1021 | "TOMATILLO PCIERR-B", pbm); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1022 |  | 
|  | 1023 | pbm = pbm_for_ino(p, SCHIZO_SERR_INO); | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 1024 | op = of_find_device_by_node(pbm->prom_node); | 
|  | 1025 | if (op) | 
| Thomas Gleixner | d356d7f | 2006-07-01 19:29:26 -0700 | [diff] [blame] | 1026 | request_irq(op->irqs[3], schizo_safarierr_intr, IRQF_SHARED, | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 1027 | "TOMATILLO SERR", p); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1028 |  | 
|  | 1029 | /* Enable UE and CE interrupts for controller. */ | 
|  | 1030 | schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL, | 
|  | 1031 | (SCHIZO_ECCCTRL_EE | | 
|  | 1032 | SCHIZO_ECCCTRL_UE | | 
|  | 1033 | SCHIZO_ECCCTRL_CE)); | 
|  | 1034 |  | 
|  | 1035 | schizo_write(p->pbm_B.controller_regs + SCHIZO_ECC_CTRL, | 
|  | 1036 | (SCHIZO_ECCCTRL_EE | | 
|  | 1037 | SCHIZO_ECCCTRL_UE | | 
|  | 1038 | SCHIZO_ECCCTRL_CE)); | 
|  | 1039 |  | 
|  | 1040 | /* Enable PCI Error interrupts and clear error | 
|  | 1041 | * bits. | 
|  | 1042 | */ | 
|  | 1043 | err_mask = (SCHIZO_PCICTRL_BUS_UNUS | | 
|  | 1044 | SCHIZO_PCICTRL_TTO_ERR | | 
|  | 1045 | SCHIZO_PCICTRL_RTRY_ERR | | 
|  | 1046 | SCHIZO_PCICTRL_SERR | | 
|  | 1047 | SCHIZO_PCICTRL_EEN); | 
|  | 1048 |  | 
|  | 1049 | err_no_mask = SCHIZO_PCICTRL_DTO_ERR; | 
|  | 1050 |  | 
|  | 1051 | tmp = schizo_read(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL); | 
|  | 1052 | tmp |= err_mask; | 
|  | 1053 | tmp &= ~err_no_mask; | 
|  | 1054 | schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL, tmp); | 
|  | 1055 |  | 
|  | 1056 | tmp = schizo_read(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL); | 
|  | 1057 | tmp |= err_mask; | 
|  | 1058 | tmp &= ~err_no_mask; | 
|  | 1059 | schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL, tmp); | 
|  | 1060 |  | 
|  | 1061 | err_mask = (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA | | 
|  | 1062 | SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR | | 
|  | 1063 | SCHIZO_PCIAFSR_PTTO | | 
|  | 1064 | SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA | | 
|  | 1065 | SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR | | 
|  | 1066 | SCHIZO_PCIAFSR_STTO); | 
|  | 1067 |  | 
|  | 1068 | schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_AFSR, err_mask); | 
|  | 1069 | schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_AFSR, err_mask); | 
|  | 1070 |  | 
|  | 1071 | err_mask = (BUS_ERROR_BADCMD | BUS_ERROR_SNOOP_GR | | 
|  | 1072 | BUS_ERROR_SNOOP_PCI | BUS_ERROR_SNOOP_RD | | 
|  | 1073 | BUS_ERROR_SNOOP_RDS | BUS_ERROR_SNOOP_RDSA | | 
|  | 1074 | BUS_ERROR_SNOOP_OWN | BUS_ERROR_SNOOP_RDO | | 
|  | 1075 | BUS_ERROR_WDATA_PERR | BUS_ERROR_CTRL_PERR | | 
|  | 1076 | BUS_ERROR_SNOOP_ERR | BUS_ERROR_JBUS_ILL_B | | 
|  | 1077 | BUS_ERROR_JBUS_ILL_C | BUS_ERROR_RD_PERR | | 
|  | 1078 | BUS_ERROR_APERR | BUS_ERROR_UNMAP | | 
|  | 1079 | BUS_ERROR_BUSERR | BUS_ERROR_TIMEOUT); | 
|  | 1080 |  | 
|  | 1081 | schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_ERRCTRL, | 
|  | 1082 | (SCHIZO_SAFERRCTRL_EN | err_mask)); | 
|  | 1083 | schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRCTRL, | 
|  | 1084 | (SCHIZO_SAFERRCTRL_EN | err_mask)); | 
|  | 1085 |  | 
|  | 1086 | schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_IRQCTRL, | 
|  | 1087 | (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP))); | 
|  | 1088 | schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_IRQCTRL, | 
|  | 1089 | (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP))); | 
|  | 1090 | } | 
|  | 1091 |  | 
| David S. Miller | 085ae41 | 2005-08-08 13:19:08 -0700 | [diff] [blame] | 1092 | static void schizo_register_error_handlers(struct pci_controller_info *p) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1093 | { | 
|  | 1094 | struct pci_pbm_info *pbm; | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 1095 | struct of_device *op; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1096 | u64 tmp, err_mask, err_no_mask; | 
|  | 1097 |  | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 1098 | /* Schizo IRQ property layout is: | 
|  | 1099 | * 0: PCIERR | 
|  | 1100 | * 1: UE ERR | 
|  | 1101 | * 2: CE ERR | 
|  | 1102 | * 3: SERR | 
|  | 1103 | * 4: POWER FAIL? | 
|  | 1104 | */ | 
|  | 1105 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1106 | pbm = pbm_for_ino(p, SCHIZO_UE_INO); | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 1107 | op = of_find_device_by_node(pbm->prom_node); | 
|  | 1108 | if (op) | 
| Thomas Gleixner | d356d7f | 2006-07-01 19:29:26 -0700 | [diff] [blame] | 1109 | request_irq(op->irqs[1], schizo_ue_intr, IRQF_SHARED, | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 1110 | "SCHIZO_UE", p); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1111 |  | 
|  | 1112 | pbm = pbm_for_ino(p, SCHIZO_CE_INO); | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 1113 | op = of_find_device_by_node(pbm->prom_node); | 
|  | 1114 | if (op) | 
| Thomas Gleixner | d356d7f | 2006-07-01 19:29:26 -0700 | [diff] [blame] | 1115 | request_irq(op->irqs[2], schizo_ce_intr, IRQF_SHARED, | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 1116 | "SCHIZO CE", p); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1117 |  | 
|  | 1118 | pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO); | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 1119 | op = of_find_device_by_node(pbm->prom_node); | 
|  | 1120 | if (op) | 
| Thomas Gleixner | d356d7f | 2006-07-01 19:29:26 -0700 | [diff] [blame] | 1121 | request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED, | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 1122 | "SCHIZO PCIERR-A", pbm); | 
|  | 1123 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1124 |  | 
|  | 1125 | pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO); | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 1126 | op = of_find_device_by_node(pbm->prom_node); | 
|  | 1127 | if (op) | 
| Thomas Gleixner | d356d7f | 2006-07-01 19:29:26 -0700 | [diff] [blame] | 1128 | request_irq(op->irqs[0], schizo_pcierr_intr, IRQF_SHARED, | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 1129 | "SCHIZO PCIERR-B", pbm); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1130 |  | 
|  | 1131 | pbm = pbm_for_ino(p, SCHIZO_SERR_INO); | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 1132 | op = of_find_device_by_node(pbm->prom_node); | 
|  | 1133 | if (op) | 
| Thomas Gleixner | d356d7f | 2006-07-01 19:29:26 -0700 | [diff] [blame] | 1134 | request_irq(op->irqs[3], schizo_safarierr_intr, IRQF_SHARED, | 
| David S. Miller | 2b1e597 | 2006-06-29 15:07:37 -0700 | [diff] [blame] | 1135 | "SCHIZO SERR", p); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1136 |  | 
|  | 1137 | /* Enable UE and CE interrupts for controller. */ | 
|  | 1138 | schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL, | 
|  | 1139 | (SCHIZO_ECCCTRL_EE | | 
|  | 1140 | SCHIZO_ECCCTRL_UE | | 
|  | 1141 | SCHIZO_ECCCTRL_CE)); | 
|  | 1142 |  | 
|  | 1143 | err_mask = (SCHIZO_PCICTRL_BUS_UNUS | | 
|  | 1144 | SCHIZO_PCICTRL_ESLCK | | 
|  | 1145 | SCHIZO_PCICTRL_TTO_ERR | | 
|  | 1146 | SCHIZO_PCICTRL_RTRY_ERR | | 
|  | 1147 | SCHIZO_PCICTRL_SBH_ERR | | 
|  | 1148 | SCHIZO_PCICTRL_SERR | | 
|  | 1149 | SCHIZO_PCICTRL_EEN); | 
|  | 1150 |  | 
|  | 1151 | err_no_mask = (SCHIZO_PCICTRL_DTO_ERR | | 
|  | 1152 | SCHIZO_PCICTRL_SBH_INT); | 
|  | 1153 |  | 
|  | 1154 | /* Enable PCI Error interrupts and clear error | 
|  | 1155 | * bits for each PBM. | 
|  | 1156 | */ | 
|  | 1157 | tmp = schizo_read(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL); | 
|  | 1158 | tmp |= err_mask; | 
|  | 1159 | tmp &= ~err_no_mask; | 
|  | 1160 | schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL, tmp); | 
|  | 1161 |  | 
|  | 1162 | schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_AFSR, | 
|  | 1163 | (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA | | 
|  | 1164 | SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR | | 
|  | 1165 | SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS | | 
|  | 1166 | SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA | | 
|  | 1167 | SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR | | 
|  | 1168 | SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS)); | 
|  | 1169 |  | 
|  | 1170 | tmp = schizo_read(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL); | 
|  | 1171 | tmp |= err_mask; | 
|  | 1172 | tmp &= ~err_no_mask; | 
|  | 1173 | schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL, tmp); | 
|  | 1174 |  | 
|  | 1175 | schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_AFSR, | 
|  | 1176 | (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA | | 
|  | 1177 | SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR | | 
|  | 1178 | SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS | | 
|  | 1179 | SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA | | 
|  | 1180 | SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR | | 
|  | 1181 | SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS)); | 
|  | 1182 |  | 
|  | 1183 | /* Make all Safari error conditions fatal except unmapped | 
|  | 1184 | * errors which we make generate interrupts. | 
|  | 1185 | */ | 
|  | 1186 | err_mask = (BUS_ERROR_BADCMD | BUS_ERROR_SSMDIS | | 
|  | 1187 | BUS_ERROR_BADMA | BUS_ERROR_BADMB | | 
|  | 1188 | BUS_ERROR_BADMC | | 
|  | 1189 | BUS_ERROR_CPU1PS | BUS_ERROR_CPU1PB | | 
|  | 1190 | BUS_ERROR_CPU0PS | BUS_ERROR_CPU0PB | | 
|  | 1191 | BUS_ERROR_CIQTO | | 
|  | 1192 | BUS_ERROR_LPQTO | BUS_ERROR_SFPQTO | | 
|  | 1193 | BUS_ERROR_UFPQTO | BUS_ERROR_APERR | | 
|  | 1194 | BUS_ERROR_BUSERR | BUS_ERROR_TIMEOUT | | 
|  | 1195 | BUS_ERROR_ILL); | 
|  | 1196 | #if 1 | 
|  | 1197 | /* XXX Something wrong with some Excalibur systems | 
|  | 1198 | * XXX Sun is shipping.  The behavior on a 2-cpu | 
|  | 1199 | * XXX machine is that both CPU1 parity error bits | 
|  | 1200 | * XXX are set and are immediately set again when | 
|  | 1201 | * XXX their error status bits are cleared.  Just | 
|  | 1202 | * XXX ignore them for now.  -DaveM | 
|  | 1203 | */ | 
|  | 1204 | err_mask &= ~(BUS_ERROR_CPU1PS | BUS_ERROR_CPU1PB | | 
|  | 1205 | BUS_ERROR_CPU0PS | BUS_ERROR_CPU0PB); | 
|  | 1206 | #endif | 
|  | 1207 |  | 
|  | 1208 | schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_ERRCTRL, | 
|  | 1209 | (SCHIZO_SAFERRCTRL_EN | err_mask)); | 
|  | 1210 |  | 
|  | 1211 | schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_IRQCTRL, | 
|  | 1212 | (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP))); | 
|  | 1213 | } | 
|  | 1214 |  | 
| David S. Miller | 085ae41 | 2005-08-08 13:19:08 -0700 | [diff] [blame] | 1215 | static void pbm_config_busmastering(struct pci_pbm_info *pbm) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1216 | { | 
|  | 1217 | u8 *addr; | 
|  | 1218 |  | 
|  | 1219 | /* Set cache-line size to 64 bytes, this is actually | 
|  | 1220 | * a nop but I do it for completeness. | 
|  | 1221 | */ | 
|  | 1222 | addr = schizo_pci_config_mkaddr(pbm, pbm->pci_first_busno, | 
|  | 1223 | 0, PCI_CACHE_LINE_SIZE); | 
|  | 1224 | pci_config_write8(addr, 64 / sizeof(u32)); | 
|  | 1225 |  | 
|  | 1226 | /* Set PBM latency timer to 64 PCI clocks. */ | 
|  | 1227 | addr = schizo_pci_config_mkaddr(pbm, pbm->pci_first_busno, | 
|  | 1228 | 0, PCI_LATENCY_TIMER); | 
|  | 1229 | pci_config_write8(addr, 64); | 
|  | 1230 | } | 
|  | 1231 |  | 
| David S. Miller | 085ae41 | 2005-08-08 13:19:08 -0700 | [diff] [blame] | 1232 | static void pbm_scan_bus(struct pci_controller_info *p, | 
|  | 1233 | struct pci_pbm_info *pbm) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1234 | { | 
| Eric Sesterhenn | 9132983 | 2006-03-06 13:48:40 -0800 | [diff] [blame] | 1235 | struct pcidev_cookie *cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1236 |  | 
|  | 1237 | if (!cookie) { | 
|  | 1238 | prom_printf("%s: Critical allocation failure.\n", pbm->name); | 
|  | 1239 | prom_halt(); | 
|  | 1240 | } | 
|  | 1241 |  | 
|  | 1242 | /* All we care about is the PBM. */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1243 | cookie->pbm = pbm; | 
|  | 1244 |  | 
|  | 1245 | pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, | 
|  | 1246 | p->pci_ops, | 
|  | 1247 | pbm); | 
|  | 1248 | pci_fixup_host_bridge_self(pbm->pci_bus); | 
|  | 1249 | pbm->pci_bus->self->sysdata = cookie; | 
|  | 1250 |  | 
| David S. Miller | de8d28b | 2006-06-22 16:18:54 -0700 | [diff] [blame] | 1251 | pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1252 | pci_record_assignments(pbm, pbm->pci_bus); | 
|  | 1253 | pci_assign_unassigned(pbm, pbm->pci_bus); | 
|  | 1254 | pci_fixup_irq(pbm, pbm->pci_bus); | 
|  | 1255 | pci_determine_66mhz_disposition(pbm, pbm->pci_bus); | 
|  | 1256 | pci_setup_busmastering(pbm, pbm->pci_bus); | 
|  | 1257 | } | 
|  | 1258 |  | 
| David S. Miller | 085ae41 | 2005-08-08 13:19:08 -0700 | [diff] [blame] | 1259 | static void __schizo_scan_bus(struct pci_controller_info *p, | 
|  | 1260 | int chip_type) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1261 | { | 
|  | 1262 | if (!p->pbm_B.prom_node || !p->pbm_A.prom_node) { | 
|  | 1263 | printk("PCI: Only one PCI bus module of controller found.\n"); | 
|  | 1264 | printk("PCI: Ignoring entire controller.\n"); | 
|  | 1265 | return; | 
|  | 1266 | } | 
|  | 1267 |  | 
|  | 1268 | pbm_config_busmastering(&p->pbm_B); | 
|  | 1269 | p->pbm_B.is_66mhz_capable = | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1270 | (of_find_property(p->pbm_B.prom_node, "66mhz-capable", NULL) | 
|  | 1271 | != NULL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1272 | pbm_config_busmastering(&p->pbm_A); | 
|  | 1273 | p->pbm_A.is_66mhz_capable = | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1274 | (of_find_property(p->pbm_A.prom_node, "66mhz-capable", NULL) | 
|  | 1275 | != NULL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1276 | pbm_scan_bus(p, &p->pbm_B); | 
|  | 1277 | pbm_scan_bus(p, &p->pbm_A); | 
|  | 1278 |  | 
|  | 1279 | /* After the PCI bus scan is complete, we can register | 
|  | 1280 | * the error interrupt handlers. | 
|  | 1281 | */ | 
|  | 1282 | if (chip_type == PBM_CHIP_TYPE_TOMATILLO) | 
|  | 1283 | tomatillo_register_error_handlers(p); | 
|  | 1284 | else | 
|  | 1285 | schizo_register_error_handlers(p); | 
|  | 1286 | } | 
|  | 1287 |  | 
| David S. Miller | 085ae41 | 2005-08-08 13:19:08 -0700 | [diff] [blame] | 1288 | static void schizo_scan_bus(struct pci_controller_info *p) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1289 | { | 
|  | 1290 | __schizo_scan_bus(p, PBM_CHIP_TYPE_SCHIZO); | 
|  | 1291 | } | 
|  | 1292 |  | 
| David S. Miller | 085ae41 | 2005-08-08 13:19:08 -0700 | [diff] [blame] | 1293 | static void tomatillo_scan_bus(struct pci_controller_info *p) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1294 | { | 
|  | 1295 | __schizo_scan_bus(p, PBM_CHIP_TYPE_TOMATILLO); | 
|  | 1296 | } | 
|  | 1297 |  | 
| David S. Miller | 085ae41 | 2005-08-08 13:19:08 -0700 | [diff] [blame] | 1298 | static void schizo_base_address_update(struct pci_dev *pdev, int resource) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1299 | { | 
|  | 1300 | struct pcidev_cookie *pcp = pdev->sysdata; | 
|  | 1301 | struct pci_pbm_info *pbm = pcp->pbm; | 
|  | 1302 | struct resource *res, *root; | 
|  | 1303 | u32 reg; | 
|  | 1304 | int where, size, is_64bit; | 
|  | 1305 |  | 
|  | 1306 | res = &pdev->resource[resource]; | 
|  | 1307 | if (resource < 6) { | 
|  | 1308 | where = PCI_BASE_ADDRESS_0 + (resource * 4); | 
|  | 1309 | } else if (resource == PCI_ROM_RESOURCE) { | 
|  | 1310 | where = pdev->rom_base_reg; | 
|  | 1311 | } else { | 
|  | 1312 | /* Somebody might have asked allocation of a non-standard resource */ | 
|  | 1313 | return; | 
|  | 1314 | } | 
|  | 1315 |  | 
|  | 1316 | is_64bit = 0; | 
|  | 1317 | if (res->flags & IORESOURCE_IO) | 
|  | 1318 | root = &pbm->io_space; | 
|  | 1319 | else { | 
|  | 1320 | root = &pbm->mem_space; | 
|  | 1321 | if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) | 
|  | 1322 | == PCI_BASE_ADDRESS_MEM_TYPE_64) | 
|  | 1323 | is_64bit = 1; | 
|  | 1324 | } | 
|  | 1325 |  | 
|  | 1326 | size = res->end - res->start; | 
|  | 1327 | pci_read_config_dword(pdev, where, ®); | 
|  | 1328 | reg = ((reg & size) | | 
|  | 1329 | (((u32)(res->start - root->start)) & ~size)); | 
|  | 1330 | if (resource == PCI_ROM_RESOURCE) { | 
|  | 1331 | reg |= PCI_ROM_ADDRESS_ENABLE; | 
|  | 1332 | res->flags |= IORESOURCE_ROM_ENABLE; | 
|  | 1333 | } | 
|  | 1334 | pci_write_config_dword(pdev, where, reg); | 
|  | 1335 |  | 
|  | 1336 | /* This knows that the upper 32-bits of the address | 
|  | 1337 | * must be zero.  Our PCI common layer enforces this. | 
|  | 1338 | */ | 
|  | 1339 | if (is_64bit) | 
|  | 1340 | pci_write_config_dword(pdev, where + 4, 0); | 
|  | 1341 | } | 
|  | 1342 |  | 
| David S. Miller | 085ae41 | 2005-08-08 13:19:08 -0700 | [diff] [blame] | 1343 | static void schizo_resource_adjust(struct pci_dev *pdev, | 
|  | 1344 | struct resource *res, | 
|  | 1345 | struct resource *root) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1346 | { | 
|  | 1347 | res->start += root->start; | 
|  | 1348 | res->end += root->start; | 
|  | 1349 | } | 
|  | 1350 |  | 
|  | 1351 | /* Use ranges property to determine where PCI MEM, I/O, and Config | 
|  | 1352 | * space are for this PCI bus module. | 
|  | 1353 | */ | 
|  | 1354 | static void schizo_determine_mem_io_space(struct pci_pbm_info *pbm) | 
|  | 1355 | { | 
|  | 1356 | int i, saw_cfg, saw_mem, saw_io; | 
|  | 1357 |  | 
|  | 1358 | saw_cfg = saw_mem = saw_io = 0; | 
|  | 1359 | for (i = 0; i < pbm->num_pbm_ranges; i++) { | 
|  | 1360 | struct linux_prom_pci_ranges *pr = &pbm->pbm_ranges[i]; | 
|  | 1361 | unsigned long a; | 
|  | 1362 | int type; | 
|  | 1363 |  | 
|  | 1364 | type = (pr->child_phys_hi >> 24) & 0x3; | 
|  | 1365 | a = (((unsigned long)pr->parent_phys_hi << 32UL) | | 
|  | 1366 | ((unsigned long)pr->parent_phys_lo  <<  0UL)); | 
|  | 1367 |  | 
|  | 1368 | switch (type) { | 
|  | 1369 | case 0: | 
|  | 1370 | /* PCI config space, 16MB */ | 
|  | 1371 | pbm->config_space = a; | 
|  | 1372 | saw_cfg = 1; | 
|  | 1373 | break; | 
|  | 1374 |  | 
|  | 1375 | case 1: | 
|  | 1376 | /* 16-bit IO space, 16MB */ | 
|  | 1377 | pbm->io_space.start = a; | 
|  | 1378 | pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL); | 
|  | 1379 | pbm->io_space.flags = IORESOURCE_IO; | 
|  | 1380 | saw_io = 1; | 
|  | 1381 | break; | 
|  | 1382 |  | 
|  | 1383 | case 2: | 
|  | 1384 | /* 32-bit MEM space, 2GB */ | 
|  | 1385 | pbm->mem_space.start = a; | 
|  | 1386 | pbm->mem_space.end = a + (0x80000000UL - 1UL); | 
|  | 1387 | pbm->mem_space.flags = IORESOURCE_MEM; | 
|  | 1388 | saw_mem = 1; | 
|  | 1389 | break; | 
|  | 1390 |  | 
|  | 1391 | default: | 
|  | 1392 | break; | 
|  | 1393 | }; | 
|  | 1394 | } | 
|  | 1395 |  | 
|  | 1396 | if (!saw_cfg || !saw_io || !saw_mem) { | 
|  | 1397 | prom_printf("%s: Fatal error, missing %s PBM range.\n", | 
|  | 1398 | pbm->name, | 
|  | 1399 | ((!saw_cfg ? | 
|  | 1400 | "CFG" : | 
|  | 1401 | (!saw_io ? | 
|  | 1402 | "IO" : "MEM")))); | 
|  | 1403 | prom_halt(); | 
|  | 1404 | } | 
|  | 1405 |  | 
|  | 1406 | printk("%s: PCI CFG[%lx] IO[%lx] MEM[%lx]\n", | 
|  | 1407 | pbm->name, | 
|  | 1408 | pbm->config_space, | 
|  | 1409 | pbm->io_space.start, | 
|  | 1410 | pbm->mem_space.start); | 
|  | 1411 | } | 
|  | 1412 |  | 
| David S. Miller | 085ae41 | 2005-08-08 13:19:08 -0700 | [diff] [blame] | 1413 | static void pbm_register_toplevel_resources(struct pci_controller_info *p, | 
|  | 1414 | struct pci_pbm_info *pbm) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1415 | { | 
|  | 1416 | pbm->io_space.name = pbm->mem_space.name = pbm->name; | 
|  | 1417 |  | 
|  | 1418 | request_resource(&ioport_resource, &pbm->io_space); | 
|  | 1419 | request_resource(&iomem_resource, &pbm->mem_space); | 
|  | 1420 | pci_register_legacy_regions(&pbm->io_space, | 
|  | 1421 | &pbm->mem_space); | 
|  | 1422 | } | 
|  | 1423 |  | 
|  | 1424 | #define SCHIZO_STRBUF_CONTROL		(0x02800UL) | 
|  | 1425 | #define SCHIZO_STRBUF_FLUSH		(0x02808UL) | 
|  | 1426 | #define SCHIZO_STRBUF_FSYNC		(0x02810UL) | 
|  | 1427 | #define SCHIZO_STRBUF_CTXFLUSH		(0x02818UL) | 
|  | 1428 | #define SCHIZO_STRBUF_CTXMATCH		(0x10000UL) | 
|  | 1429 |  | 
|  | 1430 | static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm) | 
|  | 1431 | { | 
|  | 1432 | unsigned long base = pbm->pbm_regs; | 
|  | 1433 | u64 control; | 
|  | 1434 |  | 
|  | 1435 | if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) { | 
|  | 1436 | /* TOMATILLO lacks streaming cache.  */ | 
|  | 1437 | return; | 
|  | 1438 | } | 
|  | 1439 |  | 
|  | 1440 | /* SCHIZO has context flushing. */ | 
|  | 1441 | pbm->stc.strbuf_control		= base + SCHIZO_STRBUF_CONTROL; | 
|  | 1442 | pbm->stc.strbuf_pflush		= base + SCHIZO_STRBUF_FLUSH; | 
|  | 1443 | pbm->stc.strbuf_fsync		= base + SCHIZO_STRBUF_FSYNC; | 
|  | 1444 | pbm->stc.strbuf_ctxflush	= base + SCHIZO_STRBUF_CTXFLUSH; | 
|  | 1445 | pbm->stc.strbuf_ctxmatch_base	= base + SCHIZO_STRBUF_CTXMATCH; | 
|  | 1446 |  | 
|  | 1447 | pbm->stc.strbuf_flushflag = (volatile unsigned long *) | 
|  | 1448 | ((((unsigned long)&pbm->stc.__flushflag_buf[0]) | 
|  | 1449 | + 63UL) | 
|  | 1450 | & ~63UL); | 
|  | 1451 | pbm->stc.strbuf_flushflag_pa = (unsigned long) | 
|  | 1452 | __pa(pbm->stc.strbuf_flushflag); | 
|  | 1453 |  | 
|  | 1454 | /* Turn off LRU locking and diag mode, enable the | 
|  | 1455 | * streaming buffer and leave the rerun-disable | 
|  | 1456 | * setting however OBP set it. | 
|  | 1457 | */ | 
|  | 1458 | control = schizo_read(pbm->stc.strbuf_control); | 
|  | 1459 | control &= ~(SCHIZO_STRBUF_CTRL_LPTR | | 
|  | 1460 | SCHIZO_STRBUF_CTRL_LENAB | | 
|  | 1461 | SCHIZO_STRBUF_CTRL_DENAB); | 
|  | 1462 | control |= SCHIZO_STRBUF_CTRL_ENAB; | 
|  | 1463 | schizo_write(pbm->stc.strbuf_control, control); | 
|  | 1464 |  | 
|  | 1465 | pbm->stc.strbuf_enabled = 1; | 
|  | 1466 | } | 
|  | 1467 |  | 
|  | 1468 | #define SCHIZO_IOMMU_CONTROL		(0x00200UL) | 
|  | 1469 | #define SCHIZO_IOMMU_TSBBASE		(0x00208UL) | 
|  | 1470 | #define SCHIZO_IOMMU_FLUSH		(0x00210UL) | 
|  | 1471 | #define SCHIZO_IOMMU_CTXFLUSH		(0x00218UL) | 
|  | 1472 |  | 
|  | 1473 | static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm) | 
|  | 1474 | { | 
|  | 1475 | struct pci_iommu *iommu = pbm->iommu; | 
| David S. Miller | 51e8513 | 2005-10-13 21:10:08 -0700 | [diff] [blame] | 1476 | unsigned long i, tagbase, database; | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1477 | struct property *prop; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1478 | u32 vdma[2], dma_mask; | 
|  | 1479 | u64 control; | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1480 | int tsbsize; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1481 |  | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1482 | prop = of_find_property(pbm->prom_node, "virtual-dma", NULL); | 
|  | 1483 | if (prop) { | 
|  | 1484 | u32 *val = prop->value; | 
|  | 1485 |  | 
|  | 1486 | vdma[0] = val[0]; | 
|  | 1487 | vdma[1] = val[1]; | 
|  | 1488 | } else { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1489 | /* No property, use default values. */ | 
|  | 1490 | vdma[0] = 0xc0000000; | 
|  | 1491 | vdma[1] = 0x40000000; | 
|  | 1492 | } | 
|  | 1493 |  | 
|  | 1494 | dma_mask = vdma[0]; | 
|  | 1495 | switch (vdma[1]) { | 
|  | 1496 | case 0x20000000: | 
|  | 1497 | dma_mask |= 0x1fffffff; | 
|  | 1498 | tsbsize = 64; | 
|  | 1499 | break; | 
|  | 1500 |  | 
|  | 1501 | case 0x40000000: | 
|  | 1502 | dma_mask |= 0x3fffffff; | 
|  | 1503 | tsbsize = 128; | 
|  | 1504 | break; | 
|  | 1505 |  | 
|  | 1506 | case 0x80000000: | 
|  | 1507 | dma_mask |= 0x7fffffff; | 
|  | 1508 | tsbsize = 128; | 
|  | 1509 | break; | 
|  | 1510 |  | 
|  | 1511 | default: | 
|  | 1512 | prom_printf("SCHIZO: strange virtual-dma size.\n"); | 
|  | 1513 | prom_halt(); | 
|  | 1514 | }; | 
|  | 1515 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1516 | /* Register addresses, SCHIZO has iommu ctx flushing. */ | 
|  | 1517 | iommu->iommu_control  = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL; | 
|  | 1518 | iommu->iommu_tsbbase  = pbm->pbm_regs + SCHIZO_IOMMU_TSBBASE; | 
|  | 1519 | iommu->iommu_flush    = pbm->pbm_regs + SCHIZO_IOMMU_FLUSH; | 
|  | 1520 | iommu->iommu_ctxflush = pbm->pbm_regs + SCHIZO_IOMMU_CTXFLUSH; | 
|  | 1521 |  | 
|  | 1522 | /* We use the main control/status register of SCHIZO as the write | 
|  | 1523 | * completion register. | 
|  | 1524 | */ | 
|  | 1525 | iommu->write_complete_reg = pbm->controller_regs + 0x10000UL; | 
|  | 1526 |  | 
|  | 1527 | /* | 
|  | 1528 | * Invalidate TLB Entries. | 
|  | 1529 | */ | 
|  | 1530 | control = schizo_read(iommu->iommu_control); | 
|  | 1531 | control |= SCHIZO_IOMMU_CTRL_DENAB; | 
|  | 1532 | schizo_write(iommu->iommu_control, control); | 
|  | 1533 |  | 
|  | 1534 | tagbase = SCHIZO_IOMMU_TAG, database = SCHIZO_IOMMU_DATA; | 
|  | 1535 |  | 
|  | 1536 | for(i = 0; i < 16; i++) { | 
|  | 1537 | schizo_write(pbm->pbm_regs + tagbase + (i * 8UL), 0); | 
|  | 1538 | schizo_write(pbm->pbm_regs + database + (i * 8UL), 0); | 
|  | 1539 | } | 
|  | 1540 |  | 
|  | 1541 | /* Leave diag mode enabled for full-flushing done | 
|  | 1542 | * in pci_iommu.c | 
|  | 1543 | */ | 
| David S. Miller | 51e8513 | 2005-10-13 21:10:08 -0700 | [diff] [blame] | 1544 | pci_iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1545 |  | 
| David S. Miller | 51e8513 | 2005-10-13 21:10:08 -0700 | [diff] [blame] | 1546 | schizo_write(iommu->iommu_tsbbase, __pa(iommu->page_table)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1547 |  | 
|  | 1548 | control = schizo_read(iommu->iommu_control); | 
|  | 1549 | control &= ~(SCHIZO_IOMMU_CTRL_TSBSZ | SCHIZO_IOMMU_CTRL_TBWSZ); | 
|  | 1550 | switch (tsbsize) { | 
|  | 1551 | case 64: | 
|  | 1552 | control |= SCHIZO_IOMMU_TSBSZ_64K; | 
|  | 1553 | break; | 
|  | 1554 | case 128: | 
|  | 1555 | control |= SCHIZO_IOMMU_TSBSZ_128K; | 
|  | 1556 | break; | 
|  | 1557 | }; | 
|  | 1558 |  | 
|  | 1559 | control |= SCHIZO_IOMMU_CTRL_ENAB; | 
|  | 1560 | schizo_write(iommu->iommu_control, control); | 
|  | 1561 | } | 
|  | 1562 |  | 
|  | 1563 | #define SCHIZO_PCI_IRQ_RETRY	(0x1a00UL) | 
|  | 1564 | #define  SCHIZO_IRQ_RETRY_INF	 0xffUL | 
|  | 1565 |  | 
|  | 1566 | #define SCHIZO_PCI_DIAG			(0x2020UL) | 
|  | 1567 | #define  SCHIZO_PCIDIAG_D_BADECC	(1UL << 10UL) /* Disable BAD ECC errors (Schizo) */ | 
|  | 1568 | #define  SCHIZO_PCIDIAG_D_BYPASS	(1UL <<  9UL) /* Disable MMU bypass mode (Schizo/Tomatillo) */ | 
|  | 1569 | #define  SCHIZO_PCIDIAG_D_TTO		(1UL <<  8UL) /* Disable TTO errors (Schizo/Tomatillo) */ | 
|  | 1570 | #define  SCHIZO_PCIDIAG_D_RTRYARB	(1UL <<  7UL) /* Disable retry arbitration (Schizo) */ | 
|  | 1571 | #define  SCHIZO_PCIDIAG_D_RETRY		(1UL <<  6UL) /* Disable retry limit (Schizo/Tomatillo) */ | 
|  | 1572 | #define  SCHIZO_PCIDIAG_D_INTSYNC	(1UL <<  5UL) /* Disable interrupt/DMA synch (Schizo/Tomatillo) */ | 
|  | 1573 | #define  SCHIZO_PCIDIAG_I_DMA_PARITY	(1UL <<  3UL) /* Invert DMA parity (Schizo/Tomatillo) */ | 
|  | 1574 | #define  SCHIZO_PCIDIAG_I_PIOD_PARITY	(1UL <<  2UL) /* Invert PIO data parity (Schizo/Tomatillo) */ | 
|  | 1575 | #define  SCHIZO_PCIDIAG_I_PIOA_PARITY	(1UL <<  1UL) /* Invert PIO address parity (Schizo/Tomatillo) */ | 
|  | 1576 |  | 
|  | 1577 | #define TOMATILLO_PCI_IOC_CSR		(0x2248UL) | 
|  | 1578 | #define TOMATILLO_IOC_PART_WPENAB	0x0000000000080000UL | 
|  | 1579 | #define TOMATILLO_IOC_RDMULT_PENAB	0x0000000000040000UL | 
|  | 1580 | #define TOMATILLO_IOC_RDONE_PENAB	0x0000000000020000UL | 
|  | 1581 | #define TOMATILLO_IOC_RDLINE_PENAB	0x0000000000010000UL | 
|  | 1582 | #define TOMATILLO_IOC_RDMULT_PLEN	0x000000000000c000UL | 
|  | 1583 | #define TOMATILLO_IOC_RDMULT_PLEN_SHIFT	14UL | 
|  | 1584 | #define TOMATILLO_IOC_RDONE_PLEN	0x0000000000003000UL | 
|  | 1585 | #define TOMATILLO_IOC_RDONE_PLEN_SHIFT	12UL | 
|  | 1586 | #define TOMATILLO_IOC_RDLINE_PLEN	0x0000000000000c00UL | 
|  | 1587 | #define TOMATILLO_IOC_RDLINE_PLEN_SHIFT	10UL | 
|  | 1588 | #define TOMATILLO_IOC_PREF_OFF		0x00000000000003f8UL | 
|  | 1589 | #define TOMATILLO_IOC_PREF_OFF_SHIFT	3UL | 
|  | 1590 | #define TOMATILLO_IOC_RDMULT_CPENAB	0x0000000000000004UL | 
|  | 1591 | #define TOMATILLO_IOC_RDONE_CPENAB	0x0000000000000002UL | 
|  | 1592 | #define TOMATILLO_IOC_RDLINE_CPENAB	0x0000000000000001UL | 
|  | 1593 |  | 
|  | 1594 | #define TOMATILLO_PCI_IOC_TDIAG		(0x2250UL) | 
|  | 1595 | #define TOMATILLO_PCI_IOC_DDIAG		(0x2290UL) | 
|  | 1596 |  | 
| David S. Miller | 085ae41 | 2005-08-08 13:19:08 -0700 | [diff] [blame] | 1597 | static void schizo_pbm_hw_init(struct pci_pbm_info *pbm) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1598 | { | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1599 | struct property *prop; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1600 | u64 tmp; | 
|  | 1601 |  | 
| David S. Miller | 864ae18 | 2005-07-04 15:58:19 -0700 | [diff] [blame] | 1602 | schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY, 5); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1603 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1604 | tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1605 |  | 
| David S. Miller | 9fba62a | 2005-07-04 14:53:33 -0700 | [diff] [blame] | 1606 | /* Enable arbiter for all PCI slots.  */ | 
|  | 1607 | tmp |= 0xff; | 
|  | 1608 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1609 | if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO && | 
|  | 1610 | pbm->chip_version >= 0x2) | 
|  | 1611 | tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1612 |  | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1613 | prop = of_find_property(pbm->prom_node, "no-bus-parking", NULL); | 
|  | 1614 | if (!prop) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1615 | tmp |= SCHIZO_PCICTRL_PARK; | 
| David S. Miller | 9fba62a | 2005-07-04 14:53:33 -0700 | [diff] [blame] | 1616 | else | 
|  | 1617 | tmp &= ~SCHIZO_PCICTRL_PARK; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1618 |  | 
|  | 1619 | if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO && | 
|  | 1620 | pbm->chip_version <= 0x1) | 
| David S. Miller | 9fba62a | 2005-07-04 14:53:33 -0700 | [diff] [blame] | 1621 | tmp |= SCHIZO_PCICTRL_DTO_INT; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1622 | else | 
| David S. Miller | 9fba62a | 2005-07-04 14:53:33 -0700 | [diff] [blame] | 1623 | tmp &= ~SCHIZO_PCICTRL_DTO_INT; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1624 |  | 
|  | 1625 | if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) | 
|  | 1626 | tmp |= (SCHIZO_PCICTRL_MRM_PREF | | 
|  | 1627 | SCHIZO_PCICTRL_RDO_PREF | | 
|  | 1628 | SCHIZO_PCICTRL_RDL_PREF); | 
|  | 1629 |  | 
|  | 1630 | schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp); | 
|  | 1631 |  | 
|  | 1632 | tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_DIAG); | 
|  | 1633 | tmp &= ~(SCHIZO_PCIDIAG_D_RTRYARB | | 
|  | 1634 | SCHIZO_PCIDIAG_D_RETRY | | 
|  | 1635 | SCHIZO_PCIDIAG_D_INTSYNC); | 
|  | 1636 | schizo_write(pbm->pbm_regs + SCHIZO_PCI_DIAG, tmp); | 
|  | 1637 |  | 
|  | 1638 | if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) { | 
|  | 1639 | /* Clear prefetch lengths to workaround a bug in | 
|  | 1640 | * Jalapeno... | 
|  | 1641 | */ | 
|  | 1642 | tmp = (TOMATILLO_IOC_PART_WPENAB | | 
|  | 1643 | (1 << TOMATILLO_IOC_PREF_OFF_SHIFT) | | 
|  | 1644 | TOMATILLO_IOC_RDMULT_CPENAB | | 
|  | 1645 | TOMATILLO_IOC_RDONE_CPENAB | | 
|  | 1646 | TOMATILLO_IOC_RDLINE_CPENAB); | 
|  | 1647 |  | 
|  | 1648 | schizo_write(pbm->pbm_regs + TOMATILLO_PCI_IOC_CSR, | 
|  | 1649 | tmp); | 
|  | 1650 | } | 
|  | 1651 | } | 
|  | 1652 |  | 
| David S. Miller | 085ae41 | 2005-08-08 13:19:08 -0700 | [diff] [blame] | 1653 | static void schizo_pbm_init(struct pci_controller_info *p, | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1654 | struct device_node *dp, u32 portid, | 
| David S. Miller | 085ae41 | 2005-08-08 13:19:08 -0700 | [diff] [blame] | 1655 | int chip_type) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1656 | { | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1657 | struct linux_prom64_registers *regs; | 
|  | 1658 | struct property *prop; | 
|  | 1659 | unsigned int *busrange; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1660 | struct pci_pbm_info *pbm; | 
|  | 1661 | const char *chipset_name; | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1662 | u32 *ino_bitmap; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1663 | int is_pbm_a; | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1664 | int len; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1665 |  | 
|  | 1666 | switch (chip_type) { | 
|  | 1667 | case PBM_CHIP_TYPE_TOMATILLO: | 
|  | 1668 | chipset_name = "TOMATILLO"; | 
|  | 1669 | break; | 
|  | 1670 |  | 
|  | 1671 | case PBM_CHIP_TYPE_SCHIZO_PLUS: | 
|  | 1672 | chipset_name = "SCHIZO+"; | 
|  | 1673 | break; | 
|  | 1674 |  | 
|  | 1675 | case PBM_CHIP_TYPE_SCHIZO: | 
|  | 1676 | default: | 
|  | 1677 | chipset_name = "SCHIZO"; | 
|  | 1678 | break; | 
|  | 1679 | }; | 
|  | 1680 |  | 
|  | 1681 | /* For SCHIZO, three OBP regs: | 
|  | 1682 | * 1) PBM controller regs | 
|  | 1683 | * 2) Schizo front-end controller regs (same for both PBMs) | 
|  | 1684 | * 3) PBM PCI config space | 
|  | 1685 | * | 
|  | 1686 | * For TOMATILLO, four OBP regs: | 
|  | 1687 | * 1) PBM controller regs | 
|  | 1688 | * 2) Tomatillo front-end controller regs | 
|  | 1689 | * 3) PBM PCI config space | 
|  | 1690 | * 4) Ichip regs | 
|  | 1691 | */ | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1692 | prop = of_find_property(dp, "reg", NULL); | 
|  | 1693 | regs = prop->value; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1694 |  | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1695 | is_pbm_a = ((regs[0].phys_addr & 0x00700000) == 0x00600000); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1696 |  | 
|  | 1697 | if (is_pbm_a) | 
|  | 1698 | pbm = &p->pbm_A; | 
|  | 1699 | else | 
|  | 1700 | pbm = &p->pbm_B; | 
|  | 1701 |  | 
|  | 1702 | pbm->portid = portid; | 
|  | 1703 | pbm->parent = p; | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1704 | pbm->prom_node = dp; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1705 | pbm->pci_first_slot = 1; | 
|  | 1706 |  | 
|  | 1707 | pbm->chip_type = chip_type; | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1708 | pbm->chip_version = 0; | 
|  | 1709 | prop = of_find_property(dp, "version#", NULL); | 
|  | 1710 | if (prop) | 
|  | 1711 | pbm->chip_version = *(int *) prop->value; | 
|  | 1712 | pbm->chip_revision = 0; | 
|  | 1713 | prop = of_find_property(dp, "module-revision#", NULL); | 
|  | 1714 | if (prop) | 
|  | 1715 | pbm->chip_revision = *(int *) prop->value; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1716 |  | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1717 | pbm->pbm_regs = regs[0].phys_addr; | 
|  | 1718 | pbm->controller_regs = regs[1].phys_addr - 0x10000UL; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1719 |  | 
| David S. Miller | bb6743f | 2005-07-04 13:26:04 -0700 | [diff] [blame] | 1720 | if (chip_type == PBM_CHIP_TYPE_TOMATILLO) | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1721 | pbm->sync_reg = regs[3].phys_addr + 0x1a18UL; | 
| David S. Miller | bb6743f | 2005-07-04 13:26:04 -0700 | [diff] [blame] | 1722 |  | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1723 | pbm->name = dp->full_name; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1724 |  | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1725 | printk("%s: %s PCI Bus Module ver[%x:%x]\n", | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1726 | pbm->name, | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1727 | (chip_type == PBM_CHIP_TYPE_TOMATILLO ? | 
|  | 1728 | "TOMATILLO" : "SCHIZO"), | 
|  | 1729 | pbm->chip_version, pbm->chip_revision); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1730 |  | 
|  | 1731 | schizo_pbm_hw_init(pbm); | 
|  | 1732 |  | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1733 | prop = of_find_property(dp, "ranges", &len); | 
|  | 1734 | pbm->pbm_ranges = prop->value; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1735 | pbm->num_pbm_ranges = | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1736 | (len / sizeof(struct linux_prom_pci_ranges)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1737 |  | 
|  | 1738 | schizo_determine_mem_io_space(pbm); | 
|  | 1739 | pbm_register_toplevel_resources(p, pbm); | 
|  | 1740 |  | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1741 | prop = of_find_property(dp, "interrupt-map", &len); | 
|  | 1742 | if (prop) { | 
|  | 1743 | pbm->pbm_intmap = prop->value; | 
|  | 1744 | pbm->num_pbm_intmap = | 
|  | 1745 | (len / sizeof(struct linux_prom_pci_intmap)); | 
|  | 1746 |  | 
|  | 1747 | prop = of_find_property(dp, "interrupt-map-mask", NULL); | 
|  | 1748 | pbm->pbm_intmask = prop->value; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1749 | } else { | 
|  | 1750 | pbm->num_pbm_intmap = 0; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1751 | } | 
|  | 1752 |  | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1753 | prop = of_find_property(dp, "ino-bitmap", NULL); | 
|  | 1754 | ino_bitmap = prop->value; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1755 | pbm->ino_bitmap = (((u64)ino_bitmap[1] << 32UL) | | 
|  | 1756 | ((u64)ino_bitmap[0] <<  0UL)); | 
|  | 1757 |  | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1758 | prop = of_find_property(dp, "bus-range", NULL); | 
|  | 1759 | busrange = prop->value; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1760 | pbm->pci_first_busno = busrange[0]; | 
|  | 1761 | pbm->pci_last_busno = busrange[1]; | 
|  | 1762 |  | 
|  | 1763 | schizo_pbm_iommu_init(pbm); | 
|  | 1764 | schizo_pbm_strbuf_init(pbm); | 
|  | 1765 | } | 
|  | 1766 |  | 
|  | 1767 | static inline int portid_compare(u32 x, u32 y, int chip_type) | 
|  | 1768 | { | 
|  | 1769 | if (chip_type == PBM_CHIP_TYPE_TOMATILLO) { | 
|  | 1770 | if (x == (y ^ 1)) | 
|  | 1771 | return 1; | 
|  | 1772 | return 0; | 
|  | 1773 | } | 
|  | 1774 | return (x == y); | 
|  | 1775 | } | 
|  | 1776 |  | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1777 | static void __schizo_init(struct device_node *dp, char *model_name, int chip_type) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1778 | { | 
|  | 1779 | struct pci_controller_info *p; | 
|  | 1780 | struct pci_iommu *iommu; | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1781 | struct property *prop; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1782 | int is_pbm_a; | 
|  | 1783 | u32 portid; | 
|  | 1784 |  | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1785 | portid = 0xff; | 
|  | 1786 | prop = of_find_property(dp, "portid", NULL); | 
|  | 1787 | if (prop) | 
|  | 1788 | portid = *(u32 *) prop->value; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1789 |  | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1790 | for (p = pci_controller_root; p; p = p->next) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1791 | struct pci_pbm_info *pbm; | 
|  | 1792 |  | 
|  | 1793 | if (p->pbm_A.prom_node && p->pbm_B.prom_node) | 
|  | 1794 | continue; | 
|  | 1795 |  | 
|  | 1796 | pbm = (p->pbm_A.prom_node ? | 
|  | 1797 | &p->pbm_A : | 
|  | 1798 | &p->pbm_B); | 
|  | 1799 |  | 
|  | 1800 | if (portid_compare(pbm->portid, portid, chip_type)) { | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1801 | is_pbm_a = (p->pbm_A.prom_node == NULL); | 
|  | 1802 | schizo_pbm_init(p, dp, portid, chip_type); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1803 | return; | 
|  | 1804 | } | 
|  | 1805 | } | 
|  | 1806 |  | 
| Eric Sesterhenn | 9132983 | 2006-03-06 13:48:40 -0800 | [diff] [blame] | 1807 | p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1808 | if (!p) { | 
|  | 1809 | prom_printf("SCHIZO: Fatal memory allocation error.\n"); | 
|  | 1810 | prom_halt(); | 
|  | 1811 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1812 |  | 
| Eric Sesterhenn | 9132983 | 2006-03-06 13:48:40 -0800 | [diff] [blame] | 1813 | iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1814 | if (!iommu) { | 
|  | 1815 | prom_printf("SCHIZO: Fatal memory allocation error.\n"); | 
|  | 1816 | prom_halt(); | 
|  | 1817 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1818 | p->pbm_A.iommu = iommu; | 
|  | 1819 |  | 
| Eric Sesterhenn | 9132983 | 2006-03-06 13:48:40 -0800 | [diff] [blame] | 1820 | iommu = kzalloc(sizeof(struct pci_iommu), GFP_ATOMIC); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1821 | if (!iommu) { | 
|  | 1822 | prom_printf("SCHIZO: Fatal memory allocation error.\n"); | 
|  | 1823 | prom_halt(); | 
|  | 1824 | } | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1825 | p->pbm_B.iommu = iommu; | 
|  | 1826 |  | 
|  | 1827 | p->next = pci_controller_root; | 
|  | 1828 | pci_controller_root = p; | 
|  | 1829 |  | 
|  | 1830 | p->index = pci_num_controllers++; | 
|  | 1831 | p->pbms_same_domain = 0; | 
|  | 1832 | p->scan_bus = (chip_type == PBM_CHIP_TYPE_TOMATILLO ? | 
|  | 1833 | tomatillo_scan_bus : | 
|  | 1834 | schizo_scan_bus); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1835 | p->base_address_update = schizo_base_address_update; | 
|  | 1836 | p->resource_adjust = schizo_resource_adjust; | 
|  | 1837 | p->pci_ops = &schizo_ops; | 
|  | 1838 |  | 
|  | 1839 | /* Like PSYCHO we have a 2GB aligned area for memory space. */ | 
|  | 1840 | pci_memspace_mask = 0x7fffffffUL; | 
|  | 1841 |  | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1842 | schizo_pbm_init(p, dp, portid, chip_type); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1843 | } | 
|  | 1844 |  | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1845 | void schizo_init(struct device_node *dp, char *model_name) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1846 | { | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1847 | __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1848 | } | 
|  | 1849 |  | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1850 | void schizo_plus_init(struct device_node *dp, char *model_name) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1851 | { | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1852 | __schizo_init(dp, model_name, PBM_CHIP_TYPE_SCHIZO_PLUS); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1853 | } | 
|  | 1854 |  | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1855 | void tomatillo_init(struct device_node *dp, char *model_name) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1856 | { | 
| David S. Miller | e87dc35 | 2006-06-21 18:18:47 -0700 | [diff] [blame] | 1857 | __schizo_init(dp, model_name, PBM_CHIP_TYPE_TOMATILLO); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1858 | } |