2007-02-20 22:13:21

by linas

[permalink] [raw]
Subject: [PATCH 0/12]: spidernet updates



Jeff,
Please apply and forward upstream this patch series.

This is the followup to the collision of patches that
landed on your doorstep last week. It rolls up the
patches from Jens and Kou.

--linas


2007-02-20 22:30:54

by linas

[permalink] [raw]
Subject: [PATCH 1/12]: sungem_phy: support bcm5461 phy, autoneg.


From: Jens Osterkamp <[email protected]>

This version moves the medium variable to the card specific structure and
changes the GMII_* to BCM54XX_* #defines.

This patch adds improved version of enable_fiber for both the 5421 and
the 5461 phy. It is now possible to specify with these wether you want
autonegotiation or not. This is needed for bladecenter switches where
some expect autonegotiation and some dont seem to like this at all.
Depending on this flag it sets phy->autoneg accordingly for the fiber mode.

More importantly it implements proper read_link and poll_link functions
for both phys which can handle both copper and fiber mode by determining
the medium first and then branching to the required functions. For fiber
they all work fine, for copper they are not tested but return the result
of the genmii_* function anyway which is supposed to work.

The patch moves the genmii_* functions around to avoid foreward declarations.

Signed-off-by: Jens Osterkamp <[email protected]>
Signed-off-by: Arnd Bergmann <[email protected]>
Signed-off-by: Linas Vepstas <[email protected]>

----
drivers/net/sungem_phy.c | 389 ++++++++++++++++++++++++++++++-----------------
drivers/net/sungem_phy.h | 10 +
2 files changed, 263 insertions(+), 136 deletions(-)

Index: linux-2.6.20-git16/drivers/net/sungem_phy.c
===================================================================
--- linux-2.6.20-git16.orig/drivers/net/sungem_phy.c 2007-02-20 14:24:00.000000000 -0600
+++ linux-2.6.20-git16/drivers/net/sungem_phy.c 2007-02-20 14:33:06.000000000 -0600
@@ -310,6 +310,107 @@ static int bcm5411_init(struct mii_phy*
return 0;
}

