12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316 |
- /*******************************************************************************
- Intel 10 Gigabit PCI Express Linux driver
- Copyright(c) 1999 - 2009 Intel Corporation.
- This program is free software; you can redistribute it and/or modify it
- under the terms and conditions of the GNU General Public License,
- version 2, as published by the Free Software Foundation.
- This program is distributed in the hope it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- more details.
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- The full GNU General Public License is included in this distribution in
- the file called "COPYING".
- Contact Information:
- e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
- Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *******************************************************************************/
- #include <linux/pci.h>
- #include <linux/delay.h>
- #include <linux/sched.h>
- #include "ixgbe_common.h"
- #include "ixgbe_phy.h"
- static void ixgbe_i2c_start(struct ixgbe_hw *hw);
- static void ixgbe_i2c_stop(struct ixgbe_hw *hw);
- static s32 ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data);
- static s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data);
- static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw);
- static s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data);
- static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data);
- static s32 ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl);
- static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl);
- static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data);
- static bool ixgbe_get_i2c_data(u32 *i2cctl);
- static void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw);
- static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr);
- static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id);
- static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw);
- /**
- * ixgbe_identify_phy_generic - Get physical layer module
- * @hw: pointer to hardware structure
- *
- * Determines the physical layer module found on the current adapter.
- **/
- s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw)
- {
- s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
- u32 phy_addr;
- if (hw->phy.type == ixgbe_phy_unknown) {
- for (phy_addr = 0; phy_addr < IXGBE_MAX_PHY_ADDR; phy_addr++) {
- if (ixgbe_validate_phy_addr(hw, phy_addr)) {
- hw->phy.addr = phy_addr;
- ixgbe_get_phy_id(hw);
- hw->phy.type =
- ixgbe_get_phy_type_from_id(hw->phy.id);
- status = 0;
- break;
- }
- }
- } else {
- status = 0;
- }
- return status;
- }
- /**
- * ixgbe_validate_phy_addr - Determines phy address is valid
- * @hw: pointer to hardware structure
- *
- **/
- static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr)
- {
- u16 phy_id = 0;
- bool valid = false;
- hw->phy.addr = phy_addr;
- hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH,
- IXGBE_MDIO_PMA_PMD_DEV_TYPE, &phy_id);
- if (phy_id != 0xFFFF && phy_id != 0x0)
- valid = true;
- return valid;
- }
- /**
- * ixgbe_get_phy_id - Get the phy type
- * @hw: pointer to hardware structure
- *
- **/
- static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw)
- {
- u32 status;
- u16 phy_id_high = 0;
- u16 phy_id_low = 0;
- status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_HIGH,
- IXGBE_MDIO_PMA_PMD_DEV_TYPE,
- &phy_id_high);
- if (status == 0) {
- hw->phy.id = (u32)(phy_id_high << 16);
- status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_ID_LOW,
- IXGBE_MDIO_PMA_PMD_DEV_TYPE,
- &phy_id_low);
- hw->phy.id |= (u32)(phy_id_low & IXGBE_PHY_REVISION_MASK);
- hw->phy.revision = (u32)(phy_id_low & ~IXGBE_PHY_REVISION_MASK);
- }
- return status;
- }
- /**
- * ixgbe_get_phy_type_from_id - Get the phy type
- * @hw: pointer to hardware structure
- *
- **/
- static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id)
- {
- enum ixgbe_phy_type phy_type;
- switch (phy_id) {
- case TN1010_PHY_ID:
- phy_type = ixgbe_phy_tn;
- break;
- case QT2022_PHY_ID:
- phy_type = ixgbe_phy_qt;
- break;
- case ATH_PHY_ID:
- phy_type = ixgbe_phy_nl;
- break;
- default:
- phy_type = ixgbe_phy_unknown;
- break;
- }
- return phy_type;
- }
- /**
- * ixgbe_reset_phy_generic - Performs a PHY reset
- * @hw: pointer to hardware structure
- **/
- s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw)
- {
- /*
- * Perform soft PHY reset to the PHY_XS.
- * This will cause a soft reset to the PHY
- */
- return hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
- IXGBE_MDIO_PHY_XS_DEV_TYPE,
- IXGBE_MDIO_PHY_XS_RESET);
- }
- /**
- * ixgbe_read_phy_reg_generic - Reads a value from a specified PHY register
- * @hw: pointer to hardware structure
- * @reg_addr: 32 bit address of PHY register to read
- * @phy_data: Pointer to read data from PHY register
- **/
- s32 ixgbe_read_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
- u32 device_type, u16 *phy_data)
- {
- u32 command;
- u32 i;
- u32 data;
- s32 status = 0;
- u16 gssr;
- if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
- gssr = IXGBE_GSSR_PHY1_SM;
- else
- gssr = IXGBE_GSSR_PHY0_SM;
- if (ixgbe_acquire_swfw_sync(hw, gssr) != 0)
- status = IXGBE_ERR_SWFW_SYNC;
- if (status == 0) {
- /* Setup and write the address cycle command */
- command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) |
- (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
- (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
- (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
- IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
- /*
- * Check every 10 usec to see if the address cycle completed.
- * The MDI Command bit will clear when the operation is
- * complete
- */
- for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
- udelay(10);
- command = IXGBE_READ_REG(hw, IXGBE_MSCA);
- if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
- break;
- }
- if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
- hw_dbg(hw, "PHY address command did not complete.\n");
- status = IXGBE_ERR_PHY;
- }
- if (status == 0) {
- /*
- * Address cycle complete, setup and write the read
- * command
- */
- command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) |
- (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
- (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
- (IXGBE_MSCA_READ | IXGBE_MSCA_MDI_COMMAND));
- IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
- /*
- * Check every 10 usec to see if the address cycle
- * completed. The MDI Command bit will clear when the
- * operation is complete
- */
- for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
- udelay(10);
- command = IXGBE_READ_REG(hw, IXGBE_MSCA);
- if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
- break;
- }
- if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
- hw_dbg(hw, "PHY read command didn't complete\n");
- status = IXGBE_ERR_PHY;
- } else {
- /*
- * Read operation is complete. Get the data
- * from MSRWD
- */
- data = IXGBE_READ_REG(hw, IXGBE_MSRWD);
- data >>= IXGBE_MSRWD_READ_DATA_SHIFT;
- *phy_data = (u16)(data);
- }
- }
- ixgbe_release_swfw_sync(hw, gssr);
- }
- return status;
- }
- /**
- * ixgbe_write_phy_reg_generic - Writes a value to specified PHY register
- * @hw: pointer to hardware structure
- * @reg_addr: 32 bit PHY register to write
- * @device_type: 5 bit device type
- * @phy_data: Data to write to the PHY register
- **/
- s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr,
- u32 device_type, u16 phy_data)
- {
- u32 command;
- u32 i;
- s32 status = 0;
- u16 gssr;
- if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1)
- gssr = IXGBE_GSSR_PHY1_SM;
- else
- gssr = IXGBE_GSSR_PHY0_SM;
- if (ixgbe_acquire_swfw_sync(hw, gssr) != 0)
- status = IXGBE_ERR_SWFW_SYNC;
- if (status == 0) {
- /* Put the data in the MDI single read and write data register*/
- IXGBE_WRITE_REG(hw, IXGBE_MSRWD, (u32)phy_data);
- /* Setup and write the address cycle command */
- command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) |
- (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
- (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
- (IXGBE_MSCA_ADDR_CYCLE | IXGBE_MSCA_MDI_COMMAND));
- IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
- /*
- * Check every 10 usec to see if the address cycle completed.
- * The MDI Command bit will clear when the operation is
- * complete
- */
- for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
- udelay(10);
- command = IXGBE_READ_REG(hw, IXGBE_MSCA);
- if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
- break;
- }
- if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
- hw_dbg(hw, "PHY address cmd didn't complete\n");
- status = IXGBE_ERR_PHY;
- }
- if (status == 0) {
- /*
- * Address cycle complete, setup and write the write
- * command
- */
- command = ((reg_addr << IXGBE_MSCA_NP_ADDR_SHIFT) |
- (device_type << IXGBE_MSCA_DEV_TYPE_SHIFT) |
- (hw->phy.addr << IXGBE_MSCA_PHY_ADDR_SHIFT) |
- (IXGBE_MSCA_WRITE | IXGBE_MSCA_MDI_COMMAND));
- IXGBE_WRITE_REG(hw, IXGBE_MSCA, command);
- /*
- * Check every 10 usec to see if the address cycle
- * completed. The MDI Command bit will clear when the
- * operation is complete
- */
- for (i = 0; i < IXGBE_MDIO_COMMAND_TIMEOUT; i++) {
- udelay(10);
- command = IXGBE_READ_REG(hw, IXGBE_MSCA);
- if ((command & IXGBE_MSCA_MDI_COMMAND) == 0)
- break;
- }
- if ((command & IXGBE_MSCA_MDI_COMMAND) != 0) {
- hw_dbg(hw, "PHY address cmd didn't complete\n");
- status = IXGBE_ERR_PHY;
- }
- }
- ixgbe_release_swfw_sync(hw, gssr);
- }
- return status;
- }
- /**
- * ixgbe_setup_phy_link_generic - Set and restart autoneg
- * @hw: pointer to hardware structure
- *
- * Restart autonegotiation and PHY and waits for completion.
- **/
- s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw)
- {
- s32 status = IXGBE_NOT_IMPLEMENTED;
- u32 time_out;
- u32 max_time_out = 10;
- u16 autoneg_reg = IXGBE_MII_AUTONEG_REG;
- /*
- * Set advertisement settings in PHY based on autoneg_advertised
- * settings. If autoneg_advertised = 0, then advertise default values
- * tnx devices cannot be "forced" to a autoneg 10G and fail. But can
- * for a 1G.
- */
- hw->phy.ops.read_reg(hw, IXGBE_MII_SPEED_SELECTION_REG,
- IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg);
- if (hw->phy.autoneg_advertised == IXGBE_LINK_SPEED_1GB_FULL)
- autoneg_reg &= 0xEFFF; /* 0 in bit 12 is 1G operation */
- else
- autoneg_reg |= 0x1000; /* 1 in bit 12 is 10G/1G operation */
- hw->phy.ops.write_reg(hw, IXGBE_MII_SPEED_SELECTION_REG,
- IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg);
- /* Restart PHY autonegotiation and wait for completion */
- hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL,
- IXGBE_MDIO_AUTO_NEG_DEV_TYPE, &autoneg_reg);
- autoneg_reg |= IXGBE_MII_RESTART;
- hw->phy.ops.write_reg(hw, IXGBE_MDIO_AUTO_NEG_CONTROL,
- IXGBE_MDIO_AUTO_NEG_DEV_TYPE, autoneg_reg);
- /* Wait for autonegotiation to finish */
- for (time_out = 0; time_out < max_time_out; time_out++) {
- udelay(10);
- /* Restart PHY autonegotiation and wait for completion */
- status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_STATUS,
- IXGBE_MDIO_AUTO_NEG_DEV_TYPE,
- &autoneg_reg);
- autoneg_reg &= IXGBE_MII_AUTONEG_COMPLETE;
- if (autoneg_reg == IXGBE_MII_AUTONEG_COMPLETE) {
- status = 0;
- break;
- }
- }
- if (time_out == max_time_out)
- status = IXGBE_ERR_LINK_SETUP;
- return status;
- }
- /**
- * ixgbe_setup_phy_link_speed_generic - Sets the auto advertised capabilities
- * @hw: pointer to hardware structure
- * @speed: new link speed
- * @autoneg: true if autonegotiation enabled
- **/
- s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw,
- ixgbe_link_speed speed,
- bool autoneg,
- bool autoneg_wait_to_complete)
- {
- /*
- * Clear autoneg_advertised and set new values based on input link
- * speed.
- */
- hw->phy.autoneg_advertised = 0;
- if (speed & IXGBE_LINK_SPEED_10GB_FULL)
- hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_10GB_FULL;
- if (speed & IXGBE_LINK_SPEED_1GB_FULL)
- hw->phy.autoneg_advertised |= IXGBE_LINK_SPEED_1GB_FULL;
- /* Setup link based on the new speed settings */
- hw->phy.ops.setup_link(hw);
- return 0;
- }
- /**
- * ixgbe_reset_phy_nl - Performs a PHY reset
- * @hw: pointer to hardware structure
- **/
- s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw)
- {
- u16 phy_offset, control, eword, edata, block_crc;
- bool end_data = false;
- u16 list_offset, data_offset;
- u16 phy_data = 0;
- s32 ret_val = 0;
- u32 i;
- hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
- IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data);
- /* reset the PHY and poll for completion */
- hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
- IXGBE_MDIO_PHY_XS_DEV_TYPE,
- (phy_data | IXGBE_MDIO_PHY_XS_RESET));
- for (i = 0; i < 100; i++) {
- hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL,
- IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data);
- if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) == 0)
- break;
- msleep(10);
- }
- if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) != 0) {
- hw_dbg(hw, "PHY reset did not complete.\n");
- ret_val = IXGBE_ERR_PHY;
- goto out;
- }
- /* Get init offsets */
- ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset,
- &data_offset);
- if (ret_val != 0)
- goto out;
- ret_val = hw->eeprom.ops.read(hw, data_offset, &block_crc);
- data_offset++;
- while (!end_data) {
- /*
- * Read control word from PHY init contents offset
- */
- ret_val = hw->eeprom.ops.read(hw, data_offset, &eword);
- control = (eword & IXGBE_CONTROL_MASK_NL) >>
- IXGBE_CONTROL_SHIFT_NL;
- edata = eword & IXGBE_DATA_MASK_NL;
- switch (control) {
- case IXGBE_DELAY_NL:
- data_offset++;
- hw_dbg(hw, "DELAY: %d MS\n", edata);
- msleep(edata);
- break;
- case IXGBE_DATA_NL:
- hw_dbg(hw, "DATA: \n");
- data_offset++;
- hw->eeprom.ops.read(hw, data_offset++,
- &phy_offset);
- for (i = 0; i < edata; i++) {
- hw->eeprom.ops.read(hw, data_offset, &eword);
- hw->phy.ops.write_reg(hw, phy_offset,
- IXGBE_TWINAX_DEV, eword);
- hw_dbg(hw, "Wrote %4.4x to %4.4x\n", eword,
- phy_offset);
- data_offset++;
- phy_offset++;
- }
- break;
- case IXGBE_CONTROL_NL:
- data_offset++;
- hw_dbg(hw, "CONTROL: \n");
- if (edata == IXGBE_CONTROL_EOL_NL) {
- hw_dbg(hw, "EOL\n");
- end_data = true;
- } else if (edata == IXGBE_CONTROL_SOL_NL) {
- hw_dbg(hw, "SOL\n");
- } else {
- hw_dbg(hw, "Bad control value\n");
- ret_val = IXGBE_ERR_PHY;
- goto out;
- }
- break;
- default:
- hw_dbg(hw, "Bad control type\n");
- ret_val = IXGBE_ERR_PHY;
- goto out;
- }
- }
- out:
- return ret_val;
- }
- /**
- * ixgbe_identify_sfp_module_generic - Identifies SFP module and assigns
- * the PHY type.
- * @hw: pointer to hardware structure
- *
- * Searches for and indentifies the SFP module. Assings appropriate PHY type.
- **/
- s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
- {
- s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
- u32 vendor_oui = 0;
- u8 identifier = 0;
- u8 comp_codes_1g = 0;
- u8 comp_codes_10g = 0;
- u8 oui_bytes[3] = {0, 0, 0};
- u8 transmission_media = 0;
- u16 enforce_sfp = 0;
- status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER,
- &identifier);
- if (status == IXGBE_ERR_SFP_NOT_PRESENT) {
- hw->phy.sfp_type = ixgbe_sfp_type_not_present;
- goto out;
- }
- if (identifier == IXGBE_SFF_IDENTIFIER_SFP) {
- hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_1GBE_COMP_CODES,
- &comp_codes_1g);
- hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_10GBE_COMP_CODES,
- &comp_codes_10g);
- hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_TRANSMISSION_MEDIA,
- &transmission_media);
- /* ID Module
- * =========
- * 0 SFP_DA_CU
- * 1 SFP_SR
- * 2 SFP_LR
- * 3 SFP_DA_CORE0 - 82599-specific
- * 4 SFP_DA_CORE1 - 82599-specific
- * 5 SFP_SR/LR_CORE0 - 82599-specific
- * 6 SFP_SR/LR_CORE1 - 82599-specific
- */
- if (hw->mac.type == ixgbe_mac_82598EB) {
- if (transmission_media & IXGBE_SFF_TWIN_AX_CAPABLE)
- hw->phy.sfp_type = ixgbe_sfp_type_da_cu;
- else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)
- hw->phy.sfp_type = ixgbe_sfp_type_sr;
- else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)
- hw->phy.sfp_type = ixgbe_sfp_type_lr;
- else
- hw->phy.sfp_type = ixgbe_sfp_type_unknown;
- } else if (hw->mac.type == ixgbe_mac_82599EB) {
- if (transmission_media & IXGBE_SFF_TWIN_AX_CAPABLE)
- if (hw->bus.lan_id == 0)
- hw->phy.sfp_type =
- ixgbe_sfp_type_da_cu_core0;
- else
- hw->phy.sfp_type =
- ixgbe_sfp_type_da_cu_core1;
- else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)
- if (hw->bus.lan_id == 0)
- hw->phy.sfp_type =
- ixgbe_sfp_type_srlr_core0;
- else
- hw->phy.sfp_type =
- ixgbe_sfp_type_srlr_core1;
- else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)
- if (hw->bus.lan_id == 0)
- hw->phy.sfp_type =
- ixgbe_sfp_type_srlr_core0;
- else
- hw->phy.sfp_type =
- ixgbe_sfp_type_srlr_core1;
- else
- hw->phy.sfp_type = ixgbe_sfp_type_unknown;
- }
- /* Determine PHY vendor */
- if (hw->phy.type == ixgbe_phy_unknown) {
- hw->phy.id = identifier;
- hw->phy.ops.read_i2c_eeprom(hw,
- IXGBE_SFF_VENDOR_OUI_BYTE0,
- &oui_bytes[0]);
- hw->phy.ops.read_i2c_eeprom(hw,
- IXGBE_SFF_VENDOR_OUI_BYTE1,
- &oui_bytes[1]);
- hw->phy.ops.read_i2c_eeprom(hw,
- IXGBE_SFF_VENDOR_OUI_BYTE2,
- &oui_bytes[2]);
- vendor_oui =
- ((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) |
- (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) |
- (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT));
- switch (vendor_oui) {
- case IXGBE_SFF_VENDOR_OUI_TYCO:
- if (transmission_media &
- IXGBE_SFF_TWIN_AX_CAPABLE)
- hw->phy.type = ixgbe_phy_tw_tyco;
- break;
- case IXGBE_SFF_VENDOR_OUI_FTL:
- hw->phy.type = ixgbe_phy_sfp_ftl;
- break;
- case IXGBE_SFF_VENDOR_OUI_AVAGO:
- hw->phy.type = ixgbe_phy_sfp_avago;
- break;
- case IXGBE_SFF_VENDOR_OUI_INTEL:
- hw->phy.type = ixgbe_phy_sfp_intel;
- break;
- default:
- if (transmission_media &
- IXGBE_SFF_TWIN_AX_CAPABLE)
- hw->phy.type = ixgbe_phy_tw_unknown;
- else
- hw->phy.type = ixgbe_phy_sfp_unknown;
- break;
- }
- }
- if (hw->mac.type == ixgbe_mac_82598EB ||
- (hw->phy.sfp_type != ixgbe_sfp_type_sr &&
- hw->phy.sfp_type != ixgbe_sfp_type_lr &&
- hw->phy.sfp_type != ixgbe_sfp_type_srlr_core0 &&
- hw->phy.sfp_type != ixgbe_sfp_type_srlr_core1)) {
- status = 0;
- goto out;
- }
- hw->eeprom.ops.read(hw, IXGBE_PHY_ENFORCE_INTEL_SFP_OFFSET,
- &enforce_sfp);
- if (!(enforce_sfp & IXGBE_PHY_ALLOW_ANY_SFP)) {
- /* Make sure we're a supported PHY type */
- if (hw->phy.type == ixgbe_phy_sfp_intel) {
- status = 0;
- } else {
- hw_dbg(hw, "SFP+ module not supported\n");
- status = IXGBE_ERR_SFP_NOT_SUPPORTED;
- }
- } else {
- status = 0;
- }
- }
- out:
- return status;
- }
- /**
- * ixgbe_get_sfp_init_sequence_offsets - Checks the MAC's EEPROM to see
- * if it supports a given SFP+ module type, if so it returns the offsets to the
- * phy init sequence block.
- * @hw: pointer to hardware structure
- * @list_offset: offset to the SFP ID list
- * @data_offset: offset to the SFP data block
- **/
- s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
- u16 *list_offset,
- u16 *data_offset)
- {
- u16 sfp_id;
- if (hw->phy.sfp_type == ixgbe_sfp_type_unknown)
- return IXGBE_ERR_SFP_NOT_SUPPORTED;
- if (hw->phy.sfp_type == ixgbe_sfp_type_not_present)
- return IXGBE_ERR_SFP_NOT_PRESENT;
- if ((hw->device_id == IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM) &&
- (hw->phy.sfp_type == ixgbe_sfp_type_da_cu))
- return IXGBE_ERR_SFP_NOT_SUPPORTED;
- /* Read offset to PHY init contents */
- hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset);
- if ((!*list_offset) || (*list_offset == 0xFFFF))
- return IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT;
- /* Shift offset to first ID word */
- (*list_offset)++;
- /*
- * Find the matching SFP ID in the EEPROM
- * and program the init sequence
- */
- hw->eeprom.ops.read(hw, *list_offset, &sfp_id);
- while (sfp_id != IXGBE_PHY_INIT_END_NL) {
- if (sfp_id == hw->phy.sfp_type) {
- (*list_offset)++;
- hw->eeprom.ops.read(hw, *list_offset, data_offset);
- if ((!*data_offset) || (*data_offset == 0xFFFF)) {
- hw_dbg(hw, "SFP+ module not supported\n");
- return IXGBE_ERR_SFP_NOT_SUPPORTED;
- } else {
- break;
- }
- } else {
- (*list_offset) += 2;
- if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id))
- return IXGBE_ERR_PHY;
- }
- }
- if (sfp_id == IXGBE_PHY_INIT_END_NL) {
- hw_dbg(hw, "No matching SFP+ module found\n");
- return IXGBE_ERR_SFP_NOT_SUPPORTED;
- }
- return 0;
- }
- /**
- * ixgbe_read_i2c_eeprom_generic - Reads 8 bit EEPROM word over I2C interface
- * @hw: pointer to hardware structure
- * @byte_offset: EEPROM byte offset to read
- * @eeprom_data: value read
- *
- * Performs byte read operation to SFP module's EEPROM over I2C interface.
- **/
- s32 ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
- u8 *eeprom_data)
- {
- return hw->phy.ops.read_i2c_byte(hw, byte_offset,
- IXGBE_I2C_EEPROM_DEV_ADDR,
- eeprom_data);
- }
- /**
- * ixgbe_write_i2c_eeprom_generic - Writes 8 bit EEPROM word over I2C interface
- * @hw: pointer to hardware structure
- * @byte_offset: EEPROM byte offset to write
- * @eeprom_data: value to write
- *
- * Performs byte write operation to SFP module's EEPROM over I2C interface.
- **/
- s32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
- u8 eeprom_data)
- {
- return hw->phy.ops.write_i2c_byte(hw, byte_offset,
- IXGBE_I2C_EEPROM_DEV_ADDR,
- eeprom_data);
- }
- /**
- * ixgbe_read_i2c_byte_generic - Reads 8 bit word over I2C
- * @hw: pointer to hardware structure
- * @byte_offset: byte offset to read
- * @data: value read
- *
- * Performs byte read operation to SFP module's EEPROM over I2C interface at
- * a specified deivce address.
- **/
- s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
- u8 dev_addr, u8 *data)
- {
- s32 status = 0;
- u32 max_retry = 1;
- u32 retry = 0;
- bool nack = 1;
- do {
- ixgbe_i2c_start(hw);
- /* Device Address and write indication */
- status = ixgbe_clock_out_i2c_byte(hw, dev_addr);
- if (status != 0)
- goto fail;
- status = ixgbe_get_i2c_ack(hw);
- if (status != 0)
- goto fail;
- status = ixgbe_clock_out_i2c_byte(hw, byte_offset);
- if (status != 0)
- goto fail;
- status = ixgbe_get_i2c_ack(hw);
- if (status != 0)
- goto fail;
- ixgbe_i2c_start(hw);
- /* Device Address and read indication */
- status = ixgbe_clock_out_i2c_byte(hw, (dev_addr | 0x1));
- if (status != 0)
- goto fail;
- status = ixgbe_get_i2c_ack(hw);
- if (status != 0)
- goto fail;
- status = ixgbe_clock_in_i2c_byte(hw, data);
- if (status != 0)
- goto fail;
- status = ixgbe_clock_out_i2c_bit(hw, nack);
- if (status != 0)
- goto fail;
- ixgbe_i2c_stop(hw);
- break;
- fail:
- ixgbe_i2c_bus_clear(hw);
- retry++;
- if (retry < max_retry)
- hw_dbg(hw, "I2C byte read error - Retrying.\n");
- else
- hw_dbg(hw, "I2C byte read error.\n");
- } while (retry < max_retry);
- return status;
- }
- /**
- * ixgbe_write_i2c_byte_generic - Writes 8 bit word over I2C
- * @hw: pointer to hardware structure
- * @byte_offset: byte offset to write
- * @data: value to write
- *
- * Performs byte write operation to SFP module's EEPROM over I2C interface at
- * a specified device address.
- **/
- s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
- u8 dev_addr, u8 data)
- {
- s32 status = 0;
- u32 max_retry = 1;
- u32 retry = 0;
- do {
- ixgbe_i2c_start(hw);
- status = ixgbe_clock_out_i2c_byte(hw, dev_addr);
- if (status != 0)
- goto fail;
- status = ixgbe_get_i2c_ack(hw);
- if (status != 0)
- goto fail;
- status = ixgbe_clock_out_i2c_byte(hw, byte_offset);
- if (status != 0)
- goto fail;
- status = ixgbe_get_i2c_ack(hw);
- if (status != 0)
- goto fail;
- status = ixgbe_clock_out_i2c_byte(hw, data);
- if (status != 0)
- goto fail;
- status = ixgbe_get_i2c_ack(hw);
- if (status != 0)
- goto fail;
- ixgbe_i2c_stop(hw);
- break;
- fail:
- ixgbe_i2c_bus_clear(hw);
- retry++;
- if (retry < max_retry)
- hw_dbg(hw, "I2C byte write error - Retrying.\n");
- else
- hw_dbg(hw, "I2C byte write error.\n");
- } while (retry < max_retry);
- return status;
- }
- /**
- * ixgbe_i2c_start - Sets I2C start condition
- * @hw: pointer to hardware structure
- *
- * Sets I2C start condition (High -> Low on SDA while SCL is High)
- **/
- static void ixgbe_i2c_start(struct ixgbe_hw *hw)
- {
- u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
- /* Start condition must begin with data and clock high */
- ixgbe_set_i2c_data(hw, &i2cctl, 1);
- ixgbe_raise_i2c_clk(hw, &i2cctl);
- /* Setup time for start condition (4.7us) */
- udelay(IXGBE_I2C_T_SU_STA);
- ixgbe_set_i2c_data(hw, &i2cctl, 0);
- /* Hold time for start condition (4us) */
- udelay(IXGBE_I2C_T_HD_STA);
- ixgbe_lower_i2c_clk(hw, &i2cctl);
- /* Minimum low period of clock is 4.7 us */
- udelay(IXGBE_I2C_T_LOW);
- }
- /**
- * ixgbe_i2c_stop - Sets I2C stop condition
- * @hw: pointer to hardware structure
- *
- * Sets I2C stop condition (Low -> High on SDA while SCL is High)
- **/
- static void ixgbe_i2c_stop(struct ixgbe_hw *hw)
- {
- u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
- /* Stop condition must begin with data low and clock high */
- ixgbe_set_i2c_data(hw, &i2cctl, 0);
- ixgbe_raise_i2c_clk(hw, &i2cctl);
- /* Setup time for stop condition (4us) */
- udelay(IXGBE_I2C_T_SU_STO);
- ixgbe_set_i2c_data(hw, &i2cctl, 1);
- /* bus free time between stop and start (4.7us)*/
- udelay(IXGBE_I2C_T_BUF);
- }
- /**
- * ixgbe_clock_in_i2c_byte - Clocks in one byte via I2C
- * @hw: pointer to hardware structure
- * @data: data byte to clock in
- *
- * Clocks in one byte data via I2C data/clock
- **/
- static s32 ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data)
- {
- s32 status = 0;
- s32 i;
- bool bit = 0;
- for (i = 7; i >= 0; i--) {
- status = ixgbe_clock_in_i2c_bit(hw, &bit);
- *data |= bit << i;
- if (status != 0)
- break;
- }
- return status;
- }
- /**
- * ixgbe_clock_out_i2c_byte - Clocks out one byte via I2C
- * @hw: pointer to hardware structure
- * @data: data byte clocked out
- *
- * Clocks out one byte data via I2C data/clock
- **/
- static s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data)
- {
- s32 status = 0;
- s32 i;
- u32 i2cctl;
- bool bit = 0;
- for (i = 7; i >= 0; i--) {
- bit = (data >> i) & 0x1;
- status = ixgbe_clock_out_i2c_bit(hw, bit);
- if (status != 0)
- break;
- }
- /* Release SDA line (set high) */
- i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
- i2cctl |= IXGBE_I2C_DATA_OUT;
- IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, i2cctl);
- return status;
- }
- /**
- * ixgbe_get_i2c_ack - Polls for I2C ACK
- * @hw: pointer to hardware structure
- *
- * Clocks in/out one bit via I2C data/clock
- **/
- static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw)
- {
- s32 status;
- u32 i = 0;
- u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
- u32 timeout = 10;
- bool ack = 1;
- status = ixgbe_raise_i2c_clk(hw, &i2cctl);
- if (status != 0)
- goto out;
- /* Minimum high period of clock is 4us */
- udelay(IXGBE_I2C_T_HIGH);
- /* Poll for ACK. Note that ACK in I2C spec is
- * transition from 1 to 0 */
- for (i = 0; i < timeout; i++) {
- i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
- ack = ixgbe_get_i2c_data(&i2cctl);
- udelay(1);
- if (ack == 0)
- break;
- }
- if (ack == 1) {
- hw_dbg(hw, "I2C ack was not received.\n");
- status = IXGBE_ERR_I2C;
- }
- ixgbe_lower_i2c_clk(hw, &i2cctl);
- /* Minimum low period of clock is 4.7 us */
- udelay(IXGBE_I2C_T_LOW);
- out:
- return status;
- }
- /**
- * ixgbe_clock_in_i2c_bit - Clocks in one bit via I2C data/clock
- * @hw: pointer to hardware structure
- * @data: read data value
- *
- * Clocks in one bit via I2C data/clock
- **/
- static s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data)
- {
- s32 status;
- u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
- status = ixgbe_raise_i2c_clk(hw, &i2cctl);
- /* Minimum high period of clock is 4us */
- udelay(IXGBE_I2C_T_HIGH);
- i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
- *data = ixgbe_get_i2c_data(&i2cctl);
- ixgbe_lower_i2c_clk(hw, &i2cctl);
- /* Minimum low period of clock is 4.7 us */
- udelay(IXGBE_I2C_T_LOW);
- return status;
- }
- /**
- * ixgbe_clock_out_i2c_bit - Clocks in/out one bit via I2C data/clock
- * @hw: pointer to hardware structure
- * @data: data value to write
- *
- * Clocks out one bit via I2C data/clock
- **/
- static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data)
- {
- s32 status;
- u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
- status = ixgbe_set_i2c_data(hw, &i2cctl, data);
- if (status == 0) {
- status = ixgbe_raise_i2c_clk(hw, &i2cctl);
- /* Minimum high period of clock is 4us */
- udelay(IXGBE_I2C_T_HIGH);
- ixgbe_lower_i2c_clk(hw, &i2cctl);
- /* Minimum low period of clock is 4.7 us.
- * This also takes care of the data hold time.
- */
- udelay(IXGBE_I2C_T_LOW);
- } else {
- status = IXGBE_ERR_I2C;
- hw_dbg(hw, "I2C data was not set to %X\n", data);
- }
- return status;
- }
- /**
- * ixgbe_raise_i2c_clk - Raises the I2C SCL clock
- * @hw: pointer to hardware structure
- * @i2cctl: Current value of I2CCTL register
- *
- * Raises the I2C clock line '0'->'1'
- **/
- static s32 ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
- {
- s32 status = 0;
- *i2cctl |= IXGBE_I2C_CLK_OUT;
- IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
- /* SCL rise time (1000ns) */
- udelay(IXGBE_I2C_T_RISE);
- return status;
- }
- /**
- * ixgbe_lower_i2c_clk - Lowers the I2C SCL clock
- * @hw: pointer to hardware structure
- * @i2cctl: Current value of I2CCTL register
- *
- * Lowers the I2C clock line '1'->'0'
- **/
- static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
- {
- *i2cctl &= ~IXGBE_I2C_CLK_OUT;
- IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
- /* SCL fall time (300ns) */
- udelay(IXGBE_I2C_T_FALL);
- }
- /**
- * ixgbe_set_i2c_data - Sets the I2C data bit
- * @hw: pointer to hardware structure
- * @i2cctl: Current value of I2CCTL register
- * @data: I2C data value (0 or 1) to set
- *
- * Sets the I2C data bit
- **/
- static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data)
- {
- s32 status = 0;
- if (data)
- *i2cctl |= IXGBE_I2C_DATA_OUT;
- else
- *i2cctl &= ~IXGBE_I2C_DATA_OUT;
- IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
- /* Data rise/fall (1000ns/300ns) and set-up time (250ns) */
- udelay(IXGBE_I2C_T_RISE + IXGBE_I2C_T_FALL + IXGBE_I2C_T_SU_DATA);
- /* Verify data was set correctly */
- *i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
- if (data != ixgbe_get_i2c_data(i2cctl)) {
- status = IXGBE_ERR_I2C;
- hw_dbg(hw, "Error - I2C data was not set to %X.\n", data);
- }
- return status;
- }
- /**
- * ixgbe_get_i2c_data - Reads the I2C SDA data bit
- * @hw: pointer to hardware structure
- * @i2cctl: Current value of I2CCTL register
- *
- * Returns the I2C data bit value
- **/
- static bool ixgbe_get_i2c_data(u32 *i2cctl)
- {
- bool data;
- if (*i2cctl & IXGBE_I2C_DATA_IN)
- data = 1;
- else
- data = 0;
- return data;
- }
- /**
- * ixgbe_i2c_bus_clear - Clears the I2C bus
- * @hw: pointer to hardware structure
- *
- * Clears the I2C bus by sending nine clock pulses.
- * Used when data line is stuck low.
- **/
- static void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw)
- {
- u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
- u32 i;
- ixgbe_set_i2c_data(hw, &i2cctl, 1);
- for (i = 0; i < 9; i++) {
- ixgbe_raise_i2c_clk(hw, &i2cctl);
- /* Min high period of clock is 4us */
- udelay(IXGBE_I2C_T_HIGH);
- ixgbe_lower_i2c_clk(hw, &i2cctl);
- /* Min low period of clock is 4.7us*/
- udelay(IXGBE_I2C_T_LOW);
- }
- /* Put the i2c bus back to default state */
- ixgbe_i2c_stop(hw);
- }
- /**
- * ixgbe_check_phy_link_tnx - Determine link and speed status
- * @hw: pointer to hardware structure
- *
- * Reads the VS1 register to determine if link is up and the current speed for
- * the PHY.
- **/
- s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
- bool *link_up)
- {
- s32 status = 0;
- u32 time_out;
- u32 max_time_out = 10;
- u16 phy_link = 0;
- u16 phy_speed = 0;
- u16 phy_data = 0;
- /* Initialize speed and link to default case */
- *link_up = false;
- *speed = IXGBE_LINK_SPEED_10GB_FULL;
- /*
- * Check current speed and link status of the PHY register.
- * This is a vendor specific register and may have to
- * be changed for other copper PHYs.
- */
- for (time_out = 0; time_out < max_time_out; time_out++) {
- udelay(10);
- status = hw->phy.ops.read_reg(hw,
- IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS,
- IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
- &phy_data);
- phy_link = phy_data &
- IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS;
- phy_speed = phy_data &
- IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS;
- if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) {
- *link_up = true;
- if (phy_speed ==
- IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS)
- *speed = IXGBE_LINK_SPEED_1GB_FULL;
- break;
- }
- }
- return status;
- }
- /**
- * ixgbe_get_phy_firmware_version_tnx - Gets the PHY Firmware Version
- * @hw: pointer to hardware structure
- * @firmware_version: pointer to the PHY Firmware Version
- **/
- s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw,
- u16 *firmware_version)
- {
- s32 status = 0;
- status = hw->phy.ops.read_reg(hw, TNX_FW_REV,
- IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE,
- firmware_version);
- return status;
- }
|