Exemplo n.º 1
0
/**
 *  e1000_mng_enable_host_if - Checks host interface is enabled
 *  @hw: pointer to the HW structure
 *
 *  Returns E1000_success upon success, else E1000_ERR_HOST_INTERFACE_COMMAND
 *
 *  This function checks whether the HOST IF is enabled for command operation
 *  and also checks whether the previous command is completed.  It busy waits
 *  in case of previous command is not completed.
 **/
s32 e1000_mng_enable_host_if(struct e1000_hw *hw)
{
	u32 hicr;
	u8 i;

	if (!hw->mac.arc_subsystem_valid) {
		e_dbg("ARC subsystem not valid.\n");
		return -E1000_ERR_HOST_INTERFACE_COMMAND;
	}

	/* Check that the host interface is enabled. */
	hicr = er32(HICR);
	if (!(hicr & E1000_HICR_EN)) {
		e_dbg("E1000_HOST_EN bit disabled.\n");
		return -E1000_ERR_HOST_INTERFACE_COMMAND;
	}
	/* check the previous command is completed */
	for (i = 0; i < E1000_MNG_DHCP_COMMAND_TIMEOUT; i++) {
		hicr = er32(HICR);
		if (!(hicr & E1000_HICR_C))
			break;
		mdelay(1);
	}

	if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
		e_dbg("Previous command timeout failed .\n");
		return -E1000_ERR_HOST_INTERFACE_COMMAND;
	}

	return 0;
}
Exemplo n.º 2
0
/**
 *  e1000e_enable_mng_pass_thru - Check if management passthrough is needed
 *  @hw: pointer to the HW structure
 *
 *  Verifies the hardware needs to leave interface enabled so that frames can
 *  be directed to and from the management interface.
 **/
bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw)
{
	u32 manc;
	u32 fwsm, factps;

	manc = er32(MANC);

	if (!(manc & E1000_MANC_RCV_TCO_EN))
		return false;

	if (hw->mac.has_fwsm) {
		fwsm = er32(FWSM);
		factps = er32(FACTPS);

		if (!(factps & E1000_FACTPS_MNGCG) &&
		    ((fwsm & E1000_FWSM_MODE_MASK) ==
		     (e1000_mng_mode_pt << E1000_FWSM_MODE_SHIFT)))
			return true;
	} else if ((hw->mac.type == e1000_82574) ||
		   (hw->mac.type == e1000_82583)) {
		u16 data;

		factps = er32(FACTPS);
		e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &data);

		if (!(factps & E1000_FACTPS_MNGCG) &&
		    ((data & E1000_NVM_INIT_CTRL2_MNGM) ==
		     (e1000_mng_mode_pt << 13)))
			return true;
	} else if ((manc & E1000_MANC_SMBUS_EN) && !(manc & E1000_MANC_ASF_EN)) {
		return true;
	}

	return false;
}
Exemplo n.º 3
0
/* only call this for fiber/serdes connections to es2lan */
static int e1000_set_es2lan_mac_loopback(struct e1000_adapter *adapter)
{
	struct e1000_hw *hw = &adapter->hw;
	u32 ctrlext = er32(CTRL_EXT);
	u32 ctrl = er32(CTRL);

	/*
	 * save CTRL_EXT to restore later, reuse an empty variable (unused
	 * on mac_type 80003es2lan)
	 */
	adapter->tx_fifo_head = ctrlext;

	/* clear the serdes mode bits, putting the device into mac loopback */
	ctrlext &= ~E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES;
	ew32(CTRL_EXT, ctrlext);

	/* force speed to 1000/FD, link up */
	ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
	ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX |
		 E1000_CTRL_SPD_1000 | E1000_CTRL_FD);
	ew32(CTRL, ctrl);

	/* set mac loopback */
	ctrl = er32(RCTL);
	ctrl |= E1000_RCTL_LBM_MAC;
	ew32(RCTL, ctrl);

	/* set testing mode parameters (no need to reset later) */
#define KMRNCTRLSTA_OPMODE (0x1F << 16)
#define KMRNCTRLSTA_OPMODE_1GB_FD_GMII 0x0582
	ew32(KMRNCTRLSTA,
	     (KMRNCTRLSTA_OPMODE | KMRNCTRLSTA_OPMODE_1GB_FD_GMII));

	return 0;
}
Exemplo n.º 4
0
static void igbvf_get_regs(struct net_device *netdev,
                           struct ethtool_regs *regs, void *p)
{
	struct igbvf_adapter *adapter = netdev_priv(netdev);
	struct e1000_hw *hw = &adapter->hw;
	u32 *regs_buff = p;
	u8 revision_id;

	memset(p, 0, IGBVF_REGS_LEN * sizeof(u32));

	pci_read_config_byte(adapter->pdev, PCI_REVISION_ID, &revision_id);

	regs->version = (1 << 24) | (revision_id << 16) | adapter->pdev->device;

	regs_buff[0] = er32(CTRL);
	regs_buff[1] = er32(STATUS);

	regs_buff[2] = er32(RDLEN(0));
	regs_buff[3] = er32(RDH(0));
	regs_buff[4] = er32(RDT(0));

	regs_buff[5] = er32(TDLEN(0));
	regs_buff[6] = er32(TDH(0));
	regs_buff[7] = er32(TDT(0));
}
Exemplo n.º 5
0
/**
 * e1000_get_hw_control - get control of the h/w from f/w
 * @adapter: address of board private structure
 *
 * e1000_get_hw_control sets {CTRL_EXT|SWSM}:DRV_LOAD bit.
 * For ASF and Pass Through versions of f/w this means that
 * the driver is loaded. For AMT version (only with 82573)
 * of the f/w this means that the network i/f is open.
 **/
