1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Western Digital Corporation or its affiliates.
*
* Authors:
* Anup Patel <[email protected]>
*/
#include <sbi/riscv_asm.h>
#include <sbi/riscv_atomic.h>
#include <sbi/riscv_io.h>
#include <sbi/sbi_domain.h>
#include <sbi/sbi_error.h>
#include <sbi/sbi_ipi.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_timer.h>
#include <sbi_utils/ipi/aclint_mswi.h>
static unsigned long mswi_ptr_offset;
#define mswi_get_hart_data_ptr(__scratch) \
sbi_scratch_read_type((__scratch), void *, mswi_ptr_offset)
#define mswi_set_hart_data_ptr(__scratch, __mswi) \
sbi_scratch_write_type((__scratch), void *, mswi_ptr_offset, (__mswi))
static void mswi_ipi_send(u32 hart_index)
{
u32 *msip;
struct sbi_scratch *scratch;
struct aclint_mswi_data *mswi;
scratch = sbi_hartindex_to_scratch(hart_index);
if (!scratch)
return;
mswi = mswi_get_hart_data_ptr(scratch);
if (!mswi)
return;
/* Set ACLINT IPI */
msip = (void *)mswi->addr;
writel_relaxed(1, &msip[sbi_hartindex_to_hartid(hart_index) -
mswi->first_hartid]);
}
static void mswi_ipi_clear(u32 hart_index)
{
u32 *msip;
struct sbi_scratch *scratch;
struct aclint_mswi_data *mswi;
scratch = sbi_hartindex_to_scratch(hart_index);
if (!scratch)
return;
mswi = mswi_get_hart_data_ptr(scratch);
if (!mswi)
return;
/* Clear ACLINT IPI */
msip = (void *)mswi->addr;
writel_relaxed(0, &msip[sbi_hartindex_to_hartid(hart_index) -
mswi->first_hartid]);
}
static struct sbi_ipi_device aclint_mswi = {
.name = "aclint-mswi",
.ipi_send = mswi_ipi_send,
.ipi_clear = mswi_ipi_clear
};
int aclint_mswi_warm_init(void)
{
/* Clear IPI for current HART */
mswi_ipi_clear(current_hartid());
return 0;
}
int aclint_mswi_cold_init(struct aclint_mswi_data *mswi)
{
u32 i;
int rc;
struct sbi_scratch *scratch;
unsigned long pos, region_size;
struct sbi_domain_memregion reg;
/* Sanity checks */
if (!mswi || (mswi->addr & (ACLINT_MSWI_ALIGN - 1)) ||
(mswi->size < (mswi->hart_count * sizeof(u32))) ||
(!mswi->hart_count || mswi->hart_count > ACLINT_MSWI_MAX_HARTS))
return SBI_EINVAL;
/* Allocate scratch space pointer */
if (!mswi_ptr_offset) {
mswi_ptr_offset = sbi_scratch_alloc_type_offset(void *);
if (!mswi_ptr_offset)
return SBI_ENOMEM;
}
/* Update MSWI pointer in scratch space */
for (i = 0; i < mswi->hart_count; i++) {
scratch = sbi_hartid_to_scratch(mswi->first_hartid + i);
/*
* We don't need to fail if scratch pointer is not available
* because we might be dealing with hartid of a HART disabled
* in the device tree.
*/
if (!scratch)
continue;
mswi_set_hart_data_ptr(scratch, mswi);
}
/* Add MSWI regions to the root domain */
for (pos = 0; pos < mswi->size; pos += ACLINT_MSWI_ALIGN) {
region_size = ((mswi->size - pos) < ACLINT_MSWI_ALIGN) ?
(mswi->size - pos) : ACLINT_MSWI_ALIGN;
sbi_domain_memregion_init(mswi->addr + pos, region_size,
(SBI_DOMAIN_MEMREGION_MMIO |
SBI_DOMAIN_MEMREGION_M_READABLE |
SBI_DOMAIN_MEMREGION_M_WRITABLE),
®);
rc = sbi_domain_root_add_memregion(®);
if (rc)
return rc;
}
sbi_ipi_set_device(&aclint_mswi);
return 0;
}
|