Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* |
| 2 | * This file is subject to the terms and conditions of the GNU General Public |
| 3 | * License. See the file "COPYING" in the main directory of this archive |
| 4 | * for more details. |
| 5 | * |
John Keller | 8ea6091 | 2006-10-04 16:49:25 -0500 | [diff] [blame] | 6 | * Copyright (C) 2001-2004, 2006 Silicon Graphics, Inc. All rights reserved. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 7 | */ |
| 8 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 9 | #include <linux/interrupt.h> |
Prarit Bhargava | c13cf37 | 2005-07-06 15:26:51 -0700 | [diff] [blame] | 10 | #include <linux/types.h> |
Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 11 | #include <linux/slab.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 12 | #include <linux/pci.h> |
Paul Gortmaker | bd3ff19 | 2011-07-31 18:33:21 -0400 | [diff] [blame] | 13 | #include <linux/export.h> |
Prarit Bhargava | c13cf37 | 2005-07-06 15:26:51 -0700 | [diff] [blame] | 14 | #include <asm/sn/addrs.h> |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 15 | #include <asm/sn/geo.h> |
Prarit Bhargava | c13cf37 | 2005-07-06 15:26:51 -0700 | [diff] [blame] | 16 | #include <asm/sn/pcibr_provider.h> |
Mark Maule | 9b08ebd | 2005-04-25 11:32:16 -0700 | [diff] [blame] | 17 | #include <asm/sn/pcibus_provider_defs.h> |
| 18 | #include <asm/sn/pcidev.h> |
Prarit Bhargava | c13cf37 | 2005-07-06 15:26:51 -0700 | [diff] [blame] | 19 | #include <asm/sn/sn_sal.h> |
Jes Sorensen | 1ee27a4 | 2007-06-18 17:19:05 +0200 | [diff] [blame] | 20 | #include <asm/sn/pic.h> |
Mark Goodwin | 5390970 | 2005-08-16 00:51:00 -0700 | [diff] [blame] | 21 | #include <asm/sn/sn2/sn_hwperf.h> |
Prarit Bhargava | c13cf37 | 2005-07-06 15:26:51 -0700 | [diff] [blame] | 22 | #include "xtalk/xwidgetdev.h" |
| 23 | #include "xtalk/hubdev.h" |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 24 | |
Prarit Bhargava | 6f354b0 | 2005-07-06 15:29:53 -0700 | [diff] [blame] | 25 | int |
John Keller | 6f09a92 | 2007-01-30 01:17:37 -0500 | [diff] [blame] | 26 | sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp, |
| 27 | char **ssdt) |
Prarit Bhargava | 6f354b0 | 2005-07-06 15:29:53 -0700 | [diff] [blame] | 28 | { |
| 29 | struct ia64_sal_retval ret_stuff; |
Prarit Bhargava | 53493dc | 2006-01-16 19:54:40 -0800 | [diff] [blame] | 30 | u64 busnum; |
Mike Habeck | ac354a8 | 2006-01-11 16:40:24 -0600 | [diff] [blame] | 31 | u64 segment; |
Prarit Bhargava | 6f354b0 | 2005-07-06 15:29:53 -0700 | [diff] [blame] | 32 | |
| 33 | ret_stuff.status = 0; |
| 34 | ret_stuff.v0 = 0; |
| 35 | |
Mike Habeck | ac354a8 | 2006-01-11 16:40:24 -0600 | [diff] [blame] | 36 | segment = soft->pbi_buscommon.bs_persist_segment; |
Prarit Bhargava | 6f354b0 | 2005-07-06 15:29:53 -0700 | [diff] [blame] | 37 | busnum = soft->pbi_buscommon.bs_persist_busnum; |
Mike Habeck | ac354a8 | 2006-01-11 16:40:24 -0600 | [diff] [blame] | 38 | SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_ENABLE, segment, |
John Keller | 6f09a92 | 2007-01-30 01:17:37 -0500 | [diff] [blame] | 39 | busnum, (u64) device, (u64) resp, (u64)ia64_tpa(ssdt), |
| 40 | 0, 0); |
Prarit Bhargava | 6f354b0 | 2005-07-06 15:29:53 -0700 | [diff] [blame] | 41 | |
| 42 | return (int)ret_stuff.v0; |
| 43 | } |
| 44 | |
| 45 | int |
| 46 | sal_pcibr_slot_disable(struct pcibus_info *soft, int device, int action, |
| 47 | void *resp) |
| 48 | { |
| 49 | struct ia64_sal_retval ret_stuff; |
Prarit Bhargava | 53493dc | 2006-01-16 19:54:40 -0800 | [diff] [blame] | 50 | u64 busnum; |
Mike Habeck | ac354a8 | 2006-01-11 16:40:24 -0600 | [diff] [blame] | 51 | u64 segment; |
Prarit Bhargava | 6f354b0 | 2005-07-06 15:29:53 -0700 | [diff] [blame] | 52 | |
| 53 | ret_stuff.status = 0; |
| 54 | ret_stuff.v0 = 0; |
| 55 | |
Mike Habeck | ac354a8 | 2006-01-11 16:40:24 -0600 | [diff] [blame] | 56 | segment = soft->pbi_buscommon.bs_persist_segment; |
Prarit Bhargava | 6f354b0 | 2005-07-06 15:29:53 -0700 | [diff] [blame] | 57 | busnum = soft->pbi_buscommon.bs_persist_busnum; |
| 58 | SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_DISABLE, |
Mike Habeck | ac354a8 | 2006-01-11 16:40:24 -0600 | [diff] [blame] | 59 | segment, busnum, (u64) device, (u64) action, |
| 60 | (u64) resp, 0, 0); |
Prarit Bhargava | 6f354b0 | 2005-07-06 15:29:53 -0700 | [diff] [blame] | 61 | |
| 62 | return (int)ret_stuff.v0; |
| 63 | } |
| 64 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 65 | static int sal_pcibr_error_interrupt(struct pcibus_info *soft) |
| 66 | { |
| 67 | struct ia64_sal_retval ret_stuff; |
Prarit Bhargava | 53493dc | 2006-01-16 19:54:40 -0800 | [diff] [blame] | 68 | u64 busnum; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 69 | int segment; |
| 70 | ret_stuff.status = 0; |
| 71 | ret_stuff.v0 = 0; |
| 72 | |
Colin Ngam | 674c6479 | 2005-08-03 13:35:00 -0700 | [diff] [blame] | 73 | segment = soft->pbi_buscommon.bs_persist_segment; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 74 | busnum = soft->pbi_buscommon.bs_persist_busnum; |
| 75 | SAL_CALL_NOLOCK(ret_stuff, |
| 76 | (u64) SN_SAL_IOIF_ERROR_INTERRUPT, |
| 77 | (u64) segment, (u64) busnum, 0, 0, 0, 0, 0); |
| 78 | |
| 79 | return (int)ret_stuff.v0; |
| 80 | } |
| 81 | |
Prarit Bhargava | f90aa8c | 2006-03-08 13:30:18 -0500 | [diff] [blame] | 82 | u16 sn_ioboard_to_pci_bus(struct pci_bus *pci_bus) |
| 83 | { |
Matthew Wilcox | e088a4a | 2009-05-22 13:49:49 -0700 | [diff] [blame] | 84 | long rc; |
Jes Sorensen | 256a7e0 | 2007-07-11 17:26:30 +0200 | [diff] [blame] | 85 | u16 uninitialized_var(ioboard); /* GCC be quiet */ |
Prarit Bhargava | f90aa8c | 2006-03-08 13:30:18 -0500 | [diff] [blame] | 86 | nasid_t nasid = NASID_GET(SN_PCIBUS_BUSSOFT(pci_bus)->bs_base); |
| 87 | |
| 88 | rc = ia64_sn_sysctl_ioboard_get(nasid, &ioboard); |
| 89 | if (rc) { |
| 90 | printk(KERN_WARNING "ia64_sn_sysctl_ioboard_get failed: %ld\n", |
| 91 | rc); |
| 92 | return 0; |
| 93 | } |
| 94 | |
| 95 | return ioboard; |
| 96 | } |
| 97 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 98 | /* |
| 99 | * PCI Bridge Error interrupt handler. Gets invoked whenever a PCI |
| 100 | * bridge sends an error interrupt. |
| 101 | */ |
| 102 | static irqreturn_t |
Al Viro | a23b7cb | 2006-10-09 12:47:31 +0100 | [diff] [blame] | 103 | pcibr_error_intr_handler(int irq, void *arg) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 104 | { |
Jeff Garzik | 15aafa2 | 2008-02-06 01:36:20 -0800 | [diff] [blame] | 105 | struct pcibus_info *soft = arg; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 106 | |
Jeff Garzik | 15aafa2 | 2008-02-06 01:36:20 -0800 | [diff] [blame] | 107 | if (sal_pcibr_error_interrupt(soft) < 0) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 108 | panic("pcibr_error_intr_handler(): Fatal Bridge Error"); |
Jeff Garzik | 15aafa2 | 2008-02-06 01:36:20 -0800 | [diff] [blame] | 109 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 110 | return IRQ_HANDLED; |
| 111 | } |
| 112 | |
| 113 | void * |
Christoph Lameter | 7c2a6c6 | 2005-07-12 16:03:00 -0700 | [diff] [blame] | 114 | pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *controller) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 115 | { |
| 116 | int nasid, cnode, j; |
| 117 | struct hubdev_info *hubdev_info; |
| 118 | struct pcibus_info *soft; |
Prarit Bhargava | 6d6e420 | 2005-12-23 13:33:25 -0500 | [diff] [blame] | 119 | struct sn_flush_device_kernel *sn_flush_device_kernel; |
| 120 | struct sn_flush_device_common *common; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 121 | |
| 122 | if (! IS_PCI_BRIDGE_ASIC(prom_bussoft->bs_asic_type)) { |
| 123 | return NULL; |
| 124 | } |
| 125 | |
| 126 | /* |
| 127 | * Allocate kernel bus soft and copy from prom. |
| 128 | */ |
| 129 | |
Thomas Meyer | a4b1d1b | 2011-11-19 12:26:05 +0100 | [diff] [blame^] | 130 | soft = kmemdup(prom_bussoft, sizeof(struct pcibus_info), GFP_KERNEL); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 131 | if (!soft) { |
| 132 | return NULL; |
| 133 | } |
| 134 | |
Jes Sorensen | 1ee27a4 | 2007-06-18 17:19:05 +0200 | [diff] [blame] | 135 | soft->pbi_buscommon.bs_base = (unsigned long) |
| 136 | ioremap(REGION_OFFSET(soft->pbi_buscommon.bs_base), |
| 137 | sizeof(struct pic)); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 138 | |
| 139 | spin_lock_init(&soft->pbi_lock); |
| 140 | |
| 141 | /* |
| 142 | * register the bridge's error interrupt handler |
| 143 | */ |
Al Viro | a23b7cb | 2006-10-09 12:47:31 +0100 | [diff] [blame] | 144 | if (request_irq(SGI_PCIASIC_ERROR, pcibr_error_intr_handler, |
Thomas Gleixner | 121a422 | 2006-07-01 19:29:17 -0700 | [diff] [blame] | 145 | IRQF_SHARED, "PCIBR error", (void *)(soft))) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 146 | printk(KERN_WARNING |
| 147 | "pcibr cannot allocate interrupt for error handler\n"); |
| 148 | } |
John Keller | 6e9de18 | 2007-08-22 19:32:06 -0500 | [diff] [blame] | 149 | sn_set_err_irq_affinity(SGI_PCIASIC_ERROR); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 150 | |
| 151 | /* |
| 152 | * Update the Bridge with the "kernel" pagesize |
| 153 | */ |
| 154 | if (PAGE_SIZE < 16384) { |
| 155 | pcireg_control_bit_clr(soft, PCIBR_CTRL_PAGE_SIZE); |
| 156 | } else { |
| 157 | pcireg_control_bit_set(soft, PCIBR_CTRL_PAGE_SIZE); |
| 158 | } |
| 159 | |
| 160 | nasid = NASID_GET(soft->pbi_buscommon.bs_base); |
| 161 | cnode = nasid_to_cnodeid(nasid); |
| 162 | hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo); |
| 163 | |
| 164 | if (hubdev_info->hdi_flush_nasid_list.widget_p) { |
Prarit Bhargava | 6d6e420 | 2005-12-23 13:33:25 -0500 | [diff] [blame] | 165 | sn_flush_device_kernel = hubdev_info->hdi_flush_nasid_list. |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 166 | widget_p[(int)soft->pbi_buscommon.bs_xid]; |
Prarit Bhargava | 6d6e420 | 2005-12-23 13:33:25 -0500 | [diff] [blame] | 167 | if (sn_flush_device_kernel) { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 168 | for (j = 0; j < DEV_PER_WIDGET; |
Prarit Bhargava | 6d6e420 | 2005-12-23 13:33:25 -0500 | [diff] [blame] | 169 | j++, sn_flush_device_kernel++) { |
| 170 | common = sn_flush_device_kernel->common; |
| 171 | if (common->sfdl_slot == -1) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 172 | continue; |
Prarit Bhargava | 6d6e420 | 2005-12-23 13:33:25 -0500 | [diff] [blame] | 173 | if ((common->sfdl_persistent_segment == |
Colin Ngam | 674c6479 | 2005-08-03 13:35:00 -0700 | [diff] [blame] | 174 | soft->pbi_buscommon.bs_persist_segment) && |
Prarit Bhargava | 6d6e420 | 2005-12-23 13:33:25 -0500 | [diff] [blame] | 175 | (common->sfdl_persistent_busnum == |
Colin Ngam | 674c6479 | 2005-08-03 13:35:00 -0700 | [diff] [blame] | 176 | soft->pbi_buscommon.bs_persist_busnum)) |
Prarit Bhargava | 6d6e420 | 2005-12-23 13:33:25 -0500 | [diff] [blame] | 177 | common->sfdl_pcibus_info = |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 178 | soft; |
| 179 | } |
| 180 | } |
| 181 | } |
| 182 | |
| 183 | /* Setup the PMU ATE map */ |
| 184 | soft->pbi_int_ate_resource.lowest_free_index = 0; |
| 185 | soft->pbi_int_ate_resource.ate = |
Jes Sorensen | 8ed9b2c | 2006-02-13 05:29:57 -0500 | [diff] [blame] | 186 | kzalloc(soft->pbi_int_ate_size * sizeof(u64), GFP_KERNEL); |
| 187 | |
| 188 | if (!soft->pbi_int_ate_resource.ate) { |
| 189 | kfree(soft); |
| 190 | return NULL; |
| 191 | } |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 192 | |
| 193 | return soft; |
| 194 | } |
| 195 | |
| 196 | void pcibr_force_interrupt(struct sn_irq_info *sn_irq_info) |
| 197 | { |
| 198 | struct pcidev_info *pcidev_info; |
| 199 | struct pcibus_info *pcibus_info; |
| 200 | int bit = sn_irq_info->irq_int_bit; |
| 201 | |
Mark Maule | 735e60f | 2005-08-03 14:06:00 -0700 | [diff] [blame] | 202 | if (! sn_irq_info->irq_bridge) |
| 203 | return; |
| 204 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 205 | pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; |
| 206 | if (pcidev_info) { |
| 207 | pcibus_info = |
| 208 | (struct pcibus_info *)pcidev_info->pdi_host_pcidev_info-> |
| 209 | pdi_pcibus_info; |
| 210 | pcireg_force_intr_set(pcibus_info, bit); |
| 211 | } |
| 212 | } |
| 213 | |
Mark Maule | 8409668 | 2005-08-25 11:45:00 -0700 | [diff] [blame] | 214 | void pcibr_target_interrupt(struct sn_irq_info *sn_irq_info) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 215 | { |
| 216 | struct pcidev_info *pcidev_info; |
| 217 | struct pcibus_info *pcibus_info; |
| 218 | int bit = sn_irq_info->irq_int_bit; |
Prarit Bhargava | 53493dc | 2006-01-16 19:54:40 -0800 | [diff] [blame] | 219 | u64 xtalk_addr = sn_irq_info->irq_xtalkaddr; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 220 | |
| 221 | pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; |
| 222 | if (pcidev_info) { |
| 223 | pcibus_info = |
| 224 | (struct pcibus_info *)pcidev_info->pdi_host_pcidev_info-> |
| 225 | pdi_pcibus_info; |
| 226 | |
| 227 | /* Disable the device's IRQ */ |
Mark Maule | 6fb93a9 | 2005-11-07 15:48:50 -0600 | [diff] [blame] | 228 | pcireg_intr_enable_bit_clr(pcibus_info, (1 << bit)); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 229 | |
| 230 | /* Change the device's IRQ */ |
| 231 | pcireg_intr_addr_addr_set(pcibus_info, bit, xtalk_addr); |
| 232 | |
| 233 | /* Re-enable the device's IRQ */ |
Mark Maule | 6fb93a9 | 2005-11-07 15:48:50 -0600 | [diff] [blame] | 234 | pcireg_intr_enable_bit_set(pcibus_info, (1 << bit)); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 235 | |
| 236 | pcibr_force_interrupt(sn_irq_info); |
| 237 | } |
| 238 | } |
Mark Maule | e955d82 | 2005-04-25 11:26:03 -0700 | [diff] [blame] | 239 | |
| 240 | /* |
| 241 | * Provider entries for PIC/CP |
| 242 | */ |
| 243 | |
| 244 | struct sn_pcibus_provider pcibr_provider = { |
| 245 | .dma_map = pcibr_dma_map, |
| 246 | .dma_map_consistent = pcibr_dma_map_consistent, |
| 247 | .dma_unmap = pcibr_dma_unmap, |
| 248 | .bus_fixup = pcibr_bus_fixup, |
Mark Maule | 8409668 | 2005-08-25 11:45:00 -0700 | [diff] [blame] | 249 | .force_interrupt = pcibr_force_interrupt, |
| 250 | .target_interrupt = pcibr_target_interrupt |
Mark Maule | e955d82 | 2005-04-25 11:26:03 -0700 | [diff] [blame] | 251 | }; |
| 252 | |
| 253 | int |
| 254 | pcibr_init_provider(void) |
| 255 | { |
| 256 | sn_pci_provider[PCIIO_ASIC_TYPE_PIC] = &pcibr_provider; |
| 257 | sn_pci_provider[PCIIO_ASIC_TYPE_TIOCP] = &pcibr_provider; |
| 258 | |
| 259 | return 0; |
| 260 | } |
Prarit Bhargava | 6f354b0 | 2005-07-06 15:29:53 -0700 | [diff] [blame] | 261 | |
| 262 | EXPORT_SYMBOL_GPL(sal_pcibr_slot_enable); |
| 263 | EXPORT_SYMBOL_GPL(sal_pcibr_slot_disable); |
Prarit Bhargava | f90aa8c | 2006-03-08 13:30:18 -0500 | [diff] [blame] | 264 | EXPORT_SYMBOL_GPL(sn_ioboard_to_pci_bus); |