]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/net/via-velocity.c
Merge tag 'v2.6.37' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / drivers / net / via-velocity.c
index f53412368ce1e1745a7796a8cc8181b16027e797..cab96ad49e601488100d744ecacc6a76539f9b34 100644 (file)
@@ -312,13 +312,14 @@ VELOCITY_PARAM(flow_control, "Enable flow control ability");
 
 #define MED_LNK_DEF 0
 #define MED_LNK_MIN 0
-#define MED_LNK_MAX 4
+#define MED_LNK_MAX 5
 /* speed_duplex[] is used for setting the speed and duplex mode of NIC.
    0: indicate autonegotiation for both speed and duplex mode
    1: indicate 100Mbps half duplex mode
    2: indicate 100Mbps full duplex mode
    3: indicate 10Mbps half duplex mode
    4: indicate 10Mbps full duplex mode
+   5: indicate 1000Mbps full duplex mode
 
    Note:
    if EEPROM have been set to the force mode, this option is ignored
@@ -617,6 +618,9 @@ static u32 velocity_get_opt_media_mode(struct velocity_info *vptr)
        case SPD_DPX_10_HALF:
                status = VELOCITY_SPEED_10;
                break;
+       case SPD_DPX_1000_FULL:
+               status = VELOCITY_SPEED_1000 | VELOCITY_DUPLEX_FULL;
+               break;
        }
        vptr->mii_status = status;
        return status;
@@ -922,6 +926,7 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
                /* enable AUTO-NEGO mode */
                mii_set_auto_on(vptr);
        } else {
+               u16 CTRL1000;
                u16 ANAR;
                u8 CHIPGCR;
 
@@ -936,7 +941,11 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
                BYTE_REG_BITS_ON(CHIPGCR_FCMODE, &regs->CHIPGCR);
 
                CHIPGCR = readb(&regs->CHIPGCR);
-               CHIPGCR &= ~CHIPGCR_FCGMII;
+
+               if (mii_status & VELOCITY_SPEED_1000)
+                       CHIPGCR |= CHIPGCR_FCGMII;
+               else
+                       CHIPGCR &= ~CHIPGCR_FCGMII;
 
                if (mii_status & VELOCITY_DUPLEX_FULL) {
                        CHIPGCR |= CHIPGCR_FCFDX;
@@ -952,7 +961,13 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
                                BYTE_REG_BITS_ON(TCR_TB2BDIS, &regs->TCR);
                }
 
-               MII_REG_BITS_OFF(ADVERTISE_1000FULL | ADVERTISE_1000HALF, MII_CTRL1000, vptr->mac_regs);
+               velocity_mii_read(vptr->mac_regs, MII_CTRL1000, &CTRL1000);
+               CTRL1000 &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+               if ((mii_status & VELOCITY_SPEED_1000) &&
+                   (mii_status & VELOCITY_DUPLEX_FULL)) {
+                       CTRL1000 |= ADVERTISE_1000FULL;
+               }
+               velocity_mii_write(vptr->mac_regs, MII_CTRL1000, CTRL1000);
 
                if (!(mii_status & VELOCITY_DUPLEX_FULL) && (mii_status & VELOCITY_SPEED_10))
                        BYTE_REG_BITS_OFF(TESTCFG_HBDIS, &regs->TESTCFG);
@@ -967,7 +982,7 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
                                ANAR |= ADVERTISE_100FULL;
                        else
                                ANAR |= ADVERTISE_100HALF;
-               } else {
+               } else if (mii_status & VELOCITY_SPEED_10) {
                        if (mii_status & VELOCITY_DUPLEX_FULL)
                                ANAR |= ADVERTISE_10FULL;
                        else
@@ -1013,6 +1028,9 @@ static void velocity_print_link_status(struct velocity_info *vptr)
        } else {
                VELOCITY_PRT(MSG_LEVEL_INFO, KERN_NOTICE "%s: Link forced", vptr->dev->name);
                switch (vptr->options.spd_dpx) {
+               case SPD_DPX_1000_FULL:
+                       VELOCITY_PRT(MSG_LEVEL_INFO, " speed 1000M bps full duplex\n");
+                       break;
                case SPD_DPX_100_HALF:
                        VELOCITY_PRT(MSG_LEVEL_INFO, " speed 100M bps half duplex\n");
                        break;
@@ -1954,7 +1972,7 @@ static int velocity_tx_srv(struct velocity_info *vptr)
  */
 static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb)
 {
-       skb->ip_summed = CHECKSUM_NONE;
+       skb_checksum_none_assert(skb);
 
        if (rd->rdesc1.CSM & CSM_IPKT) {
                if (rd->rdesc1.CSM & CSM_IPOK) {
@@ -2574,7 +2592,7 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb,
 
        td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16;
 
-       if (vptr->vlgrp && vlan_tx_tag_present(skb)) {
+       if (vlan_tx_tag_present(skb)) {
                td_ptr->tdesc1.vlan = cpu_to_le16(vlan_tx_tag_get(skb));
                td_ptr->tdesc1.TCR |= TCR0_VETAG;
        }
@@ -3170,6 +3188,37 @@ static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd
                        SUPPORTED_100baseT_Full |
                        SUPPORTED_1000baseT_Half |
                        SUPPORTED_1000baseT_Full;
+
+       cmd->advertising = ADVERTISED_TP | ADVERTISED_Autoneg;
+       if (vptr->options.spd_dpx == SPD_DPX_AUTO) {
+               cmd->advertising |=
+                       ADVERTISED_10baseT_Half |
+                       ADVERTISED_10baseT_Full |
+                       ADVERTISED_100baseT_Half |
+                       ADVERTISED_100baseT_Full |
+                       ADVERTISED_1000baseT_Half |
+                       ADVERTISED_1000baseT_Full;
+       } else {
+               switch (vptr->options.spd_dpx) {
+               case SPD_DPX_1000_FULL:
+                       cmd->advertising |= ADVERTISED_1000baseT_Full;
+                       break;
+               case SPD_DPX_100_HALF:
+                       cmd->advertising |= ADVERTISED_100baseT_Half;
+                       break;
+               case SPD_DPX_100_FULL:
+                       cmd->advertising |= ADVERTISED_100baseT_Full;
+                       break;
+               case SPD_DPX_10_HALF:
+                       cmd->advertising |= ADVERTISED_10baseT_Half;
+                       break;
+               case SPD_DPX_10_FULL:
+                       cmd->advertising |= ADVERTISED_10baseT_Full;
+                       break;
+               default:
+                       break;
+               }
+       }
        if (status & VELOCITY_SPEED_1000)
                cmd->speed = SPEED_1000;
        else if (status & VELOCITY_SPEED_100)
@@ -3200,14 +3249,35 @@ static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd
        curr_status &= (~VELOCITY_LINK_FAIL);
 
        new_status |= ((cmd->autoneg) ? VELOCITY_AUTONEG_ENABLE : 0);
+       new_status |= ((cmd->speed == SPEED_1000) ? VELOCITY_SPEED_1000 : 0);
        new_status |= ((cmd->speed == SPEED_100) ? VELOCITY_SPEED_100 : 0);
        new_status |= ((cmd->speed == SPEED_10) ? VELOCITY_SPEED_10 : 0);
        new_status |= ((cmd->duplex == DUPLEX_FULL) ? VELOCITY_DUPLEX_FULL : 0);
 
-       if ((new_status & VELOCITY_AUTONEG_ENABLE) && (new_status != (curr_status | VELOCITY_AUTONEG_ENABLE)))
+       if ((new_status & VELOCITY_AUTONEG_ENABLE) &&
+           (new_status != (curr_status | VELOCITY_AUTONEG_ENABLE))) {
                ret = -EINVAL;
-       else
+       } else {
+               enum speed_opt spd_dpx;
+
+               if (new_status & VELOCITY_AUTONEG_ENABLE)
+                       spd_dpx = SPD_DPX_AUTO;
+               else if ((new_status & VELOCITY_SPEED_1000) &&
+                        (new_status & VELOCITY_DUPLEX_FULL)) {
+                       spd_dpx = SPD_DPX_1000_FULL;
+               } else if (new_status & VELOCITY_SPEED_100)
+                       spd_dpx = (new_status & VELOCITY_DUPLEX_FULL) ?
+                               SPD_DPX_100_FULL : SPD_DPX_100_HALF;
+               else if (new_status & VELOCITY_SPEED_10)
+                       spd_dpx = (new_status & VELOCITY_DUPLEX_FULL) ?
+                               SPD_DPX_10_FULL : SPD_DPX_10_HALF;
+               else
+                       return -EOPNOTSUPP;
+
+               vptr->options.spd_dpx = spd_dpx;
+
                velocity_set_media_mode(vptr, new_status);
+       }
 
        return ret;
 }