aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorMatt Carlson <mcarlson@broadcom.com>2011-04-25 08:42:47 -0400
committerDavid S. Miller <davem@davemloft.net>2011-04-26 03:07:02 -0400
commitbb158d696489244f79fd4c3abd47968a06b48c79 (patch)
tree612365ad9a11987aa06adcbf6bc025d3e7b3bea1 /drivers/net
parent00c266b794d589dcf7d280926dfc27c5896a410a (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')
-rw-r--r--drivers/net/tg3.c158
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
11087static const u8 tg3_tso_header[] = {
110880x08, 0x00,
110890x45, 0x00, 0x00, 0x00,
110900x00, 0x00, 0x40, 0x00,
110910x40, 0x06, 0x00, 0x00,
110920x0a, 0x00, 0x00, 0x01,
110930x0a, 0x00, 0x00, 0x02,
110940x0d, 0x00, 0xe0, 0x00,
110950x00, 0x00, 0x01, 0x00,
110960x00, 0x00, 0x02, 0x00,
110970x80, 0x10, 0x10, 0x00,
110980x14, 0x09, 0x00, 0x00,
110990x01, 0x01, 0x08, 0x0a,
111000x11, 0x11, 0x11, 0x11,
111010x11, 0x11, 0x11, 0x11,
11102};
11079 11103
11080static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, int loopback_mode) 11104static 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
11286static int tg3_test_loopback(struct tg3 *tp) 11370static 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 <<