Skip to content

Commit

Permalink
treewide: Consolidate Apple DMI checks
Browse files Browse the repository at this point in the history
We're about to amend ACPI bus scan with DMI checks whether we're running
on a Mac to support Apple device properties in AML.  The DMI checks are
performed for every single device, adding overhead for everything x86
that isn't Apple, which is the majority.  Rafael and Andy therefore
request to perform the DMI match only once and cache the result.

Outside of ACPI various other Apple DMI checks exist and it seems
reasonable to use the cached value there as well.  Rafael, Andy and
Darren suggest performing the DMI check in arch code and making it
available with a header in include/linux/platform_data/x86/.

To this end, add early_platform_quirks() to arch/x86/kernel/quirks.c
to perform the DMI check and invoke it from setup_arch().  Switch over
all existing Apple DMI checks, thereby fixing two deficiencies:

* They are now #defined to false on non-x86 arches and can thus be
  optimized away if they're located in cross-arch code.

* Some of them only match "Apple Inc." but not "Apple Computer, Inc.",
  which is used by BIOSes released between January 2006 (when the first
  x86 Macs started shipping) and January 2007 (when the company name
  changed upon introduction of the iPhone).

Cc: Lv Zheng <lv.zheng@intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Matt Fleming <matt@codeblueprint.co.uk>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Andreas Noever <andreas.noever@gmail.com>
Cc: Michael Jamet <michael.jamet@intel.com>
Cc: Yehezkel Bernat <yehezkel.bernat@intel.com>
Cc: Mika Westerberg <mika.westerberg@linux.intel.com>
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Suggested-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Suggested-by: Darren Hart <dvhart@infradead.org>
Signed-off-by: Lukas Wunner <lukas@wunner.de>
  • Loading branch information
l1k committed Jul 31, 2017
1 parent 8a5f8e8 commit 20f8b74
Show file tree
Hide file tree
Showing 12 changed files with 51 additions and 72 deletions.
1 change: 1 addition & 0 deletions arch/x86/include/asm/setup.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ static inline void vsmp_init(void) { }
#endif

void setup_bios_corruption_check(void);
void early_platform_quirks(void);

extern unsigned long saved_video_mode;

Expand Down
4 changes: 2 additions & 2 deletions arch/x86/kernel/early-quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
#include <linux/pci.h>
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/pci_ids.h>
#include <linux/bcma/bcma.h>
#include <linux/bcma/bcma_regs.h>
#include <linux/platform_data/x86/apple.h>
#include <drm/i915_drm.h>
#include <asm/pci-direct.h>
#include <asm/dma.h>
Expand Down Expand Up @@ -593,7 +593,7 @@ static void __init apple_airport_reset(int bus, int slot, int func)
u64 addr;
int i;

if (!dmi_match(DMI_SYS_VENDOR, "Apple Inc."))
if (!x86_apple_machine)
return;

/* Card may have been put into PCI_D3hot by grub quirk */
Expand Down
10 changes: 10 additions & 0 deletions arch/x86/kernel/quirks.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* This file contains work-arounds for x86 and x86_64 platform bugs.
*/
#include <linux/dmi.h>
#include <linux/pci.h>
#include <linux/irq.h>

Expand Down Expand Up @@ -656,3 +657,12 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x6fc0, quirk_intel_brickland_xeon_
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x2083, quirk_intel_purley_xeon_ras_cap);
#endif
#endif

bool x86_apple_machine;
EXPORT_SYMBOL(x86_apple_machine);

void __init early_platform_quirks(void)
{
x86_apple_machine = dmi_match(DMI_SYS_VENDOR, "Apple Inc.") ||
dmi_match(DMI_SYS_VENDOR, "Apple Computer, Inc.");
}
2 changes: 2 additions & 0 deletions arch/x86/kernel/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -1206,6 +1206,8 @@ void __init setup_arch(char **cmdline_p)

io_delay_init();

early_platform_quirks();

/*
* Parse the ACPI tables for possible boot-time SMP configuration.
*/
Expand Down
37 changes: 8 additions & 29 deletions drivers/acpi/osi.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <linux/kernel.h>
#include <linux/acpi.h>
#include <linux/dmi.h>
#include <linux/platform_data/x86/apple.h>

#include "internal.h"

Expand Down Expand Up @@ -257,12 +258,11 @@ bool acpi_osi_is_win8(void)
}
EXPORT_SYMBOL(acpi_osi_is_win8);

static void __init acpi_osi_dmi_darwin(bool enable,
const struct dmi_system_id *d)
static void __init acpi_osi_dmi_darwin(void)
{
pr_notice("DMI detected to setup _OSI(\"Darwin\"): %s\n", d->ident);
pr_notice("DMI detected to setup _OSI(\"Darwin\"): Apple hardware\n");
osi_config.darwin_dmi = 1;
__acpi_osi_setup_darwin(enable);
__acpi_osi_setup_darwin(true);
}

