Beispiel #1
0
static ssize_t
store_mem_state(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	struct memory_block *mem = to_memory_block(dev);
	int ret, online_type;

	ret = lock_device_hotplug_sysfs();
	if (ret)
		return ret;

	if (sysfs_streq(buf, "online_kernel"))
		online_type = MMOP_ONLINE_KERNEL;
	else if (sysfs_streq(buf, "online_movable"))
		online_type = MMOP_ONLINE_MOVABLE;
	else if (sysfs_streq(buf, "online"))
		online_type = MMOP_ONLINE_KEEP;
	else if (sysfs_streq(buf, "offline"))
		online_type = MMOP_OFFLINE;
	else {
		ret = -EINVAL;
		goto err;
	}

	/*
	 * Memory hotplug needs to hold mem_hotplug_begin() for probe to find
	 * the correct memory block to online before doing device_online(dev),
	 * which will take dev->mutex.  Take the lock early to prevent an
	 * inversion, memory_subsys_online() callbacks will be implemented by
	 * assuming it's already protected.
	 */
	mem_hotplug_begin();

	switch (online_type) {
	case MMOP_ONLINE_KERNEL:
	case MMOP_ONLINE_MOVABLE:
	case MMOP_ONLINE_KEEP:
		mem->online_type = online_type;
		ret = device_online(&mem->dev);
		break;
	case MMOP_OFFLINE:
		ret = device_offline(&mem->dev);
		break;
	default:
		ret = -EINVAL; /* should never happen */
	}

	mem_hotplug_done();
err:
	unlock_device_hotplug();

	if (ret)
		return ret;
	return count;
}
Beispiel #2
0
static ssize_t
store_mem_state(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t count)
{
	struct memory_block *mem = to_memory_block(dev);
	int ret, online_type;

	ret = lock_device_hotplug_sysfs();
	if (ret)
		return ret;

	if (sysfs_streq(buf, "online_kernel"))
		online_type = MMOP_ONLINE_KERNEL;
	else if (sysfs_streq(buf, "online_movable"))
		online_type = MMOP_ONLINE_MOVABLE;
	else if (sysfs_streq(buf, "online"))
		online_type = MMOP_ONLINE_KEEP;
	else if (sysfs_streq(buf, "offline"))
		online_type = MMOP_OFFLINE;
	else {
		ret = -EINVAL;
		goto err;
	}

	switch (online_type) {
	case MMOP_ONLINE_KERNEL:
	case MMOP_ONLINE_MOVABLE:
	case MMOP_ONLINE_KEEP:
		/*
		 * mem->online_type is not protected so there can be a
		 * race here.  However, when racing online, the first
		 * will succeed and the second will just return as the
		 * block will already be online.  The online type
		 * could be either one, but that is expected.
		 */
		mem->online_type = online_type;
		ret = device_online(&mem->dev);
		break;
	case MMOP_OFFLINE:
		ret = device_offline(&mem->dev);
		break;
	default:
		ret = -EINVAL; /* should never happen */
	}

err:
	unlock_device_hotplug();

	if (ret)
		return ret;
	return count;
}
Beispiel #3
0
static int dlpar_online_lmb(struct of_drconf_cell *lmb)
{
	struct memory_block *mem_block;
	int rc;

	mem_block = lmb_to_memblock(lmb);
	if (!mem_block)
		return -EINVAL;

	rc = device_online(&mem_block->dev);
	put_device(&mem_block->dev);
	return rc;
}
Beispiel #4
0
static int dlpar_online_cpu(struct device_node *dn)
{
	int rc = 0;
	unsigned int cpu;
	int len, nthreads, i;
	const __be32 *intserv;
	u32 thread;

	intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len);
	if (!intserv)
		return -EINVAL;

	nthreads = len / sizeof(u32);

	cpu_maps_update_begin();
	for (i = 0; i < nthreads; i++) {
		thread = be32_to_cpu(intserv[i]);
		for_each_present_cpu(cpu) {
			if (get_hard_smp_processor_id(cpu) != thread)
				continue;
			BUG_ON(get_cpu_current_state(cpu)
					!= CPU_STATE_OFFLINE);
			cpu_maps_update_done();
			timed_topology_update(1);
			find_and_online_cpu_nid(cpu);
			rc = device_online(get_cpu_device(cpu));
			if (rc)
				goto out;
			cpu_maps_update_begin();

			break;
		}
		if (cpu == num_possible_cpus())
			printk(KERN_WARNING "Could not find cpu to online "
			       "with physical id 0x%x\n", thread);
	}
	cpu_maps_update_done();

out:
	return rc;

}
Beispiel #5
0
static int dlpar_add_lmb_memory(struct of_drconf_cell *lmb)
{
	struct memory_block *mem_block;
	unsigned long block_sz;
	int nid, rc;

	block_sz = memory_block_size_bytes();

	/* Find the node id for this address */
	nid = memory_add_physaddr_to_nid(lmb->base_addr);

	/* Add the memory */
	rc = add_memory(nid, lmb->base_addr, block_sz);
	if (rc)
		return rc;

	/* Register this block of memory */
	rc = memblock_add(lmb->base_addr, block_sz);
	if (rc) {
		remove_memory(nid, lmb->base_addr, block_sz);
		return rc;
	}

	mem_block = lmb_to_memblock(lmb);
	if (!mem_block) {
		remove_memory(nid, lmb->base_addr, block_sz);
		return -EINVAL;
	}

	rc = device_online(&mem_block->dev);
	put_device(&mem_block->dev);
	if (rc) {
		remove_memory(nid, lmb->base_addr, block_sz);
		return rc;
	}

	lmb->flags |= DRCONF_MEM_ASSIGNED;
	return 0;
}