2 * linux/arch/alpha/kernel/sys_marvel.c
7 #include <linux/kernel.h>
8 #include <linux/types.h>
10 #include <linux/sched.h>
11 #include <linux/pci.h>
12 #include <linux/init.h>
13 #include <linux/bitops.h>
15 #include <asm/ptrace.h>
16 #include <asm/system.h>
19 #include <asm/mmu_context.h>
21 #include <asm/pgtable.h>
22 #include <asm/core_marvel.h>
23 #include <asm/hwrpb.h>
24 #include <asm/tlbflush.h>
30 #include "machvec_impl.h"
32 #if NR_IRQS < MARVEL_NR_IRQS
33 # error NR_IRQS < MARVEL_NR_IRQS !!!
41 io7_device_interrupt(unsigned long vector
, struct pt_regs
* regs
)
47 * Vector is 0x800 + (interrupt)
49 * where (interrupt) is:
51 * ...16|15 14|13 4|3 0
52 * -----+-----+--------+---
57 * 0x0800 - 0x0ff0 - 0x0800 + (LSI id << 4)
58 * 0x1000 - 0x2ff0 - 0x1000 + (MSI_DAT<8:0> << 4)
61 irq
= ((vector
& 0xffff) - 0x800) >> 4;
63 irq
+= 16; /* offset for legacy */
64 irq
&= MARVEL_IRQ_VEC_IRQ_MASK
; /* not too many bits */
65 irq
|= pid
<< MARVEL_IRQ_VEC_PE_SHIFT
; /* merge the pid */
67 handle_irq(irq
, regs
);
70 static volatile unsigned long *
71 io7_get_irq_ctl(unsigned int irq
, struct io7
**pio7
)
73 volatile unsigned long *ctl
;
77 pid
= irq
>> MARVEL_IRQ_VEC_PE_SHIFT
;
79 if (!(io7
= marvel_find_io7(pid
))) {
81 "%s for nonexistent io7 -- vec %x, pid %d\n",
82 __FUNCTION__
, irq
, pid
);
86 irq
&= MARVEL_IRQ_VEC_IRQ_MASK
; /* isolate the vector */
87 irq
-= 16; /* subtract legacy bias */
91 "%s for invalid irq -- pid %d adjusted irq %x\n",
92 __FUNCTION__
, pid
, irq
);
96 ctl
= &io7
->csrs
->PO7_LSI_CTL
[irq
& 0xff].csr
; /* assume LSI */
97 if (irq
>= 0x80) /* MSI */
98 ctl
= &io7
->csrs
->PO7_MSI_CTL
[((irq
- 0x80) >> 5) & 0x0f].csr
;
100 if (pio7
) *pio7
= io7
;
105 io7_enable_irq(unsigned int irq
)
107 volatile unsigned long *ctl
;
110 ctl
= io7_get_irq_ctl(irq
, &io7
);
112 printk(KERN_ERR
"%s: get_ctl failed for irq %x\n",
117 spin_lock(&io7
->irq_lock
);
121 spin_unlock(&io7
->irq_lock
);
125 io7_disable_irq(unsigned int irq
)
127 volatile unsigned long *ctl
;
130 ctl
= io7_get_irq_ctl(irq
, &io7
);
132 printk(KERN_ERR
"%s: get_ctl failed for irq %x\n",
137 spin_lock(&io7
->irq_lock
);
138 *ctl
&= ~(1UL << 24);
141 spin_unlock(&io7
->irq_lock
);
145 io7_startup_irq(unsigned int irq
)
148 return 0; /* never anything pending */
152 io7_end_irq(unsigned int irq
)
154 if (!(irq_desc
[irq
].status
& (IRQ_DISABLED
|IRQ_INPROGRESS
)))
159 marvel_irq_noop(unsigned int irq
)
165 marvel_irq_noop_return(unsigned int irq
)
170 static struct hw_interrupt_type marvel_legacy_irq_type
= {
171 .typename
= "LEGACY",
172 .startup
= marvel_irq_noop_return
,
173 .shutdown
= marvel_irq_noop
,
174 .enable
= marvel_irq_noop
,
175 .disable
= marvel_irq_noop
,
176 .ack
= marvel_irq_noop
,
177 .end
= marvel_irq_noop
,
180 static struct hw_interrupt_type io7_lsi_irq_type
= {
182 .startup
= io7_startup_irq
,
183 .shutdown
= io7_disable_irq
,
184 .enable
= io7_enable_irq
,
185 .disable
= io7_disable_irq
,
186 .ack
= io7_disable_irq
,
190 static struct hw_interrupt_type io7_msi_irq_type
= {
192 .startup
= io7_startup_irq
,
193 .shutdown
= io7_disable_irq
,
194 .enable
= io7_enable_irq
,
195 .disable
= io7_disable_irq
,
196 .ack
= marvel_irq_noop
,
201 io7_redirect_irq(struct io7
*io7
,
202 volatile unsigned long *csr
,
208 val
&= ~(0x1ffUL
<< 24); /* clear the target pid */
209 val
|= ((unsigned long)where
<< 24); /* set the new target pid */
217 io7_redirect_one_lsi(struct io7
*io7
, unsigned int which
, unsigned int where
)
222 * LSI_CTL has target PID @ 14
224 val
= io7
->csrs
->PO7_LSI_CTL
[which
].csr
;
225 val
&= ~(0x1ffUL
<< 14); /* clear the target pid */
226 val
|= ((unsigned long)where
<< 14); /* set the new target pid */
228 io7
->csrs
->PO7_LSI_CTL
[which
].csr
= val
;
230 io7
->csrs
->PO7_LSI_CTL
[which
].csr
;
234 io7_redirect_one_msi(struct io7
*io7
, unsigned int which
, unsigned int where
)
239 * MSI_CTL has target PID @ 14
241 val
= io7
->csrs
->PO7_MSI_CTL
[which
].csr
;
242 val
&= ~(0x1ffUL
<< 14); /* clear the target pid */
243 val
|= ((unsigned long)where
<< 14); /* set the new target pid */
245 io7
->csrs
->PO7_MSI_CTL
[which
].csr
= val
;
247 io7
->csrs
->PO7_MSI_CTL
[which
].csr
;
251 init_one_io7_lsi(struct io7
*io7
, unsigned int which
, unsigned int where
)
254 * LSI_CTL has target PID @ 14
256 io7
->csrs
->PO7_LSI_CTL
[which
].csr
= ((unsigned long)where
<< 14);
258 io7
->csrs
->PO7_LSI_CTL
[which
].csr
;
262 init_one_io7_msi(struct io7
*io7
, unsigned int which
, unsigned int where
)
265 * MSI_CTL has target PID @ 14
267 io7
->csrs
->PO7_MSI_CTL
[which
].csr
= ((unsigned long)where
<< 14);
269 io7
->csrs
->PO7_MSI_CTL
[which
].csr
;
273 init_io7_irqs(struct io7
*io7
,
274 struct hw_interrupt_type
*lsi_ops
,
275 struct hw_interrupt_type
*msi_ops
)
277 long base
= (io7
->pe
<< MARVEL_IRQ_VEC_PE_SHIFT
) + 16;
280 printk("Initializing interrupts for IO7 at PE %u - base %lx\n",
284 * Where should interrupts from this IO7 go?
286 * They really should be sent to the local CPU to avoid having to
287 * traverse the mesh, but if it's not an SMP kernel, they have to
288 * go to the boot CPU. Send them all to the boot CPU for now,
289 * as each secondary starts, it can redirect it's local device
292 printk(" Interrupts reported to CPU at PE %u\n", boot_cpuid
);
294 spin_lock(&io7
->irq_lock
);
296 /* set up the error irqs */
297 io7_redirect_irq(io7
, &io7
->csrs
->HLT_CTL
.csr
, boot_cpuid
);
298 io7_redirect_irq(io7
, &io7
->csrs
->HPI_CTL
.csr
, boot_cpuid
);
299 io7_redirect_irq(io7
, &io7
->csrs
->CRD_CTL
.csr
, boot_cpuid
);
300 io7_redirect_irq(io7
, &io7
->csrs
->STV_CTL
.csr
, boot_cpuid
);
301 io7_redirect_irq(io7
, &io7
->csrs
->HEI_CTL
.csr
, boot_cpuid
);
303 /* Set up the lsi irqs. */
304 for (i
= 0; i
< 128; ++i
) {
305 irq_desc
[base
+ i
].status
= IRQ_DISABLED
| IRQ_LEVEL
;
306 irq_desc
[base
+ i
].handler
= lsi_ops
;
309 /* Disable the implemented irqs in hardware. */
310 for (i
= 0; i
< 0x60; ++i
)
311 init_one_io7_lsi(io7
, i
, boot_cpuid
);
313 init_one_io7_lsi(io7
, 0x74, boot_cpuid
);
314 init_one_io7_lsi(io7
, 0x75, boot_cpuid
);
317 /* Set up the msi irqs. */
318 for (i
= 128; i
< (128 + 512); ++i
) {
319 irq_desc
[base
+ i
].status
= IRQ_DISABLED
| IRQ_LEVEL
;
320 irq_desc
[base
+ i
].handler
= msi_ops
;
323 for (i
= 0; i
< 16; ++i
)
324 init_one_io7_msi(io7
, i
, boot_cpuid
);
326 spin_unlock(&io7
->irq_lock
);
330 marvel_init_irq(void)
333 struct io7
*io7
= NULL
;
335 /* Reserve the legacy irqs. */
336 for (i
= 0; i
< 16; ++i
) {
337 irq_desc
[i
].status
= IRQ_DISABLED
;
338 irq_desc
[i
].handler
= &marvel_legacy_irq_type
;
341 /* Init the io7 irqs. */
342 for (io7
= NULL
; (io7
= marvel_next_io7(io7
)) != NULL
; )
343 init_io7_irqs(io7
, &io7_lsi_irq_type
, &io7_msi_irq_type
);
347 marvel_map_irq(struct pci_dev
*dev
, u8 slot
, u8 pin
)
349 struct pci_controller
*hose
= dev
->sysdata
;
350 struct io7_port
*io7_port
= hose
->sysdata
;
351 struct io7
*io7
= io7_port
->io7
;
352 int msi_loc
, msi_data_off
;
358 pci_read_config_byte(dev
, PCI_INTERRUPT_LINE
, &intline
);
361 msi_loc
= pci_find_capability(dev
, PCI_CAP_ID_MSI
);
364 pci_read_config_word(dev
, msi_loc
+ PCI_MSI_FLAGS
, &msg_ctl
);
366 if (msg_ctl
& PCI_MSI_FLAGS_ENABLE
) {
367 msi_data_off
= PCI_MSI_DATA_32
;
368 if (msg_ctl
& PCI_MSI_FLAGS_64BIT
)
369 msi_data_off
= PCI_MSI_DATA_64
;
370 pci_read_config_word(dev
, msi_loc
+ msi_data_off
, &msg_dat
);
372 irq
= msg_dat
& 0x1ff; /* we use msg_data<8:0> */
373 irq
+= 0x80; /* offset for lsi */
376 printk("PCI:%d:%d:%d (hose %d) [%s] is using MSI\n",
378 PCI_SLOT(dev
->devfn
),
379 PCI_FUNC(dev
->devfn
),
381 pci_pretty_name (dev
));
382 printk(" %d message(s) from 0x%04x\n",
383 1 << ((msg_ctl
& PCI_MSI_FLAGS_QSIZE
) >> 4),
385 printk(" reporting on %d IRQ(s) from %d (0x%x)\n",
386 1 << ((msg_ctl
& PCI_MSI_FLAGS_QSIZE
) >> 4),
387 (irq
+ 16) | (io7
->pe
<< MARVEL_IRQ_VEC_PE_SHIFT
),
388 (irq
+ 16) | (io7
->pe
<< MARVEL_IRQ_VEC_PE_SHIFT
));
392 pci_write_config_word(dev
, msi_loc
+ PCI_MSI_FLAGS
,
393 msg_ctl
& ~PCI_MSI_FLAGS_ENABLE
);
394 pci_read_config_byte(dev
, PCI_INTERRUPT_LINE
, &intline
);
397 printk(" forcing LSI interrupt on irq %d [0x%x]\n", irq
, irq
);
401 irq
+= 16; /* offset for legacy */
402 irq
|= io7
->pe
<< MARVEL_IRQ_VEC_PE_SHIFT
; /* merge the pid */
408 marvel_init_pci(void)
412 marvel_register_error_handlers();
417 #ifdef CONFIG_VGA_HOSE
418 locate_and_init_vga(NULL
);
421 /* Clear any io7 errors. */
422 for (io7
= NULL
; (io7
= marvel_next_io7(io7
)) != NULL
; )
423 io7_clear_errors(io7
);
427 marvel_init_rtc(void)
433 marvel_smp_callin(void)
435 int cpuid
= hard_smp_processor_id();
436 struct io7
*io7
= marvel_find_io7(cpuid
);
443 * There is a local IO7 - redirect all of its interrupts here.
445 printk("Redirecting IO7 interrupts to local CPU at PE %u\n", cpuid
);
447 /* Redirect the error IRQS here. */
448 io7_redirect_irq(io7
, &io7
->csrs
->HLT_CTL
.csr
, cpuid
);
449 io7_redirect_irq(io7
, &io7
->csrs
->HPI_CTL
.csr
, cpuid
);
450 io7_redirect_irq(io7
, &io7
->csrs
->CRD_CTL
.csr
, cpuid
);
451 io7_redirect_irq(io7
, &io7
->csrs
->STV_CTL
.csr
, cpuid
);
452 io7_redirect_irq(io7
, &io7
->csrs
->HEI_CTL
.csr
, cpuid
);
454 /* Redirect the implemented LSIs here. */
455 for (i
= 0; i
< 0x60; ++i
)
456 io7_redirect_one_lsi(io7
, i
, cpuid
);
458 io7_redirect_one_lsi(io7
, 0x74, cpuid
);
459 io7_redirect_one_lsi(io7
, 0x75, cpuid
);
461 /* Redirect the MSIs here. */
462 for (i
= 0; i
< 16; ++i
)
463 io7_redirect_one_msi(io7
, i
, cpuid
);
469 struct alpha_machine_vector marvel_ev7_mv __initmv
= {
470 .vector_name
= "MARVEL/EV7",
474 .machine_check
= marvel_machine_check
,
475 .max_isa_dma_address
= ALPHA_MAX_ISA_DMA_ADDRESS
,
476 .min_io_address
= DEFAULT_IO_BASE
,
477 .min_mem_address
= DEFAULT_MEM_BASE
,
478 .pci_dac_offset
= IO7_DAC_OFFSET
,
480 .nr_irqs
= MARVEL_NR_IRQS
,
481 .device_interrupt
= io7_device_interrupt
,
483 .agp_info
= marvel_agp_info
,
485 .smp_callin
= marvel_smp_callin
,
486 .init_arch
= marvel_init_arch
,
487 .init_irq
= marvel_init_irq
,
488 .init_rtc
= marvel_init_rtc
,
489 .init_pci
= marvel_init_pci
,
490 .kill_arch
= marvel_kill_arch
,
491 .pci_map_irq
= marvel_map_irq
,
492 .pci_swizzle
= common_swizzle
,
494 .pa_to_nid
= marvel_pa_to_nid
,
495 .cpuid_to_nid
= marvel_cpuid_to_nid
,
496 .node_mem_start
= marvel_node_mem_start
,
497 .node_mem_size
= marvel_node_mem_size
,