X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fnet%2Ftc35815.c;h=d1298e5b72c565d0e9c37fa4bef9052030475e5a;hb=cf312e077662ec3a07529551ab6e885828ccfb1d;hp=df8237360f58b2af627ac99c4ab04f66f4b72078;hpb=10d024c1b2fd58af8362670d7d6e5ae52fc33353;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index df82373..d1298e5 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -23,9 +23,9 @@ */ #ifdef TC35815_NAPI -#define DRV_VERSION "1.36-NAPI" +#define DRV_VERSION "1.38-NAPI" #else -#define DRV_VERSION "1.36" +#define DRV_VERSION "1.38" #endif static const char *version = "tc35815.c:v" DRV_VERSION "\n"; #define MODNAME "tc35815" @@ -37,6 +37,7 @@ static const char *version = "tc35815.c:v" DRV_VERSION "\n"; #include #include #include +#include #include #include #include @@ -47,8 +48,8 @@ static const char *version = "tc35815.c:v" DRV_VERSION "\n"; #include #include #include -#include -#include +#include +#include #include #include #include @@ -60,16 +61,16 @@ static const char *version = "tc35815.c:v" DRV_VERSION "\n"; #define WORKAROUND_100HALF_PROMISC /* #define TC35815_USE_PACKEDBUFFER */ -typedef enum { +enum tc35815_chiptype { TC35815CF = 0, TC35815_NWU, TC35815_TX4939, -} board_t; +}; -/* indexed by board_t, above */ +/* indexed by tc35815_chiptype, above */ static const struct { const char *name; -} board_info[] __devinitdata = { +} chip_info[] __devinitdata = { { "TOSHIBA TC35815CF 10/100BaseTX" }, { "TOSHIBA TC35815 with Wake on LAN" }, { "TOSHIBA TC35815/TX4939" }, @@ -81,209 +82,209 @@ static const struct pci_device_id tc35815_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939), .driver_data = TC35815_TX4939 }, {0,} }; -MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl); +MODULE_DEVICE_TABLE(pci, tc35815_pci_tbl); /* see MODULE_PARM_DESC */ static struct tc35815_options { int speed; int duplex; - int doforce; } options; /* * Registers */ struct tc35815_regs { - volatile __u32 DMA_Ctl; /* 0x00 */ - volatile __u32 TxFrmPtr; - volatile __u32 TxThrsh; - volatile __u32 TxPollCtr; - volatile __u32 BLFrmPtr; - volatile __u32 RxFragSize; - volatile __u32 Int_En; - volatile __u32 FDA_Bas; - volatile __u32 FDA_Lim; /* 0x20 */ - volatile __u32 Int_Src; - volatile __u32 unused0[2]; - volatile __u32 PauseCnt; - volatile __u32 RemPauCnt; - volatile __u32 TxCtlFrmStat; - volatile __u32 unused1; - volatile __u32 MAC_Ctl; /* 0x40 */ - volatile __u32 CAM_Ctl; - volatile __u32 Tx_Ctl; - volatile __u32 Tx_Stat; - volatile __u32 Rx_Ctl; - volatile __u32 Rx_Stat; - volatile __u32 MD_Data; - volatile __u32 MD_CA; - volatile __u32 CAM_Adr; /* 0x60 */ - volatile __u32 CAM_Data; - volatile __u32 CAM_Ena; - volatile __u32 PROM_Ctl; - volatile __u32 PROM_Data; - volatile __u32 Algn_Cnt; - volatile __u32 CRC_Cnt; - volatile __u32 Miss_Cnt; + __u32 DMA_Ctl; /* 0x00 */ + __u32 TxFrmPtr; + __u32 TxThrsh; + __u32 TxPollCtr; + __u32 BLFrmPtr; + __u32 RxFragSize; + __u32 Int_En; + __u32 FDA_Bas; + __u32 FDA_Lim; /* 0x20 */ + __u32 Int_Src; + __u32 unused0[2]; + __u32 PauseCnt; + __u32 RemPauCnt; + __u32 TxCtlFrmStat; + __u32 unused1; + __u32 MAC_Ctl; /* 0x40 */ + __u32 CAM_Ctl; + __u32 Tx_Ctl; + __u32 Tx_Stat; + __u32 Rx_Ctl; + __u32 Rx_Stat; + __u32 MD_Data; + __u32 MD_CA; + __u32 CAM_Adr; /* 0x60 */ + __u32 CAM_Data; + __u32 CAM_Ena; + __u32 PROM_Ctl; + __u32 PROM_Data; + __u32 Algn_Cnt; + __u32 CRC_Cnt; + __u32 Miss_Cnt; }; /* * Bit assignments */ /* DMA_Ctl bit asign ------------------------------------------------------- */ -#define DMA_RxAlign 0x00c00000 /* 1:Reception Alignment */ -#define DMA_RxAlign_1 0x00400000 -#define DMA_RxAlign_2 0x00800000 -#define DMA_RxAlign_3 0x00c00000 -#define DMA_M66EnStat 0x00080000 /* 1:66MHz Enable State */ -#define DMA_IntMask 0x00040000 /* 1:Interupt mask */ -#define DMA_SWIntReq 0x00020000 /* 1:Software Interrupt request */ -#define DMA_TxWakeUp 0x00010000 /* 1:Transmit Wake Up */ -#define DMA_RxBigE 0x00008000 /* 1:Receive Big Endian */ -#define DMA_TxBigE 0x00004000 /* 1:Transmit Big Endian */ -#define DMA_TestMode 0x00002000 /* 1:Test Mode */ -#define DMA_PowrMgmnt 0x00001000 /* 1:Power Management */ -#define DMA_DmBurst_Mask 0x000001fc /* DMA Burst size */ +#define DMA_RxAlign 0x00c00000 /* 1:Reception Alignment */ +#define DMA_RxAlign_1 0x00400000 +#define DMA_RxAlign_2 0x00800000 +#define DMA_RxAlign_3 0x00c00000 +#define DMA_M66EnStat 0x00080000 /* 1:66MHz Enable State */ +#define DMA_IntMask 0x00040000 /* 1:Interupt mask */ +#define DMA_SWIntReq 0x00020000 /* 1:Software Interrupt request */ +#define DMA_TxWakeUp 0x00010000 /* 1:Transmit Wake Up */ +#define DMA_RxBigE 0x00008000 /* 1:Receive Big Endian */ +#define DMA_TxBigE 0x00004000 /* 1:Transmit Big Endian */ +#define DMA_TestMode 0x00002000 /* 1:Test Mode */ +#define DMA_PowrMgmnt 0x00001000 /* 1:Power Management */ +#define DMA_DmBurst_Mask 0x000001fc /* DMA Burst size */ /* RxFragSize bit asign ---------------------------------------------------- */ -#define RxFrag_EnPack 0x00008000 /* 1:Enable Packing */ -#define RxFrag_MinFragMask 0x00000ffc /* Minimum Fragment */ +#define RxFrag_EnPack 0x00008000 /* 1:Enable Packing */ +#define RxFrag_MinFragMask 0x00000ffc /* Minimum Fragment */ /* MAC_Ctl bit asign ------------------------------------------------------- */ -#define MAC_Link10 0x00008000 /* 1:Link Status 10Mbits */ -#define MAC_EnMissRoll 0x00002000 /* 1:Enable Missed Roll */ -#define MAC_MissRoll 0x00000400 /* 1:Missed Roll */ -#define MAC_Loop10 0x00000080 /* 1:Loop 10 Mbps */ -#define MAC_Conn_Auto 0x00000000 /*00:Connection mode (Automatic) */ -#define MAC_Conn_10M 0x00000020 /*01: (10Mbps endec)*/ -#define MAC_Conn_Mll 0x00000040 /*10: (Mll clock) */ -#define MAC_MacLoop 0x00000010 /* 1:MAC Loopback */ -#define MAC_FullDup 0x00000008 /* 1:Full Duplex 0:Half Duplex */ -#define MAC_Reset 0x00000004 /* 1:Software Reset */ -#define MAC_HaltImm 0x00000002 /* 1:Halt Immediate */ -#define MAC_HaltReq 0x00000001 /* 1:Halt request */ +#define MAC_Link10 0x00008000 /* 1:Link Status 10Mbits */ +#define MAC_EnMissRoll 0x00002000 /* 1:Enable Missed Roll */ +#define MAC_MissRoll 0x00000400 /* 1:Missed Roll */ +#define MAC_Loop10 0x00000080 /* 1:Loop 10 Mbps */ +#define MAC_Conn_Auto 0x00000000 /*00:Connection mode (Automatic) */ +#define MAC_Conn_10M 0x00000020 /*01: (10Mbps endec)*/ +#define MAC_Conn_Mll 0x00000040 /*10: (Mll clock) */ +#define MAC_MacLoop 0x00000010 /* 1:MAC Loopback */ +#define MAC_FullDup 0x00000008 /* 1:Full Duplex 0:Half Duplex */ +#define MAC_Reset 0x00000004 /* 1:Software Reset */ +#define MAC_HaltImm 0x00000002 /* 1:Halt Immediate */ +#define MAC_HaltReq 0x00000001 /* 1:Halt request */ /* PROM_Ctl bit asign ------------------------------------------------------ */ -#define PROM_Busy 0x00008000 /* 1:Busy (Start Operation) */ -#define PROM_Read 0x00004000 /*10:Read operation */ -#define PROM_Write 0x00002000 /*01:Write operation */ -#define PROM_Erase 0x00006000 /*11:Erase operation */ - /*00:Enable or Disable Writting, */ - /* as specified in PROM_Addr. */ -#define PROM_Addr_Ena 0x00000030 /*11xxxx:PROM Write enable */ - /*00xxxx: disable */ +#define PROM_Busy 0x00008000 /* 1:Busy (Start Operation) */ +#define PROM_Read 0x00004000 /*10:Read operation */ +#define PROM_Write 0x00002000 /*01:Write operation */ +#define PROM_Erase 0x00006000 /*11:Erase operation */ + /*00:Enable or Disable Writting, */ + /* as specified in PROM_Addr. */ +#define PROM_Addr_Ena 0x00000030 /*11xxxx:PROM Write enable */ + /*00xxxx: disable */ /* CAM_Ctl bit asign ------------------------------------------------------- */ -#define CAM_CompEn 0x00000010 /* 1:CAM Compare Enable */ -#define CAM_NegCAM 0x00000008 /* 1:Reject packets CAM recognizes,*/ - /* accept other */ -#define CAM_BroadAcc 0x00000004 /* 1:Broadcast assept */ -#define CAM_GroupAcc 0x00000002 /* 1:Multicast assept */ -#define CAM_StationAcc 0x00000001 /* 1:unicast accept */ +#define CAM_CompEn 0x00000010 /* 1:CAM Compare Enable */ +#define CAM_NegCAM 0x00000008 /* 1:Reject packets CAM recognizes,*/ + /* accept other */ +#define CAM_BroadAcc 0x00000004 /* 1:Broadcast assept */ +#define CAM_GroupAcc 0x00000002 /* 1:Multicast assept */ +#define CAM_StationAcc 0x00000001 /* 1:unicast accept */ /* CAM_Ena bit asign ------------------------------------------------------- */ -#define CAM_ENTRY_MAX 21 /* CAM Data entry max count */ +#define CAM_ENTRY_MAX 21 /* CAM Data entry max count */ #define CAM_Ena_Mask ((1<boardtype != TC35815CF) +#define HAVE_DMA_RXALIGN(lp) likely((lp)->chiptype != TC35815CF) /* Tuning parameters */ #define DMA_BURST_SIZE 32 #define TX_THRESHOLD 1024 -#define TX_THRESHOLD_MAX 1536 /* used threshold with packet max byte for low pci transfer ability.*/ -#define TX_THRESHOLD_KEEP_LIMIT 10 /* setting threshold max value when overrun error occured this count. */ +/* used threshold with packet max byte for low pci transfer ability.*/ +#define TX_THRESHOLD_MAX 1536 +/* setting threshold max value when overrun error occured this count. */ +#define TX_THRESHOLD_KEEP_LIMIT 10 /* 16 + RX_BUF_NUM * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*FD_PAGE_NUM */ #ifdef TC35815_USE_PACKEDBUFFER @@ -371,9 +375,11 @@ struct BDesc { #if RX_CTL_CMD & Rx_LongEn #define RX_BUF_SIZE PAGE_SIZE #elif RX_CTL_CMD & Rx_StripCRC -#define RX_BUF_SIZE ALIGN(ETH_FRAME_LEN + 4 + 2, 32) /* +2: reserve */ +#define RX_BUF_SIZE \ + L1_CACHE_ALIGN(ETH_FRAME_LEN + VLAN_HLEN + NET_IP_ALIGN) #else -#define RX_BUF_SIZE ALIGN(ETH_FRAME_LEN + 2, 32) /* +2: reserve */ +#define RX_BUF_SIZE \ + L1_CACHE_ALIGN(ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN + NET_IP_ALIGN) #endif #endif /* TC35815_USE_PACKEDBUFFER */ #define RX_FD_RESERVE (2 / 2) /* max 2 BD per RxFD */ @@ -396,21 +402,12 @@ struct FrFD { }; -#define tc_readl(addr) readl(addr) -#define tc_writel(d, addr) writel(d, addr) +#define tc_readl(addr) ioread32(addr) +#define tc_writel(d, addr) iowrite32(d, addr) #define TC35815_TX_TIMEOUT msecs_to_jiffies(400) -/* Timer state engine. */ -enum tc35815_timer_state { - arbwait = 0, /* Waiting for auto negotiation to complete. */ - lupwait = 1, /* Auto-neg complete, awaiting link-up status. */ - ltrywait = 2, /* Forcing try of all modes, from fastest to slowest. */ - asleep = 3, /* Time inactive. */ - lcheck = 4, /* Check link status. */ -}; - -/* Information that need to be kept for each board. */ +/* Information that need to be kept for each controller. */ struct tc35815_local { struct pci_dev *pci_dev; @@ -418,12 +415,11 @@ struct tc35815_local { struct napi_struct napi; /* statistics */ - struct net_device_stats stats; struct { int max_tx_qlen; int tx_ints; int rx_ints; - int tx_underrun; + int tx_underrun; } lstats; /* Tx control lock. This protects the transmit buffer ring @@ -433,12 +429,12 @@ struct tc35815_local { */ spinlock_t lock; - int phy_addr; - int fullduplex; - unsigned short saved_lpa; - struct timer_list timer; - enum tc35815_timer_state timer_state; /* State of auto-neg timer. */ - unsigned int timer_ticks; /* Number of clicks at each state */ + struct mii_bus *mii_bus; + struct phy_device *phy_dev; + int duplex; + int speed; + int link; + struct work_struct restart_work; /* * Transmitting: Batch Mode. @@ -452,7 +448,7 @@ struct tc35815_local { * RX_BUF_NUM BD in Free Buffer FD. * One Free Buffer BD has ETH_FRAME_LEN data buffer. */ - void * fd_buf; /* for TxFD, RxFD, FrFD */ + void *fd_buf; /* for TxFD, RxFD, FrFD */ dma_addr_t fd_buf_dma; struct TxFD *tfd_base; unsigned int tfd_start; @@ -463,7 +459,7 @@ struct tc35815_local { struct FrFD *fbl_ptr; #ifdef TC35815_USE_PACKEDBUFFER unsigned char fbl_curid; - void * data_buf[RX_BUF_NUM]; /* packing */ + void *data_buf[RX_BUF_NUM]; /* packing */ dma_addr_t data_buf_dma[RX_BUF_NUM]; struct { struct sk_buff *skb; @@ -476,10 +472,8 @@ struct tc35815_local { dma_addr_t skb_dma; } tx_skbs[TX_FD_NUM], rx_skbs[RX_BUF_NUM]; #endif - struct mii_if_info mii; - unsigned short mii_id[2]; u32 msg_enable; - board_t boardtype; + enum tc35815_chiptype chiptype; }; static inline dma_addr_t fd_virt_to_bus(struct tc35815_local *lp, void *virt) @@ -506,17 +500,18 @@ static inline void *rxbuf_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus) } #define TC35815_DMA_SYNC_ONDEMAND -static void* alloc_rxbuf_page(struct pci_dev *hwdev, dma_addr_t *dma_handle) +static void *alloc_rxbuf_page(struct pci_dev *hwdev, dma_addr_t *dma_handle) { #ifdef TC35815_DMA_SYNC_ONDEMAND void *buf; /* pci_map + pci_dma_sync will be more effective than * pci_alloc_consistent on some archs. */ - if ((buf = (void *)__get_free_page(GFP_ATOMIC)) == NULL) + buf = (void *)__get_free_page(GFP_ATOMIC); + if (!buf) return NULL; *dma_handle = pci_map_single(hwdev, buf, PAGE_SIZE, PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(*dma_handle)) { + if (pci_dma_mapping_error(hwdev, *dma_handle)) { free_page((unsigned long)buf); return NULL; } @@ -546,7 +541,7 @@ static struct sk_buff *alloc_rxbuf_skb(struct net_device *dev, return NULL; *dma_handle = pci_map_single(hwdev, skb->data, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(*dma_handle)) { + if (pci_dma_mapping_error(hwdev, *dma_handle)) { dev_kfree_skb_any(skb); return NULL; } @@ -577,7 +572,7 @@ static void tc35815_txdone(struct net_device *dev); static int tc35815_close(struct net_device *dev); static struct net_device_stats *tc35815_get_stats(struct net_device *dev); static void tc35815_set_multicast_list(struct net_device *dev); -static void tc35815_tx_timeout(struct net_device *dev); +static void tc35815_tx_timeout(struct net_device *dev); static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); #ifdef CONFIG_NET_POLL_CONTROLLER static void tc35815_poll_controller(struct net_device *dev); @@ -585,21 +580,231 @@ static void tc35815_poll_controller(struct net_device *dev); static const struct ethtool_ops tc35815_ethtool_ops; /* Example routines you must write ;->. */ -static void tc35815_chip_reset(struct net_device *dev); -static void tc35815_chip_init(struct net_device *dev); -static void tc35815_find_phy(struct net_device *dev); -static void tc35815_phy_chip_init(struct net_device *dev); +static void tc35815_chip_reset(struct net_device *dev); +static void tc35815_chip_init(struct net_device *dev); #ifdef DEBUG static void panic_queues(struct net_device *dev); #endif -static void tc35815_timer(unsigned long data); -static void tc35815_start_auto_negotiation(struct net_device *dev, - struct ethtool_cmd *ep); -static int tc_mdio_read(struct net_device *dev, int phy_id, int location); -static void tc_mdio_write(struct net_device *dev, int phy_id, int location, - int val); +static void tc35815_restart_work(struct work_struct *work); + +static int tc_mdio_read(struct mii_bus *bus, int mii_id, int regnum) +{ + struct net_device *dev = bus->priv; + struct tc35815_regs __iomem *tr = + (struct tc35815_regs __iomem *)dev->base_addr; + unsigned long timeout = jiffies + HZ; + + tc_writel(MD_CA_Busy | (mii_id << 5) | (regnum & 0x1f), &tr->MD_CA); + udelay(12); /* it takes 32 x 400ns at least */ + while (tc_readl(&tr->MD_CA) & MD_CA_Busy) { + if (time_after(jiffies, timeout)) + return -EIO; + cpu_relax(); + } + return tc_readl(&tr->MD_Data) & 0xffff; +} + +static int tc_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 val) +{ + struct net_device *dev = bus->priv; + struct tc35815_regs __iomem *tr = + (struct tc35815_regs __iomem *)dev->base_addr; + unsigned long timeout = jiffies + HZ; + + tc_writel(val, &tr->MD_Data); + tc_writel(MD_CA_Busy | MD_CA_Wr | (mii_id << 5) | (regnum & 0x1f), + &tr->MD_CA); + udelay(12); /* it takes 32 x 400ns at least */ + while (tc_readl(&tr->MD_CA) & MD_CA_Busy) { + if (time_after(jiffies, timeout)) + return -EIO; + cpu_relax(); + } + return 0; +} + +static void tc_handle_link_change(struct net_device *dev) +{ + struct tc35815_local *lp = netdev_priv(dev); + struct phy_device *phydev = lp->phy_dev; + unsigned long flags; + int status_change = 0; + + spin_lock_irqsave(&lp->lock, flags); + if (phydev->link && + (lp->speed != phydev->speed || lp->duplex != phydev->duplex)) { + struct tc35815_regs __iomem *tr = + (struct tc35815_regs __iomem *)dev->base_addr; + u32 reg; + + reg = tc_readl(&tr->MAC_Ctl); + reg |= MAC_HaltReq; + tc_writel(reg, &tr->MAC_Ctl); + if (phydev->duplex == DUPLEX_FULL) + reg |= MAC_FullDup; + else + reg &= ~MAC_FullDup; + tc_writel(reg, &tr->MAC_Ctl); + reg &= ~MAC_HaltReq; + tc_writel(reg, &tr->MAC_Ctl); + + /* + * TX4939 PCFG.SPEEDn bit will be changed on + * NETDEV_CHANGE event. + */ + +#if !defined(NO_CHECK_CARRIER) && defined(WORKAROUND_LOSTCAR) + /* + * WORKAROUND: enable LostCrS only if half duplex + * operation. + * (TX4939 does not have EnLCarr) + */ + if (phydev->duplex == DUPLEX_HALF && + lp->chiptype != TC35815_TX4939) + tc_writel(tc_readl(&tr->Tx_Ctl) | Tx_EnLCarr, + &tr->Tx_Ctl); +#endif + + lp->speed = phydev->speed; + lp->duplex = phydev->duplex; + status_change = 1; + } + + if (phydev->link != lp->link) { + if (phydev->link) { +#ifdef WORKAROUND_100HALF_PROMISC + /* delayed promiscuous enabling */ + if (dev->flags & IFF_PROMISC) + tc35815_set_multicast_list(dev); +#endif + } else { + lp->speed = 0; + lp->duplex = -1; + } + lp->link = phydev->link; + + status_change = 1; + } + spin_unlock_irqrestore(&lp->lock, flags); + + if (status_change && netif_msg_link(lp)) { + phy_print_status(phydev); + pr_debug("%s: MII BMCR %04x BMSR %04x LPA %04x\n", + dev->name, + phy_read(phydev, MII_BMCR), + phy_read(phydev, MII_BMSR), + phy_read(phydev, MII_LPA)); + } +} + +static int tc_mii_probe(struct net_device *dev) +{ + struct tc35815_local *lp = netdev_priv(dev); + struct phy_device *phydev = NULL; + int phy_addr; + u32 dropmask; + + /* find the first phy */ + for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { + if (lp->mii_bus->phy_map[phy_addr]) { + if (phydev) { + printk(KERN_ERR "%s: multiple PHYs found\n", + dev->name); + return -EINVAL; + } + phydev = lp->mii_bus->phy_map[phy_addr]; + break; + } + } + + if (!phydev) { + printk(KERN_ERR "%s: no PHY found\n", dev->name); + return -ENODEV; + } + + /* attach the mac to the phy */ + phydev = phy_connect(dev, dev_name(&phydev->dev), + &tc_handle_link_change, 0, + lp->chiptype == TC35815_TX4939 ? + PHY_INTERFACE_MODE_RMII : PHY_INTERFACE_MODE_MII); + if (IS_ERR(phydev)) { + printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); + return PTR_ERR(phydev); + } + printk(KERN_INFO "%s: attached PHY driver [%s] " + "(mii_bus:phy_addr=%s, id=%x)\n", + dev->name, phydev->drv->name, dev_name(&phydev->dev), + phydev->phy_id); + + /* mask with MAC supported features */ + phydev->supported &= PHY_BASIC_FEATURES; + dropmask = 0; + if (options.speed == 10) + dropmask |= SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full; + else if (options.speed == 100) + dropmask |= SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full; + if (options.duplex == 1) + dropmask |= SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full; + else if (options.duplex == 2) + dropmask |= SUPPORTED_10baseT_Half | SUPPORTED_100baseT_Half; + phydev->supported &= ~dropmask; + phydev->advertising = phydev->supported; + + lp->link = 0; + lp->speed = 0; + lp->duplex = -1; + lp->phy_dev = phydev; + + return 0; +} + +static int tc_mii_init(struct net_device *dev) +{ + struct tc35815_local *lp = netdev_priv(dev); + int err; + int i; + + lp->mii_bus = mdiobus_alloc(); + if (lp->mii_bus == NULL) { + err = -ENOMEM; + goto err_out; + } + + lp->mii_bus->name = "tc35815_mii_bus"; + lp->mii_bus->read = tc_mdio_read; + lp->mii_bus->write = tc_mdio_write; + snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%x", + (lp->pci_dev->bus->number << 8) | lp->pci_dev->devfn); + lp->mii_bus->priv = dev; + lp->mii_bus->parent = &lp->pci_dev->dev; + lp->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); + if (!lp->mii_bus->irq) { + err = -ENOMEM; + goto err_out_free_mii_bus; + } + + for (i = 0; i < PHY_MAX_ADDR; i++) + lp->mii_bus->irq[i] = PHY_POLL; + + err = mdiobus_register(lp->mii_bus); + if (err) + goto err_out_free_mdio_irq; + err = tc_mii_probe(dev); + if (err) + goto err_out_unregister_bus; + return 0; + +err_out_unregister_bus: + mdiobus_unregister(lp->mii_bus); +err_out_free_mdio_irq: + kfree(lp->mii_bus->irq); +err_out_free_mii_bus: + mdiobus_free(lp->mii_bus); +err_out: + return err; +} #ifdef CONFIG_CPU_TX49XX /* @@ -611,13 +816,13 @@ static int __devinit tc35815_mac_match(struct device *dev, void *data) { struct platform_device *plat_dev = to_platform_device(dev); struct pci_dev *pci_dev = data; - unsigned int id = (pci_dev->bus->number << 8) | pci_dev->devfn; + unsigned int id = pci_dev->irq; return !strcmp(plat_dev->name, "tc35815-mac") && plat_dev->id == id; } static int __devinit tc35815_read_plat_dev_addr(struct net_device *dev) { - struct tc35815_local *lp = dev->priv; + struct tc35815_local *lp = netdev_priv(dev); struct device *pd = bus_find_device(&platform_bus_type, NULL, lp->pci_dev, tc35815_mac_match); if (pd) { @@ -635,7 +840,7 @@ static int __devinit tc35815_read_plat_dev_addr(struct net_device *dev) } #endif -static int __devinit tc35815_init_dev_addr (struct net_device *dev) +static int __devinit tc35815_init_dev_addr(struct net_device *dev) { struct tc35815_regs __iomem *tr = (struct tc35815_regs __iomem *)dev->base_addr; @@ -657,21 +862,36 @@ static int __devinit tc35815_init_dev_addr (struct net_device *dev) return 0; } -static int __devinit tc35815_init_one (struct pci_dev *pdev, - const struct pci_device_id *ent) +static const struct net_device_ops tc35815_netdev_ops = { + .ndo_open = tc35815_open, + .ndo_stop = tc35815_close, + .ndo_start_xmit = tc35815_send_packet, + .ndo_get_stats = tc35815_get_stats, + .ndo_set_multicast_list = tc35815_set_multicast_list, + .ndo_tx_timeout = tc35815_tx_timeout, + .ndo_do_ioctl = tc35815_ioctl, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = tc35815_poll_controller, +#endif +}; + +static int __devinit tc35815_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) { void __iomem *ioaddr = NULL; struct net_device *dev; struct tc35815_local *lp; int rc; - unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; static int printed_version; if (!printed_version++) { printk(version); dev_printk(KERN_DEBUG, &pdev->dev, - "speed:%d duplex:%d doforce:%d\n", - options.speed, options.duplex, options.doforce); + "speed:%d duplex:%d\n", + options.speed, options.duplex); } if (!pdev->irq) { @@ -680,79 +900,40 @@ static int __devinit tc35815_init_one (struct pci_dev *pdev, } /* dev zeroed in alloc_etherdev */ - dev = alloc_etherdev (sizeof (*lp)); + dev = alloc_etherdev(sizeof(*lp)); if (dev == NULL) { dev_err(&pdev->dev, "unable to alloc new ethernet\n"); return -ENOMEM; } SET_NETDEV_DEV(dev, &pdev->dev); - lp = dev->priv; + lp = netdev_priv(dev); lp->dev = dev; /* enable device (incl. PCI PM wakeup), and bus-mastering */ - rc = pci_enable_device (pdev); + rc = pcim_enable_device(pdev); if (rc) goto err_out; - - mmio_start = pci_resource_start (pdev, 1); - mmio_end = pci_resource_end (pdev, 1); - mmio_flags = pci_resource_flags (pdev, 1); - mmio_len = pci_resource_len (pdev, 1); - - /* set this immediately, we need to know before - * we talk to the chip directly */ - - /* make sure PCI base addr 1 is MMIO */ - if (!(mmio_flags & IORESOURCE_MEM)) { - dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n"); - rc = -ENODEV; - goto err_out; - } - - /* check for weird/broken PCI region reporting */ - if ((mmio_len < sizeof(struct tc35815_regs))) { - dev_err(&pdev->dev, "Invalid PCI region size(s), aborting\n"); - rc = -ENODEV; - goto err_out; - } - - rc = pci_request_regions (pdev, MODNAME); + rc = pcim_iomap_regions(pdev, 1 << 1, MODNAME); if (rc) goto err_out; - - pci_set_master (pdev); - - /* ioremap MMIO region */ - ioaddr = ioremap (mmio_start, mmio_len); - if (ioaddr == NULL) { - dev_err(&pdev->dev, "cannot remap MMIO, aborting\n"); - rc = -EIO; - goto err_out_free_res; - } + pci_set_master(pdev); + ioaddr = pcim_iomap_table(pdev)[1]; /* Initialize the device structure. */ - dev->open = tc35815_open; - dev->hard_start_xmit = tc35815_send_packet; - dev->stop = tc35815_close; - dev->get_stats = tc35815_get_stats; - dev->set_multicast_list = tc35815_set_multicast_list; - dev->do_ioctl = tc35815_ioctl; + dev->netdev_ops = &tc35815_netdev_ops; dev->ethtool_ops = &tc35815_ethtool_ops; - dev->tx_timeout = tc35815_tx_timeout; dev->watchdog_timeo = TC35815_TX_TIMEOUT; #ifdef TC35815_NAPI netif_napi_add(dev, &lp->napi, tc35815_poll, NAPI_WEIGHT); #endif -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = tc35815_poll_controller; -#endif dev->irq = pdev->irq; - dev->base_addr = (unsigned long) ioaddr; + dev->base_addr = (unsigned long)ioaddr; + INIT_WORK(&lp->restart_work, tc35815_restart_work); spin_lock_init(&lp->lock); lp->pci_dev = pdev; - lp->boardtype = ent->driver_data; + lp->chiptype = ent->driver_data; lp->msg_enable = NETIF_MSG_TX_ERR | NETIF_MSG_HW | NETIF_MSG_DRV | NETIF_MSG_LINK; pci_set_drvdata(pdev, dev); @@ -766,68 +947,50 @@ static int __devinit tc35815_init_one (struct pci_dev *pdev, random_ether_addr(dev->dev_addr); } - rc = register_netdev (dev); + rc = register_netdev(dev); if (rc) - goto err_out_unmap; + goto err_out; memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - printk(KERN_INFO "%s: %s at 0x%lx, " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " - "IRQ %d\n", + printk(KERN_INFO "%s: %s at 0x%lx, %pM, IRQ %d\n", dev->name, - board_info[ent->driver_data].name, + chip_info[ent->driver_data].name, dev->base_addr, - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5], + dev->dev_addr, dev->irq); - setup_timer(&lp->timer, tc35815_timer, (unsigned long) dev); - lp->mii.dev = dev; - lp->mii.mdio_read = tc_mdio_read; - lp->mii.mdio_write = tc_mdio_write; - lp->mii.phy_id_mask = 0x1f; - lp->mii.reg_num_mask = 0x1f; - tc35815_find_phy(dev); - lp->mii.phy_id = lp->phy_addr; - lp->mii.full_duplex = 0; - lp->mii.force_media = 0; + rc = tc_mii_init(dev); + if (rc) + goto err_out_unregister; return 0; -err_out_unmap: - iounmap(ioaddr); -err_out_free_res: - pci_release_regions (pdev); +err_out_unregister: + unregister_netdev(dev); err_out: - free_netdev (dev); + free_netdev(dev); return rc; } -static void __devexit tc35815_remove_one (struct pci_dev *pdev) +static void __devexit tc35815_remove_one(struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata (pdev); - unsigned long mmio_addr; - - mmio_addr = dev->base_addr; - - unregister_netdev (dev); - - if (mmio_addr) { - iounmap ((void __iomem *)mmio_addr); - pci_release_regions (pdev); - } - - free_netdev (dev); + struct net_device *dev = pci_get_drvdata(pdev); + struct tc35815_local *lp = netdev_priv(dev); - pci_set_drvdata (pdev, NULL); + phy_disconnect(lp->phy_dev); + mdiobus_unregister(lp->mii_bus); + kfree(lp->mii_bus->irq); + mdiobus_free(lp->mii_bus); + unregister_netdev(dev); + free_netdev(dev); + pci_set_drvdata(pdev, NULL); } static int tc35815_init_queues(struct net_device *dev) { - struct tc35815_local *lp = dev->priv; + struct tc35815_local *lp = netdev_priv(dev); int i; unsigned long fd_addr; @@ -838,11 +1001,17 @@ tc35815_init_queues(struct net_device *dev) sizeof(struct TxFD) * TX_FD_NUM > PAGE_SIZE * FD_PAGE_NUM); - if ((lp->fd_buf = pci_alloc_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM, &lp->fd_buf_dma)) == 0) + lp->fd_buf = pci_alloc_consistent(lp->pci_dev, + PAGE_SIZE * FD_PAGE_NUM, + &lp->fd_buf_dma); + if (!lp->fd_buf) return -ENOMEM; for (i = 0; i < RX_BUF_NUM; i++) { #ifdef TC35815_USE_PACKEDBUFFER - if ((lp->data_buf[i] = alloc_rxbuf_page(lp->pci_dev, &lp->data_buf_dma[i])) == NULL) { + lp->data_buf[i] = + alloc_rxbuf_page(lp->pci_dev, + &lp->data_buf_dma[i]); + if (!lp->data_buf[i]) { while (--i >= 0) { free_rxbuf_page(lp->pci_dev, lp->data_buf[i], @@ -885,18 +1054,17 @@ tc35815_init_queues(struct net_device *dev) #endif printk("\n"); } else { - for (i = 0; i < FD_PAGE_NUM; i++) { - clear_page((void *)((unsigned long)lp->fd_buf + i * PAGE_SIZE)); - } + for (i = 0; i < FD_PAGE_NUM; i++) + clear_page((void *)((unsigned long)lp->fd_buf + + i * PAGE_SIZE)); } fd_addr = (unsigned long)lp->fd_buf; /* Free Descriptors (for Receive) */ lp->rfd_base = (struct RxFD *)fd_addr; fd_addr += sizeof(struct RxFD) * RX_FD_NUM; - for (i = 0; i < RX_FD_NUM; i++) { + for (i = 0; i < RX_FD_NUM; i++) lp->rfd_base[i].fd.FDCtl = cpu_to_le32(FD_CownsFD); - } lp->rfd_cur = lp->rfd_base; lp->rfd_limit = (struct RxFD *)fd_addr - (RX_FD_RESERVE + 1); @@ -964,7 +1132,7 @@ tc35815_init_queues(struct net_device *dev) static void tc35815_clear_queues(struct net_device *dev) { - struct tc35815_local *lp = dev->priv; + struct tc35815_local *lp = netdev_priv(dev); int i; for (i = 0; i < TX_FD_NUM; i++) { @@ -995,7 +1163,7 @@ tc35815_clear_queues(struct net_device *dev) static void tc35815_free_queues(struct net_device *dev) { - struct tc35815_local *lp = dev->priv; + struct tc35815_local *lp = netdev_priv(dev); int i; if (lp->tfd_base) { @@ -1076,7 +1244,7 @@ dump_rxfd(struct RxFD *fd) le32_to_cpu(fd->fd.FDStat), le32_to_cpu(fd->fd.FDCtl)); if (le32_to_cpu(fd->fd.FDCtl) & FD_CownsFD) - return 0; + return 0; printk("BD: "); for (i = 0; i < bd_count; i++) printk(" %08x %08x", @@ -1109,7 +1277,7 @@ dump_frfd(struct FrFD *fd) static void panic_queues(struct net_device *dev) { - struct tc35815_local *lp = dev->priv; + struct tc35815_local *lp = netdev_priv(dev); int i; printk("TxFD base %p, start %u, end %u\n", @@ -1128,42 +1296,30 @@ panic_queues(struct net_device *dev) } #endif -static void print_eth(char *add) +static void print_eth(const u8 *add) { - int i; - - printk("print_eth(%p)\n", add); - for (i = 0; i < 6; i++) - printk(" %2.2X", (unsigned char) add[i + 6]); - printk(" =>"); - for (i = 0; i < 6; i++) - printk(" %2.2X", (unsigned char) add[i]); - printk(" : %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]); + printk(KERN_DEBUG "print_eth(%p)\n", add); + printk(KERN_DEBUG " %pM => %pM : %02x%02x\n", + add + 6, add, add[12], add[13]); } static int tc35815_tx_full(struct net_device *dev) { - struct tc35815_local *lp = dev->priv; + struct tc35815_local *lp = netdev_priv(dev); return ((lp->tfd_start + 1) % TX_FD_NUM == lp->tfd_end); } static void tc35815_restart(struct net_device *dev) { - struct tc35815_local *lp = dev->priv; - int pid = lp->phy_addr; - int do_phy_reset = 1; - del_timer(&lp->timer); /* Kill if running */ - - if (lp->mii_id[0] == 0x0016 && (lp->mii_id[1] & 0xfc00) == 0xf800) { - /* Resetting PHY cause problem on some chip... (SEEQ 80221) */ - do_phy_reset = 0; - } - if (do_phy_reset) { + struct tc35815_local *lp = netdev_priv(dev); + + if (lp->phy_dev) { int timeout; - tc_mdio_write(dev, pid, MII_BMCR, BMCR_RESET); + + phy_write(lp->phy_dev, MII_BMCR, BMCR_RESET); timeout = 100; while (--timeout) { - if (!(tc_mdio_read(dev, pid, MII_BMCR) & BMCR_RESET)) + if (!(phy_read(lp->phy_dev, MII_BMCR) & BMCR_RESET)) break; udelay(1); } @@ -1171,16 +1327,40 @@ static void tc35815_restart(struct net_device *dev) printk(KERN_ERR "%s: BMCR reset failed.\n", dev->name); } + spin_lock_irq(&lp->lock); tc35815_chip_reset(dev); tc35815_clear_queues(dev); tc35815_chip_init(dev); /* Reconfigure CAM again since tc35815_chip_init() initialize it. */ tc35815_set_multicast_list(dev); + spin_unlock_irq(&lp->lock); + + netif_wake_queue(dev); +} + +static void tc35815_restart_work(struct work_struct *work) +{ + struct tc35815_local *lp = + container_of(work, struct tc35815_local, restart_work); + struct net_device *dev = lp->dev; + + tc35815_restart(dev); +} + +static void tc35815_schedule_restart(struct net_device *dev) +{ + struct tc35815_local *lp = netdev_priv(dev); + struct tc35815_regs __iomem *tr = + (struct tc35815_regs __iomem *)dev->base_addr; + + /* disable interrupts */ + tc_writel(0, &tr->Int_En); + tc_writel(tc_readl(&tr->DMA_Ctl) | DMA_IntMask, &tr->DMA_Ctl); + schedule_work(&lp->restart_work); } static void tc35815_tx_timeout(struct net_device *dev) { - struct tc35815_local *lp = dev->priv; struct tc35815_regs __iomem *tr = (struct tc35815_regs __iomem *)dev->base_addr; @@ -1188,28 +1368,12 @@ static void tc35815_tx_timeout(struct net_device *dev) dev->name, tc_readl(&tr->Tx_Stat)); /* Try to restart the adaptor. */ - spin_lock_irq(&lp->lock); - tc35815_restart(dev); - spin_unlock_irq(&lp->lock); - - lp->stats.tx_errors++; - - /* If we have space available to accept new transmit - * requests, wake up the queueing layer. This would - * be the case if the chipset_init() call above just - * flushes out the tx queue and empties it. - * - * If instead, the tx queue is retained then the - * netif_wake_queue() call should be placed in the - * TX completion interrupt handler of the driver instead - * of here. - */ - if (!tc35815_tx_full(dev)) - netif_wake_queue(dev); + tc35815_schedule_restart(dev); + dev->stats.tx_errors++; } /* - * Open/initialize the board. This is called (in the current kernel) + * Open/initialize the controller. This is called (in the current kernel) * sometime after booting when the 'ifconfig' program is run. * * This routine should set everything up anew at each open, even @@ -1219,17 +1383,16 @@ static void tc35815_tx_timeout(struct net_device *dev) static int tc35815_open(struct net_device *dev) { - struct tc35815_local *lp = dev->priv; + struct tc35815_local *lp = netdev_priv(dev); /* * This is used if the interrupt line can turned off (shared). * See 3c503.c for an example of selecting the IRQ at config-time. */ - if (request_irq(dev->irq, &tc35815_interrupt, IRQF_SHARED, dev->name, dev)) { + if (request_irq(dev->irq, &tc35815_interrupt, IRQF_SHARED, + dev->name, dev)) return -EAGAIN; - } - del_timer(&lp->timer); /* Kill if running */ tc35815_chip_reset(dev); if (tc35815_init_queues(dev) != 0) { @@ -1246,6 +1409,10 @@ tc35815_open(struct net_device *dev) tc35815_chip_init(dev); spin_unlock_irq(&lp->lock); + netif_carrier_off(dev); + /* schedule a link state check */ + phy_start(lp->phy_dev); + /* We are now ready to accept transmit requeusts from * the queueing layer of the networking. */ @@ -1261,7 +1428,7 @@ tc35815_open(struct net_device *dev) */ static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct tc35815_local *lp = dev->priv; + struct tc35815_local *lp = netdev_priv(dev); struct TxFD *txfd; unsigned long flags; @@ -1345,7 +1512,7 @@ static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev) */ spin_unlock_irqrestore(&lp->lock, flags); - return 0; + return NETDEV_TX_OK; } #define FATAL_ERROR_INT \ @@ -1366,7 +1533,7 @@ static void tc35815_fatal_error_interrupt(struct net_device *dev, u32 status) panic("%s: Too many fatal errors.", dev->name); printk(KERN_WARNING "%s: Resetting ...\n", dev->name); /* Try to restart the adaptor. */ - tc35815_restart(dev); + tc35815_schedule_restart(dev); } #ifdef TC35815_NAPI @@ -1375,9 +1542,7 @@ static int tc35815_do_interrupt(struct net_device *dev, u32 status, int limit) static int tc35815_do_interrupt(struct net_device *dev, u32 status) #endif { - struct tc35815_local *lp = dev->priv; - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; + struct tc35815_local *lp = netdev_priv(dev); int ret = -1; /* Fatal errors... */ @@ -1387,28 +1552,27 @@ static int tc35815_do_interrupt(struct net_device *dev, u32 status) } /* recoverable errors */ if (status & Int_IntFDAEx) { - /* disable FDAEx int. (until we make rooms...) */ - tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En); - printk(KERN_WARNING - "%s: Free Descriptor Area Exhausted (%#x).\n", - dev->name, status); - lp->stats.rx_dropped++; + if (netif_msg_rx_err(lp)) + dev_warn(&dev->dev, + "Free Descriptor Area Exhausted (%#x).\n", + status); + dev->stats.rx_dropped++; ret = 0; } if (status & Int_IntBLEx) { - /* disable BLEx int. (until we make rooms...) */ - tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En); - printk(KERN_WARNING - "%s: Buffer List Exhausted (%#x).\n", - dev->name, status); - lp->stats.rx_dropped++; + if (netif_msg_rx_err(lp)) + dev_warn(&dev->dev, + "Buffer List Exhausted (%#x).\n", + status); + dev->stats.rx_dropped++; ret = 0; } if (status & Int_IntExBD) { - printk(KERN_WARNING - "%s: Excessive Buffer Descriptiors (%#x).\n", - dev->name, status); - lp->stats.rx_length_errors++; + if (netif_msg_rx_err(lp)) + dev_warn(&dev->dev, + "Excessive Buffer Descriptiors (%#x).\n", + status); + dev->stats.rx_length_errors++; ret = 0; } @@ -1449,8 +1613,8 @@ static irqreturn_t tc35815_interrupt(int irq, void *dev_id) if (!(dmactl & DMA_IntMask)) { /* disable interrupts */ tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl); - if (netif_rx_schedule_prep(dev, &lp->napi)) - __netif_rx_schedule(dev, &lp->napi); + if (napi_schedule_prep(&lp->napi)) + __napi_schedule(&lp->napi); else { printk(KERN_ERR "%s: interrupt taken in poll\n", dev->name); @@ -1461,14 +1625,17 @@ static irqreturn_t tc35815_interrupt(int irq, void *dev_id) } return IRQ_NONE; #else - struct tc35815_local *lp = dev->priv; int handled; u32 status; spin_lock(&lp->lock); status = tc_readl(&tr->Int_Src); - tc_writel(status, &tr->Int_Src); /* write to clear */ + /* BLEx, FDAEx will be cleared later */ + tc_writel(status & ~(Int_BLEx | Int_FDAEx), + &tr->Int_Src); /* write to clear */ handled = tc35815_do_interrupt(dev, status); + if (status & (Int_BLEx | Int_FDAEx)) + tc_writel(status & (Int_BLEx | Int_FDAEx), &tr->Int_Src); (void)tc_readl(&tr->Int_Src); /* flush */ spin_unlock(&lp->lock); return IRQ_RETVAL(handled >= 0); @@ -1493,11 +1660,9 @@ static void tc35815_rx(struct net_device *dev) #endif { - struct tc35815_local *lp = dev->priv; + struct tc35815_local *lp = netdev_priv(dev); unsigned int fdctl; int i; - int buf_free_count = 0; - int fd_free_count = 0; #ifdef TC35815_NAPI int received = 0; #endif @@ -1510,7 +1675,7 @@ tc35815_rx(struct net_device *dev) struct RxFD *next_rfd; #endif #if (RX_CTL_CMD & Rx_StripCRC) == 0 - pkt_len -= 4; + pkt_len -= ETH_FCS_LEN; #endif if (netif_msg_rx_status(lp)) @@ -1529,14 +1694,14 @@ tc35815_rx(struct net_device *dev) #endif #ifdef TC35815_USE_PACKEDBUFFER BUG_ON(bd_count > 2); - skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */ + skb = dev_alloc_skb(pkt_len + NET_IP_ALIGN); if (skb == NULL) { printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); - lp->stats.rx_dropped++; + dev->stats.rx_dropped++; break; } - skb_reserve(skb, 2); /* 16 bit alignment */ + skb_reserve(skb, NET_IP_ALIGN); data = skb_put(skb, pkt_len); @@ -1585,12 +1750,12 @@ tc35815_rx(struct net_device *dev) skb = lp->rx_skbs[cur_bd].skb; prefetch(skb->data); lp->rx_skbs[cur_bd].skb = NULL; - lp->fbl_count--; pci_unmap_single(lp->pci_dev, lp->rx_skbs[cur_bd].skb_dma, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); - if (!HAVE_DMA_RXALIGN(lp)) - memmove(skb->data, skb->data - 2, pkt_len); + if (!HAVE_DMA_RXALIGN(lp) && NET_IP_ALIGN) + memmove(skb->data, skb->data - NET_IP_ALIGN, + pkt_len); data = skb_put(skb, pkt_len); #endif /* TC35815_USE_PACKEDBUFFER */ if (netif_msg_pktdata(lp)) @@ -1602,22 +1767,26 @@ tc35815_rx(struct net_device *dev) #else netif_rx(skb); #endif - dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; } else { - lp->stats.rx_errors++; - printk(KERN_DEBUG "%s: Rx error (status %x)\n", - dev->name, status & Rx_Stat_Mask); + dev->stats.rx_errors++; + if (netif_msg_rx_err(lp)) + dev_info(&dev->dev, "Rx error (status %x)\n", + status & Rx_Stat_Mask); /* WORKAROUND: LongErr and CRCErr means Overflow. */ if ((status & Rx_LongErr) && (status & Rx_CRCErr)) { status &= ~(Rx_LongErr|Rx_CRCErr); status |= Rx_Over; } - if (status & Rx_LongErr) lp->stats.rx_length_errors++; - if (status & Rx_Over) lp->stats.rx_fifo_errors++; - if (status & Rx_CRCErr) lp->stats.rx_crc_errors++; - if (status & Rx_Align) lp->stats.rx_frame_errors++; + if (status & Rx_LongErr) + dev->stats.rx_length_errors++; + if (status & Rx_Over) + dev->stats.rx_fifo_errors++; + if (status & Rx_CRCErr) + dev->stats.rx_crc_errors++; + if (status & Rx_Align) + dev->stats.rx_frame_errors++; } if (bd_count > 0) { @@ -1637,6 +1806,7 @@ tc35815_rx(struct net_device *dev) #ifdef TC35815_USE_PACKEDBUFFER while (lp->fbl_curid != id) #else + lp->fbl_count--; while (lp->fbl_count < RX_BUF_NUM) #endif { @@ -1655,7 +1825,7 @@ tc35815_rx(struct net_device *dev) panic_queues(dev); } #endif - /* pass BD to controler */ + /* pass BD to controller */ #ifndef TC35815_USE_PACKEDBUFFER if (!lp->rx_skbs[curid].skb) { lp->rx_skbs[curid].skb = @@ -1681,7 +1851,6 @@ tc35815_rx(struct net_device *dev) #else lp->fbl_count++; #endif - buf_free_count++; } } @@ -1695,7 +1864,7 @@ tc35815_rx(struct net_device *dev) } #endif for (i = 0; i < (bd_count + 1) / 2 + 1; i++) { - /* pass FD to controler */ + /* pass FD to controller */ #ifdef DEBUG lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead); #else @@ -1703,7 +1872,6 @@ tc35815_rx(struct net_device *dev) #endif lp->rfd_cur->fd.FDCtl = cpu_to_le32(FD_CownsFD); lp->rfd_cur++; - fd_free_count++; } if (lp->rfd_cur > lp->rfd_limit) lp->rfd_cur = lp->rfd_base; @@ -1714,17 +1882,6 @@ tc35815_rx(struct net_device *dev) #endif } - /* re-enable BL/FDA Exhaust interrupts. */ - if (fd_free_count) { - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; - u32 en, en_old = tc_readl(&tr->Int_En); - en = en_old | Int_FDAExEn; - if (buf_free_count) - en |= Int_BLExEn; - if (en != en_old) - tc_writel(en, &tr->Int_En); - } #ifdef TC35815_NAPI return received; #endif @@ -1743,9 +1900,14 @@ static int tc35815_poll(struct napi_struct *napi, int budget) spin_lock(&lp->lock); status = tc_readl(&tr->Int_Src); do { - tc_writel(status, &tr->Int_Src); /* write to clear */ - - handled = tc35815_do_interrupt(dev, status, limit); + /* BLEx, FDAEx will be cleared later */ + tc_writel(status & ~(Int_BLEx | Int_FDAEx), + &tr->Int_Src); /* write to clear */ + + handled = tc35815_do_interrupt(dev, status, budget - received); + if (status & (Int_BLEx | Int_FDAEx)) + tc_writel(status & (Int_BLEx | Int_FDAEx), + &tr->Int_Src); if (handled >= 0) { received += handled; if (received >= budget) @@ -1756,7 +1918,7 @@ static int tc35815_poll(struct napi_struct *napi, int budget) spin_unlock(&lp->lock); if (received < budget) { - netif_rx_complete(dev, napi); + napi_complete(napi); /* enable interrupts */ tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl); } @@ -1773,40 +1935,39 @@ static int tc35815_poll(struct napi_struct *napi, int budget) static void tc35815_check_tx_stat(struct net_device *dev, int status) { - struct tc35815_local *lp = dev->priv; + struct tc35815_local *lp = netdev_priv(dev); const char *msg = NULL; /* count collisions */ if (status & Tx_ExColl) - lp->stats.collisions += 16; + dev->stats.collisions += 16; if (status & Tx_TxColl_MASK) - lp->stats.collisions += status & Tx_TxColl_MASK; + dev->stats.collisions += status & Tx_TxColl_MASK; #ifndef NO_CHECK_CARRIER /* TX4939 does not have NCarr */ - if (lp->boardtype == TC35815_TX4939) + if (lp->chiptype == TC35815_TX4939) status &= ~Tx_NCarr; #ifdef WORKAROUND_LOSTCAR /* WORKAROUND: ignore LostCrS in full duplex operation */ - if ((lp->timer_state != asleep && lp->timer_state != lcheck) - || lp->fullduplex) + if (!lp->link || lp->duplex == DUPLEX_FULL) status &= ~Tx_NCarr; #endif #endif if (!(status & TX_STA_ERR)) { /* no error. */ - lp->stats.tx_packets++; + dev->stats.tx_packets++; return; } - lp->stats.tx_errors++; + dev->stats.tx_errors++; if (status & Tx_ExColl) { - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; msg = "Excessive Collision."; } if (status & Tx_Under) { - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; msg = "Tx FIFO Underrun."; if (lp->lstats.tx_underrun < TX_THRESHOLD_KEEP_LIMIT) { lp->lstats.tx_underrun++; @@ -1819,25 +1980,25 @@ tc35815_check_tx_stat(struct net_device *dev, int status) } } if (status & Tx_Defer) { - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; msg = "Excessive Deferral."; } #ifndef NO_CHECK_CARRIER if (status & Tx_NCarr) { - lp->stats.tx_carrier_errors++; + dev->stats.tx_carrier_errors++; msg = "Lost Carrier Sense."; } #endif if (status & Tx_LateColl) { - lp->stats.tx_aborted_errors++; + dev->stats.tx_aborted_errors++; msg = "Late Collision."; } if (status & Tx_TxPar) { - lp->stats.tx_fifo_errors++; + dev->stats.tx_fifo_errors++; msg = "Transmit Parity Error."; } if (status & Tx_SQErr) { - lp->stats.tx_heartbeat_errors++; + dev->stats.tx_heartbeat_errors++; msg = "Signal Quality Error."; } if (msg && netif_msg_tx_err(lp)) @@ -1850,7 +2011,7 @@ tc35815_check_tx_stat(struct net_device *dev, int status) static void tc35815_txdone(struct net_device *dev) { - struct tc35815_local *lp = dev->priv; + struct tc35815_local *lp = netdev_priv(dev); struct TxFD *txfd; unsigned int fdctl; @@ -1879,7 +2040,7 @@ tc35815_txdone(struct net_device *dev) BUG_ON(lp->tx_skbs[lp->tfd_end].skb != skb); #endif if (skb) { - lp->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; pci_unmap_single(lp->pci_dev, lp->tx_skbs[lp->tfd_end].skb_dma, skb->len, PCI_DMA_TODEVICE); lp->tx_skbs[lp->tfd_end].skb = NULL; lp->tx_skbs[lp->tfd_end].skb_dma = 0; @@ -1905,7 +2066,7 @@ tc35815_txdone(struct net_device *dev) struct tc35815_regs __iomem *tr = (struct tc35815_regs __iomem *)dev->base_addr; int head = (lp->tfd_start + TX_FD_NUM - 1) % TX_FD_NUM; - struct TxFD* txhead = &lp->tfd_base[head]; + struct TxFD *txhead = &lp->tfd_base[head]; int qlen = (lp->tfd_start + TX_FD_NUM - lp->tfd_end) % TX_FD_NUM; @@ -1940,7 +2101,7 @@ tc35815_txdone(struct net_device *dev) * condition, and space has now been made available, * wake up the queue. */ - if (netif_queue_stopped(dev) && ! tc35815_tx_full(dev)) + if (netif_queue_stopped(dev) && !tc35815_tx_full(dev)) netif_wake_queue(dev); } @@ -1948,16 +2109,17 @@ tc35815_txdone(struct net_device *dev) static int tc35815_close(struct net_device *dev) { - struct tc35815_local *lp = dev->priv; + struct tc35815_local *lp = netdev_priv(dev); netif_stop_queue(dev); #ifdef TC35815_NAPI napi_disable(&lp->napi); #endif + if (lp->phy_dev) + phy_stop(lp->phy_dev); + cancel_work_sync(&lp->restart_work); /* Flush the Tx and disable Rx here. */ - - del_timer(&lp->timer); /* Kill if running */ tc35815_chip_reset(dev); free_irq(dev->irq, dev); @@ -1973,34 +2135,29 @@ tc35815_close(struct net_device *dev) */ static struct net_device_stats *tc35815_get_stats(struct net_device *dev) { - struct tc35815_local *lp = dev->priv; struct tc35815_regs __iomem *tr = (struct tc35815_regs __iomem *)dev->base_addr; - if (netif_running(dev)) { + if (netif_running(dev)) /* Update the statistics from the device registers. */ - lp->stats.rx_missed_errors = tc_readl(&tr->Miss_Cnt); - } + dev->stats.rx_missed_errors += tc_readl(&tr->Miss_Cnt); - return &lp->stats; + return &dev->stats; } static void tc35815_set_cam_entry(struct net_device *dev, int index, unsigned char *addr) { - struct tc35815_local *lp = dev->priv; + struct tc35815_local *lp = netdev_priv(dev); struct tc35815_regs __iomem *tr = (struct tc35815_regs __iomem *)dev->base_addr; int cam_index = index * 6; u32 cam_data; u32 saved_addr; + saved_addr = tc_readl(&tr->CAM_Adr); - if (netif_msg_hw(lp)) { - int i; - printk(KERN_DEBUG "%s: CAM %d:", dev->name, index); - for (i = 0; i < 6; i++) - printk(" %02x", addr[i]); - printk("\n"); - } + if (netif_msg_hw(lp)) + printk(KERN_DEBUG "%s: CAM %d: %pM\n", + dev->name, index, addr); if (index & 1) { /* read modify write */ tc_writel(cam_index - 2, &tr->CAM_Adr); @@ -2040,28 +2197,24 @@ tc35815_set_multicast_list(struct net_device *dev) struct tc35815_regs __iomem *tr = (struct tc35815_regs __iomem *)dev->base_addr; - if (dev->flags&IFF_PROMISC) - { + if (dev->flags & IFF_PROMISC) { #ifdef WORKAROUND_100HALF_PROMISC /* With some (all?) 100MHalf HUB, controller will hang * if we enabled promiscuous mode before linkup... */ - struct tc35815_local *lp = dev->priv; - int pid = lp->phy_addr; - if (!(tc_mdio_read(dev, pid, MII_BMSR) & BMSR_LSTATUS)) + struct tc35815_local *lp = netdev_priv(dev); + + if (!lp->link) return; #endif /* Enable promiscuous mode */ tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl); - } - else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > CAM_ENTRY_MAX - 3) - { + } else if ((dev->flags & IFF_ALLMULTI) || + dev->mc_count > CAM_ENTRY_MAX - 3) { /* CAM 0, 1, 20 are reserved. */ /* Disable promiscuous mode, use normal mode. */ tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc, &tr->CAM_Ctl); - } - else if(dev->mc_count) - { - struct dev_mc_list* cur_addr = dev->mc_list; + } else if (dev->mc_count) { + struct dev_mc_list *cur_addr = dev->mc_list; int i; int ena_bits = CAM_Ena_Bit(CAM_ENTRY_SOURCE); @@ -2076,8 +2229,7 @@ tc35815_set_multicast_list(struct net_device *dev) } tc_writel(ena_bits, &tr->CAM_Ena); tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl); - } - else { + } else { tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena); tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl); } @@ -2085,7 +2237,7 @@ tc35815_set_multicast_list(struct net_device *dev) static void tc35815_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct tc35815_local *lp = dev->priv; + struct tc35815_local *lp = netdev_priv(dev); strcpy(info->driver, MODNAME); strcpy(info->version, DRV_VERSION); strcpy(info->bus_info, pci_name(lp->pci_dev)); @@ -2093,84 +2245,49 @@ static void tc35815_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo * static int tc35815_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct tc35815_local *lp = dev->priv; - spin_lock_irq(&lp->lock); - mii_ethtool_gset(&lp->mii, cmd); - spin_unlock_irq(&lp->lock); - return 0; -} - -static int tc35815_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct tc35815_local *lp = dev->priv; - int rc; -#if 1 /* use our negotiation method... */ - /* Verify the settings we care about. */ - if (cmd->autoneg != AUTONEG_ENABLE && - cmd->autoneg != AUTONEG_DISABLE) - return -EINVAL; - if (cmd->autoneg == AUTONEG_DISABLE && - ((cmd->speed != SPEED_100 && - cmd->speed != SPEED_10) || - (cmd->duplex != DUPLEX_HALF && - cmd->duplex != DUPLEX_FULL))) - return -EINVAL; + struct tc35815_local *lp = netdev_priv(dev); - /* Ok, do it to it. */ - spin_lock_irq(&lp->lock); - del_timer(&lp->timer); - tc35815_start_auto_negotiation(dev, cmd); - spin_unlock_irq(&lp->lock); - rc = 0; -#else - spin_lock_irq(&lp->lock); - rc = mii_ethtool_sset(&lp->mii, cmd); - spin_unlock_irq(&lp->lock); -#endif - return rc; + if (!lp->phy_dev) + return -ENODEV; + return phy_ethtool_gset(lp->phy_dev, cmd); } -static int tc35815_nway_reset(struct net_device *dev) +static int tc35815_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct tc35815_local *lp = dev->priv; - int rc; - spin_lock_irq(&lp->lock); - rc = mii_nway_restart(&lp->mii); - spin_unlock_irq(&lp->lock); - return rc; -} + struct tc35815_local *lp = netdev_priv(dev); -static u32 tc35815_get_link(struct net_device *dev) -{ - struct tc35815_local *lp = dev->priv; - int rc; - spin_lock_irq(&lp->lock); - rc = mii_link_ok(&lp->mii); - spin_unlock_irq(&lp->lock); - return rc; + if (!lp->phy_dev) + return -ENODEV; + return phy_ethtool_sset(lp->phy_dev, cmd); } static u32 tc35815_get_msglevel(struct net_device *dev) { - struct tc35815_local *lp = dev->priv; + struct tc35815_local *lp = netdev_priv(dev); return lp->msg_enable; } static void tc35815_set_msglevel(struct net_device *dev, u32 datum) { - struct tc35815_local *lp = dev->priv; + struct tc35815_local *lp = netdev_priv(dev); lp->msg_enable = datum; } -static int tc35815_get_stats_count(struct net_device *dev) +static int tc35815_get_sset_count(struct net_device *dev, int sset) { - struct tc35815_local *lp = dev->priv; - return sizeof(lp->lstats) / sizeof(int); + struct tc35815_local *lp = netdev_priv(dev); + + switch (sset) { + case ETH_SS_STATS: + return sizeof(lp->lstats) / sizeof(int); + default: + return -EOPNOTSUPP; + } } static void tc35815_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { - struct tc35815_local *lp = dev->priv; + struct tc35815_local *lp = netdev_priv(dev); data[0] = lp->lstats.max_tx_qlen; data[1] = lp->lstats.tx_ints; data[2] = lp->lstats.rx_ints; @@ -2195,622 +2312,23 @@ static const struct ethtool_ops tc35815_ethtool_ops = { .get_drvinfo = tc35815_get_drvinfo, .get_settings = tc35815_get_settings, .set_settings = tc35815_set_settings, - .nway_reset = tc35815_nway_reset, - .get_link = tc35815_get_link, + .get_link = ethtool_op_get_link, .get_msglevel = tc35815_get_msglevel, .set_msglevel = tc35815_set_msglevel, .get_strings = tc35815_get_strings, - .get_stats_count = tc35815_get_stats_count, + .get_sset_count = tc35815_get_sset_count, .get_ethtool_stats = tc35815_get_ethtool_stats, }; static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct tc35815_local *lp = dev->priv; - int rc; + struct tc35815_local *lp = netdev_priv(dev); if (!netif_running(dev)) return -EINVAL; - - spin_lock_irq(&lp->lock); - rc = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL); - spin_unlock_irq(&lp->lock); - - return rc; -} - -static int tc_mdio_read(struct net_device *dev, int phy_id, int location) -{ - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; - u32 data; - tc_writel(MD_CA_Busy | (phy_id << 5) | location, &tr->MD_CA); - while (tc_readl(&tr->MD_CA) & MD_CA_Busy) - ; - data = tc_readl(&tr->MD_Data); - return data & 0xffff; -} - -static void tc_mdio_write(struct net_device *dev, int phy_id, int location, - int val) -{ - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; - tc_writel(val, &tr->MD_Data); - tc_writel(MD_CA_Busy | MD_CA_Wr | (phy_id << 5) | location, &tr->MD_CA); - while (tc_readl(&tr->MD_CA) & MD_CA_Busy) - ; -} - -/* Auto negotiation. The scheme is very simple. We have a timer routine - * that keeps watching the auto negotiation process as it progresses. - * The DP83840 is first told to start doing it's thing, we set up the time - * and place the timer state machine in it's initial state. - * - * Here the timer peeks at the DP83840 status registers at each click to see - * if the auto negotiation has completed, we assume here that the DP83840 PHY - * will time out at some point and just tell us what (didn't) happen. For - * complete coverage we only allow so many of the ticks at this level to run, - * when this has expired we print a warning message and try another strategy. - * This "other" strategy is to force the interface into various speed/duplex - * configurations and we stop when we see a link-up condition before the - * maximum number of "peek" ticks have occurred. - * - * Once a valid link status has been detected we configure the BigMAC and - * the rest of the Happy Meal to speak the most efficient protocol we could - * get a clean link for. The priority for link configurations, highest first - * is: - * 100 Base-T Full Duplex - * 100 Base-T Half Duplex - * 10 Base-T Full Duplex - * 10 Base-T Half Duplex - * - * We start a new timer now, after a successful auto negotiation status has - * been detected. This timer just waits for the link-up bit to get set in - * the BMCR of the DP83840. When this occurs we print a kernel log message - * describing the link type in use and the fact that it is up. - * - * If a fatal error of some sort is signalled and detected in the interrupt - * service routine, and the chip is reset, or the link is ifconfig'd down - * and then back up, this entire process repeats itself all over again. - */ -/* Note: Above comments are come from sunhme driver. */ - -static int tc35815_try_next_permutation(struct net_device *dev) -{ - struct tc35815_local *lp = dev->priv; - int pid = lp->phy_addr; - unsigned short bmcr; - - bmcr = tc_mdio_read(dev, pid, MII_BMCR); - - /* Downgrade from full to half duplex. Only possible via ethtool. */ - if (bmcr & BMCR_FULLDPLX) { - bmcr &= ~BMCR_FULLDPLX; - printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr); - tc_mdio_write(dev, pid, MII_BMCR, bmcr); - return 0; - } - - /* Downgrade from 100 to 10. */ - if (bmcr & BMCR_SPEED100) { - bmcr &= ~BMCR_SPEED100; - printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr); - tc_mdio_write(dev, pid, MII_BMCR, bmcr); - return 0; - } - - /* We've tried everything. */ - return -1; -} - -static void -tc35815_display_link_mode(struct net_device *dev) -{ - struct tc35815_local *lp = dev->priv; - int pid = lp->phy_addr; - unsigned short lpa, bmcr; - char *speed = "", *duplex = ""; - - lpa = tc_mdio_read(dev, pid, MII_LPA); - bmcr = tc_mdio_read(dev, pid, MII_BMCR); - if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL))) - speed = "100Mb/s"; - else - speed = "10Mb/s"; - if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL))) - duplex = "Full Duplex"; - else - duplex = "Half Duplex"; - - if (netif_msg_link(lp)) - printk(KERN_INFO "%s: Link is up at %s, %s.\n", - dev->name, speed, duplex); - printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n", - dev->name, - bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa); -} - -static void tc35815_display_forced_link_mode(struct net_device *dev) -{ - struct tc35815_local *lp = dev->priv; - int pid = lp->phy_addr; - unsigned short bmcr; - char *speed = "", *duplex = ""; - - bmcr = tc_mdio_read(dev, pid, MII_BMCR); - if (bmcr & BMCR_SPEED100) - speed = "100Mb/s"; - else - speed = "10Mb/s"; - if (bmcr & BMCR_FULLDPLX) - duplex = "Full Duplex.\n"; - else - duplex = "Half Duplex.\n"; - - if (netif_msg_link(lp)) - printk(KERN_INFO "%s: Link has been forced up at %s, %s", - dev->name, speed, duplex); -} - -static void tc35815_set_link_modes(struct net_device *dev) -{ - struct tc35815_local *lp = dev->priv; - struct tc35815_regs __iomem *tr = - (struct tc35815_regs __iomem *)dev->base_addr; - int pid = lp->phy_addr; - unsigned short bmcr, lpa; - int speed; - - if (lp->timer_state == arbwait) { - lpa = tc_mdio_read(dev, pid, MII_LPA); - bmcr = tc_mdio_read(dev, pid, MII_BMCR); - printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n", - dev->name, - bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa); - if (!(lpa & (LPA_10HALF | LPA_10FULL | - LPA_100HALF | LPA_100FULL))) { - /* fall back to 10HALF */ - printk(KERN_INFO "%s: bad ability %04x - falling back to 10HD.\n", - dev->name, lpa); - lpa = LPA_10HALF; - } - if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL))) - lp->fullduplex = 1; - else - lp->fullduplex = 0; - if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL))) - speed = 100; - else - speed = 10; - } else { - /* Forcing a link mode. */ - bmcr = tc_mdio_read(dev, pid, MII_BMCR); - if (bmcr & BMCR_FULLDPLX) - lp->fullduplex = 1; - else - lp->fullduplex = 0; - if (bmcr & BMCR_SPEED100) - speed = 100; - else - speed = 10; - } - - tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_HaltReq, &tr->MAC_Ctl); - if (lp->fullduplex) { - tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl); - } else { - tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_FullDup, &tr->MAC_Ctl); - } - tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_HaltReq, &tr->MAC_Ctl); - - /* TX4939 PCFG.SPEEDn bit will be changed on NETDEV_CHANGE event. */ - -#ifndef NO_CHECK_CARRIER - /* TX4939 does not have EnLCarr */ - if (lp->boardtype != TC35815_TX4939) { -#ifdef WORKAROUND_LOSTCAR - /* WORKAROUND: enable LostCrS only if half duplex operation */ - if (!lp->fullduplex && lp->boardtype != TC35815_TX4939) - tc_writel(tc_readl(&tr->Tx_Ctl) | Tx_EnLCarr, &tr->Tx_Ctl); -#endif - } -#endif - lp->mii.full_duplex = lp->fullduplex; -} - -static void tc35815_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct tc35815_local *lp = dev->priv; - int pid = lp->phy_addr; - unsigned short bmsr, bmcr, lpa; - int restart_timer = 0; - - spin_lock_irq(&lp->lock); - - lp->timer_ticks++; - switch (lp->timer_state) { - case arbwait: - /* - * Only allow for 5 ticks, thats 10 seconds and much too - * long to wait for arbitration to complete. - */ - /* TC35815 need more times... */ - if (lp->timer_ticks >= 10) { - /* Enter force mode. */ - if (!options.doforce) { - printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful," - " cable probblem?\n", dev->name); - /* Try to restart the adaptor. */ - tc35815_restart(dev); - goto out; - } - printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful," - " trying force link mode\n", dev->name); - printk(KERN_DEBUG "%s: BMCR %x BMSR %x\n", dev->name, - tc_mdio_read(dev, pid, MII_BMCR), - tc_mdio_read(dev, pid, MII_BMSR)); - bmcr = BMCR_SPEED100; - tc_mdio_write(dev, pid, MII_BMCR, bmcr); - - /* - * OK, seems we need do disable the transceiver - * for the first tick to make sure we get an - * accurate link state at the second tick. - */ - - lp->timer_state = ltrywait; - lp->timer_ticks = 0; - restart_timer = 1; - } else { - /* Anything interesting happen? */ - bmsr = tc_mdio_read(dev, pid, MII_BMSR); - if (bmsr & BMSR_ANEGCOMPLETE) { - /* Just what we've been waiting for... */ - tc35815_set_link_modes(dev); - - /* - * Success, at least so far, advance our state - * engine. - */ - lp->timer_state = lupwait; - restart_timer = 1; - } else { - restart_timer = 1; - } - } - break; - - case lupwait: - /* - * Auto negotiation was successful and we are awaiting a - * link up status. I have decided to let this timer run - * forever until some sort of error is signalled, reporting - * a message to the user at 10 second intervals. - */ - bmsr = tc_mdio_read(dev, pid, MII_BMSR); - if (bmsr & BMSR_LSTATUS) { - /* - * Wheee, it's up, display the link mode in use and put - * the timer to sleep. - */ - tc35815_display_link_mode(dev); - netif_carrier_on(dev); -#ifdef WORKAROUND_100HALF_PROMISC - /* delayed promiscuous enabling */ - if (dev->flags & IFF_PROMISC) - tc35815_set_multicast_list(dev); -#endif -#if 1 - lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA); - lp->timer_state = lcheck; - restart_timer = 1; -#else - lp->timer_state = asleep; - restart_timer = 0; -#endif - } else { - if (lp->timer_ticks >= 10) { - printk(KERN_NOTICE "%s: Auto negotiation successful, link still " - "not completely up.\n", dev->name); - lp->timer_ticks = 0; - restart_timer = 1; - } else { - restart_timer = 1; - } - } - break; - - case ltrywait: - /* - * Making the timeout here too long can make it take - * annoyingly long to attempt all of the link mode - * permutations, but then again this is essentially - * error recovery code for the most part. - */ - bmsr = tc_mdio_read(dev, pid, MII_BMSR); - bmcr = tc_mdio_read(dev, pid, MII_BMCR); - if (lp->timer_ticks == 1) { - /* - * Re-enable transceiver, we'll re-enable the - * transceiver next tick, then check link state - * on the following tick. - */ - restart_timer = 1; - break; - } - if (lp->timer_ticks == 2) { - restart_timer = 1; - break; - } - if (bmsr & BMSR_LSTATUS) { - /* Force mode selection success. */ - tc35815_display_forced_link_mode(dev); - netif_carrier_on(dev); - tc35815_set_link_modes(dev); -#ifdef WORKAROUND_100HALF_PROMISC - /* delayed promiscuous enabling */ - if (dev->flags & IFF_PROMISC) - tc35815_set_multicast_list(dev); -#endif -#if 1 - lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA); - lp->timer_state = lcheck; - restart_timer = 1; -#else - lp->timer_state = asleep; - restart_timer = 0; -#endif - } else { - if (lp->timer_ticks >= 4) { /* 6 seconds or so... */ - int ret; - - ret = tc35815_try_next_permutation(dev); - if (ret == -1) { - /* - * Aieee, tried them all, reset the - * chip and try all over again. - */ - printk(KERN_NOTICE "%s: Link down, " - "cable problem?\n", - dev->name); - - /* Try to restart the adaptor. */ - tc35815_restart(dev); - goto out; - } - lp->timer_ticks = 0; - restart_timer = 1; - } else { - restart_timer = 1; - } - } - break; - - case lcheck: - bmcr = tc_mdio_read(dev, pid, MII_BMCR); - lpa = tc_mdio_read(dev, pid, MII_LPA); - if (bmcr & (BMCR_PDOWN | BMCR_ISOLATE | BMCR_RESET)) { - printk(KERN_ERR "%s: PHY down? (BMCR %x)\n", dev->name, - bmcr); - } else if ((lp->saved_lpa ^ lpa) & - (LPA_100FULL|LPA_100HALF|LPA_10FULL|LPA_10HALF)) { - printk(KERN_NOTICE "%s: link status changed" - " (BMCR %x LPA %x->%x)\n", dev->name, - bmcr, lp->saved_lpa, lpa); - } else { - /* go on */ - restart_timer = 1; - break; - } - /* Try to restart the adaptor. */ - tc35815_restart(dev); - goto out; - - case asleep: - default: - /* Can't happens.... */ - printk(KERN_ERR "%s: Aieee, link timer is asleep but we got " - "one anyways!\n", dev->name); - restart_timer = 0; - lp->timer_ticks = 0; - lp->timer_state = asleep; /* foo on you */ - break; - } - - if (restart_timer) { - lp->timer.expires = jiffies + msecs_to_jiffies(1200); - add_timer(&lp->timer); - } -out: - spin_unlock_irq(&lp->lock); -} - -static void tc35815_start_auto_negotiation(struct net_device *dev, - struct ethtool_cmd *ep) -{ - struct tc35815_local *lp = dev->priv; - int pid = lp->phy_addr; - unsigned short bmsr, bmcr, advertize; - int timeout; - - netif_carrier_off(dev); - bmsr = tc_mdio_read(dev, pid, MII_BMSR); - bmcr = tc_mdio_read(dev, pid, MII_BMCR); - advertize = tc_mdio_read(dev, pid, MII_ADVERTISE); - - if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) { - if (options.speed || options.duplex) { - /* Advertise only specified configuration. */ - advertize &= ~(ADVERTISE_10HALF | - ADVERTISE_10FULL | - ADVERTISE_100HALF | - ADVERTISE_100FULL); - if (options.speed != 10) { - if (options.duplex != 1) - advertize |= ADVERTISE_100FULL; - if (options.duplex != 2) - advertize |= ADVERTISE_100HALF; - } - if (options.speed != 100) { - if (options.duplex != 1) - advertize |= ADVERTISE_10FULL; - if (options.duplex != 2) - advertize |= ADVERTISE_10HALF; - } - if (options.speed == 100) - bmcr |= BMCR_SPEED100; - else if (options.speed == 10) - bmcr &= ~BMCR_SPEED100; - if (options.duplex == 2) - bmcr |= BMCR_FULLDPLX; - else if (options.duplex == 1) - bmcr &= ~BMCR_FULLDPLX; - } else { - /* Advertise everything we can support. */ - if (bmsr & BMSR_10HALF) - advertize |= ADVERTISE_10HALF; - else - advertize &= ~ADVERTISE_10HALF; - if (bmsr & BMSR_10FULL) - advertize |= ADVERTISE_10FULL; - else - advertize &= ~ADVERTISE_10FULL; - if (bmsr & BMSR_100HALF) - advertize |= ADVERTISE_100HALF; - else - advertize &= ~ADVERTISE_100HALF; - if (bmsr & BMSR_100FULL) - advertize |= ADVERTISE_100FULL; - else - advertize &= ~ADVERTISE_100FULL; - } - - tc_mdio_write(dev, pid, MII_ADVERTISE, advertize); - - /* Enable Auto-Negotiation, this is usually on already... */ - bmcr |= BMCR_ANENABLE; - tc_mdio_write(dev, pid, MII_BMCR, bmcr); - - /* Restart it to make sure it is going. */ - bmcr |= BMCR_ANRESTART; - tc_mdio_write(dev, pid, MII_BMCR, bmcr); - printk(KERN_DEBUG "%s: ADVERTISE %x BMCR %x\n", dev->name, advertize, bmcr); - - /* BMCR_ANRESTART self clears when the process has begun. */ - timeout = 64; /* More than enough. */ - while (--timeout) { - bmcr = tc_mdio_read(dev, pid, MII_BMCR); - if (!(bmcr & BMCR_ANRESTART)) - break; /* got it. */ - udelay(10); - } - if (!timeout) { - printk(KERN_ERR "%s: TC35815 would not start auto " - "negotiation BMCR=0x%04x\n", - dev->name, bmcr); - printk(KERN_NOTICE "%s: Performing force link " - "detection.\n", dev->name); - goto force_link; - } else { - printk(KERN_DEBUG "%s: auto negotiation started.\n", dev->name); - lp->timer_state = arbwait; - } - } else { -force_link: - /* Force the link up, trying first a particular mode. - * Either we are here at the request of ethtool or - * because the Happy Meal would not start to autoneg. - */ - - /* Disable auto-negotiation in BMCR, enable the duplex and - * speed setting, init the timer state machine, and fire it off. - */ - if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) { - bmcr = BMCR_SPEED100; - } else { - if (ep->speed == SPEED_100) - bmcr = BMCR_SPEED100; - else - bmcr = 0; - if (ep->duplex == DUPLEX_FULL) - bmcr |= BMCR_FULLDPLX; - } - tc_mdio_write(dev, pid, MII_BMCR, bmcr); - - /* OK, seems we need do disable the transceiver for the first - * tick to make sure we get an accurate link state at the - * second tick. - */ - lp->timer_state = ltrywait; - } - - del_timer(&lp->timer); - lp->timer_ticks = 0; - lp->timer.expires = jiffies + msecs_to_jiffies(1200); - add_timer(&lp->timer); -} - -static void tc35815_find_phy(struct net_device *dev) -{ - struct tc35815_local *lp = dev->priv; - int pid = lp->phy_addr; - unsigned short id0; - - /* find MII phy */ - for (pid = 31; pid >= 0; pid--) { - id0 = tc_mdio_read(dev, pid, MII_BMSR); - if (id0 != 0xffff && id0 != 0x0000 && - (id0 & BMSR_RESV) != (0xffff & BMSR_RESV) /* paranoia? */ - ) { - lp->phy_addr = pid; - break; - } - } - if (pid < 0) { - printk(KERN_ERR "%s: No MII Phy found.\n", - dev->name); - lp->phy_addr = pid = 0; - } - - lp->mii_id[0] = tc_mdio_read(dev, pid, MII_PHYSID1); - lp->mii_id[1] = tc_mdio_read(dev, pid, MII_PHYSID2); - if (netif_msg_hw(lp)) - printk(KERN_INFO "%s: PHY(%02x) ID %04x %04x\n", dev->name, - pid, lp->mii_id[0], lp->mii_id[1]); -} - -static void tc35815_phy_chip_init(struct net_device *dev) -{ - struct tc35815_local *lp = dev->priv; - int pid = lp->phy_addr; - unsigned short bmcr; - struct ethtool_cmd ecmd, *ep; - - /* dis-isolate if needed. */ - bmcr = tc_mdio_read(dev, pid, MII_BMCR); - if (bmcr & BMCR_ISOLATE) { - int count = 32; - printk(KERN_DEBUG "%s: unisolating...", dev->name); - tc_mdio_write(dev, pid, MII_BMCR, bmcr & ~BMCR_ISOLATE); - while (--count) { - if (!(tc_mdio_read(dev, pid, MII_BMCR) & BMCR_ISOLATE)) - break; - udelay(20); - } - printk(" %s.\n", count ? "done" : "failed"); - } - - if (options.speed && options.duplex) { - ecmd.autoneg = AUTONEG_DISABLE; - ecmd.speed = options.speed == 10 ? SPEED_10 : SPEED_100; - ecmd.duplex = options.duplex == 1 ? DUPLEX_HALF : DUPLEX_FULL; - ep = &ecmd; - } else { - ep = NULL; - } - tc35815_start_auto_negotiation(dev, ep); + if (!lp->phy_dev) + return -ENODEV; + return phy_mii_ioctl(lp->phy_dev, if_mii(rq), cmd); } static void tc35815_chip_reset(struct net_device *dev) @@ -2857,13 +2375,11 @@ static void tc35815_chip_reset(struct net_device *dev) static void tc35815_chip_init(struct net_device *dev) { - struct tc35815_local *lp = dev->priv; + struct tc35815_local *lp = netdev_priv(dev); struct tc35815_regs __iomem *tr = (struct tc35815_regs __iomem *)dev->base_addr; unsigned long txctl = TX_CTL_CMD; - tc35815_phy_chip_init(dev); - /* load station address to CAM */ tc35815_set_cam_entry(dev, CAM_ENTRY_SOURCE, dev->dev_addr); @@ -2878,8 +2394,6 @@ static void tc35815_chip_init(struct net_device *dev) tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl); #ifdef TC35815_USE_PACKEDBUFFER tc_writel(RxFrag_EnPack | ETH_ZLEN, &tr->RxFragSize); /* Packing */ -#else - tc_writel(ETH_ZLEN, &tr->RxFragSize); #endif tc_writel(0, &tr->TxPollCtr); /* Batch mode */ tc_writel(TX_THRESHOLD, &tr->TxThrsh); @@ -2900,12 +2414,11 @@ static void tc35815_chip_init(struct net_device *dev) /* start MAC transmitter */ #ifndef NO_CHECK_CARRIER /* TX4939 does not have EnLCarr */ - if (lp->boardtype == TC35815_TX4939) + if (lp->chiptype == TC35815_TX4939) txctl &= ~Tx_EnLCarr; #ifdef WORKAROUND_LOSTCAR /* WORKAROUND: ignore LostCrS in full duplex operation */ - if ((lp->timer_state != asleep && lp->timer_state != lcheck) || - lp->fullduplex) + if (!lp->phy_dev || !lp->link || lp->duplex == DUPLEX_FULL) txctl &= ~Tx_EnLCarr; #endif #endif /* !NO_CHECK_CARRIER */ @@ -2919,15 +2432,16 @@ static void tc35815_chip_init(struct net_device *dev) static int tc35815_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); - struct tc35815_local *lp = dev->priv; + struct tc35815_local *lp = netdev_priv(dev); unsigned long flags; pci_save_state(pdev); if (!netif_running(dev)) return 0; netif_device_detach(dev); + if (lp->phy_dev) + phy_stop(lp->phy_dev); spin_lock_irqsave(&lp->lock, flags); - del_timer(&lp->timer); /* Kill if running */ tc35815_chip_reset(dev); spin_unlock_irqrestore(&lp->lock, flags); pci_set_power_state(pdev, PCI_D3hot); @@ -2937,16 +2451,16 @@ static int tc35815_suspend(struct pci_dev *pdev, pm_message_t state) static int tc35815_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct tc35815_local *lp = dev->priv; - unsigned long flags; + struct tc35815_local *lp = netdev_priv(dev); pci_restore_state(pdev); if (!netif_running(dev)) return 0; pci_set_power_state(pdev, PCI_D0); - spin_lock_irqsave(&lp->lock, flags); tc35815_restart(dev); - spin_unlock_irqrestore(&lp->lock, flags); + netif_carrier_off(dev); + if (lp->phy_dev) + phy_start(lp->phy_dev); netif_device_attach(dev); return 0; } @@ -2967,8 +2481,6 @@ module_param_named(speed, options.speed, int, 0); MODULE_PARM_DESC(speed, "0:auto, 10:10Mbps, 100:100Mbps"); module_param_named(duplex, options.duplex, int, 0); MODULE_PARM_DESC(duplex, "0:auto, 1:half, 2:full"); -module_param_named(doforce, options.doforce, int, 0); -MODULE_PARM_DESC(doforce, "try force link mode if auto-negotiation failed"); static int __init tc35815_init_module(void) {