static void __init acpi_osi_dmi_linux(bool enable,
Expand All @@ -273,13 +273,6 @@ static void __init acpi_osi_dmi_linux(bool enable,
__acpi_osi_setup_linux(enable);
}

static int __init dmi_enable_osi_darwin(const struct dmi_system_id *d)
{
acpi_osi_dmi_darwin(true, d);

return 0;
}

static int __init dmi_enable_osi_linux(const struct dmi_system_id *d)
{
acpi_osi_dmi_linux(true, d);
Expand Down Expand Up @@ -481,30 +474,16 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "1015PX"),
},
},

/*
* Enable _OSI("Darwin") for all apple platforms.
*/
{
.callback = dmi_enable_osi_darwin,
.ident = "Apple hardware",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
},
},
{
.callback = dmi_enable_osi_darwin,
.ident = "Apple hardware",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."),
},
},
{}
};

static __init void acpi_osi_dmi_blacklisted(void)
{
dmi_check_system(acpi_osi_dmi_table);

/* Enable _OSI("Darwin") for Apple platforms. */
if (x86_apple_machine)
acpi_osi_dmi_darwin();
}

int __init early_acpi_osi_init(void)
Expand Down
4 changes: 2 additions & 2 deletions drivers/acpi/pci_root.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <linux/acpi.h>
#include <linux/slab.h>
#include <linux/dmi.h>
#include <linux/platform_data/x86/apple.h>
#include <acpi/apei.h> /* for acpi_hest_init() */

#include "internal.h"
Expand Down Expand Up @@ -431,8 +432,7 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm)
* been called successfully. We know the feature set supported by the
* platform, so avoid calling _OSC at all
*/

if (dmi_match(DMI_SYS_VENDOR, "Apple Inc.")) {
if (x86_apple_machine) {
root->osc_control_set = ~OSC_PCI_EXPRESS_PME_CONTROL;
decode_osc_control(root, "OS assumes control of",
root->osc_control_set);
Expand Down
25 changes: 2 additions & 23 deletions drivers/acpi/sbs.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
#include <linux/jiffies.h>
#include <linux/delay.h>
#include <linux/power_supply.h>
#include <linux/dmi.h>
#include <linux/platform_data/x86/apple.h>

#include "sbshc.h"
#include "battery.h"
Expand All @@ -58,8 +58,6 @@ static unsigned int cache_time = 1000;
module_param(cache_time, uint, 0644);
MODULE_PARM_DESC(cache_time, "cache time in milliseconds");

static bool sbs_manager_broken;

#define MAX_SBS_BAT 4
#define ACPI_SBS_BLOCK_MAX 32

Expand Down Expand Up @@ -632,31 +630,12 @@ static void acpi_sbs_callback(void *context)
}
}

static int disable_sbs_manager(const struct dmi_system_id *d)
{
sbs_manager_broken = true;
return 0;
}

static struct dmi_system_id acpi_sbs_dmi_table[] = {
{
.callback = disable_sbs_manager,
.ident = "Apple",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc.")
},
},
{ },
};

