[ofa-general][PATCH 6/11 v3] mlx4: Dynamic port configuration
Yevgeny Petrilin
yevgenyp at mellanox.co.il
Wed Jul 9 06:35:28 PDT 2008
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>
Diff from previous version:
-Using a separate sysfs file per port for the port type configuration
---
drivers/net/mlx4/main.c | 132 ++++++++++++++++++++++++++++++++++++++++++++--
drivers/net/mlx4/mlx4.h | 4 ++
2 files changed, 130 insertions(+), 6 deletions(-)
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index e6be948..4da4682 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -266,6 +266,92 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
return 0;
}
+/* Changes the port configuration of the device.
+ * Every user of this function must hold the port lock */
+static int mlx4_change_port_types(struct mlx4_dev *dev,
+ enum mlx4_port_type *port_types)
+{
+ int err = 0;
+ int change = 0;
+ int port;
+
+ for (port = 0; port < MLX4_MAX_PORTS; port++) {
+ if (port_types[port] != dev->caps.port_type[port + 1]) {
+ change = 1;
+ dev->caps.port_type[port + 1] = port_types[port];
+ }
+ }
+ 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);
+ goto out;
+ }
+ }
+ err = mlx4_register_device(dev);
+ }
+
+out:
+ return err;
+}
+
+static ssize_t show_port_type(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct mlx4_port_info *info = container_of(attr, struct mlx4_port_info,
+ port_attr);
+ struct mlx4_dev *mdev = info->dev;
+
+ sprintf(buf, "%s\n", (mdev->caps.port_type[info->port] == 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 mlx4_port_info *info = container_of(attr, struct mlx4_port_info,
+ port_attr);
+ struct mlx4_dev *mdev = info->dev;
+ struct mlx4_priv *priv = mlx4_priv(mdev);
+ enum mlx4_port_type types[MLX4_MAX_PORTS];
+ int i;
+ int err = 0;
+
+ if (!strcmp(buf, "ib\n"))
+ info->tmp_type = MLX4_PORT_TYPE_IB;
+ else if (!strcmp(buf, "eth\n"))
+ info->tmp_type = MLX4_PORT_TYPE_ETH;
+ else {
+ mlx4_err(mdev, "%s is not supported port type\n", buf);
+ return -EINVAL;
+ }
+
+ spin_lock(&priv->port_lock);
+ for (i = 0; i < mdev->caps.num_ports; i++)
+ types[i] = priv->port[i+1].tmp_type ? priv->port[i+1].tmp_type:
+ mdev->caps.port_type[i+1];
+
+ err = mlx4_check_port_params(mdev, types);
+ if (err)
+ goto out;
+
+ for (i = 1; i <= mdev->caps.num_ports; i++)
+ priv->port[i].tmp_type = 0;
+
+ err = mlx4_change_port_types(mdev, types);
+
+out:
+ spin_unlock(&priv->port_lock);
+ return err? err: count;
+}
+
static int mlx4_load_fw(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
@@ -839,14 +925,38 @@ no_msi:
priv->eq_table.eq[i].irq = dev->pdev->irq;
}
-static void mlx4_init_port_info(struct mlx4_dev *dev, int port)
+static int mlx4_init_port_info(struct mlx4_dev *dev, int port)
{
struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
+ struct attribute attr = {.name = info->dev_name,
+ .mode = S_IWUGO | S_IRUGO};
+ int err = 0;
info->dev = dev;
info->port = port;
mlx4_init_mac_table(dev, &info->mac_table);
mlx4_init_vlan_table(dev, &info->vlan_table);
+
+ sprintf(info->dev_name, "mlx4_port%d", port);
+ memcpy(&info->port_attr.attr, &attr, sizeof(attr));
+ info->port_attr.show = show_port_type;
+ info->port_attr.store = set_port_type;
+
+ err = device_create_file(&dev->pdev->dev, &info->port_attr);
+ if (err) {
+ mlx4_err(dev, "Failed to create file for port %d\n", port);
+ info->port = -1;
+ }
+
+ return err;
+}
+
+static void mlx4_cleanup_port_info(struct mlx4_port_info *info)
+{
+ if (info->port < 0)
+ return;
+
+ device_remove_file(&info->dev->pdev->dev, &info->port_attr);
}
static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -929,6 +1039,8 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
INIT_LIST_HEAD(&priv->ctx_list);
spin_lock_init(&priv->ctx_lock);
+ spin_lock_init(&priv->port_lock);
+
INIT_LIST_HEAD(&priv->pgdir_list);
mutex_init(&priv->pgdir_mutex);
@@ -964,18 +1076,24 @@ static int __mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (err)
goto err_close;
- for (port = 1; port <= dev->caps.num_ports; port++)
- mlx4_init_port_info(dev, port);
+ for (port = 1; port <= dev->caps.num_ports; port++) {
+ err = mlx4_init_port_info(dev, port);
+ if (err)
+ goto err_port;
+ }
err = mlx4_register_device(dev);
if (err)
- goto err_cleanup;
+ goto err_port;
pci_set_drvdata(pdev, dev);
return 0;
-err_cleanup:
+err_port:
+ for (port = 1; port <= dev->caps.num_ports; port++)
+ mlx4_cleanup_port_info(&priv->port[port]);
+
mlx4_cleanup_mcg_table(dev);
mlx4_cleanup_qp_table(dev);
mlx4_cleanup_srq_table(dev);
@@ -1032,8 +1150,10 @@ static void mlx4_remove_one(struct pci_dev *pdev)
if (dev) {
mlx4_unregister_device(dev);
- for (p = 1; p <= dev->caps.num_ports; ++p)
+ for (p = 1; p <= dev->caps.num_ports; p++) {
+ mlx4_cleanup_port_info(&priv->port[p]);
mlx4_CLOSE_PORT(dev, p);
+ }
mlx4_cleanup_mcg_table(dev);
mlx4_cleanup_qp_table(dev);
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index a90a28c..a6205c5 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -278,6 +278,9 @@ struct mlx4_vlan_table {
struct mlx4_port_info {
struct mlx4_dev *dev;
int port;
+ char dev_name[16];
+ struct device_attribute port_attr;
+ enum mlx4_port_type tmp_type;
struct mlx4_mac_table mac_table;
struct mlx4_vlan_table vlan_table;
};
@@ -311,6 +314,7 @@ struct mlx4_priv {
struct mlx4_uar driver_uar;
void __iomem *kar;
struct mlx4_port_info port[MLX4_MAX_PORTS + 1];
+ spinlock_t port_lock;
};
static inline struct mlx4_priv *mlx4_priv(struct mlx4_dev *dev)
--
1.5.3.7
More information about the general
mailing list