aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r--arch/powerpc/platforms/powernv/eeh-ioda.c99
1 files changed, 98 insertions, 1 deletions
diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c
index 744eb9e39be2..a76870b6a184 100644
--- a/arch/powerpc/platforms/powernv/eeh-ioda.c
+++ b/arch/powerpc/platforms/powernv/eeh-ioda.c
@@ -116,10 +116,107 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
116 return ret; 116 return ret;
117} 117}
118 118
119/**
120 * ioda_eeh_get_state - Retrieve the state of PE
121 * @pe: EEH PE
122 *
123 * The PE's state should be retrieved from the PEEV, PEST
124 * IODA tables. Since the OPAL has exported the function
125 * to do it, it'd better to use that.
126 */
127static int ioda_eeh_get_state(struct eeh_pe *pe)
128{
129 s64 ret = 0;
130 u8 fstate;
131 u16 pcierr;
132 u32 pe_no;
133 int result;
134 struct pci_controller *hose = pe->phb;
135 struct pnv_phb *phb = hose->private_data;
136
137 /*
138 * Sanity check on PE address. The PHB PE address should
139 * be zero.
140 */
141 if (pe->addr < 0 || pe->addr >= phb->ioda.total_pe) {
142 pr_err("%s: PE address %x out of range [0, %x] "
143 "on PHB#%x\n",
144 __func__, pe->addr, phb->ioda.total_pe,
145 hose->global_number);
146 return EEH_STATE_NOT_SUPPORT;
147 }
148
149 /* Retrieve PE status through OPAL */
150 pe_no = pe->addr;
151 ret = opal_pci_eeh_freeze_status(phb->opal_id, pe_no,
152 &fstate, &pcierr, NULL);
153 if (ret) {
154 pr_err("%s: Failed to get EEH status on "
155 "PHB#%x-PE#%x\n, err=%lld\n",
156 __func__, hose->global_number, pe_no, ret);
157 return EEH_STATE_NOT_SUPPORT;
158 }
159
160 /* Check PHB status */
161 if (pe->type & EEH_PE_PHB) {
162 result = 0;
163 result &= ~EEH_STATE_RESET_ACTIVE;
164
165 if (pcierr != OPAL_EEH_PHB_ERROR) {
166 result |= EEH_STATE_MMIO_ACTIVE;
167 result |= EEH_STATE_DMA_ACTIVE;
168 result |= EEH_STATE_MMIO_ENABLED;
169 result |= EEH_STATE_DMA_ENABLED;
170 }
171
172 return result;
173 }
174
175 /* Parse result out */
176 result = 0;
177 switch (fstate) {
178 case OPAL_EEH_STOPPED_NOT_FROZEN:
179 result &= ~EEH_STATE_RESET_ACTIVE;
180 result |= EEH_STATE_MMIO_ACTIVE;
181 result |= EEH_STATE_DMA_ACTIVE;
182 result |= EEH_STATE_MMIO_ENABLED;
183 result |= EEH_STATE_DMA_ENABLED;
184 break;
185 case OPAL_EEH_STOPPED_MMIO_FREEZE:
186 result &= ~EEH_STATE_RESET_ACTIVE;
187 result |= EEH_STATE_DMA_ACTIVE;
188 result |= EEH_STATE_DMA_ENABLED;
189 break;
190 case OPAL_EEH_STOPPED_DMA_FREEZE:
191 result &= ~EEH_STATE_RESET_ACTIVE;
192 result |= EEH_STATE_MMIO_ACTIVE;
193 result |= EEH_STATE_MMIO_ENABLED;
194 break;
195 case OPAL_EEH_STOPPED_MMIO_DMA_FREEZE:
196 result &= ~EEH_STATE_RESET_ACTIVE;
197 break;
198 case OPAL_EEH_STOPPED_RESET:
199 result |= EEH_STATE_RESET_ACTIVE;
200 break;
201 case OPAL_EEH_STOPPED_TEMP_UNAVAIL:
202 result |= EEH_STATE_UNAVAILABLE;
203 break;
204 case OPAL_EEH_STOPPED_PERM_UNAVAIL:
205 result |= EEH_STATE_NOT_SUPPORT;
206 break;
207 default:
208 pr_warning("%s: Unexpected EEH status 0x%x "
209 "on PHB#%x-PE#%x\n",
210 __func__, fstate, hose->global_number, pe_no);
211 }
212
213 return result;
214}
215
119struct pnv_eeh_ops ioda_eeh_ops = { 216struct pnv_eeh_ops ioda_eeh_ops = {
120 .post_init = ioda_eeh_post_init, 217 .post_init = ioda_eeh_post_init,
121 .set_option = ioda_eeh_set_option, 218 .set_option = ioda_eeh_set_option,
122 .get_state = NULL, 219 .get_state = ioda_eeh_get_state,
123 .reset = NULL, 220 .reset = NULL,
124 .get_log = NULL, 221 .get_log = NULL,
125 .configure_bridge = NULL, 222 .configure_bridge = NULL,