Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/mips/mti-malta/malta-smtc.c
10817 views
1
/*
2
* Malta Platform-specific hooks for SMP operation
3
*/
4
#include <linux/irq.h>
5
#include <linux/init.h>
6
7
#include <asm/mipsregs.h>
8
#include <asm/mipsmtregs.h>
9
#include <asm/smtc.h>
10
#include <asm/smtc_ipi.h>
11
12
/* VPE/SMP Prototype implements platform interfaces directly */
13
14
/*
15
* Cause the specified action to be performed on a targeted "CPU"
16
*/
17
18
static void msmtc_send_ipi_single(int cpu, unsigned int action)
19
{
20
/* "CPU" may be TC of same VPE, VPE of same CPU, or different CPU */
21
smtc_send_ipi(cpu, LINUX_SMP_IPI, action);
22
}
23
24
static void msmtc_send_ipi_mask(const struct cpumask *mask, unsigned int action)
25
{
26
unsigned int i;
27
28
for_each_cpu(i, mask)
29
msmtc_send_ipi_single(i, action);
30
}
31
32
/*
33
* Post-config but pre-boot cleanup entry point
34
*/
35
static void __cpuinit msmtc_init_secondary(void)
36
{
37
int myvpe;
38
39
/* Don't enable Malta I/O interrupts (IP2) for secondary VPEs */
40
myvpe = read_c0_tcbind() & TCBIND_CURVPE;
41
if (myvpe != 0) {
42
/* Ideally, this should be done only once per VPE, but... */
43
clear_c0_status(ST0_IM);
44
set_c0_status((0x100 << cp0_compare_irq)
45
| (0x100 << MIPS_CPU_IPI_IRQ));
46
if (cp0_perfcount_irq >= 0)
47
set_c0_status(0x100 << cp0_perfcount_irq);
48
}
49
50
smtc_init_secondary();
51
}
52
53
/*
54
* Platform "CPU" startup hook
55
*/
56
static void __cpuinit msmtc_boot_secondary(int cpu, struct task_struct *idle)
57
{
58
smtc_boot_secondary(cpu, idle);
59
}
60
61
/*
62
* SMP initialization finalization entry point
63
*/
64
static void __cpuinit msmtc_smp_finish(void)
65
{
66
smtc_smp_finish();
67
}
68
69
/*
70
* Hook for after all CPUs are online
71
*/
72
73
static void msmtc_cpus_done(void)
74
{
75
}
76
77
/*
78
* Platform SMP pre-initialization
79
*
80
* As noted above, we can assume a single CPU for now
81
* but it may be multithreaded.
82
*/
83
84
static void __init msmtc_smp_setup(void)
85
{
86
/*
87
* we won't get the definitive value until
88
* we've run smtc_prepare_cpus later, but
89
* we would appear to need an upper bound now.
90
*/
91
smp_num_siblings = smtc_build_cpu_map(0);
92
}
93
94
static void __init msmtc_prepare_cpus(unsigned int max_cpus)
95
{
96
smtc_prepare_cpus(max_cpus);
97
}
98
99
struct plat_smp_ops msmtc_smp_ops = {
100
.send_ipi_single = msmtc_send_ipi_single,
101
.send_ipi_mask = msmtc_send_ipi_mask,
102
.init_secondary = msmtc_init_secondary,
103
.smp_finish = msmtc_smp_finish,
104
.cpus_done = msmtc_cpus_done,
105
.boot_secondary = msmtc_boot_secondary,
106
.smp_setup = msmtc_smp_setup,
107
.prepare_cpus = msmtc_prepare_cpus,
108
};
109
110
#ifdef CONFIG_MIPS_MT_SMTC_IRQAFF
111
/*
112
* IRQ affinity hook
113
*/
114
115
116
int plat_set_irq_affinity(struct irq_data *d, const struct cpumask *affinity,
117
bool force)
118
{
119
cpumask_t tmask;
120
int cpu = 0;
121
void smtc_set_irq_affinity(unsigned int irq, cpumask_t aff);
122
123
/*
124
* On the legacy Malta development board, all I/O interrupts
125
* are routed through the 8259 and combined in a single signal
126
* to the CPU daughterboard, and on the CoreFPGA2/3 34K models,
127
* that signal is brought to IP2 of both VPEs. To avoid racing
128
* concurrent interrupt service events, IP2 is enabled only on
129
* one VPE, by convention VPE0. So long as no bits are ever
130
* cleared in the affinity mask, there will never be any
131
* interrupt forwarding. But as soon as a program or operator
132
* sets affinity for one of the related IRQs, we need to make
133
* sure that we don't ever try to forward across the VPE boundary,
134
* at least not until we engineer a system where the interrupt
135
* _ack() or _end() function can somehow know that it corresponds
136
* to an interrupt taken on another VPE, and perform the appropriate
137
* restoration of Status.IM state using MFTR/MTTR instead of the
138
* normal local behavior. We also ensure that no attempt will
139
* be made to forward to an offline "CPU".
140
*/
141
142
cpumask_copy(&tmask, affinity);
143
for_each_cpu(cpu, affinity) {
144
if ((cpu_data[cpu].vpe_id != 0) || !cpu_online(cpu))
145
cpu_clear(cpu, tmask);
146
}
147
cpumask_copy(d->affinity, &tmask);
148
149
if (cpus_empty(tmask))
150
/*
151
* We could restore a default mask here, but the
152
* runtime code can anyway deal with the null set
153
*/
154
printk(KERN_WARNING
155
"IRQ affinity leaves no legal CPU for IRQ %d\n", irq);
156
157
/* Do any generic SMTC IRQ affinity setup */
158
smtc_set_irq_affinity(d->irq, tmask);
159
160
return IRQ_SET_MASK_OK_NOCOPY;
161
}
162
#endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */
163
164