mirror of
https://github.com/torvalds/linux.git
synced 2024-12-24 20:01:55 +00:00
cd354f1ae7
After Al Viro (finally) succeeded in removing the sched.h #include in module.h recently, it makes sense again to remove other superfluous sched.h includes. There are quite a lot of files which include it but don't actually need anything defined in there. Presumably these includes were once needed for macros that used to live in sched.h, but moved to other header files in the course of cleaning it up. To ease the pain, this time I did not fiddle with any header files and only removed #includes from .c-files, which tend to cause less trouble. Compile tested against 2.6.20-rc2 and 2.6.20-rc2-mm2 (with offsets) on alpha, arm, i386, ia64, mips, powerpc, and x86_64 with allnoconfig, defconfig, allmodconfig, and allyesconfig as well as a few randconfigs on x86_64 and all configs in arch/arm/configs on arm. I also checked that no new warnings were introduced by the patch (actually, some warnings are removed that were emitted by unnecessarily included header files). Signed-off-by: Tim Schmielau <tim@physik3.uni-rostock.de> Acked-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
421 lines
10 KiB
C
421 lines
10 KiB
C
/*
|
|
* Fast Ethernet Controller (FEC) driver for Motorola MPC8xx.
|
|
*
|
|
* Copyright (c) 2003 Intracom S.A.
|
|
* by Pantelis Antoniou <panto@intracom.gr>
|
|
*
|
|
* Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com>
|
|
* and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se>
|
|
*
|
|
* Released under the GPL
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/types.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/string.h>
|
|
#include <linux/ptrace.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/ioport.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/pci.h>
|
|
#include <linux/init.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/netdevice.h>
|
|
#include <linux/etherdevice.h>
|
|
#include <linux/skbuff.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/mii.h>
|
|
#include <linux/ethtool.h>
|
|
#include <linux/bitops.h>
|
|
|
|
#include <asm/8xx_immap.h>
|
|
#include <asm/pgtable.h>
|
|
#include <asm/mpc8xx.h>
|
|
#include <asm/irq.h>
|
|
#include <asm/uaccess.h>
|
|
#include <asm/commproc.h>
|
|
|
|
/*************************************************/
|
|
|
|
#include "fec_8xx.h"
|
|
|
|
/*************************************************/
|
|
|
|
/* Make MII read/write commands for the FEC.
|
|
*/
|
|
#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18))
|
|
#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff))
|
|
#define mk_mii_end 0
|
|
|
|
/*************************************************/
|
|
|
|
/* XXX both FECs use the MII interface of FEC1 */
|
|
static DEFINE_SPINLOCK(fec_mii_lock);
|
|
|
|
#define FEC_MII_LOOPS 10000
|
|
|
|
int fec_mii_read(struct net_device *dev, int phy_id, int location)
|
|
{
|
|
struct fec_enet_private *fep = netdev_priv(dev);
|
|
fec_t *fecp;
|
|
int i, ret = -1;
|
|
unsigned long flags;
|
|
|
|
/* XXX MII interface is only connected to FEC1 */
|
|
fecp = &((immap_t *) IMAP_ADDR)->im_cpm.cp_fec;
|
|
|
|
spin_lock_irqsave(&fec_mii_lock, flags);
|
|
|
|
if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) {
|
|
FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */
|
|
FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
|
|
FW(fecp, ievent, FEC_ENET_MII);
|
|
}
|
|
|
|
/* Add PHY address to register command. */
|
|
FW(fecp, mii_speed, fep->fec_phy_speed);
|
|
FW(fecp, mii_data, (phy_id << 23) | mk_mii_read(location));
|
|
|
|
for (i = 0; i < FEC_MII_LOOPS; i++)
|
|
if ((FR(fecp, ievent) & FEC_ENET_MII) != 0)
|
|
break;
|
|
|
|
if (i < FEC_MII_LOOPS) {
|
|
FW(fecp, ievent, FEC_ENET_MII);
|
|
ret = FR(fecp, mii_data) & 0xffff;
|
|
}
|
|
|
|
spin_unlock_irqrestore(&fec_mii_lock, flags);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void fec_mii_write(struct net_device *dev, int phy_id, int location, int value)
|
|
{
|
|
struct fec_enet_private *fep = netdev_priv(dev);
|
|
fec_t *fecp;
|
|
unsigned long flags;
|
|
int i;
|
|
|
|
/* XXX MII interface is only connected to FEC1 */
|
|
fecp = &((immap_t *) IMAP_ADDR)->im_cpm.cp_fec;
|
|
|
|
spin_lock_irqsave(&fec_mii_lock, flags);
|
|
|
|
if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) {
|
|
FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */
|
|
FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
|
|
FW(fecp, ievent, FEC_ENET_MII);
|
|
}
|
|
|
|
/* Add PHY address to register command. */
|
|
FW(fecp, mii_speed, fep->fec_phy_speed); /* always adapt mii speed */
|
|
FW(fecp, mii_data, (phy_id << 23) | mk_mii_write(location, value));
|
|
|
|
for (i = 0; i < FEC_MII_LOOPS; i++)
|
|
if ((FR(fecp, ievent) & FEC_ENET_MII) != 0)
|
|
break;
|
|
|
|
if (i < FEC_MII_LOOPS)
|
|
FW(fecp, ievent, FEC_ENET_MII);
|
|
|
|
spin_unlock_irqrestore(&fec_mii_lock, flags);
|
|
}
|
|
|
|
/*************************************************/
|
|
|
|
#ifdef CONFIG_FEC_8XX_GENERIC_PHY
|
|
|
|
/*
|
|
* Generic PHY support.
|
|
* Should work for all PHYs, but link change is detected by polling
|
|
*/
|
|
|
|
static void generic_timer_callback(unsigned long data)
|
|
{
|
|
struct net_device *dev = (struct net_device *)data;
|
|
struct fec_enet_private *fep = netdev_priv(dev);
|
|
|
|
fep->phy_timer_list.expires = jiffies + HZ / 2;
|
|
|
|
add_timer(&fep->phy_timer_list);
|
|
|
|
fec_mii_link_status_change_check(dev, 0);
|
|
}
|
|
|
|
static void generic_startup(struct net_device *dev)
|
|
{
|
|
struct fec_enet_private *fep = netdev_priv(dev);
|
|
|
|
fep->phy_timer_list.expires = jiffies + HZ / 2; /* every 500ms */
|
|
fep->phy_timer_list.data = (unsigned long)dev;
|
|
fep->phy_timer_list.function = generic_timer_callback;
|
|
add_timer(&fep->phy_timer_list);
|
|
}
|
|
|
|
static void generic_shutdown(struct net_device *dev)
|
|
{
|
|
struct fec_enet_private *fep = netdev_priv(dev);
|
|
|
|
del_timer_sync(&fep->phy_timer_list);
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_FEC_8XX_DM9161_PHY
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
/* The Davicom DM9161 is used on the NETTA board */
|
|
|
|
/* register definitions */
|
|
|
|
#define MII_DM9161_ACR 16 /* Aux. Config Register */
|
|
#define MII_DM9161_ACSR 17 /* Aux. Config/Status Register */
|
|
#define MII_DM9161_10TCSR 18 /* 10BaseT Config/Status Reg. */
|
|
#define MII_DM9161_INTR 21 /* Interrupt Register */
|
|
#define MII_DM9161_RECR 22 /* Receive Error Counter Reg. */
|
|
#define MII_DM9161_DISCR 23 /* Disconnect Counter Register */
|
|
|
|
static void dm9161_startup(struct net_device *dev)
|
|
{
|
|
struct fec_enet_private *fep = netdev_priv(dev);
|
|
|
|
fec_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0000);
|
|
}
|
|
|
|
static void dm9161_ack_int(struct net_device *dev)
|
|
{
|
|
struct fec_enet_private *fep = netdev_priv(dev);
|
|
|
|
fec_mii_read(dev, fep->mii_if.phy_id, MII_DM9161_INTR);
|
|
}
|
|
|
|
static void dm9161_shutdown(struct net_device *dev)
|
|
{
|
|
struct fec_enet_private *fep = netdev_priv(dev);
|
|
|
|
fec_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0f00);
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_FEC_8XX_LXT971_PHY
|
|
|
|
/* Support for LXT971/972 PHY */
|
|
|
|
#define MII_LXT971_PCR 16 /* Port Control Register */
|
|
#define MII_LXT971_SR2 17 /* Status Register 2 */
|
|
#define MII_LXT971_IER 18 /* Interrupt Enable Register */
|
|
#define MII_LXT971_ISR 19 /* Interrupt Status Register */
|
|
#define MII_LXT971_LCR 20 /* LED Control Register */
|
|
#define MII_LXT971_TCR 30 /* Transmit Control Register */
|
|
|
|
static void lxt971_startup(struct net_device *dev)
|
|
{
|
|
struct fec_enet_private *fep = netdev_priv(dev);
|
|
|
|
fec_mii_write(dev, fep->mii_if.phy_id, MII_LXT971_IER, 0x00F2);
|
|
}
|
|
|
|
static void lxt971_ack_int(struct net_device *dev)
|
|
{
|
|
struct fec_enet_private *fep = netdev_priv(dev);
|
|
|
|
fec_mii_read(dev, fep->mii_if.phy_id, MII_LXT971_ISR);
|
|
}
|
|
|
|
static void lxt971_shutdown(struct net_device *dev)
|
|
{
|
|
struct fec_enet_private *fep = netdev_priv(dev);
|
|
|
|
fec_mii_write(dev, fep->mii_if.phy_id, MII_LXT971_IER, 0x0000);
|
|
}
|
|
#endif
|
|
|
|
/**********************************************************************************/
|
|
|
|
static const struct phy_info phy_info[] = {
|
|
#ifdef CONFIG_FEC_8XX_DM9161_PHY
|
|
{
|
|
.id = 0x00181b88,
|
|
.name = "DM9161",
|
|
.startup = dm9161_startup,
|
|
.ack_int = dm9161_ack_int,
|
|
.shutdown = dm9161_shutdown,
|
|
},
|
|
#endif
|
|
#ifdef CONFIG_FEC_8XX_LXT971_PHY
|
|
{
|
|
.id = 0x0001378e,
|
|
.name = "LXT971/972",
|
|
.startup = lxt971_startup,
|
|
.ack_int = lxt971_ack_int,
|
|
.shutdown = lxt971_shutdown,
|
|
},
|
|
#endif
|
|
#ifdef CONFIG_FEC_8XX_GENERIC_PHY
|
|
{
|
|
.id = 0,
|
|
.name = "GENERIC",
|
|
.startup = generic_startup,
|
|
.shutdown = generic_shutdown,
|
|
},
|
|
#endif
|
|
};
|
|
|
|
/**********************************************************************************/
|
|
|
|
int fec_mii_phy_id_detect(struct net_device *dev)
|
|
{
|
|
struct fec_enet_private *fep = netdev_priv(dev);
|
|
const struct fec_platform_info *fpi = fep->fpi;
|
|
int i, r, start, end, phytype, physubtype;
|
|
const struct phy_info *phy;
|
|
int phy_hwid, phy_id;
|
|
|
|
/* if no MDIO */
|
|
if (fpi->use_mdio == 0)
|
|
return -1;
|
|
|
|
phy_hwid = -1;
|
|
fep->phy = NULL;
|
|
|
|
/* auto-detect? */
|
|
if (fpi->phy_addr == -1) {
|
|
start = 0;
|
|
end = 32;
|
|
} else { /* direct */
|
|
start = fpi->phy_addr;
|
|
end = start + 1;
|
|
}
|
|
|
|
for (phy_id = start; phy_id < end; phy_id++) {
|
|
r = fec_mii_read(dev, phy_id, MII_PHYSID1);
|
|
if (r == -1 || (phytype = (r & 0xffff)) == 0xffff)
|
|
continue;
|
|
r = fec_mii_read(dev, phy_id, MII_PHYSID2);
|
|
if (r == -1 || (physubtype = (r & 0xffff)) == 0xffff)
|
|
continue;
|
|
phy_hwid = (phytype << 16) | physubtype;
|
|
if (phy_hwid != -1)
|
|
break;
|
|
}
|
|
|
|
if (phy_hwid == -1) {
|
|
printk(KERN_ERR DRV_MODULE_NAME
|
|
": %s No PHY detected!\n", dev->name);
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0, phy = phy_info; i < sizeof(phy_info) / sizeof(phy_info[0]);
|
|
i++, phy++)
|
|
if (phy->id == (phy_hwid >> 4) || phy->id == 0)
|
|
break;
|
|
|
|
if (i >= sizeof(phy_info) / sizeof(phy_info[0])) {
|
|
printk(KERN_ERR DRV_MODULE_NAME
|
|
": %s PHY id 0x%08x is not supported!\n",
|
|
dev->name, phy_hwid);
|
|
return -1;
|
|
}
|
|
|
|
fep->phy = phy;
|
|
|
|
printk(KERN_INFO DRV_MODULE_NAME
|
|
": %s Phy @ 0x%x, type %s (0x%08x)\n",
|
|
dev->name, phy_id, fep->phy->name, phy_hwid);
|
|
|
|
return phy_id;
|
|
}
|
|
|
|
void fec_mii_startup(struct net_device *dev)
|
|
{
|
|
struct fec_enet_private *fep = netdev_priv(dev);
|
|
const struct fec_platform_info *fpi = fep->fpi;
|
|
|
|
if (!fpi->use_mdio || fep->phy == NULL)
|
|
return;
|
|
|
|
if (fep->phy->startup == NULL)
|
|
return;
|
|
|
|
(*fep->phy->startup) (dev);
|
|
}
|
|
|
|
void fec_mii_shutdown(struct net_device *dev)
|
|
{
|
|
struct fec_enet_private *fep = netdev_priv(dev);
|
|
const struct fec_platform_info *fpi = fep->fpi;
|
|
|
|
if (!fpi->use_mdio || fep->phy == NULL)
|
|
return;
|
|
|
|
if (fep->phy->shutdown == NULL)
|
|
return;
|
|
|
|
(*fep->phy->shutdown) (dev);
|
|
}
|
|
|
|
void fec_mii_ack_int(struct net_device *dev)
|
|
{
|
|
struct fec_enet_private *fep = netdev_priv(dev);
|
|
const struct fec_platform_info *fpi = fep->fpi;
|
|
|
|
if (!fpi->use_mdio || fep->phy == NULL)
|
|
return;
|
|
|
|
if (fep->phy->ack_int == NULL)
|
|
return;
|
|
|
|
(*fep->phy->ack_int) (dev);
|
|
}
|
|
|
|
/* helper function */
|
|
static int mii_negotiated(struct mii_if_info *mii)
|
|
{
|
|
int advert, lpa, val;
|
|
|
|
if (!mii_link_ok(mii))
|
|
return 0;
|
|
|
|
val = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_BMSR);
|
|
if ((val & BMSR_ANEGCOMPLETE) == 0)
|
|
return 0;
|
|
|
|
advert = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_ADVERTISE);
|
|
lpa = (*mii->mdio_read) (mii->dev, mii->phy_id, MII_LPA);
|
|
|
|
return mii_nway_result(advert & lpa);
|
|
}
|
|
|
|
void fec_mii_link_status_change_check(struct net_device *dev, int init_media)
|
|
{
|
|
struct fec_enet_private *fep = netdev_priv(dev);
|
|
unsigned int media;
|
|
unsigned long flags;
|
|
|
|
if (mii_check_media(&fep->mii_if, netif_msg_link(fep), init_media) == 0)
|
|
return;
|
|
|
|
media = mii_negotiated(&fep->mii_if);
|
|
|
|
if (netif_carrier_ok(dev)) {
|
|
spin_lock_irqsave(&fep->lock, flags);
|
|
fec_restart(dev, !!(media & ADVERTISE_FULL),
|
|
(media & (ADVERTISE_100FULL | ADVERTISE_100HALF)) ?
|
|
100 : 10);
|
|
spin_unlock_irqrestore(&fep->lock, flags);
|
|
|
|
netif_start_queue(dev);
|
|
} else {
|
|
netif_stop_queue(dev);
|
|
|
|
spin_lock_irqsave(&fep->lock, flags);
|
|
fec_stop(dev);
|
|
spin_unlock_irqrestore(&fep->lock, flags);
|
|
|
|
}
|
|
}
|