core_apecs.c (10258B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * linux/arch/alpha/kernel/core_apecs.c 4 * 5 * Rewritten for Apecs from the lca.c from: 6 * 7 * Written by David Mosberger (davidm@cs.arizona.edu) with some code 8 * taken from Dave Rusling's (david.rusling@reo.mts.dec.com) 32-bit 9 * bios code. 10 * 11 * Code common to all APECS core logic chips. 12 */ 13 14#define __EXTERN_INLINE inline 15#include <asm/io.h> 16#include <asm/core_apecs.h> 17#undef __EXTERN_INLINE 18 19#include <linux/types.h> 20#include <linux/pci.h> 21#include <linux/init.h> 22 23#include <asm/ptrace.h> 24#include <asm/smp.h> 25#include <asm/mce.h> 26 27#include "proto.h" 28#include "pci_impl.h" 29 30/* 31 * NOTE: Herein lie back-to-back mb instructions. They are magic. 32 * One plausible explanation is that the i/o controller does not properly 33 * handle the system transaction. Another involves timing. Ho hum. 34 */ 35 36/* 37 * BIOS32-style PCI interface: 38 */ 39 40#define DEBUG_CONFIG 0 41 42#if DEBUG_CONFIG 43# define DBGC(args) printk args 44#else 45# define DBGC(args) 46#endif 47 48#define vuip volatile unsigned int * 49 50/* 51 * Given a bus, device, and function number, compute resulting 52 * configuration space address and setup the APECS_HAXR2 register 53 * accordingly. It is therefore not safe to have concurrent 54 * invocations to configuration space access routines, but there 55 * really shouldn't be any need for this. 56 * 57 * Type 0: 58 * 59 * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 60 * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 61 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 62 * | | | | | | | | | | | | | | | | | | | | | | | |F|F|F|R|R|R|R|R|R|0|0| 63 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 64 * 65 * 31:11 Device select bit. 66 * 10:8 Function number 67 * 7:2 Register number 68 * 69 * Type 1: 70 * 71 * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 72 * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0 73 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 74 * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1| 75 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 76 * 77 * 31:24 reserved 78 * 23:16 bus number (8 bits = 128 possible buses) 79 * 15:11 Device number (5 bits) 80 * 10:8 function number 81 * 7:2 register number 82 * 83 * Notes: 84 * The function number selects which function of a multi-function device 85 * (e.g., SCSI and Ethernet). 86 * 87 * The register selects a DWORD (32 bit) register offset. Hence it 88 * doesn't get shifted by 2 bits as we want to "drop" the bottom two 89 * bits. 90 */ 91 92static int 93mk_conf_addr(struct pci_bus *pbus, unsigned int device_fn, int where, 94 unsigned long *pci_addr, unsigned char *type1) 95{ 96 unsigned long addr; 97 u8 bus = pbus->number; 98 99 DBGC(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x," 100 " pci_addr=0x%p, type1=0x%p)\n", 101 bus, device_fn, where, pci_addr, type1)); 102 103 if (bus == 0) { 104 int device = device_fn >> 3; 105 106 /* type 0 configuration cycle: */ 107 108 if (device > 20) { 109 DBGC(("mk_conf_addr: device (%d) > 20, returning -1\n", 110 device)); 111 return -1; 112 } 113 114 *type1 = 0; 115 addr = (device_fn << 8) | (where); 116 } else { 117 /* type 1 configuration cycle: */ 118 *type1 = 1; 119 addr = (bus << 16) | (device_fn << 8) | (where); 120 } 121 *pci_addr = addr; 122 DBGC(("mk_conf_addr: returning pci_addr 0x%lx\n", addr)); 123 return 0; 124} 125 126static unsigned int 127conf_read(unsigned long addr, unsigned char type1) 128{ 129 unsigned long flags; 130 unsigned int stat0, value; 131 unsigned int haxr2 = 0; 132 133 local_irq_save(flags); /* avoid getting hit by machine check */ 134 135 DBGC(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1)); 136 137 /* Reset status register to avoid losing errors. */ 138 stat0 = *(vuip)APECS_IOC_DCSR; 139 *(vuip)APECS_IOC_DCSR = stat0; 140 mb(); 141 DBGC(("conf_read: APECS DCSR was 0x%x\n", stat0)); 142 143 /* If Type1 access, must set HAE #2. */ 144 if (type1) { 145 haxr2 = *(vuip)APECS_IOC_HAXR2; 146 mb(); 147 *(vuip)APECS_IOC_HAXR2 = haxr2 | 1; 148 DBGC(("conf_read: TYPE1 access\n")); 149 } 150 151 draina(); 152 mcheck_expected(0) = 1; 153 mcheck_taken(0) = 0; 154 mb(); 155 156 /* Access configuration space. */ 157 158 /* Some SRMs step on these registers during a machine check. */ 159 asm volatile("ldl %0,%1; mb; mb" : "=r"(value) : "m"(*(vuip)addr) 160 : "$9", "$10", "$11", "$12", "$13", "$14", "memory"); 161 162 if (mcheck_taken(0)) { 163 mcheck_taken(0) = 0; 164 value = 0xffffffffU; 165 mb(); 166 } 167 mcheck_expected(0) = 0; 168 mb(); 169 170#if 1 171 /* 172 * david.rusling@reo.mts.dec.com. This code is needed for the 173 * EB64+ as it does not generate a machine check (why I don't 174 * know). When we build kernels for one particular platform 175 * then we can make this conditional on the type. 176 */ 177 draina(); 178 179 /* Now look for any errors. */ 180 stat0 = *(vuip)APECS_IOC_DCSR; 181 DBGC(("conf_read: APECS DCSR after read 0x%x\n", stat0)); 182 183 /* Is any error bit set? */ 184 if (stat0 & 0xffe0U) { 185 /* If not NDEV, print status. */ 186 if (!(stat0 & 0x0800)) { 187 printk("apecs.c:conf_read: got stat0=%x\n", stat0); 188 } 189 190 /* Reset error status. */ 191 *(vuip)APECS_IOC_DCSR = stat0; 192 mb(); 193 wrmces(0x7); /* reset machine check */ 194 value = 0xffffffff; 195 } 196#endif 197 198 /* If Type1 access, must reset HAE #2 so normal IO space ops work. */ 199 if (type1) { 200 *(vuip)APECS_IOC_HAXR2 = haxr2 & ~1; 201 mb(); 202 } 203 local_irq_restore(flags); 204 205 return value; 206} 207 208static void 209conf_write(unsigned long addr, unsigned int value, unsigned char type1) 210{ 211 unsigned long flags; 212 unsigned int stat0; 213 unsigned int haxr2 = 0; 214 215 local_irq_save(flags); /* avoid getting hit by machine check */ 216 217 /* Reset status register to avoid losing errors. */ 218 stat0 = *(vuip)APECS_IOC_DCSR; 219 *(vuip)APECS_IOC_DCSR = stat0; 220 mb(); 221 222 /* If Type1 access, must set HAE #2. */ 223 if (type1) { 224 haxr2 = *(vuip)APECS_IOC_HAXR2; 225 mb(); 226 *(vuip)APECS_IOC_HAXR2 = haxr2 | 1; 227 } 228 229 draina(); 230 mcheck_expected(0) = 1; 231 mb(); 232 233 /* Access configuration space. */ 234 *(vuip)addr = value; 235 mb(); 236 mb(); /* magic */ 237 mcheck_expected(0) = 0; 238 mb(); 239 240#if 1 241 /* 242 * david.rusling@reo.mts.dec.com. This code is needed for the 243 * EB64+ as it does not generate a machine check (why I don't 244 * know). When we build kernels for one particular platform 245 * then we can make this conditional on the type. 246 */ 247 draina(); 248 249 /* Now look for any errors. */ 250 stat0 = *(vuip)APECS_IOC_DCSR; 251 252 /* Is any error bit set? */ 253 if (stat0 & 0xffe0U) { 254 /* If not NDEV, print status. */ 255 if (!(stat0 & 0x0800)) { 256 printk("apecs.c:conf_write: got stat0=%x\n", stat0); 257 } 258 259 /* Reset error status. */ 260 *(vuip)APECS_IOC_DCSR = stat0; 261 mb(); 262 wrmces(0x7); /* reset machine check */ 263 } 264#endif 265 266 /* If Type1 access, must reset HAE #2 so normal IO space ops work. */ 267 if (type1) { 268 *(vuip)APECS_IOC_HAXR2 = haxr2 & ~1; 269 mb(); 270 } 271 local_irq_restore(flags); 272} 273 274static int 275apecs_read_config(struct pci_bus *bus, unsigned int devfn, int where, 276 int size, u32 *value) 277{ 278 unsigned long addr, pci_addr; 279 unsigned char type1; 280 long mask; 281 int shift; 282 283 if (mk_conf_addr(bus, devfn, where, &pci_addr, &type1)) 284 return PCIBIOS_DEVICE_NOT_FOUND; 285 286 mask = (size - 1) * 8; 287 shift = (where & 3) * 8; 288 addr = (pci_addr << 5) + mask + APECS_CONF; 289 *value = conf_read(addr, type1) >> (shift); 290 return PCIBIOS_SUCCESSFUL; 291} 292 293static int 294apecs_write_config(struct pci_bus *bus, unsigned int devfn, int where, 295 int size, u32 value) 296{ 297 unsigned long addr, pci_addr; 298 unsigned char type1; 299 long mask; 300 301 if (mk_conf_addr(bus, devfn, where, &pci_addr, &type1)) 302 return PCIBIOS_DEVICE_NOT_FOUND; 303 304 mask = (size - 1) * 8; 305 addr = (pci_addr << 5) + mask + APECS_CONF; 306 conf_write(addr, value << ((where & 3) * 8), type1); 307 return PCIBIOS_SUCCESSFUL; 308} 309 310struct pci_ops apecs_pci_ops = 311{ 312 .read = apecs_read_config, 313 .write = apecs_write_config, 314}; 315 316void 317apecs_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end) 318{ 319 wmb(); 320 *(vip)APECS_IOC_TBIA = 0; 321 mb(); 322} 323 324void __init 325apecs_init_arch(void) 326{ 327 struct pci_controller *hose; 328 329 /* 330 * Create our single hose. 331 */ 332 333 pci_isa_hose = hose = alloc_pci_controller(); 334 hose->io_space = &ioport_resource; 335 hose->mem_space = &iomem_resource; 336 hose->index = 0; 337 338 hose->sparse_mem_base = APECS_SPARSE_MEM - IDENT_ADDR; 339 hose->dense_mem_base = APECS_DENSE_MEM - IDENT_ADDR; 340 hose->sparse_io_base = APECS_IO - IDENT_ADDR; 341 hose->dense_io_base = 0; 342 343 /* 344 * Set up the PCI to main memory translation windows. 345 * 346 * Window 1 is direct access 1GB at 1GB 347 * Window 2 is scatter-gather 8MB at 8MB (for isa) 348 */ 349 hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 350 SMP_CACHE_BYTES); 351 hose->sg_pci = NULL; 352 __direct_map_base = 0x40000000; 353 __direct_map_size = 0x40000000; 354 355 *(vuip)APECS_IOC_PB1R = __direct_map_base | 0x00080000; 356 *(vuip)APECS_IOC_PM1R = (__direct_map_size - 1) & 0xfff00000U; 357 *(vuip)APECS_IOC_TB1R = 0; 358 359 *(vuip)APECS_IOC_PB2R = hose->sg_isa->dma_base | 0x000c0000; 360 *(vuip)APECS_IOC_PM2R = (hose->sg_isa->size - 1) & 0xfff00000; 361 *(vuip)APECS_IOC_TB2R = virt_to_phys(hose->sg_isa->ptes) >> 1; 362 363 apecs_pci_tbi(hose, 0, -1); 364 365 /* 366 * Finally, clear the HAXR2 register, which gets used 367 * for PCI Config Space accesses. That is the way 368 * we want to use it, and we do not want to depend on 369 * what ARC or SRM might have left behind... 370 */ 371 *(vuip)APECS_IOC_HAXR2 = 0; 372 mb(); 373} 374 375void 376apecs_pci_clr_err(void) 377{ 378 unsigned int jd; 379 380 jd = *(vuip)APECS_IOC_DCSR; 381 if (jd & 0xffe0L) { 382 *(vuip)APECS_IOC_SEAR; 383 *(vuip)APECS_IOC_DCSR = jd | 0xffe1L; 384 mb(); 385 *(vuip)APECS_IOC_DCSR; 386 } 387 *(vuip)APECS_IOC_TBIA = (unsigned int)APECS_IOC_TBIA; 388 mb(); 389 *(vuip)APECS_IOC_TBIA; 390} 391 392void 393apecs_machine_check(unsigned long vector, unsigned long la_ptr) 394{ 395 struct el_common *mchk_header; 396 struct el_apecs_procdata *mchk_procdata; 397 struct el_apecs_sysdata_mcheck *mchk_sysdata; 398 399 mchk_header = (struct el_common *)la_ptr; 400 401 mchk_procdata = (struct el_apecs_procdata *) 402 (la_ptr + mchk_header->proc_offset 403 - sizeof(mchk_procdata->paltemp)); 404 405 mchk_sysdata = (struct el_apecs_sysdata_mcheck *) 406 (la_ptr + mchk_header->sys_offset); 407 408 409 /* Clear the error before any reporting. */ 410 mb(); 411 mb(); /* magic */ 412 draina(); 413 apecs_pci_clr_err(); 414 wrmces(0x7); /* reset machine check pending flag */ 415 mb(); 416 417 process_mcheck_info(vector, la_ptr, "APECS", 418 (mcheck_expected(0) 419 && (mchk_sysdata->epic_dcsr & 0x0c00UL))); 420}