Commit 723ab324 authored by David Mosberger's avatar David Mosberger

ia64: Forward-port hp-agp.c fix from 2.4

See this ChangeSet:

http://lia64.bkbits.net:8080/linux-ia64-2.4/cset@40524248tkgE0RDYQL0IyiAdFxo_Ew
parent 2c7c376e
......@@ -27,10 +27,6 @@
#define HP_ZX1_TCNFG 0x318
#define HP_ZX1_PDIR_BASE 0x320
/* HP ZX1 LBA registers */
#define HP_ZX1_AGP_STATUS 0x64
#define HP_ZX1_AGP_COMMAND 0x68
#define HP_ZX1_IOVA_BASE GB(1UL)
#define HP_ZX1_IOVA_SIZE GB(1UL)
#define HP_ZX1_GART_SIZE (HP_ZX1_IOVA_SIZE / 2)
......@@ -39,6 +35,9 @@
#define HP_ZX1_PDIR_VALID_BIT 0x8000000000000000UL
#define HP_ZX1_IOVA_TO_PDIR(va) ((va - hp_private.iova_base) >> hp_private.io_tlb_shift)
#define AGP8X_MODE_BIT 3
#define AGP8X_MODE (1 << AGP8X_MODE_BIT)
/* AGP bridge need not be PCI device, but DRM thinks it is. */
static struct pci_dev fake_bridge_dev;
......@@ -57,6 +56,7 @@ static struct gatt_mask hp_zx1_masks[] =
static struct _hp_private {
volatile u8 *ioc_regs;
volatile u8 *lba_regs;
int lba_cap_offset;
u64 *io_pdir; // PDIR for entire IOVA
u64 *gatt; // PDIR just for GART (subset of above)
u64 gatt_entries;
......@@ -109,6 +109,7 @@ static int __init hp_zx1_ioc_shared(void)
hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)];
if (hp->gatt[0] != HP_ZX1_SBA_IOMMU_COOKIE) {
/* Normal case when no AGP device in system */
hp->gatt = 0;
hp->gatt_entries = 0;
printk(KERN_ERR PFX "No reserved IO PDIR entry found; "
......@@ -156,12 +157,13 @@ hp_zx1_ioc_owner (void)
}
static int __init
hp_zx1_ioc_init (u64 ioc_hpa, u64 lba_hpa)
hp_zx1_ioc_init (u64 hpa)
{
struct _hp_private *hp = &hp_private;
hp->ioc_regs = ioremap(ioc_hpa, 1024);
hp->lba_regs = ioremap(lba_hpa, 256);
hp->ioc_regs = ioremap(hpa, 1024);
if (!hp->ioc_regs)
return -ENOMEM;
/*
* If the IOTLB is currently disabled, we can take it over.
......@@ -175,6 +177,51 @@ hp_zx1_ioc_init (u64 ioc_hpa, u64 lba_hpa)
return hp_zx1_ioc_shared();
}
static int
hp_zx1_lba_find_capability (volatile u8 *hpa, int cap)
{
u16 status;
u8 pos, id;
int ttl = 48;
status = INREG16(hpa, PCI_STATUS);
if (!(status & PCI_STATUS_CAP_LIST))
return 0;
pos = INREG8(hpa, PCI_CAPABILITY_LIST);
while (ttl-- && pos >= 0x40) {
pos &= ~3;
id = INREG8(hpa, pos + PCI_CAP_LIST_ID);
if (id == 0xff)
break;
if (id == cap)
return pos;
pos = INREG8(hpa, pos + PCI_CAP_LIST_NEXT);
}
return 0;
}
static int __init
hp_zx1_lba_init (u64 hpa)
{
struct _hp_private *hp = &hp_private;
int cap;
hp->lba_regs = ioremap(hpa, 256);
if (!hp->lba_regs)
return -ENOMEM;
hp->lba_cap_offset = hp_zx1_lba_find_capability(hp->lba_regs, PCI_CAP_ID_AGP);
cap = INREG32(hp->lba_regs, hp->lba_cap_offset) & 0xff;
if (cap != PCI_CAP_ID_AGP) {
printk(KERN_ERR PFX "Invalid capability ID 0x%02x at 0x%x\n",
cap, hp->lba_cap_offset);
return -ENODEV;
}
return 0;
}
static int
hp_zx1_fetch_size(void)
{
......@@ -192,13 +239,8 @@ hp_zx1_configure (void)
struct _hp_private *hp = &hp_private;
agp_bridge->gart_bus_addr = hp->gart_base;
#if 0
/* ouch!! can't do that with a non-PCI AGP bridge... */
agp_bridge->capndx = pci_find_capability(agp_bridge->dev, PCI_CAP_ID_AGP);
#else
agp_bridge->capndx = 0;
#endif
agp_bridge->mode = INREG32(hp->lba_regs, HP_ZX1_AGP_STATUS);
agp_bridge->capndx = hp->lba_cap_offset;
agp_bridge->mode = INREG32(hp->lba_regs, hp->lba_cap_offset + PCI_AGP_STATUS);
if (hp->io_pdir_owner) {
OUTREG64(hp->ioc_regs, HP_ZX1_PDIR_BASE, virt_to_phys(hp->io_pdir));
......@@ -217,9 +259,13 @@ hp_zx1_cleanup (void)
{
struct _hp_private *hp = &hp_private;
if (hp->io_pdir_owner)
OUTREG64(hp->ioc_regs, HP_ZX1_IBASE, 0);
iounmap((void *) hp->ioc_regs);
if (hp->ioc_regs) {
if (hp->io_pdir_owner)
OUTREG64(hp->ioc_regs, HP_ZX1_IBASE, 0);
iounmap((void *) hp->ioc_regs);
}
if (hp->lba_regs)
iounmap((void *) hp->lba_regs);
}
static void
......@@ -350,14 +396,14 @@ hp_zx1_enable (u32 mode)
struct _hp_private *hp = &hp_private;
u32 command;
command = INREG32(hp->lba_regs, HP_ZX1_AGP_STATUS);
command = INREG32(hp->lba_regs, hp->lba_cap_offset + PCI_AGP_STATUS);
command = agp_collect_device_status(mode, command);
command |= 0x00000100;
OUTREG32(hp->lba_regs, HP_ZX1_AGP_COMMAND, command);
OUTREG32(hp->lba_regs, hp->lba_cap_offset + PCI_AGP_COMMAND, command);
agp_device_command(command, 0);
agp_device_command(command, (mode & AGP8X_MODE) != 0);
}
struct agp_bridge_driver hp_zx1_driver = {
......@@ -386,22 +432,32 @@ static int __init
hp_zx1_setup (u64 ioc_hpa, u64 lba_hpa)
{
struct agp_bridge_data *bridge;
int error;
int error = 0;
error = hp_zx1_ioc_init(ioc_hpa);
if (error)
goto fail;
error = hp_zx1_ioc_init(ioc_hpa, lba_hpa);
error = hp_zx1_lba_init(lba_hpa);
if (error)
return error;
goto fail;
bridge = agp_alloc_bridge();
if (!bridge)
return -ENOMEM;
if (!bridge) {
error = -ENOMEM;
goto fail;
}
bridge->driver = &hp_zx1_driver;
fake_bridge_dev.vendor = PCI_VENDOR_ID_HP;
fake_bridge_dev.device = PCI_DEVICE_ID_HP_PCIX_LBA;
bridge->dev = &fake_bridge_dev;
return agp_add_bridge(bridge);
error = agp_add_bridge(bridge);
fail:
if (error)
hp_zx1_cleanup();
return error;
}
static acpi_status __init
......@@ -416,7 +472,7 @@ zx1_gart_probe (acpi_handle obj, u32 depth, void *context, void **ret)
status = hp_acpi_csr_space(obj, &lba_hpa, &length);
if (ACPI_FAILURE(status))
return AE_OK;
return AE_OK; /* keep looking for another bridge */
/* Look for an enclosing IOC scope and find its CSR space */
handle = obj;
......@@ -452,7 +508,7 @@ zx1_gart_probe (acpi_handle obj, u32 depth, void *context, void **ret)
(char *) context, sba_hpa + HP_ZX1_IOC_OFFSET, lba_hpa);
hp_zx1_gart_found = 1;
return AE_CTRL_TERMINATE;
return AE_CTRL_TERMINATE; /* we only support one bridge; quit looking */
}
static int __init
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment