hpzx1_misc.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:8k
- /*
- * Misc. support for HP zx1 chipset support
- *
- * Copyright (C) 2002 Hewlett-Packard Co
- * Copyright (C) 2002 Alex Williamson <alex_williamson@hp.com>
- * Copyright (C) 2002 Bjorn Helgaas <bjorn_helgaas@hp.com>
- */
- #include <linux/config.h>
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/pci.h>
- #include <linux/acpi.h>
- #include <linux/efi.h>
- #include <asm/dma.h>
- #include <asm/iosapic.h>
- extern acpi_status acpi_evaluate_integer (acpi_handle, acpi_string, acpi_object_list *, unsigned long *);
- #define PFX "hpzx1: "
- static int hpzx1_devices;
- struct fake_pci_dev {
- unsigned long csr_base;
- unsigned long csr_size;
- unsigned long mapped_csrs; // ioremapped
- int sizing; // in middle of BAR sizing operation?
- };
- #define PCI_FAKE_DEV(dev) ((struct fake_pci_dev *)
- PCI_CONTROLLER(dev)->platform_data)
- static struct pci_ops *orig_pci_ops;
- #define HP_CFG_RD(sz, bits, name)
- static int hp_cfg_read##sz (struct pci_dev *dev, int where, u##bits *value)
- {
- struct fake_pci_dev *fake_dev;
- if (!(fake_dev = PCI_FAKE_DEV(dev)))
- return orig_pci_ops->name(dev, where, value);
-
- if (where == PCI_BASE_ADDRESS_0) {
- if (fake_dev->sizing)
- *value = ~(fake_dev->csr_size - 1);
- else
- *value = (fake_dev->csr_base &
- PCI_BASE_ADDRESS_MEM_MASK) |
- PCI_BASE_ADDRESS_SPACE_MEMORY;
- fake_dev->sizing = 0;
- return PCIBIOS_SUCCESSFUL;
- }
- *value = read##sz(fake_dev->mapped_csrs + where);
- if (where == PCI_COMMAND)
- *value |= PCI_COMMAND_MEMORY; /* SBA omits this */
- return PCIBIOS_SUCCESSFUL;
- }
- #define HP_CFG_WR(sz, bits, name)
- static int hp_cfg_write##sz (struct pci_dev *dev, int where, u##bits value)
- {
- struct fake_pci_dev *fake_dev;
-
- if (!(fake_dev = PCI_FAKE_DEV(dev)))
- return orig_pci_ops->name(dev, where, value);
-
- if (where == PCI_BASE_ADDRESS_0) {
- if (value == (u##bits) ~0)
- fake_dev->sizing = 1;
- return PCIBIOS_SUCCESSFUL;
- } else
- write##sz(value, fake_dev->mapped_csrs + where);
- return PCIBIOS_SUCCESSFUL;
- }
- HP_CFG_RD(b, 8, read_byte)
- HP_CFG_RD(w, 16, read_word)
- HP_CFG_RD(l, 32, read_dword)
- HP_CFG_WR(b, 8, write_byte)
- HP_CFG_WR(w, 16, write_word)
- HP_CFG_WR(l, 32, write_dword)
- static struct pci_ops hp_pci_conf = {
- hp_cfg_readb,
- hp_cfg_readw,
- hp_cfg_readl,
- hp_cfg_writeb,
- hp_cfg_writew,
- hp_cfg_writel,
- };
- static void
- hpzx1_fake_pci_dev(char *name, unsigned int busnum, unsigned long addr, unsigned int size)
- {
- struct pci_controller *controller;
- struct fake_pci_dev *fake;
- int slot;
- struct pci_dev *dev;
- struct pci_bus *b, *bus = NULL;
- u8 hdr;
- controller = kmalloc(sizeof(*controller), GFP_KERNEL);
- if (!controller) {
- printk(KERN_ERR PFX "No memory for %s (0x%p) sysdatan", name,
- (void *) addr);
- return;
- }
- memset(controller, 0, sizeof(*controller));
- fake = kmalloc(sizeof(*fake), GFP_KERNEL);
- if (!fake) {
- printk(KERN_ERR PFX "No memory for %s (0x%p) sysdatan", name,
- (void *) addr);
- kfree(controller);
- return;
- }
- memset(fake, 0, sizeof(*fake));
- fake->csr_base = addr;
- fake->csr_size = size;
- fake->mapped_csrs = (unsigned long) ioremap(addr, size);
- fake->sizing = 0;
- controller->platform_data = fake;
- pci_for_each_bus(b)
- if (busnum == b->number) {
- bus = b;
- break;
- }
- if (!bus) {
- printk(KERN_ERR PFX "No host bus 0x%02x for %s (0x%p)n",
- busnum, name, (void *) addr);
- kfree(fake);
- kfree(controller);
- return;
- }
- for (slot = 0x1e; slot; slot--)
- if (!pci_find_slot(busnum, PCI_DEVFN(slot, 0)))
- break;
- if (slot < 0) {
- printk(KERN_ERR PFX "No space for %s (0x%p) on bus 0x%02xn",
- name, (void *) addr, busnum);
- kfree(fake);
- kfree(controller);
- return;
- }
- dev = kmalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev) {
- printk(KERN_ERR PFX "No memory for %s (0x%p)n", name,
- (void *) addr);
- kfree(fake);
- kfree(controller);
- return;
- }
- bus->ops = &hp_pci_conf; // replace pci ops for this bus
- memset(dev, 0, sizeof(*dev));
- dev->bus = bus;
- dev->sysdata = controller;
- dev->devfn = PCI_DEVFN(slot, 0);
- pci_read_config_word(dev, PCI_VENDOR_ID, &dev->vendor);
- pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device);
- pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr);
- dev->hdr_type = hdr & 0x7f;
- pci_setup_device(dev);
- // pci_insert_device() without running /sbin/hotplug
- list_add_tail(&dev->bus_list, &bus->devices);
- list_add_tail(&dev->global_list, &pci_devices);
- printk(KERN_INFO PFX "%s at 0x%lx; pci dev %sn", name, addr,
- dev->slot_name);
- hpzx1_devices++;
- }
- static acpi_status
- hpzx1_sba_probe(acpi_handle obj, u32 depth, void *context, void **ret)
- {
- u64 csr_base = 0, csr_length = 0;
- acpi_status status;
- char *name = context;
- char fullname[16];
- status = acpi_hp_csr_space(obj, &csr_base, &csr_length);
- if (ACPI_FAILURE(status))
- return status;
- /*
- * Only SBA shows up in ACPI namespace, so its CSR space
- * includes both SBA and IOC. Make SBA and IOC show up
- * separately in PCI space.
- */
- sprintf(fullname, "%s SBA", name);
- hpzx1_fake_pci_dev(fullname, 0, csr_base, 0x1000);
- sprintf(fullname, "%s IOC", name);
- hpzx1_fake_pci_dev(fullname, 0, csr_base + 0x1000, 0x1000);
- return AE_OK;
- }
- static acpi_status
- hpzx1_lba_probe(acpi_handle obj, u32 depth, void *context, void **ret)
- {
- u64 csr_base = 0, csr_length = 0;
- acpi_status status;
- NATIVE_UINT busnum;
- char *name = context;
- char fullname[32];
- status = acpi_hp_csr_space(obj, &csr_base, &csr_length);
- if (ACPI_FAILURE(status))
- return status;
- status = acpi_evaluate_integer(obj, METHOD_NAME__BBN, NULL, &busnum);
- if (ACPI_FAILURE(status)) {
- printk(KERN_WARNING PFX "evaluate _BBN fail=0x%xn", status);
- busnum = 0; // no _BBN; stick it on bus 0
- }
- sprintf(fullname, "%s _BBN 0x%02x", name, (unsigned int) busnum);
- hpzx1_fake_pci_dev(fullname, busnum, csr_base, csr_length);
- return AE_OK;
- }
- static void
- hpzx1_acpi_dev_init(void)
- {
- extern struct pci_ops *pci_root_ops;
- orig_pci_ops = pci_root_ops;
- /*
- * Make fake PCI devices for the following hardware in the
- * ACPI namespace. This makes it more convenient for drivers
- * because they can claim these devices based on PCI
- * information, rather than needing to know about ACPI. The
- * 64-bit "HPA" space for this hardware is available as BAR
- * 0/1.
- *
- * HWP0001: Single IOC SBA w/o IOC in namespace
- * HWP0002: LBA device
- * HWP0003: AGP LBA device
- */
- acpi_get_devices("HWP0001", hpzx1_sba_probe, "HWP0001", NULL);
- #ifdef CONFIG_IA64_HP_PROTO
- if (hpzx1_devices) {
- #endif
- acpi_get_devices("HWP0002", hpzx1_lba_probe, "HWP0002 PCI LBA", NULL);
- acpi_get_devices("HWP0003", hpzx1_lba_probe, "HWP0003 AGP LBA", NULL);
- #ifdef CONFIG_IA64_HP_PROTO
- }
- #define ZX1_FUNC_ID_VALUE (PCI_DEVICE_ID_HP_ZX1_SBA << 16) | PCI_VENDOR_ID_HP
- /*
- * Early protos don't have bridges in the ACPI namespace, so
- * if we didn't find anything, add the things we know are
- * there.
- */
- if (hpzx1_devices == 0) {
- u64 hpa, csr_base;
- csr_base = 0xfed00000UL;
- hpa = (u64) ioremap(csr_base, 0x2000);
- if (__raw_readl(hpa) == ZX1_FUNC_ID_VALUE) {
- hpzx1_fake_pci_dev("HWP0001 SBA", 0, csr_base, 0x1000);
- hpzx1_fake_pci_dev("HWP0001 IOC", 0, csr_base + 0x1000,
- 0x1000);
- csr_base = 0xfed24000UL;
- iounmap(hpa);
- hpa = (u64) ioremap(csr_base, 0x1000);
- hpzx1_fake_pci_dev("HWP0003 AGP LBA", 0x40, csr_base,
- 0x1000);
- }
- iounmap(hpa);
- }
- #endif
- }
- extern void sba_init(void);
- void
- hpzx1_pci_fixup (int phase)
- {
- iosapic_pci_fixup(phase);
- switch (phase) {
- case 0:
- /* zx1 has a hardware I/O TLB which lets us DMA from any device to any address */
- MAX_DMA_ADDRESS = ~0UL;
- break;
- case 1:
- hpzx1_acpi_dev_init();
- sba_init();
- break;
- }
- }