Commit 920c3ed741340a88f2042ab0c44a25b8c743a379

Authored by David S. Miller
1 parent cb32da0416

[SPARC64]: Add basic infrastructure for MD add/remove notification.

And add dummy handlers for the VIO device layer.  These will be filled
in with real code after the vdc, vnet, and ds drivers are reworked to
have simpler dependencies on the VIO device tree.

Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 3 changed files with 118 additions and 3 deletions Side-by-side Diff

arch/sparc64/kernel/mdesc.c
... ... @@ -137,7 +137,7 @@
137 137 sizeof(struct mdesc_hdr) +
138 138 mdesc_size);
139 139  
140   - base = kmalloc(handle_size + 15, GFP_KERNEL);
  140 + base = kmalloc(handle_size + 15, GFP_KERNEL | __GFP_NOFAIL);
141 141 if (base) {
142 142 struct mdesc_handle *hp;
143 143 unsigned long addr;
144 144  
145 145  
... ... @@ -214,18 +214,83 @@
214 214 }
215 215 EXPORT_SYMBOL(mdesc_release);
216 216  
  217 +static DEFINE_MUTEX(mdesc_mutex);
  218 +static struct mdesc_notifier_client *client_list;
  219 +
  220 +void 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. */
  235 +static 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 +
  261 +static 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 +
  269 +static 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 +
217 280 void mdesc_update(void)
218 281 {
219 282 unsigned long len, real_len, status;
220 283 struct mdesc_handle *hp, *orig_hp;
221 284 unsigned long flags;
222 285  
  286 + mutex_lock(&mdesc_mutex);
  287 +
223 288 (void) sun4v_mach_desc(0UL, 0UL, &len);
224 289  
225 290 hp = mdesc_alloc(len, &kmalloc_mdesc_memops);
226 291 if (!hp) {
227 292 printk(KERN_ERR "MD: mdesc alloc fails\n");
228   - return;
  293 + goto out;
229 294 }
230 295  
231 296 status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len);
232 297  
233 298  
234 299  
... ... @@ -234,18 +299,25 @@
234 299 status);
235 300 atomic_dec(&hp->refcnt);
236 301 mdesc_free(hp);
237   - return;
  302 + goto out;
238 303 }
239 304  
240 305 spin_lock_irqsave(&mdesc_lock, flags);
241 306 orig_hp = cur_mdesc;
242 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 313 if (atomic_dec_and_test(&orig_hp->refcnt))
245 314 mdesc_free(orig_hp);
246 315 else
247 316 list_add(&orig_hp->list, &mdesc_zombie_list);
248 317 spin_unlock_irqrestore(&mdesc_lock, flags);
  318 +
  319 +out:
  320 + mutex_unlock(&mdesc_mutex);
249 321 }
250 322  
251 323 static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)
arch/sparc64/kernel/vio.c
... ... @@ -172,6 +172,36 @@
172 172 static struct vio_dev *root_vdev;
173 173 static u64 cdev_cfg_handle;
174 174  
  175 +static 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 +
  184 +static 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 +
  193 +static struct mdesc_notifier_client vio_device_notifier = {
  194 + .add = vio_add,
  195 + .remove = vio_remove,
  196 + .node_name = "virtual-device-port",
  197 +};
  198 +
  199 +static struct mdesc_notifier_client vio_ds_notifier = {
  200 + .add = vio_add,
  201 + .remove = vio_remove,
  202 + .node_name = "domain-services-port",
  203 +};
  204 +
175 205 static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
176 206 struct vio_dev *vdev)
177 207 {
... ... @@ -380,6 +410,9 @@
380 410 }
381 411  
382 412 cdev_cfg_handle = *cfg_handle;
  413 +
  414 + mdesc_register_notifier(&vio_device_notifier);
  415 + mdesc_register_notifier(&vio_ds_notifier);
383 416  
384 417 create_devices(hp, root);
385 418  
include/asm-sparc64/mdesc.h
... ... @@ -61,6 +61,16 @@
61 61  
62 62 extern void mdesc_update(void);
63 63  
  64 +struct mdesc_notifier_client {
  65 + void (*add)(struct mdesc_handle *handle, u64 node);
  66 + void (*remove)(struct mdesc_handle *handle, u64 node);
  67 +
  68 + const char *node_name;
  69 + struct mdesc_notifier_client *next;
  70 +};
  71 +
  72 +extern void mdesc_register_notifier(struct mdesc_notifier_client *client);
  73 +
64 74 extern void mdesc_fill_in_cpu_data(cpumask_t mask);
65 75  
66 76 extern void sun4v_mdesc_init(void);