162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci	drivers/net/ethernet/dec/tulip/timer.c
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci	Copyright 2000,2001  The Linux Kernel Team
562306a36Sopenharmony_ci	Written/copyright 1994-2001 by Donald Becker.
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci	This software may be used and distributed according to the terms
862306a36Sopenharmony_ci	of the GNU General Public License, incorporated herein by reference.
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci	Please submit bugs to http://bugzilla.kernel.org/ .
1162306a36Sopenharmony_ci*/
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include "tulip.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_civoid tulip_media_task(struct work_struct *work)
1862306a36Sopenharmony_ci{
1962306a36Sopenharmony_ci	struct tulip_private *tp =
2062306a36Sopenharmony_ci		container_of(work, struct tulip_private, media_work);
2162306a36Sopenharmony_ci	struct net_device *dev = tp->dev;
2262306a36Sopenharmony_ci	void __iomem *ioaddr = tp->base_addr;
2362306a36Sopenharmony_ci	u32 csr12 = ioread32(ioaddr + CSR12);
2462306a36Sopenharmony_ci	int next_tick = 2*HZ;
2562306a36Sopenharmony_ci	unsigned long flags;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	if (tulip_debug > 2) {
2862306a36Sopenharmony_ci		netdev_dbg(dev, "Media selection tick, %s, status %08x mode %08x SIA %08x %08x %08x %08x\n",
2962306a36Sopenharmony_ci			   medianame[dev->if_port],
3062306a36Sopenharmony_ci			   ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR6),
3162306a36Sopenharmony_ci			   csr12, ioread32(ioaddr + CSR13),
3262306a36Sopenharmony_ci			   ioread32(ioaddr + CSR14), ioread32(ioaddr + CSR15));
3362306a36Sopenharmony_ci	}
3462306a36Sopenharmony_ci	switch (tp->chip_id) {
3562306a36Sopenharmony_ci	case DC21140:
3662306a36Sopenharmony_ci	case DC21142:
3762306a36Sopenharmony_ci	case MX98713:
3862306a36Sopenharmony_ci	case COMPEX9881:
3962306a36Sopenharmony_ci	case DM910X:
4062306a36Sopenharmony_ci	default: {
4162306a36Sopenharmony_ci		struct medialeaf *mleaf;
4262306a36Sopenharmony_ci		unsigned char *p;
4362306a36Sopenharmony_ci		if (tp->mtable == NULL) {	/* No EEPROM info, use generic code. */
4462306a36Sopenharmony_ci			/* Not much that can be done.
4562306a36Sopenharmony_ci			   Assume this a generic MII or SYM transceiver. */
4662306a36Sopenharmony_ci			next_tick = 60*HZ;
4762306a36Sopenharmony_ci			if (tulip_debug > 2)
4862306a36Sopenharmony_ci				netdev_dbg(dev, "network media monitor CSR6 %08x CSR12 0x%02x\n",
4962306a36Sopenharmony_ci					   ioread32(ioaddr + CSR6),
5062306a36Sopenharmony_ci					   csr12 & 0xff);
5162306a36Sopenharmony_ci			break;
5262306a36Sopenharmony_ci		}
5362306a36Sopenharmony_ci		mleaf = &tp->mtable->mleaf[tp->cur_index];
5462306a36Sopenharmony_ci		p = mleaf->leafdata;
5562306a36Sopenharmony_ci		switch (mleaf->type) {
5662306a36Sopenharmony_ci		case 0: case 4: {
5762306a36Sopenharmony_ci			/* Type 0 serial or 4 SYM transceiver.  Check the link beat bit. */
5862306a36Sopenharmony_ci			int offset = mleaf->type == 4 ? 5 : 2;
5962306a36Sopenharmony_ci			s8 bitnum = p[offset];
6062306a36Sopenharmony_ci			if (p[offset+1] & 0x80) {
6162306a36Sopenharmony_ci				if (tulip_debug > 1)
6262306a36Sopenharmony_ci					netdev_dbg(dev, "Transceiver monitor tick CSR12=%#02x, no media sense\n",
6362306a36Sopenharmony_ci						   csr12);
6462306a36Sopenharmony_ci				if (mleaf->type == 4) {
6562306a36Sopenharmony_ci					if (mleaf->media == 3 && (csr12 & 0x02))
6662306a36Sopenharmony_ci						goto select_next_media;
6762306a36Sopenharmony_ci				}
6862306a36Sopenharmony_ci				break;
6962306a36Sopenharmony_ci			}
7062306a36Sopenharmony_ci			if (tulip_debug > 2)
7162306a36Sopenharmony_ci				netdev_dbg(dev, "Transceiver monitor tick: CSR12=%#02x bit %d is %d, expecting %d\n",
7262306a36Sopenharmony_ci					   csr12, (bitnum >> 1) & 7,
7362306a36Sopenharmony_ci					   (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
7462306a36Sopenharmony_ci					   (bitnum >= 0));
7562306a36Sopenharmony_ci			/* Check that the specified bit has the proper value. */
7662306a36Sopenharmony_ci			if ((bitnum < 0) !=
7762306a36Sopenharmony_ci				((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
7862306a36Sopenharmony_ci				if (tulip_debug > 2)
7962306a36Sopenharmony_ci					netdev_dbg(dev, "Link beat detected for %s\n",
8062306a36Sopenharmony_ci						   medianame[mleaf->media & MEDIA_MASK]);
8162306a36Sopenharmony_ci				if ((p[2] & 0x61) == 0x01)	/* Bogus Znyx board. */
8262306a36Sopenharmony_ci					goto actually_mii;
8362306a36Sopenharmony_ci				netif_carrier_on(dev);
8462306a36Sopenharmony_ci				break;
8562306a36Sopenharmony_ci			}
8662306a36Sopenharmony_ci			netif_carrier_off(dev);
8762306a36Sopenharmony_ci			if (tp->medialock)
8862306a36Sopenharmony_ci				break;
8962306a36Sopenharmony_ci	  select_next_media:
9062306a36Sopenharmony_ci			if (--tp->cur_index < 0) {
9162306a36Sopenharmony_ci				/* We start again, but should instead look for default. */
9262306a36Sopenharmony_ci				tp->cur_index = tp->mtable->leafcount - 1;
9362306a36Sopenharmony_ci			}
9462306a36Sopenharmony_ci			dev->if_port = tp->mtable->mleaf[tp->cur_index].media;
9562306a36Sopenharmony_ci			if (tulip_media_cap[dev->if_port] & MediaIsFD)
9662306a36Sopenharmony_ci				goto select_next_media; /* Skip FD entries. */
9762306a36Sopenharmony_ci			if (tulip_debug > 1)
9862306a36Sopenharmony_ci				netdev_dbg(dev, "No link beat on media %s, trying transceiver type %s\n",
9962306a36Sopenharmony_ci					   medianame[mleaf->media & MEDIA_MASK],
10062306a36Sopenharmony_ci					   medianame[tp->mtable->mleaf[tp->cur_index].media]);
10162306a36Sopenharmony_ci			tulip_select_media(dev, 0);
10262306a36Sopenharmony_ci			/* Restart the transmit process. */
10362306a36Sopenharmony_ci			tulip_restart_rxtx(tp);
10462306a36Sopenharmony_ci			next_tick = (24*HZ)/10;
10562306a36Sopenharmony_ci			break;
10662306a36Sopenharmony_ci		}
10762306a36Sopenharmony_ci		case 1:  case 3:		/* 21140, 21142 MII */
10862306a36Sopenharmony_ci		actually_mii:
10962306a36Sopenharmony_ci			if (tulip_check_duplex(dev) < 0) {
11062306a36Sopenharmony_ci				netif_carrier_off(dev);
11162306a36Sopenharmony_ci				next_tick = 3*HZ;
11262306a36Sopenharmony_ci			} else {
11362306a36Sopenharmony_ci				netif_carrier_on(dev);
11462306a36Sopenharmony_ci				next_tick = 60*HZ;
11562306a36Sopenharmony_ci			}
11662306a36Sopenharmony_ci			break;
11762306a36Sopenharmony_ci		case 2:					/* 21142 serial block has no link beat. */
11862306a36Sopenharmony_ci		default:
11962306a36Sopenharmony_ci			break;
12062306a36Sopenharmony_ci		}
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci	break;
12362306a36Sopenharmony_ci	}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	spin_lock_irqsave(&tp->lock, flags);
12762306a36Sopenharmony_ci	if (tp->timeout_recovery) {
12862306a36Sopenharmony_ci		tulip_tx_timeout_complete(tp, ioaddr);
12962306a36Sopenharmony_ci		tp->timeout_recovery = 0;
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci	spin_unlock_irqrestore(&tp->lock, flags);
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	/* mod_timer synchronizes us with potential add_timer calls
13462306a36Sopenharmony_ci	 * from interrupts.
13562306a36Sopenharmony_ci	 */
13662306a36Sopenharmony_ci	mod_timer(&tp->timer, RUN_AT(next_tick));
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_civoid mxic_timer(struct timer_list *t)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	struct tulip_private *tp = from_timer(tp, t, timer);
14362306a36Sopenharmony_ci	struct net_device *dev = tp->dev;
14462306a36Sopenharmony_ci	void __iomem *ioaddr = tp->base_addr;
14562306a36Sopenharmony_ci	int next_tick = 60*HZ;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	if (tulip_debug > 3) {
14862306a36Sopenharmony_ci		dev_info(&dev->dev, "MXIC negotiation status %08x\n",
14962306a36Sopenharmony_ci			 ioread32(ioaddr + CSR12));
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci	if (next_tick) {
15262306a36Sopenharmony_ci		mod_timer(&tp->timer, RUN_AT(next_tick));
15362306a36Sopenharmony_ci	}
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_civoid comet_timer(struct timer_list *t)
15862306a36Sopenharmony_ci{
15962306a36Sopenharmony_ci	struct tulip_private *tp = from_timer(tp, t, timer);
16062306a36Sopenharmony_ci	struct net_device *dev = tp->dev;
16162306a36Sopenharmony_ci	int next_tick = 2*HZ;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	if (tulip_debug > 1)
16462306a36Sopenharmony_ci		netdev_dbg(dev, "Comet link status %04x partner capability %04x\n",
16562306a36Sopenharmony_ci			   tulip_mdio_read(dev, tp->phys[0], 1),
16662306a36Sopenharmony_ci			   tulip_mdio_read(dev, tp->phys[0], 5));
16762306a36Sopenharmony_ci	/* mod_timer synchronizes us with potential add_timer calls
16862306a36Sopenharmony_ci	 * from interrupts.
16962306a36Sopenharmony_ci	 */
17062306a36Sopenharmony_ci	if (tulip_check_duplex(dev) < 0)
17162306a36Sopenharmony_ci		{ netif_carrier_off(dev); }
17262306a36Sopenharmony_ci	else
17362306a36Sopenharmony_ci		{ netif_carrier_on(dev); }
17462306a36Sopenharmony_ci	mod_timer(&tp->timer, RUN_AT(next_tick));
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
177