mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-28 15:20:41 +00:00
Merge branch 'remotes/lorenzo/pci/mvebu'
- Fix mvebu I/O space remapping issues (Thomas Petazzoni) - Use generic pci_host_bridge in mvebu instead of ARM-specific API (Thomas Petazzoni) * remotes/lorenzo/pci/mvebu: PCI: mvebu: Drop bogus comment above mvebu_pcie_map_registers() PCI: mvebu: Convert to use pci_host_bridge directly PCI: mvebu: Use resource_size() to remap I/O space PCI: mvebu: Only remap I/O space if configured PCI: mvebu: Fix I/O space end address calculation PCI: mvebu: Remove redundant platform_set_drvdata() call
This commit is contained in:
commit
323fc7509a
1 changed files with 76 additions and 93 deletions
|
@ -125,6 +125,7 @@ struct mvebu_pcie {
|
||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
struct mvebu_pcie_port *ports;
|
struct mvebu_pcie_port *ports;
|
||||||
struct msi_controller *msi;
|
struct msi_controller *msi;
|
||||||
|
struct list_head resources;
|
||||||
struct resource io;
|
struct resource io;
|
||||||
struct resource realio;
|
struct resource realio;
|
||||||
struct resource mem;
|
struct resource mem;
|
||||||
|
@ -800,7 +801,7 @@ static struct mvebu_pcie_port *mvebu_pcie_find_port(struct mvebu_pcie *pcie,
|
||||||
static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
|
static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
|
||||||
int where, int size, u32 val)
|
int where, int size, u32 val)
|
||||||
{
|
{
|
||||||
struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata);
|
struct mvebu_pcie *pcie = bus->sysdata;
|
||||||
struct mvebu_pcie_port *port;
|
struct mvebu_pcie_port *port;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -826,7 +827,7 @@ static int mvebu_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
|
||||||
static int mvebu_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
|
static int mvebu_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
|
||||||
int size, u32 *val)
|
int size, u32 *val)
|
||||||
{
|
{
|
||||||
struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata);
|
struct mvebu_pcie *pcie = bus->sysdata;
|
||||||
struct mvebu_pcie_port *port;
|
struct mvebu_pcie_port *port;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -857,36 +858,6 @@ static struct pci_ops mvebu_pcie_ops = {
|
||||||
.write = mvebu_pcie_wr_conf,
|
.write = mvebu_pcie_wr_conf,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys)
|
|
||||||
{
|
|
||||||
struct mvebu_pcie *pcie = sys_to_pcie(sys);
|
|
||||||
int err, i;
|
|
||||||
|
|
||||||
pcie->mem.name = "PCI MEM";
|
|
||||||
pcie->realio.name = "PCI I/O";
|
|
||||||
|
|
||||||
if (resource_size(&pcie->realio) != 0)
|
|
||||||
pci_add_resource_offset(&sys->resources, &pcie->realio,
|
|
||||||
sys->io_offset);
|
|
||||||
|
|
||||||
pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
|
|
||||||
pci_add_resource(&sys->resources, &pcie->busn);
|
|
||||||
|
|
||||||
err = devm_request_pci_bus_resources(&pcie->pdev->dev, &sys->resources);
|
|
||||||
if (err)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for (i = 0; i < pcie->nports; i++) {
|
|
||||||
struct mvebu_pcie_port *port = &pcie->ports[i];
|
|
||||||
|
|
||||||
if (!port->base)
|
|
||||||
continue;
|
|
||||||
mvebu_pcie_setup_hw(port);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev,
|
static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev,
|
||||||
const struct resource *res,
|
const struct resource *res,
|
||||||
resource_size_t start,
|
resource_size_t start,
|
||||||
|
@ -917,31 +888,6 @@ static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev,
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mvebu_pcie_enable(struct mvebu_pcie *pcie)
|
|
||||||
{
|
|
||||||
struct hw_pci hw;
|
|
||||||
|
|
||||||
memset(&hw, 0, sizeof(hw));
|
|
||||||
|
|
||||||
#ifdef CONFIG_PCI_MSI
|
|
||||||
hw.msi_ctrl = pcie->msi;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
hw.nr_controllers = 1;
|
|
||||||
hw.private_data = (void **)&pcie;
|
|
||||||
hw.setup = mvebu_pcie_setup;
|
|
||||||
hw.map_irq = of_irq_parse_and_map_pci;
|
|
||||||
hw.ops = &mvebu_pcie_ops;
|
|
||||||
hw.align_resource = mvebu_pcie_align_resource;
|
|
||||||
|
|
||||||
pci_common_init_dev(&pcie->pdev->dev, &hw);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Looks up the list of register addresses encoded into the reg =
|
|
||||||
* <...> property for one that matches the given port/lane. Once
|
|
||||||
* found, maps it.
|
|
||||||
*/
|
|
||||||
static void __iomem *mvebu_pcie_map_registers(struct platform_device *pdev,
|
static void __iomem *mvebu_pcie_map_registers(struct platform_device *pdev,
|
||||||
struct device_node *np,
|
struct device_node *np,
|
||||||
struct mvebu_pcie_port *port)
|
struct mvebu_pcie_port *port)
|
||||||
|
@ -1190,38 +1136,19 @@ static void mvebu_pcie_powerdown(struct mvebu_pcie_port *port)
|
||||||
clk_disable_unprepare(port->clk);
|
clk_disable_unprepare(port->clk);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mvebu_pcie_probe(struct platform_device *pdev)
|
/*
|
||||||
|
* We can't use devm_of_pci_get_host_bridge_resources() because we
|
||||||
|
* need to parse our special DT properties encoding the MEM and IO
|
||||||
|
* apertures.
|
||||||
|
*/
|
||||||
|
static int mvebu_pcie_parse_request_resources(struct mvebu_pcie *pcie)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pcie->pdev->dev;
|
||||||
struct mvebu_pcie *pcie;
|
|
||||||
struct device_node *np = dev->of_node;
|
struct device_node *np = dev->of_node;
|
||||||
struct device_node *child;
|
unsigned int i;
|
||||||
int num, i, ret;
|
int ret;
|
||||||
|
|
||||||
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
|
INIT_LIST_HEAD(&pcie->resources);
|
||||||
if (!pcie)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
pcie->pdev = pdev;
|
|
||||||
platform_set_drvdata(pdev, pcie);
|
|
||||||
|
|
||||||
/* Get the PCIe memory and I/O aperture */
|
|
||||||
mvebu_mbus_get_pcie_mem_aperture(&pcie->mem);
|
|
||||||
if (resource_size(&pcie->mem) == 0) {
|
|
||||||
dev_err(dev, "invalid memory aperture size\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
mvebu_mbus_get_pcie_io_aperture(&pcie->io);
|
|
||||||
|
|
||||||
if (resource_size(&pcie->io) != 0) {
|
|
||||||
pcie->realio.flags = pcie->io.flags;
|
|
||||||
pcie->realio.start = PCIBIOS_MIN_IO;
|
|
||||||
pcie->realio.end = min_t(resource_size_t,
|
|
||||||
IO_SPACE_LIMIT,
|
|
||||||
resource_size(&pcie->io));
|
|
||||||
} else
|
|
||||||
pcie->realio = pcie->io;
|
|
||||||
|
|
||||||
/* Get the bus range */
|
/* Get the bus range */
|
||||||
ret = of_pci_parse_bus_range(np, &pcie->busn);
|
ret = of_pci_parse_bus_range(np, &pcie->busn);
|
||||||
|
@ -1229,6 +1156,58 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
|
||||||
dev_err(dev, "failed to parse bus-range property: %d\n", ret);
|
dev_err(dev, "failed to parse bus-range property: %d\n", ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
pci_add_resource(&pcie->resources, &pcie->busn);
|
||||||
|
|
||||||
|
/* Get the PCIe memory aperture */
|
||||||
|
mvebu_mbus_get_pcie_mem_aperture(&pcie->mem);
|
||||||
|
if (resource_size(&pcie->mem) == 0) {
|
||||||
|
dev_err(dev, "invalid memory aperture size\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pcie->mem.name = "PCI MEM";
|
||||||
|
pci_add_resource(&pcie->resources, &pcie->mem);
|
||||||
|
|
||||||
|
/* Get the PCIe IO aperture */
|
||||||
|
mvebu_mbus_get_pcie_io_aperture(&pcie->io);
|
||||||
|
|
||||||
|
if (resource_size(&pcie->io) != 0) {
|
||||||
|
pcie->realio.flags = pcie->io.flags;
|
||||||
|
pcie->realio.start = PCIBIOS_MIN_IO;
|
||||||
|
pcie->realio.end = min_t(resource_size_t,
|
||||||
|
IO_SPACE_LIMIT - SZ_64K,
|
||||||
|
resource_size(&pcie->io) - 1);
|
||||||
|
pcie->realio.name = "PCI I/O";
|
||||||
|
|
||||||
|
for (i = 0; i < resource_size(&pcie->realio); i += SZ_64K)
|
||||||
|
pci_ioremap_io(i, pcie->io.start + i);
|
||||||
|
|
||||||
|
pci_add_resource(&pcie->resources, &pcie->realio);
|
||||||
|
}
|
||||||
|
|
||||||
|
return devm_request_pci_bus_resources(dev, &pcie->resources);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mvebu_pcie_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct mvebu_pcie *pcie;
|
||||||
|
struct pci_host_bridge *bridge;
|
||||||
|
struct device_node *np = dev->of_node;
|
||||||
|
struct device_node *child;
|
||||||
|
int num, i, ret;
|
||||||
|
|
||||||
|
bridge = devm_pci_alloc_host_bridge(dev, sizeof(struct mvebu_pcie));
|
||||||
|
if (!bridge)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
pcie = pci_host_bridge_priv(bridge);
|
||||||
|
pcie->pdev = pdev;
|
||||||
|
platform_set_drvdata(pdev, pcie);
|
||||||
|
|
||||||
|
ret = mvebu_pcie_parse_request_resources(pcie);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
num = of_get_available_child_count(np);
|
num = of_get_available_child_count(np);
|
||||||
|
|
||||||
|
@ -1272,20 +1251,24 @@ static int mvebu_pcie_probe(struct platform_device *pdev)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mvebu_pcie_setup_hw(port);
|
||||||
mvebu_pcie_set_local_dev_nr(port, 1);
|
mvebu_pcie_set_local_dev_nr(port, 1);
|
||||||
mvebu_sw_pci_bridge_init(port);
|
mvebu_sw_pci_bridge_init(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
pcie->nports = i;
|
pcie->nports = i;
|
||||||
|
|
||||||
for (i = 0; i < (IO_SPACE_LIMIT - SZ_64K); i += SZ_64K)
|
list_splice_init(&pcie->resources, &bridge->windows);
|
||||||
pci_ioremap_io(i, pcie->io.start + i);
|
bridge->dev.parent = dev;
|
||||||
|
bridge->sysdata = pcie;
|
||||||
|
bridge->busnr = 0;
|
||||||
|
bridge->ops = &mvebu_pcie_ops;
|
||||||
|
bridge->map_irq = of_irq_parse_and_map_pci;
|
||||||
|
bridge->swizzle_irq = pci_common_swizzle;
|
||||||
|
bridge->align_resource = mvebu_pcie_align_resource;
|
||||||
|
bridge->msi = pcie->msi;
|
||||||
|
|
||||||
mvebu_pcie_enable(pcie);
|
return pci_host_probe(bridge);
|
||||||
|
|
||||||
platform_set_drvdata(pdev, pcie);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id mvebu_pcie_of_match_table[] = {
|
static const struct of_device_id mvebu_pcie_of_match_table[] = {
|
||||||
|
|
Loading…
Reference in a new issue