X-Git-Url: http://git.ozo.com/?p=openwrt-10.03%2F.git;a=blobdiff_plain;f=target%2Flinux%2Far71xx%2Ffiles%2Fdrivers%2Fnet%2Fag71xx%2Fag71xx_ar7240.c;h=534af4b9f9ea3d998c5fa8e894b56184826455cc;hp=3ce2f0a5db4905573ada383d7547abdd4b650b18;hb=41fd52fb29cc6d7a522e9e9331055691d437f1ee;hpb=2d335ddc1c69d7a28d5d854da1e809b40d72bca5 diff --git a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ar7240.c b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ar7240.c index 3ce2f0a5d..534af4b9f 100644 --- a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ar7240.c +++ b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ar7240.c @@ -57,7 +57,13 @@ #define AR7240_VTUDATA_MEMBER BITS(0, 10) #define AR7240_VTUDATA_VALID BIT(11) +#define AR7240_REG_ATU 0x50 +#define AR7240_ATU_FLUSH_ALL 0x1 + #define AR7240_REG_AT_CTRL 0x5c +#define AR7240_AT_CTRL_AGE_TIME BITS(0, 15) +#define AR7240_AT_CTRL_AGE_EN BIT(17) +#define AR7240_AT_CTRL_LEARN_CHANGE BIT(18) #define AR7240_AT_CTRL_ARP_EN BIT(20) #define AR7240_REG_TAG_PRIORITY 0x70 @@ -233,37 +239,39 @@ static inline u16 mk_high_addr(u32 reg) static u32 __ar7240sw_reg_read(struct mii_bus *mii, u32 reg) { + unsigned long flags; u16 phy_addr; u16 phy_reg; u32 hi, lo; reg = (reg & 0xfffffffc) >> 2; - - ag71xx_mdio_mii_write(mii->priv, 0x1f, 0x10, mk_high_addr(reg)); - phy_addr = mk_phy_addr(reg); phy_reg = mk_phy_reg(reg); + local_irq_save(flags); + ag71xx_mdio_mii_write(mii->priv, 0x1f, 0x10, mk_high_addr(reg)); lo = (u32) ag71xx_mdio_mii_read(mii->priv, phy_addr, phy_reg); hi = (u32) ag71xx_mdio_mii_read(mii->priv, phy_addr, phy_reg + 1); + local_irq_restore(flags); return (hi << 16) | lo; } static void __ar7240sw_reg_write(struct mii_bus *mii, u32 reg, u32 val) { + unsigned long flags; u16 phy_addr; u16 phy_reg; reg = (reg & 0xfffffffc) >> 2; - - ag71xx_mdio_mii_write(mii->priv, 0x1f, 0x10, mk_high_addr(reg)); - phy_addr = mk_phy_addr(reg); phy_reg = mk_phy_reg(reg); + local_irq_save(flags); + ag71xx_mdio_mii_write(mii->priv, 0x1f, 0x10, mk_high_addr(reg)); ag71xx_mdio_mii_write(mii->priv, phy_addr, phy_reg + 1, (val >> 16)); ag71xx_mdio_mii_write(mii->priv, phy_addr, phy_reg, (val & 0xffff)); + local_irq_restore(flags); } static u32 ar7240sw_reg_read(struct mii_bus *mii, u32 reg_addr) @@ -410,28 +418,6 @@ static void ar7240sw_disable_port(struct ar7240sw *as, unsigned port) AR7240_PORT_CTRL_STATE_DISABLED); } -static int ar7240sw_reset(struct ar7240sw *as) -{ - struct mii_bus *mii = as->mii_bus; - int ret; - int i; - - /* Set all ports to disabled state. */ - for (i = 0; i < AR7240_NUM_PORTS; i++) - ar7240sw_disable_port(as, i); - - /* Wait for transmit queues to drain. */ - msleep(2); - - /* Reset the switch. */ - ar7240sw_reg_write(mii, AR7240_REG_MASK_CTRL, - AR7240_MASK_CTRL_SOFT_RESET); - - ret = ar7240sw_reg_wait(mii, AR7240_REG_MASK_CTRL, - AR7240_MASK_CTRL_SOFT_RESET, 0, 1000); - return ret; -} - static void ar7240sw_setup(struct ar7240sw *as) { struct mii_bus *mii = as->mii_bus; @@ -444,8 +430,12 @@ static void ar7240sw_setup(struct ar7240sw *as) /* Setup TAG priority mapping */ ar7240sw_reg_write(mii, AR7240_REG_TAG_PRIORITY, 0xfa50); - /* Enable ARP frame acknowledge */ - ar7240sw_reg_set(mii, AR7240_REG_AT_CTRL, AR7240_AT_CTRL_ARP_EN); + /* Enable ARP frame acknowledge, aging, MAC replacing */ + ar7240sw_reg_write(mii, AR7240_REG_AT_CTRL, + 0x2b /* 5 min age time */ | + AR7240_AT_CTRL_AGE_EN | + AR7240_AT_CTRL_ARP_EN | + AR7240_AT_CTRL_LEARN_CHANGE); /* Enable Broadcast frames transmitted to the CPU */ ar7240sw_reg_set(mii, AR7240_REG_FLOOD_MASK, @@ -459,6 +449,30 @@ static void ar7240sw_setup(struct ar7240sw *as) ar7240sw_reg_rmw(mii, AR7240_REG_SERVICE_TAG, AR7240_SERVICE_TAG_M, 0); } +static int ar7240sw_reset(struct ar7240sw *as) +{ + struct mii_bus *mii = as->mii_bus; + int ret; + int i; + + /* Set all ports to disabled state. */ + for (i = 0; i < AR7240_NUM_PORTS; i++) + ar7240sw_disable_port(as, i); + + /* Wait for transmit queues to drain. */ + msleep(2); + + /* Reset the switch. */ + ar7240sw_reg_write(mii, AR7240_REG_MASK_CTRL, + AR7240_MASK_CTRL_SOFT_RESET); + + ret = ar7240sw_reg_wait(mii, AR7240_REG_MASK_CTRL, + AR7240_MASK_CTRL_SOFT_RESET, 0, 1000); + + ar7240sw_setup(as); + return ret; +} + static void ar7240sw_setup_port(struct ar7240sw *as, unsigned port, u8 portmask) { struct mii_bus *mii = as->mii_bus; @@ -826,23 +840,48 @@ static struct ar7240sw *ar7240_probe(struct ag71xx *ag) return as; } +static void link_function(struct work_struct *work) { + struct ag71xx *ag = container_of(work, struct ag71xx, link_work.work); + unsigned long flags; + int i; + int status = 0; + + for (i = 0; i < 4; i++) { + int link = ar7240sw_phy_read(ag->mii_bus, i, MII_BMSR); + if(link & BMSR_LSTATUS) { + status = 1; + break; + } + } + + spin_lock_irqsave(&ag->lock, flags); + if(status != ag->link) { + ag->link = status; + ag71xx_link_adjust(ag); + } + spin_unlock_irqrestore(&ag->lock, flags); + + schedule_delayed_work(&ag->link_work, HZ / 2); +} + void ag71xx_ar7240_start(struct ag71xx *ag) { struct ar7240sw *as = ag->phy_priv; ar7240sw_reset(as); - ar7240sw_setup(as); ag->speed = SPEED_1000; - ag->link = 1; ag->duplex = 1; ar7240_set_addr(as, ag->dev->dev_addr); ar7240_hw_apply(&as->swdev); + + schedule_delayed_work(&ag->link_work, HZ / 10); } void ag71xx_ar7240_stop(struct ag71xx *ag) { + cancel_delayed_work_sync(&ag->link_work); } int __devinit ag71xx_ar7240_init(struct ag71xx *ag) @@ -856,10 +895,12 @@ int __devinit ag71xx_ar7240_init(struct ag71xx *ag) ag->phy_priv = as; ar7240sw_reset(as); + INIT_DELAYED_WORK(&ag->link_work, link_function); + return 0; } -void __devexit ag71xx_ar7240_cleanup(struct ag71xx *ag) +void ag71xx_ar7240_cleanup(struct ag71xx *ag) { struct ar7240sw *as = ag->phy_priv;