#include <linux/stringify.h>
#include <linux/delay.h>
#include <linux/initrd.h>
+#include <linux/bitops.h>
#include <asm/prom.h>
#include <asm/rtas.h>
#include <asm/lmb.h>
#include <asm/system.h>
#include <asm/mmu.h>
#include <asm/pgtable.h>
-#include <asm/bitops.h>
-#include <asm/naca.h>
#include <asm/pci.h>
#include <asm/iommu.h>
#include <asm/bootinfo.h>
#include <asm/btext.h>
#include <asm/sections.h>
#include <asm/machdep.h>
-#include "open_pic.h"
#ifdef DEBUG
#define DBG(fmt...) udbg_printf(fmt)
/* use when traversing tree through the allnext, child, sibling,
* or parent members of struct device_node.
*/
-static rwlock_t devtree_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(devtree_lock);
/* export that to outside world */
struct device_node *of_chosen;
if (rp != 0 && l >= sizeof(struct isa_reg_property)) {
i = 0;
adr = (struct address_range *) mem_start;
- while ((l -= sizeof(struct reg_property)) >= 0) {
+ while ((l -= sizeof(struct isa_reg_property)) >= 0) {
if (!measure_only) {
adr[i].space = rp[i].space;
adr[i].address = rp[i].address;
DBG(" -> finish_device_tree\n");
- if (naca->interrupt_controller == IC_INVALID) {
+ if (ppc64_interrupt_controller == IC_INVALID) {
DBG("failed to configure interrupt controller type\n");
panic("failed to configure interrupt controller type\n");
}
dad->next->sibling = np;
dad->next = np;
}
+ kref_init(&np->kref);
}
while(1) {
u32 sz, noff;
strlcpy(cmd_line, p, min(l, COMMAND_LINE_SIZE));
}
#ifdef CONFIG_CMDLINE
- if (l == 0) /* dbl check */
+ if (l == 0 || (l == 1 && (*p) == 0))
strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
#endif /* CONFIG_CMDLINE */
/* On LPAR, look for the first ibm,pft-size property for the hash table size
*/
- if (systemcfg->platform == PLATFORM_PSERIES_LPAR && naca->pftSize == 0) {
+ if (systemcfg->platform == PLATFORM_PSERIES_LPAR && ppc64_pft_size == 0) {
u32 *pft_size;
pft_size = (u32 *)get_flat_dt_prop(node, "ibm,pft-size", NULL);
if (pft_size != NULL) {
/* pft_size[0] is the NUMA CEC cookie */
- naca->pftSize = pft_size[1];
+ ppc64_pft_size = pft_size[1];
}
}
- /* Check if it's the boot-cpu, set it's hw index in paca now */
- if (get_flat_dt_prop(node, "linux,boot-cpu", NULL) != NULL) {
- u32 *prop = get_flat_dt_prop(node, "reg", NULL);
- paca[0].hw_cpu_id = prop == NULL ? 0 : *prop;
+ if (initial_boot_params && initial_boot_params->version >= 2) {
+ /* version 2 of the kexec param format adds the phys cpuid
+ * of booted proc.
+ */
+ boot_cpuid_phys = initial_boot_params->boot_cpuid_phys;
+ boot_cpuid = 0;
+ } else {
+ /* Check if it's the boot-cpu, set it's hw index in paca now */
+ if (get_flat_dt_prop(node, "linux,boot-cpu", NULL) != NULL) {
+ u32 *prop = get_flat_dt_prop(node, "reg", NULL);
+ set_hard_smp_processor_id(0, prop == NULL ? 0 : *prop);
+ boot_cpuid_phys = get_hard_smp_processor_id(0);
+ }
}
return 0;
initial_boot_params = params;
/* By default, hash size is not set */
- naca->pftSize = 0;
+ ppc64_pft_size = 0;
/* Retreive various informations from the /chosen node of the
* device-tree, including the platform type, initrd location and
scan_flat_dt(early_init_dt_scan_memory, NULL);
lmb_analyze();
systemcfg->physicalMemorySize = lmb_phys_mem_size();
+ lmb_reserve(0, __pa(klimit));
DBG("Phys. mem: %lx\n", systemcfg->physicalMemorySize);
/* If hash size wasn't obtained above, we calculate it now based on
* the total RAM size
*/
- if (naca->pftSize == 0) {
+ if (ppc64_pft_size == 0) {
unsigned long rnd_mem_size, pteg_count;
/* round mem_size up to next power of 2 */
rnd_mem_size <<= 1;
/* # pages / 2 */
- pteg_count = (rnd_mem_size >> (12 + 1));
+ pteg_count = max(rnd_mem_size >> (12 + 1), 1UL << 11);
- naca->pftSize = __ilog2(pteg_count << 7);
+ ppc64_pft_size = __ilog2(pteg_count << 7);
}
- DBG("Hash pftSize: %x\n", (int)naca->pftSize);
+ DBG("Hash pftSize: %x\n", (int)ppc64_pft_size);
DBG(" <- early_init_devtree()\n");
}
* Work out the sense (active-low level / active-high edge)
* of each interrupt from the device tree.
*/
-void __init
-prom_get_irq_senses(unsigned char *senses, int off, int max)
+void __init prom_get_irq_senses(unsigned char *senses, int off, int max)
{
struct device_node *np;
int i, j;
for (j = 0; j < np->n_intrs; j++) {
i = np->intrs[j].line;
if (i >= off && i < max)
- senses[i-off] = np->intrs[j].sense;
+ senses[i-off] = np->intrs[j].sense ?
+ IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE :
+ IRQ_SENSE_EDGE | IRQ_POLARITY_POSITIVE;
}
}
}
* @node: Node to inc refcount, NULL is supported to
* simplify writing of callers
*
- * Returns the node itself or NULL if gone.
+ * Returns node.
*/
struct device_node *of_node_get(struct device_node *node)
{
- if (node && !OF_IS_STALE(node)) {
- atomic_inc(&node->_users);
- return node;
- }
- return NULL;
+ if (node)
+ kref_get(&node->kref);
+ return node;
}
EXPORT_SYMBOL(of_node_get);
+static inline struct device_node * kref_to_device_node(struct kref *kref)
+{
+ return container_of(kref, struct device_node, kref);
+}
+
/**
- * of_node_cleanup - release a dynamically allocated node
- * @arg: Node to be released
+ * of_node_release - release a dynamically allocated node
+ * @kref: kref element of the node to be released
+ *
+ * In of_node_put() this function is passed to kref_put()
+ * as the destructor.
*/
-static void of_node_cleanup(struct device_node *node)
+static void of_node_release(struct kref *kref)
{
+ struct device_node *node = kref_to_device_node(kref);
struct property *prop = node->properties;
if (!OF_IS_DYNAMIC(node))
*/
void of_node_put(struct device_node *node)
{
- if (!node)
- return;
-
- WARN_ON(0 == atomic_read(&node->_users));
-
- if (OF_IS_STALE(node)) {
- if (atomic_dec_and_test(&node->_users)) {
- of_node_cleanup(node);
- return;
- }
- }
- else
- atomic_dec(&node->_users);
+ if (node)
+ kref_put(&node->kref, of_node_release);
}
EXPORT_SYMBOL(of_node_put);
node->devfn = (regs[0] >> 8) & 0xff;
}
- /* fixing up iommu_table */
-
-#ifdef CONFIG_PPC_PSERIES
- if (strcmp(node->name, "pci") == 0 &&
- get_property(node, "ibm,dma-window", NULL)) {
- node->bussubno = node->busno;
- iommu_devnode_init(node);
- } else
- node->iommu_table = parent->iommu_table;
-#endif /* CONFIG_PPC_PSERIES */
-
out:
of_node_put(parent);
return err;
np->properties = proplist;
OF_MARK_DYNAMIC(np);
+ kref_init(&np->kref);
of_node_get(np);
np->parent = derive_parent(path);
if (!np->parent) {
}
/*
- * Remove an OF device node from the system.
- * Caller should have already "gotten" np.
+ * Prepare an OF node for removal from system
+ */
+static void of_cleanup_node(struct device_node *np)
+{
+ if (np->iommu_table && get_property(np, "ibm,dma-window", NULL))
+ iommu_free_table(np);
+}
+
+/*
+ * "Unplug" a node from the device tree. The caller must hold
+ * a reference to the node. The memory associated with the node
+ * is not freed until its refcount goes to zero.
*/
int of_remove_node(struct device_node *np)
{
return -EBUSY;
}
+ of_cleanup_node(np);
+
write_lock(&devtree_lock);
- OF_MARK_STALE(np);
remove_node_proc_entries(np);
if (allnodes == np)
allnodes = np->allnext;
}
write_unlock(&devtree_lock);
of_node_put(parent);
+ of_node_put(np); /* Must decrement the refcount */
return 0;
}