#include <linux/config.h>
#include <linux/module.h>
-
+#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/compiler.h>
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.10"
-#define DRV_MODULE_RELDATE "September 14, 2004"
+#define DRV_MODULE_VERSION "3.23"
+#define DRV_MODULE_RELDATE "February 15, 2005"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
MODULE_AUTHOR("David S. Miller (davem@redhat.com) and Jeff Garzik (jgarzik@pobox.com)");
MODULE_DESCRIPTION("Broadcom Tigon3 ethernet driver");
MODULE_LICENSE("GPL");
-MODULE_PARM(tg3_debug, "i");
-MODULE_PARM_DESC(tg3_debug, "Tigon3 bitmapped debugging message enable value");
+MODULE_VERSION(DRV_MODULE_VERSION);
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 struct pci_device_id tg3_pci_tbl[] = {
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5700,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+ { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+ { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753M,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+ { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753F,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+ { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5781,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX,
MODULE_DEVICE_TABLE(pci, tg3_pci_tbl);
-struct {
- char string[ETH_GSTRING_LEN];
+static struct {
+ const char string[ETH_GSTRING_LEN];
} ethtool_stats_keys[TG3_NUM_STATS] = {
{ "rx_octets" },
{ "rx_fragments" },
tg3_cond_int(tp);
}
+/* tg3_restart_ints
+ * similar to tg3_enable_ints, but it can return without flushing the
+ * PIO write which reenables interrupts
+ */
+static void tg3_restart_ints(struct tg3 *tp)
+{
+ tw32(TG3PCI_MISC_HOST_CTRL,
+ (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
+ tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000000);
+ mmiowb();
+
+ tg3_cond_int(tp);
+}
+
static inline void tg3_netif_stop(struct tg3 *tp)
{
netif_poll_disable(tp->dev);
static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
{
u32 frame_val;
- int loops, ret;
+ unsigned int loops;
+ int ret;
if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
tw32_f(MAC_MI_MODE,
udelay(80);
}
- *val = 0xffffffff;
+ *val = 0x0;
frame_val = ((PHY_ADDR << MI_COM_PHY_ADDR_SHIFT) &
MI_COM_PHY_ADDR_MASK);
tw32_f(MAC_MI_COM, frame_val);
loops = PHY_BUSY_LOOPS;
- while (loops-- > 0) {
+ while (loops != 0) {
udelay(10);
frame_val = tr32(MAC_MI_COM);
frame_val = tr32(MAC_MI_COM);
break;
}
+ loops -= 1;
}
ret = -EBUSY;
- if (loops > 0) {
+ if (loops != 0) {
*val = frame_val & MI_COM_DATA_MASK;
ret = 0;
}
static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
{
u32 frame_val;
- int loops, ret;
+ unsigned int loops;
+ int ret;
if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
tw32_f(MAC_MI_MODE,
tw32_f(MAC_MI_COM, frame_val);
loops = PHY_BUSY_LOOPS;
- while (loops-- > 0) {
+ while (loops != 0) {
udelay(10);
frame_val = tr32(MAC_MI_COM);
if ((frame_val & MI_COM_BUSY) == 0) {
frame_val = tr32(MAC_MI_COM);
break;
}
+ loops -= 1;
}
ret = -EBUSY;
- if (loops > 0)
+ if (loops != 0)
ret = 0;
if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
if (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED)
return;
- 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)));
+ 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 int tg3_bmcr_reset(struct tg3 *tp)
while (limit--) {
u32 tmp32;
- tg3_readphy(tp, 0x16, &tmp32);
- if ((tmp32 & 0x1000) == 0)
- break;
+ if (!tg3_readphy(tp, 0x16, &tmp32)) {
+ if ((tmp32 & 0x1000) == 0)
+ break;
+ }
}
if (limit <= 0)
return -EBUSY;
for (i = 0; i < 6; i += 2) {
u32 low, high;
- tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &low);
- tg3_readphy(tp, MII_TG3_DSP_RW_PORT, &high);
- if (tg3_wait_macro_done(tp)) {
+ 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;
}
}
/* Disable transmitter and interrupt. */
- tg3_readphy(tp, MII_TG3_EXT_CTRL, ®32);
+ if (tg3_readphy(tp, MII_TG3_EXT_CTRL, ®32))
+ continue;
+
reg32 |= 0x3000;
tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
BMCR_FULLDPLX | TG3_BMCR_SPEED1000);
/* Set to master mode. */
- tg3_readphy(tp, MII_TG3_CTRL, &phy9_orig);
+ 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));
tg3_writephy(tp, MII_TG3_CTRL, phy9_orig);
- tg3_readphy(tp, MII_TG3_EXT_CTRL, ®32);
- reg32 &= ~0x3000;
- tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32);
+ 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;
}
u32 phy_reg;
/* Set bit 14 with read-modify-write to preserve other bits */
- tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0007);
- tg3_readphy(tp, MII_TG3_AUX_CTRL, &phy_reg);
- tg3_writephy(tp, MII_TG3_AUX_CTRL, phy_reg | 0x4000);
+ if (!tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0007) &&
+ !tg3_readphy(tp, MII_TG3_AUX_CTRL, &phy_reg))
+ tg3_writephy(tp, MII_TG3_AUX_CTRL, phy_reg | 0x4000);
}
tg3_phy_set_wirespeed(tp);
return 0;
GRC_LCLCTRL_GPIO_OUTPUT1));
udelay(100);
} else {
+ u32 no_gpio2;
+ u32 grc_local_ctrl;
+
if (tp_peer != tp &&
(tp_peer->tg3_flags & TG3_FLAG_INIT_COMPLETE) != 0)
return;
+ /* 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_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
- (GRC_LCLCTRL_GPIO_OE0 |
- GRC_LCLCTRL_GPIO_OE1 |
- GRC_LCLCTRL_GPIO_OE2 |
- GRC_LCLCTRL_GPIO_OUTPUT1 |
- GRC_LCLCTRL_GPIO_OUTPUT2));
+ grc_local_ctrl);
udelay(100);
- tw32_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 |
- GRC_LCLCTRL_GPIO_OUTPUT2));
- udelay(100);
+ grc_local_ctrl |= GRC_LCLCTRL_GPIO_OUTPUT0;
tw32_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));
+ grc_local_ctrl);
udelay(100);
+
+ if (!no_gpio2) {
+ grc_local_ctrl &= ~GRC_LCLCTRL_GPIO_OUTPUT2;
+ tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
+ grc_local_ctrl);
+ udelay(100);
+ }
}
} else {
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
};
}
-static int tg3_phy_copper_begin(struct tg3 *tp)
+static void tg3_phy_copper_begin(struct tg3 *tp)
{
u32 new_adv;
int i;
if (tp->link_config.duplex == DUPLEX_FULL)
bmcr |= BMCR_FULLDPLX;
- tg3_readphy(tp, MII_BMCR, &orig_bmcr);
- if (bmcr != orig_bmcr) {
+ if (!tg3_readphy(tp, MII_BMCR, &orig_bmcr) &&
+ (bmcr != orig_bmcr)) {
tg3_writephy(tp, MII_BMCR, BMCR_LOOPBACK);
for (i = 0; i < 1500; i++) {
u32 tmp;
udelay(10);
- tg3_readphy(tp, MII_BMSR, &tmp);
- tg3_readphy(tp, MII_BMSR, &tmp);
+ if (tg3_readphy(tp, MII_BMSR, &tmp) ||
+ tg3_readphy(tp, MII_BMSR, &tmp))
+ continue;
if (!(tmp & BMSR_LSTATUS)) {
udelay(40);
break;
tg3_writephy(tp, MII_BMCR,
BMCR_ANENABLE | BMCR_ANRESTART);
}
-
- return 0;
}
static int tg3_init_5401phy_dsp(struct tg3 *tp)
{
u32 adv_reg, all_mask;
- tg3_readphy(tp, MII_ADVERTISE, &adv_reg);
+ if (tg3_readphy(tp, MII_ADVERTISE, &adv_reg))
+ return 0;
+
all_mask = (ADVERTISE_10HALF | ADVERTISE_10FULL |
ADVERTISE_100HALF | ADVERTISE_100FULL);
if ((adv_reg & all_mask) != all_mask)
if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY)) {
u32 tg3_ctrl;
- tg3_readphy(tp, MII_TG3_CTRL, &tg3_ctrl);
+ if (tg3_readphy(tp, MII_TG3_CTRL, &tg3_ctrl))
+ return 0;
+
all_mask = (MII_TG3_CTRL_ADV_1000_HALF |
MII_TG3_CTRL_ADV_1000_FULL);
if ((tg3_ctrl & all_mask) != all_mask)
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
netif_carrier_ok(tp->dev)) {
tg3_readphy(tp, MII_BMSR, &bmsr);
- tg3_readphy(tp, MII_BMSR, &bmsr);
- if (!(bmsr & BMSR_LSTATUS))
+ if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
+ !(bmsr & BMSR_LSTATUS))
force_reset = 1;
}
if (force_reset)
if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
tg3_readphy(tp, MII_BMSR, &bmsr);
- tg3_readphy(tp, MII_BMSR, &bmsr);
-
- if (!(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE))
+ if (tg3_readphy(tp, MII_BMSR, &bmsr) ||
+ !(tp->tg3_flags & TG3_FLAG_INIT_COMPLETE))
bmsr = 0;
if (!(bmsr & BMSR_LSTATUS)) {
tg3_readphy(tp, MII_BMSR, &bmsr);
for (i = 0; i < 1000; i++) {
udelay(10);
- tg3_readphy(tp, MII_BMSR, &bmsr);
- if (bmsr & BMSR_LSTATUS) {
+ if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
+ (bmsr & BMSR_LSTATUS)) {
udelay(40);
break;
}
bmsr = 0;
for (i = 0; i < 100; i++) {
tg3_readphy(tp, MII_BMSR, &bmsr);
- tg3_readphy(tp, MII_BMSR, &bmsr);
- if (bmsr & BMSR_LSTATUS)
+ if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
+ (bmsr & BMSR_LSTATUS))
break;
udelay(40);
}
tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat);
for (i = 0; i < 2000; i++) {
udelay(10);
- tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat);
- if (aux_stat)
+ if (!tg3_readphy(tp, MII_TG3_AUX_STAT, &aux_stat) &&
+ aux_stat)
break;
}
bmcr = 0;
for (i = 0; i < 200; i++) {
tg3_readphy(tp, MII_BMCR, &bmcr);
- tg3_readphy(tp, MII_BMCR, &bmcr);
+ if (tg3_readphy(tp, MII_BMCR, &bmcr))
+ continue;
if (bmcr && bmcr != 0x7fff)
break;
udelay(10);
(tp->link_config.autoneg == AUTONEG_ENABLE)) {
u32 local_adv, remote_adv;
- tg3_readphy(tp, MII_ADVERTISE, &local_adv);
+ if (tg3_readphy(tp, MII_ADVERTISE, &local_adv))
+ local_adv = 0;
local_adv &= (ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
- tg3_readphy(tp, MII_LPA, &remote_adv);
+ if (tg3_readphy(tp, MII_LPA, &remote_adv))
+ remote_adv = 0;
+
remote_adv &= (LPA_PAUSE_CAP | LPA_PAUSE_ASYM);
/* If we are not advertising full pause capability,
tg3_phy_copper_begin(tp);
tg3_readphy(tp, MII_BMSR, &tmp);
- tg3_readphy(tp, MII_BMSR, &tmp);
- if (tmp & BMSR_LSTATUS)
+ if (!tg3_readphy(tp, MII_BMSR, &tmp) &&
+ (tmp & BMSR_LSTATUS))
current_link_up = 1;
}
if (tr32(TG3PCI_DUAL_MAC_CTRL) & DUAL_MAC_CTRL_ID)
port_a = 0;
- serdes_cfg = tr32(MAC_SERDES_CFG) &
- ((1 << 23) | (1 << 22) | (1 << 21) | (1 << 20));
+ /* preserve bits 0-11,13,14 for signal pre-emphasis */
+ /* preserve bits 20-23 for voltage regulator */
+ serdes_cfg = tr32(MAC_SERDES_CFG) & 0x00f06fff;
}
sg_dig_ctrl = tr32(SG_DIG_CTRL);
u32 val = serdes_cfg;
if (port_a)
- val |= 0xc010880;
+ val |= 0xc010000;
else
- val |= 0x4010880;
+ val |= 0x4010000;
tw32_f(MAC_SERDES_CFG, val);
}
tw32_f(SG_DIG_CTRL, 0x01388400);
if (sg_dig_ctrl != expected_sg_dig_ctrl) {
if (workaround)
- tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011880);
+ tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011000);
tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | (1 << 30));
udelay(5);
tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl);
tp->tg3_flags2 |= TG3_FLG2_PHY_JUST_INITTED;
} else if (mac_status & (MAC_STATUS_PCS_SYNCED |
MAC_STATUS_SIGNAL_DET)) {
- sg_dig_status = tr32(SG_DIG_STATUS);
+ int i;
+
+ /* Giver time to negotiate (~200ms) */
+ for (i = 0; i < 40000; i++) {
+ sg_dig_status = tr32(SG_DIG_STATUS);
+ if (sg_dig_status & (0x3))
+ break;
+ udelay(5);
+ }
+ mac_status = tr32(MAC_STATUS);
if ((sg_dig_status & (1 << 1)) &&
(mac_status & MAC_STATUS_PCS_SYNCED)) {
u32 val = serdes_cfg;
if (port_a)
- val |= 0xc010880;
+ val |= 0xc010000;
else
- val |= 0x4010880;
+ val |= 0x4010000;
tw32_f(MAC_SERDES_CFG, val);
}
tw32_f(SG_DIG_CTRL, 0x01388400);
udelay(40);
+ /* Link parallel detection - link is up */
+ /* only if we have PCS_SYNC and not */
+ /* receiving config code words */
mac_status = tr32(MAC_STATUS);
- if (mac_status & MAC_STATUS_PCS_SYNCED) {
+ if ((mac_status & MAC_STATUS_PCS_SYNCED) &&
+ !(mac_status & MAC_STATUS_RCVD_CFG)) {
tg3_setup_flow_control(tp, 0, 0);
current_link_up = 1;
}
len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; /* omit crc */
- if (len > RX_COPY_THRESHOLD) {
+ if (len > RX_COPY_THRESHOLD
+ && tp->rx_offset == 2
+ /* rx_offset != 2 iff this is a 5701 card running
+ * in PCI-X mode [see tg3_get_invariants()] */
+ ) {
int skb_size;
skb_size = tg3_alloc_rx_skb(tp, opaque_key,
tw32_rx_mbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW,
sw_idx);
}
+ mmiowb();
return received;
}
if (done) {
spin_lock_irqsave(&tp->lock, flags);
__netif_rx_complete(netdev);
- tg3_enable_ints(tp);
+ tg3_restart_ints(tp);
spin_unlock_irqrestore(&tp->lock, flags);
}
skb->nh.iph->check = 0;
skb->nh.iph->tot_len = ntohs(mss + ip_tcp_len + tcp_opt_len);
- skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr,
- skb->nh.iph->daddr,
- 0, IPPROTO_TCP, 0);
+ if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
+ skb->h.th->check = 0;
+ base_flags &= ~TXD_FLAG_TCPUDP_CSUM;
+ }
+ else {
+ skb->h.th->check =
+ ~csum_tcpudp_magic(skb->nh.iph->saddr,
+ skb->nh.iph->daddr,
+ 0, IPPROTO_TCP, 0);
+ }
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
+ if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO) ||
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)) {
if (tcp_opt_len || skb->nh.iph->ihl > 5) {
int tsflags;
would_hit_hwbug = entry + 1;
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
+ if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
tg3_set_txd(tp, entry, mapping, len,
base_flags, (i == last)|(mss << 1));
else
netif_stop_queue(dev);
out_unlock:
+ mmiowb();
spin_unlock_irqrestore(&tp->tx_lock, flags);
dev->trans_start = jiffies;
val |= PCISTATE_RETRY_SAME_DMA;
pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
- pci_restore_state(tp->pdev, tp->pci_cfg_state);
+ pci_restore_state(tp->pdev);
/* Make sure PCI-X relaxed ordering bit is clear. */
pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val);
0xac470014, 0xac4a0018, 0x03e00008, 0xac4b001c, 0x00000000, 0x00000000,
};
-u32 tg3TsoFwRodata[] = {
+static u32 tg3TsoFwRodata[] = {
0x4d61696e, 0x43707542, 0x00000000, 0x4d61696e, 0x43707541, 0x00000000,
0x00000000, 0x00000000, 0x73746b6f, 0x66666c64, 0x496e0000, 0x73746b6f,
0x66662a2a, 0x00000000, 0x53774576, 0x656e7430, 0x00000000, 0x00000000,
0x00000000,
};
-u32 tg3TsoFwData[] = {
+static u32 tg3TsoFwData[] = {
0x00000000, 0x73746b6f, 0x66666c64, 0x5f76312e, 0x362e3000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000,
0x00000000, 0x00000000, 0x00000000,
};
-u32 tg3Tso5FwRodata[(TG3_TSO5_FW_RODATA_LEN / 4) + 1] = {
+static u32 tg3Tso5FwRodata[(TG3_TSO5_FW_RODATA_LEN / 4) + 1] = {
0x4d61696e, 0x43707542, 0x00000000, 0x4d61696e, 0x43707541, 0x00000000,
0x00000000, 0x00000000, 0x73746b6f, 0x66666c64, 0x00000000, 0x00000000,
0x73746b6f, 0x66666c64, 0x00000000, 0x00000000, 0x66617461, 0x6c457272,
0x00000000, 0x00000000, 0x00000000,
};
-u32 tg3Tso5FwData[(TG3_TSO5_FW_DATA_LEN / 4) + 1] = {
+static u32 tg3Tso5FwData[(TG3_TSO5_FW_DATA_LEN / 4) + 1] = {
0x00000000, 0x73746b6f, 0x66666c64, 0x5f76312e, 0x322e3000, 0x00000000,
0x00000000, 0x00000000, 0x00000000,
};
unsigned long cpu_base, cpu_scratch_base, cpu_scratch_size;
int err, i;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
+ if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
return 0;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
tw32(MAC_ADDR_0_LOW + (i * 8), addr_low);
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) {
+ 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);
(bdinfo_addr + TG3_BDINFO_MAXLEN_FLAGS),
maxlen_flags);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705)
+ if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705) &&
+ (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750))
tg3_write_mem(tp,
(bdinfo_addr + TG3_BDINFO_NIC_ADDR),
nic_addr);
}
#if TG3_TSO_SUPPORT != 0
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
+ if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
rdmac_mode |= (1 << 27);
#endif
tw32(RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ);
tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE);
#if TG3_TSO_SUPPORT != 0
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
+ if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE | 0x8);
#endif
tw32(SNDBDI_MODE, SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE);
udelay(10);
if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) {
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
+ if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) &&
+ !(tp->tg3_flags2 & TG3_FLG2_SERDES_PREEMPHASIS)) {
/* Set drive transmission level to 1.2V */
+ /* only if the signal pre-emphasis bit is not set */
val = tr32(MAC_SERDES_CFG);
val &= 0xfffff000;
val |= 0x880;
u32 tmp;
/* Clear CRC stats. */
- tg3_readphy(tp, 0x1e, &tmp);
- tg3_writephy(tp, 0x1e, tmp | 0x8000);
- tg3_readphy(tp, 0x14, &tmp);
+ if (!tg3_readphy(tp, 0x1e, &tmp)) {
+ tg3_writephy(tp, 0x1e, tmp | 0x8000);
+ tg3_readphy(tp, 0x14, &tmp);
+ }
}
__tg3_set_rx_mode(tp->dev);
u32 val;
spin_lock_irqsave(&tp->lock, flags);
- tg3_readphy(tp, 0x1e, &val);
- tg3_writephy(tp, 0x1e, val | 0x8000);
- tg3_readphy(tp, 0x14, &val);
+ if (!tg3_readphy(tp, 0x1e, &val)) {
+ tg3_writephy(tp, 0x1e, val | 0x8000);
+ tg3_readphy(tp, 0x14, &val);
+ } else
+ val = 0;
spin_unlock_irqrestore(&tp->lock, flags);
tp->phy_crc_errors += val;
static int tg3_get_eeprom_len(struct net_device *dev)
{
- return EEPROM_CHIP_SIZE;
+ struct tg3 *tp = netdev_priv(dev);
+
+ return tp->nvram_size;
}
-static int __devinit tg3_nvram_read_using_eeprom(struct tg3 *tp,
- u32 offset, u32 *val);
+static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val);
+
static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data)
{
- struct tg3 *tp = dev->priv;
+ struct tg3 *tp = netdev_priv(dev);
int ret;
u8 *pd;
u32 i, offset, len, val, b_offset, b_count;
len = eeprom->len;
eeprom->len = 0;
- ret = tg3_nvram_read_using_eeprom(tp, 0, &eeprom->magic);
- if (ret)
- return ret;
- eeprom->magic = swab32(eeprom->magic);
+ eeprom->magic = TG3_EEPROM_MAGIC;
if (offset & 3) {
/* adjustments to start on required 4 byte boundary */
/* i.e. offset=1 len=2 */
b_count = len;
}
- ret = tg3_nvram_read_using_eeprom(tp, offset-b_offset, &val);
+ ret = tg3_nvram_read(tp, offset-b_offset, &val);
if (ret)
return ret;
+ val = cpu_to_le32(val);
memcpy(data, ((char*)&val) + b_offset, b_count);
len -= b_count;
offset += b_count;
/* read bytes upto the last 4 byte boundary */
pd = &data[eeprom->len];
for (i = 0; i < (len - (len & 3)); i += 4) {
- ret = tg3_nvram_read_using_eeprom(tp, offset + i,
- (u32*)(pd + i));
+ ret = tg3_nvram_read(tp, offset + i, &val);
if (ret) {
eeprom->len += i;
return ret;
}
+ val = cpu_to_le32(val);
+ memcpy(pd + i, &val, 4);
}
eeprom->len += i;
pd = &data[eeprom->len];
b_count = len & 3;
b_offset = offset + len - b_count;
- ret = tg3_nvram_read_using_eeprom(tp, b_offset, &val);
+ ret = tg3_nvram_read(tp, b_offset, &val);
if (ret)
return ret;
+ val = cpu_to_le32(val);
memcpy(pd, ((char*)&val), b_count);
eeprom->len += b_count;
}
return 0;
}
+static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf);
+
+static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data)
+{
+ struct tg3 *tp = netdev_priv(dev);
+ int ret;
+ u32 offset, len, b_offset, odd_len, start, end;
+ u8 *buf;
+
+ if (eeprom->magic != TG3_EEPROM_MAGIC)
+ return -EINVAL;
+
+ offset = eeprom->offset;
+ len = eeprom->len;
+
+ if ((b_offset = (offset & 3))) {
+ /* adjustments to start on required 4 byte boundary */
+ ret = tg3_nvram_read(tp, offset-b_offset, &start);
+ if (ret)
+ return ret;
+ start = cpu_to_le32(start);
+ len += b_offset;
+ offset &= ~3;
+ }
+
+ odd_len = 0;
+ if ((len & 3) && ((len > 4) || (b_offset == 0))) {
+ /* adjustments to end on required 4 byte boundary */
+ odd_len = 1;
+ len = (len + 3) & ~3;
+ ret = tg3_nvram_read(tp, offset+len-4, &end);
+ if (ret)
+ return ret;
+ end = cpu_to_le32(end);
+ }
+
+ buf = data;
+ if (b_offset || odd_len) {
+ buf = kmalloc(len, GFP_KERNEL);
+ if (buf == 0)
+ return -ENOMEM;
+ if (b_offset)
+ memcpy(buf, &start, 4);
+ if (odd_len)
+ memcpy(buf+len-4, &end, 4);
+ memcpy(buf + b_offset, data, eeprom->len);
+ }
+
+ ret = tg3_nvram_write_block(tp, offset, len, buf);
+
+ if (buf != data)
+ kfree(buf);
+
+ return ret;
+}
+
static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct tg3 *tp = netdev_priv(dev);
int r;
spin_lock_irq(&tp->lock);
- tg3_readphy(tp, MII_BMCR, &bmcr);
- tg3_readphy(tp, MII_BMCR, &bmcr);
r = -EINVAL;
- if (bmcr & BMCR_ANENABLE) {
+ tg3_readphy(tp, MII_BMCR, &bmcr);
+ if (!tg3_readphy(tp, MII_BMCR, &bmcr) &&
+ (bmcr & BMCR_ANENABLE)) {
tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART);
r = 0;
}
static void tg3_get_ethtool_stats (struct net_device *dev,
struct ethtool_stats *estats, u64 *tmp_stats)
{
- struct tg3 *tp = dev->priv;
+ struct tg3 *tp = netdev_priv(dev);
memcpy(tmp_stats, tg3_get_estats(tp), sizeof(tp->estats));
}
.get_link = ethtool_op_get_link,
.get_eeprom_len = tg3_get_eeprom_len,
.get_eeprom = tg3_get_eeprom,
+ .set_eeprom = tg3_set_eeprom,
.get_ringparam = tg3_get_ringparam,
.set_ringparam = tg3_set_ringparam,
.get_pauseparam = tg3_get_pauseparam,
.get_ethtool_stats = tg3_get_ethtool_stats,
};
+static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
+{
+ u32 cursize, val;
+
+ tp->nvram_size = EEPROM_CHIP_SIZE;
+
+ if (tg3_nvram_read(tp, 0, &val) != 0)
+ return;
+
+ if (swab32(val) != TG3_EEPROM_MAGIC)
+ return;
+
+ /*
+ * Size the chip by reading offsets at increasing powers of two.
+ * When we encounter our validation signature, we know the addressing
+ * has wrapped around, and thus have our chip size.
+ */
+ cursize = 0x800;
+
+ while (cursize < tp->nvram_size) {
+ if (tg3_nvram_read(tp, cursize, &val) != 0)
+ return;
+
+ if (swab32(val) == TG3_EEPROM_MAGIC)
+ break;
+
+ cursize <<= 1;
+ }
+
+ tp->nvram_size = cursize;
+}
+
+static void __devinit tg3_get_nvram_size(struct tg3 *tp)
+{
+ u32 val;
+
+ if (tg3_nvram_read(tp, 0xf0, &val) == 0) {
+ if (val != 0) {
+ tp->nvram_size = (val >> 16) * 1024;
+ return;
+ }
+ }
+ tp->nvram_size = 0x20000;
+}
+
+static void __devinit tg3_get_nvram_info(struct tg3 *tp)
+{
+ u32 nvcfg1;
+
+ nvcfg1 = tr32(NVRAM_CFG1);
+ if (nvcfg1 & NVRAM_CFG1_FLASHIF_ENAB) {
+ tp->tg3_flags2 |= TG3_FLG2_FLASH;
+ }
+ else {
+ nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
+ tw32(NVRAM_CFG1, nvcfg1);
+ }
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
+ switch (nvcfg1 & NVRAM_CFG1_VENDOR_MASK) {
+ case FLASH_VENDOR_ATMEL_FLASH_BUFFERED:
+ tp->nvram_jedecnum = JEDEC_ATMEL;
+ tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE;
+ tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+ break;
+ case FLASH_VENDOR_ATMEL_FLASH_UNBUFFERED:
+ tp->nvram_jedecnum = JEDEC_ATMEL;
+ tp->nvram_pagesize = ATMEL_AT25F512_PAGE_SIZE;
+ break;
+ case FLASH_VENDOR_ATMEL_EEPROM:
+ tp->nvram_jedecnum = JEDEC_ATMEL;
+ tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
+ tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+ break;
+ case FLASH_VENDOR_ST:
+ tp->nvram_jedecnum = JEDEC_ST;
+ tp->nvram_pagesize = ST_M45PEX0_PAGE_SIZE;
+ tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+ break;
+ case FLASH_VENDOR_SAIFUN:
+ tp->nvram_jedecnum = JEDEC_SAIFUN;
+ tp->nvram_pagesize = SAIFUN_SA25F0XX_PAGE_SIZE;
+ break;
+ case FLASH_VENDOR_SST_SMALL:
+ case FLASH_VENDOR_SST_LARGE:
+ tp->nvram_jedecnum = JEDEC_SST;
+ tp->nvram_pagesize = SST_25VF0X0_PAGE_SIZE;
+ break;
+ }
+ }
+ else {
+ tp->nvram_jedecnum = JEDEC_ATMEL;
+ tp->nvram_pagesize = ATMEL_AT45DB0X1B_PAGE_SIZE;
+ tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+ }
+}
+
/* Chips other than 5700/5701 use the NVRAM for fetching info. */
static void __devinit tg3_nvram_init(struct tg3 *tp)
{
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) {
- u32 nvcfg1;
+ tp->tg3_flags |= TG3_FLAG_NVRAM;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
u32 nvaccess = tr32(NVRAM_ACCESS);
- tw32_f(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE);
+ tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE);
}
- nvcfg1 = tr32(NVRAM_CFG1);
-
- tp->tg3_flags |= TG3_FLAG_NVRAM;
- if (nvcfg1 & NVRAM_CFG1_FLASHIF_ENAB) {
- if (nvcfg1 & NVRAM_CFG1_BUFFERED_MODE)
- tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
- } else {
- nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS;
- tw32(NVRAM_CFG1, nvcfg1);
- }
+ tg3_get_nvram_info(tp);
+ tg3_get_nvram_size(tp);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
u32 nvaccess = tr32(NVRAM_ACCESS);
- tw32_f(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE);
+ tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE);
}
+
} else {
tp->tg3_flags &= ~(TG3_FLAG_NVRAM | TG3_FLAG_NVRAM_BUFFERED);
+
+ tg3_get_eeprom_size(tp);
}
}
-static int __devinit tg3_nvram_read_using_eeprom(struct tg3 *tp,
- u32 offset, u32 *val)
+static int tg3_nvram_read_using_eeprom(struct tg3 *tp,
+ u32 offset, u32 *val)
{
u32 tmp;
int i;
return 0;
}
-static int __devinit tg3_nvram_read(struct tg3 *tp,
- u32 offset, u32 *val)
+#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 int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val)
+{
+ int ret;
+
if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) {
printk(KERN_ERR PFX "Attempt to do nvram_read on Sun 570X\n");
return -EINVAL;
if (!(tp->tg3_flags & TG3_FLAG_NVRAM))
return tg3_nvram_read_using_eeprom(tp, offset, val);
- if (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED)
- offset = ((offset / NVRAM_BUFFERED_PAGE_SIZE) <<
- NVRAM_BUFFERED_PAGE_POS) +
- (offset % NVRAM_BUFFERED_PAGE_SIZE);
+ if ((tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) &&
+ (tp->tg3_flags2 & TG3_FLG2_FLASH) &&
+ (tp->nvram_jedecnum == JEDEC_ATMEL)) {
+
+ offset = ((offset / tp->nvram_pagesize) <<
+ ATMEL_AT45DB0X1B_PAGE_POS) +
+ (offset % tp->nvram_pagesize);
+ }
if (offset > NVRAM_ADDR_MSK)
return -EINVAL;
}
tw32(NVRAM_ADDR, offset);
- tw32(NVRAM_CMD,
- NVRAM_CMD_RD | NVRAM_CMD_GO |
- NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_DONE);
+ ret = tg3_nvram_exec_cmd(tp, NVRAM_CMD_RD | NVRAM_CMD_GO |
+ NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_DONE);
- /* Wait for done bit to clear. */
- for (i = 0; i < 1000; i++) {
- udelay(10);
- if (tr32(NVRAM_CMD) & NVRAM_CMD_DONE) {
- udelay(10);
- *val = swab32(tr32(NVRAM_RDDATA));
- break;
- }
- }
+ if (ret == 0)
+ *val = swab32(tr32(NVRAM_RDDATA));
tg3_nvram_unlock(tp);
tw32_f(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE);
}
- if (i >= 1000)
- return -EBUSY;
+ return ret;
+}
- return 0;
+static int tg3_nvram_write_block_using_eeprom(struct tg3 *tp,
+ u32 offset, u32 len, u8 *buf)
+{
+ int i, j, rc = 0;
+ u32 val;
+
+ for (i = 0; i < len; i += 4) {
+ u32 addr, data;
+
+ addr = offset + i;
+
+ memcpy(&data, buf + i, 4);
+
+ tw32(GRC_EEPROM_DATA, cpu_to_le32(data));
+
+ val = tr32(GRC_EEPROM_ADDR);
+ tw32(GRC_EEPROM_ADDR, val | EEPROM_ADDR_COMPLETE);
+
+ val &= ~(EEPROM_ADDR_ADDR_MASK | EEPROM_ADDR_DEVID_MASK |
+ EEPROM_ADDR_READ);
+ tw32(GRC_EEPROM_ADDR, val |
+ (0 << EEPROM_ADDR_DEVID_SHIFT) |
+ (addr & EEPROM_ADDR_ADDR_MASK) |
+ EEPROM_ADDR_START |
+ EEPROM_ADDR_WRITE);
+
+ for (j = 0; j < 10000; j++) {
+ val = tr32(GRC_EEPROM_ADDR);
+
+ if (val & EEPROM_ADDR_COMPLETE)
+ break;
+ udelay(100);
+ }
+ if (!(val & EEPROM_ADDR_COMPLETE)) {
+ rc = -EBUSY;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+/* offset and length are dword aligned */
+static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len,
+ u8 *buf)
+{
+ int ret = 0;
+ u32 pagesize = tp->nvram_pagesize;
+ u32 pagemask = pagesize - 1;
+ u32 nvram_cmd;
+ u8 *tmp;
+
+ tmp = kmalloc(pagesize, GFP_KERNEL);
+ if (tmp == NULL)
+ return -ENOMEM;
+
+ while (len) {
+ int j;
+ u32 phy_addr, page_off, size, nvaccess;
+
+ phy_addr = offset & ~pagemask;
+
+ for (j = 0; j < pagesize; j += 4) {
+ if ((ret = tg3_nvram_read(tp, phy_addr + j,
+ (u32 *) (tmp + j))))
+ break;
+ }
+ if (ret)
+ break;
+
+ page_off = offset & pagemask;
+ size = pagesize;
+ if (len < size)
+ size = len;
+
+ len -= size;
+
+ memcpy(tmp + page_off, buf, size);
+
+ offset = offset + (pagesize - page_off);
+
+ nvaccess = tr32(NVRAM_ACCESS);
+ tw32_f(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE);
+
+ /*
+ * Before we can erase the flash page, we need
+ * to issue a special "write enable" command.
+ */
+ nvram_cmd = NVRAM_CMD_WREN | NVRAM_CMD_GO | NVRAM_CMD_DONE;
+
+ if (tg3_nvram_exec_cmd(tp, nvram_cmd))
+ break;
+
+ /* Erase the target page */
+ tw32(NVRAM_ADDR, phy_addr);
+
+ nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | NVRAM_CMD_WR |
+ NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_ERASE;
+
+ if (tg3_nvram_exec_cmd(tp, nvram_cmd))
+ break;
+
+ /* Issue another write enable to start the write. */
+ nvram_cmd = NVRAM_CMD_WREN | NVRAM_CMD_GO | NVRAM_CMD_DONE;
+
+ if (tg3_nvram_exec_cmd(tp, nvram_cmd))
+ break;
+
+ for (j = 0; j < pagesize; j += 4) {
+ u32 data;
+
+ data = *((u32 *) (tmp + j));
+ tw32(NVRAM_WRDATA, cpu_to_be32(data));
+
+ tw32(NVRAM_ADDR, phy_addr + j);
+
+ nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE |
+ NVRAM_CMD_WR;
+
+ if (j == 0)
+ nvram_cmd |= NVRAM_CMD_FIRST;
+ else if (j == (pagesize - 4))
+ nvram_cmd |= NVRAM_CMD_LAST;
+
+ if ((ret = tg3_nvram_exec_cmd(tp, nvram_cmd)))
+ break;
+ }
+ if (ret)
+ break;
+ }
+
+ nvram_cmd = NVRAM_CMD_WRDI | NVRAM_CMD_GO | NVRAM_CMD_DONE;
+ tg3_nvram_exec_cmd(tp, nvram_cmd);
+
+ kfree(tmp);
+
+ return ret;
+}
+
+/* offset and length are dword aligned */
+static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len,
+ u8 *buf)
+{
+ int i, ret = 0;
+
+ for (i = 0; i < len; i += 4, offset += 4) {
+ u32 data, page_off, phy_addr, nvram_cmd;
+
+ memcpy(&data, buf + i, 4);
+ tw32(NVRAM_WRDATA, cpu_to_be32(data));
+
+ page_off = offset % tp->nvram_pagesize;
+
+ if ((tp->tg3_flags2 & TG3_FLG2_FLASH) &&
+ (tp->nvram_jedecnum == JEDEC_ATMEL)) {
+
+ phy_addr = ((offset / tp->nvram_pagesize) <<
+ ATMEL_AT45DB0X1B_PAGE_POS) + page_off;
+ }
+ else {
+ phy_addr = offset;
+ }
+
+ tw32(NVRAM_ADDR, phy_addr);
+
+ nvram_cmd = NVRAM_CMD_GO | NVRAM_CMD_DONE | NVRAM_CMD_WR;
+
+ if ((page_off == 0) || (i == 0))
+ nvram_cmd |= NVRAM_CMD_FIRST;
+ else if (page_off == (tp->nvram_pagesize - 4))
+ nvram_cmd |= NVRAM_CMD_LAST;
+
+ if (i == (len - 4))
+ nvram_cmd |= NVRAM_CMD_LAST;
+
+ if ((tp->nvram_jedecnum == JEDEC_ST) &&
+ (nvram_cmd & NVRAM_CMD_FIRST)) {
+
+ if ((ret = tg3_nvram_exec_cmd(tp,
+ NVRAM_CMD_WREN | NVRAM_CMD_GO |
+ NVRAM_CMD_DONE)))
+
+ break;
+ }
+ if (!(tp->tg3_flags2 & TG3_FLG2_FLASH)) {
+ /* We always do complete word writes to eeprom. */
+ nvram_cmd |= (NVRAM_CMD_FIRST | NVRAM_CMD_LAST);
+ }
+
+ if ((ret = tg3_nvram_exec_cmd(tp, nvram_cmd)))
+ break;
+ }
+ return ret;
+}
+
+/* offset and length are dword aligned */
+static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf)
+{
+ int ret;
+
+ if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) {
+ printk(KERN_ERR PFX "Attempt to do nvram_write on Sun 570X\n");
+ return -EINVAL;
+ }
+
+ if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) {
+ tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
+ GRC_LCLCTRL_GPIO_OE1);
+ udelay(40);
+ }
+
+ if (!(tp->tg3_flags & TG3_FLAG_NVRAM)) {
+ ret = tg3_nvram_write_block_using_eeprom(tp, offset, len, buf);
+ }
+ else {
+ u32 grc_mode;
+
+ tg3_nvram_lock(tp);
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
+ u32 nvaccess = tr32(NVRAM_ACCESS);
+
+ tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE);
+
+ tw32(NVRAM_WRITE1, 0x406);
+ }
+
+ grc_mode = tr32(GRC_MODE);
+ tw32(GRC_MODE, grc_mode | GRC_MODE_NVRAM_WR_ENABLE);
+
+ if ((tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) ||
+ !(tp->tg3_flags2 & TG3_FLG2_FLASH)) {
+
+ ret = tg3_nvram_write_block_buffered(tp, offset, len,
+ buf);
+ }
+ else {
+ ret = tg3_nvram_write_block_unbuffered(tp, offset, len,
+ buf);
+ }
+
+ grc_mode = tr32(GRC_MODE);
+ tw32(GRC_MODE, grc_mode & ~GRC_MODE_NVRAM_WR_ENABLE);
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
+ u32 nvaccess = tr32(NVRAM_ACCESS);
+
+ tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE);
+ }
+ tg3_nvram_unlock(tp);
+ }
+
+ if (tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) {
+ tw32_f(GRC_LOCAL_CTRL, tp->grc_local_ctrl |
+ GRC_LCLCTRL_GPIO_OE1 | GRC_LCLCTRL_GPIO_OUTPUT1);
+ udelay(40);
+ }
+
+ return ret;
}
struct subsys_tbl_ent {
tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val);
if (val == NIC_SRAM_DATA_SIG_MAGIC) {
u32 nic_cfg, led_cfg;
- u32 nic_phy_id, cfg2;
+ u32 nic_phy_id, ver, cfg2 = 0;
tg3_read_mem(tp, NIC_SRAM_DATA_CFG, &nic_cfg);
tp->nic_sram_data_cfg = nic_cfg;
+ tg3_read_mem(tp, NIC_SRAM_DATA_VER, &ver);
+ ver >>= NIC_SRAM_DATA_VER_SHIFT;
+ if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) &&
+ (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) &&
+ (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5703) &&
+ (ver > 0) && (ver < 0x100))
+ tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &cfg2);
+
eeprom_signature_found = 1;
if ((nic_cfg & NIC_SRAM_DATA_CFG_PHY_TYPE_MASK) ==
eeprom_phy_id = 0;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750) {
- tg3_read_mem(tp, NIC_SRAM_DATA_CFG_2, &led_cfg);
- led_cfg &= (NIC_SRAM_DATA_CFG_LED_MODE_MASK |
+ led_cfg = cfg2 & (NIC_SRAM_DATA_CFG_LED_MODE_MASK |
SHASTA_EXT_LED_MODE_MASK);
} else
led_cfg = nic_cfg & NIC_SRAM_DATA_CFG_LED_MODE_MASK;
tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL)
tp->led_ctrl = LED_CTRL_MODE_PHY_2;
- 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)) &&
+ if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) &&
+ (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5701) &&
(nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP))
tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
if (nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL)
tp->tg3_flags |= TG3_FLAG_SERDES_WOL_CAP;
- tg3_read_mem(tp, NIC_SRAM_DATA_PHY_ID, &cfg2);
if (cfg2 & (1 << 17))
tp->tg3_flags2 |= TG3_FLG2_CAPACITIVE_COUPLING;
+
+ /* serdes signal pre-emphasis in register 0x590 set by */
+ /* bootcode if bit 18 is set */
+ if (cfg2 & (1 << 18))
+ tp->tg3_flags2 |= TG3_FLG2_SERDES_PREEMPHASIS;
}
/* Reading the PHY ID register can conflict with ASF
u32 bmsr, adv_reg, tg3_ctrl;
tg3_readphy(tp, MII_BMSR, &bmsr);
- tg3_readphy(tp, MII_BMSR, &bmsr);
-
- if (bmsr & BMSR_LSTATUS)
+ if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
+ (bmsr & BMSR_LSTATUS))
goto skip_phy_reset;
err = tg3_phy_reset(tp);
tp->pci_hdr_type = (cacheline_sz_reg >> 16) & 0xff;
tp->pci_bist = (cacheline_sz_reg >> 24) & 0xff;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
+ tp->tg3_flags2 |= TG3_FLG2_HW_TSO;
+
if (pci_find_capability(tp->pdev, PCI_CAP_ID_EXP) != 0)
tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS;
tp->pdev->device == PCI_DEVICE_ID_TIGON3_5901_2 ||
tp->pdev->device == PCI_DEVICE_ID_TIGON3_5705F)) ||
(tp->pdev->vendor == PCI_VENDOR_ID_BROADCOM &&
- tp->pdev->device == PCI_DEVICE_ID_TIGON3_5751F))
+ (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5751F ||
+ tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F)))
tp->tg3_flags |= TG3_FLAG_10_100_ONLY;
err = tg3_phy_probe(tp);
#endif
if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) {
- tp->dma_rwctrl |= 0x001f0000;
+ /* DMA read watermark not used on PCIE */
+ tp->dma_rwctrl |= 0x00180000;
} else if (!(tp->tg3_flags & TG3_FLAG_PCIX_MODE)) {
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750)
spin_lock_init(&tp->indirect_lock);
INIT_WORK(&tp->reset_task, tg3_reset_task, tp);
- tp->regs = ioremap(tg3reg_base, tg3reg_len);
+ tp->regs = ioremap_nocache(tg3reg_base, tg3reg_len);
if (tp->regs == 0UL) {
printk(KERN_ERR PFX "Cannot map device registers, "
"aborting.\n");
}
#if TG3_TSO_SUPPORT != 0
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
+ if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
+ tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
+ }
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 ||
tp->pci_chip_rev_id == CHIPREV_ID_5705_A0 ||
- ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750)) {
+ (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0) {
tp->tg3_flags2 &= ~TG3_FLG2_TSO_CAPABLE;
} else {
tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
*/
if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) ||
(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
- pci_save_state(tp->pdev, tp->pci_cfg_state);
+ pci_save_state(tp->pdev);
tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
tg3_halt(tp);
}
* of the PCI config space. We need to restore this after
* GRC_MISC_CFG core clock resets and some resume events.
*/
- pci_save_state(tp->pdev, tp->pci_cfg_state);
+ pci_save_state(tp->pdev);
printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] (PCI%s:%s:%s) %sBaseT Ethernet ",
dev->name,
if (!netif_running(dev))
return 0;
- pci_restore_state(tp->pdev, tp->pci_cfg_state);
+ pci_restore_state(tp->pdev);
err = tg3_set_power_state(tp, 0);
if (err)