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

📄 ap_bus.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		if (ap_dev->queue_count > 0)			*flags |= 1;		break;	case AP_RESPONSE_NO_PENDING_REPLY:		if (status.queue_empty) {			/* The card shouldn't forget requests but who knows. */			atomic_sub(ap_dev->queue_count, &ap_poll_requests);			ap_dev->queue_count = 0;			list_splice_init(&ap_dev->pendingq, &ap_dev->requestq);			ap_dev->requestq_count += ap_dev->pendingq_count;			ap_dev->pendingq_count = 0;		} else			*flags |= 2;		break;	default:		return -ENODEV;	}	return 0;}/** * Send messages from the request queue to an AP device. * @ap_dev: pointer to the AP device * @flags: pointer to control flags, bit 2^0 is set if another poll is *	   required, bit 2^1 is set if the poll timer needs to get armed * Returns 0 if the device is still present, -ENODEV if not. */static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags){	struct ap_queue_status status;	struct ap_message *ap_msg;	if (ap_dev->requestq_count <= 0 ||	    ap_dev->queue_count >= ap_dev->queue_depth)		return 0;	/* Start the next request on the queue. */	ap_msg = list_entry(ap_dev->requestq.next, struct ap_message, list);	status = __ap_send(ap_dev->qid, ap_msg->psmid,			   ap_msg->message, ap_msg->length);	switch (status.response_code) {	case AP_RESPONSE_NORMAL:		atomic_inc(&ap_poll_requests);		ap_increase_queue_count(ap_dev);		list_move_tail(&ap_msg->list, &ap_dev->pendingq);		ap_dev->requestq_count--;		ap_dev->pendingq_count++;		if (ap_dev->queue_count < ap_dev->queue_depth &&		    ap_dev->requestq_count > 0)			*flags |= 1;		*flags |= 2;		break;	case AP_RESPONSE_Q_FULL:	case AP_RESPONSE_RESET_IN_PROGRESS:		*flags |= 2;		break;	case AP_RESPONSE_MESSAGE_TOO_BIG:		return -EINVAL;	default:		return -ENODEV;	}	return 0;}/** * Poll AP device for pending replies and send new messages. If either * ap_poll_read or ap_poll_write returns -ENODEV unregister the device. * @ap_dev: pointer to the bus device * @flags: pointer to control flags, bit 2^0 is set if another poll is *	   required, bit 2^1 is set if the poll timer needs to get armed * Returns 0. */static inline int ap_poll_queue(struct ap_device *ap_dev, unsigned long *flags){	int rc;	rc = ap_poll_read(ap_dev, flags);	if (rc)		return rc;	return ap_poll_write(ap_dev, flags);}/** * Queue a message to a device. * @ap_dev: pointer to the AP device * @ap_msg: the message to be queued */static int __ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg){	struct ap_queue_status status;	if (list_empty(&ap_dev->requestq) &&	    ap_dev->queue_count < ap_dev->queue_depth) {		status = __ap_send(ap_dev->qid, ap_msg->psmid,				   ap_msg->message, ap_msg->length);		switch (status.response_code) {		case AP_RESPONSE_NORMAL:			list_add_tail(&ap_msg->list, &ap_dev->pendingq);			atomic_inc(&ap_poll_requests);			ap_dev->pendingq_count++;			ap_increase_queue_count(ap_dev);			ap_dev->total_request_count++;			break;		case AP_RESPONSE_Q_FULL:		case AP_RESPONSE_RESET_IN_PROGRESS:			list_add_tail(&ap_msg->list, &ap_dev->requestq);			ap_dev->requestq_count++;			ap_dev->total_request_count++;			return -EBUSY;		case AP_RESPONSE_MESSAGE_TOO_BIG:			ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-EINVAL));			return -EINVAL;		default:	/* Device is gone. */			ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));			return -ENODEV;		}	} else {		list_add_tail(&ap_msg->list, &ap_dev->requestq);		ap_dev->requestq_count++;		ap_dev->total_request_count++;		return -EBUSY;	}	ap_schedule_poll_timer();	return 0;}void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg){	unsigned long flags;	int rc;	spin_lock_bh(&ap_dev->lock);	if (!ap_dev->unregistered) {		/* Make room on the queue by polling for finished requests. */		rc = ap_poll_queue(ap_dev, &flags);		if (!rc)			rc = __ap_queue_message(ap_dev, ap_msg);		if (!rc)			wake_up(&ap_poll_wait);		if (rc == -ENODEV)			ap_dev->unregistered = 1;	} else {		ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));		rc = -ENODEV;	}	spin_unlock_bh(&ap_dev->lock);	if (rc == -ENODEV)		device_unregister(&ap_dev->device);}EXPORT_SYMBOL(ap_queue_message);/** * Cancel a crypto request. This is done by removing the request * from the devive pendingq or requestq queue. Note that the * request stays on the AP queue. When it finishes the message * reply will be discarded because the psmid can't be found. * @ap_dev: AP device that has the message queued * @ap_msg: the message that is to be removed */void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg){	struct ap_message *tmp;	spin_lock_bh(&ap_dev->lock);	if (!list_empty(&ap_msg->list)) {		list_for_each_entry(tmp, &ap_dev->pendingq, list)			if (tmp->psmid == ap_msg->psmid) {				ap_dev->pendingq_count--;				goto found;			}		ap_dev->requestq_count--;	found:		list_del_init(&ap_msg->list);	}	spin_unlock_bh(&ap_dev->lock);}EXPORT_SYMBOL(ap_cancel_message);/** * AP receive polling for finished AP requests */static void ap_poll_timeout(unsigned long unused){	tasklet_schedule(&ap_tasklet);}/** * Reset a not responding AP device and move all requests from the * pending queue to the request queue. */static void ap_reset(struct ap_device *ap_dev){	int rc;	ap_dev->reset = AP_RESET_IGNORE;	atomic_sub(ap_dev->queue_count, &ap_poll_requests);	ap_dev->queue_count = 0;	list_splice_init(&ap_dev->pendingq, &ap_dev->requestq);	ap_dev->requestq_count += ap_dev->pendingq_count;	ap_dev->pendingq_count = 0;	rc = ap_init_queue(ap_dev->qid);	if (rc == -ENODEV)		ap_dev->unregistered = 1;}/** * Poll all AP devices on the bus in a round robin fashion. Continue * polling until bit 2^0 of the control flags is not set. If bit 2^1 * of the control flags has been set arm the poll timer. */static int __ap_poll_all(struct ap_device *ap_dev, unsigned long *flags){	spin_lock(&ap_dev->lock);	if (!ap_dev->unregistered) {		if (ap_poll_queue(ap_dev, flags))			ap_dev->unregistered = 1;		if (ap_dev->reset == AP_RESET_DO)			ap_reset(ap_dev);	}	spin_unlock(&ap_dev->lock);	return 0;}static void ap_poll_all(unsigned long dummy){	unsigned long flags;	struct ap_device *ap_dev;	do {		flags = 0;		spin_lock(&ap_device_lock);		list_for_each_entry(ap_dev, &ap_device_list, list) {			__ap_poll_all(ap_dev, &flags);		}		spin_unlock(&ap_device_lock);	} while (flags & 1);	if (flags & 2)		ap_schedule_poll_timer();}/** * AP bus poll thread. The purpose of this thread is to poll for * finished requests in a loop if there is a "free" cpu - that is * a cpu that doesn't have anything better to do. The polling stops * as soon as there is another task or if all messages have been * delivered. */static int ap_poll_thread(void *data){	DECLARE_WAITQUEUE(wait, current);	unsigned long flags;	int requests;	struct ap_device *ap_dev;	set_user_nice(current, 19);	while (1) {		if (need_resched()) {			schedule();			continue;		}		add_wait_queue(&ap_poll_wait, &wait);		set_current_state(TASK_INTERRUPTIBLE);		if (kthread_should_stop())			break;		requests = atomic_read(&ap_poll_requests);		if (requests <= 0)			schedule();		set_current_state(TASK_RUNNING);		remove_wait_queue(&ap_poll_wait, &wait);		flags = 0;		spin_lock_bh(&ap_device_lock);		list_for_each_entry(ap_dev, &ap_device_list, list) {			__ap_poll_all(ap_dev, &flags);		}		spin_unlock_bh(&ap_device_lock);	}	set_current_state(TASK_RUNNING);	remove_wait_queue(&ap_poll_wait, &wait);	return 0;}static int ap_poll_thread_start(void){	int rc;	mutex_lock(&ap_poll_thread_mutex);	if (!ap_poll_kthread) {		ap_poll_kthread = kthread_run(ap_poll_thread, NULL, "appoll");		rc = IS_ERR(ap_poll_kthread) ? PTR_ERR(ap_poll_kthread) : 0;		if (rc)			ap_poll_kthread = NULL;	}	else		rc = 0;	mutex_unlock(&ap_poll_thread_mutex);	return rc;}static void ap_poll_thread_stop(void){	mutex_lock(&ap_poll_thread_mutex);	if (ap_poll_kthread) {		kthread_stop(ap_poll_kthread);		ap_poll_kthread = NULL;	}	mutex_unlock(&ap_poll_thread_mutex);}/** * Handling of request timeouts */static void ap_request_timeout(unsigned long data){	struct ap_device *ap_dev = (struct ap_device *) data;	if (ap_dev->reset == AP_RESET_ARMED)		ap_dev->reset = AP_RESET_DO;}static void ap_reset_domain(void){	int i;	if (ap_domain_index != -1)		for (i = 0; i < AP_DEVICES; i++)			ap_reset_queue(AP_MKQID(i, ap_domain_index));}static void ap_reset_all(void){	int i, j;	for (i = 0; i < AP_DOMAINS; i++)		for (j = 0; j < AP_DEVICES; j++)			ap_reset_queue(AP_MKQID(j, i));}static struct reset_call ap_reset_call = {	.fn = ap_reset_all,};/** * The module initialization code. */int __init ap_module_init(void){	int rc, i;	if (ap_domain_index < -1 || ap_domain_index >= AP_DOMAINS) {		printk(KERN_WARNING "Invalid param: domain = %d. "		       " Not loading.\n", ap_domain_index);		return -EINVAL;	}	if (ap_instructions_available() != 0) {		printk(KERN_WARNING "AP instructions not installed.\n");		return -ENODEV;	}	register_reset_call(&ap_reset_call);	/* Create /sys/bus/ap. */	rc = bus_register(&ap_bus_type);	if (rc)		goto out;	for (i = 0; ap_bus_attrs[i]; i++) {		rc = bus_create_file(&ap_bus_type, ap_bus_attrs[i]);		if (rc)			goto out_bus;	}	/* Create /sys/devices/ap. */	ap_root_device = s390_root_dev_register("ap");	rc = IS_ERR(ap_root_device) ? PTR_ERR(ap_root_device) : 0;	if (rc)		goto out_bus;	ap_work_queue = create_singlethread_workqueue("kapwork");	if (!ap_work_queue) {		rc = -ENOMEM;		goto out_root;	}	if (ap_select_domain() == 0)		ap_scan_bus(NULL);	/* Setup the ap bus rescan timer. */	init_timer(&ap_config_timer);	ap_config_timer.function = ap_config_timeout;	ap_config_timer.data = 0;	ap_config_timer.expires = jiffies + ap_config_time * HZ;	add_timer(&ap_config_timer);	/* Start the low priority AP bus poll thread. */	if (ap_thread_flag) {		rc = ap_poll_thread_start();		if (rc)			goto out_work;	}	return 0;out_work:	del_timer_sync(&ap_config_timer);	del_timer_sync(&ap_poll_timer);	destroy_workqueue(ap_work_queue);out_root:	s390_root_dev_unregister(ap_root_device);out_bus:	while (i--)		bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);	bus_unregister(&ap_bus_type);out:	unregister_reset_call(&ap_reset_call);	return rc;}static int __ap_match_all(struct device *dev, void *data){	return 1;}/** * The module termination code */void ap_module_exit(void){	int i;	struct device *dev;	ap_reset_domain();	ap_poll_thread_stop();	del_timer_sync(&ap_config_timer);	del_timer_sync(&ap_poll_timer);	destroy_workqueue(ap_work_queue);	tasklet_kill(&ap_tasklet);	s390_root_dev_unregister(ap_root_device);	while ((dev = bus_find_device(&ap_bus_type, NULL, NULL,		    __ap_match_all)))	{		device_unregister(dev);		put_device(dev);	}	for (i = 0; ap_bus_attrs[i]; i++)		bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);	bus_unregister(&ap_bus_type);	unregister_reset_call(&ap_reset_call);}#ifndef CONFIG_ZCRYPT_MONOLITHICmodule_init(ap_module_init);module_exit(ap_module_exit);#endif

⌨️ 快捷键说明

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