| 1 | /******************************************************************************* |
| 2 | Copyright (C) Marvell International Ltd. and its affiliates |
| 3 | |
| 4 | This software file (the "File") is owned and distributed by Marvell |
| 5 | International Ltd. and/or its affiliates ("Marvell") under the following |
| 6 | alternative licensing terms. Once you have made an election to distribute the |
| 7 | File under one of the following license alternatives, please (i) delete this |
| 8 | introductory statement regarding license alternatives, (ii) delete the two |
| 9 | license alternatives that you have not elected to use and (iii) preserve the |
| 10 | Marvell copyright notice above. |
| 11 | |
| 12 | ******************************************************************************** |
| 13 | Marvell Commercial License Option |
| 14 | |
| 15 | If you received this File from Marvell and you have entered into a commercial |
| 16 | license agreement (a "Commercial License") with Marvell, the File is licensed |
| 17 | to you under the terms of the applicable Commercial License. |
| 18 | |
| 19 | ******************************************************************************** |
| 20 | Marvell GPL License Option |
| 21 | |
| 22 | If you received this File from Marvell, you may opt to use, redistribute and/or |
| 23 | modify this File in accordance with the terms and conditions of the General |
| 24 | Public License Version 2, June 1991 (the "GPL License"), a copy of which is |
| 25 | available along with the File in the license.txt file or by writing to the Free |
| 26 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or |
| 27 | on the worldwide web at http://www.gnu.org/licenses/gpl.txt. |
| 28 | |
| 29 | THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED |
| 30 | WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY |
| 31 | DISCLAIMED. The GPL License provides additional details about this warranty |
| 32 | disclaimer. |
| 33 | ******************************************************************************** |
| 34 | Marvell BSD License Option |
| 35 | |
| 36 | If you received this File from Marvell, you may opt to use, redistribute and/or |
| 37 | modify this File under the following licensing terms. |
| 38 | Redistribution and use in source and binary forms, with or without modification, |
| 39 | are permitted provided that the following conditions are met: |
| 40 | |
| 41 | * Redistributions of source code must retain the above copyright notice, |
| 42 | this list of conditions and the following disclaimer. |
| 43 | |
| 44 | * Redistributions in binary form must reproduce the above copyright |
| 45 | notice, this list of conditions and the following disclaimer in the |
| 46 | documentation and/or other materials provided with the distribution. |
| 47 | |
| 48 | * Neither the name of Marvell nor the names of its contributors may be |
| 49 | used to endorse or promote products derived from this software without |
| 50 | specific prior written permission. |
| 51 | |
| 52 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
| 53 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 54 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 55 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR |
| 56 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 57 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 58 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
| 59 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 60 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 61 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 62 | |
| 63 | *******************************************************************************/ |
| 64 | |
| 65 | /* includes */ |
| 66 | #include "mvPciUtils.h" |
| 67 | |
| 68 | #include "ctrlEnv/mvCtrlEnvLib.h" |
| 69 | |
| 70 | /* #define MV_DEBUG */ |
| 71 | /* defines */ |
| 72 | #ifdef MV_DEBUG |
| 73 | #define DB(x) x |
| 74 | #define mvOsPrintf printf |
| 75 | #else |
| 76 | #define DB(x) |
| 77 | #endif |
| 78 | |
| 79 | /* |
| 80 | This module only support scanning of Header type 00h of pci devices |
| 81 | There is no suppotr for Header type 01h of pci devices ( PCI bridges ) |
| 82 | */ |
| 83 | |
| 84 | |
| 85 | static MV_STATUS pciDetectDevice(MV_U32 pciIf, |
| 86 | MV_U32 bus, |
| 87 | MV_U32 dev, |
| 88 | MV_U32 func, |
| 89 | MV_PCI_DEVICE *pPciAgent); |
| 90 | |
| 91 | static MV_U32 pciDetectDeviceBars(MV_U32 pciIf, |
| 92 | MV_U32 bus, |
| 93 | MV_U32 dev, |
| 94 | MV_U32 func, |
| 95 | MV_PCI_DEVICE *pPciAgent); |
| 96 | |
| 97 | |
| 98 | |
| 99 | |
| 100 | |
| 101 | |
| 102 | /******************************************************************************* |
| 103 | * mvPciScan - Scan a PCI interface bus |
| 104 | * |
| 105 | * DESCRIPTION: |
| 106 | * Performs a full scan on a PCI interface and returns all possible details |
| 107 | * on the agents found on the bus. |
| 108 | * |
| 109 | * INPUT: |
| 110 | * pciIf - PCI Interface |
| 111 | * pPciAgents - Pointer to an Array of the pci agents to be detected |
| 112 | * pPciAgentsNum - pPciAgents array maximum number of elements |
| 113 | * |
| 114 | * OUTPUT: |
| 115 | * pPciAgents - Array of the pci agents detected on the bus |
| 116 | * pPciAgentsNum - Number of pci agents detected on the bus |
| 117 | * |
| 118 | * RETURN: |
| 119 | * MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK |
| 120 | * |
| 121 | *******************************************************************************/ |
| 122 | |
| 123 | MV_STATUS mvPciScan(MV_U32 pciIf, |
| 124 | MV_PCI_DEVICE *pPciAgents, |
| 125 | MV_U32 *pPciAgentsNum) |
| 126 | { |
| 127 | |
| 128 | MV_U32 devIndex,funcIndex=0,busIndex=0,detectedDevNum=0; |
| 129 | MV_U32 localBus=mvPciIfLocalBusNumGet(pciIf); |
| 130 | MV_PCI_DEVICE *pPciDevice; |
| 131 | MV_PCI_DEVICE *pMainDevice; |
| 132 | |
| 133 | DB(mvOsPrintf("mvPciScan: PCI interface num %d\n", pciIf)); |
| 134 | /* Parameter checking */ |
| 135 | if (pciIf >= mvCtrlPexMaxIfGet()) |
| 136 | { |
| 137 | DB(mvOsPrintf("mvPciScan: ERR. Invalid PCI interface num %d\n", pciIf)); |
| 138 | return MV_BAD_PARAM; |
| 139 | } |
| 140 | if (NULL == pPciAgents) |
| 141 | { |
| 142 | DB(mvOsPrintf("mvPciScan: ERR. pPciAgents=NULL \n")); |
| 143 | return MV_BAD_PARAM; |
| 144 | } |
| 145 | if (NULL == pPciAgentsNum) |
| 146 | { |
| 147 | DB(mvOsPrintf("mvPciScan: ERR. pPciAgentsNum=NULL \n")); |
| 148 | return MV_BAD_PARAM; |
| 149 | } |
| 150 | |
| 151 | |
| 152 | DB(mvOsPrintf("mvPciScan: PCI interface num %d mvPciMasterEnable\n", pciIf)); |
| 153 | /* Master enable the MV PCI master */ |
| 154 | if (MV_OK != mvPciIfMasterEnable(pciIf,MV_TRUE)) |
| 155 | { |
| 156 | DB(mvOsPrintf("mvPciScan: ERR. mvPciMasterEnable failed \n")); |
| 157 | return MV_ERROR; |
| 158 | |
| 159 | } |
| 160 | |
| 161 | DB(mvOsPrintf("mvPciScan: PCI interface num scan%d\n", pciIf)); |
| 162 | |
| 163 | /* go through all busses */ |
| 164 | for (busIndex=localBus ; busIndex < MAX_PCI_BUSSES ; busIndex++) |
| 165 | { |
| 166 | /* go through all possible devices on the local bus */ |
| 167 | for (devIndex=0 ; devIndex < MAX_PCI_DEVICES ; devIndex++) |
| 168 | { |
| 169 | /* always start with function equal to zero */ |
| 170 | funcIndex=0; |
| 171 | |
| 172 | pPciDevice=&pPciAgents[detectedDevNum]; |
| 173 | DB(mvOsPrintf("mvPciScan: PCI interface num scan%d:%d\n", busIndex, devIndex)); |
| 174 | |
| 175 | if (MV_ERROR == pciDetectDevice(pciIf, |
| 176 | busIndex, |
| 177 | devIndex, |
| 178 | funcIndex, |
| 179 | pPciDevice)) |
| 180 | { |
| 181 | /* no device detected , try the next address */ |
| 182 | continue; |
| 183 | } |
| 184 | |
| 185 | /* We are here ! means we have detected a device*/ |
| 186 | /* always we start with only one function per device */ |
| 187 | pMainDevice = pPciDevice; |
| 188 | pPciDevice->funtionsNum = 1; |
| 189 | |
| 190 | |
| 191 | /* move on */ |
| 192 | detectedDevNum++; |
| 193 | |
| 194 | |
| 195 | /* check if we have no more room for a new device */ |
| 196 | if (detectedDevNum == *pPciAgentsNum) |
| 197 | { |
| 198 | DB(mvOsPrintf("mvPciScan: ERR. array passed too small \n")); |
| 199 | return MV_ERROR; |
| 200 | } |
| 201 | |
| 202 | /* check the detected device if it is a multi functional device then |
| 203 | scan all device functions*/ |
| 204 | if (pPciDevice->isMultiFunction == MV_TRUE) |
| 205 | { |
| 206 | /* start with function number 1 because we have already detected |
| 207 | function 0 */ |
| 208 | for (funcIndex=1; funcIndex<MAX_PCI_FUNCS ; funcIndex++) |
| 209 | { |
| 210 | pPciDevice=&pPciAgents[detectedDevNum]; |
| 211 | |
| 212 | if (MV_ERROR == pciDetectDevice(pciIf, |
| 213 | busIndex, |
| 214 | devIndex, |
| 215 | funcIndex, |
| 216 | pPciDevice)) |
| 217 | { |
| 218 | /* no device detected means no more functions !*/ |
| 219 | continue; |
| 220 | } |
| 221 | /* We are here ! means we have detected a device */ |
| 222 | |
| 223 | /* move on */ |
| 224 | pMainDevice->funtionsNum++; |
| 225 | detectedDevNum++; |
| 226 | |
| 227 | /* check if we have no more room for a new device */ |
| 228 | if (detectedDevNum == *pPciAgentsNum) |
| 229 | { |
| 230 | DB(mvOsPrintf("mvPciScan: ERR. Array too small\n")); |
| 231 | return MV_ERROR; |
| 232 | } |
| 233 | |
| 234 | |
| 235 | } |
| 236 | } |
| 237 | |
| 238 | } |
| 239 | |
| 240 | } |
| 241 | |
| 242 | /* return the number of devices actually detected on the bus ! */ |
| 243 | *pPciAgentsNum = detectedDevNum; |
| 244 | |
| 245 | return MV_OK; |
| 246 | |
| 247 | } |
| 248 | |
| 249 | |
| 250 | /******************************************************************************* |
| 251 | * pciDetectDevice - Detect a pci device parameters |
| 252 | * |
| 253 | * DESCRIPTION: |
| 254 | * This function detect if a pci agent exist on certain address ! |
| 255 | * and if exists then it fills all possible information on the |
| 256 | * agent |
| 257 | * |
| 258 | * INPUT: |
| 259 | * pciIf - PCI Interface |
| 260 | * bus - Bus number |
| 261 | * dev - Device number |
| 262 | * func - Function number |
| 263 | * |
| 264 | * |
| 265 | * |
| 266 | * OUTPUT: |
| 267 | * pPciAgent - pointer to the pci agent filled with its information |
| 268 | * |
| 269 | * RETURN: |
| 270 | * MV_ERROR if no device , MV_OK otherwise |
| 271 | * |
| 272 | *******************************************************************************/ |
| 273 | |
| 274 | static MV_STATUS pciDetectDevice(MV_U32 pciIf, |
| 275 | MV_U32 bus, |
| 276 | MV_U32 dev, |
| 277 | MV_U32 func, |
| 278 | MV_PCI_DEVICE *pPciAgent) |
| 279 | { |
| 280 | MV_U32 pciData; |
| 281 | |
| 282 | /* no Parameters checking ! because it is static function and it is assumed |
| 283 | that all parameters were checked in the calling function */ |
| 284 | |
| 285 | |
| 286 | /* Try read the PCI Vendor ID and Device ID */ |
| 287 | |
| 288 | /* We will scan only ourselves and the PCI slots that exist on the |
| 289 | board, because we may have a case that we have one slot that has |
| 290 | a Cardbus connector, and because CardBus answers all IDsels we want |
| 291 | to scan only this slot and ourseleves. |
| 292 | |
| 293 | */ |
| 294 | #if defined(MV_INCLUDE_PCI) |
| 295 | if ((PCI_IF_TYPE_CONVEN_PCIX == mvPciIfTypeGet(pciIf)) && |
| 296 | (DB_88F5181_DDR1_PRPMC != mvBoardIdGet()) && |
| 297 | (DB_88F5181_DDR1_PEXPCI != mvBoardIdGet()) && |
| 298 | (DB_88F5181_DDR1_MNG != mvBoardIdGet())) |
| 299 | { |
| 300 | |
| 301 | if (mvBoardIsOurPciSlot(bus, dev) == MV_FALSE) |
| 302 | { |
| 303 | return MV_ERROR; |
| 304 | } |
| 305 | } |
| 306 | #endif /* defined(MV_INCLUDE_PCI) */ |
| 307 | |
| 308 | pciData = mvPciIfConfigRead(pciIf, bus,dev,func, PCI_DEVICE_AND_VENDOR_ID); |
| 309 | |
| 310 | if (PCI_ERROR_CODE == pciData) |
| 311 | { |
| 312 | /* no device exist */ |
| 313 | return MV_ERROR; |
| 314 | } |
| 315 | |
| 316 | /* we are here ! means a device is detected */ |
| 317 | |
| 318 | /* fill basic information */ |
| 319 | pPciAgent->busNumber=bus; |
| 320 | pPciAgent->deviceNum=dev; |
| 321 | pPciAgent->function=func; |
| 322 | |
| 323 | /* Fill the PCI Vendor ID and Device ID */ |
| 324 | |
| 325 | pPciAgent->venID = (pciData & PDVIR_VEN_ID_MASK) >> PDVIR_VEN_ID_OFFS; |
| 326 | pPciAgent->deviceID = (pciData & PDVIR_DEV_ID_MASK) >> PDVIR_DEV_ID_OFFS; |
| 327 | |
| 328 | /* Read Status and command */ |
| 329 | pciData = mvPciIfConfigRead(pciIf, |
| 330 | bus,dev,func, |
| 331 | PCI_STATUS_AND_COMMAND); |
| 332 | |
| 333 | |
| 334 | /* Fill related Status and Command information*/ |
| 335 | |
| 336 | if (pciData & PSCR_TAR_FAST_BB) |
| 337 | { |
| 338 | pPciAgent->isFastB2BCapable = MV_TRUE; |
| 339 | } |
| 340 | else |
| 341 | { |
| 342 | pPciAgent->isFastB2BCapable = MV_FALSE; |
| 343 | } |
| 344 | |
| 345 | if (pciData & PSCR_CAP_LIST) |
| 346 | { |
| 347 | pPciAgent->isCapListSupport=MV_TRUE; |
| 348 | } |
| 349 | else |
| 350 | { |
| 351 | pPciAgent->isCapListSupport=MV_FALSE; |
| 352 | } |
| 353 | |
| 354 | if (pciData & PSCR_66MHZ_EN) |
| 355 | { |
| 356 | pPciAgent->is66MHZCapable=MV_TRUE; |
| 357 | } |
| 358 | else |
| 359 | { |
| 360 | pPciAgent->is66MHZCapable=MV_FALSE; |
| 361 | } |
| 362 | |
| 363 | /* Read Class Code and Revision */ |
| 364 | pciData = mvPciIfConfigRead(pciIf, |
| 365 | bus,dev,func, |
| 366 | PCI_CLASS_CODE_AND_REVISION_ID); |
| 367 | |
| 368 | |
| 369 | pPciAgent->baseClassCode = |
| 370 | (pciData & PCCRIR_BASE_CLASS_MASK) >> PCCRIR_BASE_CLASS_OFFS; |
| 371 | |
| 372 | pPciAgent->subClassCode = |
| 373 | (pciData & PCCRIR_SUB_CLASS_MASK) >> PCCRIR_SUB_CLASS_OFFS; |
| 374 | |
| 375 | pPciAgent->progIf = |
| 376 | (pciData & PCCRIR_PROGIF_MASK) >> PCCRIR_PROGIF_OFFS; |
| 377 | |
| 378 | pPciAgent->revisionID = |
| 379 | (pciData & PCCRIR_REVID_MASK) >> PCCRIR_REVID_OFFS; |
| 380 | |
| 381 | /* Read PCI_BIST_HDR_TYPE_LAT_TMR_CACHE_LINE */ |
| 382 | pciData = mvPciIfConfigRead(pciIf, |
| 383 | bus,dev,func, |
| 384 | PCI_BIST_HDR_TYPE_LAT_TMR_CACHE_LINE); |
| 385 | |
| 386 | |
| 387 | |
| 388 | pPciAgent->pciCacheLine= |
| 389 | (pciData & PBHTLTCLR_CACHELINE_MASK ) >> PBHTLTCLR_CACHELINE_OFFS; |
| 390 | pPciAgent->pciLatencyTimer= |
| 391 | (pciData & PBHTLTCLR_LATTIMER_MASK) >> PBHTLTCLR_LATTIMER_OFFS; |
| 392 | |
| 393 | switch (pciData & PBHTLTCLR_HEADER_MASK) |
| 394 | { |
| 395 | case PBHTLTCLR_HEADER_STANDARD: |
| 396 | |
| 397 | pPciAgent->pciHeader=MV_PCI_STANDARD; |
| 398 | break; |
| 399 | case PBHTLTCLR_HEADER_PCI2PCI_BRIDGE: |
| 400 | |
| 401 | pPciAgent->pciHeader=MV_PCI_PCI2PCI_BRIDGE; |
| 402 | break; |
| 403 | |
| 404 | } |
| 405 | |
| 406 | if (pciData & PBHTLTCLR_MULTI_FUNC) |
| 407 | { |
| 408 | pPciAgent->isMultiFunction=MV_TRUE; |
| 409 | } |
| 410 | else |
| 411 | { |
| 412 | pPciAgent->isMultiFunction=MV_FALSE; |
| 413 | } |
| 414 | |
| 415 | if (pciData & PBHTLTCLR_BISTCAP) |
| 416 | { |
| 417 | pPciAgent->isBISTCapable=MV_TRUE; |
| 418 | } |
| 419 | else |
| 420 | { |
| 421 | pPciAgent->isBISTCapable=MV_FALSE; |
| 422 | } |
| 423 | |
| 424 | |
| 425 | /* read this device pci bars */ |
| 426 | |
| 427 | pciDetectDeviceBars(pciIf, |
| 428 | bus,dev,func, |
| 429 | pPciAgent); |
| 430 | |
| 431 | |
| 432 | /* check if we are bridge*/ |
| 433 | if ((pPciAgent->baseClassCode == PCI_BRIDGE_CLASS)&& |
| 434 | (pPciAgent->subClassCode == P2P_BRIDGE_SUB_CLASS_CODE)) |
| 435 | { |
| 436 | |
| 437 | /* Read P2P_BUSSES_NUM */ |
| 438 | pciData = mvPciIfConfigRead(pciIf, |
| 439 | bus,dev,func, |
| 440 | P2P_BUSSES_NUM); |
| 441 | |
| 442 | pPciAgent->p2pPrimBusNum = |
| 443 | (pciData & PBM_PRIME_BUS_NUM_MASK) >> PBM_PRIME_BUS_NUM_OFFS; |
| 444 | |
| 445 | pPciAgent->p2pSecBusNum = |
| 446 | (pciData & PBM_SEC_BUS_NUM_MASK) >> PBM_SEC_BUS_NUM_OFFS; |
| 447 | |
| 448 | pPciAgent->p2pSubBusNum = |
| 449 | (pciData & PBM_SUB_BUS_NUM_MASK) >> PBM_SUB_BUS_NUM_OFFS; |
| 450 | |
| 451 | pPciAgent->p2pSecLatencyTimer = |
| 452 | (pciData & PBM_SEC_LAT_TMR_MASK) >> PBM_SEC_LAT_TMR_OFFS; |
| 453 | |
| 454 | /* Read P2P_IO_BASE_LIMIT_SEC_STATUS */ |
| 455 | pciData = mvPciIfConfigRead(pciIf, |
| 456 | bus,dev,func, |
| 457 | P2P_IO_BASE_LIMIT_SEC_STATUS); |
| 458 | |
| 459 | pPciAgent->p2pSecStatus = |
| 460 | (pciData & PIBLSS_SEC_STATUS_MASK) >> PIBLSS_SEC_STATUS_OFFS; |
| 461 | |
| 462 | |
| 463 | pPciAgent->p2pIObase = |
| 464 | (pciData & PIBLSS_IO_BASE_MASK) << PIBLSS_IO_LIMIT_OFFS; |
| 465 | |
| 466 | /* clear low address (should be zero)*/ |
| 467 | pPciAgent->p2pIObase &= PIBLSS_HIGH_ADDR_MASK; |
| 468 | |
| 469 | pPciAgent->p2pIOLimit = |
| 470 | (pciData & PIBLSS_IO_LIMIT_MASK); |
| 471 | |
| 472 | /* fill low address with 0xfff */ |
| 473 | pPciAgent->p2pIOLimit |= PIBLSS_LOW_ADDR_MASK; |
| 474 | |
| 475 | |
| 476 | switch ((pciData & PIBLSS_ADD_CAP_MASK) >> PIBLSS_ADD_CAP_OFFS) |
| 477 | { |
| 478 | case PIBLSS_ADD_CAP_16BIT: |
| 479 | |
| 480 | pPciAgent->bIO32 = MV_FALSE; |
| 481 | |
| 482 | break; |
| 483 | case PIBLSS_ADD_CAP_32BIT: |
| 484 | |
| 485 | pPciAgent->bIO32 = MV_TRUE; |
| 486 | |
| 487 | /* Read P2P_IO_BASE_LIMIT_UPPER_16 */ |
| 488 | pciData = mvPciIfConfigRead(pciIf, |
| 489 | bus,dev,func, |
| 490 | P2P_IO_BASE_LIMIT_UPPER_16); |
| 491 | |
| 492 | pPciAgent->p2pIObase |= |
| 493 | (pciData & PRBU_IO_UPP_BASE_MASK) << PRBU_IO_UPP_LIMIT_OFFS; |
| 494 | |
| 495 | |
| 496 | pPciAgent->p2pIOLimit |= |
| 497 | (pciData & PRBU_IO_UPP_LIMIT_MASK); |
| 498 | |
| 499 | break; |
| 500 | |
| 501 | } |
| 502 | |
| 503 | |
| 504 | /* Read P2P_MEM_BASE_LIMIT */ |
| 505 | pciData = mvPciIfConfigRead(pciIf, |
| 506 | bus,dev,func, |
| 507 | P2P_MEM_BASE_LIMIT); |
| 508 | |
| 509 | pPciAgent->p2pMemBase = |
| 510 | (pciData & PMBL_MEM_BASE_MASK) << PMBL_MEM_LIMIT_OFFS; |
| 511 | |
| 512 | /* clear low address */ |
| 513 | pPciAgent->p2pMemBase &= PMBL_HIGH_ADDR_MASK; |
| 514 | |
| 515 | pPciAgent->p2pMemLimit = |
| 516 | (pciData & PMBL_MEM_LIMIT_MASK); |
| 517 | |
| 518 | /* add 0xfffff */ |
| 519 | pPciAgent->p2pMemLimit |= PMBL_LOW_ADDR_MASK; |
| 520 | |
| 521 | |
| 522 | /* Read P2P_PREF_MEM_BASE_LIMIT */ |
| 523 | pciData = mvPciIfConfigRead(pciIf, |
| 524 | bus,dev,func, |
| 525 | P2P_PREF_MEM_BASE_LIMIT); |
| 526 | |
| 527 | |
| 528 | pPciAgent->p2pPrefMemBase = |
| 529 | (pciData & PRMBL_PREF_MEM_BASE_MASK) << PRMBL_PREF_MEM_LIMIT_OFFS; |
| 530 | |
| 531 | /* get high address only */ |
| 532 | pPciAgent->p2pPrefMemBase &= PRMBL_HIGH_ADDR_MASK; |
| 533 | |
| 534 | |
| 535 | |
| 536 | pPciAgent->p2pPrefMemLimit = |
| 537 | (pciData & PRMBL_PREF_MEM_LIMIT_MASK); |
| 538 | |
| 539 | /* add 0xfffff */ |
| 540 | pPciAgent->p2pPrefMemLimit |= PRMBL_LOW_ADDR_MASK; |
| 541 | |
| 542 | switch (pciData & PRMBL_ADD_CAP_MASK) |
| 543 | { |
| 544 | case PRMBL_ADD_CAP_32BIT: |
| 545 | |
| 546 | pPciAgent->bPrefMem64 = MV_FALSE; |
| 547 | |
| 548 | /* Read P2P_PREF_BASE_UPPER_32 */ |
| 549 | pPciAgent->p2pPrefBaseUpper32Bits = 0; |
| 550 | |
| 551 | /* Read P2P_PREF_LIMIT_UPPER_32 */ |
| 552 | pPciAgent->p2pPrefLimitUpper32Bits = 0; |
| 553 | |
| 554 | break; |
| 555 | case PRMBL_ADD_CAP_64BIT: |
| 556 | |
| 557 | pPciAgent->bPrefMem64 = MV_TRUE; |
| 558 | |
| 559 | /* Read P2P_PREF_BASE_UPPER_32 */ |
| 560 | pPciAgent->p2pPrefBaseUpper32Bits = mvPciIfConfigRead(pciIf, |
| 561 | bus,dev,func, |
| 562 | P2P_PREF_BASE_UPPER_32); |
| 563 | |
| 564 | /* Read P2P_PREF_LIMIT_UPPER_32 */ |
| 565 | pPciAgent->p2pPrefLimitUpper32Bits = mvPciIfConfigRead(pciIf, |
| 566 | bus,dev,func, |
| 567 | P2P_PREF_LIMIT_UPPER_32); |
| 568 | |
| 569 | break; |
| 570 | |
| 571 | } |
| 572 | |
| 573 | } |
| 574 | else /* no bridge */ |
| 575 | { |
| 576 | /* Read PCI_SUBSYS_ID_AND_SUBSYS_VENDOR_ID */ |
| 577 | pciData = mvPciIfConfigRead(pciIf, |
| 578 | bus,dev,func, |
| 579 | PCI_SUBSYS_ID_AND_SUBSYS_VENDOR_ID); |
| 580 | |
| 581 | |
| 582 | pPciAgent->subSysVenID = |
| 583 | (pciData & PSISVIR_VENID_MASK) >> PSISVIR_VENID_OFFS; |
| 584 | pPciAgent->subSysID = |
| 585 | (pciData & PSISVIR_DEVID_MASK) >> PSISVIR_DEVID_OFFS; |
| 586 | |
| 587 | |
| 588 | /* Read PCI_EXPANSION_ROM_BASE_ADDR_REG */ |
| 589 | pciData = mvPciIfConfigRead(pciIf, |
| 590 | bus,dev,func, |
| 591 | PCI_EXPANSION_ROM_BASE_ADDR_REG); |
| 592 | |
| 593 | |
| 594 | if (pciData & PERBAR_EXPROMEN) |
| 595 | { |
| 596 | pPciAgent->isExpRom = MV_TRUE; |
| 597 | } |
| 598 | else |
| 599 | { |
| 600 | pPciAgent->isExpRom = MV_FALSE; |
| 601 | } |
| 602 | |
| 603 | pPciAgent->expRomAddr = |
| 604 | (pciData & PERBAR_BASE_MASK) >> PERBAR_BASE_OFFS; |
| 605 | |
| 606 | } |
| 607 | |
| 608 | |
| 609 | if (MV_TRUE == pPciAgent->isCapListSupport) |
| 610 | { |
| 611 | /* Read PCI_CAPABILTY_LIST_POINTER */ |
| 612 | pciData = mvPciIfConfigRead(pciIf, |
| 613 | bus,dev,func, |
| 614 | PCI_CAPABILTY_LIST_POINTER); |
| 615 | |
| 616 | pPciAgent->capListPointer = |
| 617 | (pciData & PCLPR_CAPPTR_MASK) >> PCLPR_CAPPTR_OFFS; |
| 618 | |
| 619 | } |
| 620 | |
| 621 | /* Read PCI_INTERRUPT_PIN_AND_LINE */ |
| 622 | pciData = mvPciIfConfigRead(pciIf, |
| 623 | bus,dev,func, |
| 624 | PCI_INTERRUPT_PIN_AND_LINE); |
| 625 | |
| 626 | |
| 627 | pPciAgent->irqLine= |
| 628 | (pciData & PIPLR_INTLINE_MASK) >> PIPLR_INTLINE_OFFS; |
| 629 | |
| 630 | pPciAgent->intPin= |
| 631 | (MV_PCI_INT_PIN)(pciData & PIPLR_INTPIN_MASK) >> PIPLR_INTPIN_OFFS; |
| 632 | |
| 633 | pPciAgent->minGrant= |
| 634 | (pciData & PIPLR_MINGRANT_MASK) >> PIPLR_MINGRANT_OFFS; |
| 635 | pPciAgent->maxLatency= |
| 636 | (pciData & PIPLR_MAXLATEN_MASK) >> PIPLR_MAXLATEN_OFFS; |
| 637 | |
| 638 | mvPciClassNameGet(pPciAgent->baseClassCode, |
| 639 | (MV_8 *)pPciAgent->type); |
| 640 | |
| 641 | return MV_OK; |
| 642 | |
| 643 | |
| 644 | } |
| 645 | |
| 646 | /******************************************************************************* |
| 647 | * pciDetectDeviceBars - Detect a pci device bars |
| 648 | * |
| 649 | * DESCRIPTION: |
| 650 | * This function detects all pci agent bars |
| 651 | * |
| 652 | * INPUT: |
| 653 | * pciIf - PCI Interface |
| 654 | * bus - Bus number |
| 655 | * dev - Device number |
| 656 | * func - Function number |
| 657 | * |
| 658 | * |
| 659 | * |
| 660 | * OUTPUT: |
| 661 | * pPciAgent - pointer to the pci agent filled with its information |
| 662 | * |
| 663 | * RETURN: |
| 664 | * detected bars number |
| 665 | * |
| 666 | *******************************************************************************/ |
| 667 | static MV_U32 pciDetectDeviceBars(MV_U32 pciIf, |
| 668 | MV_U32 bus, |
| 669 | MV_U32 dev, |
| 670 | MV_U32 func, |
| 671 | MV_PCI_DEVICE *pPciAgent) |
| 672 | { |
| 673 | MV_U32 pciData,barIndex,detectedBar=0; |
| 674 | MV_U32 tmpBaseHigh=0,tmpBaseLow=0; |
| 675 | MV_U32 pciMaxBars=0; |
| 676 | |
| 677 | pPciAgent->barsNum=0; |
| 678 | |
| 679 | /* check if we are bridge*/ |
| 680 | if ((pPciAgent->baseClassCode == PCI_BRIDGE_CLASS)&& |
| 681 | (pPciAgent->subClassCode == P2P_BRIDGE_SUB_CLASS_CODE)) |
| 682 | { |
| 683 | pciMaxBars = 2; |
| 684 | } |
| 685 | else /* no bridge */ |
| 686 | { |
| 687 | pciMaxBars = 6; |
| 688 | } |
| 689 | |
| 690 | /* read this device pci bars */ |
| 691 | for (barIndex = 0 ; barIndex < pciMaxBars ; barIndex++ ) |
| 692 | { |
| 693 | /* Read PCI_MEMORY_BAR_BASE_ADDR */ |
| 694 | tmpBaseLow = pciData = mvPciIfConfigRead(pciIf, |
| 695 | bus,dev,func, |
| 696 | PCI_MEMORY_BAR_BASE_ADDR(barIndex)); |
| 697 | |
| 698 | pPciAgent->pciBar[detectedBar].barOffset = |
| 699 | PCI_MEMORY_BAR_BASE_ADDR(barIndex); |
| 700 | |
| 701 | /* check if the bar is 32bit or 64bit bar */ |
| 702 | switch (pciData & PBBLR_TYPE_MASK) |
| 703 | { |
| 704 | case PBBLR_TYPE_32BIT_ADDR: |
| 705 | pPciAgent->pciBar[detectedBar].barType = PCI_32BIT_BAR; |
| 706 | break; |
| 707 | case PBBLR_TYPE_64BIT_ADDR: |
| 708 | pPciAgent->pciBar[detectedBar].barType = PCI_64BIT_BAR; |
| 709 | break; |
| 710 | |
| 711 | } |
| 712 | |
| 713 | /* check if it is memory or IO bar */ |
| 714 | if (pciData & PBBLR_IOSPACE) |
| 715 | { |
| 716 | pPciAgent->pciBar[detectedBar].barMapping=PCI_IO_BAR; |
| 717 | } |
| 718 | else |
| 719 | { |
| 720 | pPciAgent->pciBar[detectedBar].barMapping=PCI_MEMORY_BAR; |
| 721 | } |
| 722 | |
| 723 | /* if it is memory bar then check if it is prefetchable */ |
| 724 | if (PCI_MEMORY_BAR == pPciAgent->pciBar[detectedBar].barMapping) |
| 725 | { |
| 726 | if (pciData & PBBLR_PREFETCH_EN) |
| 727 | { |
| 728 | pPciAgent->pciBar[detectedBar].isPrefetchable = MV_TRUE; |
| 729 | } |
| 730 | else |
| 731 | { |
| 732 | pPciAgent->pciBar[detectedBar].isPrefetchable = MV_FALSE; |
| 733 | } |
| 734 | |
| 735 | pPciAgent->pciBar[detectedBar].barBaseLow = |
| 736 | pciData & PBBLR_MEM_BASE_MASK; |
| 737 | |
| 738 | |
| 739 | } |
| 740 | else /* IO Bar */ |
| 741 | { |
| 742 | pPciAgent->pciBar[detectedBar].barBaseLow = |
| 743 | pciData & PBBLR_IO_BASE_MASK; |
| 744 | |
| 745 | } |
| 746 | |
| 747 | pPciAgent->pciBar[detectedBar].barBaseHigh=0; |
| 748 | |
| 749 | if (PCI_64BIT_BAR == pPciAgent->pciBar[detectedBar].barType) |
| 750 | { |
| 751 | barIndex++; |
| 752 | |
| 753 | tmpBaseHigh = pPciAgent->pciBar[detectedBar].barBaseHigh = |
| 754 | mvPciIfConfigRead(pciIf, |
| 755 | bus,dev,func, |
| 756 | PCI_MEMORY_BAR_BASE_ADDR(barIndex)); |
| 757 | |
| 758 | |
| 759 | } |
| 760 | |
| 761 | /* calculating full base address (64bit) */ |
| 762 | pPciAgent->pciBar[detectedBar].barBaseAddr = |
| 763 | (MV_U64)pPciAgent->pciBar[detectedBar].barBaseHigh; |
| 764 | |
| 765 | pPciAgent->pciBar[detectedBar].barBaseAddr <<= 32; |
| 766 | |
| 767 | pPciAgent->pciBar[detectedBar].barBaseAddr |= |
| 768 | (MV_U64)pPciAgent->pciBar[detectedBar].barBaseLow; |
| 769 | |
| 770 | |
| 771 | |
| 772 | /* get the sizes of the the bar */ |
| 773 | |
| 774 | pPciAgent->pciBar[detectedBar].barSizeHigh=0; |
| 775 | |
| 776 | if ((PCI_64BIT_BAR == pPciAgent->pciBar[detectedBar].barType) && |
| 777 | (PCI_MEMORY_BAR == pPciAgent->pciBar[detectedBar].barMapping)) |
| 778 | |
| 779 | { |
| 780 | /* write oxffffffff to the bar to get the size */ |
| 781 | /* start with sizelow ( original value was saved in tmpBaseLow ) */ |
| 782 | mvPciIfConfigWrite(pciIf, |
| 783 | bus,dev,func, |
| 784 | PCI_MEMORY_BAR_BASE_ADDR(barIndex-1), |
| 785 | 0xffffffff); |
| 786 | |
| 787 | /* read size */ |
| 788 | pPciAgent->pciBar[detectedBar].barSizeLow = |
| 789 | mvPciIfConfigRead(pciIf, |
| 790 | bus,dev,func, |
| 791 | PCI_MEMORY_BAR_BASE_ADDR(barIndex-1)); |
| 792 | |
| 793 | |
| 794 | |
| 795 | /* restore original value */ |
| 796 | mvPciIfConfigWrite(pciIf, |
| 797 | bus,dev,func, |
| 798 | PCI_MEMORY_BAR_BASE_ADDR(barIndex-1), |
| 799 | tmpBaseLow); |
| 800 | |
| 801 | |
| 802 | /* now do the same for BaseHigh */ |
| 803 | |
| 804 | /* write oxffffffff to the bar to get the size */ |
| 805 | mvPciIfConfigWrite(pciIf, |
| 806 | bus,dev,func, |
| 807 | PCI_MEMORY_BAR_BASE_ADDR(barIndex), |
| 808 | 0xffffffff); |
| 809 | |
| 810 | /* read size */ |
| 811 | pPciAgent->pciBar[detectedBar].barSizeHigh = |
| 812 | mvPciIfConfigRead(pciIf, |
| 813 | bus,dev,func, |
| 814 | PCI_MEMORY_BAR_BASE_ADDR(barIndex)); |
| 815 | |
| 816 | /* restore original value */ |
| 817 | mvPciIfConfigWrite(pciIf, |
| 818 | bus,dev,func, |
| 819 | PCI_MEMORY_BAR_BASE_ADDR(barIndex), |
| 820 | tmpBaseHigh); |
| 821 | |
| 822 | if ((0 == pPciAgent->pciBar[detectedBar].barSizeLow)&& |
| 823 | (0 == pPciAgent->pciBar[detectedBar].barSizeHigh)) |
| 824 | { |
| 825 | /* this bar is not applicable for this device, |
| 826 | ignore all previous settings and check the next bar*/ |
| 827 | |
| 828 | /* we though this was a 64bit bar , and it seems this |
| 829 | was wrong ! so decrement barIndex */ |
| 830 | barIndex--; |
| 831 | continue; |
| 832 | } |
| 833 | |
| 834 | /* calculate the full 64 bit size */ |
| 835 | |
| 836 | if (0 != pPciAgent->pciBar[detectedBar].barSizeHigh) |
| 837 | { |
| 838 | pPciAgent->pciBar[detectedBar].barSizeLow &= PBBLR_MEM_BASE_MASK; |
| 839 | |
| 840 | pPciAgent->pciBar[detectedBar].barSizeLow = |
| 841 | ~pPciAgent->pciBar[detectedBar].barSizeLow + 1; |
| 842 | |
| 843 | pPciAgent->pciBar[detectedBar].barSizeHigh = 0; |
| 844 | |
| 845 | } |
| 846 | else |
| 847 | { |
| 848 | |
| 849 | pPciAgent->pciBar[detectedBar].barSizeLow &= PBBLR_MEM_BASE_MASK; |
| 850 | |
| 851 | pPciAgent->pciBar[detectedBar].barSizeLow = |
| 852 | ~pPciAgent->pciBar[detectedBar].barSizeLow + 1; |
| 853 | |
| 854 | pPciAgent->pciBar[detectedBar].barSizeHigh = 0; |
| 855 | |
| 856 | } |
| 857 | |
| 858 | |
| 859 | |
| 860 | } |
| 861 | else /* 32bit bar */ |
| 862 | { |
| 863 | /* write oxffffffff to the bar to get the size */ |
| 864 | mvPciIfConfigWrite(pciIf, |
| 865 | bus,dev,func, |
| 866 | PCI_MEMORY_BAR_BASE_ADDR(barIndex), |
| 867 | 0xffffffff); |
| 868 | |
| 869 | /* read size */ |
| 870 | pPciAgent->pciBar[detectedBar].barSizeLow = |
| 871 | mvPciIfConfigRead(pciIf, |
| 872 | bus,dev,func, |
| 873 | PCI_MEMORY_BAR_BASE_ADDR(barIndex)); |
| 874 | |
| 875 | if (0 == pPciAgent->pciBar[detectedBar].barSizeLow) |
| 876 | { |
| 877 | /* this bar is not applicable for this device, |
| 878 | ignore all previous settings and check the next bar*/ |
| 879 | continue; |
| 880 | } |
| 881 | |
| 882 | |
| 883 | /* restore original value */ |
| 884 | mvPciIfConfigWrite(pciIf, |
| 885 | bus,dev,func, |
| 886 | PCI_MEMORY_BAR_BASE_ADDR(barIndex), |
| 887 | tmpBaseLow); |
| 888 | |
| 889 | /* calculate size low */ |
| 890 | |
| 891 | if (PCI_MEMORY_BAR == pPciAgent->pciBar[detectedBar].barMapping) |
| 892 | { |
| 893 | pPciAgent->pciBar[detectedBar].barSizeLow &= PBBLR_MEM_BASE_MASK; |
| 894 | } |
| 895 | else |
| 896 | { |
| 897 | pPciAgent->pciBar[detectedBar].barSizeLow &= PBBLR_IO_BASE_MASK; |
| 898 | } |
| 899 | |
| 900 | pPciAgent->pciBar[detectedBar].barSizeLow = |
| 901 | ~pPciAgent->pciBar[detectedBar].barSizeLow + 1; |
| 902 | |
| 903 | pPciAgent->pciBar[detectedBar].barSizeHigh = 0; |
| 904 | pPciAgent->pciBar[detectedBar].barSize = |
| 905 | (MV_U64)pPciAgent->pciBar[detectedBar].barSizeLow; |
| 906 | |
| 907 | |
| 908 | } |
| 909 | |
| 910 | /* we are here ! this means we have already detected a bar for |
| 911 | this device , now move on */ |
| 912 | |
| 913 | detectedBar++; |
| 914 | pPciAgent->barsNum++; |
| 915 | } |
| 916 | |
| 917 | return detectedBar; |
| 918 | } |
| 919 | |
| 920 | |
| 921 | /******************************************************************************* |
| 922 | * mvPciClassNameGet - get PCI class name |
| 923 | * |
| 924 | * DESCRIPTION: |
| 925 | * This function returns the PCI class name |
| 926 | * |
| 927 | * INPUT: |
| 928 | * baseClassCode - Base Class Code. |
| 929 | * |
| 930 | * OUTPUT: |
| 931 | * pType - the class name |
| 932 | * |
| 933 | * RETURN: |
| 934 | * MV_BAD_PARAM for bad parameters ,MV_ERROR on error ! otherwise MV_OK |
| 935 | * |
| 936 | *******************************************************************************/ |
| 937 | MV_STATUS mvPciClassNameGet(MV_U32 baseClassCode, MV_8 *pType) |
| 938 | { |
| 939 | |
| 940 | switch(baseClassCode) |
| 941 | { |
| 942 | case 0x0: |
| 943 | strcpy(pType,"Old generation device"); |
| 944 | break; |
| 945 | case 0x1: |
| 946 | strcpy(pType,"Mass storage controller"); |
| 947 | break; |
| 948 | case 0x2: |
| 949 | strcpy(pType,"Network controller"); |
| 950 | break; |
| 951 | case 0x3: |
| 952 | strcpy(pType,"Display controller"); |
| 953 | break; |
| 954 | case 0x4: |
| 955 | strcpy(pType,"Multimedia device"); |
| 956 | break; |
| 957 | case 0x5: |
| 958 | strcpy(pType,"Memory controller"); |
| 959 | break; |
| 960 | case 0x6: |
| 961 | strcpy(pType,"Bridge Device"); |
| 962 | break; |
| 963 | case 0x7: |
| 964 | strcpy(pType,"Simple Communication controllers"); |
| 965 | break; |
| 966 | case 0x8: |
| 967 | strcpy(pType,"Base system peripherals"); |
| 968 | break; |
| 969 | case 0x9: |
| 970 | strcpy(pType,"Input Devices"); |
| 971 | break; |
| 972 | case 0xa: |
| 973 | strcpy(pType,"Docking stations"); |
| 974 | break; |
| 975 | case 0xb: |
| 976 | strcpy(pType,"Processors"); |
| 977 | break; |
| 978 | case 0xc: |
| 979 | strcpy(pType,"Serial bus controllers"); |
| 980 | break; |
| 981 | case 0xd: |
| 982 | strcpy(pType,"Wireless controllers"); |
| 983 | break; |
| 984 | case 0xe: |
| 985 | strcpy(pType,"Intelligent I/O controllers"); |
| 986 | break; |
| 987 | case 0xf: |
| 988 | strcpy(pType,"Satellite communication controllers"); |
| 989 | break; |
| 990 | case 0x10: |
| 991 | strcpy(pType,"Encryption/Decryption controllers"); |
| 992 | break; |
| 993 | case 0x11: |
| 994 | strcpy(pType,"Data acquisition and signal processing controllers"); |
| 995 | break; |
| 996 | default: |
| 997 | strcpy(pType,"Unknown device"); |
| 998 | break; |
| 999 | } |
| 1000 | |
| 1001 | return MV_OK; |
| 1002 | |
| 1003 | } |
| 1004 | |
| 1005 | |
| 1006 | |
| 1007 | |