sc92031.c 39.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*  Silan SC92031 PCI Fast Ethernet Adapter driver
 *
 *  Based on vendor drivers:
 *  Silan Fast Ethernet Netcard Driver:
 *    MODULE_AUTHOR ("gaoyonghong");
 *    MODULE_DESCRIPTION ("SILAN Fast Ethernet driver");
 *    MODULE_LICENSE("GPL");
 *  8139D Fast Ethernet driver:
 *    (C) 2002 by gaoyonghong
 *    MODULE_AUTHOR ("gaoyonghong");
 *    MODULE_DESCRIPTION ("Rsltek 8139D PCI Fast Ethernet Adapter driver");
 *    MODULE_LICENSE("GPL");
 *  Both are almost identical and seem to be based on pci-skeleton.c
 *
 *  Rewritten for 2.6 by Cesar Eduardo Barros
16 17
 *
 *  A datasheet for this chip can be found at
18
 *  http://www.silan.com.cn/english/product/pdf/SC92031AY.pdf 
19 20 21 22 23 24
 */

/* Note about set_mac_address: I don't know how to change the hardware
 * matching, so you need to enable IFF_PROMISC when using it.
 */

25
#include <linux/interrupt.h>
26 27 28 29 30 31 32 33
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
34
#include <linux/mii.h>
35 36 37 38 39 40 41
#include <linux/crc32.h>

#include <asm/irq.h>

#define SC92031_NAME "sc92031"

/* BAR 0 is MMIO, BAR 1 is PIO */
42
#define SC92031_USE_PIO	0
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366

/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). */
static int multicast_filter_limit = 64;
module_param(multicast_filter_limit, int, 0);
MODULE_PARM_DESC(multicast_filter_limit,
	"Maximum number of filtered multicast addresses");

static int media;
module_param(media, int, 0);
MODULE_PARM_DESC(media, "Media type (0x00 = autodetect,"
	" 0x01 = 10M half, 0x02 = 10M full,"
	" 0x04 = 100M half, 0x08 = 100M full)");

/* Size of the in-memory receive ring. */
#define  RX_BUF_LEN_IDX  3 /* 0==8K, 1==16K, 2==32K, 3==64K ,4==128K*/
#define  RX_BUF_LEN	(8192 << RX_BUF_LEN_IDX)

/* Number of Tx descriptor registers. */
#define  NUM_TX_DESC	   4

/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/
#define  MAX_ETH_FRAME_SIZE	  1536

/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
#define  TX_BUF_SIZE       MAX_ETH_FRAME_SIZE
#define  TX_BUF_TOT_LEN    (TX_BUF_SIZE * NUM_TX_DESC)

/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024, 7==end of packet. */
#define  RX_FIFO_THRESH    7     /* Rx buffer level before first PCI xfer.  */

/* Time in jiffies before concluding the transmitter is hung. */
#define  TX_TIMEOUT     (4*HZ)

#define  SILAN_STATS_NUM    2    /* number of ETHTOOL_GSTATS */

/* media options */
#define  AUTOSELECT    0x00
#define  M10_HALF      0x01
#define  M10_FULL      0x02
#define  M100_HALF     0x04
#define  M100_FULL     0x08

 /* Symbolic offsets to registers. */
enum  silan_registers {
   Config0    = 0x00,         // Config0
   Config1    = 0x04,         // Config1
   RxBufWPtr  = 0x08,         // Rx buffer writer poiter
   IntrStatus = 0x0C,         // Interrupt status
   IntrMask   = 0x10,         // Interrupt mask
   RxbufAddr  = 0x14,         // Rx buffer start address
   RxBufRPtr  = 0x18,         // Rx buffer read pointer
   Txstatusall = 0x1C,        // Transmit status of all descriptors
   TxStatus0  = 0x20,	      // Transmit status (Four 32bit registers).
   TxAddr0    = 0x30,         // Tx descriptors (also four 32bit).
   RxConfig   = 0x40,         // Rx configuration
   MAC0	      = 0x44,	      // Ethernet hardware address.
   MAR0	      = 0x4C,	      // Multicast filter.
   RxStatus0  = 0x54,         // Rx status
   TxConfig   = 0x5C,         // Tx configuration
   PhyCtrl    = 0x60,         // physical control
   FlowCtrlConfig = 0x64,     // flow control
   Miicmd0    = 0x68,         // Mii command0 register
   Miicmd1    = 0x6C,         // Mii command1 register
   Miistatus  = 0x70,         // Mii status register
   Timercnt   = 0x74,         // Timer counter register
   TimerIntr  = 0x78,         // Timer interrupt register
   PMConfig   = 0x7C,         // Power Manager configuration
   CRC0       = 0x80,         // Power Manager CRC ( Two 32bit regisers)
   Wakeup0    = 0x88,         // power Manager wakeup( Eight 64bit regiser)
   LSBCRC0    = 0xC8,         // power Manager LSBCRC(Two 32bit regiser)
   TestD0     = 0xD0,
   TestD4     = 0xD4,
   TestD8     = 0xD8,
};

#define MII_JAB             16
#define MII_OutputStatus    24

#define PHY_16_JAB_ENB      0x1000
#define PHY_16_PORT_ENB     0x1

enum IntrStatusBits {
   LinkFail       = 0x80000000,
   LinkOK         = 0x40000000,
   TimeOut        = 0x20000000,
   RxOverflow     = 0x0040,
   RxOK           = 0x0020,
   TxOK           = 0x0001,
   IntrBits = LinkFail|LinkOK|TimeOut|RxOverflow|RxOK|TxOK,
};

enum TxStatusBits {
   TxCarrierLost = 0x20000000,
   TxAborted     = 0x10000000,
   TxOutOfWindow = 0x08000000,
   TxNccShift    = 22,
   EarlyTxThresShift = 16,
   TxStatOK      = 0x8000,
   TxUnderrun    = 0x4000,
   TxOwn         = 0x2000,
};

enum RxStatusBits {
   RxStatesOK   = 0x80000,
   RxBadAlign   = 0x40000,
   RxHugeFrame  = 0x20000,
   RxSmallFrame = 0x10000,
   RxCRCOK      = 0x8000,
   RxCrlFrame   = 0x4000,
   Rx_Broadcast = 0x2000,
   Rx_Multicast = 0x1000,
   RxAddrMatch  = 0x0800,
   MiiErr       = 0x0400,
};

enum RxConfigBits {
   RxFullDx    = 0x80000000,
   RxEnb       = 0x40000000,
   RxSmall     = 0x20000000,
   RxHuge      = 0x10000000,
   RxErr       = 0x08000000,
   RxAllphys   = 0x04000000,
   RxMulticast = 0x02000000,
   RxBroadcast = 0x01000000,
   RxLoopBack  = (1 << 23) | (1 << 22),
   LowThresholdShift  = 12,
   HighThresholdShift = 2,
};

