bnx2: Refine VPD logic.
[safe/jmp/linux-2.6] / drivers / net / smsc9420.c
index 80dab8b..12f0f5d 100644 (file)
@@ -252,6 +252,9 @@ static int smsc9420_ethtool_get_settings(struct net_device *dev,
 {
        struct smsc9420_pdata *pd = netdev_priv(dev);
 
+       if (!pd->phy_dev)
+               return -ENODEV;
+
        cmd->maxtxpkt = 1;
        cmd->maxrxpkt = 1;
        return phy_ethtool_gset(pd->phy_dev, cmd);
@@ -262,6 +265,9 @@ static int smsc9420_ethtool_set_settings(struct net_device *dev,
 {
        struct smsc9420_pdata *pd = netdev_priv(dev);
 
+       if (!pd->phy_dev)
+               return -ENODEV;
+
        return phy_ethtool_sset(pd->phy_dev, cmd);
 }
 
@@ -290,9 +296,162 @@ static void smsc9420_ethtool_set_msglevel(struct net_device *netdev, u32 data)
 static int smsc9420_ethtool_nway_reset(struct net_device *netdev)
 {
        struct smsc9420_pdata *pd = netdev_priv(netdev);
+
+       if (!pd->phy_dev)
+               return -ENODEV;
+
        return phy_start_aneg(pd->phy_dev);
 }
 
+static int smsc9420_ethtool_getregslen(struct net_device *dev)
+{
+       /* all smsc9420 registers plus all phy registers */
+       return 0x100 + (32 * sizeof(u32));
+}
+
+static void
+smsc9420_ethtool_getregs(struct net_device *dev, struct ethtool_regs *regs,
+                        void *buf)
+{
+       struct smsc9420_pdata *pd = netdev_priv(dev);
+       struct phy_device *phy_dev = pd->phy_dev;
+       unsigned int i, j = 0;
+       u32 *data = buf;
+
+       regs->version = smsc9420_reg_read(pd, ID_REV);
+       for (i = 0; i < 0x100; i += (sizeof(u32)))
+               data[j++] = smsc9420_reg_read(pd, i);
+
+       // cannot read phy registers if the net device is down
+       if (!phy_dev)
+               return;
+
+       for (i = 0; i <= 31; i++)
+               data[j++] = smsc9420_mii_read(phy_dev->bus, phy_dev->addr, i);
+}
+
+static void smsc9420_eeprom_enable_access(struct smsc9420_pdata *pd)
+{
+       unsigned int temp = smsc9420_reg_read(pd, GPIO_CFG);
+       temp &= ~GPIO_CFG_EEPR_EN_;
+       smsc9420_reg_write(pd, GPIO_CFG, temp);
+       msleep(1);
+}
+
+static int smsc9420_eeprom_send_cmd(struct smsc9420_pdata *pd, u32 op)
+{
+       int timeout = 100;
+       u32 e2cmd;
+
+       smsc_dbg(HW, "op 0x%08x", op);
+       if (smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_) {
+               smsc_warn(HW, "Busy at start");
+               return -EBUSY;
+       }
+
+       e2cmd = op | E2P_CMD_EPC_BUSY_;
+       smsc9420_reg_write(pd, E2P_CMD, e2cmd);
+
+       do {
+               msleep(1);
+               e2cmd = smsc9420_reg_read(pd, E2P_CMD);
+       } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (--timeout));
+
+       if (!timeout) {
+               smsc_info(HW, "TIMED OUT");
+               return -EAGAIN;
+       }
+
+       if (e2cmd & E2P_CMD_EPC_TIMEOUT_) {
+               smsc_info(HW, "Error occured during eeprom operation");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int smsc9420_eeprom_read_location(struct smsc9420_pdata *pd,
+                                        u8 address, u8 *data)
+{
+       u32 op = E2P_CMD_EPC_CMD_READ_ | address;
+       int ret;
+
+       smsc_dbg(HW, "address 0x%x", address);
+       ret = smsc9420_eeprom_send_cmd(pd, op);
+
+       if (!ret)
+               data[address] = smsc9420_reg_read(pd, E2P_DATA);
+
+       return ret;
+}
+
+static int smsc9420_eeprom_write_location(struct smsc9420_pdata *pd,
+                                         u8 address, u8 data)
+{
+       u32 op = E2P_CMD_EPC_CMD_ERASE_ | address;
+       int ret;
+
+       smsc_dbg(HW, "address 0x%x, data 0x%x", address, data);
+       ret = smsc9420_eeprom_send_cmd(pd, op);
+
+       if (!ret) {
+               op = E2P_CMD_EPC_CMD_WRITE_ | address;
+               smsc9420_reg_write(pd, E2P_DATA, (u32)data);
+               ret = smsc9420_eeprom_send_cmd(pd, op);
+       }
+
+       return ret;
+}
+
+static int smsc9420_ethtool_get_eeprom_len(struct net_device *dev)
+{
+       return SMSC9420_EEPROM_SIZE;
+}
+
+static int smsc9420_ethtool_get_eeprom(struct net_device *dev,
+                                      struct ethtool_eeprom *eeprom, u8 *data)
+{
+       struct smsc9420_pdata *pd = netdev_priv(dev);
+       u8 eeprom_data[SMSC9420_EEPROM_SIZE];
+       int len, i;
+
+       smsc9420_eeprom_enable_access(pd);
+
+       len = min(eeprom->len, SMSC9420_EEPROM_SIZE);
+       for (i = 0; i < len; i++) {
+               int ret = smsc9420_eeprom_read_location(pd, i, eeprom_data);
+               if (ret < 0) {
+                       eeprom->len = 0;
+                       return ret;
+               }
+       }
+
+       memcpy(data, &eeprom_data[eeprom->offset], len);
+       eeprom->magic = SMSC9420_EEPROM_MAGIC;
+       eeprom->len = len;
+       return 0;
+}
+
+static int smsc9420_ethtool_set_eeprom(struct net_device *dev,
+                                      struct ethtool_eeprom *eeprom, u8 *data)
+{
+       struct smsc9420_pdata *pd = netdev_priv(dev);
+       int ret;
+
+       if (eeprom->magic != SMSC9420_EEPROM_MAGIC)
+               return -EINVAL;
+
+       smsc9420_eeprom_enable_access(pd);
+       smsc9420_eeprom_send_cmd(pd, E2P_CMD_EPC_CMD_EWEN_);
+       ret = smsc9420_eeprom_write_location(pd, eeprom->offset, *data);
+       smsc9420_eeprom_send_cmd(pd, E2P_CMD_EPC_CMD_EWDS_);
+
+       /* Single byte write, according to man page */
+       eeprom->len = 1;
+
+       return ret;
+}
+
 static const struct ethtool_ops smsc9420_ethtool_ops = {
        .get_settings = smsc9420_ethtool_get_settings,
        .set_settings = smsc9420_ethtool_set_settings,
@@ -301,6 +460,11 @@ static const struct ethtool_ops smsc9420_ethtool_ops = {
        .set_msglevel = smsc9420_ethtool_set_msglevel,
        .nway_reset = smsc9420_ethtool_nway_reset,
        .get_link = ethtool_op_get_link,
+       .get_eeprom_len = smsc9420_ethtool_get_eeprom_len,
+       .get_eeprom = smsc9420_ethtool_get_eeprom,
+       .set_eeprom = smsc9420_ethtool_set_eeprom,
+       .get_regs_len = smsc9420_ethtool_getregslen,
+       .get_regs = smsc9420_ethtool_getregs,
 };
 
 /* Sets the device MAC address to dev_addr */
@@ -352,7 +516,7 @@ static void smsc9420_check_mac_address(struct net_device *dev)
 static void smsc9420_stop_tx(struct smsc9420_pdata *pd)
 {
        u32 dmac_control, mac_cr, dma_intr_ena;
-       int timeOut = 1000;
+       int timeout = 1000;
 
        /* disable TX DMAC */
        dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL);
@@ -360,13 +524,13 @@ static void smsc9420_stop_tx(struct smsc9420_pdata *pd)
        smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control);
 
        /* Wait max 10ms for transmit process to stop */
-       while (timeOut--) {
+       while (--timeout) {
                if (smsc9420_reg_read(pd, DMAC_STATUS) & DMAC_STS_TS_)
                        break;
                udelay(10);
        }
 
-       if (!timeOut)
+       if (!timeout)
                smsc_warn(IFDOWN, "TX DMAC failed to stop");
 
        /* ACK Tx DMAC stop bit */
@@ -450,7 +614,7 @@ static void smsc9420_free_rx_ring(struct smsc9420_pdata *pd)
 
 static void smsc9420_stop_rx(struct smsc9420_pdata *pd)
 {
-       int timeOut = 1000;
+       int timeout = 1000;
        u32 mac_cr, dmac_control, dma_intr_ena;
 
        /* mask RX DMAC interrupts */
@@ -471,13 +635,13 @@ static void smsc9420_stop_rx(struct smsc9420_pdata *pd)
        smsc9420_pci_flush_write(pd);
 
        /* wait up to 10ms for receive to stop */
-       while (timeOut--) {
+       while (--timeout) {
                if (smsc9420_reg_read(pd, DMAC_STATUS) & DMAC_STS_RS_)
                        break;
                udelay(10);
        }
 
-       if (!timeOut)
+       if (!timeout)
                smsc_warn(IFDOWN, "RX DMAC did not stop! timeout.");
 
        /* ACK the Rx DMAC stop bit */
@@ -520,7 +684,7 @@ static irqreturn_t smsc9420_isr(int irq, void *dev_id)
                        smsc9420_pci_flush_write(pd);
 
                        ints_to_clear |= (DMAC_STS_RX_ | DMAC_STS_NIS_);
-                       netif_rx_schedule(pd->dev, &pd->napi);
+                       napi_schedule(&pd->napi);
                }
 
                if (ints_to_clear)
@@ -657,7 +821,7 @@ static void smsc9420_rx_handoff(struct smsc9420_pdata *pd, const int index,
        if (pd->rx_csum) {
                u16 hw_csum = get_unaligned_le16(skb_tail_pointer(skb) +
                        NET_IP_ALIGN + packet_length + 4);
-               put_unaligned_le16(cpu_to_le16(hw_csum), &skb->csum);
+               put_unaligned_le16(hw_csum, &skb->csum);
                skb->ip_summed = CHECKSUM_COMPLETE;
        }
 
@@ -667,7 +831,6 @@ static void smsc9420_rx_handoff(struct smsc9420_pdata *pd, const int index,
        skb->protocol = eth_type_trans(skb, dev);
 
        netif_receive_skb(skb);
-       dev->last_rx = jiffies;
 }
 
 static int smsc9420_alloc_rx_buffer(struct smsc9420_pdata *pd, int index)
@@ -743,7 +906,7 @@ static int smsc9420_rx_poll(struct napi_struct *napi, int budget)
        smsc9420_pci_flush_write(pd);
 
        if (work_done < budget) {
-               netif_rx_complete(dev, &pd->napi);
+               napi_complete(&pd->napi);
 
                /* re-enable RX DMA interrupts */
                dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA);
@@ -818,7 +981,8 @@ static void smsc9420_complete_tx(struct net_device *dev)
        }
 }
 
-static int smsc9420_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t smsc9420_hard_start_xmit(struct sk_buff *skb,
+                                           struct net_device *dev)
 {
        struct smsc9420_pdata *pd = netdev_priv(dev);
        dma_addr_t mapping;
@@ -934,28 +1098,6 @@ static void smsc9420_set_multicast_list(struct net_device *dev)
        smsc9420_pci_flush_write(pd);
 }
 
-static u8 smsc9420_resolve_flowctrl_fulldplx(u16 lcladv, u16 rmtadv)
-{
-       u8 cap = 0;
-
-       if (lcladv & ADVERTISE_PAUSE_CAP) {
-               if (lcladv & ADVERTISE_PAUSE_ASYM) {
-                       if (rmtadv & LPA_PAUSE_CAP)
-                               cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
-                       else if (rmtadv & LPA_PAUSE_ASYM)
-                               cap = FLOW_CTRL_RX;
-               } else {
-                       if (rmtadv & LPA_PAUSE_CAP)
-                               cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
-               }
-       } else if (lcladv & ADVERTISE_PAUSE_ASYM) {
-               if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM))
-                       cap = FLOW_CTRL_TX;
-       }
-
-       return cap;
-}
-
 static void smsc9420_phy_update_flowcontrol(struct smsc9420_pdata *pd)
 {
        struct phy_device *phy_dev = pd->phy_dev;
@@ -964,7 +1106,7 @@ static void smsc9420_phy_update_flowcontrol(struct smsc9420_pdata *pd)
        if (phy_dev->duplex == DUPLEX_FULL) {
                u16 lcladv = phy_read(phy_dev, MII_ADVERTISE);
                u16 rmtadv = phy_read(phy_dev, MII_LPA);
-               u8 cap = smsc9420_resolve_flowctrl_fulldplx(lcladv, rmtadv);
+               u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv);
 
                if (cap & FLOW_CTRL_RX)
                        flow = 0xFFFF0002;
@@ -1032,8 +1174,8 @@ static int smsc9420_mii_probe(struct net_device *dev)
        smsc_info(PROBE, "PHY addr %d, phy_id 0x%08X", phydev->addr,
                phydev->phy_id);
 
-       phydev = phy_connect(dev, phydev->dev.bus_id,
-               &smsc9420_phy_adjust_link, 0, PHY_INTERFACE_MODE_MII);
+       phydev = phy_connect(dev, dev_name(&phydev->dev),
+               smsc9420_phy_adjust_link, 0, PHY_INTERFACE_MODE_MII);
 
        if (IS_ERR(phydev)) {
                pr_err("%s: Could not attach to PHY\n", dev->name);
@@ -1041,7 +1183,7 @@ static int smsc9420_mii_probe(struct net_device *dev)
        }
 
        pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
-               dev->name, phydev->drv->name, phydev->dev.bus_id, phydev->irq);
+               dev->name, phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
 
        /* mask with MAC supported features */
        phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
@@ -1254,6 +1396,7 @@ static int smsc9420_open(struct net_device *dev)
 
        /* test the IRQ connection to the ISR */
        smsc_dbg(IFUP, "Testing ISR using IRQ %d", dev->irq);
+       pd->software_irq_signal = false;
 
        spin_lock_irqsave(&pd->int_lock, flags);
        /* configure interrupt deassertion timer and enable interrupts */
@@ -1269,8 +1412,6 @@ static int smsc9420_open(struct net_device *dev)
        smsc9420_pci_flush_write(pd);
 
        timeout = 1000;
-       pd->software_irq_signal = false;
-       smp_wmb();
        while (timeout--) {
                if (pd->software_irq_signal)
                        break;
@@ -1427,6 +1568,7 @@ static const struct net_device_ops smsc9420_netdev_ops = {
        .ndo_set_multicast_list = smsc9420_set_multicast_list,
        .ndo_do_ioctl           = smsc9420_do_ioctl,
        .ndo_validate_addr      = eth_validate_addr,
+       .ndo_set_mac_address    = eth_mac_addr,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = smsc9420_poll_controller,
 #endif /* CONFIG_NET_POLL_CONTROLLER */
@@ -1470,7 +1612,7 @@ smsc9420_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto out_free_netdev_2;
        }
 
-       if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
+       if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
                printk(KERN_ERR "No usable DMA configuration, aborting.\n");
                goto out_free_regions_3;
        }