static void e1000e_get_hw_control(struct e1000_adapter *adapter)
{
	struct e1000_hw *hw = &adapter->hw;
	u32 ctrl_ext;
	u32 swsm;

	/* Let firmware know the driver has taken over */
	if (adapter->flags & FLAG_HAS_SWSM_ON_LOAD) {
		swsm = er32(SWSM);
		ew32(SWSM, swsm | E1000_SWSM_DRV_LOAD);
	} else if (adapter->flags & FLAG_HAS_CTRLEXT_ON_LOAD) {
		ctrl_ext = er32(CTRL_EXT);
		ew32(CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_DRV_LOAD);
	}
}
Exemplo n.º 6
0
static int
e1000_hw_reset(struct e1000_hw *hw)
{
	uint32_t ctrl;
	uint32_t icr;

	/* Clear interrupt mask to stop board from generating interrupts */
	ew32(IMC, 0xffffffff);

	/* Disable the Transmit and Receive units.  Then delay to allow
	 * any pending transactions to complete before we hit the MAC with
	 * the global reset.
	 */
	ew32(RCTL, 0);
	ew32(TCTL, E1000_TCTL_PSP);
	er32(STATUS); /* wait for complete */

	/* Delay to allow any outstanding PCI transactions to complete before
	 * resetting the device
	 */
	delay_usec(10000);
	ctrl = er32(CTRL);

	/* reset phy */
	ew32(CTRL, (ctrl | E1000_CTRL_PHY_RST));
	delay_usec(5000);

	/* Issue a global reset to the MAC.  This will reset the chip's
	 * transmit, receive, DMA, and link units.  It will not effect
	 * the current PCI configuration.  The global reset bit is self-
	 * clearing, and should clear within a microsecond.
	 */
	ew32(CTRL, (ctrl | E1000_CTRL_RST));

	/* After MAC reset, force reload of EEPROM to restore power-on
	 * settings to device.  Later controllers reload the EEPROM
	 * automatically, so just wait for reload to complete.
	 */
	delay_usec(20000);

	/* Clear interrupt mask to stop board from generating interrupts */
	ew32(IMC, 0xffffffff);

	/* Clear any pending interrupt events. */
	icr = er32(ICR);

	return 0;
}
Exemplo n.º 7
0
/**
 *  e1000e_check_mng_mode_generic - Generic check management mode
 *  @hw: pointer to the HW structure
 *
 *  Reads the firmware semaphore register and returns true (>0) if
 *  manageability is enabled, else false (0).
 **/
bool e1000e_check_mng_mode_generic(struct e1000_hw *hw)
{
	u32 fwsm = er32(FWSM);

	return (fwsm & E1000_FWSM_MODE_MASK) ==
	    (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
}
Exemplo n.º 8
0
/**
 *  e1000e_mng_write_dhcp_info - Writes DHCP info to host interface
 *  @hw: pointer to the HW structure
 *  @buffer: pointer to the host interface
 *  @length: size of the buffer
 *
 *  Writes the DHCP information to the host interface.
 **/
s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length)
{
	struct e1000_host_mng_command_header hdr;
	s32 ret_val;
	u32 hicr;

	hdr.command_id = E1000_MNG_DHCP_TX_PAYLOAD_CMD;
	hdr.command_length = length;
	hdr.reserved1 = 0;
	hdr.reserved2 = 0;
	hdr.checksum = 0;

	/* Enable the host interface */
	ret_val = hw->mac.ops.mng_enable_host_if(hw);
	if (ret_val)
		return ret_val;

	/* Populate the host interface with the contents of "buffer". */
	ret_val = hw->mac.ops.mng_host_if_write(hw, buffer, length,
						sizeof(hdr), &(hdr.checksum));
	if (ret_val)
		return ret_val;

	/* Write the manageability command header */
	ret_val = hw->mac.ops.mng_write_cmd_header(hw, &hdr);
	if (ret_val)
		return ret_val;

	/* Tell the ARC a new command is pending. */
	hicr = er32(HICR);
	ew32(HICR, hicr | E1000_HICR_C);

	return 0;
}
Exemplo n.º 9
0
static int e1000_setup_loopback_test(struct e1000_adapter *adapter)
{
	struct e1000_hw *hw = &adapter->hw;
	u32 rctl;

	if (hw->phy.media_type == e1000_media_type_fiber ||
	    hw->phy.media_type == e1000_media_type_internal_serdes) {
		switch (hw->mac.type) {
		case e1000_80003es2lan:
			return e1000_set_es2lan_mac_loopback(adapter);
			break;
		case e1000_82571:
		case e1000_82572:
			return e1000_set_82571_fiber_loopback(adapter);
			break;
		default:
			rctl = er32(RCTL);
			rctl |= E1000_RCTL_LBM_TCVR;
			ew32(RCTL, rctl);
			return 0;
		}
	} else if (hw->phy.media_type == e1000_media_type_copper) {
		return e1000_integrated_phy_loopback(adapter);
	}

	return 7;
}
Exemplo n.º 10
0
Arquivo: mbx.c Projeto: 020gzh/linux
/**
 *  e1000_read_v2p_mailbox - read v2p mailbox
 *  @hw: pointer to the HW structure
 *
 *  This function is used to read the v2p mailbox without losing the read to
 *  clear status bits.
 **/
static u32 e1000_read_v2p_mailbox(struct e1000_hw *hw)
{
	u32 v2p_mailbox = er32(V2PMAILBOX(0));

	v2p_mailbox |= hw->dev_spec.vf.v2p_mailbox;
	hw->dev_spec.vf.v2p_mailbox |= v2p_mailbox & E1000_V2PMAILBOX_R2C_BITS;

	return v2p_mailbox;
}
Exemplo n.º 11
0
/**
 * e1000e_ptp_init - initialize PTP for devices which support it
 * @adapter: board private structure
 *
 * This function performs the required steps for enabling PTP support.
 * If PTP support has already been loaded it simply calls the cyclecounter
 * init routine and exits.
 **/
