Skip to content
Snippets Groups Projects
au1000_eth.c 56.6 KiB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
		for (i = 0; mii_chip_table[i].phy_id1; i++) {
			if (phy_id0 == mii_chip_table[i].phy_id0 &&
			    phy_id1 == mii_chip_table[i].phy_id1) {
				struct mii_phy * mii_phy;

				printk(KERN_INFO "%s: %s at phy address %d\n",
				       dev->name, mii_chip_table[i].name, 
				       phy_addr);
				mii_phy = kmalloc(sizeof(struct mii_phy), 
						GFP_KERNEL);
				if (mii_phy) {
					mii_phy->chip_info = mii_chip_table+i;
					aup->phy_addr = phy_addr;
					mii_phy->next = aup->mii;
					aup->phy_ops = 
						mii_chip_table[i].phy_ops;
					aup->mii = mii_phy;
					aup->phy_ops->phy_init(dev,phy_addr);
				} else {
					printk(KERN_ERR "%s: out of memory\n", 
							dev->name);
					return -1;
				}
				mii_phy->chip_info = mii_chip_table+i;
				aup->phy_addr = phy_addr;
				aup->phy_ops = mii_chip_table[i].phy_ops;
				aup->phy_ops->phy_init(dev,phy_addr);
				break;
			}
		}
	}
	if (aup->mac_id == 0) {
		/* the Bosporus phy responds to addresses 0-5 but 
		 * 5 is the correct one.
		 */
		aup->phy_addr = 5;
	}
#endif

	if (aup->mii->chip_info == NULL) {
		printk(KERN_ERR "%s: Au1x No known MII transceivers found!\n",
Linus Torvalds's avatar
Linus Torvalds committed
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 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 1115 1116 1117 1118 1119 1120 1121 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 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 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 1230 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 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 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 1473 1474 1475 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 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541
				dev->name);
		return -1;
	}

	printk(KERN_INFO "%s: Using %s as default\n", 
			dev->name, aup->mii->chip_info->name);

	return 0;
}


/*
 * Buffer allocation/deallocation routines. The buffer descriptor returned
 * has the virtual and dma address of a buffer suitable for 
 * both, receive and transmit operations.
 */
static db_dest_t *GetFreeDB(struct au1000_private *aup)
{
	db_dest_t *pDB;
	pDB = aup->pDBfree;

	if (pDB) {
		aup->pDBfree = pDB->pnext;
	}
	return pDB;
}

void ReleaseDB(struct au1000_private *aup, db_dest_t *pDB)
{
	db_dest_t *pDBfree = aup->pDBfree;
	if (pDBfree)
		pDBfree->pnext = pDB;
	aup->pDBfree = pDB;
}

static void enable_rx_tx(struct net_device *dev)
{
	struct au1000_private *aup = (struct au1000_private *) dev->priv;

	if (au1000_debug > 4)
		printk(KERN_INFO "%s: enable_rx_tx\n", dev->name);

	aup->mac->control |= (MAC_RX_ENABLE | MAC_TX_ENABLE);
	au_sync_delay(10);
}

static void hard_stop(struct net_device *dev)
{
	struct au1000_private *aup = (struct au1000_private *) dev->priv;

	if (au1000_debug > 4)
		printk(KERN_INFO "%s: hard stop\n", dev->name);

	aup->mac->control &= ~(MAC_RX_ENABLE | MAC_TX_ENABLE);
	au_sync_delay(10);
}


static void reset_mac(struct net_device *dev)
{
	int i;
	u32 flags;
	struct au1000_private *aup = (struct au1000_private *) dev->priv;

	if (au1000_debug > 4) 
		printk(KERN_INFO "%s: reset mac, aup %x\n", 
				dev->name, (unsigned)aup);

	spin_lock_irqsave(&aup->lock, flags);
	if (aup->timer.function == &au1000_timer) {/* check if timer initted */
		del_timer(&aup->timer);
	}

	hard_stop(dev);
	#ifdef CONFIG_BCM5222_DUAL_PHY
	if (aup->mac_id != 0) {
	#endif
		/* If BCM5222, we can't leave MAC0 in reset because then 
		 * we can't access the dual phy for ETH1 */
		*aup->enable = MAC_EN_CLOCK_ENABLE;
		au_sync_delay(2);
		*aup->enable = 0;
		au_sync_delay(2);
	#ifdef CONFIG_BCM5222_DUAL_PHY
	}
	#endif
	aup->tx_full = 0;
	for (i = 0; i < NUM_RX_DMA; i++) {
		/* reset control bits */
		aup->rx_dma_ring[i]->buff_stat &= ~0xf;
	}
	for (i = 0; i < NUM_TX_DMA; i++) {
		/* reset control bits */
		aup->tx_dma_ring[i]->buff_stat &= ~0xf;
	}
	spin_unlock_irqrestore(&aup->lock, flags);
}


