[ofa-general][PATCH 8/12 v1] mlx4: Dynamic port configuration

Yevgeny Petrilin yevgenyp at mellanox.co.il
Wed Apr 23 08:05:10 PDT 2008


>From e13bef843cb2c7cee5a0ba388d97e21188087424 Mon Sep 17 00:00:00 2001
From: Yevgeny Petrilin <yevgenyp at mellanox.co.il>
Date: Tue, 22 Apr 2008 15:14:30 +0300
Subject: [PATCH] mlx4: Dynamic port configuration

Port type can be set using sysfs interface when the low level driver is up.
The low level driver unregisters all its customers and then registers them
again with the new port types (which they query for in add_one)

Signed-off-by: Yevgeny Petrilin <yevgenyp at mellanox.co.il>
---
 drivers/net/mlx4/main.c |   97 +++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 97 insertions(+), 0 deletions(-)

diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index a528809..e3fd4e9 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -281,6 +281,96 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
 	return 0;
 }

+static int mlx4_change_port_types(struct mlx4_dev *dev,
+				  enum mlx4_port_type *port_types)
+{
+	int i;
+	int err = 0;
+	int change = 0;
+	int port;
+
+	for (i = 0; i <  MLX4_MAX_PORTS; i++) {
+		if (port_types[i] != dev->caps.port_type[i + 1]) {
+			change = 1;
+			dev->caps.port_type[i + 1] = port_types[i];
+		}
+	}
+	if (change) {
+		mlx4_unregister_device(dev);
+		for (port = 1; port <= dev->caps.num_ports; port++) {
+			mlx4_CLOSE_PORT(dev, port);
+			err = mlx4_SET_PORT(dev, port);
+			if (err) {
+				mlx4_err(dev, "Failed to set port %d, "
+					      "aborting\n", port);
+				return err;
+			}
+		}
+		err = mlx4_register_device(dev);
+	}
+	return err;
+}
+
+static ssize_t show_port_type(struct device *dev,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct mlx4_dev *mdev = pci_get_drvdata(pdev);
+	int i;
+
+	sprintf(buf, "Current port types:\n");
+	for (i = 1; i <= MLX4_MAX_PORTS; i++) {
+		sprintf(buf, "%sPort%d: %s\n", buf, i,
+			(mdev->caps.port_type[i] == MLX4_PORT_TYPE_IB)?
+			"ib": "eth");
+	}
+	return strlen(buf);
+}
+
+static ssize_t set_port_type(struct device *dev,
+			     struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct mlx4_dev *mdev = pci_get_drvdata(pdev);
+	char *type;
+	enum mlx4_port_type port_types[MLX4_MAX_PORTS];
+	char *loc_buf;
+	char *ptr;
+	int i;
+	int err = 0;
+
+	loc_buf = kmalloc(count + 1, GFP_KERNEL);
+	if (!loc_buf)
+		return -ENOMEM;
+
+	ptr = loc_buf;
+	memcpy(loc_buf, buf, count + 1);
+	for (i = 0; i < MLX4_MAX_PORTS; i++) {
+		type = strsep(&loc_buf, ",");
+		if (!strcmp(type, "ib"))
+			port_types[i] = MLX4_PORT_TYPE_IB;
+		else if (!strcmp(type, "eth"))
+			port_types[i] = MLX4_PORT_TYPE_ETH;
+		else {
+			dev_warn(dev, "%s is not acceptable port type "
+				 "(use 'eth' or 'ib' only)\n", type);
+			err = -EINVAL;
+			goto out;
+		}
+	}
+	err = mlx4_check_port_params(mdev, port_types);
+	if (err)
+		goto out;
+
+	err = mlx4_change_port_types(mdev, port_types);
+out:
+	kfree(ptr);
+	return err ? err: count;
+}
+static DEVICE_ATTR(mlx4_port_type, S_IWUGO | S_IRUGO, show_port_type, set_port_type);
+
 static int mlx4_load_fw(struct mlx4_dev *dev)
 {
 	struct mlx4_priv *priv = mlx4_priv(dev);
@@ -979,8 +1069,14 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)

 	pci_set_drvdata(pdev, dev);

+	if (device_create_file(&pdev->dev, &dev_attr_mlx4_port_type))
+		goto err_sysfs;
+
 	return 0;

+err_sysfs:
+	mlx4_unregister_device(dev);
+
 err_cleanup:
 	mlx4_cleanup_mcg_table(dev);
 	mlx4_cleanup_qp_table(dev);
@@ -1036,6 +1132,7 @@ static void mlx4_remove_one(struct pci_dev *pdev)
 	int p;

 	if (dev) {
+		device_remove_file(&pdev->dev, &dev_attr_mlx4_port_type);
 		mlx4_unregister_device(dev);

 		for (p = 1; p <= dev->caps.num_ports; ++p)
-- 
1.5.4




More information about the general mailing list