css.c

来自「linux 内核源代码」· C语言 代码 · 共 841 行 · 第 1/2 页

C
841
字号
	unsigned long flags;	spin_lock_irqsave(&slow_subchannel_lock, flags);	idset_fill(slow_subchannel_set);	queue_work(slow_path_wq, &slow_path_work);	spin_unlock_irqrestore(&slow_subchannel_lock, flags);}/* Reprobe subchannel if unregistered. */static int reprobe_subchannel(struct subchannel_id schid, void *data){	struct subchannel *sch;	int ret;	CIO_MSG_EVENT(6, "cio: reprobe 0.%x.%04x\n",		      schid.ssid, schid.sch_no);	if (need_reprobe)		return -EAGAIN;	sch = get_subchannel_by_schid(schid);	if (sch) {		/* Already known. */		put_device(&sch->dev);		return 0;	}	ret = css_probe_device(schid);	switch (ret) {	case 0:		break;	case -ENXIO:	case -ENOMEM:	case -EIO:		/* These should abort looping */		break;	default:		ret = 0;	}	return ret;}/* Work function used to reprobe all unregistered subchannels. */static void reprobe_all(struct work_struct *unused){	int ret;	CIO_MSG_EVENT(2, "reprobe start\n");	need_reprobe = 0;	/* Make sure initial subchannel scan is done. */	wait_event(ccw_device_init_wq,		   atomic_read(&ccw_device_init_count) == 0);	ret = for_each_subchannel(reprobe_subchannel, NULL);	CIO_MSG_EVENT(2, "reprobe done (rc=%d, need_reprobe=%d)\n", ret,		      need_reprobe);}static DECLARE_WORK(css_reprobe_work, reprobe_all);/* Schedule reprobing of all unregistered subchannels. */void css_schedule_reprobe(void){	need_reprobe = 1;	queue_work(slow_path_wq, &css_reprobe_work);}EXPORT_SYMBOL_GPL(css_schedule_reprobe);/* * Called from the machine check handler for subchannel report words. */void css_process_crw(int rsid1, int rsid2){	struct subchannel_id mchk_schid;	CIO_CRW_EVENT(2, "source is subchannel %04X, subsystem id %x\n",		      rsid1, rsid2);	init_subchannel_id(&mchk_schid);	mchk_schid.sch_no = rsid1;	if (rsid2 != 0)		mchk_schid.ssid = (rsid2 >> 8) & 3;	/* 	 * Since we are always presented with IPI in the CRW, we have to	 * use stsch() to find out if the subchannel in question has come	 * or gone.	 */	css_evaluate_subchannel(mchk_schid, 0);}static int __init__init_channel_subsystem(struct subchannel_id schid, void *data){	struct subchannel *sch;	int ret;	if (cio_is_console(schid))		sch = cio_get_console_subchannel();	else {		sch = css_alloc_subchannel(schid);		if (IS_ERR(sch))			ret = PTR_ERR(sch);		else			ret = 0;		switch (ret) {		case 0:			break;		case -ENOMEM:			panic("Out of memory in init_channel_subsystem\n");		/* -ENXIO: no more subchannels. */		case -ENXIO:			return ret;		/* -EIO: this subchannel set not supported. */		case -EIO:			return ret;		default:			return 0;		}	}	/*	 * We register ALL valid subchannels in ioinfo, even those	 * that have been present before init_channel_subsystem.	 * These subchannels can't have been registered yet (kmalloc	 * not working) so we do it now. This is true e.g. for the	 * console subchannel.	 */	css_register_subchannel(sch);	return 0;}static void __initcss_generate_pgid(struct channel_subsystem *css, u32 tod_high){	if (css_characteristics_avail && css_general_characteristics.mcss) {		css->global_pgid.pgid_high.ext_cssid.version = 0x80;		css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid;	} else {#ifdef CONFIG_SMP		css->global_pgid.pgid_high.cpu_addr = hard_smp_processor_id();#else		css->global_pgid.pgid_high.cpu_addr = 0;#endif	}	css->global_pgid.cpu_id = ((cpuid_t *) __LC_CPUID)->ident;	css->global_pgid.cpu_model = ((cpuid_t *) __LC_CPUID)->machine;	css->global_pgid.tod_high = tod_high;}static voidchannel_subsystem_release(struct device *dev){	struct channel_subsystem *css;	css = to_css(dev);	mutex_destroy(&css->mutex);	kfree(css);}static ssize_tcss_cm_enable_show(struct device *dev, struct device_attribute *attr,		   char *buf){	struct channel_subsystem *css = to_css(dev);	if (!css)		return 0;	return sprintf(buf, "%x\n", css->cm_enabled);}static ssize_tcss_cm_enable_store(struct device *dev, struct device_attribute *attr,		    const char *buf, size_t count){	struct channel_subsystem *css = to_css(dev);	int ret;	switch (buf[0]) {	case '0':		ret = css->cm_enabled ? chsc_secm(css, 0) : 0;		break;	case '1':		ret = css->cm_enabled ? 0 : chsc_secm(css, 1);		break;	default:		ret = -EINVAL;	}	return ret < 0 ? ret : count;}static DEVICE_ATTR(cm_enable, 0644, css_cm_enable_show, css_cm_enable_store);static int __init setup_css(int nr){	u32 tod_high;	int ret;	struct channel_subsystem *css;	css = channel_subsystems[nr];	memset(css, 0, sizeof(struct channel_subsystem));	css->pseudo_subchannel =		kzalloc(sizeof(*css->pseudo_subchannel), GFP_KERNEL);	if (!css->pseudo_subchannel)		return -ENOMEM;	css->pseudo_subchannel->dev.parent = &css->device;	css->pseudo_subchannel->dev.release = css_subchannel_release;	sprintf(css->pseudo_subchannel->dev.bus_id, "defunct");	ret = cio_create_sch_lock(css->pseudo_subchannel);	if (ret) {		kfree(css->pseudo_subchannel);		return ret;	}	mutex_init(&css->mutex);	css->valid = 1;	css->cssid = nr;	sprintf(css->device.bus_id, "css%x", nr);	css->device.release = channel_subsystem_release;	tod_high = (u32) (get_clock() >> 32);	css_generate_pgid(css, tod_high);	return 0;}static int css_reboot_event(struct notifier_block *this,			    unsigned long event,			    void *ptr){	int ret, i;	ret = NOTIFY_DONE;	for (i = 0; i <= __MAX_CSSID; i++) {		struct channel_subsystem *css;		css = channel_subsystems[i];		if (css->cm_enabled)			if (chsc_secm(css, 0))				ret = NOTIFY_BAD;	}	return ret;}static struct notifier_block css_reboot_notifier = {	.notifier_call = css_reboot_event,};/* * Now that the driver core is running, we can setup our channel subsystem. * The struct subchannel's are created during probing (except for the * static console subchannel). */static int __initinit_channel_subsystem (void){	int ret, i;	ret = chsc_determine_css_characteristics();	if (ret == -ENOMEM)		goto out; /* No need to continue. */	if (ret == 0)		css_characteristics_avail = 1;	ret = chsc_alloc_sei_area();	if (ret)		goto out;	ret = slow_subchannel_init();	if (ret)		goto out;	if ((ret = bus_register(&css_bus_type)))		goto out;	/* Try to enable MSS. */	ret = chsc_enable_facility(CHSC_SDA_OC_MSS);	switch (ret) {	case 0: /* Success. */		max_ssid = __MAX_SSID;		break;	case -ENOMEM:		goto out_bus;	default:		max_ssid = 0;	}	/* Setup css structure. */	for (i = 0; i <= __MAX_CSSID; i++) {		struct channel_subsystem *css;		css = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL);		if (!css) {			ret = -ENOMEM;			goto out_unregister;		}		channel_subsystems[i] = css;		ret = setup_css(i);		if (ret)			goto out_free;		ret = device_register(&css->device);		if (ret)			goto out_free_all;		if (css_characteristics_avail &&		    css_chsc_characteristics.secm) {			ret = device_create_file(&css->device,						 &dev_attr_cm_enable);			if (ret)				goto out_device;		}		ret = device_register(&css->pseudo_subchannel->dev);		if (ret)			goto out_file;	}	ret = register_reboot_notifier(&css_reboot_notifier);	if (ret)		goto out_pseudo;	css_init_done = 1;	ctl_set_bit(6, 28);	for_each_subchannel(__init_channel_subsystem, NULL);	return 0;out_pseudo:	device_unregister(&channel_subsystems[i]->pseudo_subchannel->dev);out_file:	device_remove_file(&channel_subsystems[i]->device,			   &dev_attr_cm_enable);out_device:	device_unregister(&channel_subsystems[i]->device);out_free_all:	kfree(channel_subsystems[i]->pseudo_subchannel->lock);	kfree(channel_subsystems[i]->pseudo_subchannel);out_free:	kfree(channel_subsystems[i]);out_unregister:	while (i > 0) {		struct channel_subsystem *css;		i--;		css = channel_subsystems[i];		device_unregister(&css->pseudo_subchannel->dev);		if (css_characteristics_avail && css_chsc_characteristics.secm)			device_remove_file(&css->device,					   &dev_attr_cm_enable);		device_unregister(&css->device);	}out_bus:	bus_unregister(&css_bus_type);out:	chsc_free_sei_area();	kfree(slow_subchannel_set);	printk(KERN_WARNING"cio: failed to initialize css driver (%d)!\n",	       ret);	return ret;}int sch_is_pseudo_sch(struct subchannel *sch){	return sch == to_css(sch->dev.parent)->pseudo_subchannel;}/* * find a driver for a subchannel. They identify by the subchannel * type with the exception that the console subchannel driver has its own * subchannel type although the device is an i/o subchannel */static intcss_bus_match (struct device *dev, struct device_driver *drv){	struct subchannel *sch = container_of (dev, struct subchannel, dev);	struct css_driver *driver = container_of (drv, struct css_driver, drv);	if (sch->st == driver->subchannel_type)		return 1;	return 0;}static intcss_probe (struct device *dev){	struct subchannel *sch;	sch = to_subchannel(dev);	sch->driver = container_of (dev->driver, struct css_driver, drv);	return (sch->driver->probe ? sch->driver->probe(sch) : 0);}static intcss_remove (struct device *dev){	struct subchannel *sch;	sch = to_subchannel(dev);	return (sch->driver->remove ? sch->driver->remove(sch) : 0);}static voidcss_shutdown (struct device *dev){	struct subchannel *sch;	sch = to_subchannel(dev);	if (sch->driver->shutdown)		sch->driver->shutdown(sch);}struct bus_type css_bus_type = {	.name     = "css",	.match    = css_bus_match,	.probe    = css_probe,	.remove   = css_remove,	.shutdown = css_shutdown,};subsys_initcall(init_channel_subsystem);MODULE_LICENSE("GPL");EXPORT_SYMBOL(css_bus_type);EXPORT_SYMBOL_GPL(css_characteristics_avail);

⌨️ 快捷键说明

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