Commit 908339ef authored by Gabor Juhos's avatar Gabor Juhos Committed by John Crispin

MIPS: pci-ar724x: use dynamically allocated PCI controller structure

The current code uses static variables to store the
PCI controller specific data. This works if the system
contains one PCI controller only, however it becomes
impractical when multiple PCI controllers are present.

Move the variables into a dynamically allocated controller
specific structure, and use that instead of the static
variables.
Signed-off-by: default avatarGabor Juhos <juhosg@openwrt.org>
Patchwork: http://patchwork.linux-mips.org/patch/4912/Signed-off-by: default avatarJohn Crispin <blogic@openwrt.org>
parent 617fed41
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
* by the Free Software Foundation. * by the Free Software Foundation.
*/ */
#include <linux/spinlock.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -28,38 +29,56 @@ ...@@ -28,38 +29,56 @@
#define AR7240_BAR0_WAR_VALUE 0xffff #define AR7240_BAR0_WAR_VALUE 0xffff
static DEFINE_SPINLOCK(ar724x_pci_lock); struct ar724x_pci_controller {
static void __iomem *ar724x_pci_devcfg_base; void __iomem *devcfg_base;
static void __iomem *ar724x_pci_ctrl_base; void __iomem *ctrl_base;
static u32 ar724x_pci_bar0_value; int irq;
static bool ar724x_pci_bar0_is_cached;
static bool ar724x_pci_link_up; bool link_up;
bool bar0_is_cached;
u32 bar0_value;
spinlock_t lock;
struct pci_controller pci_controller;
};
static inline bool ar724x_pci_check_link(void) static inline bool ar724x_pci_check_link(struct ar724x_pci_controller *apc)
{ {
u32 reset; u32 reset;
reset = __raw_readl(ar724x_pci_ctrl_base + AR724X_PCI_REG_RESET); reset = __raw_readl(apc->ctrl_base + AR724X_PCI_REG_RESET);
return reset & AR724X_PCI_RESET_LINK_UP; return reset & AR724X_PCI_RESET_LINK_UP;
} }
static inline struct ar724x_pci_controller *
pci_bus_to_ar724x_controller(struct pci_bus *bus)
{
struct pci_controller *hose;
hose = (struct pci_controller *) bus->sysdata;
return container_of(hose, struct ar724x_pci_controller, pci_controller);
}
static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where,
int size, uint32_t *value) int size, uint32_t *value)
{ {
struct ar724x_pci_controller *apc;
unsigned long flags; unsigned long flags;
void __iomem *base; void __iomem *base;
u32 data; u32 data;
if (!ar724x_pci_link_up) apc = pci_bus_to_ar724x_controller(bus);
if (!apc->link_up)
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
if (devfn) if (devfn)
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
base = ar724x_pci_devcfg_base; base = apc->devcfg_base;
spin_lock_irqsave(&ar724x_pci_lock, flags); spin_lock_irqsave(&apc->lock, flags);
data = __raw_readl(base + (where & ~3)); data = __raw_readl(base + (where & ~3));
switch (size) { switch (size) {
...@@ -78,17 +97,17 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, ...@@ -78,17 +97,17 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where,
case 4: case 4:
break; break;
default: default:
spin_unlock_irqrestore(&ar724x_pci_lock, flags); spin_unlock_irqrestore(&apc->lock, flags);
return PCIBIOS_BAD_REGISTER_NUMBER; return PCIBIOS_BAD_REGISTER_NUMBER;
} }
spin_unlock_irqrestore(&ar724x_pci_lock, flags); spin_unlock_irqrestore(&apc->lock, flags);
if (where == PCI_BASE_ADDRESS_0 && size == 4 && if (where == PCI_BASE_ADDRESS_0 && size == 4 &&
ar724x_pci_bar0_is_cached) { apc->bar0_is_cached) {
/* use the cached value */ /* use the cached value */
*value = ar724x_pci_bar0_value; *value = apc->bar0_value;
} else { } else {
*value = data; *value = data;
} }
...@@ -99,12 +118,14 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, ...@@ -99,12 +118,14 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where,
static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where,
int size, uint32_t value) int size, uint32_t value)
{ {
struct ar724x_pci_controller *apc;
unsigned long flags; unsigned long flags;
void __iomem *base; void __iomem *base;
u32 data; u32 data;
int s; int s;
if (!ar724x_pci_link_up) apc = pci_bus_to_ar724x_controller(bus);
if (!apc->link_up)
return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_DEVICE_NOT_FOUND;
if (devfn) if (devfn)
...@@ -122,18 +143,18 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, ...@@ -122,18 +143,18 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where,
* BAR0 register in order to make the device memory * BAR0 register in order to make the device memory
* accessible. * accessible.
*/ */
ar724x_pci_bar0_is_cached = true; apc->bar0_is_cached = true;
ar724x_pci_bar0_value = value; apc->bar0_value = value;
value = AR7240_BAR0_WAR_VALUE; value = AR7240_BAR0_WAR_VALUE;
} else { } else {
ar724x_pci_bar0_is_cached = false; apc->bar0_is_cached = false;
} }
} }
base = ar724x_pci_devcfg_base; base = apc->devcfg_base;
spin_lock_irqsave(&ar724x_pci_lock, flags); spin_lock_irqsave(&apc->lock, flags);
data = __raw_readl(base + (where & ~3)); data = __raw_readl(base + (where & ~3));
switch (size) { switch (size) {
...@@ -151,7 +172,7 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, ...@@ -151,7 +172,7 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where,
data = value; data = value;
break; break;
default: default:
spin_unlock_irqrestore(&ar724x_pci_lock, flags); spin_unlock_irqrestore(&apc->lock, flags);
return PCIBIOS_BAD_REGISTER_NUMBER; return PCIBIOS_BAD_REGISTER_NUMBER;
} }
...@@ -159,7 +180,7 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, ...@@ -159,7 +180,7 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where,
__raw_writel(data, base + (where & ~3)); __raw_writel(data, base + (where & ~3));
/* flush write */ /* flush write */
__raw_readl(base + (where & ~3)); __raw_readl(base + (where & ~3));
spin_unlock_irqrestore(&ar724x_pci_lock, flags); spin_unlock_irqrestore(&apc->lock, flags);
return PCIBIOS_SUCCESSFUL; return PCIBIOS_SUCCESSFUL;
} }
...@@ -183,18 +204,14 @@ static struct resource ar724x_mem_resource = { ...@@ -183,18 +204,14 @@ static struct resource ar724x_mem_resource = {
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}; };
static struct pci_controller ar724x_pci_controller = {
.pci_ops = &ar724x_pci_ops,
.io_resource = &ar724x_io_resource,
.mem_resource = &ar724x_mem_resource,
};
static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc) static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc)
{ {
struct ar724x_pci_controller *apc;
void __iomem *base; void __iomem *base;
u32 pending; u32 pending;
base = ar724x_pci_ctrl_base; apc = irq_get_handler_data(irq);
base = apc->ctrl_base;
pending = __raw_readl(base + AR724X_PCI_REG_INT_STATUS) & pending = __raw_readl(base + AR724X_PCI_REG_INT_STATUS) &
__raw_readl(base + AR724X_PCI_REG_INT_MASK); __raw_readl(base + AR724X_PCI_REG_INT_MASK);
...@@ -208,10 +225,12 @@ static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc) ...@@ -208,10 +225,12 @@ static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc)
static void ar724x_pci_irq_unmask(struct irq_data *d) static void ar724x_pci_irq_unmask(struct irq_data *d)
{ {
struct ar724x_pci_controller *apc;
void __iomem *base; void __iomem *base;
u32 t; u32 t;
base = ar724x_pci_ctrl_base; apc = irq_data_get_irq_chip_data(d);
base = apc->ctrl_base;
switch (d->irq) { switch (d->irq) {
case ATH79_PCI_IRQ(0): case ATH79_PCI_IRQ(0):
...@@ -225,10 +244,12 @@ static void ar724x_pci_irq_unmask(struct irq_data *d) ...@@ -225,10 +244,12 @@ static void ar724x_pci_irq_unmask(struct irq_data *d)
static void ar724x_pci_irq_mask(struct irq_data *d) static void ar724x_pci_irq_mask(struct irq_data *d)
{ {
struct ar724x_pci_controller *apc;
void __iomem *base; void __iomem *base;
u32 t; u32 t;
base = ar724x_pci_ctrl_base; apc = irq_data_get_irq_chip_data(d);
base = apc->ctrl_base;
switch (d->irq) { switch (d->irq) {
case ATH79_PCI_IRQ(0): case ATH79_PCI_IRQ(0):
...@@ -255,12 +276,12 @@ static struct irq_chip ar724x_pci_irq_chip = { ...@@ -255,12 +276,12 @@ static struct irq_chip ar724x_pci_irq_chip = {
.irq_mask_ack = ar724x_pci_irq_mask, .irq_mask_ack = ar724x_pci_irq_mask,
}; };
static void ar724x_pci_irq_init(int irq) static void ar724x_pci_irq_init(struct ar724x_pci_controller *apc)
{ {
void __iomem *base; void __iomem *base;
int i; int i;
base = ar724x_pci_ctrl_base; base = apc->ctrl_base;
__raw_writel(0, base + AR724X_PCI_REG_INT_MASK); __raw_writel(0, base + AR724X_PCI_REG_INT_MASK);
__raw_writel(0, base + AR724X_PCI_REG_INT_STATUS); __raw_writel(0, base + AR724X_PCI_REG_INT_STATUS);
...@@ -268,45 +289,59 @@ static void ar724x_pci_irq_init(int irq) ...@@ -268,45 +289,59 @@ static void ar724x_pci_irq_init(int irq)
BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR724X_PCI_IRQ_COUNT); BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR724X_PCI_IRQ_COUNT);
for (i = ATH79_PCI_IRQ_BASE; for (i = ATH79_PCI_IRQ_BASE;
i < ATH79_PCI_IRQ_BASE + AR724X_PCI_IRQ_COUNT; i++) i < ATH79_PCI_IRQ_BASE + AR724X_PCI_IRQ_COUNT; i++) {
irq_set_chip_and_handler(i, &ar724x_pci_irq_chip, irq_set_chip_and_handler(i, &ar724x_pci_irq_chip,
handle_level_irq); handle_level_irq);
irq_set_chip_data(i, apc);
}
irq_set_chained_handler(irq, ar724x_pci_irq_handler); irq_set_handler_data(apc->irq, apc);
irq_set_chained_handler(apc->irq, ar724x_pci_irq_handler);
} }
static int ar724x_pci_probe(struct platform_device *pdev) static int ar724x_pci_probe(struct platform_device *pdev)
{ {
struct ar724x_pci_controller *apc;
struct resource *res; struct resource *res;
int irq;
apc = devm_kzalloc(&pdev->dev, sizeof(struct ar724x_pci_controller),
GFP_KERNEL);
if (!apc)
return -ENOMEM;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl_base"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl_base");
if (!res) if (!res)
return -EINVAL; return -EINVAL;
ar724x_pci_ctrl_base = devm_request_and_ioremap(&pdev->dev, res); apc->ctrl_base = devm_request_and_ioremap(&pdev->dev, res);
if (ar724x_pci_ctrl_base == NULL) if (apc->ctrl_base == NULL)
return -EBUSY; return -EBUSY;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg_base"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg_base");
if (!res) if (!res)
return -EINVAL; return -EINVAL;
ar724x_pci_devcfg_base = devm_request_and_ioremap(&pdev->dev, res); apc->devcfg_base = devm_request_and_ioremap(&pdev->dev, res);
if (!ar724x_pci_devcfg_base) if (!apc->devcfg_base)
return -EBUSY; return -EBUSY;
irq = platform_get_irq(pdev, 0); apc->irq = platform_get_irq(pdev, 0);
if (irq < 0) if (apc->irq < 0)
return -EINVAL; return -EINVAL;
ar724x_pci_link_up = ar724x_pci_check_link(); spin_lock_init(&apc->lock);
if (!ar724x_pci_link_up)
apc->pci_controller.pci_ops = &ar724x_pci_ops;
apc->pci_controller.io_resource = &ar724x_io_resource;
apc->pci_controller.mem_resource = &ar724x_mem_resource;
apc->link_up = ar724x_pci_check_link(apc);
if (!apc->link_up)
dev_warn(&pdev->dev, "PCIe link is down\n"); dev_warn(&pdev->dev, "PCIe link is down\n");
ar724x_pci_irq_init(irq); ar724x_pci_irq_init(apc);
register_pci_controller(&ar724x_pci_controller); register_pci_controller(&apc->pci_controller);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment