cyberchallenge-modem/buildroot/board/tiesse/tgr/kernel-patches/1009-imx8mm-mv88e6xxx-sysfs-interface.patch

230 lines
6.0 KiB
Diff
Raw Normal View History

Index: drivers/net/dsa/mv88e6xxx/chip.c
===================================================================
--- drivers/net/dsa/mv88e6xxx/chip.c
+++ linux-imx/drivers/net/dsa/mv88e6xxx/chip.c
@@ -3936,6 +3936,212 @@ static void mv88e6xxx_unregister_switch(
dsa_unregister_switch(chip->ds);
}
+/*
+ * Marvell switch mv88e6xxx sysfs interface
+ */
+static int mv88e6xxx_port;
+static u16 mv88e6xxx_reg;
+static ssize_t sysfs_reg_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "0x%x", mv88e6xxx_reg);
+}
+
+static ssize_t sysfs_reg_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ if (kstrtou16(buf, 0, &mv88e6xxx_reg)) {
+ dev_err(dev, "Invalid reg\n");
+ return -EINVAL;
+ }
+ return (ssize_t)count;
+}
+
+static ssize_t sysfs_port_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "0x%x", mv88e6xxx_port);
+}
+
+static ssize_t sysfs_port_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ if (kstrtoint(buf, 0, &mv88e6xxx_port)) {
+ dev_err(dev, "Invalid port \n");
+ return -EINVAL;
+ }
+ return (ssize_t)count;
+}
+
+/*
+ * Read the specified register of a specified port
+ */
+static ssize_t sysfs_port_reg_val_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dsa_switch *ds = (struct dsa_switch *)dev_get_drvdata(dev);
+ struct mv88e6xxx_chip *chip = ds->priv;
+ u16 reg;
+ int err;
+
+ mutex_lock(&chip->reg_lock);
+ err = mv88e6xxx_port_read(chip, mv88e6xxx_port, mv88e6xxx_reg, &reg);
+ mutex_unlock(&chip->reg_lock);
+
+ if (err) {
+ dev_err(dev, "Port %d register %x failed\n", mv88e6xxx_port, mv88e6xxx_reg);
+ return -EIO;
+ }
+
+ return scnprintf(buf, PAGE_SIZE, "0x%x\n", reg);
+}
+
+/*
+ * Purge the switch ATU cache
+ */
+static ssize_t sysfs_atu_flush(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct dsa_switch *ds = (struct dsa_switch *)dev_get_drvdata(dev);
+ struct mv88e6xxx_chip *chip = ds->priv;
+ int err;
+
+ mutex_lock(&chip->reg_lock);
+ err = mv88e6xxx_g1_atu_flush(chip, 0, true);
+ mutex_unlock(&chip->reg_lock);
+
+ if (err) {
+ dev_err(dev, "ATU flush failed\n");
+ return -EIO;
+ }
+
+ return (ssize_t)count;
+}
+
+/*
+ * Returns the ATU cache content
+ */
+static ssize_t sysfs_atu_dump(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct dsa_switch *ds = (struct dsa_switch *)dev_get_drvdata(dev);
+ struct mv88e6xxx_chip *chip = ds->priv;
+ struct mv88e6xxx_atu_entry addr;
+ u16 fid = 0;
+ ssize_t n = 0;
+ int err;
+
+ addr.state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
+ eth_broadcast_addr(addr.mac);
+
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ "\nATU List:\n");
+
+ mutex_lock(&chip->reg_lock);
+ while (1) {
+ err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
+ if (err)
+ break;
+
+ if (addr.state == MV88E6XXX_G1_ATU_DATA_STATE_UNUSED)
+ break;
+ n += scnprintf(buf + n, PAGE_SIZE - n,
+ "(%02x:%02x:%02x:%02x:%02x:%02x), PortVec %#x, State %#x\n",
+ addr.mac[0], addr.mac[1], addr.mac[2],
+ addr.mac[3], addr.mac[4], addr.mac[5],
+ addr.portvec,
+ addr.state);
+ }
+ mutex_unlock(&chip->reg_lock);
+ n += scnprintf(buf + n, PAGE_SIZE - n,"\n");
+ if (err)
+ return 0;
+ else
+ return n;
+}
+
+static ssize_t sysfs_atu_uc_static_entry_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct dsa_switch *ds = (struct dsa_switch *)dev_get_drvdata(dev);
+ struct mv88e6xxx_chip *chip = ds->priv;
+ const char *name = attr->attr.name;
+ struct mv88e6xxx_atu_entry entry;
+ u8 mac[ETH_ALEN];
+ u8 state;
+ int values[ETH_ALEN], dpv;
+ int i, err;
+
+ if(7 != sscanf(buf, "%x:%x:%x:%x:%x:%x %x%*c",
+ &values[0], &values[1], &values[2],
+ &values[3], &values[4], &values[5],
+ &dpv)) {
+ dev_err(dev, "Invalid input %s\n", buf);
+ return -EINVAL;
+ }
+
+ for (i = 0; i<ETH_ALEN; i++) {
+ if (values[i] < 0 || values[i] > 255) {
+ dev_err(dev, "Invalid mac %s\n", buf);
+ return -EINVAL;
+ }
+ mac[i] = (u8)values[i];
+ }
+
+ if (!strcmp(name, "atu_uc_static_entry_add"))
+ state = MV88E6XXX_G1_ATU_DATA_STATE_UC_STATIC;
+ else
+ state = MV88E6XXX_G1_ATU_DATA_STATE_UNUSED;
+
+ memset(&entry, 0, sizeof(entry));
+ ether_addr_copy(entry.mac, mac);
+ entry.portvec = dpv;
+ entry.state = state;
+
+ mutex_lock(&chip->reg_lock);
+ err = mv88e6xxx_g1_atu_loadpurge(chip, 0, &entry);
+ mutex_unlock(&chip->reg_lock);
+
+ if (err) {
+ dev_err(dev, "Load static entry failed\n");
+ return -EIO;
+ }
+
+ return (ssize_t)count;
+}
+
+static DEVICE_ATTR(reg, S_IWUSR | S_IRUSR,
+ sysfs_reg_show, sysfs_reg_store);
+static DEVICE_ATTR(port, S_IWUSR | S_IRUSR,
+ sysfs_port_show, sysfs_port_store);
+static DEVICE_ATTR(port_reg_val, S_IWUSR | S_IRUSR,
+ sysfs_port_reg_val_show, NULL);
+static DEVICE_ATTR(atu, S_IWUSR | S_IRUSR,
+ sysfs_atu_dump, sysfs_atu_flush);
+static DEVICE_ATTR(atu_uc_static_entry_add, S_IWUSR | S_IRUSR,
+ NULL, sysfs_atu_uc_static_entry_store);
+static DEVICE_ATTR(atu_uc_static_entry_del, S_IWUSR | S_IRUSR,
+ NULL, sysfs_atu_uc_static_entry_store);
+
+static struct attribute *mv88e6xxx_sysfs_entries[] = {
+ &dev_attr_reg.attr,
+ &dev_attr_port.attr,
+ &dev_attr_port_reg_val.attr,
+ &dev_attr_atu.attr,
+ &dev_attr_atu_uc_static_entry_add.attr,
+ &dev_attr_atu_uc_static_entry_del.attr,
+ NULL
+};
+
+static struct attribute_group mv88e6xxx_attribute_group = {
+ .name = "config",
+ .attrs = mv88e6xxx_sysfs_entries,
+};
+
static int mv88e6xxx_probe(struct mdio_device *mdiodev)
{
struct device *dev = &mdiodev->dev;
@@ -4013,6 +4219,11 @@ static int mv88e6xxx_probe(struct mdio_d
if (err)
goto out_mdio;
+ /* register sysfs files */
+ err = sysfs_create_group(&dev->kobj, &mv88e6xxx_attribute_group);
+ if (err)
+ dev_err(chip->dev, "sysfs_create_group failed\n");
+
return 0;
out_mdio: