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, &reg2);	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 + -
显示快捷键?