+static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
+{
+ u16 ctl, adv;
+
+ phy->autoneg = 1;
+ phy->speed = SPEED_10;
+ phy->duplex = DUPLEX_HALF;
+ phy->pause = 0;
+ phy->advertising = advertise;
+
+ /* Setup standard advertise */
+ adv = phy_read(phy, 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;
+ phy_write(phy, MII_ADVERTISE, adv);
+
+ /* Start/Restart aneg */
+ ctl = phy_read(phy, MII_BMCR);
+ ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+ phy_write(phy, MII_BMCR, ctl);
+
+ return 0;
+}
+
+static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
+{
+ u16 ctl;
+
+ phy->autoneg = 0;
+ phy->speed = speed;
+ phy->duplex = fd;
+ phy->pause = 0;
+
+ ctl = phy_read(phy, MII_BMCR);
+ ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
+
+ /* First reset the PHY */
+ phy_write(phy, 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;
+ phy_write(phy, MII_BMCR, ctl);
+
+ return 0;
+}
+
+static int genmii_poll_link(struct mii_phy *phy)
+{
+ u16 status;
+
+ (void)phy_read(phy, MII_BMSR);
+ status = phy_read(phy, MII_BMSR);
+ if ((status & BMSR_LSTATUS) == 0)
+ return 0;
+ if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
+ return 0;
+ return 1;
+}
+
+static int genmii_read_link(struct mii_phy *phy)
+{
+ u16 lpa;
+
+ if (phy->autoneg) {
+ lpa = phy_read(phy, MII_LPA);
+
+ if (lpa & (LPA_10FULL | LPA_100FULL))
+ phy->duplex = DUPLEX_FULL;
+ else
+ phy->duplex = DUPLEX_HALF;
+ if (lpa & (LPA_100FULL | LPA_100HALF))
+ phy->speed = SPEED_100;
+ else
+ phy->speed = SPEED_10;
+ phy->pause = 0;
+ }
+ /* On non-aneg, we assume what we put in BMCR is the speed,
+ * though magic-aneg shouldn't prevent this case from occurring
+ */
+
+ return 0;
+}
+
static int generic_suspend(struct mii_phy* phy)
{
phy_write(phy, MII_BMCR, BMCR_PDOWN);
@@ -364,30 +465,6 @@ static int bcm5421_init(struct mii_phy*
return 0;
}

-static int bcm5421_enable_fiber(struct mii_phy* phy)
-{
- /* enable fiber mode */
- phy_write(phy, MII_NCONFIG, 0x9020);
- /* LEDs active in both modes, autosense prio = fiber */
- phy_write(phy, MII_NCONFIG, 0x945f);
-
- /* switch off fibre autoneg */
- phy_write(phy, MII_NCONFIG, 0xfc01);
- phy_write(phy, 0x0b, 0x0004);
-
- return 0;
-}
-
-static int bcm5461_enable_fiber(struct mii_phy* phy)
-{
- phy_write(phy, MII_NCONFIG, 0xfc0c);
- phy_write(phy, MII_BMCR, 0x4140);
- phy_write(phy, MII_NCONFIG, 0xfc0b);
- phy_write(phy, MII_BMCR, 0x0140);
-
- return 0;
-}
-
static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
{
u16 ctl, adv;
@@ -515,6 +592,155 @@ static int marvell88e1111_init(struct mi
return 0;
}

+#define BCM5421_MODE_MASK (1 << 5)
+
+static int bcm5421_poll_link(struct mii_phy* phy)
+{
+ u32 phy_reg;
+ int mode;
+
+ /* find out in what mode we are */
+ phy_write(phy, MII_NCONFIG, 0x1000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ mode = (phy_reg & BCM5421_MODE_MASK) >> 5;
+
+ if ( mode == BCM54XX_COPPER)
+ return genmii_poll_link(phy);
+
+ /* try to find out wether we have a link */
+ phy_write(phy, MII_NCONFIG, 0x2000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ if (phy_reg & 0x0020)
+ return 0;
+ else
+ return 1;
+}
+
+static int bcm5421_read_link(struct mii_phy* phy)
+{
+ u32 phy_reg;
+ int mode;
+
+ /* find out in what mode we are */
+ phy_write(phy, MII_NCONFIG, 0x1000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ mode = (phy_reg & BCM5421_MODE_MASK ) >> 5;
+
+ if ( mode == BCM54XX_COPPER)
+ return bcm54xx_read_link(phy);
+
+ phy->speed = SPEED_1000;
+
+ /* find out wether we are running half- or full duplex */
+ phy_write(phy, MII_NCONFIG, 0x2000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ if ( (phy_reg & 0x0080) >> 7)
+ phy->duplex |= DUPLEX_HALF;
+ else
+ phy->duplex |= DUPLEX_FULL;
+
+ return 0;
+}
+
+static int bcm5421_enable_fiber(struct mii_phy* phy, int autoneg)
+{
+ /* enable fiber mode */
+ phy_write(phy, MII_NCONFIG, 0x9020);
+ /* LEDs active in both modes, autosense prio = fiber */
+ phy_write(phy, MII_NCONFIG, 0x945f);
+
+ if (!autoneg) {
+ /* switch off fibre autoneg */
+ phy_write(phy, MII_NCONFIG, 0xfc01);
+ phy_write(phy, 0x0b, 0x0004);
+ }
+
+ phy->autoneg = autoneg;
+
+ return 0;
+}
+
+#define BCM5461_FIBER_LINK (1 << 2)
+#define BCM5461_MODE_MASK (3 << 1)
+
+static int bcm5461_poll_link(struct mii_phy* phy)
+{
+ u32 phy_reg;
+ int mode;
+
+ /* find out in what mode we are */
+ phy_write(phy, MII_NCONFIG, 0x7c00);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
+
+ if ( mode == BCM54XX_COPPER)
+ return genmii_poll_link(phy);
+
+ /* find out wether we have a link */
+ phy_write(phy, MII_NCONFIG, 0x7000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ if (phy_reg & BCM5461_FIBER_LINK)
+ return 1;
+ else
+ return 0;
+}
+
+#define BCM5461_FIBER_DUPLEX (1 << 3)
+
+static int bcm5461_read_link(struct mii_phy* phy)
+{
+ u32 phy_reg;
+ int mode;
+
+ /* find out in what mode we are */
+ phy_write(phy, MII_NCONFIG, 0x7c00);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ mode = (phy_reg & BCM5461_MODE_MASK ) >> 1;
+
+ if ( mode == BCM54XX_COPPER) {
+ return bcm54xx_read_link(phy);
+ }
+
+ phy->speed = SPEED_1000;
+
+ /* find out wether we are running half- or full duplex */
+ phy_write(phy, MII_NCONFIG, 0x7000);
+ phy_reg = phy_read(phy, MII_NCONFIG);
+
+ if (phy_reg & BCM5461_FIBER_DUPLEX)
+ phy->duplex |= DUPLEX_FULL;
+ else
+ phy->duplex |= DUPLEX_HALF;
+
+ return 0;
+}
+
+static int bcm5461_enable_fiber(struct mii_phy* phy, int autoneg)
+{
+ /* select fiber mode, enable 1000 base-X registers */
+ phy_write(phy, MII_NCONFIG, 0xfc0b);
+
+ if (autoneg) {
+ /* enable fiber with no autonegotiation */
+ phy_write(phy, MII_ADVERTISE, 0x01e0);
+ phy_write(phy, MII_BMCR, 0x1140);
+ } else {
+ /* enable fiber with autonegotiation */
+ phy_write(phy, MII_BMCR, 0x0140);
+ }
+
+ phy->autoneg = autoneg;
+
+ return 0;
+}
+
static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
{
u16 ctl, adv;
@@ -645,113 +871,6 @@ static int marvell_read_link(struct mii_
return 0;
}

-static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
-{
- u16 ctl, adv;
-
- phy->autoneg = 1;
- phy->speed = SPEED_10;
- phy->duplex = DUPLEX_HALF;
- phy->pause = 0;
- phy->advertising = advertise;
-
- /* Setup standard advertise */
- adv = phy_read(phy, 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;
- if (advertise & ADVERTISED_Pause)
- adv |= ADVERTISE_PAUSE_CAP;
- if (advertise & ADVERTISED_Asym_Pause)
- adv |= ADVERTISE_PAUSE_ASYM;
- phy_write(phy, MII_ADVERTISE, adv);
-
- /* Start/Restart aneg */
- ctl = phy_read(phy, MII_BMCR);
- ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
- phy_write(phy, MII_BMCR, ctl);
-
- return 0;
-}
-
-static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
-{
- u16 ctl;
-
- phy->autoneg = 0;
- phy->speed = speed;
- phy->duplex = fd;
- phy->pause = 0;
-
- ctl = phy_read(phy, MII_BMCR);
- ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
-
- /* First reset the PHY */
- phy_write(phy, 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;
- phy_write(phy, MII_BMCR, ctl);
-
- return 0;
-}
-
-static int genmii_poll_link(struct mii_phy *phy)
-{
- u16 status;
-
- (void)phy_read(phy, MII_BMSR);
- status = phy_read(phy, MII_BMSR);
- if ((status & BMSR_LSTATUS) == 0)
- return 0;
- if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
- return 0;
- return 1;
-}
-
-static int genmii_read_link(struct mii_phy *phy)
-{
- u16 lpa;
-
- if (phy->autoneg) {
- lpa = phy_read(phy, MII_LPA);
-
- if (lpa & (LPA_10FULL | LPA_100FULL))
- phy->duplex = DUPLEX_FULL;
- else
- phy->duplex = DUPLEX_HALF;
- if (lpa & (LPA_100FULL | LPA_100HALF))
- phy->speed = SPEED_100;
- else
- phy->speed = SPEED_10;
- phy->pause = (phy->duplex == DUPLEX_FULL) &&
- ((lpa & LPA_PAUSE) != 0);
- }
- /* On non-aneg, we assume what we put in BMCR is the speed,
- * though magic-aneg shouldn't prevent this case from occurring
- */
-
- return 0;
-}
-
-
#define MII_BASIC_FEATURES \
(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
@@ -885,8 +1004,8 @@ static struct mii_phy_ops bcm5421_phy_op
.suspend = generic_suspend,
.setup_aneg = bcm54xx_setup_aneg,
.setup_forced = bcm54xx_setup_forced,
- .poll_link = genmii_poll_link,
- .read_link = bcm54xx_read_link,
+ .poll_link = bcm5421_poll_link,
+ .read_link = bcm5421_read_link,
.enable_fiber = bcm5421_enable_fiber,
};

@@ -923,8 +1042,8 @@ static struct mii_phy_ops bcm5461_phy_op
.suspend = generic_suspend,
.setup_aneg = bcm54xx_setup_aneg,
.setup_forced = bcm54xx_setup_forced,
- .poll_link = genmii_poll_link,
- .read_link = bcm54xx_read_link,
+ .poll_link = bcm5461_poll_link,
+ .read_link = bcm5461_read_link,
.enable_fiber = bcm5461_enable_fiber,
};

Index: linux-2.6.20-git16/drivers/net/sungem_phy.h
===================================================================
--- linux-2.6.20-git16.orig/drivers/net/sungem_phy.h 2007-02-04 12:44:54.000000000 -0600
+++ linux-2.6.20-git16/drivers/net/sungem_phy.h 2007-02-20 14:33:06.000000000 -0600
@@ -12,7 +12,7 @@ struct mii_phy_ops
int (*setup_forced)(struct mii_phy *phy, int speed, int fd);
int (*poll_link)(struct mii_phy *phy);
int (*read_link)(struct mii_phy *phy);
- int (*enable_fiber)(struct mii_phy *phy);
+ int (*enable_fiber)(struct mii_phy *phy, int autoneg);
};

/* Structure used to statically define an mii/gii based PHY */
@@ -26,6 +26,14 @@ struct mii_phy_def
const struct mii_phy_ops* ops;
};

+enum {
+ BCM54XX_COPPER,
+ BCM54XX_FIBER,
+ BCM54XX_GBIC,
+ BCM54XX_SGMII,
+ BCM54XX_UNKNOWN,
+};
+
/* An instance of a PHY, partially borrowed from mii_if_info */
struct mii_phy
{

2007-02-20 22:32:06

by linas

[permalink] [raw]
Subject: [PATCH 2/12] spidernet: compile break.


As of 2.6.20-git4, the spider_net driver does not compile.
This appears to be due to some archaic usage involving kobjects.

It also fixes a nasty double-free during ifdown of the interface.

Signed-off-by: Linas Vepstas <[email protected]>
Cc: Jens Osterkamp <[email protected]>
Cc: Kou Ishizaki <[email protected]>

----
drivers/net/spider_net.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)

Index: linux-2.6.20-git16/drivers/net/spider_net.c
===================================================================
--- linux-2.6.20-git16.orig/drivers/net/spider_net.c 2007-02-20 14:24:00.000000000 -0600
+++ linux-2.6.20-git16/drivers/net/spider_net.c 2007-02-20 14:36:13.000000000 -0600
@@ -1906,8 +1906,7 @@ spider_net_stop(struct net_device *netde
spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK, 0);
spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0);

- /* free_irq(netdev->irq, netdev);*/
- free_irq(to_pci_dev(netdev->dev.parent)->irq, netdev);
+ free_irq(netdev->irq, netdev);

spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
SPIDER_NET_DMA_TX_FEND_VALUE);
@@ -1919,8 +1918,6 @@ spider_net_stop(struct net_device *netde
spider_net_release_tx_chain(card, 1);
spider_net_free_rx_chain_contents(card);

- spider_net_free_rx_chain_contents(card);
-
spider_net_free_chain(card, &card->tx_chain);
spider_net_free_chain(card, &card->rx_chain);

2007-02-20 22:33:45

by linas

[permalink] [raw]
Subject: [PATCH 3/12] spidernet: autoneg support for Celleb


From: Kou Ishizaki <[email protected]>

Add auto negotiation support for Celleb.

Signed-off-by: Kou Ishizaki <[email protected]>
Signed-off-by: Linas Vepstas <[email protected]>

----
drivers/net/spider_net.c | 176 ++++++++++++++++++++++++++++++++++++++++++-----
drivers/net/spider_net.h | 10 ++
2 files changed, 170 insertions(+), 16 deletions(-)

Index: linux-2.6.20-git16/drivers/net/spider_net.h
===================================================================
--- linux-2.6.20-git16.orig/drivers/net/spider_net.h 2007-02-20 14:24:00.000000000 -0600
+++ linux-2.6.20-git16/drivers/net/spider_net.h 2007-02-20 15:02:32.000000000 -0600
@@ -50,6 +50,8 @@ extern char spider_net_driver_name[];
#define SPIDER_NET_TX_DESCRIPTORS_MAX 512

#define SPIDER_NET_TX_TIMER (HZ/5)
+#define SPIDER_NET_ANEG_TIMER (HZ)
+#define SPIDER_NET_ANEG_TIMEOUT 2

#define SPIDER_NET_RX_CSUM_DEFAULT 1

@@ -104,6 +106,7 @@ extern char spider_net_driver_name[];

#define SPIDER_NET_GMACOPEMD 0x00000100
#define SPIDER_NET_GMACLENLMT 0x00000108
+#define SPIDER_NET_GMACST 0x00000110
#define SPIDER_NET_GMACINTEN 0x00000118
#define SPIDER_NET_GMACPHYCTRL 0x00000120

@@ -333,9 +336,12 @@ enum spider_net_int2_status {
/* We rely on flagged descriptor interrupts */
#define SPIDER_NET_RXINT ( (1 << SPIDER_NET_GDAFDCINT) )

+#define SPIDER_NET_LINKINT ( 1 << SPIDER_NET_GMAC2INT )
+
#define SPIDER_NET_ERRINT ( 0xffffffff & \
(~SPIDER_NET_TXINT) & \
- (~SPIDER_NET_RXINT) )
+ (~SPIDER_NET_RXINT) & \
+ (~SPIDER_NET_LINKINT) )

#define SPIDER_NET_GPREXEC 0x80000000
#define SPIDER_NET_GPRDAT_MASK 0x0000ffff
@@ -442,6 +448,8 @@ struct spider_net_card {
struct spider_net_descr_chain rx_chain;
struct spider_net_descr *low_watermark;

+ int aneg_count;
+ struct timer_list aneg_timer;
struct timer_list tx_timer;
struct work_struct tx_timeout_task;
atomic_t tx_timeout_task_counter;
Index: linux-2.6.20-git16/drivers/net/spider_net.c
===================================================================
--- linux-2.6.20-git16.orig/drivers/net/spider_net.c 2007-02-20 14:36:13.000000000 -0600
+++ linux-2.6.20-git16/drivers/net/spider_net.c 2007-02-20 15:02:32.000000000 -0600
@@ -166,6 +166,41 @@ spider_net_read_phy(struct net_device *n
}

/**
+ * spider_net_setup_aneg - initial auto-negotiation setup
+ * @card: device structure
+ **/
+static void
+spider_net_setup_aneg(struct spider_net_card *card)
+{
+ struct mii_phy *phy = &card->phy;
+ u32 advertise = 0;
+ u16 bmcr, bmsr, stat1000, estat;
+
+ bmcr = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMCR);
+ bmsr = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR);
+ stat1000 = spider_net_read_phy(card->netdev, phy->mii_id, MII_STAT1000);
+ estat = spider_net_read_phy(card->netdev, phy->mii_id, MII_ESTATUS);
+
+ if (bmsr & BMSR_10HALF)
+ advertise |= ADVERTISED_10baseT_Half;
+ if (bmsr & BMSR_10FULL)
+ advertise |= ADVERTISED_10baseT_Full;
+ if (bmsr & BMSR_100HALF)
+ advertise |= ADVERTISED_100baseT_Half;
+ if (bmsr & BMSR_100FULL)
+ advertise |= ADVERTISED_100baseT_Full;
+
+ if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_TFULL))
+ advertise |= SUPPORTED_1000baseT_Full;
+ if ((bmsr & BMSR_ESTATEN) && (estat & ESTATUS_1000_THALF))
+ advertise |= SUPPORTED_1000baseT_Half;
+
+ mii_phy_probe(phy, phy->mii_id);
+ phy->def->ops->setup_aneg(phy, advertise);
+
+}
+
+/**
* spider_net_rx_irq_off - switch off rx irq on this spider card
* @card: device structure
*
@@ -1248,6 +1283,33 @@ spider_net_set_mac(struct net_device *ne
}

/**
+ * spider_net_link_reset
+ * @netdev: net device structure
+ *
+ * This is called when the PHY_LINK signal is asserted. For the blade this is
+ * not connected so we should never get here.
+ *
+ */
+static void
+spider_net_link_reset(struct net_device *netdev)
+{
+
+ struct spider_net_card *card = netdev_priv(netdev);
+
+ del_timer_sync(&card->aneg_timer);
+
+ /* clear interrupt, block further interrupts */
+ spider_net_write_reg(card, SPIDER_NET_GMACST,
+ spider_net_read_reg(card, SPIDER_NET_GMACST));
+ spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0);
+
+ /* reset phy and setup aneg */
+ spider_net_setup_aneg(card);
+ mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
+
+}
+
+/**
* spider_net_handle_error_irq - handles errors raised by an interrupt
* @card: card structure
* @status_reg: interrupt status register 0 (GHIINT0STS)
@@ -1500,6 +1562,9 @@ spider_net_interrupt(int irq, void *ptr)
if (status_reg & SPIDER_NET_TXINT)
netif_rx_schedule(netdev);

+ if (status_reg & SPIDER_NET_LINKINT)
+ spider_net_link_reset(netdev);
+
if (status_reg & SPIDER_NET_ERRINT )
spider_net_handle_error_irq(card, status_reg);

@@ -1624,8 +1689,6 @@ spider_net_enable_card(struct spider_net

spider_net_write_reg(card, SPIDER_NET_GMACLENLMT,
SPIDER_NET_LENLMT_VALUE);
- spider_net_write_reg(card, SPIDER_NET_GMACMODE,
- SPIDER_NET_MACMODE_VALUE);
spider_net_write_reg(card, SPIDER_NET_GMACOPEMD,
SPIDER_NET_OPMODE_VALUE);

@@ -1656,6 +1719,11 @@ spider_net_open(struct net_device *netde
struct spider_net_card *card = netdev_priv(netdev);
int result;

+ /* start probing with copper */
+ spider_net_setup_aneg(card);
+ if (card->phy.def->phy_id)
+ mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
+
result = spider_net_init_chain(card, &card->tx_chain);
if (result)
goto alloc_tx_failed;
@@ -1693,17 +1761,88 @@ alloc_skbs_failed:
alloc_rx_failed:
spider_net_free_chain(card, &card->tx_chain);
alloc_tx_failed:
+ del_timer_sync(&card->aneg_timer);
return result;
}

/**
+ * spider_net_link_phy
+ * @data: used for pointer to card structure
+ *
+ */
+static void spider_net_link_phy(unsigned long data)
+{
+ struct spider_net_card *card = (struct spider_net_card *)data;
+ struct mii_phy *phy = &card->phy;
+
+ /* if link didn't come up after SPIDER_NET_ANEG_TIMEOUT tries, setup phy again */
+ if (card->aneg_count > SPIDER_NET_ANEG_TIMEOUT) {
+
+ pr_info("%s: link is down trying to bring it up\n", card->netdev->name);
+
+ switch (phy->medium) {
+ case GMII_COPPER:
+ /* enable fiber with autonegotiation first */
+ if (phy->def->ops->enable_fiber)
+ phy->def->ops->enable_fiber(phy, 1);
+ phy->medium = GMII_FIBER;
+ break;
+
+ case GMII_FIBER:
+ /* fiber didn't come up, try to disable fiber autoneg */
+ if (phy->def->ops->enable_fiber)
+ phy->def->ops->enable_fiber(phy, 0);
+ phy->medium = GMII_UNKNOWN;
+ break;
+
+ case GMII_UNKNOWN:
+ /* copper, fiber with and without failed,
+ * retry from beginning */
+ spider_net_setup_aneg(card);
+ phy->medium = GMII_COPPER;
+ break;
+ }
+
+ card->aneg_count = 0;
+ mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
+ return;
+ }
+
+ /* link still not up, try again later */
+ if (!(phy->def->ops->poll_link(phy))) {
+ card->aneg_count++;
+ mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);
+ return;
+ }
+
+ /* link came up, get abilities */
+ phy->def->ops->read_link(phy);
+
+ spider_net_write_reg(card, SPIDER_NET_GMACST,
+ spider_net_read_reg(card, SPIDER_NET_GMACST));
+ spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0x4);
+
+ if (phy->speed == 1000)
+ spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0x00000001);
+ else
+ spider_net_write_reg(card, SPIDER_NET_GMACMODE, 0);
+
+ card->aneg_count = 0;
+
+ pr_debug("Found %s with %i Mbps, %s-duplex %sautoneg.\n",
+ phy->def->name, phy->speed, phy->duplex==1 ? "Full" : "Half",
+ phy->autoneg==1 ? "" : "no ");
+
+ return;
+}
+
+/**
* spider_net_setup_phy - setup PHY
* @card: card structure
*
* returns 0 on success, <0 on failure
*
- * spider_net_setup_phy is used as part of spider_net_probe. Sets
- * the PHY to 1000 Mbps
+ * spider_net_setup_phy is used as part of spider_net_probe.
**/
static int
spider_net_setup_phy(struct spider_net_card *card)
@@ -1714,21 +1853,21 @@ spider_net_setup_phy(struct spider_net_c
SPIDER_NET_DMASEL_VALUE);
spider_net_write_reg(card, SPIDER_NET_GPCCTRL,
SPIDER_NET_PHY_CTRL_VALUE);
- phy->mii_id = 1;
+
phy->dev = card->netdev;
phy->mdio_read = spider_net_read_phy;
phy->mdio_write = spider_net_write_phy;