void e1000e_ptp_init(struct e1000_adapter *adapter)
{
	struct e1000_hw *hw = &adapter->hw;

	adapter->ptp_clock = NULL;

	if (!(adapter->flags & FLAG_HAS_HW_TIMESTAMP))
		return;

	adapter->ptp_clock_info = e1000e_ptp_clock_info;

	snprintf(adapter->ptp_clock_info.name,
		 sizeof(adapter->ptp_clock_info.name), "%pm",
		 adapter->netdev->perm_addr);

	switch (hw->mac.type) {
	case e1000_pch2lan:
	case e1000_pch_lpt:
	case e1000_pch_spt:
		if (((hw->mac.type != e1000_pch_lpt) &&
		     (hw->mac.type != e1000_pch_spt)) ||
		    (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)) {
			adapter->ptp_clock_info.max_adj = 24000000 - 1;
			break;
		}
		/* fall-through */
	case e1000_82574:
	case e1000_82583:
		adapter->ptp_clock_info.max_adj = 600000000 - 1;
		break;
	default:
		break;
	}

#ifdef CONFIG_E1000E_HWTS
	/* CPU must have ART and GBe must be from Sunrise Point or greater */
	if (hw->mac.type >= e1000_pch_spt && boot_cpu_has(X86_FEATURE_ART))
		adapter->ptp_clock_info.getcrosststamp =
			e1000e_phc_getcrosststamp;
#endif/*CONFIG_E1000E_HWTS*/

	INIT_DELAYED_WORK(&adapter->systim_overflow_work,
			  e1000e_systim_overflow_work);

	schedule_delayed_work(&adapter->systim_overflow_work,
			      E1000_SYSTIM_OVERFLOW_PERIOD);

	adapter->ptp_clock = ptp_clock_register(&adapter->ptp_clock_info,
						&adapter->pdev->dev);
	if (IS_ERR(adapter->ptp_clock)) {
		adapter->ptp_clock = NULL;
		e_err("ptp_clock_register failed\n");
	} else if (adapter->ptp_clock) {
		e_info("registered PHC clock\n");
	}
}
Exemplo n.º 12
0
Arquivo: ethtool.c Projeto: A-K/linux
static irqreturn_t e1000_test_intr(int irq, void *data)
{
	struct net_device *netdev = (struct net_device *) data;
	struct e1000_adapter *adapter = netdev_priv(netdev);
	struct e1000_hw *hw = &adapter->hw;

	adapter->test_icr |= er32(ICR);

	return IRQ_HANDLED;
}
Exemplo n.º 13
0
static int igbvf_link_test(struct igbvf_adapter *adapter, u64 *data)
{
	struct e1000_hw *hw = &adapter->hw;
	*data = 0;

	hw->mac.ops.check_for_link(hw);

	if (!(er32(STATUS) & E1000_STATUS_LU))
		*data = 1;

	return *data;
}
Exemplo n.º 14
0
static int e1000_set_82571_fiber_loopback(struct e1000_adapter *adapter)
{
	struct e1000_hw *hw = &adapter->hw;
	u32 ctrl = er32(CTRL);
	int link = 0;

	/* special requirements for 82571/82572 fiber adapters */

	/*
	 * jump through hoops to make sure link is up because serdes
	 * link is hardwired up
	 */
	ctrl |= E1000_CTRL_SLU;
	ew32(CTRL, ctrl);

	/* disable autoneg */
	ctrl = er32(TXCW);
	ctrl &= ~(1 << 31);
	ew32(TXCW, ctrl);

	link = (er32(STATUS) & E1000_STATUS_LU);

	if (!link) {
		/* set invert loss of signal */
		ctrl = er32(CTRL);
		ctrl |= E1000_CTRL_ILOS;
		ew32(CTRL, ctrl);
	}

	/*
	 * special write to serdes control register to enable SerDes analog
	 * loopback
	 */
#define E1000_SERDES_LB_ON 0x410
	ew32(SCTL, E1000_SERDES_LB_ON);
	msleep(10);

	return 0;
}
Exemplo n.º 15
0
/**
 * e1000e_ptp_init - initialize PTP for devices which support it
 * @adapter: board private structure
 *
 * This function performs the required steps for enabling PTP support.
 * If PTP support has already been loaded it simply calls the cyclecounter
 * init routine and exits.
 **/
