root/arch/alpha/kernel/apecs.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mk_conf_addr
  2. conf_read
  3. conf_write
  4. pcibios_read_config_byte
  5. pcibios_read_config_word
  6. pcibios_read_config_dword
  7. pcibios_write_config_byte
  8. pcibios_write_config_word
  9. pcibios_write_config_dword
  10. apecs_init
  11. apecs_pci_clr_err
  12. apecs_machine_check

   1 /*
   2  * Code common to all APECS chips.
   3  *
   4  * Rewritten for Apecs from the lca.c from:
   5  *
   6  * Written by David Mosberger (davidm@cs.arizona.edu) with some code
   7  * taken from Dave Rusling's (david.rusling@reo.mts.dec.com) 32-bit
   8  * bios code.
   9  */
  10 #include <linux/kernel.h>
  11 #include <linux/config.h>
  12 #include <linux/types.h>
  13 #include <linux/bios32.h>
  14 #include <linux/pci.h>
  15 
  16 #include <asm/system.h>
  17 #include <asm/io.h>
  18 #include <asm/hwrpb.h>
  19 #include <asm/ptrace.h>
  20 
  21 extern struct hwrpb_struct *hwrpb;
  22 extern asmlinkage void wrmces(unsigned long mces);
  23 extern int alpha_sys_type;
  24 /*
  25  * BIOS32-style PCI interface:
  26  */
  27 
  28 #ifdef CONFIG_ALPHA_APECS
  29 
  30 #ifdef DEBUG
  31 # define DBG(args)      printk args
  32 #else
  33 # define DBG(args)
  34 #endif
  35 
  36 #define vulp    volatile unsigned long *
  37 #define vuip    volatile unsigned int  *
  38 
  39 static volatile unsigned int apecs_mcheck_expected = 0;
  40 static volatile unsigned int apecs_mcheck_taken = 0;
  41 static unsigned long apecs_jd, apecs_jd1, apecs_jd2;
  42 
  43 
  44 /*
  45  * Given a bus, device, and function number, compute resulting
  46  * configuration space address and setup the APECS_HAXR2 register
  47  * accordingly.  It is therefore not safe to have concurrent
  48  * invocations to configuration space access routines, but there
  49  * really shouldn't be any need for this.
  50  *
  51  * Type 0:
  52  *
  53  *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
  54  *  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
  55  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  56  * | | | | | | | | | | | | | | | | | | | | | | | |F|F|F|R|R|R|R|R|R|0|0|
  57  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  58  *
  59  *      31:11   Device select bit.
  60  *      10:8    Function number
  61  *       7:2    Register number
  62  *
  63  * Type 1:
  64  *
  65  *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
  66  *  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
  67  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  68  * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
  69  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  70  *
  71  *      31:24   reserved
  72  *      23:16   bus number (8 bits = 128 possible buses)
  73  *      15:11   Device number (5 bits)
  74  *      10:8    function number
  75  *       7:2    register number
  76  *  
  77  * Notes:
  78  *      The function number selects which function of a multi-function device 
  79  *      (e.g., scsi and ethernet).
  80  * 
  81  *      The register selects a DWORD (32 bit) register offset.  Hence it
  82  *      doesn't get shifted by 2 bits as we want to "drop" the bottom two
  83  *      bits.
  84  */
  85 static int mk_conf_addr(unsigned char bus, unsigned char device_fn,
     /* [previous][next][first][last][top][bottom][index][help] */
  86                         unsigned char where, unsigned long *pci_addr,
  87                         unsigned char *type1)
  88 {
  89         unsigned long addr;
  90 
  91         DBG(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, pci_addr=0x%p, type1=0x%p)\n",
  92              bus, device_fn, where, pci_addr, type1));
  93 
  94         if (bus == 0) {
  95                 int device = device_fn >> 3;
  96 
  97                 /* type 0 configuration cycle: */
  98 
  99                 if (device > 20) {
 100                         DBG(("mk_conf_addr: device (%d) > 20, returning -1\n", device));
 101                         return -1;
 102                 }
 103 
 104                 *type1 = 0;
 105                 addr = (device_fn << 8) | (where);
 106         } else {
 107                 /* type 1 configuration cycle: */
 108                 *type1 = 1;
 109                 addr = (bus << 16) | (device_fn << 8) | (where);
 110         }
 111         *pci_addr = addr;
 112         DBG(("mk_conf_addr: returning pci_addr 0x%lx\n", addr));
 113         return 0;
 114 }
 115 
 116 
 117 static unsigned int conf_read(unsigned long addr, unsigned char type1)
     /* [previous][next][first][last][top][bottom][index][help] */
 118 {
 119         unsigned long flags;
 120         unsigned int stat0, value;
 121         unsigned int haxr2 = 0; /* to keep gcc quiet */
 122 
 123 #ifdef CONFIG_ALPHA_SRM
 124         /* some SRMs step on these registers during a machine check: */
 125         register long s0 asm ("9");
 126         register long s1 asm ("10");
 127         register long s2 asm ("11");
 128         register long s3 asm ("12");
 129         register long s4 asm ("13");
 130         register long s5 asm ("14");
 131         asm volatile ("# %0" : "r="(s0));
 132         asm volatile ("# %0" : "r="(s1));
 133         asm volatile ("# %0" : "r="(s2));
 134         asm volatile ("# %0" : "r="(s3));
 135         asm volatile ("# %0" : "r="(s4));
 136         asm volatile ("# %0" : "r="(s5));
 137 #endif
 138 
 139         save_flags(flags);      /* avoid getting hit by machine check */
 140         cli();
 141 
 142         DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
 143 
 144         /* reset status register to avoid losing errors: */
 145         stat0 = *((volatile unsigned int *)APECS_IOC_DCSR);
 146         *((volatile unsigned int *)APECS_IOC_DCSR) = stat0;
 147         mb();
 148         DBG(("conf_read: APECS DCSR was 0x%x\n", stat0));
 149         /* if Type1 access, must set HAE #2 */
 150         if (type1) {
 151                 haxr2 = *((unsigned int *)APECS_IOC_HAXR2);
 152                 mb();
 153                 *((unsigned int *)APECS_IOC_HAXR2) = haxr2 | 1;
 154                 DBG(("conf_read: TYPE1 access\n"));
 155         }
 156 
 157         draina();
 158         apecs_mcheck_expected = 1;
 159         apecs_mcheck_taken = 0;
 160         mb();
 161         /* access configuration space: */
 162         value = *((volatile unsigned int *)addr);
 163         mb();
 164         mb();
 165         if (apecs_mcheck_taken) {
 166                 apecs_mcheck_taken = 0;
 167                 value = 0xffffffffU;
 168                 mb();
 169         }
 170         apecs_mcheck_expected = 0;
 171         mb();
 172         /*
 173          * david.rusling@reo.mts.dec.com.  This code is needed for the
 174          * EB64+ as it does not generate a machine check (why I don't
 175          * know).  When we build kernels for one particular platform
 176          * then we can make this conditional on the type.
 177          */
 178 #if 1
 179         draina();
 180 
 181         /* now look for any errors */
 182         stat0 = *((unsigned int *)APECS_IOC_DCSR);
 183         DBG(("conf_read: APECS DCSR after read 0x%x\n", stat0));
 184         if (stat0 & 0xffe0U) { /* is any error bit set? */
 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                 *((volatile unsigned long *)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                 *((unsigned int *)APECS_IOC_HAXR2) = haxr2 & ~1;
 201                 mb();
 202         }
 203         restore_flags(flags);
 204 #ifdef CONFIG_ALPHA_SRM
 205         /* some SRMs step on these registers during a machine check: */
 206         asm volatile ("# %0" :: "r"(s0));
 207         asm volatile ("# %0" :: "r"(s1));
 208         asm volatile ("# %0" :: "r"(s2));
 209         asm volatile ("# %0" :: "r"(s3));
 210         asm volatile ("# %0" :: "r"(s4));
 211         asm volatile ("# %0" :: "r"(s5));
 212 #endif
 213         return value;
 214 }
 215 
 216 
 217 static void conf_write(unsigned long addr, unsigned int value, unsigned char type1)
     /* [previous][next][first][last][top][bottom][index][help] */
 218 {
 219         unsigned long flags;
 220         unsigned int stat0;
 221         unsigned int haxr2 = 0; /* to keep gcc quiet */
 222 
 223         save_flags(flags);      /* avoid getting hit by machine check */
 224         cli();
 225 
 226         /* reset status register to avoid losing errors: */
 227         stat0 = *((volatile unsigned int *)APECS_IOC_DCSR);
 228         *((volatile unsigned int *)APECS_IOC_DCSR) = stat0;
 229         mb();
 230 
 231         /* if Type1 access, must set HAE #2 */
 232         if (type1) {
 233                 haxr2 = *((unsigned int *)APECS_IOC_HAXR2);
 234                 mb();
 235                 *((unsigned int *)APECS_IOC_HAXR2) = haxr2 | 1;
 236         }
 237 
 238         draina();
 239         apecs_mcheck_expected = 1;
 240         mb();
 241         /* access configuration space: */
 242         *((volatile unsigned int *)addr) = value;
 243         mb();
 244         mb();
 245         apecs_mcheck_expected = 0;
 246         mb();
 247         /*
 248          * david.rusling@reo.mts.dec.com.  This code is needed for the
 249          * EB64+ as it does not generate a machine check (why I don't
 250          * know).  When we build kernels for one particular platform
 251          * then we can make this conditional on the type.
 252          */
 253 #if 1
 254         draina();
 255 
 256         /* now look for any errors */
 257         stat0 = *((unsigned int *)APECS_IOC_DCSR);
 258         if (stat0 & 0xffe0U) { /* is any error bit set? */
 259                 /* if not NDEV, print status */
 260                 if (!(stat0 & 0x0800)) {
 261                         printk("apecs.c:conf_write: got stat0=%x\n", stat0);
 262                 }
 263 
 264                 /* reset error status: */
 265                 *((volatile unsigned long *)APECS_IOC_DCSR) = stat0;
 266                 mb();
 267                 wrmces(0x7);                    /* reset machine check */
 268         }
 269 #endif
 270 
 271         /* if Type1 access, must reset HAE #2 so normal IO space ops work */
 272         if (type1) {
 273                 *((unsigned int *)APECS_IOC_HAXR2) = haxr2 & ~1;
 274                 mb();
 275         }
 276         restore_flags(flags);
 277 }
 278 
 279 
 280 int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn,
     /* [previous][next][first][last][top][bottom][index][help] */
 281                               unsigned char where, unsigned char *value)
 282 {
 283         unsigned long addr = APECS_CONF;
 284         unsigned long pci_addr;
 285         unsigned char type1;
 286 
 287         *value = 0xff;
 288 
 289         if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
 290                 return PCIBIOS_SUCCESSFUL;
 291         }
 292 
 293         addr |= (pci_addr << 5) + 0x00;
 294 
 295         *value = conf_read(addr, type1) >> ((where & 3) * 8);
 296 
 297         return PCIBIOS_SUCCESSFUL;
 298 }
 299 
 300 
 301 int pcibios_read_config_word (unsigned char bus, unsigned char device_fn,
     /* [previous][next][first][last][top][bottom][index][help] */
 302                               unsigned char where, unsigned short *value)
 303 {
 304         unsigned long addr = APECS_CONF;
 305         unsigned long pci_addr;
 306         unsigned char type1;
 307 
 308         *value = 0xffff;
 309 
 310         if (where & 0x1) {
 311                 return PCIBIOS_BAD_REGISTER_NUMBER;
 312         }
 313 
 314         if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) {
 315                 return PCIBIOS_SUCCESSFUL;
 316         }
 317 
 318         addr |= (pci_addr << 5) + 0x08;
 319 
 320         *value = conf_read(addr, type1) >> ((where & 3) * 8);
 321         return PCIBIOS_SUCCESSFUL;
 322 }
 323 
 324 
 325 int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
     /* [previous][next][first][last][top][bottom][index][help] */
 326                                unsigned char where, unsigned int *value)
 327 {
 328         unsigned long addr = APECS_CONF;
 329         unsigned long pci_addr;
 330         unsigned char type1;
 331 
 332         *value = 0xffffffff;
 333         if (where & 0x3) {
 334                 return PCIBIOS_BAD_REGISTER_NUMBER;
 335         }
 336 
 337         if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) {
 338                 return PCIBIOS_SUCCESSFUL;
 339         }
 340         addr |= (pci_addr << 5) + 0x18;
 341         *value = conf_read(addr, type1);
 342         return PCIBIOS_SUCCESSFUL;
 343 }
 344 
 345 
 346 int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn,
     /* [previous][next][first][last][top][bottom][index][help] */
 347                                unsigned char where, unsigned char value)
 348 {
 349         unsigned long addr = APECS_CONF;
 350         unsigned long pci_addr;
 351         unsigned char type1;
 352 
 353         if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
 354                 return PCIBIOS_SUCCESSFUL;
 355         }
 356         addr |= (pci_addr << 5) + 0x00;
 357         conf_write(addr, value << ((where & 3) * 8), type1);
 358         return PCIBIOS_SUCCESSFUL;
 359 }
 360 
 361 
 362 int pcibios_write_config_word (unsigned char bus, unsigned char device_fn,
     /* [previous][next][first][last][top][bottom][index][help] */
 363                                unsigned char where, unsigned short value)
 364 {
 365         unsigned long addr = APECS_CONF;
 366         unsigned long pci_addr;
 367         unsigned char type1;
 368 
 369         if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
 370                 return PCIBIOS_SUCCESSFUL;
 371         }
 372         addr |= (pci_addr << 5) + 0x08;
 373         conf_write(addr, value << ((where & 3) * 8), type1);
 374         return PCIBIOS_SUCCESSFUL;
 375 }
 376 
 377 
 378 int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
     /* [previous][next][first][last][top][bottom][index][help] */
 379                                 unsigned char where, unsigned int value)
 380 {
 381         unsigned long addr = APECS_CONF;
 382         unsigned long pci_addr;
 383         unsigned char type1;
 384 
 385         if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
 386                 return PCIBIOS_SUCCESSFUL;
 387         }
 388         addr |= (pci_addr << 5) + 0x18;
 389         conf_write(addr, value << ((where & 3) * 8), type1);
 390         return PCIBIOS_SUCCESSFUL;
 391 }
 392 
 393 
 394 unsigned long apecs_init(unsigned long mem_start, unsigned long mem_end)
     /* [previous][next][first][last][top][bottom][index][help] */
 395 {
 396 
 397 #ifdef CONFIG_ALPHA_XL
 398         /*
 399          * Set up the PCI->physical memory translation windows.
 400          * For the XL we *must* use both windows, in order to
 401          * maximize the amount of physical memory that can be used
 402          * to DMA from the ISA bus, and still allow PCI bus devices
 403          * access to all of host memory.
 404          *
 405          * see <asm/apecs.h> for window bases and sizes.
 406          *
 407          * this restriction due to the true XL motherboards' 82379AB SIO
 408          * PCI<->ISA bridge chip which passes only 27 bits of address...
 409          */
 410 
 411         *(vuip)APECS_IOC_PB1R = 1U<<19 | (APECS_XL_DMA_WIN1_BASE & 0xfff00000U);
 412         *(vuip)APECS_IOC_PM1R = (APECS_XL_DMA_WIN1_SIZE - 1) & 0xfff00000U;
 413         *(vuip)APECS_IOC_TB1R = 0;
 414 
 415         *(vuip)APECS_IOC_PB2R = 1U<<19 | (APECS_XL_DMA_WIN2_BASE & 0xfff00000U);
 416         *(vuip)APECS_IOC_PM2R = (APECS_XL_DMA_WIN2_SIZE - 1) & 0xfff00000U;
 417         *(vuip)APECS_IOC_TB2R = 0;
 418 
 419 #else  /* CONFIG_ALPHA_XL */
 420         /*
 421          * Set up the PCI->physical memory translation windows.
 422          * For now, window 2 is disabled.  In the future, we may
 423          * want to use it to do scatter/gather DMA.  Window 1
 424          * goes at 1 GB and is 1 GB large.
 425          */
 426         *(vuip)APECS_IOC_PB2R  = 0U; /* disable window 2 */
 427 
 428         *(vuip)APECS_IOC_PB1R  = 1U<<19 | (APECS_DMA_WIN_BASE & 0xfff00000U);
 429         *(vuip)APECS_IOC_PM1R  = (APECS_DMA_WIN_SIZE - 1) & 0xfff00000U;
 430         *(vuip)APECS_IOC_TB1R  = 0;
 431 #endif /* CONFIG_ALPHA_XL */
 432 
 433 #ifdef CONFIG_ALPHA_CABRIOLET
 434         /*
 435          * JAE: HACK!!! for now, hardwire if configured...
 436          * davidm: Older miniloader versions don't set the clockfrequency
 437          * right, so hardcode it for now.
 438          */
 439         if (hwrpb->sys_type == ST_DEC_EB64P) {
 440                 hwrpb->sys_type = ST_DEC_EBPC64;
 441         }
 442         if (hwrpb->cycle_freq == 0) {
 443             hwrpb->cycle_freq = 275000000;
 444         }
 445 
 446         /* update checksum: */
 447         {
 448             unsigned long *l, sum;
 449 
 450             sum = 0;
 451             for (l = (unsigned long *) hwrpb; l < (unsigned long *) &hwrpb->chksum; ++l)
 452               sum += *l;
 453             hwrpb->chksum = sum;
 454         }
 455 #endif /* CONFIG_ALPHA_CABRIOLET */
 456         return mem_start;
 457 }
 458 
 459 int apecs_pci_clr_err(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 460 {
 461         apecs_jd = *((unsigned long *)APECS_IOC_DCSR);
 462         if (apecs_jd & 0xffe0L) {
 463                 apecs_jd1 = *((unsigned long *)APECS_IOC_SEAR);
 464                 *((unsigned long *)APECS_IOC_DCSR) = apecs_jd | 0xffe1L;
 465                 apecs_jd = *((unsigned long *)APECS_IOC_DCSR);
 466                 mb();
 467         }
 468         *((unsigned long *)APECS_IOC_TBIA) = APECS_IOC_TBIA;
 469         apecs_jd2 = *((unsigned long *)APECS_IOC_TBIA);
 470         mb();
 471         return 0;
 472 }
 473 
 474 void apecs_machine_check(unsigned long vector, unsigned long la_ptr,
     /* [previous][next][first][last][top][bottom][index][help] */
 475                          struct pt_regs * regs)
 476 {
 477         struct el_common *mchk_header;
 478         struct el_apecs_sysdata_mcheck *mchk_sysdata;
 479 
 480         mchk_header = (struct el_common *)la_ptr;
 481 
 482         mchk_sysdata = 
 483           (struct el_apecs_sysdata_mcheck *)(la_ptr + mchk_header->sys_offset);
 484 
 485         DBG(("apecs_machine_check: vector=0x%lx la_ptr=0x%lx\n", vector, la_ptr));
 486         DBG(("                     pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
 487              regs->pc, mchk_header->size, mchk_header->proc_offset, mchk_header->sys_offset));
 488         DBG(("apecs_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n",
 489              apecs_mcheck_expected, mchk_sysdata->epic_dcsr, mchk_sysdata->epic_pear));
 490 #ifdef DEBUG
 491         {
 492             unsigned long *ptr;
 493             int i;
 494 
 495             ptr = (unsigned long *)la_ptr;
 496             for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
 497                 printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]);
 498             }
 499         }
 500 #endif /* DEBUG */
 501 
 502         /*
 503          * Check if machine check is due to a badaddr() and if so,
 504          * ignore the machine check.
 505          */
 506         if (apecs_mcheck_expected && (mchk_sysdata->epic_dcsr && 0x0c00UL)) {
 507                 apecs_mcheck_expected = 0;
 508                 apecs_mcheck_taken = 1;
 509                 mb();
 510                 mb();
 511                 apecs_pci_clr_err();
 512                 wrmces(0x7);
 513                 mb();
 514                 draina();
 515         }
 516 }
 517 
 518 #endif /* CONFIG_ALPHA_APECS */

/* [previous][next][first][last][top][bottom][index][help] */