mirror of
https://github.com/torvalds/linux.git
synced 2024-11-30 08:01:59 +00:00
[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>
This commit is contained in:
parent
cb32da0416
commit
920c3ed741
@ -137,7 +137,7 @@ static struct mdesc_handle *mdesc_kmalloc(unsigned int mdesc_size)
|
||||
sizeof(struct mdesc_hdr) +
|
||||
mdesc_size);
|
||||
|
||||
base = kmalloc(handle_size + 15, GFP_KERNEL);
|
||||
base = kmalloc(handle_size + 15, GFP_KERNEL | __GFP_NOFAIL);
|
||||
if (base) {
|
||||
struct mdesc_handle *hp;
|
||||
unsigned long addr;
|
||||
@ -214,18 +214,83 @@ void mdesc_release(struct mdesc_handle *hp)
|
||||
}
|
||||
EXPORT_SYMBOL(mdesc_release);
|
||||
|
||||
static DEFINE_MUTEX(mdesc_mutex);
|
||||
static struct mdesc_notifier_client *client_list;
|
||||
|
||||
void mdesc_register_notifier(struct mdesc_notifier_client *client)
|
||||
{
|
||||
u64 node;
|
||||
|
||||
mutex_lock(&mdesc_mutex);
|
||||
client->next = client_list;
|
||||
client_list = client;
|
||||
|
||||
mdesc_for_each_node_by_name(cur_mdesc, node, client->node_name)
|
||||
client->add(cur_mdesc, node);
|
||||
|
||||
mutex_unlock(&mdesc_mutex);
|
||||
}
|
||||
|
||||
/* Run 'func' on nodes which are in A but not in B. */
|
||||
static void invoke_on_missing(const char *name,
|
||||
struct mdesc_handle *a,
|
||||
struct mdesc_handle *b,
|
||||
void (*func)(struct mdesc_handle *, u64))
|
||||
{
|
||||
u64 node;
|
||||
|
||||
mdesc_for_each_node_by_name(a, node, name) {
|
||||
const u64 *id = mdesc_get_property(a, node, "id", NULL);
|
||||
int found = 0;
|
||||
u64 fnode;
|
||||
|
||||
mdesc_for_each_node_by_name(b, fnode, name) {
|
||||
const u64 *fid = mdesc_get_property(b, fnode,
|
||||
"id", NULL);
|
||||
|
||||
if (*id == *fid) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
func(a, node);
|
||||
}
|
||||
}
|
||||
|
||||
static void notify_one(struct mdesc_notifier_client *p,
|
||||
struct mdesc_handle *old_hp,
|
||||
struct mdesc_handle *new_hp)
|
||||
{
|
||||
invoke_on_missing(p->node_name, old_hp, new_hp, p->remove);
|
||||
invoke_on_missing(p->node_name, new_hp, old_hp, p->add);
|
||||
}
|
||||
|
||||
static void mdesc_notify_clients(struct mdesc_handle *old_hp,
|
||||
struct mdesc_handle *new_hp)
|
||||
{
|
||||
struct mdesc_notifier_client *p = client_list;
|
||||
|
||||
while (p) {
|
||||
notify_one(p, old_hp, new_hp);
|
||||
p = p->next;
|
||||
}
|
||||
}
|
||||
|
||||
void mdesc_update(void)
|
||||
{
|
||||
unsigned long len, real_len, status;
|
||||
struct mdesc_handle *hp, *orig_hp;
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&mdesc_mutex);
|
||||
|
||||
(void) sun4v_mach_desc(0UL, 0UL, &len);
|
||||
|
||||
hp = mdesc_alloc(len, &kmalloc_mdesc_memops);
|
||||
if (!hp) {
|
||||
printk(KERN_ERR "MD: mdesc alloc fails\n");
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len);
|
||||
@ -234,18 +299,25 @@ void mdesc_update(void)
|
||||
status);
|
||||
atomic_dec(&hp->refcnt);
|
||||
mdesc_free(hp);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&mdesc_lock, flags);
|
||||
orig_hp = cur_mdesc;
|
||||
cur_mdesc = hp;
|
||||
spin_unlock_irqrestore(&mdesc_lock, flags);
|
||||
|
||||
mdesc_notify_clients(orig_hp, hp);
|
||||
|
||||
spin_lock_irqsave(&mdesc_lock, flags);
|
||||
if (atomic_dec_and_test(&orig_hp->refcnt))
|
||||
mdesc_free(orig_hp);
|
||||
else
|
||||
list_add(&orig_hp->list, &mdesc_zombie_list);
|
||||
spin_unlock_irqrestore(&mdesc_lock, flags);
|
||||
|
||||
out:
|
||||
mutex_unlock(&mdesc_mutex);
|
||||
}
|
||||
|
||||
static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)
|
||||
|
@ -172,6 +172,36 @@ struct device_node *cdev_node;
|
||||
static struct vio_dev *root_vdev;
|
||||
static u64 cdev_cfg_handle;
|
||||
|
||||
static void vio_add(struct mdesc_handle *hp, u64 node)
|
||||
{
|
||||
const char *name = mdesc_get_property(hp, node, "name", NULL);
|
||||
const u64 *id = mdesc_get_property(hp, node, "id", NULL);
|
||||
|
||||
printk(KERN_ERR "VIO: Device add (%s) ID[%lx]\n",
|
||||
name, *id);
|
||||
}
|
||||
|
||||
static void vio_remove(struct mdesc_handle *hp, u64 node)
|
||||
{
|
||||
const char *name = mdesc_get_property(hp, node, "name", NULL);
|
||||
const u64 *id = mdesc_get_property(hp, node, "id", NULL);
|
||||
|
||||
printk(KERN_ERR "VIO: Device remove (%s) ID[%lx]\n",
|
||||
name, *id);
|
||||
}
|
||||
|
||||
static struct mdesc_notifier_client vio_device_notifier = {
|
||||
.add = vio_add,
|
||||
.remove = vio_remove,
|
||||
.node_name = "virtual-device-port",
|
||||
};
|
||||
|
||||
static struct mdesc_notifier_client vio_ds_notifier = {
|
||||
.add = vio_add,
|
||||
.remove = vio_remove,
|
||||
.node_name = "domain-services-port",
|
||||
};
|
||||
|
||||
static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
|
||||
struct vio_dev *vdev)
|
||||
{
|
||||
@ -381,6 +411,9 @@ static int __init vio_init(void)
|
||||
|
||||
cdev_cfg_handle = *cfg_handle;
|
||||
|
||||
mdesc_register_notifier(&vio_device_notifier);
|
||||
mdesc_register_notifier(&vio_ds_notifier);
|
||||
|
||||
create_devices(hp, root);
|
||||
|
||||
mdesc_release(hp);
|
||||
|
@ -61,6 +61,16 @@ extern u64 mdesc_arc_target(struct mdesc_handle *hp, u64 arc);
|
||||
|
||||
extern void mdesc_update(void);
|
||||
|
||||
struct mdesc_notifier_client {
|
||||
void (*add)(struct mdesc_handle *handle, u64 node);
|
||||
void (*remove)(struct mdesc_handle *handle, u64 node);
|
||||
|
||||
const char *node_name;
|
||||
struct mdesc_notifier_client *next;
|
||||
};
|
||||
|
||||
extern void mdesc_register_notifier(struct mdesc_notifier_client *client);
|
||||
|
||||
extern void mdesc_fill_in_cpu_data(cpumask_t mask);
|
||||
|
||||
extern void sun4v_mdesc_init(void);
|
||||
|
Loading…
Reference in New Issue
Block a user