summaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2007-10-12 21:27:47 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2007-10-12 21:27:47 -0400
commitb981d8b3f5e008ff10d993be633ad00564fc22cd (patch)
treee292dc07b22308912cf6a58354a608b9e5e8e1fd /arch/sparc64/kernel
parentb11d2127c4893a7315d1e16273bc8560049fa3ca (diff)
parent2b9e0aae1d50e880c58d46788e5e3ebd89d75d62 (diff)
Merge master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts: drivers/macintosh/adbhid.c
Diffstat (limited to 'arch/sparc64/kernel')
-rw-r--r--arch/sparc64/kernel/Makefile4
-rw-r--r--arch/sparc64/kernel/auxio.c2
-rw-r--r--arch/sparc64/kernel/binfmt_aout32.c4
-rw-r--r--arch/sparc64/kernel/cpu.c36
-rw-r--r--arch/sparc64/kernel/ds.c270
-rw-r--r--arch/sparc64/kernel/ebus.c12
-rw-r--r--arch/sparc64/kernel/head.S168
-rw-r--r--arch/sparc64/kernel/hvtramp.S7
-rw-r--r--arch/sparc64/kernel/init_task.c1
-rw-r--r--arch/sparc64/kernel/iommu.c (renamed from arch/sparc64/kernel/pci_iommu.c)304
-rw-r--r--arch/sparc64/kernel/irq.c177
-rw-r--r--arch/sparc64/kernel/isa.c7
-rw-r--r--arch/sparc64/kernel/mdesc.c200
-rw-r--r--arch/sparc64/kernel/of_device.c243
-rw-r--r--arch/sparc64/kernel/pci.c91
-rw-r--r--arch/sparc64/kernel/pci_common.c127
-rw-r--r--arch/sparc64/kernel/pci_fire.c24
-rw-r--r--arch/sparc64/kernel/pci_psycho.c32
-rw-r--r--arch/sparc64/kernel/pci_sabre.c35
-rw-r--r--arch/sparc64/kernel/pci_schizo.c42
-rw-r--r--arch/sparc64/kernel/pci_sun4v.c190
-rw-r--r--arch/sparc64/kernel/power.c68
-rw-r--r--arch/sparc64/kernel/process.c7
-rw-r--r--arch/sparc64/kernel/prom.c253
-rw-r--r--arch/sparc64/kernel/sbus.c568
-rw-r--r--arch/sparc64/kernel/setup.c70
-rw-r--r--arch/sparc64/kernel/smp.c7
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c3
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c12
-rw-r--r--arch/sparc64/kernel/systbls.S11
-rw-r--r--arch/sparc64/kernel/time.c210
-rw-r--r--arch/sparc64/kernel/trampoline.S47
-rw-r--r--arch/sparc64/kernel/traps.c18
-rw-r--r--arch/sparc64/kernel/us2e_cpufreq.c1
-rw-r--r--arch/sparc64/kernel/vio.c156
-rw-r--r--arch/sparc64/kernel/viohs.c32
-rw-r--r--arch/sparc64/kernel/vmlinux.lds.S8
37 files changed, 1665 insertions, 1782 deletions
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index b66876bf410..40d2f3aae91 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -8,14 +8,14 @@ EXTRA_CFLAGS := -Werror
extra-y := head.o init_task.o vmlinux.lds
obj-y := process.o setup.o cpu.o idprom.o \
- traps.o auxio.o una_asm.o sysfs.o \
+ traps.o auxio.o una_asm.o sysfs.o iommu.o \
irq.o ptrace.o time.o sys_sparc.o signal.o \
unaligned.o central.o pci.o starfire.o semaphore.o \
power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \
visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
-obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.o \
+obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o \
pci_psycho.o pci_sabre.o pci_schizo.o \
pci_sun4v.o pci_sun4v_asm.o pci_fire.o
obj-$(CONFIG_SMP) += smp.o trampoline.o hvtramp.o
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
index 826118ee53d..7b379761e9f 100644
--- a/arch/sparc64/kernel/auxio.c
+++ b/arch/sparc64/kernel/auxio.c
@@ -155,7 +155,7 @@ static struct of_platform_driver auxio_driver = {
static int __init auxio_init(void)
{
- return of_register_driver(&auxio_driver, &of_bus_type);
+ return of_register_driver(&auxio_driver, &of_platform_bus_type);
}
/* Must be after subsys_initcall() so that busses are probed. Must
diff --git a/arch/sparc64/kernel/binfmt_aout32.c b/arch/sparc64/kernel/binfmt_aout32.c
index f205fc7cbcd..d208cc7804f 100644
--- a/arch/sparc64/kernel/binfmt_aout32.c
+++ b/arch/sparc64/kernel/binfmt_aout32.c
@@ -177,7 +177,7 @@ static u32 __user *create_aout32_tables(char __user *p, struct linux_binprm *bpr
get_user(c,p++);
} while (c);
}
- put_user(NULL,argv);
+ put_user(0,argv);
current->mm->arg_end = current->mm->env_start = (unsigned long) p;
while (envc-->0) {
char c;
@@ -186,7 +186,7 @@ static u32 __user *create_aout32_tables(char __user *p, struct linux_binprm *bpr
get_user(c,p++);
} while (c);
}
- put_user(NULL,envp);
+ put_user(0,envp);
current->mm->env_end = (unsigned long) p;
return sp;
}
diff --git a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
index 7eb81d3954d..e43db73f2b9 100644
--- a/arch/sparc64/kernel/cpu.c
+++ b/arch/sparc64/kernel/cpu.c
@@ -1,7 +1,7 @@
/* cpu.c: Dinky routines to look for the kind of Sparc cpu
* we are on.
*
- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996, 2007 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
@@ -13,6 +13,7 @@
#include <asm/fpumacro.h>
#include <asm/cpudata.h>
#include <asm/spitfire.h>
+#include <asm/oplib.h>
DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 };
@@ -61,21 +62,40 @@ struct cpu_iu_info linux_sparc_chips[] = {
#define NSPARCCHIPS ARRAY_SIZE(linux_sparc_chips)
-char *sparc_cpu_type = "cpu-oops";
-char *sparc_fpu_type = "fpu-oops";
+char *sparc_cpu_type;
+char *sparc_fpu_type;
unsigned int fsr_storage;
+static void __init sun4v_cpu_probe(void)
+{
+ switch (sun4v_chip_type) {
+ case SUN4V_CHIP_NIAGARA1:
+ sparc_cpu_type = "UltraSparc T1 (Niagara)";
+ sparc_fpu_type = "UltraSparc T1 integrated FPU";
+ break;
+
+ case SUN4V_CHIP_NIAGARA2:
+ sparc_cpu_type = "UltraSparc T2 (Niagara2)";
+ sparc_fpu_type = "UltraSparc T2 integrated FPU";
+ break;
+
+ default:
+ printk(KERN_WARNING "CPU: Unknown sun4v cpu type [%s]\n",
+ prom_cpu_compatible);
+ sparc_cpu_type = "Unknown SUN4V CPU";
+ sparc_fpu_type = "Unknown SUN4V FPU";
+ break;
+ }
+}
+
void __init cpu_probe(void)
{
unsigned long ver, fpu_vers, manuf, impl, fprs;
int i;
- if (tlb_type == hypervisor) {
- sparc_cpu_type = "UltraSparc T1 (Niagara)";
- sparc_fpu_type = "UltraSparc T1 integrated FPU";
- return;
- }
+ if (tlb_type == hypervisor)
+ return sun4v_cpu_probe();
fprs = fprs_read();
fprs_write(FPRS_FEF);
diff --git a/arch/sparc64/kernel/ds.c b/arch/sparc64/kernel/ds.c
index ba01533f4e0..9f472a79d37 100644
--- a/arch/sparc64/kernel/ds.c
+++ b/arch/sparc64/kernel/ds.c
@@ -13,11 +13,11 @@
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/kthread.h>
+#include <linux/reboot.h>
#include <linux/cpu.h>
#include <asm/ldc.h>
#include <asm/vio.h>
-#include <asm/power.h>
#include <asm/mdesc.h>
#include <asm/head.h>
#include <asm/irq.h>
@@ -124,10 +124,11 @@ struct ds_data_nack {
__u64 result;
};
+struct ds_info;
struct ds_cap_state {
__u64 handle;
- void (*data)(struct ldc_channel *lp,
+ void (*data)(struct ds_info *dp,
struct ds_cap_state *cp,
void *buf, int len);
@@ -139,27 +140,27 @@ struct ds_cap_state {
#define CAP_STATE_REGISTERED 0x02
};
-static void md_update_data(struct ldc_channel *lp, struct ds_cap_state *cp,
+static void md_update_data(struct ds_info *dp, struct ds_cap_state *cp,
void *buf, int len);
-static void domain_shutdown_data(struct ldc_channel *lp,
+static void domain_shutdown_data(struct ds_info *dp,
struct ds_cap_state *cp,
void *buf, int len);
-static void domain_panic_data(struct ldc_channel *lp,
+static void domain_panic_data(struct ds_info *dp,
struct ds_cap_state *cp,
void *buf, int len);
#ifdef CONFIG_HOTPLUG_CPU
-static void dr_cpu_data(struct ldc_channel *lp,
+static void dr_cpu_data(struct ds_info *dp,
struct ds_cap_state *cp,
void *buf, int len);
#endif
-static void ds_pri_data(struct ldc_channel *lp,
+static void ds_pri_data(struct ds_info *dp,
struct ds_cap_state *cp,
void *buf, int len);
-static void ds_var_data(struct ldc_channel *lp,
+static void ds_var_data(struct ds_info *dp,
struct ds_cap_state *cp,
void *buf, int len);
-struct ds_cap_state ds_states[] = {
+struct ds_cap_state ds_states_template[] = {
{
.service_id = "md-update",
.data = md_update_data,
@@ -200,30 +201,38 @@ struct ds_info {
#define DS_HS_START 0x01
#define DS_HS_DONE 0x02
+ u64 id;
+
void *rcv_buf;
int rcv_buf_len;
+
+ struct ds_cap_state *ds_states;
+ int num_ds_states;
+
+ struct ds_info *next;
};
-static struct ds_info *ds_info;
+static struct ds_info *ds_info_list;
-static struct ds_cap_state *find_cap(u64 handle)
+static struct ds_cap_state *find_cap(struct ds_info *dp, u64 handle)
{
unsigned int index = handle >> 32;
- if (index >= ARRAY_SIZE(ds_states))
+ if (index >= dp->num_ds_states)
return NULL;
- return &ds_states[index];
+ return &dp->ds_states[index];
}
-static struct ds_cap_state *find_cap_by_string(const char *name)
+static struct ds_cap_state *find_cap_by_string(struct ds_info *dp,
+ const char *name)
{
int i;
- for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
- if (strcmp(ds_states[i].service_id, name))
+ for (i = 0; i < dp->num_ds_states; i++) {
+ if (strcmp(dp->ds_states[i].service_id, name))
continue;
- return &ds_states[i];
+ return &dp->ds_states[i];
}
return NULL;
}
@@ -264,10 +273,11 @@ struct ds_md_update_res {
__u32 result;
};
-static void md_update_data(struct ldc_channel *lp,
- struct ds_cap_state *dp,
+static void md_update_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
void *buf, int len)
{
+ struct ldc_channel *lp = dp->lp;
struct ds_data *dpkt = buf;
struct ds_md_update_req *rp;
struct {
@@ -277,14 +287,14 @@ static void md_update_data(struct ldc_channel *lp,
rp = (struct ds_md_update_req *) (dpkt + 1);
- printk(KERN_INFO PFX "Machine description update.\n");
+ printk(KERN_INFO "ds-%lu: Machine description update.\n", dp->id);
mdesc_update();
memset(&pkt, 0, sizeof(pkt));
pkt.data.tag.type = DS_DATA;
pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
- pkt.data.handle = dp->handle;
+ pkt.data.handle = cp->handle;
pkt.res.req_num = rp->req_num;
pkt.res.result = DS_OK;
@@ -302,10 +312,11 @@ struct ds_shutdown_res {
char reason[1];
};
-static void domain_shutdown_data(struct ldc_channel *lp,
- struct ds_cap_state *dp,
+static void domain_shutdown_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
void *buf, int len)
{
+ struct ldc_channel *lp = dp->lp;
struct ds_data *dpkt = buf;
struct ds_shutdown_req *rp;
struct {
@@ -315,20 +326,20 @@ static void domain_shutdown_data(struct ldc_channel *lp,
rp = (struct ds_shutdown_req *) (dpkt + 1);
- printk(KERN_ALERT PFX "Shutdown request from "
- "LDOM manager received.\n");
+ printk(KERN_ALERT "ds-%lu: Shutdown request from "
+ "LDOM manager received.\n", dp->id);
memset(&pkt, 0, sizeof(pkt));
pkt.data.tag.type = DS_DATA;
pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
- pkt.data.handle = dp->handle;
+ pkt.data.handle = cp->handle;
pkt.res.req_num = rp->req_num;
pkt.res.result = DS_OK;
pkt.res.reason[0] = 0;
ds_send(lp, &pkt, sizeof(pkt));
- wake_up_powerd();
+ orderly_poweroff(true);
}
struct ds_panic_req {
@@ -341,10 +352,11 @@ struct ds_panic_res {
char reason[1];
};
-static void domain_panic_data(struct ldc_channel *lp,
- struct ds_cap_state *dp,
+static void domain_panic_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
void *buf, int len)
{
+ struct ldc_channel *lp = dp->lp;
struct ds_data *dpkt = buf;
struct ds_panic_req *rp;
struct {
@@ -354,13 +366,13 @@ static void domain_panic_data(struct ldc_channel *lp,
rp = (struct ds_panic_req *) (dpkt + 1);
- printk(KERN_ALERT PFX "Panic request from "
- "LDOM manager received.\n");
+ printk(KERN_ALERT "ds-%lu: Panic request from "
+ "LDOM manager received.\n", dp->id);
memset(&pkt, 0, sizeof(pkt));
pkt.data.tag.type = DS_DATA;
pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
- pkt.data.handle = dp->handle;
+ pkt.data.handle = cp->handle;
pkt.res.req_num = rp->req_num;
pkt.res.result = DS_OK;
pkt.res.reason[0] = 0;
@@ -403,10 +415,11 @@ struct dr_cpu_resp_entry {
__u32 str_off;
};
-static void __dr_cpu_send_error(struct ds_cap_state *cp, struct ds_data *data)
+static void __dr_cpu_send_error(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ struct ds_data *data)
{
struct dr_cpu_tag *tag = (struct dr_cpu_tag *) (data + 1);
- struct ds_info *dp = ds_info;
struct {
struct ds_data data;
struct dr_cpu_tag tag;
@@ -428,12 +441,14 @@ static void __dr_cpu_send_error(struct ds_cap_state *cp, struct ds_data *data)
__ds_send(dp->lp, &pkt, msg_len);
}
-static void dr_cpu_send_error(struct ds_cap_state *cp, struct ds_data *data)
+static void dr_cpu_send_error(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ struct ds_data *data)
{
unsigned long flags;
spin_lock_irqsave(&ds_lock, flags);
- __dr_cpu_send_error(cp, data);
+ __dr_cpu_send_error(dp, cp, data);
spin_unlock_irqrestore(&ds_lock, flags);
}
@@ -511,7 +526,9 @@ static void dr_cpu_mark(struct ds_data *resp, int cpu, int ncpus,
}
}
-static int dr_cpu_configure(struct ds_cap_state *cp, u64 req_num,
+static int dr_cpu_configure(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ u64 req_num,
cpumask_t *mask)
{
struct ds_data *resp;
@@ -533,7 +550,8 @@ static int dr_cpu_configure(struct ds_cap_state *cp, u64 req_num,
for_each_cpu_mask(cpu, *mask) {
int err;
- printk(KERN_INFO PFX "Starting cpu %d...\n", cpu);
+ printk(KERN_INFO "ds-%lu: Starting cpu %d...\n",
+ dp->id, cpu);
err = cpu_up(cpu);
if (err) {
__u32 res = DR_CPU_RES_FAILURE;
@@ -548,14 +566,14 @@ static int dr_cpu_configure(struct ds_cap_state *cp, u64 req_num,
res = DR_CPU_RES_CPU_NOT_RESPONDING;
}
- printk(KERN_INFO PFX "CPU startup failed err=%d\n",
- err);
+ printk(KERN_INFO "ds-%lu: CPU startup failed err=%d\n",
+ dp->id, err);
dr_cpu_mark(resp, cpu, ncpus, res, stat);
}
}
spin_lock_irqsave(&ds_lock, flags);
- __ds_send(ds_info->lp, resp, resp_len);
+ __ds_send(dp->lp, resp, resp_len);
spin_unlock_irqrestore(&ds_lock, flags);
kfree(resp);
@@ -566,7 +584,9 @@ static int dr_cpu_configure(struct ds_cap_state *cp, u64 req_num,
return 0;
}
-static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num,
+static int dr_cpu_unconfigure(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ u64 req_num,
cpumask_t *mask)
{
struct ds_data *resp;
@@ -586,8 +606,8 @@ static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num,
for_each_cpu_mask(cpu, *mask) {
int err;
- printk(KERN_INFO PFX "CPU[%d]: Shutting down cpu %d...\n",
- smp_processor_id(), cpu);
+ printk(KERN_INFO "ds-%lu: Shutting down cpu %d...\n",
+ dp->id, cpu);
err = cpu_down(cpu);
if (err)
dr_cpu_mark(resp, cpu, ncpus,
@@ -596,7 +616,7 @@ static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num,
}
spin_lock_irqsave(&ds_lock, flags);
- __ds_send(ds_info->lp, resp, resp_len);
+ __ds_send(dp->lp, resp, resp_len);
spin_unlock_irqrestore(&ds_lock, flags);
kfree(resp);
@@ -604,7 +624,7 @@ static int dr_cpu_unconfigure(struct ds_cap_state *cp, u64 req_num,
return 0;
}
-static void dr_cpu_data(struct ldc_channel *lp,
+static void dr_cpu_data(struct ds_info *dp,
struct ds_cap_state *cp,
void *buf, int len)
{
@@ -623,7 +643,7 @@ static void dr_cpu_data(struct ldc_channel *lp,
break;
default:
- dr_cpu_send_error(cp, data);
+ dr_cpu_send_error(dp, cp, data);
return;
}
@@ -639,12 +659,12 @@ static void dr_cpu_data(struct ldc_channel *lp,
}
if (tag->type == DR_CPU_CONFIGURE)
- err = dr_cpu_configure(cp, req_num, &mask);
+ err = dr_cpu_configure(dp, cp, req_num, &mask);
else
- err = dr_cpu_unconfigure(cp, req_num, &mask);
+ err = dr_cpu_unconfigure(dp, cp, req_num, &mask);
if (err)
- dr_cpu_send_error(cp, data);
+ dr_cpu_send_error(dp, cp, data);
}
#endif /* CONFIG_HOTPLUG_CPU */
@@ -656,8 +676,8 @@ struct ds_pri_msg {
#define DS_PRI_UPDATE 0x02
};
-static void ds_pri_data(struct ldc_channel *lp,
- struct ds_cap_state *dp,
+static void ds_pri_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
void *buf, int len)
{
struct ds_data *dpkt = buf;
@@ -665,8 +685,8 @@ static void ds_pri_data(struct ldc_channel *lp,
rp = (struct ds_pri_msg *) (dpkt + 1);
- printk(KERN_INFO PFX "PRI REQ [%lx:%lx], len=%d\n",
- rp->req_num, rp->type, len);
+ printk(KERN_INFO "ds-%lu: PRI REQ [%lx:%lx], len=%d\n",
+ dp->id, rp->req_num, rp->type, len);
}
struct ds_var_hdr {
@@ -701,8 +721,8 @@ static DEFINE_MUTEX(ds_var_mutex);
static int ds_var_doorbell;
static int ds_var_response;
-static void ds_var_data(struct ldc_channel *lp,
- struct ds_cap_state *dp,
+static void ds_var_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
void *buf, int len)
{
struct ds_data *dpkt = buf;
@@ -721,14 +741,35 @@ static void ds_var_data(struct ldc_channel *lp,
void ldom_set_var(const char *var, const char *value)
{
- struct ds_info *dp = ds_info;
struct ds_cap_state *cp;
+ struct ds_info *dp;
+ unsigned long flags;
- cp = find_cap_by_string("var-config");
- if (cp->state != CAP_STATE_REGISTERED)
- cp = find_cap_by_string("var-config-backup");
+ spin_lock_irqsave(&ds_lock, flags);
+ cp = NULL;
+ for (dp = ds_info_list; dp; dp = dp->next) {
+ struct ds_cap_state *tmp;
+
+ tmp = find_cap_by_string(dp, "var-config");
+ if (tmp && tmp->state == CAP_STATE_REGISTERED) {
+ cp = tmp;
+ break;
+ }
+ }
+ if (!cp) {
+ for (dp = ds_info_list; dp; dp = dp->next) {
+ struct ds_cap_state *tmp;
+
+ tmp = find_cap_by_string(dp, "var-config-backup");
+ if (tmp && tmp->state == CAP_STATE_REGISTERED) {
+ cp = tmp;
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&ds_lock, flags);
- if (cp->state == CAP_STATE_REGISTERED) {
+ if (cp) {
union {
struct {
struct ds_data data;
@@ -736,7 +777,6 @@ void ldom_set_var(const char *var, const char *value)
} header;
char all[512];
} pkt;
- unsigned long flags;
char *base, *p;
int msg_len, loops;
@@ -777,9 +817,9 @@ void ldom_set_var(const char *var, const char *value)
if (ds_var_doorbell == 0 ||
ds_var_response != DS_VAR_SUCCESS)
- printk(KERN_ERR PFX "var-config [%s:%s] "
+ printk(KERN_ERR "ds-%lu: var-config [%s:%s] "
"failed, response(%d).\n",
- var, value,
+ dp->id, var, value,
ds_var_response);
} else {
printk(KERN_ERR PFX "var-config not registered so "
@@ -811,8 +851,8 @@ void ldom_power_off(void)
static void ds_conn_reset(struct ds_info *dp)
{
- printk(KERN_ERR PFX "ds_conn_reset() from %p\n",
- __builtin_return_address(0));
+ printk(KERN_ERR "ds-%lu: ds_conn_reset() from %p\n",
+ dp->id, __builtin_return_address(0));
}
static int register_services(struct ds_info *dp)
@@ -820,12 +860,12 @@ static int register_services(struct ds_info *dp)
struct ldc_channel *lp = dp->lp;
int i;
- for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
+ for (i = 0; i < dp->num_ds_states; i++) {
struct {
struct ds_reg_req req;
u8 id_buf[256];
} pbuf;
- struct ds_cap_state *cp = &ds_states[i];
+ struct ds_cap_state *cp = &dp->ds_states[i];
int err, msg_len;
u64 new_count;
@@ -870,28 +910,26 @@ static int ds_handshake(struct ds_info *dp, struct ds_msg_tag *pkt)
if (pkt->type == DS_REG_ACK) {
struct ds_reg_ack *ap = (struct ds_reg_ack *) pkt;
- struct ds_cap_state *cp = find_cap(ap->handle);
+ struct ds_cap_state *cp = find_cap(dp, ap->handle);
if (!cp) {
- printk(KERN_ERR PFX "REG ACK for unknown handle %lx\n",
- ap->handle);
+ printk(KERN_ERR "ds-%lu: REG ACK for unknown "
+ "handle %lx\n", dp->id, ap->handle);
return 0;
}
- printk(KERN_INFO PFX "Registered %s service.\n",
- cp->service_id);
+ printk(KERN_INFO "ds-%lu: Registered %s service.\n",
+ dp->id, cp->service_id);
cp->state = CAP_STATE_REGISTERED;
} else if (pkt->type == DS_REG_NACK) {
struct ds_reg_nack *np = (struct ds_reg_nack *) pkt;
- struct ds_cap_state *cp = find_cap(np->handle);
+ struct ds_cap_state *cp = find_cap(dp, np->handle);
if (!cp) {
- printk(KERN_ERR PFX "REG NACK for "
+ printk(KERN_ERR "ds-%lu: REG NACK for "
"unknown handle %lx\n",
- np->handle);
+ dp->id, np->handle);
return 0;
}
- printk(KERN_INFO PFX "Could not register %s service\n",
- cp->service_id);
cp->state = CAP_STATE_UNKNOWN;
}
@@ -922,6 +960,7 @@ static DECLARE_WAIT_QUEUE_HEAD(ds_wait);
struct ds_queue_entry {
struct list_head list;
+ struct ds_info *dp;
int req_len;
int __pad;
u64 req[0];
@@ -930,7 +969,6 @@ struct ds_queue_entry {
static void process_ds_work(void)
{
struct ds_queue_entry *qp, *tmp;
- static struct ds_info *dp;
unsigned long flags;
LIST_HEAD(todo);
@@ -939,22 +977,22 @@ static void process_ds_work(void)
INIT_LIST_HEAD(&ds_work_list);
spin_unlock_irqrestore(&ds_lock, flags);
- dp = ds_info;
-
list_for_each_entry_safe(qp, tmp, &todo, list) {
struct ds_data *dpkt = (struct ds_data *) qp->req;
- struct ds_cap_state *cp = find_cap(dpkt->handle);
+ struct ds_info *dp = qp->dp;
+ struct ds_cap_state *cp = find_cap(dp, dpkt->handle);
int req_len = qp->req_len;
if (!cp) {
- printk(KERN_ERR PFX "Data for unknown handle %lu\n",
- dpkt->handle);
+ printk(KERN_ERR "ds-%lu: Data for unknown "
+ "handle %lu\n",
+ dp->id, dpkt->handle);
spin_lock_irqsave(&ds_lock, flags);
__send_ds_nack(dp, dpkt->handle);
spin_unlock_irqrestore(&ds_lock, flags);
} else {
- cp->data(dp->lp, cp, dpkt, req_len);
+ cp->data(dp, cp, dpkt, req_len);
}
list_del(&qp->list);
@@ -990,6 +1028,7 @@ static int ds_data(struct ds_info *dp, struct ds_msg_tag *pkt, int len)
if (!qp) {
__send_ds_nack(dp, dpkt->handle);
} else {
+ qp->dp = dp;
memcpy(&qp->req, pkt, len);
list_add_tail(&qp->list, &ds_work_list);
wake_up(&ds_wait);
@@ -1013,6 +1052,19 @@ static void ds_up(struct ds_info *dp)
dp->hs_state = DS_HS_START;
}
+static void ds_reset(struct ds_info *dp)
+{
+ int i;
+
+ dp->hs_state = 0;
+
+ for (i = 0; i < dp->num_ds_states; i++) {
+ struct ds_cap_state *cp = &dp->ds_states[i];
+
+ cp->state = CAP_STATE_UNKNOWN;
+ }
+}
+
static void ds_event(void *arg, int event)
{
struct ds_info *dp = arg;
@@ -1028,8 +1080,15 @@ static void ds_event(void *arg, int event)
return;
}
+ if (event == LDC_EVENT_RESET) {
+ ds_reset(dp);
+ spin_unlock_irqrestore(&ds_lock, flags);
+ return;
+ }
+
if (event != LDC_EVENT_DATA_READY) {
- printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event);
+ printk(KERN_WARNING "ds-%lu: Unexpected LDC event %d\n",
+ dp->id, event);
spin_unlock_irqrestore(&ds_lock, flags);
return;
}
@@ -1080,9 +1139,11 @@ static int __devinit ds_probe(struct vio_dev *vdev,
.mtu = 4096,
.mode = LDC_MODE_STREAM,
};
+ struct mdesc_handle *hp;
struct ldc_channel *lp;
struct ds_info *dp;
- int err;
+ const u64 *val;
+ int err, i;
if (ds_version_printed++ == 0)
printk(KERN_INFO "%s", version);
@@ -1092,19 +1153,37 @@ static int __devinit ds_probe(struct vio_dev *vdev,
if (!dp)
goto out_err;
+ hp = mdesc_grab();
+ val = mdesc_get_property(hp, vdev->mp, "id", NULL);
+ if (val)
+ dp->id = *val;
+ mdesc_release(hp);
+
dp->rcv_buf = kzalloc(4096, GFP_KERNEL);
if (!dp->rcv_buf)
goto out_free_dp;
dp->rcv_buf_len = 4096;
+ dp->ds_states = kzalloc(sizeof(ds_states_template),
+ GFP_KERNEL);
+ if (!dp->ds_states)
+ goto out_free_rcv_buf;
+
+ memcpy(dp->ds_states, ds_states_template,
+ sizeof(ds_states_template));
+ dp->num_ds_states = ARRAY_SIZE(ds_states_template);
+
+ for (i = 0; i < dp->num_ds_states; i++)
+ dp->ds_states[i].handle = ((u64)i << 32);
+
ds_cfg.tx_irq = vdev->tx_irq;
ds_cfg.rx_irq = vdev->rx_irq;
lp = ldc_alloc(vdev->channel_id, &ds_cfg, dp);
if (IS_ERR(lp)) {
err = PTR_ERR(lp);
- goto out_free_rcv_buf;
+ goto out_free_ds_states;
}
dp->lp = lp;
@@ -1112,15 +1191,19 @@ static int __devinit ds_probe(struct vio_dev *vdev,
if (err)
goto out_free_ldc;
- ds_info = dp;
-
- start_powerd();
+ spin_lock_irq(&ds_lock);
+ dp->next = ds_info_list;
+ ds_info_list = dp;
+ spin_unlock_irq(&ds_lock);
return err;
out_free_ldc:
ldc_free(dp->lp);
+out_free_ds_states:
+ kfree(dp->ds_states);
+
out_free_rcv_buf:
kfree(dp->rcv_buf);
@@ -1155,11 +1238,6 @@ static struct vio_driver ds_driver = {
static int __init ds_init(void)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ds_states); i++)
- ds_states[i].handle = ((u64)i << 32);
-
kthread_run(ds_thread, NULL, "kldomd");
return vio_register_driver(&ds_driver);
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index ad55a9bb50d..04ab81cb4f4 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -362,6 +362,7 @@ static int __init child_regs_nonstandard(struct linux_ebus_device *dev)
static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *dev)
{
struct linux_ebus_child *child;
+ struct dev_archdata *sd;
struct of_device *op;
int i, len;
@@ -374,7 +375,10 @@ static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_de
dev->num_addrs = 0;
dev->num_irqs = 0;
} else {
- (void) of_get_property(dp, "reg", &len);
+ const int *regs = of_get_property(dp, "reg", &len);
+
+ if (!regs)
+ len = 0;
dev->num_addrs = len / sizeof(struct linux_prom_registers);
for (i = 0; i < dev->num_addrs; i++)
@@ -387,6 +391,12 @@ static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_de
dev->irqs[i] = op->irqs[i];
}
+ sd = &dev->ofdev.dev.archdata;
+ sd->prom_node = dp;
+ sd->op = &dev->ofdev;
+ sd->iommu = dev->bus->ofdev.dev.parent->archdata.iommu;
+ sd->stc = dev->bus->ofdev.dev.parent->archdata.stc;
+
dev->ofdev.node = dp;
dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
dev->ofdev.dev.bus = &ebus_bus_type;
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index 77259526cb1..c4147ad8677 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -1,15 +1,15 @@
-/* $Id: head.S,v 1.87 2002/02/09 19:49:31 davem Exp $
- * head.S: Initial boot code for the Sparc64 port of Linux.
+/* head.S: Initial boot code for the Sparc64 port of Linux.
*
- * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996, 1997, 2007 David S. Miller (davem@davemloft.net)
* Copyright (C) 1996 David Sitsky (David.Sitsky@anu.edu.au)
- * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997, 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
* Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
*/
#include <linux/version.h>
#include <linux/errno.h>
#include <linux/threads.h>
+#include <linux/init.h>
#include <asm/thread_info.h>
#include <asm/asi.h>
#include <asm/pstate.h>
@@ -97,7 +97,8 @@ sparc64_boot:
.globl prom_map_name, prom_unmap_name, prom_mmu_ihandle_cache
.globl prom_boot_mapped_pc, prom_boot_mapping_mode
.globl prom_boot_mapping_phys_high, prom_boot_mapping_phys_low
- .globl is_sun4v
+ .globl prom_compatible_name, prom_cpu_path, prom_cpu_compatible
+ .globl is_sun4v, sun4v_chip_type, prom_set_trap_table_name
prom_peer_name:
.asciz "peer"
prom_compatible_name:
@@ -106,6 +107,8 @@ prom_finddev_name:
.asciz "finddevice"
prom_chosen_path:
.asciz "/chosen"
+prom_cpu_path:
+ .asciz "/cpu"
prom_getprop_name:
.asciz "getprop"
prom_mmu_name:
@@ -118,11 +121,17 @@ prom_map_name:
.asciz "map"
prom_unmap_name:
.asciz "unmap"
+prom_set_trap_table_name:
+ .asciz "SUNW,set-trap-table"
prom_sun4v_name:
.asciz "sun4v"
+prom_niagara_prefix:
+ .asciz "SUNW,UltraSPARC-T"
.align 4
prom_root_compatible:
.skip 64
+prom_cpu_compatible:
+ .skip 64
prom_root_node:
.word 0
prom_mmu_ihandle_cache:
@@ -138,6 +147,8 @@ prom_boot_mapping_phys_low:
.xword 0
is_sun4v:
.word 0
+sun4v_chip_type:
+ .word SUN4V_CHIP_INVALID
1:
rd %pc, %l0
@@ -296,13 +307,13 @@ is_sun4v:
sethi %hi(prom_sun4v_name), %g7
or %g7, %lo(prom_sun4v_name), %g7
mov 5, %g3
-1: ldub [%g7], %g2
+90: ldub [%g7], %g2
ldub [%g1], %g4
cmp %g2, %g4
- bne,pn %icc, 2f
+ bne,pn %icc, 80f
add %g7, 1, %g7
subcc %g3, 1, %g3
- bne,pt %xcc, 1b
+ bne,pt %xcc, 90b
add %g1, 1, %g1
sethi %hi(is_sun4v), %g1
@@ -310,7 +321,80 @@ is_sun4v:
mov 1, %g7
stw %g7, [%g1]
-2:
+ /* cpu_node = prom_finddevice("/cpu") */
+ mov (1b - prom_finddev_name), %l1
+ mov (1b - prom_cpu_path), %l2
+ sub %l0, %l1, %l1
+ sub %l0, %l2, %l2
+ sub %sp, (192 + 128), %sp
+
+ stx %l1, [%sp + 2047 + 128 + 0x00] ! service, "finddevice"
+ mov 1, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x08] ! num_args, 1
+ stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 1
+ stx %l2, [%sp + 2047 + 128 + 0x18] ! arg1, "/cpu"
+ stx %g0, [%sp + 2047 + 128 + 0x20] ! ret1
+ call %l7
+ add %sp, (2047 + 128), %o0 ! argument array
+
+ ldx [%sp + 2047 + 128 + 0x20], %l4 ! cpu device node
+
+ mov (1b - prom_getprop_name), %l1
+ mov (1b - prom_compatible_name), %l2
+ mov (1b - prom_cpu_compatible), %l5
+ sub %l0, %l1, %l1
+ sub %l0, %l2, %l2
+ sub %l0, %l5, %l5
+
+ /* prom_getproperty(cpu_node, "compatible",
+ * &prom_cpu_compatible, 64)
+ */
+ stx %l1, [%sp + 2047 + 128 + 0x00] ! service, "getprop"
+ mov 4, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x08] ! num_args, 4
+ mov 1, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 1
+ stx %l4, [%sp + 2047 + 128 + 0x18] ! arg1, cpu_node
+ stx %l2, [%sp + 2047 + 128 + 0x20] ! arg2, "compatible"
+ stx %l5, [%sp + 2047 + 128 + 0x28] ! arg3, &prom_cpu_compatible
+ mov 64, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x30] ! arg4, size
+ stx %g0, [%sp + 2047 + 128 + 0x38] ! ret1
+ call %l7
+ add %sp, (2047 + 128), %o0 ! argument array
+
+ add %sp, (192 + 128), %sp
+
+ sethi %hi(prom_cpu_compatible), %g1
+ or %g1, %lo(prom_cpu_compatible), %g1
+ sethi %hi(prom_niagara_prefix), %g7
+ or %g7, %lo(prom_niagara_prefix), %g7
+ mov 17, %g3
+90: ldub [%g7], %g2
+ ldub [%g1], %g4
+ cmp %g2, %g4
+ bne,pn %icc, 4f
+ add %g7, 1, %g7
+ subcc %g3, 1, %g3
+ bne,pt %xcc, 90b
+ add %g1, 1, %g1
+
+ sethi %hi(prom_cpu_compatible), %g1
+ or %g1, %lo(prom_cpu_compatible), %g1
+ ldub [%g1 + 17], %g2
+ cmp %g2, '1'
+ be,pt %xcc, 5f
+ mov SUN4V_CHIP_NIAGARA1, %g4
+ cmp %g2, '2'
+ be,pt %xcc, 5f
+ mov SUN4V_CHIP_NIAGARA2, %g4
+4:
+ mov SUN4V_CHIP_UNKNOWN, %g4
+5: sethi %hi(sun4v_chip_type), %g2
+ or %g2, %lo(sun4v_chip_type), %g2
+ stw %g4, [%g2]
+
+80:
BRANCH_IF_SUN4V(g1, jump_to_sun4u_init)
BRANCH_IF_CHEETAH_BASE(g1,g7,cheetah_boot)
BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,cheetah_plus_boot)
@@ -374,6 +458,7 @@ jump_to_sun4u_init:
jmpl %g2 + %g0, %g0
nop
+ .section .text.init.refok
sun4u_init:
BRANCH_IF_SUN4V(g1, sun4v_init)
@@ -413,6 +498,33 @@ niagara_tlb_fixup:
stw %g2, [%g1 + %lo(tlb_type)]
/* Patch copy/clear ops. */
+ sethi %hi(sun4v_chip_type), %g1
+ lduw [%g1 + %lo(sun4v_chip_type)], %g1
+ cmp %g1, SUN4V_CHIP_NIAGARA1
+ be,pt %xcc, niagara_patch
+ cmp %g1, SUN4V_CHIP_NIAGARA2
+ be,pt %xcc, niagara2_patch
+ nop
+
+ call generic_patch_copyops
+ nop
+ call generic_patch_bzero
+ nop
+ call generic_patch_pageops
+ nop
+
+ ba,a,pt %xcc, 80f
+niagara2_patch:
+ call niagara2_patch_copyops
+ nop
+ call niagara_patch_bzero
+ nop
+ call niagara2_patch_pageops
+ nop
+
+ ba,a,pt %xcc, 80f
+
+niagara_patch:
call niagara_patch_copyops
nop
call niagara_patch_bzero
@@ -420,6 +532,7 @@ niagara_tlb_fixup:
call niagara_patch_pageops
nop
+80:
/* Patch TLB/cache ops. */
call hypervisor_patch_cachetlbops
nop
@@ -458,7 +571,6 @@ tlb_fixup_done:
or %g6, %lo(init_thread_union), %g6
ldx [%g6 + TI_TASK], %g4
mov %sp, %l6
- mov %o4, %l7
wr %g0, ASI_P, %asi
mov 1, %g1
@@ -530,6 +642,8 @@ tlb_fixup_done:
nop
/* Not reached... */
+ .previous
+
/* This is meant to allow the sharing of this code between
* boot processor invocation (via setup_tba() below) and
* secondary processor startup (via trampoline.S). The
@@ -579,15 +693,38 @@ setup_trap_table:
sethi %hi(kern_base), %g3
ldx [%g3 + %lo(kern_base)], %g3
add %g2, %g3, %o1
+ sethi %hi(sparc64_ttable_tl0), %o0
- call prom_set_trap_table_sun4v
- sethi %hi(sparc64_ttable_tl0), %o0
+ set prom_set_trap_table_name, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x00]
+ mov 2, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x08]
+ mov 0, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x10]
+ stx %o0, [%sp + 2047 + 128 + 0x18]
+ stx %o1, [%sp + 2047 + 128 + 0x20]
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x08], %o1
+ call %o1
+ add %sp, (2047 + 128), %o0
ba,pt %xcc, 2f
nop
-1: call prom_set_trap_table
- sethi %hi(sparc64_ttable_tl0), %o0
+1: sethi %hi(sparc64_ttable_tl0), %o0
+ set prom_set_trap_table_name, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x00]
+ mov 1, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x08]
+ mov 0, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x10]
+ stx %o0, [%sp + 2047 + 128 + 0x18]
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x08], %o1
+ call %o1
+ add %sp, (2047 + 128), %o0
/* Start using proper page size encodings in ctx register. */
2: sethi %hi(sparc64_kern_pri_context), %g3
@@ -603,12 +740,13 @@ setup_trap_table:
membar #Sync
+ BRANCH_IF_SUN4V(o2, 1f)
+
/* Kill PROM timer */
sethi %hi(0x80000000), %o2
sllx %o2, 32, %o2
wr %o2, 0, %tick_cmpr
- BRANCH_IF_SUN4V(o2, 1f)
BRANCH_IF_ANY_CHEETAH(o2, o3, 1f)
ba,pt %xcc, 2f
diff --git a/arch/sparc64/kernel/hvtramp.S b/arch/sparc64/kernel/hvtramp.S
index a55c252e18c..b692e044a46 100644
--- a/arch/sparc64/kernel/hvtramp.S
+++ b/arch/sparc64/kernel/hvtramp.S
@@ -115,11 +115,8 @@ hv_cpu_startup:
call hard_smp_processor_id
nop
- mov %o0, %o1
- mov 0, %o0
- mov 0, %o2
- call sun4v_init_mondo_queues
- mov 1, %o3
+ call sun4v_register_mondo_queues
+ nop
call init_cur_cpu_trap
mov %g6, %o0
diff --git a/arch/sparc64/kernel/init_task.c b/arch/sparc64/kernel/init_task.c
index 329b38fa5c8..90007cf88ba 100644
--- a/arch/sparc64/kernel/init_task.c
+++ b/arch/sparc64/kernel/init_task.c
@@ -1,4 +1,5 @@
#include <linux/mm.h>
+#include <linux/fs.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/init_task.h>
diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/iommu.c
index 70d2364fdfe..b35a62167e9 100644
--- a/arch/sparc64/kernel/pci_iommu.c
+++ b/arch/sparc64/kernel/iommu.c
@@ -1,28 +1,32 @@
-/* pci_iommu.c: UltraSparc PCI controller IOM/STC support.
+/* iommu.c: Generic sparc64 IOMMU support.
*
* Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net)
* Copyright (C) 1999, 2000 Jakub Jelinek (jakub@redhat.com)
*/
#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
+#include <linux/module.h>
#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+
+#ifdef CONFIG_PCI
#include <linux/pci.h>
+#endif
-#include <asm/oplib.h>
+#include <asm/iommu.h>
#include "iommu_common.h"
-#include "pci_impl.h"
-#define PCI_STC_CTXMATCH_ADDR(STC, CTX) \
+#define STC_CTXMATCH_ADDR(STC, CTX) \
((STC)->strbuf_ctxmatch_base + ((CTX) << 3))
+#define STC_FLUSHFLAG_INIT(STC) \
+ (*((STC)->strbuf_flushflag) = 0UL)
+#define STC_FLUSHFLAG_SET(STC) \
+ (*((STC)->strbuf_flushflag) != 0UL)
-/* Accessing IOMMU and Streaming Buffer registers.
- * REG parameter is a physical address. All registers
- * are 64-bits in size.
- */
-#define pci_iommu_read(__reg) \
+#define iommu_read(__reg) \
({ u64 __ret; \
__asm__ __volatile__("ldxa [%1] %2, %0" \
: "=r" (__ret) \
@@ -30,7 +34,7 @@
: "memory"); \
__ret; \
})
-#define pci_iommu_write(__reg, __val) \
+#define iommu_write(__reg, __val) \
__asm__ __volatile__("stxa %0, [%1] %2" \
: /* no outputs */ \
: "r" (__val), "r" (__reg), \
@@ -40,19 +44,19 @@
static void __iommu_flushall(struct iommu *iommu)
{
if (iommu->iommu_flushinv) {
- pci_iommu_write(iommu->iommu_flushinv, ~(u64)0);
+ iommu_write(iommu->iommu_flushinv, ~(u64)0);
} else {
unsigned long tag;
int entry;
- tag = iommu->iommu_flush + (0xa580UL - 0x0210UL);
+ tag = iommu->iommu_tags;
for (entry = 0; entry < 16; entry++) {
- pci_iommu_write(tag, 0);
+ iommu_write(tag, 0);
tag += 8;
}
/* Ensure completion of previous PIO writes. */
- (void) pci_iommu_read(iommu->write_complete_reg);
+ (void) iommu_read(iommu->write_complete_reg);
}
}
@@ -80,7 +84,7 @@ static inline void iopte_make_dummy(struct iommu *iommu, iopte_t *iopte)
}
/* Based largely upon the ppc64 iommu allocator. */
-static long pci_arena_alloc(struct iommu *iommu, unsigned long npages)
+static long arena_alloc(struct iommu *iommu, unsigned long npages)
{
struct iommu_arena *arena = &iommu->arena;
unsigned long n, i, start, end, limit;
@@ -121,7 +125,7 @@ again:
return n;
}
-static void pci_arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages)
+static void arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages)
{
unsigned long i;
@@ -129,7 +133,8 @@ static void pci_arena_free(struct iommu_arena *arena, unsigned long base, unsign
__clear_bit(i, arena->map);
}
-void pci_iommu_table_init(struct iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask)
+int iommu_table_init(struct iommu *iommu, int tsbsize,
+ u32 dma_offset, u32 dma_addr_mask)
{
unsigned long i, tsbbase, order, sz, num_tsb_entries;
@@ -146,8 +151,8 @@ void pci_iommu_table_init(struct iommu *iommu, int tsbsize, u32 dma_offset, u32
sz = (sz + 7UL) & ~7UL;
iommu->arena.map = kzalloc(sz, GFP_KERNEL);
if (!iommu->arena.map) {
- prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n");
- prom_halt();
+ printk(KERN_ERR "IOMMU: Error, kmalloc(arena.map) failed.\n");
+ return -ENOMEM;
}
iommu->arena.limit = num_tsb_entries;
@@ -156,8 +161,8 @@ void pci_iommu_table_init(struct iommu *iommu, int tsbsize, u32 dma_offset, u32
*/
iommu->dummy_page = __get_free_pages(GFP_KERNEL, 0);
if (!iommu->dummy_page) {
- prom_printf("PCI_IOMMU: Error, gfp(dummy_page) failed.\n");
- prom_halt();
+ printk(KERN_ERR "IOMMU: Error, gfp(dummy_page) failed.\n");
+ goto out_free_map;
}
memset((void *)iommu->dummy_page, 0, PAGE_SIZE);
iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page);
@@ -166,20 +171,32 @@ void pci_iommu_table_init(struct iommu *iommu, int tsbsize, u32 dma_offset, u32
order = get_order(tsbsize);
tsbbase = __get_free_pages(GFP_KERNEL, order);
if (!tsbbase) {
- prom_printf("PCI_IOMMU: Error, gfp(tsb) failed.\n");
- prom_halt();
+ printk(KERN_ERR "IOMMU: Error, gfp(tsb) failed.\n");
+ goto out_free_dummy_page;
}
iommu->page_table = (iopte_t *)tsbbase;
for (i = 0; i < num_tsb_entries; i++)
iopte_make_dummy(iommu, &iommu->page_table[i]);
+
+ return 0;
+
+out_free_dummy_page:
+ free_page(iommu->dummy_page);
+ iommu->dummy_page = 0UL;
+
+out_free_map:
+ kfree(iommu->arena.map);
+ iommu->arena.map = NULL;
+
+ return -ENOMEM;
}
static inline iopte_t *alloc_npages(struct iommu *iommu, unsigned long npages)
{
long entry;
- entry = pci_arena_alloc(iommu, npages);
+ entry = arena_alloc(iommu, npages);
if (unlikely(entry < 0))
return NULL;
@@ -188,7 +205,7 @@ static inline iopte_t *alloc_npages(struct iommu *iommu, unsigned long npages)
static inline void free_npages(struct iommu *iommu, dma_addr_t base, unsigned long npages)
{
- pci_arena_free(&iommu->arena, base >> IO_PAGE_SHIFT, npages);
+ arena_free(&iommu->arena, base >> IO_PAGE_SHIFT, npages);
}
static int iommu_alloc_ctx(struct iommu *iommu)
@@ -219,11 +236,8 @@ static inline void iommu_free_ctx(struct iommu *iommu, int ctx)
}
}
-/* Allocate and map kernel buffer of size SIZE using consistent mode
- * DMA for PCI device PDEV. Return non-NULL cpu-side address if
- * successful and set *DMA_ADDRP to the PCI side dma address.
- */
-static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp)
+static void *dma_4u_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_addrp, gfp_t gfp)
{
struct iommu *iommu;
iopte_t *iopte;
@@ -241,7 +255,7 @@ static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr
return NULL;
memset((char *)first_page, 0, PAGE_SIZE << order);
- iommu = pdev->dev.archdata.iommu;
+ iommu = dev->archdata.iommu;
spin_lock_irqsave(&iommu->lock, flags);
iopte = alloc_npages(iommu, size >> IO_PAGE_SHIFT);
@@ -268,15 +282,15 @@ static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr
return ret;
}
-/* Free and unmap a consistent DMA translation. */
-static void pci_4u_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma)
+static void dma_4u_free_coherent(struct device *dev, size_t size,
+ void *cpu, dma_addr_t dvma)
{
struct iommu *iommu;
iopte_t *iopte;
unsigned long flags, order, npages;
npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT;
- iommu = pdev->dev.archdata.iommu;
+ iommu = dev->archdata.iommu;
iopte = iommu->page_table +
((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
@@ -291,10 +305,8 @@ static void pci_4u_free_consistent(struct pci_dev *pdev, size_t size, void *cpu,
free_pages((unsigned long)cpu, order);
}
-/* Map a single buffer at PTR of SZ bytes for PCI DMA
- * in streaming mode.
- */
-static dma_addr_t pci_4u_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction)
+static dma_addr_t dma_4u_map_single(struct device *dev, void *ptr, size_t sz,
+ enum dma_data_direction direction)
{
struct iommu *iommu;
struct strbuf *strbuf;
@@ -304,10 +316,10 @@ static dma_addr_t pci_4u_map_single(struct pci_dev *pdev, void *ptr, size_t sz,
u32 bus_addr, ret;
unsigned long iopte_protection;
- iommu = pdev->dev.archdata.iommu;
- strbuf = pdev->dev.archdata.stc;
+ iommu = dev->archdata.iommu;
+ strbuf = dev->archdata.stc;
- if (unlikely(direction == PCI_DMA_NONE))
+ if (unlikely(direction == DMA_NONE))
goto bad_no_ctx;
oaddr = (unsigned long)ptr;
@@ -332,7 +344,7 @@ static dma_addr_t pci_4u_map_single(struct pci_dev *pdev, void *ptr, size_t sz,
iopte_protection = IOPTE_STREAMING(ctx);
else
iopte_protection = IOPTE_CONSISTENT(ctx);
- if (direction != PCI_DMA_TODEVICE)
+ if (direction != DMA_TO_DEVICE)
iopte_protection |= IOPTE_WRITE;
for (i = 0; i < npages; i++, base++, base_paddr += IO_PAGE_SIZE)
@@ -345,10 +357,12 @@ bad:
bad_no_ctx:
if (printk_ratelimit())
WARN_ON(1);
- return PCI_DMA_ERROR_CODE;
+ return DMA_ERROR_CODE;
}
-static void pci_strbuf_flush(struct strbuf *strbuf, struct iommu *iommu, u32 vaddr, unsigned long ctx, unsigned long npages, int direction)
+static void strbuf_flush(struct strbuf *strbuf, struct iommu *iommu,
+ u32 vaddr, unsigned long ctx, unsigned long npages,
+ enum dma_data_direction direction)
{
int limit;
@@ -358,22 +372,22 @@ static void pci_strbuf_flush(struct strbuf *strbuf, struct iommu *iommu, u32 vad
u64 val;
flushreg = strbuf->strbuf_ctxflush;
- matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx);
+ matchreg = STC_CTXMATCH_ADDR(strbuf, ctx);
- pci_iommu_write(flushreg, ctx);
- val = pci_iommu_read(matchreg);
+ iommu_write(flushreg, ctx);
+ val = iommu_read(matchreg);
val &= 0xffff;
if (!val)
goto do_flush_sync;
while (val) {
if (val & 0x1)
- pci_iommu_write(flushreg, ctx);
+ iommu_write(flushreg, ctx);
val >>= 1;
}
- val = pci_iommu_read(matchreg);
+ val = iommu_read(matchreg);
if (unlikely(val)) {
- printk(KERN_WARNING "pci_strbuf_flush: ctx flush "
+ printk(KERN_WARNING "strbuf_flush: ctx flush "
"timeout matchreg[%lx] ctx[%lx]\n",
val, ctx);
goto do_page_flush;
@@ -383,7 +397,7 @@ static void pci_strbuf_flush(struct strbuf *strbuf, struct iommu *iommu, u32 vad
do_page_flush:
for (i = 0; i < npages; i++, vaddr += IO_PAGE_SIZE)
- pci_iommu_write(strbuf->strbuf_pflush, vaddr);
+ iommu_write(strbuf->strbuf_pflush, vaddr);
}
do_flush_sync:
@@ -391,15 +405,15 @@ do_flush_sync:
* the streaming cache, no flush-flag synchronization needs
* to be performed.
*/
- if (direction == PCI_DMA_TODEVICE)
+ if (direction == DMA_TO_DEVICE)
return;
- PCI_STC_FLUSHFLAG_INIT(strbuf);
- pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa);
- (void) pci_iommu_read(iommu->write_complete_reg);
+ STC_FLUSHFLAG_INIT(strbuf);
+ iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa);
+ (void) iommu_read(iommu->write_complete_reg);
limit = 100000;
- while (!PCI_STC_FLUSHFLAG_SET(strbuf)) {
+ while (!STC_FLUSHFLAG_SET(strbuf)) {
limit--;
if (!limit)
break;
@@ -407,37 +421,32 @@ do_flush_sync:
rmb();
}
if (!limit)
- printk(KERN_WARNING "pci_strbuf_flush: flushflag timeout "
+ printk(KERN_WARNING "strbuf_flush: flushflag timeout "
"vaddr[%08x] ctx[%lx] npages[%ld]\n",
vaddr, ctx, npages);
}
-/* Unmap a single streaming mode DMA translation. */
-static void pci_4u_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
+static void dma_4u_unmap_single(struct device *dev, dma_addr_t bus_addr,
+ size_t sz, enum dma_data_direction direction)
{
struct iommu *iommu;
struct strbuf *strbuf;
iopte_t *base;
unsigned long flags, npages, ctx, i;
- if (unlikely(direction == PCI_DMA_NONE)) {
+ if (unlikely(direction == DMA_NONE)) {
if (printk_ratelimit())
WARN_ON(1);
return;
}
- iommu = pdev->dev.archdata.iommu;
- strbuf = pdev->dev.archdata.stc;
+ iommu = dev->archdata.iommu;
+ strbuf = dev->archdata.stc;
npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
npages >>= IO_PAGE_SHIFT;
base = iommu->page_table +
((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
-#ifdef DEBUG_PCI_IOMMU
- if (IOPTE_IS_DUMMY(iommu, base))
- printk("pci_unmap_single called on non-mapped region %08x,%08x from %016lx\n",
- bus_addr, sz, __builtin_return_address(0));
-#endif
bus_addr &= IO_PAGE_MASK;
spin_lock_irqsave(&iommu->lock, flags);
@@ -449,8 +458,8 @@ static void pci_4u_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_
/* Step 1: Kick data out of streaming buffers if necessary. */
if (strbuf->strbuf_enabled)
- pci_strbuf_flush(strbuf, iommu, bus_addr, ctx,
- npages, direction);
+ strbuf_flush(strbuf, iommu, bus_addr, ctx,
+ npages, direction);
/* Step 2: Clear out TSB entries. */
for (i = 0; i < npages; i++)
@@ -467,7 +476,8 @@ static void pci_4u_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_
(__pa(page_address((SG)->page)) + (SG)->offset)
static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg,
- int nused, int nelems, unsigned long iopte_protection)
+ int nused, int nelems,
+ unsigned long iopte_protection)
{
struct scatterlist *dma_sg = sg;
struct scatterlist *sg_end = sg + nelems;
@@ -539,12 +549,8 @@ static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg,
}
}
-/* Map a set of buffers described by SGLIST with NELEMS array
- * elements in streaming mode for PCI DMA.
- * When making changes here, inspect the assembly output. I was having
- * hard time to keep this routine out of using stack slots for holding variables.
- */
-static int pci_4u_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
+static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
+ int nelems, enum dma_data_direction direction)
{
struct iommu *iommu;
struct strbuf *strbuf;
@@ -557,19 +563,20 @@ static int pci_4u_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int n
/* Fast path single entry scatterlists. */
if (nelems == 1) {
sglist->dma_address =
- pci_4u_map_single(pdev,
- (page_address(sglist->page) + sglist->offset),
+ dma_4u_map_single(dev,
+ (page_address(sglist->page) +
+ sglist->offset),
sglist->length, direction);
- if (unlikely(sglist->dma_address == PCI_DMA_ERROR_CODE))
+ if (unlikely(sglist->dma_address == DMA_ERROR_CODE))
return 0;
sglist->dma_length = sglist->length;
return 1;
}
- iommu = pdev->dev.archdata.iommu;
- strbuf = pdev->dev.archdata.stc;
-
- if (unlikely(direction == PCI_DMA_NONE))
+ iommu = dev->archdata.iommu;
+ strbuf = dev->archdata.stc;
+
+ if (unlikely(direction == DMA_NONE))
goto bad_no_ctx;
/* Step 1: Prepare scatter list. */
@@ -609,7 +616,7 @@ static int pci_4u_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int n
iopte_protection = IOPTE_STREAMING(ctx);
else
iopte_protection = IOPTE_CONSISTENT(ctx);
- if (direction != PCI_DMA_TODEVICE)
+ if (direction != DMA_TO_DEVICE)
iopte_protection |= IOPTE_WRITE;
fill_sg(base, sglist, used, nelems, iopte_protection);
@@ -628,8 +635,8 @@ bad_no_ctx:
return 0;
}
-/* Unmap a set of streaming mode DMA translations. */
-static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
+static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist,
+ int nelems, enum dma_data_direction direction)
{
struct iommu *iommu;
struct strbuf *strbuf;
@@ -637,14 +644,14 @@ static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, in
unsigned long flags, ctx, i, npages;
u32 bus_addr;
- if (unlikely(direction == PCI_DMA_NONE)) {
+ if (unlikely(direction == DMA_NONE)) {
if (printk_ratelimit())
WARN_ON(1);
}
- iommu = pdev->dev.archdata.iommu;
- strbuf = pdev->dev.archdata.stc;
-
+ iommu = dev->archdata.iommu;
+ strbuf = dev->archdata.stc;
+
bus_addr = sglist->dma_address & IO_PAGE_MASK;
for (i = 1; i < nelems; i++)
@@ -657,11 +664,6 @@ static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, in
base = iommu->page_table +
((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
-#ifdef DEBUG_PCI_IOMMU
- if (IOPTE_IS_DUMMY(iommu, base))
- printk("pci_unmap_sg called on non-mapped region %016lx,%d from %016lx\n", sglist->dma_address, nelems, __builtin_return_address(0));
-#endif
-
spin_lock_irqsave(&iommu->lock, flags);
/* Record the context, if any. */
@@ -671,7 +673,7 @@ static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, in
/* Step 1: Kick data out of streaming buffers if necessary. */
if (strbuf->strbuf_enabled)
- pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction);
+ strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction);
/* Step 2: Clear out the TSB entries. */
for (i = 0; i < npages; i++)
@@ -684,17 +686,16 @@ static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, in
spin_unlock_irqrestore(&iommu->lock, flags);
}
-/* Make physical memory consistent for a single
- * streaming mode DMA translation after a transfer.
- */
-static void pci_4u_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
+static void dma_4u_sync_single_for_cpu(struct device *dev,
+ dma_addr_t bus_addr, size_t sz,
+ enum dma_data_direction direction)
{
struct iommu *iommu;
struct strbuf *strbuf;
unsigned long flags, ctx, npages;
- iommu = pdev->dev.archdata.iommu;
- strbuf = pdev->dev.archdata.stc;
+ iommu = dev->archdata.iommu;
+ strbuf = dev->archdata.stc;
if (!strbuf->strbuf_enabled)
return;
@@ -717,23 +718,22 @@ static void pci_4u_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_
}
/* Step 2: Kick data out of streaming buffers. */
- pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction);
+ strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction);
spin_unlock_irqrestore(&iommu->lock, flags);
}
-/* Make physical memory consistent for a set of streaming
- * mode DMA translations after a transfer.
- */
-static void pci_4u_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
+static void dma_4u_sync_sg_for_cpu(struct device *dev,
+ struct scatterlist *sglist, int nelems,
+ enum dma_data_direction direction)
{
struct iommu *iommu;
struct strbuf *strbuf;
unsigned long flags, ctx, npages, i;
u32 bus_addr;
- iommu = pdev->dev.archdata.iommu;
- strbuf = pdev->dev.archdata.stc;
+ iommu = dev->archdata.iommu;
+ strbuf = dev->archdata.stc;
if (!strbuf->strbuf_enabled)
return;
@@ -759,65 +759,51 @@ static void pci_4u_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist
i--;
npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length)
- bus_addr) >> IO_PAGE_SHIFT;
- pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction);
+ strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction);
spin_unlock_irqrestore(&iommu->lock, flags);
}
-const struct pci_iommu_ops pci_sun4u_iommu_ops = {
- .alloc_consistent = pci_4u_alloc_consistent,
- .free_consistent = pci_4u_free_consistent,
- .map_single = pci_4u_map_single,
- .unmap_single = pci_4u_unmap_single,
- .map_sg = pci_4u_map_sg,
- .unmap_sg = pci_4u_unmap_sg,
- .dma_sync_single_for_cpu = pci_4u_dma_sync_single_for_cpu,
- .dma_sync_sg_for_cpu = pci_4u_dma_sync_sg_for_cpu,
+const struct dma_ops sun4u_dma_ops = {
+ .alloc_coherent = dma_4u_alloc_coherent,
+ .free_coherent = dma_4u_free_coherent,
+ .map_single = dma_4u_map_single,
+ .unmap_single = dma_4u_unmap_single,
+ .map_sg = dma_4u_map_sg,
+ .unmap_sg = dma_4u_unmap_sg,
+ .sync_single_for_cpu = dma_4u_sync_single_for_cpu,
+ .sync_sg_for_cpu = dma_4u_sync_sg_for_cpu,
};
-static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit)
-{
- struct pci_dev *ali_isa_bridge;
- u8 val;
+const struct dma_ops *dma_ops = &sun4u_dma_ops;
+EXPORT_SYMBOL(dma_ops);
- /* ALI sound chips generate 31-bits of DMA, a special register
- * determines what bit 31 is emitted as.
- */
- ali_isa_bridge = pci_get_device(PCI_VENDOR_ID_AL,
- PCI_DEVICE_ID_AL_M1533,
- NULL);
-
- pci_read_config_byte(ali_isa_bridge, 0x7e, &val);
- if (set_bit)
- val |= 0x01;
- else
- val &= ~0x01;
- pci_write_config_byte(ali_isa_bridge, 0x7e, val);
- pci_dev_put(ali_isa_bridge);
-}
-
-int pci_dma_supported(struct pci_dev *pdev, u64 device_mask)
+int dma_supported(struct device *dev, u64 device_mask)
{
- u64 dma_addr_mask;
+ struct iommu *iommu = dev->archdata.iommu;
+ u64 dma_addr_mask = iommu->dma_addr_mask;
- if (pdev == NULL) {
- dma_addr_mask = 0xffffffff;
- } else {
- struct iommu *iommu = pdev->dev.archdata.iommu;
+ if (device_mask >= (1UL << 32UL))
+ return 0;
- dma_addr_mask = iommu->dma_addr_mask;
+ if ((device_mask & dma_addr_mask) == dma_addr_mask)
+ return 1;
- if (pdev->vendor == PCI_VENDOR_ID_AL &&
- pdev->device == PCI_DEVICE_ID_AL_M5451 &&
- device_mask == 0x7fffffff) {
- ali_sound_dma_hack(pdev,
- (dma_addr_mask & 0x80000000) != 0);
- return 1;
- }
- }
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type)
+ return pci_dma_supported(to_pci_dev(dev), device_mask);
+#endif
- if (device_mask >= (1UL << 32UL))
- return 0;
+ return 0;
+}
+EXPORT_SYMBOL(dma_supported);
- return (device_mask & dma_addr_mask) == dma_addr_mask;
+int dma_set_mask(struct device *dev, u64 dma_mask)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type)
+ return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
+#endif
+ return -EINVAL;
}
+EXPORT_SYMBOL(dma_set_mask);
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 8cb3358674f..23956096b3b 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -87,7 +87,11 @@ struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BY
*/
#define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist)
-static unsigned int virt_to_real_irq_table[NR_IRQS];
+static struct {
+ unsigned int irq;
+ unsigned int dev_handle;
+ unsigned int dev_ino;
+} virt_to_real_irq_table[NR_IRQS];
static unsigned char virt_irq_alloc(unsigned int real_irq)
{
@@ -96,7 +100,7 @@ static unsigned char virt_irq_alloc(unsigned int real_irq)
BUILD_BUG_ON(NR_IRQS >= 256);
for (ent = 1; ent < NR_IRQS; ent++) {
- if (!virt_to_real_irq_table[ent])
+ if (!virt_to_real_irq_table[ent].irq)
break;
}
if (ent >= NR_IRQS) {
@@ -104,7 +108,7 @@ static unsigned char virt_irq_alloc(unsigned int real_irq)
return 0;
}
- virt_to_real_irq_table[ent] = real_irq;
+ virt_to_real_irq_table[ent].irq = real_irq;
return ent;
}
@@ -117,8 +121,8 @@ static void virt_irq_free(unsigned int virt_irq)
if (virt_irq >= NR_IRQS)
return;
- real_irq = virt_to_real_irq_table[virt_irq];
- virt_to_real_irq_table[virt_irq] = 0;
+ real_irq = virt_to_real_irq_table[virt_irq].irq;
+ virt_to_real_irq_table[virt_irq].irq = 0;
__bucket(real_irq)->virt_irq = 0;
}
@@ -126,7 +130,7 @@ static void virt_irq_free(unsigned int virt_irq)
static unsigned int virt_to_real_irq(unsigned char virt_irq)
{
- return virt_to_real_irq_table[virt_irq];
+ return virt_to_real_irq_table[virt_irq].irq;
}
/*
@@ -213,8 +217,27 @@ struct irq_handler_data {
void (*pre_handler)(unsigned int, void *, void *);
void *pre_handler_arg1;
void *pre_handler_arg2;
+
+ u32 msi;
};
+void sparc64_set_msi(unsigned int virt_irq, u32 msi)
+{
+ struct irq_handler_data *data = get_irq_chip_data(virt_irq);
+
+ if (data)
+ data->msi = msi;
+}
+
+u32 sparc64_get_msi(unsigned int virt_irq)
+{
+ struct irq_handler_data *data = get_irq_chip_data(virt_irq);
+
+ if (data)
+ return data->msi;
+ return 0xffffffff;
+}
+
static inline struct ino_bucket *virt_irq_to_bucket(unsigned int virt_irq)
{
unsigned int real_irq = virt_to_real_irq(virt_irq);
@@ -304,7 +327,7 @@ static void sun4u_irq_disable(unsigned int virt_irq)
if (likely(data)) {
unsigned long imap = data->imap;
- u32 tmp = upa_readq(imap);
+ unsigned long tmp = upa_readq(imap);
tmp &= ~IMAP_VALID;
upa_writeq(tmp, imap);
@@ -336,15 +359,15 @@ static void sun4v_irq_enable(unsigned int virt_irq)
err = sun4v_intr_settarget(ino, cpuid);
if (err != HV_EOK)
- printk("sun4v_intr_settarget(%x,%lu): err(%d)\n",
- ino, cpuid, err);
+ printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
+ "err(%d)\n", ino, cpuid, err);
err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
if (err != HV_EOK)
- printk("sun4v_intr_setstate(%x): "
+ printk(KERN_ERR "sun4v_intr_setstate(%x): "
"err(%d)\n", ino, err);
err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
if (err != HV_EOK)
- printk("sun4v_intr_setenabled(%x): err(%d)\n",
+ printk(KERN_ERR "sun4v_intr_setenabled(%x): err(%d)\n",
ino, err);
}
}
@@ -362,8 +385,8 @@ static void sun4v_set_affinity(unsigned int virt_irq, cpumask_t mask)
err = sun4v_intr_settarget(ino, cpuid);
if (err != HV_EOK)
- printk("sun4v_intr_settarget(%x,%lu): err(%d)\n",
- ino, cpuid, err);
+ printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
+ "err(%d)\n", ino, cpuid, err);
}
}
@@ -377,7 +400,7 @@ static void sun4v_irq_disable(unsigned int virt_irq)
err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED);
if (err != HV_EOK)
- printk("sun4v_intr_setenabled(%x): "
+ printk(KERN_ERR "sun4v_intr_setenabled(%x): "
"err(%d)\n", ino, err);
}
}
@@ -410,7 +433,7 @@ static void sun4v_irq_end(unsigned int virt_irq)
err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
if (err != HV_EOK)
- printk("sun4v_intr_setstate(%x): "
+ printk(KERN_ERR "sun4v_intr_setstate(%x): "
"err(%d)\n", ino, err);
}
}
@@ -418,7 +441,6 @@ static void sun4v_irq_end(unsigned int virt_irq)
static void sun4v_virq_enable(unsigned int virt_irq)
{
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
- unsigned int ino = bucket - &ivector_table[0];
if (likely(bucket)) {
unsigned long cpuid, dev_handle, dev_ino;
@@ -426,24 +448,24 @@ static void sun4v_virq_enable(unsigned int virt_irq)
cpuid = irq_choose_cpu(virt_irq);
- dev_handle = ino & IMAP_IGN;
- dev_ino = ino & IMAP_INO;
+ dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+ dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
if (err != HV_EOK)
- printk("sun4v_vintr_set_target(%lx,%lx,%lu): "
+ printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
"err(%d)\n",
dev_handle, dev_ino, cpuid, err);
err = sun4v_vintr_set_state(dev_handle, dev_ino,
HV_INTR_STATE_IDLE);
if (err != HV_EOK)
- printk("sun4v_vintr_set_state(%lx,%lx,"
+ printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
"HV_INTR_STATE_IDLE): err(%d)\n",
dev_handle, dev_ino, err);
err = sun4v_vintr_set_valid(dev_handle, dev_ino,
HV_INTR_ENABLED);
if (err != HV_EOK)
- printk("sun4v_vintr_set_state(%lx,%lx,"
+ printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
"HV_INTR_ENABLED): err(%d)\n",
dev_handle, dev_ino, err);
}
@@ -452,7 +474,6 @@ static void sun4v_virq_enable(unsigned int virt_irq)
static void sun4v_virt_set_affinity(unsigned int virt_irq, cpumask_t mask)
{
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
- unsigned int ino = bucket - &ivector_table[0];
if (likely(bucket)) {
unsigned long cpuid, dev_handle, dev_ino;
@@ -460,12 +481,12 @@ static void sun4v_virt_set_affinity(unsigned int virt_irq, cpumask_t mask)
cpuid = irq_choose_cpu(virt_irq);
- dev_handle = ino & IMAP_IGN;
- dev_ino = ino & IMAP_INO;
+ dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+ dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
if (err != HV_EOK)
- printk("sun4v_vintr_set_target(%lx,%lx,%lu): "
+ printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
"err(%d)\n",
dev_handle, dev_ino, cpuid, err);
}
@@ -474,19 +495,18 @@ static void sun4v_virt_set_affinity(unsigned int virt_irq, cpumask_t mask)
static void sun4v_virq_disable(unsigned int virt_irq)
{
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
- unsigned int ino = bucket - &ivector_table[0];
if (likely(bucket)) {
unsigned long dev_handle, dev_ino;
int err;
- dev_handle = ino & IMAP_IGN;
- dev_ino = ino & IMAP_INO;
+ dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+ dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
err = sun4v_vintr_set_valid(dev_handle, dev_ino,
HV_INTR_DISABLED);
if (err != HV_EOK)
- printk("sun4v_vintr_set_state(%lx,%lx,"
+ printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
"HV_INTR_DISABLED): err(%d)\n",
dev_handle, dev_ino, err);
}
@@ -495,7 +515,6 @@ static void sun4v_virq_disable(unsigned int virt_irq)
static void sun4v_virq_end(unsigned int virt_irq)
{
struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
- unsigned int ino = bucket - &ivector_table[0];
struct irq_desc *desc = irq_desc + virt_irq;
if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
@@ -505,13 +524,13 @@ static void sun4v_virq_end(unsigned int virt_irq)
unsigned long dev_handle, dev_ino;
int err;
- dev_handle = ino & IMAP_IGN;
- dev_ino = ino & IMAP_INO;
+ dev_handle = virt_to_real_irq_table[virt_irq].dev_handle;
+ dev_ino = virt_to_real_irq_table[virt_irq].dev_ino;
err = sun4v_vintr_set_state(dev_handle, dev_ino,
HV_INTR_STATE_IDLE);
if (err != HV_EOK)
- printk("sun4v_vintr_set_state(%lx,%lx,"
+ printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
"HV_INTR_STATE_IDLE): err(%d)\n",
dev_handle, dev_ino, err);
}
@@ -700,11 +719,12 @@ unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
{
unsigned long sysino, hv_err;
+ unsigned int virq;
- BUG_ON(devhandle & ~IMAP_IGN);
- BUG_ON(devino & ~IMAP_INO);
+ BUG_ON(devhandle & devino);
sysino = devhandle | devino;
+ BUG_ON(sysino & ~(IMAP_IGN | IMAP_INO));
hv_err = sun4v_vintr_set_cookie(devhandle, devino, sysino);
if (hv_err) {
@@ -713,7 +733,12 @@ unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
prom_halt();
}
- return sun4v_build_common(sysino, &sun4v_virq);
+ virq = sun4v_build_common(sysino, &sun4v_virq);
+
+ virt_to_real_irq_table[virq].dev_handle = devhandle;
+ virt_to_real_irq_table[virq].dev_ino = devino;
+
+ return virq;
}
#ifdef CONFIG_PCI_MSI
@@ -735,7 +760,7 @@ unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p,
break;
}
if (devino >= msi_end)
- return 0;
+ return -ENOSPC;
sysino = sun4v_devino_to_sysino(devhandle, devino);
bucket = &ivector_table[sysino];
@@ -749,8 +774,8 @@ unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p,
data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
if (unlikely(!data)) {
- prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n");
- prom_halt();
+ virt_irq_free(*virt_irq_p);
+ return -ENOMEM;
}
set_irq_chip_data(bucket->virt_irq, data);
@@ -923,7 +948,7 @@ static void __cpuinit register_one_mondo(unsigned long paddr, unsigned long type
}
}
-static void __cpuinit sun4v_register_mondo_queues(int this_cpu)
+void __cpuinit sun4v_register_mondo_queues(int this_cpu)
{
struct trap_per_cpu *tb = &trap_block[this_cpu];
@@ -937,20 +962,10 @@ static void __cpuinit sun4v_register_mondo_queues(int this_cpu)
tb->nonresum_qmask);
}
-static void __cpuinit alloc_one_mondo(unsigned long *pa_ptr, unsigned long qmask, int use_bootmem)
+static void __init alloc_one_mondo(unsigned long *pa_ptr, unsigned long qmask)
{
unsigned long size = PAGE_ALIGN(qmask + 1);
- unsigned long order = get_order(size);
- void *p = NULL;
-
- if (use_bootmem) {
- p = __alloc_bootmem_low(size, size, 0);
- } else {
- struct page *page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, order);
- if (page)
- p = page_address(page);
- }
-
+ void *p = __alloc_bootmem_low(size, size, 0);
if (!p) {
prom_printf("SUN4V: Error, cannot allocate mondo queue.\n");
prom_halt();
@@ -959,19 +974,10 @@ static void __cpuinit alloc_one_mondo(unsigned long *pa_ptr, unsigned long qmask
*pa_ptr = __pa(p);
}
-static void __cpuinit alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask, int use_bootmem)
+static void __init alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask)
{
unsigned long size = PAGE_ALIGN(qmask + 1);
- unsigned long order = get_order(size);
- void *p = NULL;
-
- if (use_bootmem) {
- p = __alloc_bootmem_low(size, size, 0);
- } else {
- struct page *page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, order);
- if (page)
- p = page_address(page);
- }
+ void *p = __alloc_bootmem_low(size, size, 0);
if (!p) {
prom_printf("SUN4V: Error, cannot allocate kbuf page.\n");
@@ -981,18 +987,14 @@ static void __cpuinit alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask,
*pa_ptr = __pa(p);
}
-static void __cpuinit init_cpu_send_mondo_info(struct trap_per_cpu *tb, int use_bootmem)
+static void __init init_cpu_send_mondo_info(struct trap_per_cpu *tb)
{
#ifdef CONFIG_SMP
void *page;
BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > (PAGE_SIZE - 64));
- if (use_bootmem)
- page = alloc_bootmem_low_pages(PAGE_SIZE);
- else
- page = (void *) get_zeroed_page(GFP_ATOMIC);
-
+ page = alloc_bootmem_low_pages(PAGE_SIZE);
if (!page) {
prom_printf("SUN4V: Error, cannot allocate cpu mondo page.\n");
prom_halt();
@@ -1003,30 +1005,27 @@ static void __cpuinit init_cpu_send_mondo_info(struct trap_per_cpu *tb, int use_
#endif
}
-/* Allocate and register the mondo and error queues for this cpu. */
-void __cpuinit sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load)
+/* Allocate mondo and error queues for all possible cpus. */
+static void __init sun4v_init_mondo_queues(void)
{
- struct trap_per_cpu *tb = &trap_block[cpu];
+ int cpu;
- if (alloc) {
- alloc_one_mondo(&tb->cpu_mondo_pa, tb->cpu_mondo_qmask, use_bootmem);
- alloc_one_mondo(&tb->dev_mondo_pa, tb->dev_mondo_qmask, use_bootmem);
- alloc_one_mondo(&tb->resum_mondo_pa, tb->resum_qmask, use_bootmem);
- alloc_one_kbuf(&tb->resum_kernel_buf_pa, tb->resum_qmask, use_bootmem);
- alloc_one_mondo(&tb->nonresum_mondo_pa, tb->nonresum_qmask, use_bootmem);
- alloc_one_kbuf(&tb->nonresum_kernel_buf_pa, tb->nonresum_qmask, use_bootmem);
+ for_each_possible_cpu(cpu) {
+ struct trap_per_cpu *tb = &trap_block[cpu];
- init_cpu_send_mondo_info(tb, use_bootmem);
- }
+ alloc_one_mondo(&tb->cpu_mondo_pa, tb->cpu_mondo_qmask);
+ alloc_one_mondo(&tb->dev_mondo_pa, tb->dev_mondo_qmask);
+ alloc_one_mondo(&tb->resum_mondo_pa, tb->resum_qmask);
+ alloc_one_kbuf(&tb->resum_kernel_buf_pa, tb->resum_qmask);
+ alloc_one_mondo(&tb->nonresum_mondo_pa, tb->nonresum_qmask);
+ alloc_one_kbuf(&tb->nonresum_kernel_buf_pa,
+ tb->nonresum_qmask);
- if (load) {
- if (cpu != hard_smp_processor_id()) {
- prom_printf("SUN4V: init mondo on cpu %d not %d\n",
- cpu, hard_smp_processor_id());
- prom_halt();
- }
- sun4v_register_mondo_queues(cpu);
+ init_cpu_send_mondo_info(tb);
}
+
+ /* Load up the boot cpu's entries. */
+ sun4v_register_mondo_queues(hard_smp_processor_id());
}
static struct irqaction timer_irq_action = {
@@ -1041,7 +1040,7 @@ void __init init_IRQ(void)
memset(&ivector_table[0], 0, sizeof(ivector_table));
if (tlb_type == hypervisor)
- sun4v_init_mondo_queues(1, hard_smp_processor_id(), 1, 1);
+ sun4v_init_mondo_queues();
/* We need to clear any IRQ's pending in the soft interrupt
* registers, a spurious one could be left around from the
diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c
index 6a6882e57ff..0f19dce1c90 100644
--- a/arch/sparc64/kernel/isa.c
+++ b/arch/sparc64/kernel/isa.c
@@ -79,6 +79,7 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
while (dp) {
struct sparc_isa_device *isa_dev;
+ struct dev_archdata *sd;
isa_dev = kzalloc(sizeof(*isa_dev), GFP_KERNEL);
if (!isa_dev) {
@@ -86,6 +87,12 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br)
return;
}
+ sd = &isa_dev->ofdev.dev.archdata;
+ sd->prom_node = dp;
+ sd->op = &isa_dev->ofdev;
+ sd->iommu = isa_br->ofdev.dev.parent->archdata.iommu;
+ sd->stc = isa_br->ofdev.dev.parent->archdata.stc;
+
isa_dev->ofdev.node = dp;
isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev;
isa_dev->ofdev.dev.bus = &isa_bus_type;
diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c
index de5310ffdb4..856659bb131 100644
--- a/arch/sparc64/kernel/mdesc.c
+++ b/arch/sparc64/kernel/mdesc.c
@@ -9,6 +9,7 @@
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/mm.h>
+#include <linux/miscdevice.h>
#include <asm/hypervisor.h>
#include <asm/mdesc.h>
@@ -83,7 +84,7 @@ static void mdesc_handle_init(struct mdesc_handle *hp,
hp->handle_size = handle_size;
}
-static struct mdesc_handle *mdesc_bootmem_alloc(unsigned int mdesc_size)
+static struct mdesc_handle * __init mdesc_bootmem_alloc(unsigned int mdesc_size)
{
struct mdesc_handle *hp;
unsigned int handle_size, alloc_size;
@@ -123,7 +124,7 @@ static void mdesc_bootmem_free(struct mdesc_handle *hp)
}
}
-static struct mdesc_mem_ops bootmem_mdesc_memops = {
+static struct mdesc_mem_ops bootmem_mdesc_ops = {
.alloc = mdesc_bootmem_alloc,
.free = mdesc_bootmem_free,
};
@@ -137,7 +138,7 @@ static struct mdesc_handle *mdesc_kmalloc(unsigned int mdesc_size)
sizeof(struct mdesc_hdr) +
mdesc_size);
- base = kmalloc(handle_size + 15, GFP_KERNEL);
+ base = kmalloc(handle_size + 15, GFP_KERNEL | __GFP_NOFAIL);
if (base) {
struct mdesc_handle *hp;
unsigned long addr;
@@ -214,18 +215,131 @@ void mdesc_release(struct mdesc_handle *hp)
}
EXPORT_SYMBOL(mdesc_release);
+static DEFINE_MUTEX(mdesc_mutex);
+static struct mdesc_notifier_client *client_list;
+
+void mdesc_register_notifier(struct mdesc_notifier_client *client)
+{
+ u64 node;
+
+ mutex_lock(&mdesc_mutex);
+ client->next = client_list;
+ client_list = client;
+
+ mdesc_for_each_node_by_name(cur_mdesc, node, client->node_name)
+ client->add(cur_mdesc, node);
+
+ mutex_unlock(&mdesc_mutex);
+}
+
+static const u64 *parent_cfg_handle(struct mdesc_handle *hp, u64 node)
+{
+ const u64 *id;
+ u64 a;
+
+ id = NULL;
+ mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) {
+ u64 target;
+
+ target = mdesc_arc_target(hp, a);
+ id = mdesc_get_property(hp, target,
+ "cfg-handle", NULL);
+ if (id)
+ break;
+ }
+
+ return id;
+}
+
+/* Run 'func' on nodes which are in A but not in B. */
+static void invoke_on_missing(const char *name,
+ struct mdesc_handle *a,
+ struct mdesc_handle *b,
+ void (*func)(struct mdesc_handle *, u64))
+{
+ u64 node;
+
+ mdesc_for_each_node_by_name(a, node, name) {
+ int found = 0, is_vdc_port = 0;
+ const char *name_prop;
+ const u64 *id;
+ u64 fnode;
+
+ name_prop = mdesc_get_property(a, node, "name", NULL);
+ if (name_prop && !strcmp(name_prop, "vdc-port")) {
+ is_vdc_port = 1;
+ id = parent_cfg_handle(a, node);
+ } else
+ id = mdesc_get_property(a, node, "id", NULL);
+
+ if (!id) {
+ printk(KERN_ERR "MD: Cannot find ID for %s node.\n",
+ (name_prop ? name_prop : name));
+ continue;
+ }
+
+ mdesc_for_each_node_by_name(b, fnode, name) {
+ const u64 *fid;
+
+ if (is_vdc_port) {
+ name_prop = mdesc_get_property(b, fnode,
+ "name", NULL);
+ if (!name_prop ||
+ strcmp(name_prop, "vdc-port"))
+ continue;
+ fid = parent_cfg_handle(b, fnode);
+ if (!fid) {
+ printk(KERN_ERR "MD: Cannot find ID "
+ "for vdc-port node.\n");
+ continue;
+ }
+ } else
+ fid = mdesc_get_property(b, fnode,
+ "id", NULL);
+
+ if (*id == *fid) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ func(a, node);
+ }
+}
+
+static void notify_one(struct mdesc_notifier_client *p,
+ struct mdesc_handle *old_hp,
+ struct mdesc_handle *new_hp)
+{
+ invoke_on_missing(p->node_name, old_hp, new_hp, p->remove);
+ invoke_on_missing(p->node_name, new_hp, old_hp, p->add);
+}
+
+static void mdesc_notify_clients(struct mdesc_handle *old_hp,
+ struct mdesc_handle *new_hp)
+{
+ struct mdesc_notifier_client *p = client_list;
+
+ while (p) {
+ notify_one(p, old_hp, new_hp);
+ p = p->next;
+ }
+}
+
void mdesc_update(void)
{
unsigned long len, real_len, status;
struct mdesc_handle *hp, *orig_hp;
unsigned long flags;
+ mutex_lock(&mdesc_mutex);
+
(void) sun4v_mach_desc(0UL, 0UL, &len);
hp = mdesc_alloc(len, &kmalloc_mdesc_memops);
if (!hp) {
printk(KERN_ERR "MD: mdesc alloc fails\n");
- return;
+ goto out;
}
status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len);
@@ -234,18 +348,25 @@ void mdesc_update(void)
status);
atomic_dec(&hp->refcnt);
mdesc_free(hp);
- return;
+ goto out;
}
spin_lock_irqsave(&mdesc_lock, flags);
orig_hp = cur_mdesc;
cur_mdesc = hp;
+ spin_unlock_irqrestore(&mdesc_lock, flags);
+
+ mdesc_notify_clients(orig_hp, hp);
+ spin_lock_irqsave(&mdesc_lock, flags);
if (atomic_dec_and_test(&orig_hp->refcnt))
mdesc_free(orig_hp);
else
list_add(&orig_hp->list, &mdesc_zombie_list);
spin_unlock_irqrestore(&mdesc_lock, flags);
+
+out:
+ mutex_unlock(&mdesc_mutex);
}
static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)
@@ -448,20 +569,6 @@ static void __init report_platform_properties(void)
mdesc_release(hp);
}
-static int inline find_in_proplist(const char *list, const char *match, int len)
-{
- while (len > 0) {
- int l;
-
- if (!strcmp(list, match))
- return 1;
- l = strlen(list) + 1;
- list += l;
- len -= l;
- }
- return 0;
-}
-
static void __devinit fill_in_one_cache(cpuinfo_sparc *c,
struct mdesc_handle *hp,
u64 mp)
@@ -476,10 +583,10 @@ static void __devinit fill_in_one_cache(cpuinfo_sparc *c,
switch (*level) {
case 1:
- if (find_in_proplist(type, "instn", type_len)) {
+ if (of_find_in_proplist(type, "instn", type_len)) {
c->icache_size = *size;
c->icache_line_size = *line_size;
- } else if (find_in_proplist(type, "data", type_len)) {
+ } else if (of_find_in_proplist(type, "data", type_len)) {
c->dcache_size = *size;
c->dcache_line_size = *line_size;
}
@@ -557,7 +664,7 @@ static void __devinit set_core_ids(struct mdesc_handle *hp)
continue;
type = mdesc_get_property(hp, mp, "type", &len);
- if (!find_in_proplist(type, "instn", len))
+ if (!of_find_in_proplist(type, "instn", len))
continue;
mark_core_ids(hp, mp, idx);
@@ -598,8 +705,8 @@ static void __devinit __set_proc_ids(struct mdesc_handle *hp,
int len;
type = mdesc_get_property(hp, mp, "type", &len);
- if (!find_in_proplist(type, "int", len) &&
- !find_in_proplist(type, "integer", len))
+ if (!of_find_in_proplist(type, "int", len) &&
+ !of_find_in_proplist(type, "integer", len))
continue;
mark_proc_ids(hp, mp, idx);
@@ -670,8 +777,12 @@ void __devinit mdesc_fill_in_cpu_data(cpumask_t mask)
cpuid = *id;
#ifdef CONFIG_SMP
- if (cpuid >= NR_CPUS)
+ if (cpuid >= NR_CPUS) {
+ printk(KERN_WARNING "Ignoring CPU %d which is "
+ ">= NR_CPUS (%d)\n",
+ cpuid, NR_CPUS);
continue;
+ }
if (!cpu_isset(cpuid, mask))
continue;
#else
@@ -730,6 +841,43 @@ void __devinit mdesc_fill_in_cpu_data(cpumask_t mask)
mdesc_release(hp);
}
+static ssize_t mdesc_read(struct file *file, char __user *buf,
+ size_t len, loff_t *offp)
+{
+ struct mdesc_handle *hp = mdesc_grab();
+ int err;
+
+ if (!hp)
+ return -ENODEV;
+
+ err = hp->handle_size;
+ if (len < hp->handle_size)
+ err = -EMSGSIZE;
+ else if (copy_to_user(buf, &hp->mdesc, hp->handle_size))
+ err = -EFAULT;
+ mdesc_release(hp);
+
+ return err;
+}
+
+static const struct file_operations mdesc_fops = {
+ .read = mdesc_read,
+ .owner = THIS_MODULE,
+};
+
+static struct miscdevice mdesc_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "mdesc",
+ .fops = &mdesc_fops,
+};
+
+static int __init mdesc_misc_init(void)
+{
+ return misc_register(&mdesc_misc);
+}
+
+__initcall(mdesc_misc_init);
+
void __init sun4v_mdesc_init(void)
{
struct mdesc_handle *hp;
@@ -740,7 +888,7 @@ void __init sun4v_mdesc_init(void)
printk("MDESC: Size is %lu bytes.\n", len);
- hp = mdesc_alloc(len, &bootmem_mdesc_memops);
+ hp = mdesc_alloc(len, &bootmem_mdesc_ops);
if (hp == NULL) {
prom_printf("MDESC: alloc of %lu bytes failed.\n", len);
prom_halt();
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
index 6676b93219d..4cc77485f53 100644
--- a/arch/sparc64/kernel/of_device.c
+++ b/arch/sparc64/kernel/of_device.c
@@ -1,132 +1,13 @@
#include <linux/string.h>
#include <linux/kernel.h>
+#include <linux/of.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/slab.h>
-
-#include <asm/errno.h>
-#include <asm/of_device.h>
-
-/**
- * of_match_device - Tell if an of_device structure has a matching
- * of_match structure
- * @ids: array of of device match structures to search in
- * @dev: the of device structure to match against
- *
- * Used by a driver to check whether an of_device present in the
- * system is in its list of supported devices.
- */
-const struct of_device_id *of_match_device(const struct of_device_id *matches,
- const struct of_device *dev)
-{
- if (!dev->node)
- return NULL;
- while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
- int match = 1;
- if (matches->name[0])
- match &= dev->node->name
- && !strcmp(matches->name, dev->node->name);
- if (matches->type[0])
- match &= dev->node->type
- && !strcmp(matches->type, dev->node->type);
- if (matches->compatible[0])
- match &= of_device_is_compatible(dev->node,
- matches->compatible);
- if (match)
- return matches;
- matches++;
- }
- return NULL;
-}
-
-static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
-{
- struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * of_drv = to_of_platform_driver(drv);
- const struct of_device_id * matches = of_drv->match_table;
-
- if (!matches)
- return 0;
-
- return of_match_device(matches, of_dev) != NULL;
-}
-
-struct of_device *of_dev_get(struct of_device *dev)
-{
- struct device *tmp;
-
- if (!dev)
- return NULL;
- tmp = get_device(&dev->dev);
- if (tmp)
- return to_of_device(tmp);
- else
- return NULL;
-}
-
-void of_dev_put(struct of_device *dev)
-{
- if (dev)
- put_device(&dev->dev);
-}
-
-
-static int of_device_probe(struct device *dev)
-{
- int error = -ENODEV;
- struct of_platform_driver *drv;
- struct of_device *of_dev;
- const struct of_device_id *match;
-
- drv = to_of_platform_driver(dev->driver);
- of_dev = to_of_device(dev);
-
- if (!drv->probe)
- return error;
-
- of_dev_get(of_dev);
-
- match = of_match_device(drv->match_table, of_dev);
- if (match)
- error = drv->probe(of_dev, match);
- if (error)
- of_dev_put(of_dev);
-
- return error;
-}
-
-static int of_device_remove(struct device *dev)
-{
- struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
-
- if (dev->driver && drv->remove)
- drv->remove(of_dev);
- return 0;
-}
-
-static int of_device_suspend(struct device *dev, pm_message_t state)
-{
- struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
- int error = 0;
-
- if (dev->driver && drv->suspend)
- error = drv->suspend(of_dev, state);
- return error;
-}
-
-static int of_device_resume(struct device * dev)
-{
- struct of_device * of_dev = to_of_device(dev);
- struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
- int error = 0;
-
- if (dev->driver && drv->resume)
- error = drv->resume(of_dev);
- return error;
-}
+#include <linux/errno.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name)
{
@@ -163,7 +44,7 @@ static int node_match(struct device *dev, void *data)
struct of_device *of_find_device_by_node(struct device_node *dp)
{
- struct device *dev = bus_find_device(&of_bus_type, NULL,
+ struct device *dev = bus_find_device(&of_platform_bus_type, NULL,
dp, node_match);
if (dev)
@@ -174,48 +55,20 @@ struct of_device *of_find_device_by_node(struct device_node *dp)
EXPORT_SYMBOL(of_find_device_by_node);
#ifdef CONFIG_PCI
-struct bus_type isa_bus_type = {
- .name = "isa",
- .match = of_platform_bus_match,
- .probe = of_device_probe,
- .remove = of_device_remove,
- .suspend = of_device_suspend,
- .resume = of_device_resume,
-};
+struct bus_type isa_bus_type;
EXPORT_SYMBOL(isa_bus_type);
-struct bus_type ebus_bus_type = {
- .name = "ebus",
- .match = of_platform_bus_match,
- .probe = of_device_probe,
- .remove = of_device_remove,
- .suspend = of_device_suspend,
- .resume = of_device_resume,
-};
+struct bus_type ebus_bus_type;
EXPORT_SYMBOL(ebus_bus_type);
#endif
#ifdef CONFIG_SBUS
-struct bus_type sbus_bus_type = {
- .name = "sbus",
- .match = of_platform_bus_match,
- .probe = of_device_probe,
- .remove = of_device_remove,
- .suspend = of_device_suspend,
- .resume = of_device_resume,
-};
+struct bus_type sbus_bus_type;
EXPORT_SYMBOL(sbus_bus_type);
#endif
-struct bus_type of_bus_type = {
- .name = "of",
- .match = of_platform_bus_match,
- .probe = of_device_probe,
- .remove = of_device_remove,
- .suspend = of_device_suspend,
- .resume = of_device_resume,
-};
-EXPORT_SYMBOL(of_bus_type);
+struct bus_type of_platform_bus_type;
+EXPORT_SYMBOL(of_platform_bus_type);
static inline u64 of_read_addr(const u32 *cell, int size)
{
@@ -899,11 +752,16 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
{
struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
const unsigned int *irq;
+ struct dev_archdata *sd;
int len, i;
if (!op)
return NULL;
+ sd = &op->dev.archdata;
+ sd->prom_node = dp;
+ sd->op = op;
+
op->node = dp;
op->clock_freq = of_getintprop_default(dp, "clock-frequency",
@@ -933,7 +791,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
op->irqs[i] = build_one_device_irq(op, parent, op->irqs[i]);
op->dev.parent = parent;
- op->dev.bus = &of_bus_type;
+ op->dev.bus = &of_platform_bus_type;
if (!parent)
strcpy(op->dev.bus_id, "root");
else
@@ -977,16 +835,16 @@ static int __init of_bus_driver_init(void)
{
int err;
- err = bus_register(&of_bus_type);
+ err = of_bus_type_init(&of_platform_bus_type, "of");
#ifdef CONFIG_PCI
if (!err)
- err = bus_register(&isa_bus_type);
+ err = of_bus_type_init(&isa_bus_type, "isa");
if (!err)
- err = bus_register(&ebus_bus_type);
+ err = of_bus_type_init(&ebus_bus_type, "ebus");
#endif
#ifdef CONFIG_SBUS
if (!err)
- err = bus_register(&sbus_bus_type);
+ err = of_bus_type_init(&sbus_bus_type, "sbus");
#endif
if (!err)
@@ -1020,61 +878,13 @@ int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
/* register with core */
return driver_register(&drv->driver);
}
+EXPORT_SYMBOL(of_register_driver);
void of_unregister_driver(struct of_platform_driver *drv)
{
driver_unregister(&drv->driver);
}
-
-
-static ssize_t dev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct of_device *ofdev;
-
- ofdev = to_of_device(dev);
- return sprintf(buf, "%s", ofdev->node->full_name);
-}
-
-static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
-
-/**
- * of_release_dev - free an of device structure when all users of it are finished.
- * @dev: device that's been disconnected
- *
- * Will be called only by the device core when all users of this of device are
- * done.
- */
-void of_release_dev(struct device *dev)
-{
- struct of_device *ofdev;
-
- ofdev = to_of_device(dev);
-
- kfree(ofdev);
-}
-
-int of_device_register(struct of_device *ofdev)
-{
- int rc;
-
- BUG_ON(ofdev->node == NULL);
-
- rc = device_register(&ofdev->dev);
- if (rc)
- return rc;
-
- rc = device_create_file(&ofdev->dev, &dev_attr_devspec);
- if (rc)
- device_unregister(&ofdev->dev);
-
- return rc;
-}
-
-void of_device_unregister(struct of_device *ofdev)
-{
- device_remove_file(&ofdev->dev, &dev_attr_devspec);
- device_unregister(&ofdev->dev);
-}
+EXPORT_SYMBOL(of_unregister_driver);
struct of_device* of_platform_device_create(struct device_node *np,
const char *bus_id,
@@ -1100,13 +910,4 @@ struct of_device* of_platform_device_create(struct device_node *np,
return dev;
}
-
-EXPORT_SYMBOL(of_match_device);
-EXPORT_SYMBOL(of_register_driver);
-EXPORT_SYMBOL(of_unregister_driver);
-EXPORT_SYMBOL(of_device_register);
-EXPORT_SYMBOL(of_device_unregister);
-EXPORT_SYMBOL(of_dev_get);
-EXPORT_SYMBOL(of_dev_put);
EXPORT_SYMBOL(of_platform_device_create);
-EXPORT_SYMBOL(of_release_dev);
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index 55ad1b899bb..e8dac81d8a0 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -283,12 +283,6 @@ int __init pcic_present(void)
return pci_controller_scan(pci_is_controller);
}
-const struct pci_iommu_ops *pci_iommu_ops;
-EXPORT_SYMBOL(pci_iommu_ops);
-
-extern const struct pci_iommu_ops pci_sun4u_iommu_ops,
- pci_sun4v_iommu_ops;
-
/* Find each controller in the system, attach and initialize
* software state structure for each and link into the
* pci_pbm_root. Setup the controller enough such
@@ -296,11 +290,6 @@ extern const struct pci_iommu_ops pci_sun4u_iommu_ops,
*/
static void __init pci_controller_probe(void)
{
- if (tlb_type == hypervisor)
- pci_iommu_ops = &pci_sun4v_iommu_ops;
- else
- pci_iommu_ops = &pci_sun4u_iommu_ops;
-
printk("PCI: Probing for controllers.\n");
pci_controller_scan(pci_controller_init);
@@ -404,7 +393,10 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
sd->host_controller = pbm;
sd->prom_node = node;
sd->op = of_find_device_by_node(node);
- sd->msi_num = 0xffffffff;
+
+ sd = &sd->op->dev.archdata;
+ sd->iommu = pbm->iommu;
+ sd->stc = &pbm->stc;
type = of_get_property(node, "device_type", NULL);
if (type == NULL)
@@ -422,10 +414,15 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
dev->multifunction = 0; /* maybe a lie? */
if (host_controller) {
- dev->vendor = 0x108e;
- dev->device = 0x8000;
- dev->subsystem_vendor = 0x0000;
- dev->subsystem_device = 0x0000;
+ if (tlb_type != hypervisor) {
+ pci_read_config_word(dev, PCI_VENDOR_ID,
+ &dev->vendor);
+ pci_read_config_word(dev, PCI_DEVICE_ID,
+ &dev->device);
+ } else {
+ dev->vendor = PCI_VENDOR_ID_SUN;
+ dev->device = 0x80f0;
+ }
dev->cfg_size = 256;
dev->class = PCI_CLASS_BRIDGE_HOST << 8;
sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
@@ -747,7 +744,7 @@ static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm,
{
struct device_node *child;
const u32 *reg;
- int reglen, devfn;
+ int reglen, devfn, prev_devfn;
struct pci_dev *dev;
if (ofpci_verbose)
@@ -755,14 +752,25 @@ static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm,
node->full_name, bus->number);
child = NULL;
+ prev_devfn = -1;
while ((child = of_get_next_child(node, child)) != NULL) {
if (ofpci_verbose)
printk(" * %s\n", child->full_name);
reg = of_get_property(child, "reg", &reglen);
if (reg == NULL || reglen < 20)
continue;
+
devfn = (reg[0] >> 8) & 0xff;
+ /* This is a workaround for some device trees
+ * which list PCI devices twice. On the V100
+ * for example, device number 3 is listed twice.
+ * Once as "pm" and once again as "lomp".
+ */
+ if (devfn == prev_devfn)
+ continue;
+ prev_devfn = devfn;
+
/* create a new pci_dev for this device */
dev = of_create_pci_dev(pbm, child, bus, devfn, 0);
if (!dev)
@@ -818,7 +826,7 @@ int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev,
{
static u8 fake_pci_config[] = {
0x8e, 0x10, /* Vendor: 0x108e (Sun) */
- 0x00, 0x80, /* Device: 0x8000 (PBM) */
+ 0xf0, 0x80, /* Device: 0x80f0 (Fire) */
0x46, 0x01, /* Command: 0x0146 (SERR, PARITY, MASTER, MEM) */
0xa0, 0x22, /* Status: 0x02a0 (DEVSEL_MED, FB2B, 66MHZ) */
0x00, 0x00, 0x00, 0x06, /* Class: 0x06000000 host bridge */
@@ -1221,4 +1229,51 @@ struct device_node *pci_device_to_OF_node(struct pci_dev *pdev)
}
EXPORT_SYMBOL(pci_device_to_OF_node);
+static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit)
+{
+ struct pci_dev *ali_isa_bridge;
+ u8 val;
+
+ /* ALI sound chips generate 31-bits of DMA, a special register
+ * determines what bit 31 is emitted as.
+ */
+ ali_isa_bridge = pci_get_device(PCI_VENDOR_ID_AL,
+ PCI_DEVICE_ID_AL_M1533,
+ NULL);
+
+ pci_read_config_byte(ali_isa_bridge, 0x7e, &val);
+ if (set_bit)
+ val |= 0x01;
+ else
+ val &= ~0x01;
+ pci_write_config_byte(ali_isa_bridge, 0x7e, val);
+ pci_dev_put(ali_isa_bridge);
+}
+
+int pci_dma_supported(struct pci_dev *pdev, u64 device_mask)
+{
+ u64 dma_addr_mask;
+
+ if (pdev == NULL) {
+ dma_addr_mask = 0xffffffff;
+ } else {
+ struct iommu *iommu = pdev->dev.archdata.iommu;
+
+ dma_addr_mask = iommu->dma_addr_mask;
+
+ if (pdev->vendor == PCI_VENDOR_ID_AL &&
+ pdev->device == PCI_DEVICE_ID_AL_M5451 &&
+ device_mask == 0x7fffffff) {
+ ali_sound_dma_hack(pdev,
+ (dma_addr_mask & 0x80000000) != 0);
+ return 1;
+ }
+ }
+
+ if (device_mask >= (1UL << 32UL))
+ return 0;
+
+ return (device_mask & dma_addr_mask) == dma_addr_mask;
+}
+
#endif /* !(CONFIG_PCI) */
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
index 4249214608a..c76bfbb7da0 100644
--- a/arch/sparc64/kernel/pci_common.c
+++ b/arch/sparc64/kernel/pci_common.c
@@ -44,6 +44,67 @@ static void *sun4u_config_mkaddr(struct pci_pbm_info *pbm,
return (void *) (pbm->config_space | bus | devfn | reg);
}
+/* At least on Sabre, it is necessary to access all PCI host controller
+ * registers at their natural size, otherwise zeros are returned.
+ * Strange but true, and I see no language in the UltraSPARC-IIi
+ * programmer's manual that mentions this even indirectly.
+ */
+static int sun4u_read_pci_cfg_host(struct pci_pbm_info *pbm,
+ unsigned char bus, unsigned int devfn,
+ int where, int size, u32 *value)
+{
+ u32 tmp32, *addr;
+ u16 tmp16;
+ u8 tmp8;
+
+ addr = sun4u_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ switch (size) {
+ case 1:
+ if (where < 8) {
+ unsigned long align = (unsigned long) addr;
+
+ align &= ~1;
+ pci_config_read16((u16 *)align, &tmp16);
+ if (where & 1)
+ *value = tmp16 >> 8;
+ else
+ *value = tmp16 & 0xff;
+ } else {
+ pci_config_read8((u8 *)addr, &tmp8);
+ *value = (u32) tmp8;
+ }
+ break;
+
+ case 2:
+ if (where < 8) {
+ pci_config_read16((u16 *)addr, &tmp16);
+ *value = (u32) tmp16;
+ } else {
+ pci_config_read8((u8 *)addr, &tmp8);
+ *value = (u32) tmp8;
+ pci_config_read8(((u8 *)addr) + 1, &tmp8);
+ *value |= ((u32) tmp8) << 8;
+ }
+ break;
+
+ case 4:
+ tmp32 = 0xffffffff;
+ sun4u_read_pci_cfg_host(pbm, bus, devfn,
+ where, 2, &tmp32);
+ *value = tmp32;
+
+ tmp32 = 0xffffffff;
+ sun4u_read_pci_cfg_host(pbm, bus, devfn,
+ where + 2, 2, &tmp32);
+ *value |= tmp32 << 16;
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
int where, int size, u32 *value)
{
@@ -53,10 +114,6 @@ static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
u16 tmp16;
u8 tmp8;
- if (bus_dev == pbm->pci_bus && devfn == 0x00)
- return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
- size, value);
-
switch (size) {
case 1:
*value = 0xff;
@@ -69,6 +126,10 @@ static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
break;
}
+ if (!bus_dev->number && !PCI_SLOT(devfn))
+ return sun4u_read_pci_cfg_host(pbm, bus, devfn, where,
+ size, value);
+
addr = sun4u_config_mkaddr(pbm, bus, devfn, where);
if (!addr)
return PCIBIOS_SUCCESSFUL;
@@ -101,6 +162,53 @@ static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
return PCIBIOS_SUCCESSFUL;
}
+static int sun4u_write_pci_cfg_host(struct pci_pbm_info *pbm,
+ unsigned char bus, unsigned int devfn,
+ int where, int size, u32 value)
+{
+ u32 *addr;
+
+ addr = sun4u_config_mkaddr(pbm, bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_SUCCESSFUL;
+
+ switch (size) {
+ case 1:
+ if (where < 8) {
+ unsigned long align = (unsigned long) addr;
+ u16 tmp16;
+
+ align &= ~1;
+ pci_config_read16((u16 *)align, &tmp16);
+ if (where & 1) {
+ tmp16 &= 0x00ff;
+ tmp16 |= value << 8;
+ } else {
+ tmp16 &= 0xff00;
+ tmp16 |= value;
+ }
+ pci_config_write16((u16 *)align, tmp16);
+ } else
+ pci_config_write8((u8 *)addr, value);
+ break;
+ case 2:
+ if (where < 8) {
+ pci_config_write16((u16 *)addr, value);
+ } else {
+ pci_config_write8((u8 *)addr, value & 0xff);
+ pci_config_write8(((u8 *)addr) + 1, value >> 8);
+ }
+ break;
+ case 4:
+ sun4u_write_pci_cfg_host(pbm, bus, devfn,
+ where, 2, value & 0xffff);
+ sun4u_write_pci_cfg_host(pbm, bus, devfn,
+ where + 2, 2, value >> 16);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
static int sun4u_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
int where, int size, u32 value)
{
@@ -108,9 +216,10 @@ static int sun4u_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
unsigned char bus = bus_dev->number;
u32 *addr;
- if (bus_dev == pbm->pci_bus && devfn == 0x00)
- return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
- size, value);
+ if (!bus_dev->number && !PCI_SLOT(devfn))
+ return sun4u_write_pci_cfg_host(pbm, bus, devfn, where,
+ size, value);
+
addr = sun4u_config_mkaddr(pbm, bus, devfn, where);
if (!addr)
return PCIBIOS_SUCCESSFUL;
@@ -155,7 +264,7 @@ static int sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
unsigned int func = PCI_FUNC(devfn);
unsigned long ret;
- if (bus_dev == pbm->pci_bus && devfn == 0x00)
+ if (!bus && devfn == 0x00)
return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where,
size, value);
if (config_out_of_range(pbm, bus, devfn, where)) {
@@ -191,7 +300,7 @@ static int sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn,
unsigned int func = PCI_FUNC(devfn);
unsigned long ret;
- if (bus_dev == pbm->pci_bus && devfn == 0x00)
+ if (!bus && devfn == 0x00)
return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where,
size, value);
if (config_out_of_range(pbm, bus, devfn, where)) {
diff --git a/arch/sparc64/kernel/pci_fire.c b/arch/sparc64/kernel/pci_fire.c
index 7f5d473901c..14d67fe21ab 100644
--- a/arch/sparc64/kernel/pci_fire.c
+++ b/arch/sparc64/kernel/pci_fire.c
@@ -39,12 +39,12 @@ static void pci_fire_scan_bus(struct pci_pbm_info *pbm)
#define FIRE_IOMMU_FLUSH 0x40100UL
#define FIRE_IOMMU_FLUSHINV 0x40108UL
-static void pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm)
+static int pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm)
{
struct iommu *iommu = pbm->iommu;
u32 vdma[2], dma_mask;
u64 control;
- int tsbsize;
+ int tsbsize, err;
/* No virtual-dma property on these guys, use largest size. */
vdma[0] = 0xc0000000; /* base */
@@ -68,7 +68,9 @@ static void pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm)
*/
fire_write(iommu->iommu_flushinv, ~(u64)0);
- pci_iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask);
+ err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask);
+ if (err)
+ return err;
fire_write(iommu->iommu_tsbbase, __pa(iommu->page_table) | 0x7UL);
@@ -78,6 +80,8 @@ static void pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm)
0x00000002 /* Bypass enable */ |
0x00000001 /* Translation enable */);
fire_write(iommu->iommu_control, control);
+
+ return 0;
}
/* Based at pbm->controller_regs */
@@ -167,8 +171,8 @@ static void pci_fire_hw_init(struct pci_pbm_info *pbm)
fire_write(pbm->pbm_regs + FIRE_PEC_IENAB, ~(u64)0);
}
-static void pci_fire_pbm_init(struct pci_controller_info *p,
- struct device_node *dp, u32 portid)
+static int pci_fire_pbm_init(struct pci_controller_info *p,
+ struct device_node *dp, u32 portid)
{
const struct linux_prom64_registers *regs;
struct pci_pbm_info *pbm;
@@ -203,7 +207,8 @@ static void pci_fire_pbm_init(struct pci_controller_info *p,
pci_get_pbm_props(pbm);
pci_fire_hw_init(pbm);
- pci_fire_pbm_iommu_init(pbm);
+
+ return pci_fire_pbm_iommu_init(pbm);
}
static inline int portid_compare(u32 x, u32 y)
@@ -222,7 +227,8 @@ void fire_pci_init(struct device_node *dp, const char *model_name)
for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
if (portid_compare(pbm->portid, portid)) {
- pci_fire_pbm_init(pbm->parent, dp, portid);
+ if (pci_fire_pbm_init(pbm->parent, dp, portid))
+ goto fatal_memory_error;
return;
}
}
@@ -250,7 +256,9 @@ void fire_pci_init(struct device_node *dp, const char *model_name)
*/
pci_memspace_mask = 0x7fffffffUL;
- pci_fire_pbm_init(p, dp, portid);
+ if (pci_fire_pbm_init(p, dp, portid))
+ goto fatal_memory_error;
+
return;
fatal_memory_error:
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index 598393a2df1..b6b4cfea5b5 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -813,16 +813,19 @@ static void psycho_scan_bus(struct pci_pbm_info *pbm)
psycho_register_error_handlers(pbm);
}
-static void psycho_iommu_init(struct pci_pbm_info *pbm)
+static int psycho_iommu_init(struct pci_pbm_info *pbm)
{
struct iommu *iommu = pbm->iommu;
unsigned long i;
u64 control;
+ int err;
/* Register addresses. */
iommu->iommu_control = pbm->controller_regs + PSYCHO_IOMMU_CONTROL;
iommu->iommu_tsbbase = pbm->controller_regs + PSYCHO_IOMMU_TSBBASE;
iommu->iommu_flush = pbm->controller_regs + PSYCHO_IOMMU_FLUSH;
+ iommu->iommu_tags = iommu->iommu_flush + (0xa580UL - 0x0210UL);
+
/* PSYCHO's IOMMU lacks ctx flushing. */
iommu->iommu_ctxflush = 0;
@@ -845,7 +848,9 @@ static void psycho_iommu_init(struct pci_pbm_info *pbm)
/* Leave diag mode enabled for full-flushing done
* in pci_iommu.c
*/
- pci_iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff);
+ err = iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff);
+ if (err)
+ return err;
psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TSBBASE,
__pa(iommu->page_table));
@@ -858,6 +863,8 @@ static void psycho_iommu_init(struct pci_pbm_info *pbm)
/* If necessary, hook us up for starfire IRQ translations. */
if (this_is_starfire)
starfire_hookup(pbm->portid);
+
+ return 0;
}
#define PSYCHO_IRQ_RETRY 0x1a00UL
@@ -1031,15 +1038,12 @@ void psycho_init(struct device_node *dp, char *model_name)
}
p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
- if (!p) {
- prom_printf("PSYCHO: Fatal memory allocation error.\n");
- prom_halt();
- }
+ if (!p)
+ goto fatal_memory_error;
iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
- if (!iommu) {
- prom_printf("PSYCHO: Fatal memory allocation error.\n");
- prom_halt();
- }
+ if (!iommu)
+ goto fatal_memory_error;
+
p->pbm_A.iommu = p->pbm_B.iommu = iommu;
p->pbm_A.portid = upa_portid;
@@ -1062,8 +1066,14 @@ void psycho_init(struct device_node *dp, char *model_name)
psycho_controller_hwinit(&p->pbm_A);
- psycho_iommu_init(&p->pbm_A);
+ if (psycho_iommu_init(&p->pbm_A))
+ goto fatal_memory_error;
is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000);
psycho_pbm_init(p, dp, is_pbm_a);
+ return;
+
+fatal_memory_error:
+ prom_printf("PSYCHO: Fatal memory allocation error.\n");
+ prom_halt();
}
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index 22e1be5c748..fba67c3d880 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -672,18 +672,20 @@ static void sabre_scan_bus(struct pci_pbm_info *pbm)
sabre_register_error_handlers(pbm);
}
-static void sabre_iommu_init(struct pci_pbm_info *pbm,
- int tsbsize, unsigned long dvma_offset,
- u32 dma_mask)
+static int sabre_iommu_init(struct pci_pbm_info *pbm,
+ int tsbsize, unsigned long dvma_offset,
+ u32 dma_mask)
{
struct iommu *iommu = pbm->iommu;
unsigned long i;
u64 control;
+ int err;
/* Register addresses. */
iommu->iommu_control = pbm->controller_regs + SABRE_IOMMU_CONTROL;
iommu->iommu_tsbbase = pbm->controller_regs + SABRE_IOMMU_TSBBASE;
iommu->iommu_flush = pbm->controller_regs + SABRE_IOMMU_FLUSH;
+ iommu->iommu_tags = iommu->iommu_flush + (0xa580UL - 0x0210UL);
iommu->write_complete_reg = pbm->controller_regs + SABRE_WRSYNC;
/* Sabre's IOMMU lacks ctx flushing. */
iommu->iommu_ctxflush = 0;
@@ -701,7 +703,10 @@ static void sabre_iommu_init(struct pci_pbm_info *pbm,
/* Leave diag mode enabled for full-flushing done
* in pci_iommu.c
*/
- pci_iommu_table_init(iommu, tsbsize * 1024 * 8, dvma_offset, dma_mask);
+ err = iommu_table_init(iommu, tsbsize * 1024 * 8,
+ dvma_offset, dma_mask);
+ if (err)
+ return err;
sabre_write(pbm->controller_regs + SABRE_IOMMU_TSBBASE,
__pa(iommu->page_table));
@@ -722,6 +727,8 @@ static void sabre_iommu_init(struct pci_pbm_info *pbm,
break;
}
sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control);
+
+ return 0;
}
static void sabre_pbm_init(struct pci_controller_info *p, struct pci_pbm_info *pbm, struct device_node *dp)
@@ -775,16 +782,12 @@ void sabre_init(struct device_node *dp, char *model_name)
}
p = kzalloc(sizeof(*p), GFP_ATOMIC);
- if (!p) {
- prom_printf("SABRE: Error, kmalloc(pci_controller_info) failed.\n");
- prom_halt();
- }
+ if (!p)
+ goto fatal_memory_error;
iommu = kzalloc(sizeof(*iommu), GFP_ATOMIC);
- if (!iommu) {
- prom_printf("SABRE: Error, kmalloc(pci_iommu) failed.\n");
- prom_halt();
- }
+ if (!iommu)
+ goto fatal_memory_error;
pbm = &p->pbm_A;
pbm->iommu = iommu;
@@ -847,10 +850,16 @@ void sabre_init(struct device_node *dp, char *model_name)
prom_halt();
}
- sabre_iommu_init(pbm, tsbsize, vdma[0], dma_mask);
+ if (sabre_iommu_init(pbm, tsbsize, vdma[0], dma_mask))
+ goto fatal_memory_error;
/*
* Look for APB underneath.
*/
sabre_pbm_init(p, pbm, dp);
+ return;
+
+fatal_memory_error:
+ prom_printf("SABRE: Fatal memory allocation error.\n");
+ prom_halt();
}
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
index ae76898bbe2..3c30bfa1f3a 100644
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/arch/sparc64/kernel/pci_schizo.c
@@ -1148,14 +1148,14 @@ static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm)
#define SCHIZO_IOMMU_FLUSH (0x00210UL)
#define SCHIZO_IOMMU_CTXFLUSH (0x00218UL)
-static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
+static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
{
struct iommu *iommu = pbm->iommu;
unsigned long i, tagbase, database;
struct property *prop;
u32 vdma[2], dma_mask;
+ int tsbsize, err;
u64 control;
- int tsbsize;
prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
if (prop) {
@@ -1195,6 +1195,7 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
iommu->iommu_control = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL;
iommu->iommu_tsbbase = pbm->pbm_regs + SCHIZO_IOMMU_TSBBASE;
iommu->iommu_flush = pbm->pbm_regs + SCHIZO_IOMMU_FLUSH;
+ iommu->iommu_tags = iommu->iommu_flush + (0xa580UL - 0x0210UL);
iommu->iommu_ctxflush = pbm->pbm_regs + SCHIZO_IOMMU_CTXFLUSH;
/* We use the main control/status register of SCHIZO as the write
@@ -1219,7 +1220,9 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
/* Leave diag mode enabled for full-flushing done
* in pci_iommu.c
*/
- pci_iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask);
+ err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask);
+ if (err)
+ return err;
schizo_write(iommu->iommu_tsbbase, __pa(iommu->page_table));
@@ -1236,6 +1239,8 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
control |= SCHIZO_IOMMU_CTRL_ENAB;
schizo_write(iommu->iommu_control, control);
+
+ return 0;
}
#define SCHIZO_PCI_IRQ_RETRY (0x1a00UL)
@@ -1328,14 +1333,14 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm)
}
}
-static void schizo_pbm_init(struct pci_controller_info *p,
- struct device_node *dp, u32 portid,
- int chip_type)
+static int schizo_pbm_init(struct pci_controller_info *p,
+ struct device_node *dp, u32 portid,
+ int chip_type)
{
const struct linux_prom64_registers *regs;
struct pci_pbm_info *pbm;
const char *chipset_name;
- int is_pbm_a;
+ int is_pbm_a, err;
switch (chip_type) {
case PBM_CHIP_TYPE_TOMATILLO:
@@ -1406,8 +1411,13 @@ static void schizo_pbm_init(struct pci_controller_info *p,
pci_get_pbm_props(pbm);
- schizo_pbm_iommu_init(pbm);
+ err = schizo_pbm_iommu_init(pbm);
+ if (err)
+ return err;
+
schizo_pbm_strbuf_init(pbm);
+
+ return 0;
}
static inline int portid_compare(u32 x, u32 y, int chip_type)
@@ -1431,34 +1441,38 @@ static void __schizo_init(struct device_node *dp, char *model_name, int chip_typ
for (pbm = pci_pbm_root; pbm; pbm = pbm->next) {
if (portid_compare(pbm->portid, portid, chip_type)) {
- schizo_pbm_init(pbm->parent, dp, portid, chip_type);
+ if (schizo_pbm_init(pbm->parent, dp,
+ portid, chip_type))
+ goto fatal_memory_error;
return;
}
}
p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
if (!p)
- goto memfail;
+ goto fatal_memory_error;
iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
if (!iommu)
- goto memfail;
+ goto fatal_memory_error;
p->pbm_A.iommu = iommu;
iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC);
if (!iommu)
- goto memfail;
+ goto fatal_memory_error;
p->pbm_B.iommu = iommu;
/* Like PSYCHO we have a 2GB aligned area for memory space. */
pci_memspace_mask = 0x7fffffffUL;
- schizo_pbm_init(p, dp, portid, chip_type);
+ if (schizo_pbm_init(p, dp, portid, chip_type))
+ goto fatal_memory_error;
+
return;
-memfail:
+fatal_memory_error:
prom_printf("SCHIZO: Fatal memory allocation error.\n");
prom_halt();
}
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index 6b3fe2c1d65..da724b13e89 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -33,30 +33,30 @@ static unsigned long vpci_minor = 1;
#define PGLIST_NENTS (PAGE_SIZE / sizeof(u64))
struct iommu_batch {
- struct pci_dev *pdev; /* Device mapping is for. */
+ struct device *dev; /* Device mapping is for. */
unsigned long prot; /* IOMMU page protections */
unsigned long entry; /* Index into IOTSB. */
u64 *pglist; /* List of physical pages */
unsigned long npages; /* Number of pages in list. */
};
-static DEFINE_PER_CPU(struct iommu_batch, pci_iommu_batch);
+static DEFINE_PER_CPU(struct iommu_batch, iommu_batch);
/* Interrupts must be disabled. */
-static inline void pci_iommu_batch_start(struct pci_dev *pdev, unsigned long prot, unsigned long entry)
+static inline void iommu_batch_start(struct device *dev, unsigned long prot, unsigned long entry)
{
- struct iommu_batch *p = &__get_cpu_var(pci_iommu_batch);
+ struct iommu_batch *p = &__get_cpu_var(iommu_batch);
- p->pdev = pdev;
+ p->dev = dev;
p->prot = prot;
p->entry = entry;
p->npages = 0;
}
/* Interrupts must be disabled. */
-static long pci_iommu_batch_flush(struct iommu_batch *p)
+static long iommu_batch_flush(struct iommu_batch *p)
{
- struct pci_pbm_info *pbm = p->pdev->dev.archdata.host_controller;
+ struct pci_pbm_info *pbm = p->dev->archdata.host_controller;
unsigned long devhandle = pbm->devhandle;
unsigned long prot = p->prot;
unsigned long entry = p->entry;
@@ -70,7 +70,7 @@ static long pci_iommu_batch_flush(struct iommu_batch *p)
npages, prot, __pa(pglist));
if (unlikely(num < 0)) {
if (printk_ratelimit())
- printk("pci_iommu_batch_flush: IOMMU map of "
+ printk("iommu_batch_flush: IOMMU map of "
"[%08lx:%08lx:%lx:%lx:%lx] failed with "
"status %ld\n",
devhandle, HV_PCI_TSBID(0, entry),
@@ -90,30 +90,30 @@ static long pci_iommu_batch_flush(struct iommu_batch *p)
}
/* Interrupts must be disabled. */
-static inline long pci_iommu_batch_add(u64 phys_page)
+static inline long iommu_batch_add(u64 phys_page)
{
- struct iommu_batch *p = &__get_cpu_var(pci_iommu_batch);
+ struct iommu_batch *p = &__get_cpu_var(iommu_batch);
BUG_ON(p->npages >= PGLIST_NENTS);
p->pglist[p->npages++] = phys_page;
if (p->npages == PGLIST_NENTS)
- return pci_iommu_batch_flush(p);
+ return iommu_batch_flush(p);
return 0;
}
/* Interrupts must be disabled. */
-static inline long pci_iommu_batch_end(void)
+static inline long iommu_batch_end(void)
{
- struct iommu_batch *p = &__get_cpu_var(pci_iommu_batch);
+ struct iommu_batch *p = &__get_cpu_var(iommu_batch);
BUG_ON(p->npages >= PGLIST_NENTS);
- return pci_iommu_batch_flush(p);
+ return iommu_batch_flush(p);
}
-static long pci_arena_alloc(struct iommu_arena *arena, unsigned long npages)
+static long arena_alloc(struct iommu_arena *arena, unsigned long npages)
{
unsigned long n, i, start, end, limit;
int pass;
@@ -152,7 +152,8 @@ again:
return n;
}
-static void pci_arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages)
+static void arena_free(struct iommu_arena *arena, unsigned long base,
+ unsigned long npages)
{
unsigned long i;
@@ -160,7 +161,8 @@ static void pci_arena_free(struct iommu_arena *arena, unsigned long base, unsign
__clear_bit(i, arena->map);
}
-static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp)
+static void *dma_4v_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_addrp, gfp_t gfp)
{
struct iommu *iommu;
unsigned long flags, order, first_page, npages, n;
@@ -180,10 +182,10 @@ static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr
memset((char *)first_page, 0, PAGE_SIZE << order);
- iommu = pdev->dev.archdata.iommu;
+ iommu = dev->archdata.iommu;
spin_lock_irqsave(&iommu->lock, flags);
- entry = pci_arena_alloc(&iommu->arena, npages);
+ entry = arena_alloc(&iommu->arena, npages);
spin_unlock_irqrestore(&iommu->lock, flags);
if (unlikely(entry < 0L))
@@ -196,18 +198,18 @@ static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr
local_irq_save(flags);
- pci_iommu_batch_start(pdev,
- (HV_PCI_MAP_ATTR_READ |
- HV_PCI_MAP_ATTR_WRITE),
- entry);
+ iommu_batch_start(dev,
+ (HV_PCI_MAP_ATTR_READ |
+ HV_PCI_MAP_ATTR_WRITE),
+ entry);
for (n = 0; n < npages; n++) {
- long err = pci_iommu_batch_add(first_page + (n * PAGE_SIZE));
+ long err = iommu_batch_add(first_page + (n * PAGE_SIZE));
if (unlikely(err < 0L))
goto iommu_map_fail;
}
- if (unlikely(pci_iommu_batch_end() < 0L))
+ if (unlikely(iommu_batch_end() < 0L))
goto iommu_map_fail;
local_irq_restore(flags);
@@ -217,7 +219,7 @@ static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr
iommu_map_fail:
/* Interrupts are disabled. */
spin_lock(&iommu->lock);
- pci_arena_free(&iommu->arena, entry, npages);
+ arena_free(&iommu->arena, entry, npages);
spin_unlock_irqrestore(&iommu->lock, flags);
arena_alloc_fail:
@@ -225,7 +227,8 @@ arena_alloc_fail:
return NULL;
}
-static void pci_4v_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma)
+static void dma_4v_free_coherent(struct device *dev, size_t size, void *cpu,
+ dma_addr_t dvma)
{
struct pci_pbm_info *pbm;
struct iommu *iommu;
@@ -233,14 +236,14 @@ static void pci_4v_free_consistent(struct pci_dev *pdev, size_t size, void *cpu,
u32 devhandle;
npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT;
- iommu = pdev->dev.archdata.iommu;
- pbm = pdev->dev.archdata.host_controller;
+ iommu = dev->archdata.iommu;
+ pbm = dev->archdata.host_controller;
devhandle = pbm->devhandle;
entry = ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
spin_lock_irqsave(&iommu->lock, flags);
- pci_arena_free(&iommu->arena, entry, npages);
+ arena_free(&iommu->arena, entry, npages);
do {
unsigned long num;
@@ -258,7 +261,8 @@ static void pci_4v_free_consistent(struct pci_dev *pdev, size_t size, void *cpu,
free_pages((unsigned long)cpu, order);
}
-static dma_addr_t pci_4v_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction)
+static dma_addr_t dma_4v_map_single(struct device *dev, void *ptr, size_t sz,
+ enum dma_data_direction direction)
{
struct iommu *iommu;
unsigned long flags, npages, oaddr;
@@ -267,9 +271,9 @@ static dma_addr_t pci_4v_map_single(struct pci_dev *pdev, void *ptr, size_t sz,
unsigned long prot;
long entry;
- iommu = pdev->dev.archdata.iommu;
+ iommu = dev->archdata.iommu;
- if (unlikely(direction == PCI_DMA_NONE))
+ if (unlikely(direction == DMA_NONE))
goto bad;
oaddr = (unsigned long)ptr;
@@ -277,7 +281,7 @@ static dma_addr_t pci_4v_map_single(struct pci_dev *pdev, void *ptr, size_t sz,
npages >>= IO_PAGE_SHIFT;
spin_lock_irqsave(&iommu->lock, flags);
- entry = pci_arena_alloc(&iommu->arena, npages);
+ entry = arena_alloc(&iommu->arena, npages);
spin_unlock_irqrestore(&iommu->lock, flags);
if (unlikely(entry < 0L))
@@ -288,19 +292,19 @@ static dma_addr_t pci_4v_map_single(struct pci_dev *pdev, void *ptr, size_t sz,
ret = bus_addr | (oaddr & ~IO_PAGE_MASK);
base_paddr = __pa(oaddr & IO_PAGE_MASK);
prot = HV_PCI_MAP_ATTR_READ;
- if (direction != PCI_DMA_TODEVICE)
+ if (direction != DMA_TO_DEVICE)
prot |= HV_PCI_MAP_ATTR_WRITE;
local_irq_save(flags);
- pci_iommu_batch_start(pdev, prot, entry);
+ iommu_batch_start(dev, prot, entry);
for (i = 0; i < npages; i++, base_paddr += IO_PAGE_SIZE) {
- long err = pci_iommu_batch_add(base_paddr);
+ long err = iommu_batch_add(base_paddr);
if (unlikely(err < 0L))
goto iommu_map_fail;
}
- if (unlikely(pci_iommu_batch_end() < 0L))
+ if (unlikely(iommu_batch_end() < 0L))
goto iommu_map_fail;
local_irq_restore(flags);
@@ -310,18 +314,19 @@ static dma_addr_t pci_4v_map_single(struct pci_dev *pdev, void *ptr, size_t sz,
bad:
if (printk_ratelimit())
WARN_ON(1);
- return PCI_DMA_ERROR_CODE;
+ return DMA_ERROR_CODE;
iommu_map_fail:
/* Interrupts are disabled. */
spin_lock(&iommu->lock);
- pci_arena_free(&iommu->arena, entry, npages);
+ arena_free(&iommu->arena, entry, npages);
spin_unlock_irqrestore(&iommu->lock, flags);
- return PCI_DMA_ERROR_CODE;
+ return DMA_ERROR_CODE;
}
-static void pci_4v_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
+static void dma_4v_unmap_single(struct device *dev, dma_addr_t bus_addr,
+ size_t sz, enum dma_data_direction direction)
{
struct pci_pbm_info *pbm;
struct iommu *iommu;
@@ -329,14 +334,14 @@ static void pci_4v_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_
long entry;
u32 devhandle;
- if (unlikely(direction == PCI_DMA_NONE)) {
+ if (unlikely(direction == DMA_NONE)) {
if (printk_ratelimit())
WARN_ON(1);
return;
}
- iommu = pdev->dev.archdata.iommu;
- pbm = pdev->dev.archdata.host_controller;
+ iommu = dev->archdata.iommu;
+ pbm = dev->archdata.host_controller;
devhandle = pbm->devhandle;
npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
@@ -346,7 +351,7 @@ static void pci_4v_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_
spin_lock_irqsave(&iommu->lock, flags);
entry = (bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT;
- pci_arena_free(&iommu->arena, entry, npages);
+ arena_free(&iommu->arena, entry, npages);
do {
unsigned long num;
@@ -363,7 +368,7 @@ static void pci_4v_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_
#define SG_ENT_PHYS_ADDRESS(SG) \
(__pa(page_address((SG)->page)) + (SG)->offset)
-static inline long fill_sg(long entry, struct pci_dev *pdev,
+static inline long fill_sg(long entry, struct device *dev,
struct scatterlist *sg,
int nused, int nelems, unsigned long prot)
{
@@ -374,7 +379,7 @@ static inline long fill_sg(long entry, struct pci_dev *pdev,
local_irq_save(flags);
- pci_iommu_batch_start(pdev, prot, entry);
+ iommu_batch_start(dev, prot, entry);
for (i = 0; i < nused; i++) {
unsigned long pteval = ~0UL;
@@ -415,7 +420,7 @@ static inline long fill_sg(long entry, struct pci_dev *pdev,
while (len > 0) {
long err;
- err = pci_iommu_batch_add(pteval);
+ err = iommu_batch_add(pteval);
if (unlikely(err < 0L))
goto iommu_map_failed;
@@ -446,7 +451,7 @@ static inline long fill_sg(long entry, struct pci_dev *pdev,
dma_sg++;
}
- if (unlikely(pci_iommu_batch_end() < 0L))
+ if (unlikely(iommu_batch_end() < 0L))
goto iommu_map_failed;
local_irq_restore(flags);
@@ -457,7 +462,8 @@ iommu_map_failed:
return -1L;
}
-static int pci_4v_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
+static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
+ int nelems, enum dma_data_direction direction)
{
struct iommu *iommu;
unsigned long flags, npages, prot;
@@ -469,18 +475,19 @@ static int pci_4v_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int n
/* Fast path single entry scatterlists. */
if (nelems == 1) {
sglist->dma_address =
- pci_4v_map_single(pdev,
- (page_address(sglist->page) + sglist->offset),
+ dma_4v_map_single(dev,
+ (page_address(sglist->page) +
+ sglist->offset),
sglist->length, direction);
- if (unlikely(sglist->dma_address == PCI_DMA_ERROR_CODE))
+ if (unlikely(sglist->dma_address == DMA_ERROR_CODE))
return 0;
sglist->dma_length = sglist->length;
return 1;
}
- iommu = pdev->dev.archdata.iommu;
+ iommu = dev->archdata.iommu;
- if (unlikely(direction == PCI_DMA_NONE))
+ if (unlikely(direction == DMA_NONE))
goto bad;
/* Step 1: Prepare scatter list. */
@@ -488,7 +495,7 @@ static int pci_4v_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int n
/* Step 2: Allocate a cluster and context, if necessary. */
spin_lock_irqsave(&iommu->lock, flags);
- entry = pci_arena_alloc(&iommu->arena, npages);
+ entry = arena_alloc(&iommu->arena, npages);
spin_unlock_irqrestore(&iommu->lock, flags);
if (unlikely(entry < 0L))
@@ -510,10 +517,10 @@ static int pci_4v_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int n
/* Step 4: Create the mappings. */
prot = HV_PCI_MAP_ATTR_READ;
- if (direction != PCI_DMA_TODEVICE)
+ if (direction != DMA_TO_DEVICE)
prot |= HV_PCI_MAP_ATTR_WRITE;
- err = fill_sg(entry, pdev, sglist, used, nelems, prot);
+ err = fill_sg(entry, dev, sglist, used, nelems, prot);
if (unlikely(err < 0L))
goto iommu_map_failed;
@@ -526,13 +533,14 @@ bad:
iommu_map_failed:
spin_lock_irqsave(&iommu->lock, flags);
- pci_arena_free(&iommu->arena, entry, npages);
+ arena_free(&iommu->arena, entry, npages);
spin_unlock_irqrestore(&iommu->lock, flags);
return 0;
}
-static void pci_4v_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
+static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist,
+ int nelems, enum dma_data_direction direction)
{
struct pci_pbm_info *pbm;
struct iommu *iommu;
@@ -540,13 +548,13 @@ static void pci_4v_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, in
long entry;
u32 devhandle, bus_addr;
- if (unlikely(direction == PCI_DMA_NONE)) {
+ if (unlikely(direction == DMA_NONE)) {
if (printk_ratelimit())
WARN_ON(1);
}
- iommu = pdev->dev.archdata.iommu;
- pbm = pdev->dev.archdata.host_controller;
+ iommu = dev->archdata.iommu;
+ pbm = dev->archdata.host_controller;
devhandle = pbm->devhandle;
bus_addr = sglist->dma_address & IO_PAGE_MASK;
@@ -562,7 +570,7 @@ static void pci_4v_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, in
spin_lock_irqsave(&iommu->lock, flags);
- pci_arena_free(&iommu->arena, entry, npages);
+ arena_free(&iommu->arena, entry, npages);
do {
unsigned long num;
@@ -576,25 +584,29 @@ static void pci_4v_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, in
spin_unlock_irqrestore(&iommu->lock, flags);
}
-static void pci_4v_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction)
+static void dma_4v_sync_single_for_cpu(struct device *dev,
+ dma_addr_t bus_addr, size_t sz,
+ enum dma_data_direction direction)
{
/* Nothing to do... */
}
-static void pci_4v_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction)
+static void dma_4v_sync_sg_for_cpu(struct device *dev,
+ struct scatterlist *sglist, int nelems,
+ enum dma_data_direction direction)
{
/* Nothing to do... */
}
-const struct pci_iommu_ops pci_sun4v_iommu_ops = {
- .alloc_consistent = pci_4v_alloc_consistent,
- .free_consistent = pci_4v_free_consistent,
- .map_single = pci_4v_map_single,
- .unmap_single = pci_4v_unmap_single,
- .map_sg = pci_4v_map_sg,
- .unmap_sg = pci_4v_unmap_sg,
- .dma_sync_single_for_cpu = pci_4v_dma_sync_single_for_cpu,
- .dma_sync_sg_for_cpu = pci_4v_dma_sync_sg_for_cpu,
+const struct dma_ops sun4v_dma_ops = {
+ .alloc_coherent = dma_4v_alloc_coherent,
+ .free_coherent = dma_4v_free_coherent,
+ .map_single = dma_4v_map_single,
+ .unmap_single = dma_4v_unmap_single,
+ .map_sg = dma_4v_map_sg,
+ .unmap_sg = dma_4v_unmap_sg,
+ .sync_single_for_cpu = dma_4v_sync_single_for_cpu,
+ .sync_sg_for_cpu = dma_4v_sync_sg_for_cpu,
};
static void pci_sun4v_scan_bus(struct pci_pbm_info *pbm)
@@ -928,13 +940,13 @@ static int pci_sun4v_setup_msi_irq(unsigned int *virt_irq_p,
if (msi_num < 0)
return msi_num;
- devino = sun4v_build_msi(pbm->devhandle, virt_irq_p,
- pbm->msiq_first_devino,
- (pbm->msiq_first_devino +
- pbm->msiq_num));
- err = -ENOMEM;
- if (!devino)
+ err = sun4v_build_msi(pbm->devhandle, virt_irq_p,
+ pbm->msiq_first_devino,
+ (pbm->msiq_first_devino +
+ pbm->msiq_num));
+ if (err < 0)
goto out_err;
+ devino = err;
msiqid = ((devino - pbm->msiq_first_devino) +
pbm->msiq_first);
@@ -959,7 +971,7 @@ static int pci_sun4v_setup_msi_irq(unsigned int *virt_irq_p,
if (pci_sun4v_msi_setvalid(pbm->devhandle, msi_num, HV_MSIVALID_VALID))
goto out_err;
- pdev->dev.archdata.msi_num = msi_num;
+ sparc64_set_msi(*virt_irq_p, msi_num);
if (entry->msi_attrib.is_64) {
msg.address_hi = pbm->msi64_start >> 32;
@@ -981,8 +993,6 @@ static int pci_sun4v_setup_msi_irq(unsigned int *virt_irq_p,
out_err:
free_msi(pbm, msi_num);
- sun4v_destroy_msi(*virt_irq_p);
- *virt_irq_p = 0;
return err;
}
@@ -994,7 +1004,7 @@ static void pci_sun4v_teardown_msi_irq(unsigned int virt_irq,
unsigned long msiqid, err;
unsigned int msi_num;
- msi_num = pdev->dev.archdata.msi_num;
+ msi_num = sparc64_get_msi(virt_irq);
err = pci_sun4v_msi_getmsiq(pbm->devhandle, msi_num, &msiqid);
if (err) {
printk(KERN_ERR "%s: getmsiq gives error %lu\n",
@@ -1129,7 +1139,7 @@ static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
}
#endif /* !(CONFIG_PCI_MSI) */
-static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle)
+static void __init pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle)
{
struct pci_pbm_info *pbm;
@@ -1163,7 +1173,7 @@ static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node
pci_sun4v_msi_init(pbm);
}
-void sun4v_pci_init(struct device_node *dp, char *model_name)
+void __init sun4v_pci_init(struct device_node *dp, char *model_name)
{
static int hvapi_negotiated = 0;
struct pci_controller_info *p;
@@ -1186,6 +1196,8 @@ void sun4v_pci_init(struct device_node *dp, char *model_name)
}
printk("SUN4V_PCI: Registered hvapi major[%lu] minor[%lu]\n",
vpci_major, vpci_minor);
+
+ dma_ops = &sun4v_dma_ops;
}
prop = of_find_property(dp, "reg", NULL);
@@ -1206,7 +1218,7 @@ void sun4v_pci_init(struct device_node *dp, char *model_name)
if (!page)
goto fatal_memory_error;
- per_cpu(pci_iommu_batch, i).pglist = (u64 *) page;
+ per_cpu(iommu_batch, i).pglist = (u64 *) page;
}
p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC);
diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
index 8dd4294ad21..881a09ee4c4 100644
--- a/arch/sparc64/kernel/power.c
+++ b/arch/sparc64/kernel/power.c
@@ -12,13 +12,13 @@
#include <linux/interrupt.h>
#include <linux/pm.h>
#include <linux/syscalls.h>
+#include <linux/reboot.h>
#include <asm/system.h>
#include <asm/auxio.h>
#include <asm/prom.h>
#include <asm/of_device.h>
#include <asm/io.h>
-#include <asm/power.h>
#include <asm/sstate.h>
#include <linux/unistd.h>
@@ -31,20 +31,9 @@ int scons_pwroff = 1;
static void __iomem *power_reg;
-static DECLARE_WAIT_QUEUE_HEAD(powerd_wait);
-static int button_pressed;
-
-void wake_up_powerd(void)
-{
- if (button_pressed == 0) {
- button_pressed = 1;
- wake_up(&powerd_wait);
- }
-}
-
static irqreturn_t power_handler(int irq, void *dev_id)
{
- wake_up_powerd();
+ orderly_poweroff(true);
/* FIXME: Check registers for status... */
return IRQ_HANDLED;
@@ -57,7 +46,7 @@ static void (*poweroff_method)(void) = machine_alt_power_off;
void machine_power_off(void)
{
sstate_poweroff();
- if (!serial_console || scons_pwroff) {
+ if (strcmp(of_console_device->type, "serial") || scons_pwroff) {
if (power_reg) {
/* Both register bits seem to have the
* same effect, so until I figure out
@@ -77,48 +66,6 @@ void machine_power_off(void)
void (*pm_power_off)(void) = machine_power_off;
EXPORT_SYMBOL(pm_power_off);
-static int powerd(void *__unused)
-{
- static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
- char *argv[] = { "/sbin/shutdown", "-h", "now", NULL };
- DECLARE_WAITQUEUE(wait, current);
-
- daemonize("powerd");
-
- add_wait_queue(&powerd_wait, &wait);
-
- for (;;) {
- set_task_state(current, TASK_INTERRUPTIBLE);
- if (button_pressed)
- break;
- flush_signals(current);
- schedule();
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&powerd_wait, &wait);
-
- /* Ok, down we go... */
- button_pressed = 0;
- if (kernel_execve("/sbin/shutdown", argv, envp) < 0) {
- printk(KERN_ERR "powerd: shutdown execution failed\n");
- machine_power_off();
- }
- return 0;
-}
-
-int start_powerd(void)
-{
- int err;
-
- err = kernel_thread(powerd, NULL, CLONE_FS);
- if (err < 0)
- printk(KERN_ERR "power: Failed to start power daemon.\n");
- else
- printk(KERN_INFO "power: powerd running.\n");
-
- return err;
-}
-
static int __init has_button_interrupt(unsigned int irq, struct device_node *dp)
{
if (irq == 0xffffffff)
@@ -136,20 +83,15 @@ static int __devinit power_probe(struct of_device *op, const struct of_device_id
power_reg = of_ioremap(res, 0, 0x4, "power");
- printk("%s: Control reg at %lx ... ",
+ printk(KERN_INFO "%s: Control reg at %lx\n",
op->node->name, res->start);
poweroff_method = machine_halt; /* able to use the standard halt */
if (has_button_interrupt(irq, op->node)) {
- if (start_powerd() < 0)
- return 0;
-
if (request_irq(irq,
power_handler, 0, "power", NULL) < 0)
printk(KERN_ERR "power: Cannot setup IRQ handler.\n");
- } else {
- printk(KERN_INFO "power: Not using powerd.\n");
}
return 0;
@@ -170,6 +112,6 @@ static struct of_platform_driver power_driver = {
void __init power_init(void)
{
- of_register_driver(&power_driver, &of_bus_type);
+ of_register_driver(&power_driver, &of_platform_bus_type);
return;
}
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 93557507ec9..ca7cdfd55f7 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -18,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/kallsyms.h>
#include <linux/mm.h>
+#include <linux/fs.h>
#include <linux/smp.h>
#include <linux/stddef.h>
#include <linux/ptrace.h>
@@ -119,7 +120,7 @@ extern void (*prom_keyboard)(void);
void machine_halt(void)
{
sstate_halt();
- if (!serial_console && prom_palette)
+ if (prom_palette)
prom_palette (1);
if (prom_keyboard)
prom_keyboard();
@@ -130,7 +131,7 @@ void machine_halt(void)
void machine_alt_power_off(void)
{
sstate_poweroff();
- if (!serial_console && prom_palette)
+ if (prom_palette)
prom_palette(1);
if (prom_keyboard)
prom_keyboard();
@@ -145,7 +146,7 @@ void machine_restart(char * cmd)
sstate_reboot();
p = strchr (reboot_command, '\n');
if (p) *p = 0;
- if (!serial_console && prom_palette)
+ if (prom_palette)
prom_palette (1);
if (prom_keyboard)
prom_keyboard();
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index 5d220302cd5..a246e962e5a 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -30,73 +30,9 @@
#include <asm/upa.h>
#include <asm/smp.h>
-static struct device_node *allnodes;
+extern struct device_node *allnodes; /* temporary while merging */
-/* use when traversing tree through the allnext, child, sibling,
- * or parent members of struct device_node.
- */
-static DEFINE_RWLOCK(devtree_lock);
-
-int of_device_is_compatible(const struct device_node *device,
- const char *compat)
-{
- const char* cp;
- int cplen, l;
-
- cp = of_get_property(device, "compatible", &cplen);
- if (cp == NULL)
- return 0;
- while (cplen > 0) {
- if (strncmp(cp, compat, strlen(compat)) == 0)
- return 1;
- l = strlen(cp) + 1;
- cp += l;
- cplen -= l;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(of_device_is_compatible);
-
-struct device_node *of_get_parent(const struct device_node *node)
-{
- struct device_node *np;
-
- if (!node)
- return NULL;
-
- np = node->parent;
-
- return np;
-}
-EXPORT_SYMBOL(of_get_parent);
-
-struct device_node *of_get_next_child(const struct device_node *node,
- struct device_node *prev)
-{
- struct device_node *next;
-
- next = prev ? prev->sibling : node->child;
- for (; next != 0; next = next->sibling) {
- break;
- }
-
- return next;
-}
-EXPORT_SYMBOL(of_get_next_child);
-
-struct device_node *of_find_node_by_path(const char *path)
-{
- struct device_node *np = allnodes;
-
- for (; np != 0; np = np->allnext) {
- if (np->full_name != 0 && strcmp(np->full_name, path) == 0)
- break;
- }
-
- return np;
-}
-EXPORT_SYMBOL(of_find_node_by_path);
+extern rwlock_t devtree_lock; /* temporary while merging */
struct device_node *of_find_node_by_phandle(phandle handle)
{
@@ -110,81 +46,6 @@ struct device_node *of_find_node_by_phandle(phandle handle)
}
EXPORT_SYMBOL(of_find_node_by_phandle);
-struct device_node *of_find_node_by_name(struct device_node *from,
- const char *name)
-{
- struct device_node *np;
-
- np = from ? from->allnext : allnodes;
- for (; np != NULL; np = np->allnext)
- if (np->name != NULL && strcmp(np->name, name) == 0)
- break;
-
- return np;
-}
-EXPORT_SYMBOL(of_find_node_by_name);
-
-struct device_node *of_find_node_by_type(struct device_node *from,
- const char *type)
-{
- struct device_node *np;
-
- np = from ? from->allnext : allnodes;
- for (; np != 0; np = np->allnext)
- if (np->type != 0 && strcmp(np->type, type) == 0)
- break;
-
- return np;
-}
-EXPORT_SYMBOL(of_find_node_by_type);
-
-struct device_node *of_find_compatible_node(struct device_node *from,
- const char *type, const char *compatible)
-{
- struct device_node *np;
-
- np = from ? from->allnext : allnodes;
- for (; np != 0; np = np->allnext) {
- if (type != NULL
- && !(np->type != 0 && strcmp(np->type, type) == 0))
- continue;
- if (of_device_is_compatible(np, compatible))
- break;
- }
-
- return np;
-}
-EXPORT_SYMBOL(of_find_compatible_node);
-
-struct property *of_find_property(const struct device_node *np,
- const char *name,
- int *lenp)
-{
- struct property *pp;
-
- for (pp = np->properties; pp != 0; pp = pp->next) {
- if (strcasecmp(pp->name, name) == 0) {
- if (lenp != 0)
- *lenp = pp->length;
- break;
- }
- }
- return pp;
-}
-EXPORT_SYMBOL(of_find_property);
-
-/*
- * Find a property with a given name for a given node
- * and return the value.
- */
-const void *of_get_property(const struct device_node *np, const char *name,
- int *lenp)
-{
- struct property *pp = of_find_property(np,name,lenp);
- return pp ? pp->value : NULL;
-}
-EXPORT_SYMBOL(of_get_property);
-
int of_getintprop_default(struct device_node *np, const char *name, int def)
{
struct property *prop;
@@ -198,36 +59,6 @@ int of_getintprop_default(struct device_node *np, const char *name, int def)
}
EXPORT_SYMBOL(of_getintprop_default);
-int of_n_addr_cells(struct device_node *np)
-{
- const int* ip;
- do {
- if (np->parent)
- np = np->parent;
- ip = of_get_property(np, "#address-cells", NULL);
- if (ip != NULL)
- return *ip;
- } while (np->parent);
- /* No #address-cells property for the root node, default to 2 */
- return 2;
-}
-EXPORT_SYMBOL(of_n_addr_cells);
-
-int of_n_size_cells(struct device_node *np)
-{
- const int* ip;
- do {
- if (np->parent)
- np = np->parent;
- ip = of_get_property(np, "#size-cells", NULL);
- if (ip != NULL)
- return *ip;
- } while (np->parent);
- /* No #size-cells property for the root node, default to 1 */
- return 1;
-}
-EXPORT_SYMBOL(of_n_size_cells);
-
int of_set_property(struct device_node *dp, const char *name, void *val, int len)
{
struct property **prevp;
@@ -276,6 +107,21 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len
}
EXPORT_SYMBOL(of_set_property);
+int of_find_in_proplist(const char *list, const char *match, int len)
+{
+ while (len > 0) {
+ int l;
+
+ if (!strcmp(list, match))
+ return 1;
+ l = strlen(list) + 1;
+ list += l;
+ len -= l;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(of_find_in_proplist);
+
static unsigned int prom_early_allocated;
static void * __init prom_early_alloc(unsigned long size)
@@ -1200,7 +1046,8 @@ static void __init irq_trans_init(struct device_node *dp)
if (!strcmp(dp->name, "fhc") &&
!strcmp(dp->parent->name, "central"))
return central_irq_trans_init(dp);
- if (!strcmp(dp->name, "virtual-devices"))
+ if (!strcmp(dp->name, "virtual-devices") ||
+ !strcmp(dp->name, "niu"))
return sun4v_vdev_irq_trans_init(dp);
}
@@ -1737,8 +1584,12 @@ static void __init of_fill_in_cpu_data(void)
ncpus_probed++;
#ifdef CONFIG_SMP
- if (cpuid >= NR_CPUS)
+ if (cpuid >= NR_CPUS) {
+ printk(KERN_WARNING "Ignoring CPU %d which is "
+ ">= NR_CPUS (%d)\n",
+ cpuid, NR_CPUS);
continue;
+ }
#else
/* On uniprocessor we only want the values for the
* real physical cpu the kernel booted onto, however
@@ -1815,6 +1666,60 @@ static void __init of_fill_in_cpu_data(void)
smp_fill_in_sib_core_maps();
}
+struct device_node *of_console_device;
+EXPORT_SYMBOL(of_console_device);
+
+char *of_console_path;
+EXPORT_SYMBOL(of_console_path);
+
+char *of_console_options;
+EXPORT_SYMBOL(of_console_options);
+
+static void __init of_console_init(void)
+{
+ char *msg = "OF stdout device is: %s\n";
+ struct device_node *dp;
+ const char *type;
+ phandle node;
+
+ of_console_path = prom_early_alloc(256);
+ if (prom_ihandle2path(prom_stdout, of_console_path, 256) < 0) {
+ prom_printf("Cannot obtain path of stdout.\n");
+ prom_halt();
+ }
+ of_console_options = strrchr(of_console_path, ':');
+ if (of_console_options) {
+ of_console_options++;
+ if (*of_console_options == '\0')
+ of_console_options = NULL;
+ }
+
+ node = prom_inst2pkg(prom_stdout);
+ if (!node) {
+ prom_printf("Cannot resolve stdout node from "
+ "instance %08x.\n", prom_stdout);
+ prom_halt();
+ }
+
+ dp = of_find_node_by_phandle(node);
+ type = of_get_property(dp, "device_type", NULL);
+ if (!type) {
+ prom_printf("Console stdout lacks device_type property.\n");
+ prom_halt();
+ }
+
+ if (strcmp(type, "display") && strcmp(type, "serial")) {
+ prom_printf("Console device_type is neither display "
+ "nor serial.\n");
+ prom_halt();
+ }
+
+ of_console_device = dp;
+
+ prom_printf(msg, of_console_path);
+ printk(msg, of_console_path);
+}
+
void __init prom_build_devicetree(void)
{
struct device_node **nextp;
@@ -1827,6 +1732,8 @@ void __init prom_build_devicetree(void)
allnodes->child = build_tree(allnodes,
prom_getchild(allnodes->node),
&nextp);
+ of_console_init();
+
printk("PROM: Built device tree with %u bytes of memory.\n",
prom_early_allocated);
diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
index a1fd9bcc0b8..d1fb13ba02b 100644
--- a/arch/sparc64/kernel/sbus.c
+++ b/arch/sparc64/kernel/sbus.c
@@ -26,11 +26,6 @@
#define MAP_BASE ((u32)0xc0000000)
-struct sbus_info {
- struct iommu iommu;
- struct strbuf strbuf;
-};
-
/* Offsets from iommu_regs */
#define SYSIO_IOMMUREG_BASE 0x2400UL
#define IOMMU_CONTROL (0x2400UL - 0x2400UL) /* IOMMU control register */
@@ -44,19 +39,6 @@ struct sbus_info {
#define IOMMU_DRAM_VALID (1UL << 30UL)
-static void __iommu_flushall(struct iommu *iommu)
-{
- unsigned long tag;
- int entry;
-
- tag = iommu->iommu_control + (IOMMU_TAGDIAG - IOMMU_CONTROL);
- for (entry = 0; entry < 16; entry++) {
- upa_writeq(0, tag);
- tag += 8UL;
- }
- upa_readq(iommu->write_complete_reg);
-}
-
/* Offsets from strbuf_regs */
#define SYSIO_STRBUFREG_BASE 0x2800UL
#define STRBUF_CONTROL (0x2800UL - 0x2800UL) /* Control */
@@ -69,511 +51,10 @@ static void __iommu_flushall(struct iommu *iommu)
#define STRBUF_TAG_VALID 0x02UL
-static void sbus_strbuf_flush(struct iommu *iommu, struct strbuf *strbuf, u32 base, unsigned long npages, int direction)
-{
- unsigned long n;
- int limit;
-
- n = npages;
- while (n--)
- upa_writeq(base + (n << IO_PAGE_SHIFT), strbuf->strbuf_pflush);
-
- /* If the device could not have possibly put dirty data into
- * the streaming cache, no flush-flag synchronization needs
- * to be performed.
- */
- if (direction == SBUS_DMA_TODEVICE)
- return;
-
- *(strbuf->strbuf_flushflag) = 0UL;
-
- /* Whoopee cushion! */
- upa_writeq(strbuf->strbuf_flushflag_pa, strbuf->strbuf_fsync);
- upa_readq(iommu->write_complete_reg);
-
- limit = 100000;
- while (*(strbuf->strbuf_flushflag) == 0UL) {
- limit--;
- if (!limit)
- break;
- udelay(1);
- rmb();
- }
- if (!limit)
- printk(KERN_WARNING "sbus_strbuf_flush: flushflag timeout "
- "vaddr[%08x] npages[%ld]\n",
- base, npages);
-}
-
-/* Based largely upon the ppc64 iommu allocator. */
-static long sbus_arena_alloc(struct iommu *iommu, unsigned long npages)
-{
- struct iommu_arena *arena = &iommu->arena;
- unsigned long n, i, start, end, limit;
- int pass;
-
- limit = arena->limit;
- start = arena->hint;
- pass = 0;
-
-again:
- n = find_next_zero_bit(arena->map, limit, start);
- end = n + npages;
- if (unlikely(end >= limit)) {
- if (likely(pass < 1)) {
- limit = start;
- start = 0;
- __iommu_flushall(iommu);
- pass++;
- goto again;
- } else {
- /* Scanned the whole thing, give up. */
- return -1;
- }
- }
-
- for (i = n; i < end; i++) {
- if (test_bit(i, arena->map)) {
- start = i + 1;
- goto again;
- }
- }
-
- for (i = n; i < end; i++)
- __set_bit(i, arena->map);
-
- arena->hint = end;
-
- return n;
-}
-
-static void sbus_arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages)
-{
- unsigned long i;
-
- for (i = base; i < (base + npages); i++)
- __clear_bit(i, arena->map);
-}
-
-static void sbus_iommu_table_init(struct iommu *iommu, unsigned int tsbsize)
-{
- unsigned long tsbbase, order, sz, num_tsb_entries;
-
- num_tsb_entries = tsbsize / sizeof(iopte_t);
-
- /* Setup initial software IOMMU state. */
- spin_lock_init(&iommu->lock);
- iommu->page_table_map_base = MAP_BASE;
-
- /* Allocate and initialize the free area map. */
- sz = num_tsb_entries / 8;
- sz = (sz + 7UL) & ~7UL;
- iommu->arena.map = kzalloc(sz, GFP_KERNEL);
- if (!iommu->arena.map) {
- prom_printf("SBUS_IOMMU: Error, kmalloc(arena.map) failed.\n");
- prom_halt();
- }
- iommu->arena.limit = num_tsb_entries;
-
- /* Now allocate and setup the IOMMU page table itself. */
- order = get_order(tsbsize);
- tsbbase = __get_free_pages(GFP_KERNEL, order);
- if (!tsbbase) {
- prom_printf("IOMMU: Error, gfp(tsb) failed.\n");
- prom_halt();
- }
- iommu->page_table = (iopte_t *)tsbbase;
- memset(iommu->page_table, 0, tsbsize);
-}
-
-static inline iopte_t *alloc_npages(struct iommu *iommu, unsigned long npages)
-{
- long entry;
-
- entry = sbus_arena_alloc(iommu, npages);
- if (unlikely(entry < 0))
- return NULL;
-
- return iommu->page_table + entry;
-}
-
-static inline void free_npages(struct iommu *iommu, dma_addr_t base, unsigned long npages)
-{
- sbus_arena_free(&iommu->arena, base >> IO_PAGE_SHIFT, npages);
-}
-
-void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma_addr)
-{
- struct sbus_info *info;
- struct iommu *iommu;
- iopte_t *iopte;
- unsigned long flags, order, first_page;
- void *ret;
- int npages;
-
- size = IO_PAGE_ALIGN(size);
- order = get_order(size);
- if (order >= 10)
- return NULL;
-
- first_page = __get_free_pages(GFP_KERNEL|__GFP_COMP, order);
- if (first_page == 0UL)
- return NULL;
- memset((char *)first_page, 0, PAGE_SIZE << order);
-
- info = sdev->bus->iommu;
- iommu = &info->iommu;
-
- spin_lock_irqsave(&iommu->lock, flags);
- iopte = alloc_npages(iommu, size >> IO_PAGE_SHIFT);
- spin_unlock_irqrestore(&iommu->lock, flags);
-
- if (unlikely(iopte == NULL)) {
- free_pages(first_page, order);
- return NULL;
- }
-
- *dvma_addr = (iommu->page_table_map_base +
- ((iopte - iommu->page_table) << IO_PAGE_SHIFT));
- ret = (void *) first_page;
- npages = size >> IO_PAGE_SHIFT;
- first_page = __pa(first_page);
- while (npages--) {
- iopte_val(*iopte) = (IOPTE_VALID | IOPTE_CACHE |
- IOPTE_WRITE |
- (first_page & IOPTE_PAGE));
- iopte++;
- first_page += IO_PAGE_SIZE;
- }
-
- return ret;
-}
-
-void sbus_free_consistent(struct sbus_dev *sdev, size_t size, void *cpu, dma_addr_t dvma)
-{
- struct sbus_info *info;
- struct iommu *iommu;
- iopte_t *iopte;
- unsigned long flags, order, npages;
-
- npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT;
- info = sdev->bus->iommu;
- iommu = &info->iommu;
- iopte = iommu->page_table +
- ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
-
- spin_lock_irqsave(&iommu->lock, flags);
-
- free_npages(iommu, dvma - iommu->page_table_map_base, npages);
-
- spin_unlock_irqrestore(&iommu->lock, flags);
-
- order = get_order(size);
- if (order < 10)
- free_pages((unsigned long)cpu, order);
-}
-
-dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t sz, int direction)
-{
- struct sbus_info *info;
- struct iommu *iommu;
- iopte_t *base;
- unsigned long flags, npages, oaddr;
- unsigned long i, base_paddr;
- u32 bus_addr, ret;
- unsigned long iopte_protection;
-
- info = sdev->bus->iommu;
- iommu = &info->iommu;
-
- if (unlikely(direction == SBUS_DMA_NONE))
- BUG();
-
- oaddr = (unsigned long)ptr;
- npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK);
- npages >>= IO_PAGE_SHIFT;
-
- spin_lock_irqsave(&iommu->lock, flags);
- base = alloc_npages(iommu, npages);
- spin_unlock_irqrestore(&iommu->lock, flags);
-
- if (unlikely(!base))
- BUG();
-
- bus_addr = (iommu->page_table_map_base +
- ((base - iommu->page_table) << IO_PAGE_SHIFT));
- ret = bus_addr | (oaddr & ~IO_PAGE_MASK);
- base_paddr = __pa(oaddr & IO_PAGE_MASK);
-
- iopte_protection = IOPTE_VALID | IOPTE_STBUF | IOPTE_CACHE;
- if (direction != SBUS_DMA_TODEVICE)
- iopte_protection |= IOPTE_WRITE;
-
- for (i = 0; i < npages; i++, base++, base_paddr += IO_PAGE_SIZE)
- iopte_val(*base) = iopte_protection | base_paddr;
-
- return ret;
-}
-
-void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t bus_addr, size_t sz, int direction)
-{
- struct sbus_info *info = sdev->bus->iommu;
- struct iommu *iommu = &info->iommu;
- struct strbuf *strbuf = &info->strbuf;
- iopte_t *base;
- unsigned long flags, npages, i;
-
- if (unlikely(direction == SBUS_DMA_NONE))
- BUG();
-
- npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
- npages >>= IO_PAGE_SHIFT;
- base = iommu->page_table +
- ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
-
- bus_addr &= IO_PAGE_MASK;
-
- spin_lock_irqsave(&iommu->lock, flags);
- sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction);
- for (i = 0; i < npages; i++)
- iopte_val(base[i]) = 0UL;
- free_npages(iommu, bus_addr - iommu->page_table_map_base, npages);
- spin_unlock_irqrestore(&iommu->lock, flags);
-}
-
-#define SG_ENT_PHYS_ADDRESS(SG) \
- (__pa(page_address((SG)->page)) + (SG)->offset)
-
-static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg,
- int nused, int nelems, unsigned long iopte_protection)
-{
- struct scatterlist *dma_sg = sg;
- struct scatterlist *sg_end = sg + nelems;
- int i;
-
- for (i = 0; i < nused; i++) {
- unsigned long pteval = ~0UL;
- u32 dma_npages;
-
- dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) +
- dma_sg->dma_length +
- ((IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT;
- do {
- unsigned long offset;
- signed int len;
-
- /* If we are here, we know we have at least one
- * more page to map. So walk forward until we
- * hit a page crossing, and begin creating new
- * mappings from that spot.
- */
- for (;;) {
- unsigned long tmp;
-
- tmp = SG_ENT_PHYS_ADDRESS(sg);
- len = sg->length;
- if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) {
- pteval = tmp & IO_PAGE_MASK;
- offset = tmp & (IO_PAGE_SIZE - 1UL);
- break;
- }
- if (((tmp ^ (tmp + len - 1UL)) >> IO_PAGE_SHIFT) != 0UL) {
- pteval = (tmp + IO_PAGE_SIZE) & IO_PAGE_MASK;
- offset = 0UL;
- len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL)));
- break;
- }
- sg++;
- }
-
- pteval = iopte_protection | (pteval & IOPTE_PAGE);
- while (len > 0) {
- *iopte++ = __iopte(pteval);
- pteval += IO_PAGE_SIZE;
- len -= (IO_PAGE_SIZE - offset);
- offset = 0;
- dma_npages--;
- }
-
- pteval = (pteval & IOPTE_PAGE) + len;
- sg++;
-
- /* Skip over any tail mappings we've fully mapped,
- * adjusting pteval along the way. Stop when we
- * detect a page crossing event.
- */
- while (sg < sg_end &&
- (pteval << (64 - IO_PAGE_SHIFT)) != 0UL &&
- (pteval == SG_ENT_PHYS_ADDRESS(sg)) &&
- ((pteval ^
- (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) {
- pteval += sg->length;
- sg++;
- }
- if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL)
- pteval = ~0UL;
- } while (dma_npages != 0);
- dma_sg++;
- }
-}
-
-int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction)
-{
- struct sbus_info *info;
- struct iommu *iommu;
- unsigned long flags, npages, iopte_protection;
- iopte_t *base;
- u32 dma_base;
- struct scatterlist *sgtmp;
- int used;
-
- /* Fast path single entry scatterlists. */
- if (nelems == 1) {
- sglist->dma_address =
- sbus_map_single(sdev,
- (page_address(sglist->page) + sglist->offset),
- sglist->length, direction);
- sglist->dma_length = sglist->length;
- return 1;
- }
-
- info = sdev->bus->iommu;
- iommu = &info->iommu;
-
- if (unlikely(direction == SBUS_DMA_NONE))
- BUG();
-
- npages = prepare_sg(sglist, nelems);
-
- spin_lock_irqsave(&iommu->lock, flags);
- base = alloc_npages(iommu, npages);
- spin_unlock_irqrestore(&iommu->lock, flags);
-
- if (unlikely(base == NULL))
- BUG();
-
- dma_base = iommu->page_table_map_base +
- ((base - iommu->page_table) << IO_PAGE_SHIFT);
-
- /* Normalize DVMA addresses. */
- used = nelems;
-
- sgtmp = sglist;
- while (used && sgtmp->dma_length) {
- sgtmp->dma_address += dma_base;
- sgtmp++;
- used--;
- }
- used = nelems - used;
-
- iopte_protection = IOPTE_VALID | IOPTE_STBUF | IOPTE_CACHE;
- if (direction != SBUS_DMA_TODEVICE)
- iopte_protection |= IOPTE_WRITE;
-
- fill_sg(base, sglist, used, nelems, iopte_protection);
-
-#ifdef VERIFY_SG
- verify_sglist(sglist, nelems, base, npages);
-#endif
-
- return used;
-}
-
-void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction)
-{
- struct sbus_info *info;
- struct iommu *iommu;
- struct strbuf *strbuf;
- iopte_t *base;
- unsigned long flags, i, npages;
- u32 bus_addr;
-
- if (unlikely(direction == SBUS_DMA_NONE))
- BUG();
-
- info = sdev->bus->iommu;
- iommu = &info->iommu;
- strbuf = &info->strbuf;
-
- bus_addr = sglist->dma_address & IO_PAGE_MASK;
-
- for (i = 1; i < nelems; i++)
- if (sglist[i].dma_length == 0)
- break;
- i--;
- npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) -
- bus_addr) >> IO_PAGE_SHIFT;
-
- base = iommu->page_table +
- ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
-
- spin_lock_irqsave(&iommu->lock, flags);
- sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction);
- for (i = 0; i < npages; i++)
- iopte_val(base[i]) = 0UL;
- free_npages(iommu, bus_addr - iommu->page_table_map_base, npages);
- spin_unlock_irqrestore(&iommu->lock, flags);
-}
-
-void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t bus_addr, size_t sz, int direction)
-{
- struct sbus_info *info;
- struct iommu *iommu;
- struct strbuf *strbuf;
- unsigned long flags, npages;
-
- info = sdev->bus->iommu;
- iommu = &info->iommu;
- strbuf = &info->strbuf;
-
- npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
- npages >>= IO_PAGE_SHIFT;
- bus_addr &= IO_PAGE_MASK;
-
- spin_lock_irqsave(&iommu->lock, flags);
- sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction);
- spin_unlock_irqrestore(&iommu->lock, flags);
-}
-
-void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t base, size_t size, int direction)
-{
-}
-
-void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction)
-{
- struct sbus_info *info;
- struct iommu *iommu;
- struct strbuf *strbuf;
- unsigned long flags, npages, i;
- u32 bus_addr;
-
- info = sdev->bus->iommu;
- iommu = &info->iommu;
- strbuf = &info->strbuf;
-
- bus_addr = sglist[0].dma_address & IO_PAGE_MASK;
- for (i = 0; i < nelems; i++) {
- if (!sglist[i].dma_length)
- break;
- }
- i--;
- npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length)
- - bus_addr) >> IO_PAGE_SHIFT;
-
- spin_lock_irqsave(&iommu->lock, flags);
- sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction);
- spin_unlock_irqrestore(&iommu->lock, flags);
-}
-
-void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int direction)
-{
-}
-
/* Enable 64-bit DVMA mode for the given device. */
void sbus_set_sbus64(struct sbus_dev *sdev, int bursts)
{
- struct sbus_info *info = sdev->bus->iommu;
- struct iommu *iommu = &info->iommu;
+ struct iommu *iommu = sdev->ofdev.dev.archdata.iommu;
int slot = sdev->slot;
unsigned long cfg_reg;
u64 val;
@@ -713,8 +194,7 @@ static unsigned long sysio_imap_to_iclr(unsigned long imap)
unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
{
struct sbus_bus *sbus = (struct sbus_bus *)buscookie;
- struct sbus_info *info = sbus->iommu;
- struct iommu *iommu = &info->iommu;
+ struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
unsigned long imap, iclr;
int sbus_level = 0;
@@ -776,8 +256,7 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
{
struct sbus_bus *sbus = dev_id;
- struct sbus_info *info = sbus->iommu;
- struct iommu *iommu = &info->iommu;
+ struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
unsigned long afsr_reg, afar_reg;
unsigned long afsr, afar, error_bits;
@@ -849,8 +328,7 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
{
struct sbus_bus *sbus = dev_id;
- struct sbus_info *info = sbus->iommu;
- struct iommu *iommu = &info->iommu;
+ struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
unsigned long afsr_reg, afar_reg;
unsigned long afsr, afar, error_bits;
@@ -927,8 +405,7 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
{
struct sbus_bus *sbus = dev_id;
- struct sbus_info *info = sbus->iommu;
- struct iommu *iommu = &info->iommu;
+ struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
unsigned long afsr_reg, afar_reg, reg_base;
unsigned long afsr, afar, error_bits;
int reported;
@@ -995,8 +472,7 @@ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
static void __init sysio_register_error_handlers(struct sbus_bus *sbus)
{
- struct sbus_info *info = sbus->iommu;
- struct iommu *iommu = &info->iommu;
+ struct iommu *iommu = sbus->ofdev.dev.archdata.iommu;
unsigned long reg_base = iommu->write_complete_reg - 0x2000UL;
unsigned int irq;
u64 control;
@@ -1041,7 +517,6 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
{
const struct linux_prom64_registers *pr;
struct device_node *dp;
- struct sbus_info *info;
struct iommu *iommu;
struct strbuf *strbuf;
unsigned long regs, reg_base;
@@ -1054,25 +529,28 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
pr = of_get_property(dp, "reg", NULL);
if (!pr) {
- prom_printf("sbus_iommu_init: Cannot map SYSIO control registers.\n");
+ prom_printf("sbus_iommu_init: Cannot map SYSIO "
+ "control registers.\n");
prom_halt();
}
regs = pr->phys_addr;
- info = kzalloc(sizeof(*info), GFP_ATOMIC);
- if (info == NULL) {
- prom_printf("sbus_iommu_init: Fatal error, "
- "kmalloc(info) failed\n");
- prom_halt();
- }
+ iommu = kzalloc(sizeof(*iommu), GFP_ATOMIC);
+ if (!iommu)
+ goto fatal_memory_error;
+ strbuf = kzalloc(sizeof(*strbuf), GFP_ATOMIC);
+ if (!strbuf)
+ goto fatal_memory_error;
- iommu = &info->iommu;
- strbuf = &info->strbuf;
+ sbus->ofdev.dev.archdata.iommu = iommu;
+ sbus->ofdev.dev.archdata.stc = strbuf;
reg_base = regs + SYSIO_IOMMUREG_BASE;
iommu->iommu_control = reg_base + IOMMU_CONTROL;
iommu->iommu_tsbbase = reg_base + IOMMU_TSBBASE;
iommu->iommu_flush = reg_base + IOMMU_FLUSH;
+ iommu->iommu_tags = iommu->iommu_control +
+ (IOMMU_TAGDIAG - IOMMU_CONTROL);
reg_base = regs + SYSIO_STRBUFREG_BASE;
strbuf->strbuf_control = reg_base + STRBUF_CONTROL;
@@ -1093,14 +571,12 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
*/
iommu->write_complete_reg = regs + 0x2000UL;
- /* Link into SYSIO software state. */
- sbus->iommu = info;
-
printk("SYSIO: UPA portID %x, at %016lx\n",
sbus->portid, regs);
/* Setup for TSB_SIZE=7, TBW_SIZE=0, MMU_DE=1, MMU_EN=1 */
- sbus_iommu_table_init(iommu, IO_TSB_SIZE);
+ if (iommu_table_init(iommu, IO_TSB_SIZE, MAP_BASE, 0xffffffff))
+ goto fatal_memory_error;
control = upa_readq(iommu->iommu_control);
control = ((7UL << 16UL) |
@@ -1157,6 +633,10 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus)
starfire_hookup(sbus->portid);
sysio_register_error_handlers(sbus);
+ return;
+
+fatal_memory_error:
+ prom_printf("sbus_iommu_init: Fatal memory allocation error.\n");
}
void sbus_fill_device_irq(struct sbus_dev *sdev)
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index aafde3dd9fd..0f5be828ee9 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -133,33 +133,6 @@ static void __init process_switch(char c)
}
}
-static void __init process_console(char *commands)
-{
- serial_console = 0;
- commands += 8;
- /* Linux-style serial */
- if (!strncmp(commands, "ttyS", 4))
- serial_console = simple_strtoul(commands + 4, NULL, 10) + 1;
- else if (!strncmp(commands, "tty", 3)) {
- char c = *(commands + 3);
- /* Solaris-style serial */
- if (c == 'a' || c == 'b') {
- serial_console = c - 'a' + 1;
- prom_printf ("Using /dev/tty%c as console.\n", c);
- }
- /* else Linux-style fbcon, not serial */
- }
-#if defined(CONFIG_PROM_CONSOLE)
- if (!strncmp(commands, "prom", 4)) {
- char *p;
-
- for (p = commands - 8; *p && *p != ' '; p++)
- *p = ' ';
- conswitchp = &prom_con;
- }
-#endif
-}
-
static void __init boot_flags_init(char *commands)
{
while (*commands) {
@@ -176,9 +149,7 @@ static void __init boot_flags_init(char *commands)
process_switch(*commands++);
continue;
}
- if (!strncmp(commands, "console=", 8)) {
- process_console(commands);
- } else if (!strncmp(commands, "mem=", 4)) {
+ if (!strncmp(commands, "mem=", 4)) {
/*
* "mem=XXX[kKmM]" overrides the PROM-reported
* memory size.
@@ -378,44 +349,6 @@ void __init setup_arch(char **cmdline_p)
paging_init();
}
-static int __init set_preferred_console(void)
-{
- int idev, odev;
-
- /* The user has requested a console so this is already set up. */
- if (serial_console >= 0)
- return -EBUSY;
-
- idev = prom_query_input_device();
- odev = prom_query_output_device();
- if (idev == PROMDEV_IKBD && odev == PROMDEV_OSCREEN) {
- serial_console = 0;
- } else if (idev == PROMDEV_ITTYA && odev == PROMDEV_OTTYA) {
- serial_console = 1;
- } else if (idev == PROMDEV_ITTYB && odev == PROMDEV_OTTYB) {
- serial_console = 2;
- } else if (idev == PROMDEV_IRSC && odev == PROMDEV_ORSC) {
- serial_console = 3;
- } else if (idev == PROMDEV_IVCONS && odev == PROMDEV_OVCONS) {
- /* sunhv_console_init() doesn't check the serial_console
- * value anyways...
- */
- serial_console = 4;
- return add_preferred_console("ttyHV", 0, NULL);
- } else {
- prom_printf("Inconsistent console: "
- "input %d, output %d\n",
- idev, odev);
- prom_halt();
- }
-
- if (serial_console)
- return add_preferred_console("ttyS", serial_console - 1, NULL);
-
- return -ENODEV;
-}
-console_initcall(set_preferred_console);
-
/* BUFFER is PAGE_SIZE bytes long. */
extern char *sparc_cpu_type;
@@ -508,5 +441,4 @@ void sun_do_break(void)
prom_cmdline();
}
-int serial_console = -1;
int stop_a_enabled = 1;
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index b448d33321c..c73b7a48b03 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -334,8 +334,6 @@ static void ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread_reg)
}
#endif
-extern void sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load);
-
extern unsigned long sparc64_cpu_startup;
/* The OBP cpu startup callback truncates the 3rd arg cookie to
@@ -355,13 +353,12 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu)
int timeout, ret;
p = fork_idle(cpu);
+ if (IS_ERR(p))
+ return PTR_ERR(p);
callin_flag = 0;
cpu_new_thread = task_thread_info(p);
if (tlb_type == hypervisor) {
- /* Alloc the mondo queues, cpu will load them. */
- sun4v_init_mondo_queues(0, cpu, 1, 0);
-
#if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU)
if (ldom_domaining_enabled)
ldom_startcpu_cpuid(cpu,
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index 719d676c2dd..23fad7ebdd0 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -168,6 +168,7 @@ EXPORT_SYMBOL(change_bit);
EXPORT_SYMBOL(__flushw_user);
EXPORT_SYMBOL(tlb_type);
+EXPORT_SYMBOL(sun4v_chip_type);
EXPORT_SYMBOL(get_fb_unmapped_area);
EXPORT_SYMBOL(flush_icache_range);
@@ -280,6 +281,7 @@ EXPORT_SYMBOL(sys_getgid);
EXPORT_SYMBOL(svr4_getcontext);
EXPORT_SYMBOL(svr4_setcontext);
EXPORT_SYMBOL(compat_sys_ioctl);
+EXPORT_SYMBOL(sys_ioctl);
EXPORT_SYMBOL(sparc32_open);
#endif
@@ -330,7 +332,6 @@ EXPORT_SYMBOL(VISenter);
/* for input/keybdev */
EXPORT_SYMBOL(sun_do_break);
-EXPORT_SYMBOL(serial_console);
EXPORT_SYMBOL(stop_a_enabled);
#ifdef CONFIG_DEBUG_BUGVERBOSE
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index abd83129b2e..e8dce90d05d 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -1,8 +1,7 @@
-/* $Id: sys_sparc32.c,v 1.184 2002/02/09 19:49:31 davem Exp $
- * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
+/* sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
*
* Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997, 2007 David S. Miller (davem@davemloft.net)
*
* These routines maintain argument size conversion between 32bit and 64bit
* environment.
@@ -1028,3 +1027,10 @@ long compat_sync_file_range(int fd, unsigned long off_high, unsigned long off_lo
(nb_high << 32) | nb_low,
flags);
}
+
+asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo,
+ u32 lenhi, u32 lenlo)
+{
+ return sys_fallocate(fd, mode, ((loff_t)offhi << 32) | offlo,
+ ((loff_t)lenhi << 32) | lenlo);
+}
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index 8765e32155a..06d10907d8c 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -1,8 +1,7 @@
-/* $Id: systbls.S,v 1.81 2002/02/08 03:57:14 davem Exp $
- * systbls.S: System call entry point tables for OS compatibility.
+/* systbls.S: System call entry point tables for OS compatibility.
* The native Linux system call table lives here also.
*
- * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 1996, 2007 David S. Miller (davem@davemloft.net)
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*
* Based upon preliminary work which is:
@@ -81,7 +80,7 @@ sys_call_table32:
.word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare
/*300*/ .word compat_sys_set_robust_list, compat_sys_get_robust_list, compat_sys_migrate_pages, compat_sys_mbind, compat_sys_get_mempolicy
.word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait
-/*310*/ .word compat_sys_utimensat, compat_sys_signalfd, compat_sys_timerfd, sys_eventfd
+/*310*/ .word compat_sys_utimensat, compat_sys_signalfd, compat_sys_timerfd, sys_eventfd, compat_sys_fallocate
#endif /* CONFIG_COMPAT */
@@ -153,7 +152,7 @@ sys_call_table:
.word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare
/*300*/ .word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy
.word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait
-/*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd
+/*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd, sys_eventfd, sys_fallocate
#if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \
defined(CONFIG_SOLARIS_EMUL_MODULE)
@@ -272,6 +271,6 @@ sunos_sys_table:
.word sunos_nosys, sunos_nosys, sunos_nosys
.word sunos_nosys
/*310*/ .word sunos_nosys, sunos_nosys, sunos_nosys
- .word sunos_nosys
+ .word sunos_nosys, sunos_nosys
#endif
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index 62e316ab133..69cad1b653c 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -403,58 +403,9 @@ static struct sparc64_tick_ops hbtick_operations __read_mostly = {
static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
-#define TICK_SIZE (tick_nsec / 1000)
-
-#define USEC_AFTER 500000
-#define USEC_BEFORE 500000
-
-static void sync_cmos_clock(unsigned long dummy);
-
-static DEFINE_TIMER(sync_cmos_timer, sync_cmos_clock, 0, 0);
-
-static void sync_cmos_clock(unsigned long dummy)
+int update_persistent_clock(struct timespec now)
{
- struct timeval now, next;
- int fail = 1;
-
- /*
- * If we have an externally synchronized Linux clock, then update
- * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be
- * called as close as possible to 500 ms before the new second starts.
- * This code is run on a timer. If the clock is set, that timer
- * may not expire at the correct time. Thus, we adjust...
- */
- if (!ntp_synced())
- /*
- * Not synced, exit, do not restart a timer (if one is
- * running, let it run out).
- */
- return;
-
- do_gettimeofday(&now);
- if (now.tv_usec >= USEC_AFTER - ((unsigned) TICK_SIZE) / 2 &&
- now.tv_usec <= USEC_BEFORE + ((unsigned) TICK_SIZE) / 2)
- fail = set_rtc_mmss(now.tv_sec);
-
- next.tv_usec = USEC_AFTER - now.tv_usec;
- if (next.tv_usec <= 0)
- next.tv_usec += USEC_PER_SEC;
-
- if (!fail)
- next.tv_sec = 659;
- else
- next.tv_sec = 0;
-
- if (next.tv_usec >= USEC_PER_SEC) {
- next.tv_sec++;
- next.tv_usec -= USEC_PER_SEC;
- }
- mod_timer(&sync_cmos_timer, jiffies + timeval_to_jiffies(&next));
-}
-
-void notify_arch_cmos_timer(void)
-{
- mod_timer(&sync_cmos_timer, jiffies + 1);
+ return set_rtc_mmss(now.tv_sec);
}
/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
@@ -835,7 +786,7 @@ static int __init clock_init(void)
return 0;
}
- return of_register_driver(&clock_driver, &of_bus_type);
+ return of_register_driver(&clock_driver, &of_platform_bus_type);
}
/* Must be after subsys_initcall() so that busses are probed. Must
@@ -931,6 +882,7 @@ static void sparc64_timer_setup(enum clock_event_mode mode,
{
switch (mode) {
case CLOCK_EVT_MODE_ONESHOT:
+ case CLOCK_EVT_MODE_RESUME:
break;
case CLOCK_EVT_MODE_SHUTDOWN:
@@ -1434,8 +1386,148 @@ static int bq4802_set_rtc_time(struct rtc_time *time)
return 0;
}
+
+static void cmos_get_rtc_time(struct rtc_time *rtc_tm)
+{
+ unsigned char ctrl;
+
+ rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
+ rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
+ rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
+ rtc_tm->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
+ rtc_tm->tm_mon = CMOS_READ(RTC_MONTH);
+ rtc_tm->tm_year = CMOS_READ(RTC_YEAR);
+ rtc_tm->tm_wday = CMOS_READ(RTC_DAY_OF_WEEK);
+
+ ctrl = CMOS_READ(RTC_CONTROL);
+ if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ BCD_TO_BIN(rtc_tm->tm_sec);
+ BCD_TO_BIN(rtc_tm->tm_min);
+ BCD_TO_BIN(rtc_tm->tm_hour);
+ BCD_TO_BIN(rtc_tm->tm_mday);
+ BCD_TO_BIN(rtc_tm->tm_mon);
+ BCD_TO_BIN(rtc_tm->tm_year);
+ BCD_TO_BIN(rtc_tm->tm_wday);
+ }
+
+ if (rtc_tm->tm_year <= 69)
+ rtc_tm->tm_year += 100;
+
+ rtc_tm->tm_mon--;
+}
+
+static int cmos_set_rtc_time(struct rtc_time *rtc_tm)
+{
+ unsigned char mon, day, hrs, min, sec;
+ unsigned char save_control, save_freq_select;
+ unsigned int yrs;
+
+ yrs = rtc_tm->tm_year;
+ mon = rtc_tm->tm_mon + 1;
+ day = rtc_tm->tm_mday;
+ hrs = rtc_tm->tm_hour;
+ min = rtc_tm->tm_min;
+ sec = rtc_tm->tm_sec;
+
+ if (yrs >= 100)
+ yrs -= 100;
+
+ if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ BIN_TO_BCD(sec);
+ BIN_TO_BCD(min);
+ BIN_TO_BCD(hrs);
+ BIN_TO_BCD(day);
+ BIN_TO_BCD(mon);
+ BIN_TO_BCD(yrs);
+ }
+
+ save_control = CMOS_READ(RTC_CONTROL);
+ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+ save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
+ CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+ CMOS_WRITE(yrs, RTC_YEAR);
+ CMOS_WRITE(mon, RTC_MONTH);
+ CMOS_WRITE(day, RTC_DAY_OF_MONTH);
+ CMOS_WRITE(hrs, RTC_HOURS);
+ CMOS_WRITE(min, RTC_MINUTES);
+ CMOS_WRITE(sec, RTC_SECONDS);
+
+ CMOS_WRITE(save_control, RTC_CONTROL);
+ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+
+ return 0;
+}
#endif /* CONFIG_PCI */
+static void mostek_get_rtc_time(struct rtc_time *rtc_tm)
+{
+ void __iomem *regs = mstk48t02_regs;
+ u8 tmp;
+
+ spin_lock_irq(&mostek_lock);
+
+ tmp = mostek_read(regs + MOSTEK_CREG);
+ tmp |= MSTK_CREG_READ;
+ mostek_write(regs + MOSTEK_CREG, tmp);
+
+ rtc_tm->tm_sec = MSTK_REG_SEC(regs);
+ rtc_tm->tm_min = MSTK_REG_MIN(regs);
+ rtc_tm->tm_hour = MSTK_REG_HOUR(regs);
+ rtc_tm->tm_mday = MSTK_REG_DOM(regs);
+ rtc_tm->tm_mon = MSTK_REG_MONTH(regs);
+ rtc_tm->tm_year = MSTK_CVT_YEAR( MSTK_REG_YEAR(regs) );
+ rtc_tm->tm_wday = MSTK_REG_DOW(regs);
+
+ tmp = mostek_read(regs + MOSTEK_CREG);
+ tmp &= ~MSTK_CREG_READ;
+ mostek_write(regs + MOSTEK_CREG, tmp);
+
+ spin_unlock_irq(&mostek_lock);
+
+ rtc_tm->tm_mon--;
+ rtc_tm->tm_wday--;
+ rtc_tm->tm_year -= 1900;
+}
+
+static int mostek_set_rtc_time(struct rtc_time *rtc_tm)
+{
+ unsigned char mon, day, hrs, min, sec, wday;
+ void __iomem *regs = mstk48t02_regs;
+ unsigned int yrs;
+ u8 tmp;
+
+ yrs = rtc_tm->tm_year + 1900;
+ mon = rtc_tm->tm_mon + 1;
+ day = rtc_tm->tm_mday;
+ wday = rtc_tm->tm_wday + 1;
+ hrs = rtc_tm->tm_hour;
+ min = rtc_tm->tm_min;
+ sec = rtc_tm->tm_sec;
+
+ spin_lock_irq(&mostek_lock);
+
+ tmp = mostek_read(regs + MOSTEK_CREG);
+ tmp |= MSTK_CREG_WRITE;
+ mostek_write(regs + MOSTEK_CREG, tmp);
+
+ MSTK_SET_REG_SEC(regs, sec);
+ MSTK_SET_REG_MIN(regs, min);
+ MSTK_SET_REG_HOUR(regs, hrs);
+ MSTK_SET_REG_DOW(regs, wday);
+ MSTK_SET_REG_DOM(regs, day);
+ MSTK_SET_REG_MONTH(regs, mon);
+ MSTK_SET_REG_YEAR(regs, yrs - MSTK_YEAR_ZERO);
+
+ tmp = mostek_read(regs + MOSTEK_CREG);
+ tmp &= ~MSTK_CREG_WRITE;
+ mostek_write(regs + MOSTEK_CREG, tmp);
+
+ spin_unlock_irq(&mostek_lock);
+
+ return 0;
+}
+
struct mini_rtc_ops {
void (*get_rtc_time)(struct rtc_time *);
int (*set_rtc_time)(struct rtc_time *);
@@ -1456,8 +1548,18 @@ static struct mini_rtc_ops bq4802_rtc_ops = {
.get_rtc_time = bq4802_get_rtc_time,
.set_rtc_time = bq4802_set_rtc_time,
};
+
+static struct mini_rtc_ops cmos_rtc_ops = {
+ .get_rtc_time = cmos_get_rtc_time,
+ .set_rtc_time = cmos_set_rtc_time,
+};
#endif /* CONFIG_PCI */
+static struct mini_rtc_ops mostek_rtc_ops = {
+ .get_rtc_time = mostek_get_rtc_time,
+ .set_rtc_time = mostek_set_rtc_time,
+};
+
static struct mini_rtc_ops *mini_rtc_ops;
static inline void mini_get_rtc_time(struct rtc_time *time)
@@ -1583,7 +1685,11 @@ static int __init rtc_mini_init(void)
#ifdef CONFIG_PCI
else if (bq4802_regs)
mini_rtc_ops = &bq4802_rtc_ops;
+ else if (ds1287_regs)
+ mini_rtc_ops = &cmos_rtc_ops;
#endif /* CONFIG_PCI */
+ else if (mstk48t02_regs)
+ mini_rtc_ops = &mostek_rtc_ops;
else
return -ENODEV;
diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S
index a4dc01a3d23..04e81dda13d 100644
--- a/arch/sparc64/kernel/trampoline.S
+++ b/arch/sparc64/kernel/trampoline.S
@@ -95,14 +95,13 @@ spitfire_startup:
membar #Sync
startup_continue:
+ mov %o0, %l0
+ BRANCH_IF_SUN4V(g1, niagara_lock_tlb)
+
sethi %hi(0x80000000), %g2
sllx %g2, 32, %g2
wr %g2, 0, %tick_cmpr
- mov %o0, %l0
-
- BRANCH_IF_SUN4V(g1, niagara_lock_tlb)
-
/* Call OBP by hand to lock KERNBASE into i/d tlbs.
* We lock 2 consequetive entries if we are 'bigkernel'.
*/
@@ -346,7 +345,7 @@ after_lock_tlb:
sethi %hi(tramp_stack), %g1
or %g1, %lo(tramp_stack), %g1
add %g1, TRAMP_STACK_SIZE, %g1
- sub %g1, STACKFRAME_SZ + STACK_BIAS, %sp
+ sub %g1, STACKFRAME_SZ + STACK_BIAS + 256, %sp
mov 0, %fp
/* Put garbage in these registers to trap any access to them. */
@@ -366,11 +365,8 @@ after_lock_tlb:
call hard_smp_processor_id
nop
- mov %o0, %o1
- mov 0, %o0
- mov 0, %o2
- call sun4v_init_mondo_queues
- mov 1, %o3
+ call sun4v_register_mondo_queues
+ nop
1: call init_cur_cpu_trap
ldx [%l0], %o0
@@ -415,15 +411,38 @@ after_lock_tlb:
sethi %hi(kern_base), %g3
ldx [%g3 + %lo(kern_base)], %g3
add %g2, %g3, %o1
+ sethi %hi(sparc64_ttable_tl0), %o0
- call prom_set_trap_table_sun4v
- sethi %hi(sparc64_ttable_tl0), %o0
+ set prom_set_trap_table_name, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x00]
+ mov 2, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x08]
+ mov 0, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x10]
+ stx %o0, [%sp + 2047 + 128 + 0x18]
+ stx %o1, [%sp + 2047 + 128 + 0x20]
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x08], %o1
+ call %o1
+ add %sp, (2047 + 128), %o0
ba,pt %xcc, 2f
nop
-1: call prom_set_trap_table
- sethi %hi(sparc64_ttable_tl0), %o0
+1: sethi %hi(sparc64_ttable_tl0), %o0
+ set prom_set_trap_table_name, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x00]
+ mov 1, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x08]
+ mov 0, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x10]
+ stx %o0, [%sp + 2047 + 128 + 0x18]
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x08], %o1
+ call %o1
+ add %sp, (2047 + 128), %o0
2: ldx [%l0], %g6
ldx [%g6 + TI_TASK], %g4
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 6ef2d299fb1..6ef42b8e53d 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -2134,12 +2134,20 @@ static void user_instruction_dump (unsigned int __user *pc)
void show_stack(struct task_struct *tsk, unsigned long *_ksp)
{
unsigned long pc, fp, thread_base, ksp;
- void *tp = task_stack_page(tsk);
+ struct thread_info *tp;
struct reg_window *rw;
int count = 0;
ksp = (unsigned long) _ksp;
-
+ if (!tsk)
+ tsk = current;
+ tp = task_thread_info(tsk);
+ if (ksp == 0UL) {
+ if (tsk == current)
+ asm("mov %%fp, %0" : "=r" (ksp));
+ else
+ ksp = tp->ksp;
+ }
if (tp == current_thread_info())
flushw_all();
@@ -2168,11 +2176,7 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp)
void dump_stack(void)
{
- unsigned long *ksp;
-
- __asm__ __volatile__("mov %%fp, %0"
- : "=r" (ksp));
- show_stack(current, ksp);
+ show_stack(current, NULL);
}
EXPORT_SYMBOL(dump_stack);
diff --git a/arch/sparc64/kernel/us2e_cpufreq.c b/arch/sparc64/kernel/us2e_cpufreq.c
index 1f83fe6a82d..791c15138f3 100644
--- a/arch/sparc64/kernel/us2e_cpufreq.c
+++ b/arch/sparc64/kernel/us2e_cpufreq.c
@@ -326,7 +326,6 @@ static int __init us2e_freq_cpu_init(struct cpufreq_policy *policy)
table[2].index = 5;
table[3].frequency = CPUFREQ_TABLE_END;
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = 0;
policy->cur = clock_tick;
diff --git a/arch/sparc64/kernel/vio.c b/arch/sparc64/kernel/vio.c
index 49569b44ea1..0c1ee619d81 100644
--- a/arch/sparc64/kernel/vio.c
+++ b/arch/sparc64/kernel/vio.c
@@ -16,21 +16,6 @@
#include <asm/mdesc.h>
#include <asm/vio.h>
-static inline int find_in_proplist(const char *list, const char *match,
- int len)
-{
- while (len > 0) {
- int l;
-
- if (!strcmp(list, match))
- return 1;
- l = strlen(list) + 1;
- list += l;
- len -= l;
- }
- return 0;
-}
-
static const struct vio_device_id *vio_match_device(
const struct vio_device_id *matches,
const struct vio_dev *dev)
@@ -49,7 +34,7 @@ static const struct vio_device_id *vio_match_device(
if (matches->compat[0]) {
match &= len &&
- find_in_proplist(compat, matches->compat, len);
+ of_find_in_proplist(compat, matches->compat, len);
}
if (match)
return matches;
@@ -103,9 +88,9 @@ static ssize_t devspec_show(struct device *dev,
struct vio_dev *vdev = to_vio_dev(dev);
const char *str = "none";
- if (!strcmp(vdev->type, "network"))
+ if (!strcmp(vdev->type, "vnet-port"))
str = "vnet";
- else if (!strcmp(vdev->type, "block"))
+ else if (!strcmp(vdev->type, "vdc-port"))
str = "vdisk";
return sprintf(buf, "%s\n", str);
@@ -201,10 +186,12 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
struct device *parent)
{
- const char *type, *compat;
+ const char *type, *compat, *bus_id_name;
struct device_node *dp;
struct vio_dev *vdev;
int err, tlen, clen;
+ const u64 *id, *cfg_handle;
+ u64 a;
type = mdesc_get_property(hp, mp, "device-type", &tlen);
if (!type) {
@@ -220,6 +207,29 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
return NULL;
}
+ id = mdesc_get_property(hp, mp, "id", NULL);
+
+ cfg_handle = NULL;
+ mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) {
+ u64 target;
+
+ target = mdesc_arc_target(hp, a);
+ cfg_handle = mdesc_get_property(hp, target,
+ "cfg-handle", NULL);
+ if (cfg_handle)
+ break;
+ }
+
+ bus_id_name = type;
+ if (!strcmp(type, "domain-services-port"))
+ bus_id_name = "ds";
+
+ if (strlen(bus_id_name) >= KOBJ_NAME_LEN - 4) {
+ printk(KERN_ERR "VIO: bus_id_name [%s] is too long.\n",
+ bus_id_name);
+ return NULL;
+ }
+
compat = mdesc_get_property(hp, mp, "device-type", &clen);
if (!compat) {
clen = 0;
@@ -249,7 +259,20 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
vio_fill_channel_info(hp, mp, vdev);
- snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%lx", mp);
+ if (!id) {
+ snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s",
+ bus_id_name);
+ vdev->dev_no = ~(u64)0;
+ } else if (!cfg_handle) {
+ snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu",
+ bus_id_name, *id);
+ vdev->dev_no = *id;
+ } else {
+ snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu-%lu",
+ bus_id_name, *cfg_handle, *id);
+ vdev->dev_no = *cfg_handle;
+ }
+
vdev->dev.parent = parent;
vdev->dev.bus = &vio_bus_type;
vdev->dev.release = vio_dev_release;
@@ -269,6 +292,8 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
}
vdev->dp = dp;
+ printk(KERN_INFO "VIO: Adding device %s\n", vdev->dev.bus_id);
+
err = device_register(&vdev->dev);
if (err) {
printk(KERN_ERR "VIO: Could not register device %s, err=%d\n",
@@ -283,46 +308,71 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
return vdev;
}
-static void walk_tree(struct mdesc_handle *hp, u64 n, struct vio_dev *parent)
+static void vio_add(struct mdesc_handle *hp, u64 node)
{
- u64 a;
+ (void) vio_create_one(hp, node, &root_vdev->dev);
+}
- mdesc_for_each_arc(a, hp, n, MDESC_ARC_TYPE_FWD) {
- struct vio_dev *vdev;
- u64 target;
+static int vio_md_node_match(struct device *dev, void *arg)
+{
+ struct vio_dev *vdev = to_vio_dev(dev);
- target = mdesc_arc_target(hp, a);
- vdev = vio_create_one(hp, target, &parent->dev);
- if (vdev)
- walk_tree(hp, target, vdev);
- }
+ if (vdev->mp == (u64) arg)
+ return 1;
+
+ return 0;
}
-static void create_devices(struct mdesc_handle *hp, u64 root)
+static void vio_remove(struct mdesc_handle *hp, u64 node)
{
- u64 mp;
+ struct device *dev;
- root_vdev = vio_create_one(hp, root, NULL);
- if (!root_vdev) {
- printk(KERN_ERR "VIO: Coult not create root device.\n");
- return;
+ dev = device_find_child(&root_vdev->dev, (void *) node,
+ vio_md_node_match);
+ if (dev) {
+ printk(KERN_INFO "VIO: Removing device %s\n", dev->bus_id);
+
+ device_unregister(dev);
}
+}
+
+static struct mdesc_notifier_client vio_device_notifier = {
+ .add = vio_add,
+ .remove = vio_remove,
+ .node_name = "virtual-device-port",
+};
- walk_tree(hp, root, root_vdev);
+/* We are only interested in domain service ports under the
+ * "domain-services" node. On control nodes there is another port
+ * under "openboot" that we should not mess with as aparently that is
+ * reserved exclusively for OBP use.
+ */
+static void vio_add_ds(struct mdesc_handle *hp, u64 node)
+{
+ int found;
+ u64 a;
- /* Domain services is odd as it doesn't sit underneath the
- * channel-devices node, so we plug it in manually.
- */
- mp = mdesc_node_by_name(hp, MDESC_NODE_NULL, "domain-services");
- if (mp != MDESC_NODE_NULL) {
- struct vio_dev *parent = vio_create_one(hp, mp,
- &root_vdev->dev);
+ found = 0;
+ mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) {
+ u64 target = mdesc_arc_target(hp, a);
+ const char *name = mdesc_node_name(hp, target);
- if (parent)
- walk_tree(hp, mp, parent);
+ if (!strcmp(name, "domain-services")) {
+ found = 1;
+ break;
+ }
}
+
+ if (found)
+ (void) vio_create_one(hp, node, &root_vdev->dev);
}
+static struct mdesc_notifier_client vio_ds_notifier = {
+ .add = vio_add_ds,
+ .remove = vio_remove,
+ .node_name = "domain-services-port",
+};
+
const char *channel_devices_node = "channel-devices";
const char *channel_devices_compat = "SUNW,sun4v-channel-devices";
const char *cfg_handle_prop = "cfg-handle";
@@ -366,7 +416,7 @@ static int __init vio_init(void)
"property\n");
goto out_release;
}
- if (!find_in_proplist(compat, channel_devices_compat, len)) {
+ if (!of_find_in_proplist(compat, channel_devices_compat, len)) {
printk(KERN_ERR "VIO: Channel devices node lacks (%s) "
"compat entry.\n", channel_devices_compat);
goto out_release;
@@ -381,11 +431,19 @@ static int __init vio_init(void)
cdev_cfg_handle = *cfg_handle;
- create_devices(hp, root);
+ root_vdev = vio_create_one(hp, root, NULL);
+ err = -ENODEV;
+ if (!root_vdev) {
+ printk(KERN_ERR "VIO: Coult not create root device.\n");
+ goto out_release;
+ }
+
+ mdesc_register_notifier(&vio_device_notifier);
+ mdesc_register_notifier(&vio_ds_notifier);
mdesc_release(hp);
- return 0;
+ return err;
out_release:
mdesc_release(hp);
diff --git a/arch/sparc64/kernel/viohs.c b/arch/sparc64/kernel/viohs.c
index 15613add45d..708fa1705fb 100644
--- a/arch/sparc64/kernel/viohs.c
+++ b/arch/sparc64/kernel/viohs.c
@@ -78,6 +78,24 @@ static int start_handshake(struct vio_driver_state *vio)
return 0;
}
+static void flush_rx_dring(struct vio_driver_state *vio)
+{
+ struct vio_dring_state *dr;
+ u64 ident;
+
+ BUG_ON(!(vio->dr_state & VIO_DR_STATE_RXREG));
+
+ dr = &vio->drings[VIO_DRIVER_RX_RING];
+ ident = dr->ident;
+
+ BUG_ON(!vio->desc_buf);
+ kfree(vio->desc_buf);
+ vio->desc_buf = NULL;
+
+ memset(dr, 0, sizeof(*dr));
+ dr->ident = ident;
+}
+
void vio_link_state_change(struct vio_driver_state *vio, int event)
{
if (event == LDC_EVENT_UP) {
@@ -98,6 +116,16 @@ void vio_link_state_change(struct vio_driver_state *vio, int event)
break;
}
start_handshake(vio);
+ } else if (event == LDC_EVENT_RESET) {
+ vio->hs_state = VIO_HS_INVALID;
+
+ if (vio->dr_state & VIO_DR_STATE_RXREG)
+ flush_rx_dring(vio);
+
+ vio->dr_state = 0x00;
+ memset(&vio->ver, 0, sizeof(vio->ver));
+
+ ldc_disconnect(vio->lp);
}
}
EXPORT_SYMBOL(vio_link_state_change);
@@ -396,6 +424,8 @@ static int process_dreg_info(struct vio_driver_state *vio,
if (vio->dr_state & VIO_DR_STATE_RXREG)
goto send_nack;
+ BUG_ON(vio->desc_buf);
+
vio->desc_buf = kzalloc(pkt->descr_size, GFP_ATOMIC);
if (!vio->desc_buf)
goto send_nack;
@@ -672,7 +702,7 @@ u32 vio_send_sid(struct vio_driver_state *vio)
}
EXPORT_SYMBOL(vio_send_sid);
-extern int vio_ldc_alloc(struct vio_driver_state *vio,
+int vio_ldc_alloc(struct vio_driver_state *vio,
struct ldc_channel_config *base_cfg,
void *event_arg)
{
diff --git a/arch/sparc64/kernel/vmlinux.lds.S b/arch/sparc64/kernel/vmlinux.lds.S
index 3ad10f3027e..b982fa3dd74 100644
--- a/arch/sparc64/kernel/vmlinux.lds.S
+++ b/arch/sparc64/kernel/vmlinux.lds.S
@@ -45,6 +45,8 @@ SECTIONS
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
+ NOTES
+
. = ALIGN(PAGE_SIZE);
__init_begin = .;
.init.text : {
@@ -90,10 +92,8 @@ SECTIONS
__initramfs_end = .;
#endif
- . = ALIGN(PAGE_SIZE);
- __per_cpu_start = .;
- .data.percpu : { *(.data.percpu) }
- __per_cpu_end = .;
+ PERCPU(PAGE_SIZE)
+
. = ALIGN(PAGE_SIZE);
__init_end = .;
__bss_start = .;