diff options
author | Michael Ellerman <mpe@ellerman.id.au> | 2015-04-06 23:24:55 -0400 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2015-04-06 23:24:55 -0400 |
commit | 428d4d6520a0b8683fe9eac6df3077001e13d00b (patch) | |
tree | 8afa1af0babc8f2c375acc244aae969846dfe199 /arch/powerpc/platforms/pseries | |
parent | 28ea605caac49497e5e34a73ee4f4682fc035f1d (diff) | |
parent | 027fa02f84e851e21daffdf8900d6117071890f8 (diff) |
Merge branch 'next-eeh' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc into next
Diffstat (limited to 'arch/powerpc/platforms/pseries')
-rw-r--r-- | arch/powerpc/platforms/pseries/eeh_pseries.c | 98 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/msi.c | 6 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/pci_dlpar.c | 2 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/setup.c | 2 |
4 files changed, 41 insertions, 67 deletions
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c index a6c7e19f5eb3..2039397cc75d 100644 --- a/arch/powerpc/platforms/pseries/eeh_pseries.c +++ b/arch/powerpc/platforms/pseries/eeh_pseries.c | |||
@@ -118,9 +118,8 @@ static int pseries_eeh_init(void) | |||
118 | return 0; | 118 | return 0; |
119 | } | 119 | } |
120 | 120 | ||
121 | static int pseries_eeh_cap_start(struct device_node *dn) | 121 | static int pseries_eeh_cap_start(struct pci_dn *pdn) |
122 | { | 122 | { |
123 | struct pci_dn *pdn = PCI_DN(dn); | ||
124 | u32 status; | 123 | u32 status; |
125 | 124 | ||
126 | if (!pdn) | 125 | if (!pdn) |
@@ -134,10 +133,9 @@ static int pseries_eeh_cap_start(struct device_node *dn) | |||
134 | } | 133 | } |
135 | 134 | ||
136 | 135 | ||
137 | static int pseries_eeh_find_cap(struct device_node *dn, int cap) | 136 | static int pseries_eeh_find_cap(struct pci_dn *pdn, int cap) |
138 | { | 137 | { |
139 | struct pci_dn *pdn = PCI_DN(dn); | 138 | int pos = pseries_eeh_cap_start(pdn); |
140 | int pos = pseries_eeh_cap_start(dn); | ||
141 | int cnt = 48; /* Maximal number of capabilities */ | 139 | int cnt = 48; /* Maximal number of capabilities */ |
142 | u32 id; | 140 | u32 id; |
143 | 141 | ||
@@ -160,10 +158,9 @@ static int pseries_eeh_find_cap(struct device_node *dn, int cap) | |||
160 | return 0; | 158 | return 0; |
161 | } | 159 | } |
162 | 160 | ||
163 | static int pseries_eeh_find_ecap(struct device_node *dn, int cap) | 161 | static int pseries_eeh_find_ecap(struct pci_dn *pdn, int cap) |
164 | { | 162 | { |
165 | struct pci_dn *pdn = PCI_DN(dn); | 163 | struct eeh_dev *edev = pdn_to_eeh_dev(pdn); |
166 | struct eeh_dev *edev = of_node_to_eeh_dev(dn); | ||
167 | u32 header; | 164 | u32 header; |
168 | int pos = 256; | 165 | int pos = 256; |
169 | int ttl = (4096 - 256) / 8; | 166 | int ttl = (4096 - 256) / 8; |
@@ -191,53 +188,44 @@ static int pseries_eeh_find_ecap(struct device_node *dn, int cap) | |||
191 | } | 188 | } |
192 | 189 | ||
193 | /** | 190 | /** |
194 | * pseries_eeh_of_probe - EEH probe on the given device | 191 | * pseries_eeh_probe - EEH probe on the given device |
195 | * @dn: OF node | 192 | * @pdn: PCI device node |
196 | * @flag: Unused | 193 | * @data: Unused |
197 | * | 194 | * |
198 | * When EEH module is installed during system boot, all PCI devices | 195 | * When EEH module is installed during system boot, all PCI devices |
199 | * are checked one by one to see if it supports EEH. The function | 196 | * are checked one by one to see if it supports EEH. The function |
200 | * is introduced for the purpose. | 197 | * is introduced for the purpose. |
201 | */ | 198 | */ |
202 | static void *pseries_eeh_of_probe(struct device_node *dn, void *flag) | 199 | static void *pseries_eeh_probe(struct pci_dn *pdn, void *data) |
203 | { | 200 | { |
204 | struct eeh_dev *edev; | 201 | struct eeh_dev *edev; |
205 | struct eeh_pe pe; | 202 | struct eeh_pe pe; |
206 | struct pci_dn *pdn = PCI_DN(dn); | ||
207 | const __be32 *classp, *vendorp, *devicep; | ||
208 | u32 class_code; | ||
209 | const __be32 *regs; | ||
210 | u32 pcie_flags; | 203 | u32 pcie_flags; |
211 | int enable = 0; | 204 | int enable = 0; |
212 | int ret; | 205 | int ret; |
213 | 206 | ||
214 | /* Retrieve OF node and eeh device */ | 207 | /* Retrieve OF node and eeh device */ |
215 | edev = of_node_to_eeh_dev(dn); | 208 | edev = pdn_to_eeh_dev(pdn); |
216 | if (edev->pe || !of_device_is_available(dn)) | 209 | if (!edev || edev->pe) |
217 | return NULL; | 210 | return NULL; |
218 | 211 | ||
219 | /* Retrieve class/vendor/device IDs */ | 212 | /* Check class/vendor/device IDs */ |
220 | classp = of_get_property(dn, "class-code", NULL); | 213 | if (!pdn->vendor_id || !pdn->device_id || !pdn->class_code) |
221 | vendorp = of_get_property(dn, "vendor-id", NULL); | ||
222 | devicep = of_get_property(dn, "device-id", NULL); | ||
223 | |||
224 | /* Skip for bad OF node or PCI-ISA bridge */ | ||
225 | if (!classp || !vendorp || !devicep) | ||
226 | return NULL; | ||
227 | if (dn->type && !strcmp(dn->type, "isa")) | ||
228 | return NULL; | 214 | return NULL; |
229 | 215 | ||
230 | class_code = of_read_number(classp, 1); | 216 | /* Skip for PCI-ISA bridge */ |
217 | if ((pdn->class_code >> 8) == PCI_CLASS_BRIDGE_ISA) | ||
218 | return NULL; | ||
231 | 219 | ||
232 | /* | 220 | /* |
233 | * Update class code and mode of eeh device. We need | 221 | * Update class code and mode of eeh device. We need |
234 | * correctly reflects that current device is root port | 222 | * correctly reflects that current device is root port |
235 | * or PCIe switch downstream port. | 223 | * or PCIe switch downstream port. |
236 | */ | 224 | */ |
237 | edev->class_code = class_code; | 225 | edev->class_code = pdn->class_code; |
238 | edev->pcix_cap = pseries_eeh_find_cap(dn, PCI_CAP_ID_PCIX); | 226 | edev->pcix_cap = pseries_eeh_find_cap(pdn, PCI_CAP_ID_PCIX); |
239 | edev->pcie_cap = pseries_eeh_find_cap(dn, PCI_CAP_ID_EXP); | 227 | edev->pcie_cap = pseries_eeh_find_cap(pdn, PCI_CAP_ID_EXP); |
240 | edev->aer_cap = pseries_eeh_find_ecap(dn, PCI_EXT_CAP_ID_ERR); | 228 | edev->aer_cap = pseries_eeh_find_ecap(pdn, PCI_EXT_CAP_ID_ERR); |
241 | edev->mode &= 0xFFFFFF00; | 229 | edev->mode &= 0xFFFFFF00; |
242 | if ((edev->class_code >> 8) == PCI_CLASS_BRIDGE_PCI) { | 230 | if ((edev->class_code >> 8) == PCI_CLASS_BRIDGE_PCI) { |
243 | edev->mode |= EEH_DEV_BRIDGE; | 231 | edev->mode |= EEH_DEV_BRIDGE; |
@@ -252,24 +240,16 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag) | |||
252 | } | 240 | } |
253 | } | 241 | } |
254 | 242 | ||
255 | /* Retrieve the device address */ | ||
256 | regs = of_get_property(dn, "reg", NULL); | ||
257 | if (!regs) { | ||
258 | pr_warn("%s: OF node property %s::reg not found\n", | ||
259 | __func__, dn->full_name); | ||
260 | return NULL; | ||
261 | } | ||
262 | |||
263 | /* Initialize the fake PE */ | 243 | /* Initialize the fake PE */ |
264 | memset(&pe, 0, sizeof(struct eeh_pe)); | 244 | memset(&pe, 0, sizeof(struct eeh_pe)); |
265 | pe.phb = edev->phb; | 245 | pe.phb = edev->phb; |
266 | pe.config_addr = of_read_number(regs, 1); | 246 | pe.config_addr = (pdn->busno << 16) | (pdn->devfn << 8); |
267 | 247 | ||
268 | /* Enable EEH on the device */ | 248 | /* Enable EEH on the device */ |
269 | ret = eeh_ops->set_option(&pe, EEH_OPT_ENABLE); | 249 | ret = eeh_ops->set_option(&pe, EEH_OPT_ENABLE); |
270 | if (!ret) { | 250 | if (!ret) { |
271 | edev->config_addr = of_read_number(regs, 1); | ||
272 | /* Retrieve PE address */ | 251 | /* Retrieve PE address */ |
252 | edev->config_addr = (pdn->busno << 16) | (pdn->devfn << 8); | ||
273 | edev->pe_config_addr = eeh_ops->get_pe_addr(&pe); | 253 | edev->pe_config_addr = eeh_ops->get_pe_addr(&pe); |
274 | pe.addr = edev->pe_config_addr; | 254 | pe.addr = edev->pe_config_addr; |
275 | 255 | ||
@@ -285,16 +265,17 @@ static void *pseries_eeh_of_probe(struct device_node *dn, void *flag) | |||
285 | eeh_add_flag(EEH_ENABLED); | 265 | eeh_add_flag(EEH_ENABLED); |
286 | eeh_add_to_parent_pe(edev); | 266 | eeh_add_to_parent_pe(edev); |
287 | 267 | ||
288 | pr_debug("%s: EEH enabled on %s PHB#%d-PE#%x, config addr#%x\n", | 268 | pr_debug("%s: EEH enabled on %02x:%02x.%01x PHB#%d-PE#%x\n", |
289 | __func__, dn->full_name, pe.phb->global_number, | 269 | __func__, pdn->busno, PCI_SLOT(pdn->devfn), |
290 | pe.addr, pe.config_addr); | 270 | PCI_FUNC(pdn->devfn), pe.phb->global_number, |
291 | } else if (dn->parent && of_node_to_eeh_dev(dn->parent) && | 271 | pe.addr); |
292 | (of_node_to_eeh_dev(dn->parent))->pe) { | 272 | } else if (pdn->parent && pdn_to_eeh_dev(pdn->parent) && |
273 | (pdn_to_eeh_dev(pdn->parent))->pe) { | ||
293 | /* This device doesn't support EEH, but it may have an | 274 | /* This device doesn't support EEH, but it may have an |
294 | * EEH parent, in which case we mark it as supported. | 275 | * EEH parent, in which case we mark it as supported. |
295 | */ | 276 | */ |
296 | edev->config_addr = of_node_to_eeh_dev(dn->parent)->config_addr; | 277 | edev->config_addr = pdn_to_eeh_dev(pdn->parent)->config_addr; |
297 | edev->pe_config_addr = of_node_to_eeh_dev(dn->parent)->pe_config_addr; | 278 | edev->pe_config_addr = pdn_to_eeh_dev(pdn->parent)->pe_config_addr; |
298 | eeh_add_to_parent_pe(edev); | 279 | eeh_add_to_parent_pe(edev); |
299 | } | 280 | } |
300 | } | 281 | } |
@@ -670,45 +651,36 @@ static int pseries_eeh_configure_bridge(struct eeh_pe *pe) | |||
670 | 651 | ||
671 | /** | 652 | /** |
672 | * pseries_eeh_read_config - Read PCI config space | 653 | * pseries_eeh_read_config - Read PCI config space |
673 | * @dn: device node | 654 | * @pdn: PCI device node |
674 | * @where: PCI address | 655 | * @where: PCI address |
675 | * @size: size to read | 656 | * @size: size to read |
676 | * @val: return value | 657 | * @val: return value |
677 | * | 658 | * |
678 | * Read config space from the speicifed device | 659 | * Read config space from the speicifed device |
679 | */ | 660 | */ |
680 | static int pseries_eeh_read_config(struct device_node *dn, int where, int size, u32 *val) | 661 | static int pseries_eeh_read_config(struct pci_dn *pdn, int where, int size, u32 *val) |
681 | { | 662 | { |
682 | struct pci_dn *pdn; | ||
683 | |||
684 | pdn = PCI_DN(dn); | ||
685 | |||
686 | return rtas_read_config(pdn, where, size, val); | 663 | return rtas_read_config(pdn, where, size, val); |
687 | } | 664 | } |
688 | 665 | ||
689 | /** | 666 | /** |
690 | * pseries_eeh_write_config - Write PCI config space | 667 | * pseries_eeh_write_config - Write PCI config space |
691 | * @dn: device node | 668 | * @pdn: PCI device node |
692 | * @where: PCI address | 669 | * @where: PCI address |
693 | * @size: size to write | 670 | * @size: size to write |
694 | * @val: value to be written | 671 | * @val: value to be written |
695 | * | 672 | * |
696 | * Write config space to the specified device | 673 | * Write config space to the specified device |
697 | */ | 674 | */ |
698 | static int pseries_eeh_write_config(struct device_node *dn, int where, int size, u32 val) | 675 | static int pseries_eeh_write_config(struct pci_dn *pdn, int where, int size, u32 val) |
699 | { | 676 | { |
700 | struct pci_dn *pdn; | ||
701 | |||
702 | pdn = PCI_DN(dn); | ||
703 | |||
704 | return rtas_write_config(pdn, where, size, val); | 677 | return rtas_write_config(pdn, where, size, val); |
705 | } | 678 | } |
706 | 679 | ||
707 | static struct eeh_ops pseries_eeh_ops = { | 680 | static struct eeh_ops pseries_eeh_ops = { |
708 | .name = "pseries", | 681 | .name = "pseries", |
709 | .init = pseries_eeh_init, | 682 | .init = pseries_eeh_init, |
710 | .of_probe = pseries_eeh_of_probe, | 683 | .probe = pseries_eeh_probe, |
711 | .dev_probe = NULL, | ||
712 | .set_option = pseries_eeh_set_option, | 684 | .set_option = pseries_eeh_set_option, |
713 | .get_pe_addr = pseries_eeh_get_pe_addr, | 685 | .get_pe_addr = pseries_eeh_get_pe_addr, |
714 | .get_state = pseries_eeh_get_state, | 686 | .get_state = pseries_eeh_get_state, |
diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index 691a154c286d..c8d24f9a6948 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c | |||
@@ -195,6 +195,7 @@ static struct device_node *find_pe_total_msi(struct pci_dev *dev, int *total) | |||
195 | static struct device_node *find_pe_dn(struct pci_dev *dev, int *total) | 195 | static struct device_node *find_pe_dn(struct pci_dev *dev, int *total) |
196 | { | 196 | { |
197 | struct device_node *dn; | 197 | struct device_node *dn; |
198 | struct pci_dn *pdn; | ||
198 | struct eeh_dev *edev; | 199 | struct eeh_dev *edev; |
199 | 200 | ||
200 | /* Found our PE and assume 8 at that point. */ | 201 | /* Found our PE and assume 8 at that point. */ |
@@ -204,10 +205,11 @@ static struct device_node *find_pe_dn(struct pci_dev *dev, int *total) | |||
204 | return NULL; | 205 | return NULL; |
205 | 206 | ||
206 | /* Get the top level device in the PE */ | 207 | /* Get the top level device in the PE */ |
207 | edev = of_node_to_eeh_dev(dn); | 208 | edev = pdn_to_eeh_dev(PCI_DN(dn)); |
208 | if (edev->pe) | 209 | if (edev->pe) |
209 | edev = list_first_entry(&edev->pe->edevs, struct eeh_dev, list); | 210 | edev = list_first_entry(&edev->pe->edevs, struct eeh_dev, list); |
210 | dn = eeh_dev_to_of_node(edev); | 211 | pdn = eeh_dev_to_pdn(edev); |
212 | dn = pdn ? pdn->node : NULL; | ||
211 | if (!dn) | 213 | if (!dn) |
212 | return NULL; | 214 | return NULL; |
213 | 215 | ||
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index 89e23811199c..f735f4fee48c 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c | |||
@@ -82,7 +82,7 @@ struct pci_controller *init_phb_dynamic(struct device_node *dn) | |||
82 | eeh_dev_phb_init_dynamic(phb); | 82 | eeh_dev_phb_init_dynamic(phb); |
83 | 83 | ||
84 | if (dn->child) | 84 | if (dn->child) |
85 | eeh_add_device_tree_early(dn); | 85 | eeh_add_device_tree_early(PCI_DN(dn)); |
86 | 86 | ||
87 | pcibios_scan_phb(phb); | 87 | pcibios_scan_phb(phb); |
88 | pcibios_finish_adding_to_bus(phb->bus); | 88 | pcibios_finish_adding_to_bus(phb->bus); |
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index e445b6701f50..70304070a260 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c | |||
@@ -265,7 +265,7 @@ static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long act | |||
265 | update_dn_pci_info(np, pci->phb); | 265 | update_dn_pci_info(np, pci->phb); |
266 | 266 | ||
267 | /* Create EEH device for the OF node */ | 267 | /* Create EEH device for the OF node */ |
268 | eeh_dev_init(np, pci->phb); | 268 | eeh_dev_init(PCI_DN(np), pci->phb); |
269 | } | 269 | } |
270 | break; | 270 | break; |
271 | default: | 271 | default: |