Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pci-xlr.c
Go to the documentation of this file.
1 /*
2  * Copyright 2003-2011 NetLogic Microsystems, Inc. (NetLogic). All rights
3  * reserved.
4  *
5  * This software is available to you under a choice of one of two
6  * licenses. You may choose to be licensed under the terms of the GNU
7  * General Public License (GPL) Version 2, available from the file
8  * COPYING in the main directory of this source tree, or the NetLogic
9  * license below:
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  *
15  * 1. Redistributions of source code must retain the above copyright
16  * notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  * notice, this list of conditions and the following disclaimer in
19  * the documentation and/or other materials provided with the
20  * distribution.
21  *
22  * THIS SOFTWARE IS PROVIDED BY NETLOGIC ``AS IS'' AND ANY EXPRESS OR
23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL NETLOGIC OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
29  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
31  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
32  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include <linux/types.h>
36 #include <linux/pci.h>
37 #include <linux/kernel.h>
38 #include <linux/init.h>
39 #include <linux/msi.h>
40 #include <linux/mm.h>
41 #include <linux/irq.h>
42 #include <linux/irqdesc.h>
43 #include <linux/console.h>
44 #include <linux/pci_regs.h>
45 
46 #include <asm/io.h>
47 
48 #include <asm/netlogic/interrupt.h>
49 #include <asm/netlogic/haldefs.h>
50 
52 #include <asm/netlogic/xlr/iomap.h>
53 #include <asm/netlogic/xlr/pic.h>
54 #include <asm/netlogic/xlr/xlr.h>
55 
56 static void *pci_config_base;
57 
58 #define pci_cfg_addr(bus, devfn, off) (((bus) << 16) | ((devfn) << 8) | (off))
59 
60 /* PCI ops */
61 static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn,
62  int where)
63 {
64  u32 data;
65  u32 *cfgaddr;
66 
67  cfgaddr = (u32 *)(pci_config_base +
68  pci_cfg_addr(bus->number, devfn, where & ~3));
69  data = *cfgaddr;
70  return cpu_to_le32(data);
71 }
72 
73 static inline void pci_cfg_write_32bit(struct pci_bus *bus, unsigned int devfn,
74  int where, u32 data)
75 {
76  u32 *cfgaddr;
77 
78  cfgaddr = (u32 *)(pci_config_base +
79  pci_cfg_addr(bus->number, devfn, where & ~3));
80  *cfgaddr = cpu_to_le32(data);
81 }
82 
83 static int nlm_pcibios_read(struct pci_bus *bus, unsigned int devfn,
84  int where, int size, u32 *val)
85 {
86  u32 data;
87 
88  if ((size == 2) && (where & 1))
90  else if ((size == 4) && (where & 3))
92 
93  data = pci_cfg_read_32bit(bus, devfn, where);
94 
95  if (size == 1)
96  *val = (data >> ((where & 3) << 3)) & 0xff;
97  else if (size == 2)
98  *val = (data >> ((where & 3) << 3)) & 0xffff;
99  else
100  *val = data;
101 
102  return PCIBIOS_SUCCESSFUL;
103 }
104 
105 
106 static int nlm_pcibios_write(struct pci_bus *bus, unsigned int devfn,
107  int where, int size, u32 val)
108 {
109  u32 data;
110 
111  if ((size == 2) && (where & 1))
113  else if ((size == 4) && (where & 3))
115 
116  data = pci_cfg_read_32bit(bus, devfn, where);
117 
118  if (size == 1)
119  data = (data & ~(0xff << ((where & 3) << 3))) |
120  (val << ((where & 3) << 3));
121  else if (size == 2)
122  data = (data & ~(0xffff << ((where & 3) << 3))) |
123  (val << ((where & 3) << 3));
124  else
125  data = val;
126 
127  pci_cfg_write_32bit(bus, devfn, where, data);
128 
129  return PCIBIOS_SUCCESSFUL;
130 }
131 
133  .read = nlm_pcibios_read,
134  .write = nlm_pcibios_write
135 };
136 
137 static struct resource nlm_pci_mem_resource = {
138  .name = "XLR PCI MEM",
139  .start = 0xd0000000UL, /* 256MB PCI mem @ 0xd000_0000 */
140  .end = 0xdfffffffUL,
141  .flags = IORESOURCE_MEM,
142 };
143 
144 static struct resource nlm_pci_io_resource = {
145  .name = "XLR IO MEM",
146  .start = 0x10000000UL, /* 16MB PCI IO @ 0x1000_0000 */
147  .end = 0x100fffffUL,
148  .flags = IORESOURCE_IO,
149 };
150 
152  .index = 0,
153  .pci_ops = &nlm_pci_ops,
154  .mem_resource = &nlm_pci_mem_resource,
155  .mem_offset = 0x00000000UL,
156  .io_resource = &nlm_pci_io_resource,
157  .io_offset = 0x00000000UL,
158 };
159 
160 /*
161  * The top level PCIe links on the XLS PCIe controller appear as
162  * bridges. Given a device, this function finds which link it is
163  * on.
164  */
165 static struct pci_dev *xls_get_pcie_link(const struct pci_dev *dev)
166 {
167  struct pci_bus *bus, *p;
168 
169  /* Find the bridge on bus 0 */
170  bus = dev->bus;
171  for (p = bus->parent; p && p->number != 0; p = p->parent)
172  bus = p;
173 
174  return p ? bus->self : NULL;
175 }
176 
177 static int get_irq_vector(const struct pci_dev *dev)
178 {
179  struct pci_dev *lnk;
180 
181  if (!nlm_chip_is_xls())
182  return PIC_PCIX_IRQ; /* for XLR just one IRQ */
183 
184  /*
185  * For XLS PCIe, there is an IRQ per Link, find out which
186  * link the device is on to assign interrupts
187  */
188  lnk = xls_get_pcie_link(dev);
189  if (lnk == NULL)
190  return 0;
191 
192  switch (PCI_SLOT(lnk->devfn)) {
193  case 0:
194  return PIC_PCIE_LINK0_IRQ;
195  case 1:
196  return PIC_PCIE_LINK1_IRQ;
197  case 2:
198  if (nlm_chip_is_xls_b())
200  else
201  return PIC_PCIE_LINK2_IRQ;
202  case 3:
203  if (nlm_chip_is_xls_b())
205  else
206  return PIC_PCIE_LINK3_IRQ;
207  }
208  WARN(1, "Unexpected devfn %d\n", lnk->devfn);
209  return 0;
210 }
211 
212 #ifdef CONFIG_PCI_MSI
213 void destroy_irq(unsigned int irq)
214 {
215  /* nothing to do yet */
216 }
217 
218 void arch_teardown_msi_irq(unsigned int irq)
219 {
220  destroy_irq(irq);
221 }
222 
223 int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
224 {
225  struct msi_msg msg;
226  struct pci_dev *lnk;
227  int irq, ret;
228  u16 val;
229 
230  /* MSI not supported on XLR */
231  if (!nlm_chip_is_xls())
232  return 1;
233 
234  /*
235  * Enable MSI on the XLS PCIe controller bridge which was disabled
236  * at enumeration, the bridge MSI capability is at 0x50
237  */
238  lnk = xls_get_pcie_link(dev);
239  if (lnk == NULL)
240  return 1;
241 
242  pci_read_config_word(lnk, 0x50 + PCI_MSI_FLAGS, &val);
243  if ((val & PCI_MSI_FLAGS_ENABLE) == 0) {
244  val |= PCI_MSI_FLAGS_ENABLE;
245  pci_write_config_word(lnk, 0x50 + PCI_MSI_FLAGS, val);
246  }
247 
248  irq = get_irq_vector(dev);
249  if (irq <= 0)
250  return 1;
251 
252  msg.address_hi = MSI_ADDR_BASE_HI;
253  msg.address_lo = MSI_ADDR_BASE_LO |
256 
257  msg.data = MSI_DATA_TRIGGER_EDGE |
260 
261  ret = irq_set_msi_desc(irq, desc);
262  if (ret < 0) {
263  destroy_irq(irq);
264  return ret;
265  }
266 
267  write_msi_msg(irq, &msg);
268  return 0;
269 }
270 #endif
271 
272 /* Extra ACK needed for XLR on chip PCI controller */
273 static void xlr_pci_ack(struct irq_data *d)
274 {
275  uint64_t pcibase = nlm_mmio_base(NETLOGIC_IO_PCIX_OFFSET);
276 
277  nlm_read_reg(pcibase, (0x140 >> 2));
278 }
279 
280 /* Extra ACK needed for XLS on chip PCIe controller */
281 static void xls_pcie_ack(struct irq_data *d)
282 {
283  uint64_t pciebase_le = nlm_mmio_base(NETLOGIC_IO_PCIE_1_OFFSET);
284 
285  switch (d->irq) {
286  case PIC_PCIE_LINK0_IRQ:
287  nlm_write_reg(pciebase_le, (0x90 >> 2), 0xffffffff);
288  break;
289  case PIC_PCIE_LINK1_IRQ:
290  nlm_write_reg(pciebase_le, (0x94 >> 2), 0xffffffff);
291  break;
292  case PIC_PCIE_LINK2_IRQ:
293  nlm_write_reg(pciebase_le, (0x190 >> 2), 0xffffffff);
294  break;
295  case PIC_PCIE_LINK3_IRQ:
296  nlm_write_reg(pciebase_le, (0x194 >> 2), 0xffffffff);
297  break;
298  }
299 }
300 
301 /* For XLS B silicon, the 3,4 PCI interrupts are different */
302 static void xls_pcie_ack_b(struct irq_data *d)
303 {
304  uint64_t pciebase_le = nlm_mmio_base(NETLOGIC_IO_PCIE_1_OFFSET);
305 
306  switch (d->irq) {
307  case PIC_PCIE_LINK0_IRQ:
308  nlm_write_reg(pciebase_le, (0x90 >> 2), 0xffffffff);
309  break;
310  case PIC_PCIE_LINK1_IRQ:
311  nlm_write_reg(pciebase_le, (0x94 >> 2), 0xffffffff);
312  break;
314  nlm_write_reg(pciebase_le, (0x190 >> 2), 0xffffffff);
315  break;
317  nlm_write_reg(pciebase_le, (0x194 >> 2), 0xffffffff);
318  break;
319  }
320 }
321 
322 int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
323 {
324  return get_irq_vector(dev);
325 }
326 
327 /* Do platform specific device initialization at pci_enable_device() time */
329 {
330  return 0;
331 }
332 
333 static int __init pcibios_init(void)
334 {
335  /* PSB assigns PCI resources */
336  pci_set_flags(PCI_PROBE_ONLY);
337  pci_config_base = ioremap(DEFAULT_PCI_CONFIG_BASE, 16 << 20);
338 
339  /* Extend IO port for memory mapped io */
340  ioport_resource.start = 0;
341  ioport_resource.end = ~0;
342 
343  set_io_port_base(CKSEG1);
344  nlm_pci_controller.io_map_base = CKSEG1;
345 
346  pr_info("Registering XLR/XLS PCIX/PCIE Controller.\n");
347  register_pci_controller(&nlm_pci_controller);
348 
349  /*
350  * For PCI interrupts, we need to ack the PCI controller too, overload
351  * irq handler data to do this
352  */
353  if (nlm_chip_is_xls()) {
354  if (nlm_chip_is_xls_b()) {
356  xls_pcie_ack_b);
358  xls_pcie_ack_b);
360  xls_pcie_ack_b);
362  xls_pcie_ack_b);
363  } else {
368  }
369  } else {
370  /* XLR PCI controller ACK */
371  irq_set_handler_data(PIC_PCIX_IRQ, xlr_pci_ack);
372  }
373 
374  return 0;
375 }
376 
377 arch_initcall(pcibios_init);