diff options
author | Jon Mason <jdmason@kudzu.us> | 2011-04-08 07:11:22 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-04-12 14:22:34 -0400 |
commit | 9f9b16458134ba9f06ef6f15369513aa9eebc81c (patch) | |
tree | d43804b6c7e2b2b4eea94f5383cb9ba1cdf30a3e /drivers/net/vxge | |
parent | cd883a791b55c3c52ce402cd551585fed092d240 (diff) |
vxge: spin-lock issue
In vxge_hw_vpath_close, __vxge_hw_vp_terminate memsets the vpath which
clobbers the spin lock state, then the driver attempts to acquire the
spin lock. Resolve this by not zeroing the lock part of vpath struct,
clean-up vpath locking in init, close, and fix locking hole in fw_api
call.
Issue found by Bob Picco <bpicco@redhat.com>
Signed-off-by: Jon Mason <jdmason@kudzu.us>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/vxge')
-rw-r--r-- | drivers/net/vxge/vxge-config.c | 48 |
1 files changed, 32 insertions, 16 deletions
diff --git a/drivers/net/vxge/vxge-config.c b/drivers/net/vxge/vxge-config.c index 401bebf59502..32763b2dd73f 100644 --- a/drivers/net/vxge/vxge-config.c +++ b/drivers/net/vxge/vxge-config.c | |||
@@ -159,16 +159,15 @@ vxge_hw_vpath_fw_api(struct __vxge_hw_virtualpath *vpath, u32 action, | |||
159 | u32 fw_memo, u32 offset, u64 *data0, u64 *data1, | 159 | u32 fw_memo, u32 offset, u64 *data0, u64 *data1, |
160 | u64 *steer_ctrl) | 160 | u64 *steer_ctrl) |
161 | { | 161 | { |
162 | struct vxge_hw_vpath_reg __iomem *vp_reg; | 162 | struct vxge_hw_vpath_reg __iomem *vp_reg = vpath->vp_reg; |
163 | enum vxge_hw_status status; | 163 | enum vxge_hw_status status; |
164 | u64 val64; | 164 | u64 val64; |
165 | u32 retry = 0, max_retry = 100; | 165 | u32 retry = 0, max_retry = 3; |
166 | |||
167 | vp_reg = vpath->vp_reg; | ||
168 | 166 | ||
169 | if (vpath->vp_open) { | 167 | spin_lock(&vpath->lock); |
170 | max_retry = 3; | 168 | if (!vpath->vp_open) { |
171 | spin_lock(&vpath->lock); | 169 | spin_unlock(&vpath->lock); |
170 | max_retry = 100; | ||
172 | } | 171 | } |
173 | 172 | ||
174 | writeq(*data0, &vp_reg->rts_access_steer_data0); | 173 | writeq(*data0, &vp_reg->rts_access_steer_data0); |
@@ -1000,7 +999,7 @@ exit: | |||
1000 | /** | 999 | /** |
1001 | * vxge_hw_device_hw_info_get - Get the hw information | 1000 | * vxge_hw_device_hw_info_get - Get the hw information |
1002 | * Returns the vpath mask that has the bits set for each vpath allocated | 1001 | * Returns the vpath mask that has the bits set for each vpath allocated |
1003 | * for the driver, FW version information and the first mac addresse for | 1002 | * for the driver, FW version information, and the first mac address for |
1004 | * each vpath | 1003 | * each vpath |
1005 | */ | 1004 | */ |
1006 | enum vxge_hw_status __devinit | 1005 | enum vxge_hw_status __devinit |
@@ -1064,9 +1063,10 @@ vxge_hw_device_hw_info_get(void __iomem *bar0, | |||
1064 | 1063 | ||
1065 | val64 = readq(&toc->toc_vpath_pointer[i]); | 1064 | val64 = readq(&toc->toc_vpath_pointer[i]); |
1066 | 1065 | ||
1066 | spin_lock_init(&vpath.lock); | ||
1067 | vpath.vp_reg = (struct vxge_hw_vpath_reg __iomem *) | 1067 | vpath.vp_reg = (struct vxge_hw_vpath_reg __iomem *) |
1068 | (bar0 + val64); | 1068 | (bar0 + val64); |
1069 | vpath.vp_open = 0; | 1069 | vpath.vp_open = VXGE_HW_VP_NOT_OPEN; |
1070 | 1070 | ||
1071 | status = __vxge_hw_vpath_pci_func_mode_get(&vpath, hw_info); | 1071 | status = __vxge_hw_vpath_pci_func_mode_get(&vpath, hw_info); |
1072 | if (status != VXGE_HW_OK) | 1072 | if (status != VXGE_HW_OK) |
@@ -1090,7 +1090,7 @@ vxge_hw_device_hw_info_get(void __iomem *bar0, | |||
1090 | val64 = readq(&toc->toc_vpath_pointer[i]); | 1090 | val64 = readq(&toc->toc_vpath_pointer[i]); |
1091 | vpath.vp_reg = (struct vxge_hw_vpath_reg __iomem *) | 1091 | vpath.vp_reg = (struct vxge_hw_vpath_reg __iomem *) |
1092 | (bar0 + val64); | 1092 | (bar0 + val64); |
1093 | vpath.vp_open = 0; | 1093 | vpath.vp_open = VXGE_HW_VP_NOT_OPEN; |
1094 | 1094 | ||
1095 | status = __vxge_hw_vpath_addr_get(&vpath, | 1095 | status = __vxge_hw_vpath_addr_get(&vpath, |
1096 | hw_info->mac_addrs[i], | 1096 | hw_info->mac_addrs[i], |
@@ -4646,7 +4646,27 @@ static void __vxge_hw_vp_terminate(struct __vxge_hw_device *hldev, u32 vp_id) | |||
4646 | vpath->hldev->tim_int_mask1, vpath->vp_id); | 4646 | vpath->hldev->tim_int_mask1, vpath->vp_id); |
4647 | hldev->stats.hw_dev_info_stats.vpath_info[vpath->vp_id] = NULL; | 4647 | hldev->stats.hw_dev_info_stats.vpath_info[vpath->vp_id] = NULL; |
4648 | 4648 | ||
4649 | memset(vpath, 0, sizeof(struct __vxge_hw_virtualpath)); | 4649 | /* If the whole struct __vxge_hw_virtualpath is zeroed, nothing will |
4650 | * work after the interface is brought down. | ||
4651 | */ | ||
4652 | spin_lock(&vpath->lock); | ||
4653 | vpath->vp_open = VXGE_HW_VP_NOT_OPEN; | ||
4654 | spin_unlock(&vpath->lock); | ||
4655 | |||
4656 | vpath->vpmgmt_reg = NULL; | ||
4657 | vpath->nofl_db = NULL; | ||
4658 | vpath->max_mtu = 0; | ||
4659 | vpath->vsport_number = 0; | ||
4660 | vpath->max_kdfc_db = 0; | ||
4661 | vpath->max_nofl_db = 0; | ||
4662 | vpath->ringh = NULL; | ||
4663 | vpath->fifoh = NULL; | ||
4664 | memset(&vpath->vpath_handles, 0, sizeof(struct list_head)); | ||
4665 | vpath->stats_block = 0; | ||
4666 | vpath->hw_stats = NULL; | ||
4667 | vpath->hw_stats_sav = NULL; | ||
4668 | vpath->sw_stats = NULL; | ||
4669 | |||
4650 | exit: | 4670 | exit: |
4651 | return; | 4671 | return; |
4652 | } | 4672 | } |
@@ -4670,7 +4690,7 @@ __vxge_hw_vp_initialize(struct __vxge_hw_device *hldev, u32 vp_id, | |||
4670 | 4690 | ||
4671 | vpath = &hldev->virtual_paths[vp_id]; | 4691 | vpath = &hldev->virtual_paths[vp_id]; |
4672 | 4692 | ||
4673 | spin_lock_init(&hldev->virtual_paths[vp_id].lock); | 4693 | spin_lock_init(&vpath->lock); |
4674 | vpath->vp_id = vp_id; | 4694 | vpath->vp_id = vp_id; |
4675 | vpath->vp_open = VXGE_HW_VP_OPEN; | 4695 | vpath->vp_open = VXGE_HW_VP_OPEN; |
4676 | vpath->hldev = hldev; | 4696 | vpath->hldev = hldev; |
@@ -5019,10 +5039,6 @@ enum vxge_hw_status vxge_hw_vpath_close(struct __vxge_hw_vpath_handle *vp) | |||
5019 | 5039 | ||
5020 | __vxge_hw_vp_terminate(devh, vp_id); | 5040 | __vxge_hw_vp_terminate(devh, vp_id); |
5021 | 5041 | ||
5022 | spin_lock(&vpath->lock); | ||
5023 | vpath->vp_open = VXGE_HW_VP_NOT_OPEN; | ||
5024 | spin_unlock(&vpath->lock); | ||
5025 | |||
5026 | vpath_close_exit: | 5042 | vpath_close_exit: |
5027 | return status; | 5043 | return status; |
5028 | } | 5044 | } |