To get away from using pci_dn we need a way to find the edev for a given
bdfn. The easiest way to do this is to find the ioda_pe for that BDFN in
the PHB's reverse mapping table and scan the device list of the
corresponding eeh_pe.

Is this slow? Yeah probably. Is it slower than the existing "traverse the
pdn tree" method? Probably not.

Signed-off-by: Oliver O'Halloran <ooh...@gmail.com>
---
 arch/powerpc/platforms/powernv/eeh-powernv.c | 31 ++++++++++++++++++++
 arch/powerpc/platforms/powernv/pci.h         |  2 ++
 2 files changed, 33 insertions(+)

diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c 
b/arch/powerpc/platforms/powernv/eeh-powernv.c
index f58fe6bda46e..a974822c5097 100644
--- a/arch/powerpc/platforms/powernv/eeh-powernv.c
+++ b/arch/powerpc/platforms/powernv/eeh-powernv.c
@@ -278,6 +278,37 @@ int pnv_eeh_post_init(void)
        return ret;
 }
 
+struct eeh_dev *pnv_eeh_find_edev(struct pnv_phb *phb, u16 bdfn)
+{
+       struct pnv_ioda_pe *ioda_pe;
+       struct eeh_dev *tmp, *edev;
+       struct eeh_pe *pe;
+
+       /* EEH not enabled ? */
+       if (!(phb->flags & PNV_PHB_FLAG_EEH))
+               return NULL;
+
+       /* Fish the EEH PE from the IODA PE */
+       ioda_pe = __pnv_ioda_get_pe(phb, bdfn);
+       if (!ioda_pe)
+               return NULL;
+
+       /*
+        * FIXME: Doing a tree-traversal followed by a list traversal
+        * on every config access is dumb. Not much dumber than the pci_dn
+        * tree traversal we did before, but still quite dumb.
+        */
+       pe = eeh_pe_get(phb->hose, ioda_pe->pe_number, 0);
+       if (!pe)
+               return NULL;
+
+       eeh_pe_for_each_dev(pe, edev, tmp)
+               if (edev->bdfn == bdfn)
+                       return edev;
+
+       return NULL;
+}
+
 static inline bool pnv_eeh_cfg_blocked(struct eeh_dev *edev)
 {
        if (!edev || !edev->pe)
diff --git a/arch/powerpc/platforms/powernv/pci.h 
b/arch/powerpc/platforms/powernv/pci.h
index 3c33a0c91a69..a343f3c8e65c 100644
--- a/arch/powerpc/platforms/powernv/pci.h
+++ b/arch/powerpc/platforms/powernv/pci.h
@@ -196,6 +196,8 @@ extern void pnv_set_msi_irq_chip(struct pnv_phb *phb, 
unsigned int virq);
 extern unsigned long pnv_pci_ioda2_get_table_size(__u32 page_shift,
                __u64 window_size, __u32 levels);
 extern int pnv_eeh_post_init(void);
+struct eeh_dev;
+struct eeh_dev *pnv_eeh_find_edev(struct pnv_phb *phb, u16 bdfn);
 
 __printf(3, 4)
 extern void pe_level_printk(const struct pnv_ioda_pe *pe, const char *level,
-- 
2.21.0

Reply via email to