summaryrefslogtreecommitdiff
path: root/drivers/accel/qaic
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/accel/qaic')
-rw-r--r--drivers/accel/qaic/mhi_controller.c192
-rw-r--r--drivers/accel/qaic/qaic.h1
-rw-r--r--drivers/accel/qaic/qaic_data.c22
-rw-r--r--drivers/accel/qaic/qaic_debugfs.c1
-rw-r--r--drivers/accel/qaic/qaic_drv.c48
-rw-r--r--drivers/accel/qaic/qaic_ras.c1
-rw-r--r--drivers/accel/qaic/qaic_ssr.c1
-rw-r--r--drivers/accel/qaic/qaic_timesync.c1
-rw-r--r--drivers/accel/qaic/sahara.c2
9 files changed, 262 insertions, 7 deletions
diff --git a/drivers/accel/qaic/mhi_controller.c b/drivers/accel/qaic/mhi_controller.c
index 40e6d262ef21..c720b70b1e0f 100644
--- a/drivers/accel/qaic/mhi_controller.c
+++ b/drivers/accel/qaic/mhi_controller.c
@@ -23,6 +23,7 @@ MODULE_PARM_DESC(mhi_timeout_ms, "MHI controller timeout value");
static const char *fw_image_paths[FAMILY_MAX] = {
[FAMILY_AIC100] = "qcom/aic100/sbl.bin",
[FAMILY_AIC200] = "qcom/aic200/sbl.bin",
+ [FAMILY_AIC200_VF] = NULL,
};
static const struct mhi_channel_config aic100_channels[] = {
@@ -691,6 +692,159 @@ static const struct mhi_channel_config aic200_channels[] = {
},
};
+static const struct mhi_channel_config aic200vf_channels[] = {
+ {
+ .name = "QAIC_LOOPBACK",
+ .num = 0,
+ .num_elements = 32,
+ .local_elements = 0,
+ .event_ring = 0,
+ .dir = DMA_TO_DEVICE,
+ .ee_mask = MHI_CH_EE_AMSS,
+ .pollcfg = 0,
+ .doorbell = MHI_DB_BRST_DISABLE,
+ .lpm_notify = false,
+ .offload_channel = false,
+ .doorbell_mode_switch = false,
+ .wake_capable = false,
+ },
+ {
+ .name = "QAIC_LOOPBACK",
+ .num = 1,
+ .num_elements = 32,
+ .local_elements = 0,
+ .event_ring = 0,
+ .dir = DMA_FROM_DEVICE,
+ .ee_mask = MHI_CH_EE_AMSS,
+ .pollcfg = 0,
+ .doorbell = MHI_DB_BRST_DISABLE,
+ .lpm_notify = false,
+ .offload_channel = false,
+ .doorbell_mode_switch = false,
+ .wake_capable = false,
+ },
+ {
+ .name = "QAIC_SSR",
+ .num = 6,
+ .num_elements = 32,
+ .local_elements = 0,
+ .event_ring = 0,
+ .dir = DMA_TO_DEVICE,
+ .ee_mask = MHI_CH_EE_AMSS,
+ .pollcfg = 0,
+ .doorbell = MHI_DB_BRST_DISABLE,
+ .lpm_notify = false,
+ .offload_channel = false,
+ .doorbell_mode_switch = false,
+ .wake_capable = false,
+ },
+ {
+ .name = "QAIC_SSR",
+ .num = 7,
+ .num_elements = 32,
+ .local_elements = 0,
+ .event_ring = 0,
+ .dir = DMA_FROM_DEVICE,
+ .ee_mask = MHI_CH_EE_AMSS,
+ .pollcfg = 0,
+ .doorbell = MHI_DB_BRST_DISABLE,
+ .lpm_notify = false,
+ .offload_channel = false,
+ .doorbell_mode_switch = false,
+ .wake_capable = false,
+ },
+ {
+ .name = "QAIC_CONTROL",
+ .num = 10,
+ .num_elements = 128,
+ .local_elements = 0,
+ .event_ring = 0,
+ .dir = DMA_TO_DEVICE,
+ .ee_mask = MHI_CH_EE_AMSS,
+ .pollcfg = 0,
+ .doorbell = MHI_DB_BRST_DISABLE,
+ .lpm_notify = false,
+ .offload_channel = false,
+ .doorbell_mode_switch = false,
+ .wake_capable = false,
+ },
+ {
+ .name = "QAIC_CONTROL",
+ .num = 11,
+ .num_elements = 128,
+ .local_elements = 0,
+ .event_ring = 0,
+ .dir = DMA_FROM_DEVICE,
+ .ee_mask = MHI_CH_EE_AMSS,
+ .pollcfg = 0,
+ .doorbell = MHI_DB_BRST_DISABLE,
+ .lpm_notify = false,
+ .offload_channel = false,
+ .doorbell_mode_switch = false,
+ .wake_capable = false,
+ },
+ {
+ .name = "QAIC_TELEMETRY",
+ .num = 16,
+ .num_elements = 32,
+ .local_elements = 0,
+ .event_ring = 0,
+ .dir = DMA_TO_DEVICE,
+ .ee_mask = MHI_CH_EE_AMSS,
+ .pollcfg = 0,
+ .doorbell = MHI_DB_BRST_DISABLE,
+ .lpm_notify = false,
+ .offload_channel = false,
+ .doorbell_mode_switch = false,
+ .wake_capable = false,
+ },
+ {
+ .name = "QAIC_TELEMETRY",
+ .num = 17,
+ .num_elements = 32,
+ .local_elements = 0,
+ .event_ring = 0,
+ .dir = DMA_FROM_DEVICE,
+ .ee_mask = MHI_CH_EE_AMSS,
+ .pollcfg = 0,
+ .doorbell = MHI_DB_BRST_DISABLE,
+ .lpm_notify = false,
+ .offload_channel = false,
+ .doorbell_mode_switch = false,
+ .wake_capable = false,
+ },
+ {
+ .name = "IPCR",
+ .num = 24,
+ .num_elements = 32,
+ .local_elements = 0,
+ .event_ring = 0,
+ .dir = DMA_TO_DEVICE,
+ .ee_mask = MHI_CH_EE_AMSS,
+ .pollcfg = 0,
+ .doorbell = MHI_DB_BRST_DISABLE,
+ .lpm_notify = false,
+ .offload_channel = false,
+ .doorbell_mode_switch = false,
+ .wake_capable = false,
+ },
+ {
+ .name = "IPCR",
+ .num = 25,
+ .num_elements = 32,
+ .local_elements = 0,
+ .event_ring = 0,
+ .dir = DMA_FROM_DEVICE,
+ .ee_mask = MHI_CH_EE_AMSS,
+ .pollcfg = 0,
+ .doorbell = MHI_DB_BRST_DISABLE,
+ .lpm_notify = false,
+ .offload_channel = false,
+ .doorbell_mode_switch = false,
+ .wake_capable = false,
+ },
+};
+
static struct mhi_event_config aic100_events[] = {
{
.num_elements = 32,
@@ -721,6 +875,21 @@ static struct mhi_event_config aic200_events[] = {
},
};
+static struct mhi_event_config aic200vf_events[] = {
+ {
+ .num_elements = 32,
+ .irq_moderation_ms = 0,
+ .irq = 0,
+ .channel = U32_MAX,
+ .priority = 1,
+ .mode = MHI_DB_BRST_DISABLE,
+ .data_type = MHI_ER_CTRL,
+ .hardware_event = false,
+ .client_managed = false,
+ .offload_channel = false,
+ },
+};
+
static struct mhi_controller_config mhi_cntrl_configs[] = {
[FAMILY_AIC100] = {
.max_channels = 128,
@@ -744,6 +913,17 @@ static struct mhi_controller_config mhi_cntrl_configs[] = {
.use_bounce_buf = false,
.m2_no_db = false,
},
+ [FAMILY_AIC200_VF] = {
+ .max_channels = 128,
+ .timeout_ms = 0, /* controlled by mhi_timeout */
+ .buf_len = 0,
+ .num_channels = ARRAY_SIZE(aic200vf_channels),
+ .ch_cfg = aic200vf_channels,
+ .num_events = ARRAY_SIZE(aic200vf_events),
+ .event_cfg = aic200vf_events,
+ .use_bounce_buf = false,
+ .m2_no_db = false,
+ },
};
static int mhi_read_reg(struct mhi_controller *mhi_cntrl, void __iomem *addr, u32 *out)
@@ -864,11 +1044,19 @@ struct mhi_controller *qaic_mhi_register_controller(struct pci_dev *pci_dev, voi
mhi_cntrl->fw_image = fw_image_paths[family];
- if (family == FAMILY_AIC200) {
+ switch (family) {
+ case FAMILY_AIC200:
mhi_cntrl->name = "AIC200";
mhi_cntrl->seg_len = SZ_512K;
- } else {
+ break;
+ case FAMILY_AIC200_VF:
+ mhi_cntrl->name = "AIC200_VF";
+ break;
+ case FAMILY_AIC100:
mhi_cntrl->name = "AIC100";
+ break;
+ default:
+ mhi_cntrl->name = NULL;
}
/* use latest configured timeout */
diff --git a/drivers/accel/qaic/qaic.h b/drivers/accel/qaic/qaic.h
index 02ca99000e2a..889fa51da7da 100644
--- a/drivers/accel/qaic/qaic.h
+++ b/drivers/accel/qaic/qaic.h
@@ -35,6 +35,7 @@
enum aic_families {
FAMILY_AIC100,
FAMILY_AIC200,
+ FAMILY_AIC200_VF,
FAMILY_MAX,
};
diff --git a/drivers/accel/qaic/qaic_data.c b/drivers/accel/qaic/qaic_data.c
index ef0351b6dc9b..ee35e13091b3 100644
--- a/drivers/accel/qaic/qaic_data.c
+++ b/drivers/accel/qaic/qaic_data.c
@@ -15,6 +15,7 @@
#include <linux/math64.h>
#include <linux/mm.h>
#include <linux/moduleparam.h>
+#include <linux/overflow.h>
#include <linux/scatterlist.h>
#include <linux/spinlock.h>
#include <linux/srcu.h>
@@ -455,7 +456,12 @@ static int create_sgt(struct qaic_device *qdev, struct sg_table **sgt_out, u64 s
int order;
if (size) {
- nr_pages = DIV_ROUND_UP(size, PAGE_SIZE);
+ u64 nr_pages_u64 = DIV_ROUND_UP_ULL(size, PAGE_SIZE);
+
+ if (overflows_type(nr_pages_u64, int))
+ return -E2BIG;
+
+ nr_pages = nr_pages_u64;
/*
* calculate how much extra we are going to allocate, to remove
* later
@@ -1834,15 +1840,16 @@ int qaic_perf_stats_bo_ioctl(struct drm_device *dev, void *data, struct drm_file
goto free_ent;
}
bo = to_qaic_bo(obj);
+ ret = mutex_lock_interruptible(&bo->lock);
+ if (ret)
+ goto put_obj;
if (!bo->sliced) {
- drm_gem_object_put(obj);
ret = -EINVAL;
- goto free_ent;
+ goto unlock_bo;
}
if (bo->dbc->id != args->hdr.dbc_id) {
- drm_gem_object_put(obj);
ret = -EINVAL;
- goto free_ent;
+ goto unlock_bo;
}
/*
* perf stats ioctl is called before wait ioctl is complete then
@@ -1858,7 +1865,12 @@ int qaic_perf_stats_bo_ioctl(struct drm_device *dev, void *data, struct drm_file
bo->perf_stats.req_received_ts), 1000);
ent[i].queue_level_before = bo->perf_stats.queue_level_before;
ent[i].num_queue_element = bo->total_slice_nents;
+unlock_bo:
+ mutex_unlock(&bo->lock);
+put_obj:
drm_gem_object_put(obj);
+ if (ret)
+ goto free_ent;
}
if (copy_to_user(u64_to_user_ptr(args->data), ent, args->hdr.count * sizeof(*ent)))
diff --git a/drivers/accel/qaic/qaic_debugfs.c b/drivers/accel/qaic/qaic_debugfs.c
index 95c78e12dd61..909a4d774d90 100644
--- a/drivers/accel/qaic/qaic_debugfs.c
+++ b/drivers/accel/qaic/qaic_debugfs.c
@@ -5,6 +5,7 @@
#include <linux/debugfs.h>
#include <linux/device.h>
+#include <linux/device-id/mhi.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/mhi.h>
diff --git a/drivers/accel/qaic/qaic_drv.c b/drivers/accel/qaic/qaic_drv.c
index 0acf6cdd44f8..9e1e184efe0d 100644
--- a/drivers/accel/qaic/qaic_drv.c
+++ b/drivers/accel/qaic/qaic_drv.c
@@ -4,6 +4,7 @@
/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */
#include <linux/delay.h>
+#include <linux/device-id/mhi.h>
#include <linux/dma-mapping.h>
#include <linux/idr.h>
#include <linux/interrupt.h>
@@ -39,6 +40,7 @@ MODULE_IMPORT_NS("DMA_BUF");
#define PCI_DEVICE_ID_QCOM_AIC080 0xa080
#define PCI_DEVICE_ID_QCOM_AIC100 0xa100
#define PCI_DEVICE_ID_QCOM_AIC200 0xa110
+#define PCI_DEVICE_ID_QCOM_AIC200VF 0xa111
#define QAIC_NAME "qaic"
#define QAIC_DESC "Qualcomm Cloud AI Accelerators"
#define CNTL_MAJOR 5
@@ -77,6 +79,13 @@ static const struct qaic_device_config aic200_config = {
.dbc_bar_idx = 2,
};
+static const struct qaic_device_config aic200vf_config = {
+ .family = FAMILY_AIC200_VF,
+ .bar_mask = BIT(0) | BIT(1) | BIT(2) | BIT(4),
+ .mhi_bar_idx = 1,
+ .dbc_bar_idx = 2,
+};
+
bool datapath_polling;
module_param(datapath_polling, bool, 0400);
MODULE_PARM_DESC(datapath_polling, "Operate the datapath in polling mode");
@@ -609,6 +618,8 @@ static void qaic_pci_remove(struct pci_dev *pdev)
{
struct qaic_device *qdev = pci_get_drvdata(pdev);
+ pci_disable_sriov(pdev);
+
if (!qdev)
return;
@@ -665,6 +676,7 @@ static const struct pci_device_id qaic_ids[] = {
{ PCI_DEVICE_DATA(QCOM, AIC080, (kernel_ulong_t)&aic080_config), },
{ PCI_DEVICE_DATA(QCOM, AIC100, (kernel_ulong_t)&aic100_config), },
{ PCI_DEVICE_DATA(QCOM, AIC200, (kernel_ulong_t)&aic200_config), },
+ { PCI_DEVICE_DATA(QCOM, AIC200VF, (kernel_ulong_t)&aic200vf_config), },
{ }
};
MODULE_DEVICE_TABLE(pci, qaic_ids);
@@ -761,6 +773,41 @@ static const struct dev_pm_ops qaic_pm_ops = {
SYSTEM_SLEEP_PM_OPS(qaic_pm_suspend, qaic_pm_resume)
};
+static int qaic_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
+{
+ struct qaic_device *qdev = pci_get_drvdata(pdev);
+ int rcu_id;
+ int ret;
+
+ if (num_vfs == 0) {
+ pci_disable_sriov(pdev);
+ return 0;
+ }
+
+ rcu_id = srcu_read_lock(&qdev->dev_lock);
+ /* Qaic device must be online to process VF bringup */
+ if (qdev->dev_state == QAIC_OFFLINE) {
+ ret = -ENODEV;
+ goto unlock_dev_srcu;
+ }
+ if (qdev->dev_state == QAIC_BOOT) {
+ ret = -EBUSY;
+ goto unlock_dev_srcu;
+ }
+
+ ret = pci_enable_sriov(pdev, num_vfs);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to enable SR-IOV: %d (requested %d VFs, max %d)\n",
+ ret, num_vfs, pci_sriov_get_totalvfs(pdev));
+ goto unlock_dev_srcu;
+ }
+
+ dev_dbg(&pdev->dev, "Successfully enabled %d VFs\n", num_vfs);
+unlock_dev_srcu:
+ srcu_read_unlock(&qdev->dev_lock, rcu_id);
+ return ret ?: num_vfs;
+}
+
static struct pci_driver qaic_pci_driver = {
.name = QAIC_NAME,
.id_table = qaic_ids,
@@ -768,6 +815,7 @@ static struct pci_driver qaic_pci_driver = {
.remove = qaic_pci_remove,
.shutdown = qaic_pci_shutdown,
.err_handler = &qaic_pci_err_handler,
+ .sriov_configure = qaic_pci_sriov_configure,
.driver = {
.pm = pm_sleep_ptr(&qaic_pm_ops),
},
diff --git a/drivers/accel/qaic/qaic_ras.c b/drivers/accel/qaic/qaic_ras.c
index e0205c2cda3d..236e520f708f 100644
--- a/drivers/accel/qaic/qaic_ras.c
+++ b/drivers/accel/qaic/qaic_ras.c
@@ -5,6 +5,7 @@
#include <asm/byteorder.h>
#include <linux/device.h>
+#include <linux/device-id/mhi.h>
#include <linux/kernel.h>
#include <linux/mhi.h>
diff --git a/drivers/accel/qaic/qaic_ssr.c b/drivers/accel/qaic/qaic_ssr.c
index a98928654959..418f14936f9a 100644
--- a/drivers/accel/qaic/qaic_ssr.c
+++ b/drivers/accel/qaic/qaic_ssr.c
@@ -8,6 +8,7 @@
#include <drm/drm_managed.h>
#include <linux/devcoredump.h>
#include <linux/device.h>
+#include <linux/device-id/mhi.h>
#include <linux/kernel.h>
#include <linux/mhi.h>
#include <linux/workqueue.h>
diff --git a/drivers/accel/qaic/qaic_timesync.c b/drivers/accel/qaic/qaic_timesync.c
index 45e5f0728ebe..b5162677ccc4 100644
--- a/drivers/accel/qaic/qaic_timesync.c
+++ b/drivers/accel/qaic/qaic_timesync.c
@@ -2,6 +2,7 @@
/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */
+#include <linux/device-id/mhi.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/math64.h>
diff --git a/drivers/accel/qaic/sahara.c b/drivers/accel/qaic/sahara.c
index c7c0b3eb4b65..e951181e424f 100644
--- a/drivers/accel/qaic/sahara.c
+++ b/drivers/accel/qaic/sahara.c
@@ -3,6 +3,7 @@
/* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */
#include <linux/devcoredump.h>
+#include <linux/device-id/mhi.h>
#include <linux/firmware.h>
#include <linux/limits.h>
#include <linux/mhi.h>
@@ -880,6 +881,7 @@ static void sahara_mhi_remove(struct mhi_device *mhi_dev)
cancel_work_sync(&context->fw_work);
cancel_work_sync(&context->dump_work);
+ cancel_work_sync(&context->read_data_work);
vfree(context->mem_dump);
sahara_release_image(context);
mhi_unprepare_from_transfer(mhi_dev);