/* 
 * Setup the receive and transmit "rings".  These pointers are the addresses
 * of the rx and tx MAC DMA registers so they are fixed by the hardware --
 * these are not descriptors sitting in memory.
 */
static void 
setup_hw_rings(struct au1000_private *aup, u32 rx_base, u32 tx_base)
{
	int i;

	for (i = 0; i < NUM_RX_DMA; i++) {
		aup->rx_dma_ring[i] = 
			(volatile rx_dma_t *) (rx_base + sizeof(rx_dma_t)*i);
	}
	for (i = 0; i < NUM_TX_DMA; i++) {
		aup->tx_dma_ring[i] = 
			(volatile tx_dma_t *) (tx_base + sizeof(tx_dma_t)*i);
	}
}

static struct {
	int port;
	u32 base_addr;
	u32 macen_addr;
	int irq;
	struct net_device *dev;
} iflist[2];

static int num_ifs;

/*
 * Setup the base address and interupt of the Au1xxx ethernet macs
 * based on cpu type and whether the interface is enabled in sys_pinfunc
 * register. The last interface is enabled if SYS_PF_NI2 (bit 4) is 0.
 */
static int __init au1000_init_module(void)
{
	struct cpuinfo_mips *c = &current_cpu_data;
	int ni = (int)((au_readl(SYS_PINFUNC) & (u32)(SYS_PF_NI2)) >> 4);
	struct net_device *dev;
	int i, found_one = 0;

	switch (c->cputype) {
#ifdef CONFIG_SOC_AU1000
	case CPU_AU1000:
		num_ifs = 2 - ni;
		iflist[0].base_addr = AU1000_ETH0_BASE;
		iflist[1].base_addr = AU1000_ETH1_BASE;
		iflist[0].macen_addr = AU1000_MAC0_ENABLE;
		iflist[1].macen_addr = AU1000_MAC1_ENABLE;
		iflist[0].irq = AU1000_MAC0_DMA_INT;
		iflist[1].irq = AU1000_MAC1_DMA_INT;
		break;
#endif
#ifdef CONFIG_SOC_AU1100
	case CPU_AU1100:
		num_ifs = 1 - ni;
		iflist[0].base_addr = AU1100_ETH0_BASE;
		iflist[0].macen_addr = AU1100_MAC0_ENABLE;
		iflist[0].irq = AU1100_MAC0_DMA_INT;
		break;
#endif
#ifdef CONFIG_SOC_AU1500
	case CPU_AU1500:
		num_ifs = 2 - ni;
		iflist[0].base_addr = AU1500_ETH0_BASE;
		iflist[1].base_addr = AU1500_ETH1_BASE;
		iflist[0].macen_addr = AU1500_MAC0_ENABLE;
		iflist[1].macen_addr = AU1500_MAC1_ENABLE;
		iflist[0].irq = AU1500_MAC0_DMA_INT;
		iflist[1].irq = AU1500_MAC1_DMA_INT;
		break;
#endif
#ifdef CONFIG_SOC_AU1550
	case CPU_AU1550:
		num_ifs = 2 - ni;
		iflist[0].base_addr = AU1550_ETH0_BASE;
		iflist[1].base_addr = AU1550_ETH1_BASE;
		iflist[0].macen_addr = AU1550_MAC0_ENABLE;
		iflist[1].macen_addr = AU1550_MAC1_ENABLE;
		iflist[0].irq = AU1550_MAC0_DMA_INT;
		iflist[1].irq = AU1550_MAC1_DMA_INT;
		break;
#endif
	default:
		num_ifs = 0;
	}
	for(i = 0; i < num_ifs; i++) {
		dev = au1000_probe(iflist[i].base_addr, iflist[i].irq, i);
		iflist[i].dev = dev;
		if (dev)
			found_one++;
	}
	if (!found_one)
		return -ENODEV;
	return 0;
}

