162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching, 362306a36Sopenharmony_ci * auto carrier detecting ethernet driver. Also known as the 462306a36Sopenharmony_ci * "Happy Meal Ethernet" found on SunSwift SBUS cards. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 1996, 1998, 1999, 2002, 2003, 762306a36Sopenharmony_ci * 2006, 2008 David S. Miller (davem@davemloft.net) 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Changes : 1062306a36Sopenharmony_ci * 2000/11/11 Willy Tarreau <willy AT meta-x.org> 1162306a36Sopenharmony_ci * - port to non-sparc architectures. Tested only on x86 and 1262306a36Sopenharmony_ci * only currently works with QFE PCI cards. 1362306a36Sopenharmony_ci * - ability to specify the MAC address at module load time by passing this 1462306a36Sopenharmony_ci * argument : macaddr=0x00,0x10,0x20,0x30,0x40,0x50 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/bitops.h> 1862306a36Sopenharmony_ci#include <linux/crc32.h> 1962306a36Sopenharmony_ci#include <linux/delay.h> 2062306a36Sopenharmony_ci#include <linux/dma-mapping.h> 2162306a36Sopenharmony_ci#include <linux/errno.h> 2262306a36Sopenharmony_ci#include <linux/etherdevice.h> 2362306a36Sopenharmony_ci#include <linux/ethtool.h> 2462306a36Sopenharmony_ci#include <linux/fcntl.h> 2562306a36Sopenharmony_ci#include <linux/in.h> 2662306a36Sopenharmony_ci#include <linux/init.h> 2762306a36Sopenharmony_ci#include <linux/interrupt.h> 2862306a36Sopenharmony_ci#include <linux/io.h> 2962306a36Sopenharmony_ci#include <linux/ioport.h> 3062306a36Sopenharmony_ci#include <linux/kernel.h> 3162306a36Sopenharmony_ci#include <linux/mii.h> 3262306a36Sopenharmony_ci#include <linux/mm.h> 3362306a36Sopenharmony_ci#include <linux/module.h> 3462306a36Sopenharmony_ci#include <linux/netdevice.h> 3562306a36Sopenharmony_ci#include <linux/of.h> 3662306a36Sopenharmony_ci#include <linux/of_device.h> 3762306a36Sopenharmony_ci#include <linux/pci.h> 3862306a36Sopenharmony_ci#include <linux/platform_device.h> 3962306a36Sopenharmony_ci#include <linux/random.h> 4062306a36Sopenharmony_ci#include <linux/skbuff.h> 4162306a36Sopenharmony_ci#include <linux/slab.h> 4262306a36Sopenharmony_ci#include <linux/string.h> 4362306a36Sopenharmony_ci#include <linux/types.h> 4462306a36Sopenharmony_ci#include <linux/uaccess.h> 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#include <asm/byteorder.h> 4762306a36Sopenharmony_ci#include <asm/dma.h> 4862306a36Sopenharmony_ci#include <asm/irq.h> 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#ifdef CONFIG_SPARC 5162306a36Sopenharmony_ci#include <asm/auxio.h> 5262306a36Sopenharmony_ci#include <asm/idprom.h> 5362306a36Sopenharmony_ci#include <asm/openprom.h> 5462306a36Sopenharmony_ci#include <asm/oplib.h> 5562306a36Sopenharmony_ci#include <asm/prom.h> 5662306a36Sopenharmony_ci#endif 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#include "sunhme.h" 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define DRV_NAME "sunhme" 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ciMODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); 6362306a36Sopenharmony_ciMODULE_DESCRIPTION("Sun HappyMealEthernet(HME) 10/100baseT ethernet driver"); 6462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic int macaddr[6]; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* accept MAC address of the form macaddr=0x08,0x00,0x20,0x30,0x40,0x50 */ 6962306a36Sopenharmony_cimodule_param_array(macaddr, int, NULL, 0); 7062306a36Sopenharmony_ciMODULE_PARM_DESC(macaddr, "Happy Meal MAC address to set"); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#ifdef CONFIG_SBUS 7362306a36Sopenharmony_cistatic struct quattro *qfe_sbus_list; 7462306a36Sopenharmony_ci#endif 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#ifdef CONFIG_PCI 7762306a36Sopenharmony_cistatic struct quattro *qfe_pci_list; 7862306a36Sopenharmony_ci#endif 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#define hme_debug(fmt, ...) pr_debug("%s: " fmt, __func__, ##__VA_ARGS__) 8162306a36Sopenharmony_ci#define HMD hme_debug 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* "Auto Switch Debug" aka phy debug */ 8462306a36Sopenharmony_ci#if 1 8562306a36Sopenharmony_ci#define ASD hme_debug 8662306a36Sopenharmony_ci#else 8762306a36Sopenharmony_ci#define ASD(...) 8862306a36Sopenharmony_ci#endif 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci#if 0 9162306a36Sopenharmony_cistruct hme_tx_logent { 9262306a36Sopenharmony_ci unsigned int tstamp; 9362306a36Sopenharmony_ci int tx_new, tx_old; 9462306a36Sopenharmony_ci unsigned int action; 9562306a36Sopenharmony_ci#define TXLOG_ACTION_IRQ 0x01 9662306a36Sopenharmony_ci#define TXLOG_ACTION_TXMIT 0x02 9762306a36Sopenharmony_ci#define TXLOG_ACTION_TBUSY 0x04 9862306a36Sopenharmony_ci#define TXLOG_ACTION_NBUFS 0x08 9962306a36Sopenharmony_ci unsigned int status; 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci#define TX_LOG_LEN 128 10262306a36Sopenharmony_cistatic struct hme_tx_logent tx_log[TX_LOG_LEN]; 10362306a36Sopenharmony_cistatic int txlog_cur_entry; 10462306a36Sopenharmony_cistatic __inline__ void tx_add_log(struct happy_meal *hp, unsigned int a, unsigned int s) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct hme_tx_logent *tlp; 10762306a36Sopenharmony_ci unsigned long flags; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci local_irq_save(flags); 11062306a36Sopenharmony_ci tlp = &tx_log[txlog_cur_entry]; 11162306a36Sopenharmony_ci tlp->tstamp = (unsigned int)jiffies; 11262306a36Sopenharmony_ci tlp->tx_new = hp->tx_new; 11362306a36Sopenharmony_ci tlp->tx_old = hp->tx_old; 11462306a36Sopenharmony_ci tlp->action = a; 11562306a36Sopenharmony_ci tlp->status = s; 11662306a36Sopenharmony_ci txlog_cur_entry = (txlog_cur_entry + 1) & (TX_LOG_LEN - 1); 11762306a36Sopenharmony_ci local_irq_restore(flags); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_cistatic __inline__ void tx_dump_log(void) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci int i, this; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci this = txlog_cur_entry; 12462306a36Sopenharmony_ci for (i = 0; i < TX_LOG_LEN; i++) { 12562306a36Sopenharmony_ci pr_err("TXLOG[%d]: j[%08x] tx[N(%d)O(%d)] action[%08x] stat[%08x]\n", i, 12662306a36Sopenharmony_ci tx_log[this].tstamp, 12762306a36Sopenharmony_ci tx_log[this].tx_new, tx_log[this].tx_old, 12862306a36Sopenharmony_ci tx_log[this].action, tx_log[this].status); 12962306a36Sopenharmony_ci this = (this + 1) & (TX_LOG_LEN - 1); 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci#else 13362306a36Sopenharmony_ci#define tx_add_log(hp, a, s) 13462306a36Sopenharmony_ci#define tx_dump_log() 13562306a36Sopenharmony_ci#endif 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci#define DEFAULT_IPG0 16 /* For lance-mode only */ 13862306a36Sopenharmony_ci#define DEFAULT_IPG1 8 /* For all modes */ 13962306a36Sopenharmony_ci#define DEFAULT_IPG2 4 /* For all modes */ 14062306a36Sopenharmony_ci#define DEFAULT_JAMSIZE 4 /* Toe jam */ 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci/* NOTE: In the descriptor writes one _must_ write the address 14362306a36Sopenharmony_ci * member _first_. The card must not be allowed to see 14462306a36Sopenharmony_ci * the updated descriptor flags until the address is 14562306a36Sopenharmony_ci * correct. I've added a write memory barrier between 14662306a36Sopenharmony_ci * the two stores so that I can sleep well at night... -DaveM 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci#if defined(CONFIG_SBUS) && defined(CONFIG_PCI) 15062306a36Sopenharmony_cistatic void sbus_hme_write32(void __iomem *reg, u32 val) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci sbus_writel(val, reg); 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic u32 sbus_hme_read32(void __iomem *reg) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci return sbus_readl(reg); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic void sbus_hme_write_rxd(struct happy_meal_rxd *rxd, u32 flags, u32 addr) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci rxd->rx_addr = (__force hme32)addr; 16362306a36Sopenharmony_ci dma_wmb(); 16462306a36Sopenharmony_ci rxd->rx_flags = (__force hme32)flags; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic void sbus_hme_write_txd(struct happy_meal_txd *txd, u32 flags, u32 addr) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci txd->tx_addr = (__force hme32)addr; 17062306a36Sopenharmony_ci dma_wmb(); 17162306a36Sopenharmony_ci txd->tx_flags = (__force hme32)flags; 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic u32 sbus_hme_read_desc32(hme32 *p) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci return (__force u32)*p; 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic void pci_hme_write32(void __iomem *reg, u32 val) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci writel(val, reg); 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic u32 pci_hme_read32(void __iomem *reg) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci return readl(reg); 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic void pci_hme_write_rxd(struct happy_meal_rxd *rxd, u32 flags, u32 addr) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci rxd->rx_addr = (__force hme32)cpu_to_le32(addr); 19262306a36Sopenharmony_ci dma_wmb(); 19362306a36Sopenharmony_ci rxd->rx_flags = (__force hme32)cpu_to_le32(flags); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic void pci_hme_write_txd(struct happy_meal_txd *txd, u32 flags, u32 addr) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci txd->tx_addr = (__force hme32)cpu_to_le32(addr); 19962306a36Sopenharmony_ci dma_wmb(); 20062306a36Sopenharmony_ci txd->tx_flags = (__force hme32)cpu_to_le32(flags); 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic u32 pci_hme_read_desc32(hme32 *p) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci return le32_to_cpup((__le32 *)p); 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci#define hme_write32(__hp, __reg, __val) \ 20962306a36Sopenharmony_ci ((__hp)->write32((__reg), (__val))) 21062306a36Sopenharmony_ci#define hme_read32(__hp, __reg) \ 21162306a36Sopenharmony_ci ((__hp)->read32(__reg)) 21262306a36Sopenharmony_ci#define hme_write_rxd(__hp, __rxd, __flags, __addr) \ 21362306a36Sopenharmony_ci ((__hp)->write_rxd((__rxd), (__flags), (__addr))) 21462306a36Sopenharmony_ci#define hme_write_txd(__hp, __txd, __flags, __addr) \ 21562306a36Sopenharmony_ci ((__hp)->write_txd((__txd), (__flags), (__addr))) 21662306a36Sopenharmony_ci#define hme_read_desc32(__hp, __p) \ 21762306a36Sopenharmony_ci ((__hp)->read_desc32(__p)) 21862306a36Sopenharmony_ci#else 21962306a36Sopenharmony_ci#ifdef CONFIG_SBUS 22062306a36Sopenharmony_ci/* SBUS only compilation */ 22162306a36Sopenharmony_ci#define hme_write32(__hp, __reg, __val) \ 22262306a36Sopenharmony_ci sbus_writel((__val), (__reg)) 22362306a36Sopenharmony_ci#define hme_read32(__hp, __reg) \ 22462306a36Sopenharmony_ci sbus_readl(__reg) 22562306a36Sopenharmony_ci#define hme_write_rxd(__hp, __rxd, __flags, __addr) \ 22662306a36Sopenharmony_cido { (__rxd)->rx_addr = (__force hme32)(u32)(__addr); \ 22762306a36Sopenharmony_ci dma_wmb(); \ 22862306a36Sopenharmony_ci (__rxd)->rx_flags = (__force hme32)(u32)(__flags); \ 22962306a36Sopenharmony_ci} while(0) 23062306a36Sopenharmony_ci#define hme_write_txd(__hp, __txd, __flags, __addr) \ 23162306a36Sopenharmony_cido { (__txd)->tx_addr = (__force hme32)(u32)(__addr); \ 23262306a36Sopenharmony_ci dma_wmb(); \ 23362306a36Sopenharmony_ci (__txd)->tx_flags = (__force hme32)(u32)(__flags); \ 23462306a36Sopenharmony_ci} while(0) 23562306a36Sopenharmony_ci#define hme_read_desc32(__hp, __p) ((__force u32)(hme32)*(__p)) 23662306a36Sopenharmony_ci#else 23762306a36Sopenharmony_ci/* PCI only compilation */ 23862306a36Sopenharmony_ci#define hme_write32(__hp, __reg, __val) \ 23962306a36Sopenharmony_ci writel((__val), (__reg)) 24062306a36Sopenharmony_ci#define hme_read32(__hp, __reg) \ 24162306a36Sopenharmony_ci readl(__reg) 24262306a36Sopenharmony_ci#define hme_write_rxd(__hp, __rxd, __flags, __addr) \ 24362306a36Sopenharmony_cido { (__rxd)->rx_addr = (__force hme32)cpu_to_le32(__addr); \ 24462306a36Sopenharmony_ci dma_wmb(); \ 24562306a36Sopenharmony_ci (__rxd)->rx_flags = (__force hme32)cpu_to_le32(__flags); \ 24662306a36Sopenharmony_ci} while(0) 24762306a36Sopenharmony_ci#define hme_write_txd(__hp, __txd, __flags, __addr) \ 24862306a36Sopenharmony_cido { (__txd)->tx_addr = (__force hme32)cpu_to_le32(__addr); \ 24962306a36Sopenharmony_ci dma_wmb(); \ 25062306a36Sopenharmony_ci (__txd)->tx_flags = (__force hme32)cpu_to_le32(__flags); \ 25162306a36Sopenharmony_ci} while(0) 25262306a36Sopenharmony_cistatic inline u32 hme_read_desc32(struct happy_meal *hp, hme32 *p) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci return le32_to_cpup((__le32 *)p); 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci#endif 25762306a36Sopenharmony_ci#endif 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci/* Oh yes, the MIF BitBang is mighty fun to program. BitBucket is more like it. */ 26162306a36Sopenharmony_cistatic void BB_PUT_BIT(struct happy_meal *hp, void __iomem *tregs, int bit) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBDATA, bit); 26462306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBCLOCK, 0); 26562306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBCLOCK, 1); 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci#if 0 26962306a36Sopenharmony_cistatic u32 BB_GET_BIT(struct happy_meal *hp, void __iomem *tregs, int internal) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci u32 ret; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBCLOCK, 0); 27462306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBCLOCK, 1); 27562306a36Sopenharmony_ci ret = hme_read32(hp, tregs + TCVR_CFG); 27662306a36Sopenharmony_ci if (internal) 27762306a36Sopenharmony_ci ret &= TCV_CFG_MDIO0; 27862306a36Sopenharmony_ci else 27962306a36Sopenharmony_ci ret &= TCV_CFG_MDIO1; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci return ret; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci#endif 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic u32 BB_GET_BIT2(struct happy_meal *hp, void __iomem *tregs, int internal) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci u32 retval; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBCLOCK, 0); 29062306a36Sopenharmony_ci udelay(1); 29162306a36Sopenharmony_ci retval = hme_read32(hp, tregs + TCVR_CFG); 29262306a36Sopenharmony_ci if (internal) 29362306a36Sopenharmony_ci retval &= TCV_CFG_MDIO0; 29462306a36Sopenharmony_ci else 29562306a36Sopenharmony_ci retval &= TCV_CFG_MDIO1; 29662306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBCLOCK, 1); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci return retval; 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci#define TCVR_FAILURE 0x80000000 /* Impossible MIF read value */ 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic int happy_meal_bb_read(struct happy_meal *hp, 30462306a36Sopenharmony_ci void __iomem *tregs, int reg) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci u32 tmp; 30762306a36Sopenharmony_ci int retval = 0; 30862306a36Sopenharmony_ci int i; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci /* Enable the MIF BitBang outputs. */ 31162306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBOENAB, 1); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* Force BitBang into the idle state. */ 31462306a36Sopenharmony_ci for (i = 0; i < 32; i++) 31562306a36Sopenharmony_ci BB_PUT_BIT(hp, tregs, 1); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci /* Give it the read sequence. */ 31862306a36Sopenharmony_ci BB_PUT_BIT(hp, tregs, 0); 31962306a36Sopenharmony_ci BB_PUT_BIT(hp, tregs, 1); 32062306a36Sopenharmony_ci BB_PUT_BIT(hp, tregs, 1); 32162306a36Sopenharmony_ci BB_PUT_BIT(hp, tregs, 0); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* Give it the PHY address. */ 32462306a36Sopenharmony_ci tmp = hp->paddr & 0xff; 32562306a36Sopenharmony_ci for (i = 4; i >= 0; i--) 32662306a36Sopenharmony_ci BB_PUT_BIT(hp, tregs, ((tmp >> i) & 1)); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* Tell it what register we want to read. */ 32962306a36Sopenharmony_ci tmp = (reg & 0xff); 33062306a36Sopenharmony_ci for (i = 4; i >= 0; i--) 33162306a36Sopenharmony_ci BB_PUT_BIT(hp, tregs, ((tmp >> i) & 1)); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* Close down the MIF BitBang outputs. */ 33462306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBOENAB, 0); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* Now read in the value. */ 33762306a36Sopenharmony_ci (void) BB_GET_BIT2(hp, tregs, (hp->tcvr_type == internal)); 33862306a36Sopenharmony_ci for (i = 15; i >= 0; i--) 33962306a36Sopenharmony_ci retval |= BB_GET_BIT2(hp, tregs, (hp->tcvr_type == internal)); 34062306a36Sopenharmony_ci (void) BB_GET_BIT2(hp, tregs, (hp->tcvr_type == internal)); 34162306a36Sopenharmony_ci (void) BB_GET_BIT2(hp, tregs, (hp->tcvr_type == internal)); 34262306a36Sopenharmony_ci (void) BB_GET_BIT2(hp, tregs, (hp->tcvr_type == internal)); 34362306a36Sopenharmony_ci ASD("reg=%d value=%x\n", reg, retval); 34462306a36Sopenharmony_ci return retval; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic void happy_meal_bb_write(struct happy_meal *hp, 34862306a36Sopenharmony_ci void __iomem *tregs, int reg, 34962306a36Sopenharmony_ci unsigned short value) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci u32 tmp; 35262306a36Sopenharmony_ci int i; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci ASD("reg=%d value=%x\n", reg, value); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* Enable the MIF BitBang outputs. */ 35762306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBOENAB, 1); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci /* Force BitBang into the idle state. */ 36062306a36Sopenharmony_ci for (i = 0; i < 32; i++) 36162306a36Sopenharmony_ci BB_PUT_BIT(hp, tregs, 1); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* Give it write sequence. */ 36462306a36Sopenharmony_ci BB_PUT_BIT(hp, tregs, 0); 36562306a36Sopenharmony_ci BB_PUT_BIT(hp, tregs, 1); 36662306a36Sopenharmony_ci BB_PUT_BIT(hp, tregs, 0); 36762306a36Sopenharmony_ci BB_PUT_BIT(hp, tregs, 1); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* Give it the PHY address. */ 37062306a36Sopenharmony_ci tmp = (hp->paddr & 0xff); 37162306a36Sopenharmony_ci for (i = 4; i >= 0; i--) 37262306a36Sopenharmony_ci BB_PUT_BIT(hp, tregs, ((tmp >> i) & 1)); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci /* Tell it what register we will be writing. */ 37562306a36Sopenharmony_ci tmp = (reg & 0xff); 37662306a36Sopenharmony_ci for (i = 4; i >= 0; i--) 37762306a36Sopenharmony_ci BB_PUT_BIT(hp, tregs, ((tmp >> i) & 1)); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci /* Tell it to become ready for the bits. */ 38062306a36Sopenharmony_ci BB_PUT_BIT(hp, tregs, 1); 38162306a36Sopenharmony_ci BB_PUT_BIT(hp, tregs, 0); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci for (i = 15; i >= 0; i--) 38462306a36Sopenharmony_ci BB_PUT_BIT(hp, tregs, ((value >> i) & 1)); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* Close down the MIF BitBang outputs. */ 38762306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBOENAB, 0); 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci#define TCVR_READ_TRIES 16 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic int happy_meal_tcvr_read(struct happy_meal *hp, 39362306a36Sopenharmony_ci void __iomem *tregs, int reg) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci int tries = TCVR_READ_TRIES; 39662306a36Sopenharmony_ci int retval; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (hp->tcvr_type == none) { 39962306a36Sopenharmony_ci ASD("no transceiver, value=TCVR_FAILURE\n"); 40062306a36Sopenharmony_ci return TCVR_FAILURE; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if (!(hp->happy_flags & HFLAG_FENABLE)) { 40462306a36Sopenharmony_ci ASD("doing bit bang\n"); 40562306a36Sopenharmony_ci return happy_meal_bb_read(hp, tregs, reg); 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_FRAME, 40962306a36Sopenharmony_ci (FRAME_READ | (hp->paddr << 23) | ((reg & 0xff) << 18))); 41062306a36Sopenharmony_ci while (!(hme_read32(hp, tregs + TCVR_FRAME) & 0x10000) && --tries) 41162306a36Sopenharmony_ci udelay(20); 41262306a36Sopenharmony_ci if (!tries) { 41362306a36Sopenharmony_ci netdev_err(hp->dev, "Aieee, transceiver MIF read bolixed\n"); 41462306a36Sopenharmony_ci return TCVR_FAILURE; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci retval = hme_read32(hp, tregs + TCVR_FRAME) & 0xffff; 41762306a36Sopenharmony_ci ASD("reg=0x%02x value=%04x\n", reg, retval); 41862306a36Sopenharmony_ci return retval; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci#define TCVR_WRITE_TRIES 16 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic void happy_meal_tcvr_write(struct happy_meal *hp, 42462306a36Sopenharmony_ci void __iomem *tregs, int reg, 42562306a36Sopenharmony_ci unsigned short value) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci int tries = TCVR_WRITE_TRIES; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci ASD("reg=0x%02x value=%04x\n", reg, value); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci /* Welcome to Sun Microsystems, can I take your order please? */ 43262306a36Sopenharmony_ci if (!(hp->happy_flags & HFLAG_FENABLE)) { 43362306a36Sopenharmony_ci happy_meal_bb_write(hp, tregs, reg, value); 43462306a36Sopenharmony_ci return; 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* Would you like fries with that? */ 43862306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_FRAME, 43962306a36Sopenharmony_ci (FRAME_WRITE | (hp->paddr << 23) | 44062306a36Sopenharmony_ci ((reg & 0xff) << 18) | (value & 0xffff))); 44162306a36Sopenharmony_ci while (!(hme_read32(hp, tregs + TCVR_FRAME) & 0x10000) && --tries) 44262306a36Sopenharmony_ci udelay(20); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci /* Anything else? */ 44562306a36Sopenharmony_ci if (!tries) 44662306a36Sopenharmony_ci netdev_err(hp->dev, "Aieee, transceiver MIF write bolixed\n"); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci /* Fifty-two cents is your change, have a nice day. */ 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci/* Auto negotiation. The scheme is very simple. We have a timer routine 45262306a36Sopenharmony_ci * that keeps watching the auto negotiation process as it progresses. 45362306a36Sopenharmony_ci * The DP83840 is first told to start doing it's thing, we set up the time 45462306a36Sopenharmony_ci * and place the timer state machine in it's initial state. 45562306a36Sopenharmony_ci * 45662306a36Sopenharmony_ci * Here the timer peeks at the DP83840 status registers at each click to see 45762306a36Sopenharmony_ci * if the auto negotiation has completed, we assume here that the DP83840 PHY 45862306a36Sopenharmony_ci * will time out at some point and just tell us what (didn't) happen. For 45962306a36Sopenharmony_ci * complete coverage we only allow so many of the ticks at this level to run, 46062306a36Sopenharmony_ci * when this has expired we print a warning message and try another strategy. 46162306a36Sopenharmony_ci * This "other" strategy is to force the interface into various speed/duplex 46262306a36Sopenharmony_ci * configurations and we stop when we see a link-up condition before the 46362306a36Sopenharmony_ci * maximum number of "peek" ticks have occurred. 46462306a36Sopenharmony_ci * 46562306a36Sopenharmony_ci * Once a valid link status has been detected we configure the BigMAC and 46662306a36Sopenharmony_ci * the rest of the Happy Meal to speak the most efficient protocol we could 46762306a36Sopenharmony_ci * get a clean link for. The priority for link configurations, highest first 46862306a36Sopenharmony_ci * is: 46962306a36Sopenharmony_ci * 100 Base-T Full Duplex 47062306a36Sopenharmony_ci * 100 Base-T Half Duplex 47162306a36Sopenharmony_ci * 10 Base-T Full Duplex 47262306a36Sopenharmony_ci * 10 Base-T Half Duplex 47362306a36Sopenharmony_ci * 47462306a36Sopenharmony_ci * We start a new timer now, after a successful auto negotiation status has 47562306a36Sopenharmony_ci * been detected. This timer just waits for the link-up bit to get set in 47662306a36Sopenharmony_ci * the BMCR of the DP83840. When this occurs we print a kernel log message 47762306a36Sopenharmony_ci * describing the link type in use and the fact that it is up. 47862306a36Sopenharmony_ci * 47962306a36Sopenharmony_ci * If a fatal error of some sort is signalled and detected in the interrupt 48062306a36Sopenharmony_ci * service routine, and the chip is reset, or the link is ifconfig'd down 48162306a36Sopenharmony_ci * and then back up, this entire process repeats itself all over again. 48262306a36Sopenharmony_ci */ 48362306a36Sopenharmony_cistatic int try_next_permutation(struct happy_meal *hp, void __iomem *tregs) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci /* Downgrade from full to half duplex. Only possible 48862306a36Sopenharmony_ci * via ethtool. 48962306a36Sopenharmony_ci */ 49062306a36Sopenharmony_ci if (hp->sw_bmcr & BMCR_FULLDPLX) { 49162306a36Sopenharmony_ci hp->sw_bmcr &= ~(BMCR_FULLDPLX); 49262306a36Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr); 49362306a36Sopenharmony_ci return 0; 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci /* Downgrade from 100 to 10. */ 49762306a36Sopenharmony_ci if (hp->sw_bmcr & BMCR_SPEED100) { 49862306a36Sopenharmony_ci hp->sw_bmcr &= ~(BMCR_SPEED100); 49962306a36Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr); 50062306a36Sopenharmony_ci return 0; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci /* We've tried everything. */ 50462306a36Sopenharmony_ci return -1; 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_cistatic void display_link_mode(struct happy_meal *hp, void __iomem *tregs) 50862306a36Sopenharmony_ci{ 50962306a36Sopenharmony_ci hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, MII_LPA); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci netdev_info(hp->dev, 51262306a36Sopenharmony_ci "Link is up using %s transceiver at %dMb/s, %s Duplex.\n", 51362306a36Sopenharmony_ci hp->tcvr_type == external ? "external" : "internal", 51462306a36Sopenharmony_ci hp->sw_lpa & (LPA_100HALF | LPA_100FULL) ? 100 : 10, 51562306a36Sopenharmony_ci hp->sw_lpa & (LPA_100FULL | LPA_10FULL) ? "Full" : "Half"); 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic void display_forced_link_mode(struct happy_meal *hp, void __iomem *tregs) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci netdev_info(hp->dev, 52362306a36Sopenharmony_ci "Link has been forced up using %s transceiver at %dMb/s, %s Duplex.\n", 52462306a36Sopenharmony_ci hp->tcvr_type == external ? "external" : "internal", 52562306a36Sopenharmony_ci hp->sw_bmcr & BMCR_SPEED100 ? 100 : 10, 52662306a36Sopenharmony_ci hp->sw_bmcr & BMCR_FULLDPLX ? "Full" : "Half"); 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic int set_happy_link_modes(struct happy_meal *hp, void __iomem *tregs) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci int full; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci /* All we care about is making sure the bigmac tx_cfg has a 53462306a36Sopenharmony_ci * proper duplex setting. 53562306a36Sopenharmony_ci */ 53662306a36Sopenharmony_ci if (hp->timer_state == arbwait) { 53762306a36Sopenharmony_ci hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, MII_LPA); 53862306a36Sopenharmony_ci if (!(hp->sw_lpa & (LPA_10HALF | LPA_10FULL | LPA_100HALF | LPA_100FULL))) 53962306a36Sopenharmony_ci goto no_response; 54062306a36Sopenharmony_ci if (hp->sw_lpa & LPA_100FULL) 54162306a36Sopenharmony_ci full = 1; 54262306a36Sopenharmony_ci else if (hp->sw_lpa & LPA_100HALF) 54362306a36Sopenharmony_ci full = 0; 54462306a36Sopenharmony_ci else if (hp->sw_lpa & LPA_10FULL) 54562306a36Sopenharmony_ci full = 1; 54662306a36Sopenharmony_ci else 54762306a36Sopenharmony_ci full = 0; 54862306a36Sopenharmony_ci } else { 54962306a36Sopenharmony_ci /* Forcing a link mode. */ 55062306a36Sopenharmony_ci hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR); 55162306a36Sopenharmony_ci if (hp->sw_bmcr & BMCR_FULLDPLX) 55262306a36Sopenharmony_ci full = 1; 55362306a36Sopenharmony_ci else 55462306a36Sopenharmony_ci full = 0; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci /* Before changing other bits in the tx_cfg register, and in 55862306a36Sopenharmony_ci * general any of other the TX config registers too, you 55962306a36Sopenharmony_ci * must: 56062306a36Sopenharmony_ci * 1) Clear Enable 56162306a36Sopenharmony_ci * 2) Poll with reads until that bit reads back as zero 56262306a36Sopenharmony_ci * 3) Make TX configuration changes 56362306a36Sopenharmony_ci * 4) Set Enable once more 56462306a36Sopenharmony_ci */ 56562306a36Sopenharmony_ci hme_write32(hp, hp->bigmacregs + BMAC_TXCFG, 56662306a36Sopenharmony_ci hme_read32(hp, hp->bigmacregs + BMAC_TXCFG) & 56762306a36Sopenharmony_ci ~(BIGMAC_TXCFG_ENABLE)); 56862306a36Sopenharmony_ci while (hme_read32(hp, hp->bigmacregs + BMAC_TXCFG) & BIGMAC_TXCFG_ENABLE) 56962306a36Sopenharmony_ci barrier(); 57062306a36Sopenharmony_ci if (full) { 57162306a36Sopenharmony_ci hp->happy_flags |= HFLAG_FULL; 57262306a36Sopenharmony_ci hme_write32(hp, hp->bigmacregs + BMAC_TXCFG, 57362306a36Sopenharmony_ci hme_read32(hp, hp->bigmacregs + BMAC_TXCFG) | 57462306a36Sopenharmony_ci BIGMAC_TXCFG_FULLDPLX); 57562306a36Sopenharmony_ci } else { 57662306a36Sopenharmony_ci hp->happy_flags &= ~(HFLAG_FULL); 57762306a36Sopenharmony_ci hme_write32(hp, hp->bigmacregs + BMAC_TXCFG, 57862306a36Sopenharmony_ci hme_read32(hp, hp->bigmacregs + BMAC_TXCFG) & 57962306a36Sopenharmony_ci ~(BIGMAC_TXCFG_FULLDPLX)); 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci hme_write32(hp, hp->bigmacregs + BMAC_TXCFG, 58262306a36Sopenharmony_ci hme_read32(hp, hp->bigmacregs + BMAC_TXCFG) | 58362306a36Sopenharmony_ci BIGMAC_TXCFG_ENABLE); 58462306a36Sopenharmony_ci return 0; 58562306a36Sopenharmony_cino_response: 58662306a36Sopenharmony_ci return 1; 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_cistatic int is_lucent_phy(struct happy_meal *hp) 59062306a36Sopenharmony_ci{ 59162306a36Sopenharmony_ci void __iomem *tregs = hp->tcvregs; 59262306a36Sopenharmony_ci unsigned short mr2, mr3; 59362306a36Sopenharmony_ci int ret = 0; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci mr2 = happy_meal_tcvr_read(hp, tregs, 2); 59662306a36Sopenharmony_ci mr3 = happy_meal_tcvr_read(hp, tregs, 3); 59762306a36Sopenharmony_ci if ((mr2 & 0xffff) == 0x0180 && 59862306a36Sopenharmony_ci ((mr3 & 0xffff) >> 10) == 0x1d) 59962306a36Sopenharmony_ci ret = 1; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci return ret; 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci/* hp->happy_lock must be held */ 60562306a36Sopenharmony_cistatic void 60662306a36Sopenharmony_cihappy_meal_begin_auto_negotiation(struct happy_meal *hp, 60762306a36Sopenharmony_ci void __iomem *tregs, 60862306a36Sopenharmony_ci const struct ethtool_link_ksettings *ep) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci int timeout; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci /* Read all of the registers we are interested in now. */ 61362306a36Sopenharmony_ci hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, MII_BMSR); 61462306a36Sopenharmony_ci hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR); 61562306a36Sopenharmony_ci hp->sw_physid1 = happy_meal_tcvr_read(hp, tregs, MII_PHYSID1); 61662306a36Sopenharmony_ci hp->sw_physid2 = happy_meal_tcvr_read(hp, tregs, MII_PHYSID2); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci /* XXX Check BMSR_ANEGCAPABLE, should not be necessary though. */ 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, MII_ADVERTISE); 62162306a36Sopenharmony_ci if (!ep || ep->base.autoneg == AUTONEG_ENABLE) { 62262306a36Sopenharmony_ci /* Advertise everything we can support. */ 62362306a36Sopenharmony_ci if (hp->sw_bmsr & BMSR_10HALF) 62462306a36Sopenharmony_ci hp->sw_advertise |= (ADVERTISE_10HALF); 62562306a36Sopenharmony_ci else 62662306a36Sopenharmony_ci hp->sw_advertise &= ~(ADVERTISE_10HALF); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if (hp->sw_bmsr & BMSR_10FULL) 62962306a36Sopenharmony_ci hp->sw_advertise |= (ADVERTISE_10FULL); 63062306a36Sopenharmony_ci else 63162306a36Sopenharmony_ci hp->sw_advertise &= ~(ADVERTISE_10FULL); 63262306a36Sopenharmony_ci if (hp->sw_bmsr & BMSR_100HALF) 63362306a36Sopenharmony_ci hp->sw_advertise |= (ADVERTISE_100HALF); 63462306a36Sopenharmony_ci else 63562306a36Sopenharmony_ci hp->sw_advertise &= ~(ADVERTISE_100HALF); 63662306a36Sopenharmony_ci if (hp->sw_bmsr & BMSR_100FULL) 63762306a36Sopenharmony_ci hp->sw_advertise |= (ADVERTISE_100FULL); 63862306a36Sopenharmony_ci else 63962306a36Sopenharmony_ci hp->sw_advertise &= ~(ADVERTISE_100FULL); 64062306a36Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_ADVERTISE, hp->sw_advertise); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci /* XXX Currently no Happy Meal cards I know off support 100BaseT4, 64362306a36Sopenharmony_ci * XXX and this is because the DP83840 does not support it, changes 64462306a36Sopenharmony_ci * XXX would need to be made to the tx/rx logic in the driver as well 64562306a36Sopenharmony_ci * XXX so I completely skip checking for it in the BMSR for now. 64662306a36Sopenharmony_ci */ 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci ASD("Advertising [ %s%s%s%s]\n", 64962306a36Sopenharmony_ci hp->sw_advertise & ADVERTISE_10HALF ? "10H " : "", 65062306a36Sopenharmony_ci hp->sw_advertise & ADVERTISE_10FULL ? "10F " : "", 65162306a36Sopenharmony_ci hp->sw_advertise & ADVERTISE_100HALF ? "100H " : "", 65262306a36Sopenharmony_ci hp->sw_advertise & ADVERTISE_100FULL ? "100F " : ""); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci /* Enable Auto-Negotiation, this is usually on already... */ 65562306a36Sopenharmony_ci hp->sw_bmcr |= BMCR_ANENABLE; 65662306a36Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr); 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci /* Restart it to make sure it is going. */ 65962306a36Sopenharmony_ci hp->sw_bmcr |= BMCR_ANRESTART; 66062306a36Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci /* BMCR_ANRESTART self clears when the process has begun. */ 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci timeout = 64; /* More than enough. */ 66562306a36Sopenharmony_ci while (--timeout) { 66662306a36Sopenharmony_ci hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR); 66762306a36Sopenharmony_ci if (!(hp->sw_bmcr & BMCR_ANRESTART)) 66862306a36Sopenharmony_ci break; /* got it. */ 66962306a36Sopenharmony_ci udelay(10); 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci if (!timeout) { 67262306a36Sopenharmony_ci netdev_err(hp->dev, 67362306a36Sopenharmony_ci "Happy Meal would not start auto negotiation BMCR=0x%04x\n", 67462306a36Sopenharmony_ci hp->sw_bmcr); 67562306a36Sopenharmony_ci netdev_notice(hp->dev, 67662306a36Sopenharmony_ci "Performing force link detection.\n"); 67762306a36Sopenharmony_ci goto force_link; 67862306a36Sopenharmony_ci } else { 67962306a36Sopenharmony_ci hp->timer_state = arbwait; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci } else { 68262306a36Sopenharmony_ciforce_link: 68362306a36Sopenharmony_ci /* Force the link up, trying first a particular mode. 68462306a36Sopenharmony_ci * Either we are here at the request of ethtool or 68562306a36Sopenharmony_ci * because the Happy Meal would not start to autoneg. 68662306a36Sopenharmony_ci */ 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci /* Disable auto-negotiation in BMCR, enable the duplex and 68962306a36Sopenharmony_ci * speed setting, init the timer state machine, and fire it off. 69062306a36Sopenharmony_ci */ 69162306a36Sopenharmony_ci if (!ep || ep->base.autoneg == AUTONEG_ENABLE) { 69262306a36Sopenharmony_ci hp->sw_bmcr = BMCR_SPEED100; 69362306a36Sopenharmony_ci } else { 69462306a36Sopenharmony_ci if (ep->base.speed == SPEED_100) 69562306a36Sopenharmony_ci hp->sw_bmcr = BMCR_SPEED100; 69662306a36Sopenharmony_ci else 69762306a36Sopenharmony_ci hp->sw_bmcr = 0; 69862306a36Sopenharmony_ci if (ep->base.duplex == DUPLEX_FULL) 69962306a36Sopenharmony_ci hp->sw_bmcr |= BMCR_FULLDPLX; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci if (!is_lucent_phy(hp)) { 70462306a36Sopenharmony_ci /* OK, seems we need do disable the transceiver for the first 70562306a36Sopenharmony_ci * tick to make sure we get an accurate link state at the 70662306a36Sopenharmony_ci * second tick. 70762306a36Sopenharmony_ci */ 70862306a36Sopenharmony_ci hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, 70962306a36Sopenharmony_ci DP83840_CSCONFIG); 71062306a36Sopenharmony_ci hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB); 71162306a36Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, 71262306a36Sopenharmony_ci hp->sw_csconfig); 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci hp->timer_state = ltrywait; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci hp->timer_ticks = 0; 71862306a36Sopenharmony_ci hp->happy_timer.expires = jiffies + (12 * HZ)/10; /* 1.2 sec. */ 71962306a36Sopenharmony_ci add_timer(&hp->happy_timer); 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_cistatic void happy_meal_timer(struct timer_list *t) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci struct happy_meal *hp = from_timer(hp, t, happy_timer); 72562306a36Sopenharmony_ci void __iomem *tregs = hp->tcvregs; 72662306a36Sopenharmony_ci int restart_timer = 0; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci hp->timer_ticks++; 73162306a36Sopenharmony_ci switch(hp->timer_state) { 73262306a36Sopenharmony_ci case arbwait: 73362306a36Sopenharmony_ci /* Only allow for 5 ticks, thats 10 seconds and much too 73462306a36Sopenharmony_ci * long to wait for arbitration to complete. 73562306a36Sopenharmony_ci */ 73662306a36Sopenharmony_ci if (hp->timer_ticks >= 10) { 73762306a36Sopenharmony_ci /* Enter force mode. */ 73862306a36Sopenharmony_ci do_force_mode: 73962306a36Sopenharmony_ci hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR); 74062306a36Sopenharmony_ci netdev_notice(hp->dev, 74162306a36Sopenharmony_ci "Auto-Negotiation unsuccessful, trying force link mode\n"); 74262306a36Sopenharmony_ci hp->sw_bmcr = BMCR_SPEED100; 74362306a36Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci if (!is_lucent_phy(hp)) { 74662306a36Sopenharmony_ci /* OK, seems we need do disable the transceiver for the first 74762306a36Sopenharmony_ci * tick to make sure we get an accurate link state at the 74862306a36Sopenharmony_ci * second tick. 74962306a36Sopenharmony_ci */ 75062306a36Sopenharmony_ci hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG); 75162306a36Sopenharmony_ci hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB); 75262306a36Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, hp->sw_csconfig); 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci hp->timer_state = ltrywait; 75562306a36Sopenharmony_ci hp->timer_ticks = 0; 75662306a36Sopenharmony_ci restart_timer = 1; 75762306a36Sopenharmony_ci } else { 75862306a36Sopenharmony_ci /* Anything interesting happen? */ 75962306a36Sopenharmony_ci hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, MII_BMSR); 76062306a36Sopenharmony_ci if (hp->sw_bmsr & BMSR_ANEGCOMPLETE) { 76162306a36Sopenharmony_ci int ret; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci /* Just what we've been waiting for... */ 76462306a36Sopenharmony_ci ret = set_happy_link_modes(hp, tregs); 76562306a36Sopenharmony_ci if (ret) { 76662306a36Sopenharmony_ci /* Ooops, something bad happened, go to force 76762306a36Sopenharmony_ci * mode. 76862306a36Sopenharmony_ci * 76962306a36Sopenharmony_ci * XXX Broken hubs which don't support 802.3u 77062306a36Sopenharmony_ci * XXX auto-negotiation make this happen as well. 77162306a36Sopenharmony_ci */ 77262306a36Sopenharmony_ci goto do_force_mode; 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci /* Success, at least so far, advance our state engine. */ 77662306a36Sopenharmony_ci hp->timer_state = lupwait; 77762306a36Sopenharmony_ci restart_timer = 1; 77862306a36Sopenharmony_ci } else { 77962306a36Sopenharmony_ci restart_timer = 1; 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci break; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci case lupwait: 78562306a36Sopenharmony_ci /* Auto negotiation was successful and we are awaiting a 78662306a36Sopenharmony_ci * link up status. I have decided to let this timer run 78762306a36Sopenharmony_ci * forever until some sort of error is signalled, reporting 78862306a36Sopenharmony_ci * a message to the user at 10 second intervals. 78962306a36Sopenharmony_ci */ 79062306a36Sopenharmony_ci hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, MII_BMSR); 79162306a36Sopenharmony_ci if (hp->sw_bmsr & BMSR_LSTATUS) { 79262306a36Sopenharmony_ci /* Wheee, it's up, display the link mode in use and put 79362306a36Sopenharmony_ci * the timer to sleep. 79462306a36Sopenharmony_ci */ 79562306a36Sopenharmony_ci display_link_mode(hp, tregs); 79662306a36Sopenharmony_ci hp->timer_state = asleep; 79762306a36Sopenharmony_ci restart_timer = 0; 79862306a36Sopenharmony_ci } else { 79962306a36Sopenharmony_ci if (hp->timer_ticks >= 10) { 80062306a36Sopenharmony_ci netdev_notice(hp->dev, 80162306a36Sopenharmony_ci "Auto negotiation successful, link still not completely up.\n"); 80262306a36Sopenharmony_ci hp->timer_ticks = 0; 80362306a36Sopenharmony_ci restart_timer = 1; 80462306a36Sopenharmony_ci } else { 80562306a36Sopenharmony_ci restart_timer = 1; 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci break; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci case ltrywait: 81162306a36Sopenharmony_ci /* Making the timeout here too long can make it take 81262306a36Sopenharmony_ci * annoyingly long to attempt all of the link mode 81362306a36Sopenharmony_ci * permutations, but then again this is essentially 81462306a36Sopenharmony_ci * error recovery code for the most part. 81562306a36Sopenharmony_ci */ 81662306a36Sopenharmony_ci hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, MII_BMSR); 81762306a36Sopenharmony_ci hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG); 81862306a36Sopenharmony_ci if (hp->timer_ticks == 1) { 81962306a36Sopenharmony_ci if (!is_lucent_phy(hp)) { 82062306a36Sopenharmony_ci /* Re-enable transceiver, we'll re-enable the transceiver next 82162306a36Sopenharmony_ci * tick, then check link state on the following tick. 82262306a36Sopenharmony_ci */ 82362306a36Sopenharmony_ci hp->sw_csconfig |= CSCONFIG_TCVDISAB; 82462306a36Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, 82562306a36Sopenharmony_ci DP83840_CSCONFIG, hp->sw_csconfig); 82662306a36Sopenharmony_ci } 82762306a36Sopenharmony_ci restart_timer = 1; 82862306a36Sopenharmony_ci break; 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci if (hp->timer_ticks == 2) { 83162306a36Sopenharmony_ci if (!is_lucent_phy(hp)) { 83262306a36Sopenharmony_ci hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB); 83362306a36Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, 83462306a36Sopenharmony_ci DP83840_CSCONFIG, hp->sw_csconfig); 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci restart_timer = 1; 83762306a36Sopenharmony_ci break; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci if (hp->sw_bmsr & BMSR_LSTATUS) { 84062306a36Sopenharmony_ci /* Force mode selection success. */ 84162306a36Sopenharmony_ci display_forced_link_mode(hp, tregs); 84262306a36Sopenharmony_ci set_happy_link_modes(hp, tregs); /* XXX error? then what? */ 84362306a36Sopenharmony_ci hp->timer_state = asleep; 84462306a36Sopenharmony_ci restart_timer = 0; 84562306a36Sopenharmony_ci } else { 84662306a36Sopenharmony_ci if (hp->timer_ticks >= 4) { /* 6 seconds or so... */ 84762306a36Sopenharmony_ci int ret; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci ret = try_next_permutation(hp, tregs); 85062306a36Sopenharmony_ci if (ret == -1) { 85162306a36Sopenharmony_ci /* Aieee, tried them all, reset the 85262306a36Sopenharmony_ci * chip and try all over again. 85362306a36Sopenharmony_ci */ 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci /* Let the user know... */ 85662306a36Sopenharmony_ci netdev_notice(hp->dev, 85762306a36Sopenharmony_ci "Link down, cable problem?\n"); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci happy_meal_begin_auto_negotiation(hp, tregs, NULL); 86062306a36Sopenharmony_ci goto out; 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci if (!is_lucent_phy(hp)) { 86362306a36Sopenharmony_ci hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, 86462306a36Sopenharmony_ci DP83840_CSCONFIG); 86562306a36Sopenharmony_ci hp->sw_csconfig |= CSCONFIG_TCVDISAB; 86662306a36Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, 86762306a36Sopenharmony_ci DP83840_CSCONFIG, hp->sw_csconfig); 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci hp->timer_ticks = 0; 87062306a36Sopenharmony_ci restart_timer = 1; 87162306a36Sopenharmony_ci } else { 87262306a36Sopenharmony_ci restart_timer = 1; 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci break; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci case asleep: 87862306a36Sopenharmony_ci default: 87962306a36Sopenharmony_ci /* Can't happens.... */ 88062306a36Sopenharmony_ci netdev_err(hp->dev, 88162306a36Sopenharmony_ci "Aieee, link timer is asleep but we got one anyways!\n"); 88262306a36Sopenharmony_ci restart_timer = 0; 88362306a36Sopenharmony_ci hp->timer_ticks = 0; 88462306a36Sopenharmony_ci hp->timer_state = asleep; /* foo on you */ 88562306a36Sopenharmony_ci break; 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci if (restart_timer) { 88962306a36Sopenharmony_ci hp->happy_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2 sec. */ 89062306a36Sopenharmony_ci add_timer(&hp->happy_timer); 89162306a36Sopenharmony_ci } 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ciout: 89462306a36Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 89562306a36Sopenharmony_ci} 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci#define TX_RESET_TRIES 32 89862306a36Sopenharmony_ci#define RX_RESET_TRIES 32 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci/* hp->happy_lock must be held */ 90162306a36Sopenharmony_cistatic void happy_meal_tx_reset(struct happy_meal *hp, void __iomem *bregs) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci int tries = TX_RESET_TRIES; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci HMD("reset...\n"); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci /* Would you like to try our SMCC Delux? */ 90862306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_TXSWRESET, 0); 90962306a36Sopenharmony_ci while ((hme_read32(hp, bregs + BMAC_TXSWRESET) & 1) && --tries) 91062306a36Sopenharmony_ci udelay(20); 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci /* Lettuce, tomato, buggy hardware (no extra charge)? */ 91362306a36Sopenharmony_ci if (!tries) 91462306a36Sopenharmony_ci netdev_err(hp->dev, "Transceiver BigMac ATTACK!"); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci /* Take care. */ 91762306a36Sopenharmony_ci HMD("done\n"); 91862306a36Sopenharmony_ci} 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci/* hp->happy_lock must be held */ 92162306a36Sopenharmony_cistatic void happy_meal_rx_reset(struct happy_meal *hp, void __iomem *bregs) 92262306a36Sopenharmony_ci{ 92362306a36Sopenharmony_ci int tries = RX_RESET_TRIES; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci HMD("reset...\n"); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci /* We have a special on GNU/Viking hardware bugs today. */ 92862306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_RXSWRESET, 0); 92962306a36Sopenharmony_ci while ((hme_read32(hp, bregs + BMAC_RXSWRESET) & 1) && --tries) 93062306a36Sopenharmony_ci udelay(20); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci /* Will that be all? */ 93362306a36Sopenharmony_ci if (!tries) 93462306a36Sopenharmony_ci netdev_err(hp->dev, "Receiver BigMac ATTACK!\n"); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci /* Don't forget your vik_1137125_wa. Have a nice day. */ 93762306a36Sopenharmony_ci HMD("done\n"); 93862306a36Sopenharmony_ci} 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci#define STOP_TRIES 16 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci/* hp->happy_lock must be held */ 94362306a36Sopenharmony_cistatic void happy_meal_stop(struct happy_meal *hp, void __iomem *gregs) 94462306a36Sopenharmony_ci{ 94562306a36Sopenharmony_ci int tries = STOP_TRIES; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci HMD("reset...\n"); 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci /* We're consolidating our STB products, it's your lucky day. */ 95062306a36Sopenharmony_ci hme_write32(hp, gregs + GREG_SWRESET, GREG_RESET_ALL); 95162306a36Sopenharmony_ci while (hme_read32(hp, gregs + GREG_SWRESET) && --tries) 95262306a36Sopenharmony_ci udelay(20); 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci /* Come back next week when we are "Sun Microelectronics". */ 95562306a36Sopenharmony_ci if (!tries) 95662306a36Sopenharmony_ci netdev_err(hp->dev, "Fry guys.\n"); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci /* Remember: "Different name, same old buggy as shit hardware." */ 95962306a36Sopenharmony_ci HMD("done\n"); 96062306a36Sopenharmony_ci} 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci/* hp->happy_lock must be held */ 96362306a36Sopenharmony_cistatic void happy_meal_get_counters(struct happy_meal *hp, void __iomem *bregs) 96462306a36Sopenharmony_ci{ 96562306a36Sopenharmony_ci struct net_device_stats *stats = &hp->dev->stats; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci stats->rx_crc_errors += hme_read32(hp, bregs + BMAC_RCRCECTR); 96862306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_RCRCECTR, 0); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci stats->rx_frame_errors += hme_read32(hp, bregs + BMAC_UNALECTR); 97162306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_UNALECTR, 0); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci stats->rx_length_errors += hme_read32(hp, bregs + BMAC_GLECTR); 97462306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_GLECTR, 0); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci stats->tx_aborted_errors += hme_read32(hp, bregs + BMAC_EXCTR); 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci stats->collisions += 97962306a36Sopenharmony_ci (hme_read32(hp, bregs + BMAC_EXCTR) + 98062306a36Sopenharmony_ci hme_read32(hp, bregs + BMAC_LTCTR)); 98162306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_EXCTR, 0); 98262306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_LTCTR, 0); 98362306a36Sopenharmony_ci} 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci/* Only Sun can take such nice parts and fuck up the programming interface 98662306a36Sopenharmony_ci * like this. Good job guys... 98762306a36Sopenharmony_ci */ 98862306a36Sopenharmony_ci#define TCVR_RESET_TRIES 16 /* It should reset quickly */ 98962306a36Sopenharmony_ci#define TCVR_UNISOLATE_TRIES 32 /* Dis-isolation can take longer. */ 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci/* hp->happy_lock must be held */ 99262306a36Sopenharmony_cistatic int happy_meal_tcvr_reset(struct happy_meal *hp, void __iomem *tregs) 99362306a36Sopenharmony_ci{ 99462306a36Sopenharmony_ci u32 tconfig; 99562306a36Sopenharmony_ci int result, tries = TCVR_RESET_TRIES; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci tconfig = hme_read32(hp, tregs + TCVR_CFG); 99862306a36Sopenharmony_ci ASD("tcfg=%08x\n", tconfig); 99962306a36Sopenharmony_ci if (hp->tcvr_type == external) { 100062306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, tconfig & ~(TCV_CFG_PSELECT)); 100162306a36Sopenharmony_ci hp->tcvr_type = internal; 100262306a36Sopenharmony_ci hp->paddr = TCV_PADDR_ITX; 100362306a36Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_BMCR, 100462306a36Sopenharmony_ci (BMCR_LOOPBACK|BMCR_PDOWN|BMCR_ISOLATE)); 100562306a36Sopenharmony_ci result = happy_meal_tcvr_read(hp, tregs, MII_BMCR); 100662306a36Sopenharmony_ci if (result == TCVR_FAILURE) { 100762306a36Sopenharmony_ci ASD("phyread_fail\n"); 100862306a36Sopenharmony_ci return -1; 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci ASD("external: ISOLATE, phyread_ok, PSELECT\n"); 101162306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, tconfig | TCV_CFG_PSELECT); 101262306a36Sopenharmony_ci hp->tcvr_type = external; 101362306a36Sopenharmony_ci hp->paddr = TCV_PADDR_ETX; 101462306a36Sopenharmony_ci } else { 101562306a36Sopenharmony_ci if (tconfig & TCV_CFG_MDIO1) { 101662306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, (tconfig | TCV_CFG_PSELECT)); 101762306a36Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_BMCR, 101862306a36Sopenharmony_ci (BMCR_LOOPBACK|BMCR_PDOWN|BMCR_ISOLATE)); 101962306a36Sopenharmony_ci result = happy_meal_tcvr_read(hp, tregs, MII_BMCR); 102062306a36Sopenharmony_ci if (result == TCVR_FAILURE) { 102162306a36Sopenharmony_ci ASD("phyread_fail>\n"); 102262306a36Sopenharmony_ci return -1; 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci ASD("internal: PSELECT, ISOLATE, phyread_ok, ~PSELECT\n"); 102562306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, (tconfig & ~(TCV_CFG_PSELECT))); 102662306a36Sopenharmony_ci hp->tcvr_type = internal; 102762306a36Sopenharmony_ci hp->paddr = TCV_PADDR_ITX; 102862306a36Sopenharmony_ci } 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci ASD("BMCR_RESET...\n"); 103262306a36Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_BMCR, BMCR_RESET); 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci while (--tries) { 103562306a36Sopenharmony_ci result = happy_meal_tcvr_read(hp, tregs, MII_BMCR); 103662306a36Sopenharmony_ci if (result == TCVR_FAILURE) 103762306a36Sopenharmony_ci return -1; 103862306a36Sopenharmony_ci hp->sw_bmcr = result; 103962306a36Sopenharmony_ci if (!(result & BMCR_RESET)) 104062306a36Sopenharmony_ci break; 104162306a36Sopenharmony_ci udelay(20); 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci if (!tries) { 104462306a36Sopenharmony_ci ASD("BMCR RESET FAILED!\n"); 104562306a36Sopenharmony_ci return -1; 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci ASD("RESET_OK\n"); 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci /* Get fresh copies of the PHY registers. */ 105062306a36Sopenharmony_ci hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, MII_BMSR); 105162306a36Sopenharmony_ci hp->sw_physid1 = happy_meal_tcvr_read(hp, tregs, MII_PHYSID1); 105262306a36Sopenharmony_ci hp->sw_physid2 = happy_meal_tcvr_read(hp, tregs, MII_PHYSID2); 105362306a36Sopenharmony_ci hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, MII_ADVERTISE); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci ASD("UNISOLATE...\n"); 105662306a36Sopenharmony_ci hp->sw_bmcr &= ~(BMCR_ISOLATE); 105762306a36Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr); 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci tries = TCVR_UNISOLATE_TRIES; 106062306a36Sopenharmony_ci while (--tries) { 106162306a36Sopenharmony_ci result = happy_meal_tcvr_read(hp, tregs, MII_BMCR); 106262306a36Sopenharmony_ci if (result == TCVR_FAILURE) 106362306a36Sopenharmony_ci return -1; 106462306a36Sopenharmony_ci if (!(result & BMCR_ISOLATE)) 106562306a36Sopenharmony_ci break; 106662306a36Sopenharmony_ci udelay(20); 106762306a36Sopenharmony_ci } 106862306a36Sopenharmony_ci if (!tries) { 106962306a36Sopenharmony_ci ASD("UNISOLATE FAILED!\n"); 107062306a36Sopenharmony_ci return -1; 107162306a36Sopenharmony_ci } 107262306a36Sopenharmony_ci ASD("SUCCESS and CSCONFIG_DFBYPASS\n"); 107362306a36Sopenharmony_ci if (!is_lucent_phy(hp)) { 107462306a36Sopenharmony_ci result = happy_meal_tcvr_read(hp, tregs, 107562306a36Sopenharmony_ci DP83840_CSCONFIG); 107662306a36Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, 107762306a36Sopenharmony_ci DP83840_CSCONFIG, (result | CSCONFIG_DFBYPASS)); 107862306a36Sopenharmony_ci } 107962306a36Sopenharmony_ci return 0; 108062306a36Sopenharmony_ci} 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci/* Figure out whether we have an internal or external transceiver. 108362306a36Sopenharmony_ci * 108462306a36Sopenharmony_ci * hp->happy_lock must be held 108562306a36Sopenharmony_ci */ 108662306a36Sopenharmony_cistatic void happy_meal_transceiver_check(struct happy_meal *hp, void __iomem *tregs) 108762306a36Sopenharmony_ci{ 108862306a36Sopenharmony_ci unsigned long tconfig = hme_read32(hp, tregs + TCVR_CFG); 108962306a36Sopenharmony_ci u32 reread = hme_read32(hp, tregs + TCVR_CFG); 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci ASD("tcfg=%08lx\n", tconfig); 109262306a36Sopenharmony_ci if (reread & TCV_CFG_MDIO1) { 109362306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, tconfig | TCV_CFG_PSELECT); 109462306a36Sopenharmony_ci hp->paddr = TCV_PADDR_ETX; 109562306a36Sopenharmony_ci hp->tcvr_type = external; 109662306a36Sopenharmony_ci ASD("not polling, external\n"); 109762306a36Sopenharmony_ci } else { 109862306a36Sopenharmony_ci if (reread & TCV_CFG_MDIO0) { 109962306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, 110062306a36Sopenharmony_ci tconfig & ~(TCV_CFG_PSELECT)); 110162306a36Sopenharmony_ci hp->paddr = TCV_PADDR_ITX; 110262306a36Sopenharmony_ci hp->tcvr_type = internal; 110362306a36Sopenharmony_ci ASD("not polling, internal\n"); 110462306a36Sopenharmony_ci } else { 110562306a36Sopenharmony_ci netdev_err(hp->dev, 110662306a36Sopenharmony_ci "Transceiver and a coke please."); 110762306a36Sopenharmony_ci hp->tcvr_type = none; /* Grrr... */ 110862306a36Sopenharmony_ci ASD("not polling, none\n"); 110962306a36Sopenharmony_ci } 111062306a36Sopenharmony_ci } 111162306a36Sopenharmony_ci} 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci/* The receive ring buffers are a bit tricky to get right. Here goes... 111462306a36Sopenharmony_ci * 111562306a36Sopenharmony_ci * The buffers we dma into must be 64 byte aligned. So we use a special 111662306a36Sopenharmony_ci * alloc_skb() routine for the happy meal to allocate 64 bytes more than 111762306a36Sopenharmony_ci * we really need. 111862306a36Sopenharmony_ci * 111962306a36Sopenharmony_ci * We use skb_reserve() to align the data block we get in the skb. We 112062306a36Sopenharmony_ci * also program the etxregs->cfg register to use an offset of 2. This 112162306a36Sopenharmony_ci * imperical constant plus the ethernet header size will always leave 112262306a36Sopenharmony_ci * us with a nicely aligned ip header once we pass things up to the 112362306a36Sopenharmony_ci * protocol layers. 112462306a36Sopenharmony_ci * 112562306a36Sopenharmony_ci * The numbers work out to: 112662306a36Sopenharmony_ci * 112762306a36Sopenharmony_ci * Max ethernet frame size 1518 112862306a36Sopenharmony_ci * Ethernet header size 14 112962306a36Sopenharmony_ci * Happy Meal base offset 2 113062306a36Sopenharmony_ci * 113162306a36Sopenharmony_ci * Say a skb data area is at 0xf001b010, and its size alloced is 113262306a36Sopenharmony_ci * (ETH_FRAME_LEN + 64 + 2) = (1514 + 64 + 2) = 1580 bytes. 113362306a36Sopenharmony_ci * 113462306a36Sopenharmony_ci * First our alloc_skb() routine aligns the data base to a 64 byte 113562306a36Sopenharmony_ci * boundary. We now have 0xf001b040 as our skb data address. We 113662306a36Sopenharmony_ci * plug this into the receive descriptor address. 113762306a36Sopenharmony_ci * 113862306a36Sopenharmony_ci * Next, we skb_reserve() 2 bytes to account for the Happy Meal offset. 113962306a36Sopenharmony_ci * So now the data we will end up looking at starts at 0xf001b042. When 114062306a36Sopenharmony_ci * the packet arrives, we will check out the size received and subtract 114162306a36Sopenharmony_ci * this from the skb->length. Then we just pass the packet up to the 114262306a36Sopenharmony_ci * protocols as is, and allocate a new skb to replace this slot we have 114362306a36Sopenharmony_ci * just received from. 114462306a36Sopenharmony_ci * 114562306a36Sopenharmony_ci * The ethernet layer will strip the ether header from the front of the 114662306a36Sopenharmony_ci * skb we just sent to it, this leaves us with the ip header sitting 114762306a36Sopenharmony_ci * nicely aligned at 0xf001b050. Also, for tcp and udp packets the 114862306a36Sopenharmony_ci * Happy Meal has even checksummed the tcp/udp data for us. The 16 114962306a36Sopenharmony_ci * bit checksum is obtained from the low bits of the receive descriptor 115062306a36Sopenharmony_ci * flags, thus: 115162306a36Sopenharmony_ci * 115262306a36Sopenharmony_ci * skb->csum = rxd->rx_flags & 0xffff; 115362306a36Sopenharmony_ci * skb->ip_summed = CHECKSUM_COMPLETE; 115462306a36Sopenharmony_ci * 115562306a36Sopenharmony_ci * before sending off the skb to the protocols, and we are good as gold. 115662306a36Sopenharmony_ci */ 115762306a36Sopenharmony_cistatic void happy_meal_clean_rings(struct happy_meal *hp) 115862306a36Sopenharmony_ci{ 115962306a36Sopenharmony_ci int i; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) { 116262306a36Sopenharmony_ci if (hp->rx_skbs[i] != NULL) { 116362306a36Sopenharmony_ci struct sk_buff *skb = hp->rx_skbs[i]; 116462306a36Sopenharmony_ci struct happy_meal_rxd *rxd; 116562306a36Sopenharmony_ci u32 dma_addr; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci rxd = &hp->happy_block->happy_meal_rxd[i]; 116862306a36Sopenharmony_ci dma_addr = hme_read_desc32(hp, &rxd->rx_addr); 116962306a36Sopenharmony_ci dma_unmap_single(hp->dma_dev, dma_addr, 117062306a36Sopenharmony_ci RX_BUF_ALLOC_SIZE, DMA_FROM_DEVICE); 117162306a36Sopenharmony_ci dev_kfree_skb_any(skb); 117262306a36Sopenharmony_ci hp->rx_skbs[i] = NULL; 117362306a36Sopenharmony_ci } 117462306a36Sopenharmony_ci } 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci for (i = 0; i < TX_RING_SIZE; i++) { 117762306a36Sopenharmony_ci if (hp->tx_skbs[i] != NULL) { 117862306a36Sopenharmony_ci struct sk_buff *skb = hp->tx_skbs[i]; 117962306a36Sopenharmony_ci struct happy_meal_txd *txd; 118062306a36Sopenharmony_ci u32 dma_addr; 118162306a36Sopenharmony_ci int frag; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci hp->tx_skbs[i] = NULL; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) { 118662306a36Sopenharmony_ci txd = &hp->happy_block->happy_meal_txd[i]; 118762306a36Sopenharmony_ci dma_addr = hme_read_desc32(hp, &txd->tx_addr); 118862306a36Sopenharmony_ci if (!frag) 118962306a36Sopenharmony_ci dma_unmap_single(hp->dma_dev, dma_addr, 119062306a36Sopenharmony_ci (hme_read_desc32(hp, &txd->tx_flags) 119162306a36Sopenharmony_ci & TXFLAG_SIZE), 119262306a36Sopenharmony_ci DMA_TO_DEVICE); 119362306a36Sopenharmony_ci else 119462306a36Sopenharmony_ci dma_unmap_page(hp->dma_dev, dma_addr, 119562306a36Sopenharmony_ci (hme_read_desc32(hp, &txd->tx_flags) 119662306a36Sopenharmony_ci & TXFLAG_SIZE), 119762306a36Sopenharmony_ci DMA_TO_DEVICE); 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci if (frag != skb_shinfo(skb)->nr_frags) 120062306a36Sopenharmony_ci i++; 120162306a36Sopenharmony_ci } 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci dev_kfree_skb_any(skb); 120462306a36Sopenharmony_ci } 120562306a36Sopenharmony_ci } 120662306a36Sopenharmony_ci} 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci/* hp->happy_lock must be held */ 120962306a36Sopenharmony_cistatic void happy_meal_init_rings(struct happy_meal *hp) 121062306a36Sopenharmony_ci{ 121162306a36Sopenharmony_ci struct hmeal_init_block *hb = hp->happy_block; 121262306a36Sopenharmony_ci int i; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci HMD("counters to zero\n"); 121562306a36Sopenharmony_ci hp->rx_new = hp->rx_old = hp->tx_new = hp->tx_old = 0; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci /* Free any skippy bufs left around in the rings. */ 121862306a36Sopenharmony_ci happy_meal_clean_rings(hp); 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci /* Now get new skippy bufs for the receive ring. */ 122162306a36Sopenharmony_ci HMD("init rxring\n"); 122262306a36Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) { 122362306a36Sopenharmony_ci struct sk_buff *skb; 122462306a36Sopenharmony_ci u32 mapping; 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); 122762306a36Sopenharmony_ci if (!skb) { 122862306a36Sopenharmony_ci hme_write_rxd(hp, &hb->happy_meal_rxd[i], 0, 0); 122962306a36Sopenharmony_ci continue; 123062306a36Sopenharmony_ci } 123162306a36Sopenharmony_ci hp->rx_skbs[i] = skb; 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci /* Because we reserve afterwards. */ 123462306a36Sopenharmony_ci skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET + 4)); 123562306a36Sopenharmony_ci mapping = dma_map_single(hp->dma_dev, skb->data, RX_BUF_ALLOC_SIZE, 123662306a36Sopenharmony_ci DMA_FROM_DEVICE); 123762306a36Sopenharmony_ci if (dma_mapping_error(hp->dma_dev, mapping)) { 123862306a36Sopenharmony_ci dev_kfree_skb_any(skb); 123962306a36Sopenharmony_ci hme_write_rxd(hp, &hb->happy_meal_rxd[i], 0, 0); 124062306a36Sopenharmony_ci continue; 124162306a36Sopenharmony_ci } 124262306a36Sopenharmony_ci hme_write_rxd(hp, &hb->happy_meal_rxd[i], 124362306a36Sopenharmony_ci (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)), 124462306a36Sopenharmony_ci mapping); 124562306a36Sopenharmony_ci skb_reserve(skb, RX_OFFSET); 124662306a36Sopenharmony_ci } 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci HMD("init txring\n"); 124962306a36Sopenharmony_ci for (i = 0; i < TX_RING_SIZE; i++) 125062306a36Sopenharmony_ci hme_write_txd(hp, &hb->happy_meal_txd[i], 0, 0); 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci HMD("done\n"); 125362306a36Sopenharmony_ci} 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci/* hp->happy_lock must be held */ 125662306a36Sopenharmony_cistatic int happy_meal_init(struct happy_meal *hp) 125762306a36Sopenharmony_ci{ 125862306a36Sopenharmony_ci const unsigned char *e = &hp->dev->dev_addr[0]; 125962306a36Sopenharmony_ci void __iomem *gregs = hp->gregs; 126062306a36Sopenharmony_ci void __iomem *etxregs = hp->etxregs; 126162306a36Sopenharmony_ci void __iomem *erxregs = hp->erxregs; 126262306a36Sopenharmony_ci void __iomem *bregs = hp->bigmacregs; 126362306a36Sopenharmony_ci void __iomem *tregs = hp->tcvregs; 126462306a36Sopenharmony_ci const char *bursts = "64"; 126562306a36Sopenharmony_ci u32 regtmp, rxcfg; 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci /* If auto-negotiation timer is running, kill it. */ 126862306a36Sopenharmony_ci del_timer(&hp->happy_timer); 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci HMD("happy_flags[%08x]\n", hp->happy_flags); 127162306a36Sopenharmony_ci if (!(hp->happy_flags & HFLAG_INIT)) { 127262306a36Sopenharmony_ci HMD("set HFLAG_INIT\n"); 127362306a36Sopenharmony_ci hp->happy_flags |= HFLAG_INIT; 127462306a36Sopenharmony_ci happy_meal_get_counters(hp, bregs); 127562306a36Sopenharmony_ci } 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci /* Stop transmitter and receiver. */ 127862306a36Sopenharmony_ci HMD("to happy_meal_stop\n"); 127962306a36Sopenharmony_ci happy_meal_stop(hp, gregs); 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci /* Alloc and reset the tx/rx descriptor chains. */ 128262306a36Sopenharmony_ci HMD("to happy_meal_init_rings\n"); 128362306a36Sopenharmony_ci happy_meal_init_rings(hp); 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci /* See if we can enable the MIF frame on this card to speak to the DP83840. */ 128662306a36Sopenharmony_ci if (hp->happy_flags & HFLAG_FENABLE) { 128762306a36Sopenharmony_ci HMD("use frame old[%08x]\n", 128862306a36Sopenharmony_ci hme_read32(hp, tregs + TCVR_CFG)); 128962306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, 129062306a36Sopenharmony_ci hme_read32(hp, tregs + TCVR_CFG) & ~(TCV_CFG_BENABLE)); 129162306a36Sopenharmony_ci } else { 129262306a36Sopenharmony_ci HMD("use bitbang old[%08x]\n", 129362306a36Sopenharmony_ci hme_read32(hp, tregs + TCVR_CFG)); 129462306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, 129562306a36Sopenharmony_ci hme_read32(hp, tregs + TCVR_CFG) | TCV_CFG_BENABLE); 129662306a36Sopenharmony_ci } 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci /* Check the state of the transceiver. */ 129962306a36Sopenharmony_ci HMD("to happy_meal_transceiver_check\n"); 130062306a36Sopenharmony_ci happy_meal_transceiver_check(hp, tregs); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci /* Put the Big Mac into a sane state. */ 130362306a36Sopenharmony_ci switch(hp->tcvr_type) { 130462306a36Sopenharmony_ci case none: 130562306a36Sopenharmony_ci /* Cannot operate if we don't know the transceiver type! */ 130662306a36Sopenharmony_ci HMD("AAIEEE no transceiver type, EAGAIN\n"); 130762306a36Sopenharmony_ci return -EAGAIN; 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci case internal: 131062306a36Sopenharmony_ci /* Using the MII buffers. */ 131162306a36Sopenharmony_ci HMD("internal, using MII\n"); 131262306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_XIFCFG, 0); 131362306a36Sopenharmony_ci break; 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci case external: 131662306a36Sopenharmony_ci /* Not using the MII, disable it. */ 131762306a36Sopenharmony_ci HMD("external, disable MII\n"); 131862306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_XIFCFG, BIGMAC_XCFG_MIIDISAB); 131962306a36Sopenharmony_ci break; 132062306a36Sopenharmony_ci } 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci if (happy_meal_tcvr_reset(hp, tregs)) 132362306a36Sopenharmony_ci return -EAGAIN; 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci /* Reset the Happy Meal Big Mac transceiver and the receiver. */ 132662306a36Sopenharmony_ci HMD("tx/rx reset\n"); 132762306a36Sopenharmony_ci happy_meal_tx_reset(hp, bregs); 132862306a36Sopenharmony_ci happy_meal_rx_reset(hp, bregs); 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci /* Set jam size and inter-packet gaps to reasonable defaults. */ 133162306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_JSIZE, DEFAULT_JAMSIZE); 133262306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_IGAP1, DEFAULT_IPG1); 133362306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_IGAP2, DEFAULT_IPG2); 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci /* Load up the MAC address and random seed. */ 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci /* The docs recommend to use the 10LSB of our MAC here. */ 133862306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_RSEED, ((e[5] | e[4]<<8)&0x3ff)); 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_MACADDR2, ((e[4] << 8) | e[5])); 134162306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_MACADDR1, ((e[2] << 8) | e[3])); 134262306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_MACADDR0, ((e[0] << 8) | e[1])); 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci if ((hp->dev->flags & IFF_ALLMULTI) || 134562306a36Sopenharmony_ci (netdev_mc_count(hp->dev) > 64)) { 134662306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE0, 0xffff); 134762306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE1, 0xffff); 134862306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE2, 0xffff); 134962306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE3, 0xffff); 135062306a36Sopenharmony_ci } else if ((hp->dev->flags & IFF_PROMISC) == 0) { 135162306a36Sopenharmony_ci u16 hash_table[4]; 135262306a36Sopenharmony_ci struct netdev_hw_addr *ha; 135362306a36Sopenharmony_ci u32 crc; 135462306a36Sopenharmony_ci 135562306a36Sopenharmony_ci memset(hash_table, 0, sizeof(hash_table)); 135662306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, hp->dev) { 135762306a36Sopenharmony_ci crc = ether_crc_le(6, ha->addr); 135862306a36Sopenharmony_ci crc >>= 26; 135962306a36Sopenharmony_ci hash_table[crc >> 4] |= 1 << (crc & 0xf); 136062306a36Sopenharmony_ci } 136162306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE0, hash_table[0]); 136262306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE1, hash_table[1]); 136362306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE2, hash_table[2]); 136462306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE3, hash_table[3]); 136562306a36Sopenharmony_ci } else { 136662306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE3, 0); 136762306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE2, 0); 136862306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE1, 0); 136962306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE0, 0); 137062306a36Sopenharmony_ci } 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci /* Set the RX and TX ring ptrs. */ 137362306a36Sopenharmony_ci HMD("ring ptrs rxr[%08x] txr[%08x]\n", 137462306a36Sopenharmony_ci ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)), 137562306a36Sopenharmony_ci ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_txd, 0))); 137662306a36Sopenharmony_ci hme_write32(hp, erxregs + ERX_RING, 137762306a36Sopenharmony_ci ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0))); 137862306a36Sopenharmony_ci hme_write32(hp, etxregs + ETX_RING, 137962306a36Sopenharmony_ci ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_txd, 0))); 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci /* Parity issues in the ERX unit of some HME revisions can cause some 138262306a36Sopenharmony_ci * registers to not be written unless their parity is even. Detect such 138362306a36Sopenharmony_ci * lost writes and simply rewrite with a low bit set (which will be ignored 138462306a36Sopenharmony_ci * since the rxring needs to be 2K aligned). 138562306a36Sopenharmony_ci */ 138662306a36Sopenharmony_ci if (hme_read32(hp, erxregs + ERX_RING) != 138762306a36Sopenharmony_ci ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0))) 138862306a36Sopenharmony_ci hme_write32(hp, erxregs + ERX_RING, 138962306a36Sopenharmony_ci ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)) 139062306a36Sopenharmony_ci | 0x4); 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci /* Set the supported burst sizes. */ 139362306a36Sopenharmony_ci#ifndef CONFIG_SPARC 139462306a36Sopenharmony_ci /* It is always PCI and can handle 64byte bursts. */ 139562306a36Sopenharmony_ci hme_write32(hp, gregs + GREG_CFG, GREG_CFG_BURST64); 139662306a36Sopenharmony_ci#else 139762306a36Sopenharmony_ci if ((hp->happy_bursts & DMA_BURST64) && 139862306a36Sopenharmony_ci ((hp->happy_flags & HFLAG_PCI) != 0 139962306a36Sopenharmony_ci#ifdef CONFIG_SBUS 140062306a36Sopenharmony_ci || sbus_can_burst64() 140162306a36Sopenharmony_ci#endif 140262306a36Sopenharmony_ci || 0)) { 140362306a36Sopenharmony_ci u32 gcfg = GREG_CFG_BURST64; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci /* I have no idea if I should set the extended 140662306a36Sopenharmony_ci * transfer mode bit for Cheerio, so for now I 140762306a36Sopenharmony_ci * do not. -DaveM 140862306a36Sopenharmony_ci */ 140962306a36Sopenharmony_ci#ifdef CONFIG_SBUS 141062306a36Sopenharmony_ci if ((hp->happy_flags & HFLAG_PCI) == 0) { 141162306a36Sopenharmony_ci struct platform_device *op = hp->happy_dev; 141262306a36Sopenharmony_ci if (sbus_can_dma_64bit()) { 141362306a36Sopenharmony_ci sbus_set_sbus64(&op->dev, 141462306a36Sopenharmony_ci hp->happy_bursts); 141562306a36Sopenharmony_ci gcfg |= GREG_CFG_64BIT; 141662306a36Sopenharmony_ci } 141762306a36Sopenharmony_ci } 141862306a36Sopenharmony_ci#endif 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci bursts = "64"; 142162306a36Sopenharmony_ci hme_write32(hp, gregs + GREG_CFG, gcfg); 142262306a36Sopenharmony_ci } else if (hp->happy_bursts & DMA_BURST32) { 142362306a36Sopenharmony_ci bursts = "32"; 142462306a36Sopenharmony_ci hme_write32(hp, gregs + GREG_CFG, GREG_CFG_BURST32); 142562306a36Sopenharmony_ci } else if (hp->happy_bursts & DMA_BURST16) { 142662306a36Sopenharmony_ci bursts = "16"; 142762306a36Sopenharmony_ci hme_write32(hp, gregs + GREG_CFG, GREG_CFG_BURST16); 142862306a36Sopenharmony_ci } else { 142962306a36Sopenharmony_ci bursts = "XXX"; 143062306a36Sopenharmony_ci hme_write32(hp, gregs + GREG_CFG, 0); 143162306a36Sopenharmony_ci } 143262306a36Sopenharmony_ci#endif /* CONFIG_SPARC */ 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci HMD("old[%08x] bursts<%s>\n", 143562306a36Sopenharmony_ci hme_read32(hp, gregs + GREG_CFG), bursts); 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci /* Turn off interrupts we do not want to hear. */ 143862306a36Sopenharmony_ci hme_write32(hp, gregs + GREG_IMASK, 143962306a36Sopenharmony_ci (GREG_IMASK_GOTFRAME | GREG_IMASK_RCNTEXP | 144062306a36Sopenharmony_ci GREG_IMASK_SENTFRAME | GREG_IMASK_TXPERR)); 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci /* Set the transmit ring buffer size. */ 144362306a36Sopenharmony_ci HMD("tx rsize=%d oreg[%08x]\n", (int)TX_RING_SIZE, 144462306a36Sopenharmony_ci hme_read32(hp, etxregs + ETX_RSIZE)); 144562306a36Sopenharmony_ci hme_write32(hp, etxregs + ETX_RSIZE, (TX_RING_SIZE >> ETX_RSIZE_SHIFT) - 1); 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci /* Enable transmitter DVMA. */ 144862306a36Sopenharmony_ci HMD("tx dma enable old[%08x]\n", hme_read32(hp, etxregs + ETX_CFG)); 144962306a36Sopenharmony_ci hme_write32(hp, etxregs + ETX_CFG, 145062306a36Sopenharmony_ci hme_read32(hp, etxregs + ETX_CFG) | ETX_CFG_DMAENABLE); 145162306a36Sopenharmony_ci 145262306a36Sopenharmony_ci /* This chip really rots, for the receiver sometimes when you 145362306a36Sopenharmony_ci * write to its control registers not all the bits get there 145462306a36Sopenharmony_ci * properly. I cannot think of a sane way to provide complete 145562306a36Sopenharmony_ci * coverage for this hardware bug yet. 145662306a36Sopenharmony_ci */ 145762306a36Sopenharmony_ci HMD("erx regs bug old[%08x]\n", 145862306a36Sopenharmony_ci hme_read32(hp, erxregs + ERX_CFG)); 145962306a36Sopenharmony_ci hme_write32(hp, erxregs + ERX_CFG, ERX_CFG_DEFAULT(RX_OFFSET)); 146062306a36Sopenharmony_ci regtmp = hme_read32(hp, erxregs + ERX_CFG); 146162306a36Sopenharmony_ci hme_write32(hp, erxregs + ERX_CFG, ERX_CFG_DEFAULT(RX_OFFSET)); 146262306a36Sopenharmony_ci if (hme_read32(hp, erxregs + ERX_CFG) != ERX_CFG_DEFAULT(RX_OFFSET)) { 146362306a36Sopenharmony_ci netdev_err(hp->dev, 146462306a36Sopenharmony_ci "Eieee, rx config register gets greasy fries.\n"); 146562306a36Sopenharmony_ci netdev_err(hp->dev, 146662306a36Sopenharmony_ci "Trying to set %08x, reread gives %08x\n", 146762306a36Sopenharmony_ci ERX_CFG_DEFAULT(RX_OFFSET), regtmp); 146862306a36Sopenharmony_ci /* XXX Should return failure here... */ 146962306a36Sopenharmony_ci } 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci /* Enable Big Mac hash table filter. */ 147262306a36Sopenharmony_ci HMD("enable hash rx_cfg_old[%08x]\n", 147362306a36Sopenharmony_ci hme_read32(hp, bregs + BMAC_RXCFG)); 147462306a36Sopenharmony_ci rxcfg = BIGMAC_RXCFG_HENABLE | BIGMAC_RXCFG_REJME; 147562306a36Sopenharmony_ci if (hp->dev->flags & IFF_PROMISC) 147662306a36Sopenharmony_ci rxcfg |= BIGMAC_RXCFG_PMISC; 147762306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_RXCFG, rxcfg); 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci /* Let the bits settle in the chip. */ 148062306a36Sopenharmony_ci udelay(10); 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci /* Ok, configure the Big Mac transmitter. */ 148362306a36Sopenharmony_ci HMD("BIGMAC init\n"); 148462306a36Sopenharmony_ci regtmp = 0; 148562306a36Sopenharmony_ci if (hp->happy_flags & HFLAG_FULL) 148662306a36Sopenharmony_ci regtmp |= BIGMAC_TXCFG_FULLDPLX; 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci /* Don't turn on the "don't give up" bit for now. It could cause hme 148962306a36Sopenharmony_ci * to deadlock with the PHY if a Jabber occurs. 149062306a36Sopenharmony_ci */ 149162306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_TXCFG, regtmp /*| BIGMAC_TXCFG_DGIVEUP*/); 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci /* Give up after 16 TX attempts. */ 149462306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_ALIMIT, 16); 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci /* Enable the output drivers no matter what. */ 149762306a36Sopenharmony_ci regtmp = BIGMAC_XCFG_ODENABLE; 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci /* If card can do lance mode, enable it. */ 150062306a36Sopenharmony_ci if (hp->happy_flags & HFLAG_LANCE) 150162306a36Sopenharmony_ci regtmp |= (DEFAULT_IPG0 << 5) | BIGMAC_XCFG_LANCE; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci /* Disable the MII buffers if using external transceiver. */ 150462306a36Sopenharmony_ci if (hp->tcvr_type == external) 150562306a36Sopenharmony_ci regtmp |= BIGMAC_XCFG_MIIDISAB; 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci HMD("XIF config old[%08x]\n", hme_read32(hp, bregs + BMAC_XIFCFG)); 150862306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_XIFCFG, regtmp); 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci /* Start things up. */ 151162306a36Sopenharmony_ci HMD("tx old[%08x] and rx [%08x] ON!\n", 151262306a36Sopenharmony_ci hme_read32(hp, bregs + BMAC_TXCFG), 151362306a36Sopenharmony_ci hme_read32(hp, bregs + BMAC_RXCFG)); 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci /* Set larger TX/RX size to allow for 802.1q */ 151662306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_TXMAX, ETH_FRAME_LEN + 8); 151762306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_RXMAX, ETH_FRAME_LEN + 8); 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_TXCFG, 152062306a36Sopenharmony_ci hme_read32(hp, bregs + BMAC_TXCFG) | BIGMAC_TXCFG_ENABLE); 152162306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_RXCFG, 152262306a36Sopenharmony_ci hme_read32(hp, bregs + BMAC_RXCFG) | BIGMAC_RXCFG_ENABLE); 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci /* Get the autonegotiation started, and the watch timer ticking. */ 152562306a36Sopenharmony_ci happy_meal_begin_auto_negotiation(hp, tregs, NULL); 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci /* Success. */ 152862306a36Sopenharmony_ci return 0; 152962306a36Sopenharmony_ci} 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci/* hp->happy_lock must be held */ 153262306a36Sopenharmony_cistatic void happy_meal_set_initial_advertisement(struct happy_meal *hp) 153362306a36Sopenharmony_ci{ 153462306a36Sopenharmony_ci void __iomem *tregs = hp->tcvregs; 153562306a36Sopenharmony_ci void __iomem *bregs = hp->bigmacregs; 153662306a36Sopenharmony_ci void __iomem *gregs = hp->gregs; 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci happy_meal_stop(hp, gregs); 153962306a36Sopenharmony_ci if (hp->happy_flags & HFLAG_FENABLE) 154062306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, 154162306a36Sopenharmony_ci hme_read32(hp, tregs + TCVR_CFG) & ~(TCV_CFG_BENABLE)); 154262306a36Sopenharmony_ci else 154362306a36Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, 154462306a36Sopenharmony_ci hme_read32(hp, tregs + TCVR_CFG) | TCV_CFG_BENABLE); 154562306a36Sopenharmony_ci happy_meal_transceiver_check(hp, tregs); 154662306a36Sopenharmony_ci switch(hp->tcvr_type) { 154762306a36Sopenharmony_ci case none: 154862306a36Sopenharmony_ci return; 154962306a36Sopenharmony_ci case internal: 155062306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_XIFCFG, 0); 155162306a36Sopenharmony_ci break; 155262306a36Sopenharmony_ci case external: 155362306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_XIFCFG, BIGMAC_XCFG_MIIDISAB); 155462306a36Sopenharmony_ci break; 155562306a36Sopenharmony_ci } 155662306a36Sopenharmony_ci if (happy_meal_tcvr_reset(hp, tregs)) 155762306a36Sopenharmony_ci return; 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci /* Latch PHY registers as of now. */ 156062306a36Sopenharmony_ci hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, MII_BMSR); 156162306a36Sopenharmony_ci hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, MII_ADVERTISE); 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci /* Advertise everything we can support. */ 156462306a36Sopenharmony_ci if (hp->sw_bmsr & BMSR_10HALF) 156562306a36Sopenharmony_ci hp->sw_advertise |= (ADVERTISE_10HALF); 156662306a36Sopenharmony_ci else 156762306a36Sopenharmony_ci hp->sw_advertise &= ~(ADVERTISE_10HALF); 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci if (hp->sw_bmsr & BMSR_10FULL) 157062306a36Sopenharmony_ci hp->sw_advertise |= (ADVERTISE_10FULL); 157162306a36Sopenharmony_ci else 157262306a36Sopenharmony_ci hp->sw_advertise &= ~(ADVERTISE_10FULL); 157362306a36Sopenharmony_ci if (hp->sw_bmsr & BMSR_100HALF) 157462306a36Sopenharmony_ci hp->sw_advertise |= (ADVERTISE_100HALF); 157562306a36Sopenharmony_ci else 157662306a36Sopenharmony_ci hp->sw_advertise &= ~(ADVERTISE_100HALF); 157762306a36Sopenharmony_ci if (hp->sw_bmsr & BMSR_100FULL) 157862306a36Sopenharmony_ci hp->sw_advertise |= (ADVERTISE_100FULL); 157962306a36Sopenharmony_ci else 158062306a36Sopenharmony_ci hp->sw_advertise &= ~(ADVERTISE_100FULL); 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci /* Update the PHY advertisement register. */ 158362306a36Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_ADVERTISE, hp->sw_advertise); 158462306a36Sopenharmony_ci} 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci/* Once status is latched (by happy_meal_interrupt) it is cleared by 158762306a36Sopenharmony_ci * the hardware, so we cannot re-read it and get a correct value. 158862306a36Sopenharmony_ci * 158962306a36Sopenharmony_ci * hp->happy_lock must be held 159062306a36Sopenharmony_ci */ 159162306a36Sopenharmony_cistatic int happy_meal_is_not_so_happy(struct happy_meal *hp, u32 status) 159262306a36Sopenharmony_ci{ 159362306a36Sopenharmony_ci int reset = 0; 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci /* Only print messages for non-counter related interrupts. */ 159662306a36Sopenharmony_ci if (status & (GREG_STAT_STSTERR | GREG_STAT_TFIFO_UND | 159762306a36Sopenharmony_ci GREG_STAT_MAXPKTERR | GREG_STAT_RXERR | 159862306a36Sopenharmony_ci GREG_STAT_RXPERR | GREG_STAT_RXTERR | GREG_STAT_EOPERR | 159962306a36Sopenharmony_ci GREG_STAT_MIFIRQ | GREG_STAT_TXEACK | GREG_STAT_TXLERR | 160062306a36Sopenharmony_ci GREG_STAT_TXPERR | GREG_STAT_TXTERR | GREG_STAT_SLVERR | 160162306a36Sopenharmony_ci GREG_STAT_SLVPERR)) 160262306a36Sopenharmony_ci netdev_err(hp->dev, 160362306a36Sopenharmony_ci "Error interrupt for happy meal, status = %08x\n", 160462306a36Sopenharmony_ci status); 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci if (status & GREG_STAT_RFIFOVF) { 160762306a36Sopenharmony_ci /* Receive FIFO overflow is harmless and the hardware will take 160862306a36Sopenharmony_ci care of it, just some packets are lost. Who cares. */ 160962306a36Sopenharmony_ci netdev_dbg(hp->dev, "Happy Meal receive FIFO overflow.\n"); 161062306a36Sopenharmony_ci } 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci if (status & GREG_STAT_STSTERR) { 161362306a36Sopenharmony_ci /* BigMAC SQE link test failed. */ 161462306a36Sopenharmony_ci netdev_err(hp->dev, "Happy Meal BigMAC SQE test failed.\n"); 161562306a36Sopenharmony_ci reset = 1; 161662306a36Sopenharmony_ci } 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci if (status & GREG_STAT_TFIFO_UND) { 161962306a36Sopenharmony_ci /* Transmit FIFO underrun, again DMA error likely. */ 162062306a36Sopenharmony_ci netdev_err(hp->dev, 162162306a36Sopenharmony_ci "Happy Meal transmitter FIFO underrun, DMA error.\n"); 162262306a36Sopenharmony_ci reset = 1; 162362306a36Sopenharmony_ci } 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci if (status & GREG_STAT_MAXPKTERR) { 162662306a36Sopenharmony_ci /* Driver error, tried to transmit something larger 162762306a36Sopenharmony_ci * than ethernet max mtu. 162862306a36Sopenharmony_ci */ 162962306a36Sopenharmony_ci netdev_err(hp->dev, "Happy Meal MAX Packet size error.\n"); 163062306a36Sopenharmony_ci reset = 1; 163162306a36Sopenharmony_ci } 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci if (status & GREG_STAT_NORXD) { 163462306a36Sopenharmony_ci /* This is harmless, it just means the system is 163562306a36Sopenharmony_ci * quite loaded and the incoming packet rate was 163662306a36Sopenharmony_ci * faster than the interrupt handler could keep up 163762306a36Sopenharmony_ci * with. 163862306a36Sopenharmony_ci */ 163962306a36Sopenharmony_ci netdev_info(hp->dev, 164062306a36Sopenharmony_ci "Happy Meal out of receive descriptors, packet dropped.\n"); 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci 164362306a36Sopenharmony_ci if (status & (GREG_STAT_RXERR|GREG_STAT_RXPERR|GREG_STAT_RXTERR)) { 164462306a36Sopenharmony_ci /* All sorts of DMA receive errors. */ 164562306a36Sopenharmony_ci netdev_err(hp->dev, "Happy Meal rx DMA errors [ %s%s%s]\n", 164662306a36Sopenharmony_ci status & GREG_STAT_RXERR ? "GenericError " : "", 164762306a36Sopenharmony_ci status & GREG_STAT_RXPERR ? "ParityError " : "", 164862306a36Sopenharmony_ci status & GREG_STAT_RXTERR ? "RxTagBotch " : ""); 164962306a36Sopenharmony_ci reset = 1; 165062306a36Sopenharmony_ci } 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci if (status & GREG_STAT_EOPERR) { 165362306a36Sopenharmony_ci /* Driver bug, didn't set EOP bit in tx descriptor given 165462306a36Sopenharmony_ci * to the happy meal. 165562306a36Sopenharmony_ci */ 165662306a36Sopenharmony_ci netdev_err(hp->dev, 165762306a36Sopenharmony_ci "EOP not set in happy meal transmit descriptor!\n"); 165862306a36Sopenharmony_ci reset = 1; 165962306a36Sopenharmony_ci } 166062306a36Sopenharmony_ci 166162306a36Sopenharmony_ci if (status & GREG_STAT_MIFIRQ) { 166262306a36Sopenharmony_ci /* MIF signalled an interrupt, were we polling it? */ 166362306a36Sopenharmony_ci netdev_err(hp->dev, "Happy Meal MIF interrupt.\n"); 166462306a36Sopenharmony_ci } 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci if (status & 166762306a36Sopenharmony_ci (GREG_STAT_TXEACK|GREG_STAT_TXLERR|GREG_STAT_TXPERR|GREG_STAT_TXTERR)) { 166862306a36Sopenharmony_ci /* All sorts of transmit DMA errors. */ 166962306a36Sopenharmony_ci netdev_err(hp->dev, "Happy Meal tx DMA errors [ %s%s%s%s]\n", 167062306a36Sopenharmony_ci status & GREG_STAT_TXEACK ? "GenericError " : "", 167162306a36Sopenharmony_ci status & GREG_STAT_TXLERR ? "LateError " : "", 167262306a36Sopenharmony_ci status & GREG_STAT_TXPERR ? "ParityError " : "", 167362306a36Sopenharmony_ci status & GREG_STAT_TXTERR ? "TagBotch " : ""); 167462306a36Sopenharmony_ci reset = 1; 167562306a36Sopenharmony_ci } 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci if (status & (GREG_STAT_SLVERR|GREG_STAT_SLVPERR)) { 167862306a36Sopenharmony_ci /* Bus or parity error when cpu accessed happy meal registers 167962306a36Sopenharmony_ci * or it's internal FIFO's. Should never see this. 168062306a36Sopenharmony_ci */ 168162306a36Sopenharmony_ci netdev_err(hp->dev, 168262306a36Sopenharmony_ci "Happy Meal register access SBUS slave (%s) error.\n", 168362306a36Sopenharmony_ci (status & GREG_STAT_SLVPERR) ? "parity" : "generic"); 168462306a36Sopenharmony_ci reset = 1; 168562306a36Sopenharmony_ci } 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci if (reset) { 168862306a36Sopenharmony_ci netdev_notice(hp->dev, "Resetting...\n"); 168962306a36Sopenharmony_ci happy_meal_init(hp); 169062306a36Sopenharmony_ci return 1; 169162306a36Sopenharmony_ci } 169262306a36Sopenharmony_ci return 0; 169362306a36Sopenharmony_ci} 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci/* hp->happy_lock must be held */ 169662306a36Sopenharmony_cistatic void happy_meal_tx(struct happy_meal *hp) 169762306a36Sopenharmony_ci{ 169862306a36Sopenharmony_ci struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0]; 169962306a36Sopenharmony_ci struct happy_meal_txd *this; 170062306a36Sopenharmony_ci struct net_device *dev = hp->dev; 170162306a36Sopenharmony_ci int elem; 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci elem = hp->tx_old; 170462306a36Sopenharmony_ci while (elem != hp->tx_new) { 170562306a36Sopenharmony_ci struct sk_buff *skb; 170662306a36Sopenharmony_ci u32 flags, dma_addr, dma_len; 170762306a36Sopenharmony_ci int frag; 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_ci netdev_vdbg(hp->dev, "TX[%d]\n", elem); 171062306a36Sopenharmony_ci this = &txbase[elem]; 171162306a36Sopenharmony_ci flags = hme_read_desc32(hp, &this->tx_flags); 171262306a36Sopenharmony_ci if (flags & TXFLAG_OWN) 171362306a36Sopenharmony_ci break; 171462306a36Sopenharmony_ci skb = hp->tx_skbs[elem]; 171562306a36Sopenharmony_ci if (skb_shinfo(skb)->nr_frags) { 171662306a36Sopenharmony_ci int last; 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci last = elem + skb_shinfo(skb)->nr_frags; 171962306a36Sopenharmony_ci last &= (TX_RING_SIZE - 1); 172062306a36Sopenharmony_ci flags = hme_read_desc32(hp, &txbase[last].tx_flags); 172162306a36Sopenharmony_ci if (flags & TXFLAG_OWN) 172262306a36Sopenharmony_ci break; 172362306a36Sopenharmony_ci } 172462306a36Sopenharmony_ci hp->tx_skbs[elem] = NULL; 172562306a36Sopenharmony_ci dev->stats.tx_bytes += skb->len; 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) { 172862306a36Sopenharmony_ci dma_addr = hme_read_desc32(hp, &this->tx_addr); 172962306a36Sopenharmony_ci dma_len = hme_read_desc32(hp, &this->tx_flags); 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci dma_len &= TXFLAG_SIZE; 173262306a36Sopenharmony_ci if (!frag) 173362306a36Sopenharmony_ci dma_unmap_single(hp->dma_dev, dma_addr, dma_len, DMA_TO_DEVICE); 173462306a36Sopenharmony_ci else 173562306a36Sopenharmony_ci dma_unmap_page(hp->dma_dev, dma_addr, dma_len, DMA_TO_DEVICE); 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci elem = NEXT_TX(elem); 173862306a36Sopenharmony_ci this = &txbase[elem]; 173962306a36Sopenharmony_ci } 174062306a36Sopenharmony_ci 174162306a36Sopenharmony_ci dev_consume_skb_irq(skb); 174262306a36Sopenharmony_ci dev->stats.tx_packets++; 174362306a36Sopenharmony_ci } 174462306a36Sopenharmony_ci hp->tx_old = elem; 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci if (netif_queue_stopped(dev) && 174762306a36Sopenharmony_ci TX_BUFFS_AVAIL(hp) > (MAX_SKB_FRAGS + 1)) 174862306a36Sopenharmony_ci netif_wake_queue(dev); 174962306a36Sopenharmony_ci} 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_ci/* Originally I used to handle the allocation failure by just giving back just 175262306a36Sopenharmony_ci * that one ring buffer to the happy meal. Problem is that usually when that 175362306a36Sopenharmony_ci * condition is triggered, the happy meal expects you to do something reasonable 175462306a36Sopenharmony_ci * with all of the packets it has DMA'd in. So now I just drop the entire 175562306a36Sopenharmony_ci * ring when we cannot get a new skb and give them all back to the happy meal, 175662306a36Sopenharmony_ci * maybe things will be "happier" now. 175762306a36Sopenharmony_ci * 175862306a36Sopenharmony_ci * hp->happy_lock must be held 175962306a36Sopenharmony_ci */ 176062306a36Sopenharmony_cistatic void happy_meal_rx(struct happy_meal *hp, struct net_device *dev) 176162306a36Sopenharmony_ci{ 176262306a36Sopenharmony_ci struct happy_meal_rxd *rxbase = &hp->happy_block->happy_meal_rxd[0]; 176362306a36Sopenharmony_ci struct happy_meal_rxd *this; 176462306a36Sopenharmony_ci int elem = hp->rx_new, drops = 0; 176562306a36Sopenharmony_ci u32 flags; 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci this = &rxbase[elem]; 176862306a36Sopenharmony_ci while (!((flags = hme_read_desc32(hp, &this->rx_flags)) & RXFLAG_OWN)) { 176962306a36Sopenharmony_ci struct sk_buff *skb; 177062306a36Sopenharmony_ci int len = flags >> 16; 177162306a36Sopenharmony_ci u16 csum = flags & RXFLAG_CSUM; 177262306a36Sopenharmony_ci u32 dma_addr = hme_read_desc32(hp, &this->rx_addr); 177362306a36Sopenharmony_ci 177462306a36Sopenharmony_ci /* Check for errors. */ 177562306a36Sopenharmony_ci if ((len < ETH_ZLEN) || (flags & RXFLAG_OVERFLOW)) { 177662306a36Sopenharmony_ci netdev_vdbg(dev, "RX[%d ERR(%08x)]", elem, flags); 177762306a36Sopenharmony_ci dev->stats.rx_errors++; 177862306a36Sopenharmony_ci if (len < ETH_ZLEN) 177962306a36Sopenharmony_ci dev->stats.rx_length_errors++; 178062306a36Sopenharmony_ci if (len & (RXFLAG_OVERFLOW >> 16)) { 178162306a36Sopenharmony_ci dev->stats.rx_over_errors++; 178262306a36Sopenharmony_ci dev->stats.rx_fifo_errors++; 178362306a36Sopenharmony_ci } 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci /* Return it to the Happy meal. */ 178662306a36Sopenharmony_ci drop_it: 178762306a36Sopenharmony_ci dev->stats.rx_dropped++; 178862306a36Sopenharmony_ci hme_write_rxd(hp, this, 178962306a36Sopenharmony_ci (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)), 179062306a36Sopenharmony_ci dma_addr); 179162306a36Sopenharmony_ci goto next; 179262306a36Sopenharmony_ci } 179362306a36Sopenharmony_ci skb = hp->rx_skbs[elem]; 179462306a36Sopenharmony_ci if (len > RX_COPY_THRESHOLD) { 179562306a36Sopenharmony_ci struct sk_buff *new_skb; 179662306a36Sopenharmony_ci u32 mapping; 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci /* Now refill the entry, if we can. */ 179962306a36Sopenharmony_ci new_skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); 180062306a36Sopenharmony_ci if (new_skb == NULL) { 180162306a36Sopenharmony_ci drops++; 180262306a36Sopenharmony_ci goto drop_it; 180362306a36Sopenharmony_ci } 180462306a36Sopenharmony_ci skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET + 4)); 180562306a36Sopenharmony_ci mapping = dma_map_single(hp->dma_dev, new_skb->data, 180662306a36Sopenharmony_ci RX_BUF_ALLOC_SIZE, 180762306a36Sopenharmony_ci DMA_FROM_DEVICE); 180862306a36Sopenharmony_ci if (unlikely(dma_mapping_error(hp->dma_dev, mapping))) { 180962306a36Sopenharmony_ci dev_kfree_skb_any(new_skb); 181062306a36Sopenharmony_ci drops++; 181162306a36Sopenharmony_ci goto drop_it; 181262306a36Sopenharmony_ci } 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci dma_unmap_single(hp->dma_dev, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROM_DEVICE); 181562306a36Sopenharmony_ci hp->rx_skbs[elem] = new_skb; 181662306a36Sopenharmony_ci hme_write_rxd(hp, this, 181762306a36Sopenharmony_ci (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)), 181862306a36Sopenharmony_ci mapping); 181962306a36Sopenharmony_ci skb_reserve(new_skb, RX_OFFSET); 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci /* Trim the original skb for the netif. */ 182262306a36Sopenharmony_ci skb_trim(skb, len); 182362306a36Sopenharmony_ci } else { 182462306a36Sopenharmony_ci struct sk_buff *copy_skb = netdev_alloc_skb(dev, len + 2); 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci if (copy_skb == NULL) { 182762306a36Sopenharmony_ci drops++; 182862306a36Sopenharmony_ci goto drop_it; 182962306a36Sopenharmony_ci } 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci skb_reserve(copy_skb, 2); 183262306a36Sopenharmony_ci skb_put(copy_skb, len); 183362306a36Sopenharmony_ci dma_sync_single_for_cpu(hp->dma_dev, dma_addr, len + 2, DMA_FROM_DEVICE); 183462306a36Sopenharmony_ci skb_copy_from_linear_data(skb, copy_skb->data, len); 183562306a36Sopenharmony_ci dma_sync_single_for_device(hp->dma_dev, dma_addr, len + 2, DMA_FROM_DEVICE); 183662306a36Sopenharmony_ci /* Reuse original ring buffer. */ 183762306a36Sopenharmony_ci hme_write_rxd(hp, this, 183862306a36Sopenharmony_ci (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)), 183962306a36Sopenharmony_ci dma_addr); 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci skb = copy_skb; 184262306a36Sopenharmony_ci } 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci /* This card is _fucking_ hot... */ 184562306a36Sopenharmony_ci skb->csum = csum_unfold(~(__force __sum16)htons(csum)); 184662306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_COMPLETE; 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci netdev_vdbg(dev, "RX[%d len=%d csum=%4x]", elem, len, csum); 184962306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 185062306a36Sopenharmony_ci netif_rx(skb); 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci dev->stats.rx_packets++; 185362306a36Sopenharmony_ci dev->stats.rx_bytes += len; 185462306a36Sopenharmony_ci next: 185562306a36Sopenharmony_ci elem = NEXT_RX(elem); 185662306a36Sopenharmony_ci this = &rxbase[elem]; 185762306a36Sopenharmony_ci } 185862306a36Sopenharmony_ci hp->rx_new = elem; 185962306a36Sopenharmony_ci if (drops) 186062306a36Sopenharmony_ci netdev_info(hp->dev, "Memory squeeze, deferring packet.\n"); 186162306a36Sopenharmony_ci} 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_cistatic irqreturn_t happy_meal_interrupt(int irq, void *dev_id) 186462306a36Sopenharmony_ci{ 186562306a36Sopenharmony_ci struct net_device *dev = dev_id; 186662306a36Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 186762306a36Sopenharmony_ci u32 happy_status = hme_read32(hp, hp->gregs + GREG_STAT); 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci HMD("status=%08x\n", happy_status); 187062306a36Sopenharmony_ci if (!happy_status) 187162306a36Sopenharmony_ci return IRQ_NONE; 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci spin_lock(&hp->happy_lock); 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci if (happy_status & GREG_STAT_ERRORS) { 187662306a36Sopenharmony_ci if (happy_meal_is_not_so_happy(hp, /* un- */ happy_status)) 187762306a36Sopenharmony_ci goto out; 187862306a36Sopenharmony_ci } 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci if (happy_status & GREG_STAT_TXALL) 188162306a36Sopenharmony_ci happy_meal_tx(hp); 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci if (happy_status & GREG_STAT_RXTOHOST) 188462306a36Sopenharmony_ci happy_meal_rx(hp, dev); 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci HMD("done\n"); 188762306a36Sopenharmony_ciout: 188862306a36Sopenharmony_ci spin_unlock(&hp->happy_lock); 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci return IRQ_HANDLED; 189162306a36Sopenharmony_ci} 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_cistatic int happy_meal_open(struct net_device *dev) 189462306a36Sopenharmony_ci{ 189562306a36Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 189662306a36Sopenharmony_ci int res; 189762306a36Sopenharmony_ci 189862306a36Sopenharmony_ci res = request_irq(hp->irq, happy_meal_interrupt, IRQF_SHARED, 189962306a36Sopenharmony_ci dev->name, dev); 190062306a36Sopenharmony_ci if (res) { 190162306a36Sopenharmony_ci netdev_err(dev, "Can't order irq %d to go.\n", hp->irq); 190262306a36Sopenharmony_ci return res; 190362306a36Sopenharmony_ci } 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci HMD("to happy_meal_init\n"); 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 190862306a36Sopenharmony_ci res = happy_meal_init(hp); 190962306a36Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci if (res) 191262306a36Sopenharmony_ci free_irq(hp->irq, dev); 191362306a36Sopenharmony_ci return res; 191462306a36Sopenharmony_ci} 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_cistatic int happy_meal_close(struct net_device *dev) 191762306a36Sopenharmony_ci{ 191862306a36Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 192162306a36Sopenharmony_ci happy_meal_stop(hp, hp->gregs); 192262306a36Sopenharmony_ci happy_meal_clean_rings(hp); 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ci /* If auto-negotiation timer is running, kill it. */ 192562306a36Sopenharmony_ci del_timer(&hp->happy_timer); 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci free_irq(hp->irq, dev); 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_ci return 0; 193262306a36Sopenharmony_ci} 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_cistatic void happy_meal_tx_timeout(struct net_device *dev, unsigned int txqueue) 193562306a36Sopenharmony_ci{ 193662306a36Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci netdev_err(dev, "transmit timed out, resetting\n"); 193962306a36Sopenharmony_ci tx_dump_log(); 194062306a36Sopenharmony_ci netdev_err(dev, "Happy Status %08x TX[%08x:%08x]\n", 194162306a36Sopenharmony_ci hme_read32(hp, hp->gregs + GREG_STAT), 194262306a36Sopenharmony_ci hme_read32(hp, hp->etxregs + ETX_CFG), 194362306a36Sopenharmony_ci hme_read32(hp, hp->bigmacregs + BMAC_TXCFG)); 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 194662306a36Sopenharmony_ci happy_meal_init(hp); 194762306a36Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 194862306a36Sopenharmony_ci 194962306a36Sopenharmony_ci netif_wake_queue(dev); 195062306a36Sopenharmony_ci} 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_cistatic void unmap_partial_tx_skb(struct happy_meal *hp, u32 first_mapping, 195362306a36Sopenharmony_ci u32 first_len, u32 first_entry, u32 entry) 195462306a36Sopenharmony_ci{ 195562306a36Sopenharmony_ci struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0]; 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci dma_unmap_single(hp->dma_dev, first_mapping, first_len, DMA_TO_DEVICE); 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci first_entry = NEXT_TX(first_entry); 196062306a36Sopenharmony_ci while (first_entry != entry) { 196162306a36Sopenharmony_ci struct happy_meal_txd *this = &txbase[first_entry]; 196262306a36Sopenharmony_ci u32 addr, len; 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci addr = hme_read_desc32(hp, &this->tx_addr); 196562306a36Sopenharmony_ci len = hme_read_desc32(hp, &this->tx_flags); 196662306a36Sopenharmony_ci len &= TXFLAG_SIZE; 196762306a36Sopenharmony_ci dma_unmap_page(hp->dma_dev, addr, len, DMA_TO_DEVICE); 196862306a36Sopenharmony_ci } 196962306a36Sopenharmony_ci} 197062306a36Sopenharmony_ci 197162306a36Sopenharmony_cistatic netdev_tx_t happy_meal_start_xmit(struct sk_buff *skb, 197262306a36Sopenharmony_ci struct net_device *dev) 197362306a36Sopenharmony_ci{ 197462306a36Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 197562306a36Sopenharmony_ci int entry; 197662306a36Sopenharmony_ci u32 tx_flags; 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci tx_flags = TXFLAG_OWN; 197962306a36Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL) { 198062306a36Sopenharmony_ci const u32 csum_start_off = skb_checksum_start_offset(skb); 198162306a36Sopenharmony_ci const u32 csum_stuff_off = csum_start_off + skb->csum_offset; 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci tx_flags = (TXFLAG_OWN | TXFLAG_CSENABLE | 198462306a36Sopenharmony_ci ((csum_start_off << 14) & TXFLAG_CSBUFBEGIN) | 198562306a36Sopenharmony_ci ((csum_stuff_off << 20) & TXFLAG_CSLOCATION)); 198662306a36Sopenharmony_ci } 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci if (TX_BUFFS_AVAIL(hp) <= (skb_shinfo(skb)->nr_frags + 1)) { 199162306a36Sopenharmony_ci netif_stop_queue(dev); 199262306a36Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 199362306a36Sopenharmony_ci netdev_err(dev, "BUG! Tx Ring full when queue awake!\n"); 199462306a36Sopenharmony_ci return NETDEV_TX_BUSY; 199562306a36Sopenharmony_ci } 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci entry = hp->tx_new; 199862306a36Sopenharmony_ci netdev_vdbg(dev, "SX<l[%d]e[%d]>\n", skb->len, entry); 199962306a36Sopenharmony_ci hp->tx_skbs[entry] = skb; 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci if (skb_shinfo(skb)->nr_frags == 0) { 200262306a36Sopenharmony_ci u32 mapping, len; 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci len = skb->len; 200562306a36Sopenharmony_ci mapping = dma_map_single(hp->dma_dev, skb->data, len, DMA_TO_DEVICE); 200662306a36Sopenharmony_ci if (unlikely(dma_mapping_error(hp->dma_dev, mapping))) 200762306a36Sopenharmony_ci goto out_dma_error; 200862306a36Sopenharmony_ci tx_flags |= (TXFLAG_SOP | TXFLAG_EOP); 200962306a36Sopenharmony_ci hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry], 201062306a36Sopenharmony_ci (tx_flags | (len & TXFLAG_SIZE)), 201162306a36Sopenharmony_ci mapping); 201262306a36Sopenharmony_ci entry = NEXT_TX(entry); 201362306a36Sopenharmony_ci } else { 201462306a36Sopenharmony_ci u32 first_len, first_mapping; 201562306a36Sopenharmony_ci int frag, first_entry = entry; 201662306a36Sopenharmony_ci 201762306a36Sopenharmony_ci /* We must give this initial chunk to the device last. 201862306a36Sopenharmony_ci * Otherwise we could race with the device. 201962306a36Sopenharmony_ci */ 202062306a36Sopenharmony_ci first_len = skb_headlen(skb); 202162306a36Sopenharmony_ci first_mapping = dma_map_single(hp->dma_dev, skb->data, first_len, 202262306a36Sopenharmony_ci DMA_TO_DEVICE); 202362306a36Sopenharmony_ci if (unlikely(dma_mapping_error(hp->dma_dev, first_mapping))) 202462306a36Sopenharmony_ci goto out_dma_error; 202562306a36Sopenharmony_ci entry = NEXT_TX(entry); 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { 202862306a36Sopenharmony_ci const skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag]; 202962306a36Sopenharmony_ci u32 len, mapping, this_txflags; 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci len = skb_frag_size(this_frag); 203262306a36Sopenharmony_ci mapping = skb_frag_dma_map(hp->dma_dev, this_frag, 203362306a36Sopenharmony_ci 0, len, DMA_TO_DEVICE); 203462306a36Sopenharmony_ci if (unlikely(dma_mapping_error(hp->dma_dev, mapping))) { 203562306a36Sopenharmony_ci unmap_partial_tx_skb(hp, first_mapping, first_len, 203662306a36Sopenharmony_ci first_entry, entry); 203762306a36Sopenharmony_ci goto out_dma_error; 203862306a36Sopenharmony_ci } 203962306a36Sopenharmony_ci this_txflags = tx_flags; 204062306a36Sopenharmony_ci if (frag == skb_shinfo(skb)->nr_frags - 1) 204162306a36Sopenharmony_ci this_txflags |= TXFLAG_EOP; 204262306a36Sopenharmony_ci hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry], 204362306a36Sopenharmony_ci (this_txflags | (len & TXFLAG_SIZE)), 204462306a36Sopenharmony_ci mapping); 204562306a36Sopenharmony_ci entry = NEXT_TX(entry); 204662306a36Sopenharmony_ci } 204762306a36Sopenharmony_ci hme_write_txd(hp, &hp->happy_block->happy_meal_txd[first_entry], 204862306a36Sopenharmony_ci (tx_flags | TXFLAG_SOP | (first_len & TXFLAG_SIZE)), 204962306a36Sopenharmony_ci first_mapping); 205062306a36Sopenharmony_ci } 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci hp->tx_new = entry; 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci if (TX_BUFFS_AVAIL(hp) <= (MAX_SKB_FRAGS + 1)) 205562306a36Sopenharmony_ci netif_stop_queue(dev); 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci /* Get it going. */ 205862306a36Sopenharmony_ci hme_write32(hp, hp->etxregs + ETX_PENDING, ETX_TP_DMAWAKEUP); 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ci tx_add_log(hp, TXLOG_ACTION_TXMIT, 0); 206362306a36Sopenharmony_ci return NETDEV_TX_OK; 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ciout_dma_error: 206662306a36Sopenharmony_ci hp->tx_skbs[hp->tx_new] = NULL; 206762306a36Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 207062306a36Sopenharmony_ci dev->stats.tx_dropped++; 207162306a36Sopenharmony_ci return NETDEV_TX_OK; 207262306a36Sopenharmony_ci} 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_cistatic struct net_device_stats *happy_meal_get_stats(struct net_device *dev) 207562306a36Sopenharmony_ci{ 207662306a36Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 207962306a36Sopenharmony_ci happy_meal_get_counters(hp, hp->bigmacregs); 208062306a36Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_ci return &dev->stats; 208362306a36Sopenharmony_ci} 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_cistatic void happy_meal_set_multicast(struct net_device *dev) 208662306a36Sopenharmony_ci{ 208762306a36Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 208862306a36Sopenharmony_ci void __iomem *bregs = hp->bigmacregs; 208962306a36Sopenharmony_ci struct netdev_hw_addr *ha; 209062306a36Sopenharmony_ci u32 crc; 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_ci if ((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) { 209562306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE0, 0xffff); 209662306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE1, 0xffff); 209762306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE2, 0xffff); 209862306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE3, 0xffff); 209962306a36Sopenharmony_ci } else if (dev->flags & IFF_PROMISC) { 210062306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_RXCFG, 210162306a36Sopenharmony_ci hme_read32(hp, bregs + BMAC_RXCFG) | BIGMAC_RXCFG_PMISC); 210262306a36Sopenharmony_ci } else { 210362306a36Sopenharmony_ci u16 hash_table[4]; 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci memset(hash_table, 0, sizeof(hash_table)); 210662306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 210762306a36Sopenharmony_ci crc = ether_crc_le(6, ha->addr); 210862306a36Sopenharmony_ci crc >>= 26; 210962306a36Sopenharmony_ci hash_table[crc >> 4] |= 1 << (crc & 0xf); 211062306a36Sopenharmony_ci } 211162306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE0, hash_table[0]); 211262306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE1, hash_table[1]); 211362306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE2, hash_table[2]); 211462306a36Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE3, hash_table[3]); 211562306a36Sopenharmony_ci } 211662306a36Sopenharmony_ci 211762306a36Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 211862306a36Sopenharmony_ci} 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci/* Ethtool support... */ 212162306a36Sopenharmony_cistatic int hme_get_link_ksettings(struct net_device *dev, 212262306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 212362306a36Sopenharmony_ci{ 212462306a36Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 212562306a36Sopenharmony_ci u32 speed; 212662306a36Sopenharmony_ci u32 supported; 212762306a36Sopenharmony_ci 212862306a36Sopenharmony_ci supported = 212962306a36Sopenharmony_ci (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | 213062306a36Sopenharmony_ci SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | 213162306a36Sopenharmony_ci SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII); 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ci /* XXX hardcoded stuff for now */ 213462306a36Sopenharmony_ci cmd->base.port = PORT_TP; /* XXX no MII support */ 213562306a36Sopenharmony_ci cmd->base.phy_address = 0; /* XXX fixed PHYAD */ 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci /* Record PHY settings. */ 213862306a36Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 213962306a36Sopenharmony_ci hp->sw_bmcr = happy_meal_tcvr_read(hp, hp->tcvregs, MII_BMCR); 214062306a36Sopenharmony_ci hp->sw_lpa = happy_meal_tcvr_read(hp, hp->tcvregs, MII_LPA); 214162306a36Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci if (hp->sw_bmcr & BMCR_ANENABLE) { 214462306a36Sopenharmony_ci cmd->base.autoneg = AUTONEG_ENABLE; 214562306a36Sopenharmony_ci speed = ((hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) ? 214662306a36Sopenharmony_ci SPEED_100 : SPEED_10); 214762306a36Sopenharmony_ci if (speed == SPEED_100) 214862306a36Sopenharmony_ci cmd->base.duplex = 214962306a36Sopenharmony_ci (hp->sw_lpa & (LPA_100FULL)) ? 215062306a36Sopenharmony_ci DUPLEX_FULL : DUPLEX_HALF; 215162306a36Sopenharmony_ci else 215262306a36Sopenharmony_ci cmd->base.duplex = 215362306a36Sopenharmony_ci (hp->sw_lpa & (LPA_10FULL)) ? 215462306a36Sopenharmony_ci DUPLEX_FULL : DUPLEX_HALF; 215562306a36Sopenharmony_ci } else { 215662306a36Sopenharmony_ci cmd->base.autoneg = AUTONEG_DISABLE; 215762306a36Sopenharmony_ci speed = (hp->sw_bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10; 215862306a36Sopenharmony_ci cmd->base.duplex = 215962306a36Sopenharmony_ci (hp->sw_bmcr & BMCR_FULLDPLX) ? 216062306a36Sopenharmony_ci DUPLEX_FULL : DUPLEX_HALF; 216162306a36Sopenharmony_ci } 216262306a36Sopenharmony_ci cmd->base.speed = speed; 216362306a36Sopenharmony_ci ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, 216462306a36Sopenharmony_ci supported); 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci return 0; 216762306a36Sopenharmony_ci} 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_cistatic int hme_set_link_ksettings(struct net_device *dev, 217062306a36Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 217162306a36Sopenharmony_ci{ 217262306a36Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci /* Verify the settings we care about. */ 217562306a36Sopenharmony_ci if (cmd->base.autoneg != AUTONEG_ENABLE && 217662306a36Sopenharmony_ci cmd->base.autoneg != AUTONEG_DISABLE) 217762306a36Sopenharmony_ci return -EINVAL; 217862306a36Sopenharmony_ci if (cmd->base.autoneg == AUTONEG_DISABLE && 217962306a36Sopenharmony_ci ((cmd->base.speed != SPEED_100 && 218062306a36Sopenharmony_ci cmd->base.speed != SPEED_10) || 218162306a36Sopenharmony_ci (cmd->base.duplex != DUPLEX_HALF && 218262306a36Sopenharmony_ci cmd->base.duplex != DUPLEX_FULL))) 218362306a36Sopenharmony_ci return -EINVAL; 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci /* Ok, do it to it. */ 218662306a36Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 218762306a36Sopenharmony_ci del_timer(&hp->happy_timer); 218862306a36Sopenharmony_ci happy_meal_begin_auto_negotiation(hp, hp->tcvregs, cmd); 218962306a36Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci return 0; 219262306a36Sopenharmony_ci} 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_cistatic void hme_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) 219562306a36Sopenharmony_ci{ 219662306a36Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 219762306a36Sopenharmony_ci 219862306a36Sopenharmony_ci strscpy(info->driver, DRV_NAME, sizeof(info->driver)); 219962306a36Sopenharmony_ci if (hp->happy_flags & HFLAG_PCI) { 220062306a36Sopenharmony_ci struct pci_dev *pdev = hp->happy_dev; 220162306a36Sopenharmony_ci strscpy(info->bus_info, pci_name(pdev), sizeof(info->bus_info)); 220262306a36Sopenharmony_ci } 220362306a36Sopenharmony_ci#ifdef CONFIG_SBUS 220462306a36Sopenharmony_ci else { 220562306a36Sopenharmony_ci const struct linux_prom_registers *regs; 220662306a36Sopenharmony_ci struct platform_device *op = hp->happy_dev; 220762306a36Sopenharmony_ci regs = of_get_property(op->dev.of_node, "regs", NULL); 220862306a36Sopenharmony_ci if (regs) 220962306a36Sopenharmony_ci snprintf(info->bus_info, sizeof(info->bus_info), 221062306a36Sopenharmony_ci "SBUS:%d", 221162306a36Sopenharmony_ci regs->which_io); 221262306a36Sopenharmony_ci } 221362306a36Sopenharmony_ci#endif 221462306a36Sopenharmony_ci} 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_cistatic u32 hme_get_link(struct net_device *dev) 221762306a36Sopenharmony_ci{ 221862306a36Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 222162306a36Sopenharmony_ci hp->sw_bmcr = happy_meal_tcvr_read(hp, hp->tcvregs, MII_BMCR); 222262306a36Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_ci return hp->sw_bmsr & BMSR_LSTATUS; 222562306a36Sopenharmony_ci} 222662306a36Sopenharmony_ci 222762306a36Sopenharmony_cistatic const struct ethtool_ops hme_ethtool_ops = { 222862306a36Sopenharmony_ci .get_drvinfo = hme_get_drvinfo, 222962306a36Sopenharmony_ci .get_link = hme_get_link, 223062306a36Sopenharmony_ci .get_link_ksettings = hme_get_link_ksettings, 223162306a36Sopenharmony_ci .set_link_ksettings = hme_set_link_ksettings, 223262306a36Sopenharmony_ci}; 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_ci#ifdef CONFIG_SBUS 223562306a36Sopenharmony_ci/* Given a happy meal sbus device, find it's quattro parent. 223662306a36Sopenharmony_ci * If none exist, allocate and return a new one. 223762306a36Sopenharmony_ci * 223862306a36Sopenharmony_ci * Return NULL on failure. 223962306a36Sopenharmony_ci */ 224062306a36Sopenharmony_cistatic struct quattro *quattro_sbus_find(struct platform_device *child) 224162306a36Sopenharmony_ci{ 224262306a36Sopenharmony_ci struct device *parent = child->dev.parent; 224362306a36Sopenharmony_ci struct platform_device *op; 224462306a36Sopenharmony_ci struct quattro *qp; 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ci op = to_platform_device(parent); 224762306a36Sopenharmony_ci qp = platform_get_drvdata(op); 224862306a36Sopenharmony_ci if (qp) 224962306a36Sopenharmony_ci return qp; 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci qp = kzalloc(sizeof(*qp), GFP_KERNEL); 225262306a36Sopenharmony_ci if (!qp) 225362306a36Sopenharmony_ci return NULL; 225462306a36Sopenharmony_ci 225562306a36Sopenharmony_ci qp->quattro_dev = child; 225662306a36Sopenharmony_ci qp->next = qfe_sbus_list; 225762306a36Sopenharmony_ci qfe_sbus_list = qp; 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_ci platform_set_drvdata(op, qp); 226062306a36Sopenharmony_ci return qp; 226162306a36Sopenharmony_ci} 226262306a36Sopenharmony_ci#endif /* CONFIG_SBUS */ 226362306a36Sopenharmony_ci 226462306a36Sopenharmony_ci#ifdef CONFIG_PCI 226562306a36Sopenharmony_cistatic struct quattro *quattro_pci_find(struct pci_dev *pdev) 226662306a36Sopenharmony_ci{ 226762306a36Sopenharmony_ci int i; 226862306a36Sopenharmony_ci struct pci_dev *bdev = pdev->bus->self; 226962306a36Sopenharmony_ci struct quattro *qp; 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci if (!bdev) 227262306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_ci for (qp = qfe_pci_list; qp != NULL; qp = qp->next) { 227562306a36Sopenharmony_ci struct pci_dev *qpdev = qp->quattro_dev; 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_ci if (qpdev == bdev) 227862306a36Sopenharmony_ci return qp; 227962306a36Sopenharmony_ci } 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci qp = kmalloc(sizeof(struct quattro), GFP_KERNEL); 228262306a36Sopenharmony_ci if (!qp) 228362306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ci for (i = 0; i < 4; i++) 228662306a36Sopenharmony_ci qp->happy_meals[i] = NULL; 228762306a36Sopenharmony_ci 228862306a36Sopenharmony_ci qp->quattro_dev = bdev; 228962306a36Sopenharmony_ci qp->next = qfe_pci_list; 229062306a36Sopenharmony_ci qfe_pci_list = qp; 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci /* No range tricks necessary on PCI. */ 229362306a36Sopenharmony_ci qp->nranges = 0; 229462306a36Sopenharmony_ci return qp; 229562306a36Sopenharmony_ci} 229662306a36Sopenharmony_ci#endif /* CONFIG_PCI */ 229762306a36Sopenharmony_ci 229862306a36Sopenharmony_cistatic const struct net_device_ops hme_netdev_ops = { 229962306a36Sopenharmony_ci .ndo_open = happy_meal_open, 230062306a36Sopenharmony_ci .ndo_stop = happy_meal_close, 230162306a36Sopenharmony_ci .ndo_start_xmit = happy_meal_start_xmit, 230262306a36Sopenharmony_ci .ndo_tx_timeout = happy_meal_tx_timeout, 230362306a36Sopenharmony_ci .ndo_get_stats = happy_meal_get_stats, 230462306a36Sopenharmony_ci .ndo_set_rx_mode = happy_meal_set_multicast, 230562306a36Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 230662306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 230762306a36Sopenharmony_ci}; 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci#ifdef CONFIG_PCI 231062306a36Sopenharmony_cistatic int is_quattro_p(struct pci_dev *pdev) 231162306a36Sopenharmony_ci{ 231262306a36Sopenharmony_ci struct pci_dev *busdev = pdev->bus->self; 231362306a36Sopenharmony_ci struct pci_dev *this_pdev; 231462306a36Sopenharmony_ci int n_hmes; 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci if (!busdev || busdev->vendor != PCI_VENDOR_ID_DEC || 231762306a36Sopenharmony_ci busdev->device != PCI_DEVICE_ID_DEC_21153) 231862306a36Sopenharmony_ci return 0; 231962306a36Sopenharmony_ci 232062306a36Sopenharmony_ci n_hmes = 0; 232162306a36Sopenharmony_ci list_for_each_entry(this_pdev, &pdev->bus->devices, bus_list) { 232262306a36Sopenharmony_ci if (this_pdev->vendor == PCI_VENDOR_ID_SUN && 232362306a36Sopenharmony_ci this_pdev->device == PCI_DEVICE_ID_SUN_HAPPYMEAL) 232462306a36Sopenharmony_ci n_hmes++; 232562306a36Sopenharmony_ci } 232662306a36Sopenharmony_ci 232762306a36Sopenharmony_ci if (n_hmes != 4) 232862306a36Sopenharmony_ci return 0; 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci return 1; 233162306a36Sopenharmony_ci} 233262306a36Sopenharmony_ci 233362306a36Sopenharmony_ci/* Fetch MAC address from vital product data of PCI ROM. */ 233462306a36Sopenharmony_cistatic int find_eth_addr_in_vpd(void __iomem *rom_base, int len, int index, unsigned char *dev_addr) 233562306a36Sopenharmony_ci{ 233662306a36Sopenharmony_ci int this_offset; 233762306a36Sopenharmony_ci 233862306a36Sopenharmony_ci for (this_offset = 0x20; this_offset < len; this_offset++) { 233962306a36Sopenharmony_ci void __iomem *p = rom_base + this_offset; 234062306a36Sopenharmony_ci 234162306a36Sopenharmony_ci if (readb(p + 0) != 0x90 || 234262306a36Sopenharmony_ci readb(p + 1) != 0x00 || 234362306a36Sopenharmony_ci readb(p + 2) != 0x09 || 234462306a36Sopenharmony_ci readb(p + 3) != 0x4e || 234562306a36Sopenharmony_ci readb(p + 4) != 0x41 || 234662306a36Sopenharmony_ci readb(p + 5) != 0x06) 234762306a36Sopenharmony_ci continue; 234862306a36Sopenharmony_ci 234962306a36Sopenharmony_ci this_offset += 6; 235062306a36Sopenharmony_ci p += 6; 235162306a36Sopenharmony_ci 235262306a36Sopenharmony_ci if (index == 0) { 235362306a36Sopenharmony_ci for (int i = 0; i < 6; i++) 235462306a36Sopenharmony_ci dev_addr[i] = readb(p + i); 235562306a36Sopenharmony_ci return 1; 235662306a36Sopenharmony_ci } 235762306a36Sopenharmony_ci index--; 235862306a36Sopenharmony_ci } 235962306a36Sopenharmony_ci return 0; 236062306a36Sopenharmony_ci} 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_cistatic void __maybe_unused get_hme_mac_nonsparc(struct pci_dev *pdev, 236362306a36Sopenharmony_ci unsigned char *dev_addr) 236462306a36Sopenharmony_ci{ 236562306a36Sopenharmony_ci void __iomem *p; 236662306a36Sopenharmony_ci size_t size; 236762306a36Sopenharmony_ci 236862306a36Sopenharmony_ci p = pci_map_rom(pdev, &size); 236962306a36Sopenharmony_ci if (p) { 237062306a36Sopenharmony_ci int index = 0; 237162306a36Sopenharmony_ci int found; 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_ci if (is_quattro_p(pdev)) 237462306a36Sopenharmony_ci index = PCI_SLOT(pdev->devfn); 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci found = readb(p) == 0x55 && 237762306a36Sopenharmony_ci readb(p + 1) == 0xaa && 237862306a36Sopenharmony_ci find_eth_addr_in_vpd(p, (64 * 1024), index, dev_addr); 237962306a36Sopenharmony_ci pci_unmap_rom(pdev, p); 238062306a36Sopenharmony_ci if (found) 238162306a36Sopenharmony_ci return; 238262306a36Sopenharmony_ci } 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci /* Sun MAC prefix then 3 random bytes. */ 238562306a36Sopenharmony_ci dev_addr[0] = 0x08; 238662306a36Sopenharmony_ci dev_addr[1] = 0x00; 238762306a36Sopenharmony_ci dev_addr[2] = 0x20; 238862306a36Sopenharmony_ci get_random_bytes(&dev_addr[3], 3); 238962306a36Sopenharmony_ci} 239062306a36Sopenharmony_ci#endif 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_cistatic void happy_meal_addr_init(struct happy_meal *hp, 239362306a36Sopenharmony_ci struct device_node *dp, int qfe_slot) 239462306a36Sopenharmony_ci{ 239562306a36Sopenharmony_ci int i; 239662306a36Sopenharmony_ci 239762306a36Sopenharmony_ci for (i = 0; i < 6; i++) { 239862306a36Sopenharmony_ci if (macaddr[i] != 0) 239962306a36Sopenharmony_ci break; 240062306a36Sopenharmony_ci } 240162306a36Sopenharmony_ci 240262306a36Sopenharmony_ci if (i < 6) { /* a mac address was given */ 240362306a36Sopenharmony_ci u8 addr[ETH_ALEN]; 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci for (i = 0; i < 6; i++) 240662306a36Sopenharmony_ci addr[i] = macaddr[i]; 240762306a36Sopenharmony_ci eth_hw_addr_set(hp->dev, addr); 240862306a36Sopenharmony_ci macaddr[5]++; 240962306a36Sopenharmony_ci } else { 241062306a36Sopenharmony_ci#ifdef CONFIG_SPARC 241162306a36Sopenharmony_ci const unsigned char *addr; 241262306a36Sopenharmony_ci int len; 241362306a36Sopenharmony_ci 241462306a36Sopenharmony_ci /* If user did not specify a MAC address specifically, use 241562306a36Sopenharmony_ci * the Quattro local-mac-address property... 241662306a36Sopenharmony_ci */ 241762306a36Sopenharmony_ci if (qfe_slot != -1) { 241862306a36Sopenharmony_ci addr = of_get_property(dp, "local-mac-address", &len); 241962306a36Sopenharmony_ci if (addr && len == 6) { 242062306a36Sopenharmony_ci eth_hw_addr_set(hp->dev, addr); 242162306a36Sopenharmony_ci return; 242262306a36Sopenharmony_ci } 242362306a36Sopenharmony_ci } 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_ci eth_hw_addr_set(hp->dev, idprom->id_ethaddr); 242662306a36Sopenharmony_ci#else 242762306a36Sopenharmony_ci u8 addr[ETH_ALEN]; 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ci get_hme_mac_nonsparc(hp->happy_dev, addr); 243062306a36Sopenharmony_ci eth_hw_addr_set(hp->dev, addr); 243162306a36Sopenharmony_ci#endif 243262306a36Sopenharmony_ci } 243362306a36Sopenharmony_ci} 243462306a36Sopenharmony_ci 243562306a36Sopenharmony_cistatic int happy_meal_common_probe(struct happy_meal *hp, 243662306a36Sopenharmony_ci struct device_node *dp) 243762306a36Sopenharmony_ci{ 243862306a36Sopenharmony_ci struct net_device *dev = hp->dev; 243962306a36Sopenharmony_ci int err; 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci#ifdef CONFIG_SPARC 244262306a36Sopenharmony_ci hp->hm_revision = of_getintprop_default(dp, "hm-rev", hp->hm_revision); 244362306a36Sopenharmony_ci#endif 244462306a36Sopenharmony_ci 244562306a36Sopenharmony_ci /* Now enable the feature flags we can. */ 244662306a36Sopenharmony_ci if (hp->hm_revision == 0x20 || hp->hm_revision == 0x21) 244762306a36Sopenharmony_ci hp->happy_flags |= HFLAG_20_21; 244862306a36Sopenharmony_ci else if (hp->hm_revision != 0xa0) 244962306a36Sopenharmony_ci hp->happy_flags |= HFLAG_NOT_A0; 245062306a36Sopenharmony_ci 245162306a36Sopenharmony_ci hp->happy_block = dmam_alloc_coherent(hp->dma_dev, PAGE_SIZE, 245262306a36Sopenharmony_ci &hp->hblock_dvma, GFP_KERNEL); 245362306a36Sopenharmony_ci if (!hp->happy_block) 245462306a36Sopenharmony_ci return -ENOMEM; 245562306a36Sopenharmony_ci 245662306a36Sopenharmony_ci /* Force check of the link first time we are brought up. */ 245762306a36Sopenharmony_ci hp->linkcheck = 0; 245862306a36Sopenharmony_ci 245962306a36Sopenharmony_ci /* Force timer state to 'asleep' with count of zero. */ 246062306a36Sopenharmony_ci hp->timer_state = asleep; 246162306a36Sopenharmony_ci hp->timer_ticks = 0; 246262306a36Sopenharmony_ci 246362306a36Sopenharmony_ci timer_setup(&hp->happy_timer, happy_meal_timer, 0); 246462306a36Sopenharmony_ci 246562306a36Sopenharmony_ci dev->netdev_ops = &hme_netdev_ops; 246662306a36Sopenharmony_ci dev->watchdog_timeo = 5 * HZ; 246762306a36Sopenharmony_ci dev->ethtool_ops = &hme_ethtool_ops; 246862306a36Sopenharmony_ci 246962306a36Sopenharmony_ci /* Happy Meal can do it all... */ 247062306a36Sopenharmony_ci dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; 247162306a36Sopenharmony_ci dev->features |= dev->hw_features | NETIF_F_RXCSUM; 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci /* Grrr, Happy Meal comes up by default not advertising 247562306a36Sopenharmony_ci * full duplex 100baseT capabilities, fix this. 247662306a36Sopenharmony_ci */ 247762306a36Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 247862306a36Sopenharmony_ci happy_meal_set_initial_advertisement(hp); 247962306a36Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 248062306a36Sopenharmony_ci 248162306a36Sopenharmony_ci err = devm_register_netdev(hp->dma_dev, dev); 248262306a36Sopenharmony_ci if (err) 248362306a36Sopenharmony_ci dev_err(hp->dma_dev, "Cannot register net device, aborting.\n"); 248462306a36Sopenharmony_ci return err; 248562306a36Sopenharmony_ci} 248662306a36Sopenharmony_ci 248762306a36Sopenharmony_ci#ifdef CONFIG_SBUS 248862306a36Sopenharmony_cistatic int happy_meal_sbus_probe_one(struct platform_device *op, int is_qfe) 248962306a36Sopenharmony_ci{ 249062306a36Sopenharmony_ci struct device_node *dp = op->dev.of_node, *sbus_dp; 249162306a36Sopenharmony_ci struct quattro *qp = NULL; 249262306a36Sopenharmony_ci struct happy_meal *hp; 249362306a36Sopenharmony_ci struct net_device *dev; 249462306a36Sopenharmony_ci int qfe_slot = -1; 249562306a36Sopenharmony_ci int err; 249662306a36Sopenharmony_ci 249762306a36Sopenharmony_ci sbus_dp = op->dev.parent->of_node; 249862306a36Sopenharmony_ci 249962306a36Sopenharmony_ci /* We can match PCI devices too, do not accept those here. */ 250062306a36Sopenharmony_ci if (!of_node_name_eq(sbus_dp, "sbus") && !of_node_name_eq(sbus_dp, "sbi")) 250162306a36Sopenharmony_ci return -ENODEV; 250262306a36Sopenharmony_ci 250362306a36Sopenharmony_ci if (is_qfe) { 250462306a36Sopenharmony_ci qp = quattro_sbus_find(op); 250562306a36Sopenharmony_ci if (qp == NULL) 250662306a36Sopenharmony_ci return -ENODEV; 250762306a36Sopenharmony_ci for (qfe_slot = 0; qfe_slot < 4; qfe_slot++) 250862306a36Sopenharmony_ci if (qp->happy_meals[qfe_slot] == NULL) 250962306a36Sopenharmony_ci break; 251062306a36Sopenharmony_ci if (qfe_slot == 4) 251162306a36Sopenharmony_ci return -ENODEV; 251262306a36Sopenharmony_ci } 251362306a36Sopenharmony_ci 251462306a36Sopenharmony_ci dev = devm_alloc_etherdev(&op->dev, sizeof(struct happy_meal)); 251562306a36Sopenharmony_ci if (!dev) 251662306a36Sopenharmony_ci return -ENOMEM; 251762306a36Sopenharmony_ci SET_NETDEV_DEV(dev, &op->dev); 251862306a36Sopenharmony_ci 251962306a36Sopenharmony_ci hp = netdev_priv(dev); 252062306a36Sopenharmony_ci hp->dev = dev; 252162306a36Sopenharmony_ci hp->happy_dev = op; 252262306a36Sopenharmony_ci hp->dma_dev = &op->dev; 252362306a36Sopenharmony_ci happy_meal_addr_init(hp, dp, qfe_slot); 252462306a36Sopenharmony_ci 252562306a36Sopenharmony_ci spin_lock_init(&hp->happy_lock); 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci if (qp != NULL) { 252862306a36Sopenharmony_ci hp->qfe_parent = qp; 252962306a36Sopenharmony_ci hp->qfe_ent = qfe_slot; 253062306a36Sopenharmony_ci qp->happy_meals[qfe_slot] = dev; 253162306a36Sopenharmony_ci } 253262306a36Sopenharmony_ci 253362306a36Sopenharmony_ci hp->gregs = devm_platform_ioremap_resource(op, 0); 253462306a36Sopenharmony_ci if (IS_ERR(hp->gregs)) { 253562306a36Sopenharmony_ci dev_err(&op->dev, "Cannot map global registers.\n"); 253662306a36Sopenharmony_ci err = PTR_ERR(hp->gregs); 253762306a36Sopenharmony_ci goto err_out_clear_quattro; 253862306a36Sopenharmony_ci } 253962306a36Sopenharmony_ci 254062306a36Sopenharmony_ci hp->etxregs = devm_platform_ioremap_resource(op, 1); 254162306a36Sopenharmony_ci if (IS_ERR(hp->etxregs)) { 254262306a36Sopenharmony_ci dev_err(&op->dev, "Cannot map MAC TX registers.\n"); 254362306a36Sopenharmony_ci err = PTR_ERR(hp->etxregs); 254462306a36Sopenharmony_ci goto err_out_clear_quattro; 254562306a36Sopenharmony_ci } 254662306a36Sopenharmony_ci 254762306a36Sopenharmony_ci hp->erxregs = devm_platform_ioremap_resource(op, 2); 254862306a36Sopenharmony_ci if (IS_ERR(hp->erxregs)) { 254962306a36Sopenharmony_ci dev_err(&op->dev, "Cannot map MAC RX registers.\n"); 255062306a36Sopenharmony_ci err = PTR_ERR(hp->erxregs); 255162306a36Sopenharmony_ci goto err_out_clear_quattro; 255262306a36Sopenharmony_ci } 255362306a36Sopenharmony_ci 255462306a36Sopenharmony_ci hp->bigmacregs = devm_platform_ioremap_resource(op, 3); 255562306a36Sopenharmony_ci if (IS_ERR(hp->bigmacregs)) { 255662306a36Sopenharmony_ci dev_err(&op->dev, "Cannot map BIGMAC registers.\n"); 255762306a36Sopenharmony_ci err = PTR_ERR(hp->bigmacregs); 255862306a36Sopenharmony_ci goto err_out_clear_quattro; 255962306a36Sopenharmony_ci } 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci hp->tcvregs = devm_platform_ioremap_resource(op, 4); 256262306a36Sopenharmony_ci if (IS_ERR(hp->tcvregs)) { 256362306a36Sopenharmony_ci dev_err(&op->dev, "Cannot map TCVR registers.\n"); 256462306a36Sopenharmony_ci err = PTR_ERR(hp->tcvregs); 256562306a36Sopenharmony_ci goto err_out_clear_quattro; 256662306a36Sopenharmony_ci } 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_ci hp->hm_revision = 0xa0; 256962306a36Sopenharmony_ci 257062306a36Sopenharmony_ci if (qp != NULL) 257162306a36Sopenharmony_ci hp->happy_flags |= HFLAG_QUATTRO; 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ci hp->irq = op->archdata.irqs[0]; 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_ci /* Get the supported DVMA burst sizes from our Happy SBUS. */ 257662306a36Sopenharmony_ci hp->happy_bursts = of_getintprop_default(sbus_dp, 257762306a36Sopenharmony_ci "burst-sizes", 0x00); 257862306a36Sopenharmony_ci 257962306a36Sopenharmony_ci#ifdef CONFIG_PCI 258062306a36Sopenharmony_ci /* Hook up SBUS register/descriptor accessors. */ 258162306a36Sopenharmony_ci hp->read_desc32 = sbus_hme_read_desc32; 258262306a36Sopenharmony_ci hp->write_txd = sbus_hme_write_txd; 258362306a36Sopenharmony_ci hp->write_rxd = sbus_hme_write_rxd; 258462306a36Sopenharmony_ci hp->read32 = sbus_hme_read32; 258562306a36Sopenharmony_ci hp->write32 = sbus_hme_write32; 258662306a36Sopenharmony_ci#endif 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_ci err = happy_meal_common_probe(hp, dp); 258962306a36Sopenharmony_ci if (err) 259062306a36Sopenharmony_ci goto err_out_clear_quattro; 259162306a36Sopenharmony_ci 259262306a36Sopenharmony_ci platform_set_drvdata(op, hp); 259362306a36Sopenharmony_ci 259462306a36Sopenharmony_ci if (qfe_slot != -1) 259562306a36Sopenharmony_ci netdev_info(dev, 259662306a36Sopenharmony_ci "Quattro HME slot %d (SBUS) 10/100baseT Ethernet %pM\n", 259762306a36Sopenharmony_ci qfe_slot, dev->dev_addr); 259862306a36Sopenharmony_ci else 259962306a36Sopenharmony_ci netdev_info(dev, "HAPPY MEAL (SBUS) 10/100baseT Ethernet %pM\n", 260062306a36Sopenharmony_ci dev->dev_addr); 260162306a36Sopenharmony_ci 260262306a36Sopenharmony_ci return 0; 260362306a36Sopenharmony_ci 260462306a36Sopenharmony_cierr_out_clear_quattro: 260562306a36Sopenharmony_ci if (qp) 260662306a36Sopenharmony_ci qp->happy_meals[qfe_slot] = NULL; 260762306a36Sopenharmony_ci return err; 260862306a36Sopenharmony_ci} 260962306a36Sopenharmony_ci#endif 261062306a36Sopenharmony_ci 261162306a36Sopenharmony_ci#ifdef CONFIG_PCI 261262306a36Sopenharmony_cistatic int happy_meal_pci_probe(struct pci_dev *pdev, 261362306a36Sopenharmony_ci const struct pci_device_id *ent) 261462306a36Sopenharmony_ci{ 261562306a36Sopenharmony_ci struct device_node *dp = NULL; 261662306a36Sopenharmony_ci struct quattro *qp = NULL; 261762306a36Sopenharmony_ci struct happy_meal *hp; 261862306a36Sopenharmony_ci struct net_device *dev; 261962306a36Sopenharmony_ci void __iomem *hpreg_base; 262062306a36Sopenharmony_ci struct resource *hpreg_res; 262162306a36Sopenharmony_ci char prom_name[64]; 262262306a36Sopenharmony_ci int qfe_slot = -1; 262362306a36Sopenharmony_ci int err = -ENODEV; 262462306a36Sopenharmony_ci 262562306a36Sopenharmony_ci /* Now make sure pci_dev cookie is there. */ 262662306a36Sopenharmony_ci#ifdef CONFIG_SPARC 262762306a36Sopenharmony_ci dp = pci_device_to_OF_node(pdev); 262862306a36Sopenharmony_ci snprintf(prom_name, sizeof(prom_name), "%pOFn", dp); 262962306a36Sopenharmony_ci#else 263062306a36Sopenharmony_ci if (is_quattro_p(pdev)) 263162306a36Sopenharmony_ci strcpy(prom_name, "SUNW,qfe"); 263262306a36Sopenharmony_ci else 263362306a36Sopenharmony_ci strcpy(prom_name, "SUNW,hme"); 263462306a36Sopenharmony_ci#endif 263562306a36Sopenharmony_ci 263662306a36Sopenharmony_ci err = pcim_enable_device(pdev); 263762306a36Sopenharmony_ci if (err) 263862306a36Sopenharmony_ci return err; 263962306a36Sopenharmony_ci pci_set_master(pdev); 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_ci if (!strcmp(prom_name, "SUNW,qfe") || !strcmp(prom_name, "qfe")) { 264262306a36Sopenharmony_ci qp = quattro_pci_find(pdev); 264362306a36Sopenharmony_ci if (IS_ERR(qp)) 264462306a36Sopenharmony_ci return PTR_ERR(qp); 264562306a36Sopenharmony_ci 264662306a36Sopenharmony_ci for (qfe_slot = 0; qfe_slot < 4; qfe_slot++) 264762306a36Sopenharmony_ci if (!qp->happy_meals[qfe_slot]) 264862306a36Sopenharmony_ci break; 264962306a36Sopenharmony_ci 265062306a36Sopenharmony_ci if (qfe_slot == 4) 265162306a36Sopenharmony_ci return -ENODEV; 265262306a36Sopenharmony_ci } 265362306a36Sopenharmony_ci 265462306a36Sopenharmony_ci dev = devm_alloc_etherdev(&pdev->dev, sizeof(struct happy_meal)); 265562306a36Sopenharmony_ci if (!dev) 265662306a36Sopenharmony_ci return -ENOMEM; 265762306a36Sopenharmony_ci SET_NETDEV_DEV(dev, &pdev->dev); 265862306a36Sopenharmony_ci 265962306a36Sopenharmony_ci hp = netdev_priv(dev); 266062306a36Sopenharmony_ci hp->dev = dev; 266162306a36Sopenharmony_ci hp->happy_dev = pdev; 266262306a36Sopenharmony_ci hp->dma_dev = &pdev->dev; 266362306a36Sopenharmony_ci 266462306a36Sopenharmony_ci spin_lock_init(&hp->happy_lock); 266562306a36Sopenharmony_ci 266662306a36Sopenharmony_ci if (qp != NULL) { 266762306a36Sopenharmony_ci hp->qfe_parent = qp; 266862306a36Sopenharmony_ci hp->qfe_ent = qfe_slot; 266962306a36Sopenharmony_ci qp->happy_meals[qfe_slot] = dev; 267062306a36Sopenharmony_ci } 267162306a36Sopenharmony_ci 267262306a36Sopenharmony_ci err = -EINVAL; 267362306a36Sopenharmony_ci if ((pci_resource_flags(pdev, 0) & IORESOURCE_IO) != 0) { 267462306a36Sopenharmony_ci dev_err(&pdev->dev, 267562306a36Sopenharmony_ci "Cannot find proper PCI device base address.\n"); 267662306a36Sopenharmony_ci goto err_out_clear_quattro; 267762306a36Sopenharmony_ci } 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_ci hpreg_res = devm_request_mem_region(&pdev->dev, 268062306a36Sopenharmony_ci pci_resource_start(pdev, 0), 268162306a36Sopenharmony_ci pci_resource_len(pdev, 0), 268262306a36Sopenharmony_ci DRV_NAME); 268362306a36Sopenharmony_ci if (!hpreg_res) { 268462306a36Sopenharmony_ci err = -EBUSY; 268562306a36Sopenharmony_ci dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n"); 268662306a36Sopenharmony_ci goto err_out_clear_quattro; 268762306a36Sopenharmony_ci } 268862306a36Sopenharmony_ci 268962306a36Sopenharmony_ci hpreg_base = pcim_iomap(pdev, 0, 0x8000); 269062306a36Sopenharmony_ci if (!hpreg_base) { 269162306a36Sopenharmony_ci err = -ENOMEM; 269262306a36Sopenharmony_ci dev_err(&pdev->dev, "Unable to remap card memory.\n"); 269362306a36Sopenharmony_ci goto err_out_clear_quattro; 269462306a36Sopenharmony_ci } 269562306a36Sopenharmony_ci 269662306a36Sopenharmony_ci happy_meal_addr_init(hp, dp, qfe_slot); 269762306a36Sopenharmony_ci 269862306a36Sopenharmony_ci /* Layout registers. */ 269962306a36Sopenharmony_ci hp->gregs = (hpreg_base + 0x0000UL); 270062306a36Sopenharmony_ci hp->etxregs = (hpreg_base + 0x2000UL); 270162306a36Sopenharmony_ci hp->erxregs = (hpreg_base + 0x4000UL); 270262306a36Sopenharmony_ci hp->bigmacregs = (hpreg_base + 0x6000UL); 270362306a36Sopenharmony_ci hp->tcvregs = (hpreg_base + 0x7000UL); 270462306a36Sopenharmony_ci 270562306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_SPARC)) 270662306a36Sopenharmony_ci hp->hm_revision = 0xc0 | (pdev->revision & 0x0f); 270762306a36Sopenharmony_ci else 270862306a36Sopenharmony_ci hp->hm_revision = 0x20; 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci if (qp != NULL) 271162306a36Sopenharmony_ci hp->happy_flags |= HFLAG_QUATTRO; 271262306a36Sopenharmony_ci 271362306a36Sopenharmony_ci /* And of course, indicate this is PCI. */ 271462306a36Sopenharmony_ci hp->happy_flags |= HFLAG_PCI; 271562306a36Sopenharmony_ci 271662306a36Sopenharmony_ci#ifdef CONFIG_SPARC 271762306a36Sopenharmony_ci /* Assume PCI happy meals can handle all burst sizes. */ 271862306a36Sopenharmony_ci hp->happy_bursts = DMA_BURSTBITS; 271962306a36Sopenharmony_ci#endif 272062306a36Sopenharmony_ci hp->irq = pdev->irq; 272162306a36Sopenharmony_ci 272262306a36Sopenharmony_ci#ifdef CONFIG_SBUS 272362306a36Sopenharmony_ci /* Hook up PCI register/descriptor accessors. */ 272462306a36Sopenharmony_ci hp->read_desc32 = pci_hme_read_desc32; 272562306a36Sopenharmony_ci hp->write_txd = pci_hme_write_txd; 272662306a36Sopenharmony_ci hp->write_rxd = pci_hme_write_rxd; 272762306a36Sopenharmony_ci hp->read32 = pci_hme_read32; 272862306a36Sopenharmony_ci hp->write32 = pci_hme_write32; 272962306a36Sopenharmony_ci#endif 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_ci err = happy_meal_common_probe(hp, dp); 273262306a36Sopenharmony_ci if (err) 273362306a36Sopenharmony_ci goto err_out_clear_quattro; 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_ci pci_set_drvdata(pdev, hp); 273662306a36Sopenharmony_ci 273762306a36Sopenharmony_ci if (!qfe_slot) { 273862306a36Sopenharmony_ci struct pci_dev *qpdev = qp->quattro_dev; 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_ci prom_name[0] = 0; 274162306a36Sopenharmony_ci if (!strncmp(dev->name, "eth", 3)) { 274262306a36Sopenharmony_ci int i = simple_strtoul(dev->name + 3, NULL, 10); 274362306a36Sopenharmony_ci sprintf(prom_name, "-%d", i + 3); 274462306a36Sopenharmony_ci } 274562306a36Sopenharmony_ci netdev_info(dev, 274662306a36Sopenharmony_ci "%s: Quattro HME (PCI/CheerIO) 10/100baseT Ethernet bridge %04x.%04x\n", 274762306a36Sopenharmony_ci prom_name, qpdev->vendor, qpdev->device); 274862306a36Sopenharmony_ci } 274962306a36Sopenharmony_ci 275062306a36Sopenharmony_ci if (qfe_slot != -1) 275162306a36Sopenharmony_ci netdev_info(dev, 275262306a36Sopenharmony_ci "Quattro HME slot %d (PCI/CheerIO) 10/100baseT Ethernet %pM\n", 275362306a36Sopenharmony_ci qfe_slot, dev->dev_addr); 275462306a36Sopenharmony_ci else 275562306a36Sopenharmony_ci netdev_info(dev, 275662306a36Sopenharmony_ci "HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet %pM\n", 275762306a36Sopenharmony_ci dev->dev_addr); 275862306a36Sopenharmony_ci 275962306a36Sopenharmony_ci return 0; 276062306a36Sopenharmony_ci 276162306a36Sopenharmony_cierr_out_clear_quattro: 276262306a36Sopenharmony_ci if (qp != NULL) 276362306a36Sopenharmony_ci qp->happy_meals[qfe_slot] = NULL; 276462306a36Sopenharmony_ci return err; 276562306a36Sopenharmony_ci} 276662306a36Sopenharmony_ci 276762306a36Sopenharmony_cistatic const struct pci_device_id happymeal_pci_ids[] = { 276862306a36Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_HAPPYMEAL) }, 276962306a36Sopenharmony_ci { } /* Terminating entry */ 277062306a36Sopenharmony_ci}; 277162306a36Sopenharmony_ci 277262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, happymeal_pci_ids); 277362306a36Sopenharmony_ci 277462306a36Sopenharmony_cistatic struct pci_driver hme_pci_driver = { 277562306a36Sopenharmony_ci .name = "hme", 277662306a36Sopenharmony_ci .id_table = happymeal_pci_ids, 277762306a36Sopenharmony_ci .probe = happy_meal_pci_probe, 277862306a36Sopenharmony_ci}; 277962306a36Sopenharmony_ci 278062306a36Sopenharmony_cistatic int __init happy_meal_pci_init(void) 278162306a36Sopenharmony_ci{ 278262306a36Sopenharmony_ci return pci_register_driver(&hme_pci_driver); 278362306a36Sopenharmony_ci} 278462306a36Sopenharmony_ci 278562306a36Sopenharmony_cistatic void happy_meal_pci_exit(void) 278662306a36Sopenharmony_ci{ 278762306a36Sopenharmony_ci pci_unregister_driver(&hme_pci_driver); 278862306a36Sopenharmony_ci 278962306a36Sopenharmony_ci while (qfe_pci_list) { 279062306a36Sopenharmony_ci struct quattro *qfe = qfe_pci_list; 279162306a36Sopenharmony_ci struct quattro *next = qfe->next; 279262306a36Sopenharmony_ci 279362306a36Sopenharmony_ci kfree(qfe); 279462306a36Sopenharmony_ci 279562306a36Sopenharmony_ci qfe_pci_list = next; 279662306a36Sopenharmony_ci } 279762306a36Sopenharmony_ci} 279862306a36Sopenharmony_ci 279962306a36Sopenharmony_ci#endif 280062306a36Sopenharmony_ci 280162306a36Sopenharmony_ci#ifdef CONFIG_SBUS 280262306a36Sopenharmony_cistatic const struct of_device_id hme_sbus_match[]; 280362306a36Sopenharmony_cistatic int hme_sbus_probe(struct platform_device *op) 280462306a36Sopenharmony_ci{ 280562306a36Sopenharmony_ci const struct of_device_id *match; 280662306a36Sopenharmony_ci struct device_node *dp = op->dev.of_node; 280762306a36Sopenharmony_ci const char *model = of_get_property(dp, "model", NULL); 280862306a36Sopenharmony_ci int is_qfe; 280962306a36Sopenharmony_ci 281062306a36Sopenharmony_ci match = of_match_device(hme_sbus_match, &op->dev); 281162306a36Sopenharmony_ci if (!match) 281262306a36Sopenharmony_ci return -EINVAL; 281362306a36Sopenharmony_ci is_qfe = (match->data != NULL); 281462306a36Sopenharmony_ci 281562306a36Sopenharmony_ci if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe")) 281662306a36Sopenharmony_ci is_qfe = 1; 281762306a36Sopenharmony_ci 281862306a36Sopenharmony_ci return happy_meal_sbus_probe_one(op, is_qfe); 281962306a36Sopenharmony_ci} 282062306a36Sopenharmony_ci 282162306a36Sopenharmony_cistatic const struct of_device_id hme_sbus_match[] = { 282262306a36Sopenharmony_ci { 282362306a36Sopenharmony_ci .name = "SUNW,hme", 282462306a36Sopenharmony_ci }, 282562306a36Sopenharmony_ci { 282662306a36Sopenharmony_ci .name = "SUNW,qfe", 282762306a36Sopenharmony_ci .data = (void *) 1, 282862306a36Sopenharmony_ci }, 282962306a36Sopenharmony_ci { 283062306a36Sopenharmony_ci .name = "qfe", 283162306a36Sopenharmony_ci .data = (void *) 1, 283262306a36Sopenharmony_ci }, 283362306a36Sopenharmony_ci {}, 283462306a36Sopenharmony_ci}; 283562306a36Sopenharmony_ci 283662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, hme_sbus_match); 283762306a36Sopenharmony_ci 283862306a36Sopenharmony_cistatic struct platform_driver hme_sbus_driver = { 283962306a36Sopenharmony_ci .driver = { 284062306a36Sopenharmony_ci .name = "hme", 284162306a36Sopenharmony_ci .of_match_table = hme_sbus_match, 284262306a36Sopenharmony_ci }, 284362306a36Sopenharmony_ci .probe = hme_sbus_probe, 284462306a36Sopenharmony_ci}; 284562306a36Sopenharmony_ci 284662306a36Sopenharmony_cistatic int __init happy_meal_sbus_init(void) 284762306a36Sopenharmony_ci{ 284862306a36Sopenharmony_ci return platform_driver_register(&hme_sbus_driver); 284962306a36Sopenharmony_ci} 285062306a36Sopenharmony_ci 285162306a36Sopenharmony_cistatic void happy_meal_sbus_exit(void) 285262306a36Sopenharmony_ci{ 285362306a36Sopenharmony_ci platform_driver_unregister(&hme_sbus_driver); 285462306a36Sopenharmony_ci 285562306a36Sopenharmony_ci while (qfe_sbus_list) { 285662306a36Sopenharmony_ci struct quattro *qfe = qfe_sbus_list; 285762306a36Sopenharmony_ci struct quattro *next = qfe->next; 285862306a36Sopenharmony_ci 285962306a36Sopenharmony_ci kfree(qfe); 286062306a36Sopenharmony_ci 286162306a36Sopenharmony_ci qfe_sbus_list = next; 286262306a36Sopenharmony_ci } 286362306a36Sopenharmony_ci} 286462306a36Sopenharmony_ci#endif 286562306a36Sopenharmony_ci 286662306a36Sopenharmony_cistatic int __init happy_meal_probe(void) 286762306a36Sopenharmony_ci{ 286862306a36Sopenharmony_ci int err = 0; 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_ci#ifdef CONFIG_SBUS 287162306a36Sopenharmony_ci err = happy_meal_sbus_init(); 287262306a36Sopenharmony_ci#endif 287362306a36Sopenharmony_ci#ifdef CONFIG_PCI 287462306a36Sopenharmony_ci if (!err) { 287562306a36Sopenharmony_ci err = happy_meal_pci_init(); 287662306a36Sopenharmony_ci#ifdef CONFIG_SBUS 287762306a36Sopenharmony_ci if (err) 287862306a36Sopenharmony_ci happy_meal_sbus_exit(); 287962306a36Sopenharmony_ci#endif 288062306a36Sopenharmony_ci } 288162306a36Sopenharmony_ci#endif 288262306a36Sopenharmony_ci 288362306a36Sopenharmony_ci return err; 288462306a36Sopenharmony_ci} 288562306a36Sopenharmony_ci 288662306a36Sopenharmony_ci 288762306a36Sopenharmony_cistatic void __exit happy_meal_exit(void) 288862306a36Sopenharmony_ci{ 288962306a36Sopenharmony_ci#ifdef CONFIG_SBUS 289062306a36Sopenharmony_ci happy_meal_sbus_exit(); 289162306a36Sopenharmony_ci#endif 289262306a36Sopenharmony_ci#ifdef CONFIG_PCI 289362306a36Sopenharmony_ci happy_meal_pci_exit(); 289462306a36Sopenharmony_ci#endif 289562306a36Sopenharmony_ci} 289662306a36Sopenharmony_ci 289762306a36Sopenharmony_cimodule_init(happy_meal_probe); 289862306a36Sopenharmony_cimodule_exit(happy_meal_exit); 2899