The attached patches add agpgart support for the HP ZX1 (an IA64
chipset).  Any comments would be appreciated.  Jeff, if you like them,
it'd be great if you'd forward them to Marcelo/Linus.
-- 
Bjorn Helgaas - [EMAIL PROTECTED]
Linux Systems Operation R&D
Hewlett-Packard
diff -u -r -X /home/helgaas/exclude linux-2.4.19-pre5/Documentation/Configure.help 
build/linux-2.4.19-pre5-agp/Documentation/Configure.help
--- linux-2.4.19-pre5/Documentation/Configure.help      Mon Apr  1 12:44:56 2002
+++ build/linux-2.4.19-pre5-agp/Documentation/Configure.help    Mon Apr  1 12:48:12 
+2002
@@ -3394,6 +3394,10 @@
   You should say Y here if you use XFree86 3.3.6 or 4.x and want to
   use GLX or DRI.  If unsure, say N.
 
+CONFIG_AGP_HP_ZX1
+  This option gives you AGP GART support for the HP ZX1 chipset
+  for IA64 processors.
+
 Support for ISA-bus hardware
 CONFIG_ISA
   Find out whether you have ISA slots on your motherboard.  ISA is the
diff -u -r -X /home/helgaas/exclude linux-2.4.19-pre5/drivers/char/Config.in 
build/linux-2.4.19-pre5-agp/drivers/char/Config.in
--- linux-2.4.19-pre5/drivers/char/Config.in    Mon Apr  1 12:45:04 2002
+++ build/linux-2.4.19-pre5-agp/drivers/char/Config.in  Mon Apr  1 12:50:24 2002
@@ -252,6 +252,7 @@
    bool '  Generic SiS support' CONFIG_AGP_SIS
    bool '  ALI chipset support' CONFIG_AGP_ALI
    bool '  Serverworks LE/HE support' CONFIG_AGP_SWORKS
+   dep_bool '  HP ZX1 AGP support' CONFIG_AGP_HP_ZX1 $CONFIG_IA64
 fi
 
 bool 'Direct Rendering Manager (XFree86 DRI support)' CONFIG_DRM
diff -u -r -X /home/helgaas/exclude linux-2.4.19-pre5/drivers/char/agp/agp.h 
build/linux-2.4.19-pre5-agp/drivers/char/agp/agp.h
--- linux-2.4.19-pre5/drivers/char/agp/agp.h    Mon Feb 25 12:37:57 2002
+++ build/linux-2.4.19-pre5-agp/drivers/char/agp/agp.h  Mon Apr  1 12:47:10 2002
@@ -125,10 +125,12 @@
        
 };
 
+#define OUTREG64(mmap, addr, val)   __raw_writeq((val), (mmap)+(addr))
 #define OUTREG32(mmap, addr, val)   __raw_writel((val), (mmap)+(addr))
 #define OUTREG16(mmap, addr, val)   __raw_writew((val), (mmap)+(addr))
 #define OUTREG8(mmap, addr, val)   __raw_writeb((val), (mmap)+(addr))
 
+#define INREG64(mmap, addr)         __raw_readq((mmap)+(addr))
 #define INREG32(mmap, addr)         __raw_readl((mmap)+(addr))
 #define INREG16(mmap, addr)         __raw_readw((mmap)+(addr))
 #define INREG8(mmap, addr)         __raw_readb((mmap)+(addr))
@@ -374,5 +376,14 @@
 #define SVWRKS_TLBFLUSH   0x10
 #define SVWRKS_POSTFLUSH  0x14
 #define SVWRKS_DIRFLUSH   0x0c
+
+/* HP ZX1 SBA registers */
+#define HP_ZX1_CTRL            0x200
+#define HP_ZX1_IBASE           0x300
+#define HP_ZX1_IMASK           0x308
+#define HP_ZX1_PCOM            0x310
+#define HP_ZX1_TCNFG           0x318
+#define HP_ZX1_PDIR_BASE       0x320
+#define HP_ZX1_CACHE_FLUSH     0x428
 
 #endif                         /* _AGP_BACKEND_PRIV_H */
diff -u -r -X /home/helgaas/exclude linux-2.4.19-pre5/drivers/char/agp/agpgart_be.c 
build/linux-2.4.19-pre5-agp/drivers/char/agp/agpgart_be.c
--- linux-2.4.19-pre5/drivers/char/agp/agpgart_be.c     Mon Apr  1 12:45:04 2002
+++ build/linux-2.4.19-pre5-agp/drivers/char/agp/agpgart_be.c   Mon Apr  1 12:47:10 
+2002
@@ -3440,6 +3440,368 @@
 
 #endif /* CONFIG_AGP_SWORKS */
 