static int acpi_sbs_add(struct acpi_device *device)
{
struct acpi_sbs *sbs;
int result = 0;
int id;

dmi_check_system(acpi_sbs_dmi_table);

sbs = kzalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
if (!sbs) {
result = -ENOMEM;
Expand All @@ -677,7 +656,7 @@ static int acpi_sbs_add(struct acpi_device *device)

result = 0;

if (!sbs_manager_broken) {
if (!x86_apple_machine) {
result = acpi_manager_get_info(sbs);
if (!result) {
sbs->manager_present = 1;
Expand Down
5 changes: 2 additions & 3 deletions drivers/firmware/efi/apple-properties.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
#define pr_fmt(fmt) "apple-properties: " fmt

#include <linux/bootmem.h>
#include <linux/dmi.h>
#include <linux/efi.h>
#include <linux/platform_data/x86/apple.h>
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/ucs2_string.h>
Expand Down Expand Up @@ -191,8 +191,7 @@ static int __init map_properties(void)
u64 pa_data;
int ret;

if (!dmi_match(DMI_SYS_VENDOR, "Apple Inc.") &&
!dmi_match(DMI_SYS_VENDOR, "Apple Computer, Inc."))
if (!x86_apple_machine)
return 0;

pa_data = boot_params.hdr.setup_data;
Expand Down
5 changes: 3 additions & 2 deletions drivers/pci/quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <linux/sched.h>
#include <linux/ktime.h>
#include <linux/mm.h>
#include <linux/platform_data/x86/apple.h>
#include <asm/dma.h> /* isa_dma_bridge_buggy */
#include "pci.h"

Expand Down Expand Up @@ -3447,7 +3448,7 @@ static void quirk_apple_poweroff_thunderbolt(struct pci_dev *dev)
{
acpi_handle bridge, SXIO, SXFP, SXLV;

if (!dmi_match(DMI_BOARD_VENDOR, "Apple Inc."))
if (!x86_apple_machine)
return;
if (pci_pcie_type(dev) != PCI_EXP_TYPE_UPSTREAM)
return;
Expand Down Expand Up @@ -3492,7 +3493,7 @@ static void quirk_apple_wait_for_thunderbolt(struct pci_dev *dev)
struct pci_dev *sibling = NULL;
struct pci_dev *nhi = NULL;

if (!dmi_match(DMI_BOARD_VENDOR, "Apple Inc."))
if (!x86_apple_machine)
return;
if (pci_pcie_type(dev) != PCI_EXP_TYPE_DOWNSTREAM)
return;
Expand Down
13 changes: 4 additions & 9 deletions drivers/thunderbolt/icm.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
*/

#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/platform_data/x86/apple.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
Expand Down Expand Up @@ -102,11 +102,6 @@ static inline u64 get_route(u32 route_hi, u32 route_lo)
return (u64)route_hi << 32 | route_lo;
}

static inline bool is_apple(void)
{
return dmi_match(DMI_BOARD_VENDOR, "Apple Inc.");
}

static bool icm_match(const struct tb_cfg_request *req,
const struct ctl_pkg *pkg)
{
Expand Down Expand Up @@ -176,7 +171,7 @@ static int icm_request(struct tb *tb, const void *request, size_t request_size,

static bool icm_fr_is_supported(struct tb *tb)
{
return !is_apple();
return !x86_apple_machine;
}

static inline int icm_fr_get_switch_index(u32 port)
Expand Down Expand Up @@ -517,7 +512,7 @@ static bool icm_ar_is_supported(struct tb *tb)
* Starting from Alpine Ridge we can use ICM on Apple machines
* as well. We just need to reset and re-enable it first.
*/
if (!is_apple())
if (!x86_apple_machine)
return true;

/*
Expand Down Expand Up @@ -1011,7 +1006,7 @@ static int icm_start(struct tb *tb)
* don't provide images publicly either. To be on the safe side
* prevent root switch NVM upgrade on Macs for now.
*/
tb->root_switch->no_nvm_upgrade = is_apple();
tb->root_switch->no_nvm_upgrade = x86_apple_machine;

ret = tb_switch_add(tb->root_switch);
if (ret)
Expand Down
4 changes: 2 additions & 2 deletions drivers/thunderbolt/tb.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/dmi.h>
#include <linux/platform_data/x86/apple.h>

#include "tb.h"
#include "tb_regs.h"
Expand Down Expand Up @@ -453,7 +453,7 @@ struct tb *tb_probe(struct tb_nhi *nhi)
struct tb_cm *tcm;
struct tb *tb;

if (!dmi_match(DMI_BOARD_VENDOR, "Apple Inc."))
if (!x86_apple_machine)
return NULL;

tb = tb_domain_alloc(nhi, sizeof(*tcm));
Expand Down
13 changes: 13 additions & 0 deletions include/linux/platform_data/x86/apple.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef PLATFORM_DATA_X86_APPLE_H
#define PLATFORM_DATA_X86_APPLE_H

#ifdef CONFIG_X86
/**
* x86_apple_machine - whether the machine is an x86 Apple Macintosh
*/
extern bool x86_apple_machine;
#else
#define x86_apple_machine false
#endif

#endif

3 comments on commit 20f8b74

@andy-shev
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't you include a new header to arch/x86/kernel/quirks.c as well?

@andy-shev
Copy link

@andy-shev andy-shev commented on 20f8b74 Jul 31, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dunno about differences in the BIOS of 2006 vs 2007, but if we by some reason need to distuinguish them now or in the future, would be better to use bitwise flags:

#include <linux/bitops.h>

#define APPLE_HW_2006  BIT(0)
#define APPLE_HW_2007  BIT(1)

extern unsigned int x86_apple_machine;

...

unsigned int x86_apple_machine;
EXPORT_SYMBOL(x86_apple_machine);
...
if (dmi_match(DMI_SYS_VENDOR, "Apple Inc."))
    x86_apple_machine |= HW_2007;
if (dmi_match(DMI_SYS_VENDOR, "Apple Computer, Inc."))
    x86_apple_machine |= HW_2006;

@l1k
Copy link
Owner Author

@l1k l1k commented on 20f8b74 Aug 1, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't you include a new header to arch/x86/kernel/quirks.c as well?

This file only needs <linux/dmi.h> (which I've added). The new header <linux/platform_data/x86/apple.h> is only needed by files that subsequently query the new boolean x86_apple_machine.

I dunno about differences in the BIOS of 2006 vs 2007, but if we by some reason need to distuinguish them now or in the future, would be better to use bitwise flags

It was just a change of the company name, AFAIK it didn't have any technical impact on the BIOSes. There are certainly changes between BIOS versions but I think nothing that would be distinguishable based on the company name. A check for DMI_BIOS_DATE or DMI_BIOS_VERSION would seem more appropriate in such a case.

Thanks!

Please sign in to comment.