void e1000e_ptp_init(struct e1000_adapter *adapter)
{
	struct e1000_hw *hw = &adapter->hw;

	adapter->ptp_clock = NULL;

	if (!(adapter->flags & FLAG_HAS_HW_TIMESTAMP))
		return;

	adapter->ptp_clock_info = e1000e_ptp_clock_info;

	snprintf(adapter->ptp_clock_info.name,
		 sizeof(adapter->ptp_clock_info.name), "%pm",
		 adapter->netdev->perm_addr);

	switch (hw->mac.type) {
	case e1000_pch2lan:
	case e1000_pch_lpt:
	case e1000_pch_spt:
		if (((hw->mac.type != e1000_pch_lpt) &&
		     (hw->mac.type != e1000_pch_spt)) ||
		    (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI)) {
			adapter->ptp_clock_info.max_adj = 24000000 - 1;
			break;
		}
		/* fall-through */
	case e1000_82574:
	case e1000_82583:
		adapter->ptp_clock_info.max_adj = 600000000 - 1;
		break;
	default:
		break;
	}

	INIT_DELAYED_WORK(&adapter->systim_overflow_work,
			  e1000e_systim_overflow_work);

	schedule_delayed_work(&adapter->systim_overflow_work,
			      E1000_SYSTIM_OVERFLOW_PERIOD);

	adapter->ptp_clock = ptp_clock_register(&adapter->ptp_clock_info,
						pci_dev_to_dev(adapter->pdev));
	if (IS_ERR(adapter->ptp_clock)) {
		adapter->ptp_clock = NULL;
		e_err("ptp_clock_register failed\n");
	} else {
		e_info("registered PHC clock\n");
	}
}
Exemplo n.º 16
0
static void e1000_loopback_cleanup(struct e1000_adapter *adapter)
{
	struct e1000_hw *hw = &adapter->hw;
	u32 rctl;
	u16 phy_reg;

	rctl = er32(RCTL);
	rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC);
	ew32(RCTL, rctl);

	switch (hw->mac.type) {
	case e1000_80003es2lan:
		if (hw->phy.media_type == e1000_media_type_fiber ||
		    hw->phy.media_type == e1000_media_type_internal_serdes) {
			/* restore CTRL_EXT, steal
Exemplo n.º 17
0
static int igbvf_get_settings(struct net_device *netdev,
                              struct ethtool_cmd *ecmd)
{
	struct igbvf_adapter *adapter = netdev_priv(netdev);
	struct e1000_hw *hw = &adapter->hw;
	u32 status;

	ecmd->supported   = SUPPORTED_1000baseT_Full;

	ecmd->advertising = ADVERTISED_1000baseT_Full;

	ecmd->port = -1;
	ecmd->transceiver = XCVR_DUMMY1;

	status = er32(STATUS);
	if (status & E1000_STATUS_LU) {
		if (status & E1000_STATUS_SPEED_1000)
			ecmd->speed = 1000;
		else if (status & E1000_STATUS_SPEED_100)
			ecmd->speed = 100;
		else
			ecmd->speed = 10;

		if (status & E1000_STATUS_FD)
			ecmd->duplex = DUPLEX_FULL;
		else
			ecmd->duplex = DUPLEX_HALF;
	} else {
		ecmd->speed = -1;
		ecmd->duplex = -1;
	}

	ecmd->autoneg = AUTONEG_DISABLE;

	return 0;
}
Exemplo n.º 18
0
/**
 * e1000e_phc_get_syncdevicetime - Callback given to timekeeping code reads system/device registers
 * @device: current device time
 * @system: system counter value read synchronously with device time
 * @ctx: context provided by timekeeping code
 *
 * Read device and system (ART) clock simultaneously and return the corrected
 * clock values in ns.
 **/
static int e1000e_phc_get_syncdevicetime(ktime_t *device,
					 struct system_counterval_t *system,
					 void *ctx)
{
	struct e1000_adapter *adapter = (struct e1000_adapter *)ctx;
	struct e1000_hw *hw = &adapter->hw;
	unsigned long flags;
	int i;
	u32 tsync_ctrl;
	u64 dev_cycles;
	u64 sys_cycles;

	tsync_ctrl = er32(TSYNCTXCTL);
	tsync_ctrl |= E1000_TSYNCTXCTL_START_SYNC |
		E1000_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK;
	ew32(TSYNCTXCTL, tsync_ctrl);
	for (i = 0; i < MAX_HW_WAIT_COUNT; ++i) {
		udelay(1);
		tsync_ctrl = er32(TSYNCTXCTL);
		if (tsync_ctrl & E1000_TSYNCTXCTL_SYNC_COMP)
			break;
	}

	if (i == MAX_HW_WAIT_COUNT)
		return -ETIMEDOUT;

	dev_cycles = er32(SYSSTMPH);
	dev_cycles <<= 32;
	dev_cycles |= er32(SYSSTMPL);
	spin_lock_irqsave(&adapter->systim_lock, flags);
	*device = ns_to_ktime(timecounter_cyc2time(&adapter->tc, dev_cycles));
	spin_unlock_irqrestore(&adapter->systim_lock, flags);

	sys_cycles = er32(PLTSTMPH);
	sys_cycles <<= 32;
	sys_cycles |= er32(PLTSTMPL);
	*system = convert_art_to_tsc(sys_cycles);

	return 0;
}
Exemplo n.º 19
0
static int e1000_setup_desc_rings(struct e1000_adapter *adapter)
{
	struct e1000_ring *tx_ring = &adapter->test_tx_ring;
	struct e1000_ring *rx_ring = &adapter->test_rx_ring;
	struct pci_dev *pdev = adapter->pdev;
	struct e1000_hw *hw = &adapter->hw;
	u32 rctl;
	int i;
	int ret_val;

	/* Setup Tx descriptor ring and Tx buffers */

	if (!tx_ring->count)
		tx_ring->count = E1000_DEFAULT_TXD;

	tx_ring->buffer_info = kcalloc(tx_ring->count,
				       sizeof(struct e1000_buffer),
				       GFP_KERNEL);
	if (!(tx_ring->buffer_info)) {
		ret_val = 1;
		goto err_nomem;
	}

	tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc);
	tx_ring->size = ALIGN(tx_ring->size, 4096);
	tx_ring->desc = dma_alloc_coherent(&pdev->dev, tx_ring->size,
					   &tx_ring->dma, GFP_KERNEL);
	if (!tx_ring->desc) {
		ret_val = 2;
		goto err_nomem;
	}
	tx_ring->next_to_use = 0;
	tx_ring->next_to_clean = 0;

	ew32(TDBAL, ((u64) tx_ring->dma & 0x00000000FFFFFFFF));
	ew32(TDBAH, ((u64) tx_ring->dma >> 32));
	ew32(TDLEN, tx_ring->count * sizeof(struct e1000_tx_desc));
	ew32(TDH, 0);
	ew32(TDT, 0);
	ew32(TCTL, E1000_TCTL_PSP | E1000_TCTL_EN | E1000_TCTL_MULR |
	     E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT |
	     E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT);

	for (i = 0; i < tx_ring->count; i++) {
		struct e1000_tx_desc *tx_desc = E1000_TX_DESC(*tx_ring, i);
		struct sk_buff *skb;
		unsigned int skb_size = 1024;

		skb = alloc_skb(skb_size, GFP_KERNEL);
		if (!skb) {
			ret_val = 3;
			goto err_nomem;
		}
		skb_put(skb, skb_size);
		tx_ring->buffer_info[i].skb = skb;
		tx_ring->buffer_info[i].length = skb->len;
		tx_ring->buffer_info[i].dma =
			pci_map_single(pdev, skb->data, skb->len,
				       PCI_DMA_TODEVICE);
		if (pci_dma_mapping_error(pdev, tx_ring->buffer_info[i].dma)) {
			ret_val = 4;
			goto err_nomem;
		}
		tx_desc->buffer_addr = cpu_to_le64(tx_ring->buffer_info[i].dma);
		tx_desc->lower.data = cpu_to_le32(skb->len);
		tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP |
						   E1000_TXD_CMD_IFCS |
						   E1000_TXD_CMD_RS);
		tx_desc->upper.data = 0;
	}

	/* Setup Rx descriptor ring and Rx buffers */

	if (!rx_ring->count)
		rx_ring->count = E1000_DEFAULT_RXD;

	rx_ring->buffer_info = kcalloc(rx_ring->count,
				       sizeof(struct e1000_buffer),
				       GFP_KERNEL);
	if (!(rx_ring->buffer_info)) {
		ret_val = 5;
		goto err_nomem;
	}

	rx_ring->size = rx_ring->count * sizeof(struct e1000_rx_desc);
	rx_ring->desc = dma_alloc_coherent(&pdev->dev, rx_ring->size,
					   &rx_ring->dma, GFP_KERNEL);
	if (!rx_ring->desc) {
		ret_val = 6;
		goto err_nomem;
	}
	rx_ring->next_to_use = 0;
	rx_ring->next_to_clean = 0;

	rctl = er32(RCTL);
	ew32(RCTL, rctl & ~E1000_RCTL_EN);
	ew32(RDBAL, ((u64) rx_ring->dma & 0xFFFFFFFF));
	ew32(RDBAH, ((u64) rx_ring->dma >> 32));
	ew32(RDLEN, rx_ring->size);
	ew32(RDH, 0);
	ew32(RDT, 0);
	rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 |
		E1000_RCTL_UPE | E1000_RCTL_MPE | E1000_RCTL_LPE |
		E1000_RCTL_SBP | E1000_RCTL_SECRC |
		E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
		(adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT);
	ew32(RCTL, rctl);

	for (i = 0; i < rx_ring->count; i++) {
		struct e1000_rx_desc *rx_desc = E1000_RX_DESC(*rx_ring, i);
		struct sk_buff *skb;

		skb = alloc_skb(2048 + NET_IP_ALIGN, GFP_KERNEL);
		if (!skb) {
			ret_val = 7;
			goto err_nomem;
		}
		skb_reserve(skb, NET_IP_ALIGN);
		rx_ring->buffer_info[i].skb = skb;
		rx_ring->buffer_info[i].dma =
			pci_map_single(pdev, skb->data, 2048,
				       PCI_DMA_FROMDEVICE);
		if (pci_dma_mapping_error(pdev, rx_ring->buffer_info[i].dma)) {
			ret_val = 8;
			goto err_nomem;
		}
		rx_desc->buffer_addr =
			cpu_to_le64(rx_ring->buffer_info[i].dma);
		memset(skb->data, 0x00, skb->len);
	}

	return 0;

err_nomem:
	e1000_free_desc_rings(adapter);
	return ret_val;
}
Exemplo n.º 20
0
static s32 e1000e_get_variants_82571(struct e1000_adapter *adapter)
{
	struct e1000_hw *hw = &adapter->hw;
	static int global_quad_port_a; /* global port a indication */
	struct pci_device *pdev = adapter->pdev;
	u16 eeprom_data = 0;
	int is_port_b = er32(STATUS) & E1000_STATUS_FUNC_1;

	/* tag quad port adapters first, it's used below */
	switch (pdev->device) {
	case E1000_DEV_ID_82571EB_QUAD_COPPER:
	case E1000_DEV_ID_82571EB_QUAD_FIBER:
	case E1000_DEV_ID_82571EB_QUAD_COPPER_LP:
	case E1000_DEV_ID_82571PT_QUAD_COPPER:
		adapter->flags |= FLAG_IS_QUAD_PORT;
		/* mark the first port */
		if (global_quad_port_a == 0)
			adapter->flags |= FLAG_IS_QUAD_PORT_A;
		/* Reset for multiple quad port adapters */
		global_quad_port_a++;
		if (global_quad_port_a == 4)
			global_quad_port_a = 0;
		break;
	default:
		break;
	}

	switch (adapter->hw.mac.type) {
	case e1000_82571:
		/* these dual ports don't have WoL on port B at all */
		if (((pdev->device == E1000_DEV_ID_82571EB_FIBER) ||
		     (pdev->device == E1000_DEV_ID_82571EB_SERDES) ||
		     (pdev->device == E1000_DEV_ID_82571EB_COPPER)) &&
		    (is_port_b))
			adapter->flags &= ~FLAG_HAS_WOL;
		/* quad ports only support WoL on port A */
		if (adapter->flags & FLAG_IS_QUAD_PORT &&
		    (!(adapter->flags & FLAG_IS_QUAD_PORT_A)))
			adapter->flags &= ~FLAG_HAS_WOL;
		/* Does not support WoL on any port */
		if (pdev->device == E1000_DEV_ID_82571EB_SERDES_QUAD)
			adapter->flags &= ~FLAG_HAS_WOL;
		break;

	case e1000_82573:
		if (pdev->device == E1000_DEV_ID_82573L) {
			if (e1000e_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1,
					   &eeprom_data) < 0)
				break;
			if (!(eeprom_data & NVM_WORD1A_ASPM_MASK)) {
				adapter->flags |= FLAG_HAS_JUMBO_FRAMES;
				adapter->max_hw_frame_size = DEFAULT_JUMBO;
			}
		}
		break;

	default:
		break;
	}

	return 0;
}
Exemplo n.º 21
0
/**
 * e1000_configure_tx - Configure 8254x Transmit Unit after Reset
 * @adapter: board private structure
 *
 * Configure the Tx unit of the MAC after a reset.
 **/
