mirror of https://github.com/ipxe/ipxe.git
[arbel] Ensure hardware is quiescent when no interfaces are open
Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/5/head
parent
6c73a8b51d
commit
8ef5f6065d
|
@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
#include <byteswap.h>
|
#include <byteswap.h>
|
||||||
#include <ipxe/io.h>
|
#include <ipxe/io.h>
|
||||||
#include <ipxe/pci.h>
|
#include <ipxe/pci.h>
|
||||||
|
#include <ipxe/pcibackup.h>
|
||||||
#include <ipxe/malloc.h>
|
#include <ipxe/malloc.h>
|
||||||
#include <ipxe/umalloc.h>
|
#include <ipxe/umalloc.h>
|
||||||
#include <ipxe/iobuf.h>
|
#include <ipxe/iobuf.h>
|
||||||
|
@ -1991,7 +1992,7 @@ static int arbel_start_firmware ( struct arbel *arbel ) {
|
||||||
struct arbelprm_query_fw fw;
|
struct arbelprm_query_fw fw;
|
||||||
struct arbelprm_access_lam lam;
|
struct arbelprm_access_lam lam;
|
||||||
unsigned int fw_pages;
|
unsigned int fw_pages;
|
||||||
size_t fw_size;
|
size_t fw_len;
|
||||||
physaddr_t fw_base;
|
physaddr_t fw_base;
|
||||||
uint64_t eq_set_ci_base_addr;
|
uint64_t eq_set_ci_base_addr;
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -2019,17 +2020,22 @@ static int arbel_start_firmware ( struct arbel *arbel ) {
|
||||||
arbel_cmd_enable_lam ( arbel, &lam );
|
arbel_cmd_enable_lam ( arbel, &lam );
|
||||||
|
|
||||||
/* Allocate firmware pages and map firmware area */
|
/* Allocate firmware pages and map firmware area */
|
||||||
fw_size = ( fw_pages * ARBEL_PAGE_SIZE );
|
fw_len = ( fw_pages * ARBEL_PAGE_SIZE );
|
||||||
arbel->firmware_area = umalloc ( fw_size );
|
if ( ! arbel->firmware_area ) {
|
||||||
|
arbel->firmware_len = fw_len;
|
||||||
|
arbel->firmware_area = umalloc ( arbel->firmware_len );
|
||||||
if ( ! arbel->firmware_area ) {
|
if ( ! arbel->firmware_area ) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto err_alloc_fa;
|
goto err_alloc_fa;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
assert ( arbel->firmware_len == fw_len );
|
||||||
|
}
|
||||||
fw_base = user_to_phys ( arbel->firmware_area, 0 );
|
fw_base = user_to_phys ( arbel->firmware_area, 0 );
|
||||||
DBGC ( arbel, "Arbel %p firmware area at [%08lx,%08lx)\n",
|
DBGC ( arbel, "Arbel %p firmware area at [%08lx,%08lx)\n",
|
||||||
arbel, fw_base, ( fw_base + fw_size ) );
|
arbel, fw_base, ( fw_base + fw_len ) );
|
||||||
if ( ( rc = arbel_map_vpm ( arbel, arbel_cmd_map_fa,
|
if ( ( rc = arbel_map_vpm ( arbel, arbel_cmd_map_fa,
|
||||||
0, fw_base, fw_size ) ) != 0 ) {
|
0, fw_base, fw_len ) ) != 0 ) {
|
||||||
DBGC ( arbel, "Arbel %p could not map firmware: %s\n",
|
DBGC ( arbel, "Arbel %p could not map firmware: %s\n",
|
||||||
arbel, strerror ( rc ) );
|
arbel, strerror ( rc ) );
|
||||||
goto err_map_fa;
|
goto err_map_fa;
|
||||||
|
@ -2048,8 +2054,6 @@ static int arbel_start_firmware ( struct arbel *arbel ) {
|
||||||
err_run_fw:
|
err_run_fw:
|
||||||
arbel_cmd_unmap_fa ( arbel );
|
arbel_cmd_unmap_fa ( arbel );
|
||||||
err_map_fa:
|
err_map_fa:
|
||||||
ufree ( arbel->firmware_area );
|
|
||||||
arbel->firmware_area = UNULL;
|
|
||||||
err_alloc_fa:
|
err_alloc_fa:
|
||||||
err_query_fw:
|
err_query_fw:
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -2067,10 +2071,9 @@ static void arbel_stop_firmware ( struct arbel *arbel ) {
|
||||||
DBGC ( arbel, "Arbel %p FATAL could not stop firmware: %s\n",
|
DBGC ( arbel, "Arbel %p FATAL could not stop firmware: %s\n",
|
||||||
arbel, strerror ( rc ) );
|
arbel, strerror ( rc ) );
|
||||||
/* Leak memory and return; at least we avoid corruption */
|
/* Leak memory and return; at least we avoid corruption */
|
||||||
|
arbel->firmware_area = UNULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ufree ( arbel->firmware_area );
|
|
||||||
arbel->firmware_area = UNULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
|
@ -2180,6 +2183,7 @@ static int arbel_alloc_icm ( struct arbel *arbel,
|
||||||
unsigned int log_num_uars, log_num_qps, log_num_srqs, log_num_ees;
|
unsigned int log_num_uars, log_num_qps, log_num_srqs, log_num_ees;
|
||||||
unsigned int log_num_cqs, log_num_mtts, log_num_mpts, log_num_rdbs;
|
unsigned int log_num_cqs, log_num_mtts, log_num_mpts, log_num_rdbs;
|
||||||
unsigned int log_num_eqs, log_num_mcs;
|
unsigned int log_num_eqs, log_num_mcs;
|
||||||
|
size_t icm_len, icm_aux_len;
|
||||||
size_t len;
|
size_t len;
|
||||||
physaddr_t icm_phys;
|
physaddr_t icm_phys;
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -2351,7 +2355,7 @@ static int arbel_alloc_icm ( struct arbel *arbel,
|
||||||
|
|
||||||
/* Record amount of ICM to be allocated */
|
/* Record amount of ICM to be allocated */
|
||||||
icm_offset = icm_align ( icm_offset, ARBEL_PAGE_SIZE );
|
icm_offset = icm_align ( icm_offset, ARBEL_PAGE_SIZE );
|
||||||
arbel->icm_len = icm_offset;
|
icm_len = icm_offset;
|
||||||
|
|
||||||
/* User access region contexts
|
/* User access region contexts
|
||||||
*
|
*
|
||||||
|
@ -2376,25 +2380,30 @@ static int arbel_alloc_icm ( struct arbel *arbel,
|
||||||
|
|
||||||
/* Get ICM auxiliary area size */
|
/* Get ICM auxiliary area size */
|
||||||
memset ( &icm_size, 0, sizeof ( icm_size ) );
|
memset ( &icm_size, 0, sizeof ( icm_size ) );
|
||||||
MLX_FILL_1 ( &icm_size, 1, value, arbel->icm_len );
|
MLX_FILL_1 ( &icm_size, 1, value, icm_len );
|
||||||
if ( ( rc = arbel_cmd_set_icm_size ( arbel, &icm_size,
|
if ( ( rc = arbel_cmd_set_icm_size ( arbel, &icm_size,
|
||||||
&icm_aux_size ) ) != 0 ) {
|
&icm_aux_size ) ) != 0 ) {
|
||||||
DBGC ( arbel, "Arbel %p could not set ICM size: %s\n",
|
DBGC ( arbel, "Arbel %p could not set ICM size: %s\n",
|
||||||
arbel, strerror ( rc ) );
|
arbel, strerror ( rc ) );
|
||||||
goto err_set_icm_size;
|
goto err_set_icm_size;
|
||||||
}
|
}
|
||||||
arbel->icm_aux_len =
|
icm_aux_len = ( MLX_GET ( &icm_aux_size, value ) * ARBEL_PAGE_SIZE );
|
||||||
( MLX_GET ( &icm_aux_size, value ) * ARBEL_PAGE_SIZE );
|
|
||||||
|
|
||||||
/* Allocate ICM data and auxiliary area */
|
/* Allocate ICM data and auxiliary area */
|
||||||
DBGC ( arbel, "Arbel %p requires %zd kB ICM and %zd kB AUX ICM\n",
|
DBGC ( arbel, "Arbel %p requires %zd kB ICM and %zd kB AUX ICM\n",
|
||||||
arbel, ( arbel->icm_len / 1024 ),
|
arbel, ( icm_len / 1024 ), ( icm_aux_len / 1024 ) );
|
||||||
( arbel->icm_aux_len / 1024 ) );
|
if ( ! arbel->icm ) {
|
||||||
|
arbel->icm_len = icm_len;
|
||||||
|
arbel->icm_aux_len = icm_aux_len;
|
||||||
arbel->icm = umalloc ( arbel->icm_len + arbel->icm_aux_len );
|
arbel->icm = umalloc ( arbel->icm_len + arbel->icm_aux_len );
|
||||||
if ( ! arbel->icm ) {
|
if ( ! arbel->icm ) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto err_alloc_icm;
|
goto err_alloc_icm;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
assert ( arbel->icm_len == icm_len );
|
||||||
|
assert ( arbel->icm_aux_len == icm_aux_len );
|
||||||
|
}
|
||||||
icm_phys = user_to_phys ( arbel->icm, 0 );
|
icm_phys = user_to_phys ( arbel->icm, 0 );
|
||||||
|
|
||||||
/* Allocate doorbell UAR */
|
/* Allocate doorbell UAR */
|
||||||
|
@ -2459,8 +2468,6 @@ static int arbel_alloc_icm ( struct arbel *arbel,
|
||||||
free_dma ( arbel->db_rec, ARBEL_PAGE_SIZE );
|
free_dma ( arbel->db_rec, ARBEL_PAGE_SIZE );
|
||||||
arbel->db_rec= NULL;
|
arbel->db_rec= NULL;
|
||||||
err_alloc_doorbell:
|
err_alloc_doorbell:
|
||||||
ufree ( arbel->icm );
|
|
||||||
arbel->icm = UNULL;
|
|
||||||
err_alloc_icm:
|
err_alloc_icm:
|
||||||
err_set_icm_size:
|
err_set_icm_size:
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -2483,17 +2490,41 @@ static void arbel_free_icm ( struct arbel *arbel ) {
|
||||||
arbel_cmd_unmap_icm_aux ( arbel );
|
arbel_cmd_unmap_icm_aux ( arbel );
|
||||||
free_dma ( arbel->db_rec, ARBEL_PAGE_SIZE );
|
free_dma ( arbel->db_rec, ARBEL_PAGE_SIZE );
|
||||||
arbel->db_rec = NULL;
|
arbel->db_rec = NULL;
|
||||||
ufree ( arbel->icm );
|
|
||||||
arbel->icm = UNULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
*
|
*
|
||||||
* Initialisation
|
* Initialisation and teardown
|
||||||
*
|
*
|
||||||
***************************************************************************
|
***************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset device
|
||||||
|
*
|
||||||
|
* @v arbel Arbel device
|
||||||
|
*/
|
||||||
|
static void arbel_reset ( struct arbel *arbel ) {
|
||||||
|
struct pci_device *pci = arbel->pci;
|
||||||
|
struct pci_config_backup backup;
|
||||||
|
static const uint8_t backup_exclude[] =
|
||||||
|
PCI_CONFIG_BACKUP_EXCLUDE ( 0x58, 0x5c );
|
||||||
|
uint16_t vendor;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
/* Perform device reset and preserve PCI configuration */
|
||||||
|
pci_backup ( pci, &backup, backup_exclude );
|
||||||
|
writel ( ARBEL_RESET_MAGIC,
|
||||||
|
( arbel->config + ARBEL_RESET_OFFSET ) );
|
||||||
|
for ( i = 0 ; i < ARBEL_RESET_WAIT_TIME_MS ; i++ ) {
|
||||||
|
mdelay ( 1 );
|
||||||
|
pci_read_config_word ( pci, PCI_VENDOR_ID, &vendor );
|
||||||
|
if ( vendor != 0xffff )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pci_restore ( pci, &backup, backup_exclude );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up memory protection table
|
* Set up memory protection table
|
||||||
*
|
*
|
||||||
|
@ -2572,6 +2603,115 @@ static int arbel_configure_special_qps ( struct arbel *arbel ) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start Arbel device
|
||||||
|
*
|
||||||
|
* @v arbel Arbel device
|
||||||
|
* @v running Firmware is already running
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
static int arbel_start ( struct arbel *arbel, int running ) {
|
||||||
|
struct arbelprm_init_hca init_hca;
|
||||||
|
unsigned int i;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Start firmware if not already running */
|
||||||
|
if ( ! running ) {
|
||||||
|
if ( ( rc = arbel_start_firmware ( arbel ) ) != 0 )
|
||||||
|
goto err_start_firmware;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate ICM */
|
||||||
|
memset ( &init_hca, 0, sizeof ( init_hca ) );
|
||||||
|
if ( ( rc = arbel_alloc_icm ( arbel, &init_hca ) ) != 0 )
|
||||||
|
goto err_alloc_icm;
|
||||||
|
|
||||||
|
/* Initialise HCA */
|
||||||
|
if ( ( rc = arbel_cmd_init_hca ( arbel, &init_hca ) ) != 0 ) {
|
||||||
|
DBGC ( arbel, "Arbel %p could not initialise HCA: %s\n",
|
||||||
|
arbel, strerror ( rc ) );
|
||||||
|
goto err_init_hca;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set up memory protection */
|
||||||
|
if ( ( rc = arbel_setup_mpt ( arbel ) ) != 0 )
|
||||||
|
goto err_setup_mpt;
|
||||||
|
for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ )
|
||||||
|
arbel->ibdev[i]->rdma_key = arbel->lkey;
|
||||||
|
|
||||||
|
/* Set up event queue */
|
||||||
|
if ( ( rc = arbel_create_eq ( arbel ) ) != 0 )
|
||||||
|
goto err_create_eq;
|
||||||
|
|
||||||
|
/* Configure special QPs */
|
||||||
|
if ( ( rc = arbel_configure_special_qps ( arbel ) ) != 0 )
|
||||||
|
goto err_conf_special_qps;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_conf_special_qps:
|
||||||
|
arbel_destroy_eq ( arbel );
|
||||||
|
err_create_eq:
|
||||||
|
err_setup_mpt:
|
||||||
|
arbel_cmd_close_hca ( arbel );
|
||||||
|
err_init_hca:
|
||||||
|
arbel_free_icm ( arbel );
|
||||||
|
err_alloc_icm:
|
||||||
|
arbel_stop_firmware ( arbel );
|
||||||
|
err_start_firmware:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop Arbel device
|
||||||
|
*
|
||||||
|
* @v arbel Arbel device
|
||||||
|
*/
|
||||||
|
static void arbel_stop ( struct arbel *arbel ) {
|
||||||
|
arbel_destroy_eq ( arbel );
|
||||||
|
arbel_cmd_close_hca ( arbel );
|
||||||
|
arbel_free_icm ( arbel );
|
||||||
|
arbel_stop_firmware ( arbel );
|
||||||
|
arbel_reset ( arbel );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open Arbel device
|
||||||
|
*
|
||||||
|
* @v arbel Arbel device
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
static int arbel_open ( struct arbel *arbel ) {
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Start device if applicable */
|
||||||
|
if ( arbel->open_count == 0 ) {
|
||||||
|
if ( ( rc = arbel_start ( arbel, 0 ) ) != 0 )
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increment open counter */
|
||||||
|
arbel->open_count++;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close Arbel device
|
||||||
|
*
|
||||||
|
* @v arbel Arbel device
|
||||||
|
*/
|
||||||
|
static void arbel_close ( struct arbel *arbel ) {
|
||||||
|
|
||||||
|
/* Decrement open counter */
|
||||||
|
assert ( arbel->open_count != 0 );
|
||||||
|
arbel->open_count--;
|
||||||
|
|
||||||
|
/* Stop device if applicable */
|
||||||
|
if ( arbel->open_count == 0 )
|
||||||
|
arbel_stop ( arbel );
|
||||||
|
}
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
*
|
*
|
||||||
* Infiniband link-layer operations
|
* Infiniband link-layer operations
|
||||||
|
@ -2585,11 +2725,16 @@ static int arbel_configure_special_qps ( struct arbel *arbel ) {
|
||||||
* @v ibdev Infiniband device
|
* @v ibdev Infiniband device
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int arbel_open ( struct ib_device *ibdev ) {
|
static int arbel_ib_open ( struct ib_device *ibdev ) {
|
||||||
struct arbel *arbel = ib_get_drvdata ( ibdev );
|
struct arbel *arbel = ib_get_drvdata ( ibdev );
|
||||||
struct arbelprm_init_ib init_ib;
|
struct arbelprm_init_ib init_ib;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
/* Open hardware */
|
||||||
|
if ( ( rc = arbel_open ( arbel ) ) != 0 )
|
||||||
|
goto err_open;
|
||||||
|
|
||||||
|
/* Initialise IB */
|
||||||
memset ( &init_ib, 0, sizeof ( init_ib ) );
|
memset ( &init_ib, 0, sizeof ( init_ib ) );
|
||||||
MLX_FILL_3 ( &init_ib, 0,
|
MLX_FILL_3 ( &init_ib, 0,
|
||||||
mtu_cap, ARBEL_MTU_2048,
|
mtu_cap, ARBEL_MTU_2048,
|
||||||
|
@ -2601,13 +2746,18 @@ static int arbel_open ( struct ib_device *ibdev ) {
|
||||||
&init_ib ) ) != 0 ) {
|
&init_ib ) ) != 0 ) {
|
||||||
DBGC ( arbel, "Arbel %p port %d could not intialise IB: %s\n",
|
DBGC ( arbel, "Arbel %p port %d could not intialise IB: %s\n",
|
||||||
arbel, ibdev->port, strerror ( rc ) );
|
arbel, ibdev->port, strerror ( rc ) );
|
||||||
return rc;
|
goto err_init_ib;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update MAD parameters */
|
/* Update MAD parameters */
|
||||||
ib_smc_update ( ibdev, arbel_mad );
|
ib_smc_update ( ibdev, arbel_mad );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_init_ib:
|
||||||
|
arbel_close ( arbel );
|
||||||
|
err_open:
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2615,15 +2765,19 @@ static int arbel_open ( struct ib_device *ibdev ) {
|
||||||
*
|
*
|
||||||
* @v ibdev Infiniband device
|
* @v ibdev Infiniband device
|
||||||
*/
|
*/
|
||||||
static void arbel_close ( struct ib_device *ibdev ) {
|
static void arbel_ib_close ( struct ib_device *ibdev ) {
|
||||||
struct arbel *arbel = ib_get_drvdata ( ibdev );
|
struct arbel *arbel = ib_get_drvdata ( ibdev );
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
/* Close IB */
|
||||||
if ( ( rc = arbel_cmd_close_ib ( arbel, ibdev->port ) ) != 0 ) {
|
if ( ( rc = arbel_cmd_close_ib ( arbel, ibdev->port ) ) != 0 ) {
|
||||||
DBGC ( arbel, "Arbel %p port %d could not close IB: %s\n",
|
DBGC ( arbel, "Arbel %p port %d could not close IB: %s\n",
|
||||||
arbel, ibdev->port, strerror ( rc ) );
|
arbel, ibdev->port, strerror ( rc ) );
|
||||||
/* Nothing we can do about this */
|
/* Nothing we can do about this */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Close hardware */
|
||||||
|
arbel_close ( arbel );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2753,8 +2907,8 @@ static struct ib_device_operations arbel_ib_operations = {
|
||||||
.post_recv = arbel_post_recv,
|
.post_recv = arbel_post_recv,
|
||||||
.poll_cq = arbel_poll_cq,
|
.poll_cq = arbel_poll_cq,
|
||||||
.poll_eq = arbel_poll_eq,
|
.poll_eq = arbel_poll_eq,
|
||||||
.open = arbel_open,
|
.open = arbel_ib_open,
|
||||||
.close = arbel_close,
|
.close = arbel_ib_close,
|
||||||
.mcast_attach = arbel_mcast_attach,
|
.mcast_attach = arbel_mcast_attach,
|
||||||
.mcast_detach = arbel_mcast_detach,
|
.mcast_detach = arbel_mcast_detach,
|
||||||
.set_port_info = arbel_inform_sma,
|
.set_port_info = arbel_inform_sma,
|
||||||
|
@ -2768,6 +2922,52 @@ static struct ib_device_operations arbel_ib_operations = {
|
||||||
***************************************************************************
|
***************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocate Arbel device
|
||||||
|
*
|
||||||
|
* @ret arbel Arbel device
|
||||||
|
*/
|
||||||
|
static struct arbel * arbel_alloc ( void ) {
|
||||||
|
struct arbel *arbel;
|
||||||
|
|
||||||
|
/* Allocate Arbel device */
|
||||||
|
arbel = zalloc ( sizeof ( *arbel ) );
|
||||||
|
if ( ! arbel )
|
||||||
|
goto err_arbel;
|
||||||
|
|
||||||
|
/* Allocate space for mailboxes */
|
||||||
|
arbel->mailbox_in = malloc_dma ( ARBEL_MBOX_SIZE, ARBEL_MBOX_ALIGN );
|
||||||
|
if ( ! arbel->mailbox_in )
|
||||||
|
goto err_mailbox_in;
|
||||||
|
arbel->mailbox_out = malloc_dma ( ARBEL_MBOX_SIZE, ARBEL_MBOX_ALIGN );
|
||||||
|
if ( ! arbel->mailbox_out )
|
||||||
|
goto err_mailbox_out;
|
||||||
|
|
||||||
|
return arbel;
|
||||||
|
|
||||||
|
free_dma ( arbel->mailbox_out, ARBEL_MBOX_SIZE );
|
||||||
|
err_mailbox_out:
|
||||||
|
free_dma ( arbel->mailbox_in, ARBEL_MBOX_SIZE );
|
||||||
|
err_mailbox_in:
|
||||||
|
free ( arbel );
|
||||||
|
err_arbel:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free Arbel device
|
||||||
|
*
|
||||||
|
* @v arbel Arbel device
|
||||||
|
*/
|
||||||
|
static void arbel_free ( struct arbel *arbel ) {
|
||||||
|
|
||||||
|
ufree ( arbel->icm );
|
||||||
|
ufree ( arbel->firmware_area );
|
||||||
|
free_dma ( arbel->mailbox_out, ARBEL_MBOX_SIZE );
|
||||||
|
free_dma ( arbel->mailbox_in, ARBEL_MBOX_SIZE );
|
||||||
|
free ( arbel );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Probe PCI device
|
* Probe PCI device
|
||||||
*
|
*
|
||||||
|
@ -2778,17 +2978,17 @@ static struct ib_device_operations arbel_ib_operations = {
|
||||||
static int arbel_probe ( struct pci_device *pci ) {
|
static int arbel_probe ( struct pci_device *pci ) {
|
||||||
struct arbel *arbel;
|
struct arbel *arbel;
|
||||||
struct ib_device *ibdev;
|
struct ib_device *ibdev;
|
||||||
struct arbelprm_init_hca init_hca;
|
|
||||||
int i;
|
int i;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Allocate Arbel device */
|
/* Allocate Arbel device */
|
||||||
arbel = zalloc ( sizeof ( *arbel ) );
|
arbel = arbel_alloc();
|
||||||
if ( ! arbel ) {
|
if ( ! arbel ) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto err_alloc_arbel;
|
goto err_alloc;
|
||||||
}
|
}
|
||||||
pci_set_drvdata ( pci, arbel );
|
pci_set_drvdata ( pci, arbel );
|
||||||
|
arbel->pci = pci;
|
||||||
|
|
||||||
/* Allocate Infiniband devices */
|
/* Allocate Infiniband devices */
|
||||||
for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ ) {
|
for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ ) {
|
||||||
|
@ -2814,17 +3014,8 @@ static int arbel_probe ( struct pci_device *pci ) {
|
||||||
ARBEL_PCI_UAR_IDX * ARBEL_PCI_UAR_SIZE ),
|
ARBEL_PCI_UAR_IDX * ARBEL_PCI_UAR_SIZE ),
|
||||||
ARBEL_PCI_UAR_SIZE );
|
ARBEL_PCI_UAR_SIZE );
|
||||||
|
|
||||||
/* Allocate space for mailboxes */
|
/* Reset device */
|
||||||
arbel->mailbox_in = malloc_dma ( ARBEL_MBOX_SIZE, ARBEL_MBOX_ALIGN );
|
arbel_reset ( arbel );
|
||||||
if ( ! arbel->mailbox_in ) {
|
|
||||||
rc = -ENOMEM;
|
|
||||||
goto err_mailbox_in;
|
|
||||||
}
|
|
||||||
arbel->mailbox_out = malloc_dma ( ARBEL_MBOX_SIZE, ARBEL_MBOX_ALIGN );
|
|
||||||
if ( ! arbel->mailbox_out ) {
|
|
||||||
rc = -ENOMEM;
|
|
||||||
goto err_mailbox_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start firmware */
|
/* Start firmware */
|
||||||
if ( ( rc = arbel_start_firmware ( arbel ) ) != 0 )
|
if ( ( rc = arbel_start_firmware ( arbel ) ) != 0 )
|
||||||
|
@ -2834,31 +3025,9 @@ static int arbel_probe ( struct pci_device *pci ) {
|
||||||
if ( ( rc = arbel_get_limits ( arbel ) ) != 0 )
|
if ( ( rc = arbel_get_limits ( arbel ) ) != 0 )
|
||||||
goto err_get_limits;
|
goto err_get_limits;
|
||||||
|
|
||||||
/* Allocate ICM */
|
/* Start device */
|
||||||
memset ( &init_hca, 0, sizeof ( init_hca ) );
|
if ( ( rc = arbel_start ( arbel, 1 ) ) != 0 )
|
||||||
if ( ( rc = arbel_alloc_icm ( arbel, &init_hca ) ) != 0 )
|
goto err_start;
|
||||||
goto err_alloc_icm;
|
|
||||||
|
|
||||||
/* Initialise HCA */
|
|
||||||
if ( ( rc = arbel_cmd_init_hca ( arbel, &init_hca ) ) != 0 ) {
|
|
||||||
DBGC ( arbel, "Arbel %p could not initialise HCA: %s\n",
|
|
||||||
arbel, strerror ( rc ) );
|
|
||||||
goto err_init_hca;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set up memory protection */
|
|
||||||
if ( ( rc = arbel_setup_mpt ( arbel ) ) != 0 )
|
|
||||||
goto err_setup_mpt;
|
|
||||||
for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ )
|
|
||||||
arbel->ibdev[i]->rdma_key = arbel->lkey;
|
|
||||||
|
|
||||||
/* Set up event queue */
|
|
||||||
if ( ( rc = arbel_create_eq ( arbel ) ) != 0 )
|
|
||||||
goto err_create_eq;
|
|
||||||
|
|
||||||
/* Configure special QPs */
|
|
||||||
if ( ( rc = arbel_configure_special_qps ( arbel ) ) != 0 )
|
|
||||||
goto err_conf_special_qps;
|
|
||||||
|
|
||||||
/* Initialise parameters using SMC */
|
/* Initialise parameters using SMC */
|
||||||
for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ )
|
for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ )
|
||||||
|
@ -2874,33 +3043,27 @@ static int arbel_probe ( struct pci_device *pci ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Leave device quiescent until opened */
|
||||||
|
if ( arbel->open_count == 0 )
|
||||||
|
arbel_stop ( arbel );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
i = ARBEL_NUM_PORTS;
|
i = ARBEL_NUM_PORTS;
|
||||||
err_register_ibdev:
|
err_register_ibdev:
|
||||||
for ( i-- ; i >= 0 ; i-- )
|
for ( i-- ; i >= 0 ; i-- )
|
||||||
unregister_ibdev ( arbel->ibdev[i] );
|
unregister_ibdev ( arbel->ibdev[i] );
|
||||||
err_conf_special_qps:
|
arbel_stop ( arbel );
|
||||||
arbel_destroy_eq ( arbel );
|
err_start:
|
||||||
err_create_eq:
|
|
||||||
err_setup_mpt:
|
|
||||||
arbel_cmd_close_hca ( arbel );
|
|
||||||
err_init_hca:
|
|
||||||
arbel_free_icm ( arbel );
|
|
||||||
err_alloc_icm:
|
|
||||||
err_get_limits:
|
err_get_limits:
|
||||||
arbel_stop_firmware ( arbel );
|
arbel_stop_firmware ( arbel );
|
||||||
err_start_firmware:
|
err_start_firmware:
|
||||||
free_dma ( arbel->mailbox_out, ARBEL_MBOX_SIZE );
|
|
||||||
err_mailbox_out:
|
|
||||||
free_dma ( arbel->mailbox_in, ARBEL_MBOX_SIZE );
|
|
||||||
err_mailbox_in:
|
|
||||||
i = ARBEL_NUM_PORTS;
|
i = ARBEL_NUM_PORTS;
|
||||||
err_alloc_ibdev:
|
err_alloc_ibdev:
|
||||||
for ( i-- ; i >= 0 ; i-- )
|
for ( i-- ; i >= 0 ; i-- )
|
||||||
ibdev_put ( arbel->ibdev[i] );
|
ibdev_put ( arbel->ibdev[i] );
|
||||||
free ( arbel );
|
arbel_free ( arbel );
|
||||||
err_alloc_arbel:
|
err_alloc:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2915,15 +3078,9 @@ static void arbel_remove ( struct pci_device *pci ) {
|
||||||
|
|
||||||
for ( i = ( ARBEL_NUM_PORTS - 1 ) ; i >= 0 ; i-- )
|
for ( i = ( ARBEL_NUM_PORTS - 1 ) ; i >= 0 ; i-- )
|
||||||
unregister_ibdev ( arbel->ibdev[i] );
|
unregister_ibdev ( arbel->ibdev[i] );
|
||||||
arbel_destroy_eq ( arbel );
|
|
||||||
arbel_cmd_close_hca ( arbel );
|
|
||||||
arbel_free_icm ( arbel );
|
|
||||||
arbel_stop_firmware ( arbel );
|
|
||||||
free_dma ( arbel->mailbox_out, ARBEL_MBOX_SIZE );
|
|
||||||
free_dma ( arbel->mailbox_in, ARBEL_MBOX_SIZE );
|
|
||||||
for ( i = ( ARBEL_NUM_PORTS - 1 ) ; i >= 0 ; i-- )
|
for ( i = ( ARBEL_NUM_PORTS - 1 ) ; i >= 0 ; i-- )
|
||||||
ibdev_put ( arbel->ibdev[i] );
|
ibdev_put ( arbel->ibdev[i] );
|
||||||
free ( arbel );
|
arbel_free ( arbel );
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct pci_device_id arbel_nics[] = {
|
static struct pci_device_id arbel_nics[] = {
|
||||||
|
|
|
@ -31,6 +31,11 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||||
#define ARBEL_PCI_UAR_IDX 1
|
#define ARBEL_PCI_UAR_IDX 1
|
||||||
#define ARBEL_PCI_UAR_SIZE 0x1000
|
#define ARBEL_PCI_UAR_SIZE 0x1000
|
||||||
|
|
||||||
|
/* Device reset */
|
||||||
|
#define ARBEL_RESET_OFFSET 0x0f0010
|
||||||
|
#define ARBEL_RESET_MAGIC 0x01000000UL
|
||||||
|
#define ARBEL_RESET_WAIT_TIME_MS 1000
|
||||||
|
|
||||||
/* UAR context table (UCE) resource types */
|
/* UAR context table (UCE) resource types */
|
||||||
#define ARBEL_UAR_RES_NONE 0x00
|
#define ARBEL_UAR_RES_NONE 0x00
|
||||||
#define ARBEL_UAR_RES_CQ_CI 0x01
|
#define ARBEL_UAR_RES_CQ_CI 0x01
|
||||||
|
@ -458,6 +463,8 @@ typedef uint32_t arbel_bitmask_t;
|
||||||
|
|
||||||
/** An Arbel device */
|
/** An Arbel device */
|
||||||
struct arbel {
|
struct arbel {
|
||||||
|
/** PCI device */
|
||||||
|
struct pci_device *pci;
|
||||||
/** PCI configuration registers */
|
/** PCI configuration registers */
|
||||||
void *config;
|
void *config;
|
||||||
/** PCI user Access Region */
|
/** PCI user Access Region */
|
||||||
|
@ -470,13 +477,28 @@ struct arbel {
|
||||||
/** Command output mailbox */
|
/** Command output mailbox */
|
||||||
void *mailbox_out;
|
void *mailbox_out;
|
||||||
|
|
||||||
/** Firmware area in external memory */
|
/** Device open request counter */
|
||||||
|
unsigned int open_count;
|
||||||
|
|
||||||
|
/** Firmware size */
|
||||||
|
size_t firmware_len;
|
||||||
|
/** Firmware area in external memory
|
||||||
|
*
|
||||||
|
* This is allocated when first needed, and freed only on
|
||||||
|
* final teardown, in order to avoid memory map changes at
|
||||||
|
* runtime.
|
||||||
|
*/
|
||||||
userptr_t firmware_area;
|
userptr_t firmware_area;
|
||||||
/** ICM size */
|
/** ICM size */
|
||||||
size_t icm_len;
|
size_t icm_len;
|
||||||
/** ICM AUX size */
|
/** ICM AUX size */
|
||||||
size_t icm_aux_len;
|
size_t icm_aux_len;
|
||||||
/** ICM area */
|
/** ICM area
|
||||||
|
*
|
||||||
|
* This is allocated when first needed, and freed only on
|
||||||
|
* final teardown, in order to avoid memory map changes at
|
||||||
|
* runtime.
|
||||||
|
*/
|
||||||
userptr_t icm;
|
userptr_t icm;
|
||||||
/** Offset within ICM of doorbell records */
|
/** Offset within ICM of doorbell records */
|
||||||
size_t db_rec_offset;
|
size_t db_rec_offset;
|
||||||
|
|
Loading…
Reference in New Issue