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

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