162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright IBM Corp. 2012
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author(s):
662306a36Sopenharmony_ci *   Jan Glauber <jang@linux.vnet.ibm.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#define KMSG_COMPONENT "zpci"
1062306a36Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/stat.h>
1462306a36Sopenharmony_ci#include <linux/pci.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "../../../drivers/pci/pci.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <asm/sclp.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define zpci_attr(name, fmt, member)					\
2162306a36Sopenharmony_cistatic ssize_t name##_show(struct device *dev,				\
2262306a36Sopenharmony_ci			   struct device_attribute *attr, char *buf)	\
2362306a36Sopenharmony_ci{									\
2462306a36Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));		\
2562306a36Sopenharmony_ci									\
2662306a36Sopenharmony_ci	return sprintf(buf, fmt, zdev->member);				\
2762306a36Sopenharmony_ci}									\
2862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(name)
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cizpci_attr(function_id, "0x%08x\n", fid);
3162306a36Sopenharmony_cizpci_attr(function_handle, "0x%08x\n", fh);
3262306a36Sopenharmony_cizpci_attr(pchid, "0x%04x\n", pchid);
3362306a36Sopenharmony_cizpci_attr(pfgid, "0x%02x\n", pfgid);
3462306a36Sopenharmony_cizpci_attr(vfn, "0x%04x\n", vfn);
3562306a36Sopenharmony_cizpci_attr(pft, "0x%02x\n", pft);
3662306a36Sopenharmony_cizpci_attr(port, "%d\n", port);
3762306a36Sopenharmony_cizpci_attr(uid, "0x%x\n", uid);
3862306a36Sopenharmony_cizpci_attr(segment0, "0x%02x\n", pfip[0]);
3962306a36Sopenharmony_cizpci_attr(segment1, "0x%02x\n", pfip[1]);
4062306a36Sopenharmony_cizpci_attr(segment2, "0x%02x\n", pfip[2]);
4162306a36Sopenharmony_cizpci_attr(segment3, "0x%02x\n", pfip[3]);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic ssize_t mio_enabled_show(struct device *dev,
4462306a36Sopenharmony_ci				struct device_attribute *attr, char *buf)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	return sprintf(buf, zpci_use_mio(zdev) ? "1\n" : "0\n");
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(mio_enabled);
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic ssize_t recover_store(struct device *dev, struct device_attribute *attr,
5362306a36Sopenharmony_ci			     const char *buf, size_t count)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	struct kernfs_node *kn;
5662306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
5762306a36Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(pdev);
5862306a36Sopenharmony_ci	int ret = 0;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	/* Can't use device_remove_self() here as that would lead us to lock
6162306a36Sopenharmony_ci	 * the pci_rescan_remove_lock while holding the device' kernfs lock.
6262306a36Sopenharmony_ci	 * This would create a possible deadlock with disable_slot() which is
6362306a36Sopenharmony_ci	 * not directly protected by the device' kernfs lock but takes it
6462306a36Sopenharmony_ci	 * during the device removal which happens under
6562306a36Sopenharmony_ci	 * pci_rescan_remove_lock.
6662306a36Sopenharmony_ci	 *
6762306a36Sopenharmony_ci	 * This is analogous to sdev_store_delete() in
6862306a36Sopenharmony_ci	 * drivers/scsi/scsi_sysfs.c
6962306a36Sopenharmony_ci	 */
7062306a36Sopenharmony_ci	kn = sysfs_break_active_protection(&dev->kobj, &attr->attr);
7162306a36Sopenharmony_ci	WARN_ON_ONCE(!kn);
7262306a36Sopenharmony_ci	/* device_remove_file() serializes concurrent calls ignoring all but
7362306a36Sopenharmony_ci	 * the first
7462306a36Sopenharmony_ci	 */
7562306a36Sopenharmony_ci	device_remove_file(dev, attr);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	/* A concurrent call to recover_store() may slip between
7862306a36Sopenharmony_ci	 * sysfs_break_active_protection() and the sysfs file removal.
7962306a36Sopenharmony_ci	 * Once it unblocks from pci_lock_rescan_remove() the original pdev
8062306a36Sopenharmony_ci	 * will already be removed.
8162306a36Sopenharmony_ci	 */
8262306a36Sopenharmony_ci	pci_lock_rescan_remove();
8362306a36Sopenharmony_ci	if (pci_dev_is_added(pdev)) {
8462306a36Sopenharmony_ci		pci_stop_and_remove_bus_device(pdev);
8562306a36Sopenharmony_ci		if (zdev->dma_table) {
8662306a36Sopenharmony_ci			ret = zpci_dma_exit_device(zdev);
8762306a36Sopenharmony_ci			if (ret)
8862306a36Sopenharmony_ci				goto out;
8962306a36Sopenharmony_ci		}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci		if (zdev_enabled(zdev)) {
9262306a36Sopenharmony_ci			ret = zpci_disable_device(zdev);
9362306a36Sopenharmony_ci			/*
9462306a36Sopenharmony_ci			 * Due to a z/VM vs LPAR inconsistency in the error
9562306a36Sopenharmony_ci			 * state the FH may indicate an enabled device but
9662306a36Sopenharmony_ci			 * disable says the device is already disabled don't
9762306a36Sopenharmony_ci			 * treat it as an error here.
9862306a36Sopenharmony_ci			 */
9962306a36Sopenharmony_ci			if (ret == -EINVAL)
10062306a36Sopenharmony_ci				ret = 0;
10162306a36Sopenharmony_ci			if (ret)
10262306a36Sopenharmony_ci				goto out;
10362306a36Sopenharmony_ci		}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci		ret = zpci_enable_device(zdev);
10662306a36Sopenharmony_ci		if (ret)
10762306a36Sopenharmony_ci			goto out;
10862306a36Sopenharmony_ci		ret = zpci_dma_init_device(zdev);
10962306a36Sopenharmony_ci		if (ret) {
11062306a36Sopenharmony_ci			zpci_disable_device(zdev);
11162306a36Sopenharmony_ci			goto out;
11262306a36Sopenharmony_ci		}
11362306a36Sopenharmony_ci		pci_rescan_bus(zdev->zbus->bus);
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ciout:
11662306a36Sopenharmony_ci	pci_unlock_rescan_remove();
11762306a36Sopenharmony_ci	if (kn)
11862306a36Sopenharmony_ci		sysfs_unbreak_active_protection(kn);
11962306a36Sopenharmony_ci	return ret ? ret : count;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_cistatic DEVICE_ATTR_WO(recover);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic ssize_t util_string_read(struct file *filp, struct kobject *kobj,
12462306a36Sopenharmony_ci				struct bin_attribute *attr, char *buf,
12562306a36Sopenharmony_ci				loff_t off, size_t count)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
12862306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
12962306a36Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(pdev);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	return memory_read_from_buffer(buf, count, &off, zdev->util_str,
13262306a36Sopenharmony_ci				       sizeof(zdev->util_str));
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_cistatic BIN_ATTR_RO(util_string, CLP_UTIL_STR_LEN);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic ssize_t report_error_write(struct file *filp, struct kobject *kobj,
13762306a36Sopenharmony_ci				  struct bin_attribute *attr, char *buf,
13862306a36Sopenharmony_ci				  loff_t off, size_t count)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	struct zpci_report_error_header *report = (void *) buf;
14162306a36Sopenharmony_ci	struct device *dev = kobj_to_dev(kobj);
14262306a36Sopenharmony_ci	struct pci_dev *pdev = to_pci_dev(dev);
14362306a36Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(pdev);
14462306a36Sopenharmony_ci	int ret;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	if (off || (count < sizeof(*report)))
14762306a36Sopenharmony_ci		return -EINVAL;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	ret = sclp_pci_report(report, zdev->fh, zdev->fid);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	return ret ? ret : count;
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_cistatic BIN_ATTR(report_error, S_IWUSR, NULL, report_error_write, PAGE_SIZE);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic ssize_t uid_is_unique_show(struct device *dev,
15662306a36Sopenharmony_ci				  struct device_attribute *attr, char *buf)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", zpci_unique_uid ? 1 : 0);
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(uid_is_unique);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci#ifndef CONFIG_DMI
16362306a36Sopenharmony_ci/* analogous to smbios index */
16462306a36Sopenharmony_cistatic ssize_t index_show(struct device *dev,
16562306a36Sopenharmony_ci			  struct device_attribute *attr, char *buf)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
16862306a36Sopenharmony_ci	u32 index = ~0;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	if (zpci_unique_uid)
17162306a36Sopenharmony_ci		index = zdev->uid;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", index);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_cistatic DEVICE_ATTR_RO(index);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic umode_t zpci_index_is_visible(struct kobject *kobj,
17862306a36Sopenharmony_ci				     struct attribute *attr, int n)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	return zpci_unique_uid ? attr->mode : 0;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic struct attribute *zpci_ident_attrs[] = {
18462306a36Sopenharmony_ci	&dev_attr_index.attr,
18562306a36Sopenharmony_ci	NULL,
18662306a36Sopenharmony_ci};
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic struct attribute_group zpci_ident_attr_group = {
18962306a36Sopenharmony_ci	.attrs = zpci_ident_attrs,
19062306a36Sopenharmony_ci	.is_visible = zpci_index_is_visible,
19162306a36Sopenharmony_ci};
19262306a36Sopenharmony_ci#endif
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistatic struct bin_attribute *zpci_bin_attrs[] = {
19562306a36Sopenharmony_ci	&bin_attr_util_string,
19662306a36Sopenharmony_ci	&bin_attr_report_error,
19762306a36Sopenharmony_ci	NULL,
19862306a36Sopenharmony_ci};
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic struct attribute *zpci_dev_attrs[] = {
20162306a36Sopenharmony_ci	&dev_attr_function_id.attr,
20262306a36Sopenharmony_ci	&dev_attr_function_handle.attr,
20362306a36Sopenharmony_ci	&dev_attr_pchid.attr,
20462306a36Sopenharmony_ci	&dev_attr_pfgid.attr,
20562306a36Sopenharmony_ci	&dev_attr_pft.attr,
20662306a36Sopenharmony_ci	&dev_attr_port.attr,
20762306a36Sopenharmony_ci	&dev_attr_vfn.attr,
20862306a36Sopenharmony_ci	&dev_attr_uid.attr,
20962306a36Sopenharmony_ci	&dev_attr_recover.attr,
21062306a36Sopenharmony_ci	&dev_attr_mio_enabled.attr,
21162306a36Sopenharmony_ci	&dev_attr_uid_is_unique.attr,
21262306a36Sopenharmony_ci	NULL,
21362306a36Sopenharmony_ci};
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic struct attribute_group zpci_attr_group = {
21662306a36Sopenharmony_ci	.attrs = zpci_dev_attrs,
21762306a36Sopenharmony_ci	.bin_attrs = zpci_bin_attrs,
21862306a36Sopenharmony_ci};
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic struct attribute *pfip_attrs[] = {
22162306a36Sopenharmony_ci	&dev_attr_segment0.attr,
22262306a36Sopenharmony_ci	&dev_attr_segment1.attr,
22362306a36Sopenharmony_ci	&dev_attr_segment2.attr,
22462306a36Sopenharmony_ci	&dev_attr_segment3.attr,
22562306a36Sopenharmony_ci	NULL,
22662306a36Sopenharmony_ci};
22762306a36Sopenharmony_cistatic struct attribute_group pfip_attr_group = {
22862306a36Sopenharmony_ci	.name = "pfip",
22962306a36Sopenharmony_ci	.attrs = pfip_attrs,
23062306a36Sopenharmony_ci};
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ciconst struct attribute_group *zpci_attr_groups[] = {
23362306a36Sopenharmony_ci	&zpci_attr_group,
23462306a36Sopenharmony_ci	&pfip_attr_group,
23562306a36Sopenharmony_ci#ifndef CONFIG_DMI
23662306a36Sopenharmony_ci	&zpci_ident_attr_group,
23762306a36Sopenharmony_ci#endif
23862306a36Sopenharmony_ci	NULL,
23962306a36Sopenharmony_ci};
240