Update Linux kernel release to v7.2.8-5 for base and BORE kernels
Signed-off-by: Krzysztof Wilczyński <kwilczynski@omarchy.org>
This commit is contained in:
325 files changed
+4747
-1308
No files matched your search
@@ -0,0 +1,413 @@
|
||||
diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h
|
||||
--- a/drivers/iommu/amd/amd_iommu.h
|
||||
+++ b/drivers/iommu/amd/amd_iommu.h
|
||||
@@ -48,6 +48,9 @@ extern u8 amd_iommu_hpt_vasize;
|
||||
extern unsigned long amd_iommu_pgsize_bitmap;
|
||||
extern bool amd_iommu_hatdis;
|
||||
|
||||
+int amd_iommu_perfopt_clear(struct amd_iommu *iommu);
|
||||
+int amd_iommu_perfopt_restore(struct amd_iommu *iommu);
|
||||
+
|
||||
/* Protection domain ops */
|
||||
void amd_iommu_init_identity_domain(void);
|
||||
struct protection_domain *protection_domain_alloc(void);
|
||||
diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h
|
||||
--- a/drivers/iommu/amd/amd_iommu_types.h
|
||||
+++ b/drivers/iommu/amd/amd_iommu_types.h
|
||||
@@ -65,6 +65,7 @@
|
||||
#define MMIO_MSI_ADDR_LO_OFFSET 0x015C
|
||||
#define MMIO_MSI_ADDR_HI_OFFSET 0x0160
|
||||
#define MMIO_MSI_DATA_OFFSET 0x0164
|
||||
+#define MMIO_PERF_OPT_OFFSET 0x016C
|
||||
#define MMIO_INTCAPXT_EVT_OFFSET 0x0170
|
||||
#define MMIO_INTCAPXT_PPR_OFFSET 0x0178
|
||||
#define MMIO_INTCAPXT_GALOG_OFFSET 0x0180
|
||||
@@ -99,6 +100,8 @@
|
||||
#define FEATURE_GLX GENMASK_ULL(15, 14)
|
||||
#define FEATURE_GAM_VAPIC BIT_ULL(21)
|
||||
#define FEATURE_PASMAX GENMASK_ULL(36, 32)
|
||||
+#define FEATURE_PERF_OPT BIT_ULL(45)
|
||||
+#define PERF_OPT_EN BIT(13)
|
||||
#define FEATURE_GIOSUP BIT_ULL(48)
|
||||
#define FEATURE_HASUP BIT_ULL(49)
|
||||
#define FEATURE_EPHSUP BIT_ULL(50)
|
||||
@@ -663,6 +666,9 @@ struct amd_iommu {
|
||||
/* Extended features 2 */
|
||||
u64 features2;
|
||||
|
||||
+ /* Devices requesting PerfOpt; the shared PERF_OPT_EN bit is on while >0. Protected by @lock. */
|
||||
+ int perfopt_refcount;
|
||||
+
|
||||
/* PCI device id of the IOMMU device */
|
||||
u16 devid;
|
||||
|
||||
@@ -824,6 +830,7 @@ struct iommu_dev_data {
|
||||
u8 ppr :1; /* Enable device PPR support */
|
||||
bool use_vapic; /* Enable device to use vapic mode */
|
||||
bool defer_attach;
|
||||
+ bool perfopt;
|
||||
|
||||
struct ratelimit_state rs; /* Ratelimit IOPF messages */
|
||||
};
|
||||
diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c
|
||||
--- a/drivers/iommu/amd/init.c
|
||||
+++ b/drivers/iommu/amd/init.c
|
||||
@@ -1945,6 +1945,9 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h,
|
||||
if (!iommu->mmio_base)
|
||||
return -ENOMEM;
|
||||
|
||||
+ if (amd_iommu_perfopt_clear(iommu))
|
||||
+ pr_err("IOMMU%d: failed to clear PerfOpt\n", iommu->index);
|
||||
+
|
||||
return init_iommu_from_acpi(iommu, h);
|
||||
}
|
||||
|
||||
@@ -3035,10 +3038,46 @@ static void enable_iommus_vapic(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
+static int clear_perfopt_all(void)
|
||||
+{
|
||||
+ struct amd_iommu *iommu;
|
||||
+ int err, ret = 0;
|
||||
+
|
||||
+ for_each_iommu(iommu) {
|
||||
+ err = amd_iommu_perfopt_clear(iommu);
|
||||
+ if (err)
|
||||
+ ret = err;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int restore_perfopt_all(void)
|
||||
+{
|
||||
+ struct amd_iommu *iommu;
|
||||
+ int err, ret = 0;
|
||||
+
|
||||
+ for_each_iommu(iommu) {
|
||||
+ err = amd_iommu_perfopt_restore(iommu);
|
||||
+ if (err)
|
||||
+ ret = err;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
static void disable_iommus(void)
|
||||
{
|
||||
struct amd_iommu *iommu;
|
||||
|
||||
+ /*
|
||||
+ * PerfOpt is an optional performance bit, so a failure to clear it must
|
||||
+ * not skip the mandatory disable below. This also runs from the void
|
||||
+ * amd_iommu_disable() shutdown/kexec path, which cannot report an error.
|
||||
+ */
|
||||
+ if (clear_perfopt_all())
|
||||
+ pr_err("Failed to clear PerfOpt while disabling IOMMUs\n");
|
||||
+
|
||||
for_each_iommu(iommu)
|
||||
iommu_disable(iommu);
|
||||
|
||||
@@ -3064,6 +3103,10 @@ static void amd_iommu_resume(void *data)
|
||||
for_each_iommu(iommu)
|
||||
early_enable_iommu(iommu);
|
||||
|
||||
+ /* early_enable_iommu() cleared PERF_OPT_EN; re-assert it from the refcount. */
|
||||
+ if (restore_perfopt_all())
|
||||
+ pr_err("Failed to restore PerfOpt after IOMMU resume\n");
|
||||
+
|
||||
iommu_enable_event_buffer();
|
||||
amd_iommu_enable_interrupts();
|
||||
}
|
||||
diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c
|
||||
--- a/drivers/iommu/amd/iommu.c
|
||||
+++ b/drivers/iommu/amd/iommu.c
|
||||
@@ -2352,6 +2352,9 @@ static int attach_device(struct device *dev,
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
+ if (dev_data->perfopt)
|
||||
+ goto skip_caps;
|
||||
+
|
||||
/* Setup GCR3 table */
|
||||
if (pdom_is_sva_capable(domain)) {
|
||||
ret = init_gcr3_table(dev_data, domain);
|
||||
@@ -2376,6 +2379,7 @@ static int attach_device(struct device *dev,
|
||||
pdev_enable_cap_ats(pdev);
|
||||
}
|
||||
|
||||
+skip_caps:
|
||||
/* Update data structures */
|
||||
dev_data->domain = domain;
|
||||
spin_lock_irqsave(&domain->lock, flags);
|
||||
@@ -2444,6 +2448,192 @@ static void detach_device(struct device *dev)
|
||||
mutex_unlock(&dev_data->mutex);
|
||||
}
|
||||
|
||||
+/* Program the per-IOMMU PerfOpt enable bit. Caller must hold iommu->lock. */
|
||||
+static int __perfopt_write(struct amd_iommu *iommu, bool enable)
|
||||
+{
|
||||
+ u32 old, val, readback;
|
||||
+
|
||||
+ if (!(readq(iommu->mmio_base + MMIO_EXT_FEATURES) & FEATURE_PERF_OPT))
|
||||
+ return enable ? -ENODEV : 0;
|
||||
+
|
||||
+ old = readl(iommu->mmio_base + MMIO_PERF_OPT_OFFSET);
|
||||
+ if (old == U32_MAX)
|
||||
+ return -EIO;
|
||||
+
|
||||
+ val = enable ? old | PERF_OPT_EN : old & ~PERF_OPT_EN;
|
||||
+ if (val != old)
|
||||
+ writel(val, iommu->mmio_base + MMIO_PERF_OPT_OFFSET);
|
||||
+ readback = readl(iommu->mmio_base + MMIO_PERF_OPT_OFFSET);
|
||||
+ if (readback == U32_MAX ||
|
||||
+ (readback & PERF_OPT_EN) != (val & PERF_OPT_EN))
|
||||
+ return -EIO;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * PERF_OPT_EN is a single bit shared by every device behind @iommu, so it is
|
||||
+ * reference counted: armed on the first requesting device, cleared on the last.
|
||||
+ */
|
||||
+static int perfopt_get(struct amd_iommu *iommu)
|
||||
+{
|
||||
+ unsigned long flags;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (!iommu->mmio_base)
|
||||
+ return 0;
|
||||
+
|
||||
+ raw_spin_lock_irqsave(&iommu->lock, flags);
|
||||
+ if (iommu->perfopt_refcount == 0) {
|
||||
+ ret = __perfopt_write(iommu, true);
|
||||
+ if (ret)
|
||||
+ goto out;
|
||||
+ }
|
||||
+ iommu->perfopt_refcount++;
|
||||
+out:
|
||||
+ raw_spin_unlock_irqrestore(&iommu->lock, flags);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int perfopt_put(struct amd_iommu *iommu)
|
||||
+{
|
||||
+ unsigned long flags;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (!iommu->mmio_base)
|
||||
+ return 0;
|
||||
+
|
||||
+ raw_spin_lock_irqsave(&iommu->lock, flags);
|
||||
+ if (iommu->perfopt_refcount > 0 && --iommu->perfopt_refcount == 0)
|
||||
+ ret = __perfopt_write(iommu, false);
|
||||
+ raw_spin_unlock_irqrestore(&iommu->lock, flags);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Force PERF_OPT_EN off without touching the refcount (used on init, shutdown,
|
||||
+ * and suspend). The count is preserved so amd_iommu_perfopt_restore() can
|
||||
+ * re-arm on resume.
|
||||
+ */
|
||||
+int amd_iommu_perfopt_clear(struct amd_iommu *iommu)
|
||||
+{
|
||||
+ unsigned long flags;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (!iommu->mmio_base)
|
||||
+ return 0;
|
||||
+
|
||||
+ raw_spin_lock_irqsave(&iommu->lock, flags);
|
||||
+ ret = __perfopt_write(iommu, false);
|
||||
+ raw_spin_unlock_irqrestore(&iommu->lock, flags);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Re-assert PERF_OPT_EN from the refcount after the hardware was reprogrammed on
|
||||
+ * resume, so devices armed before suspend keep the optimization without each
|
||||
+ * consumer driver re-arming.
|
||||
+ */
|
||||
+int amd_iommu_perfopt_restore(struct amd_iommu *iommu)
|
||||
+{
|
||||
+ unsigned long flags;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (!iommu->mmio_base)
|
||||
+ return 0;
|
||||
+
|
||||
+ raw_spin_lock_irqsave(&iommu->lock, flags);
|
||||
+ ret = __perfopt_write(iommu, iommu->perfopt_refcount > 0);
|
||||
+ raw_spin_unlock_irqrestore(&iommu->lock, flags);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+int amd_iommu_enable_perfopt(struct pci_dev *pdev)
|
||||
+{
|
||||
+ struct iommu_dev_data *dev_data = dev_iommu_priv_get(&pdev->dev);
|
||||
+ struct amd_iommu *iommu = rlookup_amd_iommu(&pdev->dev);
|
||||
+ struct protection_domain *domain;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (!iommu || !dev_data)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ if (!(iommu->features & FEATURE_PERF_OPT))
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ domain = dev_data->domain;
|
||||
+ if (!domain)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ /* Already armed for this device (e.g. re-entry on resume). */
|
||||
+ if (dev_data->perfopt)
|
||||
+ return 0;
|
||||
+
|
||||
+ /*
|
||||
+ * The bit is only architecturally valid while the device is untranslated:
|
||||
+ * identity domain with ATS/PRI/PASID off. The identity domain is
|
||||
+ * SVA-capable so attach_device() enabled ATS/PRI/PASID and built a GCR3
|
||||
+ * table. Re-home the device onto the same identity domain with
|
||||
+ * perfopt set, so the attach_device() skip_caps path leaves
|
||||
+ * ATS/PRI/PASID off and no GCR3 table. This follows the detach/attach
|
||||
+ * pattern used by amd_iommu_attach_device().
|
||||
+ *
|
||||
+ * Locking: this and amd_iommu_disable_perfopt() run only from the
|
||||
+ * consumer driver's bind/unbind path. group->mutex is not exposed to
|
||||
+ * drivers, but a device bound to its native driver cannot have its domain
|
||||
+ * changed concurrently by the core (VFIO ownership is mutually exclusive;
|
||||
+ * sysfs domain changes require an unused group), so the detach/attach pair
|
||||
+ * is serialized without it.
|
||||
+ */
|
||||
+ dev_data->perfopt = true;
|
||||
+ detach_device(&pdev->dev);
|
||||
+ ret = attach_device(&pdev->dev, domain);
|
||||
+ if (ret)
|
||||
+ goto err_restore;
|
||||
+
|
||||
+ ret = perfopt_get(iommu);
|
||||
+ if (ret)
|
||||
+ goto err_rearm;
|
||||
+
|
||||
+ dev_info_once(&pdev->dev, "PerfOpt armed on IOMMU%d\n", iommu->index);
|
||||
+ return 0;
|
||||
+
|
||||
+err_rearm:
|
||||
+ detach_device(&pdev->dev);
|
||||
+err_restore:
|
||||
+ dev_data->perfopt = false;
|
||||
+ if (attach_device(&pdev->dev, domain))
|
||||
+ pci_err(pdev, "failed to restore state after PerfOpt setup; device left detached\n");
|
||||
+ dev_err_once(&pdev->dev, "PerfOpt failed to arm on IOMMU%d (%d)\n",
|
||||
+ iommu->index, ret);
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(amd_iommu_enable_perfopt);
|
||||
+
|
||||
+void amd_iommu_disable_perfopt(struct pci_dev *pdev)
|
||||
+{
|
||||
+ struct iommu_dev_data *dev_data = dev_iommu_priv_get(&pdev->dev);
|
||||
+ struct amd_iommu *iommu = rlookup_amd_iommu(&pdev->dev);
|
||||
+ struct protection_domain *domain;
|
||||
+
|
||||
+ if (!iommu || !dev_data || !dev_data->perfopt || !dev_data->domain)
|
||||
+ return;
|
||||
+
|
||||
+ if (WARN_ON(perfopt_put(iommu)))
|
||||
+ pci_err(pdev, "failed to clear PerfOpt\n");
|
||||
+
|
||||
+ /*
|
||||
+ * Restore ATS/PRI/PASID (and thus SVA) by re-homing the device onto its
|
||||
+ * identity domain with the flag cleared, so a later bind without PerfOpt
|
||||
+ * sees a normally-capable device. See the locking note in
|
||||
+ * amd_iommu_enable_perfopt().
|
||||
+ */
|
||||
+ domain = dev_data->domain;
|
||||
+ dev_data->perfopt = false;
|
||||
+ detach_device(&pdev->dev);
|
||||
+ if (attach_device(&pdev->dev, domain))
|
||||
+ pci_err(pdev, "failed to restore caps after PerfOpt disable\n");
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(amd_iommu_disable_perfopt);
|
||||
static struct iommu_device *amd_iommu_probe_device(struct device *dev)
|
||||
{
|
||||
struct iommu_device *iommu_dev;
|
||||
@@ -2511,6 +2701,14 @@ static struct iommu_device *amd_iommu_probe_device(struct device *dev)
|
||||
static void amd_iommu_release_device(struct device *dev)
|
||||
{
|
||||
struct iommu_dev_data *dev_data = dev_iommu_priv_get(dev);
|
||||
+ struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data);
|
||||
+
|
||||
+ if (dev_data->perfopt) {
|
||||
+ if (WARN_ON(perfopt_put(iommu)))
|
||||
+ dev_err(dev, "IOMMU%d: failed to clear PerfOpt on release\n",
|
||||
+ iommu->index);
|
||||
+ dev_data->perfopt = false;
|
||||
+ }
|
||||
|
||||
WARN_ON(dev_data->domain);
|
||||
|
||||
@@ -2885,6 +3083,19 @@ static int blocked_domain_attach_device(struct iommu_domain *domain,
|
||||
struct iommu_domain *old)
|
||||
{
|
||||
struct iommu_dev_data *dev_data = dev_iommu_priv_get(dev);
|
||||
+ struct amd_iommu *iommu = get_amd_iommu_from_dev_data(dev_data);
|
||||
+
|
||||
+ /*
|
||||
+ * blocked_domain is also the .release_domain, so this is the normal
|
||||
+ * teardown path: drop the reference and clear the flag here too, and
|
||||
+ * don't fail teardown if the WARN-guarded write doesn't stick.
|
||||
+ */
|
||||
+ if (dev_data->perfopt) {
|
||||
+ if (WARN_ON(perfopt_put(iommu)))
|
||||
+ dev_err(dev, "IOMMU%d: failed to clear PerfOpt for blocked domain\n",
|
||||
+ iommu->index);
|
||||
+ dev_data->perfopt = false;
|
||||
+ }
|
||||
|
||||
if (dev_data->domain)
|
||||
detach_device(dev);
|
||||
@@ -2953,6 +3164,9 @@ static int amd_iommu_attach_device(struct iommu_domain *dom, struct device *dev,
|
||||
struct amd_iommu *iommu = get_amd_iommu_from_dev(dev);
|
||||
int ret;
|
||||
|
||||
+ if (dev_data->perfopt && !pdom_is_in_pt_mode(domain))
|
||||
+ return -EBUSY;
|
||||
+
|
||||
/*
|
||||
* Skip attach device to domain if new domain is same as
|
||||
* devices current domain
|
||||
diff --git a/include/linux/amd-iommu.h b/include/linux/amd-iommu.h
|
||||
--- a/include/linux/amd-iommu.h
|
||||
+++ b/include/linux/amd-iommu.h
|
||||
@@ -11,11 +11,11 @@
|
||||
#include <linux/types.h>
|
||||
|
||||
struct amd_iommu;
|
||||
+struct pci_dev;
|
||||
|
||||
#ifdef CONFIG_AMD_IOMMU
|
||||
|
||||
struct task_struct;
|
||||
-struct pci_dev;
|
||||
|
||||
extern void amd_iommu_detect(void);
|
||||
|
||||
@@ -76,4 +76,15 @@ static inline int amd_iommu_snp_disable(void) { return 0; }
|
||||
static inline bool amd_iommu_sev_tio_supported(void) { return false; }
|
||||
#endif
|
||||
|
||||
+#ifdef CONFIG_AMD_IOMMU
|
||||
+int amd_iommu_enable_perfopt(struct pci_dev *pdev);
|
||||
+void amd_iommu_disable_perfopt(struct pci_dev *pdev);
|
||||
+#else
|
||||
+static inline int amd_iommu_enable_perfopt(struct pci_dev *pdev)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+static inline void amd_iommu_disable_perfopt(struct pci_dev *pdev) { }
|
||||
+#endif
|
||||
+
|
||||
#endif /* _ASM_X86_AMD_IOMMU_H */
|
||||
Binary file not shown.
@@ -0,0 +1,128 @@
|
||||
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
|
||||
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
|
||||
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
|
||||
@@ -160,6 +160,7 @@ struct amdgpu_watchdog_timer {
|
||||
* Modules parameters.
|
||||
*/
|
||||
extern int amdgpu_modeset;
|
||||
+extern int amdgpu_iommu_perfopt;
|
||||
extern unsigned int amdgpu_vram_limit;
|
||||
extern int amdgpu_vis_vram_limit;
|
||||
extern int amdgpu_gart_size;
|
||||
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
|
||||
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
|
||||
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <linux/console.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/iommu.h>
|
||||
+#include <linux/amd-iommu.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pci-p2pdma.h>
|
||||
#include <linux/apple-gmux.h>
|
||||
@@ -3842,6 +3843,28 @@ amdgpu_device_should_register_switcheroo(struct amdgpu_device *adev, bool px)
|
||||
apple_gmux_detect(NULL, NULL)));
|
||||
}
|
||||
|
||||
+static inline bool amdgpu_device_identity(struct amdgpu_device *adev)
|
||||
+{
|
||||
+ struct pci_dev *pdev = adev->pdev;
|
||||
+ struct iommu_domain *domain = iommu_get_domain_for_dev(&pdev->dev);
|
||||
+
|
||||
+ if (!domain)
|
||||
+ return false;
|
||||
+
|
||||
+ return domain->type == IOMMU_DOMAIN_IDENTITY;
|
||||
+}
|
||||
+
|
||||
+static bool amdgpu_device_use_perfopt(struct amdgpu_device *adev)
|
||||
+{
|
||||
+ if (amdgpu_iommu_perfopt == 0)
|
||||
+ return false;
|
||||
+
|
||||
+ if (!(adev->flags & AMD_IS_APU))
|
||||
+ return false;
|
||||
+
|
||||
+ return amdgpu_device_identity(adev);
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* amdgpu_device_init - initialize the driver
|
||||
*
|
||||
@@ -4048,6 +4071,16 @@ int amdgpu_device_init(struct amdgpu_device *adev,
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
+ if (amdgpu_device_use_perfopt(adev)) {
|
||||
+ int perfopt_ret = amd_iommu_enable_perfopt(pdev);
|
||||
+
|
||||
+ /* Optional optimization; a failure to arm it must not abort probe. */
|
||||
+ if (perfopt_ret)
|
||||
+ dev_warn(adev->dev,
|
||||
+ "Failed to enable IOMMU PerfOpt (%d); continuing without it\n",
|
||||
+ perfopt_ret);
|
||||
+ }
|
||||
+
|
||||
/*
|
||||
* No need to remove conflicting FBs for non-display class devices.
|
||||
* This prevents the sysfb from being freed accidently.
|
||||
@@ -4416,6 +4449,9 @@ void amdgpu_device_fini_hw(struct amdgpu_device *adev)
|
||||
|
||||
amdgpu_gart_dummy_page_fini(adev);
|
||||
|
||||
+ if (amdgpu_device_use_perfopt(adev))
|
||||
+ amd_iommu_disable_perfopt(adev->pdev);
|
||||
+
|
||||
if (pci_dev_is_disconnected(adev->pdev))
|
||||
amdgpu_device_unmap_mmio(adev);
|
||||
|
||||
@@ -4779,6 +4815,20 @@ int amdgpu_device_resume(struct drm_device *dev, bool notify_clients)
|
||||
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
|
||||
return 0;
|
||||
|
||||
+ if (amdgpu_device_use_perfopt(adev)) {
|
||||
+ int perfopt_ret = amd_iommu_enable_perfopt(adev->pdev);
|
||||
+
|
||||
+ /*
|
||||
+ * Must not return on failure: a bare return would leak the
|
||||
+ * SR-IOV VF exclusive-mode acquisition taken above (released
|
||||
+ * via the exit: path).
|
||||
+ */
|
||||
+ if (perfopt_ret)
|
||||
+ dev_warn(adev->dev,
|
||||
+ "Failed to enable IOMMU PerfOpt (%d); continuing without it\n",
|
||||
+ perfopt_ret);
|
||||
+ }
|
||||
+
|
||||
if (adev->in_s0ix)
|
||||
amdgpu_dpm_gfx_state_change(adev, sGpuChangeState_D0Entry);
|
||||
|
||||
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
|
||||
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
|
||||
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
|
||||
@@ -185,6 +185,7 @@ char *amdgpu_disable_cu;
|
||||
char *amdgpu_virtual_display;
|
||||
int amdgpu_enforce_isolation = -1;
|
||||
int amdgpu_modeset = -1;
|
||||
+int amdgpu_iommu_perfopt = -1;
|
||||
|
||||
/* Specifies the default granularity for SVM, used in buffer
|
||||
* migration and restoration of backing memory when handling
|
||||
@@ -393,6 +394,17 @@ module_param_named(fw_load_type, amdgpu_fw_load_type, int, 0444);
|
||||
MODULE_PARM_DESC(aspm, "ASPM support (1 = enable, 0 = disable, -1 = auto)");
|
||||
module_param_named(aspm, amdgpu_aspm, int, 0444);
|
||||
|
||||
+/**
|
||||
+ * DOC: iommu_perfopt (int)
|
||||
+ * Control the AMD IOMMU PerfOpt DMA-latency optimization
|
||||
+ * (0 = disable; -1 = enable on supported devices).
|
||||
+ * This arms the IOMMU PerfOpt control (IOMMU spec, MMIO Offset 016Ch, EFR PerfOptSup / PerfOptEn)
|
||||
+ * Arming it disables ATS, PRI, PASID and SVA for the GPU and removes IOMMU DMA containment for it,
|
||||
+ * trading isolation for lower DMA latency.
|
||||
+ */
|
||||
+MODULE_PARM_DESC(iommu_perfopt, "Control IOMMU PerfOpt DMA-latency optimization (-1 = enable on supported devices, 0 = disable)");
|
||||
+module_param_named(iommu_perfopt, amdgpu_iommu_perfopt, int, 0444);
|
||||
+
|
||||
/**
|
||||
* DOC: runpm (int)
|
||||
* Override for runtime power management control for dGPUs. The amdgpu driver can dynamically power down
|
||||
Binary file not shown.
@@ -0,0 +1,412 @@
|
||||
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
|
||||
--- a/drivers/acpi/battery.c
|
||||
+++ b/drivers/acpi/battery.c
|
||||
@@ -736,7 +736,7 @@ static LIST_HEAD(acpi_battery_list);
|
||||
static LIST_HEAD(battery_hook_list);
|
||||
static DEFINE_MUTEX(hook_mutex);
|
||||
|
||||
-static void battery_hook_unregister_unlocked(struct acpi_battery_hook *hook)
|
||||
+static void acpi_battery_hook_unregister_unlocked(struct acpi_battery_hook *hook)
|
||||
{
|
||||
struct acpi_battery *battery;
|
||||
|
||||
@@ -753,7 +753,7 @@ static void battery_hook_unregister_unlocked(struct acpi_battery_hook *hook)
|
||||
pr_info("hook unregistered: %s\n", hook->name);
|
||||
}
|
||||
|
||||
-void battery_hook_unregister(struct acpi_battery_hook *hook)
|
||||
+void acpi_battery_hook_unregister(struct acpi_battery_hook *hook)
|
||||
{
|
||||
mutex_lock(&hook_mutex);
|
||||
/*
|
||||
@@ -762,13 +762,13 @@ void battery_hook_unregister(struct acpi_battery_hook *hook)
|
||||
* adding a new battery.
|
||||
*/
|
||||
if (!list_empty(&hook->list))
|
||||
- battery_hook_unregister_unlocked(hook);
|
||||
+ acpi_battery_hook_unregister_unlocked(hook);
|
||||
|
||||
mutex_unlock(&hook_mutex);
|
||||
}
|
||||
-EXPORT_SYMBOL_GPL(battery_hook_unregister);
|
||||
+EXPORT_SYMBOL_GPL(acpi_battery_hook_unregister);
|
||||
|
||||
-void battery_hook_register(struct acpi_battery_hook *hook)
|
||||
+void acpi_battery_hook_register(struct acpi_battery_hook *hook)
|
||||
{
|
||||
struct acpi_battery *battery;
|
||||
|
||||
@@ -789,7 +789,7 @@ void battery_hook_register(struct acpi_battery_hook *hook)
|
||||
* hooks.
|
||||
*/
|
||||
pr_err("hook failed to load: %s", hook->name);
|
||||
- battery_hook_unregister_unlocked(hook);
|
||||
+ acpi_battery_hook_unregister_unlocked(hook);
|
||||
goto end;
|
||||
}
|
||||
|
||||
@@ -799,22 +799,22 @@ void battery_hook_register(struct acpi_battery_hook *hook)
|
||||
end:
|
||||
mutex_unlock(&hook_mutex);
|
||||
}
|
||||
-EXPORT_SYMBOL_GPL(battery_hook_register);
|
||||
+EXPORT_SYMBOL_GPL(acpi_battery_hook_register);
|
||||
|
||||
-static void devm_battery_hook_unregister(void *data)
|
||||
+static void devm_acpi_battery_hook_unregister(void *data)
|
||||
{
|
||||
struct acpi_battery_hook *hook = data;
|
||||
|
||||
- battery_hook_unregister(hook);
|
||||
+ acpi_battery_hook_unregister(hook);
|
||||
}
|
||||
|
||||
-int devm_battery_hook_register(struct device *dev, struct acpi_battery_hook *hook)
|
||||
+int devm_acpi_battery_hook_register(struct device *dev, struct acpi_battery_hook *hook)
|
||||
{
|
||||
- battery_hook_register(hook);
|
||||
+ acpi_battery_hook_register(hook);
|
||||
|
||||
- return devm_add_action_or_reset(dev, devm_battery_hook_unregister, hook);
|
||||
+ return devm_add_action_or_reset(dev, devm_acpi_battery_hook_unregister, hook);
|
||||
}
|
||||
-EXPORT_SYMBOL_GPL(devm_battery_hook_register);
|
||||
+EXPORT_SYMBOL_GPL(devm_acpi_battery_hook_register);
|
||||
|
||||
/*
|
||||
* This function gets called right after the battery sysfs
|
||||
@@ -843,7 +843,7 @@ static void battery_hook_add_battery(struct acpi_battery *battery)
|
||||
*/
|
||||
pr_err("error in hook, unloading: %s",
|
||||
hook_node->name);
|
||||
- battery_hook_unregister_unlocked(hook_node);
|
||||
+ acpi_battery_hook_unregister_unlocked(hook_node);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&hook_mutex);
|
||||
@@ -876,7 +876,7 @@ static void __exit battery_hook_exit(void)
|
||||
* need to remove the hooks.
|
||||
*/
|
||||
list_for_each_entry_safe(hook, ptr, &battery_hook_list, list) {
|
||||
- battery_hook_unregister(hook);
|
||||
+ acpi_battery_hook_unregister(hook);
|
||||
}
|
||||
mutex_destroy(&hook_mutex);
|
||||
}
|
||||
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
|
||||
--- a/drivers/platform/x86/asus-wmi.c
|
||||
+++ b/drivers/platform/x86/asus-wmi.c
|
||||
@@ -1681,14 +1681,14 @@ static void asus_wmi_battery_init(struct asus_wmi *asus)
|
||||
asus->battery_rsoc_available = false;
|
||||
if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_RSOC)) {
|
||||
asus->battery_rsoc_available = true;
|
||||
- battery_hook_register(&battery_hook);
|
||||
+ acpi_battery_hook_register(&battery_hook);
|
||||
}
|
||||
}
|
||||
|
||||
static void asus_wmi_battery_exit(struct asus_wmi *asus)
|
||||
{
|
||||
if (asus->battery_rsoc_available)
|
||||
- battery_hook_unregister(&battery_hook);
|
||||
+ acpi_battery_hook_unregister(&battery_hook);
|
||||
}
|
||||
|
||||
/* LEDs ***********************************************************************/
|
||||
diff --git a/drivers/platform/x86/ayaneo-ec.c b/drivers/platform/x86/ayaneo-ec.c
|
||||
--- a/drivers/platform/x86/ayaneo-ec.c
|
||||
+++ b/drivers/platform/x86/ayaneo-ec.c
|
||||
@@ -493,7 +493,7 @@ static int ayaneo_ec_probe(struct platform_device *pdev)
|
||||
data->battery_hook.add_battery = ayaneo_add_battery;
|
||||
data->battery_hook.remove_battery = ayaneo_remove_battery;
|
||||
data->battery_hook.name = "Ayaneo Battery";
|
||||
- ret = devm_battery_hook_register(&pdev->dev, &data->battery_hook);
|
||||
+ ret = devm_acpi_battery_hook_register(&pdev->dev, &data->battery_hook);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
diff --git a/drivers/platform/x86/dell/dell-laptop.c b/drivers/platform/x86/dell/dell-laptop.c
|
||||
--- a/drivers/platform/x86/dell/dell-laptop.c
|
||||
+++ b/drivers/platform/x86/dell/dell-laptop.c
|
||||
@@ -2446,13 +2446,13 @@ static void __init dell_battery_init(struct device *dev)
|
||||
battery_supported_modes = battery_get_supported_modes();
|
||||
|
||||
if (battery_supported_modes != 0)
|
||||
- battery_hook_register(&dell_battery_hook);
|
||||
+ acpi_battery_hook_register(&dell_battery_hook);
|
||||
}
|
||||
|
||||
static void dell_battery_exit(void)
|
||||
{
|
||||
if (battery_supported_modes != 0)
|
||||
- battery_hook_unregister(&dell_battery_hook);
|
||||
+ acpi_battery_hook_unregister(&dell_battery_hook);
|
||||
}
|
||||
|
||||
static int __init dell_init(void)
|
||||
diff --git a/drivers/platform/x86/dell/dell-wmi-ddv.c b/drivers/platform/x86/dell/dell-wmi-ddv.c
|
||||
--- a/drivers/platform/x86/dell/dell-wmi-ddv.c
|
||||
+++ b/drivers/platform/x86/dell/dell-wmi-ddv.c
|
||||
@@ -972,7 +972,7 @@ static int dell_wmi_ddv_battery_add(struct dell_wmi_ddv_data *data)
|
||||
data->eppid_attr.attr.mode = 0444;
|
||||
data->eppid_attr.show = eppid_show;
|
||||
|
||||
- return devm_battery_hook_register(&data->wdev->dev, &data->hook);
|
||||
+ return devm_acpi_battery_hook_register(&data->wdev->dev, &data->hook);
|
||||
}
|
||||
|
||||
static int dell_wmi_ddv_buffer_read(struct seq_file *seq, enum dell_ddv_method method)
|
||||
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
|
||||
--- a/drivers/platform/x86/fujitsu-laptop.c
|
||||
+++ b/drivers/platform/x86/fujitsu-laptop.c
|
||||
@@ -267,7 +267,7 @@ static int fujitsu_battery_charge_control_add(struct device *dev)
|
||||
return -ENODEV;
|
||||
|
||||
priv->charge_control_supported = true;
|
||||
- battery_hook_register(&battery_hook);
|
||||
+ acpi_battery_hook_register(&battery_hook);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -277,7 +277,7 @@ static void fujitsu_battery_charge_control_remove(struct device *dev)
|
||||
struct fujitsu_laptop *priv = dev_get_drvdata(dev);
|
||||
|
||||
if (priv->charge_control_supported)
|
||||
- battery_hook_unregister(&battery_hook);
|
||||
+ acpi_battery_hook_unregister(&battery_hook);
|
||||
}
|
||||
|
||||
/* Hardware access for LCD brightness control */
|
||||
diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c
|
||||
--- a/drivers/platform/x86/huawei-wmi.c
|
||||
+++ b/drivers/platform/x86/huawei-wmi.c
|
||||
@@ -512,7 +512,7 @@ static void huawei_wmi_battery_setup(struct device *dev)
|
||||
return;
|
||||
}
|
||||
|
||||
- battery_hook_register(&huawei_wmi_battery_hook);
|
||||
+ acpi_battery_hook_register(&huawei_wmi_battery_hook);
|
||||
device_create_file(dev, &dev_attr_charge_control_thresholds);
|
||||
}
|
||||
|
||||
@@ -521,7 +521,7 @@ static void huawei_wmi_battery_exit(struct device *dev)
|
||||
struct huawei_wmi *huawei = dev_get_drvdata(dev);
|
||||
|
||||
if (huawei->battery_available) {
|
||||
- battery_hook_unregister(&huawei_wmi_battery_hook);
|
||||
+ acpi_battery_hook_unregister(&huawei_wmi_battery_hook);
|
||||
device_remove_file(dev, &dev_attr_charge_control_thresholds);
|
||||
}
|
||||
}
|
||||
diff --git a/drivers/platform/x86/lenovo/ideapad-laptop.c b/drivers/platform/x86/lenovo/ideapad-laptop.c
|
||||
--- a/drivers/platform/x86/lenovo/ideapad-laptop.c
|
||||
+++ b/drivers/platform/x86/lenovo/ideapad-laptop.c
|
||||
@@ -2197,8 +2197,8 @@ static int ideapad_check_features(struct ideapad_private *priv)
|
||||
priv->battery_hook.remove_battery = ideapad_battery_remove;
|
||||
priv->battery_hook.name = "Ideapad Battery Extension";
|
||||
|
||||
- err = devm_battery_hook_register(&priv->platform_device->dev,
|
||||
- &priv->battery_hook);
|
||||
+ err = devm_acpi_battery_hook_register(&priv->platform_device->dev,
|
||||
+ &priv->battery_hook);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
diff --git a/drivers/platform/x86/lenovo/thinkpad_acpi.c b/drivers/platform/x86/lenovo/thinkpad_acpi.c
|
||||
--- a/drivers/platform/x86/lenovo/thinkpad_acpi.c
|
||||
+++ b/drivers/platform/x86/lenovo/thinkpad_acpi.c
|
||||
@@ -10021,13 +10021,13 @@ static int __init tpacpi_battery_init(struct ibm_init_struct *ibm)
|
||||
battery_quirk_table,
|
||||
ARRAY_SIZE(battery_quirk_table));
|
||||
|
||||
- battery_hook_register(&battery_hook);
|
||||
+ acpi_battery_hook_register(&battery_hook);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tpacpi_battery_exit(void)
|
||||
{
|
||||
- battery_hook_unregister(&battery_hook);
|
||||
+ acpi_battery_hook_unregister(&battery_hook);
|
||||
}
|
||||
|
||||
static struct ibm_struct battery_driver_data = {
|
||||
diff --git a/drivers/platform/x86/lenovo/wmi-other.c b/drivers/platform/x86/lenovo/wmi-other.c
|
||||
--- a/drivers/platform/x86/lenovo/wmi-other.c
|
||||
+++ b/drivers/platform/x86/lenovo/wmi-other.c
|
||||
@@ -946,7 +946,7 @@ static void lwmi_om_psy_ext_init(struct lwmi_om_priv *priv)
|
||||
priv->battery_hook.name = "Lenovo WMI Other Battery Extension";
|
||||
priv->bh_registered = true;
|
||||
|
||||
- battery_hook_register(&priv->battery_hook);
|
||||
+ acpi_battery_hook_register(&priv->battery_hook);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -960,7 +960,7 @@ static void lwmi_om_psy_remove(struct lwmi_om_priv *priv)
|
||||
if (!priv->bh_registered)
|
||||
return;
|
||||
|
||||
- battery_hook_unregister(&priv->battery_hook);
|
||||
+ acpi_battery_hook_unregister(&priv->battery_hook);
|
||||
priv->bh_registered = false;
|
||||
}
|
||||
|
||||
diff --git a/drivers/platform/x86/lg-laptop.c b/drivers/platform/x86/lg-laptop.c
|
||||
--- a/drivers/platform/x86/lg-laptop.c
|
||||
+++ b/drivers/platform/x86/lg-laptop.c
|
||||
@@ -1053,7 +1053,7 @@ static int acpi_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto out_platform_device;
|
||||
|
||||
- battery_hook_register(&battery_hook);
|
||||
+ acpi_battery_hook_register(&battery_hook);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1068,7 +1068,7 @@ static void acpi_remove(struct platform_device *pdev)
|
||||
{
|
||||
sysfs_remove_group(&pf_device->dev.kobj, &dev_attribute_group);
|
||||
|
||||
- battery_hook_unregister(&battery_hook);
|
||||
+ acpi_battery_hook_unregister(&battery_hook);
|
||||
platform_device_unregister(pf_device);
|
||||
pf_device = NULL;
|
||||
platform_driver_unregister(&pf_driver);
|
||||
diff --git a/drivers/platform/x86/msi-ec.c b/drivers/platform/x86/msi-ec.c
|
||||
--- a/drivers/platform/x86/msi-ec.c
|
||||
+++ b/drivers/platform/x86/msi-ec.c
|
||||
@@ -1428,13 +1428,13 @@ static int __init msi_ec_init(void)
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
- battery_hook_register(&battery_hook);
|
||||
+ acpi_battery_hook_register(&battery_hook);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit msi_ec_exit(void)
|
||||
{
|
||||
- battery_hook_unregister(&battery_hook);
|
||||
+ acpi_battery_hook_unregister(&battery_hook);
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
diff --git a/drivers/platform/x86/oxpec.c b/drivers/platform/x86/oxpec.c
|
||||
--- a/drivers/platform/x86/oxpec.c
|
||||
+++ b/drivers/platform/x86/oxpec.c
|
||||
@@ -956,7 +956,7 @@ static int oxp_platform_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(hwdev);
|
||||
|
||||
if (oxp_psy_ext_supported()) {
|
||||
- ret = devm_battery_hook_register(dev, &battery_hook);
|
||||
+ ret = devm_acpi_battery_hook_register(dev, &battery_hook);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
diff --git a/drivers/platform/x86/samsung-galaxybook.c b/drivers/platform/x86/samsung-galaxybook.c
|
||||
--- a/drivers/platform/x86/samsung-galaxybook.c
|
||||
+++ b/drivers/platform/x86/samsung-galaxybook.c
|
||||
@@ -549,7 +549,8 @@ static int galaxybook_battery_threshold_init(struct samsung_galaxybook *galaxybo
|
||||
galaxybook->battery_hook.remove_battery = galaxybook_battery_remove;
|
||||
galaxybook->battery_hook.name = "Samsung Galaxy Book Battery Extension";
|
||||
|
||||
- return devm_battery_hook_register(&galaxybook->platform->dev, &galaxybook->battery_hook);
|
||||
+ return devm_acpi_battery_hook_register(&galaxybook->platform->dev,
|
||||
+ &galaxybook->battery_hook);
|
||||
}
|
||||
|
||||
/*
|
||||
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
|
||||
--- a/drivers/platform/x86/samsung-laptop.c
|
||||
+++ b/drivers/platform/x86/samsung-laptop.c
|
||||
@@ -1142,8 +1142,8 @@ static int __init samsung_battery_hook_init(struct samsung_laptop *samsung)
|
||||
samsung->battery_hook.add_battery = samsung_battery_add;
|
||||
samsung->battery_hook.remove_battery = samsung_battery_remove;
|
||||
samsung->battery_hook.name = "Samsung Battery Extension";
|
||||
- retval = devm_battery_hook_register(&samsung->platform_device->dev,
|
||||
- &samsung->battery_hook);
|
||||
+ retval = devm_acpi_battery_hook_register(&samsung->platform_device->dev,
|
||||
+ &samsung->battery_hook);
|
||||
}
|
||||
|
||||
return retval;
|
||||
diff --git a/drivers/platform/x86/system76_acpi.c b/drivers/platform/x86/system76_acpi.c
|
||||
--- a/drivers/platform/x86/system76_acpi.c
|
||||
+++ b/drivers/platform/x86/system76_acpi.c
|
||||
@@ -288,12 +288,12 @@ static struct acpi_battery_hook system76_battery_hook = {
|
||||
|
||||
static void system76_battery_init(void)
|
||||
{
|
||||
- battery_hook_register(&system76_battery_hook);
|
||||
+ acpi_battery_hook_register(&system76_battery_hook);
|
||||
}
|
||||
|
||||
static void system76_battery_exit(void)
|
||||
{
|
||||
- battery_hook_unregister(&system76_battery_hook);
|
||||
+ acpi_battery_hook_unregister(&system76_battery_hook);
|
||||
}
|
||||
|
||||
// Get the airplane mode LED brightness
|
||||
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
|
||||
--- a/drivers/platform/x86/toshiba_acpi.c
|
||||
+++ b/drivers/platform/x86/toshiba_acpi.c
|
||||
@@ -3301,7 +3301,7 @@ static void toshiba_acpi_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
if (dev->battery_charge_mode_supported)
|
||||
- battery_hook_unregister(&battery_hook);
|
||||
+ acpi_battery_hook_unregister(&battery_hook);
|
||||
|
||||
if (toshiba_acpi)
|
||||
toshiba_acpi = NULL;
|
||||
@@ -3566,7 +3566,7 @@ static int toshiba_acpi_probe(struct platform_device *pdev)
|
||||
* set, this must be done after toshiba_acpi is assigned.
|
||||
*/
|
||||
if (dev->battery_charge_mode_supported)
|
||||
- battery_hook_register(&battery_hook);
|
||||
+ acpi_battery_hook_register(&battery_hook);
|
||||
|
||||
return 0;
|
||||
|
||||
diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
|
||||
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
|
||||
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
|
||||
@@ -2165,7 +2165,7 @@ static int uniwill_battery_init(struct uniwill_data *data)
|
||||
data->hook.add_battery = uniwill_add_battery;
|
||||
data->hook.remove_battery = uniwill_remove_battery;
|
||||
|
||||
- return devm_battery_hook_register(data->dev, &data->hook);
|
||||
+ return devm_acpi_battery_hook_register(data->dev, &data->hook);
|
||||
}
|
||||
|
||||
static int uniwill_notifier_call(struct notifier_block *nb, unsigned long action, void *dummy)
|
||||
diff --git a/drivers/power/supply/cros_charge-control.c b/drivers/power/supply/cros_charge-control.c
|
||||
--- a/drivers/power/supply/cros_charge-control.c
|
||||
+++ b/drivers/power/supply/cros_charge-control.c
|
||||
@@ -315,7 +315,7 @@ static int cros_chctl_probe(struct platform_device *pdev)
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
- return devm_battery_hook_register(dev, &priv->battery_hook);
|
||||
+ return devm_acpi_battery_hook_register(dev, &priv->battery_hook);
|
||||
}
|
||||
|
||||
static const struct platform_device_id cros_chctl_id[] = {
|
||||
diff --git a/include/acpi/battery.h b/include/acpi/battery.h
|
||||
--- a/include/acpi/battery.h
|
||||
+++ b/include/acpi/battery.h
|
||||
@@ -18,8 +18,9 @@ struct acpi_battery_hook {
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
-void battery_hook_register(struct acpi_battery_hook *hook);
|
||||
-void battery_hook_unregister(struct acpi_battery_hook *hook);
|
||||
-int devm_battery_hook_register(struct device *dev, struct acpi_battery_hook *hook);
|
||||
+void acpi_battery_hook_register(struct acpi_battery_hook *hook);
|
||||
+void acpi_battery_hook_unregister(struct acpi_battery_hook *hook);
|
||||
+int devm_acpi_battery_hook_register(struct device *dev,
|
||||
+ struct acpi_battery_hook *hook);
|
||||
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,472 @@
|
||||
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
|
||||
--- a/drivers/acpi/Kconfig
|
||||
+++ b/drivers/acpi/Kconfig
|
||||
@@ -171,8 +171,12 @@ config ACPI_AC
|
||||
To compile this driver as a module, choose M here:
|
||||
the module will be called ac.
|
||||
|
||||
+config ACPI_BATTERY_HOOKS
|
||||
+ tristate
|
||||
+
|
||||
config ACPI_BATTERY
|
||||
tristate "Battery"
|
||||
+ select ACPI_BATTERY_HOOKS
|
||||
select POWER_SUPPLY
|
||||
default y
|
||||
help
|
||||
@@ -445,6 +449,7 @@ config ACPI_HOTPLUG_IOAPIC
|
||||
config ACPI_SBS
|
||||
tristate "Smart Battery System"
|
||||
depends on X86 && ACPI_EC
|
||||
+ select ACPI_BATTERY_HOOKS
|
||||
select POWER_SUPPLY
|
||||
help
|
||||
This driver supports the Smart Battery System, another
|
||||
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
|
||||
--- a/drivers/acpi/Makefile
|
||||
+++ b/drivers/acpi/Makefile
|
||||
@@ -97,6 +97,7 @@ obj-$(CONFIG_ACPI_NHLT) += nhlt.o
|
||||
obj-$(CONFIG_ACPI_NUMA) += numa/
|
||||
obj-$(CONFIG_ACPI) += acpi_memhotplug.o
|
||||
obj-$(CONFIG_ACPI_HOTPLUG_IOAPIC) += ioapic.o
|
||||
+obj-$(CONFIG_ACPI_BATTERY_HOOKS) += battery_hooks.o
|
||||
obj-$(CONFIG_ACPI_BATTERY) += battery.o
|
||||
obj-$(CONFIG_ACPI_SBS) += sbshc.o
|
||||
obj-$(CONFIG_ACPI_SBS) += sbs.o
|
||||
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
|
||||
--- a/drivers/acpi/battery.c
|
||||
+++ b/drivers/acpi/battery.c
|
||||
@@ -48,6 +48,7 @@ MODULE_AUTHOR("Paul Diefenbaugh");
|
||||
MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>");
|
||||
MODULE_DESCRIPTION("ACPI Battery Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
+MODULE_IMPORT_NS("ACPI_BATTERY_HOOKS");
|
||||
|
||||
static int battery_bix_broken_package;
|
||||
static int battery_notification_delay_ms;
|
||||
@@ -97,7 +98,7 @@ struct acpi_battery {
|
||||
struct acpi_device *device;
|
||||
struct device *phys_dev;
|
||||
struct notifier_block pm_nb;
|
||||
- struct list_head list;
|
||||
+ struct acpi_battery_hooks_list_entry hooks_list_entry;
|
||||
unsigned long flags;
|
||||
|
||||
struct mutex property_lock; /* Protects properties below. */
|
||||
@@ -723,164 +724,6 @@ static struct attribute *acpi_battery_attrs[] = {
|
||||
};
|
||||
ATTRIBUTE_GROUPS(acpi_battery);
|
||||
|
||||
-/*
|
||||
- * The Battery Hooking API
|
||||
- *
|
||||
- * This API is used inside other drivers that need to expose
|
||||
- * platform-specific behaviour within the generic driver in a
|
||||
- * generic way.
|
||||
- *
|
||||
- */
|
||||
-
|
||||
-static LIST_HEAD(acpi_battery_list);
|
||||
-static LIST_HEAD(battery_hook_list);
|
||||
-static DEFINE_MUTEX(hook_mutex);
|
||||
-
|
||||
-static void acpi_battery_hook_unregister_unlocked(struct acpi_battery_hook *hook)
|
||||
-{
|
||||
- struct acpi_battery *battery;
|
||||
-
|
||||
- /*
|
||||
- * In order to remove a hook, we first need to
|
||||
- * de-register all the batteries that are registered.
|
||||
- */
|
||||
- list_for_each_entry(battery, &acpi_battery_list, list) {
|
||||
- if (!hook->remove_battery(battery->bat, hook))
|
||||
- power_supply_changed(battery->bat);
|
||||
- }
|
||||
- list_del_init(&hook->list);
|
||||
-
|
||||
- pr_info("hook unregistered: %s\n", hook->name);
|
||||
-}
|
||||
-
|
||||
-void acpi_battery_hook_unregister(struct acpi_battery_hook *hook)
|
||||
-{
|
||||
- mutex_lock(&hook_mutex);
|
||||
- /*
|
||||
- * Ignore already unregistered battery hooks. This might happen
|
||||
- * if a battery hook was previously unloaded due to an error when
|
||||
- * adding a new battery.
|
||||
- */
|
||||
- if (!list_empty(&hook->list))
|
||||
- acpi_battery_hook_unregister_unlocked(hook);
|
||||
-
|
||||
- mutex_unlock(&hook_mutex);
|
||||
-}
|
||||
-EXPORT_SYMBOL_GPL(acpi_battery_hook_unregister);
|
||||
-
|
||||
-void acpi_battery_hook_register(struct acpi_battery_hook *hook)
|
||||
-{
|
||||
- struct acpi_battery *battery;
|
||||
-
|
||||
- mutex_lock(&hook_mutex);
|
||||
- list_add(&hook->list, &battery_hook_list);
|
||||
- /*
|
||||
- * Now that the driver is registered, we need
|
||||
- * to notify the hook that a battery is available
|
||||
- * for each battery, so that the driver may add
|
||||
- * its attributes.
|
||||
- */
|
||||
- list_for_each_entry(battery, &acpi_battery_list, list) {
|
||||
- if (hook->add_battery(battery->bat, hook)) {
|
||||
- /*
|
||||
- * If a add-battery returns non-zero,
|
||||
- * the registration of the hook has failed,
|
||||
- * and we will not add it to the list of loaded
|
||||
- * hooks.
|
||||
- */
|
||||
- pr_err("hook failed to load: %s", hook->name);
|
||||
- acpi_battery_hook_unregister_unlocked(hook);
|
||||
- goto end;
|
||||
- }
|
||||
-
|
||||
- power_supply_changed(battery->bat);
|
||||
- }
|
||||
- pr_info("new hook: %s\n", hook->name);
|
||||
-end:
|
||||
- mutex_unlock(&hook_mutex);
|
||||
-}
|
||||
-EXPORT_SYMBOL_GPL(acpi_battery_hook_register);
|
||||
-
|
||||
-static void devm_acpi_battery_hook_unregister(void *data)
|
||||
-{
|
||||
- struct acpi_battery_hook *hook = data;
|
||||
-
|
||||
- acpi_battery_hook_unregister(hook);
|
||||
-}
|
||||
-
|
||||
-int devm_acpi_battery_hook_register(struct device *dev, struct acpi_battery_hook *hook)
|
||||
-{
|
||||
- acpi_battery_hook_register(hook);
|
||||
-
|
||||
- return devm_add_action_or_reset(dev, devm_acpi_battery_hook_unregister, hook);
|
||||
-}
|
||||
-EXPORT_SYMBOL_GPL(devm_acpi_battery_hook_register);
|
||||
-
|
||||
-/*
|
||||
- * This function gets called right after the battery sysfs
|
||||
- * attributes have been added, so that the drivers that
|
||||
- * define custom sysfs attributes can add their own.
|
||||
- */
|
||||
-static void battery_hook_add_battery(struct acpi_battery *battery)
|
||||
-{
|
||||
- struct acpi_battery_hook *hook_node, *tmp;
|
||||
-
|
||||
- mutex_lock(&hook_mutex);
|
||||
- INIT_LIST_HEAD(&battery->list);
|
||||
- list_add(&battery->list, &acpi_battery_list);
|
||||
- /*
|
||||
- * Since we added a new battery to the list, we need to
|
||||
- * iterate over the hooks and call add_battery for each
|
||||
- * hook that was registered. This usually happens
|
||||
- * when a battery gets hotplugged or initialized
|
||||
- * during the battery module initialization.
|
||||
- */
|
||||
- list_for_each_entry_safe(hook_node, tmp, &battery_hook_list, list) {
|
||||
- if (hook_node->add_battery(battery->bat, hook_node)) {
|
||||
- /*
|
||||
- * The notification of the hook has failed, to
|
||||
- * prevent further errors we will unload the hook.
|
||||
- */
|
||||
- pr_err("error in hook, unloading: %s",
|
||||
- hook_node->name);
|
||||
- acpi_battery_hook_unregister_unlocked(hook_node);
|
||||
- }
|
||||
- }
|
||||
- mutex_unlock(&hook_mutex);
|
||||
-}
|
||||
-
|
||||
-static void battery_hook_remove_battery(struct acpi_battery *battery)
|
||||
-{
|
||||
- struct acpi_battery_hook *hook;
|
||||
-
|
||||
- mutex_lock(&hook_mutex);
|
||||
- /*
|
||||
- * Before removing the hook, we need to remove all
|
||||
- * custom attributes from the battery.
|
||||
- */
|
||||
- list_for_each_entry(hook, &battery_hook_list, list) {
|
||||
- hook->remove_battery(battery->bat, hook);
|
||||
- }
|
||||
- /* Then, just remove the battery from the list */
|
||||
- list_del(&battery->list);
|
||||
- mutex_unlock(&hook_mutex);
|
||||
-}
|
||||
-
|
||||
-static void __exit battery_hook_exit(void)
|
||||
-{
|
||||
- struct acpi_battery_hook *hook;
|
||||
- struct acpi_battery_hook *ptr;
|
||||
- /*
|
||||
- * At this point, the acpi_bus_unregister_driver()
|
||||
- * has called remove for all batteries. We just
|
||||
- * need to remove the hooks.
|
||||
- */
|
||||
- list_for_each_entry_safe(hook, ptr, &battery_hook_list, list) {
|
||||
- acpi_battery_hook_unregister(hook);
|
||||
- }
|
||||
- mutex_destroy(&hook_mutex);
|
||||
-}
|
||||
-
|
||||
static int sysfs_add_battery(struct acpi_battery *battery)
|
||||
{
|
||||
struct power_supply_config psy_cfg = {
|
||||
@@ -936,7 +779,7 @@ static int sysfs_add_battery(struct acpi_battery *battery)
|
||||
battery->bat = NULL;
|
||||
return result;
|
||||
}
|
||||
- battery_hook_add_battery(battery);
|
||||
+ acpi_battery_add_hooks(&battery->hooks_list_entry, battery->bat);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -945,7 +788,7 @@ static void sysfs_remove_battery(struct acpi_battery *battery)
|
||||
if (!battery->bat)
|
||||
return;
|
||||
|
||||
- battery_hook_remove_battery(battery);
|
||||
+ acpi_battery_remove_hooks(&battery->hooks_list_entry);
|
||||
power_supply_unregister(battery->bat);
|
||||
battery->bat = NULL;
|
||||
}
|
||||
@@ -1391,7 +1234,6 @@ static int __init acpi_battery_init(void)
|
||||
static void __exit acpi_battery_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&acpi_battery_driver);
|
||||
- battery_hook_exit();
|
||||
}
|
||||
|
||||
module_init(acpi_battery_init);
|
||||
diff --git a/drivers/acpi/battery_hooks.c b/drivers/acpi/battery_hooks.c
|
||||
new file mode 100644
|
||||
--- /dev/null
|
||||
+++ b/drivers/acpi/battery_hooks.c
|
||||
@@ -0,0 +1,159 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+/*
|
||||
+ * ACPI Battery Hooks
|
||||
+ *
|
||||
+ * Provides helpers for registering and unregistering battery hooks for
|
||||
+ * drivers that use platform-specific extensions to ACPI-enumerated
|
||||
+ * batteries (both ACPI Control Method batteries and Smart Battery System
|
||||
+ * batteries).
|
||||
+ */
|
||||
+
|
||||
+#define pr_fmt(fmt) "ACPI: battery: " fmt
|
||||
+
|
||||
+#include <linux/cleanup.h>
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/export.h>
|
||||
+#include <linux/list.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/mutex.h>
|
||||
+#include <linux/power_supply.h>
|
||||
+#include <acpi/battery.h>
|
||||
+
|
||||
+static LIST_HEAD(acpi_battery_list);
|
||||
+static LIST_HEAD(battery_hook_list);
|
||||
+static DEFINE_MUTEX(hook_mutex);
|
||||
+
|
||||
+static void acpi_battery_hook_unregister_unlocked(struct acpi_battery_hook *hook)
|
||||
+{
|
||||
+ struct acpi_battery_hooks_list_entry *entry;
|
||||
+
|
||||
+ /*
|
||||
+ * In order to remove a hook, we first need to
|
||||
+ * de-register all the batteries that are registered.
|
||||
+ */
|
||||
+ list_for_each_entry(entry, &acpi_battery_list, list_entry) {
|
||||
+ if (!hook->remove_battery(entry->battery, hook))
|
||||
+ power_supply_changed(entry->battery);
|
||||
+ }
|
||||
+ list_del_init(&hook->list);
|
||||
+
|
||||
+ pr_info("hook unregistered: %s\n", hook->name);
|
||||
+}
|
||||
+
|
||||
+void acpi_battery_hook_unregister(struct acpi_battery_hook *hook)
|
||||
+{
|
||||
+ guard(mutex)(&hook_mutex);
|
||||
+
|
||||
+ /*
|
||||
+ * Ignore already unregistered battery hooks. This might happen
|
||||
+ * if a battery hook was previously unloaded due to an error when
|
||||
+ * adding a new battery.
|
||||
+ */
|
||||
+ if (!list_empty(&hook->list))
|
||||
+ acpi_battery_hook_unregister_unlocked(hook);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(acpi_battery_hook_unregister);
|
||||
+
|
||||
+void acpi_battery_hook_register(struct acpi_battery_hook *hook)
|
||||
+{
|
||||
+ struct acpi_battery_hooks_list_entry *entry;
|
||||
+
|
||||
+ guard(mutex)(&hook_mutex);
|
||||
+
|
||||
+ list_add(&hook->list, &battery_hook_list);
|
||||
+ /*
|
||||
+ * Now that the driver is registered, we need
|
||||
+ * to notify the hook that a battery is available
|
||||
+ * for each battery, so that the driver may add
|
||||
+ * its attributes.
|
||||
+ */
|
||||
+ list_for_each_entry(entry, &acpi_battery_list, list_entry) {
|
||||
+ if (hook->add_battery(entry->battery, hook)) {
|
||||
+ /*
|
||||
+ * If a add-battery returns non-zero,
|
||||
+ * the registration of the hook has failed,
|
||||
+ * and we will not add it to the list of loaded
|
||||
+ * hooks.
|
||||
+ */
|
||||
+ pr_err("hook failed to load: %s\n", hook->name);
|
||||
+ acpi_battery_hook_unregister_unlocked(hook);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ power_supply_changed(entry->battery);
|
||||
+ }
|
||||
+ pr_info("new hook: %s\n", hook->name);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(acpi_battery_hook_register);
|
||||
+
|
||||
+static void devm_acpi_battery_hook_unregister(void *data)
|
||||
+{
|
||||
+ struct acpi_battery_hook *hook = data;
|
||||
+
|
||||
+ acpi_battery_hook_unregister(hook);
|
||||
+}
|
||||
+
|
||||
+int devm_acpi_battery_hook_register(struct device *dev,
|
||||
+ struct acpi_battery_hook *hook)
|
||||
+{
|
||||
+ acpi_battery_hook_register(hook);
|
||||
+
|
||||
+ return devm_add_action_or_reset(dev, devm_acpi_battery_hook_unregister, hook);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(devm_acpi_battery_hook_register);
|
||||
+
|
||||
+/*
|
||||
+ * This function gets called right after the battery sysfs
|
||||
+ * attributes have been added, so that the drivers that
|
||||
+ * define custom sysfs attributes can add their own.
|
||||
+ */
|
||||
+void acpi_battery_add_hooks(struct acpi_battery_hooks_list_entry *entry,
|
||||
+ struct power_supply *battery)
|
||||
+{
|
||||
+ struct acpi_battery_hook *hook_node, *tmp;
|
||||
+
|
||||
+ entry->battery = battery;
|
||||
+
|
||||
+ guard(mutex)(&hook_mutex);
|
||||
+
|
||||
+ list_add(&entry->list_entry, &acpi_battery_list);
|
||||
+ /*
|
||||
+ * Since we added a new battery to the list, we need to
|
||||
+ * iterate over the hooks and call add_battery for each
|
||||
+ * hook that was registered. This usually happens
|
||||
+ * when a battery gets hotplugged or initialized
|
||||
+ * during the battery module initialization.
|
||||
+ */
|
||||
+ list_for_each_entry_safe(hook_node, tmp, &battery_hook_list, list) {
|
||||
+ if (hook_node->add_battery(entry->battery, hook_node)) {
|
||||
+ /*
|
||||
+ * The notification of the hook has failed, to
|
||||
+ * prevent further errors we will unload the hook.
|
||||
+ */
|
||||
+ pr_err("error in hook, unloading: %s\n", hook_node->name);
|
||||
+ acpi_battery_hook_unregister_unlocked(hook_node);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL_NS_GPL(acpi_battery_add_hooks, "ACPI_BATTERY_HOOKS");
|
||||
+
|
||||
+void acpi_battery_remove_hooks(struct acpi_battery_hooks_list_entry *entry)
|
||||
+{
|
||||
+ struct acpi_battery_hook *hook;
|
||||
+
|
||||
+ guard(mutex)(&hook_mutex);
|
||||
+ /*
|
||||
+ * Before removing the hook, we need to remove all
|
||||
+ * custom attributes from the battery.
|
||||
+ */
|
||||
+ list_for_each_entry(hook, &battery_hook_list, list)
|
||||
+ hook->remove_battery(entry->battery, hook);
|
||||
+
|
||||
+ /* Then, just remove the battery from the list */
|
||||
+ list_del(&entry->list_entry);
|
||||
+ entry->battery = NULL;
|
||||
+}
|
||||
+EXPORT_SYMBOL_NS_GPL(acpi_battery_remove_hooks, "ACPI_BATTERY_HOOKS");
|
||||
+
|
||||
+MODULE_DESCRIPTION("ACPI battery hooks");
|
||||
+MODULE_LICENSE("GPL");
|
||||
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
|
||||
--- a/drivers/acpi/sbs.c
|
||||
+++ b/drivers/acpi/sbs.c
|
||||
@@ -36,6 +36,7 @@
|
||||
MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>");
|
||||
MODULE_DESCRIPTION("Smart Battery System ACPI interface driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
+MODULE_IMPORT_NS("ACPI_BATTERY_HOOKS");
|
||||
|
||||
static unsigned int cache_time = 1000;
|
||||
module_param(cache_time, uint, 0644);
|
||||
@@ -54,6 +55,7 @@ struct acpi_battery {
|
||||
struct power_supply *bat;
|
||||
struct power_supply_desc bat_desc;
|
||||
struct acpi_sbs *sbs;
|
||||
+ struct acpi_battery_hooks_list_entry hooks_list_entry;
|
||||
unsigned long update_time;
|
||||
char name[8];
|
||||
char manufacturer_name[ACPI_SBS_BLOCK_MAX];
|
||||
@@ -555,6 +557,8 @@ static int acpi_battery_add(struct acpi_sbs *sbs, int id)
|
||||
goto end;
|
||||
}
|
||||
|
||||
+ acpi_battery_add_hooks(&battery->hooks_list_entry, battery->bat);
|
||||
+
|
||||
end:
|
||||
pr_info("%s [%s]: Battery Slot [%s] (battery %s)\n",
|
||||
ACPI_SBS_DEVICE_NAME, acpi_device_bid(sbs->device),
|
||||
@@ -566,8 +570,10 @@ static void acpi_battery_remove(struct acpi_sbs *sbs, int id)
|
||||
{
|
||||
struct acpi_battery *battery = &sbs->battery[id];
|
||||
|
||||
- if (battery->bat)
|
||||
+ if (battery->bat) {
|
||||
+ acpi_battery_remove_hooks(&battery->hooks_list_entry);
|
||||
power_supply_unregister(battery->bat);
|
||||
+ }
|
||||
}
|
||||
|
||||
static int acpi_charger_add(struct acpi_sbs *sbs)
|
||||
diff --git a/include/acpi/battery.h b/include/acpi/battery.h
|
||||
--- a/include/acpi/battery.h
|
||||
+++ b/include/acpi/battery.h
|
||||
@@ -18,9 +18,18 @@ struct acpi_battery_hook {
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
+struct acpi_battery_hooks_list_entry {
|
||||
+ struct list_head list_entry;
|
||||
+ struct power_supply *battery;
|
||||
+};
|
||||
+
|
||||
void acpi_battery_hook_register(struct acpi_battery_hook *hook);
|
||||
void acpi_battery_hook_unregister(struct acpi_battery_hook *hook);
|
||||
int devm_acpi_battery_hook_register(struct device *dev,
|
||||
struct acpi_battery_hook *hook);
|
||||
|
||||
+void acpi_battery_add_hooks(struct acpi_battery_hooks_list_entry *entry,
|
||||
+ struct power_supply *battery);
|
||||
+void acpi_battery_remove_hooks(struct acpi_battery_hooks_list_entry *entry);
|
||||
+
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,209 @@
|
||||
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
|
||||
--- a/drivers/hwmon/Kconfig
|
||||
+++ b/drivers/hwmon/Kconfig
|
||||
@@ -380,6 +380,7 @@ config SENSORS_FAM15H_POWER
|
||||
config SENSORS_APPLESMC
|
||||
tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)"
|
||||
depends on INPUT && X86
|
||||
+ depends on POWER_SUPPLY || POWER_SUPPLY=n
|
||||
select NEW_LEDS
|
||||
select LEDS_CLASS
|
||||
help
|
||||
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
|
||||
--- a/drivers/hwmon/applesmc.c
|
||||
+++ b/drivers/hwmon/applesmc.c
|
||||
@@ -33,6 +33,8 @@
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/bits.h>
|
||||
+#include <linux/power_supply.h>
|
||||
+#include <acpi/battery.h>
|
||||
#include <asm/barrier.h>
|
||||
|
||||
/* data port used by Apple SMC */
|
||||
@@ -76,6 +78,20 @@
|
||||
|
||||
#define TEMP_SENSOR_TYPE "sp78"
|
||||
|
||||
+/*
|
||||
+ * BCLM caps charging at a percentage. BFCL only sets when the charging LED
|
||||
+ * switches from orange to green.
|
||||
+ */
|
||||
+#define BATTERY_CHARGE_LIMIT_KEY "BCLM" /* r/w ui8 */
|
||||
+#define BATTERY_CHARGE_LIMIT_LED_KEY "BFCL" /* r/w ui8 */
|
||||
+
|
||||
+/*
|
||||
+ * Points kept between BCLM and BFCL so the LED turns green before charging
|
||||
+ * stops. Measured on a MacBookAir6,2, where a margin of 1 only just ties;
|
||||
+ * 3 leaves headroom for other models.
|
||||
+ */
|
||||
+#define APPLESMC_BATTERY_CHARGE_LIMIT_LED_MARGIN 3
|
||||
+
|
||||
/* List of keys used to read/write fan speeds */
|
||||
static const char *const fan_speed_fmt[] = {
|
||||
"F%dAc", /* actual speed */
|
||||
@@ -131,6 +147,8 @@ static struct applesmc_registers {
|
||||
int num_light_sensors; /* number of light sensors */
|
||||
bool has_accelerometer; /* has motion sensor */
|
||||
bool has_key_backlight; /* has keyboard backlight */
|
||||
+ bool has_battery_charge_limit; /* has BCLM battery charge limit */
|
||||
+ bool has_battery_charge_limit_led; /* has BFCL MagSafe LED charge limit */
|
||||
bool init_complete; /* true when fully initialized */
|
||||
struct applesmc_entry *cache; /* cached key entries */
|
||||
const char **index; /* temperature key index */
|
||||
@@ -633,6 +651,12 @@ static int applesmc_init_smcreg_try(void)
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = applesmc_has_key(BACKLIGHT_KEY, &s->has_key_backlight);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ ret = applesmc_has_key(BATTERY_CHARGE_LIMIT_KEY, &s->has_battery_charge_limit);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ ret = applesmc_has_key(BATTERY_CHARGE_LIMIT_LED_KEY, &s->has_battery_charge_limit_led);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -724,6 +748,120 @@ static struct platform_driver applesmc_driver = {
|
||||
},
|
||||
};
|
||||
|
||||
+static DEFINE_MUTEX(applesmc_bat_lock);
|
||||
+
|
||||
+static int applesmc_bat_get_property(struct power_supply *psy,
|
||||
+ const struct power_supply_ext *ext,
|
||||
+ void *data,
|
||||
+ enum power_supply_property psp,
|
||||
+ union power_supply_propval *val)
|
||||
+{
|
||||
+ u8 limit;
|
||||
+ int ret;
|
||||
+
|
||||
+ switch (psp) {
|
||||
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
|
||||
+ scoped_guard(mutex, &applesmc_bat_lock)
|
||||
+ ret = applesmc_read_key(BATTERY_CHARGE_LIMIT_KEY, &limit, 1);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ val->intval = limit;
|
||||
+ return 0;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int applesmc_bat_set_property(struct power_supply *psy,
|
||||
+ const struct power_supply_ext *ext,
|
||||
+ void *data,
|
||||
+ enum power_supply_property psp,
|
||||
+ const union power_supply_propval *val)
|
||||
+{
|
||||
+ u8 limit, led_limit, readback;
|
||||
+ int ret;
|
||||
+
|
||||
+ switch (psp) {
|
||||
+ case POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD:
|
||||
+ /* 20 is known to work and 10 is not accepted; the floor is unknown. */
|
||||
+ if (val->intval < 20 || val->intval > 100)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ limit = val->intval;
|
||||
+ /* At 100% charging is never cut short, so no margin is needed. */
|
||||
+ led_limit = limit < 100 ?
|
||||
+ limit - APPLESMC_BATTERY_CHARGE_LIMIT_LED_MARGIN : limit;
|
||||
+
|
||||
+ scoped_guard(mutex, &applesmc_bat_lock) {
|
||||
+ ret = applesmc_write_key(BATTERY_CHARGE_LIMIT_KEY, &limit, 1);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /*
|
||||
+ * The SMC silently ignores values it does not accept and
|
||||
+ * still reports success, so read the limit back.
|
||||
+ */
|
||||
+ ret = applesmc_read_key(BATTERY_CHARGE_LIMIT_KEY, &readback, 1);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ if (readback != limit)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (smcreg.has_battery_charge_limit_led) {
|
||||
+ ret = applesmc_write_key(BATTERY_CHARGE_LIMIT_LED_KEY,
|
||||
+ &led_limit, 1);
|
||||
+ /* BCLM is already applied, so this is not an error. */
|
||||
+ if (ret)
|
||||
+ pr_warn("failed to update MagSafe LED threshold (BFCL): %d\n",
|
||||
+ ret);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ power_supply_changed(psy);
|
||||
+ return 0;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int applesmc_bat_property_is_writeable(struct power_supply *psy,
|
||||
+ const struct power_supply_ext *ext,
|
||||
+ void *data,
|
||||
+ enum power_supply_property psp)
|
||||
+{
|
||||
+ return psp == POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD;
|
||||
+}
|
||||
+
|
||||
+static const enum power_supply_property applesmc_bat_props[] = {
|
||||
+ POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD,
|
||||
+};
|
||||
+
|
||||
+static const struct power_supply_ext applesmc_bat_ext = {
|
||||
+ .name = "applesmc-charge-control",
|
||||
+ .properties = applesmc_bat_props,
|
||||
+ .num_properties = ARRAY_SIZE(applesmc_bat_props),
|
||||
+ .get_property = applesmc_bat_get_property,
|
||||
+ .set_property = applesmc_bat_set_property,
|
||||
+ .property_is_writeable = applesmc_bat_property_is_writeable,
|
||||
+};
|
||||
+
|
||||
+static int applesmc_bat_add(struct power_supply *battery, struct acpi_battery_hook *hook)
|
||||
+{
|
||||
+ return power_supply_register_extension(battery, &applesmc_bat_ext, &pdev->dev, NULL);
|
||||
+}
|
||||
+
|
||||
+static int applesmc_bat_remove(struct power_supply *battery, struct acpi_battery_hook *hook)
|
||||
+{
|
||||
+ power_supply_unregister_extension(battery, &applesmc_bat_ext);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct acpi_battery_hook applesmc_bat_hook = {
|
||||
+ .name = "Apple SMC Battery Charge Control",
|
||||
+ .add_battery = applesmc_bat_add,
|
||||
+ .remove_battery = applesmc_bat_remove,
|
||||
+};
|
||||
+
|
||||
/*
|
||||
* applesmc_calibrate - Set our "resting" values. Callers must
|
||||
* hold applesmc_lock.
|
||||
@@ -1563,6 +1701,10 @@ static int __init applesmc_init(void)
|
||||
goto out_light_ledclass;
|
||||
}
|
||||
|
||||
+ if (smcreg.has_battery_charge_limit &&
|
||||
+ IS_REACHABLE(CONFIG_ACPI_BATTERY_HOOKS))
|
||||
+ acpi_battery_hook_register(&applesmc_bat_hook);
|
||||
+
|
||||
return 0;
|
||||
|
||||
out_light_ledclass:
|
||||
@@ -1589,6 +1731,10 @@ static int __init applesmc_init(void)
|
||||
|
||||
static void __exit applesmc_exit(void)
|
||||
{
|
||||
+ if (smcreg.has_battery_charge_limit &&
|
||||
+ IS_REACHABLE(CONFIG_ACPI_BATTERY_HOOKS))
|
||||
+ acpi_battery_hook_unregister(&applesmc_bat_hook);
|
||||
+
|
||||
hwmon_device_unregister(hwmon_dev);
|
||||
applesmc_release_key_backlight();
|
||||
applesmc_release_light_sensor();
|
||||
BIN
Binary file not shown.
@@ -1,170 +0,0 @@
|
||||
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
|
||||
--- a/kernel/trace/ftrace.c
|
||||
+++ b/kernel/trace/ftrace.c
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/sched/task.h>
|
||||
#include <linux/kallsyms.h>
|
||||
+#include <linux/module_symbol.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/tracefs.h>
|
||||
@@ -4385,6 +4386,109 @@ static int test_for_valid_rec(struct dyn_ftrace *rec)
|
||||
return 1;
|
||||
}
|
||||
|
||||
+#if defined(CONFIG_MODULES) && defined(CONFIG_KALLSYMS)
|
||||
+#define FTRACE_MOD_SYMS
|
||||
+/*
|
||||
+ * test_for_valid_rec() resolves an address with kallsyms_lookup(), which
|
||||
+ * scans the whole symbol table of a module. Calling it for every record of
|
||||
+ * a module being loaded costs O(records * symbols): several seconds for a
|
||||
+ * driver as large as amdgpu, all of it under ftrace_lock. Sort the symbol
|
||||
+ * addresses of the module once instead and binary search them. The module
|
||||
+ * symbol table itself is left untouched, as livepatch relies on its order.
|
||||
+ */
|
||||
+struct ftrace_mod_syms {
|
||||
+ unsigned long *addrs;
|
||||
+ unsigned int nr;
|
||||
+};
|
||||
+
|
||||
+static int ftrace_cmp_addr(const void *a, const void *b)
|
||||
+{
|
||||
+ unsigned long x = *(const unsigned long *)a;
|
||||
+ unsigned long y = *(const unsigned long *)b;
|
||||
+
|
||||
+ return x < y ? -1 : x > y;
|
||||
+}
|
||||
+
|
||||
+/* Collect the symbols find_kallsyms_symbol() would consider. */
|
||||
+static void ftrace_mod_syms_init(struct ftrace_mod_syms *syms,
|
||||
+ struct module *mod)
|
||||
+{
|
||||
+ /* A coming module cannot have its kallsyms replaced under us. */
|
||||
+ struct mod_kallsyms *kallsyms = rcu_dereference_raw(mod->kallsyms);
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ syms->nr = 0;
|
||||
+ syms->addrs = kvmalloc_array(kallsyms->num_symtab,
|
||||
+ sizeof(*syms->addrs), GFP_KERNEL);
|
||||
+ if (!syms->addrs)
|
||||
+ return;
|
||||
+
|
||||
+ for (i = 1; i < kallsyms->num_symtab; i++) {
|
||||
+ const Elf_Sym *sym = &kallsyms->symtab[i];
|
||||
+ const char *name = kallsyms->strtab + sym->st_name;
|
||||
+
|
||||
+ if (sym->st_shndx == SHN_UNDEF || *name == '\0' ||
|
||||
+ is_mapping_symbol(name))
|
||||
+ continue;
|
||||
+ syms->addrs[syms->nr++] = kallsyms_symbol_value(sym);
|
||||
+ }
|
||||
+
|
||||
+ sort(syms->addrs, syms->nr, sizeof(*syms->addrs), ftrace_cmp_addr, NULL);
|
||||
+}
|
||||
+
|
||||
+/* Same answer as test_for_valid_rec(), using the sorted addresses. */
|
||||
+static int test_for_valid_mod_rec(struct ftrace_mod_syms *syms,
|
||||
+ struct module *mod, struct dyn_ftrace *rec)
|
||||
+{
|
||||
+ unsigned long ip = rec->ip, base, best;
|
||||
+ unsigned int lo = 0, hi = syms->nr, mid;
|
||||
+ struct module_memory *mod_mem = NULL;
|
||||
+
|
||||
+ if (!syms->addrs)
|
||||
+ return test_for_valid_rec(rec);
|
||||
+
|
||||
+ for_each_mod_mem_type(type) {
|
||||
+#ifndef CONFIG_KALLSYMS_ALL
|
||||
+ if (!mod_mem_type_is_text(type))
|
||||
+ continue;
|
||||
+#endif
|
||||
+ if (within_module_mem_type(ip, mod, type)) {
|
||||
+ mod_mem = &mod->mem[type];
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ if (!mod_mem)
|
||||
+ goto invalid;
|
||||
+ base = (unsigned long)mod_mem->base;
|
||||
+
|
||||
+ /* Find the last symbol at or below ip. */
|
||||
+ while (lo < hi) {
|
||||
+ mid = lo + (hi - lo) / 2;
|
||||
+ if (syms->addrs[mid] <= ip)
|
||||
+ lo = mid + 1;
|
||||
+ else
|
||||
+ hi = mid;
|
||||
+ }
|
||||
+ if (!lo)
|
||||
+ goto invalid;
|
||||
+ best = syms->addrs[lo - 1];
|
||||
+
|
||||
+ /* Weak functions can cause invalid addresses */
|
||||
+ if (best < base || ip - best > FTRACE_MCOUNT_MAX_OFFSET)
|
||||
+ goto invalid;
|
||||
+ return 1;
|
||||
+
|
||||
+invalid:
|
||||
+ rec->flags |= FTRACE_FL_DISABLED;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void ftrace_mod_syms_free(struct ftrace_mod_syms *syms)
|
||||
+{
|
||||
+ kvfree(syms->addrs);
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
static struct workqueue_struct *ftrace_check_wq __initdata;
|
||||
static struct work_struct ftrace_check_work __initdata;
|
||||
|
||||
@@ -8010,11 +8114,30 @@ void ftrace_release_mod(struct module *mod)
|
||||
}
|
||||
}
|
||||
|
||||
+#ifndef FTRACE_MOD_SYMS
|
||||
+struct ftrace_mod_syms { };
|
||||
+
|
||||
+static inline void ftrace_mod_syms_init(struct ftrace_mod_syms *syms,
|
||||
+ struct module *mod) { }
|
||||
+
|
||||
+static inline int test_for_valid_mod_rec(struct ftrace_mod_syms *syms,
|
||||
+ struct module *mod,
|
||||
+ struct dyn_ftrace *rec)
|
||||
+{
|
||||
+ return test_for_valid_rec(rec);
|
||||
+}
|
||||
+
|
||||
+static inline void ftrace_mod_syms_free(struct ftrace_mod_syms *syms) { }
|
||||
+#endif
|
||||
+
|
||||
void ftrace_module_enable(struct module *mod)
|
||||
{
|
||||
+ struct ftrace_mod_syms syms;
|
||||
struct dyn_ftrace *rec;
|
||||
struct ftrace_page *pg;
|
||||
|
||||
+ ftrace_mod_syms_init(&syms, mod);
|
||||
+
|
||||
mutex_lock(&ftrace_lock);
|
||||
|
||||
if (ftrace_disabled)
|
||||
@@ -8050,7 +8173,7 @@ void ftrace_module_enable(struct module *mod)
|
||||
cond_resched();
|
||||
|
||||
/* Weak functions should still be ignored */
|
||||
- if (!test_for_valid_rec(rec)) {
|
||||
+ if (!test_for_valid_mod_rec(&syms, mod, rec)) {
|
||||
/* Clear all other flags. Should not be enabled anyway */
|
||||
rec->flags = FTRACE_FL_DISABLED;
|
||||
continue;
|
||||
@@ -8087,6 +8210,8 @@ void ftrace_module_enable(struct module *mod)
|
||||
out_unlock:
|
||||
mutex_unlock(&ftrace_lock);
|
||||
|
||||
+ ftrace_mod_syms_free(&syms);
|
||||
+
|
||||
process_cached_mods(mod->name);
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,95 @@
|
||||
diff --git a/include/linux/module.h b/include/linux/module.h
|
||||
--- a/include/linux/module.h
|
||||
+++ b/include/linux/module.h
|
||||
@@ -975,6 +975,10 @@ unsigned long module_kallsyms_lookup_name(const char *name);
|
||||
|
||||
unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name);
|
||||
|
||||
+void module_kallsyms_on_each_addr(struct module *mod,
|
||||
+ void (*fn)(void *, unsigned long),
|
||||
+ void *data);
|
||||
+
|
||||
#else /* CONFIG_MODULES && CONFIG_KALLSYMS */
|
||||
|
||||
static inline int module_kallsyms_on_each_symbol(const char *modname,
|
||||
@@ -1018,6 +1022,12 @@ static inline unsigned long find_kallsyms_symbol_value(struct module *mod,
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static inline void module_kallsyms_on_each_addr(struct module *mod,
|
||||
+ void (*fn)(void *, unsigned long),
|
||||
+ void *data)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
#endif /* CONFIG_MODULES && CONFIG_KALLSYMS */
|
||||
|
||||
/* Define __free(module_put) macro for struct module *. */
|
||||
diff --git a/kernel/module/kallsyms.c b/kernel/module/kallsyms.c
|
||||
--- a/kernel/module/kallsyms.c
|
||||
+++ b/kernel/module/kallsyms.c
|
||||
@@ -246,6 +246,18 @@ static const char *kallsyms_symbol_name(struct mod_kallsyms *kallsyms, unsigned
|
||||
return kallsyms->strtab + kallsyms->symtab[symnum].st_name;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Whether find_kallsyms_symbol() may resolve an address to symbol @symnum.
|
||||
+ * Unnamed symbols are ignored: they're uninformative and inserted at a whim.
|
||||
+ */
|
||||
+static bool is_lookup_symbol(struct mod_kallsyms *kallsyms, unsigned int symnum)
|
||||
+{
|
||||
+ const char *name = kallsyms_symbol_name(kallsyms, symnum);
|
||||
+
|
||||
+ return kallsyms->symtab[symnum].st_shndx != SHN_UNDEF &&
|
||||
+ *name != '\0' && !is_mapping_symbol(name);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Given a module and address, find the corresponding symbol and return its name
|
||||
* while providing its size and offset if needed.
|
||||
@@ -286,15 +298,7 @@ static const char *find_kallsyms_symbol(struct module *mod,
|
||||
const Elf_Sym *sym = &kallsyms->symtab[i];
|
||||
unsigned long thisval = kallsyms_symbol_value(sym);
|
||||
|
||||
- if (sym->st_shndx == SHN_UNDEF)
|
||||
- continue;
|
||||
-
|
||||
- /*
|
||||
- * We ignore unnamed symbols: they're uninformative
|
||||
- * and inserted at a whim.
|
||||
- */
|
||||
- if (*kallsyms_symbol_name(kallsyms, i) == '\0' ||
|
||||
- is_mapping_symbol(kallsyms_symbol_name(kallsyms, i)))
|
||||
+ if (!is_lookup_symbol(kallsyms, i))
|
||||
continue;
|
||||
|
||||
if (thisval <= addr && thisval > bestval) {
|
||||
@@ -458,6 +462,28 @@ unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name)
|
||||
return __find_kallsyms_symbol_value(mod, name);
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Call @fn with the address of each symbol of @mod that find_kallsyms_symbol()
|
||||
+ * may resolve an address to. Unlike module_kallsyms_on_each_symbol(), this
|
||||
+ * also works while @mod is still being loaded.
|
||||
+ */
|
||||
+void module_kallsyms_on_each_addr(struct module *mod,
|
||||
+ void (*fn)(void *, unsigned long),
|
||||
+ void *data)
|
||||
+{
|
||||
+ struct mod_kallsyms *kallsyms;
|
||||
+ unsigned int i;
|
||||
+
|
||||
+ guard(rcu)();
|
||||
+ kallsyms = rcu_dereference(mod->kallsyms);
|
||||
+
|
||||
+ /* ELF starts real symbols at 1. */
|
||||
+ for (i = 1; i < kallsyms->num_symtab; i++) {
|
||||
+ if (is_lookup_symbol(kallsyms, i))
|
||||
+ fn(data, kallsyms_symbol_value(&kallsyms->symtab[i]));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
int module_kallsyms_on_each_symbol(const char *modname,
|
||||
int (*fn)(void *, const char *, unsigned long),
|
||||
void *data)
|
||||
Binary file not shown.
+113
@@ -0,0 +1,113 @@
|
||||
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
|
||||
--- a/kernel/trace/ftrace.c
|
||||
+++ b/kernel/trace/ftrace.c
|
||||
@@ -4445,11 +4445,6 @@ static int print_rec(struct seq_file *m, unsigned long ip)
|
||||
return ret == NULL ? -1 : 0;
|
||||
}
|
||||
#else
|
||||
-static inline int test_for_valid_rec(struct dyn_ftrace *rec)
|
||||
-{
|
||||
- return 1;
|
||||
-}
|
||||
-
|
||||
static inline int print_rec(struct seq_file *m, unsigned long ip)
|
||||
{
|
||||
seq_printf(m, "%ps", (void *)ip);
|
||||
@@ -7611,6 +7606,73 @@ static void test_is_sorted(unsigned long *start, unsigned long count)
|
||||
}
|
||||
#endif
|
||||
|
||||
+#ifdef FTRACE_MCOUNT_MAX_OFFSET
|
||||
+struct ftrace_mod_locs {
|
||||
+ unsigned long *start;
|
||||
+ unsigned long count;
|
||||
+ unsigned long *valid;
|
||||
+};
|
||||
+
|
||||
+/* Mark the locations that lie at most FTRACE_MCOUNT_MAX_OFFSET after @addr. */
|
||||
+static void ftrace_mark_valid_locs(void *data, unsigned long addr)
|
||||
+{
|
||||
+ struct ftrace_mod_locs *locs = data;
|
||||
+ unsigned long lo = 0, hi = locs->count, mid, ip;
|
||||
+
|
||||
+ /*
|
||||
+ * ftrace_call_adjust() moves a location forward by at most
|
||||
+ * FTRACE_MCOUNT_MAX_OFFSET, so start looking that far before @addr.
|
||||
+ */
|
||||
+ while (lo < hi) {
|
||||
+ mid = lo + (hi - lo) / 2;
|
||||
+ if (locs->start[mid] + FTRACE_MCOUNT_MAX_OFFSET < addr)
|
||||
+ lo = mid + 1;
|
||||
+ else
|
||||
+ hi = mid;
|
||||
+ }
|
||||
+
|
||||
+ for (; lo < locs->count; lo++) {
|
||||
+ if (locs->start[lo] > addr + FTRACE_MCOUNT_MAX_OFFSET)
|
||||
+ break;
|
||||
+ ip = ftrace_call_adjust(locs->start[lo]);
|
||||
+ if (ip >= addr && ip - addr <= FTRACE_MCOUNT_MAX_OFFSET)
|
||||
+ __set_bit(lo, locs->valid);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * A weak function overridden within its module keeps its mcount location but
|
||||
+ * has no symbol. Zero such locations before they become records, as sorttable
|
||||
+ * does for vmlinux: keep only those with a symbol at most
|
||||
+ * FTRACE_MCOUNT_MAX_OFFSET before them.
|
||||
+ */
|
||||
+static int ftrace_zero_weak_locs(struct module *mod, unsigned long *start,
|
||||
+ unsigned long count)
|
||||
+{
|
||||
+ struct ftrace_mod_locs locs = { .start = start, .count = count };
|
||||
+ unsigned long i;
|
||||
+
|
||||
+ locs.valid = bitmap_zalloc(count, GFP_KERNEL);
|
||||
+ if (!locs.valid)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ module_kallsyms_on_each_addr(mod, ftrace_mark_valid_locs, &locs);
|
||||
+
|
||||
+ for_each_clear_bit(i, locs.valid, count)
|
||||
+ start[i] = 0;
|
||||
+
|
||||
+ bitmap_free(locs.valid);
|
||||
+ return 0;
|
||||
+}
|
||||
+#else
|
||||
+static inline int ftrace_zero_weak_locs(struct module *mod,
|
||||
+ unsigned long *start,
|
||||
+ unsigned long count)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
static int ftrace_process_locs(struct module *mod,
|
||||
unsigned long *start,
|
||||
unsigned long *end)
|
||||
@@ -7644,6 +7706,9 @@ static int ftrace_process_locs(struct module *mod,
|
||||
test_is_sorted(start, count);
|
||||
}
|
||||
|
||||
+ if (mod && ftrace_zero_weak_locs(mod, start, count))
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
start_pg = ftrace_allocate_pages(count, &pages);
|
||||
if (!start_pg)
|
||||
return -ENOMEM;
|
||||
@@ -8049,13 +8114,6 @@ void ftrace_module_enable(struct module *mod)
|
||||
|
||||
cond_resched();
|
||||
|
||||
- /* Weak functions should still be ignored */
|
||||
- if (!test_for_valid_rec(rec)) {
|
||||
- /* Clear all other flags. Should not be enabled anyway */
|
||||
- rec->flags = FTRACE_FL_DISABLED;
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
cnt = 0;
|
||||
|
||||
/*
|
||||
BIN
Binary file not shown.
@@ -3,7 +3,7 @@
|
||||
|
||||
pkgbase=linux-omarchy-bore
|
||||
pkgver=7.2.8
|
||||
pkgrel=2
|
||||
pkgrel=5
|
||||
pkgdesc='Omarchy Linux (BORE CPU scheduler, ADIOS I/O scheduler)'
|
||||
url='https://omarchy.org'
|
||||
arch=(
|
||||
@@ -165,6 +165,8 @@ source=(
|
||||
0703-pci-vmd-scan-bios-enumerated-devices.patch{,.sig}
|
||||
0704-pci-vmd-meteor-lake-mtl016-flush.patch{,.sig}
|
||||
0705-pci-toshiba-ahci-ssd-dma-alias-quirk.patch{,.sig}
|
||||
0711-iommu-amd-perfopt-support.patch{,.sig}
|
||||
0712-drm-amdgpu-perfopt-in-identity-domain.patch{,.sig}
|
||||
0740-hwmon-updates.patch{,.sig}
|
||||
0741-hwmon-fixes-1.patch{,.sig}
|
||||
0742-hwmon-fixes-2.patch{,.sig}
|
||||
@@ -172,10 +174,14 @@ source=(
|
||||
0800-platform-updates.patch{,.sig}
|
||||
0801-amd-pmf-util-unbind-use-after-free.patch{,.sig}
|
||||
0802-platform-fixes.patch{,.sig}
|
||||
0803-acpi-battery-hook-api-acpi-prefix.patch{,.sig}
|
||||
0804-acpi-battery-unified-hooks-acpi-sbs.patch{,.sig}
|
||||
0805-hwmon-applesmc-charge-control-end-threshold.patch{,.sig}
|
||||
0850-futex-wait-multiple.patch{,.sig}
|
||||
0851-futex-wait-multiple-fixes.patch{,.sig}
|
||||
0852-futex-wait-multiple-abi-fixes.patch{,.sig}
|
||||
0860-ftrace-module-enable-sorted-symbol-search.patch{,.sig}
|
||||
0860-module-add-module-kallsyms-on-each-addr.patch{,.sig}
|
||||
0861-ftrace-drop-weak-function-locations-of-modules.patch{,.sig}
|
||||
8204-mm-opportunistic-compaction.patch{,.sig}
|
||||
8205-mm-hint-uses-allocation-order.patch{,.sig}
|
||||
8206-mm-carry-order-and-hint-in-one-word.patch{,.sig}
|
||||
@@ -442,6 +448,10 @@ b2sums=('5326dde778eb945f282740ef0d8765b46fbd198f1209cdfd7b91e5dac1312fc01f8bf0b
|
||||
'SKIP'
|
||||
'da96dbbe3b6b4e189cf7bdce14647bba07bbc5599ce28ed385a1c34d237ee7ae3ac595d2552444615f2b15c2b7eda42f40743d5bdebd443e3ec31e5743f59056'
|
||||
'SKIP'
|
||||
'cb2494c930b2c2c4cd6755494339c5f95ace87940b2b2e51928d98ea63262e4bf7a4245f629b8bb06e7592f45a0c379e5583c8695563011009fdb07f965d7c1a'
|
||||
'SKIP'
|
||||
'6083db5b92aa46bf54144b4d2fab368916974ef01334fbe934bded3818c5dfb4fc8d5d0e896bf1baddc29aac1c559f80dabc727082a757301117843def8089c8'
|
||||
'SKIP'
|
||||
'c25bff6e5be62aca887ae0781899e37a39e1aec90f0eb934ec5394abf560f4d02ad1fb3973a45d00058b46555bbc8d9febfcc8026e210f53a8864a91b3b80a9d'
|
||||
'SKIP'
|
||||
'e70e0077249bf008e069041a0239c6bb63075044cd0df3218649ff92a6a2d43467026886f2a6a70c70552268f6936764459d7cc0817a103b6a0f74c37c52c72d'
|
||||
@@ -456,13 +466,21 @@ b2sums=('5326dde778eb945f282740ef0d8765b46fbd198f1209cdfd7b91e5dac1312fc01f8bf0b
|
||||
'SKIP'
|
||||
'4e4792acaf0455f41cb1541d20d37e7a39104aa2dfb505e9be29dc3e7fecf328557780982b32cd8f67f77594542f5b8104766a4e8b5ce2270c9c601728363b3f'
|
||||
'SKIP'
|
||||
'00417f024d2cc0b0fad28dec7f11c3054f5da7bf8c353d06fd1086be1926eacbe07ba924380157f270aac910d771f909f34beed0f60106f6ae60c96f58423b4a'
|
||||
'SKIP'
|
||||
'2c254a2df00e79f03b51d13846f232073e9276e022c7bf46bfe810cc98456d481535152afa9d915e0726e7701594453f9363b6190b8e616db203d176a08fd31f'
|
||||
'SKIP'
|
||||
'cbfa20431371f3332f28013bfa21beef21a5a6f616e09fa91e9adb42899cb2e1880e27cf4b90bba980bce26710af3ac3c1e49054df4e48051bcc4612732d3e9e'
|
||||
'SKIP'
|
||||
'aca0527f5630671a319e7ecff958a3a64f29df73b427c67c1d29763cc1801fa82e96761c3a61c22d936913943a49261da64d490a0752ba9ffc8e0c1d92f99835'
|
||||
'SKIP'
|
||||
'803736a8e836560b3e50b7c0c8cf1f9ebb16b8642cc7bc6e5167d19037bd757431565fe4581776e50eb2693c49f778a24fecff41a553612e7e498f755b8f2f67'
|
||||
'SKIP'
|
||||
'4bc132d9c34deaae9b13d08dcff8ea83aa8f9ce4398531e0e0a80df30da3808815f3a587fe5627f6553b8e9c2aea6cc1749b752250a91c94f1cf8ba4f3eb5e8d'
|
||||
'SKIP'
|
||||
'b76c03e8c59c0d2c06d00130cbe4984932762107f3d8180f90ac6c63bd435d6b8dfd317b9d1e756a89c513a20bdb52dcf4f3887daa6598449e560ca1076c5a1d'
|
||||
'335c0c1164e9a2b9a9a252ddf7418ca0e6493f2f0fddcf3f01ae20666b6cb6713b8bf7a2a165d37485d2107b6c00f42b201974154c41c15c4456615b3bb0d78f'
|
||||
'SKIP'
|
||||
'01a28159b9c42e6b52147d1b061e1a2cb40ee381f8b6f7e2db3f94adc160365bc0dee602713cf42745fd2275b822b273df25d739d7b77f03273922edc746e50f'
|
||||
'SKIP'
|
||||
'42703ec988c2b1865fbe4eef67840f4370958e3e874d9f8a03a46c43619bed7656c56cae0ef1d8cca5340648b47ba7ddf813d25d9db3307f10146c45b8e34ade'
|
||||
'SKIP'
|
||||
@@ -482,7 +500,7 @@ b2sums=('5326dde778eb945f282740ef0d8765b46fbd198f1209cdfd7b91e5dac1312fc01f8bf0b
|
||||
'SKIP'
|
||||
'ae93d961d0eef41ed39c473fe9478b62fab13ba395333b3c11b34b7787904a3d2684520ec76dbe2603dd96a146a68bcbe98da1b7e4cc1e659246127384bce22c'
|
||||
'SKIP')
|
||||
b2sums_x86_64=('7bcc8b4bc054268c8aa7aec3c6db22d6773d4bca1322edc157c7d23095998eedb0c6698d042310fced5fd759347297c500d2fa987bd71684c8c043c395ce4fc8')
|
||||
b2sums_x86_64=('a1961cda00700926c9618bd311b83bdbc1a392c1dde41d541de9f091b750121cc879560ffd1c398ab75078588e0677726eedb84529a13d66be934c85be5f7a73')
|
||||
|
||||
# https://www.kernel.org/pub/linux/kernel/v7.x/sha256sums.asc
|
||||
sha256sums=('12e8d5a973d1ad7c5a5c69882e4022b131ed715db7003fdcd760ddf8c3e51941'
|
||||
@@ -735,6 +753,10 @@ sha256sums=('12e8d5a973d1ad7c5a5c69882e4022b131ed715db7003fdcd760ddf8c3e51941'
|
||||
'SKIP'
|
||||
'3175c56fd2935848ce99fe10be1bc348231909f8479c3d3af911c5c7ab7f381b'
|
||||
'SKIP'
|
||||
'30a12a616afa8fe95b969e90b42aeb240962b9fab8b8bd357ac00706abdd68c7'
|
||||
'SKIP'
|
||||
'eb0ebb8c55332dab8931c667ec84cd32c91c657d21af4504327ae05643108e1d'
|
||||
'SKIP'
|
||||
'945c90d99f9a9fa47d61e471f76d17c0229ffa0fa8cda22de990a2ccc4194bb2'
|
||||
'SKIP'
|
||||
'70ff41b2341836c27c5545a7948258f137d991c2879cbeb29f7af740c11d20e6'
|
||||
@@ -749,13 +771,21 @@ sha256sums=('12e8d5a973d1ad7c5a5c69882e4022b131ed715db7003fdcd760ddf8c3e51941'
|
||||
'SKIP'
|
||||
'a008c052ca657efcd4e27b8f7b819adbc9606e261aac37d41a40cf67c094cff9'
|
||||
'SKIP'
|
||||
'57169ef893dff957cbf33f7c0dc22f2fdfcfcb3befcd62ad59e2456484423bac'
|
||||
'SKIP'
|
||||
'01ecc1adbe715bb31153a2350ca46e1cb8a6e3fdc6899b2debeff015af2412ed'
|
||||
'SKIP'
|
||||
'a4331d3968fc5002534063b42bd219bddfe4a7d6b08e4cb30ed60f4366ca3c41'
|
||||
'SKIP'
|
||||
'028bf538c870465e1752514725372fa9eef6b7178d9b8d1e2ecc15edc5a63cc8'
|
||||
'SKIP'
|
||||
'a92a84405ee9845738c6b52d8f0f0eca16eb40afe0ebe0f4e9e1168597675311'
|
||||
'SKIP'
|
||||
'44a0b10a6dc83465ea86f5fba936b2bfbeffb1b3f0b2e04013bfed99ba4f6c5a'
|
||||
'SKIP'
|
||||
'ab4a43d7b8d56a4405aaebaac00dd33d2019cae407039fad4b0dae9ba1ffaa78'
|
||||
'6f01b5357af7deed3f4bccea6678b4d9e8afc83e598978f42f244241667f975d'
|
||||
'SKIP'
|
||||
'0da7247035a359e2491933f9effff43ea7b29748f21a0e3080bef0018c2488e3'
|
||||
'SKIP'
|
||||
'f81f6b5769e47716ca318ecf76ab1c0fafa0e165fa858a64251359937bffcf04'
|
||||
'SKIP'
|
||||
|
||||
@@ -670,6 +670,7 @@ CONFIG_ACPI_REV_OVERRIDE_POSSIBLE=y
|
||||
CONFIG_ACPI_EC=y
|
||||
CONFIG_ACPI_EC_DEBUGFS=m
|
||||
CONFIG_ACPI_AC=y
|
||||
CONFIG_ACPI_BATTERY_HOOKS=y
|
||||
CONFIG_ACPI_BATTERY=y
|
||||
CONFIG_ACPI_BUTTON=y
|
||||
CONFIG_ACPI_VIDEO=m
|
||||
|
||||
Reference in new issue
Block a user