18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching, 38c2ecf20Sopenharmony_ci * auto carrier detecting ethernet driver. Also known as the 48c2ecf20Sopenharmony_ci * "Happy Meal Ethernet" found on SunSwift SBUS cards. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 1996, 1998, 1999, 2002, 2003, 78c2ecf20Sopenharmony_ci * 2006, 2008 David S. Miller (davem@davemloft.net) 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Changes : 108c2ecf20Sopenharmony_ci * 2000/11/11 Willy Tarreau <willy AT meta-x.org> 118c2ecf20Sopenharmony_ci * - port to non-sparc architectures. Tested only on x86 and 128c2ecf20Sopenharmony_ci * only currently works with QFE PCI cards. 138c2ecf20Sopenharmony_ci * - ability to specify the MAC address at module load time by passing this 148c2ecf20Sopenharmony_ci * argument : macaddr=0x00,0x10,0x20,0x30,0x40,0x50 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/kernel.h> 198c2ecf20Sopenharmony_ci#include <linux/types.h> 208c2ecf20Sopenharmony_ci#include <linux/fcntl.h> 218c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 228c2ecf20Sopenharmony_ci#include <linux/ioport.h> 238c2ecf20Sopenharmony_ci#include <linux/in.h> 248c2ecf20Sopenharmony_ci#include <linux/slab.h> 258c2ecf20Sopenharmony_ci#include <linux/string.h> 268c2ecf20Sopenharmony_ci#include <linux/delay.h> 278c2ecf20Sopenharmony_ci#include <linux/init.h> 288c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 298c2ecf20Sopenharmony_ci#include <linux/mii.h> 308c2ecf20Sopenharmony_ci#include <linux/crc32.h> 318c2ecf20Sopenharmony_ci#include <linux/random.h> 328c2ecf20Sopenharmony_ci#include <linux/errno.h> 338c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 348c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 358c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 368c2ecf20Sopenharmony_ci#include <linux/mm.h> 378c2ecf20Sopenharmony_ci#include <linux/bitops.h> 388c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#include <asm/io.h> 418c2ecf20Sopenharmony_ci#include <asm/dma.h> 428c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARC 458c2ecf20Sopenharmony_ci#include <linux/of.h> 468c2ecf20Sopenharmony_ci#include <linux/of_device.h> 478c2ecf20Sopenharmony_ci#include <asm/idprom.h> 488c2ecf20Sopenharmony_ci#include <asm/openprom.h> 498c2ecf20Sopenharmony_ci#include <asm/oplib.h> 508c2ecf20Sopenharmony_ci#include <asm/prom.h> 518c2ecf20Sopenharmony_ci#include <asm/auxio.h> 528c2ecf20Sopenharmony_ci#endif 538c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#include <asm/irq.h> 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 588c2ecf20Sopenharmony_ci#include <linux/pci.h> 598c2ecf20Sopenharmony_ci#endif 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#include "sunhme.h" 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define DRV_NAME "sunhme" 648c2ecf20Sopenharmony_ci#define DRV_VERSION "3.10" 658c2ecf20Sopenharmony_ci#define DRV_RELDATE "August 26, 2008" 668c2ecf20Sopenharmony_ci#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)" 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic char version[] = 698c2ecf20Sopenharmony_ci DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n"; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 728c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRV_AUTHOR); 738c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Sun HappyMealEthernet(HME) 10/100baseT ethernet driver"); 748c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic int macaddr[6]; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* accept MAC address of the form macaddr=0x08,0x00,0x20,0x30,0x40,0x50 */ 798c2ecf20Sopenharmony_cimodule_param_array(macaddr, int, NULL, 0); 808c2ecf20Sopenharmony_ciMODULE_PARM_DESC(macaddr, "Happy Meal MAC address to set"); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#ifdef CONFIG_SBUS 838c2ecf20Sopenharmony_cistatic struct quattro *qfe_sbus_list; 848c2ecf20Sopenharmony_ci#endif 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 878c2ecf20Sopenharmony_cistatic struct quattro *qfe_pci_list; 888c2ecf20Sopenharmony_ci#endif 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci#undef HMEDEBUG 918c2ecf20Sopenharmony_ci#undef SXDEBUG 928c2ecf20Sopenharmony_ci#undef RXDEBUG 938c2ecf20Sopenharmony_ci#undef TXDEBUG 948c2ecf20Sopenharmony_ci#undef TXLOGGING 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#ifdef TXLOGGING 978c2ecf20Sopenharmony_cistruct hme_tx_logent { 988c2ecf20Sopenharmony_ci unsigned int tstamp; 998c2ecf20Sopenharmony_ci int tx_new, tx_old; 1008c2ecf20Sopenharmony_ci unsigned int action; 1018c2ecf20Sopenharmony_ci#define TXLOG_ACTION_IRQ 0x01 1028c2ecf20Sopenharmony_ci#define TXLOG_ACTION_TXMIT 0x02 1038c2ecf20Sopenharmony_ci#define TXLOG_ACTION_TBUSY 0x04 1048c2ecf20Sopenharmony_ci#define TXLOG_ACTION_NBUFS 0x08 1058c2ecf20Sopenharmony_ci unsigned int status; 1068c2ecf20Sopenharmony_ci}; 1078c2ecf20Sopenharmony_ci#define TX_LOG_LEN 128 1088c2ecf20Sopenharmony_cistatic struct hme_tx_logent tx_log[TX_LOG_LEN]; 1098c2ecf20Sopenharmony_cistatic int txlog_cur_entry; 1108c2ecf20Sopenharmony_cistatic __inline__ void tx_add_log(struct happy_meal *hp, unsigned int a, unsigned int s) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct hme_tx_logent *tlp; 1138c2ecf20Sopenharmony_ci unsigned long flags; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci local_irq_save(flags); 1168c2ecf20Sopenharmony_ci tlp = &tx_log[txlog_cur_entry]; 1178c2ecf20Sopenharmony_ci tlp->tstamp = (unsigned int)jiffies; 1188c2ecf20Sopenharmony_ci tlp->tx_new = hp->tx_new; 1198c2ecf20Sopenharmony_ci tlp->tx_old = hp->tx_old; 1208c2ecf20Sopenharmony_ci tlp->action = a; 1218c2ecf20Sopenharmony_ci tlp->status = s; 1228c2ecf20Sopenharmony_ci txlog_cur_entry = (txlog_cur_entry + 1) & (TX_LOG_LEN - 1); 1238c2ecf20Sopenharmony_ci local_irq_restore(flags); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_cistatic __inline__ void tx_dump_log(void) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci int i, this; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci this = txlog_cur_entry; 1308c2ecf20Sopenharmony_ci for (i = 0; i < TX_LOG_LEN; i++) { 1318c2ecf20Sopenharmony_ci printk("TXLOG[%d]: j[%08x] tx[N(%d)O(%d)] action[%08x] stat[%08x]\n", i, 1328c2ecf20Sopenharmony_ci tx_log[this].tstamp, 1338c2ecf20Sopenharmony_ci tx_log[this].tx_new, tx_log[this].tx_old, 1348c2ecf20Sopenharmony_ci tx_log[this].action, tx_log[this].status); 1358c2ecf20Sopenharmony_ci this = (this + 1) & (TX_LOG_LEN - 1); 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_cistatic __inline__ void tx_dump_ring(struct happy_meal *hp) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct hmeal_init_block *hb = hp->happy_block; 1418c2ecf20Sopenharmony_ci struct happy_meal_txd *tp = &hb->happy_meal_txd[0]; 1428c2ecf20Sopenharmony_ci int i; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci for (i = 0; i < TX_RING_SIZE; i+=4) { 1458c2ecf20Sopenharmony_ci printk("TXD[%d..%d]: [%08x:%08x] [%08x:%08x] [%08x:%08x] [%08x:%08x]\n", 1468c2ecf20Sopenharmony_ci i, i + 4, 1478c2ecf20Sopenharmony_ci le32_to_cpu(tp[i].tx_flags), le32_to_cpu(tp[i].tx_addr), 1488c2ecf20Sopenharmony_ci le32_to_cpu(tp[i + 1].tx_flags), le32_to_cpu(tp[i + 1].tx_addr), 1498c2ecf20Sopenharmony_ci le32_to_cpu(tp[i + 2].tx_flags), le32_to_cpu(tp[i + 2].tx_addr), 1508c2ecf20Sopenharmony_ci le32_to_cpu(tp[i + 3].tx_flags), le32_to_cpu(tp[i + 3].tx_addr)); 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci#else 1548c2ecf20Sopenharmony_ci#define tx_add_log(hp, a, s) do { } while(0) 1558c2ecf20Sopenharmony_ci#define tx_dump_log() do { } while(0) 1568c2ecf20Sopenharmony_ci#define tx_dump_ring(hp) do { } while(0) 1578c2ecf20Sopenharmony_ci#endif 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci#ifdef HMEDEBUG 1608c2ecf20Sopenharmony_ci#define HMD(x) printk x 1618c2ecf20Sopenharmony_ci#else 1628c2ecf20Sopenharmony_ci#define HMD(x) 1638c2ecf20Sopenharmony_ci#endif 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* #define AUTO_SWITCH_DEBUG */ 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci#ifdef AUTO_SWITCH_DEBUG 1688c2ecf20Sopenharmony_ci#define ASD(x) printk x 1698c2ecf20Sopenharmony_ci#else 1708c2ecf20Sopenharmony_ci#define ASD(x) 1718c2ecf20Sopenharmony_ci#endif 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci#define DEFAULT_IPG0 16 /* For lance-mode only */ 1748c2ecf20Sopenharmony_ci#define DEFAULT_IPG1 8 /* For all modes */ 1758c2ecf20Sopenharmony_ci#define DEFAULT_IPG2 4 /* For all modes */ 1768c2ecf20Sopenharmony_ci#define DEFAULT_JAMSIZE 4 /* Toe jam */ 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci/* NOTE: In the descriptor writes one _must_ write the address 1798c2ecf20Sopenharmony_ci * member _first_. The card must not be allowed to see 1808c2ecf20Sopenharmony_ci * the updated descriptor flags until the address is 1818c2ecf20Sopenharmony_ci * correct. I've added a write memory barrier between 1828c2ecf20Sopenharmony_ci * the two stores so that I can sleep well at night... -DaveM 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci#if defined(CONFIG_SBUS) && defined(CONFIG_PCI) 1868c2ecf20Sopenharmony_cistatic void sbus_hme_write32(void __iomem *reg, u32 val) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci sbus_writel(val, reg); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic u32 sbus_hme_read32(void __iomem *reg) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci return sbus_readl(reg); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic void sbus_hme_write_rxd(struct happy_meal_rxd *rxd, u32 flags, u32 addr) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci rxd->rx_addr = (__force hme32)addr; 1998c2ecf20Sopenharmony_ci dma_wmb(); 2008c2ecf20Sopenharmony_ci rxd->rx_flags = (__force hme32)flags; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic void sbus_hme_write_txd(struct happy_meal_txd *txd, u32 flags, u32 addr) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci txd->tx_addr = (__force hme32)addr; 2068c2ecf20Sopenharmony_ci dma_wmb(); 2078c2ecf20Sopenharmony_ci txd->tx_flags = (__force hme32)flags; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic u32 sbus_hme_read_desc32(hme32 *p) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci return (__force u32)*p; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic void pci_hme_write32(void __iomem *reg, u32 val) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci writel(val, reg); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic u32 pci_hme_read32(void __iomem *reg) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci return readl(reg); 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic void pci_hme_write_rxd(struct happy_meal_rxd *rxd, u32 flags, u32 addr) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci rxd->rx_addr = (__force hme32)cpu_to_le32(addr); 2288c2ecf20Sopenharmony_ci dma_wmb(); 2298c2ecf20Sopenharmony_ci rxd->rx_flags = (__force hme32)cpu_to_le32(flags); 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic void pci_hme_write_txd(struct happy_meal_txd *txd, u32 flags, u32 addr) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci txd->tx_addr = (__force hme32)cpu_to_le32(addr); 2358c2ecf20Sopenharmony_ci dma_wmb(); 2368c2ecf20Sopenharmony_ci txd->tx_flags = (__force hme32)cpu_to_le32(flags); 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic u32 pci_hme_read_desc32(hme32 *p) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci return le32_to_cpup((__le32 *)p); 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci#define hme_write32(__hp, __reg, __val) \ 2458c2ecf20Sopenharmony_ci ((__hp)->write32((__reg), (__val))) 2468c2ecf20Sopenharmony_ci#define hme_read32(__hp, __reg) \ 2478c2ecf20Sopenharmony_ci ((__hp)->read32(__reg)) 2488c2ecf20Sopenharmony_ci#define hme_write_rxd(__hp, __rxd, __flags, __addr) \ 2498c2ecf20Sopenharmony_ci ((__hp)->write_rxd((__rxd), (__flags), (__addr))) 2508c2ecf20Sopenharmony_ci#define hme_write_txd(__hp, __txd, __flags, __addr) \ 2518c2ecf20Sopenharmony_ci ((__hp)->write_txd((__txd), (__flags), (__addr))) 2528c2ecf20Sopenharmony_ci#define hme_read_desc32(__hp, __p) \ 2538c2ecf20Sopenharmony_ci ((__hp)->read_desc32(__p)) 2548c2ecf20Sopenharmony_ci#define hme_dma_map(__hp, __ptr, __size, __dir) \ 2558c2ecf20Sopenharmony_ci ((__hp)->dma_map((__hp)->dma_dev, (__ptr), (__size), (__dir))) 2568c2ecf20Sopenharmony_ci#define hme_dma_unmap(__hp, __addr, __size, __dir) \ 2578c2ecf20Sopenharmony_ci ((__hp)->dma_unmap((__hp)->dma_dev, (__addr), (__size), (__dir))) 2588c2ecf20Sopenharmony_ci#define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \ 2598c2ecf20Sopenharmony_ci ((__hp)->dma_sync_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir))) 2608c2ecf20Sopenharmony_ci#define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \ 2618c2ecf20Sopenharmony_ci ((__hp)->dma_sync_for_device((__hp)->dma_dev, (__addr), (__size), (__dir))) 2628c2ecf20Sopenharmony_ci#else 2638c2ecf20Sopenharmony_ci#ifdef CONFIG_SBUS 2648c2ecf20Sopenharmony_ci/* SBUS only compilation */ 2658c2ecf20Sopenharmony_ci#define hme_write32(__hp, __reg, __val) \ 2668c2ecf20Sopenharmony_ci sbus_writel((__val), (__reg)) 2678c2ecf20Sopenharmony_ci#define hme_read32(__hp, __reg) \ 2688c2ecf20Sopenharmony_ci sbus_readl(__reg) 2698c2ecf20Sopenharmony_ci#define hme_write_rxd(__hp, __rxd, __flags, __addr) \ 2708c2ecf20Sopenharmony_cido { (__rxd)->rx_addr = (__force hme32)(u32)(__addr); \ 2718c2ecf20Sopenharmony_ci dma_wmb(); \ 2728c2ecf20Sopenharmony_ci (__rxd)->rx_flags = (__force hme32)(u32)(__flags); \ 2738c2ecf20Sopenharmony_ci} while(0) 2748c2ecf20Sopenharmony_ci#define hme_write_txd(__hp, __txd, __flags, __addr) \ 2758c2ecf20Sopenharmony_cido { (__txd)->tx_addr = (__force hme32)(u32)(__addr); \ 2768c2ecf20Sopenharmony_ci dma_wmb(); \ 2778c2ecf20Sopenharmony_ci (__txd)->tx_flags = (__force hme32)(u32)(__flags); \ 2788c2ecf20Sopenharmony_ci} while(0) 2798c2ecf20Sopenharmony_ci#define hme_read_desc32(__hp, __p) ((__force u32)(hme32)*(__p)) 2808c2ecf20Sopenharmony_ci#define hme_dma_map(__hp, __ptr, __size, __dir) \ 2818c2ecf20Sopenharmony_ci dma_map_single((__hp)->dma_dev, (__ptr), (__size), (__dir)) 2828c2ecf20Sopenharmony_ci#define hme_dma_unmap(__hp, __addr, __size, __dir) \ 2838c2ecf20Sopenharmony_ci dma_unmap_single((__hp)->dma_dev, (__addr), (__size), (__dir)) 2848c2ecf20Sopenharmony_ci#define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \ 2858c2ecf20Sopenharmony_ci dma_dma_sync_single_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir)) 2868c2ecf20Sopenharmony_ci#define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \ 2878c2ecf20Sopenharmony_ci dma_dma_sync_single_for_device((__hp)->dma_dev, (__addr), (__size), (__dir)) 2888c2ecf20Sopenharmony_ci#else 2898c2ecf20Sopenharmony_ci/* PCI only compilation */ 2908c2ecf20Sopenharmony_ci#define hme_write32(__hp, __reg, __val) \ 2918c2ecf20Sopenharmony_ci writel((__val), (__reg)) 2928c2ecf20Sopenharmony_ci#define hme_read32(__hp, __reg) \ 2938c2ecf20Sopenharmony_ci readl(__reg) 2948c2ecf20Sopenharmony_ci#define hme_write_rxd(__hp, __rxd, __flags, __addr) \ 2958c2ecf20Sopenharmony_cido { (__rxd)->rx_addr = (__force hme32)cpu_to_le32(__addr); \ 2968c2ecf20Sopenharmony_ci dma_wmb(); \ 2978c2ecf20Sopenharmony_ci (__rxd)->rx_flags = (__force hme32)cpu_to_le32(__flags); \ 2988c2ecf20Sopenharmony_ci} while(0) 2998c2ecf20Sopenharmony_ci#define hme_write_txd(__hp, __txd, __flags, __addr) \ 3008c2ecf20Sopenharmony_cido { (__txd)->tx_addr = (__force hme32)cpu_to_le32(__addr); \ 3018c2ecf20Sopenharmony_ci dma_wmb(); \ 3028c2ecf20Sopenharmony_ci (__txd)->tx_flags = (__force hme32)cpu_to_le32(__flags); \ 3038c2ecf20Sopenharmony_ci} while(0) 3048c2ecf20Sopenharmony_cistatic inline u32 hme_read_desc32(struct happy_meal *hp, hme32 *p) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci return le32_to_cpup((__le32 *)p); 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci#define hme_dma_map(__hp, __ptr, __size, __dir) \ 3098c2ecf20Sopenharmony_ci pci_map_single((__hp)->dma_dev, (__ptr), (__size), (__dir)) 3108c2ecf20Sopenharmony_ci#define hme_dma_unmap(__hp, __addr, __size, __dir) \ 3118c2ecf20Sopenharmony_ci pci_unmap_single((__hp)->dma_dev, (__addr), (__size), (__dir)) 3128c2ecf20Sopenharmony_ci#define hme_dma_sync_for_cpu(__hp, __addr, __size, __dir) \ 3138c2ecf20Sopenharmony_ci pci_dma_sync_single_for_cpu((__hp)->dma_dev, (__addr), (__size), (__dir)) 3148c2ecf20Sopenharmony_ci#define hme_dma_sync_for_device(__hp, __addr, __size, __dir) \ 3158c2ecf20Sopenharmony_ci pci_dma_sync_single_for_device((__hp)->dma_dev, (__addr), (__size), (__dir)) 3168c2ecf20Sopenharmony_ci#endif 3178c2ecf20Sopenharmony_ci#endif 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci/* Oh yes, the MIF BitBang is mighty fun to program. BitBucket is more like it. */ 3218c2ecf20Sopenharmony_cistatic void BB_PUT_BIT(struct happy_meal *hp, void __iomem *tregs, int bit) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBDATA, bit); 3248c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBCLOCK, 0); 3258c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBCLOCK, 1); 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci#if 0 3298c2ecf20Sopenharmony_cistatic u32 BB_GET_BIT(struct happy_meal *hp, void __iomem *tregs, int internal) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci u32 ret; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBCLOCK, 0); 3348c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBCLOCK, 1); 3358c2ecf20Sopenharmony_ci ret = hme_read32(hp, tregs + TCVR_CFG); 3368c2ecf20Sopenharmony_ci if (internal) 3378c2ecf20Sopenharmony_ci ret &= TCV_CFG_MDIO0; 3388c2ecf20Sopenharmony_ci else 3398c2ecf20Sopenharmony_ci ret &= TCV_CFG_MDIO1; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci return ret; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci#endif 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic u32 BB_GET_BIT2(struct happy_meal *hp, void __iomem *tregs, int internal) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci u32 retval; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBCLOCK, 0); 3508c2ecf20Sopenharmony_ci udelay(1); 3518c2ecf20Sopenharmony_ci retval = hme_read32(hp, tregs + TCVR_CFG); 3528c2ecf20Sopenharmony_ci if (internal) 3538c2ecf20Sopenharmony_ci retval &= TCV_CFG_MDIO0; 3548c2ecf20Sopenharmony_ci else 3558c2ecf20Sopenharmony_ci retval &= TCV_CFG_MDIO1; 3568c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBCLOCK, 1); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci return retval; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci#define TCVR_FAILURE 0x80000000 /* Impossible MIF read value */ 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic int happy_meal_bb_read(struct happy_meal *hp, 3648c2ecf20Sopenharmony_ci void __iomem *tregs, int reg) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci u32 tmp; 3678c2ecf20Sopenharmony_ci int retval = 0; 3688c2ecf20Sopenharmony_ci int i; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci ASD(("happy_meal_bb_read: reg=%d ", reg)); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci /* Enable the MIF BitBang outputs. */ 3738c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBOENAB, 1); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* Force BitBang into the idle state. */ 3768c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) 3778c2ecf20Sopenharmony_ci BB_PUT_BIT(hp, tregs, 1); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* Give it the read sequence. */ 3808c2ecf20Sopenharmony_ci BB_PUT_BIT(hp, tregs, 0); 3818c2ecf20Sopenharmony_ci BB_PUT_BIT(hp, tregs, 1); 3828c2ecf20Sopenharmony_ci BB_PUT_BIT(hp, tregs, 1); 3838c2ecf20Sopenharmony_ci BB_PUT_BIT(hp, tregs, 0); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* Give it the PHY address. */ 3868c2ecf20Sopenharmony_ci tmp = hp->paddr & 0xff; 3878c2ecf20Sopenharmony_ci for (i = 4; i >= 0; i--) 3888c2ecf20Sopenharmony_ci BB_PUT_BIT(hp, tregs, ((tmp >> i) & 1)); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci /* Tell it what register we want to read. */ 3918c2ecf20Sopenharmony_ci tmp = (reg & 0xff); 3928c2ecf20Sopenharmony_ci for (i = 4; i >= 0; i--) 3938c2ecf20Sopenharmony_ci BB_PUT_BIT(hp, tregs, ((tmp >> i) & 1)); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci /* Close down the MIF BitBang outputs. */ 3968c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBOENAB, 0); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci /* Now read in the value. */ 3998c2ecf20Sopenharmony_ci (void) BB_GET_BIT2(hp, tregs, (hp->tcvr_type == internal)); 4008c2ecf20Sopenharmony_ci for (i = 15; i >= 0; i--) 4018c2ecf20Sopenharmony_ci retval |= BB_GET_BIT2(hp, tregs, (hp->tcvr_type == internal)); 4028c2ecf20Sopenharmony_ci (void) BB_GET_BIT2(hp, tregs, (hp->tcvr_type == internal)); 4038c2ecf20Sopenharmony_ci (void) BB_GET_BIT2(hp, tregs, (hp->tcvr_type == internal)); 4048c2ecf20Sopenharmony_ci (void) BB_GET_BIT2(hp, tregs, (hp->tcvr_type == internal)); 4058c2ecf20Sopenharmony_ci ASD(("value=%x\n", retval)); 4068c2ecf20Sopenharmony_ci return retval; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic void happy_meal_bb_write(struct happy_meal *hp, 4108c2ecf20Sopenharmony_ci void __iomem *tregs, int reg, 4118c2ecf20Sopenharmony_ci unsigned short value) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci u32 tmp; 4148c2ecf20Sopenharmony_ci int i; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci ASD(("happy_meal_bb_write: reg=%d value=%x\n", reg, value)); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* Enable the MIF BitBang outputs. */ 4198c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBOENAB, 1); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* Force BitBang into the idle state. */ 4228c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) 4238c2ecf20Sopenharmony_ci BB_PUT_BIT(hp, tregs, 1); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci /* Give it write sequence. */ 4268c2ecf20Sopenharmony_ci BB_PUT_BIT(hp, tregs, 0); 4278c2ecf20Sopenharmony_ci BB_PUT_BIT(hp, tregs, 1); 4288c2ecf20Sopenharmony_ci BB_PUT_BIT(hp, tregs, 0); 4298c2ecf20Sopenharmony_ci BB_PUT_BIT(hp, tregs, 1); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci /* Give it the PHY address. */ 4328c2ecf20Sopenharmony_ci tmp = (hp->paddr & 0xff); 4338c2ecf20Sopenharmony_ci for (i = 4; i >= 0; i--) 4348c2ecf20Sopenharmony_ci BB_PUT_BIT(hp, tregs, ((tmp >> i) & 1)); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci /* Tell it what register we will be writing. */ 4378c2ecf20Sopenharmony_ci tmp = (reg & 0xff); 4388c2ecf20Sopenharmony_ci for (i = 4; i >= 0; i--) 4398c2ecf20Sopenharmony_ci BB_PUT_BIT(hp, tregs, ((tmp >> i) & 1)); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* Tell it to become ready for the bits. */ 4428c2ecf20Sopenharmony_ci BB_PUT_BIT(hp, tregs, 1); 4438c2ecf20Sopenharmony_ci BB_PUT_BIT(hp, tregs, 0); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci for (i = 15; i >= 0; i--) 4468c2ecf20Sopenharmony_ci BB_PUT_BIT(hp, tregs, ((value >> i) & 1)); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci /* Close down the MIF BitBang outputs. */ 4498c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_BBOENAB, 0); 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci#define TCVR_READ_TRIES 16 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_cistatic int happy_meal_tcvr_read(struct happy_meal *hp, 4558c2ecf20Sopenharmony_ci void __iomem *tregs, int reg) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci int tries = TCVR_READ_TRIES; 4588c2ecf20Sopenharmony_ci int retval; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci ASD(("happy_meal_tcvr_read: reg=0x%02x ", reg)); 4618c2ecf20Sopenharmony_ci if (hp->tcvr_type == none) { 4628c2ecf20Sopenharmony_ci ASD(("no transceiver, value=TCVR_FAILURE\n")); 4638c2ecf20Sopenharmony_ci return TCVR_FAILURE; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (!(hp->happy_flags & HFLAG_FENABLE)) { 4678c2ecf20Sopenharmony_ci ASD(("doing bit bang\n")); 4688c2ecf20Sopenharmony_ci return happy_meal_bb_read(hp, tregs, reg); 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_FRAME, 4728c2ecf20Sopenharmony_ci (FRAME_READ | (hp->paddr << 23) | ((reg & 0xff) << 18))); 4738c2ecf20Sopenharmony_ci while (!(hme_read32(hp, tregs + TCVR_FRAME) & 0x10000) && --tries) 4748c2ecf20Sopenharmony_ci udelay(20); 4758c2ecf20Sopenharmony_ci if (!tries) { 4768c2ecf20Sopenharmony_ci printk(KERN_ERR "happy meal: Aieee, transceiver MIF read bolixed\n"); 4778c2ecf20Sopenharmony_ci return TCVR_FAILURE; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci retval = hme_read32(hp, tregs + TCVR_FRAME) & 0xffff; 4808c2ecf20Sopenharmony_ci ASD(("value=%04x\n", retval)); 4818c2ecf20Sopenharmony_ci return retval; 4828c2ecf20Sopenharmony_ci} 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci#define TCVR_WRITE_TRIES 16 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic void happy_meal_tcvr_write(struct happy_meal *hp, 4878c2ecf20Sopenharmony_ci void __iomem *tregs, int reg, 4888c2ecf20Sopenharmony_ci unsigned short value) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci int tries = TCVR_WRITE_TRIES; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci ASD(("happy_meal_tcvr_write: reg=0x%02x value=%04x\n", reg, value)); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci /* Welcome to Sun Microsystems, can I take your order please? */ 4958c2ecf20Sopenharmony_ci if (!(hp->happy_flags & HFLAG_FENABLE)) { 4968c2ecf20Sopenharmony_ci happy_meal_bb_write(hp, tregs, reg, value); 4978c2ecf20Sopenharmony_ci return; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci /* Would you like fries with that? */ 5018c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_FRAME, 5028c2ecf20Sopenharmony_ci (FRAME_WRITE | (hp->paddr << 23) | 5038c2ecf20Sopenharmony_ci ((reg & 0xff) << 18) | (value & 0xffff))); 5048c2ecf20Sopenharmony_ci while (!(hme_read32(hp, tregs + TCVR_FRAME) & 0x10000) && --tries) 5058c2ecf20Sopenharmony_ci udelay(20); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci /* Anything else? */ 5088c2ecf20Sopenharmony_ci if (!tries) 5098c2ecf20Sopenharmony_ci printk(KERN_ERR "happy meal: Aieee, transceiver MIF write bolixed\n"); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci /* Fifty-two cents is your change, have a nice day. */ 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci/* Auto negotiation. The scheme is very simple. We have a timer routine 5158c2ecf20Sopenharmony_ci * that keeps watching the auto negotiation process as it progresses. 5168c2ecf20Sopenharmony_ci * The DP83840 is first told to start doing it's thing, we set up the time 5178c2ecf20Sopenharmony_ci * and place the timer state machine in it's initial state. 5188c2ecf20Sopenharmony_ci * 5198c2ecf20Sopenharmony_ci * Here the timer peeks at the DP83840 status registers at each click to see 5208c2ecf20Sopenharmony_ci * if the auto negotiation has completed, we assume here that the DP83840 PHY 5218c2ecf20Sopenharmony_ci * will time out at some point and just tell us what (didn't) happen. For 5228c2ecf20Sopenharmony_ci * complete coverage we only allow so many of the ticks at this level to run, 5238c2ecf20Sopenharmony_ci * when this has expired we print a warning message and try another strategy. 5248c2ecf20Sopenharmony_ci * This "other" strategy is to force the interface into various speed/duplex 5258c2ecf20Sopenharmony_ci * configurations and we stop when we see a link-up condition before the 5268c2ecf20Sopenharmony_ci * maximum number of "peek" ticks have occurred. 5278c2ecf20Sopenharmony_ci * 5288c2ecf20Sopenharmony_ci * Once a valid link status has been detected we configure the BigMAC and 5298c2ecf20Sopenharmony_ci * the rest of the Happy Meal to speak the most efficient protocol we could 5308c2ecf20Sopenharmony_ci * get a clean link for. The priority for link configurations, highest first 5318c2ecf20Sopenharmony_ci * is: 5328c2ecf20Sopenharmony_ci * 100 Base-T Full Duplex 5338c2ecf20Sopenharmony_ci * 100 Base-T Half Duplex 5348c2ecf20Sopenharmony_ci * 10 Base-T Full Duplex 5358c2ecf20Sopenharmony_ci * 10 Base-T Half Duplex 5368c2ecf20Sopenharmony_ci * 5378c2ecf20Sopenharmony_ci * We start a new timer now, after a successful auto negotiation status has 5388c2ecf20Sopenharmony_ci * been detected. This timer just waits for the link-up bit to get set in 5398c2ecf20Sopenharmony_ci * the BMCR of the DP83840. When this occurs we print a kernel log message 5408c2ecf20Sopenharmony_ci * describing the link type in use and the fact that it is up. 5418c2ecf20Sopenharmony_ci * 5428c2ecf20Sopenharmony_ci * If a fatal error of some sort is signalled and detected in the interrupt 5438c2ecf20Sopenharmony_ci * service routine, and the chip is reset, or the link is ifconfig'd down 5448c2ecf20Sopenharmony_ci * and then back up, this entire process repeats itself all over again. 5458c2ecf20Sopenharmony_ci */ 5468c2ecf20Sopenharmony_cistatic int try_next_permutation(struct happy_meal *hp, void __iomem *tregs) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci /* Downgrade from full to half duplex. Only possible 5518c2ecf20Sopenharmony_ci * via ethtool. 5528c2ecf20Sopenharmony_ci */ 5538c2ecf20Sopenharmony_ci if (hp->sw_bmcr & BMCR_FULLDPLX) { 5548c2ecf20Sopenharmony_ci hp->sw_bmcr &= ~(BMCR_FULLDPLX); 5558c2ecf20Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr); 5568c2ecf20Sopenharmony_ci return 0; 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci /* Downgrade from 100 to 10. */ 5608c2ecf20Sopenharmony_ci if (hp->sw_bmcr & BMCR_SPEED100) { 5618c2ecf20Sopenharmony_ci hp->sw_bmcr &= ~(BMCR_SPEED100); 5628c2ecf20Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr); 5638c2ecf20Sopenharmony_ci return 0; 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci /* We've tried everything. */ 5678c2ecf20Sopenharmony_ci return -1; 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_cistatic void display_link_mode(struct happy_meal *hp, void __iomem *tregs) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Link is up using ", hp->dev->name); 5738c2ecf20Sopenharmony_ci if (hp->tcvr_type == external) 5748c2ecf20Sopenharmony_ci printk("external "); 5758c2ecf20Sopenharmony_ci else 5768c2ecf20Sopenharmony_ci printk("internal "); 5778c2ecf20Sopenharmony_ci printk("transceiver at "); 5788c2ecf20Sopenharmony_ci hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, MII_LPA); 5798c2ecf20Sopenharmony_ci if (hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) { 5808c2ecf20Sopenharmony_ci if (hp->sw_lpa & LPA_100FULL) 5818c2ecf20Sopenharmony_ci printk("100Mb/s, Full Duplex.\n"); 5828c2ecf20Sopenharmony_ci else 5838c2ecf20Sopenharmony_ci printk("100Mb/s, Half Duplex.\n"); 5848c2ecf20Sopenharmony_ci } else { 5858c2ecf20Sopenharmony_ci if (hp->sw_lpa & LPA_10FULL) 5868c2ecf20Sopenharmony_ci printk("10Mb/s, Full Duplex.\n"); 5878c2ecf20Sopenharmony_ci else 5888c2ecf20Sopenharmony_ci printk("10Mb/s, Half Duplex.\n"); 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cistatic void display_forced_link_mode(struct happy_meal *hp, void __iomem *tregs) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Link has been forced up using ", hp->dev->name); 5958c2ecf20Sopenharmony_ci if (hp->tcvr_type == external) 5968c2ecf20Sopenharmony_ci printk("external "); 5978c2ecf20Sopenharmony_ci else 5988c2ecf20Sopenharmony_ci printk("internal "); 5998c2ecf20Sopenharmony_ci printk("transceiver at "); 6008c2ecf20Sopenharmony_ci hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR); 6018c2ecf20Sopenharmony_ci if (hp->sw_bmcr & BMCR_SPEED100) 6028c2ecf20Sopenharmony_ci printk("100Mb/s, "); 6038c2ecf20Sopenharmony_ci else 6048c2ecf20Sopenharmony_ci printk("10Mb/s, "); 6058c2ecf20Sopenharmony_ci if (hp->sw_bmcr & BMCR_FULLDPLX) 6068c2ecf20Sopenharmony_ci printk("Full Duplex.\n"); 6078c2ecf20Sopenharmony_ci else 6088c2ecf20Sopenharmony_ci printk("Half Duplex.\n"); 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_cistatic int set_happy_link_modes(struct happy_meal *hp, void __iomem *tregs) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci int full; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci /* All we care about is making sure the bigmac tx_cfg has a 6168c2ecf20Sopenharmony_ci * proper duplex setting. 6178c2ecf20Sopenharmony_ci */ 6188c2ecf20Sopenharmony_ci if (hp->timer_state == arbwait) { 6198c2ecf20Sopenharmony_ci hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, MII_LPA); 6208c2ecf20Sopenharmony_ci if (!(hp->sw_lpa & (LPA_10HALF | LPA_10FULL | LPA_100HALF | LPA_100FULL))) 6218c2ecf20Sopenharmony_ci goto no_response; 6228c2ecf20Sopenharmony_ci if (hp->sw_lpa & LPA_100FULL) 6238c2ecf20Sopenharmony_ci full = 1; 6248c2ecf20Sopenharmony_ci else if (hp->sw_lpa & LPA_100HALF) 6258c2ecf20Sopenharmony_ci full = 0; 6268c2ecf20Sopenharmony_ci else if (hp->sw_lpa & LPA_10FULL) 6278c2ecf20Sopenharmony_ci full = 1; 6288c2ecf20Sopenharmony_ci else 6298c2ecf20Sopenharmony_ci full = 0; 6308c2ecf20Sopenharmony_ci } else { 6318c2ecf20Sopenharmony_ci /* Forcing a link mode. */ 6328c2ecf20Sopenharmony_ci hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR); 6338c2ecf20Sopenharmony_ci if (hp->sw_bmcr & BMCR_FULLDPLX) 6348c2ecf20Sopenharmony_ci full = 1; 6358c2ecf20Sopenharmony_ci else 6368c2ecf20Sopenharmony_ci full = 0; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci /* Before changing other bits in the tx_cfg register, and in 6408c2ecf20Sopenharmony_ci * general any of other the TX config registers too, you 6418c2ecf20Sopenharmony_ci * must: 6428c2ecf20Sopenharmony_ci * 1) Clear Enable 6438c2ecf20Sopenharmony_ci * 2) Poll with reads until that bit reads back as zero 6448c2ecf20Sopenharmony_ci * 3) Make TX configuration changes 6458c2ecf20Sopenharmony_ci * 4) Set Enable once more 6468c2ecf20Sopenharmony_ci */ 6478c2ecf20Sopenharmony_ci hme_write32(hp, hp->bigmacregs + BMAC_TXCFG, 6488c2ecf20Sopenharmony_ci hme_read32(hp, hp->bigmacregs + BMAC_TXCFG) & 6498c2ecf20Sopenharmony_ci ~(BIGMAC_TXCFG_ENABLE)); 6508c2ecf20Sopenharmony_ci while (hme_read32(hp, hp->bigmacregs + BMAC_TXCFG) & BIGMAC_TXCFG_ENABLE) 6518c2ecf20Sopenharmony_ci barrier(); 6528c2ecf20Sopenharmony_ci if (full) { 6538c2ecf20Sopenharmony_ci hp->happy_flags |= HFLAG_FULL; 6548c2ecf20Sopenharmony_ci hme_write32(hp, hp->bigmacregs + BMAC_TXCFG, 6558c2ecf20Sopenharmony_ci hme_read32(hp, hp->bigmacregs + BMAC_TXCFG) | 6568c2ecf20Sopenharmony_ci BIGMAC_TXCFG_FULLDPLX); 6578c2ecf20Sopenharmony_ci } else { 6588c2ecf20Sopenharmony_ci hp->happy_flags &= ~(HFLAG_FULL); 6598c2ecf20Sopenharmony_ci hme_write32(hp, hp->bigmacregs + BMAC_TXCFG, 6608c2ecf20Sopenharmony_ci hme_read32(hp, hp->bigmacregs + BMAC_TXCFG) & 6618c2ecf20Sopenharmony_ci ~(BIGMAC_TXCFG_FULLDPLX)); 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci hme_write32(hp, hp->bigmacregs + BMAC_TXCFG, 6648c2ecf20Sopenharmony_ci hme_read32(hp, hp->bigmacregs + BMAC_TXCFG) | 6658c2ecf20Sopenharmony_ci BIGMAC_TXCFG_ENABLE); 6668c2ecf20Sopenharmony_ci return 0; 6678c2ecf20Sopenharmony_cino_response: 6688c2ecf20Sopenharmony_ci return 1; 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cistatic int happy_meal_init(struct happy_meal *hp); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic int is_lucent_phy(struct happy_meal *hp) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci void __iomem *tregs = hp->tcvregs; 6768c2ecf20Sopenharmony_ci unsigned short mr2, mr3; 6778c2ecf20Sopenharmony_ci int ret = 0; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci mr2 = happy_meal_tcvr_read(hp, tregs, 2); 6808c2ecf20Sopenharmony_ci mr3 = happy_meal_tcvr_read(hp, tregs, 3); 6818c2ecf20Sopenharmony_ci if ((mr2 & 0xffff) == 0x0180 && 6828c2ecf20Sopenharmony_ci ((mr3 & 0xffff) >> 10) == 0x1d) 6838c2ecf20Sopenharmony_ci ret = 1; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci return ret; 6868c2ecf20Sopenharmony_ci} 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_cistatic void happy_meal_timer(struct timer_list *t) 6898c2ecf20Sopenharmony_ci{ 6908c2ecf20Sopenharmony_ci struct happy_meal *hp = from_timer(hp, t, happy_timer); 6918c2ecf20Sopenharmony_ci void __iomem *tregs = hp->tcvregs; 6928c2ecf20Sopenharmony_ci int restart_timer = 0; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci hp->timer_ticks++; 6978c2ecf20Sopenharmony_ci switch(hp->timer_state) { 6988c2ecf20Sopenharmony_ci case arbwait: 6998c2ecf20Sopenharmony_ci /* Only allow for 5 ticks, thats 10 seconds and much too 7008c2ecf20Sopenharmony_ci * long to wait for arbitration to complete. 7018c2ecf20Sopenharmony_ci */ 7028c2ecf20Sopenharmony_ci if (hp->timer_ticks >= 10) { 7038c2ecf20Sopenharmony_ci /* Enter force mode. */ 7048c2ecf20Sopenharmony_ci do_force_mode: 7058c2ecf20Sopenharmony_ci hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR); 7068c2ecf20Sopenharmony_ci printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful, trying force link mode\n", 7078c2ecf20Sopenharmony_ci hp->dev->name); 7088c2ecf20Sopenharmony_ci hp->sw_bmcr = BMCR_SPEED100; 7098c2ecf20Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (!is_lucent_phy(hp)) { 7128c2ecf20Sopenharmony_ci /* OK, seems we need do disable the transceiver for the first 7138c2ecf20Sopenharmony_ci * tick to make sure we get an accurate link state at the 7148c2ecf20Sopenharmony_ci * second tick. 7158c2ecf20Sopenharmony_ci */ 7168c2ecf20Sopenharmony_ci hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG); 7178c2ecf20Sopenharmony_ci hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB); 7188c2ecf20Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, hp->sw_csconfig); 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci hp->timer_state = ltrywait; 7218c2ecf20Sopenharmony_ci hp->timer_ticks = 0; 7228c2ecf20Sopenharmony_ci restart_timer = 1; 7238c2ecf20Sopenharmony_ci } else { 7248c2ecf20Sopenharmony_ci /* Anything interesting happen? */ 7258c2ecf20Sopenharmony_ci hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, MII_BMSR); 7268c2ecf20Sopenharmony_ci if (hp->sw_bmsr & BMSR_ANEGCOMPLETE) { 7278c2ecf20Sopenharmony_ci int ret; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci /* Just what we've been waiting for... */ 7308c2ecf20Sopenharmony_ci ret = set_happy_link_modes(hp, tregs); 7318c2ecf20Sopenharmony_ci if (ret) { 7328c2ecf20Sopenharmony_ci /* Ooops, something bad happened, go to force 7338c2ecf20Sopenharmony_ci * mode. 7348c2ecf20Sopenharmony_ci * 7358c2ecf20Sopenharmony_ci * XXX Broken hubs which don't support 802.3u 7368c2ecf20Sopenharmony_ci * XXX auto-negotiation make this happen as well. 7378c2ecf20Sopenharmony_ci */ 7388c2ecf20Sopenharmony_ci goto do_force_mode; 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci /* Success, at least so far, advance our state engine. */ 7428c2ecf20Sopenharmony_ci hp->timer_state = lupwait; 7438c2ecf20Sopenharmony_ci restart_timer = 1; 7448c2ecf20Sopenharmony_ci } else { 7458c2ecf20Sopenharmony_ci restart_timer = 1; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci break; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci case lupwait: 7518c2ecf20Sopenharmony_ci /* Auto negotiation was successful and we are awaiting a 7528c2ecf20Sopenharmony_ci * link up status. I have decided to let this timer run 7538c2ecf20Sopenharmony_ci * forever until some sort of error is signalled, reporting 7548c2ecf20Sopenharmony_ci * a message to the user at 10 second intervals. 7558c2ecf20Sopenharmony_ci */ 7568c2ecf20Sopenharmony_ci hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, MII_BMSR); 7578c2ecf20Sopenharmony_ci if (hp->sw_bmsr & BMSR_LSTATUS) { 7588c2ecf20Sopenharmony_ci /* Wheee, it's up, display the link mode in use and put 7598c2ecf20Sopenharmony_ci * the timer to sleep. 7608c2ecf20Sopenharmony_ci */ 7618c2ecf20Sopenharmony_ci display_link_mode(hp, tregs); 7628c2ecf20Sopenharmony_ci hp->timer_state = asleep; 7638c2ecf20Sopenharmony_ci restart_timer = 0; 7648c2ecf20Sopenharmony_ci } else { 7658c2ecf20Sopenharmony_ci if (hp->timer_ticks >= 10) { 7668c2ecf20Sopenharmony_ci printk(KERN_NOTICE "%s: Auto negotiation successful, link still " 7678c2ecf20Sopenharmony_ci "not completely up.\n", hp->dev->name); 7688c2ecf20Sopenharmony_ci hp->timer_ticks = 0; 7698c2ecf20Sopenharmony_ci restart_timer = 1; 7708c2ecf20Sopenharmony_ci } else { 7718c2ecf20Sopenharmony_ci restart_timer = 1; 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci break; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci case ltrywait: 7778c2ecf20Sopenharmony_ci /* Making the timeout here too long can make it take 7788c2ecf20Sopenharmony_ci * annoyingly long to attempt all of the link mode 7798c2ecf20Sopenharmony_ci * permutations, but then again this is essentially 7808c2ecf20Sopenharmony_ci * error recovery code for the most part. 7818c2ecf20Sopenharmony_ci */ 7828c2ecf20Sopenharmony_ci hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, MII_BMSR); 7838c2ecf20Sopenharmony_ci hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, DP83840_CSCONFIG); 7848c2ecf20Sopenharmony_ci if (hp->timer_ticks == 1) { 7858c2ecf20Sopenharmony_ci if (!is_lucent_phy(hp)) { 7868c2ecf20Sopenharmony_ci /* Re-enable transceiver, we'll re-enable the transceiver next 7878c2ecf20Sopenharmony_ci * tick, then check link state on the following tick. 7888c2ecf20Sopenharmony_ci */ 7898c2ecf20Sopenharmony_ci hp->sw_csconfig |= CSCONFIG_TCVDISAB; 7908c2ecf20Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, 7918c2ecf20Sopenharmony_ci DP83840_CSCONFIG, hp->sw_csconfig); 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci restart_timer = 1; 7948c2ecf20Sopenharmony_ci break; 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci if (hp->timer_ticks == 2) { 7978c2ecf20Sopenharmony_ci if (!is_lucent_phy(hp)) { 7988c2ecf20Sopenharmony_ci hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB); 7998c2ecf20Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, 8008c2ecf20Sopenharmony_ci DP83840_CSCONFIG, hp->sw_csconfig); 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci restart_timer = 1; 8038c2ecf20Sopenharmony_ci break; 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci if (hp->sw_bmsr & BMSR_LSTATUS) { 8068c2ecf20Sopenharmony_ci /* Force mode selection success. */ 8078c2ecf20Sopenharmony_ci display_forced_link_mode(hp, tregs); 8088c2ecf20Sopenharmony_ci set_happy_link_modes(hp, tregs); /* XXX error? then what? */ 8098c2ecf20Sopenharmony_ci hp->timer_state = asleep; 8108c2ecf20Sopenharmony_ci restart_timer = 0; 8118c2ecf20Sopenharmony_ci } else { 8128c2ecf20Sopenharmony_ci if (hp->timer_ticks >= 4) { /* 6 seconds or so... */ 8138c2ecf20Sopenharmony_ci int ret; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci ret = try_next_permutation(hp, tregs); 8168c2ecf20Sopenharmony_ci if (ret == -1) { 8178c2ecf20Sopenharmony_ci /* Aieee, tried them all, reset the 8188c2ecf20Sopenharmony_ci * chip and try all over again. 8198c2ecf20Sopenharmony_ci */ 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci /* Let the user know... */ 8228c2ecf20Sopenharmony_ci printk(KERN_NOTICE "%s: Link down, cable problem?\n", 8238c2ecf20Sopenharmony_ci hp->dev->name); 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci ret = happy_meal_init(hp); 8268c2ecf20Sopenharmony_ci if (ret) { 8278c2ecf20Sopenharmony_ci /* ho hum... */ 8288c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Error, cannot re-init the " 8298c2ecf20Sopenharmony_ci "Happy Meal.\n", hp->dev->name); 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci goto out; 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci if (!is_lucent_phy(hp)) { 8348c2ecf20Sopenharmony_ci hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, 8358c2ecf20Sopenharmony_ci DP83840_CSCONFIG); 8368c2ecf20Sopenharmony_ci hp->sw_csconfig |= CSCONFIG_TCVDISAB; 8378c2ecf20Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, 8388c2ecf20Sopenharmony_ci DP83840_CSCONFIG, hp->sw_csconfig); 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci hp->timer_ticks = 0; 8418c2ecf20Sopenharmony_ci restart_timer = 1; 8428c2ecf20Sopenharmony_ci } else { 8438c2ecf20Sopenharmony_ci restart_timer = 1; 8448c2ecf20Sopenharmony_ci } 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci break; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci case asleep: 8498c2ecf20Sopenharmony_ci default: 8508c2ecf20Sopenharmony_ci /* Can't happens.... */ 8518c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Aieee, link timer is asleep but we got one anyways!\n", 8528c2ecf20Sopenharmony_ci hp->dev->name); 8538c2ecf20Sopenharmony_ci restart_timer = 0; 8548c2ecf20Sopenharmony_ci hp->timer_ticks = 0; 8558c2ecf20Sopenharmony_ci hp->timer_state = asleep; /* foo on you */ 8568c2ecf20Sopenharmony_ci break; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci if (restart_timer) { 8608c2ecf20Sopenharmony_ci hp->happy_timer.expires = jiffies + ((12 * HZ)/10); /* 1.2 sec. */ 8618c2ecf20Sopenharmony_ci add_timer(&hp->happy_timer); 8628c2ecf20Sopenharmony_ci } 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ciout: 8658c2ecf20Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 8668c2ecf20Sopenharmony_ci} 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci#define TX_RESET_TRIES 32 8698c2ecf20Sopenharmony_ci#define RX_RESET_TRIES 32 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci/* hp->happy_lock must be held */ 8728c2ecf20Sopenharmony_cistatic void happy_meal_tx_reset(struct happy_meal *hp, void __iomem *bregs) 8738c2ecf20Sopenharmony_ci{ 8748c2ecf20Sopenharmony_ci int tries = TX_RESET_TRIES; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci HMD(("happy_meal_tx_reset: reset, ")); 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci /* Would you like to try our SMCC Delux? */ 8798c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_TXSWRESET, 0); 8808c2ecf20Sopenharmony_ci while ((hme_read32(hp, bregs + BMAC_TXSWRESET) & 1) && --tries) 8818c2ecf20Sopenharmony_ci udelay(20); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci /* Lettuce, tomato, buggy hardware (no extra charge)? */ 8848c2ecf20Sopenharmony_ci if (!tries) 8858c2ecf20Sopenharmony_ci printk(KERN_ERR "happy meal: Transceiver BigMac ATTACK!"); 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci /* Take care. */ 8888c2ecf20Sopenharmony_ci HMD(("done\n")); 8898c2ecf20Sopenharmony_ci} 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci/* hp->happy_lock must be held */ 8928c2ecf20Sopenharmony_cistatic void happy_meal_rx_reset(struct happy_meal *hp, void __iomem *bregs) 8938c2ecf20Sopenharmony_ci{ 8948c2ecf20Sopenharmony_ci int tries = RX_RESET_TRIES; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci HMD(("happy_meal_rx_reset: reset, ")); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci /* We have a special on GNU/Viking hardware bugs today. */ 8998c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_RXSWRESET, 0); 9008c2ecf20Sopenharmony_ci while ((hme_read32(hp, bregs + BMAC_RXSWRESET) & 1) && --tries) 9018c2ecf20Sopenharmony_ci udelay(20); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci /* Will that be all? */ 9048c2ecf20Sopenharmony_ci if (!tries) 9058c2ecf20Sopenharmony_ci printk(KERN_ERR "happy meal: Receiver BigMac ATTACK!"); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci /* Don't forget your vik_1137125_wa. Have a nice day. */ 9088c2ecf20Sopenharmony_ci HMD(("done\n")); 9098c2ecf20Sopenharmony_ci} 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci#define STOP_TRIES 16 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci/* hp->happy_lock must be held */ 9148c2ecf20Sopenharmony_cistatic void happy_meal_stop(struct happy_meal *hp, void __iomem *gregs) 9158c2ecf20Sopenharmony_ci{ 9168c2ecf20Sopenharmony_ci int tries = STOP_TRIES; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci HMD(("happy_meal_stop: reset, ")); 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci /* We're consolidating our STB products, it's your lucky day. */ 9218c2ecf20Sopenharmony_ci hme_write32(hp, gregs + GREG_SWRESET, GREG_RESET_ALL); 9228c2ecf20Sopenharmony_ci while (hme_read32(hp, gregs + GREG_SWRESET) && --tries) 9238c2ecf20Sopenharmony_ci udelay(20); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci /* Come back next week when we are "Sun Microelectronics". */ 9268c2ecf20Sopenharmony_ci if (!tries) 9278c2ecf20Sopenharmony_ci printk(KERN_ERR "happy meal: Fry guys."); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci /* Remember: "Different name, same old buggy as shit hardware." */ 9308c2ecf20Sopenharmony_ci HMD(("done\n")); 9318c2ecf20Sopenharmony_ci} 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci/* hp->happy_lock must be held */ 9348c2ecf20Sopenharmony_cistatic void happy_meal_get_counters(struct happy_meal *hp, void __iomem *bregs) 9358c2ecf20Sopenharmony_ci{ 9368c2ecf20Sopenharmony_ci struct net_device_stats *stats = &hp->dev->stats; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci stats->rx_crc_errors += hme_read32(hp, bregs + BMAC_RCRCECTR); 9398c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_RCRCECTR, 0); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci stats->rx_frame_errors += hme_read32(hp, bregs + BMAC_UNALECTR); 9428c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_UNALECTR, 0); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci stats->rx_length_errors += hme_read32(hp, bregs + BMAC_GLECTR); 9458c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_GLECTR, 0); 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci stats->tx_aborted_errors += hme_read32(hp, bregs + BMAC_EXCTR); 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci stats->collisions += 9508c2ecf20Sopenharmony_ci (hme_read32(hp, bregs + BMAC_EXCTR) + 9518c2ecf20Sopenharmony_ci hme_read32(hp, bregs + BMAC_LTCTR)); 9528c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_EXCTR, 0); 9538c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_LTCTR, 0); 9548c2ecf20Sopenharmony_ci} 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci/* hp->happy_lock must be held */ 9578c2ecf20Sopenharmony_cistatic void happy_meal_poll_stop(struct happy_meal *hp, void __iomem *tregs) 9588c2ecf20Sopenharmony_ci{ 9598c2ecf20Sopenharmony_ci ASD(("happy_meal_poll_stop: ")); 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci /* If polling disabled or not polling already, nothing to do. */ 9628c2ecf20Sopenharmony_ci if ((hp->happy_flags & (HFLAG_POLLENABLE | HFLAG_POLL)) != 9638c2ecf20Sopenharmony_ci (HFLAG_POLLENABLE | HFLAG_POLL)) { 9648c2ecf20Sopenharmony_ci HMD(("not polling, return\n")); 9658c2ecf20Sopenharmony_ci return; 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci /* Shut up the MIF. */ 9698c2ecf20Sopenharmony_ci ASD(("were polling, mif ints off, ")); 9708c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_IMASK, 0xffff); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci /* Turn off polling. */ 9738c2ecf20Sopenharmony_ci ASD(("polling off, ")); 9748c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, 9758c2ecf20Sopenharmony_ci hme_read32(hp, tregs + TCVR_CFG) & ~(TCV_CFG_PENABLE)); 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci /* We are no longer polling. */ 9788c2ecf20Sopenharmony_ci hp->happy_flags &= ~(HFLAG_POLL); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci /* Let the bits set. */ 9818c2ecf20Sopenharmony_ci udelay(200); 9828c2ecf20Sopenharmony_ci ASD(("done\n")); 9838c2ecf20Sopenharmony_ci} 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci/* Only Sun can take such nice parts and fuck up the programming interface 9868c2ecf20Sopenharmony_ci * like this. Good job guys... 9878c2ecf20Sopenharmony_ci */ 9888c2ecf20Sopenharmony_ci#define TCVR_RESET_TRIES 16 /* It should reset quickly */ 9898c2ecf20Sopenharmony_ci#define TCVR_UNISOLATE_TRIES 32 /* Dis-isolation can take longer. */ 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci/* hp->happy_lock must be held */ 9928c2ecf20Sopenharmony_cistatic int happy_meal_tcvr_reset(struct happy_meal *hp, void __iomem *tregs) 9938c2ecf20Sopenharmony_ci{ 9948c2ecf20Sopenharmony_ci u32 tconfig; 9958c2ecf20Sopenharmony_ci int result, tries = TCVR_RESET_TRIES; 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci tconfig = hme_read32(hp, tregs + TCVR_CFG); 9988c2ecf20Sopenharmony_ci ASD(("happy_meal_tcvr_reset: tcfg<%08lx> ", tconfig)); 9998c2ecf20Sopenharmony_ci if (hp->tcvr_type == external) { 10008c2ecf20Sopenharmony_ci ASD(("external<")); 10018c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, tconfig & ~(TCV_CFG_PSELECT)); 10028c2ecf20Sopenharmony_ci hp->tcvr_type = internal; 10038c2ecf20Sopenharmony_ci hp->paddr = TCV_PADDR_ITX; 10048c2ecf20Sopenharmony_ci ASD(("ISOLATE,")); 10058c2ecf20Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_BMCR, 10068c2ecf20Sopenharmony_ci (BMCR_LOOPBACK|BMCR_PDOWN|BMCR_ISOLATE)); 10078c2ecf20Sopenharmony_ci result = happy_meal_tcvr_read(hp, tregs, MII_BMCR); 10088c2ecf20Sopenharmony_ci if (result == TCVR_FAILURE) { 10098c2ecf20Sopenharmony_ci ASD(("phyread_fail>\n")); 10108c2ecf20Sopenharmony_ci return -1; 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci ASD(("phyread_ok,PSELECT>")); 10138c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, tconfig | TCV_CFG_PSELECT); 10148c2ecf20Sopenharmony_ci hp->tcvr_type = external; 10158c2ecf20Sopenharmony_ci hp->paddr = TCV_PADDR_ETX; 10168c2ecf20Sopenharmony_ci } else { 10178c2ecf20Sopenharmony_ci if (tconfig & TCV_CFG_MDIO1) { 10188c2ecf20Sopenharmony_ci ASD(("internal<PSELECT,")); 10198c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, (tconfig | TCV_CFG_PSELECT)); 10208c2ecf20Sopenharmony_ci ASD(("ISOLATE,")); 10218c2ecf20Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_BMCR, 10228c2ecf20Sopenharmony_ci (BMCR_LOOPBACK|BMCR_PDOWN|BMCR_ISOLATE)); 10238c2ecf20Sopenharmony_ci result = happy_meal_tcvr_read(hp, tregs, MII_BMCR); 10248c2ecf20Sopenharmony_ci if (result == TCVR_FAILURE) { 10258c2ecf20Sopenharmony_ci ASD(("phyread_fail>\n")); 10268c2ecf20Sopenharmony_ci return -1; 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci ASD(("phyread_ok,~PSELECT>")); 10298c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, (tconfig & ~(TCV_CFG_PSELECT))); 10308c2ecf20Sopenharmony_ci hp->tcvr_type = internal; 10318c2ecf20Sopenharmony_ci hp->paddr = TCV_PADDR_ITX; 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci ASD(("BMCR_RESET ")); 10368c2ecf20Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_BMCR, BMCR_RESET); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci while (--tries) { 10398c2ecf20Sopenharmony_ci result = happy_meal_tcvr_read(hp, tregs, MII_BMCR); 10408c2ecf20Sopenharmony_ci if (result == TCVR_FAILURE) 10418c2ecf20Sopenharmony_ci return -1; 10428c2ecf20Sopenharmony_ci hp->sw_bmcr = result; 10438c2ecf20Sopenharmony_ci if (!(result & BMCR_RESET)) 10448c2ecf20Sopenharmony_ci break; 10458c2ecf20Sopenharmony_ci udelay(20); 10468c2ecf20Sopenharmony_ci } 10478c2ecf20Sopenharmony_ci if (!tries) { 10488c2ecf20Sopenharmony_ci ASD(("BMCR RESET FAILED!\n")); 10498c2ecf20Sopenharmony_ci return -1; 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci ASD(("RESET_OK\n")); 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci /* Get fresh copies of the PHY registers. */ 10548c2ecf20Sopenharmony_ci hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, MII_BMSR); 10558c2ecf20Sopenharmony_ci hp->sw_physid1 = happy_meal_tcvr_read(hp, tregs, MII_PHYSID1); 10568c2ecf20Sopenharmony_ci hp->sw_physid2 = happy_meal_tcvr_read(hp, tregs, MII_PHYSID2); 10578c2ecf20Sopenharmony_ci hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, MII_ADVERTISE); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci ASD(("UNISOLATE")); 10608c2ecf20Sopenharmony_ci hp->sw_bmcr &= ~(BMCR_ISOLATE); 10618c2ecf20Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr); 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci tries = TCVR_UNISOLATE_TRIES; 10648c2ecf20Sopenharmony_ci while (--tries) { 10658c2ecf20Sopenharmony_ci result = happy_meal_tcvr_read(hp, tregs, MII_BMCR); 10668c2ecf20Sopenharmony_ci if (result == TCVR_FAILURE) 10678c2ecf20Sopenharmony_ci return -1; 10688c2ecf20Sopenharmony_ci if (!(result & BMCR_ISOLATE)) 10698c2ecf20Sopenharmony_ci break; 10708c2ecf20Sopenharmony_ci udelay(20); 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci if (!tries) { 10738c2ecf20Sopenharmony_ci ASD((" FAILED!\n")); 10748c2ecf20Sopenharmony_ci return -1; 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci ASD((" SUCCESS and CSCONFIG_DFBYPASS\n")); 10778c2ecf20Sopenharmony_ci if (!is_lucent_phy(hp)) { 10788c2ecf20Sopenharmony_ci result = happy_meal_tcvr_read(hp, tregs, 10798c2ecf20Sopenharmony_ci DP83840_CSCONFIG); 10808c2ecf20Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, 10818c2ecf20Sopenharmony_ci DP83840_CSCONFIG, (result | CSCONFIG_DFBYPASS)); 10828c2ecf20Sopenharmony_ci } 10838c2ecf20Sopenharmony_ci return 0; 10848c2ecf20Sopenharmony_ci} 10858c2ecf20Sopenharmony_ci 10868c2ecf20Sopenharmony_ci/* Figure out whether we have an internal or external transceiver. 10878c2ecf20Sopenharmony_ci * 10888c2ecf20Sopenharmony_ci * hp->happy_lock must be held 10898c2ecf20Sopenharmony_ci */ 10908c2ecf20Sopenharmony_cistatic void happy_meal_transceiver_check(struct happy_meal *hp, void __iomem *tregs) 10918c2ecf20Sopenharmony_ci{ 10928c2ecf20Sopenharmony_ci unsigned long tconfig = hme_read32(hp, tregs + TCVR_CFG); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci ASD(("happy_meal_transceiver_check: tcfg=%08lx ", tconfig)); 10958c2ecf20Sopenharmony_ci if (hp->happy_flags & HFLAG_POLL) { 10968c2ecf20Sopenharmony_ci /* If we are polling, we must stop to get the transceiver type. */ 10978c2ecf20Sopenharmony_ci ASD(("<polling> ")); 10988c2ecf20Sopenharmony_ci if (hp->tcvr_type == internal) { 10998c2ecf20Sopenharmony_ci if (tconfig & TCV_CFG_MDIO1) { 11008c2ecf20Sopenharmony_ci ASD(("<internal> <poll stop> ")); 11018c2ecf20Sopenharmony_ci happy_meal_poll_stop(hp, tregs); 11028c2ecf20Sopenharmony_ci hp->paddr = TCV_PADDR_ETX; 11038c2ecf20Sopenharmony_ci hp->tcvr_type = external; 11048c2ecf20Sopenharmony_ci ASD(("<external>\n")); 11058c2ecf20Sopenharmony_ci tconfig &= ~(TCV_CFG_PENABLE); 11068c2ecf20Sopenharmony_ci tconfig |= TCV_CFG_PSELECT; 11078c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, tconfig); 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci } else { 11108c2ecf20Sopenharmony_ci if (hp->tcvr_type == external) { 11118c2ecf20Sopenharmony_ci ASD(("<external> ")); 11128c2ecf20Sopenharmony_ci if (!(hme_read32(hp, tregs + TCVR_STATUS) >> 16)) { 11138c2ecf20Sopenharmony_ci ASD(("<poll stop> ")); 11148c2ecf20Sopenharmony_ci happy_meal_poll_stop(hp, tregs); 11158c2ecf20Sopenharmony_ci hp->paddr = TCV_PADDR_ITX; 11168c2ecf20Sopenharmony_ci hp->tcvr_type = internal; 11178c2ecf20Sopenharmony_ci ASD(("<internal>\n")); 11188c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, 11198c2ecf20Sopenharmony_ci hme_read32(hp, tregs + TCVR_CFG) & 11208c2ecf20Sopenharmony_ci ~(TCV_CFG_PSELECT)); 11218c2ecf20Sopenharmony_ci } 11228c2ecf20Sopenharmony_ci ASD(("\n")); 11238c2ecf20Sopenharmony_ci } else { 11248c2ecf20Sopenharmony_ci ASD(("<none>\n")); 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci } else { 11288c2ecf20Sopenharmony_ci u32 reread = hme_read32(hp, tregs + TCVR_CFG); 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci /* Else we can just work off of the MDIO bits. */ 11318c2ecf20Sopenharmony_ci ASD(("<not polling> ")); 11328c2ecf20Sopenharmony_ci if (reread & TCV_CFG_MDIO1) { 11338c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, tconfig | TCV_CFG_PSELECT); 11348c2ecf20Sopenharmony_ci hp->paddr = TCV_PADDR_ETX; 11358c2ecf20Sopenharmony_ci hp->tcvr_type = external; 11368c2ecf20Sopenharmony_ci ASD(("<external>\n")); 11378c2ecf20Sopenharmony_ci } else { 11388c2ecf20Sopenharmony_ci if (reread & TCV_CFG_MDIO0) { 11398c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, 11408c2ecf20Sopenharmony_ci tconfig & ~(TCV_CFG_PSELECT)); 11418c2ecf20Sopenharmony_ci hp->paddr = TCV_PADDR_ITX; 11428c2ecf20Sopenharmony_ci hp->tcvr_type = internal; 11438c2ecf20Sopenharmony_ci ASD(("<internal>\n")); 11448c2ecf20Sopenharmony_ci } else { 11458c2ecf20Sopenharmony_ci printk(KERN_ERR "happy meal: Transceiver and a coke please."); 11468c2ecf20Sopenharmony_ci hp->tcvr_type = none; /* Grrr... */ 11478c2ecf20Sopenharmony_ci ASD(("<none>\n")); 11488c2ecf20Sopenharmony_ci } 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci } 11518c2ecf20Sopenharmony_ci} 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci/* The receive ring buffers are a bit tricky to get right. Here goes... 11548c2ecf20Sopenharmony_ci * 11558c2ecf20Sopenharmony_ci * The buffers we dma into must be 64 byte aligned. So we use a special 11568c2ecf20Sopenharmony_ci * alloc_skb() routine for the happy meal to allocate 64 bytes more than 11578c2ecf20Sopenharmony_ci * we really need. 11588c2ecf20Sopenharmony_ci * 11598c2ecf20Sopenharmony_ci * We use skb_reserve() to align the data block we get in the skb. We 11608c2ecf20Sopenharmony_ci * also program the etxregs->cfg register to use an offset of 2. This 11618c2ecf20Sopenharmony_ci * imperical constant plus the ethernet header size will always leave 11628c2ecf20Sopenharmony_ci * us with a nicely aligned ip header once we pass things up to the 11638c2ecf20Sopenharmony_ci * protocol layers. 11648c2ecf20Sopenharmony_ci * 11658c2ecf20Sopenharmony_ci * The numbers work out to: 11668c2ecf20Sopenharmony_ci * 11678c2ecf20Sopenharmony_ci * Max ethernet frame size 1518 11688c2ecf20Sopenharmony_ci * Ethernet header size 14 11698c2ecf20Sopenharmony_ci * Happy Meal base offset 2 11708c2ecf20Sopenharmony_ci * 11718c2ecf20Sopenharmony_ci * Say a skb data area is at 0xf001b010, and its size alloced is 11728c2ecf20Sopenharmony_ci * (ETH_FRAME_LEN + 64 + 2) = (1514 + 64 + 2) = 1580 bytes. 11738c2ecf20Sopenharmony_ci * 11748c2ecf20Sopenharmony_ci * First our alloc_skb() routine aligns the data base to a 64 byte 11758c2ecf20Sopenharmony_ci * boundary. We now have 0xf001b040 as our skb data address. We 11768c2ecf20Sopenharmony_ci * plug this into the receive descriptor address. 11778c2ecf20Sopenharmony_ci * 11788c2ecf20Sopenharmony_ci * Next, we skb_reserve() 2 bytes to account for the Happy Meal offset. 11798c2ecf20Sopenharmony_ci * So now the data we will end up looking at starts at 0xf001b042. When 11808c2ecf20Sopenharmony_ci * the packet arrives, we will check out the size received and subtract 11818c2ecf20Sopenharmony_ci * this from the skb->length. Then we just pass the packet up to the 11828c2ecf20Sopenharmony_ci * protocols as is, and allocate a new skb to replace this slot we have 11838c2ecf20Sopenharmony_ci * just received from. 11848c2ecf20Sopenharmony_ci * 11858c2ecf20Sopenharmony_ci * The ethernet layer will strip the ether header from the front of the 11868c2ecf20Sopenharmony_ci * skb we just sent to it, this leaves us with the ip header sitting 11878c2ecf20Sopenharmony_ci * nicely aligned at 0xf001b050. Also, for tcp and udp packets the 11888c2ecf20Sopenharmony_ci * Happy Meal has even checksummed the tcp/udp data for us. The 16 11898c2ecf20Sopenharmony_ci * bit checksum is obtained from the low bits of the receive descriptor 11908c2ecf20Sopenharmony_ci * flags, thus: 11918c2ecf20Sopenharmony_ci * 11928c2ecf20Sopenharmony_ci * skb->csum = rxd->rx_flags & 0xffff; 11938c2ecf20Sopenharmony_ci * skb->ip_summed = CHECKSUM_COMPLETE; 11948c2ecf20Sopenharmony_ci * 11958c2ecf20Sopenharmony_ci * before sending off the skb to the protocols, and we are good as gold. 11968c2ecf20Sopenharmony_ci */ 11978c2ecf20Sopenharmony_cistatic void happy_meal_clean_rings(struct happy_meal *hp) 11988c2ecf20Sopenharmony_ci{ 11998c2ecf20Sopenharmony_ci int i; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) { 12028c2ecf20Sopenharmony_ci if (hp->rx_skbs[i] != NULL) { 12038c2ecf20Sopenharmony_ci struct sk_buff *skb = hp->rx_skbs[i]; 12048c2ecf20Sopenharmony_ci struct happy_meal_rxd *rxd; 12058c2ecf20Sopenharmony_ci u32 dma_addr; 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci rxd = &hp->happy_block->happy_meal_rxd[i]; 12088c2ecf20Sopenharmony_ci dma_addr = hme_read_desc32(hp, &rxd->rx_addr); 12098c2ecf20Sopenharmony_ci dma_unmap_single(hp->dma_dev, dma_addr, 12108c2ecf20Sopenharmony_ci RX_BUF_ALLOC_SIZE, DMA_FROM_DEVICE); 12118c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 12128c2ecf20Sopenharmony_ci hp->rx_skbs[i] = NULL; 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci } 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci for (i = 0; i < TX_RING_SIZE; i++) { 12178c2ecf20Sopenharmony_ci if (hp->tx_skbs[i] != NULL) { 12188c2ecf20Sopenharmony_ci struct sk_buff *skb = hp->tx_skbs[i]; 12198c2ecf20Sopenharmony_ci struct happy_meal_txd *txd; 12208c2ecf20Sopenharmony_ci u32 dma_addr; 12218c2ecf20Sopenharmony_ci int frag; 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci hp->tx_skbs[i] = NULL; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) { 12268c2ecf20Sopenharmony_ci txd = &hp->happy_block->happy_meal_txd[i]; 12278c2ecf20Sopenharmony_ci dma_addr = hme_read_desc32(hp, &txd->tx_addr); 12288c2ecf20Sopenharmony_ci if (!frag) 12298c2ecf20Sopenharmony_ci dma_unmap_single(hp->dma_dev, dma_addr, 12308c2ecf20Sopenharmony_ci (hme_read_desc32(hp, &txd->tx_flags) 12318c2ecf20Sopenharmony_ci & TXFLAG_SIZE), 12328c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 12338c2ecf20Sopenharmony_ci else 12348c2ecf20Sopenharmony_ci dma_unmap_page(hp->dma_dev, dma_addr, 12358c2ecf20Sopenharmony_ci (hme_read_desc32(hp, &txd->tx_flags) 12368c2ecf20Sopenharmony_ci & TXFLAG_SIZE), 12378c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci if (frag != skb_shinfo(skb)->nr_frags) 12408c2ecf20Sopenharmony_ci i++; 12418c2ecf20Sopenharmony_ci } 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 12448c2ecf20Sopenharmony_ci } 12458c2ecf20Sopenharmony_ci } 12468c2ecf20Sopenharmony_ci} 12478c2ecf20Sopenharmony_ci 12488c2ecf20Sopenharmony_ci/* hp->happy_lock must be held */ 12498c2ecf20Sopenharmony_cistatic void happy_meal_init_rings(struct happy_meal *hp) 12508c2ecf20Sopenharmony_ci{ 12518c2ecf20Sopenharmony_ci struct hmeal_init_block *hb = hp->happy_block; 12528c2ecf20Sopenharmony_ci int i; 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci HMD(("happy_meal_init_rings: counters to zero, ")); 12558c2ecf20Sopenharmony_ci hp->rx_new = hp->rx_old = hp->tx_new = hp->tx_old = 0; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci /* Free any skippy bufs left around in the rings. */ 12588c2ecf20Sopenharmony_ci HMD(("clean, ")); 12598c2ecf20Sopenharmony_ci happy_meal_clean_rings(hp); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci /* Now get new skippy bufs for the receive ring. */ 12628c2ecf20Sopenharmony_ci HMD(("init rxring, ")); 12638c2ecf20Sopenharmony_ci for (i = 0; i < RX_RING_SIZE; i++) { 12648c2ecf20Sopenharmony_ci struct sk_buff *skb; 12658c2ecf20Sopenharmony_ci u32 mapping; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); 12688c2ecf20Sopenharmony_ci if (!skb) { 12698c2ecf20Sopenharmony_ci hme_write_rxd(hp, &hb->happy_meal_rxd[i], 0, 0); 12708c2ecf20Sopenharmony_ci continue; 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci hp->rx_skbs[i] = skb; 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci /* Because we reserve afterwards. */ 12758c2ecf20Sopenharmony_ci skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET + 4)); 12768c2ecf20Sopenharmony_ci mapping = dma_map_single(hp->dma_dev, skb->data, RX_BUF_ALLOC_SIZE, 12778c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 12788c2ecf20Sopenharmony_ci if (dma_mapping_error(hp->dma_dev, mapping)) { 12798c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 12808c2ecf20Sopenharmony_ci hme_write_rxd(hp, &hb->happy_meal_rxd[i], 0, 0); 12818c2ecf20Sopenharmony_ci continue; 12828c2ecf20Sopenharmony_ci } 12838c2ecf20Sopenharmony_ci hme_write_rxd(hp, &hb->happy_meal_rxd[i], 12848c2ecf20Sopenharmony_ci (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)), 12858c2ecf20Sopenharmony_ci mapping); 12868c2ecf20Sopenharmony_ci skb_reserve(skb, RX_OFFSET); 12878c2ecf20Sopenharmony_ci } 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci HMD(("init txring, ")); 12908c2ecf20Sopenharmony_ci for (i = 0; i < TX_RING_SIZE; i++) 12918c2ecf20Sopenharmony_ci hme_write_txd(hp, &hb->happy_meal_txd[i], 0, 0); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci HMD(("done\n")); 12948c2ecf20Sopenharmony_ci} 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci/* hp->happy_lock must be held */ 12978c2ecf20Sopenharmony_cistatic void 12988c2ecf20Sopenharmony_cihappy_meal_begin_auto_negotiation(struct happy_meal *hp, 12998c2ecf20Sopenharmony_ci void __iomem *tregs, 13008c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *ep) 13018c2ecf20Sopenharmony_ci{ 13028c2ecf20Sopenharmony_ci int timeout; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci /* Read all of the registers we are interested in now. */ 13058c2ecf20Sopenharmony_ci hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, MII_BMSR); 13068c2ecf20Sopenharmony_ci hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR); 13078c2ecf20Sopenharmony_ci hp->sw_physid1 = happy_meal_tcvr_read(hp, tregs, MII_PHYSID1); 13088c2ecf20Sopenharmony_ci hp->sw_physid2 = happy_meal_tcvr_read(hp, tregs, MII_PHYSID2); 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci /* XXX Check BMSR_ANEGCAPABLE, should not be necessary though. */ 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, MII_ADVERTISE); 13138c2ecf20Sopenharmony_ci if (!ep || ep->base.autoneg == AUTONEG_ENABLE) { 13148c2ecf20Sopenharmony_ci /* Advertise everything we can support. */ 13158c2ecf20Sopenharmony_ci if (hp->sw_bmsr & BMSR_10HALF) 13168c2ecf20Sopenharmony_ci hp->sw_advertise |= (ADVERTISE_10HALF); 13178c2ecf20Sopenharmony_ci else 13188c2ecf20Sopenharmony_ci hp->sw_advertise &= ~(ADVERTISE_10HALF); 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci if (hp->sw_bmsr & BMSR_10FULL) 13218c2ecf20Sopenharmony_ci hp->sw_advertise |= (ADVERTISE_10FULL); 13228c2ecf20Sopenharmony_ci else 13238c2ecf20Sopenharmony_ci hp->sw_advertise &= ~(ADVERTISE_10FULL); 13248c2ecf20Sopenharmony_ci if (hp->sw_bmsr & BMSR_100HALF) 13258c2ecf20Sopenharmony_ci hp->sw_advertise |= (ADVERTISE_100HALF); 13268c2ecf20Sopenharmony_ci else 13278c2ecf20Sopenharmony_ci hp->sw_advertise &= ~(ADVERTISE_100HALF); 13288c2ecf20Sopenharmony_ci if (hp->sw_bmsr & BMSR_100FULL) 13298c2ecf20Sopenharmony_ci hp->sw_advertise |= (ADVERTISE_100FULL); 13308c2ecf20Sopenharmony_ci else 13318c2ecf20Sopenharmony_ci hp->sw_advertise &= ~(ADVERTISE_100FULL); 13328c2ecf20Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_ADVERTISE, hp->sw_advertise); 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci /* XXX Currently no Happy Meal cards I know off support 100BaseT4, 13358c2ecf20Sopenharmony_ci * XXX and this is because the DP83840 does not support it, changes 13368c2ecf20Sopenharmony_ci * XXX would need to be made to the tx/rx logic in the driver as well 13378c2ecf20Sopenharmony_ci * XXX so I completely skip checking for it in the BMSR for now. 13388c2ecf20Sopenharmony_ci */ 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci#ifdef AUTO_SWITCH_DEBUG 13418c2ecf20Sopenharmony_ci ASD(("%s: Advertising [ ", hp->dev->name)); 13428c2ecf20Sopenharmony_ci if (hp->sw_advertise & ADVERTISE_10HALF) 13438c2ecf20Sopenharmony_ci ASD(("10H ")); 13448c2ecf20Sopenharmony_ci if (hp->sw_advertise & ADVERTISE_10FULL) 13458c2ecf20Sopenharmony_ci ASD(("10F ")); 13468c2ecf20Sopenharmony_ci if (hp->sw_advertise & ADVERTISE_100HALF) 13478c2ecf20Sopenharmony_ci ASD(("100H ")); 13488c2ecf20Sopenharmony_ci if (hp->sw_advertise & ADVERTISE_100FULL) 13498c2ecf20Sopenharmony_ci ASD(("100F ")); 13508c2ecf20Sopenharmony_ci#endif 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci /* Enable Auto-Negotiation, this is usually on already... */ 13538c2ecf20Sopenharmony_ci hp->sw_bmcr |= BMCR_ANENABLE; 13548c2ecf20Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr); 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci /* Restart it to make sure it is going. */ 13578c2ecf20Sopenharmony_ci hp->sw_bmcr |= BMCR_ANRESTART; 13588c2ecf20Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr); 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci /* BMCR_ANRESTART self clears when the process has begun. */ 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci timeout = 64; /* More than enough. */ 13638c2ecf20Sopenharmony_ci while (--timeout) { 13648c2ecf20Sopenharmony_ci hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR); 13658c2ecf20Sopenharmony_ci if (!(hp->sw_bmcr & BMCR_ANRESTART)) 13668c2ecf20Sopenharmony_ci break; /* got it. */ 13678c2ecf20Sopenharmony_ci udelay(10); 13688c2ecf20Sopenharmony_ci } 13698c2ecf20Sopenharmony_ci if (!timeout) { 13708c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Happy Meal would not start auto negotiation " 13718c2ecf20Sopenharmony_ci "BMCR=0x%04x\n", hp->dev->name, hp->sw_bmcr); 13728c2ecf20Sopenharmony_ci printk(KERN_NOTICE "%s: Performing force link detection.\n", 13738c2ecf20Sopenharmony_ci hp->dev->name); 13748c2ecf20Sopenharmony_ci goto force_link; 13758c2ecf20Sopenharmony_ci } else { 13768c2ecf20Sopenharmony_ci hp->timer_state = arbwait; 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci } else { 13798c2ecf20Sopenharmony_ciforce_link: 13808c2ecf20Sopenharmony_ci /* Force the link up, trying first a particular mode. 13818c2ecf20Sopenharmony_ci * Either we are here at the request of ethtool or 13828c2ecf20Sopenharmony_ci * because the Happy Meal would not start to autoneg. 13838c2ecf20Sopenharmony_ci */ 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci /* Disable auto-negotiation in BMCR, enable the duplex and 13868c2ecf20Sopenharmony_ci * speed setting, init the timer state machine, and fire it off. 13878c2ecf20Sopenharmony_ci */ 13888c2ecf20Sopenharmony_ci if (!ep || ep->base.autoneg == AUTONEG_ENABLE) { 13898c2ecf20Sopenharmony_ci hp->sw_bmcr = BMCR_SPEED100; 13908c2ecf20Sopenharmony_ci } else { 13918c2ecf20Sopenharmony_ci if (ep->base.speed == SPEED_100) 13928c2ecf20Sopenharmony_ci hp->sw_bmcr = BMCR_SPEED100; 13938c2ecf20Sopenharmony_ci else 13948c2ecf20Sopenharmony_ci hp->sw_bmcr = 0; 13958c2ecf20Sopenharmony_ci if (ep->base.duplex == DUPLEX_FULL) 13968c2ecf20Sopenharmony_ci hp->sw_bmcr |= BMCR_FULLDPLX; 13978c2ecf20Sopenharmony_ci } 13988c2ecf20Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr); 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci if (!is_lucent_phy(hp)) { 14018c2ecf20Sopenharmony_ci /* OK, seems we need do disable the transceiver for the first 14028c2ecf20Sopenharmony_ci * tick to make sure we get an accurate link state at the 14038c2ecf20Sopenharmony_ci * second tick. 14048c2ecf20Sopenharmony_ci */ 14058c2ecf20Sopenharmony_ci hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs, 14068c2ecf20Sopenharmony_ci DP83840_CSCONFIG); 14078c2ecf20Sopenharmony_ci hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB); 14088c2ecf20Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG, 14098c2ecf20Sopenharmony_ci hp->sw_csconfig); 14108c2ecf20Sopenharmony_ci } 14118c2ecf20Sopenharmony_ci hp->timer_state = ltrywait; 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci hp->timer_ticks = 0; 14158c2ecf20Sopenharmony_ci hp->happy_timer.expires = jiffies + (12 * HZ)/10; /* 1.2 sec. */ 14168c2ecf20Sopenharmony_ci add_timer(&hp->happy_timer); 14178c2ecf20Sopenharmony_ci} 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci/* hp->happy_lock must be held */ 14208c2ecf20Sopenharmony_cistatic int happy_meal_init(struct happy_meal *hp) 14218c2ecf20Sopenharmony_ci{ 14228c2ecf20Sopenharmony_ci void __iomem *gregs = hp->gregs; 14238c2ecf20Sopenharmony_ci void __iomem *etxregs = hp->etxregs; 14248c2ecf20Sopenharmony_ci void __iomem *erxregs = hp->erxregs; 14258c2ecf20Sopenharmony_ci void __iomem *bregs = hp->bigmacregs; 14268c2ecf20Sopenharmony_ci void __iomem *tregs = hp->tcvregs; 14278c2ecf20Sopenharmony_ci u32 regtmp, rxcfg; 14288c2ecf20Sopenharmony_ci unsigned char *e = &hp->dev->dev_addr[0]; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci /* If auto-negotiation timer is running, kill it. */ 14318c2ecf20Sopenharmony_ci del_timer(&hp->happy_timer); 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci HMD(("happy_meal_init: happy_flags[%08x] ", 14348c2ecf20Sopenharmony_ci hp->happy_flags)); 14358c2ecf20Sopenharmony_ci if (!(hp->happy_flags & HFLAG_INIT)) { 14368c2ecf20Sopenharmony_ci HMD(("set HFLAG_INIT, ")); 14378c2ecf20Sopenharmony_ci hp->happy_flags |= HFLAG_INIT; 14388c2ecf20Sopenharmony_ci happy_meal_get_counters(hp, bregs); 14398c2ecf20Sopenharmony_ci } 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci /* Stop polling. */ 14428c2ecf20Sopenharmony_ci HMD(("to happy_meal_poll_stop\n")); 14438c2ecf20Sopenharmony_ci happy_meal_poll_stop(hp, tregs); 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci /* Stop transmitter and receiver. */ 14468c2ecf20Sopenharmony_ci HMD(("happy_meal_init: to happy_meal_stop\n")); 14478c2ecf20Sopenharmony_ci happy_meal_stop(hp, gregs); 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci /* Alloc and reset the tx/rx descriptor chains. */ 14508c2ecf20Sopenharmony_ci HMD(("happy_meal_init: to happy_meal_init_rings\n")); 14518c2ecf20Sopenharmony_ci happy_meal_init_rings(hp); 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci /* Shut up the MIF. */ 14548c2ecf20Sopenharmony_ci HMD(("happy_meal_init: Disable all MIF irqs (old[%08x]), ", 14558c2ecf20Sopenharmony_ci hme_read32(hp, tregs + TCVR_IMASK))); 14568c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_IMASK, 0xffff); 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci /* See if we can enable the MIF frame on this card to speak to the DP83840. */ 14598c2ecf20Sopenharmony_ci if (hp->happy_flags & HFLAG_FENABLE) { 14608c2ecf20Sopenharmony_ci HMD(("use frame old[%08x], ", 14618c2ecf20Sopenharmony_ci hme_read32(hp, tregs + TCVR_CFG))); 14628c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, 14638c2ecf20Sopenharmony_ci hme_read32(hp, tregs + TCVR_CFG) & ~(TCV_CFG_BENABLE)); 14648c2ecf20Sopenharmony_ci } else { 14658c2ecf20Sopenharmony_ci HMD(("use bitbang old[%08x], ", 14668c2ecf20Sopenharmony_ci hme_read32(hp, tregs + TCVR_CFG))); 14678c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, 14688c2ecf20Sopenharmony_ci hme_read32(hp, tregs + TCVR_CFG) | TCV_CFG_BENABLE); 14698c2ecf20Sopenharmony_ci } 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci /* Check the state of the transceiver. */ 14728c2ecf20Sopenharmony_ci HMD(("to happy_meal_transceiver_check\n")); 14738c2ecf20Sopenharmony_ci happy_meal_transceiver_check(hp, tregs); 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci /* Put the Big Mac into a sane state. */ 14768c2ecf20Sopenharmony_ci HMD(("happy_meal_init: ")); 14778c2ecf20Sopenharmony_ci switch(hp->tcvr_type) { 14788c2ecf20Sopenharmony_ci case none: 14798c2ecf20Sopenharmony_ci /* Cannot operate if we don't know the transceiver type! */ 14808c2ecf20Sopenharmony_ci HMD(("AAIEEE no transceiver type, EAGAIN")); 14818c2ecf20Sopenharmony_ci return -EAGAIN; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci case internal: 14848c2ecf20Sopenharmony_ci /* Using the MII buffers. */ 14858c2ecf20Sopenharmony_ci HMD(("internal, using MII, ")); 14868c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_XIFCFG, 0); 14878c2ecf20Sopenharmony_ci break; 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci case external: 14908c2ecf20Sopenharmony_ci /* Not using the MII, disable it. */ 14918c2ecf20Sopenharmony_ci HMD(("external, disable MII, ")); 14928c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_XIFCFG, BIGMAC_XCFG_MIIDISAB); 14938c2ecf20Sopenharmony_ci break; 14948c2ecf20Sopenharmony_ci } 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci if (happy_meal_tcvr_reset(hp, tregs)) 14978c2ecf20Sopenharmony_ci return -EAGAIN; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci /* Reset the Happy Meal Big Mac transceiver and the receiver. */ 15008c2ecf20Sopenharmony_ci HMD(("tx/rx reset, ")); 15018c2ecf20Sopenharmony_ci happy_meal_tx_reset(hp, bregs); 15028c2ecf20Sopenharmony_ci happy_meal_rx_reset(hp, bregs); 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci /* Set jam size and inter-packet gaps to reasonable defaults. */ 15058c2ecf20Sopenharmony_ci HMD(("jsize/ipg1/ipg2, ")); 15068c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_JSIZE, DEFAULT_JAMSIZE); 15078c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_IGAP1, DEFAULT_IPG1); 15088c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_IGAP2, DEFAULT_IPG2); 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci /* Load up the MAC address and random seed. */ 15118c2ecf20Sopenharmony_ci HMD(("rseed/macaddr, ")); 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci /* The docs recommend to use the 10LSB of our MAC here. */ 15148c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_RSEED, ((e[5] | e[4]<<8)&0x3ff)); 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_MACADDR2, ((e[4] << 8) | e[5])); 15178c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_MACADDR1, ((e[2] << 8) | e[3])); 15188c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_MACADDR0, ((e[0] << 8) | e[1])); 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci HMD(("htable, ")); 15218c2ecf20Sopenharmony_ci if ((hp->dev->flags & IFF_ALLMULTI) || 15228c2ecf20Sopenharmony_ci (netdev_mc_count(hp->dev) > 64)) { 15238c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE0, 0xffff); 15248c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE1, 0xffff); 15258c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE2, 0xffff); 15268c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE3, 0xffff); 15278c2ecf20Sopenharmony_ci } else if ((hp->dev->flags & IFF_PROMISC) == 0) { 15288c2ecf20Sopenharmony_ci u16 hash_table[4]; 15298c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 15308c2ecf20Sopenharmony_ci u32 crc; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci memset(hash_table, 0, sizeof(hash_table)); 15338c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, hp->dev) { 15348c2ecf20Sopenharmony_ci crc = ether_crc_le(6, ha->addr); 15358c2ecf20Sopenharmony_ci crc >>= 26; 15368c2ecf20Sopenharmony_ci hash_table[crc >> 4] |= 1 << (crc & 0xf); 15378c2ecf20Sopenharmony_ci } 15388c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE0, hash_table[0]); 15398c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE1, hash_table[1]); 15408c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE2, hash_table[2]); 15418c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE3, hash_table[3]); 15428c2ecf20Sopenharmony_ci } else { 15438c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE3, 0); 15448c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE2, 0); 15458c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE1, 0); 15468c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE0, 0); 15478c2ecf20Sopenharmony_ci } 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci /* Set the RX and TX ring ptrs. */ 15508c2ecf20Sopenharmony_ci HMD(("ring ptrs rxr[%08x] txr[%08x]\n", 15518c2ecf20Sopenharmony_ci ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)), 15528c2ecf20Sopenharmony_ci ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_txd, 0)))); 15538c2ecf20Sopenharmony_ci hme_write32(hp, erxregs + ERX_RING, 15548c2ecf20Sopenharmony_ci ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0))); 15558c2ecf20Sopenharmony_ci hme_write32(hp, etxregs + ETX_RING, 15568c2ecf20Sopenharmony_ci ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_txd, 0))); 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci /* Parity issues in the ERX unit of some HME revisions can cause some 15598c2ecf20Sopenharmony_ci * registers to not be written unless their parity is even. Detect such 15608c2ecf20Sopenharmony_ci * lost writes and simply rewrite with a low bit set (which will be ignored 15618c2ecf20Sopenharmony_ci * since the rxring needs to be 2K aligned). 15628c2ecf20Sopenharmony_ci */ 15638c2ecf20Sopenharmony_ci if (hme_read32(hp, erxregs + ERX_RING) != 15648c2ecf20Sopenharmony_ci ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0))) 15658c2ecf20Sopenharmony_ci hme_write32(hp, erxregs + ERX_RING, 15668c2ecf20Sopenharmony_ci ((__u32)hp->hblock_dvma + hblock_offset(happy_meal_rxd, 0)) 15678c2ecf20Sopenharmony_ci | 0x4); 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci /* Set the supported burst sizes. */ 15708c2ecf20Sopenharmony_ci HMD(("happy_meal_init: old[%08x] bursts<", 15718c2ecf20Sopenharmony_ci hme_read32(hp, gregs + GREG_CFG))); 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci#ifndef CONFIG_SPARC 15748c2ecf20Sopenharmony_ci /* It is always PCI and can handle 64byte bursts. */ 15758c2ecf20Sopenharmony_ci hme_write32(hp, gregs + GREG_CFG, GREG_CFG_BURST64); 15768c2ecf20Sopenharmony_ci#else 15778c2ecf20Sopenharmony_ci if ((hp->happy_bursts & DMA_BURST64) && 15788c2ecf20Sopenharmony_ci ((hp->happy_flags & HFLAG_PCI) != 0 15798c2ecf20Sopenharmony_ci#ifdef CONFIG_SBUS 15808c2ecf20Sopenharmony_ci || sbus_can_burst64() 15818c2ecf20Sopenharmony_ci#endif 15828c2ecf20Sopenharmony_ci || 0)) { 15838c2ecf20Sopenharmony_ci u32 gcfg = GREG_CFG_BURST64; 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci /* I have no idea if I should set the extended 15868c2ecf20Sopenharmony_ci * transfer mode bit for Cheerio, so for now I 15878c2ecf20Sopenharmony_ci * do not. -DaveM 15888c2ecf20Sopenharmony_ci */ 15898c2ecf20Sopenharmony_ci#ifdef CONFIG_SBUS 15908c2ecf20Sopenharmony_ci if ((hp->happy_flags & HFLAG_PCI) == 0) { 15918c2ecf20Sopenharmony_ci struct platform_device *op = hp->happy_dev; 15928c2ecf20Sopenharmony_ci if (sbus_can_dma_64bit()) { 15938c2ecf20Sopenharmony_ci sbus_set_sbus64(&op->dev, 15948c2ecf20Sopenharmony_ci hp->happy_bursts); 15958c2ecf20Sopenharmony_ci gcfg |= GREG_CFG_64BIT; 15968c2ecf20Sopenharmony_ci } 15978c2ecf20Sopenharmony_ci } 15988c2ecf20Sopenharmony_ci#endif 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci HMD(("64>")); 16018c2ecf20Sopenharmony_ci hme_write32(hp, gregs + GREG_CFG, gcfg); 16028c2ecf20Sopenharmony_ci } else if (hp->happy_bursts & DMA_BURST32) { 16038c2ecf20Sopenharmony_ci HMD(("32>")); 16048c2ecf20Sopenharmony_ci hme_write32(hp, gregs + GREG_CFG, GREG_CFG_BURST32); 16058c2ecf20Sopenharmony_ci } else if (hp->happy_bursts & DMA_BURST16) { 16068c2ecf20Sopenharmony_ci HMD(("16>")); 16078c2ecf20Sopenharmony_ci hme_write32(hp, gregs + GREG_CFG, GREG_CFG_BURST16); 16088c2ecf20Sopenharmony_ci } else { 16098c2ecf20Sopenharmony_ci HMD(("XXX>")); 16108c2ecf20Sopenharmony_ci hme_write32(hp, gregs + GREG_CFG, 0); 16118c2ecf20Sopenharmony_ci } 16128c2ecf20Sopenharmony_ci#endif /* CONFIG_SPARC */ 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci /* Turn off interrupts we do not want to hear. */ 16158c2ecf20Sopenharmony_ci HMD((", enable global interrupts, ")); 16168c2ecf20Sopenharmony_ci hme_write32(hp, gregs + GREG_IMASK, 16178c2ecf20Sopenharmony_ci (GREG_IMASK_GOTFRAME | GREG_IMASK_RCNTEXP | 16188c2ecf20Sopenharmony_ci GREG_IMASK_SENTFRAME | GREG_IMASK_TXPERR)); 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci /* Set the transmit ring buffer size. */ 16218c2ecf20Sopenharmony_ci HMD(("tx rsize=%d oreg[%08x], ", (int)TX_RING_SIZE, 16228c2ecf20Sopenharmony_ci hme_read32(hp, etxregs + ETX_RSIZE))); 16238c2ecf20Sopenharmony_ci hme_write32(hp, etxregs + ETX_RSIZE, (TX_RING_SIZE >> ETX_RSIZE_SHIFT) - 1); 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci /* Enable transmitter DVMA. */ 16268c2ecf20Sopenharmony_ci HMD(("tx dma enable old[%08x], ", 16278c2ecf20Sopenharmony_ci hme_read32(hp, etxregs + ETX_CFG))); 16288c2ecf20Sopenharmony_ci hme_write32(hp, etxregs + ETX_CFG, 16298c2ecf20Sopenharmony_ci hme_read32(hp, etxregs + ETX_CFG) | ETX_CFG_DMAENABLE); 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci /* This chip really rots, for the receiver sometimes when you 16328c2ecf20Sopenharmony_ci * write to its control registers not all the bits get there 16338c2ecf20Sopenharmony_ci * properly. I cannot think of a sane way to provide complete 16348c2ecf20Sopenharmony_ci * coverage for this hardware bug yet. 16358c2ecf20Sopenharmony_ci */ 16368c2ecf20Sopenharmony_ci HMD(("erx regs bug old[%08x]\n", 16378c2ecf20Sopenharmony_ci hme_read32(hp, erxregs + ERX_CFG))); 16388c2ecf20Sopenharmony_ci hme_write32(hp, erxregs + ERX_CFG, ERX_CFG_DEFAULT(RX_OFFSET)); 16398c2ecf20Sopenharmony_ci regtmp = hme_read32(hp, erxregs + ERX_CFG); 16408c2ecf20Sopenharmony_ci hme_write32(hp, erxregs + ERX_CFG, ERX_CFG_DEFAULT(RX_OFFSET)); 16418c2ecf20Sopenharmony_ci if (hme_read32(hp, erxregs + ERX_CFG) != ERX_CFG_DEFAULT(RX_OFFSET)) { 16428c2ecf20Sopenharmony_ci printk(KERN_ERR "happy meal: Eieee, rx config register gets greasy fries.\n"); 16438c2ecf20Sopenharmony_ci printk(KERN_ERR "happy meal: Trying to set %08x, reread gives %08x\n", 16448c2ecf20Sopenharmony_ci ERX_CFG_DEFAULT(RX_OFFSET), regtmp); 16458c2ecf20Sopenharmony_ci /* XXX Should return failure here... */ 16468c2ecf20Sopenharmony_ci } 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci /* Enable Big Mac hash table filter. */ 16498c2ecf20Sopenharmony_ci HMD(("happy_meal_init: enable hash rx_cfg_old[%08x], ", 16508c2ecf20Sopenharmony_ci hme_read32(hp, bregs + BMAC_RXCFG))); 16518c2ecf20Sopenharmony_ci rxcfg = BIGMAC_RXCFG_HENABLE | BIGMAC_RXCFG_REJME; 16528c2ecf20Sopenharmony_ci if (hp->dev->flags & IFF_PROMISC) 16538c2ecf20Sopenharmony_ci rxcfg |= BIGMAC_RXCFG_PMISC; 16548c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_RXCFG, rxcfg); 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci /* Let the bits settle in the chip. */ 16578c2ecf20Sopenharmony_ci udelay(10); 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_ci /* Ok, configure the Big Mac transmitter. */ 16608c2ecf20Sopenharmony_ci HMD(("BIGMAC init, ")); 16618c2ecf20Sopenharmony_ci regtmp = 0; 16628c2ecf20Sopenharmony_ci if (hp->happy_flags & HFLAG_FULL) 16638c2ecf20Sopenharmony_ci regtmp |= BIGMAC_TXCFG_FULLDPLX; 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci /* Don't turn on the "don't give up" bit for now. It could cause hme 16668c2ecf20Sopenharmony_ci * to deadlock with the PHY if a Jabber occurs. 16678c2ecf20Sopenharmony_ci */ 16688c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_TXCFG, regtmp /*| BIGMAC_TXCFG_DGIVEUP*/); 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci /* Give up after 16 TX attempts. */ 16718c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_ALIMIT, 16); 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci /* Enable the output drivers no matter what. */ 16748c2ecf20Sopenharmony_ci regtmp = BIGMAC_XCFG_ODENABLE; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci /* If card can do lance mode, enable it. */ 16778c2ecf20Sopenharmony_ci if (hp->happy_flags & HFLAG_LANCE) 16788c2ecf20Sopenharmony_ci regtmp |= (DEFAULT_IPG0 << 5) | BIGMAC_XCFG_LANCE; 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci /* Disable the MII buffers if using external transceiver. */ 16818c2ecf20Sopenharmony_ci if (hp->tcvr_type == external) 16828c2ecf20Sopenharmony_ci regtmp |= BIGMAC_XCFG_MIIDISAB; 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci HMD(("XIF config old[%08x], ", 16858c2ecf20Sopenharmony_ci hme_read32(hp, bregs + BMAC_XIFCFG))); 16868c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_XIFCFG, regtmp); 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci /* Start things up. */ 16898c2ecf20Sopenharmony_ci HMD(("tx old[%08x] and rx [%08x] ON!\n", 16908c2ecf20Sopenharmony_ci hme_read32(hp, bregs + BMAC_TXCFG), 16918c2ecf20Sopenharmony_ci hme_read32(hp, bregs + BMAC_RXCFG))); 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci /* Set larger TX/RX size to allow for 802.1q */ 16948c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_TXMAX, ETH_FRAME_LEN + 8); 16958c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_RXMAX, ETH_FRAME_LEN + 8); 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_TXCFG, 16988c2ecf20Sopenharmony_ci hme_read32(hp, bregs + BMAC_TXCFG) | BIGMAC_TXCFG_ENABLE); 16998c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_RXCFG, 17008c2ecf20Sopenharmony_ci hme_read32(hp, bregs + BMAC_RXCFG) | BIGMAC_RXCFG_ENABLE); 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci /* Get the autonegotiation started, and the watch timer ticking. */ 17038c2ecf20Sopenharmony_ci happy_meal_begin_auto_negotiation(hp, tregs, NULL); 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci /* Success. */ 17068c2ecf20Sopenharmony_ci return 0; 17078c2ecf20Sopenharmony_ci} 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci/* hp->happy_lock must be held */ 17108c2ecf20Sopenharmony_cistatic void happy_meal_set_initial_advertisement(struct happy_meal *hp) 17118c2ecf20Sopenharmony_ci{ 17128c2ecf20Sopenharmony_ci void __iomem *tregs = hp->tcvregs; 17138c2ecf20Sopenharmony_ci void __iomem *bregs = hp->bigmacregs; 17148c2ecf20Sopenharmony_ci void __iomem *gregs = hp->gregs; 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci happy_meal_stop(hp, gregs); 17178c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_IMASK, 0xffff); 17188c2ecf20Sopenharmony_ci if (hp->happy_flags & HFLAG_FENABLE) 17198c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, 17208c2ecf20Sopenharmony_ci hme_read32(hp, tregs + TCVR_CFG) & ~(TCV_CFG_BENABLE)); 17218c2ecf20Sopenharmony_ci else 17228c2ecf20Sopenharmony_ci hme_write32(hp, tregs + TCVR_CFG, 17238c2ecf20Sopenharmony_ci hme_read32(hp, tregs + TCVR_CFG) | TCV_CFG_BENABLE); 17248c2ecf20Sopenharmony_ci happy_meal_transceiver_check(hp, tregs); 17258c2ecf20Sopenharmony_ci switch(hp->tcvr_type) { 17268c2ecf20Sopenharmony_ci case none: 17278c2ecf20Sopenharmony_ci return; 17288c2ecf20Sopenharmony_ci case internal: 17298c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_XIFCFG, 0); 17308c2ecf20Sopenharmony_ci break; 17318c2ecf20Sopenharmony_ci case external: 17328c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_XIFCFG, BIGMAC_XCFG_MIIDISAB); 17338c2ecf20Sopenharmony_ci break; 17348c2ecf20Sopenharmony_ci } 17358c2ecf20Sopenharmony_ci if (happy_meal_tcvr_reset(hp, tregs)) 17368c2ecf20Sopenharmony_ci return; 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci /* Latch PHY registers as of now. */ 17398c2ecf20Sopenharmony_ci hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, MII_BMSR); 17408c2ecf20Sopenharmony_ci hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, MII_ADVERTISE); 17418c2ecf20Sopenharmony_ci 17428c2ecf20Sopenharmony_ci /* Advertise everything we can support. */ 17438c2ecf20Sopenharmony_ci if (hp->sw_bmsr & BMSR_10HALF) 17448c2ecf20Sopenharmony_ci hp->sw_advertise |= (ADVERTISE_10HALF); 17458c2ecf20Sopenharmony_ci else 17468c2ecf20Sopenharmony_ci hp->sw_advertise &= ~(ADVERTISE_10HALF); 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci if (hp->sw_bmsr & BMSR_10FULL) 17498c2ecf20Sopenharmony_ci hp->sw_advertise |= (ADVERTISE_10FULL); 17508c2ecf20Sopenharmony_ci else 17518c2ecf20Sopenharmony_ci hp->sw_advertise &= ~(ADVERTISE_10FULL); 17528c2ecf20Sopenharmony_ci if (hp->sw_bmsr & BMSR_100HALF) 17538c2ecf20Sopenharmony_ci hp->sw_advertise |= (ADVERTISE_100HALF); 17548c2ecf20Sopenharmony_ci else 17558c2ecf20Sopenharmony_ci hp->sw_advertise &= ~(ADVERTISE_100HALF); 17568c2ecf20Sopenharmony_ci if (hp->sw_bmsr & BMSR_100FULL) 17578c2ecf20Sopenharmony_ci hp->sw_advertise |= (ADVERTISE_100FULL); 17588c2ecf20Sopenharmony_ci else 17598c2ecf20Sopenharmony_ci hp->sw_advertise &= ~(ADVERTISE_100FULL); 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci /* Update the PHY advertisement register. */ 17628c2ecf20Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_ADVERTISE, hp->sw_advertise); 17638c2ecf20Sopenharmony_ci} 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci/* Once status is latched (by happy_meal_interrupt) it is cleared by 17668c2ecf20Sopenharmony_ci * the hardware, so we cannot re-read it and get a correct value. 17678c2ecf20Sopenharmony_ci * 17688c2ecf20Sopenharmony_ci * hp->happy_lock must be held 17698c2ecf20Sopenharmony_ci */ 17708c2ecf20Sopenharmony_cistatic int happy_meal_is_not_so_happy(struct happy_meal *hp, u32 status) 17718c2ecf20Sopenharmony_ci{ 17728c2ecf20Sopenharmony_ci int reset = 0; 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci /* Only print messages for non-counter related interrupts. */ 17758c2ecf20Sopenharmony_ci if (status & (GREG_STAT_STSTERR | GREG_STAT_TFIFO_UND | 17768c2ecf20Sopenharmony_ci GREG_STAT_MAXPKTERR | GREG_STAT_RXERR | 17778c2ecf20Sopenharmony_ci GREG_STAT_RXPERR | GREG_STAT_RXTERR | GREG_STAT_EOPERR | 17788c2ecf20Sopenharmony_ci GREG_STAT_MIFIRQ | GREG_STAT_TXEACK | GREG_STAT_TXLERR | 17798c2ecf20Sopenharmony_ci GREG_STAT_TXPERR | GREG_STAT_TXTERR | GREG_STAT_SLVERR | 17808c2ecf20Sopenharmony_ci GREG_STAT_SLVPERR)) 17818c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Error interrupt for happy meal, status = %08x\n", 17828c2ecf20Sopenharmony_ci hp->dev->name, status); 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci if (status & GREG_STAT_RFIFOVF) { 17858c2ecf20Sopenharmony_ci /* Receive FIFO overflow is harmless and the hardware will take 17868c2ecf20Sopenharmony_ci care of it, just some packets are lost. Who cares. */ 17878c2ecf20Sopenharmony_ci printk(KERN_DEBUG "%s: Happy Meal receive FIFO overflow.\n", hp->dev->name); 17888c2ecf20Sopenharmony_ci } 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci if (status & GREG_STAT_STSTERR) { 17918c2ecf20Sopenharmony_ci /* BigMAC SQE link test failed. */ 17928c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Happy Meal BigMAC SQE test failed.\n", hp->dev->name); 17938c2ecf20Sopenharmony_ci reset = 1; 17948c2ecf20Sopenharmony_ci } 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci if (status & GREG_STAT_TFIFO_UND) { 17978c2ecf20Sopenharmony_ci /* Transmit FIFO underrun, again DMA error likely. */ 17988c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Happy Meal transmitter FIFO underrun, DMA error.\n", 17998c2ecf20Sopenharmony_ci hp->dev->name); 18008c2ecf20Sopenharmony_ci reset = 1; 18018c2ecf20Sopenharmony_ci } 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci if (status & GREG_STAT_MAXPKTERR) { 18048c2ecf20Sopenharmony_ci /* Driver error, tried to transmit something larger 18058c2ecf20Sopenharmony_ci * than ethernet max mtu. 18068c2ecf20Sopenharmony_ci */ 18078c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Happy Meal MAX Packet size error.\n", hp->dev->name); 18088c2ecf20Sopenharmony_ci reset = 1; 18098c2ecf20Sopenharmony_ci } 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci if (status & GREG_STAT_NORXD) { 18128c2ecf20Sopenharmony_ci /* This is harmless, it just means the system is 18138c2ecf20Sopenharmony_ci * quite loaded and the incoming packet rate was 18148c2ecf20Sopenharmony_ci * faster than the interrupt handler could keep up 18158c2ecf20Sopenharmony_ci * with. 18168c2ecf20Sopenharmony_ci */ 18178c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Happy Meal out of receive " 18188c2ecf20Sopenharmony_ci "descriptors, packet dropped.\n", 18198c2ecf20Sopenharmony_ci hp->dev->name); 18208c2ecf20Sopenharmony_ci } 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci if (status & (GREG_STAT_RXERR|GREG_STAT_RXPERR|GREG_STAT_RXTERR)) { 18238c2ecf20Sopenharmony_ci /* All sorts of DMA receive errors. */ 18248c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Happy Meal rx DMA errors [ ", hp->dev->name); 18258c2ecf20Sopenharmony_ci if (status & GREG_STAT_RXERR) 18268c2ecf20Sopenharmony_ci printk("GenericError "); 18278c2ecf20Sopenharmony_ci if (status & GREG_STAT_RXPERR) 18288c2ecf20Sopenharmony_ci printk("ParityError "); 18298c2ecf20Sopenharmony_ci if (status & GREG_STAT_RXTERR) 18308c2ecf20Sopenharmony_ci printk("RxTagBotch "); 18318c2ecf20Sopenharmony_ci printk("]\n"); 18328c2ecf20Sopenharmony_ci reset = 1; 18338c2ecf20Sopenharmony_ci } 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci if (status & GREG_STAT_EOPERR) { 18368c2ecf20Sopenharmony_ci /* Driver bug, didn't set EOP bit in tx descriptor given 18378c2ecf20Sopenharmony_ci * to the happy meal. 18388c2ecf20Sopenharmony_ci */ 18398c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: EOP not set in happy meal transmit descriptor!\n", 18408c2ecf20Sopenharmony_ci hp->dev->name); 18418c2ecf20Sopenharmony_ci reset = 1; 18428c2ecf20Sopenharmony_ci } 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci if (status & GREG_STAT_MIFIRQ) { 18458c2ecf20Sopenharmony_ci /* MIF signalled an interrupt, were we polling it? */ 18468c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Happy Meal MIF interrupt.\n", hp->dev->name); 18478c2ecf20Sopenharmony_ci } 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci if (status & 18508c2ecf20Sopenharmony_ci (GREG_STAT_TXEACK|GREG_STAT_TXLERR|GREG_STAT_TXPERR|GREG_STAT_TXTERR)) { 18518c2ecf20Sopenharmony_ci /* All sorts of transmit DMA errors. */ 18528c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Happy Meal tx DMA errors [ ", hp->dev->name); 18538c2ecf20Sopenharmony_ci if (status & GREG_STAT_TXEACK) 18548c2ecf20Sopenharmony_ci printk("GenericError "); 18558c2ecf20Sopenharmony_ci if (status & GREG_STAT_TXLERR) 18568c2ecf20Sopenharmony_ci printk("LateError "); 18578c2ecf20Sopenharmony_ci if (status & GREG_STAT_TXPERR) 18588c2ecf20Sopenharmony_ci printk("ParityError "); 18598c2ecf20Sopenharmony_ci if (status & GREG_STAT_TXTERR) 18608c2ecf20Sopenharmony_ci printk("TagBotch "); 18618c2ecf20Sopenharmony_ci printk("]\n"); 18628c2ecf20Sopenharmony_ci reset = 1; 18638c2ecf20Sopenharmony_ci } 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci if (status & (GREG_STAT_SLVERR|GREG_STAT_SLVPERR)) { 18668c2ecf20Sopenharmony_ci /* Bus or parity error when cpu accessed happy meal registers 18678c2ecf20Sopenharmony_ci * or it's internal FIFO's. Should never see this. 18688c2ecf20Sopenharmony_ci */ 18698c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: Happy Meal register access SBUS slave (%s) error.\n", 18708c2ecf20Sopenharmony_ci hp->dev->name, 18718c2ecf20Sopenharmony_ci (status & GREG_STAT_SLVPERR) ? "parity" : "generic"); 18728c2ecf20Sopenharmony_ci reset = 1; 18738c2ecf20Sopenharmony_ci } 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci if (reset) { 18768c2ecf20Sopenharmony_ci printk(KERN_NOTICE "%s: Resetting...\n", hp->dev->name); 18778c2ecf20Sopenharmony_ci happy_meal_init(hp); 18788c2ecf20Sopenharmony_ci return 1; 18798c2ecf20Sopenharmony_ci } 18808c2ecf20Sopenharmony_ci return 0; 18818c2ecf20Sopenharmony_ci} 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci/* hp->happy_lock must be held */ 18848c2ecf20Sopenharmony_cistatic void happy_meal_mif_interrupt(struct happy_meal *hp) 18858c2ecf20Sopenharmony_ci{ 18868c2ecf20Sopenharmony_ci void __iomem *tregs = hp->tcvregs; 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Link status change.\n", hp->dev->name); 18898c2ecf20Sopenharmony_ci hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR); 18908c2ecf20Sopenharmony_ci hp->sw_lpa = happy_meal_tcvr_read(hp, tregs, MII_LPA); 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci /* Use the fastest transmission protocol possible. */ 18938c2ecf20Sopenharmony_ci if (hp->sw_lpa & LPA_100FULL) { 18948c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Switching to 100Mbps at full duplex.", hp->dev->name); 18958c2ecf20Sopenharmony_ci hp->sw_bmcr |= (BMCR_FULLDPLX | BMCR_SPEED100); 18968c2ecf20Sopenharmony_ci } else if (hp->sw_lpa & LPA_100HALF) { 18978c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Switching to 100MBps at half duplex.", hp->dev->name); 18988c2ecf20Sopenharmony_ci hp->sw_bmcr |= BMCR_SPEED100; 18998c2ecf20Sopenharmony_ci } else if (hp->sw_lpa & LPA_10FULL) { 19008c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Switching to 10MBps at full duplex.", hp->dev->name); 19018c2ecf20Sopenharmony_ci hp->sw_bmcr |= BMCR_FULLDPLX; 19028c2ecf20Sopenharmony_ci } else { 19038c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Using 10Mbps at half duplex.", hp->dev->name); 19048c2ecf20Sopenharmony_ci } 19058c2ecf20Sopenharmony_ci happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr); 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci /* Finally stop polling and shut up the MIF. */ 19088c2ecf20Sopenharmony_ci happy_meal_poll_stop(hp, tregs); 19098c2ecf20Sopenharmony_ci} 19108c2ecf20Sopenharmony_ci 19118c2ecf20Sopenharmony_ci#ifdef TXDEBUG 19128c2ecf20Sopenharmony_ci#define TXD(x) printk x 19138c2ecf20Sopenharmony_ci#else 19148c2ecf20Sopenharmony_ci#define TXD(x) 19158c2ecf20Sopenharmony_ci#endif 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci/* hp->happy_lock must be held */ 19188c2ecf20Sopenharmony_cistatic void happy_meal_tx(struct happy_meal *hp) 19198c2ecf20Sopenharmony_ci{ 19208c2ecf20Sopenharmony_ci struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0]; 19218c2ecf20Sopenharmony_ci struct happy_meal_txd *this; 19228c2ecf20Sopenharmony_ci struct net_device *dev = hp->dev; 19238c2ecf20Sopenharmony_ci int elem; 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci elem = hp->tx_old; 19268c2ecf20Sopenharmony_ci TXD(("TX<")); 19278c2ecf20Sopenharmony_ci while (elem != hp->tx_new) { 19288c2ecf20Sopenharmony_ci struct sk_buff *skb; 19298c2ecf20Sopenharmony_ci u32 flags, dma_addr, dma_len; 19308c2ecf20Sopenharmony_ci int frag; 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci TXD(("[%d]", elem)); 19338c2ecf20Sopenharmony_ci this = &txbase[elem]; 19348c2ecf20Sopenharmony_ci flags = hme_read_desc32(hp, &this->tx_flags); 19358c2ecf20Sopenharmony_ci if (flags & TXFLAG_OWN) 19368c2ecf20Sopenharmony_ci break; 19378c2ecf20Sopenharmony_ci skb = hp->tx_skbs[elem]; 19388c2ecf20Sopenharmony_ci if (skb_shinfo(skb)->nr_frags) { 19398c2ecf20Sopenharmony_ci int last; 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci last = elem + skb_shinfo(skb)->nr_frags; 19428c2ecf20Sopenharmony_ci last &= (TX_RING_SIZE - 1); 19438c2ecf20Sopenharmony_ci flags = hme_read_desc32(hp, &txbase[last].tx_flags); 19448c2ecf20Sopenharmony_ci if (flags & TXFLAG_OWN) 19458c2ecf20Sopenharmony_ci break; 19468c2ecf20Sopenharmony_ci } 19478c2ecf20Sopenharmony_ci hp->tx_skbs[elem] = NULL; 19488c2ecf20Sopenharmony_ci dev->stats.tx_bytes += skb->len; 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_ci for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) { 19518c2ecf20Sopenharmony_ci dma_addr = hme_read_desc32(hp, &this->tx_addr); 19528c2ecf20Sopenharmony_ci dma_len = hme_read_desc32(hp, &this->tx_flags); 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci dma_len &= TXFLAG_SIZE; 19558c2ecf20Sopenharmony_ci if (!frag) 19568c2ecf20Sopenharmony_ci dma_unmap_single(hp->dma_dev, dma_addr, dma_len, DMA_TO_DEVICE); 19578c2ecf20Sopenharmony_ci else 19588c2ecf20Sopenharmony_ci dma_unmap_page(hp->dma_dev, dma_addr, dma_len, DMA_TO_DEVICE); 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci elem = NEXT_TX(elem); 19618c2ecf20Sopenharmony_ci this = &txbase[elem]; 19628c2ecf20Sopenharmony_ci } 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_ci dev_consume_skb_irq(skb); 19658c2ecf20Sopenharmony_ci dev->stats.tx_packets++; 19668c2ecf20Sopenharmony_ci } 19678c2ecf20Sopenharmony_ci hp->tx_old = elem; 19688c2ecf20Sopenharmony_ci TXD((">")); 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci if (netif_queue_stopped(dev) && 19718c2ecf20Sopenharmony_ci TX_BUFFS_AVAIL(hp) > (MAX_SKB_FRAGS + 1)) 19728c2ecf20Sopenharmony_ci netif_wake_queue(dev); 19738c2ecf20Sopenharmony_ci} 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci#ifdef RXDEBUG 19768c2ecf20Sopenharmony_ci#define RXD(x) printk x 19778c2ecf20Sopenharmony_ci#else 19788c2ecf20Sopenharmony_ci#define RXD(x) 19798c2ecf20Sopenharmony_ci#endif 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci/* Originally I used to handle the allocation failure by just giving back just 19828c2ecf20Sopenharmony_ci * that one ring buffer to the happy meal. Problem is that usually when that 19838c2ecf20Sopenharmony_ci * condition is triggered, the happy meal expects you to do something reasonable 19848c2ecf20Sopenharmony_ci * with all of the packets it has DMA'd in. So now I just drop the entire 19858c2ecf20Sopenharmony_ci * ring when we cannot get a new skb and give them all back to the happy meal, 19868c2ecf20Sopenharmony_ci * maybe things will be "happier" now. 19878c2ecf20Sopenharmony_ci * 19888c2ecf20Sopenharmony_ci * hp->happy_lock must be held 19898c2ecf20Sopenharmony_ci */ 19908c2ecf20Sopenharmony_cistatic void happy_meal_rx(struct happy_meal *hp, struct net_device *dev) 19918c2ecf20Sopenharmony_ci{ 19928c2ecf20Sopenharmony_ci struct happy_meal_rxd *rxbase = &hp->happy_block->happy_meal_rxd[0]; 19938c2ecf20Sopenharmony_ci struct happy_meal_rxd *this; 19948c2ecf20Sopenharmony_ci int elem = hp->rx_new, drops = 0; 19958c2ecf20Sopenharmony_ci u32 flags; 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci RXD(("RX<")); 19988c2ecf20Sopenharmony_ci this = &rxbase[elem]; 19998c2ecf20Sopenharmony_ci while (!((flags = hme_read_desc32(hp, &this->rx_flags)) & RXFLAG_OWN)) { 20008c2ecf20Sopenharmony_ci struct sk_buff *skb; 20018c2ecf20Sopenharmony_ci int len = flags >> 16; 20028c2ecf20Sopenharmony_ci u16 csum = flags & RXFLAG_CSUM; 20038c2ecf20Sopenharmony_ci u32 dma_addr = hme_read_desc32(hp, &this->rx_addr); 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci RXD(("[%d ", elem)); 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci /* Check for errors. */ 20088c2ecf20Sopenharmony_ci if ((len < ETH_ZLEN) || (flags & RXFLAG_OVERFLOW)) { 20098c2ecf20Sopenharmony_ci RXD(("ERR(%08x)]", flags)); 20108c2ecf20Sopenharmony_ci dev->stats.rx_errors++; 20118c2ecf20Sopenharmony_ci if (len < ETH_ZLEN) 20128c2ecf20Sopenharmony_ci dev->stats.rx_length_errors++; 20138c2ecf20Sopenharmony_ci if (len & (RXFLAG_OVERFLOW >> 16)) { 20148c2ecf20Sopenharmony_ci dev->stats.rx_over_errors++; 20158c2ecf20Sopenharmony_ci dev->stats.rx_fifo_errors++; 20168c2ecf20Sopenharmony_ci } 20178c2ecf20Sopenharmony_ci 20188c2ecf20Sopenharmony_ci /* Return it to the Happy meal. */ 20198c2ecf20Sopenharmony_ci drop_it: 20208c2ecf20Sopenharmony_ci dev->stats.rx_dropped++; 20218c2ecf20Sopenharmony_ci hme_write_rxd(hp, this, 20228c2ecf20Sopenharmony_ci (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)), 20238c2ecf20Sopenharmony_ci dma_addr); 20248c2ecf20Sopenharmony_ci goto next; 20258c2ecf20Sopenharmony_ci } 20268c2ecf20Sopenharmony_ci skb = hp->rx_skbs[elem]; 20278c2ecf20Sopenharmony_ci if (len > RX_COPY_THRESHOLD) { 20288c2ecf20Sopenharmony_ci struct sk_buff *new_skb; 20298c2ecf20Sopenharmony_ci u32 mapping; 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci /* Now refill the entry, if we can. */ 20328c2ecf20Sopenharmony_ci new_skb = happy_meal_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); 20338c2ecf20Sopenharmony_ci if (new_skb == NULL) { 20348c2ecf20Sopenharmony_ci drops++; 20358c2ecf20Sopenharmony_ci goto drop_it; 20368c2ecf20Sopenharmony_ci } 20378c2ecf20Sopenharmony_ci skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET + 4)); 20388c2ecf20Sopenharmony_ci mapping = dma_map_single(hp->dma_dev, new_skb->data, 20398c2ecf20Sopenharmony_ci RX_BUF_ALLOC_SIZE, 20408c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 20418c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(hp->dma_dev, mapping))) { 20428c2ecf20Sopenharmony_ci dev_kfree_skb_any(new_skb); 20438c2ecf20Sopenharmony_ci drops++; 20448c2ecf20Sopenharmony_ci goto drop_it; 20458c2ecf20Sopenharmony_ci } 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci dma_unmap_single(hp->dma_dev, dma_addr, RX_BUF_ALLOC_SIZE, DMA_FROM_DEVICE); 20488c2ecf20Sopenharmony_ci hp->rx_skbs[elem] = new_skb; 20498c2ecf20Sopenharmony_ci hme_write_rxd(hp, this, 20508c2ecf20Sopenharmony_ci (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)), 20518c2ecf20Sopenharmony_ci mapping); 20528c2ecf20Sopenharmony_ci skb_reserve(new_skb, RX_OFFSET); 20538c2ecf20Sopenharmony_ci 20548c2ecf20Sopenharmony_ci /* Trim the original skb for the netif. */ 20558c2ecf20Sopenharmony_ci skb_trim(skb, len); 20568c2ecf20Sopenharmony_ci } else { 20578c2ecf20Sopenharmony_ci struct sk_buff *copy_skb = netdev_alloc_skb(dev, len + 2); 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci if (copy_skb == NULL) { 20608c2ecf20Sopenharmony_ci drops++; 20618c2ecf20Sopenharmony_ci goto drop_it; 20628c2ecf20Sopenharmony_ci } 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci skb_reserve(copy_skb, 2); 20658c2ecf20Sopenharmony_ci skb_put(copy_skb, len); 20668c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(hp->dma_dev, dma_addr, len + 2, DMA_FROM_DEVICE); 20678c2ecf20Sopenharmony_ci skb_copy_from_linear_data(skb, copy_skb->data, len); 20688c2ecf20Sopenharmony_ci dma_sync_single_for_device(hp->dma_dev, dma_addr, len + 2, DMA_FROM_DEVICE); 20698c2ecf20Sopenharmony_ci /* Reuse original ring buffer. */ 20708c2ecf20Sopenharmony_ci hme_write_rxd(hp, this, 20718c2ecf20Sopenharmony_ci (RXFLAG_OWN|((RX_BUF_ALLOC_SIZE-RX_OFFSET)<<16)), 20728c2ecf20Sopenharmony_ci dma_addr); 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci skb = copy_skb; 20758c2ecf20Sopenharmony_ci } 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci /* This card is _fucking_ hot... */ 20788c2ecf20Sopenharmony_ci skb->csum = csum_unfold(~(__force __sum16)htons(csum)); 20798c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_COMPLETE; 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci RXD(("len=%d csum=%4x]", len, csum)); 20828c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 20838c2ecf20Sopenharmony_ci netif_rx(skb); 20848c2ecf20Sopenharmony_ci 20858c2ecf20Sopenharmony_ci dev->stats.rx_packets++; 20868c2ecf20Sopenharmony_ci dev->stats.rx_bytes += len; 20878c2ecf20Sopenharmony_ci next: 20888c2ecf20Sopenharmony_ci elem = NEXT_RX(elem); 20898c2ecf20Sopenharmony_ci this = &rxbase[elem]; 20908c2ecf20Sopenharmony_ci } 20918c2ecf20Sopenharmony_ci hp->rx_new = elem; 20928c2ecf20Sopenharmony_ci if (drops) 20938c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Memory squeeze, deferring packet.\n", hp->dev->name); 20948c2ecf20Sopenharmony_ci RXD((">")); 20958c2ecf20Sopenharmony_ci} 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_cistatic irqreturn_t happy_meal_interrupt(int irq, void *dev_id) 20988c2ecf20Sopenharmony_ci{ 20998c2ecf20Sopenharmony_ci struct net_device *dev = dev_id; 21008c2ecf20Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 21018c2ecf20Sopenharmony_ci u32 happy_status = hme_read32(hp, hp->gregs + GREG_STAT); 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ci HMD(("happy_meal_interrupt: status=%08x ", happy_status)); 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci spin_lock(&hp->happy_lock); 21068c2ecf20Sopenharmony_ci 21078c2ecf20Sopenharmony_ci if (happy_status & GREG_STAT_ERRORS) { 21088c2ecf20Sopenharmony_ci HMD(("ERRORS ")); 21098c2ecf20Sopenharmony_ci if (happy_meal_is_not_so_happy(hp, /* un- */ happy_status)) 21108c2ecf20Sopenharmony_ci goto out; 21118c2ecf20Sopenharmony_ci } 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci if (happy_status & GREG_STAT_MIFIRQ) { 21148c2ecf20Sopenharmony_ci HMD(("MIFIRQ ")); 21158c2ecf20Sopenharmony_ci happy_meal_mif_interrupt(hp); 21168c2ecf20Sopenharmony_ci } 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci if (happy_status & GREG_STAT_TXALL) { 21198c2ecf20Sopenharmony_ci HMD(("TXALL ")); 21208c2ecf20Sopenharmony_ci happy_meal_tx(hp); 21218c2ecf20Sopenharmony_ci } 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci if (happy_status & GREG_STAT_RXTOHOST) { 21248c2ecf20Sopenharmony_ci HMD(("RXTOHOST ")); 21258c2ecf20Sopenharmony_ci happy_meal_rx(hp, dev); 21268c2ecf20Sopenharmony_ci } 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci HMD(("done\n")); 21298c2ecf20Sopenharmony_ciout: 21308c2ecf20Sopenharmony_ci spin_unlock(&hp->happy_lock); 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ci return IRQ_HANDLED; 21338c2ecf20Sopenharmony_ci} 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci#ifdef CONFIG_SBUS 21368c2ecf20Sopenharmony_cistatic irqreturn_t quattro_sbus_interrupt(int irq, void *cookie) 21378c2ecf20Sopenharmony_ci{ 21388c2ecf20Sopenharmony_ci struct quattro *qp = (struct quattro *) cookie; 21398c2ecf20Sopenharmony_ci int i; 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 21428c2ecf20Sopenharmony_ci struct net_device *dev = qp->happy_meals[i]; 21438c2ecf20Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 21448c2ecf20Sopenharmony_ci u32 happy_status = hme_read32(hp, hp->gregs + GREG_STAT); 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci HMD(("quattro_interrupt: status=%08x ", happy_status)); 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci if (!(happy_status & (GREG_STAT_ERRORS | 21498c2ecf20Sopenharmony_ci GREG_STAT_MIFIRQ | 21508c2ecf20Sopenharmony_ci GREG_STAT_TXALL | 21518c2ecf20Sopenharmony_ci GREG_STAT_RXTOHOST))) 21528c2ecf20Sopenharmony_ci continue; 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci spin_lock(&hp->happy_lock); 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci if (happy_status & GREG_STAT_ERRORS) { 21578c2ecf20Sopenharmony_ci HMD(("ERRORS ")); 21588c2ecf20Sopenharmony_ci if (happy_meal_is_not_so_happy(hp, happy_status)) 21598c2ecf20Sopenharmony_ci goto next; 21608c2ecf20Sopenharmony_ci } 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci if (happy_status & GREG_STAT_MIFIRQ) { 21638c2ecf20Sopenharmony_ci HMD(("MIFIRQ ")); 21648c2ecf20Sopenharmony_ci happy_meal_mif_interrupt(hp); 21658c2ecf20Sopenharmony_ci } 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci if (happy_status & GREG_STAT_TXALL) { 21688c2ecf20Sopenharmony_ci HMD(("TXALL ")); 21698c2ecf20Sopenharmony_ci happy_meal_tx(hp); 21708c2ecf20Sopenharmony_ci } 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci if (happy_status & GREG_STAT_RXTOHOST) { 21738c2ecf20Sopenharmony_ci HMD(("RXTOHOST ")); 21748c2ecf20Sopenharmony_ci happy_meal_rx(hp, dev); 21758c2ecf20Sopenharmony_ci } 21768c2ecf20Sopenharmony_ci 21778c2ecf20Sopenharmony_ci next: 21788c2ecf20Sopenharmony_ci spin_unlock(&hp->happy_lock); 21798c2ecf20Sopenharmony_ci } 21808c2ecf20Sopenharmony_ci HMD(("done\n")); 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_ci return IRQ_HANDLED; 21838c2ecf20Sopenharmony_ci} 21848c2ecf20Sopenharmony_ci#endif 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_cistatic int happy_meal_open(struct net_device *dev) 21878c2ecf20Sopenharmony_ci{ 21888c2ecf20Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 21898c2ecf20Sopenharmony_ci int res; 21908c2ecf20Sopenharmony_ci 21918c2ecf20Sopenharmony_ci HMD(("happy_meal_open: ")); 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ci /* On SBUS Quattro QFE cards, all hme interrupts are concentrated 21948c2ecf20Sopenharmony_ci * into a single source which we register handling at probe time. 21958c2ecf20Sopenharmony_ci */ 21968c2ecf20Sopenharmony_ci if ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO) { 21978c2ecf20Sopenharmony_ci res = request_irq(hp->irq, happy_meal_interrupt, IRQF_SHARED, 21988c2ecf20Sopenharmony_ci dev->name, dev); 21998c2ecf20Sopenharmony_ci if (res) { 22008c2ecf20Sopenharmony_ci HMD(("EAGAIN\n")); 22018c2ecf20Sopenharmony_ci printk(KERN_ERR "happy_meal(SBUS): Can't order irq %d to go.\n", 22028c2ecf20Sopenharmony_ci hp->irq); 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci return -EAGAIN; 22058c2ecf20Sopenharmony_ci } 22068c2ecf20Sopenharmony_ci } 22078c2ecf20Sopenharmony_ci 22088c2ecf20Sopenharmony_ci HMD(("to happy_meal_init\n")); 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 22118c2ecf20Sopenharmony_ci res = happy_meal_init(hp); 22128c2ecf20Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci if (res && ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO)) 22158c2ecf20Sopenharmony_ci free_irq(hp->irq, dev); 22168c2ecf20Sopenharmony_ci return res; 22178c2ecf20Sopenharmony_ci} 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_cistatic int happy_meal_close(struct net_device *dev) 22208c2ecf20Sopenharmony_ci{ 22218c2ecf20Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 22248c2ecf20Sopenharmony_ci happy_meal_stop(hp, hp->gregs); 22258c2ecf20Sopenharmony_ci happy_meal_clean_rings(hp); 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci /* If auto-negotiation timer is running, kill it. */ 22288c2ecf20Sopenharmony_ci del_timer(&hp->happy_timer); 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci /* On Quattro QFE cards, all hme interrupts are concentrated 22338c2ecf20Sopenharmony_ci * into a single source which we register handling at probe 22348c2ecf20Sopenharmony_ci * time and never unregister. 22358c2ecf20Sopenharmony_ci */ 22368c2ecf20Sopenharmony_ci if ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO) 22378c2ecf20Sopenharmony_ci free_irq(hp->irq, dev); 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci return 0; 22408c2ecf20Sopenharmony_ci} 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci#ifdef SXDEBUG 22438c2ecf20Sopenharmony_ci#define SXD(x) printk x 22448c2ecf20Sopenharmony_ci#else 22458c2ecf20Sopenharmony_ci#define SXD(x) 22468c2ecf20Sopenharmony_ci#endif 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_cistatic void happy_meal_tx_timeout(struct net_device *dev, unsigned int txqueue) 22498c2ecf20Sopenharmony_ci{ 22508c2ecf20Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name); 22538c2ecf20Sopenharmony_ci tx_dump_log(); 22548c2ecf20Sopenharmony_ci printk (KERN_ERR "%s: Happy Status %08x TX[%08x:%08x]\n", dev->name, 22558c2ecf20Sopenharmony_ci hme_read32(hp, hp->gregs + GREG_STAT), 22568c2ecf20Sopenharmony_ci hme_read32(hp, hp->etxregs + ETX_CFG), 22578c2ecf20Sopenharmony_ci hme_read32(hp, hp->bigmacregs + BMAC_TXCFG)); 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 22608c2ecf20Sopenharmony_ci happy_meal_init(hp); 22618c2ecf20Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ci netif_wake_queue(dev); 22648c2ecf20Sopenharmony_ci} 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_cistatic void unmap_partial_tx_skb(struct happy_meal *hp, u32 first_mapping, 22678c2ecf20Sopenharmony_ci u32 first_len, u32 first_entry, u32 entry) 22688c2ecf20Sopenharmony_ci{ 22698c2ecf20Sopenharmony_ci struct happy_meal_txd *txbase = &hp->happy_block->happy_meal_txd[0]; 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci dma_unmap_single(hp->dma_dev, first_mapping, first_len, DMA_TO_DEVICE); 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ci first_entry = NEXT_TX(first_entry); 22748c2ecf20Sopenharmony_ci while (first_entry != entry) { 22758c2ecf20Sopenharmony_ci struct happy_meal_txd *this = &txbase[first_entry]; 22768c2ecf20Sopenharmony_ci u32 addr, len; 22778c2ecf20Sopenharmony_ci 22788c2ecf20Sopenharmony_ci addr = hme_read_desc32(hp, &this->tx_addr); 22798c2ecf20Sopenharmony_ci len = hme_read_desc32(hp, &this->tx_flags); 22808c2ecf20Sopenharmony_ci len &= TXFLAG_SIZE; 22818c2ecf20Sopenharmony_ci dma_unmap_page(hp->dma_dev, addr, len, DMA_TO_DEVICE); 22828c2ecf20Sopenharmony_ci } 22838c2ecf20Sopenharmony_ci} 22848c2ecf20Sopenharmony_ci 22858c2ecf20Sopenharmony_cistatic netdev_tx_t happy_meal_start_xmit(struct sk_buff *skb, 22868c2ecf20Sopenharmony_ci struct net_device *dev) 22878c2ecf20Sopenharmony_ci{ 22888c2ecf20Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 22898c2ecf20Sopenharmony_ci int entry; 22908c2ecf20Sopenharmony_ci u32 tx_flags; 22918c2ecf20Sopenharmony_ci 22928c2ecf20Sopenharmony_ci tx_flags = TXFLAG_OWN; 22938c2ecf20Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL) { 22948c2ecf20Sopenharmony_ci const u32 csum_start_off = skb_checksum_start_offset(skb); 22958c2ecf20Sopenharmony_ci const u32 csum_stuff_off = csum_start_off + skb->csum_offset; 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci tx_flags = (TXFLAG_OWN | TXFLAG_CSENABLE | 22988c2ecf20Sopenharmony_ci ((csum_start_off << 14) & TXFLAG_CSBUFBEGIN) | 22998c2ecf20Sopenharmony_ci ((csum_stuff_off << 20) & TXFLAG_CSLOCATION)); 23008c2ecf20Sopenharmony_ci } 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci if (TX_BUFFS_AVAIL(hp) <= (skb_shinfo(skb)->nr_frags + 1)) { 23058c2ecf20Sopenharmony_ci netif_stop_queue(dev); 23068c2ecf20Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 23078c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: BUG! Tx Ring full when queue awake!\n", 23088c2ecf20Sopenharmony_ci dev->name); 23098c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 23108c2ecf20Sopenharmony_ci } 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci entry = hp->tx_new; 23138c2ecf20Sopenharmony_ci SXD(("SX<l[%d]e[%d]>", len, entry)); 23148c2ecf20Sopenharmony_ci hp->tx_skbs[entry] = skb; 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci if (skb_shinfo(skb)->nr_frags == 0) { 23178c2ecf20Sopenharmony_ci u32 mapping, len; 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci len = skb->len; 23208c2ecf20Sopenharmony_ci mapping = dma_map_single(hp->dma_dev, skb->data, len, DMA_TO_DEVICE); 23218c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(hp->dma_dev, mapping))) 23228c2ecf20Sopenharmony_ci goto out_dma_error; 23238c2ecf20Sopenharmony_ci tx_flags |= (TXFLAG_SOP | TXFLAG_EOP); 23248c2ecf20Sopenharmony_ci hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry], 23258c2ecf20Sopenharmony_ci (tx_flags | (len & TXFLAG_SIZE)), 23268c2ecf20Sopenharmony_ci mapping); 23278c2ecf20Sopenharmony_ci entry = NEXT_TX(entry); 23288c2ecf20Sopenharmony_ci } else { 23298c2ecf20Sopenharmony_ci u32 first_len, first_mapping; 23308c2ecf20Sopenharmony_ci int frag, first_entry = entry; 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci /* We must give this initial chunk to the device last. 23338c2ecf20Sopenharmony_ci * Otherwise we could race with the device. 23348c2ecf20Sopenharmony_ci */ 23358c2ecf20Sopenharmony_ci first_len = skb_headlen(skb); 23368c2ecf20Sopenharmony_ci first_mapping = dma_map_single(hp->dma_dev, skb->data, first_len, 23378c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 23388c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(hp->dma_dev, first_mapping))) 23398c2ecf20Sopenharmony_ci goto out_dma_error; 23408c2ecf20Sopenharmony_ci entry = NEXT_TX(entry); 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { 23438c2ecf20Sopenharmony_ci const skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag]; 23448c2ecf20Sopenharmony_ci u32 len, mapping, this_txflags; 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_ci len = skb_frag_size(this_frag); 23478c2ecf20Sopenharmony_ci mapping = skb_frag_dma_map(hp->dma_dev, this_frag, 23488c2ecf20Sopenharmony_ci 0, len, DMA_TO_DEVICE); 23498c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(hp->dma_dev, mapping))) { 23508c2ecf20Sopenharmony_ci unmap_partial_tx_skb(hp, first_mapping, first_len, 23518c2ecf20Sopenharmony_ci first_entry, entry); 23528c2ecf20Sopenharmony_ci goto out_dma_error; 23538c2ecf20Sopenharmony_ci } 23548c2ecf20Sopenharmony_ci this_txflags = tx_flags; 23558c2ecf20Sopenharmony_ci if (frag == skb_shinfo(skb)->nr_frags - 1) 23568c2ecf20Sopenharmony_ci this_txflags |= TXFLAG_EOP; 23578c2ecf20Sopenharmony_ci hme_write_txd(hp, &hp->happy_block->happy_meal_txd[entry], 23588c2ecf20Sopenharmony_ci (this_txflags | (len & TXFLAG_SIZE)), 23598c2ecf20Sopenharmony_ci mapping); 23608c2ecf20Sopenharmony_ci entry = NEXT_TX(entry); 23618c2ecf20Sopenharmony_ci } 23628c2ecf20Sopenharmony_ci hme_write_txd(hp, &hp->happy_block->happy_meal_txd[first_entry], 23638c2ecf20Sopenharmony_ci (tx_flags | TXFLAG_SOP | (first_len & TXFLAG_SIZE)), 23648c2ecf20Sopenharmony_ci first_mapping); 23658c2ecf20Sopenharmony_ci } 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_ci hp->tx_new = entry; 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci if (TX_BUFFS_AVAIL(hp) <= (MAX_SKB_FRAGS + 1)) 23708c2ecf20Sopenharmony_ci netif_stop_queue(dev); 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci /* Get it going. */ 23738c2ecf20Sopenharmony_ci hme_write32(hp, hp->etxregs + ETX_PENDING, ETX_TP_DMAWAKEUP); 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci tx_add_log(hp, TXLOG_ACTION_TXMIT, 0); 23788c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ciout_dma_error: 23818c2ecf20Sopenharmony_ci hp->tx_skbs[hp->tx_new] = NULL; 23828c2ecf20Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 23858c2ecf20Sopenharmony_ci dev->stats.tx_dropped++; 23868c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 23878c2ecf20Sopenharmony_ci} 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_cistatic struct net_device_stats *happy_meal_get_stats(struct net_device *dev) 23908c2ecf20Sopenharmony_ci{ 23918c2ecf20Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 23948c2ecf20Sopenharmony_ci happy_meal_get_counters(hp, hp->bigmacregs); 23958c2ecf20Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci return &dev->stats; 23988c2ecf20Sopenharmony_ci} 23998c2ecf20Sopenharmony_ci 24008c2ecf20Sopenharmony_cistatic void happy_meal_set_multicast(struct net_device *dev) 24018c2ecf20Sopenharmony_ci{ 24028c2ecf20Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 24038c2ecf20Sopenharmony_ci void __iomem *bregs = hp->bigmacregs; 24048c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 24058c2ecf20Sopenharmony_ci u32 crc; 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci if ((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) { 24108c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE0, 0xffff); 24118c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE1, 0xffff); 24128c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE2, 0xffff); 24138c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE3, 0xffff); 24148c2ecf20Sopenharmony_ci } else if (dev->flags & IFF_PROMISC) { 24158c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_RXCFG, 24168c2ecf20Sopenharmony_ci hme_read32(hp, bregs + BMAC_RXCFG) | BIGMAC_RXCFG_PMISC); 24178c2ecf20Sopenharmony_ci } else { 24188c2ecf20Sopenharmony_ci u16 hash_table[4]; 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ci memset(hash_table, 0, sizeof(hash_table)); 24218c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 24228c2ecf20Sopenharmony_ci crc = ether_crc_le(6, ha->addr); 24238c2ecf20Sopenharmony_ci crc >>= 26; 24248c2ecf20Sopenharmony_ci hash_table[crc >> 4] |= 1 << (crc & 0xf); 24258c2ecf20Sopenharmony_ci } 24268c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE0, hash_table[0]); 24278c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE1, hash_table[1]); 24288c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE2, hash_table[2]); 24298c2ecf20Sopenharmony_ci hme_write32(hp, bregs + BMAC_HTABLE3, hash_table[3]); 24308c2ecf20Sopenharmony_ci } 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 24338c2ecf20Sopenharmony_ci} 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ci/* Ethtool support... */ 24368c2ecf20Sopenharmony_cistatic int hme_get_link_ksettings(struct net_device *dev, 24378c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd) 24388c2ecf20Sopenharmony_ci{ 24398c2ecf20Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 24408c2ecf20Sopenharmony_ci u32 speed; 24418c2ecf20Sopenharmony_ci u32 supported; 24428c2ecf20Sopenharmony_ci 24438c2ecf20Sopenharmony_ci supported = 24448c2ecf20Sopenharmony_ci (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | 24458c2ecf20Sopenharmony_ci SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | 24468c2ecf20Sopenharmony_ci SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII); 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_ci /* XXX hardcoded stuff for now */ 24498c2ecf20Sopenharmony_ci cmd->base.port = PORT_TP; /* XXX no MII support */ 24508c2ecf20Sopenharmony_ci cmd->base.phy_address = 0; /* XXX fixed PHYAD */ 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci /* Record PHY settings. */ 24538c2ecf20Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 24548c2ecf20Sopenharmony_ci hp->sw_bmcr = happy_meal_tcvr_read(hp, hp->tcvregs, MII_BMCR); 24558c2ecf20Sopenharmony_ci hp->sw_lpa = happy_meal_tcvr_read(hp, hp->tcvregs, MII_LPA); 24568c2ecf20Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 24578c2ecf20Sopenharmony_ci 24588c2ecf20Sopenharmony_ci if (hp->sw_bmcr & BMCR_ANENABLE) { 24598c2ecf20Sopenharmony_ci cmd->base.autoneg = AUTONEG_ENABLE; 24608c2ecf20Sopenharmony_ci speed = ((hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) ? 24618c2ecf20Sopenharmony_ci SPEED_100 : SPEED_10); 24628c2ecf20Sopenharmony_ci if (speed == SPEED_100) 24638c2ecf20Sopenharmony_ci cmd->base.duplex = 24648c2ecf20Sopenharmony_ci (hp->sw_lpa & (LPA_100FULL)) ? 24658c2ecf20Sopenharmony_ci DUPLEX_FULL : DUPLEX_HALF; 24668c2ecf20Sopenharmony_ci else 24678c2ecf20Sopenharmony_ci cmd->base.duplex = 24688c2ecf20Sopenharmony_ci (hp->sw_lpa & (LPA_10FULL)) ? 24698c2ecf20Sopenharmony_ci DUPLEX_FULL : DUPLEX_HALF; 24708c2ecf20Sopenharmony_ci } else { 24718c2ecf20Sopenharmony_ci cmd->base.autoneg = AUTONEG_DISABLE; 24728c2ecf20Sopenharmony_ci speed = (hp->sw_bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10; 24738c2ecf20Sopenharmony_ci cmd->base.duplex = 24748c2ecf20Sopenharmony_ci (hp->sw_bmcr & BMCR_FULLDPLX) ? 24758c2ecf20Sopenharmony_ci DUPLEX_FULL : DUPLEX_HALF; 24768c2ecf20Sopenharmony_ci } 24778c2ecf20Sopenharmony_ci cmd->base.speed = speed; 24788c2ecf20Sopenharmony_ci ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, 24798c2ecf20Sopenharmony_ci supported); 24808c2ecf20Sopenharmony_ci 24818c2ecf20Sopenharmony_ci return 0; 24828c2ecf20Sopenharmony_ci} 24838c2ecf20Sopenharmony_ci 24848c2ecf20Sopenharmony_cistatic int hme_set_link_ksettings(struct net_device *dev, 24858c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 24868c2ecf20Sopenharmony_ci{ 24878c2ecf20Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci /* Verify the settings we care about. */ 24908c2ecf20Sopenharmony_ci if (cmd->base.autoneg != AUTONEG_ENABLE && 24918c2ecf20Sopenharmony_ci cmd->base.autoneg != AUTONEG_DISABLE) 24928c2ecf20Sopenharmony_ci return -EINVAL; 24938c2ecf20Sopenharmony_ci if (cmd->base.autoneg == AUTONEG_DISABLE && 24948c2ecf20Sopenharmony_ci ((cmd->base.speed != SPEED_100 && 24958c2ecf20Sopenharmony_ci cmd->base.speed != SPEED_10) || 24968c2ecf20Sopenharmony_ci (cmd->base.duplex != DUPLEX_HALF && 24978c2ecf20Sopenharmony_ci cmd->base.duplex != DUPLEX_FULL))) 24988c2ecf20Sopenharmony_ci return -EINVAL; 24998c2ecf20Sopenharmony_ci 25008c2ecf20Sopenharmony_ci /* Ok, do it to it. */ 25018c2ecf20Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 25028c2ecf20Sopenharmony_ci del_timer(&hp->happy_timer); 25038c2ecf20Sopenharmony_ci happy_meal_begin_auto_negotiation(hp, hp->tcvregs, cmd); 25048c2ecf20Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 25058c2ecf20Sopenharmony_ci 25068c2ecf20Sopenharmony_ci return 0; 25078c2ecf20Sopenharmony_ci} 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_cistatic void hme_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) 25108c2ecf20Sopenharmony_ci{ 25118c2ecf20Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_ci strlcpy(info->driver, "sunhme", sizeof(info->driver)); 25148c2ecf20Sopenharmony_ci strlcpy(info->version, "2.02", sizeof(info->version)); 25158c2ecf20Sopenharmony_ci if (hp->happy_flags & HFLAG_PCI) { 25168c2ecf20Sopenharmony_ci struct pci_dev *pdev = hp->happy_dev; 25178c2ecf20Sopenharmony_ci strlcpy(info->bus_info, pci_name(pdev), sizeof(info->bus_info)); 25188c2ecf20Sopenharmony_ci } 25198c2ecf20Sopenharmony_ci#ifdef CONFIG_SBUS 25208c2ecf20Sopenharmony_ci else { 25218c2ecf20Sopenharmony_ci const struct linux_prom_registers *regs; 25228c2ecf20Sopenharmony_ci struct platform_device *op = hp->happy_dev; 25238c2ecf20Sopenharmony_ci regs = of_get_property(op->dev.of_node, "regs", NULL); 25248c2ecf20Sopenharmony_ci if (regs) 25258c2ecf20Sopenharmony_ci snprintf(info->bus_info, sizeof(info->bus_info), 25268c2ecf20Sopenharmony_ci "SBUS:%d", 25278c2ecf20Sopenharmony_ci regs->which_io); 25288c2ecf20Sopenharmony_ci } 25298c2ecf20Sopenharmony_ci#endif 25308c2ecf20Sopenharmony_ci} 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_cistatic u32 hme_get_link(struct net_device *dev) 25338c2ecf20Sopenharmony_ci{ 25348c2ecf20Sopenharmony_ci struct happy_meal *hp = netdev_priv(dev); 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 25378c2ecf20Sopenharmony_ci hp->sw_bmcr = happy_meal_tcvr_read(hp, hp->tcvregs, MII_BMCR); 25388c2ecf20Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci return hp->sw_bmsr & BMSR_LSTATUS; 25418c2ecf20Sopenharmony_ci} 25428c2ecf20Sopenharmony_ci 25438c2ecf20Sopenharmony_cistatic const struct ethtool_ops hme_ethtool_ops = { 25448c2ecf20Sopenharmony_ci .get_drvinfo = hme_get_drvinfo, 25458c2ecf20Sopenharmony_ci .get_link = hme_get_link, 25468c2ecf20Sopenharmony_ci .get_link_ksettings = hme_get_link_ksettings, 25478c2ecf20Sopenharmony_ci .set_link_ksettings = hme_set_link_ksettings, 25488c2ecf20Sopenharmony_ci}; 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_cistatic int hme_version_printed; 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci#ifdef CONFIG_SBUS 25538c2ecf20Sopenharmony_ci/* Given a happy meal sbus device, find it's quattro parent. 25548c2ecf20Sopenharmony_ci * If none exist, allocate and return a new one. 25558c2ecf20Sopenharmony_ci * 25568c2ecf20Sopenharmony_ci * Return NULL on failure. 25578c2ecf20Sopenharmony_ci */ 25588c2ecf20Sopenharmony_cistatic struct quattro *quattro_sbus_find(struct platform_device *child) 25598c2ecf20Sopenharmony_ci{ 25608c2ecf20Sopenharmony_ci struct device *parent = child->dev.parent; 25618c2ecf20Sopenharmony_ci struct platform_device *op; 25628c2ecf20Sopenharmony_ci struct quattro *qp; 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci op = to_platform_device(parent); 25658c2ecf20Sopenharmony_ci qp = platform_get_drvdata(op); 25668c2ecf20Sopenharmony_ci if (qp) 25678c2ecf20Sopenharmony_ci return qp; 25688c2ecf20Sopenharmony_ci 25698c2ecf20Sopenharmony_ci qp = kmalloc(sizeof(struct quattro), GFP_KERNEL); 25708c2ecf20Sopenharmony_ci if (qp != NULL) { 25718c2ecf20Sopenharmony_ci int i; 25728c2ecf20Sopenharmony_ci 25738c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 25748c2ecf20Sopenharmony_ci qp->happy_meals[i] = NULL; 25758c2ecf20Sopenharmony_ci 25768c2ecf20Sopenharmony_ci qp->quattro_dev = child; 25778c2ecf20Sopenharmony_ci qp->next = qfe_sbus_list; 25788c2ecf20Sopenharmony_ci qfe_sbus_list = qp; 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci platform_set_drvdata(op, qp); 25818c2ecf20Sopenharmony_ci } 25828c2ecf20Sopenharmony_ci return qp; 25838c2ecf20Sopenharmony_ci} 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci/* After all quattro cards have been probed, we call these functions 25868c2ecf20Sopenharmony_ci * to register the IRQ handlers for the cards that have been 25878c2ecf20Sopenharmony_ci * successfully probed and skip the cards that failed to initialize 25888c2ecf20Sopenharmony_ci */ 25898c2ecf20Sopenharmony_cistatic int __init quattro_sbus_register_irqs(void) 25908c2ecf20Sopenharmony_ci{ 25918c2ecf20Sopenharmony_ci struct quattro *qp; 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) { 25948c2ecf20Sopenharmony_ci struct platform_device *op = qp->quattro_dev; 25958c2ecf20Sopenharmony_ci int err, qfe_slot, skip = 0; 25968c2ecf20Sopenharmony_ci 25978c2ecf20Sopenharmony_ci for (qfe_slot = 0; qfe_slot < 4; qfe_slot++) { 25988c2ecf20Sopenharmony_ci if (!qp->happy_meals[qfe_slot]) 25998c2ecf20Sopenharmony_ci skip = 1; 26008c2ecf20Sopenharmony_ci } 26018c2ecf20Sopenharmony_ci if (skip) 26028c2ecf20Sopenharmony_ci continue; 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_ci err = request_irq(op->archdata.irqs[0], 26058c2ecf20Sopenharmony_ci quattro_sbus_interrupt, 26068c2ecf20Sopenharmony_ci IRQF_SHARED, "Quattro", 26078c2ecf20Sopenharmony_ci qp); 26088c2ecf20Sopenharmony_ci if (err != 0) { 26098c2ecf20Sopenharmony_ci printk(KERN_ERR "Quattro HME: IRQ registration " 26108c2ecf20Sopenharmony_ci "error %d.\n", err); 26118c2ecf20Sopenharmony_ci return err; 26128c2ecf20Sopenharmony_ci } 26138c2ecf20Sopenharmony_ci } 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_ci return 0; 26168c2ecf20Sopenharmony_ci} 26178c2ecf20Sopenharmony_ci 26188c2ecf20Sopenharmony_cistatic void quattro_sbus_free_irqs(void) 26198c2ecf20Sopenharmony_ci{ 26208c2ecf20Sopenharmony_ci struct quattro *qp; 26218c2ecf20Sopenharmony_ci 26228c2ecf20Sopenharmony_ci for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) { 26238c2ecf20Sopenharmony_ci struct platform_device *op = qp->quattro_dev; 26248c2ecf20Sopenharmony_ci int qfe_slot, skip = 0; 26258c2ecf20Sopenharmony_ci 26268c2ecf20Sopenharmony_ci for (qfe_slot = 0; qfe_slot < 4; qfe_slot++) { 26278c2ecf20Sopenharmony_ci if (!qp->happy_meals[qfe_slot]) 26288c2ecf20Sopenharmony_ci skip = 1; 26298c2ecf20Sopenharmony_ci } 26308c2ecf20Sopenharmony_ci if (skip) 26318c2ecf20Sopenharmony_ci continue; 26328c2ecf20Sopenharmony_ci 26338c2ecf20Sopenharmony_ci free_irq(op->archdata.irqs[0], qp); 26348c2ecf20Sopenharmony_ci } 26358c2ecf20Sopenharmony_ci} 26368c2ecf20Sopenharmony_ci#endif /* CONFIG_SBUS */ 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 26398c2ecf20Sopenharmony_cistatic struct quattro *quattro_pci_find(struct pci_dev *pdev) 26408c2ecf20Sopenharmony_ci{ 26418c2ecf20Sopenharmony_ci struct pci_dev *bdev = pdev->bus->self; 26428c2ecf20Sopenharmony_ci struct quattro *qp; 26438c2ecf20Sopenharmony_ci 26448c2ecf20Sopenharmony_ci if (!bdev) return NULL; 26458c2ecf20Sopenharmony_ci for (qp = qfe_pci_list; qp != NULL; qp = qp->next) { 26468c2ecf20Sopenharmony_ci struct pci_dev *qpdev = qp->quattro_dev; 26478c2ecf20Sopenharmony_ci 26488c2ecf20Sopenharmony_ci if (qpdev == bdev) 26498c2ecf20Sopenharmony_ci return qp; 26508c2ecf20Sopenharmony_ci } 26518c2ecf20Sopenharmony_ci qp = kmalloc(sizeof(struct quattro), GFP_KERNEL); 26528c2ecf20Sopenharmony_ci if (qp != NULL) { 26538c2ecf20Sopenharmony_ci int i; 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 26568c2ecf20Sopenharmony_ci qp->happy_meals[i] = NULL; 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci qp->quattro_dev = bdev; 26598c2ecf20Sopenharmony_ci qp->next = qfe_pci_list; 26608c2ecf20Sopenharmony_ci qfe_pci_list = qp; 26618c2ecf20Sopenharmony_ci 26628c2ecf20Sopenharmony_ci /* No range tricks necessary on PCI. */ 26638c2ecf20Sopenharmony_ci qp->nranges = 0; 26648c2ecf20Sopenharmony_ci } 26658c2ecf20Sopenharmony_ci return qp; 26668c2ecf20Sopenharmony_ci} 26678c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */ 26688c2ecf20Sopenharmony_ci 26698c2ecf20Sopenharmony_cistatic const struct net_device_ops hme_netdev_ops = { 26708c2ecf20Sopenharmony_ci .ndo_open = happy_meal_open, 26718c2ecf20Sopenharmony_ci .ndo_stop = happy_meal_close, 26728c2ecf20Sopenharmony_ci .ndo_start_xmit = happy_meal_start_xmit, 26738c2ecf20Sopenharmony_ci .ndo_tx_timeout = happy_meal_tx_timeout, 26748c2ecf20Sopenharmony_ci .ndo_get_stats = happy_meal_get_stats, 26758c2ecf20Sopenharmony_ci .ndo_set_rx_mode = happy_meal_set_multicast, 26768c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 26778c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 26788c2ecf20Sopenharmony_ci}; 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_ci#ifdef CONFIG_SBUS 26818c2ecf20Sopenharmony_cistatic int happy_meal_sbus_probe_one(struct platform_device *op, int is_qfe) 26828c2ecf20Sopenharmony_ci{ 26838c2ecf20Sopenharmony_ci struct device_node *dp = op->dev.of_node, *sbus_dp; 26848c2ecf20Sopenharmony_ci struct quattro *qp = NULL; 26858c2ecf20Sopenharmony_ci struct happy_meal *hp; 26868c2ecf20Sopenharmony_ci struct net_device *dev; 26878c2ecf20Sopenharmony_ci int i, qfe_slot = -1; 26888c2ecf20Sopenharmony_ci int err = -ENODEV; 26898c2ecf20Sopenharmony_ci 26908c2ecf20Sopenharmony_ci sbus_dp = op->dev.parent->of_node; 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_ci /* We can match PCI devices too, do not accept those here. */ 26938c2ecf20Sopenharmony_ci if (!of_node_name_eq(sbus_dp, "sbus") && !of_node_name_eq(sbus_dp, "sbi")) 26948c2ecf20Sopenharmony_ci return err; 26958c2ecf20Sopenharmony_ci 26968c2ecf20Sopenharmony_ci if (is_qfe) { 26978c2ecf20Sopenharmony_ci qp = quattro_sbus_find(op); 26988c2ecf20Sopenharmony_ci if (qp == NULL) 26998c2ecf20Sopenharmony_ci goto err_out; 27008c2ecf20Sopenharmony_ci for (qfe_slot = 0; qfe_slot < 4; qfe_slot++) 27018c2ecf20Sopenharmony_ci if (qp->happy_meals[qfe_slot] == NULL) 27028c2ecf20Sopenharmony_ci break; 27038c2ecf20Sopenharmony_ci if (qfe_slot == 4) 27048c2ecf20Sopenharmony_ci goto err_out; 27058c2ecf20Sopenharmony_ci } 27068c2ecf20Sopenharmony_ci 27078c2ecf20Sopenharmony_ci err = -ENOMEM; 27088c2ecf20Sopenharmony_ci dev = alloc_etherdev(sizeof(struct happy_meal)); 27098c2ecf20Sopenharmony_ci if (!dev) 27108c2ecf20Sopenharmony_ci goto err_out; 27118c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, &op->dev); 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci if (hme_version_printed++ == 0) 27148c2ecf20Sopenharmony_ci printk(KERN_INFO "%s", version); 27158c2ecf20Sopenharmony_ci 27168c2ecf20Sopenharmony_ci /* If user did not specify a MAC address specifically, use 27178c2ecf20Sopenharmony_ci * the Quattro local-mac-address property... 27188c2ecf20Sopenharmony_ci */ 27198c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) { 27208c2ecf20Sopenharmony_ci if (macaddr[i] != 0) 27218c2ecf20Sopenharmony_ci break; 27228c2ecf20Sopenharmony_ci } 27238c2ecf20Sopenharmony_ci if (i < 6) { /* a mac address was given */ 27248c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) 27258c2ecf20Sopenharmony_ci dev->dev_addr[i] = macaddr[i]; 27268c2ecf20Sopenharmony_ci macaddr[5]++; 27278c2ecf20Sopenharmony_ci } else { 27288c2ecf20Sopenharmony_ci const unsigned char *addr; 27298c2ecf20Sopenharmony_ci int len; 27308c2ecf20Sopenharmony_ci 27318c2ecf20Sopenharmony_ci addr = of_get_property(dp, "local-mac-address", &len); 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ci if (qfe_slot != -1 && addr && len == ETH_ALEN) 27348c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, addr, ETH_ALEN); 27358c2ecf20Sopenharmony_ci else 27368c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, idprom->id_ethaddr, ETH_ALEN); 27378c2ecf20Sopenharmony_ci } 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci hp = netdev_priv(dev); 27408c2ecf20Sopenharmony_ci 27418c2ecf20Sopenharmony_ci hp->happy_dev = op; 27428c2ecf20Sopenharmony_ci hp->dma_dev = &op->dev; 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci spin_lock_init(&hp->happy_lock); 27458c2ecf20Sopenharmony_ci 27468c2ecf20Sopenharmony_ci err = -ENODEV; 27478c2ecf20Sopenharmony_ci if (qp != NULL) { 27488c2ecf20Sopenharmony_ci hp->qfe_parent = qp; 27498c2ecf20Sopenharmony_ci hp->qfe_ent = qfe_slot; 27508c2ecf20Sopenharmony_ci qp->happy_meals[qfe_slot] = dev; 27518c2ecf20Sopenharmony_ci } 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci hp->gregs = of_ioremap(&op->resource[0], 0, 27548c2ecf20Sopenharmony_ci GREG_REG_SIZE, "HME Global Regs"); 27558c2ecf20Sopenharmony_ci if (!hp->gregs) { 27568c2ecf20Sopenharmony_ci printk(KERN_ERR "happymeal: Cannot map global registers.\n"); 27578c2ecf20Sopenharmony_ci goto err_out_free_netdev; 27588c2ecf20Sopenharmony_ci } 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ci hp->etxregs = of_ioremap(&op->resource[1], 0, 27618c2ecf20Sopenharmony_ci ETX_REG_SIZE, "HME TX Regs"); 27628c2ecf20Sopenharmony_ci if (!hp->etxregs) { 27638c2ecf20Sopenharmony_ci printk(KERN_ERR "happymeal: Cannot map MAC TX registers.\n"); 27648c2ecf20Sopenharmony_ci goto err_out_iounmap; 27658c2ecf20Sopenharmony_ci } 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci hp->erxregs = of_ioremap(&op->resource[2], 0, 27688c2ecf20Sopenharmony_ci ERX_REG_SIZE, "HME RX Regs"); 27698c2ecf20Sopenharmony_ci if (!hp->erxregs) { 27708c2ecf20Sopenharmony_ci printk(KERN_ERR "happymeal: Cannot map MAC RX registers.\n"); 27718c2ecf20Sopenharmony_ci goto err_out_iounmap; 27728c2ecf20Sopenharmony_ci } 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_ci hp->bigmacregs = of_ioremap(&op->resource[3], 0, 27758c2ecf20Sopenharmony_ci BMAC_REG_SIZE, "HME BIGMAC Regs"); 27768c2ecf20Sopenharmony_ci if (!hp->bigmacregs) { 27778c2ecf20Sopenharmony_ci printk(KERN_ERR "happymeal: Cannot map BIGMAC registers.\n"); 27788c2ecf20Sopenharmony_ci goto err_out_iounmap; 27798c2ecf20Sopenharmony_ci } 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci hp->tcvregs = of_ioremap(&op->resource[4], 0, 27828c2ecf20Sopenharmony_ci TCVR_REG_SIZE, "HME Tranceiver Regs"); 27838c2ecf20Sopenharmony_ci if (!hp->tcvregs) { 27848c2ecf20Sopenharmony_ci printk(KERN_ERR "happymeal: Cannot map TCVR registers.\n"); 27858c2ecf20Sopenharmony_ci goto err_out_iounmap; 27868c2ecf20Sopenharmony_ci } 27878c2ecf20Sopenharmony_ci 27888c2ecf20Sopenharmony_ci hp->hm_revision = of_getintprop_default(dp, "hm-rev", 0xff); 27898c2ecf20Sopenharmony_ci if (hp->hm_revision == 0xff) 27908c2ecf20Sopenharmony_ci hp->hm_revision = 0xa0; 27918c2ecf20Sopenharmony_ci 27928c2ecf20Sopenharmony_ci /* Now enable the feature flags we can. */ 27938c2ecf20Sopenharmony_ci if (hp->hm_revision == 0x20 || hp->hm_revision == 0x21) 27948c2ecf20Sopenharmony_ci hp->happy_flags = HFLAG_20_21; 27958c2ecf20Sopenharmony_ci else if (hp->hm_revision != 0xa0) 27968c2ecf20Sopenharmony_ci hp->happy_flags = HFLAG_NOT_A0; 27978c2ecf20Sopenharmony_ci 27988c2ecf20Sopenharmony_ci if (qp != NULL) 27998c2ecf20Sopenharmony_ci hp->happy_flags |= HFLAG_QUATTRO; 28008c2ecf20Sopenharmony_ci 28018c2ecf20Sopenharmony_ci /* Get the supported DVMA burst sizes from our Happy SBUS. */ 28028c2ecf20Sopenharmony_ci hp->happy_bursts = of_getintprop_default(sbus_dp, 28038c2ecf20Sopenharmony_ci "burst-sizes", 0x00); 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_ci hp->happy_block = dma_alloc_coherent(hp->dma_dev, 28068c2ecf20Sopenharmony_ci PAGE_SIZE, 28078c2ecf20Sopenharmony_ci &hp->hblock_dvma, 28088c2ecf20Sopenharmony_ci GFP_ATOMIC); 28098c2ecf20Sopenharmony_ci err = -ENOMEM; 28108c2ecf20Sopenharmony_ci if (!hp->happy_block) 28118c2ecf20Sopenharmony_ci goto err_out_iounmap; 28128c2ecf20Sopenharmony_ci 28138c2ecf20Sopenharmony_ci /* Force check of the link first time we are brought up. */ 28148c2ecf20Sopenharmony_ci hp->linkcheck = 0; 28158c2ecf20Sopenharmony_ci 28168c2ecf20Sopenharmony_ci /* Force timer state to 'asleep' with count of zero. */ 28178c2ecf20Sopenharmony_ci hp->timer_state = asleep; 28188c2ecf20Sopenharmony_ci hp->timer_ticks = 0; 28198c2ecf20Sopenharmony_ci 28208c2ecf20Sopenharmony_ci timer_setup(&hp->happy_timer, happy_meal_timer, 0); 28218c2ecf20Sopenharmony_ci 28228c2ecf20Sopenharmony_ci hp->dev = dev; 28238c2ecf20Sopenharmony_ci dev->netdev_ops = &hme_netdev_ops; 28248c2ecf20Sopenharmony_ci dev->watchdog_timeo = 5*HZ; 28258c2ecf20Sopenharmony_ci dev->ethtool_ops = &hme_ethtool_ops; 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_ci /* Happy Meal can do it all... */ 28288c2ecf20Sopenharmony_ci dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; 28298c2ecf20Sopenharmony_ci dev->features |= dev->hw_features | NETIF_F_RXCSUM; 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci hp->irq = op->archdata.irqs[0]; 28328c2ecf20Sopenharmony_ci 28338c2ecf20Sopenharmony_ci#if defined(CONFIG_SBUS) && defined(CONFIG_PCI) 28348c2ecf20Sopenharmony_ci /* Hook up SBUS register/descriptor accessors. */ 28358c2ecf20Sopenharmony_ci hp->read_desc32 = sbus_hme_read_desc32; 28368c2ecf20Sopenharmony_ci hp->write_txd = sbus_hme_write_txd; 28378c2ecf20Sopenharmony_ci hp->write_rxd = sbus_hme_write_rxd; 28388c2ecf20Sopenharmony_ci hp->read32 = sbus_hme_read32; 28398c2ecf20Sopenharmony_ci hp->write32 = sbus_hme_write32; 28408c2ecf20Sopenharmony_ci#endif 28418c2ecf20Sopenharmony_ci 28428c2ecf20Sopenharmony_ci /* Grrr, Happy Meal comes up by default not advertising 28438c2ecf20Sopenharmony_ci * full duplex 100baseT capabilities, fix this. 28448c2ecf20Sopenharmony_ci */ 28458c2ecf20Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 28468c2ecf20Sopenharmony_ci happy_meal_set_initial_advertisement(hp); 28478c2ecf20Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_ci err = register_netdev(hp->dev); 28508c2ecf20Sopenharmony_ci if (err) { 28518c2ecf20Sopenharmony_ci printk(KERN_ERR "happymeal: Cannot register net device, " 28528c2ecf20Sopenharmony_ci "aborting.\n"); 28538c2ecf20Sopenharmony_ci goto err_out_free_coherent; 28548c2ecf20Sopenharmony_ci } 28558c2ecf20Sopenharmony_ci 28568c2ecf20Sopenharmony_ci platform_set_drvdata(op, hp); 28578c2ecf20Sopenharmony_ci 28588c2ecf20Sopenharmony_ci if (qfe_slot != -1) 28598c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ", 28608c2ecf20Sopenharmony_ci dev->name, qfe_slot); 28618c2ecf20Sopenharmony_ci else 28628c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ", 28638c2ecf20Sopenharmony_ci dev->name); 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci printk("%pM\n", dev->dev_addr); 28668c2ecf20Sopenharmony_ci 28678c2ecf20Sopenharmony_ci return 0; 28688c2ecf20Sopenharmony_ci 28698c2ecf20Sopenharmony_cierr_out_free_coherent: 28708c2ecf20Sopenharmony_ci dma_free_coherent(hp->dma_dev, 28718c2ecf20Sopenharmony_ci PAGE_SIZE, 28728c2ecf20Sopenharmony_ci hp->happy_block, 28738c2ecf20Sopenharmony_ci hp->hblock_dvma); 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_cierr_out_iounmap: 28768c2ecf20Sopenharmony_ci if (hp->gregs) 28778c2ecf20Sopenharmony_ci of_iounmap(&op->resource[0], hp->gregs, GREG_REG_SIZE); 28788c2ecf20Sopenharmony_ci if (hp->etxregs) 28798c2ecf20Sopenharmony_ci of_iounmap(&op->resource[1], hp->etxregs, ETX_REG_SIZE); 28808c2ecf20Sopenharmony_ci if (hp->erxregs) 28818c2ecf20Sopenharmony_ci of_iounmap(&op->resource[2], hp->erxregs, ERX_REG_SIZE); 28828c2ecf20Sopenharmony_ci if (hp->bigmacregs) 28838c2ecf20Sopenharmony_ci of_iounmap(&op->resource[3], hp->bigmacregs, BMAC_REG_SIZE); 28848c2ecf20Sopenharmony_ci if (hp->tcvregs) 28858c2ecf20Sopenharmony_ci of_iounmap(&op->resource[4], hp->tcvregs, TCVR_REG_SIZE); 28868c2ecf20Sopenharmony_ci 28878c2ecf20Sopenharmony_ci if (qp) 28888c2ecf20Sopenharmony_ci qp->happy_meals[qfe_slot] = NULL; 28898c2ecf20Sopenharmony_ci 28908c2ecf20Sopenharmony_cierr_out_free_netdev: 28918c2ecf20Sopenharmony_ci free_netdev(dev); 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_cierr_out: 28948c2ecf20Sopenharmony_ci return err; 28958c2ecf20Sopenharmony_ci} 28968c2ecf20Sopenharmony_ci#endif 28978c2ecf20Sopenharmony_ci 28988c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 28998c2ecf20Sopenharmony_ci#ifndef CONFIG_SPARC 29008c2ecf20Sopenharmony_cistatic int is_quattro_p(struct pci_dev *pdev) 29018c2ecf20Sopenharmony_ci{ 29028c2ecf20Sopenharmony_ci struct pci_dev *busdev = pdev->bus->self; 29038c2ecf20Sopenharmony_ci struct pci_dev *this_pdev; 29048c2ecf20Sopenharmony_ci int n_hmes; 29058c2ecf20Sopenharmony_ci 29068c2ecf20Sopenharmony_ci if (busdev == NULL || 29078c2ecf20Sopenharmony_ci busdev->vendor != PCI_VENDOR_ID_DEC || 29088c2ecf20Sopenharmony_ci busdev->device != PCI_DEVICE_ID_DEC_21153) 29098c2ecf20Sopenharmony_ci return 0; 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci n_hmes = 0; 29128c2ecf20Sopenharmony_ci list_for_each_entry(this_pdev, &pdev->bus->devices, bus_list) { 29138c2ecf20Sopenharmony_ci if (this_pdev->vendor == PCI_VENDOR_ID_SUN && 29148c2ecf20Sopenharmony_ci this_pdev->device == PCI_DEVICE_ID_SUN_HAPPYMEAL) 29158c2ecf20Sopenharmony_ci n_hmes++; 29168c2ecf20Sopenharmony_ci } 29178c2ecf20Sopenharmony_ci 29188c2ecf20Sopenharmony_ci if (n_hmes != 4) 29198c2ecf20Sopenharmony_ci return 0; 29208c2ecf20Sopenharmony_ci 29218c2ecf20Sopenharmony_ci return 1; 29228c2ecf20Sopenharmony_ci} 29238c2ecf20Sopenharmony_ci 29248c2ecf20Sopenharmony_ci/* Fetch MAC address from vital product data of PCI ROM. */ 29258c2ecf20Sopenharmony_cistatic int find_eth_addr_in_vpd(void __iomem *rom_base, int len, int index, unsigned char *dev_addr) 29268c2ecf20Sopenharmony_ci{ 29278c2ecf20Sopenharmony_ci int this_offset; 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_ci for (this_offset = 0x20; this_offset < len; this_offset++) { 29308c2ecf20Sopenharmony_ci void __iomem *p = rom_base + this_offset; 29318c2ecf20Sopenharmony_ci 29328c2ecf20Sopenharmony_ci if (readb(p + 0) != 0x90 || 29338c2ecf20Sopenharmony_ci readb(p + 1) != 0x00 || 29348c2ecf20Sopenharmony_ci readb(p + 2) != 0x09 || 29358c2ecf20Sopenharmony_ci readb(p + 3) != 0x4e || 29368c2ecf20Sopenharmony_ci readb(p + 4) != 0x41 || 29378c2ecf20Sopenharmony_ci readb(p + 5) != 0x06) 29388c2ecf20Sopenharmony_ci continue; 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ci this_offset += 6; 29418c2ecf20Sopenharmony_ci p += 6; 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_ci if (index == 0) { 29448c2ecf20Sopenharmony_ci int i; 29458c2ecf20Sopenharmony_ci 29468c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) 29478c2ecf20Sopenharmony_ci dev_addr[i] = readb(p + i); 29488c2ecf20Sopenharmony_ci return 1; 29498c2ecf20Sopenharmony_ci } 29508c2ecf20Sopenharmony_ci index--; 29518c2ecf20Sopenharmony_ci } 29528c2ecf20Sopenharmony_ci return 0; 29538c2ecf20Sopenharmony_ci} 29548c2ecf20Sopenharmony_ci 29558c2ecf20Sopenharmony_cistatic void get_hme_mac_nonsparc(struct pci_dev *pdev, unsigned char *dev_addr) 29568c2ecf20Sopenharmony_ci{ 29578c2ecf20Sopenharmony_ci size_t size; 29588c2ecf20Sopenharmony_ci void __iomem *p = pci_map_rom(pdev, &size); 29598c2ecf20Sopenharmony_ci 29608c2ecf20Sopenharmony_ci if (p) { 29618c2ecf20Sopenharmony_ci int index = 0; 29628c2ecf20Sopenharmony_ci int found; 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_ci if (is_quattro_p(pdev)) 29658c2ecf20Sopenharmony_ci index = PCI_SLOT(pdev->devfn); 29668c2ecf20Sopenharmony_ci 29678c2ecf20Sopenharmony_ci found = readb(p) == 0x55 && 29688c2ecf20Sopenharmony_ci readb(p + 1) == 0xaa && 29698c2ecf20Sopenharmony_ci find_eth_addr_in_vpd(p, (64 * 1024), index, dev_addr); 29708c2ecf20Sopenharmony_ci pci_unmap_rom(pdev, p); 29718c2ecf20Sopenharmony_ci if (found) 29728c2ecf20Sopenharmony_ci return; 29738c2ecf20Sopenharmony_ci } 29748c2ecf20Sopenharmony_ci 29758c2ecf20Sopenharmony_ci /* Sun MAC prefix then 3 random bytes. */ 29768c2ecf20Sopenharmony_ci dev_addr[0] = 0x08; 29778c2ecf20Sopenharmony_ci dev_addr[1] = 0x00; 29788c2ecf20Sopenharmony_ci dev_addr[2] = 0x20; 29798c2ecf20Sopenharmony_ci get_random_bytes(&dev_addr[3], 3); 29808c2ecf20Sopenharmony_ci} 29818c2ecf20Sopenharmony_ci#endif /* !(CONFIG_SPARC) */ 29828c2ecf20Sopenharmony_ci 29838c2ecf20Sopenharmony_cistatic int happy_meal_pci_probe(struct pci_dev *pdev, 29848c2ecf20Sopenharmony_ci const struct pci_device_id *ent) 29858c2ecf20Sopenharmony_ci{ 29868c2ecf20Sopenharmony_ci struct quattro *qp = NULL; 29878c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARC 29888c2ecf20Sopenharmony_ci struct device_node *dp; 29898c2ecf20Sopenharmony_ci#endif 29908c2ecf20Sopenharmony_ci struct happy_meal *hp; 29918c2ecf20Sopenharmony_ci struct net_device *dev; 29928c2ecf20Sopenharmony_ci void __iomem *hpreg_base; 29938c2ecf20Sopenharmony_ci unsigned long hpreg_res; 29948c2ecf20Sopenharmony_ci int i, qfe_slot = -1; 29958c2ecf20Sopenharmony_ci char prom_name[64]; 29968c2ecf20Sopenharmony_ci int err; 29978c2ecf20Sopenharmony_ci 29988c2ecf20Sopenharmony_ci /* Now make sure pci_dev cookie is there. */ 29998c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARC 30008c2ecf20Sopenharmony_ci dp = pci_device_to_OF_node(pdev); 30018c2ecf20Sopenharmony_ci snprintf(prom_name, sizeof(prom_name), "%pOFn", dp); 30028c2ecf20Sopenharmony_ci#else 30038c2ecf20Sopenharmony_ci if (is_quattro_p(pdev)) 30048c2ecf20Sopenharmony_ci strcpy(prom_name, "SUNW,qfe"); 30058c2ecf20Sopenharmony_ci else 30068c2ecf20Sopenharmony_ci strcpy(prom_name, "SUNW,hme"); 30078c2ecf20Sopenharmony_ci#endif 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci err = -ENODEV; 30108c2ecf20Sopenharmony_ci 30118c2ecf20Sopenharmony_ci if (pci_enable_device(pdev)) 30128c2ecf20Sopenharmony_ci goto err_out; 30138c2ecf20Sopenharmony_ci pci_set_master(pdev); 30148c2ecf20Sopenharmony_ci 30158c2ecf20Sopenharmony_ci if (!strcmp(prom_name, "SUNW,qfe") || !strcmp(prom_name, "qfe")) { 30168c2ecf20Sopenharmony_ci qp = quattro_pci_find(pdev); 30178c2ecf20Sopenharmony_ci if (qp == NULL) 30188c2ecf20Sopenharmony_ci goto err_out; 30198c2ecf20Sopenharmony_ci for (qfe_slot = 0; qfe_slot < 4; qfe_slot++) 30208c2ecf20Sopenharmony_ci if (qp->happy_meals[qfe_slot] == NULL) 30218c2ecf20Sopenharmony_ci break; 30228c2ecf20Sopenharmony_ci if (qfe_slot == 4) 30238c2ecf20Sopenharmony_ci goto err_out; 30248c2ecf20Sopenharmony_ci } 30258c2ecf20Sopenharmony_ci 30268c2ecf20Sopenharmony_ci dev = alloc_etherdev(sizeof(struct happy_meal)); 30278c2ecf20Sopenharmony_ci err = -ENOMEM; 30288c2ecf20Sopenharmony_ci if (!dev) 30298c2ecf20Sopenharmony_ci goto err_out; 30308c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, &pdev->dev); 30318c2ecf20Sopenharmony_ci 30328c2ecf20Sopenharmony_ci if (hme_version_printed++ == 0) 30338c2ecf20Sopenharmony_ci printk(KERN_INFO "%s", version); 30348c2ecf20Sopenharmony_ci 30358c2ecf20Sopenharmony_ci hp = netdev_priv(dev); 30368c2ecf20Sopenharmony_ci 30378c2ecf20Sopenharmony_ci hp->happy_dev = pdev; 30388c2ecf20Sopenharmony_ci hp->dma_dev = &pdev->dev; 30398c2ecf20Sopenharmony_ci 30408c2ecf20Sopenharmony_ci spin_lock_init(&hp->happy_lock); 30418c2ecf20Sopenharmony_ci 30428c2ecf20Sopenharmony_ci if (qp != NULL) { 30438c2ecf20Sopenharmony_ci hp->qfe_parent = qp; 30448c2ecf20Sopenharmony_ci hp->qfe_ent = qfe_slot; 30458c2ecf20Sopenharmony_ci qp->happy_meals[qfe_slot] = dev; 30468c2ecf20Sopenharmony_ci } 30478c2ecf20Sopenharmony_ci 30488c2ecf20Sopenharmony_ci hpreg_res = pci_resource_start(pdev, 0); 30498c2ecf20Sopenharmony_ci err = -ENODEV; 30508c2ecf20Sopenharmony_ci if ((pci_resource_flags(pdev, 0) & IORESOURCE_IO) != 0) { 30518c2ecf20Sopenharmony_ci printk(KERN_ERR "happymeal(PCI): Cannot find proper PCI device base address.\n"); 30528c2ecf20Sopenharmony_ci goto err_out_clear_quattro; 30538c2ecf20Sopenharmony_ci } 30548c2ecf20Sopenharmony_ci if (pci_request_regions(pdev, DRV_NAME)) { 30558c2ecf20Sopenharmony_ci printk(KERN_ERR "happymeal(PCI): Cannot obtain PCI resources, " 30568c2ecf20Sopenharmony_ci "aborting.\n"); 30578c2ecf20Sopenharmony_ci goto err_out_clear_quattro; 30588c2ecf20Sopenharmony_ci } 30598c2ecf20Sopenharmony_ci 30608c2ecf20Sopenharmony_ci if ((hpreg_base = ioremap(hpreg_res, 0x8000)) == NULL) { 30618c2ecf20Sopenharmony_ci printk(KERN_ERR "happymeal(PCI): Unable to remap card memory.\n"); 30628c2ecf20Sopenharmony_ci goto err_out_free_res; 30638c2ecf20Sopenharmony_ci } 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) { 30668c2ecf20Sopenharmony_ci if (macaddr[i] != 0) 30678c2ecf20Sopenharmony_ci break; 30688c2ecf20Sopenharmony_ci } 30698c2ecf20Sopenharmony_ci if (i < 6) { /* a mac address was given */ 30708c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) 30718c2ecf20Sopenharmony_ci dev->dev_addr[i] = macaddr[i]; 30728c2ecf20Sopenharmony_ci macaddr[5]++; 30738c2ecf20Sopenharmony_ci } else { 30748c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARC 30758c2ecf20Sopenharmony_ci const unsigned char *addr; 30768c2ecf20Sopenharmony_ci int len; 30778c2ecf20Sopenharmony_ci 30788c2ecf20Sopenharmony_ci if (qfe_slot != -1 && 30798c2ecf20Sopenharmony_ci (addr = of_get_property(dp, "local-mac-address", &len)) 30808c2ecf20Sopenharmony_ci != NULL && 30818c2ecf20Sopenharmony_ci len == 6) { 30828c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, addr, ETH_ALEN); 30838c2ecf20Sopenharmony_ci } else { 30848c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, idprom->id_ethaddr, ETH_ALEN); 30858c2ecf20Sopenharmony_ci } 30868c2ecf20Sopenharmony_ci#else 30878c2ecf20Sopenharmony_ci get_hme_mac_nonsparc(pdev, &dev->dev_addr[0]); 30888c2ecf20Sopenharmony_ci#endif 30898c2ecf20Sopenharmony_ci } 30908c2ecf20Sopenharmony_ci 30918c2ecf20Sopenharmony_ci /* Layout registers. */ 30928c2ecf20Sopenharmony_ci hp->gregs = (hpreg_base + 0x0000UL); 30938c2ecf20Sopenharmony_ci hp->etxregs = (hpreg_base + 0x2000UL); 30948c2ecf20Sopenharmony_ci hp->erxregs = (hpreg_base + 0x4000UL); 30958c2ecf20Sopenharmony_ci hp->bigmacregs = (hpreg_base + 0x6000UL); 30968c2ecf20Sopenharmony_ci hp->tcvregs = (hpreg_base + 0x7000UL); 30978c2ecf20Sopenharmony_ci 30988c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARC 30998c2ecf20Sopenharmony_ci hp->hm_revision = of_getintprop_default(dp, "hm-rev", 0xff); 31008c2ecf20Sopenharmony_ci if (hp->hm_revision == 0xff) 31018c2ecf20Sopenharmony_ci hp->hm_revision = 0xc0 | (pdev->revision & 0x0f); 31028c2ecf20Sopenharmony_ci#else 31038c2ecf20Sopenharmony_ci /* works with this on non-sparc hosts */ 31048c2ecf20Sopenharmony_ci hp->hm_revision = 0x20; 31058c2ecf20Sopenharmony_ci#endif 31068c2ecf20Sopenharmony_ci 31078c2ecf20Sopenharmony_ci /* Now enable the feature flags we can. */ 31088c2ecf20Sopenharmony_ci if (hp->hm_revision == 0x20 || hp->hm_revision == 0x21) 31098c2ecf20Sopenharmony_ci hp->happy_flags = HFLAG_20_21; 31108c2ecf20Sopenharmony_ci else if (hp->hm_revision != 0xa0 && hp->hm_revision != 0xc0) 31118c2ecf20Sopenharmony_ci hp->happy_flags = HFLAG_NOT_A0; 31128c2ecf20Sopenharmony_ci 31138c2ecf20Sopenharmony_ci if (qp != NULL) 31148c2ecf20Sopenharmony_ci hp->happy_flags |= HFLAG_QUATTRO; 31158c2ecf20Sopenharmony_ci 31168c2ecf20Sopenharmony_ci /* And of course, indicate this is PCI. */ 31178c2ecf20Sopenharmony_ci hp->happy_flags |= HFLAG_PCI; 31188c2ecf20Sopenharmony_ci 31198c2ecf20Sopenharmony_ci#ifdef CONFIG_SPARC 31208c2ecf20Sopenharmony_ci /* Assume PCI happy meals can handle all burst sizes. */ 31218c2ecf20Sopenharmony_ci hp->happy_bursts = DMA_BURSTBITS; 31228c2ecf20Sopenharmony_ci#endif 31238c2ecf20Sopenharmony_ci 31248c2ecf20Sopenharmony_ci hp->happy_block = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, 31258c2ecf20Sopenharmony_ci &hp->hblock_dvma, GFP_KERNEL); 31268c2ecf20Sopenharmony_ci err = -ENODEV; 31278c2ecf20Sopenharmony_ci if (!hp->happy_block) 31288c2ecf20Sopenharmony_ci goto err_out_iounmap; 31298c2ecf20Sopenharmony_ci 31308c2ecf20Sopenharmony_ci hp->linkcheck = 0; 31318c2ecf20Sopenharmony_ci hp->timer_state = asleep; 31328c2ecf20Sopenharmony_ci hp->timer_ticks = 0; 31338c2ecf20Sopenharmony_ci 31348c2ecf20Sopenharmony_ci timer_setup(&hp->happy_timer, happy_meal_timer, 0); 31358c2ecf20Sopenharmony_ci 31368c2ecf20Sopenharmony_ci hp->irq = pdev->irq; 31378c2ecf20Sopenharmony_ci hp->dev = dev; 31388c2ecf20Sopenharmony_ci dev->netdev_ops = &hme_netdev_ops; 31398c2ecf20Sopenharmony_ci dev->watchdog_timeo = 5*HZ; 31408c2ecf20Sopenharmony_ci dev->ethtool_ops = &hme_ethtool_ops; 31418c2ecf20Sopenharmony_ci 31428c2ecf20Sopenharmony_ci /* Happy Meal can do it all... */ 31438c2ecf20Sopenharmony_ci dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; 31448c2ecf20Sopenharmony_ci dev->features |= dev->hw_features | NETIF_F_RXCSUM; 31458c2ecf20Sopenharmony_ci 31468c2ecf20Sopenharmony_ci#if defined(CONFIG_SBUS) && defined(CONFIG_PCI) 31478c2ecf20Sopenharmony_ci /* Hook up PCI register/descriptor accessors. */ 31488c2ecf20Sopenharmony_ci hp->read_desc32 = pci_hme_read_desc32; 31498c2ecf20Sopenharmony_ci hp->write_txd = pci_hme_write_txd; 31508c2ecf20Sopenharmony_ci hp->write_rxd = pci_hme_write_rxd; 31518c2ecf20Sopenharmony_ci hp->read32 = pci_hme_read32; 31528c2ecf20Sopenharmony_ci hp->write32 = pci_hme_write32; 31538c2ecf20Sopenharmony_ci#endif 31548c2ecf20Sopenharmony_ci 31558c2ecf20Sopenharmony_ci /* Grrr, Happy Meal comes up by default not advertising 31568c2ecf20Sopenharmony_ci * full duplex 100baseT capabilities, fix this. 31578c2ecf20Sopenharmony_ci */ 31588c2ecf20Sopenharmony_ci spin_lock_irq(&hp->happy_lock); 31598c2ecf20Sopenharmony_ci happy_meal_set_initial_advertisement(hp); 31608c2ecf20Sopenharmony_ci spin_unlock_irq(&hp->happy_lock); 31618c2ecf20Sopenharmony_ci 31628c2ecf20Sopenharmony_ci err = register_netdev(hp->dev); 31638c2ecf20Sopenharmony_ci if (err) { 31648c2ecf20Sopenharmony_ci printk(KERN_ERR "happymeal(PCI): Cannot register net device, " 31658c2ecf20Sopenharmony_ci "aborting.\n"); 31668c2ecf20Sopenharmony_ci goto err_out_free_coherent; 31678c2ecf20Sopenharmony_ci } 31688c2ecf20Sopenharmony_ci 31698c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, hp); 31708c2ecf20Sopenharmony_ci 31718c2ecf20Sopenharmony_ci if (!qfe_slot) { 31728c2ecf20Sopenharmony_ci struct pci_dev *qpdev = qp->quattro_dev; 31738c2ecf20Sopenharmony_ci 31748c2ecf20Sopenharmony_ci prom_name[0] = 0; 31758c2ecf20Sopenharmony_ci if (!strncmp(dev->name, "eth", 3)) { 31768c2ecf20Sopenharmony_ci int i = simple_strtoul(dev->name + 3, NULL, 10); 31778c2ecf20Sopenharmony_ci sprintf(prom_name, "-%d", i + 3); 31788c2ecf20Sopenharmony_ci } 31798c2ecf20Sopenharmony_ci printk(KERN_INFO "%s%s: Quattro HME (PCI/CheerIO) 10/100baseT Ethernet ", dev->name, prom_name); 31808c2ecf20Sopenharmony_ci if (qpdev->vendor == PCI_VENDOR_ID_DEC && 31818c2ecf20Sopenharmony_ci qpdev->device == PCI_DEVICE_ID_DEC_21153) 31828c2ecf20Sopenharmony_ci printk("DEC 21153 PCI Bridge\n"); 31838c2ecf20Sopenharmony_ci else 31848c2ecf20Sopenharmony_ci printk("unknown bridge %04x.%04x\n", 31858c2ecf20Sopenharmony_ci qpdev->vendor, qpdev->device); 31868c2ecf20Sopenharmony_ci } 31878c2ecf20Sopenharmony_ci 31888c2ecf20Sopenharmony_ci if (qfe_slot != -1) 31898c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: Quattro HME slot %d (PCI/CheerIO) 10/100baseT Ethernet ", 31908c2ecf20Sopenharmony_ci dev->name, qfe_slot); 31918c2ecf20Sopenharmony_ci else 31928c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ", 31938c2ecf20Sopenharmony_ci dev->name); 31948c2ecf20Sopenharmony_ci 31958c2ecf20Sopenharmony_ci printk("%pM\n", dev->dev_addr); 31968c2ecf20Sopenharmony_ci 31978c2ecf20Sopenharmony_ci return 0; 31988c2ecf20Sopenharmony_ci 31998c2ecf20Sopenharmony_cierr_out_free_coherent: 32008c2ecf20Sopenharmony_ci dma_free_coherent(hp->dma_dev, PAGE_SIZE, 32018c2ecf20Sopenharmony_ci hp->happy_block, hp->hblock_dvma); 32028c2ecf20Sopenharmony_ci 32038c2ecf20Sopenharmony_cierr_out_iounmap: 32048c2ecf20Sopenharmony_ci iounmap(hp->gregs); 32058c2ecf20Sopenharmony_ci 32068c2ecf20Sopenharmony_cierr_out_free_res: 32078c2ecf20Sopenharmony_ci pci_release_regions(pdev); 32088c2ecf20Sopenharmony_ci 32098c2ecf20Sopenharmony_cierr_out_clear_quattro: 32108c2ecf20Sopenharmony_ci if (qp != NULL) 32118c2ecf20Sopenharmony_ci qp->happy_meals[qfe_slot] = NULL; 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_ci free_netdev(dev); 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_cierr_out: 32168c2ecf20Sopenharmony_ci return err; 32178c2ecf20Sopenharmony_ci} 32188c2ecf20Sopenharmony_ci 32198c2ecf20Sopenharmony_cistatic void happy_meal_pci_remove(struct pci_dev *pdev) 32208c2ecf20Sopenharmony_ci{ 32218c2ecf20Sopenharmony_ci struct happy_meal *hp = pci_get_drvdata(pdev); 32228c2ecf20Sopenharmony_ci struct net_device *net_dev = hp->dev; 32238c2ecf20Sopenharmony_ci 32248c2ecf20Sopenharmony_ci unregister_netdev(net_dev); 32258c2ecf20Sopenharmony_ci 32268c2ecf20Sopenharmony_ci dma_free_coherent(hp->dma_dev, PAGE_SIZE, 32278c2ecf20Sopenharmony_ci hp->happy_block, hp->hblock_dvma); 32288c2ecf20Sopenharmony_ci iounmap(hp->gregs); 32298c2ecf20Sopenharmony_ci pci_release_regions(hp->happy_dev); 32308c2ecf20Sopenharmony_ci 32318c2ecf20Sopenharmony_ci free_netdev(net_dev); 32328c2ecf20Sopenharmony_ci} 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_cistatic const struct pci_device_id happymeal_pci_ids[] = { 32358c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_HAPPYMEAL) }, 32368c2ecf20Sopenharmony_ci { } /* Terminating entry */ 32378c2ecf20Sopenharmony_ci}; 32388c2ecf20Sopenharmony_ci 32398c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, happymeal_pci_ids); 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_cistatic struct pci_driver hme_pci_driver = { 32428c2ecf20Sopenharmony_ci .name = "hme", 32438c2ecf20Sopenharmony_ci .id_table = happymeal_pci_ids, 32448c2ecf20Sopenharmony_ci .probe = happy_meal_pci_probe, 32458c2ecf20Sopenharmony_ci .remove = happy_meal_pci_remove, 32468c2ecf20Sopenharmony_ci}; 32478c2ecf20Sopenharmony_ci 32488c2ecf20Sopenharmony_cistatic int __init happy_meal_pci_init(void) 32498c2ecf20Sopenharmony_ci{ 32508c2ecf20Sopenharmony_ci return pci_register_driver(&hme_pci_driver); 32518c2ecf20Sopenharmony_ci} 32528c2ecf20Sopenharmony_ci 32538c2ecf20Sopenharmony_cistatic void happy_meal_pci_exit(void) 32548c2ecf20Sopenharmony_ci{ 32558c2ecf20Sopenharmony_ci pci_unregister_driver(&hme_pci_driver); 32568c2ecf20Sopenharmony_ci 32578c2ecf20Sopenharmony_ci while (qfe_pci_list) { 32588c2ecf20Sopenharmony_ci struct quattro *qfe = qfe_pci_list; 32598c2ecf20Sopenharmony_ci struct quattro *next = qfe->next; 32608c2ecf20Sopenharmony_ci 32618c2ecf20Sopenharmony_ci kfree(qfe); 32628c2ecf20Sopenharmony_ci 32638c2ecf20Sopenharmony_ci qfe_pci_list = next; 32648c2ecf20Sopenharmony_ci } 32658c2ecf20Sopenharmony_ci} 32668c2ecf20Sopenharmony_ci 32678c2ecf20Sopenharmony_ci#endif 32688c2ecf20Sopenharmony_ci 32698c2ecf20Sopenharmony_ci#ifdef CONFIG_SBUS 32708c2ecf20Sopenharmony_cistatic const struct of_device_id hme_sbus_match[]; 32718c2ecf20Sopenharmony_cistatic int hme_sbus_probe(struct platform_device *op) 32728c2ecf20Sopenharmony_ci{ 32738c2ecf20Sopenharmony_ci const struct of_device_id *match; 32748c2ecf20Sopenharmony_ci struct device_node *dp = op->dev.of_node; 32758c2ecf20Sopenharmony_ci const char *model = of_get_property(dp, "model", NULL); 32768c2ecf20Sopenharmony_ci int is_qfe; 32778c2ecf20Sopenharmony_ci 32788c2ecf20Sopenharmony_ci match = of_match_device(hme_sbus_match, &op->dev); 32798c2ecf20Sopenharmony_ci if (!match) 32808c2ecf20Sopenharmony_ci return -EINVAL; 32818c2ecf20Sopenharmony_ci is_qfe = (match->data != NULL); 32828c2ecf20Sopenharmony_ci 32838c2ecf20Sopenharmony_ci if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe")) 32848c2ecf20Sopenharmony_ci is_qfe = 1; 32858c2ecf20Sopenharmony_ci 32868c2ecf20Sopenharmony_ci return happy_meal_sbus_probe_one(op, is_qfe); 32878c2ecf20Sopenharmony_ci} 32888c2ecf20Sopenharmony_ci 32898c2ecf20Sopenharmony_cistatic int hme_sbus_remove(struct platform_device *op) 32908c2ecf20Sopenharmony_ci{ 32918c2ecf20Sopenharmony_ci struct happy_meal *hp = platform_get_drvdata(op); 32928c2ecf20Sopenharmony_ci struct net_device *net_dev = hp->dev; 32938c2ecf20Sopenharmony_ci 32948c2ecf20Sopenharmony_ci unregister_netdev(net_dev); 32958c2ecf20Sopenharmony_ci 32968c2ecf20Sopenharmony_ci /* XXX qfe parent interrupt... */ 32978c2ecf20Sopenharmony_ci 32988c2ecf20Sopenharmony_ci of_iounmap(&op->resource[0], hp->gregs, GREG_REG_SIZE); 32998c2ecf20Sopenharmony_ci of_iounmap(&op->resource[1], hp->etxregs, ETX_REG_SIZE); 33008c2ecf20Sopenharmony_ci of_iounmap(&op->resource[2], hp->erxregs, ERX_REG_SIZE); 33018c2ecf20Sopenharmony_ci of_iounmap(&op->resource[3], hp->bigmacregs, BMAC_REG_SIZE); 33028c2ecf20Sopenharmony_ci of_iounmap(&op->resource[4], hp->tcvregs, TCVR_REG_SIZE); 33038c2ecf20Sopenharmony_ci dma_free_coherent(hp->dma_dev, 33048c2ecf20Sopenharmony_ci PAGE_SIZE, 33058c2ecf20Sopenharmony_ci hp->happy_block, 33068c2ecf20Sopenharmony_ci hp->hblock_dvma); 33078c2ecf20Sopenharmony_ci 33088c2ecf20Sopenharmony_ci free_netdev(net_dev); 33098c2ecf20Sopenharmony_ci 33108c2ecf20Sopenharmony_ci return 0; 33118c2ecf20Sopenharmony_ci} 33128c2ecf20Sopenharmony_ci 33138c2ecf20Sopenharmony_cistatic const struct of_device_id hme_sbus_match[] = { 33148c2ecf20Sopenharmony_ci { 33158c2ecf20Sopenharmony_ci .name = "SUNW,hme", 33168c2ecf20Sopenharmony_ci }, 33178c2ecf20Sopenharmony_ci { 33188c2ecf20Sopenharmony_ci .name = "SUNW,qfe", 33198c2ecf20Sopenharmony_ci .data = (void *) 1, 33208c2ecf20Sopenharmony_ci }, 33218c2ecf20Sopenharmony_ci { 33228c2ecf20Sopenharmony_ci .name = "qfe", 33238c2ecf20Sopenharmony_ci .data = (void *) 1, 33248c2ecf20Sopenharmony_ci }, 33258c2ecf20Sopenharmony_ci {}, 33268c2ecf20Sopenharmony_ci}; 33278c2ecf20Sopenharmony_ci 33288c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, hme_sbus_match); 33298c2ecf20Sopenharmony_ci 33308c2ecf20Sopenharmony_cistatic struct platform_driver hme_sbus_driver = { 33318c2ecf20Sopenharmony_ci .driver = { 33328c2ecf20Sopenharmony_ci .name = "hme", 33338c2ecf20Sopenharmony_ci .of_match_table = hme_sbus_match, 33348c2ecf20Sopenharmony_ci }, 33358c2ecf20Sopenharmony_ci .probe = hme_sbus_probe, 33368c2ecf20Sopenharmony_ci .remove = hme_sbus_remove, 33378c2ecf20Sopenharmony_ci}; 33388c2ecf20Sopenharmony_ci 33398c2ecf20Sopenharmony_cistatic int __init happy_meal_sbus_init(void) 33408c2ecf20Sopenharmony_ci{ 33418c2ecf20Sopenharmony_ci int err; 33428c2ecf20Sopenharmony_ci 33438c2ecf20Sopenharmony_ci err = platform_driver_register(&hme_sbus_driver); 33448c2ecf20Sopenharmony_ci if (!err) 33458c2ecf20Sopenharmony_ci err = quattro_sbus_register_irqs(); 33468c2ecf20Sopenharmony_ci 33478c2ecf20Sopenharmony_ci return err; 33488c2ecf20Sopenharmony_ci} 33498c2ecf20Sopenharmony_ci 33508c2ecf20Sopenharmony_cistatic void happy_meal_sbus_exit(void) 33518c2ecf20Sopenharmony_ci{ 33528c2ecf20Sopenharmony_ci platform_driver_unregister(&hme_sbus_driver); 33538c2ecf20Sopenharmony_ci quattro_sbus_free_irqs(); 33548c2ecf20Sopenharmony_ci 33558c2ecf20Sopenharmony_ci while (qfe_sbus_list) { 33568c2ecf20Sopenharmony_ci struct quattro *qfe = qfe_sbus_list; 33578c2ecf20Sopenharmony_ci struct quattro *next = qfe->next; 33588c2ecf20Sopenharmony_ci 33598c2ecf20Sopenharmony_ci kfree(qfe); 33608c2ecf20Sopenharmony_ci 33618c2ecf20Sopenharmony_ci qfe_sbus_list = next; 33628c2ecf20Sopenharmony_ci } 33638c2ecf20Sopenharmony_ci} 33648c2ecf20Sopenharmony_ci#endif 33658c2ecf20Sopenharmony_ci 33668c2ecf20Sopenharmony_cistatic int __init happy_meal_probe(void) 33678c2ecf20Sopenharmony_ci{ 33688c2ecf20Sopenharmony_ci int err = 0; 33698c2ecf20Sopenharmony_ci 33708c2ecf20Sopenharmony_ci#ifdef CONFIG_SBUS 33718c2ecf20Sopenharmony_ci err = happy_meal_sbus_init(); 33728c2ecf20Sopenharmony_ci#endif 33738c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 33748c2ecf20Sopenharmony_ci if (!err) { 33758c2ecf20Sopenharmony_ci err = happy_meal_pci_init(); 33768c2ecf20Sopenharmony_ci#ifdef CONFIG_SBUS 33778c2ecf20Sopenharmony_ci if (err) 33788c2ecf20Sopenharmony_ci happy_meal_sbus_exit(); 33798c2ecf20Sopenharmony_ci#endif 33808c2ecf20Sopenharmony_ci } 33818c2ecf20Sopenharmony_ci#endif 33828c2ecf20Sopenharmony_ci 33838c2ecf20Sopenharmony_ci return err; 33848c2ecf20Sopenharmony_ci} 33858c2ecf20Sopenharmony_ci 33868c2ecf20Sopenharmony_ci 33878c2ecf20Sopenharmony_cistatic void __exit happy_meal_exit(void) 33888c2ecf20Sopenharmony_ci{ 33898c2ecf20Sopenharmony_ci#ifdef CONFIG_SBUS 33908c2ecf20Sopenharmony_ci happy_meal_sbus_exit(); 33918c2ecf20Sopenharmony_ci#endif 33928c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 33938c2ecf20Sopenharmony_ci happy_meal_pci_exit(); 33948c2ecf20Sopenharmony_ci#endif 33958c2ecf20Sopenharmony_ci} 33968c2ecf20Sopenharmony_ci 33978c2ecf20Sopenharmony_cimodule_init(happy_meal_probe); 33988c2ecf20Sopenharmony_cimodule_exit(happy_meal_exit); 3399