summaryrefslogtreecommitdiff
path: root/ethtool.c
diff options
context:
space:
mode:
authorAjit Khaparde <ajitk@serverengines.com>2009-09-03 08:33:08 +0530
committerJeff Garzik <jgarzik@redhat.com>2009-11-25 09:42:47 -0500
commit9efed0a996f30e1f2d2d33611b209fee6faabc2c (patch)
tree6c733c529a510aff40c5648de56c489e7e49857d /ethtool.c
parent0bae92474a3d96070c1235928d0ce821c051583c (diff)
downloadethtool-9efed0a996f30e1f2d2d33611b209fee6faabc2c.tar.gz
ethtool: Add option to flash firmware image from specified file, to a device.
This patch adds a new "-f" option to the ethtool utility to flash a firmware image specified by a file, to a network device. The filename is passed to the network driver which will flash the image on the chip using the request_firmware path. The region "on the chip" to be flashed can be specified by an option. It is up to the device driver to enumerate the region number passed by ethtool, to the region to be flashed. The default behavior is to flash all the regions on the chip. Usage: ethtool -f <interface name> <filename of firmware image> ethtool -f <interface name> <filename of firmware image> [ REGION-NUMBER-TO-FLASH ] Signed-off-by: Ajit Khaparde <ajitk@serverengines.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'ethtool.c')
-rw-r--r--ethtool.c55
1 files changed, 54 insertions, 1 deletions
diff --git a/ethtool.c b/ethtool.c
index a409e02..52915d6 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -77,6 +77,7 @@ static char *unparse_rxfhashopts(u64 opts);
static int dump_rxfhash(int fhash, u64 val);
static int do_srxclass(int fd, struct ifreq *ifr);
static int do_grxclass(int fd, struct ifreq *ifr);
+static int do_flash(int fd, struct ifreq *ifr);
static int send_ioctl(int fd, struct ifreq *ifr);
static enum {
@@ -101,6 +102,7 @@ static enum {
MODE_GSTATS,
MODE_GNFC,
MODE_SNFC,
+ MODE_FLASHDEV,
} mode = MODE_GSET;
static struct option {
@@ -188,6 +190,9 @@ static struct option {
"options",
" [ rx-flow-hash tcp4|udp4|ah4|sctp4|"
"tcp6|udp6|ah6|sctp6 ]\n" },
+ { "-f", "--flash", MODE_FLASHDEV, "FILENAME " "Flash firmware image "
+ "from the specified file to a region on the device",
+ " [ REGION-NUMBER-TO-FLASH ]\n" },
{ "-N", "--config-nfc", MODE_SNFC, "Configure Rx network flow "
"classification options",
" [ rx-flow-hash tcp4|udp4|ah4|sctp4|"
@@ -304,6 +309,9 @@ static int rx_fhash_get = 0;
static int rx_fhash_set = 0;
static u32 rx_fhash_val = 0;
static int rx_fhash_changed = 0;
+static char *flash_file = NULL;
+static int flash = -1;
+static int flash_region = -1;
static enum {
ONLINE=0,
OFFLINE,
@@ -496,7 +504,8 @@ static void parse_cmdline(int argc, char **argp)
(mode == MODE_GSTATS) ||
(mode == MODE_GNFC) ||
(mode == MODE_SNFC) ||
- (mode == MODE_PHYS_ID)) {
+ (mode == MODE_PHYS_ID) ||
+ (mode == MODE_FLASHDEV)) {
devname = argp[i];
break;
}
@@ -516,6 +525,10 @@ static void parse_cmdline(int argc, char **argp)
if (phys_id_time < 0)
show_usage(1);
break;
+ } else if (mode == MODE_FLASHDEV) {
+ flash_file = argp[i];
+ flash = 1;
+ break;
}
/* fallthrough */
default:
@@ -590,6 +603,12 @@ static void parse_cmdline(int argc, char **argp)
show_usage(1);
break;
}
+ if (mode == MODE_FLASHDEV) {
+ flash_region = strtol(argp[i], NULL, 0);
+ if ((flash_region < 0))
+ show_usage(1);
+ break;
+ }
if (mode == MODE_SNFC) {
if (!strcmp(argp[i], "rx-flow-hash")) {
i += 1;
@@ -1516,6 +1535,8 @@ static int doit(void)
return do_grxclass(fd, &ifr);
} else if (mode == MODE_SNFC) {
return do_srxclass(fd, &ifr);
+ } else if (mode == MODE_FLASHDEV) {
+ return do_flash(fd, &ifr);
}
return 69;
@@ -2410,6 +2431,38 @@ static int do_grxclass(int fd, struct ifreq *ifr)
return 0;
}
+static int do_flash(int fd, struct ifreq *ifr)
+{
+ struct ethtool_flash efl;
+ int err;
+
+ if (flash < 0) {
+ fprintf(stdout, "Missing filename argument\n");
+ show_usage(1);
+ return 98;
+ }
+
+ if (strlen(flash_file) > ETHTOOL_FLASH_MAX_FILENAME - 1) {
+ fprintf(stdout, "Filename too long\n");
+ return 99;
+ }
+
+ efl.cmd = ETHTOOL_FLASHDEV;
+ strcpy(efl.data, flash_file);
+
+ if (flash_region < 0)
+ efl.region = ETHTOOL_FLASH_ALL_REGIONS;
+ else
+ efl.region = flash_region;
+
+ ifr->ifr_data = (caddr_t)&efl;
+ err = send_ioctl(fd, ifr);
+ if (err < 0)
+ perror("Flashing failed");
+
+ return err;
+}
+
static int send_ioctl(int fd, struct ifreq *ifr)
{
return ioctl(fd, SIOCETHTOOL, ifr);