static int au1000_setup_aneg(struct net_device *dev, u32 advertise)
{
	struct au1000_private *aup = (struct au1000_private *)dev->priv;
	u16 ctl, adv;

	/* Setup standard advertise */
	adv = mdio_read(dev, aup->phy_addr, MII_ADVERTISE);
	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
	if (advertise & ADVERTISED_10baseT_Half)
		adv |= ADVERTISE_10HALF;
	if (advertise & ADVERTISED_10baseT_Full)
		adv |= ADVERTISE_10FULL;
	if (advertise & ADVERTISED_100baseT_Half)
		adv |= ADVERTISE_100HALF;
	if (advertise & ADVERTISED_100baseT_Full)
		adv |= ADVERTISE_100FULL;
	mdio_write(dev, aup->phy_addr, MII_ADVERTISE, adv);

	/* Start/Restart aneg */
	ctl = mdio_read(dev, aup->phy_addr, MII_BMCR);
	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
	mdio_write(dev, aup->phy_addr, MII_BMCR, ctl);

	return 0;
}

static int au1000_setup_forced(struct net_device *dev, int speed, int fd)
{
	struct au1000_private *aup = (struct au1000_private *)dev->priv;
	u16 ctl;

	ctl = mdio_read(dev, aup->phy_addr, MII_BMCR);
	ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_ANENABLE);

	/* First reset the PHY */
	mdio_write(dev, aup->phy_addr, MII_BMCR, ctl | BMCR_RESET);

	/* Select speed & duplex */
	switch (speed) {
		case SPEED_10:
			break;
		case SPEED_100:
			ctl |= BMCR_SPEED100;
			break;
		case SPEED_1000:
		default:
			return -EINVAL;
	}
	if (fd == DUPLEX_FULL)
		ctl |= BMCR_FULLDPLX;
	mdio_write(dev, aup->phy_addr, MII_BMCR, ctl);

	return 0;
}


static void
au1000_start_link(struct net_device *dev, struct ethtool_cmd *cmd)
{
	struct au1000_private *aup = (struct au1000_private *)dev->priv;
	u32 advertise;
	int autoneg;
	int forced_speed;
	int forced_duplex;

	/* Default advertise */
	advertise = GENMII_DEFAULT_ADVERTISE;
	autoneg = aup->want_autoneg;
	forced_speed = SPEED_100;
	forced_duplex = DUPLEX_FULL;

	/* Setup link parameters */
	if (cmd) {
		if (cmd->autoneg == AUTONEG_ENABLE) {
			advertise = cmd->advertising;
			autoneg = 1;
		} else {
			autoneg = 0;

			forced_speed = cmd->speed;
			forced_duplex = cmd->duplex;
		}
	}

	/* Configure PHY & start aneg */
	aup->want_autoneg = autoneg;
	if (autoneg)
		au1000_setup_aneg(dev, advertise);
	else
		au1000_setup_forced(dev, forced_speed, forced_duplex);
	mod_timer(&aup->timer, jiffies + HZ);
}

static int au1000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
	struct au1000_private *aup = (struct au1000_private *)dev->priv;
	u16 link, speed;

	cmd->supported = GENMII_DEFAULT_FEATURES;
	cmd->advertising = GENMII_DEFAULT_ADVERTISE;
	cmd->port = PORT_MII;
	cmd->transceiver = XCVR_EXTERNAL;
	cmd->phy_address = aup->phy_addr;
	spin_lock_irq(&aup->lock);
	cmd->autoneg = aup->want_autoneg;
	aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed);
	if ((speed == IF_PORT_100BASETX) || (speed == IF_PORT_100BASEFX))
		cmd->speed = SPEED_100;
	else if (speed == IF_PORT_10BASET)
		cmd->speed = SPEED_10;
	if (link && (dev->if_port == IF_PORT_100BASEFX))
		cmd->duplex = DUPLEX_FULL;
	else
		cmd->duplex = DUPLEX_HALF;
	spin_unlock_irq(&aup->lock);
	return 0;
}

