#include <linux/delay.h>
#include <linux/crc32.h>
#include <linux/dma-mapping.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
#include <linux/mii.h>
#include <asm/irq.h>
#include "skge.h"
#define DRV_NAME "skge"
-#define DRV_VERSION "1.11"
+#define DRV_VERSION "1.13"
#define PFX DRV_NAME " "
#define DEFAULT_TX_RING_SIZE 128
#define BLINK_MS 250
#define LINK_HZ HZ
+#define SKGE_EEPROM_MAGIC 0x9933aabb
+
+
MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver");
MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>");
MODULE_LICENSE("GPL");
static void yukon_init(struct skge_hw *hw, int port);
static void genesis_mac_init(struct skge_hw *hw, int port);
static void genesis_link_up(struct skge_port *skge);
+static void skge_set_multicast(struct net_device *dev);
/* Avoid conditionals by using array */
static const int txqaddr[] = { Q_XA1, Q_XA2 };
return WAKE_MAGIC | WAKE_PHY;
}
-static u32 pci_wake_enabled(struct pci_dev *dev)
-{
- int pm = pci_find_capability(dev, PCI_CAP_ID_PM);
- u16 value;
-
- /* If device doesn't support PM Capabilities, but request is to disable
- * wake events, it's a nop; otherwise fail */
- if (!pm)
- return 0;
-
- pci_read_config_word(dev, pm + PCI_PM_PMC, &value);
-
- value &= PCI_PM_CAP_PME_MASK;
- value >>= ffs(PCI_PM_CAP_PME_MASK) - 1; /* First bit of mask */
-
- return value != 0;
-}
-
static void skge_wol_init(struct skge_port *skge)
{
struct skge_hw *hw = skge->hw;
if (skge->wol & WAKE_MAGIC)
ctrl |= WOL_CTL_ENA_PME_ON_MAGIC_PKT|WOL_CTL_ENA_MAGIC_PKT_UNIT;
else
- ctrl |= WOL_CTL_DIS_PME_ON_MAGIC_PKT|WOL_CTL_DIS_MAGIC_PKT_UNIT;;
+ ctrl |= WOL_CTL_DIS_PME_ON_MAGIC_PKT|WOL_CTL_DIS_MAGIC_PKT_UNIT;
ctrl |= WOL_CTL_DIS_PME_ON_PATTERN|WOL_CTL_DIS_PATTERN_UNIT;
skge_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl);
struct skge_port *skge = netdev_priv(dev);
struct skge_hw *hw = skge->hw;
- if (wol->wolopts & ~wol_supported(hw))
+ if ((wol->wolopts & ~wol_supported(hw))
+ || !device_can_wakeup(&hw->pdev->dev))
return -EOPNOTSUPP;
skge->wol = wol->wolopts;
+
+ device_set_wakeup_enable(&hw->pdev->dev, skge->wol);
+
return 0;
}
struct skge_port *skge = netdev_priv(dev);
const struct skge_hw *hw = skge->hw;
u32 supported = skge_supported_modes(hw);
+ int err = 0;
if (ecmd->autoneg == AUTONEG_ENABLE) {
ecmd->advertising = supported;
skge->autoneg = ecmd->autoneg;
skge->advertising = ecmd->advertising;
- if (netif_running(dev))
- skge_phy_reset(skge);
+ if (netif_running(dev)) {
+ skge_down(dev);
+ err = skge_up(dev);
+ if (err) {
+ dev_close(dev);
+ return err;
+ }
+ }
return (0);
}
struct ethtool_ringparam *p)
{
struct skge_port *skge = netdev_priv(dev);
- int err;
+ int err = 0;
if (p->rx_pending == 0 || p->rx_pending > MAX_RX_RING_SIZE ||
p->tx_pending < TX_LOW_WATER || p->tx_pending > MAX_TX_RING_SIZE)
dev_close(dev);
}
- return 0;
+ return err;
}
static u32 skge_get_msglevel(struct net_device *netdev)
{
struct skge_port *skge = netdev_priv(dev);
struct ethtool_pauseparam old;
+ int err = 0;
skge_get_pauseparam(dev, &old);
skge->flow_control = FLOW_MODE_NONE;
}
- if (netif_running(dev))
- skge_phy_reset(skge);
+ if (netif_running(dev)) {
+ skge_down(dev);
+ err = skge_up(dev);
+ if (err) {
+ dev_close(dev);
+ return err;
+ }
+ }
return 0;
}
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,
.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,
{
struct net_device *dev = hw->dev[port];
struct skge_port *skge = netdev_priv(dev);
- u16 cmd = xm_read16(hw, port, XM_MMU_CMD);
xm_write16(hw, port, XM_IMSK, XM_IMSK_DISABLE);
- cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX);
- xm_write16(hw, port, XM_MMU_CMD, cmd);
-
- /* dummy read to ensure writing */
- xm_read16(hw, port, XM_MMU_CMD);
-
if (netif_carrier_ok(dev))
skge_link_down(skge);
}
static void genesis_reset(struct skge_hw *hw, int port)
{
const u8 zero[8] = { 0 };
+ u32 reg;
skge_write8(hw, SK_REG(port, GMAC_IRQ_MSK), 0);
xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
xm_outhash(hw, port, XM_HSM, zero);
+
+ /* Flush TX and RX fifo */
+ reg = xm_read32(hw, port, XM_MODE);
+ xm_write32(hw, port, XM_MODE, reg | XM_MD_FTF);
+ xm_write32(hw, port, XM_MODE, reg | XM_MD_FRF);
}
}
xm_write16(hw, port, XM_RX_CMD, r);
-
/* We want short frames padded to 60 bytes. */
xm_write16(hw, port, XM_TX_CMD, XM_TX_AUTO_PAD);
- /*
- * Bump up the transmit threshold. This helps hold off transmit
- * underruns when we're blasting traffic from both ports at once.
- */
- xm_write16(hw, port, XM_TX_THR, 512);
+ /* Increase threshold for jumbo frames on dual port */
+ if (hw->ports > 1 && jumbo)
+ xm_write16(hw, port, XM_TX_THR, 1020);
+ else
+ xm_write16(hw, port, XM_TX_THR, 512);
/*
* Enable the reception of all error frames. This is is
{
struct skge_hw *hw = skge->hw;
int port = skge->port;
- u32 reg;
+ unsigned retries = 1000;
+ u16 cmd;
+
+ /* Disable Tx and Rx */
+ 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);
genesis_reset(hw, port);
skge_write16(hw, B3_PA_CTRL,
port == 0 ? PA_CLR_TO_TX1 : PA_CLR_TO_TX2);
- /*
- * If the transfer sticks at the MAC the STOP command will not
- * terminate if we don't flush the XMAC's transmit FIFO !
- */
- xm_write32(hw, port, XM_MODE,
- xm_read32(hw, port, XM_MODE)|XM_MD_FTF);
-
-
/* Reset the MAC */
- skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
+ skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);
+ do {
+ skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
+ if (!(skge_read16(hw, SK_REG(port, TX_MFF_CTRL1)) & MFF_SET_MAC_RST))
+ break;
+ } while (--retries > 0);
/* For external PHYs there must be special handling */
if (hw->phy_type != SK_PHY_XMAC) {
- reg = skge_read32(hw, B2_GP_IO);
+ u32 reg = skge_read32(hw, B2_GP_IO);
if (port == 0) {
reg |= GP_DIR_0;
reg &= ~GP_IO_0;
xm_write32(hw, port, XM_MODE, XM_MD_FTF);
++dev->stats.tx_fifo_errors;
}
-
- if (status & XM_IS_RXF_OV) {
- xm_write32(hw, port, XM_MODE, XM_MD_FRF);
- ++dev->stats.rx_fifo_errors;
- }
}
static void genesis_link_up(struct skge_port *skge)
xm_write32(hw, port, XM_MODE, mode);
- /* Turn on detection of Tx underrun, Rx overrun */
+ /* Turn on detection of Tx underrun */
msk = xm_read16(hw, port, XM_IMSK);
- msk &= ~(XM_IS_RXF_OV | XM_IS_TXF_UR);
+ msk &= ~XM_IS_TXF_UR;
xm_write16(hw, port, XM_IMSK, msk);
xm_read16(hw, port, XM_ISRC);
TX_JAM_IPG_VAL(TX_JAM_IPG_DEF) |
TX_IPG_JAM_DATA(TX_IPG_JAM_DEF));
- /* serial mode register */
- reg = GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF);
- if (hw->dev[port]->mtu > 1500)
+ /* configure the Serial Mode Register */
+ reg = DATA_BLIND_VAL(DATA_BLIND_DEF)
+ | GM_SMOD_VLAN_ENA
+ | IPG_DATA_VAL(IPG_DATA_DEF);
+
+ if (hw->dev[port]->mtu > ETH_DATA_LEN)
reg |= GM_SMOD_JUMBO_ENA;
gma_write16(hw, port, GM_SERIAL_MODE, reg);
}
spin_unlock_bh(&hw->phy_lock);
- dev->set_multicast_list(dev);
+ skge_set_multicast(dev);
}
/* Basic MII support */
}
case SIOCSMIIREG:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
spin_lock_bh(&hw->phy_lock);
if (hw->chip_id == CHIP_ID_GENESIS)
err = xm_phy_write(hw, skge->port, data->reg_num & 0x1f,
return err;
}
-/* Assign Ram Buffer allocation to queue */
-static void skge_ramset(struct skge_hw *hw, u16 q, u32 start, u32 space)
+static void skge_ramset(struct skge_hw *hw, u16 q, u32 start, size_t len)
{
u32 end;
- /* convert from K bytes to qwords used for hw register */
- start *= 1024/8;
- space *= 1024/8;
- end = start + space - 1;
+ start /= 8;
+ len /= 8;
+ end = start + len - 1;
skge_write8(hw, RB_ADDR(q, RB_CTRL), RB_RST_CLR);
skge_write32(hw, RB_ADDR(q, RB_START), start);
- skge_write32(hw, RB_ADDR(q, RB_END), end);
skge_write32(hw, RB_ADDR(q, RB_WP), start);
skge_write32(hw, RB_ADDR(q, RB_RP), start);
+ skge_write32(hw, RB_ADDR(q, RB_END), end);
if (q == Q_R1 || q == Q_R2) {
- u32 tp = space - space/4;
-
/* Set thresholds on receive queue's */
- skge_write32(hw, RB_ADDR(q, RB_RX_UTPP), tp);
- skge_write32(hw, RB_ADDR(q, RB_RX_LTPP), space/4);
- } else if (hw->chip_id != CHIP_ID_GENESIS)
- /* Genesis Tx Fifo is too small for normal store/forward */
+ skge_write32(hw, RB_ADDR(q, RB_RX_UTPP),
+ start + (2*len)/3);
+ skge_write32(hw, RB_ADDR(q, RB_RX_LTPP),
+ start + (len/3));
+ } else {
+ /* Enable store & forward on Tx queue's because
+ * Tx FIFO is only 4K on Genesis and 1K on Yukon
+ */
skge_write8(hw, RB_ADDR(q, RB_CTRL), RB_ENA_STFWD);
+ }
skge_write8(hw, RB_ADDR(q, RB_CTRL), RB_ENA_OP_MD);
}
struct skge_port *skge = netdev_priv(dev);
struct skge_hw *hw = skge->hw;
int port = skge->port;
- u32 ramaddr, ramsize, rxspace;
+ u32 chunk, ram_addr;
size_t rx_size, tx_size;
int err;
yukon_mac_init(hw, port);
spin_unlock_bh(&hw->phy_lock);
- /* Configure RAMbuffers */
- ramsize = (hw->ram_size - hw->ram_offset) / hw->ports;
- ramaddr = hw->ram_offset + port * ramsize;
- rxspace = 8 + (2*(ramsize - 16))/3;
-
- skge_ramset(hw, rxqaddr[port], ramaddr, rxspace);
- skge_ramset(hw, txqaddr[port], ramaddr + rxspace, ramsize - rxspace);
+ /* Configure RAMbuffers - equally between ports and tx/rx */
+ chunk = (hw->ram_size - hw->ram_offset) / (hw->ports * 2);
+ ram_addr = hw->ram_offset + 2 * chunk * port;
+ skge_ramset(hw, rxqaddr[port], ram_addr, chunk);
skge_qset(skge, rxqaddr[port], skge->rx_ring.to_clean);
+
BUG_ON(skge->tx_ring.to_use != skge->tx_ring.to_clean);
+ skge_ramset(hw, txqaddr[port], ram_addr+chunk, chunk);
skge_qset(skge, txqaddr[port], skge->tx_ring.to_use);
/* Start receiver BMU */
if (netif_msg_ifdown(skge))
printk(KERN_INFO PFX "%s: disabling interface\n", dev->name);
- netif_stop_queue(dev);
+ netif_tx_disable(dev);
if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC)
del_timer_sync(&skge->link_timer);
+ (ring->to_clean - ring->to_use) - 1;
}
-static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t skge_xmit_frame(struct sk_buff *skb,
+ struct net_device *dev)
{
struct skge_port *skge = netdev_priv(dev);
struct skge_hw *hw = skge->hw;
netif_stop_queue(dev);
}
- dev->trans_start = jiffies;
-
return NETDEV_TX_OK;
}
}
skge->tx_ring.to_clean = e;
- netif_wake_queue(dev);
}
static void skge_tx_timeout(struct net_device *dev)
skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_STOP);
skge_tx_clean(dev);
+ netif_wake_queue(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;
return 0;
}
- 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);
+ skge_down(dev);
dev->mtu = new_mtu;
- 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);
-
+ err = skge_up(dev);
if (err)
dev_close(dev);
- else {
- gma_write16(hw, port, GM_GP_CTRL, ctl);
-
- napi_enable(&skge->napi);
- netif_wake_queue(dev);
- }
return err;
}
(status & GMR_FS_RX_OK) == 0;
}
+static void skge_set_multicast(struct net_device *dev)
+{
+ struct skge_port *skge = netdev_priv(dev);
+ struct skge_hw *hw = skge->hw;
+
+ if (hw->chip_id == CHIP_ID_GENESIS)
+ genesis_set_multicast(dev);
+ else
+ yukon_set_multicast(dev);
+
+}
+
/* Get receive buffer from descriptor.
* Handles copy of small buffers and reallocation failures
goto error;
if (len < RX_COPY_THRESHOLD) {
- skb = netdev_alloc_skb(dev, len + 2);
+ skb = netdev_alloc_skb_ip_align(dev, len);
if (!skb)
goto resubmit;
- skb_reserve(skb, 2);
pci_dma_sync_single_for_cpu(skge->hw->pdev,
pci_unmap_addr(e, mapaddr),
len, PCI_DMA_FROMDEVICE);
skge_rx_reuse(e, skge->rx_buf_size);
} else {
struct sk_buff *nskb;
- nskb = netdev_alloc_skb(dev, skge->rx_buf_size + NET_IP_ALIGN);
+
+ nskb = netdev_alloc_skb_ip_align(dev, skge->rx_buf_size);
if (!nskb)
goto resubmit;
- skb_reserve(nskb, NET_IP_ALIGN);
pci_unmap_single(skge->hw->pdev,
pci_unmap_addr(e, mapaddr),
pci_unmap_len(e, maplen),
skb = skge_rx_get(dev, e, control, rd->status, rd->csum2);
if (likely(skb)) {
- dev->last_rx = jiffies;
netif_receive_skb(skb);
++work_done;
skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR), CSR_START);
if (work_done < to_do) {
- spin_lock_irq(&hw->hw_lock);
- __netif_rx_complete(dev, napi);
+ unsigned long flags;
+
+ spin_lock_irqsave(&hw->hw_lock, flags);
+ __napi_complete(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);
+ spin_unlock_irqrestore(&hw->hw_lock, flags);
}
return work_done;
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], &skge->napi);
+ napi_schedule(&skge->napi);
}
if (status & IS_PA_TO_TX1)
if (status & (IS_XA2_F|IS_R2_F)) {
hw->intr_mask &= ~(IS_XA2_F|IS_R2_F);
- netif_rx_schedule(hw->dev[1], &skge->napi);
+ napi_schedule(&skge->napi);
}
if (status & IS_PA_TO_RX2) {
if (hw->chip_id == CHIP_ID_GENESIS) {
if (t8 == 3) {
/* special case: 4 x 64k x 36, offset = 0x80000 */
- hw->ram_size = 1024;
- hw->ram_offset = 512;
+ hw->ram_size = 0x100000;
+ hw->ram_offset = 0x80000;
} else
hw->ram_size = t8 * 512;
- } else /* Yukon */
- hw->ram_size = t8 ? t8 * 4 : 128;
+ }
+ else if (t8 == 0)
+ hw->ram_size = 0x20000;
+ else
+ hw->ram_size = t8 * 4096;
hw->intr_mask = IS_HW_ERR;
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->netdev_ops->ndo_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
+
+static const struct net_device_ops skge_netdev_ops = {
+ .ndo_open = skge_up,
+ .ndo_stop = skge_down,
+ .ndo_start_xmit = skge_xmit_frame,
+ .ndo_do_ioctl = skge_ioctl,
+ .ndo_get_stats = skge_get_stats,
+ .ndo_tx_timeout = skge_tx_timeout,
+ .ndo_change_mtu = skge_change_mtu,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_set_multicast_list = skge_set_multicast,
+ .ndo_set_mac_address = skge_set_mac_address,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = skge_netpoll,
+#endif
+};
+
+
/* Initialize network device */
static struct net_device *skge_devinit(struct skge_hw *hw, int port,
int highmem)
}
SET_NETDEV_DEV(dev, &hw->pdev->dev);
- dev->open = skge_up;
- dev->stop = skge_down;
- dev->do_ioctl = skge_ioctl;
- dev->hard_start_xmit = skge_xmit_frame;
- dev->get_stats = skge_get_stats;
- if (hw->chip_id == CHIP_ID_GENESIS)
- dev->set_multicast_list = genesis_set_multicast;
- else
- dev->set_multicast_list = yukon_set_multicast;
-
- dev->set_mac_address = skge_set_mac_address;
- dev->change_mtu = skge_change_mtu;
- SET_ETHTOOL_OPS(dev, &skge_ethtool_ops);
- dev->tx_timeout = skge_tx_timeout;
+ dev->netdev_ops = &skge_netdev_ops;
+ dev->ethtool_ops = &skge_ethtool_ops;
dev->watchdog_timeo = TX_WATCHDOG;
-#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = skge_netpoll;
-#endif
dev->irq = hw->pdev->irq;
if (highmem)
skge->speed = -1;
skge->advertising = skge_supported_modes(hw);
- if (pci_wake_enabled(hw->pdev))
+ if (device_can_wakeup(&hw->pdev->dev)) {
skge->wol = wol_supported(hw) & WAKE_MAGIC;
+ device_set_wakeup_enable(&hw->pdev->dev, skge->wol);
+ }
hw->dev[port] = dev;
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 %s\n",
- dev->name, print_mac(mac, dev->dev_addr));
+ printk(KERN_INFO PFX "%s: addr %pM\n",
+ dev->name, dev->dev_addr);
}
static int __devinit skge_probe(struct pci_dev *pdev,
pci_set_master(pdev);
- if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+ if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) {
using_dac = 1;
- err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
- } else if (!(err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) {
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
+ } else if (!(err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))) {
using_dac = 0;
- err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
}
if (err) {
#endif
err = -ENOMEM;
- hw = kzalloc(sizeof(*hw), GFP_KERNEL);
+ /* space for skge@pci:0000:04:00.0 */
+ hw = kzalloc(sizeof(*hw) + strlen(DRV_NAME "@pci:" )
+ + strlen(pci_name(pdev)) + 1, GFP_KERNEL);
if (!hw) {
dev_err(&pdev->dev, "cannot allocate hardware struct\n");
goto err_out_free_regions;
}
+ sprintf(hw->irq_name, DRV_NAME "@pci:%s", pci_name(pdev));
hw->pdev = pdev;
spin_lock_init(&hw->hw_lock);
goto err_out_free_netdev;
}
- err = request_irq(pdev->irq, skge_intr, IRQF_SHARED, dev->name, hw);
+ err = request_irq(pdev->irq, skge_intr, IRQF_SHARED, hw->irq_name, hw);
if (err) {
dev_err(&pdev->dev, "%s: cannot assign irq %d\n",
dev->name, pdev->irq);
}
skge_show_addr(dev);
- if (hw->ports > 1 && (dev1 = skge_devinit(hw, 1, using_dac))) {
- if (register_netdev(dev1) == 0)
+ if (hw->ports > 1) {
+ dev1 = skge_devinit(hw, 1, using_dac);
+ if (dev1 && register_netdev(dev1) == 0)
skge_show_addr(dev1);
else {
/* Failure to register second port need not be fatal */
dev_warn(&pdev->dev, "register of second port failed\n");
hw->dev[1] = NULL;
- free_netdev(dev1);
+ hw->ports = 1;
+ if (dev1)
+ free_netdev(dev1);
}
}
pci_set_drvdata(pdev, hw);
}
skge_write32(hw, B0_IMSK, 0);
- pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ pci_prepare_to_sleep(pdev);
return 0;
}
if (!hw)
return 0;
- err = pci_set_power_state(pdev, PCI_D0);
+ err = pci_back_from_sleep(pdev);
if (err)
goto out;
if (err)
goto out;
- pci_enable_wake(pdev, PCI_D0, 0);
-
err = skge_reset(hw);
if (err)
goto out;
wol |= skge->wol;
}
- pci_enable_wake(pdev, PCI_D3hot, wol);
- pci_enable_wake(pdev, PCI_D3cold, wol);
+ if (pci_enable_wake(pdev, PCI_D3cold, wol))
+ pci_enable_wake(pdev, PCI_D3hot, wol);
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
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);