176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * gPXE driver for Marvell Yukon chipset and SysKonnect Gigabit 376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Ethernet adapters. Derived from Linux skge driver (v1.13), which was 476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * based on earlier sk98lin, e100 and FreeBSD if_sk drivers. 576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This driver intentionally does not support all the features of the 776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * original driver such as link fail-over and link management because 876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * those should be done at higher levels. 976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Copyright (C) 2004, 2005 Stephen Hemminger <shemminger@osdl.org> 1176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Modified for gPXE, July 2008 by Michael Decker <mrd999@gmail.com> 1376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Tested and Modified in December 2009 by 1476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Thomas Miletich <thomas.miletich@gmail.com> 1576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This program is free software; you can redistribute it and/or modify 1776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * it under the terms of the GNU General Public License as published by 1876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the Free Software Foundation; either version 2 of the License. 1976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 2076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This program is distributed in the hope that it will be useful, 2176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * but WITHOUT ANY WARRANTY; without even the implied warranty of 2276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 2376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * GNU General Public License for more details. 2476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 2576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * You should have received a copy of the GNU General Public License 2676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * along with this program; if not, write to the Free Software 2776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 2876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 2976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3076d05dc695b06c4e987bb8078f78032441e1430cGreg HartmanFILE_LICENCE ( GPL2_ONLY ); 3176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 3276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdint.h> 3376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <errno.h> 3476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <stdio.h> 3576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <unistd.h> 3676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/netdevice.h> 3776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/ethernet.h> 3876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/if_ether.h> 3976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/iobuf.h> 4076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/malloc.h> 4176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include <gpxe/pci.h> 4276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman#include "skge.h" 4476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 4576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct pci_device_id skge_id_table[] = { 4676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PCI_ROM(0x10b7, 0x1700, "3C940", "3COM 3C940", 0), 4776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PCI_ROM(0x10b7, 0x80eb, "3C940B", "3COM 3C940", 0), 4876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PCI_ROM(0x1148, 0x4300, "GE", "Syskonnect GE", 0), 4976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PCI_ROM(0x1148, 0x4320, "YU", "Syskonnect YU", 0), 5076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PCI_ROM(0x1186, 0x4C00, "DGE510T", "DLink DGE-510T", 0), 5176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PCI_ROM(0x1186, 0x4b01, "DGE530T", "DLink DGE-530T", 0), 5276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PCI_ROM(0x11ab, 0x4320, "id4320", "Marvell id4320", 0), 5376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PCI_ROM(0x11ab, 0x5005, "id5005", "Marvell id5005", 0), /* Belkin */ 5476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PCI_ROM(0x1371, 0x434e, "Gigacard", "CNET Gigacard", 0), 5576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PCI_ROM(0x1737, 0x1064, "EG1064", "Linksys EG1064", 0), 5676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PCI_ROM(0x1737, 0xffff, "id_any", "Linksys [any]", 0) 5776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 5876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 5976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int skge_up(struct net_device *dev); 6076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_down(struct net_device *dev); 6176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_tx_clean(struct net_device *dev); 6276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val); 6376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val); 6476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void yukon_init(struct skge_hw *hw, int port); 6576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void genesis_mac_init(struct skge_hw *hw, int port); 6676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void genesis_link_up(struct skge_port *skge); 6776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 6876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_phyirq(struct skge_hw *hw); 6976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_poll(struct net_device *dev); 7076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int skge_xmit_frame(struct net_device *dev, struct io_buffer *iob); 7176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_net_irq ( struct net_device *dev, int enable ); 7276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_rx_refill(struct net_device *dev); 7476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 7576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct net_device_operations skge_operations = { 7676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .open = skge_up, 7776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .close = skge_down, 7876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .transmit = skge_xmit_frame, 7976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .poll = skge_poll, 8076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .irq = skge_net_irq 8176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 8276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 8376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Avoid conditionals by using array */ 8476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const int txqaddr[] = { Q_XA1, Q_XA2 }; 8576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const int rxqaddr[] = { Q_R1, Q_R2 }; 8676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const u32 rxirqmask[] = { IS_R1_F, IS_R2_F }; 8776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const u32 txirqmask[] = { IS_XA1_F, IS_XA2_F }; 8876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const u32 napimask[] = { IS_R1_F|IS_XA1_F, IS_R2_F|IS_XA2_F }; 8976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const u32 portmask[] = { IS_PORT_1, IS_PORT_2 }; 9076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Determine supported/advertised modes based on hardware. 9276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Note: ethtool ADVERTISED_xxx == SUPPORTED_xxx 9376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 9476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic u32 skge_supported_modes(const struct skge_hw *hw) 9576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 9676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 supported; 9776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 9876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->copper) { 9976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman supported = SUPPORTED_10baseT_Half 10076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman | SUPPORTED_10baseT_Full 10176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman | SUPPORTED_100baseT_Half 10276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman | SUPPORTED_100baseT_Full 10376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman | SUPPORTED_1000baseT_Half 10476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman | SUPPORTED_1000baseT_Full 10576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman | SUPPORTED_Autoneg| SUPPORTED_TP; 10676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 10776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->chip_id == CHIP_ID_GENESIS) 10876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman supported &= ~(SUPPORTED_10baseT_Half 10976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman | SUPPORTED_10baseT_Full 11076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman | SUPPORTED_100baseT_Half 11176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman | SUPPORTED_100baseT_Full); 11276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else if (hw->chip_id == CHIP_ID_YUKON) 11476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman supported &= ~SUPPORTED_1000baseT_Half; 11576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else 11676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman supported = SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half 11776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman | SUPPORTED_FIBRE | SUPPORTED_Autoneg; 11876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 11976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return supported; 12076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 12176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Chip internal frequency for clock calculations */ 12376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline u32 hwkhz(const struct skge_hw *hw) 12476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 12576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return (hw->chip_id == CHIP_ID_GENESIS) ? 53125 : 78125; 12676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 12776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 12876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Microseconds to chip HZ */ 12976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline u32 skge_usecs2clk(const struct skge_hw *hw, u32 usec) 13076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 13176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return hwkhz(hw) * usec / 1000; 13276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 13376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 13476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanenum led_mode { LED_MODE_OFF, LED_MODE_ON, LED_MODE_TST }; 13576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_led(struct skge_port *skge, enum led_mode mode) 13676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 13776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_hw *hw = skge->hw; 13876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int port = skge->port; 13976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 14076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->chip_id == CHIP_ID_GENESIS) { 14176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (mode) { 14276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case LED_MODE_OFF: 14376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->phy_type == SK_PHY_BCOM) 14476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF); 14576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else { 14676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, SK_REG(port, TX_LED_VAL), 0); 14776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_T_OFF); 14876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 14976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF); 15076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, SK_REG(port, RX_LED_VAL), 0); 15176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_T_OFF); 15276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 15376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case LED_MODE_ON: 15576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON); 15676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_LINKSYNC_ON); 15776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 15876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START); 15976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START); 16076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 16276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case LED_MODE_TST: 16476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, RX_LED_TST), LED_T_ON); 16576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, SK_REG(port, RX_LED_VAL), 100); 16676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START); 16776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 16876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->phy_type == SK_PHY_BCOM) 16976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON); 17076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else { 17176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, TX_LED_TST), LED_T_ON); 17276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, SK_REG(port, TX_LED_VAL), 100); 17376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START); 17476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 17576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 17676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 17776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 17876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (mode) { 17976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case LED_MODE_OFF: 18076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0); 18176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gm_phy_write(hw, port, PHY_MARV_LED_OVER, 18276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PHY_M_LED_MO_DUP(MO_LED_OFF) | 18376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PHY_M_LED_MO_10(MO_LED_OFF) | 18476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PHY_M_LED_MO_100(MO_LED_OFF) | 18576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PHY_M_LED_MO_1000(MO_LED_OFF) | 18676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PHY_M_LED_MO_RX(MO_LED_OFF)); 18776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 18876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case LED_MODE_ON: 18976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 19076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PHY_M_LED_PULS_DUR(PULS_170MS) | 19176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PHY_M_LED_BLINK_RT(BLINK_84MS) | 19276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PHY_M_LEDC_TX_CTRL | 19376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PHY_M_LEDC_DP_CTRL); 19476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 19576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gm_phy_write(hw, port, PHY_MARV_LED_OVER, 19676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PHY_M_LED_MO_RX(MO_LED_OFF) | 19776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (skge->speed == SPEED_100 ? 19876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PHY_M_LED_MO_100(MO_LED_ON) : 0)); 19976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 20076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case LED_MODE_TST: 20176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0); 20276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gm_phy_write(hw, port, PHY_MARV_LED_OVER, 20376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PHY_M_LED_MO_DUP(MO_LED_ON) | 20476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PHY_M_LED_MO_10(MO_LED_ON) | 20576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PHY_M_LED_MO_100(MO_LED_ON) | 20676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PHY_M_LED_MO_1000(MO_LED_ON) | 20776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PHY_M_LED_MO_RX(MO_LED_ON)); 20876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 20976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 21076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 21176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 21276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 21376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * I've left in these EEPROM and VPD functions, as someone may desire to 21476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * integrate them in the future. -mdeck 21576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 21676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * static int skge_get_eeprom_len(struct net_device *dev) 21776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * { 21876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * struct skge_port *skge = netdev_priv(dev); 21976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * u32 reg2; 22076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 22176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * pci_read_config_dword(skge->hw->pdev, PCI_DEV_REG2, ®2); 22276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * return 1 << ( ((reg2 & PCI_VPD_ROM_SZ) >> 14) + 8); 22376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * } 22476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 22576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * static u32 skge_vpd_read(struct pci_dev *pdev, int cap, u16 offset) 22676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * { 22776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * u32 val; 22876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 22976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * pci_write_config_word(pdev, cap + PCI_VPD_ADDR, offset); 23076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 23176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * do { 23276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset); 23376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * } while (!(offset & PCI_VPD_ADDR_F)); 23476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 23576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * pci_read_config_dword(pdev, cap + PCI_VPD_DATA, &val); 23676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * return val; 23776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * } 23876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 23976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * static void skge_vpd_write(struct pci_dev *pdev, int cap, u16 offset, u32 val) 24076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * { 24176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * pci_write_config_dword(pdev, cap + PCI_VPD_DATA, val); 24276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * pci_write_config_word(pdev, cap + PCI_VPD_ADDR, 24376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * offset | PCI_VPD_ADDR_F); 24476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 24576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * do { 24676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * pci_read_config_word(pdev, cap + PCI_VPD_ADDR, &offset); 24776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * } while (offset & PCI_VPD_ADDR_F); 24876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * } 24976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 25076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * static int skge_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, 25176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * u8 *data) 25276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * { 25376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * struct skge_port *skge = netdev_priv(dev); 25476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * struct pci_dev *pdev = skge->hw->pdev; 25576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * int cap = pci_find_capability(pdev, PCI_CAP_ID_VPD); 25676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * int length = eeprom->len; 25776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * u16 offset = eeprom->offset; 25876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 25976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * if (!cap) 26076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * return -EINVAL; 26176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 26276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * eeprom->magic = SKGE_EEPROM_MAGIC; 26376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 26476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * while (length > 0) { 26576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * u32 val = skge_vpd_read(pdev, cap, offset); 26676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * int n = min_t(int, length, sizeof(val)); 26776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 26876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * memcpy(data, &val, n); 26976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * length -= n; 27076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * data += n; 27176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * offset += n; 27276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * } 27376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * return 0; 27476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * } 27576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 27676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * static int skge_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, 27776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * u8 *data) 27876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * { 27976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * struct skge_port *skge = netdev_priv(dev); 28076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * struct pci_dev *pdev = skge->hw->pdev; 28176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * int cap = pci_find_capability(pdev, PCI_CAP_ID_VPD); 28276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * int length = eeprom->len; 28376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * u16 offset = eeprom->offset; 28476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 28576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * if (!cap) 28676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * return -EINVAL; 28776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 28876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * if (eeprom->magic != SKGE_EEPROM_MAGIC) 28976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * return -EINVAL; 29076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 29176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * while (length > 0) { 29276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * u32 val; 29376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * int n = min_t(int, length, sizeof(val)); 29476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 29576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * if (n < sizeof(val)) 29676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * val = skge_vpd_read(pdev, cap, offset); 29776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * memcpy(&val, data, n); 29876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 29976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * skge_vpd_write(pdev, cap, offset, val); 30076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 30176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * length -= n; 30276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * data += n; 30376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * offset += n; 30476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * } 30576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * return 0; 30676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * } 30776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 30876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 30976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 31076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Allocate ring elements and chain them together 31176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * One-to-one association of board descriptors with ring elements 31276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 31376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u32 base, 31476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman size_t num) 31576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 31676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_tx_desc *d; 31776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_element *e; 31876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int i; 31976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 32076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ring->start = zalloc(num*sizeof(*e)); 32176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!ring->start) 32276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -ENOMEM; 32376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 32476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0, e = ring->start, d = vaddr; i < num; i++, e++, d++) { 32576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman e->desc = d; 32676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (i == num - 1) { 32776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman e->next = ring->start; 32876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman d->next_offset = base; 32976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 33076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman e->next = e + 1; 33176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman d->next_offset = base + (i+1) * sizeof(*d); 33276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 33376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 33476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ring->to_use = ring->to_clean = ring->start; 33576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 33676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 33776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 33876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 33976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Allocate and setup a new buffer for receiving */ 34076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_rx_setup(struct skge_port *skge __unused, 34176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_element *e, 34276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct io_buffer *iob, unsigned int bufsize) 34376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 34476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_rx_desc *rd = e->desc; 34576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u64 map; 34676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman map = ( iob != NULL ) ? virt_to_bus(iob->data) : 0; 34876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 34976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rd->dma_lo = map; 35076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rd->dma_hi = map >> 32; 35176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman e->iob = iob; 35276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rd->csum1_start = ETH_HLEN; 35376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rd->csum2_start = ETH_HLEN; 35476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rd->csum1 = 0; 35576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rd->csum2 = 0; 35676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 35776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman wmb(); 35876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 35976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | bufsize; 36076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 36176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 36276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Resume receiving using existing skb, 36376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Note: DMA address is not changed by chip. 36476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * MTU not changed while receiver active. 36576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 36676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void skge_rx_reuse(struct skge_element *e, unsigned int size) 36776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 36876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_rx_desc *rd = e->desc; 36976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rd->csum2 = 0; 37176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rd->csum2_start = ETH_HLEN; 37276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman wmb(); 37476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | size; 37676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 37776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 37976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Free all buffers in receive ring, assumes receiver stopped */ 38076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_rx_clean(struct skge_port *skge) 38176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 38276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_ring *ring = &skge->rx_ring; 38376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_element *e; 38476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 38576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman e = ring->start; 38676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman do { 38776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_rx_desc *rd = e->desc; 38876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rd->control = 0; 38976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (e->iob) { 39076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free_iob(e->iob); 39176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman e->iob = NULL; 39276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 39376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } while ((e = e->next) != ring->start); 39476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 39576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 39676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_link_up(struct skge_port *skge) 39776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 39876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), 39976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman LED_BLK_OFF|LED_SYNC_OFF|LED_ON); 40076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_link_up(skge->netdev); 40276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2(PFX "%s: Link is up at %d Mbps, %s duplex\n", 40476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->netdev->name, skge->speed, 40576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->duplex == DUPLEX_FULL ? "full" : "half"); 40676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 40776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 40876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_link_down(struct skge_port *skge) 40976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 41076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF); 41176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_link_down(skge->netdev); 41276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 41376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2(PFX "%s: Link is down.\n", skge->netdev->name); 41476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 41576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 41676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 41776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void xm_link_down(struct skge_hw *hw, int port) 41876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 41976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_device *dev = hw->dev[port]; 42076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_port *skge = netdev_priv(dev); 42176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 42276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_IMSK, XM_IMSK_DISABLE); 42376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 42476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (netdev_link_ok(dev)) 42576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_link_down(skge); 42676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 42776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 42876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int __xm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val) 42976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 43076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 43176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 43276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr); 43376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *val = xm_read16(hw, port, XM_PHY_DATA); 43476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 43576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->phy_type == SK_PHY_XMAC) 43676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto ready; 43776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 43876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < PHY_RETRIES; i++) { 43976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_RDY) 44076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto ready; 44176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman udelay(1); 44276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 44376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 44476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -ETIMEDOUT; 44576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ready: 44676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *val = xm_read16(hw, port, XM_PHY_DATA); 44776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 44876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 44976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 45076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 45176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic u16 xm_phy_read(struct skge_hw *hw, int port, u16 reg) 45276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 45376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 v = 0; 45476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (__xm_phy_read(hw, port, reg, &v)) 45576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG(PFX "%s: phy read timed out\n", 45676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->dev[port]->name); 45776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return v; 45876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 45976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 46076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val) 46176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 46276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 46376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 46476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr); 46576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < PHY_RETRIES; i++) { 46676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY)) 46776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto ready; 46876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman udelay(1); 46976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 47076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EIO; 47176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 47276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ready: 47376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_PHY_DATA, val); 47476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < PHY_RETRIES; i++) { 47576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY)) 47676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 47776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman udelay(1); 47876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 47976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -ETIMEDOUT; 48076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 48176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 48276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void genesis_init(struct skge_hw *hw) 48376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 48476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* set blink source counter */ 48576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, B2_BSC_INI, (SK_BLK_DUR * SK_FACT_53) / 100); 48676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B2_BSC_CTRL, BSC_START); 48776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 48876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* configure mac arbiter */ 48976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, B3_MA_TO_CTRL, MA_RST_CLR); 49076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 49176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* configure mac arbiter timeout values */ 49276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_MA_TOINI_RX1, SK_MAC_TO_53); 49376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_MA_TOINI_RX2, SK_MAC_TO_53); 49476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_MA_TOINI_TX1, SK_MAC_TO_53); 49576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_MA_TOINI_TX2, SK_MAC_TO_53); 49676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 49776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_MA_RCINI_RX1, 0); 49876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_MA_RCINI_RX2, 0); 49976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_MA_RCINI_TX1, 0); 50076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_MA_RCINI_TX2, 0); 50176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 50276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* configure packet arbiter timeout */ 50376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, B3_PA_CTRL, PA_RST_CLR); 50476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, B3_PA_TOINI_RX1, SK_PKT_TO_MAX); 50576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, B3_PA_TOINI_TX1, SK_PKT_TO_MAX); 50676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, B3_PA_TOINI_RX2, SK_PKT_TO_MAX); 50776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, B3_PA_TOINI_TX2, SK_PKT_TO_MAX); 50876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 50976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 51076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void genesis_reset(struct skge_hw *hw, int port) 51176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 51276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const u8 zero[8] = { 0 }; 51376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 reg; 51476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 51576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, GMAC_IRQ_MSK), 0); 51676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 51776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* reset the statistics module */ 51876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT); 51976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_IMSK, XM_IMSK_DISABLE); 52076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write32(hw, port, XM_MODE, 0); /* clear Mode Reg */ 52176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_TX_CMD, 0); /* reset TX CMD Reg */ 52276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */ 52376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 52476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* disable Broadcom PHY IRQ */ 52576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->phy_type == SK_PHY_BCOM) 52676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff); 52776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 52876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_outhash(hw, port, XM_HSM, zero); 52976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 53076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Flush TX and RX fifo */ 53176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg = xm_read32(hw, port, XM_MODE); 53276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write32(hw, port, XM_MODE, reg | XM_MD_FTF); 53376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write32(hw, port, XM_MODE, reg | XM_MD_FRF); 53476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 53576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 53676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 53776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Convert mode to MII values */ 53876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const u16 phy_pause_map[] = { 53976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman [FLOW_MODE_NONE] = 0, 54076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman [FLOW_MODE_LOC_SEND] = PHY_AN_PAUSE_ASYM, 54176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman [FLOW_MODE_SYMMETRIC] = PHY_AN_PAUSE_CAP, 54276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman [FLOW_MODE_SYM_OR_REM] = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM, 54376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 54476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 54576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* special defines for FIBER (88E1011S only) */ 54676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const u16 fiber_pause_map[] = { 54776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman [FLOW_MODE_NONE] = PHY_X_P_NO_PAUSE, 54876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman [FLOW_MODE_LOC_SEND] = PHY_X_P_ASYM_MD, 54976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman [FLOW_MODE_SYMMETRIC] = PHY_X_P_SYM_MD, 55076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman [FLOW_MODE_SYM_OR_REM] = PHY_X_P_BOTH_MD, 55176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 55276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 55376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 55476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Check status of Broadcom phy link */ 55576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void bcom_check_link(struct skge_hw *hw, int port) 55676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 55776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_device *dev = hw->dev[port]; 55876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_port *skge = netdev_priv(dev); 55976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 status; 56076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 56176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* read twice because of latch */ 56276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_phy_read(hw, port, PHY_BCOM_STAT); 56376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = xm_phy_read(hw, port, PHY_BCOM_STAT); 56476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 56576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((status & PHY_ST_LSYNC) == 0) { 56676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_link_down(hw, port); 56776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 56876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 56976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 57076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->autoneg == AUTONEG_ENABLE) { 57176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 lpa, aux; 57276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 57376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!(status & PHY_ST_AN_OVER)) 57476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 57576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 57676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP); 57776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (lpa & PHY_B_AN_RF) { 57876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG(PFX "%s: remote fault\n", 57976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dev->name); 58076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 58176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 58276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 58376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT); 58476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 58576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Check Duplex mismatch */ 58676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (aux & PHY_B_AS_AN_RES_MSK) { 58776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case PHY_B_RES_1000FD: 58876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->duplex = DUPLEX_FULL; 58976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 59076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case PHY_B_RES_1000HD: 59176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->duplex = DUPLEX_HALF; 59276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 59376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 59476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG(PFX "%s: duplex mismatch\n", 59576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dev->name); 59676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 59776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 59876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 59976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* We are using IEEE 802.3z/D5.0 Table 37-4 */ 60076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (aux & PHY_B_AS_PAUSE_MSK) { 60176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case PHY_B_AS_PAUSE_MSK: 60276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->flow_status = FLOW_STAT_SYMMETRIC; 60376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 60476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case PHY_B_AS_PRR: 60576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->flow_status = FLOW_STAT_REM_SEND; 60676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 60776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case PHY_B_AS_PRT: 60876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->flow_status = FLOW_STAT_LOC_SEND; 60976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 61076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 61176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->flow_status = FLOW_STAT_NONE; 61276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 61376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->speed = SPEED_1000; 61476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 61576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 61676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!netdev_link_ok(dev)) 61776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman genesis_link_up(skge); 61876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 61976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 62076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Broadcom 5400 only supports giagabit! SysKonnect did not put an additional 62176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Phy on for 100 or 10Mbit operation 62276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 62376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void bcom_phy_init(struct skge_port *skge) 62476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 62576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_hw *hw = skge->hw; 62676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int port = skge->port; 62776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int i; 62876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 id1, r, ext, ctl; 62976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 63076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* magic workaround patterns for Broadcom */ 63176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman static const struct { 63276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 reg; 63376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 val; 63476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } A1hack[] = { 63576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1104 }, 63676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman { 0x17, 0x0013 }, { 0x15, 0x0404 }, { 0x17, 0x8006 }, 63776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman { 0x15, 0x0132 }, { 0x17, 0x8006 }, { 0x15, 0x0232 }, 63876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman { 0x17, 0x800D }, { 0x15, 0x000F }, { 0x18, 0x0420 }, 63976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman }, C0hack[] = { 64076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1204 }, 64176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman { 0x17, 0x0013 }, { 0x15, 0x0A04 }, { 0x18, 0x0420 }, 64276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman }; 64376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 64476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* read Id from external PHY (all have the same address) */ 64576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman id1 = xm_phy_read(hw, port, PHY_XMAC_ID1); 64676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 64776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Optimize MDIO transfer by suppressing preamble. */ 64876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman r = xm_read16(hw, port, XM_MMU_CMD); 64976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman r |= XM_MMU_NO_PRE; 65076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_MMU_CMD,r); 65176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 65276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (id1) { 65376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case PHY_BCOM_ID1_C0: 65476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 65576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Workaround BCOM Errata for the C0 type. 65676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Write magic patterns to reserved registers. 65776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 65876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < ARRAY_SIZE(C0hack); i++) 65976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_phy_write(hw, port, 66076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman C0hack[i].reg, C0hack[i].val); 66176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 66276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 66376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case PHY_BCOM_ID1_A1: 66476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 66576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Workaround BCOM Errata for the A1 type. 66676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Write magic patterns to reserved registers. 66776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 66876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < ARRAY_SIZE(A1hack); i++) 66976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_phy_write(hw, port, 67076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman A1hack[i].reg, A1hack[i].val); 67176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 67276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 67376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 67476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 67576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Workaround BCOM Errata (#10523) for all BCom PHYs. 67676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Disable Power Management after reset. 67776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 67876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman r = xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL); 67976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman r |= PHY_B_AC_DIS_PM; 68076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, r); 68176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 68276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Dummy read */ 68376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_read16(hw, port, XM_ISRC); 68476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 68576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ext = PHY_B_PEC_EN_LTR; /* enable tx led */ 68676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctl = PHY_CT_SP1000; /* always 1000mbit */ 68776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 68876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->autoneg == AUTONEG_ENABLE) { 68976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 69076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Workaround BCOM Errata #1 for the C5 type. 69176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 1000Base-T Link Acquisition Failure in Slave Mode 69276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Set Repeater/DTE bit 10 of the 1000Base-T Control Register 69376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 69476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 adv = PHY_B_1000C_RD; 69576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->advertising & ADVERTISED_1000baseT_Half) 69676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman adv |= PHY_B_1000C_AHD; 69776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->advertising & ADVERTISED_1000baseT_Full) 69876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman adv |= PHY_B_1000C_AFD; 69976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, adv); 70076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 70176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctl |= PHY_CT_ANE | PHY_CT_RE_CFG; 70276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 70376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->duplex == DUPLEX_FULL) 70476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctl |= PHY_CT_DUP_MD; 70576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Force to slave */ 70676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, PHY_B_1000C_MSE); 70776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 70876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 70976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set autonegotiation pause parameters */ 71076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_phy_write(hw, port, PHY_BCOM_AUNE_ADV, 71176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman phy_pause_map[skge->flow_control] | PHY_AN_CSMA); 71276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 71376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, ext); 71476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_phy_write(hw, port, PHY_BCOM_CTRL, ctl); 71576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 71676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Use link status change interrupt */ 71776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK); 71876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 71976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 72076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void xm_phy_init(struct skge_port *skge) 72176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 72276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_hw *hw = skge->hw; 72376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int port = skge->port; 72476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 ctrl = 0; 72576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 72676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->autoneg == AUTONEG_ENABLE) { 72776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->advertising & ADVERTISED_1000baseT_Half) 72876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl |= PHY_X_AN_HD; 72976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->advertising & ADVERTISED_1000baseT_Full) 73076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl |= PHY_X_AN_FD; 73176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 73276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl |= fiber_pause_map[skge->flow_control]; 73376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 73476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_phy_write(hw, port, PHY_XMAC_AUNE_ADV, ctrl); 73576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 73676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Restart Auto-negotiation */ 73776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl = PHY_CT_ANE | PHY_CT_RE_CFG; 73876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 73976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set DuplexMode in Config register */ 74076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->duplex == DUPLEX_FULL) 74176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl |= PHY_CT_DUP_MD; 74276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 74376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Do NOT enable Auto-negotiation here. This would hold 74476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the link down because no IDLEs are transmitted 74576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 74676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 74776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 74876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_phy_write(hw, port, PHY_XMAC_CTRL, ctrl); 74976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 75076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Poll PHY for status changes */ 75176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->use_xm_link_timer = 1; 75276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 75376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 75476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int xm_check_link(struct net_device *dev) 75576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 75676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_port *skge = netdev_priv(dev); 75776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_hw *hw = skge->hw; 75876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int port = skge->port; 75976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 status; 76076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 76176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* read twice because of latch */ 76276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_phy_read(hw, port, PHY_XMAC_STAT); 76376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = xm_phy_read(hw, port, PHY_XMAC_STAT); 76476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 76576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((status & PHY_ST_LSYNC) == 0) { 76676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_link_down(hw, port); 76776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 76876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 76976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 77076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->autoneg == AUTONEG_ENABLE) { 77176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 lpa, res; 77276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 77376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!(status & PHY_ST_AN_OVER)) 77476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 77576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 77676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP); 77776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (lpa & PHY_B_AN_RF) { 77876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG(PFX "%s: remote fault\n", 77976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dev->name); 78076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 78176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 78276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 78376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman res = xm_phy_read(hw, port, PHY_XMAC_RES_ABI); 78476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 78576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Check Duplex mismatch */ 78676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (res & (PHY_X_RS_HD | PHY_X_RS_FD)) { 78776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case PHY_X_RS_FD: 78876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->duplex = DUPLEX_FULL; 78976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 79076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case PHY_X_RS_HD: 79176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->duplex = DUPLEX_HALF; 79276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 79376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 79476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG(PFX "%s: duplex mismatch\n", 79576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dev->name); 79676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 79776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 79876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 79976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* We are using IEEE 802.3z/D5.0 Table 37-4 */ 80076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((skge->flow_control == FLOW_MODE_SYMMETRIC || 80176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->flow_control == FLOW_MODE_SYM_OR_REM) && 80276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (lpa & PHY_X_P_SYM_MD)) 80376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->flow_status = FLOW_STAT_SYMMETRIC; 80476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else if (skge->flow_control == FLOW_MODE_SYM_OR_REM && 80576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (lpa & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) 80676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Enable PAUSE receive, disable PAUSE transmit */ 80776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->flow_status = FLOW_STAT_REM_SEND; 80876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else if (skge->flow_control == FLOW_MODE_LOC_SEND && 80976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (lpa & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) 81076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Disable PAUSE receive, enable PAUSE transmit */ 81176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->flow_status = FLOW_STAT_LOC_SEND; 81276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 81376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->flow_status = FLOW_STAT_NONE; 81476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 81576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->speed = SPEED_1000; 81676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 81776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 81876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!netdev_link_ok(dev)) 81976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman genesis_link_up(skge); 82076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 1; 82176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 82276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 82376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Poll to check for link coming up. 82476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 82576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Since internal PHY is wired to a level triggered pin, can't 82676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * get an interrupt when carrier is detected, need to poll for 82776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * link coming up. 82876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 82976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void xm_link_timer(struct skge_port *skge) 83076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 83176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_device *dev = skge->netdev; 83276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_hw *hw = skge->hw; 83376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int port = skge->port; 83476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 83576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 83676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 83776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Verify that the link by checking GPIO register three times. 83876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This pin has the signal from the link_sync pin connected to it. 83976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 84076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < 3; i++) { 84176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (xm_read16(hw, port, XM_GP_PORT) & XM_GP_INP_ASS) 84276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 84376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 84476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 84576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Re-enable interrupt to detect link down */ 84676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (xm_check_link(dev)) { 84776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 msk = xm_read16(hw, port, XM_IMSK); 84876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman msk &= ~XM_IS_INP_ASS; 84976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_IMSK, msk); 85076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_read16(hw, port, XM_ISRC); 85176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 85276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 85376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 85476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void genesis_mac_init(struct skge_hw *hw, int port) 85576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 85676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_device *dev = hw->dev[port]; 85776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_port *skge = netdev_priv(dev); 85876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 85976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 r; 86076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const u8 zero[6] = { 0 }; 86176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 86276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < 10; i++) { 86376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), 86476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman MFF_SET_MAC_RST); 86576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge_read16(hw, SK_REG(port, TX_MFF_CTRL1)) & MFF_SET_MAC_RST) 86676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto reset_ok; 86776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman udelay(1); 86876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 86976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 87076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG(PFX "%s: genesis reset failed\n", dev->name); 87176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 87276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reset_ok: 87376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Unreset the XMAC. */ 87476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_CLR_MAC_RST); 87576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 87676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 87776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Perform additional initialization for external PHYs, 87876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * namely for the 1000baseTX cards that use the XMAC's 87976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * GMII mode. 88076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 88176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->phy_type != SK_PHY_XMAC) { 88276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Take external Phy out of reset */ 88376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman r = skge_read32(hw, B2_GP_IO); 88476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (port == 0) 88576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman r |= GP_DIR_0|GP_IO_0; 88676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 88776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman r |= GP_DIR_2|GP_IO_2; 88876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 88976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, B2_GP_IO, r); 89076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 89176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Enable GMII interface */ 89276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD); 89376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 89476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 89576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 89676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch(hw->phy_type) { 89776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case SK_PHY_XMAC: 89876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_phy_init(skge); 89976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 90076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case SK_PHY_BCOM: 90176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bcom_phy_init(skge); 90276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bcom_check_link(hw, port); 90376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 90476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 90576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set Station Address */ 90676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_outaddr(hw, port, XM_SA, dev->ll_addr); 90776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 90876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* We don't use match addresses so clear */ 90976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 1; i < 16; i++) 91076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_outaddr(hw, port, XM_EXM(i), zero); 91176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 91276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Clear MIB counters */ 91376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_STAT_CMD, 91476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman XM_SC_CLR_RXC | XM_SC_CLR_TXC); 91576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Clear two times according to Errata #3 */ 91676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_STAT_CMD, 91776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman XM_SC_CLR_RXC | XM_SC_CLR_TXC); 91876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 91976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* configure Rx High Water Mark (XM_RX_HI_WM) */ 92076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_RX_HI_WM, 1450); 92176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 92276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* We don't need the FCS appended to the packet. */ 92376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman r = XM_RX_LENERR_OK | XM_RX_STRIP_FCS; 92476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 92576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->duplex == DUPLEX_HALF) { 92676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 92776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * If in manual half duplex mode the other side might be in 92876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * full duplex mode, so ignore if a carrier extension is not seen 92976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * on frames received 93076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 93176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman r |= XM_RX_DIS_CEXT; 93276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 93376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_RX_CMD, r); 93476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 93576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* We want short frames padded to 60 bytes. */ 93676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_TX_CMD, XM_TX_AUTO_PAD); 93776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 93876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_TX_THR, 512); 93976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 94076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 94176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Enable the reception of all error frames. This is is 94276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * a necessary evil due to the design of the XMAC. The 94376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * XMAC's receive FIFO is only 8K in size, however jumbo 94476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * frames can be up to 9000 bytes in length. When bad 94576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * frame filtering is enabled, the XMAC's RX FIFO operates 94676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * in 'store and forward' mode. For this to work, the 94776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * entire frame has to fit into the FIFO, but that means 94876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * that jumbo frames larger than 8192 bytes will be 94976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * truncated. Disabling all bad frame filtering causes 95076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the RX FIFO to operate in streaming mode, in which 95176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * case the XMAC will start transferring frames out of the 95276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * RX FIFO as soon as the FIFO threshold is reached. 95376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 95476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write32(hw, port, XM_MODE, XM_DEF_MODE); 95576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 95676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 95776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 95876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Initialize the Receive Counter Event Mask (XM_RX_EV_MSK) 95976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * - Enable all bits excepting 'Octets Rx OK Low CntOv' 96076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * and 'Octets Rx OK Hi Cnt Ov'. 96176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 96276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write32(hw, port, XM_RX_EV_MSK, XMR_DEF_MSK); 96376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 96476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 96576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Initialize the Transmit Counter Event Mask (XM_TX_EV_MSK) 96676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * - Enable all bits excepting 'Octets Tx OK Low CntOv' 96776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * and 'Octets Tx OK Hi Cnt Ov'. 96876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 96976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write32(hw, port, XM_TX_EV_MSK, XMT_DEF_MSK); 97076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 97176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Configure MAC arbiter */ 97276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, B3_MA_TO_CTRL, MA_RST_CLR); 97376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 97476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* configure timeout values */ 97576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_MA_TOINI_RX1, 72); 97676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_MA_TOINI_RX2, 72); 97776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_MA_TOINI_TX1, 72); 97876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_MA_TOINI_TX2, 72); 97976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 98076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_MA_RCINI_RX1, 0); 98176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_MA_RCINI_RX2, 0); 98276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_MA_RCINI_TX1, 0); 98376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_MA_RCINI_TX2, 0); 98476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 98576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Configure Rx MAC FIFO */ 98676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, RX_MFF_CTRL2), MFF_RST_CLR); 98776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_ENA_TIM_PAT); 98876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, RX_MFF_CTRL2), MFF_ENA_OP_MD); 98976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 99076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Configure Tx MAC FIFO */ 99176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_RST_CLR); 99276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF); 99376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_ENA_OP_MD); 99476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 99576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* enable timeout timers */ 99676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, B3_PA_CTRL, 99776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (port == 0) ? PA_ENA_TO_TX1 : PA_ENA_TO_TX2); 99876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 99976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 100076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void genesis_stop(struct skge_port *skge) 100176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 100276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_hw *hw = skge->hw; 100376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int port = skge->port; 100476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned retries = 1000; 100576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 cmd; 100676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 100776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Disable Tx and Rx */ 100876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cmd = xm_read16(hw, port, XM_MMU_CMD); 100976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); 101076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_MMU_CMD, cmd); 101176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 101276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman genesis_reset(hw, port); 101376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 101476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Clear Tx packet arbiter timeout IRQ */ 101576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, B3_PA_CTRL, 101676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman port == 0 ? PA_CLR_TO_TX1 : PA_CLR_TO_TX2); 101776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 101876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Reset the MAC */ 101976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_CLR_MAC_RST); 102076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman do { 102176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST); 102276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!(skge_read16(hw, SK_REG(port, TX_MFF_CTRL1)) & MFF_SET_MAC_RST)) 102376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 102476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } while (--retries > 0); 102576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 102676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* For external PHYs there must be special handling */ 102776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->phy_type != SK_PHY_XMAC) { 102876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 reg = skge_read32(hw, B2_GP_IO); 102976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (port == 0) { 103076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg |= GP_DIR_0; 103176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg &= ~GP_IO_0; 103276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 103376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg |= GP_DIR_2; 103476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg &= ~GP_IO_2; 103576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 103676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, B2_GP_IO, reg); 103776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_read32(hw, B2_GP_IO); 103876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 103976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 104076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_MMU_CMD, 104176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_read16(hw, port, XM_MMU_CMD) 104276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX)); 104376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 104476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_read16(hw, port, XM_MMU_CMD); 104576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 104676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 104776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void genesis_link_up(struct skge_port *skge) 104876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 104976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_hw *hw = skge->hw; 105076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int port = skge->port; 105176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 cmd, msk; 105276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 mode; 105376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 105476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cmd = xm_read16(hw, port, XM_MMU_CMD); 105576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 105676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 105776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * enabling pause frame reception is required for 1000BT 105876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * because the XMAC is not reset if the link is going down 105976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 106076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->flow_status == FLOW_STAT_NONE || 106176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->flow_status == FLOW_STAT_LOC_SEND) 106276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Disable Pause Frame Reception */ 106376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cmd |= XM_MMU_IGN_PF; 106476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 106576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Enable Pause Frame Reception */ 106676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cmd &= ~XM_MMU_IGN_PF; 106776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 106876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_MMU_CMD, cmd); 106976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 107076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mode = xm_read32(hw, port, XM_MODE); 107176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->flow_status== FLOW_STAT_SYMMETRIC || 107276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->flow_status == FLOW_STAT_LOC_SEND) { 107376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 107476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Configure Pause Frame Generation 107576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Use internal and external Pause Frame Generation. 107676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Sending pause frames is edge triggered. 107776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Send a Pause frame with the maximum pause time if 107876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * internal oder external FIFO full condition occurs. 107976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Send a zero pause time frame to re-start transmission. 108076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 108176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* XM_PAUSE_DA = '010000C28001' (default) */ 108276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* XM_MAC_PTIME = 0xffff (maximum) */ 108376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* remember this value is defined in big endian (!) */ 108476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_MAC_PTIME, 0xffff); 108576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 108676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mode |= XM_PAUSE_MODE; 108776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_ENA_PAUSE); 108876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 108976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 109076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * disable pause frame generation is required for 1000BT 109176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * because the XMAC is not reset if the link is going down 109276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 109376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Disable Pause Mode in Mode Register */ 109476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mode &= ~XM_PAUSE_MODE; 109576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 109676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_DIS_PAUSE); 109776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 109876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 109976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write32(hw, port, XM_MODE, mode); 110076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 110176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Turn on detection of Tx underrun */ 110276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman msk = xm_read16(hw, port, XM_IMSK); 110376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman msk &= ~XM_IS_TXF_UR; 110476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_IMSK, msk); 110576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 110676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_read16(hw, port, XM_ISRC); 110776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 110876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* get MMU Command Reg. */ 110976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cmd = xm_read16(hw, port, XM_MMU_CMD); 111076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->phy_type != SK_PHY_XMAC && skge->duplex == DUPLEX_FULL) 111176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cmd |= XM_MMU_GMII_FD; 111276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 111376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 111476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Workaround BCOM Errata (#10523) for all BCom Phys 111576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Enable Power Management after link up 111676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 111776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->phy_type == SK_PHY_BCOM) { 111876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, 111976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL) 112076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman & ~PHY_B_AC_DIS_PM); 112176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK); 112276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 112376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 112476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* enable Rx/Tx */ 112576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_write16(hw, port, XM_MMU_CMD, 112676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman cmd | XM_MMU_ENA_RX | XM_MMU_ENA_TX); 112776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_link_up(skge); 112876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 112976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 113076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 113176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline void bcom_phy_intr(struct skge_port *skge) 113276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 113376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_hw *hw = skge->hw; 113476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int port = skge->port; 113576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 isrc; 113676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 113776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman isrc = xm_phy_read(hw, port, PHY_BCOM_INT_STAT); 113876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGIO(PFX "%s: phy interrupt status 0x%x\n", 113976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->netdev->name, isrc); 114076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 114176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (isrc & PHY_B_IS_PSE) 114276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG(PFX "%s: uncorrectable pair swap error\n", 114376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->dev[port]->name); 114476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 114576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Workaround BCom Errata: 114676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * enable and disable loopback mode if "NO HCD" occurs. 114776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 114876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (isrc & PHY_B_IS_NO_HDCL) { 114976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 ctrl = xm_phy_read(hw, port, PHY_BCOM_CTRL); 115076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_phy_write(hw, port, PHY_BCOM_CTRL, 115176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl | PHY_CT_LOOP); 115276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_phy_write(hw, port, PHY_BCOM_CTRL, 115376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl & ~PHY_CT_LOOP); 115476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 115576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 115676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (isrc & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) 115776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bcom_check_link(hw, port); 115876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 115976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 116076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 116176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val) 116276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 116376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 116476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 116576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_SMI_DATA, val); 116676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_SMI_CTRL, 116776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman GM_SMI_CT_PHY_AD(hw->phy_addr) | GM_SMI_CT_REG_AD(reg)); 116876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < PHY_RETRIES; i++) { 116976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman udelay(1); 117076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 117176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!(gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY)) 117276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 117376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 117476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 117576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG(PFX "%s: phy write timeout port %x reg %x val %x\n", 117676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->dev[port]->name, 117776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman port, reg, val); 117876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EIO; 117976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 118076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 118176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int __gm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val) 118276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 118376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 118476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 118576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_SMI_CTRL, 118676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman GM_SMI_CT_PHY_AD(hw->phy_addr) 118776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman | GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD); 118876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 118976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < PHY_RETRIES; i++) { 119076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman udelay(1); 119176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL) 119276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto ready; 119376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 119476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 119576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -ETIMEDOUT; 119676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ready: 119776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman *val = gma_read16(hw, port, GM_SMI_DATA); 119876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 119976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 120076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 120176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic u16 gm_phy_read(struct skge_hw *hw, int port, u16 reg) 120276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 120376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 v = 0; 120476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (__gm_phy_read(hw, port, reg, &v)) 120576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG(PFX "%s: phy read timeout port %x reg %x val %x\n", 120676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->dev[port]->name, 120776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman port, reg, v); 120876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return v; 120976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 121076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 121176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Marvell Phy Initialization */ 121276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void yukon_init(struct skge_hw *hw, int port) 121376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 121476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_port *skge = netdev_priv(hw->dev[port]); 121576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 ctrl, ct1000, adv; 121676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 121776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->autoneg == AUTONEG_ENABLE) { 121876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL); 121976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 122076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK | 122176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PHY_M_EC_MAC_S_MSK); 122276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ectrl |= PHY_M_EC_MAC_S(MAC_TX_CLK_25_MHZ); 122376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 122476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ectrl |= PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1); 122576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 122676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gm_phy_write(hw, port, PHY_MARV_EXT_CTRL, ectrl); 122776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 122876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 122976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL); 123076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->autoneg == AUTONEG_DISABLE) 123176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl &= ~PHY_CT_ANE; 123276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 123376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl |= PHY_CT_RESET; 123476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl); 123576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 123676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl = 0; 123776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ct1000 = 0; 123876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman adv = PHY_AN_CSMA; 123976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 124076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->autoneg == AUTONEG_ENABLE) { 124176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->copper) { 124276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->advertising & ADVERTISED_1000baseT_Full) 124376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ct1000 |= PHY_M_1000C_AFD; 124476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->advertising & ADVERTISED_1000baseT_Half) 124576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ct1000 |= PHY_M_1000C_AHD; 124676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->advertising & ADVERTISED_100baseT_Full) 124776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman adv |= PHY_M_AN_100_FD; 124876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->advertising & ADVERTISED_100baseT_Half) 124976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman adv |= PHY_M_AN_100_HD; 125076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->advertising & ADVERTISED_10baseT_Full) 125176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman adv |= PHY_M_AN_10_FD; 125276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->advertising & ADVERTISED_10baseT_Half) 125376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman adv |= PHY_M_AN_10_HD; 125476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 125576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set Flow-control capabilities */ 125676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman adv |= phy_pause_map[skge->flow_control]; 125776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 125876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->advertising & ADVERTISED_1000baseT_Full) 125976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman adv |= PHY_M_AN_1000X_AFD; 126076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->advertising & ADVERTISED_1000baseT_Half) 126176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman adv |= PHY_M_AN_1000X_AHD; 126276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 126376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman adv |= fiber_pause_map[skge->flow_control]; 126476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 126576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 126676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Restart Auto-negotiation */ 126776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl |= PHY_CT_ANE | PHY_CT_RE_CFG; 126876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 126976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* forced speed/duplex settings */ 127076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ct1000 = PHY_M_1000C_MSE; 127176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 127276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->duplex == DUPLEX_FULL) 127376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl |= PHY_CT_DUP_MD; 127476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 127576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (skge->speed) { 127676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case SPEED_1000: 127776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl |= PHY_CT_SP1000; 127876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 127976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case SPEED_100: 128076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl |= PHY_CT_SP100; 128176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 128276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 128376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 128476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl |= PHY_CT_RESET; 128576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 128676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 128776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000); 128876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 128976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv); 129076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl); 129176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 129276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Enable phy interrupt on autonegotiation complete (or link up) */ 129376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->autoneg == AUTONEG_ENABLE) 129476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_MSK); 129576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 129676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_DEF_MSK); 129776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 129876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 129976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void yukon_reset(struct skge_hw *hw, int port) 130076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 130176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);/* disable PHY IRQs */ 130276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_MC_ADDR_H1, 0); /* clear MC hash */ 130376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_MC_ADDR_H2, 0); 130476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_MC_ADDR_H3, 0); 130576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_MC_ADDR_H4, 0); 130676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 130776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_RX_CTRL, 130876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_read16(hw, port, GM_RX_CTRL) 130976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman | GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); 131076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 131176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 131276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Apparently, early versions of Yukon-Lite had wrong chip_id? */ 131376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int is_yukon_lite_a0(struct skge_hw *hw) 131476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 131576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 reg; 131676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int ret; 131776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 131876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->chip_id != CHIP_ID_YUKON) 131976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 132076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 132176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg = skge_read32(hw, B2_FAR); 132276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B2_FAR + 3, 0xff); 132376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ret = (skge_read8(hw, B2_FAR + 3) != 0); 132476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, B2_FAR, reg); 132576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ret; 132676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 132776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 132876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void yukon_mac_init(struct skge_hw *hw, int port) 132976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 133076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_port *skge = netdev_priv(hw->dev[port]); 133176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 133276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 reg; 133376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const u8 *addr = hw->dev[port]->ll_addr; 133476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 133576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* WA code for COMA mode -- set PHY reset */ 133676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->chip_id == CHIP_ID_YUKON_LITE && 133776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->chip_rev >= CHIP_REV_YU_LITE_A3) { 133876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg = skge_read32(hw, B2_GP_IO); 133976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg |= GP_DIR_9 | GP_IO_9; 134076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, B2_GP_IO, reg); 134176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 134276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 134376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* hard reset */ 134476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET); 134576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_RST_SET); 134676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 134776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* WA code for COMA mode -- clear PHY reset */ 134876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->chip_id == CHIP_ID_YUKON_LITE && 134976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->chip_rev >= CHIP_REV_YU_LITE_A3) { 135076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg = skge_read32(hw, B2_GP_IO); 135176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg |= GP_DIR_9; 135276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg &= ~GP_IO_9; 135376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, B2_GP_IO, reg); 135476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 135576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 135676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set hardware config mode */ 135776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg = GPC_INT_POL_HI | GPC_DIS_FC | GPC_DIS_SLEEP | 135876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman GPC_ENA_XC | GPC_ANEG_ADV_ALL_M | GPC_ENA_PAUSE; 135976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg |= hw->copper ? GPC_HWCFG_GMII_COP : GPC_HWCFG_GMII_FIB; 136076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 136176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Clear GMC reset */ 136276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, SK_REG(port, GPHY_CTRL), reg | GPC_RST_SET); 136376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, SK_REG(port, GPHY_CTRL), reg | GPC_RST_CLR); 136476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR); 136576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 136676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->autoneg == AUTONEG_DISABLE) { 136776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg = GM_GPCR_AU_ALL_DIS; 136876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_GP_CTRL, 136976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_read16(hw, port, GM_GP_CTRL) | reg); 137076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 137176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (skge->speed) { 137276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case SPEED_1000: 137376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg &= ~GM_GPCR_SPEED_100; 137476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg |= GM_GPCR_SPEED_1000; 137576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 137676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case SPEED_100: 137776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg &= ~GM_GPCR_SPEED_1000; 137876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg |= GM_GPCR_SPEED_100; 137976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 138076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case SPEED_10: 138176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg &= ~(GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100); 138276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 138376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 138476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 138576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->duplex == DUPLEX_FULL) 138676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg |= GM_GPCR_DUP_FULL; 138776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else 138876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg = GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100 | GM_GPCR_DUP_FULL; 138976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 139076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (skge->flow_control) { 139176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case FLOW_MODE_NONE: 139276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); 139376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg |= GM_GPCR_FC_TX_DIS | GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS; 139476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 139576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case FLOW_MODE_LOC_SEND: 139676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* disable Rx flow-control */ 139776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS; 139876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 139976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case FLOW_MODE_SYMMETRIC: 140076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case FLOW_MODE_SYM_OR_REM: 140176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* enable Tx & Rx flow-control */ 140276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 140376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 140476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 140576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_GP_CTRL, reg); 140676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_read16(hw, SK_REG(port, GMAC_IRQ_SRC)); 140776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 140876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman yukon_init(hw, port); 140976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 141076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* MIB clear */ 141176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg = gma_read16(hw, port, GM_PHY_ADDR); 141276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR); 141376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 141476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < GM_MIB_CNT_SIZE; i++) 141576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_read16(hw, port, GM_MIB_CNT_BASE + 8*i); 141676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_PHY_ADDR, reg); 141776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 141876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* transmit control */ 141976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_TX_CTRL, TX_COL_THR(TX_COL_DEF)); 142076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 142176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* receive control reg: unicast + multicast + no FCS */ 142276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_RX_CTRL, 142376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman GM_RXCR_UCF_ENA | GM_RXCR_CRC_DIS | GM_RXCR_MCF_ENA); 142476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 142576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* transmit flow control */ 142676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_TX_FLOW_CTRL, 0xffff); 142776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 142876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* transmit parameter */ 142976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_TX_PARAM, 143076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman TX_JAM_LEN_VAL(TX_JAM_LEN_DEF) | 143176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman TX_JAM_IPG_VAL(TX_JAM_IPG_DEF) | 143276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman TX_IPG_JAM_DATA(TX_IPG_JAM_DEF)); 143376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 143476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* configure the Serial Mode Register */ 143576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg = DATA_BLIND_VAL(DATA_BLIND_DEF) 143676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman | GM_SMOD_VLAN_ENA 143776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman | IPG_DATA_VAL(IPG_DATA_DEF); 143876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 143976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_SERIAL_MODE, reg); 144076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 144176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* physical address: used for pause frames */ 144276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_set_addr(hw, port, GM_SRC_ADDR_1L, addr); 144376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* virtual address for data */ 144476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_set_addr(hw, port, GM_SRC_ADDR_2L, addr); 144576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 144676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* enable interrupt mask for counter overflows */ 144776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_TX_IRQ_MSK, 0); 144876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_RX_IRQ_MSK, 0); 144976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_TR_IRQ_MSK, 0); 145076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 145176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Initialize Mac Fifo */ 145276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 145376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Configure Rx MAC FIFO */ 145476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, SK_REG(port, RX_GMF_FL_MSK), RX_FF_FL_DEF_MSK); 145576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg = GMF_OPER_ON | GMF_RX_F_FL_ON; 145676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 145776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* disable Rx GMAC FIFO Flush for YUKON-Lite Rev. A0 only */ 145876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (is_yukon_lite_a0(hw)) 145976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg &= ~GMF_RX_F_FL_ON; 146076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 146176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR); 146276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, SK_REG(port, RX_GMF_CTRL_T), reg); 146376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* 146476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * because Pause Packet Truncation in GMAC is not working 146576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * we have to increase the Flush Threshold to 64 bytes 146676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * in order to flush pause packets in Rx FIFO on Yukon-1 146776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 146876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, SK_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF+1); 146976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 147076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Configure Tx MAC FIFO */ 147176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR); 147276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON); 147376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 147476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 147576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Go into power down mode */ 147676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void yukon_suspend(struct skge_hw *hw, int port) 147776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 147876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 ctrl; 147976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 148076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL); 148176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl |= PHY_M_PC_POL_R_DIS; 148276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl); 148376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 148476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL); 148576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl |= PHY_CT_RESET; 148676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl); 148776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 148876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* switch IEEE compatible power down mode on */ 148976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL); 149076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl |= PHY_CT_PDOWN; 149176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl); 149276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 149376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 149476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void yukon_stop(struct skge_port *skge) 149576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 149676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_hw *hw = skge->hw; 149776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int port = skge->port; 149876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 149976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, GMAC_IRQ_MSK), 0); 150076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman yukon_reset(hw, port); 150176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 150276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_GP_CTRL, 150376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_read16(hw, port, GM_GP_CTRL) 150476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman & ~(GM_GPCR_TX_ENA|GM_GPCR_RX_ENA)); 150576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_read16(hw, port, GM_GP_CTRL); 150676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 150776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman yukon_suspend(hw, port); 150876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 150976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* set GPHY Control reset */ 151076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET); 151176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_SET); 151276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 151376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 151476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic u16 yukon_speed(const struct skge_hw *hw __unused, u16 aux) 151576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 151676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (aux & PHY_M_PS_SPEED_MSK) { 151776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case PHY_M_PS_SPEED_1000: 151876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return SPEED_1000; 151976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case PHY_M_PS_SPEED_100: 152076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return SPEED_100; 152176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 152276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return SPEED_10; 152376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 152476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 152576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 152676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void yukon_link_up(struct skge_port *skge) 152776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 152876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_hw *hw = skge->hw; 152976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int port = skge->port; 153076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 reg; 153176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 153276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Enable Transmit FIFO Underrun */ 153376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, GMAC_IRQ_MSK), GMAC_DEF_MSK); 153476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 153576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg = gma_read16(hw, port, GM_GP_CTRL); 153676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->duplex == DUPLEX_FULL || skge->autoneg == AUTONEG_ENABLE) 153776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg |= GM_GPCR_DUP_FULL; 153876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 153976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* enable Rx/Tx */ 154076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA; 154176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_GP_CTRL, reg); 154276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 154376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_DEF_MSK); 154476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_link_up(skge); 154576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 154676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 154776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void yukon_link_down(struct skge_port *skge) 154876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 154976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_hw *hw = skge->hw; 155076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int port = skge->port; 155176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 ctrl; 155276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 155376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl = gma_read16(hw, port, GM_GP_CTRL); 155476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); 155576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gma_write16(hw, port, GM_GP_CTRL, ctrl); 155676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 155776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->flow_status == FLOW_STAT_REM_SEND) { 155876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl = gm_phy_read(hw, port, PHY_MARV_AUNE_ADV); 155976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctrl |= PHY_M_AN_ASP; 156076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* restore Asymmetric Pause bit */ 156176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, ctrl); 156276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 156376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 156476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_link_down(skge); 156576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 156676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman yukon_init(hw, port); 156776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 156876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 156976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void yukon_phy_intr(struct skge_port *skge) 157076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 157176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_hw *hw = skge->hw; 157276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int port = skge->port; 157376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const char *reason = NULL; 157476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 istatus, phystat; 157576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 157676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman istatus = gm_phy_read(hw, port, PHY_MARV_INT_STAT); 157776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman phystat = gm_phy_read(hw, port, PHY_MARV_PHY_STAT); 157876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 157976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGIO(PFX "%s: phy interrupt status 0x%x 0x%x\n", 158076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->netdev->name, istatus, phystat); 158176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 158276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (istatus & PHY_M_IS_AN_COMPL) { 158376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (gm_phy_read(hw, port, PHY_MARV_AUNE_LP) 158476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman & PHY_M_AN_RF) { 158576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reason = "remote fault"; 158676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto failed; 158776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 158876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 158976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (gm_phy_read(hw, port, PHY_MARV_1000T_STAT) & PHY_B_1000S_MSF) { 159076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reason = "master/slave fault"; 159176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto failed; 159276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 159376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 159476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!(phystat & PHY_M_PS_SPDUP_RES)) { 159576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reason = "speed/duplex"; 159676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto failed; 159776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 159876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 159976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->duplex = (phystat & PHY_M_PS_FULL_DUP) 160076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ? DUPLEX_FULL : DUPLEX_HALF; 160176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->speed = yukon_speed(hw, phystat); 160276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 160376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* We are using IEEE 802.3z/D5.0 Table 37-4 */ 160476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (phystat & PHY_M_PS_PAUSE_MSK) { 160576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case PHY_M_PS_PAUSE_MSK: 160676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->flow_status = FLOW_STAT_SYMMETRIC; 160776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 160876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case PHY_M_PS_RX_P_EN: 160976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->flow_status = FLOW_STAT_REM_SEND; 161076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 161176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case PHY_M_PS_TX_P_EN: 161276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->flow_status = FLOW_STAT_LOC_SEND; 161376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 161476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 161576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->flow_status = FLOW_STAT_NONE; 161676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 161776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 161876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->flow_status == FLOW_STAT_NONE || 161976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (skge->speed < SPEED_1000 && skge->duplex == DUPLEX_HALF)) 162076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); 162176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 162276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON); 162376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman yukon_link_up(skge); 162476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 162576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 162676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 162776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (istatus & PHY_M_IS_LSP_CHANGE) 162876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->speed = yukon_speed(hw, phystat); 162976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 163076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (istatus & PHY_M_IS_DUP_CHANGE) 163176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->duplex = (phystat & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF; 163276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (istatus & PHY_M_IS_LST_CHANGE) { 163376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (phystat & PHY_M_PS_LINK_UP) 163476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman yukon_link_up(skge); 163576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 163676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman yukon_link_down(skge); 163776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 163876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 163976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman failed: 164076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG(PFX "%s: autonegotiation failed (%s)\n", 164176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->netdev->name, reason); 164276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 164376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* XXX restart autonegotiation? */ 164476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 164576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 164676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_ramset(struct skge_hw *hw, u16 q, u32 start, size_t len) 164776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 164876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 end; 164976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 165076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman start /= 8; 165176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman len /= 8; 165276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman end = start + len - 1; 165376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 165476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, RB_ADDR(q, RB_CTRL), RB_RST_CLR); 165576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, RB_ADDR(q, RB_START), start); 165676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, RB_ADDR(q, RB_WP), start); 165776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, RB_ADDR(q, RB_RP), start); 165876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, RB_ADDR(q, RB_END), end); 165976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 166076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (q == Q_R1 || q == Q_R2) { 166176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set thresholds on receive queue's */ 166276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, RB_ADDR(q, RB_RX_UTPP), 166376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman start + (2*len)/3); 166476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, RB_ADDR(q, RB_RX_LTPP), 166576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman start + (len/3)); 166676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 166776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Enable store & forward on Tx queue's because 166876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Tx FIFO is only 4K on Genesis and 1K on Yukon 166976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 167076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, RB_ADDR(q, RB_CTRL), RB_ENA_STFWD); 167176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 167276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 167376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, RB_ADDR(q, RB_CTRL), RB_ENA_OP_MD); 167476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 167576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 167676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Setup Bus Memory Interface */ 167776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_qset(struct skge_port *skge, u16 q, 167876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const struct skge_element *e) 167976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 168076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_hw *hw = skge->hw; 168176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 watermark = 0x600; 168276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u64 base = skge->dma + (e->desc - skge->mem); 168376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 168476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* optimization to reduce window on 32bit/33mhz */ 168576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((skge_read16(hw, B0_CTST) & (CS_BUS_CLOCK | CS_BUS_SLOT_SZ)) == 0) 168676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman watermark /= 2; 168776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 168876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, Q_ADDR(q, Q_CSR), CSR_CLR_RESET); 168976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, Q_ADDR(q, Q_F), watermark); 169076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, Q_ADDR(q, Q_DA_H), (u32)(base >> 32)); 169176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, Q_ADDR(q, Q_DA_L), (u32)base); 169276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 169376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 169476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanvoid skge_free(struct net_device *dev) 169576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 169676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_port *skge = netdev_priv(dev); 169776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 169876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(skge->rx_ring.start); 169976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->rx_ring.start = NULL; 170076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 170176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(skge->tx_ring.start); 170276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->tx_ring.start = NULL; 170376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 170476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free_dma(skge->mem, RING_SIZE); 170576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->mem = NULL; 170676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->dma = 0; 170776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 170876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 170976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int skge_up(struct net_device *dev) 171076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 171176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_port *skge = netdev_priv(dev); 171276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_hw *hw = skge->hw; 171376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int port = skge->port; 171476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 chunk, ram_addr; 171576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int err; 171676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 171776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2(PFX "%s: enabling interface\n", dev->name); 171876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 171976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->mem = malloc_dma(RING_SIZE, SKGE_RING_ALIGN); 172076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->dma = virt_to_bus(skge->mem); 172176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!skge->mem) 172276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -ENOMEM; 172376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memset(skge->mem, 0, RING_SIZE); 172476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 172576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman assert(!(skge->dma & 7)); 172676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 172776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* FIXME: find out whether 64 bit gPXE will be loaded > 4GB */ 172876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((u64)skge->dma >> 32 != ((u64) skge->dma + RING_SIZE) >> 32) { 172976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG(PFX "pci_alloc_consistent region crosses 4G boundary\n"); 173076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = -EINVAL; 173176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto err; 173276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 173376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 173476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = skge_ring_alloc(&skge->rx_ring, skge->mem, skge->dma, NUM_RX_DESC); 173576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (err) 173676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto err; 173776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 173876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* this call relies on e->iob and d->control to be 0 173976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This is assured by calling memset() on skge->mem and using zalloc() 174076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * for the skge_element structures. 174176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 174276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_rx_refill(dev); 174376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 174476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = skge_ring_alloc(&skge->tx_ring, skge->mem + RX_RING_SIZE, 174576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->dma + RX_RING_SIZE, NUM_TX_DESC); 174676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (err) 174776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto err; 174876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 174976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Initialize MAC */ 175076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->chip_id == CHIP_ID_GENESIS) 175176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman genesis_mac_init(hw, port); 175276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 175376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman yukon_mac_init(hw, port); 175476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 175576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Configure RAMbuffers - equally between ports and tx/rx */ 175676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman chunk = (hw->ram_size - hw->ram_offset) / (hw->ports * 2); 175776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ram_addr = hw->ram_offset + 2 * chunk * port; 175876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 175976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_ramset(hw, rxqaddr[port], ram_addr, chunk); 176076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_qset(skge, rxqaddr[port], skge->rx_ring.to_clean); 176176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 176276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman assert(!(skge->tx_ring.to_use != skge->tx_ring.to_clean)); 176376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_ramset(hw, txqaddr[port], ram_addr+chunk, chunk); 176476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_qset(skge, txqaddr[port], skge->tx_ring.to_use); 176576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 176676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Start receiver BMU */ 176776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman wmb(); 176876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_START | CSR_IRQ_CL_F); 176976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_led(skge, LED_MODE_ON); 177076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 177176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->intr_mask |= portmask[port]; 177276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, B0_IMSK, hw->intr_mask); 177376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 177476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 177576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 177676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err: 177776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_rx_clean(skge); 177876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_free(dev); 177976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 178076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return err; 178176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 178276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 178376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* stop receiver */ 178476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_rx_stop(struct skge_hw *hw, int port) 178576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 178676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_STOP); 178776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, RB_ADDR(port ? Q_R2 : Q_R1, RB_CTRL), 178876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman RB_RST_SET|RB_DIS_OP_MD); 178976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_SET_RESET); 179076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 179176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 179276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_down(struct net_device *dev) 179376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 179476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_port *skge = netdev_priv(dev); 179576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_hw *hw = skge->hw; 179676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int port = skge->port; 179776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 179876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->mem == NULL) 179976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 180076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 180176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2(PFX "%s: disabling interface\n", dev->name); 180276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 180376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC) 180476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->use_xm_link_timer = 0; 180576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 180676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_link_down(dev); 180776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 180876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->intr_mask &= ~portmask[port]; 180976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, B0_IMSK, hw->intr_mask); 181076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 181176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF); 181276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->chip_id == CHIP_ID_GENESIS) 181376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman genesis_stop(skge); 181476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 181576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman yukon_stop(skge); 181676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 181776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Stop transmitter */ 181876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, Q_ADDR(txqaddr[port], Q_CSR), CSR_STOP); 181976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL), 182076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman RB_RST_SET|RB_DIS_OP_MD); 182176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 182276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 182376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Disable Force Sync bit and Enable Alloc bit */ 182476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, TXA_CTRL), 182576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC); 182676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 182776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Stop Interval Timer and Limit Counter of Tx Arbiter */ 182876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, SK_REG(port, TXA_ITI_INI), 0L); 182976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, SK_REG(port, TXA_LIM_INI), 0L); 183076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 183176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Reset PCI FIFO */ 183276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), CSR_SET_RESET); 183376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL), RB_RST_SET); 183476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 183576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Reset the RAM Buffer async Tx queue */ 183676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, RB_ADDR(port == 0 ? Q_XA1 : Q_XA2, RB_CTRL), RB_RST_SET); 183776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 183876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_rx_stop(hw, port); 183976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 184076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->chip_id == CHIP_ID_GENESIS) { 184176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_RST_SET); 184276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, RX_MFF_CTRL2), MFF_RST_SET); 184376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 184476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); 184576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET); 184676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 184776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 184876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_led(skge, LED_MODE_OFF); 184976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 185076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_tx_clean(dev); 185176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 185276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_rx_clean(skge); 185376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 185476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_free(dev); 185576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 185676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 185776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 185876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline int skge_tx_avail(const struct skge_ring *ring) 185976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 186076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mb(); 186176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return ((ring->to_clean > ring->to_use) ? 0 : NUM_TX_DESC) 186276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman + (ring->to_clean - ring->to_use) - 1; 186376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 186476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 186576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int skge_xmit_frame(struct net_device *dev, struct io_buffer *iob) 186676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 186776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_port *skge = netdev_priv(dev); 186876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_hw *hw = skge->hw; 186976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_element *e; 187076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_tx_desc *td; 187176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 control, len; 187276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u64 map; 187376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 187476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge_tx_avail(&skge->tx_ring) < 1) 187576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EBUSY; 187676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 187776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman e = skge->tx_ring.to_use; 187876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman td = e->desc; 187976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman assert(!(td->control & BMU_OWN)); 188076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman e->iob = iob; 188176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman len = iob_len(iob); 188276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman map = virt_to_bus(iob->data); 188376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 188476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman td->dma_lo = map; 188576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman td->dma_hi = map >> 32; 188676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 188776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman control = BMU_CHECK; 188876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 188976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman control |= BMU_EOF| BMU_IRQ_EOF; 189076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Make sure all the descriptors written */ 189176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman wmb(); 189276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman td->control = BMU_OWN | BMU_SW | BMU_STF | control | len; 189376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman wmb(); 189476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 189576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_START); 189676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 189776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBGIO(PFX "%s: tx queued, slot %td, len %d\n", 189876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dev->name, e - skge->tx_ring.start, (unsigned int)len); 189976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 190076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->tx_ring.to_use = e->next; 190176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman wmb(); 190276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 190376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge_tx_avail(&skge->tx_ring) <= 1) { 190476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG(PFX "%s: transmit queue full\n", dev->name); 190576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 190676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 190776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 190876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 190976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 191076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Free all buffers in transmit ring */ 191176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_tx_clean(struct net_device *dev) 191276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 191376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_port *skge = netdev_priv(dev); 191476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_element *e; 191576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 191676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (e = skge->tx_ring.to_clean; e != skge->tx_ring.to_use; e = e->next) { 191776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_tx_desc *td = e->desc; 191876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman td->control = 0; 191976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 192076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 192176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->tx_ring.to_clean = e; 192276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 192376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 192476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const u8 pause_mc_addr[ETH_ALEN] = { 0x1, 0x80, 0xc2, 0x0, 0x0, 0x1 }; 192576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 192676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline u16 phy_length(const struct skge_hw *hw, u32 status) 192776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 192876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->chip_id == CHIP_ID_GENESIS) 192976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return status >> XMR_FS_LEN_SHIFT; 193076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 193176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return status >> GMR_FS_LEN_SHIFT; 193276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 193376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 193476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic inline int bad_phy_status(const struct skge_hw *hw, u32 status) 193576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 193676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->chip_id == CHIP_ID_GENESIS) 193776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return (status & (XMR_FS_ERR | XMR_FS_2L_VLAN)) != 0; 193876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 193976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return (status & GMR_FS_ANY_ERR) || 194076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (status & GMR_FS_RX_OK) == 0; 194176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 194276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 194376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Free all buffers in Tx ring which are no longer owned by device */ 194476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_tx_done(struct net_device *dev) 194576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 194676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_port *skge = netdev_priv(dev); 194776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_ring *ring = &skge->tx_ring; 194876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_element *e; 194976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 195076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F); 195176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 195276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (e = ring->to_clean; e != ring->to_use; e = e->next) { 195376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 control = ((const struct skge_tx_desc *) e->desc)->control; 195476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 195576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (control & BMU_OWN) 195676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 195776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 195876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_tx_complete(dev, e->iob); 195976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 196076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->tx_ring.to_clean = e; 196176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 196276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Can run lockless until we need to synchronize to restart queue. */ 196376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mb(); 196476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 196576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 196676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_rx_refill(struct net_device *dev) 196776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 196876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_port *skge = netdev_priv(dev); 196976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_ring *ring = &skge->rx_ring; 197076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_element *e; 197176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct io_buffer *iob; 197276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_rx_desc *rd; 197376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 control; 197476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 197576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 197676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < NUM_RX_DESC; i++) { 197776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman e = ring->to_clean; 197876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rd = e->desc; 197976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iob = e->iob; 198076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman control = rd->control; 198176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 198276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* nothing to do here */ 198376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (iob || (control & BMU_OWN)) 198476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman continue; 198576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 198676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2("refilling rx desc %d: ", (ring->to_clean - ring->start)); 198776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 198876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iob = alloc_iob(RX_BUF_SIZE); 198976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (iob) { 199076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_rx_setup(skge, e, iob, RX_BUF_SIZE); 199176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 199276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG("descr %d: alloc_iob() failed\n", 199376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (ring->to_clean - ring->start)); 199476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* We pass the descriptor to the NIC even if the 199576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * allocation failed. The card will stop as soon as it 199676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * encounters a descriptor with the OWN bit set to 0, 199776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * thus never getting to the next descriptor that might 199876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * contain a valid io_buffer. This would effectively 199976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * stall the receive. 200076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 200176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_rx_setup(skge, e, NULL, 0); 200276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 200376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 200476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ring->to_clean = e->next; 200576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 200676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 200776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 200876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_rx_done(struct net_device *dev) 200976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 201076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_port *skge = netdev_priv(dev); 201176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_ring *ring = &skge->rx_ring; 201276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_rx_desc *rd; 201376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_element *e; 201476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct io_buffer *iob; 201576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 control; 201676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 len; 201776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 201876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 201976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman e = ring->to_clean; 202076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < NUM_RX_DESC; i++) { 202176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iob = e->iob; 202276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rd = e->desc; 202376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 202476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman rmb(); 202576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman control = rd->control; 202676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 202776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((control & BMU_OWN)) 202876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 202976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 203076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!iob) 203176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman continue; 203276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 203376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman len = control & BMU_BBC; 203476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 203576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* catch RX errors */ 203676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((bad_phy_status(skge->hw, rd->status)) || 203776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (phy_length(skge->hw, rd->status) != len)) { 203876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* report receive errors */ 203976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG("rx error\n"); 204076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_rx_err(dev, iob, -EIO); 204176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else { 204276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2("received packet, len %d\n", len); 204376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iob_put(iob, len); 204476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_rx(dev, iob); 204576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 204676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 204776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* io_buffer passed to core, make sure we don't reuse it */ 204876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman e->iob = NULL; 204976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 205076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman e = e->next; 205176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 205276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_rx_refill(dev); 205376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 205476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 205576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_poll(struct net_device *dev) 205676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 205776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_port *skge = netdev_priv(dev); 205876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_hw *hw = skge->hw; 205976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 status; 206076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 206176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* reading this register ACKs interrupts */ 206276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman status = skge_read32(hw, B0_SP_ISRC); 206376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 206476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Link event? */ 206576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (status & IS_EXT_REG) { 206676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_phyirq(hw); 206776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge->use_xm_link_timer) 206876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman xm_link_timer(skge); 206976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 207076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 207176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_tx_done(dev); 207276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 207376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F); 207476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 207576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_rx_done(dev); 207676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 207776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* restart receiver */ 207876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman wmb(); 207976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR), CSR_START); 208076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 208176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_read32(hw, B0_IMSK); 208276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 208376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 208476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 208576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 208676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_phyirq(struct skge_hw *hw) 208776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 208876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int port; 208976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 209076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (port = 0; port < hw->ports; port++) { 209176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_device *dev = hw->dev[port]; 209276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_port *skge = netdev_priv(dev); 209376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 209476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->chip_id != CHIP_ID_GENESIS) 209576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman yukon_phy_intr(skge); 209676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else if (hw->phy_type == SK_PHY_BCOM) 209776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman bcom_phy_intr(skge); 209876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 209976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 210076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->intr_mask |= IS_EXT_REG; 210176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, B0_IMSK, hw->intr_mask); 210276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_read32(hw, B0_IMSK); 210376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 210476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 210576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const struct { 210676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 id; 210776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const char *name; 210876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} skge_chips[] = { 210976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman { CHIP_ID_GENESIS, "Genesis" }, 211076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman { CHIP_ID_YUKON, "Yukon" }, 211176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman { CHIP_ID_YUKON_LITE, "Yukon-Lite"}, 211276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman { CHIP_ID_YUKON_LP, "Yukon-LP"}, 211376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 211476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 211576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic const char *skge_board_name(const struct skge_hw *hw) 211676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 211776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unsigned int i; 211876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman static char buf[16]; 211976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 212076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < ARRAY_SIZE(skge_chips); i++) 212176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (skge_chips[i].id == hw->chip_id) 212276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return skge_chips[i].name; 212376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 212476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman snprintf(buf, sizeof buf, "chipid 0x%x", hw->chip_id); 212576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return buf; 212676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 212776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 212876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 212976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 213076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Setup the board data structure, but don't bring up 213176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * the port(s) 213276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 213376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int skge_reset(struct skge_hw *hw) 213476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 213576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u32 reg; 213676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u16 ctst, pci_status; 213776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman u8 t8, mac_cfg, pmd_type; 213876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int i; 213976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 214076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctst = skge_read16(hw, B0_CTST); 214176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 214276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* do a SW reset */ 214376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B0_CTST, CS_RST_SET); 214476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B0_CTST, CS_RST_CLR); 214576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 214676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* clear PCI errors, if any */ 214776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); 214876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B2_TST_CTRL2, 0); 214976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 215076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_read_config_word(hw->pdev, PCI_STATUS, &pci_status); 215176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_write_config_word(hw->pdev, PCI_STATUS, 215276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_status | PCI_STATUS_ERROR_BITS); 215376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); 215476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B0_CTST, CS_MRST_CLR); 215576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 215676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* restore CLK_RUN bits (for Yukon-Lite) */ 215776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, B0_CTST, 215876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman ctst & (CS_CLK_RUN_HOT|CS_CLK_RUN_RST|CS_CLK_RUN_ENA)); 215976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 216076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->chip_id = skge_read8(hw, B2_CHIP_ID); 216176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->phy_type = skge_read8(hw, B2_E_1) & 0xf; 216276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pmd_type = skge_read8(hw, B2_PMD_TYP); 216376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->copper = (pmd_type == 'T' || pmd_type == '1'); 216476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 216576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (hw->chip_id) { 216676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case CHIP_ID_GENESIS: 216776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman switch (hw->phy_type) { 216876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case SK_PHY_XMAC: 216976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->phy_addr = PHY_ADDR_XMAC; 217076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 217176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case SK_PHY_BCOM: 217276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->phy_addr = PHY_ADDR_BCOM; 217376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 217476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 217576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG(PFX "unsupported phy type 0x%x\n", 217676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->phy_type); 217776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EOPNOTSUPP; 217876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 217976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 218076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 218176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case CHIP_ID_YUKON: 218276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case CHIP_ID_YUKON_LITE: 218376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman case CHIP_ID_YUKON_LP: 218476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S') 218576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->copper = 1; 218676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 218776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->phy_addr = PHY_ADDR_MARV; 218876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman break; 218976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 219076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman default: 219176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG(PFX "unsupported chip type 0x%x\n", 219276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->chip_id); 219376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return -EOPNOTSUPP; 219476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 219576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 219676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman mac_cfg = skge_read8(hw, B2_MAC_CFG); 219776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->ports = (mac_cfg & CFG_SNG_MAC) ? 1 : 2; 219876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->chip_rev = (mac_cfg & CFG_CHIP_R_MSK) >> 4; 219976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 220076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* read the adapters RAM size */ 220176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman t8 = skge_read8(hw, B2_E_0); 220276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->chip_id == CHIP_ID_GENESIS) { 220376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (t8 == 3) { 220476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* special case: 4 x 64k x 36, offset = 0x80000 */ 220576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->ram_size = 0x100000; 220676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->ram_offset = 0x80000; 220776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } else 220876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->ram_size = t8 * 512; 220976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 221076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else if (t8 == 0) 221176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->ram_size = 0x20000; 221276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 221376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->ram_size = t8 * 4096; 221476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 221576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->intr_mask = IS_HW_ERR; 221676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 221776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Use PHY IRQ for all but fiber based Genesis board */ 221876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!(hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC)) 221976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->intr_mask |= IS_EXT_REG; 222076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 222176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->chip_id == CHIP_ID_GENESIS) 222276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman genesis_init(hw); 222376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else { 222476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* switch power to VCC (WA for VAUX problem) */ 222576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B0_POWER_CTRL, 222676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON); 222776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 222876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* avoid boards with stuck Hardware error bits */ 222976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((skge_read32(hw, B0_ISRC) & IS_HW_ERR) && 223076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (skge_read32(hw, B0_HWE_ISRC) & IS_IRQ_SENSOR)) { 223176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG(PFX "stuck hardware sensor bit\n"); 223276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->intr_mask &= ~IS_HW_ERR; 223376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 223476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 223576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Clear PHY COMA */ 223676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); 223776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_read_config_dword(hw->pdev, PCI_DEV_REG1, ®); 223876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman reg &= ~PCI_PHY_COMA; 223976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_write_config_dword(hw->pdev, PCI_DEV_REG1, reg); 224076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); 224176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 224276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 224376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < hw->ports; i++) { 224476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET); 224576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR); 224676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 224776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 224876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 224976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* turn off hardware timer (unused) */ 225076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B2_TI_CTRL, TIM_STOP); 225176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B2_TI_CTRL, TIM_CLR_IRQ); 225276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B0_LED, LED_STAT_ON); 225376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 225476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* enable the Tx Arbiters */ 225576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < hw->ports; i++) 225676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, SK_REG(i, TXA_CTRL), TXA_ENA_ARB); 225776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 225876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Initialize ram interface */ 225976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, B3_RI_CTRL, RI_RST_CLR); 226076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 226176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_RI_WTO_R1, SK_RI_TO_53); 226276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_RI_WTO_XA1, SK_RI_TO_53); 226376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_RI_WTO_XS1, SK_RI_TO_53); 226476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_RI_RTO_R1, SK_RI_TO_53); 226576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_RI_RTO_XA1, SK_RI_TO_53); 226676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_RI_RTO_XS1, SK_RI_TO_53); 226776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_RI_WTO_R2, SK_RI_TO_53); 226876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_RI_WTO_XA2, SK_RI_TO_53); 226976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_RI_WTO_XS2, SK_RI_TO_53); 227076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_RI_RTO_R2, SK_RI_TO_53); 227176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_RI_RTO_XA2, SK_RI_TO_53); 227276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B3_RI_RTO_XS2, SK_RI_TO_53); 227376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 227476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, B0_HWE_IMSK, IS_ERR_MSK); 227576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 227676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Set interrupt moderation for Transmit only 227776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Receive interrupts avoided by NAPI 227876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 227976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, B2_IRQM_MSK, IS_XA1_F|IS_XA2_F); 228076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, B2_IRQM_INI, skge_usecs2clk(hw, 100)); 228176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, B2_IRQM_CTRL, TIM_START); 228276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 228376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, B0_IMSK, hw->intr_mask); 228476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 228576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman for (i = 0; i < hw->ports; i++) { 228676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->chip_id == CHIP_ID_GENESIS) 228776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman genesis_reset(hw, i); 228876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 228976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman yukon_reset(hw, i); 229076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 229176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 229276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 229376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 229476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 229576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* Initialize network device */ 229676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic struct net_device *skge_devinit(struct skge_hw *hw, int port, 229776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int highmem __unused) 229876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 229976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_port *skge; 230076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_device *dev = alloc_etherdev(sizeof(*skge)); 230176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 230276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!dev) { 230376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG(PFX "etherdev alloc failed\n"); 230476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return NULL; 230576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 230676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 230776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dev->dev = &hw->pdev->dev; 230876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 230976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge = netdev_priv(dev); 231076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->netdev = dev; 231176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->hw = hw; 231276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 231376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Auto speed and flow control */ 231476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->autoneg = AUTONEG_ENABLE; 231576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->flow_control = FLOW_MODE_SYM_OR_REM; 231676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->duplex = -1; 231776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->speed = -1; 231876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->advertising = skge_supported_modes(hw); 231976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 232076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->dev[port] = dev; 232176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 232276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge->port = port; 232376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 232476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* read the mac address */ 232576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman memcpy(dev->hw_addr, (void *) (hw->regs + B2_MAC_1 + port*8), ETH_ALEN); 232676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 232776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* device is off until link detection */ 232876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_link_down(dev); 232976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 233076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return dev; 233176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 233276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 233376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_show_addr(struct net_device *dev) 233476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 233576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG2(PFX "%s: addr %s\n", 233676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dev->name, netdev_addr(dev)); 233776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 233876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 233976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic int skge_probe(struct pci_device *pdev, 234076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman const struct pci_device_id *ent __unused) 234176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 234276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_device *dev, *dev1; 234376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_hw *hw; 234476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman int err, using_dac = 0; 234576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 234676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman adjust_pci_device(pdev); 234776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 234876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = -ENOMEM; 234976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw = zalloc(sizeof(*hw)); 235076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!hw) { 235176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG(PFX "cannot allocate hardware struct\n"); 235276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto err_out_free_regions; 235376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 235476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 235576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->pdev = pdev; 235676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 235776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->regs = (u32)ioremap(pci_bar_start(pdev, PCI_BASE_ADDRESS_0), 235876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman SKGE_REG_SIZE); 235976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!hw->regs) { 236076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG(PFX "cannot map device registers\n"); 236176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto err_out_free_hw; 236276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 236376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 236476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = skge_reset(hw); 236576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (err) 236676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto err_out_iounmap; 236776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 236876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG(PFX " addr 0x%llx irq %d chip %s rev %d\n", 236976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman (unsigned long long)pdev->ioaddr, pdev->irq, 237076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_board_name(hw), hw->chip_rev); 237176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 237276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dev = skge_devinit(hw, 0, using_dac); 237376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!dev) 237476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto err_out_led_off; 237576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 237676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_init ( dev, &skge_operations ); 237776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 237876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman err = register_netdev(dev); 237976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (err) { 238076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG(PFX "cannot register net device\n"); 238176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman goto err_out_free_netdev; 238276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 238376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 238476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_show_addr(dev); 238576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 238676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (hw->ports > 1 && (dev1 = skge_devinit(hw, 1, using_dac))) { 238776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (register_netdev(dev1) == 0) 238876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_show_addr(dev1); 238976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else { 239076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman /* Failure to register second port need not be fatal */ 239176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman DBG(PFX "register of second port failed\n"); 239276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->dev[1] = NULL; 239376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_nullify(dev1); 239476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_put(dev1); 239576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 239676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 239776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_set_drvdata(pdev, hw); 239876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 239976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return 0; 240076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 240176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_out_free_netdev: 240276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_nullify(dev); 240376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_put(dev); 240476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_out_led_off: 240576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, B0_LED, LED_STAT_OFF); 240676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_out_iounmap: 240776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iounmap((void*)hw->regs); 240876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_out_free_hw: 240976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(hw); 241076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanerr_out_free_regions: 241176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_set_drvdata(pdev, NULL); 241276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return err; 241376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 241476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 241576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_remove(struct pci_device *pdev) 241676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman{ 241776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_hw *hw = pci_get_drvdata(pdev); 241876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct net_device *dev0, *dev1; 241976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 242076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (!hw) 242176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman return; 242276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 242376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if ((dev1 = hw->dev[1])) 242476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unregister_netdev(dev1); 242576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman dev0 = hw->dev[0]; 242676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman unregister_netdev(dev0); 242776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 242876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->intr_mask = 0; 242976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, B0_IMSK, 0); 243076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_read32(hw, B0_IMSK); 243176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 243276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write16(hw, B0_LED, LED_STAT_OFF); 243376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write8(hw, B0_CTST, CS_RST_SET); 243476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 243576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (dev1) { 243676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_nullify(dev1); 243776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_put(dev1); 243876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman } 243976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_nullify(dev0); 244076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman netdev_put(dev0); 244176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 244276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman iounmap((void*)hw->regs); 244376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman free(hw); 244476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman pci_set_drvdata(pdev, NULL); 244576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 244676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 244776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman/* 244876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * Enable or disable IRQ masking. 244976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 245076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v netdev Device to control. 245176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * @v enable Zero to mask off IRQ, non-zero to enable IRQ. 245276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * 245376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman * This is a gPXE Network Driver API function. 245476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman */ 245576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstatic void skge_net_irq ( struct net_device *dev, int enable ) { 245676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_port *skge = netdev_priv(dev); 245776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman struct skge_hw *hw = skge->hw; 245876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 245976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman if (enable) 246076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->intr_mask |= portmask[skge->port]; 246176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman else 246276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman hw->intr_mask &= ~portmask[skge->port]; 246376d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman skge_write32(hw, B0_IMSK, hw->intr_mask); 246476d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman} 246576d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 246676d05dc695b06c4e987bb8078f78032441e1430cGreg Hartmanstruct pci_driver skge_driver __pci_driver = { 246776d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .ids = skge_id_table, 246876d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .id_count = ( sizeof (skge_id_table) / sizeof (skge_id_table[0]) ), 246976d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .probe = skge_probe, 247076d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman .remove = skge_remove 247176d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman}; 247276d05dc695b06c4e987bb8078f78032441e1430cGreg Hartman 2473