49,7 → 49,6 |
|
|
#include "pci.inc" |
#include "isoch.inc" |
|
static void intel_8xx_tlbflush(void *mem) |
{ |
500,8 → 499,176 |
} |
|
|
struct agp_3_5_dev |
{ |
link_t link; |
int capndx; |
u32_t maxbw; |
PCITAG tag; |
}; |
|
|
/* |
* Fully configure and enable an AGP 3.0 host bridge and all the devices |
* lying behind it. |
*/ |
int agp_3_5_enable(agp_t *bridge) |
{ |
u8_t mcapndx; |
u32_t isoch, arqsz; |
u32_t tstatus, mstatus, ncapid; |
u32_t mmajor; |
u16_t mpstat; |
|
link_t dev_list; |
|
struct agp_3_5_dev *cur, *pos; |
|
unsigned int ndevs = 0; |
PCITAG dev = 0; |
int ret = 0; |
|
/* Extract some power-on defaults from the target */ |
tstatus = pciReadLong(bridge->PciTag, bridge->capndx+AGPSTAT); |
isoch = (tstatus >> 17) & 0x1; |
if (isoch == 0) /* isoch xfers not available, bail out. */ |
return -1; |
|
arqsz = (tstatus >> 13) & 0x7; |
|
list_initialize(&dev_list); |
|
/* Find all AGP devices, and add them to dev_list. */ |
for_each_pci_dev(dev) |
{ |
u16_t devclass; |
|
mcapndx = pci_find_capability(dev, PCI_CAP_ID_AGP); |
if (mcapndx == 0) |
continue; |
|
devclass = pciReadWord(dev, 0x0A); |
|
switch (devclass & 0xff00) |
{ |
case 0x0600: /* Bridge */ |
/* Skip bridges. We should call this function for each one. */ |
continue; |
|
case 0x0001: /* Unclassified device */ |
/* Don't know what this is, but log it for investigation. */ |
if (mcapndx != 0) { |
dbgprintf("Wacky, found unclassified AGP device.\n"); |
} |
continue; |
|
case 0x0300: /* Display controller */ |
case 0x0400: /* Multimedia controller */ |
if((cur = malloc(sizeof(*cur))) == NULL) |
{ |
ret = -1; |
goto free_and_exit; |
} |
cur->tag = dev; |
list_prepend(&cur->link, &dev_list); |
ndevs++; |
continue; |
|
default: |
continue; |
} |
} |
|
/* |
* 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 |
*/ |
|
cur = (struct agp_3_5_dev*)dev_list.next; |
|
while(&cur->link != &dev_list) |
{ |
dev = cur->tag; |
|
mpstat = pciReadWord(dev, PCI_STATUS); |
if ((mpstat & PCI_STATUS_CAP_LIST) == 0) |
continue; |
|
mcapndx = pciReadByte(dev, PCI_CAPABILITY_LIST); |
if (mcapndx != 0) { |
do { |
ncapid = pciReadLong(dev, mcapndx); |
if ((ncapid & 0xff) != 2) |
mcapndx = (ncapid >> 8) & 0xff; |
} |
while (((ncapid & 0xff) != 2) && (mcapndx != 0)); |
} |
|
if (mcapndx == 0) { |
dbgprintf("woah! Non-AGP device " |
"found on the secondary bus of an AGP 3.5 bridge!\n"); |
ret = -1; |
goto free_and_exit; |
} |
|
mmajor = (ncapid >> AGP_MAJOR_VERSION_SHIFT) & 0xf; |
if (mmajor < 3) { |
dbgprintf("woah! AGP 2.0 device " |
"found on the secondary bus of an AGP 3.5 " |
"bridge operating with AGP 3.0 electricals!\n"); |
ret = -1; |
goto free_and_exit; |
} |
|
cur->capndx = mcapndx; |
|
mstatus = pciReadLong(dev, cur->capndx+AGPSTAT); |
|
if (((mstatus >> 3) & 0x1) == 0) { |
dbgprintf("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 = -1; |
goto free_and_exit; |
} |
cur = (struct agp_3_5_dev*)cur->link.next; |
} |
|
/* |
* Call functions to divide target resources amongst the AGP 3.0 |
* masters. This process is dramatically different depending on |
* whether isochronous transfers are supported. |
*/ |
if (isoch) { |
ret = agp_3_5_isochronous_node_enable(bridge, &dev_list, ndevs); |
if (ret) { |
dbgprintf("Something bad happened setting " |
"up isochronous xfers. Falling back to " |
"non-isochronous xfer mode.\n"); |
} else { |
goto free_and_exit; |
} |
} |
agp_3_5_nonisochronous_node_enable(bridge, dev_list, ndevs); |
|
free_and_exit: |
/* Be sure to free the dev_list */ |
for (pos = (struct agp_3_5_dev*)dev_list.next; &pos->link != &dev_list; ) |
{ |
cur = pos; |
|
pos = (struct agp_3_5_dev*)pos->link.next; |
free(cur); |
} |
|
get_out: |
return ret; |
} |
|
|
void agp_generic_enable(u32_t requested_mode) |
{ |
u32_t bridge_agpstat, temp; |