+#ifdef CONFIG_AGP_HP_ZX1
+
+#ifndef log2
+#define log2(x)                ffz(~(x))
+#endif
+
+#define HP_ZX1_IOVA_BASE       GB(1UL)
+#define HP_ZX1_IOVA_SIZE       GB(1UL)
+#define HP_ZX1_GART_SIZE       (HP_ZX1_IOVA_SIZE / 2)
+#define HP_ZX1_SBA_IOMMU_COOKIE        0x0000badbadc0ffeeUL
+
+#define HP_ZX1_PDIR_VALID_BIT  0x8000000000000000UL
+#define HP_ZX1_IOVA_TO_PDIR(va)        ((va - hp_private.iova_base) >> \
+                                       hp_private.io_tlb_shift)
+
+static aper_size_info_fixed hp_zx1_sizes[] =
+{
+       {0, 0, 0},              /* filled in by hp_zx1_fetch_size() */
+};
+
+static gatt_mask hp_zx1_masks[] =
+{
+       {HP_ZX1_PDIR_VALID_BIT, 0}
+};
+
+static struct _hp_private {
+       struct pci_dev *ioc;
+       volatile u8 *registers;
+       u64 *io_pdir;           // PDIR for entire IOVA
+       u64 *gatt;              // PDIR just for GART (subset of above)
+       u64 gatt_entries;
+       u64 iova_base;
+       u64 gart_base;
+       u64 gart_size;
+       u64 io_pdir_size;
+       int io_pdir_owner;      // do we own it, or share it with sba_iommu?
+       int io_page_size;
+       int io_tlb_shift;
+       int io_tlb_ps;          // IOC ps config
+       int io_pages_per_kpage;
+} hp_private;
+
+static int __init hp_zx1_ioc_shared(void)
+{
+       struct _hp_private *hp = &hp_private;
+
+       printk(KERN_INFO PFX "HP ZX1 IOC: IOPDIR shared with sba_iommu\n");
+
+       /*
+        * IOC already configured by sba_iommu module; just use
+        * its setup.  We assume:
+        *      - IOVA space is 1Gb in size
+        *      - first 512Mb is IOMMU, second 512Mb is GART
+        */
+       hp->io_tlb_ps = INREG64(hp->registers, HP_ZX1_TCNFG);
+       switch (hp->io_tlb_ps) {
+               case 0: hp->io_tlb_shift = 12; break;
+               case 1: hp->io_tlb_shift = 13; break;
+               case 2: hp->io_tlb_shift = 14; break;
+               case 3: hp->io_tlb_shift = 16; break;
+               default:
+                       printk(KERN_ERR PFX "Invalid IOTLB page size "
+                              "configuration 0x%x\n", hp->io_tlb_ps);
+                       hp->gatt = 0;
+                       hp->gatt_entries = 0;
+                       return -ENODEV;
+       }
+       hp->io_page_size = 1 << hp->io_tlb_shift;
+       hp->io_pages_per_kpage = PAGE_SIZE / hp->io_page_size;
+
+       hp->iova_base = INREG64(hp->registers, HP_ZX1_IBASE) & ~0x1;
+       hp->gart_base = hp->iova_base + HP_ZX1_IOVA_SIZE - HP_ZX1_GART_SIZE;
+
+       hp->gart_size = HP_ZX1_GART_SIZE;
+       hp->gatt_entries = hp->gart_size / hp->io_page_size;
+
+       hp->io_pdir = phys_to_virt(INREG64(hp->registers, HP_ZX1_PDIR_BASE));
+       hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)];
+
+       if (hp->gatt[0] != HP_ZX1_SBA_IOMMU_COOKIE) {
+               hp->gatt = 0;
+               hp->gatt_entries = 0;
+               printk(KERN_ERR PFX "No reserved IO PDIR entry found; "
+                      "GART disabled\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int __init hp_zx1_ioc_owner(u8 ioc_rev)
+{
+       struct _hp_private *hp = &hp_private;
+
+       printk(KERN_INFO PFX "HP ZX1 IOC: IOPDIR dedicated to GART\n");
+
+       /*
+        * Select an IOV page size no larger than system page size.
+        */
+       if (PAGE_SIZE >= KB(64)) {
+               hp->io_tlb_shift = 16;
+               hp->io_tlb_ps = 3;
+       } else if (PAGE_SIZE >= KB(16)) {
+               hp->io_tlb_shift = 14;
+               hp->io_tlb_ps = 2;
+       } else if (PAGE_SIZE >= KB(8)) {
+               hp->io_tlb_shift = 13;
+               hp->io_tlb_ps = 1;
+       } else {
+               hp->io_tlb_shift = 12;
+               hp->io_tlb_ps = 0;
+       }
+       hp->io_page_size = 1 << hp->io_tlb_shift;
+       hp->io_pages_per_kpage = PAGE_SIZE / hp->io_page_size;
+
+       hp->iova_base = HP_ZX1_IOVA_BASE;
+       hp->gart_size = HP_ZX1_GART_SIZE;
+       hp->gart_base = hp->iova_base + HP_ZX1_IOVA_SIZE - hp->gart_size;
+
+       hp->gatt_entries = hp->gart_size / hp->io_page_size;
+       hp->io_pdir_size = (HP_ZX1_IOVA_SIZE / hp->io_page_size) * sizeof(u64);
+
+       return 0;
+}
+
+static int __init hp_zx1_ioc_init(void)
+{
+       struct _hp_private *hp = &hp_private;
+       struct pci_dev *ioc;
+       int i;
+       u8 ioc_rev;
+
+       ioc = pci_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_ZX1_IOC, NULL);
+       if (!ioc) {
+               printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no IOC\n");
+               return -ENODEV;
+       }
+       hp->ioc = ioc;
+
+       pci_read_config_byte(ioc, PCI_REVISION_ID, &ioc_rev);
+
+       for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+               if (pci_resource_flags(ioc, i) == IORESOURCE_MEM) {
+                       hp->registers = (u8 *) ioremap(pci_resource_start(ioc,
+                                                                           i),
+                                                   pci_resource_len(ioc, i));
+                       break;
+               }
+       }
+       if (!hp->registers) {
+               printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no CSRs\n");
+
+               return -ENODEV;
+       }
+
+       /*
+        * If the IOTLB is currently disabled, we can take it over.
+        * Otherwise, we have to share with sba_iommu.
+        */
+       hp->io_pdir_owner = (INREG64(hp->registers, HP_ZX1_IBASE) & 0x1) == 0;
+
+       if (hp->io_pdir_owner)
+               return hp_zx1_ioc_owner(ioc_rev);
+
+       return hp_zx1_ioc_shared();
+}
+
+static int hp_zx1_fetch_size(void)
+{
+       int size;
+
+       size = hp_private.gart_size / MB(1);
+       hp_zx1_sizes[0].size = size;
+       agp_bridge.current_size = (void *) &hp_zx1_sizes[0];
+       return size;
+}
+
+static int hp_zx1_configure(void)
+{
+       struct _hp_private *hp = &hp_private;
+
+       agp_bridge.gart_bus_addr = hp->gart_base;
+       agp_bridge.capndx = pci_find_capability(agp_bridge.dev, PCI_CAP_ID_AGP);
+       pci_read_config_dword(agp_bridge.dev,
+               agp_bridge.capndx + PCI_AGP_STATUS, &agp_bridge.mode);
+
+       if (hp->io_pdir_owner) {
+               OUTREG64(hp->registers, HP_ZX1_PDIR_BASE,
+                       virt_to_phys(hp->io_pdir));
+               OUTREG64(hp->registers, HP_ZX1_TCNFG, hp->io_tlb_ps);
+               OUTREG64(hp->registers, HP_ZX1_IMASK, ~(HP_ZX1_IOVA_SIZE - 1));
+               OUTREG64(hp->registers, HP_ZX1_IBASE, hp->iova_base | 0x1);
+               OUTREG64(hp->registers, HP_ZX1_PCOM,
+                       hp->iova_base | log2(HP_ZX1_IOVA_SIZE));
+               INREG64(hp->registers, HP_ZX1_PCOM);
+       }
+
+       return 0;
+}
+
+static void hp_zx1_cleanup(void)
+{
+       struct _hp_private *hp = &hp_private;
+
+       if (hp->io_pdir_owner)
+               OUTREG64(hp->registers, HP_ZX1_IBASE, 0);
+       iounmap((void *) hp->registers);
+}
+
+static void hp_zx1_tlbflush(agp_memory * mem)
+{
+       struct _hp_private *hp = &hp_private;
+
+       OUTREG64(hp->registers, HP_ZX1_PCOM, 
+               hp->gart_base | log2(hp->gart_size));
+       INREG64(hp->registers, HP_ZX1_PCOM);
+}
+
+static int hp_zx1_create_gatt_table(void)
+{
+       struct _hp_private *hp = &hp_private;
+       int i;
+
+       if (hp->io_pdir_owner) {
+               hp->io_pdir = (u64 *) __get_free_pages(GFP_KERNEL,
+                                               get_order(hp->io_pdir_size));
+               if (!hp->io_pdir) {
+                       printk(KERN_ERR PFX "Couldn't allocate contiguous "
+                               "memory for I/O PDIR\n");
+                       hp->gatt = 0;
+                       hp->gatt_entries = 0;
+                       return -ENOMEM;
+               }
+               memset(hp->io_pdir, 0, hp->io_pdir_size);
+
+               hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)];
+       }
+
+       for (i = 0; i < hp->gatt_entries; i++) {
+               hp->gatt[i] = (unsigned long) agp_bridge.scratch_page;
+       }
+
+       return 0;
+}
+
+static int hp_zx1_free_gatt_table(void)
+{
+       struct _hp_private *hp = &hp_private;
+       
+       if (hp->io_pdir_owner)
+               free_pages((unsigned long) hp->io_pdir,
+                           get_order(hp->io_pdir_size));
+       else
+               hp->gatt[0] = HP_ZX1_SBA_IOMMU_COOKIE;
+       return 0;
+}
+
+static int hp_zx1_insert_memory(agp_memory * mem, off_t pg_start, int type)
+{
+       struct _hp_private *hp = &hp_private;
+       int i, k;
+       off_t j, io_pg_start;
+       int io_pg_count;
+
+       if (type != 0 || mem->type != 0) {
+               return -EINVAL;
+       }
+
+       io_pg_start = hp->io_pages_per_kpage * pg_start;
+       io_pg_count = hp->io_pages_per_kpage * mem->page_count;
+       if ((io_pg_start + io_pg_count) > hp->gatt_entries) {
+               return -EINVAL;
+       }
+
+       j = io_pg_start;
+       while (j < (io_pg_start + io_pg_count)) {
+               if (hp->gatt[j]) {
+                       return -EBUSY;
+               }
+               j++;
+       }
+
+       if (mem->is_flushed == FALSE) {
+               CACHE_FLUSH();
+               mem->is_flushed = TRUE;
+       }
+
+       for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
+               unsigned long paddr;
+
+               paddr = mem->memory[i];
+               for (k = 0;
+                    k < hp->io_pages_per_kpage;
+                    k++, j++, paddr += hp->io_page_size) {
+                       hp->gatt[j] = agp_bridge.mask_memory(paddr, type);
+               }
+       }
+
+       agp_bridge.tlb_flush(mem);
+       return 0;
+}
+
+static int hp_zx1_remove_memory(agp_memory * mem, off_t pg_start, int type)
+{
+       struct _hp_private *hp = &hp_private;
+       int i, io_pg_start, io_pg_count;
+
+       if (type != 0 || mem->type != 0) {
+               return -EINVAL;
+       }
+
+       io_pg_start = hp->io_pages_per_kpage * pg_start;
+       io_pg_count = hp->io_pages_per_kpage * mem->page_count;
+       for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) {
+               hp->gatt[i] = agp_bridge.scratch_page;
+       }
+
+       agp_bridge.tlb_flush(mem);
+       return 0;
+}
+
+static unsigned long hp_zx1_mask_memory(unsigned long addr, int type)
+{
+       return HP_ZX1_PDIR_VALID_BIT | addr;
+}
+
+static unsigned long hp_zx1_unmask_memory(unsigned long addr)
+{
+       return addr & ~(HP_ZX1_PDIR_VALID_BIT);
+}
+
+static int __init hp_zx1_setup (struct pci_dev *pdev)
+{
+       agp_bridge.masks = hp_zx1_masks;
+       agp_bridge.num_of_masks = 1;
+       agp_bridge.dev_private_data = NULL;
+       agp_bridge.size_type = FIXED_APER_SIZE;
+       agp_bridge.needs_scratch_page = FALSE;
+       agp_bridge.configure = hp_zx1_configure;
+       agp_bridge.fetch_size = hp_zx1_fetch_size;
+       agp_bridge.cleanup = hp_zx1_cleanup;
+       agp_bridge.tlb_flush = hp_zx1_tlbflush;
+       agp_bridge.mask_memory = hp_zx1_mask_memory;
+       agp_bridge.unmask_memory = hp_zx1_unmask_memory;
+       agp_bridge.agp_enable = agp_generic_agp_enable;
+       agp_bridge.cache_flush = global_cache_flush;
+       agp_bridge.create_gatt_table = hp_zx1_create_gatt_table;
+       agp_bridge.free_gatt_table = hp_zx1_free_gatt_table;
+       agp_bridge.insert_memory = hp_zx1_insert_memory;
+       agp_bridge.remove_memory = hp_zx1_remove_memory;
+       agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+       agp_bridge.free_by_type = agp_generic_free_by_type;
+       agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+       agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+       agp_bridge.cant_use_aperture = 1;
+
+       return hp_zx1_ioc_init();
+
+       (void) pdev; /* unused */
+}
+
+#endif /* CONFIG_AGP_HP_ZX1 */
 
 /* per-chipset initialization data.
  * note -- all chipsets for a single vendor MUST be grouped together
@@ -3733,6 +4095,15 @@
                via_generic_setup },
 #endif /* CONFIG_AGP_VIA */
 
