lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20080627210053.20f4fa17@osprey.hogchain.net>
Date:	Fri, 27 Jun 2008 21:00:53 -0500
From:	Jay Cliburn <jacliburn@...lsouth.net>
To:	Jie Yang <Jie.Yang@...eros.com>
Cc:	"jeff@...zik.org" <jeff@...zik.org>,
	"linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
	"netdev@...r.kernel.org" <netdev@...r.kernel.org>
Subject: Re: [PATCH 2.6.25.3 4/5] atl1e: Atheros L1E Gigabit Ethernet driver

On Thu, 26 Jun 2008 13:38:09 +0800
Jie Yang <Jie.Yang@...eros.com> wrote:

> From: Jie Yang <jie.yang@...eros.com>
> 
> Full patch for the Atheros L1E Gigabit Ethernet driver.
> Supportring AR8121, AR8113 and AR8114
> 
> Signed-off-by: Jie Yang <jie.yang @atheros.com>
> ---
> 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 <linux/mii.h>
> +
> +#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 *) &eth_addr[2] = swab32(addr[0]);
> +               *(u16 *) &eth_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 *) &eth_addr[2] = swab32(addr[0]);
> +       *(u16 *) &eth_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@...r.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 netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