static int au1000_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
	 struct au1000_private *aup = (struct au1000_private *)dev->priv;
	  unsigned long features = GENMII_DEFAULT_FEATURES;

	 if (!capable(CAP_NET_ADMIN))
		 return -EPERM;

	 if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE)
		 return -EINVAL;
	 if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0)
		 return -EINVAL;
	 if (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL)
		 return -EINVAL;
	 if (cmd->autoneg == AUTONEG_DISABLE)
		 switch (cmd->speed) {
		 case SPEED_10:
			 if (cmd->duplex == DUPLEX_HALF &&
				 (features & SUPPORTED_10baseT_Half) == 0)
				 return -EINVAL;
			 if (cmd->duplex == DUPLEX_FULL &&
				 (features & SUPPORTED_10baseT_Full) == 0)
				 return -EINVAL;
			 break;
		 case SPEED_100:
			 if (cmd->duplex == DUPLEX_HALF &&
				 (features & SUPPORTED_100baseT_Half) == 0)
				 return -EINVAL;
			 if (cmd->duplex == DUPLEX_FULL &&
				 (features & SUPPORTED_100baseT_Full) == 0)
				 return -EINVAL;
			 break;
		 default:
			 return -EINVAL;
		 }
	 else if ((features & SUPPORTED_Autoneg) == 0)
		 return -EINVAL;

	 spin_lock_irq(&aup->lock);
	 au1000_start_link(dev, cmd);
	 spin_unlock_irq(&aup->lock);
	 return 0;
}

static int au1000_nway_reset(struct net_device *dev)
{
	struct au1000_private *aup = (struct au1000_private *)dev->priv;

	if (!aup->want_autoneg)
		return -EINVAL;
	spin_lock_irq(&aup->lock);
	au1000_start_link(dev, NULL);
	spin_unlock_irq(&aup->lock);
	return 0;
}

static void
au1000_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
	struct au1000_private *aup = (struct au1000_private *)dev->priv;

	strcpy(info->driver, DRV_NAME);
	strcpy(info->version, DRV_VERSION);
	info->fw_version[0] = '\0';
	sprintf(info->bus_info, "%s %d", DRV_NAME, aup->mac_id);
	info->regdump_len = 0;
}

static u32 au1000_get_link(struct net_device *dev)
{
	return netif_carrier_ok(dev);
}

static struct ethtool_ops au1000_ethtool_ops = {
	.get_settings = au1000_get_settings,
	.set_settings = au1000_set_settings,
	.get_drvinfo = au1000_get_drvinfo,
	.nway_reset = au1000_nway_reset,
	.get_link = au1000_get_link
};

static struct net_device *
au1000_probe(u32 ioaddr, int irq, int port_num)
{
	static unsigned version_printed = 0;
	struct au1000_private *aup = NULL;
	struct net_device *dev = NULL;
	db_dest_t *pDB, *pDBfree;
	char *pmac, *argptr;
	char ethaddr[6];
	int i, err;

	if (!request_mem_region(CPHYSADDR(ioaddr), MAC_IOSIZE, "Au1x00 ENET"))
		return NULL;

	if (version_printed++ == 0) 
		printk("%s version %s %s\n", DRV_NAME, DRV_VERSION, DRV_AUTHOR);

	dev = alloc_etherdev(sizeof(struct au1000_private));
	if (!dev) {
		printk (KERN_ERR "au1000 eth: alloc_etherdev failed\n");  
		return NULL;
	}

	if ((err = register_netdev(dev))) {
		printk(KERN_ERR "Au1x_eth Cannot register net device err %d\n",
				err);
		free_netdev(dev);
		return NULL;
	}

	printk("%s: Au1x Ethernet found at 0x%x, irq %d\n", 
			dev->name, ioaddr, irq);

	aup = dev->priv;

	/* Allocate the data buffers */
	/* Snooping works fine with eth on all au1xxx */
	aup->vaddr = (u32)dma_alloc_noncoherent(NULL,
			MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS),
			&aup->dma_addr,
			0);
	if (!aup->vaddr) {
		free_netdev(dev);
		release_mem_region(CPHYSADDR(ioaddr), MAC_IOSIZE);
		return NULL;
	}

	/* aup->mac is the base address of the MAC's registers */
	aup->mac = (volatile mac_reg_t *)((unsigned long)ioaddr);
	/* Setup some variables for quick register address access */
	if (ioaddr == iflist[0].base_addr)
	{
		/* check env variables first */
		if (!get_ethernet_addr(ethaddr)) { 
			memcpy(au1000_mac_addr, ethaddr, sizeof(au1000_mac_addr));
		} else {
			/* Check command line */
			argptr = prom_getcmdline();
			if ((pmac = strstr(argptr, "ethaddr=")) == NULL) {
				printk(KERN_INFO "%s: No mac address found\n", 
						dev->name);
				/* use the hard coded mac addresses */
			} else {
				str2eaddr(ethaddr, pmac + strlen("ethaddr="));
				memcpy(au1000_mac_addr, ethaddr, 
						sizeof(au1000_mac_addr));
			}
		}
			aup->enable = (volatile u32 *) 
				((unsigned long)iflist[0].macen_addr);
		memcpy(dev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
		setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR);
		aup->mac_id = 0;
		au_macs[0] = aup;
	}
		else
	if (ioaddr == iflist[1].base_addr)
	{
			aup->enable = (volatile u32 *) 
				((unsigned long)iflist[1].macen_addr);
		memcpy(dev->dev_addr, au1000_mac_addr, sizeof(au1000_mac_addr));
		dev->dev_addr[4] += 0x10;
		setup_hw_rings(aup, MAC1_RX_DMA_ADDR, MAC1_TX_DMA_ADDR);
		aup->mac_id = 1;
		au_macs[1] = aup;
	}
	else
	{
		printk(KERN_ERR "%s: bad ioaddr\n", dev->name);
	}

	/* bring the device out of reset, otherwise probing the mii
	 * will hang */
	*aup->enable = MAC_EN_CLOCK_ENABLE;
	au_sync_delay(2);
	*aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 | 
		MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE;
	au_sync_delay(2);

	aup->mii = kmalloc(sizeof(struct mii_phy), GFP_KERNEL);
	if (!aup->mii) {
		printk(KERN_ERR "%s: out of memory\n", dev->name);
		goto err_out;
	}
	aup->mii->next = NULL;
	aup->mii->chip_info = NULL;
	aup->mii->status = 0;