static void e1000e_configure_tx ( struct e1000_adapter *adapter )
{
	struct e1000_hw *hw = &adapter->hw;
	u32 tctl, tipg, tarc;
	u32 ipgr1, ipgr2;

	DBGP ( "e1000_configure_tx\n" );

	/* disable transmits while setting up the descriptors */
	tctl = E1000_READ_REG ( hw, E1000_TCTL );
	E1000_WRITE_REG ( hw, E1000_TCTL, tctl & ~E1000_TCTL_EN );
	e1e_flush();
	mdelay(10);

	E1000_WRITE_REG ( hw, E1000_TDBAH(0), 0 );
	E1000_WRITE_REG ( hw, E1000_TDBAL(0), virt_to_bus ( adapter->tx_base ) );
	E1000_WRITE_REG ( hw, E1000_TDLEN(0), adapter->tx_ring_size );

	DBG ( "E1000_TDBAL(0): %#08x\n",  E1000_READ_REG ( hw, E1000_TDBAL(0) ) );
	DBG ( "E1000_TDLEN(0): %d\n",	  E1000_READ_REG ( hw, E1000_TDLEN(0) ) );

	/* Setup the HW Tx Head and Tail descriptor pointers */
	E1000_WRITE_REG ( hw, E1000_TDH(0), 0 );
	E1000_WRITE_REG ( hw, E1000_TDT(0), 0 );

	adapter->tx_head = 0;
	adapter->tx_tail = 0;
	adapter->tx_fill_ctr = 0;

	/* Set the default values for the Tx Inter Packet Gap timer */
	tipg = DEFAULT_82543_TIPG_IPGT_COPPER;		/*  8  */
	ipgr1 = DEFAULT_82543_TIPG_IPGR1;		/*  8  */
	ipgr2 = DEFAULT_82543_TIPG_IPGR2;		/*  6  */

	if (adapter->flags & FLAG_TIPG_MEDIUM_FOR_80003ESLAN)
		ipgr2 = DEFAULT_80003ES2LAN_TIPG_IPGR2; /*  7  */

	tipg |= ipgr1 << E1000_TIPG_IPGR1_SHIFT;
	tipg |= ipgr2 << E1000_TIPG_IPGR2_SHIFT;
	ew32(TIPG, tipg);

	/* Program the Transmit Control Register */
	tctl = er32(TCTL);
	tctl &= ~E1000_TCTL_CT;
	tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
		(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);

	if (adapter->flags & FLAG_TARC_SPEED_MODE_BIT) {
		tarc = er32(TARC(0));
		/*
		 * set the speed mode bit, we'll clear it if we're not at
		 * gigabit link later
		 */
#define SPEED_MODE_BIT (1 << 21)
		tarc |= SPEED_MODE_BIT;
		ew32(TARC(0), tarc);
	}

	/* errata: program both queues to unweighted RR */
	if (adapter->flags & FLAG_TARC_SET_BIT_ZERO) {
		tarc = er32(TARC(0));
		tarc |= 1;
		ew32(TARC(0), tarc);
		tarc = er32(TARC(1));
		tarc |= 1;
		ew32(TARC(1), tarc);
	}

	/* Setup Transmit Descriptor Settings for eop descriptor */
	adapter->txd_cmd = E1000_TXD_CMD_EOP | E1000_TXD_CMD_IFCS;

	/* enable Report Status bit */
	adapter->txd_cmd |= E1000_TXD_CMD_RS;

	/*
	 * enable transmits in the hardware, need to do this
	 * after setting TARC(0)
	 */
	tctl |= E1000_TCTL_EN;
	ew32(TCTL, tctl);
	e1e_flush();

	e1000e_config_collision_dist(hw);
}
Exemplo n.º 22
0
static int e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
{
	struct e1000_hw *hw = &adapter->hw;
	u32 ctrl_reg = 0;
	u32 stat_reg = 0;
	u16 phy_reg = 0;

	hw->mac.autoneg = 0;

	if (hw->phy.type == e1000_phy_m88) {
		/* Auto-MDI/MDIX Off */
		e1e_wphy(hw, M88E1000_PHY_SPEC_CTRL, 0x0808);
		/* reset to update Auto-MDI/MDIX */
		e1e_wphy(hw, PHY_CONTROL, 0x9140);
		/* autoneg off */
		e1e_wphy(hw, PHY_CONTROL, 0x8140);
	} else if (hw->phy.type == e1000_phy_gg82563)
		e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, 0x1CC);

	ctrl_reg = er32(CTRL);

	switch (hw->phy.type) {
	case e1000_phy_ife:
		/* force 100, set loopback */
		e1e_wphy(hw, PHY_CONTROL, 0x6100);

		/* Now set up the MAC to the same speed/duplex as the PHY. */
		ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
		ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
			     E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
			     E1000_CTRL_SPD_100 |/* Force Speed to 100 */
			     E1000_CTRL_FD);	 /* Force Duplex to FULL */
		break;
	case e1000_phy_bm:
		/* Set Default MAC Interface speed to 1GB */
		e1e_rphy(hw, PHY_REG(2, 21), &phy_reg);
		phy_reg &= ~0x0007;
		phy_reg |= 0x006;
		e1e_wphy(hw, PHY_REG(2, 21), phy_reg);
		/* Assert SW reset for above settings to take effect */
		e1000e_commit_phy(hw);
		mdelay(1);
		/* Force Full Duplex */
		e1e_rphy(hw, PHY_REG(769, 16), &phy_reg);
		e1e_wphy(hw, PHY_REG(769, 16), phy_reg | 0x000C);
		/* Set Link Up (in force link) */
		e1e_rphy(hw, PHY_REG(776, 16), &phy_reg);
		e1e_wphy(hw, PHY_REG(776, 16), phy_reg | 0x0040);
		/* Force Link */
		e1e_rphy(hw, PHY_REG(769, 16), &phy_reg);
		e1e_wphy(hw, PHY_REG(769, 16), phy_reg | 0x0040);
		/* Set Early Link Enable */
		e1e_rphy(hw, PHY_REG(769, 20), &phy_reg);
		e1e_wphy(hw, PHY_REG(769, 20), phy_reg | 0x0400);
		/* fall through */
	default:
		/* force 1000, set loopback */
		e1e_wphy(hw, PHY_CONTROL, 0x4140);
		mdelay(250);

		/* Now set up the MAC to the same speed/duplex as the PHY. */
		ctrl_reg = er32(CTRL);
		ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
		ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
			     E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
			     E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
			     E1000_CTRL_FD);	 /* Force Duplex to FULL */

		if (adapter->flags & FLAG_IS_ICH)
			ctrl_reg |= E1000_CTRL_SLU;	/* Set Link Up */
	}

	if (hw->phy.media_type == e1000_media_type_copper &&
	    hw->phy.type == e1000_phy_m88) {
		ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
	} else {
		/*
		 * Set the ILOS bit on the fiber Nic if half duplex link is
		 * detected.
		 */
		stat_reg = er32(STATUS);
		if ((stat_reg & E1000_STATUS_FD) == 0)
			ctrl_reg |= (E1000_CTRL_ILOS | E1000_CTRL_SLU);
	}

	ew32(CTRL, ctrl_reg);

	/*
	 * Disable the receiver on the PHY so when a cable is plugged in, the
	 * PHY does not begin to autoneg when a cable is reconnected to the NIC.
	 */
	if (hw->phy.type == e1000_phy_m88)
		e1000_phy_disable_receiver(adapter);

	udelay(500);

	return 0;
}
Exemplo n.º 23
0
Arquivo: ethtool.c Projeto: A-K/linux
static int e1000_get_settings(struct net_device *netdev,
			      struct ethtool_cmd *ecmd)
{
	struct e1000_adapter *adapter = netdev_priv(netdev);
	struct e1000_hw *hw = &adapter->hw;
	u32 speed;

