Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 31bdc5dc authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6

* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6:
  [SPARC64]: Set vio->desc_buf to NULL after freeing.
  [SPARC]: Mark sparc and sparc64 as not having virt_to_bus
  [SPARC64]: Fix reset handling in VNET driver.
  [SPARC64]: Handle reset events in vio_link_state_change().
  [SPARC64]: Handle LDC resets properly in domain-services driver.
  [SPARC64]: Massively simplify VIO device layer and support hot add/remove.
  [SPARC64]: Simplify VNET probing.
  [SPARC64]: Simplify VDC device probing.
  [SPARC64]: Add basic infrastructure for MD add/remove notification.
parents 5cc97bf2 a5f8967e
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -21,6 +21,9 @@ config GENERIC_ISA_DMA
	bool
	default y

config ARCH_NO_VIRT_TO_BUS
	def_bool y

source "init/Kconfig"

menu "General machine setup"
+3 −0
Original line number Diff line number Diff line
@@ -62,6 +62,9 @@ config AUDIT_ARCH
	bool
	default y

config ARCH_NO_VIRT_TO_BUS
	def_bool y

choice
	prompt "Kernel page size"
	default SPARC64_PAGE_SIZE_8KB
+19 −0
Original line number Diff line number Diff line
@@ -1013,6 +1013,19 @@ static void ds_up(struct ds_info *dp)
		dp->hs_state = DS_HS_START;
}

static void ds_reset(struct ds_info *dp)
{
	int i;

	dp->hs_state = 0;

	for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
		struct ds_cap_state *cp = &ds_states[i];

		cp->state = CAP_STATE_UNKNOWN;
	}
}

static void ds_event(void *arg, int event)
{
	struct ds_info *dp = arg;
@@ -1028,6 +1041,12 @@ static void ds_event(void *arg, int event)
		return;
	}

	if (event == LDC_EVENT_RESET) {
		ds_reset(dp);
		spin_unlock_irqrestore(&ds_lock, flags);
		return;
	}

	if (event != LDC_EVENT_DATA_READY) {
		printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event);
		spin_unlock_irqrestore(&ds_lock, flags);
+75 −3
Original line number Diff line number Diff line
@@ -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)
+61 −33
Original line number Diff line number Diff line
@@ -201,10 +201,11 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
				      struct device *parent)
{
	const char *type, *compat;
	const char *type, *compat, *bus_id_name;
	struct device_node *dp;
	struct vio_dev *vdev;
	int err, tlen, clen;
	const u64 *id;

	type = mdesc_get_property(hp, mp, "device-type", &tlen);
	if (!type) {
@@ -220,6 +221,16 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
		return NULL;
	}

	bus_id_name = type;
	if (!strcmp(type, "domain-services-port"))
		bus_id_name = "ds";

	if (strlen(bus_id_name) >= KOBJ_NAME_LEN - 4) {
		printk(KERN_ERR "VIO: bus_id_name [%s] is too long.\n",
		       bus_id_name);
		return NULL;
	}

	compat = mdesc_get_property(hp, mp, "device-type", &clen);
	if (!compat) {
		clen = 0;
@@ -249,7 +260,14 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,

	vio_fill_channel_info(hp, mp, vdev);

	snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%lx", mp);
	id = mdesc_get_property(hp, mp, "id", NULL);
	if (!id)
		snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s",
			 bus_id_name);
	else
		snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu",
			 bus_id_name, *id);

	vdev->dev.parent = parent;
	vdev->dev.bus = &vio_bus_type;
	vdev->dev.release = vio_dev_release;
@@ -269,6 +287,8 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
	}
	vdev->dp = dp;

	printk(KERN_ERR "VIO: Adding device %s\n", vdev->dev.bus_id);

	err = device_register(&vdev->dev);
	if (err) {
		printk(KERN_ERR "VIO: Could not register device %s, err=%d\n",
@@ -283,46 +303,46 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
	return vdev;
}

static void walk_tree(struct mdesc_handle *hp, u64 n, struct vio_dev *parent)
static void vio_add(struct mdesc_handle *hp, u64 node)
{
	u64 a;

	mdesc_for_each_arc(a, hp, n, MDESC_ARC_TYPE_FWD) {
		struct vio_dev *vdev;
		u64 target;

		target = mdesc_arc_target(hp, a);
		vdev = vio_create_one(hp, target, &parent->dev);
		if (vdev)
			walk_tree(hp, target, vdev);
	}
	(void) vio_create_one(hp, node, &root_vdev->dev);
}

static void create_devices(struct mdesc_handle *hp, u64 root)
static int vio_md_node_match(struct device *dev, void *arg)
{
	u64 mp;
	struct vio_dev *vdev = to_vio_dev(dev);

	root_vdev = vio_create_one(hp, root, NULL);
	if (!root_vdev) {
		printk(KERN_ERR "VIO: Coult not create root device.\n");
		return;
	if (vdev->mp == (u64) arg)
		return 1;

	return 0;
}

	walk_tree(hp, root, root_vdev);
static void vio_remove(struct mdesc_handle *hp, u64 node)
{
	struct device *dev;

	/* Domain services is odd as it doesn't sit underneath the
	 * channel-devices node, so we plug it in manually.
	 */
	mp = mdesc_node_by_name(hp, MDESC_NODE_NULL, "domain-services");
	if (mp != MDESC_NODE_NULL) {
		struct vio_dev *parent = vio_create_one(hp, mp,
							&root_vdev->dev);
	dev = device_find_child(&root_vdev->dev, (void *) node,
				vio_md_node_match);
	if (dev) {
		printk(KERN_INFO "VIO: Removing device %s\n", dev->bus_id);

		if (parent)
			walk_tree(hp, mp, parent);
		device_unregister(dev);
	}
}

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",
};

const char *channel_devices_node = "channel-devices";
const char *channel_devices_compat = "SUNW,sun4v-channel-devices";
const char *cfg_handle_prop = "cfg-handle";
@@ -381,11 +401,19 @@ static int __init vio_init(void)

	cdev_cfg_handle = *cfg_handle;

	create_devices(hp, root);
	root_vdev = vio_create_one(hp, root, NULL);
	err = -ENODEV;
	if (!root_vdev) {
		printk(KERN_ERR "VIO: Coult not create root device.\n");
		goto out_release;
	}

	mdesc_register_notifier(&vio_device_notifier);
	mdesc_register_notifier(&vio_ds_notifier);

	mdesc_release(hp);

	return 0;
	return err;

out_release:
	mdesc_release(hp);
Loading