Linus Torvalds's avatar
Linus Torvalds committed
	aup->mii->mii_control_reg = 0;
	aup->mii->mii_data_reg = 0;

	if (mii_probe(dev) != 0) {
		goto err_out;
	}

	pDBfree = NULL;
	/* setup the data buffer descriptors and attach a buffer to each one */
	pDB = aup->db;
	for (i = 0; i < (NUM_TX_BUFFS+NUM_RX_BUFFS); i++) {
		pDB->pnext = pDBfree;
		pDBfree = pDB;
		pDB->vaddr = (u32 *)((unsigned)aup->vaddr + MAX_BUF_SIZE*i);
		pDB->dma_addr = (dma_addr_t)virt_to_bus(pDB->vaddr);
		pDB++;
	}
	aup->pDBfree = pDBfree;

	for (i = 0; i < NUM_RX_DMA; i++) {
		pDB = GetFreeDB(aup);
		if (!pDB) {
			goto err_out;
		}
		aup->rx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr;
		aup->rx_db_inuse[i] = pDB;
	}
	for (i = 0; i < NUM_TX_DMA; i++) {
		pDB = GetFreeDB(aup);
		if (!pDB) {
			goto err_out;
		}
		aup->tx_dma_ring[i]->buff_stat = (unsigned)pDB->dma_addr;
		aup->tx_dma_ring[i]->len = 0;
		aup->tx_db_inuse[i] = pDB;
	}

	spin_lock_init(&aup->lock);
	dev->base_addr = ioaddr;
	dev->irq = irq;
	dev->open = au1000_open;
	dev->hard_start_xmit = au1000_tx;
	dev->stop = au1000_close;
	dev->get_stats = au1000_get_stats;
	dev->set_multicast_list = &set_rx_mode;
	dev->do_ioctl = &au1000_ioctl;
	SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops);
	dev->set_config = &au1000_set_config;
	dev->tx_timeout = au1000_tx_timeout;
	dev->watchdog_timeo = ETH_TX_TIMEOUT;

	/* 
	 * The boot code uses the ethernet controller, so reset it to start 
	 * fresh.  au1000_init() expects that the device is in reset state.
	 */
	reset_mac(dev);

	return dev;

err_out:
	/* here we should have a valid dev plus aup-> register addresses
	 * so we can reset the mac properly.*/
	reset_mac(dev);
Linus Torvalds's avatar
Linus Torvalds committed
	for (i = 0; i < NUM_RX_DMA; i++) {
		if (aup->rx_db_inuse[i])
			ReleaseDB(aup, aup->rx_db_inuse[i]);
	}
	for (i = 0; i < NUM_TX_DMA; i++) {
		if (aup->tx_db_inuse[i])
			ReleaseDB(aup, aup->tx_db_inuse[i]);
	}
	dma_free_noncoherent(NULL,
			MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS),
			(void *)aup->vaddr,
			aup->dma_addr);
	unregister_netdev(dev);
	free_netdev(dev);
	release_mem_region(CPHYSADDR(ioaddr), MAC_IOSIZE);
	return NULL;
}

