162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci    A Davicom DM9102/DM9102A/DM9102A+DM9801/DM9102A+DM9802 NIC fast
462306a36Sopenharmony_ci    ethernet driver for Linux.
562306a36Sopenharmony_ci    Copyright (C) 1997  Sten Wang
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci    DAVICOM Web-Site: www.davicom.com.tw
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci    Author: Sten Wang, 886-3-5798797-8517, E-mail: sten_wang@davicom.com.tw
1162306a36Sopenharmony_ci    Maintainer: Tobias Ringstrom <tori@unhappy.mine.nu>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci    (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved.
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci    Marcelo Tosatti <marcelo@conectiva.com.br> :
1662306a36Sopenharmony_ci    Made it compile in 2.3 (device to net_device)
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci    Alan Cox <alan@lxorguk.ukuu.org.uk> :
1962306a36Sopenharmony_ci    Cleaned up for kernel merge.
2062306a36Sopenharmony_ci    Removed the back compatibility support
2162306a36Sopenharmony_ci    Reformatted, fixing spelling etc as I went
2262306a36Sopenharmony_ci    Removed IRQ 0-15 assumption
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci    Jeff Garzik <jgarzik@pobox.com> :
2562306a36Sopenharmony_ci    Updated to use new PCI driver API.
2662306a36Sopenharmony_ci    Resource usage cleanups.
2762306a36Sopenharmony_ci    Report driver version to user.
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci    Tobias Ringstrom <tori@unhappy.mine.nu> :
3062306a36Sopenharmony_ci    Cleaned up and added SMP safety.  Thanks go to Jeff Garzik,
3162306a36Sopenharmony_ci    Andrew Morton and Frank Davis for the SMP safety fixes.
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci    Vojtech Pavlik <vojtech@suse.cz> :
3462306a36Sopenharmony_ci    Cleaned up pointer arithmetics.
3562306a36Sopenharmony_ci    Fixed a lot of 64bit issues.
3662306a36Sopenharmony_ci    Cleaned up printk()s a bit.
3762306a36Sopenharmony_ci    Fixed some obvious big endian problems.
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci    Tobias Ringstrom <tori@unhappy.mine.nu> :
4062306a36Sopenharmony_ci    Use time_after for jiffies calculation.  Added ethtool
4162306a36Sopenharmony_ci    support.  Updated PCI resource allocation.  Do not
4262306a36Sopenharmony_ci    forget to unmap PCI mapped skbs.
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci    Alan Cox <alan@lxorguk.ukuu.org.uk>
4562306a36Sopenharmony_ci    Added new PCI identifiers provided by Clear Zhang at ALi
4662306a36Sopenharmony_ci    for their 1563 ethernet device.
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci    TODO
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci    Check on 64 bit boxes.
5162306a36Sopenharmony_ci    Check and fix on big endian boxes.
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci    Test and make sure PCI latency is now correct for all cases.
5462306a36Sopenharmony_ci*/
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#define DRV_NAME	"dmfe"
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#include <linux/module.h>
6162306a36Sopenharmony_ci#include <linux/kernel.h>
6262306a36Sopenharmony_ci#include <linux/string.h>
6362306a36Sopenharmony_ci#include <linux/timer.h>
6462306a36Sopenharmony_ci#include <linux/ptrace.h>
6562306a36Sopenharmony_ci#include <linux/errno.h>
6662306a36Sopenharmony_ci#include <linux/ioport.h>
6762306a36Sopenharmony_ci#include <linux/interrupt.h>
6862306a36Sopenharmony_ci#include <linux/pci.h>
6962306a36Sopenharmony_ci#include <linux/dma-mapping.h>
7062306a36Sopenharmony_ci#include <linux/init.h>
7162306a36Sopenharmony_ci#include <linux/netdevice.h>
7262306a36Sopenharmony_ci#include <linux/etherdevice.h>
7362306a36Sopenharmony_ci#include <linux/ethtool.h>
7462306a36Sopenharmony_ci#include <linux/skbuff.h>
7562306a36Sopenharmony_ci#include <linux/delay.h>
7662306a36Sopenharmony_ci#include <linux/spinlock.h>
7762306a36Sopenharmony_ci#include <linux/crc32.h>
7862306a36Sopenharmony_ci#include <linux/bitops.h>
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci#include <asm/processor.h>
8162306a36Sopenharmony_ci#include <asm/io.h>
8262306a36Sopenharmony_ci#include <asm/dma.h>
8362306a36Sopenharmony_ci#include <linux/uaccess.h>
8462306a36Sopenharmony_ci#include <asm/irq.h>
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci#ifdef CONFIG_TULIP_DM910X
8762306a36Sopenharmony_ci#include <linux/of.h>
8862306a36Sopenharmony_ci#endif
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/* Board/System/Debug information/definition ---------------- */
9262306a36Sopenharmony_ci#define PCI_DM9132_ID   0x91321282      /* Davicom DM9132 ID */
9362306a36Sopenharmony_ci#define PCI_DM9102_ID   0x91021282      /* Davicom DM9102 ID */
9462306a36Sopenharmony_ci#define PCI_DM9100_ID   0x91001282      /* Davicom DM9100 ID */
9562306a36Sopenharmony_ci#define PCI_DM9009_ID   0x90091282      /* Davicom DM9009 ID */
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci#define DM9102_IO_SIZE  0x80
9862306a36Sopenharmony_ci#define DM9102A_IO_SIZE 0x100
9962306a36Sopenharmony_ci#define TX_MAX_SEND_CNT 0x1             /* Maximum tx packet per time */
10062306a36Sopenharmony_ci#define TX_DESC_CNT     0x10            /* Allocated Tx descriptors */
10162306a36Sopenharmony_ci#define RX_DESC_CNT     0x20            /* Allocated Rx descriptors */
10262306a36Sopenharmony_ci#define TX_FREE_DESC_CNT (TX_DESC_CNT - 2)	/* Max TX packet count */
10362306a36Sopenharmony_ci#define TX_WAKE_DESC_CNT (TX_DESC_CNT - 3)	/* TX wakeup count */
10462306a36Sopenharmony_ci#define DESC_ALL_CNT    (TX_DESC_CNT + RX_DESC_CNT)
10562306a36Sopenharmony_ci#define TX_BUF_ALLOC    0x600
10662306a36Sopenharmony_ci#define RX_ALLOC_SIZE   0x620
10762306a36Sopenharmony_ci#define DM910X_RESET    1
10862306a36Sopenharmony_ci#define CR0_DEFAULT     0x00E00000      /* TX & RX burst mode */
10962306a36Sopenharmony_ci#define CR6_DEFAULT     0x00080000      /* HD */
11062306a36Sopenharmony_ci#define CR7_DEFAULT     0x180c1
11162306a36Sopenharmony_ci#define CR15_DEFAULT    0x06            /* TxJabber RxWatchdog */
11262306a36Sopenharmony_ci#define TDES0_ERR_MASK  0x4302          /* TXJT, LC, EC, FUE */
11362306a36Sopenharmony_ci#define MAX_PACKET_SIZE 1514
11462306a36Sopenharmony_ci#define DMFE_MAX_MULTICAST 14
11562306a36Sopenharmony_ci#define RX_COPY_SIZE	100
11662306a36Sopenharmony_ci#define MAX_CHECK_PACKET 0x8000
11762306a36Sopenharmony_ci#define DM9801_NOISE_FLOOR 8
11862306a36Sopenharmony_ci#define DM9802_NOISE_FLOOR 5
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci#define DMFE_WOL_LINKCHANGE	0x20000000
12162306a36Sopenharmony_ci#define DMFE_WOL_SAMPLEPACKET	0x10000000
12262306a36Sopenharmony_ci#define DMFE_WOL_MAGICPACKET	0x08000000
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci#define DMFE_10MHF      0
12662306a36Sopenharmony_ci#define DMFE_100MHF     1
12762306a36Sopenharmony_ci#define DMFE_10MFD      4
12862306a36Sopenharmony_ci#define DMFE_100MFD     5
12962306a36Sopenharmony_ci#define DMFE_AUTO       8
13062306a36Sopenharmony_ci#define DMFE_1M_HPNA    0x10
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci#define DMFE_TXTH_72	0x400000	/* TX TH 72 byte */
13362306a36Sopenharmony_ci#define DMFE_TXTH_96	0x404000	/* TX TH 96 byte */
13462306a36Sopenharmony_ci#define DMFE_TXTH_128	0x0000		/* TX TH 128 byte */
13562306a36Sopenharmony_ci#define DMFE_TXTH_256	0x4000		/* TX TH 256 byte */
13662306a36Sopenharmony_ci#define DMFE_TXTH_512	0x8000		/* TX TH 512 byte */
13762306a36Sopenharmony_ci#define DMFE_TXTH_1K	0xC000		/* TX TH 1K  byte */
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci#define DMFE_TIMER_WUT  (jiffies + HZ * 1)/* timer wakeup time : 1 second */
14062306a36Sopenharmony_ci#define DMFE_TX_TIMEOUT ((3*HZ)/2)	/* tx packet time-out time 1.5 s" */
14162306a36Sopenharmony_ci#define DMFE_TX_KICK 	(HZ/2)	/* tx packet Kick-out time 0.5 s" */
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci#define dw32(reg, val)	iowrite32(val, ioaddr + (reg))
14462306a36Sopenharmony_ci#define dw16(reg, val)	iowrite16(val, ioaddr + (reg))
14562306a36Sopenharmony_ci#define dr32(reg)	ioread32(ioaddr + (reg))
14662306a36Sopenharmony_ci#define dr16(reg)	ioread16(ioaddr + (reg))
14762306a36Sopenharmony_ci#define dr8(reg)	ioread8(ioaddr + (reg))
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci#define DMFE_DBUG(dbug_now, msg, value)			\
15062306a36Sopenharmony_ci	do {						\
15162306a36Sopenharmony_ci		if (dmfe_debug || (dbug_now))		\
15262306a36Sopenharmony_ci			pr_err("%s %lx\n",		\
15362306a36Sopenharmony_ci			       (msg), (long) (value));	\
15462306a36Sopenharmony_ci	} while (0)
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci#define SHOW_MEDIA_TYPE(mode)				\
15762306a36Sopenharmony_ci	pr_info("Change Speed to %sMhz %s duplex\n" ,	\
15862306a36Sopenharmony_ci		(mode & 1) ? "100":"10",		\
15962306a36Sopenharmony_ci		(mode & 4) ? "full":"half");
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci/* CR9 definition: SROM/MII */
16362306a36Sopenharmony_ci#define CR9_SROM_READ   0x4800
16462306a36Sopenharmony_ci#define CR9_SRCS        0x1
16562306a36Sopenharmony_ci#define CR9_SRCLK       0x2
16662306a36Sopenharmony_ci#define CR9_CRDOUT      0x8
16762306a36Sopenharmony_ci#define SROM_DATA_0     0x0
16862306a36Sopenharmony_ci#define SROM_DATA_1     0x4
16962306a36Sopenharmony_ci#define PHY_DATA_1      0x20000
17062306a36Sopenharmony_ci#define PHY_DATA_0      0x00000
17162306a36Sopenharmony_ci#define MDCLKH          0x10000
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci#define PHY_POWER_DOWN	0x800
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci#define SROM_V41_CODE   0x14
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci#define __CHK_IO_SIZE(pci_id, dev_rev) \
17862306a36Sopenharmony_ci (( ((pci_id)==PCI_DM9132_ID) || ((dev_rev) >= 0x30) ) ? \
17962306a36Sopenharmony_ci	DM9102A_IO_SIZE: DM9102_IO_SIZE)
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci#define CHK_IO_SIZE(pci_dev) \
18262306a36Sopenharmony_ci	(__CHK_IO_SIZE(((pci_dev)->device << 16) | (pci_dev)->vendor, \
18362306a36Sopenharmony_ci	(pci_dev)->revision))
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci/* Structure/enum declaration ------------------------------- */
18662306a36Sopenharmony_cistruct tx_desc {
18762306a36Sopenharmony_ci        __le32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */
18862306a36Sopenharmony_ci        char *tx_buf_ptr;               /* Data for us */
18962306a36Sopenharmony_ci        struct tx_desc *next_tx_desc;
19062306a36Sopenharmony_ci} __attribute__(( aligned(32) ));
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistruct rx_desc {
19362306a36Sopenharmony_ci	__le32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */
19462306a36Sopenharmony_ci	struct sk_buff *rx_skb_ptr;	/* Data for us */
19562306a36Sopenharmony_ci	struct rx_desc *next_rx_desc;
19662306a36Sopenharmony_ci} __attribute__(( aligned(32) ));
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cistruct dmfe_board_info {
19962306a36Sopenharmony_ci	u32 chip_id;			/* Chip vendor/Device ID */
20062306a36Sopenharmony_ci	u8 chip_revision;		/* Chip revision */
20162306a36Sopenharmony_ci	struct net_device *next_dev;	/* next device */
20262306a36Sopenharmony_ci	struct pci_dev *pdev;		/* PCI device */
20362306a36Sopenharmony_ci	spinlock_t lock;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	void __iomem *ioaddr;		/* I/O base address */
20662306a36Sopenharmony_ci	u32 cr0_data;
20762306a36Sopenharmony_ci	u32 cr5_data;
20862306a36Sopenharmony_ci	u32 cr6_data;
20962306a36Sopenharmony_ci	u32 cr7_data;
21062306a36Sopenharmony_ci	u32 cr15_data;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	/* pointer for memory physical address */
21362306a36Sopenharmony_ci	dma_addr_t buf_pool_dma_ptr;	/* Tx buffer pool memory */
21462306a36Sopenharmony_ci	dma_addr_t buf_pool_dma_start;	/* Tx buffer pool align dword */
21562306a36Sopenharmony_ci	dma_addr_t desc_pool_dma_ptr;	/* descriptor pool memory */
21662306a36Sopenharmony_ci	dma_addr_t first_tx_desc_dma;
21762306a36Sopenharmony_ci	dma_addr_t first_rx_desc_dma;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	/* descriptor pointer */
22062306a36Sopenharmony_ci	unsigned char *buf_pool_ptr;	/* Tx buffer pool memory */
22162306a36Sopenharmony_ci	unsigned char *buf_pool_start;	/* Tx buffer pool align dword */
22262306a36Sopenharmony_ci	unsigned char *desc_pool_ptr;	/* descriptor pool memory */
22362306a36Sopenharmony_ci	struct tx_desc *first_tx_desc;
22462306a36Sopenharmony_ci	struct tx_desc *tx_insert_ptr;
22562306a36Sopenharmony_ci	struct tx_desc *tx_remove_ptr;
22662306a36Sopenharmony_ci	struct rx_desc *first_rx_desc;
22762306a36Sopenharmony_ci	struct rx_desc *rx_insert_ptr;
22862306a36Sopenharmony_ci	struct rx_desc *rx_ready_ptr;	/* packet come pointer */
22962306a36Sopenharmony_ci	unsigned long tx_packet_cnt;	/* transmitted packet count */
23062306a36Sopenharmony_ci	unsigned long tx_queue_cnt;	/* wait to send packet count */
23162306a36Sopenharmony_ci	unsigned long rx_avail_cnt;	/* available rx descriptor count */
23262306a36Sopenharmony_ci	unsigned long interval_rx_cnt;	/* rx packet count a callback time */
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	u16 HPNA_command;		/* For HPNA register 16 */
23562306a36Sopenharmony_ci	u16 HPNA_timer;			/* For HPNA remote device check */
23662306a36Sopenharmony_ci	u16 dbug_cnt;
23762306a36Sopenharmony_ci	u16 NIC_capability;		/* NIC media capability */
23862306a36Sopenharmony_ci	u16 PHY_reg4;			/* Saved Phyxcer register 4 value */
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	u8 HPNA_present;		/* 0:none, 1:DM9801, 2:DM9802 */
24162306a36Sopenharmony_ci	u8 chip_type;			/* Keep DM9102A chip type */
24262306a36Sopenharmony_ci	u8 media_mode;			/* user specify media mode */
24362306a36Sopenharmony_ci	u8 op_mode;			/* real work media mode */
24462306a36Sopenharmony_ci	u8 phy_addr;
24562306a36Sopenharmony_ci	u8 wait_reset;			/* Hardware failed, need to reset */
24662306a36Sopenharmony_ci	u8 dm910x_chk_mode;		/* Operating mode check */
24762306a36Sopenharmony_ci	u8 first_in_callback;		/* Flag to record state */
24862306a36Sopenharmony_ci	u8 wol_mode;			/* user WOL settings */
24962306a36Sopenharmony_ci	struct timer_list timer;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	/* Driver defined statistic counter */
25262306a36Sopenharmony_ci	unsigned long tx_fifo_underrun;
25362306a36Sopenharmony_ci	unsigned long tx_loss_carrier;
25462306a36Sopenharmony_ci	unsigned long tx_no_carrier;
25562306a36Sopenharmony_ci	unsigned long tx_late_collision;
25662306a36Sopenharmony_ci	unsigned long tx_excessive_collision;
25762306a36Sopenharmony_ci	unsigned long tx_jabber_timeout;
25862306a36Sopenharmony_ci	unsigned long reset_count;
25962306a36Sopenharmony_ci	unsigned long reset_cr8;
26062306a36Sopenharmony_ci	unsigned long reset_fatal;
26162306a36Sopenharmony_ci	unsigned long reset_TXtimeout;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	/* NIC SROM data */
26462306a36Sopenharmony_ci	unsigned char srom[128];
26562306a36Sopenharmony_ci};
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_cienum dmfe_offsets {
26862306a36Sopenharmony_ci	DCR0 = 0x00, DCR1 = 0x08, DCR2 = 0x10, DCR3 = 0x18, DCR4 = 0x20,
26962306a36Sopenharmony_ci	DCR5 = 0x28, DCR6 = 0x30, DCR7 = 0x38, DCR8 = 0x40, DCR9 = 0x48,
27062306a36Sopenharmony_ci	DCR10 = 0x50, DCR11 = 0x58, DCR12 = 0x60, DCR13 = 0x68, DCR14 = 0x70,
27162306a36Sopenharmony_ci	DCR15 = 0x78
27262306a36Sopenharmony_ci};
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cienum dmfe_CR6_bits {
27562306a36Sopenharmony_ci	CR6_RXSC = 0x2, CR6_PBF = 0x8, CR6_PM = 0x40, CR6_PAM = 0x80,
27662306a36Sopenharmony_ci	CR6_FDM = 0x200, CR6_TXSC = 0x2000, CR6_STI = 0x100000,
27762306a36Sopenharmony_ci	CR6_SFT = 0x200000, CR6_RXA = 0x40000000, CR6_NO_PURGE = 0x20000000
27862306a36Sopenharmony_ci};
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci/* Global variable declaration ----------------------------- */
28162306a36Sopenharmony_cistatic int dmfe_debug;
28262306a36Sopenharmony_cistatic unsigned char dmfe_media_mode = DMFE_AUTO;
28362306a36Sopenharmony_cistatic u32 dmfe_cr6_user_set;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci/* For module input parameter */
28662306a36Sopenharmony_cistatic int debug;
28762306a36Sopenharmony_cistatic u32 cr6set;
28862306a36Sopenharmony_cistatic unsigned char mode = 8;
28962306a36Sopenharmony_cistatic u8 chkmode = 1;
29062306a36Sopenharmony_cistatic u8 HPNA_mode;		/* Default: Low Power/High Speed */
29162306a36Sopenharmony_cistatic u8 HPNA_rx_cmd;		/* Default: Disable Rx remote command */
29262306a36Sopenharmony_cistatic u8 HPNA_tx_cmd;		/* Default: Don't issue remote command */
29362306a36Sopenharmony_cistatic u8 HPNA_NoiseFloor;	/* Default: HPNA NoiseFloor */
29462306a36Sopenharmony_cistatic u8 SF_mode;		/* Special Function: 1:VLAN, 2:RX Flow Control
29562306a36Sopenharmony_ci				   4: TX pause packet */
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci/* function declaration ------------------------------------- */
29962306a36Sopenharmony_cistatic int dmfe_open(struct net_device *);
30062306a36Sopenharmony_cistatic netdev_tx_t dmfe_start_xmit(struct sk_buff *, struct net_device *);
30162306a36Sopenharmony_cistatic int dmfe_stop(struct net_device *);
30262306a36Sopenharmony_cistatic void dmfe_set_filter_mode(struct net_device *);
30362306a36Sopenharmony_cistatic const struct ethtool_ops netdev_ethtool_ops;
30462306a36Sopenharmony_cistatic u16 read_srom_word(void __iomem *, int);
30562306a36Sopenharmony_cistatic irqreturn_t dmfe_interrupt(int , void *);
30662306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
30762306a36Sopenharmony_cistatic void poll_dmfe (struct net_device *dev);
30862306a36Sopenharmony_ci#endif
30962306a36Sopenharmony_cistatic void dmfe_descriptor_init(struct net_device *);
31062306a36Sopenharmony_cistatic void allocate_rx_buffer(struct net_device *);
31162306a36Sopenharmony_cistatic void update_cr6(u32, void __iomem *);
31262306a36Sopenharmony_cistatic void send_filter_frame(struct net_device *);
31362306a36Sopenharmony_cistatic void dm9132_id_table(struct net_device *);
31462306a36Sopenharmony_cistatic u16 dmfe_phy_read(void __iomem *, u8, u8, u32);
31562306a36Sopenharmony_cistatic void dmfe_phy_write(void __iomem *, u8, u8, u16, u32);
31662306a36Sopenharmony_cistatic void dmfe_phy_write_1bit(void __iomem *, u32);
31762306a36Sopenharmony_cistatic u16 dmfe_phy_read_1bit(void __iomem *);
31862306a36Sopenharmony_cistatic u8 dmfe_sense_speed(struct dmfe_board_info *);
31962306a36Sopenharmony_cistatic void dmfe_process_mode(struct dmfe_board_info *);
32062306a36Sopenharmony_cistatic void dmfe_timer(struct timer_list *);
32162306a36Sopenharmony_cistatic inline u32 cal_CRC(unsigned char *, unsigned int, u8);
32262306a36Sopenharmony_cistatic void dmfe_rx_packet(struct net_device *, struct dmfe_board_info *);
32362306a36Sopenharmony_cistatic void dmfe_free_tx_pkt(struct net_device *, struct dmfe_board_info *);
32462306a36Sopenharmony_cistatic void dmfe_reuse_skb(struct dmfe_board_info *, struct sk_buff *);
32562306a36Sopenharmony_cistatic void dmfe_dynamic_reset(struct net_device *);
32662306a36Sopenharmony_cistatic void dmfe_free_rxbuffer(struct dmfe_board_info *);
32762306a36Sopenharmony_cistatic void dmfe_init_dm910x(struct net_device *);
32862306a36Sopenharmony_cistatic void dmfe_parse_srom(struct dmfe_board_info *);
32962306a36Sopenharmony_cistatic void dmfe_program_DM9801(struct dmfe_board_info *, int);
33062306a36Sopenharmony_cistatic void dmfe_program_DM9802(struct dmfe_board_info *);
33162306a36Sopenharmony_cistatic void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * );
33262306a36Sopenharmony_cistatic void dmfe_set_phyxcer(struct dmfe_board_info *);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci/* DM910X network board routine ---------------------------- */
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic const struct net_device_ops netdev_ops = {
33762306a36Sopenharmony_ci	.ndo_open 		= dmfe_open,
33862306a36Sopenharmony_ci	.ndo_stop		= dmfe_stop,
33962306a36Sopenharmony_ci	.ndo_start_xmit		= dmfe_start_xmit,
34062306a36Sopenharmony_ci	.ndo_set_rx_mode	= dmfe_set_filter_mode,
34162306a36Sopenharmony_ci	.ndo_set_mac_address	= eth_mac_addr,
34262306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
34362306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
34462306a36Sopenharmony_ci	.ndo_poll_controller	= poll_dmfe,
34562306a36Sopenharmony_ci#endif
34662306a36Sopenharmony_ci};
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci/*
34962306a36Sopenharmony_ci *	Search DM910X board ,allocate space and register it
35062306a36Sopenharmony_ci */
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic int dmfe_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	struct dmfe_board_info *db;	/* board information structure */
35562306a36Sopenharmony_ci	struct net_device *dev;
35662306a36Sopenharmony_ci	u32 pci_pmr;
35762306a36Sopenharmony_ci	int i, err;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	DMFE_DBUG(0, "dmfe_init_one()", 0);
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	/*
36262306a36Sopenharmony_ci	 *	SPARC on-board DM910x chips should be handled by the main
36362306a36Sopenharmony_ci	 *	tulip driver, except for early DM9100s.
36462306a36Sopenharmony_ci	 */
36562306a36Sopenharmony_ci#ifdef CONFIG_TULIP_DM910X
36662306a36Sopenharmony_ci	if ((ent->driver_data == PCI_DM9100_ID && pdev->revision >= 0x30) ||
36762306a36Sopenharmony_ci	    ent->driver_data == PCI_DM9102_ID) {
36862306a36Sopenharmony_ci		struct device_node *dp = pci_device_to_OF_node(pdev);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci		if (dp && of_get_property(dp, "local-mac-address", NULL)) {
37162306a36Sopenharmony_ci			pr_info("skipping on-board DM910x (use tulip)\n");
37262306a36Sopenharmony_ci			return -ENODEV;
37362306a36Sopenharmony_ci		}
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci#endif
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	/* Init network device */
37862306a36Sopenharmony_ci	dev = alloc_etherdev(sizeof(*db));
37962306a36Sopenharmony_ci	if (dev == NULL)
38062306a36Sopenharmony_ci		return -ENOMEM;
38162306a36Sopenharmony_ci	SET_NETDEV_DEV(dev, &pdev->dev);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
38462306a36Sopenharmony_ci		pr_warn("32-bit PCI DMA not available\n");
38562306a36Sopenharmony_ci		err = -ENODEV;
38662306a36Sopenharmony_ci		goto err_out_free;
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	/* Enable Master/IO access, Disable memory access */
39062306a36Sopenharmony_ci	err = pci_enable_device(pdev);
39162306a36Sopenharmony_ci	if (err)
39262306a36Sopenharmony_ci		goto err_out_free;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	if (!pci_resource_start(pdev, 0)) {
39562306a36Sopenharmony_ci		pr_err("I/O base is zero\n");
39662306a36Sopenharmony_ci		err = -ENODEV;
39762306a36Sopenharmony_ci		goto err_out_disable;
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	if (pci_resource_len(pdev, 0) < (CHK_IO_SIZE(pdev)) ) {
40162306a36Sopenharmony_ci		pr_err("Allocated I/O size too small\n");
40262306a36Sopenharmony_ci		err = -ENODEV;
40362306a36Sopenharmony_ci		goto err_out_disable;
40462306a36Sopenharmony_ci	}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci#if 0	/* pci_{enable_device,set_master} sets minimum latency for us now */
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	/* Set Latency Timer 80h */
40962306a36Sopenharmony_ci	/* FIXME: setting values > 32 breaks some SiS 559x stuff.
41062306a36Sopenharmony_ci	   Need a PCI quirk.. */
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);
41362306a36Sopenharmony_ci#endif
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	if (pci_request_regions(pdev, DRV_NAME)) {
41662306a36Sopenharmony_ci		pr_err("Failed to request PCI regions\n");
41762306a36Sopenharmony_ci		err = -ENODEV;
41862306a36Sopenharmony_ci		goto err_out_disable;
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	/* Init system & device */
42262306a36Sopenharmony_ci	db = netdev_priv(dev);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	/* Allocate Tx/Rx descriptor memory */
42562306a36Sopenharmony_ci	db->desc_pool_ptr = dma_alloc_coherent(&pdev->dev,
42662306a36Sopenharmony_ci					       sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20,
42762306a36Sopenharmony_ci					       &db->desc_pool_dma_ptr, GFP_KERNEL);
42862306a36Sopenharmony_ci	if (!db->desc_pool_ptr) {
42962306a36Sopenharmony_ci		err = -ENOMEM;
43062306a36Sopenharmony_ci		goto err_out_res;
43162306a36Sopenharmony_ci	}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	db->buf_pool_ptr = dma_alloc_coherent(&pdev->dev,
43462306a36Sopenharmony_ci					      TX_BUF_ALLOC * TX_DESC_CNT + 4,
43562306a36Sopenharmony_ci					      &db->buf_pool_dma_ptr, GFP_KERNEL);
43662306a36Sopenharmony_ci	if (!db->buf_pool_ptr) {
43762306a36Sopenharmony_ci		err = -ENOMEM;
43862306a36Sopenharmony_ci		goto err_out_free_desc;
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	db->first_tx_desc = (struct tx_desc *) db->desc_pool_ptr;
44262306a36Sopenharmony_ci	db->first_tx_desc_dma = db->desc_pool_dma_ptr;
44362306a36Sopenharmony_ci	db->buf_pool_start = db->buf_pool_ptr;
44462306a36Sopenharmony_ci	db->buf_pool_dma_start = db->buf_pool_dma_ptr;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	db->chip_id = ent->driver_data;
44762306a36Sopenharmony_ci	/* IO type range. */
44862306a36Sopenharmony_ci	db->ioaddr = pci_iomap(pdev, 0, 0);
44962306a36Sopenharmony_ci	if (!db->ioaddr) {
45062306a36Sopenharmony_ci		err = -ENOMEM;
45162306a36Sopenharmony_ci		goto err_out_free_buf;
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	db->chip_revision = pdev->revision;
45562306a36Sopenharmony_ci	db->wol_mode = 0;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	db->pdev = pdev;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	pci_set_drvdata(pdev, dev);
46062306a36Sopenharmony_ci	dev->netdev_ops = &netdev_ops;
46162306a36Sopenharmony_ci	dev->ethtool_ops = &netdev_ethtool_ops;
46262306a36Sopenharmony_ci	netif_carrier_off(dev);
46362306a36Sopenharmony_ci	spin_lock_init(&db->lock);
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	pci_read_config_dword(pdev, 0x50, &pci_pmr);
46662306a36Sopenharmony_ci	pci_pmr &= 0x70000;
46762306a36Sopenharmony_ci	if ( (pci_pmr == 0x10000) && (db->chip_revision == 0x31) )
46862306a36Sopenharmony_ci		db->chip_type = 1;	/* DM9102A E3 */
46962306a36Sopenharmony_ci	else
47062306a36Sopenharmony_ci		db->chip_type = 0;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	/* read 64 word srom data */
47362306a36Sopenharmony_ci	for (i = 0; i < 64; i++) {
47462306a36Sopenharmony_ci		((__le16 *) db->srom)[i] =
47562306a36Sopenharmony_ci			cpu_to_le16(read_srom_word(db->ioaddr, i));
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	/* Set Node address */
47962306a36Sopenharmony_ci	eth_hw_addr_set(dev, &db->srom[20]);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	err = register_netdev (dev);
48262306a36Sopenharmony_ci	if (err)
48362306a36Sopenharmony_ci		goto err_out_unmap;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	dev_info(&dev->dev, "Davicom DM%04lx at pci%s, %pM, irq %d\n",
48662306a36Sopenharmony_ci		 ent->driver_data >> 16,
48762306a36Sopenharmony_ci		 pci_name(pdev), dev->dev_addr, pdev->irq);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	pci_set_master(pdev);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	return 0;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cierr_out_unmap:
49462306a36Sopenharmony_ci	pci_iounmap(pdev, db->ioaddr);
49562306a36Sopenharmony_cierr_out_free_buf:
49662306a36Sopenharmony_ci	dma_free_coherent(&pdev->dev, TX_BUF_ALLOC * TX_DESC_CNT + 4,
49762306a36Sopenharmony_ci			  db->buf_pool_ptr, db->buf_pool_dma_ptr);
49862306a36Sopenharmony_cierr_out_free_desc:
49962306a36Sopenharmony_ci	dma_free_coherent(&pdev->dev,
50062306a36Sopenharmony_ci			  sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20,
50162306a36Sopenharmony_ci			  db->desc_pool_ptr, db->desc_pool_dma_ptr);
50262306a36Sopenharmony_cierr_out_res:
50362306a36Sopenharmony_ci	pci_release_regions(pdev);
50462306a36Sopenharmony_cierr_out_disable:
50562306a36Sopenharmony_ci	pci_disable_device(pdev);
50662306a36Sopenharmony_cierr_out_free:
50762306a36Sopenharmony_ci	free_netdev(dev);
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	return err;
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_cistatic void dmfe_remove_one(struct pci_dev *pdev)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(pdev);
51662306a36Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	DMFE_DBUG(0, "dmfe_remove_one()", 0);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	if (dev) {
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci		unregister_netdev(dev);
52362306a36Sopenharmony_ci		pci_iounmap(db->pdev, db->ioaddr);
52462306a36Sopenharmony_ci		dma_free_coherent(&db->pdev->dev,
52562306a36Sopenharmony_ci				  sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20,
52662306a36Sopenharmony_ci				  db->desc_pool_ptr, db->desc_pool_dma_ptr);
52762306a36Sopenharmony_ci		dma_free_coherent(&db->pdev->dev,
52862306a36Sopenharmony_ci				  TX_BUF_ALLOC * TX_DESC_CNT + 4,
52962306a36Sopenharmony_ci				  db->buf_pool_ptr, db->buf_pool_dma_ptr);
53062306a36Sopenharmony_ci		pci_release_regions(pdev);
53162306a36Sopenharmony_ci		free_netdev(dev);	/* free board information */
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	DMFE_DBUG(0, "dmfe_remove_one() exit", 0);
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci/*
53962306a36Sopenharmony_ci *	Open the interface.
54062306a36Sopenharmony_ci *	The interface is opened whenever "ifconfig" actives it.
54162306a36Sopenharmony_ci */
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic int dmfe_open(struct net_device *dev)
54462306a36Sopenharmony_ci{
54562306a36Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
54662306a36Sopenharmony_ci	const int irq = db->pdev->irq;
54762306a36Sopenharmony_ci	int ret;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	DMFE_DBUG(0, "dmfe_open", 0);
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	ret = request_irq(irq, dmfe_interrupt, IRQF_SHARED, dev->name, dev);
55262306a36Sopenharmony_ci	if (ret)
55362306a36Sopenharmony_ci		return ret;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	/* system variable init */
55662306a36Sopenharmony_ci	db->cr6_data = CR6_DEFAULT | dmfe_cr6_user_set;
55762306a36Sopenharmony_ci	db->tx_packet_cnt = 0;
55862306a36Sopenharmony_ci	db->tx_queue_cnt = 0;
55962306a36Sopenharmony_ci	db->rx_avail_cnt = 0;
56062306a36Sopenharmony_ci	db->wait_reset = 0;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	db->first_in_callback = 0;
56362306a36Sopenharmony_ci	db->NIC_capability = 0xf;	/* All capability*/
56462306a36Sopenharmony_ci	db->PHY_reg4 = 0x1e0;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	/* CR6 operation mode decision */
56762306a36Sopenharmony_ci	if ( !chkmode || (db->chip_id == PCI_DM9132_ID) ||
56862306a36Sopenharmony_ci		(db->chip_revision >= 0x30) ) {
56962306a36Sopenharmony_ci		db->cr6_data |= DMFE_TXTH_256;
57062306a36Sopenharmony_ci		db->cr0_data = CR0_DEFAULT;
57162306a36Sopenharmony_ci		db->dm910x_chk_mode=4;		/* Enter the normal mode */
57262306a36Sopenharmony_ci	} else {
57362306a36Sopenharmony_ci		db->cr6_data |= CR6_SFT;	/* Store & Forward mode */
57462306a36Sopenharmony_ci		db->cr0_data = 0;
57562306a36Sopenharmony_ci		db->dm910x_chk_mode = 1;	/* Enter the check mode */
57662306a36Sopenharmony_ci	}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	/* Initialize DM910X board */
57962306a36Sopenharmony_ci	dmfe_init_dm910x(dev);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	/* Active System Interface */
58262306a36Sopenharmony_ci	netif_wake_queue(dev);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	/* set and active a timer process */
58562306a36Sopenharmony_ci	timer_setup(&db->timer, dmfe_timer, 0);
58662306a36Sopenharmony_ci	db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
58762306a36Sopenharmony_ci	add_timer(&db->timer);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	return 0;
59062306a36Sopenharmony_ci}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci/*	Initialize DM910X board
59462306a36Sopenharmony_ci *	Reset DM910X board
59562306a36Sopenharmony_ci *	Initialize TX/Rx descriptor chain structure
59662306a36Sopenharmony_ci *	Send the set-up frame
59762306a36Sopenharmony_ci *	Enable Tx/Rx machine
59862306a36Sopenharmony_ci */
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_cistatic void dmfe_init_dm910x(struct net_device *dev)
60162306a36Sopenharmony_ci{
60262306a36Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
60362306a36Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	DMFE_DBUG(0, "dmfe_init_dm910x()", 0);
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	/* Reset DM910x MAC controller */
60862306a36Sopenharmony_ci	dw32(DCR0, DM910X_RESET);	/* RESET MAC */
60962306a36Sopenharmony_ci	udelay(100);
61062306a36Sopenharmony_ci	dw32(DCR0, db->cr0_data);
61162306a36Sopenharmony_ci	udelay(5);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	/* Phy addr : DM910(A)2/DM9132/9801, phy address = 1 */
61462306a36Sopenharmony_ci	db->phy_addr = 1;
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	/* Parser SROM and media mode */
61762306a36Sopenharmony_ci	dmfe_parse_srom(db);
61862306a36Sopenharmony_ci	db->media_mode = dmfe_media_mode;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	/* RESET Phyxcer Chip by GPR port bit 7 */
62162306a36Sopenharmony_ci	dw32(DCR12, 0x180);		/* Let bit 7 output port */
62262306a36Sopenharmony_ci	if (db->chip_id == PCI_DM9009_ID) {
62362306a36Sopenharmony_ci		dw32(DCR12, 0x80);	/* Issue RESET signal */
62462306a36Sopenharmony_ci		mdelay(300);			/* Delay 300 ms */
62562306a36Sopenharmony_ci	}
62662306a36Sopenharmony_ci	dw32(DCR12, 0x0);	/* Clear RESET signal */
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	/* Process Phyxcer Media Mode */
62962306a36Sopenharmony_ci	if ( !(db->media_mode & 0x10) )	/* Force 1M mode */
63062306a36Sopenharmony_ci		dmfe_set_phyxcer(db);
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	/* Media Mode Process */
63362306a36Sopenharmony_ci	if ( !(db->media_mode & DMFE_AUTO) )
63462306a36Sopenharmony_ci		db->op_mode = db->media_mode; 	/* Force Mode */
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	/* Initialize Transmit/Receive descriptor and CR3/4 */
63762306a36Sopenharmony_ci	dmfe_descriptor_init(dev);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	/* Init CR6 to program DM910x operation */
64062306a36Sopenharmony_ci	update_cr6(db->cr6_data, ioaddr);
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	/* Send setup frame */
64362306a36Sopenharmony_ci	if (db->chip_id == PCI_DM9132_ID)
64462306a36Sopenharmony_ci		dm9132_id_table(dev);	/* DM9132 */
64562306a36Sopenharmony_ci	else
64662306a36Sopenharmony_ci		send_filter_frame(dev);	/* DM9102/DM9102A */
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	/* Init CR7, interrupt active bit */
64962306a36Sopenharmony_ci	db->cr7_data = CR7_DEFAULT;
65062306a36Sopenharmony_ci	dw32(DCR7, db->cr7_data);
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	/* Init CR15, Tx jabber and Rx watchdog timer */
65362306a36Sopenharmony_ci	dw32(DCR15, db->cr15_data);
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	/* Enable DM910X Tx/Rx function */
65662306a36Sopenharmony_ci	db->cr6_data |= CR6_RXSC | CR6_TXSC | 0x40000;
65762306a36Sopenharmony_ci	update_cr6(db->cr6_data, ioaddr);
65862306a36Sopenharmony_ci}
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci/*
66262306a36Sopenharmony_ci *	Hardware start transmission.
66362306a36Sopenharmony_ci *	Send a packet to media from the upper layer.
66462306a36Sopenharmony_ci */
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_cistatic netdev_tx_t dmfe_start_xmit(struct sk_buff *skb,
66762306a36Sopenharmony_ci					 struct net_device *dev)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
67062306a36Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
67162306a36Sopenharmony_ci	struct tx_desc *txptr;
67262306a36Sopenharmony_ci	unsigned long flags;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	DMFE_DBUG(0, "dmfe_start_xmit", 0);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	/* Too large packet check */
67762306a36Sopenharmony_ci	if (skb->len > MAX_PACKET_SIZE) {
67862306a36Sopenharmony_ci		pr_err("big packet = %d\n", (u16)skb->len);
67962306a36Sopenharmony_ci		dev_kfree_skb_any(skb);
68062306a36Sopenharmony_ci		return NETDEV_TX_OK;
68162306a36Sopenharmony_ci	}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	/* Resource flag check */
68462306a36Sopenharmony_ci	netif_stop_queue(dev);
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	spin_lock_irqsave(&db->lock, flags);
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	/* No Tx resource check, it never happen nromally */
68962306a36Sopenharmony_ci	if (db->tx_queue_cnt >= TX_FREE_DESC_CNT) {
69062306a36Sopenharmony_ci		spin_unlock_irqrestore(&db->lock, flags);
69162306a36Sopenharmony_ci		pr_err("No Tx resource %ld\n", db->tx_queue_cnt);
69262306a36Sopenharmony_ci		return NETDEV_TX_BUSY;
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	/* Disable NIC interrupt */
69662306a36Sopenharmony_ci	dw32(DCR7, 0);
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	/* transmit this packet */
69962306a36Sopenharmony_ci	txptr = db->tx_insert_ptr;
70062306a36Sopenharmony_ci	skb_copy_from_linear_data(skb, txptr->tx_buf_ptr, skb->len);
70162306a36Sopenharmony_ci	txptr->tdes1 = cpu_to_le32(0xe1000000 | skb->len);
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	/* Point to next transmit free descriptor */
70462306a36Sopenharmony_ci	db->tx_insert_ptr = txptr->next_tx_desc;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	/* Transmit Packet Process */
70762306a36Sopenharmony_ci	if ( (!db->tx_queue_cnt) && (db->tx_packet_cnt < TX_MAX_SEND_CNT) ) {
70862306a36Sopenharmony_ci		txptr->tdes0 = cpu_to_le32(0x80000000);	/* Set owner bit */
70962306a36Sopenharmony_ci		db->tx_packet_cnt++;			/* Ready to send */
71062306a36Sopenharmony_ci		dw32(DCR1, 0x1);			/* Issue Tx polling */
71162306a36Sopenharmony_ci		netif_trans_update(dev);		/* saved time stamp */
71262306a36Sopenharmony_ci	} else {
71362306a36Sopenharmony_ci		db->tx_queue_cnt++;			/* queue TX packet */
71462306a36Sopenharmony_ci		dw32(DCR1, 0x1);			/* Issue Tx polling */
71562306a36Sopenharmony_ci	}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	/* Tx resource check */
71862306a36Sopenharmony_ci	if ( db->tx_queue_cnt < TX_FREE_DESC_CNT )
71962306a36Sopenharmony_ci		netif_wake_queue(dev);
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	/* Restore CR7 to enable interrupt */
72262306a36Sopenharmony_ci	spin_unlock_irqrestore(&db->lock, flags);
72362306a36Sopenharmony_ci	dw32(DCR7, db->cr7_data);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	/* free this SKB */
72662306a36Sopenharmony_ci	dev_consume_skb_any(skb);
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	return NETDEV_TX_OK;
72962306a36Sopenharmony_ci}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci/*
73362306a36Sopenharmony_ci *	Stop the interface.
73462306a36Sopenharmony_ci *	The interface is stopped when it is brought.
73562306a36Sopenharmony_ci */
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_cistatic int dmfe_stop(struct net_device *dev)
73862306a36Sopenharmony_ci{
73962306a36Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
74062306a36Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	DMFE_DBUG(0, "dmfe_stop", 0);
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	/* disable system */
74562306a36Sopenharmony_ci	netif_stop_queue(dev);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	/* deleted timer */
74862306a36Sopenharmony_ci	del_timer_sync(&db->timer);
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	/* Reset & stop DM910X board */
75162306a36Sopenharmony_ci	dw32(DCR0, DM910X_RESET);
75262306a36Sopenharmony_ci	udelay(100);
75362306a36Sopenharmony_ci	dmfe_phy_write(ioaddr, db->phy_addr, 0, 0x8000, db->chip_id);
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	/* free interrupt */
75662306a36Sopenharmony_ci	free_irq(db->pdev->irq, dev);
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	/* free allocated rx buffer */
75962306a36Sopenharmony_ci	dmfe_free_rxbuffer(db);
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci#if 0
76262306a36Sopenharmony_ci	/* show statistic counter */
76362306a36Sopenharmony_ci	printk("FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n",
76462306a36Sopenharmony_ci	       db->tx_fifo_underrun, db->tx_excessive_collision,
76562306a36Sopenharmony_ci	       db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier,
76662306a36Sopenharmony_ci	       db->tx_jabber_timeout, db->reset_count, db->reset_cr8,
76762306a36Sopenharmony_ci	       db->reset_fatal, db->reset_TXtimeout);
76862306a36Sopenharmony_ci#endif
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci	return 0;
77162306a36Sopenharmony_ci}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci/*
77562306a36Sopenharmony_ci *	DM9102 insterrupt handler
77662306a36Sopenharmony_ci *	receive the packet to upper layer, free the transmitted packet
77762306a36Sopenharmony_ci */
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_cistatic irqreturn_t dmfe_interrupt(int irq, void *dev_id)
78062306a36Sopenharmony_ci{
78162306a36Sopenharmony_ci	struct net_device *dev = dev_id;
78262306a36Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
78362306a36Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
78462306a36Sopenharmony_ci	unsigned long flags;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	DMFE_DBUG(0, "dmfe_interrupt()", 0);
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	spin_lock_irqsave(&db->lock, flags);
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	/* Got DM910X status */
79162306a36Sopenharmony_ci	db->cr5_data = dr32(DCR5);
79262306a36Sopenharmony_ci	dw32(DCR5, db->cr5_data);
79362306a36Sopenharmony_ci	if ( !(db->cr5_data & 0xc1) ) {
79462306a36Sopenharmony_ci		spin_unlock_irqrestore(&db->lock, flags);
79562306a36Sopenharmony_ci		return IRQ_HANDLED;
79662306a36Sopenharmony_ci	}
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	/* Disable all interrupt in CR7 to solve the interrupt edge problem */
79962306a36Sopenharmony_ci	dw32(DCR7, 0);
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	/* Check system status */
80262306a36Sopenharmony_ci	if (db->cr5_data & 0x2000) {
80362306a36Sopenharmony_ci		/* system bus error happen */
80462306a36Sopenharmony_ci		DMFE_DBUG(1, "System bus error happen. CR5=", db->cr5_data);
80562306a36Sopenharmony_ci		db->reset_fatal++;
80662306a36Sopenharmony_ci		db->wait_reset = 1;	/* Need to RESET */
80762306a36Sopenharmony_ci		spin_unlock_irqrestore(&db->lock, flags);
80862306a36Sopenharmony_ci		return IRQ_HANDLED;
80962306a36Sopenharmony_ci	}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	 /* Received the coming packet */
81262306a36Sopenharmony_ci	if ( (db->cr5_data & 0x40) && db->rx_avail_cnt )
81362306a36Sopenharmony_ci		dmfe_rx_packet(dev, db);
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	/* reallocate rx descriptor buffer */
81662306a36Sopenharmony_ci	if (db->rx_avail_cnt<RX_DESC_CNT)
81762306a36Sopenharmony_ci		allocate_rx_buffer(dev);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	/* Free the transmitted descriptor */
82062306a36Sopenharmony_ci	if ( db->cr5_data & 0x01)
82162306a36Sopenharmony_ci		dmfe_free_tx_pkt(dev, db);
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	/* Mode Check */
82462306a36Sopenharmony_ci	if (db->dm910x_chk_mode & 0x2) {
82562306a36Sopenharmony_ci		db->dm910x_chk_mode = 0x4;
82662306a36Sopenharmony_ci		db->cr6_data |= 0x100;
82762306a36Sopenharmony_ci		update_cr6(db->cr6_data, ioaddr);
82862306a36Sopenharmony_ci	}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	/* Restore CR7 to enable interrupt mask */
83162306a36Sopenharmony_ci	dw32(DCR7, db->cr7_data);
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	spin_unlock_irqrestore(&db->lock, flags);
83462306a36Sopenharmony_ci	return IRQ_HANDLED;
83562306a36Sopenharmony_ci}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER
83962306a36Sopenharmony_ci/*
84062306a36Sopenharmony_ci * Polling 'interrupt' - used by things like netconsole to send skbs
84162306a36Sopenharmony_ci * without having to re-enable interrupts. It's not called while
84262306a36Sopenharmony_ci * the interrupt routine is executing.
84362306a36Sopenharmony_ci */
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_cistatic void poll_dmfe (struct net_device *dev)
84662306a36Sopenharmony_ci{
84762306a36Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
84862306a36Sopenharmony_ci	const int irq = db->pdev->irq;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	/* disable_irq here is not very nice, but with the lockless
85162306a36Sopenharmony_ci	   interrupt handler we have no other choice. */
85262306a36Sopenharmony_ci	disable_irq(irq);
85362306a36Sopenharmony_ci	dmfe_interrupt (irq, dev);
85462306a36Sopenharmony_ci	enable_irq(irq);
85562306a36Sopenharmony_ci}
85662306a36Sopenharmony_ci#endif
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci/*
85962306a36Sopenharmony_ci *	Free TX resource after TX complete
86062306a36Sopenharmony_ci */
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_cistatic void dmfe_free_tx_pkt(struct net_device *dev, struct dmfe_board_info *db)
86362306a36Sopenharmony_ci{
86462306a36Sopenharmony_ci	struct tx_desc *txptr;
86562306a36Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
86662306a36Sopenharmony_ci	u32 tdes0;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	txptr = db->tx_remove_ptr;
86962306a36Sopenharmony_ci	while(db->tx_packet_cnt) {
87062306a36Sopenharmony_ci		tdes0 = le32_to_cpu(txptr->tdes0);
87162306a36Sopenharmony_ci		if (tdes0 & 0x80000000)
87262306a36Sopenharmony_ci			break;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci		/* A packet sent completed */
87562306a36Sopenharmony_ci		db->tx_packet_cnt--;
87662306a36Sopenharmony_ci		dev->stats.tx_packets++;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci		/* Transmit statistic counter */
87962306a36Sopenharmony_ci		if ( tdes0 != 0x7fffffff ) {
88062306a36Sopenharmony_ci			dev->stats.collisions += (tdes0 >> 3) & 0xf;
88162306a36Sopenharmony_ci			dev->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff;
88262306a36Sopenharmony_ci			if (tdes0 & TDES0_ERR_MASK) {
88362306a36Sopenharmony_ci				dev->stats.tx_errors++;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci				if (tdes0 & 0x0002) {	/* UnderRun */
88662306a36Sopenharmony_ci					db->tx_fifo_underrun++;
88762306a36Sopenharmony_ci					if ( !(db->cr6_data & CR6_SFT) ) {
88862306a36Sopenharmony_ci						db->cr6_data = db->cr6_data | CR6_SFT;
88962306a36Sopenharmony_ci						update_cr6(db->cr6_data, ioaddr);
89062306a36Sopenharmony_ci					}
89162306a36Sopenharmony_ci				}
89262306a36Sopenharmony_ci				if (tdes0 & 0x0100)
89362306a36Sopenharmony_ci					db->tx_excessive_collision++;
89462306a36Sopenharmony_ci				if (tdes0 & 0x0200)
89562306a36Sopenharmony_ci					db->tx_late_collision++;
89662306a36Sopenharmony_ci				if (tdes0 & 0x0400)
89762306a36Sopenharmony_ci					db->tx_no_carrier++;
89862306a36Sopenharmony_ci				if (tdes0 & 0x0800)
89962306a36Sopenharmony_ci					db->tx_loss_carrier++;
90062306a36Sopenharmony_ci				if (tdes0 & 0x4000)
90162306a36Sopenharmony_ci					db->tx_jabber_timeout++;
90262306a36Sopenharmony_ci			}
90362306a36Sopenharmony_ci		}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_ci		txptr = txptr->next_tx_desc;
90662306a36Sopenharmony_ci	}/* End of while */
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	/* Update TX remove pointer to next */
90962306a36Sopenharmony_ci	db->tx_remove_ptr = txptr;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	/* Send the Tx packet in queue */
91262306a36Sopenharmony_ci	if ( (db->tx_packet_cnt < TX_MAX_SEND_CNT) && db->tx_queue_cnt ) {
91362306a36Sopenharmony_ci		txptr->tdes0 = cpu_to_le32(0x80000000);	/* Set owner bit */
91462306a36Sopenharmony_ci		db->tx_packet_cnt++;			/* Ready to send */
91562306a36Sopenharmony_ci		db->tx_queue_cnt--;
91662306a36Sopenharmony_ci		dw32(DCR1, 0x1);			/* Issue Tx polling */
91762306a36Sopenharmony_ci		netif_trans_update(dev);		/* saved time stamp */
91862306a36Sopenharmony_ci	}
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	/* Resource available check */
92162306a36Sopenharmony_ci	if ( db->tx_queue_cnt < TX_WAKE_DESC_CNT )
92262306a36Sopenharmony_ci		netif_wake_queue(dev);	/* Active upper layer, send again */
92362306a36Sopenharmony_ci}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci/*
92762306a36Sopenharmony_ci *	Calculate the CRC valude of the Rx packet
92862306a36Sopenharmony_ci *	flag = 	1 : return the reverse CRC (for the received packet CRC)
92962306a36Sopenharmony_ci *		0 : return the normal CRC (for Hash Table index)
93062306a36Sopenharmony_ci */
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_cistatic inline u32 cal_CRC(unsigned char * Data, unsigned int Len, u8 flag)
93362306a36Sopenharmony_ci{
93462306a36Sopenharmony_ci	u32 crc = crc32(~0, Data, Len);
93562306a36Sopenharmony_ci	if (flag) crc = ~crc;
93662306a36Sopenharmony_ci	return crc;
93762306a36Sopenharmony_ci}
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci/*
94162306a36Sopenharmony_ci *	Receive the come packet and pass to upper layer
94262306a36Sopenharmony_ci */
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_cistatic void dmfe_rx_packet(struct net_device *dev, struct dmfe_board_info *db)
94562306a36Sopenharmony_ci{
94662306a36Sopenharmony_ci	struct rx_desc *rxptr;
94762306a36Sopenharmony_ci	struct sk_buff *skb, *newskb;
94862306a36Sopenharmony_ci	int rxlen;
94962306a36Sopenharmony_ci	u32 rdes0;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	rxptr = db->rx_ready_ptr;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	while(db->rx_avail_cnt) {
95462306a36Sopenharmony_ci		rdes0 = le32_to_cpu(rxptr->rdes0);
95562306a36Sopenharmony_ci		if (rdes0 & 0x80000000)	/* packet owner check */
95662306a36Sopenharmony_ci			break;
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci		db->rx_avail_cnt--;
95962306a36Sopenharmony_ci		db->interval_rx_cnt++;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci		dma_unmap_single(&db->pdev->dev, le32_to_cpu(rxptr->rdes2),
96262306a36Sopenharmony_ci				 RX_ALLOC_SIZE, DMA_FROM_DEVICE);
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci		if ( (rdes0 & 0x300) != 0x300) {
96562306a36Sopenharmony_ci			/* A packet without First/Last flag */
96662306a36Sopenharmony_ci			/* reuse this SKB */
96762306a36Sopenharmony_ci			DMFE_DBUG(0, "Reuse SK buffer, rdes0", rdes0);
96862306a36Sopenharmony_ci			dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
96962306a36Sopenharmony_ci		} else {
97062306a36Sopenharmony_ci			/* A packet with First/Last flag */
97162306a36Sopenharmony_ci			rxlen = ( (rdes0 >> 16) & 0x3fff) - 4;
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci			/* error summary bit check */
97462306a36Sopenharmony_ci			if (rdes0 & 0x8000) {
97562306a36Sopenharmony_ci				/* This is a error packet */
97662306a36Sopenharmony_ci				dev->stats.rx_errors++;
97762306a36Sopenharmony_ci				if (rdes0 & 1)
97862306a36Sopenharmony_ci					dev->stats.rx_fifo_errors++;
97962306a36Sopenharmony_ci				if (rdes0 & 2)
98062306a36Sopenharmony_ci					dev->stats.rx_crc_errors++;
98162306a36Sopenharmony_ci				if (rdes0 & 0x80)
98262306a36Sopenharmony_ci					dev->stats.rx_length_errors++;
98362306a36Sopenharmony_ci			}
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci			if ( !(rdes0 & 0x8000) ||
98662306a36Sopenharmony_ci				((db->cr6_data & CR6_PM) && (rxlen>6)) ) {
98762306a36Sopenharmony_ci				skb = rxptr->rx_skb_ptr;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci				/* Received Packet CRC check need or not */
99062306a36Sopenharmony_ci				if ( (db->dm910x_chk_mode & 1) &&
99162306a36Sopenharmony_ci					(cal_CRC(skb->data, rxlen, 1) !=
99262306a36Sopenharmony_ci					(*(u32 *) (skb->data+rxlen) ))) { /* FIXME (?) */
99362306a36Sopenharmony_ci					/* Found a error received packet */
99462306a36Sopenharmony_ci					dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
99562306a36Sopenharmony_ci					db->dm910x_chk_mode = 3;
99662306a36Sopenharmony_ci				} else {
99762306a36Sopenharmony_ci					/* Good packet, send to upper layer */
99862306a36Sopenharmony_ci					/* Shorst packet used new SKB */
99962306a36Sopenharmony_ci					if ((rxlen < RX_COPY_SIZE) &&
100062306a36Sopenharmony_ci						((newskb = netdev_alloc_skb(dev, rxlen + 2))
100162306a36Sopenharmony_ci						!= NULL)) {
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci						skb = newskb;
100462306a36Sopenharmony_ci						/* size less than COPY_SIZE, allocate a rxlen SKB */
100562306a36Sopenharmony_ci						skb_reserve(skb, 2); /* 16byte align */
100662306a36Sopenharmony_ci						skb_copy_from_linear_data(rxptr->rx_skb_ptr,
100762306a36Sopenharmony_ci							  skb_put(skb, rxlen),
100862306a36Sopenharmony_ci									  rxlen);
100962306a36Sopenharmony_ci						dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
101062306a36Sopenharmony_ci					} else
101162306a36Sopenharmony_ci						skb_put(skb, rxlen);
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci					skb->protocol = eth_type_trans(skb, dev);
101462306a36Sopenharmony_ci					netif_rx(skb);
101562306a36Sopenharmony_ci					dev->stats.rx_packets++;
101662306a36Sopenharmony_ci					dev->stats.rx_bytes += rxlen;
101762306a36Sopenharmony_ci				}
101862306a36Sopenharmony_ci			} else {
101962306a36Sopenharmony_ci				/* Reuse SKB buffer when the packet is error */
102062306a36Sopenharmony_ci				DMFE_DBUG(0, "Reuse SK buffer, rdes0", rdes0);
102162306a36Sopenharmony_ci				dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
102262306a36Sopenharmony_ci			}
102362306a36Sopenharmony_ci		}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci		rxptr = rxptr->next_rx_desc;
102662306a36Sopenharmony_ci	}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	db->rx_ready_ptr = rxptr;
102962306a36Sopenharmony_ci}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci/*
103262306a36Sopenharmony_ci * Set DM910X multicast address
103362306a36Sopenharmony_ci */
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_cistatic void dmfe_set_filter_mode(struct net_device *dev)
103662306a36Sopenharmony_ci{
103762306a36Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
103862306a36Sopenharmony_ci	unsigned long flags;
103962306a36Sopenharmony_ci	int mc_count = netdev_mc_count(dev);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	DMFE_DBUG(0, "dmfe_set_filter_mode()", 0);
104262306a36Sopenharmony_ci	spin_lock_irqsave(&db->lock, flags);
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	if (dev->flags & IFF_PROMISC) {
104562306a36Sopenharmony_ci		DMFE_DBUG(0, "Enable PROM Mode", 0);
104662306a36Sopenharmony_ci		db->cr6_data |= CR6_PM | CR6_PBF;
104762306a36Sopenharmony_ci		update_cr6(db->cr6_data, db->ioaddr);
104862306a36Sopenharmony_ci		spin_unlock_irqrestore(&db->lock, flags);
104962306a36Sopenharmony_ci		return;
105062306a36Sopenharmony_ci	}
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	if (dev->flags & IFF_ALLMULTI || mc_count > DMFE_MAX_MULTICAST) {
105362306a36Sopenharmony_ci		DMFE_DBUG(0, "Pass all multicast address", mc_count);
105462306a36Sopenharmony_ci		db->cr6_data &= ~(CR6_PM | CR6_PBF);
105562306a36Sopenharmony_ci		db->cr6_data |= CR6_PAM;
105662306a36Sopenharmony_ci		spin_unlock_irqrestore(&db->lock, flags);
105762306a36Sopenharmony_ci		return;
105862306a36Sopenharmony_ci	}
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	DMFE_DBUG(0, "Set multicast address", mc_count);
106162306a36Sopenharmony_ci	if (db->chip_id == PCI_DM9132_ID)
106262306a36Sopenharmony_ci		dm9132_id_table(dev);	/* DM9132 */
106362306a36Sopenharmony_ci	else
106462306a36Sopenharmony_ci		send_filter_frame(dev);	/* DM9102/DM9102A */
106562306a36Sopenharmony_ci	spin_unlock_irqrestore(&db->lock, flags);
106662306a36Sopenharmony_ci}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci/*
106962306a36Sopenharmony_ci * 	Ethtool interace
107062306a36Sopenharmony_ci */
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_cistatic void dmfe_ethtool_get_drvinfo(struct net_device *dev,
107362306a36Sopenharmony_ci			       struct ethtool_drvinfo *info)
107462306a36Sopenharmony_ci{
107562306a36Sopenharmony_ci	struct dmfe_board_info *np = netdev_priv(dev);
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	strscpy(info->driver, DRV_NAME, sizeof(info->driver));
107862306a36Sopenharmony_ci	strscpy(info->bus_info, pci_name(np->pdev), sizeof(info->bus_info));
107962306a36Sopenharmony_ci}
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_cistatic int dmfe_ethtool_set_wol(struct net_device *dev,
108262306a36Sopenharmony_ci				struct ethtool_wolinfo *wolinfo)
108362306a36Sopenharmony_ci{
108462306a36Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_ci	if (wolinfo->wolopts & (WAKE_UCAST | WAKE_MCAST | WAKE_BCAST |
108762306a36Sopenharmony_ci		   		WAKE_ARP | WAKE_MAGICSECURE))
108862306a36Sopenharmony_ci		   return -EOPNOTSUPP;
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	db->wol_mode = wolinfo->wolopts;
109162306a36Sopenharmony_ci	return 0;
109262306a36Sopenharmony_ci}
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_cistatic void dmfe_ethtool_get_wol(struct net_device *dev,
109562306a36Sopenharmony_ci				 struct ethtool_wolinfo *wolinfo)
109662306a36Sopenharmony_ci{
109762306a36Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_ci	wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
110062306a36Sopenharmony_ci	wolinfo->wolopts = db->wol_mode;
110162306a36Sopenharmony_ci}
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_cistatic const struct ethtool_ops netdev_ethtool_ops = {
110562306a36Sopenharmony_ci	.get_drvinfo		= dmfe_ethtool_get_drvinfo,
110662306a36Sopenharmony_ci	.get_link               = ethtool_op_get_link,
110762306a36Sopenharmony_ci	.set_wol		= dmfe_ethtool_set_wol,
110862306a36Sopenharmony_ci	.get_wol		= dmfe_ethtool_get_wol,
110962306a36Sopenharmony_ci};
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_ci/*
111262306a36Sopenharmony_ci *	A periodic timer routine
111362306a36Sopenharmony_ci *	Dynamic media sense, allocate Rx buffer...
111462306a36Sopenharmony_ci */
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_cistatic void dmfe_timer(struct timer_list *t)
111762306a36Sopenharmony_ci{
111862306a36Sopenharmony_ci	struct dmfe_board_info *db = from_timer(db, t, timer);
111962306a36Sopenharmony_ci	struct net_device *dev = pci_get_drvdata(db->pdev);
112062306a36Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
112162306a36Sopenharmony_ci	u32 tmp_cr8;
112262306a36Sopenharmony_ci	unsigned char tmp_cr12;
112362306a36Sopenharmony_ci	unsigned long flags;
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	int link_ok, link_ok_phy;
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	DMFE_DBUG(0, "dmfe_timer()", 0);
112862306a36Sopenharmony_ci	spin_lock_irqsave(&db->lock, flags);
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	/* Media mode process when Link OK before enter this route */
113162306a36Sopenharmony_ci	if (db->first_in_callback == 0) {
113262306a36Sopenharmony_ci		db->first_in_callback = 1;
113362306a36Sopenharmony_ci		if (db->chip_type && (db->chip_id==PCI_DM9102_ID)) {
113462306a36Sopenharmony_ci			db->cr6_data &= ~0x40000;
113562306a36Sopenharmony_ci			update_cr6(db->cr6_data, ioaddr);
113662306a36Sopenharmony_ci			dmfe_phy_write(ioaddr, db->phy_addr, 0, 0x1000, db->chip_id);
113762306a36Sopenharmony_ci			db->cr6_data |= 0x40000;
113862306a36Sopenharmony_ci			update_cr6(db->cr6_data, ioaddr);
113962306a36Sopenharmony_ci			db->timer.expires = DMFE_TIMER_WUT + HZ * 2;
114062306a36Sopenharmony_ci			add_timer(&db->timer);
114162306a36Sopenharmony_ci			spin_unlock_irqrestore(&db->lock, flags);
114262306a36Sopenharmony_ci			return;
114362306a36Sopenharmony_ci		}
114462306a36Sopenharmony_ci	}
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	/* Operating Mode Check */
114862306a36Sopenharmony_ci	if ( (db->dm910x_chk_mode & 0x1) &&
114962306a36Sopenharmony_ci		(dev->stats.rx_packets > MAX_CHECK_PACKET) )
115062306a36Sopenharmony_ci		db->dm910x_chk_mode = 0x4;
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_ci	/* Dynamic reset DM910X : system error or transmit time-out */
115362306a36Sopenharmony_ci	tmp_cr8 = dr32(DCR8);
115462306a36Sopenharmony_ci	if ( (db->interval_rx_cnt==0) && (tmp_cr8) ) {
115562306a36Sopenharmony_ci		db->reset_cr8++;
115662306a36Sopenharmony_ci		db->wait_reset = 1;
115762306a36Sopenharmony_ci	}
115862306a36Sopenharmony_ci	db->interval_rx_cnt = 0;
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	/* TX polling kick monitor */
116162306a36Sopenharmony_ci	if ( db->tx_packet_cnt &&
116262306a36Sopenharmony_ci	     time_after(jiffies, dev_trans_start(dev) + DMFE_TX_KICK) ) {
116362306a36Sopenharmony_ci		dw32(DCR1, 0x1);   /* Tx polling again */
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci		/* TX Timeout */
116662306a36Sopenharmony_ci		if (time_after(jiffies, dev_trans_start(dev) + DMFE_TX_TIMEOUT) ) {
116762306a36Sopenharmony_ci			db->reset_TXtimeout++;
116862306a36Sopenharmony_ci			db->wait_reset = 1;
116962306a36Sopenharmony_ci			dev_warn(&dev->dev, "Tx timeout - resetting\n");
117062306a36Sopenharmony_ci		}
117162306a36Sopenharmony_ci	}
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	if (db->wait_reset) {
117462306a36Sopenharmony_ci		DMFE_DBUG(0, "Dynamic Reset device", db->tx_packet_cnt);
117562306a36Sopenharmony_ci		db->reset_count++;
117662306a36Sopenharmony_ci		dmfe_dynamic_reset(dev);
117762306a36Sopenharmony_ci		db->first_in_callback = 0;
117862306a36Sopenharmony_ci		db->timer.expires = DMFE_TIMER_WUT;
117962306a36Sopenharmony_ci		add_timer(&db->timer);
118062306a36Sopenharmony_ci		spin_unlock_irqrestore(&db->lock, flags);
118162306a36Sopenharmony_ci		return;
118262306a36Sopenharmony_ci	}
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	/* Link status check, Dynamic media type change */
118562306a36Sopenharmony_ci	if (db->chip_id == PCI_DM9132_ID)
118662306a36Sopenharmony_ci		tmp_cr12 = dr8(DCR9 + 3);	/* DM9132 */
118762306a36Sopenharmony_ci	else
118862306a36Sopenharmony_ci		tmp_cr12 = dr8(DCR12);		/* DM9102/DM9102A */
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	if ( ((db->chip_id == PCI_DM9102_ID) &&
119162306a36Sopenharmony_ci		(db->chip_revision == 0x30)) ||
119262306a36Sopenharmony_ci		((db->chip_id == PCI_DM9132_ID) &&
119362306a36Sopenharmony_ci		(db->chip_revision == 0x10)) ) {
119462306a36Sopenharmony_ci		/* DM9102A Chip */
119562306a36Sopenharmony_ci		if (tmp_cr12 & 2)
119662306a36Sopenharmony_ci			link_ok = 0;
119762306a36Sopenharmony_ci		else
119862306a36Sopenharmony_ci			link_ok = 1;
119962306a36Sopenharmony_ci	}
120062306a36Sopenharmony_ci	else
120162306a36Sopenharmony_ci		/*0x43 is used instead of 0x3 because bit 6 should represent
120262306a36Sopenharmony_ci			link status of external PHY */
120362306a36Sopenharmony_ci		link_ok = (tmp_cr12 & 0x43) ? 1 : 0;
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ci	/* If chip reports that link is failed it could be because external
120762306a36Sopenharmony_ci		PHY link status pin is not connected correctly to chip
120862306a36Sopenharmony_ci		To be sure ask PHY too.
120962306a36Sopenharmony_ci	*/
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	/* need a dummy read because of PHY's register latch*/
121262306a36Sopenharmony_ci	dmfe_phy_read (db->ioaddr, db->phy_addr, 1, db->chip_id);
121362306a36Sopenharmony_ci	link_ok_phy = (dmfe_phy_read (db->ioaddr,
121462306a36Sopenharmony_ci				      db->phy_addr, 1, db->chip_id) & 0x4) ? 1 : 0;
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	if (link_ok_phy != link_ok) {
121762306a36Sopenharmony_ci		DMFE_DBUG (0, "PHY and chip report different link status", 0);
121862306a36Sopenharmony_ci		link_ok = link_ok | link_ok_phy;
121962306a36Sopenharmony_ci	}
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	if ( !link_ok && netif_carrier_ok(dev)) {
122262306a36Sopenharmony_ci		/* Link Failed */
122362306a36Sopenharmony_ci		DMFE_DBUG(0, "Link Failed", tmp_cr12);
122462306a36Sopenharmony_ci		netif_carrier_off(dev);
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci		/* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */
122762306a36Sopenharmony_ci		/* AUTO or force 1M Homerun/Longrun don't need */
122862306a36Sopenharmony_ci		if ( !(db->media_mode & 0x38) )
122962306a36Sopenharmony_ci			dmfe_phy_write(db->ioaddr, db->phy_addr,
123062306a36Sopenharmony_ci				       0, 0x1000, db->chip_id);
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci		/* AUTO mode, if INT phyxcer link failed, select EXT device */
123362306a36Sopenharmony_ci		if (db->media_mode & DMFE_AUTO) {
123462306a36Sopenharmony_ci			/* 10/100M link failed, used 1M Home-Net */
123562306a36Sopenharmony_ci			db->cr6_data|=0x00040000;	/* bit18=1, MII */
123662306a36Sopenharmony_ci			db->cr6_data&=~0x00000200;	/* bit9=0, HD mode */
123762306a36Sopenharmony_ci			update_cr6(db->cr6_data, ioaddr);
123862306a36Sopenharmony_ci		}
123962306a36Sopenharmony_ci	} else if (!netif_carrier_ok(dev)) {
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci		DMFE_DBUG(0, "Link link OK", tmp_cr12);
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci		/* Auto Sense Speed */
124462306a36Sopenharmony_ci		if ( !(db->media_mode & DMFE_AUTO) || !dmfe_sense_speed(db)) {
124562306a36Sopenharmony_ci			netif_carrier_on(dev);
124662306a36Sopenharmony_ci			SHOW_MEDIA_TYPE(db->op_mode);
124762306a36Sopenharmony_ci		}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci		dmfe_process_mode(db);
125062306a36Sopenharmony_ci	}
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	/* HPNA remote command check */
125362306a36Sopenharmony_ci	if (db->HPNA_command & 0xf00) {
125462306a36Sopenharmony_ci		db->HPNA_timer--;
125562306a36Sopenharmony_ci		if (!db->HPNA_timer)
125662306a36Sopenharmony_ci			dmfe_HPNA_remote_cmd_chk(db);
125762306a36Sopenharmony_ci	}
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	/* Timer active again */
126062306a36Sopenharmony_ci	db->timer.expires = DMFE_TIMER_WUT;
126162306a36Sopenharmony_ci	add_timer(&db->timer);
126262306a36Sopenharmony_ci	spin_unlock_irqrestore(&db->lock, flags);
126362306a36Sopenharmony_ci}
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci/*
126762306a36Sopenharmony_ci *	Dynamic reset the DM910X board
126862306a36Sopenharmony_ci *	Stop DM910X board
126962306a36Sopenharmony_ci *	Free Tx/Rx allocated memory
127062306a36Sopenharmony_ci *	Reset DM910X board
127162306a36Sopenharmony_ci *	Re-initialize DM910X board
127262306a36Sopenharmony_ci */
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_cistatic void dmfe_dynamic_reset(struct net_device *dev)
127562306a36Sopenharmony_ci{
127662306a36Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
127762306a36Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	DMFE_DBUG(0, "dmfe_dynamic_reset()", 0);
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	/* Sopt MAC controller */
128262306a36Sopenharmony_ci	db->cr6_data &= ~(CR6_RXSC | CR6_TXSC);	/* Disable Tx/Rx */
128362306a36Sopenharmony_ci	update_cr6(db->cr6_data, ioaddr);
128462306a36Sopenharmony_ci	dw32(DCR7, 0);				/* Disable Interrupt */
128562306a36Sopenharmony_ci	dw32(DCR5, dr32(DCR5));
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	/* Disable upper layer interface */
128862306a36Sopenharmony_ci	netif_stop_queue(dev);
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	/* Free Rx Allocate buffer */
129162306a36Sopenharmony_ci	dmfe_free_rxbuffer(db);
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	/* system variable init */
129462306a36Sopenharmony_ci	db->tx_packet_cnt = 0;
129562306a36Sopenharmony_ci	db->tx_queue_cnt = 0;
129662306a36Sopenharmony_ci	db->rx_avail_cnt = 0;
129762306a36Sopenharmony_ci	netif_carrier_off(dev);
129862306a36Sopenharmony_ci	db->wait_reset = 0;
129962306a36Sopenharmony_ci
130062306a36Sopenharmony_ci	/* Re-initialize DM910X board */
130162306a36Sopenharmony_ci	dmfe_init_dm910x(dev);
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	/* Restart upper layer interface */
130462306a36Sopenharmony_ci	netif_wake_queue(dev);
130562306a36Sopenharmony_ci}
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci/*
130962306a36Sopenharmony_ci *	free all allocated rx buffer
131062306a36Sopenharmony_ci */
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_cistatic void dmfe_free_rxbuffer(struct dmfe_board_info * db)
131362306a36Sopenharmony_ci{
131462306a36Sopenharmony_ci	DMFE_DBUG(0, "dmfe_free_rxbuffer()", 0);
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ci	/* free allocated rx buffer */
131762306a36Sopenharmony_ci	while (db->rx_avail_cnt) {
131862306a36Sopenharmony_ci		dev_kfree_skb(db->rx_ready_ptr->rx_skb_ptr);
131962306a36Sopenharmony_ci		db->rx_ready_ptr = db->rx_ready_ptr->next_rx_desc;
132062306a36Sopenharmony_ci		db->rx_avail_cnt--;
132162306a36Sopenharmony_ci	}
132262306a36Sopenharmony_ci}
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci/*
132662306a36Sopenharmony_ci *	Reuse the SK buffer
132762306a36Sopenharmony_ci */
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_cistatic void dmfe_reuse_skb(struct dmfe_board_info *db, struct sk_buff * skb)
133062306a36Sopenharmony_ci{
133162306a36Sopenharmony_ci	struct rx_desc *rxptr = db->rx_insert_ptr;
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	if (!(rxptr->rdes0 & cpu_to_le32(0x80000000))) {
133462306a36Sopenharmony_ci		rxptr->rx_skb_ptr = skb;
133562306a36Sopenharmony_ci		rxptr->rdes2 = cpu_to_le32(dma_map_single(&db->pdev->dev, skb->data,
133662306a36Sopenharmony_ci							  RX_ALLOC_SIZE, DMA_FROM_DEVICE));
133762306a36Sopenharmony_ci		wmb();
133862306a36Sopenharmony_ci		rxptr->rdes0 = cpu_to_le32(0x80000000);
133962306a36Sopenharmony_ci		db->rx_avail_cnt++;
134062306a36Sopenharmony_ci		db->rx_insert_ptr = rxptr->next_rx_desc;
134162306a36Sopenharmony_ci	} else
134262306a36Sopenharmony_ci		DMFE_DBUG(0, "SK Buffer reuse method error", db->rx_avail_cnt);
134362306a36Sopenharmony_ci}
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci/*
134762306a36Sopenharmony_ci *	Initialize transmit/Receive descriptor
134862306a36Sopenharmony_ci *	Using Chain structure, and allocate Tx/Rx buffer
134962306a36Sopenharmony_ci */
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_cistatic void dmfe_descriptor_init(struct net_device *dev)
135262306a36Sopenharmony_ci{
135362306a36Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
135462306a36Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
135562306a36Sopenharmony_ci	struct tx_desc *tmp_tx;
135662306a36Sopenharmony_ci	struct rx_desc *tmp_rx;
135762306a36Sopenharmony_ci	unsigned char *tmp_buf;
135862306a36Sopenharmony_ci	dma_addr_t tmp_tx_dma, tmp_rx_dma;
135962306a36Sopenharmony_ci	dma_addr_t tmp_buf_dma;
136062306a36Sopenharmony_ci	int i;
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	DMFE_DBUG(0, "dmfe_descriptor_init()", 0);
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	/* tx descriptor start pointer */
136562306a36Sopenharmony_ci	db->tx_insert_ptr = db->first_tx_desc;
136662306a36Sopenharmony_ci	db->tx_remove_ptr = db->first_tx_desc;
136762306a36Sopenharmony_ci	dw32(DCR4, db->first_tx_desc_dma);     /* TX DESC address */
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	/* rx descriptor start pointer */
137062306a36Sopenharmony_ci	db->first_rx_desc = (void *)db->first_tx_desc +
137162306a36Sopenharmony_ci			sizeof(struct tx_desc) * TX_DESC_CNT;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	db->first_rx_desc_dma =  db->first_tx_desc_dma +
137462306a36Sopenharmony_ci			sizeof(struct tx_desc) * TX_DESC_CNT;
137562306a36Sopenharmony_ci	db->rx_insert_ptr = db->first_rx_desc;
137662306a36Sopenharmony_ci	db->rx_ready_ptr = db->first_rx_desc;
137762306a36Sopenharmony_ci	dw32(DCR3, db->first_rx_desc_dma);		/* RX DESC address */
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	/* Init Transmit chain */
138062306a36Sopenharmony_ci	tmp_buf = db->buf_pool_start;
138162306a36Sopenharmony_ci	tmp_buf_dma = db->buf_pool_dma_start;
138262306a36Sopenharmony_ci	tmp_tx_dma = db->first_tx_desc_dma;
138362306a36Sopenharmony_ci	for (tmp_tx = db->first_tx_desc, i = 0; i < TX_DESC_CNT; i++, tmp_tx++) {
138462306a36Sopenharmony_ci		tmp_tx->tx_buf_ptr = tmp_buf;
138562306a36Sopenharmony_ci		tmp_tx->tdes0 = cpu_to_le32(0);
138662306a36Sopenharmony_ci		tmp_tx->tdes1 = cpu_to_le32(0x81000000);	/* IC, chain */
138762306a36Sopenharmony_ci		tmp_tx->tdes2 = cpu_to_le32(tmp_buf_dma);
138862306a36Sopenharmony_ci		tmp_tx_dma += sizeof(struct tx_desc);
138962306a36Sopenharmony_ci		tmp_tx->tdes3 = cpu_to_le32(tmp_tx_dma);
139062306a36Sopenharmony_ci		tmp_tx->next_tx_desc = tmp_tx + 1;
139162306a36Sopenharmony_ci		tmp_buf = tmp_buf + TX_BUF_ALLOC;
139262306a36Sopenharmony_ci		tmp_buf_dma = tmp_buf_dma + TX_BUF_ALLOC;
139362306a36Sopenharmony_ci	}
139462306a36Sopenharmony_ci	(--tmp_tx)->tdes3 = cpu_to_le32(db->first_tx_desc_dma);
139562306a36Sopenharmony_ci	tmp_tx->next_tx_desc = db->first_tx_desc;
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	 /* Init Receive descriptor chain */
139862306a36Sopenharmony_ci	tmp_rx_dma=db->first_rx_desc_dma;
139962306a36Sopenharmony_ci	for (tmp_rx = db->first_rx_desc, i = 0; i < RX_DESC_CNT; i++, tmp_rx++) {
140062306a36Sopenharmony_ci		tmp_rx->rdes0 = cpu_to_le32(0);
140162306a36Sopenharmony_ci		tmp_rx->rdes1 = cpu_to_le32(0x01000600);
140262306a36Sopenharmony_ci		tmp_rx_dma += sizeof(struct rx_desc);
140362306a36Sopenharmony_ci		tmp_rx->rdes3 = cpu_to_le32(tmp_rx_dma);
140462306a36Sopenharmony_ci		tmp_rx->next_rx_desc = tmp_rx + 1;
140562306a36Sopenharmony_ci	}
140662306a36Sopenharmony_ci	(--tmp_rx)->rdes3 = cpu_to_le32(db->first_rx_desc_dma);
140762306a36Sopenharmony_ci	tmp_rx->next_rx_desc = db->first_rx_desc;
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	/* pre-allocate Rx buffer */
141062306a36Sopenharmony_ci	allocate_rx_buffer(dev);
141162306a36Sopenharmony_ci}
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci/*
141562306a36Sopenharmony_ci *	Update CR6 value
141662306a36Sopenharmony_ci *	Firstly stop DM910X , then written value and start
141762306a36Sopenharmony_ci */
141862306a36Sopenharmony_ci
141962306a36Sopenharmony_cistatic void update_cr6(u32 cr6_data, void __iomem *ioaddr)
142062306a36Sopenharmony_ci{
142162306a36Sopenharmony_ci	u32 cr6_tmp;
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	cr6_tmp = cr6_data & ~0x2002;           /* stop Tx/Rx */
142462306a36Sopenharmony_ci	dw32(DCR6, cr6_tmp);
142562306a36Sopenharmony_ci	udelay(5);
142662306a36Sopenharmony_ci	dw32(DCR6, cr6_data);
142762306a36Sopenharmony_ci	udelay(5);
142862306a36Sopenharmony_ci}
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci/*
143262306a36Sopenharmony_ci *	Send a setup frame for DM9132
143362306a36Sopenharmony_ci *	This setup frame initialize DM910X address filter mode
143462306a36Sopenharmony_ci*/
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_cistatic void dm9132_id_table(struct net_device *dev)
143762306a36Sopenharmony_ci{
143862306a36Sopenharmony_ci	const u16 *addrptr = (const u16 *)dev->dev_addr;
143962306a36Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
144062306a36Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr + 0xc0;
144162306a36Sopenharmony_ci	struct netdev_hw_addr *ha;
144262306a36Sopenharmony_ci	u16 i, hash_table[4];
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	/* Node address */
144562306a36Sopenharmony_ci	for (i = 0; i < 3; i++) {
144662306a36Sopenharmony_ci		dw16(0, addrptr[i]);
144762306a36Sopenharmony_ci		ioaddr += 4;
144862306a36Sopenharmony_ci	}
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	/* Clear Hash Table */
145162306a36Sopenharmony_ci	memset(hash_table, 0, sizeof(hash_table));
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	/* broadcast address */
145462306a36Sopenharmony_ci	hash_table[3] = 0x8000;
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	/* the multicast address in Hash Table : 64 bits */
145762306a36Sopenharmony_ci	netdev_for_each_mc_addr(ha, dev) {
145862306a36Sopenharmony_ci		u32 hash_val = cal_CRC((char *)ha->addr, 6, 0) & 0x3f;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci		hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16);
146162306a36Sopenharmony_ci	}
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	/* Write the hash table to MAC MD table */
146462306a36Sopenharmony_ci	for (i = 0; i < 4; i++, ioaddr += 4)
146562306a36Sopenharmony_ci		dw16(0, hash_table[i]);
146662306a36Sopenharmony_ci}
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci/*
147062306a36Sopenharmony_ci *	Send a setup frame for DM9102/DM9102A
147162306a36Sopenharmony_ci *	This setup frame initialize DM910X address filter mode
147262306a36Sopenharmony_ci */
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_cistatic void send_filter_frame(struct net_device *dev)
147562306a36Sopenharmony_ci{
147662306a36Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
147762306a36Sopenharmony_ci	struct netdev_hw_addr *ha;
147862306a36Sopenharmony_ci	struct tx_desc *txptr;
147962306a36Sopenharmony_ci	const u16 * addrptr;
148062306a36Sopenharmony_ci	u32 * suptr;
148162306a36Sopenharmony_ci	int i;
148262306a36Sopenharmony_ci
148362306a36Sopenharmony_ci	DMFE_DBUG(0, "send_filter_frame()", 0);
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	txptr = db->tx_insert_ptr;
148662306a36Sopenharmony_ci	suptr = (u32 *) txptr->tx_buf_ptr;
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	/* Node address */
148962306a36Sopenharmony_ci	addrptr = (const u16 *) dev->dev_addr;
149062306a36Sopenharmony_ci	*suptr++ = addrptr[0];
149162306a36Sopenharmony_ci	*suptr++ = addrptr[1];
149262306a36Sopenharmony_ci	*suptr++ = addrptr[2];
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	/* broadcast address */
149562306a36Sopenharmony_ci	*suptr++ = 0xffff;
149662306a36Sopenharmony_ci	*suptr++ = 0xffff;
149762306a36Sopenharmony_ci	*suptr++ = 0xffff;
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	/* fit the multicast address */
150062306a36Sopenharmony_ci	netdev_for_each_mc_addr(ha, dev) {
150162306a36Sopenharmony_ci		addrptr = (u16 *) ha->addr;
150262306a36Sopenharmony_ci		*suptr++ = addrptr[0];
150362306a36Sopenharmony_ci		*suptr++ = addrptr[1];
150462306a36Sopenharmony_ci		*suptr++ = addrptr[2];
150562306a36Sopenharmony_ci	}
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci	for (i = netdev_mc_count(dev); i < 14; i++) {
150862306a36Sopenharmony_ci		*suptr++ = 0xffff;
150962306a36Sopenharmony_ci		*suptr++ = 0xffff;
151062306a36Sopenharmony_ci		*suptr++ = 0xffff;
151162306a36Sopenharmony_ci	}
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	/* prepare the setup frame */
151462306a36Sopenharmony_ci	db->tx_insert_ptr = txptr->next_tx_desc;
151562306a36Sopenharmony_ci	txptr->tdes1 = cpu_to_le32(0x890000c0);
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	/* Resource Check and Send the setup packet */
151862306a36Sopenharmony_ci	if (!db->tx_packet_cnt) {
151962306a36Sopenharmony_ci		void __iomem *ioaddr = db->ioaddr;
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci		/* Resource Empty */
152262306a36Sopenharmony_ci		db->tx_packet_cnt++;
152362306a36Sopenharmony_ci		txptr->tdes0 = cpu_to_le32(0x80000000);
152462306a36Sopenharmony_ci		update_cr6(db->cr6_data | 0x2000, ioaddr);
152562306a36Sopenharmony_ci		dw32(DCR1, 0x1);	/* Issue Tx polling */
152662306a36Sopenharmony_ci		update_cr6(db->cr6_data, ioaddr);
152762306a36Sopenharmony_ci		netif_trans_update(dev);
152862306a36Sopenharmony_ci	} else
152962306a36Sopenharmony_ci		db->tx_queue_cnt++;	/* Put in TX queue */
153062306a36Sopenharmony_ci}
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci/*
153462306a36Sopenharmony_ci *	Allocate rx buffer,
153562306a36Sopenharmony_ci *	As possible as allocate maxiumn Rx buffer
153662306a36Sopenharmony_ci */
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_cistatic void allocate_rx_buffer(struct net_device *dev)
153962306a36Sopenharmony_ci{
154062306a36Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
154162306a36Sopenharmony_ci	struct rx_desc *rxptr;
154262306a36Sopenharmony_ci	struct sk_buff *skb;
154362306a36Sopenharmony_ci
154462306a36Sopenharmony_ci	rxptr = db->rx_insert_ptr;
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	while(db->rx_avail_cnt < RX_DESC_CNT) {
154762306a36Sopenharmony_ci		if ( ( skb = netdev_alloc_skb(dev, RX_ALLOC_SIZE) ) == NULL )
154862306a36Sopenharmony_ci			break;
154962306a36Sopenharmony_ci		rxptr->rx_skb_ptr = skb; /* FIXME (?) */
155062306a36Sopenharmony_ci		rxptr->rdes2 = cpu_to_le32(dma_map_single(&db->pdev->dev, skb->data,
155162306a36Sopenharmony_ci							  RX_ALLOC_SIZE, DMA_FROM_DEVICE));
155262306a36Sopenharmony_ci		wmb();
155362306a36Sopenharmony_ci		rxptr->rdes0 = cpu_to_le32(0x80000000);
155462306a36Sopenharmony_ci		rxptr = rxptr->next_rx_desc;
155562306a36Sopenharmony_ci		db->rx_avail_cnt++;
155662306a36Sopenharmony_ci	}
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	db->rx_insert_ptr = rxptr;
155962306a36Sopenharmony_ci}
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_cistatic void srom_clk_write(void __iomem *ioaddr, u32 data)
156262306a36Sopenharmony_ci{
156362306a36Sopenharmony_ci	static const u32 cmd[] = {
156462306a36Sopenharmony_ci		CR9_SROM_READ | CR9_SRCS,
156562306a36Sopenharmony_ci		CR9_SROM_READ | CR9_SRCS | CR9_SRCLK,
156662306a36Sopenharmony_ci		CR9_SROM_READ | CR9_SRCS
156762306a36Sopenharmony_ci	};
156862306a36Sopenharmony_ci	int i;
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(cmd); i++) {
157162306a36Sopenharmony_ci		dw32(DCR9, data | cmd[i]);
157262306a36Sopenharmony_ci		udelay(5);
157362306a36Sopenharmony_ci	}
157462306a36Sopenharmony_ci}
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci/*
157762306a36Sopenharmony_ci *	Read one word data from the serial ROM
157862306a36Sopenharmony_ci */
157962306a36Sopenharmony_cistatic u16 read_srom_word(void __iomem *ioaddr, int offset)
158062306a36Sopenharmony_ci{
158162306a36Sopenharmony_ci	u16 srom_data;
158262306a36Sopenharmony_ci	int i;
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_ci	dw32(DCR9, CR9_SROM_READ);
158562306a36Sopenharmony_ci	udelay(5);
158662306a36Sopenharmony_ci	dw32(DCR9, CR9_SROM_READ | CR9_SRCS);
158762306a36Sopenharmony_ci	udelay(5);
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci	/* Send the Read Command 110b */
159062306a36Sopenharmony_ci	srom_clk_write(ioaddr, SROM_DATA_1);
159162306a36Sopenharmony_ci	srom_clk_write(ioaddr, SROM_DATA_1);
159262306a36Sopenharmony_ci	srom_clk_write(ioaddr, SROM_DATA_0);
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	/* Send the offset */
159562306a36Sopenharmony_ci	for (i = 5; i >= 0; i--) {
159662306a36Sopenharmony_ci		srom_data = (offset & (1 << i)) ? SROM_DATA_1 : SROM_DATA_0;
159762306a36Sopenharmony_ci		srom_clk_write(ioaddr, srom_data);
159862306a36Sopenharmony_ci	}
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	dw32(DCR9, CR9_SROM_READ | CR9_SRCS);
160162306a36Sopenharmony_ci	udelay(5);
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	for (i = 16; i > 0; i--) {
160462306a36Sopenharmony_ci		dw32(DCR9, CR9_SROM_READ | CR9_SRCS | CR9_SRCLK);
160562306a36Sopenharmony_ci		udelay(5);
160662306a36Sopenharmony_ci		srom_data = (srom_data << 1) |
160762306a36Sopenharmony_ci				((dr32(DCR9) & CR9_CRDOUT) ? 1 : 0);
160862306a36Sopenharmony_ci		dw32(DCR9, CR9_SROM_READ | CR9_SRCS);
160962306a36Sopenharmony_ci		udelay(5);
161062306a36Sopenharmony_ci	}
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	dw32(DCR9, CR9_SROM_READ);
161362306a36Sopenharmony_ci	udelay(5);
161462306a36Sopenharmony_ci	return srom_data;
161562306a36Sopenharmony_ci}
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci/*
161962306a36Sopenharmony_ci *	Auto sense the media mode
162062306a36Sopenharmony_ci */
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_cistatic u8 dmfe_sense_speed(struct dmfe_board_info *db)
162362306a36Sopenharmony_ci{
162462306a36Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
162562306a36Sopenharmony_ci	u8 ErrFlag = 0;
162662306a36Sopenharmony_ci	u16 phy_mode;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	/* CR6 bit18=0, select 10/100M */
162962306a36Sopenharmony_ci	update_cr6(db->cr6_data & ~0x40000, ioaddr);
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	phy_mode = dmfe_phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
163262306a36Sopenharmony_ci	phy_mode = dmfe_phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id);
163362306a36Sopenharmony_ci
163462306a36Sopenharmony_ci	if ( (phy_mode & 0x24) == 0x24 ) {
163562306a36Sopenharmony_ci		if (db->chip_id == PCI_DM9132_ID)	/* DM9132 */
163662306a36Sopenharmony_ci			phy_mode = dmfe_phy_read(db->ioaddr,
163762306a36Sopenharmony_ci						 db->phy_addr, 7, db->chip_id) & 0xf000;
163862306a36Sopenharmony_ci		else 				/* DM9102/DM9102A */
163962306a36Sopenharmony_ci			phy_mode = dmfe_phy_read(db->ioaddr,
164062306a36Sopenharmony_ci						 db->phy_addr, 17, db->chip_id) & 0xf000;
164162306a36Sopenharmony_ci		switch (phy_mode) {
164262306a36Sopenharmony_ci		case 0x1000: db->op_mode = DMFE_10MHF; break;
164362306a36Sopenharmony_ci		case 0x2000: db->op_mode = DMFE_10MFD; break;
164462306a36Sopenharmony_ci		case 0x4000: db->op_mode = DMFE_100MHF; break;
164562306a36Sopenharmony_ci		case 0x8000: db->op_mode = DMFE_100MFD; break;
164662306a36Sopenharmony_ci		default: db->op_mode = DMFE_10MHF;
164762306a36Sopenharmony_ci			ErrFlag = 1;
164862306a36Sopenharmony_ci			break;
164962306a36Sopenharmony_ci		}
165062306a36Sopenharmony_ci	} else {
165162306a36Sopenharmony_ci		db->op_mode = DMFE_10MHF;
165262306a36Sopenharmony_ci		DMFE_DBUG(0, "Link Failed :", phy_mode);
165362306a36Sopenharmony_ci		ErrFlag = 1;
165462306a36Sopenharmony_ci	}
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	return ErrFlag;
165762306a36Sopenharmony_ci}
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci/*
166162306a36Sopenharmony_ci *	Set 10/100 phyxcer capability
166262306a36Sopenharmony_ci *	AUTO mode : phyxcer register4 is NIC capability
166362306a36Sopenharmony_ci *	Force mode: phyxcer register4 is the force media
166462306a36Sopenharmony_ci */
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_cistatic void dmfe_set_phyxcer(struct dmfe_board_info *db)
166762306a36Sopenharmony_ci{
166862306a36Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
166962306a36Sopenharmony_ci	u16 phy_reg;
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_ci	/* Select 10/100M phyxcer */
167262306a36Sopenharmony_ci	db->cr6_data &= ~0x40000;
167362306a36Sopenharmony_ci	update_cr6(db->cr6_data, ioaddr);
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	/* DM9009 Chip: Phyxcer reg18 bit12=0 */
167662306a36Sopenharmony_ci	if (db->chip_id == PCI_DM9009_ID) {
167762306a36Sopenharmony_ci		phy_reg = dmfe_phy_read(db->ioaddr,
167862306a36Sopenharmony_ci					db->phy_addr, 18, db->chip_id) & ~0x1000;
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci		dmfe_phy_write(db->ioaddr,
168162306a36Sopenharmony_ci			       db->phy_addr, 18, phy_reg, db->chip_id);
168262306a36Sopenharmony_ci	}
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	/* Phyxcer capability setting */
168562306a36Sopenharmony_ci	phy_reg = dmfe_phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0;
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	if (db->media_mode & DMFE_AUTO) {
168862306a36Sopenharmony_ci		/* AUTO Mode */
168962306a36Sopenharmony_ci		phy_reg |= db->PHY_reg4;
169062306a36Sopenharmony_ci	} else {
169162306a36Sopenharmony_ci		/* Force Mode */
169262306a36Sopenharmony_ci		switch(db->media_mode) {
169362306a36Sopenharmony_ci		case DMFE_10MHF: phy_reg |= 0x20; break;
169462306a36Sopenharmony_ci		case DMFE_10MFD: phy_reg |= 0x40; break;
169562306a36Sopenharmony_ci		case DMFE_100MHF: phy_reg |= 0x80; break;
169662306a36Sopenharmony_ci		case DMFE_100MFD: phy_reg |= 0x100; break;
169762306a36Sopenharmony_ci		}
169862306a36Sopenharmony_ci		if (db->chip_id == PCI_DM9009_ID) phy_reg &= 0x61;
169962306a36Sopenharmony_ci	}
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci	/* Write new capability to Phyxcer Reg4 */
170262306a36Sopenharmony_ci	if ( !(phy_reg & 0x01e0)) {
170362306a36Sopenharmony_ci		phy_reg|=db->PHY_reg4;
170462306a36Sopenharmony_ci		db->media_mode|=DMFE_AUTO;
170562306a36Sopenharmony_ci	}
170662306a36Sopenharmony_ci	dmfe_phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id);
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_ci	/* Restart Auto-Negotiation */
170962306a36Sopenharmony_ci	if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )
171062306a36Sopenharmony_ci		dmfe_phy_write(db->ioaddr, db->phy_addr, 0, 0x1800, db->chip_id);
171162306a36Sopenharmony_ci	if ( !db->chip_type )
171262306a36Sopenharmony_ci		dmfe_phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id);
171362306a36Sopenharmony_ci}
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_ci/*
171762306a36Sopenharmony_ci *	Process op-mode
171862306a36Sopenharmony_ci *	AUTO mode : PHY controller in Auto-negotiation Mode
171962306a36Sopenharmony_ci *	Force mode: PHY controller in force mode with HUB
172062306a36Sopenharmony_ci *			N-way force capability with SWITCH
172162306a36Sopenharmony_ci */
172262306a36Sopenharmony_ci
172362306a36Sopenharmony_cistatic void dmfe_process_mode(struct dmfe_board_info *db)
172462306a36Sopenharmony_ci{
172562306a36Sopenharmony_ci	u16 phy_reg;
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	/* Full Duplex Mode Check */
172862306a36Sopenharmony_ci	if (db->op_mode & 0x4)
172962306a36Sopenharmony_ci		db->cr6_data |= CR6_FDM;	/* Set Full Duplex Bit */
173062306a36Sopenharmony_ci	else
173162306a36Sopenharmony_ci		db->cr6_data &= ~CR6_FDM;	/* Clear Full Duplex Bit */
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	/* Transciver Selection */
173462306a36Sopenharmony_ci	if (db->op_mode & 0x10)		/* 1M HomePNA */
173562306a36Sopenharmony_ci		db->cr6_data |= 0x40000;/* External MII select */
173662306a36Sopenharmony_ci	else
173762306a36Sopenharmony_ci		db->cr6_data &= ~0x40000;/* Internal 10/100 transciver */
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	update_cr6(db->cr6_data, db->ioaddr);
174062306a36Sopenharmony_ci
174162306a36Sopenharmony_ci	/* 10/100M phyxcer force mode need */
174262306a36Sopenharmony_ci	if ( !(db->media_mode & 0x18)) {
174362306a36Sopenharmony_ci		/* Forece Mode */
174462306a36Sopenharmony_ci		phy_reg = dmfe_phy_read(db->ioaddr, db->phy_addr, 6, db->chip_id);
174562306a36Sopenharmony_ci		if ( !(phy_reg & 0x1) ) {
174662306a36Sopenharmony_ci			/* parter without N-Way capability */
174762306a36Sopenharmony_ci			phy_reg = 0x0;
174862306a36Sopenharmony_ci			switch(db->op_mode) {
174962306a36Sopenharmony_ci			case DMFE_10MHF: phy_reg = 0x0; break;
175062306a36Sopenharmony_ci			case DMFE_10MFD: phy_reg = 0x100; break;
175162306a36Sopenharmony_ci			case DMFE_100MHF: phy_reg = 0x2000; break;
175262306a36Sopenharmony_ci			case DMFE_100MFD: phy_reg = 0x2100; break;
175362306a36Sopenharmony_ci			}
175462306a36Sopenharmony_ci			dmfe_phy_write(db->ioaddr,
175562306a36Sopenharmony_ci				       db->phy_addr, 0, phy_reg, db->chip_id);
175662306a36Sopenharmony_ci			if ( db->chip_type && (db->chip_id == PCI_DM9102_ID) )
175762306a36Sopenharmony_ci				mdelay(20);
175862306a36Sopenharmony_ci			dmfe_phy_write(db->ioaddr,
175962306a36Sopenharmony_ci				       db->phy_addr, 0, phy_reg, db->chip_id);
176062306a36Sopenharmony_ci		}
176162306a36Sopenharmony_ci	}
176262306a36Sopenharmony_ci}
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci/*
176662306a36Sopenharmony_ci *	Write a word to Phy register
176762306a36Sopenharmony_ci */
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_cistatic void dmfe_phy_write(void __iomem *ioaddr, u8 phy_addr, u8 offset,
177062306a36Sopenharmony_ci			   u16 phy_data, u32 chip_id)
177162306a36Sopenharmony_ci{
177262306a36Sopenharmony_ci	u16 i;
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	if (chip_id == PCI_DM9132_ID) {
177562306a36Sopenharmony_ci		dw16(0x80 + offset * 4, phy_data);
177662306a36Sopenharmony_ci	} else {
177762306a36Sopenharmony_ci		/* DM9102/DM9102A Chip */
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci		/* Send 33 synchronization clock to Phy controller */
178062306a36Sopenharmony_ci		for (i = 0; i < 35; i++)
178162306a36Sopenharmony_ci			dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci		/* Send start command(01) to Phy */
178462306a36Sopenharmony_ci		dmfe_phy_write_1bit(ioaddr, PHY_DATA_0);
178562306a36Sopenharmony_ci		dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_ci		/* Send write command(01) to Phy */
178862306a36Sopenharmony_ci		dmfe_phy_write_1bit(ioaddr, PHY_DATA_0);
178962306a36Sopenharmony_ci		dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci		/* Send Phy address */
179262306a36Sopenharmony_ci		for (i = 0x10; i > 0; i = i >> 1)
179362306a36Sopenharmony_ci			dmfe_phy_write_1bit(ioaddr,
179462306a36Sopenharmony_ci					    phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci		/* Send register address */
179762306a36Sopenharmony_ci		for (i = 0x10; i > 0; i = i >> 1)
179862306a36Sopenharmony_ci			dmfe_phy_write_1bit(ioaddr,
179962306a36Sopenharmony_ci					    offset & i ? PHY_DATA_1 : PHY_DATA_0);
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci		/* written trasnition */
180262306a36Sopenharmony_ci		dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
180362306a36Sopenharmony_ci		dmfe_phy_write_1bit(ioaddr, PHY_DATA_0);
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci		/* Write a word data to PHY controller */
180662306a36Sopenharmony_ci		for ( i = 0x8000; i > 0; i >>= 1)
180762306a36Sopenharmony_ci			dmfe_phy_write_1bit(ioaddr,
180862306a36Sopenharmony_ci					    phy_data & i ? PHY_DATA_1 : PHY_DATA_0);
180962306a36Sopenharmony_ci	}
181062306a36Sopenharmony_ci}
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci/*
181462306a36Sopenharmony_ci *	Read a word data from phy register
181562306a36Sopenharmony_ci */
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_cistatic u16 dmfe_phy_read(void __iomem *ioaddr, u8 phy_addr, u8 offset, u32 chip_id)
181862306a36Sopenharmony_ci{
181962306a36Sopenharmony_ci	int i;
182062306a36Sopenharmony_ci	u16 phy_data;
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_ci	if (chip_id == PCI_DM9132_ID) {
182362306a36Sopenharmony_ci		/* DM9132 Chip */
182462306a36Sopenharmony_ci		phy_data = dr16(0x80 + offset * 4);
182562306a36Sopenharmony_ci	} else {
182662306a36Sopenharmony_ci		/* DM9102/DM9102A Chip */
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci		/* Send 33 synchronization clock to Phy controller */
182962306a36Sopenharmony_ci		for (i = 0; i < 35; i++)
183062306a36Sopenharmony_ci			dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci		/* Send start command(01) to Phy */
183362306a36Sopenharmony_ci		dmfe_phy_write_1bit(ioaddr, PHY_DATA_0);
183462306a36Sopenharmony_ci		dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
183562306a36Sopenharmony_ci
183662306a36Sopenharmony_ci		/* Send read command(10) to Phy */
183762306a36Sopenharmony_ci		dmfe_phy_write_1bit(ioaddr, PHY_DATA_1);
183862306a36Sopenharmony_ci		dmfe_phy_write_1bit(ioaddr, PHY_DATA_0);
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci		/* Send Phy address */
184162306a36Sopenharmony_ci		for (i = 0x10; i > 0; i = i >> 1)
184262306a36Sopenharmony_ci			dmfe_phy_write_1bit(ioaddr,
184362306a36Sopenharmony_ci					    phy_addr & i ? PHY_DATA_1 : PHY_DATA_0);
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci		/* Send register address */
184662306a36Sopenharmony_ci		for (i = 0x10; i > 0; i = i >> 1)
184762306a36Sopenharmony_ci			dmfe_phy_write_1bit(ioaddr,
184862306a36Sopenharmony_ci					    offset & i ? PHY_DATA_1 : PHY_DATA_0);
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci		/* Skip transition state */
185162306a36Sopenharmony_ci		dmfe_phy_read_1bit(ioaddr);
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci		/* read 16bit data */
185462306a36Sopenharmony_ci		for (phy_data = 0, i = 0; i < 16; i++) {
185562306a36Sopenharmony_ci			phy_data <<= 1;
185662306a36Sopenharmony_ci			phy_data |= dmfe_phy_read_1bit(ioaddr);
185762306a36Sopenharmony_ci		}
185862306a36Sopenharmony_ci	}
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci	return phy_data;
186162306a36Sopenharmony_ci}
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci
186462306a36Sopenharmony_ci/*
186562306a36Sopenharmony_ci *	Write one bit data to Phy Controller
186662306a36Sopenharmony_ci */
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_cistatic void dmfe_phy_write_1bit(void __iomem *ioaddr, u32 phy_data)
186962306a36Sopenharmony_ci{
187062306a36Sopenharmony_ci	dw32(DCR9, phy_data);		/* MII Clock Low */
187162306a36Sopenharmony_ci	udelay(1);
187262306a36Sopenharmony_ci	dw32(DCR9, phy_data | MDCLKH);	/* MII Clock High */
187362306a36Sopenharmony_ci	udelay(1);
187462306a36Sopenharmony_ci	dw32(DCR9, phy_data);		/* MII Clock Low */
187562306a36Sopenharmony_ci	udelay(1);
187662306a36Sopenharmony_ci}
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci
187962306a36Sopenharmony_ci/*
188062306a36Sopenharmony_ci *	Read one bit phy data from PHY controller
188162306a36Sopenharmony_ci */
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_cistatic u16 dmfe_phy_read_1bit(void __iomem *ioaddr)
188462306a36Sopenharmony_ci{
188562306a36Sopenharmony_ci	u16 phy_data;
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci	dw32(DCR9, 0x50000);
188862306a36Sopenharmony_ci	udelay(1);
188962306a36Sopenharmony_ci	phy_data = (dr32(DCR9) >> 19) & 0x1;
189062306a36Sopenharmony_ci	dw32(DCR9, 0x40000);
189162306a36Sopenharmony_ci	udelay(1);
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	return phy_data;
189462306a36Sopenharmony_ci}
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci/*
189862306a36Sopenharmony_ci *	Parser SROM and media mode
189962306a36Sopenharmony_ci */
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_cistatic void dmfe_parse_srom(struct dmfe_board_info * db)
190262306a36Sopenharmony_ci{
190362306a36Sopenharmony_ci	char * srom = db->srom;
190462306a36Sopenharmony_ci	int dmfe_mode, tmp_reg;
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci	DMFE_DBUG(0, "dmfe_parse_srom() ", 0);
190762306a36Sopenharmony_ci
190862306a36Sopenharmony_ci	/* Init CR15 */
190962306a36Sopenharmony_ci	db->cr15_data = CR15_DEFAULT;
191062306a36Sopenharmony_ci
191162306a36Sopenharmony_ci	/* Check SROM Version */
191262306a36Sopenharmony_ci	if ( ( (int) srom[18] & 0xff) == SROM_V41_CODE) {
191362306a36Sopenharmony_ci		/* SROM V4.01 */
191462306a36Sopenharmony_ci		/* Get NIC support media mode */
191562306a36Sopenharmony_ci		db->NIC_capability = le16_to_cpup((__le16 *) (srom + 34));
191662306a36Sopenharmony_ci		db->PHY_reg4 = 0;
191762306a36Sopenharmony_ci		for (tmp_reg = 1; tmp_reg < 0x10; tmp_reg <<= 1) {
191862306a36Sopenharmony_ci			switch( db->NIC_capability & tmp_reg ) {
191962306a36Sopenharmony_ci			case 0x1: db->PHY_reg4 |= 0x0020; break;
192062306a36Sopenharmony_ci			case 0x2: db->PHY_reg4 |= 0x0040; break;
192162306a36Sopenharmony_ci			case 0x4: db->PHY_reg4 |= 0x0080; break;
192262306a36Sopenharmony_ci			case 0x8: db->PHY_reg4 |= 0x0100; break;
192362306a36Sopenharmony_ci			}
192462306a36Sopenharmony_ci		}
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci		/* Media Mode Force or not check */
192762306a36Sopenharmony_ci		dmfe_mode = (le32_to_cpup((__le32 *) (srom + 34)) &
192862306a36Sopenharmony_ci			     le32_to_cpup((__le32 *) (srom + 36)));
192962306a36Sopenharmony_ci		switch(dmfe_mode) {
193062306a36Sopenharmony_ci		case 0x4: dmfe_media_mode = DMFE_100MHF; break;	/* 100MHF */
193162306a36Sopenharmony_ci		case 0x2: dmfe_media_mode = DMFE_10MFD; break;	/* 10MFD */
193262306a36Sopenharmony_ci		case 0x8: dmfe_media_mode = DMFE_100MFD; break;	/* 100MFD */
193362306a36Sopenharmony_ci		case 0x100:
193462306a36Sopenharmony_ci		case 0x200: dmfe_media_mode = DMFE_1M_HPNA; break;/* HomePNA */
193562306a36Sopenharmony_ci		}
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci		/* Special Function setting */
193862306a36Sopenharmony_ci		/* VLAN function */
193962306a36Sopenharmony_ci		if ( (SF_mode & 0x1) || (srom[43] & 0x80) )
194062306a36Sopenharmony_ci			db->cr15_data |= 0x40;
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci		/* Flow Control */
194362306a36Sopenharmony_ci		if ( (SF_mode & 0x2) || (srom[40] & 0x1) )
194462306a36Sopenharmony_ci			db->cr15_data |= 0x400;
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci		/* TX pause packet */
194762306a36Sopenharmony_ci		if ( (SF_mode & 0x4) || (srom[40] & 0xe) )
194862306a36Sopenharmony_ci			db->cr15_data |= 0x9800;
194962306a36Sopenharmony_ci	}
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	/* Parse HPNA parameter */
195262306a36Sopenharmony_ci	db->HPNA_command = 1;
195362306a36Sopenharmony_ci
195462306a36Sopenharmony_ci	/* Accept remote command or not */
195562306a36Sopenharmony_ci	if (HPNA_rx_cmd == 0)
195662306a36Sopenharmony_ci		db->HPNA_command |= 0x8000;
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	 /* Issue remote command & operation mode */
195962306a36Sopenharmony_ci	if (HPNA_tx_cmd == 1)
196062306a36Sopenharmony_ci		switch(HPNA_mode) {	/* Issue Remote Command */
196162306a36Sopenharmony_ci		case 0: db->HPNA_command |= 0x0904; break;
196262306a36Sopenharmony_ci		case 1: db->HPNA_command |= 0x0a00; break;
196362306a36Sopenharmony_ci		case 2: db->HPNA_command |= 0x0506; break;
196462306a36Sopenharmony_ci		case 3: db->HPNA_command |= 0x0602; break;
196562306a36Sopenharmony_ci		}
196662306a36Sopenharmony_ci	else
196762306a36Sopenharmony_ci		switch(HPNA_mode) {	/* Don't Issue */
196862306a36Sopenharmony_ci		case 0: db->HPNA_command |= 0x0004; break;
196962306a36Sopenharmony_ci		case 1: db->HPNA_command |= 0x0000; break;
197062306a36Sopenharmony_ci		case 2: db->HPNA_command |= 0x0006; break;
197162306a36Sopenharmony_ci		case 3: db->HPNA_command |= 0x0002; break;
197262306a36Sopenharmony_ci		}
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci	/* Check DM9801 or DM9802 present or not */
197562306a36Sopenharmony_ci	db->HPNA_present = 0;
197662306a36Sopenharmony_ci	update_cr6(db->cr6_data | 0x40000, db->ioaddr);
197762306a36Sopenharmony_ci	tmp_reg = dmfe_phy_read(db->ioaddr, db->phy_addr, 3, db->chip_id);
197862306a36Sopenharmony_ci	if ( ( tmp_reg & 0xfff0 ) == 0xb900 ) {
197962306a36Sopenharmony_ci		/* DM9801 or DM9802 present */
198062306a36Sopenharmony_ci		db->HPNA_timer = 8;
198162306a36Sopenharmony_ci		if ( dmfe_phy_read(db->ioaddr, db->phy_addr, 31, db->chip_id) == 0x4404) {
198262306a36Sopenharmony_ci			/* DM9801 HomeRun */
198362306a36Sopenharmony_ci			db->HPNA_present = 1;
198462306a36Sopenharmony_ci			dmfe_program_DM9801(db, tmp_reg);
198562306a36Sopenharmony_ci		} else {
198662306a36Sopenharmony_ci			/* DM9802 LongRun */
198762306a36Sopenharmony_ci			db->HPNA_present = 2;
198862306a36Sopenharmony_ci			dmfe_program_DM9802(db);
198962306a36Sopenharmony_ci		}
199062306a36Sopenharmony_ci	}
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci}
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci
199562306a36Sopenharmony_ci/*
199662306a36Sopenharmony_ci *	Init HomeRun DM9801
199762306a36Sopenharmony_ci */
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_cistatic void dmfe_program_DM9801(struct dmfe_board_info * db, int HPNA_rev)
200062306a36Sopenharmony_ci{
200162306a36Sopenharmony_ci	uint reg17, reg25;
200262306a36Sopenharmony_ci
200362306a36Sopenharmony_ci	if ( !HPNA_NoiseFloor ) HPNA_NoiseFloor = DM9801_NOISE_FLOOR;
200462306a36Sopenharmony_ci	switch(HPNA_rev) {
200562306a36Sopenharmony_ci	case 0xb900: /* DM9801 E3 */
200662306a36Sopenharmony_ci		db->HPNA_command |= 0x1000;
200762306a36Sopenharmony_ci		reg25 = dmfe_phy_read(db->ioaddr, db->phy_addr, 24, db->chip_id);
200862306a36Sopenharmony_ci		reg25 = ( (reg25 + HPNA_NoiseFloor) & 0xff) | 0xf000;
200962306a36Sopenharmony_ci		reg17 = dmfe_phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
201062306a36Sopenharmony_ci		break;
201162306a36Sopenharmony_ci	case 0xb901: /* DM9801 E4 */
201262306a36Sopenharmony_ci		reg25 = dmfe_phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
201362306a36Sopenharmony_ci		reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor;
201462306a36Sopenharmony_ci		reg17 = dmfe_phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
201562306a36Sopenharmony_ci		reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor + 3;
201662306a36Sopenharmony_ci		break;
201762306a36Sopenharmony_ci	case 0xb902: /* DM9801 E5 */
201862306a36Sopenharmony_ci	case 0xb903: /* DM9801 E6 */
201962306a36Sopenharmony_ci	default:
202062306a36Sopenharmony_ci		db->HPNA_command |= 0x1000;
202162306a36Sopenharmony_ci		reg25 = dmfe_phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
202262306a36Sopenharmony_ci		reg25 = (reg25 & 0xff00) + HPNA_NoiseFloor - 5;
202362306a36Sopenharmony_ci		reg17 = dmfe_phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id);
202462306a36Sopenharmony_ci		reg17 = (reg17 & 0xfff0) + HPNA_NoiseFloor;
202562306a36Sopenharmony_ci		break;
202662306a36Sopenharmony_ci	}
202762306a36Sopenharmony_ci	dmfe_phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
202862306a36Sopenharmony_ci	dmfe_phy_write(db->ioaddr, db->phy_addr, 17, reg17, db->chip_id);
202962306a36Sopenharmony_ci	dmfe_phy_write(db->ioaddr, db->phy_addr, 25, reg25, db->chip_id);
203062306a36Sopenharmony_ci}
203162306a36Sopenharmony_ci
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci/*
203462306a36Sopenharmony_ci *	Init HomeRun DM9802
203562306a36Sopenharmony_ci */
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_cistatic void dmfe_program_DM9802(struct dmfe_board_info * db)
203862306a36Sopenharmony_ci{
203962306a36Sopenharmony_ci	uint phy_reg;
204062306a36Sopenharmony_ci
204162306a36Sopenharmony_ci	if ( !HPNA_NoiseFloor ) HPNA_NoiseFloor = DM9802_NOISE_FLOOR;
204262306a36Sopenharmony_ci	dmfe_phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command, db->chip_id);
204362306a36Sopenharmony_ci	phy_reg = dmfe_phy_read(db->ioaddr, db->phy_addr, 25, db->chip_id);
204462306a36Sopenharmony_ci	phy_reg = ( phy_reg & 0xff00) + HPNA_NoiseFloor;
204562306a36Sopenharmony_ci	dmfe_phy_write(db->ioaddr, db->phy_addr, 25, phy_reg, db->chip_id);
204662306a36Sopenharmony_ci}
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci/*
205062306a36Sopenharmony_ci *	Check remote HPNA power and speed status. If not correct,
205162306a36Sopenharmony_ci *	issue command again.
205262306a36Sopenharmony_ci*/
205362306a36Sopenharmony_ci
205462306a36Sopenharmony_cistatic void dmfe_HPNA_remote_cmd_chk(struct dmfe_board_info * db)
205562306a36Sopenharmony_ci{
205662306a36Sopenharmony_ci	uint phy_reg;
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci	/* Got remote device status */
205962306a36Sopenharmony_ci	phy_reg = dmfe_phy_read(db->ioaddr, db->phy_addr, 17, db->chip_id) & 0x60;
206062306a36Sopenharmony_ci	switch(phy_reg) {
206162306a36Sopenharmony_ci	case 0x00: phy_reg = 0x0a00;break; /* LP/LS */
206262306a36Sopenharmony_ci	case 0x20: phy_reg = 0x0900;break; /* LP/HS */
206362306a36Sopenharmony_ci	case 0x40: phy_reg = 0x0600;break; /* HP/LS */
206462306a36Sopenharmony_ci	case 0x60: phy_reg = 0x0500;break; /* HP/HS */
206562306a36Sopenharmony_ci	}
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci	/* Check remote device status match our setting ot not */
206862306a36Sopenharmony_ci	if ( phy_reg != (db->HPNA_command & 0x0f00) ) {
206962306a36Sopenharmony_ci		dmfe_phy_write(db->ioaddr, db->phy_addr, 16, db->HPNA_command,
207062306a36Sopenharmony_ci			       db->chip_id);
207162306a36Sopenharmony_ci		db->HPNA_timer=8;
207262306a36Sopenharmony_ci	} else
207362306a36Sopenharmony_ci		db->HPNA_timer=600;	/* Match, every 10 minutes, check */
207462306a36Sopenharmony_ci}
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_ci
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_cistatic const struct pci_device_id dmfe_pci_tbl[] = {
207962306a36Sopenharmony_ci	{ 0x1282, 0x9132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9132_ID },
208062306a36Sopenharmony_ci	{ 0x1282, 0x9102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9102_ID },
208162306a36Sopenharmony_ci	{ 0x1282, 0x9100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9100_ID },
208262306a36Sopenharmony_ci	{ 0x1282, 0x9009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_DM9009_ID },
208362306a36Sopenharmony_ci	{ 0, }
208462306a36Sopenharmony_ci};
208562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, dmfe_pci_tbl);
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_cistatic int __maybe_unused dmfe_suspend(struct device *dev_d)
208862306a36Sopenharmony_ci{
208962306a36Sopenharmony_ci	struct net_device *dev = dev_get_drvdata(dev_d);
209062306a36Sopenharmony_ci	struct dmfe_board_info *db = netdev_priv(dev);
209162306a36Sopenharmony_ci	void __iomem *ioaddr = db->ioaddr;
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci	/* Disable upper layer interface */
209462306a36Sopenharmony_ci	netif_device_detach(dev);
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci	/* Disable Tx/Rx */
209762306a36Sopenharmony_ci	db->cr6_data &= ~(CR6_RXSC | CR6_TXSC);
209862306a36Sopenharmony_ci	update_cr6(db->cr6_data, ioaddr);
209962306a36Sopenharmony_ci
210062306a36Sopenharmony_ci	/* Disable Interrupt */
210162306a36Sopenharmony_ci	dw32(DCR7, 0);
210262306a36Sopenharmony_ci	dw32(DCR5, dr32(DCR5));
210362306a36Sopenharmony_ci
210462306a36Sopenharmony_ci	/* Fre RX buffers */
210562306a36Sopenharmony_ci	dmfe_free_rxbuffer(db);
210662306a36Sopenharmony_ci
210762306a36Sopenharmony_ci	/* Enable WOL */
210862306a36Sopenharmony_ci	device_wakeup_enable(dev_d);
210962306a36Sopenharmony_ci
211062306a36Sopenharmony_ci	return 0;
211162306a36Sopenharmony_ci}
211262306a36Sopenharmony_ci
211362306a36Sopenharmony_cistatic int __maybe_unused dmfe_resume(struct device *dev_d)
211462306a36Sopenharmony_ci{
211562306a36Sopenharmony_ci	struct net_device *dev = dev_get_drvdata(dev_d);
211662306a36Sopenharmony_ci
211762306a36Sopenharmony_ci	/* Re-initialize DM910X board */
211862306a36Sopenharmony_ci	dmfe_init_dm910x(dev);
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	/* Disable WOL */
212162306a36Sopenharmony_ci	device_wakeup_disable(dev_d);
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_ci	/* Restart upper layer interface */
212462306a36Sopenharmony_ci	netif_device_attach(dev);
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	return 0;
212762306a36Sopenharmony_ci}
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(dmfe_pm_ops, dmfe_suspend, dmfe_resume);
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_cistatic struct pci_driver dmfe_driver = {
213262306a36Sopenharmony_ci	.name		= "dmfe",
213362306a36Sopenharmony_ci	.id_table	= dmfe_pci_tbl,
213462306a36Sopenharmony_ci	.probe		= dmfe_init_one,
213562306a36Sopenharmony_ci	.remove		= dmfe_remove_one,
213662306a36Sopenharmony_ci	.driver.pm	= &dmfe_pm_ops,
213762306a36Sopenharmony_ci};
213862306a36Sopenharmony_ci
213962306a36Sopenharmony_ciMODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw");
214062306a36Sopenharmony_ciMODULE_DESCRIPTION("Davicom DM910X fast ethernet driver");
214162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
214262306a36Sopenharmony_ci
214362306a36Sopenharmony_cimodule_param(debug, int, 0);
214462306a36Sopenharmony_cimodule_param(mode, byte, 0);
214562306a36Sopenharmony_cimodule_param(cr6set, int, 0);
214662306a36Sopenharmony_cimodule_param(chkmode, byte, 0);
214762306a36Sopenharmony_cimodule_param(HPNA_mode, byte, 0);
214862306a36Sopenharmony_cimodule_param(HPNA_rx_cmd, byte, 0);
214962306a36Sopenharmony_cimodule_param(HPNA_tx_cmd, byte, 0);
215062306a36Sopenharmony_cimodule_param(HPNA_NoiseFloor, byte, 0);
215162306a36Sopenharmony_cimodule_param(SF_mode, byte, 0);
215262306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "Davicom DM9xxx enable debugging (0-1)");
215362306a36Sopenharmony_ciMODULE_PARM_DESC(mode, "Davicom DM9xxx: "
215462306a36Sopenharmony_ci		"Bit 0: 10/100Mbps, bit 2: duplex, bit 8: HomePNA");
215562306a36Sopenharmony_ci
215662306a36Sopenharmony_ciMODULE_PARM_DESC(SF_mode, "Davicom DM9xxx special function "
215762306a36Sopenharmony_ci		"(bit 0: VLAN, bit 1 Flow Control, bit 2: TX pause packet)");
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci/*	Description:
216062306a36Sopenharmony_ci *	when user used insmod to add module, system invoked init_module()
216162306a36Sopenharmony_ci *	to initialize and register.
216262306a36Sopenharmony_ci */
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_cistatic int __init dmfe_init_module(void)
216562306a36Sopenharmony_ci{
216662306a36Sopenharmony_ci	int rc;
216762306a36Sopenharmony_ci
216862306a36Sopenharmony_ci	DMFE_DBUG(0, "init_module() ", debug);
216962306a36Sopenharmony_ci
217062306a36Sopenharmony_ci	if (debug)
217162306a36Sopenharmony_ci		dmfe_debug = debug;	/* set debug flag */
217262306a36Sopenharmony_ci	if (cr6set)
217362306a36Sopenharmony_ci		dmfe_cr6_user_set = cr6set;
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci	switch (mode) {
217662306a36Sopenharmony_ci	case DMFE_10MHF:
217762306a36Sopenharmony_ci	case DMFE_100MHF:
217862306a36Sopenharmony_ci	case DMFE_10MFD:
217962306a36Sopenharmony_ci	case DMFE_100MFD:
218062306a36Sopenharmony_ci	case DMFE_1M_HPNA:
218162306a36Sopenharmony_ci		dmfe_media_mode = mode;
218262306a36Sopenharmony_ci		break;
218362306a36Sopenharmony_ci	default:
218462306a36Sopenharmony_ci		dmfe_media_mode = DMFE_AUTO;
218562306a36Sopenharmony_ci		break;
218662306a36Sopenharmony_ci	}
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci	if (HPNA_mode > 4)
218962306a36Sopenharmony_ci		HPNA_mode = 0;		/* Default: LP/HS */
219062306a36Sopenharmony_ci	if (HPNA_rx_cmd > 1)
219162306a36Sopenharmony_ci		HPNA_rx_cmd = 0;	/* Default: Ignored remote cmd */
219262306a36Sopenharmony_ci	if (HPNA_tx_cmd > 1)
219362306a36Sopenharmony_ci		HPNA_tx_cmd = 0;	/* Default: Don't issue remote cmd */
219462306a36Sopenharmony_ci	if (HPNA_NoiseFloor > 15)
219562306a36Sopenharmony_ci		HPNA_NoiseFloor = 0;
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci	rc = pci_register_driver(&dmfe_driver);
219862306a36Sopenharmony_ci	if (rc < 0)
219962306a36Sopenharmony_ci		return rc;
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_ci	return 0;
220262306a36Sopenharmony_ci}
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci
220562306a36Sopenharmony_ci/*
220662306a36Sopenharmony_ci *	Description:
220762306a36Sopenharmony_ci *	when user used rmmod to delete module, system invoked clean_module()
220862306a36Sopenharmony_ci *	to un-register all registered services.
220962306a36Sopenharmony_ci */
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_cistatic void __exit dmfe_cleanup_module(void)
221262306a36Sopenharmony_ci{
221362306a36Sopenharmony_ci	DMFE_DBUG(0, "dmfe_cleanup_module() ", debug);
221462306a36Sopenharmony_ci	pci_unregister_driver(&dmfe_driver);
221562306a36Sopenharmony_ci}
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_cimodule_init(dmfe_init_module);
221862306a36Sopenharmony_cimodule_exit(dmfe_cleanup_module);
2219