#include "skge.h"
#define DRV_NAME "skge"
-#define DRV_VERSION "1.2"
+#define DRV_VERSION "1.3"
#define PFX DRV_NAME " "
#define DEFAULT_TX_RING_SIZE 128
static int skge_up(struct net_device *dev);
static int skge_down(struct net_device *dev);
+static void skge_phy_reset(struct skge_port *skge);
static void skge_tx_clean(struct skge_port *skge);
static int xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
static int gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
static void genesis_get_stats(struct skge_port *skge, u64 *data);
static void yukon_get_stats(struct skge_port *skge, u64 *data);
static void yukon_init(struct skge_hw *hw, int port);
-static void yukon_reset(struct skge_hw *hw, int port);
static void genesis_mac_init(struct skge_hw *hw, int port);
-static void genesis_reset(struct skge_hw *hw, int port);
static void genesis_link_up(struct skge_port *skge);
/* Avoid conditionals by using array */
skge->autoneg = ecmd->autoneg;
skge->advertising = ecmd->advertising;
- if (netif_running(dev)) {
- skge_down(dev);
- skge_up(dev);
- }
+ if (netif_running(dev))
+ skge_phy_reset(skge);
+
return (0);
}
struct ethtool_ringparam *p)
{
struct skge_port *skge = netdev_priv(dev);
+ int err;
if (p->rx_pending == 0 || p->rx_pending > MAX_RX_RING_SIZE ||
p->tx_pending == 0 || p->tx_pending > MAX_TX_RING_SIZE)
if (netif_running(dev)) {
skge_down(dev);
- skge_up(dev);
+ err = skge_up(dev);
+ if (err)
+ dev_close(dev);
+ else
+ dev->set_multicast_list(dev);
}
return 0;
static int skge_nway_reset(struct net_device *dev)
{
struct skge_port *skge = netdev_priv(dev);
- struct skge_hw *hw = skge->hw;
- int port = skge->port;
if (skge->autoneg != AUTONEG_ENABLE || !netif_running(dev))
return -EINVAL;
- spin_lock_bh(&hw->phy_lock);
- if (hw->chip_id == CHIP_ID_GENESIS) {
- genesis_reset(hw, port);
- genesis_mac_init(hw, port);
- } else {
- yukon_reset(hw, port);
- yukon_init(hw, port);
- }
- spin_unlock_bh(&hw->phy_lock);
+ skge_phy_reset(skge);
return 0;
}
else
skge->flow_control = FLOW_MODE_NONE;
- if (netif_running(dev)) {
- skge_down(dev);
- skge_up(dev);
- }
+ if (netif_running(dev))
+ skge_phy_reset(skge);
return 0;
}
}
- yukon_reset(hw, port);
skge_link_down(skge);
yukon_init(hw, port);
/* XXX restart autonegotiation? */
}
+static void skge_phy_reset(struct skge_port *skge)
+{
+ struct skge_hw *hw = skge->hw;
+ int port = skge->port;
+
+ netif_stop_queue(skge->netdev);
+ netif_carrier_off(skge->netdev);
+
+ spin_lock_bh(&hw->phy_lock);
+ if (hw->chip_id == CHIP_ID_GENESIS)
+ genesis_mac_init(hw, port);
+ else
+ yukon_init(hw, port);
+ spin_unlock_bh(&hw->phy_lock);
+}
+
/* Basic MII support */
static int skge_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
kfree(skge->rx_ring.start);
free_pci_mem:
pci_free_consistent(hw->pdev, skge->mem_size, skge->mem, skge->dma);
+ skge->mem = NULL;
return err;
}
struct skge_hw *hw = skge->hw;
int port = skge->port;
+ if (skge->mem == NULL)
+ return 0;
+
if (netif_msg_ifdown(skge))
printk(KERN_INFO PFX "%s: disabling interface\n", dev->name);
kfree(skge->rx_ring.start);
kfree(skge->tx_ring.start);
pci_free_consistent(hw->pdev, skge->mem_size, skge->mem, skge->dma);
+ skge->mem = NULL;
return 0;
}
static int skge_change_mtu(struct net_device *dev, int new_mtu)
{
- int err = 0;
- int running = netif_running(dev);
+ int err;
if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
return -EINVAL;
+ if (!netif_running(dev)) {
+ dev->mtu = new_mtu;
+ return 0;
+ }
+
+ skge_down(dev);
- if (running)
- skge_down(dev);
dev->mtu = new_mtu;
- if (running)
- skge_up(dev);
+
+ err = skge_up(dev);
+ if (err)
+ dev_close(dev);
return err;
}
struct net_device *dev = hw->dev[i];
if (dev) {
netif_device_attach(dev);
- if (netif_running(dev))
- skge_up(dev);
+ if (netif_running(dev) && skge_up(dev))
+ dev_close(dev);
}
}
return 0;