+#ifdef CONFIG_AGP_HP_ZX1
+       { PCI_DEVICE_ID_HP_ZX1_LBA,
+               PCI_VENDOR_ID_HP,
+               HP_ZX1,
+               "HP",
+               "ZX1",
+               hp_zx1_setup },
+#endif
+
        { 0, }, /* dummy final entry, always present */
 };
 
@@ -3958,6 +4329,23 @@
        }
 
 #endif /* CONFIG_AGP_SWORKS */
+
+#ifdef CONFIG_AGP_HP_ZX1
+       if (dev->vendor == PCI_VENDOR_ID_HP) {
+               do {
+                       /* ZX1 LBAs can be either PCI or AGP bridges */
+                       if (pci_find_capability(dev, PCI_CAP_ID_AGP)) {
+                               printk(KERN_INFO PFX "Detected HP ZX1 AGP "
+                                      "chipset at %s\n", dev->slot_name);
+                               agp_bridge.type = HP_ZX1;
+                               agp_bridge.dev = dev;
+                               return hp_zx1_setup(dev);
+                       }
+                       dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, dev);
+               } while (dev);
+               return -ENODEV;
+       }
+#endif /* CONFIG_AGP_HP_ZX1 */
 
        /* find capndx */
        cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP);
diff -u -r -X /home/helgaas/exclude 
linux-2.4.19-pre5/drivers/char/drm/drm_agpsupport.h 
build/linux-2.4.19-pre5-agp/drivers/char/drm/drm_agpsupport.h
--- linux-2.4.19-pre5/drivers/char/drm/drm_agpsupport.h Fri Mar  1 17:20:18 2002
+++ build/linux-2.4.19-pre5-agp/drivers/char/drm/drm_agpsupport.h       Mon Apr  1 
+12:47:10 2002
@@ -316,6 +316,8 @@
                        break;
 #endif
 