enum TxConfigBits {
   TxFullDx       = 0x80000000,
   TxEnb          = 0x40000000,
   TxEnbPad       = 0x20000000,
   TxEnbHuge      = 0x10000000,
   TxEnbFCS       = 0x08000000,
   TxNoBackOff    = 0x04000000,
   TxEnbPrem      = 0x02000000,
   TxCareLostCrs  = 0x1000000,
   TxExdCollNum   = 0xf00000,
   TxDataRate     = 0x80000,
};

enum PhyCtrlconfigbits {
   PhyCtrlAne         = 0x80000000,
   PhyCtrlSpd100      = 0x40000000,
   PhyCtrlSpd10       = 0x20000000,
   PhyCtrlPhyBaseAddr = 0x1f000000,
   PhyCtrlDux         = 0x800000,
   PhyCtrlReset       = 0x400000,
};

enum FlowCtrlConfigBits {
   FlowCtrlFullDX = 0x80000000,
   FlowCtrlEnb    = 0x40000000,
};

enum Config0Bits {
   Cfg0_Reset  = 0x80000000,
   Cfg0_Anaoff = 0x40000000,
   Cfg0_LDPS   = 0x20000000,
};

enum Config1Bits {
   Cfg1_EarlyRx = 1 << 31,
   Cfg1_EarlyTx = 1 << 30,

   //rx buffer size
   Cfg1_Rcv8K   = 0x0,
   Cfg1_Rcv16K  = 0x1,
   Cfg1_Rcv32K  = 0x3,
   Cfg1_Rcv64K  = 0x7,
   Cfg1_Rcv128K = 0xf,
};

enum MiiCmd0Bits {
   Mii_Divider = 0x20000000,
   Mii_WRITE   = 0x400000,
   Mii_READ    = 0x200000,
   Mii_SCAN    = 0x100000,
   Mii_Tamod   = 0x80000,
   Mii_Drvmod  = 0x40000,
   Mii_mdc     = 0x20000,
   Mii_mdoen   = 0x10000,
   Mii_mdo     = 0x8000,
   Mii_mdi     = 0x4000,
};

enum MiiStatusBits {
    Mii_StatusBusy = 0x80000000,
};

enum PMConfigBits {
   PM_Enable  = 1 << 31,
   PM_LongWF  = 1 << 30,
   PM_Magic   = 1 << 29,
   PM_LANWake = 1 << 28,
   PM_LWPTN   = (1 << 27 | 1<< 26),
   PM_LinkUp  = 1 << 25,
   PM_WakeUp  = 1 << 24,
};

/* Locking rules:
 * priv->lock protects most of the fields of priv and most of the
 * hardware registers. It does not have to protect against softirqs
 * between sc92031_disable_interrupts and sc92031_enable_interrupts;
 * it also does not need to be used in ->open and ->stop while the
 * device interrupts are off.
 * Not having to protect against softirqs is very useful due to heavy
 * use of mdelay() at _sc92031_reset.
 * Functions prefixed with _sc92031_ must be called with the lock held;
 * functions prefixed with sc92031_ must be called without the lock held.
 * Use mmiowb() before unlocking if the hardware was written to.
 */

/* Locking rules for the interrupt:
 * - the interrupt and the tasklet never run at the same time
 * - neither run between sc92031_disable_interrupts and
 *   sc92031_enable_interrupt
 */

struct sc92031_priv {
	spinlock_t		lock;
	/* iomap.h cookie */
	void __iomem		*port_base;
	/* pci device structure */
	struct pci_dev		*pdev;
	/* tasklet */
	struct tasklet_struct	tasklet;

	/* CPU address of rx ring */
	void			*rx_ring;
	/* PCI address of rx ring */
	dma_addr_t		rx_ring_dma_addr;
	/* PCI address of rx ring read pointer */
	dma_addr_t		rx_ring_tail;

	/* tx ring write index */
	unsigned		tx_head;
	/* tx ring read index */
	unsigned		tx_tail;
	/* CPU address of tx bounce buffer */
	void			*tx_bufs;
	/* PCI address of tx bounce buffer */
	dma_addr_t		tx_bufs_dma_addr;

	/* copies of some hardware registers */
	u32			intr_status;
	atomic_t		intr_mask;
	u32			rx_config;
	u32			tx_config;
	u32			pm_config;

	/* copy of some flags from dev->flags */
	unsigned int		mc_flags;

	/* for ETHTOOL_GSTATS */
	u64			tx_timeouts;
	u64			rx_loss;

	/* for dev->get_stats */
	long			rx_value;
};

/* I don't know which registers can be safely read; however, I can guess
 * MAC0 is one of them. */
static inline void _sc92031_dummy_read(void __iomem *port_base)
{
	ioread32(port_base + MAC0);
}

static u32 _sc92031_mii_wait(void __iomem *port_base)
{
	u32 mii_status;

	do {
		udelay(10);
		mii_status = ioread32(port_base + Miistatus);
	} while (mii_status & Mii_StatusBusy);

	return mii_status;
}

static u32 _sc92031_mii_cmd(void __iomem *port_base, u32 cmd0, u32 cmd1)
{
	iowrite32(Mii_Divider, port_base + Miicmd0);

	_sc92031_mii_wait(port_base);

	iowrite32(cmd1, port_base + Miicmd1);
	iowrite32(Mii_Divider | cmd0, port_base + Miicmd0);

	return _sc92031_mii_wait(port_base);
}

static void _sc92031_mii_scan(void __iomem *port_base)
{
	_sc92031_mii_cmd(port_base, Mii_SCAN, 0x1 << 6);
}

static u16 _sc92031_mii_read(void __iomem *port_base, unsigned reg)
{
	return _sc92031_mii_cmd(port_base, Mii_READ, reg << 6) >> 13;
}

static void _sc92031_mii_write(void __iomem *port_base, unsigned reg, u16 val)
{
	_sc92031_mii_cmd(port_base, Mii_WRITE, (reg << 6) | ((u32)val << 11));
}

static void sc92031_disable_interrupts(struct net_device *dev)
{
	struct sc92031_priv *priv = netdev_priv(dev);
	void __iomem *port_base = priv->port_base;

	/* tell the tasklet/interrupt not to enable interrupts */
	atomic_set(&priv->intr_mask, 0);
	wmb();

	/* stop interrupts */
	iowrite32(0, port_base + IntrMask);
	_sc92031_dummy_read(port_base);
	mmiowb();

	/* wait for any concurrent interrupt/tasklet to finish */
367
	synchronize_irq(priv->pdev->irq);
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
	tasklet_disable(&priv->tasklet);
}

static void sc92031_enable_interrupts(struct net_device *dev)
{
	struct sc92031_priv *priv = netdev_priv(dev);
	void __iomem *port_base = priv->port_base;

	tasklet_enable(&priv->tasklet);

	atomic_set(&priv->intr_mask, IntrBits);
	wmb();

	iowrite32(IntrBits, port_base + IntrMask);
	mmiowb();
}

static void _sc92031_disable_tx_rx(struct net_device *dev)
{
	struct sc92031_priv *priv = netdev_priv(dev);
	void __iomem *port_base = priv->port_base;

	priv->rx_config &= ~RxEnb;
	priv->tx_config &= ~TxEnb;
	iowrite32(priv->rx_config, port_base + RxConfig);
	iowrite32(priv->tx_config, port_base + TxConfig);
}