	if (hw->phy.media_type == e1000_media_type_copper) {

		ecmd->supported = (SUPPORTED_10baseT_Half |
				   SUPPORTED_10baseT_Full |
				   SUPPORTED_100baseT_Half |
				   SUPPORTED_100baseT_Full |
				   SUPPORTED_1000baseT_Full |
				   SUPPORTED_Autoneg |
				   SUPPORTED_TP);
		if (hw->phy.type == e1000_phy_ife)
			ecmd->supported &= ~SUPPORTED_1000baseT_Full;
		ecmd->advertising = ADVERTISED_TP;

		if (hw->mac.autoneg == 1) {
			ecmd->advertising |= ADVERTISED_Autoneg;
			/* the e1000 autoneg seems to match ethtool nicely */
			ecmd->advertising |= hw->phy.autoneg_advertised;
		}

		ecmd->port = PORT_TP;
		ecmd->phy_address = hw->phy.addr;
		ecmd->transceiver = XCVR_INTERNAL;

	} else {
		ecmd->supported   = (SUPPORTED_1000baseT_Full |
				     SUPPORTED_FIBRE |
				     SUPPORTED_Autoneg);

		ecmd->advertising = (ADVERTISED_1000baseT_Full |
				     ADVERTISED_FIBRE |
				     ADVERTISED_Autoneg);

		ecmd->port = PORT_FIBRE;
		ecmd->transceiver = XCVR_EXTERNAL;
	}

