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_AVANTI
 124         register long s0 asm ("9");
 125         register long s1 asm ("10");
 126         register long s2 asm ("11");
 127         register long s3 asm ("12");
 128         register long s4 asm ("13");
 129         register long s5 asm ("14");
 130         asm volatile ("# %0" : "r="(s0));/* SRM X4.2 on Avanti steps on this */
 131         asm volatile ("# %0" : "r="(s1));/* SRM X4.2 on Avanti steps on this */
 132         asm volatile ("# %0" : "r="(s2));/* SRM X4.2 on Avanti steps on this */
 133         asm volatile ("# %0" : "r="(s3));/* SRM X4.2 on Avanti steps on this */
 134         asm volatile ("# %0" : "r="(s4));/* SRM X4.2 on Avanti steps on this */
 135         asm volatile ("# %0" : "r="(s5));/* SRM X4.2 on Avanti steps on this */
 136 #endif
 137 
 138         save_flags(flags);      /* avoid getting hit by machine check */
 139         cli();
 140 
 141         DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1));
 142 
 143         /* reset status register to avoid losing errors: */
 144         stat0 = *((volatile unsigned int *)APECS_IOC_DCSR);
 145         *((volatile unsigned int *)APECS_IOC_DCSR) = stat0;
 146         mb();
 147         DBG(("conf_read: APECS DCSR was 0x%x\n", stat0));
 148         /* if Type1 access, must set HAE #2 */
 149         if (type1) {
 150                 haxr2 = *((unsigned int *)APECS_IOC_HAXR2);
 151                 mb();
 152                 *((unsigned int *)APECS_IOC_HAXR2) = haxr2 | 1;
 153                 DBG(("conf_read: TYPE1 access\n"));
 154         }
 155 
 156         draina();
 157         apecs_mcheck_expected = 1;
 158         apecs_mcheck_taken = 0;
 159         mb();
 160         /* access configuration space: */
 161         value = *((volatile unsigned int *)addr);
 162         mb();
 163         mb();
 164         if (apecs_mcheck_taken) {
 165                 apecs_mcheck_taken = 0;
 166                 value = 0xffffffffU;
 167                 mb();
 168         }
 169         apecs_mcheck_expected = 0;
 170         mb();
 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 #if 1
 178         draina();
 179 
 180         /* now look for any errors */
 181         stat0 = *((unsigned int *)APECS_IOC_DCSR);
 182         DBG(("conf_read: APECS DCSR after read 0x%x\n", stat0));
 183         if (stat0 & 0xffe0U) { /* is any error bit set? */
 184                 /* if not NDEV, print status */
 185                 if (!(stat0 & 0x0800)) {
 186                         printk("apecs.c:conf_read: got stat0=%x\n", stat0);
 187                 }
 188 
 189                 /* reset error status: */
 190                 *((volatile unsigned long *)APECS_IOC_DCSR) = stat0;
 191                 mb();
 192                 wrmces(0x7);                    /* reset machine check */
 193                 value = 0xffffffff;
 194         }
 195 #endif
 196 
 197         /* if Type1 access, must reset HAE #2 so normal IO space ops work */
 198         if (type1) {
 199                 *((unsigned int *)APECS_IOC_HAXR2) = haxr2 & ~1;
 200                 mb();
 201         }
 202         restore_flags(flags);
 203 #ifdef CONFIG_ALPHA_AVANTI
 204         asm volatile ("# %0" :: "r"(s0));/* SRM X4.2 on Avanti steps on this */
 205         asm volatile ("# %0" :: "r"(s1));/* SRM X4.2 on Avanti steps on this */
 206         asm volatile ("# %0" :: "r"(s2));/* SRM X4.2 on Avanti steps on this */
 207         asm volatile ("# %0" :: "r"(s3));/* SRM X4.2 on Avanti steps on this */
 208         asm volatile ("# %0" :: "r"(s4));/* SRM X4.2 on Avanti steps on this */
 209         asm volatile ("# %0" :: "r"(s5));/* SRM X4.2 on Avanti steps on this */
 210 #endif
 211         return value;
 212 }
 213 
 214 
 215 static void conf_write(unsigned long addr, unsigned int value, unsigned char type1)
     /* [previous][next][first][last][top][bottom][index][help] */
 216 {
 217         unsigned long flags;
 218         unsigned int stat0;
 219         unsigned int haxr2 = 0; /* to keep gcc quiet */
 220 
 221         save_flags(flags);      /* avoid getting hit by machine check */
 222         cli();
 223 
 224         /* reset status register to avoid losing errors: */
 225         stat0 = *((volatile unsigned int *)APECS_IOC_DCSR);
 226         *((volatile unsigned int *)APECS_IOC_DCSR) = stat0;
 227         mb();
 228 
 229         /* if Type1 access, must set HAE #2 */
 230         if (type1) {
 231                 haxr2 = *((unsigned int *)APECS_IOC_HAXR2);
 232                 mb();
 233                 *((unsigned int *)APECS_IOC_HAXR2) = haxr2 | 1;
 234         }
 235 
 236         draina();
 237         apecs_mcheck_expected = 1;
 238         mb();
 239         /* access configuration space: */
 240         *((volatile unsigned int *)addr) = value;
 241         mb();
 242         mb();
 243         apecs_mcheck_expected = 0;
 244         mb();
 245         /*
 246          * david.rusling@reo.mts.dec.com.  This code is needed for the
 247          * EB64+ as it does not generate a machine check (why I don't
 248          * know).  When we build kernels for one particular platform
 249          * then we can make this conditional on the type.
 250          */
 251 #if 1
 252         draina();
 253 
 254         /* now look for any errors */
 255         stat0 = *((unsigned int *)APECS_IOC_DCSR);
 256         if (stat0 & 0xffe0U) { /* is any error bit set? */
 257                 /* if not NDEV, print status */
 258                 if (!(stat0 & 0x0800)) {
 259                         printk("apecs.c:conf_write: got stat0=%x\n", stat0);
 260                 }
 261 
 262                 /* reset error status: */
 263                 *((volatile unsigned long *)APECS_IOC_DCSR) = stat0;
 264                 mb();
 265                 wrmces(0x7);                    /* reset machine check */
 266         }
 267 #endif
 268 
 269         /* if Type1 access, must reset HAE #2 so normal IO space ops work */
 270         if (type1) {
 271                 *((unsigned int *)APECS_IOC_HAXR2) = haxr2 & ~1;
 272                 mb();
 273         }
 274         restore_flags(flags);
 275 }
 276 
 277 
 278 int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn,
     /* [previous][next][first][last][top][bottom][index][help] */
 279                               unsigned char where, unsigned char *value)
 280 {
 281         unsigned long addr = APECS_CONF;
 282         unsigned long pci_addr;
 283         unsigned char type1;
 284 
 285         *value = 0xff;
 286 
 287         if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
 288                 return PCIBIOS_SUCCESSFUL;
 289         }
 290 
 291         addr |= (pci_addr << 5) + 0x00;
 292 
 293         *value = conf_read(addr, type1) >> ((where & 3) * 8);
 294 
 295         return PCIBIOS_SUCCESSFUL;
 296 }
 297 
 298 
 299 int pcibios_read_config_word (unsigned char bus, unsigned char device_fn,
     /* [previous][next][first][last][top][bottom][index][help] */
 300                               unsigned char where, unsigned short *value)
 301 {
 302         unsigned long addr = APECS_CONF;
 303         unsigned long pci_addr;
 304         unsigned char type1;
 305 
 306         *value = 0xffff;
 307 
 308         if (where & 0x1) {
 309                 return PCIBIOS_BAD_REGISTER_NUMBER;
 310         }
 311 
 312         if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) {
 313                 return PCIBIOS_SUCCESSFUL;
 314         }
 315 
 316         addr |= (pci_addr << 5) + 0x08;
 317 
 318         *value = conf_read(addr, type1) >> ((where & 3) * 8);
 319         return PCIBIOS_SUCCESSFUL;
 320 }
 321 
 322 
 323 int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
     /* [previous][next][first][last][top][bottom][index][help] */
 324                                unsigned char where, unsigned int *value)
 325 {
 326         unsigned long addr = APECS_CONF;
 327         unsigned long pci_addr;
 328         unsigned char type1;
 329 
 330         *value = 0xffffffff;
 331         if (where & 0x3) {
 332                 return PCIBIOS_BAD_REGISTER_NUMBER;
 333         }
 334 
 335         if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) {
 336                 return PCIBIOS_SUCCESSFUL;
 337         }
 338         addr |= (pci_addr << 5) + 0x18;
 339         *value = conf_read(addr, type1);
 340         return PCIBIOS_SUCCESSFUL;
 341 }
 342 
 343 
 344 int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn,
     /* [previous][next][first][last][top][bottom][index][help] */
 345                                unsigned char where, unsigned char value)
 346 {
 347         unsigned long addr = APECS_CONF;
 348         unsigned long pci_addr;
 349         unsigned char type1;
 350 
 351         if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
 352                 return PCIBIOS_SUCCESSFUL;
 353         }
 354         addr |= (pci_addr << 5) + 0x00;
 355         conf_write(addr, value << ((where & 3) * 8), type1);
 356         return PCIBIOS_SUCCESSFUL;
 357 }
 358 
 359 
 360 int pcibios_write_config_word (unsigned char bus, unsigned char device_fn,
     /* [previous][next][first][last][top][bottom][index][help] */
 361                                unsigned char where, unsigned short value)
 362 {
 363         unsigned long addr = APECS_CONF;
 364         unsigned long pci_addr;
 365         unsigned char type1;
 366 
 367         if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
 368                 return PCIBIOS_SUCCESSFUL;
 369         }
 370         addr |= (pci_addr << 5) + 0x08;
 371         conf_write(addr, value << ((where & 3) * 8), type1);
 372         return PCIBIOS_SUCCESSFUL;
 373 }
 374 
 375 
 376 int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
     /* [previous][next][first][last][top][bottom][index][help] */
 377                                 unsigned char where, unsigned int value)
 378 {
 379         unsigned long addr = APECS_CONF;
 380         unsigned long pci_addr;
 381         unsigned char type1;
 382 
 383         if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
 384                 return PCIBIOS_SUCCESSFUL;
 385         }
 386         addr |= (pci_addr << 5) + 0x18;
 387         conf_write(addr, value << ((where & 3) * 8), type1);
 388         return PCIBIOS_SUCCESSFUL;
 389 }
 390 
 391 
 392 unsigned long apecs_init(unsigned long mem_start, unsigned long mem_end)
     /* [previous][next][first][last][top][bottom][index][help] */
 393 {
 394         /*
 395          * Set up the PCI->physical memory translation windows.
 396          * For now, window 1 is disabled.  In the future, we may
 397          * want to use it to do scatter/gather DMA.  Window 0
 398          * goes at 1 GB and is 1 GB large.
 399          */
 400         *(vuip)APECS_IOC_PB2R  = 0U; /* disable window 2 */
 401 
 402         *(vuip)APECS_IOC_PB1R  = 1U<<19 | (APECS_DMA_WIN_BASE & 0xfff00000U);
 403         *(vuip)APECS_IOC_PM1R  = (APECS_DMA_WIN_SIZE - 1) & 0xfff00000U;
 404         *(vuip)APECS_IOC_TB1R  = 0;
 405 
 406 #ifdef CONFIG_ALPHA_CABRIOLET
 407         /*
 408          * JAE: HACK!!! for now, hardwire if configured...
 409          * davidm: Older miniloader versions don't set the clockfrequency
 410          * right, so hardcode it for now.
 411          */
 412         if (hwrpb->sys_type == ST_DEC_EB64P) {
 413                 hwrpb->sys_type = ST_DEC_EBPC64;
 414         }
 415         if (hwrpb->cycle_freq == 0) {
 416             hwrpb->cycle_freq = 275000000;
 417         }
 418 
 419         /* update checksum: */
 420         {
 421             unsigned long *l, sum;
 422 
 423             sum = 0;
 424             for (l = (unsigned long *) hwrpb; l < (unsigned long *) &hwrpb->chksum; ++l)
 425               sum += *l;
 426             hwrpb->chksum = sum;
 427         }
 428 #endif /* CONFIG_ALPHA_CABRIOLET */
 429         return mem_start;
 430 }
 431 
 432 int apecs_pci_clr_err(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 433 {
 434         apecs_jd = *((unsigned long *)APECS_IOC_DCSR);
 435         if (apecs_jd & 0xffe0L) {
 436                 apecs_jd1 = *((unsigned long *)APECS_IOC_SEAR);
 437                 *((unsigned long *)APECS_IOC_DCSR) = apecs_jd | 0xffe1L;
 438                 apecs_jd = *((unsigned long *)APECS_IOC_DCSR);
 439                 mb();
 440         }
 441         *((unsigned long *)APECS_IOC_TBIA) = APECS_IOC_TBIA;
 442         apecs_jd2 = *((unsigned long *)APECS_IOC_TBIA);
 443         mb();
 444         return 0;
 445 }
 446 
 447 void apecs_machine_check(unsigned long vector, unsigned long la_ptr,
     /* [previous][next][first][last][top][bottom][index][help] */
 448                          struct pt_regs * regs)
 449 {
 450         struct el_common *mchk_header;
 451         struct el_apecs_sysdata_mcheck *mchk_sysdata;
 452 
 453         mchk_header = (struct el_common *)la_ptr;
 454 
 455         mchk_sysdata = 
 456           (struct el_apecs_sysdata_mcheck *)(la_ptr + mchk_header->sys_offset);
 457 
 458         DBG(("apecs_machine_check: vector=0x%lx la_ptr=0x%lx\n", vector, la_ptr));
 459         DBG(("                     pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
 460              regs->pc, mchk_header->size, mchk_header->proc_offset, mchk_header->sys_offset));
 461         DBG(("apecs_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n",
 462              apecs_mcheck_expected, mchk_sysdata->epic_dcsr, mchk_sysdata->epic_pear));
 463 #ifdef DEBUG
 464         {
 465             unsigned long *ptr;
 466             int i;
 467 
 468             ptr = (unsigned long *)la_ptr;
 469             for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
 470                 printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]);
 471             }
 472         }
 473 #endif /* DEBUG */
 474 
 475         /*
 476          * Check if machine check is due to a badaddr() and if so,
 477          * ignore the machine check.
 478          */
 479         if (apecs_mcheck_expected && (mchk_sysdata->epic_dcsr && 0x0c00UL)) {
 480                 apecs_mcheck_expected = 0;
 481                 apecs_mcheck_taken = 1;
 482                 mb();
 483                 mb();
 484                 apecs_pci_clr_err();
 485                 wrmces(0x7);
 486                 mb();
 487                 draina();
 488         }
 489 }
 490 
 491 #endif /* CONFIG_ALPHA_APECS */

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