X-Git-Url: https://git.rohieb.name/openwrt.git/blobdiff_plain/356b45cef33154bbf0e6f0d7cd67018365c0d013..9de5c06f89388ac423e517df31d3fdd83f306097:/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c diff --git a/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c index 9b70a9282..e34c84c97 100644 --- a/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c +++ b/target/linux/generic/files/drivers/net/phy/rtl8366_smi.c @@ -448,7 +448,7 @@ static int rtl8366_set_pvid(struct rtl8366_smi *smi, unsigned port, return -ENOSPC; } -static int rtl8366_enable_vlan(struct rtl8366_smi *smi, int enable) +int rtl8366_enable_vlan(struct rtl8366_smi *smi, int enable) { int err; @@ -465,6 +465,7 @@ static int rtl8366_enable_vlan(struct rtl8366_smi *smi, int enable) return err; } +EXPORT_SYMBOL_GPL(rtl8366_enable_vlan); static int rtl8366_enable_vlan4k(struct rtl8366_smi *smi, int enable) { @@ -486,6 +487,21 @@ static int rtl8366_enable_vlan4k(struct rtl8366_smi *smi, int enable) return 0; } +int rtl8366_enable_all_ports(struct rtl8366_smi *smi, int enable) +{ + int port; + int err; + + for (port = 0; port < smi->num_ports; port++) { + err = smi->ops->enable_port(smi, port, enable); + if (err) + return err; + } + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_enable_all_ports); + int rtl8366_reset_vlan(struct rtl8366_smi *smi) { struct rtl8366_vlan_mc vlanmc; @@ -507,25 +523,38 @@ int rtl8366_reset_vlan(struct rtl8366_smi *smi) return err; } - for (i = 0; i < smi->num_ports; i++) { - if (i == smi->cpu_port) - continue; + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_reset_vlan); - err = rtl8366_set_vlan(smi, (i + 1), - (1 << i) | (1 << smi->cpu_port), - (1 << i) | (1 << smi->cpu_port), - 0); +static int rtl8366_init_vlan(struct rtl8366_smi *smi) +{ + int port; + int err; + + err = rtl8366_reset_vlan(smi); + if (err) + return err; + + for (port = 0; port < smi->num_ports; port++) { + u32 mask; + + if (port == smi->cpu_port) + mask = (1 << smi->num_ports) - 1; + else + mask = (1 << port) | (1 << smi->cpu_port); + + err = rtl8366_set_vlan(smi, (port + 1), mask, mask, 0); if (err) return err; - err = rtl8366_set_pvid(smi, i, (i + 1)); + err = rtl8366_set_pvid(smi, port, (port + 1)); if (err) return err; } - return 0; + return rtl8366_enable_vlan(smi, 1); } -EXPORT_SYMBOL_GPL(rtl8366_reset_vlan); #ifdef CONFIG_RTL8366S_PHY_DEBUG_FS int rtl8366_debugfs_open(struct inode *inode, struct file *file) @@ -561,6 +590,43 @@ static ssize_t rtl8366_read_debugfs_vlan_mc(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, len); } +#define RTL8366_VLAN4K_PAGE_SIZE 64 +#define RTL8366_VLAN4K_NUM_PAGES (4096 / RTL8366_VLAN4K_PAGE_SIZE) + +static ssize_t rtl8366_read_debugfs_vlan_4k(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8366_smi *smi = (struct rtl8366_smi *)file->private_data; + int i, len = 0; + int offset; + char *buf = smi->buf; + + if (smi->dbg_vlan_4k_page >= RTL8366_VLAN4K_NUM_PAGES) { + len += snprintf(buf + len, sizeof(smi->buf) - len, + "invalid page: %u\n", smi->dbg_vlan_4k_page); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); + } + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%4s %6s %6s %3s\n", + "vid", "member", "untag", "fid"); + + offset = RTL8366_VLAN4K_PAGE_SIZE * smi->dbg_vlan_4k_page; + for (i = 0; i < RTL8366_VLAN4K_PAGE_SIZE; i++) { + struct rtl8366_vlan_4k vlan4k; + + smi->ops->get_vlan_4k(smi, offset + i, &vlan4k); + + len += snprintf(buf + len, sizeof(smi->buf) - len, + "%4d 0x%04x 0x%04x %3d\n", + vlan4k.vid, vlan4k.member, + vlan4k.untag, vlan4k.fid); + } + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + static ssize_t rtl8366_read_debugfs_pvid(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -703,6 +769,12 @@ static const struct file_operations fops_rtl8366_vlan_mc = { .owner = THIS_MODULE }; +static const struct file_operations fops_rtl8366_vlan_4k = { + .read = rtl8366_read_debugfs_vlan_4k, + .open = rtl8366_debugfs_open, + .owner = THIS_MODULE +}; + static const struct file_operations fops_rtl8366_pvid = { .read = rtl8366_read_debugfs_pvid, .open = rtl8366_debugfs_open, @@ -754,6 +826,22 @@ static void rtl8366_debugfs_init(struct rtl8366_smi *smi) return; } + node = debugfs_create_u8("vlan_4k_page", S_IRUGO | S_IWUSR, root, + &smi->dbg_vlan_4k_page); + if (!node) { + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "vlan_4k_page"); + return; + } + + node = debugfs_create_file("vlan_4k", S_IRUSR, root, smi, + &fops_rtl8366_vlan_4k); + if (!node) { + dev_err(smi->parent, "Creating debugfs file '%s' failed\n", + "vlan_4k"); + return; + } + node = debugfs_create_file("pvid", S_IRUSR, root, smi, &fops_rtl8366_pvid); if (!node) { @@ -946,6 +1034,7 @@ int rtl8366_sw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val) struct switch_port *port; u32 member = 0; u32 untag = 0; + int err; int i; if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) @@ -957,12 +1046,66 @@ int rtl8366_sw_set_vlan_ports(struct switch_dev *dev, struct switch_val *val) if (!(port->flags & BIT(SWITCH_PORT_FLAG_TAGGED))) untag |= BIT(port->id); + + /* + * To ensure that we have a valid MC entry for this VLAN, + * initialize the port VLAN ID here. + */ + err = rtl8366_set_pvid(smi, port->id, val->port_vlan); + if (err < 0) + return err; } return rtl8366_set_vlan(smi, val->port_vlan, member, untag, 0); } EXPORT_SYMBOL_GPL(rtl8366_sw_set_vlan_ports); +int rtl8366_sw_get_vlan_fid(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_vlan_4k vlan4k; + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int err; + + if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) + return -EINVAL; + + err = smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k); + if (err) + return err; + + val->value.i = vlan4k.fid; + + return 0; +} +EXPORT_SYMBOL_GPL(rtl8366_sw_get_vlan_fid); + +int rtl8366_sw_set_vlan_fid(struct switch_dev *dev, + const struct switch_attr *attr, + struct switch_val *val) +{ + struct rtl8366_vlan_4k vlan4k; + struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); + int err; + + if (!smi->ops->is_vlan_valid(smi, val->port_vlan)) + return -EINVAL; + + if (val->value.i < 0 || val->value.i > attr->max) + return -EINVAL; + + err = smi->ops->get_vlan_4k(smi, val->port_vlan, &vlan4k); + if (err) + return err; + + return rtl8366_set_vlan(smi, val->port_vlan, + vlan4k.member, + vlan4k.untag, + val->value.i); +} +EXPORT_SYMBOL_GPL(rtl8366_sw_set_vlan_fid); + int rtl8366_sw_get_vlan_enable(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) @@ -1055,6 +1198,17 @@ int rtl8366_smi_init(struct rtl8366_smi *smi) goto err_free_sck; } + err = rtl8366_init_vlan(smi); + if (err) { + dev_err(smi->parent, "VLAN initialization failed, err=%d\n", + err); + goto err_disable_hw; + } + + err = rtl8366_enable_all_ports(smi, 1); + if (err) + goto err_disable_hw; + err = rtl8366_smi_mii_init(smi); if (err) goto err_free_sck;