In multifunctional devices, only the primary function would succeed
to execute QUERY_FW command, all other would fail with _EACCES error.
Ownership on the device can also be claimed by reading a descriptor before
sw reset. If it is 0, no one claimed ownership on the device so far,
otherwise, you are not the owner.
A physical function that is not primary would behave as slave.

Signed-off-by: Yevgeny Petrilin <[email protected]>
---
 drivers/net/mlx4/fw.c       |    4 ++++
 drivers/net/mlx4/fw.h       |    1 +
 drivers/net/mlx4/main.c     |   32 ++++++++++++++++++++++++++++++--
 drivers/net/mlx4/mlx4.h     |    2 ++
 drivers/net/mlx4/reset.c    |   33 +++++++++++++++++++++++++++++++++
 include/linux/mlx4/device.h |    2 ++
 6 files changed, 72 insertions(+), 2 deletions(-)

diff --git a/drivers/net/mlx4/fw.c b/drivers/net/mlx4/fw.c
index dc0570f..d1427e5 100644
--- a/drivers/net/mlx4/fw.c
+++ b/drivers/net/mlx4/fw.c
@@ -309,6 +309,10 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct 
mlx4_dev_cap *dev_cap)
        dev_cap->max_rdma_global = 1 << (field & 0x3f);
        MLX4_GET(field, outbox, QUERY_DEV_CAP_ACK_DELAY_OFFSET);
        dev_cap->local_ca_ack_delay = field & 0x1f;
+       MLX4_GET(field, outbox, QUERY_DEV_CAP_MTU_WIDTH_OFFSET);
+       dev_cap->pf_num = field;
+       if (dev_cap->pf_num > 1)
+               dev->flags |= MLX4_FLAG_MASTER;
        MLX4_GET(field, outbox, QUERY_DEV_CAP_VL_PORT_OFFSET);
        dev_cap->num_ports = field & 0xf;
        MLX4_GET(field, outbox, QUERY_DEV_CAP_MAX_MSG_SZ_OFFSET);
diff --git a/drivers/net/mlx4/fw.h b/drivers/net/mlx4/fw.h
index d066c69..a9d7e55 100644
--- a/drivers/net/mlx4/fw.h
+++ b/drivers/net/mlx4/fw.h
@@ -64,6 +64,7 @@ struct mlx4_dev_cap {
        int max_responder_per_qp;
        int max_rdma_global;
        int local_ca_ack_delay;
+       int pf_num;
        int num_ports;
        u32 max_msg_sz;
        int ib_mtu[MLX4_MAX_PORTS + 1];
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index 3331c33..9dca6f4 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -191,6 +191,7 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct 
mlx4_dev_cap *dev_cap)
                return -ENODEV;
        }
 
+       dev->caps.pf_num = dev_cap->pf_num;
        dev->caps.num_ports          = dev_cap->num_ports;
        for (i = 1; i <= dev->caps.num_ports; ++i) {
                dev->caps.vl_cap[i]         = dev_cap->max_vl[i];
@@ -1296,6 +1297,19 @@ static int __mlx4_init_one(struct pci_dev *pdev, const 
struct pci_device_id *id)
 
        /* We reset the device and enable SRIOV only for physical devices */
        if (!mlx4_is_slave(dev)) {
+               /* Claim ownership on the device,
+                * if already taken, act as slave*/
+               err = mlx4_get_ownership(dev);
+               if (err) {
+                       if (err < 0) {
+                               goto err_free_dev;
+                       } else {
+                               err = 0;
+                               dev->flags |= MLX4_FLAG_SLAVE;
+                               goto slave_start;
+                       }
+               }
+
                /*
                 * Now reset the HCA before we touch the PCI capabilities or
                 * attempt a firmware command, since a boot ROM may have left
@@ -1317,6 +1331,7 @@ static int __mlx4_init_one(struct pci_dev *pdev, const 
struct pci_device_id *id)
                }
        }
 
+slave_start:
        if (mlx4_cmd_init(dev)) {
                mlx4_err(dev, "Failed to init command interface, aborting.\n");
                goto err_sriov;
@@ -1332,8 +1347,17 @@ static int __mlx4_init_one(struct pci_dev *pdev, const 
struct pci_device_id *id)
        }
 
        err = mlx4_init_hca(dev);
-       if (err)
-               goto err_cmd;
+       if (err) {
+               if (err == -EACCES) {
+                       /* Not primary Physical function
+                        * Running in slave mode */
+                       mlx4_cmd_cleanup(dev);
+                       dev->flags |= MLX4_FLAG_SLAVE;
+                       dev->flags &= ~MLX4_FLAG_MASTER;
+                       goto slave_start;
+               } else
+                       goto err_cmd;
+       }
 
        /* In master functions, the communication channel must be initialized 
after obtaining
         * its address from fw */
