skge.c
来自「linux 内核源代码」· C语言 代码 · 共 2,432 行 · 第 1/5 页
C
2,432 行
p->tx_pending = skge->tx_ring.count; p->rx_mini_pending = 0; p->rx_jumbo_pending = 0;}static int skge_set_ring_param(struct net_device *dev, 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 < TX_LOW_WATER || p->tx_pending > MAX_TX_RING_SIZE) return -EINVAL; skge->rx_ring.count = p->rx_pending; skge->tx_ring.count = p->tx_pending; if (netif_running(dev)) { skge_down(dev); err = skge_up(dev); if (err) dev_close(dev); } return 0;}static u32 skge_get_msglevel(struct net_device *netdev){ struct skge_port *skge = netdev_priv(netdev); return skge->msg_enable;}static void skge_set_msglevel(struct net_device *netdev, u32 value){ struct skge_port *skge = netdev_priv(netdev); skge->msg_enable = value;}static int skge_nway_reset(struct net_device *dev){ struct skge_port *skge = netdev_priv(dev); if (skge->autoneg != AUTONEG_ENABLE || !netif_running(dev)) return -EINVAL; skge_phy_reset(skge); return 0;}static int skge_set_sg(struct net_device *dev, u32 data){ struct skge_port *skge = netdev_priv(dev); struct skge_hw *hw = skge->hw; if (hw->chip_id == CHIP_ID_GENESIS && data) return -EOPNOTSUPP; return ethtool_op_set_sg(dev, data);}static int skge_set_tx_csum(struct net_device *dev, u32 data){ struct skge_port *skge = netdev_priv(dev); struct skge_hw *hw = skge->hw; if (hw->chip_id == CHIP_ID_GENESIS && data) return -EOPNOTSUPP; return ethtool_op_set_tx_csum(dev, data);}static u32 skge_get_rx_csum(struct net_device *dev){ struct skge_port *skge = netdev_priv(dev); return skge->rx_csum;}/* Only Yukon supports checksum offload. */static int skge_set_rx_csum(struct net_device *dev, u32 data){ struct skge_port *skge = netdev_priv(dev); if (skge->hw->chip_id == CHIP_ID_GENESIS && data) return -EOPNOTSUPP; skge->rx_csum = data; return 0;}static void skge_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *ecmd){ struct skge_port *skge = netdev_priv(dev); ecmd->rx_pause = (skge->flow_control == FLOW_MODE_SYMMETRIC) || (skge->flow_control == FLOW_MODE_SYM_OR_REM); ecmd->tx_pause = ecmd->rx_pause || (skge->flow_control == FLOW_MODE_LOC_SEND); ecmd->autoneg = ecmd->rx_pause || ecmd->tx_pause;}static int skge_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *ecmd){ struct skge_port *skge = netdev_priv(dev); struct ethtool_pauseparam old; skge_get_pauseparam(dev, &old); if (ecmd->autoneg != old.autoneg) skge->flow_control = ecmd->autoneg ? FLOW_MODE_NONE : FLOW_MODE_SYMMETRIC; else { if (ecmd->rx_pause && ecmd->tx_pause) skge->flow_control = FLOW_MODE_SYMMETRIC; else if (ecmd->rx_pause && !ecmd->tx_pause) skge->flow_control = FLOW_MODE_SYM_OR_REM; else if (!ecmd->rx_pause && ecmd->tx_pause) skge->flow_control = FLOW_MODE_LOC_SEND; else skge->flow_control = FLOW_MODE_NONE; } if (netif_running(dev)) skge_phy_reset(skge); return 0;}/* Chip internal frequency for clock calculations */static inline u32 hwkhz(const struct skge_hw *hw){ return (hw->chip_id == CHIP_ID_GENESIS) ? 53125 : 78125;}/* Chip HZ to microseconds */static inline u32 skge_clk2usec(const struct skge_hw *hw, u32 ticks){ return (ticks * 1000) / hwkhz(hw);}/* Microseconds to chip HZ */static inline u32 skge_usecs2clk(const struct skge_hw *hw, u32 usec){ return hwkhz(hw) * usec / 1000;}static int skge_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ecmd){ struct skge_port *skge = netdev_priv(dev); struct skge_hw *hw = skge->hw; int port = skge->port; ecmd->rx_coalesce_usecs = 0; ecmd->tx_coalesce_usecs = 0; if (skge_read32(hw, B2_IRQM_CTRL) & TIM_START) { u32 delay = skge_clk2usec(hw, skge_read32(hw, B2_IRQM_INI)); u32 msk = skge_read32(hw, B2_IRQM_MSK); if (msk & rxirqmask[port]) ecmd->rx_coalesce_usecs = delay; if (msk & txirqmask[port]) ecmd->tx_coalesce_usecs = delay; } return 0;}/* Note: interrupt timer is per board, but can turn on/off per port */static int skge_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ecmd){ struct skge_port *skge = netdev_priv(dev); struct skge_hw *hw = skge->hw; int port = skge->port; u32 msk = skge_read32(hw, B2_IRQM_MSK); u32 delay = 25; if (ecmd->rx_coalesce_usecs == 0) msk &= ~rxirqmask[port]; else if (ecmd->rx_coalesce_usecs < 25 || ecmd->rx_coalesce_usecs > 33333) return -EINVAL; else { msk |= rxirqmask[port]; delay = ecmd->rx_coalesce_usecs; } if (ecmd->tx_coalesce_usecs == 0) msk &= ~txirqmask[port]; else if (ecmd->tx_coalesce_usecs < 25 || ecmd->tx_coalesce_usecs > 33333) return -EINVAL; else { msk |= txirqmask[port]; delay = min(delay, ecmd->rx_coalesce_usecs); } skge_write32(hw, B2_IRQM_MSK, msk); if (msk == 0) skge_write32(hw, B2_IRQM_CTRL, TIM_STOP); else { skge_write32(hw, B2_IRQM_INI, skge_usecs2clk(hw, delay)); skge_write32(hw, B2_IRQM_CTRL, TIM_START); } return 0;}enum led_mode { LED_MODE_OFF, LED_MODE_ON, LED_MODE_TST };static void skge_led(struct skge_port *skge, enum led_mode mode){ struct skge_hw *hw = skge->hw; int port = skge->port; spin_lock_bh(&hw->phy_lock); if (hw->chip_id == CHIP_ID_GENESIS) { switch (mode) { case LED_MODE_OFF: if (hw->phy_type == SK_PHY_BCOM) xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF); else { skge_write32(hw, SK_REG(port, TX_LED_VAL), 0); skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_T_OFF); } skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF); skge_write32(hw, SK_REG(port, RX_LED_VAL), 0); skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_T_OFF); break; case LED_MODE_ON: skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON); skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_LINKSYNC_ON); skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START); skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START); break; case LED_MODE_TST: skge_write8(hw, SK_REG(port, RX_LED_TST), LED_T_ON); skge_write32(hw, SK_REG(port, RX_LED_VAL), 100); skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START); if (hw->phy_type == SK_PHY_BCOM) xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON); else { skge_write8(hw, SK_REG(port, TX_LED_TST), LED_T_ON); skge_write32(hw, SK_REG(port, TX_LED_VAL), 100); skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START); } } } else { switch (mode) { case LED_MODE_OFF: gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0); gm_phy_write(hw, port, PHY_MARV_LED_OVER, PHY_M_LED_MO_DUP(MO_LED_OFF) | PHY_M_LED_MO_10(MO_LED_OFF) | PHY_M_LED_MO_100(MO_LED_OFF) | PHY_M_LED_MO_1000(MO_LED_OFF) | PHY_M_LED_MO_RX(MO_LED_OFF)); break; case LED_MODE_ON: gm_phy_write(hw, port, PHY_MARV_LED_CTRL, PHY_M_LED_PULS_DUR(PULS_170MS) | PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL | PHY_M_LEDC_DP_CTRL); gm_phy_write(hw, port, PHY_MARV_LED_OVER, PHY_M_LED_MO_RX(MO_LED_OFF) | (skge->speed == SPEED_100 ? PHY_M_LED_MO_100(MO_LED_ON) : 0)); break; case LED_MODE_TST: gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0); gm_phy_write(hw, port, PHY_MARV_LED_OVER, PHY_M_LED_MO_DUP(MO_LED_ON) | PHY_M_LED_MO_10(MO_LED_ON) | PHY_M_LED_MO_100(MO_LED_ON) | PHY_M_LED_MO_1000(MO_LED_ON) | PHY_M_LED_MO_RX(MO_LED_ON)); } } spin_unlock_bh(&hw->phy_lock);}/* blink LED's for finding board */static int skge_phys_id(struct net_device *dev, u32 data){ struct skge_port *skge = netdev_priv(dev); unsigned long ms; enum led_mode mode = LED_MODE_TST; if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)) ms = jiffies_to_msecs(MAX_SCHEDULE_TIMEOUT / HZ) * 1000; else ms = data * 1000; while (ms > 0) { skge_led(skge, mode); mode ^= LED_MODE_TST; if (msleep_interruptible(BLINK_MS)) break; ms -= BLINK_MS; } /* back to regular LED state */ skge_led(skge, netif_running(dev) ? LED_MODE_ON : LED_MODE_OFF); 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, .get_drvinfo = skge_get_drvinfo, .get_regs_len = skge_get_regs_len, .get_regs = skge_get_regs, .get_wol = skge_get_wol, .set_wol = skge_set_wol, .get_msglevel = skge_get_msglevel, .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, .set_sg = skge_set_sg, .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_sset_count = skge_get_sset_count, .get_ethtool_stats = skge_get_ethtool_stats,};/* * Allocate ring elements and chain them together * One-to-one association of board descriptors with ring elements */static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u32 base){ struct skge_tx_desc *d; struct skge_element *e; int i; ring->start = kcalloc(ring->count, sizeof(*e), GFP_KERNEL); if (!ring->start) return -ENOMEM; for (i = 0, e = ring->start, d = vaddr; i < ring->count; i++, e++, d++) { e->desc = d; if (i == ring->count - 1) { e->next = ring->start; d->next_offset = base; } else { e->next = e + 1; d->next_offset = base + (i+1) * sizeof(*d); } } ring->to_use = ring->to_clean = ring->start; return 0;}/* Allocate and setup a new buffer for receiving */static void skge_rx_setup(struct skge_port *skge, struct skge_element *e, struct sk_buff *skb, unsigned int bufsize){ struct skge_rx_desc *rd = e->desc; u64 map; map = pci_map_single(skge->hw->pdev, skb->data, bufsize, PCI_DMA_FROMDEVICE); rd->dma_lo = map; rd->dma_hi = map >> 32; e->skb = skb; rd->csum1_start = ETH_HLEN; rd->csum2_start = ETH_HLEN; rd->csum1 = 0; rd->csum2 = 0;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?