18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci    A Davicom DM9102/DM9102A/DM9102A+DM9801/DM9102A+DM9802 NIC fast
48c2ecf20Sopenharmony_ci    ethernet driver for Linux.
58c2ecf20Sopenharmony_ci    Copyright (C) 1997  Sten Wang
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci    DAVICOM Web-Site: www.davicom.com.tw
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci    Author: Sten Wang, 886-3-5798797-8517, E-mail: sten_wang@davicom.com.tw
118c2ecf20Sopenharmony_ci    Maintainer: Tobias Ringstrom <tori@unhappy.mine.nu>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci    (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci    Marcelo Tosatti <marcelo@conectiva.com.br> :
168c2ecf20Sopenharmony_ci    Made it compile in 2.3 (device to net_device)
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci    Alan Cox <alan@lxorguk.ukuu.org.uk> :
198c2ecf20Sopenharmony_ci    Cleaned up for kernel merge.
208c2ecf20Sopenharmony_ci    Removed the back compatibility support
218c2ecf20Sopenharmony_ci    Reformatted, fixing spelling etc as I went
228c2ecf20Sopenharmony_ci    Removed IRQ 0-15 assumption
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci    Jeff Garzik <jgarzik@pobox.com> :
258c2ecf20Sopenharmony_ci    Updated to use new PCI driver API.
268c2ecf20Sopenharmony_ci    Resource usage cleanups.
278c2ecf20Sopenharmony_ci    Report driver version to user.
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci    Tobias Ringstrom <tori@unhappy.mine.nu> :
308c2ecf20Sopenharmony_ci    Cleaned up and added SMP safety.  Thanks go to Jeff Garzik,
318c2ecf20Sopenharmony_ci    Andrew Morton and Frank Davis for the SMP safety fixes.
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci    Vojtech Pavlik <vojtech@suse.cz> :
348c2ecf20Sopenharmony_ci    Cleaned up pointer arithmetics.
358c2ecf20Sopenharmony_ci    Fixed a lot of 64bit issues.
368c2ecf20Sopenharmony_ci    Cleaned up printk()s a bit.
378c2ecf20Sopenharmony_ci    Fixed some obvious big endian problems.
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci    Tobias Ringstrom <tori@unhappy.mine.nu> :
408c2ecf20Sopenharmony_ci    Use time_after for jiffies calculation.  Added ethtool
418c2ecf20Sopenharmony_ci    support.  Updated PCI resource allocation.  Do not
428c2ecf20Sopenharmony_ci    forget to unmap PCI mapped skbs.
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci    Alan Cox <alan@lxorguk.ukuu.org.uk>
458c2ecf20Sopenharmony_ci    Added new PCI identifiers provided by Clear Zhang at ALi
468c2ecf20Sopenharmony_ci    for their 1563 ethernet device.
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci    TODO
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci    Check on 64 bit boxes.
518c2ecf20Sopenharmony_ci    Check and fix on big endian boxes.
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci    Test and make sure PCI latency is now correct for all cases.
548c2ecf20Sopenharmony_ci*/
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#define DRV_NAME	"dmfe"
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#include <linux/module.h>
618c2ecf20Sopenharmony_ci#include <linux/kernel.h>
628c2ecf20Sopenharmony_ci#include <linux/string.h>
638c2ecf20Sopenharmony_ci#include <linux/timer.h>
648c2ecf20Sopenharmony_ci#include <linux/ptrace.h>
658c2ecf20Sopenharmony_ci#include <linux/errno.h>
668c2ecf20Sopenharmony_ci#include <linux/ioport.h>
678c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
688c2ecf20Sopenharmony_ci#include <linux/pci.h>
698c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
708c2ecf20Sopenharmony_ci#include <linux/init.h>
718c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
728c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
738c2ecf20Sopenharmony_ci#include <linux/ethtool.h>
748c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
758c2ecf20Sopenharmony_ci#include <linux/delay.h>
768c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
778c2ecf20Sopenharmony_ci#include <linux/crc32.h>
788c2ecf20Sopenharmony_ci#include <linux/bitops.h>
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci#include <asm/processor.h>
818c2ecf20Sopenharmony_ci#include <asm/io.h>
828c2ecf20Sopenharmony_ci#include <asm/dma.h>
838c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
848c2ecf20Sopenharmony_ci#include <asm/irq.h>
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#ifdef CONFIG_TULIP_DM910X
878c2ecf20Sopenharmony_ci#include <linux/of.h>
888c2ecf20Sopenharmony_ci#endif
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci/* Board/System/Debug information/definition ---------------- */
928c2ecf20Sopenharmony_ci#define PCI_DM9132_ID   0x91321282      /* Davicom DM9132 ID */
938c2ecf20Sopenharmony_ci#define PCI_DM9102_ID   0x91021282      /* Davicom DM9102 ID */
948c2ecf20Sopenharmony_ci#define PCI_DM9100_ID   0x91001282      /* Davicom DM9100 ID */
958c2ecf20Sopenharmony_ci#define PCI_DM9009_ID   0x90091282      /* Davicom DM9009 ID */
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci#define DM9102_IO_SIZE  0x80
988c2ecf20Sopenharmony_ci#define DM9102A_IO_SIZE 0x100
998c2ecf20Sopenharmony_ci#define TX_MAX_SEND_CNT 0x1             /* Maximum tx packet per time */
1008c2ecf20Sopenharmony_ci#define TX_DESC_CNT     0x10            /* Allocated Tx descriptors */
1018c2ecf20Sopenharmony_ci#define RX_DESC_CNT     0x20            /* Allocated Rx descriptors */
1028c2ecf20Sopenharmony_ci#define TX_FREE_DESC_CNT (TX_DESC_CNT - 2)	/* Max TX packet count */
1038c2ecf20Sopenharmony_ci#define TX_WAKE_DESC_CNT (TX_DESC_CNT - 3)	/* TX wakeup count */
1048c2ecf20Sopenharmony_ci#define DESC_ALL_CNT    (TX_DESC_CNT + RX_DESC_CNT)
1058c2ecf20Sopenharmony_ci#define TX_BUF_ALLOC    0x600
1068c2ecf20Sopenharmony_ci#define RX_ALLOC_SIZE   0x620
1078c2ecf20Sopenharmony_ci#define DM910X_RESET    1
1088c2ecf20Sopenharmony_ci#define CR0_DEFAULT     0x00E00000      /* TX & RX burst mode */
1098c2ecf20Sopenharmony_ci#define CR6_DEFAULT     0x00080000      /* HD */
1108c2ecf20Sopenharmony_ci#define CR7_DEFAULT     0x180c1
1118c2ecf20Sopenharmony_ci#define CR15_DEFAULT    0x06            /* TxJabber RxWatchdog */
1128c2ecf20Sopenharmony_ci#define TDES0_ERR_MASK  0x4302          /* TXJT, LC, EC, FUE */
1138c2ecf20Sopenharmony_ci#define MAX_PACKET_SIZE 1514
1148c2ecf20Sopenharmony_ci#define DMFE_MAX_MULTICAST 14
1158c2ecf20Sopenharmony_ci#define RX_COPY_SIZE	100
1168c2ecf20Sopenharmony_ci#define MAX_CHECK_PACKET 0x8000
1178c2ecf20Sopenharmony_ci#define DM9801_NOISE_FLOOR 8
1188c2ecf20Sopenharmony_ci#define DM9802_NOISE_FLOOR 5
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci#define DMFE_WOL_LINKCHANGE	0x20000000
1218c2ecf20Sopenharmony_ci#define DMFE_WOL_SAMPLEPACKET	0x10000000
1228c2ecf20Sopenharmony_ci#define DMFE_WOL_MAGICPACKET	0x08000000
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci#define DMFE_10MHF      0
1268c2ecf20Sopenharmony_ci#define DMFE_100MHF     1
1278c2ecf20Sopenharmony_ci#define DMFE_10MFD      4
1288c2ecf20Sopenharmony_ci#define DMFE_100MFD     5
1298c2ecf20Sopenharmony_ci#define DMFE_AUTO       8
1308c2ecf20Sopenharmony_ci#define DMFE_1M_HPNA    0x10
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci#define DMFE_TXTH_72	0x400000	/* TX TH 72 byte */
1338c2ecf20Sopenharmony_ci#define DMFE_TXTH_96	0x404000	/* TX TH 96 byte */
1348c2ecf20Sopenharmony_ci#define DMFE_TXTH_128	0x0000		/* TX TH 128 byte */
1358c2ecf20Sopenharmony_ci#define DMFE_TXTH_256	0x4000		/* TX TH 256 byte */
1368c2ecf20Sopenharmony_ci#define DMFE_TXTH_512	0x8000		/* TX TH 512 byte */
1378c2ecf20Sopenharmony_ci#define DMFE_TXTH_1K	0xC000		/* TX TH 1K  byte */
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci#define DMFE_TIMER_WUT  (jiffies + HZ * 1)/* timer wakeup time : 1 second */
1408c2ecf20Sopenharmony_ci#define DMFE_TX_TIMEOUT ((3*HZ)/2)	/* tx packet time-out time 1.5 s" */
1418c2ecf20Sopenharmony_ci#define DMFE_TX_KICK 	(HZ/2)	/* tx packet Kick-out time 0.5 s" */
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci#define dw32(reg, val)	iowrite32(val, ioaddr + (reg))
1448c2ecf20Sopenharmony_ci#define dw16(reg, val)	iowrite16(val, ioaddr + (reg))
1458c2ecf20Sopenharmony_ci#define dr32(reg)	ioread32(ioaddr + (reg))
1468c2ecf20Sopenharmony_ci#define dr16(reg)	ioread16(ioaddr + (reg))
1478c2ecf20Sopenharmony_ci#define dr8(reg)	ioread8(ioaddr + (reg))
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci#define DMFE_DBUG(dbug_now, msg, value)			\
1508c2ecf20Sopenharmony_ci	do {						\
1518c2ecf20Sopenharmony_ci		if (dmfe_debug || (dbug_now))		\
1528c2ecf20Sopenharmony_ci			pr_err("%s %lx\n",		\
1538c2ecf20Sopenharmony_ci			       (msg), (long) (value));	\
1548c2ecf20Sopenharmony_ci	} while (0)
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci#define SHOW_MEDIA_TYPE(mode)				\
1578c2ecf20Sopenharmony_ci	pr_info("Change Speed to %sMhz %s duplex\n" ,	\
1588c2ecf20Sopenharmony_ci		(mode & 1) ? "100":"10",		\
1598c2ecf20Sopenharmony_ci		(mode & 4) ? "full":"half");
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci/* CR9 definition: SROM/MII */
1638c2ecf20Sopenharmony_ci#define CR9_SROM_READ   0x4800
1648c2ecf20Sopenharmony_ci#define CR9_SRCS        0x1
1658c2ecf20Sopenharmony_ci#define CR9_SRCLK       0x2
1668c2ecf20Sopenharmony_ci#define CR9_CRDOUT      0x8
1678c2ecf20Sopenharmony_ci#define SROM_DATA_0     0x0
1688c2ecf20Sopenharmony_ci#define SROM_DATA_1     0x4
1698c2ecf20Sopenharmony_ci#define PHY_DATA_1      0x20000
1708c2ecf20Sopenharmony_ci#define PHY_DATA_0      0x00000
1718c2ecf20Sopenharmony_ci#define MDCLKH          0x10000
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci#define PHY_POWER_DOWN	0x800
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci#define SROM_V41_CODE   0x14
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci#define __CHK_IO_SIZE(pci_id, dev_rev) \
1788c2ecf20Sopenharmony_ci (( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x30) ) ? \
1798c2ecf20Sopenharmony_ci	DM9102A_IO_SIZE: DM9102_IO_SIZE)
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci#define CHK_IO_SIZE(pci_dev) \
1828c2ecf20Sopenharmony_ci	(__CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, \
1838c2ecf20Sopenharmony_ci	(pci_dev)->revision))
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci/* Structure/enum declaration ------------------------------- */
1868c2ecf20Sopenharmony_cistruct tx_desc {
1878c2ecf20Sopenharmony_ci        __le32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */
1888c2ecf20Sopenharmony_ci        char *tx_buf_ptr;               /* Data for us */
1898c2ecf20Sopenharmony_ci        struct tx_desc *next_tx_desc;
1908c2ecf20Sopenharmony_ci} __attribute__(( aligned(32) ));
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cistruct rx_desc {
1938c2ecf20Sopenharmony_ci	__le32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */
1948c2ecf20Sopenharmony_ci	struct sk_buff *rx_skb_ptr;	/* Data for us */
1958c2ecf20Sopenharmony_ci	struct rx_desc *next_rx_desc;
1968c2ecf20Sopenharmony_ci} __attribute__(( aligned(32) ));
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistruct dmfe_board_info {
1998c2ecf20Sopenharmony_ci	u32 chip_id;			/* Chip vendor/Device ID */
2008c2ecf20Sopenharmony_ci	u8 chip_revision;		/* Chip revision */
2018c2ecf20Sopenharmony_ci	struct net_device *next_dev;	/* next device */
2028c2ecf20Sopenharmony_ci	struct pci_dev *pdev;		/* PCI device */
2038c2ecf20Sopenharmony_ci	spinlock_t lock;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	void __iomem *ioaddr;		/* I/O base address */
2068c2ecf20Sopenharmony_ci	u32 cr0_data;
2078c2ecf20Sopenharmony_ci	u32 cr5_data;
2088c2ecf20Sopenharmony_ci	u32 cr6_data;
2098c2ecf20Sopenharmony_ci	u32 cr7_data;
2108c2ecf20Sopenharmony_ci	u32 cr15_data;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	/* pointer for memory physical address */
2138c2ecf20Sopenharmony_ci	dma_addr_t buf_pool_dma_ptr;	/* Tx buffer pool memory */
2148c2ecf20Sopenharmony_ci	dma_addr_t buf_pool_dma_start;	/* Tx buffer pool align dword */
2158c2ecf20Sopenharmony_ci	dma_addr_t desc_pool_dma_ptr;	/* descriptor pool memory */
2168c2ecf20Sopenharmony_ci	dma_addr_t first_tx_desc_dma;
2178c2ecf20Sopenharmony_ci	dma_addr_t first_rx_desc_dma;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	/* descriptor pointer */
2208c2ecf20Sopenharmony_ci	unsigned char *buf_pool_ptr;	/* Tx buffer pool memory */
2218c2ecf20Sopenharmony_ci	unsigned char *buf_pool_start;	/* Tx buffer pool align dword */
2228c2ecf20Sopenharmony_ci	unsigned char *desc_pool_ptr;	/* descriptor pool memory */
2238c2ecf20Sopenharmony_ci	struct tx_desc *first_tx_desc;
2248c2ecf20Sopenharmony_ci	struct tx_desc *tx_insert_ptr;
2258c2ecf20Sopenharmony_ci	struct tx_desc *tx_remove_ptr;
2268c2ecf20Sopenharmony_ci	struct rx_desc *first_rx_desc;
2278c2ecf20Sopenharmony_ci	struct rx_desc *rx_insert_ptr;
2288c2ecf20Sopenharmony_ci	struct rx_desc *rx_ready_ptr;	/* packet come pointer */
2298c2ecf20Sopenharmony_ci	unsigned long tx_packet_cnt;	/* transmitted packet count */
2308c2ecf20Sopenharmony_ci	unsigned long tx_queue_cnt;	/* wait to send packet count */
2318c2ecf20Sopenharmony_ci	unsigned long rx_avail_cnt;	/* available rx descriptor count */
2328c2ecf20Sopenharmony_ci	unsigned long interval_rx_cnt;	/* rx packet count a callback time */
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	u16 HPNA_command;		/* For HPNA register 16 */
2358c2ecf20Sopenharmony_ci	u16 HPNA_timer;			/* For HPNA remote device check */
2368c2ecf20Sopenharmony_ci	u16 dbug_cnt;
2378c2ecf20Sopenharmony_ci	u16 NIC_capability;		/* NIC media capability */
2388c2ecf20Sopenharmony_ci	u16 PHY_reg4;			/* Saved Phyxcer register 4 value */
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	u8 HPNA_present;		/* 0:none, 1:DM9801, 2:DM9802 */
2418c2ecf20Sopenharmony_ci	u8 chip_type;			/* Keep DM9102A chip type */
2428c2ecf20Sopenharmony_ci	u8 media_mode;			/* user specify media mode */
2438c2ecf20Sopenharmony_ci	u8 op_mode;			/* real work media mode */
2448c2ecf20Sopenharmony_ci	u8 phy_addr;
2458c2ecf20Sopenharmony_ci	u8 wait_reset;			/* Hardware failed, need to reset */
2468c2ecf20Sopenharmony_ci	u8 dm910x_chk_mode;		/* Operating mode check */
2478c2ecf20Sopenharmony_ci	u8 first_in_callback;		/* Flag to record state */
2488c2ecf20Sopenharmony_ci	u8 wol_mode;			/* user WOL settings */
2498c2ecf20Sopenharmony_ci	struct timer_list timer;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	/* Driver defined statistic counter */
2528c2ecf20Sopenharmony_ci	unsigned long tx_fifo_underrun;
2538c2ecf20Sopenharmony_ci	unsigned long tx_loss_carrier;
2548c2ecf20Sopenharmony_ci	unsigned long tx_no_carrier;
2558c2ecf20Sopenharmony_ci	unsigned long tx_late_collision;
2568c2ecf20Sopenharmony_ci	unsigned long tx_excessive_collision;
2578c2ecf20Sopenharmony_ci	unsigned long tx_jabber_timeout;
2588c2ecf20Sopenharmony_ci	unsigned long reset_count;
2598c2ecf20Sopenharmony_ci	unsigned long reset_cr8;
2608c2ecf20Sopenharmony_ci	unsigned long reset_fatal;
2618c2ecf20Sopenharmony_ci	unsigned long reset_TXtimeout;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	/* NIC SROM data */
2648c2ecf20Sopenharmony_ci	unsigned char srom[128];
2658c2ecf20Sopenharmony_ci};
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_cienum dmfe_offsets {
2688c2ecf20Sopenharmony_ci	DCR0 = 0x00, DCR1 = 0x08, DCR2 = 0x10, DCR3 = 0x18, DCR4 = 0x20,
2698c2ecf20Sopenharmony_ci	DCR5 = 0x28, DCR6 = 0x30, DCR7 = 0x38, DCR8 = 0x40, DCR9 = 0x48,
2708c2ecf20Sopenharmony_ci	DCR10 = 0x50, DCR11 = 0x58, DCR12 = 0x60, DCR13 = 0x68, DCR14 = 0x70,
2718c2ecf20Sopenharmony_ci	DCR15 = 0x78
2728c2ecf20Sopenharmony_ci};
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cienum dmfe_CR6_bits {
2758c2ecf20Sopenharmony_ci	CR6_RXSC = 0x2, CR6_PBF = 0x8, CR6_PM = 0x40, CR6_PAM = 0x80,
2768c2ecf20Sopenharmony_ci	CR6_FDM = 0x200, CR6_TXSC = 0x2000, CR6_STI = 0x100000,
2778c2ecf20Sopenharmony_ci	CR6_SFT = 0x200000, CR6_RXA = 0x40000000, CR6_NO_PURGE = 0x20000000
2788c2ecf20Sopenharmony_ci};
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci/* Global variable declaration ----------------------------- */
2818c2ecf20Sopenharmony_cistatic int dmfe_debug;
2828c2ecf20Sopenharmony_cistatic unsigned char dmfe_media_mode = DMFE_AUTO;
2838c2ecf20Sopenharmony_cistatic u32 dmfe_cr6_user_set;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci/* For module input parameter */
2868c2ecf20Sopenharmony_cistatic int debug;
2878c2ecf20Sopenharmony_cistatic u32 cr6set;
2888c2ecf20Sopenharmony_cistatic unsigned char mode = 8;
2898c2ecf20Sopenharmony_cistatic u8 chkmode = 1;
2908c2ecf20Sopenharmony_cistatic u8 HPNA_mode;		/* Default: Low Power/High Speed */
2918c2ecf20Sopenharmony_cistatic u8 HPNA_rx_cmd;		/* Default: Disable Rx remote command */
2928c2ecf20Sopenharmony_cistatic u8 HPNA_tx_cmd;		/* Default: Don't issue remote command */
2938c2ecf20Sopenharmony_cistatic u8 HPNA_NoiseFloor;	/* Default: HPNA NoiseFloor */
2948c2ecf20Sopenharmony_cistatic u8 SF_mode;		/* Special Function: 1:VLAN, 2:RX Flow Control
2958c2ecf20Sopenharmony_ci				   4: TX pause packet */
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci/* function declaration ------------------------------------- */
2998c2ecf20Sopenharmony_cistatic int dmfe_open(struct net_device *);
3008c2ecf20Sopenharmony_cistatic netdev_tx_t dmfe_start_xmit(struct sk_buff *, struct net_device *);
3018c2ecf20Sopenharmony_cistatic int dmfe_stop(struct net_device *);
3028c2ecf20Sopenharmony_cistatic void dmfe_set_filter_mode(struct net_device *);
3038c2ecf20Sopenharmony_cistatic const struct ethtool_ops netdev_ethtool_ops;
3048c2ecf20Sopenharmony_cistatic u16 read_srom_word(void __iomem *, int);
3058c2ecf20Sopenharmony_cistatic irqreturn_t dmfe_interrupt(int , void *);
3068c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
3078c2ecf20Sopenharmony_cistatic void poll_dmfe (struct net_device *dev);
3088c2ecf20Sopenharmony_ci#endif
3098c2ecf20Sopenharmony_cistatic void dmfe_descriptor_init(struct net_device *);
3108c2ecf20Sopenharmony_cistatic void allocate_rx_buffer(struct net_device *);
3118c2ecf20Sopenharmony_cistatic void update_cr6(u32, void __iomem *);
3128c2ecf20Sopenharmony_cistatic void send_filter_frame(struct net_device *);
3138c2ecf20Sopenharmony_cistatic void dm9132_id_table(struct net_device *);
3148c2ecf20Sopenharmony_cistatic u16 dmfe_phy_read(void __iomem *, u8, u8, u32);
3158c2ecf20Sopenharmony_cistatic void dmfe_phy_write(void __iomem *, u8, u8, u16, u32);
3168c2ecf20Sopenharmony_cistatic void dmfe_phy_write_1bit(void __iomem *, u32);
3178c2ecf20Sopenharmony_cistatic u16 dmfe_phy_read_1bit(void __iomem *);
3188c2ecf20Sopenharmony_cistatic u8 dmfe_sense_speed(struct dmfe_board_info *);
3198c2ecf20Sopenharmony_cistatic void dmfe_process_mode(struct dmfe_board_info *);
3208c2ecf20Sopenharmony_cistatic void dmfe_timer(struct timer_list *);
3218c2ecf20Sopenharmony_cistatic inline u32 cal_CRC(unsigned char *, unsigned int, u8);
3228c2ecf20Sopenharmony_cistatic void dmfe_rx_packet(struct net_device *, struct dmfe_board_info *);
3238c2ecf20Sopenharmony_cistatic void dmfe_free_tx_pkt(struct net_device *, struct dmfe_board_info *);
3248c2ecf20Sopenharmony_cistatic void dmfe_reuse_skb(struct dmfe_board_info *, struct sk_buff *);
3258c2ecf20Sopenharmony_cistatic void dmfe_dynamic_reset(struct net_device *);
3268c2ecf20Sopenharmony_cistatic void dmfe_free_rxbuffer(struct dmfe_board_info *);
3278c2ecf20Sopenharmony_cistatic void dmfe_init_dm910x(struct net_device *);
3288c2ecf20Sopenharmony_cistatic void dmfe_parse_srom(struct dmfe_board_info *);
3298c2ecf20Sopenharmony_cistatic void dmfe_program_DM9801(struct dmfe_board_info *, int);
3308c2ecf20Sopenharmony_cistatic void dmfe_program_DM9802(struct dmfe_board_info *);
3318c2ecf20Sopenharmony_cistatic void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * );
3328c2ecf20Sopenharmony_cistatic void dmfe_set_phyxcer(struct dmfe_board_info *);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci/* DM910X network board routine ---------------------------- */
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_cistatic const struct net_device_ops netdev_ops = {
3378c2ecf20Sopenharmony_ci	.ndo_open 		= dmfe_open,
3388c2ecf20Sopenharmony_ci	.ndo_stop		= dmfe_stop,
3398c2ecf20Sopenharmony_ci	.ndo_start_xmit		= dmfe_start_xmit,
3408c2ecf20Sopenharmony_ci	.ndo_set_rx_mode	= dmfe_set_filter_mode,
3418c2ecf20Sopenharmony_ci	.ndo_set_mac_address	= eth_mac_addr,
3428c2ecf20Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
3438c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
3448c2ecf20Sopenharmony_ci	.ndo_poll_controller	= poll_dmfe,
3458c2ecf20Sopenharmony_ci#endif
3468c2ecf20Sopenharmony_ci};
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci/*
3498c2ecf20Sopenharmony_ci *	Search DM910X board ,allocate space and register it
3508c2ecf20Sopenharmony_ci */
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_cistatic int dmfe_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	struct dmfe_board_info *db;	/* board information structure */
3558c2ecf20Sopenharmony_ci	struct net_device *dev;
3568c2ecf20Sopenharmony_ci	u32 pci_pmr;
3578c2ecf20Sopenharmony_ci	int i, err;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	DMFE_DBUG(0, "dmfe_init_one()", 0);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	/*
3628c2ecf20Sopenharmony_ci	 *	SPARC on-board DM910x chips should be handled by the main
3638c2ecf20Sopenharmony_ci	 *	tulip driver, except for early DM9100s.
3648c2ecf20Sopenharmony_ci	 */
3658c2ecf20Sopenharmony_ci#ifdef CONFIG_TULIP_DM910X
3668c2ecf20Sopenharmony_ci	if ((ent->driver_data == PCI_DM9100_ID && pdev->revision >= 0x30) ||
3678c2ecf20Sopenharmony_ci	    ent->driver_data == PCI_DM9102_ID) {
3688c2ecf20Sopenharmony_ci		struct device_node *dp = pci_device_to_OF_node(pdev);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci		if (dp && of_get_property(dp, "local-mac-address", NULL)) {
3718c2ecf20Sopenharmony_ci			pr_info("skipping on-board DM910x (use tulip)\n");
3728c2ecf20Sopenharmony_ci			return -ENODEV;
3738c2ecf20Sopenharmony_ci		}
3748c2ecf20Sopenharmony_ci	}
3758c2ecf20Sopenharmony_ci#endif
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	/* Init network device */
3788c2ecf20Sopenharmony_ci	dev = alloc_etherdev(sizeof(*db));
3798c2ecf20Sopenharmony_ci	if (dev == NULL)
3808c2ecf20Sopenharmony_ci		return -ENOMEM;
3818c2ecf20Sopenharmony_ci	SET_NETDEV_DEV(dev, &pdev->dev);
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
3848c2ecf20Sopenharmony_ci		pr_warn("32-bit PCI DMA not available\n");
3858c2ecf20Sopenharmony_ci		err = -ENODEV;
3868c2ecf20Sopenharmony_ci		goto err_out_free;
3878c2ecf20Sopenharmony_ci	}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	/* Enable Master/IO access, Disable memory access */
3908c2ecf20Sopenharmony_ci	err = pci_enable_device(pdev);
3918c2ecf20Sopenharmony_ci	if (err)
3928c2ecf20Sopenharmony_ci		goto err_out_free;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	if (!pci_resource_start(pdev, 0)) {
3958c2ecf20Sopenharmony_ci		pr_err("I/O base is zero\n");
3968c2ecf20Sopenharmony_ci		err = -ENODEV;
3978c2ecf20Sopenharmony_ci		goto err_out_disable;
3988c2ecf20Sopenharmony_ci	}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	if (pci_resource_len(pdev, 0) < (CHK_IO_SIZE(pdev)) ) {
4018c2ecf20Sopenharmony_ci		pr_err("Allocated I/O size too small\n");
4028c2ecf20Sopenharmony_ci		err = -ENODEV;
4038c2ecf20Sopenharmony_ci		goto err_out_disable;
4048c2ecf20Sopenharmony_ci	}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci#if 0	/* pci_{enable_device,set_master} sets minimum latency for us now */
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	/* Set Latency Timer 80h */
4098c2ecf20Sopenharmony_ci	/* FIXME: setting values > 32 breaks some SiS 559x stuff.
4108c2ecf20Sopenharmony_ci	   Need a PCI quirk.. */
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);
4138c2ecf20Sopenharmony_ci#endif
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	if (pci_request_regions(pdev, DRV_NAME)) {
4168c2ecf20Sopenharmony_ci		pr_err("Failed to request PCI regions\n");
4178c2ecf20Sopenharmony_ci		err = -ENODEV;
4188c2ecf20Sopenharmony_ci		goto err_out_disable;
4198c2ecf20Sopenharmony_ci	}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	/* Init system & device */
4228c2ecf20Sopenharmony_ci	db = netdev_priv(dev);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	/* Allocate Tx/Rx descriptor memory */
4258c2ecf20Sopenharmony_ci	db->desc_pool_ptr = dma_alloc_coherent(&pdev->dev,
4268c2ecf20Sopenharmony_ci					       sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20,
4278c2ecf20Sopenharmony_ci					       &db->desc_pool_dma_ptr, GFP_KERNEL);
4288c2ecf20Sopenharmony_ci	if (!db->desc_pool_ptr) {
4298c2ecf20Sopenharmony_ci		err = -ENOMEM;
4308c2ecf20Sopenharmony_ci		goto err_out_res;
4318c2ecf20Sopenharmony_ci	}
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	db->buf_pool_ptr = dma_alloc_coherent(&pdev->dev,
4348c2ecf20Sopenharmony_ci					      TX_BUF_ALLOC * TX_DESC_CNT + 4,
4358c2ecf20Sopenharmony_ci					      &db->buf_pool_dma_ptr, GFP_KERNEL);
4368c2ecf20Sopenharmony_ci	if (!db->buf_pool_ptr) {
4378c2ecf20Sopenharmony_ci		err = -ENOMEM;
4388c2ecf20Sopenharmony_ci		goto err_out_free_desc;
4398c2ecf20Sopenharmony_ci	}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	db->first_tx_desc = (struct tx_desc *) db->desc_pool_ptr;
4428c2ecf20Sopenharmony_ci	db->first_tx_desc_dma = db->desc_pool_dma_ptr;
4438c2ecf20Sopenharmony_ci	db->buf_pool_start = db->buf_pool_ptr;
4448c2ecf20Sopenharmony_ci	db->buf_pool_dma_start = db->buf_pool_dma_ptr;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	db->chip_id = ent->driver_data;
4478c2ecf20Sopenharmony_ci	/* IO type range. */
4488c2ecf20Sopenharmony_ci	db->ioaddr = pci_iomap(pdev, 0, 0);
4498c2ecf20Sopenharmony_ci	if (!db->ioaddr) {
4508c2ecf20Sopenharmony_ci		err = -ENOMEM;
4518c2ecf20Sopenharmony_ci		goto err_out_free_buf;
4528c2ecf20Sopenharmony_ci	}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	db->chip_revision = pdev->revision;
4558c2ecf20Sopenharmony_ci	db->wol_mode = 0;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	db->pdev = pdev;
4588c2ecf20Sopenharmony_ci
4598c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, dev);
4608c2ecf20Sopenharmony_ci	dev->netdev_ops = &netdev_ops;
4618c2ecf20Sopenharmony_ci	dev->ethtool_ops = &netdev_ethtool_ops;
4628c2ecf20Sopenharmony_ci	netif_carrier_off(dev);
4638c2ecf20Sopenharmony_ci	spin_lock_init(&db->lock);
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	pci_read_config_dword(pdev, 0x50, &pci_pmr);
4668c2ecf20Sopenharmony_ci	pci_pmr &= 0x70000;
4678c2ecf20Sopenharmony_ci	if ( (pci_pmr == 0x10000) && (db->chip_revision == 0x31) )
4688c2ecf20Sopenharmony_ci		db->chip_type = 1;	/* DM9102A E3 */
4698c2ecf20Sopenharmony_ci	else
4708c2ecf20Sopenharmony_ci		db->chip_type = 0;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	/* read 64 word srom data */
4738c2ecf20Sopenharmony_ci	for (i = 0; i < 64; i++) {
4748c2ecf20Sopenharmony_ci		((__le16 *) db->srom)[i] =
4758c2ecf20Sopenharmony_ci			cpu_to_le16(read_srom_word(db->ioaddr, i));
4768c2ecf20Sopenharmony_ci	}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	/* Set Node address */
4798c2ecf20Sopenharmony_ci	for (i = 0; i < 6; i++)
4808c2ecf20Sopenharmony_ci		dev->dev_addr[i] = db->srom[20 + i];
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	err = register_netdev (dev);
4838c2ecf20Sopenharmony_ci	if (err)
4848c2ecf20Sopenharmony_ci		goto err_out_unmap;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	dev_info(&dev->dev, "Davicom DM%04lx at pci%s, %pM, irq %d\n",
4878c2ecf20Sopenharmony_ci		 ent->driver_data >> 16,
4888c2ecf20Sopenharmony_ci		 pci_name(pdev), dev->dev_addr, pdev->irq);
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	pci_set_master(pdev);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	return 0;
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_cierr_out_unmap:
4958c2ecf20Sopenharmony_ci	pci_iounmap(pdev, db->ioaddr);
4968c2ecf20Sopenharmony_cierr_out_free_buf:
4978c2ecf20Sopenharmony_ci	dma_free_coherent(&pdev->dev, TX_BUF_ALLOC * TX_DESC_CNT + 4,
4988c2ecf20Sopenharmony_ci			  db->buf_pool_ptr, db->buf_pool_dma_ptr);
4998c2ecf20Sopenharmony_cierr_out_free_desc:
5008c2ecf20Sopenharmony_ci	dma_free_coherent(&pdev->dev,
5018c2ecf20Sopenharmony_ci			  sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20,
5028c2ecf20Sopenharmony_ci			  db->desc_pool_ptr, db->desc_pool_dma_ptr);
5038c2ecf20Sopenharmony_cierr_out_res:
5048c2ecf20Sopenharmony_ci	pci_release_regions(pdev);
5058c2ecf20Sopenharmony_cierr_out_disable:
5068c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
5078c2ecf20Sopenharmony_cierr_out_free:
5088c2ecf20Sopenharmony_ci	free_netdev(dev);
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	return err;
5118c2ecf20Sopenharmony_ci}
5128c2ecf20Sopenharmony_ci
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_cistatic void dmfe_remove_one(struct pci_dev *pdev)
5158c2ecf20Sopenharmony_ci{
5168c2ecf20Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(pdev);
5178c2ecf20Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	DMFE_DBUG(0, "dmfe_remove_one()", 0);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci 	if (dev) {
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci		unregister_netdev(dev);
5248c2ecf20Sopenharmony_ci		pci_iounmap(db->pdev, db->ioaddr);
5258c2ecf20Sopenharmony_ci		dma_free_coherent(&db->pdev->dev,
5268c2ecf20Sopenharmony_ci				  sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20,
5278c2ecf20Sopenharmony_ci				  db->desc_pool_ptr, db->desc_pool_dma_ptr);
5288c2ecf20Sopenharmony_ci		dma_free_coherent(&db->pdev->dev,
5298c2ecf20Sopenharmony_ci				  TX_BUF_ALLOC * TX_DESC_CNT + 4,
5308c2ecf20Sopenharmony_ci				  db->buf_pool_ptr, db->buf_pool_dma_ptr);
5318c2ecf20Sopenharmony_ci		pci_release_regions(pdev);
5328c2ecf20Sopenharmony_ci		free_netdev(dev);	/* free board information */
5338c2ecf20Sopenharmony_ci	}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	DMFE_DBUG(0, "dmfe_remove_one() exit", 0);
5368c2ecf20Sopenharmony_ci}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci/*
5408c2ecf20Sopenharmony_ci *	Open the interface.
5418c2ecf20Sopenharmony_ci *	The interface is opened whenever "ifconfig" actives it.
5428c2ecf20Sopenharmony_ci */
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_cistatic int dmfe_open(struct net_device *dev)
5458c2ecf20Sopenharmony_ci{
5468c2ecf20Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
5478c2ecf20Sopenharmony_ci	const int irq = db->pdev->irq;
5488c2ecf20Sopenharmony_ci	int ret;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	DMFE_DBUG(0, "dmfe_open", 0);
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	ret = request_irq(irq, dmfe_interrupt, IRQF_SHARED, dev->name, dev);
5538c2ecf20Sopenharmony_ci	if (ret)
5548c2ecf20Sopenharmony_ci		return ret;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	/* system variable init */
5578c2ecf20Sopenharmony_ci	db->cr6_data = CR6_DEFAULT | dmfe_cr6_user_set;
5588c2ecf20Sopenharmony_ci	db->tx_packet_cnt = 0;
5598c2ecf20Sopenharmony_ci	db->tx_queue_cnt = 0;
5608c2ecf20Sopenharmony_ci	db->rx_avail_cnt = 0;
5618c2ecf20Sopenharmony_ci	db->wait_reset = 0;
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	db->first_in_callback = 0;
5648c2ecf20Sopenharmony_ci	db->NIC_capability = 0xf;	/* All capability*/
5658c2ecf20Sopenharmony_ci	db->PHY_reg4 = 0x1e0;
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	/* CR6 operation mode decision */
5688c2ecf20Sopenharmony_ci	if ( !chkmode || (db->chip_id == PCI_DM9132_ID) ||
5698c2ecf20Sopenharmony_ci		(db->chip_revision >= 0x30) ) {
5708c2ecf20Sopenharmony_ci    		db->cr6_data |= DMFE_TXTH_256;
5718c2ecf20Sopenharmony_ci		db->cr0_data = CR0_DEFAULT;
5728c2ecf20Sopenharmony_ci		db->dm910x_chk_mode=4;		/* Enter the normal mode */
5738c2ecf20Sopenharmony_ci 	} else {
5748c2ecf20Sopenharmony_ci		db->cr6_data |= CR6_SFT;	/* Store & Forward mode */
5758c2ecf20Sopenharmony_ci		db->cr0_data = 0;
5768c2ecf20Sopenharmony_ci		db->dm910x_chk_mode = 1;	/* Enter the check mode */
5778c2ecf20Sopenharmony_ci	}
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	/* Initialize DM910X board */
5808c2ecf20Sopenharmony_ci	dmfe_init_dm910x(dev);
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	/* Active System Interface */
5838c2ecf20Sopenharmony_ci	netif_wake_queue(dev);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	/* set and active a timer process */
5868c2ecf20Sopenharmony_ci	timer_setup(&db->timer, dmfe_timer, 0);
5878c2ecf20Sopenharmony_ci	db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
5888c2ecf20Sopenharmony_ci	add_timer(&db->timer);
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	return 0;
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci/*	Initialize DM910X board
5958c2ecf20Sopenharmony_ci *	Reset DM910X board
5968c2ecf20Sopenharmony_ci *	Initialize TX/Rx descriptor chain structure
5978c2ecf20Sopenharmony_ci *	Send the set-up frame
5988c2ecf20Sopenharmony_ci *	Enable Tx/Rx machine
5998c2ecf20Sopenharmony_ci */
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_cistatic void dmfe_init_dm910x(struct net_device *dev)
6028c2ecf20Sopenharmony_ci{
6038c2ecf20Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
6048c2ecf20Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	DMFE_DBUG(0, "dmfe_init_dm910x()", 0);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	/* Reset DM910x MAC controller */
6098c2ecf20Sopenharmony_ci	dw32(DCR0, DM910X_RESET);	/* RESET MAC */
6108c2ecf20Sopenharmony_ci	udelay(100);
6118c2ecf20Sopenharmony_ci	dw32(DCR0, db->cr0_data);
6128c2ecf20Sopenharmony_ci	udelay(5);
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	/* Phy addr : DM910(A)2/DM9132/9801, phy address = 1 */
6158c2ecf20Sopenharmony_ci	db->phy_addr = 1;
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	/* Parser SROM and media mode */
6188c2ecf20Sopenharmony_ci	dmfe_parse_srom(db);
6198c2ecf20Sopenharmony_ci	db->media_mode = dmfe_media_mode;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	/* RESET Phyxcer Chip by GPR port bit 7 */
6228c2ecf20Sopenharmony_ci	dw32(DCR12, 0x180);		/* Let bit 7 output port */
6238c2ecf20Sopenharmony_ci	if (db->chip_id == PCI_DM9009_ID) {
6248c2ecf20Sopenharmony_ci		dw32(DCR12, 0x80);	/* Issue RESET signal */
6258c2ecf20Sopenharmony_ci		mdelay(300);			/* Delay 300 ms */
6268c2ecf20Sopenharmony_ci	}
6278c2ecf20Sopenharmony_ci	dw32(DCR12, 0x0);	/* Clear RESET signal */
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	/* Process Phyxcer Media Mode */
6308c2ecf20Sopenharmony_ci	if ( !(db->media_mode & 0x10) )	/* Force 1M mode */
6318c2ecf20Sopenharmony_ci		dmfe_set_phyxcer(db);
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	/* Media Mode Process */
6348c2ecf20Sopenharmony_ci	if ( !(db->media_mode & DMFE_AUTO) )
6358c2ecf20Sopenharmony_ci		db->op_mode = db->media_mode; 	/* Force Mode */
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	/* Initialize Transmit/Receive descriptor and CR3/4 */
6388c2ecf20Sopenharmony_ci	dmfe_descriptor_init(dev);
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	/* Init CR6 to program DM910x operation */
6418c2ecf20Sopenharmony_ci	update_cr6(db->cr6_data, ioaddr);
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	/* Send setup frame */
6448c2ecf20Sopenharmony_ci	if (db->chip_id == PCI_DM9132_ID)
6458c2ecf20Sopenharmony_ci		dm9132_id_table(dev);	/* DM9132 */
6468c2ecf20Sopenharmony_ci	else
6478c2ecf20Sopenharmony_ci		send_filter_frame(dev);	/* DM9102/DM9102A */
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	/* Init CR7, interrupt active bit */
6508c2ecf20Sopenharmony_ci	db->cr7_data = CR7_DEFAULT;
6518c2ecf20Sopenharmony_ci	dw32(DCR7, db->cr7_data);
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	/* Init CR15, Tx jabber and Rx watchdog timer */
6548c2ecf20Sopenharmony_ci	dw32(DCR15, db->cr15_data);
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	/* Enable DM910X Tx/Rx function */
6578c2ecf20Sopenharmony_ci	db->cr6_data |= CR6_RXSC | CR6_TXSC | 0x40000;
6588c2ecf20Sopenharmony_ci	update_cr6(db->cr6_data, ioaddr);
6598c2ecf20Sopenharmony_ci}
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci/*
6638c2ecf20Sopenharmony_ci *	Hardware start transmission.
6648c2ecf20Sopenharmony_ci *	Send a packet to media from the upper layer.
6658c2ecf20Sopenharmony_ci */
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_cistatic netdev_tx_t dmfe_start_xmit(struct sk_buff *skb,
6688c2ecf20Sopenharmony_ci					 struct net_device *dev)
6698c2ecf20Sopenharmony_ci{
6708c2ecf20Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
6718c2ecf20Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
6728c2ecf20Sopenharmony_ci	struct tx_desc *txptr;
6738c2ecf20Sopenharmony_ci	unsigned long flags;
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	DMFE_DBUG(0, "dmfe_start_xmit", 0);
6768c2ecf20Sopenharmony_ci
6778c2ecf20Sopenharmony_ci	/* Too large packet check */
6788c2ecf20Sopenharmony_ci	if (skb->len > MAX_PACKET_SIZE) {
6798c2ecf20Sopenharmony_ci		pr_err("big packet = %d\n", (u16)skb->len);
6808c2ecf20Sopenharmony_ci		dev_kfree_skb_any(skb);
6818c2ecf20Sopenharmony_ci		return NETDEV_TX_OK;
6828c2ecf20Sopenharmony_ci	}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	/* Resource flag check */
6858c2ecf20Sopenharmony_ci	netif_stop_queue(dev);
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	spin_lock_irqsave(&db->lock, flags);
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	/* No Tx resource check, it never happen nromally */
6908c2ecf20Sopenharmony_ci	if (db->tx_queue_cnt >= TX_FREE_DESC_CNT) {
6918c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&db->lock, flags);
6928c2ecf20Sopenharmony_ci		pr_err("No Tx resource %ld\n", db->tx_queue_cnt);
6938c2ecf20Sopenharmony_ci		return NETDEV_TX_BUSY;
6948c2ecf20Sopenharmony_ci	}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	/* Disable NIC interrupt */
6978c2ecf20Sopenharmony_ci	dw32(DCR7, 0);
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	/* transmit this packet */
7008c2ecf20Sopenharmony_ci	txptr = db->tx_insert_ptr;
7018c2ecf20Sopenharmony_ci	skb_copy_from_linear_data(skb, txptr->tx_buf_ptr, skb->len);
7028c2ecf20Sopenharmony_ci	txptr->tdes1 = cpu_to_le32(0xe1000000 | skb->len);
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	/* Point to next transmit free descriptor */
7058c2ecf20Sopenharmony_ci	db->tx_insert_ptr = txptr->next_tx_desc;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	/* Transmit Packet Process */
7088c2ecf20Sopenharmony_ci	if ( (!db->tx_queue_cnt) && (db->tx_packet_cnt < TX_MAX_SEND_CNT) ) {
7098c2ecf20Sopenharmony_ci		txptr->tdes0 = cpu_to_le32(0x80000000);	/* Set owner bit */
7108c2ecf20Sopenharmony_ci		db->tx_packet_cnt++;			/* Ready to send */
7118c2ecf20Sopenharmony_ci		dw32(DCR1, 0x1);			/* Issue Tx polling */
7128c2ecf20Sopenharmony_ci		netif_trans_update(dev);		/* saved time stamp */
7138c2ecf20Sopenharmony_ci	} else {
7148c2ecf20Sopenharmony_ci		db->tx_queue_cnt++;			/* queue TX packet */
7158c2ecf20Sopenharmony_ci		dw32(DCR1, 0x1);			/* Issue Tx polling */
7168c2ecf20Sopenharmony_ci	}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	/* Tx resource check */
7198c2ecf20Sopenharmony_ci	if ( db->tx_queue_cnt < TX_FREE_DESC_CNT )
7208c2ecf20Sopenharmony_ci		netif_wake_queue(dev);
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	/* Restore CR7 to enable interrupt */
7238c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&db->lock, flags);
7248c2ecf20Sopenharmony_ci	dw32(DCR7, db->cr7_data);
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	/* free this SKB */
7278c2ecf20Sopenharmony_ci	dev_consume_skb_any(skb);
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
7308c2ecf20Sopenharmony_ci}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci/*
7348c2ecf20Sopenharmony_ci *	Stop the interface.
7358c2ecf20Sopenharmony_ci *	The interface is stopped when it is brought.
7368c2ecf20Sopenharmony_ci */
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_cistatic int dmfe_stop(struct net_device *dev)
7398c2ecf20Sopenharmony_ci{
7408c2ecf20Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
7418c2ecf20Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	DMFE_DBUG(0, "dmfe_stop", 0);
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	/* disable system */
7468c2ecf20Sopenharmony_ci	netif_stop_queue(dev);
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	/* deleted timer */
7498c2ecf20Sopenharmony_ci	del_timer_sync(&db->timer);
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	/* Reset & stop DM910X board */
7528c2ecf20Sopenharmony_ci	dw32(DCR0, DM910X_RESET);
7538c2ecf20Sopenharmony_ci	udelay(100);
7548c2ecf20Sopenharmony_ci	dmfe_phy_write(ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	/* free interrupt */
7578c2ecf20Sopenharmony_ci	free_irq(db->pdev->irq, dev);
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	/* free allocated rx buffer */
7608c2ecf20Sopenharmony_ci	dmfe_free_rxbuffer(db);
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci#if 0
7638c2ecf20Sopenharmony_ci	/* show statistic counter */
7648c2ecf20Sopenharmony_ci	printk("FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n",
7658c2ecf20Sopenharmony_ci	       db->tx_fifo_underrun, db->tx_excessive_collision,
7668c2ecf20Sopenharmony_ci	       db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier,
7678c2ecf20Sopenharmony_ci	       db->tx_jabber_timeout, db->reset_count, db->reset_cr8,
7688c2ecf20Sopenharmony_ci	       db->reset_fatal, db->reset_TXtimeout);
7698c2ecf20Sopenharmony_ci#endif
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	return 0;
7728c2ecf20Sopenharmony_ci}
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci/*
7768c2ecf20Sopenharmony_ci *	DM9102 insterrupt handler
7778c2ecf20Sopenharmony_ci *	receive the packet to upper layer, free the transmitted packet
7788c2ecf20Sopenharmony_ci */
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_cistatic irqreturn_t dmfe_interrupt(int irq, void *dev_id)
7818c2ecf20Sopenharmony_ci{
7828c2ecf20Sopenharmony_ci	struct net_device *dev = dev_id;
7838c2ecf20Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
7848c2ecf20Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
7858c2ecf20Sopenharmony_ci	unsigned long flags;
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	DMFE_DBUG(0, "dmfe_interrupt()", 0);
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	spin_lock_irqsave(&db->lock, flags);
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	/* Got DM910X status */
7928c2ecf20Sopenharmony_ci	db->cr5_data = dr32(DCR5);
7938c2ecf20Sopenharmony_ci	dw32(DCR5, db->cr5_data);
7948c2ecf20Sopenharmony_ci	if ( !(db->cr5_data & 0xc1) ) {
7958c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&db->lock, flags);
7968c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
7978c2ecf20Sopenharmony_ci	}
7988c2ecf20Sopenharmony_ci
7998c2ecf20Sopenharmony_ci	/* Disable all interrupt in CR7 to solve the interrupt edge problem */
8008c2ecf20Sopenharmony_ci	dw32(DCR7, 0);
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci	/* Check system status */
8038c2ecf20Sopenharmony_ci	if (db->cr5_data & 0x2000) {
8048c2ecf20Sopenharmony_ci		/* system bus error happen */
8058c2ecf20Sopenharmony_ci		DMFE_DBUG(1, "System bus error happen. CR5=", db->cr5_data);
8068c2ecf20Sopenharmony_ci		db->reset_fatal++;
8078c2ecf20Sopenharmony_ci		db->wait_reset = 1;	/* Need to RESET */
8088c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&db->lock, flags);
8098c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
8108c2ecf20Sopenharmony_ci	}
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	 /* Received the coming packet */
8138c2ecf20Sopenharmony_ci	if ( (db->cr5_data & 0x40) && db->rx_avail_cnt )
8148c2ecf20Sopenharmony_ci		dmfe_rx_packet(dev, db);
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci	/* reallocate rx descriptor buffer */
8178c2ecf20Sopenharmony_ci	if (db->rx_avail_cnt<RX_DESC_CNT)
8188c2ecf20Sopenharmony_ci		allocate_rx_buffer(dev);
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	/* Free the transmitted descriptor */
8218c2ecf20Sopenharmony_ci	if ( db->cr5_data & 0x01)
8228c2ecf20Sopenharmony_ci		dmfe_free_tx_pkt(dev, db);
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	/* Mode Check */
8258c2ecf20Sopenharmony_ci	if (db->dm910x_chk_mode & 0x2) {
8268c2ecf20Sopenharmony_ci		db->dm910x_chk_mode = 0x4;
8278c2ecf20Sopenharmony_ci		db->cr6_data |= 0x100;
8288c2ecf20Sopenharmony_ci		update_cr6(db->cr6_data, ioaddr);
8298c2ecf20Sopenharmony_ci	}
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	/* Restore CR7 to enable interrupt mask */
8328c2ecf20Sopenharmony_ci	dw32(DCR7, db->cr7_data);
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&db->lock, flags);
8358c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
8368c2ecf20Sopenharmony_ci}
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
8408c2ecf20Sopenharmony_ci/*
8418c2ecf20Sopenharmony_ci * Polling 'interrupt' - used by things like netconsole to send skbs
8428c2ecf20Sopenharmony_ci * without having to re-enable interrupts. It's not called while
8438c2ecf20Sopenharmony_ci * the interrupt routine is executing.
8448c2ecf20Sopenharmony_ci */
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_cistatic void poll_dmfe (struct net_device *dev)
8478c2ecf20Sopenharmony_ci{
8488c2ecf20Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
8498c2ecf20Sopenharmony_ci	const int irq = db->pdev->irq;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	/* disable_irq here is not very nice, but with the lockless
8528c2ecf20Sopenharmony_ci	   interrupt handler we have no other choice. */
8538c2ecf20Sopenharmony_ci	disable_irq(irq);
8548c2ecf20Sopenharmony_ci	dmfe_interrupt (irq, dev);
8558c2ecf20Sopenharmony_ci	enable_irq(irq);
8568c2ecf20Sopenharmony_ci}
8578c2ecf20Sopenharmony_ci#endif
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci/*
8608c2ecf20Sopenharmony_ci *	Free TX resource after TX complete
8618c2ecf20Sopenharmony_ci */
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_cistatic void dmfe_free_tx_pkt(struct net_device *dev, struct dmfe_board_info *db)
8648c2ecf20Sopenharmony_ci{
8658c2ecf20Sopenharmony_ci	struct tx_desc *txptr;
8668c2ecf20Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
8678c2ecf20Sopenharmony_ci	u32 tdes0;
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci	txptr = db->tx_remove_ptr;
8708c2ecf20Sopenharmony_ci	while(db->tx_packet_cnt) {
8718c2ecf20Sopenharmony_ci		tdes0 = le32_to_cpu(txptr->tdes0);
8728c2ecf20Sopenharmony_ci		if (tdes0 & 0x80000000)
8738c2ecf20Sopenharmony_ci			break;
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci		/* A packet sent completed */
8768c2ecf20Sopenharmony_ci		db->tx_packet_cnt--;
8778c2ecf20Sopenharmony_ci		dev->stats.tx_packets++;
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci		/* Transmit statistic counter */
8808c2ecf20Sopenharmony_ci		if ( tdes0 != 0x7fffffff ) {
8818c2ecf20Sopenharmony_ci			dev->stats.collisions += (tdes0 >> 3) & 0xf;
8828c2ecf20Sopenharmony_ci			dev->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff;
8838c2ecf20Sopenharmony_ci			if (tdes0 & TDES0_ERR_MASK) {
8848c2ecf20Sopenharmony_ci				dev->stats.tx_errors++;
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci				if (tdes0 & 0x0002) {	/* UnderRun */
8878c2ecf20Sopenharmony_ci					db->tx_fifo_underrun++;
8888c2ecf20Sopenharmony_ci					if ( !(db->cr6_data & CR6_SFT) ) {
8898c2ecf20Sopenharmony_ci						db->cr6_data = db->cr6_data | CR6_SFT;
8908c2ecf20Sopenharmony_ci						update_cr6(db->cr6_data, ioaddr);
8918c2ecf20Sopenharmony_ci					}
8928c2ecf20Sopenharmony_ci				}
8938c2ecf20Sopenharmony_ci				if (tdes0 & 0x0100)
8948c2ecf20Sopenharmony_ci					db->tx_excessive_collision++;
8958c2ecf20Sopenharmony_ci				if (tdes0 & 0x0200)
8968c2ecf20Sopenharmony_ci					db->tx_late_collision++;
8978c2ecf20Sopenharmony_ci				if (tdes0 & 0x0400)
8988c2ecf20Sopenharmony_ci					db->tx_no_carrier++;
8998c2ecf20Sopenharmony_ci				if (tdes0 & 0x0800)
9008c2ecf20Sopenharmony_ci					db->tx_loss_carrier++;
9018c2ecf20Sopenharmony_ci				if (tdes0 & 0x4000)
9028c2ecf20Sopenharmony_ci					db->tx_jabber_timeout++;
9038c2ecf20Sopenharmony_ci			}
9048c2ecf20Sopenharmony_ci		}
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci    		txptr = txptr->next_tx_desc;
9078c2ecf20Sopenharmony_ci	}/* End of while */
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	/* Update TX remove pointer to next */
9108c2ecf20Sopenharmony_ci	db->tx_remove_ptr = txptr;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	/* Send the Tx packet in queue */
9138c2ecf20Sopenharmony_ci	if ( (db->tx_packet_cnt < TX_MAX_SEND_CNT) && db->tx_queue_cnt ) {
9148c2ecf20Sopenharmony_ci		txptr->tdes0 = cpu_to_le32(0x80000000);	/* Set owner bit */
9158c2ecf20Sopenharmony_ci		db->tx_packet_cnt++;			/* Ready to send */
9168c2ecf20Sopenharmony_ci		db->tx_queue_cnt--;
9178c2ecf20Sopenharmony_ci		dw32(DCR1, 0x1);			/* Issue Tx polling */
9188c2ecf20Sopenharmony_ci		netif_trans_update(dev);		/* saved time stamp */
9198c2ecf20Sopenharmony_ci	}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	/* Resource available check */
9228c2ecf20Sopenharmony_ci	if ( db->tx_queue_cnt < TX_WAKE_DESC_CNT )
9238c2ecf20Sopenharmony_ci		netif_wake_queue(dev);	/* Active upper layer, send again */
9248c2ecf20Sopenharmony_ci}
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci/*
9288c2ecf20Sopenharmony_ci *	Calculate the CRC valude of the Rx packet
9298c2ecf20Sopenharmony_ci *	flag = 	1 : return the reverse CRC (for the received packet CRC)
9308c2ecf20Sopenharmony_ci *		0 : return the normal CRC (for Hash Table index)
9318c2ecf20Sopenharmony_ci */
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_cistatic inline u32 cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
9348c2ecf20Sopenharmony_ci{
9358c2ecf20Sopenharmony_ci	u32 crc = crc32(~0, Data, Len);
9368c2ecf20Sopenharmony_ci	if (flag) crc = ~crc;
9378c2ecf20Sopenharmony_ci	return crc;
9388c2ecf20Sopenharmony_ci}
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci/*
9428c2ecf20Sopenharmony_ci *	Receive the come packet and pass to upper layer
9438c2ecf20Sopenharmony_ci */
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_cistatic void dmfe_rx_packet(struct net_device *dev, struct dmfe_board_info *db)
9468c2ecf20Sopenharmony_ci{
9478c2ecf20Sopenharmony_ci	struct rx_desc *rxptr;
9488c2ecf20Sopenharmony_ci	struct sk_buff *skb, *newskb;
9498c2ecf20Sopenharmony_ci	int rxlen;
9508c2ecf20Sopenharmony_ci	u32 rdes0;
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_ci	rxptr = db->rx_ready_ptr;
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_ci	while(db->rx_avail_cnt) {
9558c2ecf20Sopenharmony_ci		rdes0 = le32_to_cpu(rxptr->rdes0);
9568c2ecf20Sopenharmony_ci		if (rdes0 & 0x80000000)	/* packet owner check */
9578c2ecf20Sopenharmony_ci			break;
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci		db->rx_avail_cnt--;
9608c2ecf20Sopenharmony_ci		db->interval_rx_cnt++;
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci		dma_unmap_single(&db->pdev->dev, le32_to_cpu(rxptr->rdes2),
9638c2ecf20Sopenharmony_ci				 RX_ALLOC_SIZE, DMA_FROM_DEVICE);
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci		if ( (rdes0 & 0x300) != 0x300) {
9668c2ecf20Sopenharmony_ci			/* A packet without First/Last flag */
9678c2ecf20Sopenharmony_ci			/* reuse this SKB */
9688c2ecf20Sopenharmony_ci			DMFE_DBUG(0, "Reuse SK buffer, rdes0", rdes0);
9698c2ecf20Sopenharmony_ci			dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
9708c2ecf20Sopenharmony_ci		} else {
9718c2ecf20Sopenharmony_ci			/* A packet with First/Last flag */
9728c2ecf20Sopenharmony_ci			rxlen = ( (rdes0 >> 16) & 0x3fff) - 4;
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci			/* error summary bit check */
9758c2ecf20Sopenharmony_ci			if (rdes0 & 0x8000) {
9768c2ecf20Sopenharmony_ci				/* This is a error packet */
9778c2ecf20Sopenharmony_ci				dev->stats.rx_errors++;
9788c2ecf20Sopenharmony_ci				if (rdes0 & 1)
9798c2ecf20Sopenharmony_ci					dev->stats.rx_fifo_errors++;
9808c2ecf20Sopenharmony_ci				if (rdes0 & 2)
9818c2ecf20Sopenharmony_ci					dev->stats.rx_crc_errors++;
9828c2ecf20Sopenharmony_ci				if (rdes0 & 0x80)
9838c2ecf20Sopenharmony_ci					dev->stats.rx_length_errors++;
9848c2ecf20Sopenharmony_ci			}
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci			if ( !(rdes0 & 0x8000) ||
9878c2ecf20Sopenharmony_ci				((db->cr6_data & CR6_PM) && (rxlen>6)) ) {
9888c2ecf20Sopenharmony_ci				skb = rxptr->rx_skb_ptr;
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci				/* Received Packet CRC check need or not */
9918c2ecf20Sopenharmony_ci				if ( (db->dm910x_chk_mode & 1) &&
9928c2ecf20Sopenharmony_ci					(cal_CRC(skb->data, rxlen, 1) !=
9938c2ecf20Sopenharmony_ci					(*(u32 *) (skb->data+rxlen) ))) { /* FIXME (?) */
9948c2ecf20Sopenharmony_ci					/* Found a error received packet */
9958c2ecf20Sopenharmony_ci					dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
9968c2ecf20Sopenharmony_ci					db->dm910x_chk_mode = 3;
9978c2ecf20Sopenharmony_ci				} else {
9988c2ecf20Sopenharmony_ci					/* Good packet, send to upper layer */
9998c2ecf20Sopenharmony_ci					/* Shorst packet used new SKB */
10008c2ecf20Sopenharmony_ci					if ((rxlen < RX_COPY_SIZE) &&
10018c2ecf20Sopenharmony_ci						((newskb = netdev_alloc_skb(dev, rxlen + 2))
10028c2ecf20Sopenharmony_ci						!= NULL)) {
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci						skb = newskb;
10058c2ecf20Sopenharmony_ci						/* size less than COPY_SIZE, allocate a rxlen SKB */
10068c2ecf20Sopenharmony_ci						skb_reserve(skb, 2); /* 16byte align */
10078c2ecf20Sopenharmony_ci						skb_copy_from_linear_data(rxptr->rx_skb_ptr,
10088c2ecf20Sopenharmony_ci							  skb_put(skb, rxlen),
10098c2ecf20Sopenharmony_ci									  rxlen);
10108c2ecf20Sopenharmony_ci						dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
10118c2ecf20Sopenharmony_ci					} else
10128c2ecf20Sopenharmony_ci						skb_put(skb, rxlen);
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci					skb->protocol = eth_type_trans(skb, dev);
10158c2ecf20Sopenharmony_ci					netif_rx(skb);
10168c2ecf20Sopenharmony_ci					dev->stats.rx_packets++;
10178c2ecf20Sopenharmony_ci					dev->stats.rx_bytes += rxlen;
10188c2ecf20Sopenharmony_ci				}
10198c2ecf20Sopenharmony_ci			} else {
10208c2ecf20Sopenharmony_ci				/* Reuse SKB buffer when the packet is error */
10218c2ecf20Sopenharmony_ci				DMFE_DBUG(0, "Reuse SK buffer, rdes0", rdes0);
10228c2ecf20Sopenharmony_ci				dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
10238c2ecf20Sopenharmony_ci			}
10248c2ecf20Sopenharmony_ci		}
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci		rxptr = rxptr->next_rx_desc;
10278c2ecf20Sopenharmony_ci	}
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci	db->rx_ready_ptr = rxptr;
10308c2ecf20Sopenharmony_ci}
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci/*
10338c2ecf20Sopenharmony_ci * Set DM910X multicast address
10348c2ecf20Sopenharmony_ci */
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_cistatic void dmfe_set_filter_mode(struct net_device *dev)
10378c2ecf20Sopenharmony_ci{
10388c2ecf20Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
10398c2ecf20Sopenharmony_ci	unsigned long flags;
10408c2ecf20Sopenharmony_ci	int mc_count = netdev_mc_count(dev);
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	DMFE_DBUG(0, "dmfe_set_filter_mode()", 0);
10438c2ecf20Sopenharmony_ci	spin_lock_irqsave(&db->lock, flags);
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	if (dev->flags & IFF_PROMISC) {
10468c2ecf20Sopenharmony_ci		DMFE_DBUG(0, "Enable PROM Mode", 0);
10478c2ecf20Sopenharmony_ci		db->cr6_data |= CR6_PM | CR6_PBF;
10488c2ecf20Sopenharmony_ci		update_cr6(db->cr6_data, db->ioaddr);
10498c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&db->lock, flags);
10508c2ecf20Sopenharmony_ci		return;
10518c2ecf20Sopenharmony_ci	}
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	if (dev->flags & IFF_ALLMULTI || mc_count > DMFE_MAX_MULTICAST) {
10548c2ecf20Sopenharmony_ci		DMFE_DBUG(0, "Pass all multicast address", mc_count);
10558c2ecf20Sopenharmony_ci		db->cr6_data &= ~(CR6_PM | CR6_PBF);
10568c2ecf20Sopenharmony_ci		db->cr6_data |= CR6_PAM;
10578c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&db->lock, flags);
10588c2ecf20Sopenharmony_ci		return;
10598c2ecf20Sopenharmony_ci	}
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	DMFE_DBUG(0, "Set multicast address", mc_count);
10628c2ecf20Sopenharmony_ci	if (db->chip_id == PCI_DM9132_ID)
10638c2ecf20Sopenharmony_ci		dm9132_id_table(dev);	/* DM9132 */
10648c2ecf20Sopenharmony_ci	else
10658c2ecf20Sopenharmony_ci		send_filter_frame(dev);	/* DM9102/DM9102A */
10668c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&db->lock, flags);
10678c2ecf20Sopenharmony_ci}
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci/*
10708c2ecf20Sopenharmony_ci * 	Ethtool interace
10718c2ecf20Sopenharmony_ci */
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_cistatic void dmfe_ethtool_get_drvinfo(struct net_device *dev,
10748c2ecf20Sopenharmony_ci			       struct ethtool_drvinfo *info)
10758c2ecf20Sopenharmony_ci{
10768c2ecf20Sopenharmony_ci	struct dmfe_board_info *np = netdev_priv(dev);
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
10798c2ecf20Sopenharmony_ci	strlcpy(info->bus_info, pci_name(np->pdev), sizeof(info->bus_info));
10808c2ecf20Sopenharmony_ci}
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_cistatic int dmfe_ethtool_set_wol(struct net_device *dev,
10838c2ecf20Sopenharmony_ci				struct ethtool_wolinfo *wolinfo)
10848c2ecf20Sopenharmony_ci{
10858c2ecf20Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	if (wolinfo->wolopts & (WAKE_UCAST | WAKE_MCAST | WAKE_BCAST |
10888c2ecf20Sopenharmony_ci		   		WAKE_ARP | WAKE_MAGICSECURE))
10898c2ecf20Sopenharmony_ci		   return -EOPNOTSUPP;
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ci	db->wol_mode = wolinfo->wolopts;
10928c2ecf20Sopenharmony_ci	return 0;
10938c2ecf20Sopenharmony_ci}
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_cistatic void dmfe_ethtool_get_wol(struct net_device *dev,
10968c2ecf20Sopenharmony_ci				 struct ethtool_wolinfo *wolinfo)
10978c2ecf20Sopenharmony_ci{
10988c2ecf20Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
11018c2ecf20Sopenharmony_ci	wolinfo->wolopts = db->wol_mode;
11028c2ecf20Sopenharmony_ci}
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_cistatic const struct ethtool_ops netdev_ethtool_ops = {
11068c2ecf20Sopenharmony_ci	.get_drvinfo		= dmfe_ethtool_get_drvinfo,
11078c2ecf20Sopenharmony_ci	.get_link               = ethtool_op_get_link,
11088c2ecf20Sopenharmony_ci	.set_wol		= dmfe_ethtool_set_wol,
11098c2ecf20Sopenharmony_ci	.get_wol		= dmfe_ethtool_get_wol,
11108c2ecf20Sopenharmony_ci};
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci/*
11138c2ecf20Sopenharmony_ci *	A periodic timer routine
11148c2ecf20Sopenharmony_ci *	Dynamic media sense, allocate Rx buffer...
11158c2ecf20Sopenharmony_ci */
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_cistatic void dmfe_timer(struct timer_list *t)
11188c2ecf20Sopenharmony_ci{
11198c2ecf20Sopenharmony_ci	struct dmfe_board_info *db = from_timer(db, t, timer);
11208c2ecf20Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(db->pdev);
11218c2ecf20Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
11228c2ecf20Sopenharmony_ci	u32 tmp_cr8;
11238c2ecf20Sopenharmony_ci	unsigned char tmp_cr12;
11248c2ecf20Sopenharmony_ci 	unsigned long flags;
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	int link_ok, link_ok_phy;
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	DMFE_DBUG(0, "dmfe_timer()", 0);
11298c2ecf20Sopenharmony_ci	spin_lock_irqsave(&db->lock, flags);
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	/* Media mode process when Link OK before enter this route */
11328c2ecf20Sopenharmony_ci	if (db->first_in_callback == 0) {
11338c2ecf20Sopenharmony_ci		db->first_in_callback = 1;
11348c2ecf20Sopenharmony_ci		if (db->chip_type && (db->chip_id==PCI_DM9102_ID)) {
11358c2ecf20Sopenharmony_ci			db->cr6_data &= ~0x40000;
11368c2ecf20Sopenharmony_ci			update_cr6(db->cr6_data, ioaddr);
11378c2ecf20Sopenharmony_ci			dmfe_phy_write(ioaddr, db->phy_addr, 0, 0x1000, db->chip_id);
11388c2ecf20Sopenharmony_ci			db->cr6_data |= 0x40000;
11398c2ecf20Sopenharmony_ci			update_cr6(db->cr6_data, ioaddr);
11408c2ecf20Sopenharmony_ci			db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
11418c2ecf20Sopenharmony_ci			add_timer(&db->timer);
11428c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&db->lock, flags);
11438c2ecf20Sopenharmony_ci			return;
11448c2ecf20Sopenharmony_ci		}
11458c2ecf20Sopenharmony_ci	}
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	/* Operating Mode Check */
11498c2ecf20Sopenharmony_ci	if ( (db->dm910x_chk_mode & 0x1) &&
11508c2ecf20Sopenharmony_ci		(dev->stats.rx_packets > MAX_CHECK_PACKET) )
11518c2ecf20Sopenharmony_ci		db->dm910x_chk_mode = 0x4;
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci	/* Dynamic reset DM910X : system error or transmit time-out */
11548c2ecf20Sopenharmony_ci	tmp_cr8 = dr32(DCR8);
11558c2ecf20Sopenharmony_ci	if ( (db->interval_rx_cnt==0) && (tmp_cr8) ) {
11568c2ecf20Sopenharmony_ci		db->reset_cr8++;
11578c2ecf20Sopenharmony_ci		db->wait_reset = 1;
11588c2ecf20Sopenharmony_ci	}
11598c2ecf20Sopenharmony_ci	db->interval_rx_cnt = 0;
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	/* TX polling kick monitor */
11628c2ecf20Sopenharmony_ci	if ( db->tx_packet_cnt &&
11638c2ecf20Sopenharmony_ci	     time_after(jiffies, dev_trans_start(dev) + DMFE_TX_KICK) ) {
11648c2ecf20Sopenharmony_ci		dw32(DCR1, 0x1);   /* Tx polling again */
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci		/* TX Timeout */
11678c2ecf20Sopenharmony_ci		if (time_after(jiffies, dev_trans_start(dev) + DMFE_TX_TIMEOUT) ) {
11688c2ecf20Sopenharmony_ci			db->reset_TXtimeout++;
11698c2ecf20Sopenharmony_ci			db->wait_reset = 1;
11708c2ecf20Sopenharmony_ci			dev_warn(&dev->dev, "Tx timeout - resetting\n");
11718c2ecf20Sopenharmony_ci		}
11728c2ecf20Sopenharmony_ci	}
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_ci	if (db->wait_reset) {
11758c2ecf20Sopenharmony_ci		DMFE_DBUG(0, "Dynamic Reset device", db->tx_packet_cnt);
11768c2ecf20Sopenharmony_ci		db->reset_count++;
11778c2ecf20Sopenharmony_ci		dmfe_dynamic_reset(dev);
11788c2ecf20Sopenharmony_ci		db->first_in_callback = 0;
11798c2ecf20Sopenharmony_ci		db->timer.expires = DMFE_TIMER_WUT;
11808c2ecf20Sopenharmony_ci		add_timer(&db->timer);
11818c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&db->lock, flags);
11828c2ecf20Sopenharmony_ci		return;
11838c2ecf20Sopenharmony_ci	}
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	/* Link status check, Dynamic media type change */
11868c2ecf20Sopenharmony_ci	if (db->chip_id == PCI_DM9132_ID)
11878c2ecf20Sopenharmony_ci		tmp_cr12 = dr8(DCR9 + 3);	/* DM9132 */
11888c2ecf20Sopenharmony_ci	else
11898c2ecf20Sopenharmony_ci		tmp_cr12 = dr8(DCR12);		/* DM9102/DM9102A */
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	if ( ((db->chip_id == PCI_DM9102_ID) &&
11928c2ecf20Sopenharmony_ci		(db->chip_revision == 0x30)) ||
11938c2ecf20Sopenharmony_ci		((db->chip_id == PCI_DM9132_ID) &&
11948c2ecf20Sopenharmony_ci		(db->chip_revision == 0x10)) ) {
11958c2ecf20Sopenharmony_ci		/* DM9102A Chip */
11968c2ecf20Sopenharmony_ci		if (tmp_cr12 & 2)
11978c2ecf20Sopenharmony_ci			link_ok = 0;
11988c2ecf20Sopenharmony_ci		else
11998c2ecf20Sopenharmony_ci			link_ok = 1;
12008c2ecf20Sopenharmony_ci	}
12018c2ecf20Sopenharmony_ci	else
12028c2ecf20Sopenharmony_ci		/*0x43 is used instead of 0x3 because bit 6 should represent
12038c2ecf20Sopenharmony_ci			link status of external PHY */
12048c2ecf20Sopenharmony_ci		link_ok = (tmp_cr12 & 0x43) ? 1 : 0;
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci
12078c2ecf20Sopenharmony_ci	/* If chip reports that link is failed it could be because external
12088c2ecf20Sopenharmony_ci		PHY link status pin is not connected correctly to chip
12098c2ecf20Sopenharmony_ci		To be sure ask PHY too.
12108c2ecf20Sopenharmony_ci	*/
12118c2ecf20Sopenharmony_ci
12128c2ecf20Sopenharmony_ci	/* need a dummy read because of PHY's register latch*/
12138c2ecf20Sopenharmony_ci	dmfe_phy_read (db->ioaddr, db->phy_addr, 1, db->chip_id);
12148c2ecf20Sopenharmony_ci	link_ok_phy = (dmfe_phy_read (db->ioaddr,
12158c2ecf20Sopenharmony_ci				      db->phy_addr, 1, db->chip_id) & 0x4) ? 1 : 0;
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci	if (link_ok_phy != link_ok) {
12188c2ecf20Sopenharmony_ci		DMFE_DBUG (0, "PHY and chip report different link status", 0);
12198c2ecf20Sopenharmony_ci		link_ok = link_ok | link_ok_phy;
12208c2ecf20Sopenharmony_ci 	}
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci	if ( !link_ok && netif_carrier_ok(dev)) {
12238c2ecf20Sopenharmony_ci		/* Link Failed */
12248c2ecf20Sopenharmony_ci		DMFE_DBUG(0, "Link Failed", tmp_cr12);
12258c2ecf20Sopenharmony_ci		netif_carrier_off(dev);
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci		/* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */
12288c2ecf20Sopenharmony_ci		/* AUTO or force 1M Homerun/Longrun don't need */
12298c2ecf20Sopenharmony_ci		if ( !(db->media_mode & 0x38) )
12308c2ecf20Sopenharmony_ci			dmfe_phy_write(db->ioaddr, db->phy_addr,
12318c2ecf20Sopenharmony_ci				       0, 0x1000, db->chip_id);
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci		/* AUTO mode, if INT phyxcer link failed, select EXT device */
12348c2ecf20Sopenharmony_ci		if (db->media_mode & DMFE_AUTO) {
12358c2ecf20Sopenharmony_ci			/* 10/100M link failed, used 1M Home-Net */
12368c2ecf20Sopenharmony_ci			db->cr6_data|=0x00040000;	/* bit18=1, MII */
12378c2ecf20Sopenharmony_ci			db->cr6_data&=~0x00000200;	/* bit9=0, HD mode */
12388c2ecf20Sopenharmony_ci			update_cr6(db->cr6_data, ioaddr);
12398c2ecf20Sopenharmony_ci		}
12408c2ecf20Sopenharmony_ci	} else if (!netif_carrier_ok(dev)) {
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci		DMFE_DBUG(0, "Link link OK", tmp_cr12);
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci		/* Auto Sense Speed */
12458c2ecf20Sopenharmony_ci		if ( !(db->media_mode & DMFE_AUTO) || !dmfe_sense_speed(db)) {
12468c2ecf20Sopenharmony_ci			netif_carrier_on(dev);
12478c2ecf20Sopenharmony_ci			SHOW_MEDIA_TYPE(db->op_mode);
12488c2ecf20Sopenharmony_ci		}
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci		dmfe_process_mode(db);
12518c2ecf20Sopenharmony_ci	}
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	/* HPNA remote command check */
12548c2ecf20Sopenharmony_ci	if (db->HPNA_command & 0xf00) {
12558c2ecf20Sopenharmony_ci		db->HPNA_timer--;
12568c2ecf20Sopenharmony_ci		if (!db->HPNA_timer)
12578c2ecf20Sopenharmony_ci			dmfe_HPNA_remote_cmd_chk(db);
12588c2ecf20Sopenharmony_ci	}
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci	/* Timer active again */
12618c2ecf20Sopenharmony_ci	db->timer.expires = DMFE_TIMER_WUT;
12628c2ecf20Sopenharmony_ci	add_timer(&db->timer);
12638c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&db->lock, flags);
12648c2ecf20Sopenharmony_ci}
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci/*
12688c2ecf20Sopenharmony_ci *	Dynamic reset the DM910X board
12698c2ecf20Sopenharmony_ci *	Stop DM910X board
12708c2ecf20Sopenharmony_ci *	Free Tx/Rx allocated memory
12718c2ecf20Sopenharmony_ci *	Reset DM910X board
12728c2ecf20Sopenharmony_ci *	Re-initialize DM910X board
12738c2ecf20Sopenharmony_ci */
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_cistatic void dmfe_dynamic_reset(struct net_device *dev)
12768c2ecf20Sopenharmony_ci{
12778c2ecf20Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
12788c2ecf20Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_ci	DMFE_DBUG(0, "dmfe_dynamic_reset()", 0);
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci	/* Sopt MAC controller */
12838c2ecf20Sopenharmony_ci	db->cr6_data &= ~(CR6_RXSC | CR6_TXSC);	/* Disable Tx/Rx */
12848c2ecf20Sopenharmony_ci	update_cr6(db->cr6_data, ioaddr);
12858c2ecf20Sopenharmony_ci	dw32(DCR7, 0);				/* Disable Interrupt */
12868c2ecf20Sopenharmony_ci	dw32(DCR5, dr32(DCR5));
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci	/* Disable upper layer interface */
12898c2ecf20Sopenharmony_ci	netif_stop_queue(dev);
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci	/* Free Rx Allocate buffer */
12928c2ecf20Sopenharmony_ci	dmfe_free_rxbuffer(db);
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	/* system variable init */
12958c2ecf20Sopenharmony_ci	db->tx_packet_cnt = 0;
12968c2ecf20Sopenharmony_ci	db->tx_queue_cnt = 0;
12978c2ecf20Sopenharmony_ci	db->rx_avail_cnt = 0;
12988c2ecf20Sopenharmony_ci	netif_carrier_off(dev);
12998c2ecf20Sopenharmony_ci	db->wait_reset = 0;
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci	/* Re-initialize DM910X board */
13028c2ecf20Sopenharmony_ci	dmfe_init_dm910x(dev);
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	/* Restart upper layer interface */
13058c2ecf20Sopenharmony_ci	netif_wake_queue(dev);
13068c2ecf20Sopenharmony_ci}
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci/*
13108c2ecf20Sopenharmony_ci *	free all allocated rx buffer
13118c2ecf20Sopenharmony_ci */
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_cistatic void dmfe_free_rxbuffer(struct dmfe_board_info * db)
13148c2ecf20Sopenharmony_ci{
13158c2ecf20Sopenharmony_ci	DMFE_DBUG(0, "dmfe_free_rxbuffer()", 0);
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci	/* free allocated rx buffer */
13188c2ecf20Sopenharmony_ci	while (db->rx_avail_cnt) {
13198c2ecf20Sopenharmony_ci		dev_kfree_skb(db->rx_ready_ptr->rx_skb_ptr);
13208c2ecf20Sopenharmony_ci		db->rx_ready_ptr = db->rx_ready_ptr->next_rx_desc;
13218c2ecf20Sopenharmony_ci		db->rx_avail_cnt--;
13228c2ecf20Sopenharmony_ci	}
13238c2ecf20Sopenharmony_ci}
13248c2ecf20Sopenharmony_ci
13258c2ecf20Sopenharmony_ci
13268c2ecf20Sopenharmony_ci/*
13278c2ecf20Sopenharmony_ci *	Reuse the SK buffer
13288c2ecf20Sopenharmony_ci */
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_cistatic void dmfe_reuse_skb(struct dmfe_board_info *db, struct sk_buff * skb)
13318c2ecf20Sopenharmony_ci{
13328c2ecf20Sopenharmony_ci	struct rx_desc *rxptr = db->rx_insert_ptr;
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci	if (!(rxptr->rdes0 & cpu_to_le32(0x80000000))) {
13358c2ecf20Sopenharmony_ci		rxptr->rx_skb_ptr = skb;
13368c2ecf20Sopenharmony_ci		rxptr->rdes2 = cpu_to_le32(dma_map_single(&db->pdev->dev, skb->data,
13378c2ecf20Sopenharmony_ci							  RX_ALLOC_SIZE, DMA_FROM_DEVICE));
13388c2ecf20Sopenharmony_ci		wmb();
13398c2ecf20Sopenharmony_ci		rxptr->rdes0 = cpu_to_le32(0x80000000);
13408c2ecf20Sopenharmony_ci		db->rx_avail_cnt++;
13418c2ecf20Sopenharmony_ci		db->rx_insert_ptr = rxptr->next_rx_desc;
13428c2ecf20Sopenharmony_ci	} else
13438c2ecf20Sopenharmony_ci		DMFE_DBUG(0, "SK Buffer reuse method error", db->rx_avail_cnt);
13448c2ecf20Sopenharmony_ci}
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci/*
13488c2ecf20Sopenharmony_ci *	Initialize transmit/Receive descriptor
13498c2ecf20Sopenharmony_ci *	Using Chain structure, and allocate Tx/Rx buffer
13508c2ecf20Sopenharmony_ci */
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_cistatic void dmfe_descriptor_init(struct net_device *dev)
13538c2ecf20Sopenharmony_ci{
13548c2ecf20Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
13558c2ecf20Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
13568c2ecf20Sopenharmony_ci	struct tx_desc *tmp_tx;
13578c2ecf20Sopenharmony_ci	struct rx_desc *tmp_rx;
13588c2ecf20Sopenharmony_ci	unsigned char *tmp_buf;
13598c2ecf20Sopenharmony_ci	dma_addr_t tmp_tx_dma, tmp_rx_dma;
13608c2ecf20Sopenharmony_ci	dma_addr_t tmp_buf_dma;
13618c2ecf20Sopenharmony_ci	int i;
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	DMFE_DBUG(0, "dmfe_descriptor_init()", 0);
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	/* tx descriptor start pointer */
13668c2ecf20Sopenharmony_ci	db->tx_insert_ptr = db->first_tx_desc;
13678c2ecf20Sopenharmony_ci	db->tx_remove_ptr = db->first_tx_desc;
13688c2ecf20Sopenharmony_ci	dw32(DCR4, db->first_tx_desc_dma);     /* TX DESC address */
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci	/* rx descriptor start pointer */
13718c2ecf20Sopenharmony_ci	db->first_rx_desc = (void *)db->first_tx_desc +
13728c2ecf20Sopenharmony_ci			sizeof(struct tx_desc) * TX_DESC_CNT;
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	db->first_rx_desc_dma =  db->first_tx_desc_dma +
13758c2ecf20Sopenharmony_ci			sizeof(struct tx_desc) * TX_DESC_CNT;
13768c2ecf20Sopenharmony_ci	db->rx_insert_ptr = db->first_rx_desc;
13778c2ecf20Sopenharmony_ci	db->rx_ready_ptr = db->first_rx_desc;
13788c2ecf20Sopenharmony_ci	dw32(DCR3, db->first_rx_desc_dma);		/* RX DESC address */
13798c2ecf20Sopenharmony_ci
13808c2ecf20Sopenharmony_ci	/* Init Transmit chain */
13818c2ecf20Sopenharmony_ci	tmp_buf = db->buf_pool_start;
13828c2ecf20Sopenharmony_ci	tmp_buf_dma = db->buf_pool_dma_start;
13838c2ecf20Sopenharmony_ci	tmp_tx_dma = db->first_tx_desc_dma;
13848c2ecf20Sopenharmony_ci	for (tmp_tx = db->first_tx_desc, i = 0; i < TX_DESC_CNT; i++, tmp_tx++) {
13858c2ecf20Sopenharmony_ci		tmp_tx->tx_buf_ptr = tmp_buf;
13868c2ecf20Sopenharmony_ci		tmp_tx->tdes0 = cpu_to_le32(0);
13878c2ecf20Sopenharmony_ci		tmp_tx->tdes1 = cpu_to_le32(0x81000000);	/* IC, chain */
13888c2ecf20Sopenharmony_ci		tmp_tx->tdes2 = cpu_to_le32(tmp_buf_dma);
13898c2ecf20Sopenharmony_ci		tmp_tx_dma += sizeof(struct tx_desc);
13908c2ecf20Sopenharmony_ci		tmp_tx->tdes3 = cpu_to_le32(tmp_tx_dma);
13918c2ecf20Sopenharmony_ci		tmp_tx->next_tx_desc = tmp_tx + 1;
13928c2ecf20Sopenharmony_ci		tmp_buf = tmp_buf + TX_BUF_ALLOC;
13938c2ecf20Sopenharmony_ci		tmp_buf_dma = tmp_buf_dma + TX_BUF_ALLOC;
13948c2ecf20Sopenharmony_ci	}
13958c2ecf20Sopenharmony_ci	(--tmp_tx)->tdes3 = cpu_to_le32(db->first_tx_desc_dma);
13968c2ecf20Sopenharmony_ci	tmp_tx->next_tx_desc = db->first_tx_desc;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci	 /* Init Receive descriptor chain */
13998c2ecf20Sopenharmony_ci	tmp_rx_dma=db->first_rx_desc_dma;
14008c2ecf20Sopenharmony_ci	for (tmp_rx = db->first_rx_desc, i = 0; i < RX_DESC_CNT; i++, tmp_rx++) {
14018c2ecf20Sopenharmony_ci		tmp_rx->rdes0 = cpu_to_le32(0);
14028c2ecf20Sopenharmony_ci		tmp_rx->rdes1 = cpu_to_le32(0x01000600);
14038c2ecf20Sopenharmony_ci		tmp_rx_dma += sizeof(struct rx_desc);
14048c2ecf20Sopenharmony_ci		tmp_rx->rdes3 = cpu_to_le32(tmp_rx_dma);
14058c2ecf20Sopenharmony_ci		tmp_rx->next_rx_desc = tmp_rx + 1;
14068c2ecf20Sopenharmony_ci	}
14078c2ecf20Sopenharmony_ci	(--tmp_rx)->rdes3 = cpu_to_le32(db->first_rx_desc_dma);
14088c2ecf20Sopenharmony_ci	tmp_rx->next_rx_desc = db->first_rx_desc;
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	/* pre-allocate Rx buffer */
14118c2ecf20Sopenharmony_ci	allocate_rx_buffer(dev);
14128c2ecf20Sopenharmony_ci}
14138c2ecf20Sopenharmony_ci
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_ci/*
14168c2ecf20Sopenharmony_ci *	Update CR6 value
14178c2ecf20Sopenharmony_ci *	Firstly stop DM910X , then written value and start
14188c2ecf20Sopenharmony_ci */
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_cistatic void update_cr6(u32 cr6_data, void __iomem *ioaddr)
14218c2ecf20Sopenharmony_ci{
14228c2ecf20Sopenharmony_ci	u32 cr6_tmp;
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci	cr6_tmp = cr6_data & ~0x2002;           /* stop Tx/Rx */
14258c2ecf20Sopenharmony_ci	dw32(DCR6, cr6_tmp);
14268c2ecf20Sopenharmony_ci	udelay(5);
14278c2ecf20Sopenharmony_ci	dw32(DCR6, cr6_data);
14288c2ecf20Sopenharmony_ci	udelay(5);
14298c2ecf20Sopenharmony_ci}
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci/*
14338c2ecf20Sopenharmony_ci *	Send a setup frame for DM9132
14348c2ecf20Sopenharmony_ci *	This setup frame initialize DM910X address filter mode
14358c2ecf20Sopenharmony_ci*/
14368c2ecf20Sopenharmony_ci
14378c2ecf20Sopenharmony_cistatic void dm9132_id_table(struct net_device *dev)
14388c2ecf20Sopenharmony_ci{
14398c2ecf20Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
14408c2ecf20Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr + 0xc0;
14418c2ecf20Sopenharmony_ci	u16 *addrptr = (u16 *)dev->dev_addr;
14428c2ecf20Sopenharmony_ci	struct netdev_hw_addr *ha;
14438c2ecf20Sopenharmony_ci	u16 i, hash_table[4];
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci	/* Node address */
14468c2ecf20Sopenharmony_ci	for (i = 0; i < 3; i++) {
14478c2ecf20Sopenharmony_ci		dw16(0, addrptr[i]);
14488c2ecf20Sopenharmony_ci		ioaddr += 4;
14498c2ecf20Sopenharmony_ci	}
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	/* Clear Hash Table */
14528c2ecf20Sopenharmony_ci	memset(hash_table, 0, sizeof(hash_table));
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	/* broadcast address */
14558c2ecf20Sopenharmony_ci	hash_table[3] = 0x8000;
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci	/* the multicast address in Hash Table : 64 bits */
14588c2ecf20Sopenharmony_ci	netdev_for_each_mc_addr(ha, dev) {
14598c2ecf20Sopenharmony_ci		u32 hash_val = cal_CRC((char *)ha->addr, 6, 0) & 0x3f;
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci		hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);
14628c2ecf20Sopenharmony_ci	}
14638c2ecf20Sopenharmony_ci
14648c2ecf20Sopenharmony_ci	/* Write the hash table to MAC MD table */
14658c2ecf20Sopenharmony_ci	for (i = 0; i < 4; i++, ioaddr += 4)
14668c2ecf20Sopenharmony_ci		dw16(0, hash_table[i]);
14678c2ecf20Sopenharmony_ci}
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci/*
14718c2ecf20Sopenharmony_ci *	Send a setup frame for DM9102/DM9102A
14728c2ecf20Sopenharmony_ci *	This setup frame initialize DM910X address filter mode
14738c2ecf20Sopenharmony_ci */
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_cistatic void send_filter_frame(struct net_device *dev)
14768c2ecf20Sopenharmony_ci{
14778c2ecf20Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
14788c2ecf20Sopenharmony_ci	struct netdev_hw_addr *ha;
14798c2ecf20Sopenharmony_ci	struct tx_desc *txptr;
14808c2ecf20Sopenharmony_ci	u16 * addrptr;
14818c2ecf20Sopenharmony_ci	u32 * suptr;
14828c2ecf20Sopenharmony_ci	int i;
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	DMFE_DBUG(0, "send_filter_frame()", 0);
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_ci	txptr = db->tx_insert_ptr;
14878c2ecf20Sopenharmony_ci	suptr = (u32 *) txptr->tx_buf_ptr;
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	/* Node address */
14908c2ecf20Sopenharmony_ci	addrptr = (u16 *) dev->dev_addr;
14918c2ecf20Sopenharmony_ci	*suptr++ = addrptr[0];
14928c2ecf20Sopenharmony_ci	*suptr++ = addrptr[1];
14938c2ecf20Sopenharmony_ci	*suptr++ = addrptr[2];
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ci	/* broadcast address */
14968c2ecf20Sopenharmony_ci	*suptr++ = 0xffff;
14978c2ecf20Sopenharmony_ci	*suptr++ = 0xffff;
14988c2ecf20Sopenharmony_ci	*suptr++ = 0xffff;
14998c2ecf20Sopenharmony_ci
15008c2ecf20Sopenharmony_ci	/* fit the multicast address */
15018c2ecf20Sopenharmony_ci	netdev_for_each_mc_addr(ha, dev) {
15028c2ecf20Sopenharmony_ci		addrptr = (u16 *) ha->addr;
15038c2ecf20Sopenharmony_ci		*suptr++ = addrptr[0];
15048c2ecf20Sopenharmony_ci		*suptr++ = addrptr[1];
15058c2ecf20Sopenharmony_ci		*suptr++ = addrptr[2];
15068c2ecf20Sopenharmony_ci	}
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	for (i = netdev_mc_count(dev); i < 14; i++) {
15098c2ecf20Sopenharmony_ci		*suptr++ = 0xffff;
15108c2ecf20Sopenharmony_ci		*suptr++ = 0xffff;
15118c2ecf20Sopenharmony_ci		*suptr++ = 0xffff;
15128c2ecf20Sopenharmony_ci	}
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci	/* prepare the setup frame */
15158c2ecf20Sopenharmony_ci	db->tx_insert_ptr = txptr->next_tx_desc;
15168c2ecf20Sopenharmony_ci	txptr->tdes1 = cpu_to_le32(0x890000c0);
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	/* Resource Check and Send the setup packet */
15198c2ecf20Sopenharmony_ci	if (!db->tx_packet_cnt) {
15208c2ecf20Sopenharmony_ci		void __iomem *ioaddr = db->ioaddr;
15218c2ecf20Sopenharmony_ci
15228c2ecf20Sopenharmony_ci		/* Resource Empty */
15238c2ecf20Sopenharmony_ci		db->tx_packet_cnt++;
15248c2ecf20Sopenharmony_ci		txptr->tdes0 = cpu_to_le32(0x80000000);
15258c2ecf20Sopenharmony_ci		update_cr6(db->cr6_data | 0x2000, ioaddr);
15268c2ecf20Sopenharmony_ci		dw32(DCR1, 0x1);	/* Issue Tx polling */
15278c2ecf20Sopenharmony_ci		update_cr6(db->cr6_data, ioaddr);
15288c2ecf20Sopenharmony_ci		netif_trans_update(dev);
15298c2ecf20Sopenharmony_ci	} else
15308c2ecf20Sopenharmony_ci		db->tx_queue_cnt++;	/* Put in TX queue */
15318c2ecf20Sopenharmony_ci}
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci/*
15358c2ecf20Sopenharmony_ci *	Allocate rx buffer,
15368c2ecf20Sopenharmony_ci *	As possible as allocate maxiumn Rx buffer
15378c2ecf20Sopenharmony_ci */
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_cistatic void allocate_rx_buffer(struct net_device *dev)
15408c2ecf20Sopenharmony_ci{
15418c2ecf20Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
15428c2ecf20Sopenharmony_ci	struct rx_desc *rxptr;
15438c2ecf20Sopenharmony_ci	struct sk_buff *skb;
15448c2ecf20Sopenharmony_ci
15458c2ecf20Sopenharmony_ci	rxptr = db->rx_insert_ptr;
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ci	while(db->rx_avail_cnt < RX_DESC_CNT) {
15488c2ecf20Sopenharmony_ci		if ( ( skb = netdev_alloc_skb(dev, RX_ALLOC_SIZE) ) == NULL )
15498c2ecf20Sopenharmony_ci			break;
15508c2ecf20Sopenharmony_ci		rxptr->rx_skb_ptr = skb; /* FIXME (?) */
15518c2ecf20Sopenharmony_ci		rxptr->rdes2 = cpu_to_le32(dma_map_single(&db->pdev->dev, skb->data,
15528c2ecf20Sopenharmony_ci							  RX_ALLOC_SIZE, DMA_FROM_DEVICE));
15538c2ecf20Sopenharmony_ci		wmb();
15548c2ecf20Sopenharmony_ci		rxptr->rdes0 = cpu_to_le32(0x80000000);
15558c2ecf20Sopenharmony_ci		rxptr = rxptr->next_rx_desc;
15568c2ecf20Sopenharmony_ci		db->rx_avail_cnt++;
15578c2ecf20Sopenharmony_ci	}
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_ci	db->rx_insert_ptr = rxptr;
15608c2ecf20Sopenharmony_ci}
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_cistatic void srom_clk_write(void __iomem *ioaddr, u32 data)
15638c2ecf20Sopenharmony_ci{
15648c2ecf20Sopenharmony_ci	static const u32 cmd[] = {
15658c2ecf20Sopenharmony_ci		CR9_SROM_READ | CR9_SRCS,
15668c2ecf20Sopenharmony_ci		CR9_SROM_READ | CR9_SRCS | CR9_SRCLK,
15678c2ecf20Sopenharmony_ci		CR9_SROM_READ | CR9_SRCS
15688c2ecf20Sopenharmony_ci	};
15698c2ecf20Sopenharmony_ci	int i;
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(cmd); i++) {
15728c2ecf20Sopenharmony_ci		dw32(DCR9, data | cmd[i]);
15738c2ecf20Sopenharmony_ci		udelay(5);
15748c2ecf20Sopenharmony_ci	}
15758c2ecf20Sopenharmony_ci}
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_ci/*
15788c2ecf20Sopenharmony_ci *	Read one word data from the serial ROM
15798c2ecf20Sopenharmony_ci */
15808c2ecf20Sopenharmony_cistatic u16 read_srom_word(void __iomem *ioaddr, int offset)
15818c2ecf20Sopenharmony_ci{
15828c2ecf20Sopenharmony_ci	u16 srom_data;
15838c2ecf20Sopenharmony_ci	int i;
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	dw32(DCR9, CR9_SROM_READ);
15868c2ecf20Sopenharmony_ci	udelay(5);
15878c2ecf20Sopenharmony_ci	dw32(DCR9, CR9_SROM_READ | CR9_SRCS);
15888c2ecf20Sopenharmony_ci	udelay(5);
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci	/* Send the Read Command 110b */
15918c2ecf20Sopenharmony_ci	srom_clk_write(ioaddr, SROM_DATA_1);
15928c2ecf20Sopenharmony_ci	srom_clk_write(ioaddr, SROM_DATA_1);
15938c2ecf20Sopenharmony_ci	srom_clk_write(ioaddr, SROM_DATA_0);
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ci	/* Send the offset */
15968c2ecf20Sopenharmony_ci	for (i = 5; i >= 0; i--) {
15978c2ecf20Sopenharmony_ci		srom_data = (offset & (1 << i)) ? SROM_DATA_1 : SROM_DATA_0;
15988c2ecf20Sopenharmony_ci		srom_clk_write(ioaddr, srom_data);
15998c2ecf20Sopenharmony_ci	}
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci	dw32(DCR9, CR9_SROM_READ | CR9_SRCS);
16028c2ecf20Sopenharmony_ci	udelay(5);
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci	for (i = 16; i > 0; i--) {
16058c2ecf20Sopenharmony_ci		dw32(DCR9, CR9_SROM_READ | CR9_SRCS | CR9_SRCLK);
16068c2ecf20Sopenharmony_ci		udelay(5);
16078c2ecf20Sopenharmony_ci		srom_data = (srom_data << 1) |
16088c2ecf20Sopenharmony_ci				((dr32(DCR9) & CR9_CRDOUT) ? 1 : 0);
16098c2ecf20Sopenharmony_ci		dw32(DCR9, CR9_SROM_READ | CR9_SRCS);
16108c2ecf20Sopenharmony_ci		udelay(5);
16118c2ecf20Sopenharmony_ci	}
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci	dw32(DCR9, CR9_SROM_READ);
16148c2ecf20Sopenharmony_ci	udelay(5);
16158c2ecf20Sopenharmony_ci	return srom_data;
16168c2ecf20Sopenharmony_ci}
16178c2ecf20Sopenharmony_ci
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_ci/*
16208c2ecf20Sopenharmony_ci *	Auto sense the media mode
16218c2ecf20Sopenharmony_ci */
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_cistatic u8 dmfe_sense_speed(struct dmfe_board_info *db)
16248c2ecf20Sopenharmony_ci{
16258c2ecf20Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
16268c2ecf20Sopenharmony_ci	u8 ErrFlag = 0;
16278c2ecf20Sopenharmony_ci	u16 phy_mode;
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_ci	/* CR6 bit18=0, select 10/100M */
16308c2ecf20Sopenharmony_ci	update_cr6(db->cr6_data & ~0x40000, ioaddr);
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci	phy_mode = dmfe_phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
16338c2ecf20Sopenharmony_ci	phy_mode = dmfe_phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	if ( (phy_mode & 0x24) == 0x24 ) {
16368c2ecf20Sopenharmony_ci		if (db->chip_id == PCI_DM9132_ID)	/* DM9132 */
16378c2ecf20Sopenharmony_ci			phy_mode = dmfe_phy_read(db->ioaddr,
16388c2ecf20Sopenharmony_ci						 db->phy_addr, 7, db->chip_id) & 0xf000;
16398c2ecf20Sopenharmony_ci		else 				/* DM9102/DM9102A */
16408c2ecf20Sopenharmony_ci			phy_mode = dmfe_phy_read(db->ioaddr,
16418c2ecf20Sopenharmony_ci						 db->phy_addr, 17, db->chip_id) & 0xf000;
16428c2ecf20Sopenharmony_ci		switch (phy_mode) {
16438c2ecf20Sopenharmony_ci		case 0x1000: db->op_mode = DMFE_10MHF; break;
16448c2ecf20Sopenharmony_ci		case 0x2000: db->op_mode = DMFE_10MFD; break;
16458c2ecf20Sopenharmony_ci		case 0x4000: db->op_mode = DMFE_100MHF; break;
16468c2ecf20Sopenharmony_ci		case 0x8000: db->op_mode = DMFE_100MFD; break;
16478c2ecf20Sopenharmony_ci		default: db->op_mode = DMFE_10MHF;
16488c2ecf20Sopenharmony_ci			ErrFlag = 1;
16498c2ecf20Sopenharmony_ci			break;
16508c2ecf20Sopenharmony_ci		}
16518c2ecf20Sopenharmony_ci	} else {
16528c2ecf20Sopenharmony_ci		db->op_mode = DMFE_10MHF;
16538c2ecf20Sopenharmony_ci		DMFE_DBUG(0, "Link Failed :", phy_mode);
16548c2ecf20Sopenharmony_ci		ErrFlag = 1;
16558c2ecf20Sopenharmony_ci	}
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_ci	return ErrFlag;
16588c2ecf20Sopenharmony_ci}
16598c2ecf20Sopenharmony_ci
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci/*
16628c2ecf20Sopenharmony_ci *	Set 10/100 phyxcer capability
16638c2ecf20Sopenharmony_ci *	AUTO mode : phyxcer register4 is NIC capability
16648c2ecf20Sopenharmony_ci *	Force mode: phyxcer register4 is the force media
16658c2ecf20Sopenharmony_ci */
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_cistatic void dmfe_set_phyxcer(struct dmfe_board_info *db)
16688c2ecf20Sopenharmony_ci{
16698c2ecf20Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
16708c2ecf20Sopenharmony_ci	u16 phy_reg;
16718c2ecf20Sopenharmony_ci
16728c2ecf20Sopenharmony_ci	/* Select 10/100M phyxcer */
16738c2ecf20Sopenharmony_ci	db->cr6_data &= ~0x40000;
16748c2ecf20Sopenharmony_ci	update_cr6(db->cr6_data, ioaddr);
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci	/* DM9009 Chip: Phyxcer reg18 bit12=0 */
16778c2ecf20Sopenharmony_ci	if (db->chip_id == PCI_DM9009_ID) {
16788c2ecf20Sopenharmony_ci		phy_reg = dmfe_phy_read(db->ioaddr,
16798c2ecf20Sopenharmony_ci					db->phy_addr, 18, db->chip_id) & ~0x1000;
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci		dmfe_phy_write(db->ioaddr,
16828c2ecf20Sopenharmony_ci			       db->phy_addr, 18, phy_reg, db->chip_id);
16838c2ecf20Sopenharmony_ci	}
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci	/* Phyxcer capability setting */
16868c2ecf20Sopenharmony_ci	phy_reg = dmfe_phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0;
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ci	if (db->media_mode & DMFE_AUTO) {
16898c2ecf20Sopenharmony_ci		/* AUTO Mode */
16908c2ecf20Sopenharmony_ci		phy_reg |= db->PHY_reg4;
16918c2ecf20Sopenharmony_ci	} else {
16928c2ecf20Sopenharmony_ci		/* Force Mode */
16938c2ecf20Sopenharmony_ci		switch(db->media_mode) {
16948c2ecf20Sopenharmony_ci		case DMFE_10MHF: phy_reg |= 0x20; break;
16958c2ecf20Sopenharmony_ci		case DMFE_10MFD: phy_reg |= 0x40; break;
16968c2ecf20Sopenharmony_ci		case DMFE_100MHF: phy_reg |= 0x80; break;
16978c2ecf20Sopenharmony_ci		case DMFE_100MFD: phy_reg |= 0x100; break;
16988c2ecf20Sopenharmony_ci		}
16998c2ecf20Sopenharmony_ci		if (db->chip_id == PCI_DM9009_ID) phy_reg &= 0x61;
17008c2ecf20Sopenharmony_ci	}
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_ci  	/* Write new capability to Phyxcer Reg4 */
17038c2ecf20Sopenharmony_ci	if ( !(phy_reg & 0x01e0)) {
17048c2ecf20Sopenharmony_ci		phy_reg|=db->PHY_reg4;
17058c2ecf20Sopenharmony_ci		db->media_mode|=DMFE_AUTO;
17068c2ecf20Sopenharmony_ci	}
17078c2ecf20Sopenharmony_ci	dmfe_phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id);
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci 	/* Restart Auto-Negotiation */
17108c2ecf20Sopenharmony_ci	if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )
17118c2ecf20Sopenharmony_ci		dmfe_phy_write(db->ioaddr, db->phy_addr, 0, 0x1800, db->chip_id);
17128c2ecf20Sopenharmony_ci	if ( !db->chip_type )
17138c2ecf20Sopenharmony_ci		dmfe_phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id);
17148c2ecf20Sopenharmony_ci}
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci/*
17188c2ecf20Sopenharmony_ci *	Process op-mode
17198c2ecf20Sopenharmony_ci *	AUTO mode : PHY controller in Auto-negotiation Mode
17208c2ecf20Sopenharmony_ci *	Force mode: PHY controller in force mode with HUB
17218c2ecf20Sopenharmony_ci *			N-way force capability with SWITCH
17228c2ecf20Sopenharmony_ci */
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_cistatic void dmfe_process_mode(struct dmfe_board_info *db)
17258c2ecf20Sopenharmony_ci{
17268c2ecf20Sopenharmony_ci	u16 phy_reg;
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ci	/* Full Duplex Mode Check */
17298c2ecf20Sopenharmony_ci	if (db->op_mode & 0x4)
17308c2ecf20Sopenharmony_ci		db->cr6_data |= CR6_FDM;	/* Set Full Duplex Bit */
17318c2ecf20Sopenharmony_ci	else
17328c2ecf20Sopenharmony_ci		db->cr6_data &= ~CR6_FDM;	/* Clear Full Duplex Bit */
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	/* Transciver Selection */
17358c2ecf20Sopenharmony_ci	if (db->op_mode & 0x10)		/* 1M HomePNA */
17368c2ecf20Sopenharmony_ci		db->cr6_data |= 0x40000;/* External MII select */
17378c2ecf20Sopenharmony_ci	else
17388c2ecf20Sopenharmony_ci		db->cr6_data &= ~0x40000;/* Internal 10/100 transciver */
17398c2ecf20Sopenharmony_ci
17408c2ecf20Sopenharmony_ci	update_cr6(db->cr6_data, db->ioaddr);
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci	/* 10/100M phyxcer force mode need */
17438c2ecf20Sopenharmony_ci	if ( !(db->media_mode & 0x18)) {
17448c2ecf20Sopenharmony_ci		/* Forece Mode */
17458c2ecf20Sopenharmony_ci		phy_reg = dmfe_phy_read(db->ioaddr, db->phy_addr, 6, db->chip_id);
17468c2ecf20Sopenharmony_ci		if ( !(phy_reg & 0x1) ) {
17478c2ecf20Sopenharmony_ci			/* parter without N-Way capability */
17488c2ecf20Sopenharmony_ci			phy_reg = 0x0;
17498c2ecf20Sopenharmony_ci			switch(db->op_mode) {
17508c2ecf20Sopenharmony_ci			case DMFE_10MHF: phy_reg = 0x0; break;
17518c2ecf20Sopenharmony_ci			case DMFE_10MFD: phy_reg = 0x100; break;
17528c2ecf20Sopenharmony_ci			case DMFE_100MHF: phy_reg = 0x2000; break;
17538c2ecf20Sopenharmony_ci			case DMFE_100MFD: phy_reg = 0x2100; break;
17548c2ecf20Sopenharmony_ci			}
17558c2ecf20Sopenharmony_ci			dmfe_phy_write(db->ioaddr,
17568c2ecf20Sopenharmony_ci				       db->phy_addr, 0, phy_reg, db->chip_id);
17578c2ecf20Sopenharmony_ci       			if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )
17588c2ecf20Sopenharmony_ci				mdelay(20);
17598c2ecf20Sopenharmony_ci			dmfe_phy_write(db->ioaddr,
17608c2ecf20Sopenharmony_ci				       db->phy_addr, 0, phy_reg, db->chip_id);
17618c2ecf20Sopenharmony_ci		}
17628c2ecf20Sopenharmony_ci	}
17638c2ecf20Sopenharmony_ci}
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci/*
17678c2ecf20Sopenharmony_ci *	Write a word to Phy register
17688c2ecf20Sopenharmony_ci */
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_cistatic void dmfe_phy_write(void __iomem *ioaddr, u8 phy_addr, u8 offset,
17718c2ecf20Sopenharmony_ci			   u16 phy_data, u32 chip_id)
17728c2ecf20Sopenharmony_ci{
17738c2ecf20Sopenharmony_ci	u16 i;
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_ci	if (chip_id == PCI_DM9132_ID) {
17768c2ecf20Sopenharmony_ci		dw16(0x80 + offset * 4, phy_data);
17778c2ecf20Sopenharmony_ci	} else {
17788c2ecf20Sopenharmony_ci		/* DM9102/DM9102A Chip */
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci		/* Send 33 synchronization clock to Phy controller */
17818c2ecf20Sopenharmony_ci		for (i = 0; i < 35; i++)
17828c2ecf20Sopenharmony_ci			dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci		/* Send start command(01) to Phy */
17858c2ecf20Sopenharmony_ci		dmfe_phy_write_1bit(ioaddr, PHY_DATA_0);
17868c2ecf20Sopenharmony_ci		dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_ci		/* Send write command(01) to Phy */
17898c2ecf20Sopenharmony_ci		dmfe_phy_write_1bit(ioaddr, PHY_DATA_0);
17908c2ecf20Sopenharmony_ci		dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
17918c2ecf20Sopenharmony_ci
17928c2ecf20Sopenharmony_ci		/* Send Phy address */
17938c2ecf20Sopenharmony_ci		for (i = 0x10; i > 0; i = i >> 1)
17948c2ecf20Sopenharmony_ci			dmfe_phy_write_1bit(ioaddr,
17958c2ecf20Sopenharmony_ci					    phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci		/* Send register address */
17988c2ecf20Sopenharmony_ci		for (i = 0x10; i > 0; i = i >> 1)
17998c2ecf20Sopenharmony_ci			dmfe_phy_write_1bit(ioaddr,
18008c2ecf20Sopenharmony_ci					    offset & i ? PHY_DATA_1 : PHY_DATA_0);
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_ci		/* written trasnition */
18038c2ecf20Sopenharmony_ci		dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
18048c2ecf20Sopenharmony_ci		dmfe_phy_write_1bit(ioaddr, PHY_DATA_0);
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci		/* Write a word data to PHY controller */
18078c2ecf20Sopenharmony_ci		for ( i = 0x8000; i > 0; i >>= 1)
18088c2ecf20Sopenharmony_ci			dmfe_phy_write_1bit(ioaddr,
18098c2ecf20Sopenharmony_ci					    phy_data & i ? PHY_DATA_1 : PHY_DATA_0);
18108c2ecf20Sopenharmony_ci	}
18118c2ecf20Sopenharmony_ci}
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_ci
18148c2ecf20Sopenharmony_ci/*
18158c2ecf20Sopenharmony_ci *	Read a word data from phy register
18168c2ecf20Sopenharmony_ci */
18178c2ecf20Sopenharmony_ci
18188c2ecf20Sopenharmony_cistatic u16 dmfe_phy_read(void __iomem *ioaddr, u8 phy_addr, u8 offset, u32 chip_id)
18198c2ecf20Sopenharmony_ci{
18208c2ecf20Sopenharmony_ci	int i;
18218c2ecf20Sopenharmony_ci	u16 phy_data;
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_ci	if (chip_id == PCI_DM9132_ID) {
18248c2ecf20Sopenharmony_ci		/* DM9132 Chip */
18258c2ecf20Sopenharmony_ci		phy_data = dr16(0x80 + offset * 4);
18268c2ecf20Sopenharmony_ci	} else {
18278c2ecf20Sopenharmony_ci		/* DM9102/DM9102A Chip */
18288c2ecf20Sopenharmony_ci
18298c2ecf20Sopenharmony_ci		/* Send 33 synchronization clock to Phy controller */
18308c2ecf20Sopenharmony_ci		for (i = 0; i < 35; i++)
18318c2ecf20Sopenharmony_ci			dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci		/* Send start command(01) to Phy */
18348c2ecf20Sopenharmony_ci		dmfe_phy_write_1bit(ioaddr, PHY_DATA_0);
18358c2ecf20Sopenharmony_ci		dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci		/* Send read command(10) to Phy */
18388c2ecf20Sopenharmony_ci		dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
18398c2ecf20Sopenharmony_ci		dmfe_phy_write_1bit(ioaddr, PHY_DATA_0);
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci		/* Send Phy address */
18428c2ecf20Sopenharmony_ci		for (i = 0x10; i > 0; i = i >> 1)
18438c2ecf20Sopenharmony_ci			dmfe_phy_write_1bit(ioaddr,
18448c2ecf20Sopenharmony_ci					    phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci		/* Send register address */
18478c2ecf20Sopenharmony_ci		for (i = 0x10; i > 0; i = i >> 1)
18488c2ecf20Sopenharmony_ci			dmfe_phy_write_1bit(ioaddr,
18498c2ecf20Sopenharmony_ci					    offset & i ? PHY_DATA_1 : PHY_DATA_0);
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci		/* Skip transition state */
18528c2ecf20Sopenharmony_ci		dmfe_phy_read_1bit(ioaddr);
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci		/* read 16bit data */
18558c2ecf20Sopenharmony_ci		for (phy_data = 0, i = 0; i < 16; i++) {
18568c2ecf20Sopenharmony_ci			phy_data <<= 1;
18578c2ecf20Sopenharmony_ci			phy_data |= dmfe_phy_read_1bit(ioaddr);
18588c2ecf20Sopenharmony_ci		}
18598c2ecf20Sopenharmony_ci	}
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci	return phy_data;
18628c2ecf20Sopenharmony_ci}
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci/*
18668c2ecf20Sopenharmony_ci *	Write one bit data to Phy Controller
18678c2ecf20Sopenharmony_ci */
18688c2ecf20Sopenharmony_ci
18698c2ecf20Sopenharmony_cistatic void dmfe_phy_write_1bit(void __iomem *ioaddr, u32 phy_data)
18708c2ecf20Sopenharmony_ci{
18718c2ecf20Sopenharmony_ci	dw32(DCR9, phy_data);		/* MII Clock Low */
18728c2ecf20Sopenharmony_ci	udelay(1);
18738c2ecf20Sopenharmony_ci	dw32(DCR9, phy_data | MDCLKH);	/* MII Clock High */
18748c2ecf20Sopenharmony_ci	udelay(1);
18758c2ecf20Sopenharmony_ci	dw32(DCR9, phy_data);		/* MII Clock Low */
18768c2ecf20Sopenharmony_ci	udelay(1);
18778c2ecf20Sopenharmony_ci}
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci
18808c2ecf20Sopenharmony_ci/*
18818c2ecf20Sopenharmony_ci *	Read one bit phy data from PHY controller
18828c2ecf20Sopenharmony_ci */
18838c2ecf20Sopenharmony_ci
18848c2ecf20Sopenharmony_cistatic u16 dmfe_phy_read_1bit(void __iomem *ioaddr)
18858c2ecf20Sopenharmony_ci{
18868c2ecf20Sopenharmony_ci	u16 phy_data;
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_ci	dw32(DCR9, 0x50000);
18898c2ecf20Sopenharmony_ci	udelay(1);
18908c2ecf20Sopenharmony_ci	phy_data = (dr32(DCR9) >> 19) & 0x1;
18918c2ecf20Sopenharmony_ci	dw32(DCR9, 0x40000);
18928c2ecf20Sopenharmony_ci	udelay(1);
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci	return phy_data;
18958c2ecf20Sopenharmony_ci}
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci/*
18998c2ecf20Sopenharmony_ci *	Parser SROM and media mode
19008c2ecf20Sopenharmony_ci */
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_cistatic void dmfe_parse_srom(struct dmfe_board_info * db)
19038c2ecf20Sopenharmony_ci{
19048c2ecf20Sopenharmony_ci	char * srom = db->srom;
19058c2ecf20Sopenharmony_ci	int dmfe_mode, tmp_reg;
19068c2ecf20Sopenharmony_ci
19078c2ecf20Sopenharmony_ci	DMFE_DBUG(0, "dmfe_parse_srom() ", 0);
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci	/* Init CR15 */
19108c2ecf20Sopenharmony_ci	db->cr15_data = CR15_DEFAULT;
19118c2ecf20Sopenharmony_ci
19128c2ecf20Sopenharmony_ci	/* Check SROM Version */
19138c2ecf20Sopenharmony_ci	if ( ( (int) srom[18] & 0xff) == SROM_V41_CODE) {
19148c2ecf20Sopenharmony_ci		/* SROM V4.01 */
19158c2ecf20Sopenharmony_ci		/* Get NIC support media mode */
19168c2ecf20Sopenharmony_ci		db->NIC_capability = le16_to_cpup((__le16 *) (srom + 34));
19178c2ecf20Sopenharmony_ci		db->PHY_reg4 = 0;
19188c2ecf20Sopenharmony_ci		for (tmp_reg = 1; tmp_reg < 0x10; tmp_reg <<= 1) {
19198c2ecf20Sopenharmony_ci			switch( db->NIC_capability & tmp_reg ) {
19208c2ecf20Sopenharmony_ci			case 0x1: db->PHY_reg4 |= 0x0020; break;
19218c2ecf20Sopenharmony_ci			case 0x2: db->PHY_reg4 |= 0x0040; break;
19228c2ecf20Sopenharmony_ci			case 0x4: db->PHY_reg4 |= 0x0080; break;
19238c2ecf20Sopenharmony_ci			case 0x8: db->PHY_reg4 |= 0x0100; break;
19248c2ecf20Sopenharmony_ci			}
19258c2ecf20Sopenharmony_ci		}
19268c2ecf20Sopenharmony_ci
19278c2ecf20Sopenharmony_ci		/* Media Mode Force or not check */
19288c2ecf20Sopenharmony_ci		dmfe_mode = (le32_to_cpup((__le32 *) (srom + 34)) &
19298c2ecf20Sopenharmony_ci			     le32_to_cpup((__le32 *) (srom + 36)));
19308c2ecf20Sopenharmony_ci		switch(dmfe_mode) {
19318c2ecf20Sopenharmony_ci		case 0x4: dmfe_media_mode = DMFE_100MHF; break;	/* 100MHF */
19328c2ecf20Sopenharmony_ci		case 0x2: dmfe_media_mode = DMFE_10MFD; break;	/* 10MFD */
19338c2ecf20Sopenharmony_ci		case 0x8: dmfe_media_mode = DMFE_100MFD; break;	/* 100MFD */
19348c2ecf20Sopenharmony_ci		case 0x100:
19358c2ecf20Sopenharmony_ci		case 0x200: dmfe_media_mode = DMFE_1M_HPNA; break;/* HomePNA */
19368c2ecf20Sopenharmony_ci		}
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_ci		/* Special Function setting */
19398c2ecf20Sopenharmony_ci		/* VLAN function */
19408c2ecf20Sopenharmony_ci		if ( (SF_mode & 0x1) || (srom[43] & 0x80) )
19418c2ecf20Sopenharmony_ci			db->cr15_data |= 0x40;
19428c2ecf20Sopenharmony_ci
19438c2ecf20Sopenharmony_ci		/* Flow Control */
19448c2ecf20Sopenharmony_ci		if ( (SF_mode & 0x2) || (srom[40] & 0x1) )
19458c2ecf20Sopenharmony_ci			db->cr15_data |= 0x400;
19468c2ecf20Sopenharmony_ci
19478c2ecf20Sopenharmony_ci		/* TX pause packet */
19488c2ecf20Sopenharmony_ci		if ( (SF_mode & 0x4) || (srom[40] & 0xe) )
19498c2ecf20Sopenharmony_ci			db->cr15_data |= 0x9800;
19508c2ecf20Sopenharmony_ci	}
19518c2ecf20Sopenharmony_ci
19528c2ecf20Sopenharmony_ci	/* Parse HPNA parameter */
19538c2ecf20Sopenharmony_ci	db->HPNA_command = 1;
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ci	/* Accept remote command or not */
19568c2ecf20Sopenharmony_ci	if (HPNA_rx_cmd == 0)
19578c2ecf20Sopenharmony_ci		db->HPNA_command |= 0x8000;
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_ci	 /* Issue remote command & operation mode */
19608c2ecf20Sopenharmony_ci	if (HPNA_tx_cmd == 1)
19618c2ecf20Sopenharmony_ci		switch(HPNA_mode) {	/* Issue Remote Command */
19628c2ecf20Sopenharmony_ci		case 0: db->HPNA_command |= 0x0904; break;
19638c2ecf20Sopenharmony_ci		case 1: db->HPNA_command |= 0x0a00; break;
19648c2ecf20Sopenharmony_ci		case 2: db->HPNA_command |= 0x0506; break;
19658c2ecf20Sopenharmony_ci		case 3: db->HPNA_command |= 0x0602; break;
19668c2ecf20Sopenharmony_ci		}
19678c2ecf20Sopenharmony_ci	else
19688c2ecf20Sopenharmony_ci		switch(HPNA_mode) {	/* Don't Issue */
19698c2ecf20Sopenharmony_ci		case 0: db->HPNA_command |= 0x0004; break;
19708c2ecf20Sopenharmony_ci		case 1: db->HPNA_command |= 0x0000; break;
19718c2ecf20Sopenharmony_ci		case 2: db->HPNA_command |= 0x0006; break;
19728c2ecf20Sopenharmony_ci		case 3: db->HPNA_command |= 0x0002; break;
19738c2ecf20Sopenharmony_ci		}
19748c2ecf20Sopenharmony_ci
19758c2ecf20Sopenharmony_ci	/* Check DM9801 or DM9802 present or not */
19768c2ecf20Sopenharmony_ci	db->HPNA_present = 0;
19778c2ecf20Sopenharmony_ci	update_cr6(db->cr6_data | 0x40000, db->ioaddr);
19788c2ecf20Sopenharmony_ci	tmp_reg = dmfe_phy_read(db->ioaddr, db->phy_addr, 3, db->chip_id);
19798c2ecf20Sopenharmony_ci	if ( ( tmp_reg & 0xfff0 ) == 0xb900 ) {
19808c2ecf20Sopenharmony_ci		/* DM9801 or DM9802 present */
19818c2ecf20Sopenharmony_ci		db->HPNA_timer = 8;
19828c2ecf20Sopenharmony_ci		if ( dmfe_phy_read(db->ioaddr, db->phy_addr, 31, db->chip_id) == 0x4404) {
19838c2ecf20Sopenharmony_ci			/* DM9801 HomeRun */
19848c2ecf20Sopenharmony_ci			db->HPNA_present = 1;
19858c2ecf20Sopenharmony_ci			dmfe_program_DM9801(db, tmp_reg);
19868c2ecf20Sopenharmony_ci		} else {
19878c2ecf20Sopenharmony_ci			/* DM9802 LongRun */
19888c2ecf20Sopenharmony_ci			db->HPNA_present = 2;
19898c2ecf20Sopenharmony_ci			dmfe_program_DM9802(db);
19908c2ecf20Sopenharmony_ci		}
19918c2ecf20Sopenharmony_ci	}
19928c2ecf20Sopenharmony_ci
19938c2ecf20Sopenharmony_ci}
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_ci
19968c2ecf20Sopenharmony_ci/*
19978c2ecf20Sopenharmony_ci *	Init HomeRun DM9801
19988c2ecf20Sopenharmony_ci */
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_cistatic void dmfe_program_DM9801(struct dmfe_board_info * db, int HPNA_rev)
20018c2ecf20Sopenharmony_ci{
20028c2ecf20Sopenharmony_ci	uint reg17, reg25;
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_ci	if ( !HPNA_NoiseFloor ) HPNA_NoiseFloor = DM9801_NOISE_FLOOR;
20058c2ecf20Sopenharmony_ci	switch(HPNA_rev) {
20068c2ecf20Sopenharmony_ci	case 0xb900: /* DM9801 E3 */
20078c2ecf20Sopenharmony_ci		db->HPNA_command |= 0x1000;
20088c2ecf20Sopenharmony_ci		reg25 = dmfe_phy_read(db->ioaddr, db->phy_addr, 24, db->chip_id);
20098c2ecf20Sopenharmony_ci		reg25 = ( (reg25 + HPNA_NoiseFloor) & 0xff) | 0xf000;
20108c2ecf20Sopenharmony_ci		reg17 = dmfe_phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
20118c2ecf20Sopenharmony_ci		break;
20128c2ecf20Sopenharmony_ci	case 0xb901: /* DM9801 E4 */
20138c2ecf20Sopenharmony_ci		reg25 = dmfe_phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
20148c2ecf20Sopenharmony_ci		reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor;
20158c2ecf20Sopenharmony_ci		reg17 = dmfe_phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
20168c2ecf20Sopenharmony_ci		reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor + 3;
20178c2ecf20Sopenharmony_ci		break;
20188c2ecf20Sopenharmony_ci	case 0xb902: /* DM9801 E5 */
20198c2ecf20Sopenharmony_ci	case 0xb903: /* DM9801 E6 */
20208c2ecf20Sopenharmony_ci	default:
20218c2ecf20Sopenharmony_ci		db->HPNA_command |= 0x1000;
20228c2ecf20Sopenharmony_ci		reg25 = dmfe_phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
20238c2ecf20Sopenharmony_ci		reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor - 5;
20248c2ecf20Sopenharmony_ci		reg17 = dmfe_phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
20258c2ecf20Sopenharmony_ci		reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor;
20268c2ecf20Sopenharmony_ci		break;
20278c2ecf20Sopenharmony_ci	}
20288c2ecf20Sopenharmony_ci	dmfe_phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
20298c2ecf20Sopenharmony_ci	dmfe_phy_write(db->ioaddr, db->phy_addr, 17, reg17, db->chip_id);
20308c2ecf20Sopenharmony_ci	dmfe_phy_write(db->ioaddr, db->phy_addr, 25, reg25, db->chip_id);
20318c2ecf20Sopenharmony_ci}
20328c2ecf20Sopenharmony_ci
20338c2ecf20Sopenharmony_ci
20348c2ecf20Sopenharmony_ci/*
20358c2ecf20Sopenharmony_ci *	Init HomeRun DM9802
20368c2ecf20Sopenharmony_ci */
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_cistatic void dmfe_program_DM9802(struct dmfe_board_info * db)
20398c2ecf20Sopenharmony_ci{
20408c2ecf20Sopenharmony_ci	uint phy_reg;
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci	if ( !HPNA_NoiseFloor ) HPNA_NoiseFloor = DM9802_NOISE_FLOOR;
20438c2ecf20Sopenharmony_ci	dmfe_phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
20448c2ecf20Sopenharmony_ci	phy_reg = dmfe_phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
20458c2ecf20Sopenharmony_ci	phy_reg = ( phy_reg & 0xff00) + HPNA_NoiseFloor;
20468c2ecf20Sopenharmony_ci	dmfe_phy_write(db->ioaddr, db->phy_addr, 25, phy_reg, db->chip_id);
20478c2ecf20Sopenharmony_ci}
20488c2ecf20Sopenharmony_ci
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci/*
20518c2ecf20Sopenharmony_ci *	Check remote HPNA power and speed status. If not correct,
20528c2ecf20Sopenharmony_ci *	issue command again.
20538c2ecf20Sopenharmony_ci*/
20548c2ecf20Sopenharmony_ci
20558c2ecf20Sopenharmony_cistatic void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * db)
20568c2ecf20Sopenharmony_ci{
20578c2ecf20Sopenharmony_ci	uint phy_reg;
20588c2ecf20Sopenharmony_ci
20598c2ecf20Sopenharmony_ci	/* Got remote device status */
20608c2ecf20Sopenharmony_ci	phy_reg = dmfe_phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0x60;
20618c2ecf20Sopenharmony_ci	switch(phy_reg) {
20628c2ecf20Sopenharmony_ci	case 0x00: phy_reg = 0x0a00;break; /* LP/LS */
20638c2ecf20Sopenharmony_ci	case 0x20: phy_reg = 0x0900;break; /* LP/HS */
20648c2ecf20Sopenharmony_ci	case 0x40: phy_reg = 0x0600;break; /* HP/LS */
20658c2ecf20Sopenharmony_ci	case 0x60: phy_reg = 0x0500;break; /* HP/HS */
20668c2ecf20Sopenharmony_ci	}
20678c2ecf20Sopenharmony_ci
20688c2ecf20Sopenharmony_ci	/* Check remote device status match our setting ot not */
20698c2ecf20Sopenharmony_ci	if ( phy_reg != (db->HPNA_command & 0x0f00) ) {
20708c2ecf20Sopenharmony_ci		dmfe_phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command,
20718c2ecf20Sopenharmony_ci			       db->chip_id);
20728c2ecf20Sopenharmony_ci		db->HPNA_timer=8;
20738c2ecf20Sopenharmony_ci	} else
20748c2ecf20Sopenharmony_ci		db->HPNA_timer=600;	/* Match, every 10 minutes, check */
20758c2ecf20Sopenharmony_ci}
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_ci
20788c2ecf20Sopenharmony_ci
20798c2ecf20Sopenharmony_cistatic const struct pci_device_id dmfe_pci_tbl[] = {
20808c2ecf20Sopenharmony_ci	{ 0x1282, 0x9132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9132_ID },
20818c2ecf20Sopenharmony_ci	{ 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9102_ID },
20828c2ecf20Sopenharmony_ci	{ 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9100_ID },
20838c2ecf20Sopenharmony_ci	{ 0x1282, 0x9009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9009_ID },
20848c2ecf20Sopenharmony_ci	{ 0, }
20858c2ecf20Sopenharmony_ci};
20868c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, dmfe_pci_tbl);
20878c2ecf20Sopenharmony_ci
20888c2ecf20Sopenharmony_cistatic int __maybe_unused dmfe_suspend(struct device *dev_d)
20898c2ecf20Sopenharmony_ci{
20908c2ecf20Sopenharmony_ci	struct net_device *dev = dev_get_drvdata(dev_d);
20918c2ecf20Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
20928c2ecf20Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
20938c2ecf20Sopenharmony_ci
20948c2ecf20Sopenharmony_ci	/* Disable upper layer interface */
20958c2ecf20Sopenharmony_ci	netif_device_detach(dev);
20968c2ecf20Sopenharmony_ci
20978c2ecf20Sopenharmony_ci	/* Disable Tx/Rx */
20988c2ecf20Sopenharmony_ci	db->cr6_data &= ~(CR6_RXSC | CR6_TXSC);
20998c2ecf20Sopenharmony_ci	update_cr6(db->cr6_data, ioaddr);
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_ci	/* Disable Interrupt */
21028c2ecf20Sopenharmony_ci	dw32(DCR7, 0);
21038c2ecf20Sopenharmony_ci	dw32(DCR5, dr32(DCR5));
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_ci	/* Fre RX buffers */
21068c2ecf20Sopenharmony_ci	dmfe_free_rxbuffer(db);
21078c2ecf20Sopenharmony_ci
21088c2ecf20Sopenharmony_ci	/* Enable WOL */
21098c2ecf20Sopenharmony_ci	device_wakeup_enable(dev_d);
21108c2ecf20Sopenharmony_ci
21118c2ecf20Sopenharmony_ci	return 0;
21128c2ecf20Sopenharmony_ci}
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_cistatic int __maybe_unused dmfe_resume(struct device *dev_d)
21158c2ecf20Sopenharmony_ci{
21168c2ecf20Sopenharmony_ci	struct net_device *dev = dev_get_drvdata(dev_d);
21178c2ecf20Sopenharmony_ci
21188c2ecf20Sopenharmony_ci	/* Re-initialize DM910X board */
21198c2ecf20Sopenharmony_ci	dmfe_init_dm910x(dev);
21208c2ecf20Sopenharmony_ci
21218c2ecf20Sopenharmony_ci	/* Disable WOL */
21228c2ecf20Sopenharmony_ci	device_wakeup_disable(dev_d);
21238c2ecf20Sopenharmony_ci
21248c2ecf20Sopenharmony_ci	/* Restart upper layer interface */
21258c2ecf20Sopenharmony_ci	netif_device_attach(dev);
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci	return 0;
21288c2ecf20Sopenharmony_ci}
21298c2ecf20Sopenharmony_ci
21308c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(dmfe_pm_ops, dmfe_suspend, dmfe_resume);
21318c2ecf20Sopenharmony_ci
21328c2ecf20Sopenharmony_cistatic struct pci_driver dmfe_driver = {
21338c2ecf20Sopenharmony_ci	.name		= "dmfe",
21348c2ecf20Sopenharmony_ci	.id_table	= dmfe_pci_tbl,
21358c2ecf20Sopenharmony_ci	.probe		= dmfe_init_one,
21368c2ecf20Sopenharmony_ci	.remove		= dmfe_remove_one,
21378c2ecf20Sopenharmony_ci	.driver.pm	= &dmfe_pm_ops,
21388c2ecf20Sopenharmony_ci};
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw");
21418c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Davicom DM910X fast ethernet driver");
21428c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
21438c2ecf20Sopenharmony_ci
21448c2ecf20Sopenharmony_cimodule_param(debug, int, 0);
21458c2ecf20Sopenharmony_cimodule_param(mode, byte, 0);
21468c2ecf20Sopenharmony_cimodule_param(cr6set, int, 0);
21478c2ecf20Sopenharmony_cimodule_param(chkmode, byte, 0);
21488c2ecf20Sopenharmony_cimodule_param(HPNA_mode, byte, 0);
21498c2ecf20Sopenharmony_cimodule_param(HPNA_rx_cmd, byte, 0);
21508c2ecf20Sopenharmony_cimodule_param(HPNA_tx_cmd, byte, 0);
21518c2ecf20Sopenharmony_cimodule_param(HPNA_NoiseFloor, byte, 0);
21528c2ecf20Sopenharmony_cimodule_param(SF_mode, byte, 0);
21538c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Davicom DM9xxx enable debugging (0-1)");
21548c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mode, "Davicom DM9xxx: "
21558c2ecf20Sopenharmony_ci		"Bit 0: 10/100Mbps, bit 2: duplex, bit 8: HomePNA");
21568c2ecf20Sopenharmony_ci
21578c2ecf20Sopenharmony_ciMODULE_PARM_DESC(SF_mode, "Davicom DM9xxx special function "
21588c2ecf20Sopenharmony_ci		"(bit 0: VLAN, bit 1 Flow Control, bit 2: TX pause packet)");
21598c2ecf20Sopenharmony_ci
21608c2ecf20Sopenharmony_ci/*	Description:
21618c2ecf20Sopenharmony_ci *	when user used insmod to add module, system invoked init_module()
21628c2ecf20Sopenharmony_ci *	to initialize and register.
21638c2ecf20Sopenharmony_ci */
21648c2ecf20Sopenharmony_ci
21658c2ecf20Sopenharmony_cistatic int __init dmfe_init_module(void)
21668c2ecf20Sopenharmony_ci{
21678c2ecf20Sopenharmony_ci	int rc;
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_ci	DMFE_DBUG(0, "init_module() ", debug);
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_ci	if (debug)
21728c2ecf20Sopenharmony_ci		dmfe_debug = debug;	/* set debug flag */
21738c2ecf20Sopenharmony_ci	if (cr6set)
21748c2ecf20Sopenharmony_ci		dmfe_cr6_user_set = cr6set;
21758c2ecf20Sopenharmony_ci
21768c2ecf20Sopenharmony_ci	switch (mode) {
21778c2ecf20Sopenharmony_ci	case DMFE_10MHF:
21788c2ecf20Sopenharmony_ci	case DMFE_100MHF:
21798c2ecf20Sopenharmony_ci	case DMFE_10MFD:
21808c2ecf20Sopenharmony_ci	case DMFE_100MFD:
21818c2ecf20Sopenharmony_ci	case DMFE_1M_HPNA:
21828c2ecf20Sopenharmony_ci		dmfe_media_mode = mode;
21838c2ecf20Sopenharmony_ci		break;
21848c2ecf20Sopenharmony_ci	default:
21858c2ecf20Sopenharmony_ci		dmfe_media_mode = DMFE_AUTO;
21868c2ecf20Sopenharmony_ci		break;
21878c2ecf20Sopenharmony_ci	}
21888c2ecf20Sopenharmony_ci
21898c2ecf20Sopenharmony_ci	if (HPNA_mode > 4)
21908c2ecf20Sopenharmony_ci		HPNA_mode = 0;		/* Default: LP/HS */
21918c2ecf20Sopenharmony_ci	if (HPNA_rx_cmd > 1)
21928c2ecf20Sopenharmony_ci		HPNA_rx_cmd = 0;	/* Default: Ignored remote cmd */
21938c2ecf20Sopenharmony_ci	if (HPNA_tx_cmd > 1)
21948c2ecf20Sopenharmony_ci		HPNA_tx_cmd = 0;	/* Default: Don't issue remote cmd */
21958c2ecf20Sopenharmony_ci	if (HPNA_NoiseFloor > 15)
21968c2ecf20Sopenharmony_ci		HPNA_NoiseFloor = 0;
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_ci	rc = pci_register_driver(&dmfe_driver);
21998c2ecf20Sopenharmony_ci	if (rc < 0)
22008c2ecf20Sopenharmony_ci		return rc;
22018c2ecf20Sopenharmony_ci
22028c2ecf20Sopenharmony_ci	return 0;
22038c2ecf20Sopenharmony_ci}
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_ci
22068c2ecf20Sopenharmony_ci/*
22078c2ecf20Sopenharmony_ci *	Description:
22088c2ecf20Sopenharmony_ci *	when user used rmmod to delete module, system invoked clean_module()
22098c2ecf20Sopenharmony_ci *	to un-register all registered services.
22108c2ecf20Sopenharmony_ci */
22118c2ecf20Sopenharmony_ci
22128c2ecf20Sopenharmony_cistatic void __exit dmfe_cleanup_module(void)
22138c2ecf20Sopenharmony_ci{
22148c2ecf20Sopenharmony_ci	DMFE_DBUG(0, "dmfe_cleanup_module() ", debug);
22158c2ecf20Sopenharmony_ci	pci_unregister_driver(&dmfe_driver);
22168c2ecf20Sopenharmony_ci}
22178c2ecf20Sopenharmony_ci
22188c2ecf20Sopenharmony_cimodule_init(dmfe_init_module);
22198c2ecf20Sopenharmony_cimodule_exit(dmfe_cleanup_module);
2220