Commit e0f4c5ce authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by David S. Miller

[SUNGEM]: Rework PM handling and fix MAC reset on stuck receiver.

This patch updates the sungem driver. I reworked all of the PM stuff, making it
less prone to races, probably simpler to read as well, and I no longer shut the
PHY down when the interface is down so that things like laptop-net no longer
die (the gain in power consumption was minimal, not worth the pain). I also
implemented basic WOL support.

There is still something I'm not totally happy with in the locking
(explained in the comment at the beginning), basically too much locking and a
couple of places with delays in locks. I will try to improve these later on.

It also adds a fix for a MAC reset issue when the receiver gets stuck.
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7f8a50e9
This diff is collapsed.
......@@ -170,6 +170,27 @@
* them later. -DaveM
*/
/* WakeOnLan Registers */
#define WOL_MATCH0 0x3000UL
#define WOL_MATCH1 0x3004UL
#define WOL_MATCH2 0x3008UL
#define WOL_MCOUNT 0x300CUL
#define WOL_WAKECSR 0x3010UL
/* WOL Match count register
*/
#define WOL_MCOUNT_N 0x00000010
#define WOL_MCOUNT_M 0x00000000 /* 0 << 8 */
#define WOL_WAKECSR_ENABLE 0x00000001
#define WOL_WAKECSR_MII 0x00000002
#define WOL_WAKECSR_SEEN 0x00000004
#define WOL_WAKECSR_FILT_UCAST 0x00000008
#define WOL_WAKECSR_FILT_MCAST 0x00000010
#define WOL_WAKECSR_FILT_BCAST 0x00000020
#define WOL_WAKECSR_FILT_SEEN 0x00000040
/* Receive DMA Registers */
#define RXDMA_CFG 0x4000UL /* RX Configuration Register */
#define RXDMA_DBLOW 0x4004UL /* RX Descriptor Base Low */
......@@ -958,39 +979,32 @@ struct gem {
int rx_new, rx_old;
int tx_new, tx_old;
/* Set when chip is actually in operational state
* (ie. not power managed)
*/
int hw_running;
int opened;
struct semaphore pm_sem;
struct work_struct pm_task;
struct timer_list pm_timer;
unsigned int has_wol : 1; /* chip supports wake-on-lan */
unsigned int asleep : 1; /* chip asleep, protected by pm_sem */
unsigned int asleep_wol : 1; /* was asleep with WOL enabled */
unsigned int opened : 1; /* driver opened, protected by pm_sem */
unsigned int running : 1; /* chip running, protected by lock */
struct gem_init_block *init_block;
/* cell enable count, protected by lock */
int cell_enabled;
struct sk_buff *rx_skbs[RX_RING_SIZE];
struct sk_buff *tx_skbs[RX_RING_SIZE];
struct semaphore pm_sem;
u32 msg_enable;
u32 status;
struct net_device_stats net_stats;
enum gem_phy_type phy_type;
struct mii_phy phy_mii;
int tx_fifo_sz;
int rx_fifo_sz;
int rx_pause_off;
int rx_pause_on;
int rx_buf_sz;
int mii_phy_addr;
u64 pause_entered;
u16 pause_last_time_recvd;
u32 mac_rx_cfg;
u32 swrst_base;
/* Autoneg & PHY control */
int want_autoneg;
int last_forced_speed;
enum link_state lstate;
......@@ -1000,11 +1014,15 @@ struct gem {
struct work_struct reset_task;
volatile int reset_task_pending;
/* Diagnostic counters and state. */
u64 pause_entered;
u16 pause_last_time_recvd;
enum gem_phy_type phy_type;
struct mii_phy phy_mii;
int mii_phy_addr;
struct gem_init_block *init_block;
struct sk_buff *rx_skbs[RX_RING_SIZE];
struct sk_buff *tx_skbs[RX_RING_SIZE];
dma_addr_t gblock_dvma;
struct pci_dev *pdev;
struct net_device *dev;
#ifdef CONFIG_PPC_PMAC
......
......@@ -98,25 +98,15 @@ static int bcm5201_init(struct mii_phy* phy)
data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
phy_write(phy, MII_BCM5201_MULTIPHY, data);
phy_write(phy, MII_BCM5201_INTERRUPT, 0);
return 0;
}
static int bcm5201_suspend(struct mii_phy* phy, int wol_options)
static int bcm5201_suspend(struct mii_phy* phy)
{
if (!wol_options)
phy_write(phy, MII_BCM5201_INTERRUPT, 0);
/* Here's a strange hack used by both MacOS 9 and X */
phy_write(phy, MII_LPA, phy_read(phy, MII_LPA));
if (!wol_options) {
#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
u16 val = phy_read(phy, MII_BCM5201_AUXMODE2)
phy_write(phy, MII_BCM5201_AUXMODE2,
val & ~MII_BCM5201_AUXMODE2_LOWPOWER);
#endif
phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
}
return 0;
}
......@@ -144,6 +134,21 @@ static int bcm5221_init(struct mii_phy* phy)
return 0;
}
static int bcm5221_suspend(struct mii_phy* phy)
{
u16 data;
data = phy_read(phy, MII_BCM5221_TEST);
phy_write(phy, MII_BCM5221_TEST,
data | MII_BCM5221_TEST_ENABLE_SHADOWS);
data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
data | MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE);
return 0;
}
static int bcm5400_init(struct mii_phy* phy)
{
u16 data;
......@@ -173,7 +178,7 @@ static int bcm5400_init(struct mii_phy* phy)
return 0;
}
static int bcm5400_suspend(struct mii_phy* phy, int wol_options)
static int bcm5400_suspend(struct mii_phy* phy)
{
#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
phy_write(phy, MII_BMCR, BMCR_PDOWN);
......@@ -229,7 +234,7 @@ static int bcm5401_init(struct mii_phy* phy)
return 0;
}
static int bcm5401_suspend(struct mii_phy* phy, int wol_options)
static int bcm5401_suspend(struct mii_phy* phy)
{
#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
phy_write(phy, MII_BMCR, BMCR_PDOWN);
......@@ -266,7 +271,7 @@ static int bcm5411_init(struct mii_phy* phy)
return 0;
}
static int bcm5411_suspend(struct mii_phy* phy, int wol_options)
static int bcm5411_suspend(struct mii_phy* phy)
{
phy_write(phy, MII_BMCR, BMCR_PDOWN);
......@@ -662,7 +667,7 @@ static struct mii_phy_def bcm5201_phy_def = {
/* Broadcom BCM 5221 */
static struct mii_phy_ops bcm5221_phy_ops = {
.suspend = bcm5201_suspend,
.suspend = bcm5221_suspend,
.init = bcm5221_init,
.setup_aneg = genmii_setup_aneg,
.setup_forced = genmii_setup_forced,
......
......@@ -7,7 +7,7 @@ struct mii_phy;
struct mii_phy_ops
{
int (*init)(struct mii_phy *phy);
int (*suspend)(struct mii_phy *phy, int wol_options);
int (*suspend)(struct mii_phy *phy);
int (*setup_aneg)(struct mii_phy *phy, u32 advertise);
int (*setup_forced)(struct mii_phy *phy, int speed, int fd);
int (*poll_link)(struct mii_phy *phy);
......@@ -80,6 +80,7 @@ extern int mii_phy_probe(struct mii_phy *phy, int mii_id);
#define MII_BCM5221_SHDOW_AUX_STAT2 0x1b
#define MII_BCM5221_SHDOW_AUX_STAT2_APD 0x0020
#define MII_BCM5221_SHDOW_AUX_MODE4 0x1a
#define MII_BCM5221_SHDOW_AUX_MODE4_IDDQMODE 0x0001
#define MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR 0x0004
/* MII BCM5400 1000-BASET Control register */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment