Skip to content

Commit

Permalink
cxgb4: update set_flash to flash different images
Browse files Browse the repository at this point in the history
Chelsio adapter contains different flash regions and each
region is used by different binary files. This patch adds
support to flash images like PHY firmware, boot and boot config
using ethtool -f N.

The N value mapping is as follows.
N = 0 : Parse image and decide which region to flash
N = 1 : Firmware
N = 2 : PHY firmware
N = 3 : boot image
N = 4 : boot cfg

Signed-off-by: Vishal Kulkarni <vishal@chelsio.com>"
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Vishal Kulkarni authored and David S. Miller committed Jun 19, 2020
1 parent 0fb9fba commit 3893c90
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 15 deletions.
9 changes: 9 additions & 0 deletions drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@ enum cc_fec {
FEC_BASER_RS = 1 << 2 /* BaseR/Reed-Solomon */
};

enum {
CXGB4_ETHTOOL_FLASH_FW = 1,
};

struct port_stats {
u64 tx_octets; /* total # of octets in good frames */
u64 tx_frames; /* all good frames */
Expand Down Expand Up @@ -492,6 +496,11 @@ struct trace_params {
unsigned char port;
};

struct cxgb4_fw_data {
__be32 signature;
__u8 reserved[4];
};

/* Firmware Port Capabilities types. */

typedef u16 fw_port_cap16_t; /* 16-bit Port Capabilities integral value */
Expand Down
121 changes: 106 additions & 15 deletions drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ static void set_msglevel(struct net_device *dev, u32 val)
netdev2adap(dev)->msg_enable = val;
}

static const char * const flash_region_strings[] = {
"All",
"Firmware",
};

static const char stats_strings[][ETH_GSTRING_LEN] = {
"tx_octets_ok ",
"tx_frames_ok ",
Expand Down Expand Up @@ -1235,15 +1240,88 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
return err;
}

static int set_flash(struct net_device *netdev, struct ethtool_flash *ef)
static int cxgb4_ethtool_flash_fw(struct net_device *netdev,
const u8 *data, u32 size)
{
int ret;
const struct firmware *fw;
struct adapter *adap = netdev2adap(netdev);
unsigned int mbox = PCIE_FW_MASTER_M + 1;
u32 pcie_fw;
int ret;

/* If the adapter has been fully initialized then we'll go ahead and
* try to get the firmware's cooperation in upgrading to the new
* firmware image otherwise we'll try to do the entire job from the
* host ... and we always "force" the operation in this path.
*/
if (adap->flags & CXGB4_FULL_INIT_DONE)
mbox = adap->mbox;

ret = t4_fw_upgrade(adap, mbox, data, size, 1);
if (ret)
dev_err(adap->pdev_dev,
"Failed to flash firmware\n");

return ret;
}

static int cxgb4_ethtool_flash_region(struct net_device *netdev,
const u8 *data, u32 size, u32 region)
{
struct adapter *adap = netdev2adap(netdev);
int ret;

switch (region) {
case CXGB4_ETHTOOL_FLASH_FW:
ret = cxgb4_ethtool_flash_fw(netdev, data, size);
break;
default:
ret = -EOPNOTSUPP;
break;
}

if (!ret)
dev_info(adap->pdev_dev,
"loading %s successful, reload cxgb4 driver\n",
flash_region_strings[region]);
return ret;
}

#define CXGB4_FW_SIG 0x4368656c
#define CXGB4_FW_SIG_OFFSET 0x160

static int cxgb4_validate_fw_image(const u8 *data, u32 *size)
{
struct cxgb4_fw_data *header;

header = (struct cxgb4_fw_data *)&data[CXGB4_FW_SIG_OFFSET];
if (be32_to_cpu(header->signature) != CXGB4_FW_SIG)
return -EINVAL;

if (size)
*size = be16_to_cpu(((struct fw_hdr *)data)->len512) * 512;

return 0;
}

static int cxgb4_ethtool_get_flash_region(const u8 *data, u32 *size)
{
if (!cxgb4_validate_fw_image(data, size))
return CXGB4_ETHTOOL_FLASH_FW;

return -EOPNOTSUPP;
}

static int set_flash(struct net_device *netdev, struct ethtool_flash *ef)
{
struct adapter *adap = netdev2adap(netdev);
const struct firmware *fw;
unsigned int master;
u8 master_vld = 0;
const u8 *fw_data;
size_t fw_size;
u32 size = 0;
u32 pcie_fw;
int region;
int ret;

pcie_fw = t4_read_reg(adap, PCIE_FW_A);
master = PCIE_FW_MASTER_G(pcie_fw);
Expand All @@ -1261,19 +1339,32 @@ static int set_flash(struct net_device *netdev, struct ethtool_flash *ef)
if (ret < 0)
return ret;

/* If the adapter has been fully initialized then we'll go ahead and
* try to get the firmware's cooperation in upgrading to the new
* firmware image otherwise we'll try to do the entire job from the
* host ... and we always "force" the operation in this path.
*/
if (adap->flags & CXGB4_FULL_INIT_DONE)
mbox = adap->mbox;
fw_data = fw->data;
fw_size = fw->size;
if (ef->region == ETHTOOL_FLASH_ALL_REGIONS) {
while (fw_size > 0) {
size = 0;
region = cxgb4_ethtool_get_flash_region(fw_data, &size);
if (region < 0 || !size) {
ret = region;
goto out_free_fw;
}

ret = cxgb4_ethtool_flash_region(netdev, fw_data, size,
region);
if (ret)
goto out_free_fw;

fw_data += size;
fw_size -= size;
}
} else {
ret = cxgb4_ethtool_flash_region(netdev, fw_data, fw_size,
ef->region);
}

ret = t4_fw_upgrade(adap, mbox, fw->data, fw->size, 1);
out_free_fw:
release_firmware(fw);
if (!ret)
dev_info(adap->pdev_dev,
"loaded firmware %s, reload cxgb4 driver\n", ef->data);
return ret;
}

Expand Down

0 comments on commit 3893c90

Please sign in to comment.