diff options
author | Sreenivasa Honnur <Sreenivasa.Honnur@neterion.com> | 2010-03-28 18:07:34 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-03-29 19:57:20 -0400 |
commit | 18dec74c16abaa92d663dfef64ee6503e085be89 (patch) | |
tree | 88c03fb3ec663cb4b1c2d2ed4ae7d6ac180ae32b /drivers/net/vxge | |
parent | 7905e357ebe67a26d9dc8caa1a0b8346431b5f0d (diff) |
vxge: Fix a receive stall due to driver being out of synch with chip.
- Fix a receive stall due to driver being out of synch with chip. In a corner
case scenario the adapter's ring controller may return a RxD with transfer code
of 0xC, while the host ownership bit is still set to the adapter. The driver
needs to assume that this case where (host_ownership == 1 or adapter) and
(transfer_code == 0xC) is valid, that is, this RxD has been returned by the
receive ring controller but no frame data is associated with the rxd.
- Restore the transfer code field of each newly replenished RxD to 0x0.
- Code cleanup. Removed usage of magic numbers.
Signed-off-by: Sreenivasa Honnur <sreenivasa.honnur@neterion.com>
Signed-off-by: Ramkrishna Vepa <ram.vepa@neterion.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/vxge')
-rw-r--r-- | drivers/net/vxge/vxge-traffic.c | 18 | ||||
-rw-r--r-- | drivers/net/vxge/vxge-traffic.h | 45 |
2 files changed, 56 insertions, 7 deletions
diff --git a/drivers/net/vxge/vxge-traffic.c b/drivers/net/vxge/vxge-traffic.c index 2c012f4ce465..c8b3997e9eeb 100644 --- a/drivers/net/vxge/vxge-traffic.c +++ b/drivers/net/vxge/vxge-traffic.c | |||
@@ -878,7 +878,7 @@ void vxge_hw_ring_rxd_post_post(struct __vxge_hw_ring *ring, void *rxdh) | |||
878 | 878 | ||
879 | channel = &ring->channel; | 879 | channel = &ring->channel; |
880 | 880 | ||
881 | rxdp->control_0 |= VXGE_HW_RING_RXD_LIST_OWN_ADAPTER; | 881 | rxdp->control_0 = VXGE_HW_RING_RXD_LIST_OWN_ADAPTER; |
882 | 882 | ||
883 | if (ring->stats->common_stats.usage_cnt > 0) | 883 | if (ring->stats->common_stats.usage_cnt > 0) |
884 | ring->stats->common_stats.usage_cnt--; | 884 | ring->stats->common_stats.usage_cnt--; |
@@ -902,7 +902,7 @@ void vxge_hw_ring_rxd_post(struct __vxge_hw_ring *ring, void *rxdh) | |||
902 | channel = &ring->channel; | 902 | channel = &ring->channel; |
903 | 903 | ||
904 | wmb(); | 904 | wmb(); |
905 | rxdp->control_0 |= VXGE_HW_RING_RXD_LIST_OWN_ADAPTER; | 905 | rxdp->control_0 = VXGE_HW_RING_RXD_LIST_OWN_ADAPTER; |
906 | 906 | ||
907 | vxge_hw_channel_dtr_post(channel, rxdh); | 907 | vxge_hw_channel_dtr_post(channel, rxdh); |
908 | 908 | ||
@@ -966,6 +966,7 @@ enum vxge_hw_status vxge_hw_ring_rxd_next_completed( | |||
966 | struct __vxge_hw_channel *channel; | 966 | struct __vxge_hw_channel *channel; |
967 | struct vxge_hw_ring_rxd_1 *rxdp; | 967 | struct vxge_hw_ring_rxd_1 *rxdp; |
968 | enum vxge_hw_status status = VXGE_HW_OK; | 968 | enum vxge_hw_status status = VXGE_HW_OK; |
969 | u64 control_0, own; | ||
969 | 970 | ||
970 | channel = &ring->channel; | 971 | channel = &ring->channel; |
971 | 972 | ||
@@ -977,8 +978,12 @@ enum vxge_hw_status vxge_hw_ring_rxd_next_completed( | |||
977 | goto exit; | 978 | goto exit; |
978 | } | 979 | } |
979 | 980 | ||
981 | control_0 = rxdp->control_0; | ||
982 | own = control_0 & VXGE_HW_RING_RXD_LIST_OWN_ADAPTER; | ||
983 | *t_code = (u8)VXGE_HW_RING_RXD_T_CODE_GET(control_0); | ||
984 | |||
980 | /* check whether it is not the end */ | 985 | /* check whether it is not the end */ |
981 | if (!(rxdp->control_0 & VXGE_HW_RING_RXD_LIST_OWN_ADAPTER)) { | 986 | if (!own || ((*t_code == VXGE_HW_RING_T_CODE_FRM_DROP) && own)) { |
982 | 987 | ||
983 | vxge_assert(((struct vxge_hw_ring_rxd_1 *)rxdp)->host_control != | 988 | vxge_assert(((struct vxge_hw_ring_rxd_1 *)rxdp)->host_control != |
984 | 0); | 989 | 0); |
@@ -986,8 +991,6 @@ enum vxge_hw_status vxge_hw_ring_rxd_next_completed( | |||
986 | ++ring->cmpl_cnt; | 991 | ++ring->cmpl_cnt; |
987 | vxge_hw_channel_dtr_complete(channel); | 992 | vxge_hw_channel_dtr_complete(channel); |
988 | 993 | ||
989 | *t_code = (u8)VXGE_HW_RING_RXD_T_CODE_GET(rxdp->control_0); | ||
990 | |||
991 | vxge_assert(*t_code != VXGE_HW_RING_RXD_T_CODE_UNUSED); | 994 | vxge_assert(*t_code != VXGE_HW_RING_RXD_T_CODE_UNUSED); |
992 | 995 | ||
993 | ring->stats->common_stats.usage_cnt++; | 996 | ring->stats->common_stats.usage_cnt++; |
@@ -1035,12 +1038,13 @@ enum vxge_hw_status vxge_hw_ring_handle_tcode( | |||
1035 | * such as unknown UPV6 header), Drop it !!! | 1038 | * such as unknown UPV6 header), Drop it !!! |
1036 | */ | 1039 | */ |
1037 | 1040 | ||
1038 | if (t_code == 0 || t_code == 5) { | 1041 | if (t_code == VXGE_HW_RING_T_CODE_OK || |
1042 | t_code == VXGE_HW_RING_T_CODE_L3_PKT_ERR) { | ||
1039 | status = VXGE_HW_OK; | 1043 | status = VXGE_HW_OK; |
1040 | goto exit; | 1044 | goto exit; |
1041 | } | 1045 | } |
1042 | 1046 | ||
1043 | if (t_code > 0xF) { | 1047 | if (t_code > VXGE_HW_RING_T_CODE_MULTI_ERR) { |
1044 | status = VXGE_HW_ERR_INVALID_TCODE; | 1048 | status = VXGE_HW_ERR_INVALID_TCODE; |
1045 | goto exit; | 1049 | goto exit; |
1046 | } | 1050 | } |
diff --git a/drivers/net/vxge/vxge-traffic.h b/drivers/net/vxge/vxge-traffic.h index 861c853e3e84..3c35e446e247 100644 --- a/drivers/net/vxge/vxge-traffic.h +++ b/drivers/net/vxge/vxge-traffic.h | |||
@@ -1866,6 +1866,51 @@ struct vxge_hw_ring_rxd_info { | |||
1866 | u32 rth_hash_type; | 1866 | u32 rth_hash_type; |
1867 | u32 rth_value; | 1867 | u32 rth_value; |
1868 | }; | 1868 | }; |
1869 | /** | ||
1870 | * enum vxge_hw_ring_tcode - Transfer codes returned by adapter | ||
1871 | * @VXGE_HW_RING_T_CODE_OK: Transfer ok. | ||
1872 | * @VXGE_HW_RING_T_CODE_L3_CKSUM_MISMATCH: Layer 3 checksum presentation | ||
1873 | * configuration mismatch. | ||
1874 | * @VXGE_HW_RING_T_CODE_L4_CKSUM_MISMATCH: Layer 4 checksum presentation | ||
1875 | * configuration mismatch. | ||
1876 | * @VXGE_HW_RING_T_CODE_L3_L4_CKSUM_MISMATCH: Layer 3 and Layer 4 checksum | ||
1877 | * presentation configuration mismatch. | ||
1878 | * @VXGE_HW_RING_T_CODE_L3_PKT_ERR: Layer 3 error unparseable packet, | ||
1879 | * such as unknown IPv6 header. | ||
1880 | * @VXGE_HW_RING_T_CODE_L2_FRM_ERR: Layer 2 error frame integrity | ||
1881 | * error, such as FCS or ECC). | ||
1882 | * @VXGE_HW_RING_T_CODE_BUF_SIZE_ERR: Buffer size error the RxD buffer( | ||
1883 | * s) were not appropriately sized and data loss occurred. | ||
1884 | * @VXGE_HW_RING_T_CODE_INT_ECC_ERR: Internal ECC error RxD corrupted. | ||
1885 | * @VXGE_HW_RING_T_CODE_BENIGN_OVFLOW: Benign overflow the contents of | ||
1886 | * Segment1 exceeded the capacity of Buffer1 and the remainder | ||
1887 | * was placed in Buffer2. Segment2 now starts in Buffer3. | ||
1888 | * No data loss or errors occurred. | ||
1889 | * @VXGE_HW_RING_T_CODE_ZERO_LEN_BUFF: Buffer size 0 one of the RxDs | ||
1890 | * assigned buffers has a size of 0 bytes. | ||
1891 | * @VXGE_HW_RING_T_CODE_FRM_DROP: Frame dropped either due to | ||
1892 | * VPath Reset or because of a VPIN mismatch. | ||
1893 | * @VXGE_HW_RING_T_CODE_UNUSED: Unused | ||
1894 | * @VXGE_HW_RING_T_CODE_MULTI_ERR: Multiple errors more than one | ||
1895 | * transfer code condition occurred. | ||
1896 | * | ||
1897 | * Transfer codes returned by adapter. | ||
1898 | */ | ||
1899 | enum vxge_hw_ring_tcode { | ||
1900 | VXGE_HW_RING_T_CODE_OK = 0x0, | ||
1901 | VXGE_HW_RING_T_CODE_L3_CKSUM_MISMATCH = 0x1, | ||
1902 | VXGE_HW_RING_T_CODE_L4_CKSUM_MISMATCH = 0x2, | ||
1903 | VXGE_HW_RING_T_CODE_L3_L4_CKSUM_MISMATCH = 0x3, | ||
1904 | VXGE_HW_RING_T_CODE_L3_PKT_ERR = 0x5, | ||
1905 | VXGE_HW_RING_T_CODE_L2_FRM_ERR = 0x6, | ||
1906 | VXGE_HW_RING_T_CODE_BUF_SIZE_ERR = 0x7, | ||
1907 | VXGE_HW_RING_T_CODE_INT_ECC_ERR = 0x8, | ||
1908 | VXGE_HW_RING_T_CODE_BENIGN_OVFLOW = 0x9, | ||
1909 | VXGE_HW_RING_T_CODE_ZERO_LEN_BUFF = 0xA, | ||
1910 | VXGE_HW_RING_T_CODE_FRM_DROP = 0xC, | ||
1911 | VXGE_HW_RING_T_CODE_UNUSED = 0xE, | ||
1912 | VXGE_HW_RING_T_CODE_MULTI_ERR = 0xF | ||
1913 | }; | ||
1869 | 1914 | ||
1870 | /** | 1915 | /** |
1871 | * enum enum vxge_hw_ring_hash_type - RTH hash types | 1916 | * enum enum vxge_hw_ring_hash_type - RTH hash types |