| /* |
| * tg3.c: Broadcom Tigon3 ethernet driver. |
| * |
| * Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com) |
| * Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com) |
| * Copyright (C) 2004 Sun Microsystems Inc. |
| * Copyright (C) 2005-2010 Broadcom Corporation. |
| * |
| * Firmware is: |
| * Derived from proprietary unpublished source code, |
| * Copyright (C) 2000-2003 Broadcom Corporation. |
| * |
| * Permission is hereby granted for the distribution of this firmware |
| * data in hexadecimal or equivalent format, provided this copyright |
| * notice is accompanying it. |
| */ |
| |
| |
| #include <linux/module.h> |
| #include <linux/moduleparam.h> |
| #include <linux/stringify.h> |
| #include <linux/kernel.h> |
| #include <linux/types.h> |
| #include <linux/compiler.h> |
| #include <linux/slab.h> |
| #include <linux/delay.h> |
| #include <linux/in.h> |
| #include <linux/init.h> |
| #include <linux/ioport.h> |
| #include <linux/pci.h> |
| #include <linux/netdevice.h> |
| #include <linux/etherdevice.h> |
| #include <linux/skbuff.h> |
| #include <linux/ethtool.h> |
| #include <linux/mii.h> |
| #include <linux/phy.h> |
| #include <linux/brcmphy.h> |
| #include <linux/if_vlan.h> |
| #include <linux/ip.h> |
| #include <linux/tcp.h> |
| #include <linux/workqueue.h> |
| #include <linux/prefetch.h> |
| #include <linux/dma-mapping.h> |
| #include <linux/firmware.h> |
| |
| #include <net/checksum.h> |
| #include <net/ip.h> |
| |
| #include <asm/system.h> |
| #include <asm/io.h> |
| #include <asm/byteorder.h> |
| #include <asm/uaccess.h> |
| |
| #ifdef CONFIG_SPARC |
| #include <asm/idprom.h> |
| #include <asm/prom.h> |
| #endif |
| |
| #define BAR_0 0 |
| #define BAR_2 2 |
| |
| #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) |
| #define TG3_VLAN_TAG_USED 1 |
| #else |
| #define TG3_VLAN_TAG_USED 0 |
| #endif |
| |
| #include "tg3.h" |
| |
| #define DRV_MODULE_NAME "tg3" |
| #define TG3_MAJ_NUM 3 |
| #define TG3_MIN_NUM 115 |
| #define DRV_MODULE_VERSION \ |
| __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM) |
| #define DRV_MODULE_RELDATE "October 14, 2010" |
| |
| #define TG3_DEF_MAC_MODE 0 |
| #define TG3_DEF_RX_MODE 0 |
| #define TG3_DEF_TX_MODE 0 |
| #define TG3_DEF_MSG_ENABLE \ |
| (NETIF_MSG_DRV | \ |
| NETIF_MSG_PROBE | \ |
| NETIF_MSG_LINK | \ |
| NETIF_MSG_TIMER | \ |
| NETIF_MSG_IFDOWN | \ |
| NETIF_MSG_IFUP | \ |
| NETIF_MSG_RX_ERR | \ |
| NETIF_MSG_TX_ERR) |
| |
| /* length of time before we decide the hardware is borked, |
| * and dev->tx_timeout() should be called to fix the problem |
| */ |
| #define TG3_TX_TIMEOUT (5 * HZ) |
| |
| /* hardware minimum and maximum for a single frame's data payload */ |
| #define TG3_MIN_MTU 60 |
| #define TG3_MAX_MTU(tp) \ |
| ((tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) ? 9000 : 1500) |
| |
| /* These numbers seem to be hard coded in the NIC firmware somehow. |
| * You can't change the ring sizes, but you can change where you place |
| * them in the NIC onboard memory. |
| */ |
| #define TG3_RX_STD_RING_SIZE(tp) \ |
| ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || \ |
| GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) ? \ |
| RX_STD_MAX_SIZE_5717 : 512) |
| #define TG3_DEF_RX_RING_PENDING 200 |
| #define TG3_RX_JMB_RING_SIZE(tp) \ |
| ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || \ |
| GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) ? \ |
| 1024 : 256) |
| #define TG3_DEF_RX_JUMBO_RING_PENDING 100 |
| #define TG3_RSS_INDIR_TBL_SIZE 128 |
| |
| /* Do not place this n-ring entries value into the tp struct itself, |
| * we really want to expose these constants to GCC so that modulo et |
| * al. operations are done with shifts and masks instead of with |
| * hw multiply/modulo instructions. Another solution would be to |
| * replace things like '% foo' with '& (foo - 1)'. |
| */ |
| |
| #define TG3_TX_RING_SIZE 512 |
| #define TG3_DEF_TX_RING_PENDING (TG3_TX_RING_SIZE - 1) |
| |
| #define TG3_RX_STD_RING_BYTES(tp) \ |
| (sizeof(struct tg3_rx_buffer_desc) * TG3_RX_STD_RING_SIZE(tp)) |
| #define TG3_RX_JMB_RING_BYTES(tp) \ |
| (sizeof(struct tg3_ext_rx_buffer_desc) * TG3_RX_JMB_RING_SIZE(tp)) |
| #define TG3_RX_RCB_RING_BYTES(tp) \ |
| (sizeof(struct tg3_rx_buffer_desc) * (tp->rx_ret_ring_mask + 1)) |
| #define TG3_TX_RING_BYTES (sizeof(struct tg3_tx_buffer_desc) * \ |
| TG3_TX_RING_SIZE) |
| #define NEXT_TX(N) (((N) + 1) & (TG3_TX_RING_SIZE - 1)) |
| |
| #define TG3_RX_DMA_ALIGN 16 |
| #define TG3_RX_HEADROOM ALIGN(VLAN_HLEN, TG3_RX_DMA_ALIGN) |
| |
| #define TG3_DMA_BYTE_ENAB 64 |
| |
| #define TG3_RX_STD_DMA_SZ 1536 |
| #define TG3_RX_JMB_DMA_SZ 9046 |
| |
| #define TG3_RX_DMA_TO_MAP_SZ(x) ((x) + TG3_DMA_BYTE_ENAB) |
| |
| #define TG3_RX_STD_MAP_SZ TG3_RX_DMA_TO_MAP_SZ(TG3_RX_STD_DMA_SZ) |
| #define TG3_RX_JMB_MAP_SZ TG3_RX_DMA_TO_MAP_SZ(TG3_RX_JMB_DMA_SZ) |
| |
| #define TG3_RX_STD_BUFF_RING_SIZE(tp) \ |
| (sizeof(struct ring_info) * TG3_RX_STD_RING_SIZE(tp)) |
| |
| #define TG3_RX_JMB_BUFF_RING_SIZE(tp) \ |
| (sizeof(struct ring_info) * TG3_RX_JMB_RING_SIZE(tp)) |
| |
| /* Due to a hardware bug, the 5701 can only DMA to memory addresses |
| * that are at least dword aligned when used in PCIX mode. The driver |
| * works around this bug by double copying the packet. This workaround |
| * is built into the normal double copy length check for efficiency. |
| * |
| * However, the double copy is only necessary on those architectures |
| * where unaligned memory accesses are inefficient. For those architectures |
| * where unaligned memory accesses incur little penalty, we can reintegrate |
| * the 5701 in the normal rx path. Doing so saves a device structure |
| * dereference by hardcoding the double copy threshold in place. |
| */ |
| #define TG3_RX_COPY_THRESHOLD 256 |
| #if NET_IP_ALIGN == 0 || defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) |
| #define TG3_RX_COPY_THRESH(tp) TG3_RX_COPY_THRESHOLD |
| #else |
| #define TG3_RX_COPY_THRESH(tp) ((tp)->rx_copy_thresh) |
| #endif |
| |
| /* minimum number of free TX descriptors required to wake up TX process */ |
| #define TG3_TX_WAKEUP_THRESH(tnapi) ((tnapi)->tx_pending / 4) |
| |
| #define TG3_RAW_IP_ALIGN 2 |
| |
| /* number of ETHTOOL_GSTATS u64's */ |
| #define TG3_NUM_STATS (sizeof(struct tg3_ethtool_stats)/sizeof(u64)) |
| |
| #define TG3_NUM_TEST 6 |
| |
| #define TG3_FW_UPDATE_TIMEOUT_SEC 5 |
| |
| #define FIRMWARE_TG3 "tigon/tg3.bin" |
| #define FIRMWARE_TG3TSO "tigon/tg3_tso.bin" |
| #define FIRMWARE_TG3TSO5 "tigon/tg3_tso5.bin" |
| |
| static char version[] __devinitdata = |
| DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")"; |
| |
| MODULE_AUTHOR("David S. Miller (davem@redhat.com) and Jeff Garzik (jgarzik@pobox.com)"); |
| MODULE_DESCRIPTION("Broadcom Tigon3 ethernet driver"); |
| MODULE_LICENSE("GPL"); |
| MODULE_VERSION(DRV_MODULE_VERSION); |
| MODULE_FIRMWARE(FIRMWARE_TG3); |
| MODULE_FIRMWARE(FIRMWARE_TG3TSO); |
| MODULE_FIRMWARE(FIRMWARE_TG3TSO5); |
| |
| static int tg3_debug = -1; /* -1 == use TG3_DEF_MSG_ENABLE as value */ |
| module_param(tg3_debug, int, 0); |
| MODULE_PARM_DESC(tg3_debug, "Tigon3 bitmapped debugging message enable value"); |
| |
| static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = { |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5700)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5701)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702FE)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705_2)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705M)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705M_2)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702X)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703X)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702A3)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703A3)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5782)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5788)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5789)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901_2)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S_2)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705F)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5721)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5722)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751M)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752M)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753M)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753F)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754M)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755M)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5756)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5786)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787M)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787F)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714S)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715S)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780S)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5781)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906M)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5784)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5764)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5723)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5761S)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5761SE)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5785_G)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5785_F)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57780)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57760)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57790)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57788)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5717)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5718)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57781)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57785)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57761)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57765)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57791)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57795)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5719)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1001)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1003)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100)}, |
| {PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_TIGON3)}, |
| {} |
| }; |
| |
| MODULE_DEVICE_TABLE(pci, tg3_pci_tbl); |
| |
| static const struct { |
| const char string[ETH_GSTRING_LEN]; |
| } ethtool_stats_keys[TG3_NUM_STATS] = { |
| { "rx_octets" }, |
| { "rx_fragments" }, |
| { "rx_ucast_packets" }, |
| { "rx_mcast_packets" }, |
| { "rx_bcast_packets" }, |
| { "rx_fcs_errors" }, |
| { "rx_align_errors" }, |
| { "rx_xon_pause_rcvd" }, |
| { "rx_xoff_pause_rcvd" }, |
| { "rx_mac_ctrl_rcvd" }, |
| { "rx_xoff_entered" }, |
| { "rx_frame_too_long_errors" }, |
| { "rx_jabbers" }, |
| { "rx_undersize_packets" }, |
| { "rx_in_length_errors" }, |
| { "rx_out_length_errors" }, |
| { "rx_64_or_less_octet_packets" }, |
| { "rx_65_to_127_octet_packets" }, |
| { "rx_128_to_255_octet_packets" }, |
| { "rx_256_to_511_octet_packets" }, |
| { "rx_512_to_1023_octet_packets" }, |
| { "rx_1024_to_1522_octet_packets" }, |
| { "rx_1523_to_2047_octet_packets" }, |
| { "rx_2048_to_4095_octet_packets" }, |
| { "rx_4096_to_8191_octet_packets" }, |
| { "rx_8192_to_9022_octet_packets" }, |
| |
| { "tx_octets" }, |
| { "tx_collisions" }, |
| |
| { "tx_xon_sent" }, |
| { "tx_xoff_sent" }, |
| { "tx_flow_control" }, |
| { "tx_mac_errors" }, |
| { "tx_single_collisions" }, |
| { "tx_mult_collisions" }, |
| { "tx_deferred" }, |
| { "tx_excessive_collisions" }, |
| { "tx_late_collisions" }, |
| { "tx_collide_2times" }, |
| { "tx_collide_3times" }, |
| { "tx_collide_4times" }, |
| { "tx_collide_5times" }, |
| { "tx_collide_6times" }, |
| { "tx_collide_7times" }, |
| { "tx_collide_8times" }, |
| { "tx_collide_9times" }, |
| { "tx_collide_10times" }, |
| { "tx_collide_11times" }, |
| { "tx_collide_12times" }, |
| { "tx_collide_13times" }, |
| { "tx_collide_14times" }, |
| { "tx_collide_15times" }, |
| { "tx_ucast_packets" }, |
| { "tx_mcast_packets" }, |
| { "tx_bcast_packets" }, |
| { "tx_carrier_sense_errors" }, |
| { "tx_discards" }, |
| { "tx_errors" }, |
| |
| { "dma_writeq_full" }, |
| { "dma_write_prioq_full" }, |
| { "rxbds_empty" }, |
| { "rx_discards" }, |
| { "rx_errors" }, |
| { "rx_threshold_hit" }, |
| |
| { "dma_readq_full" }, |
| { "dma_read_prioq_full" }, |
| { "tx_comp_queue_full" }, |
| |
| { "ring_set_send_prod_index" }, |
| { "ring_status_update" }, |
| { "nic_irqs" }, |
| { "nic_avoided_irqs" }, |
| { "nic_tx_threshold_hit" } |
| }; |
| |
| static const struct { |
| const char string[ETH_GSTRING_LEN]; |
| } ethtool_test_keys[TG3_NUM_TEST] = { |
| { "nvram test (online) " }, |
| { "link test (online) " }, |
| { "register test (offline)" }, |
| { "memory test (offline)" }, |
| { "loopback test (offline)" }, |
| { "interrupt test (offline)" }, |
| }; |
| |
| static void tg3_write32(struct tg3 *tp, u32 off, u32 val) |
| { |
| writel(val, tp->regs + off); |
| } |
| |
| static u32 tg3_read32(struct tg3 *tp, u32 off) |
| { |
| return readl(tp->regs + off); |
| } |
| |
| static void tg3_ape_write32(struct tg3 *tp, u32 off, u32 val) |
| { |
| writel(val, tp->aperegs + off); |
| } |
| |
| static u32 tg3_ape_read32(struct tg3 *tp, u32 off) |
| { |
| return readl(tp->aperegs + off); |
| } |
| |
| static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val) |
| { |
| unsigned long flags; |
| |
| spin_lock_irqsave(&tp->indirect_lock, flags); |
| pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off); |
| pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val); |
| spin_unlock_irqrestore(&tp->indirect_lock, flags); |
| } |
| |
| static void tg3_write_flush_reg32(struct tg3 *tp, u32 off, u32 val) |
| { |
| writel(val, tp->regs + off); |
| readl(tp->regs + off); |
| } |
| |
| static u32 tg3_read_indirect_reg32(struct tg3 *tp, u32 off) |
| { |
| unsigned long flags; |
| u32 val; |
| |
| spin_lock_irqsave(&tp->indirect_lock, flags); |
| pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off); |
| pci_read_config_dword(tp->pdev, TG3PCI_REG_DATA, &val); |
| spin_unlock_irqrestore(&tp->indirect_lock, flags); |
| return val; |
| } |
| |
| static void tg3_write_indirect_mbox(struct tg3 *tp, u32 off, u32 val) |
| { |
| unsigned long flags; |
| |
| if (off == (MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW)) { |
| pci_write_config_dword(tp->pdev, TG3PCI_RCV_RET_RING_CON_IDX + |
| TG3_64BIT_REG_LOW, val); |
| return; |
| } |
| if (off == TG3_RX_STD_PROD_IDX_REG) { |
| pci_write_config_dword(tp->pdev, TG3PCI_STD_RING_PROD_IDX + |
| TG3_64BIT_REG_LOW, val); |
| return; |
| } |
| |
| spin_lock_irqsave(&tp->indirect_lock, flags); |
| pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off + 0x5600); |
| pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val); |
| spin_unlock_irqrestore(&tp->indirect_lock, flags); |
| |
| /* In indirect mode when disabling interrupts, we also need |
| * to clear the interrupt bit in the GRC local ctrl register. |
| */ |
| if ((off == (MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW)) && |
| (val == 0x1)) { |
| pci_write_config_dword(tp->pdev, TG3PCI_MISC_LOCAL_CTRL, |
| tp->grc_local_ctrl|GRC_LCLCTRL_CLEARINT); |
| } |
| } |
| |
| static u32 tg3_read_indirect_mbox(struct tg3 *tp, u32 off) |
| { |
| unsigned long flags; |
| u32 val; |
| |
| spin_lock_irqsave(&tp->indirect_lock, flags); |
| pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off + 0x5600); |
| pci_read_config_dword(tp->pdev, TG3PCI_REG_DATA, &val); |
| spin_unlock_irqrestore(&tp->indirect_lock, flags); |
| return val; |
| } |
| |
| /* usec_wait specifies the wait time in usec when writing to certain registers |
| * where it is unsafe to read back the register without some delay. |
| * GRC_LOCAL_CTRL is one example if the GPIOs are toggled to switch power. |
| * TG3PCI_CLOCK_CTRL is another example if the clock frequencies are changed. |
| */ |
| static void _tw32_flush(struct tg3 *tp, u32 off, u32 val, u32 usec_wait) |
| { |
| if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) || |
| (tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND)) |
| /* Non-posted methods */ |
| tp->write32(tp, off, val); |
| else { |
| /* Posted method */ |
| tg3_write32(tp, off, val); |
| if (usec_wait) |
| udelay(usec_wait); |
| tp->read32(tp, off); |
| } |
| /* Wait again after the read for the posted method to guarantee that |
| * the wait time is met. |
| */ |
| if (usec_wait) |
| udelay(usec_wait); |
| } |
| |
| static inline void tw32_mailbox_flush(struct tg3 *tp, u32 off, u32 val) |
| { |
| tp->write32_mbox(tp, off, val); |
| if (!(tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) && |
| !(tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND)) |
| tp->read32_mbox(tp, off); |
| } |
| |
| static void tg3_write32_tx_mbox(struct tg3 *tp, u32 off, u32 val) |
| { |
| void __iomem *mbox = tp->regs + off; |
| writel(val, mbox); |
| if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) |
| writel(val, mbox); |
| if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) |
| readl(mbox); |
| } |
| |
| static u32 tg3_read32_mbox_5906(struct tg3 *tp, u32 off) |
| { |
| return readl(tp->regs + off + GRCMBOX_BASE); |
| } |
| |
| static void tg3_write32_mbox_5906(struct tg3 *tp, u32 off, u32 val) |
| { |
| writel(val, tp->regs + off + GRCMBOX_BASE); |
| } |
| |
| #define tw32_mailbox(reg, val) tp->write32_mbox(tp, reg, val) |
| #define tw32_mailbox_f(reg, val) tw32_mailbox_flush(tp, (reg), (val)) |
| #define tw32_rx_mbox(reg, val) tp->write32_rx_mbox(tp, reg, val) |
| #define tw32_tx_mbox(reg, val) tp->write32_tx_mbox(tp, reg, val) |
| #define tr32_mailbox(reg) tp->read32_mbox(tp, reg) |
| |
| #define tw32(reg, val) tp->write32(tp, reg, val) |
| #define tw32_f(reg, val) _tw32_flush(tp, (reg), (val), 0) |
| #define tw32_wait_f(reg, val, us) _tw32_flush(tp, (reg), (val), (us)) |
| #define tr32(reg) tp->read32(tp, reg) |
| |
| static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val) |
| { |
| unsigned long flags; |
| |
| if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) && |
| (off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC)) |
| return; |
| |
| spin_lock_irqsave(&tp->indirect_lock, flags); |
| if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) { |
| pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); |
| pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); |
| |
| /* Always leave this as zero. */ |
| pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); |
| } else { |
| tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, off); |
| tw32_f(TG3PCI_MEM_WIN_DATA, val); |
| |
| /* Always leave this as zero. */ |
| tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, 0); |
| } |
| spin_unlock_irqrestore(&tp->indirect_lock, flags); |
| } |
| |
| static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val) |
| { |
| unsigned long flags; |
| |
| if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) && |
| (off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC)) { |
| *val = 0; |
| return; |
| } |
| |
| spin_lock_irqsave(&tp->indirect_lock, flags); |
| if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) { |
| pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); |
| pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); |
| |
| /* Always leave this as zero. */ |
| pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); |
| } else { |
| tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, off); |
| *val = tr32(TG3PCI_MEM_WIN_DATA); |
| |
| /* Always leave this as zero. */ |
| tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, 0); |
| } |
| spin_unlock_irqrestore(&tp->indirect_lock, flags); |
| } |
| |
| static void tg3_ape_lock_init(struct tg3 *tp) |
| { |
| int i; |
| u32 regbase; |
| |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) |
| regbase = TG3_APE_LOCK_GRANT; |
| else |
| regbase = TG3_APE_PER_LOCK_GRANT; |
| |
| /* Make sure the driver hasn't any stale locks. */ |
| for (i = 0; i < 8; i++) |
| tg3_ape_write32(tp, regbase + 4 * i, APE_LOCK_GRANT_DRIVER); |
| } |
| |
| static int tg3_ape_lock(struct tg3 *tp, int locknum) |
| { |
| int i, off; |
| int ret = 0; |
| u32 status, req, gnt; |
| |
| if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) |
| return 0; |
| |
| switch (locknum) { |
| case TG3_APE_LOCK_GRC: |
| case TG3_APE_LOCK_MEM: |
| break; |
| default: |
| return -EINVAL; |
| } |
| |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) { |
| req = TG3_APE_LOCK_REQ; |
| gnt = TG3_APE_LOCK_GRANT; |
| } else { |
| req = TG3_APE_PER_LOCK_REQ; |
| gnt = TG3_APE_PER_LOCK_GRANT; |
| } |
| |
| off = 4 * locknum; |
| |
| tg3_ape_write32(tp, req + off, APE_LOCK_REQ_DRIVER); |
| |
| /* Wait for up to 1 millisecond to acquire lock. */ |
| for (i = 0; i < 100; i++) { |
| status = tg3_ape_read32(tp, gnt + off); |
| if (status == APE_LOCK_GRANT_DRIVER) |
| break; |
| udelay(10); |
| } |
| |
| if (status != APE_LOCK_GRANT_DRIVER) { |
| /* Revoke the lock request. */ |
| tg3_ape_write32(tp, gnt + off, |
| APE_LOCK_GRANT_DRIVER); |
| |
| ret = -EBUSY; |
| } |
| |
| return ret; |
| } |
| |
| static void tg3_ape_unlock(struct tg3 *tp, int locknum) |
| { |
| u32 gnt; |
| |
| if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) |
| return; |
| |
| switch (locknum) { |
| case TG3_APE_LOCK_GRC: |
| case TG3_APE_LOCK_MEM: |
| break; |
| default: |
| return; |
| } |
| |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) |
| gnt = TG3_APE_LOCK_GRANT; |
| else |
| gnt = TG3_APE_PER_LOCK_GRANT; |
| |
| tg3_ape_write32(tp, gnt + 4 * locknum, APE_LOCK_GRANT_DRIVER); |
| } |
| |
| static void tg3_disable_ints(struct tg3 *tp) |
| { |
| int i; |
| |
| tw32(TG3PCI_MISC_HOST_CTRL, |
| (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT)); |
| for (i = 0; i < tp->irq_max; i++) |
| tw32_mailbox_f(tp->napi[i].int_mbox, 0x00000001); |
| } |
| |
| static void tg3_enable_ints(struct tg3 *tp) |
| { |
| int i; |
| |
| tp->irq_sync = 0; |
| wmb(); |
| |
| tw32(TG3PCI_MISC_HOST_CTRL, |
| (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT)); |
| |
| tp->coal_now = tp->coalesce_mode | HOSTCC_MODE_ENABLE; |
| for (i = 0; i < tp->irq_cnt; i++) { |
| struct tg3_napi *tnapi = &tp->napi[i]; |
| |
| tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); |
| if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) |
| tw32_mailbox_f(tnapi->int_mbox, tnapi->last_tag << 24); |
| |
| tp->coal_now |= tnapi->coal_now; |
| } |
| |
| /* Force an initial interrupt */ |
| if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && |
| (tp->napi[0].hw_status->status & SD_STATUS_UPDATED)) |
| tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); |
| else |
| tw32(HOSTCC_MODE, tp->coal_now); |
| |
| tp->coal_now &= ~(tp->napi[0].coal_now | tp->napi[1].coal_now); |
| } |
| |
| static inline unsigned int tg3_has_work(struct tg3_napi *tnapi) |
| { |
| struct tg3 *tp = tnapi->tp; |
| struct tg3_hw_status *sblk = tnapi->hw_status; |
| unsigned int work_exists = 0; |
| |
| /* check for phy events */ |
| if (!(tp->tg3_flags & |
| (TG3_FLAG_USE_LINKCHG_REG | |
| TG3_FLAG_POLL_SERDES))) { |
| if (sblk->status & SD_STATUS_LINK_CHG) |
| work_exists = 1; |
| } |
| /* check for RX/TX work to do */ |
| if (sblk->idx[0].tx_consumer != tnapi->tx_cons || |
| *(tnapi->rx_rcb_prod_idx) != tnapi->rx_rcb_ptr) |
| work_exists = 1; |
| |
| return work_exists; |
| } |
| |
| /* tg3_int_reenable |
| * similar to tg3_enable_ints, but it accurately determines whether there |
| * is new work pending and can return without flushing the PIO write |
| * which reenables interrupts |
| */ |
| static void tg3_int_reenable(struct tg3_napi *tnapi) |
| { |
| struct tg3 *tp = tnapi->tp; |
| |
| tw32_mailbox(tnapi->int_mbox, tnapi->last_tag << 24); |
| mmiowb(); |
| |
| /* When doing tagged status, this work check is unnecessary. |
| * The last_tag we write above tells the chip which piece of |
| * work we've completed. |
| */ |
| if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) && |
| tg3_has_work(tnapi)) |
| tw32(HOSTCC_MODE, tp->coalesce_mode | |
| HOSTCC_MODE_ENABLE | tnapi->coal_now); |
| } |
| |
| static void tg3_switch_clocks(struct tg3 *tp) |
| { |
| u32 clock_ctrl; |
| u32 orig_clock_ctrl; |
| |
| if ((tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) || |
| (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) |
| return; |
| |
| clock_ctrl = tr32(TG3PCI_CLOCK_CTRL); |
| |
| orig_clock_ctrl = clock_ctrl; |
| clock_ctrl &= (CLOCK_CTRL_FORCE_CLKRUN | |
| CLOCK_CTRL_CLKRUN_OENABLE | |
| 0x1f); |
| tp->pci_clock_ctrl = clock_ctrl; |
| |
| if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { |
| if (orig_clock_ctrl & CLOCK_CTRL_625_CORE) { |
| tw32_wait_f(TG3PCI_CLOCK_CTRL, |
| clock_ctrl | CLOCK_CTRL_625_CORE, 40); |
| } |
| } else if ((orig_clock_ctrl & CLOCK_CTRL_44MHZ_CORE) != 0) { |
| tw32_wait_f(TG3PCI_CLOCK_CTRL, |
| clock_ctrl | |
| (CLOCK_CTRL_44MHZ_CORE | CLOCK_CTRL_ALTCLK), |
| 40); |
| tw32_wait_f(TG3PCI_CLOCK_CTRL, |
| clock_ctrl | (CLOCK_CTRL_ALTCLK), |
| 40); |
| } |
| tw32_wait_f(TG3PCI_CLOCK_CTRL, clock_ctrl, 40); |
| } |
| |
| #define PHY_BUSY_LOOPS 5000 |
| |
| static int tg3_readphy(struct tg3 *tp, int reg, u32 *val) |
| { |
| u32 frame_val; |
| unsigned int loops; |
| int ret; |
| |
| if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) { |
| tw32_f(MAC_MI_MODE, |
| (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL)); |
| udelay(80); |
| } |
| |
| *val = 0x0; |
| |
| frame_val = ((tp->phy_addr << MI_COM_PHY_ADDR_SHIFT) & |
| MI_COM_PHY_ADDR_MASK); |
| frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) & |
| MI_COM_REG_ADDR_MASK); |
| frame_val |= (MI_COM_CMD_READ | MI_COM_START); |
| |
| tw32_f(MAC_MI_COM, frame_val); |
| |
| loops = PHY_BUSY_LOOPS; |
| while (loops != 0) { |
| udelay(10); |
| frame_val = tr32(MAC_MI_COM); |
| |
| if ((frame_val & MI_COM_BUSY) == 0) { |
| udelay(5); |
| frame_val = tr32(MAC_MI_COM); |
| break; |
| } |
| loops -= 1; |
| } |
| |
| ret = -EBUSY; |
| if (loops != 0) { |
| *val = frame_val & MI_COM_DATA_MASK; |
| ret = 0; |
| } |
| |
| if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) { |
| tw32_f(MAC_MI_MODE, tp->mi_mode); |
| udelay(80); |
| } |
| |
| return ret; |
| } |
| |
| static int tg3_writephy(struct tg3 *tp, int reg, u32 val) |
| { |
| u32 frame_val; |
| unsigned int loops; |
| int ret; |
| |
| if ((tp->phy_flags & TG3_PHYFLG_IS_FET) && |
| (reg == MII_TG3_CTRL || reg == MII_TG3_AUX_CTRL)) |
| return 0; |
| |
| if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) { |
| tw32_f(MAC_MI_MODE, |
| (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL)); |
| udelay(80); |
| } |
| |
| frame_val = ((tp->phy_addr << MI_COM_PHY_ADDR_SHIFT) & |
| MI_COM_PHY_ADDR_MASK); |
| frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) & |
| MI_COM_REG_ADDR_MASK); |
| frame_val |= (val & MI_COM_DATA_MASK); |
| frame_val |= (MI_COM_CMD_WRITE | MI_COM_START); |
| |
| tw32_f(MAC_MI_COM, frame_val); |
| |
| loops = PHY_BUSY_LOOPS; |
| while (loops != 0) { |
| udelay(10); |
| frame_val = tr32(MAC_MI_COM); |
| if ((frame_val & MI_COM_BUSY) == 0) { |
| udelay(5); |
| frame_val = tr32(MAC_MI_COM); |
| break; |
| } |
| loops -= 1; |
| } |
| |
| ret = -EBUSY; |
| if (loops != 0) |
| ret = 0; |
| |
| if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) { |
| tw32_f(MAC_MI_MODE, tp->mi_mode); |
| udelay(80); |
| } |
| |
| return ret; |
| } |
| |
| static int tg3_bmcr_reset(struct tg3 *tp) |
| { |
| u32 phy_control; |
| int limit, err; |
| |
| /* OK, reset it, and poll the BMCR_RESET bit until it |
| * clears or we time out. |
| */ |
| phy_control = BMCR_RESET; |
| err = tg3_writephy(tp, MII_BMCR, phy_control); |
| if (err != 0) |
| return -EBUSY; |
| |
| limit = 5000; |
| while (limit--) { |
| err = tg3_readphy(tp, MII_BMCR, &phy_control); |
| if (err != 0) |
| return -EBUSY; |
| |
| if ((phy_control & BMCR_RESET) == 0) { |
| udelay(40); |
| break; |
| } |
| udelay(10); |
| } |
| if (limit < 0) |
| return -EBUSY; |
| |
| return 0; |
| } |
| |
| static int tg3_mdio_read(struct mii_bus *bp, int mii_id, int reg) |
| { |
| struct tg3 *tp = bp->priv; |
| u32 val; |
| |
| spin_lock_bh(&tp->lock); |
| |
| if (tg3_readphy(tp, reg, &val)) |
| val = -EIO; |
| |
| spin_unlock_bh(&tp->lock); |
| |
| return val; |
| } |
| |
| static int tg3_mdio_write(struct mii_bus *bp, int mii_id, int reg, u16 val) |
| { |
| struct tg3 *tp = bp->priv; |
| u32 ret = 0; |
| |
| spin_lock_bh(&tp->lock); |
| |
| if (tg3_writephy(tp, reg, val)) |
| ret = -EIO; |
| |
| spin_unlock_bh(&tp->lock); |
| |
| return ret; |
| } |
| |
| static int tg3_mdio_reset(struct mii_bus *bp) |
| { |
| return 0; |
| } |
| |
| static void tg3_mdio_config_5785(struct tg3 *tp) |
| { |
| u32 val; |
| struct phy_device *phydev; |
| |
| phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]; |
| switch (phydev->drv->phy_id & phydev->drv->phy_id_mask) { |
| case PHY_ID_BCM50610: |
| case PHY_ID_BCM50610M: |
| val = MAC_PHYCFG2_50610_LED_MODES; |
| break; |
| case PHY_ID_BCMAC131: |
| val = MAC_PHYCFG2_AC131_LED_MODES; |
| break; |
| case PHY_ID_RTL8211C: |
| val = MAC_PHYCFG2_RTL8211C_LED_MODES; |
| break; |
| case PHY_ID_RTL8201E: |
| val = MAC_PHYCFG2_RTL8201E_LED_MODES; |
| break; |
| default: |
| return; |
| } |
| |
| if (phydev->interface != PHY_INTERFACE_MODE_RGMII) { |
| tw32(MAC_PHYCFG2, val); |
| |
| val = tr32(MAC_PHYCFG1); |
| val &= ~(MAC_PHYCFG1_RGMII_INT | |
| MAC_PHYCFG1_RXCLK_TO_MASK | MAC_PHYCFG1_TXCLK_TO_MASK); |
| val |= MAC_PHYCFG1_RXCLK_TIMEOUT | MAC_PHYCFG1_TXCLK_TIMEOUT; |
| tw32(MAC_PHYCFG1, val); |
| |
| return; |
| } |
| |
| if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_INBAND_DISABLE)) |
| val |= MAC_PHYCFG2_EMODE_MASK_MASK | |
| MAC_PHYCFG2_FMODE_MASK_MASK | |
| MAC_PHYCFG2_GMODE_MASK_MASK | |
| MAC_PHYCFG2_ACT_MASK_MASK | |
| MAC_PHYCFG2_QUAL_MASK_MASK | |
| MAC_PHYCFG2_INBAND_ENABLE; |
| |
| tw32(MAC_PHYCFG2, val); |
| |
| val = tr32(MAC_PHYCFG1); |
| val &= ~(MAC_PHYCFG1_RXCLK_TO_MASK | MAC_PHYCFG1_TXCLK_TO_MASK | |
| MAC_PHYCFG1_RGMII_EXT_RX_DEC | MAC_PHYCFG1_RGMII_SND_STAT_EN); |
| if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_INBAND_DISABLE)) { |
| if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN) |
| val |= MAC_PHYCFG1_RGMII_EXT_RX_DEC; |
| if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN) |
| val |= MAC_PHYCFG1_RGMII_SND_STAT_EN; |
| } |
| val |= MAC_PHYCFG1_RXCLK_TIMEOUT | MAC_PHYCFG1_TXCLK_TIMEOUT | |
| MAC_PHYCFG1_RGMII_INT | MAC_PHYCFG1_TXC_DRV; |
| tw32(MAC_PHYCFG1, val); |
| |
| val = tr32(MAC_EXT_RGMII_MODE); |
| val &= ~(MAC_RGMII_MODE_RX_INT_B | |
| MAC_RGMII_MODE_RX_QUALITY | |
| MAC_RGMII_MODE_RX_ACTIVITY | |
| MAC_RGMII_MODE_RX_ENG_DET | |
| MAC_RGMII_MODE_TX_ENABLE | |
| MAC_RGMII_MODE_TX_LOWPWR | |
| MAC_RGMII_MODE_TX_RESET); |
| if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_INBAND_DISABLE)) { |
| if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN) |
| val |= MAC_RGMII_MODE_RX_INT_B | |
| MAC_RGMII_MODE_RX_QUALITY | |
| MAC_RGMII_MODE_RX_ACTIVITY | |
| MAC_RGMII_MODE_RX_ENG_DET; |
| if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN) |
| val |= MAC_RGMII_MODE_TX_ENABLE | |
| MAC_RGMII_MODE_TX_LOWPWR | |
| MAC_RGMII_MODE_TX_RESET; |
| } |
| tw32(MAC_EXT_RGMII_MODE, val); |
| } |
| |
| static void tg3_mdio_start(struct tg3 *tp) |
| { |
| tp->mi_mode &= ~MAC_MI_MODE_AUTO_POLL; |
| tw32_f(MAC_MI_MODE, tp->mi_mode); |
| udelay(80); |
| |
| if ((tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) && |
| GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) |
| tg3_mdio_config_5785(tp); |
| } |
| |
| static int tg3_mdio_init(struct tg3 *tp) |
| { |
| int i; |
| u32 reg; |
| struct phy_device *phydev; |
| |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || |
| GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) { |
| u32 is_serdes; |
| |
| tp->phy_addr = PCI_FUNC(tp->pdev->devfn) + 1; |
| |
| if (tp->pci_chip_rev_id != CHIPREV_ID_5717_A0) |
| is_serdes = tr32(SG_DIG_STATUS) & SG_DIG_IS_SERDES; |
| else |
| is_serdes = tr32(TG3_CPMU_PHY_STRAP) & |
| TG3_CPMU_PHY_STRAP_IS_SERDES; |
| if (is_serdes) |
| tp->phy_addr += 7; |
| } else |
| tp->phy_addr = TG3_PHY_MII_ADDR; |
| |
| tg3_mdio_start(tp); |
| |
| if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) || |
| (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED)) |
| return 0; |
| |
| tp->mdio_bus = mdiobus_alloc(); |
| if (tp->mdio_bus == NULL) |
| return -ENOMEM; |
| |
| tp->mdio_bus->name = "tg3 mdio bus"; |
| snprintf(tp->mdio_bus->id, MII_BUS_ID_SIZE, "%x", |
| (tp->pdev->bus->number << 8) | tp->pdev->devfn); |
| tp->mdio_bus->priv = tp; |
| tp->mdio_bus->parent = &tp->pdev->dev; |
| tp->mdio_bus->read = &tg3_mdio_read; |
| tp->mdio_bus->write = &tg3_mdio_write; |
| tp->mdio_bus->reset = &tg3_mdio_reset; |
| tp->mdio_bus->phy_mask = ~(1 << TG3_PHY_MII_ADDR); |
| tp->mdio_bus->irq = &tp->mdio_irq[0]; |
| |
| for (i = 0; i < PHY_MAX_ADDR; i++) |
| tp->mdio_bus->irq[i] = PHY_POLL; |
| |
| /* The bus registration will look for all the PHYs on the mdio bus. |
| * Unfortunately, it does not ensure the PHY is powered up before |
| * accessing the PHY ID registers. A chip reset is the |
| * quickest way to bring the device back to an operational state.. |
| */ |
| if (tg3_readphy(tp, MII_BMCR, ®) || (reg & BMCR_PDOWN)) |
| tg3_bmcr_reset(tp); |
| |
| i = mdiobus_register(tp->mdio_bus); |
| if (i) { |
| dev_warn(&tp->pdev->dev, "mdiobus_reg failed (0x%x)\n", i); |
| mdiobus_free(tp->mdio_bus); |
| return i; |
| } |
| |
| phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]; |
| |
| if (!phydev || !phydev->drv) { |
| dev_warn(&tp->pdev->dev, "No PHY devices\n"); |
| mdiobus_unregister(tp->mdio_bus); |
| mdiobus_free(tp->mdio_bus); |
| return -ENODEV; |
| } |
| |
| switch (phydev->drv->phy_id & phydev->drv->phy_id_mask) { |
| case PHY_ID_BCM57780: |
| phydev->interface = PHY_INTERFACE_MODE_GMII; |
| phydev->dev_flags |= PHY_BRCM_AUTO_PWRDWN_ENABLE; |
| break; |
| case PHY_ID_BCM50610: |
| case PHY_ID_BCM50610M: |
| phydev->dev_flags |= PHY_BRCM_CLEAR_RGMII_MODE | |
| PHY_BRCM_RX_REFCLK_UNUSED | |
| PHY_BRCM_DIS_TXCRXC_NOENRGY | |
| PHY_BRCM_AUTO_PWRDWN_ENABLE; |
| if (tp->tg3_flags3 & TG3_FLG3_RGMII_INBAND_DISABLE) |
| phydev->dev_flags |= PHY_BRCM_STD_IBND_DISABLE; |
| if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN) |
| phydev->dev_flags |= PHY_BRCM_EXT_IBND_RX_ENABLE; |
| if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN) |
| phydev->dev_flags |= PHY_BRCM_EXT_IBND_TX_ENABLE; |
| /* fallthru */ |
| case PHY_ID_RTL8211C: |
| phydev->interface = PHY_INTERFACE_MODE_RGMII; |
| break; |
| case PHY_ID_RTL8201E: |
| case PHY_ID_BCMAC131: |
| phydev->interface = PHY_INTERFACE_MODE_MII; |
| phydev->dev_flags |= PHY_BRCM_AUTO_PWRDWN_ENABLE; |
| tp->phy_flags |= TG3_PHYFLG_IS_FET; |
| break; |
| } |
| |
| tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_INITED; |
| |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) |
| tg3_mdio_config_5785(tp); |
| |
| return 0; |
| } |
| |
| static void tg3_mdio_fini(struct tg3 *tp) |
| { |
| if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) { |
| tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_INITED; |
| mdiobus_unregister(tp->mdio_bus); |
| mdiobus_free(tp->mdio_bus); |
| } |
| } |
| |
| static int tg3_phy_cl45_write(struct tg3 *tp, u32 devad, u32 addr, u32 val) |
| { |
| int err; |
| |
| err = tg3_writephy(tp, MII_TG3_MMD_CTRL, devad); |
| if (err) |
| goto done; |
| |
| err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, addr); |
| if (err) |
| goto done; |
| |
| err = tg3_writephy(tp, MII_TG3_MMD_CTRL, |
| MII_TG3_MMD_CTRL_DATA_NOINC | devad); |
| if (err) |
| goto done; |
| |
| err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, val); |
| |
| done: |
| return err; |
| } |
| |
| static int tg3_phy_cl45_read(struct tg3 *tp, u32 devad, u32 addr, u32 *val) |
| { |
| int err; |
| |
| err = tg3_writephy(tp, MII_TG3_MMD_CTRL, devad); |
| if (err) |
| goto done; |
| |
| err = tg3_writephy(tp, MII_TG3_MMD_ADDRESS, addr); |
| if (err) |
| goto done; |
| |
| err = tg3_writephy(tp, MII_TG3_MMD_CTRL, |
| MII_TG3_MMD_CTRL_DATA_NOINC | devad); |
| if (err) |
| goto done; |
| |
| err = tg3_readphy(tp, MII_TG3_MMD_ADDRESS, val); |
| |
| done: |
| return err; |
| } |
| |
| /* tp->lock is held. */ |
| static inline void tg3_generate_fw_event(struct tg3 *tp) |
| { |
| u32 val; |
| |
| val = tr32(GRC_RX_CPU_EVENT); |
| val |= GRC_RX_CPU_DRIVER_EVENT; |
| tw32_f(GRC_RX_CPU_EVENT, val); |
| |
| tp->last_event_jiffies = jiffies; |
| } |
| |
| #define TG3_FW_EVENT_TIMEOUT_USEC 2500 |
| |
| /* tp->lock is held. */ |
| static void tg3_wait_for_event_ack(struct tg3 *tp) |
| { |
| int i; |
| unsigned int delay_cnt; |
| long time_remain; |
| |
| /* If enough time has passed, no wait is necessary. */ |
| time_remain = (long)(tp->last_event_jiffies + 1 + |
| usecs_to_jiffies(TG3_FW_EVENT_TIMEOUT_USEC)) - |
| (long)jiffies; |
| if (time_remain < 0) |
| return; |
| |
| /* Check if we can shorten the wait time. */ |
| delay_cnt = jiffies_to_usecs(time_remain); |
| if (delay_cnt > TG3_FW_EVENT_TIMEOUT_USEC) |
| delay_cnt = TG3_FW_EVENT_TIMEOUT_USEC; |
| delay_cnt = (delay_cnt >> 3) + 1; |
| |
| for (i = 0; i < delay_cnt; i++) { |
| if (!(tr32(GRC_RX_CPU_EVENT) & GRC_RX_CPU_DRIVER_EVENT)) |
| break; |
| udelay(8); |
| } |
| } |
| |
| /* tp->lock is held. */ |
| static void tg3_ump_link_report(struct tg3 *tp) |
| { |
| u32 reg; |
| u32 val; |
| |
| if (!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS) || |
| !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) |
| return; |
| |
| tg3_wait_for_event_ack(tp); |
| |
| tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_LINK_UPDATE); |
| |
| tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 14); |
| |
| val = 0; |
| if (!tg3_readphy(tp, MII_BMCR, ®)) |
| val = reg << 16; |
| if (!tg3_readphy(tp, MII_BMSR, ®)) |
| val |= (reg & 0xffff); |
| tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, val); |
| |
| val = 0; |
| if (!tg3_readphy(tp, MII_ADVERTISE, ®)) |
| val = reg << 16; |
| if (!tg3_readphy(tp, MII_LPA, ®)) |
| val |= (reg & 0xffff); |
| tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 4, val); |
| |
| val = 0; |
| if (!(tp->phy_flags & TG3_PHYFLG_MII_SERDES)) { |
| if (!tg3_readphy(tp, MII_CTRL1000, ®)) |
| val = reg << 16; |
| if (!tg3_readphy(tp, MII_STAT1000, ®)) |
| val |= (reg & 0xffff); |
| } |
| tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 8, val); |
| |
| if (!tg3_readphy(tp, MII_PHYADDR, ®)) |
| val = reg << 16; |
| else |
| val = 0; |
| tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX + 12, val); |
| |
| tg3_generate_fw_event(tp); |
| } |
| |
| static void tg3_link_report(struct tg3 *tp) |
| { |
| if (!netif_carrier_ok(tp->dev)) { |
| netif_info(tp, link, tp->dev, "Link is down\n"); |
| tg3_ump_link_report(tp); |
| } else if (netif_msg_link(tp)) { |
| netdev_info(tp->dev, "Link is up at %d Mbps, %s duplex\n", |
| (tp->link_config.active_speed == SPEED_1000 ? |
| 1000 : |
| (tp->link_config.active_speed == SPEED_100 ? |
| 100 : 10)), |
| (tp->link_config.active_duplex == DUPLEX_FULL ? |
| "full" : "half")); |
| |
| netdev_info(tp->dev, "Flow control is %s for TX and %s for RX\n", |
| (tp->link_config.active_flowctrl & FLOW_CTRL_TX) ? |
| "on" : "off", |
| (tp->link_config.active_flowctrl & FLOW_CTRL_RX) ? |
| "on" : "off"); |
| tg3_ump_link_report(tp); |
| } |
| } |
| |
| static u16 tg3_advert_flowctrl_1000T(u8 flow_ctrl) |
| { |
| u16 miireg; |
| |
| if ((flow_ctrl & FLOW_CTRL_TX) && (flow_ctrl & FLOW_CTRL_RX)) |
| miireg = ADVERTISE_PAUSE_CAP; |
| else if (flow_ctrl & FLOW_CTRL_TX) |
| miireg = ADVERTISE_PAUSE_ASYM; |
| else if (flow_ctrl & FLOW_CTRL_RX) |
| miireg = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; |
| else |
| miireg = 0; |
| |
| return miireg; |
| } |
| |
| static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl) |
| { |
| u16 miireg; |
| |
| if ((flow_ctrl & FLOW_CTRL_TX) && (flow_ctrl & FLOW_CTRL_RX)) |
| miireg = ADVERTISE_1000XPAUSE; |
| else if (flow_ctrl & FLOW_CTRL_TX) |
| miireg = ADVERTISE_1000XPSE_ASYM; |
| else if (flow_ctrl & FLOW_CTRL_RX) |
| miireg = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM; |
| else |
| miireg = 0; |
| |
| return miireg; |
| } |
| |
| static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv) |
| { |
| u8 cap = 0; |
| |
| if (lcladv & ADVERTISE_1000XPAUSE) { |
| if (lcladv & ADVERTISE_1000XPSE_ASYM) { |
| if (rmtadv & LPA_1000XPAUSE) |
| cap = FLOW_CTRL_TX | FLOW_CTRL_RX; |
| else if (rmtadv & LPA_1000XPAUSE_ASYM) |
| cap = FLOW_CTRL_RX; |
| } else { |
| if (rmtadv & LPA_1000XPAUSE) |
| cap = FLOW_CTRL_TX | FLOW_CTRL_RX; |
| } |
| } else if (lcladv & ADVERTISE_1000XPSE_ASYM) { |
| if ((rmtadv & LPA_1000XPAUSE) && (rmtadv & LPA_1000XPAUSE_ASYM)) |
| cap = FLOW_CTRL_TX; |
| } |
| |
| return cap; |
| } |
| |
| static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv) |
| { |
| u8 autoneg; |
| u8 flowctrl = 0; |
| u32 old_rx_mode = tp->rx_mode; |
| u32 old_tx_mode = tp->tx_mode; |
| |
| if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) |
| autoneg = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]->autoneg; |
| else |
| autoneg = tp->link_config.autoneg; |
| |
| if (autoneg == AUTONEG_ENABLE && |
| (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG)) { |
| if (tp->phy_flags & TG3_PHYFLG_ANY_SERDES) |
| flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv); |
| else |
| flowctrl = mii_resolve_flowctrl_fdx(lcladv, rmtadv); |
| } else |
| flowctrl = tp->link_config.flowctrl; |
| |
| tp->link_config.active_flowctrl = flowctrl; |
| |
| if (flowctrl & FLOW_CTRL_RX) |
| tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE; |
| else |
| tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE; |
| |
| if (old_rx_mode != tp->rx_mode) |
| tw32_f(MAC_RX_MODE, tp->rx_mode); |
| |
| if (flowctrl & FLOW_CTRL_TX) |
| tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE; |
| else |
| tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE; |
| |
| if (old_tx_mode != tp->tx_mode) |
| tw32_f(MAC_TX_MODE, tp->tx_mode); |
| } |
| |
| static void tg3_adjust_link(struct net_device *dev) |
| { |
| u8 oldflowctrl, linkmesg = 0; |
| u32 mac_mode, lcl_adv, rmt_adv; |
| struct tg3 *tp = netdev_priv(dev); |
| struct phy_device *phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]; |
| |
| spin_lock_bh(&tp->lock); |
| |
| mac_mode = tp->mac_mode & ~(MAC_MODE_PORT_MODE_MASK | |
| MAC_MODE_HALF_DUPLEX); |
| |
| oldflowctrl = tp->link_config.active_flowctrl; |
| |
| if (phydev->link) { |
| lcl_adv = 0; |
| rmt_adv = 0; |
| |
| if (phydev->speed == SPEED_100 || phydev->speed == SPEED_10) |
| mac_mode |= MAC_MODE_PORT_MODE_MII; |
| else if (phydev->speed == SPEED_1000 || |
| GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) |
| mac_mode |= MAC_MODE_PORT_MODE_GMII; |
| else |
| mac_mode |= MAC_MODE_PORT_MODE_MII; |
| |
| if (phydev->duplex == DUPLEX_HALF) |
| mac_mode |= MAC_MODE_HALF_DUPLEX; |
| else { |
| lcl_adv = tg3_advert_flowctrl_1000T( |
| tp->link_config.flowctrl); |
| |
| if (phydev->pause) |
| rmt_adv = LPA_PAUSE_CAP; |
| if (phydev->asym_pause) |
| rmt_adv |= LPA_PAUSE_ASYM; |
| } |
| |
| tg3_setup_flow_control(tp, lcl_adv, rmt_adv); |
| } else |
| mac_mode |= MAC_MODE_PORT_MODE_GMII; |
| |
| if (mac_mode != tp->mac_mode) { |
| tp->mac_mode = mac_mode; |
| tw32_f(MAC_MODE, tp->mac_mode); |
| udelay(40); |
| } |
| |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { |
| if (phydev->speed == SPEED_10) |
| tw32(MAC_MI_STAT, |
| MAC_MI_STAT_10MBPS_MODE | |
| MAC_MI_STAT_LNKSTAT_ATTN_ENAB); |
| else |
| tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB); |
| } |
| |
| if (phydev->speed == SPEED_1000 && phydev->duplex == DUPLEX_HALF) |
| tw32(MAC_TX_LENGTHS, |
| ((2 << TX_LENGTHS_IPG_CRS_SHIFT) | |
| (6 << TX_LENGTHS_IPG_SHIFT) | |
| (0xff << TX_LENGTHS_SLOT_TIME_SHIFT))); |
| else |
| tw32(MAC_TX_LENGTHS, |
| ((2 << TX_LENGTHS_IPG_CRS_SHIFT) | |
| (6 << TX_LENGTHS_IPG_SHIFT) | |
| (32 << TX_LENGTHS_SLOT_TIME_SHIFT))); |
| |
| if ((phydev->link && tp->link_config.active_speed == SPEED_INVALID) || |
| (!phydev->link && tp->link_config.active_speed != SPEED_INVALID) || |
| phydev->speed != tp->link_config.active_speed || |
| phydev->duplex != tp->link_config.active_duplex || |
| oldflowctrl != tp->link_config.active_flowctrl) |
| linkmesg = 1; |
| |
| tp->link_config.active_speed = phydev->speed; |
| tp->link_config.active_duplex = phydev->duplex; |
| |
| spin_unlock_bh(&tp->lock); |
| |
| if (linkmesg) |
| tg3_link_report(tp); |
| } |
| |
| static int tg3_phy_init(struct tg3 *tp) |
| { |
| struct phy_device *phydev; |
| |
| if (tp->phy_flags & TG3_PHYFLG_IS_CONNECTED) |
| return 0; |
| |
| /* Bring the PHY back to a known state. */ |
| tg3_bmcr_reset(tp); |
| |
| phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]; |
| |
| /* Attach the MAC to the PHY. */ |
| phydev = phy_connect(tp->dev, dev_name(&phydev->dev), tg3_adjust_link, |
| phydev->dev_flags, phydev->interface); |
| if (IS_ERR(phydev)) { |
| dev_err(&tp->pdev->dev, "Could not attach to PHY\n"); |
| return PTR_ERR(phydev); |
| } |
| |
| /* Mask with MAC supported features. */ |
| switch (phydev->interface) { |
| case PHY_INTERFACE_MODE_GMII: |
| case PHY_INTERFACE_MODE_RGMII: |
| if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY)) { |
| phydev->supported &= (PHY_GBIT_FEATURES | |
| SUPPORTED_Pause | |
| SUPPORTED_Asym_Pause); |
| break; |
| } |
| /* fallthru */ |
| case PHY_INTERFACE_MODE_MII: |
| phydev->supported &= (PHY_BASIC_FEATURES | |
| SUPPORTED_Pause | |
| SUPPORTED_Asym_Pause); |
| break; |
| default: |
| phy_disconnect(tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]); |
| return -EINVAL; |
| } |
| |
| tp->phy_flags |= TG3_PHYFLG_IS_CONNECTED; |
| |
| phydev->advertising = phydev->supported; |
| |
| return 0; |
| } |
| |
| static void tg3_phy_start(struct tg3 *tp) |
| { |
| struct phy_device *phydev; |
| |
| if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED)) |
| return; |
| |
| phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]; |
| |
| if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) { |
| tp->phy_flags &= ~TG3_PHYFLG_IS_LOW_POWER; |
| phydev->speed = tp->link_config.orig_speed; |
| phydev->duplex = tp->link_config.orig_duplex; |
| phydev->autoneg = tp->link_config.orig_autoneg; |
| phydev->advertising = tp->link_config.orig_advertising; |
| } |
| |
| phy_start(phydev); |
| |
| phy_start_aneg(phydev); |
| } |
| |
| static void tg3_phy_stop(struct tg3 *tp) |
| { |
| if (!(tp->phy_flags & TG3_PHYFLG_IS_CONNECTED)) |
| return; |
| |
| phy_stop(tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]); |
| } |
| |
| static void tg3_phy_fini(struct tg3 *tp) |
| { |
| if (tp->phy_flags & TG3_PHYFLG_IS_CONNECTED) { |
| phy_disconnect(tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]); |
| tp->phy_flags &= ~TG3_PHYFLG_IS_CONNECTED; |
| } |
| } |
| |
| static int tg3_phydsp_read(struct tg3 *tp, u32 reg, u32 *val) |
| { |
| int err; |
| |
| err = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg); |
| if (!err) |
| err = tg3_readphy(tp, MII_TG3_DSP_RW_PORT, val); |
| |
| return err; |
| } |
| |
| static int tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val) |
| { |
| int err; |
| |
| err = tg3_writephy(tp, MII_TG3_DSP_ADDRESS, reg); |
| if (!err) |
| err = tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val); |
| |
| return err; |
| } |
| |
| static void tg3_phy_fet_toggle_apd(struct tg3 *tp, bool enable) |
| { |
| u32 phytest; |
| |
| if (!tg3_readphy(tp, MII_TG3_FET_TEST, &phytest)) { |
| u32 phy; |
| |
| tg3_writephy(tp, MII_TG3_FET_TEST, |
| phytest | MII_TG3_FET_SHADOW_EN); |
| if (!tg3_readphy(tp, MII_TG3_FET_SHDW_AUXSTAT2, &phy)) { |
| if (enable) |
| phy |= MII_TG3_FET_SHDW_AUXSTAT2_APD; |
| else |
| phy &= ~MII_TG3_FET_SHDW_AUXSTAT2_APD; |
| tg3_writephy(tp, MII_TG3_FET_SHDW_AUXSTAT2, phy); |
| } |
| tg3_writephy(tp, MII_TG3_FET_TEST, phytest); |
| } |
| } |
| |
| static void tg3_phy_toggle_apd(struct tg3 *tp, bool enable) |
| { |
| u32 reg; |
| |
| if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || |
| ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || |
| GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) && |
| (tp->phy_flags & TG3_PHYFLG_MII_SERDES))) |
| return; |
| |
| if (tp->phy_flags & TG3_PHYFLG_IS_FET) { |
| tg3_phy_fet_toggle_apd(tp, enable); |
| return; |
| } |
| |
| reg = MII_TG3_MISC_SHDW_WREN | |
| MII_TG3_MISC_SHDW_SCR5_SEL | |
| MII_TG3_MISC_SHDW_SCR5_LPED | |
| MII_TG3_MISC_SHDW_SCR5_DLPTLM | |
| MII_TG3_MISC_SHDW_SCR5_SDTL | |
| MII_TG3_MISC_SHDW_SCR5_C125OE; |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 || !enable) |
| reg |= MII_TG3_MISC_SHDW_SCR5_DLLAPD; |
| |
| tg3_writephy(tp, MII_TG3_MISC_SHDW, reg); |
| |
| |
| reg = MII_TG3_MISC_SHDW_WREN | |
| MII_TG3_MISC_SHDW_APD_SEL | |
| MII_TG3_MISC_SHDW_APD_WKTM_84MS; |
| if (enable) |
| reg |= MII_TG3_MISC_SHDW_APD_ENABLE; |
| |
| tg3_writephy(tp, MII_TG3_MISC_SHDW, reg); |
| } |
| |
| static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable) |
| { |
| u32 phy; |
| |
| if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || |
| (tp->phy_flags & TG3_PHYFLG_ANY_SERDES)) |
| return; |
| |
| if (tp->phy_flags & TG3_PHYFLG_IS_FET) { |
| u32 ephy; |
| |
| if (!tg3_readphy(tp, MII_TG3_FET_TEST, &ephy)) { |
| u32 reg = MII_TG3_FET_SHDW_MISCCTRL; |
| |
| tg3_writephy(tp, MII_TG3_FET_TEST, |
| ephy | MII_TG3_FET_SHADOW_EN); |
| if (!tg3_readphy(tp, reg, &phy)) { |
| if (enable) |
| phy |= MII_TG3_FET_SHDW_MISCCTRL_MDIX; |
| else |
| phy &= ~MII_TG3_FET_SHDW_MISCCTRL_MDIX; |
| tg3_writephy(tp, reg, phy); |
| } |
| tg3_writephy(tp, MII_TG3_FET_TEST, ephy); |
| } |
| } else { |
| phy = MII_TG3_AUXCTL_MISC_RDSEL_MISC | |
| MII_TG3_AUXCTL_SHDWSEL_MISC; |
| if (!tg3_writephy(tp, MII_TG3_AUX_CTRL, phy) && |
| !tg3_readphy(tp, MII_TG3_AUX_CTRL, &phy)) { |
| if (enable) |
| phy |= MII_TG3_AUXCTL_MISC_FORCE_AMDIX; |
| else |
| phy &= ~MII_TG3_AUXCTL_MISC_FORCE_AMDIX; |
| phy |= MII_TG3_AUXCTL_MISC_WREN; |
| tg3_writephy(tp, MII_TG3_AUX_CTRL, phy); |
| } |
| } |
| } |
| |
| static void tg3_phy_set_wirespeed(struct tg3 *tp) |
| { |
| u32 val; |
| |
| if (tp->phy_flags & TG3_PHYFLG_NO_ETH_WIRE_SPEED) |
| return; |
| |
| if (!tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x7007) && |
| !tg3_readphy(tp, MII_TG3_AUX_CTRL, &val)) |
| tg3_writephy(tp, MII_TG3_AUX_CTRL, |
| (val | (1 << 15) | (1 << 4))); |
| } |
| |
| static void tg3_phy_apply_otp(struct tg3 *tp) |
| { |
| u32 otp, phy; |
| |
| if (!tp->phy_otp) |
| return; |
| |
| otp = tp->phy_otp; |
| |
| /* Enable SM_DSP clock and tx 6dB coding. */ |
| phy = MII_TG3_AUXCTL_SHDWSEL_AUXCTL | |
| MII_TG3_AUXCTL_ACTL_SMDSP_ENA | |
| MII_TG3_AUXCTL_ACTL_TX_6DB; |
| tg3_writephy(tp, MII_TG3_AUX_CTRL, phy); |
| |
| phy = ((otp & TG3_OTP_AGCTGT_MASK) >> TG3_OTP_AGCTGT_SHIFT); |
| phy |= MII_TG3_DSP_TAP1_AGCTGT_DFLT; |
| tg3_phydsp_write(tp, MII_TG3_DSP_TAP1, phy); |
| |
| phy = ((otp & TG3_OTP_HPFFLTR_MASK) >> TG3_OTP_HPFFLTR_SHIFT) | |
| ((otp & TG3_OTP_HPFOVER_MASK) >> TG3_OTP_HPFOVER_SHIFT); |
| tg3_phydsp_write(tp, MII_TG3_DSP_AADJ1CH0, phy); |
| |
| phy = ((otp & TG3_OTP_LPFDIS_MASK) >> TG3_OTP_LPFDIS_SHIFT); |
| phy |= MII_TG3_DSP_AADJ1CH3_ADCCKADJ; |
| tg3_phydsp_write(tp, MII_TG3_DSP_AADJ1CH3, phy); |
| |
| phy = ((otp & TG3_OTP_VDAC_MASK) >> TG3_OTP_VDAC_SHIFT); |
| tg3_phydsp_write(tp, MII_TG3_DSP_EXP75, phy); |
| |
| phy = ((otp & TG3_OTP_10BTAMP_MASK) >> TG3_OTP_10BTAMP_SHIFT); |
| tg3_phydsp_write(tp, MII_TG3_DSP_EXP96, phy); |
| |
| phy = ((otp & TG3_OTP_ROFF_MASK) >> TG3_OTP_ROFF_SHIFT) | |
| ((otp & TG3_OTP_RCOFF_MASK) >> TG3_OTP_RCOFF_SHIFT); |
| tg3_phydsp_write(tp, MII_TG3_DSP_EXP97, phy); |
| |
| /* Turn off SM_DSP clock. */ |
| phy = MII_TG3_AUXCTL_SHDWSEL_AUXCTL | |
| MII_TG3_AUXCTL_ACTL_TX_6DB; |
| tg3_writephy(tp, MII_TG3_AUX_CTRL, phy); |
| } |
| |
| static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up) |
| { |
| u32 val; |
| |
| if (!(tp->phy_flags & TG3_PHYFLG_EEE_CAP)) |
| return; |
| |
| tp->setlpicnt = 0; |
| |
| if (tp->link_config.autoneg == AUTONEG_ENABLE && |
| current_link_up == 1 && |
| (tp->link_config.active_speed == SPEED_1000 || |
| (tp->link_config.active_speed == SPEED_100 && |
| tp->link_config.active_duplex == DUPLEX_FULL))) { |
| u32 eeectl; |
| |
| if (tp->link_config.active_speed == SPEED_1000) |
| eeectl = TG3_CPMU_EEE_CTRL_EXIT_16_5_US; |
| else |
| eeectl = TG3_CPMU_EEE_CTRL_EXIT_36_US; |
| |
| tw32(TG3_CPMU_EEE_CTRL, eeectl); |
| |
| tg3_phy_cl45_read(tp, 0x7, TG3_CL45_D7_EEERES_STAT, &val); |
| |
| if (val == TG3_CL45_D7_EEERES_STAT_LP_1000T || |
| val == TG3_CL45_D7_EEERES_STAT_LP_100TX) |
| tp->setlpicnt = 2; |
| } |
| |
| if (!tp->setlpicnt) { |
| val = tr32(TG3_CPMU_EEE_MODE); |
| tw32(TG3_CPMU_EEE_MODE, val & ~TG3_CPMU_EEEMD_LPI_ENABLE); |
| } |
| } |
| |
| static int tg3_wait_macro_done(struct tg3 *tp) |
| { |
| int limit = 100; |
| |
| while (limit--) { |
| u32 tmp32; |
| |
| if (!tg3_readphy(tp, MII_TG3_DSP_CONTROL, &tmp32)) { |
| if ((tmp32 & 0x1000) == 0) |
| break; |
| } |
| } |
| if (limit < 0) |
| return -EBUSY; |
| |
| return 0; |
| } |
| |
| static int tg3_phy_write_and_check_testpat(struct tg3 *tp, int *resetp) |
| { |
| static const u32 test_pat[4][6] = { |
| { 0x00005555, 0x00000005, 0x00002aaa, 0x0000000a, 0x00003456, 0x00000003 }, |
| { 0x00002aaa, 0x0000000a, 0x00003333, 0x00000003, 0x0000789a, 0x00000005 }, |
| { 0x00005a5a, 0x00000005, 0x00002a6a, 0x0000000a, 0x00001bcd, 0x00000003 }, |
| { 0x00002a5a, 0x0000000a, 0x000033c3, 0x00000003, 0x00002ef1, 0x00000005 } |
| }; |
| int chan; |
| |
| for (chan = 0; chan < 4; chan++) { |
| int i; |
| |
| tg3_writephy(tp, MII_TG3_DSP_ADDRESS, |
| (chan * 0x2000) | 0x0200); |
| tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0002); |
| |
| for (i = 0; i < 6; i++) |
| tg3_writephy(tp, MII_TG3_DSP_RW_PORT, |
| test_pat[chan][i]); |
| |
| tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0202); |
| if (tg3_wait_macro_done(tp)) { |
| *resetp = 1; |
| return -EBUSY; |
| } |
| |
| tg3_writephy(tp, MII_TG3_DSP_ADDRESS, |
| (chan * 0x2000) | 0x0200); |
| tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0082); |
| if (tg3_wait_macro_done(tp)) { |
| *resetp = 1; |
| return -EBUSY; |
| } |
| |
| tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0802); |
| if (tg3_wait_macro_done(tp)) { |
| *resetp = 1; |
| return -EBUSY; |
| } |
| |
| for (i = 0; i < 6; i += 2) { |
| u32 low, high; |
| |
| if (tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &low) || |
| tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &high) || |
| tg3_wait_macro_done(tp)) { |
| *resetp = 1; |
| return -EBUSY; |
| } |
| low &= 0x7fff; |
| high &= 0x000f; |
| if (low != test_pat[chan][i] || |
| high != test_pat[chan][i+1]) { |
| tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000b); |
| tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x4001); |
| tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x4005); |
| |
| return -EBUSY; |
| } |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int tg3_phy_reset_chanpat(struct tg3 *tp) |
| { |
| int chan; |
| |
| for (chan = 0; chan < 4; chan++) { |
| int i; |
| |
| tg3_writephy(tp, MII_TG3_DSP_ADDRESS, |
| (chan * 0x2000) | 0x0200); |
| tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0002); |
| for (i = 0; i < 6; i++) |
| tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x000); |
| tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0202); |
| if (tg3_wait_macro_done(tp)) |
| return -EBUSY; |
| } |
| |
| return 0; |
| } |
| |
| static int tg3_phy_reset_5703_4_5(struct tg3 *tp) |
| { |
| u32 reg32, phy9_orig; |
| int retries, do_phy_reset, err; |
| |
| retries = 10; |
| do_phy_reset = 1; |
| do { |
| if (do_phy_reset) { |
| err = tg3_bmcr_reset(tp); |
| if (err) |
| return err; |
| do_phy_reset = 0; |
| } |
| |
| /* Disable transmitter and interrupt. */ |
| if (tg3_readphy(tp, MII_TG3_EXT_CTRL, ®32)) |
| continue; |
| |
| reg32 |= 0x3000; |
| tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32); |
| |
| /* Set full-duplex, 1000 mbps. */ |
| tg3_writephy(tp, MII_BMCR, |
| BMCR_FULLDPLX | TG3_BMCR_SPEED1000); |
| |
| /* Set to master mode. */ |
| if (tg3_readphy(tp, MII_TG3_CTRL, &phy9_orig)) |
| continue; |
| |
| tg3_writephy(tp, MII_TG3_CTRL, |
| (MII_TG3_CTRL_AS_MASTER | |
| MII_TG3_CTRL_ENABLE_AS_MASTER)); |
| |
| /* Enable SM_DSP_CLOCK and 6dB. */ |
| tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00); |
| |
| /* Block the PHY control access. */ |
| tg3_phydsp_write(tp, 0x8005, 0x0800); |
| |
| err = tg3_phy_write_and_check_testpat(tp, &do_phy_reset); |
| if (!err) |
| break; |
| } while (--retries); |
| |
| err = tg3_phy_reset_chanpat(tp); |
| if (err) |
| return err; |
| |
| tg3_phydsp_write(tp, 0x8005, 0x0000); |
| |
| tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x8200); |
| tg3_writephy(tp, MII_TG3_DSP_CONTROL, 0x0000); |
| |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 || |
| GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { |
| /* Set Extended packet length bit for jumbo frames */ |
| tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4400); |
| } else { |
| tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400); |
| } |
| |
| tg3_writephy(tp, MII_TG3_CTRL, phy9_orig); |
| |
| if (!tg3_readphy(tp, MII_TG3_EXT_CTRL, ®32)) { |
| reg32 &= ~0x3000; |
| tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32); |
| } else if (!err) |
| err = -EBUSY; |
| |
| return err; |
| } |
| |
| /* This will reset the tigon3 PHY if there is no valid |
| * link unless the FORCE argument is non-zero. |
| */ |
| static int tg3_phy_reset(struct tg3 *tp) |
| { |
| u32 val, cpmuctrl; |
| int err; |
| |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { |
| val = tr32(GRC_MISC_CFG); |
| tw32_f(GRC_MISC_CFG, val & ~GRC_MISC_CFG_EPHY_IDDQ); |
| udelay(40); |
| } |
| err = tg3_readphy(tp, MII_BMSR, &val); |
| err |= tg3_readphy(tp, MII_BMSR, &val); |
| if (err != 0) |
| return -EBUSY; |
| |
| if (netif_running(tp->dev) && netif_carrier_ok(tp->dev)) { |
| netif_carrier_off(tp->dev); |
| tg3_link_report(tp); |
| } |
| |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 || |
| GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || |
| GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) { |
| err = tg3_phy_reset_5703_4_5(tp); |
| if (err) |
| return err; |
| goto out; |
| } |
| |
| cpmuctrl = 0; |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && |
| GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) { |
| cpmuctrl = tr32(TG3_CPMU_CTRL); |
| if (cpmuctrl & CPMU_CTRL_GPHY_10MB_RXONLY) |
| tw32(TG3_CPMU_CTRL, |
| cpmuctrl & ~CPMU_CTRL_GPHY_10MB_RXONLY); |
| } |
| |
| err = tg3_bmcr_reset(tp); |
| if (err) |
| return err; |
| |
| if (cpmuctrl & CPMU_CTRL_GPHY_10MB_RXONLY) { |
| val = MII_TG3_DSP_EXP8_AEDW | MII_TG3_DSP_EXP8_REJ2MHz; |
| tg3_phydsp_write(tp, MII_TG3_DSP_EXP8, val); |
| |
| tw32(TG3_CPMU_CTRL, cpmuctrl); |
| } |
| |
| if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX || |
| GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5761_AX) { |
| val = tr32(TG3_CPMU_LSPD_1000MB_CLK); |
| if ((val & CPMU_LSPD_1000MB_MACCLK_MASK) == |
| CPMU_LSPD_1000MB_MACCLK_12_5) { |
| val &= ~CPMU_LSPD_1000MB_MACCLK_MASK; |
| udelay(40); |
| tw32_f(TG3_CPMU_LSPD_1000MB_CLK, val); |
| } |
| } |
| |
| if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || |
| GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) && |
| (tp->phy_flags & TG3_PHYFLG_MII_SERDES)) |
| return 0; |
| |
| tg3_phy_apply_otp(tp); |
| |
| if (tp->phy_flags & TG3_PHYFLG_ENABLE_APD) |
| tg3_phy_toggle_apd(tp, true); |
| else |
| tg3_phy_toggle_apd(tp, false); |
| |
| out: |
| if (tp->phy_flags & TG3_PHYFLG_ADC_BUG) { |
| tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00); |
| tg3_phydsp_write(tp, 0x201f, 0x2aaa); |
| tg3_phydsp_write(tp, 0x000a, 0x0323); |
| tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400); |
| } |
| if (tp->phy_flags & TG3_PHYFLG_5704_A0_BUG) { |
| tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8d68); |
| tg3_writephy(tp, MII_TG3_MISC_SHDW, 0x8d68); |
| } |
| if (tp->phy_flags & TG3_PHYFLG_BER_BUG) { |
| tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00); |
| tg3_phydsp_write(tp, 0x000a, 0x310b); |
| tg3_phydsp_write(tp, 0x201f, 0x9506); |
| tg3_phydsp_write(tp, 0x401f, 0x14e2); |
| tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400); |
| } else if (tp->phy_flags & TG3_PHYFLG_JITTER_BUG) { |
| tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00); |
| tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x000a); |
| if (tp->phy_flags & TG3_PHYFLG_ADJUST_TRIM) { |
| tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x110b); |
| tg3_writephy(tp, MII_TG3_TEST1, |
| MII_TG3_TEST1_TRIM_EN | 0x4); |
| } else |
| tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x010b); |
| tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0400); |
| } |
| /* Set Extended packet length bit (bit 14) on all chips that */ |
| /* support jumbo frames */ |
| if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5401) { |
| /* Cannot do read-modify-write on 5401 */ |
| tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x4c20); |
| } else if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { |
| /* Set bit 14 with read-modify-write to preserve other bits */ |
| if (!tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0007) && |
| !tg3_readphy(tp, MII_TG3_AUX_CTRL, &val)) |
| tg3_writephy(tp, MII_TG3_AUX_CTRL, val | 0x4000); |
| } |
| |
| /* Set phy register 0x10 bit 0 to high fifo elasticity to support |
| * jumbo frames transmission. |
| */ |
| if (tp->tg3_flags & TG3_FLAG_JUMBO_CAPABLE) { |
| if (!tg3_readphy(tp, MII_TG3_EXT_CTRL, &val)) |
| tg3_writephy(tp, MII_TG3_EXT_CTRL, |
| val | MII_TG3_EXT_CTRL_FIFO_ELASTIC); |
| } |
| |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { |
| /* adjust output voltage */ |
| tg3_writephy(tp, MII_TG3_FET_PTEST, 0x12); |
| } |
| |
| tg3_phy_toggle_automdix(tp, 1); |
| tg3_phy_set_wirespeed(tp); |
| return 0; |
| } |
| |
| static void tg3_frob_aux_power(struct tg3 *tp) |
| { |
| struct tg3 *tp_peer = tp; |
| |
| /* The GPIOs do something completely different on 57765. */ |
| if ((tp->tg3_flags2 & TG3_FLG2_IS_NIC) == 0 || |
| GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || |
| GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) |
| return; |
| |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || |
| GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714 || |
| GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) { |
| struct net_device *dev_peer; |
| |
| dev_peer = pci_get_drvdata(tp->pdev_peer); |
| /* remove_one() may have been run on the peer. */ |
| if (!dev_peer) |
| tp_peer = tp; |
| else |
| tp_peer = netdev_priv(dev_peer); |
| } |
| |
| if ((tp->tg3_flags & TG3_FLAG_WOL_ENABLE) != 0 || |
| (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0 || |
| (tp_peer->tg3_flags & TG3_FLAG_WOL_ENABLE) != 0 || |
| (tp_peer->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0) { |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || |
| GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) { |
| tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | |
| (GRC_LCLCTRL_GPIO_OE0 | |
| GRC_LCLCTRL_GPIO_OE1 | |
| GRC_LCLCTRL_GPIO_OE2 | |
| GRC_LCLCTRL_GPIO_OUTPUT0 | |
| GRC_LCLCTRL_GPIO_OUTPUT1), |
| 100); |
| } else if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761 || |
| tp->pdev->device == TG3PCI_DEVICE_TIGON3_5761S) { |
| /* The 5761 non-e device swaps GPIO 0 and GPIO 2. */ |
| u32 grc_local_ctrl = GRC_LCLCTRL_GPIO_OE0 | |
| GRC_LCLCTRL_GPIO_OE1 | |
| GRC_LCLCTRL_GPIO_OE2 | |
| GRC_LCLCTRL_GPIO_OUTPUT0 | |
| GRC_LCLCTRL_GPIO_OUTPUT1 | |
| tp->grc_local_ctrl; |
| tw32_wait_f(GRC_LOCAL_CTRL, grc_local_ctrl, 100); |
| |
| grc_local_ctrl |= GRC_LCLCTRL_GPIO_OUTPUT2; |
| tw32_wait_f(GRC_LOCAL_CTRL, grc_local_ctrl, 100); |
| |
| grc_local_ctrl &= ~GRC_LCLCTRL_GPIO_OUTPUT0; |
| tw32_wait_f(GRC_LOCAL_CTRL, grc_local_ctrl, 100); |
| } else { |
| u32 no_gpio2; |
| u32 grc_local_ctrl = 0; |
| |
| if (tp_peer != tp && |
| (tp_peer->tg3_flags & TG3_FLAG_INIT_COMPLETE) != 0) |
| return; |
| |
| /* Workaround to prevent overdrawing Amps. */ |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == |
| ASIC_REV_5714) { |
| grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE3; |
| tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | |
| grc_local_ctrl, 100); |
| } |
| |
| /* On 5753 and variants, GPIO2 cannot be used. */ |
| no_gpio2 = tp->nic_sram_data_cfg & |
| NIC_SRAM_DATA_CFG_NO_GPIO2; |
| |
| grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE0 | |
| GRC_LCLCTRL_GPIO_OE1 | |
| GRC_LCLCTRL_GPIO_OE2 | |
| GRC_LCLCTRL_GPIO_OUTPUT1 | |
| GRC_LCLCTRL_GPIO_OUTPUT2; |
| if (no_gpio2) { |
| grc_local_ctrl &= ~(GRC_LCLCTRL_GPIO_OE2 | |
| GRC_LCLCTRL_GPIO_OUTPUT2); |
| } |
| tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | |
| grc_local_ctrl, 100); |
| |
| grc_local_ctrl |= GRC_LCLCTRL_GPIO_OUTPUT0; |
| |
| tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | |
| grc_local_ctrl, 100); |
| |
| if (!no_gpio2) { |
| grc_local_ctrl &= ~GRC_LCLCTRL_GPIO_OUTPUT2; |
| tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | |
| grc_local_ctrl, 100); |
| } |
| } |
| } else { |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 && |
| GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) { |
| if (tp_peer != tp && |
| (tp_peer->tg3_flags & TG3_FLAG_INIT_COMPLETE) != 0) |
| return; |
| |
| tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | |
| (GRC_LCLCTRL_GPIO_OE1 | |
| GRC_LCLCTRL_GPIO_OUTPUT1), 100); |
| |
| tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | |
| GRC_LCLCTRL_GPIO_OE1, 100); |
| |
| tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl | |
| (GRC_LCLCTRL_GPIO_OE1 | |
| GRC_LCLCTRL_GPIO_OUTPUT1), 100); |
| } |
| } |
| } |
| |
| static int tg3_5700_link_polarity(struct tg3 *tp, u32 speed) |
| { |
| if (tp->led_ctrl == LED_CTRL_MODE_PHY_2) |
| return 1; |
| else if ((tp->phy_id & TG3_PHY_ID_MASK) == TG3_PHY_ID_BCM5411) { |
| if (speed != SPEED_10) |
| return 1; |
| } else if (speed == SPEED_10) |
| return 1; |
| |
| return 0; |
| } |
| |
| static int tg3_setup_phy(struct tg3 *, int); |
| |
| #define RESET_KIND_SHUTDOWN 0 |
| #define RESET_KIND_INIT 1 |
| #define RESET_KIND_SUSPEND 2 |
| |
| static void tg3_write_sig_post_reset(struct tg3 *, int); |
| static int tg3_halt_cpu(struct tg3 *, u32); |
| |
| static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power) |
| { |
| u32 val; |
| |
| if (tp->phy_flags & TG3_PHYFLG_PHY_SERDES) { |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { |
| u32 sg_dig_ctrl = tr32(SG_DIG_CTRL); |
| u32 serdes_cfg = tr32(MAC_SERDES_CFG); |
| |
| sg_dig_ctrl |= |
| SG_DIG_USING_HW_AUTONEG | SG_DIG_SOFT_RESET; |
| tw32(SG_DIG_CTRL, sg_dig_ctrl); |
| tw32(MAC_SERDES_CFG, serdes_cfg | (1 << 15)); |
| } |
| return; |
| } |
| |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { |
| tg3_bmcr_reset(tp); |
| val = tr32(GRC_MISC_CFG); |
| tw32_f(GRC_MISC_CFG, val | GRC_MISC_CFG_EPHY_IDDQ); |
| udelay(40); |
| return; |
| } else if (tp->phy_flags & TG3_PHYFLG_IS_FET) { |
| u32 phytest; |
| if (!tg3_readphy(tp, MII_TG3_FET_TEST, &phytest)) { |
| u32 phy; |
| |
| tg3_writephy(tp, MII_ADVERTISE, 0); |
| tg3_writephy(tp, MII_BMCR, |
| BMCR_ANENABLE | BMCR_ANRESTART); |
| |
| tg3_writephy(tp, MII_TG3_FET_TEST, |
| phytest | MII_TG3_FET_SHADOW_EN); |
| if (!tg3_readphy(tp, MII_TG3_FET_SHDW_AUXMODE4, &phy)) { |
| phy |= MII_TG3_FET_SHDW_AUXMODE4_SBPD; |
| tg3_writephy(tp, |
| MII_TG3_FET_SHDW_AUXMODE4, |
| phy); |
| } |
| tg3_writephy(tp, MII_TG3_FET_TEST, phytest); |
| } |
| return; |
| } else if (do_low_power) { |
| tg3_writephy(tp, MII_TG3_EXT_CTRL, |
| MII_TG3_EXT_CTRL_FORCE_LED_OFF); |
| |
| tg3_writephy(tp, MII_TG3_AUX_CTRL, |
| MII_TG3_AUXCTL_SHDWSEL_PWRCTL | |
| MII_TG3_AUXCTL_PCTL_100TX_LPWR | |
| MII_TG3_AUXCTL_PCTL_SPR_ISOLATE | |
| MII_TG3_AUXCTL_PCTL_VREG_11V); |
| } |
| |
| /* The PHY should not be powered down on some chips because |
| * of bugs. |
| */ |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || |
| GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || |
| (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 && |
| (tp->phy_flags & TG3_PHYFLG_MII_SERDES))) |
| return; |
| |
| if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX || |
| GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5761_AX) { |
| val = tr32(TG3_CPMU_LSPD_1000MB_CLK); |
| val &= ~CPMU_LSPD_1000MB_MACCLK_MASK; |
| val |= CPMU_LSPD_1000MB_MACCLK_12_5; |
| tw32_f(TG3_CPMU_LSPD_1000MB_CLK, val); |
| } |
| |
| tg3_writephy(tp, MII_BMCR, BMCR_PDOWN); |
| } |
| |
| /* tp->lock is held. */ |
| static int tg3_nvram_lock(struct tg3 *tp) |
| { |
| if (tp->tg3_flags & TG3_FLAG_NVRAM) { |
| int i; |
| |
| if (tp->nvram_lock_cnt == 0) { |
| tw32(NVRAM_SWARB, SWARB_REQ_SET1); |
| for (i = 0; i < 8000; i++) { |
| if (tr32(NVRAM_SWARB) & SWARB_GNT1) |
| break; |
| udelay(20); |
| } |
| if (i == 8000) { |
| tw32(NVRAM_SWARB, SWARB_REQ_CLR1); |
| return -ENODEV; |
| } |
| } |
| tp->nvram_lock_cnt++; |
| } |
| return 0; |
| } |
| |
| /* tp->lock is held. */ |
| static void tg3_nvram_unlock(struct tg3 *tp) |
| { |
| if (tp->tg3_flags & TG3_FLAG_NVRAM) { |
| if (tp->nvram_lock_cnt > 0) |
| tp->nvram_lock_cnt--; |
| if (tp->nvram_lock_cnt == 0) |
| tw32_f(NVRAM_SWARB, SWARB_REQ_CLR1); |
| } |
| } |
| |
| /* tp->lock is held. */ |
| static void tg3_enable_nvram_access(struct tg3 *tp) |
| { |
| if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && |
| !(tp->tg3_flags3 & TG3_FLG3_PROTECTED_NVRAM)) { |
| u32 nvaccess = tr32(NVRAM_ACCESS); |
| |
| tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE); |
| } |
| } |
| |
| /* tp->lock is held. */ |
| static void tg3_disable_nvram_access(struct tg3 *tp) |
| { |
| if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && |
| !(tp->tg3_flags3 & TG3_FLG3_PROTECTED_NVRAM)) { |
| u32 nvaccess = tr32(NVRAM_ACCESS); |
| |
| tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE); |
| } |
| } |
| |
| static int tg3_nvram_read_using_eeprom(struct tg3 *tp, |
| u32 offset, u32 *val) |
| { |
| u32 tmp; |
| int i; |
| |
| if (offset > EEPROM_ADDR_ADDR_MASK || (offset % 4) != 0) |
| return -EINVAL; |
| |
| tmp = tr32(GRC_EEPROM_ADDR) & ~(EEPROM_ADDR_ADDR_MASK | |
| EEPROM_ADDR_DEVID_MASK | |
| EEPROM_ADDR_READ); |
| tw32(GRC_EEPROM_ADDR, |
| tmp | |
| (0 << EEPROM_ADDR_DEVID_SHIFT) | |
| ((offset << EEPROM_ADDR_ADDR_SHIFT) & |
| EEPROM_ADDR_ADDR_MASK) | |
| EEPROM_ADDR_READ | EEPROM_ADDR_START); |
| |
| for (i = 0; i < 1000; i++) { |
| tmp = tr32(GRC_EEPROM_ADDR); |
| |
| if (tmp & EEPROM_ADDR_COMPLETE) |
| break; |
| msleep(1); |
| } |
| if (!(tmp & EEPROM_ADDR_COMPLETE)) |
| return -EBUSY; |
| |
| tmp = tr32(GRC_EEPROM_DATA); |
| |
| /* |
| * The data will always be opposite the native endian |
| * format. Perform a blind byteswap to compensate. |
| */ |
| *val = swab32(tmp); |
| |
| return 0; |
| } |
| |
| #define NVRAM_CMD_TIMEOUT 10000 |
| |
| static int tg3_nvram_exec_cmd(struct tg3 *tp, u32 nvram_cmd) |
| { |
| int i; |
| |
| tw32(NVRAM_CMD, nvram_cmd); |
| for (i = 0; i < NVRAM_CMD_TIMEOUT; i++) { |
| udelay(10); |
| if (tr32(NVRAM_CMD) & NVRAM_CMD_DONE) { |
| udelay(10); |
| break; |
| } |
| } |
| |
| if (i == NVRAM_CMD_TIMEOUT) |
| return -EBUSY; |
| |
| return 0; |
| } |
| |
| static u32 tg3_nvram_phys_addr(struct tg3 *tp, u32 addr) |
| { |
| if ((tp->tg3_flags & TG3_FLAG_NVRAM) && |
| (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) && |
| (tp->tg3_flags2 & TG3_FLG2_FLASH) && |
| !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) && |
| (tp->nvram_jedecnum == JEDEC_ATMEL)) |
| |
| addr = ((addr / tp->nvram_pagesize) << |
| ATMEL_AT45DB0X1B_PAGE_POS) + |
| (addr % tp->nvram_pagesize); |
| |
| return addr; |
| } |
| |
| static u32 tg3_nvram_logical_addr(struct tg3 *tp, u32 addr) |
| { |
| if ((tp->tg3_flags & TG3_FLAG_NVRAM) && |
| (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) && |
| (tp->tg3_flags2 & TG3_FLG2_FLASH) && |
| !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) && |
| (tp->nvram_jedecnum == JEDEC_ATMEL)) |
| |
| addr = ((addr >> ATMEL_AT45DB0X1B_PAGE_POS) * |
| tp->nvram_pagesize) + |
| (addr & ((1 << ATMEL_AT45DB0X1B_PAGE_POS) - 1)); |
| |
| return addr; |
| } |
| |
| /* NOTE: Data read in from NVRAM is byteswapped according to |
| * the byteswapping settings for all other register accesses. |
| * tg3 devices are BE devices, so on a BE machine, the data |
| * returned will be exactly as it is seen in NVRAM. On a LE |
| * machine, the 32-bit value will be byteswapped. |
| */ |
| static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val) |
| { |
| int ret; |
| |
| if (!(tp->tg3_flags & TG3_FLAG_NVRAM)) |
| return tg3_nvram_read_using_eeprom(tp, offset, val); |
| |
| offset = tg3_nvram_phys_addr(tp, offset); |
| |
| if (offset > NVRAM_ADDR_MSK) |
| return -EINVAL; |
| |
| ret = tg3_nvram_lock(tp); |
| if (ret) |
| return ret; |
| |
| tg3_enable_nvram_access(tp); |
| |
| tw32(NVRAM_ADDR, offset); |
| ret = tg3_nvram_exec_cmd(tp, NVRAM_CMD_RD | NVRAM_CMD_GO | |
| NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_DONE); |
| |
| if (ret == 0) |
| *val = tr32(NVRAM_RDDATA); |
| |
| tg3_disable_nvram_access(tp); |
| |
| tg3_nvram_unlock(tp); |
| |
| return ret; |
| } |
| |
| /* Ensures NVRAM data is in bytestream format. */ |
| static int tg3_nvram_read_be32(struct tg3 *tp, u32 offset, __be32 *val) |
| { |
| u32 v; |
| int res = tg3_nvram_read(tp, offset, &v); |
| if (!res) |
| *val = cpu_to_be32(v); |
| return res; |
| } |
| |
| /* tp->lock is held. */ |
| static void __tg3_set_mac_addr(struct tg3 *tp, int skip_mac_1) |
| { |
| u32 addr_high, addr_low; |
| int i; |
| |
| addr_high = ((tp->dev->dev_addr[0] << 8) | |
| tp->dev->dev_addr[1]); |
| addr_low = ((tp->dev->dev_addr[2] << 24) | |
| (tp->dev->dev_addr[3] << 16) | |
| (tp->dev->dev_addr[4] << 8) | |
| (tp->dev->dev_addr[5] << 0)); |
| for (i = 0; i < 4; i++) { |
| if (i == 1 && skip_mac_1) |
| continue; |
| tw32(MAC_ADDR_0_HIGH + (i * 8), addr_high); |
| tw32(MAC_ADDR_0_LOW + (i * 8), addr_low); |
| } |
| |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 || |
| GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { |
| for (i = 0; i < 12; i++) { |
| tw32(MAC_EXTADDR_0_HIGH + (i * 8), addr_high); |
| tw32(MAC_EXTADDR_0_LOW + (i * 8), addr_low); |
| } |
| } |
| |
| addr_high = (tp->dev->dev_addr[0] + |
| tp->dev->dev_addr[1] + |
| tp->dev->dev_addr[2] + |
| tp->dev->dev_addr[3] + |
| tp->dev->dev_addr[4] + |
| tp->dev->dev_addr[5]) & |
| TX_BACKOFF_SEED_MASK; |
| tw32(MAC_TX_BACKOFF_SEED, addr_high); |
| } |
| |
| static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) |
| { |
| u32 misc_host_ctrl; |
| bool device_should_wake, do_low_power; |
| |
| /* Make sure register accesses (indirect or otherwise) |
| * will function correctly. |
| */ |
| pci_write_config_dword(tp->pdev, |
| TG3PCI_MISC_HOST_CTRL, |
| tp->misc_host_ctrl); |
| |
| switch (state) { |
| case PCI_D0: |
| pci_enable_wake(tp->pdev, state, false); |
| pci_set_power_state(tp->pdev, PCI_D0); |
| |
| /* Switch out of Vaux if it is a NIC */ |
| if (tp->tg3_flags2 & TG3_FLG2_IS_NIC) |
| tw32_wait_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl, 100); |
| |
| return 0; |
| |
| case PCI_D1: |
| case PCI_D2: |
| case PCI_D3hot: |
| break; |
| |
| default: |
| netdev_err(tp->dev, "Invalid power state (D%d) requested\n", |
| state); |
| return -EINVAL; |
| } |
| |
| /* Restore the CLKREQ setting. */ |
| if (tp->tg3_flags3 & TG3_FLG3_CLKREQ_BUG) { |
| u16 lnkctl; |
| |
| pci_read_config_word(tp->pdev, |
| tp->pcie_cap + PCI_EXP_LNKCTL, |
| &lnkctl); |
| lnkctl |= PCI_EXP_LNKCTL_CLKREQ_EN; |
| pci_write_config_word(tp->pdev, |
| tp->pcie_cap + PCI_EXP_LNKCTL, |
| lnkctl); |
| } |
| |
| misc_host_ctrl = tr32(TG3PCI_MISC_HOST_CTRL); |
| tw32(TG3PCI_MISC_HOST_CTRL, |
| misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT); |
| |
| device_should_wake = pci_pme_capable(tp->pdev, state) && |
| device_may_wakeup(&tp->pdev->dev) && |
| (tp->tg3_flags & TG3_FLAG_WOL_ENABLE); |
| |
| if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { |
| do_low_power = false; |
| if ((tp->phy_flags & TG3_PHYFLG_IS_CONNECTED) && |
| !(tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) { |
| struct phy_device *phydev; |
| u32 phyid, advertising; |
| |
| phydev = tp->mdio_bus->phy_map[TG3_PHY_MII_ADDR]; |
| |
| tp->phy_flags |= TG3_PHYFLG_IS_LOW_POWER; |
| |
| tp->link_config.orig_speed = phydev->speed; |
| tp->link_config.orig_duplex = phydev->duplex; |
| tp->link_config.orig_autoneg = phydev->autoneg; |
| tp->link_config.orig_advertising = phydev->advertising; |
| |
| advertising = ADVERTISED_TP | |
| ADVERTISED_Pause | |
| ADVERTISED_Autoneg | |
| ADVERTISED_10baseT_Half; |
| |
| if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) || |
| device_should_wake) { |
| if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) |
| advertising |= |
| ADVERTISED_100baseT_Half | |
| ADVERTISED_100baseT_Full | |
| ADVERTISED_10baseT_Full; |
| else |
| advertising |= ADVERTISED_10baseT_Full; |
| } |
| |
| phydev->advertising = advertising; |
| |
| phy_start_aneg(phydev); |
| |
| phyid = phydev->drv->phy_id & phydev->drv->phy_id_mask; |
| if (phyid != PHY_ID_BCMAC131) { |
| phyid &= PHY_BCM_OUI_MASK; |
| if (phyid == PHY_BCM_OUI_1 || |
| phyid == PHY_BCM_OUI_2 || |
| phyid == PHY_BCM_OUI_3) |
| do_low_power = true; |
| } |
| } |
| } else { |
| do_low_power = true; |
| |
| if (!(tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER)) { |
| tp->phy_flags |= TG3_PHYFLG_IS_LOW_POWER; |
| tp->link_config.orig_speed = tp->link_config.speed; |
| tp->link_config.orig_duplex = tp->link_config.duplex; |
| tp->link_config.orig_autoneg = tp->link_config.autoneg; |
| } |
| |
| if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES)) { |
| tp->link_config.speed = SPEED_10; |
| tp->link_config.duplex = DUPLEX_HALF; |
| tp->link_config.autoneg = AUTONEG_ENABLE; |
| tg3_setup_phy(tp, 0); |
| } |
| } |
| |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { |
| u32 val; |
| |
| val = tr32(GRC_VCPU_EXT_CTRL); |
| tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_DISABLE_WOL); |
| } else if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) { |
| int i; |
| u32 val; |
| |
| for (i = 0; i < 200; i++) { |
| tg3_read_mem(tp, NIC_SRAM_FW_ASF_STATUS_MBOX, &val); |
| if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1) |
| break; |
| msleep(1); |
| } |
| } |
| if (tp->tg3_flags & TG3_FLAG_WOL_CAP) |
| tg3_write_mem(tp, NIC_SRAM_WOL_MBOX, WOL_SIGNATURE | |
| WOL_DRV_STATE_SHUTDOWN | |
| WOL_DRV_WOL | |
| WOL_SET_MAGIC_PKT); |
| |
| if (device_should_wake) { |
| u32 mac_mode; |
| |
| if (!(tp->phy_flags & TG3_PHYFLG_PHY_SERDES)) { |
| if (do_low_power) { |
| tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a); |
| udelay(40); |
| } |
| |
| if (tp->phy_flags & TG3_PHYFLG_MII_SERDES) |
| mac_mode = MAC_MODE_PORT_MODE_GMII; |
| else |
| mac_mode = MAC_MODE_PORT_MODE_MII; |
| |
| mac_mode |= tp->mac_mode & MAC_MODE_LINK_POLARITY; |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == |
| ASIC_REV_5700) { |
| u32 speed = (tp->tg3_flags & |
| TG3_FLAG_WOL_SPEED_100MB) ? |
| SPEED_100 : SPEED_10; |
| if (tg3_5700_link_polarity(tp, speed)) |
| mac_mode |= MAC_MODE_LINK_POLARITY; |
| else |
| mac_mode &= ~MAC_MODE_LINK_POLARITY; |
| } |
| } else { |
| mac_mode = MAC_MODE_PORT_MODE_TBI; |
| } |
| |
| if (!(tp->tg3_flags2 & TG3_FLG2_5750_PLUS)) |
| tw32(MAC_LED_CTRL, tp->led_ctrl); |
| |
| mac_mode |= MAC_MODE_MAGIC_PKT_ENABLE; |
| if (((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && |
| !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) && |
| ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) || |
| (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))) |
| mac_mode |= MAC_MODE_KEEP_FRAME_IN_WOL; |
| |
| if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) { |
| mac_mode |= tp->mac_mode & |
| (MAC_MODE_APE_TX_EN | MAC_MODE_APE_RX_EN); |
| if (mac_mode & MAC_MODE_APE_TX_EN) |
| mac_mode |= MAC_MODE_TDE_ENABLE; |
| } |
| |
| tw32_f(MAC_MODE, mac_mode); |
| udelay(100); |
| |
| tw32_f(MAC_RX_MODE, RX_MODE_ENABLE); |
| udelay(10); |
| } |
| |
| if (!(tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) && |
| (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || |
| GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) { |
| u32 base_val; |
| |
| base_val = tp->pci_clock_ctrl; |
| base_val |= (CLOCK_CTRL_RXCLK_DISABLE | |
| CLOCK_CTRL_TXCLK_DISABLE); |
| |
| tw32_wait_f(TG3PCI_CLOCK_CTRL, base_val | CLOCK_CTRL_ALTCLK | |
| CLOCK_CTRL_PWRDOWN_PLL133, 40); |
| } else if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) || |
| (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) || |
| (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)) { |
| /* do nothing */ |
| } else if (!((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && |
| (tp->tg3_flags & TG3_FLAG_ENABLE_ASF))) { |
| u32 newbits1, newbits2; |
| |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || |
| GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) { |
| newbits1 = (CLOCK_CTRL_RXCLK_DISABLE | |
| CLOCK_CTRL_TXCLK_DISABLE | |
| CLOCK_CTRL_ALTCLK); |
| newbits2 = newbits1 | CLOCK_CTRL_44MHZ_CORE; |
| } else if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { |
| newbits1 = CLOCK_CTRL_625_CORE; |
| newbits2 = newbits1 | CLOCK_CTRL_ALTCLK; |
| } else { |
| newbits1 = CLOCK_CTRL_ALTCLK; |
| newbits2 = newbits1 | CLOCK_CTRL_44MHZ_CORE; |
| } |
| |
| tw32_wait_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits1, |
| 40); |
| |
| tw32_wait_f(TG3PCI_CLOCK_CTRL, tp->pci_clock_ctrl | newbits2, |
| 40); |
| |
| if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) { |
| u32 newbits3; |
| |
| if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || |
| GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) { |
| newbits3 = (CLOCK_CTRL_RXCLK_DISABLE | |
| CLOCK_CTRL_TXCLK_DISABLE | |
| CLOCK_CTRL_44MHZ_CORE); |
| } else { |
| newbits3 = CLOCK_CTRL_44MHZ_CORE; |
| } |
| |
| tw32_wait_f(TG3PCI_CLOCK_CTRL, |
| tp->pci_clock_ctrl | newbits3, 40); |
| } |
| } |
| |
| if (!(device_should_wake) && |
| !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) |
| tg3_power_down_phy(tp, do_low_power); |
| |
| tg3_frob_aux_power(tp); |
| |
| /* Workaround for unstable PLL clock */ |
| if ((GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX) || |
| (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_BX)) { |
| u32 val = tr32(0x7d00); |
| |
| val &= ~((1 << 16) | (1 << 4) | (1 << 2) | (1 << 1) | 1); |
| tw32(0x7d00, val); |
| if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) { |
| int err; |
| |
| err = tg3_nvram_lock(tp); |
| tg3_halt_cpu(tp, RX_CPU_BASE); |
| if (!err) |
| tg3_nvram_unlock(tp); |
| } |
| } |
| |
| tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN); |
| |
| if (device_should_wake) |
| pci_enable_wake(tp->pdev, state, true); |
| |
| /* Finally, set the new power state. */ |
| pci_set_power_state(tp->pdev, state); |
| |
| return 0; |
| } |
| |
| static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8 *duplex) |
| { |
| switch (val & MII_TG3_AUX_STAT_SPDMASK) { |
| case MII_TG3_AUX_STAT_10HALF: |
| *speed = SPEED_10; |
| *duplex = DUPLEX_HALF; |
| break; |
| |
| case MII_TG3_AUX_STAT_10FULL: |
| *speed = SPEED_10; |
| *duplex = DUPLEX_FULL; |
| break; |
| |
| case MII_TG3_AUX_STAT_100HALF: |
| *speed = SPEED_100; |
| *duplex = DUPLEX_HALF; |
| break; |
| |
| case MII_TG3_AUX_STAT_100FULL: |
| *speed = SPEED_100; |
| *duplex = DUPLEX_FULL; |
| break; |
| |
| case MII_TG3_AUX_STAT_1000HALF: |
| *speed = SPEED_1000; |
| *duplex = DUPLEX_HALF; |
| break; |
| |
| case MII_TG3_AUX_STAT_1000FULL: |
| *speed = SPEED_1000; |
| *duplex = DUPLEX_FULL; |
| break; |
| |
| default: |
| if (tp->phy_flags & TG3_PHYFLG_IS_FET) { |
| *speed = (val & MII_TG3_AUX_STAT_100) ? SPEED_100 : |
| SPEED_10; |
| *duplex = (val & MII_TG3_AUX_STAT_FULL) ? DUPLEX_FULL : |
| DUPLEX_HALF; |
| break; |
| } |
| *speed = SPEED_INVALID; |
| *duplex = DUPLEX_INVALID; |
| break; |
| } |
| } |
| |
| static void tg3_phy_copper_begin(struct tg3 *tp) |
| { |
| u32 new_adv; |
| int i; |
| |
| if (tp->phy_flags & TG3_PHYFLG_IS_LOW_POWER) { |
| /* Entering low power mode. Disable gigabit and |
| * 100baseT advertisements. |
| */ |
| tg3_writephy(tp, MII_TG3_CTRL, 0); |
| |
| new_adv = (ADVERTISE_10HALF | ADVERTISE_10FULL | |
| ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); |
| if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) |
| new_adv |= (ADVERTISE_100HALF | ADVERTISE_100FULL); |
| |
| tg3_writephy(tp, MII_ADVERTISE, new_adv); |
| } else if (tp->link_config.speed == SPEED_INVALID) { |
| if (tp->phy_flags & TG3_PHYFLG_10_100_ONLY) |
| tp->link_config.advertising &= |
| ~(ADVERTISED_1000baseT_Half | |
| ADVERTISED_1000baseT_Full); |
| |
| new_adv = ADVERTISE_CSMA; |
| if (tp->link_config.advertising & ADVERTISED_10baseT_Half) |
| new_adv |= ADVERTISE_10HALF; |
| if (tp->link_config.advertising & ADVERTISED_10baseT_Full) |
| new_adv |= ADVERTISE_10FULL; |
| if (tp->link_config.advertising & ADVERTISED_100baseT_Half) |
| new_adv |= ADVERTISE_100HALF; |
| if (tp->link_config.advertising & ADVERTISED_100baseT_Full) |
| new_adv |= ADVERTISE_100FULL; |
| |
| new_adv |= tg3_advert_flowctrl_1000T(tp->link_config.flowctrl); |
| |
| tg3_writephy(tp, MII_ADVERTISE, new_adv); |
| |
| if (tp->link_config.advertising & |
| (ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full)) { |
| new_adv = 0; |
| if (tp->link_config.advertising & ADVERTISED_1000baseT_Half) |
| new_adv |= MII_TG3_CTRL_ADV_1000_HALF; |
| if (tp->link_config.advertising & ADVERTISED_1000baseT_Full) |
| new_adv |= MII_TG3_CTRL_ADV_1000_FULL; |
| if (!(tp->phy_flags & TG3_PHYFLG_10_100_ONLY) && |
| (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || |
| tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)) |
| new_adv |= (MII_TG3_CTRL_AS_MASTER | |
| MII_TG3_CTRL_ENABLE_AS_MASTER); |
| tg3_writephy(tp, MII_TG3_CTRL, new_adv); |
| } else { |
| tg3_writephy(tp, MII_TG3_CTRL, 0); |
| } |
| } else { |
| new_adv = tg3_advert_flowctrl_1000T(tp->link_config.flowctrl); |
| new_adv |= ADVERTISE_CSMA; |
| |
| /* Asking for a specific link mode. */ |
| if (tp->link_config.speed == SPEED_1000) { |
| tg3_writephy(tp, MII_ADVERTISE, new_adv); |
| |
| if (tp->link_config.duplex == DUPLEX_FULL) |
| new_adv = MII_TG3_CTRL_ADV_1000_FULL; |
| else |
| new_adv = MII_TG3_CTRL_ADV_1000_HALF; |
| if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || |
| tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) |
| new_adv |= (MII_TG3_CTRL_AS_MASTER | |
| MII_TG3_CTRL_ENABLE_AS_MASTER); |
| } else { |
| if (tp->link_config.speed == SPEED_100) { |
| if (tp->link_config.duplex == DUPLEX_FULL) |
| new_adv |= ADVERTISE_100FULL; |
| else |
| new_adv |= ADVERTISE_100HALF; |
| } else { |
| if (tp->link_config.duplex == DUPLEX_FULL) |
| new_adv |= ADVERTISE_10FULL; |
| else |
| new_adv |= ADVERTISE_10HALF; |
| } |
| tg3_writephy(tp, MII_ADVERTISE, new_adv); |
| |
| new_adv = 0; |
| } |
| |
| tg3_writephy(tp, MII_TG3_CTRL, new_adv); |
| } |
| |
| if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) { |
| u32 val = 0; |
| |
| tw32(TG3_CPMU_EEE_MODE, |
| tr32(TG3_CPMU_EEE_MODE) & ~TG3_CPMU_EEEMD_LPI_ENABLE); |
| |
| /* Enable SM_DSP clock and tx 6dB coding. */ |
| val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL | |
| MII_TG3_AUXCTL_ACTL_SMDSP_ENA | |
| MII_TG3_AUXCTL_ACTL_TX_6DB; |
| tg3_writephy(tp, MII_TG3_AUX_CTRL, val); |
| |
| if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 || |
| GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) && |
| !tg3_phydsp_read(tp, MII_TG3_DSP_CH34TP2, &val)) |
| tg3_phydsp_write(tp, MII_TG3_DSP_CH34TP2, |
| val | MII_TG3_DSP_CH34TP2_HIBW01); |
| |
| if (tp->link_config.autoneg == AUTONEG_ENABLE) { |
| /* Advertise 100-BaseTX EEE ability */ |
| if (tp->link_config.advertising & |
| (ADVERTISED_100baseT_Half | |
| ADVERTISED_100baseT_Full)) |
| val |= TG3_CL45_D7_EEEADV_CAP_100TX; |
| /* Advertise 1000-BaseT EEE ability */ |
| if (tp->link_config.advertising & |
| (ADVERTISED_1000baseT_Half | |
| ADVERTISED_1000baseT_Full)) |
| val |= TG3_CL45_D7_EEEADV_CAP_1000T; |
| } |
| tg3_phy_cl45_write(tp, 0x7, TG3_CL45_D7_EEEADV_CAP, val); |
| |
| /* Turn off SM_DSP clock. */ |
| val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL | |
| |