+               case HP_ZX1:            head->chipset = "HP ZX1";        break;
+
                default:                head->chipset = "Unknown";       break;
                }
 #if LINUX_VERSION_CODE <= 0x020408
diff -u -r -X /home/helgaas/exclude linux-2.4.19-pre5/drivers/pci/pci.ids 
build/linux-2.4.19-pre5-agp/drivers/pci/pci.ids
--- linux-2.4.19-pre5/drivers/pci/pci.ids       Mon Apr  1 12:45:10 2002
+++ build/linux-2.4.19-pre5-agp/drivers/pci/pci.ids     Mon Apr  1 12:49:19 2002
@@ -1120,6 +1120,9 @@
        121a  NetServer SMIC Controller
        121b  NetServer Legacy COM Port Decoder
        121c  NetServer PCI COM Port Decoder
+       1229  zx1 System Bus Adapter
+       122a  zx1 I/O Controller
+       122e  zx1 Local Bus Adapter
        2910  E2910A PCIBus Exerciser
        2925  E2925A 32 Bit, 33 MHzPCI Exerciser & Analyzer
 103e  Solliday Engineering
diff -u -r -X /home/helgaas/exclude linux-2.4.19-pre5/include/linux/agp_backend.h 
build/linux-2.4.19-pre5-agp/include/linux/agp_backend.h
--- linux-2.4.19-pre5/include/linux/agp_backend.h       Fri Nov  9 15:11:15 2001
+++ build/linux-2.4.19-pre5-agp/include/linux/agp_backend.h     Mon Apr  1 12:47:10 
+2002
@@ -74,7 +74,8 @@
        ALI_GENERIC,
        SVWRKS_HE,
        SVWRKS_LE,
