11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Setup routines for AGP 3.5 compliant bridges. 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/list.h> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/agp_backend.h> 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 94e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/slab.h> 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "agp.h" 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Generic AGP 3.5 enabling routines */ 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct agp_3_5_dev { 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head list; 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 capndx; 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 maxbw; 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_dev *dev; 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void agp_3_5_dev_list_insert(struct list_head *head, struct list_head *new) 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct agp_3_5_dev *cur, *n = list_entry(new, struct agp_3_5_dev, list); 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *pos; 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each(pos, head) { 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur = list_entry(pos, struct agp_3_5_dev, list); 296a92a4e0d201aea6d7c83f100d77310676b2e049Dave Jones if (cur->maxbw > n->maxbw) 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add_tail(new, pos); 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void agp_3_5_dev_list_sort(struct agp_3_5_dev *list, unsigned int ndevs) 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct agp_3_5_dev *cur; 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_dev *dev; 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *pos, *tmp, *head = &list->list, *start = head->next; 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 nistat; 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(head); 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (pos=start; pos!=head; ) { 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur = list_entry(pos, struct agp_3_5_dev, list); 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = cur->dev; 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_dword(dev, cur->capndx+AGPNISTAT, &nistat); 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur->maxbw = (nistat >> 16) & 0xff; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = pos; 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pos = pos->next; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds agp_3_5_dev_list_insert(head, tmp); 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 576a92a4e0d201aea6d7c83f100d77310676b2e049Dave Jones/* 586a92a4e0d201aea6d7c83f100d77310676b2e049Dave Jones * Initialize all isochronous transfer parameters for an AGP 3.0 596a92a4e0d201aea6d7c83f100d77310676b2e049Dave Jones * node (i.e. a host bridge in combination with the adapters 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * lying behind it...) 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int agp_3_5_isochronous_node_enable(struct agp_bridge_data *bridge, 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct agp_3_5_dev *dev_list, unsigned int ndevs) 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Convenience structure to make the calculations clearer 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * here. The field names come straight from the AGP 3.0 spec. 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct isoch_data { 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 maxbw; 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 n; 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 y; 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 l; 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 rq; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct agp_3_5_dev *dev; 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_dev *td = bridge->dev, *dev; 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *head = &dev_list->list, *pos; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct agp_3_5_dev *cur; 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct isoch_data *master, target; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cdev = 0; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 mnistat, tnistat, tstatus, mcmd; 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 tnicmd, mnicmd; 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 mcapndx; 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 tot_bw = 0, tot_n = 0, tot_rq = 0, y_max, rq_isoch, rq_async; 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 step, rem, rem_isoch, rem_async; 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We'll work with an array of isoch_data's (one for each 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device in dev_list) throughout this function. 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((master = kmalloc(ndevs * sizeof(*master), GFP_KERNEL)) == NULL) { 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto get_out; 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Sort the device list by maxbw. We need to do this because the 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * spec suggests that the devices with the smallest requirements 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * have their resources allocated first, with all remaining resources 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * falling to the device with the largest requirement. 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We don't exactly do this, we divide target resources by ndevs 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and split them amongst the AGP 3.0 devices. The remainder of such 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * division operations are dropped on the last device, sort of like 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the spec mentions it should be done. 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We can't do this sort when we initially construct the dev_list 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * because we don't know until this function whether isochronous 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transfers are enabled and consequently whether maxbw will mean 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * anything. 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds agp_3_5_dev_list_sort(dev_list, ndevs); 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_dword(td, bridge->capndx+AGPNISTAT, &tnistat); 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_dword(td, bridge->capndx+AGPSTAT, &tstatus); 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Extract power-on defaults from the target */ 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target.maxbw = (tnistat >> 16) & 0xff; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target.n = (tnistat >> 8) & 0xff; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target.y = (tnistat >> 6) & 0x3; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target.l = (tnistat >> 3) & 0x7; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target.rq = (tstatus >> 24) & 0xff; 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds y_max = target.y; 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Extract power-on defaults for each device in dev_list. Along 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the way, calculate the total isochronous bandwidth required 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by these devices and the largest requested payload size. 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each(pos, head) { 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur = list_entry(pos, struct agp_3_5_dev, list); 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = cur->dev; 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mcapndx = cur->capndx; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_dword(dev, cur->capndx+AGPNISTAT, &mnistat); 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds master[cdev].maxbw = (mnistat >> 16) & 0xff; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds master[cdev].n = (mnistat >> 8) & 0xff; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds master[cdev].y = (mnistat >> 6) & 0x3; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds master[cdev].dev = cur; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tot_bw += master[cdev].maxbw; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds y_max = max(y_max, master[cdev].y); 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cdev++; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check if this configuration has any chance of working */ 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tot_bw > target.maxbw) { 156e3cf69511a2c5369c58f6fd6a065de152c3d4b22Bjorn Helgaas dev_err(&td->dev, "isochronous bandwidth required " 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "by AGP 3.0 devices exceeds that which is supported by " 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "the AGP 3.0 bridge!\n"); 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENODEV; 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_and_exit; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target.y = y_max; 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write the calculated payload size into the target's NICMD 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * register. Doing this directly effects the ISOCH_N value 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in the target's NISTAT register, so we need to do this now 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to get an accurate value for ISOCH_N later. 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_word(td, bridge->capndx+AGPNICMD, &tnicmd); 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tnicmd &= ~(0x3 << 6); 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tnicmd |= target.y << 6; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_word(td, bridge->capndx+AGPNICMD, tnicmd); 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Reread the target's ISOCH_N */ 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_dword(td, bridge->capndx+AGPNISTAT, &tnistat); 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target.n = (tnistat >> 8) & 0xff; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Calculate the minimum ISOCH_N needed by each master */ 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (cdev=0; cdev<ndevs; cdev++) { 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds master[cdev].y = target.y; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds master[cdev].n = master[cdev].maxbw / (master[cdev].y + 1); 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tot_n += master[cdev].n; 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Exit if the minimal ISOCH_N allocation among the masters is more 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * than the target can handle. */ 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tot_n > target.n) { 191e3cf69511a2c5369c58f6fd6a065de152c3d4b22Bjorn Helgaas dev_err(&td->dev, "number of isochronous " 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "transactions per period required by AGP 3.0 devices " 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "exceeds that which is supported by the AGP 3.0 " 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "bridge!\n"); 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENODEV; 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_and_exit; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Calculate left over ISOCH_N capability in the target. We'll give 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this to the hungriest device (as per the spec) */ 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rem = target.n - tot_n; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2036a92a4e0d201aea6d7c83f100d77310676b2e049Dave Jones /* 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Calculate the minimum isochronous RQ depth needed by each master. 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Along the way, distribute the extra ISOCH_N capability calculated 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * above. 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (cdev=0; cdev<ndevs; cdev++) { 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is a little subtle. If ISOCH_Y > 64B, then ISOCH_Y 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * byte isochronous writes will be broken into 64B pieces. 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This means we need to budget more RQ depth to account for 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * these kind of writes (each isochronous write is actually 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * many writes on the AGP bus). 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds master[cdev].rq = master[cdev].n; 2176a92a4e0d201aea6d7c83f100d77310676b2e049Dave Jones if (master[cdev].y > 0x1) 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds master[cdev].rq *= (1 << (master[cdev].y - 1)); 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tot_rq += master[cdev].rq; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 222496ebd386439fee838df6b9c7d1306c36e7f6952Daniel =?ISO- master[ndevs-1].n += rem; 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Figure the number of isochronous and asynchronous RQ slots the 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * target is providing. */ 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rq_isoch = (target.y > 0x1) ? target.n * (1 << (target.y - 1)) : target.n; 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rq_async = target.rq - rq_isoch; 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Exit if the minimal RQ needs of the masters exceeds what the target 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * can provide. */ 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tot_rq > rq_isoch) { 232e3cf69511a2c5369c58f6fd6a065de152c3d4b22Bjorn Helgaas dev_err(&td->dev, "number of request queue slots " 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "required by the isochronous bandwidth requested by " 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "AGP 3.0 devices exceeds the number provided by the " 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "AGP 3.0 bridge!\n"); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENODEV; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_and_exit; 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Calculate asynchronous RQ capability in the target (per master) as 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * well as the total number of leftover isochronous RQ slots. */ 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds step = rq_async / ndevs; 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rem_async = step + (rq_async % ndevs); 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rem_isoch = rq_isoch - tot_rq; 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Distribute the extra RQ slots calculated above and write our 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * isochronous settings out to the actual devices. */ 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (cdev=0; cdev<ndevs; cdev++) { 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur = master[cdev].dev; 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = cur->dev; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mcapndx = cur->capndx; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds master[cdev].rq += (cdev == ndevs - 1) 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ? (rem_async + rem_isoch) : step; 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_word(dev, cur->capndx+AGPNICMD, &mnicmd); 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_dword(dev, cur->capndx+AGPCMD, &mcmd); 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mnicmd &= ~(0xff << 8); 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mnicmd &= ~(0x3 << 6); 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mcmd &= ~(0xff << 24); 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mnicmd |= master[cdev].n << 8; 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mnicmd |= master[cdev].y << 6; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mcmd |= master[cdev].rq << 24; 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_dword(dev, cur->capndx+AGPCMD, mcmd); 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_word(dev, cur->capndx+AGPNICMD, mnicmd); 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfree_and_exit: 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(master); 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsget_out: 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function basically allocates request queue slots among the 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * AGP 3.0 systems in nonisochronous nodes. The algorithm is 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pretty stupid, divide the total number of RQ slots provided by the 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * target by ndevs. Distribute this many slots to each AGP 3.0 device, 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * giving any left over slots to the last device in dev_list. 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void agp_3_5_nonisochronous_node_enable(struct agp_bridge_data *bridge, 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct agp_3_5_dev *dev_list, unsigned int ndevs) 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct agp_3_5_dev *cur; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *head = &dev_list->list, *pos; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 tstatus, mcmd; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 trq, mrq, rem; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int cdev = 0; 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_dword(bridge->dev, bridge->capndx+AGPSTAT, &tstatus); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds trq = (tstatus >> 24) & 0xff; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mrq = trq / ndevs; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rem = mrq + (trq % ndevs); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (pos=head->next; cdev<ndevs; cdev++, pos=pos->next) { 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur = list_entry(pos, struct agp_3_5_dev, list); 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_dword(cur->dev, cur->capndx+AGPCMD, &mcmd); 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mcmd &= ~(0xff << 24); 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mcmd |= ((cdev == ndevs - 1) ? rem : mrq) << 24; 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_dword(cur->dev, cur->capndx+AGPCMD, mcmd); 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fully configure and enable an AGP 3.0 host bridge and all the devices 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * lying behind it. 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint agp_3_5_enable(struct agp_bridge_data *bridge) 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pci_dev *td = bridge->dev, *dev = NULL; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 mcapndx; 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 isoch, arqsz; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 tstatus, mstatus, ncapid; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 mmajor; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 mpstat; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct agp_3_5_dev *dev_list, *cur; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *head, *pos; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int ndevs = 0; 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret = 0; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Extract some power-on defaults from the target */ 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_dword(td, bridge->capndx+AGPSTAT, &tstatus); 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds isoch = (tstatus >> 17) & 0x1; 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isoch == 0) /* isoch xfers not available, bail out. */ 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds arqsz = (tstatus >> 13) & 0x7; 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3376a92a4e0d201aea6d7c83f100d77310676b2e049Dave Jones /* 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate a head for our AGP 3.5 device list 3396a92a4e0d201aea6d7c83f100d77310676b2e049Dave Jones * (multiple AGP v3 devices are allowed behind a single bridge). 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((dev_list = kmalloc(sizeof(*dev_list), GFP_KERNEL)) == NULL) { 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto get_out; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds head = &dev_list->list; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_LIST_HEAD(head); 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Find all AGP devices, and add them to dev_list. */ 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for_each_pci_dev(dev) { 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mcapndx = pci_find_capability(dev, PCI_CAP_ID_AGP); 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mcapndx == 0) 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch ((dev->class >>8) & 0xff00) { 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x0600: /* Bridge */ 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Skip bridges. We should call this function for each one. */ 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x0001: /* Unclassified device */ 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Don't know what this is, but log it for investigation. */ 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mcapndx != 0) { 362e3cf69511a2c5369c58f6fd6a065de152c3d4b22Bjorn Helgaas dev_info(&td->dev, "wacky, found unclassified AGP device %s [%04x/%04x]\n", 363e3cf69511a2c5369c58f6fd6a065de152c3d4b22Bjorn Helgaas pci_name(dev), 364e3cf69511a2c5369c58f6fd6a065de152c3d4b22Bjorn Helgaas dev->vendor, dev->device); 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x0300: /* Display controller */ 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0x0400: /* Multimedia controller */ 3706a92a4e0d201aea6d7c83f100d77310676b2e049Dave Jones if ((cur = kmalloc(sizeof(*cur), GFP_KERNEL)) == NULL) { 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENOMEM; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_and_exit; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur->dev = dev; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pos = &cur->list; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add(pos, head); 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ndevs++; 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Take an initial pass through the devices lying behind our host 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bridge. Make sure each one is actually an AGP 3.0 device, otherwise 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * exit with an error message. Along the way store the AGP 3.0 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cap_ptr for each device 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each(pos, head) { 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur = list_entry(pos, struct agp_3_5_dev, list); 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = cur->dev; 3956a92a4e0d201aea6d7c83f100d77310676b2e049Dave Jones 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_word(dev, PCI_STATUS, &mpstat); 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((mpstat & PCI_STATUS_CAP_LIST) == 0) 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &mcapndx); 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mcapndx != 0) { 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_dword(dev, mcapndx, &ncapid); 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ncapid & 0xff) != 2) 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mcapndx = (ncapid >> 8) & 0xff; 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (((ncapid & 0xff) != 2) && (mcapndx != 0)); 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mcapndx == 0) { 411e3cf69511a2c5369c58f6fd6a065de152c3d4b22Bjorn Helgaas dev_err(&td->dev, "woah! Non-AGP device %s on " 412e3cf69511a2c5369c58f6fd6a065de152c3d4b22Bjorn Helgaas "secondary bus of AGP 3.5 bridge!\n", 413e3cf69511a2c5369c58f6fd6a065de152c3d4b22Bjorn Helgaas pci_name(dev)); 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENODEV; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_and_exit; 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mmajor = (ncapid >> AGP_MAJOR_VERSION_SHIFT) & 0xf; 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mmajor < 3) { 420e3cf69511a2c5369c58f6fd6a065de152c3d4b22Bjorn Helgaas dev_err(&td->dev, "woah! AGP 2.0 device %s on " 421e3cf69511a2c5369c58f6fd6a065de152c3d4b22Bjorn Helgaas "secondary bus of AGP 3.5 bridge operating " 422e3cf69511a2c5369c58f6fd6a065de152c3d4b22Bjorn Helgaas "with AGP 3.0 electricals!\n", pci_name(dev)); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENODEV; 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_and_exit; 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur->capndx = mcapndx; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_dword(dev, cur->capndx+AGPSTAT, &mstatus); 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (((mstatus >> 3) & 0x1) == 0) { 432e3cf69511a2c5369c58f6fd6a065de152c3d4b22Bjorn Helgaas dev_err(&td->dev, "woah! AGP 3.x device %s not " 433e3cf69511a2c5369c58f6fd6a065de152c3d4b22Bjorn Helgaas "operating in AGP 3.x mode on secondary bus " 434e3cf69511a2c5369c58f6fd6a065de152c3d4b22Bjorn Helgaas "of AGP 3.5 bridge operating with AGP 3.0 " 435e3cf69511a2c5369c58f6fd6a065de152c3d4b22Bjorn Helgaas "electricals!\n", pci_name(dev)); 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -ENODEV; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_and_exit; 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Call functions to divide target resources amongst the AGP 3.0 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * masters. This process is dramatically different depending on 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * whether isochronous transfers are supported. 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (isoch) { 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = agp_3_5_isochronous_node_enable(bridge, dev_list, ndevs); 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret) { 449e3cf69511a2c5369c58f6fd6a065de152c3d4b22Bjorn Helgaas dev_info(&td->dev, "something bad happened setting " 450e3cf69511a2c5369c58f6fd6a065de152c3d4b22Bjorn Helgaas "up isochronous xfers; falling back to " 451e3cf69511a2c5369c58f6fd6a065de152c3d4b22Bjorn Helgaas "non-isochronous xfer mode\n"); 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto free_and_exit; 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds agp_3_5_nonisochronous_node_enable(bridge, dev_list, ndevs); 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfree_and_exit: 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Be sure to free the dev_list */ 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (pos=head->next; pos!=head; ) { 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cur = list_entry(pos, struct agp_3_5_dev, list); 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pos = pos->next; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(cur); 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(dev_list); 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsget_out: 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 471