- mii_phy_probe(phy, phy->mii_id);
-
- if (phy->def->ops->setup_forced)
- phy->def->ops->setup_forced(phy, SPEED_1000, DUPLEX_FULL);
-
- phy->def->ops->enable_fiber(phy);
-
- phy->def->ops->read_link(phy);
- pr_info("Found %s with %i Mbps, %s-duplex.\n", phy->def->name,
- phy->speed, phy->duplex==1 ? "Full" : "Half");
+ for (phy->mii_id = 1; phy->mii_id <= 31; phy->mii_id++) {
+ unsigned short id;
+ id = spider_net_read_phy(card->netdev, phy->mii_id, MII_BMSR);
+ if (id != 0x0000 && id != 0xffff) {
+ if (!mii_phy_probe(phy, phy->mii_id)) {
+ pr_info("Found %s.\n", phy->def->name);
+ break;
+ }
+ }
+ }

return 0;
}
@@ -1900,11 +2039,13 @@ spider_net_stop(struct net_device *netde
netif_carrier_off(netdev);
netif_stop_queue(netdev);
del_timer_sync(&card->tx_timer);
+ del_timer_sync(&card->aneg_timer);

/* disable/mask all interrupts */
spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0);
spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK, 0);
spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0);
+ spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0);

free_irq(netdev->irq, netdev);

