aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2010-08-12 01:04:31 -0400
committerRusty Russell <rusty@rustcorp.com.au>2010-08-11 09:34:32 -0400
commit7d3510356b066bcfa9898ec3f90c9c7810ba6ed7 (patch)
treeff39499bd06c42bc7cd3965f2491091ab937b9ee /drivers/net
parentd6d1b650ae6acce73d55dd0246de22180303ae73 (diff)
param: lock myri10ge_fw_name against sysfs changes.
Since it can be changed via sysfs, we need to make a copy. This most generic way of doing this is to keep a flag so we know when to free it. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Reviewed-by: Takashi Iwai <tiwai@suse.de> Cc: Andrew Gallatin <gallatin@myri.com> Cc: Brice Goglin <brice@myri.com> Cc: netdev@vger.kernel.org
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/myri10ge/myri10ge.c54
1 files changed, 41 insertions, 13 deletions
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index d771d1650d60..fb2c0927d3cc 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -239,6 +239,7 @@ struct myri10ge_priv {
239 int watchdog_resets; 239 int watchdog_resets;
240 int watchdog_pause; 240 int watchdog_pause;
241 int pause; 241 int pause;
242 bool fw_name_allocated;
242 char *fw_name; 243 char *fw_name;
243 char eeprom_strings[MYRI10GE_EEPROM_STRINGS_SIZE]; 244 char eeprom_strings[MYRI10GE_EEPROM_STRINGS_SIZE];
244 char *product_code_string; 245 char *product_code_string;
@@ -271,6 +272,7 @@ MODULE_FIRMWARE("myri10ge_eth_z8e.dat");
271MODULE_FIRMWARE("myri10ge_rss_ethp_z8e.dat"); 272MODULE_FIRMWARE("myri10ge_rss_ethp_z8e.dat");
272MODULE_FIRMWARE("myri10ge_rss_eth_z8e.dat"); 273MODULE_FIRMWARE("myri10ge_rss_eth_z8e.dat");
273 274
275/* Careful: must be accessed under kparam_block_sysfs_write */
274static char *myri10ge_fw_name = NULL; 276static char *myri10ge_fw_name = NULL;
275module_param(myri10ge_fw_name, charp, S_IRUGO | S_IWUSR); 277module_param(myri10ge_fw_name, charp, S_IRUGO | S_IWUSR);
276MODULE_PARM_DESC(myri10ge_fw_name, "Firmware image name"); 278MODULE_PARM_DESC(myri10ge_fw_name, "Firmware image name");
@@ -376,6 +378,14 @@ static inline void put_be32(__be32 val, __be32 __iomem * p)
376 378
377static struct net_device_stats *myri10ge_get_stats(struct net_device *dev); 379static struct net_device_stats *myri10ge_get_stats(struct net_device *dev);
378 380
381static void set_fw_name(struct myri10ge_priv *mgp, char *name, bool allocated)
382{
383 if (mgp->fw_name_allocated)
384 kfree(mgp->fw_name);
385 mgp->fw_name = name;
386 mgp->fw_name_allocated = allocated;
387}
388
379static int 389static int
380myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd, 390myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd,
381 struct myri10ge_cmd *data, int atomic) 391 struct myri10ge_cmd *data, int atomic)
@@ -747,7 +757,7 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp, int adopt)
747 dev_warn(&mgp->pdev->dev, "via hotplug\n"); 757 dev_warn(&mgp->pdev->dev, "via hotplug\n");
748 } 758 }
749 759
750 mgp->fw_name = "adopted"; 760 set_fw_name(mgp, "adopted", false);
751 mgp->tx_boundary = 2048; 761 mgp->tx_boundary = 2048;
752 myri10ge_dummy_rdma(mgp, 1); 762 myri10ge_dummy_rdma(mgp, 1);
753 status = myri10ge_get_firmware_capabilities(mgp); 763 status = myri10ge_get_firmware_capabilities(mgp);
@@ -3233,7 +3243,7 @@ static void myri10ge_firmware_probe(struct myri10ge_priv *mgp)
3233 * load the optimized firmware (which assumes aligned PCIe 3243 * load the optimized firmware (which assumes aligned PCIe
3234 * completions) in order to see if it works on this host. 3244 * completions) in order to see if it works on this host.
3235 */ 3245 */
3236 mgp->fw_name = myri10ge_fw_aligned; 3246 set_fw_name(mgp, myri10ge_fw_aligned, false);
3237 status = myri10ge_load_firmware(mgp, 1); 3247 status = myri10ge_load_firmware(mgp, 1);
3238 if (status != 0) { 3248 if (status != 0) {
3239 goto abort; 3249 goto abort;
@@ -3261,7 +3271,7 @@ static void myri10ge_firmware_probe(struct myri10ge_priv *mgp)
3261abort: 3271abort:
3262 /* fall back to using the unaligned firmware */ 3272 /* fall back to using the unaligned firmware */
3263 mgp->tx_boundary = 2048; 3273 mgp->tx_boundary = 2048;
3264 mgp->fw_name = myri10ge_fw_unaligned; 3274 set_fw_name(mgp, myri10ge_fw_unaligned, false);
3265 3275
3266} 3276}
3267 3277
@@ -3284,7 +3294,7 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
3284 dev_info(&mgp->pdev->dev, "PCIE x%d Link\n", 3294 dev_info(&mgp->pdev->dev, "PCIE x%d Link\n",
3285 link_width); 3295 link_width);
3286 mgp->tx_boundary = 4096; 3296 mgp->tx_boundary = 4096;
3287 mgp->fw_name = myri10ge_fw_aligned; 3297 set_fw_name(mgp, myri10ge_fw_aligned, false);
3288 } else { 3298 } else {
3289 myri10ge_firmware_probe(mgp); 3299 myri10ge_firmware_probe(mgp);
3290 } 3300 }
@@ -3293,22 +3303,29 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
3293 dev_info(&mgp->pdev->dev, 3303 dev_info(&mgp->pdev->dev,
3294 "Assuming aligned completions (forced)\n"); 3304 "Assuming aligned completions (forced)\n");
3295 mgp->tx_boundary = 4096; 3305 mgp->tx_boundary = 4096;
3296 mgp->fw_name = myri10ge_fw_aligned; 3306 set_fw_name(mgp, myri10ge_fw_aligned, false);
3297 } else { 3307 } else {
3298 dev_info(&mgp->pdev->dev, 3308 dev_info(&mgp->pdev->dev,
3299 "Assuming unaligned completions (forced)\n"); 3309 "Assuming unaligned completions (forced)\n");
3300 mgp->tx_boundary = 2048; 3310 mgp->tx_boundary = 2048;
3301 mgp->fw_name = myri10ge_fw_unaligned; 3311 set_fw_name(mgp, myri10ge_fw_unaligned, false);
3302 } 3312 }
3303 } 3313 }
3314
3315 kparam_block_sysfs_write(myri10ge_fw_name);
3304 if (myri10ge_fw_name != NULL) { 3316 if (myri10ge_fw_name != NULL) {
3305 overridden = 1; 3317 char *fw_name = kstrdup(myri10ge_fw_name, GFP_KERNEL);
3306 mgp->fw_name = myri10ge_fw_name; 3318 if (fw_name) {
3319 overridden = 1;
3320 set_fw_name(mgp, fw_name, true);
3321 }
3307 } 3322 }
3323 kparam_unblock_sysfs_write(myri10ge_fw_name);
3324
3308 if (mgp->board_number < MYRI10GE_MAX_BOARDS && 3325 if (mgp->board_number < MYRI10GE_MAX_BOARDS &&
3309 myri10ge_fw_names[mgp->board_number] != NULL && 3326 myri10ge_fw_names[mgp->board_number] != NULL &&
3310 strlen(myri10ge_fw_names[mgp->board_number])) { 3327 strlen(myri10ge_fw_names[mgp->board_number])) {
3311 mgp->fw_name = myri10ge_fw_names[mgp->board_number]; 3328 set_fw_name(mgp, myri10ge_fw_names[mgp->board_number], false);
3312 overridden = 1; 3329 overridden = 1;
3313 } 3330 }
3314 if (overridden) 3331 if (overridden)
@@ -3660,6 +3677,7 @@ static void myri10ge_probe_slices(struct myri10ge_priv *mgp)
3660 struct myri10ge_cmd cmd; 3677 struct myri10ge_cmd cmd;
3661 struct pci_dev *pdev = mgp->pdev; 3678 struct pci_dev *pdev = mgp->pdev;
3662 char *old_fw; 3679 char *old_fw;
3680 bool old_allocated;
3663 int i, status, ncpus, msix_cap; 3681 int i, status, ncpus, msix_cap;
3664 3682
3665 mgp->num_slices = 1; 3683 mgp->num_slices = 1;
@@ -3672,17 +3690,23 @@ static void myri10ge_probe_slices(struct myri10ge_priv *mgp)
3672 3690
3673 /* try to load the slice aware rss firmware */ 3691 /* try to load the slice aware rss firmware */
3674 old_fw = mgp->fw_name; 3692 old_fw = mgp->fw_name;
3693 old_allocated = mgp->fw_name_allocated;
3694 /* don't free old_fw if we override it. */
3695 mgp->fw_name_allocated = false;
3696
3675 if (myri10ge_fw_name != NULL) { 3697 if (myri10ge_fw_name != NULL) {
3676 dev_info(&mgp->pdev->dev, "overriding rss firmware to %s\n", 3698 dev_info(&mgp->pdev->dev, "overriding rss firmware to %s\n",
3677 myri10ge_fw_name); 3699 myri10ge_fw_name);
3678 mgp->fw_name = myri10ge_fw_name; 3700 set_fw_name(mgp, myri10ge_fw_name, false);
3679 } else if (old_fw == myri10ge_fw_aligned) 3701 } else if (old_fw == myri10ge_fw_aligned)
3680 mgp->fw_name = myri10ge_fw_rss_aligned; 3702 set_fw_name(mgp, myri10ge_fw_rss_aligned, false);
3681 else 3703 else
3682 mgp->fw_name = myri10ge_fw_rss_unaligned; 3704 set_fw_name(mgp, myri10ge_fw_rss_unaligned, false);
3683 status = myri10ge_load_firmware(mgp, 0); 3705 status = myri10ge_load_firmware(mgp, 0);
3684 if (status != 0) { 3706 if (status != 0) {
3685 dev_info(&pdev->dev, "Rss firmware not found\n"); 3707 dev_info(&pdev->dev, "Rss firmware not found\n");
3708 if (old_allocated)
3709 kfree(old_fw);
3686 return; 3710 return;
3687 } 3711 }
3688 3712
@@ -3747,6 +3771,8 @@ static void myri10ge_probe_slices(struct myri10ge_priv *mgp)
3747 mgp->num_slices); 3771 mgp->num_slices);
3748 if (status == 0) { 3772 if (status == 0) {
3749 pci_disable_msix(pdev); 3773 pci_disable_msix(pdev);
3774 if (old_allocated)
3775 kfree(old_fw);
3750 return; 3776 return;
3751 } 3777 }
3752 if (status > 0) 3778 if (status > 0)
@@ -3763,7 +3789,7 @@ disable_msix:
3763 3789
3764abort_with_fw: 3790abort_with_fw:
3765 mgp->num_slices = 1; 3791 mgp->num_slices = 1;
3766 mgp->fw_name = old_fw; 3792 set_fw_name(mgp, old_fw, old_allocated);
3767 myri10ge_load_firmware(mgp, 0); 3793 myri10ge_load_firmware(mgp, 0);
3768} 3794}
3769 3795
@@ -3993,6 +4019,7 @@ abort_with_enabled:
3993 pci_disable_device(pdev); 4019 pci_disable_device(pdev);
3994 4020
3995abort_with_netdev: 4021abort_with_netdev:
4022 set_fw_name(mgp, NULL, false);
3996 free_netdev(netdev); 4023 free_netdev(netdev);
3997 return status; 4024 return status;
3998} 4025}
@@ -4037,6 +4064,7 @@ static void myri10ge_remove(struct pci_dev *pdev)
4037 dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd), 4064 dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd),
4038 mgp->cmd, mgp->cmd_bus); 4065 mgp->cmd, mgp->cmd_bus);
4039 4066
4067 set_fw_name(mgp, NULL, false);
4040 free_netdev(netdev); 4068 free_netdev(netdev);
4041 pci_disable_device(pdev); 4069 pci_disable_device(pdev);
4042 pci_set_drvdata(pdev, NULL); 4070 pci_set_drvdata(pdev, NULL);