net/mlx5: FPGA, Add basic support for Innova
authorIlan Tayari <ilant@mellanox.com>
Mon, 13 Mar 2017 18:05:45 +0000 (20:05 +0200)
committerSaeed Mahameed <saeedm@mellanox.com>
Sun, 14 May 2017 11:24:17 +0000 (14:24 +0300)
Mellanox Innova is a NIC with ConnectX and an FPGA on the same
board. The FPGA is a bump-on-the-wire and thus affects operation of
the mlx5_core driver on the ConnectX ASIC.

Add basic support for Innova in mlx5_core.

This allows using the Innova card as a regular NIC, by detecting
the FPGA capability bit, and verifying its load state before
initializing ConnectX interfaces.

Also detect FPGA fatal runtime failures and enter error state if
they ever happen.

All new FPGA-related logic is placed in its own subdirectory 'fpga',
which may be built by selecting CONFIG_MLX5_FPGA.
This prepares for further support of various Innova features in later
patchsets.
Additional details about hardware architecture will be provided as
more features get submitted.

Signed-off-by: Ilan Tayari <ilant@mellanox.com>
Reviewed-by: Boris Pismenny <borisp@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
13 files changed:
MAINTAINERS
drivers/net/ethernet/mellanox/mlx5/core/Kconfig
drivers/net/ethernet/mellanox/mlx5/core/Makefile
drivers/net/ethernet/mellanox/mlx5/core/eq.c
drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h [new file with mode: 0644]
drivers/net/ethernet/mellanox/mlx5/core/main.c
include/linux/mlx5/device.h
include/linux/mlx5/driver.h
include/linux/mlx5/mlx5_ifc.h
include/linux/mlx5/mlx5_ifc_fpga.h [new file with mode: 0644]

index f7d568b8f133d9919e3823c102d7ac78f89c894a..374ebf1b5d5db22b3f193e0e2852a674b5bf6379 100644 (file)
@@ -8304,6 +8304,16 @@ W:       http://www.mellanox.com
 Q:     http://patchwork.ozlabs.org/project/netdev/list/
 F:     drivers/net/ethernet/mellanox/mlx5/core/en_*
 
