diff options
-rw-r--r-- | arch/mips/pci/pci-ar724x.c | 129 |
1 files changed, 82 insertions, 47 deletions
diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c index 8f008d9a112c..93ab8778ce10 100644 --- a/arch/mips/pci/pci-ar724x.c +++ b/arch/mips/pci/pci-ar724x.c | |||
@@ -9,6 +9,7 @@ | |||
9 | * by the Free Software Foundation. | 9 | * by the Free Software Foundation. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/spinlock.h> | ||
12 | #include <linux/irq.h> | 13 | #include <linux/irq.h> |
13 | #include <linux/pci.h> | 14 | #include <linux/pci.h> |
14 | #include <linux/module.h> | 15 | #include <linux/module.h> |
@@ -28,38 +29,56 @@ | |||
28 | 29 | ||
29 | #define AR7240_BAR0_WAR_VALUE 0xffff | 30 | #define AR7240_BAR0_WAR_VALUE 0xffff |
30 | 31 | ||
31 | static DEFINE_SPINLOCK(ar724x_pci_lock); | 32 | struct ar724x_pci_controller { |
32 | static void __iomem *ar724x_pci_devcfg_base; | 33 | void __iomem *devcfg_base; |
33 | static void __iomem *ar724x_pci_ctrl_base; | 34 | void __iomem *ctrl_base; |
34 | 35 | ||
35 | static u32 ar724x_pci_bar0_value; | 36 | int irq; |
36 | static bool ar724x_pci_bar0_is_cached; | 37 | |
37 | static bool ar724x_pci_link_up; | 38 | bool link_up; |
39 | bool bar0_is_cached; | ||
40 | u32 bar0_value; | ||
41 | |||
42 | spinlock_t lock; | ||
43 | |||
44 | struct pci_controller pci_controller; | ||
45 | }; | ||
38 | 46 | ||
39 | static inline bool ar724x_pci_check_link(void) | 47 | static inline bool ar724x_pci_check_link(struct ar724x_pci_controller *apc) |
40 | { | 48 | { |
41 | u32 reset; | 49 | u32 reset; |
42 | 50 | ||
43 | reset = __raw_readl(ar724x_pci_ctrl_base + AR724X_PCI_REG_RESET); | 51 | reset = __raw_readl(apc->ctrl_base + AR724X_PCI_REG_RESET); |
44 | return reset & AR724X_PCI_RESET_LINK_UP; | 52 | return reset & AR724X_PCI_RESET_LINK_UP; |
45 | } | 53 | } |
46 | 54 | ||
55 | static inline struct ar724x_pci_controller * | ||
56 | pci_bus_to_ar724x_controller(struct pci_bus *bus) | ||
57 | { | ||
58 | struct pci_controller *hose; | ||
59 | |||
60 | hose = (struct pci_controller *) bus->sysdata; | ||
61 | return container_of(hose, struct ar724x_pci_controller, pci_controller); | ||
62 | } | ||
63 | |||
47 | static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, | 64 | static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, |
48 | int size, uint32_t *value) | 65 | int size, uint32_t *value) |
49 | { | 66 | { |
67 | struct ar724x_pci_controller *apc; | ||
50 | unsigned long flags; | 68 | unsigned long flags; |
51 | void __iomem *base; | 69 | void __iomem *base; |
52 | u32 data; | 70 | u32 data; |
53 | 71 | ||
54 | if (!ar724x_pci_link_up) | 72 | apc = pci_bus_to_ar724x_controller(bus); |
73 | if (!apc->link_up) | ||
55 | return PCIBIOS_DEVICE_NOT_FOUND; | 74 | return PCIBIOS_DEVICE_NOT_FOUND; |
56 | 75 | ||
57 | if (devfn) | 76 | if (devfn) |
58 | return PCIBIOS_DEVICE_NOT_FOUND; | 77 | return PCIBIOS_DEVICE_NOT_FOUND; |
59 | 78 | ||
60 | base = ar724x_pci_devcfg_base; | 79 | base = apc->devcfg_base; |
61 | 80 | ||
62 | spin_lock_irqsave(&ar724x_pci_lock, flags); | 81 | spin_lock_irqsave(&apc->lock, flags); |
63 | data = __raw_readl(base + (where & ~3)); | 82 | data = __raw_readl(base + (where & ~3)); |
64 | 83 | ||
65 | switch (size) { | 84 | switch (size) { |
@@ -78,17 +97,17 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, | |||
78 | case 4: | 97 | case 4: |
79 | break; | 98 | break; |
80 | default: | 99 | default: |
81 | spin_unlock_irqrestore(&ar724x_pci_lock, flags); | 100 | spin_unlock_irqrestore(&apc->lock, flags); |
82 | 101 | ||
83 | return PCIBIOS_BAD_REGISTER_NUMBER; | 102 | return PCIBIOS_BAD_REGISTER_NUMBER; |
84 | } | 103 | } |
85 | 104 | ||
86 | spin_unlock_irqrestore(&ar724x_pci_lock, flags); | 105 | spin_unlock_irqrestore(&apc->lock, flags); |
87 | 106 | ||
88 | if (where == PCI_BASE_ADDRESS_0 && size == 4 && | 107 | if (where == PCI_BASE_ADDRESS_0 && size == 4 && |
89 | ar724x_pci_bar0_is_cached) { | 108 | apc->bar0_is_cached) { |
90 | /* use the cached value */ | 109 | /* use the cached value */ |
91 | *value = ar724x_pci_bar0_value; | 110 | *value = apc->bar0_value; |
92 | } else { | 111 | } else { |
93 | *value = data; | 112 | *value = data; |
94 | } | 113 | } |
@@ -99,12 +118,14 @@ static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, | |||
99 | static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, | 118 | static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, |
100 | int size, uint32_t value) | 119 | int size, uint32_t value) |
101 | { | 120 | { |
121 | struct ar724x_pci_controller *apc; | ||
102 | unsigned long flags; | 122 | unsigned long flags; |
103 | void __iomem *base; | 123 | void __iomem *base; |
104 | u32 data; | 124 | u32 data; |
105 | int s; | 125 | int s; |
106 | 126 | ||
107 | if (!ar724x_pci_link_up) | 127 | apc = pci_bus_to_ar724x_controller(bus); |
128 | if (!apc->link_up) | ||
108 | return PCIBIOS_DEVICE_NOT_FOUND; | 129 | return PCIBIOS_DEVICE_NOT_FOUND; |
109 | 130 | ||
110 | if (devfn) | 131 | if (devfn) |
@@ -122,18 +143,18 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, | |||
122 | * BAR0 register in order to make the device memory | 143 | * BAR0 register in order to make the device memory |
123 | * accessible. | 144 | * accessible. |
124 | */ | 145 | */ |
125 | ar724x_pci_bar0_is_cached = true; | 146 | apc->bar0_is_cached = true; |
126 | ar724x_pci_bar0_value = value; | 147 | apc->bar0_value = value; |
127 | 148 | ||
128 | value = AR7240_BAR0_WAR_VALUE; | 149 | value = AR7240_BAR0_WAR_VALUE; |
129 | } else { | 150 | } else { |
130 | ar724x_pci_bar0_is_cached = false; | 151 | apc->bar0_is_cached = false; |
131 | } | 152 | } |
132 | } | 153 | } |
133 | 154 | ||
134 | base = ar724x_pci_devcfg_base; | 155 | base = apc->devcfg_base; |
135 | 156 | ||
136 | spin_lock_irqsave(&ar724x_pci_lock, flags); | 157 | spin_lock_irqsave(&apc->lock, flags); |
137 | data = __raw_readl(base + (where & ~3)); | 158 | data = __raw_readl(base + (where & ~3)); |
138 | 159 | ||
139 | switch (size) { | 160 | switch (size) { |
@@ -151,7 +172,7 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, | |||
151 | data = value; | 172 | data = value; |
152 | break; | 173 | break; |
153 | default: | 174 | default: |
154 | spin_unlock_irqrestore(&ar724x_pci_lock, flags); | 175 | spin_unlock_irqrestore(&apc->lock, flags); |
155 | 176 | ||
156 | return PCIBIOS_BAD_REGISTER_NUMBER; | 177 | return PCIBIOS_BAD_REGISTER_NUMBER; |
157 | } | 178 | } |
@@ -159,7 +180,7 @@ static int ar724x_pci_write(struct pci_bus *bus, unsigned int devfn, int where, | |||
159 | __raw_writel(data, base + (where & ~3)); | 180 | __raw_writel(data, base + (where & ~3)); |
160 | /* flush write */ | 181 | /* flush write */ |
161 | __raw_readl(base + (where & ~3)); | 182 | __raw_readl(base + (where & ~3)); |
162 | spin_unlock_irqrestore(&ar724x_pci_lock, flags); | 183 | spin_unlock_irqrestore(&apc->lock, flags); |
163 | 184 | ||
164 | return PCIBIOS_SUCCESSFUL; | 185 | return PCIBIOS_SUCCESSFUL; |
165 | } | 186 | } |
@@ -183,18 +204,14 @@ static struct resource ar724x_mem_resource = { | |||
183 | .flags = IORESOURCE_MEM, | 204 | .flags = IORESOURCE_MEM, |
184 | }; | 205 | }; |
185 | 206 | ||
186 | static struct pci_controller ar724x_pci_controller = { | ||
187 | .pci_ops = &ar724x_pci_ops, | ||
188 | .io_resource = &ar724x_io_resource, | ||
189 | .mem_resource = &ar724x_mem_resource, | ||
190 | }; | ||
191 | |||
192 | static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc) | 207 | static void ar724x_pci_irq_handler(unsigned int irq, struct irq_desc *desc) |
193 | { | 208 | { |
209 | struct ar724x_pci_controller *apc; | ||
194 | void __iomem *base; | 210 | void __iomem *base; |
195 | u32 pending; | 211 | u32 pending; |
196 | 212 | ||
197 | base = ar724x_pci_ctrl_base; | 213 | apc = irq_get_handler_data(irq); |
214 | base = apc->ctrl_base; | ||
198 | 215 | ||
199 | pending = __raw_readl(base + AR724X_PCI_REG_INT_STATUS) & | 216 | pending = __raw_readl(base + AR724X_PCI_REG_INT_STATUS) & |
200 | __raw_readl(base + AR724X_PCI_REG_INT_MASK); | 217 | __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 | 225 | ||
209 | static void ar724x_pci_irq_unmask(struct irq_data *d) | 226 | static void ar724x_pci_irq_unmask(struct irq_data *d) |
210 | { | 227 | { |
228 | struct ar724x_pci_controller *apc; | ||
211 | void __iomem *base; | 229 | void __iomem *base; |
212 | u32 t; | 230 | u32 t; |
213 | 231 | ||
214 | base = ar724x_pci_ctrl_base; | 232 | apc = irq_data_get_irq_chip_data(d); |
233 | base = apc->ctrl_base; | ||
215 | 234 | ||
216 | switch (d->irq) { | 235 | switch (d->irq) { |
217 | case ATH79_PCI_IRQ(0): | 236 | case ATH79_PCI_IRQ(0): |
@@ -225,10 +244,12 @@ static void ar724x_pci_irq_unmask(struct irq_data *d) | |||
225 | 244 | ||
226 | static void ar724x_pci_irq_mask(struct irq_data *d) | 245 | static void ar724x_pci_irq_mask(struct irq_data *d) |
227 | { | 246 | { |
247 | struct ar724x_pci_controller *apc; | ||
228 | void __iomem *base; | 248 | void __iomem *base; |
229 | u32 t; | 249 | u32 t; |
230 | 250 | ||
231 | base = ar724x_pci_ctrl_base; | 251 | apc = irq_data_get_irq_chip_data(d); |
252 | base = apc->ctrl_base; | ||
232 | 253 | ||
233 | switch (d->irq) { | 254 | switch (d->irq) { |
234 | case ATH79_PCI_IRQ(0): | 255 | case ATH79_PCI_IRQ(0): |
@@ -255,12 +276,12 @@ static struct irq_chip ar724x_pci_irq_chip = { | |||
255 | .irq_mask_ack = ar724x_pci_irq_mask, | 276 | .irq_mask_ack = ar724x_pci_irq_mask, |
256 | }; | 277 | }; |
257 | 278 | ||
258 | static void ar724x_pci_irq_init(int irq) | 279 | static void ar724x_pci_irq_init(struct ar724x_pci_controller *apc) |
259 | { | 280 | { |
260 | void __iomem *base; | 281 | void __iomem *base; |
261 | int i; | 282 | int i; |
262 | 283 | ||
263 | base = ar724x_pci_ctrl_base; | 284 | base = apc->ctrl_base; |
264 | 285 | ||
265 | __raw_writel(0, base + AR724X_PCI_REG_INT_MASK); | 286 | __raw_writel(0, base + AR724X_PCI_REG_INT_MASK); |
266 | __raw_writel(0, base + AR724X_PCI_REG_INT_STATUS); | 287 | __raw_writel(0, base + AR724X_PCI_REG_INT_STATUS); |
@@ -268,45 +289,59 @@ static void ar724x_pci_irq_init(int irq) | |||
268 | BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR724X_PCI_IRQ_COUNT); | 289 | BUILD_BUG_ON(ATH79_PCI_IRQ_COUNT < AR724X_PCI_IRQ_COUNT); |
269 | 290 | ||
270 | for (i = ATH79_PCI_IRQ_BASE; | 291 | for (i = ATH79_PCI_IRQ_BASE; |
271 | i < ATH79_PCI_IRQ_BASE + AR724X_PCI_IRQ_COUNT; i++) | 292 | i < ATH79_PCI_IRQ_BASE + AR724X_PCI_IRQ_COUNT; i++) { |
272 | irq_set_chip_and_handler(i, &ar724x_pci_irq_chip, | 293 | irq_set_chip_and_handler(i, &ar724x_pci_irq_chip, |
273 | handle_level_irq); | 294 | handle_level_irq); |
295 | irq_set_chip_data(i, apc); | ||
296 | } | ||
274 | 297 | ||
275 | irq_set_chained_handler(irq, ar724x_pci_irq_handler); | 298 | irq_set_handler_data(apc->irq, apc); |
299 | irq_set_chained_handler(apc->irq, ar724x_pci_irq_handler); | ||
276 | } | 300 | } |
277 | 301 | ||
278 | static int ar724x_pci_probe(struct platform_device *pdev) | 302 | static int ar724x_pci_probe(struct platform_device *pdev) |
279 | { | 303 | { |
304 | struct ar724x_pci_controller *apc; | ||
280 | struct resource *res; | 305 | struct resource *res; |
281 | int irq; | 306 | |
307 | apc = devm_kzalloc(&pdev->dev, sizeof(struct ar724x_pci_controller), | ||
308 | GFP_KERNEL); | ||
309 | if (!apc) | ||
310 | return -ENOMEM; | ||
282 | 311 | ||
283 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl_base"); | 312 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl_base"); |
284 | if (!res) | 313 | if (!res) |
285 | return -EINVAL; | 314 | return -EINVAL; |
286 | 315 | ||
287 | ar724x_pci_ctrl_base = devm_request_and_ioremap(&pdev->dev, res); | 316 | apc->ctrl_base = devm_request_and_ioremap(&pdev->dev, res); |
288 | if (ar724x_pci_ctrl_base == NULL) | 317 | if (apc->ctrl_base == NULL) |
289 | return -EBUSY; | 318 | return -EBUSY; |
290 | 319 | ||
291 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg_base"); | 320 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg_base"); |
292 | if (!res) | 321 | if (!res) |
293 | return -EINVAL; | 322 | return -EINVAL; |
294 | 323 | ||
295 | ar724x_pci_devcfg_base = devm_request_and_ioremap(&pdev->dev, res); | 324 | apc->devcfg_base = devm_request_and_ioremap(&pdev->dev, res); |
296 | if (!ar724x_pci_devcfg_base) | 325 | if (!apc->devcfg_base) |
297 | return -EBUSY; | 326 | return -EBUSY; |
298 | 327 | ||
299 | irq = platform_get_irq(pdev, 0); | 328 | apc->irq = platform_get_irq(pdev, 0); |
300 | if (irq < 0) | 329 | if (apc->irq < 0) |
301 | return -EINVAL; | 330 | return -EINVAL; |
302 | 331 | ||
303 | ar724x_pci_link_up = ar724x_pci_check_link(); | 332 | spin_lock_init(&apc->lock); |
304 | if (!ar724x_pci_link_up) | 333 | |
334 | apc->pci_controller.pci_ops = &ar724x_pci_ops; | ||
335 | apc->pci_controller.io_resource = &ar724x_io_resource; | ||
336 | apc->pci_controller.mem_resource = &ar724x_mem_resource; | ||
337 | |||
338 | apc->link_up = ar724x_pci_check_link(apc); | ||
339 | if (!apc->link_up) | ||
305 | dev_warn(&pdev->dev, "PCIe link is down\n"); | 340 | dev_warn(&pdev->dev, "PCIe link is down\n"); |
306 | 341 | ||
307 | ar724x_pci_irq_init(irq); | 342 | ar724x_pci_irq_init(apc); |
308 | 343 | ||
309 | register_pci_controller(&ar724x_pci_controller); | 344 | register_pci_controller(&apc->pci_controller); |
310 | 345 | ||
311 | return 0; | 346 | return 0; |
312 | } | 347 | } |