root/arch/alpha/kernel/alcor.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. alcor_init
  11. ALCOR_pci_clr_err
  12. alcor_machine_check

   1 /*
   2  * Code common to all ALCOR chips.
   3  *
   4  * Written by David A Rusling (david.rusling@reo.mts.dec.com).
   5  * December 1995.
   6  *
   7  */
   8 #include <linux/kernel.h>
   9 #include <linux/config.h>
  10 #include <linux/types.h>
  11 #include <linux/bios32.h>
  12 #include <linux/pci.h>
  13 #include <linux/sched.h>
  14 
  15 #include <asm/system.h>
  16 #include <asm/io.h>
  17 #include <asm/hwrpb.h>
  18 #include <asm/ptrace.h>
  19 #include <asm/mmu_context.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_ALCOR
  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 ALCOR_mcheck_expected = 0;
  40 static volatile unsigned int ALCOR_mcheck_taken = 0;
  41 static unsigned long ALCOR_jd, ALCOR_jd1, ALCOR_jd2;
  42 
  43 
  44 /*
  45  * Given a bus, device, and function number, compute resulting
  46  * configuration space address and setup the ALCOR_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  * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|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 cia_cfg = 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 *)ALCOR_IOC_CIA_ERR);
 130         *((volatile unsigned int *)ALCOR_IOC_CIA_ERR) = stat0;
 131         mb();
 132         DBG(("conf_read: ALCOR CIA ERR was 0x%x\n", stat0));
 133         /* if Type1 access, must set CIA CFG */
 134         if (type1) {
 135                 cia_cfg = *((unsigned int *)ALCOR_IOC_CFG);
 136                 mb();
 137                 *((unsigned int *)ALCOR_IOC_CFG) = cia_cfg | 1;
 138                 DBG(("conf_read: TYPE1 access\n"));
 139         }
 140 
 141         draina();
 142         ALCOR_mcheck_expected = 1;
 143         ALCOR_mcheck_taken = 0;
 144         mb();
 145         /* access configuration space: */
 146         value = *((volatile unsigned int *)addr);
 147         mb();
 148         mb();
 149         if (ALCOR_mcheck_taken) {
 150                 ALCOR_mcheck_taken = 0;
 151                 value = 0xffffffffU;
 152                 mb();
 153         }
 154         ALCOR_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 *)ALCOR_IOC_CIA_ERR);
 167         DBG(("conf_read: ALCOR CIA ERR after read 0x%x\n", stat0));
 168         if (stat0 & 0x8280U) { /* is any error bit set? */
 169                 /* if not NDEV, print status */
 170                 if (!(stat0 & 0x0080)) {
 171                         printk("ALCOR.c:conf_read: got stat0=%x\n", stat0);
 172                 }
 173 
 174                 /* reset error status: */
 175                 *((volatile unsigned long *)ALCOR_IOC_CIA_ERR) = stat0;
 176                 mb();
 177                 wrmces(0x7);                    /* reset machine check */
 178                 value = 0xffffffff;
 179         }
 180 #endif
 181 
 182         /* if Type1 access, must reset IOC CFG so normal IO space ops work */
 183         if (type1) {
 184                 *((unsigned int *)ALCOR_IOC_CFG) = cia_cfg & ~1;
 185                 mb();
 186         }
 187 
 188         DBG(("conf_read(): finished\n"));
 189 
 190         restore_flags(flags);
 191         return value;
 192 }
 193 
 194 
 195 static void conf_write(unsigned long addr, unsigned int value, unsigned char type1)
     /* [previous][next][first][last][top][bottom][index][help] */
 196 {
 197         unsigned long flags;
 198         unsigned int stat0;
 199         unsigned int cia_cfg = 0; /* to keep gcc quiet */
 200 
 201         save_flags(flags);      /* avoid getting hit by machine check */
 202         cli();
 203 
 204         /* reset status register to avoid losing errors: */
 205         stat0 = *((volatile unsigned int *)ALCOR_IOC_CIA_ERR);
 206         *((volatile unsigned int *)ALCOR_IOC_CIA_ERR) = stat0;
 207         mb();
 208         DBG(("conf_write: ALCOR CIA ERR was 0x%x\n", stat0));
 209         /* if Type1 access, must set CIA CFG */
 210         if (type1) {
 211                 cia_cfg = *((unsigned int *)ALCOR_IOC_CFG);
 212                 mb();
 213                 *((unsigned int *)ALCOR_IOC_CFG) = cia_cfg | 1;
 214                 DBG(("conf_read: TYPE1 access\n"));
 215         }
 216 
 217         draina();
 218         ALCOR_mcheck_expected = 1;
 219         mb();
 220         /* access configuration space: */
 221         *((volatile unsigned int *)addr) = value;
 222         mb();
 223         mb();
 224         ALCOR_mcheck_expected = 0;
 225         mb();
 226         /*
 227          * david.rusling@reo.mts.dec.com.  This code is needed for the
 228          * EB64+ as it does not generate a machine check (why I don't
 229          * know).  When we build kernels for one particular platform
 230          * then we can make this conditional on the type.
 231          */
 232 #if 1
 233         draina();
 234 
 235         /* now look for any errors */
 236         stat0 = *((unsigned int *)ALCOR_IOC_CIA_ERR);
 237         DBG(("conf_write: ALCOR CIA ERR after write 0x%x\n", stat0));
 238         if (stat0 & 0x8280U) { /* is any error bit set? */
 239                 /* if not NDEV, print status */
 240                 if (!(stat0 & 0x0080)) {
 241                         printk("ALCOR.c:conf_read: got stat0=%x\n", stat0);
 242                 }
 243 
 244                 /* reset error status: */
 245                 *((volatile unsigned long *)ALCOR_IOC_CIA_ERR) = stat0;
 246                 mb();
 247                 wrmces(0x7);                    /* reset machine check */
 248                 value = 0xffffffff;
 249         }
 250 #endif
 251 
 252         /* if Type1 access, must reset IOC CFG so normal IO space ops work */
 253         if (type1) {
 254                 *((unsigned int *)ALCOR_IOC_CFG) = cia_cfg & ~1;
 255                 mb();
 256         }
 257 
 258         DBG(("conf_write(): finished\n"));
 259         restore_flags(flags);
 260 }
 261 
 262 
 263 int pcibios_read_config_byte (unsigned char bus, unsigned char device_fn,
     /* [previous][next][first][last][top][bottom][index][help] */
 264                               unsigned char where, unsigned char *value)
 265 {
 266         unsigned long addr = ALCOR_CONF;
 267         unsigned long pci_addr;
 268         unsigned char type1;
 269 
 270         *value = 0xff;
 271 
 272         if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
 273                 return PCIBIOS_SUCCESSFUL;
 274         }
 275 
 276         addr |= (pci_addr << 5) + 0x00;
 277 
 278         *value = conf_read(addr, type1) >> ((where & 3) * 8);
 279 
 280         return PCIBIOS_SUCCESSFUL;
 281 }
 282 
 283 
 284 int pcibios_read_config_word (unsigned char bus, unsigned char device_fn,
     /* [previous][next][first][last][top][bottom][index][help] */
 285                               unsigned char where, unsigned short *value)
 286 {
 287         unsigned long addr = ALCOR_CONF;
 288         unsigned long pci_addr;
 289         unsigned char type1;
 290 
 291         *value = 0xffff;
 292 
 293         if (where & 0x1) {
 294                 return PCIBIOS_BAD_REGISTER_NUMBER;
 295         }
 296 
 297         if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) {
 298                 return PCIBIOS_SUCCESSFUL;
 299         }
 300 
 301         addr |= (pci_addr << 5) + 0x08;
 302 
 303         *value = conf_read(addr, type1) >> ((where & 3) * 8);
 304         return PCIBIOS_SUCCESSFUL;
 305 }
 306 
 307 
 308 int pcibios_read_config_dword (unsigned char bus, unsigned char device_fn,
     /* [previous][next][first][last][top][bottom][index][help] */
 309                                unsigned char where, unsigned int *value)
 310 {
 311         unsigned long addr = ALCOR_CONF;
 312         unsigned long pci_addr;
 313         unsigned char type1;
 314 
 315         *value = 0xffffffff;
 316         if (where & 0x3) {
 317                 return PCIBIOS_BAD_REGISTER_NUMBER;
 318         }
 319 
 320         if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1)) {
 321                 return PCIBIOS_SUCCESSFUL;
 322         }
 323         addr |= (pci_addr << 5) + 0x18;
 324         *value = conf_read(addr, type1);
 325         return PCIBIOS_SUCCESSFUL;
 326 }
 327 
 328 
 329 int pcibios_write_config_byte (unsigned char bus, unsigned char device_fn,
     /* [previous][next][first][last][top][bottom][index][help] */
 330                                unsigned char where, unsigned char value)
 331 {
 332         unsigned long addr = ALCOR_CONF;
 333         unsigned long pci_addr;
 334         unsigned char type1;
 335 
 336         if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
 337                 return PCIBIOS_SUCCESSFUL;
 338         }
 339         addr |= (pci_addr << 5) + 0x00;
 340         conf_write(addr, value << ((where & 3) * 8), type1);
 341         return PCIBIOS_SUCCESSFUL;
 342 }
 343 
 344 
 345 int pcibios_write_config_word (unsigned char bus, unsigned char device_fn,
     /* [previous][next][first][last][top][bottom][index][help] */
 346                                unsigned char where, unsigned short value)
 347 {
 348         unsigned long addr = ALCOR_CONF;
 349         unsigned long pci_addr;
 350         unsigned char type1;
 351 
 352         if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
 353                 return PCIBIOS_SUCCESSFUL;
 354         }
 355         addr |= (pci_addr << 5) + 0x08;
 356         conf_write(addr, value << ((where & 3) * 8), type1);
 357         return PCIBIOS_SUCCESSFUL;
 358 }
 359 
 360 
 361 int pcibios_write_config_dword (unsigned char bus, unsigned char device_fn,
     /* [previous][next][first][last][top][bottom][index][help] */
 362                                 unsigned char where, unsigned int value)
 363 {
 364         unsigned long addr = ALCOR_CONF;
 365         unsigned long pci_addr;
 366         unsigned char type1;
 367 
 368         if (mk_conf_addr(bus, device_fn, where, &pci_addr, &type1) < 0) {
 369                 return PCIBIOS_SUCCESSFUL;
 370         }
 371         addr |= (pci_addr << 5) + 0x18;
 372         conf_write(addr, value << ((where & 3) * 8), type1);
 373         return PCIBIOS_SUCCESSFUL;
 374 }
 375 
 376 
 377 unsigned long alcor_init(unsigned long mem_start, unsigned long mem_end)
     /* [previous][next][first][last][top][bottom][index][help] */
 378 {
 379         unsigned int cia_err ;
 380 
 381         /* 
 382          * Set up error reporting.
 383          */
 384         cia_err = *(vuip)ALCOR_IOC_CIA_ERR ;
 385         cia_err |= (0x1 << 7) ;   /* master abort */
 386         *(vuip)ALCOR_IOC_CIA_ERR = cia_err ;
 387         mb() ;
 388 
 389         /*
 390          * Set up the PCI->physical memory translation windows.
 391          * For now, windows 1,2 and 3 are disabled.  In the future, we may
 392          * want to use them to do scatter/gather DMA.  Window 0
 393          * goes at 1 GB and is 1 GB large.
 394          */
 395 
 396         *(vuip)ALCOR_IOC_PCI_W0_BASE = 1U | (ALCOR_DMA_WIN_BASE & 0xfff00000U);
 397         *(vuip)ALCOR_IOC_PCI_W0_MASK = (ALCOR_DMA_WIN_SIZE - 1) & 0xfff00000U;
 398         *(vuip)ALCOR_IOC_PCI_T0_BASE = 0;
 399 
 400         *(vuip)ALCOR_IOC_PCI_W1_BASE = 0x0 ;
 401         *(vuip)ALCOR_IOC_PCI_W2_BASE = 0x0 ;
 402         *(vuip)ALCOR_IOC_PCI_W3_BASE = 0x0 ;
 403 
 404         /*
 405          * check ASN in HWRPB for validity, report if bad
 406          */
 407         if (hwrpb->max_asn != MAX_ASN) {
 408                 printk("alcor_init: max ASN from HWRPB is bad (0x%lx)\n",
 409                         hwrpb->max_asn);
 410                 hwrpb->max_asn = MAX_ASN;
 411         }
 412 
 413         return mem_start;
 414 }
 415 
 416 int ALCOR_pci_clr_err(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 417 {
 418         ALCOR_jd = *((unsigned int *)ALCOR_IOC_CIA_ERR);
 419         DBG(("ALCOR_pci_clr_err: ALCOR CIA ERR after read 0x%x\n", ALCOR_jd));
 420         *((unsigned long *)ALCOR_IOC_CIA_ERR) = 0x0080;
 421         mb();
 422         return 0;
 423 }
 424 
 425 void alcor_machine_check(unsigned long vector, unsigned long la_ptr,
     /* [previous][next][first][last][top][bottom][index][help] */
 426                          struct pt_regs * regs)
 427 {
 428 #if 1
 429         printk("ALCOR machine check\n") ;
 430 #else
 431         struct el_common *mchk_header;
 432         struct el_ALCOR_sysdata_mcheck *mchk_sysdata;
 433 
 434         mchk_header = (struct el_common *)la_ptr;
 435 
 436         mchk_sysdata = 
 437           (struct el_ALCOR_sysdata_mcheck *)(la_ptr + mchk_header->sys_offset);
 438 
 439         DBG(("ALCOR_machine_check: vector=0x%lx la_ptr=0x%lx\n", vector, la_ptr));
 440         DBG(("                     pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n",
 441              regs->pc, mchk_header->size, mchk_header->proc_offset, mchk_header->sys_offset));
 442         DBG(("ALCOR_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n",
 443              ALCOR_mcheck_expected, mchk_sysdata->epic_dcsr, mchk_sysdata->epic_pear));
 444 #ifdef DEBUG
 445         {
 446             unsigned long *ptr;
 447             int i;
 448 
 449             ptr = (unsigned long *)la_ptr;
 450             for (i = 0; i < mchk_header->size / sizeof(long); i += 2) {
 451                 printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]);
 452             }
 453         }
 454 #endif /* DEBUG */
 455         /*
 456          * Check if machine check is due to a badaddr() and if so,
 457          * ignore the machine check.
 458          */
 459         if (ALCOR_mcheck_expected && (mchk_sysdata->epic_dcsr && 0x0c00UL)) {
 460                 ALCOR_mcheck_expected = 0;
 461                 ALCOR_mcheck_taken = 1;
 462                 mb();
 463                 mb();
 464                 ALCOR_pci_clr_err();
 465                 wrmces(0x7);
 466                 mb();
 467                 draina();
 468         }
 469 #endif
 470 }
 471 
 472 #endif /* CONFIG_ALPHA_ALCOR */

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