From 16438af0e7fc9ca98cbcf98012f002dfe9f138b8 Mon Sep 17 00:00:00 2001 From: leonidk Date: Sun, 14 Jun 2009 09:49:18 +0000 Subject: [PATCH] [MLX4] add VPD data to bus interface. [mlnx: 4456] git-svn-id: svn://openib.tc.cornell.edu/gen1@2255 ad392aa1-c5ef-ae45-8dd8-e69d62a5ef86 --- trunk/hw/mlx4/kernel/bus/drv/drv.c | 24 +++- trunk/hw/mlx4/kernel/bus/drv/drv.h | 7 ++ trunk/hw/mlx4/kernel/bus/drv/pci.c | 169 ++++++++++++++++++++++++++--- trunk/hw/mlx4/kernel/inc/l2w.h | 2 + 4 files changed, 184 insertions(+), 18 deletions(-) diff --git a/trunk/hw/mlx4/kernel/bus/drv/drv.c b/trunk/hw/mlx4/kernel/bus/drv/drv.c index 70b46ba5..568685b9 100644 --- a/trunk/hw/mlx4/kernel/bus/drv/drv.c +++ b/trunk/hw/mlx4/kernel/bus/drv/drv.c @@ -437,7 +437,9 @@ EvtDeviceD0Entry( // start card (needed after Hibernetion) if (PreviousState > WdfPowerDeviceD0) - __start_card( Device, p_fdo ); + status = __start_card( Device, p_fdo ); + if ( !NT_SUCCESS( status ) ) + goto err; mdev = pdev->dev; // create child device @@ -746,6 +748,7 @@ EvtPrepareHardware( { NTSTATUS status; PFDO_DEVICE_DATA p_fdo = FdoGetData(Device); + struct pci_dev *pdev = &p_fdo->pci_dev; MLX4_ENTER(MLX4_DBG_DRV); @@ -758,6 +761,19 @@ EvtPrepareHardware( // start the card status = __start_card(Device, p_fdo ); + + // get VPD + + if( NT_SUCCESS( status ) ) { + status = pci_get_vpd( &pdev->bus_pci_ifc, + &pdev->pci_cfg_space, &pdev->vpd, &pdev->vpd_size ); + if( !NT_SUCCESS( status ) ) + { + MLX4_PRINT(TRACE_LEVEL_ERROR, MLX4_DBG_DRV, + ("pci_get_vpd failed, status=0x%x\n", status)); + goto err; + } + } err: MLX4_EXIT( MLX4_DBG_DRV ); @@ -781,11 +797,17 @@ EvtReleaseHardware( ) { PFDO_DEVICE_DATA p_fdo = FdoGetData(Device); + struct pci_dev *pdev = &p_fdo->pci_dev; UNUSED_PARAM(ResourcesTranslated); MLX4_ENTER(MLX4_DBG_DRV); + if ( pdev->vpd ) { + kfree( pdev->vpd ); + pdev->vpd = NULL; + pdev->vpd_size = 0; + } __stop_card( p_fdo ); __put_resources( p_fdo ); diff --git a/trunk/hw/mlx4/kernel/bus/drv/drv.h b/trunk/hw/mlx4/kernel/bus/drv/drv.h index f2f32f60..3a425ccf 100644 --- a/trunk/hw/mlx4/kernel/bus/drv/drv.h +++ b/trunk/hw/mlx4/kernel/bus/drv/drv.h @@ -201,6 +201,13 @@ pci_save_config( OUT PCI_COMMON_CONFIG* const pConfig ); +NTSTATUS pci_get_vpd( + IN BUS_INTERFACE_STANDARD *pBusIfc, + IN PCI_COMMON_CONFIG* const pConfig, + OUT UCHAR* *p_vpd, + IN OUT int* p_vpd_size + ); + NTSTATUS pci_hca_reset( IN struct pci_dev *pdev diff --git a/trunk/hw/mlx4/kernel/bus/drv/pci.c b/trunk/hw/mlx4/kernel/bus/drv/pci.c index 9c319ce0..65d92677 100644 --- a/trunk/hw/mlx4/kernel/bus/drv/pci.c +++ b/trunk/hw/mlx4/kernel/bus/drv/pci.c @@ -331,18 +331,18 @@ __save_msix_info( u64 bar; int n_supported; PHYSICAL_ADDRESS pa; - ULONG capOffset, bir; + ULONG cap_offset, bir; PPCI_MSIX_CAPABILITY pPciMsixCap; MLX4_ENTER( MLX4_DBG_PNP ); /* find capability */ - capOffset = __find_capability( p_cfg, PCI_CAPABILITY_ID_MSIX ); - if( !capOffset ) { + cap_offset = __find_capability( p_cfg, PCI_CAPABILITY_ID_MSIX ); + if( !cap_offset ) { p_info->valid = 0; return 0; } - pPciMsixCap = (PPCI_MSIX_CAPABILITY)(((UCHAR*)p_cfg) + capOffset); + pPciMsixCap = (PPCI_MSIX_CAPABILITY)(((UCHAR*)p_cfg) + cap_offset); n_supported = MSIX_FLAGS_SUPPORTED(pPciMsixCap->Flags) + 1; p_info->num = n_supported; @@ -428,15 +428,150 @@ pci_free_msix_info_resources( memset(pMsixInfo,0,sizeof(struct msix_saved_info)); } +static NTSTATUS __read_vpd_dword( + IN BUS_INTERFACE_STANDARD *pBusIfc, + IN ULONG cap_offset, + IN ULONG offset, + OUT UCHAR *p_data + ) +{ + ULONG len; + USHORT addr = (USHORT)offset; + + /* write offset inside VPD data */ + len = pBusIfc->SetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &addr, cap_offset+2,2 ); + if ( len != 2 ) + goto err_write; + + /* wait for data to be put in the data register */ + while ( !(addr & 0x8000) ) { + len = pBusIfc->GetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG, &addr, cap_offset+2, 2 ); + if ( len != 2 ) + goto err_read; + } + + /* get the tag value */ + len = pBusIfc->GetBusData( pBusIfc->Context, PCI_WHICHSPACE_CONFIG, p_data, cap_offset+4, 4 ); + if ( len != 4 ) + goto err_read; + + return STATUS_SUCCESS; + +err_write: + MLX4_PRINT( TRACE_LEVEL_ERROR , MLX4_DBG_PNP , + ("Failed to write HCA config. \n" )); + return STATUS_DEVICE_NOT_READY; + +err_read: + MLX4_PRINT( TRACE_LEVEL_ERROR , MLX4_DBG_PNP , + ("Failed to read HCA config. \n" )); + return STATUS_DEVICE_NOT_READY; +} + + +#define MAX_VPD_SIZE (1 << 16) + +NTSTATUS pci_get_vpd( + IN BUS_INTERFACE_STANDARD *pBusIfc, + IN PCI_COMMON_CONFIG* const pConfig, + OUT UCHAR* *p_vpd, + IN OUT int* p_vpd_size + ) +{ + PCI_VPD_CAPABILITY *pPciVpdCap; + ULONG cap_offset; + NTSTATUS status = STATUS_SUCCESS; + int vpd_size = 0; + UCHAR *vpd = NULL; + + *p_vpd = NULL; + *p_vpd_size = 0; + + cap_offset = __find_capability( pConfig, PCI_CAPABILITY_ID_VPD ); + if( cap_offset ) { + ULONG offset; + pPciVpdCap = (PCI_VPD_CAPABILITY*)(((UCHAR*)pConfig) + cap_offset); + + /* allocate temp buffer */ + vpd = kmalloc( MAX_VPD_SIZE, GFP_KERNEL); + if ( !vpd ) { + MLX4_PRINT( TRACE_LEVEL_ERROR , MLX4_DBG_PNP , + ("Failed to allocate VPD buffer of size %d.\n", MAX_VPD_SIZE)); + return STATUS_UNSUCCESSFUL; + } + + /* read VPD */ + for ( offset = 0; offset < MAX_VPD_SIZE; offset += 0x4 ) { + status = __read_vpd_dword( pBusIfc, cap_offset, + offset, vpd + offset); + if( !NT_SUCCESS( status ) ) { + kfree( vpd ); + return STATUS_UNSUCCESSFUL; + } + } + /* find the size */ + for ( offset = 0; offset < MAX_VPD_SIZE; ) { + ULONG size; + if ( vpd[offset] == 0x78 ) { + vpd_size = offset + 1; + break; + } + if ( vpd[offset] & 0x80 ) { /* Large Resource Type */ + size = *(PUSHORT)(&vpd[offset+1]); + offset += size + 3; + } + else { /* Small Resource Type */ + size = vpd[offset] & 7; + offset += size + 1; + } + } + /* shorten the VPD array */ + if ( offset >= MAX_VPD_SIZE ) { + /* we didn't found VPD end. We'll keep it all */ + *p_vpd = vpd; + *p_vpd_size = MAX_VPD_SIZE; + } + else { + /* allocate VPD */ + if ( vpd_size ) { + *p_vpd = kmalloc( vpd_size, GFP_KERNEL); + if ( !*p_vpd ) { + *p_vpd = vpd; + *p_vpd_size = MAX_VPD_SIZE; + } + else { + memcpy( *p_vpd, vpd, vpd_size ); + *p_vpd_size = vpd_size; + kfree( vpd ); + } + } + else { + MLX4_PRINT( TRACE_LEVEL_ERROR , MLX4_DBG_PNP , + ("VPD starts from end tag.\n")); + kfree( vpd ); + status = STATUS_UNSUCCESSFUL; + } + } + MLX4_PRINT( TRACE_LEVEL_WARNING , MLX4_DBG_PNP , + ("Found VPD of size %d, beginning with '%s'\n", *p_vpd_size, &vpd[3])); + } + else { + MLX4_PRINT( TRACE_LEVEL_ERROR , MLX4_DBG_PNP ,("Failed to find VPD capability.\n")); + status = STATUS_UNSUCCESSFUL; + } + + return status; +} + /* * Reads and saves the PCI configuration of the device accessible * through the provided bus interface. Does not read registers 22 or 23 - * as directed in PRM , Appendix A. Software Reset. + * as directed in Tavor PRM 1.0.1, Appendix A. InfiniHost Software Reset. */ NTSTATUS pci_save_config( IN BUS_INTERFACE_STANDARD *pBusIfc, - OUT PCI_COMMON_CONFIG* const pConfig) + OUT PCI_COMMON_CONFIG* const pConfig ) { ULONG len; UINT32 *pBuf; @@ -480,7 +615,7 @@ pci_get_msi_info( OUT PCI_COMMON_CONFIG * p_cfg, OUT uplink_info_t * p_uplink_info ) { - ULONG capOffset; + ULONG cap_offset; NTSTATUS status; BUS_INTERFACE_STANDARD *pBusIfc = &pdev->bus_pci_ifc; @@ -495,15 +630,15 @@ pci_get_msi_info( // PCI MSI-X Capability memset( &p_uplink_info->x, 0, sizeof(p_uplink_info->x) ); - capOffset = __find_capability( p_cfg, PCI_CAPABILITY_ID_MSIX ); - if( capOffset ) { + cap_offset = __find_capability( p_cfg, PCI_CAPABILITY_ID_MSIX ); + if( cap_offset ) { PVOID ka; ULONG sz; PHYSICAL_ADDRESS pa; PPCI_MSIX_VECTOR p_vector; PPCI_MSIX_PENDING p_pend; ULONG granted_mask = 0; - PPCI_MSIX_CAPABILITY pPciMsixCap = (PPCI_MSIX_CAPABILITY)(((UCHAR*)p_cfg) + capOffset); + PPCI_MSIX_CAPABILITY pPciMsixCap = (PPCI_MSIX_CAPABILITY)(((UCHAR*)p_cfg) + cap_offset); USHORT flags = pPciMsixCap->Flags; ULONG table_bir = MSIX_OFFSET_BIR(pPciMsixCap->Table_Offset); ULONG pend_bir = MSIX_OFFSET_BIR(pPciMsixCap->PBA_Offset); @@ -732,16 +867,16 @@ pci_get_uplink_info( IN PCI_COMMON_CONFIG * p_cfg, OUT uplink_info_t * p_uplink_info ) { - ULONG capOffset; + ULONG cap_offset; PCI_PCIX_CAPABILITY *pPciXCap; PCI_PCIEXP_CAPABILITY *pPciExpCap; MLX4_ENTER( MLX4_DBG_PNP ); // PCIX Capability - capOffset = __find_capability( p_cfg, PCI_CAPABILITY_ID_PCIX ); - if( capOffset ) { - pPciXCap = (PCI_PCIX_CAPABILITY*)(((UCHAR*)p_cfg) + capOffset); + cap_offset = __find_capability( p_cfg, PCI_CAPABILITY_ID_PCIX ); + if( cap_offset ) { + pPciXCap = (PCI_PCIX_CAPABILITY*)(((UCHAR*)p_cfg) + cap_offset); p_uplink_info->bus_type = UPLINK_BUS_PCIX; if (pPciXCap->Status & (1 << 17)) @@ -750,9 +885,9 @@ pci_get_uplink_info( } // PCI Express Capability - capOffset = __find_capability( p_cfg, PCI_CAPABILITY_ID_PCI_EXPRESS ); - if( capOffset ) { - pPciExpCap = (PCI_PCIEXP_CAPABILITY*)(((UCHAR*)p_cfg) + capOffset); + cap_offset = __find_capability( p_cfg, PCI_CAPABILITY_ID_PCI_EXPRESS ); + if( cap_offset ) { + pPciExpCap = (PCI_PCIEXP_CAPABILITY*)(((UCHAR*)p_cfg) + cap_offset); p_uplink_info->bus_type = UPLINK_BUS_PCIE; if ((pPciExpCap->LinkStatus & 15) == 1) diff --git a/trunk/hw/mlx4/kernel/inc/l2w.h b/trunk/hw/mlx4/kernel/inc/l2w.h index de2222e6..b1c2e408 100644 --- a/trunk/hw/mlx4/kernel/inc/l2w.h +++ b/trunk/hw/mlx4/kernel/inc/l2w.h @@ -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 */ -- 2.46.0