1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright IBM Corp. 2012
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Author(s):
6*4882a593Smuzhiyun * Jan Glauber <jang@linux.vnet.ibm.com>
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #define KMSG_COMPONENT "zpci"
10*4882a593Smuzhiyun #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <linux/kernel.h>
13*4882a593Smuzhiyun #include <linux/stat.h>
14*4882a593Smuzhiyun #include <linux/pci.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #include "../../../drivers/pci/pci.h"
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include <asm/sclp.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #define zpci_attr(name, fmt, member) \
21*4882a593Smuzhiyun static ssize_t name##_show(struct device *dev, \
22*4882a593Smuzhiyun struct device_attribute *attr, char *buf) \
23*4882a593Smuzhiyun { \
24*4882a593Smuzhiyun struct zpci_dev *zdev = to_zpci(to_pci_dev(dev)); \
25*4882a593Smuzhiyun \
26*4882a593Smuzhiyun return sprintf(buf, fmt, zdev->member); \
27*4882a593Smuzhiyun } \
28*4882a593Smuzhiyun static DEVICE_ATTR_RO(name)
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun zpci_attr(function_id, "0x%08x\n", fid);
31*4882a593Smuzhiyun zpci_attr(function_handle, "0x%08x\n", fh);
32*4882a593Smuzhiyun zpci_attr(pchid, "0x%04x\n", pchid);
33*4882a593Smuzhiyun zpci_attr(pfgid, "0x%02x\n", pfgid);
34*4882a593Smuzhiyun zpci_attr(vfn, "0x%04x\n", vfn);
35*4882a593Smuzhiyun zpci_attr(pft, "0x%02x\n", pft);
36*4882a593Smuzhiyun zpci_attr(port, "%d\n", port);
37*4882a593Smuzhiyun zpci_attr(uid, "0x%x\n", uid);
38*4882a593Smuzhiyun zpci_attr(segment0, "0x%02x\n", pfip[0]);
39*4882a593Smuzhiyun zpci_attr(segment1, "0x%02x\n", pfip[1]);
40*4882a593Smuzhiyun zpci_attr(segment2, "0x%02x\n", pfip[2]);
41*4882a593Smuzhiyun zpci_attr(segment3, "0x%02x\n", pfip[3]);
42*4882a593Smuzhiyun
mio_enabled_show(struct device * dev,struct device_attribute * attr,char * buf)43*4882a593Smuzhiyun static ssize_t mio_enabled_show(struct device *dev,
44*4882a593Smuzhiyun struct device_attribute *attr, char *buf)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun return sprintf(buf, zpci_use_mio(zdev) ? "1\n" : "0\n");
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun static DEVICE_ATTR_RO(mio_enabled);
51*4882a593Smuzhiyun
recover_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)52*4882a593Smuzhiyun static ssize_t recover_store(struct device *dev, struct device_attribute *attr,
53*4882a593Smuzhiyun const char *buf, size_t count)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun struct kernfs_node *kn;
56*4882a593Smuzhiyun struct pci_dev *pdev = to_pci_dev(dev);
57*4882a593Smuzhiyun struct zpci_dev *zdev = to_zpci(pdev);
58*4882a593Smuzhiyun int ret = 0;
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun /* Can't use device_remove_self() here as that would lead us to lock
61*4882a593Smuzhiyun * the pci_rescan_remove_lock while holding the device' kernfs lock.
62*4882a593Smuzhiyun * This would create a possible deadlock with disable_slot() which is
63*4882a593Smuzhiyun * not directly protected by the device' kernfs lock but takes it
64*4882a593Smuzhiyun * during the device removal which happens under
65*4882a593Smuzhiyun * pci_rescan_remove_lock.
66*4882a593Smuzhiyun *
67*4882a593Smuzhiyun * This is analogous to sdev_store_delete() in
68*4882a593Smuzhiyun * drivers/scsi/scsi_sysfs.c
69*4882a593Smuzhiyun */
70*4882a593Smuzhiyun kn = sysfs_break_active_protection(&dev->kobj, &attr->attr);
71*4882a593Smuzhiyun WARN_ON_ONCE(!kn);
72*4882a593Smuzhiyun /* device_remove_file() serializes concurrent calls ignoring all but
73*4882a593Smuzhiyun * the first
74*4882a593Smuzhiyun */
75*4882a593Smuzhiyun device_remove_file(dev, attr);
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun /* A concurrent call to recover_store() may slip between
78*4882a593Smuzhiyun * sysfs_break_active_protection() and the sysfs file removal.
79*4882a593Smuzhiyun * Once it unblocks from pci_lock_rescan_remove() the original pdev
80*4882a593Smuzhiyun * will already be removed.
81*4882a593Smuzhiyun */
82*4882a593Smuzhiyun pci_lock_rescan_remove();
83*4882a593Smuzhiyun if (pci_dev_is_added(pdev)) {
84*4882a593Smuzhiyun pci_stop_and_remove_bus_device(pdev);
85*4882a593Smuzhiyun ret = zpci_disable_device(zdev);
86*4882a593Smuzhiyun if (ret)
87*4882a593Smuzhiyun goto out;
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun ret = zpci_enable_device(zdev);
90*4882a593Smuzhiyun if (ret)
91*4882a593Smuzhiyun goto out;
92*4882a593Smuzhiyun pci_rescan_bus(zdev->zbus->bus);
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun out:
95*4882a593Smuzhiyun pci_unlock_rescan_remove();
96*4882a593Smuzhiyun if (kn)
97*4882a593Smuzhiyun sysfs_unbreak_active_protection(kn);
98*4882a593Smuzhiyun return ret ? ret : count;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun static DEVICE_ATTR_WO(recover);
101*4882a593Smuzhiyun
util_string_read(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t off,size_t count)102*4882a593Smuzhiyun static ssize_t util_string_read(struct file *filp, struct kobject *kobj,
103*4882a593Smuzhiyun struct bin_attribute *attr, char *buf,
104*4882a593Smuzhiyun loff_t off, size_t count)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun struct device *dev = kobj_to_dev(kobj);
107*4882a593Smuzhiyun struct pci_dev *pdev = to_pci_dev(dev);
108*4882a593Smuzhiyun struct zpci_dev *zdev = to_zpci(pdev);
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun return memory_read_from_buffer(buf, count, &off, zdev->util_str,
111*4882a593Smuzhiyun sizeof(zdev->util_str));
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun static BIN_ATTR_RO(util_string, CLP_UTIL_STR_LEN);
114*4882a593Smuzhiyun
report_error_write(struct file * filp,struct kobject * kobj,struct bin_attribute * attr,char * buf,loff_t off,size_t count)115*4882a593Smuzhiyun static ssize_t report_error_write(struct file *filp, struct kobject *kobj,
116*4882a593Smuzhiyun struct bin_attribute *attr, char *buf,
117*4882a593Smuzhiyun loff_t off, size_t count)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun struct zpci_report_error_header *report = (void *) buf;
120*4882a593Smuzhiyun struct device *dev = kobj_to_dev(kobj);
121*4882a593Smuzhiyun struct pci_dev *pdev = to_pci_dev(dev);
122*4882a593Smuzhiyun struct zpci_dev *zdev = to_zpci(pdev);
123*4882a593Smuzhiyun int ret;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun if (off || (count < sizeof(*report)))
126*4882a593Smuzhiyun return -EINVAL;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun ret = sclp_pci_report(report, zdev->fh, zdev->fid);
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun return ret ? ret : count;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun static BIN_ATTR(report_error, S_IWUSR, NULL, report_error_write, PAGE_SIZE);
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun static struct bin_attribute *zpci_bin_attrs[] = {
135*4882a593Smuzhiyun &bin_attr_util_string,
136*4882a593Smuzhiyun &bin_attr_report_error,
137*4882a593Smuzhiyun NULL,
138*4882a593Smuzhiyun };
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun static struct attribute *zpci_dev_attrs[] = {
141*4882a593Smuzhiyun &dev_attr_function_id.attr,
142*4882a593Smuzhiyun &dev_attr_function_handle.attr,
143*4882a593Smuzhiyun &dev_attr_pchid.attr,
144*4882a593Smuzhiyun &dev_attr_pfgid.attr,
145*4882a593Smuzhiyun &dev_attr_pft.attr,
146*4882a593Smuzhiyun &dev_attr_port.attr,
147*4882a593Smuzhiyun &dev_attr_vfn.attr,
148*4882a593Smuzhiyun &dev_attr_uid.attr,
149*4882a593Smuzhiyun &dev_attr_recover.attr,
150*4882a593Smuzhiyun &dev_attr_mio_enabled.attr,
151*4882a593Smuzhiyun NULL,
152*4882a593Smuzhiyun };
153*4882a593Smuzhiyun static struct attribute_group zpci_attr_group = {
154*4882a593Smuzhiyun .attrs = zpci_dev_attrs,
155*4882a593Smuzhiyun .bin_attrs = zpci_bin_attrs,
156*4882a593Smuzhiyun };
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun static struct attribute *pfip_attrs[] = {
159*4882a593Smuzhiyun &dev_attr_segment0.attr,
160*4882a593Smuzhiyun &dev_attr_segment1.attr,
161*4882a593Smuzhiyun &dev_attr_segment2.attr,
162*4882a593Smuzhiyun &dev_attr_segment3.attr,
163*4882a593Smuzhiyun NULL,
164*4882a593Smuzhiyun };
165*4882a593Smuzhiyun static struct attribute_group pfip_attr_group = {
166*4882a593Smuzhiyun .name = "pfip",
167*4882a593Smuzhiyun .attrs = pfip_attrs,
168*4882a593Smuzhiyun };
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun const struct attribute_group *zpci_attr_groups[] = {
171*4882a593Smuzhiyun &zpci_attr_group,
172*4882a593Smuzhiyun &pfip_attr_group,
173*4882a593Smuzhiyun NULL,
174*4882a593Smuzhiyun };
175