static void _sc92031_enable_tx_rx(struct net_device *dev)
{
	struct sc92031_priv *priv = netdev_priv(dev);
	void __iomem *port_base = priv->port_base;

	priv->rx_config |= RxEnb;
	priv->tx_config |= TxEnb;
	iowrite32(priv->rx_config, port_base + RxConfig);
	iowrite32(priv->tx_config, port_base + TxConfig);
}

static void _sc92031_tx_clear(struct net_device *dev)
{
	struct sc92031_priv *priv = netdev_priv(dev);

	while (priv->tx_head - priv->tx_tail > 0) {
		priv->tx_tail++;
413
		dev->stats.tx_dropped++;
414 415 416 417 418 419 420 421 422 423
	}
	priv->tx_head = priv->tx_tail = 0;
}

static void _sc92031_set_mar(struct net_device *dev)
{
	struct sc92031_priv *priv = netdev_priv(dev);
	void __iomem *port_base = priv->port_base;
	u32 mar0 = 0, mar1 = 0;

424
	if ((dev->flags & IFF_PROMISC) ||
425
	    netdev_mc_count(dev) > multicast_filter_limit ||
426
	    (dev->flags & IFF_ALLMULTI))
427 428
		mar0 = mar1 = 0xffffffff;
	else if (dev->flags & IFF_MULTICAST) {
429
		struct netdev_hw_addr *ha;
430

431
		netdev_for_each_mc_addr(ha, dev) {
432 433 434
			u32 crc;
			unsigned bit = 0;

435
			crc = ~ether_crc(ETH_ALEN, ha->addr);
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667
			crc >>= 24;

			if (crc & 0x01)	bit |= 0x02;
			if (crc & 0x02)	bit |= 0x01;
			if (crc & 0x10)	bit |= 0x20;
			if (crc & 0x20)	bit |= 0x10;
			if (crc & 0x40)	bit |= 0x08;
			if (crc & 0x80)	bit |= 0x04;

			if (bit > 31)
				mar0 |= 0x1 << (bit - 32);
			else
				mar1 |= 0x1 << bit;
		}
	}

	iowrite32(mar0, port_base + MAR0);
	iowrite32(mar1, port_base + MAR0 + 4);
}

static void _sc92031_set_rx_config(struct net_device *dev)
{
	struct sc92031_priv *priv = netdev_priv(dev);
	void __iomem *port_base = priv->port_base;
	unsigned int old_mc_flags;
	u32 rx_config_bits = 0;

	old_mc_flags = priv->mc_flags;

	if (dev->flags & IFF_PROMISC)
		rx_config_bits |= RxSmall | RxHuge | RxErr | RxBroadcast
				| RxMulticast | RxAllphys;

	if (dev->flags & (IFF_ALLMULTI | IFF_MULTICAST))
		rx_config_bits |= RxMulticast;

	if (dev->flags & IFF_BROADCAST)
		rx_config_bits |= RxBroadcast;

	priv->rx_config &= ~(RxSmall | RxHuge | RxErr | RxBroadcast
			| RxMulticast | RxAllphys);
	priv->rx_config |= rx_config_bits;

	priv->mc_flags = dev->flags & (IFF_PROMISC | IFF_ALLMULTI
			| IFF_MULTICAST | IFF_BROADCAST);

	if (netif_carrier_ok(dev) && priv->mc_flags != old_mc_flags)
		iowrite32(priv->rx_config, port_base + RxConfig);
}

static bool _sc92031_check_media(struct net_device *dev)
{
	struct sc92031_priv *priv = netdev_priv(dev);
	void __iomem *port_base = priv->port_base;
	u16 bmsr;

	bmsr = _sc92031_mii_read(port_base, MII_BMSR);
	rmb();
	if (bmsr & BMSR_LSTATUS) {
		bool speed_100, duplex_full;
		u32 flow_ctrl_config = 0;
		u16 output_status = _sc92031_mii_read(port_base,
				MII_OutputStatus);
		_sc92031_mii_scan(port_base);

		speed_100 = output_status & 0x2;
		duplex_full = output_status & 0x4;

		/* Initial Tx/Rx configuration */
		priv->rx_config = (0x40 << LowThresholdShift) | (0x1c0 << HighThresholdShift);
		priv->tx_config = 0x48800000;

		/* NOTE: vendor driver had dead code here to enable tx padding */

		if (!speed_100)
			priv->tx_config |= 0x80000;

		// configure rx mode
		_sc92031_set_rx_config(dev);

		if (duplex_full) {
			priv->rx_config |= RxFullDx;
			priv->tx_config |= TxFullDx;
			flow_ctrl_config = FlowCtrlFullDX | FlowCtrlEnb;
		} else {
			priv->rx_config &= ~RxFullDx;
			priv->tx_config &= ~TxFullDx;
		}

		_sc92031_set_mar(dev);
		_sc92031_set_rx_config(dev);
		_sc92031_enable_tx_rx(dev);
		iowrite32(flow_ctrl_config, port_base + FlowCtrlConfig);

		netif_carrier_on(dev);

		if (printk_ratelimit())
			printk(KERN_INFO "%s: link up, %sMbps, %s-duplex\n",
				dev->name,
				speed_100 ? "100" : "10",
				duplex_full ? "full" : "half");
		return true;
	} else {
		_sc92031_mii_scan(port_base);

		netif_carrier_off(dev);

		_sc92031_disable_tx_rx(dev);

		if (printk_ratelimit())
			printk(KERN_INFO "%s: link down\n", dev->name);
		return false;
	}
}

static void _sc92031_phy_reset(struct net_device *dev)
{
	struct sc92031_priv *priv = netdev_priv(dev);
	void __iomem *port_base = priv->port_base;
	u32 phy_ctrl;

	phy_ctrl = ioread32(port_base + PhyCtrl);
	phy_ctrl &= ~(PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10);
	phy_ctrl |= PhyCtrlAne | PhyCtrlReset;

	switch (media) {
	default:
	case AUTOSELECT:
		phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10;
		break;
	case M10_HALF:
		phy_ctrl |= PhyCtrlSpd10;
		break;
	case M10_FULL:
		phy_ctrl |= PhyCtrlDux | PhyCtrlSpd10;
		break;
	case M100_HALF:
		phy_ctrl |= PhyCtrlSpd100;
		break;
	case M100_FULL:
		phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100;
		break;
	}

	iowrite32(phy_ctrl, port_base + PhyCtrl);
	mdelay(10);

	phy_ctrl &= ~PhyCtrlReset;
	iowrite32(phy_ctrl, port_base + PhyCtrl);
	mdelay(1);

	_sc92031_mii_write(port_base, MII_JAB,
			PHY_16_JAB_ENB | PHY_16_PORT_ENB);
	_sc92031_mii_scan(port_base);

	netif_carrier_off(dev);
	netif_stop_queue(dev);
}

