X-Git-Url: https://git.archive.openwrt.org/?p=openwrt.git;a=blobdiff_plain;f=target%2Flinux%2Far71xx%2Ffiles%2Fdrivers%2Fnet%2Fethernet%2Fatheros%2Fag71xx%2Fag71xx_ar7240.c;h=d4ccc02eb483f8e4cdac2fa41433075e4ecf6612;hp=0fc4ba708fd5eae77511ff5777d74648d145a336;hb=67539ac550c360c3290faf36d10f983f510f3769;hpb=78859ab57d15257d590d0f64873a420f08afa7fa diff --git a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c index 0fc4ba708f..d4ccc02eb4 100644 --- a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c +++ b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c @@ -36,7 +36,8 @@ #define AR7240_FLOOD_MASK_BROAD_TO_CPU BIT(26) #define AR7240_REG_GLOBAL_CTRL 0x30 -#define AR7240_GLOBAL_CTRL_MTU_M BITM(12) +#define AR7240_GLOBAL_CTRL_MTU_M BITM(11) +#define AR9340_GLOBAL_CTRL_MTU_M BITM(14) #define AR7240_REG_VTU 0x0040 #define AR7240_VTU_OP BITM(3) @@ -83,6 +84,7 @@ #define AR7240_MIB_AT_HALF_EN BIT(16) #define AR7240_MIB_BUSY BIT(17) #define AR7240_MIB_FUNC_S 24 +#define AR7240_MIB_FUNC_M BITM(3) #define AR7240_MIB_FUNC_NO_OP 0x0 #define AR7240_MIB_FUNC_FLUSH 0x1 #define AR7240_MIB_FUNC_CAPTURE 0x3 @@ -207,6 +209,20 @@ #define AR934X_REG_OPER_MODE1 0x08 #define AR934X_REG_OPER_MODE1_PHY4_MII_EN BIT(28) +#define AR934X_REG_FLOOD_MASK 0x2c +#define AR934X_FLOOD_MASK_MC_DP(_p) BIT(16 + (_p)) +#define AR934X_FLOOD_MASK_BC_DP(_p) BIT(25 + (_p)) + +#define AR934X_REG_QM_CTRL 0x3c +#define AR934X_QM_CTRL_ARP_EN BIT(15) + +#define AR934X_REG_AT_CTRL 0x5c +#define AR934X_AT_CTRL_AGE_TIME BITS(0, 15) +#define AR934X_AT_CTRL_AGE_EN BIT(17) +#define AR934X_AT_CTRL_LEARN_CHANGE BIT(18) + +#define AR934X_MIB_ENABLE BIT(30) + #define AR934X_REG_PORT_BASE(_port) (0x100 + (_port) * 0x100) #define AR934X_REG_PORT_VLAN1(_port) (AR934X_REG_PORT_BASE((_port)) + 0x08) @@ -506,8 +522,9 @@ static int ar7240sw_capture_stats(struct ar7240sw *as) write_lock(&as->stats_lock); /* Capture the hardware statistics for all ports */ - ar7240sw_reg_write(mii, AR7240_REG_MIB_FUNCTION0, - (AR7240_MIB_FUNC_CAPTURE << AR7240_MIB_FUNC_S)); + ar7240sw_reg_rmw(mii, AR7240_REG_MIB_FUNCTION0, + (AR7240_MIB_FUNC_M << AR7240_MIB_FUNC_S), + (AR7240_MIB_FUNC_CAPTURE << AR7240_MIB_FUNC_S)); /* Wait for the capturing to complete. */ ret = ar7240sw_reg_wait(mii, AR7240_REG_MIB_FUNCTION0, @@ -556,21 +573,46 @@ static void ar7240sw_setup(struct ar7240sw *as) /* Setup TAG priority mapping */ ar7240sw_reg_write(mii, AR7240_REG_TAG_PRIORITY, 0xfa50); - /* Enable ARP frame acknowledge, aging, MAC replacing */ - ar7240sw_reg_write(mii, AR7240_REG_AT_CTRL, - AR7240_AT_CTRL_RESERVED | - 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, - AR7240_FLOOD_MASK_BROAD_TO_CPU); + if (sw_is_ar934x(as)) { + /* Enable aging, MAC replacing */ + ar7240sw_reg_write(mii, AR934X_REG_AT_CTRL, + 0x2b /* 5 min age time */ | + AR934X_AT_CTRL_AGE_EN | + AR934X_AT_CTRL_LEARN_CHANGE); + /* Enable ARP frame acknowledge */ + ar7240sw_reg_set(mii, AR934X_REG_QM_CTRL, + AR934X_QM_CTRL_ARP_EN); + /* Enable Broadcast/Multicast frames transmitted to the CPU */ + ar7240sw_reg_set(mii, AR934X_REG_FLOOD_MASK, + AR934X_FLOOD_MASK_BC_DP(0) | + AR934X_FLOOD_MASK_MC_DP(0)); + + /* setup MTU */ + ar7240sw_reg_rmw(mii, AR7240_REG_GLOBAL_CTRL, + AR9340_GLOBAL_CTRL_MTU_M, + AR9340_GLOBAL_CTRL_MTU_M); + + /* Enable MIB counters */ + ar7240sw_reg_set(mii, AR7240_REG_MIB_FUNCTION0, + AR934X_MIB_ENABLE); - /* setup MTU */ - ar7240sw_reg_rmw(mii, AR7240_REG_GLOBAL_CTRL, AR7240_GLOBAL_CTRL_MTU_M, - 1536); + } else { + /* Enable ARP frame acknowledge, aging, MAC replacing */ + ar7240sw_reg_write(mii, AR7240_REG_AT_CTRL, + AR7240_AT_CTRL_RESERVED | + 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, + AR7240_FLOOD_MASK_BROAD_TO_CPU); + + /* setup MTU */ + ar7240sw_reg_rmw(mii, AR7240_REG_GLOBAL_CTRL, + AR7240_GLOBAL_CTRL_MTU_M, + AR7240_GLOBAL_CTRL_MTU_M); + } /* setup Service TAG */ ar7240sw_reg_rmw(mii, AR7240_REG_SERVICE_TAG, AR7240_SERVICE_TAG_M, 0); @@ -596,6 +638,16 @@ static int ar7240sw_reset(struct ar7240sw *as) ret = ar7240sw_reg_wait(mii, AR7240_REG_MASK_CTRL, AR7240_MASK_CTRL_SOFT_RESET, 0, 1000); + /* setup PHYs */ + for (i = 0; i < AR7240_NUM_PHYS; i++) { + ar7240sw_phy_write(mii, i, MII_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_PAUSE_CAP | + ADVERTISE_PAUSE_ASYM); + ar7240sw_phy_write(mii, i, MII_BMCR, + BMCR_RESET | BMCR_ANENABLE); + } + msleep(1000); + ar7240sw_setup(as); return ret; } @@ -801,64 +853,6 @@ ar7240_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, return 0; } -static const char * -ar7240_speed_str(u32 status) -{ - u32 speed; - - speed = (status >> AR7240_PORT_STATUS_SPEED_S) & - AR7240_PORT_STATUS_SPEED_M; - switch (speed) { - case AR7240_PORT_STATUS_SPEED_10: - return "10baseT"; - case AR7240_PORT_STATUS_SPEED_100: - return "100baseT"; - case AR7240_PORT_STATUS_SPEED_1000: - return "1000baseT"; - } - - return "unknown"; -} - -static int -ar7240_port_get_link(struct switch_dev *dev, const struct switch_attr *attr, - struct switch_val *val) -{ - struct ar7240sw *as = sw_to_ar7240(dev); - struct mii_bus *mii = as->mii_bus; - u32 len; - u32 status; - int port; - - port = val->port_vlan; - - memset(as->buf, '\0', sizeof(as->buf)); - status = ar7240sw_reg_read(mii, AR7240_REG_PORT_STATUS(port)); - - if (status & AR7240_PORT_STATUS_LINK_UP) { - len = snprintf(as->buf, sizeof(as->buf), - "port:%d link:up speed:%s %s-duplex %s%s%s", - port, - ar7240_speed_str(status), - (status & AR7240_PORT_STATUS_DUPLEX) ? - "full" : "half", - (status & AR7240_PORT_STATUS_TXFLOW) ? - "txflow ": "", - (status & AR7240_PORT_STATUS_RXFLOW) ? - "rxflow " : "", - (status & AR7240_PORT_STATUS_LINK_AUTO) ? - "auto ": ""); - } else { - len = snprintf(as->buf, sizeof(as->buf), - "port:%d link:down", port); - } - - val->value.s = as->buf; - val->len = len; - - return 0; -} - static void ar7240_vtu_op(struct ar7240sw *as, u32 op, u32 val) { @@ -946,9 +940,15 @@ ar7240_get_port_link(struct switch_dev *dev, int port, return -EINVAL; status = ar7240sw_reg_read(mii, AR7240_REG_PORT_STATUS(port)); - - link->link = !!(status & AR7240_PORT_STATUS_LINK_UP); link->aneg = !!(status & AR7240_PORT_STATUS_LINK_AUTO); + if (link->aneg) { + link->link = !!(status & AR7240_PORT_STATUS_LINK_UP); + if (!link->link) + return 0; + } else { + link->link = true; + } + link->duplex = !!(status & AR7240_PORT_STATUS_DUPLEX); link->tx_flow = !!(status & AR7240_PORT_STATUS_TXFLOW); link->rx_flow = !!(status & AR7240_PORT_STATUS_RXFLOW); @@ -998,14 +998,6 @@ static struct switch_attr ar7240_globals[] = { }; static struct switch_attr ar7240_port[] = { - { - .type = SWITCH_TYPE_STRING, - .name = "link", - .description = "Get port link information", - .max = 1, - .set = NULL, - .get = ar7240_port_get_link, - }, }; static struct switch_attr ar7240_vlan[] = { @@ -1058,7 +1050,7 @@ static struct ar7240sw *ar7240_probe(struct ag71xx *ag) if ((phy_id1 != AR7240_PHY_ID1 || phy_id2 != AR7240_PHY_ID2) && (phy_id1 != AR934X_PHY_ID1 || phy_id2 != AR934X_PHY_ID2)) { pr_err("%s: unknown phy id '%04x:%04x'\n", - ag->dev->name, phy_id1, phy_id2); + dev_name(&mii->dev), phy_id1, phy_id2); return NULL; } @@ -1077,6 +1069,7 @@ static struct ar7240sw *ar7240_probe(struct ag71xx *ag) if (sw_is_ar7240(as)) { swdev->name = "AR7240/AR9330 built-in switch"; + swdev->ports = AR7240_NUM_PORTS - 1; } else if (sw_is_ar934x(as)) { swdev->name = "AR934X built-in switch"; @@ -1088,20 +1081,23 @@ static struct ar7240sw *ar7240_probe(struct ag71xx *ag) AR934X_OPER_MODE0_PHY_MII_EN); } else { pr_err("%s: invalid PHY interface mode\n", - ag->dev->name); + dev_name(&mii->dev)); goto err_free; } - if (as->swdata->phy4_mii_en) + if (as->swdata->phy4_mii_en) { ar7240sw_reg_set(mii, AR934X_REG_OPER_MODE1, AR934X_REG_OPER_MODE1_PHY4_MII_EN); + swdev->ports = AR7240_NUM_PORTS - 1; + } else { + swdev->ports = AR7240_NUM_PORTS; + } } else { pr_err("%s: unsupported chip, ctrl=%08x\n", - ag->dev->name, ctrl); + dev_name(&mii->dev), ctrl); goto err_free; } - swdev->ports = AR7240_NUM_PORTS - 1; swdev->cpu_port = AR7240_PORT_CPU; swdev->vlans = AR7240_MAX_VLANS; swdev->ops = &ar7240_ops; @@ -1109,7 +1105,7 @@ static struct ar7240sw *ar7240_probe(struct ag71xx *ag) if (register_switch(&as->swdev, ag->dev) < 0) goto err_free; - pr_info("%s: Found an %s\n", ag->dev->name, swdev->name); + pr_info("%s: Found an %s\n", dev_name(&mii->dev), swdev->name); /* initialize defaults */ for (i = 0; i < AR7240_MAX_VLANS; i++) @@ -1126,20 +1122,28 @@ err_free: static void link_function(struct work_struct *work) { struct ag71xx *ag = container_of(work, struct ag71xx, link_work.work); + struct ar7240sw *as = ag->phy_priv; unsigned long flags; + u8 mask; 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) { + mask = ~as->swdata->phy_poll_mask; + for (i = 0; i < AR7240_NUM_PHYS; i++) { + int link; + + if (!(mask & BIT(i))) + continue; + + 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) { + if (status != ag->link) { ag->link = status; ag71xx_link_adjust(ag); } @@ -1168,7 +1172,7 @@ void ag71xx_ar7240_stop(struct ag71xx *ag) cancel_delayed_work_sync(&ag->link_work); } -int __devinit ag71xx_ar7240_init(struct ag71xx *ag) +int ag71xx_ar7240_init(struct ag71xx *ag) { struct ar7240sw *as;