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

Commit 1cf3d8b3 authored by Nathan Fontenot's avatar Nathan Fontenot Committed by Benjamin Herrenschmidt
Browse files

powerpc+of: Add of node/property notification chain for adds and removes



This patch moves the notification chain for updates to the device tree
from the powerpc/pseries code to the base OF code. This makes this
functionality available to all architectures.

Additionally the notification chain is updated to allow notifications
for property add/remove/update. To make this work a pointer to a new
struct (of_prop_reconfig) is passed to the routines in the notification chain.
The of_prop_reconfig property contains a pointer to the node containing the
property and a pointer to the property itself. In the case of property
updates, the property pointer refers to the new property.

Signed-off-by: default avatarNathan Fontenot <nfont@linux.vnet.ibm.com>
Acked-by: default avatarRob Herring <rob.herring@calxeda.com>
Acked-by: default avatarGrant Likely <grant.likely@secretlab.ca>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent f5949720
Loading
Loading
Loading
Loading
+0 −32
Original line number Diff line number Diff line
@@ -2,43 +2,11 @@
#define _PPC64_PSERIES_RECONFIG_H
#ifdef __KERNEL__

#include <linux/notifier.h>

/*
 * Use this API if your code needs to know about OF device nodes being
 * added or removed on pSeries systems.
 */

#define PSERIES_RECONFIG_ADD		0x0001
#define PSERIES_RECONFIG_REMOVE		0x0002
#define PSERIES_DRCONF_MEM_ADD		0x0003
#define PSERIES_DRCONF_MEM_REMOVE	0x0004
#define PSERIES_UPDATE_PROPERTY		0x0005

/**
 * pSeries_reconfig_notify - Notifier value structure for OFDT property updates
 *
 * @node: Device tree node which owns the property being updated
 * @property: Updated property
 */
struct pSeries_reconfig_prop_update {
	struct device_node *node;
	struct property *property;
};

#ifdef CONFIG_PPC_PSERIES
extern int pSeries_reconfig_notifier_register(struct notifier_block *);
extern void pSeries_reconfig_notifier_unregister(struct notifier_block *);
extern int pSeries_reconfig_notify(unsigned long action, void *p);
/* Not the best place to put this, will be fixed when we move some
 * of the rtas suspend-me stuff to pseries */
extern void pSeries_coalesce_init(void);
#else /* !CONFIG_PPC_PSERIES */
static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb)
{
	return 0;
}
static inline void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { }
static inline void pSeries_coalesce_init(void) { }
#endif /* CONFIG_PPC_PSERIES */

+3 −3
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
#include <linux/debugfs.h>
#include <linux/irq.h>
#include <linux/memblock.h>
#include <linux/of.h>