static void _sc92031_reset(struct net_device *dev)
{
	struct sc92031_priv *priv = netdev_priv(dev);
	void __iomem *port_base = priv->port_base;

	/* disable PM */
	iowrite32(0, port_base + PMConfig);

	/* soft reset the chip */
	iowrite32(Cfg0_Reset, port_base + Config0);
	mdelay(200);

	iowrite32(0, port_base + Config0);
	mdelay(10);

	/* disable interrupts */
	iowrite32(0, port_base + IntrMask);

	/* clear multicast address */
	iowrite32(0, port_base + MAR0);
	iowrite32(0, port_base + MAR0 + 4);

	/* init rx ring */
	iowrite32(priv->rx_ring_dma_addr, port_base + RxbufAddr);
	priv->rx_ring_tail = priv->rx_ring_dma_addr;

	/* init tx ring */
	_sc92031_tx_clear(dev);

	/* clear old register values */
	priv->intr_status = 0;
	atomic_set(&priv->intr_mask, 0);
	priv->rx_config = 0;
	priv->tx_config = 0;
	priv->mc_flags = 0;

	/* configure rx buffer size */
	/* NOTE: vendor driver had dead code here to enable early tx/rx */
	iowrite32(Cfg1_Rcv64K, port_base + Config1);

	_sc92031_phy_reset(dev);
	_sc92031_check_media(dev);

	/* calculate rx fifo overflow */
	priv->rx_value = 0;

	/* enable PM */
	iowrite32(priv->pm_config, port_base + PMConfig);

	/* clear intr register */
	ioread32(port_base + IntrStatus);
}

static void _sc92031_tx_tasklet(struct net_device *dev)
{
	struct sc92031_priv *priv = netdev_priv(dev);
	void __iomem *port_base = priv->port_base;

	unsigned old_tx_tail;
	unsigned entry;
	u32 tx_status;

	old_tx_tail = priv->tx_tail;
	while (priv->tx_head - priv->tx_tail > 0) {
		entry = priv->tx_tail % NUM_TX_DESC;
		tx_status = ioread32(port_base + TxStatus0 + entry * 4);

		if (!(tx_status & (TxStatOK | TxUnderrun | TxAborted)))
			break;

		priv->tx_tail++;

		if (tx_status & TxStatOK) {
668 669
			dev->stats.tx_bytes += tx_status & 0x1fff;
			dev->stats.tx_packets++;
670
			/* Note: TxCarrierLost is always asserted at 100mbps. */
671
			dev->stats.collisions += (tx_status >> 22) & 0xf;
672 673 674
		}

		if (tx_status & (TxOutOfWindow | TxAborted)) {
675
			dev->stats.tx_errors++;
676 677

			if (tx_status & TxAborted)
678
				dev->stats.tx_aborted_errors++;
679 680

			if (tx_status & TxCarrierLost)
681
				dev->stats.tx_carrier_errors++;
682 683

			if (tx_status & TxOutOfWindow)
684
				dev->stats.tx_window_errors++;
685 686 687
		}

		if (tx_status & TxUnderrun)
688
			dev->stats.tx_fifo_errors++;
689 690 691 692 693 694 695
	}

	if (priv->tx_tail != old_tx_tail)
		if (netif_queue_stopped(dev))
			netif_wake_queue(dev);
}

696 697
static void _sc92031_rx_tasklet_error(struct net_device *dev,
				      u32 rx_status, unsigned rx_size)
698 699
{
	if(rx_size > (MAX_ETH_FRAME_SIZE + 4) || rx_size < 16) {
700 701
		dev->stats.rx_errors++;
		dev->stats.rx_length_errors++;
702 703 704
	}

	if (!(rx_status & RxStatesOK)) {
705
		dev->stats.rx_errors++;
706 707

		if (rx_status & (RxHugeFrame | RxSmallFrame))
708
			dev->stats.rx_length_errors++;
709 710

		if (rx_status & RxBadAlign)
711
			dev->stats.rx_frame_errors++;
712 713

		if (!(rx_status & RxCRCOK))
714 715 716
			dev->stats.rx_crc_errors++;
	} else {
		struct sc92031_priv *priv = netdev_priv(dev);
717
		priv->rx_loss++;
718
	}
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772
}

static void _sc92031_rx_tasklet(struct net_device *dev)
{
	struct sc92031_priv *priv = netdev_priv(dev);
	void __iomem *port_base = priv->port_base;

	dma_addr_t rx_ring_head;
	unsigned rx_len;
	unsigned rx_ring_offset;
	void *rx_ring = priv->rx_ring;

	rx_ring_head = ioread32(port_base + RxBufWPtr);
	rmb();

	/* rx_ring_head is only 17 bits in the RxBufWPtr register.
	 * we need to change it to 32 bits physical address
	 */
	rx_ring_head &= (dma_addr_t)(RX_BUF_LEN - 1);
	rx_ring_head |= priv->rx_ring_dma_addr & ~(dma_addr_t)(RX_BUF_LEN - 1);
	if (rx_ring_head < priv->rx_ring_dma_addr)
		rx_ring_head += RX_BUF_LEN;

	if (rx_ring_head >= priv->rx_ring_tail)
		rx_len = rx_ring_head - priv->rx_ring_tail;
	else
		rx_len = RX_BUF_LEN - (priv->rx_ring_tail - rx_ring_head);

	if (!rx_len)
		return;

	if (unlikely(rx_len > RX_BUF_LEN)) {
		if (printk_ratelimit())
			printk(KERN_ERR "%s: rx packets length > rx buffer\n",
					dev->name);
		return;
	}

	rx_ring_offset = (priv->rx_ring_tail - priv->rx_ring_dma_addr) % RX_BUF_LEN;

	while (rx_len) {
		u32 rx_status;
		unsigned rx_size, rx_size_align, pkt_size;
		struct sk_buff *skb;

		rx_status = le32_to_cpup((__le32 *)(rx_ring + rx_ring_offset));
		rmb();

		rx_size = rx_status >> 20;
		rx_size_align = (rx_size + 3) & ~3;	// for 4 bytes aligned
		pkt_size = rx_size - 4;	// Omit the four octet CRC from the length.

		rx_ring_offset = (rx_ring_offset + 4) % RX_BUF_LEN;

773 774 775 776
		if (unlikely(rx_status == 0 ||
			     rx_size > (MAX_ETH_FRAME_SIZE + 4) ||
			     rx_size < 16 ||
			     !(rx_status & RxStatesOK))) {
777
			_sc92031_rx_tasklet_error(dev, rx_status, rx_size);
778 779 780 781 782 783 784 785 786 787 788
			break;
		}

		if (unlikely(rx_size_align + 4 > rx_len)) {
			if (printk_ratelimit())
				printk(KERN_ERR "%s: rx_len is too small\n", dev->name);
			break;
		}

		rx_len -= rx_size_align + 4;

789
		skb = netdev_alloc_skb_ip_align(dev, pkt_size);
790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808
		if (unlikely(!skb)) {
			if (printk_ratelimit())
				printk(KERN_ERR "%s: Couldn't allocate a skb_buff for a packet of size %u\n",
						dev->name, pkt_size);
			goto next;
		}

		if ((rx_ring_offset + pkt_size) > RX_BUF_LEN) {
			memcpy(skb_put(skb, RX_BUF_LEN - rx_ring_offset),
				rx_ring + rx_ring_offset, RX_BUF_LEN - rx_ring_offset);
			memcpy(skb_put(skb, pkt_size - (RX_BUF_LEN - rx_ring_offset)),
				rx_ring, pkt_size - (RX_BUF_LEN - rx_ring_offset));
		} else {
			memcpy(skb_put(skb, pkt_size), rx_ring + rx_ring_offset, pkt_size);
		}

		skb->protocol = eth_type_trans(skb, dev);
		netif_rx(skb);

809 810
		dev->stats.rx_bytes += pkt_size;
		dev->stats.rx_packets++;
811 812

		if (rx_status & Rx_Multicast)
813
			dev->stats.multicast++;
814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829

	next:
		rx_ring_offset = (rx_ring_offset + rx_size_align) % RX_BUF_LEN;
	}
	mb();

	priv->rx_ring_tail = rx_ring_head;
	iowrite32(priv->rx_ring_tail, port_base + RxBufRPtr);
}