/* 
 * Initialize the interface.
 *
 * When the device powers up, the clocks are disabled and the
 * mac is in reset state.  When the interface is closed, we
 * do the same -- reset the device and disable the clocks to
 * conserve power. Thus, whenever au1000_init() is called,
 * the device should already be in reset state.
 */
static int au1000_init(struct net_device *dev)
{
	struct au1000_private *aup = (struct au1000_private *) dev->priv;
	u32 flags;
	int i;
	u32 control;
	u16 link, speed;

	if (au1000_debug > 4) 
		printk("%s: au1000_init\n", dev->name);

	spin_lock_irqsave(&aup->lock, flags);

	/* bring the device out of reset */
	*aup->enable = MAC_EN_CLOCK_ENABLE;
        au_sync_delay(2);
	*aup->enable = MAC_EN_RESET0 | MAC_EN_RESET1 | 
		MAC_EN_RESET2 | MAC_EN_CLOCK_ENABLE;
	au_sync_delay(20);

	aup->mac->control = 0;
	aup->tx_head = (aup->tx_dma_ring[0]->buff_stat & 0xC) >> 2;
	aup->tx_tail = aup->tx_head;
	aup->rx_head = (aup->rx_dma_ring[0]->buff_stat & 0xC) >> 2;

	aup->mac->mac_addr_high = dev->dev_addr[5]<<8 | dev->dev_addr[4];
	aup->mac->mac_addr_low = dev->dev_addr[3]<<24 | dev->dev_addr[2]<<16 |
		dev->dev_addr[1]<<8 | dev->dev_addr[0];

	for (i = 0; i < NUM_RX_DMA; i++) {
		aup->rx_dma_ring[i]->buff_stat |= RX_DMA_ENABLE;
	}
	au_sync();

	aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed);
	control = MAC_DISABLE_RX_OWN | MAC_RX_ENABLE | MAC_TX_ENABLE;
#ifndef CONFIG_CPU_LITTLE_ENDIAN
	control |= MAC_BIG_ENDIAN;
#endif
	if (link && (dev->if_port == IF_PORT_100BASEFX)) {
		control |= MAC_FULL_DUPLEX;
	}

	aup->mac->control = control;
	aup->mac->vlan1_tag = 0x8100; /* activate vlan support */
	au_sync();

	spin_unlock_irqrestore(&aup->lock, flags);
	return 0;
}

static void au1000_timer(unsigned long data)
{
	struct net_device *dev = (struct net_device *)data;
	struct au1000_private *aup = (struct au1000_private *) dev->priv;
	unsigned char if_port;
	u16 link, speed;

	if (!dev) {
		/* fatal error, don't restart the timer */
		printk(KERN_ERR "au1000_timer error: NULL dev\n");
		return;
	}

	if_port = dev->if_port;
	if (aup->phy_ops->phy_status(dev, aup->phy_addr, &link, &speed) == 0) {
		if (link) {
			if (!netif_carrier_ok(dev)) {
Linus Torvalds's avatar
Linus Torvalds committed
				netif_carrier_on(dev);
				printk(KERN_INFO "%s: link up\n", dev->name);
			}
		}
		else {
			if (netif_carrier_ok(dev)) {
Linus Torvalds's avatar
Linus Torvalds committed
				netif_carrier_off(dev);
				dev->if_port = 0;
				printk(KERN_INFO "%s: link down\n", dev->name);
			}
		}
	}

	if (link && (dev->if_port != if_port) && 
			(dev->if_port != IF_PORT_UNKNOWN)) {
		hard_stop(dev);
		if (dev->if_port == IF_PORT_100BASEFX) {
			printk(KERN_INFO "%s: going to full duplex\n", 
					dev->name);
			aup->mac->control |= MAC_FULL_DUPLEX;
			au_sync_delay(1);
		}
		else {
			aup->mac->control &= ~MAC_FULL_DUPLEX;
			au_sync_delay(1);
		}
		enable_rx_tx(dev);
	}

	aup->timer.expires = RUN_AT((1*HZ)); 
	aup->timer.data = (unsigned long)dev;
	aup->timer.function = &au1000_timer; /* timer handler */
	add_timer(&aup->timer);

}

