Subject: [PATCH 2/4] MIPS: pci-ar724x: use dynamically allocated PCI controller structure

From: Gabor Juhos <[email-masked]>
Date: Sun, 3 Feb 2013 11:58:38 +0100

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: Gabor Juhos <[email-masked]>
---
 arch/mips/pci/pci-ar724x.c |  129 ++++++++++++++++++++++++++++----------------
 1 file changed, 82 insertions(+), 47 deletions(-)

diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c
index 8f008d9..93ab877 100644
--- a/arch/mips/pci/pci-ar724x.c
+++ b/arch/mips/pci/pci-ar724x.c
@@ -9,6 +9,7 @@
  *  by the Free Software Foundation.
  */
 
+#include <linux/spinlock.h>
 #include <linux/irq.h>
 #include <linux/pci.h>
 #include <linux/module.h>
@@ -28,38 +29,56 @@
 
 #define AR7240_BAR0_WAR_VALUE	0xffff
 
-static DEFINE_SPINLOCK(ar724x_pci_lock);
-static void __iomem *ar724x_pci_devcfg_base;
-static void __iomem *ar724x_pci_ctrl_base;
+struct ar724x_pci_controller {
+	void __iomem *devcfg_base;
+	void __iomem *ctrl_base;
 
-static u32 ar724x_pci_bar0_value;
-static bool ar724x_pci_bar0_is_cached;
-static bool ar724x_pci_link_up;
+	int irq;
+
+	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;
 
-	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;
 }
 
+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,
 			    int size, uint32_t *value)
 {
+	struct ar724x_pci_controller *apc;
 	unsigned long flags;
 	void __iomem *base;
 	u32 data;
 
-	if (!ar724x_pci_link_up)
+	apc = pci_bus_to_ar724x_controller(bus);
+	if (!apc->link_up)
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
 	if (devfn)
 		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));
 
 	switch (size) {
@@ -78,17 +97,17 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where,
 	case 4:
 		break;
 	default:
-		spin_unlock_irqrestore(&ar724x_pci_lock, flags);
+		spin_unlock_irqrestore(&apc->lock, flags);
 
 		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 &&
-	    ar724x_pci_bar0_is_cached) {
+	    apc->bar0_is_cached) {
 		/* use the cached value */
-		*value = ar724x_pci_bar0_value;
+		*value = apc->bar0_value;
 	} else {
 		*value = data;
 	}
@@ -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,
 			     int size, uint32_t value)
 {
+	struct ar724x_pci_controller *apc;
 	unsigned long flags;
 	void __iomem *base;
 	u32 data;
 	int s;
 
-	if (!ar724x_pci_link_up)
+	apc = pci_bus_to_ar724x_controller(bus);
+	if (!apc->link_up)
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
 	if (devfn)
@@ -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
 			 * accessible.
 			 */
-			ar724x_pci_bar0_is_cached = true;
-			ar724x_pci_bar0_value = value;
+			apc->bar0_is_cached = true;
+			apc->bar0_value = value;
 
 			value = AR7240_BAR0_WAR_VALUE;
 		} 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));
 
 	switch (size) {
@@ -151,7 +172,7 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where,
 		data = value;
 		break;
 	default:
-		spin_unlock_irqrestore(&ar724x_pci_lock, flags);
+		spin_unlock_irqrestore(&apc->lock, flags);
 
 		return PCIBIOS_BAD_REGISTER_NUMBER;
 	}
@@ -159,7 +180,7 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where,
 	__raw_writel(data, base + (where & ~3));
 	/* flush write */
 	__raw_readl(base + (where & ~3));
-	spin_unlock_irqrestore(&ar724x_pci_lock, flags);
+	spin_unlock_irqrestore(&apc->lock, flags);
 
 	return PCIBIOS_SUCCESSFUL;
 }