static void _sc92031_link_tasklet(struct net_device *dev)
{
	if (_sc92031_check_media(dev))
		netif_wake_queue(dev);
	else {
		netif_stop_queue(dev);
830
		dev->stats.tx_carrier_errors++;
831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854
	}
}

static void sc92031_tasklet(unsigned long data)
{
	struct net_device *dev = (struct net_device *)data;
	struct sc92031_priv *priv = netdev_priv(dev);
	void __iomem *port_base = priv->port_base;
	u32 intr_status, intr_mask;

	intr_status = priv->intr_status;

	spin_lock(&priv->lock);

	if (unlikely(!netif_running(dev)))
		goto out;

	if (intr_status & TxOK)
		_sc92031_tx_tasklet(dev);

	if (intr_status & RxOK)
		_sc92031_rx_tasklet(dev);

	if (intr_status & RxOverflow)
855
		dev->stats.rx_errors++;
856 857

	if (intr_status & TimeOut) {
858 859
		dev->stats.rx_errors++;
		dev->stats.rx_length_errors++;
860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924
	}

	if (intr_status & (LinkFail | LinkOK))
		_sc92031_link_tasklet(dev);

out:
	intr_mask = atomic_read(&priv->intr_mask);
	rmb();

	iowrite32(intr_mask, port_base + IntrMask);
	mmiowb();

	spin_unlock(&priv->lock);
}

static irqreturn_t sc92031_interrupt(int irq, void *dev_id)
{
	struct net_device *dev = dev_id;
	struct sc92031_priv *priv = netdev_priv(dev);
	void __iomem *port_base = priv->port_base;
	u32 intr_status, intr_mask;

	/* mask interrupts before clearing IntrStatus */
	iowrite32(0, port_base + IntrMask);
	_sc92031_dummy_read(port_base);

	intr_status = ioread32(port_base + IntrStatus);
	if (unlikely(intr_status == 0xffffffff))
		return IRQ_NONE;	// hardware has gone missing

	intr_status &= IntrBits;
	if (!intr_status)
		goto out_none;

	priv->intr_status = intr_status;
	tasklet_schedule(&priv->tasklet);

	return IRQ_HANDLED;

out_none:
	intr_mask = atomic_read(&priv->intr_mask);
	rmb();

	iowrite32(intr_mask, port_base + IntrMask);
	mmiowb();

	return IRQ_NONE;
}

static struct net_device_stats *sc92031_get_stats(struct net_device *dev)
{
	struct sc92031_priv *priv = netdev_priv(dev);
	void __iomem *port_base = priv->port_base;

	// FIXME I do not understand what is this trying to do.
	if (netif_running(dev)) {
		int temp;

		spin_lock_bh(&priv->lock);

		/* Update the error count. */
		temp = (ioread32(port_base + RxStatus0) >> 16) & 0xffff;

		if (temp == 0xffff) {
			priv->rx_value += temp;
925 926 927
			dev->stats.rx_fifo_errors = priv->rx_value;
		} else
			dev->stats.rx_fifo_errors = temp + priv->rx_value;
928 929 930 931

		spin_unlock_bh(&priv->lock);
	}

932
	return &dev->stats;
933 934
}

935 936
static netdev_tx_t sc92031_start_xmit(struct sk_buff *skb,
				      struct net_device *dev)
937 938 939 940 941 942 943 944
{
	struct sc92031_priv *priv = netdev_priv(dev);
	void __iomem *port_base = priv->port_base;
	unsigned len;
	unsigned entry;
	u32 tx_status;

	if (unlikely(skb->len > TX_BUF_SIZE)) {
945
		dev->stats.tx_dropped++;
946 947 948
		goto out;
	}

H
Herbert Xu 已提交
949
	spin_lock(&priv->lock);
950 951

	if (unlikely(!netif_carrier_ok(dev))) {
952
		dev->stats.tx_dropped++;
953 954 955 956 957 958 959 960 961 962
		goto out_unlock;
	}

	BUG_ON(priv->tx_head - priv->tx_tail >= NUM_TX_DESC);

	entry = priv->tx_head++ % NUM_TX_DESC;

	skb_copy_and_csum_dev(skb, priv->tx_bufs + entry * TX_BUF_SIZE);

	len = skb->len;
963
	if (len < ETH_ZLEN) {
964 965 966 967
		memset(priv->tx_bufs + entry * TX_BUF_SIZE + len,
				0, ETH_ZLEN - len);
		len = ETH_ZLEN;
	}
968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986

	wmb();

	if (len < 100)
		tx_status = len;
	else if (len < 300)
		tx_status = 0x30000 | len;
	else
		tx_status = 0x50000 | len;

	iowrite32(priv->tx_bufs_dma_addr + entry * TX_BUF_SIZE,
			port_base + TxAddr0 + entry * 4);
	iowrite32(tx_status, port_base + TxStatus0 + entry * 4);
	mmiowb();

	if (priv->tx_head - priv->tx_tail >= NUM_TX_DESC)
		netif_stop_queue(dev);

out_unlock:
H
Herbert Xu 已提交
987
	spin_unlock(&priv->lock);
988 989 990 991

out:
	dev_kfree_skb(skb);

992
	return NETDEV_TX_OK;
993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
}

