Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.2 541 lines 15 kB view raw
1/* 2 * Support for Celleb PCI-Express. 3 * 4 * (C) Copyright 2007-2008 TOSHIBA CORPORATION 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License along 17 * with this program; if not, write to the Free Software Foundation, Inc., 18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 21#undef DEBUG 22 23#include <linux/kernel.h> 24#include <linux/pci.h> 25#include <linux/string.h> 26#include <linux/slab.h> 27#include <linux/init.h> 28#include <linux/bootmem.h> 29#include <linux/delay.h> 30#include <linux/interrupt.h> 31 32#include <asm/io.h> 33#include <asm/irq.h> 34#include <asm/iommu.h> 35#include <asm/byteorder.h> 36 37#include "celleb_scc.h" 38#include "celleb_pci.h" 39 40#define PEX_IN(base, off) in_be32((void __iomem *)(base) + (off)) 41#define PEX_OUT(base, off, data) out_be32((void __iomem *)(base) + (off), (data)) 42 43static void scc_pciex_io_flush(struct iowa_bus *bus) 44{ 45 (void)PEX_IN(bus->phb->cfg_addr, PEXDMRDEN0); 46} 47 48/* 49 * Memory space access to device on PCIEX 50 */ 51#define PCIEX_MMIO_READ(name, ret) \ 52static ret scc_pciex_##name(const PCI_IO_ADDR addr) \ 53{ \ 54 ret val = __do_##name(addr); \ 55 scc_pciex_io_flush(iowa_mem_find_bus(addr)); \ 56 return val; \ 57} 58 59#define PCIEX_MMIO_READ_STR(name) \ 60static void scc_pciex_##name(const PCI_IO_ADDR addr, void *buf, \ 61 unsigned long count) \ 62{ \ 63 __do_##name(addr, buf, count); \ 64 scc_pciex_io_flush(iowa_mem_find_bus(addr)); \ 65} 66 67PCIEX_MMIO_READ(readb, u8) 68PCIEX_MMIO_READ(readw, u16) 69PCIEX_MMIO_READ(readl, u32) 70PCIEX_MMIO_READ(readq, u64) 71PCIEX_MMIO_READ(readw_be, u16) 72PCIEX_MMIO_READ(readl_be, u32) 73PCIEX_MMIO_READ(readq_be, u64) 74PCIEX_MMIO_READ_STR(readsb) 75PCIEX_MMIO_READ_STR(readsw) 76PCIEX_MMIO_READ_STR(readsl) 77 78static void scc_pciex_memcpy_fromio(void *dest, const PCI_IO_ADDR src, 79 unsigned long n) 80{ 81 __do_memcpy_fromio(dest, src, n); 82 scc_pciex_io_flush(iowa_mem_find_bus(src)); 83} 84 85/* 86 * I/O port access to devices on PCIEX. 87 */ 88 89static inline unsigned long get_bus_address(struct pci_controller *phb, 90 unsigned long port) 91{ 92 return port - ((unsigned long)(phb->io_base_virt) - _IO_BASE); 93} 94 95static u32 scc_pciex_read_port(struct pci_controller *phb, 96 unsigned long port, int size) 97{ 98 unsigned int byte_enable; 99 unsigned int cmd, shift; 100 unsigned long addr; 101 u32 data, ret; 102 103 BUG_ON(((port & 0x3ul) + size) > 4); 104 105 addr = get_bus_address(phb, port); 106 shift = addr & 0x3ul; 107 byte_enable = ((1 << size) - 1) << shift; 108 cmd = PEXDCMND_IO_READ | (byte_enable << PEXDCMND_BYTE_EN_SHIFT); 109 PEX_OUT(phb->cfg_addr, PEXDADRS, (addr & ~0x3ul)); 110 PEX_OUT(phb->cfg_addr, PEXDCMND, cmd); 111 data = PEX_IN(phb->cfg_addr, PEXDRDATA); 112 ret = (data >> (shift * 8)) & (0xFFFFFFFF >> ((4 - size) * 8)); 113 114 pr_debug("PCIEX:PIO READ:port=0x%lx, addr=0x%lx, size=%d, be=%x," 115 " cmd=%x, data=%x, ret=%x\n", port, addr, size, byte_enable, 116 cmd, data, ret); 117 118 return ret; 119} 120 121static void scc_pciex_write_port(struct pci_controller *phb, 122 unsigned long port, int size, u32 val) 123{ 124 unsigned int byte_enable; 125 unsigned int cmd, shift; 126 unsigned long addr; 127 u32 data; 128 129 BUG_ON(((port & 0x3ul) + size) > 4); 130 131 addr = get_bus_address(phb, port); 132 shift = addr & 0x3ul; 133 byte_enable = ((1 << size) - 1) << shift; 134 cmd = PEXDCMND_IO_WRITE | (byte_enable << PEXDCMND_BYTE_EN_SHIFT); 135 data = (val & (0xFFFFFFFF >> (4 - size) * 8)) << (shift * 8); 136 PEX_OUT(phb->cfg_addr, PEXDADRS, (addr & ~0x3ul)); 137 PEX_OUT(phb->cfg_addr, PEXDCMND, cmd); 138 PEX_OUT(phb->cfg_addr, PEXDWDATA, data); 139 140 pr_debug("PCIEX:PIO WRITE:port=0x%lx, addr=%lx, size=%d, val=%x," 141 " be=%x, cmd=%x, data=%x\n", port, addr, size, val, 142 byte_enable, cmd, data); 143} 144 145static u8 __scc_pciex_inb(struct pci_controller *phb, unsigned long port) 146{ 147 return (u8)scc_pciex_read_port(phb, port, 1); 148} 149 150static u16 __scc_pciex_inw(struct pci_controller *phb, unsigned long port) 151{ 152 u32 data; 153 if ((port & 0x3ul) < 3) 154 data = scc_pciex_read_port(phb, port, 2); 155 else { 156 u32 d1 = scc_pciex_read_port(phb, port, 1); 157 u32 d2 = scc_pciex_read_port(phb, port + 1, 1); 158 data = d1 | (d2 << 8); 159 } 160 return (u16)data; 161} 162 163static u32 __scc_pciex_inl(struct pci_controller *phb, unsigned long port) 164{ 165 unsigned int mod = port & 0x3ul; 166 u32 data; 167 if (mod == 0) 168 data = scc_pciex_read_port(phb, port, 4); 169 else { 170 u32 d1 = scc_pciex_read_port(phb, port, 4 - mod); 171 u32 d2 = scc_pciex_read_port(phb, port + 1, mod); 172 data = d1 | (d2 << (mod * 8)); 173 } 174 return data; 175} 176 177static void __scc_pciex_outb(struct pci_controller *phb, 178 u8 val, unsigned long port) 179{ 180 scc_pciex_write_port(phb, port, 1, (u32)val); 181} 182 183static void __scc_pciex_outw(struct pci_controller *phb, 184 u16 val, unsigned long port) 185{ 186 if ((port & 0x3ul) < 3) 187 scc_pciex_write_port(phb, port, 2, (u32)val); 188 else { 189 u32 d1 = val & 0x000000FF; 190 u32 d2 = (val & 0x0000FF00) >> 8; 191 scc_pciex_write_port(phb, port, 1, d1); 192 scc_pciex_write_port(phb, port + 1, 1, d2); 193 } 194} 195 196static void __scc_pciex_outl(struct pci_controller *phb, 197 u32 val, unsigned long port) 198{ 199 unsigned int mod = port & 0x3ul; 200 if (mod == 0) 201 scc_pciex_write_port(phb, port, 4, val); 202 else { 203 u32 d1 = val & (0xFFFFFFFFul >> (mod * 8)); 204 u32 d2 = val >> ((4 - mod) * 8); 205 scc_pciex_write_port(phb, port, 4 - mod, d1); 206 scc_pciex_write_port(phb, port + 1, mod, d2); 207 } 208} 209 210#define PCIEX_PIO_FUNC(size, name) \ 211static u##size scc_pciex_in##name(unsigned long port) \ 212{ \ 213 struct iowa_bus *bus = iowa_pio_find_bus(port); \ 214 u##size data = __scc_pciex_in##name(bus->phb, port); \ 215 scc_pciex_io_flush(bus); \ 216 return data; \ 217} \ 218static void scc_pciex_ins##name(unsigned long p, void *b, unsigned long c) \ 219{ \ 220 struct iowa_bus *bus = iowa_pio_find_bus(p); \ 221 __le##size *dst = b; \ 222 for (; c != 0; c--, dst++) \ 223 *dst = cpu_to_le##size(__scc_pciex_in##name(bus->phb, p)); \ 224 scc_pciex_io_flush(bus); \ 225} \ 226static void scc_pciex_out##name(u##size val, unsigned long port) \ 227{ \ 228 struct iowa_bus *bus = iowa_pio_find_bus(port); \ 229 __scc_pciex_out##name(bus->phb, val, port); \ 230} \ 231static void scc_pciex_outs##name(unsigned long p, const void *b, \ 232 unsigned long c) \ 233{ \ 234 struct iowa_bus *bus = iowa_pio_find_bus(p); \ 235 const __le##size *src = b; \ 236 for (; c != 0; c--, src++) \ 237 __scc_pciex_out##name(bus->phb, le##size##_to_cpu(*src), p); \ 238} 239#define __le8 u8 240#define cpu_to_le8(x) (x) 241#define le8_to_cpu(x) (x) 242PCIEX_PIO_FUNC(8, b) 243PCIEX_PIO_FUNC(16, w) 244PCIEX_PIO_FUNC(32, l) 245 246static struct ppc_pci_io scc_pciex_ops = { 247 .readb = scc_pciex_readb, 248 .readw = scc_pciex_readw, 249 .readl = scc_pciex_readl, 250 .readq = scc_pciex_readq, 251 .readw_be = scc_pciex_readw_be, 252 .readl_be = scc_pciex_readl_be, 253 .readq_be = scc_pciex_readq_be, 254 .readsb = scc_pciex_readsb, 255 .readsw = scc_pciex_readsw, 256 .readsl = scc_pciex_readsl, 257 .memcpy_fromio = scc_pciex_memcpy_fromio, 258 .inb = scc_pciex_inb, 259 .inw = scc_pciex_inw, 260 .inl = scc_pciex_inl, 261 .outb = scc_pciex_outb, 262 .outw = scc_pciex_outw, 263 .outl = scc_pciex_outl, 264 .insb = scc_pciex_insb, 265 .insw = scc_pciex_insw, 266 .insl = scc_pciex_insl, 267 .outsb = scc_pciex_outsb, 268 .outsw = scc_pciex_outsw, 269 .outsl = scc_pciex_outsl, 270}; 271 272static int __init scc_pciex_iowa_init(struct iowa_bus *bus, void *data) 273{ 274 dma_addr_t dummy_page_da; 275 void *dummy_page_va; 276 277 dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL); 278 if (!dummy_page_va) { 279 pr_err("PCIEX:Alloc dummy_page_va failed\n"); 280 return -1; 281 } 282 283 dummy_page_da = dma_map_single(bus->phb->parent, dummy_page_va, 284 PAGE_SIZE, DMA_FROM_DEVICE); 285 if (dma_mapping_error(bus->phb->parent, dummy_page_da)) { 286 pr_err("PCIEX:Map dummy page failed.\n"); 287 kfree(dummy_page_va); 288 return -1; 289 } 290 291 PEX_OUT(bus->phb->cfg_addr, PEXDMRDADR0, dummy_page_da); 292 293 return 0; 294} 295 296/* 297 * config space access 298 */ 299#define MK_PEXDADRS(bus_no, dev_no, func_no, addr) \ 300 ((uint32_t)(((addr) & ~0x3UL) | \ 301 ((bus_no) << PEXDADRS_BUSNO_SHIFT) | \ 302 ((dev_no) << PEXDADRS_DEVNO_SHIFT) | \ 303 ((func_no) << PEXDADRS_FUNCNO_SHIFT))) 304 305#define MK_PEXDCMND_BYTE_EN(addr, size) \ 306 ((((0x1 << (size))-1) << ((addr) & 0x3)) << PEXDCMND_BYTE_EN_SHIFT) 307#define MK_PEXDCMND(cmd, addr, size) ((cmd) | MK_PEXDCMND_BYTE_EN(addr, size)) 308 309static uint32_t config_read_pciex_dev(unsigned int __iomem *base, 310 uint64_t bus_no, uint64_t dev_no, uint64_t func_no, 311 uint64_t off, uint64_t size) 312{ 313 uint32_t ret; 314 uint32_t addr, cmd; 315 316 addr = MK_PEXDADRS(bus_no, dev_no, func_no, off); 317 cmd = MK_PEXDCMND(PEXDCMND_CONFIG_READ, off, size); 318 PEX_OUT(base, PEXDADRS, addr); 319 PEX_OUT(base, PEXDCMND, cmd); 320 ret = (PEX_IN(base, PEXDRDATA) 321 >> ((off & (4-size)) * 8)) & ((0x1 << (size * 8)) - 1); 322 return ret; 323} 324 325static void config_write_pciex_dev(unsigned int __iomem *base, uint64_t bus_no, 326 uint64_t dev_no, uint64_t func_no, uint64_t off, uint64_t size, 327 uint32_t data) 328{ 329 uint32_t addr, cmd; 330 331 addr = MK_PEXDADRS(bus_no, dev_no, func_no, off); 332 cmd = MK_PEXDCMND(PEXDCMND_CONFIG_WRITE, off, size); 333 PEX_OUT(base, PEXDADRS, addr); 334 PEX_OUT(base, PEXDCMND, cmd); 335 PEX_OUT(base, PEXDWDATA, 336 (data & ((0x1 << (size * 8)) - 1)) << ((off & (4-size)) * 8)); 337} 338 339#define MK_PEXCADRS_BYTE_EN(off, len) \ 340 ((((0x1 << (len)) - 1) << ((off) & 0x3)) << PEXCADRS_BYTE_EN_SHIFT) 341#define MK_PEXCADRS(cmd, addr, size) \ 342 ((cmd) | MK_PEXCADRS_BYTE_EN(addr, size) | ((addr) & ~0x3)) 343static uint32_t config_read_pciex_rc(unsigned int __iomem *base, 344 uint32_t where, uint32_t size) 345{ 346 PEX_OUT(base, PEXCADRS, MK_PEXCADRS(PEXCADRS_CMD_READ, where, size)); 347 return (PEX_IN(base, PEXCRDATA) 348 >> ((where & (4 - size)) * 8)) & ((0x1 << (size * 8)) - 1); 349} 350 351static void config_write_pciex_rc(unsigned int __iomem *base, uint32_t where, 352 uint32_t size, uint32_t val) 353{ 354 uint32_t data; 355 356 data = (val & ((0x1 << (size * 8)) - 1)) << ((where & (4 - size)) * 8); 357 PEX_OUT(base, PEXCADRS, MK_PEXCADRS(PEXCADRS_CMD_WRITE, where, size)); 358 PEX_OUT(base, PEXCWDATA, data); 359} 360 361/* Interfaces */ 362/* Note: Work-around 363 * On SCC PCIEXC, one device is seen on all 32 dev_no. 364 * As SCC PCIEXC can have only one device on the bus, we look only one dev_no. 365 * (dev_no = 1) 366 */ 367static int scc_pciex_read_config(struct pci_bus *bus, unsigned int devfn, 368 int where, int size, unsigned int *val) 369{ 370 struct pci_controller *phb = pci_bus_to_host(bus); 371 372 if (bus->number == phb->first_busno && PCI_SLOT(devfn) != 1) { 373 *val = ~0; 374 return PCIBIOS_DEVICE_NOT_FOUND; 375 } 376 377 if (bus->number == 0 && PCI_SLOT(devfn) == 0) 378 *val = config_read_pciex_rc(phb->cfg_addr, where, size); 379 else 380 *val = config_read_pciex_dev(phb->cfg_addr, bus->number, 381 PCI_SLOT(devfn), PCI_FUNC(devfn), where, size); 382 383 return PCIBIOS_SUCCESSFUL; 384} 385 386static int scc_pciex_write_config(struct pci_bus *bus, unsigned int devfn, 387 int where, int size, unsigned int val) 388{ 389 struct pci_controller *phb = pci_bus_to_host(bus); 390 391 if (bus->number == phb->first_busno && PCI_SLOT(devfn) != 1) 392 return PCIBIOS_DEVICE_NOT_FOUND; 393 394 if (bus->number == 0 && PCI_SLOT(devfn) == 0) 395 config_write_pciex_rc(phb->cfg_addr, where, size, val); 396 else 397 config_write_pciex_dev(phb->cfg_addr, bus->number, 398 PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val); 399 return PCIBIOS_SUCCESSFUL; 400} 401 402static struct pci_ops scc_pciex_pci_ops = { 403 scc_pciex_read_config, 404 scc_pciex_write_config, 405}; 406 407static void pciex_clear_intr_all(unsigned int __iomem *base) 408{ 409 PEX_OUT(base, PEXAERRSTS, 0xffffffff); 410 PEX_OUT(base, PEXPRERRSTS, 0xffffffff); 411 PEX_OUT(base, PEXINTSTS, 0xffffffff); 412} 413 414#if 0 415static void pciex_disable_intr_all(unsigned int *base) 416{ 417 PEX_OUT(base, PEXINTMASK, 0x0); 418 PEX_OUT(base, PEXAERRMASK, 0x0); 419 PEX_OUT(base, PEXPRERRMASK, 0x0); 420 PEX_OUT(base, PEXVDMASK, 0x0); 421} 422#endif 423 424static void pciex_enable_intr_all(unsigned int __iomem *base) 425{ 426 PEX_OUT(base, PEXINTMASK, 0x0000e7f1); 427 PEX_OUT(base, PEXAERRMASK, 0x03ff01ff); 428 PEX_OUT(base, PEXPRERRMASK, 0x0001010f); 429 PEX_OUT(base, PEXVDMASK, 0x00000001); 430} 431 432static void pciex_check_status(unsigned int __iomem *base) 433{ 434 uint32_t err = 0; 435 uint32_t intsts, aerr, prerr, rcvcp, lenerr; 436 uint32_t maea, maec; 437 438 intsts = PEX_IN(base, PEXINTSTS); 439 aerr = PEX_IN(base, PEXAERRSTS); 440 prerr = PEX_IN(base, PEXPRERRSTS); 441 rcvcp = PEX_IN(base, PEXRCVCPLIDA); 442 lenerr = PEX_IN(base, PEXLENERRIDA); 443 444 if (intsts || aerr || prerr || rcvcp || lenerr) 445 err = 1; 446 447 pr_info("PCEXC interrupt!!\n"); 448 pr_info("PEXINTSTS :0x%08x\n", intsts); 449 pr_info("PEXAERRSTS :0x%08x\n", aerr); 450 pr_info("PEXPRERRSTS :0x%08x\n", prerr); 451 pr_info("PEXRCVCPLIDA :0x%08x\n", rcvcp); 452 pr_info("PEXLENERRIDA :0x%08x\n", lenerr); 453 454 /* print detail of Protection Error */ 455 if (intsts & 0x00004000) { 456 uint32_t i, n; 457 for (i = 0; i < 4; i++) { 458 n = 1 << i; 459 if (prerr & n) { 460 maea = PEX_IN(base, PEXMAEA(i)); 461 maec = PEX_IN(base, PEXMAEC(i)); 462 pr_info("PEXMAEC%d :0x%08x\n", i, maec); 463 pr_info("PEXMAEA%d :0x%08x\n", i, maea); 464 } 465 } 466 } 467 468 if (err) 469 pciex_clear_intr_all(base); 470} 471 472static irqreturn_t pciex_handle_internal_irq(int irq, void *dev_id) 473{ 474 struct pci_controller *phb = dev_id; 475 476 pr_debug("PCIEX:pciex_handle_internal_irq(irq=%d)\n", irq); 477 478 BUG_ON(phb->cfg_addr == NULL); 479 480 pciex_check_status(phb->cfg_addr); 481 482 return IRQ_HANDLED; 483} 484 485static __init int celleb_setup_pciex(struct device_node *node, 486 struct pci_controller *phb) 487{ 488 struct resource r; 489 struct of_irq oirq; 490 int virq; 491 492 /* SMMIO registers; used inside this file */ 493 if (of_address_to_resource(node, 0, &r)) { 494 pr_err("PCIEXC:Failed to get config resource.\n"); 495 return 1; 496 } 497 phb->cfg_addr = ioremap(r.start, resource_size(&r)); 498 if (!phb->cfg_addr) { 499 pr_err("PCIEXC:Failed to remap SMMIO region.\n"); 500 return 1; 501 } 502 503 /* Not use cfg_data, cmd and data regs are near address reg */ 504 phb->cfg_data = NULL; 505 506 /* set pci_ops */ 507 phb->ops = &scc_pciex_pci_ops; 508 509 /* internal interrupt handler */ 510 if (of_irq_map_one(node, 1, &oirq)) { 511 pr_err("PCIEXC:Failed to map irq\n"); 512 goto error; 513 } 514 virq = irq_create_of_mapping(oirq.controller, oirq.specifier, 515 oirq.size); 516 if (request_irq(virq, pciex_handle_internal_irq, 517 0, "pciex", (void *)phb)) { 518 pr_err("PCIEXC:Failed to request irq\n"); 519 goto error; 520 } 521 522 /* enable all interrupts */ 523 pciex_clear_intr_all(phb->cfg_addr); 524 pciex_enable_intr_all(phb->cfg_addr); 525 /* MSI: TBD */ 526 527 return 0; 528 529error: 530 phb->cfg_data = NULL; 531 if (phb->cfg_addr) 532 iounmap(phb->cfg_addr); 533 phb->cfg_addr = NULL; 534 return 1; 535} 536 537struct celleb_phb_spec celleb_pciex_spec __initdata = { 538 .setup = celleb_setup_pciex, 539 .ops = &scc_pciex_ops, 540 .iowa_init = &scc_pciex_iowa_init, 541};