]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
cxgb4: update set_flash to flash different images
authorVishal Kulkarni <vishal@chelsio.com>
Thu, 18 Jun 2020 06:05:52 +0000 (11:35 +0530)
committerDavid S. Miller <davem@davemloft.net>
Fri, 19 Jun 2020 03:49:55 +0000 (20:49 -0700)
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>
drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c

index cf69c6edcfec8f1e637b6b20fd3eb541fd45ffef..a7a1e1f5d554cb584efa77ddf459be975d2a81c0 100644 (file)
@@ -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 */
@@ -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 */
index 9fd496732b2ca57f679a21a282b74c09d1d02b27..92f79d0cd6ab13520a7d0e164a6daa905aadef02 100644 (file)
@@ -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           ",
@@ -1235,15 +1240,88 @@ out:
        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);
@@ -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;
 }