	speed = -1;
	ecmd->duplex = -1;

	if (netif_running(netdev)) {
		if (netif_carrier_ok(netdev)) {
			speed = adapter->link_speed;
			ecmd->duplex = adapter->link_duplex - 1;
		}
	} else {
		u32 status = er32(STATUS);
		if (status & E1000_STATUS_LU) {
			if (status & E1000_STATUS_SPEED_1000)
				speed = SPEED_1000;
			else if (status & E1000_STATUS_SPEED_100)
				speed = SPEED_100;
			else
				speed = SPEED_10;

			if (status & E1000_STATUS_FD)
				ecmd->duplex = DUPLEX_FULL;
			else
				ecmd->duplex = DUPLEX_HALF;
		}
	}

	ethtool_cmd_speed_set(ecmd, speed);
	ecmd->autoneg = ((hw->phy.media_type == e1000_media_type_fiber) ||
			 hw->mac.autoneg) ? AUTONEG_ENABLE : AUTONEG_DISABLE;

	/* MDI-X => 2; MDI =>1; Invalid =>0 */
	if ((hw->phy.media_type == e1000_media_type_copper) &&
	    netif_carrier_ok(netdev))
		ecmd->eth_tp_mdix = hw->phy.is_mdix ? ETH_TP_MDI_X :
		                                      ETH_TP_MDI;
	else
		ecmd->eth_tp_mdix = ETH_TP_MDI_INVALID;

	if (hw->phy.mdix == AUTO_ALL_MODES)
		ecmd->eth_tp_mdix_ctrl = ETH_TP_MDI_AUTO;
	else
		ecmd->eth_tp_mdix_ctrl = hw->phy.mdix;

	return 0;
}
Exemplo n.º 24
0
Arquivo: ethtool.c Projeto: A-K/linux
static void e1000_get_regs(struct net_device *netdev,
			   struct ethtool_regs *regs, void *p)
{
	struct e1000_adapter *adapter = netdev_priv(netdev);
	struct e1000_hw *hw = &adapter->hw;
	u32 *regs_buff = p;
	u16 phy_data;

	memset(p, 0, E1000_REGS_LEN * sizeof(u32));

	regs->version = (1 << 24) | (adapter->pdev->revision << 16) |
			adapter->pdev->device;

	regs_buff[0]  = er32(CTRL);
	regs_buff[1]  = er32(STATUS);

	regs_buff[2]  = er32(RCTL);
	regs_buff[3]  = er32(RDLEN(0));
	regs_buff[4]  = er32(RDH(0));
	regs_buff[5]  = er32(RDT(0));
	regs_buff[6]  = er32(RDTR);

	regs_buff[7]  = er32(TCTL);
	regs_buff[8]  = er32(TDLEN(0));
	regs_buff[9]  = er32(TDH(0));
	regs_buff[10] = er32(TDT(0));
	regs_buff[11] = er32(TIDV);

	regs_buff[12] = adapter->hw.phy.type;  /* PHY type (IGP=1, M88=0) */

