⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ds.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* ds.c: Domain Services driver for Logical Domains * * Copyright (C) 2007 David S. Miller <davem@davemloft.net> */#include <linux/kernel.h>#include <linux/module.h>#include <linux/types.h>#include <linux/string.h>#include <linux/slab.h>#include <linux/sched.h>#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/mdesc.h>#include <asm/head.h>#include <asm/irq.h>#define DRV_MODULE_NAME		"ds"#define PFX DRV_MODULE_NAME	": "#define DRV_MODULE_VERSION	"1.0"#define DRV_MODULE_RELDATE	"Jul 11, 2007"static char version[] __devinitdata =	DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");MODULE_DESCRIPTION("Sun LDOM domain services driver");MODULE_LICENSE("GPL");MODULE_VERSION(DRV_MODULE_VERSION);struct ds_msg_tag {	__u32			type;#define DS_INIT_REQ		0x00#define DS_INIT_ACK		0x01#define DS_INIT_NACK		0x02#define DS_REG_REQ		0x03#define DS_REG_ACK		0x04#define DS_REG_NACK		0x05#define DS_UNREG_REQ		0x06#define DS_UNREG_ACK		0x07#define DS_UNREG_NACK		0x08#define DS_DATA			0x09#define DS_NACK			0x0a	__u32			len;};/* Result codes */#define DS_OK			0x00#define DS_REG_VER_NACK		0x01#define DS_REG_DUP		0x02#define DS_INV_HDL		0x03#define DS_TYPE_UNKNOWN		0x04struct ds_version {	__u16			major;	__u16			minor;};struct ds_ver_req {	struct ds_msg_tag	tag;	struct ds_version	ver;};struct ds_ver_ack {	struct ds_msg_tag	tag;	__u16			minor;};struct ds_ver_nack {	struct ds_msg_tag	tag;	__u16			major;};struct ds_reg_req {	struct ds_msg_tag	tag;	__u64			handle;	__u16			major;	__u16			minor;	char			svc_id[0];};struct ds_reg_ack {	struct ds_msg_tag	tag;	__u64			handle;	__u16			minor;};struct ds_reg_nack {	struct ds_msg_tag	tag;	__u64			handle;	__u16			major;};struct ds_unreg_req {	struct ds_msg_tag	tag;	__u64			handle;};struct ds_unreg_ack {	struct ds_msg_tag	tag;	__u64			handle;};struct ds_unreg_nack {	struct ds_msg_tag	tag;	__u64			handle;};struct ds_data {	struct ds_msg_tag	tag;	__u64			handle;};struct ds_data_nack {	struct ds_msg_tag	tag;	__u64			handle;	__u64			result;};struct ds_info;struct ds_cap_state {	__u64			handle;	void			(*data)(struct ds_info *dp,					struct ds_cap_state *cp,					void *buf, int len);	const char		*service_id;	u8			state;#define CAP_STATE_UNKNOWN	0x00#define CAP_STATE_REG_SENT	0x01#define CAP_STATE_REGISTERED	0x02};static void md_update_data(struct ds_info *dp, struct ds_cap_state *cp,			   void *buf, int len);static void domain_shutdown_data(struct ds_info *dp,				 struct ds_cap_state *cp,				 void *buf, int len);static void domain_panic_data(struct ds_info *dp,			      struct ds_cap_state *cp,			      void *buf, int len);#ifdef CONFIG_HOTPLUG_CPUstatic void dr_cpu_data(struct ds_info *dp,			struct ds_cap_state *cp,			void *buf, int len);#endifstatic void ds_pri_data(struct ds_info *dp,			struct ds_cap_state *cp,			void *buf, int len);static void ds_var_data(struct ds_info *dp,			struct ds_cap_state *cp,			void *buf, int len);struct ds_cap_state ds_states_template[] = {	{		.service_id	= "md-update",		.data		= md_update_data,	},	{		.service_id	= "domain-shutdown",		.data		= domain_shutdown_data,	},	{		.service_id	= "domain-panic",		.data		= domain_panic_data,	},#ifdef CONFIG_HOTPLUG_CPU	{		.service_id	= "dr-cpu",		.data		= dr_cpu_data,	},#endif	{		.service_id	= "pri",		.data		= ds_pri_data,	},	{		.service_id	= "var-config",		.data		= ds_var_data,	},	{		.service_id	= "var-config-backup",		.data		= ds_var_data,	},};static DEFINE_SPINLOCK(ds_lock);struct ds_info {	struct ldc_channel	*lp;	u8			hs_state;#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_list;static struct ds_cap_state *find_cap(struct ds_info *dp, u64 handle){	unsigned int index = handle >> 32;	if (index >= dp->num_ds_states)		return NULL;	return &dp->ds_states[index];}static struct ds_cap_state *find_cap_by_string(struct ds_info *dp,					       const char *name){	int i;	for (i = 0; i < dp->num_ds_states; i++) {		if (strcmp(dp->ds_states[i].service_id, name))			continue;		return &dp->ds_states[i];	}	return NULL;}static int __ds_send(struct ldc_channel *lp, void *data, int len){	int err, limit = 1000;	err = -EINVAL;	while (limit-- > 0) {		err = ldc_write(lp, data, len);		if (!err || (err != -EAGAIN))			break;		udelay(1);	}	return err;}static int ds_send(struct ldc_channel *lp, void *data, int len){	unsigned long flags;	int err;	spin_lock_irqsave(&ds_lock, flags);	err = __ds_send(lp, data, len);	spin_unlock_irqrestore(&ds_lock, flags);	return err;}struct ds_md_update_req {	__u64				req_num;};struct ds_md_update_res {	__u64				req_num;	__u32				result;};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 {		struct ds_data		data;		struct ds_md_update_res	res;	} pkt;	rp = (struct ds_md_update_req *) (dpkt + 1);	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 = cp->handle;	pkt.res.req_num = rp->req_num;	pkt.res.result = DS_OK;	ds_send(lp, &pkt, sizeof(pkt));}struct ds_shutdown_req {	__u64				req_num;	__u32				ms_delay;};struct ds_shutdown_res {	__u64				req_num;	__u32				result;	char				reason[1];};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 {		struct ds_data		data;		struct ds_shutdown_res	res;	} pkt;	rp = (struct ds_shutdown_req *) (dpkt + 1);	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 = 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));	orderly_poweroff(true);}struct ds_panic_req {	__u64				req_num;};struct ds_panic_res {	__u64				req_num;	__u32				result;	char				reason[1];};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 {		struct ds_data		data;		struct ds_panic_res	res;	} pkt;	rp = (struct ds_panic_req *) (dpkt + 1);	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 = 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));	panic("PANIC requested by LDOM manager.");}#ifdef CONFIG_HOTPLUG_CPUstruct dr_cpu_tag {	__u64				req_num;	__u32				type;#define DR_CPU_CONFIGURE		0x43#define DR_CPU_UNCONFIGURE		0x55#define DR_CPU_FORCE_UNCONFIGURE	0x46#define DR_CPU_STATUS			0x53/* Responses */#define DR_CPU_OK			0x6f#define DR_CPU_ERROR			0x65	__u32				num_records;};struct dr_cpu_resp_entry {	__u32				cpu;	__u32				result;#define DR_CPU_RES_OK			0x00#define DR_CPU_RES_FAILURE		0x01#define DR_CPU_RES_BLOCKED		0x02#define DR_CPU_RES_CPU_NOT_RESPONDING	0x03#define DR_CPU_RES_NOT_IN_MD		0x04	__u32				stat;#define DR_CPU_STAT_NOT_PRESENT		0x00#define DR_CPU_STAT_UNCONFIGURED	0x01#define DR_CPU_STAT_CONFIGURED		0x02	__u32				str_off;};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 {		struct ds_data		data;		struct dr_cpu_tag	tag;	} pkt;	int msg_len;	memset(&pkt, 0, sizeof(pkt));	pkt.data.tag.type = DS_DATA;	pkt.data.handle = cp->handle;	pkt.tag.req_num = tag->req_num;	pkt.tag.type = DR_CPU_ERROR;	pkt.tag.num_records = 0;	msg_len = (sizeof(struct ds_data) +		   sizeof(struct dr_cpu_tag));	pkt.data.tag.len = msg_len - sizeof(struct ds_msg_tag);	__ds_send(dp->lp, &pkt, msg_len);}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(dp, cp, data);	spin_unlock_irqrestore(&ds_lock, flags);}#define CPU_SENTINEL	0xffffffffstatic void purge_dups(u32 *list, u32 num_ents){	unsigned int i;	for (i = 0; i < num_ents; i++) {		u32 cpu = list[i];		unsigned int j;		if (cpu == CPU_SENTINEL)			continue;		for (j = i + 1; j < num_ents; j++) {			if (list[j] == cpu)				list[j] = CPU_SENTINEL;		}	}}static int dr_cpu_size_response(int ncpus){	return (sizeof(struct ds_data) +		sizeof(struct dr_cpu_tag) +		(sizeof(struct dr_cpu_resp_entry) * ncpus));}static void dr_cpu_init_response(struct ds_data *resp, u64 req_num,				 u64 handle, int resp_len, int ncpus,				 cpumask_t *mask, u32 default_stat){	struct dr_cpu_resp_entry *ent;	struct dr_cpu_tag *tag;	int i, cpu;	tag = (struct dr_cpu_tag *) (resp + 1);	ent = (struct dr_cpu_resp_entry *) (tag + 1);	resp->tag.type = DS_DATA;	resp->tag.len = resp_len - sizeof(struct ds_msg_tag);	resp->handle = handle;	tag->req_num = req_num;	tag->type = DR_CPU_OK;	tag->num_records = ncpus;	i = 0;	for_each_cpu_mask(cpu, *mask) {		ent[i].cpu = cpu;		ent[i].result = DR_CPU_RES_OK;		ent[i].stat = default_stat;		i++;	}	BUG_ON(i != ncpus);}static void dr_cpu_mark(struct ds_data *resp, int cpu, int ncpus,			u32 res, u32 stat){	struct dr_cpu_resp_entry *ent;	struct dr_cpu_tag *tag;	int i;	tag = (struct dr_cpu_tag *) (resp + 1);	ent = (struct dr_cpu_resp_entry *) (tag + 1);	for (i = 0; i < ncpus; i++) {		if (ent[i].cpu != cpu)			continue;		ent[i].result = res;		ent[i].stat = stat;		break;	}}static int dr_cpu_configure(struct ds_info *dp,			    struct ds_cap_state *cp,			    u64 req_num,			    cpumask_t *mask){	struct ds_data *resp;	int resp_len, ncpus, cpu;	unsigned long flags;	ncpus = cpus_weight(*mask);	resp_len = dr_cpu_size_response(ncpus);	resp = kzalloc(resp_len, GFP_KERNEL);	if (!resp)		return -ENOMEM;	dr_cpu_init_response(resp, req_num, cp->handle,			     resp_len, ncpus, mask,			     DR_CPU_STAT_CONFIGURED);	mdesc_fill_in_cpu_data(*mask);	for_each_cpu_mask(cpu, *mask) {		int err;		printk(KERN_INFO "ds-%lu: Starting cpu %d...\n",		       dp->id, cpu);		err = cpu_up(cpu);		if (err) {			__u32 res = DR_CPU_RES_FAILURE;			__u32 stat = DR_CPU_STAT_UNCONFIGURED;			if (!cpu_present(cpu)) {				/* CPU not present in MD */				res = DR_CPU_RES_NOT_IN_MD;				stat = DR_CPU_STAT_NOT_PRESENT;			} else if (err == -ENODEV) {				/* CPU did not call in successfully */				res = DR_CPU_RES_CPU_NOT_RESPONDING;			}			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(dp->lp, resp, resp_len);	spin_unlock_irqrestore(&ds_lock, flags);	kfree(resp);	/* Redistribute IRQs, taking into account the new cpus.  */	fixup_irqs();	return 0;}static int dr_cpu_unconfigure(struct ds_info *dp,			      struct ds_cap_state *cp,			      u64 req_num,			      cpumask_t *mask){	struct ds_data *resp;	int resp_len, ncpus, cpu;	unsigned long flags;	ncpus = cpus_weight(*mask);	resp_len = dr_cpu_size_response(ncpus);	resp = kzalloc(resp_len, GFP_KERNEL);	if (!resp)		return -ENOMEM;	dr_cpu_init_response(resp, req_num, cp->handle,			     resp_len, ncpus, mask,			     DR_CPU_STAT_UNCONFIGURED);	for_each_cpu_mask(cpu, *mask) {		int err;		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,				    DR_CPU_RES_FAILURE,				    DR_CPU_STAT_CONFIGURED);	}	spin_lock_irqsave(&ds_lock, flags);	__ds_send(dp->lp, resp, resp_len);	spin_unlock_irqrestore(&ds_lock, flags);	kfree(resp);	return 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -