On Wed, Jan 5, 2022 at 9:03 AM Pali Rohár <pali@xxxxxxxxxx> wrote: > > Split struct pci_ops between ops and child_ops. Member ops is used for > accessing PCIe Root Ports via pci-bridge-emul.c driver and child_ops for > accessing real PCIe cards. > > There is no need to mix these two struct pci_ops into one as PCI core code > already provides separate callbacks via bridge->ops and bridge->child_ops. I had similar patches including mvebu that I never got around to sending out. I pushed the branch out now at least[1]. > Signed-off-by: Pali Rohár <pali@xxxxxxxxxx> > --- > drivers/pci/controller/pci-mvebu.c | 82 ++++++++++++++++-------------- > 1 file changed, 44 insertions(+), 38 deletions(-) > > diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c > index 9ea2f6a7c2b0..1e90ab888075 100644 > --- a/drivers/pci/controller/pci-mvebu.c > +++ b/drivers/pci/controller/pci-mvebu.c > @@ -294,11 +294,29 @@ static void mvebu_pcie_setup_hw(struct mvebu_pcie_port *port) > mvebu_writel(port, mask, PCIE_MASK_OFF); > } > > -static int mvebu_pcie_hw_rd_conf(struct mvebu_pcie_port *port, > - struct pci_bus *bus, > - u32 devfn, int where, int size, u32 *val) > +static struct mvebu_pcie_port *mvebu_pcie_find_port(struct mvebu_pcie *pcie, > + struct pci_bus *bus, > + int devfn); > + > +static int mvebu_pcie_child_rd_conf(struct pci_bus *bus, u32 devfn, int where, > + int size, u32 *val) > { > - void __iomem *conf_data = port->base + PCIE_CONF_DATA_OFF; > + struct mvebu_pcie *pcie = bus->sysdata; > + struct mvebu_pcie_port *port; > + void __iomem *conf_data; > + > + port = mvebu_pcie_find_port(pcie, bus, devfn); > + if (!port) { > + *val = 0xffffffff; > + return PCIBIOS_DEVICE_NOT_FOUND; > + } > + > + if (!mvebu_pcie_link_up(port)) { > + *val = 0xffffffff; > + return PCIBIOS_DEVICE_NOT_FOUND; > + } > + > + conf_data = port->base + PCIE_CONF_DATA_OFF; > > mvebu_writel(port, PCIE_CONF_ADDR(bus->number, devfn, where), > PCIE_CONF_ADDR_OFF); > @@ -321,11 +339,21 @@ static int mvebu_pcie_hw_rd_conf(struct mvebu_pcie_port *port, > return PCIBIOS_SUCCESSFUL; > } > > -static int mvebu_pcie_hw_wr_conf(struct mvebu_pcie_port *port, > - struct pci_bus *bus, > - u32 devfn, int where, int size, u32 val) > +static int mvebu_pcie_child_wr_conf(struct pci_bus *bus, u32 devfn, > + int where, int size, u32 val) > { > - void __iomem *conf_data = port->base + PCIE_CONF_DATA_OFF; > + struct mvebu_pcie *pcie = bus->sysdata; > + struct mvebu_pcie_port *port; > + void __iomem *conf_data; > + > + port = mvebu_pcie_find_port(pcie, bus, devfn); > + if (!port) > + return PCIBIOS_DEVICE_NOT_FOUND; > + > + if (!mvebu_pcie_link_up(port)) > + return PCIBIOS_DEVICE_NOT_FOUND; > + > + conf_data = port->base + PCIE_CONF_DATA_OFF; The same code in read and write is a hint to use .map_bus(). > > mvebu_writel(port, PCIE_CONF_ADDR(bus->number, devfn, where), > PCIE_CONF_ADDR_OFF); > @@ -347,6 +375,11 @@ static int mvebu_pcie_hw_wr_conf(struct mvebu_pcie_port *port, > return PCIBIOS_SUCCESSFUL; > } > > +static struct pci_ops mvebu_pcie_child_ops = { > + .read = mvebu_pcie_child_rd_conf, > + .write = mvebu_pcie_child_wr_conf, > +}; > + > /* > * Remove windows, starting from the largest ones to the smallest > * ones. > @@ -862,25 +895,12 @@ static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn, > { > struct mvebu_pcie *pcie = bus->sysdata; > struct mvebu_pcie_port *port; > - int ret; > > port = mvebu_pcie_find_port(pcie, bus, devfn); > if (!port) > return PCIBIOS_DEVICE_NOT_FOUND; It would be nice to go from 'bus' to 'bridge' ptr directly, but I still had this in my version. I guess a standard RP struct as part of decoupling host bridges from RPs would solve this issue. Rob [1] https://git.kernel.org/pub/scm/linux/kernel/git/robh/linux.git/log/?h=pci-child-bus-ops