+MELLANOX ETHERNET INNOVA DRIVER
+M:     Ilan Tayari <ilant@mellanox.com>
+R:     Boris Pismenny <borisp@mellanox.com>
+L:     netdev@vger.kernel.org
+S:     Supported
+W:     http://www.mellanox.com
+Q:     http://patchwork.ozlabs.org/project/netdev/list/
+F:     drivers/net/ethernet/mellanox/mlx5/core/fpga/*
+F:     include/linux/mlx5/mlx5_ifc_fpga.h
+
 MELLANOX ETHERNET SWITCH DRIVERS
 M:     Jiri Pirko <jiri@mellanox.com>
 M:     Ido Schimmel <idosch@mellanox.com>
index fc52d742b7f7a52885bc78cfcb23acbd738bc552..28cf88483ca4ff972560c3453416734db0bcac6f 100644 (file)
@@ -11,6 +11,16 @@ config MLX5_CORE
          Core driver for low level functionality of the ConnectX-4 and
          Connect-IB cards by Mellanox Technologies.
 
+config MLX5_FPGA
+        bool "Mellanox Technologies Innova support"
+        depends on MLX5_CORE
+        ---help---
+          Build support for the Innova family of network cards by Mellanox
+          Technologies. Innova network cards are comprised of a ConnectX chip
+          and an FPGA chip on one board. If you select this option, the
+          mlx5_core driver will include the Innova FPGA core and allow building
+          sandbox-specific client drivers.
+
 config MLX5_CORE_EN
        bool "Mellanox Technologies ConnectX-4 Ethernet support"
        depends on NETDEVICES && ETHERNET && PCI && MLX5_CORE
index 9e644615f07a8b4e76a680cd830d36ffeed5043a..12556c03eec40811aa7cfad0fa2d36d1fca73bd4 100644 (file)
@@ -1,10 +1,13 @@
 obj-$(CONFIG_MLX5_CORE)                += mlx5_core.o
+subdir-ccflags-y += -I$(src)
 
 mlx5_core-y := main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
                health.o mcg.o cq.o srq.o alloc.o qp.o port.o mr.o pd.o \
                mad.o transobj.o vport.o sriov.o fs_cmd.o fs_core.o \
                fs_counters.o rl.o lag.o dev.o
 
+mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o
+
 mlx5_core-$(CONFIG_MLX5_CORE_EN) += wq.o eswitch.o eswitch_offloads.o \
                en_main.o en_common.o en_fs.o en_ethtool.o en_tx.o \
                en_rx.o en_rx_am.o en_txrx.o en_clock.o vxlan.o \
index df0034d8f48c4fc9433774034e62aaffcbb485c3..01d2cd7e474695b81f3f67f85f424ecca72f55ca 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/mlx5/driver.h>
 #include <linux/mlx5/cmd.h>
 #include "mlx5_core.h"
+#include "fpga/core.h"
 #ifdef CONFIG_MLX5_CORE_EN
 #include "eswitch.h"
 #endif
@@ -156,6 +157,8 @@ static const char *eqe_type_str(u8 type)
                return "MLX5_EVENT_TYPE_PAGE_FAULT";
        case MLX5_EVENT_TYPE_PPS_EVENT:
                return "MLX5_EVENT_TYPE_PPS_EVENT";
+       case MLX5_EVENT_TYPE_FPGA_ERROR:
+               return "MLX5_EVENT_TYPE_FPGA_ERROR";
        default:
                return "Unrecognized event";
        }
@@ -476,6 +479,11 @@ static irqreturn_t mlx5_eq_int(int irq, void *eq_ptr)
                        if (dev->event)
                                dev->event(dev, MLX5_DEV_EVENT_PPS, (unsigned long)eqe);
                        break;
+
+               case MLX5_EVENT_TYPE_FPGA_ERROR:
+                       mlx5_fpga_event(dev, eqe->type, &eqe->data.raw);
+                       break;
+
                default:
                        mlx5_core_warn(dev, "Unhandled event 0x%x on EQ 0x%x\n",
                                       eqe->type, eq->eqn);
@@ -693,6 +701,9 @@ int mlx5_start_eqs(struct mlx5_core_dev *dev)
        if (MLX5_CAP_GEN(dev, pps))
                async_event_mask |= (1ull << MLX5_EVENT_TYPE_PPS_EVENT);
 
+       if (MLX5_CAP_GEN(dev, fpga))
+               async_event_mask |= (1ull << MLX5_EVENT_TYPE_FPGA_ERROR);
+
        err = mlx5_create_map_eq(dev, &table->cmd_eq, MLX5_EQ_VEC_CMD,
                                 MLX5_NUM_CMD_EQE, 1ull << MLX5_EVENT_TYPE_CMD,
                                 "mlx5_cmd_eq", MLX5_EQ_TYPE_ASYNC);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.c
new file mode 100644 (file)
index 0000000..99cba64
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017, Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/etherdevice.h>
+#include <linux/mlx5/cmd.h>
+#include <linux/mlx5/driver.h>
+
+#include "mlx5_core.h"
+#include "fpga/cmd.h"
+
+int mlx5_fpga_caps(struct mlx5_core_dev *dev, u32 *caps)
+{
+       u32 in[MLX5_ST_SZ_DW(fpga_cap)] = {0};
+
+       return mlx5_core_access_reg(dev, in, sizeof(in), caps,
+                                   MLX5_ST_SZ_BYTES(fpga_cap),
+                                   MLX5_REG_FPGA_CAP, 0, 0);
+}
+
+int mlx5_fpga_query(struct mlx5_core_dev *dev, struct mlx5_fpga_query *query)
+{
+       u32 in[MLX5_ST_SZ_DW(fpga_ctrl)] = {0};
+       u32 out[MLX5_ST_SZ_DW(fpga_ctrl)];
+       int err;
+
+       err = mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out),
+                                  MLX5_REG_FPGA_CTRL, 0, false);
+       if (err)
+               return err;
+
+       query->status = MLX5_GET(fpga_ctrl, out, status);
+       query->admin_image = MLX5_GET(fpga_ctrl, out, flash_select_admin);
+       query->oper_image = MLX5_GET(fpga_ctrl, out, flash_select_oper);
+       return 0;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/cmd.h
new file mode 100644 (file)
index 0000000..a74396a
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2017, Mellanox Technologies, Ltd.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __MLX5_FPGA_H__
+#define __MLX5_FPGA_H__
+
+#include <linux/mlx5/driver.h>
+
+enum mlx5_fpga_image {
+       MLX5_FPGA_IMAGE_USER = 0,
+       MLX5_FPGA_IMAGE_FACTORY,
+};
+
+enum mlx5_fpga_status {
+       MLX5_FPGA_STATUS_SUCCESS = 0,
+       MLX5_FPGA_STATUS_FAILURE = 1,
+       MLX5_FPGA_STATUS_IN_PROGRESS = 2,
+       MLX5_FPGA_STATUS_NONE = 0xFFFF,
+};
+
+struct mlx5_fpga_query {
+       enum mlx5_fpga_image admin_image;
+       enum mlx5_fpga_image oper_image;
+       enum mlx5_fpga_status status;
+};
+
+int mlx5_fpga_caps(struct mlx5_core_dev *dev, u32 *caps);
+int mlx5_fpga_query(struct mlx5_core_dev *dev, struct mlx5_fpga_query *query);
+
+#endif /* __MLX5_FPGA_H__ */
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.c
new file mode 100644 (file)
index 0000000..d88b332
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2017, Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <linux/mlx5/driver.h>
+
+#include "mlx5_core.h"
+#include "fpga/core.h"
+
+static const char *const mlx5_fpga_error_strings[] = {
+       "Null Syndrome",
+       "Corrupted DDR",
+       "Flash Timeout",
+       "Internal Link Error",
+       "Watchdog HW Failure",
+       "I2C Failure",
+       "Image Changed",
+       "Temperature Critical",
+};
+
+static struct mlx5_fpga_device *mlx5_fpga_device_alloc(void)
+{
+       struct mlx5_fpga_device *fdev = NULL;
+
+       fdev = kzalloc(sizeof(*fdev), GFP_KERNEL);
+       if (!fdev)
+               return NULL;
+
+       spin_lock_init(&fdev->state_lock);
+       fdev->state = MLX5_FPGA_STATUS_NONE;
+       return fdev;
+}
+
+static const char *mlx5_fpga_image_name(enum mlx5_fpga_image image)
+{
+       switch (image) {
+       case MLX5_FPGA_IMAGE_USER:
+               return "user";
+       case MLX5_FPGA_IMAGE_FACTORY:
+               return "factory";
+       default:
+               return "unknown";
+       }
+}
+
+static int mlx5_fpga_device_load_check(struct mlx5_fpga_device *fdev)
+{
+       struct mlx5_fpga_query query;
+       int err;
+
+       err = mlx5_fpga_query(fdev->mdev, &query);
+       if (err) {
+               mlx5_fpga_err(fdev, "Failed to query status: %d\n", err);
+               return err;
+       }
+
+       fdev->last_admin_image = query.admin_image;
+       fdev->last_oper_image = query.oper_image;
+
+       mlx5_fpga_dbg(fdev, "Status %u; Admin image %u; Oper image %u\n",
+                     query.status, query.admin_image, query.oper_image);
+
+       if (query.status != MLX5_FPGA_STATUS_SUCCESS) {
+               mlx5_fpga_err(fdev, "%s image failed to load; status %u\n",
+                             mlx5_fpga_image_name(fdev->last_oper_image),
+                             query.status);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+int mlx5_fpga_device_start(struct mlx5_core_dev *mdev)
+{
+       struct mlx5_fpga_device *fdev = mdev->fpga;
+       unsigned long flags;
+       int err;
+
+       if (!fdev)
+               return 0;
+
+       err = mlx5_fpga_device_load_check(fdev);
+       if (err)
+               goto out;
+
+       err = mlx5_fpga_caps(fdev->mdev,
+                            fdev->mdev->caps.hca_cur[MLX5_CAP_FPGA]);
+       if (err)
+               goto out;
+
+       mlx5_fpga_info(fdev, "device %u; %s image, version %u\n",
+                      MLX5_CAP_FPGA(fdev->mdev, fpga_device),
+                      mlx5_fpga_image_name(fdev->last_oper_image),
+                      MLX5_CAP_FPGA(fdev->mdev, image_version));
+
+out:
+       spin_lock_irqsave(&fdev->state_lock, flags);
+       fdev->state = err ? MLX5_FPGA_STATUS_FAILURE : MLX5_FPGA_STATUS_SUCCESS;
+       spin_unlock_irqrestore(&fdev->state_lock, flags);
+       return err;
+}
+
+int mlx5_fpga_device_init(struct mlx5_core_dev *mdev)
+{
+       struct mlx5_fpga_device *fdev = NULL;
+
+       if (!MLX5_CAP_GEN(mdev, fpga)) {
+               mlx5_core_dbg(mdev, "FPGA capability not present\n");
+               return 0;
+       }
+
+       mlx5_core_dbg(mdev, "Initializing FPGA\n");
+
+       fdev = mlx5_fpga_device_alloc();
+       if (!fdev)
+               return -ENOMEM;
+
+       fdev->mdev = mdev;
+       mdev->fpga = fdev;
+
+       return 0;
+}
+
+void mlx5_fpga_device_cleanup(struct mlx5_core_dev *mdev)
+{
+       kfree(mdev->fpga);
+       mdev->fpga = NULL;
+}
+
+static const char *mlx5_fpga_syndrome_to_string(u8 syndrome)
+{
+       if (syndrome < ARRAY_SIZE(mlx5_fpga_error_strings))
+               return mlx5_fpga_error_strings[syndrome];
+       return "Unknown";
+}
+
+void mlx5_fpga_event(struct mlx5_core_dev *mdev, u8 event, void *data)
+{
+       struct mlx5_fpga_device *fdev = mdev->fpga;
+       const char *event_name;
+       bool teardown = false;
+       unsigned long flags;
+       u8 syndrome;
+
+       if (event != MLX5_EVENT_TYPE_FPGA_ERROR) {
+               mlx5_fpga_warn_ratelimited(fdev, "Unexpected event %u\n",
+                                          event);
+               return;
+       }
+
+       syndrome = MLX5_GET(fpga_error_event, data, syndrome);
+       event_name = mlx5_fpga_syndrome_to_string(syndrome);
+
+       spin_lock_irqsave(&fdev->state_lock, flags);
+       switch (fdev->state) {
+       case MLX5_FPGA_STATUS_SUCCESS:
+               mlx5_fpga_warn(fdev, "Error %u: %s\n", syndrome, event_name);
+               teardown = true;
+               break;
+       default:
+               mlx5_fpga_warn_ratelimited(fdev, "Unexpected error event %u: %s\n",
+                                          syndrome, event_name);
+       }
+       spin_unlock_irqrestore(&fdev->state_lock, flags);
+       /* We tear-down the card's interfaces and functionality because
+        * the FPGA bump-on-the-wire is misbehaving and we lose ability
+        * to communicate with the network. User may still be able to
+        * recover by re-programming or debugging the FPGA
+        */
+       if (teardown)
+               mlx5_trigger_health_work(fdev->mdev);
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h b/drivers/net/ethernet/mellanox/mlx5/core/fpga/core.h
new file mode 100644 (file)
index 0000000..c55044d
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2017, Mellanox Technologies, Ltd.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __MLX5_FPGA_CORE_H__
+#define __MLX5_FPGA_CORE_H__
+
+#ifdef CONFIG_MLX5_FPGA
+
+#include "fpga/cmd.h"
+
+/* Represents an Innova device */
+struct mlx5_fpga_device {
+       struct mlx5_core_dev *mdev;
+       spinlock_t state_lock; /* Protects state transitions */
+       enum mlx5_fpga_status state;
+       enum mlx5_fpga_image last_admin_image;
+       enum mlx5_fpga_image last_oper_image;
+};
+
+#define mlx5_fpga_dbg(__adev, format, ...) \
+       dev_dbg(&(__adev)->mdev->pdev->dev, "FPGA: %s:%d:(pid %d): " format, \
+                __func__, __LINE__, current->pid, ##__VA_ARGS__)
+
+#define mlx5_fpga_err(__adev, format, ...) \
+       dev_err(&(__adev)->mdev->pdev->dev, "FPGA: %s:%d:(pid %d): " format, \
+               __func__, __LINE__, current->pid, ##__VA_ARGS__)
+
+#define mlx5_fpga_warn(__adev, format, ...) \
+       dev_warn(&(__adev)->mdev->pdev->dev, "FPGA: %s:%d:(pid %d): " format, \
+               __func__, __LINE__, current->pid, ##__VA_ARGS__)
+
+#define mlx5_fpga_warn_ratelimited(__adev, format, ...) \
+       dev_warn_ratelimited(&(__adev)->mdev->pdev->dev, "FPGA: %s:%d: " \
+               format, __func__, __LINE__, ##__VA_ARGS__)
+
+#define mlx5_fpga_notice(__adev, format, ...) \
+       dev_notice(&(__adev)->mdev->pdev->dev, "FPGA: " format, ##__VA_ARGS__)
+
+#define mlx5_fpga_info(__adev, format, ...) \
+       dev_info(&(__adev)->mdev->pdev->dev, "FPGA: " format, ##__VA_ARGS__)
+
+int mlx5_fpga_device_init(struct mlx5_core_dev *mdev);
+void mlx5_fpga_device_cleanup(struct mlx5_core_dev *mdev);
+int mlx5_fpga_device_start(struct mlx5_core_dev *mdev);
+void mlx5_fpga_event(struct mlx5_core_dev *mdev, u8 event, void *data);
+
+#else
+
+static inline int mlx5_fpga_device_init(struct mlx5_core_dev *mdev)
+{
+       return 0;
+}
+
+static inline void mlx5_fpga_device_cleanup(struct mlx5_core_dev *mdev)
+{
+}
+
+static inline int mlx5_fpga_device_start(struct mlx5_core_dev *mdev)
+{
+       return 0;
+}
+
+static inline void mlx5_fpga_event(struct mlx5_core_dev *mdev, u8 event,
+                                  void *data)
+{
+}
+
+#endif
+
+#endif /* __MLX5_FPGA_CORE_H__ */
index f933922d5cca6d29db361ca68c4d234075a09fa6..ad0202cef203d95208be1a9d677a9fa47189e20e 100644 (file)
@@ -56,6 +56,7 @@
 #ifdef CONFIG_MLX5_CORE_EN
 #include "eswitch.h"
 #endif
+#include "fpga/core.h"
 
 MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>");
 MODULE_DESCRIPTION("Mellanox Connect-IB, ConnectX-4 core driver");
@@ -1113,10 +1114,16 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
                goto err_disable_msix;
        }
 
+       err = mlx5_fpga_device_init(dev);
+       if (err) {
+               dev_err(&pdev->dev, "fpga device init failed %d\n", err);
+               goto err_put_uars;
+       }
+
        err = mlx5_start_eqs(dev);
        if (err) {
                dev_err(&pdev->dev, "Failed to start pages and async EQs\n");
-               goto err_put_uars;
+               goto err_fpga_init;
        }
 
        err = alloc_comp_eqs(dev);
@@ -1147,6 +1154,12 @@ static int mlx5_load_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
                goto err_sriov;
        }
 
+       err = mlx5_fpga_device_start(dev);
+       if (err) {
+               dev_err(&pdev->dev, "fpga device start failed %d\n", err);
+               goto err_reg_dev;
+       }
+
        if (mlx5_device_registered(dev)) {
                mlx5_attach_device(dev);
        } else {
@@ -1182,6 +1195,9 @@ err_affinity_hints:
 err_stop_eqs:
        mlx5_stop_eqs(dev);
 
+err_fpga_init:
+       mlx5_fpga_device_cleanup(dev);
+
 err_put_uars:
        mlx5_put_uars_page(dev, priv->uar);
 
@@ -1246,6 +1262,7 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv,
        mlx5_irq_clear_affinity_hints(dev);
        free_comp_eqs(dev);
        mlx5_stop_eqs(dev);
+       mlx5_fpga_device_cleanup(dev);
        mlx5_put_uars_page(dev, priv->uar);
        mlx5_disable_msix(dev);
        if (cleanup)
index dd9a263ed368d5476b06a3464bbfada0436cf6e2..786a43843da98baf3741ce0084b426af2bcc695e 100644 (file)
@@ -300,6 +300,8 @@ enum mlx5_event {
 
        MLX5_EVENT_TYPE_PAGE_FAULT         = 0xc,
        MLX5_EVENT_TYPE_NIC_VPORT_CHANGE   = 0xd,
+
+       MLX5_EVENT_TYPE_FPGA_ERROR         = 0x20,
 };
 
 enum {
@@ -967,6 +969,7 @@ enum mlx5_cap_type {
        MLX5_CAP_RESERVED,
        MLX5_CAP_VECTOR_CALC,
        MLX5_CAP_QOS,
+       MLX5_CAP_FPGA,
        /* NUM OF CAP Types */
        MLX5_CAP_NUM
 };
@@ -1088,6 +1091,9 @@ enum mlx5_mcam_feature_groups {
 #define MLX5_CAP_MCAM_FEATURE(mdev, fld) \
        MLX5_GET(mcam_reg, (mdev)->caps.mcam, mng_feature_cap_mask.enhanced_features.fld)
 
+#define MLX5_CAP_FPGA(mdev, cap) \
+       MLX5_GET(fpga_cap, (mdev)->caps.hca_cur[MLX5_CAP_FPGA], cap)
+
 enum {
        MLX5_CMD_STAT_OK                        = 0x0,
        MLX5_CMD_STAT_INT_ERR                   = 0x1,
index a277bb36c21faaaed42775d9bb7a3a835561aa5f..55bb712643cb11233273e980db06cb41abdba300 100644 (file)
@@ -108,6 +108,8 @@ enum {
        MLX5_REG_QTCT            = 0x400a,
        MLX5_REG_DCBX_PARAM      = 0x4020,
        MLX5_REG_DCBX_APP        = 0x4021,
+       MLX5_REG_FPGA_CAP        = 0x4022,
+       MLX5_REG_FPGA_CTRL       = 0x4023,
        MLX5_REG_PCAP            = 0x5001,
        MLX5_REG_PMTU            = 0x5003,
        MLX5_REG_PTYS            = 0x5004,
@@ -761,6 +763,9 @@ struct mlx5_core_dev {
        atomic_t                num_qps;
        u32                     issi;
        struct mlx5e_resources  mlx5e_res;
+#ifdef CONFIG_MLX5_FPGA
+       struct mlx5_fpga_device *fpga;
+#endif
 #ifdef CONFIG_RFS_ACCEL
        struct cpu_rmap         *rmap;
 #endif
index 32de0724b40009adc2a802dcc5abafbb5505c0b1..6fa1eb6766afcb9478fcbc432436bbfe8d55d1dd 100644 (file)
@@ -32,6 +32,8 @@
 #ifndef MLX5_IFC_H
 #define MLX5_IFC_H
 
+#include "mlx5_ifc_fpga.h"
+
 enum {
        MLX5_EVENT_TYPE_CODING_COMPLETION_EVENTS                   = 0x0,
        MLX5_EVENT_TYPE_CODING_PATH_MIGRATED_SUCCEEDED             = 0x1,
@@ -56,7 +58,8 @@ enum {
        MLX5_EVENT_TYPE_CODING_STALL_VL_EVENT                      = 0x1b,
        MLX5_EVENT_TYPE_CODING_DROPPED_PACKET_LOGGED_EVENT         = 0x1f,
        MLX5_EVENT_TYPE_CODING_COMMAND_INTERFACE_COMPLETION        = 0xa,
-       MLX5_EVENT_TYPE_CODING_PAGE_REQUEST                        = 0xb
+       MLX5_EVENT_TYPE_CODING_PAGE_REQUEST                        = 0xb,
+       MLX5_EVENT_TYPE_CODING_FPGA_ERROR                          = 0x20,
 };
 
 enum {
@@ -854,7 +857,8 @@ struct mlx5_ifc_cmd_hca_cap_bits {
        u8         max_tc[0x4];
        u8         reserved_at_1d0[0x1];
        u8         dcbx[0x1];
-       u8         reserved_at_1d2[0x4];
+       u8         reserved_at_1d2[0x3];
+       u8         fpga[0x1];
        u8         rol_s[0x1];
        u8         rol_g[0x1];
        u8         reserved_at_1d8[0x1];
@@ -2186,6 +2190,7 @@ union mlx5_ifc_hca_cap_union_bits {
        struct mlx5_ifc_e_switch_cap_bits e_switch_cap;
        struct mlx5_ifc_vector_calc_cap_bits vector_calc_cap;
        struct mlx5_ifc_qos_cap_bits qos_cap;
+       struct mlx5_ifc_fpga_cap_bits fpga_cap;
        u8         reserved_at_0[0x8000];
 };
 
@@ -8182,6 +8187,8 @@ union mlx5_ifc_ports_control_registers_document_bits {
        struct mlx5_ifc_sltp_reg_bits sltp_reg;
        struct mlx5_ifc_mtpps_reg_bits mtpps_reg;
        struct mlx5_ifc_mtppse_reg_bits mtppse_reg;
+       struct mlx5_ifc_fpga_ctrl_bits fpga_ctrl_bits;
+       struct mlx5_ifc_fpga_cap_bits fpga_cap_bits;
        u8         reserved_at_0[0x60e0];
 };
 
diff --git a/include/linux/mlx5/mlx5_ifc_fpga.h b/include/linux/mlx5/mlx5_ifc_fpga.h
new file mode 100644 (file)
index 0000000..0032d10
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2017, Mellanox Technologies, Ltd.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef MLX5_IFC_FPGA_H
+#define MLX5_IFC_FPGA_H
+
+struct mlx5_ifc_fpga_shell_caps_bits {
+       u8         max_num_qps[0x10];
+       u8         reserved_at_10[0x8];
+       u8         total_rcv_credits[0x8];
+
+       u8         reserved_at_20[0xe];
+       u8         qp_type[0x2];
+       u8         reserved_at_30[0x5];
+       u8         rae[0x1];
+       u8         rwe[0x1];
+       u8         rre[0x1];
+       u8         reserved_at_38[0x4];
+       u8         dc[0x1];
+       u8         ud[0x1];
+       u8         uc[0x1];
+       u8         rc[0x1];
+
+       u8         reserved_at_40[0x1a];
+       u8         log_ddr_size[0x6];
+
+       u8         max_fpga_qp_msg_size[0x20];
+
+       u8         reserved_at_80[0x180];
+};
+
+struct mlx5_ifc_fpga_cap_bits {
+       u8         fpga_id[0x8];
+       u8         fpga_device[0x18];
+
+       u8         register_file_ver[0x20];
+
+       u8         fpga_ctrl_modify[0x1];
+       u8         reserved_at_41[0x5];
+       u8         access_reg_query_mode[0x2];
+       u8         reserved_at_48[0x6];
+       u8         access_reg_modify_mode[0x2];
+       u8         reserved_at_50[0x10];
+
+       u8         reserved_at_60[0x20];
+
+       u8         image_version[0x20];
+
+       u8         image_date[0x20];
+
+       u8         image_time[0x20];
+
+       u8         shell_version[0x20];
+
+       u8         reserved_at_100[0x80];
+
+       struct mlx5_ifc_fpga_shell_caps_bits shell_caps;
+
+       u8         reserved_at_380[0x8];
+       u8         ieee_vendor_id[0x18];
+
+       u8         sandbox_product_version[0x10];
+       u8         sandbox_product_id[0x10];
+
+       u8         sandbox_basic_caps[0x20];
+
+       u8         reserved_at_3e0[0x10];
+       u8         sandbox_extended_caps_len[0x10];
+
+       u8         sandbox_extended_caps_addr[0x40];
+
+       u8         fpga_ddr_start_addr[0x40];
+
+       u8         fpga_cr_space_start_addr[0x40];
+
+       u8         fpga_ddr_size[0x20];
+
+       u8         fpga_cr_space_size[0x20];
+
+       u8         reserved_at_500[0x300];
+};
+
+struct mlx5_ifc_fpga_ctrl_bits {
+       u8         reserved_at_0[0x8];
+       u8         operation[0x8];
+       u8         reserved_at_10[0x8];
+       u8         status[0x8];
+
+       u8         reserved_at_20[0x8];
+       u8         flash_select_admin[0x8];
+       u8         reserved_at_30[0x8];
+       u8         flash_select_oper[0x8];
+
+       u8         reserved_at_40[0x40];
+};
+
+enum {
+       MLX5_FPGA_ERROR_EVENT_SYNDROME_CORRUPTED_DDR        = 0x1,
+       MLX5_FPGA_ERROR_EVENT_SYNDROME_FLASH_TIMEOUT        = 0x2,
+       MLX5_FPGA_ERROR_EVENT_SYNDROME_INTERNAL_LINK_ERROR  = 0x3,
+       MLX5_FPGA_ERROR_EVENT_SYNDROME_WATCHDOG_FAILURE     = 0x4,
+       MLX5_FPGA_ERROR_EVENT_SYNDROME_I2C_FAILURE          = 0x5,
+       MLX5_FPGA_ERROR_EVENT_SYNDROME_IMAGE_CHANGED        = 0x6,
+       MLX5_FPGA_ERROR_EVENT_SYNDROME_TEMPERATURE_CRITICAL = 0x7,
+};
+
+struct mlx5_ifc_fpga_error_event_bits {
+       u8         reserved_at_0[0x40];
+
+       u8         reserved_at_40[0x18];
+       u8         syndrome[0x8];
+
+       u8         reserved_at_60[0x80];
+};
+
+#endif /* MLX5_IFC_FPGA_H */