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

📄 ds.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
}static void dr_cpu_data(struct ds_info *dp,			struct ds_cap_state *cp,			void *buf, int len){	struct ds_data *data = buf;	struct dr_cpu_tag *tag = (struct dr_cpu_tag *) (data + 1);	u32 *cpu_list = (u32 *) (tag + 1);	u64 req_num = tag->req_num;	cpumask_t mask;	unsigned int i;	int err;	switch (tag->type) {	case DR_CPU_CONFIGURE:	case DR_CPU_UNCONFIGURE:	case DR_CPU_FORCE_UNCONFIGURE:		break;	default:		dr_cpu_send_error(dp, cp, data);		return;	}	purge_dups(cpu_list, tag->num_records);	cpus_clear(mask);	for (i = 0; i < tag->num_records; i++) {		if (cpu_list[i] == CPU_SENTINEL)			continue;		if (cpu_list[i] < NR_CPUS)			cpu_set(cpu_list[i], mask);	}	if (tag->type == DR_CPU_CONFIGURE)		err = dr_cpu_configure(dp, cp, req_num, &mask);	else		err = dr_cpu_unconfigure(dp, cp, req_num, &mask);	if (err)		dr_cpu_send_error(dp, cp, data);}#endif /* CONFIG_HOTPLUG_CPU */struct ds_pri_msg {	__u64				req_num;	__u64				type;#define DS_PRI_REQUEST			0x00#define DS_PRI_DATA			0x01#define DS_PRI_UPDATE			0x02};static void ds_pri_data(struct ds_info *dp,			struct ds_cap_state *cp,			void *buf, int len){	struct ds_data *dpkt = buf;	struct ds_pri_msg *rp;	rp = (struct ds_pri_msg *) (dpkt + 1);	printk(KERN_INFO "ds-%lu: PRI REQ [%lx:%lx], len=%d\n",	       dp->id, rp->req_num, rp->type, len);}struct ds_var_hdr {	__u32				type;#define DS_VAR_SET_REQ			0x00#define DS_VAR_DELETE_REQ		0x01#define DS_VAR_SET_RESP			0x02#define DS_VAR_DELETE_RESP		0x03};struct ds_var_set_msg {	struct ds_var_hdr		hdr;	char				name_and_value[0];};struct ds_var_delete_msg {	struct ds_var_hdr		hdr;	char				name[0];};struct ds_var_resp {	struct ds_var_hdr		hdr;	__u32				result;#define DS_VAR_SUCCESS			0x00#define DS_VAR_NO_SPACE			0x01#define DS_VAR_INVALID_VAR		0x02#define DS_VAR_INVALID_VAL		0x03#define DS_VAR_NOT_PRESENT		0x04};static DEFINE_MUTEX(ds_var_mutex);static int ds_var_doorbell;static int ds_var_response;static void ds_var_data(struct ds_info *dp,			struct ds_cap_state *cp,			void *buf, int len){	struct ds_data *dpkt = buf;	struct ds_var_resp *rp;	rp = (struct ds_var_resp *) (dpkt + 1);	if (rp->hdr.type != DS_VAR_SET_RESP &&	    rp->hdr.type != DS_VAR_DELETE_RESP)		return;	ds_var_response = rp->result;	wmb();	ds_var_doorbell = 1;}void ldom_set_var(const char *var, const char *value){	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;			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) {		union {			struct {				struct ds_data		data;				struct ds_var_set_msg	msg;			} header;			char			all[512];		} pkt;		char  *base, *p;		int msg_len, loops;		memset(&pkt, 0, sizeof(pkt));		pkt.header.data.tag.type = DS_DATA;		pkt.header.data.handle = cp->handle;		pkt.header.msg.hdr.type = DS_VAR_SET_REQ;		base = p = &pkt.header.msg.name_and_value[0];		strcpy(p, var);		p += strlen(var) + 1;		strcpy(p, value);		p += strlen(value) + 1;		msg_len = (sizeof(struct ds_data) +			   sizeof(struct ds_var_set_msg) +			   (p - base));		msg_len = (msg_len + 3) & ~3;		pkt.header.data.tag.len = msg_len - sizeof(struct ds_msg_tag);		mutex_lock(&ds_var_mutex);		spin_lock_irqsave(&ds_lock, flags);		ds_var_doorbell = 0;		ds_var_response = -1;		__ds_send(dp->lp, &pkt, msg_len);		spin_unlock_irqrestore(&ds_lock, flags);		loops = 1000;		while (ds_var_doorbell == 0) {			if (loops-- < 0)				break;			barrier();			udelay(100);		}		mutex_unlock(&ds_var_mutex);		if (ds_var_doorbell == 0 ||		    ds_var_response != DS_VAR_SUCCESS)			printk(KERN_ERR "ds-%lu: var-config [%s:%s] "			       "failed, response(%d).\n",			       dp->id, var, value,			       ds_var_response);	} else {		printk(KERN_ERR PFX "var-config not registered so "		       "could not set (%s) variable to (%s).\n",		       var, value);	}}void ldom_reboot(const char *boot_command){	/* Don't bother with any of this if the boot_command	 * is empty.	 */	if (boot_command && strlen(boot_command)) {		char full_boot_str[256];		strcpy(full_boot_str, "boot ");		strcpy(full_boot_str + strlen("boot "), boot_command);		ldom_set_var("reboot-command", full_boot_str);	}	sun4v_mach_sir();}void ldom_power_off(void){	sun4v_mach_exit(0);}static void ds_conn_reset(struct ds_info *dp){	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){	struct ldc_channel *lp = dp->lp;	int 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 = &dp->ds_states[i];		int err, msg_len;		u64 new_count;		if (cp->state == CAP_STATE_REGISTERED)			continue;		new_count = sched_clock() & 0xffffffff;		cp->handle = ((u64) i << 32) | new_count;		msg_len = (sizeof(struct ds_reg_req) +			   strlen(cp->service_id));		memset(&pbuf, 0, sizeof(pbuf));		pbuf.req.tag.type = DS_REG_REQ;		pbuf.req.tag.len = (msg_len - sizeof(struct ds_msg_tag));		pbuf.req.handle = cp->handle;		pbuf.req.major = 1;		pbuf.req.minor = 0;		strcpy(pbuf.req.svc_id, cp->service_id);		err = __ds_send(lp, &pbuf, msg_len);		if (err > 0)			cp->state = CAP_STATE_REG_SENT;	}	return 0;}static int ds_handshake(struct ds_info *dp, struct ds_msg_tag *pkt){	if (dp->hs_state == DS_HS_START) {		if (pkt->type != DS_INIT_ACK)			goto conn_reset;		dp->hs_state = DS_HS_DONE;		return register_services(dp);	}	if (dp->hs_state != DS_HS_DONE)		goto conn_reset;	if (pkt->type == DS_REG_ACK) {		struct ds_reg_ack *ap = (struct ds_reg_ack *) pkt;		struct ds_cap_state *cp = find_cap(dp, ap->handle);		if (!cp) {			printk(KERN_ERR "ds-%lu: REG ACK for unknown "			       "handle %lx\n", dp->id, ap->handle);			return 0;		}		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(dp, np->handle);		if (!cp) {			printk(KERN_ERR "ds-%lu: REG NACK for "			       "unknown handle %lx\n",			       dp->id, np->handle);			return 0;		}		cp->state = CAP_STATE_UNKNOWN;	}	return 0;conn_reset:	ds_conn_reset(dp);	return -ECONNRESET;}static void __send_ds_nack(struct ds_info *dp, u64 handle){	struct ds_data_nack nack = {		.tag = {			.type = DS_NACK,			.len = (sizeof(struct ds_data_nack) -				sizeof(struct ds_msg_tag)),		},		.handle = handle,		.result = DS_INV_HDL,	};	__ds_send(dp->lp, &nack, sizeof(nack));}static LIST_HEAD(ds_work_list);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];};static void process_ds_work(void){	struct ds_queue_entry *qp, *tmp;	unsigned long flags;	LIST_HEAD(todo);	spin_lock_irqsave(&ds_lock, flags);	list_splice(&ds_work_list, &todo);	INIT_LIST_HEAD(&ds_work_list);	spin_unlock_irqrestore(&ds_lock, flags);	list_for_each_entry_safe(qp, tmp, &todo, list) {		struct ds_data *dpkt = (struct ds_data *) qp->req;		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 "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, cp, dpkt, req_len);		}		list_del(&qp->list);		kfree(qp);	}}static int ds_thread(void *__unused){	DEFINE_WAIT(wait);	while (1) {		prepare_to_wait(&ds_wait, &wait, TASK_INTERRUPTIBLE);		if (list_empty(&ds_work_list))			schedule();		finish_wait(&ds_wait, &wait);		if (kthread_should_stop())			break;		process_ds_work();	}	return 0;}static int ds_data(struct ds_info *dp, struct ds_msg_tag *pkt, int len){	struct ds_data *dpkt = (struct ds_data *) pkt;	struct ds_queue_entry *qp;	qp = kmalloc(sizeof(struct ds_queue_entry) + len, GFP_ATOMIC);	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);	}	return 0;}static void ds_up(struct ds_info *dp){	struct ldc_channel *lp = dp->lp;	struct ds_ver_req req;	int err;	req.tag.type = DS_INIT_REQ;	req.tag.len = sizeof(req) - sizeof(struct ds_msg_tag);	req.ver.major = 1;	req.ver.minor = 0;	err = __ds_send(lp, &req, sizeof(req));	if (err > 0)		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;	struct ldc_channel *lp = dp->lp;	unsigned long flags;	int err;	spin_lock_irqsave(&ds_lock, flags);	if (event == LDC_EVENT_UP) {		ds_up(dp);		spin_unlock_irqrestore(&ds_lock, flags);		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 "ds-%lu: Unexpected LDC event %d\n",		       dp->id, event);		spin_unlock_irqrestore(&ds_lock, flags);		return;	}	err = 0;	while (1) {		struct ds_msg_tag *tag;		err = ldc_read(lp, dp->rcv_buf, sizeof(*tag));		if (unlikely(err < 0)) {			if (err == -ECONNRESET)				ds_conn_reset(dp);			break;		}		if (err == 0)			break;		tag = dp->rcv_buf;		err = ldc_read(lp, tag + 1, tag->len);		if (unlikely(err < 0)) {			if (err == -ECONNRESET)				ds_conn_reset(dp);			break;		}		if (err < tag->len)			break;		if (tag->type < DS_DATA)			err = ds_handshake(dp, dp->rcv_buf);		else			err = ds_data(dp, dp->rcv_buf,				      sizeof(*tag) + err);		if (err == -ECONNRESET)			break;	}	spin_unlock_irqrestore(&ds_lock, flags);}static int __devinit ds_probe(struct vio_dev *vdev,			      const struct vio_device_id *id){	static int ds_version_printed;	struct ldc_channel_config ds_cfg = {		.event		= ds_event,		.mtu		= 4096,		.mode		= LDC_MODE_STREAM,	};	struct mdesc_handle *hp;	struct ldc_channel *lp;	struct ds_info *dp;	const u64 *val;	int err, i;	if (ds_version_printed++ == 0)		printk(KERN_INFO "%s", version);	dp = kzalloc(sizeof(*dp), GFP_KERNEL);	err = -ENOMEM;	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_ds_states;	}	dp->lp = lp;	err = ldc_bind(lp, "DS");	if (err)		goto out_free_ldc;	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);out_free_dp:	kfree(dp);out_err:	return err;}static int ds_remove(struct vio_dev *vdev){	return 0;}static struct vio_device_id ds_match[] = {	{		.type = "domain-services-port",	},	{},};static struct vio_driver ds_driver = {	.id_table	= ds_match,	.probe		= ds_probe,	.remove		= ds_remove,	.driver		= {		.name	= "ds",		.owner	= THIS_MODULE,	}};static int __init ds_init(void){	kthread_run(ds_thread, NULL, "kldomd");	return vio_register_driver(&ds_driver);}subsys_initcall(ds_init);

⌨️ 快捷键说明

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