@@ -1422,6 +1446,8 @@ err_sriov:
                pci_disable_sriov(pdev);
 
 err_free_dev:
+       if (!mlx4_is_slave(dev))
+               mlx4_free_ownership(dev);
        kfree(priv);
 
 err_release_regions:
@@ -1490,6 +1516,8 @@ static void mlx4_remove_one(struct pci_dev *pdev)
                        pci_disable_sriov(pdev);
                }
 
+               if (!mlx4_is_slave(dev))
+                       mlx4_free_ownership(dev);
                kfree(priv);
                pci_release_regions(pdev);
                pci_disable_device(pdev);
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index 5206459..351956d 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -437,6 +437,8 @@ int mlx4_bitmap_init(struct mlx4_bitmap *bitmap, u32 num, 
u32 mask,
 void mlx4_bitmap_cleanup(struct mlx4_bitmap *bitmap);
 
 int mlx4_reset(struct mlx4_dev *dev);
+int mlx4_get_ownership(struct mlx4_dev *dev);
+void mlx4_free_ownership(struct mlx4_dev *dev);
 
 int mlx4_alloc_eq_table(struct mlx4_dev *dev);
 void mlx4_free_eq_table(struct mlx4_dev *dev);
diff --git a/drivers/net/mlx4/reset.c b/drivers/net/mlx4/reset.c
index e5741da..bef79c0 100644
--- a/drivers/net/mlx4/reset.c
+++ b/drivers/net/mlx4/reset.c
@@ -39,6 +39,39 @@
 
 #include "mlx4.h"
 
+
+#define MLX4_OWNER_BASE        0x8069c
+#define MLX4_OWNER_SIZE        4
+
+int mlx4_get_ownership(struct mlx4_dev *dev)
+{
+       void __iomem *owner;
+       u32 ret;
+
+       owner = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_OWNER_BASE,
+                       MLX4_OWNER_SIZE);
+       if (!owner) {
+               mlx4_err(dev, "Failed to obtain ownership bit\n");
+               return -ENOMEM;
+       }
+
+       ret = readl(owner);
+       return (int) !!ret;
+}
+
+void mlx4_free_ownership(struct mlx4_dev *dev)
+{
+       void __iomem *owner;
+
+       owner = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_OWNER_BASE,
+                       MLX4_OWNER_SIZE);
+       if (!owner) {
+               mlx4_err(dev, "Failed to obtain ownership bit\n");
+               return;
+       }
+       writel(0, owner);
+}
+
 int mlx4_reset(struct mlx4_dev *dev)
 {
        void __iomem *reset;
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index 78a5fc9..c543210 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -45,6 +45,7 @@ enum {
        MLX4_FLAG_MASTER        = 1 << 2,
        MLX4_FLAG_SLAVE         = 1 << 3,
        MLX4_FLAG_SRIOV         = 1 << 4,
+       MLX4_FLAG_PF            = 1 << 5,
 };
 
 enum {
@@ -182,6 +183,7 @@ static inline u64 mlx4_fw_ver(u64 major, u64 minor, u64 
subminor)
 
 struct mlx4_caps {
        u64                     fw_ver;
+       int                     pf_num;
        int                     num_ports;
        int                     vl_cap[MLX4_MAX_PORTS + 1];
        int                     ib_mtu_cap[MLX4_MAX_PORTS + 1];
-- 
1.6.0.2

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to