Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753200AbYF1CBy (ORCPT ); Fri, 27 Jun 2008 22:01:54 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1751737AbYF1CBG (ORCPT ); Fri, 27 Jun 2008 22:01:06 -0400 Received: from fmailhost02.isp.att.net ([204.127.217.102]:64969 "EHLO fmailhost02.isp.att.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751210AbYF1CA5 (ORCPT ); Fri, 27 Jun 2008 22:00:57 -0400 X-Originating-IP: [68.222.94.118] Date: Fri, 27 Jun 2008 21:00:53 -0500 From: Jay Cliburn To: Jie Yang Cc: "jeff@garzik.org" , "linux-kernel@vger.kernel.org" , "netdev@vger.kernel.org" Subject: Re: [PATCH 2.6.25.3 4/5] atl1e: Atheros L1E Gigabit Ethernet driver Message-ID: <20080627210053.20f4fa17@osprey.hogchain.net> In-Reply-To: <72981EBCFD196144B7C6999B9FC34A9A3EE603B867@SHEXMB-01.global.atheros.com> References: <72981EBCFD196144B7C6999B9FC34A9A3EE603B867@SHEXMB-01.global.atheros.com> X-Mailer: Claws Mail 3.4.0 (GTK+ 2.12.10; x86_64-redhat-linux-gnu) Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAIVBMVEV2dXOAgYNxSD+aemaal42A gIBqYV2UU07Ik5GXfoFMRTdbKiVwAAACbUlEQVQ4jXXTzWvbMBQAcG3EZsmt0Owc3pgNPo1oxNFt pQnEN3Wrs3UnkdXq5tOwIdq9Pci3gUqJexo55KC/cs9O/dHBRIiMfpb03rNE4v800jxIQRzsXPEP jDwndhNelo9/ngE/SFdKmZQnfOT0YSSlQBKLiJBDH6w9SPwlp5evpduDr9biQqkV8Rh7p4NRNSO1 4BHhpjLpIK2gWksIgl0LPLCHoBIcX6dp2kGKMYnfGJnjIFungZeuHA6dhSvqLXrA1zJmVKayCu1w DKuGAU+WZRRCsLdBFXgLl2Sw3N2ZEJDAn3VwEV9FK12YUGW+yqlIWiD30U5rbSi2efGuhRfxEXRB 8e+uJE/AL5z78xrqVg6aBHlMTj9V7x/RJOMGHHI11ItVUW+B0JakkGPcUsJNHuY7/ZA04X4xwQ/D 3I0FGgaT8iFponoJ26F+sNbu51O7l7QHHtNTbxMc5o/W+kw0S31Ub5i+pQBq/hjYPVPbJ/ic/aoC pbTQtxlAvvnZgNod89Y4D2sFXpMHZWU1yHb6Ft+g2aTJY84iY2iY4ySGmWdvmxlDprHkCgd1yDRV bXVfFQiZjyuyaU5p1pZkTbXBbxRagAyU2rZfcH2tTQ7+FpNQ4Ofb7lxdFzTHDGqAvHdEv0cIezi2 be+0vzdUqawaDSATHfB7itGiIfrQu2p8UQOOooHTh5lUPn6lva/qQrWwQpCUTv08hGe3dkU9KWmJ Z2EGpAeDFc3kN8oMNbNJ/AzMFERUhjmehB7ws6XBTTnfeOXT9T/C9dn4HEshpPWIjDvgi5Px2U0G Hl7dzaQHg8U4Xn6oa4g3vVnqLz3ribDLdyFmAAAAAElFTkSuQmCC Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 29477 Lines: 885 On Thu, 26 Jun 2008 13:38:09 +0800 Jie Yang wrote: > From: Jie Yang > > Full patch for the Atheros L1E Gigabit Ethernet driver. > Supportring AR8121, AR8113 and AR8114 > > Signed-off-by: Jie Yang > --- > diff -uprN -X linux-2.6.25.3.orig/Documentation/dontdiff > linux-2.6.25.3.orig/drivers/net/atl1e/atl1e_hw.c > linux-2.6.25.3.atheros/drivers/net/atl1e/atl1e_hw.c --- > linux-2.6.25.3.orig/drivers/net/atl1e/atl1e_hw.c 1970-01-01 > 08:00:00.000000000 +0800 +++ > linux-2.6.25.3.atheros/drivers/net/atl1e/atl1e_hw.c 2008-06-20 > 11:22:34.000000000 +0800 @@ -0,0 +1,748 @@ +/* > + * Copyright(c) 2007 Atheros Corporation. All rights reserved. > + * > + * Derived from Intel e1000 driver > + * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. > + * > + * This program is free software; you can redistribute it and/or > modify it > + * under the terms of the GNU General Public License as published by > the Free > + * Software Foundation; either version 2 of the License, or (at your > option) > + * any later version. > + * > + * This program is distributed in the hope that 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., 59 > + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. > + * > + * There are a lot of defines in here that are unused and/or have > cryptic > + * names. Please leave them alone, as they're the closest thing we > have > + * to a spec from Atheros at present. *ahem* -- CHS > + */ Cut/paste artifact. > + > +#include > + > +#include "atl1e.h" > +/* > + * The little-endian AUTODIN II ethernet CRC calculations. > + * A big-endian version is also available. > + * This is slow but compact code. Do not use this routine > + * for bulk data, use a table-based routine instead. > + * This is common code and should be moved to net/core/crc.c. > + * Chips may use the upper or lower CRC bits, and may reverse > + * and/or invert them. Select the endian-ness that results > + * in minimal calculations. > + */ > +static int get_permanent_address(struct atl1e_hw *hw); > + > +static u32 ether_crc_le(int length, unsigned char *data) Please use the kernel version (see include/linux/crc32.h) unless there's a compelling reason not to. > +{ > + u32 crc = ~0; /* Initial value. */ > + while (--length >= 0) { > + unsigned char current_octet = *data++; > + int bit; > + for (bit = 8; --bit >= 0; current_octet >>= 1) { > + if ((crc ^ current_octet) & 1) { > + crc >>= 1; > + crc ^= 0xedb88320; > + } else { > + crc >>= 1; > + } > + } > + } > + return ~crc; > +} > + > +/******************************************************************** Please use kernel coding style for comments. (here and several places below) > + * Reset the transmit and receive units; mask and clear all > interrupts. > + * > + * hw - Struct containing variables accessed by shared code > + * return : AT_SUCCESS or idle status (if error) > + > ********************************************************************/ > +int atl1e_reset_hw(struct atl1e_hw *hw) +{ > +#define AT_HW_MAX_IDLE_DELAY 10 Please try and keep constant declarations in header files. > + u32 idle_status_data = 0; > + u16 pci_cfg_cmd_word = 0; > + int timeout = 0; > + > + DEBUGFUNC("atl1e_reset_hw"); > + > + /* Workaround for PCI problem when BIOS sets MMRBC > incorrectly. */ > + atl1e_read_pci_cfg(hw, PCI_REG_COMMAND, &pci_cfg_cmd_word); > + if ((pci_cfg_cmd_word & (CMD_IO_SPACE | > + CMD_MEMORY_SPACE | CMD_BUS_MASTER)) > + != (CMD_IO_SPACE | CMD_MEMORY_SPACE | > CMD_BUS_MASTER)) { > + pci_cfg_cmd_word |= (CMD_IO_SPACE | > + CMD_MEMORY_SPACE | > CMD_BUS_MASTER); > + atl1e_write_pci_cfg(hw, PCI_REG_COMMAND, > &pci_cfg_cmd_word); > + } > + > + /* Issue Soft Reset to the MAC. This will reset the chip's > + * transmit, receive, DMA. It will not effect > + * the current PCI configuration. The global reset bit is > self- > + * clearing, and should clear within a microsecond. > + */ > + AT_WRITE_REG(hw, REG_MASTER_CTRL, > + MASTER_CTRL_LED_MODE | MASTER_CTRL_SOFT_RST); > + wmb(); > + msec_delay(1); > + > + /* Wait at least 10ms for All module to be Idle */ > + for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) { > + idle_status_data = AT_READ_REG(hw, REG_IDLE_STATUS); > + if (idle_status_data == 0) > + break; > + msec_delay(1); > + cpu_relax(); > + } > + > + if (timeout >= AT_HW_MAX_IDLE_DELAY) { > + DEBUGOUT("MAC state machine cann't be idle since" can't, not cann't. > + " disabled for 10ms second\n"); > + return AT_ERR_TIMEOUT; > + } > + > + return AT_SUCCESS; > +#undef AT_HW_MAX_IDLE_DELAY Why? > +} > + > + > +/********************************************************************* > + * Reads the adapter's MAC address from the EEPROM > + * > + * hw - Struct containing variables accessed by shared code > + > *********************************************************************/ > +int atl1e_read_mac_addr(struct atl1e_hw *hw) +{ > + int err = 0; Unnecessary initialization. > + > + DEBUGFUNC("atl1e_read_mac_addr"); > + > + err = get_permanent_address(hw); > + if (err) > + return AT_ERR_EEPROM; Rather than error here, just get a random mac address from random_ether_addr(). > + memcpy(hw->mac_addr, hw->perm_mac_addr, > sizeof(hw->perm_mac_addr)); > + return AT_SUCCESS; > +} > + > +/********************************************************************* > + * Hashes an address to determine its location in the multicast table > + * > + * hw - Struct containing variables accessed by shared code > + * mc_addr - the multicast address to hash > + > *********************************************************************/ > +/* > + * atl1e_hash_mc_addr > + * purpose > + * set hash value for a multicast address > + * hash calcu processing : > + * 1. calcu 32bit CRC for multicast address > + * 2. reverse crc with MSB to LSB > + */ > +u32 atl1e_hash_mc_addr(struct atl1e_hw *hw, u8 *mc_addr) > +{ > + u32 crc32; > + u32 value = 0; > + int i; > + > + crc32 = ether_crc_le(6, mc_addr); include/linux/crc32.h > + crc32 = ~crc32; > + for (i = 0; i < 32; i++) > + value |= (((crc32 >> i) & 1) << (31 - i)); > + > + return value; > +} > + > + > +/******************************************************************** > + * Sets the bit in the multicast table corresponding to the hash > value. > + * > + * hw - Struct containing variables accessed by shared code > + * hash_value - Multicast address hash value > + > ********************************************************************/ > +void atl1e_hash_set(struct atl1e_hw *hw, u32 hash_value) +{ > + u32 hash_bit, hash_reg; > + u32 mta; > + > + /* The HASH Table is a register array of 2 32-bit registers. > + * It is treated like an array of 64 bits. We want to set > + * bit BitArray[hash_value]. So we figure out what register > + * the bit is in, read it, OR in the new bit, then write > + * back the new value. The register is determined by the > + * upper 7 bits of the hash value and the bit within that Looks like the register is determined by bit 31 only, not the upper 7 bits of the hash value. > + * register are determined by the lower 5 bits of the value. > + */ > + hash_reg = (hash_value >> 31) & 0x1; > + hash_bit = (hash_value >> 26) & 0x1F; > + > + mta = AT_READ_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg); > + > + mta |= (1 << hash_bit); > + > + AT_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg, mta); > +} > + > + > +/* > + * atl1e_init_pcie - init PCIE module > + */ > +static void atl1e_init_pcie(struct atl1e_hw *hw) > +{ > + u32 value; > + /* comment 2lines below to save more power when sususpend > + value = LTSSM_TEST_MODE_DEF; > + AT_WRITE_REG(hw, REG_LTSSM_TEST_MODE, value); > + */ Just delete these lines if they're not needed. > + > + /* pcie flow control mode change */ > + value = AT_READ_REG(hw, 0x1008); > + value |= 0x8000; > + AT_WRITE_REG(hw, 0x1008, value); Please don't use vendor magic hex values; declare constants in the header file. > +} > + > +/******************************************************************** > + * Performs basic configuration of the adapter. > + * > + * hw - Struct containing variables accessed by shared code > + * Assumes that the controller has previously been reset and is in a > + * post-reset uninitialized state. Initializes multicast table, > + * and Calls routines to setup link > + * Leaves the transmit and receive units disabled and uninitialized. > + > ********************************************************************/ > +int atl1e_init_hw(struct atl1e_hw *hw) +{ > + s32 ret_val = 0; > + > + DEBUGFUNC("atl1e_init_hw"); > + > + atl1e_init_pcie(hw); > + > + > + /* Zero out the Multicast HASH table */ > + /* clear the old settings from the multicast hash table */ > + AT_WRITE_REG(hw, REG_RX_HASH_TABLE, 0); > + AT_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0); > + > + ret_val = atl1e_phy_init(hw); > + > + DEBUGOUT1("atl1e_init_hw: ret: %d", ret_val); > + > + return ret_val; > +} > + > +int atl1e_restart_autoneg(struct atl1e_hw *hw) > +{ > + int err = 0; Unnecessary initialization. > + > + err = atl1e_write_phy_reg(hw, MII_ADVERTISE, > hw->mii_autoneg_adv_reg); > + if (err) > + return err; > + > + if (hw->nic_type == athr_l1e || hw->nic_type == > athr_l2e_revA) { There's that l2e again... What's an l2e? > + err = atl1e_write_phy_reg(hw, MII_AT001_CR, > + hw->mii_1000t_ctrl_reg); > + if (err) > + return err; > + } > + > + err = atl1e_write_phy_reg(hw, MII_BMCR, > + MII_CR_RESET | MII_CR_AUTO_NEG_EN | > + MII_CR_RESTART_AUTO_NEG); > + return err; > +} > + > + > +/****************************************************************************** > + * Detects the current speed and duplex settings of the hardware. > + * > + * hw - Struct containing variables accessed by shared code > + * speed - Speed of the connection > + * duplex - Duplex setting of the connection > + > *****************************************************************************/ > +int atl1e_get_speed_and_duplex(struct atl1e_hw *hw, u16 *speed, u16 > *duplex) +{ > + int err; > + u16 phy_data; > + > + DEBUGFUNC("atl1e_get_speed_and_duplex"); > + > + /* Read PHY Specific Status Register (17) */ > + err = atl1e_read_phy_reg(hw, MII_AT001_PSSR, &phy_data); > + if (err) > + return err; > + > + if (!(phy_data & MII_AT001_PSSR_SPD_DPLX_RESOLVED)) > + return AT_ERR_PHY_RES; > + > + switch (phy_data & MII_AT001_PSSR_SPEED) { > + case MII_AT001_PSSR_1000MBS: > + *speed = SPEED_1000; > + DEBUGOUT("1000 Mbps"); > + break; > + case MII_AT001_PSSR_100MBS: > + *speed = SPEED_100; > + DEBUGOUT("100 Mbs, "); > + break; > + case MII_AT001_PSSR_10MBS: > + *speed = SPEED_10; > + DEBUGOUT("10 Mbs, "); > + break; > + default: > + DEBUGOUT("Error Speed !\n"); > + return AT_ERR_PHY_SPEED; > + break; > + } > + > + if (phy_data & MII_AT001_PSSR_DPLX) { > + *duplex = FULL_DUPLEX; > + DEBUGOUT("Full Duplex"); > + } else { > + *duplex = HALF_DUPLEX; > + DEBUGOUT(" Half Duplex"); > + } > + > + return AT_SUCCESS; > +} > + > +/********************************************************************* > + * Reads the value from a PHY register > + * hw - Struct containing variables accessed by shared code > + * reg_addr - address of the PHY register to read > + > *********************************************************************/ > +int atl1e_read_phy_reg(struct atl1e_hw *hw, u16 reg_addr, u16 > *phy_data) +{ > + u32 val; > + int i; > + > + DEBUGFUNC("atl1e_read_phy_reg"); > + > + val = ((u32)(reg_addr&MDIO_REG_ADDR_MASK)) << > MDIO_REG_ADDR_SHIFT | > + MDIO_START | MDIO_SUP_PREAMBLE | MDIO_RW | > + MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT; > + > + AT_WRITE_REG(hw, REG_MDIO_CTRL, val); > + > + wmb(); > + > + for (i = 0; i < MDIO_WAIT_TIMES; i++) { > + usec_delay(2); > + val = AT_READ_REG(hw, REG_MDIO_CTRL); > + if (!(val & (MDIO_START | MDIO_BUSY))) > + break; > + wmb(); > + } > + if (!(val & (MDIO_START | MDIO_BUSY))) { > + *phy_data = (u16)val; > + return AT_SUCCESS; > + } > + > + return AT_ERR_PHY; > +} > + > +/******************************************************************** > + * Writes a value to a PHY register > + * hw - Struct containing variables accessed by shared code > + * reg_addr - address of the PHY register to write > + * data - data to write to the PHY > + > ********************************************************************/ > +int atl1e_write_phy_reg(struct atl1e_hw *hw, u32 reg_addr, u16 > phy_data) +{ > + int i; > + u32 val; > + > + val = ((u32)(phy_data & MDIO_DATA_MASK)) << MDIO_DATA_SHIFT | > + (reg_addr&MDIO_REG_ADDR_MASK) << MDIO_REG_ADDR_SHIFT | > + MDIO_SUP_PREAMBLE | > + MDIO_START | > + MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT; > + > + AT_WRITE_REG(hw, REG_MDIO_CTRL, val); > + wmb(); > + > + for (i = 0; i < MDIO_WAIT_TIMES; i++) { > + usec_delay(2); > + val = AT_READ_REG(hw, REG_MDIO_CTRL); > + if (!(val & (MDIO_START | MDIO_BUSY))) > + break; > + wmb(); > + } > + > + if (!(val & (MDIO_START | MDIO_BUSY))) > + return AT_SUCCESS; > + > + return AT_ERR_PHY; > +} > + > +/******************************************************************** > + * Configures PHY autoneg and flow control advertisement settings > + * > + * hw - Struct containing variables accessed by shared code > + > ********************************************************************/ > +static int atl1e_phy_setup_autoneg_adv(struct atl1e_hw *hw) +{ > + s32 ret_val; > + u16 mii_autoneg_adv_reg; > + u16 mii_1000t_ctrl_reg; > + > + DEBUGFUNC("atl1e_phy_setup_autoneg_adv"); > + > + if (0 != hw->mii_autoneg_adv_reg) Kernel coding style calls for if (condition) in this particular case. > + return AT_SUCCESS; > + /* Read the MII Auto-Neg Advertisement Register (Address > 4/9). */ > + mii_autoneg_adv_reg = MII_AR_DEFAULT_CAP_MASK; > + mii_1000t_ctrl_reg = MII_AT001_CR_1000T_DEFAULT_CAP_MASK; > + > + /* Need to parse autoneg_advertised and set up > + * the appropriate PHY registers. First we will parse for > + * autoneg_advertised software override. Since we can > advertise > + * a plethora of combinations, we need to check each bit > + * individually. > + */ > + > + /* First we clear all the 10/100 mb speed bits in the Auto-Neg > + * Advertisement Register (Address 4) and the 1000 mb speed > bits in > + * the 1000Base-T control Register (Address 9). > + */ > + mii_autoneg_adv_reg &= ~MII_AR_SPEED_MASK; > + mii_1000t_ctrl_reg &= ~MII_AT001_CR_1000T_SPEED_MASK; > + > + /* Need to parse MediaType and setup the > + * appropriate PHY registers. > + */ > + switch (hw->media_type) { > + case MEDIA_TYPE_AUTO_SENSOR: > + mii_autoneg_adv_reg |= (MII_AR_10T_HD_CAPS | > + MII_AR_10T_FD_CAPS | > + MII_AR_100TX_HD_CAPS | > + MII_AR_100TX_FD_CAPS); > + hw->autoneg_advertised = ADVERTISE_10_HALF | > + ADVERTISE_10_FULL | > + ADVERTISE_100_HALF | > + ADVERTISE_100_FULL; > + if (hw->nic_type == athr_l1e) { > + mii_1000t_ctrl_reg |= > + MII_AT001_CR_1000T_FD_CAPS; > + hw->autoneg_advertised |= ADVERTISE_1000_FULL; > + } > + break; > + > + case MEDIA_TYPE_100M_FULL: > + mii_autoneg_adv_reg |= MII_AR_100TX_FD_CAPS; > + hw->autoneg_advertised = ADVERTISE_100_FULL; > + break; > + > + case MEDIA_TYPE_100M_HALF: > + mii_autoneg_adv_reg |= MII_AR_100TX_HD_CAPS; > + hw->autoneg_advertised = ADVERTISE_100_HALF; > + break; > + > + case MEDIA_TYPE_10M_FULL: > + mii_autoneg_adv_reg |= MII_AR_10T_FD_CAPS; > + hw->autoneg_advertised = ADVERTISE_10_FULL; > + break; > + > + default: > + mii_autoneg_adv_reg |= MII_AR_10T_HD_CAPS; > + hw->autoneg_advertised = ADVERTISE_10_HALF; > + break; > + } > + > + /* flow control fixed to enable all */ > + mii_autoneg_adv_reg |= (MII_AR_ASM_DIR | MII_AR_PAUSE); > + > + hw->mii_autoneg_adv_reg = mii_autoneg_adv_reg; > + hw->mii_1000t_ctrl_reg = mii_1000t_ctrl_reg; > + > + ret_val = atl1e_write_phy_reg(hw, MII_ADVERTISE, > mii_autoneg_adv_reg); > + if (ret_val) > + return ret_val; > + > + if (hw->nic_type == athr_l1e || hw->nic_type == > athr_l2e_revA) { > + ret_val = atl1e_write_phy_reg(hw, MII_AT001_CR, > + mii_1000t_ctrl_reg); > + if (ret_val) > + return ret_val; > + } > + > + return AT_SUCCESS; > +} > + > +int atl1e_phy_init(struct atl1e_hw *hw) > +{ > + s32 ret_val; > + u16 phy_val; > + > + if (hw->phy_configured) { > + if (hw->re_autoneg) { > + hw->re_autoneg = false; > + return atl1e_restart_autoneg(hw); > + } > + return AT_SUCCESS; > + } > + > + /* RESET GPHY Core */ > + AT_WRITE_REGW(hw, REG_GPHY_CTRL, GPHY_CTRL_DEFAULT); > + msec_delay(2); > + AT_WRITE_REGW(hw, REG_GPHY_CTRL, GPHY_CTRL_DEFAULT | > + GPHY_CTRL_EXT_RESET); > + msec_delay(2); > + > + /* patches */ > + /* p1. eable hibernation mode */ > + ret_val = atl1e_write_phy_reg(hw, MII_DBG_ADDR, 0xB); Please use defined constants instead of hex values to make the code easier to understand. > + if (ret_val) > + return ret_val; > + ret_val = atl1e_write_phy_reg(hw, MII_DBG_DATA, 0xBC00); > + if (ret_val) > + return ret_val; > + /* p2. set Class A/B for all modes */ > + ret_val = atl1e_write_phy_reg(hw, MII_DBG_ADDR, 0); > + if (ret_val) > + return ret_val; > + phy_val = 0x02ef; > + /* remove Class AB */ > + /* phy_val = hw->emi_ca ? 0x02ef : 0x02df; */ > + ret_val = atl1e_write_phy_reg(hw, MII_DBG_DATA, phy_val); > + if (ret_val) > + return ret_val; > + /* p3. 10B ??? */ > + ret_val = atl1e_write_phy_reg(hw, MII_DBG_ADDR, 0x12); > + if (ret_val) > + return ret_val; > + ret_val = atl1e_write_phy_reg(hw, MII_DBG_DATA, 0x4C04); > + if (ret_val) > + return ret_val; > + /* p4. 1000T power */ > + ret_val = atl1e_write_phy_reg(hw, MII_DBG_ADDR, 0x4); > + if (ret_val) > + return ret_val; > + ret_val = atl1e_write_phy_reg(hw, MII_DBG_DATA, 0x8BBB); > + if (ret_val) > + return ret_val; > + > + ret_val = atl1e_write_phy_reg(hw, MII_DBG_ADDR, 0x5); > + if (ret_val) > + return ret_val; > + ret_val = atl1e_write_phy_reg(hw, MII_DBG_DATA, 0x2C46); > + if (ret_val) > + return ret_val; > + > + msec_delay(1); > + > + /*Enable PHY LinkChange Interrupt */ > + ret_val = atl1e_write_phy_reg(hw, MII_INT_CTRL, 0xC00); > + if (ret_val) { > + DEBUGOUT("Error enable PHY linkChange Interrupt"); > + return ret_val; > + } > + /* setup AutoNeg parameters */ > + ret_val = atl1e_phy_setup_autoneg_adv(hw); > + if (ret_val) { > + DEBUGOUT("Error Setting up Auto-Negotiation"); > + return ret_val; > + } > + /* SW.Reset & En-Auto-Neg to restart Auto-Neg*/ > + DEBUGOUT("Restarting Auto-Neg"); > + ret_val = atl1e_phy_commit(hw); > + if (ret_val) { > + DEBUGOUT("Error Resetting the phy"); > + return ret_val; > + } > + > + hw->phy_configured = true; > + > + return AT_SUCCESS; > +} > + > +/******************************************************************* > + * Resets the PHY and make all config validate > + * > + * hw - Struct containing variables accessed by shared code > + * > + * Sets bit 15 and 12 of the MII control regiser (for F001 bug) > + *******************************************************************/ > +int atl1e_phy_commit(struct atl1e_hw *hw) > +{ > + int ret_val; > + u16 phy_data; > + > + DEBUGFUNC("atl1e_phy_commit"); > + > + phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN | > MII_CR_RESTART_AUTO_NEG; + > + ret_val = atl1e_write_phy_reg(hw, MII_BMCR, phy_data); > + if (ret_val) { > + u32 val; > + int i; > + /************************************** > + * pcie serdes link may be down ! > + **************************************/ > + DEBUGOUT("Auto-Neg make pcie phy link down !"); > + > + for (i = 0; i < 25; i++) { > + msec_delay(1); > + val = AT_READ_REG(hw, REG_MDIO_CTRL); > + if (!(val & (MDIO_START | MDIO_BUSY))) > + break; > + } > + > + if (0 != (val & (MDIO_START | MDIO_BUSY))) { > + AT_ERR("pcie linkdown at least for 25ms !\n"); > + return ret_val; > + } > + > + DEBUGOUT1("pcie linkup after %dms", i); > + } > + return AT_SUCCESS; > +} > + > +void set_mac_addr(struct atl1e_hw *hw) Please preface your functions with atl1e_; atl1e_set_mac_addr() > +{ > + u32 value; > + /* > + * 00-0B-6A-F6-00-DC > + * 0: 6AF600DC 1: 000B > + * low dword > + */ > + value = (((u32)hw->mac_addr[2]) << 24) | > + (((u32)hw->mac_addr[3]) << 16) | > + (((u32)hw->mac_addr[4]) << 8) | > + (((u32)hw->mac_addr[5])) ; > + AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 0, value); > + /* hight dword */ > + value = (((u32)hw->mac_addr[0]) << 8) | > + (((u32)hw->mac_addr[1])) ; > + AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 1, value); > +} > + > + > +/**************** function about EEPROM ************************/ > +/* > + * check_eeprom_exist > + * return 0 if eeprom exist > + */ > +int check_eeprom_exist(struct atl1e_hw *hw) atl1e_check_eeprom_exist > +{ > + u32 value; > + > + value = AT_READ_REG(hw, REG_SPI_FLASH_CTRL); > + if (value & SPI_FLASH_CTRL_EN_VPD) { > + value &= ~SPI_FLASH_CTRL_EN_VPD; > + AT_WRITE_REG(hw, REG_SPI_FLASH_CTRL, value); > + } > + value = AT_READ_REGW(hw, REG_PCIE_CAP_LIST); > + return ((value & 0xFF00) == 0x6C00) ? 0 : 1; Vendor magic. > +} > + > +/* > + * get_permanent_address > + * return 0 if get valid mac address, > + */ > +static int get_permanent_address(struct atl1e_hw *hw) atl1e_get_permanent_address > +{ > + u32 addr[2]; > + u32 i, control; > + u16 reg_addr; > + u8 eth_addr[ETH_ALEN]; > + bool key_valid; > + > + if (is_valid_ether_addr(hw->perm_mac_addr)) > + return 0; > + > + /* init */ > + addr[0] = addr[1] = 0; > + > + if (!check_eeprom_exist(hw)) { > + /* eeprom exist */ > + reg_addr = 0; > + key_valid = false; > + /* Read out all EEPROM content */ > + i = 0; > + while (1) { > + if (read_eeprom(hw, i+0, &control)) { > + if (key_valid) { > + if (reg_addr == > REG_MAC_STA_ADDR) > + addr[0] = control; > + else if (reg_addr == > + > (REG_MAC_STA_ADDR+4)) > + addr[1] = control; > + > + key_valid = false; > + } else if ((control & 0xff) == 0x5A) { > + key_valid = true; > + reg_addr = (u16)(control >> > 16); > + } else > + break; > + /* > + * assume data end while > encount > + * an invalid KEYWORD > + */ > + } else { > + break; /* read error */ > + } > + i += 4; > + } > + > + *(u32 *) ð_addr[2] = swab32(addr[0]); > + *(u16 *) ð_addr[0] = swab16(*(u16 *) &addr[1]); > + > + if (is_valid_ether_addr(eth_addr)) { > + memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN); > + return 0; > + } > + } > + > + /* maybe MAC-address is from BIOS */ > + addr[0] = AT_READ_REG(hw, REG_MAC_STA_ADDR); > + addr[1] = AT_READ_REG(hw, REG_MAC_STA_ADDR + 4); > + *(u32 *) ð_addr[2] = swab32(addr[0]); > + *(u16 *) ð_addr[0] = swab16(*(u16 *)&addr[1]); > + > + if (is_valid_ether_addr(eth_addr)) { > + memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN); > + return 0; > + } > + > + return 1; > +} > + > +bool write_eeprom(struct atl1e_hw *hw, u32 offset, u32 value) atl1e_ > +{ > + return true; > +} > + > +bool read_eeprom(struct atl1e_hw *hw, u32 offset, u32 *p_value) atl1e_ > +{ > + int i; > + u32 control; > + > + if (offset & 3) > + return false; /* address do not align */ > + > + AT_WRITE_REG(hw, REG_VPD_DATA, 0); > + control = (offset & VPD_CAP_VPD_ADDR_MASK) << > VPD_CAP_VPD_ADDR_SHIFT; > + AT_WRITE_REG(hw, REG_VPD_CAP, control); > + > + for (i = 0; i < 10; i++) { > + msec_delay(2); > + control = AT_READ_REG(hw, REG_VPD_CAP); > + if (control & VPD_CAP_VPD_FLAG) > + break; > + } > + if (control & VPD_CAP_VPD_FLAG) { > + *p_value = AT_READ_REG(hw, REG_VPD_DATA); > + return true; > + } > + return false; /* timeout */ > +} > + > +void atl1e_force_ps(struct atl1e_hw *hw) > +{ > + AT_WRITE_REGW(hw, REG_GPHY_CTRL, > + GPHY_CTRL_PW_WOL_DIS | GPHY_CTRL_EXT_RESET); > +} > -- > To unsubscribe from this list: send the line "unsubscribe > linux-kernel" in the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > Please read the FAQ at http://www.tux.org/lkml/ -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/