Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/powernv: Fetch frozen PE on top level

It should have been part of commit 1ad7a72c5 ("powerpc/eeh: Report
frozen parent PE prior to child PE"). There are 2 ways to report
EEH errors: proactively polling because of 0xFF's returned from
PCI config or IO read, or interrupt driven event. We missed to
report and handle parent frozen PE prior to child frozen PE for
the later case on PowerNV platform.

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

authored by

Gavin Shan and committed by
Michael Ellerman
372fb80d f2e0be5e

+34 -14
+34 -14
arch/powerpc/platforms/powernv/eeh-ioda.c
··· 886 886 * the master PE because slave PE is invisible 887 887 * to EEH core. 888 888 */ 889 - if (phb->get_pe_state) { 890 - pnv_pe = &phb->ioda.pe_array[pe_no]; 891 - if (pnv_pe->flags & PNV_IODA_PE_SLAVE) { 892 - pnv_pe = pnv_pe->master; 893 - WARN_ON(!pnv_pe || 894 - !(pnv_pe->flags & PNV_IODA_PE_MASTER)); 895 - pe_no = pnv_pe->pe_number; 896 - } 889 + pnv_pe = &phb->ioda.pe_array[pe_no]; 890 + if (pnv_pe->flags & PNV_IODA_PE_SLAVE) { 891 + pnv_pe = pnv_pe->master; 892 + WARN_ON(!pnv_pe || 893 + !(pnv_pe->flags & PNV_IODA_PE_MASTER)); 894 + pe_no = pnv_pe->pe_number; 897 895 } 898 896 899 897 /* Find the PE according to PE# */ ··· 902 904 if (!dev_pe) 903 905 return -EEXIST; 904 906 905 - /* 906 - * At this point, we're sure the compound PE should 907 - * be put into frozen state. 908 - */ 907 + /* Freeze the (compound) PE */ 909 908 *pe = dev_pe; 910 - if (phb->freeze_pe && 911 - !(dev_pe->state & EEH_PE_ISOLATED)) 909 + if (!(dev_pe->state & EEH_PE_ISOLATED)) 912 910 phb->freeze_pe(phb, pe_no); 911 + 912 + /* 913 + * At this point, we're sure the (compound) PE should 914 + * have been frozen. However, we still need poke until 915 + * hitting the frozen PE on top level. 916 + */ 917 + dev_pe = dev_pe->parent; 918 + while (dev_pe && !(dev_pe->type & EEH_PE_PHB)) { 919 + int ret; 920 + int active_flags = (EEH_STATE_MMIO_ACTIVE | 921 + EEH_STATE_DMA_ACTIVE); 922 + 923 + ret = eeh_ops->get_state(dev_pe, NULL); 924 + if (ret <= 0 || (ret & active_flags) == active_flags) { 925 + dev_pe = dev_pe->parent; 926 + continue; 927 + } 928 + 929 + /* Frozen parent PE */ 930 + *pe = dev_pe; 931 + if (!(dev_pe->state & EEH_PE_ISOLATED)) 932 + phb->freeze_pe(phb, dev_pe->addr); 933 + 934 + /* Next one */ 935 + dev_pe = dev_pe->parent; 936 + } 913 937 914 938 return 0; 915 939 }