From 2465665b73ac2f688af945b1ed510752afa816a4 Mon Sep 17 00:00:00 2001 From: David Saada Date: Tue, 15 Jan 2008 10:40:24 +0200 Subject: QE UEC: Extend number of supported UECs to 4 This patch extends the number of supported UECs to 4. Note that the problem of QE thread resources exhaustion is resolved by setting the correct number of QE threads according to Ethernet type (GBE or FE). Signed-off-by: David Saada Signed-off-by: Ben Warren --- drivers/qe/uec.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/qe/uec.c b/drivers/qe/uec.c index 6cb25bfbc1..9094643912 100644 --- a/drivers/qe/uec.c +++ b/drivers/qe/uec.c @@ -40,8 +40,13 @@ static uec_info_t eth1_uec_info = { .tx_clock = CFG_UEC1_TX_CLK, .eth_type = CFG_UEC1_ETH_TYPE, }, +#if (CFG_UEC1_ETH_TYPE == FAST_ETH) + .num_threads_tx = UEC_NUM_OF_THREADS_1, + .num_threads_rx = UEC_NUM_OF_THREADS_1, +#else .num_threads_tx = UEC_NUM_OF_THREADS_4, .num_threads_rx = UEC_NUM_OF_THREADS_4, +#endif .riscTx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, .riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, .tx_bd_ring_len = 16, @@ -58,8 +63,13 @@ static uec_info_t eth2_uec_info = { .tx_clock = CFG_UEC2_TX_CLK, .eth_type = CFG_UEC2_ETH_TYPE, }, +#if (CFG_UEC2_ETH_TYPE == FAST_ETH) + .num_threads_tx = UEC_NUM_OF_THREADS_1, + .num_threads_rx = UEC_NUM_OF_THREADS_1, +#else .num_threads_tx = UEC_NUM_OF_THREADS_4, .num_threads_rx = UEC_NUM_OF_THREADS_4, +#endif .riscTx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, .riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, .tx_bd_ring_len = 16, @@ -68,7 +78,6 @@ static uec_info_t eth2_uec_info = { .enet_interface = CFG_UEC2_INTERFACE_MODE, }; #endif - #ifdef CONFIG_UEC_ETH3 static uec_info_t eth3_uec_info = { .uf_info = { @@ -77,8 +86,13 @@ static uec_info_t eth3_uec_info = { .tx_clock = CFG_UEC3_TX_CLK, .eth_type = CFG_UEC3_ETH_TYPE, }, +#if (CFG_UEC3_ETH_TYPE == FAST_ETH) + .num_threads_tx = UEC_NUM_OF_THREADS_1, + .num_threads_rx = UEC_NUM_OF_THREADS_1, +#else .num_threads_tx = UEC_NUM_OF_THREADS_4, .num_threads_rx = UEC_NUM_OF_THREADS_4, +#endif .riscTx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, .riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, .tx_bd_ring_len = 16, @@ -87,6 +101,29 @@ static uec_info_t eth3_uec_info = { .enet_interface = CFG_UEC3_INTERFACE_MODE, }; #endif +#ifdef CONFIG_UEC_ETH4 +static uec_info_t eth4_uec_info = { + .uf_info = { + .ucc_num = CFG_UEC4_UCC_NUM, + .rx_clock = CFG_UEC4_RX_CLK, + .tx_clock = CFG_UEC4_TX_CLK, + .eth_type = CFG_UEC4_ETH_TYPE, + }, +#if (CFG_UEC4_ETH_TYPE == FAST_ETH) + .num_threads_tx = UEC_NUM_OF_THREADS_1, + .num_threads_rx = UEC_NUM_OF_THREADS_1, +#else + .num_threads_tx = UEC_NUM_OF_THREADS_4, + .num_threads_rx = UEC_NUM_OF_THREADS_4, +#endif + .riscTx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, + .riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2, + .tx_bd_ring_len = 16, + .rx_bd_ring_len = 16, + .phy_address = CFG_UEC4_PHY_ADDR, + .enet_interface = CFG_UEC4_INTERFACE_MODE, +}; +#endif static int uec_mac_enable(uec_private_t *uec, comm_dir_e mode) { @@ -1261,6 +1298,10 @@ int uec_initialize(int index) } else if (index == 2) { #ifdef CONFIG_UEC_ETH3 uec_info = ð3_uec_info; +#endif + } else if (index == 3) { +#ifdef CONFIG_UEC_ETH4 + uec_info = ð4_uec_info; #endif } else { printf("%s: index is illegal.\n", __FUNCTION__); -- cgit From 55fe7c57a8b99a130925052dcdbb77f053dc50e3 Mon Sep 17 00:00:00 2001 From: "michael.firth@bt.com" Date: Wed, 16 Jan 2008 11:40:51 +0000 Subject: TSEC driver: Change MDIO support to allow access to any PHYs on the MDIO bus The current TSEC driver limits MDIO access to the devices that have been configured as attached to a TSEC MAC. This patch allows access to any PHY device on the MDIO bus through the 'mii' commands. Signed-off-by: Michael Firth Acked-by: Andy Fleming Signed-off-by: Ben Warren --- drivers/net/tsec.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index 25392f6862..504f3e57d9 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -241,10 +241,9 @@ int tsec_init(struct eth_device *dev, bd_t * bd) * It will wait for the write to be done (or for a timeout to * expire) before exiting */ -void write_phy_reg(struct tsec_private *priv, uint regnum, uint value) +void write_any_phy_reg(struct tsec_private *priv, uint phyid, uint regnum, uint value) { volatile tsec_t *regbase = priv->phyregs; - uint phyid = priv->phyaddr; int timeout = 1000000; regbase->miimadd = (phyid << 8) | regnum; @@ -255,17 +254,19 @@ void write_phy_reg(struct tsec_private *priv, uint regnum, uint value) while ((regbase->miimind & MIIMIND_BUSY) && timeout--) ; } +/* #define to provide old write_phy_reg functionality without duplicating code */ +#define write_phy_reg(priv, regnum, value) write_any_phy_reg(priv,priv->phyaddr,regnum,value) + /* Reads register regnum on the device's PHY through the * registers specified in priv. It lowers and raises the read * command, and waits for the data to become valid (miimind * notvalid bit cleared), and the bus to cease activity (miimind * busy bit cleared), and then returns the value */ -uint read_phy_reg(struct tsec_private *priv, uint regnum) +uint read_any_phy_reg(struct tsec_private *priv, uint phyid, uint regnum) { uint value; volatile tsec_t *regbase = priv->phyregs; - uint phyid = priv->phyaddr; /* Put the address of the phy, and the register * number into MIIMADD */ @@ -288,6 +289,9 @@ uint read_phy_reg(struct tsec_private *priv, uint regnum) return value; } +/* #define to provide old read_phy_reg functionality without duplicating code */ +#define read_phy_reg(priv,regnum) read_any_phy_reg(priv,priv->phyaddr,regnum) + /* Discover which PHY is attached to the device, and configure it * properly. If the PHY is not recognized, then return 0 * (failure). Otherwise, return 1 @@ -1497,18 +1501,6 @@ static void relocate_cmds(void) #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \ && !defined(BITBANGMII) -struct tsec_private *get_priv_for_phy(unsigned char phyaddr) -{ - int i; - - for (i = 0; i < MAXCONTROLLERS; i++) { - if (privlist[i]->phyaddr == phyaddr) - return privlist[i]; - } - - return NULL; -} - /* * Read a MII PHY register. * @@ -1519,14 +1511,14 @@ static int tsec_miiphy_read(char *devname, unsigned char addr, unsigned char reg, unsigned short *value) { unsigned short ret; - struct tsec_private *priv = get_priv_for_phy(addr); + struct tsec_private *priv = privlist[0]; if (NULL == priv) { printf("Can't read PHY at address %d\n", addr); return -1; } - ret = (unsigned short)read_phy_reg(priv, reg); + ret = (unsigned short)read_any_phy_reg(priv, addr, reg); *value = ret; return 0; @@ -1541,14 +1533,14 @@ static int tsec_miiphy_read(char *devname, unsigned char addr, static int tsec_miiphy_write(char *devname, unsigned char addr, unsigned char reg, unsigned short value) { - struct tsec_private *priv = get_priv_for_phy(addr); + struct tsec_private *priv = privlist[0]; if (NULL == priv) { printf("Can't write PHY at address %d\n", addr); return -1; } - write_phy_reg(priv, reg, value); + write_any_phy_reg(priv, addr, reg, value); return 0; } -- cgit From ee62ed3286f83b98b7785e0318dc6379e78f7ff6 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Tue, 15 Jan 2008 14:11:00 -0600 Subject: net: reduce boot latency on QE UEC based boards actually polling for PHY autonegotiation to finish enables us to remove the 5 second boot prompt latency present on QE based boards. call to qe_set_mii_clk_src in init_phy, and mv call to init_phy from uec_initialize to uec_init by Joakim Tjernlund; autonegotiation wait code shamelessly stolen from tsec driver. also rm unused CONFIG_RMII_MODE code. Signed-off-by: Kim Phillips Signed-off-by: Joakim Tjernlund Signed-off-by: Ben Warren --- drivers/qe/uec.c | 69 ++++++++++++++++++++++++++++++++-------------------- drivers/qe/uec_phy.c | 58 ++++++++++++++++++++++++++----------------- 2 files changed, 79 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/qe/uec.c b/drivers/qe/uec.c index 9094643912..55f37cb55c 100644 --- a/drivers/qe/uec.c +++ b/drivers/qe/uec.c @@ -512,6 +512,8 @@ static int init_phy(struct eth_device *dev) uec->mii_info = mii_info; + qe_set_mii_clk_src(uec->uec_info->uf_info.ucc_num); + if (init_mii_management_configuration(umii_regs)) { printf("%s: The MII Bus is stuck!", dev->name); err = -1; @@ -618,21 +620,12 @@ static void adjust_link(struct eth_device *dev) static void phy_change(struct eth_device *dev) { uec_private_t *uec = (uec_private_t *)dev->priv; - uec_t *uec_regs; - int result = 0; - - uec_regs = uec->uec_regs; - - /* Delay 5s to give the PHY a chance to change the register state */ - udelay(5000000); /* Update the link, speed, duplex */ - result = uec->mii_info->phyinfo->read_status(uec->mii_info); + uec->mii_info->phyinfo->read_status(uec->mii_info); /* Adjust the interface according to speed */ - if ((0 == result) || (uec->mii_info->link == 0)) { - adjust_link(dev); - } + adjust_link(dev); } static int uec_set_mac_address(uec_private_t *uec, u8 *mac_addr) @@ -1157,27 +1150,59 @@ static int uec_startup(uec_private_t *uec) static int uec_init(struct eth_device* dev, bd_t *bd) { uec_private_t *uec; - int err; + int err, i; + struct phy_info *curphy; uec = (uec_private_t *)dev->priv; if (uec->the_first_run == 0) { - /* Set up the MAC address */ - if (dev->enetaddr[0] & 0x01) { - printf("%s: MacAddress is multcast address\n", - __FUNCTION__); - return -1; + err = init_phy(dev); + if (err) { + printf("%s: Cannot initialize PHY, aborting.\n", + dev->name); + return err; } - uec_set_mac_address(uec, dev->enetaddr); + + curphy = uec->mii_info->phyinfo; + + if (curphy->config_aneg) { + err = curphy->config_aneg(uec->mii_info); + if (err) { + printf("%s: Can't negotiate PHY\n", dev->name); + return err; + } + } + + /* Give PHYs up to 5 sec to report a link */ + i = 50; + do { + err = curphy->read_status(uec->mii_info); + udelay(100000); + } while (((i-- > 0) && !uec->mii_info->link) || err); + + if (err || i <= 0) + printf("warning: %s: timeout on PHY link\n", dev->name); + uec->the_first_run = 1; } + /* Set up the MAC address */ + if (dev->enetaddr[0] & 0x01) { + printf("%s: MacAddress is multcast address\n", + __FUNCTION__); + return -1; + } + uec_set_mac_address(uec, dev->enetaddr); + + err = uec_open(uec, COMM_DIR_RX_AND_TX); if (err) { printf("%s: cannot enable UEC device\n", dev->name); return -1; } + phy_change(dev); + return (uec->mii_info->link ? 0 : -1); } @@ -1330,14 +1355,6 @@ int uec_initialize(int index) return err; } - err = init_phy(dev); - if (err) { - printf("%s: Cannot initialize PHY, aborting.\n", dev->name); - return err; - } - - phy_change(dev); - return 1; } #endif /* CONFIG_QE */ diff --git a/drivers/qe/uec_phy.c b/drivers/qe/uec_phy.c index ca6faa6ef4..f890d4fbfb 100644 --- a/drivers/qe/uec_phy.c +++ b/drivers/qe/uec_phy.c @@ -77,11 +77,10 @@ void uec_write_phy_reg (struct eth_device *dev, int mii_id, int regnum, int valu /* Setting up the MII Mangement Control Register with the value */ out_be32 (&ug_regs->miimcon, (u32) value); + sync(); /* Wait till MII management write is complete */ while ((in_be32 (&ug_regs->miimind)) & MIIMIND_BUSY); - - udelay (100000); } /* Reads from register regnum in the PHY for device dev, */ @@ -101,16 +100,17 @@ int uec_read_phy_reg (struct eth_device *dev, int mii_id, int regnum) tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; out_be32 (&ug_regs->miimadd, tmp_reg); - /* Perform an MII management read cycle */ + /* clear MII management command cycle */ out_be32 (&ug_regs->miimcom, 0); + sync(); + + /* Perform an MII management read cycle */ out_be32 (&ug_regs->miimcom, MIIMCOM_READ_CYCLE); /* Wait till MII management write is complete */ while ((in_be32 (&ug_regs->miimind)) & (MIIMIND_NOT_VALID | MIIMIND_BUSY)); - udelay (100000); - /* Read MII management status */ value = (u16) in_be32 (&ug_regs->miimstat); if (value == 0xffff) @@ -270,20 +270,38 @@ static int genmii_update_link (struct uec_mii_info *mii_info) { u16 status; - /* Do a fake read */ + /* Status is read once to clear old link state */ phy_read (mii_info, PHY_BMSR); - /* Read link and autonegotiation status */ - status = phy_read (mii_info, PHY_BMSR); - if ((status & PHY_BMSR_LS) == 0) - mii_info->link = 0; - else + /* + * Wait if the link is up, and autonegotiation is in progress + * (ie - we're capable and it's not done) + */ + status = phy_read(mii_info, PHY_BMSR); + if ((status & PHY_BMSR_LS) && (status & PHY_BMSR_AUTN_ABLE) + && !(status & PHY_BMSR_AUTN_COMP)) { + int i = 0; + + while (!(status & PHY_BMSR_AUTN_COMP)) { + /* + * Timeout reached ? + */ + if (i > UGETH_AN_TIMEOUT) { + mii_info->link = 0; + return 0; + } + + udelay(1000); /* 1 ms */ + status = phy_read(mii_info, PHY_BMSR); + } mii_info->link = 1; - - /* If we are autonegotiating, and not done, - * return an error */ - if (mii_info->autoneg && !(status & PHY_BMSR_AUTN_COMP)) - return -EAGAIN; + udelay(500000); /* another 500 ms (results in faster booting) */ + } else { + if (status & PHY_BMSR_LS) + mii_info->link = 1; + else + mii_info->link = 0; + } return 0; } @@ -389,16 +407,12 @@ static int dm9161_init (struct uec_mii_info *mii_info) /* PHY and MAC connect */ phy_write (mii_info, PHY_BMCR, phy_read (mii_info, PHY_BMCR) & ~PHY_BMCR_ISO); -#ifdef CONFIG_RMII_MODE - phy_write (mii_info, MII_DM9161_SCR, MII_DM9161_SCR_RMII_INIT); -#else + phy_write (mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT); -#endif + config_genmii_advert (mii_info); /* Start/restart aneg */ genmii_config_aneg (mii_info); - /* Delay to wait the aneg compeleted */ - udelay (3000000); return 0; } -- cgit From 84a3047b72b70e862b0b7a8e2058077457f89a32 Mon Sep 17 00:00:00 2001 From: Joakim Tjernlund Date: Wed, 16 Jan 2008 09:40:41 +0100 Subject: Remove annoying debug printout for PHY less boards. PHY less board prints out lots of "read wrong ...": read wrong value : mii_id 3,mii_reg 2, base e0102320 read wrong value : mii_id 3,mii_reg 3, base e0102320 UEC: PHY is Generic MII (ffffffff) read wrong value : mii_id 3,mii_reg 4, base e0102320 read wrong value : mii_id 3,mii_reg 0, base e0102320 read wrong value : mii_id 3,mii_reg 1, base e0102320 read wrong value : mii_id 3,mii_reg 1, base e0102320 read wrong value : mii_id 3,mii_reg 5, base e0102320 read wrong value : mii_id 3,mii_reg 1, base e0102320 read wrong value : mii_id 3,mii_reg 1, base e0102320 read wrong value : mii_id 3,mii_reg 5, base e0102320 FSL UEC0: Full Duplex FSL UEC0: Speed 100BT FSL UEC0: Link is up Using FSL UEC0 device Make this printout depend on UEC_VERBOSE_DEBUG and remove its definition in uec_phy.c Signed-off-by: Joakim Tjernlund Signed-off-by: Ben Warren --- drivers/qe/uec_phy.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/qe/uec_phy.c b/drivers/qe/uec_phy.c index f890d4fbfb..c549b6bb99 100644 --- a/drivers/qe/uec_phy.c +++ b/drivers/qe/uec_phy.c @@ -28,7 +28,6 @@ #if defined(CONFIG_QE) -#define UEC_VERBOSE_DEBUG #define ugphy_printk(format, arg...) \ printf(format "\n", ## arg) @@ -114,7 +113,7 @@ int uec_read_phy_reg (struct eth_device *dev, int mii_id, int regnum) /* Read MII management status */ value = (u16) in_be32 (&ug_regs->miimstat); if (value == 0xffff) - ugphy_warn + ugphy_vdbg ("read wrong value : mii_id %d,mii_reg %d, base %08x", mii_id, mii_reg, (u32) & (ug_regs->miimcfg)); -- cgit From 18ee320ff63edbf7b27bbeb05f0e12a52302c68a Mon Sep 17 00:00:00 2001 From: Dave Liu Date: Fri, 11 Jan 2008 18:45:28 +0800 Subject: TSEC: Add the support for RealTek RTL8211B PHY Add the support of RealTek RTL8211B PHY, the RTL8211B PHY only supports RGMII and MII mode. Signed-off-by: Dave Liu Signed-off-by: Ben Warren --- drivers/net/tsec.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/tsec.h | 8 +++++ 2 files changed, 93 insertions(+) (limited to 'drivers') diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index 504f3e57d9..e91d9eadc1 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -575,6 +575,63 @@ uint mii_parse_88E1011_psr(uint mii_reg, struct tsec_private * priv) return 0; } +/* Parse the RTL8211B's status register for speed and duplex + * information + */ +uint mii_parse_RTL8211B_sr(uint mii_reg, struct tsec_private * priv) +{ + uint speed; + + mii_reg = read_phy_reg(priv, MIIM_RTL8211B_PHY_STATUS); + if ((mii_reg & MIIM_RTL8211B_PHYSTAT_LINK) && + !(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) { + int i = 0; + + puts("Waiting for PHY realtime link"); + while (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) { + /* Timeout reached ? */ + if (i > PHY_AUTONEGOTIATE_TIMEOUT) { + puts(" TIMEOUT !\n"); + priv->link = 0; + break; + } + + if ((i++ % 1000) == 0) { + putc('.'); + } + udelay(1000); /* 1 ms */ + mii_reg = read_phy_reg(priv, MIIM_RTL8211B_PHY_STATUS); + } + puts(" done\n"); + udelay(500000); /* another 500 ms (results in faster booting) */ + } else { + if (mii_reg & MIIM_RTL8211B_PHYSTAT_LINK) + priv->link = 1; + else + priv->link = 0; + } + + if (mii_reg & MIIM_RTL8211B_PHYSTAT_DUPLEX) + priv->duplexity = 1; + else + priv->duplexity = 0; + + speed = (mii_reg & MIIM_RTL8211B_PHYSTAT_SPEED); + + switch (speed) { + case MIIM_RTL8211B_PHYSTAT_GBIT: + priv->speed = 1000; + break; + case MIIM_RTL8211B_PHYSTAT_100: + priv->speed = 100; + break; + default: + priv->speed = 10; + } + + return 0; +} + /* Parse the cis8201's status register for speed and duplex * information */ @@ -1365,6 +1422,33 @@ struct phy_info phy_info_dp83865 = { }, }; +struct phy_info phy_info_rtl8211b = { + 0x001cc91, + "RealTek RTL8211B", + 4, + (struct phy_cmd[]){ /* config */ + /* Reset and configure the PHY */ + {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, + {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, + {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, + {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, + {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, + {miim_end,} + }, + (struct phy_cmd[]){ /* startup */ + /* Status is read once to clear old link state */ + {MIIM_STATUS, miim_read, NULL}, + /* Auto-negotiate */ + {MIIM_STATUS, miim_read, &mii_parse_sr}, + /* Read the status */ + {MIIM_RTL8211B_PHY_STATUS, miim_read, &mii_parse_RTL8211B_sr}, + {miim_end,} + }, + (struct phy_cmd[]){ /* shutdown */ + {miim_end,} + }, +}; + struct phy_info *phy_info[] = { &phy_info_cis8204, &phy_info_cis8201, @@ -1378,6 +1462,7 @@ struct phy_info *phy_info[] = { &phy_info_lxt971, &phy_info_VSC8244, &phy_info_dp83865, + &phy_info_rtl8211b, &phy_info_generic, NULL }; diff --git a/drivers/net/tsec.h b/drivers/net/tsec.h index 2f0092ad59..d4dc15a68b 100644 --- a/drivers/net/tsec.h +++ b/drivers/net/tsec.h @@ -184,6 +184,14 @@ #define MIIM_88E1145_PHY_PAGE 29 #define MIIM_88E1145_PHY_CAL_OV 30 +/* RTL8211B PHY Status Register */ +#define MIIM_RTL8211B_PHY_STATUS 0x11 +#define MIIM_RTL8211B_PHYSTAT_SPEED 0xc000 +#define MIIM_RTL8211B_PHYSTAT_GBIT 0x8000 +#define MIIM_RTL8211B_PHYSTAT_100 0x4000 +#define MIIM_RTL8211B_PHYSTAT_DUPLEX 0x2000 +#define MIIM_RTL8211B_PHYSTAT_SPDDONE 0x0800 +#define MIIM_RTL8211B_PHYSTAT_LINK 0x0400 /* DM9161 Control register values */ #define MIIM_DM9161_CR_STOP 0x0400 -- cgit From d1276c76c1e2b5035296689280ba1acb2c425104 Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Wed, 16 Jan 2008 16:11:14 +0900 Subject: drivers/net/rtl8139.c: Fix tx timeout "to = (currticks() + RTL_TIMEOUT)" has possibilities to wrap around. If it does, the condition "(currticks() < to)" becomes invalid and immediately leads to tx timeout error. This patch introduces the fine-graded udely(10) loops to ease the impact of wrapping around. Signed-off-by: Shinya Kuribayashi Cc: Masami Komiya Cc: Lucas Jin Signed-off-by: Ben Warren --- drivers/net/rtl8139.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index 4c248054c3..5d7ae74825 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -80,10 +80,7 @@ #if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \ defined(CONFIG_RTL8139) -#define TICKS_PER_SEC CFG_HZ -#define TICKS_PER_MS (TICKS_PER_SEC/1000) - -#define RTL_TIMEOUT (1*TICKS_PER_SEC) +#define RTL_TIMEOUT 100000 #define ETH_FRAME_LEN 1514 #define ETH_ALEN 6 @@ -414,9 +411,10 @@ static void rtl_reset(struct eth_device *dev) static int rtl_transmit(struct eth_device *dev, volatile void *packet, int length) { - unsigned int status, to; + unsigned int status; unsigned long txstatus; unsigned int len = length; + int i = 0; ioaddr = dev->iobase; @@ -436,8 +434,6 @@ static int rtl_transmit(struct eth_device *dev, volatile void *packet, int lengt outl(((TX_FIFO_THRESH<<11) & 0x003f0000) | len, ioaddr + TxStatus0 + cur_tx*4); - to = currticks() + RTL_TIMEOUT; - do { status = inw(ioaddr + IntrStatus); /* Only acknlowledge interrupt sources we can properly handle @@ -445,7 +441,8 @@ static int rtl_transmit(struct eth_device *dev, volatile void *packet, int lengt * rtl_poll() function. */ outw(status & (TxOK | TxErr | PCIErr), ioaddr + IntrStatus); if ((status & (TxOK | TxErr | PCIErr)) != 0) break; - } while (currticks() < to); + udelay(10); + } while (i++ < RTL_TIMEOUT); txstatus = inl(ioaddr + TxStatus0 + cur_tx*4); @@ -458,8 +455,8 @@ static int rtl_transmit(struct eth_device *dev, volatile void *packet, int lengt return length; } else { #ifdef DEBUG_TX - printf("tx timeout/error (%d ticks), status %hX txstatus %X\n", - currticks()-to, status, txstatus); + printf("tx timeout/error (%d usecs), status %hX txstatus %X\n", + 10*i, status, txstatus); #endif rtl_reset(dev); -- cgit From 96a236746fe6a7b84802afb4ed31536696d34812 Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Wed, 16 Jan 2008 16:12:26 +0900 Subject: drivers/net/rtl8139.c: Fix cache coherency issues Current driver is meant for cache coherent systems. This patch adds flush_cache() routines to support cache non-coherent systems. Signed-off-by: Shinya Kuribayashi Cc: Masami Komiya Cc: Lucas Jin Signed-off-by: Ben Warren --- drivers/net/rtl8139.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index 5d7ae74825..014f3b4324 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -389,6 +389,7 @@ static void rtl_reset(struct eth_device *dev) #ifdef DEBUG_RX printf("rx ring address is %X\n",(unsigned long)rx_ring); #endif + flush_cache((unsigned long)rx_ring, RX_BUF_LEN); outl(phys_to_bus((int)rx_ring), ioaddr + RxBuf); /* If we add multicast support, the MAR0 register would have to be @@ -430,6 +431,7 @@ static int rtl_transmit(struct eth_device *dev, volatile void *packet, int lengt tx_buffer[len++] = '\0'; } + flush_cache((unsigned long)tx_buffer, length); outl(phys_to_bus((int)tx_buffer), ioaddr + TxAddr0 + cur_tx*4); outl(((TX_FIFO_THRESH<<11) & 0x003f0000) | len, ioaddr + TxStatus0 + cur_tx*4); @@ -486,7 +488,8 @@ static int rtl_poll(struct eth_device *dev) #endif ring_offs = cur_rx % RX_BUF_LEN; - rx_status = *(unsigned int*)KSEG1ADDR((rx_ring + ring_offs)); + /* ring_offs is guaranteed being 4-byte aligned */ + rx_status = *(unsigned int *)(rx_ring + ring_offs); rx_size = rx_status >> 16; rx_status &= 0xffff; @@ -516,6 +519,7 @@ static int rtl_poll(struct eth_device *dev) printf("rx packet %d bytes", rx_size-4); #endif } + flush_cache((unsigned long)rx_ring, RX_BUF_LEN); cur_rx = (cur_rx + rx_size + 4 + 3) & ~3; outw(cur_rx - 16, ioaddr + RxBufPtr); -- cgit From c2f896b8fc4722e36915903e1942e138e68ce804 Mon Sep 17 00:00:00 2001 From: Shinya Kuribayashi Date: Wed, 16 Jan 2008 16:13:31 +0900 Subject: drivers/net/rtl8139.c: rx_status should be le32_to_cpu(rx_status). rx_status on the memory is basically in LE, but needs to be handled in CPU endian. le32_to_cpu() takes up this mission. Even if on the sane hardware, it'll work fine. Signed-off-by: Shinya Kuribayashi Cc: Masami Komiya Cc: Lucas Jin Signed-off-by: Ben Warren --- drivers/net/rtl8139.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/rtl8139.c b/drivers/net/rtl8139.c index 014f3b4324..097f6841ae 100644 --- a/drivers/net/rtl8139.c +++ b/drivers/net/rtl8139.c @@ -489,7 +489,7 @@ static int rtl_poll(struct eth_device *dev) ring_offs = cur_rx % RX_BUF_LEN; /* ring_offs is guaranteed being 4-byte aligned */ - rx_status = *(unsigned int *)(rx_ring + ring_offs); + rx_status = le32_to_cpu(*(unsigned int *)(rx_ring + ring_offs)); rx_size = rx_status >> 16; rx_status &= 0xffff; -- cgit