diff options
author | Matt Carlson <mcarlson@broadcom.com> | 2011-04-25 08:42:47 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-04-26 03:07:02 -0400 |
commit | bb158d696489244f79fd4c3abd47968a06b48c79 (patch) | |
tree | 612365ad9a11987aa06adcbf6bc025d3e7b3bea1 /drivers/net/tg3.c | |
parent | 00c266b794d589dcf7d280926dfc27c5896a410a (diff) |
tg3: Add TSO loopback test
This patch adds code to exercise the TSO portion of the device through
a phy loopback test.
Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Benjamin Li <benli@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/tg3.c')
-rw-r--r-- | drivers/net/tg3.c | 158 |
1 files changed, 123 insertions, 35 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 88cd23171510..fb2139a80700 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c | |||
@@ -11076,11 +11076,35 @@ static int tg3_test_memory(struct tg3 *tp) | |||
11076 | 11076 | ||
11077 | #define TG3_MAC_LOOPBACK 0 | 11077 | #define TG3_MAC_LOOPBACK 0 |
11078 | #define TG3_PHY_LOOPBACK 1 | 11078 | #define TG3_PHY_LOOPBACK 1 |
11079 | #define TG3_TSO_LOOPBACK 2 | ||
11080 | |||
11081 | #define TG3_TSO_MSS 500 | ||
11082 | |||
11083 | #define TG3_TSO_IP_HDR_LEN 20 | ||
11084 | #define TG3_TSO_TCP_HDR_LEN 20 | ||
11085 | #define TG3_TSO_TCP_OPT_LEN 12 | ||
11086 | |||
11087 | static const u8 tg3_tso_header[] = { | ||
11088 | 0x08, 0x00, | ||
11089 | 0x45, 0x00, 0x00, 0x00, | ||
11090 | 0x00, 0x00, 0x40, 0x00, | ||
11091 | 0x40, 0x06, 0x00, 0x00, | ||
11092 | 0x0a, 0x00, 0x00, 0x01, | ||
11093 | 0x0a, 0x00, 0x00, 0x02, | ||
11094 | 0x0d, 0x00, 0xe0, 0x00, | ||
11095 | 0x00, 0x00, 0x01, 0x00, | ||
11096 | 0x00, 0x00, 0x02, 0x00, | ||
11097 | 0x80, 0x10, 0x10, 0x00, | ||
11098 | 0x14, 0x09, 0x00, 0x00, | ||
11099 | 0x01, 0x01, 0x08, 0x0a, | ||
11100 | 0x11, 0x11, 0x11, 0x11, | ||
11101 | 0x11, 0x11, 0x11, 0x11, | ||
11102 | }; | ||
11079 | 11103 | ||
11080 | static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) | 11104 | static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) |
11081 | { | 11105 | { |
11082 | u32 mac_mode, rx_start_idx, rx_idx, tx_idx, opaque_key; | 11106 | u32 mac_mode, rx_start_idx, rx_idx, tx_idx, opaque_key; |
11083 | u32 desc_idx, coal_now; | 11107 | u32 base_flags = 0, mss = 0, desc_idx, coal_now, data_off, val; |
11084 | struct sk_buff *skb, *rx_skb; | 11108 | struct sk_buff *skb, *rx_skb; |
11085 | u8 *tx_data; | 11109 | u8 *tx_data; |
11086 | dma_addr_t map; | 11110 | dma_addr_t map; |
@@ -11119,9 +11143,7 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) | |||
11119 | else | 11143 | else |
11120 | mac_mode |= MAC_MODE_PORT_MODE_GMII; | 11144 | mac_mode |= MAC_MODE_PORT_MODE_GMII; |
11121 | tw32(MAC_MODE, mac_mode); | 11145 | tw32(MAC_MODE, mac_mode); |
11122 | } else if (loopback_mode == TG3_PHY_LOOPBACK) { | 11146 | } else { |
11123 | u32 val; | ||
11124 | |||
11125 | if (tp->phy_flags & TG3_PHYFLG_IS_FET) { | 11147 | if (tp->phy_flags & TG3_PHYFLG_IS_FET) { |
11126 | tg3_phy_fet_toggle_apd(tp, false); | 11148 | tg3_phy_fet_toggle_apd(tp, false); |
11127 | val = BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED100; | 11149 | val = BMCR_LOOPBACK | BMCR_FULLDPLX | BMCR_SPEED100; |
@@ -11169,8 +11191,6 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) | |||
11169 | break; | 11191 | break; |
11170 | mdelay(1); | 11192 | mdelay(1); |
11171 | } | 11193 | } |
11172 | } else { | ||
11173 | return -EINVAL; | ||
11174 | } | 11194 | } |
11175 | 11195 | ||
11176 | err = -EIO; | 11196 | err = -EIO; |
@@ -11186,7 +11206,54 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) | |||
11186 | 11206 | ||
11187 | tw32(MAC_RX_MTU_SIZE, tx_len + ETH_FCS_LEN); | 11207 | tw32(MAC_RX_MTU_SIZE, tx_len + ETH_FCS_LEN); |
11188 | 11208 | ||
11189 | for (i = 14; i < tx_len; i++) | 11209 | if (loopback_mode == TG3_TSO_LOOPBACK) { |
11210 | struct iphdr *iph = (struct iphdr *)&tx_data[ETH_HLEN]; | ||
11211 | |||
11212 | u32 hdr_len = TG3_TSO_IP_HDR_LEN + TG3_TSO_TCP_HDR_LEN + | ||
11213 | TG3_TSO_TCP_OPT_LEN; | ||
11214 | |||
11215 | memcpy(tx_data + ETH_ALEN * 2, tg3_tso_header, | ||
11216 | sizeof(tg3_tso_header)); | ||
11217 | mss = TG3_TSO_MSS; | ||
11218 | |||
11219 | val = tx_len - ETH_ALEN * 2 - sizeof(tg3_tso_header); | ||
11220 | num_pkts = DIV_ROUND_UP(val, TG3_TSO_MSS); | ||
11221 | |||
11222 | /* Set the total length field in the IP header */ | ||
11223 | iph->tot_len = htons((u16)(mss + hdr_len)); | ||
11224 | |||
11225 | base_flags = (TXD_FLAG_CPU_PRE_DMA | | ||
11226 | TXD_FLAG_CPU_POST_DMA); | ||
11227 | |||
11228 | if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) { | ||
11229 | struct tcphdr *th; | ||
11230 | val = ETH_HLEN + TG3_TSO_IP_HDR_LEN; | ||
11231 | th = (struct tcphdr *)&tx_data[val]; | ||
11232 | th->check = 0; | ||
11233 | } else | ||
11234 | base_flags |= TXD_FLAG_TCPUDP_CSUM; | ||
11235 | |||
11236 | if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_3) { | ||
11237 | mss |= (hdr_len & 0xc) << 12; | ||
11238 | if (hdr_len & 0x10) | ||
11239 | base_flags |= 0x00000010; | ||
11240 | base_flags |= (hdr_len & 0x3e0) << 5; | ||
11241 | } else if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) | ||
11242 | mss |= hdr_len << 9; | ||
11243 | else if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_1) || | ||
11244 | GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) { | ||
11245 | mss |= (TG3_TSO_TCP_OPT_LEN << 9); | ||
11246 | } else { | ||
11247 | base_flags |= (TG3_TSO_TCP_OPT_LEN << 10); | ||
11248 | } | ||
11249 | |||
11250 | data_off = ETH_ALEN * 2 + sizeof(tg3_tso_header); | ||
11251 | } else { | ||
11252 | num_pkts = 1; | ||
11253 | data_off = ETH_HLEN; | ||
11254 | } | ||
11255 | |||
11256 | for (i = data_off; i < tx_len; i++) | ||
11190 | tx_data[i] = (u8) (i & 0xff); | 11257 | tx_data[i] = (u8) (i & 0xff); |
11191 | 11258 | ||
11192 | map = pci_map_single(tp->pdev, skb->data, tx_len, PCI_DMA_TODEVICE); | 11259 | map = pci_map_single(tp->pdev, skb->data, tx_len, PCI_DMA_TODEVICE); |
@@ -11202,12 +11269,10 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) | |||
11202 | 11269 | ||
11203 | rx_start_idx = rnapi->hw_status->idx[0].rx_producer; | 11270 | rx_start_idx = rnapi->hw_status->idx[0].rx_producer; |
11204 | 11271 | ||
11205 | num_pkts = 0; | 11272 | tg3_set_txd(tnapi, tnapi->tx_prod, map, tx_len, |
11206 | 11273 | base_flags, (mss << 1) | 1); | |
11207 | tg3_set_txd(tnapi, tnapi->tx_prod, map, tx_len, 0, 1); | ||
11208 | 11274 | ||
11209 | tnapi->tx_prod++; | 11275 | tnapi->tx_prod++; |
11210 | num_pkts++; | ||
11211 | 11276 | ||
11212 | tw32_tx_mbox(tnapi->prodmbox, tnapi->tx_prod); | 11277 | tw32_tx_mbox(tnapi->prodmbox, tnapi->tx_prod); |
11213 | tr32_mailbox(tnapi->prodmbox); | 11278 | tr32_mailbox(tnapi->prodmbox); |
@@ -11237,38 +11302,56 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) | |||
11237 | if (rx_idx != rx_start_idx + num_pkts) | 11302 | if (rx_idx != rx_start_idx + num_pkts) |
11238 | goto out; | 11303 | goto out; |
11239 | 11304 | ||
11240 | desc = &rnapi->rx_rcb[rx_start_idx]; | 11305 | val = data_off; |
11241 | desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK; | 11306 | while (rx_idx != rx_start_idx) { |
11242 | opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK; | 11307 | desc = &rnapi->rx_rcb[rx_start_idx++]; |
11308 | desc_idx = desc->opaque & RXD_OPAQUE_INDEX_MASK; | ||
11309 | opaque_key = desc->opaque & RXD_OPAQUE_RING_MASK; | ||
11243 | 11310 | ||
11244 | if ((desc->err_vlan & RXD_ERR_MASK) != 0 && | 11311 | if ((desc->err_vlan & RXD_ERR_MASK) != 0 && |
11245 | (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) | 11312 | (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) |
11246 | goto out; | 11313 | goto out; |
11247 | 11314 | ||
11248 | rx_len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; | 11315 | rx_len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) |
11249 | if (rx_len != tx_len) | 11316 | - ETH_FCS_LEN; |
11250 | goto out; | ||
11251 | 11317 | ||
11252 | if (pktsz <= TG3_RX_STD_DMA_SZ - ETH_FCS_LEN) { | 11318 | if (loopback_mode != TG3_TSO_LOOPBACK) { |
11253 | if (opaque_key != RXD_OPAQUE_RING_STD) | 11319 | if (rx_len != tx_len) |
11254 | goto out; | 11320 | goto out; |
11255 | 11321 | ||
11256 | rx_skb = tpr->rx_std_buffers[desc_idx].skb; | 11322 | if (pktsz <= TG3_RX_STD_DMA_SZ - ETH_FCS_LEN) { |
11257 | map = dma_unmap_addr(&tpr->rx_std_buffers[desc_idx], mapping); | 11323 | if (opaque_key != RXD_OPAQUE_RING_STD) |
11258 | } else { | 11324 | goto out; |
11259 | if (opaque_key != RXD_OPAQUE_RING_JUMBO) | 11325 | } else { |
11326 | if (opaque_key != RXD_OPAQUE_RING_JUMBO) | ||
11327 | goto out; | ||
11328 | } | ||
11329 | } else if ((desc->type_flags & RXD_FLAG_TCPUDP_CSUM) && | ||
11330 | (desc->ip_tcp_csum & RXD_TCPCSUM_MASK) | ||
11331 | >> RXD_TCPCSUM_SHIFT == 0xffff) { | ||
11260 | goto out; | 11332 | goto out; |
11333 | } | ||
11261 | 11334 | ||
11262 | rx_skb = tpr->rx_jmb_buffers[desc_idx].skb; | 11335 | if (opaque_key == RXD_OPAQUE_RING_STD) { |
11263 | map = dma_unmap_addr(&tpr->rx_jmb_buffers[desc_idx], mapping); | 11336 | rx_skb = tpr->rx_std_buffers[desc_idx].skb; |
11264 | } | 11337 | map = dma_unmap_addr(&tpr->rx_std_buffers[desc_idx], |
11338 | mapping); | ||
11339 | } else if (opaque_key == RXD_OPAQUE_RING_JUMBO) { | ||
11340 | rx_skb = tpr->rx_jmb_buffers[desc_idx].skb; | ||
11341 | map = dma_unmap_addr(&tpr->rx_jmb_buffers[desc_idx], | ||
11342 | mapping); | ||
11343 | } else | ||
11344 | goto out; | ||
11265 | 11345 | ||
11266 | pci_dma_sync_single_for_cpu(tp->pdev, map, rx_len, PCI_DMA_FROMDEVICE); | 11346 | pci_dma_sync_single_for_cpu(tp->pdev, map, rx_len, |
11347 | PCI_DMA_FROMDEVICE); | ||
11267 | 11348 | ||
11268 | for (i = 14; i < tx_len; i++) { | 11349 | for (i = data_off; i < rx_len; i++, val++) { |
11269 | if (*(rx_skb->data + i) != (u8) (i & 0xff)) | 11350 | if (*(rx_skb->data + i) != (u8) (val & 0xff)) |
11270 | goto out; | 11351 | goto out; |
11352 | } | ||
11271 | } | 11353 | } |
11354 | |||
11272 | err = 0; | 11355 | err = 0; |
11273 | 11356 | ||
11274 | /* tg3_free_rings will unmap and free the rx_skb */ | 11357 | /* tg3_free_rings will unmap and free the rx_skb */ |
@@ -11278,10 +11361,11 @@ out: | |||
11278 | 11361 | ||
11279 | #define TG3_STD_LOOPBACK_FAILED 1 | 11362 | #define TG3_STD_LOOPBACK_FAILED 1 |
11280 | #define TG3_JMB_LOOPBACK_FAILED 2 | 11363 | #define TG3_JMB_LOOPBACK_FAILED 2 |
11364 | #define TG3_TSO_LOOPBACK_FAILED 4 | ||
11281 | 11365 | ||
11282 | #define TG3_MAC_LOOPBACK_SHIFT 0 | 11366 | #define TG3_MAC_LOOPBACK_SHIFT 0 |
11283 | #define TG3_PHY_LOOPBACK_SHIFT 4 | 11367 | #define TG3_PHY_LOOPBACK_SHIFT 4 |
11284 | #define TG3_LOOPBACK_FAILED 0x00000033 | 11368 | #define TG3_LOOPBACK_FAILED 0x00000077 |
11285 | 11369 | ||
11286 | static int tg3_test_loopback(struct tg3 *tp) | 11370 | static int tg3_test_loopback(struct tg3 *tp) |
11287 | { | 11371 | { |
@@ -11358,6 +11442,10 @@ static int tg3_test_loopback(struct tg3 *tp) | |||
11358 | if (tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_PHY_LOOPBACK)) | 11442 | if (tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_PHY_LOOPBACK)) |
11359 | err |= TG3_STD_LOOPBACK_FAILED << | 11443 | err |= TG3_STD_LOOPBACK_FAILED << |
11360 | TG3_PHY_LOOPBACK_SHIFT; | 11444 | TG3_PHY_LOOPBACK_SHIFT; |
11445 | if ((tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) && | ||
11446 | tg3_run_loopback(tp, ETH_FRAME_LEN, TG3_TSO_LOOPBACK)) | ||
11447 | err |= TG3_TSO_LOOPBACK_FAILED << | ||
11448 | TG3_PHY_LOOPBACK_SHIFT; | ||
11361 | if ((tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) && | 11449 | if ((tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) && |
11362 | tg3_run_loopback(tp, 9000 + ETH_HLEN, TG3_PHY_LOOPBACK)) | 11450 | tg3_run_loopback(tp, 9000 + ETH_HLEN, TG3_PHY_LOOPBACK)) |
11363 | err |= TG3_JMB_LOOPBACK_FAILED << | 11451 | err |= TG3_JMB_LOOPBACK_FAILED << |