aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms
diff options
context:
space:
mode:
authorGavin Shan <shangw@linux.vnet.ibm.com>2012-09-07 18:44:21 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-09-09 19:35:44 -0400
commitd7bb88629dd64242fbbd7dd34ecad073afdbafad (patch)
treeb1411f72e6657e2ff31a8fbfae799dc3f78b86bc /arch/powerpc/platforms
parentdbbceee12f2160ef1ac848316212f97bf5bc4c16 (diff)
powerpc/eeh: Probe mode support
While EEH module is installed, PCI devices is checked one by one to see if it supports eeh. On different platforms, the PCI devices are referred through different ways when the EEH module is loaded. For example, on pSeries platform, that is done by OF node. However, we would do that by real PCI devices (struct pci_dev) on PowerNV platform in future. So we needs some mechanism to differentiate those cases by classifying them to probe modes, either from OF nodes or real PCI devices. The patch implements the support to eeh probe mode. Also, the EEH on pSeries has set it into EEH_PROBE_MODE_DEVTREE. That means the probe will be done based on OF nodes on pSeries platform. In addition, On pSeries platform, it's done by OF nodes. The patch moves the the probe function from EEH core to platform dependent backend and some cleanup applied. Signed-off-by: Gavin Shan <shangw@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c131
-rw-r--r--arch/powerpc/platforms/pseries/eeh_pseries.c96
2 files changed, 118 insertions, 109 deletions
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 6d4323025793..4bdc278c2fd7 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -92,6 +92,17 @@ struct eeh_ops *eeh_ops = NULL;
92int eeh_subsystem_enabled; 92int eeh_subsystem_enabled;
93EXPORT_SYMBOL(eeh_subsystem_enabled); 93EXPORT_SYMBOL(eeh_subsystem_enabled);
94 94
95/*
96 * EEH probe mode support. The intention is to support multiple
97 * platforms for EEH. Some platforms like pSeries do PCI emunation
98 * based on device tree. However, other platforms like powernv probe
99 * PCI devices from hardware. The flag is used to distinguish that.
100 * In addition, struct eeh_ops::probe would be invoked for particular
101 * OF node or PCI device so that the corresponding PE would be created
102 * there.
103 */
104int eeh_probe_mode;
105
95/* Global EEH mutex */ 106/* Global EEH mutex */
96DEFINE_MUTEX(eeh_mutex); 107DEFINE_MUTEX(eeh_mutex);
97 108
@@ -590,7 +601,7 @@ int eeh_reset_pe(struct eeh_pe *pe)
590 * PCI devices are added individually; but, for the restore, 601 * PCI devices are added individually; but, for the restore,
591 * an entire slot is reset at a time. 602 * an entire slot is reset at a time.
592 */ 603 */
593static void eeh_save_bars(struct eeh_dev *edev) 604void eeh_save_bars(struct eeh_dev *edev)
594{ 605{
595 int i; 606 int i;
596 struct device_node *dn; 607 struct device_node *dn;
@@ -604,108 +615,6 @@ static void eeh_save_bars(struct eeh_dev *edev)
604} 615}
605 616
606/** 617/**
607 * eeh_early_enable - Early enable EEH on the indicated device
608 * @dn: device node
609 * @data: BUID
610 *
611 * Enable EEH functionality on the specified PCI device. The function
612 * is expected to be called before real PCI probing is done. However,
613 * the PHBs have been initialized at this point.
614 */
615static void *eeh_early_enable(struct device_node *dn, void *data)
616{
617 int ret;
618 const u32 *class_code = of_get_property(dn, "class-code", NULL);
619 const u32 *vendor_id = of_get_property(dn, "vendor-id", NULL);
620 const u32 *device_id = of_get_property(dn, "device-id", NULL);
621 const u32 *regs;
622 int enable;
623 struct eeh_dev *edev = of_node_to_eeh_dev(dn);
624 struct eeh_pe pe;
625
626 edev->class_code = 0;
627 edev->mode = 0;
628
629 if (!of_device_is_available(dn))
630 return NULL;
631
632 /* Ignore bad nodes. */
633 if (!class_code || !vendor_id || !device_id)
634 return NULL;
635
636 /* There is nothing to check on PCI to ISA bridges */
637 if (dn->type && !strcmp(dn->type, "isa"))
638 return NULL;
639 edev->class_code = *class_code;
640
641 /* Ok... see if this device supports EEH. Some do, some don't,
642 * and the only way to find out is to check each and every one.
643 */
644 regs = of_get_property(dn, "reg", NULL);
645 if (regs) {
646 /* Initialize the fake PE */
647 memset(&pe, 0, sizeof(struct eeh_pe));
648 pe.phb = edev->phb;
649 pe.config_addr = regs[0];
650
651 /* First register entry is addr (00BBSS00) */
652 /* Try to enable eeh */
653 ret = eeh_ops->set_option(&pe, EEH_OPT_ENABLE);
654
655 enable = 0;
656 if (ret == 0) {
657 edev->config_addr = regs[0];
658
659 /* If the newer, better, ibm,get-config-addr-info is supported,
660 * then use that instead.
661 */
662 edev->pe_config_addr = eeh_ops->get_pe_addr(&pe);
663 pe.addr = edev->pe_config_addr;
664
665 /* Some older systems (Power4) allow the
666 * ibm,set-eeh-option call to succeed even on nodes
667 * where EEH is not supported. Verify support
668 * explicitly.
669 */
670 ret = eeh_ops->get_state(&pe, NULL);
671 if (ret > 0 && ret != EEH_STATE_NOT_SUPPORT)
672 enable = 1;
673 }
674
675 if (enable) {
676 eeh_subsystem_enabled = 1;
677
678 eeh_add_to_parent_pe(edev);
679
680 pr_debug("EEH: %s: eeh enabled, config=%x pe_config=%x\n",
681 dn->full_name, edev->config_addr,
682 edev->pe_config_addr);
683 } else {
684
685 /* This device doesn't support EEH, but it may have an
686 * EEH parent, in which case we mark it as supported.
687 */
688 if (dn->parent && of_node_to_eeh_dev(dn->parent) &&
689 of_node_to_eeh_dev(dn->parent)->pe) {
690 /* Parent supports EEH. */
691 edev->config_addr = of_node_to_eeh_dev(dn->parent)->config_addr;
692 edev->pe_config_addr = of_node_to_eeh_dev(dn->parent)->pe_config_addr;
693
694 eeh_add_to_parent_pe(edev);
695
696 return NULL;
697 }
698 }
699 } else {
700 printk(KERN_WARNING "EEH: %s: unable to get reg property.\n",
701 dn->full_name);
702 }
703
704 eeh_save_bars(edev);
705 return NULL;
706}
707
708/**
709 * eeh_ops_register - Register platform dependent EEH operations 618 * eeh_ops_register - Register platform dependent EEH operations
710 * @ops: platform dependent EEH operations 619 * @ops: platform dependent EEH operations
711 * 620 *
@@ -790,15 +699,18 @@ static int __init eeh_init(void)
790 raw_spin_lock_init(&confirm_error_lock); 699 raw_spin_lock_init(&confirm_error_lock);
791 700
792 /* Enable EEH for all adapters */ 701 /* Enable EEH for all adapters */
793 list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { 702 if (eeh_probe_mode_devtree()) {
794 phb = hose->dn; 703 list_for_each_entry_safe(hose, tmp,
795 traverse_pci_devices(phb, eeh_early_enable, NULL); 704 &hose_list, list_node) {
705 phb = hose->dn;
706 traverse_pci_devices(phb, eeh_ops->of_probe, NULL);
707 }
796 } 708 }
797 709
798 if (eeh_subsystem_enabled) 710 if (eeh_subsystem_enabled)
799 printk(KERN_INFO "EEH: PCI Enhanced I/O Error Handling Enabled\n"); 711 pr_info("EEH: PCI Enhanced I/O Error Handling Enabled\n");
800 else 712 else
801 printk(KERN_WARNING "EEH: No capable adapters found\n"); 713 pr_warning("EEH: No capable adapters found\n");
802 714
803 return ret; 715 return ret;
804} 716}
@@ -829,7 +741,8 @@ static void eeh_add_device_early(struct device_node *dn)
829 if (NULL == phb || 0 == phb->buid) 741 if (NULL == phb || 0 == phb->buid)
830 return; 742 return;
831 743
832 eeh_early_enable(dn, NULL); 744 /* FIXME: hotplug support on POWERNV */
745 eeh_ops->of_probe(dn, NULL);
833} 746}
834 747
835/** 748/**
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
index fdeef772d714..19506f935737 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -129,10 +129,104 @@ static int pseries_eeh_init(void)
129 eeh_error_buf_size = RTAS_ERROR_LOG_MAX; 129 eeh_error_buf_size = RTAS_ERROR_LOG_MAX;
130 } 130 }
131 131
132 /* Set EEH probe mode */
133 eeh_probe_mode_set(EEH_PROBE_MODE_DEVTREE);
134
132 return 0; 135 return 0;
133} 136}
134 137
135/** 138/**
139 * pseries_eeh_of_probe - EEH probe on the given device
140 * @dn: OF node
141 * @flag: Unused
142 *
143 * When EEH module is installed during system boot, all PCI devices
144 * are checked one by one to see if it supports EEH. The function
145 * is introduced for the purpose.
146 */
147static void *pseries_eeh_of_probe(struct device_node *dn, void *flag)
148{
149 struct eeh_dev *edev;
150 struct eeh_pe pe;
151 const u32 *class_code, *vendor_id, *device_id;
152 const u32 *regs;
153 int enable = 0;
154 int ret;
155
156 /* Retrieve OF node and eeh device */
157 edev = of_node_to_eeh_dev(dn);
158 if (!of_device_is_available(dn))
159 return NULL;
160
161 /* Retrieve class/vendor/device IDs */
162 class_code = of_get_property(dn, "class-code", NULL);
163 vendor_id = of_get_property(dn, "vendor-id", NULL);
164 device_id = of_get_property(dn, "device-id", NULL);
165
166 /* Skip for bad OF node or PCI-ISA bridge */
167 if (!class_code || !vendor_id || !device_id)
168 return NULL;
169 if (dn->type && !strcmp(dn->type, "isa"))
170 return NULL;
171
172 /* Update class code and mode of eeh device */
173 edev->class_code = *class_code;
174 edev->mode = 0;
175
176 /* Retrieve the device address */
177 regs = of_get_property(dn, "reg", NULL);
178 if (!regs) {
179 pr_warning("%s: OF node property %s::reg not found\n",
180 __func__, dn->full_name);
181 return NULL;
182 }
183
184 /* Initialize the fake PE */
185 memset(&pe, 0, sizeof(struct eeh_pe));
186 pe.phb = edev->phb;
187 pe.config_addr = regs[0];
188
189 /* Enable EEH on the device */
190 ret = eeh_ops->set_option(&pe, EEH_OPT_ENABLE);
191 if (!ret) {
192 edev->config_addr = regs[0];
193 /* Retrieve PE address */
194 edev->pe_config_addr = eeh_ops->get_pe_addr(&pe);
195 pe.addr = edev->pe_config_addr;
196
197 /* Some older systems (Power4) allow the ibm,set-eeh-option
198 * call to succeed even on nodes where EEH is not supported.
199 * Verify support explicitly.
200 */
201 ret = eeh_ops->get_state(&pe, NULL);
202 if (ret > 0 && ret != EEH_STATE_NOT_SUPPORT)
203 enable = 1;
204
205 if (enable) {
206 eeh_subsystem_enabled = 1;
207 eeh_add_to_parent_pe(edev);
208
209 pr_debug("%s: EEH enabled on %s PHB#%d-PE#%x, config addr#%x\n",
210 __func__, dn->full_name, pe.phb->global_number,
211 pe.addr, pe.config_addr);
212 } else if (dn->parent && of_node_to_eeh_dev(dn->parent) &&
213 (of_node_to_eeh_dev(dn->parent))->pe) {
214 /* This device doesn't support EEH, but it may have an
215 * EEH parent, in which case we mark it as supported.
216 */
217 edev->config_addr = of_node_to_eeh_dev(dn->parent)->config_addr;
218 edev->pe_config_addr = of_node_to_eeh_dev(dn->parent)->pe_config_addr;
219 eeh_add_to_parent_pe(edev);
220 }
221 }
222
223 /* Save memory bars */
224 eeh_save_bars(edev);
225
226 return NULL;
227}
228
229/**
136 * pseries_eeh_set_option - Initialize EEH or MMIO/DMA reenable 230 * pseries_eeh_set_option - Initialize EEH or MMIO/DMA reenable
137 * @pe: EEH PE 231 * @pe: EEH PE
138 * @option: operation to be issued 232 * @option: operation to be issued
@@ -523,6 +617,8 @@ static int pseries_eeh_write_config(struct device_node *dn, int where, int size,
523static struct eeh_ops pseries_eeh_ops = { 617static struct eeh_ops pseries_eeh_ops = {
524 .name = "pseries", 618 .name = "pseries",
525 .init = pseries_eeh_init, 619 .init = pseries_eeh_init,
620 .of_probe = pseries_eeh_of_probe,
621 .dev_probe = NULL,
526 .set_option = pseries_eeh_set_option, 622 .set_option = pseries_eeh_set_option,
527 .get_pe_addr = pseries_eeh_get_pe_addr, 623 .get_pe_addr = pseries_eeh_get_pe_addr,
528 .get_state = pseries_eeh_get_state, 624 .get_state = pseries_eeh_get_state,