-       SVWRKS_GENERIC
+       SVWRKS_GENERIC,
+       HP_ZX1,
 };
 
 typedef struct _agp_version {
diff -u -r -X /home/helgaas/exclude linux-2.4.19-pre5/include/linux/pci_ids.h 
build/linux-2.4.19-pre5-agp/include/linux/pci_ids.h
--- linux-2.4.19-pre5/include/linux/pci_ids.h   Mon Apr  1 12:45:20 2002
+++ build/linux-2.4.19-pre5-agp/include/linux/pci_ids.h Mon Apr  1 12:47:10 2002
@@ -506,6 +506,9 @@
 #define PCI_DEVICE_ID_HP_DIVA1         0x1049
 #define PCI_DEVICE_ID_HP_DIVA2         0x104A
 #define PCI_DEVICE_ID_HP_SP2_0         0x104B
+#define PCI_DEVICE_ID_HP_ZX1_SBA       0x1229
+#define PCI_DEVICE_ID_HP_ZX1_IOC       0x122a
+#define PCI_DEVICE_ID_HP_ZX1_LBA       0x122e
 
 #define PCI_VENDOR_ID_PCTECH           0x1042
 #define PCI_DEVICE_ID_PCTECH_RZ1000    0x1000
diff -u -r -X /home/helgaas/exclude linux-2.5.7/drivers/char/Config.help 
build/linux-2.5.7-agp/drivers/char/Config.help
--- linux-2.5.7/drivers/char/Config.help        Mon Mar 18 13:37:13 2002
+++ build/linux-2.5.7-agp/drivers/char/Config.help      Mon Apr  1 11:09:36 2002
@@ -170,6 +170,10 @@
   You should say Y here if you use XFree86 3.3.6 or 4.x and want to
   use GLX or DRI.  If unsure, say N.
 
+CONFIG_AGP_HP_ZX1
+  This option gives you AGP GART support for the HP ZX1 chipset
+  for IA64 processors.
+
 CONFIG_I810_TCO
   Hardware driver for the TCO timer built into the Intel i810 and i815
   chipset family.  The TCO (Total Cost of Ownership) timer is a
diff -u -r -X /home/helgaas/exclude linux-2.5.7/drivers/char/Config.in 
build/linux-2.5.7-agp/drivers/char/Config.in
--- linux-2.5.7/drivers/char/Config.in  Mon Mar 18 13:37:08 2002
+++ build/linux-2.5.7-agp/drivers/char/Config.in        Mon Apr  1 12:51:21 2002
@@ -215,6 +215,7 @@
    bool '  Generic SiS support' CONFIG_AGP_SIS
    bool '  ALI chipset support' CONFIG_AGP_ALI
    bool '  Serverworks LE/HE support' CONFIG_AGP_SWORKS
+   dep_bool '  HP ZX1 AGP support' CONFIG_AGP_HP_ZX1 $CONFIG_IA64
 fi
 
 source drivers/char/drm/Config.in
diff -u -r -X /home/helgaas/exclude linux-2.5.7/drivers/char/agp/agp.h 
build/linux-2.5.7-agp/drivers/char/agp/agp.h
--- linux-2.5.7/drivers/char/agp/agp.h  Mon Mar 18 13:37:13 2002
+++ build/linux-2.5.7-agp/drivers/char/agp/agp.h        Mon Apr  1 11:07:43 2002
@@ -125,10 +125,12 @@
        
 };
 
+#define OUTREG64(mmap, addr, val)   __raw_writeq((val), (mmap)+(addr))
 #define OUTREG32(mmap, addr, val)   __raw_writel((val), (mmap)+(addr))
 #define OUTREG16(mmap, addr, val)   __raw_writew((val), (mmap)+(addr))
 #define OUTREG8(mmap, addr, val)   __raw_writeb((val), (mmap)+(addr))
 
+#define INREG64(mmap, addr)         __raw_readq((mmap)+(addr))
 #define INREG32(mmap, addr)         __raw_readl((mmap)+(addr))
 #define INREG16(mmap, addr)         __raw_readw((mmap)+(addr))
 #define INREG8(mmap, addr)         __raw_readb((mmap)+(addr))
@@ -374,5 +376,14 @@
 #define SVWRKS_TLBFLUSH   0x10
 #define SVWRKS_POSTFLUSH  0x14
 #define SVWRKS_DIRFLUSH   0x0c
+
+/* HP ZX1 SBA registers */
+#define HP_ZX1_CTRL            0x200
+#define HP_ZX1_IBASE           0x300
+#define HP_ZX1_IMASK           0x308
+#define HP_ZX1_PCOM            0x310
+#define HP_ZX1_TCNFG           0x318
+#define HP_ZX1_PDIR_BASE       0x320
+#define HP_ZX1_CACHE_FLUSH     0x428
 
 #endif                         /* _AGP_BACKEND_PRIV_H */
diff -u -r -X /home/helgaas/exclude linux-2.5.7/drivers/char/agp/agpgart_be.c 
build/linux-2.5.7-agp/drivers/char/agp/agpgart_be.c
--- linux-2.5.7/drivers/char/agp/agpgart_be.c   Mon Mar 18 13:37:07 2002
+++ build/linux-2.5.7-agp/drivers/char/agp/agpgart_be.c Mon Apr  1 12:16:37 2002
@@ -3509,6 +3509,368 @@
 
 #endif /* CONFIG_AGP_SWORKS */
 
