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