[MLX4] add VPD data to bus interface. [mlnx: 4456]
authorleonidk <leonidk@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Sun, 14 Jun 2009 09:49:18 +0000 (09:49 +0000)
committerleonidk <leonidk@ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86>
Sun, 14 Jun 2009 09:49:18 +0000 (09:49 +0000)
git-svn-id: svn://openib.tc.cornell.edu/gen1/trunk@2255 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86

hw/mlx4/kernel/bus/drv/drv.c
hw/mlx4/kernel/bus/drv/drv.h
hw/mlx4/kernel/bus/drv/pci.c
hw/mlx4/kernel/inc/l2w.h

index 70b46ba..568685b 100644 (file)
@@ -437,7 +437,9 @@ EvtDeviceD0Entry(
 \r
        // start card (needed after Hibernetion)\r
        if (PreviousState > WdfPowerDeviceD0)\r
-               __start_card( Device, p_fdo );\r
+               status = __start_card( Device, p_fdo );\r
+       if ( !NT_SUCCESS( status ) ) \r
+               goto err;\r
        mdev = pdev->dev;\r
 \r
        // create child device\r
@@ -746,6 +748,7 @@ EvtPrepareHardware(
 {\r
        NTSTATUS status;\r
        PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
+       struct pci_dev *pdev = &p_fdo->pci_dev;\r
 \r
        MLX4_ENTER(MLX4_DBG_DRV);\r
 \r
@@ -758,6 +761,19 @@ EvtPrepareHardware(
 \r
        // start the card\r
        status = __start_card(Device, p_fdo );\r
+\r
+       // get VPD \r
+       \r
+       if( NT_SUCCESS( status ) ) {\r
+               status = pci_get_vpd( &pdev->bus_pci_ifc, \r
+                       &pdev->pci_cfg_space, &pdev->vpd, &pdev->vpd_size );\r
+               if( !NT_SUCCESS( status ) )\r
+               {\r
+                       MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, \r
+                               ("pci_get_vpd failed,  status=0x%x\n", status));\r
+                       goto err;\r
+               }\r
+       }\r
        \r
 err:\r
        MLX4_EXIT( MLX4_DBG_DRV );\r
@@ -781,11 +797,17 @@ EvtReleaseHardware(
        )\r
 {\r
        PFDO_DEVICE_DATA p_fdo  = FdoGetData(Device);\r
+       struct pci_dev *pdev = &p_fdo->pci_dev;\r
 \r
        UNUSED_PARAM(ResourcesTranslated);\r
 \r
        MLX4_ENTER(MLX4_DBG_DRV);\r
 \r
+       if ( pdev->vpd ) {\r
+               kfree( pdev->vpd );\r
+               pdev->vpd = NULL;\r
+               pdev->vpd_size = 0;\r
+       }\r
        __stop_card( p_fdo );\r
        __put_resources( p_fdo );\r
 \r
index f2f32f6..3a425cc 100644 (file)
@@ -201,6 +201,13 @@ pci_save_config(
                OUT                     PCI_COMMON_CONFIG* const        pConfig\r
        );\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
 NTSTATUS\r
 pci_hca_reset( \r
        IN              struct pci_dev *pdev\r
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
index de2222e..b1c2e40 100644 (file)
@@ -180,6 +180,8 @@ struct pci_dev
        // mlx4_net: various objects and info   
        struct mlx4_dev *                               dev;
        volatile long                                   dpc_lock;
+       PUCHAR                                                  vpd;
+       int                                                             vpd_size;
 #ifdef USE_WDM_INTERRUPTS
        PKINTERRUPT                                             int_obj;                /* HCA interrupt object */
        KSPIN_LOCK                                              isr_lock;               /* lock for the ISR */