@@ -2043,6 +2184,11 @@ spider_net_setup_netdev(struct spider_ne
card->tx_timer.data = (unsigned long) card;
netdev->irq = card->pdev->irq;

+ card->aneg_count = 0;
+ init_timer(&card->aneg_timer);
+ card->aneg_timer.function = spider_net_link_phy;
+ card->aneg_timer.data = (unsigned long) card;
+
card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT;

card->tx_chain.num_desc = tx_descriptors;

2007-02-20 22:34:54

by linas

[permalink] [raw]
Subject: [PATCH 4/12] spidernet: load firmware when open


From: Kou Ishizaki <[email protected]>

This patch moves calling init_firmware() from spider_net_probe() to
spider_net_open() so as to use the driver by built-in.

Signed-off-by: Kou Ishizaki <[email protected]>
Signed-off-by: Linas Vepstas <[email protected]>

----
drivers/net/spider_net.c | 247 +++++++++++++++++++++++------------------------
1 file changed, 123 insertions(+), 124 deletions(-)

Index: linux-2.6.20-git16/drivers/net/spider_net.c
===================================================================
--- linux-2.6.20-git16.orig/drivers/net/spider_net.c 2007-02-20 15:02:32.000000000 -0600
+++ linux-2.6.20-git16/drivers/net/spider_net.c 2007-02-20 15:02:36.000000000 -0600
@@ -1705,6 +1705,124 @@ spider_net_enable_card(struct spider_net
}

/**
+ * spider_net_download_firmware - loads firmware into the adapter
+ * @card: card structure
+ * @firmware_ptr: pointer to firmware data
+ *
+ * spider_net_download_firmware loads the firmware data into the
+ * adapter. It assumes the length etc. to be allright.
+ */
+static int
+spider_net_download_firmware(struct spider_net_card *card,
+ const void *firmware_ptr)
+{
+ int sequencer, i;
+ const u32 *fw_ptr = firmware_ptr;
+
+ /* stop sequencers */
+ spider_net_write_reg(card, SPIDER_NET_GSINIT,
+ SPIDER_NET_STOP_SEQ_VALUE);
+
+ for (sequencer = 0; sequencer < SPIDER_NET_FIRMWARE_SEQS;
+ sequencer++) {
+ spider_net_write_reg(card,
+ SPIDER_NET_GSnPRGADR + sequencer * 8, 0);
+ for (i = 0; i < SPIDER_NET_FIRMWARE_SEQWORDS; i++) {
+ spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT +
+ sequencer * 8, *fw_ptr);
+ fw_ptr++;
+ }
+ }
+
+ if (spider_net_read_reg(card, SPIDER_NET_GSINIT))
+ return -EIO;
+
+ spider_net_write_reg(card, SPIDER_NET_GSINIT,
+ SPIDER_NET_RUN_SEQ_VALUE);
+
+ return 0;
+}
+
+/**
+ * spider_net_init_firmware - reads in firmware parts
+ * @card: card structure
+ *
+ * Returns 0 on success, <0 on failure
+ *
+ * spider_net_init_firmware opens the sequencer firmware and does some basic
+ * checks. This function opens and releases the firmware structure. A call
+ * to download the firmware is performed before the release.
+ *
+ * Firmware format
+ * ===============
+ * spider_fw.bin is expected to be a file containing 6*1024*4 bytes, 4k being
+ * the program for each sequencer. Use the command
+ * tail -q -n +2 Seq_code1_0x088.txt Seq_code2_0x090.txt \
+ * Seq_code3_0x098.txt Seq_code4_0x0A0.txt Seq_code5_0x0A8.txt \
+ * Seq_code6_0x0B0.txt | xxd -r -p -c4 > spider_fw.bin
+ *
+ * to generate spider_fw.bin, if you have sequencer programs with something
+ * like the following contents for each sequencer:
+ * <ONE LINE COMMENT>
+ * <FIRST 4-BYTES-WORD FOR SEQUENCER>
+ * <SECOND 4-BYTES-WORD FOR SEQUENCER>
+ * ...
+ * <1024th 4-BYTES-WORD FOR SEQUENCER>
+ */
+static int
+spider_net_init_firmware(struct spider_net_card *card)
+{
+ struct firmware *firmware = NULL;
+ struct device_node *dn;
+ const u8 *fw_prop = NULL;
+ int err = -ENOENT;
+ int fw_size;
+
+ if (request_firmware((const struct firmware **)&firmware,
+ SPIDER_NET_FIRMWARE_NAME, &card->pdev->dev) == 0) {
+ if ( (firmware->size != SPIDER_NET_FIRMWARE_LEN) &&
+ netif_msg_probe(card) ) {
+ pr_err("Incorrect size of spidernet firmware in " \
+ "filesystem. Looking in host firmware...\n");
+ goto try_host_fw;
+ }
+ err = spider_net_download_firmware(card, firmware->data);
+
+ release_firmware(firmware);
+ if (err)
+ goto try_host_fw;
+
+ goto done;
+ }
+
+try_host_fw:
+ dn = pci_device_to_OF_node(card->pdev);
+ if (!dn)
+ goto out_err;
+
+ fw_prop = get_property(dn, "firmware", &fw_size);
+ if (!fw_prop)
+ goto out_err;
+
+ if ( (fw_size != SPIDER_NET_FIRMWARE_LEN) &&
+ netif_msg_probe(card) ) {
+ pr_err("Incorrect size of spidernet firmware in " \
+ "host firmware\n");
+ goto done;
+ }
+
+ err = spider_net_download_firmware(card, fw_prop);
+
+done:
+ return err;
+out_err:
+ if (netif_msg_probe(card))
+ pr_err("Couldn't find spidernet firmware in filesystem " \
+ "or host firmware\n");
+ return err;
+}
+
+/**
* spider_net_open - called upon ifonfig up
* @netdev: interface device structure
*
@@ -1719,6 +1837,10 @@ spider_net_open(struct net_device *netde
struct spider_net_card *card = netdev_priv(netdev);
int result;

+ result = spider_net_init_firmware(card);
+ if (result)
+ goto init_firmware_failed;
+
/* start probing with copper */
spider_net_setup_aneg(card);
if (card->phy.def->phy_id)
@@ -1762,6 +1884,7 @@ alloc_rx_failed:
spider_net_free_chain(card, &card->tx_chain);
alloc_tx_failed:
del_timer_sync(&card->aneg_timer);
+init_firmware_failed:
return result;
}

@@ -1873,124 +1996,6 @@ spider_net_setup_phy(struct spider_net_c
}

/**
- * spider_net_download_firmware - loads firmware into the adapter
- * @card: card structure
- * @firmware_ptr: pointer to firmware data
- *
- * spider_net_download_firmware loads the firmware data into the
- * adapter. It assumes the length etc. to be allright.
- */
-static int
-spider_net_download_firmware(struct spider_net_card *card,
- const void *firmware_ptr)
-{
- int sequencer, i;
- const u32 *fw_ptr = firmware_ptr;
-
- /* stop sequencers */
- spider_net_write_reg(card, SPIDER_NET_GSINIT,
- SPIDER_NET_STOP_SEQ_VALUE);
-
- for (sequencer = 0; sequencer < SPIDER_NET_FIRMWARE_SEQS;
- sequencer++) {
- spider_net_write_reg(card,
- SPIDER_NET_GSnPRGADR + sequencer * 8, 0);
- for (i = 0; i < SPIDER_NET_FIRMWARE_SEQWORDS; i++) {
- spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT +
- sequencer * 8, *fw_ptr);
- fw_ptr++;
- }
- }
-
- if (spider_net_read_reg(card, SPIDER_NET_GSINIT))
- return -EIO;
-
- spider_net_write_reg(card, SPIDER_NET_GSINIT,
- SPIDER_NET_RUN_SEQ_VALUE);
-
- return 0;
-}
-
-/**
- * spider_net_init_firmware - reads in firmware parts
- * @card: card structure
- *
- * Returns 0 on success, <0 on failure
- *
- * spider_net_init_firmware opens the sequencer firmware and does some basic
- * checks. This function opens and releases the firmware structure. A call
- * to download the firmware is performed before the release.
- *
- * Firmware format
- * ===============
- * spider_fw.bin is expected to be a file containing 6*1024*4 bytes, 4k being
- * the program for each sequencer. Use the command
- * tail -q -n +2 Seq_code1_0x088.txt Seq_code2_0x090.txt \
- * Seq_code3_0x098.txt Seq_code4_0x0A0.txt Seq_code5_0x0A8.txt \
- * Seq_code6_0x0B0.txt | xxd -r -p -c4 > spider_fw.bin
- *
- * to generate spider_fw.bin, if you have sequencer programs with something
- * like the following contents for each sequencer:
- * <ONE LINE COMMENT>
- * <FIRST 4-BYTES-WORD FOR SEQUENCER>
- * <SECOND 4-BYTES-WORD FOR SEQUENCER>
- * ...
- * <1024th 4-BYTES-WORD FOR SEQUENCER>
- */
-static int
-spider_net_init_firmware(struct spider_net_card *card)
-{
- struct firmware *firmware = NULL;
- struct device_node *dn;
- const u8 *fw_prop = NULL;
- int err = -ENOENT;
- int fw_size;
-
- if (request_firmware((const struct firmware **)&firmware,
- SPIDER_NET_FIRMWARE_NAME, &card->pdev->dev) == 0) {
- if ( (firmware->size != SPIDER_NET_FIRMWARE_LEN) &&
- netif_msg_probe(card) ) {
- pr_err("Incorrect size of spidernet firmware in " \
- "filesystem. Looking in host firmware...\n");
- goto try_host_fw;
- }
- err = spider_net_download_firmware(card, firmware->data);
-
- release_firmware(firmware);
- if (err)
- goto try_host_fw;
-
- goto done;
- }
-
-try_host_fw:
- dn = pci_device_to_OF_node(card->pdev);
- if (!dn)
- goto out_err;
-
- fw_prop = get_property(dn, "firmware", &fw_size);
- if (!fw_prop)
- goto out_err;
-
- if ( (fw_size != SPIDER_NET_FIRMWARE_LEN) &&
- netif_msg_probe(card) ) {
- pr_err("Incorrect size of spidernet firmware in " \
- "host firmware\n");
- goto done;
- }
-
- err = spider_net_download_firmware(card, fw_prop);
-
-done:
- return err;
-out_err:
- if (netif_msg_probe(card))
- pr_err("Couldn't find spidernet firmware in filesystem " \
- "or host firmware\n");
- return err;
-}
-
-/**
* spider_net_workaround_rxramfull - work around firmware bug
* @card: card structure
*
@@ -2090,8 +2095,6 @@ spider_net_tx_timeout_task(struct work_s

if (spider_net_setup_phy(card))
goto out;
- if (spider_net_init_firmware(card))
- goto out;

spider_net_open(netdev);
spider_net_kick_tx_dma(card);
@@ -2363,10 +2366,6 @@ spider_net_probe(struct pci_dev *pdev, c
if (err)
goto out_undo_pci;

- err = spider_net_init_firmware(card);
- if (err)
- goto out_undo_pci;
-
err = spider_net_setup_netdev(card);
if (err)
goto out_undo_pci;

2007-02-20 22:36:19

by linas

[permalink] [raw]
Subject: [PATCH 5/12] spidernet: spidernet: add support for Celleb


From: Kou Ishizaki <[email protected]>

This patch adds or changes some HW specific settings for spider_net on
Celleb.

Signed-off-by: Kou Ishizaki <[email protected]>
Signed-off-by: Linas Vepstas <[email protected]>

----
drivers/net/Kconfig | 2 +-
drivers/net/spider_net.c | 8 +++++++-
drivers/net/spider_net.h | 6 ++++--
3 files changed, 12 insertions(+), 4 deletions(-)

Index: linux-2.6.20-git16/drivers/net/Kconfig
===================================================================
--- linux-2.6.20-git16.orig/drivers/net/Kconfig 2007-02-20 14:23:59.000000000 -0600
+++ linux-2.6.20-git16/drivers/net/Kconfig 2007-02-20 15:02:38.000000000 -0600
@@ -2245,7 +2245,7 @@ config BNX2

config SPIDER_NET
tristate "Spider Gigabit Ethernet driver"
- depends on PCI && PPC_IBM_CELL_BLADE
+ depends on PCI && (PPC_IBM_CELL_BLADE || PPC_CELLEB)
select FW_LOADER
help
This driver supports the Gigabit Ethernet chips present on the
Index: linux-2.6.20-git16/drivers/net/spider_net.h
===================================================================
--- linux-2.6.20-git16.orig/drivers/net/spider_net.h 2007-02-20 15:02:32.000000000 -0600
+++ linux-2.6.20-git16/drivers/net/spider_net.h 2007-02-20 15:02:38.000000000 -0600
@@ -1,7 +1,8 @@
/*
- * Network device driver for Cell Processor-Based Blade
+ * Network device driver for Cell Processor-Based Blade and Celleb platform
*
* (C) Copyright IBM Corp. 2005
+ * (C) Copyright 2006 TOSHIBA CORPORATION
*
* Authors : Utz Bacher <[email protected]>
* Jens Osterkamp <[email protected]>
@@ -184,7 +185,8 @@ extern char spider_net_driver_name[];

/* pause frames: automatic, no upper retransmission count */
/* outside loopback mode: ETOMOD signal dont matter, not connected */
-#define SPIDER_NET_OPMODE_VALUE 0x00000063
+/* ETOMOD signal is brought to PHY reset. bit 2 must be 1 in Celleb */
+#define SPIDER_NET_OPMODE_VALUE 0x00000067
/*#define SPIDER_NET_OPMODE_VALUE 0x001b0062*/
#define SPIDER_NET_LENLMT_VALUE 0x00000908