#include <asm/prom.h>
#include <asm/rtas.h>
@@ -49,7 +50,6 @@
#include <asm/btext.h>
#include <asm/sections.h>
#include <asm/machdep.h>
#include <asm/pSeries_reconfig.h>
#include <asm/pci-bridge.h>
#include <asm/kexec.h>
#include <asm/opal.h>
@@ -802,7 +802,7 @@ static int prom_reconfig_notifier(struct notifier_block *nb,
	int err;

	switch (action) {
	case PSERIES_RECONFIG_ADD:
	case OF_RECONFIG_ATTACH_NODE:
		err = of_finish_dynamic_node(node);
		if (err < 0)
			printk(KERN_ERR "finish_node returned %d\n", err);
@@ -821,7 +821,7 @@ static struct notifier_block prom_reconfig_nb = {

static int __init prom_reconfig_setup(void)
{
	return pSeries_reconfig_notifier_register(&prom_reconfig_nb);
	return of_reconfig_notifier_register(&prom_reconfig_nb);
}
__initcall(prom_reconfig_setup);
#endif
+8 −6
Original line number Diff line number Diff line
@@ -16,13 +16,13 @@
#include <linux/spinlock.h>
#include <linux/cpu.h>
#include <linux/slab.h>
#include <linux/of.h>
#include "offline_states.h"

#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/uaccess.h>
#include <asm/rtas.h>
#include <asm/pSeries_reconfig.h>

struct cc_workarea {
	u32	drc_index;
@@ -262,24 +262,26 @@ int dlpar_attach_node(struct device_node *dn)
	if (!dn->parent)
		return -ENOMEM;

	rc = pSeries_reconfig_notify(PSERIES_RECONFIG_ADD, dn);
	rc = of_attach_node(dn);
	if (rc) {
		printk(KERN_ERR "Failed to add device node %s\n",
		       dn->full_name);
		return rc;
	}

	of_attach_node(dn);
	of_node_put(dn->parent);
	return 0;
}

int dlpar_detach_node(struct device_node *dn)
{
	pSeries_reconfig_notify(PSERIES_RECONFIG_REMOVE, dn);
	of_detach_node(dn);
	of_node_put(dn); /* Must decrement the refcount */
	int rc;

	rc = of_detach_node(dn);
	if (rc)
		return rc;

	of_node_put(dn); /* Must decrement the refcount */
	return 0;
}

+4 −4
Original line number Diff line number Diff line
@@ -23,12 +23,12 @@
#include <linux/delay.h>
#include <linux/sched.h>	/* for idle_task_exit */
#include <linux/cpu.h>
#include <linux/of.h>
#include <asm/prom.h>
#include <asm/rtas.h>
#include <asm/firmware.h>
#include <asm/machdep.h>
#include <asm/vdso_datapage.h>
#include <asm/pSeries_reconfig.h>
#include <asm/xics.h>
#include "plpar_wrappers.h"
#include "offline_states.h"
@@ -333,10 +333,10 @@ static int pseries_smp_notifier(struct notifier_block *nb,
	int err = 0;

	switch (action) {
	case PSERIES_RECONFIG_ADD:
	case OF_RECONFIG_ATTACH_NODE:
		err = pseries_add_processor(node);
		break;
	case PSERIES_RECONFIG_REMOVE:
	case OF_RECONFIG_DETACH_NODE:
		pseries_remove_processor(node);
		break;
	}
@@ -399,7 +399,7 @@ static int __init pseries_cpu_hotplug_init(void)

	/* Processors can be added/removed only on LPAR */
	if (firmware_has_feature(FW_FEATURE_LPAR)) {
		pSeries_reconfig_notifier_register(&pseries_smp_nb);
		of_reconfig_notifier_register(&pseries_smp_nb);
		cpu_maps_update_begin();
		if (cede_offline_enabled && parse_cede_parameters() == 0) {
			default_offline_state = CPU_STATE_INACTIVE;
+43 −17
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

#include <asm/firmware.h>
#include <asm/machdep.h>
#include <asm/pSeries_reconfig.h>
#include <asm/sparsemem.h>

static unsigned long get_memblock_size(void)
@@ -187,22 +186,47 @@ static int pseries_add_memory(struct device_node *np)
	return (ret < 0) ? -EINVAL : 0;
}

static int pseries_drconf_memory(unsigned long *base, unsigned int action)
static int pseries_update_drconf_memory(struct of_prop_reconfig *pr)
{
	struct of_drconf_cell *new_drmem, *old_drmem;
	unsigned long memblock_size;
	int rc;
	u32 entries;
	u32 *p;
	int i, rc = -EINVAL;

	memblock_size = get_memblock_size();
	if (!memblock_size)
		return -EINVAL;

	if (action == PSERIES_DRCONF_MEM_ADD) {
		rc = memblock_add(*base, memblock_size);
	p = (u32 *)of_get_property(pr->dn, "ibm,dynamic-memory", NULL);
	if (!p)
		return -EINVAL;

	/* The first int of the property is the number of lmb's described
	 * by the property. This is followed by an array of of_drconf_cell
	 * entries. Get the niumber of entries and skip to the array of
	 * of_drconf_cell's.
	 */
	entries = *p++;
	old_drmem = (struct of_drconf_cell *)p;

	p = (u32 *)pr->prop->value;
	p++;
	new_drmem = (struct of_drconf_cell *)p;

	for (i = 0; i < entries; i++) {
		if ((old_drmem[i].flags & DRCONF_MEM_ASSIGNED) &&
		    (!(new_drmem[i].flags & DRCONF_MEM_ASSIGNED))) {
			rc = pseries_remove_memblock(old_drmem[i].base_addr,
						     memblock_size);
			break;
		} else if ((!(old_drmem[i].flags & DRCONF_MEM_ASSIGNED)) &&
			   (new_drmem[i].flags & DRCONF_MEM_ASSIGNED)) {
			rc = memblock_add(old_drmem[i].base_addr,
					  memblock_size);
			rc = (rc < 0) ? -EINVAL : 0;
	} else if (action == PSERIES_DRCONF_MEM_REMOVE) {
		rc = pseries_remove_memblock(*base, memblock_size);
	} else {
		rc = -EINVAL;
			break;
		}
	}

	return rc;
@@ -211,18 +235,20 @@ static int pseries_drconf_memory(unsigned long *base, unsigned int action)
static int pseries_memory_notifier(struct notifier_block *nb,
				   unsigned long action, void *node)
{
	struct of_prop_reconfig *pr;
	int err = 0;

	switch (action) {
	case PSERIES_RECONFIG_ADD:
	case OF_RECONFIG_ATTACH_NODE:
		err = pseries_add_memory(node);
		break;
	case PSERIES_RECONFIG_REMOVE:
	case OF_RECONFIG_DETACH_NODE:
		err = pseries_remove_memory(node);
		break;
	case PSERIES_DRCONF_MEM_ADD:
	case PSERIES_DRCONF_MEM_REMOVE:
		err = pseries_drconf_memory(node, action);
	case OF_RECONFIG_UPDATE_PROPERTY:
		pr = (struct of_prop_reconfig *)node;
		if (!strcmp(pr->prop->name, "ibm,dynamic-memory"))
			err = pseries_update_drconf_memory(pr);
		break;
	}
	return notifier_from_errno(err);
@@ -235,7 +261,7 @@ static struct notifier_block pseries_mem_nb = {
static int __init pseries_memory_hotplug_init(void)
{
	if (firmware_has_feature(FW_FEATURE_LPAR))
		pSeries_reconfig_notifier_register(&pseries_mem_nb);
		of_reconfig_notifier_register(&pseries_mem_nb);

	return 0;
}
Loading