2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License version 2 as
4 * published by the Free Software Foundation.
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
11 * Copyright (C) 2012 ARM Limited
14 #define pr_fmt(fmt) "vexpress-config: " fmt
16 #include <linux/bitops.h>
17 #include <linux/completion.h>
18 #include <linux/export.h>
19 #include <linux/init.h>
20 #include <linux/list.h>
22 #include <linux/of_device.h>
23 #include <linux/slab.h>
24 #include <linux/string.h>
25 #include <linux/vexpress.h>
28 #define VEXPRESS_CONFIG_MAX_BRIDGES 2
30 struct vexpress_config_bridge
{
31 struct device_node
*node
;
32 struct vexpress_config_bridge_info
*info
;
33 struct list_head transactions
;
34 spinlock_t transactions_lock
;
35 } vexpress_config_bridges
[VEXPRESS_CONFIG_MAX_BRIDGES
];
37 static DECLARE_BITMAP(vexpress_config_bridges_map
,
38 ARRAY_SIZE(vexpress_config_bridges
));
39 static DEFINE_MUTEX(vexpress_config_bridges_mutex
);
41 struct vexpress_config_bridge
*vexpress_config_bridge_register(
42 struct device_node
*node
,
43 struct vexpress_config_bridge_info
*info
)
45 struct vexpress_config_bridge
*bridge
;
48 pr_debug("Registering bridge '%s'\n", info
->name
);
50 mutex_lock(&vexpress_config_bridges_mutex
);
51 i
= find_first_zero_bit(vexpress_config_bridges_map
,
52 ARRAY_SIZE(vexpress_config_bridges
));
53 if (i
>= ARRAY_SIZE(vexpress_config_bridges
)) {
54 pr_err("Can't register more bridges!\n");
55 mutex_unlock(&vexpress_config_bridges_mutex
);
58 __set_bit(i
, vexpress_config_bridges_map
);
59 bridge
= &vexpress_config_bridges
[i
];
63 INIT_LIST_HEAD(&bridge
->transactions
);
64 spin_lock_init(&bridge
->transactions_lock
);
66 mutex_unlock(&vexpress_config_bridges_mutex
);
71 void vexpress_config_bridge_unregister(struct vexpress_config_bridge
*bridge
)
73 struct vexpress_config_bridge __bridge
= *bridge
;
76 mutex_lock(&vexpress_config_bridges_mutex
);
77 for (i
= 0; i
< ARRAY_SIZE(vexpress_config_bridges
); i
++)
78 if (&vexpress_config_bridges
[i
] == bridge
)
79 __clear_bit(i
, vexpress_config_bridges_map
);
80 mutex_unlock(&vexpress_config_bridges_mutex
);
82 WARN_ON(!list_empty(&__bridge
.transactions
));
83 while (!list_empty(&__bridge
.transactions
))
88 struct vexpress_config_func
{
89 struct vexpress_config_bridge
*bridge
;
93 struct vexpress_config_func
*__vexpress_config_func_get(struct device
*dev
,
94 struct device_node
*node
)
96 struct device_node
*bridge_node
;
97 struct vexpress_config_func
*func
;
100 if (WARN_ON(dev
&& node
&& dev
->of_node
!= node
))
105 func
= kzalloc(sizeof(*func
), GFP_KERNEL
);
109 bridge_node
= of_node_get(node
);
110 while (bridge_node
) {
111 const __be32
*prop
= of_get_property(bridge_node
,
112 "arm,vexpress,config-bridge", NULL
);
115 bridge_node
= of_find_node_by_phandle(
120 bridge_node
= of_get_next_parent(bridge_node
);
123 mutex_lock(&vexpress_config_bridges_mutex
);
124 for (i
= 0; i
< ARRAY_SIZE(vexpress_config_bridges
); i
++) {
125 struct vexpress_config_bridge
*bridge
=
126 &vexpress_config_bridges
[i
];
128 if (test_bit(i
, vexpress_config_bridges_map
) &&
129 bridge
->node
== bridge_node
) {
130 func
->bridge
= bridge
;
131 func
->func
= bridge
->info
->func_get(dev
, node
);
135 mutex_unlock(&vexpress_config_bridges_mutex
);
146 void vexpress_config_func_put(struct vexpress_config_func
*func
)
148 func
->bridge
->info
->func_put(func
->func
);
149 of_node_put(func
->bridge
->node
);
154 struct vexpress_config_trans
{
155 struct vexpress_config_func
*func
;
160 struct completion completion
;
161 struct list_head list
;
164 static void vexpress_config_dump_trans(const char *what
,
165 struct vexpress_config_trans
*trans
)
167 pr_debug("%s %s trans %p func 0x%p offset %d data 0x%x status %d\n",
168 what
, trans
->write
? "write" : "read", trans
,
169 trans
->func
->func
, trans
->offset
,
170 trans
->data
? *trans
->data
: 0, trans
->status
);
173 static int vexpress_config_schedule(struct vexpress_config_trans
*trans
)
176 struct vexpress_config_bridge
*bridge
= trans
->func
->bridge
;
179 init_completion(&trans
->completion
);
180 trans
->status
= -EFAULT
;
182 spin_lock_irqsave(&bridge
->transactions_lock
, flags
);
184 vexpress_config_dump_trans("Executing", trans
);
186 if (list_empty(&bridge
->transactions
))
187 status
= bridge
->info
->func_exec(trans
->func
->func
,
188 trans
->offset
, trans
->write
, trans
->data
);
190 status
= VEXPRESS_CONFIG_STATUS_WAIT
;
193 case VEXPRESS_CONFIG_STATUS_DONE
:
194 vexpress_config_dump_trans("Finished", trans
);
195 trans
->status
= status
;
197 case VEXPRESS_CONFIG_STATUS_WAIT
:
198 list_add_tail(&trans
->list
, &bridge
->transactions
);
202 spin_unlock_irqrestore(&bridge
->transactions_lock
, flags
);
207 void vexpress_config_complete(struct vexpress_config_bridge
*bridge
,
210 struct vexpress_config_trans
*trans
;
213 spin_lock_irqsave(&bridge
->transactions_lock
, flags
);
215 trans
= list_first_entry(&bridge
->transactions
,
216 struct vexpress_config_trans
, list
);
217 vexpress_config_dump_trans("Completed", trans
);
219 trans
->status
= status
;
220 list_del(&trans
->list
);
222 if (!list_empty(&bridge
->transactions
)) {
223 vexpress_config_dump_trans("Pending", trans
);
225 bridge
->info
->func_exec(trans
->func
->func
, trans
->offset
,
226 trans
->write
, trans
->data
);
228 spin_unlock_irqrestore(&bridge
->transactions_lock
, flags
);
230 complete(&trans
->completion
);
233 int vexpress_config_wait(struct vexpress_config_trans
*trans
)
235 wait_for_completion(&trans
->completion
);
237 return trans
->status
;
241 int vexpress_config_read(struct vexpress_config_func
*func
, int offset
,
244 struct vexpress_config_trans trans
= {
251 int status
= vexpress_config_schedule(&trans
);
253 if (status
== VEXPRESS_CONFIG_STATUS_WAIT
)
254 status
= vexpress_config_wait(&trans
);
258 EXPORT_SYMBOL(vexpress_config_read
);
260 int vexpress_config_write(struct vexpress_config_func
*func
, int offset
,
263 struct vexpress_config_trans trans
= {
270 int status
= vexpress_config_schedule(&trans
);
272 if (status
== VEXPRESS_CONFIG_STATUS_WAIT
)
273 status
= vexpress_config_wait(&trans
);
277 EXPORT_SYMBOL(vexpress_config_write
);