@@ -183,18 +204,14 @@ static struct resource ar724x_mem_resource = {
 	.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)
 {
+	struct ar724x_pci_controller *apc;
 	void __iomem *base;
 	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) &
 		  __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)
 
 static void ar724x_pci_irq_unmask(struct irq_data *d)
 {
+	struct ar724x_pci_controller *apc;
 	void __iomem *base;
 	u32 t;
 
-	base = ar724x_pci_ctrl_base;
+	apc = irq_data_get_irq_chip_data(d);
+	base = apc->ctrl_base;
 
 	switch (d->irq) {
 	case ATH79_PCI_IRQ(0):
@@ -225,10 +244,12 @@ static void ar724x_pci_irq_unmask(struct irq_data *d)
 
 static void ar724x_pci_irq_mask(struct irq_data *d)
 {
+	struct ar724x_pci_controller *apc;
 	void __iomem *base;
 	u32 t;
 
-	base = ar724x_pci_ctrl_base;
+	apc = irq_data_get_irq_chip_data(d);
+	base = apc->ctrl_base;
 
 	switch (d->irq) {
 	case ATH79_PCI_IRQ(0):
@@ -255,12 +276,12 @@ static struct irq_chip ar724x_pci_irq_chip = {
 	.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;
 	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_STATUS);
@@ -268,45 +289,59 @@ static void ar724x_pci_irq_init(int irq)
 	BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR724X_PCI_IRQ_COUNT);
 
 	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,
 					 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)
 {
+	struct ar724x_pci_controller *apc;
 	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");
 	if (!res)
 		return -EINVAL;
 
-	ar724x_pci_ctrl_base = devm_request_and_ioremap(&pdev->dev, res);
-	if (ar724x_pci_ctrl_base == NULL)
+	apc->ctrl_base = devm_request_and_ioremap(&pdev->dev, res);
+	if (apc->ctrl_base == NULL)
 		return -EBUSY;
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg_base");
 	if (!res)
 		return -EINVAL;
 
-	ar724x_pci_devcfg_base = devm_request_and_ioremap(&pdev->dev, res);
-	if (!ar724x_pci_devcfg_base)
+	apc->devcfg_base = devm_request_and_ioremap(&pdev->dev, res);
+	if (!apc->devcfg_base)
 		return -EBUSY;
 
-	irq = platform_get_irq(pdev, 0);
-	if (irq < 0)
+	apc->irq = platform_get_irq(pdev, 0);
+	if (apc->irq < 0)
 		return -EINVAL;
 
-	ar724x_pci_link_up = ar724x_pci_check_link();
-	if (!ar724x_pci_link_up)
+	spin_lock_init(&apc->lock);
+
+	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");
 
-	ar724x_pci_irq_init(irq);
+	ar724x_pci_irq_init(apc);
 
-	register_pci_controller(&ar724x_pci_controller);
+	register_pci_controller(&apc->pci_controller);
 
 	return 0;
 }
-- 
1.7.10

---

From: Gabor Juhos <[email-masked]>
Date: Sun, 3 Feb 2013 11:58:37 +0100

This is needed for multiple PCI bus support.

Signed-off-by: Gabor Juhos <[email-masked]>
---
 arch/mips/ath79/pci.c |    4 +++-
 arch/mips/ath79/pci.h |    1 +
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c
index c94bcec..d90e071 100644
--- a/arch/mips/ath79/pci.c
+++ b/arch/mips/ath79/pci.c
@@ -75,7 +75,9 @@ int __init pcibios_map_irq(const struct pci_dev *dev, uint8_t slot, uint8_t pin)
 		const struct ath79_pci_irq *entry;
 
 		entry = &ath79_pci_irq_map[i];
-		if (entry->slot == slot && entry->pin == pin) {
+		if (entry->bus == dev->bus->number &&
+		    entry->slot == slot &&
+		    entry->pin == pin) {
 			irq = entry->irq;
 			break;
 		}
diff --git a/arch/mips/ath79/pci.h b/arch/mips/ath79/pci.h
index 51c6625..1d00a38 100644
--- a/arch/mips/ath79/pci.h
+++ b/arch/mips/ath79/pci.h
@@ -14,6 +14,7 @@
 #define _ATH79_PCI_H
 
 struct ath79_pci_irq {
+	int	bus;
 	u8	slot;
 	u8	pin;
 	int	irq;
-- 
1.7.10

---

From: Gabor Juhos <[email-masked]>
Date: Sun, 3 Feb 2013 11:59:45 +0100

Static resources become impractical when multiple
PCI controllers are present. Move the resources
into the platform device registration code and
change the probe routine to get those from there
platform device's resources.

Signed-off-by: Gabor Juhos <[email-masked]>
---
 arch/mips/ath79/pci.c      |   21 ++++++++++++++++++++-
 arch/mips/pci/pci-ar724x.c |   40 ++++++++++++++++++++++++----------------
 2 files changed, 44 insertions(+), 17 deletions(-)

diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c
index d90e071..45d1112 100644
--- a/arch/mips/ath79/pci.c
+++ b/arch/mips/ath79/pci.c
@@ -139,10 +139,13 @@ static struct platform_device *
 ath79_register_pci_ar724x(int id,
 			  unsigned long cfg_base,
 			  unsigned long ctrl_base,
+			  unsigned long mem_base,
+			  unsigned long mem_size,
+			  unsigned long io_base,
 			  int irq)
 {
 	struct platform_device *pdev;
-	struct resource res[3];
+	struct resource res[5];
 
 	memset(res, 0, sizeof(res));
 
@@ -160,6 +163,16 @@ ath79_register_pci_ar724x(int id,
 	res[2].start = irq;
 	res[2].end = irq;
 
+	res[3].name = "mem_base";
+	res[3].flags = IORESOURCE_MEM;
+	res[3].start = mem_base;
+	res[3].end = mem_base + mem_size - 1;
+
+	res[4].name = "io_base";
+	res[4].flags = IORESOURCE_IO;
+	res[4].start = io_base;
+	res[4].end = io_base;
+
 	pdev = platform_device_register_simple("ar724x-pci", id,
 					       res, ARRAY_SIZE(res));
 	return pdev;
@@ -175,6 +188,9 @@ int __init ath79_register_pci(void)
 		pdev = ath79_register_pci_ar724x(-1,
 						 AR724X_PCI_CFG_BASE,
 						 AR724X_PCI_CTRL_BASE,
+						 AR724X_PCI_MEM_BASE,
+						 AR724X_PCI_MEM_SIZE,
+						 0,
 						 ATH79_CPU_IRQ_IP2);
 	} else if (soc_is_ar9342() ||
 		   soc_is_ar9344()) {
@@ -187,6 +203,9 @@ int __init ath79_register_pci(void)
 		pdev = ath79_register_pci_ar724x(-1,
 						 AR724X_PCI_CFG_BASE,
 						 AR724X_PCI_CTRL_BASE,
+						 AR724X_PCI_MEM_BASE,
+						 AR724X_PCI_MEM_SIZE,
+						 0,
 						 ATH79_IP2_IRQ(0));
 	} else {
 		/* No PCI support */
diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c
index 93ab877..d0d707d 100644
--- a/arch/mips/pci/pci-ar724x.c
+++ b/arch/mips/pci/pci-ar724x.c
@@ -42,6 +42,8 @@ struct ar724x_pci_controller {
 	spinlock_t lock;
 
 	struct pci_controller pci_controller;
+	struct resource io_res;
+	struct resource mem_res;
 };
 
 static inline bool ar724x_pci_check_link(struct ar724x_pci_controller *apc)
@@ -190,20 +192,6 @@ static struct pci_ops ar724x_pci_ops = {
 	.write	= ar724x_pci_write,
 };
 
-static struct resource ar724x_io_resource = {
-	.name   = "PCI IO space",
-	.start  = 0,
-	.end    = 0,
-	.flags  = IORESOURCE_IO,
-};
-
-static struct resource ar724x_mem_resource = {
-	.name   = "PCI memory space",
-	.start  = AR724X_PCI_MEM_BASE,
-	.end    = AR724X_PCI_MEM_BASE + AR724X_PCI_MEM_SIZE - 1,
-	.flags  = IORESOURCE_MEM,
-};
-
 static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc)
 {
 	struct ar724x_pci_controller *apc;
@@ -331,9 +319,29 @@ static int ar724x_pci_probe(struct platform_device *pdev)
 
 	spin_lock_init(&apc->lock);
 
+	res = platform_get_resource_byname(pdev, IORESOURCE_IO, "io_base");
+	if (!res)
+		return -EINVAL;
+
+	apc->io_res.parent = res;
+	apc->io_res.name = "PCI IO space";
+	apc->io_res.start = res->start;
+	apc->io_res.end = res->end;
+	apc->io_res.flags = IORESOURCE_IO;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem_base");
+	if (!res)
+		return -EINVAL;
+
+	apc->mem_res.parent = res;
+	apc->mem_res.name = "PCI memory space";
+	apc->mem_res.start = res->start;
+	apc->mem_res.end = res->end;
+	apc->mem_res.flags = IORESOURCE_MEM;
+
 	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->pci_controller.io_resource = &apc->io_res;
+	apc->pci_controller.mem_resource = &apc->mem_res;
 
 	apc->link_up = ar724x_pci_check_link(apc);
 	if (!apc->link_up)
-- 
1.7.10

---

From: Gabor Juhos <[email-masked]>
Date: Sun, 3 Feb 2013 12:00:16 +0100

Change to the code to use per-controller IRQ base.
This is needed for multiple PCI controller support.

Signed-off-by: Gabor Juhos <[email-masked]>
---
 arch/mips/pci/pci-ar724x.c |   31 +++++++++++++++++++++----------
 1 file changed, 21 insertions(+), 10 deletions(-)

diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c
index d0d707d..0440d88 100644
--- a/arch/mips/pci/pci-ar724x.c
+++ b/arch/mips/pci/pci-ar724x.c
@@ -34,6 +34,7 @@ struct ar724x_pci_controller {
 	void __iomem *ctrl_base;
 
 	int irq;
+	int irq_base;
 
 	bool link_up;
 	bool bar0_is_cached;
@@ -205,7 +206,7 @@ static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc)
 		  __raw_readl(base + AR724X_PCI_REG_INT_MASK);
 
 	if (pending & AR724X_PCI_INT_DEV0)
-		generic_handle_irq(ATH79_PCI_IRQ(0));
+		generic_handle_irq(apc->irq_base + 0);
 
 	else
 		spurious_interrupt();
@@ -215,13 +216,15 @@ static void ar724x_pci_irq_unmask(struct irq_data *d)
 {
 	struct ar724x_pci_controller *apc;
 	void __iomem *base;
+	int offset;
 	u32 t;
 
 	apc = irq_data_get_irq_chip_data(d);
 	base = apc->ctrl_base;
+	offset = apc->irq_base - d->irq;
 
-	switch (d->irq) {
-	case ATH79_PCI_IRQ(0):
+	switch (offset) {
+	case 0:
 		t = __raw_readl(base + AR724X_PCI_REG_INT_MASK);
 		__raw_writel(t | AR724X_PCI_INT_DEV0,
 			     base + AR724X_PCI_REG_INT_MASK);
@@ -234,13 +237,15 @@ static void ar724x_pci_irq_mask(struct irq_data *d)
 {
 	struct ar724x_pci_controller *apc;
 	void __iomem *base;
+	int offset;
 	u32 t;
 
 	apc = irq_data_get_irq_chip_data(d);
 	base = apc->ctrl_base;
+	offset = apc->irq_base - d->irq;
 
-	switch (d->irq) {
-	case ATH79_PCI_IRQ(0):
+	switch (offset) {
+	case 0:
 		t = __raw_readl(base + AR724X_PCI_REG_INT_MASK);
 		__raw_writel(t & ~AR724X_PCI_INT_DEV0,
 			     base + AR724X_PCI_REG_INT_MASK);
@@ -264,7 +269,8 @@ static struct irq_chip ar724x_pci_irq_chip = {
 	.irq_mask_ack	= ar724x_pci_irq_mask,
 };
 
-static void ar724x_pci_irq_init(struct ar724x_pci_controller *apc)
+static void ar724x_pci_irq_init(struct ar724x_pci_controller *apc,
+				int id)
 {
 	void __iomem *base;
 	int i;
@@ -274,10 +280,10 @@ static void ar724x_pci_irq_init(struct ar724x_pci_controller *apc)
 	__raw_writel(0, base + AR724X_PCI_REG_INT_MASK);
 	__raw_writel(0, base + AR724X_PCI_REG_INT_STATUS);
 
-	BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR724X_PCI_IRQ_COUNT);
+	apc->irq_base = ATH79_PCI_IRQ_BASE + (id * AR724X_PCI_IRQ_COUNT);
 
-	for (i = ATH79_PCI_IRQ_BASE;
-	     i < ATH79_PCI_IRQ_BASE + AR724X_PCI_IRQ_COUNT; i++) {
+	for (i = apc->irq_base;
+	     i < apc->irq_base + AR724X_PCI_IRQ_COUNT; i++) {
 		irq_set_chip_and_handler(i, &ar724x_pci_irq_chip,
 					 handle_level_irq);
 		irq_set_chip_data(i, apc);
@@ -291,6 +297,11 @@ static int ar724x_pci_probe(struct platform_device *pdev)
 {
 	struct ar724x_pci_controller *apc;
 	struct resource *res;
+	int id;
+
+	id = pdev->id;
+	if (id == -1)
+		id = 0;
 
 	apc = devm_kzalloc(&pdev->dev, sizeof(struct ar724x_pci_controller),
 			    GFP_KERNEL);
@@ -347,7 +358,7 @@ static int ar724x_pci_probe(struct platform_device *pdev)
 	if (!apc->link_up)
 		dev_warn(&pdev->dev, "PCIe link is down\n");
 
-	ar724x_pci_irq_init(apc);
+	ar724x_pci_irq_init(apc, id);
 
 	register_pci_controller(&apc->pci_controller);
 
-- 
1.7.10

---

From: Sergei Shtylyov <[email-masked]>
Date: Sun, 03 Feb 2013 15:18:52 +0400

Hello.

> +	res[4].start = io_base;

    One I/O port, hm? What is it good for?

WBR, Sergei

---

From: Gabor Juhos <[email-masked]>
Date: Sun, 03 Feb 2013 13:31:49 +0100

>    One I/O port, hm? What is it good for?

Strictly speaking it is not good for anything. This is a PCIe controller and it
does not support IO requests at all. However the whole PCI code assumes that
each PCI controller have an IO resource and uses the hose->io_resource pointer
unconditionally.

> -	.flags  = IORESOURCE_IO,

Thank you for the review.

-Gabor

---

From: Gabor Juhos <[email-masked]>
Date: Sun, 3 Feb 2013 16:52:47 +0100

The command register of the PCI controller is
not initialized correctly by the bootloader on
some boards and this leads to non working PCI
bus.

Add code to initialize the command register
from the Linux code to avoid this.

Signed-off-by: Gabor Juhos <[email-masked]>
---
Sorry for the confusing patch number. This belongs to the 
previous 'pci-ar724x' series but I forgot to add it there.

Gabor

 arch/mips/ath79/pci.c                          |   10 +++-
 arch/mips/include/asm/mach-ath79/ar71xx_regs.h |    2 +
 arch/mips/pci/pci-ar724x.c                     |   63 ++++++++++++++++++++++++
 3 files changed, 74 insertions(+), 1 deletion(-)

diff --git a/arch/mips/ath79/pci.c b/arch/mips/ath79/pci.c
index 45d1112..942e3f9 100644
--- a/arch/mips/ath79/pci.c
+++ b/arch/mips/ath79/pci.c
@@ -139,13 +139,14 @@ static struct platform_device *
 ath79_register_pci_ar724x(int id,
 			  unsigned long cfg_base,
 			  unsigned long ctrl_base,
+			  unsigned long crp_base,
 			  unsigned long mem_base,
 			  unsigned long mem_size,
 			  unsigned long io_base,
 			  int irq)
 {
 	struct platform_device *pdev;
-	struct resource res[5];
+	struct resource res[6];

@@ -173,6 +174,11 @@ ath79_register_pci_ar724x(int id,
 	res[4].start = io_base;
 	res[4].end = io_base;
 
+	res[5].name = "crp_base";
+	res[5].flags = IORESOURCE_MEM;
+	res[5].start = crp_base;
+	res[5].end = crp_base + AR724X_PCI_CRP_SIZE - 1;
+
 	pdev = platform_device_register_simple("ar724x-pci", id,
 					       res, ARRAY_SIZE(res));
 	return pdev;
@@ -188,6 +194,7 @@ int __init ath79_register_pci(void)
 		pdev = ath79_register_pci_ar724x(-1,
 						 AR724X_PCI_CFG_BASE,
 						 AR724X_PCI_CTRL_BASE,
+						 AR724X_PCI_CRP_BASE,
 						 AR724X_PCI_MEM_BASE,
 						 AR724X_PCI_MEM_SIZE,
 						 0,
@@ -203,6 +210,7 @@ int __init ath79_register_pci(void)
 		pdev = ath79_register_pci_ar724x(-1,
 						 AR724X_PCI_CFG_BASE,
 						 AR724X_PCI_CTRL_BASE,
+						 AR724X_PCI_CRP_BASE,
 						 AR724X_PCI_MEM_BASE,
 						 AR724X_PCI_MEM_SIZE,
 						 0,
diff --git a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
index 7c87bfe..a77f6ee 100644
--- a/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
+++ b/arch/mips/include/asm/mach-ath79/ar71xx_regs.h
@@ -67,6 +67,8 @@
 
 #define AR724X_PCI_CFG_BASE	0x14000000
 #define AR724X_PCI_CFG_SIZE	0x1000
+#define AR724X_PCI_CRP_BASE	(AR71XX_APB_BASE + 0x000c0000)
+#define AR724X_PCI_CRP_SIZE	0x1000
 #define AR724X_PCI_CTRL_BASE	(AR71XX_APB_BASE + 0x000f0000)
 #define AR724X_PCI_CTRL_SIZE	0x100
 
diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c
index 0440d88..8a0700d 100644
--- a/arch/mips/pci/pci-ar724x.c
+++ b/arch/mips/pci/pci-ar724x.c
@@ -29,9 +29,17 @@

+#define AR724X_PCI_CMD_INIT	(PCI_COMMAND_MEMORY |		\
+				 PCI_COMMAND_MASTER |		\
+				 PCI_COMMAND_INVALIDATE |	\
+				 PCI_COMMAND_PARITY |		\
+				 PCI_COMMAND_SERR |		\
+				 PCI_COMMAND_FAST_BACK)
+
 struct ar724x_pci_controller {
 	void __iomem *devcfg_base;
 	void __iomem *ctrl_base;
+	void __iomem *crp_base;
 
 	int irq;
 	int irq_base;
@@ -64,6 +72,51 @@ pci_bus_to_ar724x_controller(struct pci_bus *bus)
 	return container_of(hose, struct ar724x_pci_controller, pci_controller);
 }
 
+static int ar724x_pci_local_write(struct ar724x_pci_controller *apc,
+				  int where, int size, u32 value)
+{
+	unsigned long flags;
+	void __iomem *base;
+	u32 data;
+	int s;
+
+	WARN_ON(where & (size - 1));
+
+	if (!apc->link_up)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	base = apc->crp_base;
+
+	spin_lock_irqsave(&apc->lock, flags);
+	data = __raw_readl(base + (where & ~3));
+
+	switch (size) {
+	case 1:
+		s = ((where & 3) * 8);
+		data &= ~(0xff << s);
+		data |= ((value & 0xff) << s);
+		break;
+	case 2:
+		s = ((where & 2) * 8);
+		data &= ~(0xffff << s);
+		data |= ((value & 0xffff) << s);
+		break;
+	case 4:
+		data = value;
+		break;
+	default:
+		spin_unlock_irqrestore(&apc->lock, flags);
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	}
+
+	__raw_writel(data, base + (where & ~3));
+	/* flush write */
+	__raw_readl(base + (where & ~3));
+	spin_unlock_irqrestore(&apc->lock, flags);
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
 static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where,
 			    int size, uint32_t *value)
 {
@@ -324,6 +377,14 @@ static int ar724x_pci_probe(struct platform_device *pdev)
 	if (!apc->devcfg_base)
 		return -EBUSY;
 
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "crp_base");
+	if (!res)
+		return -EINVAL;
+
+	apc->crp_base = devm_request_and_ioremap(&pdev->dev, res);
+	if (apc->crp_base == NULL)
+		return -EBUSY;
+
 	apc->irq = platform_get_irq(pdev, 0);
 	if (apc->irq < 0)
 		return -EINVAL;
@@ -360,6 +421,8 @@ static int ar724x_pci_probe(struct platform_device *pdev)
 
 	ar724x_pci_irq_init(apc, id);
 
+	ar724x_pci_local_write(apc, PCI_COMMAND, 4, AR724X_PCI_CMD_INIT);
+
 	register_pci_controller(&apc->pci_controller);
 
 	return 0;
-- 
1.7.10

---

From: Sergei Shtylyov <[email-masked]>
Date: Mon, 04 Feb 2013 16:13:23 +0400

Hello.

> does not support IO requests at all.

    Is this the case with every PCIe controller or only this particular one?

> However the whole PCI code assumes that

>> -	.flags  = IORESOURCE_IO,

    Since you seems to always pass 0, maybe you don't need 'io_base' parameter 
to the function above?

WBR, Sergei

---

From: Gabor Juhos <[email-masked]>
Date: Mon, 04 Feb 2013 14:14:49 +0100

>    Is this the case with every PCIe controller or only this particular one?

It is a limitation of this controller.

>    Since you seems to always pass 0, maybe you don't need 'io_base' parameter to
> the function above?

The AR724x SoCs SoCs have one PCIe controller only. However newer chips have
more than one PCIe controllers, and each of those controllers needs a different
io_base value to avoid resource conflicts. I'm preparing patches for newer SoCs
and if everything goes well I will send those today.

-GAbor