|  | /* | 
|  | * Copyright(c) 2006 - 2007 Atheros Corporation. All rights reserved. | 
|  | * Copyright(c) 2007 - 2008 Chris Snook <csnook@redhat.com> | 
|  | * | 
|  | * 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. | 
|  | */ | 
|  |  | 
|  | #include <asm/atomic.h> | 
|  | #include <linux/crc32.h> | 
|  | #include <linux/dma-mapping.h> | 
|  | #include <linux/etherdevice.h> | 
|  | #include <linux/ethtool.h> | 
|  | #include <linux/hardirq.h> | 
|  | #include <linux/if_vlan.h> | 
|  | #include <linux/in.h> | 
|  | #include <linux/interrupt.h> | 
|  | #include <linux/ip.h> | 
|  | #include <linux/irqflags.h> | 
|  | #include <linux/irqreturn.h> | 
|  | #include <linux/mii.h> | 
|  | #include <linux/net.h> | 
|  | #include <linux/netdevice.h> | 
|  | #include <linux/pci.h> | 
|  | #include <linux/pci_ids.h> | 
|  | #include <linux/pm.h> | 
|  | #include <linux/skbuff.h> | 
|  | #include <linux/slab.h> | 
|  | #include <linux/spinlock.h> | 
|  | #include <linux/string.h> | 
|  | #include <linux/tcp.h> | 
|  | #include <linux/timer.h> | 
|  | #include <linux/types.h> | 
|  | #include <linux/workqueue.h> | 
|  |  | 
|  | #include "atl2.h" | 
|  |  | 
|  | #define ATL2_DRV_VERSION "2.2.3" | 
|  |  | 
|  | static const char atl2_driver_name[] = "atl2"; | 
|  | static const char atl2_driver_string[] = "Atheros(R) L2 Ethernet Driver"; | 
|  | static const char atl2_copyright[] = "Copyright (c) 2007 Atheros Corporation."; | 
|  | static const char atl2_driver_version[] = ATL2_DRV_VERSION; | 
|  |  | 
|  | MODULE_AUTHOR("Atheros Corporation <xiong.huang@atheros.com>, Chris Snook <csnook@redhat.com>"); | 
|  | MODULE_DESCRIPTION("Atheros Fast Ethernet Network Driver"); | 
|  | MODULE_LICENSE("GPL"); | 
|  | MODULE_VERSION(ATL2_DRV_VERSION); | 
|  |  | 
|  | /* | 
|  | * atl2_pci_tbl - PCI Device ID Table | 
|  | */ | 
|  | static DEFINE_PCI_DEVICE_TABLE(atl2_pci_tbl) = { | 
|  | {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L2)}, | 
|  | /* required last entry */ | 
|  | {0,} | 
|  | }; | 
|  | MODULE_DEVICE_TABLE(pci, atl2_pci_tbl); | 
|  |  | 
|  | static void atl2_set_ethtool_ops(struct net_device *netdev); | 
|  |  | 
|  | static void atl2_check_options(struct atl2_adapter *adapter); | 
|  |  | 
|  | /* | 
|  | * atl2_sw_init - Initialize general software structures (struct atl2_adapter) | 
|  | * @adapter: board private structure to initialize | 
|  | * | 
|  | * atl2_sw_init initializes the Adapter private data structure. | 
|  | * Fields are initialized based on PCI device information and | 
|  | * OS network device settings (MTU size). | 
|  | */ | 
|  | static int __devinit atl2_sw_init(struct atl2_adapter *adapter) | 
|  | { | 
|  | struct atl2_hw *hw = &adapter->hw; | 
|  | struct pci_dev *pdev = adapter->pdev; | 
|  |  | 
|  | /* PCI config space info */ | 
|  | hw->vendor_id = pdev->vendor; | 
|  | hw->device_id = pdev->device; | 
|  | hw->subsystem_vendor_id = pdev->subsystem_vendor; | 
|  | hw->subsystem_id = pdev->subsystem_device; | 
|  | hw->revision_id  = pdev->revision; | 
|  |  | 
|  | pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word); | 
|  |  | 
|  | adapter->wol = 0; | 
|  | adapter->ict = 50000;  /* ~100ms */ | 
|  | adapter->link_speed = SPEED_0;   /* hardware init */ | 
|  | adapter->link_duplex = FULL_DUPLEX; | 
|  |  | 
|  | hw->phy_configured = false; | 
|  | hw->preamble_len = 7; | 
|  | hw->ipgt = 0x60; | 
|  | hw->min_ifg = 0x50; | 
|  | hw->ipgr1 = 0x40; | 
|  | hw->ipgr2 = 0x60; | 
|  | hw->retry_buf = 2; | 
|  | hw->max_retry = 0xf; | 
|  | hw->lcol = 0x37; | 
|  | hw->jam_ipg = 7; | 
|  | hw->fc_rxd_hi = 0; | 
|  | hw->fc_rxd_lo = 0; | 
|  | hw->max_frame_size = adapter->netdev->mtu; | 
|  |  | 
|  | spin_lock_init(&adapter->stats_lock); | 
|  |  | 
|  | set_bit(__ATL2_DOWN, &adapter->flags); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * atl2_set_multi - Multicast and Promiscuous mode set | 
|  | * @netdev: network interface device structure | 
|  | * | 
|  | * The set_multi entry point is called whenever the multicast address | 
|  | * list or the network interface flags are updated.  This routine is | 
|  | * responsible for configuring the hardware for proper multicast, | 
|  | * promiscuous mode, and all-multi behavior. | 
|  | */ | 
|  | static void atl2_set_multi(struct net_device *netdev) | 
|  | { | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  | struct atl2_hw *hw = &adapter->hw; | 
|  | struct netdev_hw_addr *ha; | 
|  | u32 rctl; | 
|  | u32 hash_value; | 
|  |  | 
|  | /* Check for Promiscuous and All Multicast modes */ | 
|  | rctl = ATL2_READ_REG(hw, REG_MAC_CTRL); | 
|  |  | 
|  | if (netdev->flags & IFF_PROMISC) { | 
|  | rctl |= MAC_CTRL_PROMIS_EN; | 
|  | } else if (netdev->flags & IFF_ALLMULTI) { | 
|  | rctl |= MAC_CTRL_MC_ALL_EN; | 
|  | rctl &= ~MAC_CTRL_PROMIS_EN; | 
|  | } else | 
|  | rctl &= ~(MAC_CTRL_PROMIS_EN | MAC_CTRL_MC_ALL_EN); | 
|  |  | 
|  | ATL2_WRITE_REG(hw, REG_MAC_CTRL, rctl); | 
|  |  | 
|  | /* clear the old settings from the multicast hash table */ | 
|  | ATL2_WRITE_REG(hw, REG_RX_HASH_TABLE, 0); | 
|  | ATL2_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0); | 
|  |  | 
|  | /* comoute mc addresses' hash value ,and put it into hash table */ | 
|  | netdev_for_each_mc_addr(ha, netdev) { | 
|  | hash_value = atl2_hash_mc_addr(hw, ha->addr); | 
|  | atl2_hash_set(hw, hash_value); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void init_ring_ptrs(struct atl2_adapter *adapter) | 
|  | { | 
|  | /* Read / Write Ptr Initialize: */ | 
|  | adapter->txd_write_ptr = 0; | 
|  | atomic_set(&adapter->txd_read_ptr, 0); | 
|  |  | 
|  | adapter->rxd_read_ptr = 0; | 
|  | adapter->rxd_write_ptr = 0; | 
|  |  | 
|  | atomic_set(&adapter->txs_write_ptr, 0); | 
|  | adapter->txs_next_clear = 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * atl2_configure - Configure Transmit&Receive Unit after Reset | 
|  | * @adapter: board private structure | 
|  | * | 
|  | * Configure the Tx /Rx unit of the MAC after a reset. | 
|  | */ | 
|  | static int atl2_configure(struct atl2_adapter *adapter) | 
|  | { | 
|  | struct atl2_hw *hw = &adapter->hw; | 
|  | u32 value; | 
|  |  | 
|  | /* clear interrupt status */ | 
|  | ATL2_WRITE_REG(&adapter->hw, REG_ISR, 0xffffffff); | 
|  |  | 
|  | /* set MAC Address */ | 
|  | value = (((u32)hw->mac_addr[2]) << 24) | | 
|  | (((u32)hw->mac_addr[3]) << 16) | | 
|  | (((u32)hw->mac_addr[4]) << 8) | | 
|  | (((u32)hw->mac_addr[5])); | 
|  | ATL2_WRITE_REG(hw, REG_MAC_STA_ADDR, value); | 
|  | value = (((u32)hw->mac_addr[0]) << 8) | | 
|  | (((u32)hw->mac_addr[1])); | 
|  | ATL2_WRITE_REG(hw, (REG_MAC_STA_ADDR+4), value); | 
|  |  | 
|  | /* HI base address */ | 
|  | ATL2_WRITE_REG(hw, REG_DESC_BASE_ADDR_HI, | 
|  | (u32)((adapter->ring_dma & 0xffffffff00000000ULL) >> 32)); | 
|  |  | 
|  | /* LO base address */ | 
|  | ATL2_WRITE_REG(hw, REG_TXD_BASE_ADDR_LO, | 
|  | (u32)(adapter->txd_dma & 0x00000000ffffffffULL)); | 
|  | ATL2_WRITE_REG(hw, REG_TXS_BASE_ADDR_LO, | 
|  | (u32)(adapter->txs_dma & 0x00000000ffffffffULL)); | 
|  | ATL2_WRITE_REG(hw, REG_RXD_BASE_ADDR_LO, | 
|  | (u32)(adapter->rxd_dma & 0x00000000ffffffffULL)); | 
|  |  | 
|  | /* element count */ | 
|  | ATL2_WRITE_REGW(hw, REG_TXD_MEM_SIZE, (u16)(adapter->txd_ring_size/4)); | 
|  | ATL2_WRITE_REGW(hw, REG_TXS_MEM_SIZE, (u16)adapter->txs_ring_size); | 
|  | ATL2_WRITE_REGW(hw, REG_RXD_BUF_NUM,  (u16)adapter->rxd_ring_size); | 
|  |  | 
|  | /* config Internal SRAM */ | 
|  | /* | 
|  | ATL2_WRITE_REGW(hw, REG_SRAM_TXRAM_END, sram_tx_end); | 
|  | ATL2_WRITE_REGW(hw, REG_SRAM_TXRAM_END, sram_rx_end); | 
|  | */ | 
|  |  | 
|  | /* config IPG/IFG */ | 
|  | value = (((u32)hw->ipgt & MAC_IPG_IFG_IPGT_MASK) << | 
|  | MAC_IPG_IFG_IPGT_SHIFT) | | 
|  | (((u32)hw->min_ifg & MAC_IPG_IFG_MIFG_MASK) << | 
|  | MAC_IPG_IFG_MIFG_SHIFT) | | 
|  | (((u32)hw->ipgr1 & MAC_IPG_IFG_IPGR1_MASK) << | 
|  | MAC_IPG_IFG_IPGR1_SHIFT)| | 
|  | (((u32)hw->ipgr2 & MAC_IPG_IFG_IPGR2_MASK) << | 
|  | MAC_IPG_IFG_IPGR2_SHIFT); | 
|  | ATL2_WRITE_REG(hw, REG_MAC_IPG_IFG, value); | 
|  |  | 
|  | /* config  Half-Duplex Control */ | 
|  | value = ((u32)hw->lcol & MAC_HALF_DUPLX_CTRL_LCOL_MASK) | | 
|  | (((u32)hw->max_retry & MAC_HALF_DUPLX_CTRL_RETRY_MASK) << | 
|  | MAC_HALF_DUPLX_CTRL_RETRY_SHIFT) | | 
|  | MAC_HALF_DUPLX_CTRL_EXC_DEF_EN | | 
|  | (0xa << MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT) | | 
|  | (((u32)hw->jam_ipg & MAC_HALF_DUPLX_CTRL_JAMIPG_MASK) << | 
|  | MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT); | 
|  | ATL2_WRITE_REG(hw, REG_MAC_HALF_DUPLX_CTRL, value); | 
|  |  | 
|  | /* set Interrupt Moderator Timer */ | 
|  | ATL2_WRITE_REGW(hw, REG_IRQ_MODU_TIMER_INIT, adapter->imt); | 
|  | ATL2_WRITE_REG(hw, REG_MASTER_CTRL, MASTER_CTRL_ITIMER_EN); | 
|  |  | 
|  | /* set Interrupt Clear Timer */ | 
|  | ATL2_WRITE_REGW(hw, REG_CMBDISDMA_TIMER, adapter->ict); | 
|  |  | 
|  | /* set MTU */ | 
|  | ATL2_WRITE_REG(hw, REG_MTU, adapter->netdev->mtu + | 
|  | ENET_HEADER_SIZE + VLAN_SIZE + ETHERNET_FCS_SIZE); | 
|  |  | 
|  | /* 1590 */ | 
|  | ATL2_WRITE_REG(hw, REG_TX_CUT_THRESH, 0x177); | 
|  |  | 
|  | /* flow control */ | 
|  | ATL2_WRITE_REGW(hw, REG_PAUSE_ON_TH, hw->fc_rxd_hi); | 
|  | ATL2_WRITE_REGW(hw, REG_PAUSE_OFF_TH, hw->fc_rxd_lo); | 
|  |  | 
|  | /* Init mailbox */ | 
|  | ATL2_WRITE_REGW(hw, REG_MB_TXD_WR_IDX, (u16)adapter->txd_write_ptr); | 
|  | ATL2_WRITE_REGW(hw, REG_MB_RXD_RD_IDX, (u16)adapter->rxd_read_ptr); | 
|  |  | 
|  | /* enable DMA read/write */ | 
|  | ATL2_WRITE_REGB(hw, REG_DMAR, DMAR_EN); | 
|  | ATL2_WRITE_REGB(hw, REG_DMAW, DMAW_EN); | 
|  |  | 
|  | value = ATL2_READ_REG(&adapter->hw, REG_ISR); | 
|  | if ((value & ISR_PHY_LINKDOWN) != 0) | 
|  | value = 1; /* config failed */ | 
|  | else | 
|  | value = 0; | 
|  |  | 
|  | /* clear all interrupt status */ | 
|  | ATL2_WRITE_REG(&adapter->hw, REG_ISR, 0x3fffffff); | 
|  | ATL2_WRITE_REG(&adapter->hw, REG_ISR, 0); | 
|  | return value; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * atl2_setup_ring_resources - allocate Tx / RX descriptor resources | 
|  | * @adapter: board private structure | 
|  | * | 
|  | * Return 0 on success, negative on failure | 
|  | */ | 
|  | static s32 atl2_setup_ring_resources(struct atl2_adapter *adapter) | 
|  | { | 
|  | struct pci_dev *pdev = adapter->pdev; | 
|  | int size; | 
|  | u8 offset = 0; | 
|  |  | 
|  | /* real ring DMA buffer */ | 
|  | adapter->ring_size = size = | 
|  | adapter->txd_ring_size * 1 + 7 +	/* dword align */ | 
|  | adapter->txs_ring_size * 4 + 7 +	/* dword align */ | 
|  | adapter->rxd_ring_size * 1536 + 127;	/* 128bytes align */ | 
|  |  | 
|  | adapter->ring_vir_addr = pci_alloc_consistent(pdev, size, | 
|  | &adapter->ring_dma); | 
|  | if (!adapter->ring_vir_addr) | 
|  | return -ENOMEM; | 
|  | memset(adapter->ring_vir_addr, 0, adapter->ring_size); | 
|  |  | 
|  | /* Init TXD Ring */ | 
|  | adapter->txd_dma = adapter->ring_dma ; | 
|  | offset = (adapter->txd_dma & 0x7) ? (8 - (adapter->txd_dma & 0x7)) : 0; | 
|  | adapter->txd_dma += offset; | 
|  | adapter->txd_ring = (struct tx_pkt_header *) (adapter->ring_vir_addr + | 
|  | offset); | 
|  |  | 
|  | /* Init TXS Ring */ | 
|  | adapter->txs_dma = adapter->txd_dma + adapter->txd_ring_size; | 
|  | offset = (adapter->txs_dma & 0x7) ? (8 - (adapter->txs_dma & 0x7)) : 0; | 
|  | adapter->txs_dma += offset; | 
|  | adapter->txs_ring = (struct tx_pkt_status *) | 
|  | (((u8 *)adapter->txd_ring) + (adapter->txd_ring_size + offset)); | 
|  |  | 
|  | /* Init RXD Ring */ | 
|  | adapter->rxd_dma = adapter->txs_dma + adapter->txs_ring_size * 4; | 
|  | offset = (adapter->rxd_dma & 127) ? | 
|  | (128 - (adapter->rxd_dma & 127)) : 0; | 
|  | if (offset > 7) | 
|  | offset -= 8; | 
|  | else | 
|  | offset += (128 - 8); | 
|  |  | 
|  | adapter->rxd_dma += offset; | 
|  | adapter->rxd_ring = (struct rx_desc *) (((u8 *)adapter->txs_ring) + | 
|  | (adapter->txs_ring_size * 4 + offset)); | 
|  |  | 
|  | /* | 
|  | * Read / Write Ptr Initialize: | 
|  | *      init_ring_ptrs(adapter); | 
|  | */ | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * atl2_irq_enable - Enable default interrupt generation settings | 
|  | * @adapter: board private structure | 
|  | */ | 
|  | static inline void atl2_irq_enable(struct atl2_adapter *adapter) | 
|  | { | 
|  | ATL2_WRITE_REG(&adapter->hw, REG_IMR, IMR_NORMAL_MASK); | 
|  | ATL2_WRITE_FLUSH(&adapter->hw); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * atl2_irq_disable - Mask off interrupt generation on the NIC | 
|  | * @adapter: board private structure | 
|  | */ | 
|  | static inline void atl2_irq_disable(struct atl2_adapter *adapter) | 
|  | { | 
|  | ATL2_WRITE_REG(&adapter->hw, REG_IMR, 0); | 
|  | ATL2_WRITE_FLUSH(&adapter->hw); | 
|  | synchronize_irq(adapter->pdev->irq); | 
|  | } | 
|  |  | 
|  | #ifdef NETIF_F_HW_VLAN_TX | 
|  | static void atl2_vlan_rx_register(struct net_device *netdev, | 
|  | struct vlan_group *grp) | 
|  | { | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  | u32 ctrl; | 
|  |  | 
|  | atl2_irq_disable(adapter); | 
|  | adapter->vlgrp = grp; | 
|  |  | 
|  | if (grp) { | 
|  | /* enable VLAN tag insert/strip */ | 
|  | ctrl = ATL2_READ_REG(&adapter->hw, REG_MAC_CTRL); | 
|  | ctrl |= MAC_CTRL_RMV_VLAN; | 
|  | ATL2_WRITE_REG(&adapter->hw, REG_MAC_CTRL, ctrl); | 
|  | } else { | 
|  | /* disable VLAN tag insert/strip */ | 
|  | ctrl = ATL2_READ_REG(&adapter->hw, REG_MAC_CTRL); | 
|  | ctrl &= ~MAC_CTRL_RMV_VLAN; | 
|  | ATL2_WRITE_REG(&adapter->hw, REG_MAC_CTRL, ctrl); | 
|  | } | 
|  |  | 
|  | atl2_irq_enable(adapter); | 
|  | } | 
|  |  | 
|  | static void atl2_restore_vlan(struct atl2_adapter *adapter) | 
|  | { | 
|  | atl2_vlan_rx_register(adapter->netdev, adapter->vlgrp); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | static void atl2_intr_rx(struct atl2_adapter *adapter) | 
|  | { | 
|  | struct net_device *netdev = adapter->netdev; | 
|  | struct rx_desc *rxd; | 
|  | struct sk_buff *skb; | 
|  |  | 
|  | do { | 
|  | rxd = adapter->rxd_ring+adapter->rxd_write_ptr; | 
|  | if (!rxd->status.update) | 
|  | break; /* end of tx */ | 
|  |  | 
|  | /* clear this flag at once */ | 
|  | rxd->status.update = 0; | 
|  |  | 
|  | if (rxd->status.ok && rxd->status.pkt_size >= 60) { | 
|  | int rx_size = (int)(rxd->status.pkt_size - 4); | 
|  | /* alloc new buffer */ | 
|  | skb = netdev_alloc_skb_ip_align(netdev, rx_size); | 
|  | if (NULL == skb) { | 
|  | printk(KERN_WARNING | 
|  | "%s: Mem squeeze, deferring packet.\n", | 
|  | netdev->name); | 
|  | /* | 
|  | * Check that some rx space is free. If not, | 
|  | * free one and mark stats->rx_dropped++. | 
|  | */ | 
|  | netdev->stats.rx_dropped++; | 
|  | break; | 
|  | } | 
|  | memcpy(skb->data, rxd->packet, rx_size); | 
|  | skb_put(skb, rx_size); | 
|  | skb->protocol = eth_type_trans(skb, netdev); | 
|  | #ifdef NETIF_F_HW_VLAN_TX | 
|  | if (adapter->vlgrp && (rxd->status.vlan)) { | 
|  | u16 vlan_tag = (rxd->status.vtag>>4) | | 
|  | ((rxd->status.vtag&7) << 13) | | 
|  | ((rxd->status.vtag&8) << 9); | 
|  | vlan_hwaccel_rx(skb, adapter->vlgrp, vlan_tag); | 
|  | } else | 
|  | #endif | 
|  | netif_rx(skb); | 
|  | netdev->stats.rx_bytes += rx_size; | 
|  | netdev->stats.rx_packets++; | 
|  | } else { | 
|  | netdev->stats.rx_errors++; | 
|  |  | 
|  | if (rxd->status.ok && rxd->status.pkt_size <= 60) | 
|  | netdev->stats.rx_length_errors++; | 
|  | if (rxd->status.mcast) | 
|  | netdev->stats.multicast++; | 
|  | if (rxd->status.crc) | 
|  | netdev->stats.rx_crc_errors++; | 
|  | if (rxd->status.align) | 
|  | netdev->stats.rx_frame_errors++; | 
|  | } | 
|  |  | 
|  | /* advance write ptr */ | 
|  | if (++adapter->rxd_write_ptr == adapter->rxd_ring_size) | 
|  | adapter->rxd_write_ptr = 0; | 
|  | } while (1); | 
|  |  | 
|  | /* update mailbox? */ | 
|  | adapter->rxd_read_ptr = adapter->rxd_write_ptr; | 
|  | ATL2_WRITE_REGW(&adapter->hw, REG_MB_RXD_RD_IDX, adapter->rxd_read_ptr); | 
|  | } | 
|  |  | 
|  | static void atl2_intr_tx(struct atl2_adapter *adapter) | 
|  | { | 
|  | struct net_device *netdev = adapter->netdev; | 
|  | u32 txd_read_ptr; | 
|  | u32 txs_write_ptr; | 
|  | struct tx_pkt_status *txs; | 
|  | struct tx_pkt_header *txph; | 
|  | int free_hole = 0; | 
|  |  | 
|  | do { | 
|  | txs_write_ptr = (u32) atomic_read(&adapter->txs_write_ptr); | 
|  | txs = adapter->txs_ring + txs_write_ptr; | 
|  | if (!txs->update) | 
|  | break; /* tx stop here */ | 
|  |  | 
|  | free_hole = 1; | 
|  | txs->update = 0; | 
|  |  | 
|  | if (++txs_write_ptr == adapter->txs_ring_size) | 
|  | txs_write_ptr = 0; | 
|  | atomic_set(&adapter->txs_write_ptr, (int)txs_write_ptr); | 
|  |  | 
|  | txd_read_ptr = (u32) atomic_read(&adapter->txd_read_ptr); | 
|  | txph = (struct tx_pkt_header *) | 
|  | (((u8 *)adapter->txd_ring) + txd_read_ptr); | 
|  |  | 
|  | if (txph->pkt_size != txs->pkt_size) { | 
|  | struct tx_pkt_status *old_txs = txs; | 
|  | printk(KERN_WARNING | 
|  | "%s: txs packet size not consistent with txd" | 
|  | " txd_:0x%08x, txs_:0x%08x!\n", | 
|  | adapter->netdev->name, | 
|  | *(u32 *)txph, *(u32 *)txs); | 
|  | printk(KERN_WARNING | 
|  | "txd read ptr: 0x%x\n", | 
|  | txd_read_ptr); | 
|  | txs = adapter->txs_ring + txs_write_ptr; | 
|  | printk(KERN_WARNING | 
|  | "txs-behind:0x%08x\n", | 
|  | *(u32 *)txs); | 
|  | if (txs_write_ptr < 2) { | 
|  | txs = adapter->txs_ring + | 
|  | (adapter->txs_ring_size + | 
|  | txs_write_ptr - 2); | 
|  | } else { | 
|  | txs = adapter->txs_ring + (txs_write_ptr - 2); | 
|  | } | 
|  | printk(KERN_WARNING | 
|  | "txs-before:0x%08x\n", | 
|  | *(u32 *)txs); | 
|  | txs = old_txs; | 
|  | } | 
|  |  | 
|  | /* 4for TPH */ | 
|  | txd_read_ptr += (((u32)(txph->pkt_size) + 7) & ~3); | 
|  | if (txd_read_ptr >= adapter->txd_ring_size) | 
|  | txd_read_ptr -= adapter->txd_ring_size; | 
|  |  | 
|  | atomic_set(&adapter->txd_read_ptr, (int)txd_read_ptr); | 
|  |  | 
|  | /* tx statistics: */ | 
|  | if (txs->ok) { | 
|  | netdev->stats.tx_bytes += txs->pkt_size; | 
|  | netdev->stats.tx_packets++; | 
|  | } | 
|  | else | 
|  | netdev->stats.tx_errors++; | 
|  |  | 
|  | if (txs->defer) | 
|  | netdev->stats.collisions++; | 
|  | if (txs->abort_col) | 
|  | netdev->stats.tx_aborted_errors++; | 
|  | if (txs->late_col) | 
|  | netdev->stats.tx_window_errors++; | 
|  | if (txs->underun) | 
|  | netdev->stats.tx_fifo_errors++; | 
|  | } while (1); | 
|  |  | 
|  | if (free_hole) { | 
|  | if (netif_queue_stopped(adapter->netdev) && | 
|  | netif_carrier_ok(adapter->netdev)) | 
|  | netif_wake_queue(adapter->netdev); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void atl2_check_for_link(struct atl2_adapter *adapter) | 
|  | { | 
|  | struct net_device *netdev = adapter->netdev; | 
|  | u16 phy_data = 0; | 
|  |  | 
|  | spin_lock(&adapter->stats_lock); | 
|  | atl2_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); | 
|  | atl2_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data); | 
|  | spin_unlock(&adapter->stats_lock); | 
|  |  | 
|  | /* notify upper layer link down ASAP */ | 
|  | if (!(phy_data & BMSR_LSTATUS)) { /* Link Down */ | 
|  | if (netif_carrier_ok(netdev)) { /* old link state: Up */ | 
|  | printk(KERN_INFO "%s: %s NIC Link is Down\n", | 
|  | atl2_driver_name, netdev->name); | 
|  | adapter->link_speed = SPEED_0; | 
|  | netif_carrier_off(netdev); | 
|  | netif_stop_queue(netdev); | 
|  | } | 
|  | } | 
|  | schedule_work(&adapter->link_chg_task); | 
|  | } | 
|  |  | 
|  | static inline void atl2_clear_phy_int(struct atl2_adapter *adapter) | 
|  | { | 
|  | u16 phy_data; | 
|  | spin_lock(&adapter->stats_lock); | 
|  | atl2_read_phy_reg(&adapter->hw, 19, &phy_data); | 
|  | spin_unlock(&adapter->stats_lock); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * atl2_intr - Interrupt Handler | 
|  | * @irq: interrupt number | 
|  | * @data: pointer to a network interface device structure | 
|  | * @pt_regs: CPU registers structure | 
|  | */ | 
|  | static irqreturn_t atl2_intr(int irq, void *data) | 
|  | { | 
|  | struct atl2_adapter *adapter = netdev_priv(data); | 
|  | struct atl2_hw *hw = &adapter->hw; | 
|  | u32 status; | 
|  |  | 
|  | status = ATL2_READ_REG(hw, REG_ISR); | 
|  | if (0 == status) | 
|  | return IRQ_NONE; | 
|  |  | 
|  | /* link event */ | 
|  | if (status & ISR_PHY) | 
|  | atl2_clear_phy_int(adapter); | 
|  |  | 
|  | /* clear ISR status, and Enable CMB DMA/Disable Interrupt */ | 
|  | ATL2_WRITE_REG(hw, REG_ISR, status | ISR_DIS_INT); | 
|  |  | 
|  | /* check if PCIE PHY Link down */ | 
|  | if (status & ISR_PHY_LINKDOWN) { | 
|  | if (netif_running(adapter->netdev)) { /* reset MAC */ | 
|  | ATL2_WRITE_REG(hw, REG_ISR, 0); | 
|  | ATL2_WRITE_REG(hw, REG_IMR, 0); | 
|  | ATL2_WRITE_FLUSH(hw); | 
|  | schedule_work(&adapter->reset_task); | 
|  | return IRQ_HANDLED; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* check if DMA read/write error? */ | 
|  | if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) { | 
|  | ATL2_WRITE_REG(hw, REG_ISR, 0); | 
|  | ATL2_WRITE_REG(hw, REG_IMR, 0); | 
|  | ATL2_WRITE_FLUSH(hw); | 
|  | schedule_work(&adapter->reset_task); | 
|  | return IRQ_HANDLED; | 
|  | } | 
|  |  | 
|  | /* link event */ | 
|  | if (status & (ISR_PHY | ISR_MANUAL)) { | 
|  | adapter->netdev->stats.tx_carrier_errors++; | 
|  | atl2_check_for_link(adapter); | 
|  | } | 
|  |  | 
|  | /* transmit event */ | 
|  | if (status & ISR_TX_EVENT) | 
|  | atl2_intr_tx(adapter); | 
|  |  | 
|  | /* rx exception */ | 
|  | if (status & ISR_RX_EVENT) | 
|  | atl2_intr_rx(adapter); | 
|  |  | 
|  | /* re-enable Interrupt */ | 
|  | ATL2_WRITE_REG(&adapter->hw, REG_ISR, 0); | 
|  | return IRQ_HANDLED; | 
|  | } | 
|  |  | 
|  | static int atl2_request_irq(struct atl2_adapter *adapter) | 
|  | { | 
|  | struct net_device *netdev = adapter->netdev; | 
|  | int flags, err = 0; | 
|  |  | 
|  | flags = IRQF_SHARED; | 
|  | adapter->have_msi = true; | 
|  | err = pci_enable_msi(adapter->pdev); | 
|  | if (err) | 
|  | adapter->have_msi = false; | 
|  |  | 
|  | if (adapter->have_msi) | 
|  | flags &= ~IRQF_SHARED; | 
|  |  | 
|  | return request_irq(adapter->pdev->irq, atl2_intr, flags, netdev->name, | 
|  | netdev); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * atl2_free_ring_resources - Free Tx / RX descriptor Resources | 
|  | * @adapter: board private structure | 
|  | * | 
|  | * Free all transmit software resources | 
|  | */ | 
|  | static void atl2_free_ring_resources(struct atl2_adapter *adapter) | 
|  | { | 
|  | struct pci_dev *pdev = adapter->pdev; | 
|  | pci_free_consistent(pdev, adapter->ring_size, adapter->ring_vir_addr, | 
|  | adapter->ring_dma); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * atl2_open - Called when a network interface is made active | 
|  | * @netdev: network interface device structure | 
|  | * | 
|  | * Returns 0 on success, negative value on failure | 
|  | * | 
|  | * The open entry point is called when a network interface is made | 
|  | * active by the system (IFF_UP).  At this point all resources needed | 
|  | * for transmit and receive operations are allocated, the interrupt | 
|  | * handler is registered with the OS, the watchdog timer is started, | 
|  | * and the stack is notified that the interface is ready. | 
|  | */ | 
|  | static int atl2_open(struct net_device *netdev) | 
|  | { | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  | int err; | 
|  | u32 val; | 
|  |  | 
|  | /* disallow open during test */ | 
|  | if (test_bit(__ATL2_TESTING, &adapter->flags)) | 
|  | return -EBUSY; | 
|  |  | 
|  | /* allocate transmit descriptors */ | 
|  | err = atl2_setup_ring_resources(adapter); | 
|  | if (err) | 
|  | return err; | 
|  |  | 
|  | err = atl2_init_hw(&adapter->hw); | 
|  | if (err) { | 
|  | err = -EIO; | 
|  | goto err_init_hw; | 
|  | } | 
|  |  | 
|  | /* hardware has been reset, we need to reload some things */ | 
|  | atl2_set_multi(netdev); | 
|  | init_ring_ptrs(adapter); | 
|  |  | 
|  | #ifdef NETIF_F_HW_VLAN_TX | 
|  | atl2_restore_vlan(adapter); | 
|  | #endif | 
|  |  | 
|  | if (atl2_configure(adapter)) { | 
|  | err = -EIO; | 
|  | goto err_config; | 
|  | } | 
|  |  | 
|  | err = atl2_request_irq(adapter); | 
|  | if (err) | 
|  | goto err_req_irq; | 
|  |  | 
|  | clear_bit(__ATL2_DOWN, &adapter->flags); | 
|  |  | 
|  | mod_timer(&adapter->watchdog_timer, round_jiffies(jiffies + 4*HZ)); | 
|  |  | 
|  | val = ATL2_READ_REG(&adapter->hw, REG_MASTER_CTRL); | 
|  | ATL2_WRITE_REG(&adapter->hw, REG_MASTER_CTRL, | 
|  | val | MASTER_CTRL_MANUAL_INT); | 
|  |  | 
|  | atl2_irq_enable(adapter); | 
|  |  | 
|  | return 0; | 
|  |  | 
|  | err_init_hw: | 
|  | err_req_irq: | 
|  | err_config: | 
|  | atl2_free_ring_resources(adapter); | 
|  | atl2_reset_hw(&adapter->hw); | 
|  |  | 
|  | return err; | 
|  | } | 
|  |  | 
|  | static void atl2_down(struct atl2_adapter *adapter) | 
|  | { | 
|  | struct net_device *netdev = adapter->netdev; | 
|  |  | 
|  | /* signal that we're down so the interrupt handler does not | 
|  | * reschedule our watchdog timer */ | 
|  | set_bit(__ATL2_DOWN, &adapter->flags); | 
|  |  | 
|  | netif_tx_disable(netdev); | 
|  |  | 
|  | /* reset MAC to disable all RX/TX */ | 
|  | atl2_reset_hw(&adapter->hw); | 
|  | msleep(1); | 
|  |  | 
|  | atl2_irq_disable(adapter); | 
|  |  | 
|  | del_timer_sync(&adapter->watchdog_timer); | 
|  | del_timer_sync(&adapter->phy_config_timer); | 
|  | clear_bit(0, &adapter->cfg_phy); | 
|  |  | 
|  | netif_carrier_off(netdev); | 
|  | adapter->link_speed = SPEED_0; | 
|  | adapter->link_duplex = -1; | 
|  | } | 
|  |  | 
|  | static void atl2_free_irq(struct atl2_adapter *adapter) | 
|  | { | 
|  | struct net_device *netdev = adapter->netdev; | 
|  |  | 
|  | free_irq(adapter->pdev->irq, netdev); | 
|  |  | 
|  | #ifdef CONFIG_PCI_MSI | 
|  | if (adapter->have_msi) | 
|  | pci_disable_msi(adapter->pdev); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | /* | 
|  | * atl2_close - Disables a network interface | 
|  | * @netdev: network interface device structure | 
|  | * | 
|  | * Returns 0, this is not allowed to fail | 
|  | * | 
|  | * The close entry point is called when an interface is de-activated | 
|  | * by the OS.  The hardware is still under the drivers control, but | 
|  | * needs to be disabled.  A global MAC reset is issued to stop the | 
|  | * hardware, and all transmit and receive resources are freed. | 
|  | */ | 
|  | static int atl2_close(struct net_device *netdev) | 
|  | { | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  |  | 
|  | WARN_ON(test_bit(__ATL2_RESETTING, &adapter->flags)); | 
|  |  | 
|  | atl2_down(adapter); | 
|  | atl2_free_irq(adapter); | 
|  | atl2_free_ring_resources(adapter); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static inline int TxsFreeUnit(struct atl2_adapter *adapter) | 
|  | { | 
|  | u32 txs_write_ptr = (u32) atomic_read(&adapter->txs_write_ptr); | 
|  |  | 
|  | return (adapter->txs_next_clear >= txs_write_ptr) ? | 
|  | (int) (adapter->txs_ring_size - adapter->txs_next_clear + | 
|  | txs_write_ptr - 1) : | 
|  | (int) (txs_write_ptr - adapter->txs_next_clear - 1); | 
|  | } | 
|  |  | 
|  | static inline int TxdFreeBytes(struct atl2_adapter *adapter) | 
|  | { | 
|  | u32 txd_read_ptr = (u32)atomic_read(&adapter->txd_read_ptr); | 
|  |  | 
|  | return (adapter->txd_write_ptr >= txd_read_ptr) ? | 
|  | (int) (adapter->txd_ring_size - adapter->txd_write_ptr + | 
|  | txd_read_ptr - 1) : | 
|  | (int) (txd_read_ptr - adapter->txd_write_ptr - 1); | 
|  | } | 
|  |  | 
|  | static netdev_tx_t atl2_xmit_frame(struct sk_buff *skb, | 
|  | struct net_device *netdev) | 
|  | { | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  | struct tx_pkt_header *txph; | 
|  | u32 offset, copy_len; | 
|  | int txs_unused; | 
|  | int txbuf_unused; | 
|  |  | 
|  | if (test_bit(__ATL2_DOWN, &adapter->flags)) { | 
|  | dev_kfree_skb_any(skb); | 
|  | return NETDEV_TX_OK; | 
|  | } | 
|  |  | 
|  | if (unlikely(skb->len <= 0)) { | 
|  | dev_kfree_skb_any(skb); | 
|  | return NETDEV_TX_OK; | 
|  | } | 
|  |  | 
|  | txs_unused = TxsFreeUnit(adapter); | 
|  | txbuf_unused = TxdFreeBytes(adapter); | 
|  |  | 
|  | if (skb->len + sizeof(struct tx_pkt_header) + 4  > txbuf_unused || | 
|  | txs_unused < 1) { | 
|  | /* not enough resources */ | 
|  | netif_stop_queue(netdev); | 
|  | return NETDEV_TX_BUSY; | 
|  | } | 
|  |  | 
|  | offset = adapter->txd_write_ptr; | 
|  |  | 
|  | txph = (struct tx_pkt_header *) (((u8 *)adapter->txd_ring) + offset); | 
|  |  | 
|  | *(u32 *)txph = 0; | 
|  | txph->pkt_size = skb->len; | 
|  |  | 
|  | offset += 4; | 
|  | if (offset >= adapter->txd_ring_size) | 
|  | offset -= adapter->txd_ring_size; | 
|  | copy_len = adapter->txd_ring_size - offset; | 
|  | if (copy_len >= skb->len) { | 
|  | memcpy(((u8 *)adapter->txd_ring) + offset, skb->data, skb->len); | 
|  | offset += ((u32)(skb->len + 3) & ~3); | 
|  | } else { | 
|  | memcpy(((u8 *)adapter->txd_ring)+offset, skb->data, copy_len); | 
|  | memcpy((u8 *)adapter->txd_ring, skb->data+copy_len, | 
|  | skb->len-copy_len); | 
|  | offset = ((u32)(skb->len-copy_len + 3) & ~3); | 
|  | } | 
|  | #ifdef NETIF_F_HW_VLAN_TX | 
|  | if (vlan_tx_tag_present(skb)) { | 
|  | u16 vlan_tag = vlan_tx_tag_get(skb); | 
|  | vlan_tag = (vlan_tag << 4) | | 
|  | (vlan_tag >> 13) | | 
|  | ((vlan_tag >> 9) & 0x8); | 
|  | txph->ins_vlan = 1; | 
|  | txph->vlan = vlan_tag; | 
|  | } | 
|  | #endif | 
|  | if (offset >= adapter->txd_ring_size) | 
|  | offset -= adapter->txd_ring_size; | 
|  | adapter->txd_write_ptr = offset; | 
|  |  | 
|  | /* clear txs before send */ | 
|  | adapter->txs_ring[adapter->txs_next_clear].update = 0; | 
|  | if (++adapter->txs_next_clear == adapter->txs_ring_size) | 
|  | adapter->txs_next_clear = 0; | 
|  |  | 
|  | ATL2_WRITE_REGW(&adapter->hw, REG_MB_TXD_WR_IDX, | 
|  | (adapter->txd_write_ptr >> 2)); | 
|  |  | 
|  | mmiowb(); | 
|  | dev_kfree_skb_any(skb); | 
|  | return NETDEV_TX_OK; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * atl2_change_mtu - Change the Maximum Transfer Unit | 
|  | * @netdev: network interface device structure | 
|  | * @new_mtu: new value for maximum frame size | 
|  | * | 
|  | * Returns 0 on success, negative on failure | 
|  | */ | 
|  | static int atl2_change_mtu(struct net_device *netdev, int new_mtu) | 
|  | { | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  | struct atl2_hw *hw = &adapter->hw; | 
|  |  | 
|  | if ((new_mtu < 40) || (new_mtu > (ETH_DATA_LEN + VLAN_SIZE))) | 
|  | return -EINVAL; | 
|  |  | 
|  | /* set MTU */ | 
|  | if (hw->max_frame_size != new_mtu) { | 
|  | netdev->mtu = new_mtu; | 
|  | ATL2_WRITE_REG(hw, REG_MTU, new_mtu + ENET_HEADER_SIZE + | 
|  | VLAN_SIZE + ETHERNET_FCS_SIZE); | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * atl2_set_mac - Change the Ethernet Address of the NIC | 
|  | * @netdev: network interface device structure | 
|  | * @p: pointer to an address structure | 
|  | * | 
|  | * Returns 0 on success, negative on failure | 
|  | */ | 
|  | static int atl2_set_mac(struct net_device *netdev, void *p) | 
|  | { | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  | struct sockaddr *addr = p; | 
|  |  | 
|  | if (!is_valid_ether_addr(addr->sa_data)) | 
|  | return -EADDRNOTAVAIL; | 
|  |  | 
|  | if (netif_running(netdev)) | 
|  | return -EBUSY; | 
|  |  | 
|  | memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); | 
|  | memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len); | 
|  |  | 
|  | atl2_set_mac_addr(&adapter->hw); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * atl2_mii_ioctl - | 
|  | * @netdev: | 
|  | * @ifreq: | 
|  | * @cmd: | 
|  | */ | 
|  | static int atl2_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) | 
|  | { | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  | struct mii_ioctl_data *data = if_mii(ifr); | 
|  | unsigned long flags; | 
|  |  | 
|  | switch (cmd) { | 
|  | case SIOCGMIIPHY: | 
|  | data->phy_id = 0; | 
|  | break; | 
|  | case SIOCGMIIREG: | 
|  | spin_lock_irqsave(&adapter->stats_lock, flags); | 
|  | if (atl2_read_phy_reg(&adapter->hw, | 
|  | data->reg_num & 0x1F, &data->val_out)) { | 
|  | spin_unlock_irqrestore(&adapter->stats_lock, flags); | 
|  | return -EIO; | 
|  | } | 
|  | spin_unlock_irqrestore(&adapter->stats_lock, flags); | 
|  | break; | 
|  | case SIOCSMIIREG: | 
|  | if (data->reg_num & ~(0x1F)) | 
|  | return -EFAULT; | 
|  | spin_lock_irqsave(&adapter->stats_lock, flags); | 
|  | if (atl2_write_phy_reg(&adapter->hw, data->reg_num, | 
|  | data->val_in)) { | 
|  | spin_unlock_irqrestore(&adapter->stats_lock, flags); | 
|  | return -EIO; | 
|  | } | 
|  | spin_unlock_irqrestore(&adapter->stats_lock, flags); | 
|  | break; | 
|  | default: | 
|  | return -EOPNOTSUPP; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * atl2_ioctl - | 
|  | * @netdev: | 
|  | * @ifreq: | 
|  | * @cmd: | 
|  | */ | 
|  | static int atl2_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) | 
|  | { | 
|  | switch (cmd) { | 
|  | case SIOCGMIIPHY: | 
|  | case SIOCGMIIREG: | 
|  | case SIOCSMIIREG: | 
|  | return atl2_mii_ioctl(netdev, ifr, cmd); | 
|  | #ifdef ETHTOOL_OPS_COMPAT | 
|  | case SIOCETHTOOL: | 
|  | return ethtool_ioctl(ifr); | 
|  | #endif | 
|  | default: | 
|  | return -EOPNOTSUPP; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * atl2_tx_timeout - Respond to a Tx Hang | 
|  | * @netdev: network interface device structure | 
|  | */ | 
|  | static void atl2_tx_timeout(struct net_device *netdev) | 
|  | { | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  |  | 
|  | /* Do the reset outside of interrupt context */ | 
|  | schedule_work(&adapter->reset_task); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * atl2_watchdog - Timer Call-back | 
|  | * @data: pointer to netdev cast into an unsigned long | 
|  | */ | 
|  | static void atl2_watchdog(unsigned long data) | 
|  | { | 
|  | struct atl2_adapter *adapter = (struct atl2_adapter *) data; | 
|  |  | 
|  | if (!test_bit(__ATL2_DOWN, &adapter->flags)) { | 
|  | u32 drop_rxd, drop_rxs; | 
|  | unsigned long flags; | 
|  |  | 
|  | spin_lock_irqsave(&adapter->stats_lock, flags); | 
|  | drop_rxd = ATL2_READ_REG(&adapter->hw, REG_STS_RXD_OV); | 
|  | drop_rxs = ATL2_READ_REG(&adapter->hw, REG_STS_RXS_OV); | 
|  | spin_unlock_irqrestore(&adapter->stats_lock, flags); | 
|  |  | 
|  | adapter->netdev->stats.rx_over_errors += drop_rxd + drop_rxs; | 
|  |  | 
|  | /* Reset the timer */ | 
|  | mod_timer(&adapter->watchdog_timer, | 
|  | round_jiffies(jiffies + 4 * HZ)); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * atl2_phy_config - Timer Call-back | 
|  | * @data: pointer to netdev cast into an unsigned long | 
|  | */ | 
|  | static void atl2_phy_config(unsigned long data) | 
|  | { | 
|  | struct atl2_adapter *adapter = (struct atl2_adapter *) data; | 
|  | struct atl2_hw *hw = &adapter->hw; | 
|  | unsigned long flags; | 
|  |  | 
|  | spin_lock_irqsave(&adapter->stats_lock, flags); | 
|  | atl2_write_phy_reg(hw, MII_ADVERTISE, hw->mii_autoneg_adv_reg); | 
|  | atl2_write_phy_reg(hw, MII_BMCR, MII_CR_RESET | MII_CR_AUTO_NEG_EN | | 
|  | MII_CR_RESTART_AUTO_NEG); | 
|  | spin_unlock_irqrestore(&adapter->stats_lock, flags); | 
|  | clear_bit(0, &adapter->cfg_phy); | 
|  | } | 
|  |  | 
|  | static int atl2_up(struct atl2_adapter *adapter) | 
|  | { | 
|  | struct net_device *netdev = adapter->netdev; | 
|  | int err = 0; | 
|  | u32 val; | 
|  |  | 
|  | /* hardware has been reset, we need to reload some things */ | 
|  |  | 
|  | err = atl2_init_hw(&adapter->hw); | 
|  | if (err) { | 
|  | err = -EIO; | 
|  | return err; | 
|  | } | 
|  |  | 
|  | atl2_set_multi(netdev); | 
|  | init_ring_ptrs(adapter); | 
|  |  | 
|  | #ifdef NETIF_F_HW_VLAN_TX | 
|  | atl2_restore_vlan(adapter); | 
|  | #endif | 
|  |  | 
|  | if (atl2_configure(adapter)) { | 
|  | err = -EIO; | 
|  | goto err_up; | 
|  | } | 
|  |  | 
|  | clear_bit(__ATL2_DOWN, &adapter->flags); | 
|  |  | 
|  | val = ATL2_READ_REG(&adapter->hw, REG_MASTER_CTRL); | 
|  | ATL2_WRITE_REG(&adapter->hw, REG_MASTER_CTRL, val | | 
|  | MASTER_CTRL_MANUAL_INT); | 
|  |  | 
|  | atl2_irq_enable(adapter); | 
|  |  | 
|  | err_up: | 
|  | return err; | 
|  | } | 
|  |  | 
|  | static void atl2_reinit_locked(struct atl2_adapter *adapter) | 
|  | { | 
|  | WARN_ON(in_interrupt()); | 
|  | while (test_and_set_bit(__ATL2_RESETTING, &adapter->flags)) | 
|  | msleep(1); | 
|  | atl2_down(adapter); | 
|  | atl2_up(adapter); | 
|  | clear_bit(__ATL2_RESETTING, &adapter->flags); | 
|  | } | 
|  |  | 
|  | static void atl2_reset_task(struct work_struct *work) | 
|  | { | 
|  | struct atl2_adapter *adapter; | 
|  | adapter = container_of(work, struct atl2_adapter, reset_task); | 
|  |  | 
|  | atl2_reinit_locked(adapter); | 
|  | } | 
|  |  | 
|  | static void atl2_setup_mac_ctrl(struct atl2_adapter *adapter) | 
|  | { | 
|  | u32 value; | 
|  | struct atl2_hw *hw = &adapter->hw; | 
|  | struct net_device *netdev = adapter->netdev; | 
|  |  | 
|  | /* Config MAC CTRL Register */ | 
|  | value = MAC_CTRL_TX_EN | MAC_CTRL_RX_EN | MAC_CTRL_MACLP_CLK_PHY; | 
|  |  | 
|  | /* duplex */ | 
|  | if (FULL_DUPLEX == adapter->link_duplex) | 
|  | value |= MAC_CTRL_DUPLX; | 
|  |  | 
|  | /* flow control */ | 
|  | value |= (MAC_CTRL_TX_FLOW | MAC_CTRL_RX_FLOW); | 
|  |  | 
|  | /* PAD & CRC */ | 
|  | value |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD); | 
|  |  | 
|  | /* preamble length */ | 
|  | value |= (((u32)adapter->hw.preamble_len & MAC_CTRL_PRMLEN_MASK) << | 
|  | MAC_CTRL_PRMLEN_SHIFT); | 
|  |  | 
|  | /* vlan */ | 
|  | if (adapter->vlgrp) | 
|  | value |= MAC_CTRL_RMV_VLAN; | 
|  |  | 
|  | /* filter mode */ | 
|  | value |= MAC_CTRL_BC_EN; | 
|  | if (netdev->flags & IFF_PROMISC) | 
|  | value |= MAC_CTRL_PROMIS_EN; | 
|  | else if (netdev->flags & IFF_ALLMULTI) | 
|  | value |= MAC_CTRL_MC_ALL_EN; | 
|  |  | 
|  | /* half retry buffer */ | 
|  | value |= (((u32)(adapter->hw.retry_buf & | 
|  | MAC_CTRL_HALF_LEFT_BUF_MASK)) << MAC_CTRL_HALF_LEFT_BUF_SHIFT); | 
|  |  | 
|  | ATL2_WRITE_REG(hw, REG_MAC_CTRL, value); | 
|  | } | 
|  |  | 
|  | static int atl2_check_link(struct atl2_adapter *adapter) | 
|  | { | 
|  | struct atl2_hw *hw = &adapter->hw; | 
|  | struct net_device *netdev = adapter->netdev; | 
|  | int ret_val; | 
|  | u16 speed, duplex, phy_data; | 
|  | int reconfig = 0; | 
|  |  | 
|  | /* MII_BMSR must read twise */ | 
|  | atl2_read_phy_reg(hw, MII_BMSR, &phy_data); | 
|  | atl2_read_phy_reg(hw, MII_BMSR, &phy_data); | 
|  | if (!(phy_data&BMSR_LSTATUS)) { /* link down */ | 
|  | if (netif_carrier_ok(netdev)) { /* old link state: Up */ | 
|  | u32 value; | 
|  | /* disable rx */ | 
|  | value = ATL2_READ_REG(hw, REG_MAC_CTRL); | 
|  | value &= ~MAC_CTRL_RX_EN; | 
|  | ATL2_WRITE_REG(hw, REG_MAC_CTRL, value); | 
|  | adapter->link_speed = SPEED_0; | 
|  | netif_carrier_off(netdev); | 
|  | netif_stop_queue(netdev); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Link Up */ | 
|  | ret_val = atl2_get_speed_and_duplex(hw, &speed, &duplex); | 
|  | if (ret_val) | 
|  | return ret_val; | 
|  | switch (hw->MediaType) { | 
|  | case MEDIA_TYPE_100M_FULL: | 
|  | if (speed  != SPEED_100 || duplex != FULL_DUPLEX) | 
|  | reconfig = 1; | 
|  | break; | 
|  | case MEDIA_TYPE_100M_HALF: | 
|  | if (speed  != SPEED_100 || duplex != HALF_DUPLEX) | 
|  | reconfig = 1; | 
|  | break; | 
|  | case MEDIA_TYPE_10M_FULL: | 
|  | if (speed != SPEED_10 || duplex != FULL_DUPLEX) | 
|  | reconfig = 1; | 
|  | break; | 
|  | case MEDIA_TYPE_10M_HALF: | 
|  | if (speed  != SPEED_10 || duplex != HALF_DUPLEX) | 
|  | reconfig = 1; | 
|  | break; | 
|  | } | 
|  | /* link result is our setting */ | 
|  | if (reconfig == 0) { | 
|  | if (adapter->link_speed != speed || | 
|  | adapter->link_duplex != duplex) { | 
|  | adapter->link_speed = speed; | 
|  | adapter->link_duplex = duplex; | 
|  | atl2_setup_mac_ctrl(adapter); | 
|  | printk(KERN_INFO "%s: %s NIC Link is Up<%d Mbps %s>\n", | 
|  | atl2_driver_name, netdev->name, | 
|  | adapter->link_speed, | 
|  | adapter->link_duplex == FULL_DUPLEX ? | 
|  | "Full Duplex" : "Half Duplex"); | 
|  | } | 
|  |  | 
|  | if (!netif_carrier_ok(netdev)) { /* Link down -> Up */ | 
|  | netif_carrier_on(netdev); | 
|  | netif_wake_queue(netdev); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* change original link status */ | 
|  | if (netif_carrier_ok(netdev)) { | 
|  | u32 value; | 
|  | /* disable rx */ | 
|  | value = ATL2_READ_REG(hw, REG_MAC_CTRL); | 
|  | value &= ~MAC_CTRL_RX_EN; | 
|  | ATL2_WRITE_REG(hw, REG_MAC_CTRL, value); | 
|  |  | 
|  | adapter->link_speed = SPEED_0; | 
|  | netif_carrier_off(netdev); | 
|  | netif_stop_queue(netdev); | 
|  | } | 
|  |  | 
|  | /* auto-neg, insert timer to re-config phy | 
|  | * (if interval smaller than 5 seconds, something strange) */ | 
|  | if (!test_bit(__ATL2_DOWN, &adapter->flags)) { | 
|  | if (!test_and_set_bit(0, &adapter->cfg_phy)) | 
|  | mod_timer(&adapter->phy_config_timer, | 
|  | round_jiffies(jiffies + 5 * HZ)); | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * atl2_link_chg_task - deal with link change event Out of interrupt context | 
|  | * @netdev: network interface device structure | 
|  | */ | 
|  | static void atl2_link_chg_task(struct work_struct *work) | 
|  | { | 
|  | struct atl2_adapter *adapter; | 
|  | unsigned long flags; | 
|  |  | 
|  | adapter = container_of(work, struct atl2_adapter, link_chg_task); | 
|  |  | 
|  | spin_lock_irqsave(&adapter->stats_lock, flags); | 
|  | atl2_check_link(adapter); | 
|  | spin_unlock_irqrestore(&adapter->stats_lock, flags); | 
|  | } | 
|  |  | 
|  | static void atl2_setup_pcicmd(struct pci_dev *pdev) | 
|  | { | 
|  | u16 cmd; | 
|  |  | 
|  | pci_read_config_word(pdev, PCI_COMMAND, &cmd); | 
|  |  | 
|  | if (cmd & PCI_COMMAND_INTX_DISABLE) | 
|  | cmd &= ~PCI_COMMAND_INTX_DISABLE; | 
|  | if (cmd & PCI_COMMAND_IO) | 
|  | cmd &= ~PCI_COMMAND_IO; | 
|  | if (0 == (cmd & PCI_COMMAND_MEMORY)) | 
|  | cmd |= PCI_COMMAND_MEMORY; | 
|  | if (0 == (cmd & PCI_COMMAND_MASTER)) | 
|  | cmd |= PCI_COMMAND_MASTER; | 
|  | pci_write_config_word(pdev, PCI_COMMAND, cmd); | 
|  |  | 
|  | /* | 
|  | * some motherboards BIOS(PXE/EFI) driver may set PME | 
|  | * while they transfer control to OS (Windows/Linux) | 
|  | * so we should clear this bit before NIC work normally | 
|  | */ | 
|  | pci_write_config_dword(pdev, REG_PM_CTRLSTAT, 0); | 
|  | } | 
|  |  | 
|  | #ifdef CONFIG_NET_POLL_CONTROLLER | 
|  | static void atl2_poll_controller(struct net_device *netdev) | 
|  | { | 
|  | disable_irq(netdev->irq); | 
|  | atl2_intr(netdev->irq, netdev); | 
|  | enable_irq(netdev->irq); | 
|  | } | 
|  | #endif | 
|  |  | 
|  |  | 
|  | static const struct net_device_ops atl2_netdev_ops = { | 
|  | .ndo_open		= atl2_open, | 
|  | .ndo_stop		= atl2_close, | 
|  | .ndo_start_xmit		= atl2_xmit_frame, | 
|  | .ndo_set_multicast_list	= atl2_set_multi, | 
|  | .ndo_validate_addr	= eth_validate_addr, | 
|  | .ndo_set_mac_address	= atl2_set_mac, | 
|  | .ndo_change_mtu		= atl2_change_mtu, | 
|  | .ndo_do_ioctl		= atl2_ioctl, | 
|  | .ndo_tx_timeout		= atl2_tx_timeout, | 
|  | .ndo_vlan_rx_register	= atl2_vlan_rx_register, | 
|  | #ifdef CONFIG_NET_POLL_CONTROLLER | 
|  | .ndo_poll_controller	= atl2_poll_controller, | 
|  | #endif | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * atl2_probe - Device Initialization Routine | 
|  | * @pdev: PCI device information struct | 
|  | * @ent: entry in atl2_pci_tbl | 
|  | * | 
|  | * Returns 0 on success, negative on failure | 
|  | * | 
|  | * atl2_probe initializes an adapter identified by a pci_dev structure. | 
|  | * The OS initialization, configuring of the adapter private structure, | 
|  | * and a hardware reset occur. | 
|  | */ | 
|  | static int __devinit atl2_probe(struct pci_dev *pdev, | 
|  | const struct pci_device_id *ent) | 
|  | { | 
|  | struct net_device *netdev; | 
|  | struct atl2_adapter *adapter; | 
|  | static int cards_found; | 
|  | unsigned long mmio_start; | 
|  | int mmio_len; | 
|  | int err; | 
|  |  | 
|  | cards_found = 0; | 
|  |  | 
|  | err = pci_enable_device(pdev); | 
|  | if (err) | 
|  | return err; | 
|  |  | 
|  | /* | 
|  | * atl2 is a shared-high-32-bit device, so we're stuck with 32-bit DMA | 
|  | * until the kernel has the proper infrastructure to support 64-bit DMA | 
|  | * on these devices. | 
|  | */ | 
|  | if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) && | 
|  | pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { | 
|  | printk(KERN_ERR "atl2: No usable DMA configuration, aborting\n"); | 
|  | goto err_dma; | 
|  | } | 
|  |  | 
|  | /* Mark all PCI regions associated with PCI device | 
|  | * pdev as being reserved by owner atl2_driver_name */ | 
|  | err = pci_request_regions(pdev, atl2_driver_name); | 
|  | if (err) | 
|  | goto err_pci_reg; | 
|  |  | 
|  | /* Enables bus-mastering on the device and calls | 
|  | * pcibios_set_master to do the needed arch specific settings */ | 
|  | pci_set_master(pdev); | 
|  |  | 
|  | err = -ENOMEM; | 
|  | netdev = alloc_etherdev(sizeof(struct atl2_adapter)); | 
|  | if (!netdev) | 
|  | goto err_alloc_etherdev; | 
|  |  | 
|  | SET_NETDEV_DEV(netdev, &pdev->dev); | 
|  |  | 
|  | pci_set_drvdata(pdev, netdev); | 
|  | adapter = netdev_priv(netdev); | 
|  | adapter->netdev = netdev; | 
|  | adapter->pdev = pdev; | 
|  | adapter->hw.back = adapter; | 
|  |  | 
|  | mmio_start = pci_resource_start(pdev, 0x0); | 
|  | mmio_len = pci_resource_len(pdev, 0x0); | 
|  |  | 
|  | adapter->hw.mem_rang = (u32)mmio_len; | 
|  | adapter->hw.hw_addr = ioremap(mmio_start, mmio_len); | 
|  | if (!adapter->hw.hw_addr) { | 
|  | err = -EIO; | 
|  | goto err_ioremap; | 
|  | } | 
|  |  | 
|  | atl2_setup_pcicmd(pdev); | 
|  |  | 
|  | netdev->netdev_ops = &atl2_netdev_ops; | 
|  | atl2_set_ethtool_ops(netdev); | 
|  | netdev->watchdog_timeo = 5 * HZ; | 
|  | strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); | 
|  |  | 
|  | netdev->mem_start = mmio_start; | 
|  | netdev->mem_end = mmio_start + mmio_len; | 
|  | adapter->bd_number = cards_found; | 
|  | adapter->pci_using_64 = false; | 
|  |  | 
|  | /* setup the private structure */ | 
|  | err = atl2_sw_init(adapter); | 
|  | if (err) | 
|  | goto err_sw_init; | 
|  |  | 
|  | err = -EIO; | 
|  |  | 
|  | netdev->hw_features = NETIF_F_SG; | 
|  | netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX); | 
|  |  | 
|  | /* Init PHY as early as possible due to power saving issue  */ | 
|  | atl2_phy_init(&adapter->hw); | 
|  |  | 
|  | /* reset the controller to | 
|  | * put the device in a known good starting state */ | 
|  |  | 
|  | if (atl2_reset_hw(&adapter->hw)) { | 
|  | err = -EIO; | 
|  | goto err_reset; | 
|  | } | 
|  |  | 
|  | /* copy the MAC address out of the EEPROM */ | 
|  | atl2_read_mac_addr(&adapter->hw); | 
|  | memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len); | 
|  | /* FIXME: do we still need this? */ | 
|  | #ifdef ETHTOOL_GPERMADDR | 
|  | memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len); | 
|  |  | 
|  | if (!is_valid_ether_addr(netdev->perm_addr)) { | 
|  | #else | 
|  | if (!is_valid_ether_addr(netdev->dev_addr)) { | 
|  | #endif | 
|  | err = -EIO; | 
|  | goto err_eeprom; | 
|  | } | 
|  |  | 
|  | atl2_check_options(adapter); | 
|  |  | 
|  | init_timer(&adapter->watchdog_timer); | 
|  | adapter->watchdog_timer.function = atl2_watchdog; | 
|  | adapter->watchdog_timer.data = (unsigned long) adapter; | 
|  |  | 
|  | init_timer(&adapter->phy_config_timer); | 
|  | adapter->phy_config_timer.function = atl2_phy_config; | 
|  | adapter->phy_config_timer.data = (unsigned long) adapter; | 
|  |  | 
|  | INIT_WORK(&adapter->reset_task, atl2_reset_task); | 
|  | INIT_WORK(&adapter->link_chg_task, atl2_link_chg_task); | 
|  |  | 
|  | strcpy(netdev->name, "eth%d"); /* ?? */ | 
|  | err = register_netdev(netdev); | 
|  | if (err) | 
|  | goto err_register; | 
|  |  | 
|  | /* assume we have no link for now */ | 
|  | netif_carrier_off(netdev); | 
|  | netif_stop_queue(netdev); | 
|  |  | 
|  | cards_found++; | 
|  |  | 
|  | return 0; | 
|  |  | 
|  | err_reset: | 
|  | err_register: | 
|  | err_sw_init: | 
|  | err_eeprom: | 
|  | iounmap(adapter->hw.hw_addr); | 
|  | err_ioremap: | 
|  | free_netdev(netdev); | 
|  | err_alloc_etherdev: | 
|  | pci_release_regions(pdev); | 
|  | err_pci_reg: | 
|  | err_dma: | 
|  | pci_disable_device(pdev); | 
|  | return err; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * atl2_remove - Device Removal Routine | 
|  | * @pdev: PCI device information struct | 
|  | * | 
|  | * atl2_remove is called by the PCI subsystem to alert the driver | 
|  | * that it should release a PCI device.  The could be caused by a | 
|  | * Hot-Plug event, or because the driver is going to be removed from | 
|  | * memory. | 
|  | */ | 
|  | /* FIXME: write the original MAC address back in case it was changed from a | 
|  | * BIOS-set value, as in atl1 -- CHS */ | 
|  | static void __devexit atl2_remove(struct pci_dev *pdev) | 
|  | { | 
|  | struct net_device *netdev = pci_get_drvdata(pdev); | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  |  | 
|  | /* flush_scheduled work may reschedule our watchdog task, so | 
|  | * explicitly disable watchdog tasks from being rescheduled  */ | 
|  | set_bit(__ATL2_DOWN, &adapter->flags); | 
|  |  | 
|  | del_timer_sync(&adapter->watchdog_timer); | 
|  | del_timer_sync(&adapter->phy_config_timer); | 
|  | cancel_work_sync(&adapter->reset_task); | 
|  | cancel_work_sync(&adapter->link_chg_task); | 
|  |  | 
|  | unregister_netdev(netdev); | 
|  |  | 
|  | atl2_force_ps(&adapter->hw); | 
|  |  | 
|  | iounmap(adapter->hw.hw_addr); | 
|  | pci_release_regions(pdev); | 
|  |  | 
|  | free_netdev(netdev); | 
|  |  | 
|  | pci_disable_device(pdev); | 
|  | } | 
|  |  | 
|  | static int atl2_suspend(struct pci_dev *pdev, pm_message_t state) | 
|  | { | 
|  | struct net_device *netdev = pci_get_drvdata(pdev); | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  | struct atl2_hw *hw = &adapter->hw; | 
|  | u16 speed, duplex; | 
|  | u32 ctrl = 0; | 
|  | u32 wufc = adapter->wol; | 
|  |  | 
|  | #ifdef CONFIG_PM | 
|  | int retval = 0; | 
|  | #endif | 
|  |  | 
|  | netif_device_detach(netdev); | 
|  |  | 
|  | if (netif_running(netdev)) { | 
|  | WARN_ON(test_bit(__ATL2_RESETTING, &adapter->flags)); | 
|  | atl2_down(adapter); | 
|  | } | 
|  |  | 
|  | #ifdef CONFIG_PM | 
|  | retval = pci_save_state(pdev); | 
|  | if (retval) | 
|  | return retval; | 
|  | #endif | 
|  |  | 
|  | atl2_read_phy_reg(hw, MII_BMSR, (u16 *)&ctrl); | 
|  | atl2_read_phy_reg(hw, MII_BMSR, (u16 *)&ctrl); | 
|  | if (ctrl & BMSR_LSTATUS) | 
|  | wufc &= ~ATLX_WUFC_LNKC; | 
|  |  | 
|  | if (0 != (ctrl & BMSR_LSTATUS) && 0 != wufc) { | 
|  | u32 ret_val; | 
|  | /* get current link speed & duplex */ | 
|  | ret_val = atl2_get_speed_and_duplex(hw, &speed, &duplex); | 
|  | if (ret_val) { | 
|  | printk(KERN_DEBUG | 
|  | "%s: get speed&duplex error while suspend\n", | 
|  | atl2_driver_name); | 
|  | goto wol_dis; | 
|  | } | 
|  |  | 
|  | ctrl = 0; | 
|  |  | 
|  | /* turn on magic packet wol */ | 
|  | if (wufc & ATLX_WUFC_MAG) | 
|  | ctrl |= (WOL_MAGIC_EN | WOL_MAGIC_PME_EN); | 
|  |  | 
|  | /* ignore Link Chg event when Link is up */ | 
|  | ATL2_WRITE_REG(hw, REG_WOL_CTRL, ctrl); | 
|  |  | 
|  | /* Config MAC CTRL Register */ | 
|  | ctrl = MAC_CTRL_RX_EN | MAC_CTRL_MACLP_CLK_PHY; | 
|  | if (FULL_DUPLEX == adapter->link_duplex) | 
|  | ctrl |= MAC_CTRL_DUPLX; | 
|  | ctrl |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD); | 
|  | ctrl |= (((u32)adapter->hw.preamble_len & | 
|  | MAC_CTRL_PRMLEN_MASK) << MAC_CTRL_PRMLEN_SHIFT); | 
|  | ctrl |= (((u32)(adapter->hw.retry_buf & | 
|  | MAC_CTRL_HALF_LEFT_BUF_MASK)) << | 
|  | MAC_CTRL_HALF_LEFT_BUF_SHIFT); | 
|  | if (wufc & ATLX_WUFC_MAG) { | 
|  | /* magic packet maybe Broadcast&multicast&Unicast */ | 
|  | ctrl |= MAC_CTRL_BC_EN; | 
|  | } | 
|  |  | 
|  | ATL2_WRITE_REG(hw, REG_MAC_CTRL, ctrl); | 
|  |  | 
|  | /* pcie patch */ | 
|  | ctrl = ATL2_READ_REG(hw, REG_PCIE_PHYMISC); | 
|  | ctrl |= PCIE_PHYMISC_FORCE_RCV_DET; | 
|  | ATL2_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl); | 
|  | ctrl = ATL2_READ_REG(hw, REG_PCIE_DLL_TX_CTRL1); | 
|  | ctrl |= PCIE_DLL_TX_CTRL1_SEL_NOR_CLK; | 
|  | ATL2_WRITE_REG(hw, REG_PCIE_DLL_TX_CTRL1, ctrl); | 
|  |  | 
|  | pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); | 
|  | goto suspend_exit; | 
|  | } | 
|  |  | 
|  | if (0 == (ctrl&BMSR_LSTATUS) && 0 != (wufc&ATLX_WUFC_LNKC)) { | 
|  | /* link is down, so only LINK CHG WOL event enable */ | 
|  | ctrl |= (WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN); | 
|  | ATL2_WRITE_REG(hw, REG_WOL_CTRL, ctrl); | 
|  | ATL2_WRITE_REG(hw, REG_MAC_CTRL, 0); | 
|  |  | 
|  | /* pcie patch */ | 
|  | ctrl = ATL2_READ_REG(hw, REG_PCIE_PHYMISC); | 
|  | ctrl |= PCIE_PHYMISC_FORCE_RCV_DET; | 
|  | ATL2_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl); | 
|  | ctrl = ATL2_READ_REG(hw, REG_PCIE_DLL_TX_CTRL1); | 
|  | ctrl |= PCIE_DLL_TX_CTRL1_SEL_NOR_CLK; | 
|  | ATL2_WRITE_REG(hw, REG_PCIE_DLL_TX_CTRL1, ctrl); | 
|  |  | 
|  | hw->phy_configured = false; /* re-init PHY when resume */ | 
|  |  | 
|  | pci_enable_wake(pdev, pci_choose_state(pdev, state), 1); | 
|  |  | 
|  | goto suspend_exit; | 
|  | } | 
|  |  | 
|  | wol_dis: | 
|  | /* WOL disabled */ | 
|  | ATL2_WRITE_REG(hw, REG_WOL_CTRL, 0); | 
|  |  | 
|  | /* pcie patch */ | 
|  | ctrl = ATL2_READ_REG(hw, REG_PCIE_PHYMISC); | 
|  | ctrl |= PCIE_PHYMISC_FORCE_RCV_DET; | 
|  | ATL2_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl); | 
|  | ctrl = ATL2_READ_REG(hw, REG_PCIE_DLL_TX_CTRL1); | 
|  | ctrl |= PCIE_DLL_TX_CTRL1_SEL_NOR_CLK; | 
|  | ATL2_WRITE_REG(hw, REG_PCIE_DLL_TX_CTRL1, ctrl); | 
|  |  | 
|  | atl2_force_ps(hw); | 
|  | hw->phy_configured = false; /* re-init PHY when resume */ | 
|  |  | 
|  | pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); | 
|  |  | 
|  | suspend_exit: | 
|  | if (netif_running(netdev)) | 
|  | atl2_free_irq(adapter); | 
|  |  | 
|  | pci_disable_device(pdev); | 
|  |  | 
|  | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #ifdef CONFIG_PM | 
|  | static int atl2_resume(struct pci_dev *pdev) | 
|  | { | 
|  | struct net_device *netdev = pci_get_drvdata(pdev); | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  | u32 err; | 
|  |  | 
|  | pci_set_power_state(pdev, PCI_D0); | 
|  | pci_restore_state(pdev); | 
|  |  | 
|  | err = pci_enable_device(pdev); | 
|  | if (err) { | 
|  | printk(KERN_ERR | 
|  | "atl2: Cannot enable PCI device from suspend\n"); | 
|  | return err; | 
|  | } | 
|  |  | 
|  | pci_set_master(pdev); | 
|  |  | 
|  | ATL2_READ_REG(&adapter->hw, REG_WOL_CTRL); /* clear WOL status */ | 
|  |  | 
|  | pci_enable_wake(pdev, PCI_D3hot, 0); | 
|  | pci_enable_wake(pdev, PCI_D3cold, 0); | 
|  |  | 
|  | ATL2_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0); | 
|  |  | 
|  | if (netif_running(netdev)) { | 
|  | err = atl2_request_irq(adapter); | 
|  | if (err) | 
|  | return err; | 
|  | } | 
|  |  | 
|  | atl2_reset_hw(&adapter->hw); | 
|  |  | 
|  | if (netif_running(netdev)) | 
|  | atl2_up(adapter); | 
|  |  | 
|  | netif_device_attach(netdev); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | static void atl2_shutdown(struct pci_dev *pdev) | 
|  | { | 
|  | atl2_suspend(pdev, PMSG_SUSPEND); | 
|  | } | 
|  |  | 
|  | static struct pci_driver atl2_driver = { | 
|  | .name     = atl2_driver_name, | 
|  | .id_table = atl2_pci_tbl, | 
|  | .probe    = atl2_probe, | 
|  | .remove   = __devexit_p(atl2_remove), | 
|  | /* Power Management Hooks */ | 
|  | .suspend  = atl2_suspend, | 
|  | #ifdef CONFIG_PM | 
|  | .resume   = atl2_resume, | 
|  | #endif | 
|  | .shutdown = atl2_shutdown, | 
|  | }; | 
|  |  | 
|  | /* | 
|  | * atl2_init_module - Driver Registration Routine | 
|  | * | 
|  | * atl2_init_module is the first routine called when the driver is | 
|  | * loaded. All it does is register with the PCI subsystem. | 
|  | */ | 
|  | static int __init atl2_init_module(void) | 
|  | { | 
|  | printk(KERN_INFO "%s - version %s\n", atl2_driver_string, | 
|  | atl2_driver_version); | 
|  | printk(KERN_INFO "%s\n", atl2_copyright); | 
|  | return pci_register_driver(&atl2_driver); | 
|  | } | 
|  | module_init(atl2_init_module); | 
|  |  | 
|  | /* | 
|  | * atl2_exit_module - Driver Exit Cleanup Routine | 
|  | * | 
|  | * atl2_exit_module is called just before the driver is removed | 
|  | * from memory. | 
|  | */ | 
|  | static void __exit atl2_exit_module(void) | 
|  | { | 
|  | pci_unregister_driver(&atl2_driver); | 
|  | } | 
|  | module_exit(atl2_exit_module); | 
|  |  | 
|  | static void atl2_read_pci_cfg(struct atl2_hw *hw, u32 reg, u16 *value) | 
|  | { | 
|  | struct atl2_adapter *adapter = hw->back; | 
|  | pci_read_config_word(adapter->pdev, reg, value); | 
|  | } | 
|  |  | 
|  | static void atl2_write_pci_cfg(struct atl2_hw *hw, u32 reg, u16 *value) | 
|  | { | 
|  | struct atl2_adapter *adapter = hw->back; | 
|  | pci_write_config_word(adapter->pdev, reg, *value); | 
|  | } | 
|  |  | 
|  | static int atl2_get_settings(struct net_device *netdev, | 
|  | struct ethtool_cmd *ecmd) | 
|  | { | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  | struct atl2_hw *hw = &adapter->hw; | 
|  |  | 
|  | ecmd->supported = (SUPPORTED_10baseT_Half | | 
|  | SUPPORTED_10baseT_Full | | 
|  | SUPPORTED_100baseT_Half | | 
|  | SUPPORTED_100baseT_Full | | 
|  | SUPPORTED_Autoneg | | 
|  | SUPPORTED_TP); | 
|  | ecmd->advertising = ADVERTISED_TP; | 
|  |  | 
|  | ecmd->advertising |= ADVERTISED_Autoneg; | 
|  | ecmd->advertising |= hw->autoneg_advertised; | 
|  |  | 
|  | ecmd->port = PORT_TP; | 
|  | ecmd->phy_address = 0; | 
|  | ecmd->transceiver = XCVR_INTERNAL; | 
|  |  | 
|  | if (adapter->link_speed != SPEED_0) { | 
|  | ethtool_cmd_speed_set(ecmd, adapter->link_speed); | 
|  | if (adapter->link_duplex == FULL_DUPLEX) | 
|  | ecmd->duplex = DUPLEX_FULL; | 
|  | else | 
|  | ecmd->duplex = DUPLEX_HALF; | 
|  | } else { | 
|  | ethtool_cmd_speed_set(ecmd, -1); | 
|  | ecmd->duplex = -1; | 
|  | } | 
|  |  | 
|  | ecmd->autoneg = AUTONEG_ENABLE; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int atl2_set_settings(struct net_device *netdev, | 
|  | struct ethtool_cmd *ecmd) | 
|  | { | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  | struct atl2_hw *hw = &adapter->hw; | 
|  |  | 
|  | while (test_and_set_bit(__ATL2_RESETTING, &adapter->flags)) | 
|  | msleep(1); | 
|  |  | 
|  | if (ecmd->autoneg == AUTONEG_ENABLE) { | 
|  | #define MY_ADV_MASK	(ADVERTISE_10_HALF | \ | 
|  | ADVERTISE_10_FULL | \ | 
|  | ADVERTISE_100_HALF| \ | 
|  | ADVERTISE_100_FULL) | 
|  |  | 
|  | if ((ecmd->advertising & MY_ADV_MASK) == MY_ADV_MASK) { | 
|  | hw->MediaType = MEDIA_TYPE_AUTO_SENSOR; | 
|  | hw->autoneg_advertised =  MY_ADV_MASK; | 
|  | } else if ((ecmd->advertising & MY_ADV_MASK) == | 
|  | ADVERTISE_100_FULL) { | 
|  | hw->MediaType = MEDIA_TYPE_100M_FULL; | 
|  | hw->autoneg_advertised = ADVERTISE_100_FULL; | 
|  | } else if ((ecmd->advertising & MY_ADV_MASK) == | 
|  | ADVERTISE_100_HALF) { | 
|  | hw->MediaType = MEDIA_TYPE_100M_HALF; | 
|  | hw->autoneg_advertised = ADVERTISE_100_HALF; | 
|  | } else if ((ecmd->advertising & MY_ADV_MASK) == | 
|  | ADVERTISE_10_FULL) { | 
|  | hw->MediaType = MEDIA_TYPE_10M_FULL; | 
|  | hw->autoneg_advertised = ADVERTISE_10_FULL; | 
|  | }  else if ((ecmd->advertising & MY_ADV_MASK) == | 
|  | ADVERTISE_10_HALF) { | 
|  | hw->MediaType = MEDIA_TYPE_10M_HALF; | 
|  | hw->autoneg_advertised = ADVERTISE_10_HALF; | 
|  | } else { | 
|  | clear_bit(__ATL2_RESETTING, &adapter->flags); | 
|  | return -EINVAL; | 
|  | } | 
|  | ecmd->advertising = hw->autoneg_advertised | | 
|  | ADVERTISED_TP | ADVERTISED_Autoneg; | 
|  | } else { | 
|  | clear_bit(__ATL2_RESETTING, &adapter->flags); | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | /* reset the link */ | 
|  | if (netif_running(adapter->netdev)) { | 
|  | atl2_down(adapter); | 
|  | atl2_up(adapter); | 
|  | } else | 
|  | atl2_reset_hw(&adapter->hw); | 
|  |  | 
|  | clear_bit(__ATL2_RESETTING, &adapter->flags); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static u32 atl2_get_msglevel(struct net_device *netdev) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * It's sane for this to be empty, but we might want to take advantage of this. | 
|  | */ | 
|  | static void atl2_set_msglevel(struct net_device *netdev, u32 data) | 
|  | { | 
|  | } | 
|  |  | 
|  | static int atl2_get_regs_len(struct net_device *netdev) | 
|  | { | 
|  | #define ATL2_REGS_LEN 42 | 
|  | return sizeof(u32) * ATL2_REGS_LEN; | 
|  | } | 
|  |  | 
|  | static void atl2_get_regs(struct net_device *netdev, | 
|  | struct ethtool_regs *regs, void *p) | 
|  | { | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  | struct atl2_hw *hw = &adapter->hw; | 
|  | u32 *regs_buff = p; | 
|  | u16 phy_data; | 
|  |  | 
|  | memset(p, 0, sizeof(u32) * ATL2_REGS_LEN); | 
|  |  | 
|  | regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id; | 
|  |  | 
|  | regs_buff[0]  = ATL2_READ_REG(hw, REG_VPD_CAP); | 
|  | regs_buff[1]  = ATL2_READ_REG(hw, REG_SPI_FLASH_CTRL); | 
|  | regs_buff[2]  = ATL2_READ_REG(hw, REG_SPI_FLASH_CONFIG); | 
|  | regs_buff[3]  = ATL2_READ_REG(hw, REG_TWSI_CTRL); | 
|  | regs_buff[4]  = ATL2_READ_REG(hw, REG_PCIE_DEV_MISC_CTRL); | 
|  | regs_buff[5]  = ATL2_READ_REG(hw, REG_MASTER_CTRL); | 
|  | regs_buff[6]  = ATL2_READ_REG(hw, REG_MANUAL_TIMER_INIT); | 
|  | regs_buff[7]  = ATL2_READ_REG(hw, REG_IRQ_MODU_TIMER_INIT); | 
|  | regs_buff[8]  = ATL2_READ_REG(hw, REG_PHY_ENABLE); | 
|  | regs_buff[9]  = ATL2_READ_REG(hw, REG_CMBDISDMA_TIMER); | 
|  | regs_buff[10] = ATL2_READ_REG(hw, REG_IDLE_STATUS); | 
|  | regs_buff[11] = ATL2_READ_REG(hw, REG_MDIO_CTRL); | 
|  | regs_buff[12] = ATL2_READ_REG(hw, REG_SERDES_LOCK); | 
|  | regs_buff[13] = ATL2_READ_REG(hw, REG_MAC_CTRL); | 
|  | regs_buff[14] = ATL2_READ_REG(hw, REG_MAC_IPG_IFG); | 
|  | regs_buff[15] = ATL2_READ_REG(hw, REG_MAC_STA_ADDR); | 
|  | regs_buff[16] = ATL2_READ_REG(hw, REG_MAC_STA_ADDR+4); | 
|  | regs_buff[17] = ATL2_READ_REG(hw, REG_RX_HASH_TABLE); | 
|  | regs_buff[18] = ATL2_READ_REG(hw, REG_RX_HASH_TABLE+4); | 
|  | regs_buff[19] = ATL2_READ_REG(hw, REG_MAC_HALF_DUPLX_CTRL); | 
|  | regs_buff[20] = ATL2_READ_REG(hw, REG_MTU); | 
|  | regs_buff[21] = ATL2_READ_REG(hw, REG_WOL_CTRL); | 
|  | regs_buff[22] = ATL2_READ_REG(hw, REG_SRAM_TXRAM_END); | 
|  | regs_buff[23] = ATL2_READ_REG(hw, REG_DESC_BASE_ADDR_HI); | 
|  | regs_buff[24] = ATL2_READ_REG(hw, REG_TXD_BASE_ADDR_LO); | 
|  | regs_buff[25] = ATL2_READ_REG(hw, REG_TXD_MEM_SIZE); | 
|  | regs_buff[26] = ATL2_READ_REG(hw, REG_TXS_BASE_ADDR_LO); | 
|  | regs_buff[27] = ATL2_READ_REG(hw, REG_TXS_MEM_SIZE); | 
|  | regs_buff[28] = ATL2_READ_REG(hw, REG_RXD_BASE_ADDR_LO); | 
|  | regs_buff[29] = ATL2_READ_REG(hw, REG_RXD_BUF_NUM); | 
|  | regs_buff[30] = ATL2_READ_REG(hw, REG_DMAR); | 
|  | regs_buff[31] = ATL2_READ_REG(hw, REG_TX_CUT_THRESH); | 
|  | regs_buff[32] = ATL2_READ_REG(hw, REG_DMAW); | 
|  | regs_buff[33] = ATL2_READ_REG(hw, REG_PAUSE_ON_TH); | 
|  | regs_buff[34] = ATL2_READ_REG(hw, REG_PAUSE_OFF_TH); | 
|  | regs_buff[35] = ATL2_READ_REG(hw, REG_MB_TXD_WR_IDX); | 
|  | regs_buff[36] = ATL2_READ_REG(hw, REG_MB_RXD_RD_IDX); | 
|  | regs_buff[38] = ATL2_READ_REG(hw, REG_ISR); | 
|  | regs_buff[39] = ATL2_READ_REG(hw, REG_IMR); | 
|  |  | 
|  | atl2_read_phy_reg(hw, MII_BMCR, &phy_data); | 
|  | regs_buff[40] = (u32)phy_data; | 
|  | atl2_read_phy_reg(hw, MII_BMSR, &phy_data); | 
|  | regs_buff[41] = (u32)phy_data; | 
|  | } | 
|  |  | 
|  | static int atl2_get_eeprom_len(struct net_device *netdev) | 
|  | { | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  |  | 
|  | if (!atl2_check_eeprom_exist(&adapter->hw)) | 
|  | return 512; | 
|  | else | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int atl2_get_eeprom(struct net_device *netdev, | 
|  | struct ethtool_eeprom *eeprom, u8 *bytes) | 
|  | { | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  | struct atl2_hw *hw = &adapter->hw; | 
|  | u32 *eeprom_buff; | 
|  | int first_dword, last_dword; | 
|  | int ret_val = 0; | 
|  | int i; | 
|  |  | 
|  | if (eeprom->len == 0) | 
|  | return -EINVAL; | 
|  |  | 
|  | if (atl2_check_eeprom_exist(hw)) | 
|  | return -EINVAL; | 
|  |  | 
|  | eeprom->magic = hw->vendor_id | (hw->device_id << 16); | 
|  |  | 
|  | first_dword = eeprom->offset >> 2; | 
|  | last_dword = (eeprom->offset + eeprom->len - 1) >> 2; | 
|  |  | 
|  | eeprom_buff = kmalloc(sizeof(u32) * (last_dword - first_dword + 1), | 
|  | GFP_KERNEL); | 
|  | if (!eeprom_buff) | 
|  | return -ENOMEM; | 
|  |  | 
|  | for (i = first_dword; i < last_dword; i++) { | 
|  | if (!atl2_read_eeprom(hw, i*4, &(eeprom_buff[i-first_dword]))) { | 
|  | ret_val = -EIO; | 
|  | goto free; | 
|  | } | 
|  | } | 
|  |  | 
|  | memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 3), | 
|  | eeprom->len); | 
|  | free: | 
|  | kfree(eeprom_buff); | 
|  |  | 
|  | return ret_val; | 
|  | } | 
|  |  | 
|  | static int atl2_set_eeprom(struct net_device *netdev, | 
|  | struct ethtool_eeprom *eeprom, u8 *bytes) | 
|  | { | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  | struct atl2_hw *hw = &adapter->hw; | 
|  | u32 *eeprom_buff; | 
|  | u32 *ptr; | 
|  | int max_len, first_dword, last_dword, ret_val = 0; | 
|  | int i; | 
|  |  | 
|  | if (eeprom->len == 0) | 
|  | return -EOPNOTSUPP; | 
|  |  | 
|  | if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) | 
|  | return -EFAULT; | 
|  |  | 
|  | max_len = 512; | 
|  |  | 
|  | first_dword = eeprom->offset >> 2; | 
|  | last_dword = (eeprom->offset + eeprom->len - 1) >> 2; | 
|  | eeprom_buff = kmalloc(max_len, GFP_KERNEL); | 
|  | if (!eeprom_buff) | 
|  | return -ENOMEM; | 
|  |  | 
|  | ptr = eeprom_buff; | 
|  |  | 
|  | if (eeprom->offset & 3) { | 
|  | /* need read/modify/write of first changed EEPROM word */ | 
|  | /* only the second byte of the word is being modified */ | 
|  | if (!atl2_read_eeprom(hw, first_dword*4, &(eeprom_buff[0]))) { | 
|  | ret_val = -EIO; | 
|  | goto out; | 
|  | } | 
|  | ptr++; | 
|  | } | 
|  | if (((eeprom->offset + eeprom->len) & 3)) { | 
|  | /* | 
|  | * need read/modify/write of last changed EEPROM word | 
|  | * only the first byte of the word is being modified | 
|  | */ | 
|  | if (!atl2_read_eeprom(hw, last_dword * 4, | 
|  | &(eeprom_buff[last_dword - first_dword]))) { | 
|  | ret_val = -EIO; | 
|  | goto out; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Device's eeprom is always little-endian, word addressable */ | 
|  | memcpy(ptr, bytes, eeprom->len); | 
|  |  | 
|  | for (i = 0; i < last_dword - first_dword + 1; i++) { | 
|  | if (!atl2_write_eeprom(hw, ((first_dword+i)*4), eeprom_buff[i])) { | 
|  | ret_val = -EIO; | 
|  | goto out; | 
|  | } | 
|  | } | 
|  | out: | 
|  | kfree(eeprom_buff); | 
|  | return ret_val; | 
|  | } | 
|  |  | 
|  | static void atl2_get_drvinfo(struct net_device *netdev, | 
|  | struct ethtool_drvinfo *drvinfo) | 
|  | { | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  |  | 
|  | strncpy(drvinfo->driver,  atl2_driver_name, 32); | 
|  | strncpy(drvinfo->version, atl2_driver_version, 32); | 
|  | strncpy(drvinfo->fw_version, "L2", 32); | 
|  | strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); | 
|  | drvinfo->n_stats = 0; | 
|  | drvinfo->testinfo_len = 0; | 
|  | drvinfo->regdump_len = atl2_get_regs_len(netdev); | 
|  | drvinfo->eedump_len = atl2_get_eeprom_len(netdev); | 
|  | } | 
|  |  | 
|  | static void atl2_get_wol(struct net_device *netdev, | 
|  | struct ethtool_wolinfo *wol) | 
|  | { | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  |  | 
|  | wol->supported = WAKE_MAGIC; | 
|  | wol->wolopts = 0; | 
|  |  | 
|  | if (adapter->wol & ATLX_WUFC_EX) | 
|  | wol->wolopts |= WAKE_UCAST; | 
|  | if (adapter->wol & ATLX_WUFC_MC) | 
|  | wol->wolopts |= WAKE_MCAST; | 
|  | if (adapter->wol & ATLX_WUFC_BC) | 
|  | wol->wolopts |= WAKE_BCAST; | 
|  | if (adapter->wol & ATLX_WUFC_MAG) | 
|  | wol->wolopts |= WAKE_MAGIC; | 
|  | if (adapter->wol & ATLX_WUFC_LNKC) | 
|  | wol->wolopts |= WAKE_PHY; | 
|  | } | 
|  |  | 
|  | static int atl2_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) | 
|  | { | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  |  | 
|  | if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE)) | 
|  | return -EOPNOTSUPP; | 
|  |  | 
|  | if (wol->wolopts & (WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)) | 
|  | return -EOPNOTSUPP; | 
|  |  | 
|  | /* these settings will always override what we currently have */ | 
|  | adapter->wol = 0; | 
|  |  | 
|  | if (wol->wolopts & WAKE_MAGIC) | 
|  | adapter->wol |= ATLX_WUFC_MAG; | 
|  | if (wol->wolopts & WAKE_PHY) | 
|  | adapter->wol |= ATLX_WUFC_LNKC; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static int atl2_nway_reset(struct net_device *netdev) | 
|  | { | 
|  | struct atl2_adapter *adapter = netdev_priv(netdev); | 
|  | if (netif_running(netdev)) | 
|  | atl2_reinit_locked(adapter); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static const struct ethtool_ops atl2_ethtool_ops = { | 
|  | .get_settings		= atl2_get_settings, | 
|  | .set_settings		= atl2_set_settings, | 
|  | .get_drvinfo		= atl2_get_drvinfo, | 
|  | .get_regs_len		= atl2_get_regs_len, | 
|  | .get_regs		= atl2_get_regs, | 
|  | .get_wol		= atl2_get_wol, | 
|  | .set_wol		= atl2_set_wol, | 
|  | .get_msglevel		= atl2_get_msglevel, | 
|  | .set_msglevel		= atl2_set_msglevel, | 
|  | .nway_reset		= atl2_nway_reset, | 
|  | .get_link		= ethtool_op_get_link, | 
|  | .get_eeprom_len		= atl2_get_eeprom_len, | 
|  | .get_eeprom		= atl2_get_eeprom, | 
|  | .set_eeprom		= atl2_set_eeprom, | 
|  | }; | 
|  |  | 
|  | static void atl2_set_ethtool_ops(struct net_device *netdev) | 
|  | { | 
|  | SET_ETHTOOL_OPS(netdev, &atl2_ethtool_ops); | 
|  | } | 
|  |  | 
|  | #define LBYTESWAP(a)  ((((a) & 0x00ff00ff) << 8) | \ | 
|  | (((a) & 0xff00ff00) >> 8)) | 
|  | #define LONGSWAP(a)   ((LBYTESWAP(a) << 16) | (LBYTESWAP(a) >> 16)) | 
|  | #define SHORTSWAP(a)  (((a) << 8) | ((a) >> 8)) | 
|  |  | 
|  | /* | 
|  | * Reset the transmit and receive units; mask and clear all interrupts. | 
|  | * | 
|  | * hw - Struct containing variables accessed by shared code | 
|  | * return : 0  or  idle status (if error) | 
|  | */ | 
|  | static s32 atl2_reset_hw(struct atl2_hw *hw) | 
|  | { | 
|  | u32 icr; | 
|  | u16 pci_cfg_cmd_word; | 
|  | int i; | 
|  |  | 
|  | /* Workaround for PCI problem when BIOS sets MMRBC incorrectly. */ | 
|  | atl2_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); | 
|  | atl2_write_pci_cfg(hw, PCI_REG_COMMAND, &pci_cfg_cmd_word); | 
|  | } | 
|  |  | 
|  | /* Clear Interrupt mask to stop board from generating | 
|  | * interrupts & Clear any pending interrupt events | 
|  | */ | 
|  | /* FIXME */ | 
|  | /* ATL2_WRITE_REG(hw, REG_IMR, 0); */ | 
|  | /* ATL2_WRITE_REG(hw, REG_ISR, 0xffffffff); */ | 
|  |  | 
|  | /* 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. | 
|  | */ | 
|  | ATL2_WRITE_REG(hw, REG_MASTER_CTRL, MASTER_CTRL_SOFT_RST); | 
|  | wmb(); | 
|  | msleep(1); /* delay about 1ms */ | 
|  |  | 
|  | /* Wait at least 10ms for All module to be Idle */ | 
|  | for (i = 0; i < 10; i++) { | 
|  | icr = ATL2_READ_REG(hw, REG_IDLE_STATUS); | 
|  | if (!icr) | 
|  | break; | 
|  | msleep(1); /* delay 1 ms */ | 
|  | cpu_relax(); | 
|  | } | 
|  |  | 
|  | if (icr) | 
|  | return icr; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #define CUSTOM_SPI_CS_SETUP        2 | 
|  | #define CUSTOM_SPI_CLK_HI          2 | 
|  | #define CUSTOM_SPI_CLK_LO          2 | 
|  | #define CUSTOM_SPI_CS_HOLD         2 | 
|  | #define CUSTOM_SPI_CS_HI           3 | 
|  |  | 
|  | static struct atl2_spi_flash_dev flash_table[] = | 
|  | { | 
|  | /* MFR    WRSR  READ  PROGRAM WREN  WRDI  RDSR  RDID  SECTOR_ERASE CHIP_ERASE */ | 
|  | {"Atmel", 0x0,  0x03, 0x02,   0x06, 0x04, 0x05, 0x15, 0x52,        0x62 }, | 
|  | {"SST",   0x01, 0x03, 0x02,   0x06, 0x04, 0x05, 0x90, 0x20,        0x60 }, | 
|  | {"ST",    0x01, 0x03, 0x02,   0x06, 0x04, 0x05, 0xAB, 0xD8,        0xC7 }, | 
|  | }; | 
|  |  | 
|  | static bool atl2_spi_read(struct atl2_hw *hw, u32 addr, u32 *buf) | 
|  | { | 
|  | int i; | 
|  | u32 value; | 
|  |  | 
|  | ATL2_WRITE_REG(hw, REG_SPI_DATA, 0); | 
|  | ATL2_WRITE_REG(hw, REG_SPI_ADDR, addr); | 
|  |  | 
|  | value = SPI_FLASH_CTRL_WAIT_READY | | 
|  | (CUSTOM_SPI_CS_SETUP & SPI_FLASH_CTRL_CS_SETUP_MASK) << | 
|  | SPI_FLASH_CTRL_CS_SETUP_SHIFT | | 
|  | (CUSTOM_SPI_CLK_HI & SPI_FLASH_CTRL_CLK_HI_MASK) << | 
|  | SPI_FLASH_CTRL_CLK_HI_SHIFT | | 
|  | (CUSTOM_SPI_CLK_LO & SPI_FLASH_CTRL_CLK_LO_MASK) << | 
|  | SPI_FLASH_CTRL_CLK_LO_SHIFT | | 
|  | (CUSTOM_SPI_CS_HOLD & SPI_FLASH_CTRL_CS_HOLD_MASK) << | 
|  | SPI_FLASH_CTRL_CS_HOLD_SHIFT | | 
|  | (CUSTOM_SPI_CS_HI & SPI_FLASH_CTRL_CS_HI_MASK) << | 
|  | SPI_FLASH_CTRL_CS_HI_SHIFT | | 
|  | (0x1 & SPI_FLASH_CTRL_INS_MASK) << SPI_FLASH_CTRL_INS_SHIFT; | 
|  |  | 
|  | ATL2_WRITE_REG(hw, REG_SPI_FLASH_CTRL, value); | 
|  |  | 
|  | value |= SPI_FLASH_CTRL_START; | 
|  |  | 
|  | ATL2_WRITE_REG(hw, REG_SPI_FLASH_CTRL, value); | 
|  |  | 
|  | for (i = 0; i < 10; i++) { | 
|  | msleep(1); | 
|  | value = ATL2_READ_REG(hw, REG_SPI_FLASH_CTRL); | 
|  | if (!(value & SPI_FLASH_CTRL_START)) | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (value & SPI_FLASH_CTRL_START) | 
|  | return false; | 
|  |  | 
|  | *buf = ATL2_READ_REG(hw, REG_SPI_DATA); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * get_permanent_address | 
|  | * return 0 if get valid mac address, | 
|  | */ | 
|  | static int get_permanent_address(struct atl2_hw *hw) | 
|  | { | 
|  | u32 Addr[2]; | 
|  | u32 i, Control; | 
|  | u16 Register; | 
|  | u8  EthAddr[NODE_ADDRESS_SIZE]; | 
|  | bool KeyValid; | 
|  |  | 
|  | if (is_valid_ether_addr(hw->perm_mac_addr)) | 
|  | return 0; | 
|  |  | 
|  | Addr[0] = 0; | 
|  | Addr[1] = 0; | 
|  |  | 
|  | if (!atl2_check_eeprom_exist(hw)) { /* eeprom exists */ | 
|  | Register = 0; | 
|  | KeyValid = false; | 
|  |  | 
|  | /* Read out all EEPROM content */ | 
|  | i = 0; | 
|  | while (1) { | 
|  | if (atl2_read_eeprom(hw, i + 0x100, &Control)) { | 
|  | if (KeyValid) { | 
|  | if (Register == REG_MAC_STA_ADDR) | 
|  | Addr[0] = Control; | 
|  | else if (Register == | 
|  | (REG_MAC_STA_ADDR + 4)) | 
|  | Addr[1] = Control; | 
|  | KeyValid = false; | 
|  | } else if ((Control & 0xff) == 0x5A) { | 
|  | KeyValid = true; | 
|  | Register = (u16) (Control >> 16); | 
|  | } else { | 
|  | /* assume data end while encount an invalid KEYWORD */ | 
|  | break; | 
|  | } | 
|  | } else { | 
|  | break; /* read error */ | 
|  | } | 
|  | i += 4; | 
|  | } | 
|  |  | 
|  | *(u32 *) &EthAddr[2] = LONGSWAP(Addr[0]); | 
|  | *(u16 *) &EthAddr[0] = SHORTSWAP(*(u16 *) &Addr[1]); | 
|  |  | 
|  | if (is_valid_ether_addr(EthAddr)) { | 
|  | memcpy(hw->perm_mac_addr, EthAddr, NODE_ADDRESS_SIZE); | 
|  | return 0; | 
|  | } | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /* see if SPI flash exists? */ | 
|  | Addr[0] = 0; | 
|  | Addr[1] = 0; | 
|  | Register = 0; | 
|  | KeyValid = false; | 
|  | i = 0; | 
|  | while (1) { | 
|  | if (atl2_spi_read(hw, i + 0x1f000, &Control)) { | 
|  | if (KeyValid) { | 
|  | if (Register == REG_MAC_STA_ADDR) | 
|  | Addr[0] = Control; | 
|  | else if (Register == (REG_MAC_STA_ADDR + 4)) | 
|  | Addr[1] = Control; | 
|  | KeyValid = false; | 
|  | } else if ((Control & 0xff) == 0x5A) { | 
|  | KeyValid = true; | 
|  | Register = (u16) (Control >> 16); | 
|  | } else { | 
|  | break; /* data end */ | 
|  | } | 
|  | } else { | 
|  | break; /* read error */ | 
|  | } | 
|  | i += 4; | 
|  | } | 
|  |  | 
|  | *(u32 *) &EthAddr[2] = LONGSWAP(Addr[0]); | 
|  | *(u16 *) &EthAddr[0] = SHORTSWAP(*(u16 *)&Addr[1]); | 
|  | if (is_valid_ether_addr(EthAddr)) { | 
|  | memcpy(hw->perm_mac_addr, EthAddr, NODE_ADDRESS_SIZE); | 
|  | return 0; | 
|  | } | 
|  | /* maybe MAC-address is from BIOS */ | 
|  | Addr[0] = ATL2_READ_REG(hw, REG_MAC_STA_ADDR); | 
|  | Addr[1] = ATL2_READ_REG(hw, REG_MAC_STA_ADDR + 4); | 
|  | *(u32 *) &EthAddr[2] = LONGSWAP(Addr[0]); | 
|  | *(u16 *) &EthAddr[0] = SHORTSWAP(*(u16 *) &Addr[1]); | 
|  |  | 
|  | if (is_valid_ether_addr(EthAddr)) { | 
|  | memcpy(hw->perm_mac_addr, EthAddr, NODE_ADDRESS_SIZE); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Reads the adapter's MAC address from the EEPROM | 
|  | * | 
|  | * hw - Struct containing variables accessed by shared code | 
|  | */ | 
|  | static s32 atl2_read_mac_addr(struct atl2_hw *hw) | 
|  | { | 
|  | u16 i; | 
|  |  | 
|  | if (get_permanent_address(hw)) { | 
|  | /* for test */ | 
|  | /* FIXME: shouldn't we use random_ether_addr() here? */ | 
|  | hw->perm_mac_addr[0] = 0x00; | 
|  | hw->perm_mac_addr[1] = 0x13; | 
|  | hw->perm_mac_addr[2] = 0x74; | 
|  | hw->perm_mac_addr[3] = 0x00; | 
|  | hw->perm_mac_addr[4] = 0x5c; | 
|  | hw->perm_mac_addr[5] = 0x38; | 
|  | } | 
|  |  | 
|  | for (i = 0; i < NODE_ADDRESS_SIZE; i++) | 
|  | hw->mac_addr[i] = hw->perm_mac_addr[i]; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * 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 | 
|  | * | 
|  | * atl2_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 | 
|  | */ | 
|  | static u32 atl2_hash_mc_addr(struct atl2_hw *hw, u8 *mc_addr) | 
|  | { | 
|  | u32 crc32, value; | 
|  | int i; | 
|  |  | 
|  | value = 0; | 
|  | crc32 = ether_crc_le(6, mc_addr); | 
|  |  | 
|  | 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 | 
|  | */ | 
|  | static void atl2_hash_set(struct atl2_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 | 
|  | * register are determined by the lower 5 bits of the value. | 
|  | */ | 
|  | hash_reg = (hash_value >> 31) & 0x1; | 
|  | hash_bit = (hash_value >> 26) & 0x1F; | 
|  |  | 
|  | mta = ATL2_READ_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg); | 
|  |  | 
|  | mta |= (1 << hash_bit); | 
|  |  | 
|  | ATL2_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg, mta); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * atl2_init_pcie - init PCIE module | 
|  | */ | 
|  | static void atl2_init_pcie(struct atl2_hw *hw) | 
|  | { | 
|  | u32 value; | 
|  | value = LTSSM_TEST_MODE_DEF; | 
|  | ATL2_WRITE_REG(hw, REG_LTSSM_TEST_MODE, value); | 
|  |  | 
|  | value = PCIE_DLL_TX_CTRL1_DEF; | 
|  | ATL2_WRITE_REG(hw, REG_PCIE_DLL_TX_CTRL1, value); | 
|  | } | 
|  |  | 
|  | static void atl2_init_flash_opcode(struct atl2_hw *hw) | 
|  | { | 
|  | if (hw->flash_vendor >= ARRAY_SIZE(flash_table)) | 
|  | hw->flash_vendor = 0; /* ATMEL */ | 
|  |  | 
|  | /* Init OP table */ | 
|  | ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_PROGRAM, | 
|  | flash_table[hw->flash_vendor].cmdPROGRAM); | 
|  | ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_SC_ERASE, | 
|  | flash_table[hw->flash_vendor].cmdSECTOR_ERASE); | 
|  | ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_CHIP_ERASE, | 
|  | flash_table[hw->flash_vendor].cmdCHIP_ERASE); | 
|  | ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_RDID, | 
|  | flash_table[hw->flash_vendor].cmdRDID); | 
|  | ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_WREN, | 
|  | flash_table[hw->flash_vendor].cmdWREN); | 
|  | ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_RDSR, | 
|  | flash_table[hw->flash_vendor].cmdRDSR); | 
|  | ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_WRSR, | 
|  | flash_table[hw->flash_vendor].cmdWRSR); | 
|  | ATL2_WRITE_REGB(hw, REG_SPI_FLASH_OP_READ, | 
|  | flash_table[hw->flash_vendor].cmdREAD); | 
|  | } | 
|  |  | 
|  | /******************************************************************** | 
|  | * 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. | 
|  | ********************************************************************/ | 
|  | static s32 atl2_init_hw(struct atl2_hw *hw) | 
|  | { | 
|  | u32 ret_val = 0; | 
|  |  | 
|  | atl2_init_pcie(hw); | 
|  |  | 
|  | /* Zero out the Multicast HASH table */ | 
|  | /* clear the old settings from the multicast hash table */ | 
|  | ATL2_WRITE_REG(hw, REG_RX_HASH_TABLE, 0); | 
|  | ATL2_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0); | 
|  |  | 
|  | atl2_init_flash_opcode(hw); | 
|  |  | 
|  | ret_val = atl2_phy_init(hw); | 
|  |  | 
|  | return ret_val; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * 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 | 
|  | */ | 
|  | static s32 atl2_get_speed_and_duplex(struct atl2_hw *hw, u16 *speed, | 
|  | u16 *duplex) | 
|  | { | 
|  | s32 ret_val; | 
|  | u16 phy_data; | 
|  |  | 
|  | /* Read PHY Specific Status Register (17) */ | 
|  | ret_val = atl2_read_phy_reg(hw, MII_ATLX_PSSR, &phy_data); | 
|  | if (ret_val) | 
|  | return ret_val; | 
|  |  | 
|  | if (!(phy_data & MII_ATLX_PSSR_SPD_DPLX_RESOLVED)) | 
|  | return ATLX_ERR_PHY_RES; | 
|  |  | 
|  | switch (phy_data & MII_ATLX_PSSR_SPEED) { | 
|  | case MII_ATLX_PSSR_100MBS: | 
|  | *speed = SPEED_100; | 
|  | break; | 
|  | case MII_ATLX_PSSR_10MBS: | 
|  | *speed = SPEED_10; | 
|  | break; | 
|  | default: | 
|  | return ATLX_ERR_PHY_SPEED; | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (phy_data & MII_ATLX_PSSR_DPLX) | 
|  | *duplex = FULL_DUPLEX; | 
|  | else | 
|  | *duplex = HALF_DUPLEX; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Reads the value from a PHY register | 
|  | * hw - Struct containing variables accessed by shared code | 
|  | * reg_addr - address of the PHY register to read | 
|  | */ | 
|  | static s32 atl2_read_phy_reg(struct atl2_hw *hw, u16 reg_addr, u16 *phy_data) | 
|  | { | 
|  | u32 val; | 
|  | int i; | 
|  |  | 
|  | 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; | 
|  | ATL2_WRITE_REG(hw, REG_MDIO_CTRL, val); | 
|  |  | 
|  | wmb(); | 
|  |  | 
|  | for (i = 0; i < MDIO_WAIT_TIMES; i++) { | 
|  | udelay(2); | 
|  | val = ATL2_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 0; | 
|  | } | 
|  |  | 
|  | return ATLX_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 | 
|  | */ | 
|  | static s32 atl2_write_phy_reg(struct atl2_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; | 
|  | ATL2_WRITE_REG(hw, REG_MDIO_CTRL, val); | 
|  |  | 
|  | wmb(); | 
|  |  | 
|  | for (i = 0; i < MDIO_WAIT_TIMES; i++) { | 
|  | udelay(2); | 
|  | val = ATL2_READ_REG(hw, REG_MDIO_CTRL); | 
|  | if (!(val & (MDIO_START | MDIO_BUSY))) | 
|  | break; | 
|  |  | 
|  | wmb(); | 
|  | } | 
|  |  | 
|  | if (!(val & (MDIO_START | MDIO_BUSY))) | 
|  | return 0; | 
|  |  | 
|  | return ATLX_ERR_PHY; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Configures PHY autoneg and flow control advertisement settings | 
|  | * | 
|  | * hw - Struct containing variables accessed by shared code | 
|  | */ | 
|  | static s32 atl2_phy_setup_autoneg_adv(struct atl2_hw *hw) | 
|  | { | 
|  | s32 ret_val; | 
|  | s16 mii_autoneg_adv_reg; | 
|  |  | 
|  | /* Read the MII Auto-Neg Advertisement Register (Address 4). */ | 
|  | mii_autoneg_adv_reg = MII_AR_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; | 
|  |  | 
|  | /* Need to parse MediaType and setup the | 
|  | * appropriate PHY registers. */ | 
|  | switch (hw->MediaType) { | 
|  | 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; | 
|  | 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; | 
|  |  | 
|  | ret_val = atl2_write_phy_reg(hw, MII_ADVERTISE, mii_autoneg_adv_reg); | 
|  |  | 
|  | if (ret_val) | 
|  | return ret_val; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * 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) | 
|  | */ | 
|  | static s32 atl2_phy_commit(struct atl2_hw *hw) | 
|  | { | 
|  | s32 ret_val; | 
|  | u16 phy_data; | 
|  |  | 
|  | phy_data = MII_CR_RESET | MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG; | 
|  | ret_val = atl2_write_phy_reg(hw, MII_BMCR, phy_data); | 
|  | if (ret_val) { | 
|  | u32 val; | 
|  | int i; | 
|  | /* pcie serdes link may be down ! */ | 
|  | for (i = 0; i < 25; i++) { | 
|  | msleep(1); | 
|  | val = ATL2_READ_REG(hw, REG_MDIO_CTRL); | 
|  | if (!(val & (MDIO_START | MDIO_BUSY))) | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (0 != (val & (MDIO_START | MDIO_BUSY))) { | 
|  | printk(KERN_ERR "atl2: PCIe link down for at least 25ms !\n"); | 
|  | return ret_val; | 
|  | } | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static s32 atl2_phy_init(struct atl2_hw *hw) | 
|  | { | 
|  | s32 ret_val; | 
|  | u16 phy_val; | 
|  |  | 
|  | if (hw->phy_configured) | 
|  | return 0; | 
|  |  | 
|  | /* Enable PHY */ | 
|  | ATL2_WRITE_REGW(hw, REG_PHY_ENABLE, 1); | 
|  | ATL2_WRITE_FLUSH(hw); | 
|  | msleep(1); | 
|  |  | 
|  | /* check if the PHY is in powersaving mode */ | 
|  | atl2_write_phy_reg(hw, MII_DBG_ADDR, 0); | 
|  | atl2_read_phy_reg(hw, MII_DBG_DATA, &phy_val); | 
|  |  | 
|  | /* 024E / 124E 0r 0274 / 1274 ? */ | 
|  | if (phy_val & 0x1000) { | 
|  | phy_val &= ~0x1000; | 
|  | atl2_write_phy_reg(hw, MII_DBG_DATA, phy_val); | 
|  | } | 
|  |  | 
|  | msleep(1); | 
|  |  | 
|  | /*Enable PHY LinkChange Interrupt */ | 
|  | ret_val = atl2_write_phy_reg(hw, 18, 0xC00); | 
|  | if (ret_val) | 
|  | return ret_val; | 
|  |  | 
|  | /* setup AutoNeg parameters */ | 
|  | ret_val = atl2_phy_setup_autoneg_adv(hw); | 
|  | if (ret_val) | 
|  | return ret_val; | 
|  |  | 
|  | /* SW.Reset & En-Auto-Neg to restart Auto-Neg */ | 
|  | ret_val = atl2_phy_commit(hw); | 
|  | if (ret_val) | 
|  | return ret_val; | 
|  |  | 
|  | hw->phy_configured = true; | 
|  |  | 
|  | return ret_val; | 
|  | } | 
|  |  | 
|  | static void atl2_set_mac_addr(struct atl2_hw *hw) | 
|  | { | 
|  | 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])); | 
|  | ATL2_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 0, value); | 
|  | /* hight dword */ | 
|  | value = (((u32)hw->mac_addr[0]) << 8) | | 
|  | (((u32)hw->mac_addr[1])); | 
|  | ATL2_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 1, value); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * check_eeprom_exist | 
|  | * return 0 if eeprom exist | 
|  | */ | 
|  | static int atl2_check_eeprom_exist(struct atl2_hw *hw) | 
|  | { | 
|  | u32 value; | 
|  |  | 
|  | value = ATL2_READ_REG(hw, REG_SPI_FLASH_CTRL); | 
|  | if (value & SPI_FLASH_CTRL_EN_VPD) { | 
|  | value &= ~SPI_FLASH_CTRL_EN_VPD; | 
|  | ATL2_WRITE_REG(hw, REG_SPI_FLASH_CTRL, value); | 
|  | } | 
|  | value = ATL2_READ_REGW(hw, REG_PCIE_CAP_LIST); | 
|  | return ((value & 0xFF00) == 0x6C00) ? 0 : 1; | 
|  | } | 
|  |  | 
|  | /* FIXME: This doesn't look right. -- CHS */ | 
|  | static bool atl2_write_eeprom(struct atl2_hw *hw, u32 offset, u32 value) | 
|  | { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static bool atl2_read_eeprom(struct atl2_hw *hw, u32 Offset, u32 *pValue) | 
|  | { | 
|  | int i; | 
|  | u32    Control; | 
|  |  | 
|  | if (Offset & 0x3) | 
|  | return false; /* address do not align */ | 
|  |  | 
|  | ATL2_WRITE_REG(hw, REG_VPD_DATA, 0); | 
|  | Control = (Offset & VPD_CAP_VPD_ADDR_MASK) << VPD_CAP_VPD_ADDR_SHIFT; | 
|  | ATL2_WRITE_REG(hw, REG_VPD_CAP, Control); | 
|  |  | 
|  | for (i = 0; i < 10; i++) { | 
|  | msleep(2); | 
|  | Control = ATL2_READ_REG(hw, REG_VPD_CAP); | 
|  | if (Control & VPD_CAP_VPD_FLAG) | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (Control & VPD_CAP_VPD_FLAG) { | 
|  | *pValue = ATL2_READ_REG(hw, REG_VPD_DATA); | 
|  | return true; | 
|  | } | 
|  | return false; /* timeout */ | 
|  | } | 
|  |  | 
|  | static void atl2_force_ps(struct atl2_hw *hw) | 
|  | { | 
|  | u16 phy_val; | 
|  |  | 
|  | atl2_write_phy_reg(hw, MII_DBG_ADDR, 0); | 
|  | atl2_read_phy_reg(hw, MII_DBG_DATA, &phy_val); | 
|  | atl2_write_phy_reg(hw, MII_DBG_DATA, phy_val | 0x1000); | 
|  |  | 
|  | atl2_write_phy_reg(hw, MII_DBG_ADDR, 2); | 
|  | atl2_write_phy_reg(hw, MII_DBG_DATA, 0x3000); | 
|  | atl2_write_phy_reg(hw, MII_DBG_ADDR, 3); | 
|  | atl2_write_phy_reg(hw, MII_DBG_DATA, 0); | 
|  | } | 
|  |  | 
|  | /* This is the only thing that needs to be changed to adjust the | 
|  | * maximum number of ports that the driver can manage. | 
|  | */ | 
|  | #define ATL2_MAX_NIC 4 | 
|  |  | 
|  | #define OPTION_UNSET    -1 | 
|  | #define OPTION_DISABLED 0 | 
|  | #define OPTION_ENABLED  1 | 
|  |  | 
|  | /* All parameters are treated the same, as an integer array of values. | 
|  | * This macro just reduces the need to repeat the same declaration code | 
|  | * over and over (plus this helps to avoid typo bugs). | 
|  | */ | 
|  | #define ATL2_PARAM_INIT {[0 ... ATL2_MAX_NIC] = OPTION_UNSET} | 
|  | #ifndef module_param_array | 
|  | /* Module Parameters are always initialized to -1, so that the driver | 
|  | * can tell the difference between no user specified value or the | 
|  | * user asking for the default value. | 
|  | * The true default values are loaded in when atl2_check_options is called. | 
|  | * | 
|  | * This is a GCC extension to ANSI C. | 
|  | * See the item "Labeled Elements in Initializers" in the section | 
|  | * "Extensions to the C Language Family" of the GCC documentation. | 
|  | */ | 
|  |  | 
|  | #define ATL2_PARAM(X, desc) \ | 
|  | static const int __devinitdata X[ATL2_MAX_NIC + 1] = ATL2_PARAM_INIT; \ | 
|  | MODULE_PARM(X, "1-" __MODULE_STRING(ATL2_MAX_NIC) "i"); \ | 
|  | MODULE_PARM_DESC(X, desc); | 
|  | #else | 
|  | #define ATL2_PARAM(X, desc) \ | 
|  | static int __devinitdata X[ATL2_MAX_NIC+1] = ATL2_PARAM_INIT; \ | 
|  | static unsigned int num_##X; \ | 
|  | module_param_array_named(X, X, int, &num_##X, 0); \ | 
|  | MODULE_PARM_DESC(X, desc); | 
|  | #endif | 
|  |  | 
|  | /* | 
|  | * Transmit Memory Size | 
|  | * Valid Range: 64-2048 | 
|  | * Default Value: 128 | 
|  | */ | 
|  | #define ATL2_MIN_TX_MEMSIZE		4	/* 4KB */ | 
|  | #define ATL2_MAX_TX_MEMSIZE		64	/* 64KB */ | 
|  | #define ATL2_DEFAULT_TX_MEMSIZE		8	/* 8KB */ | 
|  | ATL2_PARAM(TxMemSize, "Bytes of Transmit Memory"); | 
|  |  | 
|  | /* | 
|  | * Receive Memory Block Count | 
|  | * Valid Range: 16-512 | 
|  | * Default Value: 128 | 
|  | */ | 
|  | #define ATL2_MIN_RXD_COUNT		16 | 
|  | #define ATL2_MAX_RXD_COUNT		512 | 
|  | #define ATL2_DEFAULT_RXD_COUNT		64 | 
|  | ATL2_PARAM(RxMemBlock, "Number of receive memory block"); | 
|  |  | 
|  | /* | 
|  | * User Specified MediaType Override | 
|  | * | 
|  | * Valid Range: 0-5 | 
|  | *  - 0    - auto-negotiate at all supported speeds | 
|  | *  - 1    - only link at 1000Mbps Full Duplex | 
|  | *  - 2    - only link at 100Mbps Full Duplex | 
|  | *  - 3    - only link at 100Mbps Half Duplex | 
|  | *  - 4    - only link at 10Mbps Full Duplex | 
|  | *  - 5    - only link at 10Mbps Half Duplex | 
|  | * Default Value: 0 | 
|  | */ | 
|  | ATL2_PARAM(MediaType, "MediaType Select"); | 
|  |  | 
|  | /* | 
|  | * Interrupt Moderate Timer in units of 2048 ns (~2 us) | 
|  | * Valid Range: 10-65535 | 
|  | * Default Value: 45000(90ms) | 
|  | */ | 
|  | #define INT_MOD_DEFAULT_CNT	100 /* 200us */ | 
|  | #define INT_MOD_MAX_CNT		65000 | 
|  | #define INT_MOD_MIN_CNT		50 | 
|  | ATL2_PARAM(IntModTimer, "Interrupt Moderator Timer"); | 
|  |  | 
|  | /* | 
|  | * FlashVendor | 
|  | * Valid Range: 0-2 | 
|  | * 0 - Atmel | 
|  | * 1 - SST | 
|  | * 2 - ST | 
|  | */ | 
|  | ATL2_PARAM(FlashVendor, "SPI Flash Vendor"); | 
|  |  | 
|  | #define AUTONEG_ADV_DEFAULT	0x2F | 
|  | #define AUTONEG_ADV_MASK	0x2F | 
|  | #define FLOW_CONTROL_DEFAULT	FLOW_CONTROL_FULL | 
|  |  | 
|  | #define FLASH_VENDOR_DEFAULT	0 | 
|  | #define FLASH_VENDOR_MIN	0 | 
|  | #define FLASH_VENDOR_MAX	2 | 
|  |  | 
|  | struct atl2_option { | 
|  | enum { enable_option, range_option, list_option } type; | 
|  | char *name; | 
|  | char *err; | 
|  | int  def; | 
|  | union { | 
|  | struct { /* range_option info */ | 
|  | int min; | 
|  | int max; | 
|  | } r; | 
|  | struct { /* list_option info */ | 
|  | int nr; | 
|  | struct atl2_opt_list { int i; char *str; } *p; | 
|  | } l; | 
|  | } arg; | 
|  | }; | 
|  |  | 
|  | static int __devinit atl2_validate_option(int *value, struct atl2_option *opt) | 
|  | { | 
|  | int i; | 
|  | struct atl2_opt_list *ent; | 
|  |  | 
|  | if (*value == OPTION_UNSET) { | 
|  | *value = opt->def; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | switch (opt->type) { | 
|  | case enable_option: | 
|  | switch (*value) { | 
|  | case OPTION_ENABLED: | 
|  | printk(KERN_INFO "%s Enabled\n", opt->name); | 
|  | return 0; | 
|  | break; | 
|  | case OPTION_DISABLED: | 
|  | printk(KERN_INFO "%s Disabled\n", opt->name); | 
|  | return 0; | 
|  | break; | 
|  | } | 
|  | break; | 
|  | case range_option: | 
|  | if (*value >= opt->arg.r.min && *value <= opt->arg.r.max) { | 
|  | printk(KERN_INFO "%s set to %i\n", opt->name, *value); | 
|  | return 0; | 
|  | } | 
|  | break; | 
|  | case list_option: | 
|  | for (i = 0; i < opt->arg.l.nr; i++) { | 
|  | ent = &opt->arg.l.p[i]; | 
|  | if (*value == ent->i) { | 
|  | if (ent->str[0] != '\0') | 
|  | printk(KERN_INFO "%s\n", ent->str); | 
|  | return 0; | 
|  | } | 
|  | } | 
|  | break; | 
|  | default: | 
|  | BUG(); | 
|  | } | 
|  |  | 
|  | printk(KERN_INFO "Invalid %s specified (%i) %s\n", | 
|  | opt->name, *value, opt->err); | 
|  | *value = opt->def; | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * atl2_check_options - Range Checking for Command Line Parameters | 
|  | * @adapter: board private structure | 
|  | * | 
|  | * This routine checks all command line parameters for valid user | 
|  | * input.  If an invalid value is given, or if no user specified | 
|  | * value exists, a default value is used.  The final value is stored | 
|  | * in a variable in the adapter structure. | 
|  | */ | 
|  | static void __devinit atl2_check_options(struct atl2_adapter *adapter) | 
|  | { | 
|  | int val; | 
|  | struct atl2_option opt; | 
|  | int bd = adapter->bd_number; | 
|  | if (bd >= ATL2_MAX_NIC) { | 
|  | printk(KERN_NOTICE "Warning: no configuration for board #%i\n", | 
|  | bd); | 
|  | printk(KERN_NOTICE "Using defaults for all values\n"); | 
|  | #ifndef module_param_array | 
|  | bd = ATL2_MAX_NIC; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | /* Bytes of Transmit Memory */ | 
|  | opt.type = range_option; | 
|  | opt.name = "Bytes of Transmit Memory"; | 
|  | opt.err = "using default of " __MODULE_STRING(ATL2_DEFAULT_TX_MEMSIZE); | 
|  | opt.def = ATL2_DEFAULT_TX_MEMSIZE; | 
|  | opt.arg.r.min = ATL2_MIN_TX_MEMSIZE; | 
|  | opt.arg.r.max = ATL2_MAX_TX_MEMSIZE; | 
|  | #ifdef module_param_array | 
|  | if (num_TxMemSize > bd) { | 
|  | #endif | 
|  | val = TxMemSize[bd]; | 
|  | atl2_validate_option(&val, &opt); | 
|  | adapter->txd_ring_size = ((u32) val) * 1024; | 
|  | #ifdef module_param_array | 
|  | } else | 
|  | adapter->txd_ring_size = ((u32)opt.def) * 1024; | 
|  | #endif | 
|  | /* txs ring size: */ | 
|  | adapter->txs_ring_size = adapter->txd_ring_size / 128; | 
|  | if (adapter->txs_ring_size > 160) | 
|  | adapter->txs_ring_size = 160; | 
|  |  | 
|  | /* Receive Memory Block Count */ | 
|  | opt.type = range_option; | 
|  | opt.name = "Number of receive memory block"; | 
|  | opt.err = "using default of " __MODULE_STRING(ATL2_DEFAULT_RXD_COUNT); | 
|  | opt.def = ATL2_DEFAULT_RXD_COUNT; | 
|  | opt.arg.r.min = ATL2_MIN_RXD_COUNT; | 
|  | opt.arg.r.max = ATL2_MAX_RXD_COUNT; | 
|  | #ifdef module_param_array | 
|  | if (num_RxMemBlock > bd) { | 
|  | #endif | 
|  | val = RxMemBlock[bd]; | 
|  | atl2_validate_option(&val, &opt); | 
|  | adapter->rxd_ring_size = (u32)val; | 
|  | /* FIXME */ | 
|  | /* ((u16)val)&~1; */	/* even number */ | 
|  | #ifdef module_param_array | 
|  | } else | 
|  | adapter->rxd_ring_size = (u32)opt.def; | 
|  | #endif | 
|  | /* init RXD Flow control value */ | 
|  | adapter->hw.fc_rxd_hi = (adapter->rxd_ring_size / 8) * 7; | 
|  | adapter->hw.fc_rxd_lo = (ATL2_MIN_RXD_COUNT / 8) > | 
|  | (adapter->rxd_ring_size / 12) ? (ATL2_MIN_RXD_COUNT / 8) : | 
|  | (adapter->rxd_ring_size / 12); | 
|  |  | 
|  | /* Interrupt Moderate Timer */ | 
|  | opt.type = range_option; | 
|  | opt.name = "Interrupt Moderate Timer"; | 
|  | opt.err = "using default of " __MODULE_STRING(INT_MOD_DEFAULT_CNT); | 
|  | opt.def = INT_MOD_DEFAULT_CNT; | 
|  | opt.arg.r.min = INT_MOD_MIN_CNT; | 
|  | opt.arg.r.max = INT_MOD_MAX_CNT; | 
|  | #ifdef module_param_array | 
|  | if (num_IntModTimer > bd) { | 
|  | #endif | 
|  | val = IntModTimer[bd]; | 
|  | atl2_validate_option(&val, &opt); | 
|  | adapter->imt = (u16) val; | 
|  | #ifdef module_param_array | 
|  | } else | 
|  | adapter->imt = (u16)(opt.def); | 
|  | #endif | 
|  | /* Flash Vendor */ | 
|  | opt.type = range_option; | 
|  | opt.name = "SPI Flash Vendor"; | 
|  | opt.err = "using default of " __MODULE_STRING(FLASH_VENDOR_DEFAULT); | 
|  | opt.def = FLASH_VENDOR_DEFAULT; | 
|  | opt.arg.r.min = FLASH_VENDOR_MIN; | 
|  | opt.arg.r.max = FLASH_VENDOR_MAX; | 
|  | #ifdef module_param_array | 
|  | if (num_FlashVendor > bd) { | 
|  | #endif | 
|  | val = FlashVendor[bd]; | 
|  | atl2_validate_option(&val, &opt); | 
|  | adapter->hw.flash_vendor = (u8) val; | 
|  | #ifdef module_param_array | 
|  | } else | 
|  | adapter->hw.flash_vendor = (u8)(opt.def); | 
|  | #endif | 
|  | /* MediaType */ | 
|  | opt.type = range_option; | 
|  | opt.name = "Speed/Duplex Selection"; | 
|  | opt.err = "using default of " __MODULE_STRING(MEDIA_TYPE_AUTO_SENSOR); | 
|  | opt.def = MEDIA_TYPE_AUTO_SENSOR; | 
|  | opt.arg.r.min = MEDIA_TYPE_AUTO_SENSOR; | 
|  | opt.arg.r.max = MEDIA_TYPE_10M_HALF; | 
|  | #ifdef module_param_array | 
|  | if (num_MediaType > bd) { | 
|  | #endif | 
|  | val = MediaType[bd]; | 
|  | atl2_validate_option(&val, &opt); | 
|  | adapter->hw.MediaType = (u16) val; | 
|  | #ifdef module_param_array | 
|  | } else | 
|  | adapter->hw.MediaType = (u16)(opt.def); | 
|  | #endif | 
|  | } |