1/* 2 * Support PCI/PCIe on PowerNV platforms 3 * 4 * Currently supports only P5IOC2 5 * 6 * Copyright 2011 Benjamin Herrenschmidt, IBM Corp. 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * as published by the Free Software Foundation; either version 11 * 2 of the License, or (at your option) any later version. 12 */ 13 14#include <linux/kernel.h> 15#include <linux/pci.h> 16#include <linux/delay.h> 17#include <linux/string.h> 18#include <linux/init.h> 19#include <linux/bootmem.h> 20#include <linux/irq.h> 21#include <linux/io.h> 22#include <linux/msi.h> 23 24#include <asm/sections.h> 25#include <asm/io.h> 26#include <asm/prom.h> 27#include <asm/pci-bridge.h> 28#include <asm/machdep.h> 29#include <asm/msi_bitmap.h> 30#include <asm/ppc-pci.h> 31#include <asm/opal.h> 32#include <asm/iommu.h> 33#include <asm/tce.h> 34 35#include "powernv.h" 36#include "pci.h" 37 38/* For now, use a fixed amount of TCE memory for each p5ioc2 39 * hub, 16M will do 40 */ 41#define P5IOC2_TCE_MEMORY 0x01000000 42 43#ifdef CONFIG_PCI_MSI 44static int pnv_pci_p5ioc2_msi_setup(struct pnv_phb *phb, struct pci_dev *dev, 45 unsigned int hwirq, unsigned int virq, 46 unsigned int is_64, struct msi_msg *msg) 47{ 48 if (WARN_ON(!is_64)) 49 return -ENXIO; 50 msg->data = hwirq - phb->msi_base; 51 msg->address_hi = 0x10000000; 52 msg->address_lo = 0; 53 54 return 0; 55} 56 57static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb) 58{ 59 unsigned int count; 60 const __be32 *prop = of_get_property(phb->hose->dn, 61 "ibm,opal-msi-ranges", NULL); 62 if (!prop) 63 return; 64 65 /* Don't do MSI's on p5ioc2 PCI-X are they are not properly 66 * verified in HW 67 */ 68 if (of_device_is_compatible(phb->hose->dn, "ibm,p5ioc2-pcix")) 69 return; 70 phb->msi_base = be32_to_cpup(prop); 71 count = be32_to_cpup(prop + 1); 72 if (msi_bitmap_alloc(&phb->msi_bmp, count, phb->hose->dn)) { 73 pr_err("PCI %d: Failed to allocate MSI bitmap !\n", 74 phb->hose->global_number); 75 return; 76 } 77 phb->msi_setup = pnv_pci_p5ioc2_msi_setup; 78 phb->msi32_support = 0; 79 pr_info(" Allocated bitmap for %d MSIs (base IRQ 0x%x)\n", 80 count, phb->msi_base); 81} 82#else 83static void pnv_pci_init_p5ioc2_msis(struct pnv_phb *phb) { } 84#endif /* CONFIG_PCI_MSI */ 85 86static void pnv_pci_p5ioc2_dma_dev_setup(struct pnv_phb *phb, 87 struct pci_dev *pdev) 88{ 89 if (phb->p5ioc2.iommu_table.it_map == NULL) { 90 iommu_init_table(&phb->p5ioc2.iommu_table, phb->hose->node); 91 iommu_register_group(&phb->p5ioc2.iommu_table, 92 pci_domain_nr(phb->hose->bus), phb->opal_id); 93 } 94 95 set_iommu_table_base_and_group(&pdev->dev, &phb->p5ioc2.iommu_table); 96} 97 98static void __init pnv_pci_init_p5ioc2_phb(struct device_node *np, u64 hub_id, 99 void *tce_mem, u64 tce_size) 100{ 101 struct pnv_phb *phb; 102 const __be64 *prop64; 103 u64 phb_id; 104 int64_t rc; 105 static int primary = 1; 106 107 pr_info(" Initializing p5ioc2 PHB %s\n", np->full_name); 108 109 prop64 = of_get_property(np, "ibm,opal-phbid", NULL); 110 if (!prop64) { 111 pr_err(" Missing \"ibm,opal-phbid\" property !\n"); 112 return; 113 } 114 phb_id = be64_to_cpup(prop64); 115 pr_devel(" PHB-ID : 0x%016llx\n", phb_id); 116 pr_devel(" TCE AT : 0x%016lx\n", __pa(tce_mem)); 117 pr_devel(" TCE SZ : 0x%016llx\n", tce_size); 118 119 rc = opal_pci_set_phb_tce_memory(phb_id, __pa(tce_mem), tce_size); 120 if (rc != OPAL_SUCCESS) { 121 pr_err(" Failed to set TCE memory, OPAL error %lld\n", rc); 122 return; 123 } 124 125 phb = memblock_virt_alloc(sizeof(struct pnv_phb), 0); 126 phb->hose = pcibios_alloc_controller(np); 127 if (!phb->hose) { 128 pr_err(" Failed to allocate PCI controller\n"); 129 return; 130 } 131 132 spin_lock_init(&phb->lock); 133 phb->hose->first_busno = 0; 134 phb->hose->last_busno = 0xff; 135 phb->hose->private_data = phb; 136 phb->hose->controller_ops = pnv_pci_controller_ops; 137 phb->hub_id = hub_id; 138 phb->opal_id = phb_id; 139 phb->type = PNV_PHB_P5IOC2; 140 phb->model = PNV_PHB_MODEL_P5IOC2; 141 142 phb->regs = of_iomap(np, 0); 143 144 if (phb->regs == NULL) 145 pr_err(" Failed to map registers !\n"); 146 else { 147 pr_devel(" P_BUID = 0x%08x\n", in_be32(phb->regs + 0x100)); 148 pr_devel(" P_IOSZ = 0x%08x\n", in_be32(phb->regs + 0x1b0)); 149 pr_devel(" P_IO_ST = 0x%08x\n", in_be32(phb->regs + 0x1e0)); 150 pr_devel(" P_MEM1_H = 0x%08x\n", in_be32(phb->regs + 0x1a0)); 151 pr_devel(" P_MEM1_L = 0x%08x\n", in_be32(phb->regs + 0x190)); 152 pr_devel(" P_MSZ1_L = 0x%08x\n", in_be32(phb->regs + 0x1c0)); 153 pr_devel(" P_MEM_ST = 0x%08x\n", in_be32(phb->regs + 0x1d0)); 154 pr_devel(" P_MEM2_H = 0x%08x\n", in_be32(phb->regs + 0x2c0)); 155 pr_devel(" P_MEM2_L = 0x%08x\n", in_be32(phb->regs + 0x2b0)); 156 pr_devel(" P_MSZ2_H = 0x%08x\n", in_be32(phb->regs + 0x2d0)); 157 pr_devel(" P_MSZ2_L = 0x%08x\n", in_be32(phb->regs + 0x2e0)); 158 } 159 160 /* Interpret the "ranges" property */ 161 /* This also maps the I/O region and sets isa_io/mem_base */ 162 pci_process_bridge_OF_ranges(phb->hose, np, primary); 163 primary = 0; 164 165 phb->hose->ops = &pnv_pci_ops; 166 167 /* Setup MSI support */ 168 pnv_pci_init_p5ioc2_msis(phb); 169 170 /* Setup TCEs */ 171 phb->dma_dev_setup = pnv_pci_p5ioc2_dma_dev_setup; 172 pnv_pci_setup_iommu_table(&phb->p5ioc2.iommu_table, 173 tce_mem, tce_size, 0, 174 IOMMU_PAGE_SHIFT_4K); 175} 176 177void __init pnv_pci_init_p5ioc2_hub(struct device_node *np) 178{ 179 struct device_node *phbn; 180 const __be64 *prop64; 181 u64 hub_id; 182 void *tce_mem; 183 uint64_t tce_per_phb; 184 int64_t rc; 185 int phb_count = 0; 186 187 pr_info("Probing p5ioc2 IO-Hub %s\n", np->full_name); 188 189 prop64 = of_get_property(np, "ibm,opal-hubid", NULL); 190 if (!prop64) { 191 pr_err(" Missing \"ibm,opal-hubid\" property !\n"); 192 return; 193 } 194 hub_id = be64_to_cpup(prop64); 195 pr_info(" HUB-ID : 0x%016llx\n", hub_id); 196 197 /* Count child PHBs and calculate TCE space per PHB */ 198 for_each_child_of_node(np, phbn) { 199 if (of_device_is_compatible(phbn, "ibm,p5ioc2-pcix") || 200 of_device_is_compatible(phbn, "ibm,p5ioc2-pciex")) 201 phb_count++; 202 } 203 204 if (phb_count <= 0) { 205 pr_info(" No PHBs for Hub %s\n", np->full_name); 206 return; 207 } 208 209 tce_per_phb = __rounddown_pow_of_two(P5IOC2_TCE_MEMORY / phb_count); 210 pr_info(" Allocating %lld MB of TCE memory per PHB\n", 211 tce_per_phb >> 20); 212 213 /* Currently allocate 16M of TCE memory for every Hub 214 * 215 * XXX TODO: Make it chip local if possible 216 */ 217 tce_mem = memblock_virt_alloc(P5IOC2_TCE_MEMORY, P5IOC2_TCE_MEMORY); 218 pr_debug(" TCE : 0x%016lx..0x%016lx\n", 219 __pa(tce_mem), __pa(tce_mem) + P5IOC2_TCE_MEMORY - 1); 220 rc = opal_pci_set_hub_tce_memory(hub_id, __pa(tce_mem), 221 P5IOC2_TCE_MEMORY); 222 if (rc != OPAL_SUCCESS) { 223 pr_err(" Failed to allocate TCE memory, OPAL error %lld\n", rc); 224 return; 225 } 226 227 /* Initialize PHBs */ 228 for_each_child_of_node(np, phbn) { 229 if (of_device_is_compatible(phbn, "ibm,p5ioc2-pcix") || 230 of_device_is_compatible(phbn, "ibm,p5ioc2-pciex")) { 231 pnv_pci_init_p5ioc2_phb(phbn, hub_id, 232 tce_mem, tce_per_phb); 233 tce_mem += tce_per_phb; 234 } 235 } 236} 237