From 515a2f507491e7c3818e74ef4f4e088c1fecb190 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 8 Jan 2022 07:50:56 +0100 Subject: mei: me: Use dma_set_mask_and_coherent() and simplify code Use dma_set_mask_and_coherent() instead of unrolling it with some dma_set_mask()+dma_set_coherent_mask(). Moreover, as stated in [1], dma_set_mask() with a 64-bit mask will never fail if dev->dma_mask is non-NULL. So, if it fails, the 32 bits case will also fail for the same reason. Simplify code and remove some dead code accordingly. While at it, include directly instead on relying on indirect inclusion. [1]: https://lkml.org/lkml/2021/6/7/398 Acked-by: Tomas Winkler Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/67ddcec656194153830684e6ff4513114e8859d6.1641624544.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/pci-me.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index 3a45aaf002ac..a05cdb25d0c4 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -192,14 +193,7 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto end; } - if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) || - dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) { - - err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (err) - err = dma_set_coherent_mask(&pdev->dev, - DMA_BIT_MASK(32)); - } + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); if (err) { dev_err(&pdev->dev, "No usable DMA configuration, aborting\n"); goto end; -- cgit v1.3.1 From 597568e8df046ebf349c706b281a711297ab20fb Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Tue, 25 Jan 2022 13:50:07 +0800 Subject: misc: rtsx: Rework runtime power management flow Commit 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM") uses "rtd3_work" and "idle_work" to manage it's own runtime PM state machine. When its child device, rtsx_pci_sdmmc, uses runtime PM refcount correctly, all the additional works can be managed by generic runtime PM helpers. So consolidate "idle_work" and "rtd3_work" into generic runtime idle callback and runtime suspend callback, respectively. Fixes: 5b4258f6721f ("misc: rtsx: rts5249 support runtime PM") Cc: Ricky WU Tested-by: Ricky WU Signed-off-by: Kai-Heng Feng Link: https://lore.kernel.org/r/20220125055010.1866563-2-kai.heng.feng@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cardreader/rtsx_pcr.c | 118 ++++++++++++------------------------- include/linux/rtsx_pci.h | 3 - 2 files changed, 39 insertions(+), 82 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c index 6ac509c1821c..8aba47a7d973 100644 --- a/drivers/misc/cardreader/rtsx_pcr.c +++ b/drivers/misc/cardreader/rtsx_pcr.c @@ -152,20 +152,12 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr) if (pcr->remove_pci) return; - if (pcr->rtd3_en) - if (pcr->is_runtime_suspended) { - pm_runtime_get(&(pcr->pci->dev)); - pcr->is_runtime_suspended = false; - } - if (pcr->state != PDEV_STAT_RUN) { pcr->state = PDEV_STAT_RUN; if (pcr->ops->enable_auto_blink) pcr->ops->enable_auto_blink(pcr); rtsx_pm_full_on(pcr); } - - mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200)); } EXPORT_SYMBOL_GPL(rtsx_pci_start_run); @@ -1094,40 +1086,6 @@ static void rtsx_pm_power_saving(struct rtsx_pcr *pcr) rtsx_comm_pm_power_saving(pcr); } -static void rtsx_pci_rtd3_work(struct work_struct *work) -{ - struct delayed_work *dwork = to_delayed_work(work); - struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, rtd3_work); - - pcr_dbg(pcr, "--> %s\n", __func__); - if (!pcr->is_runtime_suspended) - pm_runtime_put(&(pcr->pci->dev)); -} - -static void rtsx_pci_idle_work(struct work_struct *work) -{ - struct delayed_work *dwork = to_delayed_work(work); - struct rtsx_pcr *pcr = container_of(dwork, struct rtsx_pcr, idle_work); - - pcr_dbg(pcr, "--> %s\n", __func__); - - mutex_lock(&pcr->pcr_mutex); - - pcr->state = PDEV_STAT_IDLE; - - if (pcr->ops->disable_auto_blink) - pcr->ops->disable_auto_blink(pcr); - if (pcr->ops->turn_off_led) - pcr->ops->turn_off_led(pcr); - - rtsx_pm_power_saving(pcr); - - mutex_unlock(&pcr->pcr_mutex); - - if (pcr->rtd3_en) - mod_delayed_work(system_wq, &pcr->rtd3_work, msecs_to_jiffies(10000)); -} - static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) { /* Set relink_time to 0 */ @@ -1598,7 +1556,6 @@ static int rtsx_pci_probe(struct pci_dev *pcidev, pcr->card_inserted = 0; pcr->card_removed = 0; INIT_DELAYED_WORK(&pcr->carddet_work, rtsx_pci_card_detect); - INIT_DELAYED_WORK(&pcr->idle_work, rtsx_pci_idle_work); pcr->msi_en = msi_en; if (pcr->msi_en) { @@ -1623,20 +1580,14 @@ static int rtsx_pci_probe(struct pci_dev *pcidev, rtsx_pcr_cells[i].pdata_size = sizeof(*handle); } - if (pcr->rtd3_en) { - INIT_DELAYED_WORK(&pcr->rtd3_work, rtsx_pci_rtd3_work); - pm_runtime_allow(&pcidev->dev); - pm_runtime_enable(&pcidev->dev); - pcr->is_runtime_suspended = false; - } - ret = mfd_add_devices(&pcidev->dev, pcr->id, rtsx_pcr_cells, ARRAY_SIZE(rtsx_pcr_cells), NULL, 0, NULL); if (ret < 0) goto free_slots; - schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200)); + pm_runtime_allow(&pcidev->dev); + pm_runtime_put(&pcidev->dev); return 0; @@ -1668,11 +1619,11 @@ static void rtsx_pci_remove(struct pci_dev *pcidev) struct pcr_handle *handle = pci_get_drvdata(pcidev); struct rtsx_pcr *pcr = handle->pcr; - if (pcr->rtd3_en) - pm_runtime_get_noresume(&pcr->pci->dev); - pcr->remove_pci = true; + pm_runtime_get_sync(&pcidev->dev); + pm_runtime_forbid(&pcidev->dev); + /* Disable interrupts at the pcr level */ spin_lock_irq(&pcr->lock); rtsx_pci_writel(pcr, RTSX_BIER, 0); @@ -1680,9 +1631,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev) spin_unlock_irq(&pcr->lock); cancel_delayed_work_sync(&pcr->carddet_work); - cancel_delayed_work_sync(&pcr->idle_work); - if (pcr->rtd3_en) - cancel_delayed_work_sync(&pcr->rtd3_work); mfd_remove_devices(&pcidev->dev); @@ -1700,11 +1648,6 @@ static void rtsx_pci_remove(struct pci_dev *pcidev) idr_remove(&rtsx_pci_idr, pcr->id); spin_unlock(&rtsx_pci_lock); - if (pcr->rtd3_en) { - pm_runtime_disable(&pcr->pci->dev); - pm_runtime_put_noidle(&pcr->pci->dev); - } - kfree(pcr->slots); kfree(pcr); kfree(handle); @@ -1726,7 +1669,6 @@ static int __maybe_unused rtsx_pci_suspend(struct device *dev_d) pcr = handle->pcr; cancel_delayed_work(&pcr->carddet_work); - cancel_delayed_work(&pcr->idle_work); mutex_lock(&pcr->pcr_mutex); @@ -1760,8 +1702,6 @@ static int __maybe_unused rtsx_pci_resume(struct device *dev_d) if (ret) goto out; - schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200)); - out: mutex_unlock(&pcr->pcr_mutex); return ret; @@ -1786,6 +1726,33 @@ static void rtsx_pci_shutdown(struct pci_dev *pcidev) pci_disable_msi(pcr->pci); } +static int rtsx_pci_runtime_idle(struct device *device) +{ + struct pci_dev *pcidev = to_pci_dev(device); + struct pcr_handle *handle = pci_get_drvdata(pcidev); + struct rtsx_pcr *pcr = handle->pcr; + + dev_dbg(device, "--> %s\n", __func__); + + mutex_lock(&pcr->pcr_mutex); + + pcr->state = PDEV_STAT_IDLE; + + if (pcr->ops->disable_auto_blink) + pcr->ops->disable_auto_blink(pcr); + if (pcr->ops->turn_off_led) + pcr->ops->turn_off_led(pcr); + + rtsx_pm_power_saving(pcr); + + mutex_unlock(&pcr->pcr_mutex); + + if (pcr->rtd3_en) + pm_schedule_suspend(device, 10000); + + return -EBUSY; +} + static int rtsx_pci_runtime_suspend(struct device *device) { struct pci_dev *pcidev = to_pci_dev(device); @@ -1794,31 +1761,26 @@ static int rtsx_pci_runtime_suspend(struct device *device) handle = pci_get_drvdata(pcidev); pcr = handle->pcr; - dev_dbg(&(pcidev->dev), "--> %s\n", __func__); - cancel_delayed_work(&pcr->carddet_work); - cancel_delayed_work(&pcr->rtd3_work); - cancel_delayed_work(&pcr->idle_work); + dev_dbg(device, "--> %s\n", __func__); + + cancel_delayed_work_sync(&pcr->carddet_work); mutex_lock(&pcr->pcr_mutex); rtsx_pci_power_off(pcr, HOST_ENTER_S3); mutex_unlock(&pcr->pcr_mutex); - pcr->is_runtime_suspended = true; - return 0; } static int rtsx_pci_runtime_resume(struct device *device) { struct pci_dev *pcidev = to_pci_dev(device); - struct pcr_handle *handle; - struct rtsx_pcr *pcr; + struct pcr_handle *handle = pci_get_drvdata(pcidev); + struct rtsx_pcr *pcr = handle->pcr; - handle = pci_get_drvdata(pcidev); - pcr = handle->pcr; - dev_dbg(&(pcidev->dev), "--> %s\n", __func__); + dev_dbg(device, "--> %s\n", __func__); mutex_lock(&pcr->pcr_mutex); @@ -1834,8 +1796,6 @@ static int rtsx_pci_runtime_resume(struct device *device) pcr->slots[RTSX_SD_CARD].p_dev); } - schedule_delayed_work(&pcr->idle_work, msecs_to_jiffies(200)); - mutex_unlock(&pcr->pcr_mutex); return 0; } @@ -1850,7 +1810,7 @@ static int rtsx_pci_runtime_resume(struct device *device) static const struct dev_pm_ops rtsx_pci_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(rtsx_pci_suspend, rtsx_pci_resume) - SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend, rtsx_pci_runtime_resume, NULL) + SET_RUNTIME_PM_OPS(rtsx_pci_runtime_suspend, rtsx_pci_runtime_resume, rtsx_pci_runtime_idle) }; static struct pci_driver rtsx_pci_driver = { diff --git a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h index 4ab7bfc675f1..89b7d34e25b6 100644 --- a/include/linux/rtsx_pci.h +++ b/include/linux/rtsx_pci.h @@ -1201,8 +1201,6 @@ struct rtsx_pcr { unsigned int card_exist; struct delayed_work carddet_work; - struct delayed_work idle_work; - struct delayed_work rtd3_work; spinlock_t lock; struct mutex pcr_mutex; @@ -1212,7 +1210,6 @@ struct rtsx_pcr { unsigned int cur_clock; bool remove_pci; bool msi_en; - bool is_runtime_suspended; #define EXTRA_CAPS_SD_SDR50 (1 << 0) #define EXTRA_CAPS_SD_SDR104 (1 << 1) -- cgit v1.3.1 From b11a3c7a4b31fbc331670d5e2378ed71a4334be0 Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Tue, 25 Jan 2022 13:50:08 +0800 Subject: misc: rtsx: Cleanup power management ops - Use cancel_delayed_work_sync to ensure there's no race with carddet_work. - Remove device_wakeup_disable to save some CPU cycles. If the device really has ACPI _DSW then the wakeup should be disabled in probe routine. - Remove fetch_vendor_settings from runtime resume routine, since they are already saved in "struct rtsx_pcr". - Move variable assignments to the top of the functions. Cc: Ricky WU Tested-by: Ricky WU Signed-off-by: Kai-Heng Feng Link: https://lore.kernel.org/r/20220125055010.1866563-3-kai.heng.feng@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cardreader/rtsx_pcr.c | 34 +++++++++------------------------- 1 file changed, 9 insertions(+), 25 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c index 8aba47a7d973..3c97d3b50456 100644 --- a/drivers/misc/cardreader/rtsx_pcr.c +++ b/drivers/misc/cardreader/rtsx_pcr.c @@ -1660,22 +1660,17 @@ static void rtsx_pci_remove(struct pci_dev *pcidev) static int __maybe_unused rtsx_pci_suspend(struct device *dev_d) { struct pci_dev *pcidev = to_pci_dev(dev_d); - struct pcr_handle *handle; - struct rtsx_pcr *pcr; + struct pcr_handle *handle = pci_get_drvdata(pcidev); + struct rtsx_pcr *pcr = handle->pcr; dev_dbg(&(pcidev->dev), "--> %s\n", __func__); - handle = pci_get_drvdata(pcidev); - pcr = handle->pcr; - - cancel_delayed_work(&pcr->carddet_work); + cancel_delayed_work_sync(&pcr->carddet_work); mutex_lock(&pcr->pcr_mutex); rtsx_pci_power_off(pcr, HOST_ENTER_S3); - device_wakeup_disable(dev_d); - mutex_unlock(&pcr->pcr_mutex); return 0; } @@ -1683,15 +1678,12 @@ static int __maybe_unused rtsx_pci_suspend(struct device *dev_d) static int __maybe_unused rtsx_pci_resume(struct device *dev_d) { struct pci_dev *pcidev = to_pci_dev(dev_d); - struct pcr_handle *handle; - struct rtsx_pcr *pcr; + struct pcr_handle *handle = pci_get_drvdata(pcidev); + struct rtsx_pcr *pcr = handle->pcr; int ret = 0; dev_dbg(&(pcidev->dev), "--> %s\n", __func__); - handle = pci_get_drvdata(pcidev); - pcr = handle->pcr; - mutex_lock(&pcr->pcr_mutex); ret = rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00); @@ -1711,13 +1703,11 @@ out: static void rtsx_pci_shutdown(struct pci_dev *pcidev) { - struct pcr_handle *handle; - struct rtsx_pcr *pcr; + struct pcr_handle *handle = pci_get_drvdata(pcidev); + struct rtsx_pcr *pcr = handle->pcr; dev_dbg(&(pcidev->dev), "--> %s\n", __func__); - handle = pci_get_drvdata(pcidev); - pcr = handle->pcr; rtsx_pci_power_off(pcr, HOST_ENTER_S1); pci_disable_device(pcidev); @@ -1756,11 +1746,8 @@ static int rtsx_pci_runtime_idle(struct device *device) static int rtsx_pci_runtime_suspend(struct device *device) { struct pci_dev *pcidev = to_pci_dev(device); - struct pcr_handle *handle; - struct rtsx_pcr *pcr; - - handle = pci_get_drvdata(pcidev); - pcr = handle->pcr; + struct pcr_handle *handle = pci_get_drvdata(pcidev); + struct rtsx_pcr *pcr = handle->pcr; dev_dbg(device, "--> %s\n", __func__); @@ -1786,9 +1773,6 @@ static int rtsx_pci_runtime_resume(struct device *device) rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00); - if (pcr->ops->fetch_vendor_settings) - pcr->ops->fetch_vendor_settings(pcr); - rtsx_pci_init_hw(pcr); if (pcr->slots[RTSX_SD_CARD].p_dev != NULL) { -- cgit v1.3.1 From 71732e24609b5a7af96efc89aebde55f76c1de3e Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Tue, 25 Jan 2022 13:50:09 +0800 Subject: misc: rtsx: Quiesce rts5249 on system suspend Set more registers in force_power_down callback to avoid S3 wakeup from hotplugging cards. This is originally written by Ricky WU. Link: https://lore.kernel.org/lkml/c4525b4738f94483b9b8f8571fc80646@realtek.com/ Cc: Ricky WU Tested-by: Ricky WU Signed-off-by: Kai-Heng Feng Link: https://lore.kernel.org/r/20220125055010.1866563-4-kai.heng.feng@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cardreader/rtl8411.c | 2 +- drivers/misc/cardreader/rts5209.c | 2 +- drivers/misc/cardreader/rts5228.c | 2 +- drivers/misc/cardreader/rts5229.c | 2 +- drivers/misc/cardreader/rts5249.c | 31 +++++++++++++++++++++++++++++-- drivers/misc/cardreader/rts5261.c | 2 +- drivers/misc/cardreader/rtsx_pcr.c | 14 +++++++------- drivers/misc/cardreader/rtsx_pcr.h | 1 + include/linux/rtsx_pci.h | 2 +- 9 files changed, 43 insertions(+), 15 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/cardreader/rtl8411.c b/drivers/misc/cardreader/rtl8411.c index 4c5621b17a6f..06457e875a90 100644 --- a/drivers/misc/cardreader/rtl8411.c +++ b/drivers/misc/cardreader/rtl8411.c @@ -76,7 +76,7 @@ static void rtl8411b_fetch_vendor_settings(struct rtsx_pcr *pcr) map_sd_drive(rtl8411b_reg_to_sd30_drive_sel_3v3(reg)); } -static void rtl8411_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) +static void rtl8411_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime) { rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07); } diff --git a/drivers/misc/cardreader/rts5209.c b/drivers/misc/cardreader/rts5209.c index 29f5414072bf..52b0a476ba51 100644 --- a/drivers/misc/cardreader/rts5209.c +++ b/drivers/misc/cardreader/rts5209.c @@ -47,7 +47,7 @@ static void rts5209_fetch_vendor_settings(struct rtsx_pcr *pcr) } } -static void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) +static void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime) { rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07); } diff --git a/drivers/misc/cardreader/rts5228.c b/drivers/misc/cardreader/rts5228.c index ffc128278613..ffe3afbf8bfe 100644 --- a/drivers/misc/cardreader/rts5228.c +++ b/drivers/misc/cardreader/rts5228.c @@ -91,7 +91,7 @@ static int rts5228_optimize_phy(struct rtsx_pcr *pcr) return rtsx_pci_write_phy_register(pcr, 0x07, 0x8F40); } -static void rts5228_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) +static void rts5228_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime) { /* Set relink_time to 0 */ rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0); diff --git a/drivers/misc/cardreader/rts5229.c b/drivers/misc/cardreader/rts5229.c index c748eaf1ec1f..b0edd8006d52 100644 --- a/drivers/misc/cardreader/rts5229.c +++ b/drivers/misc/cardreader/rts5229.c @@ -44,7 +44,7 @@ static void rts5229_fetch_vendor_settings(struct rtsx_pcr *pcr) map_sd_drive(rtsx_reg_to_sd30_drive_sel_3v3(reg)); } -static void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) +static void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime) { rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03); } diff --git a/drivers/misc/cardreader/rts5249.c b/drivers/misc/cardreader/rts5249.c index 53f3a1f45c4a..91d240dd68fa 100644 --- a/drivers/misc/cardreader/rts5249.c +++ b/drivers/misc/cardreader/rts5249.c @@ -74,7 +74,8 @@ static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr) pci_read_config_dword(pdev, PCR_SETTING_REG2, ®); pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg); - pcr->rtd3_en = rtsx_reg_to_rtd3_uhsii(reg); + if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A)) + pcr->rtd3_en = rtsx_reg_to_rtd3_uhsii(reg); if (rtsx_check_mmc_support(reg)) pcr->extra_caps |= EXTRA_CAPS_NO_MMC; @@ -143,6 +144,27 @@ static int rts5249_init_from_hw(struct rtsx_pcr *pcr) return 0; } +static void rts52xa_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime) +{ + /* Set relink_time to 0 */ + rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0); + rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, MASK_8_BIT_DEF, 0); + rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3, + RELINK_TIME_MASK, 0); + + rtsx_pci_write_register(pcr, RTS524A_PM_CTRL3, + D3_DELINK_MODE_EN, D3_DELINK_MODE_EN); + + if (!runtime) { + rtsx_pci_write_register(pcr, RTS524A_AUTOLOAD_CFG1, + CD_RESUME_EN_MASK, 0); + rtsx_pci_write_register(pcr, RTS524A_PM_CTRL3, 0x01, 0x00); + rtsx_pci_write_register(pcr, RTS524A_PME_FORCE_CTL, 0x30, 0x20); + } + + rtsx_pci_write_register(pcr, FPDCTL, ALL_POWER_DOWN, ALL_POWER_DOWN); +} + static void rts52xa_save_content_from_efuse(struct rtsx_pcr *pcr) { u8 cnt, sv; @@ -281,8 +303,11 @@ static int rts5249_extra_init_hw(struct rtsx_pcr *pcr) rtsx_pci_send_cmd(pcr, CMD_TIMEOUT_DEF); - if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A)) + if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A)) { rtsx_pci_write_register(pcr, REG_VREF, PWD_SUSPND_EN, PWD_SUSPND_EN); + rtsx_pci_write_register(pcr, RTS524A_AUTOLOAD_CFG1, + CD_RESUME_EN_MASK, CD_RESUME_EN_MASK); + } if (pcr->rtd3_en) { if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A)) { @@ -724,6 +749,7 @@ static const struct pcr_ops rts524a_pcr_ops = { .card_power_on = rtsx_base_card_power_on, .card_power_off = rtsx_base_card_power_off, .switch_output_voltage = rtsx_base_switch_output_voltage, + .force_power_down = rts52xa_force_power_down, .set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0, }; @@ -841,6 +867,7 @@ static const struct pcr_ops rts525a_pcr_ops = { .card_power_on = rts525a_card_power_on, .card_power_off = rtsx_base_card_power_off, .switch_output_voltage = rts525a_switch_output_voltage, + .force_power_down = rts52xa_force_power_down, .set_l1off_cfg_sub_d0 = rts5250_set_l1off_cfg_sub_d0, }; diff --git a/drivers/misc/cardreader/rts5261.c b/drivers/misc/cardreader/rts5261.c index 1fd4e0e50730..64333347c14a 100644 --- a/drivers/misc/cardreader/rts5261.c +++ b/drivers/misc/cardreader/rts5261.c @@ -91,7 +91,7 @@ static void rtsx5261_fetch_vendor_settings(struct rtsx_pcr *pcr) pcr->sd30_drive_sel_3v3 = rts5261_reg_to_sd30_drive_sel_3v3(reg); } -static void rts5261_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) +static void rts5261_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime) { /* Set relink_time to 0 */ rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0); diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c index 3c97d3b50456..1cb6425e8369 100644 --- a/drivers/misc/cardreader/rtsx_pcr.c +++ b/drivers/misc/cardreader/rtsx_pcr.c @@ -1086,7 +1086,7 @@ static void rtsx_pm_power_saving(struct rtsx_pcr *pcr) rtsx_comm_pm_power_saving(pcr); } -static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) +static void rtsx_base_force_power_down(struct rtsx_pcr *pcr) { /* Set relink_time to 0 */ rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0); @@ -1100,7 +1100,7 @@ static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state) rtsx_pci_write_register(pcr, FPDCTL, ALL_POWER_DOWN, ALL_POWER_DOWN); } -static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state) +static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state, bool runtime) { if (pcr->ops->turn_off_led) pcr->ops->turn_off_led(pcr); @@ -1112,9 +1112,9 @@ static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state) rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, pm_state); if (pcr->ops->force_power_down) - pcr->ops->force_power_down(pcr, pm_state); + pcr->ops->force_power_down(pcr, pm_state, runtime); else - rtsx_base_force_power_down(pcr, pm_state); + rtsx_base_force_power_down(pcr); } void rtsx_pci_enable_ocp(struct rtsx_pcr *pcr) @@ -1669,7 +1669,7 @@ static int __maybe_unused rtsx_pci_suspend(struct device *dev_d) mutex_lock(&pcr->pcr_mutex); - rtsx_pci_power_off(pcr, HOST_ENTER_S3); + rtsx_pci_power_off(pcr, HOST_ENTER_S3, false); mutex_unlock(&pcr->pcr_mutex); return 0; @@ -1708,7 +1708,7 @@ static void rtsx_pci_shutdown(struct pci_dev *pcidev) dev_dbg(&(pcidev->dev), "--> %s\n", __func__); - rtsx_pci_power_off(pcr, HOST_ENTER_S1); + rtsx_pci_power_off(pcr, HOST_ENTER_S1, false); pci_disable_device(pcidev); free_irq(pcr->irq, (void *)pcr); @@ -1754,7 +1754,7 @@ static int rtsx_pci_runtime_suspend(struct device *device) cancel_delayed_work_sync(&pcr->carddet_work); mutex_lock(&pcr->pcr_mutex); - rtsx_pci_power_off(pcr, HOST_ENTER_S3); + rtsx_pci_power_off(pcr, HOST_ENTER_S3, true); mutex_unlock(&pcr->pcr_mutex); diff --git a/drivers/misc/cardreader/rtsx_pcr.h b/drivers/misc/cardreader/rtsx_pcr.h index daf057c4eea6..aa0ebd667227 100644 --- a/drivers/misc/cardreader/rtsx_pcr.h +++ b/drivers/misc/cardreader/rtsx_pcr.h @@ -25,6 +25,7 @@ #define REG_EFUSE_POWEROFF 0x00 #define RTS5250_CLK_CFG3 0xFF79 #define RTS525A_CFG_MEM_PD 0xF0 +#define RTS524A_AUTOLOAD_CFG1 0xFF7C #define RTS524A_PM_CTRL3 0xFF7E #define RTS525A_BIOS_CFG 0xFF2D #define RTS525A_LOAD_BIOS_FLAG 0x01 diff --git a/include/linux/rtsx_pci.h b/include/linux/rtsx_pci.h index 89b7d34e25b6..3d780b44e678 100644 --- a/include/linux/rtsx_pci.h +++ b/include/linux/rtsx_pci.h @@ -1095,7 +1095,7 @@ struct pcr_ops { unsigned int (*cd_deglitch)(struct rtsx_pcr *pcr); int (*conv_clk_and_div_n)(int clk, int dir); void (*fetch_vendor_settings)(struct rtsx_pcr *pcr); - void (*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state); + void (*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state, bool runtime); void (*stop_cmd)(struct rtsx_pcr *pcr); void (*set_aspm)(struct rtsx_pcr *pcr, bool enable); -- cgit v1.3.1 From 710f8af199ee9d72dd87083edd55c5ee250ee6f4 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 18 Jan 2022 10:20:47 -0800 Subject: eeprom: at25: Replace strncpy() with strscpy() Use strscpy() instead of strncpy(), since its use has been deprecated[1]. [1] https://www.kernel.org/doc/html/latest/process/deprecated.html#strncpy-on-nul-terminated-strings Cc: Greg Kroah-Hartman Cc: Andy Shevchenko Cc: Arnd Bergmann Cc: Jiri Prchal Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20220118182047.3385295-1-keescook@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/eeprom/at25.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index c3305bdda69c..ecaae1550cb9 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c @@ -309,7 +309,7 @@ static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip) u32 val; int err; - strncpy(chip->name, "at25", sizeof(chip->name)); + strscpy(chip->name, "at25", sizeof(chip->name)); err = device_property_read_u32(dev, "size", &val); if (err) @@ -370,7 +370,7 @@ static int at25_fram_to_chip(struct device *dev, struct spi_eeprom *chip) u8 id[FM25_ID_LEN]; int i; - strncpy(chip->name, "fm25", sizeof(chip->name)); + strscpy(chip->name, "fm25", sizeof(chip->name)); /* Get ID of chip */ fm25_aux_read(at25, id, FM25_RDID, FM25_ID_LEN); -- cgit v1.3.1 From f396ededbd8bf5911d588b683a3ce335844b7c89 Mon Sep 17 00:00:00 2001 From: David Brazdil Date: Wed, 26 Jan 2022 23:12:37 +0000 Subject: misc: open-dice: Add driver to expose DICE data to userspace Open Profile for DICE is an open protocol for measured boot compatible with the Trusted Computing Group's Device Identifier Composition Engine (DICE) specification. The generated Compound Device Identifier (CDI) certificates represent the hardware/software combination measured by DICE, and can be used for remote attestation and sealing. Add a driver that exposes reserved memory regions populated by firmware with DICE CDIs and exposes them to userspace via a character device. Userspace obtains the memory region's size from read() and calls mmap() to create a mapping of the memory region in its address space. The mapping is not allowed to be write+shared, giving userspace a guarantee that the data were not overwritten by another process. Userspace can also call write(), which triggers a wipe of the DICE data by the driver. Because both the kernel and userspace mappings use write-combine semantics, all clients observe the memory as zeroed after the syscall has returned. Cc: Andrew Scull Cc: Will Deacon Acked-by: Rob Herring Signed-off-by: David Brazdil Link: https://lore.kernel.org/r/20220126231237.529308-3-dbrazdil@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/Kconfig | 12 +++ drivers/misc/Makefile | 1 + drivers/misc/open-dice.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/of/platform.c | 1 + 4 files changed, 222 insertions(+) create mode 100644 drivers/misc/open-dice.c (limited to 'drivers/misc') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 0f5a49fc7c9e..a2b26426efba 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -470,6 +470,18 @@ config HISI_HIKEY_USB switching between the dual-role USB-C port and the USB-A host ports using only one USB controller. +config OPEN_DICE + tristate "Open Profile for DICE driver" + depends on OF_RESERVED_MEM + help + This driver exposes a DICE reserved memory region to userspace via + a character device. The memory region contains Compound Device + Identifiers (CDIs) generated by firmware as an output of DICE + measured boot flow. Userspace can use CDIs for remote attestation + and sealing. + + If unsure, say N. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index a086197af544..70e800e9127f 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -59,3 +59,4 @@ obj-$(CONFIG_UACCE) += uacce/ obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o obj-$(CONFIG_HISI_HIKEY_USB) += hisi_hikey_usb.o obj-$(CONFIG_HI6421V600_IRQ) += hi6421v600-irq.o +obj-$(CONFIG_OPEN_DICE) += open-dice.o diff --git a/drivers/misc/open-dice.c b/drivers/misc/open-dice.c new file mode 100644 index 000000000000..c61be3404c6f --- /dev/null +++ b/drivers/misc/open-dice.c @@ -0,0 +1,208 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 - Google LLC + * Author: David Brazdil + * + * Driver for Open Profile for DICE. + * + * This driver takes ownership of a reserved memory region containing data + * generated by the Open Profile for DICE measured boot protocol. The memory + * contents are not interpreted by the kernel but can be mapped into a userspace + * process via a misc device. Userspace can also request a wipe of the memory. + * + * Userspace can access the data with (w/o error handling): + * + * fd = open("/dev/open-dice0", O_RDWR); + * read(fd, &size, sizeof(unsigned long)); + * data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + * write(fd, NULL, 0); // wipe + * close(fd); + */ + +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "open-dice" + +struct open_dice_drvdata { + struct mutex lock; + char name[16]; + struct reserved_mem *rmem; + struct miscdevice misc; +}; + +static inline struct open_dice_drvdata *to_open_dice_drvdata(struct file *filp) +{ + return container_of(filp->private_data, struct open_dice_drvdata, misc); +} + +static int open_dice_wipe(struct open_dice_drvdata *drvdata) +{ + void *kaddr; + + mutex_lock(&drvdata->lock); + kaddr = devm_memremap(drvdata->misc.this_device, drvdata->rmem->base, + drvdata->rmem->size, MEMREMAP_WC); + if (IS_ERR(kaddr)) { + mutex_unlock(&drvdata->lock); + return PTR_ERR(kaddr); + } + + memset(kaddr, 0, drvdata->rmem->size); + devm_memunmap(drvdata->misc.this_device, kaddr); + mutex_unlock(&drvdata->lock); + return 0; +} + +/* + * Copies the size of the reserved memory region to the user-provided buffer. + */ +static ssize_t open_dice_read(struct file *filp, char __user *ptr, size_t len, + loff_t *off) +{ + unsigned long val = to_open_dice_drvdata(filp)->rmem->size; + + return simple_read_from_buffer(ptr, len, off, &val, sizeof(val)); +} + +/* + * Triggers a wipe of the reserved memory region. The user-provided pointer + * is never dereferenced. + */ +static ssize_t open_dice_write(struct file *filp, const char __user *ptr, + size_t len, loff_t *off) +{ + if (open_dice_wipe(to_open_dice_drvdata(filp))) + return -EIO; + + /* Consume the input buffer. */ + return len; +} + +/* + * Creates a mapping of the reserved memory region in user address space. + */ +static int open_dice_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct open_dice_drvdata *drvdata = to_open_dice_drvdata(filp); + + /* Do not allow userspace to modify the underlying data. */ + if ((vma->vm_flags & VM_WRITE) && (vma->vm_flags & VM_SHARED)) + return -EPERM; + + /* Ensure userspace cannot acquire VM_WRITE + VM_SHARED later. */ + if (vma->vm_flags & VM_WRITE) + vma->vm_flags &= ~VM_MAYSHARE; + else if (vma->vm_flags & VM_SHARED) + vma->vm_flags &= ~VM_MAYWRITE; + + /* Create write-combine mapping so all clients observe a wipe. */ + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + vma->vm_flags |= VM_DONTCOPY | VM_DONTDUMP; + return vm_iomap_memory(vma, drvdata->rmem->base, drvdata->rmem->size); +} + +static const struct file_operations open_dice_fops = { + .owner = THIS_MODULE, + .read = open_dice_read, + .write = open_dice_write, + .mmap = open_dice_mmap, +}; + +static int __init open_dice_probe(struct platform_device *pdev) +{ + static unsigned int dev_idx; + struct device *dev = &pdev->dev; + struct reserved_mem *rmem; + struct open_dice_drvdata *drvdata; + int ret; + + rmem = of_reserved_mem_lookup(dev->of_node); + if (!rmem) { + dev_err(dev, "failed to lookup reserved memory\n"); + return -EINVAL; + } + + if (!rmem->size || (rmem->size > ULONG_MAX)) { + dev_err(dev, "invalid memory region size\n"); + return -EINVAL; + } + + if (!PAGE_ALIGNED(rmem->base) || !PAGE_ALIGNED(rmem->size)) { + dev_err(dev, "memory region must be page-aligned\n"); + return -EINVAL; + } + + drvdata = devm_kmalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + *drvdata = (struct open_dice_drvdata){ + .lock = __MUTEX_INITIALIZER(drvdata->lock), + .rmem = rmem, + .misc = (struct miscdevice){ + .parent = dev, + .name = drvdata->name, + .minor = MISC_DYNAMIC_MINOR, + .fops = &open_dice_fops, + .mode = 0600, + }, + }; + + /* Index overflow check not needed, misc_register() will fail. */ + snprintf(drvdata->name, sizeof(drvdata->name), DRIVER_NAME"%u", dev_idx++); + + ret = misc_register(&drvdata->misc); + if (ret) { + dev_err(dev, "failed to register misc device '%s': %d\n", + drvdata->name, ret); + return ret; + } + + platform_set_drvdata(pdev, drvdata); + return 0; +} + +static int open_dice_remove(struct platform_device *pdev) +{ + struct open_dice_drvdata *drvdata = platform_get_drvdata(pdev); + + misc_deregister(&drvdata->misc); + return 0; +} + +static const struct of_device_id open_dice_of_match[] = { + { .compatible = "google,open-dice" }, + {}, +}; + +static struct platform_driver open_dice_driver = { + .remove = open_dice_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = open_dice_of_match, + }, +}; + +static int __init open_dice_init(void) +{ + int ret = platform_driver_probe(&open_dice_driver, open_dice_probe); + + /* DICE regions are optional. Succeed even with zero instances. */ + return (ret == -ENODEV) ? 0 : ret; +} + +static void __exit open_dice_exit(void) +{ + platform_driver_unregister(&open_dice_driver); +} + +module_init(open_dice_init); +module_exit(open_dice_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("David Brazdil "); diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 793350028906..a16b74f32aa9 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -514,6 +514,7 @@ static const struct of_device_id reserved_mem_matches[] = { { .compatible = "qcom,smem" }, { .compatible = "ramoops" }, { .compatible = "nvmem-rmem" }, + { .compatible = "google,open-dice" }, {} }; -- cgit v1.3.1 From 5b3dc949f554379edcb8ef6111aa5ecb78feb798 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 6 Feb 2022 09:39:54 +0100 Subject: misc: alcor_pci: Fix an error handling path A successful ida_simple_get() should be balanced by a corresponding ida_simple_remove(). Add the missing call in the error handling path of the probe. While at it, switch to ida_alloc()/ida_free() instead to ida_simple_get()/ida_simple_remove(). The latter is deprecated and more verbose. Fixes: 4f556bc04e3c ("misc: cardreader: add new Alcor Micro Cardreader PCI driver") Reviewed-by: Oleksij Rempel Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/918a9875b7f67b7f8f123c4446452603422e8c5e.1644136776.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cardreader/alcor_pci.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/cardreader/alcor_pci.c b/drivers/misc/cardreader/alcor_pci.c index de6d44a158bb..3f514d77a843 100644 --- a/drivers/misc/cardreader/alcor_pci.c +++ b/drivers/misc/cardreader/alcor_pci.c @@ -266,7 +266,7 @@ static int alcor_pci_probe(struct pci_dev *pdev, if (!priv) return -ENOMEM; - ret = ida_simple_get(&alcor_pci_idr, 0, 0, GFP_KERNEL); + ret = ida_alloc(&alcor_pci_idr, GFP_KERNEL); if (ret < 0) return ret; priv->id = ret; @@ -280,7 +280,8 @@ static int alcor_pci_probe(struct pci_dev *pdev, ret = pci_request_regions(pdev, DRV_NAME_ALCOR_PCI); if (ret) { dev_err(&pdev->dev, "Cannot request region\n"); - return -ENOMEM; + ret = -ENOMEM; + goto error_free_ida; } if (!(pci_resource_flags(pdev, bar) & IORESOURCE_MEM)) { @@ -324,6 +325,8 @@ static int alcor_pci_probe(struct pci_dev *pdev, error_release_regions: pci_release_regions(pdev); +error_free_ida: + ida_free(&alcor_pci_idr, priv->id); return ret; } @@ -337,7 +340,7 @@ static void alcor_pci_remove(struct pci_dev *pdev) mfd_remove_devices(&pdev->dev); - ida_simple_remove(&alcor_pci_idr, priv->id); + ida_free(&alcor_pci_idr, priv->id); pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); -- cgit v1.3.1 From e283a0e8b7ea83915e988ed059384af166b444c0 Mon Sep 17 00:00:00 2001 From: Jorgen Hansen Date: Mon, 7 Feb 2022 02:27:19 -0800 Subject: VMCI: dma dg: add MMIO access to registers Detect the support for MMIO access through examination of the length of the region requested in BAR1. If it is 256KB, the VMCI device supports MMIO access to registers. If MMIO access is supported, map the area of the region used for MMIO access (64KB size at offset 128KB). Add wrapper functions for accessing 32 bit register accesses through either MMIO or IO ports based on device configuration. Sending and receiving datagrams through iowrite8_rep/ioread8_rep is left unchanged for now, and will be addressed in a later change. Reviewed-by: Vishnu Dasa Signed-off-by: Jorgen Hansen Link: https://lore.kernel.org/r/20220207102725.2742-3-jhansen@vmware.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_guest.c | 67 +++++++++++++++++++++++++++----------- include/linux/vmw_vmci_defs.h | 12 +++++++ 2 files changed, 60 insertions(+), 19 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c index 1018dc77269d..d30d66258e52 100644 --- a/drivers/misc/vmw_vmci/vmci_guest.c +++ b/drivers/misc/vmw_vmci/vmci_guest.c @@ -45,6 +45,7 @@ static u32 vm_context_id = VMCI_INVALID_ID; struct vmci_guest_device { struct device *dev; /* PCI device we are attached to */ void __iomem *iobase; + void __iomem *mmio_base; bool exclusive_vectors; @@ -89,6 +90,21 @@ u32 vmci_get_vm_context_id(void) return vm_context_id; } +static unsigned int vmci_read_reg(struct vmci_guest_device *dev, u32 reg) +{ + if (dev->mmio_base != NULL) + return readl(dev->mmio_base + reg); + return ioread32(dev->iobase + reg); +} + +static void vmci_write_reg(struct vmci_guest_device *dev, u32 val, u32 reg) +{ + if (dev->mmio_base != NULL) + writel(val, dev->mmio_base + reg); + else + iowrite32(val, dev->iobase + reg); +} + /* * VM to hypervisor call mechanism. We use the standard VMware naming * convention since shared code is calling this function as well. @@ -116,7 +132,7 @@ int vmci_send_datagram(struct vmci_datagram *dg) if (vmci_dev_g) { iowrite8_rep(vmci_dev_g->iobase + VMCI_DATA_OUT_ADDR, dg, VMCI_DG_SIZE(dg)); - result = ioread32(vmci_dev_g->iobase + VMCI_RESULT_LOW_ADDR); + result = vmci_read_reg(vmci_dev_g, VMCI_RESULT_LOW_ADDR); } else { result = VMCI_ERROR_UNAVAILABLE; } @@ -384,7 +400,7 @@ static irqreturn_t vmci_interrupt(int irq, void *_dev) unsigned int icr; /* Acknowledge interrupt and determine what needs doing. */ - icr = ioread32(dev->iobase + VMCI_ICR_ADDR); + icr = vmci_read_reg(dev, VMCI_ICR_ADDR); if (icr == 0 || icr == ~0) return IRQ_NONE; @@ -429,7 +445,8 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, const struct pci_device_id *id) { struct vmci_guest_device *vmci_dev; - void __iomem *iobase; + void __iomem *iobase = NULL; + void __iomem *mmio_base = NULL; unsigned int capabilities; unsigned int caps_in_use; unsigned long cmd; @@ -445,16 +462,29 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, return error; } - error = pcim_iomap_regions(pdev, 1 << 0, KBUILD_MODNAME); - if (error) { - dev_err(&pdev->dev, "Failed to reserve/map IO regions\n"); - return error; - } + /* + * The VMCI device with mmio access to registers requests 256KB + * for BAR1. If present, driver will use new VMCI device + * functionality for register access and datagram send/recv. + */ - iobase = pcim_iomap_table(pdev)[0]; + if (pci_resource_len(pdev, 1) == VMCI_WITH_MMIO_ACCESS_BAR_SIZE) { + dev_info(&pdev->dev, "MMIO register access is available\n"); + mmio_base = pci_iomap_range(pdev, 1, VMCI_MMIO_ACCESS_OFFSET, + VMCI_MMIO_ACCESS_SIZE); + /* If the map fails, we fall back to IOIO access. */ + if (!mmio_base) + dev_warn(&pdev->dev, "Failed to map MMIO register access\n"); + } - dev_info(&pdev->dev, "Found VMCI PCI device at %#lx, irq %u\n", - (unsigned long)iobase, pdev->irq); + if (!mmio_base) { + error = pcim_iomap_regions(pdev, BIT(0), KBUILD_MODNAME); + if (error) { + dev_err(&pdev->dev, "Failed to reserve/map IO regions\n"); + return error; + } + iobase = pcim_iomap_table(pdev)[0]; + } vmci_dev = devm_kzalloc(&pdev->dev, sizeof(*vmci_dev), GFP_KERNEL); if (!vmci_dev) { @@ -466,6 +496,7 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, vmci_dev->dev = &pdev->dev; vmci_dev->exclusive_vectors = false; vmci_dev->iobase = iobase; + vmci_dev->mmio_base = mmio_base; tasklet_init(&vmci_dev->datagram_tasklet, vmci_dispatch_dgs, (unsigned long)vmci_dev); @@ -490,7 +521,7 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, * * Right now, we need datagrams. There are no fallbacks. */ - capabilities = ioread32(vmci_dev->iobase + VMCI_CAPS_ADDR); + capabilities = vmci_read_reg(vmci_dev, VMCI_CAPS_ADDR); if (!(capabilities & VMCI_CAPS_DATAGRAM)) { dev_err(&pdev->dev, "Device does not support datagrams\n"); error = -ENXIO; @@ -534,7 +565,7 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, dev_info(&pdev->dev, "Using capabilities 0x%x\n", caps_in_use); /* Let the host know which capabilities we intend to use. */ - iowrite32(caps_in_use, vmci_dev->iobase + VMCI_CAPS_ADDR); + vmci_write_reg(vmci_dev, caps_in_use, VMCI_CAPS_ADDR); /* Set up global device so that we can start sending datagrams */ spin_lock_irq(&vmci_dev_spinlock); @@ -630,11 +661,10 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, cmd = VMCI_IMR_DATAGRAM; if (caps_in_use & VMCI_CAPS_NOTIFICATIONS) cmd |= VMCI_IMR_NOTIFICATION; - iowrite32(cmd, vmci_dev->iobase + VMCI_IMR_ADDR); + vmci_write_reg(vmci_dev, cmd, VMCI_IMR_ADDR); /* Enable interrupts. */ - iowrite32(VMCI_CONTROL_INT_ENABLE, - vmci_dev->iobase + VMCI_CONTROL_ADDR); + vmci_write_reg(vmci_dev, VMCI_CONTROL_INT_ENABLE, VMCI_CONTROL_ADDR); pci_set_drvdata(pdev, vmci_dev); @@ -657,8 +687,7 @@ err_disable_msi: err_remove_bitmap: if (vmci_dev->notification_bitmap) { - iowrite32(VMCI_CONTROL_RESET, - vmci_dev->iobase + VMCI_CONTROL_ADDR); + vmci_write_reg(vmci_dev, VMCI_CONTROL_RESET, VMCI_CONTROL_ADDR); dma_free_coherent(&pdev->dev, PAGE_SIZE, vmci_dev->notification_bitmap, vmci_dev->notification_base); @@ -700,7 +729,7 @@ static void vmci_guest_remove_device(struct pci_dev *pdev) spin_unlock_irq(&vmci_dev_spinlock); dev_dbg(&pdev->dev, "Resetting vmci device\n"); - iowrite32(VMCI_CONTROL_RESET, vmci_dev->iobase + VMCI_CONTROL_ADDR); + vmci_write_reg(vmci_dev, VMCI_CONTROL_RESET, VMCI_CONTROL_ADDR); /* * Free IRQ and then disable MSI/MSI-X as appropriate. For diff --git a/include/linux/vmw_vmci_defs.h b/include/linux/vmw_vmci_defs.h index 9911ecfc18ba..8fc00e2685cf 100644 --- a/include/linux/vmw_vmci_defs.h +++ b/include/linux/vmw_vmci_defs.h @@ -82,6 +82,18 @@ enum { */ #define VMCI_MAX_PINNED_QP_MEMORY ((size_t)(32 * 1024)) +/* + * The version of the VMCI device that supports MMIO access to registers + * requests 256KB for BAR1 whereas the version of VMCI that supports + * MSI/MSI-X only requests 8KB. The layout of the larger 256KB region is: + * - the first 128KB are used for MSI/MSI-X. + * - the following 64KB are used for MMIO register access. + * - the remaining 64KB are unused. + */ +#define VMCI_WITH_MMIO_ACCESS_BAR_SIZE ((size_t)(256 * 1024)) +#define VMCI_MMIO_ACCESS_OFFSET ((size_t)(128 * 1024)) +#define VMCI_MMIO_ACCESS_SIZE ((size_t)(64 * 1024)) + /* * We have a fixed set of resource IDs available in the VMX. * This allows us to have a very simple implementation since we statically -- cgit v1.3.1 From eed2298d936087a1c85e0fa6f7170028e4f4fded Mon Sep 17 00:00:00 2001 From: Jorgen Hansen Date: Mon, 7 Feb 2022 02:27:20 -0800 Subject: VMCI: dma dg: detect DMA datagram capability Detect the VMCI DMA datagram capability, and if present, ack it to the device. Reviewed-by: Vishnu Dasa Signed-off-by: Jorgen Hansen Link: https://lore.kernel.org/r/20220207102725.2742-4-jhansen@vmware.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_guest.c | 11 +++++++++++ include/linux/vmw_vmci_defs.h | 1 + 2 files changed, 12 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c index d30d66258e52..b93afe7f7119 100644 --- a/drivers/misc/vmw_vmci/vmci_guest.c +++ b/drivers/misc/vmw_vmci/vmci_guest.c @@ -562,6 +562,17 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, } } + if (mmio_base != NULL) { + if (capabilities & VMCI_CAPS_DMA_DATAGRAM) { + caps_in_use |= VMCI_CAPS_DMA_DATAGRAM; + } else { + dev_err(&pdev->dev, + "Missing capability: VMCI_CAPS_DMA_DATAGRAM\n"); + error = -ENXIO; + goto err_free_data_buffer; + } + } + dev_info(&pdev->dev, "Using capabilities 0x%x\n", caps_in_use); /* Let the host know which capabilities we intend to use. */ diff --git a/include/linux/vmw_vmci_defs.h b/include/linux/vmw_vmci_defs.h index 8fc00e2685cf..1ce2cffdc3ae 100644 --- a/include/linux/vmw_vmci_defs.h +++ b/include/linux/vmw_vmci_defs.h @@ -39,6 +39,7 @@ #define VMCI_CAPS_DATAGRAM BIT(2) #define VMCI_CAPS_NOTIFICATIONS BIT(3) #define VMCI_CAPS_PPN64 BIT(4) +#define VMCI_CAPS_DMA_DATAGRAM BIT(5) /* Interrupt Cause register bits. */ #define VMCI_ICR_DATAGRAM BIT(0) -- cgit v1.3.1 From 8cb520bea1470ca205980fbf030ed1f472f4af2f Mon Sep 17 00:00:00 2001 From: Jorgen Hansen Date: Mon, 7 Feb 2022 02:27:21 -0800 Subject: VMCI: dma dg: set OS page size Tell the device the page size used by the OS. Reviewed-by: Vishnu Dasa Signed-off-by: Jorgen Hansen Link: https://lore.kernel.org/r/20220207102725.2742-5-jhansen@vmware.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_guest.c | 4 ++++ include/linux/vmw_vmci_defs.h | 1 + 2 files changed, 5 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c index b93afe7f7119..ced187e7ac08 100644 --- a/drivers/misc/vmw_vmci/vmci_guest.c +++ b/drivers/misc/vmw_vmci/vmci_guest.c @@ -578,6 +578,10 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, /* Let the host know which capabilities we intend to use. */ vmci_write_reg(vmci_dev, caps_in_use, VMCI_CAPS_ADDR); + /* Let the device know the size for pages passed down. */ + if (caps_in_use & VMCI_CAPS_DMA_DATAGRAM) + vmci_write_reg(vmci_dev, PAGE_SHIFT, VMCI_GUEST_PAGE_SHIFT); + /* Set up global device so that we can start sending datagrams */ spin_lock_irq(&vmci_dev_spinlock); vmci_dev_g = vmci_dev; diff --git a/include/linux/vmw_vmci_defs.h b/include/linux/vmw_vmci_defs.h index 1ce2cffdc3ae..4167779469fd 100644 --- a/include/linux/vmw_vmci_defs.h +++ b/include/linux/vmw_vmci_defs.h @@ -21,6 +21,7 @@ #define VMCI_CAPS_ADDR 0x18 #define VMCI_RESULT_LOW_ADDR 0x1c #define VMCI_RESULT_HIGH_ADDR 0x20 +#define VMCI_GUEST_PAGE_SHIFT 0x34 /* Max number of devices. */ #define VMCI_MAX_DEVICES 1 -- cgit v1.3.1 From cc68f2177fcbfe2dbe5e9514789b96ba5995ec1e Mon Sep 17 00:00:00 2001 From: Jorgen Hansen Date: Mon, 7 Feb 2022 02:27:22 -0800 Subject: VMCI: dma dg: register dummy IRQ handlers for DMA datagrams Register dummy interrupt handlers for DMA datagrams in preparation for DMA datagram receive operations. Reviewed-by: Vishnu Dasa Signed-off-by: Jorgen Hansen Link: https://lore.kernel.org/r/20220207102725.2742-6-jhansen@vmware.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_guest.c | 42 +++++++++++++++++++++++++++++++++++--- include/linux/vmw_vmci_defs.h | 14 +++++++++++-- 2 files changed, 51 insertions(+), 5 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c index ced187e7ac08..acef19c562b3 100644 --- a/drivers/misc/vmw_vmci/vmci_guest.c +++ b/drivers/misc/vmw_vmci/vmci_guest.c @@ -414,6 +414,9 @@ static irqreturn_t vmci_interrupt(int irq, void *_dev) icr &= ~VMCI_ICR_NOTIFICATION; } + if (icr & VMCI_ICR_DMA_DATAGRAM) + icr &= ~VMCI_ICR_DMA_DATAGRAM; + if (icr != 0) dev_warn(dev->dev, "Ignoring unknown interrupt cause (%d)\n", @@ -438,6 +441,16 @@ static irqreturn_t vmci_interrupt_bm(int irq, void *_dev) return IRQ_HANDLED; } +/* + * Interrupt handler for MSI-X interrupt vector VMCI_INTR_DMA_DATAGRAM, + * which is for the completion of a DMA datagram send or receive operation. + * Will only get called if we are using MSI-X with exclusive vectors. + */ +static irqreturn_t vmci_interrupt_dma_datagram(int irq, void *_dev) +{ + return IRQ_HANDLED; +} + /* * Most of the initialization at module load time is done here. */ @@ -447,6 +460,7 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, struct vmci_guest_device *vmci_dev; void __iomem *iobase = NULL; void __iomem *mmio_base = NULL; + unsigned int num_irq_vectors; unsigned int capabilities; unsigned int caps_in_use; unsigned long cmd; @@ -627,8 +641,12 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, * Enable interrupts. Try MSI-X first, then MSI, and then fallback on * legacy interrupts. */ - error = pci_alloc_irq_vectors(pdev, VMCI_MAX_INTRS, VMCI_MAX_INTRS, - PCI_IRQ_MSIX); + if (vmci_dev->mmio_base != NULL) + num_irq_vectors = VMCI_MAX_INTRS; + else + num_irq_vectors = VMCI_MAX_INTRS_NOTIFICATION; + error = pci_alloc_irq_vectors(pdev, num_irq_vectors, num_irq_vectors, + PCI_IRQ_MSIX); if (error < 0) { error = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX | PCI_IRQ_MSI | PCI_IRQ_LEGACY); @@ -666,6 +684,17 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, pci_irq_vector(pdev, 1), error); goto err_free_irq; } + if (caps_in_use & VMCI_CAPS_DMA_DATAGRAM) { + error = request_irq(pci_irq_vector(pdev, 2), + vmci_interrupt_dma_datagram, + 0, KBUILD_MODNAME, vmci_dev); + if (error) { + dev_err(&pdev->dev, + "Failed to allocate irq %u: %d\n", + pci_irq_vector(pdev, 2), error); + goto err_free_bm_irq; + } + } } dev_dbg(&pdev->dev, "Registered device\n"); @@ -676,6 +705,8 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, cmd = VMCI_IMR_DATAGRAM; if (caps_in_use & VMCI_CAPS_NOTIFICATIONS) cmd |= VMCI_IMR_NOTIFICATION; + if (caps_in_use & VMCI_CAPS_DMA_DATAGRAM) + cmd |= VMCI_IMR_DMA_DATAGRAM; vmci_write_reg(vmci_dev, cmd, VMCI_IMR_ADDR); /* Enable interrupts. */ @@ -686,6 +717,8 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, vmci_call_vsock_callback(false); return 0; +err_free_bm_irq: + free_irq(pci_irq_vector(pdev, 1), vmci_dev); err_free_irq: free_irq(pci_irq_vector(pdev, 0), vmci_dev); tasklet_kill(&vmci_dev->datagram_tasklet); @@ -751,8 +784,11 @@ static void vmci_guest_remove_device(struct pci_dev *pdev) * MSI-X, we might have multiple vectors, each with their own * IRQ, which we must free too. */ - if (vmci_dev->exclusive_vectors) + if (vmci_dev->exclusive_vectors) { free_irq(pci_irq_vector(pdev, 1), vmci_dev); + if (vmci_dev->mmio_base != NULL) + free_irq(pci_irq_vector(pdev, 2), vmci_dev); + } free_irq(pci_irq_vector(pdev, 0), vmci_dev); pci_free_irq_vectors(pdev); diff --git a/include/linux/vmw_vmci_defs.h b/include/linux/vmw_vmci_defs.h index 4167779469fd..2b70c024dacb 100644 --- a/include/linux/vmw_vmci_defs.h +++ b/include/linux/vmw_vmci_defs.h @@ -45,13 +45,22 @@ /* Interrupt Cause register bits. */ #define VMCI_ICR_DATAGRAM BIT(0) #define VMCI_ICR_NOTIFICATION BIT(1) +#define VMCI_ICR_DMA_DATAGRAM BIT(2) /* Interrupt Mask register bits. */ #define VMCI_IMR_DATAGRAM BIT(0) #define VMCI_IMR_NOTIFICATION BIT(1) +#define VMCI_IMR_DMA_DATAGRAM BIT(2) -/* Maximum MSI/MSI-X interrupt vectors in the device. */ -#define VMCI_MAX_INTRS 2 +/* + * Maximum MSI/MSI-X interrupt vectors in the device. + * If VMCI_CAPS_DMA_DATAGRAM is supported by the device, + * VMCI_MAX_INTRS_DMA_DATAGRAM vectors are available, + * otherwise only VMCI_MAX_INTRS_NOTIFICATION. + */ +#define VMCI_MAX_INTRS_NOTIFICATION 2 +#define VMCI_MAX_INTRS_DMA_DATAGRAM 3 +#define VMCI_MAX_INTRS VMCI_MAX_INTRS_DMA_DATAGRAM /* * Supported interrupt vectors. There is one for each ICR value above, @@ -60,6 +69,7 @@ enum { VMCI_INTR_DATAGRAM = 0, VMCI_INTR_NOTIFICATION = 1, + VMCI_INTR_DMA_DATAGRAM = 2, }; /* -- cgit v1.3.1 From 5ee109828e73bbe4213c373988608d8f33e03d78 Mon Sep 17 00:00:00 2001 From: Jorgen Hansen Date: Mon, 7 Feb 2022 02:27:23 -0800 Subject: VMCI: dma dg: allocate send and receive buffers for DMA datagrams If DMA datagrams are used, allocate send and receive buffers in coherent DMA memory. This is done in preparation for the send and receive datagram operations, where the buffers are used for the exchange of data between driver and device. Reviewed-by: Vishnu Dasa Signed-off-by: Jorgen Hansen Link: https://lore.kernel.org/r/20220207102725.2742-7-jhansen@vmware.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_guest.c | 71 +++++++++++++++++++++++++++++++++----- include/linux/vmw_vmci_defs.h | 4 +++ 2 files changed, 66 insertions(+), 9 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c index acef19c562b3..36eade15ba87 100644 --- a/drivers/misc/vmw_vmci/vmci_guest.c +++ b/drivers/misc/vmw_vmci/vmci_guest.c @@ -31,6 +31,12 @@ #define VMCI_UTIL_NUM_RESOURCES 1 +/* + * Datagram buffers for DMA send/receive must accommodate at least + * a maximum sized datagram and the header. + */ +#define VMCI_DMA_DG_BUFFER_SIZE (VMCI_MAX_DG_SIZE + PAGE_SIZE) + static bool vmci_disable_msi; module_param_named(disable_msi, vmci_disable_msi, bool, 0); MODULE_PARM_DESC(disable_msi, "Disable MSI use in driver - (default=0)"); @@ -53,6 +59,9 @@ struct vmci_guest_device { struct tasklet_struct bm_tasklet; void *data_buffer; + dma_addr_t data_buffer_base; + void *tx_buffer; + dma_addr_t tx_buffer_base; void *notification_bitmap; dma_addr_t notification_base; }; @@ -451,6 +460,24 @@ static irqreturn_t vmci_interrupt_dma_datagram(int irq, void *_dev) return IRQ_HANDLED; } +static void vmci_free_dg_buffers(struct vmci_guest_device *vmci_dev) +{ + if (vmci_dev->mmio_base != NULL) { + if (vmci_dev->tx_buffer != NULL) + dma_free_coherent(vmci_dev->dev, + VMCI_DMA_DG_BUFFER_SIZE, + vmci_dev->tx_buffer, + vmci_dev->tx_buffer_base); + if (vmci_dev->data_buffer != NULL) + dma_free_coherent(vmci_dev->dev, + VMCI_DMA_DG_BUFFER_SIZE, + vmci_dev->data_buffer, + vmci_dev->data_buffer_base); + } else { + vfree(vmci_dev->data_buffer); + } +} + /* * Most of the initialization at module load time is done here. */ @@ -517,11 +544,27 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, tasklet_init(&vmci_dev->bm_tasklet, vmci_process_bitmap, (unsigned long)vmci_dev); - vmci_dev->data_buffer = vmalloc(VMCI_MAX_DG_SIZE); + if (mmio_base != NULL) { + vmci_dev->tx_buffer = dma_alloc_coherent(&pdev->dev, VMCI_DMA_DG_BUFFER_SIZE, + &vmci_dev->tx_buffer_base, + GFP_KERNEL); + if (!vmci_dev->tx_buffer) { + dev_err(&pdev->dev, + "Can't allocate memory for datagram tx buffer\n"); + return -ENOMEM; + } + + vmci_dev->data_buffer = dma_alloc_coherent(&pdev->dev, VMCI_DMA_DG_BUFFER_SIZE, + &vmci_dev->data_buffer_base, + GFP_KERNEL); + } else { + vmci_dev->data_buffer = vmalloc(VMCI_MAX_DG_SIZE); + } if (!vmci_dev->data_buffer) { dev_err(&pdev->dev, "Can't allocate memory for datagram buffer\n"); - return -ENOMEM; + error = -ENOMEM; + goto err_free_data_buffers; } pci_set_master(pdev); /* To enable queue_pair functionality. */ @@ -539,7 +582,7 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, if (!(capabilities & VMCI_CAPS_DATAGRAM)) { dev_err(&pdev->dev, "Device does not support datagrams\n"); error = -ENXIO; - goto err_free_data_buffer; + goto err_free_data_buffers; } caps_in_use = VMCI_CAPS_DATAGRAM; @@ -583,7 +626,7 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, dev_err(&pdev->dev, "Missing capability: VMCI_CAPS_DMA_DATAGRAM\n"); error = -ENXIO; - goto err_free_data_buffer; + goto err_free_data_buffers; } } @@ -592,10 +635,17 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, /* Let the host know which capabilities we intend to use. */ vmci_write_reg(vmci_dev, caps_in_use, VMCI_CAPS_ADDR); - /* Let the device know the size for pages passed down. */ - if (caps_in_use & VMCI_CAPS_DMA_DATAGRAM) + if (caps_in_use & VMCI_CAPS_DMA_DATAGRAM) { + /* Let the device know the size for pages passed down. */ vmci_write_reg(vmci_dev, PAGE_SHIFT, VMCI_GUEST_PAGE_SHIFT); + /* Configure the high order parts of the data in/out buffers. */ + vmci_write_reg(vmci_dev, upper_32_bits(vmci_dev->data_buffer_base), + VMCI_DATA_IN_HIGH_ADDR); + vmci_write_reg(vmci_dev, upper_32_bits(vmci_dev->tx_buffer_base), + VMCI_DATA_OUT_HIGH_ADDR); + } + /* Set up global device so that we can start sending datagrams */ spin_lock_irq(&vmci_dev_spinlock); vmci_dev_g = vmci_dev; @@ -747,8 +797,8 @@ err_remove_vmci_dev_g: vmci_dev_g = NULL; spin_unlock_irq(&vmci_dev_spinlock); -err_free_data_buffer: - vfree(vmci_dev->data_buffer); +err_free_data_buffers: + vmci_free_dg_buffers(vmci_dev); /* The rest are managed resources and will be freed by PCI core */ return error; @@ -806,7 +856,10 @@ static void vmci_guest_remove_device(struct pci_dev *pdev) vmci_dev->notification_base); } - vfree(vmci_dev->data_buffer); + vmci_free_dg_buffers(vmci_dev); + + if (vmci_dev->mmio_base != NULL) + pci_iounmap(pdev, vmci_dev->mmio_base); /* The rest are managed resources and will be freed by PCI core */ } diff --git a/include/linux/vmw_vmci_defs.h b/include/linux/vmw_vmci_defs.h index 2b70c024dacb..8bc37d8244a8 100644 --- a/include/linux/vmw_vmci_defs.h +++ b/include/linux/vmw_vmci_defs.h @@ -21,6 +21,10 @@ #define VMCI_CAPS_ADDR 0x18 #define VMCI_RESULT_LOW_ADDR 0x1c #define VMCI_RESULT_HIGH_ADDR 0x20 +#define VMCI_DATA_OUT_LOW_ADDR 0x24 +#define VMCI_DATA_OUT_HIGH_ADDR 0x28 +#define VMCI_DATA_IN_LOW_ADDR 0x2c +#define VMCI_DATA_IN_HIGH_ADDR 0x30 #define VMCI_GUEST_PAGE_SHIFT 0x34 /* Max number of devices. */ -- cgit v1.3.1 From 22aa5c7f323022477b70e044eb00e6bfea9498e8 Mon Sep 17 00:00:00 2001 From: Jorgen Hansen Date: Mon, 7 Feb 2022 02:27:24 -0800 Subject: VMCI: dma dg: add support for DMA datagrams sends Use DMA based send operation from the transmit buffer instead of the iowrite8_rep based datagram send when DMA datagrams are supported. The outgoing datagram is sent as inline data in the VMCI transmit buffer. Once the header has been configured, the send is initiated by writing the lower 32 bit of the buffer base address to the VMCI_DATA_OUT_LOW_ADDR register. Only then will the device process the header and the datagram itself. Following that, the driver busy waits (it isn't possible to sleep on the send path) for the header busy flag to change - indicating that the send is complete. Reviewed-by: Vishnu Dasa Signed-off-by: Jorgen Hansen Link: https://lore.kernel.org/r/20220207102725.2742-8-jhansen@vmware.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_guest.c | 45 ++++++++++++++++++++++++++++++++++++-- include/linux/vmw_vmci_defs.h | 34 ++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c index 36eade15ba87..bf524217914e 100644 --- a/drivers/misc/vmw_vmci/vmci_guest.c +++ b/drivers/misc/vmw_vmci/vmci_guest.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -114,6 +115,47 @@ static void vmci_write_reg(struct vmci_guest_device *dev, u32 val, u32 reg) iowrite32(val, dev->iobase + reg); } +static int vmci_write_data(struct vmci_guest_device *dev, + struct vmci_datagram *dg) +{ + int result; + + if (dev->mmio_base != NULL) { + struct vmci_data_in_out_header *buffer_header = dev->tx_buffer; + u8 *dg_out_buffer = (u8 *)(buffer_header + 1); + + if (VMCI_DG_SIZE(dg) > VMCI_MAX_DG_SIZE) + return VMCI_ERROR_INVALID_ARGS; + + /* + * Initialize send buffer with outgoing datagram + * and set up header for inline data. Device will + * not access buffer asynchronously - only after + * the write to VMCI_DATA_OUT_LOW_ADDR. + */ + memcpy(dg_out_buffer, dg, VMCI_DG_SIZE(dg)); + buffer_header->opcode = 0; + buffer_header->size = VMCI_DG_SIZE(dg); + buffer_header->busy = 1; + + vmci_write_reg(dev, lower_32_bits(dev->tx_buffer_base), + VMCI_DATA_OUT_LOW_ADDR); + + /* Caller holds a spinlock, so cannot block. */ + spin_until_cond(buffer_header->busy == 0); + + result = vmci_read_reg(vmci_dev_g, VMCI_RESULT_LOW_ADDR); + if (result == VMCI_SUCCESS) + result = (int)buffer_header->result; + } else { + iowrite8_rep(dev->iobase + VMCI_DATA_OUT_ADDR, + dg, VMCI_DG_SIZE(dg)); + result = vmci_read_reg(vmci_dev_g, VMCI_RESULT_LOW_ADDR); + } + + return result; +} + /* * VM to hypervisor call mechanism. We use the standard VMware naming * convention since shared code is calling this function as well. @@ -139,8 +181,7 @@ int vmci_send_datagram(struct vmci_datagram *dg) spin_lock_irqsave(&vmci_dev_spinlock, flags); if (vmci_dev_g) { - iowrite8_rep(vmci_dev_g->iobase + VMCI_DATA_OUT_ADDR, - dg, VMCI_DG_SIZE(dg)); + vmci_write_data(vmci_dev_g, dg); result = vmci_read_reg(vmci_dev_g, VMCI_RESULT_LOW_ADDR); } else { result = VMCI_ERROR_UNAVAILABLE; diff --git a/include/linux/vmw_vmci_defs.h b/include/linux/vmw_vmci_defs.h index 8bc37d8244a8..6fb663b36f72 100644 --- a/include/linux/vmw_vmci_defs.h +++ b/include/linux/vmw_vmci_defs.h @@ -110,6 +110,40 @@ enum { #define VMCI_MMIO_ACCESS_OFFSET ((size_t)(128 * 1024)) #define VMCI_MMIO_ACCESS_SIZE ((size_t)(64 * 1024)) +/* + * For VMCI devices supporting the VMCI_CAPS_DMA_DATAGRAM capability, the + * sending and receiving of datagrams can be performed using DMA to/from + * a driver allocated buffer. + * Sending and receiving will be handled as follows: + * - when sending datagrams, the driver initializes the buffer where the + * data part will refer to the outgoing VMCI datagram, sets the busy flag + * to 1 and writes the address of the buffer to VMCI_DATA_OUT_HIGH_ADDR + * and VMCI_DATA_OUT_LOW_ADDR. Writing to VMCI_DATA_OUT_LOW_ADDR triggers + * the device processing of the buffer. When the device has processed the + * buffer, it will write the result value to the buffer and then clear the + * busy flag. + * - when receiving datagrams, the driver initializes the buffer where the + * data part will describe the receive buffer, clears the busy flag and + * writes the address of the buffer to VMCI_DATA_IN_HIGH_ADDR and + * VMCI_DATA_IN_LOW_ADDR. Writing to VMCI_DATA_IN_LOW_ADDR triggers the + * device processing of the buffer. The device will copy as many available + * datagrams into the buffer as possible, and then sets the busy flag. + * When the busy flag is set, the driver will process the datagrams in the + * buffer. + */ +struct vmci_data_in_out_header { + uint32_t busy; + uint32_t opcode; + uint32_t size; + uint32_t rsvd; + uint64_t result; +}; + +struct vmci_sg_elem { + uint64_t addr; + uint64_t size; +}; + /* * We have a fixed set of resource IDs available in the VMX. * This allows us to have a very simple implementation since we statically -- cgit v1.3.1 From 463713eb6164b6577f8e91447c7745628215531b Mon Sep 17 00:00:00 2001 From: Jorgen Hansen Date: Mon, 7 Feb 2022 02:27:25 -0800 Subject: VMCI: dma dg: add support for DMA datagrams receive Use the DMA based receive operation instead of the ioread8_rep based datagram receive when DMA datagrams are supported. In the receive operation, configure the header to point to the page aligned VMCI_MAX_DG_SIZE part of the receive buffer using s/g configuration for the header. This ensures that the existing dispatch routine can be used with little modification. Initiate the receive by writing the lower 32 bit of the buffer to the VMCI_DATA_IN_LOW_ADDR register, and wait for the busy flag to be changed by the device using a wait queue. The existing dispatch routine for received datagrams is reused for the DMA datagrams with a few modifications: - the receive buffer is always the maximum size for DMA datagrams (IO ports would try with a shorter buffer first to reduce overhead of the ioread8_rep operation). - for DMA datagrams, datagrams are provided contiguous in the buffer as opposed to IO port datagrams, where they can start on any page boundary Reviewed-by: Vishnu Dasa Signed-off-by: Jorgen Hansen Link: https://lore.kernel.org/r/20220207102725.2742-9-jhansen@vmware.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_guest.c | 103 ++++++++++++++++++++++++++++--------- 1 file changed, 79 insertions(+), 24 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c index bf524217914e..aa61a687b3e2 100644 --- a/drivers/misc/vmw_vmci/vmci_guest.c +++ b/drivers/misc/vmw_vmci/vmci_guest.c @@ -58,6 +58,7 @@ struct vmci_guest_device { struct tasklet_struct datagram_tasklet; struct tasklet_struct bm_tasklet; + struct wait_queue_head inout_wq; void *data_buffer; dma_addr_t data_buffer_base; @@ -115,6 +116,36 @@ static void vmci_write_reg(struct vmci_guest_device *dev, u32 val, u32 reg) iowrite32(val, dev->iobase + reg); } +static void vmci_read_data(struct vmci_guest_device *vmci_dev, + void *dest, size_t size) +{ + if (vmci_dev->mmio_base == NULL) + ioread8_rep(vmci_dev->iobase + VMCI_DATA_IN_ADDR, + dest, size); + else { + /* + * For DMA datagrams, the data_buffer will contain the header on the + * first page, followed by the incoming datagram(s) on the following + * pages. The header uses an S/G element immediately following the + * header on the first page to point to the data area. + */ + struct vmci_data_in_out_header *buffer_header = vmci_dev->data_buffer; + struct vmci_sg_elem *sg_array = (struct vmci_sg_elem *)(buffer_header + 1); + size_t buffer_offset = dest - vmci_dev->data_buffer; + + buffer_header->opcode = 1; + buffer_header->size = 1; + buffer_header->busy = 0; + sg_array[0].addr = vmci_dev->data_buffer_base + buffer_offset; + sg_array[0].size = size; + + vmci_write_reg(vmci_dev, lower_32_bits(vmci_dev->data_buffer_base), + VMCI_DATA_IN_LOW_ADDR); + + wait_event(vmci_dev->inout_wq, buffer_header->busy == 1); + } +} + static int vmci_write_data(struct vmci_guest_device *dev, struct vmci_datagram *dg) { @@ -261,15 +292,17 @@ static int vmci_check_host_caps(struct pci_dev *pdev) } /* - * Reads datagrams from the data in port and dispatches them. We - * always start reading datagrams into only the first page of the - * datagram buffer. If the datagrams don't fit into one page, we - * use the maximum datagram buffer size for the remainder of the - * invocation. This is a simple heuristic for not penalizing - * small datagrams. + * Reads datagrams from the device and dispatches them. For IO port + * based access to the device, we always start reading datagrams into + * only the first page of the datagram buffer. If the datagrams don't + * fit into one page, we use the maximum datagram buffer size for the + * remainder of the invocation. This is a simple heuristic for not + * penalizing small datagrams. For DMA-based datagrams, we always + * use the maximum datagram buffer size, since there is no performance + * penalty for doing so. * * This function assumes that it has exclusive access to the data - * in port for the duration of the call. + * in register(s) for the duration of the call. */ static void vmci_dispatch_dgs(unsigned long data) { @@ -277,23 +310,41 @@ static void vmci_dispatch_dgs(unsigned long data) u8 *dg_in_buffer = vmci_dev->data_buffer; struct vmci_datagram *dg; size_t dg_in_buffer_size = VMCI_MAX_DG_SIZE; - size_t current_dg_in_buffer_size = PAGE_SIZE; + size_t current_dg_in_buffer_size; size_t remaining_bytes; + bool is_io_port = vmci_dev->mmio_base == NULL; BUILD_BUG_ON(VMCI_MAX_DG_SIZE < PAGE_SIZE); - ioread8_rep(vmci_dev->iobase + VMCI_DATA_IN_ADDR, - vmci_dev->data_buffer, current_dg_in_buffer_size); + if (!is_io_port) { + /* For mmio, the first page is used for the header. */ + dg_in_buffer += PAGE_SIZE; + + /* + * For DMA-based datagram operations, there is no performance + * penalty for reading the maximum buffer size. + */ + current_dg_in_buffer_size = VMCI_MAX_DG_SIZE; + } else { + current_dg_in_buffer_size = PAGE_SIZE; + } + vmci_read_data(vmci_dev, dg_in_buffer, current_dg_in_buffer_size); dg = (struct vmci_datagram *)dg_in_buffer; remaining_bytes = current_dg_in_buffer_size; + /* + * Read through the buffer until an invalid datagram header is + * encountered. The exit condition for datagrams read through + * VMCI_DATA_IN_ADDR is a bit more complicated, since a datagram + * can start on any page boundary in the buffer. + */ while (dg->dst.resource != VMCI_INVALID_ID || - remaining_bytes > PAGE_SIZE) { + (is_io_port && remaining_bytes > PAGE_SIZE)) { unsigned dg_in_size; /* - * When the input buffer spans multiple pages, a datagram can - * start on any page boundary in the buffer. + * If using VMCI_DATA_IN_ADDR, skip to the next page + * as a datagram can start on any page boundary. */ if (dg->dst.resource == VMCI_INVALID_ID) { dg = (struct vmci_datagram *)roundup( @@ -343,11 +394,10 @@ static void vmci_dispatch_dgs(unsigned long data) current_dg_in_buffer_size = dg_in_buffer_size; - ioread8_rep(vmci_dev->iobase + - VMCI_DATA_IN_ADDR, - vmci_dev->data_buffer + + vmci_read_data(vmci_dev, + dg_in_buffer + remaining_bytes, - current_dg_in_buffer_size - + current_dg_in_buffer_size - remaining_bytes); } @@ -385,10 +435,8 @@ static void vmci_dispatch_dgs(unsigned long data) current_dg_in_buffer_size = dg_in_buffer_size; for (;;) { - ioread8_rep(vmci_dev->iobase + - VMCI_DATA_IN_ADDR, - vmci_dev->data_buffer, - current_dg_in_buffer_size); + vmci_read_data(vmci_dev, dg_in_buffer, + current_dg_in_buffer_size); if (bytes_to_skip <= current_dg_in_buffer_size) break; @@ -405,8 +453,7 @@ static void vmci_dispatch_dgs(unsigned long data) if (remaining_bytes < VMCI_DG_HEADERSIZE) { /* Get the next batch of datagrams. */ - ioread8_rep(vmci_dev->iobase + VMCI_DATA_IN_ADDR, - vmci_dev->data_buffer, + vmci_read_data(vmci_dev, dg_in_buffer, current_dg_in_buffer_size); dg = (struct vmci_datagram *)dg_in_buffer; remaining_bytes = current_dg_in_buffer_size; @@ -464,8 +511,11 @@ static irqreturn_t vmci_interrupt(int irq, void *_dev) icr &= ~VMCI_ICR_NOTIFICATION; } - if (icr & VMCI_ICR_DMA_DATAGRAM) + + if (icr & VMCI_ICR_DMA_DATAGRAM) { + wake_up_all(&dev->inout_wq); icr &= ~VMCI_ICR_DMA_DATAGRAM; + } if (icr != 0) dev_warn(dev->dev, @@ -498,6 +548,10 @@ static irqreturn_t vmci_interrupt_bm(int irq, void *_dev) */ static irqreturn_t vmci_interrupt_dma_datagram(int irq, void *_dev) { + struct vmci_guest_device *dev = _dev; + + wake_up_all(&dev->inout_wq); + return IRQ_HANDLED; } @@ -584,6 +638,7 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, vmci_dispatch_dgs, (unsigned long)vmci_dev); tasklet_init(&vmci_dev->bm_tasklet, vmci_process_bitmap, (unsigned long)vmci_dev); + init_waitqueue_head(&vmci_dev->inout_wq); if (mmio_base != NULL) { vmci_dev->tx_buffer = dma_alloc_coherent(&pdev->dev, VMCI_DMA_DG_BUFFER_SIZE, -- cgit v1.3.1 From b791da238992436f6269e8743b3bc23305702674 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 24 Feb 2022 21:22:17 +0100 Subject: VMCI: Fix the description of vmci_check_host_caps() vmci_check_host_caps() doesn't return a bool but an int. Fix the description accordingly. Fixes: 782f24453536 ("VMCI: fix error handling path when registering guest driver") Acked-by: Vishnu Dasa Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/c181bec88aab1145d3868d61b7e52d53923f8206.1645734041.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_guest.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c index aa61a687b3e2..1a1858742f75 100644 --- a/drivers/misc/vmw_vmci/vmci_guest.c +++ b/drivers/misc/vmw_vmci/vmci_guest.c @@ -253,9 +253,9 @@ static void vmci_guest_cid_update(u32 sub_id, /* * Verify that the host supports the hypercalls we need. If it does not, - * try to find fallback hypercalls and use those instead. Returns - * true if required hypercalls (or fallback hypercalls) are - * supported by the host, false otherwise. + * try to find fallback hypercalls and use those instead. Returns 0 if + * required hypercalls (or fallback hypercalls) are supported by the host, + * an error code otherwise. */ static int vmci_check_host_caps(struct pci_dev *pdev) { -- cgit v1.3.1 From cc312da2d3af87f183c57b672042c85cfe6f15c2 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 24 Feb 2022 21:22:27 +0100 Subject: VMCI: No need to clear memory after a dma_alloc_coherent() call dma_alloc_coherent() already clear the allocated memory, there is no need to explicitly call memset(). This saves a few cycles and a few lines of code. Acked-by: Vishnu Dasa Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/3e8c0bfaa77500e22d6c90f249da1c53dbae716e.1645734041.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_guest.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c index 1a1858742f75..02d4722d8474 100644 --- a/drivers/misc/vmw_vmci/vmci_guest.c +++ b/drivers/misc/vmw_vmci/vmci_guest.c @@ -706,13 +706,11 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, vmci_dev->notification_bitmap = dma_alloc_coherent( &pdev->dev, PAGE_SIZE, &vmci_dev->notification_base, GFP_KERNEL); - if (!vmci_dev->notification_bitmap) { + if (!vmci_dev->notification_bitmap) dev_warn(&pdev->dev, "Unable to allocate notification bitmap\n"); - } else { - memset(vmci_dev->notification_bitmap, 0, PAGE_SIZE); + else caps_in_use |= VMCI_CAPS_NOTIFICATIONS; - } } if (mmio_base != NULL) { -- cgit v1.3.1 From 77e861619baea5a7c934e47fda74b03c0b072aec Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 24 Feb 2022 21:22:37 +0100 Subject: VMCI: Fix some error handling paths in vmci_guest_probe_device() The 'err_remove_vmci_dev_g' error label is not at the right place. This could lead to un-released resource. There is also a missing label. If pci_alloc_irq_vectors() fails, the previous vmci_event_subscribe() call must be undone. Acked-by: Vishnu Dasa Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/959218ce3b135197946d85cd9453551cd04fa5da.1645734041.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_guest.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c index 02d4722d8474..981b19308e6f 100644 --- a/drivers/misc/vmw_vmci/vmci_guest.c +++ b/drivers/misc/vmw_vmci/vmci_guest.c @@ -765,7 +765,7 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, /* Check host capabilities. */ error = vmci_check_host_caps(pdev); if (error) - goto err_remove_bitmap; + goto err_remove_vmci_dev_g; /* Enable device. */ @@ -795,7 +795,7 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, error = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX | PCI_IRQ_MSI | PCI_IRQ_LEGACY); if (error < 0) - goto err_remove_bitmap; + goto err_unsubscribe_event; } else { vmci_dev->exclusive_vectors = true; } @@ -871,13 +871,19 @@ err_free_irq: err_disable_msi: pci_free_irq_vectors(pdev); +err_unsubscribe_event: vmci_err = vmci_event_unsubscribe(ctx_update_sub_id); if (vmci_err < VMCI_SUCCESS) dev_warn(&pdev->dev, "Failed to unsubscribe from event (type=%d) with subscriber (ID=0x%x): %d\n", VMCI_EVENT_CTX_ID_UPDATE, ctx_update_sub_id, vmci_err); -err_remove_bitmap: +err_remove_vmci_dev_g: + spin_lock_irq(&vmci_dev_spinlock); + vmci_pdev = NULL; + vmci_dev_g = NULL; + spin_unlock_irq(&vmci_dev_spinlock); + if (vmci_dev->notification_bitmap) { vmci_write_reg(vmci_dev, VMCI_CONTROL_RESET, VMCI_CONTROL_ADDR); dma_free_coherent(&pdev->dev, PAGE_SIZE, @@ -885,12 +891,6 @@ err_remove_bitmap: vmci_dev->notification_base); } -err_remove_vmci_dev_g: - spin_lock_irq(&vmci_dev_spinlock); - vmci_pdev = NULL; - vmci_dev_g = NULL; - spin_unlock_irq(&vmci_dev_spinlock); - err_free_data_buffers: vmci_free_dg_buffers(vmci_dev); -- cgit v1.3.1 From 20dde50ffe26be9cd446932e3eaf3f7d7db97423 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 14 Feb 2022 17:39:58 +0200 Subject: misc: sgi-gru: Don't cast parameter in bit operations While in this particular case (*) it would not be an issue, the pattern itself is bad and error prone in case somebody blindly copies to their code. Don't cast parameter to unsigned long pointer in the bit operations. Note, new compilers might warn on this line for potential outbound access. *) it seems a dead code, so remove it all for good Fixes: 13d19498b044 ("GRU Driver: driver internal header files") Acked-by: Dimitri Sivanich Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220214153958.9721-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/sgi-gru/grutables.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/sgi-gru/grutables.h b/drivers/misc/sgi-gru/grutables.h index e4c067c61251..5efc869fe59a 100644 --- a/drivers/misc/sgi-gru/grutables.h +++ b/drivers/misc/sgi-gru/grutables.h @@ -530,12 +530,6 @@ struct gru_blade_state { for ((i) = (k)*GRU_CBR_AU_SIZE; \ (i) < ((k) + 1) * GRU_CBR_AU_SIZE; (i)++) -/* Scan each DSR in a DSR bitmap. Note: multiple DSRs in an allocation unit */ -#define for_each_dsr_in_allocation_map(i, map, k) \ - for_each_set_bit((k), (const unsigned long *)(map), GRU_DSR_AU) \ - for ((i) = (k) * GRU_DSR_AU_CL; \ - (i) < ((k) + 1) * GRU_DSR_AU_CL; (i)++) - #define gseg_physical_address(gru, ctxnum) \ ((gru)->gs_gru_base_paddr + ctxnum * GRU_GSEG_STRIDE) #define gseg_virtual_address(gru, ctxnum) \ -- cgit v1.3.1 From 4044fe5525adb65ce0ce9931b8f23fc3ab1aa758 Mon Sep 17 00:00:00 2001 From: Cai Huoqing Date: Wed, 9 Feb 2022 11:24:21 +0800 Subject: ocxl: Make use of the helper macro LIST_HEAD() Replace "struct list_head head = LIST_HEAD_INIT(head)" with "LIST_HEAD(head)" to simplify the code. Acked-by: Frederic Barrat Acked-by: Andrew Donnellan Signed-off-by: Cai Huoqing Link: https://lore.kernel.org/r/20220209032421.37725-1-cai.huoqing@linux.dev Signed-off-by: Greg Kroah-Hartman --- drivers/misc/ocxl/link.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/ocxl/link.c b/drivers/misc/ocxl/link.c index ab039c115381..9670d02c927f 100644 --- a/drivers/misc/ocxl/link.c +++ b/drivers/misc/ocxl/link.c @@ -94,7 +94,7 @@ struct ocxl_link { struct spa *spa; void *platform_data; }; -static struct list_head links_list = LIST_HEAD_INIT(links_list); +static LIST_HEAD(links_list); static DEFINE_MUTEX(links_list_lock); enum xsl_response { -- cgit v1.3.1 From 2c9ae453543c9a3c08840cc4a51a054ebc4e75bf Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Sun, 13 Feb 2022 09:19:07 -0800 Subject: misc: rtsx: conditionally build rtsx_pm_power_saving() On s390 allyesconfig, there is this build error rtsx_pcr.c:1084:13: error: 'rtsx_pm_power_saving' defined but not used 1084 | static void rtsx_pm_power_saving(struct rtsx_pcr *pcr) | ^~~~~~~~~~~~~~~~~~~~ rtsx_pm_power_saving() is only used by rtsx_pci_runtime_idle() which is conditional on CONFIG_PM. So conditionally build rtsx_pm_power_saving() and the similar rtsx_comm_pm_power_saving() and rtsx_enable_aspm(). Signed-off-by: Tom Rix Link: https://lore.kernel.org/r/20220213171907.2786442-1-trix@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cardreader/rtsx_pcr.c | 64 +++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 32 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c index 1cb6425e8369..2a2619e3c72c 100644 --- a/drivers/misc/cardreader/rtsx_pcr.c +++ b/drivers/misc/cardreader/rtsx_pcr.c @@ -1054,38 +1054,6 @@ static int rtsx_pci_acquire_irq(struct rtsx_pcr *pcr) return 0; } -static void rtsx_enable_aspm(struct rtsx_pcr *pcr) -{ - if (pcr->ops->set_aspm) - pcr->ops->set_aspm(pcr, true); - else - rtsx_comm_set_aspm(pcr, true); -} - -static void rtsx_comm_pm_power_saving(struct rtsx_pcr *pcr) -{ - struct rtsx_cr_option *option = &pcr->option; - - if (option->ltr_enabled) { - u32 latency = option->ltr_l1off_latency; - - if (rtsx_check_dev_flag(pcr, L1_SNOOZE_TEST_EN)) - mdelay(option->l1_snooze_delay); - - rtsx_set_ltr_latency(pcr, latency); - } - - if (rtsx_check_dev_flag(pcr, LTR_L1SS_PWR_GATE_EN)) - rtsx_set_l1off_sub_cfg_d0(pcr, 0); - - rtsx_enable_aspm(pcr); -} - -static void rtsx_pm_power_saving(struct rtsx_pcr *pcr) -{ - rtsx_comm_pm_power_saving(pcr); -} - static void rtsx_base_force_power_down(struct rtsx_pcr *pcr) { /* Set relink_time to 0 */ @@ -1701,6 +1669,38 @@ out: #ifdef CONFIG_PM +static void rtsx_enable_aspm(struct rtsx_pcr *pcr) +{ + if (pcr->ops->set_aspm) + pcr->ops->set_aspm(pcr, true); + else + rtsx_comm_set_aspm(pcr, true); +} + +static void rtsx_comm_pm_power_saving(struct rtsx_pcr *pcr) +{ + struct rtsx_cr_option *option = &pcr->option; + + if (option->ltr_enabled) { + u32 latency = option->ltr_l1off_latency; + + if (rtsx_check_dev_flag(pcr, L1_SNOOZE_TEST_EN)) + mdelay(option->l1_snooze_delay); + + rtsx_set_ltr_latency(pcr, latency); + } + + if (rtsx_check_dev_flag(pcr, LTR_L1SS_PWR_GATE_EN)) + rtsx_set_l1off_sub_cfg_d0(pcr, 0); + + rtsx_enable_aspm(pcr); +} + +static void rtsx_pm_power_saving(struct rtsx_pcr *pcr) +{ + rtsx_comm_pm_power_saving(pcr); +} + static void rtsx_pci_shutdown(struct pci_dev *pcidev) { struct pcr_handle *handle = pci_get_drvdata(pcidev); -- cgit v1.3.1 From f4e335f34519ba8e1271f779a7bc7db168e4488d Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 16 Feb 2022 12:25:48 -0800 Subject: lkdtm/fortify: Swap memcpy() for strncpy() The memcpy() runtime defenses are still not landed, so test with strncpy() for now. Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Reported-by: Muhammad Usama Anjum Reviewed-by: Muhammad Usama Anjum Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20220216202548.2093883-1-keescook@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/lkdtm/fortify.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/lkdtm/fortify.c b/drivers/misc/lkdtm/fortify.c index d06458a4858e..ab33bb5e2e7a 100644 --- a/drivers/misc/lkdtm/fortify.c +++ b/drivers/misc/lkdtm/fortify.c @@ -44,14 +44,14 @@ void lkdtm_FORTIFIED_SUBOBJECT(void) strscpy(src, "over ten bytes", size); size = strlen(src) + 1; - pr_info("trying to strcpy past the end of a member of a struct\n"); + pr_info("trying to strncpy past the end of a member of a struct\n"); /* - * memcpy(target.a, src, 20); will hit a compile error because the + * strncpy(target.a, src, 20); will hit a compile error because the * compiler knows at build time that target.a < 20 bytes. Use a * volatile to force a runtime error. */ - memcpy(target.a, src, size); + strncpy(target.a, src, size); /* Store result to global to prevent the code from being eliminated */ fortify_scratch_space = target.a[3]; -- cgit v1.3.1 From 86f4c65fd5003c894dd3082d53e26307fbc211cc Mon Sep 17 00:00:00 2001 From: Ricky WU Date: Mon, 21 Feb 2022 11:20:29 +0000 Subject: misc: rtsx: rts522a rts5228 rts5261 support Runtime PM rts522a, rts5228, rts5261 add extra init flow for rtd3 add more power_down setting for avoid being woken up by plugging or unplugging card when system in S3 Tested-by: Kai-Heng Feng Signed-off-by: Ricky Wu Link: https://lore.kernel.org/r/dace32f573a445908fec0a10482c394c@realtek.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cardreader/rts5227.c | 47 ++++++++++++++++++++++++++++++++++++++ drivers/misc/cardreader/rts5228.c | 21 +++++++++++++++-- drivers/misc/cardreader/rts5261.c | 33 +++++++++++++++++++++++--- drivers/misc/cardreader/rtsx_pcr.h | 2 ++ 4 files changed, 98 insertions(+), 5 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/cardreader/rts5227.c b/drivers/misc/cardreader/rts5227.c index 4bcfbc9afbac..d676cf63a966 100644 --- a/drivers/misc/cardreader/rts5227.c +++ b/drivers/misc/cardreader/rts5227.c @@ -72,6 +72,8 @@ static void rts5227_fetch_vendor_settings(struct rtsx_pcr *pcr) pci_read_config_dword(pdev, PCR_SETTING_REG2, ®); pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg); + if (CHK_PCI_PID(pcr, 0x522A)) + pcr->rtd3_en = rtsx_reg_to_rtd3(reg); if (rtsx_check_mmc_support(reg)) pcr->extra_caps |= EXTRA_CAPS_NO_MMC; pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg); @@ -171,6 +173,28 @@ static int rts5227_extra_init_hw(struct rtsx_pcr *pcr) else rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x30, 0x00); + if (CHK_PCI_PID(pcr, 0x522A)) + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RTS522A_AUTOLOAD_CFG1, + CD_RESUME_EN_MASK, CD_RESUME_EN_MASK); + + if (pcr->rtd3_en) { + if (CHK_PCI_PID(pcr, 0x522A)) { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RTS522A_PM_CTRL3, 0x01, 0x01); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RTS522A_PME_FORCE_CTL, 0x30, 0x30); + } else { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PM_CTRL3, 0x01, 0x01); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PME_FORCE_CTL, 0xFF, 0x33); + } + } else { + if (CHK_PCI_PID(pcr, 0x522A)) { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RTS522A_PM_CTRL3, 0x01, 0x00); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, RTS522A_PME_FORCE_CTL, 0x30, 0x20); + } else { + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PME_FORCE_CTL, 0xFF, 0x30); + rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PM_CTRL3, 0x01, 0x00); + } + } + if (option->force_clkreq_0) rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW); @@ -438,6 +462,28 @@ static int rts522a_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage) return rtsx_pci_send_cmd(pcr, 100); } +static void rts522a_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime) +{ + /* Set relink_time to 0 */ + rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0); + rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, MASK_8_BIT_DEF, 0); + rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3, + RELINK_TIME_MASK, 0); + + rtsx_pci_write_register(pcr, RTS522A_PM_CTRL3, + D3_DELINK_MODE_EN, D3_DELINK_MODE_EN); + + if (!runtime) { + rtsx_pci_write_register(pcr, RTS522A_AUTOLOAD_CFG1, + CD_RESUME_EN_MASK, 0); + rtsx_pci_write_register(pcr, RTS522A_PM_CTRL3, 0x01, 0x00); + rtsx_pci_write_register(pcr, RTS522A_PME_FORCE_CTL, 0x30, 0x20); + } + + rtsx_pci_write_register(pcr, FPDCTL, ALL_POWER_DOWN, ALL_POWER_DOWN); +} + + static void rts522a_set_l1off_cfg_sub_d0(struct rtsx_pcr *pcr, int active) { struct rtsx_cr_option *option = &pcr->option; @@ -473,6 +519,7 @@ static const struct pcr_ops rts522a_pcr_ops = { .card_power_on = rts5227_card_power_on, .card_power_off = rts5227_card_power_off, .switch_output_voltage = rts522a_switch_output_voltage, + .force_power_down = rts522a_force_power_down, .cd_deglitch = NULL, .conv_clk_and_div_n = NULL, .set_l1off_cfg_sub_d0 = rts522a_set_l1off_cfg_sub_d0, diff --git a/drivers/misc/cardreader/rts5228.c b/drivers/misc/cardreader/rts5228.c index ffe3afbf8bfe..af581f4f74d1 100644 --- a/drivers/misc/cardreader/rts5228.c +++ b/drivers/misc/cardreader/rts5228.c @@ -102,6 +102,14 @@ static void rts5228_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool run rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, D3_DELINK_MODE_EN, D3_DELINK_MODE_EN); + if (!runtime) { + rtsx_pci_write_register(pcr, RTS5228_AUTOLOAD_CFG1, + CD_RESUME_EN_MASK, 0); + rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x01, 0x00); + rtsx_pci_write_register(pcr, RTS5228_REG_PME_FORCE_CTL, + FORCE_PM_CONTROL | FORCE_PM_VALUE, FORCE_PM_CONTROL); + } + rtsx_pci_write_register(pcr, FPDCTL, SSC_POWER_DOWN, SSC_POWER_DOWN); } @@ -480,9 +488,18 @@ static int rts5228_extra_init_hw(struct rtsx_pcr *pcr) FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH); rtsx_pci_write_register(pcr, PWD_SUSPEND_EN, 0xFF, 0xFB); - rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x10, 0x00); + + if (pcr->rtd3_en) { + rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x01, 0x01); rtsx_pci_write_register(pcr, RTS5228_REG_PME_FORCE_CTL, - FORCE_PM_CONTROL | FORCE_PM_VALUE, FORCE_PM_CONTROL); + FORCE_PM_CONTROL | FORCE_PM_VALUE, + FORCE_PM_CONTROL | FORCE_PM_VALUE); + } else { + rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x01, 0x00); + rtsx_pci_write_register(pcr, RTS5228_REG_PME_FORCE_CTL, + FORCE_PM_CONTROL | FORCE_PM_VALUE, FORCE_PM_CONTROL); + } + rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, D3_DELINK_MODE_EN, 0x00); return 0; } diff --git a/drivers/misc/cardreader/rts5261.c b/drivers/misc/cardreader/rts5261.c index 64333347c14a..a77585ab0f30 100644 --- a/drivers/misc/cardreader/rts5261.c +++ b/drivers/misc/cardreader/rts5261.c @@ -103,6 +103,24 @@ static void rts5261_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool run rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, D3_DELINK_MODE_EN, D3_DELINK_MODE_EN); + if (!runtime) { + rtsx_pci_write_register(pcr, RTS5261_AUTOLOAD_CFG1, + CD_RESUME_EN_MASK, 0); + rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x01, 0x00); + rtsx_pci_write_register(pcr, RTS5261_REG_PME_FORCE_CTL, + FORCE_PM_CONTROL | FORCE_PM_VALUE, FORCE_PM_CONTROL); + + } else { + rtsx_pci_write_register(pcr, RTS5261_REG_PME_FORCE_CTL, + FORCE_PM_CONTROL | FORCE_PM_VALUE, 0); + + rtsx_pci_write_register(pcr, RTS5261_FW_CTL, + RTS5261_INFORM_RTD3_COLD, RTS5261_INFORM_RTD3_COLD); + rtsx_pci_write_register(pcr, RTS5261_AUTOLOAD_CFG4, + RTS5261_FORCE_PRSNT_LOW, RTS5261_FORCE_PRSNT_LOW); + + } + rtsx_pci_write_register(pcr, RTS5261_REG_FPDCTL, SSC_POWER_DOWN, SSC_POWER_DOWN); } @@ -536,9 +554,18 @@ static int rts5261_extra_init_hw(struct rtsx_pcr *pcr) FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH); rtsx_pci_write_register(pcr, PWD_SUSPEND_EN, 0xFF, 0xFB); - rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x10, 0x00); - rtsx_pci_write_register(pcr, RTS5261_REG_PME_FORCE_CTL, - FORCE_PM_CONTROL | FORCE_PM_VALUE, FORCE_PM_CONTROL); + + if (pcr->rtd3_en) { + rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x01, 0x01); + rtsx_pci_write_register(pcr, RTS5261_REG_PME_FORCE_CTL, + FORCE_PM_CONTROL | FORCE_PM_VALUE, + FORCE_PM_CONTROL | FORCE_PM_VALUE); + } else { + rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x01, 0x00); + rtsx_pci_write_register(pcr, RTS5261_REG_PME_FORCE_CTL, + FORCE_PM_CONTROL | FORCE_PM_VALUE, FORCE_PM_CONTROL); + } + rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, D3_DELINK_MODE_EN, 0x00); /* Clear Enter RTD3_cold Information*/ rtsx_pci_write_register(pcr, RTS5261_FW_CTL, diff --git a/drivers/misc/cardreader/rtsx_pcr.h b/drivers/misc/cardreader/rtsx_pcr.h index aa0ebd667227..37d1f316ae17 100644 --- a/drivers/misc/cardreader/rtsx_pcr.h +++ b/drivers/misc/cardreader/rtsx_pcr.h @@ -15,6 +15,8 @@ #define MIN_DIV_N_PCR 80 #define MAX_DIV_N_PCR 208 +#define RTS522A_PME_FORCE_CTL 0xFF78 +#define RTS522A_AUTOLOAD_CFG1 0xFF7C #define RTS522A_PM_CTRL3 0xFF7E #define RTS524A_PME_FORCE_CTL 0xFF78 -- cgit v1.3.1 From ccdf6f806fbf559f7c29ed9302a7c1b4da7fd37f Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Tue, 15 Feb 2022 10:04:35 +0200 Subject: mei: me: disable driver on the ign firmware Add a quirk to disable MEI interface on Intel PCH Ignition (IGN) as the IGN firmware doesn't support the protocol. Cc: Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Link: https://lore.kernel.org/r/20220215080438.264876-1-tomas.winkler@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me-regs.h | 1 + drivers/misc/mei/hw-me.c | 23 ++++++++++++----------- 2 files changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index 67bb6a25fd0a..888c27bc3f1a 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -120,6 +120,7 @@ #define PCI_CFG_HFS_2 0x48 #define PCI_CFG_HFS_3 0x60 # define PCI_CFG_HFS_3_FW_SKU_MSK 0x00000070 +# define PCI_CFG_HFS_3_FW_SKU_IGN 0x00000000 # define PCI_CFG_HFS_3_FW_SKU_SPS 0x00000060 #define PCI_CFG_HFS_4 0x64 #define PCI_CFG_HFS_5 0x68 diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index d3a6c0728645..fbc4c9581864 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -1405,16 +1405,16 @@ static bool mei_me_fw_type_sps_4(const struct pci_dev *pdev) .quirk_probe = mei_me_fw_type_sps_4 /** - * mei_me_fw_type_sps() - check for sps sku + * mei_me_fw_type_sps_ign() - check for sps or ign sku * - * Read ME FW Status register to check for SPS Firmware. - * The SPS FW is only signaled in pci function 0 + * Read ME FW Status register to check for SPS or IGN Firmware. + * The SPS/IGN FW is only signaled in pci function 0 * * @pdev: pci device * - * Return: true in case of SPS firmware + * Return: true in case of SPS/IGN firmware */ -static bool mei_me_fw_type_sps(const struct pci_dev *pdev) +static bool mei_me_fw_type_sps_ign(const struct pci_dev *pdev) { u32 reg; u32 fw_type; @@ -1427,14 +1427,15 @@ static bool mei_me_fw_type_sps(const struct pci_dev *pdev) dev_dbg(&pdev->dev, "fw type is %d\n", fw_type); - return fw_type == PCI_CFG_HFS_3_FW_SKU_SPS; + return fw_type == PCI_CFG_HFS_3_FW_SKU_IGN || + fw_type == PCI_CFG_HFS_3_FW_SKU_SPS; } #define MEI_CFG_KIND_ITOUCH \ .kind = "itouch" -#define MEI_CFG_FW_SPS \ - .quirk_probe = mei_me_fw_type_sps +#define MEI_CFG_FW_SPS_IGN \ + .quirk_probe = mei_me_fw_type_sps_ign #define MEI_CFG_FW_VER_SUPP \ .fw_ver_supported = 1 @@ -1535,7 +1536,7 @@ static const struct mei_cfg mei_me_pch12_sps_cfg = { MEI_CFG_PCH8_HFS, MEI_CFG_FW_VER_SUPP, MEI_CFG_DMA_128, - MEI_CFG_FW_SPS, + MEI_CFG_FW_SPS_IGN, }; /* Cannon Lake itouch with quirk for SPS 5.0 and newer Firmware exclusion @@ -1545,7 +1546,7 @@ static const struct mei_cfg mei_me_pch12_itouch_sps_cfg = { MEI_CFG_KIND_ITOUCH, MEI_CFG_PCH8_HFS, MEI_CFG_FW_VER_SUPP, - MEI_CFG_FW_SPS, + MEI_CFG_FW_SPS_IGN, }; /* Tiger Lake and newer devices */ @@ -1562,7 +1563,7 @@ static const struct mei_cfg mei_me_pch15_sps_cfg = { MEI_CFG_FW_VER_SUPP, MEI_CFG_DMA_128, MEI_CFG_TRC, - MEI_CFG_FW_SPS, + MEI_CFG_FW_SPS_IGN, }; /* -- cgit v1.3.1 From 685867f40c4ee8cc7f7d27561ce13b43f864cb84 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Tue, 15 Feb 2022 10:04:36 +0200 Subject: mei: me: avoid link reset on shutdown Avoid lingering reset thread on driver shutdown. If the firmware is down during a shutdown flow do not initiate the link reset, simply disconnect all clients and let shutdown flow finish Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Link: https://lore.kernel.org/r/20220215080438.264876-2-tomas.winkler@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/client.c | 1 + drivers/misc/mei/hw-me.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 06734670a732..31264ab2eb13 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -2148,6 +2148,7 @@ void mei_cl_all_disconnect(struct mei_device *dev) list_for_each_entry(cl, &dev->file_list, link) mei_cl_set_disconnected(cl); } +EXPORT_SYMBOL_GPL(mei_cl_all_disconnect); static struct mei_cl *mei_cl_dma_map_find(struct mei_device *dev, u8 buffer_id) { diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index fbc4c9581864..3a86c087bc9d 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -1257,7 +1257,11 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) /* check if ME wants a reset */ if (!mei_hw_is_ready(dev) && dev->dev_state != MEI_DEV_RESETTING) { dev_warn(dev->dev, "FW not ready: resetting.\n"); - schedule_work(&dev->reset_work); + if (dev->dev_state == MEI_DEV_POWERING_DOWN || + dev->dev_state == MEI_DEV_POWER_DOWN) + mei_cl_all_disconnect(dev); + else if (dev->dev_state != MEI_DEV_DISABLED) + schedule_work(&dev->reset_work); goto end; } -- cgit v1.3.1 From 04af137c6a88b7f8f78e78abf353ec97ce28c5b5 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Tue, 15 Feb 2022 10:04:37 +0200 Subject: mei: me: fix reset policy on read error in interrupt Avoid link reset in DISABLED and POWERING_DOWN state if read error is occurred - let shutdown flow finish. In any state exit interrupt handler if read error occurred. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Link: https://lore.kernel.org/r/20220215080438.264876-3-tomas.winkler@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index 3a86c087bc9d..719fee9af156 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -1293,12 +1293,14 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) if (rets == -ENODATA) break; - if (rets && - (dev->dev_state != MEI_DEV_RESETTING && - dev->dev_state != MEI_DEV_POWER_DOWN)) { - dev_err(dev->dev, "mei_irq_read_handler ret = %d.\n", - rets); - schedule_work(&dev->reset_work); + if (rets) { + dev_err(dev->dev, "mei_irq_read_handler ret = %d, state = %d.\n", + rets, dev->dev_state); + if (dev->dev_state != MEI_DEV_RESETTING && + dev->dev_state != MEI_DEV_DISABLED && + dev->dev_state != MEI_DEV_POWERING_DOWN && + dev->dev_state != MEI_DEV_POWER_DOWN) + schedule_work(&dev->reset_work); goto end; } } -- cgit v1.3.1 From 2be483f12ea34b43826f70c60f0924a7bda991bd Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Tue, 15 Feb 2022 10:04:38 +0200 Subject: mei: do not overwrite state on hw start During the hardware start sequence, do not overwrite the driver state and do not proceed with the initialization sequence if the state was changed while the driver was waiting for the start interrupt. This can happen if the driver's removal/stop procedure was triggered from the parent level while the driver is waiting for the start interrupt. This may lead to stray the reset work or the timer after driver were removed. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Link: https://lore.kernel.org/r/20220215080438.264876-4-tomas.winkler@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/init.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index f79076c67256..eb052005ca86 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c @@ -161,6 +161,11 @@ int mei_reset(struct mei_device *dev) return ret; } + if (dev->dev_state != MEI_DEV_RESETTING) { + dev_dbg(dev->dev, "wrong state = %d on link start\n", dev->dev_state); + return 0; + } + dev_dbg(dev->dev, "link is established start sending messages.\n"); mei_set_devstate(dev, MEI_DEV_INIT_CLIENTS); -- cgit v1.3.1 From aff5d9d378e77a45f33cd933b8b8ddac8fe43528 Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Tue, 28 Dec 2021 13:47:18 +0200 Subject: habanalabs: check the return value of hl_cs_poll_fences() As part of handling of the multi-CS wait ioctl, hl_cs_poll_fences() is called in a "while (true)" loop. This function can fail, but the checking of its return value was missed. Add this check and exit the loop in case of a failure. Signed-off-by: Tomer Tayar Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/command_submission.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index 0a4ef13d9ac4..2f40b937c59f 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -2739,7 +2739,7 @@ static int hl_multi_cs_wait_ioctl(struct hl_fpriv *hpriv, void *data) mcs_data.update_ts = false; rc = hl_cs_poll_fences(&mcs_data, mcs_compl); - if (mcs_data.completion_bitmap) + if (rc || mcs_data.completion_bitmap) break; /* -- cgit v1.3.1 From eb85eec858c1a5c11d3a0bff403f6440b05b40dc Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Mon, 3 Jan 2022 09:48:27 +0200 Subject: habanalabs: fix possible memory leak in MMU DR fini This patch fixes what seems to be copy paste error. We will have a memory leak if the host-resident shadow is NULL (which will likely happen as the DR and HR are not dependent). Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/mmu/mmu_v1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/mmu/mmu_v1.c b/drivers/misc/habanalabs/common/mmu/mmu_v1.c index 6134b6ae7615..3cadef97817d 100644 --- a/drivers/misc/habanalabs/common/mmu/mmu_v1.c +++ b/drivers/misc/habanalabs/common/mmu/mmu_v1.c @@ -467,7 +467,7 @@ static void hl_mmu_v1_fini(struct hl_device *hdev) { /* MMU H/W fini was already done in device hw_fini() */ - if (!ZERO_OR_NULL_PTR(hdev->mmu_priv.hr.mmu_shadow_hop0)) { + if (!ZERO_OR_NULL_PTR(hdev->mmu_priv.dr.mmu_shadow_hop0)) { kvfree(hdev->mmu_priv.dr.mmu_shadow_hop0); gen_pool_destroy(hdev->mmu_priv.dr.mmu_pgt_pool); -- cgit v1.3.1 From 4edb4ffe39c9bdaec50186d0ca583a7ff01143de Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Wed, 5 Jan 2022 23:14:45 +0200 Subject: habanalabs/gaudi: disable CGM permanently Due to the need of SynapseAI to configure all TPC engines from a single QMAN, the driver must disable CGM and never allow the user to enable it. Otherwise, the configuration of the TPC engines will fail. Signed-off-by: Oded Gabbay --- .../ABI/testing/debugfs-driver-habanalabs | 19 +- drivers/misc/habanalabs/common/debugfs.c | 32 +-- drivers/misc/habanalabs/common/habanalabs.h | 4 - drivers/misc/habanalabs/common/habanalabs_drv.c | 1 - drivers/misc/habanalabs/gaudi/gaudi.c | 230 ++++++--------------- drivers/misc/habanalabs/gaudi/gaudiP.h | 1 - 6 files changed, 66 insertions(+), 221 deletions(-) (limited to 'drivers/misc') diff --git a/Documentation/ABI/testing/debugfs-driver-habanalabs b/Documentation/ABI/testing/debugfs-driver-habanalabs index 2667cbf940f3..783001a574b3 100644 --- a/Documentation/ABI/testing/debugfs-driver-habanalabs +++ b/Documentation/ABI/testing/debugfs-driver-habanalabs @@ -12,24 +12,7 @@ What: /sys/kernel/debug/habanalabs/hl/clk_gate Date: May 2020 KernelVersion: 5.8 Contact: ogabbay@kernel.org -Description: Allow the root user to disable/enable in runtime the clock - gating mechanism in Gaudi. Due to how Gaudi is built, the - clock gating needs to be disabled in order to access the - registers of the TPC and MME engines. This is sometimes needed - during debug by the user and hence the user needs this option. - The user can supply a bitmask value, each bit represents - a different engine to disable/enable its clock gating feature. - The bitmask is composed of 20 bits: - - ======= ============ - 0 - 7 DMA channels - 8 - 11 MME engines - 12 - 19 TPC engines - ======= ============ - - The bit's location of a specific engine can be determined - using (1 << GAUDI_ENGINE_ID_*). GAUDI_ENGINE_ID_* values - are defined in uapi habanalabs.h file in enum gaudi_engine_id +Description: This setting is now deprecated as clock gating is handled solely by the f/w What: /sys/kernel/debug/habanalabs/hl/command_buffers Date: Jan 2019 diff --git a/drivers/misc/habanalabs/common/debugfs.c b/drivers/misc/habanalabs/common/debugfs.c index fc084ee5106e..e3ee5f45d20c 100644 --- a/drivers/misc/habanalabs/common/debugfs.c +++ b/drivers/misc/habanalabs/common/debugfs.c @@ -1054,42 +1054,12 @@ static ssize_t hl_device_write(struct file *f, const char __user *buf, static ssize_t hl_clk_gate_read(struct file *f, char __user *buf, size_t count, loff_t *ppos) { - struct hl_dbg_device_entry *entry = file_inode(f)->i_private; - struct hl_device *hdev = entry->hdev; - char tmp_buf[200]; - ssize_t rc; - - if (*ppos) - return 0; - - sprintf(tmp_buf, "0x%llx\n", hdev->clock_gating_mask); - rc = simple_read_from_buffer(buf, count, ppos, tmp_buf, - strlen(tmp_buf) + 1); - - return rc; + return 0; } static ssize_t hl_clk_gate_write(struct file *f, const char __user *buf, size_t count, loff_t *ppos) { - struct hl_dbg_device_entry *entry = file_inode(f)->i_private; - struct hl_device *hdev = entry->hdev; - u64 value; - ssize_t rc; - - if (hdev->reset_info.in_reset) { - dev_warn_ratelimited(hdev->dev, - "Can't change clock gating during reset\n"); - return 0; - } - - rc = kstrtoull_from_user(buf, count, 16, &value); - if (rc) - return rc; - - hdev->clock_gating_mask = value; - hdev->asic_funcs->set_clock_gating(hdev); - return count; } diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index cb710fd478b6..27b9f24c4f75 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -2569,9 +2569,6 @@ struct hl_reset_info { * @max_power: the max power of the device, as configured by the sysadmin. This * value is saved so in case of hard-reset, the driver will restore * this value and update the F/W after the re-initialization - * @clock_gating_mask: is clock gating enabled. bitmask that represents the - * different engines. See debugfs-driver-habanalabs for - * details. * @boot_error_status_mask: contains a mask of the device boot error status. * Each bit represents a different error, according to * the defines in hl_boot_if.h. If the bit is cleared, @@ -2710,7 +2707,6 @@ struct hl_device { atomic64_t dram_used_mem; u64 timeout_jiffies; u64 max_power; - u64 clock_gating_mask; u64 boot_error_status_mask; u64 dram_pci_bar_start; u64 last_successful_open_jif; diff --git a/drivers/misc/habanalabs/common/habanalabs_drv.c b/drivers/misc/habanalabs/common/habanalabs_drv.c index 690b763c7a95..017bfc4551da 100644 --- a/drivers/misc/habanalabs/common/habanalabs_drv.c +++ b/drivers/misc/habanalabs/common/habanalabs_drv.c @@ -256,7 +256,6 @@ static void set_driver_behavior_per_device(struct hl_device *hdev) hdev->cpu_queues_enable = 1; hdev->heartbeat = 1; hdev->mmu_enable = 1; - hdev->clock_gating_mask = ULONG_MAX; hdev->sram_scrambler_enable = 1; hdev->dram_scrambler_enable = 1; hdev->bmc_enable = 1; diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 013c6da2e3ca..c20b781d4ada 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -3740,74 +3740,10 @@ static void gaudi_tpc_stall(struct hl_device *hdev) static void gaudi_set_clock_gating(struct hl_device *hdev) { - struct gaudi_device *gaudi = hdev->asic_specific; - u32 qman_offset; - bool enable; - int i; - - /* In case we are during debug session, don't enable the clock gate - * as it may interfere - */ - if (hdev->in_debug) - return; - - if (hdev->asic_prop.fw_security_enabled) - return; - - for (i = GAUDI_PCI_DMA_1, qman_offset = 0 ; i < GAUDI_HBM_DMA_1 ; i++) { - enable = !!(hdev->clock_gating_mask & - (BIT_ULL(gaudi_dma_assignment[i]))); - - qman_offset = gaudi_dma_assignment[i] * DMA_QMAN_OFFSET; - WREG32(mmDMA0_QM_CGM_CFG1 + qman_offset, - enable ? QMAN_CGM1_PWR_GATE_EN : 0); - WREG32(mmDMA0_QM_CGM_CFG + qman_offset, - enable ? QMAN_UPPER_CP_CGM_PWR_GATE_EN : 0); - } - - for (i = GAUDI_HBM_DMA_1 ; i < GAUDI_DMA_MAX ; i++) { - enable = !!(hdev->clock_gating_mask & - (BIT_ULL(gaudi_dma_assignment[i]))); - - /* GC sends work to DMA engine through Upper CP in DMA5 so - * we need to not enable clock gating in that DMA - */ - if (i == GAUDI_HBM_DMA_4) - enable = 0; - - qman_offset = gaudi_dma_assignment[i] * DMA_QMAN_OFFSET; - WREG32(mmDMA0_QM_CGM_CFG1 + qman_offset, - enable ? QMAN_CGM1_PWR_GATE_EN : 0); - WREG32(mmDMA0_QM_CGM_CFG + qman_offset, - enable ? QMAN_COMMON_CP_CGM_PWR_GATE_EN : 0); - } - - enable = !!(hdev->clock_gating_mask & (BIT_ULL(GAUDI_ENGINE_ID_MME_0))); - WREG32(mmMME0_QM_CGM_CFG1, enable ? QMAN_CGM1_PWR_GATE_EN : 0); - WREG32(mmMME0_QM_CGM_CFG, enable ? QMAN_COMMON_CP_CGM_PWR_GATE_EN : 0); - - enable = !!(hdev->clock_gating_mask & (BIT_ULL(GAUDI_ENGINE_ID_MME_2))); - WREG32(mmMME2_QM_CGM_CFG1, enable ? QMAN_CGM1_PWR_GATE_EN : 0); - WREG32(mmMME2_QM_CGM_CFG, enable ? QMAN_COMMON_CP_CGM_PWR_GATE_EN : 0); - - for (i = 0, qman_offset = 0 ; i < TPC_NUMBER_OF_ENGINES ; i++) { - enable = !!(hdev->clock_gating_mask & - (BIT_ULL(GAUDI_ENGINE_ID_TPC_0 + i))); - - WREG32(mmTPC0_QM_CGM_CFG1 + qman_offset, - enable ? QMAN_CGM1_PWR_GATE_EN : 0); - WREG32(mmTPC0_QM_CGM_CFG + qman_offset, - enable ? QMAN_COMMON_CP_CGM_PWR_GATE_EN : 0); - - qman_offset += TPC_QMAN_OFFSET; - } - - gaudi->hw_cap_initialized |= HW_CAP_CLK_GATE; } static void gaudi_disable_clock_gating(struct hl_device *hdev) { - struct gaudi_device *gaudi = hdev->asic_specific; u32 qman_offset; int i; @@ -3832,8 +3768,6 @@ static void gaudi_disable_clock_gating(struct hl_device *hdev) qman_offset += (mmTPC1_QM_CGM_CFG - mmTPC0_QM_CGM_CFG); } - - gaudi->hw_cap_initialized &= ~(HW_CAP_CLK_GATE); } static void gaudi_enable_timestamp(struct hl_device *hdev) @@ -4400,14 +4334,11 @@ skip_reset: status); if (gaudi) { - gaudi->hw_cap_initialized &= ~(HW_CAP_CPU | HW_CAP_CPU_Q | - HW_CAP_HBM | HW_CAP_PCI_DMA | - HW_CAP_MME | HW_CAP_TPC_MASK | - HW_CAP_HBM_DMA | HW_CAP_PLL | - HW_CAP_NIC_MASK | HW_CAP_MMU | - HW_CAP_SRAM_SCRAMBLER | - HW_CAP_HBM_SCRAMBLER | - HW_CAP_CLK_GATE); + gaudi->hw_cap_initialized &= ~(HW_CAP_CPU | HW_CAP_CPU_Q | HW_CAP_HBM | + HW_CAP_PCI_DMA | HW_CAP_MME | HW_CAP_TPC_MASK | + HW_CAP_HBM_DMA | HW_CAP_PLL | HW_CAP_NIC_MASK | + HW_CAP_MMU | HW_CAP_SRAM_SCRAMBLER | + HW_CAP_HBM_SCRAMBLER); memset(gaudi->events_stat, 0, sizeof(gaudi->events_stat)); @@ -6188,7 +6119,6 @@ static int gaudi_debugfs_read32(struct hl_device *hdev, u64 addr, bool user_address, u32 *val) { struct asic_fixed_properties *prop = &hdev->asic_prop; - struct gaudi_device *gaudi = hdev->asic_specific; u64 hbm_bar_addr, host_phys_end; int rc = 0; @@ -6196,38 +6126,31 @@ static int gaudi_debugfs_read32(struct hl_device *hdev, u64 addr, if ((addr >= CFG_BASE) && (addr < CFG_BASE + CFG_SIZE)) { - if ((gaudi->hw_cap_initialized & HW_CAP_CLK_GATE) && - (hdev->clock_gating_mask & - GAUDI_CLK_GATE_DEBUGFS_MASK)) { + *val = RREG32(addr - CFG_BASE); - dev_err_ratelimited(hdev->dev, - "Can't read register - clock gating is enabled!\n"); - rc = -EFAULT; - } else { - *val = RREG32(addr - CFG_BASE); - } + } else if ((addr >= SRAM_BASE_ADDR) && (addr < SRAM_BASE_ADDR + SRAM_BAR_SIZE)) { + + *val = readl(hdev->pcie_bar[SRAM_BAR_ID] + (addr - SRAM_BASE_ADDR)); - } else if ((addr >= SRAM_BASE_ADDR) && - (addr < SRAM_BASE_ADDR + SRAM_BAR_SIZE)) { - *val = readl(hdev->pcie_bar[SRAM_BAR_ID] + - (addr - SRAM_BASE_ADDR)); } else if (addr < DRAM_PHYS_BASE + hdev->asic_prop.dram_size) { - u64 bar_base_addr = DRAM_PHYS_BASE + - (addr & ~(prop->dram_pci_bar_size - 0x1ull)); + + u64 bar_base_addr = DRAM_PHYS_BASE + (addr & ~(prop->dram_pci_bar_size - 0x1ull)); hbm_bar_addr = gaudi_set_hbm_bar_base(hdev, bar_base_addr); - if (hbm_bar_addr != U64_MAX) { - *val = readl(hdev->pcie_bar[HBM_BAR_ID] + - (addr - bar_base_addr)); - hbm_bar_addr = gaudi_set_hbm_bar_base(hdev, - hbm_bar_addr); + if (hbm_bar_addr != U64_MAX) { + *val = readl(hdev->pcie_bar[HBM_BAR_ID] + (addr - bar_base_addr)); + hbm_bar_addr = gaudi_set_hbm_bar_base(hdev, hbm_bar_addr); } + if (hbm_bar_addr == U64_MAX) rc = -EIO; + } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end && user_address && !iommu_present(&pci_bus_type)) { + *val = *(u32 *) phys_to_virt(addr - HOST_PHYS_BASE); + } else { rc = -EFAULT; } @@ -6239,7 +6162,6 @@ static int gaudi_debugfs_write32(struct hl_device *hdev, u64 addr, bool user_address, u32 val) { struct asic_fixed_properties *prop = &hdev->asic_prop; - struct gaudi_device *gaudi = hdev->asic_specific; u64 hbm_bar_addr, host_phys_end; int rc = 0; @@ -6247,38 +6169,31 @@ static int gaudi_debugfs_write32(struct hl_device *hdev, u64 addr, if ((addr >= CFG_BASE) && (addr < CFG_BASE + CFG_SIZE)) { - if ((gaudi->hw_cap_initialized & HW_CAP_CLK_GATE) && - (hdev->clock_gating_mask & - GAUDI_CLK_GATE_DEBUGFS_MASK)) { + WREG32(addr - CFG_BASE, val); - dev_err_ratelimited(hdev->dev, - "Can't write register - clock gating is enabled!\n"); - rc = -EFAULT; - } else { - WREG32(addr - CFG_BASE, val); - } + } else if ((addr >= SRAM_BASE_ADDR) && (addr < SRAM_BASE_ADDR + SRAM_BAR_SIZE)) { + + writel(val, hdev->pcie_bar[SRAM_BAR_ID] + (addr - SRAM_BASE_ADDR)); - } else if ((addr >= SRAM_BASE_ADDR) && - (addr < SRAM_BASE_ADDR + SRAM_BAR_SIZE)) { - writel(val, hdev->pcie_bar[SRAM_BAR_ID] + - (addr - SRAM_BASE_ADDR)); } else if (addr < DRAM_PHYS_BASE + hdev->asic_prop.dram_size) { - u64 bar_base_addr = DRAM_PHYS_BASE + - (addr & ~(prop->dram_pci_bar_size - 0x1ull)); + + u64 bar_base_addr = DRAM_PHYS_BASE + (addr & ~(prop->dram_pci_bar_size - 0x1ull)); hbm_bar_addr = gaudi_set_hbm_bar_base(hdev, bar_base_addr); - if (hbm_bar_addr != U64_MAX) { - writel(val, hdev->pcie_bar[HBM_BAR_ID] + - (addr - bar_base_addr)); - hbm_bar_addr = gaudi_set_hbm_bar_base(hdev, - hbm_bar_addr); + if (hbm_bar_addr != U64_MAX) { + writel(val, hdev->pcie_bar[HBM_BAR_ID] + (addr - bar_base_addr)); + hbm_bar_addr = gaudi_set_hbm_bar_base(hdev, hbm_bar_addr); } + if (hbm_bar_addr == U64_MAX) rc = -EIO; + } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end && user_address && !iommu_present(&pci_bus_type)) { + *(u32 *) phys_to_virt(addr - HOST_PHYS_BASE) = val; + } else { rc = -EFAULT; } @@ -6290,7 +6205,6 @@ static int gaudi_debugfs_read64(struct hl_device *hdev, u64 addr, bool user_address, u64 *val) { struct asic_fixed_properties *prop = &hdev->asic_prop; - struct gaudi_device *gaudi = hdev->asic_specific; u64 hbm_bar_addr, host_phys_end; int rc = 0; @@ -6298,42 +6212,35 @@ static int gaudi_debugfs_read64(struct hl_device *hdev, u64 addr, if ((addr >= CFG_BASE) && (addr <= CFG_BASE + CFG_SIZE - sizeof(u64))) { - if ((gaudi->hw_cap_initialized & HW_CAP_CLK_GATE) && - (hdev->clock_gating_mask & - GAUDI_CLK_GATE_DEBUGFS_MASK)) { - - dev_err_ratelimited(hdev->dev, - "Can't read register - clock gating is enabled!\n"); - rc = -EFAULT; - } else { - u32 val_l = RREG32(addr - CFG_BASE); - u32 val_h = RREG32(addr + sizeof(u32) - CFG_BASE); + u32 val_l = RREG32(addr - CFG_BASE); + u32 val_h = RREG32(addr + sizeof(u32) - CFG_BASE); - *val = (((u64) val_h) << 32) | val_l; - } + *val = (((u64) val_h) << 32) | val_l; } else if ((addr >= SRAM_BASE_ADDR) && - (addr <= SRAM_BASE_ADDR + SRAM_BAR_SIZE - sizeof(u64))) { - *val = readq(hdev->pcie_bar[SRAM_BAR_ID] + - (addr - SRAM_BASE_ADDR)); - } else if (addr <= - DRAM_PHYS_BASE + hdev->asic_prop.dram_size - sizeof(u64)) { - u64 bar_base_addr = DRAM_PHYS_BASE + - (addr & ~(prop->dram_pci_bar_size - 0x1ull)); + (addr <= SRAM_BASE_ADDR + SRAM_BAR_SIZE - sizeof(u64))) { + + *val = readq(hdev->pcie_bar[SRAM_BAR_ID] + (addr - SRAM_BASE_ADDR)); + + } else if (addr <= DRAM_PHYS_BASE + hdev->asic_prop.dram_size - sizeof(u64)) { + + u64 bar_base_addr = DRAM_PHYS_BASE + (addr & ~(prop->dram_pci_bar_size - 0x1ull)); hbm_bar_addr = gaudi_set_hbm_bar_base(hdev, bar_base_addr); - if (hbm_bar_addr != U64_MAX) { - *val = readq(hdev->pcie_bar[HBM_BAR_ID] + - (addr - bar_base_addr)); - hbm_bar_addr = gaudi_set_hbm_bar_base(hdev, - hbm_bar_addr); + if (hbm_bar_addr != U64_MAX) { + *val = readq(hdev->pcie_bar[HBM_BAR_ID] + (addr - bar_base_addr)); + hbm_bar_addr = gaudi_set_hbm_bar_base(hdev, hbm_bar_addr); } + if (hbm_bar_addr == U64_MAX) rc = -EIO; + } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end && user_address && !iommu_present(&pci_bus_type)) { + *val = *(u64 *) phys_to_virt(addr - HOST_PHYS_BASE); + } else { rc = -EFAULT; } @@ -6345,7 +6252,6 @@ static int gaudi_debugfs_write64(struct hl_device *hdev, u64 addr, bool user_address, u64 val) { struct asic_fixed_properties *prop = &hdev->asic_prop; - struct gaudi_device *gaudi = hdev->asic_specific; u64 hbm_bar_addr, host_phys_end; int rc = 0; @@ -6353,41 +6259,33 @@ static int gaudi_debugfs_write64(struct hl_device *hdev, u64 addr, if ((addr >= CFG_BASE) && (addr <= CFG_BASE + CFG_SIZE - sizeof(u64))) { - if ((gaudi->hw_cap_initialized & HW_CAP_CLK_GATE) && - (hdev->clock_gating_mask & - GAUDI_CLK_GATE_DEBUGFS_MASK)) { - - dev_err_ratelimited(hdev->dev, - "Can't write register - clock gating is enabled!\n"); - rc = -EFAULT; - } else { - WREG32(addr - CFG_BASE, lower_32_bits(val)); - WREG32(addr + sizeof(u32) - CFG_BASE, - upper_32_bits(val)); - } + WREG32(addr - CFG_BASE, lower_32_bits(val)); + WREG32(addr + sizeof(u32) - CFG_BASE, upper_32_bits(val)); } else if ((addr >= SRAM_BASE_ADDR) && - (addr <= SRAM_BASE_ADDR + SRAM_BAR_SIZE - sizeof(u64))) { - writeq(val, hdev->pcie_bar[SRAM_BAR_ID] + - (addr - SRAM_BASE_ADDR)); - } else if (addr <= - DRAM_PHYS_BASE + hdev->asic_prop.dram_size - sizeof(u64)) { - u64 bar_base_addr = DRAM_PHYS_BASE + - (addr & ~(prop->dram_pci_bar_size - 0x1ull)); + (addr <= SRAM_BASE_ADDR + SRAM_BAR_SIZE - sizeof(u64))) { + + writeq(val, hdev->pcie_bar[SRAM_BAR_ID] + (addr - SRAM_BASE_ADDR)); + + } else if (addr <= DRAM_PHYS_BASE + hdev->asic_prop.dram_size - sizeof(u64)) { + + u64 bar_base_addr = DRAM_PHYS_BASE + (addr & ~(prop->dram_pci_bar_size - 0x1ull)); hbm_bar_addr = gaudi_set_hbm_bar_base(hdev, bar_base_addr); - if (hbm_bar_addr != U64_MAX) { - writeq(val, hdev->pcie_bar[HBM_BAR_ID] + - (addr - bar_base_addr)); - hbm_bar_addr = gaudi_set_hbm_bar_base(hdev, - hbm_bar_addr); + if (hbm_bar_addr != U64_MAX) { + writeq(val, hdev->pcie_bar[HBM_BAR_ID] + (addr - bar_base_addr)); + hbm_bar_addr = gaudi_set_hbm_bar_base(hdev, hbm_bar_addr); } + if (hbm_bar_addr == U64_MAX) rc = -EIO; + } else if (addr >= HOST_PHYS_BASE && addr < host_phys_end && user_address && !iommu_present(&pci_bus_type)) { + *(u64 *) phys_to_virt(addr - HOST_PHYS_BASE) = val; + } else { rc = -EFAULT; } diff --git a/drivers/misc/habanalabs/gaudi/gaudiP.h b/drivers/misc/habanalabs/gaudi/gaudiP.h index 8ac16a9b7d15..caa858bf6edc 100644 --- a/drivers/misc/habanalabs/gaudi/gaudiP.h +++ b/drivers/misc/habanalabs/gaudi/gaudiP.h @@ -177,7 +177,6 @@ #define HW_CAP_MSI BIT(6) #define HW_CAP_CPU_Q BIT(7) #define HW_CAP_HBM_DMA BIT(8) -#define HW_CAP_CLK_GATE BIT(9) #define HW_CAP_SRAM_SCRAMBLER BIT(10) #define HW_CAP_HBM_SCRAMBLER BIT(11) -- cgit v1.3.1 From d280d5954ec37e036c13fb64cf7ace8ce4c5fe15 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Thu, 6 Jan 2022 15:02:44 +0200 Subject: habanalabs: remove ASIC functions of clock gating Now that clock gating is permanently disabled in GAUDI, no need for the ASIC functions of setting and disabling clock gating, as this was a unique scenario in GAUDI. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/device.c | 4 - drivers/misc/habanalabs/common/habanalabs.h | 5 -- drivers/misc/habanalabs/gaudi/gaudi.c | 123 ++-------------------------- drivers/misc/habanalabs/gaudi/gaudiP.h | 3 - drivers/misc/habanalabs/goya/goya.c | 12 --- 5 files changed, 5 insertions(+), 142 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index 733338ab6f1d..9955e0d3502b 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -644,9 +644,6 @@ int hl_device_set_debug_mode(struct hl_device *hdev, struct hl_ctx *ctx, bool en hdev->in_debug = 0; - if (!hdev->reset_info.hard_reset_pending) - hdev->asic_funcs->set_clock_gating(hdev); - goto out; } @@ -657,7 +654,6 @@ int hl_device_set_debug_mode(struct hl_device *hdev, struct hl_ctx *ctx, bool en goto out; } - hdev->asic_funcs->disable_clock_gating(hdev); hdev->in_debug = 1; out: diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 27b9f24c4f75..24962807e2cf 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -1164,9 +1164,6 @@ struct fw_load_mgr { * @mmu_invalidate_cache_range: flush specific MMU STLB cache lines with * ASID-VA-size mask. * @send_heartbeat: send is-alive packet to CPU-CP and verify response. - * @set_clock_gating: enable/disable clock gating per engine according to - * clock gating mask in hdev - * @disable_clock_gating: disable clock gating completely * @debug_coresight: perform certain actions on Coresight for debugging. * @is_device_idle: return true if device is idle, false otherwise. * @non_hard_reset_late_init: perform certain actions needed after a reset which is not hard-reset @@ -1300,8 +1297,6 @@ struct hl_asic_funcs { int (*mmu_invalidate_cache_range)(struct hl_device *hdev, bool is_hard, u32 flags, u32 asid, u64 va, u64 size); int (*send_heartbeat)(struct hl_device *hdev); - void (*set_clock_gating)(struct hl_device *hdev); - void (*disable_clock_gating)(struct hl_device *hdev); int (*debug_coresight)(struct hl_device *hdev, struct hl_ctx *ctx, void *data); bool (*is_device_idle)(struct hl_device *hdev, u64 *mask_arr, u8 mask_len, struct seq_file *s); diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index c20b781d4ada..16637d629e67 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright 2016-2021 HabanaLabs, Ltd. + * Copyright 2016-2022 HabanaLabs, Ltd. * All Rights Reserved. */ @@ -458,7 +458,6 @@ struct ecc_info_extract_params { u64 block_address; u32 num_memories; bool derr; - bool disable_clock_gating; }; static int gaudi_mmu_update_asid_hop0_addr(struct hl_device *hdev, u32 asid, @@ -1896,7 +1895,6 @@ static int gaudi_sw_init(struct hl_device *hdev) goto free_cpu_accessible_dma_pool; spin_lock_init(&gaudi->hw_queues_lock); - mutex_init(&gaudi->clk_gate_mutex); hdev->supports_sync_stream = true; hdev->supports_coresight = true; @@ -1946,8 +1944,6 @@ static int gaudi_sw_fini(struct hl_device *hdev) dma_pool_destroy(hdev->dma_pool); - mutex_destroy(&gaudi->clk_gate_mutex); - kfree(gaudi); return 0; @@ -3738,10 +3734,6 @@ static void gaudi_tpc_stall(struct hl_device *hdev) WREG32(mmTPC7_CFG_TPC_STALL, 1 << TPC0_CFG_TPC_STALL_V_SHIFT); } -static void gaudi_set_clock_gating(struct hl_device *hdev) -{ -} - static void gaudi_disable_clock_gating(struct hl_device *hdev) { u32 qman_offset; @@ -3810,8 +3802,6 @@ static void gaudi_halt_engines(struct hl_device *hdev, bool hard_reset, bool fw_ gaudi_stop_hbm_dma_qmans(hdev); gaudi_stop_pci_dma_qmans(hdev); - hdev->asic_funcs->disable_clock_gating(hdev); - msleep(wait_timeout_ms); gaudi_pci_dma_stall(hdev); @@ -4137,10 +4127,8 @@ static int gaudi_hw_init(struct hl_device *hdev) /* In case the clock gating was enabled in preboot we need to disable * it here before touching the MME/TPC registers. - * There is no need to take clk gating mutex because when this function - * runs, no other relevant code can run */ - hdev->asic_funcs->disable_clock_gating(hdev); + gaudi_disable_clock_gating(hdev); /* SRAM scrambler must be initialized after CPU is running from HBM */ gaudi_init_scrambler_sram(hdev); @@ -4166,8 +4154,6 @@ static int gaudi_hw_init(struct hl_device *hdev) gaudi_init_nic_qmans(hdev); - hdev->asic_funcs->set_clock_gating(hdev); - gaudi_enable_timestamp(hdev); /* MSI must be enabled before CPU queues and NIC are initialized */ @@ -4815,7 +4801,6 @@ static int gaudi_hbm_scrubbing(struct hl_device *hdev) static int gaudi_scrub_device_mem(struct hl_device *hdev, u64 addr, u64 size) { struct asic_fixed_properties *prop = &hdev->asic_prop; - struct gaudi_device *gaudi = hdev->asic_specific; int rc = 0; u64 val = 0; @@ -4850,17 +4835,11 @@ static int gaudi_scrub_device_mem(struct hl_device *hdev, u64 addr, u64 size) return rc; } - mutex_lock(&gaudi->clk_gate_mutex); - hdev->asic_funcs->disable_clock_gating(hdev); - /* Scrub HBM using all DMA channels in parallel */ rc = gaudi_hbm_scrubbing(hdev); if (rc) dev_err(hdev->dev, "Failed to clear HBM in mem scrub all\n"); - - hdev->asic_funcs->set_clock_gating(hdev); - mutex_unlock(&gaudi->clk_gate_mutex); } return rc; @@ -6344,7 +6323,6 @@ static int gaudi_debugfs_read_dma(struct hl_device *hdev, u64 addr, u32 size, void *blob_addr) { u32 dma_core_sts0, err_cause, cfg1, size_left, pos, size_to_dma; - struct gaudi_device *gaudi = hdev->asic_specific; u32 qm_glbl_sts0, qm_cgm_sts; u64 dma_offset, qm_offset; dma_addr_t dma_addr; @@ -6360,10 +6338,6 @@ static int gaudi_debugfs_read_dma(struct hl_device *hdev, u64 addr, u32 size, if (!kernel_addr) return -ENOMEM; - mutex_lock(&gaudi->clk_gate_mutex); - - hdev->asic_funcs->disable_clock_gating(hdev); - hdev->asic_funcs->hw_queues_lock(hdev); dma_id = gaudi_dma_assignment[GAUDI_PCI_DMA_1]; @@ -6448,10 +6422,6 @@ static int gaudi_debugfs_read_dma(struct hl_device *hdev, u64 addr, u32 size, out: hdev->asic_funcs->hw_queues_unlock(hdev); - hdev->asic_funcs->set_clock_gating(hdev); - - mutex_unlock(&gaudi->clk_gate_mutex); - hdev->asic_funcs->asic_dma_free_coherent(hdev, SZ_2M, kernel_addr, dma_addr); @@ -6499,10 +6469,6 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid) return; } - mutex_lock(&gaudi->clk_gate_mutex); - - hdev->asic_funcs->disable_clock_gating(hdev); - gaudi_mmu_prepare_reg(hdev, mmDMA0_QM_GLBL_NON_SECURE_PROPS_0, asid); gaudi_mmu_prepare_reg(hdev, mmDMA0_QM_GLBL_NON_SECURE_PROPS_1, asid); gaudi_mmu_prepare_reg(hdev, mmDMA0_QM_GLBL_NON_SECURE_PROPS_2, asid); @@ -6780,10 +6746,6 @@ static void gaudi_mmu_prepare(struct hl_device *hdev, u32 asid) gaudi_mmu_prepare_reg(hdev, mmPSOC_GLOBAL_CONF_TRACE_ARUSER, asid); gaudi_mmu_prepare_reg(hdev, mmPSOC_GLOBAL_CONF_TRACE_AWUSER, asid); - - hdev->asic_funcs->set_clock_gating(hdev); - - mutex_unlock(&gaudi->clk_gate_mutex); } static int gaudi_send_job_on_qman0(struct hl_device *hdev, @@ -7164,10 +7126,8 @@ static int gaudi_extract_ecc_info(struct hl_device *hdev, struct ecc_info_extract_params *params, u64 *ecc_address, u64 *ecc_syndrom, u8 *memory_wrapper_idx) { - struct gaudi_device *gaudi = hdev->asic_specific; u32 i, num_mem_regs, reg, err_bit; u64 err_addr, err_word = 0; - int rc = 0; num_mem_regs = params->num_memories / 32 + ((params->num_memories % 32) ? 1 : 0); @@ -7180,11 +7140,6 @@ static int gaudi_extract_ecc_info(struct hl_device *hdev, else err_addr = params->block_address + GAUDI_ECC_SERR0_OFFSET; - if (params->disable_clock_gating) { - mutex_lock(&gaudi->clk_gate_mutex); - hdev->asic_funcs->disable_clock_gating(hdev); - } - /* Set invalid wrapper index */ *memory_wrapper_idx = 0xFF; @@ -7201,8 +7156,7 @@ static int gaudi_extract_ecc_info(struct hl_device *hdev, if (*memory_wrapper_idx == 0xFF) { dev_err(hdev->dev, "ECC error information cannot be found\n"); - rc = -EINVAL; - goto enable_clk_gate; + return -EINVAL; } WREG32(params->block_address + GAUDI_ECC_MEM_SEL_OFFSET, @@ -7222,14 +7176,7 @@ static int gaudi_extract_ecc_info(struct hl_device *hdev, WREG32(params->block_address + GAUDI_ECC_MEM_INFO_CLR_OFFSET, reg); -enable_clk_gate: - if (params->disable_clock_gating) { - hdev->asic_funcs->set_clock_gating(hdev); - - mutex_unlock(&gaudi->clk_gate_mutex); - } - - return rc; + return 0; } /* @@ -7487,7 +7434,6 @@ static void gaudi_handle_ecc_event(struct hl_device *hdev, u16 event_type, params.block_address = mmTPC0_CFG_BASE + index * TPC_CFG_OFFSET; params.num_memories = 90; params.derr = false; - params.disable_clock_gating = true; extract_info_from_fw = false; break; case GAUDI_EVENT_TPC0_DERR ... GAUDI_EVENT_TPC7_DERR: @@ -7496,7 +7442,6 @@ static void gaudi_handle_ecc_event(struct hl_device *hdev, u16 event_type, mmTPC0_CFG_BASE + index * TPC_CFG_OFFSET; params.num_memories = 90; params.derr = true; - params.disable_clock_gating = true; extract_info_from_fw = false; break; case GAUDI_EVENT_MME0_ACC_SERR: @@ -7507,7 +7452,6 @@ static void gaudi_handle_ecc_event(struct hl_device *hdev, u16 event_type, params.block_address = mmMME0_ACC_BASE + index * MME_ACC_OFFSET; params.num_memories = 128; params.derr = false; - params.disable_clock_gating = true; extract_info_from_fw = false; break; case GAUDI_EVENT_MME0_ACC_DERR: @@ -7518,7 +7462,6 @@ static void gaudi_handle_ecc_event(struct hl_device *hdev, u16 event_type, params.block_address = mmMME0_ACC_BASE + index * MME_ACC_OFFSET; params.num_memories = 128; params.derr = true; - params.disable_clock_gating = true; extract_info_from_fw = false; break; case GAUDI_EVENT_MME0_SBAB_SERR: @@ -7530,7 +7473,6 @@ static void gaudi_handle_ecc_event(struct hl_device *hdev, u16 event_type, mmMME0_SBAB_BASE + index * MME_ACC_OFFSET; params.num_memories = 33; params.derr = false; - params.disable_clock_gating = true; extract_info_from_fw = false; break; case GAUDI_EVENT_MME0_SBAB_DERR: @@ -7542,7 +7484,6 @@ static void gaudi_handle_ecc_event(struct hl_device *hdev, u16 event_type, mmMME0_SBAB_BASE + index * MME_ACC_OFFSET; params.num_memories = 33; params.derr = true; - params.disable_clock_gating = true; extract_info_from_fw = false; break; default: @@ -7864,19 +7805,9 @@ static int gaudi_hbm_event_to_dev(u16 hbm_event_type) static bool gaudi_tpc_read_interrupts(struct hl_device *hdev, u8 tpc_id, char *interrupt_name) { - struct gaudi_device *gaudi = hdev->asic_specific; u32 tpc_offset = tpc_id * TPC_CFG_OFFSET, tpc_interrupts_cause, i; bool soft_reset_required = false; - /* Accessing the TPC_INTR_CAUSE registers requires disabling the clock - * gating, and thus cannot be done in CPU-CP and should be done instead - * by the driver. - */ - - mutex_lock(&gaudi->clk_gate_mutex); - - hdev->asic_funcs->disable_clock_gating(hdev); - tpc_interrupts_cause = RREG32(mmTPC0_CFG_TPC_INTR_CAUSE + tpc_offset) & TPC0_CFG_TPC_INTR_CAUSE_CAUSE_MASK; @@ -7894,10 +7825,6 @@ static bool gaudi_tpc_read_interrupts(struct hl_device *hdev, u8 tpc_id, /* Clear interrupts */ WREG32(mmTPC0_CFG_TPC_INTR_CAUSE + tpc_offset, 0); - hdev->asic_funcs->set_clock_gating(hdev); - - mutex_unlock(&gaudi->clk_gate_mutex); - return soft_reset_required; } @@ -8359,10 +8286,6 @@ static bool gaudi_is_device_idle(struct hl_device *hdev, u64 *mask_arr, u64 offset; int i, dma_id, port; - mutex_lock(&gaudi->clk_gate_mutex); - - hdev->asic_funcs->disable_clock_gating(hdev); - if (s) seq_puts(s, "\nDMA is_idle QM_GLBL_STS0 QM_CGM_STS DMA_CORE_STS0\n" @@ -8483,10 +8406,6 @@ static bool gaudi_is_device_idle(struct hl_device *hdev, u64 *mask_arr, if (s) seq_puts(s, "\n"); - hdev->asic_funcs->set_clock_gating(hdev); - - mutex_unlock(&gaudi->clk_gate_mutex); - return is_idle; } @@ -8526,10 +8445,8 @@ static int gaudi_get_eeprom_data(struct hl_device *hdev, void *data, * this function should be used only during initialization and/or after reset, * when there are no active users. */ -static int gaudi_run_tpc_kernel(struct hl_device *hdev, u64 tpc_kernel, - u32 tpc_id) +static int gaudi_run_tpc_kernel(struct hl_device *hdev, u64 tpc_kernel, u32 tpc_id) { - struct gaudi_device *gaudi = hdev->asic_specific; u64 kernel_timeout; u32 status, offset; int rc; @@ -8541,10 +8458,6 @@ static int gaudi_run_tpc_kernel(struct hl_device *hdev, u64 tpc_kernel, else kernel_timeout = HL_DEVICE_TIMEOUT_USEC; - mutex_lock(&gaudi->clk_gate_mutex); - - hdev->asic_funcs->disable_clock_gating(hdev); - WREG32(mmTPC0_CFG_QM_KERNEL_BASE_ADDRESS_LOW + offset, lower_32_bits(tpc_kernel)); WREG32(mmTPC0_CFG_QM_KERNEL_BASE_ADDRESS_HIGH + offset, @@ -8584,8 +8497,6 @@ static int gaudi_run_tpc_kernel(struct hl_device *hdev, u64 tpc_kernel, dev_err(hdev->dev, "Timeout while waiting for TPC%d icache prefetch\n", tpc_id); - hdev->asic_funcs->set_clock_gating(hdev); - mutex_unlock(&gaudi->clk_gate_mutex); return -EIO; } @@ -8609,8 +8520,6 @@ static int gaudi_run_tpc_kernel(struct hl_device *hdev, u64 tpc_kernel, dev_err(hdev->dev, "Timeout while waiting for TPC%d vector pipe\n", tpc_id); - hdev->asic_funcs->set_clock_gating(hdev); - mutex_unlock(&gaudi->clk_gate_mutex); return -EIO; } @@ -8622,9 +8531,6 @@ static int gaudi_run_tpc_kernel(struct hl_device *hdev, u64 tpc_kernel, 1000, kernel_timeout); - hdev->asic_funcs->set_clock_gating(hdev); - mutex_unlock(&gaudi->clk_gate_mutex); - if (rc) { dev_err(hdev->dev, "Timeout while waiting for TPC%d kernel to execute\n", @@ -9191,23 +9097,15 @@ static int gaudi_gen_sync_to_engine_map(struct hl_device *hdev, struct hl_sync_to_engine_map *map) { struct hl_state_dump_specs *sds = &hdev->state_dump_specs; - struct gaudi_device *gaudi = hdev->asic_specific; int i, j, rc; u32 reg_value; /* Iterate over TPC engines */ for (i = 0; i < sds->props[SP_NUM_OF_TPC_ENGINES]; ++i) { - /* TPC registered must be accessed with clock gating disabled */ - mutex_lock(&gaudi->clk_gate_mutex); - hdev->asic_funcs->disable_clock_gating(hdev); reg_value = RREG32(sds->props[SP_TPC0_CFG_SO] + sds->props[SP_NEXT_TPC] * i); - /* We can reenable clock_gating */ - hdev->asic_funcs->set_clock_gating(hdev); - mutex_unlock(&gaudi->clk_gate_mutex); - rc = gaudi_add_sync_to_engine_map_entry(map, reg_value, ENGINE_TPC, i); if (rc) @@ -9217,20 +9115,11 @@ static int gaudi_gen_sync_to_engine_map(struct hl_device *hdev, /* Iterate over MME engines */ for (i = 0; i < sds->props[SP_NUM_OF_MME_ENGINES]; ++i) { for (j = 0; j < sds->props[SP_SUB_MME_ENG_NUM]; ++j) { - /* MME registered must be accessed with clock gating - * disabled - */ - mutex_lock(&gaudi->clk_gate_mutex); - hdev->asic_funcs->disable_clock_gating(hdev); reg_value = RREG32(sds->props[SP_MME_CFG_SO] + sds->props[SP_NEXT_MME] * i + j * sizeof(u32)); - /* We can reenable clock_gating */ - hdev->asic_funcs->set_clock_gating(hdev); - mutex_unlock(&gaudi->clk_gate_mutex); - rc = gaudi_add_sync_to_engine_map_entry( map, reg_value, ENGINE_MME, i * sds->props[SP_SUB_MME_ENG_NUM] + j); @@ -9481,8 +9370,6 @@ static const struct hl_asic_funcs gaudi_funcs = { .mmu_invalidate_cache = gaudi_mmu_invalidate_cache, .mmu_invalidate_cache_range = gaudi_mmu_invalidate_cache_range, .send_heartbeat = gaudi_send_heartbeat, - .set_clock_gating = gaudi_set_clock_gating, - .disable_clock_gating = gaudi_disable_clock_gating, .debug_coresight = gaudi_debug_coresight, .is_device_idle = gaudi_is_device_idle, .non_hard_reset_late_init = gaudi_non_hard_reset_late_init, diff --git a/drivers/misc/habanalabs/gaudi/gaudiP.h b/drivers/misc/habanalabs/gaudi/gaudiP.h index caa858bf6edc..fdadcbf3ef80 100644 --- a/drivers/misc/habanalabs/gaudi/gaudiP.h +++ b/drivers/misc/habanalabs/gaudi/gaudiP.h @@ -312,8 +312,6 @@ struct gaudi_internal_qman_info { * struct gaudi_device - ASIC specific manage structure. * @cpucp_info_get: get information on device from CPU-CP * @hw_queues_lock: protects the H/W queues from concurrent access. - * @clk_gate_mutex: protects code areas that require clock gating to be disabled - * temporarily * @internal_qmans: Internal QMANs information. The array size is larger than * the actual number of internal queues because they are not in * consecutive order. @@ -336,7 +334,6 @@ struct gaudi_device { /* TODO: remove hw_queues_lock after moving to scheduler code */ spinlock_t hw_queues_lock; - struct mutex clk_gate_mutex; struct gaudi_internal_qman_info internal_qmans[GAUDI_QUEUE_ID_SIZE]; diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index fbcc7bbf44b3..954ef4d7bbf7 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -5391,16 +5391,6 @@ int goya_cpucp_info_get(struct hl_device *hdev) return 0; } -static void goya_set_clock_gating(struct hl_device *hdev) -{ - /* clock gating not supported in Goya */ -} - -static void goya_disable_clock_gating(struct hl_device *hdev) -{ - /* clock gating not supported in Goya */ -} - static bool goya_is_device_idle(struct hl_device *hdev, u64 *mask_arr, u8 mask_len, struct seq_file *s) { @@ -5734,8 +5724,6 @@ static const struct hl_asic_funcs goya_funcs = { .mmu_invalidate_cache = goya_mmu_invalidate_cache, .mmu_invalidate_cache_range = goya_mmu_invalidate_cache_range, .send_heartbeat = goya_send_heartbeat, - .set_clock_gating = goya_set_clock_gating, - .disable_clock_gating = goya_disable_clock_gating, .debug_coresight = goya_debug_coresight, .is_device_idle = goya_is_device_idle, .non_hard_reset_late_init = goya_non_hard_reset_late_init, -- cgit v1.3.1 From 2bf338f2ac69e3d41a6d45de1d9ac0d3afe109e6 Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Sat, 22 Jan 2022 20:14:24 +0200 Subject: habanalabs: make some MMU functions common Some MMU functions can be used by different versions of our MMUs, so move them to be common. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/habanalabs.h | 9 +++++ drivers/misc/habanalabs/common/mmu/mmu.c | 55 +++++++++++++++++++++++++++++ drivers/misc/habanalabs/common/mmu/mmu_v1.c | 45 +++++------------------ 3 files changed, 72 insertions(+), 37 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 24962807e2cf..e96f26e7e804 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -402,8 +402,11 @@ enum hl_device_hw_state { * @hop4_mask: mask to get the PTE address in hop 4. * @hop5_mask: mask to get the PTE address in hop 5. * @last_mask: mask to get the bit indicating this is the last hop. + * @pgt_size: size for page tables. * @page_size: default page size used to allocate memory. * @num_hops: The amount of hops supported by the translation table. + * @hop_table_size: HOP table size. + * @hop0_tables_total_size: total size for all HOP0 tables. * @host_resident: Should the MMU page table reside in host memory or in the * device DRAM. */ @@ -423,8 +426,11 @@ struct hl_mmu_properties { u64 hop4_mask; u64 hop5_mask; u64 last_mask; + u64 pgt_size; u32 page_size; u32 num_hops; + u32 hop_table_size; + u32 hop0_tables_total_size; u8 host_resident; }; @@ -3015,6 +3021,9 @@ int hl_mmu_unmap_contiguous(struct hl_ctx *ctx, u64 virt_addr, u32 size); int hl_mmu_invalidate_cache(struct hl_device *hdev, bool is_hard, u32 flags); int hl_mmu_invalidate_cache_range(struct hl_device *hdev, bool is_hard, u32 flags, u32 asid, u64 va, u64 size); +u64 hl_mmu_get_next_hop_addr(struct hl_ctx *ctx, u64 curr_pte); +u64 hl_mmu_get_hop_pte_phys_addr(struct hl_ctx *ctx, struct hl_mmu_properties *mmu_prop, + u8 hop_idx, u64 hop_addr, u64 virt_addr); void hl_mmu_swap_out(struct hl_ctx *ctx); void hl_mmu_swap_in(struct hl_ctx *ctx); int hl_mmu_if_set_funcs(struct hl_device *hdev); diff --git a/drivers/misc/habanalabs/common/mmu/mmu.c b/drivers/misc/habanalabs/common/mmu/mmu.c index 9153a1f55175..810b73421ce1 100644 --- a/drivers/misc/habanalabs/common/mmu/mmu.c +++ b/drivers/misc/habanalabs/common/mmu/mmu.c @@ -662,3 +662,58 @@ int hl_mmu_invalidate_cache_range(struct hl_device *hdev, bool is_hard, return rc; } +u64 hl_mmu_get_next_hop_addr(struct hl_ctx *ctx, u64 curr_pte) +{ + return (curr_pte & PAGE_PRESENT_MASK) ? (curr_pte & HOP_PHYS_ADDR_MASK) : ULLONG_MAX; +} + +/** + * hl_mmu_get_hop_pte_phys_addr() - extract PTE address from HOP + * @ctx: pointer to the context structure to initialize. + * @hop_idx: HOP index. + * @hop_addr: HOP address. + * @virt_addr: virtual address fro the translation. + * + * @return the matching PTE value on success, otherwise U64_MAX. + */ +u64 hl_mmu_get_hop_pte_phys_addr(struct hl_ctx *ctx, struct hl_mmu_properties *mmu_prop, + u8 hop_idx, u64 hop_addr, u64 virt_addr) +{ + u64 mask, shift; + + if (hop_idx >= mmu_prop->num_hops) { + dev_err_ratelimited(ctx->hdev->dev, "Invalid hop index %d\n", hop_idx); + return U64_MAX; + } + + /* currently max number of HOPs is 6 */ + switch (hop_idx) { + case 0: + mask = mmu_prop->hop0_mask; + shift = mmu_prop->hop0_shift; + break; + case 1: + mask = mmu_prop->hop1_mask; + shift = mmu_prop->hop1_shift; + break; + case 2: + mask = mmu_prop->hop2_mask; + shift = mmu_prop->hop2_shift; + break; + case 3: + mask = mmu_prop->hop3_mask; + shift = mmu_prop->hop3_shift; + break; + case 4: + mask = mmu_prop->hop4_mask; + shift = mmu_prop->hop4_shift; + break; + default: + mask = mmu_prop->hop5_mask; + shift = mmu_prop->hop5_shift; + break; + } + + return hop_addr + ctx->hdev->asic_prop.mmu_pte_size * ((virt_addr & mask) >> shift); +} + diff --git a/drivers/misc/habanalabs/common/mmu/mmu_v1.c b/drivers/misc/habanalabs/common/mmu/mmu_v1.c index 3cadef97817d..d03786d0c407 100644 --- a/drivers/misc/habanalabs/common/mmu/mmu_v1.c +++ b/drivers/misc/habanalabs/common/mmu/mmu_v1.c @@ -217,18 +217,10 @@ static inline u64 get_hop4_pte_addr(struct hl_ctx *ctx, mmu_prop->hop4_shift); } -static inline u64 get_next_hop_addr(struct hl_ctx *ctx, u64 curr_pte) -{ - if (curr_pte & PAGE_PRESENT_MASK) - return curr_pte & HOP_PHYS_ADDR_MASK; - else - return ULLONG_MAX; -} - static inline u64 get_alloc_next_hop_addr(struct hl_ctx *ctx, u64 curr_pte, bool *is_new_hop) { - u64 hop_addr = get_next_hop_addr(ctx, curr_pte); + u64 hop_addr = hl_mmu_get_next_hop_addr(ctx, curr_pte); if (hop_addr == ULLONG_MAX) { hop_addr = alloc_hop(ctx); @@ -546,7 +538,7 @@ static int _hl_mmu_v1_unmap(struct hl_ctx *ctx, curr_pte = *(u64 *) (uintptr_t) hop0_pte_addr; - hop1_addr = get_next_hop_addr(ctx, curr_pte); + hop1_addr = hl_mmu_get_next_hop_addr(ctx, curr_pte); if (hop1_addr == ULLONG_MAX) goto not_mapped; @@ -555,7 +547,7 @@ static int _hl_mmu_v1_unmap(struct hl_ctx *ctx, curr_pte = *(u64 *) (uintptr_t) hop1_pte_addr; - hop2_addr = get_next_hop_addr(ctx, curr_pte); + hop2_addr = hl_mmu_get_next_hop_addr(ctx, curr_pte); if (hop2_addr == ULLONG_MAX) goto not_mapped; @@ -564,7 +556,7 @@ static int _hl_mmu_v1_unmap(struct hl_ctx *ctx, curr_pte = *(u64 *) (uintptr_t) hop2_pte_addr; - hop3_addr = get_next_hop_addr(ctx, curr_pte); + hop3_addr = hl_mmu_get_next_hop_addr(ctx, curr_pte); if (hop3_addr == ULLONG_MAX) goto not_mapped; @@ -582,7 +574,7 @@ static int _hl_mmu_v1_unmap(struct hl_ctx *ctx, } if (!is_huge) { - hop4_addr = get_next_hop_addr(ctx, curr_pte); + hop4_addr = hl_mmu_get_next_hop_addr(ctx, curr_pte); if (hop4_addr == ULLONG_MAX) goto not_mapped; @@ -845,27 +837,6 @@ static void hl_mmu_v1_swap_in(struct hl_ctx *ctx) } -static inline u64 get_hop_pte_addr(struct hl_ctx *ctx, - struct hl_mmu_properties *mmu_prop, - int hop_num, u64 hop_addr, u64 virt_addr) -{ - switch (hop_num) { - case 0: - return get_hop0_pte_addr(ctx, mmu_prop, hop_addr, virt_addr); - case 1: - return get_hop1_pte_addr(ctx, mmu_prop, hop_addr, virt_addr); - case 2: - return get_hop2_pte_addr(ctx, mmu_prop, hop_addr, virt_addr); - case 3: - return get_hop3_pte_addr(ctx, mmu_prop, hop_addr, virt_addr); - case 4: - return get_hop4_pte_addr(ctx, mmu_prop, hop_addr, virt_addr); - default: - break; - } - return U64_MAX; -} - static int hl_mmu_v1_get_tlb_info(struct hl_ctx *ctx, u64 virt_addr, struct hl_mmu_hop_info *hops) { @@ -906,7 +877,7 @@ static int hl_mmu_v1_get_tlb_info(struct hl_ctx *ctx, u64 virt_addr, hops->hop_info[0].hop_addr = get_phys_hop0_addr(ctx); hops->hop_info[0].hop_pte_addr = - get_hop_pte_addr(ctx, mmu_prop, 0, + hl_mmu_get_hop_pte_phys_addr(ctx, mmu_prop, 0, hops->hop_info[0].hop_addr, virt_addr); hops->hop_info[0].hop_pte_val = hdev->asic_funcs->read_pte(hdev, @@ -914,13 +885,13 @@ static int hl_mmu_v1_get_tlb_info(struct hl_ctx *ctx, u64 virt_addr, for (i = 1 ; i < used_hops ; i++) { hops->hop_info[i].hop_addr = - get_next_hop_addr(ctx, + hl_mmu_get_next_hop_addr(ctx, hops->hop_info[i - 1].hop_pte_val); if (hops->hop_info[i].hop_addr == ULLONG_MAX) return -EFAULT; hops->hop_info[i].hop_pte_addr = - get_hop_pte_addr(ctx, mmu_prop, i, + hl_mmu_get_hop_pte_phys_addr(ctx, mmu_prop, i, hops->hop_info[i].hop_addr, virt_addr); hops->hop_info[i].hop_pte_val = -- cgit v1.3.1 From bfbe9cbedd41402e3be3c5189a6b82933a5cd76d Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Sat, 8 Jan 2022 13:23:54 +0200 Subject: habanalabs: sysfs functions should be in sysfs.c Move common sysfs store/show functions to sysfs.c file for consistency. This is part of a patch-set to remove hwmgr.c Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/habanalabs.h | 3 +- drivers/misc/habanalabs/common/hwmgr.c | 72 ----------------------------- drivers/misc/habanalabs/common/sysfs.c | 70 +++++++++++++++++++++++++++- drivers/misc/habanalabs/gaudi/gaudi.c | 2 +- 4 files changed, 71 insertions(+), 76 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index e96f26e7e804..571998899253 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -3125,8 +3125,7 @@ int hl_get_power(struct hl_device *hdev, int hl_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk); void hl_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq); -void hl_add_device_attr(struct hl_device *hdev, - struct attribute_group *dev_attr_grp); +void hl_sysfs_add_dev_clk_attr(struct hl_device *hdev, struct attribute_group *dev_attr_grp); void hw_sob_get(struct hl_hw_sob *hw_sob); void hw_sob_put(struct hl_hw_sob *hw_sob); void hl_encaps_handle_do_release(struct kref *ref); diff --git a/drivers/misc/habanalabs/common/hwmgr.c b/drivers/misc/habanalabs/common/hwmgr.c index 5451019f143f..f0e5417560c3 100644 --- a/drivers/misc/habanalabs/common/hwmgr.c +++ b/drivers/misc/habanalabs/common/hwmgr.c @@ -43,75 +43,3 @@ int hl_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk) return 0; } - -static ssize_t clk_max_freq_mhz_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hl_device *hdev = dev_get_drvdata(dev); - long value; - - if (!hl_device_operational(hdev, NULL)) - return -ENODEV; - - value = hl_get_frequency(hdev, hdev->asic_prop.clk_pll_index, false); - - hdev->asic_prop.max_freq_value = value; - - return sprintf(buf, "%lu\n", (value / 1000 / 1000)); -} - -static ssize_t clk_max_freq_mhz_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct hl_device *hdev = dev_get_drvdata(dev); - int rc; - u64 value; - - if (!hl_device_operational(hdev, NULL)) { - count = -ENODEV; - goto fail; - } - - rc = kstrtoull(buf, 0, &value); - if (rc) { - count = -EINVAL; - goto fail; - } - - hdev->asic_prop.max_freq_value = value * 1000 * 1000; - - hl_set_frequency(hdev, hdev->asic_prop.clk_pll_index, - hdev->asic_prop.max_freq_value); - -fail: - return count; -} - -static ssize_t clk_cur_freq_mhz_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hl_device *hdev = dev_get_drvdata(dev); - long value; - - if (!hl_device_operational(hdev, NULL)) - return -ENODEV; - - value = hl_get_frequency(hdev, hdev->asic_prop.clk_pll_index, true); - - return sprintf(buf, "%lu\n", (value / 1000 / 1000)); -} - -static DEVICE_ATTR_RW(clk_max_freq_mhz); -static DEVICE_ATTR_RO(clk_cur_freq_mhz); - -static struct attribute *hl_dev_attrs[] = { - &dev_attr_clk_max_freq_mhz.attr, - &dev_attr_clk_cur_freq_mhz.attr, - NULL, -}; - -void hl_add_device_attr(struct hl_device *hdev, - struct attribute_group *dev_attr_grp) -{ - dev_attr_grp->attrs = hl_dev_attrs; -} diff --git a/drivers/misc/habanalabs/common/sysfs.c b/drivers/misc/habanalabs/common/sysfs.c index 45c715325e2a..d66cf43788d8 100644 --- a/drivers/misc/habanalabs/common/sysfs.c +++ b/drivers/misc/habanalabs/common/sysfs.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright 2016-2019 HabanaLabs, Ltd. + * Copyright 2016-2022 HabanaLabs, Ltd. * All Rights Reserved. */ @@ -109,6 +109,69 @@ void hl_set_max_power(struct hl_device *hdev) dev_err(hdev->dev, "Failed to set max power, error %d\n", rc); } +static ssize_t clk_max_freq_mhz_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct hl_device *hdev = dev_get_drvdata(dev); + long value; + + if (!hl_device_operational(hdev, NULL)) + return -ENODEV; + + value = hl_get_frequency(hdev, hdev->asic_prop.clk_pll_index, false); + + hdev->asic_prop.max_freq_value = value; + + return sprintf(buf, "%lu\n", (value / 1000 / 1000)); +} + +static ssize_t clk_max_freq_mhz_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct hl_device *hdev = dev_get_drvdata(dev); + int rc; + u64 value; + + if (!hl_device_operational(hdev, NULL)) { + count = -ENODEV; + goto fail; + } + + rc = kstrtoull(buf, 0, &value); + if (rc) { + count = -EINVAL; + goto fail; + } + + hdev->asic_prop.max_freq_value = value * 1000 * 1000; + + hl_set_frequency(hdev, hdev->asic_prop.clk_pll_index, hdev->asic_prop.max_freq_value); + +fail: + return count; +} + +static ssize_t clk_cur_freq_mhz_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct hl_device *hdev = dev_get_drvdata(dev); + long value; + + if (!hl_device_operational(hdev, NULL)) + return -ENODEV; + + value = hl_get_frequency(hdev, hdev->asic_prop.clk_pll_index, true); + + return sprintf(buf, "%lu\n", (value / 1000 / 1000)); +} + +static DEVICE_ATTR_RW(clk_max_freq_mhz); +static DEVICE_ATTR_RO(clk_cur_freq_mhz); + +static struct attribute *hl_dev_clk_attrs[] = { + &dev_attr_clk_max_freq_mhz.attr, + &dev_attr_clk_cur_freq_mhz.attr, + NULL, +}; + static ssize_t uboot_ver_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -463,6 +526,11 @@ static const struct attribute_group *hl_dev_inference_attr_groups[] = { NULL, }; +void hl_sysfs_add_dev_clk_attr(struct hl_device *hdev, struct attribute_group *dev_attr_grp) +{ + dev_attr_grp->attrs = hl_dev_clk_attrs; +} + int hl_sysfs_init(struct hl_device *hdev) { int rc; diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 16637d629e67..f096cfc03bf3 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -9361,7 +9361,7 @@ static const struct hl_asic_funcs gaudi_funcs = { .debugfs_read64 = gaudi_debugfs_read64, .debugfs_write64 = gaudi_debugfs_write64, .debugfs_read_dma = gaudi_debugfs_read_dma, - .add_device_attr = hl_add_device_attr, + .add_device_attr = hl_sysfs_add_dev_clk_attr, .handle_eqe = gaudi_handle_eqe, .set_pll_profile = hl_set_pll_profile, .get_events_stat = gaudi_get_events_stat, -- cgit v1.3.1 From 9e2884ce989aa3c6e5a6c69b83664376cd2d98fd Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Sat, 8 Jan 2022 21:40:06 +0200 Subject: habanalabs: get clk is common function Retrieving the clock from the f/w is done exactly the same in ALL our ASICs. Therefore, no real justification for doing it as an ASIC-specific function. The only thing is we need to check if we are running on simulator, which doesn't require ASIC-specific callback. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/habanalabs.h | 7 ++----- drivers/misc/habanalabs/common/habanalabs_ioctl.c | 9 ++++----- drivers/misc/habanalabs/common/hwmgr.c | 13 ++++++++----- drivers/misc/habanalabs/gaudi/gaudi.c | 1 - drivers/misc/habanalabs/goya/goya.c | 3 +-- 5 files changed, 15 insertions(+), 18 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 571998899253..ecfdfec7abdc 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 * - * Copyright 2016-2021 HabanaLabs, Ltd. + * Copyright 2016-2022 HabanaLabs, Ltd. * All Rights Reserved. * */ @@ -1190,7 +1190,6 @@ struct fw_load_mgr { * @halt_coresight: stop the ETF and ETR traces. * @ctx_init: context dependent initialization. * @ctx_fini: context dependent cleanup. - * @get_clk_rate: Retrieve the ASIC current and maximum clock rate in MHz * @get_queue_id_for_cq: Get the H/W queue id related to the given CQ index. * @load_firmware_to_device: load the firmware to the device's memory * @load_boot_fit_to_device: load boot fit to device's memory @@ -1321,7 +1320,6 @@ struct hl_asic_funcs { void (*halt_coresight)(struct hl_device *hdev, struct hl_ctx *ctx); int (*ctx_init)(struct hl_ctx *ctx); void (*ctx_fini)(struct hl_ctx *ctx); - int (*get_clk_rate)(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk); u32 (*get_queue_id_for_cq)(struct hl_device *hdev, u32 cq_idx); int (*load_firmware_to_device)(struct hl_device *hdev); int (*load_boot_fit_to_device)(struct hl_device *hdev); @@ -3122,8 +3120,7 @@ int hl_set_power(struct hl_device *hdev, int sensor_index, u32 attr, long value); int hl_get_power(struct hl_device *hdev, int sensor_index, u32 attr, long *value); -int hl_get_clk_rate(struct hl_device *hdev, - u32 *cur_clk, u32 *max_clk); +int hl_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk); void hl_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq); void hl_sysfs_add_dev_clk_attr(struct hl_device *hdev, struct attribute_group *dev_attr_grp); void hw_sob_get(struct hl_hw_sob *hw_sob); diff --git a/drivers/misc/habanalabs/common/habanalabs_ioctl.c b/drivers/misc/habanalabs/common/habanalabs_ioctl.c index 3ba3a8ffda3e..ed516f911ee2 100644 --- a/drivers/misc/habanalabs/common/habanalabs_ioctl.c +++ b/drivers/misc/habanalabs/common/habanalabs_ioctl.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright 2016-2019 HabanaLabs, Ltd. + * Copyright 2016-2022 HabanaLabs, Ltd. * All Rights Reserved. */ @@ -251,13 +251,12 @@ static int get_clk_rate(struct hl_device *hdev, struct hl_info_args *args) if ((!max_size) || (!out)) return -EINVAL; - rc = hdev->asic_funcs->get_clk_rate(hdev, &clk_rate.cur_clk_rate_mhz, - &clk_rate.max_clk_rate_mhz); + rc = hl_get_clk_rate(hdev, &clk_rate.cur_clk_rate_mhz, &clk_rate.max_clk_rate_mhz); if (rc) return rc; - return copy_to_user(out, &clk_rate, - min((size_t) max_size, sizeof(clk_rate))) ? -EFAULT : 0; + return copy_to_user(out, &clk_rate, min_t(size_t, max_size, sizeof(clk_rate))) + ? -EFAULT : 0; } static int get_reset_count(struct hl_device *hdev, struct hl_info_args *args) diff --git a/drivers/misc/habanalabs/common/hwmgr.c b/drivers/misc/habanalabs/common/hwmgr.c index f0e5417560c3..e96126b46056 100644 --- a/drivers/misc/habanalabs/common/hwmgr.c +++ b/drivers/misc/habanalabs/common/hwmgr.c @@ -20,11 +20,16 @@ int hl_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk) if (!hl_device_operational(hdev, NULL)) return -ENODEV; + if (!hdev->pdev) { + *cur_clk = 0; + *max_clk = 0; + return 0; + } + value = hl_get_frequency(hdev, hdev->asic_prop.clk_pll_index, false); if (value < 0) { - dev_err(hdev->dev, "Failed to retrieve device max clock %ld\n", - value); + dev_err(hdev->dev, "Failed to retrieve device max clock %ld\n", value); return value; } @@ -33,9 +38,7 @@ int hl_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk) value = hl_get_frequency(hdev, hdev->asic_prop.clk_pll_index, true); if (value < 0) { - dev_err(hdev->dev, - "Failed to retrieve device current clock %ld\n", - value); + dev_err(hdev->dev, "Failed to retrieve device current clock %ld\n", value); return value; } diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index f096cfc03bf3..744d4305db40 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -9385,7 +9385,6 @@ static const struct hl_asic_funcs gaudi_funcs = { .halt_coresight = gaudi_halt_coresight, .ctx_init = gaudi_ctx_init, .ctx_fini = gaudi_ctx_fini, - .get_clk_rate = hl_get_clk_rate, .get_queue_id_for_cq = gaudi_get_queue_id_for_cq, .load_firmware_to_device = gaudi_load_firmware_to_device, .load_boot_fit_to_device = gaudi_load_boot_fit_to_device, diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 954ef4d7bbf7..318b97c53ed7 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright 2016-2021 HabanaLabs, Ltd. + * Copyright 2016-2022 HabanaLabs, Ltd. * All Rights Reserved. */ @@ -5739,7 +5739,6 @@ static const struct hl_asic_funcs goya_funcs = { .halt_coresight = goya_halt_coresight, .ctx_init = goya_ctx_init, .ctx_fini = goya_ctx_fini, - .get_clk_rate = hl_get_clk_rate, .get_queue_id_for_cq = goya_get_queue_id_for_cq, .load_firmware_to_device = goya_load_firmware_to_device, .load_boot_fit_to_device = goya_load_boot_fit_to_device, -- cgit v1.3.1 From 8d96430784fc810e6adfa61bf6bf56cdcdeb7a69 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Sat, 8 Jan 2022 21:57:57 +0200 Subject: habanalabs: remove hwmgr.c The two remaining functions in this file belong to firmware_if.c, as they communicate with the firmware. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/Makefile | 2 +- drivers/misc/habanalabs/common/firmware_if.c | 42 +++++++++++++++++++- drivers/misc/habanalabs/common/habanalabs.h | 4 +- drivers/misc/habanalabs/common/habanalabs_ioctl.c | 2 +- drivers/misc/habanalabs/common/hwmgr.c | 48 ----------------------- drivers/misc/habanalabs/gaudi/gaudi.c | 2 +- 6 files changed, 46 insertions(+), 54 deletions(-) delete mode 100644 drivers/misc/habanalabs/common/hwmgr.c (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/Makefile b/drivers/misc/habanalabs/common/Makefile index 82c3824cad00..6ebe3c7001ff 100644 --- a/drivers/misc/habanalabs/common/Makefile +++ b/drivers/misc/habanalabs/common/Makefile @@ -11,4 +11,4 @@ HL_COMMON_FILES := common/habanalabs_drv.o common/device.o common/context.o \ common/command_buffer.o common/hw_queue.o common/irq.o \ common/sysfs.o common/hwmon.o common/memory.o \ common/command_submission.o common/firmware_if.o \ - common/state_dump.o common/hwmgr.o + common/state_dump.o diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 6775c5c3166b..f7ccbd288510 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright 2016-2021 HabanaLabs, Ltd. + * Copyright 2016-2022 HabanaLabs, Ltd. * All Rights Reserved. */ @@ -2682,3 +2682,43 @@ int hl_fw_init_cpu(struct hl_device *hdev) hl_fw_dynamic_init_cpu(hdev, fw_loader) : hl_fw_static_init_cpu(hdev, fw_loader); } + +void hl_fw_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq) +{ + hl_set_frequency(hdev, hdev->asic_prop.clk_pll_index, + hdev->asic_prop.max_freq_value); +} + +int hl_fw_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk) +{ + long value; + + if (!hl_device_operational(hdev, NULL)) + return -ENODEV; + + if (!hdev->pdev) { + *cur_clk = 0; + *max_clk = 0; + return 0; + } + + value = hl_get_frequency(hdev, hdev->asic_prop.clk_pll_index, false); + + if (value < 0) { + dev_err(hdev->dev, "Failed to retrieve device max clock %ld\n", value); + return value; + } + + *max_clk = (value / 1000 / 1000); + + value = hl_get_frequency(hdev, hdev->asic_prop.clk_pll_index, true); + + if (value < 0) { + dev_err(hdev->dev, "Failed to retrieve device current clock %ld\n", value); + return value; + } + + *cur_clk = (value / 1000 / 1000); + + return 0; +} diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index ecfdfec7abdc..c782d44d58d5 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -3120,8 +3120,8 @@ int hl_set_power(struct hl_device *hdev, int sensor_index, u32 attr, long value); int hl_get_power(struct hl_device *hdev, int sensor_index, u32 attr, long *value); -int hl_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk); -void hl_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq); +int hl_fw_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk); +void hl_fw_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq); void hl_sysfs_add_dev_clk_attr(struct hl_device *hdev, struct attribute_group *dev_attr_grp); void hw_sob_get(struct hl_hw_sob *hw_sob); void hw_sob_put(struct hl_hw_sob *hw_sob); diff --git a/drivers/misc/habanalabs/common/habanalabs_ioctl.c b/drivers/misc/habanalabs/common/habanalabs_ioctl.c index ed516f911ee2..d19097576b05 100644 --- a/drivers/misc/habanalabs/common/habanalabs_ioctl.c +++ b/drivers/misc/habanalabs/common/habanalabs_ioctl.c @@ -251,7 +251,7 @@ static int get_clk_rate(struct hl_device *hdev, struct hl_info_args *args) if ((!max_size) || (!out)) return -EINVAL; - rc = hl_get_clk_rate(hdev, &clk_rate.cur_clk_rate_mhz, &clk_rate.max_clk_rate_mhz); + rc = hl_fw_get_clk_rate(hdev, &clk_rate.cur_clk_rate_mhz, &clk_rate.max_clk_rate_mhz); if (rc) return rc; diff --git a/drivers/misc/habanalabs/common/hwmgr.c b/drivers/misc/habanalabs/common/hwmgr.c deleted file mode 100644 index e96126b46056..000000000000 --- a/drivers/misc/habanalabs/common/hwmgr.c +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -/* - * Copyright 2019-2021 HabanaLabs, Ltd. - * All Rights Reserved. - */ - -#include "habanalabs.h" - -void hl_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq) -{ - hl_set_frequency(hdev, hdev->asic_prop.clk_pll_index, - hdev->asic_prop.max_freq_value); -} - -int hl_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk) -{ - long value; - - if (!hl_device_operational(hdev, NULL)) - return -ENODEV; - - if (!hdev->pdev) { - *cur_clk = 0; - *max_clk = 0; - return 0; - } - - value = hl_get_frequency(hdev, hdev->asic_prop.clk_pll_index, false); - - if (value < 0) { - dev_err(hdev->dev, "Failed to retrieve device max clock %ld\n", value); - return value; - } - - *max_clk = (value / 1000 / 1000); - - value = hl_get_frequency(hdev, hdev->asic_prop.clk_pll_index, true); - - if (value < 0) { - dev_err(hdev->dev, "Failed to retrieve device current clock %ld\n", value); - return value; - } - - *cur_clk = (value / 1000 / 1000); - - return 0; -} diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 744d4305db40..ae86147dfde4 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -9363,7 +9363,7 @@ static const struct hl_asic_funcs gaudi_funcs = { .debugfs_read_dma = gaudi_debugfs_read_dma, .add_device_attr = hl_sysfs_add_dev_clk_attr, .handle_eqe = gaudi_handle_eqe, - .set_pll_profile = hl_set_pll_profile, + .set_pll_profile = hl_fw_set_pll_profile, .get_events_stat = gaudi_get_events_stat, .read_pte = gaudi_read_pte, .write_pte = gaudi_write_pte, -- cgit v1.3.1 From 092a31c5266282838e98fffc5e80b50e53b7bec9 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Sat, 8 Jan 2022 22:35:09 +0200 Subject: habanalabs: move more f/w functions to firmware_if.c For better maintainability, try to concentrate all the common functions that communicate with the f/w in firmware_if.c Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/device.c | 6 +- drivers/misc/habanalabs/common/firmware_if.c | 101 +++++++++++++++++++++++- drivers/misc/habanalabs/common/habanalabs.h | 44 ++++------- drivers/misc/habanalabs/common/sysfs.c | 110 ++------------------------- drivers/misc/habanalabs/goya/goya_hwmgr.c | 38 ++++----- 5 files changed, 141 insertions(+), 158 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index 9955e0d3502b..c98a0a81e7d5 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright 2016-2021 HabanaLabs, Ltd. + * Copyright 2016-2022 HabanaLabs, Ltd. * All Rights Reserved. */ @@ -1228,7 +1228,7 @@ kill_processes: goto out_err; } - hl_set_max_power(hdev); + hl_fw_set_max_power(hdev); } else { rc = hdev->asic_funcs->non_hard_reset_late_init(hdev); if (rc) { @@ -1534,7 +1534,7 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass) /* Need to call this again because the max power might change, * depending on card type for certain ASICs */ - hl_set_max_power(hdev); + hl_fw_set_max_power(hdev); /* * hl_hwmon_init() must be called after device_late_init(), because only diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index f7ccbd288510..508ee349f4e4 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -2685,7 +2685,7 @@ int hl_fw_init_cpu(struct hl_device *hdev) void hl_fw_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq) { - hl_set_frequency(hdev, hdev->asic_prop.clk_pll_index, + hl_fw_set_frequency(hdev, hdev->asic_prop.clk_pll_index, hdev->asic_prop.max_freq_value); } @@ -2702,7 +2702,7 @@ int hl_fw_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk) return 0; } - value = hl_get_frequency(hdev, hdev->asic_prop.clk_pll_index, false); + value = hl_fw_get_frequency(hdev, hdev->asic_prop.clk_pll_index, false); if (value < 0) { dev_err(hdev->dev, "Failed to retrieve device max clock %ld\n", value); @@ -2711,7 +2711,7 @@ int hl_fw_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk) *max_clk = (value / 1000 / 1000); - value = hl_get_frequency(hdev, hdev->asic_prop.clk_pll_index, true); + value = hl_fw_get_frequency(hdev, hdev->asic_prop.clk_pll_index, true); if (value < 0) { dev_err(hdev->dev, "Failed to retrieve device current clock %ld\n", value); @@ -2722,3 +2722,98 @@ int hl_fw_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk) return 0; } + +long hl_fw_get_frequency(struct hl_device *hdev, u32 pll_index, bool curr) +{ + struct cpucp_packet pkt; + u32 used_pll_idx; + u64 result; + int rc; + + rc = get_used_pll_index(hdev, pll_index, &used_pll_idx); + if (rc) + return rc; + + memset(&pkt, 0, sizeof(pkt)); + + if (curr) + pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_CURR_GET << + CPUCP_PKT_CTL_OPCODE_SHIFT); + else + pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_GET << CPUCP_PKT_CTL_OPCODE_SHIFT); + + pkt.pll_index = cpu_to_le32((u32)used_pll_idx); + + rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, &result); + + if (rc) { + dev_err(hdev->dev, "Failed to get frequency of PLL %d, error %d\n", + used_pll_idx, rc); + return rc; + } + + return (long) result; +} + +void hl_fw_set_frequency(struct hl_device *hdev, u32 pll_index, u64 freq) +{ + struct cpucp_packet pkt; + u32 used_pll_idx; + int rc; + + rc = get_used_pll_index(hdev, pll_index, &used_pll_idx); + if (rc) + return; + + memset(&pkt, 0, sizeof(pkt)); + + pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_SET << CPUCP_PKT_CTL_OPCODE_SHIFT); + pkt.pll_index = cpu_to_le32((u32)used_pll_idx); + pkt.value = cpu_to_le64(freq); + + rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, NULL); + + if (rc) + dev_err(hdev->dev, "Failed to set frequency to PLL %d, error %d\n", + used_pll_idx, rc); +} + +u64 hl_fw_get_max_power(struct hl_device *hdev) +{ + struct cpucp_packet pkt; + u64 result; + int rc; + + memset(&pkt, 0, sizeof(pkt)); + + pkt.ctl = cpu_to_le32(CPUCP_PACKET_MAX_POWER_GET << CPUCP_PKT_CTL_OPCODE_SHIFT); + + rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, &result); + + if (rc) { + dev_err(hdev->dev, "Failed to get max power, error %d\n", rc); + return (u64) rc; + } + + return result; +} + +void hl_fw_set_max_power(struct hl_device *hdev) +{ + struct cpucp_packet pkt; + int rc; + + /* TODO: remove this after simulator supports this packet */ + if (!hdev->pdev) + return; + + memset(&pkt, 0, sizeof(pkt)); + + pkt.ctl = cpu_to_le32(CPUCP_PACKET_MAX_POWER_SET << CPUCP_PKT_CTL_OPCODE_SHIFT); + pkt.value = cpu_to_le64(hdev->max_power); + + rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), 0, NULL); + + if (rc) + dev_err(hdev->dev, "Failed to set max power, error %d\n", rc); +} diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index c782d44d58d5..2bf73e5ce47f 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -3092,37 +3092,25 @@ enum pci_region hl_get_pci_memory_region(struct hl_device *hdev, u64 addr); int hl_pci_init(struct hl_device *hdev); void hl_pci_fini(struct hl_device *hdev); -long hl_get_frequency(struct hl_device *hdev, u32 pll_index, - bool curr); -void hl_set_frequency(struct hl_device *hdev, u32 pll_index, - u64 freq); -int hl_get_temperature(struct hl_device *hdev, - int sensor_index, u32 attr, long *value); -int hl_set_temperature(struct hl_device *hdev, - int sensor_index, u32 attr, long value); -int hl_get_voltage(struct hl_device *hdev, - int sensor_index, u32 attr, long *value); -int hl_get_current(struct hl_device *hdev, - int sensor_index, u32 attr, long *value); -int hl_get_fan_speed(struct hl_device *hdev, - int sensor_index, u32 attr, long *value); -int hl_get_pwm_info(struct hl_device *hdev, - int sensor_index, u32 attr, long *value); -void hl_set_pwm_info(struct hl_device *hdev, int sensor_index, u32 attr, - long value); -u64 hl_get_max_power(struct hl_device *hdev); -void hl_set_max_power(struct hl_device *hdev); -int hl_set_voltage(struct hl_device *hdev, - int sensor_index, u32 attr, long value); -int hl_set_current(struct hl_device *hdev, - int sensor_index, u32 attr, long value); -int hl_set_power(struct hl_device *hdev, - int sensor_index, u32 attr, long value); -int hl_get_power(struct hl_device *hdev, - int sensor_index, u32 attr, long *value); +long hl_fw_get_frequency(struct hl_device *hdev, u32 pll_index, bool curr); +void hl_fw_set_frequency(struct hl_device *hdev, u32 pll_index, u64 freq); +int hl_get_temperature(struct hl_device *hdev, int sensor_index, u32 attr, long *value); +int hl_set_temperature(struct hl_device *hdev, int sensor_index, u32 attr, long value); +int hl_get_voltage(struct hl_device *hdev, int sensor_index, u32 attr, long *value); +int hl_get_current(struct hl_device *hdev, int sensor_index, u32 attr, long *value); +int hl_get_fan_speed(struct hl_device *hdev, int sensor_index, u32 attr, long *value); +int hl_get_pwm_info(struct hl_device *hdev, int sensor_index, u32 attr, long *value); +void hl_set_pwm_info(struct hl_device *hdev, int sensor_index, u32 attr, long value); +u64 hl_fw_get_max_power(struct hl_device *hdev); +void hl_fw_set_max_power(struct hl_device *hdev); +int hl_set_voltage(struct hl_device *hdev, int sensor_index, u32 attr, long value); +int hl_set_current(struct hl_device *hdev, int sensor_index, u32 attr, long value); +int hl_set_power(struct hl_device *hdev, int sensor_index, u32 attr, long value); +int hl_get_power(struct hl_device *hdev, int sensor_index, u32 attr, long *value); int hl_fw_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk); void hl_fw_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq); void hl_sysfs_add_dev_clk_attr(struct hl_device *hdev, struct attribute_group *dev_attr_grp); + void hw_sob_get(struct hl_hw_sob *hw_sob); void hw_sob_put(struct hl_hw_sob *hw_sob); void hl_encaps_handle_do_release(struct kref *ref); diff --git a/drivers/misc/habanalabs/common/sysfs.c b/drivers/misc/habanalabs/common/sysfs.c index d66cf43788d8..ce3538d36bb7 100644 --- a/drivers/misc/habanalabs/common/sysfs.c +++ b/drivers/misc/habanalabs/common/sysfs.c @@ -9,106 +9,6 @@ #include -long hl_get_frequency(struct hl_device *hdev, u32 pll_index, bool curr) -{ - struct cpucp_packet pkt; - u32 used_pll_idx; - u64 result; - int rc; - - rc = get_used_pll_index(hdev, pll_index, &used_pll_idx); - if (rc) - return rc; - - memset(&pkt, 0, sizeof(pkt)); - - if (curr) - pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_CURR_GET << - CPUCP_PKT_CTL_OPCODE_SHIFT); - else - pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_GET << - CPUCP_PKT_CTL_OPCODE_SHIFT); - pkt.pll_index = cpu_to_le32((u32)used_pll_idx); - - rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), - 0, &result); - - if (rc) { - dev_err(hdev->dev, - "Failed to get frequency of PLL %d, error %d\n", - used_pll_idx, rc); - return rc; - } - - return (long) result; -} - -void hl_set_frequency(struct hl_device *hdev, u32 pll_index, u64 freq) -{ - struct cpucp_packet pkt; - u32 used_pll_idx; - int rc; - - rc = get_used_pll_index(hdev, pll_index, &used_pll_idx); - if (rc) - return; - - memset(&pkt, 0, sizeof(pkt)); - - pkt.ctl = cpu_to_le32(CPUCP_PACKET_FREQUENCY_SET << - CPUCP_PKT_CTL_OPCODE_SHIFT); - pkt.pll_index = cpu_to_le32((u32)used_pll_idx); - pkt.value = cpu_to_le64(freq); - - rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), - 0, NULL); - - if (rc) - dev_err(hdev->dev, - "Failed to set frequency to PLL %d, error %d\n", - used_pll_idx, rc); -} - -u64 hl_get_max_power(struct hl_device *hdev) -{ - struct cpucp_packet pkt; - u64 result; - int rc; - - memset(&pkt, 0, sizeof(pkt)); - - pkt.ctl = cpu_to_le32(CPUCP_PACKET_MAX_POWER_GET << - CPUCP_PKT_CTL_OPCODE_SHIFT); - - rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), - 0, &result); - - if (rc) { - dev_err(hdev->dev, "Failed to get max power, error %d\n", rc); - return (u64) rc; - } - - return result; -} - -void hl_set_max_power(struct hl_device *hdev) -{ - struct cpucp_packet pkt; - int rc; - - memset(&pkt, 0, sizeof(pkt)); - - pkt.ctl = cpu_to_le32(CPUCP_PACKET_MAX_POWER_SET << - CPUCP_PKT_CTL_OPCODE_SHIFT); - pkt.value = cpu_to_le64(hdev->max_power); - - rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), - 0, NULL); - - if (rc) - dev_err(hdev->dev, "Failed to set max power, error %d\n", rc); -} - static ssize_t clk_max_freq_mhz_show(struct device *dev, struct device_attribute *attr, char *buf) { struct hl_device *hdev = dev_get_drvdata(dev); @@ -117,7 +17,7 @@ static ssize_t clk_max_freq_mhz_show(struct device *dev, struct device_attribute if (!hl_device_operational(hdev, NULL)) return -ENODEV; - value = hl_get_frequency(hdev, hdev->asic_prop.clk_pll_index, false); + value = hl_fw_get_frequency(hdev, hdev->asic_prop.clk_pll_index, false); hdev->asic_prop.max_freq_value = value; @@ -144,7 +44,7 @@ static ssize_t clk_max_freq_mhz_store(struct device *dev, struct device_attribut hdev->asic_prop.max_freq_value = value * 1000 * 1000; - hl_set_frequency(hdev, hdev->asic_prop.clk_pll_index, hdev->asic_prop.max_freq_value); + hl_fw_set_frequency(hdev, hdev->asic_prop.clk_pll_index, hdev->asic_prop.max_freq_value); fail: return count; @@ -158,7 +58,7 @@ static ssize_t clk_cur_freq_mhz_show(struct device *dev, struct device_attribute if (!hl_device_operational(hdev, NULL)) return -ENODEV; - value = hl_get_frequency(hdev, hdev->asic_prop.clk_pll_index, true); + value = hl_fw_get_frequency(hdev, hdev->asic_prop.clk_pll_index, true); return sprintf(buf, "%lu\n", (value / 1000 / 1000)); } @@ -386,7 +286,7 @@ static ssize_t max_power_show(struct device *dev, struct device_attribute *attr, if (!hl_device_operational(hdev, NULL)) return -ENODEV; - val = hl_get_max_power(hdev); + val = hl_fw_get_max_power(hdev); return sprintf(buf, "%lu\n", val); } @@ -411,7 +311,7 @@ static ssize_t max_power_store(struct device *dev, } hdev->max_power = value; - hl_set_max_power(hdev); + hl_fw_set_max_power(hdev); out: return count; diff --git a/drivers/misc/habanalabs/goya/goya_hwmgr.c b/drivers/misc/habanalabs/goya/goya_hwmgr.c index 76b47749affe..f9f3afe94056 100644 --- a/drivers/misc/habanalabs/goya/goya_hwmgr.c +++ b/drivers/misc/habanalabs/goya/goya_hwmgr.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright 2016-2021 HabanaLabs, Ltd. + * Copyright 2016-2022 HabanaLabs, Ltd. * All Rights Reserved. */ @@ -13,19 +13,19 @@ void goya_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq) switch (freq) { case PLL_HIGH: - hl_set_frequency(hdev, HL_GOYA_MME_PLL, hdev->high_pll); - hl_set_frequency(hdev, HL_GOYA_TPC_PLL, hdev->high_pll); - hl_set_frequency(hdev, HL_GOYA_IC_PLL, hdev->high_pll); + hl_fw_set_frequency(hdev, HL_GOYA_MME_PLL, hdev->high_pll); + hl_fw_set_frequency(hdev, HL_GOYA_TPC_PLL, hdev->high_pll); + hl_fw_set_frequency(hdev, HL_GOYA_IC_PLL, hdev->high_pll); break; case PLL_LOW: - hl_set_frequency(hdev, HL_GOYA_MME_PLL, GOYA_PLL_FREQ_LOW); - hl_set_frequency(hdev, HL_GOYA_TPC_PLL, GOYA_PLL_FREQ_LOW); - hl_set_frequency(hdev, HL_GOYA_IC_PLL, GOYA_PLL_FREQ_LOW); + hl_fw_set_frequency(hdev, HL_GOYA_MME_PLL, GOYA_PLL_FREQ_LOW); + hl_fw_set_frequency(hdev, HL_GOYA_TPC_PLL, GOYA_PLL_FREQ_LOW); + hl_fw_set_frequency(hdev, HL_GOYA_IC_PLL, GOYA_PLL_FREQ_LOW); break; case PLL_LAST: - hl_set_frequency(hdev, HL_GOYA_MME_PLL, goya->mme_clk); - hl_set_frequency(hdev, HL_GOYA_TPC_PLL, goya->tpc_clk); - hl_set_frequency(hdev, HL_GOYA_IC_PLL, goya->ic_clk); + hl_fw_set_frequency(hdev, HL_GOYA_MME_PLL, goya->mme_clk); + hl_fw_set_frequency(hdev, HL_GOYA_TPC_PLL, goya->tpc_clk); + hl_fw_set_frequency(hdev, HL_GOYA_IC_PLL, goya->ic_clk); break; default: dev_err(hdev->dev, "unknown frequency setting\n"); @@ -41,7 +41,7 @@ static ssize_t mme_clk_show(struct device *dev, struct device_attribute *attr, if (!hl_device_operational(hdev, NULL)) return -ENODEV; - value = hl_get_frequency(hdev, HL_GOYA_MME_PLL, false); + value = hl_fw_get_frequency(hdev, HL_GOYA_MME_PLL, false); if (value < 0) return value; @@ -74,7 +74,7 @@ static ssize_t mme_clk_store(struct device *dev, struct device_attribute *attr, goto fail; } - hl_set_frequency(hdev, HL_GOYA_MME_PLL, value); + hl_fw_set_frequency(hdev, HL_GOYA_MME_PLL, value); goya->mme_clk = value; fail: @@ -90,7 +90,7 @@ static ssize_t tpc_clk_show(struct device *dev, struct device_attribute *attr, if (!hl_device_operational(hdev, NULL)) return -ENODEV; - value = hl_get_frequency(hdev, HL_GOYA_TPC_PLL, false); + value = hl_fw_get_frequency(hdev, HL_GOYA_TPC_PLL, false); if (value < 0) return value; @@ -123,7 +123,7 @@ static ssize_t tpc_clk_store(struct device *dev, struct device_attribute *attr, goto fail; } - hl_set_frequency(hdev, HL_GOYA_TPC_PLL, value); + hl_fw_set_frequency(hdev, HL_GOYA_TPC_PLL, value); goya->tpc_clk = value; fail: @@ -139,7 +139,7 @@ static ssize_t ic_clk_show(struct device *dev, struct device_attribute *attr, if (!hl_device_operational(hdev, NULL)) return -ENODEV; - value = hl_get_frequency(hdev, HL_GOYA_IC_PLL, false); + value = hl_fw_get_frequency(hdev, HL_GOYA_IC_PLL, false); if (value < 0) return value; @@ -172,7 +172,7 @@ static ssize_t ic_clk_store(struct device *dev, struct device_attribute *attr, goto fail; } - hl_set_frequency(hdev, HL_GOYA_IC_PLL, value); + hl_fw_set_frequency(hdev, HL_GOYA_IC_PLL, value); goya->ic_clk = value; fail: @@ -188,7 +188,7 @@ static ssize_t mme_clk_curr_show(struct device *dev, if (!hl_device_operational(hdev, NULL)) return -ENODEV; - value = hl_get_frequency(hdev, HL_GOYA_MME_PLL, true); + value = hl_fw_get_frequency(hdev, HL_GOYA_MME_PLL, true); if (value < 0) return value; @@ -205,7 +205,7 @@ static ssize_t tpc_clk_curr_show(struct device *dev, if (!hl_device_operational(hdev, NULL)) return -ENODEV; - value = hl_get_frequency(hdev, HL_GOYA_TPC_PLL, true); + value = hl_fw_get_frequency(hdev, HL_GOYA_TPC_PLL, true); if (value < 0) return value; @@ -222,7 +222,7 @@ static ssize_t ic_clk_curr_show(struct device *dev, if (!hl_device_operational(hdev, NULL)) return -ENODEV; - value = hl_get_frequency(hdev, HL_GOYA_IC_PLL, true); + value = hl_fw_get_frequency(hdev, HL_GOYA_IC_PLL, true); if (value < 0) return value; -- cgit v1.3.1 From 7ae439a0614f3718df203d9f20eac7b3161867f4 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Sat, 8 Jan 2022 22:49:12 +0200 Subject: habanalabs: remove asic callback set_pll_profile() Setting PLL profile is the same for all ASICs, except for GOYA. However, because this function is never called from common code, there is no need to have an asic-specific callback function. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 2 +- drivers/misc/habanalabs/common/habanalabs.h | 5 +---- drivers/misc/habanalabs/gaudi/gaudi.c | 3 +-- drivers/misc/habanalabs/goya/goya.c | 3 +-- drivers/misc/habanalabs/goya/goya_hwmgr.c | 3 +++ 5 files changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 508ee349f4e4..93e9045461ae 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -2683,7 +2683,7 @@ int hl_fw_init_cpu(struct hl_device *hdev) hl_fw_static_init_cpu(hdev, fw_loader); } -void hl_fw_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq) +void hl_fw_set_pll_profile(struct hl_device *hdev) { hl_fw_set_frequency(hdev, hdev->asic_prop.clk_pll_index, hdev->asic_prop.max_freq_value); diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 2bf73e5ce47f..3dc155948730 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -1161,7 +1161,6 @@ struct fw_load_mgr { * internal memory via DMA engine. * @add_device_attr: add ASIC specific device attributes. * @handle_eqe: handle event queue entry (IRQ) from CPU-CP. - * @set_pll_profile: change PLL profile (manual/automatic). * @get_events_stat: retrieve event queue entries histogram. * @read_pte: read MMU page table entry from DRAM. * @write_pte: write MMU page table entry to DRAM. @@ -1291,8 +1290,6 @@ struct hl_asic_funcs { struct attribute_group *dev_attr_grp); void (*handle_eqe)(struct hl_device *hdev, struct hl_eq_entry *eq_entry); - void (*set_pll_profile)(struct hl_device *hdev, - enum hl_pll_frequency freq); void* (*get_events_stat)(struct hl_device *hdev, bool aggregate, u32 *size); u64 (*read_pte)(struct hl_device *hdev, u64 addr); @@ -3108,7 +3105,7 @@ int hl_set_current(struct hl_device *hdev, int sensor_index, u32 attr, long valu int hl_set_power(struct hl_device *hdev, int sensor_index, u32 attr, long value); int hl_get_power(struct hl_device *hdev, int sensor_index, u32 attr, long *value); int hl_fw_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk); -void hl_fw_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq); +void hl_fw_set_pll_profile(struct hl_device *hdev); void hl_sysfs_add_dev_clk_attr(struct hl_device *hdev, struct attribute_group *dev_attr_grp); void hw_sob_get(struct hl_hw_sob *hw_sob); diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index ae86147dfde4..bb0b4ff3451d 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -1635,7 +1635,7 @@ static int gaudi_late_init(struct hl_device *hdev) */ gaudi_mmu_prepare(hdev, 1); - hdev->asic_funcs->set_pll_profile(hdev, PLL_LAST); + hl_fw_set_pll_profile(hdev); return 0; @@ -9363,7 +9363,6 @@ static const struct hl_asic_funcs gaudi_funcs = { .debugfs_read_dma = gaudi_debugfs_read_dma, .add_device_attr = hl_sysfs_add_dev_clk_attr, .handle_eqe = gaudi_handle_eqe, - .set_pll_profile = hl_fw_set_pll_profile, .get_events_stat = gaudi_get_events_stat, .read_pte = gaudi_read_pte, .write_pte = gaudi_write_pte, diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 318b97c53ed7..916a718dddac 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -893,7 +893,7 @@ int goya_late_init(struct hl_device *hdev) goya->pm_mng_profile = PM_AUTO; - hdev->asic_funcs->set_pll_profile(hdev, PLL_LOW); + goya_set_pll_profile(hdev, PLL_LOW); schedule_delayed_work(&goya->goya_work->work_freq, usecs_to_jiffies(HL_PLL_LOW_JOB_FREQ_USEC)); @@ -5717,7 +5717,6 @@ static const struct hl_asic_funcs goya_funcs = { .debugfs_read_dma = goya_debugfs_read_dma, .add_device_attr = goya_add_device_attr, .handle_eqe = goya_handle_eqe, - .set_pll_profile = goya_set_pll_profile, .get_events_stat = goya_get_events_stat, .read_pte = goya_read_pte, .write_pte = goya_write_pte, diff --git a/drivers/misc/habanalabs/goya/goya_hwmgr.c b/drivers/misc/habanalabs/goya/goya_hwmgr.c index f9f3afe94056..7d4f26c67d8e 100644 --- a/drivers/misc/habanalabs/goya/goya_hwmgr.c +++ b/drivers/misc/habanalabs/goya/goya_hwmgr.c @@ -11,6 +11,9 @@ void goya_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq) { struct goya_device *goya = hdev->asic_specific; + if (!hdev->pdev) + return; + switch (freq) { case PLL_HIGH: hl_fw_set_frequency(hdev, HL_GOYA_MME_PLL, hdev->high_pll); -- cgit v1.3.1 From be028a3648f3791ce8bc74608477d7846be72c24 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Sat, 8 Jan 2022 22:55:39 +0200 Subject: habanalabs: rename dev_attr_grp to dev_clk_attr_grp In this attribute group we are only adding clocks. This is in preparation for adding a device specific attribute group which is not related to clocks. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/habanalabs.h | 5 ++--- drivers/misc/habanalabs/common/sysfs.c | 4 ++-- drivers/misc/habanalabs/goya/goyaP.h | 5 ++--- drivers/misc/habanalabs/goya/goya_hwmgr.c | 7 +++---- 4 files changed, 9 insertions(+), 12 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 3dc155948730..c116e30a5543 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -1286,8 +1286,7 @@ struct hl_asic_funcs { bool user_address, u64 val); int (*debugfs_read_dma)(struct hl_device *hdev, u64 addr, u32 size, void *blob_addr); - void (*add_device_attr)(struct hl_device *hdev, - struct attribute_group *dev_attr_grp); + void (*add_device_attr)(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp); void (*handle_eqe)(struct hl_device *hdev, struct hl_eq_entry *eq_entry); void* (*get_events_stat)(struct hl_device *hdev, bool aggregate, @@ -3106,7 +3105,7 @@ int hl_set_power(struct hl_device *hdev, int sensor_index, u32 attr, long value) int hl_get_power(struct hl_device *hdev, int sensor_index, u32 attr, long *value); int hl_fw_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk); void hl_fw_set_pll_profile(struct hl_device *hdev); -void hl_sysfs_add_dev_clk_attr(struct hl_device *hdev, struct attribute_group *dev_attr_grp); +void hl_sysfs_add_dev_clk_attr(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp); void hw_sob_get(struct hl_hw_sob *hw_sob); void hw_sob_put(struct hl_hw_sob *hw_sob); diff --git a/drivers/misc/habanalabs/common/sysfs.c b/drivers/misc/habanalabs/common/sysfs.c index ce3538d36bb7..606cee6252fe 100644 --- a/drivers/misc/habanalabs/common/sysfs.c +++ b/drivers/misc/habanalabs/common/sysfs.c @@ -426,9 +426,9 @@ static const struct attribute_group *hl_dev_inference_attr_groups[] = { NULL, }; -void hl_sysfs_add_dev_clk_attr(struct hl_device *hdev, struct attribute_group *dev_attr_grp) +void hl_sysfs_add_dev_clk_attr(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp) { - dev_attr_grp->attrs = hl_dev_clk_attrs; + dev_clk_attr_grp->attrs = hl_dev_clk_attrs; } int hl_sysfs_init(struct hl_device *hdev) diff --git a/drivers/misc/habanalabs/goya/goyaP.h b/drivers/misc/habanalabs/goya/goyaP.h index 3740fd25bf84..d71e2f4de757 100644 --- a/drivers/misc/habanalabs/goya/goyaP.h +++ b/drivers/misc/habanalabs/goya/goyaP.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 * - * Copyright 2016-2019 HabanaLabs, Ltd. + * Copyright 2016-2022 HabanaLabs, Ltd. * All Rights Reserved. * */ @@ -217,8 +217,7 @@ u64 goya_get_max_power(struct hl_device *hdev); void goya_set_max_power(struct hl_device *hdev, u64 value); void goya_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq); -void goya_add_device_attr(struct hl_device *hdev, - struct attribute_group *dev_attr_grp); +void goya_add_device_attr(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp); int goya_cpucp_info_get(struct hl_device *hdev); int goya_debug_coresight(struct hl_device *hdev, struct hl_ctx *ctx, void *data); void goya_halt_coresight(struct hl_device *hdev, struct hl_ctx *ctx); diff --git a/drivers/misc/habanalabs/goya/goya_hwmgr.c b/drivers/misc/habanalabs/goya/goya_hwmgr.c index 7d4f26c67d8e..c641ff1e23b9 100644 --- a/drivers/misc/habanalabs/goya/goya_hwmgr.c +++ b/drivers/misc/habanalabs/goya/goya_hwmgr.c @@ -350,7 +350,7 @@ static DEVICE_ATTR_RW(pm_mng_profile); static DEVICE_ATTR_RW(tpc_clk); static DEVICE_ATTR_RO(tpc_clk_curr); -static struct attribute *goya_dev_attrs[] = { +static struct attribute *goya_clk_dev_attrs[] = { &dev_attr_high_pll.attr, &dev_attr_ic_clk.attr, &dev_attr_ic_clk_curr.attr, @@ -362,8 +362,7 @@ static struct attribute *goya_dev_attrs[] = { NULL, }; -void goya_add_device_attr(struct hl_device *hdev, - struct attribute_group *dev_attr_grp) +void goya_add_device_attr(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp) { - dev_attr_grp->attrs = goya_dev_attrs; + dev_clk_attr_grp->attrs = goya_clk_dev_attrs; } -- cgit v1.3.1 From b62ff1a4123693551383f306ab736758e6fe0d84 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Sat, 8 Jan 2022 23:45:32 +0200 Subject: habanalabs: add vrm version to sysfs infineon version is only applicable to GOYA and GAUDI. For later ASICs, we display the Voltage Regulator Monitor f/w version. Signed-off-by: Oded Gabbay --- Documentation/ABI/testing/sysfs-driver-habanalabs | 10 ++++- drivers/misc/habanalabs/common/habanalabs.h | 4 +- drivers/misc/habanalabs/common/sysfs.c | 46 ++++++++++++++--------- drivers/misc/habanalabs/gaudi/gaudi.c | 25 +++++++++++- drivers/misc/habanalabs/gaudi/gaudiP.h | 4 +- drivers/misc/habanalabs/goya/goyaP.h | 3 +- drivers/misc/habanalabs/goya/goya_hwmgr.c | 21 ++++++++++- 7 files changed, 85 insertions(+), 28 deletions(-) (limited to 'drivers/misc') diff --git a/Documentation/ABI/testing/sysfs-driver-habanalabs b/Documentation/ABI/testing/sysfs-driver-habanalabs index 1f127f71d2b4..c16a573eb680 100644 --- a/Documentation/ABI/testing/sysfs-driver-habanalabs +++ b/Documentation/ABI/testing/sysfs-driver-habanalabs @@ -115,7 +115,7 @@ What: /sys/class/habanalabs/hl/infineon_ver Date: Jan 2019 KernelVersion: 5.1 Contact: ogabbay@kernel.org -Description: Version of the Device's power supply F/W code +Description: Version of the Device's power supply F/W code. Relevant only to GOYA and GAUDI What: /sys/class/habanalabs/hl/max_power Date: Jan 2019 @@ -220,4 +220,10 @@ What: /sys/class/habanalabs/hl/uboot_ver Date: Jan 2019 KernelVersion: 5.1 Contact: ogabbay@kernel.org -Description: Version of the u-boot running on the device's CPU \ No newline at end of file +Description: Version of the u-boot running on the device's CPU + +What: /sys/class/habanalabs/hl/vrm_ver +Date: Jan 2022 +KernelVersion: not yet upstreamed +Contact: ogabbay@kernel.org +Description: Version of the Device's Voltage Regulator Monitor F/W code. N/A to GOYA and GAUDI diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index c116e30a5543..b8acfef9577a 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -1286,7 +1286,8 @@ struct hl_asic_funcs { bool user_address, u64 val); int (*debugfs_read_dma)(struct hl_device *hdev, u64 addr, u32 size, void *blob_addr); - void (*add_device_attr)(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp); + void (*add_device_attr)(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp, + struct attribute_group *dev_vrm_attr_grp); void (*handle_eqe)(struct hl_device *hdev, struct hl_eq_entry *eq_entry); void* (*get_events_stat)(struct hl_device *hdev, bool aggregate, @@ -3106,6 +3107,7 @@ int hl_get_power(struct hl_device *hdev, int sensor_index, u32 attr, long *value int hl_fw_get_clk_rate(struct hl_device *hdev, u32 *cur_clk, u32 *max_clk); void hl_fw_set_pll_profile(struct hl_device *hdev); void hl_sysfs_add_dev_clk_attr(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp); +void hl_sysfs_add_dev_vrm_attr(struct hl_device *hdev, struct attribute_group *dev_vrm_attr_grp); void hw_sob_get(struct hl_hw_sob *hw_sob); void hw_sob_put(struct hl_hw_sob *hw_sob); diff --git a/drivers/misc/habanalabs/common/sysfs.c b/drivers/misc/habanalabs/common/sysfs.c index 606cee6252fe..65b132fa6dbd 100644 --- a/drivers/misc/habanalabs/common/sysfs.c +++ b/drivers/misc/habanalabs/common/sysfs.c @@ -69,7 +69,26 @@ static DEVICE_ATTR_RO(clk_cur_freq_mhz); static struct attribute *hl_dev_clk_attrs[] = { &dev_attr_clk_max_freq_mhz.attr, &dev_attr_clk_cur_freq_mhz.attr, - NULL, +}; + +static ssize_t vrm_ver_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct hl_device *hdev = dev_get_drvdata(dev); + struct cpucp_info *cpucp_info; + + cpucp_info = &hdev->asic_prop.cpucp_info; + + if (cpucp_info->infineon_second_stage_version) + return sprintf(buf, "%#04x %#04x\n", le32_to_cpu(cpucp_info->infineon_version), + le32_to_cpu(cpucp_info->infineon_second_stage_version)); + else + return sprintf(buf, "%#04x\n", le32_to_cpu(cpucp_info->infineon_version)); +} + +static DEVICE_ATTR_RO(vrm_ver); + +static struct attribute *hl_dev_vrm_attrs[] = { + &dev_attr_vrm_ver.attr, }; static ssize_t uboot_ver_show(struct device *dev, struct device_attribute *attr, @@ -121,20 +140,6 @@ static ssize_t cpucp_ver_show(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%s\n", hdev->asic_prop.cpucp_info.cpucp_version); } -static ssize_t infineon_ver_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hl_device *hdev = dev_get_drvdata(dev); - - if (hdev->asic_prop.cpucp_info.infineon_second_stage_version) - return sprintf(buf, "%#04x %#04x\n", - le32_to_cpu(hdev->asic_prop.cpucp_info.infineon_version), - le32_to_cpu(hdev->asic_prop.cpucp_info.infineon_second_stage_version)); - else - return sprintf(buf, "%#04x\n", - le32_to_cpu(hdev->asic_prop.cpucp_info.infineon_version)); -} - static ssize_t fuse_ver_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -357,7 +362,6 @@ static DEVICE_ATTR_RO(device_type); static DEVICE_ATTR_RO(fuse_ver); static DEVICE_ATTR_WO(hard_reset); static DEVICE_ATTR_RO(hard_reset_cnt); -static DEVICE_ATTR_RO(infineon_ver); static DEVICE_ATTR_RW(max_power); static DEVICE_ATTR_RO(pci_addr); static DEVICE_ATTR_RO(preboot_btl_ver); @@ -383,7 +387,6 @@ static struct attribute *hl_dev_attrs[] = { &dev_attr_fuse_ver.attr, &dev_attr_hard_reset.attr, &dev_attr_hard_reset_cnt.attr, - &dev_attr_infineon_ver.attr, &dev_attr_max_power.attr, &dev_attr_pci_addr.attr, &dev_attr_preboot_btl_ver.attr, @@ -404,10 +407,12 @@ static struct attribute_group hl_dev_attr_group = { }; static struct attribute_group hl_dev_clks_attr_group; +static struct attribute_group hl_dev_vrm_attr_group; static const struct attribute_group *hl_dev_attr_groups[] = { &hl_dev_attr_group, &hl_dev_clks_attr_group, + &hl_dev_vrm_attr_group, NULL, }; @@ -431,13 +436,18 @@ void hl_sysfs_add_dev_clk_attr(struct hl_device *hdev, struct attribute_group *d dev_clk_attr_grp->attrs = hl_dev_clk_attrs; } +void hl_sysfs_add_dev_vrm_attr(struct hl_device *hdev, struct attribute_group *dev_vrm_attr_grp) +{ + dev_vrm_attr_grp->attrs = hl_dev_vrm_attrs; +} + int hl_sysfs_init(struct hl_device *hdev) { int rc; hdev->max_power = hdev->asic_prop.max_power_default; - hdev->asic_funcs->add_device_attr(hdev, &hl_dev_clks_attr_group); + hdev->asic_funcs->add_device_attr(hdev, &hl_dev_clks_attr_group, &hl_dev_vrm_attr_group); rc = device_add_groups(hdev->dev, hl_dev_attr_groups); if (rc) { diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index bb0b4ff3451d..c4e41856ad31 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -9324,6 +9324,29 @@ static u32 *gaudi_get_stream_master_qid_arr(void) return gaudi_stream_master; } +static ssize_t infineon_ver_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct hl_device *hdev = dev_get_drvdata(dev); + struct cpucp_info *cpucp_info; + + cpucp_info = &hdev->asic_prop.cpucp_info; + + return sprintf(buf, "%#04x\n", le32_to_cpu(cpucp_info->infineon_version)); +} + +static DEVICE_ATTR_RO(infineon_ver); + +static struct attribute *gaudi_vrm_dev_attrs[] = { + &dev_attr_infineon_ver.attr, +}; + +static void gaudi_add_device_attr(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp, + struct attribute_group *dev_vrm_attr_grp) +{ + hl_sysfs_add_dev_clk_attr(hdev, dev_clk_attr_grp); + dev_vrm_attr_grp->attrs = gaudi_vrm_dev_attrs; +} + static const struct hl_asic_funcs gaudi_funcs = { .early_init = gaudi_early_init, .early_fini = gaudi_early_fini, @@ -9361,7 +9384,7 @@ static const struct hl_asic_funcs gaudi_funcs = { .debugfs_read64 = gaudi_debugfs_read64, .debugfs_write64 = gaudi_debugfs_write64, .debugfs_read_dma = gaudi_debugfs_read_dma, - .add_device_attr = hl_sysfs_add_dev_clk_attr, + .add_device_attr = gaudi_add_device_attr, .handle_eqe = gaudi_handle_eqe, .get_events_stat = gaudi_get_events_stat, .read_pte = gaudi_read_pte, diff --git a/drivers/misc/habanalabs/gaudi/gaudiP.h b/drivers/misc/habanalabs/gaudi/gaudiP.h index fdadcbf3ef80..54de7c599072 100644 --- a/drivers/misc/habanalabs/gaudi/gaudiP.h +++ b/drivers/misc/habanalabs/gaudi/gaudiP.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 * - * Copyright 2019-2020 HabanaLabs, Ltd. + * Copyright 2019-2022 HabanaLabs, Ltd. * All Rights Reserved. * */ @@ -351,8 +351,6 @@ struct gaudi_device { void gaudi_init_security(struct hl_device *hdev); void gaudi_ack_protection_bits_errors(struct hl_device *hdev); -void gaudi_add_device_attr(struct hl_device *hdev, - struct attribute_group *dev_attr_grp); int gaudi_debug_coresight(struct hl_device *hdev, struct hl_ctx *ctx, void *data); void gaudi_halt_coresight(struct hl_device *hdev, struct hl_ctx *ctx); void gaudi_mmu_prepare_reg(struct hl_device *hdev, u64 reg, u32 asid); diff --git a/drivers/misc/habanalabs/goya/goyaP.h b/drivers/misc/habanalabs/goya/goyaP.h index d71e2f4de757..647f57402616 100644 --- a/drivers/misc/habanalabs/goya/goyaP.h +++ b/drivers/misc/habanalabs/goya/goyaP.h @@ -217,7 +217,8 @@ u64 goya_get_max_power(struct hl_device *hdev); void goya_set_max_power(struct hl_device *hdev, u64 value); void goya_set_pll_profile(struct hl_device *hdev, enum hl_pll_frequency freq); -void goya_add_device_attr(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp); +void goya_add_device_attr(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp, + struct attribute_group *dev_vrm_attr_grp); int goya_cpucp_info_get(struct hl_device *hdev); int goya_debug_coresight(struct hl_device *hdev, struct hl_ctx *ctx, void *data); void goya_halt_coresight(struct hl_device *hdev, struct hl_ctx *ctx); diff --git a/drivers/misc/habanalabs/goya/goya_hwmgr.c b/drivers/misc/habanalabs/goya/goya_hwmgr.c index c641ff1e23b9..6580fc6a486a 100644 --- a/drivers/misc/habanalabs/goya/goya_hwmgr.c +++ b/drivers/misc/habanalabs/goya/goya_hwmgr.c @@ -359,10 +359,27 @@ static struct attribute *goya_clk_dev_attrs[] = { &dev_attr_pm_mng_profile.attr, &dev_attr_tpc_clk.attr, &dev_attr_tpc_clk_curr.attr, - NULL, }; -void goya_add_device_attr(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp) +static ssize_t infineon_ver_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct hl_device *hdev = dev_get_drvdata(dev); + struct cpucp_info *cpucp_info; + + cpucp_info = &hdev->asic_prop.cpucp_info; + + return sprintf(buf, "%#04x\n", le32_to_cpu(cpucp_info->infineon_version)); +} + +static DEVICE_ATTR_RO(infineon_ver); + +static struct attribute *goya_vrm_dev_attrs[] = { + &dev_attr_infineon_ver.attr, +}; + +void goya_add_device_attr(struct hl_device *hdev, struct attribute_group *dev_clk_attr_grp, + struct attribute_group *dev_vrm_attr_grp) { dev_clk_attr_grp->attrs = goya_clk_dev_attrs; + dev_vrm_attr_grp->attrs = goya_vrm_dev_attrs; } -- cgit v1.3.1 From 2491533808d71c2229582d7427dffbd9494cc85f Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Mon, 10 Jan 2022 17:01:50 +0200 Subject: habanalabs: remove power9 workaround for dma support We don't need this workaround anymore. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/habanalabs.h | 3 --- drivers/misc/habanalabs/common/pci/pci.c | 5 +---- drivers/misc/habanalabs/gaudi/gaudi.c | 9 +-------- drivers/misc/habanalabs/goya/goya.c | 11 +---------- 4 files changed, 3 insertions(+), 25 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index b8acfef9577a..6c7a60210416 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -2604,8 +2604,6 @@ struct hl_reset_info { * @in_debug: whether the device is in a state where the profiling/tracing infrastructure * can be used. This indication is needed because in some ASICs we need to do * specific operations to enable that infrastructure. - * @power9_64bit_dma_enable: true to enable 64-bit DMA mask support. Relevant - * only to POWER9 machines. * @cdev_sysfs_created: were char devices and sysfs nodes created. * @stop_on_err: true if engines should stop on error. * @supports_sync_stream: is sync stream supported. @@ -2728,7 +2726,6 @@ struct hl_device { u8 device_cpu_disabled; u8 dma_mask; u8 in_debug; - u8 power9_64bit_dma_enable; u8 cdev_sysfs_created; u8 stop_on_err; u8 supports_sync_stream; diff --git a/drivers/misc/habanalabs/common/pci/pci.c b/drivers/misc/habanalabs/common/pci/pci.c index 0b5366cc84fd..a6ffa342070c 100644 --- a/drivers/misc/habanalabs/common/pci/pci.c +++ b/drivers/misc/habanalabs/common/pci/pci.c @@ -338,10 +338,7 @@ int hl_pci_set_outbound_region(struct hl_device *hdev, lower_32_bits(outbound_region_end_address)); rc |= hl_pci_iatu_write(hdev, 0x014, 0); - if ((hdev->power9_64bit_dma_enable) && (hdev->dma_mask == 64)) - rc |= hl_pci_iatu_write(hdev, 0x018, 0x08000000); - else - rc |= hl_pci_iatu_write(hdev, 0x018, 0); + rc |= hl_pci_iatu_write(hdev, 0x018, 0); rc |= hl_pci_iatu_write(hdev, 0x020, upper_32_bits(outbound_region_end_address)); diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index c4e41856ad31..66c90164be6b 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -9008,14 +9008,7 @@ static void gaudi_reset_sob(struct hl_device *hdev, void *data) static void gaudi_set_dma_mask_from_fw(struct hl_device *hdev) { - if (RREG32(mmPSOC_GLOBAL_CONF_NON_RST_FLOPS_0) == - HL_POWER9_HOST_MAGIC) { - hdev->power9_64bit_dma_enable = 1; - hdev->dma_mask = 64; - } else { - hdev->power9_64bit_dma_enable = 0; - hdev->dma_mask = 48; - } + hdev->dma_mask = 48; } static u64 gaudi_get_device_time(struct hl_device *hdev) diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 916a718dddac..1bd23578cb83 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -5554,16 +5554,7 @@ static void goya_reset_sob_group(struct hl_device *hdev, u16 sob_group) static void goya_set_dma_mask_from_fw(struct hl_device *hdev) { - if (RREG32(mmPSOC_GLOBAL_CONF_NON_RST_FLOPS_0) == - HL_POWER9_HOST_MAGIC) { - dev_dbg(hdev->dev, "Working in 64-bit DMA mode\n"); - hdev->power9_64bit_dma_enable = 1; - hdev->dma_mask = 64; - } else { - dev_dbg(hdev->dev, "Working in 48-bit DMA mode\n"); - hdev->power9_64bit_dma_enable = 0; - hdev->dma_mask = 48; - } + hdev->dma_mask = 48; } u64 goya_get_device_time(struct hl_device *hdev) -- cgit v1.3.1 From 6ba2c0ce26929bc7dcae88e3c3450bd75d9a2423 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Mon, 10 Jan 2022 21:58:42 +0200 Subject: habanalabs: use common wrapper for MMU cache invalidation We have a common function that wraps the call to the MMU cache invalidation function, which is ASIC-specific. The wrapper checks the return value and prints error if necessary. For consistency, try to use the wrapper when possible. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 6 +++--- drivers/misc/habanalabs/goya/goya.c | 5 ++--- 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 66c90164be6b..c58e21e2db3b 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -3855,7 +3855,7 @@ static int gaudi_mmu_init(struct hl_device *hdev) /* mem cache invalidation */ WREG32(mmSTLB_MEM_CACHE_INVALIDATION, 1); - hdev->asic_funcs->mmu_invalidate_cache(hdev, true, 0); + hl_mmu_invalidate_cache(hdev, true, 0); WREG32(mmMMU_UP_MMU_ENABLE, 1); WREG32(mmMMU_UP_SPI_MASK, 0xF); @@ -8595,7 +8595,7 @@ static int gaudi_internal_cb_pool_init(struct hl_device *hdev, hdev->internal_cb_pool_dma_addr, HOST_SPACE_INTERNAL_CB_SZ); - hdev->asic_funcs->mmu_invalidate_cache(hdev, false, MMU_OP_USERPTR); + hl_mmu_invalidate_cache(hdev, false, MMU_OP_USERPTR); mutex_unlock(&ctx->mmu_lock); if (rc) @@ -8630,7 +8630,7 @@ static void gaudi_internal_cb_pool_fini(struct hl_device *hdev, HOST_SPACE_INTERNAL_CB_SZ); hl_unreserve_va_block(hdev, ctx, hdev->internal_cb_va_base, HOST_SPACE_INTERNAL_CB_SZ); - hdev->asic_funcs->mmu_invalidate_cache(hdev, true, MMU_OP_USERPTR); + hl_mmu_invalidate_cache(hdev, true, MMU_OP_USERPTR); mutex_unlock(&ctx->mmu_lock); gen_pool_destroy(hdev->internal_cb_pool); diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 1bd23578cb83..d8c6dea7c809 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -2700,8 +2700,7 @@ int goya_mmu_init(struct hl_device *hdev) WREG32_AND(mmSTLB_STLB_FEATURE_EN, (~STLB_STLB_FEATURE_EN_FOLLOWER_EN_MASK)); - hdev->asic_funcs->mmu_invalidate_cache(hdev, true, - MMU_OP_USERPTR | MMU_OP_PHYS_PACK); + hl_mmu_invalidate_cache(hdev, true, MMU_OP_USERPTR | MMU_OP_PHYS_PACK); WREG32(mmMMU_MMU_ENABLE, 1); WREG32(mmMMU_SPI_MASK, 0xF); @@ -5341,7 +5340,7 @@ static int goya_mmu_invalidate_cache_range(struct hl_device *hdev, /* Treat as invalidate all because there is no range invalidation * in Goya */ - return hdev->asic_funcs->mmu_invalidate_cache(hdev, is_hard, flags); + return hl_mmu_invalidate_cache(hdev, is_hard, flags); } int goya_send_heartbeat(struct hl_device *hdev) -- cgit v1.3.1 From 4c01e524b21ff4342d8ab16a32a0acf91db761e3 Mon Sep 17 00:00:00 2001 From: Rajaravi Krishna Katta Date: Wed, 29 Dec 2021 13:13:45 +0200 Subject: habanalabs: sysfs support for fw os version Adds new sysfs entry to display firmware os version /sys/class/habanalabs/hl/fw_os_ver Signed-off-by: Rajaravi Krishna Katta Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- Documentation/ABI/testing/sysfs-driver-habanalabs | 6 ++++++ drivers/misc/habanalabs/common/sysfs.c | 10 ++++++++++ drivers/misc/habanalabs/include/common/cpucp_if.h | 2 ++ 3 files changed, 18 insertions(+) (limited to 'drivers/misc') diff --git a/Documentation/ABI/testing/sysfs-driver-habanalabs b/Documentation/ABI/testing/sysfs-driver-habanalabs index c16a573eb680..96646fb2e7a1 100644 --- a/Documentation/ABI/testing/sysfs-driver-habanalabs +++ b/Documentation/ABI/testing/sysfs-driver-habanalabs @@ -69,6 +69,12 @@ KernelVersion: 5.1 Contact: ogabbay@kernel.org Description: Displays the device's version from the eFuse +What: /sys/class/habanalabs/hl/fw_os_ver +Date: Dec 2021 +KernelVersion: 5.18 +Contact: ogabbay@kernel.org +Description: Version of the firmware OS running on the device's CPU + What: /sys/class/habanalabs/hl/hard_reset Date: Jan 2019 KernelVersion: 5.1 diff --git a/drivers/misc/habanalabs/common/sysfs.c b/drivers/misc/habanalabs/common/sysfs.c index 65b132fa6dbd..3f220dd3b6b2 100644 --- a/drivers/misc/habanalabs/common/sysfs.c +++ b/drivers/misc/habanalabs/common/sysfs.c @@ -156,6 +156,14 @@ static ssize_t thermal_ver_show(struct device *dev, return sprintf(buf, "%s", hdev->asic_prop.cpucp_info.thermal_version); } +static ssize_t fw_os_ver_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hl_device *hdev = dev_get_drvdata(dev); + + return sprintf(buf, "%s", hdev->asic_prop.cpucp_info.fw_os_version); +} + static ssize_t preboot_btl_ver_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -370,6 +378,7 @@ static DEVICE_ATTR_RO(soft_reset_cnt); static DEVICE_ATTR_RO(status); static DEVICE_ATTR_RO(thermal_ver); static DEVICE_ATTR_RO(uboot_ver); +static DEVICE_ATTR_RO(fw_os_ver); static struct bin_attribute bin_attr_eeprom = { .attr = {.name = "eeprom", .mode = (0444)}, @@ -393,6 +402,7 @@ static struct attribute *hl_dev_attrs[] = { &dev_attr_status.attr, &dev_attr_thermal_ver.attr, &dev_attr_uboot_ver.attr, + &dev_attr_fw_os_ver.attr, NULL, }; diff --git a/drivers/misc/habanalabs/include/common/cpucp_if.h b/drivers/misc/habanalabs/include/common/cpucp_if.h index 737c39f33f05..f00db22f98fb 100644 --- a/drivers/misc/habanalabs/include/common/cpucp_if.h +++ b/drivers/misc/habanalabs/include/common/cpucp_if.h @@ -780,6 +780,7 @@ struct cpucp_security_info { * (0 = functional 1 = binned) * @xbar_binning_mask: Xbar binning mask, 1 bit per Xbar instance * (0 = functional 1 = binned) + * @fw_os_version: Firmware OS Version */ struct cpucp_info { struct cpucp_sensor sensors[CPUCP_MAX_SENSORS]; @@ -807,6 +808,7 @@ struct cpucp_info { __le32 reserved6; __u8 pll_map[PLL_MAP_LEN]; __le64 mme_binning_mask; + __u8 fw_os_version[VERSION_MAX_LEN]; }; struct cpucp_mac_addr { -- cgit v1.3.1 From e24a62cb68d117858f311d14ca366a18a44120a8 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Thu, 13 Jan 2022 10:05:38 +0200 Subject: habanalabs: there is no kernel TDR in future ASICs In future ASICs, there is no kernel TDR for new workloads that are submitted directly from user-space to the device. Therefore, the driver can NEVER know that a workload has timed-out. So, when the user asks us to wait for interrupt on the workload's completion, and the wait has timed-out, it doesn't mean the workload has timed-out. It only means the wait has timed-out, which is NOT an error from driver's perspective. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/command_submission.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index 2f40b937c59f..29e0549ff31d 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -2932,11 +2932,14 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx, rc = -EIO; *status = HL_WAIT_CS_STATUS_ABORTED; } else { - dev_err_ratelimited(hdev->dev, "Waiting for interrupt ID %d timedout\n", - interrupt->interrupt_id); - rc = -ETIMEDOUT; + /* The wait has timed-out. We don't know anything beyond that + * because the workload wasn't submitted through the driver. + * Therefore, from driver's perspective, the workload is still + * executing. + */ + rc = 0; + *status = HL_WAIT_CS_STATUS_BUSY; } - *status = HL_WAIT_CS_STATUS_BUSY; } } @@ -3049,6 +3052,12 @@ wait_again: interrupt->interrupt_id); rc = -EINTR; } else { + /* The wait has timed-out. We don't know anything beyond that + * because the workload wasn't submitted through the driver. + * Therefore, from driver's perspective, the workload is still + * executing. + */ + rc = 0; *status = HL_WAIT_CS_STATUS_BUSY; } -- cgit v1.3.1 From 1dc6cc4b38e5456b7b8741a6194018d30a521d38 Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Tue, 4 Jan 2022 14:42:50 +0200 Subject: habanalabs: duplicate HOP table props to MMU props In order to support several device MMU blocks with different architectures (e.g. different HOP table size) we need to move to per-MMU properties rather than keeping those properties as ASIC properties. Refactoring the code to use "per-MMU proprties" is a major effort. To start making the transition towards this goal but still support taking the properties from ASIC properties (for code that currently uses them) this patch copies some of the properties to the "per-MMU" properties and later, when implementing the per-MMU properties, we would be able to delete the MMU props from the ASIC props. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 3 +++ drivers/misc/habanalabs/goya/goya.c | 6 ++++++ 2 files changed, 9 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index c58e21e2db3b..f2242aa3baa2 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -613,6 +613,9 @@ static int gaudi_set_fixed_properties(struct hl_device *hdev) prop->pmmu.page_size = PAGE_SIZE_4KB; prop->pmmu.num_hops = MMU_ARCH_5_HOPS; prop->pmmu.last_mask = LAST_MASK; + /* TODO: will be duplicated until implementing per-MMU props */ + prop->pmmu.hop_table_size = prop->mmu_hop_table_size; + prop->pmmu.hop0_tables_total_size = prop->mmu_hop0_tables_total_size; /* PMMU and HPMMU are the same except of page size */ memcpy(&prop->pmmu_huge, &prop->pmmu, sizeof(prop->pmmu)); diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index d8c6dea7c809..3785fb33260d 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -430,6 +430,9 @@ int goya_set_fixed_properties(struct hl_device *hdev) prop->dmmu.page_size = PAGE_SIZE_2MB; prop->dmmu.num_hops = MMU_ARCH_5_HOPS; prop->dmmu.last_mask = LAST_MASK; + /* TODO: will be duplicated until implementing per-MMU props */ + prop->dmmu.hop_table_size = prop->mmu_hop_table_size; + prop->dmmu.hop0_tables_total_size = prop->mmu_hop0_tables_total_size; /* shifts and masks are the same in PMMU and DMMU */ memcpy(&prop->pmmu, &prop->dmmu, sizeof(prop->dmmu)); @@ -438,6 +441,9 @@ int goya_set_fixed_properties(struct hl_device *hdev) prop->pmmu.page_size = PAGE_SIZE_4KB; prop->pmmu.num_hops = MMU_ARCH_5_HOPS; prop->pmmu.last_mask = LAST_MASK; + /* TODO: will be duplicated until implementing per-MMU props */ + prop->pmmu.hop_table_size = prop->mmu_hop_table_size; + prop->pmmu.hop0_tables_total_size = prop->mmu_hop0_tables_total_size; /* PMMU and HPMMU are the same except of page size */ memcpy(&prop->pmmu_huge, &prop->pmmu, sizeof(prop->pmmu)); -- cgit v1.3.1 From 7169f0dfecf7745c810782f3f5fe22ba2a8d9ba1 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Sun, 16 Jan 2022 00:18:32 +0200 Subject: habanalabs: don't free phys_pg_pack inside lock Freeing phys_pg_pack includes calling to scrubbing functions of the device's memory, taking locks and possibly even calling reset. This is not something that should be done while holding a device-wide spinlock. Therefore, save the relevant objects on a local linked-list and after releasing the spinlock, traverse that list and free the phys_pg_pack objects. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/habanalabs.h | 3 +++ drivers/misc/habanalabs/common/memory.c | 16 +++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 6c7a60210416..9c8374d88907 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -1738,6 +1738,8 @@ struct hl_vm_hw_block_list_node { * @pages: the physical page array. * @npages: num physical pages in the pack. * @total_size: total size of all the pages in this list. + * @node: used to attach to deletion list that is used when all the allocations are cleared + * at the teardown of the context. * @mapping_cnt: number of shared mappings. * @exporting_cnt: number of dma-buf exporting. * @asid: the context related to this list. @@ -1753,6 +1755,7 @@ struct hl_vm_phys_pg_pack { u64 *pages; u64 npages; u64 total_size; + struct list_head node; atomic_t mapping_cnt; u32 exporting_cnt; u32 asid; diff --git a/drivers/misc/habanalabs/common/memory.c b/drivers/misc/habanalabs/common/memory.c index c1eefaebacb6..4a5d3a179765 100644 --- a/drivers/misc/habanalabs/common/memory.c +++ b/drivers/misc/habanalabs/common/memory.c @@ -2607,11 +2607,12 @@ int hl_vm_ctx_init(struct hl_ctx *ctx) */ void hl_vm_ctx_fini(struct hl_ctx *ctx) { - struct hl_device *hdev = ctx->hdev; - struct hl_vm *vm = &hdev->vm; struct hl_vm_phys_pg_pack *phys_pg_list; + struct hl_device *hdev = ctx->hdev; struct hl_vm_hash_node *hnode; + struct hl_vm *vm = &hdev->vm; struct hlist_node *tmp_node; + struct list_head free_list; struct hl_mem_in args; int i; @@ -2644,19 +2645,24 @@ void hl_vm_ctx_fini(struct hl_ctx *ctx) mutex_unlock(&ctx->mmu_lock); + INIT_LIST_HEAD(&free_list); + spin_lock(&vm->idr_lock); idr_for_each_entry(&vm->phys_pg_pack_handles, phys_pg_list, i) if (phys_pg_list->asid == ctx->asid) { dev_dbg(hdev->dev, "page list 0x%px of asid %d is still alive\n", phys_pg_list, ctx->asid); - atomic64_sub(phys_pg_list->total_size, - &hdev->dram_used_mem); - free_phys_pg_pack(hdev, phys_pg_list); + + atomic64_sub(phys_pg_list->total_size, &hdev->dram_used_mem); idr_remove(&vm->phys_pg_pack_handles, i); + list_add(&phys_pg_list->node, &free_list); } spin_unlock(&vm->idr_lock); + list_for_each_entry(phys_pg_list, &free_list, node) + free_phys_pg_pack(hdev, phys_pg_list); + va_range_fini(hdev, ctx->va_range[HL_VA_RANGE_TYPE_DRAM]); va_range_fini(hdev, ctx->va_range[HL_VA_RANGE_TYPE_HOST]); -- cgit v1.3.1 From ca4c8e4e7b57eec403e9887cd8b47d2ff8c97811 Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Wed, 12 Jan 2022 11:00:52 +0200 Subject: habanalabs: avoid copying pll data if pll_info_get fails If reading PLL info from F/W fails, the PLL info is not set in the "result" variable, and hence shouldn't be copied to the caller's array. Signed-off-by: Tomer Tayar Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 93e9045461ae..7f76f98154f0 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -958,15 +958,17 @@ int hl_fw_cpucp_pll_info_get(struct hl_device *hdev, u32 pll_index, rc = hdev->asic_funcs->send_cpu_message(hdev, (u32 *) &pkt, sizeof(pkt), HL_CPUCP_INFO_TIMEOUT_USEC, &result); - if (rc) + if (rc) { dev_err(hdev->dev, "Failed to read PLL info, error %d\n", rc); + return rc; + } pll_freq_arr[0] = FIELD_GET(CPUCP_PKT_RES_PLL_OUT0_MASK, result); pll_freq_arr[1] = FIELD_GET(CPUCP_PKT_RES_PLL_OUT1_MASK, result); pll_freq_arr[2] = FIELD_GET(CPUCP_PKT_RES_PLL_OUT2_MASK, result); pll_freq_arr[3] = FIELD_GET(CPUCP_PKT_RES_PLL_OUT3_MASK, result); - return rc; + return 0; } int hl_fw_cpucp_power_get(struct hl_device *hdev, u64 *power) -- cgit v1.3.1 From aa3e1f12a2c1d6e36ce18c153706c906306b2e2d Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Wed, 12 Jan 2022 11:20:41 +0200 Subject: habanalabs: add missing error check in sysfs clk_freq_mhz_show Add a missing error check in the sysfs show functions for clk_max_freq_mhz and clk_cur_freq_mhz_show. Signed-off-by: Tomer Tayar Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/sysfs.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/sysfs.c b/drivers/misc/habanalabs/common/sysfs.c index 3f220dd3b6b2..c665a3ac8876 100644 --- a/drivers/misc/habanalabs/common/sysfs.c +++ b/drivers/misc/habanalabs/common/sysfs.c @@ -18,6 +18,8 @@ static ssize_t clk_max_freq_mhz_show(struct device *dev, struct device_attribute return -ENODEV; value = hl_fw_get_frequency(hdev, hdev->asic_prop.clk_pll_index, false); + if (value < 0) + return value; hdev->asic_prop.max_freq_value = value; @@ -59,6 +61,8 @@ static ssize_t clk_cur_freq_mhz_show(struct device *dev, struct device_attribute return -ENODEV; value = hl_fw_get_frequency(hdev, hdev->asic_prop.clk_pll_index, true); + if (value < 0) + return value; return sprintf(buf, "%lu\n", (value / 1000 / 1000)); } -- cgit v1.3.1 From 15f8eb190573aa7e38c1024fb6d20abf626298df Mon Sep 17 00:00:00 2001 From: Dani Liberman Date: Tue, 11 Jan 2022 11:10:20 +0200 Subject: habanalabs: fix soft reset flow in case of failure In case of soft reset failure, hard reset should be initiated, but reset flags were not set to enable it, which caused another soft reset followed by another failure. Updated reset flags to enable hard reset flow in case of soft reset failure. Signed-off-by: Dani Liberman Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/device.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index c98a0a81e7d5..727315b36b8b 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -1293,11 +1293,14 @@ out_err: hdev->reset_info.hard_reset_cnt++; } else if (reset_upon_device_release) { dev_err(hdev->dev, "Failed to reset device after user release\n"); + flags |= HL_DRV_RESET_HARD; + flags &= ~HL_DRV_RESET_DEV_RELEASE; hard_reset = true; goto again; } else { dev_err(hdev->dev, "Failed to do soft-reset\n"); hdev->reset_info.soft_reset_cnt++; + flags |= HL_DRV_RESET_HARD; hard_reset = true; goto again; } -- cgit v1.3.1 From 4ae9548de7f84eb8f166f957cbcb9cc30f51bbd4 Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Wed, 12 Jan 2022 11:40:43 +0200 Subject: habanalabs: add missing error check in sysfs max_power_show Add a missing error check in the sysfs show function for max_power. Signed-off-by: Tomer Tayar Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 4 ++-- drivers/misc/habanalabs/common/habanalabs.h | 2 +- drivers/misc/habanalabs/common/sysfs.c | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 7f76f98154f0..39de9d86ee6c 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -2780,7 +2780,7 @@ void hl_fw_set_frequency(struct hl_device *hdev, u32 pll_index, u64 freq) used_pll_idx, rc); } -u64 hl_fw_get_max_power(struct hl_device *hdev) +long hl_fw_get_max_power(struct hl_device *hdev) { struct cpucp_packet pkt; u64 result; @@ -2794,7 +2794,7 @@ u64 hl_fw_get_max_power(struct hl_device *hdev) if (rc) { dev_err(hdev->dev, "Failed to get max power, error %d\n", rc); - return (u64) rc; + return rc; } return result; diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 9c8374d88907..995167020c27 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -3098,7 +3098,7 @@ int hl_get_current(struct hl_device *hdev, int sensor_index, u32 attr, long *val int hl_get_fan_speed(struct hl_device *hdev, int sensor_index, u32 attr, long *value); int hl_get_pwm_info(struct hl_device *hdev, int sensor_index, u32 attr, long *value); void hl_set_pwm_info(struct hl_device *hdev, int sensor_index, u32 attr, long value); -u64 hl_fw_get_max_power(struct hl_device *hdev); +long hl_fw_get_max_power(struct hl_device *hdev); void hl_fw_set_max_power(struct hl_device *hdev); int hl_set_voltage(struct hl_device *hdev, int sensor_index, u32 attr, long value); int hl_set_current(struct hl_device *hdev, int sensor_index, u32 attr, long value); diff --git a/drivers/misc/habanalabs/common/sysfs.c b/drivers/misc/habanalabs/common/sysfs.c index c665a3ac8876..9ebeb18ab85e 100644 --- a/drivers/misc/habanalabs/common/sysfs.c +++ b/drivers/misc/habanalabs/common/sysfs.c @@ -304,6 +304,8 @@ static ssize_t max_power_show(struct device *dev, struct device_attribute *attr, return -ENODEV; val = hl_fw_get_max_power(hdev); + if (val < 0) + return val; return sprintf(buf, "%lu\n", val); } -- cgit v1.3.1 From 008255ec3d799e82a5aa3e913800d196bcc5393a Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Mon, 17 Jan 2022 19:05:56 +0200 Subject: habanalabs: update to latest f/w specs Copy the latest versions of the f/w specs files. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/include/common/hl_boot_if.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/include/common/hl_boot_if.h b/drivers/misc/habanalabs/include/common/hl_boot_if.h index 135e21d6edc9..15f91ae9de6e 100644 --- a/drivers/misc/habanalabs/include/common/hl_boot_if.h +++ b/drivers/misc/habanalabs/include/common/hl_boot_if.h @@ -33,6 +33,7 @@ enum cpu_boot_err { CPU_BOOT_ERR_BOOT_FW_CRIT_ERR = 18, CPU_BOOT_ERR_BINNING_FAIL = 19, CPU_BOOT_ERR_TPM_FAIL = 20, + CPU_BOOT_ERR_TMP_THRESH_INIT_FAIL = 21, CPU_BOOT_ERR_ENABLED = 31, CPU_BOOT_ERR_SCND_EN = 63, CPU_BOOT_ERR_LAST = 64 /* we have 2 registers of 32 bits */ @@ -111,6 +112,9 @@ enum cpu_boot_err { * * CPU_BOOT_ERR0_TPM_FAIL TPM verification flow failed. * + * CPU_BOOT_ERR0_TMP_THRESH_INIT_FAIL Failed to set threshold for tmperature + * sensor. + * * CPU_BOOT_ERR0_ENABLED Error registers enabled. * This is a main indication that the * running FW populates the error @@ -134,6 +138,7 @@ enum cpu_boot_err { #define CPU_BOOT_ERR0_BOOT_FW_CRIT_ERR (1 << CPU_BOOT_ERR_BOOT_FW_CRIT_ERR) #define CPU_BOOT_ERR0_BINNING_FAIL (1 << CPU_BOOT_ERR_BINNING_FAIL) #define CPU_BOOT_ERR0_TPM_FAIL (1 << CPU_BOOT_ERR_TPM_FAIL) +#define CPU_BOOT_ERR0_TMP_THRESH_INIT_FAIL (1 << CPU_BOOT_ERR_TMP_THRESH_INIT_FAIL) #define CPU_BOOT_ERR0_ENABLED (1 << CPU_BOOT_ERR_ENABLED) #define CPU_BOOT_ERR1_ENABLED (1 << CPU_BOOT_ERR_ENABLED) -- cgit v1.3.1 From aa3766def7506e5d9bd6c8387dcfe3629eb2a1f2 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Tue, 18 Jan 2022 14:58:30 +0200 Subject: habanalabs: expose number of user interrupts Currently we only expose to the user the ID of the first available user interrupt. To make user interrupts allocation truly dynamic, we need to also expose the number of user interrupts. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/habanalabs_ioctl.c | 4 ++-- include/uapi/misc/habanalabs.h | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/habanalabs_ioctl.c b/drivers/misc/habanalabs/common/habanalabs_ioctl.c index d19097576b05..c13a3c2a7013 100644 --- a/drivers/misc/habanalabs/common/habanalabs_ioctl.c +++ b/drivers/misc/habanalabs/common/habanalabs_ioctl.c @@ -92,8 +92,8 @@ static int hw_ip_info(struct hl_device *hdev, struct hl_info_args *args) hw_ip.psoc_pci_pll_od = prop->psoc_pci_pll_od; hw_ip.psoc_pci_pll_div_factor = prop->psoc_pci_pll_div_factor; - hw_ip.first_available_interrupt_id = - prop->first_available_user_msix_interrupt; + hw_ip.first_available_interrupt_id = prop->first_available_user_msix_interrupt; + hw_ip.number_of_user_interrupts = prop->user_interrupt_count; hw_ip.server_type = prop->server_type; return copy_to_user(out, &hw_ip, diff --git a/include/uapi/misc/habanalabs.h b/include/uapi/misc/habanalabs.h index 371dfc4243b3..12976f7a8d84 100644 --- a/include/uapi/misc/habanalabs.h +++ b/include/uapi/misc/habanalabs.h @@ -404,6 +404,8 @@ enum hl_server_type { * @cpucp_version: The CPUCP f/w version. * @card_name: The card name as passed by the f/w. * @dram_page_size: The DRAM physical page size. + * @number_of_user_interrupts: The number of interrupts that are available to the userspace + * application to use. Relevant for Gaudi2 and later. */ struct hl_info_hw_ip_info { __u64 sram_base_address; @@ -428,6 +430,9 @@ struct hl_info_hw_ip_info { __u8 card_name[HL_INFO_CARD_NAME_MAX_LEN]; __u64 reserved2; __u64 dram_page_size; + __u32 reserved3; + __u16 number_of_user_interrupts; + __u16 pad2; }; struct hl_info_dram_usage { -- cgit v1.3.1 From 9a79e3e4a3637c07352d9723b825490a1b04391f Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Tue, 18 Jan 2022 12:16:53 +0200 Subject: habanalabs: reject host map with mmu disabled This is not something we can do a workaround. It is clearly an error and we should notify the user that it is an error. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/memory.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/memory.c b/drivers/misc/habanalabs/common/memory.c index 4a5d3a179765..f60a9638d9ea 100644 --- a/drivers/misc/habanalabs/common/memory.c +++ b/drivers/misc/habanalabs/common/memory.c @@ -1967,16 +1967,15 @@ err_dec_exporting_cnt: static int mem_ioctl_no_mmu(struct hl_fpriv *hpriv, union hl_mem_args *args) { struct hl_device *hdev = hpriv->hdev; - struct hl_ctx *ctx = hpriv->ctx; u64 block_handle, device_addr = 0; + struct hl_ctx *ctx = hpriv->ctx; u32 handle = 0, block_size; - int rc, dmabuf_fd = -EBADF; + int rc; switch (args->in.op) { case HL_MEM_OP_ALLOC: if (args->in.alloc.mem_size == 0) { - dev_err(hdev->dev, - "alloc size must be larger than 0\n"); + dev_err(hdev->dev, "alloc size must be larger than 0\n"); rc = -EINVAL; goto out; } @@ -1997,15 +1996,14 @@ static int mem_ioctl_no_mmu(struct hl_fpriv *hpriv, union hl_mem_args *args) case HL_MEM_OP_MAP: if (args->in.flags & HL_MEM_USERPTR) { - device_addr = args->in.map_host.host_virt_addr; - rc = 0; + dev_err(hdev->dev, "Failed to map host memory when MMU is disabled\n"); + rc = -EPERM; } else { - rc = get_paddr_from_handle(ctx, &args->in, - &device_addr); + rc = get_paddr_from_handle(ctx, &args->in, &device_addr); + memset(args, 0, sizeof(*args)); + args->out.device_virt_addr = device_addr; } - memset(args, 0, sizeof(*args)); - args->out.device_virt_addr = device_addr; break; case HL_MEM_OP_UNMAP: @@ -2013,20 +2011,14 @@ static int mem_ioctl_no_mmu(struct hl_fpriv *hpriv, union hl_mem_args *args) break; case HL_MEM_OP_MAP_BLOCK: - rc = map_block(hdev, args->in.map_block.block_addr, - &block_handle, &block_size); + rc = map_block(hdev, args->in.map_block.block_addr, &block_handle, &block_size); args->out.block_handle = block_handle; args->out.block_size = block_size; break; case HL_MEM_OP_EXPORT_DMABUF_FD: - rc = export_dmabuf_from_addr(ctx, - args->in.export_dmabuf_fd.handle, - args->in.export_dmabuf_fd.mem_size, - args->in.flags, - &dmabuf_fd); - memset(args, 0, sizeof(*args)); - args->out.fd = dmabuf_fd; + dev_err(hdev->dev, "Failed to export dma-buf object when MMU is disabled\n"); + rc = -EPERM; break; default: -- cgit v1.3.1 From 54faa5607b549ef7ef735e7d0c4523cc74bd20f4 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Wed, 19 Jan 2022 00:09:29 +0200 Subject: habanalabs: fix user interrupt wait when timeout is 0 When timeout is 0, we need to return the busy status in case the target value wasn't reached upon entry to the ioctl. Also return the correct timestamp. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/command_submission.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index 29e0549ff31d..8dd2f399d1c4 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -2858,8 +2858,7 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx, struct hl_cb_mgr *cb_mgr, u64 timeout_us, u64 cq_counters_handle, u64 cq_counters_offset, u64 target_value, struct hl_user_interrupt *interrupt, - u32 *status, - u64 *timestamp) + u32 *status, u64 *timestamp) { struct hl_user_pending_interrupt *pend; unsigned long timeout, flags; @@ -2900,10 +2899,13 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx, *status = HL_WAIT_CS_STATUS_COMPLETED; /* There was no interrupt, we assume the completion is now. */ pend->fence.timestamp = ktime_get(); - } + goto set_timestamp; - if (!timeout_us || (*status == HL_WAIT_CS_STATUS_COMPLETED)) + } else if (!timeout_us) { + *status = HL_WAIT_CS_STATUS_BUSY; + pend->fence.timestamp = ktime_get(); goto set_timestamp; + } /* Add pending user interrupt to relevant list for the interrupt * handler to monitor -- cgit v1.3.1 From 7a78d4d4819ec75c749d591c432d50cf7003448b Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Wed, 19 Jan 2022 00:10:43 +0200 Subject: habanalabs: fix race between wait and irq There is a race in the user interrupts code, where between checking the target value and adding the new pend to the list, there is a chance the interrupt happened. In that case, no one will complete the node, and we will get a timeout on it. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/command_submission.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index 8dd2f399d1c4..307a95a039e0 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -2892,16 +2892,21 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx, pend->cq_kernel_addr = (u64 *) cb->kernel_address + cq_counters_offset; pend->cq_target_value = target_value; + spin_lock_irqsave(&interrupt->wait_list_lock, flags); + /* We check for completion value as interrupt could have been received * before we added the node to the wait list */ if (*pend->cq_kernel_addr >= target_value) { + spin_unlock_irqrestore(&interrupt->wait_list_lock, flags); + *status = HL_WAIT_CS_STATUS_COMPLETED; /* There was no interrupt, we assume the completion is now. */ pend->fence.timestamp = ktime_get(); goto set_timestamp; } else if (!timeout_us) { + spin_unlock_irqrestore(&interrupt->wait_list_lock, flags); *status = HL_WAIT_CS_STATUS_BUSY; pend->fence.timestamp = ktime_get(); goto set_timestamp; @@ -2910,7 +2915,6 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx, /* Add pending user interrupt to relevant list for the interrupt * handler to monitor */ - spin_lock_irqsave(&interrupt->wait_list_lock, flags); list_add_tail(&pend->wait_list_node, &interrupt->wait_list_head); spin_unlock_irqrestore(&interrupt->wait_list_lock, flags); -- cgit v1.3.1 From 930feb41efe2e799992ae07c1a274f68be7980ea Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Tue, 18 Jan 2022 12:31:15 +0200 Subject: habanalabs: prevent false heartbeat failure during soft-reset The heartbeat thread is active during soft-reset, and it tries to send messages to CPU-CP core. Within the soft-reset, in the time window in which the device is marked as disabled, any CPU-CP command is "silently" skipped and a success value it returned. However, in addition to the return value, the heartbeat function also checks the F/W result, but because no command is sent in this time window, the result variable won't hold the expected value and we will have a false heartbeat failure. To avoid it, modify the "silent" skip to be done only in hard-reset. The CPU-CP should be able to handle messages during soft-reset. In addition to the heartbeat problem, this should also solve other issues in other flows that send messages during soft-reset and use the F/W result as it w/o being aware to the reset. Signed-off-by: Tomer Tayar Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 39de9d86ee6c..11957d36c6a9 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -214,7 +214,7 @@ int hl_fw_send_cpu_message(struct hl_device *hdev, u32 hw_queue_id, u32 *msg, dma_addr_t pkt_dma_addr; struct hl_bd *sent_bd; u32 tmp, expected_ack_val, pi; - int rc = 0; + int rc; pkt = hdev->asic_funcs->cpu_accessible_dma_pool_alloc(hdev, len, &pkt_dma_addr); @@ -228,8 +228,11 @@ int hl_fw_send_cpu_message(struct hl_device *hdev, u32 hw_queue_id, u32 *msg, mutex_lock(&hdev->send_cpu_message_lock); - if (hdev->disabled) + /* CPU-CP messages can be sent during soft-reset */ + if (hdev->disabled && !hdev->reset_info.is_in_soft_reset) { + rc = 0; goto out; + } if (hdev->device_cpu_disabled) { rc = -EIO; -- cgit v1.3.1 From d2cfd6897ce06aed87d989bf2a0b2d6bbba579db Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Thu, 20 Jan 2022 13:11:55 +0200 Subject: habanalabs: remove duplicate print We print detailed messages inside the internal ioctl functions. No need to print a generic message at the end, it doesn't add any information. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/command_submission.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index 307a95a039e0..0ea9a73e4aa5 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -3126,13 +3126,8 @@ static int hl_interrupt_wait_ioctl(struct hl_fpriv *hpriv, void *data) args->in.interrupt_timeout_us, args->in.addr, args->in.target, interrupt, &status, ×tamp); - if (rc) { - if (rc != -EINTR) - dev_err_ratelimited(hdev->dev, - "interrupt_wait_ioctl failed (%d)\n", rc); - + if (rc) return rc; - } memset(args, 0, sizeof(*args)); args->out.status = status; -- cgit v1.3.1 From a8076c47f6f78e5709d3a6b89c146c2706637f02 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 11 Jan 2022 10:16:51 +0300 Subject: habanalabs: silence an uninitialized variable warning Smatch warns that: drivers/misc/habanalabs/common/command_buffer.c:471 hl_cb_ioctl() error: uninitialized symbol 'device_va'. Which is true, but harmless. Anyway, it's easy to silence this by adding a error check. Signed-off-by: Dan Carpenter Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/command_buffer.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/command_buffer.c b/drivers/misc/habanalabs/common/command_buffer.c index 3c0ae07a2d80..b9483a3cee91 100644 --- a/drivers/misc/habanalabs/common/command_buffer.c +++ b/drivers/misc/habanalabs/common/command_buffer.c @@ -464,6 +464,8 @@ int hl_cb_ioctl(struct hl_fpriv *hpriv, void *data) args->in.flags, &usage_cnt, &device_va); + if (rc) + break; memset(&args->out, 0, sizeof(args->out)); -- cgit v1.3.1 From b32cd10480ebcfd66c3f7ae9fece951e5b5b35ae Mon Sep 17 00:00:00 2001 From: Dani Liberman Date: Mon, 27 Dec 2021 21:18:03 +0200 Subject: habanalabs: fix race when waiting on encaps signal Scenario: 1. CS which is part of encaps signal has been completed and now executing kref_put to its encaps signal handle. The refcount of the handle decremented to 0, and called the encaps signal handle release function - hl_encaps_handle_do_release. 2. At this point the user starts waiting on the signal, and finds the encaps signal handle in the handlers list and increment the habdle refcount to 1. 3. Immediately after, hl_encaps_handle_do_release removed the handle from the list and free its memory. 4. Wait function using the handle although it has been freed. This scenario caused the slab area which was previously allocated for the handle to be poison overwritten which triggered kernel bug the next time the OS needed to allocate this slab. Fixed by getting the refcount of the handle only in case it is not zero. Signed-off-by: Dani Liberman Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/command_submission.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index 0ea9a73e4aa5..ba5215b77852 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -2063,13 +2063,16 @@ static int cs_ioctl_signal_wait(struct hl_fpriv *hpriv, enum hl_cs_type cs_type, idp = &ctx->sig_mgr.handles; idr_for_each_entry(idp, encaps_sig_hdl, id) { if (encaps_sig_hdl->cs_seq == signal_seq) { - handle_found = true; - /* get refcount to protect removing - * this handle from idr, needed when - * multiple wait cs are used with offset + /* get refcount to protect removing this handle from idr, + * needed when multiple wait cs are used with offset * to wait on reserved encaps signals. + * Since kref_put of this handle is executed outside the + * current lock, it is possible that the handle refcount + * is 0 but it yet to be removed from the list. In this + * case need to consider the handle as not valid. */ - kref_get(&encaps_sig_hdl->refcount); + if (kref_get_unless_zero(&encaps_sig_hdl->refcount)) + handle_found = true; break; } } -- cgit v1.3.1 From 9158bf69e74f98fea6847cca93bbf33a589bebcd Mon Sep 17 00:00:00 2001 From: farah kassabri Date: Thu, 23 Dec 2021 13:24:34 +0200 Subject: habanalabs: Timestamps buffers registration Timestamp registration API allows the user to register a timestamp record event which will make the driver set timestamp when CQ counter reaches the target value and write it to a specific location specified by the user. This is a non blocking API, unlike the wait_for_interrupt which is a blocking one. Signed-off-by: farah kassabri Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- .../misc/habanalabs/common/command_submission.c | 197 +++++++++++++--- drivers/misc/habanalabs/common/device.c | 18 +- drivers/misc/habanalabs/common/habanalabs.h | 106 ++++++++- drivers/misc/habanalabs/common/habanalabs_drv.c | 2 + drivers/misc/habanalabs/common/irq.c | 127 +++++++++- drivers/misc/habanalabs/common/memory.c | 261 +++++++++++++++++++++ include/uapi/misc/habanalabs.h | 37 ++- 7 files changed, 690 insertions(+), 58 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index ba5215b77852..c7757c78d0b1 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -14,6 +14,8 @@ #define HL_CS_FLAGS_TYPE_MASK (HL_CS_FLAGS_SIGNAL | HL_CS_FLAGS_WAIT | \ HL_CS_FLAGS_COLLECTIVE_WAIT) +#define MAX_TS_ITER_NUM 10 + /** * enum hl_cs_wait_status - cs wait status * @CS_WAIT_STATUS_BUSY: cs was not completed yet @@ -924,7 +926,7 @@ void hl_cs_rollback_all(struct hl_device *hdev) int i; struct hl_cs *cs, *tmp; - flush_workqueue(hdev->sob_reset_wq); + flush_workqueue(hdev->ts_free_obj_wq); /* flush all completions before iterating over the CS mirror list in * order to avoid a race with the release functions @@ -948,13 +950,19 @@ void hl_cs_rollback_all(struct hl_device *hdev) static void wake_pending_user_interrupt_threads(struct hl_user_interrupt *interrupt) { - struct hl_user_pending_interrupt *pend; + struct hl_user_pending_interrupt *pend, *temp; unsigned long flags; spin_lock_irqsave(&interrupt->wait_list_lock, flags); - list_for_each_entry(pend, &interrupt->wait_list_head, wait_list_node) { - pend->fence.error = -EIO; - complete_all(&pend->fence.completion); + list_for_each_entry_safe(pend, temp, &interrupt->wait_list_head, wait_list_node) { + if (pend->ts_reg_info.ts_buff) { + list_del(&pend->wait_list_node); + hl_ts_put(pend->ts_reg_info.ts_buff); + hl_cb_put(pend->ts_reg_info.cq_cb); + } else { + pend->fence.error = -EIO; + complete_all(&pend->fence.completion); + } } spin_unlock_irqrestore(&interrupt->wait_list_lock, flags); } @@ -2857,43 +2865,133 @@ static int hl_cs_wait_ioctl(struct hl_fpriv *hpriv, void *data) return 0; } +static int ts_buff_get_kernel_ts_record(struct hl_ts_buff *ts_buff, + struct hl_cb *cq_cb, + u64 ts_offset, u64 cq_offset, u64 target_value, + spinlock_t *wait_list_lock, + struct hl_user_pending_interrupt **pend) +{ + struct hl_user_pending_interrupt *requested_offset_record = + (struct hl_user_pending_interrupt *)ts_buff->kernel_buff_address + + ts_offset; + struct hl_user_pending_interrupt *cb_last = + (struct hl_user_pending_interrupt *)ts_buff->kernel_buff_address + + (ts_buff->kernel_buff_size / sizeof(struct hl_user_pending_interrupt)); + unsigned long flags, iter_counter = 0; + u64 current_cq_counter; + + /* Validate ts_offset not exceeding last max */ + if (requested_offset_record > cb_last) { + dev_err(ts_buff->hdev->dev, "Ts offset exceeds max CB offset(0x%llx)\n", + (u64)(uintptr_t)cb_last); + return -EINVAL; + } + +start_over: + spin_lock_irqsave(wait_list_lock, flags); + + /* Unregister only if we didn't reach the target value + * since in this case there will be no handling in irq context + * and then it's safe to delete the node out of the interrupt list + * then re-use it on other interrupt + */ + if (requested_offset_record->ts_reg_info.in_use) { + current_cq_counter = *requested_offset_record->cq_kernel_addr; + if (current_cq_counter < requested_offset_record->cq_target_value) { + list_del(&requested_offset_record->wait_list_node); + spin_unlock_irqrestore(wait_list_lock, flags); + + hl_ts_put(requested_offset_record->ts_reg_info.ts_buff); + hl_cb_put(requested_offset_record->ts_reg_info.cq_cb); + + dev_dbg(ts_buff->hdev->dev, "ts node removed from interrupt list now can re-use\n"); + } else { + dev_dbg(ts_buff->hdev->dev, "ts node in middle of irq handling\n"); + + /* irq handling in the middle give it time to finish */ + spin_unlock_irqrestore(wait_list_lock, flags); + usleep_range(1, 10); + if (++iter_counter == MAX_TS_ITER_NUM) { + dev_err(ts_buff->hdev->dev, "handling registration interrupt took too long!!\n"); + return -EINVAL; + } + + goto start_over; + } + } else { + spin_unlock_irqrestore(wait_list_lock, flags); + } + + /* Fill up the new registration node info */ + requested_offset_record->ts_reg_info.in_use = 1; + requested_offset_record->ts_reg_info.ts_buff = ts_buff; + requested_offset_record->ts_reg_info.cq_cb = cq_cb; + requested_offset_record->ts_reg_info.timestamp_kernel_addr = + (u64 *) ts_buff->user_buff_address + ts_offset; + requested_offset_record->cq_kernel_addr = + (u64 *) cq_cb->kernel_address + cq_offset; + requested_offset_record->cq_target_value = target_value; + + *pend = requested_offset_record; + + dev_dbg(ts_buff->hdev->dev, "Found available node in TS kernel CB(0x%llx)\n", + (u64)(uintptr_t)requested_offset_record); + return 0; +} + static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx, - struct hl_cb_mgr *cb_mgr, u64 timeout_us, - u64 cq_counters_handle, u64 cq_counters_offset, + struct hl_cb_mgr *cb_mgr, struct hl_ts_mgr *ts_mgr, + u64 timeout_us, u64 cq_counters_handle, u64 cq_counters_offset, u64 target_value, struct hl_user_interrupt *interrupt, + bool register_ts_record, u64 ts_handle, u64 ts_offset, u32 *status, u64 *timestamp) { + u32 cq_patched_handle, ts_patched_handle; struct hl_user_pending_interrupt *pend; + struct hl_ts_buff *ts_buff; + struct hl_cb *cq_cb; unsigned long timeout, flags; long completion_rc; - struct hl_cb *cb; int rc = 0; - u32 handle; timeout = hl_usecs64_to_jiffies(timeout_us); hl_ctx_get(hdev, ctx); - cq_counters_handle >>= PAGE_SHIFT; - handle = (u32) cq_counters_handle; - - cb = hl_cb_get(hdev, cb_mgr, handle); - if (!cb) { - hl_ctx_put(ctx); - return -EINVAL; + cq_patched_handle = lower_32_bits(cq_counters_handle >> PAGE_SHIFT); + cq_cb = hl_cb_get(hdev, cb_mgr, cq_patched_handle); + if (!cq_cb) { + rc = -EINVAL; + goto put_ctx; } - pend = kzalloc(sizeof(*pend), GFP_KERNEL); - if (!pend) { - hl_cb_put(cb); - hl_ctx_put(ctx); - return -ENOMEM; - } + if (register_ts_record) { + dev_dbg(hdev->dev, "Timestamp registration: interrupt id: %u, ts offset: %llu, cq_offset: %llu\n", + interrupt->interrupt_id, ts_offset, cq_counters_offset); - hl_fence_init(&pend->fence, ULONG_MAX); + ts_patched_handle = lower_32_bits(ts_handle >> PAGE_SHIFT); + ts_buff = hl_ts_get(hdev, ts_mgr, ts_patched_handle); + if (!ts_buff) { + rc = -EINVAL; + goto put_cq_cb; + } - pend->cq_kernel_addr = (u64 *) cb->kernel_address + cq_counters_offset; - pend->cq_target_value = target_value; + /* Find first available record */ + rc = ts_buff_get_kernel_ts_record(ts_buff, cq_cb, ts_offset, + cq_counters_offset, target_value, + &interrupt->wait_list_lock, &pend); + if (rc) + goto put_ts_buff; + } else { + pend = kzalloc(sizeof(*pend), GFP_KERNEL); + if (!pend) { + rc = -ENOMEM; + goto put_cq_cb; + } + hl_fence_init(&pend->fence, ULONG_MAX); + pend->cq_kernel_addr = (u64 *) cq_cb->kernel_address + cq_counters_offset; + pend->cq_target_value = target_value; + } spin_lock_irqsave(&interrupt->wait_list_lock, flags); @@ -2901,13 +2999,19 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx, * before we added the node to the wait list */ if (*pend->cq_kernel_addr >= target_value) { + if (register_ts_record) + pend->ts_reg_info.in_use = 0; spin_unlock_irqrestore(&interrupt->wait_list_lock, flags); *status = HL_WAIT_CS_STATUS_COMPLETED; - /* There was no interrupt, we assume the completion is now. */ - pend->fence.timestamp = ktime_get(); - goto set_timestamp; + if (register_ts_record) { + *pend->ts_reg_info.timestamp_kernel_addr = ktime_get_ns(); + goto put_ts_buff; + } else { + pend->fence.timestamp = ktime_get(); + goto set_timestamp; + } } else if (!timeout_us) { spin_unlock_irqrestore(&interrupt->wait_list_lock, flags); *status = HL_WAIT_CS_STATUS_BUSY; @@ -2916,11 +3020,19 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx, } /* Add pending user interrupt to relevant list for the interrupt - * handler to monitor + * handler to monitor. + * Note that we cannot have sorted list by target value, + * in order to shorten the list pass loop, since + * same list could have nodes for different cq counter handle. */ list_add_tail(&pend->wait_list_node, &interrupt->wait_list_head); spin_unlock_irqrestore(&interrupt->wait_list_lock, flags); + if (register_ts_record) { + rc = *status = HL_WAIT_CS_STATUS_COMPLETED; + goto ts_registration_exit; + } + /* Wait for interrupt handler to signal completion */ completion_rc = wait_for_completion_interruptible_timeout(&pend->fence.completion, timeout); @@ -2952,15 +3064,30 @@ static int _hl_interrupt_wait_ioctl(struct hl_device *hdev, struct hl_ctx *ctx, } } + /* + * We keep removing the node from list here, and not at the irq handler + * for completion timeout case. and if it's a registration + * for ts record, the node will be deleted in the irq handler after + * we reach the target value. + */ spin_lock_irqsave(&interrupt->wait_list_lock, flags); list_del(&pend->wait_list_node); spin_unlock_irqrestore(&interrupt->wait_list_lock, flags); set_timestamp: *timestamp = ktime_to_ns(pend->fence.timestamp); - kfree(pend); - hl_cb_put(cb); + hl_cb_put(cq_cb); +ts_registration_exit: + hl_ctx_put(ctx); + + return rc; + +put_ts_buff: + hl_ts_put(ts_buff); +put_cq_cb: + hl_cb_put(cq_cb); +put_ctx: hl_ctx_put(ctx); return rc; @@ -3119,11 +3246,13 @@ static int hl_interrupt_wait_ioctl(struct hl_fpriv *hpriv, void *data) interrupt = &hdev->user_interrupt[interrupt_id - first_interrupt]; if (args->in.flags & HL_WAIT_CS_FLAGS_INTERRUPT_KERNEL_CQ) - rc = _hl_interrupt_wait_ioctl(hdev, hpriv->ctx, &hpriv->cb_mgr, + rc = _hl_interrupt_wait_ioctl(hdev, hpriv->ctx, &hpriv->cb_mgr, &hpriv->ts_mem_mgr, args->in.interrupt_timeout_us, args->in.cq_counters_handle, args->in.cq_counters_offset, - args->in.target, interrupt, &status, - ×tamp); + args->in.target, interrupt, + !!(args->in.flags & HL_WAIT_CS_FLAGS_REGISTER_INTERRUPT), + args->in.timestamp_handle, args->in.timestamp_offset, + &status, ×tamp); else rc = _hl_interrupt_wait_ioctl_user_addr(hdev, hpriv->ctx, args->in.interrupt_timeout_us, args->in.addr, diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index 727315b36b8b..60bfd737404b 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -145,6 +145,7 @@ static int hl_device_release(struct inode *inode, struct file *filp) hl_release_pending_user_interrupts(hpriv->hdev); hl_cb_mgr_fini(hdev, &hpriv->cb_mgr); + hl_ts_mgr_fini(hpriv->hdev, &hpriv->ts_mem_mgr); hl_ctx_mgr_fini(hdev, &hpriv->ctx_mgr); if (!hl_hpriv_put(hpriv)) @@ -209,6 +210,9 @@ static int hl_mmap(struct file *filp, struct vm_area_struct *vma) case HL_MMAP_TYPE_BLOCK: return hl_hw_block_mmap(hpriv, vma); + + case HL_MMAP_TYPE_TS_BUFF: + return hl_ts_mmap(hpriv, vma); } return -EINVAL; @@ -410,10 +414,10 @@ static int device_early_init(struct hl_device *hdev) goto free_cq_wq; } - hdev->sob_reset_wq = alloc_workqueue("hl-sob-reset", WQ_UNBOUND, 0); - if (!hdev->sob_reset_wq) { + hdev->ts_free_obj_wq = alloc_workqueue("hl-ts-free-obj", WQ_UNBOUND, 0); + if (!hdev->ts_free_obj_wq) { dev_err(hdev->dev, - "Failed to allocate SOB reset workqueue\n"); + "Failed to allocate Timestamp registration free workqueue\n"); rc = -ENOMEM; goto free_eq_wq; } @@ -422,7 +426,7 @@ static int device_early_init(struct hl_device *hdev) GFP_KERNEL); if (!hdev->hl_chip_info) { rc = -ENOMEM; - goto free_sob_reset_wq; + goto free_ts_free_wq; } rc = hl_mmu_if_set_funcs(hdev); @@ -461,8 +465,8 @@ free_cb_mgr: hl_cb_mgr_fini(hdev, &hdev->kernel_cb_mgr); free_chip_info: kfree(hdev->hl_chip_info); -free_sob_reset_wq: - destroy_workqueue(hdev->sob_reset_wq); +free_ts_free_wq: + destroy_workqueue(hdev->ts_free_obj_wq); free_eq_wq: destroy_workqueue(hdev->eq_wq); free_cq_wq: @@ -501,7 +505,7 @@ static void device_early_fini(struct hl_device *hdev) kfree(hdev->hl_chip_info); - destroy_workqueue(hdev->sob_reset_wq); + destroy_workqueue(hdev->ts_free_obj_wq); destroy_workqueue(hdev->eq_wq); destroy_workqueue(hdev->device_reset_work.wq); diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 995167020c27..b06e2b0812b6 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -31,14 +31,15 @@ #define HL_NAME "habanalabs" /* Use upper bits of mmap offset to store habana driver specific information. - * bits[63:61] - Encode mmap type + * bits[63:59] - Encode mmap type * bits[45:0] - mmap offset value * * NOTE: struct vm_area_struct.vm_pgoff uses offset in pages. Hence, these * defines are w.r.t to PAGE_SIZE */ -#define HL_MMAP_TYPE_SHIFT (61 - PAGE_SHIFT) -#define HL_MMAP_TYPE_MASK (0x7ull << HL_MMAP_TYPE_SHIFT) +#define HL_MMAP_TYPE_SHIFT (59 - PAGE_SHIFT) +#define HL_MMAP_TYPE_MASK (0x1full << HL_MMAP_TYPE_SHIFT) +#define HL_MMAP_TYPE_TS_BUFF (0x10ull << HL_MMAP_TYPE_SHIFT) #define HL_MMAP_TYPE_BLOCK (0x4ull << HL_MMAP_TYPE_SHIFT) #define HL_MMAP_TYPE_CB (0x2ull << HL_MMAP_TYPE_SHIFT) @@ -709,6 +710,40 @@ struct hl_cb_mgr { struct idr cb_handles; /* protected by cb_lock */ }; +/** + * struct hl_ts_mgr - describes the timestamp registration memory manager. + * @ts_lock: protects ts_handles. + * @ts_handles: an idr to hold all ts bufferes handles. + */ +struct hl_ts_mgr { + spinlock_t ts_lock; + struct idr ts_handles; +}; + +/** + * struct hl_ts_buff - describes a timestamp buffer. + * @refcount: reference counter for usage of the buffer. + * @hdev: pointer to device this buffer belongs to. + * @mmap: true if the buff is currently mapped to user. + * @kernel_buff_address: Holds the internal buffer's kernel virtual address. + * @user_buff_address: Holds the user buffer's kernel virtual address. + * @id: the buffer ID. + * @mmap_size: Holds the buffer size that was mmaped. + * @kernel_buff_size: Holds the internal kernel buffer size. + * @user_buff_size: Holds the user buffer size. + */ +struct hl_ts_buff { + struct kref refcount; + struct hl_device *hdev; + atomic_t mmap; + void *kernel_buff_address; + void *user_buff_address; + u32 id; + u32 mmap_size; + u32 kernel_buff_size; + u32 user_buff_size; +}; + /** * struct hl_cb - describes a Command Buffer. * @refcount: reference counter for usage of the CB. @@ -886,9 +921,54 @@ struct hl_user_interrupt { u32 interrupt_id; }; +/** + * struct timestamp_reg_free_node - holds the timestamp registration free objects node + * @free_objects_node: node in the list free_obj_jobs + * @cq_cb: pointer to cq command buffer to be freed + * @ts_buff: pointer to timestamp buffer to be freed + */ +struct timestamp_reg_free_node { + struct list_head free_objects_node; + struct hl_cb *cq_cb; + struct hl_ts_buff *ts_buff; +}; + +/* struct timestamp_reg_work_obj - holds the timestamp registration free objects job + * the job will be to pass over the free_obj_jobs list and put refcount to objects + * in each node of the list + * @free_obj: workqueue object to free timestamp registration node objects + * @hdev: pointer to the device structure + * @free_obj_head: list of free jobs nodes (node type timestamp_reg_free_node) + */ +struct timestamp_reg_work_obj { + struct work_struct free_obj; + struct hl_device *hdev; + struct list_head *free_obj_head; +}; + +/* struct timestamp_reg_info - holds the timestamp registration related data. + * @ts_buff: pointer to the timestamp buffer which include both user/kernel buffers. + * relevant only when doing timestamps records registration. + * @cq_cb: pointer to CQ counter CB. + * @timestamp_kernel_addr: timestamp handle address, where to set timestamp + * relevant only when doing timestamps records + * registration. + * @in_use: indicates if the node already in use. relevant only when doing + * timestamps records registration, since in this case the driver + * will have it's own buffer which serve as a records pool instead of + * allocating records dynamically. + */ +struct timestamp_reg_info { + struct hl_ts_buff *ts_buff; + struct hl_cb *cq_cb; + u64 *timestamp_kernel_addr; + u8 in_use; +}; + /** * struct hl_user_pending_interrupt - holds a context to a user thread * pending on an interrupt + * @ts_reg_info: holds the timestamps registration nodes info * @wait_list_node: node in the list of user threads pending on an interrupt * @fence: hl fence object for interrupt completion * @cq_target_value: CQ target value @@ -896,10 +976,11 @@ struct hl_user_interrupt { * handler for taget value comparison */ struct hl_user_pending_interrupt { - struct list_head wait_list_node; - struct hl_fence fence; - u64 cq_target_value; - u64 *cq_kernel_addr; + struct timestamp_reg_info ts_reg_info; + struct list_head wait_list_node; + struct hl_fence fence; + u64 cq_target_value; + u64 *cq_kernel_addr; }; /** @@ -1833,6 +1914,7 @@ struct hl_debug_params { * @ctx: current executing context. TODO: remove for multiple ctx per process * @ctx_mgr: context manager to handle multiple context for this FD. * @cb_mgr: command buffer manager to handle multiple buffers for this FD. + * @ts_mem_mgr: timestamp registration manager for alloc/free/map timestamp buffers. * @debugfs_list: list of relevant ASIC debugfs. * @dev_node: node in the device list of file private data * @refcount: number of related contexts. @@ -1845,6 +1927,7 @@ struct hl_fpriv { struct hl_ctx *ctx; struct hl_ctx_mgr ctx_mgr; struct hl_cb_mgr cb_mgr; + struct hl_ts_mgr ts_mem_mgr; struct list_head debugfs_list; struct list_head dev_node; struct kref refcount; @@ -2517,7 +2600,7 @@ struct hl_reset_info { * @cq_wq: work queues of completion queues for executing work in process * context. * @eq_wq: work queue of event queue for executing work in process context. - * @sob_reset_wq: work queue for sob reset executions. + * @ts_free_obj_wq: work queue for timestamp registration objects release. * @kernel_ctx: Kernel driver context structure. * @kernel_queues: array of hl_hw_queue. * @cs_mirror_list: CS mirror list for TDR. @@ -2645,7 +2728,7 @@ struct hl_device { struct hl_user_interrupt common_user_interrupt; struct workqueue_struct **cq_wq; struct workqueue_struct *eq_wq; - struct workqueue_struct *sob_reset_wq; + struct workqueue_struct *ts_free_obj_wq; struct hl_ctx *kernel_ctx; struct hl_hw_queue *kernel_queues; struct list_head cs_mirror_list; @@ -3128,6 +3211,11 @@ __printf(4, 5) int hl_snprintf_resize(char **buf, size_t *size, size_t *offset, const char *format, ...); char *hl_format_as_binary(char *buf, size_t buf_len, u32 n); const char *hl_sync_engine_to_string(enum hl_sync_engine_type engine_type); +void hl_ts_mgr_init(struct hl_ts_mgr *mgr); +void hl_ts_mgr_fini(struct hl_device *hdev, struct hl_ts_mgr *mgr); +int hl_ts_mmap(struct hl_fpriv *hpriv, struct vm_area_struct *vma); +struct hl_ts_buff *hl_ts_get(struct hl_device *hdev, struct hl_ts_mgr *mgr, u32 handle); +void hl_ts_put(struct hl_ts_buff *buff); #ifdef CONFIG_DEBUG_FS diff --git a/drivers/misc/habanalabs/common/habanalabs_drv.c b/drivers/misc/habanalabs/common/habanalabs_drv.c index 017bfc4551da..ca404ed9d9a7 100644 --- a/drivers/misc/habanalabs/common/habanalabs_drv.c +++ b/drivers/misc/habanalabs/common/habanalabs_drv.c @@ -140,6 +140,7 @@ int hl_device_open(struct inode *inode, struct file *filp) hl_cb_mgr_init(&hpriv->cb_mgr); hl_ctx_mgr_init(&hpriv->ctx_mgr); + hl_ts_mgr_init(&hpriv->ts_mem_mgr); hpriv->taskpid = get_task_pid(current, PIDTYPE_PID); @@ -184,6 +185,7 @@ int hl_device_open(struct inode *inode, struct file *filp) out_err: mutex_unlock(&hdev->fpriv_list_lock); hl_cb_mgr_fini(hpriv->hdev, &hpriv->cb_mgr); + hl_ts_mgr_fini(hpriv->hdev, &hpriv->ts_mem_mgr); hl_ctx_mgr_fini(hpriv->hdev, &hpriv->ctx_mgr); filp->private_data = NULL; mutex_destroy(&hpriv->restore_phase_mutex); diff --git a/drivers/misc/habanalabs/common/irq.c b/drivers/misc/habanalabs/common/irq.c index 1b6bdc900c26..c28f3a1c7a03 100644 --- a/drivers/misc/habanalabs/common/irq.c +++ b/drivers/misc/habanalabs/common/irq.c @@ -137,22 +137,137 @@ irqreturn_t hl_irq_handler_cq(int irq, void *arg) return IRQ_HANDLED; } +/* + * hl_ts_free_objects - handler of the free objects workqueue. + * This function should put refcount to objects that the registration node + * took refcount to them. + * @work: workqueue object pointer + */ +static void hl_ts_free_objects(struct work_struct *work) +{ + struct timestamp_reg_work_obj *job = + container_of(work, struct timestamp_reg_work_obj, free_obj); + struct timestamp_reg_free_node *free_obj, *temp_free_obj; + struct list_head *free_list_head = job->free_obj_head; + struct hl_device *hdev = job->hdev; + + list_for_each_entry_safe(free_obj, temp_free_obj, free_list_head, free_objects_node) { + dev_dbg(hdev->dev, "About to put refcount to ts_buff (%p) cq_cb(%p)\n", + free_obj->ts_buff, + free_obj->cq_cb); + + hl_ts_put(free_obj->ts_buff); + hl_cb_put(free_obj->cq_cb); + kfree(free_obj); + } + + kfree(free_list_head); + kfree(job); +} + +/* + * This function called with spin_lock of wait_list_lock taken + * This function will set timestamp and delete the registration node from the + * wait_list_lock. + * and since we're protected with spin_lock here, so we cannot just put the refcount + * for the objects here, since the release function may be called and it's also a long + * logic (which might sleep also) that cannot be handled in irq context. + * so here we'll be filling a list with nodes of "put" jobs and then will send this + * list to a dedicated workqueue to do the actual put. + */ +int handle_registration_node(struct hl_device *hdev, struct hl_user_pending_interrupt *pend, + struct list_head **free_list) +{ + struct timestamp_reg_free_node *free_node; + u64 timestamp; + + if (!(*free_list)) { + /* Alloc/Init the timestamp registration free objects list */ + *free_list = kmalloc(sizeof(struct list_head), GFP_ATOMIC); + if (!(*free_list)) + return -ENOMEM; + + INIT_LIST_HEAD(*free_list); + } + + free_node = kmalloc(sizeof(*free_node), GFP_ATOMIC); + if (!free_node) + return -ENOMEM; + + timestamp = ktime_get_ns(); + + *pend->ts_reg_info.timestamp_kernel_addr = timestamp; + + dev_dbg(hdev->dev, "Timestamp is set to ts cb address (%p), ts: 0x%llx\n", + pend->ts_reg_info.timestamp_kernel_addr, + *(u64 *)pend->ts_reg_info.timestamp_kernel_addr); + + list_del(&pend->wait_list_node); + + /* Mark kernel CB node as free */ + pend->ts_reg_info.in_use = 0; + + /* Putting the refcount for ts_buff and cq_cb objects will be handled + * in workqueue context, just add job to free_list. + */ + free_node->ts_buff = pend->ts_reg_info.ts_buff; + free_node->cq_cb = pend->ts_reg_info.cq_cb; + list_add(&free_node->free_objects_node, *free_list); + + return 0; +} + static void handle_user_cq(struct hl_device *hdev, struct hl_user_interrupt *user_cq) { - struct hl_user_pending_interrupt *pend; + struct hl_user_pending_interrupt *pend, *temp_pend; + struct list_head *ts_reg_free_list_head = NULL; + struct timestamp_reg_work_obj *job; + bool reg_node_handle_fail = false; ktime_t now = ktime_get(); + int rc; + + /* For registration nodes: + * As part of handling the registration nodes, we should put refcount to + * some objects. the problem is that we cannot do that under spinlock + * or in irq handler context at all (since release functions are long and + * might sleep), so we will need to handle that part in workqueue context. + * To avoid handling kmalloc failure which compels us rolling back actions + * and move nodes hanged on the free list back to the interrupt wait list + * we always alloc the job of the WQ at the beginning. + */ + job = kmalloc(sizeof(*job), GFP_ATOMIC); + if (!job) + return; spin_lock(&user_cq->wait_list_lock); - list_for_each_entry(pend, &user_cq->wait_list_head, wait_list_node) { - if ((pend->cq_kernel_addr && - *(pend->cq_kernel_addr) >= pend->cq_target_value) || + list_for_each_entry_safe(pend, temp_pend, &user_cq->wait_list_head, wait_list_node) { + if ((pend->cq_kernel_addr && *(pend->cq_kernel_addr) >= pend->cq_target_value) || !pend->cq_kernel_addr) { - pend->fence.timestamp = now; - complete_all(&pend->fence.completion); + if (pend->ts_reg_info.ts_buff) { + if (!reg_node_handle_fail) { + rc = handle_registration_node(hdev, pend, + &ts_reg_free_list_head); + if (rc) + reg_node_handle_fail = true; + } + } else { + /* Handle wait target value node */ + pend->fence.timestamp = now; + complete_all(&pend->fence.completion); + } } } spin_unlock(&user_cq->wait_list_lock); + + if (ts_reg_free_list_head) { + INIT_WORK(&job->free_obj, hl_ts_free_objects); + job->free_obj_head = ts_reg_free_list_head; + job->hdev = hdev; + queue_work(hdev->ts_free_obj_wq, &job->free_obj); + } else { + kfree(job); + } } /** diff --git a/drivers/misc/habanalabs/common/memory.c b/drivers/misc/habanalabs/common/memory.c index f60a9638d9ea..c0904081f37e 100644 --- a/drivers/misc/habanalabs/common/memory.c +++ b/drivers/misc/habanalabs/common/memory.c @@ -20,6 +20,9 @@ MODULE_IMPORT_NS(DMA_BUF); /* use small pages for supporting non-pow2 (32M/40M/48M) DRAM phys page sizes */ #define DRAM_POOL_PAGE_SIZE SZ_8M +static int allocate_timestamps_buffers(struct hl_fpriv *hpriv, + struct hl_mem_in *args, u64 *handle); + /* * The va ranges in context object contain a list with the available chunks of * device virtual memory. @@ -2021,6 +2024,9 @@ static int mem_ioctl_no_mmu(struct hl_fpriv *hpriv, union hl_mem_args *args) rc = -EPERM; break; + case HL_MEM_OP_TS_ALLOC: + rc = allocate_timestamps_buffers(hpriv, &args->in, &args->out.handle); + break; default: dev_err(hdev->dev, "Unknown opcode for memory IOCTL\n"); rc = -EINVAL; @@ -2031,6 +2037,258 @@ out: return rc; } +static void ts_buff_release(struct kref *ref) +{ + struct hl_ts_buff *buff; + + buff = container_of(ref, struct hl_ts_buff, refcount); + + vfree(buff->kernel_buff_address); + vfree(buff->user_buff_address); + kfree(buff); +} + +struct hl_ts_buff *hl_ts_get(struct hl_device *hdev, struct hl_ts_mgr *mgr, + u32 handle) +{ + struct hl_ts_buff *buff; + + spin_lock(&mgr->ts_lock); + buff = idr_find(&mgr->ts_handles, handle); + if (!buff) { + spin_unlock(&mgr->ts_lock); + dev_warn(hdev->dev, + "TS buff get failed, no match to handle 0x%x\n", handle); + return NULL; + } + kref_get(&buff->refcount); + spin_unlock(&mgr->ts_lock); + + return buff; +} + +void hl_ts_put(struct hl_ts_buff *buff) +{ + kref_put(&buff->refcount, ts_buff_release); +} + +static void buff_vm_close(struct vm_area_struct *vma) +{ + struct hl_ts_buff *buff = (struct hl_ts_buff *) vma->vm_private_data; + long new_mmap_size; + + new_mmap_size = buff->mmap_size - (vma->vm_end - vma->vm_start); + + if (new_mmap_size > 0) { + buff->mmap_size = new_mmap_size; + return; + } + + atomic_set(&buff->mmap, 0); + hl_ts_put(buff); + vma->vm_private_data = NULL; +} + +static const struct vm_operations_struct ts_buff_vm_ops = { + .close = buff_vm_close +}; + +int hl_ts_mmap(struct hl_fpriv *hpriv, struct vm_area_struct *vma) +{ + struct hl_device *hdev = hpriv->hdev; + struct hl_ts_buff *buff; + u32 handle, user_buff_size; + int rc; + + /* We use the page offset to hold the idr and thus we need to clear + * it before doing the mmap itself + */ + handle = vma->vm_pgoff; + vma->vm_pgoff = 0; + + buff = hl_ts_get(hdev, &hpriv->ts_mem_mgr, handle); + if (!buff) { + dev_err(hdev->dev, + "TS buff mmap failed, no match to handle 0x%x\n", handle); + return -EINVAL; + } + + /* Validation check */ + user_buff_size = vma->vm_end - vma->vm_start; + if (user_buff_size != ALIGN(buff->user_buff_size, PAGE_SIZE)) { + dev_err(hdev->dev, + "TS buff mmap failed, mmap size 0x%x != 0x%x buff size\n", + user_buff_size, ALIGN(buff->user_buff_size, PAGE_SIZE)); + rc = -EINVAL; + goto put_buff; + } + +#ifdef _HAS_TYPE_ARG_IN_ACCESS_OK + if (!access_ok(VERIFY_WRITE, + (void __user *) (uintptr_t) vma->vm_start, user_buff_size)) { +#else + if (!access_ok((void __user *) (uintptr_t) vma->vm_start, + user_buff_size)) { +#endif + dev_err(hdev->dev, + "user pointer is invalid - 0x%lx\n", + vma->vm_start); + + rc = -EINVAL; + goto put_buff; + } + + if (atomic_cmpxchg(&buff->mmap, 0, 1)) { + dev_err(hdev->dev, "TS buff memory mmap failed, already mmaped to user\n"); + rc = -EINVAL; + goto put_buff; + } + + vma->vm_ops = &ts_buff_vm_ops; + vma->vm_private_data = buff; + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP | VM_DONTCOPY | VM_NORESERVE; + rc = remap_vmalloc_range(vma, buff->user_buff_address, 0); + if (rc) { + atomic_set(&buff->mmap, 0); + goto put_buff; + } + + buff->mmap_size = buff->user_buff_size; + vma->vm_pgoff = handle; + + return 0; + +put_buff: + hl_ts_put(buff); + return rc; +} + +void hl_ts_mgr_init(struct hl_ts_mgr *mgr) +{ + spin_lock_init(&mgr->ts_lock); + idr_init(&mgr->ts_handles); +} + +void hl_ts_mgr_fini(struct hl_device *hdev, struct hl_ts_mgr *mgr) +{ + struct hl_ts_buff *buff; + struct idr *idp; + u32 id; + + idp = &mgr->ts_handles; + + idr_for_each_entry(idp, buff, id) { + if (kref_put(&buff->refcount, ts_buff_release) != 1) + dev_err(hdev->dev, "TS buff handle %d for CTX is still alive\n", + id); + } + + idr_destroy(&mgr->ts_handles); +} + +static struct hl_ts_buff *hl_ts_alloc_buff(struct hl_device *hdev, u32 num_elements) +{ + struct hl_ts_buff *ts_buff = NULL; + u32 size; + void *p; + + ts_buff = kzalloc(sizeof(*ts_buff), GFP_KERNEL); + if (!ts_buff) + return NULL; + + /* Allocate the user buffer */ + size = num_elements * sizeof(u64); + p = vmalloc_user(size); + if (!p) + goto free_mem; + + ts_buff->user_buff_address = p; + ts_buff->user_buff_size = size; + + /* Allocate the internal kernel buffer */ + size = num_elements * sizeof(struct hl_user_pending_interrupt); + p = vmalloc(size); + if (!p) + goto free_user_buff; + + ts_buff->kernel_buff_address = p; + ts_buff->kernel_buff_size = size; + + return ts_buff; + +free_user_buff: + vfree(ts_buff->user_buff_address); +free_mem: + kfree(ts_buff); + return NULL; +} + +/** + * allocate_timestamps_buffers() - allocate timestamps buffers + * This function will allocate ts buffer that will later on be mapped to the user + * in order to be able to read the timestamp. + * in additon it'll allocate an extra buffer for registration management. + * since we cannot fail during registration for out-of-memory situation, so + * we'll prepare a pool which will be used as user interrupt nodes and instead + * of dynamically allocating nodes while registration we'll pick the node from + * this pool. in addtion it'll add node to the mapping hash which will be used + * to map user ts buffer to the internal kernel ts buffer. + * @hpriv: pointer to the private data of the fd + * @args: ioctl input + * @handle: user timestamp buffer handle as an output + */ +static int allocate_timestamps_buffers(struct hl_fpriv *hpriv, struct hl_mem_in *args, u64 *handle) +{ + struct hl_ts_mgr *ts_mgr = &hpriv->ts_mem_mgr; + struct hl_device *hdev = hpriv->hdev; + struct hl_ts_buff *ts_buff; + int rc = 0; + + if (args->num_of_elements > TS_MAX_ELEMENTS_NUM) { + dev_err(hdev->dev, "Num of elements exceeds Max allowed number (0x%x > 0x%x)\n", + args->num_of_elements, TS_MAX_ELEMENTS_NUM); + return -EINVAL; + } + + /* Allocate ts buffer object + * This object will contain two buffers one that will be mapped to the user + * and another internal buffer for the driver use only, which won't be mapped + * to the user. + */ + ts_buff = hl_ts_alloc_buff(hdev, args->num_of_elements); + if (!ts_buff) { + rc = -ENOMEM; + goto out_err; + } + + spin_lock(&ts_mgr->ts_lock); + rc = idr_alloc(&ts_mgr->ts_handles, ts_buff, 1, 0, GFP_ATOMIC); + spin_unlock(&ts_mgr->ts_lock); + if (rc < 0) { + dev_err(hdev->dev, "Failed to allocate IDR for a new ts buffer\n"); + goto release_ts_buff; + } + + ts_buff->id = rc; + ts_buff->hdev = hdev; + + kref_init(&ts_buff->refcount); + + /* idr is 32-bit so we can safely OR it with a mask that is above 32 bit */ + *handle = (u64) ts_buff->id | HL_MMAP_TYPE_TS_BUFF; + *handle <<= PAGE_SHIFT; + + dev_dbg(hdev->dev, "Created ts buff object handle(%u)\n", ts_buff->id); + + return 0; + +release_ts_buff: + kref_put(&ts_buff->refcount, ts_buff_release); +out_err: + *handle = 0; + return rc; +} + int hl_mem_ioctl(struct hl_fpriv *hpriv, void *data) { enum hl_device_status status; @@ -2146,6 +2404,9 @@ int hl_mem_ioctl(struct hl_fpriv *hpriv, void *data) args->out.fd = dmabuf_fd; break; + case HL_MEM_OP_TS_ALLOC: + rc = allocate_timestamps_buffers(hpriv, &args->in, &args->out.handle); + break; default: dev_err(hdev->dev, "Unknown opcode for memory IOCTL\n"); rc = -EINVAL; diff --git a/include/uapi/misc/habanalabs.h b/include/uapi/misc/habanalabs.h index 12976f7a8d84..e21db03196ae 100644 --- a/include/uapi/misc/habanalabs.h +++ b/include/uapi/misc/habanalabs.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note * - * Copyright 2016-2020 HabanaLabs, Ltd. + * Copyright 2016-2021 HabanaLabs, Ltd. * All Rights Reserved. * */ @@ -30,6 +30,9 @@ */ #define GAUDI_FIRST_AVAILABLE_W_S_MONITOR 72 +/* Max number of elements in timestamps registration buffers */ +#define TS_MAX_ELEMENTS_NUM (1 << 20) /* 1MB */ + /* * Goya queue Numbering * @@ -695,10 +698,12 @@ struct hl_cb_in { __u64 cb_handle; /* HL_CB_OP_* */ __u32 op; + /* Size of CB. Maximum size is HL_MAX_CB_SIZE. The minimum size that * will be allocated, regardless of this parameter's value, is PAGE_SIZE */ __u32 cb_size; + /* Context ID - Currently not in use */ __u32 ctx_id; /* HL_CB_FLAGS_* */ @@ -964,6 +969,7 @@ union hl_cs_args { #define HL_WAIT_CS_FLAGS_INTERRUPT_MASK 0xFFF00000 #define HL_WAIT_CS_FLAGS_MULTI_CS 0x4 #define HL_WAIT_CS_FLAGS_INTERRUPT_KERNEL_CQ 0x10 +#define HL_WAIT_CS_FLAGS_REGISTER_INTERRUPT 0x20 #define HL_WAIT_MULTI_CS_LIST_MAX_LEN 32 @@ -1036,6 +1042,20 @@ struct hl_wait_cs_in { * relevant only when HL_WAIT_CS_FLAGS_INTERRUPT_KERNEL_CQ is set */ __u64 cq_counters_offset; + + /* + * Timestamp_handle timestamps buffer handle. + * relevant only when HL_WAIT_CS_FLAGS_REGISTER_INTERRUPT is set + */ + __u64 timestamp_handle; + + /* + * Timestamp_offset is offset inside the timestamp buffer pointed by timestamp_handle above. + * upon interrupt, if the cq reached the target value then driver will write + * timestamp to this offset. + * relevant only when HL_WAIT_CS_FLAGS_REGISTER_INTERRUPT is set + */ + __u64 timestamp_offset; }; #define HL_WAIT_CS_STATUS_COMPLETED 0 @@ -1082,6 +1102,14 @@ union hl_wait_cs_args { */ #define HL_MEM_OP_EXPORT_DMABUF_FD 5 +/* Opcode to create timestamps pool for user interrupts registration support + * The memory will be allocated by the kernel driver, A timestamp buffer which the user + * will get handle to it for mmap, and another internal buffer used by the + * driver for registration management + * The memory will be freed when the user closes the file descriptor(ctx close) + */ +#define HL_MEM_OP_TS_ALLOC 6 + /* Memory flags */ #define HL_MEM_CONTIGUOUS 0x1 #define HL_MEM_SHARED 0x2 @@ -1173,9 +1201,14 @@ struct hl_mem_in { * DMA-BUF file/FD flags. */ __u32 flags; + /* Context ID - Currently not in use */ __u32 ctx_id; - __u32 pad; + + /* number of timestamp elements + * used only when HL_MEM_OP_TS_ALLOC opcode + */ + __u32 num_of_elements; }; struct hl_mem_out { -- cgit v1.3.1 From 960be39db6fe421c49e603bbd541ff2e397f280e Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Fri, 28 Jan 2022 10:11:39 +0200 Subject: habanalabs: fix spelling mistake The name of the property is hints_range_reservation Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/memory.c b/drivers/misc/habanalabs/common/memory.c index c0904081f37e..4778f23d8098 100644 --- a/drivers/misc/habanalabs/common/memory.c +++ b/drivers/misc/habanalabs/common/memory.c @@ -655,7 +655,7 @@ static u64 get_va_block(struct hl_device *hdev, continue; /* - * In case hint address is 0, and arc_hints_range_reservation + * In case hint address is 0, and hints_range_reservation * property enabled, then avoid allocating va blocks from the * range reserved for hint addresses */ -- cgit v1.3.1 From 2a835946ee49462fc18eb6db9b53be789acaf2e5 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Sun, 30 Jan 2022 10:08:52 +0200 Subject: habanalabs: rephrase error messages in PCI initialization The iATU is an internal h/w machine inside Habana's PCI controller. Mentioning it by name doesn't say anything to the user. It is better to say the PCI controller initialization was not done successfully. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/pci/pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/pci/pci.c b/drivers/misc/habanalabs/common/pci/pci.c index a6ffa342070c..bb9ce22bafc4 100644 --- a/drivers/misc/habanalabs/common/pci/pci.c +++ b/drivers/misc/habanalabs/common/pci/pci.c @@ -408,13 +408,13 @@ int hl_pci_init(struct hl_device *hdev) rc = hdev->asic_funcs->pci_bars_map(hdev); if (rc) { - dev_err(hdev->dev, "Failed to initialize PCI BARs\n"); + dev_err(hdev->dev, "Failed to map PCI BAR addresses\n"); goto disable_device; } rc = hdev->asic_funcs->init_iatu(hdev); if (rc) { - dev_err(hdev->dev, "Failed to initialize iATU\n"); + dev_err(hdev->dev, "PCI controller was not initialized successfully\n"); goto unmap_pci_bars; } -- cgit v1.3.1 From 57b6f02fff3e2a8c394bbde6724950d492160356 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Sun, 30 Jan 2022 17:39:54 +0200 Subject: habanalabs: fix use-after-free bug When the code iterates over the free list of physical pages nodes, it deletes the physical page node which is used as the iterator. Therefore, we need to use the safe version of the iteration to prevent use-after-free. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/memory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/memory.c b/drivers/misc/habanalabs/common/memory.c index 4778f23d8098..348daac621ee 100644 --- a/drivers/misc/habanalabs/common/memory.c +++ b/drivers/misc/habanalabs/common/memory.c @@ -2860,7 +2860,7 @@ int hl_vm_ctx_init(struct hl_ctx *ctx) */ void hl_vm_ctx_fini(struct hl_ctx *ctx) { - struct hl_vm_phys_pg_pack *phys_pg_list; + struct hl_vm_phys_pg_pack *phys_pg_list, *tmp_phys_node; struct hl_device *hdev = ctx->hdev; struct hl_vm_hash_node *hnode; struct hl_vm *vm = &hdev->vm; @@ -2913,7 +2913,7 @@ void hl_vm_ctx_fini(struct hl_ctx *ctx) } spin_unlock(&vm->idr_lock); - list_for_each_entry(phys_pg_list, &free_list, node) + list_for_each_entry_safe(phys_pg_list, tmp_phys_node, &free_list, node) free_phys_pg_pack(hdev, phys_pg_list); va_range_fini(hdev, ctx->va_range[HL_VA_RANGE_TYPE_DRAM]); -- cgit v1.3.1 From 9e70ac1aa7ba50f223b4784c9e19d9ee3e47e634 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Wed, 2 Feb 2022 10:36:29 +0200 Subject: habanalabs: add missing include of vmalloc.h Use of vfree(), vmalloc_user(), vmalloc() and remap_vmalloc_range() requires this include in some architectures. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/memory.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/memory.c b/drivers/misc/habanalabs/common/memory.c index 348daac621ee..7bd4cae87a54 100644 --- a/drivers/misc/habanalabs/common/memory.c +++ b/drivers/misc/habanalabs/common/memory.c @@ -11,6 +11,7 @@ #include #include +#include #include MODULE_IMPORT_NS(DMA_BUF); -- cgit v1.3.1 From 4a0b01fa63c9dc4f0dd3ad44168c9323e4da5172 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Wed, 2 Feb 2022 10:32:53 +0200 Subject: habanalabs: change function to static handle_registration_node() is called directly from the irq handler in irq.c, so it can be static. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/irq.c b/drivers/misc/habanalabs/common/irq.c index c28f3a1c7a03..e2bc128f2291 100644 --- a/drivers/misc/habanalabs/common/irq.c +++ b/drivers/misc/habanalabs/common/irq.c @@ -175,7 +175,7 @@ static void hl_ts_free_objects(struct work_struct *work) * so here we'll be filling a list with nodes of "put" jobs and then will send this * list to a dedicated workqueue to do the actual put. */ -int handle_registration_node(struct hl_device *hdev, struct hl_user_pending_interrupt *pend, +static int handle_registration_node(struct hl_device *hdev, struct hl_user_pending_interrupt *pend, struct list_head **free_list) { struct timestamp_reg_free_node *free_node; -- cgit v1.3.1 From d01e6cc97b44d8501b5c24a36d60c9cab94640cd Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Wed, 12 Jan 2022 20:08:01 +0200 Subject: habanalabs: enable stop-on-error debugfs setting per ASIC On Goya and Gaudi, the stop-on-error configuration can be set via debugfs. However, in future devices, this configuration will always be enabled. Modify the debugfs node to be allowed only for ASICs that support this dynamic configuration. Signed-off-by: Tomer Tayar Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- Documentation/ABI/testing/debugfs-driver-habanalabs | 1 + drivers/misc/habanalabs/common/debugfs.c | 6 ++++++ drivers/misc/habanalabs/common/habanalabs.h | 2 ++ drivers/misc/habanalabs/gaudi/gaudi.c | 2 ++ drivers/misc/habanalabs/goya/goya.c | 2 ++ 5 files changed, 13 insertions(+) (limited to 'drivers/misc') diff --git a/Documentation/ABI/testing/debugfs-driver-habanalabs b/Documentation/ABI/testing/debugfs-driver-habanalabs index 783001a574b3..bcf6915987e4 100644 --- a/Documentation/ABI/testing/debugfs-driver-habanalabs +++ b/Documentation/ABI/testing/debugfs-driver-habanalabs @@ -222,6 +222,7 @@ KernelVersion: 5.6 Contact: ogabbay@kernel.org Description: Sets the stop-on_error option for the device engines. Value of "0" is for disable, otherwise enable. + Relevant only for GOYA and GAUDI. What: /sys/kernel/debug/habanalabs/hl/timeout_locked Date: Sep 2021 diff --git a/drivers/misc/habanalabs/common/debugfs.c b/drivers/misc/habanalabs/common/debugfs.c index e3ee5f45d20c..9f0aaf0ef43b 100644 --- a/drivers/misc/habanalabs/common/debugfs.c +++ b/drivers/misc/habanalabs/common/debugfs.c @@ -1071,6 +1071,9 @@ static ssize_t hl_stop_on_err_read(struct file *f, char __user *buf, char tmp_buf[200]; ssize_t rc; + if (!hdev->asic_prop.configurable_stop_on_err) + return -EOPNOTSUPP; + if (*ppos) return 0; @@ -1089,6 +1092,9 @@ static ssize_t hl_stop_on_err_write(struct file *f, const char __user *buf, u32 value; ssize_t rc; + if (!hdev->asic_prop.configurable_stop_on_err) + return -EOPNOTSUPP; + if (hdev->reset_info.in_reset) { dev_warn_ratelimited(hdev->dev, "Can't change stop on error during reset\n"); diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index b06e2b0812b6..93116fe71ef6 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -561,6 +561,7 @@ struct hl_hints_range { * use-case of doing soft-reset in training (due * to the fact that training runs on multiple * devices) + * @configurable_stop_on_err: is stop-on-error option configurable via debugfs. */ struct asic_fixed_properties { struct hw_queue_properties *hw_queues_props; @@ -644,6 +645,7 @@ struct asic_fixed_properties { u8 use_get_power_for_reset_history; u8 supports_soft_reset; u8 allow_inference_soft_reset; + u8 configurable_stop_on_err; }; /** diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index f2242aa3baa2..61aa6dce6dde 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -669,6 +669,8 @@ static int gaudi_set_fixed_properties(struct hl_device *hdev) prop->use_get_power_for_reset_history = true; + prop->configurable_stop_on_err = true; + return 0; } diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index 3785fb33260d..c8143b6616af 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -483,6 +483,8 @@ int goya_set_fixed_properties(struct hl_device *hdev) prop->use_get_power_for_reset_history = true; + prop->configurable_stop_on_err = true; + return 0; } -- cgit v1.3.1 From 35629bc171b642d5f0bbb59345471d20ecff5ff7 Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Tue, 18 Jan 2022 00:21:49 +0200 Subject: habanalabs: use proper max_power variable for device utilization The max_power variable which is used for calculating the device utilization is the ASIC specific property which is set during init. However, the max value can be modified via sysfs, and thus the updated value in the device structure should be used instead. Signed-off-by: Tomer Tayar Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index 60bfd737404b..63e2449ad136 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -614,7 +614,7 @@ int hl_device_utilization(struct hl_device *hdev, u32 *utilization) u64 max_power, curr_power, dc_power, dividend; int rc; - max_power = hdev->asic_prop.max_power_default; + max_power = hdev->max_power; dc_power = hdev->asic_prop.dc_power_default; rc = hl_fw_cpucp_power_get(hdev, &curr_power); -- cgit v1.3.1 From 2908826d09f829528cb507ce547967beccf4388d Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Tue, 18 Jan 2022 19:27:14 +0200 Subject: habanalabs: set max power on device init per ASIC For current devices there is a need to send the max power value to F/W during device init, for example because there might be several card types. In future devices, this info will be programmed in the device's EEPROM and will be read by F/W, and hence the driver should not send it. Modify the sending of the relevant message to be done only for ASIC types that need it. Signed-off-by: Tomer Tayar Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/device.c | 3 ++- drivers/misc/habanalabs/common/habanalabs.h | 2 ++ drivers/misc/habanalabs/gaudi/gaudi.c | 2 ++ drivers/misc/habanalabs/goya/goya.c | 2 ++ 4 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index 63e2449ad136..8ea9dfe3f79b 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -1541,7 +1541,8 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass) /* Need to call this again because the max power might change, * depending on card type for certain ASICs */ - hl_fw_set_max_power(hdev); + if (hdev->asic_prop.set_max_power_on_device_init) + hl_fw_set_max_power(hdev); /* * hl_hwmon_init() must be called after device_late_init(), because only diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 93116fe71ef6..b5055ab528b8 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -562,6 +562,7 @@ struct hl_hints_range { * to the fact that training runs on multiple * devices) * @configurable_stop_on_err: is stop-on-error option configurable via debugfs. + * @set_max_power_on_device_init: true if need to set max power in F/W on device init. */ struct asic_fixed_properties { struct hw_queue_properties *hw_queues_props; @@ -646,6 +647,7 @@ struct asic_fixed_properties { u8 supports_soft_reset; u8 allow_inference_soft_reset; u8 configurable_stop_on_err; + u8 set_max_power_on_device_init; }; /** diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 61aa6dce6dde..ad640a268a3c 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -671,6 +671,8 @@ static int gaudi_set_fixed_properties(struct hl_device *hdev) prop->configurable_stop_on_err = true; + prop->set_max_power_on_device_init = true; + return 0; } diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index c8143b6616af..c08d96e43c9f 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -485,6 +485,8 @@ int goya_set_fixed_properties(struct hl_device *hdev) prop->configurable_stop_on_err = true; + prop->set_max_power_on_device_init = true; + return 0; } -- cgit v1.3.1 From 59456f4c2250e1fb15b1a82bfe2ef1aaf217fa1b Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Thu, 10 Feb 2022 10:56:02 +0200 Subject: habanalabs: avoid using an uninitialized variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following compilation warning in hl_cb_ioctl() @ command_buffer.c: warning: ‘device_va’ may be used uninitialized in this function Signed-off-by: Tomer Tayar Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/command_buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/command_buffer.c b/drivers/misc/habanalabs/common/command_buffer.c index b9483a3cee91..a507110f6443 100644 --- a/drivers/misc/habanalabs/common/command_buffer.c +++ b/drivers/misc/habanalabs/common/command_buffer.c @@ -424,8 +424,8 @@ int hl_cb_ioctl(struct hl_fpriv *hpriv, void *data) { union hl_cb_args *args = data; struct hl_device *hdev = hpriv->hdev; + u64 handle = 0, device_va = 0; enum hl_device_status status; - u64 handle = 0, device_va; u32 usage_cnt = 0; int rc; -- cgit v1.3.1 From f23f280277d5a701de99c6652623b6bf8801c534 Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Mon, 14 Feb 2022 15:22:00 +0200 Subject: habanalabs: allow user to set allocation page size In future ASICs the MMU will be able to work with multiple page sizes, thus a new flag is added to allow the user to set the requested page size. This flag is added since the whole DRAM is allocated for the user and the user also should be familiar with the memory usage use case. As such, the user may choose to "over allocate" memory in favor of performance (for instance- large page allocations covers more memory in less TLB entries). For example: say available page sizes are of 1MB and 32MB. If user wants to allocate 40MB the user can either set page size to 1MB and allocate the exact amount of memory (but will result in 40 TLB entries) or the user can use 32MB pages, "waste" 8MB of physical memory but occupy only 2 TLB entries. Note that this feature will be available only to ASIC that supports multiple DRAM page sizes. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/habanalabs.h | 5 +++++ drivers/misc/habanalabs/common/memory.c | 31 ++++++++++++++++++++++++++++- drivers/misc/habanalabs/gaudi/gaudi.c | 3 ++- drivers/misc/habanalabs/goya/goya.c | 1 + include/uapi/misc/habanalabs.h | 5 ++++- 5 files changed, 42 insertions(+), 3 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index b5055ab528b8..677ae4ff922c 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -563,6 +563,7 @@ struct hl_hints_range { * devices) * @configurable_stop_on_err: is stop-on-error option configurable via debugfs. * @set_max_power_on_device_init: true if need to set max power in F/W on device init. + * @supports_user_set_page_size: true if user can set the allocation page size. */ struct asic_fixed_properties { struct hw_queue_properties *hw_queues_props; @@ -648,6 +649,7 @@ struct asic_fixed_properties { u8 allow_inference_soft_reset; u8 configurable_stop_on_err; u8 set_max_power_on_device_init; + u8 supports_user_set_page_size; }; /** @@ -1311,6 +1313,8 @@ struct fw_load_mgr { * @get_sob_addr: get SOB base address offset. * @set_pci_memory_regions: setting properties of PCI memory regions * @get_stream_master_qid_arr: get pointer to stream masters QID array + * @is_valid_dram_page_size: return true if page size is supported in device + * memory allocation, otherwise false. */ struct hl_asic_funcs { int (*early_init)(struct hl_device *hdev); @@ -1436,6 +1440,7 @@ struct hl_asic_funcs { u32 (*get_sob_addr)(struct hl_device *hdev, u32 sob_id); void (*set_pci_memory_regions)(struct hl_device *hdev); u32* (*get_stream_master_qid_arr)(void); + bool (*is_valid_dram_page_size)(u32 page_size); }; diff --git a/drivers/misc/habanalabs/common/memory.c b/drivers/misc/habanalabs/common/memory.c index 7bd4cae87a54..385bf3448c73 100644 --- a/drivers/misc/habanalabs/common/memory.c +++ b/drivers/misc/habanalabs/common/memory.c @@ -24,6 +24,31 @@ MODULE_IMPORT_NS(DMA_BUF); static int allocate_timestamps_buffers(struct hl_fpriv *hpriv, struct hl_mem_in *args, u64 *handle); +static int set_alloc_page_size(struct hl_device *hdev, struct hl_mem_in *args, u32 *page_size) +{ + struct asic_fixed_properties *prop = &hdev->asic_prop; + u32 psize; + + /* + * for ASIC that supports setting the allocation page size by user we will address + * user's choice only if it is not 0 (as 0 means taking the default page size) + */ + if (prop->supports_user_set_page_size && args->alloc.page_size) { + psize = args->alloc.page_size; + + if (!hdev->asic_funcs->is_valid_dram_page_size(psize)) { + dev_err(hdev->dev, "user page size (%#x) is not valid\n", psize); + return -EINVAL; + } + } else { + psize = hdev->asic_prop.dram_page_size; + } + + *page_size = psize; + + return 0; +} + /* * The va ranges in context object contain a list with the available chunks of * device virtual memory. @@ -69,7 +94,11 @@ static int alloc_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args, bool contiguous; num_curr_pgs = 0; - page_size = hdev->asic_prop.dram_page_size; + + rc = set_alloc_page_size(hdev, args, &page_size); + if (rc) + return rc; + num_pgs = DIV_ROUND_UP_ULL(args->alloc.mem_size, page_size); total_size = num_pgs * page_size; diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index ad640a268a3c..a60c0e23d23c 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -9432,7 +9432,8 @@ static const struct hl_asic_funcs gaudi_funcs = { .state_dump_init = gaudi_state_dump_init, .get_sob_addr = gaudi_get_sob_addr, .set_pci_memory_regions = gaudi_set_pci_memory_regions, - .get_stream_master_qid_arr = gaudi_get_stream_master_qid_arr + .get_stream_master_qid_arr = gaudi_get_stream_master_qid_arr, + .is_valid_dram_page_size = NULL }; /** diff --git a/drivers/misc/habanalabs/goya/goya.c b/drivers/misc/habanalabs/goya/goya.c index c08d96e43c9f..ec9358bcbf0b 100644 --- a/drivers/misc/habanalabs/goya/goya.c +++ b/drivers/misc/habanalabs/goya/goya.c @@ -5764,6 +5764,7 @@ static const struct hl_asic_funcs goya_funcs = { .get_sob_addr = &goya_get_sob_addr, .set_pci_memory_regions = goya_set_pci_memory_regions, .get_stream_master_qid_arr = goya_get_stream_master_qid_arr, + .is_valid_dram_page_size = NULL }; /* diff --git a/include/uapi/misc/habanalabs.h b/include/uapi/misc/habanalabs.h index a2a953a91b5e..1d6b4f0c4159 100644 --- a/include/uapi/misc/habanalabs.h +++ b/include/uapi/misc/habanalabs.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note * - * Copyright 2016-2021 HabanaLabs, Ltd. + * Copyright 2016-2022 HabanaLabs, Ltd. * All Rights Reserved. * */ @@ -1130,9 +1130,12 @@ struct hl_mem_in { /** * structure for device memory allocation (used with the HL_MEM_OP_ALLOC op) * @mem_size: memory size to allocate + * @page_size: page size to use on allocation. when the value is 0 the default page + * size will be taken. */ struct { __u64 mem_size; + __u64 page_size; } alloc; /** -- cgit v1.3.1 From 26ef1c000bc21a192618c9ec651dd36ba63ca00c Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Thu, 17 Feb 2022 16:07:03 +0200 Subject: habanalabs/gaudi: handle axi errors from NIC engines Various AXI errors can occur in the NIC engines and are reported to the driver by the f/w. Add code to print the errors and ack them to the f/w. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 48 +++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index a60c0e23d23c..95201d995743 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -7665,6 +7665,48 @@ static void gaudi_print_fw_alive_info(struct hl_device *hdev, fw_alive->thread_id, fw_alive->uptime_seconds); } +static void gaudi_print_nic_axi_irq_info(struct hl_device *hdev, u16 event_type, + void *data) +{ + char desc[64] = "", *type; + struct eq_nic_sei_event *eq_nic_sei = data; + u16 nic_id = event_type - GAUDI_EVENT_NIC_SEI_0; + + switch (eq_nic_sei->axi_error_cause) { + case RXB: + type = "RXB"; + break; + case RXE: + type = "RXE"; + break; + case TXS: + type = "TXS"; + break; + case TXE: + type = "TXE"; + break; + case QPC_RESP: + type = "QPC_RESP"; + break; + case NON_AXI_ERR: + type = "NON_AXI_ERR"; + break; + case TMR: + type = "TMR"; + break; + default: + dev_err(hdev->dev, "unknown NIC AXI cause %d\n", + eq_nic_sei->axi_error_cause); + type = "N/A"; + break; + } + + snprintf(desc, sizeof(desc), "NIC%d_%s%d", nic_id, type, + eq_nic_sei->id); + dev_err_ratelimited(hdev->dev, "Received H/W interrupt %d [\"%s\"]\n", + event_type, desc); +} + static int gaudi_non_hard_reset_late_init(struct hl_device *hdev) { /* GAUDI doesn't support any reset except hard-reset */ @@ -7898,6 +7940,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, struct hl_eq_entry *eq_entry) { struct gaudi_device *gaudi = hdev->asic_specific; + u64 data = le64_to_cpu(eq_entry->data[0]); u32 ctl = le32_to_cpu(eq_entry->hdr.ctl); u32 fw_fatal_err_flag = 0; u16 event_type = ((ctl & EQ_CTL_EVENT_TYPE_MASK) @@ -8095,6 +8138,11 @@ static void gaudi_handle_eqe(struct hl_device *hdev, hl_fw_unmask_irq(hdev, event_type); break; + case GAUDI_EVENT_NIC_SEI_0 ... GAUDI_EVENT_NIC_SEI_4: + gaudi_print_nic_axi_irq_info(hdev, event_type, &data); + hl_fw_unmask_irq(hdev, event_type); + break; + case GAUDI_EVENT_DMA_IF_SEI_0 ... GAUDI_EVENT_DMA_IF_SEI_3: gaudi_print_irq_info(hdev, event_type, false); gaudi_print_sm_sei_info(hdev, event_type, -- cgit v1.3.1 From 100fcf1e111de3e8433777f305b042267c5ad79f Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Thu, 17 Feb 2022 16:08:09 +0200 Subject: habanalabs/gaudi: add missing handling of NIC related events There are a few events that can arrive from the f/w and without proper handling can cause errors to appear in the kernel log without reason. Add the relevant handling that was missing. Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/gaudi/gaudi.c | 5 +++++ drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h | 10 ++++++++++ 2 files changed, 15 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 95201d995743..0eed0efae040 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -7977,6 +7977,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, case GAUDI_EVENT_PSOC_MEM_DERR: case GAUDI_EVENT_PSOC_CORESIGHT_DERR: case GAUDI_EVENT_SRAM0_DERR ... GAUDI_EVENT_SRAM28_DERR: + case GAUDI_EVENT_NIC0_DERR ... GAUDI_EVENT_NIC4_DERR: case GAUDI_EVENT_DMA_IF0_DERR ... GAUDI_EVENT_DMA_IF3_DERR: case GAUDI_EVENT_HBM_0_DERR ... GAUDI_EVENT_HBM_3_DERR: case GAUDI_EVENT_MMU_DERR: @@ -8077,6 +8078,7 @@ static void gaudi_handle_eqe(struct hl_device *hdev, case GAUDI_EVENT_PSOC_MEM_SERR: case GAUDI_EVENT_PSOC_CORESIGHT_SERR: case GAUDI_EVENT_SRAM0_SERR ... GAUDI_EVENT_SRAM28_SERR: + case GAUDI_EVENT_NIC0_SERR ... GAUDI_EVENT_NIC4_SERR: case GAUDI_EVENT_DMA_IF0_SERR ... GAUDI_EVENT_DMA_IF3_SERR: case GAUDI_EVENT_HBM_0_SERR ... GAUDI_EVENT_HBM_3_SERR: fallthrough; @@ -8154,6 +8156,9 @@ static void gaudi_handle_eqe(struct hl_device *hdev, hl_fw_unmask_irq(hdev, event_type); break; + case GAUDI_EVENT_STATUS_NIC0_ENG0 ... GAUDI_EVENT_STATUS_NIC4_ENG1: + break; + case GAUDI_EVENT_FIX_POWER_ENV_S ... GAUDI_EVENT_FIX_THERMAL_ENV_E: gaudi_print_clk_change_info(hdev, event_type); hl_fw_unmask_irq(hdev, event_type); diff --git a/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h b/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h index d966bd4dfea6..c07ed4ed304c 100644 --- a/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h +++ b/drivers/misc/habanalabs/include/gaudi/gaudi_async_events.h @@ -311,6 +311,16 @@ enum gaudi_async_event_id { GAUDI_EVENT_FW_ALIVE_S = 645, GAUDI_EVENT_DEV_RESET_REQ = 646, GAUDI_EVENT_PKT_QUEUE_OUT_SYNC = 647, + GAUDI_EVENT_STATUS_NIC0_ENG0 = 648, + GAUDI_EVENT_STATUS_NIC0_ENG1 = 649, + GAUDI_EVENT_STATUS_NIC1_ENG0 = 650, + GAUDI_EVENT_STATUS_NIC1_ENG1 = 651, + GAUDI_EVENT_STATUS_NIC2_ENG0 = 652, + GAUDI_EVENT_STATUS_NIC2_ENG1 = 653, + GAUDI_EVENT_STATUS_NIC3_ENG0 = 654, + GAUDI_EVENT_STATUS_NIC3_ENG1 = 655, + GAUDI_EVENT_STATUS_NIC4_ENG0 = 656, + GAUDI_EVENT_STATUS_NIC4_ENG1 = 657, GAUDI_EVENT_FIX_POWER_ENV_S = 658, GAUDI_EVENT_FIX_POWER_ENV_E = 659, GAUDI_EVENT_FIX_THERMAL_ENV_S = 660, -- cgit v1.3.1 From e8458e20e0a3c426ed5ed3ce590c05718c8b8e8e Mon Sep 17 00:00:00 2001 From: Ohad Sharabi Date: Sun, 6 Feb 2022 08:50:43 +0200 Subject: habanalabs: make sure device mem alloc is page aligned Working with MMU that supports multiple page sizes requires that mapping of a page of a certain size will be aligned to the same size (e.g. the physical address of 32MB page shall be aligned to 32MB). To achieve this the gen_poll allocation is now using the "align" variant to comply with the alignment requirements. Signed-off-by: Ohad Sharabi Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/memory.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/memory.c b/drivers/misc/habanalabs/common/memory.c index 385bf3448c73..e008d82e4ba3 100644 --- a/drivers/misc/habanalabs/common/memory.c +++ b/drivers/misc/habanalabs/common/memory.c @@ -90,8 +90,8 @@ static int alloc_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args, struct hl_vm_phys_pg_pack *phys_pg_pack; u64 paddr = 0, total_size, num_pgs, i; u32 num_curr_pgs, page_size; - int handle, rc; bool contiguous; + int handle, rc; num_curr_pgs = 0; @@ -110,7 +110,11 @@ static int alloc_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args, contiguous = args->flags & HL_MEM_CONTIGUOUS; if (contiguous) { - paddr = (u64) gen_pool_alloc(vm->dram_pg_pool, total_size); + if (is_power_of_2(page_size)) + paddr = (u64) (uintptr_t) gen_pool_dma_alloc_align(vm->dram_pg_pool, + total_size, NULL, page_size); + else + paddr = (u64) (uintptr_t) gen_pool_alloc(vm->dram_pg_pool, total_size); if (!paddr) { dev_err(hdev->dev, "failed to allocate %llu contiguous pages with total size of %llu\n", @@ -144,9 +148,14 @@ static int alloc_device_memory(struct hl_ctx *ctx, struct hl_mem_in *args, phys_pg_pack->pages[i] = paddr + i * page_size; } else { for (i = 0 ; i < num_pgs ; i++) { - phys_pg_pack->pages[i] = (u64) gen_pool_alloc( - vm->dram_pg_pool, - page_size); + if (is_power_of_2(page_size)) + phys_pg_pack->pages[i] = + (u64) gen_pool_dma_alloc_align(vm->dram_pg_pool, + page_size, NULL, + page_size); + else + phys_pg_pack->pages[i] = (u64) gen_pool_alloc(vm->dram_pg_pool, + page_size); if (!phys_pg_pack->pages[i]) { dev_err(hdev->dev, "Failed to allocate device memory (out of memory)\n"); -- cgit v1.3.1 From a78b07dcae2f9d6fafadb05540d8152f575d7e59 Mon Sep 17 00:00:00 2001 From: farah kassabri Date: Thu, 17 Feb 2022 16:15:26 +0200 Subject: habanalabs: Fix reset upon device release bug In case user application was interrupted while some cs still in-flight or in the middle of completion handling in driver, the last refcount of the kernel private data for the user process will not be put in the fd close flow, but in the cs completion workqueue context. This means that the device reset-upon-device-release will be called from that context. During the reset flow, the driver flushes all the cs workqueue to ensure that any scheduled work has run to completion, and since we are running from the completion context we will have deadlock. Therefore, we need to skip flushing the workqueue in those cases. It is safe to do it because the user won't be able to release the device unless the workqueues are already empty. Signed-off-by: farah kassabri Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/command_submission.c | 17 ++++++++++------- drivers/misc/habanalabs/common/device.c | 13 ++++++++----- drivers/misc/habanalabs/common/habanalabs.h | 2 +- 3 files changed, 19 insertions(+), 13 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/command_submission.c b/drivers/misc/habanalabs/common/command_submission.c index c7757c78d0b1..d93ef9f1c45c 100644 --- a/drivers/misc/habanalabs/common/command_submission.c +++ b/drivers/misc/habanalabs/common/command_submission.c @@ -921,18 +921,21 @@ static void cs_rollback(struct hl_device *hdev, struct hl_cs *cs) complete_job(hdev, job); } -void hl_cs_rollback_all(struct hl_device *hdev) +void hl_cs_rollback_all(struct hl_device *hdev, bool skip_wq_flush) { int i; struct hl_cs *cs, *tmp; - flush_workqueue(hdev->ts_free_obj_wq); + if (!skip_wq_flush) { + flush_workqueue(hdev->ts_free_obj_wq); - /* flush all completions before iterating over the CS mirror list in - * order to avoid a race with the release functions - */ - for (i = 0 ; i < hdev->asic_prop.completion_queues_count ; i++) - flush_workqueue(hdev->cq_wq[i]); + /* flush all completions before iterating over the CS mirror list in + * order to avoid a race with the release functions + */ + for (i = 0 ; i < hdev->asic_prop.completion_queues_count ; i++) + flush_workqueue(hdev->cq_wq[i]); + + } /* Make sure we don't have leftovers in the CS mirror list */ list_for_each_entry_safe(cs, tmp, &hdev->cs_mirror_list, mirror_node) { diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index 8ea9dfe3f79b..d52381d1fbd2 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -685,7 +685,8 @@ static void take_release_locks(struct hl_device *hdev) mutex_unlock(&hdev->fpriv_ctrl_list_lock); } -static void cleanup_resources(struct hl_device *hdev, bool hard_reset, bool fw_reset) +static void cleanup_resources(struct hl_device *hdev, bool hard_reset, bool fw_reset, + bool skip_wq_flush) { if (hard_reset) device_late_fini(hdev); @@ -698,7 +699,7 @@ static void cleanup_resources(struct hl_device *hdev, bool hard_reset, bool fw_r hdev->asic_funcs->halt_engines(hdev, hard_reset, fw_reset); /* Go over all the queues, release all CS and their jobs */ - hl_cs_rollback_all(hdev); + hl_cs_rollback_all(hdev, skip_wq_flush); /* Release all pending user interrupts, each pending user interrupt * holds a reference to user context @@ -978,7 +979,8 @@ static void handle_reset_trigger(struct hl_device *hdev, u32 flags) int hl_device_reset(struct hl_device *hdev, u32 flags) { bool hard_reset, from_hard_reset_thread, fw_reset, hard_instead_soft = false, - reset_upon_device_release = false, schedule_hard_reset = false; + reset_upon_device_release = false, schedule_hard_reset = false, + skip_wq_flush = false; u64 idle_mask[HL_BUSY_ENGINES_MASK_EXT_SIZE] = {0}; struct hl_ctx *ctx; int i, rc; @@ -991,6 +993,7 @@ int hl_device_reset(struct hl_device *hdev, u32 flags) hard_reset = !!(flags & HL_DRV_RESET_HARD); from_hard_reset_thread = !!(flags & HL_DRV_RESET_FROM_RESET_THR); fw_reset = !!(flags & HL_DRV_RESET_BYPASS_REQ_TO_FW); + skip_wq_flush = !!(flags & HL_DRV_RESET_DEV_RELEASE); if (!hard_reset && !hdev->asic_prop.supports_soft_reset) { hard_instead_soft = true; @@ -1076,7 +1079,7 @@ again: return 0; } - cleanup_resources(hdev, hard_reset, fw_reset); + cleanup_resources(hdev, hard_reset, fw_reset, skip_wq_flush); kill_processes: if (hard_reset) { @@ -1686,7 +1689,7 @@ void hl_device_fini(struct hl_device *hdev) hl_hwmon_fini(hdev); - cleanup_resources(hdev, true, false); + cleanup_resources(hdev, true, false, false); /* Kill processes here after CS rollback. This is because the process * can't really exit until all its CSs are done, which is what we diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index 677ae4ff922c..cef4717d0916 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -3054,7 +3054,7 @@ int hl_cb_pool_fini(struct hl_device *hdev); int hl_cb_va_pool_init(struct hl_ctx *ctx); void hl_cb_va_pool_fini(struct hl_ctx *ctx); -void hl_cs_rollback_all(struct hl_device *hdev); +void hl_cs_rollback_all(struct hl_device *hdev, bool skip_wq_flush); struct hl_cs_job *hl_cs_allocate_job(struct hl_device *hdev, enum hl_queue_type queue_type, bool is_kernel_allocated_cb); void hl_sob_reset_error(struct kref *ref); -- cgit v1.3.1 From 9c27896ac1bb83ea5c461ce6f7089d02102a2b21 Mon Sep 17 00:00:00 2001 From: Jiasheng Jiang Date: Thu, 24 Feb 2022 14:58:05 +0800 Subject: habanalabs: Add check for pci_enable_device As the potential failure of the pci_enable_device(), it should be better to check the return value and return error if fails. Fixes: 70b2f993ea4a ("habanalabs: create common folder") Signed-off-by: Jiasheng Jiang Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/debugfs.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/debugfs.c b/drivers/misc/habanalabs/common/debugfs.c index 9f0aaf0ef43b..f18495545854 100644 --- a/drivers/misc/habanalabs/common/debugfs.c +++ b/drivers/misc/habanalabs/common/debugfs.c @@ -890,6 +890,8 @@ static ssize_t hl_set_power_state(struct file *f, const char __user *buf, pci_set_power_state(hdev->pdev, PCI_D0); pci_restore_state(hdev->pdev); rc = pci_enable_device(hdev->pdev); + if (rc < 0) + return rc; } else if (value == 2) { pci_save_state(hdev->pdev); pci_disable_device(hdev->pdev); -- cgit v1.3.1 From b0106bc6fe5a99490f2a2407025db6f2b514b6dc Mon Sep 17 00:00:00 2001 From: Tomer Tayar Date: Wed, 23 Feb 2022 14:46:37 +0200 Subject: habanalabs: add an option to delay a device reset Several H/W events can be sent adjacently, even due to a single error. If a hard-reset is triggered as part of handling one of these events, the following events won't be handled. The debug info from these missed events is important, sometimes even more important than the one that was handled. To allow handling these close events, add an option to delay a device reset and use it when resetting due to H/W events. Signed-off-by: Tomer Tayar Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/device.c | 8 +++++++- drivers/misc/habanalabs/common/habanalabs.h | 4 ++++ drivers/misc/habanalabs/gaudi/gaudi.c | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/device.c b/drivers/misc/habanalabs/common/device.c index d52381d1fbd2..dc9341a64541 100644 --- a/drivers/misc/habanalabs/common/device.c +++ b/drivers/misc/habanalabs/common/device.c @@ -13,6 +13,8 @@ #include #include +#define HL_RESET_DELAY_USEC 10000 /* 10ms */ + enum hl_device_status hl_device_status(struct hl_device *hdev) { enum hl_device_status status; @@ -980,7 +982,7 @@ int hl_device_reset(struct hl_device *hdev, u32 flags) { bool hard_reset, from_hard_reset_thread, fw_reset, hard_instead_soft = false, reset_upon_device_release = false, schedule_hard_reset = false, - skip_wq_flush = false; + skip_wq_flush, delay_reset; u64 idle_mask[HL_BUSY_ENGINES_MASK_EXT_SIZE] = {0}; struct hl_ctx *ctx; int i, rc; @@ -994,6 +996,7 @@ int hl_device_reset(struct hl_device *hdev, u32 flags) from_hard_reset_thread = !!(flags & HL_DRV_RESET_FROM_RESET_THR); fw_reset = !!(flags & HL_DRV_RESET_BYPASS_REQ_TO_FW); skip_wq_flush = !!(flags & HL_DRV_RESET_DEV_RELEASE); + delay_reset = !!(flags & HL_DRV_RESET_DELAY); if (!hard_reset && !hdev->asic_prop.supports_soft_reset) { hard_instead_soft = true; @@ -1043,6 +1046,9 @@ do_reset: hdev->reset_info.in_reset = 1; spin_unlock(&hdev->reset_info.lock); + if (delay_reset) + usleep_range(HL_RESET_DELAY_USEC, HL_RESET_DELAY_USEC << 1); + handle_reset_trigger(hdev, flags); /* This still allows the completion of some KDMA ops */ diff --git a/drivers/misc/habanalabs/common/habanalabs.h b/drivers/misc/habanalabs/common/habanalabs.h index cef4717d0916..1edaf6ab67bd 100644 --- a/drivers/misc/habanalabs/common/habanalabs.h +++ b/drivers/misc/habanalabs/common/habanalabs.h @@ -142,6 +142,9 @@ enum hl_mmu_page_table_location { * * - HL_DRV_RESET_FW_FATAL_ERR * Set if reset is due to a fatal error from FW + * + * - HL_DRV_RESET_DELAY + * Set if a delay should be added before the reset */ #define HL_DRV_RESET_HARD (1 << 0) @@ -151,6 +154,7 @@ enum hl_mmu_page_table_location { #define HL_DRV_RESET_DEV_RELEASE (1 << 4) #define HL_DRV_RESET_BYPASS_REQ_TO_FW (1 << 5) #define HL_DRV_RESET_FW_FATAL_ERR (1 << 6) +#define HL_DRV_RESET_DELAY (1 << 7) #define HL_MAX_SOBS_PER_MONITOR 8 diff --git a/drivers/misc/habanalabs/gaudi/gaudi.c b/drivers/misc/habanalabs/gaudi/gaudi.c index 0eed0efae040..21c2b678ff72 100644 --- a/drivers/misc/habanalabs/gaudi/gaudi.c +++ b/drivers/misc/habanalabs/gaudi/gaudi.c @@ -8199,7 +8199,7 @@ reset_device: | HL_DRV_RESET_BYPASS_REQ_TO_FW | fw_fatal_err_flag); else if (hdev->hard_reset_on_fw_events) - hl_device_reset(hdev, HL_DRV_RESET_HARD | fw_fatal_err_flag); + hl_device_reset(hdev, HL_DRV_RESET_HARD | HL_DRV_RESET_DELAY | fw_fatal_err_flag); else hl_fw_unmask_irq(hdev, event_type); } -- cgit v1.3.1 From 655221c56739058ae73a7aabd90847a024dabff6 Mon Sep 17 00:00:00 2001 From: Ofir Bitton Date: Wed, 23 Feb 2022 13:03:56 +0200 Subject: habanalabs: remove deprecated firmware states During driver and F/W handshake, driver waits for F/W to reach certain states in order to progress with the boot flow. Some of the states were deprecated a long time ago and were never present on official firmwares. Therefore, let's remove them from the handshake process. Signed-off-by: Ofir Bitton Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay --- drivers/misc/habanalabs/common/firmware_if.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/habanalabs/common/firmware_if.c b/drivers/misc/habanalabs/common/firmware_if.c index 11957d36c6a9..3262126cc7ca 100644 --- a/drivers/misc/habanalabs/common/firmware_if.c +++ b/drivers/misc/habanalabs/common/firmware_if.c @@ -1207,8 +1207,6 @@ static int hl_fw_read_preboot_caps(struct hl_device *hdev, hdev, cpu_boot_status_reg, status, - (status == CPU_BOOT_STATUS_IN_UBOOT) || - (status == CPU_BOOT_STATUS_DRAM_RDY) || (status == CPU_BOOT_STATUS_NIC_FW_RDY) || (status == CPU_BOOT_STATUS_READY_TO_BOOT) || (status == CPU_BOOT_STATUS_WAITING_FOR_BOOT_FIT), -- cgit v1.3.1 From 5df0e734b8c39598effe0f17e5bd8ff7748a0693 Mon Sep 17 00:00:00 2001 From: Vishnu Dasa Date: Thu, 17 Mar 2022 22:58:43 -0700 Subject: VMCI: Check exclusive_vectors when freeing interrupt 1 free_irq() may be called to free an interrupt that was not allocated. Add missing 'if' statement to check for exclusive_vectors when freeing interrupt 1. Fixes: cc68f2177fcb ("VMCI: dma dg: register dummy IRQ handlers for DMA datagrams") Reported-by: Dan Carpenter Reviewed-by: Bryan Tan Reviewed-by: Rajesh Jalisatgi Signed-off-by: Vishnu Dasa Link: https://lore.kernel.org/r/20220318055843.30606-1-vdasa@vmware.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_guest.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c index 981b19308e6f..c8181467d4c5 100644 --- a/drivers/misc/vmw_vmci/vmci_guest.c +++ b/drivers/misc/vmw_vmci/vmci_guest.c @@ -862,7 +862,9 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, return 0; err_free_bm_irq: - free_irq(pci_irq_vector(pdev, 1), vmci_dev); + if (vmci_dev->exclusive_vectors) + free_irq(pci_irq_vector(pdev, 1), vmci_dev); + err_free_irq: free_irq(pci_irq_vector(pdev, 0), vmci_dev); tasklet_kill(&vmci_dev->datagram_tasklet); -- cgit v1.3.1 From c8e9b30ccae605bf1dbeaf03971f9b83f70b928d Mon Sep 17 00:00:00 2001 From: Vishnu Dasa Date: Thu, 17 Mar 2022 23:00:40 -0700 Subject: VMCI: Release notification_bitmap in error path notification_bitmap may not be released when VMCI_CAPS_DMA_DATAGRAM capability is missing from the device. Add missing 'err_free_notification_bitmap' label and use it instead of 'err_free_data_buffers' to avoid this. Fixes: eed2298d9360 ("VMCI: dma dg: detect DMA datagram capability") Reported-by: Dan Carpenter Reviewed-by: Bryan Tan Reviewed-by: Rajesh Jalisatgi Signed-off-by: Vishnu Dasa Link: https://lore.kernel.org/r/20220318060040.31621-1-vdasa@vmware.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_guest.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/vmw_vmci/vmci_guest.c b/drivers/misc/vmw_vmci/vmci_guest.c index c8181467d4c5..57a6157209a1 100644 --- a/drivers/misc/vmw_vmci/vmci_guest.c +++ b/drivers/misc/vmw_vmci/vmci_guest.c @@ -720,7 +720,7 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, dev_err(&pdev->dev, "Missing capability: VMCI_CAPS_DMA_DATAGRAM\n"); error = -ENXIO; - goto err_free_data_buffers; + goto err_free_notification_bitmap; } } @@ -886,6 +886,7 @@ err_remove_vmci_dev_g: vmci_dev_g = NULL; spin_unlock_irq(&vmci_dev_spinlock); +err_free_notification_bitmap: if (vmci_dev->notification_bitmap) { vmci_write_reg(vmci_dev, VMCI_CONTROL_RESET, VMCI_CONTROL_ADDR); dma_free_coherent(&pdev->dev, PAGE_SIZE, -- cgit v1.3.1 From 7bbbd0845818cffa9fa8ccfe52fa1cad58e7e4f2 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Tue, 1 Mar 2022 09:11:15 +0200 Subject: mei: me: add Alder Lake N device id. Add Alder Lake N device ID. Cc: Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Link: https://lore.kernel.org/r/20220301071115.96145-1-tomas.winkler@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me-regs.h | 1 + drivers/misc/mei/pci-me.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index 888c27bc3f1a..64ce3f830262 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -107,6 +107,7 @@ #define MEI_DEV_ID_ADP_S 0x7AE8 /* Alder Lake Point S */ #define MEI_DEV_ID_ADP_LP 0x7A60 /* Alder Lake Point LP */ #define MEI_DEV_ID_ADP_P 0x51E0 /* Alder Lake Point P */ +#define MEI_DEV_ID_ADP_N 0x54E0 /* Alder Lake Point N */ /* * MEI HW Section diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index a05cdb25d0c4..33e58821e478 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -114,6 +114,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_S, MEI_ME_PCH15_CFG)}, {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_LP, MEI_ME_PCH15_CFG)}, {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_P, MEI_ME_PCH15_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_N, MEI_ME_PCH15_CFG)}, /* required last entry */ {0, } -- cgit v1.3.1 From c10187b1c5ebb8681ca467ab7b0ded5ea415d258 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Tue, 8 Mar 2022 11:59:26 +0200 Subject: mei: avoid iterator usage outside of list_for_each_entry Usage of the iterator outside of the list_for_each_entry is considered harmful. https://lkml.org/lkml/2022/2/17/1032 Do not reference the loop variable outside of the loop, by rearranging the orders of execution. Instead of performing search loop and checking outside the loop if the end of the list was hit and no matching element was found, the execution is performed inside the loop upon a successful match followed by a goto statement to the next step, therefore no condition has to be performed after the loop has ended. Cc: Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Link: https://lore.kernel.org/r/20220308095926.300412-1-tomas.winkler@intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/interrupt.c | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index a67f4f2d33a9..0706322154cb 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -424,31 +424,26 @@ int mei_irq_read_handler(struct mei_device *dev, list_for_each_entry(cl, &dev->file_list, link) { if (mei_cl_hbm_equal(cl, mei_hdr)) { cl_dbg(dev, cl, "got a message\n"); - break; + ret = mei_cl_irq_read_msg(cl, mei_hdr, meta_hdr, cmpl_list); + goto reset_slots; } } /* if no recipient cl was found we assume corrupted header */ - if (&cl->link == &dev->file_list) { - /* A message for not connected fixed address clients - * should be silently discarded - * On power down client may be force cleaned, - * silently discard such messages - */ - if (hdr_is_fixed(mei_hdr) || - dev->dev_state == MEI_DEV_POWER_DOWN) { - mei_irq_discard_msg(dev, mei_hdr, mei_hdr->length); - ret = 0; - goto reset_slots; - } - dev_err(dev->dev, "no destination client found 0x%08X\n", - dev->rd_msg_hdr[0]); - ret = -EBADMSG; - goto end; + /* A message for not connected fixed address clients + * should be silently discarded + * On power down client may be force cleaned, + * silently discard such messages + */ + if (hdr_is_fixed(mei_hdr) || + dev->dev_state == MEI_DEV_POWER_DOWN) { + mei_irq_discard_msg(dev, mei_hdr, mei_hdr->length); + ret = 0; + goto reset_slots; } - - ret = mei_cl_irq_read_msg(cl, mei_hdr, meta_hdr, cmpl_list); - + dev_err(dev->dev, "no destination client found 0x%08X\n", dev->rd_msg_hdr[0]); + ret = -EBADMSG; + goto end; reset_slots: /* reset the number of slots and header */ -- cgit v1.3.1 From f1bc423f56306b24fb15bc4a1612ef6c6ee24603 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Thu, 3 Mar 2022 10:02:06 +0800 Subject: misc: rtsx: clean up one inconsistent indenting Eliminate the follow smatch warning: drivers/misc/cardreader/rts5228.c:494 rts5228_extra_init_hw() warn: inconsistent indenting Reported-by: Abaci Robot Signed-off-by: Yang Li Link: https://lore.kernel.org/r/20220303020206.98911-1-yang.lee@linux.alibaba.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cardreader/rts5228.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/cardreader/rts5228.c b/drivers/misc/cardreader/rts5228.c index af581f4f74d1..cfebad51d1d8 100644 --- a/drivers/misc/cardreader/rts5228.c +++ b/drivers/misc/cardreader/rts5228.c @@ -491,7 +491,7 @@ static int rts5228_extra_init_hw(struct rtsx_pcr *pcr) if (pcr->rtd3_en) { rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x01, 0x01); - rtsx_pci_write_register(pcr, RTS5228_REG_PME_FORCE_CTL, + rtsx_pci_write_register(pcr, RTS5228_REG_PME_FORCE_CTL, FORCE_PM_CONTROL | FORCE_PM_VALUE, FORCE_PM_CONTROL | FORCE_PM_VALUE); } else { -- cgit v1.3.1 From 3b2e6a932eade9625fb6388c970004ae866601ee Mon Sep 17 00:00:00 2001 From: Desmond Yan Date: Tue, 1 Mar 2022 18:53:40 -0800 Subject: misc: bcm-vk: Remove viper from device id table As bcm_vk driver is not the production driver for viper, remove its pci device id from table. Acked-by: Scott Branden Signed-off-by: Desmond Yan Link: https://lore.kernel.org/r/20220302025340.25602-1-desmond.yan@broadcom.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/bcm-vk/bcm_vk_dev.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/bcm-vk/bcm_vk_dev.c b/drivers/misc/bcm-vk/bcm_vk_dev.c index ad639ee85b2a..a16b99bdaa13 100644 --- a/drivers/misc/bcm-vk/bcm_vk_dev.c +++ b/drivers/misc/bcm-vk/bcm_vk_dev.c @@ -1633,7 +1633,6 @@ static void bcm_vk_shutdown(struct pci_dev *pdev) static const struct pci_device_id bcm_vk_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_VALKYRIE), }, - { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_VIPER), }, { } }; MODULE_DEVICE_TABLE(pci, bcm_vk_ids); -- cgit v1.3.1 From 824a29ad44b6be1c6ef7cc562f701ce70d020708 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 15 Mar 2022 22:22:53 +0000 Subject: misc: sgi-gru: Fix spelling mistake "unexpect" -> "unexpected" There is a spelling mistake in an error message. Fix it. Acked-by: Dimitri Sivanich Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20220315222253.2960047-1-colin.i.king@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/sgi-gru/grukservices.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/misc') diff --git a/drivers/misc/sgi-gru/grukservices.c b/drivers/misc/sgi-gru/grukservices.c index 0ea923fe6371..19dbdad8ad8a 100644 --- a/drivers/misc/sgi-gru/grukservices.c +++ b/drivers/misc/sgi-gru/grukservices.c @@ -1016,7 +1016,7 @@ static int quicktest1(unsigned long arg) break; } if (ret != MQE_QUEUE_FULL || i != 4) { - printk(KERN_DEBUG "GRU:%d quicktest1: unexpect status %d, i %d\n", + printk(KERN_DEBUG "GRU:%d quicktest1: unexpected status %d, i %d\n", smp_processor_id(), ret, i); goto done; } -- cgit v1.3.1 From 965602eabb57d086466ad749e81941e3dd66b595 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 14 Feb 2022 16:09:51 +0000 Subject: misc: fastrpc: separate fastrpc device from channel context Currently fastrpc misc device instance is within channel context struct with a kref. So we have 2 structs with refcount, both of them managing the same channel context structure. Separate fastrpc device from channel context and by adding a dedicated fastrpc_device structure, this should clean the structures a bit and also help when adding secure device node support. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220214161002.6831-2-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 46 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 9 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index aa1682b94a23..ee5eb87e9f87 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -78,7 +78,7 @@ #define USER_PD (1) #define SENSORS_PD (2) -#define miscdev_to_cctx(d) container_of(d, struct fastrpc_channel_ctx, miscdev) +#define miscdev_to_fdevice(d) container_of(d, struct fastrpc_device, miscdev) static const char *domains[FASTRPC_DEV_MAX] = { "adsp", "mdsp", "sdsp", "cdsp"}; @@ -212,8 +212,13 @@ struct fastrpc_channel_ctx { spinlock_t lock; struct idr ctx_idr; struct list_head users; - struct miscdevice miscdev; struct kref refcount; + struct fastrpc_device *fdevice; +}; + +struct fastrpc_device { + struct fastrpc_channel_ctx *cctx; + struct miscdevice miscdev; }; struct fastrpc_user { @@ -1220,10 +1225,14 @@ static int fastrpc_device_release(struct inode *inode, struct file *file) static int fastrpc_device_open(struct inode *inode, struct file *filp) { - struct fastrpc_channel_ctx *cctx = miscdev_to_cctx(filp->private_data); + struct fastrpc_channel_ctx *cctx; + struct fastrpc_device *fdevice; struct fastrpc_user *fl = NULL; unsigned long flags; + fdevice = miscdev_to_fdevice(filp->private_data); + cctx = fdevice->cctx; + fl = kzalloc(sizeof(*fl), GFP_KERNEL); if (!fl) return -ENOMEM; @@ -1615,6 +1624,27 @@ static struct platform_driver fastrpc_cb_driver = { }, }; +static int fastrpc_device_register(struct device *dev, struct fastrpc_channel_ctx *cctx, + const char *domain) +{ + struct fastrpc_device *fdev; + int err; + + fdev = devm_kzalloc(dev, sizeof(*fdev), GFP_KERNEL); + if (!fdev) + return -ENOMEM; + + fdev->cctx = cctx; + fdev->miscdev.minor = MISC_DYNAMIC_MINOR; + fdev->miscdev.fops = &fastrpc_fops; + fdev->miscdev.name = devm_kasprintf(dev, GFP_KERNEL, "fastrpc-%s", domain); + err = misc_register(&fdev->miscdev); + if (!err) + cctx->fdevice = fdev; + + return err; +} + static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) { struct device *rdev = &rpdev->dev; @@ -1644,11 +1674,7 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) if (!data) return -ENOMEM; - data->miscdev.minor = MISC_DYNAMIC_MINOR; - data->miscdev.name = devm_kasprintf(rdev, GFP_KERNEL, "fastrpc-%s", - domains[domain_id]); - data->miscdev.fops = &fastrpc_fops; - err = misc_register(&data->miscdev); + err = fastrpc_device_register(rdev, data, domains[domain_id]); if (err) { kfree(data); return err; @@ -1688,7 +1714,9 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev) fastrpc_notify_users(user); spin_unlock_irqrestore(&cctx->lock, flags); - misc_deregister(&cctx->miscdev); + if (cctx->fdevice) + misc_deregister(&cctx->fdevice->miscdev); + of_platform_depopulate(&rpdev->dev); cctx->rpdev = NULL; -- cgit v1.3.1 From 5c1b97c7d7b736e6439af4f43a65837bc72f56c1 Mon Sep 17 00:00:00 2001 From: Jeya R Date: Mon, 14 Feb 2022 16:09:52 +0000 Subject: misc: fastrpc: add support for FASTRPC_IOCTL_MEM_MAP/UNMAP Add support for IOCTL requests to map and unmap on DSP based on map flags. Signed-off-by: Jeya R Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220214161002.6831-3-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 154 ++++++++++++++++++++++++++++++++++++++++++++ include/uapi/misc/fastrpc.h | 51 +++++++++++++++ 2 files changed, 205 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index ee5eb87e9f87..7d8150179b1b 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -72,6 +72,8 @@ #define FASTRPC_RMID_INIT_CREATE 6 #define FASTRPC_RMID_INIT_CREATE_ATTR 7 #define FASTRPC_RMID_INIT_CREATE_STATIC 8 +#define FASTRPC_RMID_INIT_MEM_MAP 10 +#define FASTRPC_RMID_INIT_MEM_UNMAP 11 /* Protection Domain(PD) ids */ #define AUDIO_PD (0) /* also GUEST_OS PD? */ @@ -108,12 +110,29 @@ struct fastrpc_mmap_req_msg { s32 num; }; +struct fastrpc_mem_map_req_msg { + s32 pgid; + s32 fd; + s32 offset; + u32 flags; + u64 vaddrin; + s32 num; + s32 data_len; +}; + struct fastrpc_munmap_req_msg { s32 pgid; u64 vaddr; u64 size; }; +struct fastrpc_mem_unmap_req_msg { + s32 pgid; + s32 fd; + u64 vaddrin; + u64 len; +}; + struct fastrpc_msg { int pid; /* process group id */ int tid; /* thread id */ @@ -170,6 +189,7 @@ struct fastrpc_map { u64 size; void *va; u64 len; + u64 raddr; struct kref refcount; }; @@ -1500,6 +1520,134 @@ err_invoke: return err; } +static int fastrpc_req_mem_unmap_impl(struct fastrpc_user *fl, struct fastrpc_mem_unmap *req) +{ + struct fastrpc_invoke_args args[1] = { [0] = { 0 } }; + struct fastrpc_map *map = NULL, *m; + struct fastrpc_mem_unmap_req_msg req_msg = { 0 }; + int err = 0; + u32 sc; + struct device *dev = fl->sctx->dev; + + spin_lock(&fl->lock); + list_for_each_entry_safe(map, m, &fl->maps, node) { + if ((req->fd < 0 || map->fd == req->fd) && (map->raddr == req->vaddr)) + break; + map = NULL; + } + + spin_unlock(&fl->lock); + + if (!map) { + dev_err(dev, "map not in list\n"); + return -EINVAL; + } + + req_msg.pgid = fl->tgid; + req_msg.len = map->len; + req_msg.vaddrin = map->raddr; + req_msg.fd = map->fd; + + args[0].ptr = (u64) (uintptr_t) &req_msg; + args[0].length = sizeof(req_msg); + + sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MEM_UNMAP, 1, 0); + err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc, + &args[0]); + fastrpc_map_put(map); + if (err) + dev_err(dev, "unmmap\tpt fd = %d, 0x%09llx error\n", map->fd, map->raddr); + + return err; +} + +static int fastrpc_req_mem_unmap(struct fastrpc_user *fl, char __user *argp) +{ + struct fastrpc_mem_unmap req; + + if (copy_from_user(&req, argp, sizeof(req))) + return -EFAULT; + + return fastrpc_req_mem_unmap_impl(fl, &req); +} + +static int fastrpc_req_mem_map(struct fastrpc_user *fl, char __user *argp) +{ + struct fastrpc_invoke_args args[4] = { [0 ... 3] = { 0 } }; + struct fastrpc_mem_map_req_msg req_msg = { 0 }; + struct fastrpc_mmap_rsp_msg rsp_msg = { 0 }; + struct fastrpc_mem_unmap req_unmap = { 0 }; + struct fastrpc_phy_page pages = { 0 }; + struct fastrpc_mem_map req; + struct device *dev = fl->sctx->dev; + struct fastrpc_map *map = NULL; + int err; + u32 sc; + + if (copy_from_user(&req, argp, sizeof(req))) + return -EFAULT; + + /* create SMMU mapping */ + err = fastrpc_map_create(fl, req.fd, req.length, &map); + if (err) { + dev_err(dev, "failed to map buffer, fd = %d\n", req.fd); + return err; + } + + req_msg.pgid = fl->tgid; + req_msg.fd = req.fd; + req_msg.offset = req.offset; + req_msg.vaddrin = req.vaddrin; + map->va = (void *) (uintptr_t) req.vaddrin; + req_msg.flags = req.flags; + req_msg.num = sizeof(pages); + req_msg.data_len = 0; + + args[0].ptr = (u64) (uintptr_t) &req_msg; + args[0].length = sizeof(req_msg); + + pages.addr = map->phys; + pages.size = map->size; + + args[1].ptr = (u64) (uintptr_t) &pages; + args[1].length = sizeof(pages); + + args[2].ptr = (u64) (uintptr_t) &pages; + args[2].length = 0; + + args[3].ptr = (u64) (uintptr_t) &rsp_msg; + args[3].length = sizeof(rsp_msg); + + sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_MEM_MAP, 3, 1); + err = fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, sc, &args[0]); + if (err) { + dev_err(dev, "mem mmap error, fd %d, vaddr %llx, size %lld\n", + req.fd, req.vaddrin, map->size); + goto err_invoke; + } + + /* update the buffer to be able to deallocate the memory on the DSP */ + map->raddr = rsp_msg.vaddr; + + /* let the client know the address to use */ + req.vaddrout = rsp_msg.vaddr; + + if (copy_to_user((void __user *)argp, &req, sizeof(req))) { + /* unmap the memory and release the buffer */ + req_unmap.vaddr = (uintptr_t) rsp_msg.vaddr; + req_unmap.length = map->size; + fastrpc_req_mem_unmap_impl(fl, &req_unmap); + return -EFAULT; + } + + return 0; + +err_invoke: + fastrpc_map_put(map); + + return err; +} + static long fastrpc_device_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -1529,6 +1677,12 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int cmd, case FASTRPC_IOCTL_MUNMAP: err = fastrpc_req_munmap(fl, argp); break; + case FASTRPC_IOCTL_MEM_MAP: + err = fastrpc_req_mem_map(fl, argp); + break; + case FASTRPC_IOCTL_MEM_UNMAP: + err = fastrpc_req_mem_unmap(fl, argp); + break; default: err = -ENOTTY; break; diff --git a/include/uapi/misc/fastrpc.h b/include/uapi/misc/fastrpc.h index 0a89f95463f6..d248eeb20e67 100644 --- a/include/uapi/misc/fastrpc.h +++ b/include/uapi/misc/fastrpc.h @@ -13,6 +13,37 @@ #define FASTRPC_IOCTL_MMAP _IOWR('R', 6, struct fastrpc_req_mmap) #define FASTRPC_IOCTL_MUNMAP _IOWR('R', 7, struct fastrpc_req_munmap) #define FASTRPC_IOCTL_INIT_ATTACH_SNS _IO('R', 8) +#define FASTRPC_IOCTL_MEM_MAP _IOWR('R', 10, struct fastrpc_mem_map) +#define FASTRPC_IOCTL_MEM_UNMAP _IOWR('R', 11, struct fastrpc_mem_unmap) + +/** + * enum fastrpc_map_flags - control flags for mapping memory on DSP user process + * @FASTRPC_MAP_STATIC: Map memory pages with RW- permission and CACHE WRITEBACK. + * The driver is responsible for cache maintenance when passed + * the buffer to FastRPC calls. Same virtual address will be + * assigned for subsequent FastRPC calls. + * @FASTRPC_MAP_RESERVED: Reserved + * @FASTRPC_MAP_FD: Map memory pages with RW- permission and CACHE WRITEBACK. + * Mapping tagged with a file descriptor. User is responsible for + * CPU and DSP cache maintenance for the buffer. Get virtual address + * of buffer on DSP using HAP_mmap_get() and HAP_mmap_put() APIs. + * @FASTRPC_MAP_FD_DELAYED: Mapping delayed until user call HAP_mmap() and HAP_munmap() + * functions on DSP. It is useful to map a buffer with cache modes + * other than default modes. User is responsible for CPU and DSP + * cache maintenance for the buffer. + * @FASTRPC_MAP_FD_NOMAP: This flag is used to skip CPU mapping, + * otherwise behaves similar to FASTRPC_MAP_FD_DELAYED flag. + * @FASTRPC_MAP_MAX: max count for flags + * + */ +enum fastrpc_map_flags { + FASTRPC_MAP_STATIC = 0, + FASTRPC_MAP_RESERVED, + FASTRPC_MAP_FD = 2, + FASTRPC_MAP_FD_DELAYED, + FASTRPC_MAP_FD_NOMAP = 16, + FASTRPC_MAP_MAX, +}; struct fastrpc_invoke_args { __u64 ptr; @@ -49,9 +80,29 @@ struct fastrpc_req_mmap { __u64 vaddrout; /* dsp virtual address */ }; +struct fastrpc_mem_map { + __s32 version; + __s32 fd; /* fd */ + __s32 offset; /* buffer offset */ + __u32 flags; /* flags defined in enum fastrpc_map_flags */ + __u64 vaddrin; /* buffer virtual address */ + __u64 length; /* buffer length */ + __u64 vaddrout; /* [out] remote virtual address */ + __s32 attrs; /* buffer attributes used for SMMU mapping */ + __s32 reserved[4]; +}; + struct fastrpc_req_munmap { __u64 vaddrout; /* address to unmap */ __u64 size; /* size */ }; +struct fastrpc_mem_unmap { + __s32 vesion; + __s32 fd; /* fd */ + __u64 vaddr; /* remote process (dsp) virtual address */ + __u64 length; /* buffer size */ + __s32 reserved[5]; +}; + #endif /* __QCOM_FASTRPC_H__ */ -- cgit v1.3.1 From 6c16fd8bdd4058d4a6aaca9d5a7b40e4cb281d5a Mon Sep 17 00:00:00 2001 From: Jeya R Date: Mon, 14 Feb 2022 16:09:53 +0000 Subject: misc: fastrpc: Add support to get DSP capabilities Add support to get DSP capabilities. The capability information is cached on driver. Signed-off-by: Jeya R Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220214161002.6831-4-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 112 ++++++++++++++++++++++++++++++++++++++++++++ include/uapi/misc/fastrpc.h | 8 ++++ 2 files changed, 120 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 7d8150179b1b..4b1a4c1c5535 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -31,10 +31,15 @@ #define FASTRPC_PHYS(p) ((p) & 0xffffffff) #define FASTRPC_CTX_MAX (256) #define FASTRPC_INIT_HANDLE 1 +#define FASTRPC_DSP_UTILITIES_HANDLE 2 #define FASTRPC_CTXID_MASK (0xFF0) #define INIT_FILELEN_MAX (2 * 1024 * 1024) #define FASTRPC_DEVICE_NAME "fastrpc" #define ADSP_MMAP_ADD_PAGES 0x1000 +#define DSP_UNSUPPORTED_API (0x80000414) +/* MAX NUMBER of DSP ATTRIBUTES SUPPORTED */ +#define FASTRPC_MAX_DSP_ATTRIBUTES (256) +#define FASTRPC_MAX_DSP_ATTRIBUTES_LEN (sizeof(u32) * FASTRPC_MAX_DSP_ATTRIBUTES) /* Retrives number of input buffers from the scalars parameter */ #define REMOTE_SCALARS_INBUFS(sc) (((sc) >> 16) & 0x0ff) @@ -233,6 +238,9 @@ struct fastrpc_channel_ctx { struct idr ctx_idr; struct list_head users; struct kref refcount; + /* Flag if dsp attributes are cached */ + bool valid_attributes; + u32 dsp_attributes[FASTRPC_MAX_DSP_ATTRIBUTES]; struct fastrpc_device *fdevice; }; @@ -1378,6 +1386,107 @@ static int fastrpc_invoke(struct fastrpc_user *fl, char __user *argp) return err; } +static int fastrpc_get_info_from_dsp(struct fastrpc_user *fl, uint32_t *dsp_attr_buf, + uint32_t dsp_attr_buf_len) +{ + struct fastrpc_invoke_args args[2] = { 0 }; + + /* Capability filled in userspace */ + dsp_attr_buf[0] = 0; + + args[0].ptr = (u64)(uintptr_t)&dsp_attr_buf_len; + args[0].length = sizeof(dsp_attr_buf_len); + args[0].fd = -1; + args[1].ptr = (u64)(uintptr_t)&dsp_attr_buf[1]; + args[1].length = dsp_attr_buf_len; + args[1].fd = -1; + fl->pd = 1; + + return fastrpc_internal_invoke(fl, true, FASTRPC_DSP_UTILITIES_HANDLE, + FASTRPC_SCALARS(0, 1, 1), args); +} + +static int fastrpc_get_info_from_kernel(struct fastrpc_ioctl_capability *cap, + struct fastrpc_user *fl) +{ + struct fastrpc_channel_ctx *cctx = fl->cctx; + uint32_t attribute_id = cap->attribute_id; + uint32_t *dsp_attributes; + unsigned long flags; + uint32_t domain = cap->domain; + int err; + + spin_lock_irqsave(&cctx->lock, flags); + /* check if we already have queried dsp for attributes */ + if (cctx->valid_attributes) { + spin_unlock_irqrestore(&cctx->lock, flags); + goto done; + } + spin_unlock_irqrestore(&cctx->lock, flags); + + dsp_attributes = kzalloc(FASTRPC_MAX_DSP_ATTRIBUTES_LEN, GFP_KERNEL); + if (!dsp_attributes) + return -ENOMEM; + + err = fastrpc_get_info_from_dsp(fl, dsp_attributes, FASTRPC_MAX_DSP_ATTRIBUTES_LEN); + if (err == DSP_UNSUPPORTED_API) { + dev_info(&cctx->rpdev->dev, + "Warning: DSP capabilities not supported on domain: %d\n", domain); + kfree(dsp_attributes); + return -EOPNOTSUPP; + } else if (err) { + dev_err(&cctx->rpdev->dev, "Error: dsp information is incorrect err: %d\n", err); + kfree(dsp_attributes); + return err; + } + + spin_lock_irqsave(&cctx->lock, flags); + memcpy(cctx->dsp_attributes, dsp_attributes, FASTRPC_MAX_DSP_ATTRIBUTES_LEN); + cctx->valid_attributes = true; + spin_unlock_irqrestore(&cctx->lock, flags); + kfree(dsp_attributes); +done: + cap->capability = cctx->dsp_attributes[attribute_id]; + return 0; +} + +static int fastrpc_get_dsp_info(struct fastrpc_user *fl, char __user *argp) +{ + struct fastrpc_ioctl_capability cap = {0}; + int err = 0; + + if (copy_from_user(&cap, argp, sizeof(cap))) + return -EFAULT; + + cap.capability = 0; + if (cap.domain >= FASTRPC_DEV_MAX) { + dev_err(&fl->cctx->rpdev->dev, "Error: Invalid domain id:%d, err:%d\n", + cap.domain, err); + return -ECHRNG; + } + + /* Fastrpc Capablities does not support modem domain */ + if (cap.domain == MDSP_DOMAIN_ID) { + dev_err(&fl->cctx->rpdev->dev, "Error: modem not supported %d\n", err); + return -ECHRNG; + } + + if (cap.attribute_id >= FASTRPC_MAX_DSP_ATTRIBUTES) { + dev_err(&fl->cctx->rpdev->dev, "Error: invalid attribute: %d, err: %d\n", + cap.attribute_id, err); + return -EOVERFLOW; + } + + err = fastrpc_get_info_from_kernel(&cap, fl); + if (err) + return err; + + if (copy_to_user(argp, &cap.capability, sizeof(cap.capability))) + return -EFAULT; + + return 0; +} + static int fastrpc_req_munmap_impl(struct fastrpc_user *fl, struct fastrpc_req_munmap *req) { @@ -1683,6 +1792,9 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int cmd, case FASTRPC_IOCTL_MEM_UNMAP: err = fastrpc_req_mem_unmap(fl, argp); break; + case FASTRPC_IOCTL_GET_DSP_INFO: + err = fastrpc_get_dsp_info(fl, argp); + break; default: err = -ENOTTY; break; diff --git a/include/uapi/misc/fastrpc.h b/include/uapi/misc/fastrpc.h index d248eeb20e67..7cc9d342078a 100644 --- a/include/uapi/misc/fastrpc.h +++ b/include/uapi/misc/fastrpc.h @@ -15,6 +15,7 @@ #define FASTRPC_IOCTL_INIT_ATTACH_SNS _IO('R', 8) #define FASTRPC_IOCTL_MEM_MAP _IOWR('R', 10, struct fastrpc_mem_map) #define FASTRPC_IOCTL_MEM_UNMAP _IOWR('R', 11, struct fastrpc_mem_unmap) +#define FASTRPC_IOCTL_GET_DSP_INFO _IOWR('R', 13, struct fastrpc_ioctl_capability) /** * enum fastrpc_map_flags - control flags for mapping memory on DSP user process @@ -105,4 +106,11 @@ struct fastrpc_mem_unmap { __s32 reserved[5]; }; +struct fastrpc_ioctl_capability { + __u32 domain; + __u32 attribute_id; + __u32 capability; /* dsp capability */ + __u32 reserved[4]; +}; + #endif /* __QCOM_FASTRPC_H__ */ -- cgit v1.3.1 From 3abe3ab3cdab71b2073ba6331edc0b2994643133 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 14 Feb 2022 16:09:55 +0000 Subject: misc: fastrpc: add secure domain support ADSP/MDSP/SDSP are by default secured, which means it can only be loaded with a Signed process. Where as CDSP can be either be secured/unsecured. non-secured Compute DSP would allow users to load unsigned process and run hexagon instructions, but blocking access to secured hardware within the DSP. Where as signed process with secure CDSP would be allowed to access all the dsp resources. This patch adds basic code to create device nodes as per device tree property. Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220214161002.6831-6-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 55 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 9 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 4b1a4c1c5535..3b7731f158eb 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -241,12 +241,15 @@ struct fastrpc_channel_ctx { /* Flag if dsp attributes are cached */ bool valid_attributes; u32 dsp_attributes[FASTRPC_MAX_DSP_ATTRIBUTES]; + struct fastrpc_device *secure_fdevice; struct fastrpc_device *fdevice; + bool secure; }; struct fastrpc_device { struct fastrpc_channel_ctx *cctx; struct miscdevice miscdev; + bool secure; }; struct fastrpc_user { @@ -1697,7 +1700,7 @@ static int fastrpc_req_mem_map(struct fastrpc_user *fl, char __user *argp) return -EFAULT; /* create SMMU mapping */ - err = fastrpc_map_create(fl, req.fd, req.length, &map); + err = fastrpc_map_create(fl, req.fd, req.length, 0, &map); if (err) { dev_err(dev, "failed to map buffer, fd = %d\n", req.fd); return err; @@ -1891,7 +1894,7 @@ static struct platform_driver fastrpc_cb_driver = { }; static int fastrpc_device_register(struct device *dev, struct fastrpc_channel_ctx *cctx, - const char *domain) + bool is_secured, const char *domain) { struct fastrpc_device *fdev; int err; @@ -1900,13 +1903,19 @@ static int fastrpc_device_register(struct device *dev, struct fastrpc_channel_ct if (!fdev) return -ENOMEM; + fdev->secure = is_secured; fdev->cctx = cctx; fdev->miscdev.minor = MISC_DYNAMIC_MINOR; fdev->miscdev.fops = &fastrpc_fops; - fdev->miscdev.name = devm_kasprintf(dev, GFP_KERNEL, "fastrpc-%s", domain); + fdev->miscdev.name = devm_kasprintf(dev, GFP_KERNEL, "fastrpc-%s%s", + domain, is_secured ? "-secure" : ""); err = misc_register(&fdev->miscdev); - if (!err) - cctx->fdevice = fdev; + if (!err) { + if (is_secured) + cctx->secure_fdevice = fdev; + else + cctx->fdevice = fdev; + } return err; } @@ -1917,6 +1926,7 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) struct fastrpc_channel_ctx *data; int i, err, domain_id = -1; const char *domain; + bool secure_dsp; err = of_property_read_string(rdev->of_node, "label", &domain); if (err) { @@ -1940,10 +1950,31 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) if (!data) return -ENOMEM; - err = fastrpc_device_register(rdev, data, domains[domain_id]); - if (err) { - kfree(data); - return err; + + secure_dsp = !(of_property_read_bool(rdev->of_node, "qcom,non-secure-domain")); + data->secure = secure_dsp; + + switch (domain_id) { + case ADSP_DOMAIN_ID: + case MDSP_DOMAIN_ID: + case SDSP_DOMAIN_ID: + err = fastrpc_device_register(rdev, data, secure_dsp, domains[domain_id]); + if (err) + goto fdev_error; + break; + case CDSP_DOMAIN_ID: + /* Create both device nodes so that we can allow both Signed and Unsigned PD */ + err = fastrpc_device_register(rdev, data, true, domains[domain_id]); + if (err) + goto fdev_error; + + err = fastrpc_device_register(rdev, data, false, domains[domain_id]); + if (err) + goto fdev_error; + break; + default: + err = -EINVAL; + goto fdev_error; } kref_init(&data->refcount); @@ -1957,6 +1988,9 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) data->rpdev = rpdev; return of_platform_populate(rdev->of_node, NULL, NULL, rdev); +fdev_error: + kfree(data); + return err; } static void fastrpc_notify_users(struct fastrpc_user *user) @@ -1983,6 +2017,9 @@ static void fastrpc_rpmsg_remove(struct rpmsg_device *rpdev) if (cctx->fdevice) misc_deregister(&cctx->fdevice->miscdev); + if (cctx->secure_fdevice) + misc_deregister(&cctx->secure_fdevice->miscdev); + of_platform_depopulate(&rpdev->dev); cctx->rpdev = NULL; -- cgit v1.3.1 From 7f1f481263c3ce5387d4fd5ad63ddaa8a295aab2 Mon Sep 17 00:00:00 2001 From: Jeya R Date: Mon, 14 Feb 2022 16:09:56 +0000 Subject: misc: fastrpc: check before loading process to the DSP Reject session if DSP domain is secure, device node is non-secure and signed PD is requested. Secure device node can access DSP without any restriction. Unsigned PD offload is only allowed for the DSP domain that can support unsigned offloading. Signed-off-by: Jeya R Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220214161002.6831-7-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 33 +++++++++++++++++++++++++++++++++ include/uapi/misc/fastrpc.h | 17 +++++++++++++++++ 2 files changed, 50 insertions(+) (limited to 'drivers/misc') diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 3b7731f158eb..8fbb24d763bd 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -244,6 +244,7 @@ struct fastrpc_channel_ctx { struct fastrpc_device *secure_fdevice; struct fastrpc_device *fdevice; bool secure; + bool unsigned_support; }; struct fastrpc_device { @@ -264,6 +265,7 @@ struct fastrpc_user { int tgid; int pd; + bool is_secure_dev; /* Lock for lists */ spinlock_t lock; /* lock for allocations */ @@ -1052,6 +1054,24 @@ bail: return err; } +static bool is_session_rejected(struct fastrpc_user *fl, bool unsigned_pd_request) +{ + /* Check if the device node is non-secure and channel is secure*/ + if (!fl->is_secure_dev && fl->cctx->secure) { + /* + * Allow untrusted applications to offload only to Unsigned PD when + * channel is configured as secure and block untrusted apps on channel + * that does not support unsigned PD offload + */ + if (!fl->cctx->unsigned_support || !unsigned_pd_request) { + dev_err(&fl->cctx->rpdev->dev, "Error: Untrusted application trying to offload to signed PD"); + return true; + } + } + + return false; +} + static int fastrpc_init_create_process(struct fastrpc_user *fl, char __user *argp) { @@ -1071,6 +1091,7 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl, u32 siglen; } inbuf; u32 sc; + bool unsigned_module = false; args = kcalloc(FASTRPC_CREATE_PROCESS_NARGS, sizeof(*args), GFP_KERNEL); if (!args) @@ -1081,6 +1102,14 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl, goto err; } + if (init.attrs & FASTRPC_MODE_UNSIGNED_MODULE) + unsigned_module = true; + + if (is_session_rejected(fl, unsigned_module)) { + err = -ECONNREFUSED; + goto err; + } + if (init.filelen > INIT_FILELEN_MAX) { err = -EINVAL; goto err; @@ -1280,6 +1309,7 @@ static int fastrpc_device_open(struct inode *inode, struct file *filp) INIT_LIST_HEAD(&fl->user); fl->tgid = current->tgid; fl->cctx = cctx; + fl->is_secure_dev = fdevice->secure; fl->sctx = fastrpc_session_alloc(cctx); if (!fl->sctx) { @@ -1958,11 +1988,14 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) case ADSP_DOMAIN_ID: case MDSP_DOMAIN_ID: case SDSP_DOMAIN_ID: + /* Unsigned PD offloading is only supported on CDSP*/ + data->unsigned_support = false; err = fastrpc_device_register(rdev, data, secure_dsp, domains[domain_id]); if (err) goto fdev_error; break; case CDSP_DOMAIN_ID: + data->unsigned_support = true; /* Create both device nodes so that we can allow both Signed and Unsigned PD */ err = fastrpc_device_register(rdev, data, true, domains[domain_id]); if (err) diff --git a/include/uapi/misc/fastrpc.h b/include/uapi/misc/fastrpc.h index 7cc9d342078a..f39edac20305 100644 --- a/include/uapi/misc/fastrpc.h +++ b/include/uapi/misc/fastrpc.h @@ -46,6 +46,23 @@ enum fastrpc_map_flags { FASTRPC_MAP_MAX, }; +enum fastrpc_proc_attr { + /* Macro for Debug attr */ + FASTRPC_MODE_DEBUG = (1 << 0), + /* Macro for Ptrace */ + FASTRPC_MODE_PTRACE = (1 << 1), + /* Macro for CRC Check */ + FASTRPC_MODE_CRC = (1 << 2), + /* Macro for Unsigned PD */ + FASTRPC_MODE_UNSIGNED_MODULE = (1 << 3), + /* Macro for Adaptive QoS */ + FASTRPC_MODE_ADAPTIVE_QOS = (1 << 4), + /* Macro for System Process */ + FASTRPC_MODE_SYSTEM_PROCESS = (1 << 5), + /* Macro for Prvileged Process */ + FASTRPC_MODE_PRIVILEGED = (1 << 6), +}; + struct fastrpc_invoke_args { __u64 ptr; __u64 length; -- cgit v1.3.1 From e90d911906196bf987492c94e38f10ca611dfd7b Mon Sep 17 00:00:00 2001 From: Vamsi Krishna Gattupalli Date: Mon, 14 Feb 2022 16:09:58 +0000 Subject: misc: fastrpc: Add support to secure memory map This patch adds support to secure memory allocations for DSP. It repurposes the reserved field in struct fastrpc_invoke_args to add attributes to invoke request, for example to setup a secure memory map for dsp. Secure memory is assigned to DSP Virtual Machine IDs using Qualcomm SCM calls. Signed-off-by: Vamsi Krishna Gattupalli Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220214161002.6831-9-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/Kconfig | 1 + drivers/misc/fastrpc.c | 65 ++++++++++++++++++++++++++++++++++++++------- include/uapi/misc/fastrpc.h | 5 +++- 3 files changed, 61 insertions(+), 10 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index a2b26426efba..41d2bb0ae23a 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -259,6 +259,7 @@ config QCOM_FASTRPC depends on ARCH_QCOM || COMPILE_TEST depends on RPMSG select DMA_SHARED_BUFFER + select QCOM_SCM help Provides a communication mechanism that allows for clients to make remote method invocations across processor boundary to diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 8fbb24d763bd..ae7586d7956f 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #define ADSP_DOMAIN_ID (0) @@ -25,6 +26,7 @@ #define CDSP_DOMAIN_ID (3) #define FASTRPC_DEV_MAX 4 /* adsp, mdsp, slpi, cdsp*/ #define FASTRPC_MAX_SESSIONS 13 /*12 compute, 1 cpz*/ +#define FASTRPC_MAX_VMIDS 16 #define FASTRPC_ALIGN 128 #define FASTRPC_MAX_FDLIST 16 #define FASTRPC_MAX_CRCLIST 64 @@ -195,6 +197,7 @@ struct fastrpc_map { void *va; u64 len; u64 raddr; + u32 attr; struct kref refcount; }; @@ -232,6 +235,9 @@ struct fastrpc_session_ctx { struct fastrpc_channel_ctx { int domain_id; int sesscount; + int vmcount; + u32 perms; + struct qcom_scm_vmperm vmperms[FASTRPC_MAX_VMIDS]; struct rpmsg_device *rpdev; struct fastrpc_session_ctx session[FASTRPC_MAX_SESSIONS]; spinlock_t lock; @@ -279,6 +285,20 @@ static void fastrpc_free_map(struct kref *ref) map = container_of(ref, struct fastrpc_map, refcount); if (map->table) { + if (map->attr & FASTRPC_ATTR_SECUREMAP) { + struct qcom_scm_vmperm perm; + int err = 0; + + perm.vmid = QCOM_SCM_VMID_HLOS; + perm.perm = QCOM_SCM_PERM_RWX; + err = qcom_scm_assign_mem(map->phys, map->size, + &(map->fl->cctx->vmperms[0].vmid), &perm, 1); + if (err) { + dev_err(map->fl->sctx->dev, "Failed to assign memory phys 0x%llx size 0x%llx err %d", + map->phys, map->size, err); + return; + } + } dma_buf_unmap_attachment(map->attach, map->table, DMA_BIDIRECTIONAL); dma_buf_detach(map->buf, map->attach); @@ -655,7 +675,7 @@ static const struct dma_buf_ops fastrpc_dma_buf_ops = { }; static int fastrpc_map_create(struct fastrpc_user *fl, int fd, - u64 len, struct fastrpc_map **ppmap) + u64 len, u32 attr, struct fastrpc_map **ppmap) { struct fastrpc_session_ctx *sess = fl->sctx; struct fastrpc_map *map = NULL; @@ -697,6 +717,22 @@ static int fastrpc_map_create(struct fastrpc_user *fl, int fd, map->len = len; kref_init(&map->refcount); + if (attr & FASTRPC_ATTR_SECUREMAP) { + /* + * If subsystem VMIDs are defined in DTSI, then do + * hyp_assign from HLOS to those VM(s) + */ + unsigned int perms = BIT(QCOM_SCM_VMID_HLOS); + + map->attr = attr; + err = qcom_scm_assign_mem(map->phys, (u64)map->size, &perms, + fl->cctx->vmperms, fl->cctx->vmcount); + if (err) { + dev_err(sess->dev, "Failed to assign memory with phys 0x%llx size 0x%llx err %d", + map->phys, map->size, err); + goto map_err; + } + } spin_lock(&fl->lock); list_add_tail(&map->node, &fl->maps); spin_unlock(&fl->lock); @@ -781,16 +817,13 @@ static int fastrpc_create_maps(struct fastrpc_invoke_ctx *ctx) int i, err; for (i = 0; i < ctx->nscalars; ++i) { - /* Make sure reserved field is set to 0 */ - if (ctx->args[i].reserved) - return -EINVAL; if (ctx->args[i].fd == 0 || ctx->args[i].fd == -1 || ctx->args[i].length == 0) continue; err = fastrpc_map_create(ctx->fl, ctx->args[i].fd, - ctx->args[i].length, &ctx->maps[i]); + ctx->args[i].length, ctx->args[i].attr, &ctx->maps[i]); if (err) { dev_err(dev, "Error Creating map %d\n", err); return -EINVAL; @@ -1124,7 +1157,7 @@ static int fastrpc_init_create_process(struct fastrpc_user *fl, fl->pd = USER_PD; if (init.filelen && init.filefd) { - err = fastrpc_map_create(fl, init.filefd, init.filelen, &map); + err = fastrpc_map_create(fl, init.filefd, init.filelen, 0, &map); if (err) goto err; } @@ -1233,7 +1266,6 @@ static int fastrpc_release_current_dsp_process(struct fastrpc_user *fl) args[0].ptr = (u64)(uintptr_t) &tgid; args[0].length = sizeof(tgid); args[0].fd = -1; - args[0].reserved = 0; sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_RELEASE, 1, 0); return fastrpc_internal_invoke(fl, true, FASTRPC_INIT_HANDLE, @@ -1381,7 +1413,6 @@ static int fastrpc_init_attach(struct fastrpc_user *fl, int pd) args[0].ptr = (u64)(uintptr_t) &tgid; args[0].length = sizeof(tgid); args[0].fd = -1; - args[0].reserved = 0; sc = FASTRPC_SCALARS(FASTRPC_RMID_INIT_ATTACH, 1, 0); fl->pd = pd; @@ -1954,9 +1985,10 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) { struct device *rdev = &rpdev->dev; struct fastrpc_channel_ctx *data; - int i, err, domain_id = -1; + int i, err, domain_id = -1, vmcount; const char *domain; bool secure_dsp; + unsigned int vmids[FASTRPC_MAX_VMIDS]; err = of_property_read_string(rdev->of_node, "label", &domain); if (err) { @@ -1976,10 +2008,25 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) return -EINVAL; } + vmcount = of_property_read_variable_u32_array(rdev->of_node, + "qcom,vmids", &vmids[0], 0, FASTRPC_MAX_VMIDS); + if (vmcount < 0) + vmcount = 0; + else if (!qcom_scm_is_available()) + return -EPROBE_DEFER; + data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; + if (vmcount) { + data->vmcount = vmcount; + data->perms = BIT(QCOM_SCM_VMID_HLOS); + for (i = 0; i < data->vmcount; i++) { + data->vmperms[i].vmid = vmids[i]; + data->vmperms[i].perm = QCOM_SCM_PERM_RWX; + } + } secure_dsp = !(of_property_read_bool(rdev->of_node, "qcom,non-secure-domain")); data->secure = secure_dsp; diff --git a/include/uapi/misc/fastrpc.h b/include/uapi/misc/fastrpc.h index f39edac20305..5e29f2cfa42d 100644 --- a/include/uapi/misc/fastrpc.h +++ b/include/uapi/misc/fastrpc.h @@ -63,11 +63,14 @@ enum fastrpc_proc_attr { FASTRPC_MODE_PRIVILEGED = (1 << 6), }; +/* Fastrpc attribute for memory protection of buffers */ +#define FASTRPC_ATTR_SECUREMAP (1) + struct fastrpc_invoke_args { __u64 ptr; __u64 length; __s32 fd; - __u32 reserved; + __u32 attr; }; struct fastrpc_invoke { -- cgit v1.3.1 From 54f7c85be3d321b4309bf93ed34f3093d24a5518 Mon Sep 17 00:00:00 2001 From: Vamsi Krishna Gattupalli Date: Mon, 14 Feb 2022 16:09:59 +0000 Subject: misc: fastrpc: Add helper function to get list and page Add helper functions to get invoke buffer and page start pointers. Signed-off-by: Vamsi Krishna Gattupalli Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220214161002.6831-10-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index ae7586d7956f..2cf6286bb717 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -833,6 +833,16 @@ static int fastrpc_create_maps(struct fastrpc_invoke_ctx *ctx) return 0; } +static struct fastrpc_invoke_buf *fastrpc_invoke_buf_start(union fastrpc_remote_arg *pra, int len) +{ + return (struct fastrpc_invoke_buf *)(&pra[len]); +} + +static struct fastrpc_phy_page *fastrpc_phy_page_start(struct fastrpc_invoke_buf *buf, int len) +{ + return (struct fastrpc_phy_page *)(&buf[len]); +} + static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx) { struct device *dev = ctx->fl->sctx->dev; @@ -860,9 +870,8 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx) return err; rpra = ctx->buf->virt; - list = ctx->buf->virt + ctx->nscalars * sizeof(*rpra); - pages = ctx->buf->virt + ctx->nscalars * (sizeof(*list) + - sizeof(*rpra)); + list = fastrpc_invoke_buf_start(rpra, ctx->nscalars); + pages = fastrpc_phy_page_start(list, ctx->nscalars); args = (uintptr_t)ctx->buf->virt + metalen; rlen = pkt_size - metalen; ctx->rpra = rpra; -- cgit v1.3.1 From 8f6c1d8c4f0cc316b0456788fff8373554d1d99d Mon Sep 17 00:00:00 2001 From: Vamsi Krishna Gattupalli Date: Mon, 14 Feb 2022 16:10:00 +0000 Subject: misc: fastrpc: Add fdlist implementation Add fdlist implementation to support dma handles. fdlist is populated by DSP if any map is no longer used and it is freed during put_args. Signed-off-by: Vamsi Krishna Gattupalli Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220214161002.6831-11-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 2cf6286bb717..e11b790ce526 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -320,7 +320,8 @@ static void fastrpc_map_get(struct fastrpc_map *map) kref_get(&map->refcount); } -static int fastrpc_map_find(struct fastrpc_user *fl, int fd, + +static int fastrpc_map_lookup(struct fastrpc_user *fl, int fd, struct fastrpc_map **ppmap) { struct fastrpc_map *map = NULL; @@ -328,7 +329,6 @@ static int fastrpc_map_find(struct fastrpc_user *fl, int fd, mutex_lock(&fl->mutex); list_for_each_entry(map, &fl->maps, node) { if (map->fd == fd) { - fastrpc_map_get(map); *ppmap = map; mutex_unlock(&fl->mutex); return 0; @@ -339,6 +339,17 @@ static int fastrpc_map_find(struct fastrpc_user *fl, int fd, return -ENOENT; } +static int fastrpc_map_find(struct fastrpc_user *fl, int fd, + struct fastrpc_map **ppmap) +{ + int ret = fastrpc_map_lookup(fl, fd, ppmap); + + if (!ret) + fastrpc_map_get(*ppmap); + + return ret; +} + static void fastrpc_buf_free(struct fastrpc_buf *buf) { dma_free_coherent(buf->dev, buf->size, buf->virt, @@ -411,7 +422,7 @@ static void fastrpc_context_free(struct kref *ref) ctx = container_of(ref, struct fastrpc_invoke_ctx, refcount); cctx = ctx->cctx; - for (i = 0; i < ctx->nscalars; i++) + for (i = 0; i < ctx->nbufs; i++) fastrpc_map_put(ctx->maps[i]); if (ctx->buf) @@ -969,9 +980,19 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx, u32 kernel) { struct fastrpc_remote_arg *rpra = ctx->rpra; - int i, inbufs; + struct fastrpc_user *fl = ctx->fl; + struct fastrpc_map *mmap = NULL; + struct fastrpc_invoke_buf *list; + struct fastrpc_phy_page *pages; + u64 *fdlist; + int i, inbufs, outbufs, handles; inbufs = REMOTE_SCALARS_INBUFS(ctx->sc); + outbufs = REMOTE_SCALARS_OUTBUFS(ctx->sc); + handles = REMOTE_SCALARS_INHANDLES(ctx->sc) + REMOTE_SCALARS_OUTHANDLES(ctx->sc); + list = fastrpc_invoke_buf_start(rpra, ctx->nscalars); + pages = fastrpc_phy_page_start(list, ctx->nscalars); + fdlist = (uint64_t *)(pages + inbufs + outbufs + handles); for (i = inbufs; i < ctx->nbufs; ++i) { if (!ctx->maps[i]) { @@ -988,6 +1009,13 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx, } } + for (i = 0; i < FASTRPC_MAX_FDLIST; i++) { + if (!fdlist[i]) + break; + if (!fastrpc_map_lookup(fl, (int)fdlist[i], &mmap)) + fastrpc_map_put(mmap); + } + return 0; } -- cgit v1.3.1 From 35a82b87135def531f4ff3c07ba8171fe1794c9d Mon Sep 17 00:00:00 2001 From: Vamsi Krishna Gattupalli Date: Mon, 14 Feb 2022 16:10:01 +0000 Subject: misc: fastrpc: Add dma handle implementation The remote arguments carry both remote buffers and dma handles. Add proper dma handle instructions to make it compatible with DSP implementation. Signed-off-by: Vamsi Krishna Gattupalli Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20220214161002.6831-12-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/fastrpc.c | 52 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 19 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index e11b790ce526..ae32781101e2 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -101,9 +101,20 @@ struct fastrpc_invoke_buf { u32 pgidx; /* index to start of contiguous region */ }; -struct fastrpc_remote_arg { - u64 pv; - u64 len; +struct fastrpc_remote_dmahandle { + s32 fd; /* dma handle fd */ + u32 offset; /* dma handle offset */ + u32 len; /* dma handle length */ +}; + +struct fastrpc_remote_buf { + u64 pv; /* buffer pointer */ + u64 len; /* length of buffer */ +}; + +union fastrpc_remote_arg { + struct fastrpc_remote_buf buf; + struct fastrpc_remote_dmahandle dma; }; struct fastrpc_mmap_rsp_msg { @@ -217,7 +228,7 @@ struct fastrpc_invoke_ctx { struct work_struct put_work; struct fastrpc_msg msg; struct fastrpc_user *fl; - struct fastrpc_remote_arg *rpra; + union fastrpc_remote_arg *rpra; struct fastrpc_map **maps; struct fastrpc_buf *buf; struct fastrpc_invoke_args *args; @@ -767,7 +778,7 @@ get_err: * >>>>>> START of METADATA <<<<<<<<< * +---------------------------------+ * | Arguments | - * | type:(struct fastrpc_remote_arg)| + * | type:(union fastrpc_remote_arg)| * | (0 - N) | * +---------------------------------+ * | Invoke Buffer list | @@ -792,7 +803,7 @@ static int fastrpc_get_meta_size(struct fastrpc_invoke_ctx *ctx) { int size = 0; - size = (sizeof(struct fastrpc_remote_arg) + + size = (sizeof(struct fastrpc_remote_buf) + sizeof(struct fastrpc_invoke_buf) + sizeof(struct fastrpc_phy_page)) * ctx->nscalars + sizeof(u64) * FASTRPC_MAX_FDLIST + @@ -857,7 +868,7 @@ static struct fastrpc_phy_page *fastrpc_phy_page_start(struct fastrpc_invoke_buf static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx) { struct device *dev = ctx->fl->sctx->dev; - struct fastrpc_remote_arg *rpra; + union fastrpc_remote_arg *rpra; struct fastrpc_invoke_buf *list; struct fastrpc_phy_page *pages; int inbufs, i, oix, err = 0; @@ -893,8 +904,8 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx) i = ctx->olaps[oix].raix; len = ctx->args[i].length; - rpra[i].pv = 0; - rpra[i].len = len; + rpra[i].buf.pv = 0; + rpra[i].buf.len = len; list[i].num = len ? 1 : 0; list[i].pgidx = i; @@ -904,7 +915,7 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx) if (ctx->maps[i]) { struct vm_area_struct *vma = NULL; - rpra[i].pv = (u64) ctx->args[i].ptr; + rpra[i].buf.pv = (u64) ctx->args[i].ptr; pages[i].addr = ctx->maps[i]->phys; mmap_read_lock(current->mm); @@ -931,7 +942,7 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx) if (rlen < mlen) goto bail; - rpra[i].pv = args - ctx->olaps[oix].offset; + rpra[i].buf.pv = args - ctx->olaps[oix].offset; pages[i].addr = ctx->buf->phys - ctx->olaps[oix].offset + (pkt_size - rlen); @@ -945,7 +956,7 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx) } if (i < inbufs && !ctx->maps[i]) { - void *dst = (void *)(uintptr_t)rpra[i].pv; + void *dst = (void *)(uintptr_t)rpra[i].buf.pv; void *src = (void *)(uintptr_t)ctx->args[i].ptr; if (!kernel) { @@ -961,12 +972,15 @@ static int fastrpc_get_args(u32 kernel, struct fastrpc_invoke_ctx *ctx) } for (i = ctx->nbufs; i < ctx->nscalars; ++i) { - rpra[i].pv = (u64) ctx->args[i].ptr; - rpra[i].len = ctx->args[i].length; list[i].num = ctx->args[i].length ? 1 : 0; list[i].pgidx = i; - pages[i].addr = ctx->maps[i]->phys; - pages[i].size = ctx->maps[i]->size; + if (ctx->maps[i]) { + pages[i].addr = ctx->maps[i]->phys; + pages[i].size = ctx->maps[i]->size; + } + rpra[i].dma.fd = ctx->args[i].fd; + rpra[i].dma.len = ctx->args[i].length; + rpra[i].dma.offset = (u64) ctx->args[i].ptr; } bail: @@ -979,7 +993,7 @@ bail: static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx, u32 kernel) { - struct fastrpc_remote_arg *rpra = ctx->rpra; + union fastrpc_remote_arg *rpra = ctx->rpra; struct fastrpc_user *fl = ctx->fl; struct fastrpc_map *mmap = NULL; struct fastrpc_invoke_buf *list; @@ -996,9 +1010,9 @@ static int fastrpc_put_args(struct fastrpc_invoke_ctx *ctx, for (i = inbufs; i < ctx->nbufs; ++i) { if (!ctx->maps[i]) { - void *src = (void *)(uintptr_t)rpra[i].pv; + void *src = (void *)(uintptr_t)rpra[i].buf.pv; void *dst = (void *)(uintptr_t)ctx->args[i].ptr; - u64 len = rpra[i].len; + u64 len = rpra[i].buf.len; if (!kernel) { if (copy_to_user((void __user *)dst, src, len)) -- cgit v1.3.1 From 96c9e802c64014a7716865332d732cc9c7f24593 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 7 Mar 2022 19:32:55 -0800 Subject: kgdbts: fix return value of __setup handler __setup() handlers should return 1 to indicate that the boot option has been handled. A return of 0 causes the boot option/value to be listed as an Unknown kernel parameter and added to init's (limited) environment strings. So return 1 from kgdbts_option_setup(). Unknown kernel command line parameters "BOOT_IMAGE=/boot/bzImage-517rc7 kgdboc=kbd kgdbts=", will be passed to user space. Run /sbin/init as init process with arguments: /sbin/init with environment: HOME=/ TERM=linux BOOT_IMAGE=/boot/bzImage-517rc7 kgdboc=kbd kgdbts= Link: lore.kernel.org/r/64644a2f-4a20-bab3-1e15-3b2cdd0defe3@omprussia.ru Fixes: e8d31c204e36 ("kgdb: add kgdb internal test suite") Cc: kgdb-bugreport@lists.sourceforge.net Cc: Jason Wessel Cc: Daniel Thompson Cc: Douglas Anderson Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Reported-by: Igor Zhbanov Reviewed-by: Douglas Anderson Signed-off-by: Randy Dunlap Link: https://lore.kernel.org/r/20220308033255.22118-1-rdunlap@infradead.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/kgdbts.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/misc') diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index 67c5b452dd35..88b91ad8e541 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -1070,10 +1070,10 @@ static int kgdbts_option_setup(char *opt) { if (strlen(opt) >= MAX_CONFIG_LEN) { printk(KERN_ERR "kgdbts: config string too long\n"); - return -ENOSPC; + return 1; } strcpy(config, opt); - return 0; + return 1; } __setup("kgdbts=", kgdbts_option_setup); -- cgit v1.3.1