X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/340551c0628cffd6049f05b41d671262dff7b308..c86a746eceb25fd0090fb8d25260c98c7d49f8c4:/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ar7240.c 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 fe3232be5..22240902b 100644 --- a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ar7240.c +++ b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_ar7240.c @@ -96,6 +96,7 @@ #define AR7240_REG_PORT_BASE(_port) (0x100 + (_port) * 0x100) #define AR7240_REG_PORT_STATUS(_port) (AR7240_REG_PORT_BASE((_port)) + 0x00) +#define AR7240_PORT_STATUS_SPEED_S 0 #define AR7240_PORT_STATUS_SPEED_M BITM(2) #define AR7240_PORT_STATUS_SPEED_10 0 #define AR7240_PORT_STATUS_SPEED_100 1 @@ -207,6 +208,7 @@ struct ar7240sw { u8 vlan_table[AR7240_MAX_VLANS]; u8 vlan_tagged; u16 pvid[AR7240_NUM_PORTS]; + char buf[80]; }; struct ar7240sw_hw_stat { @@ -397,49 +399,12 @@ int ar7240sw_phy_write(struct mii_bus *mii, unsigned phy_addr, return ret; } -static int ar7240sw_capture_stats(struct ar7240sw *as) -{ - struct mii_bus *mii = as->mii_bus; - int ret; - - /* Capture the hardware statistics for all ports */ - ar7240sw_reg_write(mii, AR7240_REG_MIB_FUNCTION0, - (AR7240_MIB_FUNC_CAPTURE << AR7240_MIB_FUNC_S)); - - /* Wait for the capturing to complete. */ - ret = ar7240sw_reg_wait(mii, AR7240_REG_MIB_FUNCTION0, - AR7240_MIB_BUSY, 0, 10); - return ret; -} - static void ar7240sw_disable_port(struct ar7240sw *as, unsigned port) { ar7240sw_reg_write(as->mii_bus, AR7240_REG_PORT_CTRL(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; @@ -471,11 +436,34 @@ 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; u32 ctrl; - u32 dest_ports; u32 vlan; ctrl = AR7240_PORT_CTRL_STATE_FORWARD | AR7240_PORT_CTRL_LEARN | @@ -523,7 +511,7 @@ static void ar7240sw_setup_port(struct ar7240sw *as, unsigned port, u8 portmask) /* allow the port to talk to all other ports, but exclude its * own ID to prevent frames from being reflected back to the * port that they came from */ - dest_ports = AR7240_PORT_MASK_BUT(port); + portmask &= AR7240_PORT_MASK_BUT(port); /* set default VID and and destination ports for this VLAN */ vlan |= (portmask << AR7240_PORT_VLAN_DEST_PORTS_S); @@ -659,6 +647,63 @@ 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) @@ -747,6 +792,14 @@ 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[] = { @@ -867,7 +920,6 @@ void ag71xx_ar7240_start(struct ag71xx *ag) struct ar7240sw *as = ag->phy_priv; ar7240sw_reset(as); - ar7240sw_setup(as); ag->speed = SPEED_1000; ag->duplex = 1;