MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
MODULE_DESCRIPTION("Xircom CBE-100 ethernet driver");
MODULE_LICENSE("GPL v2");
+MODULE_VERSION(DRV_VERSION);
MODULE_PARM(debug, "i");
MODULE_PARM(max_interrupt_work, "i");
int saved_if_port;
struct pci_dev *pdev;
spinlock_t lock;
+#ifdef CONFIG_PM
+ u32 pci_state[16];
+#endif
};
static int mdio_read(struct net_device *dev, int phy_id, int location);
static int xircom_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void set_rx_mode(struct net_device *dev);
static void check_duplex(struct net_device *dev);
-static struct ethtool_ops ops;
/* The Xircom cards are picky about when certain bits in CSR6 can be
*/
static void find_mii_transceivers(struct net_device *dev)
{
- struct xircom_private *tp = netdev_priv(dev);
+ struct xircom_private *tp = dev->priv;
int phy, phy_idx;
if (media_cap[tp->default_port] & MediaIsMII) {
*/
static void transceiver_voodoo(struct net_device *dev)
{
- struct xircom_private *tp = netdev_priv(dev);
+ struct xircom_private *tp = dev->priv;
long ioaddr = dev->base_addr;
/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
/* Clear the missed-packet counter. */
(volatile int)inl(ioaddr + CSR8);
- tp = netdev_priv(dev);
+ tp = dev->priv;
- spin_lock_init(&tp->lock);
+ tp->lock = SPIN_LOCK_UNLOCKED;
tp->pdev = pdev;
tp->chip_id = chip_idx;
/* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles. */
#endif
dev->tx_timeout = xircom_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
- SET_ETHTOOL_OPS(dev, &ops);
transceiver_voodoo(dev);
static void
xircom_up(struct net_device *dev)
{
- struct xircom_private *tp = netdev_priv(dev);
+ struct xircom_private *tp = dev->priv;
long ioaddr = dev->base_addr;
int i;
static int
xircom_open(struct net_device *dev)
{
- struct xircom_private *tp = netdev_priv(dev);
+ struct xircom_private *tp = dev->priv;
if (request_irq(dev->irq, &xircom_interrupt, SA_SHIRQ, dev->name, dev))
return -EAGAIN;
static void xircom_tx_timeout(struct net_device *dev)
{
- struct xircom_private *tp = netdev_priv(dev);
+ struct xircom_private *tp = dev->priv;
long ioaddr = dev->base_addr;
if (media_cap[dev->if_port] & MediaIsMII) {
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
static void xircom_init_ring(struct net_device *dev)
{
- struct xircom_private *tp = netdev_priv(dev);
+ struct xircom_private *tp = dev->priv;
int i;
tp->tx_full = 0;
static int
xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct xircom_private *tp = netdev_priv(dev);
+ struct xircom_private *tp = dev->priv;
int entry;
u32 flag;
static void xircom_media_change(struct net_device *dev)
{
- struct xircom_private *tp = netdev_priv(dev);
+ struct xircom_private *tp = dev->priv;
long ioaddr = dev->base_addr;
u16 reg0, reg1, reg4, reg5;
u32 csr6 = inl(ioaddr + CSR6), newcsr6;
static void check_duplex(struct net_device *dev)
{
- struct xircom_private *tp = netdev_priv(dev);
+ struct xircom_private *tp = dev->priv;
u16 reg0;
mdio_write(dev, tp->phys[0], MII_BMCR, BMCR_RESET);
static irqreturn_t xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
{
struct net_device *dev = dev_instance;
- struct xircom_private *tp = netdev_priv(dev);
+ struct xircom_private *tp = dev->priv;
long ioaddr = dev->base_addr;
int csr5, work_budget = max_interrupt_work;
int handled = 0;
static int
xircom_rx(struct net_device *dev)
{
- struct xircom_private *tp = netdev_priv(dev);
+ struct xircom_private *tp = dev->priv;
int entry = tp->cur_rx % RX_RING_SIZE;
int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
int work_done = 0;
xircom_down(struct net_device *dev)
{
long ioaddr = dev->base_addr;
- struct xircom_private *tp = netdev_priv(dev);
+ struct xircom_private *tp = dev->priv;
/* Disable interrupts by clearing the interrupt mask. */
outl(0, ioaddr + CSR7);
xircom_close(struct net_device *dev)
{
long ioaddr = dev->base_addr;
- struct xircom_private *tp = netdev_priv(dev);
+ struct xircom_private *tp = dev->priv;
int i;
if (xircom_debug > 1)
static struct net_device_stats *xircom_get_stats(struct net_device *dev)
{
- struct xircom_private *tp = netdev_priv(dev);
+ struct xircom_private *tp = dev->priv;
long ioaddr = dev->base_addr;
if (netif_device_present(dev))
return &tp->stats;
}
-static int xircom_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
+
+static int xircom_ethtool_ioctl(struct net_device *dev, void __user *useraddr)
{
- struct xircom_private *tp = netdev_priv(dev);
- ecmd->supported =
+ struct ethtool_cmd ecmd;
+ struct xircom_private *tp = dev->priv;
+
+ if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+ return -EFAULT;
+
+ switch (ecmd.cmd) {
+ case ETHTOOL_GSET:
+ ecmd.supported =
SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_Autoneg |
SUPPORTED_MII;
- ecmd->advertising = ADVERTISED_MII;
- if (tp->advertising[0] & ADVERTISE_10HALF)
- ecmd->advertising |= ADVERTISED_10baseT_Half;
- if (tp->advertising[0] & ADVERTISE_10FULL)
- ecmd->advertising |= ADVERTISED_10baseT_Full;
- if (tp->advertising[0] & ADVERTISE_100HALF)
- ecmd->advertising |= ADVERTISED_100baseT_Half;
- if (tp->advertising[0] & ADVERTISE_100FULL)
- ecmd->advertising |= ADVERTISED_100baseT_Full;
- if (tp->autoneg) {
- ecmd->advertising |= ADVERTISED_Autoneg;
- ecmd->autoneg = AUTONEG_ENABLE;
- } else
- ecmd->autoneg = AUTONEG_DISABLE;
-
- ecmd->port = PORT_MII;
- ecmd->transceiver = XCVR_INTERNAL;
- ecmd->phy_address = tp->phys[0];
- ecmd->speed = tp->speed100 ? SPEED_100 : SPEED_10;
- ecmd->duplex = tp->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
- ecmd->maxtxpkt = TX_RING_SIZE / 2;
- ecmd->maxrxpkt = 0;
- return 0;
-}
+ ecmd.advertising = ADVERTISED_MII;
+ if (tp->advertising[0] & ADVERTISE_10HALF)
+ ecmd.advertising |= ADVERTISED_10baseT_Half;
+ if (tp->advertising[0] & ADVERTISE_10FULL)
+ ecmd.advertising |= ADVERTISED_10baseT_Full;
+ if (tp->advertising[0] & ADVERTISE_100HALF)
+ ecmd.advertising |= ADVERTISED_100baseT_Half;
+ if (tp->advertising[0] & ADVERTISE_100FULL)
+ ecmd.advertising |= ADVERTISED_100baseT_Full;
+ if (tp->autoneg) {
+ ecmd.advertising |= ADVERTISED_Autoneg;
+ ecmd.autoneg = AUTONEG_ENABLE;
+ } else
+ ecmd.autoneg = AUTONEG_DISABLE;
+
+ ecmd.port = PORT_MII;
+ ecmd.transceiver = XCVR_INTERNAL;
+ ecmd.phy_address = tp->phys[0];
+ ecmd.speed = tp->speed100 ? SPEED_100 : SPEED_10;
+ ecmd.duplex = tp->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+ ecmd.maxtxpkt = TX_RING_SIZE / 2;
+ ecmd.maxrxpkt = 0;
+
+ if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+ return -EFAULT;
+ return 0;
-static int xircom_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
-{
- struct xircom_private *tp = netdev_priv(dev);
- u16 autoneg, speed100, full_duplex;
-
- autoneg = (ecmd->autoneg == AUTONEG_ENABLE);
- speed100 = (ecmd->speed == SPEED_100);
- full_duplex = (ecmd->duplex == DUPLEX_FULL);
-
- tp->autoneg = autoneg;
- if (speed100 != tp->speed100 ||
- full_duplex != tp->full_duplex) {
- tp->speed100 = speed100;
- tp->full_duplex = full_duplex;
- /* change advertising bits */
- tp->advertising[0] &= ~(ADVERTISE_10HALF |
- ADVERTISE_10FULL |
- ADVERTISE_100HALF |
- ADVERTISE_100FULL |
- ADVERTISE_100BASE4);
- if (speed100) {
- if (full_duplex)
- tp->advertising[0] |= ADVERTISE_100FULL;
- else
- tp->advertising[0] |= ADVERTISE_100HALF;
- } else {
- if (full_duplex)
- tp->advertising[0] |= ADVERTISE_10FULL;
- else
- tp->advertising[0] |= ADVERTISE_10HALF;
+ case ETHTOOL_SSET: {
+ u16 autoneg, speed100, full_duplex;
+
+ autoneg = (ecmd.autoneg == AUTONEG_ENABLE);
+ speed100 = (ecmd.speed == SPEED_100);
+ full_duplex = (ecmd.duplex == DUPLEX_FULL);
+
+ tp->autoneg = autoneg;
+ if (speed100 != tp->speed100 ||
+ full_duplex != tp->full_duplex) {
+ tp->speed100 = speed100;
+ tp->full_duplex = full_duplex;
+ /* change advertising bits */
+ tp->advertising[0] &= ~(ADVERTISE_10HALF |
+ ADVERTISE_10FULL |
+ ADVERTISE_100HALF |
+ ADVERTISE_100FULL |
+ ADVERTISE_100BASE4);
+ if (speed100) {
+ if (full_duplex)
+ tp->advertising[0] |= ADVERTISE_100FULL;
+ else
+ tp->advertising[0] |= ADVERTISE_100HALF;
+ } else {
+ if (full_duplex)
+ tp->advertising[0] |= ADVERTISE_10FULL;
+ else
+ tp->advertising[0] |= ADVERTISE_10HALF;
+ }
}
+ check_duplex(dev);
+ return 0;
}
- check_duplex(dev);
- return 0;
-}
-static void xircom_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
-{
- struct xircom_private *tp = netdev_priv(dev);
- strcpy(info->driver, DRV_NAME);
- strcpy(info->version, DRV_VERSION);
- strcpy(info->bus_info, pci_name(tp->pdev));
+ case ETHTOOL_GDRVINFO: {
+ struct ethtool_drvinfo info;
+ memset(&info, 0, sizeof(info));
+ info.cmd = ecmd.cmd;
+ strcpy(info.driver, DRV_NAME);
+ strcpy(info.version, DRV_VERSION);
+ *info.fw_version = 0;
+ strcpy(info.bus_info, pci_name(tp->pdev));
+ if (copy_to_user(useraddr, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+
+ default:
+ return -EOPNOTSUPP;
+ }
}
-static struct ethtool_ops ops = {
- .get_settings = xircom_get_settings,
- .set_settings = xircom_set_settings,
- .get_drvinfo = xircom_get_drvinfo,
-};
/* Provide ioctl() calls to examine the MII xcvr state. */
static int xircom_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
- struct xircom_private *tp = netdev_priv(dev);
+ struct xircom_private *tp = dev->priv;
u16 *data = (u16 *)&rq->ifr_ifru;
int phy = tp->phys[0] & 0x1f;
unsigned long flags;
switch(cmd) {
+ case SIOCETHTOOL:
+ return xircom_ethtool_ioctl(dev, rq->ifr_data);
+
/* Legacy mii-diag interface */
case SIOCGMIIPHY: /* Get address of MII PHY in use. */
if (tp->mii_cnt)
when re-entered but still correct. */
static void set_rx_mode(struct net_device *dev)
{
- struct xircom_private *tp = netdev_priv(dev);
+ struct xircom_private *tp = dev->priv;
struct dev_mc_list *mclist;
long ioaddr = dev->base_addr;
int csr6 = inl(ioaddr + CSR6);
static int xircom_suspend(struct pci_dev *pdev, u32 state)
{
struct net_device *dev = pci_get_drvdata(pdev);
- struct xircom_private *tp = netdev_priv(dev);
+ struct xircom_private *tp = dev->priv;
printk(KERN_INFO "xircom_suspend(%s)\n", dev->name);
if (tp->open)
xircom_down(dev);
- pci_save_state(pdev);
+ pci_save_state(pdev, tp->pci_state);
pci_disable_device(pdev);
pci_set_power_state(pdev, 3);
static int xircom_resume(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
- struct xircom_private *tp = netdev_priv(dev);
+ struct xircom_private *tp = dev->priv;
printk(KERN_INFO "xircom_resume(%s)\n", dev->name);
pci_set_power_state(pdev,0);
pci_enable_device(pdev);
- pci_restore_state(pdev);
+ pci_restore_state(pdev, tp->pci_state);
/* Bring the chip out of sleep mode.
Caution: Snooze mode does not work with some boards! */