Index: linux-2.6.20-git16/drivers/net/spider_net.c
===================================================================
--- linux-2.6.20-git16.orig/drivers/net/spider_net.c 2007-02-20 15:02:36.000000000 -0600
+++ linux-2.6.20-git16/drivers/net/spider_net.c 2007-02-20 15:02:38.000000000 -0600
@@ -1,7 +1,8 @@
/*
- * Network device driver for Cell Processor-Based Blade
+ * Network device driver for Cell Processor-Based Blade and Celleb platform
*
* (C) Copyright IBM Corp. 2005
+ * (C) Copyright 2006 TOSHIBA CORPORATION
*
* Authors : Utz Bacher <[email protected]>
* Jens Osterkamp <[email protected]>
@@ -1605,6 +1606,11 @@ spider_net_init_card(struct spider_net_c

spider_net_write_reg(card, SPIDER_NET_CKRCTRL,
SPIDER_NET_CKRCTRL_RUN_VALUE);
+
+ /* trigger ETOMOD signal */
+ spider_net_write_reg(card, SPIDER_NET_GMACOPEMD,
+ spider_net_read_reg(card, SPIDER_NET_GMACOPEMD) | 0x4);
+
}

/**

2007-02-20 22:37:46

by linas

[permalink] [raw]
Subject: [PATCH 6/12] spidernet: remove txram full logging


From: Ishizaki Kou <[email protected]>

This patches removes logging for SPIDER_NET_GTMFLLINT interrupts.
Since the interrupts are not irregular, and they happen frequently
when using 100Mbps network switches.

Signed-off-by: Kou Ishizaki <[email protected]>
Signed-off-by: Linas Vepstas <[email protected]>

----
drivers/net/spider_net.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

Index: linux-2.6.20-git16/drivers/net/spider_net.c
===================================================================
--- linux-2.6.20-git16.orig/drivers/net/spider_net.c 2007-02-20 15:02:38.000000000 -0600
+++ linux-2.6.20-git16/drivers/net/spider_net.c 2007-02-20 15:02:40.000000000 -0600
@@ -1422,8 +1422,8 @@ spider_net_handle_error_irq(struct spide
switch (i)
{
case SPIDER_NET_GTMFLLINT:
- if (netif_msg_intr(card) && net_ratelimit())
- pr_err("Spider TX RAM full\n");
+ /* TX RAM full may happen on a usual case.
+ * Logging is not needed. */
show_error = 0;
break;
case SPIDER_NET_GRFDFLLINT: /* fallthrough */

2007-02-20 22:39:18

by linas

[permalink] [raw]
Subject: [PATCH 7/12] spidernet: move medium variable into card struct


From: Jens Osterkamp <[email protected]>

This moves the medium variable into the spidernet card structure.
It renames the GMII_ variables to BCM54XX specific ones.

Signed-off-by: Jens Osterkamp <[email protected]>
Signed-off-by: Linas Vepstas <[email protected]>

----
drivers/net/spider_net.c | 14 +++++++-------
drivers/net/spider_net.h | 2 ++
2 files changed, 9 insertions(+), 7 deletions(-)

