X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fnet%2Fskge.c;h=6d62250fba07944fab02a67dc9b93dc6fcdf36de;hb=cc1bf182bb8451a036a7c227f0a95a0416c4736e;hp=21afe108d3cb3908efd888650104a09a0b3b4d46;hpb=bc95f3669f5e6f63cf0b84fe4922c3c6dd4aa775;p=linux-2.6 diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 21afe108d3..6d62250fba 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -36,13 +36,15 @@ #include #include #include +#include +#include #include #include #include "skge.h" #define DRV_NAME "skge" -#define DRV_VERSION "1.11" +#define DRV_VERSION "1.12" #define PFX DRV_NAME " " #define DEFAULT_TX_RING_SIZE 128 @@ -57,7 +59,10 @@ #define TX_WATCHDOG (5 * HZ) #define NAPI_WEIGHT 64 #define BLINK_MS 250 -#define LINK_HZ (HZ/2) +#define LINK_HZ HZ + +#define SKGE_EEPROM_MAGIC 0x9933aabb + MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver"); MODULE_AUTHOR("Stephen Hemminger "); @@ -135,10 +140,13 @@ static void skge_get_regs(struct net_device *dev, struct ethtool_regs *regs, /* Wake on Lan only supported on Yukon chips with rev 1 or above */ static u32 wol_supported(const struct skge_hw *hw) { - if (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev != 0) - return WAKE_MAGIC | WAKE_PHY; - else + if (hw->chip_id == CHIP_ID_GENESIS) return 0; + + if (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0) + return 0; + + return WAKE_MAGIC | WAKE_PHY; } static u32 pci_wake_enabled(struct pci_dev *dev) @@ -407,9 +415,14 @@ static const struct skge_stat { { "rx_fcs_error", XM_RXF_FCS_ERR, GM_RXF_FCS_ERR }, }; -static int skge_get_stats_count(struct net_device *dev) +static int skge_get_sset_count(struct net_device *dev, int sset) { - return ARRAY_SIZE(skge_stats); + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(skge_stats); + default: + return -EOPNOTSUPP; + } } static void skge_get_ethtool_stats(struct net_device *dev, @@ -437,15 +450,15 @@ static struct net_device_stats *skge_get_stats(struct net_device *dev) else yukon_get_stats(skge, data); - skge->net_stats.tx_bytes = data[0]; - skge->net_stats.rx_bytes = data[1]; - skge->net_stats.tx_packets = data[2] + data[4] + data[6]; - skge->net_stats.rx_packets = data[3] + data[5] + data[7]; - skge->net_stats.multicast = data[3] + data[5]; - skge->net_stats.collisions = data[10]; - skge->net_stats.tx_aborted_errors = data[12]; + dev->stats.tx_bytes = data[0]; + dev->stats.rx_bytes = data[1]; + dev->stats.tx_packets = data[2] + data[4] + data[6]; + dev->stats.rx_packets = data[3] + data[5] + data[7]; + dev->stats.multicast = data[3] + data[5]; + dev->stats.collisions = data[10]; + dev->stats.tx_aborted_errors = data[12]; - return &skge->net_stats; + return &dev->stats; } static void skge_get_strings(struct net_device *dev, u32 stringset, u8 *data) @@ -790,6 +803,98 @@ static int skge_phys_id(struct net_device *dev, u32 data) return 0; } +static int skge_get_eeprom_len(struct net_device *dev) +{ + struct skge_port *skge = netdev_priv(dev); + u32 reg2; + + pci_read_config_dword(skge->hw->pdev, PCI_DEV_REG2, ®2); + return 1 << ( ((reg2 & PCI_VPD_ROM_SZ) >> 14) + 8); +} + +static u32 skge_vpd_read(struct pci_dev *pdev, int cap, u16 offset) +{ + u32 val; + + pci_write_config_word(pdev, cap + PCI_VPD_ADDR, offset); + + do { + pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset); + } while (!(offset & PCI_VPD_ADDR_F)); + + pci_read_config_dword(pdev, cap + PCI_VPD_DATA, &val); + return val; +} + +static void skge_vpd_write(struct pci_dev *pdev, int cap, u16 offset, u32 val) +{ + pci_write_config_dword(pdev, cap + PCI_VPD_DATA, val); + pci_write_config_word(pdev, cap + PCI_VPD_ADDR, + offset | PCI_VPD_ADDR_F); + + do { + pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset); + } while (offset & PCI_VPD_ADDR_F); +} + +static int skge_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, + u8 *data) +{ + struct skge_port *skge = netdev_priv(dev); + struct pci_dev *pdev = skge->hw->pdev; + int cap = pci_find_capability(pdev, PCI_CAP_ID_VPD); + int length = eeprom->len; + u16 offset = eeprom->offset; + + if (!cap) + return -EINVAL; + + eeprom->magic = SKGE_EEPROM_MAGIC; + + while (length > 0) { + u32 val = skge_vpd_read(pdev, cap, offset); + int n = min_t(int, length, sizeof(val)); + + memcpy(data, &val, n); + length -= n; + data += n; + offset += n; + } + return 0; +} + +static int skge_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, + u8 *data) +{ + struct skge_port *skge = netdev_priv(dev); + struct pci_dev *pdev = skge->hw->pdev; + int cap = pci_find_capability(pdev, PCI_CAP_ID_VPD); + int length = eeprom->len; + u16 offset = eeprom->offset; + + if (!cap) + return -EINVAL; + + if (eeprom->magic != SKGE_EEPROM_MAGIC) + return -EINVAL; + + while (length > 0) { + u32 val; + int n = min_t(int, length, sizeof(val)); + + if (n < sizeof(val)) + val = skge_vpd_read(pdev, cap, offset); + memcpy(&val, data, n); + + skge_vpd_write(pdev, cap, offset, val); + + length -= n; + data += n; + offset += n; + } + return 0; +} + static const struct ethtool_ops skge_ethtool_ops = { .get_settings = skge_get_settings, .set_settings = skge_set_settings, @@ -802,23 +907,23 @@ static const struct ethtool_ops skge_ethtool_ops = { .set_msglevel = skge_set_msglevel, .nway_reset = skge_nway_reset, .get_link = ethtool_op_get_link, + .get_eeprom_len = skge_get_eeprom_len, + .get_eeprom = skge_get_eeprom, + .set_eeprom = skge_set_eeprom, .get_ringparam = skge_get_ring_param, .set_ringparam = skge_set_ring_param, .get_pauseparam = skge_get_pauseparam, .set_pauseparam = skge_set_pauseparam, .get_coalesce = skge_get_coalesce, .set_coalesce = skge_set_coalesce, - .get_sg = ethtool_op_get_sg, .set_sg = skge_set_sg, - .get_tx_csum = ethtool_op_get_tx_csum, .set_tx_csum = skge_set_tx_csum, .get_rx_csum = skge_get_rx_csum, .set_rx_csum = skge_set_rx_csum, .get_strings = skge_get_strings, .phys_id = skge_phys_id, - .get_stats_count = skge_get_stats_count, + .get_sset_count = skge_get_sset_count, .get_ethtool_stats = skge_get_ethtool_stats, - .get_perm_addr = ethtool_op_get_perm_addr, }; /* @@ -990,19 +1095,15 @@ static void xm_link_down(struct skge_hw *hw, int port) { struct net_device *dev = hw->dev[port]; struct skge_port *skge = netdev_priv(dev); - u16 cmd, msk; + u16 cmd = xm_read16(hw, port, XM_MMU_CMD); - if (hw->phy_type == SK_PHY_XMAC) { - msk = xm_read16(hw, port, XM_IMSK); - msk |= XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE | XM_IS_AND; - xm_write16(hw, port, XM_IMSK, msk); - } + xm_write16(hw, port, XM_IMSK, XM_IMSK_DISABLE); - cmd = xm_read16(hw, port, XM_MMU_CMD); cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); xm_write16(hw, port, XM_MMU_CMD, cmd); + /* dummy read to ensure writing */ - (void) xm_read16(hw, port, XM_MMU_CMD); + xm_read16(hw, port, XM_MMU_CMD); if (netif_carrier_ok(dev)) skge_link_down(skge); @@ -1098,7 +1199,7 @@ static void genesis_reset(struct skge_hw *hw, int port) /* reset the statistics module */ xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT); - xm_write16(hw, port, XM_IMSK, 0xffff); /* disable XMAC IRQs */ + xm_write16(hw, port, XM_IMSK, XM_IMSK_DISABLE); xm_write32(hw, port, XM_MODE, 0); /* clear Mode Reg */ xm_write16(hw, port, XM_TX_CMD, 0); /* reset TX CMD Reg */ xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */ @@ -1136,7 +1237,7 @@ static void bcom_check_link(struct skge_hw *hw, int port) u16 status; /* read twice because of latch */ - (void) xm_phy_read(hw, port, PHY_BCOM_STAT); + xm_phy_read(hw, port, PHY_BCOM_STAT); status = xm_phy_read(hw, port, PHY_BCOM_STAT); if ((status & PHY_ST_LSYNC) == 0) { @@ -1337,7 +1438,7 @@ static void xm_phy_init(struct skge_port *skge) mod_timer(&skge->link_timer, jiffies + LINK_HZ); } -static void xm_check_link(struct net_device *dev) +static int xm_check_link(struct net_device *dev) { struct skge_port *skge = netdev_priv(dev); struct skge_hw *hw = skge->hw; @@ -1345,25 +1446,25 @@ static void xm_check_link(struct net_device *dev) u16 status; /* read twice because of latch */ - (void) xm_phy_read(hw, port, PHY_XMAC_STAT); + xm_phy_read(hw, port, PHY_XMAC_STAT); status = xm_phy_read(hw, port, PHY_XMAC_STAT); if ((status & PHY_ST_LSYNC) == 0) { xm_link_down(hw, port); - return; + return 0; } if (skge->autoneg == AUTONEG_ENABLE) { u16 lpa, res; if (!(status & PHY_ST_AN_OVER)) - return; + return 0; lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP); if (lpa & PHY_B_AN_RF) { printk(KERN_NOTICE PFX "%s: remote fault\n", dev->name); - return; + return 0; } res = xm_phy_read(hw, port, PHY_XMAC_RES_ABI); @@ -1379,7 +1480,7 @@ static void xm_check_link(struct net_device *dev) default: printk(KERN_NOTICE PFX "%s: duplex mismatch\n", dev->name); - return; + return 0; } /* We are using IEEE 802.3z/D5.0 Table 37-4 */ @@ -1403,11 +1504,14 @@ static void xm_check_link(struct net_device *dev) if (!netif_carrier_ok(dev)) genesis_link_up(skge); + return 1; } /* Poll to check for link coming up. + * * Since internal PHY is wired to a level triggered pin, can't - * get an interrupt when carrier is detected. + * get an interrupt when carrier is detected, need to poll for + * link coming up. */ static void xm_link_timer(unsigned long arg) { @@ -1415,29 +1519,35 @@ static void xm_link_timer(unsigned long arg) struct net_device *dev = skge->netdev; struct skge_hw *hw = skge->hw; int port = skge->port; + int i; + unsigned long flags; if (!netif_running(dev)) return; - if (netif_carrier_ok(dev)) { + spin_lock_irqsave(&hw->phy_lock, flags); + + /* + * Verify that the link by checking GPIO register three times. + * This pin has the signal from the link_sync pin connected to it. + */ + for (i = 0; i < 3; i++) { + if (xm_read16(hw, port, XM_GP_PORT) & XM_GP_INP_ASS) + goto link_down; + } + + /* Re-enable interrupt to detect link down */ + if (xm_check_link(dev)) { + u16 msk = xm_read16(hw, port, XM_IMSK); + msk &= ~XM_IS_INP_ASS; + xm_write16(hw, port, XM_IMSK, msk); xm_read16(hw, port, XM_ISRC); - if (!(xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS)) - goto nochange; } else { - if (xm_read32(hw, port, XM_GP_PORT) & XM_GP_INP_ASS) - goto nochange; - xm_read16(hw, port, XM_ISRC); - if (xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS) - goto nochange; +link_down: + mod_timer(&skge->link_timer, + round_jiffies(jiffies + LINK_HZ)); } - - spin_lock(&hw->phy_lock); - xm_check_link(dev); - spin_unlock(&hw->phy_lock); - -nochange: - if (netif_running(dev)) - mod_timer(&skge->link_timer, jiffies + LINK_HZ); + spin_unlock_irqrestore(&hw->phy_lock, flags); } static void genesis_mac_init(struct skge_hw *hw, int port) @@ -1674,24 +1784,27 @@ static void genesis_get_stats(struct skge_port *skge, u64 *data) static void genesis_mac_intr(struct skge_hw *hw, int port) { - struct skge_port *skge = netdev_priv(hw->dev[port]); + struct net_device *dev = hw->dev[port]; + struct skge_port *skge = netdev_priv(dev); u16 status = xm_read16(hw, port, XM_ISRC); if (netif_msg_intr(skge)) printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n", - skge->netdev->name, status); + dev->name, status); - if (hw->phy_type == SK_PHY_XMAC && - (status & (XM_IS_INP_ASS | XM_IS_LIPA_RC))) - xm_link_down(hw, port); + if (hw->phy_type == SK_PHY_XMAC && (status & XM_IS_INP_ASS)) { + xm_link_down(hw, port); + mod_timer(&skge->link_timer, jiffies + 1); + } if (status & XM_IS_TXF_UR) { xm_write32(hw, port, XM_MODE, XM_MD_FTF); - ++skge->net_stats.tx_fifo_errors; + ++dev->stats.tx_fifo_errors; } + if (status & XM_IS_RXF_OV) { xm_write32(hw, port, XM_MODE, XM_MD_FRF); - ++skge->net_stats.rx_fifo_errors; + ++dev->stats.rx_fifo_errors; } } @@ -1748,11 +1861,12 @@ static void genesis_link_up(struct skge_port *skge) } xm_write32(hw, port, XM_MODE, mode); - msk = XM_DEF_MSK; - if (hw->phy_type != SK_PHY_XMAC) - msk |= XM_IS_INP_ASS; /* disable GP0 interrupt bit */ + /* Turn on detection of Tx underrun, Rx overrun */ + msk = xm_read16(hw, port, XM_IMSK); + msk &= ~(XM_IS_RXF_OV | XM_IS_TXF_UR); xm_write16(hw, port, XM_IMSK, msk); + xm_read16(hw, port, XM_ISRC); /* get MMU Command Reg. */ @@ -2187,12 +2301,12 @@ static void yukon_mac_intr(struct skge_hw *hw, int port) dev->name, status); if (status & GM_IS_RX_FF_OR) { - ++skge->net_stats.rx_fifo_errors; + ++dev->stats.rx_fifo_errors; skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_CLI_RX_FO); } if (status & GM_IS_TX_FF_UR) { - ++skge->net_stats.tx_fifo_errors; + ++dev->stats.tx_fifo_errors; skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_CLI_TX_FU); } @@ -2526,7 +2640,7 @@ static int skge_up(struct net_device *dev) skge_write32(hw, B0_IMSK, hw->intr_mask); spin_unlock_irq(&hw->hw_lock); - netif_poll_enable(dev); + napi_enable(&skge->napi); return 0; free_rx_ring: @@ -2539,6 +2653,15 @@ static int skge_up(struct net_device *dev) return err; } +/* stop receiver */ +static void skge_rx_stop(struct skge_hw *hw, int port) +{ + skge_write8(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_STOP); + skge_write32(hw, RB_ADDR(port ? Q_R2 : Q_R1, RB_CTRL), + RB_RST_SET|RB_DIS_OP_MD); + skge_write32(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_SET_RESET); +} + static int skge_down(struct net_device *dev) { struct skge_port *skge = netdev_priv(dev); @@ -2556,7 +2679,7 @@ static int skge_down(struct net_device *dev) if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC) del_timer_sync(&skge->link_timer); - netif_poll_disable(dev); + napi_disable(&skge->napi); netif_carrier_off(dev); spin_lock_irq(&hw->hw_lock); @@ -2590,11 +2713,8 @@ static int skge_down(struct net_device *dev) /* Reset the RAM Buffer async Tx queue */ skge_write8(hw, RB_ADDR(port == 0 ? Q_XA1 : Q_XA2, RB_CTRL), RB_RST_SET); - /* stop receiver */ - skge_write8(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_STOP); - skge_write32(hw, RB_ADDR(port ? Q_R2 : Q_R1, RB_CTRL), - RB_RST_SET|RB_DIS_OP_MD); - skge_write32(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_SET_RESET); + + skge_rx_stop(hw, port); if (hw->chip_id == CHIP_ID_GENESIS) { skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_RST_SET); @@ -2777,7 +2897,11 @@ static void skge_tx_timeout(struct net_device *dev) static int skge_change_mtu(struct net_device *dev, int new_mtu) { + struct skge_port *skge = netdev_priv(dev); + struct skge_hw *hw = skge->hw; + int port = skge->port; int err; + u16 ctl, reg; if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU) return -EINVAL; @@ -2787,13 +2911,40 @@ static int skge_change_mtu(struct net_device *dev, int new_mtu) return 0; } - skge_down(dev); + skge_write32(hw, B0_IMSK, 0); + dev->trans_start = jiffies; /* prevent tx timeout */ + netif_stop_queue(dev); + napi_disable(&skge->napi); + + ctl = gma_read16(hw, port, GM_GP_CTRL); + gma_write16(hw, port, GM_GP_CTRL, ctl & ~GM_GPCR_RX_ENA); + + skge_rx_clean(skge); + skge_rx_stop(hw, port); dev->mtu = new_mtu; - err = skge_up(dev); + reg = GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF); + if (new_mtu > 1500) + reg |= GM_SMOD_JUMBO_ENA; + gma_write16(hw, port, GM_SERIAL_MODE, reg); + + skge_write8(hw, RB_ADDR(rxqaddr[port], RB_CTRL), RB_ENA_OP_MD); + + err = skge_rx_fill(dev); + wmb(); + if (!err) + skge_write8(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_START | CSR_IRQ_CL_F); + skge_write32(hw, B0_IMSK, hw->intr_mask); + if (err) dev_close(dev); + else { + gma_write16(hw, port, GM_GP_CTRL, ctl); + + napi_enable(&skge->napi); + netif_wake_queue(dev); + } return err; } @@ -2989,18 +3140,18 @@ error: if (skge->hw->chip_id == CHIP_ID_GENESIS) { if (status & (XMR_FS_RUNT|XMR_FS_LNG_ERR)) - skge->net_stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (status & XMR_FS_FRA_ERR) - skge->net_stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (status & XMR_FS_FCS_ERR) - skge->net_stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; } else { if (status & (GMR_FS_LONG_ERR|GMR_FS_UN_SIZE)) - skge->net_stats.rx_length_errors++; + dev->stats.rx_length_errors++; if (status & GMR_FS_FRAGMENT) - skge->net_stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (status & GMR_FS_CRC_ERR) - skge->net_stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; } resubmit: @@ -3042,14 +3193,13 @@ static void skge_tx_done(struct net_device *dev) } } -static int skge_poll(struct net_device *dev, int *budget) +static int skge_poll(struct napi_struct *napi, int to_do) { - struct skge_port *skge = netdev_priv(dev); + struct skge_port *skge = container_of(napi, struct skge_port, napi); + struct net_device *dev = skge->netdev; struct skge_hw *hw = skge->hw; struct skge_ring *ring = &skge->rx_ring; struct skge_element *e; - unsigned long flags; - int to_do = min(dev->quota, *budget); int work_done = 0; skge_tx_done(dev); @@ -3080,20 +3230,16 @@ static int skge_poll(struct net_device *dev, int *budget) wmb(); skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR), CSR_START); - *budget -= work_done; - dev->quota -= work_done; - - if (work_done >= to_do) - return 1; /* not done */ - - spin_lock_irqsave(&hw->hw_lock, flags); - __netif_rx_complete(dev); - hw->intr_mask |= napimask[skge->port]; - skge_write32(hw, B0_IMSK, hw->intr_mask); - skge_read32(hw, B0_IMSK); - spin_unlock_irqrestore(&hw->hw_lock, flags); + if (work_done < to_do) { + spin_lock_irq(&hw->hw_lock); + __netif_rx_complete(dev, napi); + hw->intr_mask |= napimask[skge->port]; + skge_write32(hw, B0_IMSK, hw->intr_mask); + skge_read32(hw, B0_IMSK); + spin_unlock_irq(&hw->hw_lock); + } - return 0; + return work_done; } /* Parity errors seem to happen when Genesis is connected to a switch @@ -3103,10 +3249,7 @@ static void skge_mac_parity(struct skge_hw *hw, int port) { struct net_device *dev = hw->dev[port]; - if (dev) { - struct skge_port *skge = netdev_priv(dev); - ++skge->net_stats.tx_heartbeat_errors; - } + ++dev->stats.tx_heartbeat_errors; if (hw->chip_id == CHIP_ID_GENESIS) skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), @@ -3250,17 +3393,16 @@ static irqreturn_t skge_intr(int irq, void *dev_id) } if (status & (IS_XA1_F|IS_R1_F)) { + struct skge_port *skge = netdev_priv(hw->dev[0]); hw->intr_mask &= ~(IS_XA1_F|IS_R1_F); - netif_rx_schedule(hw->dev[0]); + netif_rx_schedule(hw->dev[0], &skge->napi); } if (status & IS_PA_TO_TX1) skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_TX1); if (status & IS_PA_TO_RX1) { - struct skge_port *skge = netdev_priv(hw->dev[0]); - - ++skge->net_stats.rx_over_errors; + ++hw->dev[0]->stats.rx_over_errors; skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX1); } @@ -3269,14 +3411,15 @@ static irqreturn_t skge_intr(int irq, void *dev_id) skge_mac_intr(hw, 0); if (hw->dev[1]) { + struct skge_port *skge = netdev_priv(hw->dev[1]); + if (status & (IS_XA2_F|IS_R2_F)) { hw->intr_mask &= ~(IS_XA2_F|IS_R2_F); - netif_rx_schedule(hw->dev[1]); + netif_rx_schedule(hw->dev[1], &skge->napi); } if (status & IS_PA_TO_RX2) { - struct skge_port *skge = netdev_priv(hw->dev[1]); - ++skge->net_stats.rx_over_errors; + ++hw->dev[1]->stats.rx_over_errors; skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX2); } @@ -3538,6 +3681,145 @@ static int skge_reset(struct skge_hw *hw) return 0; } + +#ifdef CONFIG_SKGE_DEBUG + +static struct dentry *skge_debug; + +static int skge_debug_show(struct seq_file *seq, void *v) +{ + struct net_device *dev = seq->private; + const struct skge_port *skge = netdev_priv(dev); + const struct skge_hw *hw = skge->hw; + const struct skge_element *e; + + if (!netif_running(dev)) + return -ENETDOWN; + + seq_printf(seq, "IRQ src=%x mask=%x\n", skge_read32(hw, B0_ISRC), + skge_read32(hw, B0_IMSK)); + + seq_printf(seq, "Tx Ring: (%d)\n", skge_avail(&skge->tx_ring)); + for (e = skge->tx_ring.to_clean; e != skge->tx_ring.to_use; e = e->next) { + const struct skge_tx_desc *t = e->desc; + seq_printf(seq, "%#x dma=%#x%08x %#x csum=%#x/%x/%x\n", + t->control, t->dma_hi, t->dma_lo, t->status, + t->csum_offs, t->csum_write, t->csum_start); + } + + seq_printf(seq, "\nRx Ring: \n"); + for (e = skge->rx_ring.to_clean; ; e = e->next) { + const struct skge_rx_desc *r = e->desc; + + if (r->control & BMU_OWN) + break; + + seq_printf(seq, "%#x dma=%#x%08x %#x %#x csum=%#x/%x\n", + r->control, r->dma_hi, r->dma_lo, r->status, + r->timestamp, r->csum1, r->csum1_start); + } + + return 0; +} + +static int skge_debug_open(struct inode *inode, struct file *file) +{ + return single_open(file, skge_debug_show, inode->i_private); +} + +static const struct file_operations skge_debug_fops = { + .owner = THIS_MODULE, + .open = skge_debug_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/* + * Use network device events to create/remove/rename + * debugfs file entries + */ +static int skge_device_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev = ptr; + struct skge_port *skge; + struct dentry *d; + + if (dev->open != &skge_up || !skge_debug) + goto done; + + skge = netdev_priv(dev); + switch(event) { + case NETDEV_CHANGENAME: + if (skge->debugfs) { + d = debugfs_rename(skge_debug, skge->debugfs, + skge_debug, dev->name); + if (d) + skge->debugfs = d; + else { + pr_info(PFX "%s: rename failed\n", dev->name); + debugfs_remove(skge->debugfs); + } + } + break; + + case NETDEV_GOING_DOWN: + if (skge->debugfs) { + debugfs_remove(skge->debugfs); + skge->debugfs = NULL; + } + break; + + case NETDEV_UP: + d = debugfs_create_file(dev->name, S_IRUGO, + skge_debug, dev, + &skge_debug_fops); + if (!d || IS_ERR(d)) + pr_info(PFX "%s: debugfs create failed\n", + dev->name); + else + skge->debugfs = d; + break; + } + +done: + return NOTIFY_DONE; +} + +static struct notifier_block skge_notifier = { + .notifier_call = skge_device_event, +}; + + +static __init void skge_debug_init(void) +{ + struct dentry *ent; + + ent = debugfs_create_dir("skge", NULL); + if (!ent || IS_ERR(ent)) { + pr_info(PFX "debugfs create directory failed\n"); + return; + } + + skge_debug = ent; + register_netdevice_notifier(&skge_notifier); +} + +static __exit void skge_debug_cleanup(void) +{ + if (skge_debug) { + unregister_netdevice_notifier(&skge_notifier); + debugfs_remove(skge_debug); + skge_debug = NULL; + } +} + +#else +#define skge_debug_init() +#define skge_debug_cleanup() +#endif + /* Initialize network device */ static struct net_device *skge_devinit(struct skge_hw *hw, int port, int highmem) @@ -3550,7 +3832,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, return NULL; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &hw->pdev->dev); dev->open = skge_up; dev->stop = skge_down; @@ -3567,8 +3848,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, SET_ETHTOOL_OPS(dev, &skge_ethtool_ops); dev->tx_timeout = skge_tx_timeout; dev->watchdog_timeo = TX_WATCHDOG; - dev->poll = skge_poll; - dev->weight = NAPI_WEIGHT; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = skge_netpoll; #endif @@ -3578,6 +3857,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, dev->features |= NETIF_F_HIGHDMA; skge = netdev_priv(dev); + netif_napi_add(dev, &skge->napi, skge_poll, NAPI_WEIGHT); skge->netdev = dev; skge->hw = hw; skge->msg_enable = netif_msg_init(debug, default_msg); @@ -3591,7 +3871,9 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, skge->duplex = -1; skge->speed = -1; skge->advertising = skge_supported_modes(hw); - skge->wol = pci_wake_enabled(hw->pdev) ? wol_supported(hw) : 0; + + if (pci_wake_enabled(hw->pdev)) + skge->wol = wol_supported(hw) & WAKE_MAGIC; hw->dev[port] = dev; @@ -3619,12 +3901,11 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, static void __devinit skge_show_addr(struct net_device *dev) { const struct skge_port *skge = netdev_priv(dev); + DECLARE_MAC_BUF(mac); if (netif_msg_probe(skge)) - printk(KERN_INFO PFX "%s: addr %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->name, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + printk(KERN_INFO PFX "%s: addr %s\n", + dev->name, print_mac(mac, dev->dev_addr)); } static int __devinit skge_probe(struct pci_dev *pdev, @@ -3797,6 +4078,9 @@ static int skge_suspend(struct pci_dev *pdev, pm_message_t state) struct skge_hw *hw = pci_get_drvdata(pdev); int i, err, wol = 0; + if (!hw) + return 0; + err = pci_save_state(pdev); if (err) return err; @@ -3825,6 +4109,9 @@ static int skge_resume(struct pci_dev *pdev) struct skge_hw *hw = pci_get_drvdata(pdev); int i, err; + if (!hw) + return 0; + err = pci_set_power_state(pdev, PCI_D0); if (err) goto out; @@ -3863,6 +4150,9 @@ static void skge_shutdown(struct pci_dev *pdev) struct skge_hw *hw = pci_get_drvdata(pdev); int i, wol = 0; + if (!hw) + return; + for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; struct skge_port *skge = netdev_priv(dev); @@ -3894,12 +4184,14 @@ static struct pci_driver skge_driver = { static int __init skge_init_module(void) { + skge_debug_init(); return pci_register_driver(&skge_driver); } static void __exit skge_cleanup_module(void) { pci_unregister_driver(&skge_driver); + skge_debug_cleanup(); } module_init(skge_init_module);