示例#1
0
/*
 * MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is
 * OK to have direct references to sparsemem variables in here.
 */
static int
memory_block_action(unsigned long phys_index, unsigned long action)
{
	unsigned long start_pfn, start_paddr;
	unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block;
	struct page *first_page;
	int ret;

	first_page = pfn_to_page(phys_index << PFN_SECTION_SHIFT);

	switch (action) {
		case MEM_ONLINE:
			start_pfn = page_to_pfn(first_page);

			if (!pages_correctly_reserved(start_pfn, nr_pages))
				return -EBUSY;

			ret = online_pages(start_pfn, nr_pages);
			break;
		case MEM_OFFLINE:
			start_paddr = page_to_pfn(first_page) << PAGE_SHIFT;
			ret = remove_memory(start_paddr,
					    nr_pages << PAGE_SHIFT);
			break;
		default:
			WARN(1, KERN_WARNING "%s(%ld, %ld) unknown action: "
			     "%ld\n", __func__, phys_index, action, action);
			ret = -EINVAL;
	}

	return ret;
}
示例#2
0
static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)
{
	int result;
	u64 start = mem_device->start_addr;
	u64 len = mem_device->end_addr - start + 1;
	unsigned long attr = mem_device->read_write_attribute;

	ACPI_FUNCTION_TRACE("acpi_memory_disable_device");

	/*
	 * Ask the VM to offline this memory range.
	 * Note: Assume that this function returns zero on success
	 */
	result = remove_memory(start, len, attr);
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Hot-Remove failed.\n"));
		return_VALUE(result);
	}

	/* Power-off and eject the device */
	result = acpi_memory_powerdown_device(mem_device);
	if (result) {
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "Device Power Down failed.\n"));
		/* Set the status of the device to invalid */
		mem_device->state = MEMORY_INVALID_STATE;
		return result;
	}

	mem_device->state = MEMORY_POWER_OFF_STATE;
	return result;
}
示例#3
0
static int pseries_remove_memblock(unsigned long base, unsigned int memblock_size)
{
    unsigned long block_sz, start_pfn;
    int sections_per_block;
    int i, nid;

    start_pfn = base >> PAGE_SHIFT;

    lock_device_hotplug();

    if (!pfn_valid(start_pfn))
        goto out;

    block_sz = pseries_memory_block_size();
    sections_per_block = block_sz / MIN_MEMORY_BLOCK_SIZE;
    nid = memory_add_physaddr_to_nid(base);

    for (i = 0; i < sections_per_block; i++) {
        remove_memory(nid, base, MIN_MEMORY_BLOCK_SIZE);
        base += MIN_MEMORY_BLOCK_SIZE;
    }

out:
    /* Update memory regions for memory remove */
    memblock_remove(base, memblock_size);
    unlock_device_hotplug();
    return 0;
}
示例#4
0
static int dlpar_remove_lmb(struct of_drconf_cell *lmb)
{
	struct memory_block *mem_block;
	unsigned long block_sz;
	int nid, rc;

	if (!lmb_is_removable(lmb))
		return -EINVAL;

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

	rc = device_offline(&mem_block->dev);
	put_device(&mem_block->dev);
	if (rc)
		return rc;

	block_sz = pseries_memory_block_size();
	nid = memory_add_physaddr_to_nid(lmb->base_addr);

	remove_memory(nid, lmb->base_addr, block_sz);

	/* Update memory regions for memory remove */
	memblock_remove(lmb->base_addr, block_sz);

	dlpar_remove_device_tree_lmb(lmb);
	return 0;
}
示例#5
0
/*
 * MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is
 * OK to have direct references to sparsemem variables in here.
 */
static int
memory_block_action(struct memory_block *mem, unsigned long action)
{
	int i;
	unsigned long psection;
	unsigned long start_pfn, start_paddr;
	struct page *first_page;
	int ret;
	int old_state = mem->state;

	psection = mem->phys_index;
	first_page = pfn_to_page(psection << PFN_SECTION_SHIFT);

	/*
	 * The probe routines leave the pages reserved, just
	 * as the bootmem code does.  Make sure they're still
	 * that way.
	 */
	if (action == MEM_ONLINE) {
		for (i = 0; i < PAGES_PER_SECTION; i++) {
			if (PageReserved(first_page+i))
				continue;

			printk(KERN_WARNING "section number %ld page number %d "
				"not reserved, was it already online? \n",
				psection, i);
			return -EBUSY;
		}
	}

	switch (action) {
		case MEM_ONLINE:
			start_pfn = page_to_pfn(first_page);
			ret = online_pages(start_pfn, PAGES_PER_SECTION);
			break;
		case MEM_OFFLINE:
			mem->state = MEM_GOING_OFFLINE;
			start_paddr = page_to_pfn(first_page) << PAGE_SHIFT;
			ret = remove_memory(start_paddr,
					    PAGES_PER_SECTION << PAGE_SHIFT);
			if (ret) {
				mem->state = old_state;
				break;
			}
			break;
		default:
			WARN(1, KERN_WARNING "%s(%p, %ld) unknown action: %ld\n",
					__func__, mem, action, action);
			ret = -EINVAL;
	}

	return ret;
}
示例#6
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;
}
/*
 * MEMORY_HOTPLUG depends on SPARSEMEM in mm/Kconfig, so it is
 * OK to have direct references to sparsemem variables in here.
 */
static int
memory_block_action(unsigned long phys_index, unsigned long action)
{
	int i;
	unsigned long start_pfn, start_paddr;
	unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block;
	struct page *first_page;
	int ret;

	first_page = pfn_to_page(phys_index << PFN_SECTION_SHIFT);

	/*
	 * The probe routines leave the pages reserved, just
	 * as the bootmem code does.  Make sure they're still
	 * that way.
	 */
	if (action == MEM_ONLINE) {
		for (i = 0; i < nr_pages; i++) {
			if (page_is_ram(page_to_pfn(first_page+i))) {
				if (PageReserved(first_page+i))
					continue;
					printk(KERN_WARNING
						"section number %ld page number"
						" %d not reserved, was it "
						" already online?\n",
						phys_index, i);
					return -EBUSY;
			}
		}
	}

	switch (action) {
		case MEM_ONLINE:
			start_pfn = page_to_pfn(first_page);
			ret = online_pages(start_pfn, nr_pages);
			break;
		case MEM_OFFLINE:
			start_paddr = page_to_pfn(first_page) << PAGE_SHIFT;
			ret = remove_memory(start_paddr,
					    nr_pages << PAGE_SHIFT);
			break;
		default:
			WARN(1, KERN_WARNING "%s(%ld, %ld) unknown action: "
			     "%ld\n", __func__, phys_index, action, action);
			ret = -EINVAL;
	}

	return ret;
}
示例#8
0
static int dlpar_add_lmb(struct of_drconf_cell *lmb)
{
	unsigned long block_sz;
	int nid, rc;

	if (lmb->flags & DRCONF_MEM_ASSIGNED)
		return -EINVAL;

	rc = dlpar_add_device_tree_lmb(lmb);
	if (rc) {
		pr_err("Couldn't update device tree for drc index %x\n",
		       lmb->drc_index);
		dlpar_release_drc(lmb->drc_index);
		return 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) {
		dlpar_remove_device_tree_lmb(lmb);
		return rc;
	}

	rc = dlpar_online_lmb(lmb);
	if (rc) {
		remove_memory(nid, lmb->base_addr, block_sz);
		dlpar_remove_device_tree_lmb(lmb);
	} else {
		lmb->flags |= DRCONF_MEM_ASSIGNED;
	}

	return rc;
}