#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/ethtool.h>
+#include <linux/firmware.h>
 
 #include "nfpcore/nfp.h"
 #include "nfpcore/nfp_nsp.h"
        return nfp_net_set_num_rings(nn, total_rx, total_tx);
 }
 
+static int
+nfp_net_flash_device(struct net_device *netdev, struct ethtool_flash *flash)
+{
+       const struct firmware *fw;
+       struct nfp_app *app;
+       struct nfp_nsp *nsp;
+       struct device *dev;
+       int err;
+
+       if (flash->region != ETHTOOL_FLASH_ALL_REGIONS)
+               return -EOPNOTSUPP;
+
+       app = nfp_app_from_netdev(netdev);
+       if (!app)
+               return -EOPNOTSUPP;
+
+       dev = &app->pdev->dev;
+
+       nsp = nfp_nsp_open(app->cpp);
+       if (IS_ERR(nsp)) {
+               err = PTR_ERR(nsp);
+               dev_err(dev, "Failed to access the NSP: %d\n", err);
+               return err;
+       }
+
+       err = request_firmware_direct(&fw, flash->data, dev);
+       if (err)
+               goto exit_close_nsp;
+
+       dev_info(dev, "Please be patient while writing flash image: %s\n",
+                flash->data);
+       dev_hold(netdev);
+       rtnl_unlock();
+
+       err = nfp_nsp_write_flash(nsp, fw);
+       if (err < 0) {
+               dev_err(dev, "Flash write failed: %d\n", err);
+               goto exit_rtnl_lock;
+       }
+       dev_info(dev, "Finished writing flash image\n");
+
+exit_rtnl_lock:
+       rtnl_lock();
+       dev_put(netdev);
+       release_firmware(fw);
+
+exit_close_nsp:
+       nfp_nsp_close(nsp);
+       return err;
+}
+
 static const struct ethtool_ops nfp_net_ethtool_ops = {
        .get_drvinfo            = nfp_net_get_drvinfo,
        .get_link               = ethtool_op_get_link,
        .get_sset_count         = nfp_net_get_sset_count,
        .get_rxnfc              = nfp_net_get_rxnfc,
        .set_rxnfc              = nfp_net_set_rxnfc,
+       .flash_device           = nfp_net_flash_device,
        .get_rxfh_indir_size    = nfp_net_get_rxfh_indir_size,
        .get_rxfh_key_size      = nfp_net_get_rxfh_key_size,
        .get_rxfh               = nfp_net_get_rxfh,
        .get_strings            = nfp_port_get_strings,
        .get_ethtool_stats      = nfp_port_get_stats,
        .get_sset_count         = nfp_port_get_sset_count,
+       .flash_device           = nfp_net_flash_device,
        .set_dump               = nfp_app_set_dump,
        .get_dump_flag          = nfp_app_get_dump_flag,
        .get_dump_data          = nfp_app_get_dump_data,
 
        SPCODE_FW_LOAD          = 6, /* Load fw from buffer, len in option */
        SPCODE_ETH_RESCAN       = 7, /* Rescan ETHs, write ETH_TABLE to buf */
        SPCODE_ETH_CONTROL      = 8, /* Update media config from buffer */
+       SPCODE_NSP_WRITE_FLASH  = 11, /* Load and flash image from buffer */
        SPCODE_NSP_SENSORS      = 12, /* Read NSP sensor(s) */
        SPCODE_NSP_IDENTIFY     = 13, /* Read NSP version */
 };
                                   fw->size, NULL, 0);
 }
 
+int nfp_nsp_write_flash(struct nfp_nsp *state, const struct firmware *fw)
+{
+       /* The flash time is specified to take a maximum of 70s so we add an
+        * additional factor to this spec time.
+        */
+       u32 timeout_sec = 2.5 * 70;
+
+       return __nfp_nsp_command_buf(state, SPCODE_NSP_WRITE_FLASH, fw->size,
+                                    fw->data, fw->size, NULL, 0, timeout_sec);
+}
+
 int nfp_nsp_read_eth_table(struct nfp_nsp *state, void *buf, unsigned int size)
 {
        return nfp_nsp_command_buf(state, SPCODE_ETH_RESCAN, size, NULL, 0,