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