static int sc92031_open(struct net_device *dev)
{
	int err;
	struct sc92031_priv *priv = netdev_priv(dev);
	struct pci_dev *pdev = priv->pdev;

	priv->rx_ring = pci_alloc_consistent(pdev, RX_BUF_LEN,
			&priv->rx_ring_dma_addr);
	if (unlikely(!priv->rx_ring)) {
		err = -ENOMEM;
		goto out_alloc_rx_ring;
	}

	priv->tx_bufs = pci_alloc_consistent(pdev, TX_BUF_TOT_LEN,
			&priv->tx_bufs_dma_addr);
	if (unlikely(!priv->tx_bufs)) {
		err = -ENOMEM;
		goto out_alloc_tx_bufs;
	}
	priv->tx_head = priv->tx_tail = 0;

	err = request_irq(pdev->irq, sc92031_interrupt,
1017
			IRQF_SHARED, dev->name, dev);
1018 1019 1020 1021 1022 1023
	if (unlikely(err < 0))
		goto out_request_irq;

	priv->pm_config = 0;

	/* Interrupts already disabled by sc92031_stop or sc92031_probe */
H
Herbert Xu 已提交
1024
	spin_lock_bh(&priv->lock);
1025 1026 1027 1028

	_sc92031_reset(dev);
	mmiowb();

H
Herbert Xu 已提交
1029
	spin_unlock_bh(&priv->lock);
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058
	sc92031_enable_interrupts(dev);

	if (netif_carrier_ok(dev))
		netif_start_queue(dev);
	else
		netif_tx_disable(dev);

	return 0;

out_request_irq:
	pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs,
			priv->tx_bufs_dma_addr);
out_alloc_tx_bufs:
	pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring,
			priv->rx_ring_dma_addr);
out_alloc_rx_ring:
	return err;
}

static int sc92031_stop(struct net_device *dev)
{
	struct sc92031_priv *priv = netdev_priv(dev);
	struct pci_dev *pdev = priv->pdev;

	netif_tx_disable(dev);

	/* Disable interrupts, stop Tx and Rx. */
	sc92031_disable_interrupts(dev);

H
Herbert Xu 已提交
1059
	spin_lock_bh(&priv->lock);
1060 1061 1062 1063 1064

	_sc92031_disable_tx_rx(dev);
	_sc92031_tx_clear(dev);
	mmiowb();

H
Herbert Xu 已提交
1065
	spin_unlock_bh(&priv->lock);
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114

	free_irq(pdev->irq, dev);
	pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs,
			priv->tx_bufs_dma_addr);
	pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring,
			priv->rx_ring_dma_addr);

	return 0;
}

static void sc92031_set_multicast_list(struct net_device *dev)
{
	struct sc92031_priv *priv = netdev_priv(dev);

	spin_lock_bh(&priv->lock);

	_sc92031_set_mar(dev);
	_sc92031_set_rx_config(dev);
	mmiowb();

	spin_unlock_bh(&priv->lock);
}

static void sc92031_tx_timeout(struct net_device *dev)
{
	struct sc92031_priv *priv = netdev_priv(dev);

	/* Disable interrupts by clearing the interrupt mask.*/
	sc92031_disable_interrupts(dev);

	spin_lock(&priv->lock);

	priv->tx_timeouts++;

	_sc92031_reset(dev);
	mmiowb();

	spin_unlock(&priv->lock);

	/* enable interrupts */
	sc92031_enable_interrupts(dev);

	if (netif_carrier_ok(dev))
		netif_wake_queue(dev);
}

#ifdef CONFIG_NET_POLL_CONTROLLER
static void sc92031_poll_controller(struct net_device *dev)
{
1115 1116 1117 1118 1119
	struct sc92031_priv *priv = netdev_priv(dev);
	const int irq = priv->pdev->irq;

	disable_irq(irq);
	if (sc92031_interrupt(irq, dev) != IRQ_NONE)
1120
		sc92031_tasklet((unsigned long)dev);
1121
	enable_irq(irq);
1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171
}
#endif

static int sc92031_ethtool_get_settings(struct net_device *dev,
		struct ethtool_cmd *cmd)
{
	struct sc92031_priv *priv = netdev_priv(dev);
	void __iomem *port_base = priv->port_base;
	u8 phy_address;
	u32 phy_ctrl;
	u16 output_status;

	spin_lock_bh(&priv->lock);

	phy_address = ioread32(port_base + Miicmd1) >> 27;
	phy_ctrl = ioread32(port_base + PhyCtrl);

	output_status = _sc92031_mii_read(port_base, MII_OutputStatus);
	_sc92031_mii_scan(port_base);
	mmiowb();

	spin_unlock_bh(&priv->lock);

	cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full
			| SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full
			| SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII;

	cmd->advertising = ADVERTISED_TP | ADVERTISED_MII;

	if ((phy_ctrl & (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10))
			== (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10))
		cmd->advertising |= ADVERTISED_Autoneg;

	if ((phy_ctrl & PhyCtrlSpd10) == PhyCtrlSpd10)
		cmd->advertising |= ADVERTISED_10baseT_Half;

	if ((phy_ctrl & (PhyCtrlSpd10 | PhyCtrlDux))
			== (PhyCtrlSpd10 | PhyCtrlDux))
		cmd->advertising |= ADVERTISED_10baseT_Full;

	if ((phy_ctrl & PhyCtrlSpd100) == PhyCtrlSpd100)
		cmd->advertising |= ADVERTISED_100baseT_Half;

	if ((phy_ctrl & (PhyCtrlSpd100 | PhyCtrlDux))
			== (PhyCtrlSpd100 | PhyCtrlDux))
		cmd->advertising |= ADVERTISED_100baseT_Full;

	if (phy_ctrl & PhyCtrlAne)
		cmd->advertising |= ADVERTISED_Autoneg;

1172 1173
	ethtool_cmd_speed_set(cmd,
			      (output_status & 0x2) ? SPEED_100 : SPEED_10);
1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187
	cmd->duplex = (output_status & 0x4) ? DUPLEX_FULL : DUPLEX_HALF;
	cmd->port = PORT_MII;
	cmd->phy_address = phy_address;
	cmd->transceiver = XCVR_INTERNAL;
	cmd->autoneg = (phy_ctrl & PhyCtrlAne) ? AUTONEG_ENABLE : AUTONEG_DISABLE;

	return 0;
}

static int sc92031_ethtool_set_settings(struct net_device *dev,
		struct ethtool_cmd *cmd)
{
	struct sc92031_priv *priv = netdev_priv(dev);
	void __iomem *port_base = priv->port_base;
1188
	u32 speed = ethtool_cmd_speed(cmd);
1189 1190 1191
	u32 phy_ctrl;
	u32 old_phy_ctrl;

1192
	if (!(speed == SPEED_10 || speed == SPEED_100))
1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229
		return -EINVAL;
	if (!(cmd->duplex == DUPLEX_HALF || cmd->duplex == DUPLEX_FULL))
		return -EINVAL;
	if (!(cmd->port == PORT_MII))
		return -EINVAL;
	if (!(cmd->phy_address == 0x1f))
		return -EINVAL;
	if (!(cmd->transceiver == XCVR_INTERNAL))
		return -EINVAL;
	if (!(cmd->autoneg == AUTONEG_DISABLE || cmd->autoneg == AUTONEG_ENABLE))
		return -EINVAL;

