mirror of
https://github.com/ipxe/ipxe
synced 2025-12-08 10:20:24 +03:00
[hermon] Add BOFM support
Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -40,6 +40,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
||||
#include <ipxe/ethernet.h>
|
||||
#include <ipxe/fcoe.h>
|
||||
#include <ipxe/vlan.h>
|
||||
#include <ipxe/bofm.h>
|
||||
#include "hermon.h"
|
||||
|
||||
/**
|
||||
@@ -496,6 +497,17 @@ hermon_cmd_mgid_hash ( struct hermon *hermon, const union ib_gid *gid,
|
||||
0, gid, 0, hash );
|
||||
}
|
||||
|
||||
static inline int
|
||||
hermon_cmd_mod_stat_cfg ( struct hermon *hermon, unsigned int mode,
|
||||
unsigned int input_mod,
|
||||
struct hermonprm_scalar_parameter *portion ) {
|
||||
return hermon_cmd ( hermon,
|
||||
HERMON_HCR_INOUT_CMD ( HERMON_HCR_MOD_STAT_CFG,
|
||||
0, sizeof ( *portion ),
|
||||
0, sizeof ( *portion ) ),
|
||||
mode, portion, input_mod, portion );
|
||||
}
|
||||
|
||||
static inline int
|
||||
hermon_cmd_query_port ( struct hermon *hermon, unsigned int port,
|
||||
struct hermonprm_query_port_cap *query_port ) {
|
||||
@@ -682,6 +694,59 @@ static void hermon_free_mtt ( struct hermon *hermon,
|
||||
mtt->num_pages );
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* Static configuration operations
|
||||
*
|
||||
***************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Calculate offset within static configuration
|
||||
*
|
||||
* @v field Field
|
||||
* @ret offset Offset
|
||||
*/
|
||||
#define HERMON_MOD_STAT_CFG_OFFSET( field ) \
|
||||
( ( MLX_BIT_OFFSET ( struct hermonprm_mod_stat_cfg_st, field ) / 8 ) \
|
||||
& ~( sizeof ( struct hermonprm_scalar_parameter ) - 1 ) )
|
||||
|
||||
/**
|
||||
* Query or modify static configuration
|
||||
*
|
||||
* @v hermon Hermon device
|
||||
* @v port Port
|
||||
* @v mode Command mode
|
||||
* @v offset Offset within static configuration
|
||||
* @v stat_cfg Static configuration
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int hermon_mod_stat_cfg ( struct hermon *hermon, unsigned int port,
|
||||
unsigned int mode, unsigned int offset,
|
||||
struct hermonprm_mod_stat_cfg *stat_cfg ) {
|
||||
struct hermonprm_scalar_parameter *portion =
|
||||
( ( void * ) &stat_cfg->u.bytes[offset] );
|
||||
struct hermonprm_mod_stat_cfg_input_mod mod;
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
assert ( ( offset % sizeof ( *portion ) ) == 0 );
|
||||
|
||||
/* Construct input modifier */
|
||||
memset ( &mod, 0, sizeof ( mod ) );
|
||||
MLX_FILL_2 ( &mod, 0,
|
||||
portnum, port,
|
||||
offset, offset );
|
||||
|
||||
/* Issue command */
|
||||
if ( ( rc = hermon_cmd_mod_stat_cfg ( hermon, mode,
|
||||
be32_to_cpu ( mod.u.dwords[0] ),
|
||||
portion ) ) != 0 )
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* MAD operations
|
||||
@@ -3230,6 +3295,103 @@ static void hermon_free_icm ( struct hermon *hermon ) {
|
||||
hermon->icm = UNULL;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* BOFM interface
|
||||
*
|
||||
***************************************************************************
|
||||
*/
|
||||
|
||||
/**
|
||||
* Harvest Ethernet MAC for BOFM
|
||||
*
|
||||
* @v bofm BOFM device
|
||||
* @v mport Multi-port index
|
||||
* @v mac MAC to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int hermon_bofm_harvest ( struct bofm_device *bofm, unsigned int mport,
|
||||
uint8_t *mac ) {
|
||||
struct hermon *hermon = container_of ( bofm, struct hermon, bofm );
|
||||
struct hermonprm_mod_stat_cfg stat_cfg;
|
||||
union {
|
||||
uint8_t bytes[8];
|
||||
uint32_t dwords[2];
|
||||
} buf;
|
||||
int rc;
|
||||
|
||||
/* Query static configuration */
|
||||
if ( ( rc = hermon_mod_stat_cfg ( hermon, mport,
|
||||
HERMON_MOD_STAT_CFG_QUERY,
|
||||
HERMON_MOD_STAT_CFG_OFFSET ( mac_m ),
|
||||
&stat_cfg ) ) != 0 ) {
|
||||
DBGC ( hermon, "Hermon %p port %d could not query "
|
||||
"configuration: %s\n", hermon, mport, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Retrieve MAC address */
|
||||
buf.dwords[0] = htonl ( MLX_GET ( &stat_cfg, mac_high ) );
|
||||
buf.dwords[1] = htonl ( MLX_GET ( &stat_cfg, mac_low ) );
|
||||
memcpy ( mac, &buf.bytes[ sizeof ( buf.bytes ) - ETH_ALEN ],
|
||||
ETH_ALEN );
|
||||
|
||||
DBGC ( hermon, "Hermon %p port %d harvested MAC address %s\n",
|
||||
hermon, mport, eth_ntoa ( mac ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Ethernet MAC for BOFM
|
||||
*
|
||||
* @v bofm BOFM device
|
||||
* @v mport Multi-port index
|
||||
* @v mac MAC to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int hermon_bofm_update ( struct bofm_device *bofm, unsigned int mport,
|
||||
const uint8_t *mac ) {
|
||||
struct hermon *hermon = container_of ( bofm, struct hermon, bofm );
|
||||
struct hermonprm_mod_stat_cfg stat_cfg;
|
||||
union {
|
||||
uint8_t bytes[8];
|
||||
uint32_t dwords[2];
|
||||
} buf;
|
||||
int rc;
|
||||
|
||||
/* Prepare MAC address */
|
||||
memset ( &buf, 0, sizeof ( buf ) );
|
||||
memcpy ( &buf.bytes[ sizeof ( buf.bytes ) - ETH_ALEN ], mac,
|
||||
ETH_ALEN );
|
||||
|
||||
/* Modify static configuration */
|
||||
memset ( &stat_cfg, 0, sizeof ( stat_cfg ) );
|
||||
MLX_FILL_2 ( &stat_cfg, 36,
|
||||
mac_m, 1,
|
||||
mac_high, ntohl ( buf.dwords[0] ) );
|
||||
MLX_FILL_1 ( &stat_cfg, 37, mac_low, ntohl ( buf.dwords[1] ) );
|
||||
if ( ( rc = hermon_mod_stat_cfg ( hermon, mport,
|
||||
HERMON_MOD_STAT_CFG_SET,
|
||||
HERMON_MOD_STAT_CFG_OFFSET ( mac_m ),
|
||||
&stat_cfg ) ) != 0 ) {
|
||||
DBGC ( hermon, "Hermon %p port %d could not modify "
|
||||
"configuration: %s\n", hermon, mport, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
DBGC ( hermon, "Hermon %p port %d updated MAC address to %s\n",
|
||||
hermon, mport, eth_ntoa ( mac ) );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Hermon BOFM operations */
|
||||
static struct bofm_operations hermon_bofm_operations = {
|
||||
.harvest = hermon_bofm_harvest,
|
||||
.update = hermon_bofm_update,
|
||||
};
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* PCI interface
|
||||
@@ -3325,6 +3487,72 @@ static void hermon_reset ( struct hermon *hermon,
|
||||
pci_restore ( pci, &backup, backup_exclude );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate Hermon device
|
||||
*
|
||||
* @v pci PCI device
|
||||
* @v id PCI ID
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static struct hermon * hermon_alloc ( void ) {
|
||||
struct hermon *hermon;
|
||||
|
||||
/* Allocate Hermon device */
|
||||
hermon = zalloc ( sizeof ( *hermon ) );
|
||||
if ( ! hermon )
|
||||
goto err_hermon;
|
||||
|
||||
/* Allocate space for mailboxes */
|
||||
hermon->mailbox_in = malloc_dma ( HERMON_MBOX_SIZE,
|
||||
HERMON_MBOX_ALIGN );
|
||||
if ( ! hermon->mailbox_in )
|
||||
goto err_mailbox_in;
|
||||
hermon->mailbox_out = malloc_dma ( HERMON_MBOX_SIZE,
|
||||
HERMON_MBOX_ALIGN );
|
||||
if ( ! hermon->mailbox_out )
|
||||
goto err_mailbox_out;
|
||||
|
||||
return hermon;
|
||||
|
||||
free_dma ( hermon->mailbox_out, HERMON_MBOX_SIZE );
|
||||
err_mailbox_out:
|
||||
free_dma ( hermon->mailbox_in, HERMON_MBOX_SIZE );
|
||||
err_mailbox_in:
|
||||
free ( hermon );
|
||||
err_hermon:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free Hermon device
|
||||
*
|
||||
* @v hermon Hermon device
|
||||
*/
|
||||
static void hermon_free ( struct hermon *hermon ) {
|
||||
|
||||
free_dma ( hermon->mailbox_out, HERMON_MBOX_SIZE );
|
||||
free_dma ( hermon->mailbox_in, HERMON_MBOX_SIZE );
|
||||
free ( hermon );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise Hermon PCI parameters
|
||||
*
|
||||
* @v hermon Hermon device
|
||||
* @v pci PCI device
|
||||
*/
|
||||
static void hermon_pci_init ( struct hermon *hermon, struct pci_device *pci ) {
|
||||
|
||||
/* Fix up PCI device */
|
||||
adjust_pci_device ( pci );
|
||||
|
||||
/* Get PCI BARs */
|
||||
hermon->config = ioremap ( pci_bar_start ( pci, HERMON_PCI_CONFIG_BAR),
|
||||
HERMON_PCI_CONFIG_BAR_SIZE );
|
||||
hermon->uar = ioremap ( pci_bar_start ( pci, HERMON_PCI_UAR_BAR ),
|
||||
HERMON_UAR_NON_EQ_PAGE * HERMON_PAGE_SIZE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe PCI device
|
||||
*
|
||||
@@ -3342,39 +3570,19 @@ static int hermon_probe ( struct pci_device *pci ) {
|
||||
int rc;
|
||||
|
||||
/* Allocate Hermon device */
|
||||
hermon = zalloc ( sizeof ( *hermon ) );
|
||||
hermon = hermon_alloc();
|
||||
if ( ! hermon ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc_hermon;
|
||||
goto err_alloc;
|
||||
}
|
||||
pci_set_drvdata ( pci, hermon );
|
||||
|
||||
/* Fix up PCI device */
|
||||
adjust_pci_device ( pci );
|
||||
|
||||
/* Get PCI BARs */
|
||||
hermon->config = ioremap ( pci_bar_start ( pci, HERMON_PCI_CONFIG_BAR),
|
||||
HERMON_PCI_CONFIG_BAR_SIZE );
|
||||
hermon->uar = ioremap ( pci_bar_start ( pci, HERMON_PCI_UAR_BAR ),
|
||||
HERMON_UAR_NON_EQ_PAGE * HERMON_PAGE_SIZE );
|
||||
/* Initialise PCI parameters */
|
||||
hermon_pci_init ( hermon, pci );
|
||||
|
||||
/* Reset device */
|
||||
hermon_reset ( hermon, pci );
|
||||
|
||||
/* Allocate space for mailboxes */
|
||||
hermon->mailbox_in = malloc_dma ( HERMON_MBOX_SIZE,
|
||||
HERMON_MBOX_ALIGN );
|
||||
if ( ! hermon->mailbox_in ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_mailbox_in;
|
||||
}
|
||||
hermon->mailbox_out = malloc_dma ( HERMON_MBOX_SIZE,
|
||||
HERMON_MBOX_ALIGN );
|
||||
if ( ! hermon->mailbox_out ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_mailbox_out;
|
||||
}
|
||||
|
||||
/* Start firmware */
|
||||
if ( ( rc = hermon_start_firmware ( hermon ) ) != 0 )
|
||||
goto err_start_firmware;
|
||||
@@ -3483,12 +3691,8 @@ static int hermon_probe ( struct pci_device *pci ) {
|
||||
err_get_cap:
|
||||
hermon_stop_firmware ( hermon );
|
||||
err_start_firmware:
|
||||
free_dma ( hermon->mailbox_out, HERMON_MBOX_SIZE );
|
||||
err_mailbox_out:
|
||||
free_dma ( hermon->mailbox_in, HERMON_MBOX_SIZE );
|
||||
err_mailbox_in:
|
||||
free ( hermon );
|
||||
err_alloc_hermon:
|
||||
hermon_free ( hermon );
|
||||
err_alloc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -3511,15 +3715,65 @@ static void hermon_remove ( struct pci_device *pci ) {
|
||||
hermon_free_icm ( hermon );
|
||||
hermon_stop_firmware ( hermon );
|
||||
hermon_stop_firmware ( hermon );
|
||||
free_dma ( hermon->mailbox_out, HERMON_MBOX_SIZE );
|
||||
free_dma ( hermon->mailbox_in, HERMON_MBOX_SIZE );
|
||||
for ( i = ( hermon->cap.num_ports - 1 ) ; i >= 0 ; i-- ) {
|
||||
netdev_nullify ( hermon->port[i].netdev );
|
||||
netdev_put ( hermon->port[i].netdev );
|
||||
}
|
||||
for ( i = ( hermon->cap.num_ports - 1 ) ; i >= 0 ; i-- )
|
||||
ibdev_put ( hermon->port[i].ibdev );
|
||||
free ( hermon );
|
||||
hermon_free ( hermon );
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe PCI device for BOFM
|
||||
*
|
||||
* @v pci PCI device
|
||||
* @v id PCI ID
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int hermon_bofm_probe ( struct pci_device *pci ) {
|
||||
struct hermon *hermon;
|
||||
int rc;
|
||||
|
||||
/* Allocate Hermon device */
|
||||
hermon = hermon_alloc();
|
||||
if ( ! hermon ) {
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc;
|
||||
}
|
||||
pci_set_drvdata ( pci, hermon );
|
||||
|
||||
/* Initialise PCI parameters */
|
||||
hermon_pci_init ( hermon, pci );
|
||||
|
||||
/* Initialise BOFM device */
|
||||
bofm_init ( &hermon->bofm, pci, &hermon_bofm_operations );
|
||||
|
||||
/* Register BOFM device */
|
||||
if ( ( rc = bofm_register ( &hermon->bofm ) ) != 0 ) {
|
||||
DBGC ( hermon, "Hermon %p could not register BOFM device: "
|
||||
"%s\n", hermon, strerror ( rc ) );
|
||||
goto err_bofm_register;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_bofm_register:
|
||||
hermon_free ( hermon );
|
||||
err_alloc:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove PCI device for BOFM
|
||||
*
|
||||
* @v pci PCI device
|
||||
*/
|
||||
static void hermon_bofm_remove ( struct pci_device *pci ) {
|
||||
struct hermon *hermon = pci_get_drvdata ( pci );
|
||||
|
||||
bofm_unregister ( &hermon->bofm );
|
||||
hermon_free ( hermon );
|
||||
}
|
||||
|
||||
static struct pci_device_id hermon_nics[] = {
|
||||
@@ -3543,3 +3797,10 @@ struct pci_driver hermon_driver __pci_driver = {
|
||||
.probe = hermon_probe,
|
||||
.remove = hermon_remove,
|
||||
};
|
||||
|
||||
struct pci_driver hermon_bofm_driver __bofm_driver = {
|
||||
.ids = hermon_nics,
|
||||
.id_count = ( sizeof ( hermon_nics ) / sizeof ( hermon_nics[0] ) ),
|
||||
.probe = hermon_bofm_probe,
|
||||
.remove = hermon_bofm_remove,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user