Merge pull request #836 from kwilczynski/feature/update-kernel-releases
Update Linux kernel release to v7.2.8-5 for base and BORE kernels
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
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"source": "local",
|
||||
"skip_build": true
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loaded 100 of 325 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user