+#ifdef CONFIG_AGP_HP_ZX1
+
+#ifndef log2
+#define log2(x)                ffz(~(x))
+#endif
+
+#define HP_ZX1_IOVA_BASE       GB(1UL)
+#define HP_ZX1_IOVA_SIZE       GB(1UL)
+#define HP_ZX1_GART_SIZE       (HP_ZX1_IOVA_SIZE / 2)
+#define HP_ZX1_SBA_IOMMU_COOKIE        0x0000badbadc0ffeeUL
+
+#define HP_ZX1_PDIR_VALID_BIT  0x8000000000000000UL
+#define HP_ZX1_IOVA_TO_PDIR(va)        ((va - hp_private.iova_base) >> \
+                                       hp_private.io_tlb_shift)
+
+static aper_size_info_fixed hp_zx1_sizes[] =
+{
+       {0, 0, 0},              /* filled in by hp_zx1_fetch_size() */
+};
+
+static gatt_mask hp_zx1_masks[] =
+{
+       {HP_ZX1_PDIR_VALID_BIT, 0}
+};
+
+static struct _hp_private {
+       struct pci_dev *ioc;
+       volatile u8 *registers;
+       u64 *io_pdir;           // PDIR for entire IOVA
+       u64 *gatt;              // PDIR just for GART (subset of above)
+       u64 gatt_entries;
+       u64 iova_base;
+       u64 gart_base;
+       u64 gart_size;
+       u64 io_pdir_size;
+       int io_pdir_owner;      // do we own it, or share it with sba_iommu?
+       int io_page_size;
+       int io_tlb_shift;
+       int io_tlb_ps;          // IOC ps config
+       int io_pages_per_kpage;
+} hp_private;
+
+static int __init hp_zx1_ioc_shared(void)
+{
+       struct _hp_private *hp = &hp_private;
+
+       printk(KERN_INFO PFX "HP ZX1 IOC: IOPDIR shared with sba_iommu\n");
+
+       /*
+        * IOC already configured by sba_iommu module; just use
+        * its setup.  We assume:
+        *      - IOVA space is 1Gb in size
+        *      - first 512Mb is IOMMU, second 512Mb is GART
+        */
+       hp->io_tlb_ps = INREG64(hp->registers, HP_ZX1_TCNFG);
+       switch (hp->io_tlb_ps) {
+               case 0: hp->io_tlb_shift = 12; break;
+               case 1: hp->io_tlb_shift = 13; break;
+               case 2: hp->io_tlb_shift = 14; break;
+               case 3: hp->io_tlb_shift = 16; break;
+               default:
+                       printk(KERN_ERR PFX "Invalid IOTLB page size "
+                              "configuration 0x%x\n", hp->io_tlb_ps);
+                       hp->gatt = 0;
+                       hp->gatt_entries = 0;
+                       return -ENODEV;
+       }
+       hp->io_page_size = 1 << hp->io_tlb_shift;
+       hp->io_pages_per_kpage = PAGE_SIZE / hp->io_page_size;
+
+       hp->iova_base = INREG64(hp->registers, HP_ZX1_IBASE) & ~0x1;
+       hp->gart_base = hp->iova_base + HP_ZX1_IOVA_SIZE - HP_ZX1_GART_SIZE;
+
+       hp->gart_size = HP_ZX1_GART_SIZE;
+       hp->gatt_entries = hp->gart_size / hp->io_page_size;
+
+       hp->io_pdir = phys_to_virt(INREG64(hp->registers, HP_ZX1_PDIR_BASE));
+       hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)];
+
+       if (hp->gatt[0] != HP_ZX1_SBA_IOMMU_COOKIE) {
+               hp->gatt = 0;
+               hp->gatt_entries = 0;
+               printk(KERN_ERR PFX "No reserved IO PDIR entry found; "
+                      "GART disabled\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int __init hp_zx1_ioc_owner(u8 ioc_rev)
+{
+       struct _hp_private *hp = &hp_private;
+
+       printk(KERN_INFO PFX "HP ZX1 IOC: IOPDIR dedicated to GART\n");
+
+       /*
+        * Select an IOV page size no larger than system page size.
+        */
+       if (PAGE_SIZE >= KB(64)) {
+               hp->io_tlb_shift = 16;
+               hp->io_tlb_ps = 3;
+       } else if (PAGE_SIZE >= KB(16)) {
+               hp->io_tlb_shift = 14;
+               hp->io_tlb_ps = 2;
+       } else if (PAGE_SIZE >= KB(8)) {
+               hp->io_tlb_shift = 13;
+               hp->io_tlb_ps = 1;
+       } else {
+               hp->io_tlb_shift = 12;
+               hp->io_tlb_ps = 0;
+       }
+       hp->io_page_size = 1 << hp->io_tlb_shift;
+       hp->io_pages_per_kpage = PAGE_SIZE / hp->io_page_size;
+
+       hp->iova_base = HP_ZX1_IOVA_BASE;
+       hp->gart_size = HP_ZX1_GART_SIZE;
+       hp->gart_base = hp->iova_base + HP_ZX1_IOVA_SIZE - hp->gart_size;
+
+       hp->gatt_entries = hp->gart_size / hp->io_page_size;
+       hp->io_pdir_size = (HP_ZX1_IOVA_SIZE / hp->io_page_size) * sizeof(u64);
+
+       return 0;
+}
+
+static int __init hp_zx1_ioc_init(void)
+{
+       struct _hp_private *hp = &hp_private;
+       struct pci_dev *ioc;
+       int i;
+       u8 ioc_rev;
+
+       ioc = pci_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_ZX1_IOC, NULL);
+       if (!ioc) {
+               printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no IOC\n");
+               return -ENODEV;
+       }
+       hp->ioc = ioc;
+
+       pci_read_config_byte(ioc, PCI_REVISION_ID, &ioc_rev);
+
+       for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+               if (pci_resource_flags(ioc, i) == IORESOURCE_MEM) {
+                       hp->registers = (u8 *) ioremap(pci_resource_start(ioc,
+                                                                           i),
+                                                   pci_resource_len(ioc, i));
+                       break;
+               }
+       }
+       if (!hp->registers) {
+               printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no CSRs\n");
+
+               return -ENODEV;
+       }
+
+       /*
+        * If the IOTLB is currently disabled, we can take it over.
+        * Otherwise, we have to share with sba_iommu.
+        */
+       hp->io_pdir_owner = (INREG64(hp->registers, HP_ZX1_IBASE) & 0x1) == 0;
+
+       if (hp->io_pdir_owner)
+               return hp_zx1_ioc_owner(ioc_rev);
+
+       return hp_zx1_ioc_shared();
+}
+
+static int hp_zx1_fetch_size(void)
+{
+       int size;
+
+       size = hp_private.gart_size / MB(1);
+       hp_zx1_sizes[0].size = size;
+       agp_bridge.current_size = (void *) &hp_zx1_sizes[0];
+       return size;
+}
+
+static int hp_zx1_configure(void)
+{
+       struct _hp_private *hp = &hp_private;
+
+       agp_bridge.gart_bus_addr = hp->gart_base;
+       agp_bridge.capndx = pci_find_capability(agp_bridge.dev, PCI_CAP_ID_AGP);
+       pci_read_config_dword(agp_bridge.dev,
+               agp_bridge.capndx + PCI_AGP_STATUS, &agp_bridge.mode);
+
+       if (hp->io_pdir_owner) {
+               OUTREG64(hp->registers, HP_ZX1_PDIR_BASE,
+                       virt_to_phys(hp->io_pdir));
+               OUTREG64(hp->registers, HP_ZX1_TCNFG, hp->io_tlb_ps);
+               OUTREG64(hp->registers, HP_ZX1_IMASK, ~(HP_ZX1_IOVA_SIZE - 1));
+               OUTREG64(hp->registers, HP_ZX1_IBASE, hp->iova_base | 0x1);
+               OUTREG64(hp->registers, HP_ZX1_PCOM,
+                       hp->iova_base | log2(HP_ZX1_IOVA_SIZE));
+               INREG64(hp->registers, HP_ZX1_PCOM);
+       }
+
+       return 0;
+}
+
+static void hp_zx1_cleanup(void)
+{
+       struct _hp_private *hp = &hp_private;
+
+       if (hp->io_pdir_owner)
+               OUTREG64(hp->registers, HP_ZX1_IBASE, 0);
+       iounmap((void *) hp->registers);
+}
+
+static void hp_zx1_tlbflush(agp_memory * mem)
+{
+       struct _hp_private *hp = &hp_private;
+
+       OUTREG64(hp->registers, HP_ZX1_PCOM, 
+               hp->gart_base | log2(hp->gart_size));
+       INREG64(hp->registers, HP_ZX1_PCOM);
+}
+
+static int hp_zx1_create_gatt_table(void)
+{
+       struct _hp_private *hp = &hp_private;
+       int i;
+
+       if (hp->io_pdir_owner) {
+               hp->io_pdir = (u64 *) __get_free_pages(GFP_KERNEL,
+                                               get_order(hp->io_pdir_size));
+               if (!hp->io_pdir) {
+                       printk(KERN_ERR PFX "Couldn't allocate contiguous "
+                               "memory for I/O PDIR\n");
+                       hp->gatt = 0;
+                       hp->gatt_entries = 0;
+                       return -ENOMEM;
+               }
+               memset(hp->io_pdir, 0, hp->io_pdir_size);
+
+               hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)];
+       }
+
+       for (i = 0; i < hp->gatt_entries; i++) {
+               hp->gatt[i] = (unsigned long) agp_bridge.scratch_page;
+       }
+
+       return 0;
+}
+
+static int hp_zx1_free_gatt_table(void)
+{
+       struct _hp_private *hp = &hp_private;
+       
+       if (hp->io_pdir_owner)
+               free_pages((unsigned long) hp->io_pdir,
+                           get_order(hp->io_pdir_size));
+       else
+               hp->gatt[0] = HP_ZX1_SBA_IOMMU_COOKIE;
+       return 0;
+}
+
+static int hp_zx1_insert_memory(agp_memory * mem, off_t pg_start, int type)
+{
+       struct _hp_private *hp = &hp_private;
+       int i, k;
+       off_t j, io_pg_start;
+       int io_pg_count;
+
+       if (type != 0 || mem->type != 0) {
+               return -EINVAL;
+       }
+
+       io_pg_start = hp->io_pages_per_kpage * pg_start;
+       io_pg_count = hp->io_pages_per_kpage * mem->page_count;
+       if ((io_pg_start + io_pg_count) > hp->gatt_entries) {
+               return -EINVAL;
+       }
+
+       j = io_pg_start;
+       while (j < (io_pg_start + io_pg_count)) {
+               if (hp->gatt[j]) {
+                       return -EBUSY;
+               }
+               j++;
+       }
+
+       if (mem->is_flushed == FALSE) {
+               CACHE_FLUSH();
+               mem->is_flushed = TRUE;
+       }
+
+       for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
+               unsigned long paddr;
+
+               paddr = mem->memory[i];
+               for (k = 0;
+                    k < hp->io_pages_per_kpage;
+                    k++, j++, paddr += hp->io_page_size) {
+                       hp->gatt[j] = agp_bridge.mask_memory(paddr, type);
+               }
+       }
+
+       agp_bridge.tlb_flush(mem);
+       return 0;
+}
+
+static int hp_zx1_remove_memory(agp_memory * mem, off_t pg_start, int type)
+{
+       struct _hp_private *hp = &hp_private;
+       int i, io_pg_start, io_pg_count;
+
+       if (type != 0 || mem->type != 0) {
+               return -EINVAL;
+       }
+
+       io_pg_start = hp->io_pages_per_kpage * pg_start;
+       io_pg_count = hp->io_pages_per_kpage * mem->page_count;
+       for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) {
+               hp->gatt[i] = agp_bridge.scratch_page;
+       }
+
+       agp_bridge.tlb_flush(mem);
+       return 0;
+}
+
+static unsigned long hp_zx1_mask_memory(unsigned long addr, int type)
+{
+       return HP_ZX1_PDIR_VALID_BIT | addr;
+}
+
+static unsigned long hp_zx1_unmask_memory(unsigned long addr)
+{
+       return addr & ~(HP_ZX1_PDIR_VALID_BIT);
+}
+
+static int __init hp_zx1_setup (struct pci_dev *pdev)
+{
+       agp_bridge.masks = hp_zx1_masks;
+       agp_bridge.num_of_masks = 1;
+       agp_bridge.dev_private_data = NULL;
+       agp_bridge.size_type = FIXED_APER_SIZE;
+       agp_bridge.needs_scratch_page = FALSE;
+       agp_bridge.configure = hp_zx1_configure;
+       agp_bridge.fetch_size = hp_zx1_fetch_size;
+       agp_bridge.cleanup = hp_zx1_cleanup;
+       agp_bridge.tlb_flush = hp_zx1_tlbflush;
+       agp_bridge.mask_memory = hp_zx1_mask_memory;
+       agp_bridge.unmask_memory = hp_zx1_unmask_memory;
+       agp_bridge.agp_enable = agp_generic_agp_enable;
+       agp_bridge.cache_flush = global_cache_flush;
+       agp_bridge.create_gatt_table = hp_zx1_create_gatt_table;
+       agp_bridge.free_gatt_table = hp_zx1_free_gatt_table;
+       agp_bridge.insert_memory = hp_zx1_insert_memory;
+       agp_bridge.remove_memory = hp_zx1_remove_memory;
+       agp_bridge.alloc_by_type = agp_generic_alloc_by_type;
+       agp_bridge.free_by_type = agp_generic_free_by_type;
+       agp_bridge.agp_alloc_page = agp_generic_alloc_page;
+       agp_bridge.agp_destroy_page = agp_generic_destroy_page;
+       agp_bridge.cant_use_aperture = 1;
+
+       return hp_zx1_ioc_init();
+
+       (void) pdev; /* unused */
+}
+
+#endif /* CONFIG_AGP_HP_ZX1 */
 
 /* per-chipset initialization data.
  * note -- all chipsets for a single vendor MUST be grouped together
@@ -3796,6 +4158,15 @@
                via_generic_setup },
 #endif /* CONFIG_AGP_VIA */
 