	if (cmd->autoneg == AUTONEG_ENABLE) {
		if (!(cmd->advertising & (ADVERTISED_Autoneg
				| ADVERTISED_100baseT_Full
				| ADVERTISED_100baseT_Half
				| ADVERTISED_10baseT_Full
				| ADVERTISED_10baseT_Half)))
			return -EINVAL;

		phy_ctrl = PhyCtrlAne;

		// FIXME: I'm not sure what the original code was trying to do
		if (cmd->advertising & ADVERTISED_Autoneg)
			phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10;
		if (cmd->advertising & ADVERTISED_100baseT_Full)
			phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100;
		if (cmd->advertising & ADVERTISED_100baseT_Half)
			phy_ctrl |= PhyCtrlSpd100;
		if (cmd->advertising & ADVERTISED_10baseT_Full)
			phy_ctrl |= PhyCtrlSpd10 | PhyCtrlDux;
		if (cmd->advertising & ADVERTISED_10baseT_Half)
			phy_ctrl |= PhyCtrlSpd10;
	} else {
		// FIXME: Whole branch guessed
		phy_ctrl = 0;

1230
		if (speed == SPEED_10)
1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348
			phy_ctrl |= PhyCtrlSpd10;
		else /* cmd->speed == SPEED_100 */
			phy_ctrl |= PhyCtrlSpd100;

		if (cmd->duplex == DUPLEX_FULL)
			phy_ctrl |= PhyCtrlDux;
	}

	spin_lock_bh(&priv->lock);

	old_phy_ctrl = ioread32(port_base + PhyCtrl);
	phy_ctrl |= old_phy_ctrl & ~(PhyCtrlAne | PhyCtrlDux
			| PhyCtrlSpd100 | PhyCtrlSpd10);
	if (phy_ctrl != old_phy_ctrl)
		iowrite32(phy_ctrl, port_base + PhyCtrl);

	spin_unlock_bh(&priv->lock);

	return 0;
}

static void sc92031_ethtool_get_wol(struct net_device *dev,
		struct ethtool_wolinfo *wolinfo)
{
	struct sc92031_priv *priv = netdev_priv(dev);
	void __iomem *port_base = priv->port_base;
	u32 pm_config;

	spin_lock_bh(&priv->lock);
	pm_config = ioread32(port_base + PMConfig);
	spin_unlock_bh(&priv->lock);

	// FIXME: Guessed
	wolinfo->supported = WAKE_PHY | WAKE_MAGIC
			| WAKE_UCAST | WAKE_MCAST | WAKE_BCAST;
	wolinfo->wolopts = 0;

	if (pm_config & PM_LinkUp)
		wolinfo->wolopts |= WAKE_PHY;

	if (pm_config & PM_Magic)
		wolinfo->wolopts |= WAKE_MAGIC;

	if (pm_config & PM_WakeUp)
		// FIXME: Guessed
		wolinfo->wolopts |= WAKE_UCAST | WAKE_MCAST | WAKE_BCAST;
}

static int sc92031_ethtool_set_wol(struct net_device *dev,
		struct ethtool_wolinfo *wolinfo)
{
	struct sc92031_priv *priv = netdev_priv(dev);
	void __iomem *port_base = priv->port_base;
	u32 pm_config;

	spin_lock_bh(&priv->lock);

	pm_config = ioread32(port_base + PMConfig)
			& ~(PM_LinkUp | PM_Magic | PM_WakeUp);

	if (wolinfo->wolopts & WAKE_PHY)
		pm_config |= PM_LinkUp;

	if (wolinfo->wolopts & WAKE_MAGIC)
		pm_config |= PM_Magic;

	// FIXME: Guessed
	if (wolinfo->wolopts & (WAKE_UCAST | WAKE_MCAST | WAKE_BCAST))
		pm_config |= PM_WakeUp;

	priv->pm_config = pm_config;
	iowrite32(pm_config, port_base + PMConfig);
	mmiowb();

	spin_unlock_bh(&priv->lock);

	return 0;
}

static int sc92031_ethtool_nway_reset(struct net_device *dev)
{
	int err = 0;
	struct sc92031_priv *priv = netdev_priv(dev);
	void __iomem *port_base = priv->port_base;
	u16 bmcr;

	spin_lock_bh(&priv->lock);

	bmcr = _sc92031_mii_read(port_base, MII_BMCR);
	if (!(bmcr & BMCR_ANENABLE)) {
		err = -EINVAL;
		goto out;
	}

	_sc92031_mii_write(port_base, MII_BMCR, bmcr | BMCR_ANRESTART);

out:
	_sc92031_mii_scan(port_base);
	mmiowb();

	spin_unlock_bh(&priv->lock);

	return err;
}

static const char sc92031_ethtool_stats_strings[SILAN_STATS_NUM][ETH_GSTRING_LEN] = {
	"tx_timeout",
	"rx_loss",
};

static void sc92031_ethtool_get_strings(struct net_device *dev,
		u32 stringset, u8 *data)
{
	if (stringset == ETH_SS_STATS)
		memcpy(data, sc92031_ethtool_stats_strings,
				SILAN_STATS_NUM * ETH_GSTRING_LEN);
}

1349
static int sc92031_ethtool_get_sset_count(struct net_device *dev, int sset)
1350
{
1351 1352 1353 1354 1355 1356
	switch (sset) {
	case ETH_SS_STATS:
		return SILAN_STATS_NUM;
	default:
		return -EOPNOTSUPP;
	}
1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369
}

static void sc92031_ethtool_get_ethtool_stats(struct net_device *dev,
		struct ethtool_stats *stats, u64 *data)
{
	struct sc92031_priv *priv = netdev_priv(dev);

	spin_lock_bh(&priv->lock);
	data[0] = priv->tx_timeouts;
	data[1] = priv->rx_loss;
	spin_unlock_bh(&priv->lock);
}

1370
static const struct ethtool_ops sc92031_ethtool_ops = {
1371 1372 1373 1374 1375 1376 1377
	.get_settings		= sc92031_ethtool_get_settings,
	.set_settings		= sc92031_ethtool_set_settings,
	.get_wol		= sc92031_ethtool_get_wol,
	.set_wol		= sc92031_ethtool_set_wol,
	.nway_reset		= sc92031_ethtool_nway_reset,
	.get_link		= ethtool_op_get_link,
	.get_strings		= sc92031_ethtool_get_strings,
1378
	.get_sset_count		= sc92031_ethtool_get_sset_count,
1379 1380 1381
	.get_ethtool_stats	= sc92031_ethtool_get_ethtool_stats,
};

1382 1383 1384 1385 1386 1387

static const struct net_device_ops sc92031_netdev_ops = {
	.ndo_get_stats		= sc92031_get_stats,
	.ndo_start_xmit		= sc92031_start_xmit,
	.ndo_open		= sc92031_open,
	.ndo_stop		= sc92031_stop,
1388
	.ndo_set_rx_mode	= sc92031_set_multicast_list,
1389 1390
	.ndo_change_mtu		= eth_change_mtu,
	.ndo_validate_addr	= eth_validate_addr,
1391
	.ndo_set_mac_address 	= eth_mac_addr,
1392 1393 1394 1395 1396 1397
	.ndo_tx_timeout		= sc92031_tx_timeout,
#ifdef CONFIG_NET_POLL_CONTROLLER
	.ndo_poll_controller	= sc92031_poll_controller,
#endif
};

