18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Network device driver for the BMAC ethernet controller on 48c2ecf20Sopenharmony_ci * Apple Powermacs. Assumes it's under a DBDMA controller. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 1998 Randy Gobbel. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * May 1999, Al Viro: proper release of /proc/net/bmac entry, switched to 98c2ecf20Sopenharmony_ci * dynamic procfs inode. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 158c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 168c2ecf20Sopenharmony_ci#include <linux/delay.h> 178c2ecf20Sopenharmony_ci#include <linux/string.h> 188c2ecf20Sopenharmony_ci#include <linux/timer.h> 198c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 208c2ecf20Sopenharmony_ci#include <linux/init.h> 218c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 228c2ecf20Sopenharmony_ci#include <linux/crc32.h> 238c2ecf20Sopenharmony_ci#include <linux/crc32poly.h> 248c2ecf20Sopenharmony_ci#include <linux/bitrev.h> 258c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 268c2ecf20Sopenharmony_ci#include <linux/slab.h> 278c2ecf20Sopenharmony_ci#include <linux/pgtable.h> 288c2ecf20Sopenharmony_ci#include <asm/prom.h> 298c2ecf20Sopenharmony_ci#include <asm/dbdma.h> 308c2ecf20Sopenharmony_ci#include <asm/io.h> 318c2ecf20Sopenharmony_ci#include <asm/page.h> 328c2ecf20Sopenharmony_ci#include <asm/machdep.h> 338c2ecf20Sopenharmony_ci#include <asm/pmac_feature.h> 348c2ecf20Sopenharmony_ci#include <asm/macio.h> 358c2ecf20Sopenharmony_ci#include <asm/irq.h> 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include "bmac.h" 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define trunc_page(x) ((void *)(((unsigned long)(x)) & ~((unsigned long)(PAGE_SIZE - 1)))) 408c2ecf20Sopenharmony_ci#define round_page(x) trunc_page(((unsigned long)(x)) + ((unsigned long)(PAGE_SIZE - 1))) 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* switch to use multicast code lifted from sunhme driver */ 438c2ecf20Sopenharmony_ci#define SUNHME_MULTICAST 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define N_RX_RING 64 468c2ecf20Sopenharmony_ci#define N_TX_RING 32 478c2ecf20Sopenharmony_ci#define MAX_TX_ACTIVE 1 488c2ecf20Sopenharmony_ci#define ETHERCRC 4 498c2ecf20Sopenharmony_ci#define ETHERMINPACKET 64 508c2ecf20Sopenharmony_ci#define ETHERMTU 1500 518c2ecf20Sopenharmony_ci#define RX_BUFLEN (ETHERMTU + 14 + ETHERCRC + 2) 528c2ecf20Sopenharmony_ci#define TX_TIMEOUT HZ /* 1 second */ 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* Bits in transmit DMA status */ 558c2ecf20Sopenharmony_ci#define TX_DMA_ERR 0x80 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define XXDEBUG(args) 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistruct bmac_data { 608c2ecf20Sopenharmony_ci /* volatile struct bmac *bmac; */ 618c2ecf20Sopenharmony_ci struct sk_buff_head *queue; 628c2ecf20Sopenharmony_ci volatile struct dbdma_regs __iomem *tx_dma; 638c2ecf20Sopenharmony_ci int tx_dma_intr; 648c2ecf20Sopenharmony_ci volatile struct dbdma_regs __iomem *rx_dma; 658c2ecf20Sopenharmony_ci int rx_dma_intr; 668c2ecf20Sopenharmony_ci volatile struct dbdma_cmd *tx_cmds; /* xmit dma command list */ 678c2ecf20Sopenharmony_ci volatile struct dbdma_cmd *rx_cmds; /* recv dma command list */ 688c2ecf20Sopenharmony_ci struct macio_dev *mdev; 698c2ecf20Sopenharmony_ci int is_bmac_plus; 708c2ecf20Sopenharmony_ci struct sk_buff *rx_bufs[N_RX_RING]; 718c2ecf20Sopenharmony_ci int rx_fill; 728c2ecf20Sopenharmony_ci int rx_empty; 738c2ecf20Sopenharmony_ci struct sk_buff *tx_bufs[N_TX_RING]; 748c2ecf20Sopenharmony_ci int tx_fill; 758c2ecf20Sopenharmony_ci int tx_empty; 768c2ecf20Sopenharmony_ci unsigned char tx_fullup; 778c2ecf20Sopenharmony_ci struct timer_list tx_timeout; 788c2ecf20Sopenharmony_ci int timeout_active; 798c2ecf20Sopenharmony_ci int sleeping; 808c2ecf20Sopenharmony_ci int opened; 818c2ecf20Sopenharmony_ci unsigned short hash_use_count[64]; 828c2ecf20Sopenharmony_ci unsigned short hash_table_mask[4]; 838c2ecf20Sopenharmony_ci spinlock_t lock; 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#if 0 /* Move that to ethtool */ 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_citypedef struct bmac_reg_entry { 898c2ecf20Sopenharmony_ci char *name; 908c2ecf20Sopenharmony_ci unsigned short reg_offset; 918c2ecf20Sopenharmony_ci} bmac_reg_entry_t; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci#define N_REG_ENTRIES 31 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic bmac_reg_entry_t reg_entries[N_REG_ENTRIES] = { 968c2ecf20Sopenharmony_ci {"MEMADD", MEMADD}, 978c2ecf20Sopenharmony_ci {"MEMDATAHI", MEMDATAHI}, 988c2ecf20Sopenharmony_ci {"MEMDATALO", MEMDATALO}, 998c2ecf20Sopenharmony_ci {"TXPNTR", TXPNTR}, 1008c2ecf20Sopenharmony_ci {"RXPNTR", RXPNTR}, 1018c2ecf20Sopenharmony_ci {"IPG1", IPG1}, 1028c2ecf20Sopenharmony_ci {"IPG2", IPG2}, 1038c2ecf20Sopenharmony_ci {"ALIMIT", ALIMIT}, 1048c2ecf20Sopenharmony_ci {"SLOT", SLOT}, 1058c2ecf20Sopenharmony_ci {"PALEN", PALEN}, 1068c2ecf20Sopenharmony_ci {"PAPAT", PAPAT}, 1078c2ecf20Sopenharmony_ci {"TXSFD", TXSFD}, 1088c2ecf20Sopenharmony_ci {"JAM", JAM}, 1098c2ecf20Sopenharmony_ci {"TXCFG", TXCFG}, 1108c2ecf20Sopenharmony_ci {"TXMAX", TXMAX}, 1118c2ecf20Sopenharmony_ci {"TXMIN", TXMIN}, 1128c2ecf20Sopenharmony_ci {"PAREG", PAREG}, 1138c2ecf20Sopenharmony_ci {"DCNT", DCNT}, 1148c2ecf20Sopenharmony_ci {"NCCNT", NCCNT}, 1158c2ecf20Sopenharmony_ci {"NTCNT", NTCNT}, 1168c2ecf20Sopenharmony_ci {"EXCNT", EXCNT}, 1178c2ecf20Sopenharmony_ci {"LTCNT", LTCNT}, 1188c2ecf20Sopenharmony_ci {"TXSM", TXSM}, 1198c2ecf20Sopenharmony_ci {"RXCFG", RXCFG}, 1208c2ecf20Sopenharmony_ci {"RXMAX", RXMAX}, 1218c2ecf20Sopenharmony_ci {"RXMIN", RXMIN}, 1228c2ecf20Sopenharmony_ci {"FRCNT", FRCNT}, 1238c2ecf20Sopenharmony_ci {"AECNT", AECNT}, 1248c2ecf20Sopenharmony_ci {"FECNT", FECNT}, 1258c2ecf20Sopenharmony_ci {"RXSM", RXSM}, 1268c2ecf20Sopenharmony_ci {"RXCV", RXCV} 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci#endif 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic unsigned char *bmac_emergency_rxbuf; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* 1348c2ecf20Sopenharmony_ci * Number of bytes of private data per BMAC: allow enough for 1358c2ecf20Sopenharmony_ci * the rx and tx dma commands plus a branch dma command each, 1368c2ecf20Sopenharmony_ci * and another 16 bytes to allow us to align the dma command 1378c2ecf20Sopenharmony_ci * buffers on a 16 byte boundary. 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_ci#define PRIV_BYTES (sizeof(struct bmac_data) \ 1408c2ecf20Sopenharmony_ci + (N_RX_RING + N_TX_RING + 4) * sizeof(struct dbdma_cmd) \ 1418c2ecf20Sopenharmony_ci + sizeof(struct sk_buff_head)) 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic int bmac_open(struct net_device *dev); 1448c2ecf20Sopenharmony_cistatic int bmac_close(struct net_device *dev); 1458c2ecf20Sopenharmony_cistatic int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev); 1468c2ecf20Sopenharmony_cistatic void bmac_set_multicast(struct net_device *dev); 1478c2ecf20Sopenharmony_cistatic void bmac_reset_and_enable(struct net_device *dev); 1488c2ecf20Sopenharmony_cistatic void bmac_start_chip(struct net_device *dev); 1498c2ecf20Sopenharmony_cistatic void bmac_init_chip(struct net_device *dev); 1508c2ecf20Sopenharmony_cistatic void bmac_init_registers(struct net_device *dev); 1518c2ecf20Sopenharmony_cistatic void bmac_enable_and_reset_chip(struct net_device *dev); 1528c2ecf20Sopenharmony_cistatic int bmac_set_address(struct net_device *dev, void *addr); 1538c2ecf20Sopenharmony_cistatic irqreturn_t bmac_misc_intr(int irq, void *dev_id); 1548c2ecf20Sopenharmony_cistatic irqreturn_t bmac_txdma_intr(int irq, void *dev_id); 1558c2ecf20Sopenharmony_cistatic irqreturn_t bmac_rxdma_intr(int irq, void *dev_id); 1568c2ecf20Sopenharmony_cistatic void bmac_set_timeout(struct net_device *dev); 1578c2ecf20Sopenharmony_cistatic void bmac_tx_timeout(struct timer_list *t); 1588c2ecf20Sopenharmony_cistatic netdev_tx_t bmac_output(struct sk_buff *skb, struct net_device *dev); 1598c2ecf20Sopenharmony_cistatic void bmac_start(struct net_device *dev); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci#define DBDMA_SET(x) ( ((x) | (x) << 16) ) 1628c2ecf20Sopenharmony_ci#define DBDMA_CLEAR(x) ( (x) << 16) 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic inline void 1658c2ecf20Sopenharmony_cidbdma_st32(volatile __u32 __iomem *a, unsigned long x) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci __asm__ volatile( "stwbrx %0,0,%1" : : "r" (x), "r" (a) : "memory"); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic inline unsigned long 1718c2ecf20Sopenharmony_cidbdma_ld32(volatile __u32 __iomem *a) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci __u32 swap; 1748c2ecf20Sopenharmony_ci __asm__ volatile ("lwbrx %0,0,%1" : "=r" (swap) : "r" (a)); 1758c2ecf20Sopenharmony_ci return swap; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic void 1798c2ecf20Sopenharmony_cidbdma_continue(volatile struct dbdma_regs __iomem *dmap) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci dbdma_st32(&dmap->control, 1828c2ecf20Sopenharmony_ci DBDMA_SET(RUN|WAKE) | DBDMA_CLEAR(PAUSE|DEAD)); 1838c2ecf20Sopenharmony_ci eieio(); 1848c2ecf20Sopenharmony_ci} 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_cistatic void 1878c2ecf20Sopenharmony_cidbdma_reset(volatile struct dbdma_regs __iomem *dmap) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci dbdma_st32(&dmap->control, 1908c2ecf20Sopenharmony_ci DBDMA_CLEAR(ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN)); 1918c2ecf20Sopenharmony_ci eieio(); 1928c2ecf20Sopenharmony_ci while (dbdma_ld32(&dmap->status) & RUN) 1938c2ecf20Sopenharmony_ci eieio(); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_cistatic void 1978c2ecf20Sopenharmony_cidbdma_setcmd(volatile struct dbdma_cmd *cp, 1988c2ecf20Sopenharmony_ci unsigned short cmd, unsigned count, unsigned long addr, 1998c2ecf20Sopenharmony_ci unsigned long cmd_dep) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci out_le16(&cp->command, cmd); 2028c2ecf20Sopenharmony_ci out_le16(&cp->req_count, count); 2038c2ecf20Sopenharmony_ci out_le32(&cp->phy_addr, addr); 2048c2ecf20Sopenharmony_ci out_le32(&cp->cmd_dep, cmd_dep); 2058c2ecf20Sopenharmony_ci out_le16(&cp->xfer_status, 0); 2068c2ecf20Sopenharmony_ci out_le16(&cp->res_count, 0); 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic inline 2108c2ecf20Sopenharmony_civoid bmwrite(struct net_device *dev, unsigned long reg_offset, unsigned data ) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci out_le16((void __iomem *)dev->base_addr + reg_offset, data); 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic inline 2178c2ecf20Sopenharmony_ciunsigned short bmread(struct net_device *dev, unsigned long reg_offset ) 2188c2ecf20Sopenharmony_ci{ 2198c2ecf20Sopenharmony_ci return in_le16((void __iomem *)dev->base_addr + reg_offset); 2208c2ecf20Sopenharmony_ci} 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistatic void 2238c2ecf20Sopenharmony_cibmac_enable_and_reset_chip(struct net_device *dev) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci struct bmac_data *bp = netdev_priv(dev); 2268c2ecf20Sopenharmony_ci volatile struct dbdma_regs __iomem *rd = bp->rx_dma; 2278c2ecf20Sopenharmony_ci volatile struct dbdma_regs __iomem *td = bp->tx_dma; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (rd) 2308c2ecf20Sopenharmony_ci dbdma_reset(rd); 2318c2ecf20Sopenharmony_ci if (td) 2328c2ecf20Sopenharmony_ci dbdma_reset(td); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 1); 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci#define MIFDELAY udelay(10) 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic unsigned int 2408c2ecf20Sopenharmony_cibmac_mif_readbits(struct net_device *dev, int nb) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci unsigned int val = 0; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci while (--nb >= 0) { 2458c2ecf20Sopenharmony_ci bmwrite(dev, MIFCSR, 0); 2468c2ecf20Sopenharmony_ci MIFDELAY; 2478c2ecf20Sopenharmony_ci if (bmread(dev, MIFCSR) & 8) 2488c2ecf20Sopenharmony_ci val |= 1 << nb; 2498c2ecf20Sopenharmony_ci bmwrite(dev, MIFCSR, 1); 2508c2ecf20Sopenharmony_ci MIFDELAY; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci bmwrite(dev, MIFCSR, 0); 2538c2ecf20Sopenharmony_ci MIFDELAY; 2548c2ecf20Sopenharmony_ci bmwrite(dev, MIFCSR, 1); 2558c2ecf20Sopenharmony_ci MIFDELAY; 2568c2ecf20Sopenharmony_ci return val; 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic void 2608c2ecf20Sopenharmony_cibmac_mif_writebits(struct net_device *dev, unsigned int val, int nb) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci int b; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci while (--nb >= 0) { 2658c2ecf20Sopenharmony_ci b = (val & (1 << nb))? 6: 4; 2668c2ecf20Sopenharmony_ci bmwrite(dev, MIFCSR, b); 2678c2ecf20Sopenharmony_ci MIFDELAY; 2688c2ecf20Sopenharmony_ci bmwrite(dev, MIFCSR, b|1); 2698c2ecf20Sopenharmony_ci MIFDELAY; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic unsigned int 2748c2ecf20Sopenharmony_cibmac_mif_read(struct net_device *dev, unsigned int addr) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci unsigned int val; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci bmwrite(dev, MIFCSR, 4); 2798c2ecf20Sopenharmony_ci MIFDELAY; 2808c2ecf20Sopenharmony_ci bmac_mif_writebits(dev, ~0U, 32); 2818c2ecf20Sopenharmony_ci bmac_mif_writebits(dev, 6, 4); 2828c2ecf20Sopenharmony_ci bmac_mif_writebits(dev, addr, 10); 2838c2ecf20Sopenharmony_ci bmwrite(dev, MIFCSR, 2); 2848c2ecf20Sopenharmony_ci MIFDELAY; 2858c2ecf20Sopenharmony_ci bmwrite(dev, MIFCSR, 1); 2868c2ecf20Sopenharmony_ci MIFDELAY; 2878c2ecf20Sopenharmony_ci val = bmac_mif_readbits(dev, 17); 2888c2ecf20Sopenharmony_ci bmwrite(dev, MIFCSR, 4); 2898c2ecf20Sopenharmony_ci MIFDELAY; 2908c2ecf20Sopenharmony_ci return val; 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic void 2948c2ecf20Sopenharmony_cibmac_mif_write(struct net_device *dev, unsigned int addr, unsigned int val) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci bmwrite(dev, MIFCSR, 4); 2978c2ecf20Sopenharmony_ci MIFDELAY; 2988c2ecf20Sopenharmony_ci bmac_mif_writebits(dev, ~0U, 32); 2998c2ecf20Sopenharmony_ci bmac_mif_writebits(dev, 5, 4); 3008c2ecf20Sopenharmony_ci bmac_mif_writebits(dev, addr, 10); 3018c2ecf20Sopenharmony_ci bmac_mif_writebits(dev, 2, 2); 3028c2ecf20Sopenharmony_ci bmac_mif_writebits(dev, val, 16); 3038c2ecf20Sopenharmony_ci bmac_mif_writebits(dev, 3, 2); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic void 3078c2ecf20Sopenharmony_cibmac_init_registers(struct net_device *dev) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct bmac_data *bp = netdev_priv(dev); 3108c2ecf20Sopenharmony_ci volatile unsigned short regValue; 3118c2ecf20Sopenharmony_ci unsigned short *pWord16; 3128c2ecf20Sopenharmony_ci int i; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci /* XXDEBUG(("bmac: enter init_registers\n")); */ 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci bmwrite(dev, RXRST, RxResetValue); 3178c2ecf20Sopenharmony_ci bmwrite(dev, TXRST, TxResetBit); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci i = 100; 3208c2ecf20Sopenharmony_ci do { 3218c2ecf20Sopenharmony_ci --i; 3228c2ecf20Sopenharmony_ci udelay(10000); 3238c2ecf20Sopenharmony_ci regValue = bmread(dev, TXRST); /* wait for reset to clear..acknowledge */ 3248c2ecf20Sopenharmony_ci } while ((regValue & TxResetBit) && i > 0); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (!bp->is_bmac_plus) { 3278c2ecf20Sopenharmony_ci regValue = bmread(dev, XCVRIF); 3288c2ecf20Sopenharmony_ci regValue |= ClkBit | SerialMode | COLActiveLow; 3298c2ecf20Sopenharmony_ci bmwrite(dev, XCVRIF, regValue); 3308c2ecf20Sopenharmony_ci udelay(10000); 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci bmwrite(dev, RSEED, (unsigned short)0x1968); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci regValue = bmread(dev, XIFC); 3368c2ecf20Sopenharmony_ci regValue |= TxOutputEnable; 3378c2ecf20Sopenharmony_ci bmwrite(dev, XIFC, regValue); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci bmread(dev, PAREG); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* set collision counters to 0 */ 3428c2ecf20Sopenharmony_ci bmwrite(dev, NCCNT, 0); 3438c2ecf20Sopenharmony_ci bmwrite(dev, NTCNT, 0); 3448c2ecf20Sopenharmony_ci bmwrite(dev, EXCNT, 0); 3458c2ecf20Sopenharmony_ci bmwrite(dev, LTCNT, 0); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* set rx counters to 0 */ 3488c2ecf20Sopenharmony_ci bmwrite(dev, FRCNT, 0); 3498c2ecf20Sopenharmony_ci bmwrite(dev, LECNT, 0); 3508c2ecf20Sopenharmony_ci bmwrite(dev, AECNT, 0); 3518c2ecf20Sopenharmony_ci bmwrite(dev, FECNT, 0); 3528c2ecf20Sopenharmony_ci bmwrite(dev, RXCV, 0); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci /* set tx fifo information */ 3558c2ecf20Sopenharmony_ci bmwrite(dev, TXTH, 4); /* 4 octets before tx starts */ 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci bmwrite(dev, TXFIFOCSR, 0); /* first disable txFIFO */ 3588c2ecf20Sopenharmony_ci bmwrite(dev, TXFIFOCSR, TxFIFOEnable ); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* set rx fifo information */ 3618c2ecf20Sopenharmony_ci bmwrite(dev, RXFIFOCSR, 0); /* first disable rxFIFO */ 3628c2ecf20Sopenharmony_ci bmwrite(dev, RXFIFOCSR, RxFIFOEnable ); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci //bmwrite(dev, TXCFG, TxMACEnable); /* TxNeverGiveUp maybe later */ 3658c2ecf20Sopenharmony_ci bmread(dev, STATUS); /* read it just to clear it */ 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci /* zero out the chip Hash Filter registers */ 3688c2ecf20Sopenharmony_ci for (i=0; i<4; i++) bp->hash_table_mask[i] = 0; 3698c2ecf20Sopenharmony_ci bmwrite(dev, BHASH3, bp->hash_table_mask[0]); /* bits 15 - 0 */ 3708c2ecf20Sopenharmony_ci bmwrite(dev, BHASH2, bp->hash_table_mask[1]); /* bits 31 - 16 */ 3718c2ecf20Sopenharmony_ci bmwrite(dev, BHASH1, bp->hash_table_mask[2]); /* bits 47 - 32 */ 3728c2ecf20Sopenharmony_ci bmwrite(dev, BHASH0, bp->hash_table_mask[3]); /* bits 63 - 48 */ 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci pWord16 = (unsigned short *)dev->dev_addr; 3758c2ecf20Sopenharmony_ci bmwrite(dev, MADD0, *pWord16++); 3768c2ecf20Sopenharmony_ci bmwrite(dev, MADD1, *pWord16++); 3778c2ecf20Sopenharmony_ci bmwrite(dev, MADD2, *pWord16); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci bmwrite(dev, RXCFG, RxCRCNoStrip | RxHashFilterEnable | RxRejectOwnPackets); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci bmwrite(dev, INTDISABLE, EnableNormal); 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci#if 0 3858c2ecf20Sopenharmony_cistatic void 3868c2ecf20Sopenharmony_cibmac_disable_interrupts(struct net_device *dev) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci bmwrite(dev, INTDISABLE, DisableAll); 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic void 3928c2ecf20Sopenharmony_cibmac_enable_interrupts(struct net_device *dev) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci bmwrite(dev, INTDISABLE, EnableNormal); 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci#endif 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic void 4008c2ecf20Sopenharmony_cibmac_start_chip(struct net_device *dev) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci struct bmac_data *bp = netdev_priv(dev); 4038c2ecf20Sopenharmony_ci volatile struct dbdma_regs __iomem *rd = bp->rx_dma; 4048c2ecf20Sopenharmony_ci unsigned short oldConfig; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci /* enable rx dma channel */ 4078c2ecf20Sopenharmony_ci dbdma_continue(rd); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci oldConfig = bmread(dev, TXCFG); 4108c2ecf20Sopenharmony_ci bmwrite(dev, TXCFG, oldConfig | TxMACEnable ); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci /* turn on rx plus any other bits already on (promiscuous possibly) */ 4138c2ecf20Sopenharmony_ci oldConfig = bmread(dev, RXCFG); 4148c2ecf20Sopenharmony_ci bmwrite(dev, RXCFG, oldConfig | RxMACEnable ); 4158c2ecf20Sopenharmony_ci udelay(20000); 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic void 4198c2ecf20Sopenharmony_cibmac_init_phy(struct net_device *dev) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci unsigned int addr; 4228c2ecf20Sopenharmony_ci struct bmac_data *bp = netdev_priv(dev); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci printk(KERN_DEBUG "phy registers:"); 4258c2ecf20Sopenharmony_ci for (addr = 0; addr < 32; ++addr) { 4268c2ecf20Sopenharmony_ci if ((addr & 7) == 0) 4278c2ecf20Sopenharmony_ci printk(KERN_DEBUG); 4288c2ecf20Sopenharmony_ci printk(KERN_CONT " %.4x", bmac_mif_read(dev, addr)); 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci printk(KERN_CONT "\n"); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if (bp->is_bmac_plus) { 4338c2ecf20Sopenharmony_ci unsigned int capable, ctrl; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci ctrl = bmac_mif_read(dev, 0); 4368c2ecf20Sopenharmony_ci capable = ((bmac_mif_read(dev, 1) & 0xf800) >> 6) | 1; 4378c2ecf20Sopenharmony_ci if (bmac_mif_read(dev, 4) != capable || 4388c2ecf20Sopenharmony_ci (ctrl & 0x1000) == 0) { 4398c2ecf20Sopenharmony_ci bmac_mif_write(dev, 4, capable); 4408c2ecf20Sopenharmony_ci bmac_mif_write(dev, 0, 0x1200); 4418c2ecf20Sopenharmony_ci } else 4428c2ecf20Sopenharmony_ci bmac_mif_write(dev, 0, 0x1000); 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic void bmac_init_chip(struct net_device *dev) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci bmac_init_phy(dev); 4498c2ecf20Sopenharmony_ci bmac_init_registers(dev); 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 4538c2ecf20Sopenharmony_cistatic int bmac_suspend(struct macio_dev *mdev, pm_message_t state) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci struct net_device* dev = macio_get_drvdata(mdev); 4568c2ecf20Sopenharmony_ci struct bmac_data *bp = netdev_priv(dev); 4578c2ecf20Sopenharmony_ci unsigned long flags; 4588c2ecf20Sopenharmony_ci unsigned short config; 4598c2ecf20Sopenharmony_ci int i; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci netif_device_detach(dev); 4628c2ecf20Sopenharmony_ci /* prolly should wait for dma to finish & turn off the chip */ 4638c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 4648c2ecf20Sopenharmony_ci if (bp->timeout_active) { 4658c2ecf20Sopenharmony_ci del_timer(&bp->tx_timeout); 4668c2ecf20Sopenharmony_ci bp->timeout_active = 0; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci disable_irq(dev->irq); 4698c2ecf20Sopenharmony_ci disable_irq(bp->tx_dma_intr); 4708c2ecf20Sopenharmony_ci disable_irq(bp->rx_dma_intr); 4718c2ecf20Sopenharmony_ci bp->sleeping = 1; 4728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 4738c2ecf20Sopenharmony_ci if (bp->opened) { 4748c2ecf20Sopenharmony_ci volatile struct dbdma_regs __iomem *rd = bp->rx_dma; 4758c2ecf20Sopenharmony_ci volatile struct dbdma_regs __iomem *td = bp->tx_dma; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci config = bmread(dev, RXCFG); 4788c2ecf20Sopenharmony_ci bmwrite(dev, RXCFG, (config & ~RxMACEnable)); 4798c2ecf20Sopenharmony_ci config = bmread(dev, TXCFG); 4808c2ecf20Sopenharmony_ci bmwrite(dev, TXCFG, (config & ~TxMACEnable)); 4818c2ecf20Sopenharmony_ci bmwrite(dev, INTDISABLE, DisableAll); /* disable all intrs */ 4828c2ecf20Sopenharmony_ci /* disable rx and tx dma */ 4838c2ecf20Sopenharmony_ci rd->control = cpu_to_le32(DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE)); /* clear run bit */ 4848c2ecf20Sopenharmony_ci td->control = cpu_to_le32(DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE)); /* clear run bit */ 4858c2ecf20Sopenharmony_ci /* free some skb's */ 4868c2ecf20Sopenharmony_ci for (i=0; i<N_RX_RING; i++) { 4878c2ecf20Sopenharmony_ci if (bp->rx_bufs[i] != NULL) { 4888c2ecf20Sopenharmony_ci dev_kfree_skb(bp->rx_bufs[i]); 4898c2ecf20Sopenharmony_ci bp->rx_bufs[i] = NULL; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci for (i = 0; i<N_TX_RING; i++) { 4938c2ecf20Sopenharmony_ci if (bp->tx_bufs[i] != NULL) { 4948c2ecf20Sopenharmony_ci dev_kfree_skb(bp->tx_bufs[i]); 4958c2ecf20Sopenharmony_ci bp->tx_bufs[i] = NULL; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0); 5008c2ecf20Sopenharmony_ci return 0; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic int bmac_resume(struct macio_dev *mdev) 5048c2ecf20Sopenharmony_ci{ 5058c2ecf20Sopenharmony_ci struct net_device* dev = macio_get_drvdata(mdev); 5068c2ecf20Sopenharmony_ci struct bmac_data *bp = netdev_priv(dev); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci /* see if this is enough */ 5098c2ecf20Sopenharmony_ci if (bp->opened) 5108c2ecf20Sopenharmony_ci bmac_reset_and_enable(dev); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci enable_irq(dev->irq); 5138c2ecf20Sopenharmony_ci enable_irq(bp->tx_dma_intr); 5148c2ecf20Sopenharmony_ci enable_irq(bp->rx_dma_intr); 5158c2ecf20Sopenharmony_ci netif_device_attach(dev); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci return 0; 5188c2ecf20Sopenharmony_ci} 5198c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic int bmac_set_address(struct net_device *dev, void *addr) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci struct bmac_data *bp = netdev_priv(dev); 5248c2ecf20Sopenharmony_ci unsigned char *p = addr; 5258c2ecf20Sopenharmony_ci unsigned short *pWord16; 5268c2ecf20Sopenharmony_ci unsigned long flags; 5278c2ecf20Sopenharmony_ci int i; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci XXDEBUG(("bmac: enter set_address\n")); 5308c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci for (i = 0; i < 6; ++i) { 5338c2ecf20Sopenharmony_ci dev->dev_addr[i] = p[i]; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci /* load up the hardware address */ 5368c2ecf20Sopenharmony_ci pWord16 = (unsigned short *)dev->dev_addr; 5378c2ecf20Sopenharmony_ci bmwrite(dev, MADD0, *pWord16++); 5388c2ecf20Sopenharmony_ci bmwrite(dev, MADD1, *pWord16++); 5398c2ecf20Sopenharmony_ci bmwrite(dev, MADD2, *pWord16); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 5428c2ecf20Sopenharmony_ci XXDEBUG(("bmac: exit set_address\n")); 5438c2ecf20Sopenharmony_ci return 0; 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_cistatic inline void bmac_set_timeout(struct net_device *dev) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct bmac_data *bp = netdev_priv(dev); 5498c2ecf20Sopenharmony_ci unsigned long flags; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 5528c2ecf20Sopenharmony_ci if (bp->timeout_active) 5538c2ecf20Sopenharmony_ci del_timer(&bp->tx_timeout); 5548c2ecf20Sopenharmony_ci bp->tx_timeout.expires = jiffies + TX_TIMEOUT; 5558c2ecf20Sopenharmony_ci add_timer(&bp->tx_timeout); 5568c2ecf20Sopenharmony_ci bp->timeout_active = 1; 5578c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic void 5618c2ecf20Sopenharmony_cibmac_construct_xmt(struct sk_buff *skb, volatile struct dbdma_cmd *cp) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci void *vaddr; 5648c2ecf20Sopenharmony_ci unsigned long baddr; 5658c2ecf20Sopenharmony_ci unsigned long len; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci len = skb->len; 5688c2ecf20Sopenharmony_ci vaddr = skb->data; 5698c2ecf20Sopenharmony_ci baddr = virt_to_bus(vaddr); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci dbdma_setcmd(cp, (OUTPUT_LAST | INTR_ALWAYS | WAIT_IFCLR), len, baddr, 0); 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistatic void 5758c2ecf20Sopenharmony_cibmac_construct_rxbuff(struct sk_buff *skb, volatile struct dbdma_cmd *cp) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci unsigned char *addr = skb? skb->data: bmac_emergency_rxbuf; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci dbdma_setcmd(cp, (INPUT_LAST | INTR_ALWAYS), RX_BUFLEN, 5808c2ecf20Sopenharmony_ci virt_to_bus(addr), 0); 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic void 5848c2ecf20Sopenharmony_cibmac_init_tx_ring(struct bmac_data *bp) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci volatile struct dbdma_regs __iomem *td = bp->tx_dma; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci memset((char *)bp->tx_cmds, 0, (N_TX_RING+1) * sizeof(struct dbdma_cmd)); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci bp->tx_empty = 0; 5918c2ecf20Sopenharmony_ci bp->tx_fill = 0; 5928c2ecf20Sopenharmony_ci bp->tx_fullup = 0; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci /* put a branch at the end of the tx command list */ 5958c2ecf20Sopenharmony_ci dbdma_setcmd(&bp->tx_cmds[N_TX_RING], 5968c2ecf20Sopenharmony_ci (DBDMA_NOP | BR_ALWAYS), 0, 0, virt_to_bus(bp->tx_cmds)); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci /* reset tx dma */ 5998c2ecf20Sopenharmony_ci dbdma_reset(td); 6008c2ecf20Sopenharmony_ci out_le32(&td->wait_sel, 0x00200020); 6018c2ecf20Sopenharmony_ci out_le32(&td->cmdptr, virt_to_bus(bp->tx_cmds)); 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_cistatic int 6058c2ecf20Sopenharmony_cibmac_init_rx_ring(struct net_device *dev) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci struct bmac_data *bp = netdev_priv(dev); 6088c2ecf20Sopenharmony_ci volatile struct dbdma_regs __iomem *rd = bp->rx_dma; 6098c2ecf20Sopenharmony_ci int i; 6108c2ecf20Sopenharmony_ci struct sk_buff *skb; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci /* initialize list of sk_buffs for receiving and set up recv dma */ 6138c2ecf20Sopenharmony_ci memset((char *)bp->rx_cmds, 0, 6148c2ecf20Sopenharmony_ci (N_RX_RING + 1) * sizeof(struct dbdma_cmd)); 6158c2ecf20Sopenharmony_ci for (i = 0; i < N_RX_RING; i++) { 6168c2ecf20Sopenharmony_ci if ((skb = bp->rx_bufs[i]) == NULL) { 6178c2ecf20Sopenharmony_ci bp->rx_bufs[i] = skb = netdev_alloc_skb(dev, RX_BUFLEN + 2); 6188c2ecf20Sopenharmony_ci if (skb != NULL) 6198c2ecf20Sopenharmony_ci skb_reserve(skb, 2); 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci bmac_construct_rxbuff(skb, &bp->rx_cmds[i]); 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci bp->rx_empty = 0; 6258c2ecf20Sopenharmony_ci bp->rx_fill = i; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci /* Put a branch back to the beginning of the receive command list */ 6288c2ecf20Sopenharmony_ci dbdma_setcmd(&bp->rx_cmds[N_RX_RING], 6298c2ecf20Sopenharmony_ci (DBDMA_NOP | BR_ALWAYS), 0, 0, virt_to_bus(bp->rx_cmds)); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci /* start rx dma */ 6328c2ecf20Sopenharmony_ci dbdma_reset(rd); 6338c2ecf20Sopenharmony_ci out_le32(&rd->cmdptr, virt_to_bus(bp->rx_cmds)); 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci return 1; 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_cistatic int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci struct bmac_data *bp = netdev_priv(dev); 6428c2ecf20Sopenharmony_ci volatile struct dbdma_regs __iomem *td = bp->tx_dma; 6438c2ecf20Sopenharmony_ci int i; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci /* see if there's a free slot in the tx ring */ 6468c2ecf20Sopenharmony_ci /* XXDEBUG(("bmac_xmit_start: empty=%d fill=%d\n", */ 6478c2ecf20Sopenharmony_ci /* bp->tx_empty, bp->tx_fill)); */ 6488c2ecf20Sopenharmony_ci i = bp->tx_fill + 1; 6498c2ecf20Sopenharmony_ci if (i >= N_TX_RING) 6508c2ecf20Sopenharmony_ci i = 0; 6518c2ecf20Sopenharmony_ci if (i == bp->tx_empty) { 6528c2ecf20Sopenharmony_ci netif_stop_queue(dev); 6538c2ecf20Sopenharmony_ci bp->tx_fullup = 1; 6548c2ecf20Sopenharmony_ci XXDEBUG(("bmac_transmit_packet: tx ring full\n")); 6558c2ecf20Sopenharmony_ci return -1; /* can't take it at the moment */ 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci dbdma_setcmd(&bp->tx_cmds[i], DBDMA_STOP, 0, 0, 0); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci bmac_construct_xmt(skb, &bp->tx_cmds[bp->tx_fill]); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci bp->tx_bufs[bp->tx_fill] = skb; 6638c2ecf20Sopenharmony_ci bp->tx_fill = i; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci dev->stats.tx_bytes += skb->len; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci dbdma_continue(td); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci return 0; 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic int rxintcount; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_cistatic irqreturn_t bmac_rxdma_intr(int irq, void *dev_id) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci struct net_device *dev = (struct net_device *) dev_id; 6778c2ecf20Sopenharmony_ci struct bmac_data *bp = netdev_priv(dev); 6788c2ecf20Sopenharmony_ci volatile struct dbdma_regs __iomem *rd = bp->rx_dma; 6798c2ecf20Sopenharmony_ci volatile struct dbdma_cmd *cp; 6808c2ecf20Sopenharmony_ci int i, nb, stat; 6818c2ecf20Sopenharmony_ci struct sk_buff *skb; 6828c2ecf20Sopenharmony_ci unsigned int residual; 6838c2ecf20Sopenharmony_ci int last; 6848c2ecf20Sopenharmony_ci unsigned long flags; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci if (++rxintcount < 10) { 6898c2ecf20Sopenharmony_ci XXDEBUG(("bmac_rxdma_intr\n")); 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci last = -1; 6938c2ecf20Sopenharmony_ci i = bp->rx_empty; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci while (1) { 6968c2ecf20Sopenharmony_ci cp = &bp->rx_cmds[i]; 6978c2ecf20Sopenharmony_ci stat = le16_to_cpu(cp->xfer_status); 6988c2ecf20Sopenharmony_ci residual = le16_to_cpu(cp->res_count); 6998c2ecf20Sopenharmony_ci if ((stat & ACTIVE) == 0) 7008c2ecf20Sopenharmony_ci break; 7018c2ecf20Sopenharmony_ci nb = RX_BUFLEN - residual - 2; 7028c2ecf20Sopenharmony_ci if (nb < (ETHERMINPACKET - ETHERCRC)) { 7038c2ecf20Sopenharmony_ci skb = NULL; 7048c2ecf20Sopenharmony_ci dev->stats.rx_length_errors++; 7058c2ecf20Sopenharmony_ci dev->stats.rx_errors++; 7068c2ecf20Sopenharmony_ci } else { 7078c2ecf20Sopenharmony_ci skb = bp->rx_bufs[i]; 7088c2ecf20Sopenharmony_ci bp->rx_bufs[i] = NULL; 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci if (skb != NULL) { 7118c2ecf20Sopenharmony_ci nb -= ETHERCRC; 7128c2ecf20Sopenharmony_ci skb_put(skb, nb); 7138c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 7148c2ecf20Sopenharmony_ci netif_rx(skb); 7158c2ecf20Sopenharmony_ci ++dev->stats.rx_packets; 7168c2ecf20Sopenharmony_ci dev->stats.rx_bytes += nb; 7178c2ecf20Sopenharmony_ci } else { 7188c2ecf20Sopenharmony_ci ++dev->stats.rx_dropped; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci if ((skb = bp->rx_bufs[i]) == NULL) { 7218c2ecf20Sopenharmony_ci bp->rx_bufs[i] = skb = netdev_alloc_skb(dev, RX_BUFLEN + 2); 7228c2ecf20Sopenharmony_ci if (skb != NULL) 7238c2ecf20Sopenharmony_ci skb_reserve(bp->rx_bufs[i], 2); 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci bmac_construct_rxbuff(skb, &bp->rx_cmds[i]); 7268c2ecf20Sopenharmony_ci cp->res_count = cpu_to_le16(0); 7278c2ecf20Sopenharmony_ci cp->xfer_status = cpu_to_le16(0); 7288c2ecf20Sopenharmony_ci last = i; 7298c2ecf20Sopenharmony_ci if (++i >= N_RX_RING) i = 0; 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci if (last != -1) { 7338c2ecf20Sopenharmony_ci bp->rx_fill = last; 7348c2ecf20Sopenharmony_ci bp->rx_empty = i; 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci dbdma_continue(rd); 7388c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci if (rxintcount < 10) { 7418c2ecf20Sopenharmony_ci XXDEBUG(("bmac_rxdma_intr done\n")); 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci return IRQ_HANDLED; 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_cistatic int txintcount; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_cistatic irqreturn_t bmac_txdma_intr(int irq, void *dev_id) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci struct net_device *dev = (struct net_device *) dev_id; 7518c2ecf20Sopenharmony_ci struct bmac_data *bp = netdev_priv(dev); 7528c2ecf20Sopenharmony_ci volatile struct dbdma_cmd *cp; 7538c2ecf20Sopenharmony_ci int stat; 7548c2ecf20Sopenharmony_ci unsigned long flags; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci if (txintcount++ < 10) { 7598c2ecf20Sopenharmony_ci XXDEBUG(("bmac_txdma_intr\n")); 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci /* del_timer(&bp->tx_timeout); */ 7638c2ecf20Sopenharmony_ci /* bp->timeout_active = 0; */ 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci while (1) { 7668c2ecf20Sopenharmony_ci cp = &bp->tx_cmds[bp->tx_empty]; 7678c2ecf20Sopenharmony_ci stat = le16_to_cpu(cp->xfer_status); 7688c2ecf20Sopenharmony_ci if (txintcount < 10) { 7698c2ecf20Sopenharmony_ci XXDEBUG(("bmac_txdma_xfer_stat=%#0x\n", stat)); 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci if (!(stat & ACTIVE)) { 7728c2ecf20Sopenharmony_ci /* 7738c2ecf20Sopenharmony_ci * status field might not have been filled by DBDMA 7748c2ecf20Sopenharmony_ci */ 7758c2ecf20Sopenharmony_ci if (cp == bus_to_virt(in_le32(&bp->tx_dma->cmdptr))) 7768c2ecf20Sopenharmony_ci break; 7778c2ecf20Sopenharmony_ci } 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci if (bp->tx_bufs[bp->tx_empty]) { 7808c2ecf20Sopenharmony_ci ++dev->stats.tx_packets; 7818c2ecf20Sopenharmony_ci dev_consume_skb_irq(bp->tx_bufs[bp->tx_empty]); 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci bp->tx_bufs[bp->tx_empty] = NULL; 7848c2ecf20Sopenharmony_ci bp->tx_fullup = 0; 7858c2ecf20Sopenharmony_ci netif_wake_queue(dev); 7868c2ecf20Sopenharmony_ci if (++bp->tx_empty >= N_TX_RING) 7878c2ecf20Sopenharmony_ci bp->tx_empty = 0; 7888c2ecf20Sopenharmony_ci if (bp->tx_empty == bp->tx_fill) 7898c2ecf20Sopenharmony_ci break; 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci if (txintcount < 10) { 7958c2ecf20Sopenharmony_ci XXDEBUG(("bmac_txdma_intr done->bmac_start\n")); 7968c2ecf20Sopenharmony_ci } 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci bmac_start(dev); 7998c2ecf20Sopenharmony_ci return IRQ_HANDLED; 8008c2ecf20Sopenharmony_ci} 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci#ifndef SUNHME_MULTICAST 8038c2ecf20Sopenharmony_ci/* Real fast bit-reversal algorithm, 6-bit values */ 8048c2ecf20Sopenharmony_cistatic int reverse6[64] = { 8058c2ecf20Sopenharmony_ci 0x0,0x20,0x10,0x30,0x8,0x28,0x18,0x38, 8068c2ecf20Sopenharmony_ci 0x4,0x24,0x14,0x34,0xc,0x2c,0x1c,0x3c, 8078c2ecf20Sopenharmony_ci 0x2,0x22,0x12,0x32,0xa,0x2a,0x1a,0x3a, 8088c2ecf20Sopenharmony_ci 0x6,0x26,0x16,0x36,0xe,0x2e,0x1e,0x3e, 8098c2ecf20Sopenharmony_ci 0x1,0x21,0x11,0x31,0x9,0x29,0x19,0x39, 8108c2ecf20Sopenharmony_ci 0x5,0x25,0x15,0x35,0xd,0x2d,0x1d,0x3d, 8118c2ecf20Sopenharmony_ci 0x3,0x23,0x13,0x33,0xb,0x2b,0x1b,0x3b, 8128c2ecf20Sopenharmony_ci 0x7,0x27,0x17,0x37,0xf,0x2f,0x1f,0x3f 8138c2ecf20Sopenharmony_ci}; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cistatic unsigned int 8168c2ecf20Sopenharmony_cicrc416(unsigned int curval, unsigned short nxtval) 8178c2ecf20Sopenharmony_ci{ 8188c2ecf20Sopenharmony_ci unsigned int counter, cur = curval, next = nxtval; 8198c2ecf20Sopenharmony_ci int high_crc_set, low_data_set; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci /* Swap bytes */ 8228c2ecf20Sopenharmony_ci next = ((next & 0x00FF) << 8) | (next >> 8); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci /* Compute bit-by-bit */ 8258c2ecf20Sopenharmony_ci for (counter = 0; counter < 16; ++counter) { 8268c2ecf20Sopenharmony_ci /* is high CRC bit set? */ 8278c2ecf20Sopenharmony_ci if ((cur & 0x80000000) == 0) high_crc_set = 0; 8288c2ecf20Sopenharmony_ci else high_crc_set = 1; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci cur = cur << 1; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci if ((next & 0x0001) == 0) low_data_set = 0; 8338c2ecf20Sopenharmony_ci else low_data_set = 1; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci next = next >> 1; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci /* do the XOR */ 8388c2ecf20Sopenharmony_ci if (high_crc_set ^ low_data_set) cur = cur ^ CRC32_POLY_BE; 8398c2ecf20Sopenharmony_ci } 8408c2ecf20Sopenharmony_ci return cur; 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cistatic unsigned int 8448c2ecf20Sopenharmony_cibmac_crc(unsigned short *address) 8458c2ecf20Sopenharmony_ci{ 8468c2ecf20Sopenharmony_ci unsigned int newcrc; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci XXDEBUG(("bmac_crc: addr=%#04x, %#04x, %#04x\n", *address, address[1], address[2])); 8498c2ecf20Sopenharmony_ci newcrc = crc416(0xffffffff, *address); /* address bits 47 - 32 */ 8508c2ecf20Sopenharmony_ci newcrc = crc416(newcrc, address[1]); /* address bits 31 - 16 */ 8518c2ecf20Sopenharmony_ci newcrc = crc416(newcrc, address[2]); /* address bits 15 - 0 */ 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci return(newcrc); 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci/* 8578c2ecf20Sopenharmony_ci * Add requested mcast addr to BMac's hash table filter. 8588c2ecf20Sopenharmony_ci * 8598c2ecf20Sopenharmony_ci */ 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_cistatic void 8628c2ecf20Sopenharmony_cibmac_addhash(struct bmac_data *bp, unsigned char *addr) 8638c2ecf20Sopenharmony_ci{ 8648c2ecf20Sopenharmony_ci unsigned int crc; 8658c2ecf20Sopenharmony_ci unsigned short mask; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci if (!(*addr)) return; 8688c2ecf20Sopenharmony_ci crc = bmac_crc((unsigned short *)addr) & 0x3f; /* Big-endian alert! */ 8698c2ecf20Sopenharmony_ci crc = reverse6[crc]; /* Hyperfast bit-reversing algorithm */ 8708c2ecf20Sopenharmony_ci if (bp->hash_use_count[crc]++) return; /* This bit is already set */ 8718c2ecf20Sopenharmony_ci mask = crc % 16; 8728c2ecf20Sopenharmony_ci mask = (unsigned char)1 << mask; 8738c2ecf20Sopenharmony_ci bp->hash_use_count[crc/16] |= mask; 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_cistatic void 8778c2ecf20Sopenharmony_cibmac_removehash(struct bmac_data *bp, unsigned char *addr) 8788c2ecf20Sopenharmony_ci{ 8798c2ecf20Sopenharmony_ci unsigned int crc; 8808c2ecf20Sopenharmony_ci unsigned char mask; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci /* Now, delete the address from the filter copy, as indicated */ 8838c2ecf20Sopenharmony_ci crc = bmac_crc((unsigned short *)addr) & 0x3f; /* Big-endian alert! */ 8848c2ecf20Sopenharmony_ci crc = reverse6[crc]; /* Hyperfast bit-reversing algorithm */ 8858c2ecf20Sopenharmony_ci if (bp->hash_use_count[crc] == 0) return; /* That bit wasn't in use! */ 8868c2ecf20Sopenharmony_ci if (--bp->hash_use_count[crc]) return; /* That bit is still in use */ 8878c2ecf20Sopenharmony_ci mask = crc % 16; 8888c2ecf20Sopenharmony_ci mask = ((unsigned char)1 << mask) ^ 0xffff; /* To turn off bit */ 8898c2ecf20Sopenharmony_ci bp->hash_table_mask[crc/16] &= mask; 8908c2ecf20Sopenharmony_ci} 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci/* 8938c2ecf20Sopenharmony_ci * Sync the adapter with the software copy of the multicast mask 8948c2ecf20Sopenharmony_ci * (logical address filter). 8958c2ecf20Sopenharmony_ci */ 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistatic void 8988c2ecf20Sopenharmony_cibmac_rx_off(struct net_device *dev) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci unsigned short rx_cfg; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci rx_cfg = bmread(dev, RXCFG); 9038c2ecf20Sopenharmony_ci rx_cfg &= ~RxMACEnable; 9048c2ecf20Sopenharmony_ci bmwrite(dev, RXCFG, rx_cfg); 9058c2ecf20Sopenharmony_ci do { 9068c2ecf20Sopenharmony_ci rx_cfg = bmread(dev, RXCFG); 9078c2ecf20Sopenharmony_ci } while (rx_cfg & RxMACEnable); 9088c2ecf20Sopenharmony_ci} 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ciunsigned short 9118c2ecf20Sopenharmony_cibmac_rx_on(struct net_device *dev, int hash_enable, int promisc_enable) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci unsigned short rx_cfg; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci rx_cfg = bmread(dev, RXCFG); 9168c2ecf20Sopenharmony_ci rx_cfg |= RxMACEnable; 9178c2ecf20Sopenharmony_ci if (hash_enable) rx_cfg |= RxHashFilterEnable; 9188c2ecf20Sopenharmony_ci else rx_cfg &= ~RxHashFilterEnable; 9198c2ecf20Sopenharmony_ci if (promisc_enable) rx_cfg |= RxPromiscEnable; 9208c2ecf20Sopenharmony_ci else rx_cfg &= ~RxPromiscEnable; 9218c2ecf20Sopenharmony_ci bmwrite(dev, RXRST, RxResetValue); 9228c2ecf20Sopenharmony_ci bmwrite(dev, RXFIFOCSR, 0); /* first disable rxFIFO */ 9238c2ecf20Sopenharmony_ci bmwrite(dev, RXFIFOCSR, RxFIFOEnable ); 9248c2ecf20Sopenharmony_ci bmwrite(dev, RXCFG, rx_cfg ); 9258c2ecf20Sopenharmony_ci return rx_cfg; 9268c2ecf20Sopenharmony_ci} 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_cistatic void 9298c2ecf20Sopenharmony_cibmac_update_hash_table_mask(struct net_device *dev, struct bmac_data *bp) 9308c2ecf20Sopenharmony_ci{ 9318c2ecf20Sopenharmony_ci bmwrite(dev, BHASH3, bp->hash_table_mask[0]); /* bits 15 - 0 */ 9328c2ecf20Sopenharmony_ci bmwrite(dev, BHASH2, bp->hash_table_mask[1]); /* bits 31 - 16 */ 9338c2ecf20Sopenharmony_ci bmwrite(dev, BHASH1, bp->hash_table_mask[2]); /* bits 47 - 32 */ 9348c2ecf20Sopenharmony_ci bmwrite(dev, BHASH0, bp->hash_table_mask[3]); /* bits 63 - 48 */ 9358c2ecf20Sopenharmony_ci} 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci#if 0 9388c2ecf20Sopenharmony_cistatic void 9398c2ecf20Sopenharmony_cibmac_add_multi(struct net_device *dev, 9408c2ecf20Sopenharmony_ci struct bmac_data *bp, unsigned char *addr) 9418c2ecf20Sopenharmony_ci{ 9428c2ecf20Sopenharmony_ci /* XXDEBUG(("bmac: enter bmac_add_multi\n")); */ 9438c2ecf20Sopenharmony_ci bmac_addhash(bp, addr); 9448c2ecf20Sopenharmony_ci bmac_rx_off(dev); 9458c2ecf20Sopenharmony_ci bmac_update_hash_table_mask(dev, bp); 9468c2ecf20Sopenharmony_ci bmac_rx_on(dev, 1, (dev->flags & IFF_PROMISC)? 1 : 0); 9478c2ecf20Sopenharmony_ci /* XXDEBUG(("bmac: exit bmac_add_multi\n")); */ 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_cistatic void 9518c2ecf20Sopenharmony_cibmac_remove_multi(struct net_device *dev, 9528c2ecf20Sopenharmony_ci struct bmac_data *bp, unsigned char *addr) 9538c2ecf20Sopenharmony_ci{ 9548c2ecf20Sopenharmony_ci bmac_removehash(bp, addr); 9558c2ecf20Sopenharmony_ci bmac_rx_off(dev); 9568c2ecf20Sopenharmony_ci bmac_update_hash_table_mask(dev, bp); 9578c2ecf20Sopenharmony_ci bmac_rx_on(dev, 1, (dev->flags & IFF_PROMISC)? 1 : 0); 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci#endif 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci/* Set or clear the multicast filter for this adaptor. 9628c2ecf20Sopenharmony_ci num_addrs == -1 Promiscuous mode, receive all packets 9638c2ecf20Sopenharmony_ci num_addrs == 0 Normal mode, clear multicast list 9648c2ecf20Sopenharmony_ci num_addrs > 0 Multicast mode, receive normal and MC packets, and do 9658c2ecf20Sopenharmony_ci best-effort filtering. 9668c2ecf20Sopenharmony_ci */ 9678c2ecf20Sopenharmony_cistatic void bmac_set_multicast(struct net_device *dev) 9688c2ecf20Sopenharmony_ci{ 9698c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 9708c2ecf20Sopenharmony_ci struct bmac_data *bp = netdev_priv(dev); 9718c2ecf20Sopenharmony_ci int num_addrs = netdev_mc_count(dev); 9728c2ecf20Sopenharmony_ci unsigned short rx_cfg; 9738c2ecf20Sopenharmony_ci int i; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci if (bp->sleeping) 9768c2ecf20Sopenharmony_ci return; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci XXDEBUG(("bmac: enter bmac_set_multicast, n_addrs=%d\n", num_addrs)); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci if((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) { 9818c2ecf20Sopenharmony_ci for (i=0; i<4; i++) bp->hash_table_mask[i] = 0xffff; 9828c2ecf20Sopenharmony_ci bmac_update_hash_table_mask(dev, bp); 9838c2ecf20Sopenharmony_ci rx_cfg = bmac_rx_on(dev, 1, 0); 9848c2ecf20Sopenharmony_ci XXDEBUG(("bmac: all multi, rx_cfg=%#08x\n")); 9858c2ecf20Sopenharmony_ci } else if ((dev->flags & IFF_PROMISC) || (num_addrs < 0)) { 9868c2ecf20Sopenharmony_ci rx_cfg = bmread(dev, RXCFG); 9878c2ecf20Sopenharmony_ci rx_cfg |= RxPromiscEnable; 9888c2ecf20Sopenharmony_ci bmwrite(dev, RXCFG, rx_cfg); 9898c2ecf20Sopenharmony_ci rx_cfg = bmac_rx_on(dev, 0, 1); 9908c2ecf20Sopenharmony_ci XXDEBUG(("bmac: promisc mode enabled, rx_cfg=%#08x\n", rx_cfg)); 9918c2ecf20Sopenharmony_ci } else { 9928c2ecf20Sopenharmony_ci for (i=0; i<4; i++) bp->hash_table_mask[i] = 0; 9938c2ecf20Sopenharmony_ci for (i=0; i<64; i++) bp->hash_use_count[i] = 0; 9948c2ecf20Sopenharmony_ci if (num_addrs == 0) { 9958c2ecf20Sopenharmony_ci rx_cfg = bmac_rx_on(dev, 0, 0); 9968c2ecf20Sopenharmony_ci XXDEBUG(("bmac: multi disabled, rx_cfg=%#08x\n", rx_cfg)); 9978c2ecf20Sopenharmony_ci } else { 9988c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) 9998c2ecf20Sopenharmony_ci bmac_addhash(bp, ha->addr); 10008c2ecf20Sopenharmony_ci bmac_update_hash_table_mask(dev, bp); 10018c2ecf20Sopenharmony_ci rx_cfg = bmac_rx_on(dev, 1, 0); 10028c2ecf20Sopenharmony_ci XXDEBUG(("bmac: multi enabled, rx_cfg=%#08x\n", rx_cfg)); 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci /* XXDEBUG(("bmac: exit bmac_set_multicast\n")); */ 10068c2ecf20Sopenharmony_ci} 10078c2ecf20Sopenharmony_ci#else /* ifdef SUNHME_MULTICAST */ 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci/* The version of set_multicast below was lifted from sunhme.c */ 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_cistatic void bmac_set_multicast(struct net_device *dev) 10128c2ecf20Sopenharmony_ci{ 10138c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 10148c2ecf20Sopenharmony_ci unsigned short rx_cfg; 10158c2ecf20Sopenharmony_ci u32 crc; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci if((dev->flags & IFF_ALLMULTI) || (netdev_mc_count(dev) > 64)) { 10188c2ecf20Sopenharmony_ci bmwrite(dev, BHASH0, 0xffff); 10198c2ecf20Sopenharmony_ci bmwrite(dev, BHASH1, 0xffff); 10208c2ecf20Sopenharmony_ci bmwrite(dev, BHASH2, 0xffff); 10218c2ecf20Sopenharmony_ci bmwrite(dev, BHASH3, 0xffff); 10228c2ecf20Sopenharmony_ci } else if(dev->flags & IFF_PROMISC) { 10238c2ecf20Sopenharmony_ci rx_cfg = bmread(dev, RXCFG); 10248c2ecf20Sopenharmony_ci rx_cfg |= RxPromiscEnable; 10258c2ecf20Sopenharmony_ci bmwrite(dev, RXCFG, rx_cfg); 10268c2ecf20Sopenharmony_ci } else { 10278c2ecf20Sopenharmony_ci u16 hash_table[4] = { 0 }; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci rx_cfg = bmread(dev, RXCFG); 10308c2ecf20Sopenharmony_ci rx_cfg &= ~RxPromiscEnable; 10318c2ecf20Sopenharmony_ci bmwrite(dev, RXCFG, rx_cfg); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 10348c2ecf20Sopenharmony_ci crc = ether_crc_le(6, ha->addr); 10358c2ecf20Sopenharmony_ci crc >>= 26; 10368c2ecf20Sopenharmony_ci hash_table[crc >> 4] |= 1 << (crc & 0xf); 10378c2ecf20Sopenharmony_ci } 10388c2ecf20Sopenharmony_ci bmwrite(dev, BHASH0, hash_table[0]); 10398c2ecf20Sopenharmony_ci bmwrite(dev, BHASH1, hash_table[1]); 10408c2ecf20Sopenharmony_ci bmwrite(dev, BHASH2, hash_table[2]); 10418c2ecf20Sopenharmony_ci bmwrite(dev, BHASH3, hash_table[3]); 10428c2ecf20Sopenharmony_ci } 10438c2ecf20Sopenharmony_ci} 10448c2ecf20Sopenharmony_ci#endif /* SUNHME_MULTICAST */ 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_cistatic int miscintcount; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_cistatic irqreturn_t bmac_misc_intr(int irq, void *dev_id) 10498c2ecf20Sopenharmony_ci{ 10508c2ecf20Sopenharmony_ci struct net_device *dev = (struct net_device *) dev_id; 10518c2ecf20Sopenharmony_ci unsigned int status = bmread(dev, STATUS); 10528c2ecf20Sopenharmony_ci if (miscintcount++ < 10) { 10538c2ecf20Sopenharmony_ci XXDEBUG(("bmac_misc_intr\n")); 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci /* XXDEBUG(("bmac_misc_intr, status=%#08x\n", status)); */ 10568c2ecf20Sopenharmony_ci /* bmac_txdma_intr_inner(irq, dev_id); */ 10578c2ecf20Sopenharmony_ci /* if (status & FrameReceived) dev->stats.rx_dropped++; */ 10588c2ecf20Sopenharmony_ci if (status & RxErrorMask) dev->stats.rx_errors++; 10598c2ecf20Sopenharmony_ci if (status & RxCRCCntExp) dev->stats.rx_crc_errors++; 10608c2ecf20Sopenharmony_ci if (status & RxLenCntExp) dev->stats.rx_length_errors++; 10618c2ecf20Sopenharmony_ci if (status & RxOverFlow) dev->stats.rx_over_errors++; 10628c2ecf20Sopenharmony_ci if (status & RxAlignCntExp) dev->stats.rx_frame_errors++; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci /* if (status & FrameSent) dev->stats.tx_dropped++; */ 10658c2ecf20Sopenharmony_ci if (status & TxErrorMask) dev->stats.tx_errors++; 10668c2ecf20Sopenharmony_ci if (status & TxUnderrun) dev->stats.tx_fifo_errors++; 10678c2ecf20Sopenharmony_ci if (status & TxNormalCollExp) dev->stats.collisions++; 10688c2ecf20Sopenharmony_ci return IRQ_HANDLED; 10698c2ecf20Sopenharmony_ci} 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci/* 10728c2ecf20Sopenharmony_ci * Procedure for reading EEPROM 10738c2ecf20Sopenharmony_ci */ 10748c2ecf20Sopenharmony_ci#define SROMAddressLength 5 10758c2ecf20Sopenharmony_ci#define DataInOn 0x0008 10768c2ecf20Sopenharmony_ci#define DataInOff 0x0000 10778c2ecf20Sopenharmony_ci#define Clk 0x0002 10788c2ecf20Sopenharmony_ci#define ChipSelect 0x0001 10798c2ecf20Sopenharmony_ci#define SDIShiftCount 3 10808c2ecf20Sopenharmony_ci#define SD0ShiftCount 2 10818c2ecf20Sopenharmony_ci#define DelayValue 1000 /* number of microseconds */ 10828c2ecf20Sopenharmony_ci#define SROMStartOffset 10 /* this is in words */ 10838c2ecf20Sopenharmony_ci#define SROMReadCount 3 /* number of words to read from SROM */ 10848c2ecf20Sopenharmony_ci#define SROMAddressBits 6 10858c2ecf20Sopenharmony_ci#define EnetAddressOffset 20 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_cistatic unsigned char 10888c2ecf20Sopenharmony_cibmac_clock_out_bit(struct net_device *dev) 10898c2ecf20Sopenharmony_ci{ 10908c2ecf20Sopenharmony_ci unsigned short data; 10918c2ecf20Sopenharmony_ci unsigned short val; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci bmwrite(dev, SROMCSR, ChipSelect | Clk); 10948c2ecf20Sopenharmony_ci udelay(DelayValue); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci data = bmread(dev, SROMCSR); 10978c2ecf20Sopenharmony_ci udelay(DelayValue); 10988c2ecf20Sopenharmony_ci val = (data >> SD0ShiftCount) & 1; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci bmwrite(dev, SROMCSR, ChipSelect); 11018c2ecf20Sopenharmony_ci udelay(DelayValue); 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci return val; 11048c2ecf20Sopenharmony_ci} 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_cistatic void 11078c2ecf20Sopenharmony_cibmac_clock_in_bit(struct net_device *dev, unsigned int val) 11088c2ecf20Sopenharmony_ci{ 11098c2ecf20Sopenharmony_ci unsigned short data; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci if (val != 0 && val != 1) return; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci data = (val << SDIShiftCount); 11148c2ecf20Sopenharmony_ci bmwrite(dev, SROMCSR, data | ChipSelect ); 11158c2ecf20Sopenharmony_ci udelay(DelayValue); 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci bmwrite(dev, SROMCSR, data | ChipSelect | Clk ); 11188c2ecf20Sopenharmony_ci udelay(DelayValue); 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci bmwrite(dev, SROMCSR, data | ChipSelect); 11218c2ecf20Sopenharmony_ci udelay(DelayValue); 11228c2ecf20Sopenharmony_ci} 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_cistatic void 11258c2ecf20Sopenharmony_cireset_and_select_srom(struct net_device *dev) 11268c2ecf20Sopenharmony_ci{ 11278c2ecf20Sopenharmony_ci /* first reset */ 11288c2ecf20Sopenharmony_ci bmwrite(dev, SROMCSR, 0); 11298c2ecf20Sopenharmony_ci udelay(DelayValue); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci /* send it the read command (110) */ 11328c2ecf20Sopenharmony_ci bmac_clock_in_bit(dev, 1); 11338c2ecf20Sopenharmony_ci bmac_clock_in_bit(dev, 1); 11348c2ecf20Sopenharmony_ci bmac_clock_in_bit(dev, 0); 11358c2ecf20Sopenharmony_ci} 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_cistatic unsigned short 11388c2ecf20Sopenharmony_ciread_srom(struct net_device *dev, unsigned int addr, unsigned int addr_len) 11398c2ecf20Sopenharmony_ci{ 11408c2ecf20Sopenharmony_ci unsigned short data, val; 11418c2ecf20Sopenharmony_ci int i; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci /* send out the address we want to read from */ 11448c2ecf20Sopenharmony_ci for (i = 0; i < addr_len; i++) { 11458c2ecf20Sopenharmony_ci val = addr >> (addr_len-i-1); 11468c2ecf20Sopenharmony_ci bmac_clock_in_bit(dev, val & 1); 11478c2ecf20Sopenharmony_ci } 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci /* Now read in the 16-bit data */ 11508c2ecf20Sopenharmony_ci data = 0; 11518c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) { 11528c2ecf20Sopenharmony_ci val = bmac_clock_out_bit(dev); 11538c2ecf20Sopenharmony_ci data <<= 1; 11548c2ecf20Sopenharmony_ci data |= val; 11558c2ecf20Sopenharmony_ci } 11568c2ecf20Sopenharmony_ci bmwrite(dev, SROMCSR, 0); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci return data; 11598c2ecf20Sopenharmony_ci} 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci/* 11628c2ecf20Sopenharmony_ci * It looks like Cogent and SMC use different methods for calculating 11638c2ecf20Sopenharmony_ci * checksums. What a pain.. 11648c2ecf20Sopenharmony_ci */ 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_cistatic int 11678c2ecf20Sopenharmony_cibmac_verify_checksum(struct net_device *dev) 11688c2ecf20Sopenharmony_ci{ 11698c2ecf20Sopenharmony_ci unsigned short data, storedCS; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci reset_and_select_srom(dev); 11728c2ecf20Sopenharmony_ci data = read_srom(dev, 3, SROMAddressBits); 11738c2ecf20Sopenharmony_ci storedCS = ((data >> 8) & 0x0ff) | ((data << 8) & 0xff00); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci return 0; 11768c2ecf20Sopenharmony_ci} 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_cistatic void 11808c2ecf20Sopenharmony_cibmac_get_station_address(struct net_device *dev, unsigned char *ea) 11818c2ecf20Sopenharmony_ci{ 11828c2ecf20Sopenharmony_ci int i; 11838c2ecf20Sopenharmony_ci unsigned short data; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) 11868c2ecf20Sopenharmony_ci { 11878c2ecf20Sopenharmony_ci reset_and_select_srom(dev); 11888c2ecf20Sopenharmony_ci data = read_srom(dev, i + EnetAddressOffset/2, SROMAddressBits); 11898c2ecf20Sopenharmony_ci ea[2*i] = bitrev8(data & 0x0ff); 11908c2ecf20Sopenharmony_ci ea[2*i+1] = bitrev8((data >> 8) & 0x0ff); 11918c2ecf20Sopenharmony_ci } 11928c2ecf20Sopenharmony_ci} 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_cistatic void bmac_reset_and_enable(struct net_device *dev) 11958c2ecf20Sopenharmony_ci{ 11968c2ecf20Sopenharmony_ci struct bmac_data *bp = netdev_priv(dev); 11978c2ecf20Sopenharmony_ci unsigned long flags; 11988c2ecf20Sopenharmony_ci struct sk_buff *skb; 11998c2ecf20Sopenharmony_ci unsigned char *data; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 12028c2ecf20Sopenharmony_ci bmac_enable_and_reset_chip(dev); 12038c2ecf20Sopenharmony_ci bmac_init_tx_ring(bp); 12048c2ecf20Sopenharmony_ci bmac_init_rx_ring(dev); 12058c2ecf20Sopenharmony_ci bmac_init_chip(dev); 12068c2ecf20Sopenharmony_ci bmac_start_chip(dev); 12078c2ecf20Sopenharmony_ci bmwrite(dev, INTDISABLE, EnableNormal); 12088c2ecf20Sopenharmony_ci bp->sleeping = 0; 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci /* 12118c2ecf20Sopenharmony_ci * It seems that the bmac can't receive until it's transmitted 12128c2ecf20Sopenharmony_ci * a packet. So we give it a dummy packet to transmit. 12138c2ecf20Sopenharmony_ci */ 12148c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(dev, ETHERMINPACKET); 12158c2ecf20Sopenharmony_ci if (skb != NULL) { 12168c2ecf20Sopenharmony_ci data = skb_put_zero(skb, ETHERMINPACKET); 12178c2ecf20Sopenharmony_ci memcpy(data, dev->dev_addr, ETH_ALEN); 12188c2ecf20Sopenharmony_ci memcpy(data + ETH_ALEN, dev->dev_addr, ETH_ALEN); 12198c2ecf20Sopenharmony_ci bmac_transmit_packet(skb, dev); 12208c2ecf20Sopenharmony_ci } 12218c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 12228c2ecf20Sopenharmony_ci} 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_cistatic const struct ethtool_ops bmac_ethtool_ops = { 12258c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 12268c2ecf20Sopenharmony_ci}; 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_cistatic const struct net_device_ops bmac_netdev_ops = { 12298c2ecf20Sopenharmony_ci .ndo_open = bmac_open, 12308c2ecf20Sopenharmony_ci .ndo_stop = bmac_close, 12318c2ecf20Sopenharmony_ci .ndo_start_xmit = bmac_output, 12328c2ecf20Sopenharmony_ci .ndo_set_rx_mode = bmac_set_multicast, 12338c2ecf20Sopenharmony_ci .ndo_set_mac_address = bmac_set_address, 12348c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 12358c2ecf20Sopenharmony_ci}; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_cistatic int bmac_probe(struct macio_dev *mdev, const struct of_device_id *match) 12388c2ecf20Sopenharmony_ci{ 12398c2ecf20Sopenharmony_ci int j, rev, ret; 12408c2ecf20Sopenharmony_ci struct bmac_data *bp; 12418c2ecf20Sopenharmony_ci const unsigned char *prop_addr; 12428c2ecf20Sopenharmony_ci unsigned char addr[6]; 12438c2ecf20Sopenharmony_ci struct net_device *dev; 12448c2ecf20Sopenharmony_ci int is_bmac_plus = ((int)match->data) != 0; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) { 12478c2ecf20Sopenharmony_ci printk(KERN_ERR "BMAC: can't use, need 3 addrs and 3 intrs\n"); 12488c2ecf20Sopenharmony_ci return -ENODEV; 12498c2ecf20Sopenharmony_ci } 12508c2ecf20Sopenharmony_ci prop_addr = of_get_property(macio_get_of_node(mdev), 12518c2ecf20Sopenharmony_ci "mac-address", NULL); 12528c2ecf20Sopenharmony_ci if (prop_addr == NULL) { 12538c2ecf20Sopenharmony_ci prop_addr = of_get_property(macio_get_of_node(mdev), 12548c2ecf20Sopenharmony_ci "local-mac-address", NULL); 12558c2ecf20Sopenharmony_ci if (prop_addr == NULL) { 12568c2ecf20Sopenharmony_ci printk(KERN_ERR "BMAC: Can't get mac-address\n"); 12578c2ecf20Sopenharmony_ci return -ENODEV; 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci } 12608c2ecf20Sopenharmony_ci memcpy(addr, prop_addr, sizeof(addr)); 12618c2ecf20Sopenharmony_ci 12628c2ecf20Sopenharmony_ci dev = alloc_etherdev(PRIV_BYTES); 12638c2ecf20Sopenharmony_ci if (!dev) 12648c2ecf20Sopenharmony_ci return -ENOMEM; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci bp = netdev_priv(dev); 12678c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, &mdev->ofdev.dev); 12688c2ecf20Sopenharmony_ci macio_set_drvdata(mdev, dev); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci bp->mdev = mdev; 12718c2ecf20Sopenharmony_ci spin_lock_init(&bp->lock); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci if (macio_request_resources(mdev, "bmac")) { 12748c2ecf20Sopenharmony_ci printk(KERN_ERR "BMAC: can't request IO resource !\n"); 12758c2ecf20Sopenharmony_ci goto out_free; 12768c2ecf20Sopenharmony_ci } 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci dev->base_addr = (unsigned long) 12798c2ecf20Sopenharmony_ci ioremap(macio_resource_start(mdev, 0), macio_resource_len(mdev, 0)); 12808c2ecf20Sopenharmony_ci if (dev->base_addr == 0) 12818c2ecf20Sopenharmony_ci goto out_release; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci dev->irq = macio_irq(mdev, 0); 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci bmac_enable_and_reset_chip(dev); 12868c2ecf20Sopenharmony_ci bmwrite(dev, INTDISABLE, DisableAll); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci rev = addr[0] == 0 && addr[1] == 0xA0; 12898c2ecf20Sopenharmony_ci for (j = 0; j < 6; ++j) 12908c2ecf20Sopenharmony_ci dev->dev_addr[j] = rev ? bitrev8(addr[j]): addr[j]; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci /* Enable chip without interrupts for now */ 12938c2ecf20Sopenharmony_ci bmac_enable_and_reset_chip(dev); 12948c2ecf20Sopenharmony_ci bmwrite(dev, INTDISABLE, DisableAll); 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci dev->netdev_ops = &bmac_netdev_ops; 12978c2ecf20Sopenharmony_ci dev->ethtool_ops = &bmac_ethtool_ops; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci bmac_get_station_address(dev, addr); 13008c2ecf20Sopenharmony_ci if (bmac_verify_checksum(dev) != 0) 13018c2ecf20Sopenharmony_ci goto err_out_iounmap; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci bp->is_bmac_plus = is_bmac_plus; 13048c2ecf20Sopenharmony_ci bp->tx_dma = ioremap(macio_resource_start(mdev, 1), macio_resource_len(mdev, 1)); 13058c2ecf20Sopenharmony_ci if (!bp->tx_dma) 13068c2ecf20Sopenharmony_ci goto err_out_iounmap; 13078c2ecf20Sopenharmony_ci bp->tx_dma_intr = macio_irq(mdev, 1); 13088c2ecf20Sopenharmony_ci bp->rx_dma = ioremap(macio_resource_start(mdev, 2), macio_resource_len(mdev, 2)); 13098c2ecf20Sopenharmony_ci if (!bp->rx_dma) 13108c2ecf20Sopenharmony_ci goto err_out_iounmap_tx; 13118c2ecf20Sopenharmony_ci bp->rx_dma_intr = macio_irq(mdev, 2); 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci bp->tx_cmds = (volatile struct dbdma_cmd *) DBDMA_ALIGN(bp + 1); 13148c2ecf20Sopenharmony_ci bp->rx_cmds = bp->tx_cmds + N_TX_RING + 1; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci bp->queue = (struct sk_buff_head *)(bp->rx_cmds + N_RX_RING + 1); 13178c2ecf20Sopenharmony_ci skb_queue_head_init(bp->queue); 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci timer_setup(&bp->tx_timeout, bmac_tx_timeout, 0); 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci ret = request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev); 13228c2ecf20Sopenharmony_ci if (ret) { 13238c2ecf20Sopenharmony_ci printk(KERN_ERR "BMAC: can't get irq %d\n", dev->irq); 13248c2ecf20Sopenharmony_ci goto err_out_iounmap_rx; 13258c2ecf20Sopenharmony_ci } 13268c2ecf20Sopenharmony_ci ret = request_irq(bp->tx_dma_intr, bmac_txdma_intr, 0, "BMAC-txdma", dev); 13278c2ecf20Sopenharmony_ci if (ret) { 13288c2ecf20Sopenharmony_ci printk(KERN_ERR "BMAC: can't get irq %d\n", bp->tx_dma_intr); 13298c2ecf20Sopenharmony_ci goto err_out_irq0; 13308c2ecf20Sopenharmony_ci } 13318c2ecf20Sopenharmony_ci ret = request_irq(bp->rx_dma_intr, bmac_rxdma_intr, 0, "BMAC-rxdma", dev); 13328c2ecf20Sopenharmony_ci if (ret) { 13338c2ecf20Sopenharmony_ci printk(KERN_ERR "BMAC: can't get irq %d\n", bp->rx_dma_intr); 13348c2ecf20Sopenharmony_ci goto err_out_irq1; 13358c2ecf20Sopenharmony_ci } 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci /* Mask chip interrupts and disable chip, will be 13388c2ecf20Sopenharmony_ci * re-enabled on open() 13398c2ecf20Sopenharmony_ci */ 13408c2ecf20Sopenharmony_ci disable_irq(dev->irq); 13418c2ecf20Sopenharmony_ci pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0); 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci if (register_netdev(dev) != 0) { 13448c2ecf20Sopenharmony_ci printk(KERN_ERR "BMAC: Ethernet registration failed\n"); 13458c2ecf20Sopenharmony_ci goto err_out_irq2; 13468c2ecf20Sopenharmony_ci } 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: BMAC%s at %pM", 13498c2ecf20Sopenharmony_ci dev->name, (is_bmac_plus ? "+" : ""), dev->dev_addr); 13508c2ecf20Sopenharmony_ci XXDEBUG((", base_addr=%#0lx", dev->base_addr)); 13518c2ecf20Sopenharmony_ci printk("\n"); 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci return 0; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_cierr_out_irq2: 13568c2ecf20Sopenharmony_ci free_irq(bp->rx_dma_intr, dev); 13578c2ecf20Sopenharmony_cierr_out_irq1: 13588c2ecf20Sopenharmony_ci free_irq(bp->tx_dma_intr, dev); 13598c2ecf20Sopenharmony_cierr_out_irq0: 13608c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 13618c2ecf20Sopenharmony_cierr_out_iounmap_rx: 13628c2ecf20Sopenharmony_ci iounmap(bp->rx_dma); 13638c2ecf20Sopenharmony_cierr_out_iounmap_tx: 13648c2ecf20Sopenharmony_ci iounmap(bp->tx_dma); 13658c2ecf20Sopenharmony_cierr_out_iounmap: 13668c2ecf20Sopenharmony_ci iounmap((void __iomem *)dev->base_addr); 13678c2ecf20Sopenharmony_ciout_release: 13688c2ecf20Sopenharmony_ci macio_release_resources(mdev); 13698c2ecf20Sopenharmony_ciout_free: 13708c2ecf20Sopenharmony_ci pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0); 13718c2ecf20Sopenharmony_ci free_netdev(dev); 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci return -ENODEV; 13748c2ecf20Sopenharmony_ci} 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_cistatic int bmac_open(struct net_device *dev) 13778c2ecf20Sopenharmony_ci{ 13788c2ecf20Sopenharmony_ci struct bmac_data *bp = netdev_priv(dev); 13798c2ecf20Sopenharmony_ci /* XXDEBUG(("bmac: enter open\n")); */ 13808c2ecf20Sopenharmony_ci /* reset the chip */ 13818c2ecf20Sopenharmony_ci bp->opened = 1; 13828c2ecf20Sopenharmony_ci bmac_reset_and_enable(dev); 13838c2ecf20Sopenharmony_ci enable_irq(dev->irq); 13848c2ecf20Sopenharmony_ci return 0; 13858c2ecf20Sopenharmony_ci} 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_cistatic int bmac_close(struct net_device *dev) 13888c2ecf20Sopenharmony_ci{ 13898c2ecf20Sopenharmony_ci struct bmac_data *bp = netdev_priv(dev); 13908c2ecf20Sopenharmony_ci volatile struct dbdma_regs __iomem *rd = bp->rx_dma; 13918c2ecf20Sopenharmony_ci volatile struct dbdma_regs __iomem *td = bp->tx_dma; 13928c2ecf20Sopenharmony_ci unsigned short config; 13938c2ecf20Sopenharmony_ci int i; 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci bp->sleeping = 1; 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci /* disable rx and tx */ 13988c2ecf20Sopenharmony_ci config = bmread(dev, RXCFG); 13998c2ecf20Sopenharmony_ci bmwrite(dev, RXCFG, (config & ~RxMACEnable)); 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci config = bmread(dev, TXCFG); 14028c2ecf20Sopenharmony_ci bmwrite(dev, TXCFG, (config & ~TxMACEnable)); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci bmwrite(dev, INTDISABLE, DisableAll); /* disable all intrs */ 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci /* disable rx and tx dma */ 14078c2ecf20Sopenharmony_ci rd->control = cpu_to_le32(DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE)); /* clear run bit */ 14088c2ecf20Sopenharmony_ci td->control = cpu_to_le32(DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE)); /* clear run bit */ 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci /* free some skb's */ 14118c2ecf20Sopenharmony_ci XXDEBUG(("bmac: free rx bufs\n")); 14128c2ecf20Sopenharmony_ci for (i=0; i<N_RX_RING; i++) { 14138c2ecf20Sopenharmony_ci if (bp->rx_bufs[i] != NULL) { 14148c2ecf20Sopenharmony_ci dev_kfree_skb(bp->rx_bufs[i]); 14158c2ecf20Sopenharmony_ci bp->rx_bufs[i] = NULL; 14168c2ecf20Sopenharmony_ci } 14178c2ecf20Sopenharmony_ci } 14188c2ecf20Sopenharmony_ci XXDEBUG(("bmac: free tx bufs\n")); 14198c2ecf20Sopenharmony_ci for (i = 0; i<N_TX_RING; i++) { 14208c2ecf20Sopenharmony_ci if (bp->tx_bufs[i] != NULL) { 14218c2ecf20Sopenharmony_ci dev_kfree_skb(bp->tx_bufs[i]); 14228c2ecf20Sopenharmony_ci bp->tx_bufs[i] = NULL; 14238c2ecf20Sopenharmony_ci } 14248c2ecf20Sopenharmony_ci } 14258c2ecf20Sopenharmony_ci XXDEBUG(("bmac: all bufs freed\n")); 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci bp->opened = 0; 14288c2ecf20Sopenharmony_ci disable_irq(dev->irq); 14298c2ecf20Sopenharmony_ci pmac_call_feature(PMAC_FTR_BMAC_ENABLE, macio_get_of_node(bp->mdev), 0, 0); 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci return 0; 14328c2ecf20Sopenharmony_ci} 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_cistatic void 14358c2ecf20Sopenharmony_cibmac_start(struct net_device *dev) 14368c2ecf20Sopenharmony_ci{ 14378c2ecf20Sopenharmony_ci struct bmac_data *bp = netdev_priv(dev); 14388c2ecf20Sopenharmony_ci int i; 14398c2ecf20Sopenharmony_ci struct sk_buff *skb; 14408c2ecf20Sopenharmony_ci unsigned long flags; 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci if (bp->sleeping) 14438c2ecf20Sopenharmony_ci return; 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 14468c2ecf20Sopenharmony_ci while (1) { 14478c2ecf20Sopenharmony_ci i = bp->tx_fill + 1; 14488c2ecf20Sopenharmony_ci if (i >= N_TX_RING) 14498c2ecf20Sopenharmony_ci i = 0; 14508c2ecf20Sopenharmony_ci if (i == bp->tx_empty) 14518c2ecf20Sopenharmony_ci break; 14528c2ecf20Sopenharmony_ci skb = skb_dequeue(bp->queue); 14538c2ecf20Sopenharmony_ci if (skb == NULL) 14548c2ecf20Sopenharmony_ci break; 14558c2ecf20Sopenharmony_ci bmac_transmit_packet(skb, dev); 14568c2ecf20Sopenharmony_ci } 14578c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 14588c2ecf20Sopenharmony_ci} 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_cistatic netdev_tx_t 14618c2ecf20Sopenharmony_cibmac_output(struct sk_buff *skb, struct net_device *dev) 14628c2ecf20Sopenharmony_ci{ 14638c2ecf20Sopenharmony_ci struct bmac_data *bp = netdev_priv(dev); 14648c2ecf20Sopenharmony_ci skb_queue_tail(bp->queue, skb); 14658c2ecf20Sopenharmony_ci bmac_start(dev); 14668c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 14678c2ecf20Sopenharmony_ci} 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_cistatic void bmac_tx_timeout(struct timer_list *t) 14708c2ecf20Sopenharmony_ci{ 14718c2ecf20Sopenharmony_ci struct bmac_data *bp = from_timer(bp, t, tx_timeout); 14728c2ecf20Sopenharmony_ci struct net_device *dev = macio_get_drvdata(bp->mdev); 14738c2ecf20Sopenharmony_ci volatile struct dbdma_regs __iomem *td = bp->tx_dma; 14748c2ecf20Sopenharmony_ci volatile struct dbdma_regs __iomem *rd = bp->rx_dma; 14758c2ecf20Sopenharmony_ci volatile struct dbdma_cmd *cp; 14768c2ecf20Sopenharmony_ci unsigned long flags; 14778c2ecf20Sopenharmony_ci unsigned short config, oldConfig; 14788c2ecf20Sopenharmony_ci int i; 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci XXDEBUG(("bmac: tx_timeout called\n")); 14818c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->lock, flags); 14828c2ecf20Sopenharmony_ci bp->timeout_active = 0; 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci /* update various counters */ 14858c2ecf20Sopenharmony_ci/* bmac_handle_misc_intrs(bp, 0); */ 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci cp = &bp->tx_cmds[bp->tx_empty]; 14888c2ecf20Sopenharmony_ci/* XXDEBUG((KERN_DEBUG "bmac: tx dmastat=%x %x runt=%d pr=%x fs=%x fc=%x\n", */ 14898c2ecf20Sopenharmony_ci/* le32_to_cpu(td->status), le16_to_cpu(cp->xfer_status), bp->tx_bad_runt, */ 14908c2ecf20Sopenharmony_ci/* mb->pr, mb->xmtfs, mb->fifofc)); */ 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci /* turn off both tx and rx and reset the chip */ 14938c2ecf20Sopenharmony_ci config = bmread(dev, RXCFG); 14948c2ecf20Sopenharmony_ci bmwrite(dev, RXCFG, (config & ~RxMACEnable)); 14958c2ecf20Sopenharmony_ci config = bmread(dev, TXCFG); 14968c2ecf20Sopenharmony_ci bmwrite(dev, TXCFG, (config & ~TxMACEnable)); 14978c2ecf20Sopenharmony_ci out_le32(&td->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD)); 14988c2ecf20Sopenharmony_ci printk(KERN_ERR "bmac: transmit timeout - resetting\n"); 14998c2ecf20Sopenharmony_ci bmac_enable_and_reset_chip(dev); 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci /* restart rx dma */ 15028c2ecf20Sopenharmony_ci cp = bus_to_virt(le32_to_cpu(rd->cmdptr)); 15038c2ecf20Sopenharmony_ci out_le32(&rd->control, DBDMA_CLEAR(RUN|PAUSE|FLUSH|WAKE|ACTIVE|DEAD)); 15048c2ecf20Sopenharmony_ci out_le16(&cp->xfer_status, 0); 15058c2ecf20Sopenharmony_ci out_le32(&rd->cmdptr, virt_to_bus(cp)); 15068c2ecf20Sopenharmony_ci out_le32(&rd->control, DBDMA_SET(RUN|WAKE)); 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci /* fix up the transmit side */ 15098c2ecf20Sopenharmony_ci XXDEBUG((KERN_DEBUG "bmac: tx empty=%d fill=%d fullup=%d\n", 15108c2ecf20Sopenharmony_ci bp->tx_empty, bp->tx_fill, bp->tx_fullup)); 15118c2ecf20Sopenharmony_ci i = bp->tx_empty; 15128c2ecf20Sopenharmony_ci ++dev->stats.tx_errors; 15138c2ecf20Sopenharmony_ci if (i != bp->tx_fill) { 15148c2ecf20Sopenharmony_ci dev_kfree_skb_irq(bp->tx_bufs[i]); 15158c2ecf20Sopenharmony_ci bp->tx_bufs[i] = NULL; 15168c2ecf20Sopenharmony_ci if (++i >= N_TX_RING) i = 0; 15178c2ecf20Sopenharmony_ci bp->tx_empty = i; 15188c2ecf20Sopenharmony_ci } 15198c2ecf20Sopenharmony_ci bp->tx_fullup = 0; 15208c2ecf20Sopenharmony_ci netif_wake_queue(dev); 15218c2ecf20Sopenharmony_ci if (i != bp->tx_fill) { 15228c2ecf20Sopenharmony_ci cp = &bp->tx_cmds[i]; 15238c2ecf20Sopenharmony_ci out_le16(&cp->xfer_status, 0); 15248c2ecf20Sopenharmony_ci out_le16(&cp->command, OUTPUT_LAST); 15258c2ecf20Sopenharmony_ci out_le32(&td->cmdptr, virt_to_bus(cp)); 15268c2ecf20Sopenharmony_ci out_le32(&td->control, DBDMA_SET(RUN)); 15278c2ecf20Sopenharmony_ci /* bmac_set_timeout(dev); */ 15288c2ecf20Sopenharmony_ci XXDEBUG((KERN_DEBUG "bmac: starting %d\n", i)); 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci /* turn it back on */ 15328c2ecf20Sopenharmony_ci oldConfig = bmread(dev, RXCFG); 15338c2ecf20Sopenharmony_ci bmwrite(dev, RXCFG, oldConfig | RxMACEnable ); 15348c2ecf20Sopenharmony_ci oldConfig = bmread(dev, TXCFG); 15358c2ecf20Sopenharmony_ci bmwrite(dev, TXCFG, oldConfig | TxMACEnable ); 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->lock, flags); 15388c2ecf20Sopenharmony_ci} 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci#if 0 15418c2ecf20Sopenharmony_cistatic void dump_dbdma(volatile struct dbdma_cmd *cp,int count) 15428c2ecf20Sopenharmony_ci{ 15438c2ecf20Sopenharmony_ci int i,*ip; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci for (i=0;i< count;i++) { 15468c2ecf20Sopenharmony_ci ip = (int*)(cp+i); 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci printk("dbdma req 0x%x addr 0x%x baddr 0x%x xfer/res 0x%x\n", 15498c2ecf20Sopenharmony_ci le32_to_cpup(ip+0), 15508c2ecf20Sopenharmony_ci le32_to_cpup(ip+1), 15518c2ecf20Sopenharmony_ci le32_to_cpup(ip+2), 15528c2ecf20Sopenharmony_ci le32_to_cpup(ip+3)); 15538c2ecf20Sopenharmony_ci } 15548c2ecf20Sopenharmony_ci 15558c2ecf20Sopenharmony_ci} 15568c2ecf20Sopenharmony_ci#endif 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ci#if 0 15598c2ecf20Sopenharmony_cistatic int 15608c2ecf20Sopenharmony_cibmac_proc_info(char *buffer, char **start, off_t offset, int length) 15618c2ecf20Sopenharmony_ci{ 15628c2ecf20Sopenharmony_ci int len = 0; 15638c2ecf20Sopenharmony_ci off_t pos = 0; 15648c2ecf20Sopenharmony_ci off_t begin = 0; 15658c2ecf20Sopenharmony_ci int i; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci if (bmac_devs == NULL) 15688c2ecf20Sopenharmony_ci return -ENOSYS; 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci len += sprintf(buffer, "BMAC counters & registers\n"); 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci for (i = 0; i<N_REG_ENTRIES; i++) { 15738c2ecf20Sopenharmony_ci len += sprintf(buffer + len, "%s: %#08x\n", 15748c2ecf20Sopenharmony_ci reg_entries[i].name, 15758c2ecf20Sopenharmony_ci bmread(bmac_devs, reg_entries[i].reg_offset)); 15768c2ecf20Sopenharmony_ci pos = begin + len; 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci if (pos < offset) { 15798c2ecf20Sopenharmony_ci len = 0; 15808c2ecf20Sopenharmony_ci begin = pos; 15818c2ecf20Sopenharmony_ci } 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci if (pos > offset+length) break; 15848c2ecf20Sopenharmony_ci } 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci *start = buffer + (offset - begin); 15878c2ecf20Sopenharmony_ci len -= (offset - begin); 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci if (len > length) len = length; 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_ci return len; 15928c2ecf20Sopenharmony_ci} 15938c2ecf20Sopenharmony_ci#endif 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_cistatic int bmac_remove(struct macio_dev *mdev) 15968c2ecf20Sopenharmony_ci{ 15978c2ecf20Sopenharmony_ci struct net_device *dev = macio_get_drvdata(mdev); 15988c2ecf20Sopenharmony_ci struct bmac_data *bp = netdev_priv(dev); 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci unregister_netdev(dev); 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 16038c2ecf20Sopenharmony_ci free_irq(bp->tx_dma_intr, dev); 16048c2ecf20Sopenharmony_ci free_irq(bp->rx_dma_intr, dev); 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci iounmap((void __iomem *)dev->base_addr); 16078c2ecf20Sopenharmony_ci iounmap(bp->tx_dma); 16088c2ecf20Sopenharmony_ci iounmap(bp->rx_dma); 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci macio_release_resources(mdev); 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci free_netdev(dev); 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci return 0; 16158c2ecf20Sopenharmony_ci} 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_cistatic const struct of_device_id bmac_match[] = 16188c2ecf20Sopenharmony_ci{ 16198c2ecf20Sopenharmony_ci { 16208c2ecf20Sopenharmony_ci .name = "bmac", 16218c2ecf20Sopenharmony_ci .data = (void *)0, 16228c2ecf20Sopenharmony_ci }, 16238c2ecf20Sopenharmony_ci { 16248c2ecf20Sopenharmony_ci .type = "network", 16258c2ecf20Sopenharmony_ci .compatible = "bmac+", 16268c2ecf20Sopenharmony_ci .data = (void *)1, 16278c2ecf20Sopenharmony_ci }, 16288c2ecf20Sopenharmony_ci {}, 16298c2ecf20Sopenharmony_ci}; 16308c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE (of, bmac_match); 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_cistatic struct macio_driver bmac_driver = 16338c2ecf20Sopenharmony_ci{ 16348c2ecf20Sopenharmony_ci .driver = { 16358c2ecf20Sopenharmony_ci .name = "bmac", 16368c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 16378c2ecf20Sopenharmony_ci .of_match_table = bmac_match, 16388c2ecf20Sopenharmony_ci }, 16398c2ecf20Sopenharmony_ci .probe = bmac_probe, 16408c2ecf20Sopenharmony_ci .remove = bmac_remove, 16418c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 16428c2ecf20Sopenharmony_ci .suspend = bmac_suspend, 16438c2ecf20Sopenharmony_ci .resume = bmac_resume, 16448c2ecf20Sopenharmony_ci#endif 16458c2ecf20Sopenharmony_ci}; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_cistatic int __init bmac_init(void) 16498c2ecf20Sopenharmony_ci{ 16508c2ecf20Sopenharmony_ci if (bmac_emergency_rxbuf == NULL) { 16518c2ecf20Sopenharmony_ci bmac_emergency_rxbuf = kmalloc(RX_BUFLEN, GFP_KERNEL); 16528c2ecf20Sopenharmony_ci if (bmac_emergency_rxbuf == NULL) 16538c2ecf20Sopenharmony_ci return -ENOMEM; 16548c2ecf20Sopenharmony_ci } 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci return macio_register_driver(&bmac_driver); 16578c2ecf20Sopenharmony_ci} 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_cistatic void __exit bmac_exit(void) 16608c2ecf20Sopenharmony_ci{ 16618c2ecf20Sopenharmony_ci macio_unregister_driver(&bmac_driver); 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci kfree(bmac_emergency_rxbuf); 16648c2ecf20Sopenharmony_ci bmac_emergency_rxbuf = NULL; 16658c2ecf20Sopenharmony_ci} 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ciMODULE_AUTHOR("Randy Gobbel/Paul Mackerras"); 16688c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PowerMac BMAC ethernet driver."); 16698c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_cimodule_init(bmac_init); 16728c2ecf20Sopenharmony_cimodule_exit(bmac_exit); 1673