0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/of.h>
0010 #include <linux/pci.h>
0011 #include <linux/stat.h>
0012 #include <asm/ppc-pci.h>
0013 #include <asm/pci-bridge.h>
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #define EEH_SHOW_ATTR(_name,_memb,_format) \
0025 static ssize_t eeh_show_##_name(struct device *dev, \
0026 struct device_attribute *attr, char *buf) \
0027 { \
0028 struct pci_dev *pdev = to_pci_dev(dev); \
0029 struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev); \
0030 \
0031 if (!edev) \
0032 return 0; \
0033 \
0034 return sprintf(buf, _format "\n", edev->_memb); \
0035 } \
0036 static DEVICE_ATTR(_name, 0444, eeh_show_##_name, NULL);
0037
0038 EEH_SHOW_ATTR(eeh_mode, mode, "0x%x");
0039 EEH_SHOW_ATTR(eeh_pe_config_addr, pe_config_addr, "0x%x");
0040
0041 static ssize_t eeh_pe_state_show(struct device *dev,
0042 struct device_attribute *attr, char *buf)
0043 {
0044 struct pci_dev *pdev = to_pci_dev(dev);
0045 struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);
0046 int state;
0047
0048 if (!edev || !edev->pe)
0049 return -ENODEV;
0050
0051 state = eeh_ops->get_state(edev->pe, NULL);
0052 return sprintf(buf, "0x%08x 0x%08x\n",
0053 state, edev->pe->state);
0054 }
0055
0056 static ssize_t eeh_pe_state_store(struct device *dev,
0057 struct device_attribute *attr,
0058 const char *buf, size_t count)
0059 {
0060 struct pci_dev *pdev = to_pci_dev(dev);
0061 struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);
0062
0063 if (!edev || !edev->pe)
0064 return -ENODEV;
0065
0066
0067 if (!(edev->pe->state & EEH_PE_ISOLATED))
0068 return count;
0069
0070 if (eeh_unfreeze_pe(edev->pe))
0071 return -EIO;
0072 eeh_pe_state_clear(edev->pe, EEH_PE_ISOLATED, true);
0073
0074 return count;
0075 }
0076
0077 static DEVICE_ATTR_RW(eeh_pe_state);
0078
0079 #if defined(CONFIG_PCI_IOV) && defined(CONFIG_PPC_PSERIES)
0080 static ssize_t eeh_notify_resume_show(struct device *dev,
0081 struct device_attribute *attr, char *buf)
0082 {
0083 struct pci_dev *pdev = to_pci_dev(dev);
0084 struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);
0085 struct pci_dn *pdn = pci_get_pdn(pdev);
0086
0087 if (!edev || !edev->pe)
0088 return -ENODEV;
0089
0090 return sprintf(buf, "%d\n", pdn->last_allow_rc);
0091 }
0092
0093 static ssize_t eeh_notify_resume_store(struct device *dev,
0094 struct device_attribute *attr,
0095 const char *buf, size_t count)
0096 {
0097 struct pci_dev *pdev = to_pci_dev(dev);
0098 struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);
0099
0100 if (!edev || !edev->pe || !eeh_ops->notify_resume)
0101 return -ENODEV;
0102
0103 if (eeh_ops->notify_resume(edev))
0104 return -EIO;
0105
0106 return count;
0107 }
0108 static DEVICE_ATTR_RW(eeh_notify_resume);
0109
0110 static int eeh_notify_resume_add(struct pci_dev *pdev)
0111 {
0112 struct device_node *np;
0113 int rc = 0;
0114
0115 np = pci_device_to_OF_node(pdev->is_physfn ? pdev : pdev->physfn);
0116
0117 if (of_property_read_bool(np, "ibm,is-open-sriov-pf"))
0118 rc = device_create_file(&pdev->dev, &dev_attr_eeh_notify_resume);
0119
0120 return rc;
0121 }
0122
0123 static void eeh_notify_resume_remove(struct pci_dev *pdev)
0124 {
0125 struct device_node *np;
0126
0127 np = pci_device_to_OF_node(pdev->is_physfn ? pdev : pdev->physfn);
0128
0129 if (of_property_read_bool(np, "ibm,is-open-sriov-pf"))
0130 device_remove_file(&pdev->dev, &dev_attr_eeh_notify_resume);
0131 }
0132 #else
0133 static inline int eeh_notify_resume_add(struct pci_dev *pdev) { return 0; }
0134 static inline void eeh_notify_resume_remove(struct pci_dev *pdev) { }
0135 #endif
0136
0137 void eeh_sysfs_add_device(struct pci_dev *pdev)
0138 {
0139 struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);
0140 int rc=0;
0141
0142 if (!eeh_enabled())
0143 return;
0144
0145 if (edev && (edev->mode & EEH_DEV_SYSFS))
0146 return;
0147
0148 rc += device_create_file(&pdev->dev, &dev_attr_eeh_mode);
0149 rc += device_create_file(&pdev->dev, &dev_attr_eeh_pe_config_addr);
0150 rc += device_create_file(&pdev->dev, &dev_attr_eeh_pe_state);
0151 rc += eeh_notify_resume_add(pdev);
0152
0153 if (rc)
0154 pr_warn("EEH: Unable to create sysfs entries\n");
0155 else if (edev)
0156 edev->mode |= EEH_DEV_SYSFS;
0157 }
0158
0159 void eeh_sysfs_remove_device(struct pci_dev *pdev)
0160 {
0161 struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);
0162
0163 if (!edev) {
0164 WARN_ON(eeh_enabled());
0165 return;
0166 }
0167
0168 edev->mode &= ~EEH_DEV_SYSFS;
0169
0170
0171
0172
0173
0174 if (!pdev->dev.kobj.sd)
0175 return;
0176
0177 device_remove_file(&pdev->dev, &dev_attr_eeh_mode);
0178 device_remove_file(&pdev->dev, &dev_attr_eeh_pe_config_addr);
0179 device_remove_file(&pdev->dev, &dev_attr_eeh_pe_state);
0180
0181 eeh_notify_resume_remove(pdev);
0182 }