	/* ethtool doesn't use anything past this point, so all this
	 * code is likely legacy junk for apps that may or may not
	 * exist */
	if (hw->phy.type == e1000_phy_m88) {
		e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
		regs_buff[13] = (u32)phy_data; /* cable length */
		regs_buff[14] = 0;  /* Dummy (to align w/ IGP phy reg dump) */
		regs_buff[15] = 0;  /* Dummy (to align w/ IGP phy reg dump) */
		regs_buff[16] = 0;  /* Dummy (to align w/ IGP phy reg dump) */
		e1e_rphy(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
		regs_buff[17] = (u32)phy_data; /* extended 10bt distance */
		regs_buff[18] = regs_buff[13]; /* cable polarity */
		regs_buff[19] = 0;  /* Dummy (to align w/ IGP phy reg dump) */
		regs_buff[20] = regs_buff[17]; /* polarity correction */
		/* phy receive errors */
		regs_buff[22] = adapter->phy_stats.receive_errors;
		regs_buff[23] = regs_buff[13]; /* mdix mode */
	}
	regs_buff[21] = 0; /* was idle_errors */
	e1e_rphy(hw, PHY_1000T_STATUS, &phy_data);
	regs_buff[24] = (u32)phy_data;  /* phy local receiver status */
	regs_buff[25] = regs_buff[24];  /* phy remote receiver status */
}
Exemplo n.º 25
0
Arquivo: ethtool.c Projeto: A-K/linux
static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
{
	struct e1000_hw *hw = &adapter->hw;
	struct e1000_mac_info *mac = &adapter->hw.mac;
	u32 value;
	u32 before;
	u32 after;
	u32 i;
	u32 toggle;
	u32 mask;
	u32 wlock_mac = 0;

	/*
	 * The status register is Read Only, so a write should fail.
	 * Some bits that get toggled are ignored.
	 */
	switch (mac->type) {
	/* there are several bits on newer hardware that are r/w */
	case e1000_82571:
	case e1000_82572:
	case e1000_80003es2lan:
		toggle = 0x7FFFF3FF;
		break;
        default:
		toggle = 0x7FFFF033;
		break;
	}

	before = er32(STATUS);
	value = (er32(STATUS) & toggle);
	ew32(STATUS, toggle);
	after = er32(STATUS) & toggle;
	if (value != after) {
		e_err("failed STATUS register test got: 0x%08X expected: 0x%08X\n",
		      after, value);
		*data = 1;
		return 1;
	}
	/* restore previous status */
	ew32(STATUS, before);

	if (!(adapter->flags & FLAG_IS_ICH)) {
		REG_PATTERN_TEST(E1000_FCAL, 0xFFFFFFFF, 0xFFFFFFFF);
		REG_PATTERN_TEST(E1000_FCAH, 0x0000FFFF, 0xFFFFFFFF);
		REG_PATTERN_TEST(E1000_FCT, 0x0000FFFF, 0xFFFFFFFF);
		REG_PATTERN_TEST(E1000_VET, 0x0000FFFF, 0xFFFFFFFF);
	}

	REG_PATTERN_TEST(E1000_RDTR, 0x0000FFFF, 0xFFFFFFFF);
	REG_PATTERN_TEST(E1000_RDBAH(0), 0xFFFFFFFF, 0xFFFFFFFF);
	REG_PATTERN_TEST(E1000_RDLEN(0), 0x000FFF80, 0x000FFFFF);
	REG_PATTERN_TEST(E1000_RDH(0), 0x0000FFFF, 0x0000FFFF);
	REG_PATTERN_TEST(E1000_RDT(0), 0x0000FFFF, 0x0000FFFF);
	REG_PATTERN_TEST(E1000_FCRTH, 0x0000FFF8, 0x0000FFF8);
	REG_PATTERN_TEST(E1000_FCTTV, 0x0000FFFF, 0x0000FFFF);
	REG_PATTERN_TEST(E1000_TIPG, 0x3FFFFFFF, 0x3FFFFFFF);
	REG_PATTERN_TEST(E1000_TDBAH(0), 0xFFFFFFFF, 0xFFFFFFFF);
	REG_PATTERN_TEST(E1000_TDLEN(0), 0x000FFF80, 0x000FFFFF);

	REG_SET_AND_CHECK(E1000_RCTL, 0xFFFFFFFF, 0x00000000);

	before = ((adapter->flags & FLAG_IS_ICH) ? 0x06C3B33E : 0x06DFB3FE);
	REG_SET_AND_CHECK(E1000_RCTL, before, 0x003FFFFB);
	REG_SET_AND_CHECK(E1000_TCTL, 0xFFFFFFFF, 0x00000000);

	REG_SET_AND_CHECK(E1000_RCTL, before, 0xFFFFFFFF);
	REG_PATTERN_TEST(E1000_RDBAL(0), 0xFFFFFFF0, 0xFFFFFFFF);
	if (!(adapter->flags & FLAG_IS_ICH))
		REG_PATTERN_TEST(E1000_TXCW, 0xC000FFFF, 0x0000FFFF);
	REG_PATTERN_TEST(E1000_TDBAL(0), 0xFFFFFFF0, 0xFFFFFFFF);
	REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF);
	mask = 0x8003FFFF;
	switch (mac->type) {
	case e1000_ich10lan:
	case e1000_pchlan:
	case e1000_pch2lan:
	case e1000_pch_lpt:
		mask |= (1 << 18);
		break;
	default:
		break;
	}

	if (mac->type == e1000_pch_lpt)
		wlock_mac = (er32(FWSM) & E1000_FWSM_WLOCK_MAC_MASK) >>
		    E1000_FWSM_WLOCK_MAC_SHIFT;

	for (i = 0; i < mac->rar_entry_count; i++) {
		/* Cannot test write-protected SHRAL[n] registers */
		if ((wlock_mac == 1) || (wlock_mac && (i > wlock_mac)))
			continue;

		REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1),
				       mask, 0xFFFFFFFF);
	}

	for (i = 0; i < mac->mta_reg_count; i++)
		REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF);

	*data = 0;

	return 0;
}