aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Donnellan <andrew.donnellan@au1.ibm.com>2016-12-09 01:18:50 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-03-14 22:02:42 -0400
commit411d0b0ced692dd2c0d7c10514ca8b923d8fa0f8 (patch)
tree9058f7a58aa3465561c1ea70b8ebb8520a95b17f
parent60037aa689bac37816dca4eab2e8319eaa785dc6 (diff)
cxl: Prevent read/write to AFU config space while AFU not configured
commit 14a3ae34bfd0bcb1cc12d55b06a8584c11fac6fc upstream. During EEH recovery, we deconfigure all AFUs whilst leaving the corresponding vPHB and virtual PCI device in place. If something attempts to interact with the AFU's PCI config space (e.g. running lspci) after the AFU has been deconfigured and before it's reconfigured, cxl_pcie_{read,write}_config() will read invalid values from the deconfigured struct cxl_afu and proceed to Oops when they try to dereference pointers that have been set to NULL during deconfiguration. Add a rwsem to struct cxl_afu so we can prevent interaction with config space while the AFU is deconfigured. Reported-by: Pradipta Ghosh <pradghos@in.ibm.com> Suggested-by: Frederic Barrat <fbarrat@linux.vnet.ibm.com> Signed-off-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com> Signed-off-by: Vaibhav Jain <vaibhav@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/misc/cxl/cxl.h2
-rw-r--r--drivers/misc/cxl/main.c3
-rw-r--r--drivers/misc/cxl/pci.c2
-rw-r--r--drivers/misc/cxl/vphb.c51
4 files changed, 35 insertions, 23 deletions
diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h
index a144073593fa..379c463e0c4f 100644
--- a/drivers/misc/cxl/cxl.h
+++ b/drivers/misc/cxl/cxl.h
@@ -418,6 +418,8 @@ struct cxl_afu {
418 struct dentry *debugfs; 418 struct dentry *debugfs;
419 struct mutex contexts_lock; 419 struct mutex contexts_lock;
420 spinlock_t afu_cntl_lock; 420 spinlock_t afu_cntl_lock;
421 /* Used to block access to AFU config space while deconfigured */
422 struct rw_semaphore configured_rwsem;
421 423
422 /* AFU error buffer fields and bin attribute for sysfs */ 424 /* AFU error buffer fields and bin attribute for sysfs */
423 u64 eb_len, eb_offset; 425 u64 eb_len, eb_offset;
diff --git a/drivers/misc/cxl/main.c b/drivers/misc/cxl/main.c
index 62e0dfb5f15b..2a6bf1d0a3a4 100644
--- a/drivers/misc/cxl/main.c
+++ b/drivers/misc/cxl/main.c
@@ -268,7 +268,8 @@ struct cxl_afu *cxl_alloc_afu(struct cxl *adapter, int slice)
268 idr_init(&afu->contexts_idr); 268 idr_init(&afu->contexts_idr);
269 mutex_init(&afu->contexts_lock); 269 mutex_init(&afu->contexts_lock);
270 spin_lock_init(&afu->afu_cntl_lock); 270 spin_lock_init(&afu->afu_cntl_lock);
271 271 init_rwsem(&afu->configured_rwsem);
272 down_write(&afu->configured_rwsem);
272 afu->prefault_mode = CXL_PREFAULT_NONE; 273 afu->prefault_mode = CXL_PREFAULT_NONE;
273 afu->irqs_max = afu->adapter->user_irqs; 274 afu->irqs_max = afu->adapter->user_irqs;
274 275
diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c
index e96be9ca4e60..b2ff10891775 100644
--- a/drivers/misc/cxl/pci.c
+++ b/drivers/misc/cxl/pci.c
@@ -1129,6 +1129,7 @@ static int pci_configure_afu(struct cxl_afu *afu, struct cxl *adapter, struct pc
1129 if ((rc = cxl_native_register_psl_irq(afu))) 1129 if ((rc = cxl_native_register_psl_irq(afu)))
1130 goto err2; 1130 goto err2;
1131 1131
1132 up_write(&afu->configured_rwsem);
1132 return 0; 1133 return 0;
1133 1134
1134err2: 1135err2:
@@ -1141,6 +1142,7 @@ err1:
1141 1142
1142static void pci_deconfigure_afu(struct cxl_afu *afu) 1143static void pci_deconfigure_afu(struct cxl_afu *afu)
1143{ 1144{
1145 down_write(&afu->configured_rwsem);
1144 cxl_native_release_psl_irq(afu); 1146 cxl_native_release_psl_irq(afu);
1145 if (afu->adapter->native->sl_ops->release_serr_irq) 1147 if (afu->adapter->native->sl_ops->release_serr_irq)
1146 afu->adapter->native->sl_ops->release_serr_irq(afu); 1148 afu->adapter->native->sl_ops->release_serr_irq(afu);
diff --git a/drivers/misc/cxl/vphb.c b/drivers/misc/cxl/vphb.c
index 3519acebfdab..639a343b7836 100644
--- a/drivers/misc/cxl/vphb.c
+++ b/drivers/misc/cxl/vphb.c
@@ -76,23 +76,22 @@ static int cxl_pcie_cfg_record(u8 bus, u8 devfn)
76 return (bus << 8) + devfn; 76 return (bus << 8) + devfn;
77} 77}
78 78
79static int cxl_pcie_config_info(struct pci_bus *bus, unsigned int devfn, 79static inline struct cxl_afu *pci_bus_to_afu(struct pci_bus *bus)
80 struct cxl_afu **_afu, int *_record)
81{ 80{
82 struct pci_controller *phb; 81 struct pci_controller *phb = bus ? pci_bus_to_host(bus) : NULL;
83 struct cxl_afu *afu;
84 int record;
85 82
86 phb = pci_bus_to_host(bus); 83 return phb ? phb->private_data : NULL;
87 if (phb == NULL) 84}
88 return PCIBIOS_DEVICE_NOT_FOUND; 85
86static inline int cxl_pcie_config_info(struct pci_bus *bus, unsigned int devfn,
87 struct cxl_afu *afu, int *_record)
88{
89 int record;
89 90
90 afu = (struct cxl_afu *)phb->private_data;
91 record = cxl_pcie_cfg_record(bus->number, devfn); 91 record = cxl_pcie_cfg_record(bus->number, devfn);
92 if (record > afu->crs_num) 92 if (record > afu->crs_num)
93 return PCIBIOS_DEVICE_NOT_FOUND; 93 return PCIBIOS_DEVICE_NOT_FOUND;
94 94
95 *_afu = afu;
96 *_record = record; 95 *_record = record;
97 return 0; 96 return 0;
98} 97}
@@ -106,9 +105,14 @@ static int cxl_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
106 u16 val16; 105 u16 val16;
107 u32 val32; 106 u32 val32;
108 107
109 rc = cxl_pcie_config_info(bus, devfn, &afu, &record); 108 afu = pci_bus_to_afu(bus);
109 /* Grab a reader lock on afu. */
110 if (afu == NULL || !down_read_trylock(&afu->configured_rwsem))
111 return PCIBIOS_DEVICE_NOT_FOUND;
112
113 rc = cxl_pcie_config_info(bus, devfn, afu, &record);
110 if (rc) 114 if (rc)
111 return rc; 115 goto out;
112 116
113 switch (len) { 117 switch (len) {
114 case 1: 118 case 1:
@@ -127,10 +131,9 @@ static int cxl_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
127 WARN_ON(1); 131 WARN_ON(1);
128 } 132 }
129 133
130 if (rc) 134out:
131 return PCIBIOS_DEVICE_NOT_FOUND; 135 up_read(&afu->configured_rwsem);
132 136 return rc ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
133 return PCIBIOS_SUCCESSFUL;
134} 137}
135 138
136static int cxl_pcie_write_config(struct pci_bus *bus, unsigned int devfn, 139static int cxl_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
@@ -139,9 +142,14 @@ static int cxl_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
139 int rc, record; 142 int rc, record;
140 struct cxl_afu *afu; 143 struct cxl_afu *afu;
141 144
142 rc = cxl_pcie_config_info(bus, devfn, &afu, &record); 145 afu = pci_bus_to_afu(bus);
146 /* Grab a reader lock on afu. */
147 if (afu == NULL || !down_read_trylock(&afu->configured_rwsem))
148 return PCIBIOS_DEVICE_NOT_FOUND;
149
150 rc = cxl_pcie_config_info(bus, devfn, afu, &record);
143 if (rc) 151 if (rc)
144 return rc; 152 goto out;
145 153
146 switch (len) { 154 switch (len) {
147 case 1: 155 case 1:
@@ -157,10 +165,9 @@ static int cxl_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
157 WARN_ON(1); 165 WARN_ON(1);
158 } 166 }
159 167
160 if (rc) 168out:
161 return PCIBIOS_SET_FAILED; 169 up_read(&afu->configured_rwsem);
162 170 return rc ? PCIBIOS_SET_FAILED : PCIBIOS_SUCCESSFUL;
163 return PCIBIOS_SUCCESSFUL;
164} 171}
165 172
166static struct pci_ops cxl_pcie_pci_ops = 173static struct pci_ops cxl_pcie_pci_ops =