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

📄 sclp.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
}struct sclp_statechangebuf {	struct evbuf_header	header;	u8		validity_sclp_active_facility_mask : 1;	u8		validity_sclp_receive_mask : 1;	u8		validity_sclp_send_mask : 1;	u8		validity_read_data_function_mask : 1;	u16		_zeros : 12;	u16		mask_length;	u64		sclp_active_facility_mask;	sccb_mask_t	sclp_receive_mask;	sccb_mask_t	sclp_send_mask;	u32		read_data_function_mask;} __attribute__((packed));/* State change event callback. Inform listeners of changes. */static voidsclp_state_change_cb(struct evbuf_header *evbuf){	unsigned long flags;	struct sclp_statechangebuf *scbuf;	scbuf = (struct sclp_statechangebuf *) evbuf;	if (scbuf->mask_length != sizeof(sccb_mask_t))		return;	spin_lock_irqsave(&sclp_lock, flags);	if (scbuf->validity_sclp_receive_mask)		sclp_receive_mask = scbuf->sclp_receive_mask;	if (scbuf->validity_sclp_send_mask)		sclp_send_mask = scbuf->sclp_send_mask;	spin_unlock_irqrestore(&sclp_lock, flags);	sclp_dispatch_state_change();}static struct sclp_register sclp_state_change_event = {	.receive_mask = EvTyp_StateChange_Mask,	.receiver_fn = sclp_state_change_cb};/* Calculate receive and send mask of currently registered listeners. * Called while sclp_lock is locked. */static inline void__sclp_get_mask(sccb_mask_t *receive_mask, sccb_mask_t *send_mask){	struct list_head *l;	struct sclp_register *t;	*receive_mask = 0;	*send_mask = 0;	list_for_each(l, &sclp_reg_list) {		t = list_entry(l, struct sclp_register, list);		*receive_mask |= t->receive_mask;		*send_mask |= t->send_mask;	}}/* Register event listener. Return 0 on success, non-zero otherwise. */intsclp_register(struct sclp_register *reg){	unsigned long flags;	sccb_mask_t receive_mask;	sccb_mask_t send_mask;	int rc;	rc = sclp_init();	if (rc)		return rc;	spin_lock_irqsave(&sclp_lock, flags);	/* Check event mask for collisions */	__sclp_get_mask(&receive_mask, &send_mask);	if (reg->receive_mask & receive_mask || reg->send_mask & send_mask) {		spin_unlock_irqrestore(&sclp_lock, flags);		return -EBUSY;	}	/* Trigger initial state change callback */	reg->sclp_receive_mask = 0;	reg->sclp_send_mask = 0;	list_add(&reg->list, &sclp_reg_list);	spin_unlock_irqrestore(&sclp_lock, flags);	rc = sclp_init_mask(1);	if (rc) {		spin_lock_irqsave(&sclp_lock, flags);		list_del(&reg->list);		spin_unlock_irqrestore(&sclp_lock, flags);	}	return rc;}EXPORT_SYMBOL(sclp_register);/* Unregister event listener. */voidsclp_unregister(struct sclp_register *reg){	unsigned long flags;	spin_lock_irqsave(&sclp_lock, flags);	list_del(&reg->list);	spin_unlock_irqrestore(&sclp_lock, flags);	sclp_init_mask(1);}EXPORT_SYMBOL(sclp_unregister);/* Remove event buffers which are marked processed. Return the number of * remaining event buffers. */intsclp_remove_processed(struct sccb_header *sccb){	struct evbuf_header *evbuf;	int unprocessed;	u16 remaining;	evbuf = (struct evbuf_header *) (sccb + 1);	unprocessed = 0;	remaining = sccb->length - sizeof(struct sccb_header);	while (remaining > 0) {		remaining -= evbuf->length;		if (evbuf->flags & 0x80) {			sccb->length -= evbuf->length;			memcpy(evbuf, (void *) ((addr_t) evbuf + evbuf->length),			       remaining);		} else {			unprocessed++;			evbuf = (struct evbuf_header *)					((addr_t) evbuf + evbuf->length);		}	}	return unprocessed;}EXPORT_SYMBOL(sclp_remove_processed);struct init_sccb {	struct sccb_header header;	u16 _reserved;	u16 mask_length;	sccb_mask_t receive_mask;	sccb_mask_t send_mask;	sccb_mask_t sclp_send_mask;	sccb_mask_t sclp_receive_mask;} __attribute__((packed));/* Prepare init mask request. Called while sclp_lock is locked. */static inline void__sclp_make_init_req(u32 receive_mask, u32 send_mask){	struct init_sccb *sccb;	sccb = (struct init_sccb *) sclp_init_sccb;	clear_page(sccb);	memset(&sclp_init_req, 0, sizeof(struct sclp_req));	sclp_init_req.command = SCLP_CMDW_WRITEMASK;	sclp_init_req.status = SCLP_REQ_FILLED;	sclp_init_req.start_count = 0;	sclp_init_req.callback = NULL;	sclp_init_req.callback_data = NULL;	sclp_init_req.sccb = sccb;	sccb->header.length = sizeof(struct init_sccb);	sccb->mask_length = sizeof(sccb_mask_t);	sccb->receive_mask = receive_mask;	sccb->send_mask = send_mask;	sccb->sclp_receive_mask = 0;	sccb->sclp_send_mask = 0;}/* Start init mask request. If calculate is non-zero, calculate the mask as * requested by registered listeners. Use zero mask otherwise. Return 0 on * success, non-zero otherwise. */static intsclp_init_mask(int calculate){	unsigned long flags;	struct init_sccb *sccb = (struct init_sccb *) sclp_init_sccb;	sccb_mask_t receive_mask;	sccb_mask_t send_mask;	int retry;	int rc;	unsigned long wait;	spin_lock_irqsave(&sclp_lock, flags);	/* Check if interface is in appropriate state */	if (sclp_mask_state != sclp_mask_state_idle) {		spin_unlock_irqrestore(&sclp_lock, flags);		return -EBUSY;	}	if (sclp_activation_state == sclp_activation_state_inactive) {		spin_unlock_irqrestore(&sclp_lock, flags);		return -EINVAL;	}	sclp_mask_state = sclp_mask_state_initializing;	/* Determine mask */	if (calculate)		__sclp_get_mask(&receive_mask, &send_mask);	else {		receive_mask = 0;		send_mask = 0;	}	rc = -EIO;	for (retry = 0; retry <= SCLP_MASK_RETRY; retry++) {		/* Prepare request */		__sclp_make_init_req(receive_mask, send_mask);		spin_unlock_irqrestore(&sclp_lock, flags);		if (sclp_add_request(&sclp_init_req)) {			/* Try again later */			wait = jiffies + SCLP_BUSY_INTERVAL * HZ;			while (time_before(jiffies, wait))				sclp_sync_wait();			spin_lock_irqsave(&sclp_lock, flags);			continue;		}		while (sclp_init_req.status != SCLP_REQ_DONE &&		       sclp_init_req.status != SCLP_REQ_FAILED)			sclp_sync_wait();		spin_lock_irqsave(&sclp_lock, flags);		if (sclp_init_req.status == SCLP_REQ_DONE &&		    sccb->header.response_code == 0x20) {			/* Successful request */			if (calculate) {				sclp_receive_mask = sccb->sclp_receive_mask;				sclp_send_mask = sccb->sclp_send_mask;			} else {				sclp_receive_mask = 0;				sclp_send_mask = 0;			}			spin_unlock_irqrestore(&sclp_lock, flags);			sclp_dispatch_state_change();			spin_lock_irqsave(&sclp_lock, flags);			rc = 0;			break;		}	}	sclp_mask_state = sclp_mask_state_idle;	spin_unlock_irqrestore(&sclp_lock, flags);	return rc;}/* Deactivate SCLP interface. On success, new requests will be rejected, * events will no longer be dispatched. Return 0 on success, non-zero * otherwise. */intsclp_deactivate(void){	unsigned long flags;	int rc;	spin_lock_irqsave(&sclp_lock, flags);	/* Deactivate can only be called when active */	if (sclp_activation_state != sclp_activation_state_active) {		spin_unlock_irqrestore(&sclp_lock, flags);		return -EINVAL;	}	sclp_activation_state = sclp_activation_state_deactivating;	spin_unlock_irqrestore(&sclp_lock, flags);	rc = sclp_init_mask(0);	spin_lock_irqsave(&sclp_lock, flags);	if (rc == 0)		sclp_activation_state = sclp_activation_state_inactive;	else		sclp_activation_state = sclp_activation_state_active;	spin_unlock_irqrestore(&sclp_lock, flags);	return rc;}EXPORT_SYMBOL(sclp_deactivate);/* Reactivate SCLP interface after sclp_deactivate. On success, new * requests will be accepted, events will be dispatched again. Return 0 on * success, non-zero otherwise. */intsclp_reactivate(void){	unsigned long flags;	int rc;	spin_lock_irqsave(&sclp_lock, flags);	/* Reactivate can only be called when inactive */	if (sclp_activation_state != sclp_activation_state_inactive) {		spin_unlock_irqrestore(&sclp_lock, flags);		return -EINVAL;	}	sclp_activation_state = sclp_activation_state_activating;	spin_unlock_irqrestore(&sclp_lock, flags);	rc = sclp_init_mask(1);	spin_lock_irqsave(&sclp_lock, flags);	if (rc == 0)		sclp_activation_state = sclp_activation_state_active;	else		sclp_activation_state = sclp_activation_state_inactive;	spin_unlock_irqrestore(&sclp_lock, flags);	return rc;}EXPORT_SYMBOL(sclp_reactivate);/* Handler for external interruption used during initialization. Modify * request state to done. */static voidsclp_check_handler(struct pt_regs *regs, __u16 code){	u32 finished_sccb;	finished_sccb = S390_lowcore.ext_params & 0xfffffff8;	/* Is this the interrupt we are waiting for? */	if (finished_sccb == 0)		return;	if (finished_sccb != (u32) (addr_t) sclp_init_sccb) {		printk(KERN_WARNING SCLP_HEADER "unsolicited interrupt "		       "for buffer at 0x%x\n", finished_sccb);		return;	}	spin_lock(&sclp_lock);	if (sclp_running_state == sclp_running_state_running) {		sclp_init_req.status = SCLP_REQ_DONE;		sclp_running_state = sclp_running_state_idle;	}	spin_unlock(&sclp_lock);}/* Initial init mask request timed out. Modify request state to failed. */static voidsclp_check_timeout(unsigned long data){	unsigned long flags;	spin_lock_irqsave(&sclp_lock, flags);	if (sclp_running_state == sclp_running_state_running) {		sclp_init_req.status = SCLP_REQ_FAILED;		sclp_running_state = sclp_running_state_idle;	}	spin_unlock_irqrestore(&sclp_lock, flags);}/* Perform a check of the SCLP interface. Return zero if the interface is * available and there are no pending requests from a previous instance. * Return non-zero otherwise. */static intsclp_check_interface(void){	struct init_sccb *sccb;	unsigned long flags;	int retry;	int rc;	spin_lock_irqsave(&sclp_lock, flags);	/* Prepare init mask command */	rc = register_early_external_interrupt(0x2401, sclp_check_handler,					       &ext_int_info_hwc);	if (rc) {		spin_unlock_irqrestore(&sclp_lock, flags);		return rc;	}	for (retry = 0; retry <= SCLP_INIT_RETRY; retry++) {		__sclp_make_init_req(0, 0);		sccb = (struct init_sccb *) sclp_init_req.sccb;		rc = service_call(sclp_init_req.command, sccb);		if (rc == -EIO)			break;		sclp_init_req.status = SCLP_REQ_RUNNING;		sclp_running_state = sclp_running_state_running;		__sclp_set_request_timer(SCLP_RETRY_INTERVAL * HZ,					 sclp_check_timeout, 0);		spin_unlock_irqrestore(&sclp_lock, flags);		/* Enable service-signal interruption - needs to happen		 * with IRQs enabled. */		ctl_set_bit(0, 9);		/* Wait for signal from interrupt or timeout */		sclp_sync_wait();		/* Disable service-signal interruption - needs to happen		 * with IRQs enabled. */		ctl_clear_bit(0,9);		spin_lock_irqsave(&sclp_lock, flags);		del_timer(&sclp_request_timer);		if (sclp_init_req.status == SCLP_REQ_DONE &&		    sccb->header.response_code == 0x20) {			rc = 0;			break;		} else			rc = -EBUSY;	}	unregister_early_external_interrupt(0x2401, sclp_check_handler,					    &ext_int_info_hwc);	spin_unlock_irqrestore(&sclp_lock, flags);	return rc;}/* Reboot event handler. Reset send and receive mask to prevent pending SCLP * events from interfering with rebooted system. */static intsclp_reboot_event(struct notifier_block *this, unsigned long event, void *ptr){	sclp_deactivate();	return NOTIFY_DONE;}static struct notifier_block sclp_reboot_notifier = {	.notifier_call = sclp_reboot_event};/* Initialize SCLP driver. Return zero if driver is operational, non-zero * otherwise. */static intsclp_init(void){	unsigned long flags;	int rc;	if (!MACHINE_HAS_SCLP)		return -ENODEV;	spin_lock_irqsave(&sclp_lock, flags);	/* Check for previous or running initialization */	if (sclp_init_state != sclp_init_state_uninitialized) {		spin_unlock_irqrestore(&sclp_lock, flags);		return 0;	}	sclp_init_state = sclp_init_state_initializing;	/* Set up variables */	INIT_LIST_HEAD(&sclp_req_queue);	INIT_LIST_HEAD(&sclp_reg_list);	list_add(&sclp_state_change_event.list, &sclp_reg_list);	init_timer(&sclp_request_timer);	/* Check interface */	spin_unlock_irqrestore(&sclp_lock, flags);	rc = sclp_check_interface();	spin_lock_irqsave(&sclp_lock, flags);	if (rc) {		sclp_init_state = sclp_init_state_uninitialized;		spin_unlock_irqrestore(&sclp_lock, flags);		return rc;	}	/* Register reboot handler */	rc = register_reboot_notifier(&sclp_reboot_notifier);	if (rc) {		sclp_init_state = sclp_init_state_uninitialized;		spin_unlock_irqrestore(&sclp_lock, flags);		return rc;	}	/* Register interrupt handler */	rc = register_early_external_interrupt(0x2401, sclp_interrupt_handler,					       &ext_int_info_hwc);	if (rc) {		unregister_reboot_notifier(&sclp_reboot_notifier);		sclp_init_state = sclp_init_state_uninitialized;		spin_unlock_irqrestore(&sclp_lock, flags);		return rc;	}	sclp_init_state = sclp_init_state_initialized;	spin_unlock_irqrestore(&sclp_lock, flags);	/* Enable service-signal external interruption - needs to happen with	 * IRQs enabled. */	ctl_set_bit(0, 9);	sclp_init_mask(1);	return 0;}

⌨️ 快捷键说明

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