+#ifdef CONFIG_AGP_HP_ZX1
+       { PCI_DEVICE_ID_HP_ZX1_LBA,
+               PCI_VENDOR_ID_HP,
+               HP_ZX1,
+               "HP",
+               "ZX1",
+               hp_zx1_setup },
+#endif
+
        { 0, }, /* dummy final entry, always present */
 };
 
@@ -4020,6 +4391,23 @@
        }
 
 #endif /* CONFIG_AGP_SWORKS */
+
+#ifdef CONFIG_AGP_HP_ZX1
+       if (dev->vendor == PCI_VENDOR_ID_HP) {
+               do {
+                       /* ZX1 LBAs can be either PCI or AGP bridges */
+                       if (pci_find_capability(dev, PCI_CAP_ID_AGP)) {
+                               printk(KERN_INFO PFX "Detected HP ZX1 AGP "
+                                      "chipset at %s\n", dev->slot_name);
+                               agp_bridge.type = HP_ZX1;
+                               agp_bridge.dev = dev;
+                               return hp_zx1_setup(dev);
+                       }
+                       dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, dev);
+               } while (dev);
+               return -ENODEV;
+       }
+#endif /* CONFIG_AGP_HP_ZX1 */
 
        /* find capndx */
        pci_read_config_dword(dev, 0x04, &scratch);
