Commit e20e3ac2 authored by Dave Jones's avatar Dave Jones Committed by Dave Jones

rework as per Linus' suggestion. Chipset drivers are now seperate modules

that use the pci driver interfaces, and register with the agpgart backend.
parent 0f90b075
...@@ -39,13 +39,13 @@ config AGP_INTEL ...@@ -39,13 +39,13 @@ config AGP_INTEL
You should say Y here if you use XFree86 3.3.6 or 4.x and want to 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. use GLX or DRI. If unsure, say N.
config AGP_I810 #config AGP_I810
bool "Intel I810/I815/I830M (on-board) support" # bool "Intel I810/I815/I830M (on-board) support"
depends on AGP # depends on AGP
help # help
This option gives you AGP support for the Xserver on the Intel 810 # This option gives you AGP support for the Xserver on the Intel 810
815 and 830m chipset boards for their on-board integrated graphics. This # 815 and 830m chipset boards for their on-board integrated graphics. This
is required to do any useful video modes with these boards. # is required to do any useful video modes with these boards.
config AGP_VIA config AGP_VIA
bool "VIA chipset support" bool "VIA chipset support"
......
...@@ -3,22 +3,19 @@ ...@@ -3,22 +3,19 @@
# space ioctl interface to use agp memory. It also adds a kernel interface # space ioctl interface to use agp memory. It also adds a kernel interface
# that other drivers could use to manipulate agp memory. # that other drivers could use to manipulate agp memory.
export-objs := agp.o export-objs := backend.o
agpgart-y := agp.o frontend.o agpgart-y := backend.o frontend.o generic.o
agpgart-$(CONFIG_AGP_INTEL) += i8x0-agp.o
agpgart-$(CONFIG_AGP_I810) += i810-agp.o
agpgart-$(CONFIG_AGP_VIA) += via-agp.o
agpgart-$(CONFIG_AGP_AMD) += amd-agp.o
agpgart-$(CONFIG_AGP_SIS) += sis-agp.o
agpgart-$(CONFIG_AGP_ALI) += ali-agp.o
agpgart-$(CONFIG_AGP_SWORKS) += sworks-agp.o
agpgart-$(CONFIG_AGP_I460) += i460-agp.o
agpgart-$(CONFIG_AGP_HP_ZX1) += hp-agp.o
agpgart-$(CONFIG_AGP_AMD_8151) += k8-agp.o
agpgart-objs := $(agpgart-y) agpgart-objs := $(agpgart-y)
obj-$(CONFIG_AGP) += agpgart.o obj-$(CONFIG_AGP) += agpgart.o
include $(TOPDIR)/Rules.make obj-$(CONFIG_AGP_INTEL) += intel-agp.o
obj-$(CONFIG_AGP_VIA) += via-agp.o
obj-$(CONFIG_AGP_AMD) += amd-k7-agp.o
obj-$(CONFIG_AGP_SIS) += sis-agp.o
obj-$(CONFIG_AGP_ALI) += ali-agp.o
obj-$(CONFIG_AGP_SWORKS) += sworks-agp.o
obj-$(CONFIG_AGP_I460) += i460-agp.o
obj-$(CONFIG_AGP_HP_ZX1) += hp-agp.o
obj-$(CONFIG_AGP_AMD_8151) += amd-k8-agp.o
...@@ -47,6 +47,7 @@ void agp_generic_resume(void); ...@@ -47,6 +47,7 @@ void agp_generic_resume(void);
void agp_free_key(int key); void agp_free_key(int key);
/* chipset specific init routines. */ /* chipset specific init routines. */
/*
int __init ali_generic_setup (struct pci_dev *pdev); int __init ali_generic_setup (struct pci_dev *pdev);
int __init amd_irongate_setup (struct pci_dev *pdev); int __init amd_irongate_setup (struct pci_dev *pdev);
int __init amd_8151_setup (struct pci_dev *pdev); int __init amd_8151_setup (struct pci_dev *pdev);
...@@ -65,10 +66,12 @@ int __init intel_860_setup (struct pci_dev *pdev); ...@@ -65,10 +66,12 @@ int __init intel_860_setup (struct pci_dev *pdev);
int __init serverworks_setup (struct pci_dev *pdev); int __init serverworks_setup (struct pci_dev *pdev);
int __init sis_generic_setup (struct pci_dev *pdev); int __init sis_generic_setup (struct pci_dev *pdev);
int __init via_generic_setup (struct pci_dev *pdev); int __init via_generic_setup (struct pci_dev *pdev);
*/
#define AGPGART_MODULE_NAME "agpgart" #define PFX "agpgart: "
#define PFX AGPGART_MODULE_NAME ": "
int agp_register_driver (struct pci_dev *dev);
int agp_unregister_driver(void);
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
static void ipi_handler(void *null) static void ipi_handler(void *null)
......
/* /*
* AGPGART module version 0.99 * ALi AGPGART routines.
* Copyright (C) 1999 Jeff Hartmann
* Copyright (C) 1999 Precision Insight, Inc.
* Copyright (C) 1999 Xi Graphics, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* TODO:
* - Allocate more than order 0 pages to avoid too much linear map splitting.
*/ */
#include <linux/config.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/kernel.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/agp_backend.h> #include <linux/agp_backend.h>
#include "agp.h" #include "agp.h"
#include "ali.h"
static int agp_try_unsupported __initdata = 0;
static int ali_fetch_size(void) static int ali_fetch_size(void)
{ {
...@@ -97,21 +74,8 @@ static int ali_configure(void) ...@@ -97,21 +74,8 @@ static int ali_configure(void)
pci_write_config_dword(agp_bridge.dev, ALI_ATTBASE, temp); pci_write_config_dword(agp_bridge.dev, ALI_ATTBASE, temp);
/* tlb control */ /* tlb control */
pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp);
/* pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL, ((temp & 0xffffff00) | 0x00000010));
* Question: Jeff, ALi's patch deletes this:
*
* pci_read_config_dword(agp_bridge.dev, ALI_TLBCTRL, &temp);
* pci_write_config_dword(agp_bridge.dev, ALI_TLBCTRL,
* ((temp & 0xffffff00) | 0x00000010));
*
* and replaces it with the following, which seems to duplicate the
* next couple of lines below it. I suspect this was an oversight,
* but you might want to check up on this?
*/
pci_read_config_dword(agp_bridge.dev, ALI_APBASE, &temp);
agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
/* address to map to */ /* address to map to */
pci_read_config_dword(agp_bridge.dev, ALI_APBASE, &temp); pci_read_config_dword(agp_bridge.dev, ALI_APBASE, &temp);
...@@ -258,9 +222,180 @@ int __init ali_generic_setup (struct pci_dev *pdev) ...@@ -258,9 +222,180 @@ int __init ali_generic_setup (struct pci_dev *pdev)
agp_bridge.suspend = agp_generic_suspend; agp_bridge.suspend = agp_generic_suspend;
agp_bridge.resume = agp_generic_resume; agp_bridge.resume = agp_generic_resume;
agp_bridge.cant_use_aperture = 0; agp_bridge.cant_use_aperture = 0;
return 0; return 0;
}
struct agp_device_ids ali_agp_device_ids[] __initdata =
{
{
.device_id = PCI_DEVICE_ID_AL_M1541,
.chipset = ALI_M1541,
.chipset_name = "M1541",
},
{
.device_id = PCI_DEVICE_ID_AL_M1621,
.chipset = ALI_M1621,
.chipset_name = "M1621",
},
{
.device_id = PCI_DEVICE_ID_AL_M1631,
.chipset = ALI_M1631,
.chipset_name = "M1631",
},
{
.device_id = PCI_DEVICE_ID_AL_M1632,
.chipset = ALI_M1632,
.chipset_name = "M1632",
},
{
.device_id = PCI_DEVICE_ID_AL_M1641,
.chipset = ALI_M1641,
.chipset_name = "M1641",
},
{
.device_id = PCI_DEVICE_ID_AL_M1644,
.chipset = ALI_M1644,
.chipset_name = "M1644",
},
{
.device_id = PCI_DEVICE_ID_AL_M1647,
.chipset = ALI_M1647,
.chipset_name = "M1647",
},
{
.device_id = PCI_DEVICE_ID_AL_M1651,
.chipset = ALI_M1651,
.chipset_name = "M1651",
},
{
.device_id = PCI_DEVICE_ID_AL_M1671,
.chipset = ALI_M1671,
.chipset_name = "M1671",
},
{ }, /* dummy final entry, always present */
};
/* scan table above for supported devices */
static int __init agp_lookup_host_bridge (struct pci_dev *pdev)
{
int j=0;
struct agp_device_ids *devs;
(void) pdev; /* unused */ devs = ali_agp_device_ids;
while (devs[j].chipset_name != NULL) {
if (pdev->device == devs[j].device_id) {
if (pdev->device == PCI_DEVICE_ID_AL_M1621) {
u8 hidden_1621_id;
pci_read_config_byte(pdev, 0xFB, &hidden_1621_id);
switch (hidden_1621_id) {
case 0x31:
devs[j].chipset_name="M1631";
break;
case 0x32:
devs[j].chipset_name="M1632";
break;
case 0x41:
devs[j].chipset_name="M1641";
break;
case 0x43:
break;
case 0x47:
devs[j].chipset_name="M1647";
break;
case 0x51:
devs[j].chipset_name="M1651";
break;
default:
break;
}
}
printk (KERN_INFO PFX "Detected ALi %s chipset\n",
devs[j].chipset_name);
agp_bridge.type = devs[j].chipset;
if (devs[j].chipset_setup != NULL)
return devs[j].chipset_setup(pdev);
else
return ali_generic_setup(pdev);
}
j++;
}
/* try init anyway, if user requests it */
if (agp_try_unsupported) {
printk(KERN_WARNING PFX "Trying generic ALi routines"
" for device id: %04x\n", pdev->device);
agp_bridge.type = ALI_GENERIC;
return ali_generic_setup(pdev);
}
printk(KERN_ERR PFX "Unsupported ALi chipset (device id: %04x),"
" you might want to try agp_try_unsupported=1.\n", pdev->device);
return -ENODEV;
}
static int agp_ali_probe (struct pci_dev *dev, const struct pci_device_id *ent)
{
if (pci_find_capability(dev, PCI_CAP_ID_AGP)==0)
return -ENODEV;
agp_bridge.dev = dev;
/* probe for known chipsets */
if (agp_lookup_host_bridge (dev) != -ENODEV ) {
agp_register_driver(dev);
return 0;
}
return -ENODEV;
}
static struct pci_device_id agp_ali_pci_table[] __initdata = {
{
.class = (PCI_CLASS_BRIDGE_HOST << 8),
.class_mask = ~0,
.vendor = PCI_VENDOR_ID_AL,
.device = PCI_ANY_ID,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
{ }
};
MODULE_DEVICE_TABLE(pci, agp_ali_pci_table);
static struct pci_driver agp_ali_pci_driver = {
.name = "agpgart-ali",
.id_table = agp_ali_pci_table,
.probe = agp_ali_probe,
};
static int __init agp_ali_init(void)
{
int ret_val;
ret_val = pci_module_init(&agp_ali_pci_driver);
if (ret_val)
agp_bridge.type = NOT_SUPPORTED;
return ret_val;
} }
static void __exit agp_ali_cleanup(void)
{
agp_unregister_driver();
pci_unregister_driver(&agp_ali_pci_driver);
}
module_init(agp_ali_init);
module_exit(agp_ali_cleanup);
MODULE_PARM(agp_try_unsupported, "1i");
MODULE_AUTHOR("Dave Jones <davej@codemonkey.org.uk>");
MODULE_LICENSE("GPL and additional rights");
struct agp_device_ids ali_agp_device_ids[] __initdata =
{
{
.device_id = PCI_DEVICE_ID_AL_M1541,
.chipset = ALI_M1541,
.chipset_name = "M1541",
},
{
.device_id = PCI_DEVICE_ID_AL_M1621,
.chipset = ALI_M1621,
.chipset_name = "M1621",
},
{
.device_id = PCI_DEVICE_ID_AL_M1631,
.chipset = ALI_M1631,
.chipset_name = "M1631",
},
{
.device_id = PCI_DEVICE_ID_AL_M1632,
.chipset = ALI_M1632,
.chipset_name = "M1632",
},
{
.device_id = PCI_DEVICE_ID_AL_M1641,
.chipset = ALI_M1641,
.chipset_name = "M1641",
},
{
.device_id = PCI_DEVICE_ID_AL_M1644,
.chipset = ALI_M1644,
.chipset_name = "M1644",
},
{
.device_id = PCI_DEVICE_ID_AL_M1647,
.chipset = ALI_M1647,
.chipset_name = "M1647",
},
{
.device_id = PCI_DEVICE_ID_AL_M1651,
.chipset = ALI_M1651,
.chipset_name = "M1651",
},
{
.device_id = PCI_DEVICE_ID_AL_M1671,
.chipset = ALI_M1671,
.chipset_name = "M1671",
},
{
.device_id = 0,
.chipset = ALI_GENERIC,
.chipset_name = "Generic",
},
{ }, /* dummy final entry, always present */
};
struct agp_bridge_info ali_agp_bridge_info __initdata =
{
.vendor_id = PCI_VENDOR_ID_AL,
.vendor_name = "Ali",
.chipset_setup = ali_generic_setup,
.ids = ali_agp_device_ids,
};
/* /*
* AGPGART module version 0.99 * AMD K7 AGPGART routines.
* Copyright (C) 1999 Jeff Hartmann
* Copyright (C) 1999 Precision Insight, Inc.
* Copyright (C) 1999 Xi Graphics, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* TODO:
* - Allocate more than order 0 pages to avoid too much linear map splitting.
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -31,7 +7,8 @@ ...@@ -31,7 +7,8 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/agp_backend.h> #include <linux/agp_backend.h>
#include "agp.h" #include "agp.h"
#include "amd.h"
static int agp_try_unsupported __initdata = 0;
struct amd_page_map { struct amd_page_map {
unsigned long *real; unsigned long *real;
...@@ -401,9 +378,128 @@ int __init amd_irongate_setup (struct pci_dev *pdev) ...@@ -401,9 +378,128 @@ int __init amd_irongate_setup (struct pci_dev *pdev)
agp_bridge.suspend = agp_generic_suspend; agp_bridge.suspend = agp_generic_suspend;
agp_bridge.resume = agp_generic_resume; agp_bridge.resume = agp_generic_resume;
agp_bridge.cant_use_aperture = 0; agp_bridge.cant_use_aperture = 0;
return 0; return 0;
}
struct agp_device_ids amd_agp_device_ids[] __initdata =
{
{
.device_id = PCI_DEVICE_ID_AMD_FE_GATE_7006,
.chipset = AMD_IRONGATE,
.chipset_name = "Irongate",
},
{
.device_id = PCI_DEVICE_ID_AMD_FE_GATE_700E,
.chipset = AMD_761,
.chipset_name = "761",
},
{
.device_id = PCI_DEVICE_ID_AMD_FE_GATE_700C,
.chipset = AMD_762,
.chipset_name = "760MP",
},
{ }, /* dummy final entry, always present */
};
/* scan table above for supported devices */
static int __init agp_lookup_host_bridge (struct pci_dev *pdev)
{
int j=0;
struct agp_device_ids *devs;
(void) pdev; /* unused */ devs = amd_agp_device_ids;
while (devs[j].chipset_name != NULL) {
if (pdev->device == devs[j].device_id) {
printk (KERN_INFO PFX "Detected AMD %s chipset\n", devs[j].chipset_name);
agp_bridge.type = devs[j].chipset;
if (devs[j].chipset_setup != NULL)
return devs[j].chipset_setup(pdev);
else
return amd_irongate_setup(pdev);
}
j++;
}
/* try init anyway, if user requests it */
if (agp_try_unsupported) {
printk(KERN_WARNING PFX "Trying generic AMD routines"
" for device id: %04x\n", pdev->device);
agp_bridge.type = AMD_GENERIC;
return amd_irongate_setup(pdev);
}
printk(KERN_ERR PFX "Unsupported AMD chipset (device id: %04x),"
" you might want to try agp_try_unsupported=1.\n", pdev->device);
return -ENODEV;
}
/* Supported Device Scanning routine */
static int __init agp_find_supported_device(struct pci_dev *dev)
{
agp_bridge.dev = dev;
if (pci_find_capability(dev, PCI_CAP_ID_AGP)==0)
return -ENODEV;
/* probe for known chipsets */
return agp_lookup_host_bridge (dev);
}
static int agp_amdk7_probe (struct pci_dev *dev, const struct pci_device_id *ent)
{
if (agp_find_supported_device(dev) == 0) {
agp_register_driver(dev);
return 0;
}
return -ENODEV;
}
static struct pci_device_id agp_amdk7_pci_table[] __initdata = {
{
.class = (PCI_CLASS_BRIDGE_HOST << 8),
.class_mask = ~0,
.vendor = PCI_VENDOR_ID_AMD,
.device = PCI_ANY_ID,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
{ }
};
MODULE_DEVICE_TABLE(pci, agp_amdk7_pci_table);
static struct pci_driver agp_amdk7_pci_driver = {
.name = "agpgart-amdk7",
.id_table = agp_amdk7_pci_table,
.probe = agp_amdk7_probe,
};
static int __init agp_amdk7_init(void)
{
int ret_val;
ret_val = pci_module_init(&agp_amdk7_pci_driver);
if (ret_val)
agp_bridge.type = NOT_SUPPORTED;
return ret_val;
} }
static void __exit agp_amdk7_cleanup(void)
{
agp_unregister_driver();
pci_unregister_driver(&agp_amdk7_pci_driver);
}
module_init(agp_amdk7_init);
module_exit(agp_amdk7_cleanup);
MODULE_PARM(agp_try_unsupported, "1i");
MODULE_LICENSE("GPL and additional rights");
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/agp_backend.h> #include <linux/agp_backend.h>
#include "agp.h" #include "agp.h"
#include "k8-agp.h"
extern int agp_memory_reserved; extern int agp_memory_reserved;
extern __u32 *agp_gatt_table; extern __u32 *agp_gatt_table;
...@@ -162,7 +161,7 @@ static void inline flush_x86_64_tlb(struct pci_dev *dev) ...@@ -162,7 +161,7 @@ static void inline flush_x86_64_tlb(struct pci_dev *dev)
} }
void amd_x86_64_tlbflush(agp_memory * temp) static void amd_x86_64_tlbflush(agp_memory * temp)
{ {
struct pci_dev *dev; struct pci_dev *dev;
...@@ -179,7 +178,7 @@ void amd_x86_64_tlbflush(agp_memory * temp) ...@@ -179,7 +178,7 @@ void amd_x86_64_tlbflush(agp_memory * temp)
* In a multiprocessor x86-64 system, this function gets * In a multiprocessor x86-64 system, this function gets
* called once for each CPU. * called once for each CPU.
*/ */
u64 amd_x86_64_configure (struct pci_dev *hammer, u64 gatt_table) static u64 amd_x86_64_configure (struct pci_dev *hammer, u64 gatt_table)
{ {
u64 aperturebase; u64 aperturebase;
u32 tmp; u32 tmp;
...@@ -445,7 +444,7 @@ static void agp_x86_64_agp_enable(u32 mode) ...@@ -445,7 +444,7 @@ static void agp_x86_64_agp_enable(u32 mode)
} }
int __init amd_8151_setup (struct pci_dev *pdev) static int __init amd_8151_setup (struct pci_dev *pdev)
{ {
agp_bridge.masks = amd_8151_masks; agp_bridge.masks = amd_8151_masks;
agp_bridge.num_of_masks = 1; agp_bridge.num_of_masks = 1;
...@@ -472,6 +471,60 @@ int __init amd_8151_setup (struct pci_dev *pdev) ...@@ -472,6 +471,60 @@ int __init amd_8151_setup (struct pci_dev *pdev)
agp_bridge.suspend = agp_generic_suspend; agp_bridge.suspend = agp_generic_suspend;
agp_bridge.resume = agp_generic_resume; agp_bridge.resume = agp_generic_resume;
agp_bridge.cant_use_aperture = 0; agp_bridge.cant_use_aperture = 0;
return 0;
}
static int agp_amdk8_probe (struct pci_dev *dev, const struct pci_device_id *ent)
{
if (pci_find_capability(dev, PCI_CAP_ID_AGP)==0)
return -ENODEV;
amd_8151_setup(dev);
agp_register_driver(dev);
return 0; return 0;
} }
static struct pci_device_id agp_amdk8_pci_table[] __initdata = {
{
.class = (PCI_CLASS_BRIDGE_HOST << 8),
.class_mask = ~0,
.vendor = PCI_VENDOR_ID_AMD,
.device = PCI_DEVICE_ID_AMD_8151_0,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
{ }
};
MODULE_DEVICE_TABLE(pci, agp_amdk8_pci_table);
static struct pci_driver agp_amdk8_pci_driver = {
.name = "agpgart-amd-k8",
.id_table = agp_amdk8_pci_table,
.probe = agp_amdk8_probe,
};
static int __init agp_amdk8_init(void)
{
int ret_val;
ret_val = pci_module_init(&agp_amdk8_pci_driver);
if (ret_val)
agp_bridge.type = NOT_SUPPORTED;
return ret_val;
}
static void __exit agp_amdk8_cleanup(void)
{
agp_unregister_driver();
pci_unregister_driver(&agp_amdk8_pci_driver);
}
module_init(agp_amdk8_init);
module_exit(agp_amdk8_cleanup);
MODULE_AUTHOR("Dave Jones <davej@codemonkey.org.uk>");
MODULE_LICENSE("GPL and additional rights");
struct agp_device_ids amd_agp_device_ids[] __initdata =
{
{
.device_id = PCI_DEVICE_ID_AMD_FE_GATE_7006,
.chipset = AMD_IRONGATE,
.chipset_name = "Irongate",
},
{
.device_id = PCI_DEVICE_ID_AMD_FE_GATE_700E,
.chipset = AMD_761,
.chipset_name = "761",
},
{
.device_id = PCI_DEVICE_ID_AMD_FE_GATE_700C,
.chipset = AMD_762,
.chipset_name = "760MP",
},
{
.device_id = 0,
.chipset = AMD_GENERIC,
.chipset_name = "Generic",
},
{ }, /* dummy final entry, always present */
};
struct agp_bridge_info amd_agp_bridge_info __initdata =
{
.vendor_id = PCI_VENDOR_ID_AMD,
.vendor_name = "AMD",
.chipset_setup = amd_irongate_setup,
.ids = amd_agp_device_ids,
};
/*
* AGPGART module version 1.0
* Copyright (C) 2002 Dave Jones.
* Copyright (C) 1999 Jeff Hartmann.
* Copyright (C) 1999 Precision Insight, Inc.
* Copyright (C) 1999 Xi Graphics, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* JEFF HARTMANN, DAVE JONES, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* TODO:
* - Allocate more than order 0 pages to avoid too much linear map splitting.
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/pagemap.h>
#include <linux/miscdevice.h>
#include <linux/pm.h>
#include <linux/agp_backend.h>
#include "agp.h"
#define AGPGART_VERSION_MAJOR 1
#define AGPGART_VERSION_MINOR 0
struct agp_bridge_data agp_bridge = { .type = NOT_SUPPORTED };
int agp_backend_acquire(void)
{
if (agp_bridge.type == NOT_SUPPORTED)
return -EINVAL;
atomic_inc(&agp_bridge.agp_in_use);
if (atomic_read(&agp_bridge.agp_in_use) != 1) {
atomic_dec(&agp_bridge.agp_in_use);
return -EBUSY;
}
MOD_INC_USE_COUNT;
return 0;
}
void agp_backend_release(void)
{
if (agp_bridge.type == NOT_SUPPORTED)
return;
atomic_dec(&agp_bridge.agp_in_use);
MOD_DEC_USE_COUNT;
}
struct agp_max_table {
int mem;
int agp;
};
static struct agp_max_table maxes_table[9] __initdata =
{
{0, 0},
{32, 4},
{64, 28},
{128, 96},
{256, 204},
{512, 440},
{1024, 942},
{2048, 1920},
{4096, 3932}
};
static int __init agp_find_max (void)
{
long memory, index, result;
memory = virt_to_phys(high_memory) >> 20;
index = 1;
while ((memory > maxes_table[index].mem) && (index < 8))
index++;
result = maxes_table[index - 1].agp +
( (memory - maxes_table[index - 1].mem) *
(maxes_table[index].agp - maxes_table[index - 1].agp)) /
(maxes_table[index].mem - maxes_table[index - 1].mem);
printk(KERN_INFO PFX "Maximum main memory to use for agp memory: %ldM\n", result);
result = result << (20 - PAGE_SHIFT);
return result;
}
static struct agp_version agp_current_version =
{
.major = AGPGART_VERSION_MAJOR,
.minor = AGPGART_VERSION_MINOR,
};
static int __init agp_backend_initialize(struct pci_dev *dev)
{
int size_value, rc, got_gatt=0, got_keylist=0;
u8 cap_ptr = 0;
agp_bridge.max_memory_agp = agp_find_max();
agp_bridge.version = &agp_current_version;
cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP);
if (cap_ptr == 0)
return -ENODEV;
agp_bridge.capndx = cap_ptr;
/* Fill in the mode register */
pci_read_config_dword(agp_bridge.dev, agp_bridge.capndx + 4, &agp_bridge.mode);
if (agp_bridge.needs_scratch_page == TRUE) {
void *addr;
addr = agp_bridge.agp_alloc_page();
if (addr == NULL) {
printk(KERN_ERR PFX "unable to get memory for scratch page.\n");
return -ENOMEM;
}
agp_bridge.scratch_page = virt_to_phys(addr);
agp_bridge.scratch_page = agp_bridge.mask_memory(agp_bridge.scratch_page, 0);
}
size_value = agp_bridge.fetch_size();
if (size_value == 0) {
printk(KERN_ERR PFX "unable to determine aperture size.\n");
rc = -EINVAL;
goto err_out;
}
if (agp_bridge.create_gatt_table()) {
printk(KERN_ERR PFX "unable to get memory for graphics translation table.\n");
rc = -ENOMEM;
goto err_out;
}
got_gatt = 1;
agp_bridge.key_list = vmalloc(PAGE_SIZE * 4);
if (agp_bridge.key_list == NULL) {
printk(KERN_ERR PFX "error allocating memory for key lists.\n");
rc = -ENOMEM;
goto err_out;
}
got_keylist = 1;
/* FIXME vmalloc'd memory not guaranteed contiguous */
memset(agp_bridge.key_list, 0, PAGE_SIZE * 4);
if (agp_bridge.configure()) {
printk(KERN_ERR PFX "error configuring host chipset.\n");
rc = -EINVAL;
goto err_out;
}
printk(KERN_INFO PFX "AGP aperture is %dM @ 0x%lx\n",
size_value, agp_bridge.gart_bus_addr);
return 0;
err_out:
if (agp_bridge.needs_scratch_page == TRUE) {
agp_bridge.scratch_page &= ~(0x00000fff);
agp_bridge.agp_destroy_page(phys_to_virt(agp_bridge.scratch_page));
}
if (got_gatt)
agp_bridge.free_gatt_table();
if (got_keylist)
vfree(agp_bridge.key_list);
return rc;
}
/* cannot be __exit b/c as it could be called from __init code */
static void agp_backend_cleanup(void)
{
agp_bridge.cleanup();
agp_bridge.free_gatt_table();
vfree(agp_bridge.key_list);
if (agp_bridge.needs_scratch_page == TRUE) {
agp_bridge.scratch_page &= ~(0x00000fff);
agp_bridge.agp_destroy_page(phys_to_virt(agp_bridge.scratch_page));
}
}
static int agp_power(struct pm_dev *dev, pm_request_t rq, void *data)
{
switch(rq)
{
case PM_SUSPEND:
return agp_bridge.suspend();
case PM_RESUME:
agp_bridge.resume();
return 0;
}
return 0;
}
extern int agp_frontend_initialize(void);
extern void agp_frontend_cleanup(void);
static const drm_agp_t drm_agp = {
&agp_free_memory,
&agp_allocate_memory,
&agp_bind_memory,
&agp_unbind_memory,
&agp_enable,
&agp_backend_acquire,
&agp_backend_release,
&agp_copy_info
};
static int agp_count=0;
int agp_register_driver (struct pci_dev *dev)
{
int ret_val;
if (agp_count==1) {
printk (KERN_DEBUG PFX "Only one agpgart device currently supported.\n");
return -ENODEV;
}
ret_val = agp_backend_initialize(dev);
if (ret_val) {
agp_bridge.type = NOT_SUPPORTED;
return ret_val;
}
ret_val = agp_frontend_initialize();
if (ret_val) {
agp_bridge.type = NOT_SUPPORTED;
agp_backend_cleanup();
return ret_val;
}
inter_module_register("drm_agp", THIS_MODULE, &drm_agp);
pm_register(PM_PCI_DEV, PM_PCI_ID(agp_bridge.dev), agp_power);
agp_count++;
return 0;
}
int __exit agp_unregister_driver(void)
{
pm_unregister_all(agp_power);
agp_frontend_cleanup();
agp_backend_cleanup();
inter_module_unregister("drm_agp");
agp_count--;
return 0;
}
int __init agp_init(void)
{
memset(&agp_bridge, 0, sizeof(struct agp_bridge_data));
agp_bridge.type = NOT_SUPPORTED;
printk(KERN_INFO "Linux agpgart interface v%d.%d (c) Dave Jones\n",
AGPGART_VERSION_MAJOR, AGPGART_VERSION_MINOR);
return 0;
}
#ifndef CONFIG_GART_IOMMU
module_init(agp_init);
#endif
EXPORT_SYMBOL(agp_backend_acquire);
EXPORT_SYMBOL(agp_backend_release);
EXPORT_SYMBOL_GPL(agp_register_driver);
MODULE_AUTHOR("Dave Jones <davej@codemonkey.org.uk>");
MODULE_LICENSE("GPL and additional rights");
...@@ -1063,7 +1063,7 @@ static struct file_operations agp_fops = ...@@ -1063,7 +1063,7 @@ static struct file_operations agp_fops =
static struct miscdevice agp_miscdev = static struct miscdevice agp_miscdev =
{ {
AGPGART_MINOR, AGPGART_MINOR,
AGPGART_MODULE_NAME, "agpgart",
&agp_fops &agp_fops
}; };
......
/* /*
* AGPGART module version 0.99 * AGPGART module version 1.0
* Copyright (C) 1999 Jeff Hartmann * Copyright (C) 2002 Dave Jones.
* Copyright (C) 1999 Jeff Hartmann.
* Copyright (C) 1999 Precision Insight, Inc. * Copyright (C) 1999 Precision Insight, Inc.
* Copyright (C) 1999 Xi Graphics, Inc. * Copyright (C) 1999 Xi Graphics, Inc.
* *
...@@ -35,47 +36,8 @@ ...@@ -35,47 +36,8 @@
#include <linux/agp_backend.h> #include <linux/agp_backend.h>
#include "agp.h" #include "agp.h"
MODULE_AUTHOR("Jeff Hartmann <jhartmann@precisioninsight.com>");
MODULE_PARM(agp_try_unsupported, "1i");
MODULE_LICENSE("GPL and additional rights");
EXPORT_SYMBOL(agp_free_memory);
EXPORT_SYMBOL(agp_allocate_memory);
EXPORT_SYMBOL(agp_copy_info);
EXPORT_SYMBOL(agp_bind_memory);
EXPORT_SYMBOL(agp_unbind_memory);
EXPORT_SYMBOL(agp_enable);
EXPORT_SYMBOL(agp_backend_acquire);
EXPORT_SYMBOL(agp_backend_release);
struct agp_bridge_data agp_bridge = { .type = NOT_SUPPORTED };
static int agp_try_unsupported __initdata = 0;
int agp_memory_reserved;
__u32 *agp_gatt_table; __u32 *agp_gatt_table;
int agp_memory_reserved;
int agp_backend_acquire(void)
{
if (agp_bridge.type == NOT_SUPPORTED)
return -EINVAL;
atomic_inc(&agp_bridge.agp_in_use);
if (atomic_read(&agp_bridge.agp_in_use) != 1) {
atomic_dec(&agp_bridge.agp_in_use);
return -EBUSY;
}
MOD_INC_USE_COUNT;
return 0;
}
void agp_backend_release(void)
{
if (agp_bridge.type == NOT_SUPPORTED)
return;
atomic_dec(&agp_bridge.agp_in_use);
MOD_DEC_USE_COUNT;
}
/* /*
* Generic routines for handling agp_memory structures - * Generic routines for handling agp_memory structures -
...@@ -83,7 +45,6 @@ void agp_backend_release(void) ...@@ -83,7 +45,6 @@ void agp_backend_release(void)
* brunt of the work. * brunt of the work.
*/ */
void agp_free_key(int key) void agp_free_key(int key)
{ {
...@@ -170,19 +131,15 @@ agp_memory *agp_allocate_memory(size_t page_count, u32 type) ...@@ -170,19 +131,15 @@ agp_memory *agp_allocate_memory(size_t page_count, u32 type)
if (agp_bridge.type == NOT_SUPPORTED) if (agp_bridge.type == NOT_SUPPORTED)
return NULL; return NULL;
if ((atomic_read(&agp_bridge.current_memory_agp) + page_count) > if ((atomic_read(&agp_bridge.current_memory_agp) + page_count) > agp_bridge.max_memory_agp)
agp_bridge.max_memory_agp) {
return NULL; return NULL;
}
if (type != 0) { if (type != 0) {
new = agp_bridge.alloc_by_type(page_count, type); new = agp_bridge.alloc_by_type(page_count, type);
return new; return new;
} }
/* We always increase the module count, since free auto-decrements
* it
*/
/* We always increase the module count, since free auto-decrements it */
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
scratch_pages = (page_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE; scratch_pages = (page_count + ENTRIES_PER_PAGE - 1) / ENTRIES_PER_PAGE;
...@@ -198,7 +155,6 @@ agp_memory *agp_allocate_memory(size_t page_count, u32 type) ...@@ -198,7 +155,6 @@ agp_memory *agp_allocate_memory(size_t page_count, u32 type)
void *addr = agp_bridge.agp_alloc_page(); void *addr = agp_bridge.agp_alloc_page();
if (addr == NULL) { if (addr == NULL) {
/* Free this structure */
agp_free_memory(new); agp_free_memory(new);
return NULL; return NULL;
} }
...@@ -326,16 +282,8 @@ int agp_unbind_memory(agp_memory * curr) ...@@ -326,16 +282,8 @@ int agp_unbind_memory(agp_memory * curr)
/* End - Routines for handling swapping of agp_memory into the GATT */ /* End - Routines for handling swapping of agp_memory into the GATT */
/*
* Driver routines - start
* Currently this module supports the following chipsets:
* i810, i815, 440lx, 440bx, 440gx, i830, i840, i845, i850, i860, via vp3,
* via mvp3, via kx133, via kt133, amd irongate, amd 761, amd 762, ALi M1541,
* and generic support for the SiS chipsets.
*/
/* Generic Agp routines - Start */ /* Generic Agp routines - Start */
void agp_generic_agp_enable(u32 mode) void agp_generic_agp_enable(u32 mode)
{ {
struct pci_dev *device = NULL; struct pci_dev *device = NULL;
...@@ -345,11 +293,10 @@ void agp_generic_agp_enable(u32 mode) ...@@ -345,11 +293,10 @@ void agp_generic_agp_enable(u32 mode)
pci_read_config_dword(agp_bridge.dev, agp_bridge.capndx + 4, &command); pci_read_config_dword(agp_bridge.dev, agp_bridge.capndx + 4, &command);
/* /*
* PASS1: go throu all devices that claim to be * PASS1: go through all devices that claim to be
* AGP devices and collect their data. * AGP devices and collect their data.
*/ */
pci_for_each_dev(device) { pci_for_each_dev(device) {
cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
if (cap_ptr != 0x00) { if (cap_ptr != 0x00) {
...@@ -438,9 +385,8 @@ int agp_generic_create_gatt_table(void) ...@@ -438,9 +385,8 @@ int agp_generic_create_gatt_table(void)
struct page *page; struct page *page;
/* The generic routines can't handle 2 level gatt's */ /* The generic routines can't handle 2 level gatt's */
if (agp_bridge.size_type == LVL2_APER_SIZE) { if (agp_bridge.size_type == LVL2_APER_SIZE)
return -EINVAL; return -EINVAL;
}
table = NULL; table = NULL;
i = agp_bridge.aperture_size_idx; i = agp_bridge.aperture_size_idx;
...@@ -504,8 +450,7 @@ int agp_generic_create_gatt_table(void) ...@@ -504,8 +450,7 @@ int agp_generic_create_gatt_table(void)
} else { } else {
agp_bridge.aperture_size_idx = i; agp_bridge.aperture_size_idx = i;
} }
} while ((table == NULL) && } while ((table == NULL) && (i < agp_bridge.num_aperture_sizes));
(i < agp_bridge.num_aperture_sizes));
} else { } else {
size = ((struct aper_size_info_fixed *) temp)->size; size = ((struct aper_size_info_fixed *) temp)->size;
page_order = ((struct aper_size_info_fixed *) temp)->page_order; page_order = ((struct aper_size_info_fixed *) temp)->page_order;
...@@ -742,558 +687,10 @@ void agp_enable(u32 mode) ...@@ -742,558 +687,10 @@ void agp_enable(u32 mode)
agp_bridge.agp_enable(mode); agp_bridge.agp_enable(mode);
} }
/* End - Generic Agp routines */ EXPORT_SYMBOL(agp_free_memory);
EXPORT_SYMBOL(agp_allocate_memory);
/* per-chipset initialization data. */ EXPORT_SYMBOL(agp_copy_info);
static struct { EXPORT_SYMBOL(agp_bind_memory);
struct agp_bridge_info *ptr; EXPORT_SYMBOL(agp_unbind_memory);
} agp_bridge_list[] __initdata = { EXPORT_SYMBOL(agp_enable);
#ifdef CONFIG_AGP_ALI
{ .ptr = &ali_agp_bridge_info },
#endif
#ifdef CONFIG_AGP_AMD_8151
{.ptr = &amd_k8_agp_bridge_info },
#endif
#ifdef CONFIG_AGP_AMD
{.ptr = &amd_agp_bridge_info },
#endif
#ifdef CONFIG_AGP_INTEL
{.ptr = &intel_agp_bridge_info },
#endif
#ifdef CONFIG_AGP_SIS
{.ptr = &sis_agp_bridge_info },
#endif
#ifdef CONFIG_AGP_VIA
{.ptr = &via_agp_bridge_info },
#endif
#ifdef CONFIG_AGP_HP_ZX1
{.ptr = &hp_agp_bridge_info },
#endif
{NULL},
};
/* scan table above for supported devices */
static int __init agp_lookup_host_bridge (struct pci_dev *pdev)
{
int i=0, j=0;
struct agp_bridge_info *bridge=NULL;
struct agp_device_ids *devs;
while (agp_bridge_list[i].ptr != NULL) {
bridge = agp_bridge_list[i].ptr;
if (pdev->vendor == bridge->vendor_id)
break;
i++;
}
/* Vendor not found! */
if (bridge == NULL) {
printk (KERN_DEBUG PFX "unsupported bridge\n");
return -ENODEV;
}
devs = bridge->ids;
while (devs[j].chipset_name != NULL) {
if (pdev->device == devs[j].device_id) {
#ifdef CONFIG_AGP_ALI
if (pdev->device == PCI_DEVICE_ID_AL_M1621) {
u8 hidden_1621_id;
pci_read_config_byte(pdev, 0xFB, &hidden_1621_id);
switch (hidden_1621_id) {
case 0x31:
devs[j].chipset_name="M1631";
break;
case 0x32:
devs[j].chipset_name="M1632";
break;
case 0x41:
devs[j].chipset_name="M1641";
break;
case 0x43:
break;
case 0x47:
devs[j].chipset_name="M1647";
break;
case 0x51:
devs[j].chipset_name="M1651";
break;
default:
break;
}
}
#endif
printk (KERN_INFO PFX "Detected %s %s chipset\n",
bridge->vendor_name, devs[j].chipset_name);
agp_bridge.type = devs[j].chipset;
if (devs[j].chipset_setup != NULL)
return devs[j].chipset_setup(pdev);
else
return bridge->chipset_setup(pdev);
}
j++;
}
j--; /* point to vendor generic entry (device_id == 0) */
/* try init anyway, if user requests it AND
* there is a 'generic' bridge entry for this vendor */
if (agp_try_unsupported && devs[i].device_id == 0) {
printk(KERN_WARNING PFX "Trying generic %s routines"
" for device id: %04x\n",
bridge->vendor_name, pdev->device);
agp_bridge.type = devs[i].chipset;
return bridge->chipset_setup(pdev);
}
printk(KERN_ERR PFX "Unsupported %s chipset (device id: %04x),"
" you might want to try agp_try_unsupported=1.\n",
bridge->vendor_name, pdev->device);
return -ENODEV;
}
/* Supported Device Scanning routine */
static int __init agp_find_supported_device(struct pci_dev *dev)
{
u8 cap_ptr = 0x00;
agp_bridge.dev = dev;
/* Need to test for I810 here */
#ifdef CONFIG_AGP_I810
if (dev->vendor == PCI_VENDOR_ID_INTEL) {
struct pci_dev *i810_dev;
switch (dev->device) {
case PCI_DEVICE_ID_INTEL_82810_MC1:
i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82810_IG1,
NULL);
if (i810_dev == NULL) {
printk(KERN_ERR PFX "Detected an Intel i810,"
" but could not find the secondary"
" device.\n");
return -ENODEV;
}
printk(KERN_INFO PFX "Detected an Intel "
"i810 Chipset.\n");
agp_bridge.type = INTEL_I810;
return intel_i810_setup (i810_dev);
case PCI_DEVICE_ID_INTEL_82810_MC3:
i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82810_IG3,
NULL);
if (i810_dev == NULL) {
printk(KERN_ERR PFX "Detected an Intel i810 "
"DC100, but could not find the "
"secondary device.\n");
return -ENODEV;
}
printk(KERN_INFO PFX "Detected an Intel i810 "
"DC100 Chipset.\n");
agp_bridge.type = INTEL_I810;
return intel_i810_setup(i810_dev);
case PCI_DEVICE_ID_INTEL_82810E_MC:
i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82810E_IG,
NULL);
if (i810_dev == NULL) {
printk(KERN_ERR PFX "Detected an Intel i810 E"
", but could not find the secondary "
"device.\n");
return -ENODEV;
}
printk(KERN_INFO PFX "Detected an Intel i810 E "
"Chipset.\n");
agp_bridge.type = INTEL_I810;
return intel_i810_setup(i810_dev);
case PCI_DEVICE_ID_INTEL_82815_MC:
/* The i815 can operate either as an i810 style
* integrated device, or as an AGP4X motherboard.
*
* This only addresses the first mode:
*/
i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82815_CGC,
NULL);
if (i810_dev == NULL) {
printk(KERN_ERR PFX "agpgart: Detected an "
"Intel i815, but could not find the"
" secondary device. Assuming a "
"non-integrated video card.\n");
break;
}
printk(KERN_INFO PFX "agpgart: Detected an Intel i815 "
"Chipset.\n");
agp_bridge.type = INTEL_I810;
return intel_i810_setup(i810_dev);
case PCI_DEVICE_ID_INTEL_82845G_HB:
i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82845G_IG, NULL);
if(i810_dev && PCI_FUNC(i810_dev->devfn) != 0) {
i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82845G_IG, i810_dev);
}
if (i810_dev == NULL) {
/*
* We probably have a I845MP chipset
* with an external graphics
* card. It will be initialized later
*/
agp_bridge.type = INTEL_I845_G;
break;
}
printk(KERN_INFO PFX "Detected an Intel "
"845G Chipset.\n");
agp_bridge.type = INTEL_I810;
return intel_i830_setup(i810_dev);
case PCI_DEVICE_ID_INTEL_82830_HB:
i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82830_CGC,
NULL);
if(i810_dev && PCI_FUNC(i810_dev->devfn) != 0) {
i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82830_CGC,
i810_dev);
}
if (i810_dev == NULL) {
/* Intel 830MP with external graphic card */
/* It will be initialized later */
agp_bridge.type = INTEL_I830_M;
break;
}
printk(KERN_INFO PFX "Detected an Intel "
"830M Chipset.\n");
agp_bridge.type = INTEL_I810;
return intel_i830_setup(i810_dev);
default:
break;
}
}
#endif /* CONFIG_AGP_I810 */
#ifdef CONFIG_AGP_SWORKS
/* Everything is on func 1 here so we are hardcoding function one */
if (dev->vendor == PCI_VENDOR_ID_SERVERWORKS) {
struct pci_dev *bridge_dev;
bridge_dev = pci_find_slot ((unsigned int)dev->bus->number,
PCI_DEVFN(0, 1));
if(bridge_dev == NULL) {
printk(KERN_INFO PFX "agpgart: Detected a Serverworks "
"Chipset, but could not find the secondary "
"device.\n");
return -ENODEV;
}
switch (dev->device) {
case PCI_DEVICE_ID_SERVERWORKS_HE:
agp_bridge.type = SVWRKS_HE;
return serverworks_setup(bridge_dev);
case PCI_DEVICE_ID_SERVERWORKS_LE:
case 0x0007:
agp_bridge.type = SVWRKS_LE;
return serverworks_setup(bridge_dev);
default:
if(agp_try_unsupported) {
agp_bridge.type = SVWRKS_GENERIC;
return serverworks_setup(bridge_dev);
}
break;
}
}
#endif /* CONFIG_AGP_SWORKS */
#ifdef CONFIG_AGP_HP_ZX1
if (dev->vendor == PCI_VENDOR_ID_HP) {
/* 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);
}
return -ENODEV;
}
#endif /* CONFIG_AGP_HP_ZX1 */
/* find capndx */
cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP);
if (cap_ptr == 0x00)
return -ENODEV;
agp_bridge.capndx = cap_ptr;
/* Fill in the mode register */
pci_read_config_dword(agp_bridge.dev,
agp_bridge.capndx + 4,
&agp_bridge.mode);
/* probe for known chipsets */
return agp_lookup_host_bridge (dev);
}
struct agp_max_table {
int mem;
int agp;
};
static struct agp_max_table maxes_table[9] __initdata =
{
{0, 0},
{32, 4},
{64, 28},
{128, 96},
{256, 204},
{512, 440},
{1024, 942},
{2048, 1920},
{4096, 3932}
};
static int __init agp_find_max (void)
{
long memory, index, result;
memory = virt_to_phys(high_memory) >> 20;
index = 1;
while ((memory > maxes_table[index].mem) &&
(index < 8)) {
index++;
}
result = maxes_table[index - 1].agp +
( (memory - maxes_table[index - 1].mem) *
(maxes_table[index].agp - maxes_table[index - 1].agp)) /
(maxes_table[index].mem - maxes_table[index - 1].mem);
printk(KERN_INFO PFX "Maximum main memory to use "
"for agp memory: %ldM\n", result);
result = result << (20 - PAGE_SHIFT);
return result;
}
#define AGPGART_VERSION_MAJOR 0
#define AGPGART_VERSION_MINOR 99
static struct agp_version agp_current_version =
{
.major = AGPGART_VERSION_MAJOR,
.minor = AGPGART_VERSION_MINOR,
};
static int __init agp_backend_initialize(struct pci_dev *dev)
{
int size_value, rc, got_gatt=0, got_keylist=0;
memset(&agp_bridge, 0, sizeof(struct agp_bridge_data));
agp_bridge.type = NOT_SUPPORTED;
agp_bridge.max_memory_agp = agp_find_max();
agp_bridge.version = &agp_current_version;
rc = agp_find_supported_device(dev);
if (rc) {
/* not KERN_ERR because error msg should have already printed */
printk(KERN_DEBUG PFX "no supported devices found.\n");
return rc;
}
if (agp_bridge.needs_scratch_page == TRUE) {
void *addr;
addr = agp_bridge.agp_alloc_page();
if (addr == NULL) {
printk(KERN_ERR PFX "unable to get memory for "
"scratch page.\n");
return -ENOMEM;
}
agp_bridge.scratch_page = virt_to_phys(addr);
agp_bridge.scratch_page =
agp_bridge.mask_memory(agp_bridge.scratch_page, 0);
}
size_value = agp_bridge.fetch_size();
if (size_value == 0) {
printk(KERN_ERR PFX "unable to determine aperture size.\n");
rc = -EINVAL;
goto err_out;
}
if (agp_bridge.create_gatt_table()) {
printk(KERN_ERR PFX "unable to get memory for graphics "
"translation table.\n");
rc = -ENOMEM;
goto err_out;
}
got_gatt = 1;
agp_bridge.key_list = vmalloc(PAGE_SIZE * 4);
if (agp_bridge.key_list == NULL) {
printk(KERN_ERR PFX "error allocating memory for key lists.\n");
rc = -ENOMEM;
goto err_out;
}
got_keylist = 1;
/* FIXME vmalloc'd memory not guaranteed contiguous */
memset(agp_bridge.key_list, 0, PAGE_SIZE * 4);
if (agp_bridge.configure()) {
printk(KERN_ERR PFX "error configuring host chipset.\n");
rc = -EINVAL;
goto err_out;
}
printk(KERN_INFO PFX "AGP aperture is %dM @ 0x%lx\n",
size_value, agp_bridge.gart_bus_addr);
return 0;
err_out:
if (agp_bridge.needs_scratch_page == TRUE) {
agp_bridge.scratch_page &= ~(0x00000fff);
agp_bridge.agp_destroy_page(phys_to_virt(agp_bridge.scratch_page));
}
if (got_gatt)
agp_bridge.free_gatt_table();
if (got_keylist)
vfree(agp_bridge.key_list);
return rc;
}
/* cannot be __exit b/c as it could be called from __init code */
static void agp_backend_cleanup(void)
{
agp_bridge.cleanup();
agp_bridge.free_gatt_table();
vfree(agp_bridge.key_list);
if (agp_bridge.needs_scratch_page == TRUE) {
agp_bridge.scratch_page &= ~(0x00000fff);
agp_bridge.agp_destroy_page(phys_to_virt(agp_bridge.scratch_page));
}
}
static int agp_power(struct pm_dev *dev, pm_request_t rq, void *data)
{
switch(rq)
{
case PM_SUSPEND:
return agp_bridge.suspend();
case PM_RESUME:
agp_bridge.resume();
return 0;
}
return 0;
}
extern int agp_frontend_initialize(void);
extern void agp_frontend_cleanup(void);
static const drm_agp_t drm_agp = {
&agp_free_memory,
&agp_allocate_memory,
&agp_bind_memory,
&agp_unbind_memory,
&agp_enable,
&agp_backend_acquire,
&agp_backend_release,
&agp_copy_info
};
static int agp_probe (struct pci_dev *dev, const struct pci_device_id *ent)
{
int ret_val;
if (agp_bridge.type != NOT_SUPPORTED) {
printk (KERN_DEBUG PFX "Oops, don't init more than one agpgart device.\n");
return -ENODEV;
}
ret_val = agp_backend_initialize(dev);
if (ret_val) {
agp_bridge.type = NOT_SUPPORTED;
return ret_val;
}
ret_val = agp_frontend_initialize();
if (ret_val) {
agp_bridge.type = NOT_SUPPORTED;
agp_backend_cleanup();
return ret_val;
}
inter_module_register("drm_agp", THIS_MODULE, &drm_agp);
pm_register(PM_PCI_DEV, PM_PCI_ID(agp_bridge.dev), agp_power);
return 0;
}
static struct pci_device_id agp_pci_table[] __initdata = {
{
.class = (PCI_CLASS_BRIDGE_HOST << 8),
.class_mask = ~0,
.vendor = PCI_ANY_ID,
.device = PCI_ANY_ID,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
{ }
};
MODULE_DEVICE_TABLE(pci, agp_pci_table);
static struct pci_driver agp_pci_driver = {
.name = "agpgart",
.id_table = agp_pci_table,
.probe = agp_probe,
};
int __init agp_init(void)
{
int ret_val;
printk(KERN_INFO "Linux agpgart interface v%d.%d (c) Jeff Hartmann\n",
AGPGART_VERSION_MAJOR, AGPGART_VERSION_MINOR);
ret_val = pci_module_init(&agp_pci_driver);
if (ret_val) {
agp_bridge.type = NOT_SUPPORTED;
return ret_val;
}
return 0;
}
static void __exit agp_cleanup(void)
{
pci_unregister_driver(&agp_pci_driver);
if (agp_bridge.type != NOT_SUPPORTED) {
pm_unregister_all(agp_power);
agp_frontend_cleanup();
agp_backend_cleanup();
inter_module_unregister("drm_agp");
}
}
#ifndef CONFIG_GART_IOMMU
module_init(agp_init);
module_exit(agp_cleanup);
#endif
/* /*
* AGPGART module version 0.99 * HP AGPGART routines.
* Copyright (C) 1999 Jeff Hartmann
* Copyright (C) 1999 Precision Insight, Inc.
* Copyright (C) 1999 Xi Graphics, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* TODO:
* - Allocate more than order 0 pages to avoid too much linear map splitting.
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -31,7 +7,6 @@ ...@@ -31,7 +7,6 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/agp_backend.h> #include <linux/agp_backend.h>
#include "agp.h" #include "agp.h"
#include "hp.h"
#ifndef log2 #ifndef log2
#define log2(x) ffz(~(x)) #define log2(x) ffz(~(x))
...@@ -174,15 +149,13 @@ static int __init hp_zx1_ioc_init(void) ...@@ -174,15 +149,13 @@ static int __init hp_zx1_ioc_init(void)
for (i = 0; i < PCI_NUM_RESOURCES; i++) { for (i = 0; i < PCI_NUM_RESOURCES; i++) {
if (pci_resource_flags(ioc, i) == IORESOURCE_MEM) { if (pci_resource_flags(ioc, i) == IORESOURCE_MEM) {
hp->registers = (u8 *) ioremap(pci_resource_start(ioc, hp->registers = (u8 *) ioremap(pci_resource_start(ioc, i),
i),
pci_resource_len(ioc, i)); pci_resource_len(ioc, i));
break; break;
} }
} }
if (!hp->registers) { if (!hp->registers) {
printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no CSRs\n"); printk(KERN_ERR PFX "Detected HP ZX1 AGP bridge but no CSRs\n");
return -ENODEV; return -ENODEV;
} }
...@@ -386,9 +359,72 @@ int __init hp_zx1_setup (struct pci_dev *pdev) ...@@ -386,9 +359,72 @@ int __init hp_zx1_setup (struct pci_dev *pdev)
agp_bridge.agp_alloc_page = agp_generic_alloc_page; agp_bridge.agp_alloc_page = agp_generic_alloc_page;
agp_bridge.agp_destroy_page = agp_generic_destroy_page; agp_bridge.agp_destroy_page = agp_generic_destroy_page;
agp_bridge.cant_use_aperture = 1; agp_bridge.cant_use_aperture = 1;
return hp_zx1_ioc_init(); return hp_zx1_ioc_init();
}
static int __init agp_find_supported_device(struct pci_dev *dev)
{
agp_bridge.dev = dev;
/* 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);
}
return -ENODEV;
}
static int agp_hp_probe (struct pci_dev *dev, const struct pci_device_id *ent)
{
if (agp_find_supported_device(dev) == 0) {
agp_register_driver(dev);
return 0;
}
return -ENODEV;
}
(void) pdev; /* unused */ static struct pci_device_id agp_hp_pci_table[] __initdata = {
{
.class = (PCI_CLASS_BRIDGE_HOST << 8),
.class_mask = ~0,
.vendor_id = PCI_VENDOR_ID_HP,
.device = PCI_DEVICE_ID_HP_ZX1_LBA,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
{ }
};
MODULE_DEVICE_TABLE(pci, agp_pci_table);
static struct pci_driver agp_hp_pci_driver = {
.name = "agpgart-hp",
.id_table = agp_hp_pci_table,
.probe = agp_hp_probe,
};
static int __init agp_hp_init(void)
{
int ret_val;
ret_val = pci_module_init(&agp_hp_pci_driver);
if (ret_val)
agp_bridge.type = NOT_SUPPORTED;
return ret_val;
}
static void __exit agp_hp_cleanup(void)
{
agp_unregister_driver();
pci_unregister_driver(&agp_pci_driver);
} }
module_init(agp_hp_init);
module_exit(agp_hp_cleanup);
MODULE_LICENSE("GPL and additional rights");
struct agp_device_ids hp_agp_device_ids[] __initdata =
{
{
.device_id = PCI_DEVICE_ID_HP_ZX1_LBA,
.chipset = HP_ZX1,
.chipset_name = "ZX1",
},
{ }, /* dummy final entry, always present */
};
struct agp_bridge_info hp_agp_bridge_info __initdata =
{
.vendor_id = PCI_VENDOR_ID_HP,
.vendor_name = "HP",
.chipset_setup = hp_zx1_setup,
.ids = hp_agp_device_ids,
};
/* /*
* AGPGART module version 0.99 * FIXME: Nothing ever calls this stuff!
* Copyright (C) 1999 Jeff Hartmann
* Copyright (C) 1999 Precision Insight, Inc.
* Copyright (C) 1999 Xi Graphics, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* TODO:
* - Allocate more than order 0 pages to avoid too much linear map splitting.
*/ */
#include <linux/module.h> #include <linux/module.h>
......
/*
* AGPGART module version 0.99
* Copyright (C) 1999 Jeff Hartmann
* Copyright (C) 1999 Precision Insight, Inc.
* Copyright (C) 1999 Xi Graphics, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* TODO:
* - Allocate more than order 0 pages to avoid too much linear map splitting.
*/
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/agp_backend.h>
#include "agp.h"
static struct aper_size_info_fixed intel_i810_sizes[] =
{
{64, 16384, 4},
/* The 32M mode still requires a 64k gatt */
{32, 8192, 4}
};
#define AGP_DCACHE_MEMORY 1
#define AGP_PHYS_MEMORY 2
static struct gatt_mask intel_i810_masks[] =
{
{.mask = I810_PTE_VALID, .type = 0},
{.mask = (I810_PTE_VALID | I810_PTE_LOCAL), .type = AGP_DCACHE_MEMORY},
{.mask = I810_PTE_VALID, .type = 0}
};
static struct _intel_i810_private {
struct pci_dev *i810_dev; /* device one */
volatile u8 *registers;
int num_dcache_entries;
} intel_i810_private;
static int intel_i810_fetch_size(void)
{
u32 smram_miscc;
struct aper_size_info_fixed *values;
pci_read_config_dword(agp_bridge.dev, I810_SMRAM_MISCC, &smram_miscc);
values = A_SIZE_FIX(agp_bridge.aperture_sizes);
if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) {
printk(KERN_WARNING PFX "i810 is disabled\n");
return 0;
}
if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) {
agp_bridge.previous_size =
agp_bridge.current_size = (void *) (values + 1);
agp_bridge.aperture_size_idx = 1;
return values[1].size;
} else {
agp_bridge.previous_size =
agp_bridge.current_size = (void *) (values);
agp_bridge.aperture_size_idx = 0;
return values[0].size;
}
return 0;
}
static int intel_i810_configure(void)
{
struct aper_size_info_fixed *current_size;
u32 temp;
int i;
current_size = A_SIZE_FIX(agp_bridge.current_size);
pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp);
temp &= 0xfff80000;
intel_i810_private.registers =
(volatile u8 *) ioremap(temp, 128 * 4096);
if ((INREG32(intel_i810_private.registers, I810_DRAM_CTL)
& I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) {
/* This will need to be dynamically assigned */
printk(KERN_INFO PFX "detected 4MB dedicated video ram.\n");
intel_i810_private.num_dcache_entries = 1024;
}
pci_read_config_dword(intel_i810_private.i810_dev, I810_GMADDR, &temp);
agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL,
agp_bridge.gatt_bus_addr | I810_PGETBL_ENABLED);
CACHE_FLUSH();
if (agp_bridge.needs_scratch_page == TRUE) {
for (i = 0; i < current_size->num_entries; i++) {
OUTREG32(intel_i810_private.registers,
I810_PTE_BASE + (i * 4),
agp_bridge.scratch_page);
}
}
return 0;
}
static void intel_i810_cleanup(void)
{
OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL, 0);
iounmap((void *) intel_i810_private.registers);
}
static void intel_i810_tlbflush(agp_memory * mem)
{
return;
}
static void intel_i810_agp_enable(u32 mode)
{
return;
}
static int intel_i810_insert_entries(agp_memory * mem, off_t pg_start,
int type)
{
int i, j, num_entries;
void *temp;
temp = agp_bridge.current_size;
num_entries = A_SIZE_FIX(temp)->num_entries;
if ((pg_start + mem->page_count) > num_entries) {
return -EINVAL;
}
for (j = pg_start; j < (pg_start + mem->page_count); j++) {
if (!PGE_EMPTY(agp_bridge.gatt_table[j])) {
return -EBUSY;
}
}
if (type != 0 || mem->type != 0) {
if ((type == AGP_DCACHE_MEMORY) &&
(mem->type == AGP_DCACHE_MEMORY)) {
/* special insert */
CACHE_FLUSH();
for (i = pg_start;
i < (pg_start + mem->page_count); i++) {
OUTREG32(intel_i810_private.registers,
I810_PTE_BASE + (i * 4),
(i * 4096) | I810_PTE_LOCAL |
I810_PTE_VALID);
}
CACHE_FLUSH();
agp_bridge.tlb_flush(mem);
return 0;
}
if((type == AGP_PHYS_MEMORY) &&
(mem->type == AGP_PHYS_MEMORY)) {
goto insert;
}
return -EINVAL;
}
insert:
CACHE_FLUSH();
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
OUTREG32(intel_i810_private.registers,
I810_PTE_BASE + (j * 4), mem->memory[i]);
}
CACHE_FLUSH();
agp_bridge.tlb_flush(mem);
return 0;
}
static int intel_i810_remove_entries(agp_memory * mem, off_t pg_start,
int type)
{
int i;
for (i = pg_start; i < (mem->page_count + pg_start); i++) {
OUTREG32(intel_i810_private.registers,
I810_PTE_BASE + (i * 4),
agp_bridge.scratch_page);
}
CACHE_FLUSH();
agp_bridge.tlb_flush(mem);
return 0;
}
static agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type)
{
agp_memory *new;
if (type == AGP_DCACHE_MEMORY) {
if (pg_count != intel_i810_private.num_dcache_entries) {
return NULL;
}
new = agp_create_memory(1);
if (new == NULL) {
return NULL;
}
new->type = AGP_DCACHE_MEMORY;
new->page_count = pg_count;
new->num_scratch_pages = 0;
vfree(new->memory);
MOD_INC_USE_COUNT;
return new;
}
if(type == AGP_PHYS_MEMORY) {
void *addr;
/* The I810 requires a physical address to program
* it's mouse pointer into hardware. However the
* Xserver still writes to it through the agp
* aperture
*/
if (pg_count != 1) {
return NULL;
}
new = agp_create_memory(1);
if (new == NULL) {
return NULL;
}
MOD_INC_USE_COUNT;
addr = agp_bridge.agp_alloc_page();
if (addr == NULL) {
/* Free this structure */
agp_free_memory(new);
return NULL;
}
new->memory[0] = agp_bridge.mask_memory(virt_to_phys(addr), type);
new->page_count = 1;
new->num_scratch_pages = 1;
new->type = AGP_PHYS_MEMORY;
new->physical = virt_to_phys((void *) new->memory[0]);
return new;
}
return NULL;
}
static void intel_i810_free_by_type(agp_memory * curr)
{
agp_free_key(curr->key);
if(curr->type == AGP_PHYS_MEMORY) {
agp_bridge.agp_destroy_page(
phys_to_virt(curr->memory[0]));
vfree(curr->memory);
}
kfree(curr);
MOD_DEC_USE_COUNT;
}
static unsigned long intel_i810_mask_memory(unsigned long addr, int type)
{
/* Type checking must be done elsewhere */
return addr | agp_bridge.masks[type].mask;
}
int __init intel_i810_setup(struct pci_dev *i810_dev)
{
intel_i810_private.i810_dev = i810_dev;
agp_bridge.masks = intel_i810_masks;
agp_bridge.num_of_masks = 2;
agp_bridge.aperture_sizes = (void *) intel_i810_sizes;
agp_bridge.size_type = FIXED_APER_SIZE;
agp_bridge.num_aperture_sizes = 2;
agp_bridge.dev_private_data = (void *) &intel_i810_private;
agp_bridge.needs_scratch_page = TRUE;
agp_bridge.configure = intel_i810_configure;
agp_bridge.fetch_size = intel_i810_fetch_size;
agp_bridge.cleanup = intel_i810_cleanup;
agp_bridge.tlb_flush = intel_i810_tlbflush;
agp_bridge.mask_memory = intel_i810_mask_memory;
agp_bridge.agp_enable = intel_i810_agp_enable;
agp_bridge.cache_flush = global_cache_flush;
agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
agp_bridge.insert_memory = intel_i810_insert_entries;
agp_bridge.remove_memory = intel_i810_remove_entries;
agp_bridge.alloc_by_type = intel_i810_alloc_by_type;
agp_bridge.free_by_type = intel_i810_free_by_type;
agp_bridge.agp_alloc_page = agp_generic_alloc_page;
agp_bridge.agp_destroy_page = agp_generic_destroy_page;
agp_bridge.suspend = agp_generic_suspend;
agp_bridge.resume = agp_generic_resume;
agp_bridge.cant_use_aperture = 0;
return 0;
}
static struct aper_size_info_fixed intel_i830_sizes[] =
{
{128, 32768, 5},
/* The 64M mode still requires a 128k gatt */
{64, 16384, 5}
};
static struct _intel_i830_private {
struct pci_dev *i830_dev; /* device one */
volatile u8 *registers;
int gtt_entries;
} intel_i830_private;
static void intel_i830_init_gtt_entries(void)
{
u16 gmch_ctrl;
int gtt_entries;
u8 rdct;
static const int ddt[4] = { 0, 16, 32, 64 };
pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl);
switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
case I830_GMCH_GMS_STOLEN_512:
gtt_entries = KB(512) - KB(132);
printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1));
break;
case I830_GMCH_GMS_STOLEN_1024:
gtt_entries = MB(1) - KB(132);
printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1));
break;
case I830_GMCH_GMS_STOLEN_8192:
gtt_entries = MB(8) - KB(132);
printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1));
break;
case I830_GMCH_GMS_LOCAL:
rdct = INREG8(intel_i830_private.registers,I830_RDRAM_CHANNEL_TYPE);
gtt_entries = (I830_RDRAM_ND(rdct) + 1) * MB(ddt[I830_RDRAM_DDT(rdct)]);
printk(KERN_INFO PFX "detected %dK local memory.\n",gtt_entries / KB(1));
break;
default:
printk(KERN_INFO PFX "no video memory detected.\n");
gtt_entries = 0;
break;
}
gtt_entries /= KB(4);
intel_i830_private.gtt_entries = gtt_entries;
}
/* The intel i830 automatically initializes the agp aperture during POST.
* Use the memory already set aside for in the GTT.
*/
static int intel_i830_create_gatt_table(void)
{
int page_order;
struct aper_size_info_fixed *size;
int num_entries;
u32 temp;
size = agp_bridge.current_size;
page_order = size->page_order;
num_entries = size->num_entries;
agp_bridge.gatt_table_real = 0;
pci_read_config_dword(intel_i830_private.i830_dev,I810_MMADDR,&temp);
temp &= 0xfff80000;
intel_i830_private.registers = (volatile u8 *) ioremap(temp,128 * 4096);
if (!intel_i830_private.registers) return (-ENOMEM);
temp = INREG32(intel_i830_private.registers,I810_PGETBL_CTL) & 0xfffff000;
CACHE_FLUSH();
/* we have to call this as early as possible after the MMIO base address is known */
intel_i830_init_gtt_entries();
agp_bridge.gatt_table = NULL;
agp_bridge.gatt_bus_addr = temp;
return(0);
}
/* Return the gatt table to a sane state. Use the top of stolen
* memory for the GTT.
*/
static int intel_i830_free_gatt_table(void)
{
return(0);
}
static int intel_i830_fetch_size(void)
{
u16 gmch_ctrl;
struct aper_size_info_fixed *values;
pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl);
values = A_SIZE_FIX(agp_bridge.aperture_sizes);
if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
agp_bridge.previous_size = agp_bridge.current_size = (void *) values;
agp_bridge.aperture_size_idx = 0;
return(values[0].size);
} else {
agp_bridge.previous_size = agp_bridge.current_size = (void *) values;
agp_bridge.aperture_size_idx = 1;
return(values[1].size);
}
return(0);
}
static int intel_i830_configure(void)
{
struct aper_size_info_fixed *current_size;
u32 temp;
u16 gmch_ctrl;
int i;
current_size = A_SIZE_FIX(agp_bridge.current_size);
pci_read_config_dword(intel_i830_private.i830_dev,I810_GMADDR,&temp);
agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl);
gmch_ctrl |= I830_GMCH_ENABLED;
pci_write_config_word(agp_bridge.dev,I830_GMCH_CTRL,gmch_ctrl);
OUTREG32(intel_i830_private.registers,I810_PGETBL_CTL,agp_bridge.gatt_bus_addr | I810_PGETBL_ENABLED);
CACHE_FLUSH();
if (agp_bridge.needs_scratch_page == TRUE)
for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++)
OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page);
return (0);
}
static void intel_i830_cleanup(void)
{
iounmap((void *) intel_i830_private.registers);
}
static int intel_i830_insert_entries(agp_memory *mem,off_t pg_start,int type)
{
int i,j,num_entries;
void *temp;
temp = agp_bridge.current_size;
num_entries = A_SIZE_FIX(temp)->num_entries;
if (pg_start < intel_i830_private.gtt_entries) {
printk (KERN_DEBUG "pg_start == 0x%.8lx,intel_i830_private.gtt_entries == 0x%.8x\n",
pg_start,intel_i830_private.gtt_entries);
printk ("Trying to insert into local/stolen memory\n");
return (-EINVAL);
}
if ((pg_start + mem->page_count) > num_entries)
return (-EINVAL);
/* The i830 can't check the GTT for entries since its read only,
* depend on the caller to make the correct offset decisions.
*/
if ((type != 0 && type != AGP_PHYS_MEMORY) ||
(mem->type != 0 && mem->type != AGP_PHYS_MEMORY))
return (-EINVAL);
CACHE_FLUSH();
for (i = 0, j = pg_start; i < mem->page_count; i++, j++)
OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),mem->memory[i]);
CACHE_FLUSH();
agp_bridge.tlb_flush(mem);
return(0);
}
static int intel_i830_remove_entries(agp_memory *mem,off_t pg_start,int type)
{
int i;
CACHE_FLUSH ();
if (pg_start < intel_i830_private.gtt_entries) {
printk ("Trying to disable local/stolen memory\n");
return (-EINVAL);
}
for (i = pg_start; i < (mem->page_count + pg_start); i++)
OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page);
CACHE_FLUSH();
agp_bridge.tlb_flush(mem);
return (0);
}
static agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type)
{
agp_memory *nw;
/* always return NULL for now */
if (type == AGP_DCACHE_MEMORY) return(NULL);
if (type == AGP_PHYS_MEMORY) {
void *addr;
/* The i830 requires a physical address to program
* it's mouse pointer into hardware. However the
* Xserver still writes to it through the agp
* aperture
*/
if (pg_count != 1) return(NULL);
nw = agp_create_memory(1);
if (nw == NULL) return(NULL);
MOD_INC_USE_COUNT;
addr = agp_bridge.agp_alloc_page();
if (addr == NULL) {
/* free this structure */
agp_free_memory(nw);
return(NULL);
}
nw->memory[0] = agp_bridge.mask_memory(virt_to_phys(addr),type);
nw->page_count = 1;
nw->num_scratch_pages = 1;
nw->type = AGP_PHYS_MEMORY;
nw->physical = virt_to_phys(addr);
return(nw);
}
return(NULL);
}
int __init intel_i830_setup(struct pci_dev *i830_dev)
{
intel_i830_private.i830_dev = i830_dev;
agp_bridge.masks = intel_i810_masks;
agp_bridge.num_of_masks = 3;
agp_bridge.aperture_sizes = (void *) intel_i830_sizes;
agp_bridge.size_type = FIXED_APER_SIZE;
agp_bridge.num_aperture_sizes = 2;
agp_bridge.dev_private_data = (void *) &intel_i830_private;
agp_bridge.needs_scratch_page = TRUE;
agp_bridge.configure = intel_i830_configure;
agp_bridge.fetch_size = intel_i830_fetch_size;
agp_bridge.cleanup = intel_i830_cleanup;
agp_bridge.tlb_flush = intel_i810_tlbflush;
agp_bridge.mask_memory = intel_i810_mask_memory;
agp_bridge.agp_enable = intel_i810_agp_enable;
agp_bridge.cache_flush = global_cache_flush;
agp_bridge.create_gatt_table = intel_i830_create_gatt_table;
agp_bridge.free_gatt_table = intel_i830_free_gatt_table;
agp_bridge.insert_memory = intel_i830_insert_entries;
agp_bridge.remove_memory = intel_i830_remove_entries;
agp_bridge.alloc_by_type = intel_i830_alloc_by_type;
agp_bridge.free_by_type = intel_i810_free_by_type;
agp_bridge.agp_alloc_page = agp_generic_alloc_page;
agp_bridge.agp_destroy_page = agp_generic_destroy_page;
agp_bridge.suspend = agp_generic_suspend;
agp_bridge.resume = agp_generic_resume;
agp_bridge.cant_use_aperture = 0;
return(0);
}
struct agp_device_ids intel_agp_device_ids[] __initdata =
{
{
.device_id = PCI_DEVICE_ID_INTEL_82443LX_0,
.chipset = INTEL_LX,
.chipset_name = "440LX",
},
{
.device_id = PCI_DEVICE_ID_INTEL_82443BX_0,
.chipset = INTEL_BX,
.chipset_name = "440BX",
},
{
.device_id = PCI_DEVICE_ID_INTEL_82443GX_0,
.chipset = INTEL_GX,
.chipset_name = "440GX",
},
{
.device_id = PCI_DEVICE_ID_INTEL_82815_MC,
.chipset = INTEL_I815,
.chipset_name = "i815",
.chipset_setup = intel_815_setup
},
{
.device_id = PCI_DEVICE_ID_INTEL_82820_HB,
.chipset = INTEL_I820,
.chipset_name = "i820",
.chipset_setup = intel_820_setup
},
{
.device_id = PCI_DEVICE_ID_INTEL_82820_UP_HB,
.chipset = INTEL_I820,
.chipset_name = "i820",
.chipset_setup = intel_820_setup
},
{
.device_id = PCI_DEVICE_ID_INTEL_82830_HB,
.chipset = INTEL_I830_M,
.chipset_name = "i830M",
.chipset_setup = intel_830mp_setup
},
{
.device_id = PCI_DEVICE_ID_INTEL_82845G_HB,
.chipset = INTEL_I845_G,
.chipset_name = "i845G",
.chipset_setup = intel_830mp_setup
},
{
.device_id = PCI_DEVICE_ID_INTEL_82840_HB,
.chipset = INTEL_I840,
.chipset_name = "i840",
.chipset_setup = intel_840_setup
},
{
.device_id = PCI_DEVICE_ID_INTEL_82845_HB,
.chipset = INTEL_I845,
.chipset_name = "i845",
.chipset_setup = intel_845_setup
},
{
.device_id = PCI_DEVICE_ID_INTEL_82850_HB,
.chipset = INTEL_I850,
.chipset_name = "i850",
.chipset_setup = intel_850_setup
},
{
.device_id = PCI_DEVICE_ID_INTEL_82860_HB,
.chipset = INTEL_I860,
.chipset_name = "i860",
.chipset_setup = intel_860_setup
},
{
.device_id = 0,
.chipset = INTEL_GENERIC,
.chipset_name = "Generic",
},
{ }, /* dummy final entry, always present */
};
struct agp_bridge_info intel_agp_bridge_info __initdata =
{
.vendor_id = PCI_VENDOR_ID_INTEL,
.vendor_name = "Intel",
.chipset_setup = intel_generic_setup,
.ids = intel_agp_device_ids,
};
/* /*
* AGPGART module version 0.99 * Intel AGPGART routines.
* Copyright (C) 1999 Jeff Hartmann
* Copyright (C) 1999 Precision Insight, Inc.
* Copyright (C) 1999 Xi Graphics, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* TODO:
* - Allocate more than order 0 pages to avoid too much linear map splitting.
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -31,8 +7,569 @@ ...@@ -31,8 +7,569 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/agp_backend.h> #include <linux/agp_backend.h>
#include "agp.h" #include "agp.h"
#include "i8x0.h"
static int agp_try_unsupported __initdata = 0;
static struct aper_size_info_fixed intel_i810_sizes[] =
{
{64, 16384, 4},
/* The 32M mode still requires a 64k gatt */
{32, 8192, 4}
};
#define AGP_DCACHE_MEMORY 1
#define AGP_PHYS_MEMORY 2
static struct gatt_mask intel_i810_masks[] =
{
{.mask = I810_PTE_VALID, .type = 0},
{.mask = (I810_PTE_VALID | I810_PTE_LOCAL), .type = AGP_DCACHE_MEMORY},
{.mask = I810_PTE_VALID, .type = 0}
};
static struct _intel_i810_private {
struct pci_dev *i810_dev; /* device one */
volatile u8 *registers;
int num_dcache_entries;
} intel_i810_private;
static int intel_i810_fetch_size(void)
{
u32 smram_miscc;
struct aper_size_info_fixed *values;
pci_read_config_dword(agp_bridge.dev, I810_SMRAM_MISCC, &smram_miscc);
values = A_SIZE_FIX(agp_bridge.aperture_sizes);
if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) {
printk(KERN_WARNING PFX "i810 is disabled\n");
return 0;
}
if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) {
agp_bridge.previous_size =
agp_bridge.current_size = (void *) (values + 1);
agp_bridge.aperture_size_idx = 1;
return values[1].size;
} else {
agp_bridge.previous_size =
agp_bridge.current_size = (void *) (values);
agp_bridge.aperture_size_idx = 0;
return values[0].size;
}
return 0;
}
static int intel_i810_configure(void)
{
struct aper_size_info_fixed *current_size;
u32 temp;
int i;
current_size = A_SIZE_FIX(agp_bridge.current_size);
pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp);
temp &= 0xfff80000;
intel_i810_private.registers =
(volatile u8 *) ioremap(temp, 128 * 4096);
if ((INREG32(intel_i810_private.registers, I810_DRAM_CTL)
& I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) {
/* This will need to be dynamically assigned */
printk(KERN_INFO PFX "detected 4MB dedicated video ram.\n");
intel_i810_private.num_dcache_entries = 1024;
}
pci_read_config_dword(intel_i810_private.i810_dev, I810_GMADDR, &temp);
agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL,
agp_bridge.gatt_bus_addr | I810_PGETBL_ENABLED);
CACHE_FLUSH();
if (agp_bridge.needs_scratch_page == TRUE) {
for (i = 0; i < current_size->num_entries; i++) {
OUTREG32(intel_i810_private.registers,
I810_PTE_BASE + (i * 4),
agp_bridge.scratch_page);
}
}
return 0;
}
static void intel_i810_cleanup(void)
{
OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL, 0);
iounmap((void *) intel_i810_private.registers);
}
static void intel_i810_tlbflush(agp_memory * mem)
{
return;
}
static void intel_i810_agp_enable(u32 mode)
{
return;
}
static int intel_i810_insert_entries(agp_memory * mem, off_t pg_start,
int type)
{
int i, j, num_entries;
void *temp;
temp = agp_bridge.current_size;
num_entries = A_SIZE_FIX(temp)->num_entries;
if ((pg_start + mem->page_count) > num_entries) {
return -EINVAL;
}
for (j = pg_start; j < (pg_start + mem->page_count); j++) {
if (!PGE_EMPTY(agp_bridge.gatt_table[j])) {
return -EBUSY;
}
}
if (type != 0 || mem->type != 0) {
if ((type == AGP_DCACHE_MEMORY) &&
(mem->type == AGP_DCACHE_MEMORY)) {
/* special insert */
CACHE_FLUSH();
for (i = pg_start;
i < (pg_start + mem->page_count); i++) {
OUTREG32(intel_i810_private.registers,
I810_PTE_BASE + (i * 4),
(i * 4096) | I810_PTE_LOCAL |
I810_PTE_VALID);
}
CACHE_FLUSH();
agp_bridge.tlb_flush(mem);
return 0;
}
if((type == AGP_PHYS_MEMORY) &&
(mem->type == AGP_PHYS_MEMORY)) {
goto insert;
}
return -EINVAL;
}
insert:
CACHE_FLUSH();
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
OUTREG32(intel_i810_private.registers,
I810_PTE_BASE + (j * 4), mem->memory[i]);
}
CACHE_FLUSH();
agp_bridge.tlb_flush(mem);
return 0;
}
static int intel_i810_remove_entries(agp_memory * mem, off_t pg_start,
int type)
{
int i;
for (i = pg_start; i < (mem->page_count + pg_start); i++) {
OUTREG32(intel_i810_private.registers,
I810_PTE_BASE + (i * 4),
agp_bridge.scratch_page);
}
CACHE_FLUSH();
agp_bridge.tlb_flush(mem);
return 0;
}
static agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type)
{
agp_memory *new;
if (type == AGP_DCACHE_MEMORY) {
if (pg_count != intel_i810_private.num_dcache_entries) {
return NULL;
}
new = agp_create_memory(1);
if (new == NULL) {
return NULL;
}
new->type = AGP_DCACHE_MEMORY;
new->page_count = pg_count;
new->num_scratch_pages = 0;
vfree(new->memory);
MOD_INC_USE_COUNT;
return new;
}
if(type == AGP_PHYS_MEMORY) {
void *addr;
/* The I810 requires a physical address to program
* it's mouse pointer into hardware. However the
* Xserver still writes to it through the agp
* aperture
*/
if (pg_count != 1) {
return NULL;
}
new = agp_create_memory(1);
if (new == NULL) {
return NULL;
}
MOD_INC_USE_COUNT;
addr = agp_bridge.agp_alloc_page();
if (addr == NULL) {
/* Free this structure */
agp_free_memory(new);
return NULL;
}
new->memory[0] = agp_bridge.mask_memory(virt_to_phys(addr), type);
new->page_count = 1;
new->num_scratch_pages = 1;
new->type = AGP_PHYS_MEMORY;
new->physical = virt_to_phys((void *) new->memory[0]);
return new;
}
return NULL;
}
static void intel_i810_free_by_type(agp_memory * curr)
{
agp_free_key(curr->key);
if(curr->type == AGP_PHYS_MEMORY) {
agp_bridge.agp_destroy_page(
phys_to_virt(curr->memory[0]));
vfree(curr->memory);
}
kfree(curr);
MOD_DEC_USE_COUNT;
}
static unsigned long intel_i810_mask_memory(unsigned long addr, int type)
{
/* Type checking must be done elsewhere */
return addr | agp_bridge.masks[type].mask;
}
int __init intel_i810_setup(struct pci_dev *i810_dev)
{
intel_i810_private.i810_dev = i810_dev;
agp_bridge.masks = intel_i810_masks;
agp_bridge.num_of_masks = 2;
agp_bridge.aperture_sizes = (void *) intel_i810_sizes;
agp_bridge.size_type = FIXED_APER_SIZE;
agp_bridge.num_aperture_sizes = 2;
agp_bridge.dev_private_data = (void *) &intel_i810_private;
agp_bridge.needs_scratch_page = TRUE;
agp_bridge.configure = intel_i810_configure;
agp_bridge.fetch_size = intel_i810_fetch_size;
agp_bridge.cleanup = intel_i810_cleanup;
agp_bridge.tlb_flush = intel_i810_tlbflush;
agp_bridge.mask_memory = intel_i810_mask_memory;
agp_bridge.agp_enable = intel_i810_agp_enable;
agp_bridge.cache_flush = global_cache_flush;
agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
agp_bridge.insert_memory = intel_i810_insert_entries;
agp_bridge.remove_memory = intel_i810_remove_entries;
agp_bridge.alloc_by_type = intel_i810_alloc_by_type;
agp_bridge.free_by_type = intel_i810_free_by_type;
agp_bridge.agp_alloc_page = agp_generic_alloc_page;
agp_bridge.agp_destroy_page = agp_generic_destroy_page;
agp_bridge.suspend = agp_generic_suspend;
agp_bridge.resume = agp_generic_resume;
agp_bridge.cant_use_aperture = 0;
return 0;
}
static struct aper_size_info_fixed intel_i830_sizes[] =
{
{128, 32768, 5},
/* The 64M mode still requires a 128k gatt */
{64, 16384, 5}
};
static struct _intel_i830_private {
struct pci_dev *i830_dev; /* device one */
volatile u8 *registers;
int gtt_entries;
} intel_i830_private;
static void intel_i830_init_gtt_entries(void)
{
u16 gmch_ctrl;
int gtt_entries;
u8 rdct;
static const int ddt[4] = { 0, 16, 32, 64 };
pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl);
switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
case I830_GMCH_GMS_STOLEN_512:
gtt_entries = KB(512) - KB(132);
printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1));
break;
case I830_GMCH_GMS_STOLEN_1024:
gtt_entries = MB(1) - KB(132);
printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1));
break;
case I830_GMCH_GMS_STOLEN_8192:
gtt_entries = MB(8) - KB(132);
printk(KERN_INFO PFX "detected %dK stolen memory.\n",gtt_entries / KB(1));
break;
case I830_GMCH_GMS_LOCAL:
rdct = INREG8(intel_i830_private.registers,I830_RDRAM_CHANNEL_TYPE);
gtt_entries = (I830_RDRAM_ND(rdct) + 1) * MB(ddt[I830_RDRAM_DDT(rdct)]);
printk(KERN_INFO PFX "detected %dK local memory.\n",gtt_entries / KB(1));
break;
default:
printk(KERN_INFO PFX "no video memory detected.\n");
gtt_entries = 0;
break;
}
gtt_entries /= KB(4);
intel_i830_private.gtt_entries = gtt_entries;
}
/* The intel i830 automatically initializes the agp aperture during POST.
* Use the memory already set aside for in the GTT.
*/
static int intel_i830_create_gatt_table(void)
{
int page_order;
struct aper_size_info_fixed *size;
int num_entries;
u32 temp;
size = agp_bridge.current_size;
page_order = size->page_order;
num_entries = size->num_entries;
agp_bridge.gatt_table_real = 0;
pci_read_config_dword(intel_i830_private.i830_dev,I810_MMADDR,&temp);
temp &= 0xfff80000;
intel_i830_private.registers = (volatile u8 *) ioremap(temp,128 * 4096);
if (!intel_i830_private.registers) return (-ENOMEM);
temp = INREG32(intel_i830_private.registers,I810_PGETBL_CTL) & 0xfffff000;
CACHE_FLUSH();
/* we have to call this as early as possible after the MMIO base address is known */
intel_i830_init_gtt_entries();
agp_bridge.gatt_table = NULL;
agp_bridge.gatt_bus_addr = temp;
return(0);
}
/* Return the gatt table to a sane state. Use the top of stolen
* memory for the GTT.
*/
static int intel_i830_free_gatt_table(void)
{
return(0);
}
static int intel_i830_fetch_size(void)
{
u16 gmch_ctrl;
struct aper_size_info_fixed *values;
pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl);
values = A_SIZE_FIX(agp_bridge.aperture_sizes);
if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
agp_bridge.previous_size = agp_bridge.current_size = (void *) values;
agp_bridge.aperture_size_idx = 0;
return(values[0].size);
} else {
agp_bridge.previous_size = agp_bridge.current_size = (void *) values;
agp_bridge.aperture_size_idx = 1;
return(values[1].size);
}
return(0);
}
static int intel_i830_configure(void)
{
struct aper_size_info_fixed *current_size;
u32 temp;
u16 gmch_ctrl;
int i;
current_size = A_SIZE_FIX(agp_bridge.current_size);
pci_read_config_dword(intel_i830_private.i830_dev,I810_GMADDR,&temp);
agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
pci_read_config_word(agp_bridge.dev,I830_GMCH_CTRL,&gmch_ctrl);
gmch_ctrl |= I830_GMCH_ENABLED;
pci_write_config_word(agp_bridge.dev,I830_GMCH_CTRL,gmch_ctrl);
OUTREG32(intel_i830_private.registers,I810_PGETBL_CTL,agp_bridge.gatt_bus_addr | I810_PGETBL_ENABLED);
CACHE_FLUSH();
if (agp_bridge.needs_scratch_page == TRUE)
for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++)
OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page);
return (0);
}
static void intel_i830_cleanup(void)
{
iounmap((void *) intel_i830_private.registers);
}
static int intel_i830_insert_entries(agp_memory *mem,off_t pg_start,int type)
{
int i,j,num_entries;
void *temp;
temp = agp_bridge.current_size;
num_entries = A_SIZE_FIX(temp)->num_entries;
if (pg_start < intel_i830_private.gtt_entries) {
printk (KERN_DEBUG "pg_start == 0x%.8lx,intel_i830_private.gtt_entries == 0x%.8x\n",
pg_start,intel_i830_private.gtt_entries);
printk ("Trying to insert into local/stolen memory\n");
return (-EINVAL);
}
if ((pg_start + mem->page_count) > num_entries)
return (-EINVAL);
/* The i830 can't check the GTT for entries since its read only,
* depend on the caller to make the correct offset decisions.
*/
if ((type != 0 && type != AGP_PHYS_MEMORY) ||
(mem->type != 0 && mem->type != AGP_PHYS_MEMORY))
return (-EINVAL);
CACHE_FLUSH();
for (i = 0, j = pg_start; i < mem->page_count; i++, j++)
OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),mem->memory[i]);
CACHE_FLUSH();
agp_bridge.tlb_flush(mem);
return(0);
}
static int intel_i830_remove_entries(agp_memory *mem,off_t pg_start,int type)
{
int i;
CACHE_FLUSH ();
if (pg_start < intel_i830_private.gtt_entries) {
printk ("Trying to disable local/stolen memory\n");
return (-EINVAL);
}
for (i = pg_start; i < (mem->page_count + pg_start); i++)
OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge.scratch_page);
CACHE_FLUSH();
agp_bridge.tlb_flush(mem);
return (0);
}
static agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type)
{
agp_memory *nw;
/* always return NULL for now */
if (type == AGP_DCACHE_MEMORY) return(NULL);
if (type == AGP_PHYS_MEMORY) {
void *addr;
/* The i830 requires a physical address to program
* it's mouse pointer into hardware. However the
* Xserver still writes to it through the agp
* aperture
*/
if (pg_count != 1) return(NULL);
nw = agp_create_memory(1);
if (nw == NULL) return(NULL);
MOD_INC_USE_COUNT;
addr = agp_bridge.agp_alloc_page();
if (addr == NULL) {
/* free this structure */
agp_free_memory(nw);
return(NULL);
}
nw->memory[0] = agp_bridge.mask_memory(virt_to_phys(addr),type);
nw->page_count = 1;
nw->num_scratch_pages = 1;
nw->type = AGP_PHYS_MEMORY;
nw->physical = virt_to_phys(addr);
return(nw);
}
return(NULL);
}
int __init intel_i830_setup(struct pci_dev *i830_dev)
{
intel_i830_private.i830_dev = i830_dev;
agp_bridge.masks = intel_i810_masks;
agp_bridge.num_of_masks = 3;
agp_bridge.aperture_sizes = (void *) intel_i830_sizes;
agp_bridge.size_type = FIXED_APER_SIZE;
agp_bridge.num_aperture_sizes = 2;
agp_bridge.dev_private_data = (void *) &intel_i830_private;
agp_bridge.needs_scratch_page = TRUE;
agp_bridge.configure = intel_i830_configure;
agp_bridge.fetch_size = intel_i830_fetch_size;
agp_bridge.cleanup = intel_i830_cleanup;
agp_bridge.tlb_flush = intel_i810_tlbflush;
agp_bridge.mask_memory = intel_i810_mask_memory;
agp_bridge.agp_enable = intel_i810_agp_enable;
agp_bridge.cache_flush = global_cache_flush;
agp_bridge.create_gatt_table = intel_i830_create_gatt_table;
agp_bridge.free_gatt_table = intel_i830_free_gatt_table;
agp_bridge.insert_memory = intel_i830_insert_entries;
agp_bridge.remove_memory = intel_i830_remove_entries;
agp_bridge.alloc_by_type = intel_i830_alloc_by_type;
agp_bridge.free_by_type = intel_i810_free_by_type;
agp_bridge.agp_alloc_page = agp_generic_alloc_page;
agp_bridge.agp_destroy_page = agp_generic_destroy_page;
agp_bridge.suspend = agp_generic_suspend;
agp_bridge.resume = agp_generic_resume;
agp_bridge.cant_use_aperture = 0;
return(0);
}
static int intel_fetch_size(void) static int intel_fetch_size(void)
{ {
int i; int i;
...@@ -106,8 +643,7 @@ static void intel_cleanup(void) ...@@ -106,8 +643,7 @@ static void intel_cleanup(void)
previous_size = A_SIZE_16(agp_bridge.previous_size); previous_size = A_SIZE_16(agp_bridge.previous_size);
pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp); pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp);
pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, temp & ~(1 << 9)); pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, temp & ~(1 << 9));
pci_write_config_word(agp_bridge.dev, INTEL_APSIZE, pci_write_config_word(agp_bridge.dev, INTEL_APSIZE, previous_size->size_value);
previous_size->size_value);
} }
...@@ -119,8 +655,7 @@ static void intel_8xx_cleanup(void) ...@@ -119,8 +655,7 @@ static void intel_8xx_cleanup(void)
previous_size = A_SIZE_8(agp_bridge.previous_size); previous_size = A_SIZE_8(agp_bridge.previous_size);
pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp); pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp);
pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, temp & ~(1 << 9)); pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, temp & ~(1 << 9));
pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, previous_size->size_value);
previous_size->size_value);
} }
...@@ -133,16 +668,14 @@ static int intel_configure(void) ...@@ -133,16 +668,14 @@ static int intel_configure(void)
current_size = A_SIZE_16(agp_bridge.current_size); current_size = A_SIZE_16(agp_bridge.current_size);
/* aperture size */ /* aperture size */
pci_write_config_word(agp_bridge.dev, INTEL_APSIZE, pci_write_config_word(agp_bridge.dev, INTEL_APSIZE, current_size->size_value);
current_size->size_value);
/* address to map to */ /* address to map to */
pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
/* attbase - aperture base */ /* attbase - aperture base */
pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, agp_bridge.gatt_bus_addr);
agp_bridge.gatt_bus_addr);
/* agpctrl */ /* agpctrl */
pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2280); pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x2280);
...@@ -222,16 +755,14 @@ static int intel_820_configure(void) ...@@ -222,16 +755,14 @@ static int intel_820_configure(void)
current_size = A_SIZE_8(agp_bridge.current_size); current_size = A_SIZE_8(agp_bridge.current_size);
/* aperture size */ /* aperture size */
pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, current_size->size_value);
current_size->size_value);
/* address to map to */ /* address to map to */
pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
/* attbase - aperture base */ /* attbase - aperture base */
pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, agp_bridge.gatt_bus_addr);
agp_bridge.gatt_bus_addr);
/* agpctrl */ /* agpctrl */
pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000);
...@@ -240,8 +771,7 @@ static int intel_820_configure(void) ...@@ -240,8 +771,7 @@ static int intel_820_configure(void)
/* This flag is not accessed through MCHCFG register as in */ /* This flag is not accessed through MCHCFG register as in */
/* i850 chipset. */ /* i850 chipset. */
pci_read_config_byte(agp_bridge.dev, INTEL_I820_RDCR, &temp2); pci_read_config_byte(agp_bridge.dev, INTEL_I820_RDCR, &temp2);
pci_write_config_byte(agp_bridge.dev, INTEL_I820_RDCR, pci_write_config_byte(agp_bridge.dev, INTEL_I820_RDCR, temp2 | (1 << 1));
temp2 | (1 << 1));
/* clear any possible AGP-related error conditions */ /* clear any possible AGP-related error conditions */
pci_write_config_word(agp_bridge.dev, INTEL_I820_ERRSTS, 0x001c); pci_write_config_word(agp_bridge.dev, INTEL_I820_ERRSTS, 0x001c);
return 0; return 0;
...@@ -256,24 +786,21 @@ static int intel_840_configure(void) ...@@ -256,24 +786,21 @@ static int intel_840_configure(void)
current_size = A_SIZE_8(agp_bridge.current_size); current_size = A_SIZE_8(agp_bridge.current_size);
/* aperture size */ /* aperture size */
pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, current_size->size_value);
current_size->size_value);
/* address to map to */ /* address to map to */
pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
/* attbase - aperture base */ /* attbase - aperture base */
pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, agp_bridge.gatt_bus_addr);
agp_bridge.gatt_bus_addr);
/* agpctrl */ /* agpctrl */
pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000);
/* mcgcfg */ /* mcgcfg */
pci_read_config_word(agp_bridge.dev, INTEL_I840_MCHCFG, &temp2); pci_read_config_word(agp_bridge.dev, INTEL_I840_MCHCFG, &temp2);
pci_write_config_word(agp_bridge.dev, INTEL_I840_MCHCFG, pci_write_config_word(agp_bridge.dev, INTEL_I840_MCHCFG, temp2 | (1 << 9));
temp2 | (1 << 9));
/* clear any possible error conditions */ /* clear any possible error conditions */
pci_write_config_word(agp_bridge.dev, INTEL_I840_ERRSTS, 0xc000); pci_write_config_word(agp_bridge.dev, INTEL_I840_ERRSTS, 0xc000);
return 0; return 0;
...@@ -288,24 +815,21 @@ static int intel_845_configure(void) ...@@ -288,24 +815,21 @@ static int intel_845_configure(void)
current_size = A_SIZE_8(agp_bridge.current_size); current_size = A_SIZE_8(agp_bridge.current_size);
/* aperture size */ /* aperture size */
pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, current_size->size_value);
current_size->size_value);
/* address to map to */ /* address to map to */
pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
/* attbase - aperture base */ /* attbase - aperture base */
pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, agp_bridge.gatt_bus_addr);
agp_bridge.gatt_bus_addr);
/* agpctrl */ /* agpctrl */
pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000);
/* agpm */ /* agpm */
pci_read_config_byte(agp_bridge.dev, INTEL_I845_AGPM, &temp2); pci_read_config_byte(agp_bridge.dev, INTEL_I845_AGPM, &temp2);
pci_write_config_byte(agp_bridge.dev, INTEL_I845_AGPM, pci_write_config_byte(agp_bridge.dev, INTEL_I845_AGPM, temp2 | (1 << 1));
temp2 | (1 << 1));
/* clear any possible error conditions */ /* clear any possible error conditions */
pci_write_config_word(agp_bridge.dev, INTEL_I845_ERRSTS, 0x001c); pci_write_config_word(agp_bridge.dev, INTEL_I845_ERRSTS, 0x001c);
return 0; return 0;
...@@ -325,24 +849,21 @@ static int intel_850_configure(void) ...@@ -325,24 +849,21 @@ static int intel_850_configure(void)
current_size = A_SIZE_8(agp_bridge.current_size); current_size = A_SIZE_8(agp_bridge.current_size);
/* aperture size */ /* aperture size */
pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, current_size->size_value);
current_size->size_value);
/* address to map to */ /* address to map to */
pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
/* attbase - aperture base */ /* attbase - aperture base */
pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, agp_bridge.gatt_bus_addr);
agp_bridge.gatt_bus_addr);
/* agpctrl */ /* agpctrl */
pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000);
/* mcgcfg */ /* mcgcfg */
pci_read_config_word(agp_bridge.dev, INTEL_I850_MCHCFG, &temp2); pci_read_config_word(agp_bridge.dev, INTEL_I850_MCHCFG, &temp2);
pci_write_config_word(agp_bridge.dev, INTEL_I850_MCHCFG, pci_write_config_word(agp_bridge.dev, INTEL_I850_MCHCFG, temp2 | (1 << 9));
temp2 | (1 << 9));
/* clear any possible AGP-related error conditions */ /* clear any possible AGP-related error conditions */
pci_write_config_word(agp_bridge.dev, INTEL_I850_ERRSTS, 0x001c); pci_write_config_word(agp_bridge.dev, INTEL_I850_ERRSTS, 0x001c);
return 0; return 0;
...@@ -357,24 +878,21 @@ static int intel_860_configure(void) ...@@ -357,24 +878,21 @@ static int intel_860_configure(void)
current_size = A_SIZE_8(agp_bridge.current_size); current_size = A_SIZE_8(agp_bridge.current_size);
/* aperture size */ /* aperture size */
pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, current_size->size_value);
current_size->size_value);
/* address to map to */ /* address to map to */
pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
/* attbase - aperture base */ /* attbase - aperture base */
pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, agp_bridge.gatt_bus_addr);
agp_bridge.gatt_bus_addr);
/* agpctrl */ /* agpctrl */
pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000);
/* mcgcfg */ /* mcgcfg */
pci_read_config_word(agp_bridge.dev, INTEL_I860_MCHCFG, &temp2); pci_read_config_word(agp_bridge.dev, INTEL_I860_MCHCFG, &temp2);
pci_write_config_word(agp_bridge.dev, INTEL_I860_MCHCFG, pci_write_config_word(agp_bridge.dev, INTEL_I860_MCHCFG, temp2 | (1 << 9));
temp2 | (1 << 9));
/* clear any possible AGP-related error conditions */ /* clear any possible AGP-related error conditions */
pci_write_config_word(agp_bridge.dev, INTEL_I860_ERRSTS, 0xf700); pci_write_config_word(agp_bridge.dev, INTEL_I860_ERRSTS, 0xf700);
return 0; return 0;
...@@ -389,24 +907,21 @@ static int intel_830mp_configure(void) ...@@ -389,24 +907,21 @@ static int intel_830mp_configure(void)
current_size = A_SIZE_8(agp_bridge.current_size); current_size = A_SIZE_8(agp_bridge.current_size);
/* aperture size */ /* aperture size */
pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, pci_write_config_byte(agp_bridge.dev, INTEL_APSIZE, current_size->size_value);
current_size->size_value);
/* address to map to */ /* address to map to */
pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp); pci_read_config_dword(agp_bridge.dev, INTEL_APBASE, &temp);
agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
/* attbase - aperture base */ /* attbase - aperture base */
pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, pci_write_config_dword(agp_bridge.dev, INTEL_ATTBASE, agp_bridge.gatt_bus_addr);
agp_bridge.gatt_bus_addr);
/* agpctrl */ /* agpctrl */
pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000); pci_write_config_dword(agp_bridge.dev, INTEL_AGPCTRL, 0x0000);
/* gmch */ /* gmch */
pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp2); pci_read_config_word(agp_bridge.dev, INTEL_NBXCFG, &temp2);
pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, pci_write_config_word(agp_bridge.dev, INTEL_NBXCFG, temp2 | (1 << 9));
temp2 | (1 << 9));
/* clear any possible AGP-related error conditions */ /* clear any possible AGP-related error conditions */
pci_write_config_word(agp_bridge.dev, INTEL_I830_ERRSTS, 0x1c); pci_write_config_word(agp_bridge.dev, INTEL_I830_ERRSTS, 0x1c);
return 0; return 0;
...@@ -415,7 +930,6 @@ static int intel_830mp_configure(void) ...@@ -415,7 +930,6 @@ static int intel_830mp_configure(void)
static unsigned long intel_mask_memory(unsigned long addr, int type) static unsigned long intel_mask_memory(unsigned long addr, int type)
{ {
/* Memory type is ignored */ /* Memory type is ignored */
return addr | agp_bridge.masks[0].mask; return addr | agp_bridge.masks[0].mask;
} }
...@@ -466,7 +980,7 @@ static struct aper_size_info_8 intel_830mp_sizes[4] = ...@@ -466,7 +980,7 @@ static struct aper_size_info_8 intel_830mp_sizes[4] =
{32, 8192, 3, 56} {32, 8192, 3, 56}
}; };
int __init intel_generic_setup (struct pci_dev *pdev) static int __init intel_generic_setup (struct pci_dev *pdev)
{ {
agp_bridge.masks = intel_generic_masks; agp_bridge.masks = intel_generic_masks;
agp_bridge.num_of_masks = 1; agp_bridge.num_of_masks = 1;
...@@ -493,13 +1007,10 @@ int __init intel_generic_setup (struct pci_dev *pdev) ...@@ -493,13 +1007,10 @@ int __init intel_generic_setup (struct pci_dev *pdev)
agp_bridge.suspend = agp_generic_suspend; agp_bridge.suspend = agp_generic_suspend;
agp_bridge.resume = intel_resume; agp_bridge.resume = intel_resume;
agp_bridge.cant_use_aperture = 0; agp_bridge.cant_use_aperture = 0;
return 0; return 0;
(void) pdev; /* unused */
} }
int __init intel_815_setup (struct pci_dev *pdev) static int __init intel_815_setup (struct pci_dev *pdev)
{ {
agp_bridge.masks = intel_generic_masks; agp_bridge.masks = intel_generic_masks;
agp_bridge.num_of_masks = 1; agp_bridge.num_of_masks = 1;
...@@ -526,78 +1037,71 @@ int __init intel_815_setup (struct pci_dev *pdev) ...@@ -526,78 +1037,71 @@ int __init intel_815_setup (struct pci_dev *pdev)
agp_bridge.suspend = agp_generic_suspend; agp_bridge.suspend = agp_generic_suspend;
agp_bridge.resume = agp_generic_resume; agp_bridge.resume = agp_generic_resume;
agp_bridge.cant_use_aperture = 0; agp_bridge.cant_use_aperture = 0;
return 0;
}
static int __init intel_820_setup (struct pci_dev *pdev)
{
agp_bridge.masks = intel_generic_masks;
agp_bridge.num_of_masks = 1;
agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
agp_bridge.size_type = U8_APER_SIZE;
agp_bridge.num_aperture_sizes = 7;
agp_bridge.dev_private_data = NULL;
agp_bridge.needs_scratch_page = FALSE;
agp_bridge.configure = intel_820_configure;
agp_bridge.fetch_size = intel_8xx_fetch_size;
agp_bridge.cleanup = intel_820_cleanup;
agp_bridge.tlb_flush = intel_820_tlbflush;
agp_bridge.mask_memory = intel_mask_memory;
agp_bridge.agp_enable = agp_generic_agp_enable;
agp_bridge.cache_flush = global_cache_flush;
agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
agp_bridge.insert_memory = agp_generic_insert_memory;
agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend;
agp_bridge.resume = agp_generic_resume;
agp_bridge.cant_use_aperture = 0;
return 0; return 0;
} }
static int __init intel_830mp_setup (struct pci_dev *pdev)
{
agp_bridge.masks = intel_generic_masks;
agp_bridge.num_of_masks = 1;
agp_bridge.aperture_sizes = (void *) intel_830mp_sizes;
agp_bridge.size_type = U8_APER_SIZE;
agp_bridge.num_aperture_sizes = 4;
agp_bridge.dev_private_data = NULL;
agp_bridge.needs_scratch_page = FALSE;
agp_bridge.configure = intel_830mp_configure;
agp_bridge.fetch_size = intel_8xx_fetch_size;
agp_bridge.cleanup = intel_8xx_cleanup;
agp_bridge.tlb_flush = intel_8xx_tlbflush;
agp_bridge.mask_memory = intel_mask_memory;
agp_bridge.agp_enable = agp_generic_agp_enable;
agp_bridge.cache_flush = global_cache_flush;
agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
agp_bridge.insert_memory = agp_generic_insert_memory;
agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend;
agp_bridge.resume = agp_generic_resume;
agp_bridge.cant_use_aperture = 0;
return 0;
}
int __init intel_820_setup (struct pci_dev *pdev) static int __init intel_840_setup (struct pci_dev *pdev)
{
agp_bridge.masks = intel_generic_masks;
agp_bridge.num_of_masks = 1;
agp_bridge.aperture_sizes = (void *) intel_8xx_sizes;
agp_bridge.size_type = U8_APER_SIZE;
agp_bridge.num_aperture_sizes = 7;
agp_bridge.dev_private_data = NULL;
agp_bridge.needs_scratch_page = FALSE;
agp_bridge.configure = intel_820_configure;
agp_bridge.fetch_size = intel_8xx_fetch_size;
agp_bridge.cleanup = intel_820_cleanup;
agp_bridge.tlb_flush = intel_820_tlbflush;
agp_bridge.mask_memory = intel_mask_memory;
agp_bridge.agp_enable = agp_generic_agp_enable;
agp_bridge.cache_flush = global_cache_flush;
agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
agp_bridge.insert_memory = agp_generic_insert_memory;
agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend;
agp_bridge.resume = agp_generic_resume;
agp_bridge.cant_use_aperture = 0;
return 0;
(void) pdev; /* unused */
}
int __init intel_830mp_setup (struct pci_dev *pdev)
{
agp_bridge.masks = intel_generic_masks;
agp_bridge.num_of_masks = 1;
agp_bridge.aperture_sizes = (void *) intel_830mp_sizes;
agp_bridge.size_type = U8_APER_SIZE;
agp_bridge.num_aperture_sizes = 4;
agp_bridge.dev_private_data = NULL;
agp_bridge.needs_scratch_page = FALSE;
agp_bridge.configure = intel_830mp_configure;
agp_bridge.fetch_size = intel_8xx_fetch_size;
agp_bridge.cleanup = intel_8xx_cleanup;
agp_bridge.tlb_flush = intel_8xx_tlbflush;
agp_bridge.mask_memory = intel_mask_memory;
agp_bridge.agp_enable = agp_generic_agp_enable;
agp_bridge.cache_flush = global_cache_flush;
agp_bridge.create_gatt_table = agp_generic_create_gatt_table;
agp_bridge.free_gatt_table = agp_generic_free_gatt_table;
agp_bridge.insert_memory = agp_generic_insert_memory;
agp_bridge.remove_memory = agp_generic_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.suspend = agp_generic_suspend;
agp_bridge.resume = agp_generic_resume;
agp_bridge.cant_use_aperture = 0;
return 0;
(void) pdev; /* unused */
}
int __init intel_840_setup (struct pci_dev *pdev)
{ {
agp_bridge.masks = intel_generic_masks; agp_bridge.masks = intel_generic_masks;
agp_bridge.num_of_masks = 1; agp_bridge.num_of_masks = 1;
...@@ -624,13 +1128,10 @@ int __init intel_840_setup (struct pci_dev *pdev) ...@@ -624,13 +1128,10 @@ int __init intel_840_setup (struct pci_dev *pdev)
agp_bridge.suspend = agp_generic_suspend; agp_bridge.suspend = agp_generic_suspend;
agp_bridge.resume = agp_generic_resume; agp_bridge.resume = agp_generic_resume;
agp_bridge.cant_use_aperture = 0; agp_bridge.cant_use_aperture = 0;
return 0; return 0;
(void) pdev; /* unused */
} }
int __init intel_845_setup (struct pci_dev *pdev) static int __init intel_845_setup (struct pci_dev *pdev)
{ {
agp_bridge.masks = intel_generic_masks; agp_bridge.masks = intel_generic_masks;
agp_bridge.num_of_masks = 1; agp_bridge.num_of_masks = 1;
...@@ -657,13 +1158,10 @@ int __init intel_845_setup (struct pci_dev *pdev) ...@@ -657,13 +1158,10 @@ int __init intel_845_setup (struct pci_dev *pdev)
agp_bridge.suspend = agp_generic_suspend; agp_bridge.suspend = agp_generic_suspend;
agp_bridge.resume = intel_845_resume; agp_bridge.resume = intel_845_resume;
agp_bridge.cant_use_aperture = 0; agp_bridge.cant_use_aperture = 0;
return 0; return 0;
(void) pdev; /* unused */
} }
int __init intel_850_setup (struct pci_dev *pdev) static int __init intel_850_setup (struct pci_dev *pdev)
{ {
agp_bridge.masks = intel_generic_masks; agp_bridge.masks = intel_generic_masks;
agp_bridge.num_of_masks = 1; agp_bridge.num_of_masks = 1;
...@@ -690,13 +1188,10 @@ int __init intel_850_setup (struct pci_dev *pdev) ...@@ -690,13 +1188,10 @@ int __init intel_850_setup (struct pci_dev *pdev)
agp_bridge.suspend = agp_generic_suspend; agp_bridge.suspend = agp_generic_suspend;
agp_bridge.resume = agp_generic_resume; agp_bridge.resume = agp_generic_resume;
agp_bridge.cant_use_aperture = 0; agp_bridge.cant_use_aperture = 0;
return 0; return 0;
(void) pdev; /* unused */
} }
int __init intel_860_setup (struct pci_dev *pdev) static int __init intel_860_setup (struct pci_dev *pdev)
{ {
agp_bridge.masks = intel_generic_masks; agp_bridge.masks = intel_generic_masks;
agp_bridge.num_of_masks = 1; agp_bridge.num_of_masks = 1;
...@@ -723,9 +1218,279 @@ int __init intel_860_setup (struct pci_dev *pdev) ...@@ -723,9 +1218,279 @@ int __init intel_860_setup (struct pci_dev *pdev)
agp_bridge.suspend = agp_generic_suspend; agp_bridge.suspend = agp_generic_suspend;
agp_bridge.resume = agp_generic_resume; agp_bridge.resume = agp_generic_resume;
agp_bridge.cant_use_aperture = 0; agp_bridge.cant_use_aperture = 0;
return 0; return 0;
}
struct agp_device_ids intel_agp_device_ids[] __initdata =
{
{
.device_id = PCI_DEVICE_ID_INTEL_82443LX_0,
.chipset = INTEL_LX,
.chipset_name = "440LX",
},
{
.device_id = PCI_DEVICE_ID_INTEL_82443BX_0,
.chipset = INTEL_BX,
.chipset_name = "440BX",
},
{
.device_id = PCI_DEVICE_ID_INTEL_82443GX_0,
.chipset = INTEL_GX,
.chipset_name = "440GX",
},
{
.device_id = PCI_DEVICE_ID_INTEL_82815_MC,
.chipset = INTEL_I815,
.chipset_name = "i815",
.chipset_setup = intel_815_setup
},
{
.device_id = PCI_DEVICE_ID_INTEL_82820_HB,
.chipset = INTEL_I820,
.chipset_name = "i820",
.chipset_setup = intel_820_setup
},
{
.device_id = PCI_DEVICE_ID_INTEL_82820_UP_HB,
.chipset = INTEL_I820,
.chipset_name = "i820",
.chipset_setup = intel_820_setup
},
{
.device_id = PCI_DEVICE_ID_INTEL_82830_HB,
.chipset = INTEL_I830_M,
.chipset_name = "i830M",
.chipset_setup = intel_830mp_setup
},
{
.device_id = PCI_DEVICE_ID_INTEL_82845G_HB,
.chipset = INTEL_I845_G,
.chipset_name = "i845G",
.chipset_setup = intel_830mp_setup
},
{
.device_id = PCI_DEVICE_ID_INTEL_82840_HB,
.chipset = INTEL_I840,
.chipset_name = "i840",
.chipset_setup = intel_840_setup
},
{
.device_id = PCI_DEVICE_ID_INTEL_82845_HB,
.chipset = INTEL_I845,
.chipset_name = "i845",
.chipset_setup = intel_845_setup
},
{
.device_id = PCI_DEVICE_ID_INTEL_82850_HB,
.chipset = INTEL_I850,
.chipset_name = "i850",
.chipset_setup = intel_850_setup
},
{
.device_id = PCI_DEVICE_ID_INTEL_82860_HB,
.chipset = INTEL_I860,
.chipset_name = "i860",
.chipset_setup = intel_860_setup
},
{ }, /* dummy final entry, always present */
};
(void) pdev; /* unused */ /* scan table above for supported devices */
static int __init agp_lookup_host_bridge (struct pci_dev *pdev)
{
int j=0;
struct agp_device_ids *devs;
devs = intel_agp_device_ids;
while (devs[j].chipset_name != NULL) {
if (pdev->device == devs[j].device_id) {
printk (KERN_INFO PFX "Detected Intel %s chipset\n",
devs[j].chipset_name);
agp_bridge.type = devs[j].chipset;
if (devs[j].chipset_setup != NULL)
return devs[j].chipset_setup(pdev);
else
return intel_generic_setup(pdev);
}
j++;
}
j--;
/* try init anyway, if user requests it */
if (agp_try_unsupported) {
printk(KERN_WARNING PFX "Trying generic Intel routines"
" for device id: %04x\n", pdev->device);
agp_bridge.type = INTEL_GENERIC;
return intel_generic_setup(pdev);
}
printk(KERN_ERR PFX "Unsupported Intel chipset (device id: %04x),"
" you might want to try agp_try_unsupported=1.\n", pdev->device);
return -ENODEV;
}
/* Supported Device Scanning routine */
static int __init agp_find_supported_device(struct pci_dev *dev)
{
struct pci_dev *i810_dev;
agp_bridge.dev = dev;
/* This shit needs moving into tables/init-routines. */
switch (dev->device) {
case PCI_DEVICE_ID_INTEL_82810_MC1:
i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG1, NULL);
if (i810_dev == NULL) {
printk(KERN_ERR PFX "Detected an Intel i810,"
" but could not find the secondary device.\n");
return -ENODEV;
}
printk(KERN_INFO PFX "Detected an Intel i810 Chipset.\n");
agp_bridge.type = INTEL_I810;
return intel_i810_setup (i810_dev);
case PCI_DEVICE_ID_INTEL_82810_MC3:
i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3, NULL);
if (i810_dev == NULL) {
printk(KERN_ERR PFX "Detected an Intel i810 DC100, but could not find the "
"secondary device.\n");
return -ENODEV;
}
printk(KERN_INFO PFX "Detected an Intel i810 DC100 Chipset.\n");
agp_bridge.type = INTEL_I810;
return intel_i810_setup(i810_dev);
case PCI_DEVICE_ID_INTEL_82810E_MC:
i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810E_IG, NULL);
if (i810_dev == NULL) {
printk(KERN_ERR PFX "Detected an Intel i810 E"
", but could not find the secondary device.\n");
return -ENODEV;
}
printk(KERN_INFO PFX "Detected an Intel i810 E Chipset.\n");
agp_bridge.type = INTEL_I810;
return intel_i810_setup(i810_dev);
case PCI_DEVICE_ID_INTEL_82815_MC:
/* The i815 can operate either as an i810 style
* integrated device, or as an AGP4X motherboard.
*
* This only addresses the first mode:
*/
i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_CGC, NULL);
if (i810_dev == NULL) {
printk(KERN_ERR PFX "agpgart: Detected an "
"Intel i815, but could not find the"
" secondary device. Assuming a "
"non-integrated video card.\n");
break;
}
printk(KERN_INFO PFX "agpgart: Detected an Intel i815 Chipset.\n");
agp_bridge.type = INTEL_I810;
return intel_i810_setup(i810_dev);
case PCI_DEVICE_ID_INTEL_82845G_HB:
i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82845G_IG, NULL);
if (i810_dev && PCI_FUNC(i810_dev->devfn) != 0) {
i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82845G_IG, i810_dev);
}
if (i810_dev == NULL) {
/*
* We probably have a I845MP chipset with an external graphics
* card. It will be initialized later
*/
agp_bridge.type = INTEL_I845_G;
break;
}
printk(KERN_INFO PFX "Detected an Intel 845G Chipset.\n");
agp_bridge.type = INTEL_I810;
return intel_i830_setup(i810_dev);
case PCI_DEVICE_ID_INTEL_82830_HB:
i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82830_CGC, NULL);
if(i810_dev && PCI_FUNC(i810_dev->devfn) != 0)
i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82830_CGC, i810_dev);
if (i810_dev == NULL) {
/* Intel 830MP with external graphic card */
/* It will be initialized later */
agp_bridge.type = INTEL_I830_M;
break;
}
printk(KERN_INFO PFX "Detected an Intel 830M Chipset.\n");
agp_bridge.type = INTEL_I810;
return intel_i830_setup(i810_dev);
default:
break;
}
if (pci_find_capability(dev, PCI_CAP_ID_AGP)==0)
return -ENODEV;
/* probe for known chipsets */
return agp_lookup_host_bridge(dev);
} }
static int agp_intel_probe (struct pci_dev *dev, const struct pci_device_id *ent)
{
if (agp_find_supported_device(dev) == 0) {
agp_register_driver(dev);
return 0;
}
return -ENODEV;
}
static struct pci_device_id agp_intel_pci_table[] __initdata = {
{
.class = (PCI_CLASS_BRIDGE_HOST << 8),
.class_mask = ~0,
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_ANY_ID,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
{ }
};
MODULE_DEVICE_TABLE(pci, agp_intel_pci_table);
static struct pci_driver agp_intel_pci_driver = {
.name = "agpgart-intel",
.id_table = agp_intel_pci_table,
.probe = agp_intel_probe,
};
static int __init agp_intel_init(void)
{
int ret_val;
ret_val = pci_module_init(&agp_intel_pci_driver);
if (ret_val)
agp_bridge.type = NOT_SUPPORTED;
return ret_val;
}
static void __exit agp_intel_cleanup(void)
{
agp_unregister_driver();
pci_unregister_driver(&agp_intel_pci_driver);
}
module_init(agp_intel_init);
module_exit(agp_intel_cleanup);
MODULE_PARM(agp_try_unsupported, "1i");
MODULE_AUTHOR("Dave Jones <davej@codemonkey.org.uk>");
MODULE_LICENSE("GPL and additional rights");
struct agp_device_ids amd_k8_device_ids[] __initdata =
{
{
.device_id = PCI_DEVICE_ID_AMD_8151_0,
.chipset = AMD_8151,
.chipset_name = "8151",
},
{ }, /* dummy final entry, always present */
};
struct agp_bridge_info amd_k8_agp_bridge_info __initdata =
{
.vendor_id = PCI_VENDOR_ID_AMD,
.vendor_name = "AMD",
.chipset_setup = amd_8151_setup,
.ids = amd_k8_device_ids,
};
/* /*
* AGPGART module version 0.99 * SiS AGPGART routines.
* Copyright (C) 1999 Jeff Hartmann
* Copyright (C) 1999 Precision Insight, Inc.
* Copyright (C) 1999 Xi Graphics, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* TODO:
* - Allocate more than order 0 pages to avoid too much linear map splitting.
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -31,7 +7,8 @@ ...@@ -31,7 +7,8 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/agp_backend.h> #include <linux/agp_backend.h>
#include "agp.h" #include "agp.h"
#include "sis.h"
static int agp_try_unsupported __initdata = 0;
static int sis_fetch_size(void) static int sis_fetch_size(void)
{ {
...@@ -56,7 +33,6 @@ static int sis_fetch_size(void) ...@@ -56,7 +33,6 @@ static int sis_fetch_size(void)
return 0; return 0;
} }
static void sis_tlbflush(agp_memory * mem) static void sis_tlbflush(agp_memory * mem)
{ {
pci_write_config_byte(agp_bridge.dev, SIS_TLBFLUSH, 0x02); pci_write_config_byte(agp_bridge.dev, SIS_TLBFLUSH, 0x02);
...@@ -141,3 +117,172 @@ int __init sis_generic_setup (struct pci_dev *pdev) ...@@ -141,3 +117,172 @@ int __init sis_generic_setup (struct pci_dev *pdev)
return 0; return 0;
} }
struct agp_device_ids sis_agp_device_ids[] __initdata =
{
{
.device_id = PCI_DEVICE_ID_SI_740,
.chipset = SIS_GENERIC,
.chipset_name = "740",
},
{
.device_id = PCI_DEVICE_ID_SI_650,
.chipset = SIS_GENERIC,
.chipset_name = "650",
},
{
.device_id = PCI_DEVICE_ID_SI_651,
.chipset = SIS_GENERIC,
.chipset_name = "651",
},
{
.device_id = PCI_DEVICE_ID_SI_645,
.chipset = SIS_GENERIC,
.chipset_name = "645",
},
{
.device_id = PCI_DEVICE_ID_SI_646,
.chipset = SIS_GENERIC,
.chipset_name = "646",
},
{
.device_id = PCI_DEVICE_ID_SI_735,
.chipset = SIS_GENERIC,
.chipset_name = "735",
},
{
.device_id = PCI_DEVICE_ID_SI_745,
.chipset = SIS_GENERIC,
.chipset_name = "745",
},
{
.device_id = PCI_DEVICE_ID_SI_730,
.chipset = SIS_GENERIC,
.chipset_name = "730",
},
{
.device_id = PCI_DEVICE_ID_SI_630,
.chipset = SIS_GENERIC,
.chipset_name = "630",
},
{
.device_id = PCI_DEVICE_ID_SI_540,
.chipset = SIS_GENERIC,
.chipset_name = "540",
},
{
.device_id = PCI_DEVICE_ID_SI_620,
.chipset = SIS_GENERIC,
.chipset_name = "620",
},
{
.device_id = PCI_DEVICE_ID_SI_530,
.chipset = SIS_GENERIC,
.chipset_name = "530",
},
{
.device_id = PCI_DEVICE_ID_SI_550,
.chipset = SIS_GENERIC,
.chipset_name = "550",
},
{ }, /* dummy final entry, always present */
};
/* scan table above for supported devices */
static int __init agp_lookup_host_bridge (struct pci_dev *pdev)
{
int j=0;
struct agp_device_ids *devs;
devs = sis_agp_device_ids;
while (devs[j].chipset_name != NULL) {
if (pdev->device == devs[j].device_id) {
printk (KERN_INFO PFX "Detected SiS %s chipset\n",
devs[j].chipset_name);
agp_bridge.type = devs[j].chipset;
if (devs[j].chipset_setup != NULL)
return devs[j].chipset_setup(pdev);
else
return sis_generic_setup(pdev);
}
j++;
}
/* try init anyway, if user requests it */
if (agp_try_unsupported) {
printk(KERN_WARNING PFX "Trying generic SiS routines"
" for device id: %04x\n", pdev->device);
agp_bridge.type = SIS_GENERIC;
return sis_generic_setup(pdev);
}
printk(KERN_ERR PFX "Unsupported SiS chipset (device id: %04x),"
" you might want to try agp_try_unsupported=1.\n", pdev->device);
return -ENODEV;
}
static int __init agp_find_supported_device(struct pci_dev *dev)
{
agp_bridge.dev = dev;
if (pci_find_capability(dev, PCI_CAP_ID_AGP)==0)
return -ENODEV;
/* probe for known chipsets */
return agp_lookup_host_bridge (dev);
}
static int agp_sis_probe (struct pci_dev *dev, const struct pci_device_id *ent)
{
if (agp_find_supported_device(dev) == 0) {
agp_register_driver(dev);
return 0;
}
return -ENODEV;
}
static struct pci_device_id agp_sis_pci_table[] __initdata = {
{
.class = (PCI_CLASS_BRIDGE_HOST << 8),
.class_mask = ~0,
.vendor = PCI_VENDOR_ID_SI,
.device = PCI_ANY_ID,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
{ }
};
MODULE_DEVICE_TABLE(pci, agp_sis_pci_table);
static struct pci_driver agp_sis_pci_driver = {
.name = "agpgart-sis",
.id_table = agp_sis_pci_table,
.probe = agp_sis_probe,
};
int __init agp_sis_init(void)
{
int ret_val;
ret_val = pci_module_init(&agp_sis_pci_driver);
if (ret_val)
agp_bridge.type = NOT_SUPPORTED;
return ret_val;
}
static void __exit agp_sis_cleanup(void)
{
agp_unregister_driver();
pci_unregister_driver(&agp_sis_pci_driver);
}
module_init(agp_sis_init);
module_exit(agp_sis_cleanup);
MODULE_PARM(agp_try_unsupported, "1i");
MODULE_LICENSE("GPL and additional rights");
struct agp_device_ids sis_agp_device_ids[] __initdata =
{
{
.device_id = PCI_DEVICE_ID_SI_740,
.chipset = SIS_GENERIC,
.chipset_name = "740",
},
{
.device_id = PCI_DEVICE_ID_SI_650,
.chipset = SIS_GENERIC,
.chipset_name = "650",
},
{
.device_id = PCI_DEVICE_ID_SI_651,
.chipset = SIS_GENERIC,
.chipset_name = "651",
},
{
.device_id = PCI_DEVICE_ID_SI_645,
.chipset = SIS_GENERIC,
.chipset_name = "645",
},
{
.device_id = PCI_DEVICE_ID_SI_735,
.chipset = SIS_GENERIC,
.chipset_name = "735",
},
{
.device_id = PCI_DEVICE_ID_SI_745,
.chipset = SIS_GENERIC,
.chipset_name = "745",
},
{
.device_id = PCI_DEVICE_ID_SI_730,
.chipset = SIS_GENERIC,
.chipset_name = "730",
},
{
.device_id = PCI_DEVICE_ID_SI_630,
.chipset = SIS_GENERIC,
.chipset_name = "630",
},
{
.device_id = PCI_DEVICE_ID_SI_540,
.chipset = SIS_GENERIC,
.chipset_name = "540",
},
{
.device_id = PCI_DEVICE_ID_SI_620,
.chipset = SIS_GENERIC,
.chipset_name = "620",
},
{
.device_id = PCI_DEVICE_ID_SI_530,
.chipset = SIS_GENERIC,
.chipset_name = "530",
},
{
.device_id = PCI_DEVICE_ID_SI_550,
.chipset = SIS_GENERIC,
.chipset_name = "550",
},
{
.device_id = 0,
.chipset = SIS_GENERIC,
.chipset_name = "Generic",
},
{ }, /* dummy final entry, always present */
};
struct agp_bridge_info sis_agp_bridge_info __initdata =
{
.vendor_id = PCI_VENDOR_ID_SI,
.vendor_name = "SiS",
.chipset_setup = sis_generic_setup,
.ids = sis_agp_device_ids,
};
/* /*
* AGPGART module version 0.99 * Serverworks AGPGART routines.
* Copyright (C) 1999 Jeff Hartmann
* Copyright (C) 1999 Precision Insight, Inc.
* Copyright (C) 1999 Xi Graphics, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* TODO:
* - Allocate more than order 0 pages to avoid too much linear map splitting.
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -32,6 +8,8 @@ ...@@ -32,6 +8,8 @@
#include <linux/agp_backend.h> #include <linux/agp_backend.h>
#include "agp.h" #include "agp.h"
static int agp_try_unsupported __initdata = 0;
struct serverworks_page_map { struct serverworks_page_map {
unsigned long *real; unsigned long *real;
unsigned long *remapped; unsigned long *remapped;
...@@ -624,3 +602,91 @@ int __init serverworks_setup (struct pci_dev *pdev) ...@@ -624,3 +602,91 @@ int __init serverworks_setup (struct pci_dev *pdev)
return 0; return 0;
} }
static int __init agp_find_supported_device(struct pci_dev *dev)
{
struct pci_dev *bridge_dev;
agp_bridge.dev = dev;
/* Everything is on func 1 here so we are hardcoding function one */
bridge_dev = pci_find_slot ((unsigned int)dev->bus->number, PCI_DEVFN(0, 1));
if(bridge_dev == NULL) {
printk(KERN_INFO PFX "agpgart: Detected a Serverworks "
"Chipset, but could not find the secondary "
"device.\n");
return -ENODEV;
}
switch (dev->device) {
case PCI_DEVICE_ID_SERVERWORKS_HE:
agp_bridge.type = SVWRKS_HE;
return serverworks_setup(bridge_dev);
case PCI_DEVICE_ID_SERVERWORKS_LE:
case 0x0007:
agp_bridge.type = SVWRKS_LE;
return serverworks_setup(bridge_dev);
default:
if(agp_try_unsupported) {
agp_bridge.type = SVWRKS_GENERIC;
return serverworks_setup(bridge_dev);
}
break;
}
return -ENODEV;
}
static int agp_serverworks_probe (struct pci_dev *dev, const struct pci_device_id *ent)
{
if (agp_find_supported_device(dev) == 0) {
agp_register_driver(dev);
return 0;
}
return -ENODEV;
}
static struct pci_device_id agp_serverworks_pci_table[] __initdata = {
{
.class = (PCI_CLASS_BRIDGE_HOST << 8),
.class_mask = ~0,
.vendor = PCI_VENDOR_ID_SERVERWORKS,
.device = PCI_ANY_ID,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
{ }
};
MODULE_DEVICE_TABLE(pci, agp_serverworks_pci_table);
static struct pci_driver agp_serverworks_pci_driver = {
.name = "agpgart-serverworks",
.id_table = agp_serverworks_pci_table,
.probe = agp_serverworks_probe,
};
static int __init agp_serverworks_init(void)
{
int ret_val;
ret_val = pci_module_init(&agp_serverworks_pci_driver);
if (ret_val)
agp_bridge.type = NOT_SUPPORTED;
return ret_val;
}
static void __exit agp_serverworks_cleanup(void)
{
agp_unregister_driver();
pci_unregister_driver(&agp_serverworks_pci_driver);
}
module_init(agp_serverworks_init);
module_exit(agp_serverworks_cleanup);
MODULE_PARM(agp_try_unsupported, "1i");
MODULE_LICENSE("GPL and additional rights");
/* /*
* AGPGART module version 0.99 * VIA AGPGART routines.
* Copyright (C) 1999 Jeff Hartmann
* Copyright (C) 1999 Precision Insight, Inc.
* Copyright (C) 1999 Xi Graphics, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* JEFF HARTMANN, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* TODO:
* - Allocate more than order 0 pages to avoid too much linear map splitting.
*/ */
#include <linux/config.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/kernel.h> #include <linux/module.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/agp_backend.h> #include <linux/agp_backend.h>
#include "agp.h" #include "agp.h"
#include "via.h"
static int agp_try_unsupported __initdata = 0;
static int via_fetch_size(void) static int via_fetch_size(void)
{ {
...@@ -145,8 +121,159 @@ int __init via_generic_setup (struct pci_dev *pdev) ...@@ -145,8 +121,159 @@ int __init via_generic_setup (struct pci_dev *pdev)
agp_bridge.suspend = agp_generic_suspend; agp_bridge.suspend = agp_generic_suspend;
agp_bridge.resume = agp_generic_resume; agp_bridge.resume = agp_generic_resume;
agp_bridge.cant_use_aperture = 0; agp_bridge.cant_use_aperture = 0;
return 0; return 0;
}
struct agp_device_ids via_agp_device_ids[] __initdata =
{
{
.device_id = PCI_DEVICE_ID_VIA_8501_0,
.chipset = VIA_MVP4,
.chipset_name = "MVP4",
},
{
.device_id = PCI_DEVICE_ID_VIA_82C597_0,
.chipset = VIA_VP3,
.chipset_name = "VP3",
},
{
.device_id = PCI_DEVICE_ID_VIA_82C598_0,
.chipset = VIA_MVP3,
.chipset_name = "MVP3",
},
{
.device_id = PCI_DEVICE_ID_VIA_82C691,
.chipset = VIA_APOLLO_PRO,
.chipset_name = "Apollo Pro",
},
{
.device_id = PCI_DEVICE_ID_VIA_8371_0,
.chipset = VIA_APOLLO_KX133,
.chipset_name = "Apollo Pro KX133",
},
{
.device_id = PCI_DEVICE_ID_VIA_8633_0,
.chipset = VIA_APOLLO_PRO_266,
.chipset_name = "Apollo Pro 266",
},
{
.device_id = PCI_DEVICE_ID_VIA_8363_0,
.chipset = VIA_APOLLO_KT133,
.chipset_name = "Apollo Pro KT133",
},
{
.device_id = PCI_DEVICE_ID_VIA_8367_0,
.chipset = VIA_APOLLO_KT133,
.chipset_name = "Apollo Pro KT266",
},
{
.device_id = PCI_DEVICE_ID_VIA_8377_0,
.chipset = VIA_APOLLO_KT400,
.chipset_name = "Apollo Pro KT400",
},
{
.device_id = PCI_DEVICE_ID_VIA_8653_0,
.chipset = VIA_APOLLO_PRO,
.chipset_name = "Apollo Pro266T",
},
{
.device_id = PCI_DEVICE_ID_VIA_82C694X_0,
.chipset = VIA_VT8605,
.chipset_name = "PM133"
},
{ }, /* dummy final entry, always present */
};
/* scan table above for supported devices */
static int __init agp_lookup_host_bridge (struct pci_dev *pdev)
{
int j=0;
struct agp_device_ids *devs;
(void) pdev; /* unused */ devs = via_agp_device_ids;
while (devs[j].chipset_name != NULL) {
if (pdev->device == devs[j].device_id) {
printk (KERN_INFO PFX "Detected VIA %s chipset\n", devs[j].chipset_name);
agp_bridge.type = devs[j].chipset;
if (devs[j].chipset_setup != NULL)
return devs[j].chipset_setup(pdev);
else
return via_generic_setup(pdev);
}
j++;
}
/* try init anyway, if user requests it */
if (agp_try_unsupported) {
printk(KERN_WARNING PFX "Trying generic VIA routines"
" for device id: %04x\n", pdev->device);
agp_bridge.type = VIA_GENERIC;
return via_generic_setup(pdev);
}
printk(KERN_ERR PFX "Unsupported VIA chipset (device id: %04x),"
" you might want to try agp_try_unsupported=1.\n", pdev->device);
return -ENODEV;
}
static int agp_via_probe (struct pci_dev *dev, const struct pci_device_id *ent)
{
if (pci_find_capability(dev, PCI_CAP_ID_AGP)==0)
return -ENODEV;
agp_bridge.dev = dev;
/* probe for known chipsets */
if (agp_lookup_host_bridge (dev) != -ENODEV) {
agp_register_driver(dev);
return 0;
}
return -ENODEV;
} }
static struct pci_device_id agp_via_pci_table[] __initdata = {
{
.class = (PCI_CLASS_BRIDGE_HOST << 8),
.class_mask = ~0,
.vendor = PCI_VENDOR_ID_VIA,
.device = PCI_ANY_ID,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
{ }
};
MODULE_DEVICE_TABLE(pci, agp_via_pci_table);
static struct pci_driver agp_via_pci_driver = {
.name = "agpgart-via",
.id_table = agp_via_pci_table,
.probe = agp_via_probe,
};
static int __init agp_via_init(void)
{
int ret_val;
ret_val = pci_module_init(&agp_via_pci_driver);
if (ret_val)
agp_bridge.type = NOT_SUPPORTED;
return ret_val;
}
static void __exit agp_via_cleanup(void)
{
agp_unregister_driver();
pci_unregister_driver(&agp_via_pci_driver);
}
module_init(agp_via_init);
module_exit(agp_via_cleanup);
MODULE_PARM(agp_try_unsupported, "1i");
MODULE_LICENSE("GPL and additional rights");
struct agp_device_ids via_agp_device_ids[] __initdata =
{
{
.device_id = PCI_DEVICE_ID_VIA_8501_0,
.chipset = VIA_MVP4,
.chipset_name = "MVP4",
},
{
.device_id = PCI_DEVICE_ID_VIA_82C597_0,
.chipset = VIA_VP3,
.chipset_name = "VP3",
},
{
.device_id = PCI_DEVICE_ID_VIA_82C598_0,
.chipset = VIA_MVP3,
.chipset_name = "MVP3",
},
{
.device_id = PCI_DEVICE_ID_VIA_82C691,
.chipset = VIA_APOLLO_PRO,
.chipset_name = "Apollo Pro",
},
{
.device_id = PCI_DEVICE_ID_VIA_8371_0,
.chipset = VIA_APOLLO_KX133,
.chipset_name = "Apollo Pro KX133",
},
{
.device_id = PCI_DEVICE_ID_VIA_8633_0,
.chipset = VIA_APOLLO_PRO_266,
.chipset_name = "Apollo Pro 266",
},
{
.device_id = PCI_DEVICE_ID_VIA_8363_0,
.chipset = VIA_APOLLO_KT133,
.chipset_name = "Apollo Pro KT133",
},
{
.device_id = PCI_DEVICE_ID_VIA_8367_0,
.chipset = VIA_APOLLO_KT133,
.chipset_name = "Apollo Pro KT266",
},
{
.device_id = PCI_DEVICE_ID_VIA_8377_0,
.chipset = VIA_APOLLO_KT400,
.chipset_name = "Apollo Pro KT400",
},
{
.device_id = PCI_DEVICE_ID_VIA_8653_0,
.chipset = VIA_APOLLO_PRO,
.chipset_name = "Apollo Pro266T",
},
{
.device_id = PCI_DEVICE_ID_VIA_82C694X_0,
.chipset = VIA_VT8605,
.chipset_name = "PM133"
},
{
.device_id = 0,
.chipset = VIA_GENERIC,
.chipset_name = "Generic",
},
{ }, /* dummy final entry, always present */
};
struct agp_bridge_info via_agp_bridge_info __initdata =
{
.vendor_id = PCI_VENDOR_ID_VIA,
.vendor_name = "Via",
.chipset_setup = via_generic_setup,
.ids = via_agp_device_ids,
};
...@@ -35,9 +35,6 @@ ...@@ -35,9 +35,6 @@
#define FALSE 0 #define FALSE 0
#endif #endif
#define AGPGART_VERSION_MAJOR 0
#define AGPGART_VERSION_MINOR 99
enum chipset_type { enum chipset_type {
NOT_SUPPORTED, NOT_SUPPORTED,
INTEL_GENERIC, INTEL_GENERIC,
......
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