static int au1000_open(struct net_device *dev)
{
	int retval;
	struct au1000_private *aup = (struct au1000_private *) dev->priv;

	if (au1000_debug > 4)
		printk("%s: open: dev=%p\n", dev->name, dev);

	if ((retval = au1000_init(dev))) {
		printk(KERN_ERR "%s: error in au1000_init\n", dev->name);
		free_irq(dev->irq, dev);
		return retval;
	}
	netif_start_queue(dev);

	if ((retval = request_irq(dev->irq, &au1000_interrupt, 0, 
					dev->name, dev))) {
		printk(KERN_ERR "%s: unable to get IRQ %d\n", 
				dev->name, dev->irq);
		return retval;
	}

	init_timer(&aup->timer); /* used in ioctl() */
	aup->timer.expires = RUN_AT((3*HZ)); 
	aup->timer.data = (unsigned long)dev;
	aup->timer.function = &au1000_timer; /* timer handler */
	add_timer(&aup->timer);

	if (au1000_debug > 4)
		printk("%s: open: Initialization done.\n", dev->name);

	return 0;
}

static int au1000_close(struct net_device *dev)
{
	u32 flags;
	struct au1000_private *aup = (struct au1000_private *) dev->priv;

	if (au1000_debug > 4)
		printk("%s: close: dev=%p\n", dev->name, dev);

	reset_mac(dev);

	spin_lock_irqsave(&aup->lock, flags);
	
	/* stop the device */
	netif_stop_queue(dev);

	/* disable the interrupt */
	free_irq(dev->irq, dev);
	spin_unlock_irqrestore(&aup->lock, flags);

	return 0;
}

static void __exit au1000_cleanup_module(void)
{
	int i, j;
	struct net_device *dev;
	struct au1000_private *aup;

	for (i = 0; i < num_ifs; i++) {
		dev = iflist[i].dev;
		if (dev) {
			aup = (struct au1000_private *) dev->priv;
			unregister_netdev(dev);
Linus Torvalds's avatar
Linus Torvalds committed
			for (j = 0; j < NUM_RX_DMA; j++) {
				if (aup->rx_db_inuse[j])
					ReleaseDB(aup, aup->rx_db_inuse[j]);
			}
			for (j = 0; j < NUM_TX_DMA; j++) {
				if (aup->tx_db_inuse[j])
					ReleaseDB(aup, aup->tx_db_inuse[j]);
			}
			dma_free_noncoherent(NULL,
					MAX_BUF_SIZE * (NUM_TX_BUFFS+NUM_RX_BUFFS),
					(void *)aup->vaddr,
					aup->dma_addr);
			free_netdev(dev);
			release_mem_region(CPHYSADDR(iflist[i].base_addr), MAC_IOSIZE);
		}
	}
}

static void update_tx_stats(struct net_device *dev, u32 status)
Linus Torvalds's avatar
Linus Torvalds committed
{
	struct au1000_private *aup = (struct au1000_private *) dev->priv;
	struct net_device_stats *ps = &aup->stats;

	if (status & TX_FRAME_ABORTED) {
		if (dev->if_port == IF_PORT_100BASEFX) {
			if (status & (TX_JAB_TIMEOUT | TX_UNDERRUN)) {
				/* any other tx errors are only valid
				 * in half duplex mode */
				ps->tx_errors++;
				ps->tx_aborted_errors++;
			}
		}
		else {
			ps->tx_errors++;
			ps->tx_aborted_errors++;
			if (status & (TX_NO_CARRIER | TX_LOSS_CARRIER))
				ps->tx_carrier_errors++;
		}
	}
}


/*
 * Called from the interrupt service routine to acknowledge
 * the TX DONE bits.  This is a must if the irq is setup as
 * edge triggered.
 */
static void au1000_tx_ack(struct net_device *dev)
{
	struct au1000_private *aup = (struct au1000_private *) dev->priv;
	volatile tx_dma_t *ptxd;

	ptxd = aup->tx_dma_ring[aup->tx_tail];

	while (ptxd->buff_stat & TX_T_DONE) {
		update_tx_stats(dev, ptxd->status);
Linus Torvalds's avatar
Linus Torvalds committed
		ptxd->buff_stat &= ~TX_T_DONE;
		ptxd->len = 0;
		au_sync();

		aup->tx_tail = (aup->tx_tail + 1) & (NUM_TX_DMA - 1);
		ptxd = aup->tx_dma_ring[aup->tx_tail];

		if (aup->tx_full) {
			aup->tx_full = 0;
			netif_wake_queue(dev);
		}
	}
}


