From 6ca49bc0c1eded95762e8a3bd33dd2998f94670f Mon Sep 17 00:00:00 2001 From: Rudolf Cornelissen Date: Sun, 4 Jul 2004 15:06:08 +0000 Subject: [PATCH] updates needed to detect early AGP1.0 no-feature devices, and abort on PCI nVidia cards git-svn-id: file:///srv/svn/repos/haiku/trunk/current@8290 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../accelerants/nvidia/engine/nv_agp.c | 407 ++++++++++-------- 1 file changed, 236 insertions(+), 171 deletions(-) diff --git a/src/add-ons/accelerants/nvidia/engine/nv_agp.c b/src/add-ons/accelerants/nvidia/engine/nv_agp.c index 19c141c8d1..f6b730e0da 100644 --- a/src/add-ons/accelerants/nvidia/engine/nv_agp.c +++ b/src/add-ons/accelerants/nvidia/engine/nv_agp.c @@ -1,5 +1,9 @@ /* Author: - Rudolf Cornelissen 6/2004 + Rudolf Cornelissen 6/2004-7/2004 + + Note: + This stuff will probably be relocated to the AGP busmanager module later on, + but for now we have something to test with... */ #define MODULE_BIT 0x00000100 @@ -8,6 +12,10 @@ #include "nv_std.h" static void nv_agp_list_caps(agp_info ai); +static bool has_AGP_interface(agp_info *ai_card, uint8 *adress); + +#define PCI_CFGR(A) (nv_pci_access.offset = A, ioctl(fd,NV_GET_PCI, &nv_pci_access, sizeof(nv_pci_access)), nv_pci_access.value) +#define PCI_CFGW(A,B) (nv_pci_access.offset = A, nv_pci_access.value = B, ioctl(fd,NV_SET_PCI,&nv_pci_access,sizeof(nv_pci_access))) status_t nv_agp_setup(void) { @@ -15,190 +23,207 @@ status_t nv_agp_setup(void) int agp_fd; agp_info ai_card, ai_bridge; uint8 rq_depth_card, rq_depth_bridge; + uint8 adress; - /* check for card's AGP capabilities and list them */ - ai_card.config.agp_cap_id = CFGR(AGPREF); - ai_card.config.agp_stat = CFGR(AGPSTAT); - ai_card.config.agp_cmd = CFGR(AGPCMD); - - if ((ai_card.config.agp_cap_id & 0x00ff0000) && ((ai_card.config.agp_cap_id & AGP_id_mask) == AGP_id)) + /* check for card's AGP capabilities - see PCI specification */ + /* Note: + * We have to iterate through the capability list as specified in the PCI spec, + * otherwise we cannot distinquish between nVidia PCI and AGP cards! + * (PCI cards still have AGP registers that pretend to support AGP) */ + if (!(has_AGP_interface(&ai_card, &adress))) { - LOG(4,("AGP: graphicscard is AGP type, supporting specification %d.%d;\n", - ((ai_card.config.agp_cap_id & AGP_rev_major) >> AGP_rev_major_shift), - ((ai_card.config.agp_cap_id & AGP_rev_minor) >> AGP_rev_minor_shift))); + LOG(4,("AGP: graphicscard is PCI type.\n")); + return B_ERROR; + } - nv_agp_list_caps(ai_card); + LOG(4,("AGP: graphicscard is AGP type, supporting specification %d.%d;\n", + ((ai_card.config.agp_cap_id & AGP_rev_major) >> AGP_rev_major_shift), + ((ai_card.config.agp_cap_id & AGP_rev_minor) >> AGP_rev_minor_shift))); - /* check for motherboard AGP host bridge */ - /* open the BeOS AGP kernel driver, the permissions aren't important */ - strcpy(path, "/dev/graphics/agp/1"); - agp_fd = open(path, B_READ_WRITE); - if (agp_fd < 0) - { - LOG(4,("AGP: cannot open AGP host bridge driver, aborting!\n")); - /* program card for PCI access */ - CFGW(AGPCMD, 0x00000000); + nv_agp_list_caps(ai_card); - return B_ERROR; - } + /* check for motherboard AGP host bridge */ + /* open the BeOS AGP kernel driver, the permissions aren't important */ + strcpy(path, "/dev/graphics/agp/1"); + agp_fd = open(path, B_READ_WRITE); + if (agp_fd < 0) + { + LOG(4,("AGP: cannot open AGP host bridge driver, aborting!\n")); + /* program card for PCI access */ + PCI_CFGW((adress + 8), 0x00000000); - /* get host bridge info */ - ioctl(agp_fd, GET_CONFIG, &ai_bridge); + return B_ERROR; + } - LOG(4,("AGP: AGP host bridge found, vendorID $%04x, deviceID $%04x\n", - ai_bridge.dev.vendor_id, ai_bridge.dev.device_id)); - if (ai_bridge.status != B_OK) - { - LOG(4,("AGP: host bridge failed to respond correctly, aborting AGP setup!\n")); - /* close host bridge driver */ - close(agp_fd); - /* program card for PCI access */ - CFGW(AGPCMD, 0x00000000); - - return B_ERROR; - } - - /* list host bridge capabilities */ - LOG(4,("AGP: host bridge supports specification %d.%d;\n", - ((ai_bridge.config.agp_cap_id & AGP_rev_major) >> AGP_rev_major_shift), - ((ai_bridge.config.agp_cap_id & AGP_rev_minor) >> AGP_rev_minor_shift))); - nv_agp_list_caps(ai_bridge); - - /* abort if specified by user in nv.settings */ - if (si->settings.force_pci) - { - /* user specified not to use AGP */ - LOG(4,("AGP: forcing PCI mode (specified in nv.settings).\n")); - /* close host bridge driver */ - close(agp_fd); - /* program card for PCI access */ - CFGW(AGPCMD, 0x00000000); - - return B_OK; - } - - /* find out shared AGP capabilities of card and host bridge */ - if ((ai_card.config.agp_stat & AGP_rate_rev) != - (ai_bridge.config.agp_stat & AGP_rate_rev)) - { - LOG(4,("AGP: compatibility problem detected, aborting AGP setup!\n")); - /* close host bridge driver */ - close(agp_fd); - /* program card for PCI access */ - CFGW(AGPCMD, 0x00000000); - - return B_ERROR; - } - - /* both card and bridge are set to the same standard */ - /* (which is as it should be!) */ - LOG(4,("AGP: enabling AGP\n")); - - /* select highest AGP mode */ - if (!(ai_bridge.config.agp_stat & AGP_rate_rev)) - { - /* AGP 2.0 scheme applies */ - if ((ai_card.config.agp_stat & AGP_2_4x) && - (ai_bridge.config.agp_stat & AGP_2_4x)) - { - LOG(4,("AGP: using AGP 2.0 4x mode\n")); - ai_card.config.agp_cmd = AGP_2_4x; - ai_bridge.config.agp_cmd = AGP_2_4x; - } - else - { - if ((ai_card.config.agp_stat & AGP_2_2x) && - (ai_bridge.config.agp_stat & AGP_2_2x)) - { - LOG(4,("AGP: using AGP 2.0 2x mode\n")); - ai_card.config.agp_cmd = AGP_2_2x; - ai_bridge.config.agp_cmd = AGP_2_2x; - } - else - { - LOG(4,("AGP: using AGP 2.0 1x mode\n")); - ai_card.config.agp_cmd = AGP_2_1x; - ai_bridge.config.agp_cmd = AGP_2_1x; - } - } - } - else - { - /* AGP 3.0 scheme applies */ - if ((ai_card.config.agp_stat & AGP_3_8x) && - (ai_bridge.config.agp_stat & AGP_3_8x)) - { - LOG(4,("AGP: using AGP 3.0 8x mode\n")); - ai_card.config.agp_cmd = AGP_3_8x; - ai_bridge.config.agp_cmd = AGP_3_8x; - } - else - { - LOG(4,("AGP: using AGP 3.0 4x mode\n")); - ai_card.config.agp_cmd = AGP_3_4x; - ai_bridge.config.agp_cmd = AGP_3_4x; - } - } - - /* activate sideband adressing if possible */ - if ((ai_card.config.agp_stat & AGP_SBA) && - (ai_bridge.config.agp_stat & AGP_SBA)) - { - LOG(4,("AGP: enabling sideband adressing (SBA)\n")); - ai_card.config.agp_cmd |= AGP_SBA; - ai_bridge.config.agp_cmd |= AGP_SBA; - } - - /* activate fast writes if possible */ - if ((ai_card.config.agp_stat & AGP_FW) && - (ai_bridge.config.agp_stat & AGP_FW)) - { - LOG(4,("AGP: enabling fast writes (FW)\n")); - ai_card.config.agp_cmd |= AGP_FW; - ai_bridge.config.agp_cmd |= AGP_FW; - } - - /* setup maximum request depth supported */ - /* note: - * this is writable only in the graphics card */ - rq_depth_card = ((ai_card.config.agp_stat & AGP_RQ) >> AGP_RQ_shift); - rq_depth_bridge = ((ai_bridge.config.agp_stat & AGP_RQ) >> AGP_RQ_shift); - if (rq_depth_card < rq_depth_bridge) - { - ai_card.config.agp_cmd |= (rq_depth_card << AGP_RQ_shift); - LOG(4,("AGP: max. AGP queued request depth will be set to %d\n", - (rq_depth_card + 1))); - } - else - { - ai_card.config.agp_cmd |= (rq_depth_bridge << AGP_RQ_shift); - LOG(4,("AGP: max. AGP queued request depth will be set to %d\n", - (rq_depth_bridge + 1))); - } - - /* set the enable AGP bits */ - /* note: - * the AGP standard defines that this bit may be written to the AGPCMD - * registers simultanously with the other bits if a single 32bit write - * to each register is used. */ - ai_card.config.agp_cmd |= AGP_enable; - ai_bridge.config.agp_cmd |= AGP_enable; - - /* finally program both the host bridge and the graphics card! */ - /* note: - * the AGP standard defines that the host bridge should be enabled first. */ - ioctl(agp_fd, SET_CONFIG, &ai_bridge); - CFGW(AGPCMD, ai_card.config.agp_cmd); - - LOG(4,("AGP: graphics card AGPCMD register readback $%08x\n", CFGR(AGPCMD))); + /* get host bridge info */ + ioctl(agp_fd, GET_CONFIG, &ai_bridge); + LOG(4,("AGP: AGP host bridge found, vendorID $%04x, deviceID $%04x\n", + ai_bridge.dev.vendor_id, ai_bridge.dev.device_id)); + if (ai_bridge.status != B_OK) + { + LOG(4,("AGP: host bridge failed to respond correctly, aborting AGP setup!\n")); /* close host bridge driver */ close(agp_fd); + /* program card for PCI access */ + PCI_CFGW((adress + 8), 0x00000000); + + return B_ERROR; + } + + /* list host bridge capabilities */ + LOG(4,("AGP: host bridge supports specification %d.%d;\n", + ((ai_bridge.config.agp_cap_id & AGP_rev_major) >> AGP_rev_major_shift), + ((ai_bridge.config.agp_cap_id & AGP_rev_minor) >> AGP_rev_minor_shift))); + nv_agp_list_caps(ai_bridge); + + /* abort if specified by user in nv.settings */ + if (si->settings.force_pci) + { + /* user specified not to use AGP */ + LOG(4,("AGP: forcing PCI mode (specified in nv.settings).\n")); + /* close host bridge driver */ + close(agp_fd); + /* program card for PCI access */ + PCI_CFGW((adress + 8), 0x00000000); + + return B_ERROR; + } + + /* find out if AGP modes are supported: devices exist that have the AGP style + * connector with AGP style registers, but not the features! + * (confirmed Matrox Millenium II AGP for instance) */ + if (!(ai_card.config.agp_stat & AGP_rates) || + !(ai_bridge.config.agp_stat & AGP_rates)) + { + LOG(4,("AGP: no AGP modes possible, aborting AGP setup!\n")); + /* close host bridge driver */ + close(agp_fd); + /* program card for PCI access */ + PCI_CFGW((adress + 8), 0x00000000); + + return B_ERROR; + } + + /* find out shared AGP capabilities of card and host bridge */ + if ((ai_card.config.agp_stat & AGP_rate_rev) != + (ai_bridge.config.agp_stat & AGP_rate_rev)) + { + LOG(4,("AGP: compatibility problem detected, aborting AGP setup!\n")); + /* close host bridge driver */ + close(agp_fd); + /* program card for PCI access */ + PCI_CFGW((adress + 8), 0x00000000); + + return B_ERROR; + } + + /* both card and bridge are set to the same standard */ + /* (which is as it should be!) */ + LOG(4,("AGP: enabling AGP\n")); + + /* select highest AGP mode */ + if (!(ai_bridge.config.agp_stat & AGP_rate_rev)) + { + /* AGP 2.0 scheme applies */ + if ((ai_card.config.agp_stat & AGP_2_4x) && + (ai_bridge.config.agp_stat & AGP_2_4x)) + { + LOG(4,("AGP: using AGP 2.0 4x mode\n")); + ai_card.config.agp_cmd = AGP_2_4x; + ai_bridge.config.agp_cmd = AGP_2_4x; + } + else + { + if ((ai_card.config.agp_stat & AGP_2_2x) && + (ai_bridge.config.agp_stat & AGP_2_2x)) + { + LOG(4,("AGP: using AGP 2.0 2x mode\n")); + ai_card.config.agp_cmd = AGP_2_2x; + ai_bridge.config.agp_cmd = AGP_2_2x; + } + else + { + LOG(4,("AGP: using AGP 2.0 1x mode\n")); + ai_card.config.agp_cmd = AGP_2_1x; + ai_bridge.config.agp_cmd = AGP_2_1x; + } + } } else { - LOG(4,("AGP: graphicscard is PCI type.\n")); + /* AGP 3.0 scheme applies */ + if ((ai_card.config.agp_stat & AGP_3_8x) && + (ai_bridge.config.agp_stat & AGP_3_8x)) + { + LOG(4,("AGP: using AGP 3.0 8x mode\n")); + ai_card.config.agp_cmd = AGP_3_8x; + ai_bridge.config.agp_cmd = AGP_3_8x; + } + else + { + LOG(4,("AGP: using AGP 3.0 4x mode\n")); + ai_card.config.agp_cmd = AGP_3_4x; + ai_bridge.config.agp_cmd = AGP_3_4x; + } } + + /* activate sideband adressing if possible */ + if ((ai_card.config.agp_stat & AGP_SBA) && + (ai_bridge.config.agp_stat & AGP_SBA)) + { + LOG(4,("AGP: enabling sideband adressing (SBA)\n")); + ai_card.config.agp_cmd |= AGP_SBA; + ai_bridge.config.agp_cmd |= AGP_SBA; + } + + /* activate fast writes if possible */ + if ((ai_card.config.agp_stat & AGP_FW) && + (ai_bridge.config.agp_stat & AGP_FW)) + { + LOG(4,("AGP: enabling fast writes (FW)\n")); + ai_card.config.agp_cmd |= AGP_FW; + ai_bridge.config.agp_cmd |= AGP_FW; + } + + /* setup maximum request depth supported */ + /* note: + * this is writable only in the graphics card */ + rq_depth_card = ((ai_card.config.agp_stat & AGP_RQ) >> AGP_RQ_shift); + rq_depth_bridge = ((ai_bridge.config.agp_stat & AGP_RQ) >> AGP_RQ_shift); + if (rq_depth_card < rq_depth_bridge) + { + ai_card.config.agp_cmd |= (rq_depth_card << AGP_RQ_shift); + LOG(4,("AGP: max. AGP queued request depth will be set to %d\n", + (rq_depth_card + 1))); + } + else + { + ai_card.config.agp_cmd |= (rq_depth_bridge << AGP_RQ_shift); + LOG(4,("AGP: max. AGP queued request depth will be set to %d\n", + (rq_depth_bridge + 1))); + } + + /* set the enable AGP bits */ + /* note: + * the AGP standard defines that this bit may be written to the AGPCMD + * registers simultanously with the other bits if a single 32bit write + * to each register is used. */ + ai_card.config.agp_cmd |= AGP_enable; + ai_bridge.config.agp_cmd |= AGP_enable; + + /* finally program both the host bridge and the graphics card! */ + /* note: + * the AGP standard defines that the host bridge should be enabled first. */ + ioctl(agp_fd, SET_CONFIG, &ai_bridge); + PCI_CFGW((adress + 8), ai_card.config.agp_cmd); + + LOG(4,("AGP: graphics card AGPCMD register readback $%08x\n", CFGR(AGPCMD))); + + /* close host bridge driver */ + close(agp_fd); + + return B_OK; } static void nv_agp_list_caps(agp_info ai) @@ -282,3 +307,43 @@ static void nv_agp_list_caps(agp_info ai) else LOG(4,("AGP: this AGP interface is currently disabled.\n")); } + +static bool has_AGP_interface(agp_info *ai_card, uint8 *adress) +{ + bool has_AGP = false; + + /* check if device implements a list of capabilities */ + if (CFGR(DEVCTRL) & 0x00100000) + { + uint32 item; + uint8 item_adress; + + /* get pointer to PCI capabilities list */ + item_adress = CFGR(CFG_0) & 0x000000ff; + /* read first item from list */ + item = PCI_CFGR(item_adress); + while ((item & AGP_next_ptr) && ((item & AGP_id_mask) != AGP_id)) + { + /* read next item from list */ + item_adress = ((item & AGP_next_ptr) >> AGP_next_ptr_shift); + item = PCI_CFGR(item_adress); + } + if ((item & AGP_id_mask) == AGP_id) + { + /* we found the AGP interface! */ + has_AGP = true; + + /* return the adress if the interface */ + *adress = item_adress; + + /* readout the AGP interface capabilities and settings */ + ai_card->config.agp_cap_id = PCI_CFGR(item_adress); + ai_card->config.agp_stat = PCI_CFGR(item_adress + 4); + ai_card->config.agp_cmd = PCI_CFGR(item_adress + 8); + } + } + return has_AGP; +} + +#undef PCI_CFGR +#undef PCI_CFGW