cxgb4: add support to flash boot cfg image
authorVishal Kulkarni <vishal@chelsio.com>
Thu, 18 Jun 2020 06:05:55 +0000 (11:35 +0530)
committerDavid S. Miller <davem@davemloft.net>
Fri, 19 Jun 2020 03:49:55 +0000 (20:49 -0700)
Update set_flash to flash boot cfg image to flash region

Signed-off-by: Vishal Kulkarni <vishal@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c

index 7b5f1869d8e7f82ffb2303f66bf6f153ff189a83..999816273328e2d22703fde59f1a254ae52ef155 100644 (file)
@@ -143,6 +143,12 @@ enum {
        CXGB4_ETHTOOL_FLASH_FW = 1,
        CXGB4_ETHTOOL_FLASH_PHY = 2,
        CXGB4_ETHTOOL_FLASH_BOOT = 3,
+       CXGB4_ETHTOOL_FLASH_BOOTCFG = 4
+};
+
+struct cxgb4_bootcfg_data {
+       __le16 signature;
+       __u8 reserved[2];
 };
 
 struct cxgb4_pcir_data {
@@ -183,6 +189,7 @@ struct legacy_pci_rom_hdr {
 
 /* BOOT constants */
 enum {
+       BOOT_CFG_SIG = 0x4243,
        BOOT_SIZE_INC = 512,
        BOOT_SIGNATURE = 0xaa55,
        BOOT_MIN_SIZE = sizeof(struct cxgb4_pci_exp_rom_header),
@@ -2046,6 +2053,8 @@ int t4_i2c_rd(struct adapter *adap, unsigned int mbox, int port,
              unsigned int len, u8 *buf);
 int t4_load_boot(struct adapter *adap, u8 *boot_data,
                 unsigned int boot_addr, unsigned int size);
+int t4_load_bootcfg(struct adapter *adap,
+                   const u8 *cfg_data, unsigned int size);
 void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq, struct sge_fl *fl);
 void free_tx_desc(struct adapter *adap, struct sge_txq *q,
                  unsigned int n, bool unmap);
index 29645252aa27ab89a10127aa6274c7bece82a422..0bfdc97e908362b9aef4d5aeb1d21adf63ee97f1 100644 (file)
@@ -28,6 +28,7 @@ static const char * const flash_region_strings[] = {
        "Firmware",
        "PHY Firmware",
        "Boot",
+       "Boot CFG",
 };
 
 static const char stats_strings[][ETH_GSTRING_LEN] = {
@@ -1242,6 +1243,19 @@ out:
        return err;
 }
 
+static int cxgb4_ethtool_flash_bootcfg(struct net_device *netdev,
+                                      const u8 *data, u32 size)
+{
+       struct adapter *adap = netdev2adap(netdev);
+       int ret;
+
+       ret = t4_load_bootcfg(adap, data, size);
+       if (ret)
+               dev_err(adap->pdev_dev, "Failed to load boot cfg image\n");
+
+       return ret;
+}
+
 static int cxgb4_ethtool_flash_boot(struct net_device *netdev,
                                    const u8 *bdata, u32 size)
 {
@@ -1336,6 +1350,9 @@ static int cxgb4_ethtool_flash_region(struct net_device *netdev,
        case CXGB4_ETHTOOL_FLASH_BOOT:
                ret = cxgb4_ethtool_flash_boot(netdev, data, size);
                break;
+       case CXGB4_ETHTOOL_FLASH_BOOTCFG:
+               ret = cxgb4_ethtool_flash_bootcfg(netdev, data, size);
+               break;
        default:
                ret = -EOPNOTSUPP;
                break;
@@ -1365,6 +1382,17 @@ static int cxgb4_validate_fw_image(const u8 *data, u32 *size)
        return 0;
 }
 
+static int cxgb4_validate_bootcfg_image(const u8 *data, u32 *size)
+{
+       struct cxgb4_bootcfg_data *header;
+
+       header = (struct cxgb4_bootcfg_data *)data;
+       if (le16_to_cpu(header->signature) != BOOT_CFG_SIG)
+               return -EINVAL;
+
+       return 0;
+}
+
 static int cxgb4_validate_boot_image(const u8 *data, u32 *size)
 {
        struct cxgb4_pci_exp_rom_header *exp_header;
@@ -1401,6 +1429,8 @@ static int cxgb4_ethtool_get_flash_region(const u8 *data, u32 *size)
                return CXGB4_ETHTOOL_FLASH_BOOT;
        if (!cxgb4_validate_phy_image(data, size))
                return CXGB4_ETHTOOL_FLASH_PHY;
+       if (!cxgb4_validate_bootcfg_image(data, size))
+               return CXGB4_ETHTOOL_FLASH_BOOTCFG;
 
        return -EOPNOTSUPP;
 }
index ccb550c6fab09d6e03d775bf02846a0001596332..9d557f3cd3aad259dc8175fc8482a1d922373fd4 100644 (file)
@@ -10668,3 +10668,93 @@ out:
                        ret);
        return ret;
 }
+
+/**
+ *     t4_flash_bootcfg_addr - return the address of the flash
+ *     optionrom configuration
+ *     @adapter: the adapter
+ *
+ *     Return the address within the flash where the OptionROM Configuration
+ *     is stored, or an error if the device FLASH is too small to contain
+ *     a OptionROM Configuration.
+ */
+static int t4_flash_bootcfg_addr(struct adapter *adapter)
+{
+       /**
+        * If the device FLASH isn't large enough to hold a Firmware
+        * Configuration File, return an error.
+        */
+       if (adapter->params.sf_size <
+           FLASH_BOOTCFG_START + FLASH_BOOTCFG_MAX_SIZE)
+               return -ENOSPC;
+
+       return FLASH_BOOTCFG_START;
+}
+
+int t4_load_bootcfg(struct adapter *adap, const u8 *cfg_data, unsigned int size)
+{
+       unsigned int sf_sec_size = adap->params.sf_size / adap->params.sf_nsec;
+       struct cxgb4_bootcfg_data *header;
+       unsigned int flash_cfg_start_sec;
+       unsigned int addr, npad;
+       int ret, i, n, cfg_addr;
+
+       cfg_addr = t4_flash_bootcfg_addr(adap);
+       if (cfg_addr < 0)
+               return cfg_addr;
+
+       addr = cfg_addr;
+       flash_cfg_start_sec = addr / SF_SEC_SIZE;
+
+       if (size > FLASH_BOOTCFG_MAX_SIZE) {
+               dev_err(adap->pdev_dev, "bootcfg file too large, max is %u bytes\n",
+                       FLASH_BOOTCFG_MAX_SIZE);
+               return -EFBIG;
+       }
+
+       header = (struct cxgb4_bootcfg_data *)cfg_data;
+       if (le16_to_cpu(header->signature) != BOOT_CFG_SIG) {
+               dev_err(adap->pdev_dev, "Wrong bootcfg signature\n");
+               ret = -EINVAL;
+               goto out;
+       }
+
+       i = DIV_ROUND_UP(FLASH_BOOTCFG_MAX_SIZE,
+                        sf_sec_size);
+       ret = t4_flash_erase_sectors(adap, flash_cfg_start_sec,
+                                    flash_cfg_start_sec + i - 1);
+
+       /**
+        * If size == 0 then we're simply erasing the FLASH sectors associated
+        * with the on-adapter OptionROM Configuration File.
+        */
+       if (ret || size == 0)
+               goto out;
+
+       /* this will write to the flash up to SF_PAGE_SIZE at a time */
+       for (i = 0; i < size; i += SF_PAGE_SIZE) {
+               n = min_t(u32, size - i, SF_PAGE_SIZE);
+
+               ret = t4_write_flash(adap, addr, n, cfg_data);
+               if (ret)
+                       goto out;
+
+               addr += SF_PAGE_SIZE;
+               cfg_data += SF_PAGE_SIZE;
+       }
+
+       npad = ((size + 4 - 1) & ~3) - size;
+       for (i = 0; i < npad; i++) {
+               u8 data = 0;
+
+               ret = t4_write_flash(adap, cfg_addr + size + i, 1, &data);
+               if (ret)
+                       goto out;
+       }
+
+out:
+       if (ret)
+               dev_err(adap->pdev_dev, "boot config data %s failed %d\n",
+                       (size == 0 ? "clear" : "download"), ret);
+       return ret;
+}