/*
 * Au1000 transmit routine.
 */
static int au1000_tx(struct sk_buff *skb, struct net_device *dev)
{
	struct au1000_private *aup = (struct au1000_private *) dev->priv;
	struct net_device_stats *ps = &aup->stats;
Linus Torvalds's avatar
Linus Torvalds committed
	volatile tx_dma_t *ptxd;
	u32 buff_stat;
	db_dest_t *pDB;
	int i;

	if (au1000_debug > 5)
		printk("%s: tx: aup %x len=%d, data=%p, head %d\n", 
				dev->name, (unsigned)aup, skb->len, 
				skb->data, aup->tx_head);

	ptxd = aup->tx_dma_ring[aup->tx_head];
	buff_stat = ptxd->buff_stat;
	if (buff_stat & TX_DMA_ENABLE) {
		/* We've wrapped around and the transmitter is still busy */
		netif_stop_queue(dev);
		aup->tx_full = 1;
		return 1;
	}
	else if (buff_stat & TX_T_DONE) {
		update_tx_stats(dev, ptxd->status);
Linus Torvalds's avatar
Linus Torvalds committed
		ptxd->len = 0;
	}

	if (aup->tx_full) {
		aup->tx_full = 0;
		netif_wake_queue(dev);
	}

	pDB = aup->tx_db_inuse[aup->tx_head];
	memcpy((void *)pDB->vaddr, skb->data, skb->len);
	if (skb->len < ETH_ZLEN) {
		for (i=skb->len; i<ETH_ZLEN; i++) { 
			((char *)pDB->vaddr)[i] = 0;
		}
		ptxd->len = ETH_ZLEN;
	}
	else
		ptxd->len = skb->len;

	ps->tx_packets++;
	ps->tx_bytes += ptxd->len;

Linus Torvalds's avatar
Linus Torvalds committed
	ptxd->buff_stat = pDB->dma_addr | TX_DMA_ENABLE;
	au_sync();
	dev_kfree_skb(skb);
	aup->tx_head = (aup->tx_head + 1) & (NUM_TX_DMA - 1);
	dev->trans_start = jiffies;
	return 0;
}

static inline void update_rx_stats(struct net_device *dev, u32 status)
{
	struct au1000_private *aup = (struct au1000_private *) dev->priv;
	struct net_device_stats *ps = &aup->stats;

	ps->rx_packets++;
	if (status & RX_MCAST_FRAME)
		ps->multicast++;

	if (status & RX_ERROR) {
		ps->rx_errors++;
		if (status & RX_MISSED_FRAME)
			ps->rx_missed_errors++;
		if (status & (RX_OVERLEN | RX_OVERLEN | RX_LEN_ERROR))
			ps->rx_length_errors++;
		if (status & RX_CRC_ERROR)
			ps->rx_crc_errors++;
		if (status & RX_COLL)
			ps->collisions++;
	}
	else 
		ps->rx_bytes += status & RX_FRAME_LEN_MASK;

}

/*
 * Au1000 receive routine.
 */
static int au1000_rx(struct net_device *dev)
{
	struct au1000_private *aup = (struct au1000_private *) dev->priv;
	struct sk_buff *skb;
	volatile rx_dma_t *prxd;
	u32 buff_stat, status;
	db_dest_t *pDB;
	u32	frmlen;

	if (au1000_debug > 5)
		printk("%s: au1000_rx head %d\n", dev->name, aup->rx_head);

	prxd = aup->rx_dma_ring[aup->rx_head];
	buff_stat = prxd->buff_stat;
	while (buff_stat & RX_T_DONE)  {
		status = prxd->status;
		pDB = aup->rx_db_inuse[aup->rx_head];
		update_rx_stats(dev, status);
		if (!(status & RX_ERROR))  {

			/* good frame */
			frmlen = (status & RX_FRAME_LEN_MASK);
			frmlen -= 4; /* Remove FCS */
			skb = dev_alloc_skb(frmlen + 2);
			if (skb == NULL) {
				printk(KERN_ERR
				       "%s: Memory squeeze, dropping packet.\n",
				       dev->name);
				aup->stats.rx_dropped++;
				continue;
			}
			skb->dev = dev;
			skb_reserve(skb, 2);	/* 16 byte IP header align */
			eth_copy_and_sum(skb,
				(unsigned char *)pDB->vaddr, frmlen, 0);
			skb_put(skb, frmlen);
			skb->protocol = eth_type_trans(skb, dev);