[MLX4] add VPD data to bus interface. [mlnx: 4456]
[mirror/winof/.git] / hw / mlx4 / kernel / bus / drv / pci.c
index 9c319ce..65d9267 100644 (file)
@@ -331,18 +331,18 @@ __save_msix_info(
        u64 bar;\r
        int n_supported;\r
        PHYSICAL_ADDRESS pa;\r
-       ULONG capOffset, bir;\r
+       ULONG cap_offset, bir;\r
        PPCI_MSIX_CAPABILITY pPciMsixCap;\r
 \r
        MLX4_ENTER( MLX4_DBG_PNP );\r
 \r
        /* find capability */\r
-       capOffset = __find_capability( p_cfg, PCI_CAPABILITY_ID_MSIX );\r
-       if( !capOffset ) {\r
+       cap_offset = __find_capability( p_cfg, PCI_CAPABILITY_ID_MSIX );\r
+       if( !cap_offset ) {\r
                p_info->valid = 0;\r
                return 0;\r
        }       \r
-       pPciMsixCap = (PPCI_MSIX_CAPABILITY)(((UCHAR*)p_cfg) + capOffset);\r
+       pPciMsixCap = (PPCI_MSIX_CAPABILITY)(((UCHAR*)p_cfg) + cap_offset);\r
        n_supported = MSIX_FLAGS_SUPPORTED(pPciMsixCap->Flags) + 1;\r
        p_info->num = n_supported;\r
 \r
@@ -428,15 +428,150 @@ pci_free_msix_info_resources(
        memset(pMsixInfo,0,sizeof(struct msix_saved_info));\r
 }\r
 \r
+static NTSTATUS __read_vpd_dword(\r
+       IN                              BUS_INTERFACE_STANDARD          *pBusIfc,\r
+       IN                              ULONG                                           cap_offset,\r
+       IN                              ULONG                                           offset,\r
+               OUT                     UCHAR                                           *p_data\r
+       )\r
+{\r
+       ULONG len;\r
+       USHORT addr = (USHORT)offset;\r
+\r
+       /* write offset inside VPD data */\r
+       len = pBusIfc->SetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &addr, cap_offset+2,2 );\r
+       if ( len != 2 ) \r
+               goto err_write;\r
+\r
+       /* wait for data to be put in the data register */\r
+       while ( !(addr & 0x8000) ) {\r
+               len = pBusIfc->GetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &addr, cap_offset+2, 2 );\r
+               if ( len != 2 )\r
+                       goto err_read;\r
+       } \r
+\r
+       /* get the tag value */\r
+       len = pBusIfc->GetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG, p_data, cap_offset+4, 4 );\r
+       if ( len != 4 )\r
+               goto err_read;\r
+\r
+       return STATUS_SUCCESS;\r
+       \r
+err_write:\r
+       MLX4_PRINT( TRACE_LEVEL_ERROR  , MLX4_DBG_PNP  , \r
+               ("Failed to write HCA config. \n" )); \r
+       return STATUS_DEVICE_NOT_READY;\r
+\r
+err_read:      \r
+       MLX4_PRINT( TRACE_LEVEL_ERROR  , MLX4_DBG_PNP  , \r
+               ("Failed to read HCA config. \n" )); \r
+       return STATUS_DEVICE_NOT_READY;\r
+}\r
+\r
+\r
+#define MAX_VPD_SIZE   (1 << 16)\r
+\r
+NTSTATUS pci_get_vpd(\r
+       IN                              BUS_INTERFACE_STANDARD          *pBusIfc,\r
+       IN                              PCI_COMMON_CONFIG* const        pConfig,\r
+               OUT                     UCHAR*                                          *p_vpd,\r
+       IN      OUT                     int*                                            p_vpd_size\r
+       )\r
+{\r
+       PCI_VPD_CAPABILITY              *pPciVpdCap;\r
+       ULONG                                   cap_offset;\r
+       NTSTATUS                                status = STATUS_SUCCESS;\r
+       int                                             vpd_size = 0;\r
+       UCHAR                                   *vpd = NULL;\r
+\r
+       *p_vpd = NULL;\r
+       *p_vpd_size = 0;\r
+\r
+       cap_offset = __find_capability( pConfig, PCI_CAPABILITY_ID_VPD );\r
+       if( cap_offset ) {\r
+               ULONG offset;\r
+               pPciVpdCap = (PCI_VPD_CAPABILITY*)(((UCHAR*)pConfig) + cap_offset);\r
+\r
+               /* allocate temp buffer */\r
+               vpd = kmalloc( MAX_VPD_SIZE, GFP_KERNEL);\r
+               if ( !vpd ) {\r
+                       MLX4_PRINT( TRACE_LEVEL_ERROR  , MLX4_DBG_PNP  ,\r
+                               ("Failed to allocate VPD buffer of size %d.\n", MAX_VPD_SIZE));\r
+                       return STATUS_UNSUCCESSFUL;\r
+               }\r
+               \r
+               /* read VPD */\r
+               for ( offset = 0; offset < MAX_VPD_SIZE; offset += 0x4 ) {\r
+                       status = __read_vpd_dword( pBusIfc, cap_offset,\r
+                               offset, vpd + offset);\r
+                       if( !NT_SUCCESS( status ) ) {\r
+                               kfree( vpd );\r
+                               return STATUS_UNSUCCESSFUL;\r
+                       }\r
+               }\r
+               /* find the size */\r
+               for ( offset = 0; offset < MAX_VPD_SIZE; ) {\r
+                       ULONG size;\r
+                       if ( vpd[offset] == 0x78 ) {\r
+                               vpd_size = offset + 1;\r
+                               break;\r
+                       }\r
+                       if ( vpd[offset] & 0x80 ) { /* Large Resource Type */ \r
+                               size = *(PUSHORT)(&vpd[offset+1]);\r
+                               offset += size + 3;     \r
+                       }\r
+                       else {  /* Small Resource Type */\r
+                               size = vpd[offset] & 7;\r
+                               offset += size + 1;     \r
+                       }\r
+               }\r
+               /* shorten the VPD array */\r
+               if ( offset >= MAX_VPD_SIZE ) {\r
+                       /* we didn't found VPD end. We'll keep it all */\r
+                       *p_vpd = vpd;\r
+                       *p_vpd_size = MAX_VPD_SIZE;\r
+               }\r
+               else {\r
+                       /* allocate VPD */\r
+                       if ( vpd_size ) {\r
+                               *p_vpd = kmalloc( vpd_size, GFP_KERNEL);\r
+                               if ( !*p_vpd ) {\r
+                                       *p_vpd = vpd;\r
+                                       *p_vpd_size = MAX_VPD_SIZE;\r
+                               }\r
+                               else {\r
+                                       memcpy( *p_vpd, vpd, vpd_size );\r
+                                       *p_vpd_size = vpd_size;\r
+                                       kfree( vpd );\r
+                               }\r
+                       }\r
+                       else {\r
+                               MLX4_PRINT( TRACE_LEVEL_ERROR  , MLX4_DBG_PNP  ,\r
+                                       ("VPD starts from end tag.\n"));\r
+                               kfree( vpd );\r
+                               status = STATUS_UNSUCCESSFUL;\r
+                       }\r
+               }\r
+               MLX4_PRINT( TRACE_LEVEL_WARNING  , MLX4_DBG_PNP  ,\r
+                       ("Found VPD of size %d, beginning with '%s'\n", *p_vpd_size, &vpd[3]));\r
+       }\r
+       else {\r
+               MLX4_PRINT( TRACE_LEVEL_ERROR  , MLX4_DBG_PNP  ,("Failed to find VPD capability.\n"));\r
+               status = STATUS_UNSUCCESSFUL;\r
+       }\r
+\r
+       return status;\r
+}\r
+\r
 /*\r
  * Reads and saves the PCI configuration of the device accessible\r
  * through the provided bus interface.  Does not read registers 22 or 23\r
- * as directed in PRM , Appendix A. Software Reset.\r
+ * as directed in Tavor PRM 1.0.1, Appendix A. InfiniHost Software Reset.\r
  */\r
 NTSTATUS\r
 pci_save_config(\r
        IN                              BUS_INTERFACE_STANDARD          *pBusIfc,\r
-               OUT                     PCI_COMMON_CONFIG* const        pConfig)\r
+               OUT                     PCI_COMMON_CONFIG* const        pConfig )\r
 {\r
        ULONG                                   len;\r
        UINT32                                  *pBuf;\r
@@ -480,7 +615,7 @@ pci_get_msi_info(
                OUT                     PCI_COMMON_CONFIG *             p_cfg,\r
                OUT                     uplink_info_t *                 p_uplink_info )\r
 {\r
-       ULONG                                   capOffset;\r
+       ULONG                                   cap_offset;\r
        NTSTATUS                                status;\r
        BUS_INTERFACE_STANDARD  *pBusIfc = &pdev->bus_pci_ifc;\r
 \r
@@ -495,15 +630,15 @@ pci_get_msi_info(
 \r
        // PCI MSI-X Capability\r
        memset( &p_uplink_info->x, 0, sizeof(p_uplink_info->x) );\r
-       capOffset = __find_capability( p_cfg, PCI_CAPABILITY_ID_MSIX );\r
-       if( capOffset ) {\r
+       cap_offset = __find_capability( p_cfg, PCI_CAPABILITY_ID_MSIX );\r
+       if( cap_offset ) {\r
                PVOID ka;\r
                ULONG sz;\r
                PHYSICAL_ADDRESS pa;\r
                PPCI_MSIX_VECTOR p_vector;\r
                PPCI_MSIX_PENDING p_pend;\r
                ULONG granted_mask = 0;\r
-               PPCI_MSIX_CAPABILITY pPciMsixCap = (PPCI_MSIX_CAPABILITY)(((UCHAR*)p_cfg) + capOffset);\r
+               PPCI_MSIX_CAPABILITY pPciMsixCap = (PPCI_MSIX_CAPABILITY)(((UCHAR*)p_cfg) + cap_offset);\r
                USHORT flags = pPciMsixCap->Flags;\r
                ULONG table_bir = MSIX_OFFSET_BIR(pPciMsixCap->Table_Offset);\r
                ULONG pend_bir = MSIX_OFFSET_BIR(pPciMsixCap->PBA_Offset);\r
@@ -732,16 +867,16 @@ pci_get_uplink_info(
        IN                              PCI_COMMON_CONFIG *             p_cfg,\r
        OUT                             uplink_info_t *                 p_uplink_info )\r
 {\r
-       ULONG                                   capOffset;\r
+       ULONG                                   cap_offset;\r
        PCI_PCIX_CAPABILITY             *pPciXCap;\r
        PCI_PCIEXP_CAPABILITY   *pPciExpCap;\r
 \r
        MLX4_ENTER( MLX4_DBG_PNP );\r
 \r
        // PCIX Capability\r
-       capOffset = __find_capability( p_cfg, PCI_CAPABILITY_ID_PCIX );\r
-       if( capOffset ) {\r
-               pPciXCap = (PCI_PCIX_CAPABILITY*)(((UCHAR*)p_cfg) + capOffset);\r
+       cap_offset = __find_capability( p_cfg, PCI_CAPABILITY_ID_PCIX );\r
+       if( cap_offset ) {\r
+               pPciXCap = (PCI_PCIX_CAPABILITY*)(((UCHAR*)p_cfg) + cap_offset);\r
 \r
                p_uplink_info->bus_type = UPLINK_BUS_PCIX;\r
                if (pPciXCap->Status & (1 << 17))\r
@@ -750,9 +885,9 @@ pci_get_uplink_info(
        }\r
 \r
        // PCI Express Capability\r
-       capOffset = __find_capability( p_cfg, PCI_CAPABILITY_ID_PCI_EXPRESS );\r
-       if( capOffset ) {\r
-               pPciExpCap = (PCI_PCIEXP_CAPABILITY*)(((UCHAR*)p_cfg) + capOffset);\r
+       cap_offset = __find_capability( p_cfg, PCI_CAPABILITY_ID_PCI_EXPRESS );\r
+       if( cap_offset ) {\r
+               pPciExpCap = (PCI_PCIEXP_CAPABILITY*)(((UCHAR*)p_cfg) + cap_offset);\r
 \r
                p_uplink_info->bus_type = UPLINK_BUS_PCIE;\r
                if ((pPciExpCap->LinkStatus & 15) == 1)\r