Commit 40f911f6 authored by Linus Torvalds's avatar Linus Torvalds Committed by Linus Torvalds

Merge bk://linux-dj.bkbits.net/agpgart

into home.transmeta.com:/home/torvalds/v2.5/linux
parents f5ab74e6 5e27cb68
agpgart-y := backend.o frontend.o generic.o generic-3.0.o
agpgart-y := backend.o frontend.o generic.o isoch.o
obj-$(CONFIG_AGP) += agpgart.o
obj-$(CONFIG_AGP_ALI) += ali-agp.o
......
......@@ -139,6 +139,8 @@ struct agp_bridge_data {
int max_memory_agp; /* in number of pages */
int aperture_size_idx;
int capndx;
char major_version;
char minor_version;
};
#define OUTREG64(mmap, addr, val) __raw_writeq((val), (mmap)+(addr))
......@@ -388,27 +390,38 @@ void agp_free_key(int key);
int agp_num_entries(void);
u32 agp_collect_device_status(u32 mode, u32 command);
void agp_device_command(u32 command, int agp_v3);
int agp_3_0_node_enable(struct agp_bridge_data *bridge, u32 mode, u32 minor);
int agp_3_0_enable(struct agp_bridge_data *bridge, u32 mode);
int agp_3_5_enable(struct agp_bridge_data *bridge, u32 mode);
void global_cache_flush(void);
void get_agp_version(struct agp_bridge_data *bridge);
/* Standard agp registers */
#define AGPSTAT 0x4
#define AGPCMD 0x8
#define AGPNISTAT 0xc
#define AGPNEPG 0x16
#define AGPNICMD 0x20
#define AGP_MAJOR_VERSION_SHIFT (20)
#define AGP_MINOR_VERSION_SHIFT (16)
#define AGPSTAT_RQ_DEPTH (0xff000000)
#define AGPSTAT_CAL_MASK (1<<12|1<<11|1<<10)
#define AGPSTAT_ARQSZ (1<<15|1<<14|1<<13)
#define AGPSTAT_ARQSZ_SHIFT 13
#define AGPSTAT_AGP_ENABLE (1<<8)
#define AGPSTAT_SBA (1<<9)
#define AGPSTAT_AGP_ENABLE (1<<8)
#define AGPSTAT_FW (1<<4)
#define AGPSTAT_MODE_3_0 (1<<3)
#define AGPSTAT2_1X (1<<0)
#define AGPSTAT2_2X (1<<1)
#define AGPSTAT2_4X (1<<2)
#define AGPSTAT_FW (1<<4)
#define AGPSTAT3_RSVD (1<<2)
#define AGPSTAT3_8X (1<<1)
#define AGPSTAT3_4X (1)
#endif /* _AGP_BACKEND_PRIV_H */
......@@ -253,8 +253,10 @@ static int __init agp_amdk8_probe(struct pci_dev *pdev,
{
struct agp_bridge_data *bridge;
struct pci_dev *loop_dev;
u8 rev_id;
u8 cap_ptr;
int i = 0;
char *revstring=" ";
cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
if (!cap_ptr)
......@@ -266,14 +268,38 @@ static int __init agp_amdk8_probe(struct pci_dev *pdev,
if (!bridge)
return -ENOMEM;
/* Assume here we have an 8151. (Later this assumption will be fixed). */
pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
switch (rev_id) {
case 0x01: revstring="A0";
break;
case 0x02: revstring="A1";
break;
case 0x11: revstring="B0";
break;
case 0x12: revstring="B1";
break;
case 0x13: revstring="B2";
break;
default: revstring="??";
break;
}
printk ("Detected AMD 8151 AGP Bridge rev %s", revstring);
/*
* Work around errata.
* Chips before B2 stepping incorrectly reporting v3.5
*/
if (rev_id < 0x13) {
bridge->major_version = 3;
bridge->minor_version = 0;
}
bridge->driver = &amd_8151_driver;
bridge->dev = pdev;
bridge->capndx = cap_ptr;
/* Fill in the mode register */
pci_read_config_dword(pdev,
bridge->capndx+PCI_AGP_STATUS,
&bridge->mode);
pci_read_config_dword(pdev, bridge->capndx+PCI_AGP_STATUS, &bridge->mode);
/* cache pci_devs of northbridges. */
pci_for_each_dev(loop_dev) {
......@@ -290,7 +316,7 @@ static int __init agp_amdk8_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, bridge);
return agp_add_bridge(bridge);
out_free:
out_free:
agp_put_bridge(bridge);
return -ENOMEM;
}
......
......@@ -270,14 +270,16 @@ EXPORT_SYMBOL_GPL(agp_num_entries);
int agp_copy_info(agp_kern_info * info)
{
memset(info, 0, sizeof(agp_kern_info));
if (agp_bridge->type == NOT_SUPPORTED) {
info->chipset = agp_bridge->type;
if (!agp_bridge || agp_bridge->type == NOT_SUPPORTED ||
!agp_bridge->version) {
info->chipset = NOT_SUPPORTED;
return -EIO;
}
info->version.major = agp_bridge->version->major;
info->version.minor = agp_bridge->version->minor;
info->device = agp_bridge->dev;
info->chipset = agp_bridge->type;
info->device = agp_bridge->dev;
info->mode = agp_bridge->mode;
info->aper_base = agp_bridge->gart_bus_addr;
info->aper_size = agp_return_size();
......@@ -366,60 +368,106 @@ EXPORT_SYMBOL(agp_unbind_memory);
/* Generic Agp routines - Start */
static void agp_v2_parse_one(u32 *mode, u32 *cmd, u32 *tmp)
{
/* disable SBA if it's not supported */
if (!((*cmd & AGPSTAT_SBA) && (*tmp & AGPSTAT_SBA) && (*mode & AGPSTAT_SBA)))
*cmd &= ~AGPSTAT_SBA;
/* disable FW if it's not supported */
if (!((*cmd & AGPSTAT_FW) && (*tmp & AGPSTAT_FW) && (*mode & AGPSTAT_FW)))
*cmd &= ~AGPSTAT_FW;
/* Set speed */
if (!((*cmd & AGPSTAT2_4X) && (*tmp & AGPSTAT2_4X) && (*mode & AGPSTAT2_4X)))
*cmd &= ~AGPSTAT2_4X;
if (!((*cmd & AGPSTAT2_2X) && (*tmp & AGPSTAT2_2X) && (*mode & AGPSTAT2_2X)))
*cmd &= ~AGPSTAT2_2X;
if (!((*cmd & AGPSTAT2_1X) && (*tmp & AGPSTAT2_1X) && (*mode & AGPSTAT2_1X)))
*cmd &= ~AGPSTAT2_1X;
/* Now we know what mode it should be, clear out the unwanted bits. */
if (*cmd & AGPSTAT2_4X)
*cmd &= ~(AGPSTAT2_1X | AGPSTAT2_2X); /* 4X */
if (*cmd & AGPSTAT2_2X)
*cmd &= ~(AGPSTAT2_1X | AGPSTAT2_4X); /* 2X */
if (*cmd & AGPSTAT2_1X)
*cmd &= ~(AGPSTAT2_2X | AGPSTAT2_4X); /* 1Xf */
}
u32 agp_collect_device_status(u32 mode, u32 command)
static void agp_v3_parse_one(u32 *mode, u32 *cmd, u32 *tmp)
{
/* ARQSZ - Set the value to the maximum one.
* Don't allow the mode register to override values. */
*cmd = ((*cmd & ~AGPSTAT_ARQSZ) |
max_t(u32,(*cmd & AGPSTAT_ARQSZ),(*tmp & AGPSTAT_ARQSZ)));
/* Calibration cycle.
* Don't allow the mode register to override values. */
*cmd = ((*cmd & ~AGPSTAT_CAL_MASK) |
min_t(u32,(*cmd & AGPSTAT_CAL_MASK),(*tmp & AGPSTAT_CAL_MASK)));
/* SBA *must* be supported for AGP v3 */
*cmd |= AGPSTAT_SBA;
/* disable FW if it's not supported */
if (!((*cmd & AGPSTAT_FW) && (*tmp & AGPSTAT_FW) && (*mode & AGPSTAT_FW)))
*cmd &= ~AGPSTAT_FW;
/* Set speed. */
if (!((*cmd & AGPSTAT3_8X) && (*tmp & AGPSTAT3_8X) && (*mode & AGPSTAT3_8X)))
*cmd &= ~AGPSTAT3_8X;
if (!((*cmd & AGPSTAT3_4X) && (*tmp & AGPSTAT3_4X) && (*mode & AGPSTAT3_4X)))
*cmd &= ~AGPSTAT3_4X;
/* Clear out unwanted bits. */
if (*cmd & AGPSTAT3_8X)
*cmd *= ~(AGPSTAT3_4X | AGPSTAT3_RSVD);
if (*cmd & AGPSTAT3_4X)
*cmd *= ~(AGPSTAT3_8X | AGPSTAT3_RSVD);
}
//FIXME: This doesn't smell right.
//We need a function we pass an agp_device to.
u32 agp_collect_device_status(u32 mode, u32 cmd)
{
struct pci_dev *device;
u8 agp;
u32 scratch;
u8 cap_ptr;
u32 tmp;
u32 agp3;
pci_for_each_dev(device) {
agp = pci_find_capability(device, PCI_CAP_ID_AGP);
if (!agp)
cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
if (!cap_ptr)
continue;
/*
* Ok, here we have a AGP device. Disable impossible
* settings, and adjust the readqueue to the minimum.
*/
pci_read_config_dword(device, agp + PCI_AGP_STATUS, &scratch);
pci_read_config_dword(device, cap_ptr+PCI_AGP_STATUS, &tmp);
/* adjust RQ depth */
command = ((command & ~AGPSTAT_RQ_DEPTH) |
cmd = ((cmd & ~AGPSTAT_RQ_DEPTH) |
min_t(u32, (mode & AGPSTAT_RQ_DEPTH),
min_t(u32, (command & AGPSTAT_RQ_DEPTH),
(scratch & AGPSTAT_RQ_DEPTH))));
/* disable SBA if it's not supported */
if (!((command & AGPSTAT_SBA) && (scratch & AGPSTAT_SBA) && (mode & AGPSTAT_SBA)))
command &= ~AGPSTAT_SBA;
/* disable FW if it's not supported */
if (!((command & AGPSTAT_FW) && (scratch & AGPSTAT_FW) && (mode & AGPSTAT_FW)))
command &= ~AGPSTAT_FW;
/* Set speed */
if (!((command & AGPSTAT2_4X) && (scratch & AGPSTAT2_4X) && (mode & AGPSTAT2_4X)))
command &= ~AGPSTAT2_4X;
min_t(u32, (cmd & AGPSTAT_RQ_DEPTH), (tmp & AGPSTAT_RQ_DEPTH))));
if (!((command & AGPSTAT2_2X) && (scratch & AGPSTAT2_2X) && (mode & AGPSTAT2_2X)))
command &= ~AGPSTAT2_2X;
pci_read_config_dword(device, cap_ptr+AGPSTAT, &agp3);
if (!((command & AGPSTAT2_1X) && (scratch & AGPSTAT2_1X) && (mode & AGPSTAT2_1X)))
command &= ~AGPSTAT2_1X;
/* Check to see if we are operating in 3.0 mode */
if (agp3 & AGPSTAT_MODE_3_0) {
agp_v3_parse_one(&mode, &cmd, &tmp);
} else {
agp_v2_parse_one(&mode, &cmd, &tmp);
}
/* Now we know what mode it should be, clear out the unwanted bits. */
if (command & AGPSTAT2_4X)
command &= ~(AGPSTAT2_1X | AGPSTAT2_2X); /* 4X */
if (command & AGPSTAT2_2X)
command &= ~(AGPSTAT2_1X | AGPSTAT2_4X); /* 2X */
if (command & AGPSTAT2_1X)
command &= ~(AGPSTAT2_2X | AGPSTAT2_4X); /* 1Xf */
return command;
}
return cmd;
}
EXPORT_SYMBOL(agp_collect_device_status);
......@@ -446,29 +494,33 @@ void agp_device_command(u32 command, int agp_v3)
EXPORT_SYMBOL(agp_device_command);
void agp_generic_enable(u32 mode)
void get_agp_version(struct agp_bridge_data *bridge)
{
u32 command, ncapid, major, minor;
u32 ncapid;
/* Exit early if already set by errata workarounds. */
if (agp_bridge->major_version != 0)
return;
pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx, &ncapid);
major = (ncapid >> 20) & 0xf;
minor = (ncapid >> 16) & 0xf;
printk(KERN_INFO PFX "Found an AGP %d.%d compliant device.\n",major, minor);
agp_bridge->major_version = (ncapid >> AGP_MAJOR_VERSION_SHIFT) & 0xf;
agp_bridge->minor_version = (ncapid >> AGP_MINOR_VERSION_SHIFT) & 0xf;
}
EXPORT_SYMBOL(get_agp_version);
if(major >= 3) {
u32 agp_3_0;
pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx + 0x4, &agp_3_0);
/* Check to see if we are operating in 3.0 mode */
if((agp_3_0 >> 3) & 0x1) {
agp_3_0_node_enable(agp_bridge, mode, minor);
return;
} else {
printk (KERN_INFO PFX "not in AGP 3.0 mode, falling back to 2.x\n");
}
}
void agp_generic_enable(u32 mode)
{
u32 command;
u32 agp3;
get_agp_version(agp_bridge);
printk(KERN_INFO PFX "Found an AGP %d.%d compliant device at %s.\n",
agp_bridge->major_version,
agp_bridge->minor_version,
agp_bridge->dev->slot_name);
/* AGP v<3 */
pci_read_config_dword(agp_bridge->dev,
agp_bridge->capndx + PCI_AGP_STATUS, &command);
......@@ -477,7 +529,27 @@ void agp_generic_enable(u32 mode)
pci_write_config_dword(agp_bridge->dev,
agp_bridge->capndx + PCI_AGP_COMMAND, command);
agp_device_command(command, 0);
/* Do AGP version specific frobbing. */
if(agp_bridge->major_version >= 3) {
pci_read_config_dword(agp_bridge->dev,
agp_bridge->capndx+AGPSTAT, &agp3);
/* Check to see if we are operating in 3.0 mode */
if (agp3 & AGPSTAT_MODE_3_0) {
/* If we have 3.5, we can do the isoch stuff. */
if (agp_bridge->minor_version >= 5)
agp_3_5_enable(agp_bridge, mode);
agp_device_command(command, TRUE);
return;
} else {
printk (KERN_INFO PFX "Device is in legacy mode,"
" falling back to 2.x\n");
}
}
/* AGP v<3 */
agp_device_command(command, FALSE);
}
EXPORT_SYMBOL(agp_generic_enable);
......@@ -831,6 +903,7 @@ void agp_enable(u32 mode)
}
EXPORT_SYMBOL(agp_enable);
#ifdef CONFIG_SMP
static void ipi_handler(void *null)
{
......
/*
* Generic routines for AGP 3.0 compliant bridges.
* Setup routines for AGP 3.5 compliant bridges.
*/
#include <linux/list.h>
......@@ -9,47 +9,47 @@
#include "agp.h"
/* Generic AGP 3.0 enabling routines */
/* Generic AGP 3.5 enabling routines */
struct agp_3_0_dev {
struct agp_3_5_dev {
struct list_head list;
u8 capndx;
u32 maxbw;
struct pci_dev *dev;
};
static void agp_3_0_dev_list_insert(struct list_head *head, struct list_head *new)
static void agp_3_5_dev_list_insert(struct list_head *head, struct list_head *new)
{
struct agp_3_0_dev *cur, *n = list_entry(new, struct agp_3_0_dev, list);
struct agp_3_5_dev *cur, *n = list_entry(new, struct agp_3_5_dev, list);
struct list_head *pos;
list_for_each(pos, head) {
cur = list_entry(pos, struct agp_3_0_dev, list);
cur = list_entry(pos, struct agp_3_5_dev, list);
if(cur->maxbw > n->maxbw)
break;
}
list_add_tail(new, pos);
}
static void agp_3_0_dev_list_sort(struct agp_3_0_dev *list, unsigned int ndevs)
static void agp_3_5_dev_list_sort(struct agp_3_5_dev *list, unsigned int ndevs)
{
struct agp_3_0_dev *cur;
struct agp_3_5_dev *cur;
struct pci_dev *dev;
struct list_head *pos, *tmp, *head = &list->list, *start = head->next;
u32 nistat;
INIT_LIST_HEAD(head);
for(pos = start; pos != head;) {
cur = list_entry(pos, struct agp_3_0_dev, list);
for (pos=start; pos!=head; ) {
cur = list_entry(pos, struct agp_3_5_dev, list);
dev = cur->dev;
pci_read_config_dword(dev, cur->capndx + 0x0c, &nistat);
pci_read_config_dword(dev, cur->capndx+AGPNISTAT, &nistat);
cur->maxbw = (nistat >> 16) & 0xff;
tmp = pos;
pos = pos->next;
agp_3_0_dev_list_insert(head, tmp);
agp_3_5_dev_list_insert(head, tmp);
}
}
......@@ -59,8 +59,8 @@ static void agp_3_0_dev_list_sort(struct agp_3_0_dev *list, unsigned int ndevs)
* lying behind it...)
*/
static int agp_3_0_isochronous_node_enable(struct agp_bridge_data *bridge,
struct agp_3_0_dev *dev_list, unsigned int ndevs)
static int agp_3_5_isochronous_node_enable(struct agp_bridge_data *bridge,
struct agp_3_5_dev *dev_list, unsigned int ndevs)
{
/*
* Convenience structure to make the calculations clearer
......@@ -72,12 +72,12 @@ static int agp_3_0_isochronous_node_enable(struct agp_bridge_data *bridge,
u32 y;
u32 l;
u32 rq;
struct agp_3_0_dev *dev;
struct agp_3_5_dev *dev;
};
struct pci_dev *td = bridge->dev, *dev;
struct list_head *head = &dev_list->list, *pos;
struct agp_3_0_dev *cur;
struct agp_3_5_dev *cur;
struct isoch_data *master, target;
unsigned int cdev = 0;
u32 mnistat, tnistat, tstatus, mcmd;
......@@ -91,7 +91,7 @@ static int agp_3_0_isochronous_node_enable(struct agp_bridge_data *bridge,
* We'll work with an array of isoch_data's (one for each
* device in dev_list) throughout this function.
*/
if((master = kmalloc(ndevs * sizeof(*master), GFP_KERNEL)) == NULL) {
if ((master = kmalloc(ndevs * sizeof(*master), GFP_KERNEL)) == NULL) {
ret = -ENOMEM;
goto get_out;
}
......@@ -112,9 +112,9 @@ static int agp_3_0_isochronous_node_enable(struct agp_bridge_data *bridge,
* transfers are enabled and consequently whether maxbw will mean
* anything.
*/
agp_3_0_dev_list_sort(dev_list, ndevs);
agp_3_5_dev_list_sort(dev_list, ndevs);
pci_read_config_dword(td, bridge->capndx + 0x0c, &tnistat);
pci_read_config_dword(td, bridge->capndx+AGPNISTAT, &tnistat);
pci_read_config_dword(td, bridge->capndx+AGPSTAT, &tstatus);
/* Extract power-on defaults from the target */
......@@ -132,12 +132,12 @@ static int agp_3_0_isochronous_node_enable(struct agp_bridge_data *bridge,
* by these devices and the largest requested payload size.
*/
list_for_each(pos, head) {
cur = list_entry(pos, struct agp_3_0_dev, list);
cur = list_entry(pos, struct agp_3_5_dev, list);
dev = cur->dev;
mcapndx = cur->capndx;
pci_read_config_dword(dev, cur->capndx + 0x0c, &mnistat);
pci_read_config_dword(dev, cur->capndx+AGPNISTAT, &mnistat);
master[cdev].maxbw = (mnistat >> 16) & 0xff;
master[cdev].n = (mnistat >> 8) & 0xff;
......@@ -151,7 +151,7 @@ static int agp_3_0_isochronous_node_enable(struct agp_bridge_data *bridge,
}
/* Check if this configuration has any chance of working */
if(tot_bw > target.maxbw) {
if (tot_bw > target.maxbw) {
printk(KERN_ERR PFX "isochronous bandwidth required "
"by AGP 3.0 devices exceeds that which is supported by "
"the AGP 3.0 bridge!\n");
......@@ -167,17 +167,17 @@ static int agp_3_0_isochronous_node_enable(struct agp_bridge_data *bridge,
* in the target's NISTAT register, so we need to do this now
* to get an accurate value for ISOCH_N later.
*/
pci_read_config_word(td, bridge->capndx + 0x20, &tnicmd);
pci_read_config_word(td, bridge->capndx+AGPNICMD, &tnicmd);
tnicmd &= ~(0x3 << 6);
tnicmd |= target.y << 6;
pci_write_config_word(td, bridge->capndx + 0x20, tnicmd);
pci_write_config_word(td, bridge->capndx+AGPNICMD, tnicmd);
/* Reread the target's ISOCH_N */
pci_read_config_dword(td, bridge->capndx + 0x0c, &tnistat);
pci_read_config_dword(td, bridge->capndx+AGPNISTAT, &tnistat);
target.n = (tnistat >> 8) & 0xff;
/* Calculate the minimum ISOCH_N needed by each master */
for(cdev = 0; cdev < ndevs; cdev++) {
for (cdev=0; cdev<ndevs; cdev++) {
master[cdev].y = target.y;
master[cdev].n = master[cdev].maxbw / (master[cdev].y + 1);
......@@ -186,7 +186,7 @@ static int agp_3_0_isochronous_node_enable(struct agp_bridge_data *bridge,
/* Exit if the minimal ISOCH_N allocation among the masters is more
* than the target can handle. */
if(tot_n > target.n) {
if (tot_n > target.n) {
printk(KERN_ERR PFX "number of isochronous "
"transactions per period required by AGP 3.0 devices "
"exceeds that which is supported by the AGP 3.0 "
......@@ -204,7 +204,7 @@ static int agp_3_0_isochronous_node_enable(struct agp_bridge_data *bridge,
* Along the way, distribute the extra ISOCH_N capability calculated
* above.
*/
for(cdev = 0; cdev < ndevs; cdev++) {
for (cdev=0; cdev<ndevs; cdev++) {
/*
* This is a little subtle. If ISOCH_Y > 64B, then ISOCH_Y
* byte isochronous writes will be broken into 64B pieces.
......@@ -213,13 +213,12 @@ static int agp_3_0_isochronous_node_enable(struct agp_bridge_data *bridge,
* many writes on the AGP bus).
*/
master[cdev].rq = master[cdev].n;
if(master[cdev].y > 0x1) {
if(master[cdev].y > 0x1)
master[cdev].rq *= (1 << (master[cdev].y - 1));
}
tot_rq += master[cdev].rq;
if(cdev == ndevs - 1)
if (cdev == ndevs-1)
master[cdev].n += rem;
}
......@@ -230,7 +229,7 @@ static int agp_3_0_isochronous_node_enable(struct agp_bridge_data *bridge,
/* Exit if the minimal RQ needs of the masters exceeds what the target
* can provide. */
if(tot_rq > rq_isoch) {
if (tot_rq > rq_isoch) {
printk(KERN_ERR PFX "number of request queue slots "
"required by the isochronous bandwidth requested by "
"AGP 3.0 devices exceeds the number provided by the "
......@@ -247,7 +246,7 @@ static int agp_3_0_isochronous_node_enable(struct agp_bridge_data *bridge,
/* Distribute the extra RQ slots calculated above and write our
* isochronous settings out to the actual devices. */
for(cdev = 0; cdev < ndevs; cdev++) {
for (cdev=0; cdev<ndevs; cdev++) {
cur = master[cdev].dev;
dev = cur->dev;
......@@ -256,7 +255,7 @@ static int agp_3_0_isochronous_node_enable(struct agp_bridge_data *bridge,
master[cdev].rq += (cdev == ndevs - 1)
? (rem_async + rem_isoch) : step;
pci_read_config_word(dev, cur->capndx + 0x20, &mnicmd);
pci_read_config_word(dev, cur->capndx+AGPNICMD, &mnicmd);
pci_read_config_dword(dev, cur->capndx+AGPCMD, &mcmd);
mnicmd &= ~(0xff << 8);
......@@ -268,7 +267,7 @@ static int agp_3_0_isochronous_node_enable(struct agp_bridge_data *bridge,
mcmd |= master[cdev].rq << 24;
pci_write_config_dword(dev, cur->capndx+AGPCMD, mcmd);
pci_write_config_word(dev, cur->capndx + 0x20, mnicmd);
pci_write_config_word(dev, cur->capndx+AGPNICMD, mnicmd);
}
free_and_exit:
......@@ -285,24 +284,24 @@ static int agp_3_0_isochronous_node_enable(struct agp_bridge_data *bridge,
* target by ndevs. Distribute this many slots to each AGP 3.0 device,
* giving any left over slots to the last device in dev_list.
*/
static void agp_3_0_nonisochronous_node_enable(struct agp_bridge_data *bridge,
struct agp_3_0_dev *dev_list, unsigned int ndevs)
static void agp_3_5_nonisochronous_node_enable(struct agp_bridge_data *bridge,
struct agp_3_5_dev *dev_list, unsigned int ndevs)
{
struct agp_3_0_dev *cur;
struct agp_3_5_dev *cur;
struct list_head *head = &dev_list->list, *pos;
u32 tstatus, mcmd;
u32 trq, mrq, rem;
unsigned int cdev = 0;
pci_read_config_dword(bridge->dev, bridge->capndx + 0x04, &tstatus);
pci_read_config_dword(bridge->dev, bridge->capndx+AGPSTAT, &tstatus);
trq = (tstatus >> 24) & 0xff;
mrq = trq / ndevs;
rem = mrq + (trq % ndevs);
for(pos = head->next; cdev < ndevs; cdev++, pos = pos->next) {
cur = list_entry(pos, struct agp_3_0_dev, list);
for (pos=head->next; cdev<ndevs; cdev++, pos=pos->next) {
cur = list_entry(pos, struct agp_3_5_dev, list);
pci_read_config_dword(cur->dev, cur->capndx+AGPCMD, &mcmd);
mcmd &= ~(0xff << 24);
......@@ -315,24 +314,32 @@ static void agp_3_0_nonisochronous_node_enable(struct agp_bridge_data *bridge,
* Fully configure and enable an AGP 3.0 host bridge and all the devices
* lying behind it.
*/
int agp_3_0_node_enable(struct agp_bridge_data *bridge, u32 mode, u32 minor)
int agp_3_5_enable(struct agp_bridge_data *bridge, u32 mode)
{
struct pci_dev *td = bridge->dev, *dev;
u8 mcapndx;
u32 isoch, arqsz, cal_cycle, tmp, rate;
u32 tstatus, tcmd, mcmd, mstatus, ncapid;
u32 mmajor, mminor;
u32 isoch, arqsz;
u32 tstatus, mstatus, ncapid;
u32 mmajor;
u16 mpstat;
struct agp_3_0_dev *dev_list, *cur;
struct agp_3_5_dev *dev_list, *cur;
struct list_head *head, *pos;
unsigned int ndevs = 0;
int ret = 0;
/* Extract some power-on defaults from the target */
pci_read_config_dword(td, bridge->capndx+AGPSTAT, &tstatus);
isoch = (tstatus >> 17) & 0x1;
if (isoch == 0) /* isoch xfers not available, bail out. */
return -ENODEV;
arqsz = (tstatus >> 13) & 0x7;
/*
* Allocate a head for our AGP 3.0 device list (multiple AGP 3.0
* devices are allowed behind a single bridge).
* Allocate a head for our AGP 3.5 device list
* (multiple AGP v3 devices are allowed behind a single bridge).
*/
if((dev_list = kmalloc(sizeof(*dev_list), GFP_KERNEL)) == NULL) {
if ((dev_list = kmalloc(sizeof(*dev_list), GFP_KERNEL)) == NULL) {
ret = -ENOMEM;
goto get_out;
}
......@@ -342,6 +349,9 @@ int agp_3_0_node_enable(struct agp_bridge_data *bridge, u32 mode, u32 minor)
/* Find all AGP devices, and add them to dev_list. */
pci_for_each_dev(dev) {
mcapndx = pci_find_capability(dev, PCI_CAP_ID_AGP);
if (mcapndx == 0)
continue;
switch ((dev->class >>8) & 0xff00) {
case 0x0600: /* Bridge */
/* Skip bridges. We should call this function for each one. */
......@@ -357,9 +367,6 @@ int agp_3_0_node_enable(struct agp_bridge_data *bridge, u32 mode, u32 minor)
case 0x0300: /* Display controller */
case 0x0400: /* Multimedia controller */
if (mcapndx == 0)
continue;
if((cur = kmalloc(sizeof(*cur), GFP_KERNEL)) == NULL) {
ret = -ENOMEM;
goto free_and_exit;
......@@ -376,51 +383,41 @@ int agp_3_0_node_enable(struct agp_bridge_data *bridge, u32 mode, u32 minor)
}
}
/* Extract some power-on defaults from the target */
pci_read_config_dword(td, bridge->capndx + 0x04, &tstatus);
isoch = (tstatus >> 17) & 0x1;
arqsz = (tstatus >> 13) & 0x7;
cal_cycle = (tstatus >> 10) & 0x7;
rate = tstatus & 0x7;
/*
* Take an initial pass through the devices lying behind our host
* bridge. Make sure each one is actually an AGP 3.0 device, otherwise
* exit with an error message. Along the way store the AGP 3.0
* cap_ptr for each device, the minimum supported cal_cycle, and the
* minimum supported data rate.
* cap_ptr for each device
*/
list_for_each(pos, head) {
cur = list_entry(pos, struct agp_3_0_dev, list);
cur = list_entry(pos, struct agp_3_5_dev, list);
dev = cur->dev;
pci_read_config_word(dev, PCI_STATUS, &mpstat);
if((mpstat & PCI_STATUS_CAP_LIST) == 0)
if ((mpstat & PCI_STATUS_CAP_LIST) == 0)
continue;
pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &mcapndx);
if (mcapndx != 0x00) {
if (mcapndx != 0) {
do {
pci_read_config_dword(dev, mcapndx, &ncapid);
if ((ncapid & 0xff) != 0x02)
if ((ncapid & 0xff) != 2)
mcapndx = (ncapid >> 8) & 0xff;
}
while (((ncapid & 0xff) != 0x02) && (mcapndx != 0x00));
while (((ncapid & 0xff) != 2) && (mcapndx != 0));
}
if(mcapndx == 0) {
if (mcapndx == 0) {
printk(KERN_ERR PFX "woah! Non-AGP device "
"found on the secondary bus of an AGP 3.0 bridge!\n");
"found on the secondary bus of an AGP 3.5 bridge!\n");
ret = -ENODEV;
goto free_and_exit;
}
mmajor = (ncapid >> AGP_MAJOR_VERSION_SHIFT) & 0xf;
mminor = (ncapid >> AGP_MINOR_VERSION_SHIFT) & 0xf;
if(mmajor < 3) {
if (mmajor < 3) {
printk(KERN_ERR PFX "woah! AGP 2.0 device "
"found on the secondary bus of an AGP 3.0 "
"found on the secondary bus of an AGP 3.5 "
"bridge operating with AGP 3.0 electricals!\n");
ret = -ENODEV;
goto free_and_exit;
......@@ -428,40 +425,16 @@ int agp_3_0_node_enable(struct agp_bridge_data *bridge, u32 mode, u32 minor)
cur->capndx = mcapndx;
pci_read_config_dword(dev, cur->capndx + 0x04, &mstatus);
pci_read_config_dword(dev, cur->capndx+AGPSTAT, &mstatus);
if(((mstatus >> 3) & 0x1) == 0) {
printk(KERN_ERR PFX "woah! AGP 3.0 device "
"not operating in AGP 3.0 mode found on the "
"secondary bus of an AGP 3.0 bridge operating "
if (((mstatus >> 3) & 0x1) == 0) {
printk(KERN_ERR PFX "woah! AGP 3.x device "
"not operating in AGP 3.x mode found on the "
"secondary bus of an AGP 3.5 bridge operating "
"with AGP 3.0 electricals!\n");
ret = -ENODEV;
goto free_and_exit;
}
tmp = (mstatus >> 10) & 0x7;
cal_cycle = min(cal_cycle, tmp);
/* figure the lesser rate */
tmp = mstatus & 0x7;
if(tmp < rate)
rate = tmp;
}
/* Turn rate into something we can actually write out to AGPCMD */
switch(rate) {
case 0x1:
case 0x2:
break;
case 0x3:
rate = 0x2;
break;
default:
printk(KERN_ERR PFX "woah! Bogus AGP rate (%d) "
"value found advertised behind an AGP 3.0 bridge!\n", rate);
ret = -ENODEV;
goto free_and_exit;
}
/*
......@@ -470,59 +443,19 @@ int agp_3_0_node_enable(struct agp_bridge_data *bridge, u32 mode, u32 minor)
* whether isochronous transfers are supported.
*/
if (isoch) {
ret = agp_3_0_isochronous_node_enable(bridge, dev_list, ndevs);
ret = agp_3_5_isochronous_node_enable(bridge, dev_list, ndevs);
if (ret) {
printk(KERN_INFO PFX "Something bad happened setting "
"up isochronous xfers. Falling back to "
"non-isochronous xfer mode.\n");
}
}
agp_3_0_nonisochronous_node_enable(bridge, dev_list, ndevs);
/*
* Set the calculated minimum supported cal_cycle and minimum
* supported transfer rate in the target's AGPCMD register.
* Also set the AGP_ENABLE bit, effectively 'turning on' the
* target (this has to be done _before_ turning on the masters).
*/
pci_read_config_dword(td, bridge->capndx+AGPCMD, &tcmd);
tcmd &= ~(0x7 << 10);
tcmd &= ~0x7;
tcmd |= cal_cycle << 10;
tcmd |= 0x1 << 8;
tcmd |= rate;
pci_write_config_dword(td, bridge->capndx+AGPCMD, tcmd);
/*
* Set the target's advertised arqsz value, the minimum supported
* transfer rate, and the AGP_ENABLE bit in each master's AGPCMD
* register.
*/
list_for_each(pos, head) {
cur = list_entry(pos, struct agp_3_0_dev, list);
dev = cur->dev;
mcapndx = cur->capndx;
pci_read_config_dword(dev, cur->capndx+AGPCMD, &mcmd);
mcmd &= ~(0x7 << AGPSTAT_ARQSZ_SHIFT);
mcmd &= ~0x7;
mcmd |= arqsz << 13;
mcmd |= AGPSTAT_AGP_ENABLE;
mcmd |= rate;
pci_write_config_dword(dev, cur->capndx+AGPCMD, mcmd);
}
agp_3_5_nonisochronous_node_enable(bridge, dev_list, ndevs);
free_and_exit:
/* Be sure to free the dev_list */
for(pos = head->next; pos != head;) {
cur = list_entry(pos, struct agp_3_0_dev, list);
for (pos=head->next; pos!=head; ) {
cur = list_entry(pos, struct agp_3_5_dev, list);
pos = pos->next;
kfree(cur);
......@@ -533,5 +466,3 @@ int agp_3_0_node_enable(struct agp_bridge_data *bridge, u32 mode, u32 minor)
return ret;
}
EXPORT_SYMBOL_GPL(agp_3_0_node_enable);
......@@ -49,7 +49,7 @@ config DRM_RADEON
config DRM_I810
tristate "Intel I810"
depends on DRM && AGP
depends on DRM && AGP && AGP_INTEL
help
Choose this option if you have an Intel I810 graphics card. If M is
selected, the module will be called i810. AGP support is required
......@@ -57,7 +57,7 @@ config DRM_I810
config DRM_I830
tristate "Intel 830M, 845G, 852GM, 855GM, 865G"
depends on DRM && AGP
depends on DRM && AGP && AGP_INTEL
help
Choose this option if you have a system that has Intel 830M, 845G,
852GM, 855GM or 865G integrated graphics. If M is selected, the
......
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