diff options
author | Jon Mason <jon.mason@exar.com> | 2010-11-10 23:25:57 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-11-11 12:30:21 -0500 |
commit | e8ac175615b9458a00193c55617b5b8865e67817 (patch) | |
tree | 31c688b4b9d2a3578ef712d05534bca4395e6281 /drivers/net/vxge/vxge-main.c | |
parent | 8424e00dfd5282026a93996a165fc4079d382169 (diff) |
vxge: add support for ethtool firmware flashing
Add the ability in the vxge driver to flash firmware via ethtool.
Updated to include comments from Ben Hutchings.
Signed-off-by: Jon Mason <jon.mason@exar.com>
Signed-off-by: Ram Vepa <ram.vepa@exar.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/vxge/vxge-main.c')
-rw-r--r-- | drivers/net/vxge/vxge-main.c | 190 |
1 files changed, 174 insertions, 16 deletions
diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 53db6a4b9601..10549bd39221 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <net/ip.h> | 50 | #include <net/ip.h> |
51 | #include <linux/netdevice.h> | 51 | #include <linux/netdevice.h> |
52 | #include <linux/etherdevice.h> | 52 | #include <linux/etherdevice.h> |
53 | #include <linux/firmware.h> | ||
53 | #include "vxge-main.h" | 54 | #include "vxge-main.h" |
54 | #include "vxge-reg.h" | 55 | #include "vxge-reg.h" |
55 | 56 | ||
@@ -3248,6 +3249,7 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev, | |||
3248 | "%s: Ethernet device registered", | 3249 | "%s: Ethernet device registered", |
3249 | ndev->name); | 3250 | ndev->name); |
3250 | 3251 | ||
3252 | hldev->ndev = ndev; | ||
3251 | *vdev_out = vdev; | 3253 | *vdev_out = vdev; |
3252 | 3254 | ||
3253 | /* Resetting the Device stats */ | 3255 | /* Resetting the Device stats */ |
@@ -3935,6 +3937,142 @@ static inline u32 vxge_get_num_vfs(u64 function_mode) | |||
3935 | return num_functions; | 3937 | return num_functions; |
3936 | } | 3938 | } |
3937 | 3939 | ||
3940 | int vxge_fw_upgrade(struct vxgedev *vdev, char *fw_name, int override) | ||
3941 | { | ||
3942 | struct __vxge_hw_device *hldev = vdev->devh; | ||
3943 | u32 maj, min, bld, cmaj, cmin, cbld; | ||
3944 | enum vxge_hw_status status; | ||
3945 | const struct firmware *fw; | ||
3946 | int ret; | ||
3947 | |||
3948 | ret = request_firmware(&fw, fw_name, &vdev->pdev->dev); | ||
3949 | if (ret) { | ||
3950 | vxge_debug_init(VXGE_ERR, "%s: Firmware file '%s' not found", | ||
3951 | VXGE_DRIVER_NAME, fw_name); | ||
3952 | goto out; | ||
3953 | } | ||
3954 | |||
3955 | /* Load the new firmware onto the adapter */ | ||
3956 | status = vxge_update_fw_image(hldev, fw->data, fw->size); | ||
3957 | if (status != VXGE_HW_OK) { | ||
3958 | vxge_debug_init(VXGE_ERR, | ||
3959 | "%s: FW image download to adapter failed '%s'.", | ||
3960 | VXGE_DRIVER_NAME, fw_name); | ||
3961 | ret = -EIO; | ||
3962 | goto out; | ||
3963 | } | ||
3964 | |||
3965 | /* Read the version of the new firmware */ | ||
3966 | status = vxge_hw_upgrade_read_version(hldev, &maj, &min, &bld); | ||
3967 | if (status != VXGE_HW_OK) { | ||
3968 | vxge_debug_init(VXGE_ERR, | ||
3969 | "%s: Upgrade read version failed '%s'.", | ||
3970 | VXGE_DRIVER_NAME, fw_name); | ||
3971 | ret = -EIO; | ||
3972 | goto out; | ||
3973 | } | ||
3974 | |||
3975 | cmaj = vdev->config.device_hw_info.fw_version.major; | ||
3976 | cmin = vdev->config.device_hw_info.fw_version.minor; | ||
3977 | cbld = vdev->config.device_hw_info.fw_version.build; | ||
3978 | /* It's possible the version in /lib/firmware is not the latest version. | ||
3979 | * If so, we could get into a loop of trying to upgrade to the latest | ||
3980 | * and flashing the older version. | ||
3981 | */ | ||
3982 | if (VXGE_FW_VER(maj, min, bld) == VXGE_FW_VER(cmaj, cmin, cbld) && | ||
3983 | !override) { | ||
3984 | ret = -EINVAL; | ||
3985 | goto out; | ||
3986 | } | ||
3987 | |||
3988 | printk(KERN_NOTICE "Upgrade to firmware version %d.%d.%d commencing\n", | ||
3989 | maj, min, bld); | ||
3990 | |||
3991 | /* Flash the adapter with the new firmware */ | ||
3992 | status = vxge_hw_flash_fw(hldev); | ||
3993 | if (status != VXGE_HW_OK) { | ||
3994 | vxge_debug_init(VXGE_ERR, "%s: Upgrade commit failed '%s'.", | ||
3995 | VXGE_DRIVER_NAME, fw_name); | ||
3996 | ret = -EIO; | ||
3997 | goto out; | ||
3998 | } | ||
3999 | |||
4000 | printk(KERN_NOTICE "Upgrade of firmware successful! Adapter must be " | ||
4001 | "hard reset before using, thus requiring a system reboot or a " | ||
4002 | "hotplug event.\n"); | ||
4003 | |||
4004 | out: | ||
4005 | return ret; | ||
4006 | } | ||
4007 | |||
4008 | static int vxge_probe_fw_update(struct vxgedev *vdev) | ||
4009 | { | ||
4010 | u32 maj, min, bld; | ||
4011 | int ret, gpxe = 0; | ||
4012 | char *fw_name; | ||
4013 | |||
4014 | maj = vdev->config.device_hw_info.fw_version.major; | ||
4015 | min = vdev->config.device_hw_info.fw_version.minor; | ||
4016 | bld = vdev->config.device_hw_info.fw_version.build; | ||
4017 | |||
4018 | if (VXGE_FW_VER(maj, min, bld) == VXGE_CERT_FW_VER) | ||
4019 | return 0; | ||
4020 | |||
4021 | /* Ignore the build number when determining if the current firmware is | ||
4022 | * "too new" to load the driver | ||
4023 | */ | ||
4024 | if (VXGE_FW_VER(maj, min, 0) > VXGE_CERT_FW_VER) { | ||
4025 | vxge_debug_init(VXGE_ERR, "%s: Firmware newer than last known " | ||
4026 | "version, unable to load driver\n", | ||
4027 | VXGE_DRIVER_NAME); | ||
4028 | return -EINVAL; | ||
4029 | } | ||
4030 | |||
4031 | /* Firmware 1.4.4 and older cannot be upgraded, and is too ancient to | ||
4032 | * work with this driver. | ||
4033 | */ | ||
4034 | if (VXGE_FW_VER(maj, min, bld) <= VXGE_FW_DEAD_VER) { | ||
4035 | vxge_debug_init(VXGE_ERR, "%s: Firmware %d.%d.%d cannot be " | ||
4036 | "upgraded\n", VXGE_DRIVER_NAME, maj, min, bld); | ||
4037 | return -EINVAL; | ||
4038 | } | ||
4039 | |||
4040 | /* If file not specified, determine gPXE or not */ | ||
4041 | if (VXGE_FW_VER(maj, min, bld) >= VXGE_EPROM_FW_VER) { | ||
4042 | int i; | ||
4043 | for (i = 0; i < VXGE_HW_MAX_ROM_IMAGES; i++) | ||
4044 | if (vdev->devh->eprom_versions[i]) { | ||
4045 | gpxe = 1; | ||
4046 | break; | ||
4047 | } | ||
4048 | } | ||
4049 | if (gpxe) | ||
4050 | fw_name = "vxge/X3fw-pxe.ncf"; | ||
4051 | else | ||
4052 | fw_name = "vxge/X3fw.ncf"; | ||
4053 | |||
4054 | ret = vxge_fw_upgrade(vdev, fw_name, 0); | ||
4055 | /* -EINVAL and -ENOENT are not fatal errors for flashing firmware on | ||
4056 | * probe, so ignore them | ||
4057 | */ | ||
4058 | if (ret != -EINVAL && ret != -ENOENT) | ||
4059 | return -EIO; | ||
4060 | else | ||
4061 | ret = 0; | ||
4062 | |||
4063 | if (VXGE_FW_VER(VXGE_CERT_FW_VER_MAJOR, VXGE_CERT_FW_VER_MINOR, 0) > | ||
4064 | VXGE_FW_VER(maj, min, 0)) { | ||
4065 | vxge_debug_init(VXGE_ERR, "%s: Firmware %d.%d.%d is too old to" | ||
4066 | " be used with this driver.\n" | ||
4067 | "Please get the latest version from " | ||
4068 | "ftp://ftp.s2io.com/pub/X3100-Drivers/FIRMWARE", | ||
4069 | VXGE_DRIVER_NAME, maj, min, bld); | ||
4070 | return -EINVAL; | ||
4071 | } | ||
4072 | |||
4073 | return ret; | ||
4074 | } | ||
4075 | |||
3938 | /** | 4076 | /** |
3939 | * vxge_probe | 4077 | * vxge_probe |
3940 | * @pdev : structure containing the PCI related information of the device. | 4078 | * @pdev : structure containing the PCI related information of the device. |
@@ -4093,16 +4231,6 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) | |||
4093 | goto _exit3; | 4231 | goto _exit3; |
4094 | } | 4232 | } |
4095 | 4233 | ||
4096 | if (ll_config->device_hw_info.fw_version.major != | ||
4097 | VXGE_DRIVER_FW_VERSION_MAJOR) { | ||
4098 | vxge_debug_init(VXGE_ERR, | ||
4099 | "%s: Incorrect firmware version." | ||
4100 | "Please upgrade the firmware to version 1.x.x", | ||
4101 | VXGE_DRIVER_NAME); | ||
4102 | ret = -EINVAL; | ||
4103 | goto _exit3; | ||
4104 | } | ||
4105 | |||
4106 | vpath_mask = ll_config->device_hw_info.vpath_mask; | 4234 | vpath_mask = ll_config->device_hw_info.vpath_mask; |
4107 | if (vpath_mask == 0) { | 4235 | if (vpath_mask == 0) { |
4108 | vxge_debug_ll_config(VXGE_TRACE, | 4236 | vxge_debug_ll_config(VXGE_TRACE, |
@@ -4166,6 +4294,32 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) | |||
4166 | goto _exit3; | 4294 | goto _exit3; |
4167 | } | 4295 | } |
4168 | 4296 | ||
4297 | if (VXGE_FW_VER(ll_config->device_hw_info.fw_version.major, | ||
4298 | ll_config->device_hw_info.fw_version.minor, | ||
4299 | ll_config->device_hw_info.fw_version.build) >= | ||
4300 | VXGE_EPROM_FW_VER) { | ||
4301 | struct eprom_image img[VXGE_HW_MAX_ROM_IMAGES]; | ||
4302 | |||
4303 | status = vxge_hw_vpath_eprom_img_ver_get(hldev, img); | ||
4304 | if (status != VXGE_HW_OK) { | ||
4305 | vxge_debug_init(VXGE_ERR, "%s: Reading of EPROM failed", | ||
4306 | VXGE_DRIVER_NAME); | ||
4307 | /* This is a non-fatal error, continue */ | ||
4308 | } | ||
4309 | |||
4310 | for (i = 0; i < VXGE_HW_MAX_ROM_IMAGES; i++) { | ||
4311 | hldev->eprom_versions[i] = img[i].version; | ||
4312 | if (!img[i].is_valid) | ||
4313 | break; | ||
4314 | vxge_debug_init(VXGE_TRACE, "%s: EPROM %d, version " | ||
4315 | "%d.%d.%d.%d\n", VXGE_DRIVER_NAME, i, | ||
4316 | VXGE_EPROM_IMG_MAJOR(img[i].version), | ||
4317 | VXGE_EPROM_IMG_MINOR(img[i].version), | ||
4318 | VXGE_EPROM_IMG_FIX(img[i].version), | ||
4319 | VXGE_EPROM_IMG_BUILD(img[i].version)); | ||
4320 | } | ||
4321 | } | ||
4322 | |||
4169 | /* if FCS stripping is not disabled in MAC fail driver load */ | 4323 | /* if FCS stripping is not disabled in MAC fail driver load */ |
4170 | if (vxge_hw_vpath_strip_fcs_check(hldev, vpath_mask) != VXGE_HW_OK) { | 4324 | if (vxge_hw_vpath_strip_fcs_check(hldev, vpath_mask) != VXGE_HW_OK) { |
4171 | vxge_debug_init(VXGE_ERR, | 4325 | vxge_debug_init(VXGE_ERR, |
@@ -4194,18 +4348,22 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) | |||
4194 | ll_config->tx_pause_enable = VXGE_PAUSE_CTRL_ENABLE; | 4348 | ll_config->tx_pause_enable = VXGE_PAUSE_CTRL_ENABLE; |
4195 | ll_config->rx_pause_enable = VXGE_PAUSE_CTRL_ENABLE; | 4349 | ll_config->rx_pause_enable = VXGE_PAUSE_CTRL_ENABLE; |
4196 | 4350 | ||
4197 | if (vxge_device_register(hldev, ll_config, high_dma, no_of_vpath, | 4351 | ret = vxge_device_register(hldev, ll_config, high_dma, no_of_vpath, |
4198 | &vdev)) { | 4352 | &vdev); |
4353 | if (ret) { | ||
4199 | ret = -EINVAL; | 4354 | ret = -EINVAL; |
4200 | goto _exit4; | 4355 | goto _exit4; |
4201 | } | 4356 | } |
4202 | 4357 | ||
4358 | ret = vxge_probe_fw_update(vdev); | ||
4359 | if (ret) | ||
4360 | goto _exit5; | ||
4361 | |||
4203 | vxge_hw_device_debug_set(hldev, VXGE_TRACE, VXGE_COMPONENT_LL); | 4362 | vxge_hw_device_debug_set(hldev, VXGE_TRACE, VXGE_COMPONENT_LL); |
4204 | VXGE_COPY_DEBUG_INFO_TO_LL(vdev, vxge_hw_device_error_level_get(hldev), | 4363 | VXGE_COPY_DEBUG_INFO_TO_LL(vdev, vxge_hw_device_error_level_get(hldev), |
4205 | vxge_hw_device_trace_level_get(hldev)); | 4364 | vxge_hw_device_trace_level_get(hldev)); |
4206 | 4365 | ||
4207 | /* set private HW device info */ | 4366 | /* set private HW device info */ |
4208 | hldev->ndev = vdev->ndev; | ||
4209 | vdev->mtu = VXGE_HW_DEFAULT_MTU; | 4367 | vdev->mtu = VXGE_HW_DEFAULT_MTU; |
4210 | vdev->bar0 = attr.bar0; | 4368 | vdev->bar0 = attr.bar0; |
4211 | vdev->max_vpath_supported = max_vpath_supported; | 4369 | vdev->max_vpath_supported = max_vpath_supported; |
@@ -4307,7 +4465,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) | |||
4307 | "%s: mac_addr_list : memory allocation failed", | 4465 | "%s: mac_addr_list : memory allocation failed", |
4308 | vdev->ndev->name); | 4466 | vdev->ndev->name); |
4309 | ret = -EPERM; | 4467 | ret = -EPERM; |
4310 | goto _exit5; | 4468 | goto _exit6; |
4311 | } | 4469 | } |
4312 | macaddr = (u8 *)&entry->macaddr; | 4470 | macaddr = (u8 *)&entry->macaddr; |
4313 | memcpy(macaddr, vdev->ndev->dev_addr, ETH_ALEN); | 4471 | memcpy(macaddr, vdev->ndev->dev_addr, ETH_ALEN); |
@@ -4347,10 +4505,10 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre) | |||
4347 | kfree(ll_config); | 4505 | kfree(ll_config); |
4348 | return 0; | 4506 | return 0; |
4349 | 4507 | ||
4350 | _exit5: | 4508 | _exit6: |
4351 | for (i = 0; i < vdev->no_of_vpath; i++) | 4509 | for (i = 0; i < vdev->no_of_vpath; i++) |
4352 | vxge_free_mac_add_list(&vdev->vpaths[i]); | 4510 | vxge_free_mac_add_list(&vdev->vpaths[i]); |
4353 | 4511 | _exit5: | |
4354 | vxge_device_unregister(hldev); | 4512 | vxge_device_unregister(hldev); |
4355 | _exit4: | 4513 | _exit4: |
4356 | pci_disable_sriov(pdev); | 4514 | pci_disable_sriov(pdev); |