1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412
static int __devinit sc92031_probe(struct pci_dev *pdev,
		const struct pci_device_id *id)
{
	int err;
	void __iomem* port_base;
	struct net_device *dev;
	struct sc92031_priv *priv;
	u32 mac0, mac1;

	err = pci_enable_device(pdev);
	if (unlikely(err < 0))
		goto out_enable_device;

	pci_set_master(pdev);

1413
	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
1414 1415 1416
	if (unlikely(err < 0))
		goto out_set_dma_mask;

1417
	err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
1418 1419 1420 1421 1422 1423 1424
	if (unlikely(err < 0))
		goto out_set_dma_mask;

	err = pci_request_regions(pdev, SC92031_NAME);
	if (unlikely(err < 0))
		goto out_request_regions;

1425
	port_base = pci_iomap(pdev, SC92031_USE_PIO, 0);
1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437
	if (unlikely(!port_base)) {
		err = -EIO;
		goto out_iomap;
	}

	dev = alloc_etherdev(sizeof(struct sc92031_priv));
	if (unlikely(!dev)) {
		err = -ENOMEM;
		goto out_alloc_etherdev;
	}

	pci_set_drvdata(pdev, dev);
S
Stephen Hemminger 已提交
1438
	SET_NETDEV_DEV(dev, &pdev->dev);
1439 1440

	/* faked with skb_copy_and_csum_dev */
1441 1442
	dev->features = NETIF_F_SG | NETIF_F_HIGHDMA |
		NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
1443

1444
	dev->netdev_ops		= &sc92031_netdev_ops;
1445
	dev->watchdog_timeo	= TX_TIMEOUT;
1446
	dev->ethtool_ops	= &sc92031_ethtool_ops;
1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472

	priv = netdev_priv(dev);
	spin_lock_init(&priv->lock);
	priv->port_base = port_base;
	priv->pdev = pdev;
	tasklet_init(&priv->tasklet, sc92031_tasklet, (unsigned long)dev);
	/* Fudge tasklet count so the call to sc92031_enable_interrupts at
	 * sc92031_open will work correctly */
	tasklet_disable_nosync(&priv->tasklet);

	/* PCI PM Wakeup */
	iowrite32((~PM_LongWF & ~PM_LWPTN) | PM_Enable, port_base + PMConfig);

	mac0 = ioread32(port_base + MAC0);
	mac1 = ioread32(port_base + MAC0 + 4);
	dev->dev_addr[0] = dev->perm_addr[0] = mac0 >> 24;
	dev->dev_addr[1] = dev->perm_addr[1] = mac0 >> 16;
	dev->dev_addr[2] = dev->perm_addr[2] = mac0 >> 8;
	dev->dev_addr[3] = dev->perm_addr[3] = mac0;
	dev->dev_addr[4] = dev->perm_addr[4] = mac1 >> 8;
	dev->dev_addr[5] = dev->perm_addr[5] = mac1;

	err = register_netdev(dev);
	if (err < 0)
		goto out_register_netdev;

1473
	printk(KERN_INFO "%s: SC92031 at 0x%lx, %pM, IRQ %d\n", dev->name,
1474 1475
	       (long)pci_resource_start(pdev, SC92031_USE_PIO), dev->dev_addr,
	       pdev->irq);
1476

1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519
	return 0;

out_register_netdev:
	free_netdev(dev);
out_alloc_etherdev:
	pci_iounmap(pdev, port_base);
out_iomap:
	pci_release_regions(pdev);
out_request_regions:
out_set_dma_mask:
	pci_disable_device(pdev);
out_enable_device:
	return err;
}

static void __devexit sc92031_remove(struct pci_dev *pdev)
{
	struct net_device *dev = pci_get_drvdata(pdev);
	struct sc92031_priv *priv = netdev_priv(dev);
	void __iomem* port_base = priv->port_base;

	unregister_netdev(dev);
	free_netdev(dev);
	pci_iounmap(pdev, port_base);
	pci_release_regions(pdev);
	pci_disable_device(pdev);
}

static int sc92031_suspend(struct pci_dev *pdev, pm_message_t state)
{
	struct net_device *dev = pci_get_drvdata(pdev);
	struct sc92031_priv *priv = netdev_priv(dev);

	pci_save_state(pdev);

	if (!netif_running(dev))
		goto out;

	netif_device_detach(dev);

	/* Disable interrupts, stop Tx and Rx. */
	sc92031_disable_interrupts(dev);

H
Herbert Xu 已提交
1520
	spin_lock_bh(&priv->lock);
1521 1522 1523 1524 1525

	_sc92031_disable_tx_rx(dev);
	_sc92031_tx_clear(dev);
	mmiowb();

H
Herbert Xu 已提交
1526
	spin_unlock_bh(&priv->lock);
1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545

out:
	pci_set_power_state(pdev, pci_choose_state(pdev, state));

	return 0;
}

static int sc92031_resume(struct pci_dev *pdev)
{
	struct net_device *dev = pci_get_drvdata(pdev);
	struct sc92031_priv *priv = netdev_priv(dev);

	pci_restore_state(pdev);
	pci_set_power_state(pdev, PCI_D0);

	if (!netif_running(dev))
		goto out;

	/* Interrupts already disabled by sc92031_suspend */
H
Herbert Xu 已提交
1546
	spin_lock_bh(&priv->lock);
1547 1548 1549 1550

	_sc92031_reset(dev);
	mmiowb();

H
Herbert Xu 已提交
1551
	spin_unlock_bh(&priv->lock);
1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564
	sc92031_enable_interrupts(dev);

	netif_device_attach(dev);

	if (netif_carrier_ok(dev))
		netif_wake_queue(dev);
	else
		netif_tx_disable(dev);

out:
	return 0;
}

1565
static DEFINE_PCI_DEVICE_TABLE(sc92031_pci_device_id_table) = {
1566 1567
	{ PCI_DEVICE(PCI_VENDOR_ID_SILAN, 0x2031) },
	{ PCI_DEVICE(PCI_VENDOR_ID_SILAN, 0x8139) },
1568
	{ PCI_DEVICE(0x1088, 0x2031) },
1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596
	{ 0, }
};
MODULE_DEVICE_TABLE(pci, sc92031_pci_device_id_table);

static struct pci_driver sc92031_pci_driver = {
	.name		= SC92031_NAME,
	.id_table	= sc92031_pci_device_id_table,
	.probe		= sc92031_probe,
	.remove		= __devexit_p(sc92031_remove),
	.suspend	= sc92031_suspend,
	.resume		= sc92031_resume,
};

static int __init sc92031_init(void)
{
	return pci_register_driver(&sc92031_pci_driver);
}

static void __exit sc92031_exit(void)
{
	pci_unregister_driver(&sc92031_pci_driver);
}

module_init(sc92031_init);
module_exit(sc92031_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Cesar Eduardo Barros <cesarb@cesarb.net>");
1597
MODULE_DESCRIPTION("Silan SC92031 PCI Fast Ethernet Adapter driver");