aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel')
-rw-r--r--arch/sparc64/kernel/mdesc.c78
-rw-r--r--arch/sparc64/kernel/vio.c33
2 files changed, 108 insertions, 3 deletions
diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c
index de5310ffdb48..302ba5e5a0bb 100644
--- a/arch/sparc64/kernel/mdesc.c
+++ b/arch/sparc64/kernel/mdesc.c
@@ -137,7 +137,7 @@ static struct mdesc_handle *mdesc_kmalloc(unsigned int mdesc_size)
137 sizeof(struct mdesc_hdr) + 137 sizeof(struct mdesc_hdr) +
138 mdesc_size); 138 mdesc_size);
139 139
140 base = kmalloc(handle_size + 15, GFP_KERNEL); 140 base = kmalloc(handle_size + 15, GFP_KERNEL | __GFP_NOFAIL);
141 if (base) { 141 if (base) {
142 struct mdesc_handle *hp; 142 struct mdesc_handle *hp;
143 unsigned long addr; 143 unsigned long addr;
@@ -214,18 +214,83 @@ void mdesc_release(struct mdesc_handle *hp)
214} 214}
215EXPORT_SYMBOL(mdesc_release); 215EXPORT_SYMBOL(mdesc_release);
216 216
217static DEFINE_MUTEX(mdesc_mutex);
218static struct mdesc_notifier_client *client_list;
219
220void mdesc_register_notifier(struct mdesc_notifier_client *client)
221{
222 u64 node;
223
224 mutex_lock(&mdesc_mutex);
225 client->next = client_list;
226 client_list = client;
227
228 mdesc_for_each_node_by_name(cur_mdesc, node, client->node_name)
229 client->add(cur_mdesc, node);
230
231 mutex_unlock(&mdesc_mutex);
232}
233
234/* Run 'func' on nodes which are in A but not in B. */
235static void invoke_on_missing(const char *name,
236 struct mdesc_handle *a,
237 struct mdesc_handle *b,
238 void (*func)(struct mdesc_handle *, u64))
239{
240 u64 node;
241
242 mdesc_for_each_node_by_name(a, node, name) {
243 const u64 *id = mdesc_get_property(a, node, "id", NULL);
244 int found = 0;
245 u64 fnode;
246
247 mdesc_for_each_node_by_name(b, fnode, name) {
248 const u64 *fid = mdesc_get_property(b, fnode,
249 "id", NULL);
250
251 if (*id == *fid) {
252 found = 1;
253 break;
254 }
255 }
256 if (!found)
257 func(a, node);
258 }
259}
260
261static void notify_one(struct mdesc_notifier_client *p,
262 struct mdesc_handle *old_hp,
263 struct mdesc_handle *new_hp)
264{
265 invoke_on_missing(p->node_name, old_hp, new_hp, p->remove);
266 invoke_on_missing(p->node_name, new_hp, old_hp, p->add);
267}
268
269static void mdesc_notify_clients(struct mdesc_handle *old_hp,
270 struct mdesc_handle *new_hp)
271{
272 struct mdesc_notifier_client *p = client_list;
273
274 while (p) {
275 notify_one(p, old_hp, new_hp);
276 p = p->next;
277 }
278}
279
217void mdesc_update(void) 280void mdesc_update(void)
218{ 281{
219 unsigned long len, real_len, status; 282 unsigned long len, real_len, status;
220 struct mdesc_handle *hp, *orig_hp; 283 struct mdesc_handle *hp, *orig_hp;
221 unsigned long flags; 284 unsigned long flags;
222 285
286 mutex_lock(&mdesc_mutex);
287
223 (void) sun4v_mach_desc(0UL, 0UL, &len); 288 (void) sun4v_mach_desc(0UL, 0UL, &len);
224 289
225 hp = mdesc_alloc(len, &kmalloc_mdesc_memops); 290 hp = mdesc_alloc(len, &kmalloc_mdesc_memops);
226 if (!hp) { 291 if (!hp) {
227 printk(KERN_ERR "MD: mdesc alloc fails\n"); 292 printk(KERN_ERR "MD: mdesc alloc fails\n");
228 return; 293 goto out;
229 } 294 }
230 295
231 status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len); 296 status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len);
@@ -234,18 +299,25 @@ void mdesc_update(void)
234 status); 299 status);
235 atomic_dec(&hp->refcnt); 300 atomic_dec(&hp->refcnt);
236 mdesc_free(hp); 301 mdesc_free(hp);
237 return; 302 goto out;
238 } 303 }
239 304
240 spin_lock_irqsave(&mdesc_lock, flags); 305 spin_lock_irqsave(&mdesc_lock, flags);
241 orig_hp = cur_mdesc; 306 orig_hp = cur_mdesc;
242 cur_mdesc = hp; 307 cur_mdesc = hp;
308 spin_unlock_irqrestore(&mdesc_lock, flags);
243 309
310 mdesc_notify_clients(orig_hp, hp);
311
312 spin_lock_irqsave(&mdesc_lock, flags);
244 if (atomic_dec_and_test(&orig_hp->refcnt)) 313 if (atomic_dec_and_test(&orig_hp->refcnt))
245 mdesc_free(orig_hp); 314 mdesc_free(orig_hp);
246 else 315 else
247 list_add(&orig_hp->list, &mdesc_zombie_list); 316 list_add(&orig_hp->list, &mdesc_zombie_list);
248 spin_unlock_irqrestore(&mdesc_lock, flags); 317 spin_unlock_irqrestore(&mdesc_lock, flags);
318
319out:
320 mutex_unlock(&mdesc_mutex);
249} 321}
250 322
251static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc) 323static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)
diff --git a/arch/sparc64/kernel/vio.c b/arch/sparc64/kernel/vio.c
index 49569b44ea1f..d487be093b4a 100644
--- a/arch/sparc64/kernel/vio.c
+++ b/arch/sparc64/kernel/vio.c
@@ -172,6 +172,36 @@ struct device_node *cdev_node;
172static struct vio_dev *root_vdev; 172static struct vio_dev *root_vdev;
173static u64 cdev_cfg_handle; 173static u64 cdev_cfg_handle;
174 174
175static void vio_add(struct mdesc_handle *hp, u64 node)
176{
177 const char *name = mdesc_get_property(hp, node, "name", NULL);
178 const u64 *id = mdesc_get_property(hp, node, "id", NULL);
179
180 printk(KERN_ERR "VIO: Device add (%s) ID[%lx]\n",
181 name, *id);
182}
183
184static void vio_remove(struct mdesc_handle *hp, u64 node)
185{
186 const char *name = mdesc_get_property(hp, node, "name", NULL);
187 const u64 *id = mdesc_get_property(hp, node, "id", NULL);
188
189 printk(KERN_ERR "VIO: Device remove (%s) ID[%lx]\n",
190 name, *id);
191}
192
193static struct mdesc_notifier_client vio_device_notifier = {
194 .add = vio_add,
195 .remove = vio_remove,
196 .node_name = "virtual-device-port",
197};
198
199static struct mdesc_notifier_client vio_ds_notifier = {
200 .add = vio_add,
201 .remove = vio_remove,
202 .node_name = "domain-services-port",
203};
204
175static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp, 205static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
176 struct vio_dev *vdev) 206 struct vio_dev *vdev)
177{ 207{
@@ -381,6 +411,9 @@ static int __init vio_init(void)
381 411
382 cdev_cfg_handle = *cfg_handle; 412 cdev_cfg_handle = *cfg_handle;
383 413
414 mdesc_register_notifier(&vio_device_notifier);
415 mdesc_register_notifier(&vio_ds_notifier);
416
384 create_devices(hp, root); 417 create_devices(hp, root);
385 418
386 mdesc_release(hp); 419 mdesc_release(hp);