Index: linux-2.6.20-git16/drivers/net/spider_net.c
===================================================================
--- linux-2.6.20-git16.orig/drivers/net/spider_net.c 2007-02-20 15:02:40.000000000 -0600
+++ linux-2.6.20-git16/drivers/net/spider_net.c 2007-02-20 15:02:42.000000000 -0600
@@ -1909,26 +1909,26 @@ static void spider_net_link_phy(unsigned

pr_info("%s: link is down trying to bring it up\n", card->netdev->name);

- switch (phy->medium) {
- case GMII_COPPER:
+ switch (card->medium) {
+ case BCM54XX_COPPER:
/* enable fiber with autonegotiation first */
if (phy->def->ops->enable_fiber)
phy->def->ops->enable_fiber(phy, 1);
- phy->medium = GMII_FIBER;
+ card->medium = BCM54XX_FIBER;
break;

- case GMII_FIBER:
+ case BCM54XX_FIBER:
/* fiber didn't come up, try to disable fiber autoneg */
if (phy->def->ops->enable_fiber)
phy->def->ops->enable_fiber(phy, 0);
- phy->medium = GMII_UNKNOWN;
+ card->medium = BCM54XX_UNKNOWN;
break;

- case GMII_UNKNOWN:
+ case BCM54XX_UNKNOWN:
/* copper, fiber with and without failed,
* retry from beginning */
spider_net_setup_aneg(card);
- phy->medium = GMII_COPPER;
+ card->medium = BCM54XX_COPPER;
break;
}

Index: linux-2.6.20-git16/drivers/net/spider_net.h
===================================================================
--- linux-2.6.20-git16.orig/drivers/net/spider_net.h 2007-02-20 15:02:38.000000000 -0600
+++ linux-2.6.20-git16/drivers/net/spider_net.h 2007-02-20 15:02:42.000000000 -0600
@@ -444,6 +444,8 @@ struct spider_net_card {
struct pci_dev *pdev;
struct mii_phy phy;

+ int medium;
+
void __iomem *regs;

struct spider_net_descr_chain tx_chain;

2007-02-20 22:40:12

by linas

[permalink] [raw]
Subject: [PATCH 8/12] spidernet: separate hardware state from driver state.


This patch separates the hardware descriptor state from the
driver descriptor state, per (old) suggestion from Ben Herrenschmidt.
This compiles and boots and seems to work.

Signed-off-by: Linas Vepstas <[email protected]>
Cc: Jens Osterkamp <[email protected]>
Cc: Kou Ishizaki <[email protected]>

----
drivers/net/spider_net.c | 150 ++++++++++++++++++++++++++---------------------
drivers/net/spider_net.h | 16 +++--
2 files changed, 95 insertions(+), 71 deletions(-)

Index: linux-2.6.20-git16/drivers/net/spider_net.h
===================================================================
--- linux-2.6.20-git16.orig/drivers/net/spider_net.h 2007-02-20 15:02:42.000000000 -0600
+++ linux-2.6.20-git16/drivers/net/spider_net.h 2007-02-20 15:02:44.000000000 -0600
@@ -25,7 +25,7 @@
#ifndef _SPIDER_NET_H
#define _SPIDER_NET_H

-#define VERSION "1.6 B"
+#define VERSION "1.6 C"

#include "sungem_phy.h"

@@ -364,8 +364,8 @@ enum spider_net_int2_status {
#define SPIDER_NET_DESCR_NOT_IN_USE 0xF0000000
#define SPIDER_NET_DESCR_TXDESFLG 0x00800000

-struct spider_net_descr {
- /* as defined by the hardware */
+/* Descriptor, as defined by the hardware */
+struct spider_net_hw_descr {
u32 buf_addr;
u32 buf_size;
u32 next_descr_addr;
@@ -374,13 +374,15 @@ struct spider_net_descr {
u32 valid_size; /* all zeroes for tx */
u32 data_status;
u32 data_error; /* all zeroes for tx */
+} __attribute__((aligned(32)));

- /* used in the driver */
+struct spider_net_descr {
+ struct spider_net_hw_descr *hwdescr;
struct sk_buff *skb;
u32 bus_addr;
struct spider_net_descr *next;
struct spider_net_descr *prev;
-} __attribute__((aligned(32)));
+};

struct spider_net_descr_chain {
spinlock_t lock;
@@ -388,6 +390,7 @@ struct spider_net_descr_chain {
struct spider_net_descr *tail;
struct spider_net_descr *ring;
int num_desc;
+ struct spider_net_hw_descr *hwring;
dma_addr_t dma_addr;
};

@@ -464,6 +467,9 @@ struct spider_net_card {
struct net_device_stats netdev_stats;
struct spider_net_extra_stats spider_stats;
struct spider_net_options options;
+
+ /* Must be last item in struct */
+ struct spider_net_descr darray[0];
};

#define pr_err(fmt,arg...) \
Index: linux-2.6.20-git16/drivers/net/spider_net.c
===================================================================
--- linux-2.6.20-git16.orig/drivers/net/spider_net.c 2007-02-20 15:02:42.000000000 -0600
+++ linux-2.6.20-git16/drivers/net/spider_net.c 2007-02-20 15:02:44.000000000 -0600
@@ -299,9 +299,9 @@ spider_net_get_mac_address(struct net_de
* returns the status as in the dmac_cmd_status field of the descriptor
*/
static inline int
-spider_net_get_descr_status(struct spider_net_descr *descr)
+spider_net_get_descr_status(struct spider_net_hw_descr *hwdescr)
{
- return descr->dmac_cmd_status & SPIDER_NET_DESCR_IND_PROC_MASK;
+ return hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_IND_PROC_MASK;
}

/**
@@ -319,12 +319,12 @@ spider_net_free_chain(struct spider_net_
descr = chain->ring;
do {
descr->bus_addr = 0;
- descr->next_descr_addr = 0;
+ descr->hwdescr->next_descr_addr = 0;
descr = descr->next;
} while (descr != chain->ring);

dma_free_coherent(&card->pdev->dev, chain->num_desc,
- chain->ring, chain->dma_addr);
+ chain->hwring, chain->dma_addr);
}

/**
@@ -343,31 +343,34 @@ spider_net_init_chain(struct spider_net_
{
int i;
struct spider_net_descr *descr;
+ struct spider_net_hw_descr *hwdescr;
dma_addr_t buf;
size_t alloc_size;

- alloc_size = chain->num_desc * sizeof (struct spider_net_descr);
+ alloc_size = chain->num_desc * sizeof(struct spider_net_hw_descr);

- chain->ring = dma_alloc_coherent(&card->pdev->dev, alloc_size,
+ chain->hwring = dma_alloc_coherent(&card->pdev->dev, alloc_size,
&chain->dma_addr, GFP_KERNEL);

- if (!chain->ring)
+ if (!chain->hwring)
return -ENOMEM;

- descr = chain->ring;
- memset(descr, 0, alloc_size);
+ memset(chain->ring, 0, chain->num_desc * sizeof(struct spider_net_descr));

/* Set up the hardware pointers in each descriptor */
+ descr = chain->ring;
+ hwdescr = chain->hwring;
buf = chain->dma_addr;
- for (i=0; i < chain->num_desc; i++, descr++) {
- descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+ for (i=0; i < chain->num_desc; i++, descr++, hwdescr++) {
+ hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+ hwdescr->next_descr_addr = 0;

+ descr->hwdescr = hwdescr;
descr->bus_addr = buf;
- descr->next_descr_addr = 0;
descr->next = descr + 1;
descr->prev = descr - 1;

- buf += sizeof(struct spider_net_descr);
+ buf += sizeof(struct spider_net_hw_descr);
}
/* do actual circular list */
(descr-1)->next = chain->ring;
@@ -394,7 +397,7 @@ spider_net_free_rx_chain_contents(struct
do {
if (descr->skb) {
dev_kfree_skb(descr->skb);
- pci_unmap_single(card->pdev, descr->buf_addr,
+ pci_unmap_single(card->pdev, descr->hwdescr->buf_addr,
SPIDER_NET_MAX_FRAME,
PCI_DMA_BIDIRECTIONAL);
}
@@ -416,6 +419,7 @@ static int
spider_net_prepare_rx_descr(struct spider_net_card *card,
struct spider_net_descr *descr)
{
+ struct spider_net_hw_descr *hwdescr = descr->hwdescr;
dma_addr_t buf;
int offset;
int bufsize;
@@ -434,11 +438,11 @@ spider_net_prepare_rx_descr(struct spide
card->spider_stats.alloc_rx_skb_error++;
return -ENOMEM;
}
- descr->buf_size = bufsize;
- descr->result_size = 0;
- descr->valid_size = 0;
- descr->data_status = 0;
- descr->data_error = 0;
+ hwdescr->buf_size = bufsize;
+ hwdescr->result_size = 0;
+ hwdescr->valid_size = 0;
+ hwdescr->data_status = 0;
+ hwdescr->data_error = 0;

offset = ((unsigned long)descr->skb->data) &
(SPIDER_NET_RXBUF_ALIGN - 1);
@@ -447,21 +451,21 @@ spider_net_prepare_rx_descr(struct spide
/* iommu-map the skb */
buf = pci_map_single(card->pdev, descr->skb->data,
SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
- descr->buf_addr = buf;
if (pci_dma_mapping_error(buf)) {
dev_kfree_skb_any(descr->skb);
if (netif_msg_rx_err(card) && net_ratelimit())
pr_err("Could not iommu-map rx buffer\n");
card->spider_stats.rx_iommu_map_error++;
- descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+ hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
} else {
- descr->next_descr_addr = 0;
+ hwdescr->buf_addr = buf;
+ hwdescr->next_descr_addr = 0;
wmb();
- descr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED |
+ hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED |
SPIDER_NET_DMAC_NOINTR_COMPLETE;

wmb();
- descr->prev->next_descr_addr = descr->bus_addr;
+ descr->prev->hwdescr->next_descr_addr = descr->bus_addr;
}

return 0;
@@ -517,7 +521,7 @@ spider_net_refill_rx_chain(struct spider
if (!spin_trylock_irqsave(&chain->lock, flags))
return;

- while (spider_net_get_descr_status(chain->head) ==
+ while (spider_net_get_descr_status(chain->head->hwdescr) ==
SPIDER_NET_DESCR_NOT_IN_USE) {
if (spider_net_prepare_rx_descr(card, chain->head))
break;
@@ -679,6 +683,7 @@ spider_net_prepare_tx_descr(struct spide
struct sk_buff *skb)
{
struct spider_net_descr *descr;
+ struct spider_net_hw_descr *hwdescr;
dma_addr_t buf;
unsigned long flags;

@@ -693,30 +698,32 @@ spider_net_prepare_tx_descr(struct spide

spin_lock_irqsave(&card->tx_chain.lock, flags);
descr = card->tx_chain.head;
+ hwdescr = descr->hwdescr;
card->tx_chain.head = descr->next;

- descr->buf_addr = buf;
- descr->buf_size = skb->len;
- descr->next_descr_addr = 0;
descr->skb = skb;
- descr->data_status = 0;
+ hwdescr->buf_addr = buf;
+ hwdescr->buf_size = skb->len;
+ hwdescr->next_descr_addr = 0;
+ hwdescr->data_status = 0;

- descr->dmac_cmd_status =
+ hwdescr->dmac_cmd_status =
SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOCS;
spin_unlock_irqrestore(&card->tx_chain.lock, flags);

if (skb->protocol == htons(ETH_P_IP))
switch (skb->nh.iph->protocol) {
case IPPROTO_TCP:
- descr->dmac_cmd_status |= SPIDER_NET_DMAC_TCP;
+ hwdescr->dmac_cmd_status |= SPIDER_NET_DMAC_TCP;
break;
case IPPROTO_UDP:
- descr->dmac_cmd_status |= SPIDER_NET_DMAC_UDP;
+ hwdescr->dmac_cmd_status |= SPIDER_NET_DMAC_UDP;
break;
}

/* Chain the bus address, so that the DMA engine finds this descr. */
- descr->prev->next_descr_addr = descr->bus_addr;
+ wmb();
+ descr->prev->hwdescr->next_descr_addr = descr->bus_addr;

card->netdev->trans_start = jiffies; /* set netdev watchdog timer */
return 0;
@@ -725,16 +732,17 @@ spider_net_prepare_tx_descr(struct spide
static int
spider_net_set_low_watermark(struct spider_net_card *card)
{
+ struct spider_net_descr *descr = card->tx_chain.tail;
+ struct spider_net_hw_descr *hwdescr;
unsigned long flags;
int status;
int cnt=0;
int i;
- struct spider_net_descr *descr = card->tx_chain.tail;

/* Measure the length of the queue. Measurement does not
* need to be precise -- does not need a lock. */
while (descr != card->tx_chain.head) {
- status = descr->dmac_cmd_status & SPIDER_NET_DESCR_NOT_IN_USE;
+ status = descr->hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_NOT_IN_USE;
if (status == SPIDER_NET_DESCR_NOT_IN_USE)
break;
descr = descr->next;
@@ -753,10 +761,12 @@ spider_net_set_low_watermark(struct spid

/* Set the new watermark, clear the old watermark */
spin_lock_irqsave(&card->tx_chain.lock, flags);
- descr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG;
- if (card->low_watermark && card->low_watermark != descr)
- card->low_watermark->dmac_cmd_status =
- card->low_watermark->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG;
+ descr->hwdescr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG;
+ if (card->low_watermark && card->low_watermark != descr) {
+ hwdescr = card->low_watermark->hwdescr;
+ hwdescr->dmac_cmd_status =
+ hwdescr->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG;
+ }
card->low_watermark = descr;
spin_unlock_irqrestore(&card->tx_chain.lock, flags);
return cnt;
@@ -779,6 +789,7 @@ spider_net_release_tx_chain(struct spide
{
struct spider_net_descr_chain *chain = &card->tx_chain;
struct spider_net_descr *descr;
+ struct spider_net_hw_descr *hwdescr;
struct sk_buff *skb;
u32 buf_addr;
unsigned long flags;
@@ -787,8 +798,9 @@ spider_net_release_tx_chain(struct spide
while (chain->tail != chain->head) {
spin_lock_irqsave(&chain->lock, flags);
descr = chain->tail;
+ hwdescr = descr->hwdescr;

- status = spider_net_get_descr_status(descr);
+ status = spider_net_get_descr_status(hwdescr);
switch (status) {
case SPIDER_NET_DESCR_COMPLETE:
card->netdev_stats.tx_packets++;
@@ -824,9 +836,9 @@ spider_net_release_tx_chain(struct spide
}

chain->tail = descr->next;
- descr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE;
+ hwdescr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE;
skb = descr->skb;
- buf_addr = descr->buf_addr;
+ buf_addr = hwdescr->buf_addr;
spin_unlock_irqrestore(&chain->lock, flags);

/* unmap the skb */
@@ -862,7 +874,7 @@ spider_net_kick_tx_dma(struct spider_net

descr = card->tx_chain.tail;
for (;;) {
- if (spider_net_get_descr_status(descr) ==
+ if (spider_net_get_descr_status(descr->hwdescr) ==
SPIDER_NET_DESCR_CARDOWNED) {
spider_net_write_reg(card, SPIDER_NET_GDTDCHA,
descr->bus_addr);
@@ -958,17 +970,18 @@ static void
spider_net_pass_skb_up(struct spider_net_descr *descr,
struct spider_net_card *card)
{
+ struct spider_net_hw_descr *hwdescr= descr->hwdescr;
struct sk_buff *skb;
struct net_device *netdev;
u32 data_status, data_error;

- data_status = descr->data_status;
- data_error = descr->data_error;
+ data_status = hwdescr->data_status;
+ data_error = hwdescr->data_error;
netdev = card->netdev;

skb = descr->skb;
skb->dev = netdev;
- skb_put(skb, descr->valid_size);
+ skb_put(skb, hwdescr->valid_size);

/* the card seems to add 2 bytes of junk in front
* of the ethernet frame */
@@ -1044,9 +1057,10 @@ spider_net_decode_one_descr(struct spide
{
struct spider_net_descr_chain *chain = &card->rx_chain;
struct spider_net_descr *descr = chain->tail;
+ struct spider_net_hw_descr *hwdescr = descr->hwdescr;
int status;

- status = spider_net_get_descr_status(descr);
+ status = spider_net_get_descr_status(hwdescr);

/* Nothing in the descriptor, or ring must be empty */
if ((status == SPIDER_NET_DESCR_CARDOWNED) ||
@@ -1057,7 +1071,7 @@ spider_net_decode_one_descr(struct spide
chain->tail = descr->next;

/* unmap descriptor */
- pci_unmap_single(card->pdev, descr->buf_addr,
+ pci_unmap_single(card->pdev, hwdescr->buf_addr,
SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);

if ( (status == SPIDER_NET_DESCR_RESPONSE_ERROR) ||
@@ -1080,27 +1094,26 @@ spider_net_decode_one_descr(struct spide
}

/* The cases we'll throw away the packet immediately */
- if (descr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
+ if (hwdescr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
if (netif_msg_rx_err(card))
pr_err("%s: error in received descriptor found, "
"data_status=x%08x, data_error=x%08x\n",
card->netdev->name,
- descr->data_status, descr->data_error);
+ hwdescr->data_status, hwdescr->data_error);
goto bad_desc;
}

- if (descr->dmac_cmd_status & 0xfefe) {
+ if (hwdescr->dmac_cmd_status & 0xfefe) {
pr_err("%s: bad status, cmd_status=x%08x\n",
card->netdev->name,
- descr->dmac_cmd_status);
- pr_err("buf_addr=x%08x\n", descr->buf_addr);
- pr_err("buf_size=x%08x\n", descr->buf_size);
- pr_err("next_descr_addr=x%08x\n", descr->next_descr_addr);
- pr_err("result_size=x%08x\n", descr->result_size);
- pr_err("valid_size=x%08x\n", descr->valid_size);
- pr_err("data_status=x%08x\n", descr->data_status);
- pr_err("data_error=x%08x\n", descr->data_error);
- pr_err("bus_addr=x%08x\n", descr->bus_addr);
+ hwdescr->dmac_cmd_status);
+ pr_err("buf_addr=x%08x\n", hwdescr->buf_addr);
+ pr_err("buf_size=x%08x\n", hwdescr->buf_size);
+ pr_err("next_descr_addr=x%08x\n", hwdescr->next_descr_addr);
+ pr_err("result_size=x%08x\n", hwdescr->result_size);
+ pr_err("valid_size=x%08x\n", hwdescr->valid_size);
+ pr_err("data_status=x%08x\n", hwdescr->data_status);
+ pr_err("data_error=x%08x\n", hwdescr->data_error);
pr_err("which=%ld\n", descr - card->rx_chain.ring);

card->spider_stats.rx_desc_error++;
@@ -1109,12 +1122,12 @@ spider_net_decode_one_descr(struct spide

/* Ok, we've got a packet in descr */
spider_net_pass_skb_up(descr, card);
- descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+ hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
return 1;

bad_desc:
dev_kfree_skb_irq(descr->skb);
- descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+ hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
return 0;
}

@@ -2200,9 +2213,6 @@ spider_net_setup_netdev(struct spider_ne

card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT;

- card->tx_chain.num_desc = tx_descriptors;
- card->rx_chain.num_desc = rx_descriptors;
-
spider_net_setup_netdev_ops(netdev);

netdev->features = NETIF_F_HW_CSUM | NETIF_F_LLTX;
@@ -2250,8 +2260,11 @@ spider_net_alloc_card(void)
{
struct net_device *netdev;
struct spider_net_card *card;
+ size_t alloc_size;

- netdev = alloc_etherdev(sizeof(struct spider_net_card));
+ alloc_size = sizeof(struct spider_net_card) +
+ (tx_descriptors + rx_descriptors) * sizeof(struct spider_net_descr);
+ netdev = alloc_etherdev(alloc_size);
if (!netdev)
return NULL;

@@ -2262,6 +2275,11 @@ spider_net_alloc_card(void)
init_waitqueue_head(&card->waitq);
atomic_set(&card->tx_timeout_task_counter, 0);

+ card->rx_chain.num_desc = rx_descriptors;
+ card->rx_chain.ring = card->darray;
+ card->tx_chain.num_desc = tx_descriptors;
+ card->tx_chain.ring = card->darray + rx_descriptors;
+
return card;
}

2007-02-20 22:41:09

by linas

[permalink] [raw]
Subject: [PATCH 9/12]: spidernet: fix racy double-free of skb


It appears that under certain circumstances, a race will result
in a double-free of an skb. This patch null's out the skb pointer
upon the skb free, avoiding the inadvertent deref of bogus data.
The next patch fixes the actual race.

Signed-off-by: Linas Vepstas <[email protected]>
Cc: Jens Osterkamp <[email protected]>
Cc: Kou Ishizaki <[email protected]>

----
drivers/net/spider_net.c | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)

Index: linux-2.6.20-git16/drivers/net/spider_net.c
===================================================================
--- linux-2.6.20-git16.orig/drivers/net/spider_net.c 2007-02-20 15:02:44.000000000 -0600
+++ linux-2.6.20-git16/drivers/net/spider_net.c 2007-02-20 15:02:46.000000000 -0600
@@ -396,10 +396,11 @@ spider_net_free_rx_chain_contents(struct
descr = card->rx_chain.head;
do {
if (descr->skb) {
- dev_kfree_skb(descr->skb);
pci_unmap_single(card->pdev, descr->hwdescr->buf_addr,
SPIDER_NET_MAX_FRAME,
PCI_DMA_BIDIRECTIONAL);
+ dev_kfree_skb(descr->skb);
+ descr->skb = NULL;
}
descr = descr->next;
} while (descr != card->rx_chain.head);
@@ -453,6 +454,7 @@ spider_net_prepare_rx_descr(struct spide
SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
if (pci_dma_mapping_error(buf)) {
dev_kfree_skb_any(descr->skb);
+ descr->skb = NULL;
if (netif_msg_rx_err(card) && net_ratelimit())
pr_err("Could not iommu-map rx buffer\n");
card->spider_stats.rx_iommu_map_error++;
@@ -682,6 +684,7 @@ static int
spider_net_prepare_tx_descr(struct spider_net_card *card,
struct sk_buff *skb)
{
+ struct spider_net_descr_chain *chain = &card->tx_chain;
struct spider_net_descr *descr;
struct spider_net_hw_descr *hwdescr;
dma_addr_t buf;
@@ -696,10 +699,15 @@ spider_net_prepare_tx_descr(struct spide
return -ENOMEM;
}

- spin_lock_irqsave(&card->tx_chain.lock, flags);
+ spin_lock_irqsave(&chain->lock, flags);
descr = card->tx_chain.head;
+ if (descr->next == chain->tail->prev) {
+ spin_unlock_irqrestore(&chain->lock, flags);
+ pci_unmap_single(card->pdev, buf, skb->len, PCI_DMA_TODEVICE);
+ return -ENOMEM;
+ }
hwdescr = descr->hwdescr;
- card->tx_chain.head = descr->next;
+ chain->head = descr->next;

descr->skb = skb;
hwdescr->buf_addr = buf;
@@ -709,7 +717,7 @@ spider_net_prepare_tx_descr(struct spide

hwdescr->dmac_cmd_status =
SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOCS;
- spin_unlock_irqrestore(&card->tx_chain.lock, flags);
+ spin_unlock_irqrestore(&chain->lock, flags);

if (skb->protocol == htons(ETH_P_IP))
switch (skb->nh.iph->protocol) {
@@ -838,6 +846,7 @@ spider_net_release_tx_chain(struct spide
chain->tail = descr->next;
hwdescr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE;
skb = descr->skb;
+ descr->skb = NULL;
buf_addr = hwdescr->buf_addr;
spin_unlock_irqrestore(&chain->lock, flags);

@@ -903,13 +912,10 @@ spider_net_xmit(struct sk_buff *skb, str
{
int cnt;
struct spider_net_card *card = netdev_priv(netdev);
- struct spider_net_descr_chain *chain = &card->tx_chain;

spider_net_release_tx_chain(card, 0);

- if ((chain->head->next == chain->tail->prev) ||
- (spider_net_prepare_tx_descr(card, skb) != 0)) {
-
+ if (spider_net_prepare_tx_descr(card, skb) != 0) {
card->netdev_stats.tx_dropped++;
netif_stop_queue(netdev);
return NETDEV_TX_BUSY;
@@ -1127,6 +1133,7 @@ spider_net_decode_one_descr(struct spide

bad_desc:
dev_kfree_skb_irq(descr->skb);
+ descr->skb = NULL;
hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
return 0;
}

2007-02-20 22:42:05

by linas

[permalink] [raw]
Subject: [PATCH 10/12]: spidernet: transmit race


Multiple threads performing a transmit can race into
the spidernet tx ring cleanup code. This puts the
relevant check under a lock.

Signed-off-by: Linas Vepstas <[email protected]>
Cc: Jens Osterkamp <[email protected]>
Cc: Kou Ishizaki <[email protected]>

----
drivers/net/spider_net.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)

Index: linux-2.6.20-git16/drivers/net/spider_net.c
===================================================================
--- linux-2.6.20-git16.orig/drivers/net/spider_net.c 2007-02-20 15:02:46.000000000 -0600
+++ linux-2.6.20-git16/drivers/net/spider_net.c 2007-02-20 15:02:48.000000000 -0600
@@ -803,8 +803,12 @@ spider_net_release_tx_chain(struct spide
unsigned long flags;
int status;

- while (chain->tail != chain->head) {
+ while (1) {
spin_lock_irqsave(&chain->lock, flags);
+ if (chain->tail == chain->head) {
+ spin_unlock_irqrestore(&chain->lock, flags);
+ return 0;
+ }
descr = chain->tail;
hwdescr = descr->hwdescr;

2007-02-20 22:43:06

by linas

[permalink] [raw]
Subject: [PATCH 11/12] spidernet: janitorial, typos



Janitorial patch. Undo long lines, fix typo in err msg.

Signed-off-by: Linas Vepstas <[email protected]>
Cc: Jens Osterkamp <[email protected]>
Cc: Kou Ishizaki <[email protected]>

----
drivers/net/spider_net.c | 13 +++++++------
drivers/net/spider_net.h | 2 +-
2 files changed, 8 insertions(+), 7 deletions(-)

Index: linux-2.6.20-git16/drivers/net/spider_net.c
===================================================================
--- linux-2.6.20-git16.orig/drivers/net/spider_net.c 2007-02-20 15:02:48.000000000 -0600
+++ linux-2.6.20-git16/drivers/net/spider_net.c 2007-02-20 15:02:50.000000000 -0600
@@ -1053,14 +1053,15 @@ static void show_rx_chain(struct spider_
#endif

/**
- * spider_net_decode_one_descr - processes an rx descriptor
+ * spider_net_decode_one_descr - processes an RX descriptor
* @card: card structure
*
- * Returns 1 if a packet has been sent to the stack, otherwise 0
+ * Returns 1 if a packet has been sent to the stack, otherwise 0.
*
- * Processes an rx descriptor by iommu-unmapping the data buffer and passing
- * the packet up to the stack. This function is called in softirq
- * context, e.g. either bottom half from interrupt or NAPI polling context
+ * Processes an RX descriptor by iommu-unmapping the data buffer
+ * and passing the packet up to the stack. This function is called
+ * in softirq context, e.g. either bottom half from interrupt or
+ * NAPI polling context.
*/
static int
spider_net_decode_one_descr(struct spider_net_card *card)
@@ -1097,7 +1098,7 @@ spider_net_decode_one_descr(struct spide
if ( (status != SPIDER_NET_DESCR_COMPLETE) &&
(status != SPIDER_NET_DESCR_FRAME_END) ) {
if (netif_msg_rx_err(card))
- pr_err("%s: RX descriptor with unkown state %d\n",
+ pr_err("%s: RX descriptor with unknown state %d\n",
card->netdev->name, status);
card->spider_stats.rx_desc_unk_state++;
goto bad_desc;
Index: linux-2.6.20-git16/drivers/net/spider_net.h
===================================================================
--- linux-2.6.20-git16.orig/drivers/net/spider_net.h 2007-02-20 15:02:44.000000000 -0600
+++ linux-2.6.20-git16/drivers/net/spider_net.h 2007-02-20 15:02:50.000000000 -0600
@@ -25,7 +25,7 @@
#ifndef _SPIDER_NET_H
#define _SPIDER_NET_H

-#define VERSION "1.6 C"
+#define VERSION "2.0 A"

#include "sungem_phy.h"

2007-02-20 22:45:31

by linas

[permalink] [raw]
Subject: [PATCH 12/12] spidernet: maintainership


Update driver support contact info.

Signed-off-by: Linas Vepstas <[email protected]>
Cc: Jens Osterkamp <[email protected]>
Cc: Kou Ishizaki <[email protected]>

----
MAINTAINERS | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

Index: linux-2.6.20-git16/MAINTAINERS
===================================================================
--- linux-2.6.20-git16.orig/MAINTAINERS 2007-02-20 14:23:52.000000000 -0600
+++ linux-2.6.20-git16/MAINTAINERS 2007-02-20 15:02:53.000000000 -0600
@@ -3178,8 +3178,8 @@ L: [email protected] ?
S: Supported

SPIDERNET NETWORK DRIVER for CELL
-P: Jim Lewis
-M: [email protected]
+P: Linas Vepstas
+M: [email protected]
L: [email protected]
S: Supported

2007-02-27 09:16:56

by Jeff Garzik

[permalink] [raw]
Subject: Re: [PATCH 1/12]: sungem_phy: support bcm5461 phy, autoneg.

Linas Vepstas wrote:
> From: Jens Osterkamp <[email protected]>
>
> This version moves the medium variable to the card specific structure and
> changes the GMII_* to BCM54XX_* #defines.
>
> This patch adds improved version of enable_fiber for both the 5421 and
> the 5461 phy. It is now possible to specify with these wether you want
> autonegotiation or not. This is needed for bladecenter switches where
> some expect autonegotiation and some dont seem to like this at all.
> Depending on this flag it sets phy->autoneg accordingly for the fiber mode.
>
> More importantly it implements proper read_link and poll_link functions
> for both phys which can handle both copper and fiber mode by determining
> the medium first and then branching to the required functions. For fiber
> they all work fine, for copper they are not tested but return the result
> of the genmii_* function anyway which is supposed to work.
>
> The patch moves the genmii_* functions around to avoid foreward declarations.
>
> Signed-off-by: Jens Osterkamp <[email protected]>
> Signed-off-by: Arnd Bergmann <[email protected]>
> Signed-off-by: Linas Vepstas <[email protected]>
>
> ----
> drivers/net/sungem_phy.c | 389 ++++++++++++++++++++++++++++++-----------------
> drivers/net/sungem_phy.h | 10 +
> 2 files changed, 263 insertions(+), 136 deletions(-)

applied 1-12