diff -u -r -X /home/helgaas/exclude linux-2.5.7/drivers/char/drm/drm_agpsupport.h 
build/linux-2.5.7-agp/drivers/char/drm/drm_agpsupport.h
--- linux-2.5.7/drivers/char/drm/drm_agpsupport.h       Mon Mar 18 13:37:02 2002
+++ build/linux-2.5.7-agp/drivers/char/drm/drm_agpsupport.h     Mon Apr  1 12:35:31 
+2002
@@ -316,6 +316,8 @@
                        break;
 #endif
 
+               case HP_ZX1:            head->chipset = "HP ZX1";        break;
+
                default:                head->chipset = "Unknown";       break;
                }
 #if LINUX_VERSION_CODE <= 0x020408
diff -u -r -X /home/helgaas/exclude linux-2.5.7/drivers/pci/pci.ids 
build/linux-2.5.7-agp/drivers/pci/pci.ids
--- linux-2.5.7/drivers/pci/pci.ids     Mon Mar 18 13:37:02 2002
+++ build/linux-2.5.7-agp/drivers/pci/pci.ids   Mon Apr  1 11:22:18 2002
@@ -930,6 +930,9 @@
        121a  NetServer SMIC Controller
        121b  NetServer Legacy COM Port Decoder
        121c  NetServer PCI COM Port Decoder
+       1229  zx1 System Bus Adapter
+       122a  zx1 I/O Controller
+       122e  zx1 Local Bus Adapter
        2910  E2910A
        2925  E2925A
 103e  Solliday Engineering
diff -u -r -X /home/helgaas/exclude linux-2.5.7/include/linux/agp_backend.h 
build/linux-2.5.7-agp/include/linux/agp_backend.h
--- linux-2.5.7/include/linux/agp_backend.h     Mon Mar 18 13:37:09 2002
+++ build/linux-2.5.7-agp/include/linux/agp_backend.h   Mon Apr  1 11:07:43 2002
@@ -74,7 +74,8 @@
        ALI_GENERIC,
        SVWRKS_HE,
        SVWRKS_LE,
-       SVWRKS_GENERIC
+       SVWRKS_GENERIC,
+       HP_ZX1,
 };
 
 typedef struct _agp_version {
diff -u -r -X /home/helgaas/exclude linux-2.5.7/include/linux/pci_ids.h 
build/linux-2.5.7-agp/include/linux/pci_ids.h
--- linux-2.5.7/include/linux/pci_ids.h Mon Mar 18 13:37:13 2002
+++ build/linux-2.5.7-agp/include/linux/pci_ids.h       Mon Apr  1 11:22:18 2002
@@ -507,6 +507,9 @@
 #define PCI_DEVICE_ID_HP_DIVA1         0x1049
 #define PCI_DEVICE_ID_HP_DIVA2         0x104A
 #define PCI_DEVICE_ID_HP_SP2_0         0x104B
+#define PCI_DEVICE_ID_HP_ZX1_SBA       0x1229
+#define PCI_DEVICE_ID_HP_ZX1_IOC       0x122a
+#define PCI_DEVICE_ID_HP_ZX1_LBA       0x122e
 
 #define PCI_VENDOR_ID_PCTECH           0x1042
 #define PCI_DEVICE_ID_PCTECH_RZ1000    0x1000


Reply via email to