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
6 * Copyright (C) 2001-2004, 2006 Silicon Graphics, Inc. All rights reserved.
9 #include <linux/interrupt.h>
10 #include <linux/types.h>
11 #include <linux/slab.h>
12 #include <linux/pci.h>
13 #include <linux/export.h>
14 #include <asm/sn/addrs.h>
15 #include <asm/sn/geo.h>
16 #include <asm/sn/pcibr_provider.h>
17 #include <asm/sn/pcibus_provider_defs.h>
18 #include <asm/sn/pcidev.h>
19 #include <asm/sn/sn_sal.h>
20 #include <asm/sn/pic.h>
21 #include <asm/sn/sn2/sn_hwperf.h>
22 #include "xtalk/xwidgetdev.h"
23 #include "xtalk/hubdev.h"
26 sal_pcibr_slot_enable(struct pcibus_info
*soft
, int device
, void *resp
,
29 struct ia64_sal_retval ret_stuff
;
36 segment
= soft
->pbi_buscommon
.bs_persist_segment
;
37 busnum
= soft
->pbi_buscommon
.bs_persist_busnum
;
38 SAL_CALL_NOLOCK(ret_stuff
, (u64
) SN_SAL_IOIF_SLOT_ENABLE
, segment
,
39 busnum
, (u64
) device
, (u64
) resp
, (u64
)ia64_tpa(ssdt
),
42 return (int)ret_stuff
.v0
;
46 sal_pcibr_slot_disable(struct pcibus_info
*soft
, int device
, int action
,
49 struct ia64_sal_retval ret_stuff
;
56 segment
= soft
->pbi_buscommon
.bs_persist_segment
;
57 busnum
= soft
->pbi_buscommon
.bs_persist_busnum
;
58 SAL_CALL_NOLOCK(ret_stuff
, (u64
) SN_SAL_IOIF_SLOT_DISABLE
,
59 segment
, busnum
, (u64
) device
, (u64
) action
,
62 return (int)ret_stuff
.v0
;
65 static int sal_pcibr_error_interrupt(struct pcibus_info
*soft
)
67 struct ia64_sal_retval ret_stuff
;
73 segment
= soft
->pbi_buscommon
.bs_persist_segment
;
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);
79 return (int)ret_stuff
.v0
;
82 u16
sn_ioboard_to_pci_bus(struct pci_bus
*pci_bus
)
85 u16
uninitialized_var(ioboard
); /* GCC be quiet */
86 nasid_t nasid
= NASID_GET(SN_PCIBUS_BUSSOFT(pci_bus
)->bs_base
);
88 rc
= ia64_sn_sysctl_ioboard_get(nasid
, &ioboard
);
90 printk(KERN_WARNING
"ia64_sn_sysctl_ioboard_get failed: %ld\n",
99 * PCI Bridge Error interrupt handler. Gets invoked whenever a PCI
100 * bridge sends an error interrupt.
103 pcibr_error_intr_handler(int irq
, void *arg
)
105 struct pcibus_info
*soft
= arg
;
107 if (sal_pcibr_error_interrupt(soft
) < 0)
108 panic("pcibr_error_intr_handler(): Fatal Bridge Error");
114 pcibr_bus_fixup(struct pcibus_bussoft
*prom_bussoft
, struct pci_controller
*controller
)
117 struct hubdev_info
*hubdev_info
;
118 struct pcibus_info
*soft
;
119 struct sn_flush_device_kernel
*sn_flush_device_kernel
;
120 struct sn_flush_device_common
*common
;
122 if (! IS_PCI_BRIDGE_ASIC(prom_bussoft
->bs_asic_type
)) {
127 * Allocate kernel bus soft and copy from prom.
130 soft
= kmemdup(prom_bussoft
, sizeof(struct pcibus_info
), GFP_KERNEL
);
135 soft
->pbi_buscommon
.bs_base
= (unsigned long)
136 ioremap(REGION_OFFSET(soft
->pbi_buscommon
.bs_base
),
139 spin_lock_init(&soft
->pbi_lock
);
142 * register the bridge's error interrupt handler
144 if (request_irq(SGI_PCIASIC_ERROR
, pcibr_error_intr_handler
,
145 IRQF_SHARED
, "PCIBR error", (void *)(soft
))) {
147 "pcibr cannot allocate interrupt for error handler\n");
149 irq_set_handler(SGI_PCIASIC_ERROR
, handle_level_irq
);
150 sn_set_err_irq_affinity(SGI_PCIASIC_ERROR
);
153 * Update the Bridge with the "kernel" pagesize
155 if (PAGE_SIZE
< 16384) {
156 pcireg_control_bit_clr(soft
, PCIBR_CTRL_PAGE_SIZE
);
158 pcireg_control_bit_set(soft
, PCIBR_CTRL_PAGE_SIZE
);
161 nasid
= NASID_GET(soft
->pbi_buscommon
.bs_base
);
162 cnode
= nasid_to_cnodeid(nasid
);
163 hubdev_info
= (struct hubdev_info
*)(NODEPDA(cnode
)->pdinfo
);
165 if (hubdev_info
->hdi_flush_nasid_list
.widget_p
) {
166 sn_flush_device_kernel
= hubdev_info
->hdi_flush_nasid_list
.
167 widget_p
[(int)soft
->pbi_buscommon
.bs_xid
];
168 if (sn_flush_device_kernel
) {
169 for (j
= 0; j
< DEV_PER_WIDGET
;
170 j
++, sn_flush_device_kernel
++) {
171 common
= sn_flush_device_kernel
->common
;
172 if (common
->sfdl_slot
== -1)
174 if ((common
->sfdl_persistent_segment
==
175 soft
->pbi_buscommon
.bs_persist_segment
) &&
176 (common
->sfdl_persistent_busnum
==
177 soft
->pbi_buscommon
.bs_persist_busnum
))
178 common
->sfdl_pcibus_info
=
184 /* Setup the PMU ATE map */
185 soft
->pbi_int_ate_resource
.lowest_free_index
= 0;
186 soft
->pbi_int_ate_resource
.ate
=
187 kzalloc(soft
->pbi_int_ate_size
* sizeof(u64
), GFP_KERNEL
);
189 if (!soft
->pbi_int_ate_resource
.ate
) {
197 void pcibr_force_interrupt(struct sn_irq_info
*sn_irq_info
)
199 struct pcidev_info
*pcidev_info
;
200 struct pcibus_info
*pcibus_info
;
201 int bit
= sn_irq_info
->irq_int_bit
;
203 if (! sn_irq_info
->irq_bridge
)
206 pcidev_info
= (struct pcidev_info
*)sn_irq_info
->irq_pciioinfo
;
209 (struct pcibus_info
*)pcidev_info
->pdi_host_pcidev_info
->
211 pcireg_force_intr_set(pcibus_info
, bit
);
215 void pcibr_target_interrupt(struct sn_irq_info
*sn_irq_info
)
217 struct pcidev_info
*pcidev_info
;
218 struct pcibus_info
*pcibus_info
;
219 int bit
= sn_irq_info
->irq_int_bit
;
220 u64 xtalk_addr
= sn_irq_info
->irq_xtalkaddr
;
222 pcidev_info
= (struct pcidev_info
*)sn_irq_info
->irq_pciioinfo
;
225 (struct pcibus_info
*)pcidev_info
->pdi_host_pcidev_info
->
228 /* Disable the device's IRQ */
229 pcireg_intr_enable_bit_clr(pcibus_info
, (1 << bit
));
231 /* Change the device's IRQ */
232 pcireg_intr_addr_addr_set(pcibus_info
, bit
, xtalk_addr
);
234 /* Re-enable the device's IRQ */
235 pcireg_intr_enable_bit_set(pcibus_info
, (1 << bit
));
237 pcibr_force_interrupt(sn_irq_info
);
242 * Provider entries for PIC/CP
245 struct sn_pcibus_provider pcibr_provider
= {
246 .dma_map
= pcibr_dma_map
,
247 .dma_map_consistent
= pcibr_dma_map_consistent
,
248 .dma_unmap
= pcibr_dma_unmap
,
249 .bus_fixup
= pcibr_bus_fixup
,
250 .force_interrupt
= pcibr_force_interrupt
,
251 .target_interrupt
= pcibr_target_interrupt
255 pcibr_init_provider(void)
257 sn_pci_provider
[PCIIO_ASIC_TYPE_PIC
] = &pcibr_provider
;
258 sn_pci_provider
[PCIIO_ASIC_TYPE_TIOCP
] = &pcibr_provider
;
263 EXPORT_SYMBOL_GPL(sal_pcibr_slot_enable
);
264 EXPORT_SYMBOL_GPL(sal_pcibr_slot_disable
);
265 EXPORT_SYMBOL_GPL(sn_ioboard_to_pci_bus
);