root/arch/alpha/kernel/sys_marvel.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. io7_device_interrupt
  2. io7_get_irq_ctl
  3. io7_enable_irq
  4. io7_disable_irq
  5. marvel_irq_noop
  6. io7_redirect_irq
  7. io7_redirect_one_lsi
  8. io7_redirect_one_msi
  9. init_one_io7_lsi
  10. init_one_io7_msi
  11. init_io7_irqs
  12. marvel_init_irq
  13. marvel_map_irq
  14. marvel_init_pci
  15. marvel_init_rtc
  16. marvel_smp_callin

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * linux/arch/alpha/kernel/sys_marvel.c
   4  *
   5  * Marvel / IO7 support
   6  */
   7 
   8 #include <linux/kernel.h>
   9 #include <linux/types.h>
  10 #include <linux/mm.h>
  11 #include <linux/sched.h>
  12 #include <linux/pci.h>
  13 #include <linux/init.h>
  14 #include <linux/bitops.h>
  15 
  16 #include <asm/ptrace.h>
  17 #include <asm/dma.h>
  18 #include <asm/irq.h>
  19 #include <asm/mmu_context.h>
  20 #include <asm/io.h>
  21 #include <asm/pgtable.h>
  22 #include <asm/core_marvel.h>
  23 #include <asm/hwrpb.h>
  24 #include <asm/tlbflush.h>
  25 #include <asm/vga.h>
  26 
  27 #include "proto.h"
  28 #include "err_impl.h"
  29 #include "irq_impl.h"
  30 #include "pci_impl.h"
  31 #include "machvec_impl.h"
  32 
  33 #if NR_IRQS < MARVEL_NR_IRQS
  34 # error NR_IRQS < MARVEL_NR_IRQS !!!
  35 #endif
  36 
  37 
  38 /*
  39  * Interrupt handling.
  40  */
  41 static void 
  42 io7_device_interrupt(unsigned long vector)
  43 {
  44         unsigned int pid;
  45         unsigned int irq;
  46 
  47         /*
  48          * Vector is 0x800 + (interrupt)
  49          *
  50          * where (interrupt) is:
  51          *
  52          *      ...16|15 14|13     4|3 0
  53          *      -----+-----+--------+---
  54          *        PE |  0  |   irq  | 0
  55          *
  56          * where (irq) is 
  57          *
  58          *       0x0800 - 0x0ff0         - 0x0800 + (LSI id << 4)
  59          *       0x1000 - 0x2ff0         - 0x1000 + (MSI_DAT<8:0> << 4)
  60          */
  61         pid = vector >> 16;
  62         irq = ((vector & 0xffff) - 0x800) >> 4;
  63 
  64         irq += 16;                              /* offset for legacy */
  65         irq &= MARVEL_IRQ_VEC_IRQ_MASK;         /* not too many bits */
  66         irq |= pid << MARVEL_IRQ_VEC_PE_SHIFT;  /* merge the pid     */
  67 
  68         handle_irq(irq);
  69 }
  70 
  71 static volatile unsigned long *
  72 io7_get_irq_ctl(unsigned int irq, struct io7 **pio7)
  73 {
  74         volatile unsigned long *ctl;
  75         unsigned int pid;
  76         struct io7 *io7;
  77 
  78         pid = irq >> MARVEL_IRQ_VEC_PE_SHIFT;
  79 
  80         if (!(io7 = marvel_find_io7(pid))) {
  81                 printk(KERN_ERR 
  82                        "%s for nonexistent io7 -- vec %x, pid %d\n",
  83                        __func__, irq, pid);
  84                 return NULL;
  85         }
  86 
  87         irq &= MARVEL_IRQ_VEC_IRQ_MASK; /* isolate the vector    */
  88         irq -= 16;                      /* subtract legacy bias  */
  89 
  90         if (irq >= 0x180) {
  91                 printk(KERN_ERR 
  92                        "%s for invalid irq -- pid %d adjusted irq %x\n",
  93                        __func__, pid, irq);
  94                 return NULL;
  95         }
  96 
  97         ctl = &io7->csrs->PO7_LSI_CTL[irq & 0xff].csr; /* assume LSI */
  98         if (irq >= 0x80)                /* MSI */
  99                 ctl = &io7->csrs->PO7_MSI_CTL[((irq - 0x80) >> 5) & 0x0f].csr;
 100 
 101         if (pio7) *pio7 = io7;
 102         return ctl;
 103 }
 104 
 105 static void
 106 io7_enable_irq(struct irq_data *d)
 107 {
 108         volatile unsigned long *ctl;
 109         unsigned int irq = d->irq;
 110         struct io7 *io7;
 111 
 112         ctl = io7_get_irq_ctl(irq, &io7);
 113         if (!ctl || !io7) {
 114                 printk(KERN_ERR "%s: get_ctl failed for irq %x\n",
 115                        __func__, irq);
 116                 return;
 117         }
 118 
 119         raw_spin_lock(&io7->irq_lock);
 120         *ctl |= 1UL << 24;
 121         mb();
 122         *ctl;
 123         raw_spin_unlock(&io7->irq_lock);
 124 }
 125 
 126 static void
 127 io7_disable_irq(struct irq_data *d)
 128 {
 129         volatile unsigned long *ctl;
 130         unsigned int irq = d->irq;
 131         struct io7 *io7;
 132 
 133         ctl = io7_get_irq_ctl(irq, &io7);
 134         if (!ctl || !io7) {
 135                 printk(KERN_ERR "%s: get_ctl failed for irq %x\n",
 136                        __func__, irq);
 137                 return;
 138         }
 139 
 140         raw_spin_lock(&io7->irq_lock);
 141         *ctl &= ~(1UL << 24);
 142         mb();
 143         *ctl;
 144         raw_spin_unlock(&io7->irq_lock);
 145 }
 146 
 147 static void
 148 marvel_irq_noop(struct irq_data *d)
 149 {
 150         return;
 151 }
 152 
 153 static struct irq_chip marvel_legacy_irq_type = {
 154         .name           = "LEGACY",
 155         .irq_mask       = marvel_irq_noop,
 156         .irq_unmask     = marvel_irq_noop,
 157 };
 158 
 159 static struct irq_chip io7_lsi_irq_type = {
 160         .name           = "LSI",
 161         .irq_unmask     = io7_enable_irq,
 162         .irq_mask       = io7_disable_irq,
 163         .irq_mask_ack   = io7_disable_irq,
 164 };
 165 
 166 static struct irq_chip io7_msi_irq_type = {
 167         .name           = "MSI",
 168         .irq_unmask     = io7_enable_irq,
 169         .irq_mask       = io7_disable_irq,
 170         .irq_ack        = marvel_irq_noop,
 171 };
 172 
 173 static void
 174 io7_redirect_irq(struct io7 *io7, 
 175                  volatile unsigned long *csr, 
 176                  unsigned int where)
 177 {
 178         unsigned long val;
 179         
 180         val = *csr;
 181         val &= ~(0x1ffUL << 24);                /* clear the target pid   */
 182         val |= ((unsigned long)where << 24);    /* set the new target pid */
 183         
 184         *csr = val;
 185         mb();
 186         *csr;
 187 }
 188 
 189 static void 
 190 io7_redirect_one_lsi(struct io7 *io7, unsigned int which, unsigned int where)
 191 {
 192         unsigned long val;
 193 
 194         /*
 195          * LSI_CTL has target PID @ 14
 196          */
 197         val = io7->csrs->PO7_LSI_CTL[which].csr;
 198         val &= ~(0x1ffUL << 14);                /* clear the target pid */
 199         val |= ((unsigned long)where << 14);    /* set the new target pid */
 200 
 201         io7->csrs->PO7_LSI_CTL[which].csr = val;
 202         mb();
 203         io7->csrs->PO7_LSI_CTL[which].csr;
 204 }
 205 
 206 static void 
 207 io7_redirect_one_msi(struct io7 *io7, unsigned int which, unsigned int where)
 208 {
 209         unsigned long val;
 210 
 211         /*
 212          * MSI_CTL has target PID @ 14
 213          */
 214         val = io7->csrs->PO7_MSI_CTL[which].csr;
 215         val &= ~(0x1ffUL << 14);                /* clear the target pid */
 216         val |= ((unsigned long)where << 14);    /* set the new target pid */
 217 
 218         io7->csrs->PO7_MSI_CTL[which].csr = val;
 219         mb();
 220         io7->csrs->PO7_MSI_CTL[which].csr;
 221 }
 222 
 223 static void __init
 224 init_one_io7_lsi(struct io7 *io7, unsigned int which, unsigned int where)
 225 {
 226         /*
 227          * LSI_CTL has target PID @ 14
 228          */
 229         io7->csrs->PO7_LSI_CTL[which].csr = ((unsigned long)where << 14);
 230         mb();
 231         io7->csrs->PO7_LSI_CTL[which].csr;
 232 }
 233 
 234 static void __init
 235 init_one_io7_msi(struct io7 *io7, unsigned int which, unsigned int where)
 236 {
 237         /*
 238          * MSI_CTL has target PID @ 14
 239          */
 240         io7->csrs->PO7_MSI_CTL[which].csr = ((unsigned long)where << 14);
 241         mb();
 242         io7->csrs->PO7_MSI_CTL[which].csr;
 243 }
 244 
 245 static void __init
 246 init_io7_irqs(struct io7 *io7, 
 247               struct irq_chip *lsi_ops,
 248               struct irq_chip *msi_ops)
 249 {
 250         long base = (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT) + 16;
 251         long i;
 252 
 253         printk("Initializing interrupts for IO7 at PE %u - base %lx\n",
 254                 io7->pe, base);
 255 
 256         /*
 257          * Where should interrupts from this IO7 go?
 258          *
 259          * They really should be sent to the local CPU to avoid having to
 260          * traverse the mesh, but if it's not an SMP kernel, they have to
 261          * go to the boot CPU. Send them all to the boot CPU for now,
 262          * as each secondary starts, it can redirect it's local device 
 263          * interrupts.
 264          */
 265         printk("  Interrupts reported to CPU at PE %u\n", boot_cpuid);
 266 
 267         raw_spin_lock(&io7->irq_lock);
 268 
 269         /* set up the error irqs */
 270         io7_redirect_irq(io7, &io7->csrs->HLT_CTL.csr, boot_cpuid);
 271         io7_redirect_irq(io7, &io7->csrs->HPI_CTL.csr, boot_cpuid);
 272         io7_redirect_irq(io7, &io7->csrs->CRD_CTL.csr, boot_cpuid);
 273         io7_redirect_irq(io7, &io7->csrs->STV_CTL.csr, boot_cpuid);
 274         io7_redirect_irq(io7, &io7->csrs->HEI_CTL.csr, boot_cpuid);
 275 
 276         /* Set up the lsi irqs.  */
 277         for (i = 0; i < 128; ++i) {
 278                 irq_set_chip_and_handler(base + i, lsi_ops, handle_level_irq);
 279                 irq_set_status_flags(i, IRQ_LEVEL);
 280         }
 281 
 282         /* Disable the implemented irqs in hardware.  */
 283         for (i = 0; i < 0x60; ++i) 
 284                 init_one_io7_lsi(io7, i, boot_cpuid);
 285 
 286         init_one_io7_lsi(io7, 0x74, boot_cpuid);
 287         init_one_io7_lsi(io7, 0x75, boot_cpuid);
 288 
 289 
 290         /* Set up the msi irqs.  */
 291         for (i = 128; i < (128 + 512); ++i) {
 292                 irq_set_chip_and_handler(base + i, msi_ops, handle_level_irq);
 293                 irq_set_status_flags(i, IRQ_LEVEL);
 294         }
 295 
 296         for (i = 0; i < 16; ++i)
 297                 init_one_io7_msi(io7, i, boot_cpuid);
 298 
 299         raw_spin_unlock(&io7->irq_lock);
 300 }
 301 
 302 static void __init
 303 marvel_init_irq(void)
 304 {
 305         int i;
 306         struct io7 *io7 = NULL;
 307 
 308         /* Reserve the legacy irqs.  */
 309         for (i = 0; i < 16; ++i) {
 310                 irq_set_chip_and_handler(i, &marvel_legacy_irq_type,
 311                                          handle_level_irq);
 312         }
 313 
 314         /* Init the io7 irqs.  */
 315         for (io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; )
 316                 init_io7_irqs(io7, &io7_lsi_irq_type, &io7_msi_irq_type);
 317 }
 318 
 319 static int 
 320 marvel_map_irq(const struct pci_dev *cdev, u8 slot, u8 pin)
 321 {
 322         struct pci_dev *dev = (struct pci_dev *)cdev;
 323         struct pci_controller *hose = dev->sysdata;
 324         struct io7_port *io7_port = hose->sysdata;
 325         struct io7 *io7 = io7_port->io7;
 326         int msi_loc, msi_data_off;
 327         u16 msg_ctl;
 328         u16 msg_dat;
 329         u8 intline; 
 330         int irq;
 331 
 332         pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &intline);
 333         irq = intline;
 334 
 335         msi_loc = dev->msi_cap;
 336         msg_ctl = 0;
 337         if (msi_loc) 
 338                 pci_read_config_word(dev, msi_loc + PCI_MSI_FLAGS, &msg_ctl);
 339 
 340         if (msg_ctl & PCI_MSI_FLAGS_ENABLE) {
 341                 msi_data_off = PCI_MSI_DATA_32;
 342                 if (msg_ctl & PCI_MSI_FLAGS_64BIT) 
 343                         msi_data_off = PCI_MSI_DATA_64;
 344                 pci_read_config_word(dev, msi_loc + msi_data_off, &msg_dat);
 345 
 346                 irq = msg_dat & 0x1ff;          /* we use msg_data<8:0> */
 347                 irq += 0x80;                    /* offset for lsi       */
 348 
 349 #if 1
 350                 printk("PCI:%d:%d:%d (hose %d) is using MSI\n",
 351                        dev->bus->number, 
 352                        PCI_SLOT(dev->devfn), 
 353                        PCI_FUNC(dev->devfn),
 354                        hose->index);
 355                 printk("  %d message(s) from 0x%04x\n", 
 356                        1 << ((msg_ctl & PCI_MSI_FLAGS_QSIZE) >> 4),
 357                        msg_dat);
 358                 printk("  reporting on %d IRQ(s) from %d (0x%x)\n", 
 359                        1 << ((msg_ctl & PCI_MSI_FLAGS_QSIZE) >> 4),
 360                        (irq + 16) | (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT),
 361                        (irq + 16) | (io7->pe << MARVEL_IRQ_VEC_PE_SHIFT));
 362 #endif
 363 
 364 #if 0
 365                 pci_write_config_word(dev, msi_loc + PCI_MSI_FLAGS,
 366                                       msg_ctl & ~PCI_MSI_FLAGS_ENABLE);
 367                 pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &intline);
 368                 irq = intline;
 369 
 370                 printk("  forcing LSI interrupt on irq %d [0x%x]\n", irq, irq);
 371 #endif
 372         }
 373 
 374         irq += 16;                                      /* offset for legacy */
 375         irq |= io7->pe << MARVEL_IRQ_VEC_PE_SHIFT;      /* merge the pid     */
 376 
 377         return irq; 
 378 }
 379 
 380 static void __init
 381 marvel_init_pci(void)
 382 {
 383         struct io7 *io7;
 384 
 385         marvel_register_error_handlers();
 386 
 387         /* Indicate that we trust the console to configure things properly */
 388         pci_set_flags(PCI_PROBE_ONLY);
 389         common_init_pci();
 390         locate_and_init_vga(NULL);
 391 
 392         /* Clear any io7 errors.  */
 393         for (io7 = NULL; (io7 = marvel_next_io7(io7)) != NULL; ) 
 394                 io7_clear_errors(io7);
 395 }
 396 
 397 static void __init
 398 marvel_init_rtc(void)
 399 {
 400         init_rtc_irq();
 401 }
 402 
 403 static void
 404 marvel_smp_callin(void)
 405 {
 406         int cpuid = hard_smp_processor_id();
 407         struct io7 *io7 = marvel_find_io7(cpuid);
 408         unsigned int i;
 409 
 410         if (!io7)
 411                 return;
 412 
 413         /* 
 414          * There is a local IO7 - redirect all of its interrupts here.
 415          */
 416         printk("Redirecting IO7 interrupts to local CPU at PE %u\n", cpuid);
 417 
 418         /* Redirect the error IRQS here.  */
 419         io7_redirect_irq(io7, &io7->csrs->HLT_CTL.csr, cpuid);
 420         io7_redirect_irq(io7, &io7->csrs->HPI_CTL.csr, cpuid);
 421         io7_redirect_irq(io7, &io7->csrs->CRD_CTL.csr, cpuid);
 422         io7_redirect_irq(io7, &io7->csrs->STV_CTL.csr, cpuid);
 423         io7_redirect_irq(io7, &io7->csrs->HEI_CTL.csr, cpuid);
 424 
 425         /* Redirect the implemented LSIs here.  */
 426         for (i = 0; i < 0x60; ++i) 
 427                 io7_redirect_one_lsi(io7, i, cpuid);
 428 
 429         io7_redirect_one_lsi(io7, 0x74, cpuid);
 430         io7_redirect_one_lsi(io7, 0x75, cpuid);
 431 
 432         /* Redirect the MSIs here.  */
 433         for (i = 0; i < 16; ++i)
 434                 io7_redirect_one_msi(io7, i, cpuid);
 435 }
 436 
 437 /*
 438  * System Vectors
 439  */
 440 struct alpha_machine_vector marvel_ev7_mv __initmv = {
 441         .vector_name            = "MARVEL/EV7",
 442         DO_EV7_MMU,
 443         .rtc_port               = 0x70,
 444         .rtc_boot_cpu_only      = 1,
 445         DO_MARVEL_IO,
 446         .machine_check          = marvel_machine_check,
 447         .max_isa_dma_address    = ALPHA_MAX_ISA_DMA_ADDRESS,
 448         .min_io_address         = DEFAULT_IO_BASE,
 449         .min_mem_address        = DEFAULT_MEM_BASE,
 450         .pci_dac_offset         = IO7_DAC_OFFSET,
 451 
 452         .nr_irqs                = MARVEL_NR_IRQS,
 453         .device_interrupt       = io7_device_interrupt,
 454 
 455         .agp_info               = marvel_agp_info,
 456 
 457         .smp_callin             = marvel_smp_callin,
 458         .init_arch              = marvel_init_arch,
 459         .init_irq               = marvel_init_irq,
 460         .init_rtc               = marvel_init_rtc,
 461         .init_pci               = marvel_init_pci,
 462         .kill_arch              = marvel_kill_arch,
 463         .pci_map_irq            = marvel_map_irq,
 464         .pci_swizzle            = common_swizzle,
 465 
 466         .pa_to_nid              = marvel_pa_to_nid,
 467         .cpuid_to_nid           = marvel_cpuid_to_nid,
 468         .node_mem_start         = marvel_node_mem_start,
 469         .node_mem_size          = marvel_node_mem_size,
 470 };
 471 ALIAS_MV(marvel_ev7)

/* [<][>][^][v][top][bottom][index][help] */