Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/powerpc/sysdev/mpic_msgr.c
26424 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Copyright 2011-2012, Meador Inge, Mentor Graphics Corporation.
4
*
5
* Some ideas based on un-pushed work done by Vivek Mahajan, Jason Jin, and
6
* Mingkai Hu from Freescale Semiconductor, Inc.
7
*/
8
9
#include <linux/list.h>
10
#include <linux/of.h>
11
#include <linux/of_address.h>
12
#include <linux/of_irq.h>
13
#include <linux/platform_device.h>
14
#include <linux/errno.h>
15
#include <linux/err.h>
16
#include <linux/export.h>
17
#include <linux/slab.h>
18
#include <asm/hw_irq.h>
19
#include <asm/ppc-pci.h>
20
#include <asm/mpic_msgr.h>
21
22
#define MPIC_MSGR_REGISTERS_PER_BLOCK 4
23
#define MPIC_MSGR_STRIDE 0x10
24
#define MPIC_MSGR_MER_OFFSET (0x100 / sizeof(u32))
25
#define MSGR_INUSE 0
26
#define MSGR_FREE 1
27
28
static struct mpic_msgr **mpic_msgrs;
29
static unsigned int mpic_msgr_count;
30
static DEFINE_RAW_SPINLOCK(msgrs_lock);
31
32
static inline void _mpic_msgr_mer_write(struct mpic_msgr *msgr, u32 value)
33
{
34
out_be32(msgr->mer, value);
35
}
36
37
static inline u32 _mpic_msgr_mer_read(struct mpic_msgr *msgr)
38
{
39
return in_be32(msgr->mer);
40
}
41
42
static inline void _mpic_msgr_disable(struct mpic_msgr *msgr)
43
{
44
u32 mer = _mpic_msgr_mer_read(msgr);
45
46
_mpic_msgr_mer_write(msgr, mer & ~(1 << msgr->num));
47
}
48
49
struct mpic_msgr *mpic_msgr_get(unsigned int reg_num)
50
{
51
unsigned long flags;
52
struct mpic_msgr *msgr;
53
54
/* Assume busy until proven otherwise. */
55
msgr = ERR_PTR(-EBUSY);
56
57
if (reg_num >= mpic_msgr_count)
58
return ERR_PTR(-ENODEV);
59
60
raw_spin_lock_irqsave(&msgrs_lock, flags);
61
msgr = mpic_msgrs[reg_num];
62
if (msgr->in_use == MSGR_FREE)
63
msgr->in_use = MSGR_INUSE;
64
raw_spin_unlock_irqrestore(&msgrs_lock, flags);
65
66
return msgr;
67
}
68
EXPORT_SYMBOL_GPL(mpic_msgr_get);
69
70
void mpic_msgr_put(struct mpic_msgr *msgr)
71
{
72
unsigned long flags;
73
74
raw_spin_lock_irqsave(&msgr->lock, flags);
75
msgr->in_use = MSGR_FREE;
76
_mpic_msgr_disable(msgr);
77
raw_spin_unlock_irqrestore(&msgr->lock, flags);
78
}
79
EXPORT_SYMBOL_GPL(mpic_msgr_put);
80
81
void mpic_msgr_enable(struct mpic_msgr *msgr)
82
{
83
unsigned long flags;
84
u32 mer;
85
86
raw_spin_lock_irqsave(&msgr->lock, flags);
87
mer = _mpic_msgr_mer_read(msgr);
88
_mpic_msgr_mer_write(msgr, mer | (1 << msgr->num));
89
raw_spin_unlock_irqrestore(&msgr->lock, flags);
90
}
91
EXPORT_SYMBOL_GPL(mpic_msgr_enable);
92
93
void mpic_msgr_disable(struct mpic_msgr *msgr)
94
{
95
unsigned long flags;
96
97
raw_spin_lock_irqsave(&msgr->lock, flags);
98
_mpic_msgr_disable(msgr);
99
raw_spin_unlock_irqrestore(&msgr->lock, flags);
100
}
101
EXPORT_SYMBOL_GPL(mpic_msgr_disable);
102
103
/* The following three functions are used to compute the order and number of
104
* the message register blocks. They are clearly very inefficient. However,
105
* they are called *only* a few times during device initialization.
106
*/
107
static unsigned int mpic_msgr_number_of_blocks(void)
108
{
109
unsigned int count;
110
struct device_node *aliases;
111
112
count = 0;
113
aliases = of_find_node_by_name(NULL, "aliases");
114
115
if (aliases) {
116
char buf[32];
117
118
for (;;) {
119
snprintf(buf, sizeof(buf), "mpic-msgr-block%d", count);
120
if (!of_property_present(aliases, buf))
121
break;
122
123
count += 1;
124
}
125
of_node_put(aliases);
126
}
127
128
return count;
129
}
130
131
static unsigned int mpic_msgr_number_of_registers(void)
132
{
133
return mpic_msgr_number_of_blocks() * MPIC_MSGR_REGISTERS_PER_BLOCK;
134
}
135
136
static int mpic_msgr_block_number(struct device_node *node)
137
{
138
struct device_node *aliases;
139
unsigned int index, number_of_blocks;
140
char buf[64];
141
142
number_of_blocks = mpic_msgr_number_of_blocks();
143
aliases = of_find_node_by_name(NULL, "aliases");
144
if (!aliases)
145
return -1;
146
147
for (index = 0; index < number_of_blocks; ++index) {
148
struct property *prop;
149
struct device_node *tn;
150
151
snprintf(buf, sizeof(buf), "mpic-msgr-block%d", index);
152
prop = of_find_property(aliases, buf, NULL);
153
tn = of_find_node_by_path(prop->value);
154
if (node == tn) {
155
of_node_put(tn);
156
break;
157
}
158
of_node_put(tn);
159
}
160
of_node_put(aliases);
161
162
return index == number_of_blocks ? -1 : index;
163
}
164
165
/* The probe function for a single message register block.
166
*/
167
static int mpic_msgr_probe(struct platform_device *dev)
168
{
169
void __iomem *msgr_block_addr;
170
int block_number;
171
struct resource rsrc;
172
unsigned int i;
173
unsigned int irq_index;
174
struct device_node *np = dev->dev.of_node;
175
unsigned int receive_mask;
176
const unsigned int *prop;
177
178
if (!np) {
179
dev_err(&dev->dev, "Device OF-Node is NULL");
180
return -EFAULT;
181
}
182
183
/* Allocate the message register array upon the first device
184
* registered.
185
*/
186
if (!mpic_msgrs) {
187
mpic_msgr_count = mpic_msgr_number_of_registers();
188
dev_info(&dev->dev, "Found %d message registers\n",
189
mpic_msgr_count);
190
191
mpic_msgrs = kcalloc(mpic_msgr_count, sizeof(*mpic_msgrs),
192
GFP_KERNEL);
193
if (!mpic_msgrs) {
194
dev_err(&dev->dev,
195
"No memory for message register blocks\n");
196
return -ENOMEM;
197
}
198
}
199
dev_info(&dev->dev, "Of-device full name %pOF\n", np);
200
201
/* IO map the message register block. */
202
of_address_to_resource(np, 0, &rsrc);
203
msgr_block_addr = devm_ioremap(&dev->dev, rsrc.start, resource_size(&rsrc));
204
if (!msgr_block_addr) {
205
dev_err(&dev->dev, "Failed to iomap MPIC message registers");
206
return -EFAULT;
207
}
208
209
/* Ensure the block has a defined order. */
210
block_number = mpic_msgr_block_number(np);
211
if (block_number < 0) {
212
dev_err(&dev->dev,
213
"Failed to find message register block alias\n");
214
return -ENODEV;
215
}
216
dev_info(&dev->dev, "Setting up message register block %d\n",
217
block_number);
218
219
/* Grab the receive mask which specifies what registers can receive
220
* interrupts.
221
*/
222
prop = of_get_property(np, "mpic-msgr-receive-mask", NULL);
223
receive_mask = (prop) ? *prop : 0xF;
224
225
/* Build up the appropriate message register data structures. */
226
for (i = 0, irq_index = 0; i < MPIC_MSGR_REGISTERS_PER_BLOCK; ++i) {
227
struct mpic_msgr *msgr;
228
unsigned int reg_number;
229
230
msgr = kzalloc(sizeof(struct mpic_msgr), GFP_KERNEL);
231
if (!msgr) {
232
dev_err(&dev->dev, "No memory for message register\n");
233
return -ENOMEM;
234
}
235
236
reg_number = block_number * MPIC_MSGR_REGISTERS_PER_BLOCK + i;
237
msgr->base = msgr_block_addr + i * MPIC_MSGR_STRIDE;
238
msgr->mer = msgr->base + MPIC_MSGR_MER_OFFSET;
239
msgr->in_use = MSGR_FREE;
240
msgr->num = i;
241
raw_spin_lock_init(&msgr->lock);
242
243
if (receive_mask & (1 << i)) {
244
msgr->irq = irq_of_parse_and_map(np, irq_index);
245
if (!msgr->irq) {
246
dev_err(&dev->dev,
247
"Missing interrupt specifier");
248
kfree(msgr);
249
return -EFAULT;
250
}
251
irq_index += 1;
252
} else {
253
msgr->irq = 0;
254
}
255
256
mpic_msgrs[reg_number] = msgr;
257
mpic_msgr_disable(msgr);
258
dev_info(&dev->dev, "Register %d initialized: irq %d\n",
259
reg_number, msgr->irq);
260
261
}
262
263
return 0;
264
}
265
266
static const struct of_device_id mpic_msgr_ids[] = {
267
{
268
.compatible = "fsl,mpic-v3.1-msgr",
269
.data = NULL,
270
},
271
{}
272
};
273
274
static struct platform_driver mpic_msgr_driver = {
275
.driver = {
276
.name = "mpic-msgr",
277
.of_match_table = mpic_msgr_ids,
278
},
279
.probe = mpic_msgr_probe,
280
};
281
282
static __init int mpic_msgr_init(void)
283
{
284
return platform_driver_register(&mpic_msgr_driver);
285
}
286
subsys_initcall(mpic_msgr_init);
287
288