18c2ecf20Sopenharmony_ci/******************************************************************************* 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * Linux ThunderLAN Driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * tlan.c 68c2ecf20Sopenharmony_ci * by James Banks 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * (C) 1997-1998 Caldera, Inc. 98c2ecf20Sopenharmony_ci * (C) 1998 James Banks 108c2ecf20Sopenharmony_ci * (C) 1999-2001 Torben Mathiasen 118c2ecf20Sopenharmony_ci * (C) 2002 Samuel Chessman 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This software may be used and distributed according to the terms 148c2ecf20Sopenharmony_ci * of the GNU General Public License, incorporated herein by reference. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci ** Useful (if not required) reading: 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Texas Instruments, ThunderLAN Programmer's Guide, 198c2ecf20Sopenharmony_ci * TI Literature Number SPWU013A 208c2ecf20Sopenharmony_ci * available in PDF format from www.ti.com 218c2ecf20Sopenharmony_ci * Level One, LXT901 and LXT970 Data Sheets 228c2ecf20Sopenharmony_ci * available in PDF format from www.level1.com 238c2ecf20Sopenharmony_ci * National Semiconductor, DP83840A Data Sheet 248c2ecf20Sopenharmony_ci * available in PDF format from www.national.com 258c2ecf20Sopenharmony_ci * Microchip Technology, 24C01A/02A/04A Data Sheet 268c2ecf20Sopenharmony_ci * available in PDF format from www.microchip.com 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci ******************************************************************************/ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include <linux/hardirq.h> 338c2ecf20Sopenharmony_ci#include <linux/module.h> 348c2ecf20Sopenharmony_ci#include <linux/init.h> 358c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 368c2ecf20Sopenharmony_ci#include <linux/ioport.h> 378c2ecf20Sopenharmony_ci#include <linux/eisa.h> 388c2ecf20Sopenharmony_ci#include <linux/pci.h> 398c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 408c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 418c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 428c2ecf20Sopenharmony_ci#include <linux/delay.h> 438c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 448c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 458c2ecf20Sopenharmony_ci#include <linux/mii.h> 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#include "tlan.h" 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* For removing EISA devices */ 518c2ecf20Sopenharmony_cistatic struct net_device *tlan_eisa_devices; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic int tlan_devices_installed; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* Set speed, duplex and aui settings */ 568c2ecf20Sopenharmony_cistatic int aui[MAX_TLAN_BOARDS]; 578c2ecf20Sopenharmony_cistatic int duplex[MAX_TLAN_BOARDS]; 588c2ecf20Sopenharmony_cistatic int speed[MAX_TLAN_BOARDS]; 598c2ecf20Sopenharmony_cistatic int boards_found; 608c2ecf20Sopenharmony_cimodule_param_array(aui, int, NULL, 0); 618c2ecf20Sopenharmony_cimodule_param_array(duplex, int, NULL, 0); 628c2ecf20Sopenharmony_cimodule_param_array(speed, int, NULL, 0); 638c2ecf20Sopenharmony_ciMODULE_PARM_DESC(aui, "ThunderLAN use AUI port(s) (0-1)"); 648c2ecf20Sopenharmony_ciMODULE_PARM_DESC(duplex, 658c2ecf20Sopenharmony_ci "ThunderLAN duplex setting(s) (0-default, 1-half, 2-full)"); 668c2ecf20Sopenharmony_ciMODULE_PARM_DESC(speed, "ThunderLAN port speed setting(s) (0,10,100)"); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ciMODULE_AUTHOR("Maintainer: Samuel Chessman <chessman@tux.org>"); 698c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for TI ThunderLAN based ethernet PCI adapters"); 708c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* Turn on debugging. 738c2ecf20Sopenharmony_ci * See Documentation/networking/device_drivers/ethernet/ti/tlan.rst for details 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_cistatic int debug; 768c2ecf20Sopenharmony_cimodule_param(debug, int, 0); 778c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "ThunderLAN debug mask"); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic const char tlan_signature[] = "TLAN"; 808c2ecf20Sopenharmony_cistatic const char tlan_banner[] = "ThunderLAN driver v1.17\n"; 818c2ecf20Sopenharmony_cistatic int tlan_have_pci; 828c2ecf20Sopenharmony_cistatic int tlan_have_eisa; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic const char * const media[] = { 858c2ecf20Sopenharmony_ci "10BaseT-HD", "10BaseT-FD", "100baseTx-HD", 868c2ecf20Sopenharmony_ci "100BaseTx-FD", "100BaseT4", NULL 878c2ecf20Sopenharmony_ci}; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic struct board { 908c2ecf20Sopenharmony_ci const char *device_label; 918c2ecf20Sopenharmony_ci u32 flags; 928c2ecf20Sopenharmony_ci u16 addr_ofs; 938c2ecf20Sopenharmony_ci} board_info[] = { 948c2ecf20Sopenharmony_ci { "Compaq Netelligent 10 T PCI UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, 958c2ecf20Sopenharmony_ci { "Compaq Netelligent 10/100 TX PCI UTP", 968c2ecf20Sopenharmony_ci TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, 978c2ecf20Sopenharmony_ci { "Compaq Integrated NetFlex-3/P", TLAN_ADAPTER_NONE, 0x83 }, 988c2ecf20Sopenharmony_ci { "Compaq NetFlex-3/P", 998c2ecf20Sopenharmony_ci TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 }, 1008c2ecf20Sopenharmony_ci { "Compaq NetFlex-3/P", TLAN_ADAPTER_NONE, 0x83 }, 1018c2ecf20Sopenharmony_ci { "Compaq Netelligent Integrated 10/100 TX UTP", 1028c2ecf20Sopenharmony_ci TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, 1038c2ecf20Sopenharmony_ci { "Compaq Netelligent Dual 10/100 TX PCI UTP", 1048c2ecf20Sopenharmony_ci TLAN_ADAPTER_NONE, 0x83 }, 1058c2ecf20Sopenharmony_ci { "Compaq Netelligent 10/100 TX Embedded UTP", 1068c2ecf20Sopenharmony_ci TLAN_ADAPTER_NONE, 0x83 }, 1078c2ecf20Sopenharmony_ci { "Olicom OC-2183/2185", TLAN_ADAPTER_USE_INTERN_10, 0x83 }, 1088c2ecf20Sopenharmony_ci { "Olicom OC-2325", TLAN_ADAPTER_ACTIVITY_LED | 1098c2ecf20Sopenharmony_ci TLAN_ADAPTER_UNMANAGED_PHY, 0xf8 }, 1108c2ecf20Sopenharmony_ci { "Olicom OC-2326", TLAN_ADAPTER_ACTIVITY_LED | 1118c2ecf20Sopenharmony_ci TLAN_ADAPTER_USE_INTERN_10, 0xf8 }, 1128c2ecf20Sopenharmony_ci { "Compaq Netelligent 10/100 TX UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, 1138c2ecf20Sopenharmony_ci { "Compaq Netelligent 10 T/2 PCI UTP/coax", TLAN_ADAPTER_NONE, 0x83 }, 1148c2ecf20Sopenharmony_ci { "Compaq NetFlex-3/E", 1158c2ecf20Sopenharmony_ci TLAN_ADAPTER_ACTIVITY_LED | /* EISA card */ 1168c2ecf20Sopenharmony_ci TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 }, 1178c2ecf20Sopenharmony_ci { "Compaq NetFlex-3/E", 1188c2ecf20Sopenharmony_ci TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, /* EISA card */ 1198c2ecf20Sopenharmony_ci}; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic const struct pci_device_id tlan_pci_tbl[] = { 1228c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL10, 1238c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, 1248c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL100, 1258c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, 1268c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETFLEX3I, 1278c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, 1288c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_THUNDER, 1298c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 }, 1308c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETFLEX3B, 1318c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, 1328c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL100PI, 1338c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, 1348c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL100D, 1358c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 }, 1368c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_NETEL100I, 1378c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 }, 1388c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_OLICOM, PCI_DEVICE_ID_OLICOM_OC2183, 1398c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, 1408c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_OLICOM, PCI_DEVICE_ID_OLICOM_OC2325, 1418c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 }, 1428c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_OLICOM, PCI_DEVICE_ID_OLICOM_OC2326, 1438c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 }, 1448c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100_WS_5100, 1458c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 }, 1468c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_T2, 1478c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 }, 1488c2ecf20Sopenharmony_ci { 0,} 1498c2ecf20Sopenharmony_ci}; 1508c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, tlan_pci_tbl); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic void tlan_eisa_probe(void); 1538c2ecf20Sopenharmony_cistatic void tlan_eisa_cleanup(void); 1548c2ecf20Sopenharmony_cistatic int tlan_init(struct net_device *); 1558c2ecf20Sopenharmony_cistatic int tlan_open(struct net_device *dev); 1568c2ecf20Sopenharmony_cistatic netdev_tx_t tlan_start_tx(struct sk_buff *, struct net_device *); 1578c2ecf20Sopenharmony_cistatic irqreturn_t tlan_handle_interrupt(int, void *); 1588c2ecf20Sopenharmony_cistatic int tlan_close(struct net_device *); 1598c2ecf20Sopenharmony_cistatic struct net_device_stats *tlan_get_stats(struct net_device *); 1608c2ecf20Sopenharmony_cistatic void tlan_set_multicast_list(struct net_device *); 1618c2ecf20Sopenharmony_cistatic int tlan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); 1628c2ecf20Sopenharmony_cistatic int tlan_probe1(struct pci_dev *pdev, long ioaddr, 1638c2ecf20Sopenharmony_ci int irq, int rev, const struct pci_device_id *ent); 1648c2ecf20Sopenharmony_cistatic void tlan_tx_timeout(struct net_device *dev, unsigned int txqueue); 1658c2ecf20Sopenharmony_cistatic void tlan_tx_timeout_work(struct work_struct *work); 1668c2ecf20Sopenharmony_cistatic int tlan_init_one(struct pci_dev *pdev, 1678c2ecf20Sopenharmony_ci const struct pci_device_id *ent); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic u32 tlan_handle_tx_eof(struct net_device *, u16); 1708c2ecf20Sopenharmony_cistatic u32 tlan_handle_stat_overflow(struct net_device *, u16); 1718c2ecf20Sopenharmony_cistatic u32 tlan_handle_rx_eof(struct net_device *, u16); 1728c2ecf20Sopenharmony_cistatic u32 tlan_handle_dummy(struct net_device *, u16); 1738c2ecf20Sopenharmony_cistatic u32 tlan_handle_tx_eoc(struct net_device *, u16); 1748c2ecf20Sopenharmony_cistatic u32 tlan_handle_status_check(struct net_device *, u16); 1758c2ecf20Sopenharmony_cistatic u32 tlan_handle_rx_eoc(struct net_device *, u16); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic void tlan_timer(struct timer_list *t); 1788c2ecf20Sopenharmony_cistatic void tlan_phy_monitor(struct timer_list *t); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic void tlan_reset_lists(struct net_device *); 1818c2ecf20Sopenharmony_cistatic void tlan_free_lists(struct net_device *); 1828c2ecf20Sopenharmony_cistatic void tlan_print_dio(u16); 1838c2ecf20Sopenharmony_cistatic void tlan_print_list(struct tlan_list *, char *, int); 1848c2ecf20Sopenharmony_cistatic void tlan_read_and_clear_stats(struct net_device *, int); 1858c2ecf20Sopenharmony_cistatic void tlan_reset_adapter(struct net_device *); 1868c2ecf20Sopenharmony_cistatic void tlan_finish_reset(struct net_device *); 1878c2ecf20Sopenharmony_cistatic void tlan_set_mac(struct net_device *, int areg, char *mac); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic void tlan_phy_print(struct net_device *); 1908c2ecf20Sopenharmony_cistatic void tlan_phy_detect(struct net_device *); 1918c2ecf20Sopenharmony_cistatic void tlan_phy_power_down(struct net_device *); 1928c2ecf20Sopenharmony_cistatic void tlan_phy_power_up(struct net_device *); 1938c2ecf20Sopenharmony_cistatic void tlan_phy_reset(struct net_device *); 1948c2ecf20Sopenharmony_cistatic void tlan_phy_start_link(struct net_device *); 1958c2ecf20Sopenharmony_cistatic void tlan_phy_finish_auto_neg(struct net_device *); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci/* 1988c2ecf20Sopenharmony_ci static int tlan_phy_nop(struct net_device *); 1998c2ecf20Sopenharmony_ci static int tlan_phy_internal_check(struct net_device *); 2008c2ecf20Sopenharmony_ci static int tlan_phy_internal_service(struct net_device *); 2018c2ecf20Sopenharmony_ci static int tlan_phy_dp83840a_check(struct net_device *); 2028c2ecf20Sopenharmony_ci*/ 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_cistatic bool tlan_mii_read_reg(struct net_device *, u16, u16, u16 *); 2058c2ecf20Sopenharmony_cistatic void tlan_mii_send_data(u16, u32, unsigned); 2068c2ecf20Sopenharmony_cistatic void tlan_mii_sync(u16); 2078c2ecf20Sopenharmony_cistatic void tlan_mii_write_reg(struct net_device *, u16, u16, u16); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic void tlan_ee_send_start(u16); 2108c2ecf20Sopenharmony_cistatic int tlan_ee_send_byte(u16, u8, int); 2118c2ecf20Sopenharmony_cistatic void tlan_ee_receive_byte(u16, u8 *, int); 2128c2ecf20Sopenharmony_cistatic int tlan_ee_read_byte(struct net_device *, u8, u8 *); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic inline void 2168c2ecf20Sopenharmony_citlan_store_skb(struct tlan_list *tag, struct sk_buff *skb) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci unsigned long addr = (unsigned long)skb; 2198c2ecf20Sopenharmony_ci tag->buffer[9].address = addr; 2208c2ecf20Sopenharmony_ci tag->buffer[8].address = upper_32_bits(addr); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic inline struct sk_buff * 2248c2ecf20Sopenharmony_citlan_get_skb(const struct tlan_list *tag) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci unsigned long addr; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci addr = tag->buffer[9].address; 2298c2ecf20Sopenharmony_ci addr |= ((unsigned long) tag->buffer[8].address << 16) << 16; 2308c2ecf20Sopenharmony_ci return (struct sk_buff *) addr; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic u32 2348c2ecf20Sopenharmony_ci(*tlan_int_vector[TLAN_INT_NUMBER_OF_INTS])(struct net_device *, u16) = { 2358c2ecf20Sopenharmony_ci NULL, 2368c2ecf20Sopenharmony_ci tlan_handle_tx_eof, 2378c2ecf20Sopenharmony_ci tlan_handle_stat_overflow, 2388c2ecf20Sopenharmony_ci tlan_handle_rx_eof, 2398c2ecf20Sopenharmony_ci tlan_handle_dummy, 2408c2ecf20Sopenharmony_ci tlan_handle_tx_eoc, 2418c2ecf20Sopenharmony_ci tlan_handle_status_check, 2428c2ecf20Sopenharmony_ci tlan_handle_rx_eoc 2438c2ecf20Sopenharmony_ci}; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic inline void 2468c2ecf20Sopenharmony_citlan_set_timer(struct net_device *dev, u32 ticks, u32 type) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 2498c2ecf20Sopenharmony_ci unsigned long flags = 0; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (!in_irq()) 2528c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 2538c2ecf20Sopenharmony_ci if (priv->timer.function != NULL && 2548c2ecf20Sopenharmony_ci priv->timer_type != TLAN_TIMER_ACTIVITY) { 2558c2ecf20Sopenharmony_ci if (!in_irq()) 2568c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 2578c2ecf20Sopenharmony_ci return; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci priv->timer.function = tlan_timer; 2608c2ecf20Sopenharmony_ci if (!in_irq()) 2618c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci priv->timer_set_at = jiffies; 2648c2ecf20Sopenharmony_ci priv->timer_type = type; 2658c2ecf20Sopenharmony_ci mod_timer(&priv->timer, jiffies + ticks); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci/***************************************************************************** 2718c2ecf20Sopenharmony_ci****************************************************************************** 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ciThunderLAN driver primary functions 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cithese functions are more or less common to all linux network drivers. 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci****************************************************************************** 2788c2ecf20Sopenharmony_ci*****************************************************************************/ 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci/*************************************************************** 2858c2ecf20Sopenharmony_ci * tlan_remove_one 2868c2ecf20Sopenharmony_ci * 2878c2ecf20Sopenharmony_ci * Returns: 2888c2ecf20Sopenharmony_ci * Nothing 2898c2ecf20Sopenharmony_ci * Parms: 2908c2ecf20Sopenharmony_ci * None 2918c2ecf20Sopenharmony_ci * 2928c2ecf20Sopenharmony_ci * Goes through the TLanDevices list and frees the device 2938c2ecf20Sopenharmony_ci * structs and memory associated with each device (lists 2948c2ecf20Sopenharmony_ci * and buffers). It also ureserves the IO port regions 2958c2ecf20Sopenharmony_ci * associated with this device. 2968c2ecf20Sopenharmony_ci * 2978c2ecf20Sopenharmony_ci **************************************************************/ 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic void tlan_remove_one(struct pci_dev *pdev) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 3038c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci unregister_netdev(dev); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (priv->dma_storage) { 3088c2ecf20Sopenharmony_ci dma_free_coherent(&priv->pci_dev->dev, priv->dma_size, 3098c2ecf20Sopenharmony_ci priv->dma_storage, priv->dma_storage_dma); 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 3138c2ecf20Sopenharmony_ci pci_release_regions(pdev); 3148c2ecf20Sopenharmony_ci#endif 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci cancel_work_sync(&priv->tlan_tqueue); 3178c2ecf20Sopenharmony_ci free_netdev(dev); 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic void tlan_start(struct net_device *dev) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci tlan_reset_lists(dev); 3238c2ecf20Sopenharmony_ci /* NOTE: It might not be necessary to read the stats before a 3248c2ecf20Sopenharmony_ci reset if you don't care what the values are. 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_ci tlan_read_and_clear_stats(dev, TLAN_IGNORE); 3278c2ecf20Sopenharmony_ci tlan_reset_adapter(dev); 3288c2ecf20Sopenharmony_ci netif_wake_queue(dev); 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic void tlan_stop(struct net_device *dev) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci del_timer_sync(&priv->media_timer); 3368c2ecf20Sopenharmony_ci tlan_read_and_clear_stats(dev, TLAN_RECORD); 3378c2ecf20Sopenharmony_ci outl(TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD); 3388c2ecf20Sopenharmony_ci /* Reset and power down phy */ 3398c2ecf20Sopenharmony_ci tlan_reset_adapter(dev); 3408c2ecf20Sopenharmony_ci if (priv->timer.function != NULL) { 3418c2ecf20Sopenharmony_ci del_timer_sync(&priv->timer); 3428c2ecf20Sopenharmony_ci priv->timer.function = NULL; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic int __maybe_unused tlan_suspend(struct device *dev_d) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci struct net_device *dev = dev_get_drvdata(dev_d); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (netif_running(dev)) 3518c2ecf20Sopenharmony_ci tlan_stop(dev); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci netif_device_detach(dev); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci return 0; 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic int __maybe_unused tlan_resume(struct device *dev_d) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct net_device *dev = dev_get_drvdata(dev_d); 3618c2ecf20Sopenharmony_ci netif_device_attach(dev); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (netif_running(dev)) 3648c2ecf20Sopenharmony_ci tlan_start(dev); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci return 0; 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(tlan_pm_ops, tlan_suspend, tlan_resume); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic struct pci_driver tlan_driver = { 3728c2ecf20Sopenharmony_ci .name = "tlan", 3738c2ecf20Sopenharmony_ci .id_table = tlan_pci_tbl, 3748c2ecf20Sopenharmony_ci .probe = tlan_init_one, 3758c2ecf20Sopenharmony_ci .remove = tlan_remove_one, 3768c2ecf20Sopenharmony_ci .driver.pm = &tlan_pm_ops, 3778c2ecf20Sopenharmony_ci}; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic int __init tlan_probe(void) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci int rc = -ENODEV; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci pr_info("%s", tlan_banner); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_PROBE, "Starting PCI Probe....\n"); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci /* Use new style PCI probing. Now the kernel will 3888c2ecf20Sopenharmony_ci do most of this for us */ 3898c2ecf20Sopenharmony_ci rc = pci_register_driver(&tlan_driver); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci if (rc != 0) { 3928c2ecf20Sopenharmony_ci pr_err("Could not register pci driver\n"); 3938c2ecf20Sopenharmony_ci goto err_out_pci_free; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_PROBE, "Starting EISA Probe....\n"); 3978c2ecf20Sopenharmony_ci tlan_eisa_probe(); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci pr_info("%d device%s installed, PCI: %d EISA: %d\n", 4008c2ecf20Sopenharmony_ci tlan_devices_installed, tlan_devices_installed == 1 ? "" : "s", 4018c2ecf20Sopenharmony_ci tlan_have_pci, tlan_have_eisa); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci if (tlan_devices_installed == 0) { 4048c2ecf20Sopenharmony_ci rc = -ENODEV; 4058c2ecf20Sopenharmony_ci goto err_out_pci_unreg; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci return 0; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cierr_out_pci_unreg: 4108c2ecf20Sopenharmony_ci pci_unregister_driver(&tlan_driver); 4118c2ecf20Sopenharmony_cierr_out_pci_free: 4128c2ecf20Sopenharmony_ci return rc; 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic int tlan_init_one(struct pci_dev *pdev, 4178c2ecf20Sopenharmony_ci const struct pci_device_id *ent) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci return tlan_probe1(pdev, -1, -1, 0, ent); 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci/* 4248c2ecf20Sopenharmony_ci*************************************************************** 4258c2ecf20Sopenharmony_ci* tlan_probe1 4268c2ecf20Sopenharmony_ci* 4278c2ecf20Sopenharmony_ci* Returns: 4288c2ecf20Sopenharmony_ci* 0 on success, error code on error 4298c2ecf20Sopenharmony_ci* Parms: 4308c2ecf20Sopenharmony_ci* none 4318c2ecf20Sopenharmony_ci* 4328c2ecf20Sopenharmony_ci* The name is lower case to fit in with all the rest of 4338c2ecf20Sopenharmony_ci* the netcard_probe names. This function looks for 4348c2ecf20Sopenharmony_ci* another TLan based adapter, setting it up with the 4358c2ecf20Sopenharmony_ci* allocated device struct if one is found. 4368c2ecf20Sopenharmony_ci* tlan_probe has been ported to the new net API and 4378c2ecf20Sopenharmony_ci* now allocates its own device structure. This function 4388c2ecf20Sopenharmony_ci* is also used by modules. 4398c2ecf20Sopenharmony_ci* 4408c2ecf20Sopenharmony_ci**************************************************************/ 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_cistatic int tlan_probe1(struct pci_dev *pdev, long ioaddr, int irq, int rev, 4438c2ecf20Sopenharmony_ci const struct pci_device_id *ent) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci struct net_device *dev; 4478c2ecf20Sopenharmony_ci struct tlan_priv *priv; 4488c2ecf20Sopenharmony_ci u16 device_id; 4498c2ecf20Sopenharmony_ci int reg, rc = -ENODEV; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 4528c2ecf20Sopenharmony_ci if (pdev) { 4538c2ecf20Sopenharmony_ci rc = pci_enable_device(pdev); 4548c2ecf20Sopenharmony_ci if (rc) 4558c2ecf20Sopenharmony_ci return rc; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci rc = pci_request_regions(pdev, tlan_signature); 4588c2ecf20Sopenharmony_ci if (rc) { 4598c2ecf20Sopenharmony_ci pr_err("Could not reserve IO regions\n"); 4608c2ecf20Sopenharmony_ci goto err_out; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci } 4638c2ecf20Sopenharmony_ci#endif /* CONFIG_PCI */ 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci dev = alloc_etherdev(sizeof(struct tlan_priv)); 4668c2ecf20Sopenharmony_ci if (dev == NULL) { 4678c2ecf20Sopenharmony_ci rc = -ENOMEM; 4688c2ecf20Sopenharmony_ci goto err_out_regions; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, &pdev->dev); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci priv = netdev_priv(dev); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci priv->pci_dev = pdev; 4758c2ecf20Sopenharmony_ci priv->dev = dev; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci /* Is this a PCI device? */ 4788c2ecf20Sopenharmony_ci if (pdev) { 4798c2ecf20Sopenharmony_ci u32 pci_io_base = 0; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci priv->adapter = &board_info[ent->driver_data]; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); 4848c2ecf20Sopenharmony_ci if (rc) { 4858c2ecf20Sopenharmony_ci pr_err("No suitable PCI mapping available\n"); 4868c2ecf20Sopenharmony_ci goto err_out_free_dev; 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci for (reg = 0; reg <= 5; reg++) { 4908c2ecf20Sopenharmony_ci if (pci_resource_flags(pdev, reg) & IORESOURCE_IO) { 4918c2ecf20Sopenharmony_ci pci_io_base = pci_resource_start(pdev, reg); 4928c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_GNRL, 4938c2ecf20Sopenharmony_ci "IO mapping is available at %x.\n", 4948c2ecf20Sopenharmony_ci pci_io_base); 4958c2ecf20Sopenharmony_ci break; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci if (!pci_io_base) { 4998c2ecf20Sopenharmony_ci pr_err("No IO mappings available\n"); 5008c2ecf20Sopenharmony_ci rc = -EIO; 5018c2ecf20Sopenharmony_ci goto err_out_free_dev; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci dev->base_addr = pci_io_base; 5058c2ecf20Sopenharmony_ci dev->irq = pdev->irq; 5068c2ecf20Sopenharmony_ci priv->adapter_rev = pdev->revision; 5078c2ecf20Sopenharmony_ci pci_set_master(pdev); 5088c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, dev); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci } else { /* EISA card */ 5118c2ecf20Sopenharmony_ci /* This is a hack. We need to know which board structure 5128c2ecf20Sopenharmony_ci * is suited for this adapter */ 5138c2ecf20Sopenharmony_ci device_id = inw(ioaddr + EISA_ID2); 5148c2ecf20Sopenharmony_ci if (device_id == 0x20F1) { 5158c2ecf20Sopenharmony_ci priv->adapter = &board_info[13]; /* NetFlex-3/E */ 5168c2ecf20Sopenharmony_ci priv->adapter_rev = 23; /* TLAN 2.3 */ 5178c2ecf20Sopenharmony_ci } else { 5188c2ecf20Sopenharmony_ci priv->adapter = &board_info[14]; 5198c2ecf20Sopenharmony_ci priv->adapter_rev = 10; /* TLAN 1.0 */ 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci dev->base_addr = ioaddr; 5228c2ecf20Sopenharmony_ci dev->irq = irq; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci /* Kernel parameters */ 5268c2ecf20Sopenharmony_ci if (dev->mem_start) { 5278c2ecf20Sopenharmony_ci priv->aui = dev->mem_start & 0x01; 5288c2ecf20Sopenharmony_ci priv->duplex = ((dev->mem_start & 0x06) == 0x06) ? 0 5298c2ecf20Sopenharmony_ci : (dev->mem_start & 0x06) >> 1; 5308c2ecf20Sopenharmony_ci priv->speed = ((dev->mem_start & 0x18) == 0x18) ? 0 5318c2ecf20Sopenharmony_ci : (dev->mem_start & 0x18) >> 3; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (priv->speed == 0x1) 5348c2ecf20Sopenharmony_ci priv->speed = TLAN_SPEED_10; 5358c2ecf20Sopenharmony_ci else if (priv->speed == 0x2) 5368c2ecf20Sopenharmony_ci priv->speed = TLAN_SPEED_100; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci debug = priv->debug = dev->mem_end; 5398c2ecf20Sopenharmony_ci } else { 5408c2ecf20Sopenharmony_ci priv->aui = aui[boards_found]; 5418c2ecf20Sopenharmony_ci priv->speed = speed[boards_found]; 5428c2ecf20Sopenharmony_ci priv->duplex = duplex[boards_found]; 5438c2ecf20Sopenharmony_ci priv->debug = debug; 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci /* This will be used when we get an adapter error from 5478c2ecf20Sopenharmony_ci * within our irq handler */ 5488c2ecf20Sopenharmony_ci INIT_WORK(&priv->tlan_tqueue, tlan_tx_timeout_work); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci spin_lock_init(&priv->lock); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci rc = tlan_init(dev); 5538c2ecf20Sopenharmony_ci if (rc) { 5548c2ecf20Sopenharmony_ci pr_err("Could not set up device\n"); 5558c2ecf20Sopenharmony_ci goto err_out_free_dev; 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci rc = register_netdev(dev); 5598c2ecf20Sopenharmony_ci if (rc) { 5608c2ecf20Sopenharmony_ci pr_err("Could not register device\n"); 5618c2ecf20Sopenharmony_ci goto err_out_uninit; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci tlan_devices_installed++; 5668c2ecf20Sopenharmony_ci boards_found++; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci /* pdev is NULL if this is an EISA device */ 5698c2ecf20Sopenharmony_ci if (pdev) 5708c2ecf20Sopenharmony_ci tlan_have_pci++; 5718c2ecf20Sopenharmony_ci else { 5728c2ecf20Sopenharmony_ci priv->next_device = tlan_eisa_devices; 5738c2ecf20Sopenharmony_ci tlan_eisa_devices = dev; 5748c2ecf20Sopenharmony_ci tlan_have_eisa++; 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci netdev_info(dev, "irq=%2d, io=%04x, %s, Rev. %d\n", 5788c2ecf20Sopenharmony_ci (int)dev->irq, 5798c2ecf20Sopenharmony_ci (int)dev->base_addr, 5808c2ecf20Sopenharmony_ci priv->adapter->device_label, 5818c2ecf20Sopenharmony_ci priv->adapter_rev); 5828c2ecf20Sopenharmony_ci return 0; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_cierr_out_uninit: 5858c2ecf20Sopenharmony_ci dma_free_coherent(&priv->pci_dev->dev, priv->dma_size, 5868c2ecf20Sopenharmony_ci priv->dma_storage, priv->dma_storage_dma); 5878c2ecf20Sopenharmony_cierr_out_free_dev: 5888c2ecf20Sopenharmony_ci free_netdev(dev); 5898c2ecf20Sopenharmony_cierr_out_regions: 5908c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 5918c2ecf20Sopenharmony_ci if (pdev) 5928c2ecf20Sopenharmony_ci pci_release_regions(pdev); 5938c2ecf20Sopenharmony_cierr_out: 5948c2ecf20Sopenharmony_ci#endif 5958c2ecf20Sopenharmony_ci if (pdev) 5968c2ecf20Sopenharmony_ci pci_disable_device(pdev); 5978c2ecf20Sopenharmony_ci return rc; 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_cistatic void tlan_eisa_cleanup(void) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci struct net_device *dev; 6048c2ecf20Sopenharmony_ci struct tlan_priv *priv; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci while (tlan_have_eisa) { 6078c2ecf20Sopenharmony_ci dev = tlan_eisa_devices; 6088c2ecf20Sopenharmony_ci priv = netdev_priv(dev); 6098c2ecf20Sopenharmony_ci if (priv->dma_storage) { 6108c2ecf20Sopenharmony_ci dma_free_coherent(&priv->pci_dev->dev, priv->dma_size, 6118c2ecf20Sopenharmony_ci priv->dma_storage, 6128c2ecf20Sopenharmony_ci priv->dma_storage_dma); 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci release_region(dev->base_addr, 0x10); 6158c2ecf20Sopenharmony_ci unregister_netdev(dev); 6168c2ecf20Sopenharmony_ci tlan_eisa_devices = priv->next_device; 6178c2ecf20Sopenharmony_ci free_netdev(dev); 6188c2ecf20Sopenharmony_ci tlan_have_eisa--; 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_cistatic void __exit tlan_exit(void) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci pci_unregister_driver(&tlan_driver); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (tlan_have_eisa) 6288c2ecf20Sopenharmony_ci tlan_eisa_cleanup(); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci} 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci/* Module loading/unloading */ 6348c2ecf20Sopenharmony_cimodule_init(tlan_probe); 6358c2ecf20Sopenharmony_cimodule_exit(tlan_exit); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci/************************************************************** 6408c2ecf20Sopenharmony_ci * tlan_eisa_probe 6418c2ecf20Sopenharmony_ci * 6428c2ecf20Sopenharmony_ci * Returns: 0 on success, 1 otherwise 6438c2ecf20Sopenharmony_ci * 6448c2ecf20Sopenharmony_ci * Parms: None 6458c2ecf20Sopenharmony_ci * 6468c2ecf20Sopenharmony_ci * 6478c2ecf20Sopenharmony_ci * This functions probes for EISA devices and calls 6488c2ecf20Sopenharmony_ci * TLan_probe1 when one is found. 6498c2ecf20Sopenharmony_ci * 6508c2ecf20Sopenharmony_ci *************************************************************/ 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_cistatic void __init tlan_eisa_probe(void) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci long ioaddr; 6558c2ecf20Sopenharmony_ci int irq; 6568c2ecf20Sopenharmony_ci u16 device_id; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci if (!EISA_bus) { 6598c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_PROBE, "No EISA bus present\n"); 6608c2ecf20Sopenharmony_ci return; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci /* Loop through all slots of the EISA bus */ 6648c2ecf20Sopenharmony_ci for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_PROBE, "EISA_ID 0x%4x: 0x%4x\n", 6678c2ecf20Sopenharmony_ci (int) ioaddr + 0xc80, inw(ioaddr + EISA_ID)); 6688c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_PROBE, "EISA_ID 0x%4x: 0x%4x\n", 6698c2ecf20Sopenharmony_ci (int) ioaddr + 0xc82, inw(ioaddr + EISA_ID2)); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_PROBE, 6738c2ecf20Sopenharmony_ci "Probing for EISA adapter at IO: 0x%4x : ", 6748c2ecf20Sopenharmony_ci (int) ioaddr); 6758c2ecf20Sopenharmony_ci if (request_region(ioaddr, 0x10, tlan_signature) == NULL) 6768c2ecf20Sopenharmony_ci goto out; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci if (inw(ioaddr + EISA_ID) != 0x110E) { 6798c2ecf20Sopenharmony_ci release_region(ioaddr, 0x10); 6808c2ecf20Sopenharmony_ci goto out; 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci device_id = inw(ioaddr + EISA_ID2); 6848c2ecf20Sopenharmony_ci if (device_id != 0x20F1 && device_id != 0x40F1) { 6858c2ecf20Sopenharmony_ci release_region(ioaddr, 0x10); 6868c2ecf20Sopenharmony_ci goto out; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci /* check if adapter is enabled */ 6908c2ecf20Sopenharmony_ci if (inb(ioaddr + EISA_CR) != 0x1) { 6918c2ecf20Sopenharmony_ci release_region(ioaddr, 0x10); 6928c2ecf20Sopenharmony_ci goto out2; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci if (debug == 0x10) 6968c2ecf20Sopenharmony_ci pr_info("Found one\n"); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci /* Get irq from board */ 7008c2ecf20Sopenharmony_ci switch (inb(ioaddr + 0xcc0)) { 7018c2ecf20Sopenharmony_ci case(0x10): 7028c2ecf20Sopenharmony_ci irq = 5; 7038c2ecf20Sopenharmony_ci break; 7048c2ecf20Sopenharmony_ci case(0x20): 7058c2ecf20Sopenharmony_ci irq = 9; 7068c2ecf20Sopenharmony_ci break; 7078c2ecf20Sopenharmony_ci case(0x40): 7088c2ecf20Sopenharmony_ci irq = 10; 7098c2ecf20Sopenharmony_ci break; 7108c2ecf20Sopenharmony_ci case(0x80): 7118c2ecf20Sopenharmony_ci irq = 11; 7128c2ecf20Sopenharmony_ci break; 7138c2ecf20Sopenharmony_ci default: 7148c2ecf20Sopenharmony_ci goto out; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci /* Setup the newly found eisa adapter */ 7198c2ecf20Sopenharmony_ci tlan_probe1(NULL, ioaddr, irq, 12, NULL); 7208c2ecf20Sopenharmony_ci continue; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ciout: 7238c2ecf20Sopenharmony_ci if (debug == 0x10) 7248c2ecf20Sopenharmony_ci pr_info("None found\n"); 7258c2ecf20Sopenharmony_ci continue; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ciout2: 7288c2ecf20Sopenharmony_ci if (debug == 0x10) 7298c2ecf20Sopenharmony_ci pr_info("Card found but it is not enabled, skipping\n"); 7308c2ecf20Sopenharmony_ci continue; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci} 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 7378c2ecf20Sopenharmony_cistatic void tlan_poll(struct net_device *dev) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci disable_irq(dev->irq); 7408c2ecf20Sopenharmony_ci tlan_handle_interrupt(dev->irq, dev); 7418c2ecf20Sopenharmony_ci enable_irq(dev->irq); 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci#endif 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_cistatic const struct net_device_ops tlan_netdev_ops = { 7468c2ecf20Sopenharmony_ci .ndo_open = tlan_open, 7478c2ecf20Sopenharmony_ci .ndo_stop = tlan_close, 7488c2ecf20Sopenharmony_ci .ndo_start_xmit = tlan_start_tx, 7498c2ecf20Sopenharmony_ci .ndo_tx_timeout = tlan_tx_timeout, 7508c2ecf20Sopenharmony_ci .ndo_get_stats = tlan_get_stats, 7518c2ecf20Sopenharmony_ci .ndo_set_rx_mode = tlan_set_multicast_list, 7528c2ecf20Sopenharmony_ci .ndo_do_ioctl = tlan_ioctl, 7538c2ecf20Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 7548c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 7558c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 7568c2ecf20Sopenharmony_ci .ndo_poll_controller = tlan_poll, 7578c2ecf20Sopenharmony_ci#endif 7588c2ecf20Sopenharmony_ci}; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cistatic void tlan_get_drvinfo(struct net_device *dev, 7618c2ecf20Sopenharmony_ci struct ethtool_drvinfo *info) 7628c2ecf20Sopenharmony_ci{ 7638c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); 7668c2ecf20Sopenharmony_ci if (priv->pci_dev) 7678c2ecf20Sopenharmony_ci strlcpy(info->bus_info, pci_name(priv->pci_dev), 7688c2ecf20Sopenharmony_ci sizeof(info->bus_info)); 7698c2ecf20Sopenharmony_ci else 7708c2ecf20Sopenharmony_ci strlcpy(info->bus_info, "EISA", sizeof(info->bus_info)); 7718c2ecf20Sopenharmony_ci} 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_cistatic int tlan_get_eeprom_len(struct net_device *dev) 7748c2ecf20Sopenharmony_ci{ 7758c2ecf20Sopenharmony_ci return TLAN_EEPROM_SIZE; 7768c2ecf20Sopenharmony_ci} 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_cistatic int tlan_get_eeprom(struct net_device *dev, 7798c2ecf20Sopenharmony_ci struct ethtool_eeprom *eeprom, u8 *data) 7808c2ecf20Sopenharmony_ci{ 7818c2ecf20Sopenharmony_ci int i; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci for (i = 0; i < TLAN_EEPROM_SIZE; i++) 7848c2ecf20Sopenharmony_ci if (tlan_ee_read_byte(dev, i, &data[i])) 7858c2ecf20Sopenharmony_ci return -EIO; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci return 0; 7888c2ecf20Sopenharmony_ci} 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_cistatic const struct ethtool_ops tlan_ethtool_ops = { 7918c2ecf20Sopenharmony_ci .get_drvinfo = tlan_get_drvinfo, 7928c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 7938c2ecf20Sopenharmony_ci .get_eeprom_len = tlan_get_eeprom_len, 7948c2ecf20Sopenharmony_ci .get_eeprom = tlan_get_eeprom, 7958c2ecf20Sopenharmony_ci}; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci/*************************************************************** 7988c2ecf20Sopenharmony_ci * tlan_init 7998c2ecf20Sopenharmony_ci * 8008c2ecf20Sopenharmony_ci * Returns: 8018c2ecf20Sopenharmony_ci * 0 on success, error code otherwise. 8028c2ecf20Sopenharmony_ci * Parms: 8038c2ecf20Sopenharmony_ci * dev The structure of the device to be 8048c2ecf20Sopenharmony_ci * init'ed. 8058c2ecf20Sopenharmony_ci * 8068c2ecf20Sopenharmony_ci * This function completes the initialization of the 8078c2ecf20Sopenharmony_ci * device structure and driver. It reserves the IO 8088c2ecf20Sopenharmony_ci * addresses, allocates memory for the lists and bounce 8098c2ecf20Sopenharmony_ci * buffers, retrieves the MAC address from the eeprom 8108c2ecf20Sopenharmony_ci * and assignes the device's methods. 8118c2ecf20Sopenharmony_ci * 8128c2ecf20Sopenharmony_ci **************************************************************/ 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_cistatic int tlan_init(struct net_device *dev) 8158c2ecf20Sopenharmony_ci{ 8168c2ecf20Sopenharmony_ci int dma_size; 8178c2ecf20Sopenharmony_ci int err; 8188c2ecf20Sopenharmony_ci int i; 8198c2ecf20Sopenharmony_ci struct tlan_priv *priv; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci priv = netdev_priv(dev); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci dma_size = (TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS) 8248c2ecf20Sopenharmony_ci * (sizeof(struct tlan_list)); 8258c2ecf20Sopenharmony_ci priv->dma_storage = dma_alloc_coherent(&priv->pci_dev->dev, dma_size, 8268c2ecf20Sopenharmony_ci &priv->dma_storage_dma, GFP_KERNEL); 8278c2ecf20Sopenharmony_ci priv->dma_size = dma_size; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci if (priv->dma_storage == NULL) { 8308c2ecf20Sopenharmony_ci pr_err("Could not allocate lists and buffers for %s\n", 8318c2ecf20Sopenharmony_ci dev->name); 8328c2ecf20Sopenharmony_ci return -ENOMEM; 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci priv->rx_list = (struct tlan_list *) 8358c2ecf20Sopenharmony_ci ALIGN((unsigned long)priv->dma_storage, 8); 8368c2ecf20Sopenharmony_ci priv->rx_list_dma = ALIGN(priv->dma_storage_dma, 8); 8378c2ecf20Sopenharmony_ci priv->tx_list = priv->rx_list + TLAN_NUM_RX_LISTS; 8388c2ecf20Sopenharmony_ci priv->tx_list_dma = 8398c2ecf20Sopenharmony_ci priv->rx_list_dma + sizeof(struct tlan_list)*TLAN_NUM_RX_LISTS; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci err = 0; 8428c2ecf20Sopenharmony_ci for (i = 0; i < ETH_ALEN; i++) 8438c2ecf20Sopenharmony_ci err |= tlan_ee_read_byte(dev, 8448c2ecf20Sopenharmony_ci (u8) priv->adapter->addr_ofs + i, 8458c2ecf20Sopenharmony_ci (u8 *) &dev->dev_addr[i]); 8468c2ecf20Sopenharmony_ci if (err) { 8478c2ecf20Sopenharmony_ci pr_err("%s: Error reading MAC from eeprom: %d\n", 8488c2ecf20Sopenharmony_ci dev->name, err); 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci /* Olicom OC-2325/OC-2326 have the address byte-swapped */ 8518c2ecf20Sopenharmony_ci if (priv->adapter->addr_ofs == 0xf8) { 8528c2ecf20Sopenharmony_ci for (i = 0; i < ETH_ALEN; i += 2) { 8538c2ecf20Sopenharmony_ci char tmp = dev->dev_addr[i]; 8548c2ecf20Sopenharmony_ci dev->dev_addr[i] = dev->dev_addr[i + 1]; 8558c2ecf20Sopenharmony_ci dev->dev_addr[i + 1] = tmp; 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci netif_carrier_off(dev); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci /* Device methods */ 8628c2ecf20Sopenharmony_ci dev->netdev_ops = &tlan_netdev_ops; 8638c2ecf20Sopenharmony_ci dev->ethtool_ops = &tlan_ethtool_ops; 8648c2ecf20Sopenharmony_ci dev->watchdog_timeo = TX_TIMEOUT; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci return 0; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci} 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci/*************************************************************** 8748c2ecf20Sopenharmony_ci * tlan_open 8758c2ecf20Sopenharmony_ci * 8768c2ecf20Sopenharmony_ci * Returns: 8778c2ecf20Sopenharmony_ci * 0 on success, error code otherwise. 8788c2ecf20Sopenharmony_ci * Parms: 8798c2ecf20Sopenharmony_ci * dev Structure of device to be opened. 8808c2ecf20Sopenharmony_ci * 8818c2ecf20Sopenharmony_ci * This routine puts the driver and TLAN adapter in a 8828c2ecf20Sopenharmony_ci * state where it is ready to send and receive packets. 8838c2ecf20Sopenharmony_ci * It allocates the IRQ, resets and brings the adapter 8848c2ecf20Sopenharmony_ci * out of reset, and allows interrupts. It also delays 8858c2ecf20Sopenharmony_ci * the startup for autonegotiation or sends a Rx GO 8868c2ecf20Sopenharmony_ci * command to the adapter, as appropriate. 8878c2ecf20Sopenharmony_ci * 8888c2ecf20Sopenharmony_ci **************************************************************/ 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_cistatic int tlan_open(struct net_device *dev) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 8938c2ecf20Sopenharmony_ci int err; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci priv->tlan_rev = tlan_dio_read8(dev->base_addr, TLAN_DEF_REVISION); 8968c2ecf20Sopenharmony_ci err = request_irq(dev->irq, tlan_handle_interrupt, IRQF_SHARED, 8978c2ecf20Sopenharmony_ci dev->name, dev); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci if (err) { 9008c2ecf20Sopenharmony_ci netdev_err(dev, "Cannot open because IRQ %d is already in use\n", 9018c2ecf20Sopenharmony_ci dev->irq); 9028c2ecf20Sopenharmony_ci return err; 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci timer_setup(&priv->timer, NULL, 0); 9068c2ecf20Sopenharmony_ci timer_setup(&priv->media_timer, tlan_phy_monitor, 0); 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci tlan_start(dev); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Opened. TLAN Chip Rev: %x\n", 9118c2ecf20Sopenharmony_ci dev->name, priv->tlan_rev); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci return 0; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci} 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci/************************************************************** 9208c2ecf20Sopenharmony_ci * tlan_ioctl 9218c2ecf20Sopenharmony_ci * 9228c2ecf20Sopenharmony_ci * Returns: 9238c2ecf20Sopenharmony_ci * 0 on success, error code otherwise 9248c2ecf20Sopenharmony_ci * Params: 9258c2ecf20Sopenharmony_ci * dev structure of device to receive ioctl. 9268c2ecf20Sopenharmony_ci * 9278c2ecf20Sopenharmony_ci * rq ifreq structure to hold userspace data. 9288c2ecf20Sopenharmony_ci * 9298c2ecf20Sopenharmony_ci * cmd ioctl command. 9308c2ecf20Sopenharmony_ci * 9318c2ecf20Sopenharmony_ci * 9328c2ecf20Sopenharmony_ci *************************************************************/ 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_cistatic int tlan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 9358c2ecf20Sopenharmony_ci{ 9368c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 9378c2ecf20Sopenharmony_ci struct mii_ioctl_data *data = if_mii(rq); 9388c2ecf20Sopenharmony_ci u32 phy = priv->phy[priv->phy_num]; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci if (!priv->phy_online) 9418c2ecf20Sopenharmony_ci return -EAGAIN; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci switch (cmd) { 9448c2ecf20Sopenharmony_ci case SIOCGMIIPHY: /* get address of MII PHY in use. */ 9458c2ecf20Sopenharmony_ci data->phy_id = phy; 9468c2ecf20Sopenharmony_ci fallthrough; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci case SIOCGMIIREG: /* read MII PHY register. */ 9508c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, data->phy_id & 0x1f, 9518c2ecf20Sopenharmony_ci data->reg_num & 0x1f, &data->val_out); 9528c2ecf20Sopenharmony_ci return 0; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci case SIOCSMIIREG: /* write MII PHY register. */ 9568c2ecf20Sopenharmony_ci tlan_mii_write_reg(dev, data->phy_id & 0x1f, 9578c2ecf20Sopenharmony_ci data->reg_num & 0x1f, data->val_in); 9588c2ecf20Sopenharmony_ci return 0; 9598c2ecf20Sopenharmony_ci default: 9608c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 9618c2ecf20Sopenharmony_ci } 9628c2ecf20Sopenharmony_ci} 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci/*************************************************************** 9668c2ecf20Sopenharmony_ci * tlan_tx_timeout 9678c2ecf20Sopenharmony_ci * 9688c2ecf20Sopenharmony_ci * Returns: nothing 9698c2ecf20Sopenharmony_ci * 9708c2ecf20Sopenharmony_ci * Params: 9718c2ecf20Sopenharmony_ci * dev structure of device which timed out 9728c2ecf20Sopenharmony_ci * during transmit. 9738c2ecf20Sopenharmony_ci * 9748c2ecf20Sopenharmony_ci **************************************************************/ 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_cistatic void tlan_tx_timeout(struct net_device *dev, unsigned int txqueue) 9778c2ecf20Sopenharmony_ci{ 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Transmit timed out.\n", dev->name); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci /* Ok so we timed out, lets see what we can do about it...*/ 9828c2ecf20Sopenharmony_ci tlan_free_lists(dev); 9838c2ecf20Sopenharmony_ci tlan_reset_lists(dev); 9848c2ecf20Sopenharmony_ci tlan_read_and_clear_stats(dev, TLAN_IGNORE); 9858c2ecf20Sopenharmony_ci tlan_reset_adapter(dev); 9868c2ecf20Sopenharmony_ci netif_trans_update(dev); /* prevent tx timeout */ 9878c2ecf20Sopenharmony_ci netif_wake_queue(dev); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci/*************************************************************** 9938c2ecf20Sopenharmony_ci * tlan_tx_timeout_work 9948c2ecf20Sopenharmony_ci * 9958c2ecf20Sopenharmony_ci * Returns: nothing 9968c2ecf20Sopenharmony_ci * 9978c2ecf20Sopenharmony_ci * Params: 9988c2ecf20Sopenharmony_ci * work work item of device which timed out 9998c2ecf20Sopenharmony_ci * 10008c2ecf20Sopenharmony_ci **************************************************************/ 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_cistatic void tlan_tx_timeout_work(struct work_struct *work) 10038c2ecf20Sopenharmony_ci{ 10048c2ecf20Sopenharmony_ci struct tlan_priv *priv = 10058c2ecf20Sopenharmony_ci container_of(work, struct tlan_priv, tlan_tqueue); 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci tlan_tx_timeout(priv->dev, UINT_MAX); 10088c2ecf20Sopenharmony_ci} 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci/*************************************************************** 10138c2ecf20Sopenharmony_ci * tlan_start_tx 10148c2ecf20Sopenharmony_ci * 10158c2ecf20Sopenharmony_ci * Returns: 10168c2ecf20Sopenharmony_ci * 0 on success, non-zero on failure. 10178c2ecf20Sopenharmony_ci * Parms: 10188c2ecf20Sopenharmony_ci * skb A pointer to the sk_buff containing the 10198c2ecf20Sopenharmony_ci * frame to be sent. 10208c2ecf20Sopenharmony_ci * dev The device to send the data on. 10218c2ecf20Sopenharmony_ci * 10228c2ecf20Sopenharmony_ci * This function adds a frame to the Tx list to be sent 10238c2ecf20Sopenharmony_ci * ASAP. First it verifies that the adapter is ready and 10248c2ecf20Sopenharmony_ci * there is room in the queue. Then it sets up the next 10258c2ecf20Sopenharmony_ci * available list, copies the frame to the corresponding 10268c2ecf20Sopenharmony_ci * buffer. If the adapter Tx channel is idle, it gives 10278c2ecf20Sopenharmony_ci * the adapter a Tx Go command on the list, otherwise it 10288c2ecf20Sopenharmony_ci * sets the forward address of the previous list to point 10298c2ecf20Sopenharmony_ci * to this one. Then it frees the sk_buff. 10308c2ecf20Sopenharmony_ci * 10318c2ecf20Sopenharmony_ci **************************************************************/ 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_cistatic netdev_tx_t tlan_start_tx(struct sk_buff *skb, struct net_device *dev) 10348c2ecf20Sopenharmony_ci{ 10358c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 10368c2ecf20Sopenharmony_ci dma_addr_t tail_list_phys; 10378c2ecf20Sopenharmony_ci struct tlan_list *tail_list; 10388c2ecf20Sopenharmony_ci unsigned long flags; 10398c2ecf20Sopenharmony_ci unsigned int txlen; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci if (!priv->phy_online) { 10428c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_TX, "TRANSMIT: %s PHY is not ready\n", 10438c2ecf20Sopenharmony_ci dev->name); 10448c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 10458c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 10468c2ecf20Sopenharmony_ci } 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci if (skb_padto(skb, TLAN_MIN_FRAME_SIZE)) 10498c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 10508c2ecf20Sopenharmony_ci txlen = max(skb->len, (unsigned int)TLAN_MIN_FRAME_SIZE); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci tail_list = priv->tx_list + priv->tx_tail; 10538c2ecf20Sopenharmony_ci tail_list_phys = 10548c2ecf20Sopenharmony_ci priv->tx_list_dma + sizeof(struct tlan_list)*priv->tx_tail; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci if (tail_list->c_stat != TLAN_CSTAT_UNUSED) { 10578c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_TX, 10588c2ecf20Sopenharmony_ci "TRANSMIT: %s is busy (Head=%d Tail=%d)\n", 10598c2ecf20Sopenharmony_ci dev->name, priv->tx_head, priv->tx_tail); 10608c2ecf20Sopenharmony_ci netif_stop_queue(dev); 10618c2ecf20Sopenharmony_ci priv->tx_busy_count++; 10628c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 10638c2ecf20Sopenharmony_ci } 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci tail_list->forward = 0; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci tail_list->buffer[0].address = dma_map_single(&priv->pci_dev->dev, 10688c2ecf20Sopenharmony_ci skb->data, txlen, 10698c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 10708c2ecf20Sopenharmony_ci tlan_store_skb(tail_list, skb); 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci tail_list->frame_size = (u16) txlen; 10738c2ecf20Sopenharmony_ci tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) txlen; 10748c2ecf20Sopenharmony_ci tail_list->buffer[1].count = 0; 10758c2ecf20Sopenharmony_ci tail_list->buffer[1].address = 0; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 10788c2ecf20Sopenharmony_ci tail_list->c_stat = TLAN_CSTAT_READY; 10798c2ecf20Sopenharmony_ci if (!priv->tx_in_progress) { 10808c2ecf20Sopenharmony_ci priv->tx_in_progress = 1; 10818c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_TX, 10828c2ecf20Sopenharmony_ci "TRANSMIT: Starting TX on buffer %d\n", 10838c2ecf20Sopenharmony_ci priv->tx_tail); 10848c2ecf20Sopenharmony_ci outl(tail_list_phys, dev->base_addr + TLAN_CH_PARM); 10858c2ecf20Sopenharmony_ci outl(TLAN_HC_GO, dev->base_addr + TLAN_HOST_CMD); 10868c2ecf20Sopenharmony_ci } else { 10878c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_TX, 10888c2ecf20Sopenharmony_ci "TRANSMIT: Adding buffer %d to TX channel\n", 10898c2ecf20Sopenharmony_ci priv->tx_tail); 10908c2ecf20Sopenharmony_ci if (priv->tx_tail == 0) { 10918c2ecf20Sopenharmony_ci (priv->tx_list + (TLAN_NUM_TX_LISTS - 1))->forward 10928c2ecf20Sopenharmony_ci = tail_list_phys; 10938c2ecf20Sopenharmony_ci } else { 10948c2ecf20Sopenharmony_ci (priv->tx_list + (priv->tx_tail - 1))->forward 10958c2ecf20Sopenharmony_ci = tail_list_phys; 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci CIRC_INC(priv->tx_tail, TLAN_NUM_TX_LISTS); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci} 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci/*************************************************************** 11108c2ecf20Sopenharmony_ci * tlan_handle_interrupt 11118c2ecf20Sopenharmony_ci * 11128c2ecf20Sopenharmony_ci * Returns: 11138c2ecf20Sopenharmony_ci * Nothing 11148c2ecf20Sopenharmony_ci * Parms: 11158c2ecf20Sopenharmony_ci * irq The line on which the interrupt 11168c2ecf20Sopenharmony_ci * occurred. 11178c2ecf20Sopenharmony_ci * dev_id A pointer to the device assigned to 11188c2ecf20Sopenharmony_ci * this irq line. 11198c2ecf20Sopenharmony_ci * 11208c2ecf20Sopenharmony_ci * This function handles an interrupt generated by its 11218c2ecf20Sopenharmony_ci * assigned TLAN adapter. The function deactivates 11228c2ecf20Sopenharmony_ci * interrupts on its adapter, records the type of 11238c2ecf20Sopenharmony_ci * interrupt, executes the appropriate subhandler, and 11248c2ecf20Sopenharmony_ci * acknowdges the interrupt to the adapter (thus 11258c2ecf20Sopenharmony_ci * re-enabling adapter interrupts. 11268c2ecf20Sopenharmony_ci * 11278c2ecf20Sopenharmony_ci **************************************************************/ 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_cistatic irqreturn_t tlan_handle_interrupt(int irq, void *dev_id) 11308c2ecf20Sopenharmony_ci{ 11318c2ecf20Sopenharmony_ci struct net_device *dev = dev_id; 11328c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 11338c2ecf20Sopenharmony_ci u16 host_int; 11348c2ecf20Sopenharmony_ci u16 type; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci spin_lock(&priv->lock); 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci host_int = inw(dev->base_addr + TLAN_HOST_INT); 11398c2ecf20Sopenharmony_ci type = (host_int & TLAN_HI_IT_MASK) >> 2; 11408c2ecf20Sopenharmony_ci if (type) { 11418c2ecf20Sopenharmony_ci u32 ack; 11428c2ecf20Sopenharmony_ci u32 host_cmd; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci outw(host_int, dev->base_addr + TLAN_HOST_INT); 11458c2ecf20Sopenharmony_ci ack = tlan_int_vector[type](dev, host_int); 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci if (ack) { 11488c2ecf20Sopenharmony_ci host_cmd = TLAN_HC_ACK | ack | (type << 18); 11498c2ecf20Sopenharmony_ci outl(host_cmd, dev->base_addr + TLAN_HOST_CMD); 11508c2ecf20Sopenharmony_ci } 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci spin_unlock(&priv->lock); 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci return IRQ_RETVAL(type); 11568c2ecf20Sopenharmony_ci} 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci/*************************************************************** 11628c2ecf20Sopenharmony_ci * tlan_close 11638c2ecf20Sopenharmony_ci * 11648c2ecf20Sopenharmony_ci * Returns: 11658c2ecf20Sopenharmony_ci * An error code. 11668c2ecf20Sopenharmony_ci * Parms: 11678c2ecf20Sopenharmony_ci * dev The device structure of the device to 11688c2ecf20Sopenharmony_ci * close. 11698c2ecf20Sopenharmony_ci * 11708c2ecf20Sopenharmony_ci * This function shuts down the adapter. It records any 11718c2ecf20Sopenharmony_ci * stats, puts the adapter into reset state, deactivates 11728c2ecf20Sopenharmony_ci * its time as needed, and frees the irq it is using. 11738c2ecf20Sopenharmony_ci * 11748c2ecf20Sopenharmony_ci **************************************************************/ 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_cistatic int tlan_close(struct net_device *dev) 11778c2ecf20Sopenharmony_ci{ 11788c2ecf20Sopenharmony_ci tlan_stop(dev); 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci free_irq(dev->irq, dev); 11818c2ecf20Sopenharmony_ci tlan_free_lists(dev); 11828c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_GNRL, "Device %s closed.\n", dev->name); 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci return 0; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci} 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci/*************************************************************** 11928c2ecf20Sopenharmony_ci * tlan_get_stats 11938c2ecf20Sopenharmony_ci * 11948c2ecf20Sopenharmony_ci * Returns: 11958c2ecf20Sopenharmony_ci * A pointer to the device's statistics structure. 11968c2ecf20Sopenharmony_ci * Parms: 11978c2ecf20Sopenharmony_ci * dev The device structure to return the 11988c2ecf20Sopenharmony_ci * stats for. 11998c2ecf20Sopenharmony_ci * 12008c2ecf20Sopenharmony_ci * This function updates the devices statistics by reading 12018c2ecf20Sopenharmony_ci * the TLAN chip's onboard registers. Then it returns the 12028c2ecf20Sopenharmony_ci * address of the statistics structure. 12038c2ecf20Sopenharmony_ci * 12048c2ecf20Sopenharmony_ci **************************************************************/ 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_cistatic struct net_device_stats *tlan_get_stats(struct net_device *dev) 12078c2ecf20Sopenharmony_ci{ 12088c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 12098c2ecf20Sopenharmony_ci int i; 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci /* Should only read stats if open ? */ 12128c2ecf20Sopenharmony_ci tlan_read_and_clear_stats(dev, TLAN_RECORD); 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_RX, "RECEIVE: %s EOC count = %d\n", dev->name, 12158c2ecf20Sopenharmony_ci priv->rx_eoc_count); 12168c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_TX, "TRANSMIT: %s Busy count = %d\n", dev->name, 12178c2ecf20Sopenharmony_ci priv->tx_busy_count); 12188c2ecf20Sopenharmony_ci if (debug & TLAN_DEBUG_GNRL) { 12198c2ecf20Sopenharmony_ci tlan_print_dio(dev->base_addr); 12208c2ecf20Sopenharmony_ci tlan_phy_print(dev); 12218c2ecf20Sopenharmony_ci } 12228c2ecf20Sopenharmony_ci if (debug & TLAN_DEBUG_LIST) { 12238c2ecf20Sopenharmony_ci for (i = 0; i < TLAN_NUM_RX_LISTS; i++) 12248c2ecf20Sopenharmony_ci tlan_print_list(priv->rx_list + i, "RX", i); 12258c2ecf20Sopenharmony_ci for (i = 0; i < TLAN_NUM_TX_LISTS; i++) 12268c2ecf20Sopenharmony_ci tlan_print_list(priv->tx_list + i, "TX", i); 12278c2ecf20Sopenharmony_ci } 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci return &dev->stats; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci} 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci/*************************************************************** 12378c2ecf20Sopenharmony_ci * tlan_set_multicast_list 12388c2ecf20Sopenharmony_ci * 12398c2ecf20Sopenharmony_ci * Returns: 12408c2ecf20Sopenharmony_ci * Nothing 12418c2ecf20Sopenharmony_ci * Parms: 12428c2ecf20Sopenharmony_ci * dev The device structure to set the 12438c2ecf20Sopenharmony_ci * multicast list for. 12448c2ecf20Sopenharmony_ci * 12458c2ecf20Sopenharmony_ci * This function sets the TLAN adaptor to various receive 12468c2ecf20Sopenharmony_ci * modes. If the IFF_PROMISC flag is set, promiscuous 12478c2ecf20Sopenharmony_ci * mode is acitviated. Otherwise, promiscuous mode is 12488c2ecf20Sopenharmony_ci * turned off. If the IFF_ALLMULTI flag is set, then 12498c2ecf20Sopenharmony_ci * the hash table is set to receive all group addresses. 12508c2ecf20Sopenharmony_ci * Otherwise, the first three multicast addresses are 12518c2ecf20Sopenharmony_ci * stored in AREG_1-3, and the rest are selected via the 12528c2ecf20Sopenharmony_ci * hash table, as necessary. 12538c2ecf20Sopenharmony_ci * 12548c2ecf20Sopenharmony_ci **************************************************************/ 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_cistatic void tlan_set_multicast_list(struct net_device *dev) 12578c2ecf20Sopenharmony_ci{ 12588c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 12598c2ecf20Sopenharmony_ci u32 hash1 = 0; 12608c2ecf20Sopenharmony_ci u32 hash2 = 0; 12618c2ecf20Sopenharmony_ci int i; 12628c2ecf20Sopenharmony_ci u32 offset; 12638c2ecf20Sopenharmony_ci u8 tmp; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci if (dev->flags & IFF_PROMISC) { 12668c2ecf20Sopenharmony_ci tmp = tlan_dio_read8(dev->base_addr, TLAN_NET_CMD); 12678c2ecf20Sopenharmony_ci tlan_dio_write8(dev->base_addr, 12688c2ecf20Sopenharmony_ci TLAN_NET_CMD, tmp | TLAN_NET_CMD_CAF); 12698c2ecf20Sopenharmony_ci } else { 12708c2ecf20Sopenharmony_ci tmp = tlan_dio_read8(dev->base_addr, TLAN_NET_CMD); 12718c2ecf20Sopenharmony_ci tlan_dio_write8(dev->base_addr, 12728c2ecf20Sopenharmony_ci TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF); 12738c2ecf20Sopenharmony_ci if (dev->flags & IFF_ALLMULTI) { 12748c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) 12758c2ecf20Sopenharmony_ci tlan_set_mac(dev, i + 1, NULL); 12768c2ecf20Sopenharmony_ci tlan_dio_write32(dev->base_addr, TLAN_HASH_1, 12778c2ecf20Sopenharmony_ci 0xffffffff); 12788c2ecf20Sopenharmony_ci tlan_dio_write32(dev->base_addr, TLAN_HASH_2, 12798c2ecf20Sopenharmony_ci 0xffffffff); 12808c2ecf20Sopenharmony_ci } else { 12818c2ecf20Sopenharmony_ci i = 0; 12828c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 12838c2ecf20Sopenharmony_ci if (i < 3) { 12848c2ecf20Sopenharmony_ci tlan_set_mac(dev, i + 1, 12858c2ecf20Sopenharmony_ci (char *) &ha->addr); 12868c2ecf20Sopenharmony_ci } else { 12878c2ecf20Sopenharmony_ci offset = 12888c2ecf20Sopenharmony_ci tlan_hash_func((u8 *)&ha->addr); 12898c2ecf20Sopenharmony_ci if (offset < 32) 12908c2ecf20Sopenharmony_ci hash1 |= (1 << offset); 12918c2ecf20Sopenharmony_ci else 12928c2ecf20Sopenharmony_ci hash2 |= (1 << (offset - 32)); 12938c2ecf20Sopenharmony_ci } 12948c2ecf20Sopenharmony_ci i++; 12958c2ecf20Sopenharmony_ci } 12968c2ecf20Sopenharmony_ci for ( ; i < 3; i++) 12978c2ecf20Sopenharmony_ci tlan_set_mac(dev, i + 1, NULL); 12988c2ecf20Sopenharmony_ci tlan_dio_write32(dev->base_addr, TLAN_HASH_1, hash1); 12998c2ecf20Sopenharmony_ci tlan_dio_write32(dev->base_addr, TLAN_HASH_2, hash2); 13008c2ecf20Sopenharmony_ci } 13018c2ecf20Sopenharmony_ci } 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci} 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci/***************************************************************************** 13088c2ecf20Sopenharmony_ci****************************************************************************** 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ciThunderLAN driver interrupt vectors and table 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ciplease see chap. 4, "Interrupt Handling" of the "ThunderLAN 13138c2ecf20Sopenharmony_ciProgrammer's Guide" for more informations on handling interrupts 13148c2ecf20Sopenharmony_cigenerated by TLAN based adapters. 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci****************************************************************************** 13178c2ecf20Sopenharmony_ci*****************************************************************************/ 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci/*************************************************************** 13238c2ecf20Sopenharmony_ci * tlan_handle_tx_eof 13248c2ecf20Sopenharmony_ci * 13258c2ecf20Sopenharmony_ci * Returns: 13268c2ecf20Sopenharmony_ci * 1 13278c2ecf20Sopenharmony_ci * Parms: 13288c2ecf20Sopenharmony_ci * dev Device assigned the IRQ that was 13298c2ecf20Sopenharmony_ci * raised. 13308c2ecf20Sopenharmony_ci * host_int The contents of the HOST_INT 13318c2ecf20Sopenharmony_ci * port. 13328c2ecf20Sopenharmony_ci * 13338c2ecf20Sopenharmony_ci * This function handles Tx EOF interrupts which are raised 13348c2ecf20Sopenharmony_ci * by the adapter when it has completed sending the 13358c2ecf20Sopenharmony_ci * contents of a buffer. If detemines which list/buffer 13368c2ecf20Sopenharmony_ci * was completed and resets it. If the buffer was the last 13378c2ecf20Sopenharmony_ci * in the channel (EOC), then the function checks to see if 13388c2ecf20Sopenharmony_ci * another buffer is ready to send, and if so, sends a Tx 13398c2ecf20Sopenharmony_ci * Go command. Finally, the driver activates/continues the 13408c2ecf20Sopenharmony_ci * activity LED. 13418c2ecf20Sopenharmony_ci * 13428c2ecf20Sopenharmony_ci **************************************************************/ 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_cistatic u32 tlan_handle_tx_eof(struct net_device *dev, u16 host_int) 13458c2ecf20Sopenharmony_ci{ 13468c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 13478c2ecf20Sopenharmony_ci int eoc = 0; 13488c2ecf20Sopenharmony_ci struct tlan_list *head_list; 13498c2ecf20Sopenharmony_ci dma_addr_t head_list_phys; 13508c2ecf20Sopenharmony_ci u32 ack = 0; 13518c2ecf20Sopenharmony_ci u16 tmp_c_stat; 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_TX, 13548c2ecf20Sopenharmony_ci "TRANSMIT: Handling TX EOF (Head=%d Tail=%d)\n", 13558c2ecf20Sopenharmony_ci priv->tx_head, priv->tx_tail); 13568c2ecf20Sopenharmony_ci head_list = priv->tx_list + priv->tx_head; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci while (((tmp_c_stat = head_list->c_stat) & TLAN_CSTAT_FRM_CMP) 13598c2ecf20Sopenharmony_ci && (ack < 255)) { 13608c2ecf20Sopenharmony_ci struct sk_buff *skb = tlan_get_skb(head_list); 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci ack++; 13638c2ecf20Sopenharmony_ci dma_unmap_single(&priv->pci_dev->dev, 13648c2ecf20Sopenharmony_ci head_list->buffer[0].address, 13658c2ecf20Sopenharmony_ci max(skb->len, (unsigned int)TLAN_MIN_FRAME_SIZE), 13668c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 13678c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 13688c2ecf20Sopenharmony_ci head_list->buffer[8].address = 0; 13698c2ecf20Sopenharmony_ci head_list->buffer[9].address = 0; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci if (tmp_c_stat & TLAN_CSTAT_EOC) 13728c2ecf20Sopenharmony_ci eoc = 1; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci dev->stats.tx_bytes += head_list->frame_size; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci head_list->c_stat = TLAN_CSTAT_UNUSED; 13778c2ecf20Sopenharmony_ci netif_start_queue(dev); 13788c2ecf20Sopenharmony_ci CIRC_INC(priv->tx_head, TLAN_NUM_TX_LISTS); 13798c2ecf20Sopenharmony_ci head_list = priv->tx_list + priv->tx_head; 13808c2ecf20Sopenharmony_ci } 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci if (!ack) 13838c2ecf20Sopenharmony_ci netdev_info(dev, 13848c2ecf20Sopenharmony_ci "Received interrupt for uncompleted TX frame\n"); 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci if (eoc) { 13878c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_TX, 13888c2ecf20Sopenharmony_ci "TRANSMIT: handling TX EOC (Head=%d Tail=%d)\n", 13898c2ecf20Sopenharmony_ci priv->tx_head, priv->tx_tail); 13908c2ecf20Sopenharmony_ci head_list = priv->tx_list + priv->tx_head; 13918c2ecf20Sopenharmony_ci head_list_phys = priv->tx_list_dma 13928c2ecf20Sopenharmony_ci + sizeof(struct tlan_list)*priv->tx_head; 13938c2ecf20Sopenharmony_ci if ((head_list->c_stat & TLAN_CSTAT_READY) 13948c2ecf20Sopenharmony_ci == TLAN_CSTAT_READY) { 13958c2ecf20Sopenharmony_ci outl(head_list_phys, dev->base_addr + TLAN_CH_PARM); 13968c2ecf20Sopenharmony_ci ack |= TLAN_HC_GO; 13978c2ecf20Sopenharmony_ci } else { 13988c2ecf20Sopenharmony_ci priv->tx_in_progress = 0; 13998c2ecf20Sopenharmony_ci } 14008c2ecf20Sopenharmony_ci } 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci if (priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED) { 14038c2ecf20Sopenharmony_ci tlan_dio_write8(dev->base_addr, 14048c2ecf20Sopenharmony_ci TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT); 14058c2ecf20Sopenharmony_ci if (priv->timer.function == NULL) { 14068c2ecf20Sopenharmony_ci priv->timer.function = tlan_timer; 14078c2ecf20Sopenharmony_ci priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY; 14088c2ecf20Sopenharmony_ci priv->timer_set_at = jiffies; 14098c2ecf20Sopenharmony_ci priv->timer_type = TLAN_TIMER_ACTIVITY; 14108c2ecf20Sopenharmony_ci add_timer(&priv->timer); 14118c2ecf20Sopenharmony_ci } else if (priv->timer_type == TLAN_TIMER_ACTIVITY) { 14128c2ecf20Sopenharmony_ci priv->timer_set_at = jiffies; 14138c2ecf20Sopenharmony_ci } 14148c2ecf20Sopenharmony_ci } 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci return ack; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci} 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci/*************************************************************** 14248c2ecf20Sopenharmony_ci * TLan_HandleStatOverflow 14258c2ecf20Sopenharmony_ci * 14268c2ecf20Sopenharmony_ci * Returns: 14278c2ecf20Sopenharmony_ci * 1 14288c2ecf20Sopenharmony_ci * Parms: 14298c2ecf20Sopenharmony_ci * dev Device assigned the IRQ that was 14308c2ecf20Sopenharmony_ci * raised. 14318c2ecf20Sopenharmony_ci * host_int The contents of the HOST_INT 14328c2ecf20Sopenharmony_ci * port. 14338c2ecf20Sopenharmony_ci * 14348c2ecf20Sopenharmony_ci * This function handles the Statistics Overflow interrupt 14358c2ecf20Sopenharmony_ci * which means that one or more of the TLAN statistics 14368c2ecf20Sopenharmony_ci * registers has reached 1/2 capacity and needs to be read. 14378c2ecf20Sopenharmony_ci * 14388c2ecf20Sopenharmony_ci **************************************************************/ 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_cistatic u32 tlan_handle_stat_overflow(struct net_device *dev, u16 host_int) 14418c2ecf20Sopenharmony_ci{ 14428c2ecf20Sopenharmony_ci tlan_read_and_clear_stats(dev, TLAN_RECORD); 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci return 1; 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci} 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci/*************************************************************** 14528c2ecf20Sopenharmony_ci * TLan_HandleRxEOF 14538c2ecf20Sopenharmony_ci * 14548c2ecf20Sopenharmony_ci * Returns: 14558c2ecf20Sopenharmony_ci * 1 14568c2ecf20Sopenharmony_ci * Parms: 14578c2ecf20Sopenharmony_ci * dev Device assigned the IRQ that was 14588c2ecf20Sopenharmony_ci * raised. 14598c2ecf20Sopenharmony_ci * host_int The contents of the HOST_INT 14608c2ecf20Sopenharmony_ci * port. 14618c2ecf20Sopenharmony_ci * 14628c2ecf20Sopenharmony_ci * This function handles the Rx EOF interrupt which 14638c2ecf20Sopenharmony_ci * indicates a frame has been received by the adapter from 14648c2ecf20Sopenharmony_ci * the net and the frame has been transferred to memory. 14658c2ecf20Sopenharmony_ci * The function determines the bounce buffer the frame has 14668c2ecf20Sopenharmony_ci * been loaded into, creates a new sk_buff big enough to 14678c2ecf20Sopenharmony_ci * hold the frame, and sends it to protocol stack. It 14688c2ecf20Sopenharmony_ci * then resets the used buffer and appends it to the end 14698c2ecf20Sopenharmony_ci * of the list. If the frame was the last in the Rx 14708c2ecf20Sopenharmony_ci * channel (EOC), the function restarts the receive channel 14718c2ecf20Sopenharmony_ci * by sending an Rx Go command to the adapter. Then it 14728c2ecf20Sopenharmony_ci * activates/continues the activity LED. 14738c2ecf20Sopenharmony_ci * 14748c2ecf20Sopenharmony_ci **************************************************************/ 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_cistatic u32 tlan_handle_rx_eof(struct net_device *dev, u16 host_int) 14778c2ecf20Sopenharmony_ci{ 14788c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 14798c2ecf20Sopenharmony_ci u32 ack = 0; 14808c2ecf20Sopenharmony_ci int eoc = 0; 14818c2ecf20Sopenharmony_ci struct tlan_list *head_list; 14828c2ecf20Sopenharmony_ci struct sk_buff *skb; 14838c2ecf20Sopenharmony_ci struct tlan_list *tail_list; 14848c2ecf20Sopenharmony_ci u16 tmp_c_stat; 14858c2ecf20Sopenharmony_ci dma_addr_t head_list_phys; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_RX, "RECEIVE: handling RX EOF (Head=%d Tail=%d)\n", 14888c2ecf20Sopenharmony_ci priv->rx_head, priv->rx_tail); 14898c2ecf20Sopenharmony_ci head_list = priv->rx_list + priv->rx_head; 14908c2ecf20Sopenharmony_ci head_list_phys = 14918c2ecf20Sopenharmony_ci priv->rx_list_dma + sizeof(struct tlan_list)*priv->rx_head; 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci while (((tmp_c_stat = head_list->c_stat) & TLAN_CSTAT_FRM_CMP) 14948c2ecf20Sopenharmony_ci && (ack < 255)) { 14958c2ecf20Sopenharmony_ci dma_addr_t frame_dma = head_list->buffer[0].address; 14968c2ecf20Sopenharmony_ci u32 frame_size = head_list->frame_size; 14978c2ecf20Sopenharmony_ci struct sk_buff *new_skb; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci ack++; 15008c2ecf20Sopenharmony_ci if (tmp_c_stat & TLAN_CSTAT_EOC) 15018c2ecf20Sopenharmony_ci eoc = 1; 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci new_skb = netdev_alloc_skb_ip_align(dev, 15048c2ecf20Sopenharmony_ci TLAN_MAX_FRAME_SIZE + 5); 15058c2ecf20Sopenharmony_ci if (!new_skb) 15068c2ecf20Sopenharmony_ci goto drop_and_reuse; 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci skb = tlan_get_skb(head_list); 15098c2ecf20Sopenharmony_ci dma_unmap_single(&priv->pci_dev->dev, frame_dma, 15108c2ecf20Sopenharmony_ci TLAN_MAX_FRAME_SIZE, DMA_FROM_DEVICE); 15118c2ecf20Sopenharmony_ci skb_put(skb, frame_size); 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci dev->stats.rx_bytes += frame_size; 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 15168c2ecf20Sopenharmony_ci netif_rx(skb); 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci head_list->buffer[0].address = 15198c2ecf20Sopenharmony_ci dma_map_single(&priv->pci_dev->dev, new_skb->data, 15208c2ecf20Sopenharmony_ci TLAN_MAX_FRAME_SIZE, DMA_FROM_DEVICE); 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci tlan_store_skb(head_list, new_skb); 15238c2ecf20Sopenharmony_cidrop_and_reuse: 15248c2ecf20Sopenharmony_ci head_list->forward = 0; 15258c2ecf20Sopenharmony_ci head_list->c_stat = 0; 15268c2ecf20Sopenharmony_ci tail_list = priv->rx_list + priv->rx_tail; 15278c2ecf20Sopenharmony_ci tail_list->forward = head_list_phys; 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci CIRC_INC(priv->rx_head, TLAN_NUM_RX_LISTS); 15308c2ecf20Sopenharmony_ci CIRC_INC(priv->rx_tail, TLAN_NUM_RX_LISTS); 15318c2ecf20Sopenharmony_ci head_list = priv->rx_list + priv->rx_head; 15328c2ecf20Sopenharmony_ci head_list_phys = priv->rx_list_dma 15338c2ecf20Sopenharmony_ci + sizeof(struct tlan_list)*priv->rx_head; 15348c2ecf20Sopenharmony_ci } 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci if (!ack) 15378c2ecf20Sopenharmony_ci netdev_info(dev, 15388c2ecf20Sopenharmony_ci "Received interrupt for uncompleted RX frame\n"); 15398c2ecf20Sopenharmony_ci 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci if (eoc) { 15428c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_RX, 15438c2ecf20Sopenharmony_ci "RECEIVE: handling RX EOC (Head=%d Tail=%d)\n", 15448c2ecf20Sopenharmony_ci priv->rx_head, priv->rx_tail); 15458c2ecf20Sopenharmony_ci head_list = priv->rx_list + priv->rx_head; 15468c2ecf20Sopenharmony_ci head_list_phys = priv->rx_list_dma 15478c2ecf20Sopenharmony_ci + sizeof(struct tlan_list)*priv->rx_head; 15488c2ecf20Sopenharmony_ci outl(head_list_phys, dev->base_addr + TLAN_CH_PARM); 15498c2ecf20Sopenharmony_ci ack |= TLAN_HC_GO | TLAN_HC_RT; 15508c2ecf20Sopenharmony_ci priv->rx_eoc_count++; 15518c2ecf20Sopenharmony_ci } 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci if (priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED) { 15548c2ecf20Sopenharmony_ci tlan_dio_write8(dev->base_addr, 15558c2ecf20Sopenharmony_ci TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT); 15568c2ecf20Sopenharmony_ci if (priv->timer.function == NULL) { 15578c2ecf20Sopenharmony_ci priv->timer.function = tlan_timer; 15588c2ecf20Sopenharmony_ci priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY; 15598c2ecf20Sopenharmony_ci priv->timer_set_at = jiffies; 15608c2ecf20Sopenharmony_ci priv->timer_type = TLAN_TIMER_ACTIVITY; 15618c2ecf20Sopenharmony_ci add_timer(&priv->timer); 15628c2ecf20Sopenharmony_ci } else if (priv->timer_type == TLAN_TIMER_ACTIVITY) { 15638c2ecf20Sopenharmony_ci priv->timer_set_at = jiffies; 15648c2ecf20Sopenharmony_ci } 15658c2ecf20Sopenharmony_ci } 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci return ack; 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci} 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci/*************************************************************** 15758c2ecf20Sopenharmony_ci * tlan_handle_dummy 15768c2ecf20Sopenharmony_ci * 15778c2ecf20Sopenharmony_ci * Returns: 15788c2ecf20Sopenharmony_ci * 1 15798c2ecf20Sopenharmony_ci * Parms: 15808c2ecf20Sopenharmony_ci * dev Device assigned the IRQ that was 15818c2ecf20Sopenharmony_ci * raised. 15828c2ecf20Sopenharmony_ci * host_int The contents of the HOST_INT 15838c2ecf20Sopenharmony_ci * port. 15848c2ecf20Sopenharmony_ci * 15858c2ecf20Sopenharmony_ci * This function handles the Dummy interrupt, which is 15868c2ecf20Sopenharmony_ci * raised whenever a test interrupt is generated by setting 15878c2ecf20Sopenharmony_ci * the Req_Int bit of HOST_CMD to 1. 15888c2ecf20Sopenharmony_ci * 15898c2ecf20Sopenharmony_ci **************************************************************/ 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_cistatic u32 tlan_handle_dummy(struct net_device *dev, u16 host_int) 15928c2ecf20Sopenharmony_ci{ 15938c2ecf20Sopenharmony_ci netdev_info(dev, "Test interrupt\n"); 15948c2ecf20Sopenharmony_ci return 1; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci} 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci/*************************************************************** 16028c2ecf20Sopenharmony_ci * tlan_handle_tx_eoc 16038c2ecf20Sopenharmony_ci * 16048c2ecf20Sopenharmony_ci * Returns: 16058c2ecf20Sopenharmony_ci * 1 16068c2ecf20Sopenharmony_ci * Parms: 16078c2ecf20Sopenharmony_ci * dev Device assigned the IRQ that was 16088c2ecf20Sopenharmony_ci * raised. 16098c2ecf20Sopenharmony_ci * host_int The contents of the HOST_INT 16108c2ecf20Sopenharmony_ci * port. 16118c2ecf20Sopenharmony_ci * 16128c2ecf20Sopenharmony_ci * This driver is structured to determine EOC occurrences by 16138c2ecf20Sopenharmony_ci * reading the CSTAT member of the list structure. Tx EOC 16148c2ecf20Sopenharmony_ci * interrupts are disabled via the DIO INTDIS register. 16158c2ecf20Sopenharmony_ci * However, TLAN chips before revision 3.0 didn't have this 16168c2ecf20Sopenharmony_ci * functionality, so process EOC events if this is the 16178c2ecf20Sopenharmony_ci * case. 16188c2ecf20Sopenharmony_ci * 16198c2ecf20Sopenharmony_ci **************************************************************/ 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_cistatic u32 tlan_handle_tx_eoc(struct net_device *dev, u16 host_int) 16228c2ecf20Sopenharmony_ci{ 16238c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 16248c2ecf20Sopenharmony_ci struct tlan_list *head_list; 16258c2ecf20Sopenharmony_ci dma_addr_t head_list_phys; 16268c2ecf20Sopenharmony_ci u32 ack = 1; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci if (priv->tlan_rev < 0x30) { 16298c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_TX, 16308c2ecf20Sopenharmony_ci "TRANSMIT: handling TX EOC (Head=%d Tail=%d) -- IRQ\n", 16318c2ecf20Sopenharmony_ci priv->tx_head, priv->tx_tail); 16328c2ecf20Sopenharmony_ci head_list = priv->tx_list + priv->tx_head; 16338c2ecf20Sopenharmony_ci head_list_phys = priv->tx_list_dma 16348c2ecf20Sopenharmony_ci + sizeof(struct tlan_list)*priv->tx_head; 16358c2ecf20Sopenharmony_ci if ((head_list->c_stat & TLAN_CSTAT_READY) 16368c2ecf20Sopenharmony_ci == TLAN_CSTAT_READY) { 16378c2ecf20Sopenharmony_ci netif_stop_queue(dev); 16388c2ecf20Sopenharmony_ci outl(head_list_phys, dev->base_addr + TLAN_CH_PARM); 16398c2ecf20Sopenharmony_ci ack |= TLAN_HC_GO; 16408c2ecf20Sopenharmony_ci } else { 16418c2ecf20Sopenharmony_ci priv->tx_in_progress = 0; 16428c2ecf20Sopenharmony_ci } 16438c2ecf20Sopenharmony_ci } 16448c2ecf20Sopenharmony_ci 16458c2ecf20Sopenharmony_ci return ack; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci} 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci/*************************************************************** 16538c2ecf20Sopenharmony_ci * tlan_handle_status_check 16548c2ecf20Sopenharmony_ci * 16558c2ecf20Sopenharmony_ci * Returns: 16568c2ecf20Sopenharmony_ci * 0 if Adapter check, 1 if Network Status check. 16578c2ecf20Sopenharmony_ci * Parms: 16588c2ecf20Sopenharmony_ci * dev Device assigned the IRQ that was 16598c2ecf20Sopenharmony_ci * raised. 16608c2ecf20Sopenharmony_ci * host_int The contents of the HOST_INT 16618c2ecf20Sopenharmony_ci * port. 16628c2ecf20Sopenharmony_ci * 16638c2ecf20Sopenharmony_ci * This function handles Adapter Check/Network Status 16648c2ecf20Sopenharmony_ci * interrupts generated by the adapter. It checks the 16658c2ecf20Sopenharmony_ci * vector in the HOST_INT register to determine if it is 16668c2ecf20Sopenharmony_ci * an Adapter Check interrupt. If so, it resets the 16678c2ecf20Sopenharmony_ci * adapter. Otherwise it clears the status registers 16688c2ecf20Sopenharmony_ci * and services the PHY. 16698c2ecf20Sopenharmony_ci * 16708c2ecf20Sopenharmony_ci **************************************************************/ 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_cistatic u32 tlan_handle_status_check(struct net_device *dev, u16 host_int) 16738c2ecf20Sopenharmony_ci{ 16748c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 16758c2ecf20Sopenharmony_ci u32 ack; 16768c2ecf20Sopenharmony_ci u32 error; 16778c2ecf20Sopenharmony_ci u8 net_sts; 16788c2ecf20Sopenharmony_ci u32 phy; 16798c2ecf20Sopenharmony_ci u16 tlphy_ctl; 16808c2ecf20Sopenharmony_ci u16 tlphy_sts; 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci ack = 1; 16838c2ecf20Sopenharmony_ci if (host_int & TLAN_HI_IV_MASK) { 16848c2ecf20Sopenharmony_ci netif_stop_queue(dev); 16858c2ecf20Sopenharmony_ci error = inl(dev->base_addr + TLAN_CH_PARM); 16868c2ecf20Sopenharmony_ci netdev_info(dev, "Adaptor Error = 0x%x\n", error); 16878c2ecf20Sopenharmony_ci tlan_read_and_clear_stats(dev, TLAN_RECORD); 16888c2ecf20Sopenharmony_ci outl(TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD); 16898c2ecf20Sopenharmony_ci 16908c2ecf20Sopenharmony_ci schedule_work(&priv->tlan_tqueue); 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci netif_wake_queue(dev); 16938c2ecf20Sopenharmony_ci ack = 0; 16948c2ecf20Sopenharmony_ci } else { 16958c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Status Check\n", dev->name); 16968c2ecf20Sopenharmony_ci phy = priv->phy[priv->phy_num]; 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci net_sts = tlan_dio_read8(dev->base_addr, TLAN_NET_STS); 16998c2ecf20Sopenharmony_ci if (net_sts) { 17008c2ecf20Sopenharmony_ci tlan_dio_write8(dev->base_addr, TLAN_NET_STS, net_sts); 17018c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Net_Sts = %x\n", 17028c2ecf20Sopenharmony_ci dev->name, (unsigned) net_sts); 17038c2ecf20Sopenharmony_ci } 17048c2ecf20Sopenharmony_ci if ((net_sts & TLAN_NET_STS_MIRQ) && (priv->phy_num == 0)) { 17058c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, TLAN_TLPHY_STS, &tlphy_sts); 17068c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl); 17078c2ecf20Sopenharmony_ci if (!(tlphy_sts & TLAN_TS_POLOK) && 17088c2ecf20Sopenharmony_ci !(tlphy_ctl & TLAN_TC_SWAPOL)) { 17098c2ecf20Sopenharmony_ci tlphy_ctl |= TLAN_TC_SWAPOL; 17108c2ecf20Sopenharmony_ci tlan_mii_write_reg(dev, phy, TLAN_TLPHY_CTL, 17118c2ecf20Sopenharmony_ci tlphy_ctl); 17128c2ecf20Sopenharmony_ci } else if ((tlphy_sts & TLAN_TS_POLOK) && 17138c2ecf20Sopenharmony_ci (tlphy_ctl & TLAN_TC_SWAPOL)) { 17148c2ecf20Sopenharmony_ci tlphy_ctl &= ~TLAN_TC_SWAPOL; 17158c2ecf20Sopenharmony_ci tlan_mii_write_reg(dev, phy, TLAN_TLPHY_CTL, 17168c2ecf20Sopenharmony_ci tlphy_ctl); 17178c2ecf20Sopenharmony_ci } 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_ci if (debug) 17208c2ecf20Sopenharmony_ci tlan_phy_print(dev); 17218c2ecf20Sopenharmony_ci } 17228c2ecf20Sopenharmony_ci } 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci return ack; 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci} 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci/*************************************************************** 17328c2ecf20Sopenharmony_ci * tlan_handle_rx_eoc 17338c2ecf20Sopenharmony_ci * 17348c2ecf20Sopenharmony_ci * Returns: 17358c2ecf20Sopenharmony_ci * 1 17368c2ecf20Sopenharmony_ci * Parms: 17378c2ecf20Sopenharmony_ci * dev Device assigned the IRQ that was 17388c2ecf20Sopenharmony_ci * raised. 17398c2ecf20Sopenharmony_ci * host_int The contents of the HOST_INT 17408c2ecf20Sopenharmony_ci * port. 17418c2ecf20Sopenharmony_ci * 17428c2ecf20Sopenharmony_ci * This driver is structured to determine EOC occurrences by 17438c2ecf20Sopenharmony_ci * reading the CSTAT member of the list structure. Rx EOC 17448c2ecf20Sopenharmony_ci * interrupts are disabled via the DIO INTDIS register. 17458c2ecf20Sopenharmony_ci * However, TLAN chips before revision 3.0 didn't have this 17468c2ecf20Sopenharmony_ci * CSTAT member or a INTDIS register, so if this chip is 17478c2ecf20Sopenharmony_ci * pre-3.0, process EOC interrupts normally. 17488c2ecf20Sopenharmony_ci * 17498c2ecf20Sopenharmony_ci **************************************************************/ 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_cistatic u32 tlan_handle_rx_eoc(struct net_device *dev, u16 host_int) 17528c2ecf20Sopenharmony_ci{ 17538c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 17548c2ecf20Sopenharmony_ci dma_addr_t head_list_phys; 17558c2ecf20Sopenharmony_ci u32 ack = 1; 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci if (priv->tlan_rev < 0x30) { 17588c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_RX, 17598c2ecf20Sopenharmony_ci "RECEIVE: Handling RX EOC (head=%d tail=%d) -- IRQ\n", 17608c2ecf20Sopenharmony_ci priv->rx_head, priv->rx_tail); 17618c2ecf20Sopenharmony_ci head_list_phys = priv->rx_list_dma 17628c2ecf20Sopenharmony_ci + sizeof(struct tlan_list)*priv->rx_head; 17638c2ecf20Sopenharmony_ci outl(head_list_phys, dev->base_addr + TLAN_CH_PARM); 17648c2ecf20Sopenharmony_ci ack |= TLAN_HC_GO | TLAN_HC_RT; 17658c2ecf20Sopenharmony_ci priv->rx_eoc_count++; 17668c2ecf20Sopenharmony_ci } 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci return ack; 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci} 17718c2ecf20Sopenharmony_ci 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci/***************************************************************************** 17768c2ecf20Sopenharmony_ci****************************************************************************** 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ciThunderLAN driver timer function 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci****************************************************************************** 17818c2ecf20Sopenharmony_ci*****************************************************************************/ 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci/*************************************************************** 17858c2ecf20Sopenharmony_ci * tlan_timer 17868c2ecf20Sopenharmony_ci * 17878c2ecf20Sopenharmony_ci * Returns: 17888c2ecf20Sopenharmony_ci * Nothing 17898c2ecf20Sopenharmony_ci * Parms: 17908c2ecf20Sopenharmony_ci * data A value given to add timer when 17918c2ecf20Sopenharmony_ci * add_timer was called. 17928c2ecf20Sopenharmony_ci * 17938c2ecf20Sopenharmony_ci * This function handles timed functionality for the 17948c2ecf20Sopenharmony_ci * TLAN driver. The two current timer uses are for 17958c2ecf20Sopenharmony_ci * delaying for autonegotionation and driving the ACT LED. 17968c2ecf20Sopenharmony_ci * - Autonegotiation requires being allowed about 17978c2ecf20Sopenharmony_ci * 2 1/2 seconds before attempting to transmit a 17988c2ecf20Sopenharmony_ci * packet. It would be a very bad thing to hang 17998c2ecf20Sopenharmony_ci * the kernel this long, so the driver doesn't 18008c2ecf20Sopenharmony_ci * allow transmission 'til after this time, for 18018c2ecf20Sopenharmony_ci * certain PHYs. It would be much nicer if all 18028c2ecf20Sopenharmony_ci * PHYs were interrupt-capable like the internal 18038c2ecf20Sopenharmony_ci * PHY. 18048c2ecf20Sopenharmony_ci * - The ACT LED, which shows adapter activity, is 18058c2ecf20Sopenharmony_ci * driven by the driver, and so must be left on 18068c2ecf20Sopenharmony_ci * for a short period to power up the LED so it 18078c2ecf20Sopenharmony_ci * can be seen. This delay can be changed by 18088c2ecf20Sopenharmony_ci * changing the TLAN_TIMER_ACT_DELAY in tlan.h, 18098c2ecf20Sopenharmony_ci * if desired. 100 ms produces a slightly 18108c2ecf20Sopenharmony_ci * sluggish response. 18118c2ecf20Sopenharmony_ci * 18128c2ecf20Sopenharmony_ci **************************************************************/ 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_cistatic void tlan_timer(struct timer_list *t) 18158c2ecf20Sopenharmony_ci{ 18168c2ecf20Sopenharmony_ci struct tlan_priv *priv = from_timer(priv, t, timer); 18178c2ecf20Sopenharmony_ci struct net_device *dev = priv->dev; 18188c2ecf20Sopenharmony_ci u32 elapsed; 18198c2ecf20Sopenharmony_ci unsigned long flags = 0; 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci priv->timer.function = NULL; 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci switch (priv->timer_type) { 18248c2ecf20Sopenharmony_ci case TLAN_TIMER_PHY_PDOWN: 18258c2ecf20Sopenharmony_ci tlan_phy_power_down(dev); 18268c2ecf20Sopenharmony_ci break; 18278c2ecf20Sopenharmony_ci case TLAN_TIMER_PHY_PUP: 18288c2ecf20Sopenharmony_ci tlan_phy_power_up(dev); 18298c2ecf20Sopenharmony_ci break; 18308c2ecf20Sopenharmony_ci case TLAN_TIMER_PHY_RESET: 18318c2ecf20Sopenharmony_ci tlan_phy_reset(dev); 18328c2ecf20Sopenharmony_ci break; 18338c2ecf20Sopenharmony_ci case TLAN_TIMER_PHY_START_LINK: 18348c2ecf20Sopenharmony_ci tlan_phy_start_link(dev); 18358c2ecf20Sopenharmony_ci break; 18368c2ecf20Sopenharmony_ci case TLAN_TIMER_PHY_FINISH_AN: 18378c2ecf20Sopenharmony_ci tlan_phy_finish_auto_neg(dev); 18388c2ecf20Sopenharmony_ci break; 18398c2ecf20Sopenharmony_ci case TLAN_TIMER_FINISH_RESET: 18408c2ecf20Sopenharmony_ci tlan_finish_reset(dev); 18418c2ecf20Sopenharmony_ci break; 18428c2ecf20Sopenharmony_ci case TLAN_TIMER_ACTIVITY: 18438c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 18448c2ecf20Sopenharmony_ci if (priv->timer.function == NULL) { 18458c2ecf20Sopenharmony_ci elapsed = jiffies - priv->timer_set_at; 18468c2ecf20Sopenharmony_ci if (elapsed >= TLAN_TIMER_ACT_DELAY) { 18478c2ecf20Sopenharmony_ci tlan_dio_write8(dev->base_addr, 18488c2ecf20Sopenharmony_ci TLAN_LED_REG, TLAN_LED_LINK); 18498c2ecf20Sopenharmony_ci } else { 18508c2ecf20Sopenharmony_ci priv->timer.expires = priv->timer_set_at 18518c2ecf20Sopenharmony_ci + TLAN_TIMER_ACT_DELAY; 18528c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 18538c2ecf20Sopenharmony_ci add_timer(&priv->timer); 18548c2ecf20Sopenharmony_ci break; 18558c2ecf20Sopenharmony_ci } 18568c2ecf20Sopenharmony_ci } 18578c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 18588c2ecf20Sopenharmony_ci break; 18598c2ecf20Sopenharmony_ci default: 18608c2ecf20Sopenharmony_ci break; 18618c2ecf20Sopenharmony_ci } 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci} 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci/***************************************************************************** 18678c2ecf20Sopenharmony_ci****************************************************************************** 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ciThunderLAN driver adapter related routines 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci****************************************************************************** 18728c2ecf20Sopenharmony_ci*****************************************************************************/ 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci/*************************************************************** 18768c2ecf20Sopenharmony_ci * tlan_reset_lists 18778c2ecf20Sopenharmony_ci * 18788c2ecf20Sopenharmony_ci * Returns: 18798c2ecf20Sopenharmony_ci * Nothing 18808c2ecf20Sopenharmony_ci * Parms: 18818c2ecf20Sopenharmony_ci * dev The device structure with the list 18828c2ecf20Sopenharmony_ci * structures to be reset. 18838c2ecf20Sopenharmony_ci * 18848c2ecf20Sopenharmony_ci * This routine sets the variables associated with managing 18858c2ecf20Sopenharmony_ci * the TLAN lists to their initial values. 18868c2ecf20Sopenharmony_ci * 18878c2ecf20Sopenharmony_ci **************************************************************/ 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_cistatic void tlan_reset_lists(struct net_device *dev) 18908c2ecf20Sopenharmony_ci{ 18918c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 18928c2ecf20Sopenharmony_ci int i; 18938c2ecf20Sopenharmony_ci struct tlan_list *list; 18948c2ecf20Sopenharmony_ci dma_addr_t list_phys; 18958c2ecf20Sopenharmony_ci struct sk_buff *skb; 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ci priv->tx_head = 0; 18988c2ecf20Sopenharmony_ci priv->tx_tail = 0; 18998c2ecf20Sopenharmony_ci for (i = 0; i < TLAN_NUM_TX_LISTS; i++) { 19008c2ecf20Sopenharmony_ci list = priv->tx_list + i; 19018c2ecf20Sopenharmony_ci list->c_stat = TLAN_CSTAT_UNUSED; 19028c2ecf20Sopenharmony_ci list->buffer[0].address = 0; 19038c2ecf20Sopenharmony_ci list->buffer[2].count = 0; 19048c2ecf20Sopenharmony_ci list->buffer[2].address = 0; 19058c2ecf20Sopenharmony_ci list->buffer[8].address = 0; 19068c2ecf20Sopenharmony_ci list->buffer[9].address = 0; 19078c2ecf20Sopenharmony_ci } 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci priv->rx_head = 0; 19108c2ecf20Sopenharmony_ci priv->rx_tail = TLAN_NUM_RX_LISTS - 1; 19118c2ecf20Sopenharmony_ci for (i = 0; i < TLAN_NUM_RX_LISTS; i++) { 19128c2ecf20Sopenharmony_ci list = priv->rx_list + i; 19138c2ecf20Sopenharmony_ci list_phys = priv->rx_list_dma + sizeof(struct tlan_list)*i; 19148c2ecf20Sopenharmony_ci list->c_stat = TLAN_CSTAT_READY; 19158c2ecf20Sopenharmony_ci list->frame_size = TLAN_MAX_FRAME_SIZE; 19168c2ecf20Sopenharmony_ci list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER; 19178c2ecf20Sopenharmony_ci skb = netdev_alloc_skb_ip_align(dev, TLAN_MAX_FRAME_SIZE + 5); 19188c2ecf20Sopenharmony_ci if (!skb) 19198c2ecf20Sopenharmony_ci break; 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci list->buffer[0].address = dma_map_single(&priv->pci_dev->dev, 19228c2ecf20Sopenharmony_ci skb->data, 19238c2ecf20Sopenharmony_ci TLAN_MAX_FRAME_SIZE, 19248c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 19258c2ecf20Sopenharmony_ci tlan_store_skb(list, skb); 19268c2ecf20Sopenharmony_ci list->buffer[1].count = 0; 19278c2ecf20Sopenharmony_ci list->buffer[1].address = 0; 19288c2ecf20Sopenharmony_ci list->forward = list_phys + sizeof(struct tlan_list); 19298c2ecf20Sopenharmony_ci } 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci /* in case ran out of memory early, clear bits */ 19328c2ecf20Sopenharmony_ci while (i < TLAN_NUM_RX_LISTS) { 19338c2ecf20Sopenharmony_ci tlan_store_skb(priv->rx_list + i, NULL); 19348c2ecf20Sopenharmony_ci ++i; 19358c2ecf20Sopenharmony_ci } 19368c2ecf20Sopenharmony_ci list->forward = 0; 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci} 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_cistatic void tlan_free_lists(struct net_device *dev) 19428c2ecf20Sopenharmony_ci{ 19438c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 19448c2ecf20Sopenharmony_ci int i; 19458c2ecf20Sopenharmony_ci struct tlan_list *list; 19468c2ecf20Sopenharmony_ci struct sk_buff *skb; 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci for (i = 0; i < TLAN_NUM_TX_LISTS; i++) { 19498c2ecf20Sopenharmony_ci list = priv->tx_list + i; 19508c2ecf20Sopenharmony_ci skb = tlan_get_skb(list); 19518c2ecf20Sopenharmony_ci if (skb) { 19528c2ecf20Sopenharmony_ci dma_unmap_single(&priv->pci_dev->dev, 19538c2ecf20Sopenharmony_ci list->buffer[0].address, 19548c2ecf20Sopenharmony_ci max(skb->len, (unsigned int)TLAN_MIN_FRAME_SIZE), 19558c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 19568c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 19578c2ecf20Sopenharmony_ci list->buffer[8].address = 0; 19588c2ecf20Sopenharmony_ci list->buffer[9].address = 0; 19598c2ecf20Sopenharmony_ci } 19608c2ecf20Sopenharmony_ci } 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci for (i = 0; i < TLAN_NUM_RX_LISTS; i++) { 19638c2ecf20Sopenharmony_ci list = priv->rx_list + i; 19648c2ecf20Sopenharmony_ci skb = tlan_get_skb(list); 19658c2ecf20Sopenharmony_ci if (skb) { 19668c2ecf20Sopenharmony_ci dma_unmap_single(&priv->pci_dev->dev, 19678c2ecf20Sopenharmony_ci list->buffer[0].address, 19688c2ecf20Sopenharmony_ci TLAN_MAX_FRAME_SIZE, DMA_FROM_DEVICE); 19698c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 19708c2ecf20Sopenharmony_ci list->buffer[8].address = 0; 19718c2ecf20Sopenharmony_ci list->buffer[9].address = 0; 19728c2ecf20Sopenharmony_ci } 19738c2ecf20Sopenharmony_ci } 19748c2ecf20Sopenharmony_ci} 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_ci 19798c2ecf20Sopenharmony_ci/*************************************************************** 19808c2ecf20Sopenharmony_ci * tlan_print_dio 19818c2ecf20Sopenharmony_ci * 19828c2ecf20Sopenharmony_ci * Returns: 19838c2ecf20Sopenharmony_ci * Nothing 19848c2ecf20Sopenharmony_ci * Parms: 19858c2ecf20Sopenharmony_ci * io_base Base IO port of the device of 19868c2ecf20Sopenharmony_ci * which to print DIO registers. 19878c2ecf20Sopenharmony_ci * 19888c2ecf20Sopenharmony_ci * This function prints out all the internal (DIO) 19898c2ecf20Sopenharmony_ci * registers of a TLAN chip. 19908c2ecf20Sopenharmony_ci * 19918c2ecf20Sopenharmony_ci **************************************************************/ 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_cistatic void tlan_print_dio(u16 io_base) 19948c2ecf20Sopenharmony_ci{ 19958c2ecf20Sopenharmony_ci u32 data0, data1; 19968c2ecf20Sopenharmony_ci int i; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci pr_info("Contents of internal registers for io base 0x%04hx\n", 19998c2ecf20Sopenharmony_ci io_base); 20008c2ecf20Sopenharmony_ci pr_info("Off. +0 +4\n"); 20018c2ecf20Sopenharmony_ci for (i = 0; i < 0x4C; i += 8) { 20028c2ecf20Sopenharmony_ci data0 = tlan_dio_read32(io_base, i); 20038c2ecf20Sopenharmony_ci data1 = tlan_dio_read32(io_base, i + 0x4); 20048c2ecf20Sopenharmony_ci pr_info("0x%02x 0x%08x 0x%08x\n", i, data0, data1); 20058c2ecf20Sopenharmony_ci } 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci} 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci/*************************************************************** 20138c2ecf20Sopenharmony_ci * TLan_PrintList 20148c2ecf20Sopenharmony_ci * 20158c2ecf20Sopenharmony_ci * Returns: 20168c2ecf20Sopenharmony_ci * Nothing 20178c2ecf20Sopenharmony_ci * Parms: 20188c2ecf20Sopenharmony_ci * list A pointer to the struct tlan_list structure to 20198c2ecf20Sopenharmony_ci * be printed. 20208c2ecf20Sopenharmony_ci * type A string to designate type of list, 20218c2ecf20Sopenharmony_ci * "Rx" or "Tx". 20228c2ecf20Sopenharmony_ci * num The index of the list. 20238c2ecf20Sopenharmony_ci * 20248c2ecf20Sopenharmony_ci * This function prints out the contents of the list 20258c2ecf20Sopenharmony_ci * pointed to by the list parameter. 20268c2ecf20Sopenharmony_ci * 20278c2ecf20Sopenharmony_ci **************************************************************/ 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_cistatic void tlan_print_list(struct tlan_list *list, char *type, int num) 20308c2ecf20Sopenharmony_ci{ 20318c2ecf20Sopenharmony_ci int i; 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci pr_info("%s List %d at %p\n", type, num, list); 20348c2ecf20Sopenharmony_ci pr_info(" Forward = 0x%08x\n", list->forward); 20358c2ecf20Sopenharmony_ci pr_info(" CSTAT = 0x%04hx\n", list->c_stat); 20368c2ecf20Sopenharmony_ci pr_info(" Frame Size = 0x%04hx\n", list->frame_size); 20378c2ecf20Sopenharmony_ci /* for (i = 0; i < 10; i++) { */ 20388c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 20398c2ecf20Sopenharmony_ci pr_info(" Buffer[%d].count, addr = 0x%08x, 0x%08x\n", 20408c2ecf20Sopenharmony_ci i, list->buffer[i].count, list->buffer[i].address); 20418c2ecf20Sopenharmony_ci } 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci} 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci 20488c2ecf20Sopenharmony_ci/*************************************************************** 20498c2ecf20Sopenharmony_ci * tlan_read_and_clear_stats 20508c2ecf20Sopenharmony_ci * 20518c2ecf20Sopenharmony_ci * Returns: 20528c2ecf20Sopenharmony_ci * Nothing 20538c2ecf20Sopenharmony_ci * Parms: 20548c2ecf20Sopenharmony_ci * dev Pointer to device structure of adapter 20558c2ecf20Sopenharmony_ci * to which to read stats. 20568c2ecf20Sopenharmony_ci * record Flag indicating whether to add 20578c2ecf20Sopenharmony_ci * 20588c2ecf20Sopenharmony_ci * This functions reads all the internal status registers 20598c2ecf20Sopenharmony_ci * of the TLAN chip, which clears them as a side effect. 20608c2ecf20Sopenharmony_ci * It then either adds the values to the device's status 20618c2ecf20Sopenharmony_ci * struct, or discards them, depending on whether record 20628c2ecf20Sopenharmony_ci * is TLAN_RECORD (!=0) or TLAN_IGNORE (==0). 20638c2ecf20Sopenharmony_ci * 20648c2ecf20Sopenharmony_ci **************************************************************/ 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_cistatic void tlan_read_and_clear_stats(struct net_device *dev, int record) 20678c2ecf20Sopenharmony_ci{ 20688c2ecf20Sopenharmony_ci u32 tx_good, tx_under; 20698c2ecf20Sopenharmony_ci u32 rx_good, rx_over; 20708c2ecf20Sopenharmony_ci u32 def_tx, crc, code; 20718c2ecf20Sopenharmony_ci u32 multi_col, single_col; 20728c2ecf20Sopenharmony_ci u32 excess_col, late_col, loss; 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci outw(TLAN_GOOD_TX_FRMS, dev->base_addr + TLAN_DIO_ADR); 20758c2ecf20Sopenharmony_ci tx_good = inb(dev->base_addr + TLAN_DIO_DATA); 20768c2ecf20Sopenharmony_ci tx_good += inb(dev->base_addr + TLAN_DIO_DATA + 1) << 8; 20778c2ecf20Sopenharmony_ci tx_good += inb(dev->base_addr + TLAN_DIO_DATA + 2) << 16; 20788c2ecf20Sopenharmony_ci tx_under = inb(dev->base_addr + TLAN_DIO_DATA + 3); 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci outw(TLAN_GOOD_RX_FRMS, dev->base_addr + TLAN_DIO_ADR); 20818c2ecf20Sopenharmony_ci rx_good = inb(dev->base_addr + TLAN_DIO_DATA); 20828c2ecf20Sopenharmony_ci rx_good += inb(dev->base_addr + TLAN_DIO_DATA + 1) << 8; 20838c2ecf20Sopenharmony_ci rx_good += inb(dev->base_addr + TLAN_DIO_DATA + 2) << 16; 20848c2ecf20Sopenharmony_ci rx_over = inb(dev->base_addr + TLAN_DIO_DATA + 3); 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci outw(TLAN_DEFERRED_TX, dev->base_addr + TLAN_DIO_ADR); 20878c2ecf20Sopenharmony_ci def_tx = inb(dev->base_addr + TLAN_DIO_DATA); 20888c2ecf20Sopenharmony_ci def_tx += inb(dev->base_addr + TLAN_DIO_DATA + 1) << 8; 20898c2ecf20Sopenharmony_ci crc = inb(dev->base_addr + TLAN_DIO_DATA + 2); 20908c2ecf20Sopenharmony_ci code = inb(dev->base_addr + TLAN_DIO_DATA + 3); 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci outw(TLAN_MULTICOL_FRMS, dev->base_addr + TLAN_DIO_ADR); 20938c2ecf20Sopenharmony_ci multi_col = inb(dev->base_addr + TLAN_DIO_DATA); 20948c2ecf20Sopenharmony_ci multi_col += inb(dev->base_addr + TLAN_DIO_DATA + 1) << 8; 20958c2ecf20Sopenharmony_ci single_col = inb(dev->base_addr + TLAN_DIO_DATA + 2); 20968c2ecf20Sopenharmony_ci single_col += inb(dev->base_addr + TLAN_DIO_DATA + 3) << 8; 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci outw(TLAN_EXCESSCOL_FRMS, dev->base_addr + TLAN_DIO_ADR); 20998c2ecf20Sopenharmony_ci excess_col = inb(dev->base_addr + TLAN_DIO_DATA); 21008c2ecf20Sopenharmony_ci late_col = inb(dev->base_addr + TLAN_DIO_DATA + 1); 21018c2ecf20Sopenharmony_ci loss = inb(dev->base_addr + TLAN_DIO_DATA + 2); 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ci if (record) { 21048c2ecf20Sopenharmony_ci dev->stats.rx_packets += rx_good; 21058c2ecf20Sopenharmony_ci dev->stats.rx_errors += rx_over + crc + code; 21068c2ecf20Sopenharmony_ci dev->stats.tx_packets += tx_good; 21078c2ecf20Sopenharmony_ci dev->stats.tx_errors += tx_under + loss; 21088c2ecf20Sopenharmony_ci dev->stats.collisions += multi_col 21098c2ecf20Sopenharmony_ci + single_col + excess_col + late_col; 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci dev->stats.rx_over_errors += rx_over; 21128c2ecf20Sopenharmony_ci dev->stats.rx_crc_errors += crc; 21138c2ecf20Sopenharmony_ci dev->stats.rx_frame_errors += code; 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_ci dev->stats.tx_aborted_errors += tx_under; 21168c2ecf20Sopenharmony_ci dev->stats.tx_carrier_errors += loss; 21178c2ecf20Sopenharmony_ci } 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci} 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci 21248c2ecf20Sopenharmony_ci/*************************************************************** 21258c2ecf20Sopenharmony_ci * TLan_Reset 21268c2ecf20Sopenharmony_ci * 21278c2ecf20Sopenharmony_ci * Returns: 21288c2ecf20Sopenharmony_ci * 0 21298c2ecf20Sopenharmony_ci * Parms: 21308c2ecf20Sopenharmony_ci * dev Pointer to device structure of adapter 21318c2ecf20Sopenharmony_ci * to be reset. 21328c2ecf20Sopenharmony_ci * 21338c2ecf20Sopenharmony_ci * This function resets the adapter and it's physical 21348c2ecf20Sopenharmony_ci * device. See Chap. 3, pp. 9-10 of the "ThunderLAN 21358c2ecf20Sopenharmony_ci * Programmer's Guide" for details. The routine tries to 21368c2ecf20Sopenharmony_ci * implement what is detailed there, though adjustments 21378c2ecf20Sopenharmony_ci * have been made. 21388c2ecf20Sopenharmony_ci * 21398c2ecf20Sopenharmony_ci **************************************************************/ 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_cistatic void 21428c2ecf20Sopenharmony_citlan_reset_adapter(struct net_device *dev) 21438c2ecf20Sopenharmony_ci{ 21448c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 21458c2ecf20Sopenharmony_ci int i; 21468c2ecf20Sopenharmony_ci u32 addr; 21478c2ecf20Sopenharmony_ci u32 data; 21488c2ecf20Sopenharmony_ci u8 data8; 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci priv->tlan_full_duplex = false; 21518c2ecf20Sopenharmony_ci priv->phy_online = 0; 21528c2ecf20Sopenharmony_ci netif_carrier_off(dev); 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci/* 1. Assert reset bit. */ 21558c2ecf20Sopenharmony_ci 21568c2ecf20Sopenharmony_ci data = inl(dev->base_addr + TLAN_HOST_CMD); 21578c2ecf20Sopenharmony_ci data |= TLAN_HC_AD_RST; 21588c2ecf20Sopenharmony_ci outl(data, dev->base_addr + TLAN_HOST_CMD); 21598c2ecf20Sopenharmony_ci 21608c2ecf20Sopenharmony_ci udelay(1000); 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci/* 2. Turn off interrupts. (Probably isn't necessary) */ 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci data = inl(dev->base_addr + TLAN_HOST_CMD); 21658c2ecf20Sopenharmony_ci data |= TLAN_HC_INT_OFF; 21668c2ecf20Sopenharmony_ci outl(data, dev->base_addr + TLAN_HOST_CMD); 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci/* 3. Clear AREGs and HASHs. */ 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_ci for (i = TLAN_AREG_0; i <= TLAN_HASH_2; i += 4) 21718c2ecf20Sopenharmony_ci tlan_dio_write32(dev->base_addr, (u16) i, 0); 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci/* 4. Setup NetConfig register. */ 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN; 21768c2ecf20Sopenharmony_ci tlan_dio_write16(dev->base_addr, TLAN_NET_CONFIG, (u16) data); 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci/* 5. Load Ld_Tmr and Ld_Thr in HOST_CMD. */ 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci outl(TLAN_HC_LD_TMR | 0x3f, dev->base_addr + TLAN_HOST_CMD); 21818c2ecf20Sopenharmony_ci outl(TLAN_HC_LD_THR | 0x9, dev->base_addr + TLAN_HOST_CMD); 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ci/* 6. Unreset the MII by setting NMRST (in NetSio) to 1. */ 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR); 21868c2ecf20Sopenharmony_ci addr = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; 21878c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_NMRST, addr); 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_ci/* 7. Setup the remaining registers. */ 21908c2ecf20Sopenharmony_ci 21918c2ecf20Sopenharmony_ci if (priv->tlan_rev >= 0x30) { 21928c2ecf20Sopenharmony_ci data8 = TLAN_ID_TX_EOC | TLAN_ID_RX_EOC; 21938c2ecf20Sopenharmony_ci tlan_dio_write8(dev->base_addr, TLAN_INT_DIS, data8); 21948c2ecf20Sopenharmony_ci } 21958c2ecf20Sopenharmony_ci tlan_phy_detect(dev); 21968c2ecf20Sopenharmony_ci data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN; 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci if (priv->adapter->flags & TLAN_ADAPTER_BIT_RATE_PHY) { 21998c2ecf20Sopenharmony_ci data |= TLAN_NET_CFG_BIT; 22008c2ecf20Sopenharmony_ci if (priv->aui == 1) { 22018c2ecf20Sopenharmony_ci tlan_dio_write8(dev->base_addr, TLAN_ACOMMIT, 0x0a); 22028c2ecf20Sopenharmony_ci } else if (priv->duplex == TLAN_DUPLEX_FULL) { 22038c2ecf20Sopenharmony_ci tlan_dio_write8(dev->base_addr, TLAN_ACOMMIT, 0x00); 22048c2ecf20Sopenharmony_ci priv->tlan_full_duplex = true; 22058c2ecf20Sopenharmony_ci } else { 22068c2ecf20Sopenharmony_ci tlan_dio_write8(dev->base_addr, TLAN_ACOMMIT, 0x08); 22078c2ecf20Sopenharmony_ci } 22088c2ecf20Sopenharmony_ci } 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci /* don't power down internal PHY if we're going to use it */ 22118c2ecf20Sopenharmony_ci if (priv->phy_num == 0 || 22128c2ecf20Sopenharmony_ci (priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10)) 22138c2ecf20Sopenharmony_ci data |= TLAN_NET_CFG_PHY_EN; 22148c2ecf20Sopenharmony_ci tlan_dio_write16(dev->base_addr, TLAN_NET_CONFIG, (u16) data); 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci if (priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY) 22178c2ecf20Sopenharmony_ci tlan_finish_reset(dev); 22188c2ecf20Sopenharmony_ci else 22198c2ecf20Sopenharmony_ci tlan_phy_power_down(dev); 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci} 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci 22268c2ecf20Sopenharmony_cistatic void 22278c2ecf20Sopenharmony_citlan_finish_reset(struct net_device *dev) 22288c2ecf20Sopenharmony_ci{ 22298c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 22308c2ecf20Sopenharmony_ci u8 data; 22318c2ecf20Sopenharmony_ci u32 phy; 22328c2ecf20Sopenharmony_ci u8 sio; 22338c2ecf20Sopenharmony_ci u16 status; 22348c2ecf20Sopenharmony_ci u16 partner; 22358c2ecf20Sopenharmony_ci u16 tlphy_ctl; 22368c2ecf20Sopenharmony_ci u16 tlphy_par; 22378c2ecf20Sopenharmony_ci u16 tlphy_id1, tlphy_id2; 22388c2ecf20Sopenharmony_ci int i; 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci phy = priv->phy[priv->phy_num]; 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci data = TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP; 22438c2ecf20Sopenharmony_ci if (priv->tlan_full_duplex) 22448c2ecf20Sopenharmony_ci data |= TLAN_NET_CMD_DUPLEX; 22458c2ecf20Sopenharmony_ci tlan_dio_write8(dev->base_addr, TLAN_NET_CMD, data); 22468c2ecf20Sopenharmony_ci data = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5; 22478c2ecf20Sopenharmony_ci if (priv->phy_num == 0) 22488c2ecf20Sopenharmony_ci data |= TLAN_NET_MASK_MASK7; 22498c2ecf20Sopenharmony_ci tlan_dio_write8(dev->base_addr, TLAN_NET_MASK, data); 22508c2ecf20Sopenharmony_ci tlan_dio_write16(dev->base_addr, TLAN_MAX_RX, ((1536)+7)&~7); 22518c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, MII_GEN_ID_HI, &tlphy_id1); 22528c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, MII_GEN_ID_LO, &tlphy_id2); 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci if ((priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY) || 22558c2ecf20Sopenharmony_ci (priv->aui)) { 22568c2ecf20Sopenharmony_ci status = MII_GS_LINK; 22578c2ecf20Sopenharmony_ci netdev_info(dev, "Link forced\n"); 22588c2ecf20Sopenharmony_ci } else { 22598c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, MII_GEN_STS, &status); 22608c2ecf20Sopenharmony_ci udelay(1000); 22618c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, MII_GEN_STS, &status); 22628c2ecf20Sopenharmony_ci if (status & MII_GS_LINK) { 22638c2ecf20Sopenharmony_ci /* We only support link info on Nat.Sem. PHY's */ 22648c2ecf20Sopenharmony_ci if ((tlphy_id1 == NAT_SEM_ID1) && 22658c2ecf20Sopenharmony_ci (tlphy_id2 == NAT_SEM_ID2)) { 22668c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, MII_AN_LPA, 22678c2ecf20Sopenharmony_ci &partner); 22688c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, TLAN_TLPHY_PAR, 22698c2ecf20Sopenharmony_ci &tlphy_par); 22708c2ecf20Sopenharmony_ci 22718c2ecf20Sopenharmony_ci netdev_info(dev, 22728c2ecf20Sopenharmony_ci "Link active, %s %uMbps %s-Duplex\n", 22738c2ecf20Sopenharmony_ci !(tlphy_par & TLAN_PHY_AN_EN_STAT) 22748c2ecf20Sopenharmony_ci ? "forced" : "Autonegotiation enabled,", 22758c2ecf20Sopenharmony_ci tlphy_par & TLAN_PHY_SPEED_100 22768c2ecf20Sopenharmony_ci ? 100 : 10, 22778c2ecf20Sopenharmony_ci tlphy_par & TLAN_PHY_DUPLEX_FULL 22788c2ecf20Sopenharmony_ci ? "Full" : "Half"); 22798c2ecf20Sopenharmony_ci 22808c2ecf20Sopenharmony_ci if (tlphy_par & TLAN_PHY_AN_EN_STAT) { 22818c2ecf20Sopenharmony_ci netdev_info(dev, "Partner capability:"); 22828c2ecf20Sopenharmony_ci for (i = 5; i < 10; i++) 22838c2ecf20Sopenharmony_ci if (partner & (1 << i)) 22848c2ecf20Sopenharmony_ci pr_cont(" %s", 22858c2ecf20Sopenharmony_ci media[i-5]); 22868c2ecf20Sopenharmony_ci pr_cont("\n"); 22878c2ecf20Sopenharmony_ci } 22888c2ecf20Sopenharmony_ci } else 22898c2ecf20Sopenharmony_ci netdev_info(dev, "Link active\n"); 22908c2ecf20Sopenharmony_ci /* Enabling link beat monitoring */ 22918c2ecf20Sopenharmony_ci priv->media_timer.expires = jiffies + HZ; 22928c2ecf20Sopenharmony_ci add_timer(&priv->media_timer); 22938c2ecf20Sopenharmony_ci } 22948c2ecf20Sopenharmony_ci } 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_ci if (priv->phy_num == 0) { 22978c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, TLAN_TLPHY_CTL, &tlphy_ctl); 22988c2ecf20Sopenharmony_ci tlphy_ctl |= TLAN_TC_INTEN; 22998c2ecf20Sopenharmony_ci tlan_mii_write_reg(dev, phy, TLAN_TLPHY_CTL, tlphy_ctl); 23008c2ecf20Sopenharmony_ci sio = tlan_dio_read8(dev->base_addr, TLAN_NET_SIO); 23018c2ecf20Sopenharmony_ci sio |= TLAN_NET_SIO_MINTEN; 23028c2ecf20Sopenharmony_ci tlan_dio_write8(dev->base_addr, TLAN_NET_SIO, sio); 23038c2ecf20Sopenharmony_ci } 23048c2ecf20Sopenharmony_ci 23058c2ecf20Sopenharmony_ci if (status & MII_GS_LINK) { 23068c2ecf20Sopenharmony_ci tlan_set_mac(dev, 0, dev->dev_addr); 23078c2ecf20Sopenharmony_ci priv->phy_online = 1; 23088c2ecf20Sopenharmony_ci outb((TLAN_HC_INT_ON >> 8), dev->base_addr + TLAN_HOST_CMD + 1); 23098c2ecf20Sopenharmony_ci if (debug >= 1 && debug != TLAN_DEBUG_PROBE) 23108c2ecf20Sopenharmony_ci outb((TLAN_HC_REQ_INT >> 8), 23118c2ecf20Sopenharmony_ci dev->base_addr + TLAN_HOST_CMD + 1); 23128c2ecf20Sopenharmony_ci outl(priv->rx_list_dma, dev->base_addr + TLAN_CH_PARM); 23138c2ecf20Sopenharmony_ci outl(TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD); 23148c2ecf20Sopenharmony_ci tlan_dio_write8(dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK); 23158c2ecf20Sopenharmony_ci netif_carrier_on(dev); 23168c2ecf20Sopenharmony_ci } else { 23178c2ecf20Sopenharmony_ci netdev_info(dev, "Link inactive, will retry in 10 secs...\n"); 23188c2ecf20Sopenharmony_ci tlan_set_timer(dev, (10*HZ), TLAN_TIMER_FINISH_RESET); 23198c2ecf20Sopenharmony_ci return; 23208c2ecf20Sopenharmony_ci } 23218c2ecf20Sopenharmony_ci tlan_set_multicast_list(dev); 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci} 23248c2ecf20Sopenharmony_ci 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_ci/*************************************************************** 23298c2ecf20Sopenharmony_ci * tlan_set_mac 23308c2ecf20Sopenharmony_ci * 23318c2ecf20Sopenharmony_ci * Returns: 23328c2ecf20Sopenharmony_ci * Nothing 23338c2ecf20Sopenharmony_ci * Parms: 23348c2ecf20Sopenharmony_ci * dev Pointer to device structure of adapter 23358c2ecf20Sopenharmony_ci * on which to change the AREG. 23368c2ecf20Sopenharmony_ci * areg The AREG to set the address in (0 - 3). 23378c2ecf20Sopenharmony_ci * mac A pointer to an array of chars. Each 23388c2ecf20Sopenharmony_ci * element stores one byte of the address. 23398c2ecf20Sopenharmony_ci * IE, it isn't in ascii. 23408c2ecf20Sopenharmony_ci * 23418c2ecf20Sopenharmony_ci * This function transfers a MAC address to one of the 23428c2ecf20Sopenharmony_ci * TLAN AREGs (address registers). The TLAN chip locks 23438c2ecf20Sopenharmony_ci * the register on writing to offset 0 and unlocks the 23448c2ecf20Sopenharmony_ci * register after writing to offset 5. If NULL is passed 23458c2ecf20Sopenharmony_ci * in mac, then the AREG is filled with 0's. 23468c2ecf20Sopenharmony_ci * 23478c2ecf20Sopenharmony_ci **************************************************************/ 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_cistatic void tlan_set_mac(struct net_device *dev, int areg, char *mac) 23508c2ecf20Sopenharmony_ci{ 23518c2ecf20Sopenharmony_ci int i; 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_ci areg *= 6; 23548c2ecf20Sopenharmony_ci 23558c2ecf20Sopenharmony_ci if (mac != NULL) { 23568c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) 23578c2ecf20Sopenharmony_ci tlan_dio_write8(dev->base_addr, 23588c2ecf20Sopenharmony_ci TLAN_AREG_0 + areg + i, mac[i]); 23598c2ecf20Sopenharmony_ci } else { 23608c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) 23618c2ecf20Sopenharmony_ci tlan_dio_write8(dev->base_addr, 23628c2ecf20Sopenharmony_ci TLAN_AREG_0 + areg + i, 0); 23638c2ecf20Sopenharmony_ci } 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci} 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_ci/***************************************************************************** 23718c2ecf20Sopenharmony_ci****************************************************************************** 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ciThunderLAN driver PHY layer routines 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci****************************************************************************** 23768c2ecf20Sopenharmony_ci*****************************************************************************/ 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci/********************************************************************* 23818c2ecf20Sopenharmony_ci * tlan_phy_print 23828c2ecf20Sopenharmony_ci * 23838c2ecf20Sopenharmony_ci * Returns: 23848c2ecf20Sopenharmony_ci * Nothing 23858c2ecf20Sopenharmony_ci * Parms: 23868c2ecf20Sopenharmony_ci * dev A pointer to the device structure of the 23878c2ecf20Sopenharmony_ci * TLAN device having the PHYs to be detailed. 23888c2ecf20Sopenharmony_ci * 23898c2ecf20Sopenharmony_ci * This function prints the registers a PHY (aka transceiver). 23908c2ecf20Sopenharmony_ci * 23918c2ecf20Sopenharmony_ci ********************************************************************/ 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_cistatic void tlan_phy_print(struct net_device *dev) 23948c2ecf20Sopenharmony_ci{ 23958c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 23968c2ecf20Sopenharmony_ci u16 i, data0, data1, data2, data3, phy; 23978c2ecf20Sopenharmony_ci 23988c2ecf20Sopenharmony_ci phy = priv->phy[priv->phy_num]; 23998c2ecf20Sopenharmony_ci 24008c2ecf20Sopenharmony_ci if (priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY) { 24018c2ecf20Sopenharmony_ci netdev_info(dev, "Unmanaged PHY\n"); 24028c2ecf20Sopenharmony_ci } else if (phy <= TLAN_PHY_MAX_ADDR) { 24038c2ecf20Sopenharmony_ci netdev_info(dev, "PHY 0x%02x\n", phy); 24048c2ecf20Sopenharmony_ci pr_info(" Off. +0 +1 +2 +3\n"); 24058c2ecf20Sopenharmony_ci for (i = 0; i < 0x20; i += 4) { 24068c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, i, &data0); 24078c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, i + 1, &data1); 24088c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, i + 2, &data2); 24098c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, i + 3, &data3); 24108c2ecf20Sopenharmony_ci pr_info(" 0x%02x 0x%04hx 0x%04hx 0x%04hx 0x%04hx\n", 24118c2ecf20Sopenharmony_ci i, data0, data1, data2, data3); 24128c2ecf20Sopenharmony_ci } 24138c2ecf20Sopenharmony_ci } else { 24148c2ecf20Sopenharmony_ci netdev_info(dev, "Invalid PHY\n"); 24158c2ecf20Sopenharmony_ci } 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci} 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_ci 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_ci/********************************************************************* 24238c2ecf20Sopenharmony_ci * tlan_phy_detect 24248c2ecf20Sopenharmony_ci * 24258c2ecf20Sopenharmony_ci * Returns: 24268c2ecf20Sopenharmony_ci * Nothing 24278c2ecf20Sopenharmony_ci * Parms: 24288c2ecf20Sopenharmony_ci * dev A pointer to the device structure of the adapter 24298c2ecf20Sopenharmony_ci * for which the PHY needs determined. 24308c2ecf20Sopenharmony_ci * 24318c2ecf20Sopenharmony_ci * So far I've found that adapters which have external PHYs 24328c2ecf20Sopenharmony_ci * may also use the internal PHY for part of the functionality. 24338c2ecf20Sopenharmony_ci * (eg, AUI/Thinnet). This function finds out if this TLAN 24348c2ecf20Sopenharmony_ci * chip has an internal PHY, and then finds the first external 24358c2ecf20Sopenharmony_ci * PHY (starting from address 0) if it exists). 24368c2ecf20Sopenharmony_ci * 24378c2ecf20Sopenharmony_ci ********************************************************************/ 24388c2ecf20Sopenharmony_ci 24398c2ecf20Sopenharmony_cistatic void tlan_phy_detect(struct net_device *dev) 24408c2ecf20Sopenharmony_ci{ 24418c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 24428c2ecf20Sopenharmony_ci u16 control; 24438c2ecf20Sopenharmony_ci u16 hi; 24448c2ecf20Sopenharmony_ci u16 lo; 24458c2ecf20Sopenharmony_ci u32 phy; 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci if (priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY) { 24488c2ecf20Sopenharmony_ci priv->phy_num = 0xffff; 24498c2ecf20Sopenharmony_ci return; 24508c2ecf20Sopenharmony_ci } 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, TLAN_PHY_MAX_ADDR, MII_GEN_ID_HI, &hi); 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci if (hi != 0xffff) 24558c2ecf20Sopenharmony_ci priv->phy[0] = TLAN_PHY_MAX_ADDR; 24568c2ecf20Sopenharmony_ci else 24578c2ecf20Sopenharmony_ci priv->phy[0] = TLAN_PHY_NONE; 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_ci priv->phy[1] = TLAN_PHY_NONE; 24608c2ecf20Sopenharmony_ci for (phy = 0; phy <= TLAN_PHY_MAX_ADDR; phy++) { 24618c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, MII_GEN_CTL, &control); 24628c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, MII_GEN_ID_HI, &hi); 24638c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, MII_GEN_ID_LO, &lo); 24648c2ecf20Sopenharmony_ci if ((control != 0xffff) || 24658c2ecf20Sopenharmony_ci (hi != 0xffff) || (lo != 0xffff)) { 24668c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_GNRL, 24678c2ecf20Sopenharmony_ci "PHY found at %02x %04x %04x %04x\n", 24688c2ecf20Sopenharmony_ci phy, control, hi, lo); 24698c2ecf20Sopenharmony_ci if ((priv->phy[1] == TLAN_PHY_NONE) && 24708c2ecf20Sopenharmony_ci (phy != TLAN_PHY_MAX_ADDR)) { 24718c2ecf20Sopenharmony_ci priv->phy[1] = phy; 24728c2ecf20Sopenharmony_ci } 24738c2ecf20Sopenharmony_ci } 24748c2ecf20Sopenharmony_ci } 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_ci if (priv->phy[1] != TLAN_PHY_NONE) 24778c2ecf20Sopenharmony_ci priv->phy_num = 1; 24788c2ecf20Sopenharmony_ci else if (priv->phy[0] != TLAN_PHY_NONE) 24798c2ecf20Sopenharmony_ci priv->phy_num = 0; 24808c2ecf20Sopenharmony_ci else 24818c2ecf20Sopenharmony_ci netdev_info(dev, "Cannot initialize device, no PHY was found!\n"); 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci} 24848c2ecf20Sopenharmony_ci 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ci 24888c2ecf20Sopenharmony_cistatic void tlan_phy_power_down(struct net_device *dev) 24898c2ecf20Sopenharmony_ci{ 24908c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 24918c2ecf20Sopenharmony_ci u16 value; 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Powering down PHY(s).\n", dev->name); 24948c2ecf20Sopenharmony_ci value = MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE; 24958c2ecf20Sopenharmony_ci tlan_mii_sync(dev->base_addr); 24968c2ecf20Sopenharmony_ci tlan_mii_write_reg(dev, priv->phy[priv->phy_num], MII_GEN_CTL, value); 24978c2ecf20Sopenharmony_ci if ((priv->phy_num == 0) && (priv->phy[1] != TLAN_PHY_NONE)) { 24988c2ecf20Sopenharmony_ci /* if using internal PHY, the external PHY must be powered on */ 24998c2ecf20Sopenharmony_ci if (priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10) 25008c2ecf20Sopenharmony_ci value = MII_GC_ISOLATE; /* just isolate it from MII */ 25018c2ecf20Sopenharmony_ci tlan_mii_sync(dev->base_addr); 25028c2ecf20Sopenharmony_ci tlan_mii_write_reg(dev, priv->phy[1], MII_GEN_CTL, value); 25038c2ecf20Sopenharmony_ci } 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_ci /* Wait for 50 ms and powerup 25068c2ecf20Sopenharmony_ci * This is arbitrary. It is intended to make sure the 25078c2ecf20Sopenharmony_ci * transceiver settles. 25088c2ecf20Sopenharmony_ci */ 25098c2ecf20Sopenharmony_ci tlan_set_timer(dev, msecs_to_jiffies(50), TLAN_TIMER_PHY_PUP); 25108c2ecf20Sopenharmony_ci 25118c2ecf20Sopenharmony_ci} 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_ci 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_cistatic void tlan_phy_power_up(struct net_device *dev) 25178c2ecf20Sopenharmony_ci{ 25188c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 25198c2ecf20Sopenharmony_ci u16 value; 25208c2ecf20Sopenharmony_ci 25218c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Powering up PHY.\n", dev->name); 25228c2ecf20Sopenharmony_ci tlan_mii_sync(dev->base_addr); 25238c2ecf20Sopenharmony_ci value = MII_GC_LOOPBK; 25248c2ecf20Sopenharmony_ci tlan_mii_write_reg(dev, priv->phy[priv->phy_num], MII_GEN_CTL, value); 25258c2ecf20Sopenharmony_ci tlan_mii_sync(dev->base_addr); 25268c2ecf20Sopenharmony_ci /* Wait for 500 ms and reset the 25278c2ecf20Sopenharmony_ci * transceiver. The TLAN docs say both 50 ms and 25288c2ecf20Sopenharmony_ci * 500 ms, so do the longer, just in case. 25298c2ecf20Sopenharmony_ci */ 25308c2ecf20Sopenharmony_ci tlan_set_timer(dev, msecs_to_jiffies(500), TLAN_TIMER_PHY_RESET); 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci} 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci 25378c2ecf20Sopenharmony_cistatic void tlan_phy_reset(struct net_device *dev) 25388c2ecf20Sopenharmony_ci{ 25398c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 25408c2ecf20Sopenharmony_ci u16 phy; 25418c2ecf20Sopenharmony_ci u16 value; 25428c2ecf20Sopenharmony_ci unsigned long timeout = jiffies + HZ; 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ci phy = priv->phy[priv->phy_num]; 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Resetting PHY.\n", dev->name); 25478c2ecf20Sopenharmony_ci tlan_mii_sync(dev->base_addr); 25488c2ecf20Sopenharmony_ci value = MII_GC_LOOPBK | MII_GC_RESET; 25498c2ecf20Sopenharmony_ci tlan_mii_write_reg(dev, phy, MII_GEN_CTL, value); 25508c2ecf20Sopenharmony_ci do { 25518c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, MII_GEN_CTL, &value); 25528c2ecf20Sopenharmony_ci if (time_after(jiffies, timeout)) { 25538c2ecf20Sopenharmony_ci netdev_err(dev, "PHY reset timeout\n"); 25548c2ecf20Sopenharmony_ci return; 25558c2ecf20Sopenharmony_ci } 25568c2ecf20Sopenharmony_ci } while (value & MII_GC_RESET); 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_ci /* Wait for 500 ms and initialize. 25598c2ecf20Sopenharmony_ci * I don't remember why I wait this long. 25608c2ecf20Sopenharmony_ci * I've changed this to 50ms, as it seems long enough. 25618c2ecf20Sopenharmony_ci */ 25628c2ecf20Sopenharmony_ci tlan_set_timer(dev, msecs_to_jiffies(50), TLAN_TIMER_PHY_START_LINK); 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci} 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ci 25698c2ecf20Sopenharmony_cistatic void tlan_phy_start_link(struct net_device *dev) 25708c2ecf20Sopenharmony_ci{ 25718c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 25728c2ecf20Sopenharmony_ci u16 ability; 25738c2ecf20Sopenharmony_ci u16 control; 25748c2ecf20Sopenharmony_ci u16 data; 25758c2ecf20Sopenharmony_ci u16 phy; 25768c2ecf20Sopenharmony_ci u16 status; 25778c2ecf20Sopenharmony_ci u16 tctl; 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci phy = priv->phy[priv->phy_num]; 25808c2ecf20Sopenharmony_ci TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Trying to activate link.\n", dev->name); 25818c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, MII_GEN_STS, &status); 25828c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, MII_GEN_STS, &ability); 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci if ((status & MII_GS_AUTONEG) && 25858c2ecf20Sopenharmony_ci (!priv->aui)) { 25868c2ecf20Sopenharmony_ci ability = status >> 11; 25878c2ecf20Sopenharmony_ci if (priv->speed == TLAN_SPEED_10 && 25888c2ecf20Sopenharmony_ci priv->duplex == TLAN_DUPLEX_HALF) { 25898c2ecf20Sopenharmony_ci tlan_mii_write_reg(dev, phy, MII_GEN_CTL, 0x0000); 25908c2ecf20Sopenharmony_ci } else if (priv->speed == TLAN_SPEED_10 && 25918c2ecf20Sopenharmony_ci priv->duplex == TLAN_DUPLEX_FULL) { 25928c2ecf20Sopenharmony_ci priv->tlan_full_duplex = true; 25938c2ecf20Sopenharmony_ci tlan_mii_write_reg(dev, phy, MII_GEN_CTL, 0x0100); 25948c2ecf20Sopenharmony_ci } else if (priv->speed == TLAN_SPEED_100 && 25958c2ecf20Sopenharmony_ci priv->duplex == TLAN_DUPLEX_HALF) { 25968c2ecf20Sopenharmony_ci tlan_mii_write_reg(dev, phy, MII_GEN_CTL, 0x2000); 25978c2ecf20Sopenharmony_ci } else if (priv->speed == TLAN_SPEED_100 && 25988c2ecf20Sopenharmony_ci priv->duplex == TLAN_DUPLEX_FULL) { 25998c2ecf20Sopenharmony_ci priv->tlan_full_duplex = true; 26008c2ecf20Sopenharmony_ci tlan_mii_write_reg(dev, phy, MII_GEN_CTL, 0x2100); 26018c2ecf20Sopenharmony_ci } else { 26028c2ecf20Sopenharmony_ci 26038c2ecf20Sopenharmony_ci /* Set Auto-Neg advertisement */ 26048c2ecf20Sopenharmony_ci tlan_mii_write_reg(dev, phy, MII_AN_ADV, 26058c2ecf20Sopenharmony_ci (ability << 5) | 1); 26068c2ecf20Sopenharmony_ci /* Enablee Auto-Neg */ 26078c2ecf20Sopenharmony_ci tlan_mii_write_reg(dev, phy, MII_GEN_CTL, 0x1000); 26088c2ecf20Sopenharmony_ci /* Restart Auto-Neg */ 26098c2ecf20Sopenharmony_ci tlan_mii_write_reg(dev, phy, MII_GEN_CTL, 0x1200); 26108c2ecf20Sopenharmony_ci /* Wait for 4 sec for autonegotiation 26118c2ecf20Sopenharmony_ci * to complete. The max spec time is less than this 26128c2ecf20Sopenharmony_ci * but the card need additional time to start AN. 26138c2ecf20Sopenharmony_ci * .5 sec should be plenty extra. 26148c2ecf20Sopenharmony_ci */ 26158c2ecf20Sopenharmony_ci netdev_info(dev, "Starting autonegotiation\n"); 26168c2ecf20Sopenharmony_ci tlan_set_timer(dev, (2*HZ), TLAN_TIMER_PHY_FINISH_AN); 26178c2ecf20Sopenharmony_ci return; 26188c2ecf20Sopenharmony_ci } 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_ci } 26218c2ecf20Sopenharmony_ci 26228c2ecf20Sopenharmony_ci if ((priv->aui) && (priv->phy_num != 0)) { 26238c2ecf20Sopenharmony_ci priv->phy_num = 0; 26248c2ecf20Sopenharmony_ci data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN 26258c2ecf20Sopenharmony_ci | TLAN_NET_CFG_PHY_EN; 26268c2ecf20Sopenharmony_ci tlan_dio_write16(dev->base_addr, TLAN_NET_CONFIG, data); 26278c2ecf20Sopenharmony_ci tlan_set_timer(dev, msecs_to_jiffies(40), TLAN_TIMER_PHY_PDOWN); 26288c2ecf20Sopenharmony_ci return; 26298c2ecf20Sopenharmony_ci } else if (priv->phy_num == 0) { 26308c2ecf20Sopenharmony_ci control = 0; 26318c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, TLAN_TLPHY_CTL, &tctl); 26328c2ecf20Sopenharmony_ci if (priv->aui) { 26338c2ecf20Sopenharmony_ci tctl |= TLAN_TC_AUISEL; 26348c2ecf20Sopenharmony_ci } else { 26358c2ecf20Sopenharmony_ci tctl &= ~TLAN_TC_AUISEL; 26368c2ecf20Sopenharmony_ci if (priv->duplex == TLAN_DUPLEX_FULL) { 26378c2ecf20Sopenharmony_ci control |= MII_GC_DUPLEX; 26388c2ecf20Sopenharmony_ci priv->tlan_full_duplex = true; 26398c2ecf20Sopenharmony_ci } 26408c2ecf20Sopenharmony_ci if (priv->speed == TLAN_SPEED_100) 26418c2ecf20Sopenharmony_ci control |= MII_GC_SPEEDSEL; 26428c2ecf20Sopenharmony_ci } 26438c2ecf20Sopenharmony_ci tlan_mii_write_reg(dev, phy, MII_GEN_CTL, control); 26448c2ecf20Sopenharmony_ci tlan_mii_write_reg(dev, phy, TLAN_TLPHY_CTL, tctl); 26458c2ecf20Sopenharmony_ci } 26468c2ecf20Sopenharmony_ci 26478c2ecf20Sopenharmony_ci /* Wait for 2 sec to give the transceiver time 26488c2ecf20Sopenharmony_ci * to establish link. 26498c2ecf20Sopenharmony_ci */ 26508c2ecf20Sopenharmony_ci tlan_set_timer(dev, (4*HZ), TLAN_TIMER_FINISH_RESET); 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci} 26538c2ecf20Sopenharmony_ci 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ci 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_cistatic void tlan_phy_finish_auto_neg(struct net_device *dev) 26588c2ecf20Sopenharmony_ci{ 26598c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 26608c2ecf20Sopenharmony_ci u16 an_adv; 26618c2ecf20Sopenharmony_ci u16 an_lpa; 26628c2ecf20Sopenharmony_ci u16 mode; 26638c2ecf20Sopenharmony_ci u16 phy; 26648c2ecf20Sopenharmony_ci u16 status; 26658c2ecf20Sopenharmony_ci 26668c2ecf20Sopenharmony_ci phy = priv->phy[priv->phy_num]; 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, MII_GEN_STS, &status); 26698c2ecf20Sopenharmony_ci udelay(1000); 26708c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, MII_GEN_STS, &status); 26718c2ecf20Sopenharmony_ci 26728c2ecf20Sopenharmony_ci if (!(status & MII_GS_AUTOCMPLT)) { 26738c2ecf20Sopenharmony_ci /* Wait for 8 sec to give the process 26748c2ecf20Sopenharmony_ci * more time. Perhaps we should fail after a while. 26758c2ecf20Sopenharmony_ci */ 26768c2ecf20Sopenharmony_ci tlan_set_timer(dev, 2 * HZ, TLAN_TIMER_PHY_FINISH_AN); 26778c2ecf20Sopenharmony_ci return; 26788c2ecf20Sopenharmony_ci } 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_ci netdev_info(dev, "Autonegotiation complete\n"); 26818c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, MII_AN_ADV, &an_adv); 26828c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, MII_AN_LPA, &an_lpa); 26838c2ecf20Sopenharmony_ci mode = an_adv & an_lpa & 0x03E0; 26848c2ecf20Sopenharmony_ci if (mode & 0x0100) 26858c2ecf20Sopenharmony_ci priv->tlan_full_duplex = true; 26868c2ecf20Sopenharmony_ci else if (!(mode & 0x0080) && (mode & 0x0040)) 26878c2ecf20Sopenharmony_ci priv->tlan_full_duplex = true; 26888c2ecf20Sopenharmony_ci 26898c2ecf20Sopenharmony_ci /* switch to internal PHY for 10 Mbps */ 26908c2ecf20Sopenharmony_ci if ((!(mode & 0x0180)) && 26918c2ecf20Sopenharmony_ci (priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10) && 26928c2ecf20Sopenharmony_ci (priv->phy_num != 0)) { 26938c2ecf20Sopenharmony_ci priv->phy_num = 0; 26948c2ecf20Sopenharmony_ci tlan_set_timer(dev, msecs_to_jiffies(400), TLAN_TIMER_PHY_PDOWN); 26958c2ecf20Sopenharmony_ci return; 26968c2ecf20Sopenharmony_ci } 26978c2ecf20Sopenharmony_ci 26988c2ecf20Sopenharmony_ci if (priv->phy_num == 0) { 26998c2ecf20Sopenharmony_ci if ((priv->duplex == TLAN_DUPLEX_FULL) || 27008c2ecf20Sopenharmony_ci (an_adv & an_lpa & 0x0040)) { 27018c2ecf20Sopenharmony_ci tlan_mii_write_reg(dev, phy, MII_GEN_CTL, 27028c2ecf20Sopenharmony_ci MII_GC_AUTOENB | MII_GC_DUPLEX); 27038c2ecf20Sopenharmony_ci netdev_info(dev, "Starting internal PHY with FULL-DUPLEX\n"); 27048c2ecf20Sopenharmony_ci } else { 27058c2ecf20Sopenharmony_ci tlan_mii_write_reg(dev, phy, MII_GEN_CTL, 27068c2ecf20Sopenharmony_ci MII_GC_AUTOENB); 27078c2ecf20Sopenharmony_ci netdev_info(dev, "Starting internal PHY with HALF-DUPLEX\n"); 27088c2ecf20Sopenharmony_ci } 27098c2ecf20Sopenharmony_ci } 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_ci /* Wait for 100 ms. No reason in partiticular. 27128c2ecf20Sopenharmony_ci */ 27138c2ecf20Sopenharmony_ci tlan_set_timer(dev, msecs_to_jiffies(100), TLAN_TIMER_FINISH_RESET); 27148c2ecf20Sopenharmony_ci 27158c2ecf20Sopenharmony_ci} 27168c2ecf20Sopenharmony_ci 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_ci/********************************************************************* 27198c2ecf20Sopenharmony_ci * 27208c2ecf20Sopenharmony_ci * tlan_phy_monitor 27218c2ecf20Sopenharmony_ci * 27228c2ecf20Sopenharmony_ci * Returns: 27238c2ecf20Sopenharmony_ci * None 27248c2ecf20Sopenharmony_ci * 27258c2ecf20Sopenharmony_ci * Params: 27268c2ecf20Sopenharmony_ci * data The device structure of this device. 27278c2ecf20Sopenharmony_ci * 27288c2ecf20Sopenharmony_ci * 27298c2ecf20Sopenharmony_ci * This function monitors PHY condition by reading the status 27308c2ecf20Sopenharmony_ci * register via the MII bus, controls LINK LED and notifies the 27318c2ecf20Sopenharmony_ci * kernel about link state. 27328c2ecf20Sopenharmony_ci * 27338c2ecf20Sopenharmony_ci *******************************************************************/ 27348c2ecf20Sopenharmony_ci 27358c2ecf20Sopenharmony_cistatic void tlan_phy_monitor(struct timer_list *t) 27368c2ecf20Sopenharmony_ci{ 27378c2ecf20Sopenharmony_ci struct tlan_priv *priv = from_timer(priv, t, media_timer); 27388c2ecf20Sopenharmony_ci struct net_device *dev = priv->dev; 27398c2ecf20Sopenharmony_ci u16 phy; 27408c2ecf20Sopenharmony_ci u16 phy_status; 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_ci phy = priv->phy[priv->phy_num]; 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci /* Get PHY status register */ 27458c2ecf20Sopenharmony_ci tlan_mii_read_reg(dev, phy, MII_GEN_STS, &phy_status); 27468c2ecf20Sopenharmony_ci 27478c2ecf20Sopenharmony_ci /* Check if link has been lost */ 27488c2ecf20Sopenharmony_ci if (!(phy_status & MII_GS_LINK)) { 27498c2ecf20Sopenharmony_ci if (netif_carrier_ok(dev)) { 27508c2ecf20Sopenharmony_ci printk(KERN_DEBUG "TLAN: %s has lost link\n", 27518c2ecf20Sopenharmony_ci dev->name); 27528c2ecf20Sopenharmony_ci tlan_dio_write8(dev->base_addr, TLAN_LED_REG, 0); 27538c2ecf20Sopenharmony_ci netif_carrier_off(dev); 27548c2ecf20Sopenharmony_ci if (priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10) { 27558c2ecf20Sopenharmony_ci /* power down internal PHY */ 27568c2ecf20Sopenharmony_ci u16 data = MII_GC_PDOWN | MII_GC_LOOPBK | 27578c2ecf20Sopenharmony_ci MII_GC_ISOLATE; 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_ci tlan_mii_sync(dev->base_addr); 27608c2ecf20Sopenharmony_ci tlan_mii_write_reg(dev, priv->phy[0], 27618c2ecf20Sopenharmony_ci MII_GEN_CTL, data); 27628c2ecf20Sopenharmony_ci /* set to external PHY */ 27638c2ecf20Sopenharmony_ci priv->phy_num = 1; 27648c2ecf20Sopenharmony_ci /* restart autonegotiation */ 27658c2ecf20Sopenharmony_ci tlan_set_timer(dev, msecs_to_jiffies(400), 27668c2ecf20Sopenharmony_ci TLAN_TIMER_PHY_PDOWN); 27678c2ecf20Sopenharmony_ci return; 27688c2ecf20Sopenharmony_ci } 27698c2ecf20Sopenharmony_ci } 27708c2ecf20Sopenharmony_ci } 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_ci /* Link restablished? */ 27738c2ecf20Sopenharmony_ci if ((phy_status & MII_GS_LINK) && !netif_carrier_ok(dev)) { 27748c2ecf20Sopenharmony_ci tlan_dio_write8(dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK); 27758c2ecf20Sopenharmony_ci printk(KERN_DEBUG "TLAN: %s has reestablished link\n", 27768c2ecf20Sopenharmony_ci dev->name); 27778c2ecf20Sopenharmony_ci netif_carrier_on(dev); 27788c2ecf20Sopenharmony_ci } 27798c2ecf20Sopenharmony_ci priv->media_timer.expires = jiffies + HZ; 27808c2ecf20Sopenharmony_ci add_timer(&priv->media_timer); 27818c2ecf20Sopenharmony_ci} 27828c2ecf20Sopenharmony_ci 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci/***************************************************************************** 27858c2ecf20Sopenharmony_ci****************************************************************************** 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_ciThunderLAN driver MII routines 27888c2ecf20Sopenharmony_ci 27898c2ecf20Sopenharmony_cithese routines are based on the information in chap. 2 of the 27908c2ecf20Sopenharmony_ci"ThunderLAN Programmer's Guide", pp. 15-24. 27918c2ecf20Sopenharmony_ci 27928c2ecf20Sopenharmony_ci****************************************************************************** 27938c2ecf20Sopenharmony_ci*****************************************************************************/ 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_ci 27968c2ecf20Sopenharmony_ci/*************************************************************** 27978c2ecf20Sopenharmony_ci * tlan_mii_read_reg 27988c2ecf20Sopenharmony_ci * 27998c2ecf20Sopenharmony_ci * Returns: 28008c2ecf20Sopenharmony_ci * false if ack received ok 28018c2ecf20Sopenharmony_ci * true if no ack received or other error 28028c2ecf20Sopenharmony_ci * 28038c2ecf20Sopenharmony_ci * Parms: 28048c2ecf20Sopenharmony_ci * dev The device structure containing 28058c2ecf20Sopenharmony_ci * The io address and interrupt count 28068c2ecf20Sopenharmony_ci * for this device. 28078c2ecf20Sopenharmony_ci * phy The address of the PHY to be queried. 28088c2ecf20Sopenharmony_ci * reg The register whose contents are to be 28098c2ecf20Sopenharmony_ci * retrieved. 28108c2ecf20Sopenharmony_ci * val A pointer to a variable to store the 28118c2ecf20Sopenharmony_ci * retrieved value. 28128c2ecf20Sopenharmony_ci * 28138c2ecf20Sopenharmony_ci * This function uses the TLAN's MII bus to retrieve the contents 28148c2ecf20Sopenharmony_ci * of a given register on a PHY. It sends the appropriate info 28158c2ecf20Sopenharmony_ci * and then reads the 16-bit register value from the MII bus via 28168c2ecf20Sopenharmony_ci * the TLAN SIO register. 28178c2ecf20Sopenharmony_ci * 28188c2ecf20Sopenharmony_ci **************************************************************/ 28198c2ecf20Sopenharmony_ci 28208c2ecf20Sopenharmony_cistatic bool 28218c2ecf20Sopenharmony_citlan_mii_read_reg(struct net_device *dev, u16 phy, u16 reg, u16 *val) 28228c2ecf20Sopenharmony_ci{ 28238c2ecf20Sopenharmony_ci u8 nack; 28248c2ecf20Sopenharmony_ci u16 sio, tmp; 28258c2ecf20Sopenharmony_ci u32 i; 28268c2ecf20Sopenharmony_ci bool err; 28278c2ecf20Sopenharmony_ci int minten; 28288c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 28298c2ecf20Sopenharmony_ci unsigned long flags = 0; 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci err = false; 28328c2ecf20Sopenharmony_ci outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR); 28338c2ecf20Sopenharmony_ci sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; 28348c2ecf20Sopenharmony_ci 28358c2ecf20Sopenharmony_ci if (!in_irq()) 28368c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 28378c2ecf20Sopenharmony_ci 28388c2ecf20Sopenharmony_ci tlan_mii_sync(dev->base_addr); 28398c2ecf20Sopenharmony_ci 28408c2ecf20Sopenharmony_ci minten = tlan_get_bit(TLAN_NET_SIO_MINTEN, sio); 28418c2ecf20Sopenharmony_ci if (minten) 28428c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_MINTEN, sio); 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_ci tlan_mii_send_data(dev->base_addr, 0x1, 2); /* start (01b) */ 28458c2ecf20Sopenharmony_ci tlan_mii_send_data(dev->base_addr, 0x2, 2); /* read (10b) */ 28468c2ecf20Sopenharmony_ci tlan_mii_send_data(dev->base_addr, phy, 5); /* device # */ 28478c2ecf20Sopenharmony_ci tlan_mii_send_data(dev->base_addr, reg, 5); /* register # */ 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_MTXEN, sio); /* change direction */ 28518c2ecf20Sopenharmony_ci 28528c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_MCLK, sio); /* clock idle bit */ 28538c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_MCLK, sio); 28548c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_MCLK, sio); /* wait 300ns */ 28558c2ecf20Sopenharmony_ci 28568c2ecf20Sopenharmony_ci nack = tlan_get_bit(TLAN_NET_SIO_MDATA, sio); /* check for ACK */ 28578c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_MCLK, sio); /* finish ACK */ 28588c2ecf20Sopenharmony_ci if (nack) { /* no ACK, so fake it */ 28598c2ecf20Sopenharmony_ci for (i = 0; i < 16; i++) { 28608c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_MCLK, sio); 28618c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_MCLK, sio); 28628c2ecf20Sopenharmony_ci } 28638c2ecf20Sopenharmony_ci tmp = 0xffff; 28648c2ecf20Sopenharmony_ci err = true; 28658c2ecf20Sopenharmony_ci } else { /* ACK, so read data */ 28668c2ecf20Sopenharmony_ci for (tmp = 0, i = 0x8000; i; i >>= 1) { 28678c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_MCLK, sio); 28688c2ecf20Sopenharmony_ci if (tlan_get_bit(TLAN_NET_SIO_MDATA, sio)) 28698c2ecf20Sopenharmony_ci tmp |= i; 28708c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_MCLK, sio); 28718c2ecf20Sopenharmony_ci } 28728c2ecf20Sopenharmony_ci } 28738c2ecf20Sopenharmony_ci 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_MCLK, sio); /* idle cycle */ 28768c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_MCLK, sio); 28778c2ecf20Sopenharmony_ci 28788c2ecf20Sopenharmony_ci if (minten) 28798c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_MINTEN, sio); 28808c2ecf20Sopenharmony_ci 28818c2ecf20Sopenharmony_ci *val = tmp; 28828c2ecf20Sopenharmony_ci 28838c2ecf20Sopenharmony_ci if (!in_irq()) 28848c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_ci return err; 28878c2ecf20Sopenharmony_ci 28888c2ecf20Sopenharmony_ci} 28898c2ecf20Sopenharmony_ci 28908c2ecf20Sopenharmony_ci 28918c2ecf20Sopenharmony_ci 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_ci/*************************************************************** 28948c2ecf20Sopenharmony_ci * tlan_mii_send_data 28958c2ecf20Sopenharmony_ci * 28968c2ecf20Sopenharmony_ci * Returns: 28978c2ecf20Sopenharmony_ci * Nothing 28988c2ecf20Sopenharmony_ci * Parms: 28998c2ecf20Sopenharmony_ci * base_port The base IO port of the adapter in 29008c2ecf20Sopenharmony_ci * question. 29018c2ecf20Sopenharmony_ci * dev The address of the PHY to be queried. 29028c2ecf20Sopenharmony_ci * data The value to be placed on the MII bus. 29038c2ecf20Sopenharmony_ci * num_bits The number of bits in data that are to 29048c2ecf20Sopenharmony_ci * be placed on the MII bus. 29058c2ecf20Sopenharmony_ci * 29068c2ecf20Sopenharmony_ci * This function sends on sequence of bits on the MII 29078c2ecf20Sopenharmony_ci * configuration bus. 29088c2ecf20Sopenharmony_ci * 29098c2ecf20Sopenharmony_ci **************************************************************/ 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_cistatic void tlan_mii_send_data(u16 base_port, u32 data, unsigned num_bits) 29128c2ecf20Sopenharmony_ci{ 29138c2ecf20Sopenharmony_ci u16 sio; 29148c2ecf20Sopenharmony_ci u32 i; 29158c2ecf20Sopenharmony_ci 29168c2ecf20Sopenharmony_ci if (num_bits == 0) 29178c2ecf20Sopenharmony_ci return; 29188c2ecf20Sopenharmony_ci 29198c2ecf20Sopenharmony_ci outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR); 29208c2ecf20Sopenharmony_ci sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO; 29218c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_MTXEN, sio); 29228c2ecf20Sopenharmony_ci 29238c2ecf20Sopenharmony_ci for (i = (0x1 << (num_bits - 1)); i; i >>= 1) { 29248c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_MCLK, sio); 29258c2ecf20Sopenharmony_ci (void) tlan_get_bit(TLAN_NET_SIO_MCLK, sio); 29268c2ecf20Sopenharmony_ci if (data & i) 29278c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_MDATA, sio); 29288c2ecf20Sopenharmony_ci else 29298c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_MDATA, sio); 29308c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_MCLK, sio); 29318c2ecf20Sopenharmony_ci (void) tlan_get_bit(TLAN_NET_SIO_MCLK, sio); 29328c2ecf20Sopenharmony_ci } 29338c2ecf20Sopenharmony_ci 29348c2ecf20Sopenharmony_ci} 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_ci 29378c2ecf20Sopenharmony_ci 29388c2ecf20Sopenharmony_ci 29398c2ecf20Sopenharmony_ci/*************************************************************** 29408c2ecf20Sopenharmony_ci * TLan_MiiSync 29418c2ecf20Sopenharmony_ci * 29428c2ecf20Sopenharmony_ci * Returns: 29438c2ecf20Sopenharmony_ci * Nothing 29448c2ecf20Sopenharmony_ci * Parms: 29458c2ecf20Sopenharmony_ci * base_port The base IO port of the adapter in 29468c2ecf20Sopenharmony_ci * question. 29478c2ecf20Sopenharmony_ci * 29488c2ecf20Sopenharmony_ci * This functions syncs all PHYs in terms of the MII configuration 29498c2ecf20Sopenharmony_ci * bus. 29508c2ecf20Sopenharmony_ci * 29518c2ecf20Sopenharmony_ci **************************************************************/ 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_cistatic void tlan_mii_sync(u16 base_port) 29548c2ecf20Sopenharmony_ci{ 29558c2ecf20Sopenharmony_ci int i; 29568c2ecf20Sopenharmony_ci u16 sio; 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_ci outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR); 29598c2ecf20Sopenharmony_ci sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO; 29608c2ecf20Sopenharmony_ci 29618c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_MTXEN, sio); 29628c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) { 29638c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_MCLK, sio); 29648c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_MCLK, sio); 29658c2ecf20Sopenharmony_ci } 29668c2ecf20Sopenharmony_ci 29678c2ecf20Sopenharmony_ci} 29688c2ecf20Sopenharmony_ci 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci 29718c2ecf20Sopenharmony_ci 29728c2ecf20Sopenharmony_ci/*************************************************************** 29738c2ecf20Sopenharmony_ci * tlan_mii_write_reg 29748c2ecf20Sopenharmony_ci * 29758c2ecf20Sopenharmony_ci * Returns: 29768c2ecf20Sopenharmony_ci * Nothing 29778c2ecf20Sopenharmony_ci * Parms: 29788c2ecf20Sopenharmony_ci * dev The device structure for the device 29798c2ecf20Sopenharmony_ci * to write to. 29808c2ecf20Sopenharmony_ci * phy The address of the PHY to be written to. 29818c2ecf20Sopenharmony_ci * reg The register whose contents are to be 29828c2ecf20Sopenharmony_ci * written. 29838c2ecf20Sopenharmony_ci * val The value to be written to the register. 29848c2ecf20Sopenharmony_ci * 29858c2ecf20Sopenharmony_ci * This function uses the TLAN's MII bus to write the contents of a 29868c2ecf20Sopenharmony_ci * given register on a PHY. It sends the appropriate info and then 29878c2ecf20Sopenharmony_ci * writes the 16-bit register value from the MII configuration bus 29888c2ecf20Sopenharmony_ci * via the TLAN SIO register. 29898c2ecf20Sopenharmony_ci * 29908c2ecf20Sopenharmony_ci **************************************************************/ 29918c2ecf20Sopenharmony_ci 29928c2ecf20Sopenharmony_cistatic void 29938c2ecf20Sopenharmony_citlan_mii_write_reg(struct net_device *dev, u16 phy, u16 reg, u16 val) 29948c2ecf20Sopenharmony_ci{ 29958c2ecf20Sopenharmony_ci u16 sio; 29968c2ecf20Sopenharmony_ci int minten; 29978c2ecf20Sopenharmony_ci unsigned long flags = 0; 29988c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 29998c2ecf20Sopenharmony_ci 30008c2ecf20Sopenharmony_ci outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR); 30018c2ecf20Sopenharmony_ci sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO; 30028c2ecf20Sopenharmony_ci 30038c2ecf20Sopenharmony_ci if (!in_irq()) 30048c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_ci tlan_mii_sync(dev->base_addr); 30078c2ecf20Sopenharmony_ci 30088c2ecf20Sopenharmony_ci minten = tlan_get_bit(TLAN_NET_SIO_MINTEN, sio); 30098c2ecf20Sopenharmony_ci if (minten) 30108c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_MINTEN, sio); 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_ci tlan_mii_send_data(dev->base_addr, 0x1, 2); /* start (01b) */ 30138c2ecf20Sopenharmony_ci tlan_mii_send_data(dev->base_addr, 0x1, 2); /* write (01b) */ 30148c2ecf20Sopenharmony_ci tlan_mii_send_data(dev->base_addr, phy, 5); /* device # */ 30158c2ecf20Sopenharmony_ci tlan_mii_send_data(dev->base_addr, reg, 5); /* register # */ 30168c2ecf20Sopenharmony_ci 30178c2ecf20Sopenharmony_ci tlan_mii_send_data(dev->base_addr, 0x2, 2); /* send ACK */ 30188c2ecf20Sopenharmony_ci tlan_mii_send_data(dev->base_addr, val, 16); /* send data */ 30198c2ecf20Sopenharmony_ci 30208c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_MCLK, sio); /* idle cycle */ 30218c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_MCLK, sio); 30228c2ecf20Sopenharmony_ci 30238c2ecf20Sopenharmony_ci if (minten) 30248c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_MINTEN, sio); 30258c2ecf20Sopenharmony_ci 30268c2ecf20Sopenharmony_ci if (!in_irq()) 30278c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci} 30308c2ecf20Sopenharmony_ci 30318c2ecf20Sopenharmony_ci 30328c2ecf20Sopenharmony_ci 30338c2ecf20Sopenharmony_ci 30348c2ecf20Sopenharmony_ci/***************************************************************************** 30358c2ecf20Sopenharmony_ci****************************************************************************** 30368c2ecf20Sopenharmony_ci 30378c2ecf20Sopenharmony_ciThunderLAN driver eeprom routines 30388c2ecf20Sopenharmony_ci 30398c2ecf20Sopenharmony_cithe Compaq netelligent 10 and 10/100 cards use a microchip 24C02A 30408c2ecf20Sopenharmony_ciEEPROM. these functions are based on information in microchip's 30418c2ecf20Sopenharmony_cidata sheet. I don't know how well this functions will work with 30428c2ecf20Sopenharmony_ciother Eeproms. 30438c2ecf20Sopenharmony_ci 30448c2ecf20Sopenharmony_ci****************************************************************************** 30458c2ecf20Sopenharmony_ci*****************************************************************************/ 30468c2ecf20Sopenharmony_ci 30478c2ecf20Sopenharmony_ci 30488c2ecf20Sopenharmony_ci/*************************************************************** 30498c2ecf20Sopenharmony_ci * tlan_ee_send_start 30508c2ecf20Sopenharmony_ci * 30518c2ecf20Sopenharmony_ci * Returns: 30528c2ecf20Sopenharmony_ci * Nothing 30538c2ecf20Sopenharmony_ci * Parms: 30548c2ecf20Sopenharmony_ci * io_base The IO port base address for the 30558c2ecf20Sopenharmony_ci * TLAN device with the EEPROM to 30568c2ecf20Sopenharmony_ci * use. 30578c2ecf20Sopenharmony_ci * 30588c2ecf20Sopenharmony_ci * This function sends a start cycle to an EEPROM attached 30598c2ecf20Sopenharmony_ci * to a TLAN chip. 30608c2ecf20Sopenharmony_ci * 30618c2ecf20Sopenharmony_ci **************************************************************/ 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_cistatic void tlan_ee_send_start(u16 io_base) 30648c2ecf20Sopenharmony_ci{ 30658c2ecf20Sopenharmony_ci u16 sio; 30668c2ecf20Sopenharmony_ci 30678c2ecf20Sopenharmony_ci outw(TLAN_NET_SIO, io_base + TLAN_DIO_ADR); 30688c2ecf20Sopenharmony_ci sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_ECLOK, sio); 30718c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_EDATA, sio); 30728c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_ETXEN, sio); 30738c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_EDATA, sio); 30748c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_ECLOK, sio); 30758c2ecf20Sopenharmony_ci 30768c2ecf20Sopenharmony_ci} 30778c2ecf20Sopenharmony_ci 30788c2ecf20Sopenharmony_ci 30798c2ecf20Sopenharmony_ci 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_ci/*************************************************************** 30828c2ecf20Sopenharmony_ci * tlan_ee_send_byte 30838c2ecf20Sopenharmony_ci * 30848c2ecf20Sopenharmony_ci * Returns: 30858c2ecf20Sopenharmony_ci * If the correct ack was received, 0, otherwise 1 30868c2ecf20Sopenharmony_ci * Parms: io_base The IO port base address for the 30878c2ecf20Sopenharmony_ci * TLAN device with the EEPROM to 30888c2ecf20Sopenharmony_ci * use. 30898c2ecf20Sopenharmony_ci * data The 8 bits of information to 30908c2ecf20Sopenharmony_ci * send to the EEPROM. 30918c2ecf20Sopenharmony_ci * stop If TLAN_EEPROM_STOP is passed, a 30928c2ecf20Sopenharmony_ci * stop cycle is sent after the 30938c2ecf20Sopenharmony_ci * byte is sent after the ack is 30948c2ecf20Sopenharmony_ci * read. 30958c2ecf20Sopenharmony_ci * 30968c2ecf20Sopenharmony_ci * This function sends a byte on the serial EEPROM line, 30978c2ecf20Sopenharmony_ci * driving the clock to send each bit. The function then 30988c2ecf20Sopenharmony_ci * reverses transmission direction and reads an acknowledge 30998c2ecf20Sopenharmony_ci * bit. 31008c2ecf20Sopenharmony_ci * 31018c2ecf20Sopenharmony_ci **************************************************************/ 31028c2ecf20Sopenharmony_ci 31038c2ecf20Sopenharmony_cistatic int tlan_ee_send_byte(u16 io_base, u8 data, int stop) 31048c2ecf20Sopenharmony_ci{ 31058c2ecf20Sopenharmony_ci int err; 31068c2ecf20Sopenharmony_ci u8 place; 31078c2ecf20Sopenharmony_ci u16 sio; 31088c2ecf20Sopenharmony_ci 31098c2ecf20Sopenharmony_ci outw(TLAN_NET_SIO, io_base + TLAN_DIO_ADR); 31108c2ecf20Sopenharmony_ci sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_ci /* Assume clock is low, tx is enabled; */ 31138c2ecf20Sopenharmony_ci for (place = 0x80; place != 0; place >>= 1) { 31148c2ecf20Sopenharmony_ci if (place & data) 31158c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_EDATA, sio); 31168c2ecf20Sopenharmony_ci else 31178c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_EDATA, sio); 31188c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_ECLOK, sio); 31198c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_ECLOK, sio); 31208c2ecf20Sopenharmony_ci } 31218c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_ETXEN, sio); 31228c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_ECLOK, sio); 31238c2ecf20Sopenharmony_ci err = tlan_get_bit(TLAN_NET_SIO_EDATA, sio); 31248c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_ECLOK, sio); 31258c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_ETXEN, sio); 31268c2ecf20Sopenharmony_ci 31278c2ecf20Sopenharmony_ci if ((!err) && stop) { 31288c2ecf20Sopenharmony_ci /* STOP, raise data while clock is high */ 31298c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_EDATA, sio); 31308c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_ECLOK, sio); 31318c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_EDATA, sio); 31328c2ecf20Sopenharmony_ci } 31338c2ecf20Sopenharmony_ci 31348c2ecf20Sopenharmony_ci return err; 31358c2ecf20Sopenharmony_ci 31368c2ecf20Sopenharmony_ci} 31378c2ecf20Sopenharmony_ci 31388c2ecf20Sopenharmony_ci 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_ci/*************************************************************** 31428c2ecf20Sopenharmony_ci * tlan_ee_receive_byte 31438c2ecf20Sopenharmony_ci * 31448c2ecf20Sopenharmony_ci * Returns: 31458c2ecf20Sopenharmony_ci * Nothing 31468c2ecf20Sopenharmony_ci * Parms: 31478c2ecf20Sopenharmony_ci * io_base The IO port base address for the 31488c2ecf20Sopenharmony_ci * TLAN device with the EEPROM to 31498c2ecf20Sopenharmony_ci * use. 31508c2ecf20Sopenharmony_ci * data An address to a char to hold the 31518c2ecf20Sopenharmony_ci * data sent from the EEPROM. 31528c2ecf20Sopenharmony_ci * stop If TLAN_EEPROM_STOP is passed, a 31538c2ecf20Sopenharmony_ci * stop cycle is sent after the 31548c2ecf20Sopenharmony_ci * byte is received, and no ack is 31558c2ecf20Sopenharmony_ci * sent. 31568c2ecf20Sopenharmony_ci * 31578c2ecf20Sopenharmony_ci * This function receives 8 bits of data from the EEPROM 31588c2ecf20Sopenharmony_ci * over the serial link. It then sends and ack bit, or no 31598c2ecf20Sopenharmony_ci * ack and a stop bit. This function is used to retrieve 31608c2ecf20Sopenharmony_ci * data after the address of a byte in the EEPROM has been 31618c2ecf20Sopenharmony_ci * sent. 31628c2ecf20Sopenharmony_ci * 31638c2ecf20Sopenharmony_ci **************************************************************/ 31648c2ecf20Sopenharmony_ci 31658c2ecf20Sopenharmony_cistatic void tlan_ee_receive_byte(u16 io_base, u8 *data, int stop) 31668c2ecf20Sopenharmony_ci{ 31678c2ecf20Sopenharmony_ci u8 place; 31688c2ecf20Sopenharmony_ci u16 sio; 31698c2ecf20Sopenharmony_ci 31708c2ecf20Sopenharmony_ci outw(TLAN_NET_SIO, io_base + TLAN_DIO_ADR); 31718c2ecf20Sopenharmony_ci sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; 31728c2ecf20Sopenharmony_ci *data = 0; 31738c2ecf20Sopenharmony_ci 31748c2ecf20Sopenharmony_ci /* Assume clock is low, tx is enabled; */ 31758c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_ETXEN, sio); 31768c2ecf20Sopenharmony_ci for (place = 0x80; place; place >>= 1) { 31778c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_ECLOK, sio); 31788c2ecf20Sopenharmony_ci if (tlan_get_bit(TLAN_NET_SIO_EDATA, sio)) 31798c2ecf20Sopenharmony_ci *data |= place; 31808c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_ECLOK, sio); 31818c2ecf20Sopenharmony_ci } 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_ETXEN, sio); 31848c2ecf20Sopenharmony_ci if (!stop) { 31858c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_EDATA, sio); /* ack = 0 */ 31868c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_ECLOK, sio); 31878c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_ECLOK, sio); 31888c2ecf20Sopenharmony_ci } else { 31898c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_EDATA, sio); /* no ack = 1 (?) */ 31908c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_ECLOK, sio); 31918c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_ECLOK, sio); 31928c2ecf20Sopenharmony_ci /* STOP, raise data while clock is high */ 31938c2ecf20Sopenharmony_ci tlan_clear_bit(TLAN_NET_SIO_EDATA, sio); 31948c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_ECLOK, sio); 31958c2ecf20Sopenharmony_ci tlan_set_bit(TLAN_NET_SIO_EDATA, sio); 31968c2ecf20Sopenharmony_ci } 31978c2ecf20Sopenharmony_ci 31988c2ecf20Sopenharmony_ci} 31998c2ecf20Sopenharmony_ci 32008c2ecf20Sopenharmony_ci 32018c2ecf20Sopenharmony_ci 32028c2ecf20Sopenharmony_ci 32038c2ecf20Sopenharmony_ci/*************************************************************** 32048c2ecf20Sopenharmony_ci * tlan_ee_read_byte 32058c2ecf20Sopenharmony_ci * 32068c2ecf20Sopenharmony_ci * Returns: 32078c2ecf20Sopenharmony_ci * No error = 0, else, the stage at which the error 32088c2ecf20Sopenharmony_ci * occurred. 32098c2ecf20Sopenharmony_ci * Parms: 32108c2ecf20Sopenharmony_ci * io_base The IO port base address for the 32118c2ecf20Sopenharmony_ci * TLAN device with the EEPROM to 32128c2ecf20Sopenharmony_ci * use. 32138c2ecf20Sopenharmony_ci * ee_addr The address of the byte in the 32148c2ecf20Sopenharmony_ci * EEPROM whose contents are to be 32158c2ecf20Sopenharmony_ci * retrieved. 32168c2ecf20Sopenharmony_ci * data An address to a char to hold the 32178c2ecf20Sopenharmony_ci * data obtained from the EEPROM. 32188c2ecf20Sopenharmony_ci * 32198c2ecf20Sopenharmony_ci * This function reads a byte of information from an byte 32208c2ecf20Sopenharmony_ci * cell in the EEPROM. 32218c2ecf20Sopenharmony_ci * 32228c2ecf20Sopenharmony_ci **************************************************************/ 32238c2ecf20Sopenharmony_ci 32248c2ecf20Sopenharmony_cistatic int tlan_ee_read_byte(struct net_device *dev, u8 ee_addr, u8 *data) 32258c2ecf20Sopenharmony_ci{ 32268c2ecf20Sopenharmony_ci int err; 32278c2ecf20Sopenharmony_ci struct tlan_priv *priv = netdev_priv(dev); 32288c2ecf20Sopenharmony_ci unsigned long flags = 0; 32298c2ecf20Sopenharmony_ci int ret = 0; 32308c2ecf20Sopenharmony_ci 32318c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 32328c2ecf20Sopenharmony_ci 32338c2ecf20Sopenharmony_ci tlan_ee_send_start(dev->base_addr); 32348c2ecf20Sopenharmony_ci err = tlan_ee_send_byte(dev->base_addr, 0xa0, TLAN_EEPROM_ACK); 32358c2ecf20Sopenharmony_ci if (err) { 32368c2ecf20Sopenharmony_ci ret = 1; 32378c2ecf20Sopenharmony_ci goto fail; 32388c2ecf20Sopenharmony_ci } 32398c2ecf20Sopenharmony_ci err = tlan_ee_send_byte(dev->base_addr, ee_addr, TLAN_EEPROM_ACK); 32408c2ecf20Sopenharmony_ci if (err) { 32418c2ecf20Sopenharmony_ci ret = 2; 32428c2ecf20Sopenharmony_ci goto fail; 32438c2ecf20Sopenharmony_ci } 32448c2ecf20Sopenharmony_ci tlan_ee_send_start(dev->base_addr); 32458c2ecf20Sopenharmony_ci err = tlan_ee_send_byte(dev->base_addr, 0xa1, TLAN_EEPROM_ACK); 32468c2ecf20Sopenharmony_ci if (err) { 32478c2ecf20Sopenharmony_ci ret = 3; 32488c2ecf20Sopenharmony_ci goto fail; 32498c2ecf20Sopenharmony_ci } 32508c2ecf20Sopenharmony_ci tlan_ee_receive_byte(dev->base_addr, data, TLAN_EEPROM_STOP); 32518c2ecf20Sopenharmony_cifail: 32528c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 32538c2ecf20Sopenharmony_ci 32548c2ecf20Sopenharmony_ci return ret; 32558c2ecf20Sopenharmony_ci 32568c2ecf20Sopenharmony_ci} 32578c2ecf20Sopenharmony_ci 32588c2ecf20Sopenharmony_ci 32598c2ecf20Sopenharmony_ci 3260