提交 c2e68052 编写于 作者: L Linus Torvalds

Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6

* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6:
  [SPARC64]: fix section mismatch warning in mdesc.c
  [SPARC64]: fix section mismatch warning in pci_sunv4
  [SPARC64]: Stop using drivers/char/rtc.c
  [SPARC64]: Convert parport to of_platform_driver.
  [SPARC]: Implement fb_is_primary_device().
  [SPARC64]: Fix virq decomposition.
  [SPARC64]: Use KERN_ERR in IRQ manipulation error printks.
  [SPARC64]: Do not flood log with failed DS messages.
  [SPARC64]: Add proper multicast support to VNET driver.
  [SPARC64]: Handle multiple domain-services-port nodes properly.
  [SPARC64]: Improve VIO device naming further.
  [SPARC]: Make sure dev_archdata is filled in for all devices.
  [SPARC]: Define minimal struct dev_archdata, similarly to sparc64.
  [SPARC]: Fix serial console device detection.
......@@ -148,6 +148,7 @@ void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *d
{
const struct linux_prom_registers *regs;
struct linux_ebus_child *child;
struct dev_archdata *sd;
const int *irqs;
int i, n, len;
unsigned long baseaddr;
......@@ -234,6 +235,10 @@ void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_device *d
}
}
sd = &dev->ofdev.dev.archdata;
sd->prom_node = dp;
sd->op = &dev->ofdev;
dev->ofdev.node = dp;
dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
dev->ofdev.dev.bus = &ebus_bus_type;
......
......@@ -420,11 +420,16 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
{
struct of_device *op = kzalloc(sizeof(*op), GFP_KERNEL);
const struct linux_prom_irqs *intr;
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",
......
......@@ -39,6 +39,7 @@
#include <asm/processor.h>
#include <asm/psr.h>
#include <asm/elf.h>
#include <asm/prom.h>
#include <asm/unistd.h>
/*
......@@ -150,7 +151,7 @@ void machine_halt(void)
local_irq_enable();
mdelay(8);
local_irq_disable();
if (!serial_console && prom_palette)
if (prom_palette)
prom_palette (1);
prom_halt();
panic("Halt failed!");
......@@ -166,7 +167,7 @@ void machine_restart(char * cmd)
p = strchr (reboot_command, '\n');
if (p) *p = 0;
if (!serial_console && prom_palette)
if (prom_palette)
prom_palette (1);
if (cmd)
prom_reboot(cmd);
......@@ -179,7 +180,8 @@ void machine_restart(char * cmd)
void machine_power_off(void)
{
#ifdef CONFIG_SUN_AUXIO
if (auxio_power_register && (!serial_console || scons_pwroff))
if (auxio_power_register &&
(strcmp(of_console_device->type, "serial") || scons_pwroff))
*auxio_power_register |= AUXIO_POWER_OFF;
#endif
machine_halt();
......
......@@ -397,6 +397,135 @@ static struct device_node * __init build_tree(struct device_node *parent, phandl
return dp;
}
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);
extern void restore_current(void);
static void __init of_console_init(void)
{
char *msg = "OF stdout device is: %s\n";
struct device_node *dp;
unsigned long flags;
const char *type;
phandle node;
int skip, fd;
of_console_path = prom_early_alloc(256);
switch (prom_vers) {
case PROM_V0:
case PROM_SUN4:
skip = 0;
switch (*romvec->pv_stdout) {
case PROMDEV_SCREEN:
type = "display";
break;
case PROMDEV_TTYB:
skip = 1;
/* FALLTHRU */
case PROMDEV_TTYA:
type = "serial";
break;
default:
prom_printf("Invalid PROM_V0 stdout value %u\n",
*romvec->pv_stdout);
prom_halt();
}
for_each_node_by_type(dp, type) {
if (!skip--)
break;
}
if (!dp) {
prom_printf("Cannot find PROM_V0 console node.\n");
prom_halt();
}
of_console_device = dp;
strcpy(of_console_path, dp->full_name);
if (!strcmp(type, "serial")) {
strcat(of_console_path,
(skip ? ":b" : ":a"));
}
break;
default:
case PROM_V2:
case PROM_V3:
fd = *romvec->pv_v2bootargs.fd_stdout;
spin_lock_irqsave(&prom_lock, flags);
node = (*romvec->pv_v2devops.v2_inst2pkg)(fd);
restore_current();
spin_unlock_irqrestore(&prom_lock, flags);
if (!node) {
prom_printf("Cannot resolve stdout node from "
"instance %08x.\n", fd);
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;
if (prom_vers == PROM_V2) {
strcpy(of_console_path, dp->full_name);
switch (*romvec->pv_stdout) {
case PROMDEV_TTYA:
strcat(of_console_path, ":a");
break;
case PROMDEV_TTYB:
strcat(of_console_path, ":b");
break;
}
} else {
const char *path;
dp = of_find_node_by_path("/");
path = of_get_property(dp, "stdout-path", NULL);
if (!path) {
prom_printf("No stdout-path in root node.\n");
prom_halt();
}
strcpy(of_console_path, path);
}
break;
}
of_console_options = strrchr(of_console_path, ':');
if (of_console_options) {
of_console_options++;
if (*of_console_options == '\0')
of_console_options = NULL;
}
prom_printf(msg, of_console_path);
printk(msg, of_console_path);
}
void __init prom_build_devicetree(void)
{
struct device_node **nextp;
......@@ -409,6 +538,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);
}
......@@ -146,31 +146,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;
/* 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) {
......@@ -187,9 +162,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.
......@@ -341,41 +314,6 @@ void __init setup_arch(char **cmdline_p)
smp_setup_cpu_possible_map();
}
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_I_UNK && odev == PROMDEV_OTTYA) {
prom_printf("MrCoffee ttya\n");
serial_console = 1;
} else if (idev == PROMDEV_I_UNK && odev == PROMDEV_OSCREEN) {
serial_console = 0;
prom_printf("MrCoffee keyboard\n");
} else {
prom_printf("Confusing console (idev %d, odev %d)\n",
idev, odev);
serial_console = 1;
}
if (serial_console)
return add_preferred_console("ttyS", serial_console - 1, NULL);
return -ENODEV;
}
console_initcall(set_preferred_console);
extern char *sparc_cpu_type;
extern char *sparc_fpu_type;
......@@ -461,7 +399,6 @@ void sun_do_break(void)
prom_cmdline();
}
int serial_console = -1;
int stop_a_enabled = 1;
static int __init topology_init(void)
......
......@@ -102,119 +102,3 @@ prom_putchar(char c)
while(prom_nbputchar(c) == -1) ;
return;
}
/* Query for input device type */
enum prom_input_device
prom_query_input_device(void)
{
unsigned long flags;
int st_p;
char propb[64];
char *p;
int propl;
switch(prom_vers) {
case PROM_V0:
case PROM_V2:
case PROM_SUN4:
default:
switch(*romvec->pv_stdin) {
case PROMDEV_KBD: return PROMDEV_IKBD;
case PROMDEV_TTYA: return PROMDEV_ITTYA;
case PROMDEV_TTYB: return PROMDEV_ITTYB;
default:
return PROMDEV_I_UNK;
};
case PROM_V3:
spin_lock_irqsave(&prom_lock, flags);
st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin);
restore_current();
spin_unlock_irqrestore(&prom_lock, flags);
if(prom_node_has_property(st_p, "keyboard"))
return PROMDEV_IKBD;
if (prom_getproperty(st_p, "name", propb, sizeof(propb)) != -1) {
if(strncmp(propb, "keyboard", sizeof("serial")) == 0)
return PROMDEV_IKBD;
}
if (prom_getproperty(st_p, "device_type", propb, sizeof(propb)) != -1) {
if(strncmp(propb, "serial", sizeof("serial")))
return PROMDEV_I_UNK;
}
propl = prom_getproperty(prom_root_node, "stdin-path", propb, sizeof(propb));
if(propl > 2) {
p = propb;
while(*p) p++; p -= 2;
if(p[0] == ':') {
if(p[1] == 'a')
return PROMDEV_ITTYA;
else if(p[1] == 'b')
return PROMDEV_ITTYB;
}
}
return PROMDEV_I_UNK;
}
}
/* Query for output device type */
enum prom_output_device
prom_query_output_device(void)
{
unsigned long flags;
int st_p;
char propb[64];
char *p;
int propl;
switch(prom_vers) {
case PROM_V0:
case PROM_SUN4:
switch(*romvec->pv_stdin) {
case PROMDEV_SCREEN: return PROMDEV_OSCREEN;
case PROMDEV_TTYA: return PROMDEV_OTTYA;
case PROMDEV_TTYB: return PROMDEV_OTTYB;
};
break;
case PROM_V2:
case PROM_V3:
spin_lock_irqsave(&prom_lock, flags);
st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout);
restore_current();
spin_unlock_irqrestore(&prom_lock, flags);
propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
if (propl == sizeof("display") &&
strncmp("display", propb, sizeof("display")) == 0)
{
return PROMDEV_OSCREEN;
}
if(prom_vers == PROM_V3) {
if(propl >= 0 &&
strncmp("serial", propb, sizeof("serial")) != 0)
return PROMDEV_O_UNK;
propl = prom_getproperty(prom_root_node, "stdout-path",
propb, sizeof(propb));
if(propl == CON_SIZE_JMC &&
strncmp(propb, con_name_jmc, CON_SIZE_JMC) == 0)
return PROMDEV_OTTYA;
if(propl > 2) {
p = propb;
while(*p) p++; p-= 2;
if(p[0]==':') {
if(p[1] == 'a')
return PROMDEV_OTTYA;
else if(p[1] == 'b')
return PROMDEV_OTTYB;
}
}
} else {
switch(*romvec->pv_stdin) {
case PROMDEV_TTYA: return PROMDEV_OTTYA;
case PROMDEV_TTYB: return PROMDEV_OTTYB;
};
}
break;
default:
;
};
return PROMDEV_O_UNK;
}
......@@ -58,7 +58,7 @@ prom_cmdline(void)
extern void install_linux_ticker(void);
unsigned long flags;
if(!serial_console && prom_palette)
if (prom_palette)
prom_palette (1);
spin_lock_irqsave(&prom_lock, flags);
install_obp_ticker();
......@@ -69,7 +69,7 @@ prom_cmdline(void)
#ifdef CONFIG_SUN_AUXIO
set_auxio(AUXIO_LED, 0);
#endif
if(!serial_console && prom_palette)
if (prom_palette)
prom_palette (0);
}
......
......@@ -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,13 +326,13 @@ 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;
......@@ -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;
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;
cp = find_cap_by_string("var-config");
if (cp->state != CAP_STATE_REGISTERED)
cp = find_cap_by_string("var-config-backup");
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);
......@@ -1019,8 +1058,8 @@ static void ds_reset(struct ds_info *dp)
dp->hs_state = 0;
for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
struct ds_cap_state *cp = &ds_states[i];
for (i = 0; i < dp->num_ds_states; i++) {
struct ds_cap_state *cp = &dp->ds_states[i];
cp->state = CAP_STATE_UNKNOWN;
}
......@@ -1048,7 +1087,8 @@ static void ds_event(void *arg, int event)
}
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;
}
......@@ -1099,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);
......@@ -1111,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;
......@@ -1131,13 +1191,19 @@ static int __devinit ds_probe(struct vio_dev *vdev,
if (err)
goto out_free_ldc;
ds_info = dp;
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);
......@@ -1172,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);
......
......@@ -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;
......@@ -387,6 +388,10 @@ 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;
dev->ofdev.node = dp;
dev->ofdev.dev.parent = &dev->bus->ofdev.dev;
dev->ofdev.dev.bus = &ebus_bus_type;
......
......@@ -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;
}
/*
......@@ -336,15 +340,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 +366,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 +381,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 +414,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 +422,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 +429,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 +455,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 +462,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 +476,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 +496,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 +505,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,6 +700,7 @@ 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 & devino);
......@@ -713,7 +714,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
......
......@@ -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,10 @@ 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;
isa_dev->ofdev.node = dp;
isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev;
isa_dev->ofdev.dev.bus = &isa_bus_type;
......
......@@ -83,7 +83,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 +123,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,
};
......@@ -860,7 +860,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();
......
......@@ -752,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",
......
......@@ -1129,7 +1129,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 +1163,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;
......
......@@ -46,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
......
......@@ -119,7 +119,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 +130,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 +145,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();
......
......@@ -1646,6 +1646,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;
......@@ -1658,6 +1712,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);
......
......@@ -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;
......@@ -330,7 +330,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
......
......@@ -1434,6 +1434,78 @@ 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 */
struct mini_rtc_ops {
......@@ -1456,6 +1528,11 @@ 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 *mini_rtc_ops;
......@@ -1583,6 +1660,8 @@ 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
return -ENODEV;
......
......@@ -205,7 +205,8 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
struct device_node *dp;
struct vio_dev *vdev;
int err, tlen, clen;
const u64 *id;
const u64 *id, *cfg_handle;
u64 a;
type = mdesc_get_property(hp, mp, "device-type", &tlen);
if (!type) {
......@@ -221,26 +222,18 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
return NULL;
}
if (!strcmp(type, "vdc-port")) {
u64 a;
id = mdesc_get_property(hp, mp, "id", NULL);
id = NULL;
mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) {
u64 target;
cfg_handle = NULL;
mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_BACK) {
u64 target;
target = mdesc_arc_target(hp, a);
id = mdesc_get_property(hp, target,
target = mdesc_arc_target(hp, a);
cfg_handle = mdesc_get_property(hp, target,
"cfg-handle", NULL);
if (id)
break;
}
if (!id) {
printk(KERN_ERR "VIO: vdc-port lacks parent "
"cfg-handle.\n");
return NULL;
}
} else
id = mdesc_get_property(hp, mp, "id", NULL);
if (cfg_handle)
break;
}
bus_id_name = type;
if (!strcmp(type, "domain-services-port"))
......@@ -285,10 +278,14 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s",
bus_id_name);
vdev->dev_no = ~(u64)0;
} else {
} 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;
......
......@@ -73,88 +73,3 @@ prom_puts(const char *s, int len)
P1275_INOUT(3,1),
prom_stdout, s, P1275_SIZE(len));
}
/* Query for input device type */
enum prom_input_device
prom_query_input_device(void)
{
int st_p;
char propb[64];
st_p = prom_inst2pkg(prom_stdin);
if(prom_node_has_property(st_p, "keyboard"))
return PROMDEV_IKBD;
prom_getproperty(st_p, "device_type", propb, sizeof(propb));
if(strncmp(propb, "serial", 6))
return PROMDEV_I_UNK;
/* FIXME: Is there any better way how to find out? */
memset(propb, 0, sizeof(propb));
st_p = prom_finddevice ("/options");
prom_getproperty(st_p, "input-device", propb, sizeof(propb));
/*
* If we get here with propb == 'keyboard', we are on ttya, as
* the PROM defaulted to this due to 'no input device'.
*/
if (!strncmp(propb, "keyboard", 8))
return PROMDEV_ITTYA;
if (!strncmp (propb, "rsc", 3))
return PROMDEV_IRSC;
if (!strncmp (propb, "virtual-console", 3))
return PROMDEV_IVCONS;
if (strncmp (propb, "tty", 3) || !propb[3])
return PROMDEV_I_UNK;
switch (propb[3]) {
case 'a': return PROMDEV_ITTYA;
case 'b': return PROMDEV_ITTYB;
default: return PROMDEV_I_UNK;
}
}
/* Query for output device type */
enum prom_output_device
prom_query_output_device(void)
{
int st_p;
char propb[64];
int propl;
st_p = prom_inst2pkg(prom_stdout);
propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
if (propl >= 0 && propl == sizeof("display") &&
strncmp("display", propb, sizeof("display")) == 0)
return PROMDEV_OSCREEN;
if(strncmp("serial", propb, 6))
return PROMDEV_O_UNK;
/* FIXME: Is there any better way how to find out? */
memset(propb, 0, sizeof(propb));
st_p = prom_finddevice ("/options");
prom_getproperty(st_p, "output-device", propb, sizeof(propb));
/*
* If we get here with propb == 'screen', we are on ttya, as
* the PROM defaulted to this due to 'no input device'.
*/
if (!strncmp(propb, "screen", 6))
return PROMDEV_OTTYA;
if (!strncmp (propb, "rsc", 3))
return PROMDEV_ORSC;
if (!strncmp (propb, "virtual-console", 3))
return PROMDEV_OVCONS;
if (strncmp (propb, "tty", 3) || !propb[3])
return PROMDEV_O_UNK;
switch (propb[3]) {
case 'a': return PROMDEV_OTTYA;
case 'b': return PROMDEV_OTTYB;
default: return PROMDEV_O_UNK;
}
}
......@@ -72,7 +72,7 @@ void prom_cmdline(void)
local_irq_save(flags);
if (!serial_console && prom_palette)
if (prom_palette)
prom_palette(1);
#ifdef CONFIG_SMP
......@@ -85,7 +85,7 @@ void prom_cmdline(void)
smp_release();
#endif
if (!serial_console && prom_palette)
if (prom_palette)
prom_palette(0);
local_irq_restore(flags);
......
......@@ -304,3 +304,11 @@ prom_pathtoinode(const char *path)
if (node == -1) return 0;
return node;
}
int prom_ihandle2path(int handle, char *buffer, int bufsize)
{
return p1275_cmd("instance-to-path",
P1275_ARG(1,P1275_ARG_OUT_BUF)|
P1275_INOUT(3, 1),
handle, buffer, P1275_SIZE(bufsize));
}
......@@ -726,7 +726,7 @@ config NVRAM
config RTC
tristate "Enhanced Real Time Clock Support"
depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH && !S390
depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC64 && (!SPARC32 || PCI) && !FRV && !ARM && !SUPERH && !S390
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
......
......@@ -86,12 +86,9 @@
#include <asm/hpet.h>
#endif
#ifdef __sparc__
#ifdef CONFIG_SPARC32
#include <linux/pci.h>
#include <asm/ebus.h>
#ifdef __sparc_v9__
#include <asm/isa.h>
#endif
static unsigned long rtc_port;
static int rtc_irq = PCI_IRQ_NONE;
......@@ -930,13 +927,9 @@ static int __init rtc_init(void)
unsigned int year, ctrl;
char *guess = NULL;
#endif
#ifdef __sparc__
#ifdef CONFIG_SPARC32
struct linux_ebus *ebus;
struct linux_ebus_device *edev;
#ifdef __sparc_v9__
struct sparc_isa_bridge *isa_br;
struct sparc_isa_device *isa_dev;
#endif
#else
void *r;
#ifdef RTC_IRQ
......@@ -944,7 +937,7 @@ static int __init rtc_init(void)
#endif
#endif
#ifdef __sparc__
#ifdef CONFIG_SPARC32
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if(strcmp(edev->prom_node->name, "rtc") == 0) {
......@@ -954,17 +947,6 @@ static int __init rtc_init(void)
}
}
}
#ifdef __sparc_v9__
for_each_isa(isa_br) {
for_each_isadev(isa_dev, isa_br) {
if (strcmp(isa_dev->prom_node->name, "rtc") == 0) {
rtc_port = isa_dev->resource.start;
rtc_irq = isa_dev->irq;
goto found;
}
}
}
#endif
rtc_has_irq = 0;
printk(KERN_ERR "rtc_init: no PC rtc found\n");
return -EIO;
......@@ -1020,7 +1002,7 @@ static int __init rtc_init(void)
#endif
#endif /* __sparc__ vs. others */
#endif /* CONFIG_SPARC32 vs. others */
if (misc_register(&rtc_dev)) {
#ifdef RTC_IRQ
......@@ -1105,7 +1087,7 @@ static void __exit rtc_exit (void)
remove_proc_entry ("driver/rtc", NULL);
misc_deregister(&rtc_dev);
#ifdef __sparc__
#ifdef CONFIG_SPARC32
if (rtc_has_irq)
free_irq (rtc_irq, &rtc_port);
#else
......@@ -1117,7 +1099,7 @@ static void __exit rtc_exit (void)
if (rtc_has_irq)
free_irq (RTC_IRQ, NULL);
#endif
#endif /* __sparc__ */
#endif /* CONFIG_SPARC32 */
}
module_init(rtc_init);
......
......@@ -459,6 +459,22 @@ static int vnet_nack(struct vnet_port *port, void *msgbuf)
return 0;
}
static int handle_mcast(struct vnet_port *port, void *msgbuf)
{
struct vio_net_mcast_info *pkt = msgbuf;
if (pkt->tag.stype != VIO_SUBTYPE_ACK)
printk(KERN_ERR PFX "%s: Got unexpected MCAST reply "
"[%02x:%02x:%04x:%08x]\n",
port->vp->dev->name,
pkt->tag.type,
pkt->tag.stype,
pkt->tag.stype_env,
pkt->tag.sid);
return 0;
}
static void maybe_tx_wakeup(struct vnet *vp)
{
struct net_device *dev = vp->dev;
......@@ -544,7 +560,10 @@ static void vnet_event(void *arg, int event)
err = vnet_nack(port, &msgbuf);
}
} else if (msgbuf.tag.type == VIO_TYPE_CTRL) {
err = vio_control_pkt_engine(vio, &msgbuf);
if (msgbuf.tag.stype_env == VNET_MCAST_INFO)
err = handle_mcast(port, &msgbuf);
else
err = vio_control_pkt_engine(vio, &msgbuf);
if (err)
break;
} else {
......@@ -731,9 +750,122 @@ static int vnet_close(struct net_device *dev)
return 0;
}
static struct vnet_mcast_entry *__vnet_mc_find(struct vnet *vp, u8 *addr)
{
struct vnet_mcast_entry *m;
for (m = vp->mcast_list; m; m = m->next) {
if (!memcmp(m->addr, addr, ETH_ALEN))
return m;
}
return NULL;
}
static void __update_mc_list(struct vnet *vp, struct net_device *dev)
{
struct dev_addr_list *p;
for (p = dev->mc_list; p; p = p->next) {
struct vnet_mcast_entry *m;
m = __vnet_mc_find(vp, p->dmi_addr);
if (m) {
m->hit = 1;
continue;
}
if (!m) {
m = kzalloc(sizeof(*m), GFP_ATOMIC);
if (!m)
continue;
memcpy(m->addr, p->dmi_addr, ETH_ALEN);
m->hit = 1;
m->next = vp->mcast_list;
vp->mcast_list = m;
}
}
}
static void __send_mc_list(struct vnet *vp, struct vnet_port *port)
{
struct vio_net_mcast_info info;
struct vnet_mcast_entry *m, **pp;
int n_addrs;
memset(&info, 0, sizeof(info));
info.tag.type = VIO_TYPE_CTRL;
info.tag.stype = VIO_SUBTYPE_INFO;
info.tag.stype_env = VNET_MCAST_INFO;
info.tag.sid = vio_send_sid(&port->vio);
info.set = 1;
n_addrs = 0;
for (m = vp->mcast_list; m; m = m->next) {
if (m->sent)
continue;
m->sent = 1;
memcpy(&info.mcast_addr[n_addrs * ETH_ALEN],
m->addr, ETH_ALEN);
if (++n_addrs == VNET_NUM_MCAST) {
info.count = n_addrs;
(void) vio_ldc_send(&port->vio, &info,
sizeof(info));
n_addrs = 0;
}
}
if (n_addrs) {
info.count = n_addrs;
(void) vio_ldc_send(&port->vio, &info, sizeof(info));
}
info.set = 0;
n_addrs = 0;
pp = &vp->mcast_list;
while ((m = *pp) != NULL) {
if (m->hit) {
m->hit = 0;
pp = &m->next;
continue;
}
memcpy(&info.mcast_addr[n_addrs * ETH_ALEN],
m->addr, ETH_ALEN);
if (++n_addrs == VNET_NUM_MCAST) {
info.count = n_addrs;
(void) vio_ldc_send(&port->vio, &info,
sizeof(info));
n_addrs = 0;
}
*pp = m->next;
kfree(m);
}
if (n_addrs) {
info.count = n_addrs;
(void) vio_ldc_send(&port->vio, &info, sizeof(info));
}
}
static void vnet_set_rx_mode(struct net_device *dev)
{
/* XXX Implement multicast support XXX */
struct vnet *vp = netdev_priv(dev);
struct vnet_port *port;
unsigned long flags;
spin_lock_irqsave(&vp->lock, flags);
if (!list_empty(&vp->port_list)) {
port = list_entry(vp->port_list.next, struct vnet_port, list);
if (port->switch_port) {
__update_mc_list(vp, dev);
__send_mc_list(vp, port);
}
}
spin_unlock_irqrestore(&vp->lock, flags);
}
static int vnet_change_mtu(struct net_device *dev, int new_mtu)
......@@ -1070,6 +1202,7 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev,
switch_port = 0;
if (mdesc_get_property(hp, vdev->mp, "switch-port", NULL) != NULL)
switch_port = 1;
port->switch_port = switch_port;
spin_lock_irqsave(&vp->lock, flags);
if (switch_port)
......
......@@ -30,6 +30,8 @@ struct vnet_port {
struct hlist_node hash;
u8 raddr[ETH_ALEN];
u8 switch_port;
u8 __pad;
struct vnet *vp;
......@@ -53,6 +55,13 @@ static inline unsigned int vnet_hashfn(u8 *mac)
return val & (VNET_PORT_HASH_MASK);
}
struct vnet_mcast_entry {
u8 addr[ETH_ALEN];
u8 sent;
u8 hit;
struct vnet_mcast_entry *next;
};
struct vnet {
/* Protects port_list and port_hash. */
spinlock_t lock;
......@@ -65,6 +74,8 @@ struct vnet {
struct hlist_head port_hash[VNET_PORT_HASH_SIZE];
struct vnet_mcast_entry *mcast_list;
struct list_head list;
u64 local_mac;
};
......
......@@ -33,6 +33,7 @@ struct sbus_bus *sbus_root;
static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
{
struct dev_archdata *sd;
unsigned long base;
const void *pval;
int len, err;
......@@ -67,6 +68,10 @@ static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sde
sbus_fill_device_irq(sdev);
sd = &sdev->ofdev.dev.archdata;
sd->prom_node = dp;
sd->op = &sdev->ofdev;
sdev->ofdev.node = dp;
if (sdev->parent)
sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev;
......
......@@ -16,9 +16,10 @@
#include <linux/tty.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/serial_core.h>
#include <linux/init.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include "suncore.h"
......@@ -26,92 +27,60 @@ int sunserial_current_minor = 64;
EXPORT_SYMBOL(sunserial_current_minor);
void
sunserial_console_termios(struct console *con)
int sunserial_console_match(struct console *con, struct device_node *dp,
struct uart_driver *drv, int line)
{
char mode[16], buf[16], *s;
char mode_prop[] = "ttyX-mode";
char cd_prop[] = "ttyX-ignore-cd";
char dtr_prop[] = "ttyX-rts-dtr-off";
char *ssp_console_modes_prop = "ssp-console-modes";
int baud, bits, stop, cflag;
char parity;
int carrier = 0;
int rtsdtr = 1;
int topnd, nd;
if (!serial_console)
return;
switch (serial_console) {
case PROMDEV_OTTYA:
mode_prop[3] = 'a';
cd_prop[3] = 'a';
dtr_prop[3] = 'a';
break;
case PROMDEV_OTTYB:
mode_prop[3] = 'b';
cd_prop[3] = 'b';
dtr_prop[3] = 'b';
break;
case PROMDEV_ORSC:
nd = prom_pathtoinode("rsc");
if (!nd) {
strcpy(mode, "115200,8,n,1,-");
goto no_options;
}
int off;
if (!prom_node_has_property(nd, ssp_console_modes_prop)) {
strcpy(mode, "115200,8,n,1,-");
goto no_options;
}
if (!con || of_console_device != dp)
return 0;
memset(mode, 0, sizeof(mode));
prom_getstring(nd, ssp_console_modes_prop, mode, sizeof(mode));
goto no_options;
off = 0;
if (of_console_options &&
*of_console_options == 'b')
off = 1;
default:
strcpy(mode, "9600,8,n,1,-");
goto no_options;
}
if ((line & 1) != off)
return 0;
topnd = prom_getchild(prom_root_node);
nd = prom_searchsiblings(topnd, "options");
if (!nd) {
strcpy(mode, "9600,8,n,1,-");
goto no_options;
}
if (!prom_node_has_property(nd, mode_prop)) {
strcpy(mode, "9600,8,n,1,-");
goto no_options;
}
con->index = line;
drv->cons = con;
add_preferred_console(con->name, line, NULL);
memset(mode, 0, sizeof(mode));
prom_getstring(nd, mode_prop, mode, sizeof(mode));
if (prom_node_has_property(nd, cd_prop)) {
memset(buf, 0, sizeof(buf));
prom_getstring(nd, cd_prop, buf, sizeof(buf));
if (!strcmp(buf, "false"))
carrier = 1;
/* XXX: this is unused below. */
}
return 1;
}
EXPORT_SYMBOL(sunserial_console_match);
if (prom_node_has_property(nd, dtr_prop)) {
memset(buf, 0, sizeof(buf));
prom_getstring(nd, dtr_prop, buf, sizeof(buf));
if (!strcmp(buf, "false"))
rtsdtr = 0;
void
sunserial_console_termios(struct console *con)
{
struct device_node *dp;
const char *od, *mode, *s;
char mode_prop[] = "ttyX-mode";
int baud, bits, stop, cflag;
char parity;
/* XXX: this is unused below. */
dp = of_find_node_by_path("/options");
od = of_get_property(dp, "output-device", NULL);
if (!strcmp(od, "rsc")) {
mode = of_get_property(of_console_device,
"ssp-console-modes", NULL);
if (!mode)
mode = "115200,8,n,1,-";
} else {
char c;
c = 'a';
if (of_console_options)
c = *of_console_options;
mode_prop[3] = c;
mode = of_get_property(dp, mode_prop, NULL);
if (!mode)
mode = "9600,8,n,1,-";
}
no_options:
cflag = CREAD | HUPCL | CLOCAL;
s = mode;
......
......@@ -24,6 +24,8 @@ extern int suncore_mouse_baud_detection(unsigned char, int);
extern int sunserial_current_minor;
extern int sunserial_console_match(struct console *, struct device_node *,
struct uart_driver *, int);
extern void sunserial_console_termios(struct console *);
#endif /* !(_SERIAL_SUN_H) */
......@@ -520,16 +520,6 @@ static struct console sunhv_console = {
.data = &sunhv_reg,
};
static inline struct console *SUNHV_CONSOLE(void)
{
if (con_is_present())
return NULL;
sunhv_console.index = 0;
return &sunhv_console;
}
static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match)
{
struct uart_port *port;
......@@ -582,7 +572,8 @@ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *m
sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64;
sunserial_current_minor += 1;
sunhv_reg.cons = SUNHV_CONSOLE();
sunserial_console_match(&sunhv_console, op->node,
&sunhv_reg, port->line);
err = uart_add_one_port(&sunhv_reg, port);
if (err)
......
......@@ -968,22 +968,6 @@ static struct console sunsab_console = {
static inline struct console *SUNSAB_CONSOLE(void)
{
int i;
if (con_is_present())
return NULL;
for (i = 0; i < num_channels; i++) {
int this_minor = sunsab_reg.minor + i;
if ((this_minor - 64) == (serial_console - 1))
break;
}
if (i == num_channels)
return NULL;
sunsab_console.index = i;
return &sunsab_console;
}
#else
......@@ -1080,7 +1064,12 @@ static int __devinit sab_probe(struct of_device *op, const struct of_device_id *
return err;
}
sunserial_console_match(SUNSAB_CONSOLE(), op->node,
&sunsab_reg, up[0].port.line);
uart_add_one_port(&sunsab_reg, &up[0].port);
sunserial_console_match(SUNSAB_CONSOLE(), op->node,
&sunsab_reg, up[1].port.line);
uart_add_one_port(&sunsab_reg, &up[1].port);
dev_set_drvdata(&op->dev, &up[0]);
......@@ -1164,7 +1153,6 @@ static int __init sunsab_init(void)
}
sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64;
sunsab_reg.cons = SUNSAB_CONSOLE();
sunserial_current_minor += num_channels;
}
......
......@@ -1371,28 +1371,12 @@ static struct console sunsu_console = {
* Register console.
*/
static inline struct console *SUNSU_CONSOLE(int num_uart)
static inline struct console *SUNSU_CONSOLE(void)
{
int i;
if (con_is_present())
return NULL;
for (i = 0; i < num_uart; i++) {
int this_minor = sunsu_reg.minor + i;
if ((this_minor - 64) == (serial_console - 1))
break;
}
if (i == num_uart)
return NULL;
sunsu_console.index = i;
return &sunsu_console;
}
#else
#define SUNSU_CONSOLE(num_uart) (NULL)
#define SUNSU_CONSOLE() (NULL)
#define sunsu_serial_console_init() do { } while (0)
#endif
......@@ -1482,6 +1466,8 @@ static int __devinit su_probe(struct of_device *op, const struct of_device_id *m
up->port.ops = &sunsu_pops;
sunserial_console_match(SUNSU_CONSOLE(), dp,
&sunsu_reg, up->port.line);
err = uart_add_one_port(&sunsu_reg, &up->port);
if (err)
goto out_unmap;
......@@ -1572,7 +1558,6 @@ static int __init sunsu_init(void)
return err;
sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64;
sunserial_current_minor += num_uart;
sunsu_reg.cons = SUNSU_CONSOLE(num_uart);
}
err = of_register_driver(&su_driver, &of_bus_type);
......
......@@ -1226,23 +1226,6 @@ static struct console sunzilog_console_ops = {
static inline struct console *SUNZILOG_CONSOLE(void)
{
int i;
if (con_is_present())
return NULL;
for (i = 0; i < NUM_CHANNELS; i++) {
int this_minor = sunzilog_reg.minor + i;
if ((this_minor - 64) == (serial_console - 1))
break;
}
if (i == NUM_CHANNELS)
return NULL;
sunzilog_console_ops.index = i;
sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS;
return &sunzilog_console_ops;
}
......@@ -1428,12 +1411,18 @@ static int __devinit zs_probe(struct of_device *op, const struct of_device_id *m
sunzilog_init_hw(&up[1]);
if (!keyboard_mouse) {
if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
&sunzilog_reg, up[0].port.line))
up->flags |= SUNZILOG_FLAG_IS_CONS;
err = uart_add_one_port(&sunzilog_reg, &up[0].port);
if (err) {
of_iounmap(&op->resource[0],
rp, sizeof(struct zilog_layout));
return err;
}
if (sunserial_console_match(SUNZILOG_CONSOLE(), op->node,
&sunzilog_reg, up[1].port.line))
up->flags |= SUNZILOG_FLAG_IS_CONS;
err = uart_add_one_port(&sunzilog_reg, &up[1].port);
if (err) {
uart_remove_one_port(&sunzilog_reg, &up[0].port);
......@@ -1531,7 +1520,6 @@ static int __init sunzilog_init(void)
goto out_free_tables;
sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64;
sunzilog_reg.cons = SUNZILOG_CONSOLE();
sunserial_current_minor += uart_count;
}
......
......@@ -2913,10 +2913,6 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
int node, len, i, j, ret;
u32 mem, chip_id;
/* Do not attach when we have a serial console. */
if (!con_is_present())
return -ENXIO;
/*
* Map memory-mapped registers.
*/
......
......@@ -379,10 +379,6 @@ int __init igafb_init(void)
if (fb_get_options("igafb", NULL))
return -ENODEV;
/* Do not attach when we have a serial console. */
if (!con_is_present())
return -ENXIO;
pdev = pci_get_device(PCI_VENDOR_ID_INTERG,
PCI_DEVICE_ID_INTERG_1682, 0);
if (pdev == NULL) {
......
......@@ -3,5 +3,17 @@
*
* This file is released under the GPLv2
*/
#include <asm-generic/device.h>
#ifndef _ASM_SPARC_DEVICE_H
#define _ASM_SPARC_DEVICE_H
struct device_node;
struct of_device;
struct dev_archdata {
struct device_node *prom_node;
struct of_device *op;
};
#endif /* _ASM_SPARC_DEVICE_H */
#ifndef _ASM_FB_H_
#define _ASM_FB_H_
#include <linux/fb.h>
#include <asm/prom.h>
#define fb_pgprotect(...) do {} while (0)
static inline int fb_is_primary_device(struct fb_info *info)
{
struct device *dev = info->device;
struct device_node *node;
node = dev->archdata.prom_node;
if (node &&
node == of_console_device)
return 1;
return 0;
}
......
......@@ -158,32 +158,6 @@ extern void prom_putchar(char character);
extern void prom_printf(char *fmt, ...);
extern void prom_write(const char *buf, unsigned int len);
/* Query for input device type */
enum prom_input_device {
PROMDEV_IKBD, /* input from keyboard */
PROMDEV_ITTYA, /* input from ttya */
PROMDEV_ITTYB, /* input from ttyb */
PROMDEV_IRSC, /* input from rsc */
PROMDEV_IVCONS, /* input from virtual-console */
PROMDEV_I_UNK,
};
extern enum prom_input_device prom_query_input_device(void);
/* Query for output device type */
enum prom_output_device {
PROMDEV_OSCREEN, /* to screen */
PROMDEV_OTTYA, /* to ttya */
PROMDEV_OTTYB, /* to ttyb */
PROMDEV_ORSC, /* to rsc */
PROMDEV_OVCONS, /* to virtual-console */
PROMDEV_O_UNK,
};
extern enum prom_output_device prom_query_output_device(void);
/* Multiprocessor operations... */
/* Start the CPU with the given device tree node, context table, and context
......
......@@ -85,5 +85,9 @@ static inline void of_node_put(struct device_node *node)
*/
#include <linux/of.h>
extern struct device_node *of_console_device;
extern char *of_console_path;
extern char *of_console_options;
#endif /* __KERNEL__ */
#endif /* _SPARC_PROM_H */
......@@ -3,6 +3,7 @@
#include <linux/fb.h>
#include <linux/fs.h>
#include <asm/page.h>
#include <asm/prom.h>
static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
unsigned long off)
......@@ -12,6 +13,14 @@ static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
static inline int fb_is_primary_device(struct fb_info *info)
{
struct device *dev = info->device;
struct device_node *node;
node = dev->archdata.prom_node;
if (node &&
node == of_console_device)
return 1;
return 0;
}
......
......@@ -140,32 +140,6 @@ extern void prom_putchar(char character);
extern void prom_printf(const char *fmt, ...);
extern void prom_write(const char *buf, unsigned int len);
/* Query for input device type */
enum prom_input_device {
PROMDEV_IKBD, /* input from keyboard */
PROMDEV_ITTYA, /* input from ttya */
PROMDEV_ITTYB, /* input from ttyb */
PROMDEV_IRSC, /* input from rsc */
PROMDEV_IVCONS, /* input from virtual-console */
PROMDEV_I_UNK,
};
extern enum prom_input_device prom_query_input_device(void);
/* Query for output device type */
enum prom_output_device {
PROMDEV_OSCREEN, /* to screen */
PROMDEV_OTTYA, /* to ttya */
PROMDEV_OTTYB, /* to ttyb */
PROMDEV_ORSC, /* to rsc */
PROMDEV_OVCONS, /* to virtual-console */
PROMDEV_O_UNK,
};
extern enum prom_output_device prom_query_output_device(void);
/* Multiprocessor operations... */
#ifdef CONFIG_SMP
/* Start the CPU with the given device tree node at the passed program
......@@ -319,6 +293,8 @@ extern int prom_inst2pkg(int);
extern int prom_service_exists(const char *service_name);
extern void prom_sun4v_guest_soft_state(void);
extern int prom_ihandle2path(int handle, char *buffer, int bufsize);
/* Client interface level routines. */
extern void prom_set_trap_table(unsigned long tba);
extern void prom_set_trap_table_sun4v(unsigned long tba, unsigned long mmfsa);
......
......@@ -8,8 +8,9 @@
#define _ASM_SPARC64_PARPORT_H 1
#include <asm/ebus.h>
#include <asm/isa.h>
#include <asm/ns87303.h>
#include <asm/of_device.h>
#include <asm/prom.h>
#define PARPORT_PC_MAX_PORTS PARPORT_MAX
......@@ -35,8 +36,12 @@ static struct sparc_ebus_info {
unsigned int addr;
unsigned int count;
int lock;
struct parport *port;
} sparc_ebus_dmas[PARPORT_PC_MAX_PORTS];
static DECLARE_BITMAP(dma_slot_map, PARPORT_PC_MAX_PORTS);
static __inline__ int request_dma(unsigned int dmanr, const char *device_id)
{
if (dmanr >= PARPORT_PC_MAX_PORTS)
......@@ -98,117 +103,145 @@ static __inline__ unsigned int get_dma_residue(unsigned int dmanr)
return ebus_dma_residue(&sparc_ebus_dmas[dmanr].info);
}
static int ebus_ecpp_p(struct linux_ebus_device *edev)
static int __devinit ecpp_probe(struct of_device *op, const struct of_device_id *match)
{
if (!strcmp(edev->prom_node->name, "ecpp"))
return 1;
if (!strcmp(edev->prom_node->name, "parallel")) {
const char *compat;
compat = of_get_property(edev->prom_node,
"compatible", NULL);
if (compat &&
(!strcmp(compat, "ecpp") ||
!strcmp(compat, "ns87317-ecpp") ||
!strcmp(compat + 13, "ecpp")))
return 1;
unsigned long base = op->resource[0].start;
unsigned long config = op->resource[1].start;
unsigned long d_base = op->resource[2].start;
unsigned long d_len;
struct device_node *parent;
struct parport *p;
int slot, err;
parent = op->node->parent;
if (!strcmp(parent->name, "dma")) {
p = parport_pc_probe_port(base, base + 0x400,
op->irqs[0], PARPORT_DMA_NOFIFO,
op->dev.parent);
if (!p)
return -ENOMEM;
dev_set_drvdata(&op->dev, p);
return 0;
}
for (slot = 0; slot < PARPORT_PC_MAX_PORTS; slot++) {
if (!test_and_set_bit(slot, dma_slot_map))
break;
}
err = -ENODEV;
if (slot >= PARPORT_PC_MAX_PORTS)
goto out_err;
spin_lock_init(&sparc_ebus_dmas[slot].info.lock);
d_len = (op->resource[2].end - d_base) + 1UL;
sparc_ebus_dmas[slot].info.regs =
of_ioremap(&op->resource[2], 0, d_len, "ECPP DMA");
if (!sparc_ebus_dmas[slot].info.regs)
goto out_clear_map;
sparc_ebus_dmas[slot].info.flags = 0;
sparc_ebus_dmas[slot].info.callback = NULL;
sparc_ebus_dmas[slot].info.client_cookie = NULL;
sparc_ebus_dmas[slot].info.irq = 0xdeadbeef;
strcpy(sparc_ebus_dmas[slot].info.name, "parport");
if (ebus_dma_register(&sparc_ebus_dmas[slot].info))
goto out_unmap_regs;
ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 1);
/* Configure IRQ to Push Pull, Level Low */
/* Enable ECP, set bit 2 of the CTR first */
outb(0x04, base + 0x02);
ns87303_modify(config, PCR,
PCR_EPP_ENABLE |
PCR_IRQ_ODRAIN,
PCR_ECP_ENABLE |
PCR_ECP_CLK_ENA |
PCR_IRQ_POLAR);
/* CTR bit 5 controls direction of port */
ns87303_modify(config, PTR,
0, PTR_LPT_REG_DIR);
p = parport_pc_probe_port(base, base + 0x400,
op->irqs[0],
slot,
op->dev.parent);
err = -ENOMEM;
if (!p)
goto out_disable_irq;
dev_set_drvdata(&op->dev, p);
return 0;
out_disable_irq:
ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0);
ebus_dma_unregister(&sparc_ebus_dmas[slot].info);
out_unmap_regs:
of_iounmap(&op->resource[2], sparc_ebus_dmas[slot].info.regs, d_len);
out_clear_map:
clear_bit(slot, dma_slot_map);
out_err:
return err;
}
static int parport_isa_probe(int count)
static int __devexit ecpp_remove(struct of_device *op)
{
struct sparc_isa_bridge *isa_br;
struct sparc_isa_device *isa_dev;
for_each_isa(isa_br) {
for_each_isadev(isa_dev, isa_br) {
struct sparc_isa_device *child;
unsigned long base;
if (strcmp(isa_dev->prom_node->name, "dma"))
continue;
child = isa_dev->child;
while (child) {
if (!strcmp(child->prom_node->name, "parallel"))
break;
child = child->next;
}
if (!child)
continue;
base = child->resource.start;
/* No DMA, see commentary in
* asm-sparc64/floppy.h:isa_floppy_init()
*/
if (parport_pc_probe_port(base, base + 0x400,
child->irq, PARPORT_DMA_NOFIFO,
&child->bus->self->dev))
count++;
}
struct parport *p = dev_get_drvdata(&op->dev);
int slot = p->dma;
parport_pc_unregister_port(p);
if (slot != PARPORT_DMA_NOFIFO) {
unsigned long d_base = op->resource[2].start;
unsigned long d_len;
d_len = (op->resource[2].end - d_base) + 1UL;
ebus_dma_irq_enable(&sparc_ebus_dmas[slot].info, 0);
ebus_dma_unregister(&sparc_ebus_dmas[slot].info);
of_iounmap(&op->resource[2],
sparc_ebus_dmas[slot].info.regs,
d_len);
clear_bit(slot, dma_slot_map);
}
return count;
return 0;
}
static int parport_pc_find_nonpci_ports (int autoirq, int autodma)
static struct of_device_id ecpp_match[] = {
{
.name = "ecpp",
},
{
.name = "parallel",
.compatible = "ecpp",
},
{
.name = "parallel",
.compatible = "ns87317-ecpp",
},
{},
};
static struct of_platform_driver ecpp_driver = {
.name = "ecpp",
.match_table = ecpp_match,
.probe = ecpp_probe,
.remove = __devexit_p(ecpp_remove),
};
static int parport_pc_find_nonpci_ports(int autoirq, int autodma)
{
struct linux_ebus *ebus;
struct linux_ebus_device *edev;
int count = 0;
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
if (ebus_ecpp_p(edev)) {
unsigned long base = edev->resource[0].start;
unsigned long config = edev->resource[1].start;
unsigned long d_base = edev->resource[2].start;
unsigned long d_len;
spin_lock_init(&sparc_ebus_dmas[count].info.lock);
d_len = (edev->resource[2].end -
d_base) + 1;
sparc_ebus_dmas[count].info.regs =
ioremap(d_base, d_len);
if (!sparc_ebus_dmas[count].info.regs)
continue;
sparc_ebus_dmas[count].info.flags = 0;
sparc_ebus_dmas[count].info.callback = NULL;
sparc_ebus_dmas[count].info.client_cookie = NULL;
sparc_ebus_dmas[count].info.irq = 0xdeadbeef;
strcpy(sparc_ebus_dmas[count].info.name, "parport");
if (ebus_dma_register(&sparc_ebus_dmas[count].info))
continue;
ebus_dma_irq_enable(&sparc_ebus_dmas[count].info, 1);
/* Configure IRQ to Push Pull, Level Low */
/* Enable ECP, set bit 2 of the CTR first */
outb(0x04, base + 0x02);
ns87303_modify(config, PCR,
PCR_EPP_ENABLE |
PCR_IRQ_ODRAIN,
PCR_ECP_ENABLE |
PCR_ECP_CLK_ENA |
PCR_IRQ_POLAR);
/* CTR bit 5 controls direction of port */
ns87303_modify(config, PTR,
0, PTR_LPT_REG_DIR);
if (parport_pc_probe_port(base, base + 0x400,
edev->irqs[0],
count,
&ebus->self->dev))
count++;
}
}
}
of_register_driver(&ecpp_driver, &of_bus_type);
count = parport_isa_probe(count);
return count;
return 0;
}
#endif /* !(_ASM_SPARC64_PARPORT_H */
......@@ -94,5 +94,9 @@ static inline void of_node_put(struct device_node *node)
*/
#include <linux/of.h>
extern struct device_node *of_console_device;
extern char *of_console_path;
extern char *of_console_options;
#endif /* __KERNEL__ */
#endif /* _SPARC64_PROM_H */
......@@ -115,14 +115,8 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \
#ifndef __ASSEMBLY__
extern void sun_do_break(void);
extern int serial_console;
extern int stop_a_enabled;
static __inline__ int con_is_present(void)
{
return serial_console ? 0 : 1;
}
extern void synchronize_user_stack(void);
extern void __flushw_user(void);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册