|
@@ -513,6 +513,8 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
|
|
|
|
|
|
mlx4_log_num_mgm_entry_size = hca_param.log_mc_entry_sz;
|
|
|
|
|
|
+ dev->caps.hca_core_clock = hca_param.hca_core_clock;
|
|
|
+
|
|
|
memset(&dev_cap, 0, sizeof(dev_cap));
|
|
|
dev->caps.max_qp_dest_rdma = 1 << hca_param.log_rd_per_qp;
|
|
|
err = mlx4_dev_cap(dev, &dev_cap);
|
|
@@ -1226,8 +1228,31 @@ static void unmap_bf_area(struct mlx4_dev *dev)
|
|
|
io_mapping_free(mlx4_priv(dev)->bf_mapping);
|
|
|
}
|
|
|
|
|
|
+static int map_internal_clock(struct mlx4_dev *dev)
|
|
|
+{
|
|
|
+ struct mlx4_priv *priv = mlx4_priv(dev);
|
|
|
+
|
|
|
+ priv->clock_mapping =
|
|
|
+ ioremap(pci_resource_start(dev->pdev, priv->fw.clock_bar) +
|
|
|
+ priv->fw.clock_offset, MLX4_CLOCK_SIZE);
|
|
|
+
|
|
|
+ if (!priv->clock_mapping)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void unmap_internal_clock(struct mlx4_dev *dev)
|
|
|
+{
|
|
|
+ struct mlx4_priv *priv = mlx4_priv(dev);
|
|
|
+
|
|
|
+ if (priv->clock_mapping)
|
|
|
+ iounmap(priv->clock_mapping);
|
|
|
+}
|
|
|
+
|
|
|
static void mlx4_close_hca(struct mlx4_dev *dev)
|
|
|
{
|
|
|
+ unmap_internal_clock(dev);
|
|
|
unmap_bf_area(dev);
|
|
|
if (mlx4_is_slave(dev))
|
|
|
mlx4_slave_exit(dev);
|
|
@@ -1445,6 +1470,37 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
|
|
|
mlx4_err(dev, "INIT_HCA command failed, aborting.\n");
|
|
|
goto err_free_icm;
|
|
|
}
|
|
|
+ /*
|
|
|
+ * If TS is supported by FW
|
|
|
+ * read HCA frequency by QUERY_HCA command
|
|
|
+ */
|
|
|
+ if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) {
|
|
|
+ memset(&init_hca, 0, sizeof(init_hca));
|
|
|
+ err = mlx4_QUERY_HCA(dev, &init_hca);
|
|
|
+ if (err) {
|
|
|
+ mlx4_err(dev, "QUERY_HCA command failed, disable timestamp.\n");
|
|
|
+ dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_TS;
|
|
|
+ } else {
|
|
|
+ dev->caps.hca_core_clock =
|
|
|
+ init_hca.hca_core_clock;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* In case we got HCA frequency 0 - disable timestamping
|
|
|
+ * to avoid dividing by zero
|
|
|
+ */
|
|
|
+ if (!dev->caps.hca_core_clock) {
|
|
|
+ dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_TS;
|
|
|
+ mlx4_err(dev,
|
|
|
+ "HCA frequency is 0. Timestamping is not supported.");
|
|
|
+ } else if (map_internal_clock(dev)) {
|
|
|
+ /*
|
|
|
+ * Map internal clock,
|
|
|
+ * in case of failure disable timestamping
|
|
|
+ */
|
|
|
+ dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_TS;
|
|
|
+ mlx4_err(dev, "Failed to map internal clock. Timestamping is not supported.\n");
|
|
|
+ }
|
|
|
+ }
|
|
|
} else {
|
|
|
err = mlx4_init_slave(dev);
|
|
|
if (err) {
|
|
@@ -1478,6 +1534,7 @@ static int mlx4_init_hca(struct mlx4_dev *dev)
|
|
|
return 0;
|
|
|
|
|
|
unmap_bf:
|
|
|
+ unmap_internal_clock(dev);
|
|
|
unmap_bf_area(dev);
|
|
|
|
|
|
err_close:
|