History:
Feb 4 2002 - created initially by ShuChen <shuchen@realtek.com.tw>.
May 20 2002 - Add link status force-mode and TBI mode support.
- 2004 - Massive updates. See kernel SCM system for details.
+ 2004 - Massive updates. See kernel SCM system for details.
=========================================================================
1. [DEPRECATED: use ethtool instead] The media can be forced in 5 modes.
Command: 'insmod r8169 media = SET_MEDIA'
Ex: 'insmod r8169 media = 0x04' will force PHY to operate in 100Mpbs Half-duplex.
-
+
SET_MEDIA can be:
_10_Half = 0x01
_10_Full = 0x02
_100_Half = 0x04
_100_Full = 0x08
_1000_Full = 0x10
-
+
2. Support TBI mode.
=========================================================================
VERSION 1.1 <2002/10/4>
The bit4:0 of MII register 4 is called "selector field", and have to be
00001b to indicate support of IEEE std 802.3 during NWay process of
- exchanging Link Code Word (FLP).
+ exchanging Link Code Word (FLP).
VERSION 1.2 <2002/11/30>
#include <linux/init.h>
#include <linux/dma-mapping.h>
+#include <asm/system.h>
#include <asm/io.h>
#include <asm/irq.h>
#ifdef RTL8169_DEBUG
#define assert(expr) \
- if(!(expr)) { \
- printk( "Assertion failed! %s,%s,%s,line=%d\n", \
- #expr,__FILE__,__FUNCTION__,__LINE__); \
- }
+ if (!(expr)) { \
+ printk( "Assertion failed! %s,%s,%s,line=%d\n", \
+ #expr,__FILE__,__FUNCTION__,__LINE__); \
+ }
#define dprintk(fmt, args...) do { printk(PFX fmt, ## args); } while (0)
#else
#define assert(expr) do {} while (0)
static struct pci_device_id rtl8169_pci_tbl[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), 0, 0, RTL_CFG_0 },
- { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136), 0, 0, RTL_CFG_1 },
- { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), 0, 0, RTL_CFG_1 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136), 0, 0, RTL_CFG_2 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), 0, 0, RTL_CFG_0 },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_2 },
{ PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 },
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(0x1259, 0xc107), 0, 0, RTL_CFG_0 },
{ PCI_DEVICE(0x16ec, 0x0116), 0, 0, RTL_CFG_0 },
{ PCI_VENDOR_ID_LINKSYS, 0x1032,
PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 },
LinkStatus = 0x02,
FullDup = 0x01,
- /* GIGABIT_PHY_registers */
- PHY_CTRL_REG = 0,
- PHY_STAT_REG = 1,
- PHY_AUTO_NEGO_REG = 4,
- PHY_1000_CTRL_REG = 9,
-
- /* GIGABIT_PHY_REG_BIT */
- PHY_Restart_Auto_Nego = 0x0200,
- PHY_Enable_Auto_Nego = 0x1000,
-
- /* PHY_STAT_REG = 1 */
- PHY_Auto_Neco_Comp = 0x0020,
-
- /* PHY_AUTO_NEGO_REG = 4 */
- PHY_Cap_10_Half = 0x0020,
- PHY_Cap_10_Full = 0x0040,
- PHY_Cap_100_Half = 0x0080,
- PHY_Cap_100_Full = 0x0100,
-
- /* PHY_1000_CTRL_REG = 9 */
- PHY_Cap_1000_Half = 0x0100,
- PHY_Cap_1000_Full = 0x0200,
-
- PHY_Cap_Null = 0x0,
-
/* _MediaType */
_10_Half = 0x01,
_10_Full = 0x02,
struct rtl8169_private {
void __iomem *mmio_addr; /* memory map physical address */
struct pci_dev *pci_dev; /* Index of PCI device */
+ struct net_device *dev;
struct net_device_stats stats; /* statistics of net device */
spinlock_t lock; /* spin lock flag */
u32 msg_enable;
void (*phy_reset_enable)(void __iomem *);
unsigned int (*phy_reset_pending)(void __iomem *);
unsigned int (*link_ok)(void __iomem *);
- struct work_struct task;
+ struct delayed_work task;
unsigned wol_enabled : 1;
};
static int rtl8169_open(struct net_device *dev);
static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs);
+static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance);
static int rtl8169_init_ring(struct net_device *dev);
static void rtl8169_hw_start(struct net_device *dev);
static int rtl8169_close(struct net_device *dev);
void __iomem *);
static int rtl8169_change_mtu(struct net_device *dev, int new_mtu);
static void rtl8169_down(struct net_device *dev);
+static void rtl8169_rx_clear(struct rtl8169_private *tp);
#ifdef CONFIG_R8169_NAPI
static int rtl8169_poll(struct net_device *dev, int *budget);
static const u16 rtl8169_napi_event =
RxOK | RxOverflow | RxFIFOOver | TxOK | TxErr;
static const unsigned int rtl8169_rx_config =
- (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
-
-#define PHY_Cap_10_Half_Or_Less PHY_Cap_10_Half
-#define PHY_Cap_10_Full_Or_Less PHY_Cap_10_Full | PHY_Cap_10_Half_Or_Less
-#define PHY_Cap_100_Half_Or_Less PHY_Cap_100_Half | PHY_Cap_10_Full_Or_Less
-#define PHY_Cap_100_Full_Or_Less PHY_Cap_100_Full | PHY_Cap_100_Half_Or_Less
+ (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
static void mdio_write(void __iomem *ioaddr, int RegAddr, int value)
{
for (i = 20; i > 0; i--) {
/* Check if the RTL8169 has completed writing to the specified MII register */
- if (!(RTL_R32(PHYAR) & 0x80000000))
+ if (!(RTL_R32(PHYAR) & 0x80000000))
break;
udelay(25);
}
static unsigned int rtl8169_xmii_reset_pending(void __iomem *ioaddr)
{
- return mdio_read(ioaddr, 0) & 0x8000;
+ return mdio_read(ioaddr, MII_BMCR) & BMCR_RESET;
}
static unsigned int rtl8169_tbi_link_ok(void __iomem *ioaddr)
{
unsigned int val;
- val = (mdio_read(ioaddr, PHY_CTRL_REG) | 0x8000) & 0xffff;
- mdio_write(ioaddr, PHY_CTRL_REG, val);
+ val = mdio_read(ioaddr, MII_BMCR) | BMCR_RESET;
+ mdio_write(ioaddr, MII_BMCR, val & 0xffff);
}
static void rtl8169_check_link_status(struct net_device *dev,
{ SPEED_1000, DUPLEX_FULL, AUTONEG_ENABLE, 0xff }
}, *p;
unsigned char option;
-
+
option = ((idx < MAX_UNITS) && (idx >= 0)) ? media[idx] : 0xff;
if ((option != 0xff) && !idx && netif_msg_drv(&debug))
if (options & UWF)
wol->wolopts |= WAKE_UCAST;
if (options & BWF)
- wol->wolopts |= WAKE_BCAST;
+ wol->wolopts |= WAKE_BCAST;
if (options & MWF)
- wol->wolopts |= WAKE_MCAST;
+ wol->wolopts |= WAKE_MCAST;
out_unlock:
spin_unlock_irq(&tp->lock);
void __iomem *ioaddr = tp->mmio_addr;
int auto_nego, giga_ctrl;
- auto_nego = mdio_read(ioaddr, PHY_AUTO_NEGO_REG);
- auto_nego &= ~(PHY_Cap_10_Half | PHY_Cap_10_Full |
- PHY_Cap_100_Half | PHY_Cap_100_Full);
- giga_ctrl = mdio_read(ioaddr, PHY_1000_CTRL_REG);
- giga_ctrl &= ~(PHY_Cap_1000_Full | PHY_Cap_1000_Half | PHY_Cap_Null);
+ auto_nego = mdio_read(ioaddr, MII_ADVERTISE);
+ auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
+ ADVERTISE_100HALF | ADVERTISE_100FULL);
+ giga_ctrl = mdio_read(ioaddr, MII_CTRL1000);
+ giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
if (autoneg == AUTONEG_ENABLE) {
- auto_nego |= (PHY_Cap_10_Half | PHY_Cap_10_Full |
- PHY_Cap_100_Half | PHY_Cap_100_Full);
- giga_ctrl |= PHY_Cap_1000_Full | PHY_Cap_1000_Half;
+ auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL |
+ ADVERTISE_100HALF | ADVERTISE_100FULL);
+ giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
} else {
if (speed == SPEED_10)
- auto_nego |= PHY_Cap_10_Half | PHY_Cap_10_Full;
+ auto_nego |= ADVERTISE_10HALF | ADVERTISE_10FULL;
else if (speed == SPEED_100)
- auto_nego |= PHY_Cap_100_Half | PHY_Cap_100_Full;
+ auto_nego |= ADVERTISE_100HALF | ADVERTISE_100FULL;
else if (speed == SPEED_1000)
- giga_ctrl |= PHY_Cap_1000_Full | PHY_Cap_1000_Half;
+ giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
if (duplex == DUPLEX_HALF)
- auto_nego &= ~(PHY_Cap_10_Full | PHY_Cap_100_Full);
+ auto_nego &= ~(ADVERTISE_10FULL | ADVERTISE_100FULL);
if (duplex == DUPLEX_FULL)
- auto_nego &= ~(PHY_Cap_10_Half | PHY_Cap_100_Half);
+ auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_100HALF);
/* This tweak comes straight from Realtek's driver. */
if ((speed == SPEED_100) && (duplex == DUPLEX_HALF) &&
(tp->mac_version == RTL_GIGA_MAC_VER_13)) {
- auto_nego = PHY_Cap_100_Half | 0x01;
+ auto_nego = ADVERTISE_100HALF | ADVERTISE_CSMA;
}
}
if ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
(tp->mac_version == RTL_GIGA_MAC_VER_14) ||
(tp->mac_version == RTL_GIGA_MAC_VER_15)) {
- if ((giga_ctrl & (PHY_Cap_1000_Full | PHY_Cap_1000_Half)) &&
+ if ((giga_ctrl & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)) &&
netif_msg_link(tp)) {
printk(KERN_INFO "%s: PHY does not support 1000Mbps.\n",
dev->name);
}
- giga_ctrl &= ~(PHY_Cap_1000_Full | PHY_Cap_1000_Half);
+ giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
}
auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
tp->phy_auto_nego_reg = auto_nego;
tp->phy_1000_ctrl_reg = giga_ctrl;
- mdio_write(ioaddr, PHY_AUTO_NEGO_REG, auto_nego);
- mdio_write(ioaddr, PHY_1000_CTRL_REG, giga_ctrl);
- mdio_write(ioaddr, PHY_CTRL_REG, PHY_Enable_Auto_Nego |
- PHY_Restart_Auto_Nego);
+ mdio_write(ioaddr, MII_ADVERTISE, auto_nego);
+ mdio_write(ioaddr, MII_CTRL1000, giga_ctrl);
+ mdio_write(ioaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
return 0;
}
ret = tp->set_speed(dev, autoneg, speed, duplex);
- if (netif_running(dev) && (tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full))
+ if (netif_running(dev) && (tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL))
mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT);
return ret;
spin_lock_irqsave(&tp->lock, flags);
ret = rtl8169_set_speed(dev, cmd->autoneg, cmd->speed, cmd->duplex);
spin_unlock_irqrestore(&tp->lock, flags);
-
+
return ret;
}
unsigned long flags;
spin_lock_irqsave(&tp->lock, flags);
- if (tp->vlgrp)
- tp->vlgrp->vlan_devices[vid] = NULL;
+ vlan_group_set_device(tp->vlgrp, vid, NULL);
spin_unlock_irqrestore(&tp->lock, flags);
}
SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_Autoneg |
- SUPPORTED_TP;
+ SUPPORTED_TP;
cmd->autoneg = 1;
cmd->advertising = ADVERTISED_TP | ADVERTISED_Autoneg;
- if (tp->phy_auto_nego_reg & PHY_Cap_10_Half)
+ if (tp->phy_auto_nego_reg & ADVERTISE_10HALF)
cmd->advertising |= ADVERTISED_10baseT_Half;
- if (tp->phy_auto_nego_reg & PHY_Cap_10_Full)
+ if (tp->phy_auto_nego_reg & ADVERTISE_10FULL)
cmd->advertising |= ADVERTISED_10baseT_Full;
- if (tp->phy_auto_nego_reg & PHY_Cap_100_Half)
+ if (tp->phy_auto_nego_reg & ADVERTISE_100HALF)
cmd->advertising |= ADVERTISED_100baseT_Half;
- if (tp->phy_auto_nego_reg & PHY_Cap_100_Full)
+ if (tp->phy_auto_nego_reg & ADVERTISE_100FULL)
cmd->advertising |= ADVERTISED_100baseT_Full;
- if (tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full)
+ if (tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL)
cmd->advertising |= ADVERTISED_1000baseT_Full;
status = RTL_R8(PHYstatus);
static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs,
void *p)
{
- struct rtl8169_private *tp = netdev_priv(dev);
- unsigned long flags;
+ struct rtl8169_private *tp = netdev_priv(dev);
+ unsigned long flags;
- if (regs->len > R8169_REGS_SIZE)
- regs->len = R8169_REGS_SIZE;
+ if (regs->len > R8169_REGS_SIZE)
+ regs->len = R8169_REGS_SIZE;
- spin_lock_irqsave(&tp->lock, flags);
- memcpy_fromio(p, tp->mmio_addr, regs->len);
- spin_unlock_irqrestore(&tp->lock, flags);
+ spin_lock_irqsave(&tp->lock, flags);
+ memcpy_fromio(p, tp->mmio_addr, regs->len);
+ spin_unlock_irqrestore(&tp->lock, flags);
}
static u32 rtl8169_get_msglevel(struct net_device *dev)
RTL_W32(CounterAddrLow, 0);
RTL_W32(CounterAddrHigh, 0);
- data[0] = le64_to_cpu(counters->tx_packets);
+ data[0] = le64_to_cpu(counters->tx_packets);
data[1] = le64_to_cpu(counters->rx_packets);
data[2] = le64_to_cpu(counters->tx_errors);
data[3] = le32_to_cpu(counters->rx_errors);
}
-static struct ethtool_ops rtl8169_ethtool_ops = {
+static const struct ethtool_ops rtl8169_ethtool_ops = {
.get_drvinfo = rtl8169_get_drvinfo,
.get_regs_len = rtl8169_get_regs_len,
.get_link = ethtool_op_get_link,
val = mdio_read(ioaddr, reg);
val = (bitval == 1) ?
val | (bitval << bitnum) : val & ~(0x0001 << bitnum);
- mdio_write(ioaddr, reg, val & 0xffff);
+ mdio_write(ioaddr, reg, val & 0xffff);
}
static void rtl8169_get_mac_version(struct rtl8169_private *tp, void __iomem *ioaddr)
{ 0x38000000, RTL_GIGA_MAC_VER_12 },
{ 0x34000000, RTL_GIGA_MAC_VER_13 },
{ 0x30800000, RTL_GIGA_MAC_VER_14 },
- { 0x30000000, RTL_GIGA_MAC_VER_11 },
+ { 0x30000000, RTL_GIGA_MAC_VER_11 },
{ 0x18000000, RTL_GIGA_MAC_VER_05 },
{ 0x10000000, RTL_GIGA_MAC_VER_04 },
{ 0x04000000, RTL_GIGA_MAC_VER_03 },
}, *p = phy_info;
u16 reg;
- reg = mdio_read(ioaddr, 3) & 0xffff;
+ reg = mdio_read(ioaddr, MII_PHYSID2) & 0xffff;
while ((reg & p->mask) != p->set)
p++;
tp->phy_version = p->phy_version;
/* Shazam ! */
if (tp->mac_version == RTL_GIGA_MAC_VER_04) {
- mdio_write(ioaddr, 31, 0x0001);
- mdio_write(ioaddr, 9, 0x273a);
- mdio_write(ioaddr, 14, 0x7bfb);
- mdio_write(ioaddr, 27, 0x841e);
-
mdio_write(ioaddr, 31, 0x0002);
mdio_write(ioaddr, 1, 0x90d0);
mdio_write(ioaddr, 31, 0x0000);
assert(tp->mac_version > RTL_GIGA_MAC_VER_01);
assert(tp->phy_version < RTL_GIGA_PHY_VER_H);
- if (!(tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full))
+ if (!(tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL))
return;
spin_lock_irq(&tp->lock);
if (tp->phy_reset_pending(ioaddr)) {
- /*
+ /*
* A busy loop could burn quite a few cycles on nowadays CPU.
* Let's delay the execution of the timer for a few ticks.
*/
(tp->phy_version >= RTL_GIGA_PHY_VER_H))
return;
- init_timer(timer);
- timer->expires = jiffies + RTL8169_PHY_TIMEOUT;
- timer->data = (unsigned long)(dev);
- timer->function = rtl8169_phy_timer;
- add_timer(timer);
+ mod_timer(timer, jiffies + RTL8169_PHY_TIMEOUT);
}
#ifdef CONFIG_NET_POLL_CONTROLLER
struct pci_dev *pdev = tp->pci_dev;
disable_irq(pdev->irq);
- rtl8169_interrupt(pdev->irq, dev, NULL);
+ rtl8169_interrupt(pdev->irq, dev);
enable_irq(pdev->irq);
}
#endif
-static void __rtl8169_set_mac_addr(struct net_device *dev, void __iomem *ioaddr)
-{
- unsigned int i, j;
-
- RTL_W8(Cfg9346, Cfg9346_Unlock);
- for (i = 0; i < 2; i++) {
- __le32 l = 0;
-
- for (j = 0; j < 4; j++) {
- l <<= 8;
- l |= dev->dev_addr[4*i + j];
- }
- RTL_W32(MAC0 + 4*i, cpu_to_be32(l));
- }
- RTL_W8(Cfg9346, Cfg9346_Lock);
-}
-
-static int rtl8169_set_mac_addr(struct net_device *dev, void *p)
-{
- struct rtl8169_private *tp = netdev_priv(dev);
- struct sockaddr *addr = p;
-
- if (!is_valid_ether_addr(addr->sa_data))
- return -EINVAL;
-
- memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-
- if (netif_running(dev)) {
- spin_lock_irq(&tp->lock);
- __rtl8169_set_mac_addr(dev, tp->mmio_addr);
- spin_unlock_irq(&tp->lock);
- }
- return 0;
-}
-
static void rtl8169_release_board(struct pci_dev *pdev, struct net_device *dev,
void __iomem *ioaddr)
{
free_netdev(dev);
}
+static void rtl8169_phy_reset(struct net_device *dev,
+ struct rtl8169_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+ int i;
+
+ tp->phy_reset_enable(ioaddr);
+ for (i = 0; i < 100; i++) {
+ if (!tp->phy_reset_pending(ioaddr))
+ return;
+ msleep(1);
+ }
+ if (netif_msg_link(tp))
+ printk(KERN_ERR "%s: PHY reset failed.\n", dev->name);
+}
+
static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
{
void __iomem *ioaddr = tp->mmio_addr;
rtl8169_link_option(board_idx, &autoneg, &speed, &duplex);
+ rtl8169_phy_reset(dev, tp);
+
rtl8169_set_speed(dev, autoneg, speed, duplex);
if ((RTL_R8(PHYstatus) & TBI_Enable) && netif_msg_link(tp))
printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name);
}
+static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ struct mii_ioctl_data *data = if_mii(ifr);
+
+ if (!netif_running(dev))
+ return -ENODEV;
+
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ data->phy_id = 32; /* Internal PHY */
+ return 0;
+
+ case SIOCGMIIREG:
+ data->val_out = mdio_read(tp->mmio_addr, data->reg_num & 0x1f);
+ return 0;
+
+ case SIOCSMIIREG:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ mdio_write(tp->mmio_addr, data->reg_num & 0x1f, data->val_in);
+ return 0;
+ }
+ return -EOPNOTSUPP;
+}
+
static int __devinit
rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct rtl8169_private *tp;
struct net_device *dev;
void __iomem *ioaddr;
- unsigned int i, pm_cap;
- int rc;
+ unsigned int pm_cap;
+ int i, rc;
if (netif_msg_drv(&debug)) {
printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n",
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
tp = netdev_priv(dev);
+ tp->dev = dev;
tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT);
/* enable device (incl. PCI PM wakeup and hotplug setup) */
RTL_W8(ChipCmd, CmdReset);
/* Check that the chip has finished the reset. */
- for (i = 1000; i > 0; i--) {
+ for (i = 100; i > 0; i--) {
if ((RTL_R8(ChipCmd) & CmdReset) == 0)
break;
- udelay(10);
+ msleep_interruptible(1);
}
/* Identify chip attached to board */
tp->phy_reset_pending = rtl8169_tbi_reset_pending;
tp->link_ok = rtl8169_tbi_link_ok;
- tp->phy_1000_ctrl_reg = PHY_Cap_1000_Full; /* Implied by TBI */
+ tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */
} else {
tp->set_speed = rtl8169_set_speed_xmii;
tp->get_settings = rtl8169_gset_xmii;
tp->phy_reset_enable = rtl8169_xmii_reset_enable;
tp->phy_reset_pending = rtl8169_xmii_reset_pending;
tp->link_ok = rtl8169_xmii_link_ok;
+
+ dev->do_ioctl = rtl8169_ioctl;
}
/* Get MAC address. FIXME: read EEPROM */
dev->stop = rtl8169_close;
dev->tx_timeout = rtl8169_tx_timeout;
dev->set_multicast_list = rtl8169_set_rx_mode;
- dev->set_mac_address = rtl8169_set_mac_addr;
dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
dev->irq = pdev->irq;
dev->base_addr = (unsigned long) ioaddr;
tp->mmio_addr = ioaddr;
tp->align = rtl_cfg_info[ent->driver_data].align;
+ init_timer(&tp->timer);
+ tp->timer.data = (unsigned long) dev;
+ tp->timer.function = rtl8169_phy_timer;
+
spin_lock_init(&tp->lock);
rc = register_netdev(dev);
assert(dev != NULL);
assert(tp != NULL);
+ flush_scheduled_work();
+
unregister_netdev(dev);
rtl8169_release_board(pdev, dev, tp->mmio_addr);
pci_set_drvdata(pdev, NULL);
{
struct rtl8169_private *tp = netdev_priv(dev);
struct pci_dev *pdev = tp->pci_dev;
- int retval;
-
- rtl8169_set_rxbufsize(tp, dev);
+ int retval = -ENOMEM;
- retval =
- request_irq(dev->irq, rtl8169_interrupt, IRQF_SHARED, dev->name, dev);
- if (retval < 0)
- goto out;
- retval = -ENOMEM;
+ rtl8169_set_rxbufsize(tp, dev);
/*
* Rx and Tx desscriptors needs 256 bytes alignment.
tp->TxDescArray = pci_alloc_consistent(pdev, R8169_TX_RING_BYTES,
&tp->TxPhyAddr);
if (!tp->TxDescArray)
- goto err_free_irq;
+ goto out;
tp->RxDescArray = pci_alloc_consistent(pdev, R8169_RX_RING_BYTES,
&tp->RxPhyAddr);
if (!tp->RxDescArray)
- goto err_free_tx;
+ goto err_free_tx_0;
retval = rtl8169_init_ring(dev);
if (retval < 0)
- goto err_free_rx;
+ goto err_free_rx_1;
- INIT_WORK(&tp->task, NULL, dev);
+ INIT_DELAYED_WORK(&tp->task, NULL);
+
+ smp_mb();
+
+ retval = request_irq(dev->irq, rtl8169_interrupt, IRQF_SHARED,
+ dev->name, dev);
+ if (retval < 0)
+ goto err_release_ring_2;
rtl8169_hw_start(dev);
out:
return retval;
-err_free_rx:
+err_release_ring_2:
+ rtl8169_rx_clear(tp);
+err_free_rx_1:
pci_free_consistent(pdev, R8169_RX_RING_BYTES, tp->RxDescArray,
tp->RxPhyAddr);
-err_free_tx:
+err_free_tx_0:
pci_free_consistent(pdev, R8169_TX_RING_BYTES, tp->TxDescArray,
tp->TxPhyAddr);
-err_free_irq:
- free_irq(dev->irq, dev);
goto out;
}
RTL_R8(ChipCmd);
}
-static void
-rtl8169_hw_start(struct net_device *dev)
+static void rtl8169_set_rx_tx_config_registers(struct rtl8169_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+ u32 cfg = rtl8169_rx_config;
+
+ cfg |= (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
+ RTL_W32(RxConfig, cfg);
+
+ /* Set DMA burst size and Interframe Gap Time */
+ RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
+ (InterFrameGap << TxInterFrameGapShift));
+}
+
+static void rtl8169_hw_start(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
struct pci_dev *pdev = tp->pci_dev;
+ u16 cmd;
u32 i;
/* Soft reset the chip. */
RTL_W8(ChipCmd, CmdReset);
/* Check that the chip has finished the reset. */
- for (i = 1000; i > 0; i--) {
+ for (i = 100; i > 0; i--) {
if ((RTL_R8(ChipCmd) & CmdReset) == 0)
break;
- udelay(10);
+ msleep_interruptible(1);
+ }
+
+ if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
+ RTL_W16(CPlusCmd, RTL_R16(CPlusCmd) | PCIMulRW);
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x08);
}
if (tp->mac_version == RTL_GIGA_MAC_VER_13) {
/* Undocumented stuff. */
if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
- u16 cmd;
-
/* Realtek's r1000_n.c driver uses '&& 0x01' here. Well... */
if ((RTL_R8(Config2) & 0x07) & 0x01)
RTL_W32(0x7c, 0x0007ffff);
pci_write_config_word(pdev, PCI_COMMAND, cmd);
}
-
RTL_W8(Cfg9346, Cfg9346_Unlock);
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_02) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_03) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_04))
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+
RTL_W8(EarlyTxThres, EarlyTxThld);
/* Low hurts. Let's disable the filtering. */
RTL_W16(RxMaxSize, 16383);
- /* Set Rx Config register */
- i = rtl8169_rx_config |
- (RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
- RTL_W32(RxConfig, i);
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_01) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_02) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_03) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_04))
+ rtl8169_set_rx_tx_config_registers(tp);
- /* Set DMA burst size and Interframe Gap Time */
- RTL_W32(TxConfig,
- (TX_DMA_BURST << TxDMAShift) | (InterFrameGap <<
- TxInterFrameGapShift));
+ cmd = RTL_R16(CPlusCmd);
+ RTL_W16(CPlusCmd, cmd);
- tp->cp_cmd |= RTL_R16(CPlusCmd) | PCIMulRW;
+ tp->cp_cmd |= cmd | PCIMulRW;
if ((tp->mac_version == RTL_GIGA_MAC_VER_02) ||
(tp->mac_version == RTL_GIGA_MAC_VER_03)) {
*/
RTL_W16(IntrMitigate, 0x0000);
- RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr & DMA_32BIT_MASK));
+ /*
+ * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
+ * register to be written before TxDescAddrLow to work.
+ * Switching from MMIO to I/O access fixes the issue as well.
+ */
RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr >> 32));
- RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr & DMA_32BIT_MASK));
+ RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr & DMA_32BIT_MASK));
RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr >> 32));
- RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+ RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr & DMA_32BIT_MASK));
+
+ if ((tp->mac_version != RTL_GIGA_MAC_VER_01) &&
+ (tp->mac_version != RTL_GIGA_MAC_VER_02) &&
+ (tp->mac_version != RTL_GIGA_MAC_VER_03) &&
+ (tp->mac_version != RTL_GIGA_MAC_VER_04)) {
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
+ rtl8169_set_rx_tx_config_registers(tp);
+ }
+
RTL_W8(Cfg9346, Cfg9346_Lock);
- udelay(10);
+
+ /* Initially a 10 us delay. Turned it into a PCI commit. - FR */
+ RTL_R8(IntrMask);
RTL_W32(RxMissed, 0);
/* Enable all known interrupts by setting the interrupt mask. */
RTL_W16(IntrMask, rtl8169_intr_mask);
- __rtl8169_set_mac_addr(dev, ioaddr);
-
netif_start_queue(dev);
}
if (!skb)
goto err_out;
- skb_reserve(skb, align);
+ skb_reserve(skb, (align - 1) & (unsigned long)skb->data);
*sk_buff = skb;
mapping = pci_map_single(pdev, skb->data, rx_buf_sz,
u32 start, u32 end)
{
u32 cur;
-
+
for (cur = start; end - cur > 0; cur++) {
int ret, i = cur % NUM_RX_DESC;
tp->cur_tx = tp->dirty_tx = 0;
}
-static void rtl8169_schedule_work(struct net_device *dev, void (*task)(void *))
+static void rtl8169_schedule_work(struct net_device *dev, work_func_t task)
{
struct rtl8169_private *tp = netdev_priv(dev);
- PREPARE_WORK(&tp->task, task, dev);
+ PREPARE_DELAYED_WORK(&tp->task, task);
schedule_delayed_work(&tp->task, 4);
}
netif_poll_enable(dev);
}
-static void rtl8169_reinit_task(void *_data)
+static void rtl8169_reinit_task(struct work_struct *work)
{
- struct net_device *dev = _data;
+ struct rtl8169_private *tp =
+ container_of(work, struct rtl8169_private, task.work);
+ struct net_device *dev = tp->dev;
int ret;
- if (netif_running(dev)) {
- rtl8169_wait_for_quiescence(dev);
- rtl8169_close(dev);
- }
+ rtnl_lock();
+
+ if (!netif_running(dev))
+ goto out_unlock;
+
+ rtl8169_wait_for_quiescence(dev);
+ rtl8169_close(dev);
ret = rtl8169_open(dev);
if (unlikely(ret < 0)) {
}
rtl8169_schedule_work(dev, rtl8169_reinit_task);
}
+
+out_unlock:
+ rtnl_unlock();
}
-static void rtl8169_reset_task(void *_data)
+static void rtl8169_reset_task(struct work_struct *work)
{
- struct net_device *dev = _data;
- struct rtl8169_private *tp = netdev_priv(dev);
+ struct rtl8169_private *tp =
+ container_of(work, struct rtl8169_private, task.work);
+ struct net_device *dev = tp->dev;
+
+ rtnl_lock();
if (!netif_running(dev))
- return;
+ goto out_unlock;
rtl8169_wait_for_quiescence(dev);
}
rtl8169_schedule_work(dev, rtl8169_reset_task);
}
+
+out_unlock:
+ rtnl_unlock();
}
static void rtl8169_tx_timeout(struct net_device *dev)
if (mss)
return LargeSend | ((mss & MSSMask) << MSSShift);
}
- if (skb->ip_summed == CHECKSUM_HW) {
- const struct iphdr *ip = skb->nh.iph;
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ const struct iphdr *ip = ip_hdr(skb);
if (ip->protocol == IPPROTO_TCP)
return IPCS | TCPCS;
u32 status, len;
u32 opts1;
int ret = NETDEV_TX_OK;
-
+
if (unlikely(TX_BUFFS_AVAIL(tp) < skb_shinfo(skb)->nr_frags)) {
if (netif_msg_drv(tp)) {
printk(KERN_ERR
/*
* The recovery sequence below admits a very elaborated explanation:
* - it seems to work;
- * - I did not see what else could be done.
+ * - I did not see what else could be done;
+ * - it makes iop3xx happy.
*
* Feel free to adjust to your needs.
*/
- pci_write_config_word(pdev, PCI_COMMAND,
- pci_cmd | PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
+ if (pdev->broken_parity_status)
+ pci_cmd &= ~PCI_COMMAND_PARITY;
+ else
+ pci_cmd |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY;
+
+ pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
pci_write_config_word(pdev, PCI_STATUS,
pci_status & (PCI_STATUS_DETECTED_PARITY |
tp->cp_cmd &= ~PCIDAC;
RTL_W16(CPlusCmd, tp->cp_cmd);
dev->features &= ~NETIF_F_HIGHDMA;
- rtl8169_schedule_work(dev, rtl8169_reinit_task);
}
rtl8169_hw_reset(ioaddr);
+
+ rtl8169_schedule_work(dev, rtl8169_reinit_task);
}
static void
skb = dev_alloc_skb(pkt_size + align);
if (skb) {
- skb_reserve(skb, align);
+ skb_reserve(skb, (align - 1) & (unsigned long)skb->data);
eth_copy_and_sum(skb, sk_buff[0]->data, pkt_size, 0);
*sk_buff = skb;
rtl8169_mark_to_asic(desc, rx_buf_sz);
pci_action(tp->pci_dev, le64_to_cpu(desc->addr),
tp->rx_buf_sz, PCI_DMA_FROMDEVICE);
- skb->dev = dev;
skb_put(skb, pkt_size);
skb->protocol = eth_type_trans(skb, dev);
/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */
static irqreturn_t
-rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+rtl8169_interrupt(int irq, void *dev_instance)
{
struct net_device *dev = (struct net_device *) dev_instance;
struct rtl8169_private *tp = netdev_priv(dev);
__netif_rx_schedule(dev);
else if (netif_msg_intr(tp)) {
printk(KERN_INFO "%s: interrupt %04x taken in poll\n",
- dev->name, status);
+ dev->name, status);
}
break;
#else
struct rtl8169_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
unsigned int poll_locked = 0;
+ unsigned int intrmask;
rtl8169_delete_timer(dev);
netif_stop_queue(dev);
- flush_scheduled_work();
-
core_down:
spin_lock_irq(&tp->lock);
* 2) dev->change_mtu
* -> rtl8169_poll can not be issued again and re-enable the
* interruptions. Let's simply issue the IRQ down sequence again.
+ *
+ * No loop if hotpluged or major error (0xffff).
*/
- if (RTL_R16(IntrMask))
+ intrmask = RTL_R16(IntrMask);
+ if (intrmask && (intrmask != 0xffff))
goto core_down;
rtl8169_tx_clear(tp);
RTL_W32(RxMissed, 0);
spin_unlock_irqrestore(&tp->lock, flags);
}
-
+
return &tp->stats;
}
void __iomem *ioaddr = tp->mmio_addr;
if (!netif_running(dev))
- goto out;
+ goto out_pci_suspend;
netif_device_detach(dev);
netif_stop_queue(dev);
spin_unlock_irq(&tp->lock);
+out_pci_suspend:
pci_save_state(pdev);
pci_enable_wake(pdev, pci_choose_state(pdev, state), tp->wol_enabled);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
-out:
+
return 0;
}
{
struct net_device *dev = pci_get_drvdata(pdev);
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ pci_enable_wake(pdev, PCI_D0, 0);
+
if (!netif_running(dev))
goto out;
netif_device_attach(dev);
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
- pci_enable_wake(pdev, PCI_D0, 0);
-
rtl8169_schedule_work(dev, rtl8169_reset_task);
out:
return 0;
static int __init
rtl8169_init_module(void)
{
- return pci_module_init(&rtl8169_pci_driver);
+ return pci_register_driver(&rtl8169_pci_driver);
}
static void __exit