/* * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * SNI64 specific PCI support for SNI IO. * * Copyright (C) 1997, 1998, 2000 Colin Ngam */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DEBUG_CONFIG #define DBG(x...) printk(x) #else #define DBG(x...) #endif #ifdef CONFIG_PCI extern devfs_handle_t pci_bus_to_vertex(unsigned char); extern devfs_handle_t devfn_to_vertex(unsigned char bus, unsigned char devfn); /* * snia64_read_config_byte - Read a byte from the config area of the device. */ static int snia64_read_config_byte (struct pci_dev *dev, int where, unsigned char *val) { unsigned long res = 0; unsigned size = 1; devfs_handle_t device_vertex; if ( (dev == (struct pci_dev *)0) || (val == (unsigned char *)0) ) { return PCIBIOS_DEVICE_NOT_FOUND; } device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); if (!device_vertex) { DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); return(-1); } res = pciio_config_get(device_vertex, (unsigned) where, size); *val = (unsigned char) res; return PCIBIOS_SUCCESSFUL; } /* * snia64_read_config_word - Read 2 bytes from the config area of the device. */ static int snia64_read_config_word (struct pci_dev *dev, int where, unsigned short *val) { unsigned long res = 0; unsigned size = 2; /* 2 bytes */ devfs_handle_t device_vertex; if ( (dev == (struct pci_dev *)0) || (val == (unsigned short *)0) ) { return PCIBIOS_DEVICE_NOT_FOUND; } device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); if (!device_vertex) { DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); return(-1); } res = pciio_config_get(device_vertex, (unsigned) where, size); *val = (unsigned short) res; return PCIBIOS_SUCCESSFUL; } /* * snia64_read_config_dword - Read 4 bytes from the config area of the device. */ static int snia64_read_config_dword (struct pci_dev *dev, int where, unsigned int *val) { unsigned long res = 0; unsigned size = 4; /* 4 bytes */ devfs_handle_t device_vertex; if (where & 3) { return PCIBIOS_BAD_REGISTER_NUMBER; } if ( (dev == (struct pci_dev *)0) || (val == (unsigned int *)0) ) { return PCIBIOS_DEVICE_NOT_FOUND; } device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); if (!device_vertex) { DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); return(-1); } res = pciio_config_get(device_vertex, (unsigned) where, size); *val = (unsigned int) res; return PCIBIOS_SUCCESSFUL; } /* * snia64_write_config_byte - Writes 1 byte to the config area of the device. */ static int snia64_write_config_byte (struct pci_dev *dev, int where, unsigned char val) { devfs_handle_t device_vertex; if ( dev == (struct pci_dev *)0 ) { return PCIBIOS_DEVICE_NOT_FOUND; } /* * if it's an IOC3 then we bail out, we special * case them with pci_fixup_ioc3 */ if (dev->vendor == PCI_VENDOR_ID_SGI && dev->device == PCI_DEVICE_ID_SGI_IOC3 ) return PCIBIOS_SUCCESSFUL; device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); if (!device_vertex) { DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); return(-1); } pciio_config_set( device_vertex, (unsigned)where, 1, (uint64_t) val); return PCIBIOS_SUCCESSFUL; } /* * snia64_write_config_word - Writes 2 bytes to the config area of the device. */ static int snia64_write_config_word (struct pci_dev *dev, int where, unsigned short val) { devfs_handle_t device_vertex = NULL; if (where & 1) { return PCIBIOS_BAD_REGISTER_NUMBER; } if ( dev == (struct pci_dev *)0 ) { return PCIBIOS_DEVICE_NOT_FOUND; } /* * if it's an IOC3 then we bail out, we special * case them with pci_fixup_ioc3 */ if (dev->vendor == PCI_VENDOR_ID_SGI && dev->device == PCI_DEVICE_ID_SGI_IOC3) return PCIBIOS_SUCCESSFUL; device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); if (!device_vertex) { DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); return(-1); } pciio_config_set( device_vertex, (unsigned)where, 2, (uint64_t) val); return PCIBIOS_SUCCESSFUL; } /* * snia64_write_config_dword - Writes 4 bytes to the config area of the device. */ static int snia64_write_config_dword (struct pci_dev *dev, int where, unsigned int val) { devfs_handle_t device_vertex; if (where & 3) { return PCIBIOS_BAD_REGISTER_NUMBER; } if ( dev == (struct pci_dev *)0 ) { return PCIBIOS_DEVICE_NOT_FOUND; } /* * if it's an IOC3 then we bail out, we special * case them with pci_fixup_ioc3 */ if (dev->vendor == PCI_VENDOR_ID_SGI && dev->device == PCI_DEVICE_ID_SGI_IOC3) return PCIBIOS_SUCCESSFUL; device_vertex = devfn_to_vertex(dev->bus->number, dev->devfn); if (!device_vertex) { DBG("%s : nonexistent device: bus= 0x%x slot= 0x%x func= 0x%x\n", __FUNCTION__, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); return(-1); } pciio_config_set( device_vertex, (unsigned)where, 4, (uint64_t) val); return PCIBIOS_SUCCESSFUL; } static struct pci_ops snia64_pci_ops = { snia64_read_config_byte, snia64_read_config_word, snia64_read_config_dword, snia64_write_config_byte, snia64_write_config_word, snia64_write_config_dword }; /* * snia64_pci_find_bios - SNIA64 pci_find_bios() platform specific code. */ void __init sn1_pci_find_bios(void) { extern struct pci_ops pci_conf; /* * Go initialize our IO Infrastructure .. */ extern void sgi_master_io_infr_init(void); sgi_master_io_infr_init(); #ifdef BRINGUP if ( IS_RUNNING_ON_SIMULATOR() ) return; #endif /* sn1_io_infrastructure_init(); */ pci_conf = snia64_pci_ops; } void pci_fixup_ioc3(struct pci_dev *d) { int i; unsigned int size; devfs_handle_t bridge_vhdl = pci_bus_to_vertex(d->bus->number); /* IOC3 only decodes 0x20 bytes of the config space, reading * beyond that is relatively benign but writing beyond that * (especially the base address registers) will shut down the * pci bus...so avoid doing so. * NOTE: this means we can't program the intr_pin into the device, * currently we hack this with special code in * sgi_pci_intr_support() */ DBG("pci_fixup_ioc3: Fixing base addresses for ioc3 device %s\n", d->slot_name); /* I happen to know from the spec that the ioc3 needs only 0xfffff * The standard pci trick of writing ~0 to the baddr and seeing * what comes back doesn't work with the ioc3 */ size = 0xfffff; d->resource[0].end = (unsigned long) d->resource[0].start + (unsigned long) size; /* * Zero out the resource structure .. because we did not go through * the normal PCI Infrastructure Init, garbbage are left in these * fileds. */ for (i = 1; i <= PCI_ROM_RESOURCE; i++) { d->resource[i].start = 0UL; d->resource[i].end = 0UL; d->resource[i].flags = 0UL; } /* * Hardcode Device 4 register(IOC3 is in Slot 4) to set the * DEV_DIRECT bit. This will not work if IOC3 is not on Slot * 4. */ DBG("pci_fixup_ioc3: FIXME .. need to take NASID into account when setting IOC3 devreg 0x%x\n", *(volatile u32 *)0xc0000a000f000220); *(volatile u32 *)0xc0000a000f000220 |= 0x90000; d->subsystem_vendor = 0; d->subsystem_device = 0; } #endif /* CONFIG_PCI */