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