| 
									
										
										
										
											2012-11-29 14:36:55 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright IBM Corp. 2012 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Author(s): | 
					
						
							|  |  |  |  *   Jan Glauber <jang@linux.vnet.ibm.com> | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define COMPONENT "zPCI"
 | 
					
						
							|  |  |  | #define pr_fmt(fmt) COMPONENT ": " fmt
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/kernel.h>
 | 
					
						
							|  |  |  | #include <linux/stat.h>
 | 
					
						
							|  |  |  | #include <linux/pci.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static ssize_t show_fid(struct device *dev, struct device_attribute *attr, | 
					
						
							|  |  |  | 			char *buf) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-05-17 16:33:40 +02:00
										 |  |  | 	struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); | 
					
						
							| 
									
										
										
										
											2012-11-29 14:36:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-05 16:08:07 +02:00
										 |  |  | 	return sprintf(buf, "0x%08x\n", zdev->fid); | 
					
						
							| 
									
										
										
										
											2012-11-29 14:36:55 +01:00
										 |  |  | } | 
					
						
							|  |  |  | static DEVICE_ATTR(function_id, S_IRUGO, show_fid, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static ssize_t show_fh(struct device *dev, struct device_attribute *attr, | 
					
						
							|  |  |  | 		       char *buf) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-05-17 16:33:40 +02:00
										 |  |  | 	struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); | 
					
						
							| 
									
										
										
										
											2012-11-29 14:36:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-05 16:08:07 +02:00
										 |  |  | 	return sprintf(buf, "0x%08x\n", zdev->fh); | 
					
						
							| 
									
										
										
										
											2012-11-29 14:36:55 +01:00
										 |  |  | } | 
					
						
							|  |  |  | static DEVICE_ATTR(function_handle, S_IRUGO, show_fh, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static ssize_t show_pchid(struct device *dev, struct device_attribute *attr, | 
					
						
							|  |  |  | 			  char *buf) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-05-17 16:33:40 +02:00
										 |  |  | 	struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); | 
					
						
							| 
									
										
										
										
											2012-11-29 14:36:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-05 16:08:07 +02:00
										 |  |  | 	return sprintf(buf, "0x%04x\n", zdev->pchid); | 
					
						
							| 
									
										
										
										
											2012-11-29 14:36:55 +01:00
										 |  |  | } | 
					
						
							|  |  |  | static DEVICE_ATTR(pchid, S_IRUGO, show_pchid, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static ssize_t show_pfgid(struct device *dev, struct device_attribute *attr, | 
					
						
							|  |  |  | 			  char *buf) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-05-17 16:33:40 +02:00
										 |  |  | 	struct zpci_dev *zdev = get_zdev(to_pci_dev(dev)); | 
					
						
							| 
									
										
										
										
											2012-11-29 14:36:55 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-05 16:08:07 +02:00
										 |  |  | 	return sprintf(buf, "0x%02x\n", zdev->pfgid); | 
					
						
							| 
									
										
										
										
											2012-11-29 14:36:55 +01:00
										 |  |  | } | 
					
						
							|  |  |  | static DEVICE_ATTR(pfgid, S_IRUGO, show_pfgid, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-29 19:35:19 +02:00
										 |  |  | static void recover_callback(struct device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct pci_dev *pdev = to_pci_dev(dev); | 
					
						
							|  |  |  | 	struct zpci_dev *zdev = get_zdev(pdev); | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pci_stop_and_remove_bus_device(pdev); | 
					
						
							|  |  |  | 	ret = zpci_disable_device(zdev); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = zpci_enable_device(zdev); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pci_rescan_bus(zdev->bus); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static ssize_t store_recover(struct device *dev, struct device_attribute *attr, | 
					
						
							|  |  |  | 			     const char *buf, size_t count) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int rc = device_schedule_callback(dev, recover_callback); | 
					
						
							|  |  |  | 	return rc ? rc : count; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | static DEVICE_ATTR(recover, S_IWUSR, NULL, store_recover); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-29 14:36:55 +01:00
										 |  |  | static struct device_attribute *zpci_dev_attrs[] = { | 
					
						
							|  |  |  | 	&dev_attr_function_id, | 
					
						
							|  |  |  | 	&dev_attr_function_handle, | 
					
						
							|  |  |  | 	&dev_attr_pchid, | 
					
						
							|  |  |  | 	&dev_attr_pfgid, | 
					
						
							| 
									
										
										
										
											2013-08-29 19:35:19 +02:00
										 |  |  | 	&dev_attr_recover, | 
					
						
							| 
									
										
										
										
											2012-11-29 14:36:55 +01:00
										 |  |  | 	NULL, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int zpci_sysfs_add_device(struct device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i, rc = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; zpci_dev_attrs[i]; i++) { | 
					
						
							|  |  |  | 		rc = device_create_file(dev, zpci_dev_attrs[i]); | 
					
						
							|  |  |  | 		if (rc) | 
					
						
							|  |  |  | 			goto error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | error: | 
					
						
							|  |  |  | 	while (--i >= 0) | 
					
						
							|  |  |  | 		device_remove_file(dev, zpci_dev_attrs[i]); | 
					
						
							|  |  |  | 	return rc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void zpci_sysfs_remove_device(struct device *dev) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; zpci_dev_attrs[i]; i++) | 
					
						
							|  |  |  | 		device_remove_file(dev, zpci_dev_attrs[i]); | 
					
						
							|  |  |  | } |