⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 phy.c

📁 grub源码分析文档
💻 C
📖 第 1 页 / 共 4 页
字号:
		phy->remote_rx = e1000_1000t_rx_status_undefined;	}	return ret_val;}/** *  e1000e_get_phy_info_igp - Retrieve igp PHY information *  @hw: pointer to the HW structure * *  Read PHY status to determine if link is up.  If link is up, then *  set/determine 10base-T extended distance and polarity correction.  Read *  PHY port status to determine MDI/MDIx and speed.  Based on the speed, *  determine on the cable length, local and remote receiver. **/s32 e1000e_get_phy_info_igp(struct e1000_hw *hw){	struct e1000_phy_info *phy = &hw->phy;	s32 ret_val;	u16 data;	bool link;	ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link);	if (ret_val)		return ret_val;	if (!link) {		hw_dbg(hw, "Phy info is only valid if link is up\n");		return -E1000_ERR_CONFIG;	}	phy->polarity_correction = 1;	ret_val = e1000_check_polarity_igp(hw);	if (ret_val)		return ret_val;	ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_STATUS, &data);	if (ret_val)		return ret_val;	phy->is_mdix = (data & IGP01E1000_PSSR_MDIX);	if ((data & IGP01E1000_PSSR_SPEED_MASK) ==	    IGP01E1000_PSSR_SPEED_1000MBPS) {		ret_val = e1000_get_cable_length(hw);		if (ret_val)			return ret_val;		ret_val = e1e_rphy(hw, PHY_1000T_STATUS, &data);		if (ret_val)			return ret_val;		phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS)				? e1000_1000t_rx_status_ok				: e1000_1000t_rx_status_not_ok;		phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS)				 ? e1000_1000t_rx_status_ok				 : e1000_1000t_rx_status_not_ok;	} else {		phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;		phy->local_rx = e1000_1000t_rx_status_undefined;		phy->remote_rx = e1000_1000t_rx_status_undefined;	}	return ret_val;}/** *  e1000e_phy_sw_reset - PHY software reset *  @hw: pointer to the HW structure * *  Does a software reset of the PHY by reading the PHY control register and *  setting/write the control register reset bit to the PHY. **/s32 e1000e_phy_sw_reset(struct e1000_hw *hw){	s32 ret_val;	u16 phy_ctrl;	ret_val = e1e_rphy(hw, PHY_CONTROL, &phy_ctrl);	if (ret_val)		return ret_val;	phy_ctrl |= MII_CR_RESET;	ret_val = e1e_wphy(hw, PHY_CONTROL, phy_ctrl);	if (ret_val)		return ret_val;	udelay(1);	return ret_val;}/** *  e1000e_phy_hw_reset_generic - PHY hardware reset *  @hw: pointer to the HW structure * *  Verify the reset block is not blocking us from resetting.  Acquire *  semaphore (if necessary) and read/set/write the device control reset *  bit in the PHY.  Wait the appropriate delay time for the device to *  reset and release the semaphore (if necessary). **/s32 e1000e_phy_hw_reset_generic(struct e1000_hw *hw){	struct e1000_phy_info *phy = &hw->phy;	s32 ret_val;	u32 ctrl;	ret_val = e1000_check_reset_block(hw);	if (ret_val)		return 0;	ret_val = phy->ops.acquire_phy(hw);	if (ret_val)		return ret_val;	ctrl = er32(CTRL);	ew32(CTRL, ctrl | E1000_CTRL_PHY_RST);	e1e_flush();	udelay(phy->reset_delay_us);	ew32(CTRL, ctrl);	e1e_flush();	udelay(150);	phy->ops.release_phy(hw);	return e1000_get_phy_cfg_done(hw);}/** *  e1000e_get_cfg_done - Generic configuration done *  @hw: pointer to the HW structure * *  Generic function to wait 10 milli-seconds for configuration to complete *  and return success. **/s32 e1000e_get_cfg_done(struct e1000_hw *hw){	mdelay(10);	return 0;}/* Internal function pointers *//** *  e1000_get_phy_cfg_done - Generic PHY configuration done *  @hw: pointer to the HW structure * *  Return success if silicon family did not implement a family specific *  get_cfg_done function. **/static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw){	if (hw->phy.ops.get_cfg_done)		return hw->phy.ops.get_cfg_done(hw);	return 0;}/** *  e1000_phy_force_speed_duplex - Generic force PHY speed/duplex *  @hw: pointer to the HW structure * *  When the silicon family has not implemented a forced speed/duplex *  function for the PHY, simply return 0. **/static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw){	if (hw->phy.ops.force_speed_duplex)		return hw->phy.ops.force_speed_duplex(hw);	return 0;}/** *  e1000e_get_phy_type_from_id - Get PHY type from id *  @phy_id: phy_id read from the phy * *  Returns the phy type from the id. **/enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id){	enum e1000_phy_type phy_type = e1000_phy_unknown;	switch (phy_id) {	case M88E1000_I_PHY_ID:	case M88E1000_E_PHY_ID:	case M88E1111_I_PHY_ID:	case M88E1011_I_PHY_ID:		phy_type = e1000_phy_m88;		break;	case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */		phy_type = e1000_phy_igp_2;		break;	case GG82563_E_PHY_ID:		phy_type = e1000_phy_gg82563;		break;	case IGP03E1000_E_PHY_ID:		phy_type = e1000_phy_igp_3;		break;	case IFE_E_PHY_ID:	case IFE_PLUS_E_PHY_ID:	case IFE_C_E_PHY_ID:		phy_type = e1000_phy_ife;		break;	case BME1000_E_PHY_ID:	case BME1000_E_PHY_ID_R2:		phy_type = e1000_phy_bm;		break;	default:		phy_type = e1000_phy_unknown;		break;	}	return phy_type;}/** *  e1000e_determine_phy_address - Determines PHY address. *  @hw: pointer to the HW structure * *  This uses a trial and error method to loop through possible PHY *  addresses. It tests each by reading the PHY ID registers and *  checking for a match. **/s32 e1000e_determine_phy_address(struct e1000_hw *hw){	s32 ret_val = -E1000_ERR_PHY_TYPE;	u32 phy_addr= 0;	u32 i = 0;	enum e1000_phy_type phy_type = e1000_phy_unknown;	do {		for (phy_addr = 0; phy_addr < 4; phy_addr++) {			hw->phy.addr = phy_addr;			e1000e_get_phy_id(hw);			phy_type = e1000e_get_phy_type_from_id(hw->phy.id);			/* 			 * If phy_type is valid, break - we found our			 * PHY address			 */			if (phy_type  != e1000_phy_unknown) {				ret_val = 0;				break;			}		}		i++;	} while ((ret_val != 0) && (i < 100));	return ret_val;}/** *  e1000_get_phy_addr_for_bm_page - Retrieve PHY page address *  @page: page to access * *  Returns the phy address for the page requested. **/static u32 e1000_get_phy_addr_for_bm_page(u32 page, u32 reg){	u32 phy_addr = 2;	if ((page >= 768) || (page == 0 && reg == 25) || (reg == 31))		phy_addr = 1;	return phy_addr;}/** *  e1000e_write_phy_reg_bm - Write BM PHY register *  @hw: pointer to the HW structure *  @offset: register offset to write to *  @data: data to write at register offset * *  Acquires semaphore, if necessary, then writes the data to PHY register *  at the offset.  Release any acquired semaphores before exiting. **/s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data){	s32 ret_val;	u32 page_select = 0;	u32 page = offset >> IGP_PAGE_SHIFT;	u32 page_shift = 0;	/* Page 800 works differently than the rest so it has its own func */	if (page == BM_WUC_PAGE) {		ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data,							 FALSE);		goto out;	}	ret_val = hw->phy.ops.acquire_phy(hw);	if (ret_val)		goto out;	hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);	if (offset > MAX_PHY_MULTI_PAGE_REG) {		/*		 * Page select is register 31 for phy address 1 and 22 for		 * phy address 2 and 3. Page select is shifted only for		 * phy address 1.		 */		if (hw->phy.addr == 1) {			page_shift = IGP_PAGE_SHIFT;			page_select = IGP01E1000_PHY_PAGE_SELECT;		} else {			page_shift = 0;			page_select = BM_PHY_PAGE_SELECT;		}		/* Page is shifted left, PHY expects (page x 32) */		ret_val = e1000e_write_phy_reg_mdic(hw, page_select,		                                    (page << page_shift));		if (ret_val) {			hw->phy.ops.release_phy(hw);			goto out;		}	}	ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,	                                    data);	hw->phy.ops.release_phy(hw);out:	return ret_val;}/** *  e1000e_read_phy_reg_bm - Read BM PHY register *  @hw: pointer to the HW structure *  @offset: register offset to be read *  @data: pointer to the read data * *  Acquires semaphore, if necessary, then reads the PHY register at offset *  and storing the retrieved information in data.  Release any acquired *  semaphores before exiting. **/s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data){	s32 ret_val;	u32 page_select = 0;	u32 page = offset >> IGP_PAGE_SHIFT;	u32 page_shift = 0;	/* Page 800 works differently than the rest so it has its own func */	if (page == BM_WUC_PAGE) {		ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data,							 TRUE);		goto out;	}	ret_val = hw->phy.ops.acquire_phy(hw);	if (ret_val)		goto out;	hw->phy.addr = e1000_get_phy_addr_for_bm_page(page, offset);	if (offset > MAX_PHY_MULTI_PAGE_REG) {		/*		 * Page select is register 31 for phy address 1 and 22 for		 * phy address 2 and 3. Page select is shifted only for		 * phy address 1.		 */		if (hw->phy.addr == 1) {			page_shift = IGP_PAGE_SHIFT;			page_select = IGP01E1000_PHY_PAGE_SELECT;		} else {			page_shift = 0;			page_select = BM_PHY_PAGE_SELECT;		}		/* Page is shifted left, PHY expects (page x 32) */		ret_val = e1000e_write_phy_reg_mdic(hw, page_select,		                                    (page << page_shift));		if (ret_val) {			hw->phy.ops.release_phy(hw);			goto out;		}	}	ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,	                                   data);	hw->phy.ops.release_phy(hw);out:	return ret_val;}/** *  e1000_access_phy_wakeup_reg_bm - Read BM PHY wakeup register *  @hw: pointer to the HW structure *  @offset: register offset to be read or written *  @data: pointer to the data to read or write *  @read: determines if operation is read or write * *  Acquires semaphore, if necessary, then reads the PHY register at offset *  and storing the retrieved information in data.  Release any acquired *  semaphores before exiting. Note that procedure to read the wakeup *  registers are different. It works as such: *  1) Set page 769, register 17, bit 2 = 1 *  2) Set page to 800 for host (801 if we were manageability) *  3) Write the address using the address opcode (0x11) *  4) Read or write the data using the data opcode (0x12) *  5) Restore 769_17.2 to its original value **/static s32 e1000_access_phy_wakeup_reg_bm(struct e1000_hw *hw, u32 offset,					  u16 *data, bool read){	s32 ret_val;	u16 reg = ((u16)offset) & PHY_REG_MASK;	u16 phy_reg = 0;	u8  phy_acquired = 1;	ret_val = hw->phy.ops.acquire_phy(hw);	if (ret_val) {		phy_acquired = 0;		goto out;	}	/* All operations in this function are phy address 1 */	hw->phy.addr = 1;	/* Set page 769 */	e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,	                          (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT));	ret_val = e1000e_read_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, &phy_reg);	if (ret_val)		goto out;	/* First clear bit 4 to avoid a power state change */	phy_reg &= ~(BM_WUC_HOST_WU_BIT);	ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);	if (ret_val)		goto out;	/* Write bit 2 = 1, and clear bit 4 to 769_17 */	ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG,	                                    phy_reg | BM_WUC_ENABLE_BIT);	if (ret_val)		goto out;	/* Select page 800 */	ret_val = e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,	                                    (BM_WUC_PAGE << IGP_PAGE_SHIFT));	/* Write the page 800 offset value using opcode 0x11 */	ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ADDRESS_OPCODE, reg);	if (ret_val)		goto out;	if (read) {	        /* Read the page 800 value using opcode 0x12 */		ret_val = e1000e_read_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,		                                   data);	} else {	        /* Read the page 800 value using opcode 0x12 */		ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_DATA_OPCODE,						    *data);	}	if (ret_val)		goto out;	/*	 * Restore 769_17.2 to its original value	 * Set page 769	 */	e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT,	                          (BM_WUC_ENABLE_PAGE << IGP_PAGE_SHIFT));	/* Clear 769_17.2 */	ret_val = e1000e_write_phy_reg_mdic(hw, BM_WUC_ENABLE_REG, phy_reg);out:	if (phy_acquired == 1)		hw->phy.ops.release_phy(hw);	return ret_val;}/** *  e1000e_commit_phy - Soft PHY reset *  @hw: pointer to the HW structure * *  Performs a soft PHY reset on those that apply. This is a function pointer *  entry point called by drivers. **/s32 e1000e_commit_phy(struct e1000_hw *hw){	if (hw->phy.ops.commit_phy)		return hw->phy.ops.commit_phy(hw);	return 0;}/** *  e1000_set_d0_lplu_state - Sets low power link up state for D0 *  @hw: pointer to the HW structure *  @active: boolean used to enable/disable lplu * *  Success returns 0, Failure returns 1 * *  The low power link up (lplu) state is set to the power management level D0 *  and SmartSpeed is disabled when active is true, else clear lplu for D0 *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU *  is used during Dx states where the power conservation is most important. *  During driver activity, SmartSpeed should be enabled so performance is *  maintained.  This is a function pointer entry point called by drivers. **/static s32 e1000_set_d0_lplu_state(struct e1000_hw *hw, bool active){	if (hw->phy.ops.set_d0_lplu_state)		return hw->phy.ops.set_d0_lplu_state(hw, active);	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -