Path: blob/master/arch/ia64/sn/pci/pcibr/pcibr_provider.c
15133 views
/*1* This file is subject to the terms and conditions of the GNU General Public2* License. See the file "COPYING" in the main directory of this archive3* for more details.4*5* Copyright (C) 2001-2004, 2006 Silicon Graphics, Inc. All rights reserved.6*/78#include <linux/interrupt.h>9#include <linux/types.h>10#include <linux/slab.h>11#include <linux/pci.h>12#include <asm/sn/addrs.h>13#include <asm/sn/geo.h>14#include <asm/sn/pcibr_provider.h>15#include <asm/sn/pcibus_provider_defs.h>16#include <asm/sn/pcidev.h>17#include <asm/sn/sn_sal.h>18#include <asm/sn/pic.h>19#include <asm/sn/sn2/sn_hwperf.h>20#include "xtalk/xwidgetdev.h"21#include "xtalk/hubdev.h"2223int24sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp,25char **ssdt)26{27struct ia64_sal_retval ret_stuff;28u64 busnum;29u64 segment;3031ret_stuff.status = 0;32ret_stuff.v0 = 0;3334segment = soft->pbi_buscommon.bs_persist_segment;35busnum = soft->pbi_buscommon.bs_persist_busnum;36SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_ENABLE, segment,37busnum, (u64) device, (u64) resp, (u64)ia64_tpa(ssdt),380, 0);3940return (int)ret_stuff.v0;41}4243int44sal_pcibr_slot_disable(struct pcibus_info *soft, int device, int action,45void *resp)46{47struct ia64_sal_retval ret_stuff;48u64 busnum;49u64 segment;5051ret_stuff.status = 0;52ret_stuff.v0 = 0;5354segment = soft->pbi_buscommon.bs_persist_segment;55busnum = soft->pbi_buscommon.bs_persist_busnum;56SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_DISABLE,57segment, busnum, (u64) device, (u64) action,58(u64) resp, 0, 0);5960return (int)ret_stuff.v0;61}6263static int sal_pcibr_error_interrupt(struct pcibus_info *soft)64{65struct ia64_sal_retval ret_stuff;66u64 busnum;67int segment;68ret_stuff.status = 0;69ret_stuff.v0 = 0;7071segment = soft->pbi_buscommon.bs_persist_segment;72busnum = soft->pbi_buscommon.bs_persist_busnum;73SAL_CALL_NOLOCK(ret_stuff,74(u64) SN_SAL_IOIF_ERROR_INTERRUPT,75(u64) segment, (u64) busnum, 0, 0, 0, 0, 0);7677return (int)ret_stuff.v0;78}7980u16 sn_ioboard_to_pci_bus(struct pci_bus *pci_bus)81{82long rc;83u16 uninitialized_var(ioboard); /* GCC be quiet */84nasid_t nasid = NASID_GET(SN_PCIBUS_BUSSOFT(pci_bus)->bs_base);8586rc = ia64_sn_sysctl_ioboard_get(nasid, &ioboard);87if (rc) {88printk(KERN_WARNING "ia64_sn_sysctl_ioboard_get failed: %ld\n",89rc);90return 0;91}9293return ioboard;94}9596/*97* PCI Bridge Error interrupt handler. Gets invoked whenever a PCI98* bridge sends an error interrupt.99*/100static irqreturn_t101pcibr_error_intr_handler(int irq, void *arg)102{103struct pcibus_info *soft = arg;104105if (sal_pcibr_error_interrupt(soft) < 0)106panic("pcibr_error_intr_handler(): Fatal Bridge Error");107108return IRQ_HANDLED;109}110111void *112pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *controller)113{114int nasid, cnode, j;115struct hubdev_info *hubdev_info;116struct pcibus_info *soft;117struct sn_flush_device_kernel *sn_flush_device_kernel;118struct sn_flush_device_common *common;119120if (! IS_PCI_BRIDGE_ASIC(prom_bussoft->bs_asic_type)) {121return NULL;122}123124/*125* Allocate kernel bus soft and copy from prom.126*/127128soft = kmalloc(sizeof(struct pcibus_info), GFP_KERNEL);129if (!soft) {130return NULL;131}132133memcpy(soft, prom_bussoft, sizeof(struct pcibus_info));134soft->pbi_buscommon.bs_base = (unsigned long)135ioremap(REGION_OFFSET(soft->pbi_buscommon.bs_base),136sizeof(struct pic));137138spin_lock_init(&soft->pbi_lock);139140/*141* register the bridge's error interrupt handler142*/143if (request_irq(SGI_PCIASIC_ERROR, pcibr_error_intr_handler,144IRQF_SHARED, "PCIBR error", (void *)(soft))) {145printk(KERN_WARNING146"pcibr cannot allocate interrupt for error handler\n");147}148sn_set_err_irq_affinity(SGI_PCIASIC_ERROR);149150/*151* Update the Bridge with the "kernel" pagesize152*/153if (PAGE_SIZE < 16384) {154pcireg_control_bit_clr(soft, PCIBR_CTRL_PAGE_SIZE);155} else {156pcireg_control_bit_set(soft, PCIBR_CTRL_PAGE_SIZE);157}158159nasid = NASID_GET(soft->pbi_buscommon.bs_base);160cnode = nasid_to_cnodeid(nasid);161hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo);162163if (hubdev_info->hdi_flush_nasid_list.widget_p) {164sn_flush_device_kernel = hubdev_info->hdi_flush_nasid_list.165widget_p[(int)soft->pbi_buscommon.bs_xid];166if (sn_flush_device_kernel) {167for (j = 0; j < DEV_PER_WIDGET;168j++, sn_flush_device_kernel++) {169common = sn_flush_device_kernel->common;170if (common->sfdl_slot == -1)171continue;172if ((common->sfdl_persistent_segment ==173soft->pbi_buscommon.bs_persist_segment) &&174(common->sfdl_persistent_busnum ==175soft->pbi_buscommon.bs_persist_busnum))176common->sfdl_pcibus_info =177soft;178}179}180}181182/* Setup the PMU ATE map */183soft->pbi_int_ate_resource.lowest_free_index = 0;184soft->pbi_int_ate_resource.ate =185kzalloc(soft->pbi_int_ate_size * sizeof(u64), GFP_KERNEL);186187if (!soft->pbi_int_ate_resource.ate) {188kfree(soft);189return NULL;190}191192return soft;193}194195void pcibr_force_interrupt(struct sn_irq_info *sn_irq_info)196{197struct pcidev_info *pcidev_info;198struct pcibus_info *pcibus_info;199int bit = sn_irq_info->irq_int_bit;200201if (! sn_irq_info->irq_bridge)202return;203204pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;205if (pcidev_info) {206pcibus_info =207(struct pcibus_info *)pcidev_info->pdi_host_pcidev_info->208pdi_pcibus_info;209pcireg_force_intr_set(pcibus_info, bit);210}211}212213void pcibr_target_interrupt(struct sn_irq_info *sn_irq_info)214{215struct pcidev_info *pcidev_info;216struct pcibus_info *pcibus_info;217int bit = sn_irq_info->irq_int_bit;218u64 xtalk_addr = sn_irq_info->irq_xtalkaddr;219220pcidev_info = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;221if (pcidev_info) {222pcibus_info =223(struct pcibus_info *)pcidev_info->pdi_host_pcidev_info->224pdi_pcibus_info;225226/* Disable the device's IRQ */227pcireg_intr_enable_bit_clr(pcibus_info, (1 << bit));228229/* Change the device's IRQ */230pcireg_intr_addr_addr_set(pcibus_info, bit, xtalk_addr);231232/* Re-enable the device's IRQ */233pcireg_intr_enable_bit_set(pcibus_info, (1 << bit));234235pcibr_force_interrupt(sn_irq_info);236}237}238239/*240* Provider entries for PIC/CP241*/242243struct sn_pcibus_provider pcibr_provider = {244.dma_map = pcibr_dma_map,245.dma_map_consistent = pcibr_dma_map_consistent,246.dma_unmap = pcibr_dma_unmap,247.bus_fixup = pcibr_bus_fixup,248.force_interrupt = pcibr_force_interrupt,249.target_interrupt = pcibr_target_interrupt250};251252int253pcibr_init_provider(void)254{255sn_pci_provider[PCIIO_ASIC_TYPE_PIC] = &pcibr_provider;256sn_pci_provider[PCIIO_ASIC_TYPE_TIOCP] = &pcibr_provider;257258return 0;259}260261EXPORT_SYMBOL_GPL(sal_pcibr_slot_enable);262EXPORT_SYMBOL_GPL(sal_pcibr_slot_disable);263EXPORT_SYMBOL_GPL(sn_ioboard_to_pci_bus);264265266