14796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok/* 24796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * Dave DNET Ethernet Controller driver 34796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * 44796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * Copyright (C) 2008 Dave S.r.l. <www.dave.eu> 54796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * Copyright (C) 2009 Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com> 64796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * 74796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * This program is free software; you can redistribute it and/or modify 84796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * it under the terms of the GNU General Public License version 2 as 94796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * published by the Free Software Foundation. 104796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok */ 11142071b83426674ef2dab98cf2a6627328d0988eGeert Uytterhoeven#include <linux/io.h> 124796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok#include <linux/module.h> 134796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok#include <linux/moduleparam.h> 144796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok#include <linux/kernel.h> 154796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok#include <linux/types.h> 164796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok#include <linux/slab.h> 174796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok#include <linux/delay.h> 18a6b7a407865aab9f849dd99a71072b7cd1175116Alexey Dobriyan#include <linux/interrupt.h> 194796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok#include <linux/netdevice.h> 204796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok#include <linux/etherdevice.h> 214796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok#include <linux/dma-mapping.h> 224796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok#include <linux/platform_device.h> 234796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok#include <linux/phy.h> 244796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 254796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok#include "dnet.h" 264796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 274796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok#undef DEBUG 284796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 294796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok/* function for reading internal MAC register */ 3035f2516f0a1f9dddb339849c7a07e089322c18c3Harvey Harrisonstatic u16 dnet_readw_mac(struct dnet *bp, u16 reg) 314796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 324796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok u16 data_read; 334796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 344796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* issue a read */ 354796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writel(bp, reg, MACREG_ADDR); 364796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 374796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* since a read/write op to the MAC is very slow, 384796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * we must wait before reading the data */ 394796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok ndelay(500); 404796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 414796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* read data read from the MAC register */ 424796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok data_read = dnet_readl(bp, MACREG_DATA); 434796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 444796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* all done */ 454796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return data_read; 464796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 474796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 484796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok/* function for writing internal MAC register */ 4935f2516f0a1f9dddb339849c7a07e089322c18c3Harvey Harrisonstatic void dnet_writew_mac(struct dnet *bp, u16 reg, u16 val) 504796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 514796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* load data to write */ 524796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writel(bp, val, MACREG_DATA); 534796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 544796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* issue a write */ 554796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writel(bp, reg | DNET_INTERNAL_WRITE, MACREG_ADDR); 564796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 574796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* since a read/write op to the MAC is very slow, 584796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * we must wait before exiting */ 594796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok ndelay(500); 604796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 614796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 624796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic void __dnet_set_hwaddr(struct dnet *bp) 634796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 644796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok u16 tmp; 654796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6635f2516f0a1f9dddb339849c7a07e089322c18c3Harvey Harrison tmp = be16_to_cpup((__be16 *)bp->dev->dev_addr); 674796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writew_mac(bp, DNET_INTERNAL_MAC_ADDR_0_REG, tmp); 6835f2516f0a1f9dddb339849c7a07e089322c18c3Harvey Harrison tmp = be16_to_cpup((__be16 *)(bp->dev->dev_addr + 2)); 694796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writew_mac(bp, DNET_INTERNAL_MAC_ADDR_1_REG, tmp); 7035f2516f0a1f9dddb339849c7a07e089322c18c3Harvey Harrison tmp = be16_to_cpup((__be16 *)(bp->dev->dev_addr + 4)); 714796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writew_mac(bp, DNET_INTERNAL_MAC_ADDR_2_REG, tmp); 724796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 734796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 74a0a4efedf9dea0f2dd9625181b48c1f8c6d5418eBill Pembertonstatic void dnet_get_hwaddr(struct dnet *bp) 754796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 764796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok u16 tmp; 774796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok u8 addr[6]; 784796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 794796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* 804796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * from MAC docs: 814796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * "Note that the MAC address is stored in the registers in Hexadecimal 824796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * form. For example, to set the MAC Address to: AC-DE-48-00-00-80 834796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * would require writing 0xAC (octet 0) to address 0x0B (high byte of 844796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * Mac_addr[15:0]), 0xDE (octet 1) to address 0x0A (Low byte of 854796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * Mac_addr[15:0]), 0x48 (octet 2) to address 0x0D (high byte of 864796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * Mac_addr[15:0]), 0x00 (octet 3) to address 0x0C (Low byte of 874796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * Mac_addr[15:0]), 0x00 (octet 4) to address 0x0F (high byte of 884796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * Mac_addr[15:0]), and 0x80 (octet 5) to address * 0x0E (Low byte of 894796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * Mac_addr[15:0]). 904796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok */ 914796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok tmp = dnet_readw_mac(bp, DNET_INTERNAL_MAC_ADDR_0_REG); 9235f2516f0a1f9dddb339849c7a07e089322c18c3Harvey Harrison *((__be16 *)addr) = cpu_to_be16(tmp); 934796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok tmp = dnet_readw_mac(bp, DNET_INTERNAL_MAC_ADDR_1_REG); 9435f2516f0a1f9dddb339849c7a07e089322c18c3Harvey Harrison *((__be16 *)(addr + 2)) = cpu_to_be16(tmp); 954796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok tmp = dnet_readw_mac(bp, DNET_INTERNAL_MAC_ADDR_2_REG); 9635f2516f0a1f9dddb339849c7a07e089322c18c3Harvey Harrison *((__be16 *)(addr + 4)) = cpu_to_be16(tmp); 974796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 984796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (is_valid_ether_addr(addr)) 994796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok memcpy(bp->dev->dev_addr, addr, sizeof(addr)); 1004796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 1014796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1024796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic int dnet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) 1034796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 1044796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct dnet *bp = bus->priv; 1054796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok u16 value; 1064796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1074796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok while (!(dnet_readw_mac(bp, DNET_INTERNAL_GMII_MNG_CTL_REG) 1084796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok & DNET_INTERNAL_GMII_MNG_CMD_FIN)) 1094796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok cpu_relax(); 1104796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1114796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* only 5 bits allowed for phy-addr and reg_offset */ 1124796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok mii_id &= 0x1f; 1134796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok regnum &= 0x1f; 1144796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1154796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* prepare reg_value for a read */ 1164796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok value = (mii_id << 8); 1174796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok value |= regnum; 1184796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1194796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* write control word */ 1204796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writew_mac(bp, DNET_INTERNAL_GMII_MNG_CTL_REG, value); 1214796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1224796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* wait for end of transfer */ 1234796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok while (!(dnet_readw_mac(bp, DNET_INTERNAL_GMII_MNG_CTL_REG) 1244796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok & DNET_INTERNAL_GMII_MNG_CMD_FIN)) 1254796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok cpu_relax(); 1264796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1274796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok value = dnet_readw_mac(bp, DNET_INTERNAL_GMII_MNG_DAT_REG); 1284796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1294796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("mdio_read %02x:%02x <- %04x\n", mii_id, regnum, value); 1304796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1314796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return value; 1324796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 1334796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1344796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic int dnet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, 1354796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok u16 value) 1364796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 1374796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct dnet *bp = bus->priv; 1384796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok u16 tmp; 1394796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1404796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("mdio_write %02x:%02x <- %04x\n", mii_id, regnum, value); 1414796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1424796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok while (!(dnet_readw_mac(bp, DNET_INTERNAL_GMII_MNG_CTL_REG) 1434796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok & DNET_INTERNAL_GMII_MNG_CMD_FIN)) 1444796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok cpu_relax(); 1454796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1464796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* prepare for a write operation */ 1474796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok tmp = (1 << 13); 1484796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1494796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* only 5 bits allowed for phy-addr and reg_offset */ 1504796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok mii_id &= 0x1f; 1514796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok regnum &= 0x1f; 1524796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1534796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* only 16 bits on data */ 1544796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok value &= 0xffff; 1554796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1564796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* prepare reg_value for a write */ 1574796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok tmp |= (mii_id << 8); 1584796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok tmp |= regnum; 1594796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1604796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* write data to write first */ 1614796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writew_mac(bp, DNET_INTERNAL_GMII_MNG_DAT_REG, value); 1624796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1634796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* write control word */ 1644796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writew_mac(bp, DNET_INTERNAL_GMII_MNG_CTL_REG, tmp); 1654796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1664796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok while (!(dnet_readw_mac(bp, DNET_INTERNAL_GMII_MNG_CTL_REG) 1674796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok & DNET_INTERNAL_GMII_MNG_CMD_FIN)) 1684796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok cpu_relax(); 1694796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1704796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return 0; 1714796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 1724796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1734796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic void dnet_handle_link_change(struct net_device *dev) 1744796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 1754796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct dnet *bp = netdev_priv(dev); 1764796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct phy_device *phydev = bp->phy_dev; 1774796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok unsigned long flags; 1784796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok u32 mode_reg, ctl_reg; 1794796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1804796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok int status_change = 0; 1814796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1824796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok spin_lock_irqsave(&bp->lock, flags); 1834796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1844796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok mode_reg = dnet_readw_mac(bp, DNET_INTERNAL_MODE_REG); 1854796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok ctl_reg = dnet_readw_mac(bp, DNET_INTERNAL_RXTX_CONTROL_REG); 1864796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1874796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (phydev->link) { 1884796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (bp->duplex != phydev->duplex) { 1894796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (phydev->duplex) 1904796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok ctl_reg &= 1914796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok ~(DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP); 1924796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok else 1934796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok ctl_reg |= 1944796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP; 1954796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 1964796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok bp->duplex = phydev->duplex; 1974796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok status_change = 1; 1984796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 1994796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 2004796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (bp->speed != phydev->speed) { 2014796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok status_change = 1; 2024796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok switch (phydev->speed) { 2034796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok case 1000: 2044796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok mode_reg |= DNET_INTERNAL_MODE_GBITEN; 2054796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok break; 2064796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok case 100: 2074796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok case 10: 2084796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok mode_reg &= ~DNET_INTERNAL_MODE_GBITEN; 2094796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok break; 2104796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok default: 2114796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok printk(KERN_WARNING 2124796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok "%s: Ack! Speed (%d) is not " 2134796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok "10/100/1000!\n", dev->name, 2144796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok phydev->speed); 2154796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok break; 2164796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 2174796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok bp->speed = phydev->speed; 2184796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 2194796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 2204796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 2214796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (phydev->link != bp->link) { 2224796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (phydev->link) { 2234796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok mode_reg |= 2244796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok (DNET_INTERNAL_MODE_RXEN | DNET_INTERNAL_MODE_TXEN); 2254796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } else { 2264796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok mode_reg &= 2274796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok ~(DNET_INTERNAL_MODE_RXEN | 2284796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok DNET_INTERNAL_MODE_TXEN); 2294796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok bp->speed = 0; 2304796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok bp->duplex = -1; 2314796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 2324796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok bp->link = phydev->link; 2334796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 2344796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok status_change = 1; 2354796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 2364796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 2374796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (status_change) { 2384796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writew_mac(bp, DNET_INTERNAL_RXTX_CONTROL_REG, ctl_reg); 2394796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writew_mac(bp, DNET_INTERNAL_MODE_REG, mode_reg); 2404796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 2414796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 2424796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok spin_unlock_irqrestore(&bp->lock, flags); 2434796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 2444796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (status_change) { 2454796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (phydev->link) 2464796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok printk(KERN_INFO "%s: link up (%d/%s)\n", 2474796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dev->name, phydev->speed, 2484796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok DUPLEX_FULL == phydev->duplex ? "Full" : "Half"); 2494796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok else 2504796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok printk(KERN_INFO "%s: link down\n", dev->name); 2514796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 2524796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 2534796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 2544796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic int dnet_mii_probe(struct net_device *dev) 2554796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 2564796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct dnet *bp = netdev_priv(dev); 2574796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct phy_device *phydev = NULL; 2584796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok int phy_addr; 2594796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 2604796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* find the first phy */ 2614796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { 2624796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (bp->mii_bus->phy_map[phy_addr]) { 2634796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok phydev = bp->mii_bus->phy_map[phy_addr]; 2644796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok break; 2654796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 2664796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 2674796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 2684796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (!phydev) { 2694796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok printk(KERN_ERR "%s: no PHY found\n", dev->name); 2704796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return -ENODEV; 2714796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 2724796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 2734796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* TODO : add pin_irq */ 2744796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 2754796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* attach the mac to the phy */ 2764796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (bp->capabilities & DNET_HAS_RMII) { 2776580f57d485f70851218813fa053d971915f61fbStephen Rothwell phydev = phy_connect(dev, dev_name(&phydev->dev), 278f9a8f83b04e0c362a2fc660dbad980d24af209fcFlorian Fainelli &dnet_handle_link_change, 2794796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok PHY_INTERFACE_MODE_RMII); 2804796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } else { 2816580f57d485f70851218813fa053d971915f61fbStephen Rothwell phydev = phy_connect(dev, dev_name(&phydev->dev), 282f9a8f83b04e0c362a2fc660dbad980d24af209fcFlorian Fainelli &dnet_handle_link_change, 2834796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok PHY_INTERFACE_MODE_MII); 2844796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 2854796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 2864796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (IS_ERR(phydev)) { 2874796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); 2884796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return PTR_ERR(phydev); 2894796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 2904796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 2914796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* mask with MAC supported features */ 2924796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (bp->capabilities & DNET_HAS_GIGABIT) 2934796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok phydev->supported &= PHY_GBIT_FEATURES; 2944796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok else 2954796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok phydev->supported &= PHY_BASIC_FEATURES; 2964796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 2974796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok phydev->supported |= SUPPORTED_Asym_Pause | SUPPORTED_Pause; 2984796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 2994796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok phydev->advertising = phydev->supported; 3004796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 3014796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok bp->link = 0; 3024796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok bp->speed = 0; 3034796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok bp->duplex = -1; 3044796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok bp->phy_dev = phydev; 3054796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 3064796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return 0; 3074796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 3084796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 3094796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic int dnet_mii_init(struct dnet *bp) 3104796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 3114796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok int err, i; 3124796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 3134796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok bp->mii_bus = mdiobus_alloc(); 3144796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (bp->mii_bus == NULL) 3154796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return -ENOMEM; 3164796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 3174796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok bp->mii_bus->name = "dnet_mii_bus"; 3184796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok bp->mii_bus->read = &dnet_mdio_read; 3194796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok bp->mii_bus->write = &dnet_mdio_write; 3204796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 32163f678301fb952c2d758d9ded4ed88c1da6c0c50Florian Fainelli snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", 32263f678301fb952c2d758d9ded4ed88c1da6c0c50Florian Fainelli bp->pdev->name, bp->pdev->id); 3234796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 3244796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok bp->mii_bus->priv = bp; 3254796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 326ae29223eaf0ecf4c701457a6b40d7b8f19c90413Himangi Saraogi bp->mii_bus->irq = devm_kmalloc(&bp->pdev->dev, 327ae29223eaf0ecf4c701457a6b40d7b8f19c90413Himangi Saraogi sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); 3284796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (!bp->mii_bus->irq) { 3294796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok err = -ENOMEM; 3304796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok goto err_out; 3314796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 3324796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 3334796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok for (i = 0; i < PHY_MAX_ADDR; i++) 3344796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok bp->mii_bus->irq[i] = PHY_POLL; 3354796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 3364796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (mdiobus_register(bp->mii_bus)) { 3374796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok err = -ENXIO; 338ae29223eaf0ecf4c701457a6b40d7b8f19c90413Himangi Saraogi goto err_out; 3394796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 3404796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 3414796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (dnet_mii_probe(bp->dev) != 0) { 3424796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok err = -ENXIO; 3434796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok goto err_out_unregister_bus; 3444796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 3454796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 3464796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return 0; 3474796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 3484796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokerr_out_unregister_bus: 3494796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok mdiobus_unregister(bp->mii_bus); 3504796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokerr_out: 3514796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok mdiobus_free(bp->mii_bus); 3524796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return err; 3534796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 3544796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 3554796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok/* For Neptune board: LINK1000 as Link LED and TX as activity LED */ 35635f2516f0a1f9dddb339849c7a07e089322c18c3Harvey Harrisonstatic int dnet_phy_marvell_fixup(struct phy_device *phydev) 3574796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 3584796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return phy_write(phydev, 0x18, 0x4148); 3594796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 3604796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 3614796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic void dnet_update_stats(struct dnet *bp) 3624796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 3634796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok u32 __iomem *reg = bp->regs + DNET_RX_PKT_IGNR_CNT; 3644796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok u32 *p = &bp->hw_stats.rx_pkt_ignr; 3654796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok u32 *end = &bp->hw_stats.rx_byte + 1; 3664796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 3674796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok WARN_ON((unsigned long)(end - p - 1) != 3684796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok (DNET_RX_BYTE_CNT - DNET_RX_PKT_IGNR_CNT) / 4); 3694796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 3704796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok for (; p < end; p++, reg++) 3714796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok *p += readl(reg); 3724796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 3734796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok reg = bp->regs + DNET_TX_UNICAST_CNT; 3744796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok p = &bp->hw_stats.tx_unicast; 3754796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok end = &bp->hw_stats.tx_byte + 1; 3764796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 3774796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok WARN_ON((unsigned long)(end - p - 1) != 3784796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok (DNET_TX_BYTE_CNT - DNET_TX_UNICAST_CNT) / 4); 3794796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 3804796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok for (; p < end; p++, reg++) 3814796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok *p += readl(reg); 3824796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 3834796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 3844796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic int dnet_poll(struct napi_struct *napi, int budget) 3854796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 3864796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct dnet *bp = container_of(napi, struct dnet, napi); 3874796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct net_device *dev = bp->dev; 3884796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok int npackets = 0; 3894796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok unsigned int pkt_len; 3904796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct sk_buff *skb; 3914796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok unsigned int *data_ptr; 3924796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok u32 int_enable; 3934796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok u32 cmd_word; 3944796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok int i; 3954796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 3964796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok while (npackets < budget) { 3974796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* 3984796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * break out of while loop if there are no more 3994796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * packets waiting 4004796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok */ 4014796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (!(dnet_readl(bp, RX_FIFO_WCNT) >> 16)) { 4029fae6c3f648e38f023b99b5f5a5280907b2e796eIlya Yanok napi_complete(napi); 4034796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok int_enable = dnet_readl(bp, INTR_ENB); 4044796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok int_enable |= DNET_INTR_SRC_RX_CMDFIFOAF; 4054796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writel(bp, int_enable, INTR_ENB); 4064796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return 0; 4074796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 4084796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 4094796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok cmd_word = dnet_readl(bp, RX_LEN_FIFO); 4104796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pkt_len = cmd_word & 0xFFFF; 4114796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 4124796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (cmd_word & 0xDF180000) 4134796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok printk(KERN_ERR "%s packet receive error %x\n", 4144796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok __func__, cmd_word); 4154796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 41621a4e46995fa1a76281ac0281ff837f706231a37Pradeep A Dalvi skb = netdev_alloc_skb(dev, pkt_len + 5); 4174796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (skb != NULL) { 4184796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* Align IP on 16 byte boundaries */ 4194796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok skb_reserve(skb, 2); 4204796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* 4214796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * 'skb_put()' points to the start of sk_buff 4224796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * data area. 4234796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok */ 4244796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok data_ptr = (unsigned int *)skb_put(skb, pkt_len); 4254796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok for (i = 0; i < (pkt_len + 3) >> 2; i++) 4264796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok *data_ptr++ = dnet_readl(bp, RX_DATA_FIFO); 4274796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok skb->protocol = eth_type_trans(skb, dev); 4284796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok netif_receive_skb(skb); 4294796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok npackets++; 4304796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } else 4314796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok printk(KERN_NOTICE 4324796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok "%s: No memory to allocate a sk_buff of " 4334796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok "size %u.\n", dev->name, pkt_len); 4344796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 4354796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 4364796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok budget -= npackets; 4374796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 4384796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (npackets < budget) { 4394796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* We processed all packets available. Tell NAPI it can 4404796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * stop polling then re-enable rx interrupts */ 4419fae6c3f648e38f023b99b5f5a5280907b2e796eIlya Yanok napi_complete(napi); 4424796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok int_enable = dnet_readl(bp, INTR_ENB); 4434796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok int_enable |= DNET_INTR_SRC_RX_CMDFIFOAF; 4444796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writel(bp, int_enable, INTR_ENB); 4454796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return 0; 4464796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 4474796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 4484796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* There are still packets waiting */ 4494796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return 1; 4504796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 4514796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 4524796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic irqreturn_t dnet_interrupt(int irq, void *dev_id) 4534796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 4544796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct net_device *dev = dev_id; 4554796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct dnet *bp = netdev_priv(dev); 4564796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok u32 int_src, int_enable, int_current; 4574796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok unsigned long flags; 4584796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok unsigned int handled = 0; 4594796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 4604796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok spin_lock_irqsave(&bp->lock, flags); 4614796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 4624796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* read and clear the DNET irq (clear on read) */ 4634796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok int_src = dnet_readl(bp, INTR_SRC); 4644796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok int_enable = dnet_readl(bp, INTR_ENB); 4654796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok int_current = int_src & int_enable; 4664796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 4674796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* restart the queue if we had stopped it for TX fifo almost full */ 4684796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (int_current & DNET_INTR_SRC_TX_FIFOAE) { 4694796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok int_enable = dnet_readl(bp, INTR_ENB); 4704796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok int_enable &= ~DNET_INTR_ENB_TX_FIFOAE; 4714796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writel(bp, int_enable, INTR_ENB); 4724796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok netif_wake_queue(dev); 4734796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok handled = 1; 4744796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 4754796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 4764796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* RX FIFO error checking */ 4774796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (int_current & 4784796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok (DNET_INTR_SRC_RX_CMDFIFOFF | DNET_INTR_SRC_RX_DATAFIFOFF)) { 4794796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok printk(KERN_ERR "%s: RX fifo error %x, irq %x\n", __func__, 4804796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_readl(bp, RX_STATUS), int_current); 4814796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* we can only flush the RX FIFOs */ 4824796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writel(bp, DNET_SYS_CTL_RXFIFOFLUSH, SYS_CTL); 4834796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok ndelay(500); 4844796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writel(bp, 0, SYS_CTL); 4854796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok handled = 1; 4864796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 4874796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 4884796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* TX FIFO error checking */ 4894796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (int_current & 4904796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok (DNET_INTR_SRC_TX_FIFOFULL | DNET_INTR_SRC_TX_DISCFRM)) { 4914796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok printk(KERN_ERR "%s: TX fifo error %x, irq %x\n", __func__, 4924796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_readl(bp, TX_STATUS), int_current); 4934796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* we can only flush the TX FIFOs */ 4944796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writel(bp, DNET_SYS_CTL_TXFIFOFLUSH, SYS_CTL); 4954796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok ndelay(500); 4964796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writel(bp, 0, SYS_CTL); 4974796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok handled = 1; 4984796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 4994796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 5004796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (int_current & DNET_INTR_SRC_RX_CMDFIFOAF) { 5019fae6c3f648e38f023b99b5f5a5280907b2e796eIlya Yanok if (napi_schedule_prep(&bp->napi)) { 5024796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* 5034796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * There's no point taking any more interrupts 5044796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * until we have processed the buffers 5054796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok */ 5064796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* Disable Rx interrupts and schedule NAPI poll */ 5074796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok int_enable = dnet_readl(bp, INTR_ENB); 5084796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok int_enable &= ~DNET_INTR_SRC_RX_CMDFIFOAF; 5094796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writel(bp, int_enable, INTR_ENB); 5109fae6c3f648e38f023b99b5f5a5280907b2e796eIlya Yanok __napi_schedule(&bp->napi); 5114796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 5124796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok handled = 1; 5134796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 5144796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 5154796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (!handled) 5164796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("%s: irq %x remains\n", __func__, int_current); 5174796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 5184796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok spin_unlock_irqrestore(&bp->lock, flags); 5194796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 5204796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return IRQ_RETVAL(handled); 5214796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 5224796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 5234796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok#ifdef DEBUG 5244796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic inline void dnet_print_skb(struct sk_buff *skb) 5254796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 5264796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok int k; 5274796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok printk(KERN_DEBUG PFX "data:"); 5284796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok for (k = 0; k < skb->len; k++) 5294796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok printk(" %02x", (unsigned int)skb->data[k]); 5304796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok printk("\n"); 5314796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 5324796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok#else 5334796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok#define dnet_print_skb(skb) do {} while (0) 5344796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok#endif 5354796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 53661357325f377889a1daffa14962d705dc814dd0eStephen Hemmingerstatic netdev_tx_t dnet_start_xmit(struct sk_buff *skb, struct net_device *dev) 5374796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 5384796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 5394796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct dnet *bp = netdev_priv(dev); 5404796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok u32 tx_status, irq_enable; 5414796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok unsigned int len, i, tx_cmd, wrsz; 5424796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok unsigned long flags; 5434796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok unsigned int *bufp; 5444796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 5454796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok tx_status = dnet_readl(bp, TX_STATUS); 5464796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 5472c5849ea38fdad477d72dcf1c8c4842db4b33aaeDavid S. Miller pr_debug("start_xmit: len %u head %p data %p\n", 5482c5849ea38fdad477d72dcf1c8c4842db4b33aaeDavid S. Miller skb->len, skb->head, skb->data); 5494796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_print_skb(skb); 5504796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 5514796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* frame size (words) */ 5524796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok len = (skb->len + 3) >> 2; 5534796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 5544796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok spin_lock_irqsave(&bp->lock, flags); 5554796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 5564796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok tx_status = dnet_readl(bp, TX_STATUS); 5574796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 5582c5849ea38fdad477d72dcf1c8c4842db4b33aaeDavid S. Miller bufp = (unsigned int *)(((unsigned long) skb->data) & ~0x3UL); 5594796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok wrsz = (u32) skb->len + 3; 5602c5849ea38fdad477d72dcf1c8c4842db4b33aaeDavid S. Miller wrsz += ((unsigned long) skb->data) & 0x3; 5614796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok wrsz >>= 2; 5622c5849ea38fdad477d72dcf1c8c4842db4b33aaeDavid S. Miller tx_cmd = ((((unsigned long)(skb->data)) & 0x03) << 16) | (u32) skb->len; 5634796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 5644796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* check if there is enough room for the current frame */ 5654796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (wrsz < (DNET_FIFO_SIZE - dnet_readl(bp, TX_FIFO_WCNT))) { 5664796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok for (i = 0; i < wrsz; i++) 5674796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writel(bp, *bufp++, TX_DATA_FIFO); 5684796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 5694796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* 5704796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * inform MAC that a packet's written and ready to be 5714796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * shipped out 5724796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok */ 5734796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writel(bp, tx_cmd, TX_LEN_FIFO); 5744796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 5754796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 5764796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (dnet_readl(bp, TX_FIFO_WCNT) > DNET_FIFO_TX_DATA_AF_TH) { 5774796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok netif_stop_queue(dev); 5784796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok tx_status = dnet_readl(bp, INTR_SRC); 5794796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok irq_enable = dnet_readl(bp, INTR_ENB); 5804796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok irq_enable |= DNET_INTR_ENB_TX_FIFOAE; 5814796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writel(bp, irq_enable, INTR_ENB); 5824796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 5834796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 584ff9b3078b918480a471b065c36133a144a531038Richard Cochran skb_tx_timestamp(skb); 585ff9b3078b918480a471b065c36133a144a531038Richard Cochran 5864796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* free the buffer */ 5874796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dev_kfree_skb(skb); 5884796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 5894796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok spin_unlock_irqrestore(&bp->lock, flags); 5904796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 5916ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 5924796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 5934796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 5944796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic void dnet_reset_hw(struct dnet *bp) 5954796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 5964796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* put ts_mac in IDLE state i.e. disable rx/tx */ 5974796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writew_mac(bp, DNET_INTERNAL_MODE_REG, DNET_INTERNAL_MODE_FCEN); 5984796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 5994796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* 6004796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * RX FIFO almost full threshold: only cmd FIFO almost full is 6014796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * implemented for RX side 6024796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok */ 6034796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writel(bp, DNET_FIFO_RX_CMD_AF_TH, RX_FIFO_TH); 6044796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* 6054796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * TX FIFO almost empty threshold: only data FIFO almost empty 6064796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok * is implemented for TX side 6074796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok */ 6084796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writel(bp, DNET_FIFO_TX_DATA_AE_TH, TX_FIFO_TH); 6094796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6104796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* flush rx/tx fifos */ 6114796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writel(bp, DNET_SYS_CTL_RXFIFOFLUSH | DNET_SYS_CTL_TXFIFOFLUSH, 6124796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok SYS_CTL); 6134796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok msleep(1); 6144796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writel(bp, 0, SYS_CTL); 6154796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 6164796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6174796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic void dnet_init_hw(struct dnet *bp) 6184796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 6194796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok u32 config; 6204796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6214796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_reset_hw(bp); 6224796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok __dnet_set_hwaddr(bp); 6234796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6244796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok config = dnet_readw_mac(bp, DNET_INTERNAL_RXTX_CONTROL_REG); 6254796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6264796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (bp->dev->flags & IFF_PROMISC) 6274796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* Copy All Frames */ 6284796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok config |= DNET_INTERNAL_RXTX_CONTROL_ENPROMISC; 6294796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (!(bp->dev->flags & IFF_BROADCAST)) 6304796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* No BroadCast */ 6314796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok config |= DNET_INTERNAL_RXTX_CONTROL_RXMULTICAST; 6324796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6334796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok config |= DNET_INTERNAL_RXTX_CONTROL_RXPAUSE | 6344796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok DNET_INTERNAL_RXTX_CONTROL_RXBROADCAST | 6354796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok DNET_INTERNAL_RXTX_CONTROL_DROPCONTROL | 6364796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok DNET_INTERNAL_RXTX_CONTROL_DISCFXFCS; 6374796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6384796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writew_mac(bp, DNET_INTERNAL_RXTX_CONTROL_REG, config); 6394796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6404796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* clear irq before enabling them */ 6414796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok config = dnet_readl(bp, INTR_SRC); 6424796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6434796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* enable RX/TX interrupt, recv packet ready interrupt */ 6444796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_writel(bp, DNET_INTR_ENB_GLOBAL_ENABLE | DNET_INTR_ENB_RX_SUMMARY | 6454796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok DNET_INTR_ENB_TX_SUMMARY | DNET_INTR_ENB_RX_FIFOERR | 6464796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok DNET_INTR_ENB_RX_ERROR | DNET_INTR_ENB_RX_FIFOFULL | 6474796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok DNET_INTR_ENB_TX_FIFOFULL | DNET_INTR_ENB_TX_DISCFRM | 6484796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok DNET_INTR_ENB_RX_PKTRDY, INTR_ENB); 6494796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 6504796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6514796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic int dnet_open(struct net_device *dev) 6524796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 6534796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct dnet *bp = netdev_priv(dev); 6544796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6554796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* if the phy is not yet register, retry later */ 6564796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (!bp->phy_dev) 6574796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return -EAGAIN; 6584796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6594796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok napi_enable(&bp->napi); 6604796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_init_hw(bp); 6614796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6624796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok phy_start_aneg(bp->phy_dev); 6634796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6644796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* schedule a link state check */ 6654796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok phy_start(bp->phy_dev); 6664796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6674796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok netif_start_queue(dev); 6684796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6694796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return 0; 6704796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 6714796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6724796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic int dnet_close(struct net_device *dev) 6734796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 6744796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct dnet *bp = netdev_priv(dev); 6754796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6764796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok netif_stop_queue(dev); 6774796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok napi_disable(&bp->napi); 6784796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6794796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (bp->phy_dev) 6804796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok phy_stop(bp->phy_dev); 6814796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6824796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_reset_hw(bp); 6834796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok netif_carrier_off(dev); 6844796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6854796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return 0; 6864796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 6874796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 6884796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic inline void dnet_print_pretty_hwstats(struct dnet_stats *hwstat) 6894796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 6904796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("%s\n", __func__); 6914796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("----------------------------- RX statistics " 6924796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok "-------------------------------\n"); 6934796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("RX_PKT_IGNR_CNT %-8x\n", hwstat->rx_pkt_ignr); 6944796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("RX_LEN_CHK_ERR_CNT %-8x\n", hwstat->rx_len_chk_err); 6954796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("RX_LNG_FRM_CNT %-8x\n", hwstat->rx_lng_frm); 6964796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("RX_SHRT_FRM_CNT %-8x\n", hwstat->rx_shrt_frm); 6974796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("RX_IPG_VIOL_CNT %-8x\n", hwstat->rx_ipg_viol); 6984796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("RX_CRC_ERR_CNT %-8x\n", hwstat->rx_crc_err); 6994796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("RX_OK_PKT_CNT %-8x\n", hwstat->rx_ok_pkt); 7004796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("RX_CTL_FRM_CNT %-8x\n", hwstat->rx_ctl_frm); 7014796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("RX_PAUSE_FRM_CNT %-8x\n", hwstat->rx_pause_frm); 7024796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("RX_MULTICAST_CNT %-8x\n", hwstat->rx_multicast); 7034796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("RX_BROADCAST_CNT %-8x\n", hwstat->rx_broadcast); 7044796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("RX_VLAN_TAG_CNT %-8x\n", hwstat->rx_vlan_tag); 7054796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("RX_PRE_SHRINK_CNT %-8x\n", hwstat->rx_pre_shrink); 7064796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("RX_DRIB_NIB_CNT %-8x\n", hwstat->rx_drib_nib); 7074796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("RX_UNSUP_OPCD_CNT %-8x\n", hwstat->rx_unsup_opcd); 7084796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("RX_BYTE_CNT %-8x\n", hwstat->rx_byte); 7094796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("----------------------------- TX statistics " 7104796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok "-------------------------------\n"); 7114796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("TX_UNICAST_CNT %-8x\n", hwstat->tx_unicast); 7124796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("TX_PAUSE_FRM_CNT %-8x\n", hwstat->tx_pause_frm); 7134796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("TX_MULTICAST_CNT %-8x\n", hwstat->tx_multicast); 7144796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("TX_BRDCAST_CNT %-8x\n", hwstat->tx_brdcast); 7154796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("TX_VLAN_TAG_CNT %-8x\n", hwstat->tx_vlan_tag); 7164796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("TX_BAD_FCS_CNT %-8x\n", hwstat->tx_bad_fcs); 7174796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("TX_JUMBO_CNT %-8x\n", hwstat->tx_jumbo); 7184796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok pr_debug("TX_BYTE_CNT %-8x\n", hwstat->tx_byte); 7194796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 7204796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 7214796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic struct net_device_stats *dnet_get_stats(struct net_device *dev) 7224796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 7234796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 7244796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct dnet *bp = netdev_priv(dev); 7254796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct net_device_stats *nstat = &dev->stats; 7264796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct dnet_stats *hwstat = &bp->hw_stats; 7274796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 7284796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* read stats from hardware */ 7294796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_update_stats(bp); 7304796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 7314796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* Convert HW stats into netdevice stats */ 7324796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok nstat->rx_errors = (hwstat->rx_len_chk_err + 7334796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok hwstat->rx_lng_frm + hwstat->rx_shrt_frm + 7344796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* ignore IGP violation error 7354796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok hwstat->rx_ipg_viol + */ 7364796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok hwstat->rx_crc_err + 7374796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok hwstat->rx_pre_shrink + 7384796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok hwstat->rx_drib_nib + hwstat->rx_unsup_opcd); 7394796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok nstat->tx_errors = hwstat->tx_bad_fcs; 7404796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok nstat->rx_length_errors = (hwstat->rx_len_chk_err + 7414796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok hwstat->rx_lng_frm + 7424796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok hwstat->rx_shrt_frm + hwstat->rx_pre_shrink); 7434796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok nstat->rx_crc_errors = hwstat->rx_crc_err; 7444796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok nstat->rx_frame_errors = hwstat->rx_pre_shrink + hwstat->rx_drib_nib; 7454796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok nstat->rx_packets = hwstat->rx_ok_pkt; 7464796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok nstat->tx_packets = (hwstat->tx_unicast + 7474796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok hwstat->tx_multicast + hwstat->tx_brdcast); 7484796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok nstat->rx_bytes = hwstat->rx_byte; 7494796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok nstat->tx_bytes = hwstat->tx_byte; 7504796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok nstat->multicast = hwstat->rx_multicast; 7514796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok nstat->rx_missed_errors = hwstat->rx_pkt_ignr; 7524796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 7534796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_print_pretty_hwstats(hwstat); 7544796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 7554796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return nstat; 7564796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 7574796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 7584796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic int dnet_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) 7594796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 7604796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct dnet *bp = netdev_priv(dev); 7614796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct phy_device *phydev = bp->phy_dev; 7624796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 7634796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (!phydev) 7644796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return -ENODEV; 7654796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 7664796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return phy_ethtool_gset(phydev, cmd); 7674796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 7684796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 7694796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic int dnet_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) 7704796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 7714796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct dnet *bp = netdev_priv(dev); 7724796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct phy_device *phydev = bp->phy_dev; 7734796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 7744796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (!phydev) 7754796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return -ENODEV; 7764796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 7774796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return phy_ethtool_sset(phydev, cmd); 7784796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 7794796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 7804796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic int dnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 7814796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 7824796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct dnet *bp = netdev_priv(dev); 7834796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct phy_device *phydev = bp->phy_dev; 7844796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 7854796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (!netif_running(dev)) 7864796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return -EINVAL; 7874796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 7884796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (!phydev) 7894796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return -ENODEV; 7904796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 79128b041139e344ecd0f144d6205b004ae354cfa1eRichard Cochran return phy_mii_ioctl(phydev, rq, cmd); 7924796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 7934796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 7944796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic void dnet_get_drvinfo(struct net_device *dev, 7954796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct ethtool_drvinfo *info) 7964796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 79768aad78c5023b8aa82da99b47f9d8cf40e8ca453Rick Jones strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); 79868aad78c5023b8aa82da99b47f9d8cf40e8ca453Rick Jones strlcpy(info->version, DRV_VERSION, sizeof(info->version)); 79968aad78c5023b8aa82da99b47f9d8cf40e8ca453Rick Jones strlcpy(info->bus_info, "0", sizeof(info->bus_info)); 8004796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 8014796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 8024796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic const struct ethtool_ops dnet_ethtool_ops = { 8034796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok .get_settings = dnet_get_settings, 8044796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok .set_settings = dnet_set_settings, 8054796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok .get_drvinfo = dnet_get_drvinfo, 8064796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok .get_link = ethtool_op_get_link, 807eb774cbeae027d1060cb71a235bb085df8eb2874Richard Cochran .get_ts_info = ethtool_op_get_ts_info, 8084796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok}; 8094796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 8104796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic const struct net_device_ops dnet_netdev_ops = { 8114796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok .ndo_open = dnet_open, 8124796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok .ndo_stop = dnet_close, 8134796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok .ndo_get_stats = dnet_get_stats, 8144796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok .ndo_start_xmit = dnet_start_xmit, 8154796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok .ndo_do_ioctl = dnet_ioctl, 8164796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok .ndo_set_mac_address = eth_mac_addr, 8174796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok .ndo_validate_addr = eth_validate_addr, 8184796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok .ndo_change_mtu = eth_change_mtu, 8194796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok}; 8204796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 821a0a4efedf9dea0f2dd9625181b48c1f8c6d5418eBill Pembertonstatic int dnet_probe(struct platform_device *pdev) 8224796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 8234796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct resource *res; 8244796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct net_device *dev; 8254796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct dnet *bp; 8264796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct phy_device *phydev; 827ae29223eaf0ecf4c701457a6b40d7b8f19c90413Himangi Saraogi int err; 828ae29223eaf0ecf4c701457a6b40d7b8f19c90413Himangi Saraogi unsigned int irq; 8294796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 8304796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok irq = platform_get_irq(pdev, 0); 8314796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 8324796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dev = alloc_etherdev(sizeof(*bp)); 83341de8d4cff21a2e81e3d9ff66f5f7c903f9c3ab1Joe Perches if (!dev) 834ae29223eaf0ecf4c701457a6b40d7b8f19c90413Himangi Saraogi return -ENOMEM; 8354796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 8364796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* TODO: Actually, we have some interesting features... */ 8374796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dev->features |= 0; 8384796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 8394796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok bp = netdev_priv(dev); 8404796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok bp->dev = dev; 8414796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 842b093dd96844186cd03318aaf0cd96f91db3970efIlya Yanok platform_set_drvdata(pdev, dev); 8434796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok SET_NETDEV_DEV(dev, &pdev->dev); 8444796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 8454796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok spin_lock_init(&bp->lock); 8464796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 847ae29223eaf0ecf4c701457a6b40d7b8f19c90413Himangi Saraogi res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 848ae29223eaf0ecf4c701457a6b40d7b8f19c90413Himangi Saraogi bp->regs = devm_ioremap_resource(&pdev->dev, res); 849ae29223eaf0ecf4c701457a6b40d7b8f19c90413Himangi Saraogi if (IS_ERR(bp->regs)) { 850ae29223eaf0ecf4c701457a6b40d7b8f19c90413Himangi Saraogi err = PTR_ERR(bp->regs); 8514796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok goto err_out_free_dev; 8524796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 8534796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 8544796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dev->irq = irq; 8554796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok err = request_irq(dev->irq, dnet_interrupt, 0, DRV_NAME, dev); 8564796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (err) { 8574796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dev_err(&pdev->dev, "Unable to request IRQ %d (error %d)\n", 8584796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok irq, err); 859ae29223eaf0ecf4c701457a6b40d7b8f19c90413Himangi Saraogi goto err_out_free_dev; 8604796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 8614796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 8624796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dev->netdev_ops = &dnet_netdev_ops; 8634796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok netif_napi_add(dev, &bp->napi, dnet_poll, 64); 8644796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dev->ethtool_ops = &dnet_ethtool_ops; 8654796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 8664796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dev->base_addr = (unsigned long)bp->regs; 8674796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 8684796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok bp->capabilities = dnet_readl(bp, VERCAPS) & DNET_CAPS_MASK; 8694796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 8704796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_get_hwaddr(bp); 8714796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 8724796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (!is_valid_ether_addr(dev->dev_addr)) { 8734796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* choose a random ethernet address */ 874f2cedb63df14342ad40a8b5b324fc5d94a60b665Danny Kukawka eth_hw_addr_random(dev); 8754796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok __dnet_set_hwaddr(bp); 8764796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 8774796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 8784796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok err = register_netdev(dev); 8794796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (err) { 8804796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dev_err(&pdev->dev, "Cannot register net device, aborting.\n"); 8814796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok goto err_out_free_irq; 8824796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 8834796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 8844796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* register the PHY board fixup (for Marvell 88E1111) */ 8854796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok err = phy_register_fixup_for_uid(0x01410cc0, 0xfffffff0, 8864796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dnet_phy_marvell_fixup); 8874796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok /* we can live without it, so just issue a warning */ 8884796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (err) 8894796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dev_warn(&pdev->dev, "Cannot register PHY board fixup.\n"); 8904796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 891de140b0d511ad86a5dd0888c9095ae030ada2e86Dan Carpenter err = dnet_mii_init(bp); 892de140b0d511ad86a5dd0888c9095ae030ada2e86Dan Carpenter if (err) 8934796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok goto err_out_unregister_netdev; 8944796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 8954796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dev_info(&pdev->dev, "Dave DNET at 0x%p (0x%08x) irq %d %pM\n", 896ae29223eaf0ecf4c701457a6b40d7b8f19c90413Himangi Saraogi bp->regs, (unsigned int)res->start, dev->irq, dev->dev_addr); 8972381a55c88453d3f29fe62d235579a05fc20b7b3Frans Pop dev_info(&pdev->dev, "has %smdio, %sirq, %sgigabit, %sdma\n", 8984796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok (bp->capabilities & DNET_HAS_MDIO) ? "" : "no ", 8994796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok (bp->capabilities & DNET_HAS_IRQ) ? "" : "no ", 9004796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok (bp->capabilities & DNET_HAS_GIGABIT) ? "" : "no ", 9014796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok (bp->capabilities & DNET_HAS_DMA) ? "" : "no "); 9024796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok phydev = bp->phy_dev; 9034796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dev_info(&pdev->dev, "attached PHY driver [%s] " 9044796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok "(mii_bus:phy_addr=%s, irq=%d)\n", 9056580f57d485f70851218813fa053d971915f61fbStephen Rothwell phydev->drv->name, dev_name(&phydev->dev), phydev->irq); 9064796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 9074796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return 0; 9084796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 9094796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokerr_out_unregister_netdev: 9104796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok unregister_netdev(dev); 9114796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokerr_out_free_irq: 9124796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok free_irq(dev->irq, dev); 9134796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokerr_out_free_dev: 9144796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok free_netdev(dev); 9154796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return err; 9164796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 9174796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 918a0a4efedf9dea0f2dd9625181b48c1f8c6d5418eBill Pembertonstatic int dnet_remove(struct platform_device *pdev) 9194796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok{ 9204796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 9214796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct net_device *dev; 9224796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok struct dnet *bp; 9234796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 9244796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok dev = platform_get_drvdata(pdev); 9254796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 9264796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (dev) { 9274796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok bp = netdev_priv(dev); 9284796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok if (bp->phy_dev) 9294796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok phy_disconnect(bp->phy_dev); 9304796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok mdiobus_unregister(bp->mii_bus); 9314796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok mdiobus_free(bp->mii_bus); 9324796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok unregister_netdev(dev); 9334796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok free_irq(dev->irq, dev); 9344796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok free_netdev(dev); 9354796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok } 9364796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 9374796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok return 0; 9384796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok} 9394796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 9404796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanokstatic struct platform_driver dnet_driver = { 9414796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok .probe = dnet_probe, 942a0a4efedf9dea0f2dd9625181b48c1f8c6d5418eBill Pemberton .remove = dnet_remove, 9434796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok .driver = { 9444796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok .name = "dnet", 9454796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok }, 9464796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok}; 9474796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 948db62f684deeb291ab2533b99843d5df9a36b1f19Axel Linmodule_platform_driver(dnet_driver); 9494796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok 9504796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya YanokMODULE_LICENSE("GPL"); 9514796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya YanokMODULE_DESCRIPTION("Dave DNET Ethernet driver"); 9524796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya YanokMODULE_AUTHOR("Ilya Yanok <yanok@emcraft.com>, " 9534796417417a62e2ae83d92cb92e1ecf9ec67b5f5Ilya Yanok "Matteo Vit <matteo.vit@dave.eu>"); 954