Merge branch 'x86-platform-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 platform changes from Ingo Molnar: - Support for the Technologic Systems TS-5500 platform, by Vivien Didelot - Improved NUMA support on AMD systems: Add support for federated systems where multiple memory controllers can exist and see each other over multiple PCI domains. This basically means that AMD node ids can be more than 8 now and the code handling this is taught to incorporate PCI domain into those IDs. - Support for the Goldfish virtual Android emulator, by Jun Nakajima, Intel, Google, et al. - Misc fixlets. * 'x86-platform-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86: Add TS-5500 platform support x86/srat: Simplify memory affinity init error handling x86/apb/timer: Remove unnecessary "if" goldfish: platform device for x86 amd64_edac: Fix type usage in NB IDs and memory ranges amd64_edac: Fix PCI function lookup x86, AMD, NB: Use u16 for northbridge IDs in amd_get_nb_id x86, AMD, NB: Add multi-domain support
This commit is contained in:
commit
f98982ce80
15 changed files with 563 additions and 79 deletions
47
Documentation/ABI/testing/sysfs-platform-ts5500
Normal file
47
Documentation/ABI/testing/sysfs-platform-ts5500
Normal file
|
@ -0,0 +1,47 @@
|
|||
What: /sys/devices/platform/ts5500/adc
|
||||
Date: January 2013
|
||||
KernelVersion: 3.7
|
||||
Contact: "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com>
|
||||
Description:
|
||||
Indicates the presence of an A/D Converter. If it is present,
|
||||
it will display "1", otherwise "0".
|
||||
|
||||
What: /sys/devices/platform/ts5500/ereset
|
||||
Date: January 2013
|
||||
KernelVersion: 3.7
|
||||
Contact: "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com>
|
||||
Description:
|
||||
Indicates the presence of an external reset. If it is present,
|
||||
it will display "1", otherwise "0".
|
||||
|
||||
What: /sys/devices/platform/ts5500/id
|
||||
Date: January 2013
|
||||
KernelVersion: 3.7
|
||||
Contact: "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com>
|
||||
Description:
|
||||
Product ID of the TS board. TS-5500 ID is 0x60.
|
||||
|
||||
What: /sys/devices/platform/ts5500/jumpers
|
||||
Date: January 2013
|
||||
KernelVersion: 3.7
|
||||
Contact: "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com>
|
||||
Description:
|
||||
Bitfield showing the jumpers' state. If a jumper is present,
|
||||
the corresponding bit is set. For instance, 0x0e means jumpers
|
||||
2, 3 and 4 are set.
|
||||
|
||||
What: /sys/devices/platform/ts5500/rs485
|
||||
Date: January 2013
|
||||
KernelVersion: 3.7
|
||||
Contact: "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com>
|
||||
Description:
|
||||
Indicates the presence of the RS485 option. If it is present,
|
||||
it will display "1", otherwise "0".
|
||||
|
||||
What: /sys/devices/platform/ts5500/sram
|
||||
Date: January 2013
|
||||
KernelVersion: 3.7
|
||||
Contact: "Savoir-faire Linux Inc." <kernel@savoirfairelinux.com>
|
||||
Description:
|
||||
Indicates the presence of the SRAM option. If it is present,
|
||||
it will display "1", otherwise "0".
|
|
@ -7533,6 +7533,11 @@ F: drivers/net/team/
|
|||
F: include/linux/if_team.h
|
||||
F: include/uapi/linux/if_team.h
|
||||
|
||||
TECHNOLOGIC SYSTEMS TS-5500 PLATFORM SUPPORT
|
||||
M: Savoir-faire Linux Inc. <kernel@savoirfairelinux.com>
|
||||
S: Maintained
|
||||
F: arch/x86/platform/ts5500/
|
||||
|
||||
TECHNOTREND USB IR RECEIVER
|
||||
M: Sean Young <sean@mess.org>
|
||||
L: linux-media@vger.kernel.org
|
||||
|
|
|
@ -323,6 +323,10 @@ config X86_BIGSMP
|
|||
---help---
|
||||
This option is needed for the systems that have more than 8 CPUs
|
||||
|
||||
config GOLDFISH
|
||||
def_bool y
|
||||
depends on X86_GOLDFISH
|
||||
|
||||
if X86_32
|
||||
config X86_EXTENDED_PLATFORM
|
||||
bool "Support for extended (non-PC) x86 platforms"
|
||||
|
@ -405,6 +409,14 @@ config X86_UV
|
|||
# Following is an alphabetically sorted list of 32 bit extended platforms
|
||||
# Please maintain the alphabetic order if and when there are additions
|
||||
|
||||
config X86_GOLDFISH
|
||||
bool "Goldfish (Virtual Platform)"
|
||||
depends on X86_32
|
||||
---help---
|
||||
Enable support for the Goldfish virtual platform used primarily
|
||||
for Android development. Unless you are building for the Android
|
||||
Goldfish emulator say N here.
|
||||
|
||||
config X86_INTEL_CE
|
||||
bool "CE4100 TV platform"
|
||||
depends on PCI
|
||||
|
@ -2191,6 +2203,15 @@ config GEOS
|
|||
---help---
|
||||
This option enables system support for the Traverse Technologies GEOS.
|
||||
|
||||
config TS5500
|
||||
bool "Technologic Systems TS-5500 platform support"
|
||||
depends on MELAN
|
||||
select CHECK_SIGNATURE
|
||||
select NEW_LEDS
|
||||
select LEDS_CLASS
|
||||
---help---
|
||||
This option enables system support for the Technologic Systems TS-5500.
|
||||
|
||||
endif # X86_32
|
||||
|
||||
config AMD_NB
|
||||
|
|
|
@ -81,6 +81,23 @@ static inline struct amd_northbridge *node_to_amd_nb(int node)
|
|||
return (node < amd_northbridges.num) ? &amd_northbridges.nb[node] : NULL;
|
||||
}
|
||||
|
||||
static inline u16 amd_get_node_id(struct pci_dev *pdev)
|
||||
{
|
||||
struct pci_dev *misc;
|
||||
int i;
|
||||
|
||||
for (i = 0; i != amd_nb_num(); i++) {
|
||||
misc = node_to_amd_nb(i)->misc;
|
||||
|
||||
if (pci_domain_nr(misc->bus) == pci_domain_nr(pdev->bus) &&
|
||||
PCI_SLOT(misc->devfn) == PCI_SLOT(pdev->devfn))
|
||||
return i;
|
||||
}
|
||||
|
||||
WARN(1, "Unable to find AMD Northbridge id for %s\n", pci_name(pdev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define amd_nb_num(x) 0
|
||||
|
|
|
@ -943,7 +943,7 @@ extern void start_thread(struct pt_regs *regs, unsigned long new_ip,
|
|||
extern int get_tsc_mode(unsigned long adr);
|
||||
extern int set_tsc_mode(unsigned int val);
|
||||
|
||||
extern int amd_get_nb_id(int cpu);
|
||||
extern u16 amd_get_nb_id(int cpu);
|
||||
|
||||
struct aperfmperf {
|
||||
u64 aperf, mperf;
|
||||
|
|
|
@ -240,7 +240,7 @@ static int apbt_cpuhp_notify(struct notifier_block *n,
|
|||
dw_apb_clockevent_pause(adev->timer);
|
||||
if (system_state == SYSTEM_RUNNING) {
|
||||
pr_debug("skipping APBT CPU %lu offline\n", cpu);
|
||||
} else if (adev) {
|
||||
} else {
|
||||
pr_debug("APBT clockevent for cpu %lu offline\n", cpu);
|
||||
dw_apb_clockevent_stop(adev->timer);
|
||||
}
|
||||
|
|
|
@ -364,9 +364,9 @@ static void __cpuinit amd_detect_cmp(struct cpuinfo_x86 *c)
|
|||
#endif
|
||||
}
|
||||
|
||||
int amd_get_nb_id(int cpu)
|
||||
u16 amd_get_nb_id(int cpu)
|
||||
{
|
||||
int id = 0;
|
||||
u16 id = 0;
|
||||
#ifdef CONFIG_SMP
|
||||
id = per_cpu(cpu_llc_id, cpu);
|
||||
#endif
|
||||
|
|
|
@ -149,39 +149,40 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
|
|||
int node, pxm;
|
||||
|
||||
if (srat_disabled())
|
||||
return -1;
|
||||
if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) {
|
||||
bad_srat();
|
||||
return -1;
|
||||
}
|
||||
goto out_err;
|
||||
if (ma->header.length != sizeof(struct acpi_srat_mem_affinity))
|
||||
goto out_err_bad_srat;
|
||||
if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0)
|
||||
return -1;
|
||||
|
||||
goto out_err;
|
||||
if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info())
|
||||
return -1;
|
||||
goto out_err;
|
||||
|
||||
start = ma->base_address;
|
||||
end = start + ma->length;
|
||||
pxm = ma->proximity_domain;
|
||||
if (acpi_srat_revision <= 1)
|
||||
pxm &= 0xff;
|
||||
|
||||
node = setup_node(pxm);
|
||||
if (node < 0) {
|
||||
printk(KERN_ERR "SRAT: Too many proximity domains.\n");
|
||||
bad_srat();
|
||||
return -1;
|
||||
goto out_err_bad_srat;
|
||||
}
|
||||
|
||||
if (numa_add_memblk(node, start, end) < 0) {
|
||||
bad_srat();
|
||||
return -1;
|
||||
}
|
||||
if (numa_add_memblk(node, start, end) < 0)
|
||||
goto out_err_bad_srat;
|
||||
|
||||
node_set(node, numa_nodes_parsed);
|
||||
|
||||
printk(KERN_INFO "SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]\n",
|
||||
node, pxm,
|
||||
(unsigned long long) start, (unsigned long long) end - 1);
|
||||
|
||||
return 0;
|
||||
out_err_bad_srat:
|
||||
bad_srat();
|
||||
out_err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void __init acpi_numa_arch_fixup(void) {}
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
obj-y += ce4100/
|
||||
obj-y += efi/
|
||||
obj-y += geode/
|
||||
obj-y += goldfish/
|
||||
obj-y += iris/
|
||||
obj-y += mrst/
|
||||
obj-y += olpc/
|
||||
obj-y += scx200/
|
||||
obj-y += sfi/
|
||||
obj-y += ts5500/
|
||||
obj-y += visws/
|
||||
obj-y += uv/
|
||||
|
|
1
arch/x86/platform/goldfish/Makefile
Normal file
1
arch/x86/platform/goldfish/Makefile
Normal file
|
@ -0,0 +1 @@
|
|||
obj-$(CONFIG_GOLDFISH) += goldfish.o
|
51
arch/x86/platform/goldfish/goldfish.c
Normal file
51
arch/x86/platform/goldfish/goldfish.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (C) 2007 Google, Inc.
|
||||
* Copyright (C) 2011 Intel, Inc.
|
||||
* Copyright (C) 2013 Intel, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
/*
|
||||
* Where in virtual device memory the IO devices (timers, system controllers
|
||||
* and so on)
|
||||
*/
|
||||
|
||||
#define GOLDFISH_PDEV_BUS_BASE (0xff001000)
|
||||
#define GOLDFISH_PDEV_BUS_END (0xff7fffff)
|
||||
#define GOLDFISH_PDEV_BUS_IRQ (4)
|
||||
|
||||
#define GOLDFISH_TTY_BASE (0x2000)
|
||||
|
||||
static struct resource goldfish_pdev_bus_resources[] = {
|
||||
{
|
||||
.start = GOLDFISH_PDEV_BUS_BASE,
|
||||
.end = GOLDFISH_PDEV_BUS_END,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
{
|
||||
.start = GOLDFISH_PDEV_BUS_IRQ,
|
||||
.end = GOLDFISH_PDEV_BUS_IRQ,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
}
|
||||
};
|
||||
|
||||
static int __init goldfish_init(void)
|
||||
{
|
||||
platform_device_register_simple("goldfish_pdev_bus", -1,
|
||||
goldfish_pdev_bus_resources, 2);
|
||||
return 0;
|
||||
}
|
||||
device_initcall(goldfish_init);
|
1
arch/x86/platform/ts5500/Makefile
Normal file
1
arch/x86/platform/ts5500/Makefile
Normal file
|
@ -0,0 +1 @@
|
|||
obj-$(CONFIG_TS5500) += ts5500.o
|
339
arch/x86/platform/ts5500/ts5500.c
Normal file
339
arch/x86/platform/ts5500/ts5500.c
Normal file
|
@ -0,0 +1,339 @@
|
|||
/*
|
||||
* Technologic Systems TS-5500 Single Board Computer support
|
||||
*
|
||||
* Copyright (C) 2013 Savoir-faire Linux Inc.
|
||||
* Vivien Didelot <vivien.didelot@savoirfairelinux.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your option) any later
|
||||
* version.
|
||||
*
|
||||
*
|
||||
* This driver registers the Technologic Systems TS-5500 Single Board Computer
|
||||
* (SBC) and its devices, and exposes information to userspace such as jumpers'
|
||||
* state or available options. For further information about sysfs entries, see
|
||||
* Documentation/ABI/testing/sysfs-platform-ts5500.
|
||||
*
|
||||
* This code actually supports the TS-5500 platform, but it may be extended to
|
||||
* support similar Technologic Systems x86-based platforms, such as the TS-5600.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_data/gpio-ts5500.h>
|
||||
#include <linux/platform_data/max197.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* Product code register */
|
||||
#define TS5500_PRODUCT_CODE_ADDR 0x74
|
||||
#define TS5500_PRODUCT_CODE 0x60 /* TS-5500 product code */
|
||||
|
||||
/* SRAM/RS-485/ADC options, and RS-485 RTS/Automatic RS-485 flags register */
|
||||
#define TS5500_SRAM_RS485_ADC_ADDR 0x75
|
||||
#define TS5500_SRAM BIT(0) /* SRAM option */
|
||||
#define TS5500_RS485 BIT(1) /* RS-485 option */
|
||||
#define TS5500_ADC BIT(2) /* A/D converter option */
|
||||
#define TS5500_RS485_RTS BIT(6) /* RTS for RS-485 */
|
||||
#define TS5500_RS485_AUTO BIT(7) /* Automatic RS-485 */
|
||||
|
||||
/* External Reset/Industrial Temperature Range options register */
|
||||
#define TS5500_ERESET_ITR_ADDR 0x76
|
||||
#define TS5500_ERESET BIT(0) /* External Reset option */
|
||||
#define TS5500_ITR BIT(1) /* Indust. Temp. Range option */
|
||||
|
||||
/* LED/Jumpers register */
|
||||
#define TS5500_LED_JP_ADDR 0x77
|
||||
#define TS5500_LED BIT(0) /* LED flag */
|
||||
#define TS5500_JP1 BIT(1) /* Automatic CMOS */
|
||||
#define TS5500_JP2 BIT(2) /* Enable Serial Console */
|
||||
#define TS5500_JP3 BIT(3) /* Write Enable Drive A */
|
||||
#define TS5500_JP4 BIT(4) /* Fast Console (115K baud) */
|
||||
#define TS5500_JP5 BIT(5) /* User Jumper */
|
||||
#define TS5500_JP6 BIT(6) /* Console on COM1 (req. JP2) */
|
||||
#define TS5500_JP7 BIT(7) /* Undocumented (Unused) */
|
||||
|
||||
/* A/D Converter registers */
|
||||
#define TS5500_ADC_CONV_BUSY_ADDR 0x195 /* Conversion state register */
|
||||
#define TS5500_ADC_CONV_BUSY BIT(0)
|
||||
#define TS5500_ADC_CONV_INIT_LSB_ADDR 0x196 /* Start conv. / LSB register */
|
||||
#define TS5500_ADC_CONV_MSB_ADDR 0x197 /* MSB register */
|
||||
#define TS5500_ADC_CONV_DELAY 12 /* usec */
|
||||
|
||||
/**
|
||||
* struct ts5500_sbc - TS-5500 board description
|
||||
* @id: Board product ID.
|
||||
* @sram: Flag for SRAM option.
|
||||
* @rs485: Flag for RS-485 option.
|
||||
* @adc: Flag for Analog/Digital converter option.
|
||||
* @ereset: Flag for External Reset option.
|
||||
* @itr: Flag for Industrial Temperature Range option.
|
||||
* @jumpers: Bitfield for jumpers' state.
|
||||
*/
|
||||
struct ts5500_sbc {
|
||||
int id;
|
||||
bool sram;
|
||||
bool rs485;
|
||||
bool adc;
|
||||
bool ereset;
|
||||
bool itr;
|
||||
u8 jumpers;
|
||||
};
|
||||
|
||||
/* Board signatures in BIOS shadow RAM */
|
||||
static const struct {
|
||||
const char * const string;
|
||||
const ssize_t offset;
|
||||
} ts5500_signatures[] __initdata = {
|
||||
{ "TS-5x00 AMD Elan", 0xb14 },
|
||||
};
|
||||
|
||||
static int __init ts5500_check_signature(void)
|
||||
{
|
||||
void __iomem *bios;
|
||||
int i, ret = -ENODEV;
|
||||
|
||||
bios = ioremap(0xf0000, 0x10000);
|
||||
if (!bios)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ts5500_signatures); i++) {
|
||||
if (check_signature(bios + ts5500_signatures[i].offset,
|
||||
ts5500_signatures[i].string,
|
||||
strlen(ts5500_signatures[i].string))) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
iounmap(bios);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __init ts5500_detect_config(struct ts5500_sbc *sbc)
|
||||
{
|
||||
u8 tmp;
|
||||
int ret = 0;
|
||||
|
||||
if (!request_region(TS5500_PRODUCT_CODE_ADDR, 4, "ts5500"))
|
||||
return -EBUSY;
|
||||
|
||||
tmp = inb(TS5500_PRODUCT_CODE_ADDR);
|
||||
if (tmp != TS5500_PRODUCT_CODE) {
|
||||
pr_err("This platform is not a TS-5500 (found ID 0x%x)\n", tmp);
|
||||
ret = -ENODEV;
|
||||
goto cleanup;
|
||||
}
|
||||
sbc->id = tmp;
|
||||
|
||||
tmp = inb(TS5500_SRAM_RS485_ADC_ADDR);
|
||||
sbc->sram = tmp & TS5500_SRAM;
|
||||
sbc->rs485 = tmp & TS5500_RS485;
|
||||
sbc->adc = tmp & TS5500_ADC;
|
||||
|
||||
tmp = inb(TS5500_ERESET_ITR_ADDR);
|
||||
sbc->ereset = tmp & TS5500_ERESET;
|
||||
sbc->itr = tmp & TS5500_ITR;
|
||||
|
||||
tmp = inb(TS5500_LED_JP_ADDR);
|
||||
sbc->jumpers = tmp & ~TS5500_LED;
|
||||
|
||||
cleanup:
|
||||
release_region(TS5500_PRODUCT_CODE_ADDR, 4);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t ts5500_show_id(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct ts5500_sbc *sbc = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "0x%.2x\n", sbc->id);
|
||||
}
|
||||
|
||||
static ssize_t ts5500_show_jumpers(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ts5500_sbc *sbc = dev_get_drvdata(dev);
|
||||
|
||||
return sprintf(buf, "0x%.2x\n", sbc->jumpers >> 1);
|
||||
}
|
||||
|
||||
#define TS5500_SHOW(field) \
|
||||
static ssize_t ts5500_show_##field(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
char *buf) \
|
||||
{ \
|
||||
struct ts5500_sbc *sbc = dev_get_drvdata(dev); \
|
||||
return sprintf(buf, "%d\n", sbc->field); \
|
||||
}
|
||||
|
||||
TS5500_SHOW(sram)
|
||||
TS5500_SHOW(rs485)
|
||||
TS5500_SHOW(adc)
|
||||
TS5500_SHOW(ereset)
|
||||
TS5500_SHOW(itr)
|
||||
|
||||
static DEVICE_ATTR(id, S_IRUGO, ts5500_show_id, NULL);
|
||||
static DEVICE_ATTR(jumpers, S_IRUGO, ts5500_show_jumpers, NULL);
|
||||
static DEVICE_ATTR(sram, S_IRUGO, ts5500_show_sram, NULL);
|
||||
static DEVICE_ATTR(rs485, S_IRUGO, ts5500_show_rs485, NULL);
|
||||
static DEVICE_ATTR(adc, S_IRUGO, ts5500_show_adc, NULL);
|
||||
static DEVICE_ATTR(ereset, S_IRUGO, ts5500_show_ereset, NULL);
|
||||
static DEVICE_ATTR(itr, S_IRUGO, ts5500_show_itr, NULL);
|
||||
|
||||
static struct attribute *ts5500_attributes[] = {
|
||||
&dev_attr_id.attr,
|
||||
&dev_attr_jumpers.attr,
|
||||
&dev_attr_sram.attr,
|
||||
&dev_attr_rs485.attr,
|
||||
&dev_attr_adc.attr,
|
||||
&dev_attr_ereset.attr,
|
||||
&dev_attr_itr.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group ts5500_attr_group = {
|
||||
.attrs = ts5500_attributes,
|
||||
};
|
||||
|
||||
static struct resource ts5500_dio1_resource[] = {
|
||||
DEFINE_RES_IRQ_NAMED(7, "DIO1 interrupt"),
|
||||
};
|
||||
|
||||
static struct platform_device ts5500_dio1_pdev = {
|
||||
.name = "ts5500-dio1",
|
||||
.id = -1,
|
||||
.resource = ts5500_dio1_resource,
|
||||
.num_resources = 1,
|
||||
};
|
||||
|
||||
static struct resource ts5500_dio2_resource[] = {
|
||||
DEFINE_RES_IRQ_NAMED(6, "DIO2 interrupt"),
|
||||
};
|
||||
|
||||
static struct platform_device ts5500_dio2_pdev = {
|
||||
.name = "ts5500-dio2",
|
||||
.id = -1,
|
||||
.resource = ts5500_dio2_resource,
|
||||
.num_resources = 1,
|
||||
};
|
||||
|
||||
static void ts5500_led_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
outb(!!brightness, TS5500_LED_JP_ADDR);
|
||||
}
|
||||
|
||||
static enum led_brightness ts5500_led_get(struct led_classdev *led_cdev)
|
||||
{
|
||||
return (inb(TS5500_LED_JP_ADDR) & TS5500_LED) ? LED_FULL : LED_OFF;
|
||||
}
|
||||
|
||||
static struct led_classdev ts5500_led_cdev = {
|
||||
.name = "ts5500:green:",
|
||||
.brightness_set = ts5500_led_set,
|
||||
.brightness_get = ts5500_led_get,
|
||||
};
|
||||
|
||||
static int ts5500_adc_convert(u8 ctrl)
|
||||
{
|
||||
u8 lsb, msb;
|
||||
|
||||
/* Start conversion (ensure the 3 MSB are set to 0) */
|
||||
outb(ctrl & 0x1f, TS5500_ADC_CONV_INIT_LSB_ADDR);
|
||||
|
||||
/*
|
||||
* The platform has CPLD logic driving the A/D converter.
|
||||
* The conversion must complete within 11 microseconds,
|
||||
* otherwise we have to re-initiate a conversion.
|
||||
*/
|
||||
udelay(TS5500_ADC_CONV_DELAY);
|
||||
if (inb(TS5500_ADC_CONV_BUSY_ADDR) & TS5500_ADC_CONV_BUSY)
|
||||
return -EBUSY;
|
||||
|
||||
/* Read the raw data */
|
||||
lsb = inb(TS5500_ADC_CONV_INIT_LSB_ADDR);
|
||||
msb = inb(TS5500_ADC_CONV_MSB_ADDR);
|
||||
|
||||
return (msb << 8) | lsb;
|
||||
}
|
||||
|
||||
static struct max197_platform_data ts5500_adc_pdata = {
|
||||
.convert = ts5500_adc_convert,
|
||||
};
|
||||
|
||||
static struct platform_device ts5500_adc_pdev = {
|
||||
.name = "max197",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.platform_data = &ts5500_adc_pdata,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init ts5500_init(void)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct ts5500_sbc *sbc;
|
||||
int err;
|
||||
|
||||
/*
|
||||
* There is no DMI available or PCI bridge subvendor info,
|
||||
* only the BIOS provides a 16-bit identification call.
|
||||
* It is safer to find a signature in the BIOS shadow RAM.
|
||||
*/
|
||||
err = ts5500_check_signature();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
pdev = platform_device_register_simple("ts5500", -1, NULL, 0);
|
||||
if (IS_ERR(pdev))
|
||||
return PTR_ERR(pdev);
|
||||
|
||||
sbc = devm_kzalloc(&pdev->dev, sizeof(struct ts5500_sbc), GFP_KERNEL);
|
||||
if (!sbc) {
|
||||
err = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = ts5500_detect_config(sbc);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
platform_set_drvdata(pdev, sbc);
|
||||
|
||||
err = sysfs_create_group(&pdev->dev.kobj, &ts5500_attr_group);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
ts5500_dio1_pdev.dev.parent = &pdev->dev;
|
||||
if (platform_device_register(&ts5500_dio1_pdev))
|
||||
dev_warn(&pdev->dev, "DIO1 block registration failed\n");
|
||||
ts5500_dio2_pdev.dev.parent = &pdev->dev;
|
||||
if (platform_device_register(&ts5500_dio2_pdev))
|
||||
dev_warn(&pdev->dev, "DIO2 block registration failed\n");
|
||||
|
||||
if (led_classdev_register(&pdev->dev, &ts5500_led_cdev))
|
||||
dev_warn(&pdev->dev, "LED registration failed\n");
|
||||
|
||||
if (sbc->adc) {
|
||||
ts5500_adc_pdev.dev.parent = &pdev->dev;
|
||||
if (platform_device_register(&ts5500_adc_pdev))
|
||||
dev_warn(&pdev->dev, "ADC registration failed\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
error:
|
||||
platform_device_unregister(pdev);
|
||||
return err;
|
||||
}
|
||||
device_initcall(ts5500_init);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Savoir-faire Linux Inc. <kernel@savoirfairelinux.com>");
|
||||
MODULE_DESCRIPTION("Technologic Systems TS-5500 platform driver");
|
|
@ -31,7 +31,7 @@ static struct ecc_settings **ecc_stngs;
|
|||
*
|
||||
*FIXME: Produce a better mapping/linearisation.
|
||||
*/
|
||||
struct scrubrate {
|
||||
static const struct scrubrate {
|
||||
u32 scrubval; /* bit pattern for scrub rate */
|
||||
u32 bandwidth; /* bandwidth consumed (bytes/sec) */
|
||||
} scrubrates[] = {
|
||||
|
@ -239,7 +239,7 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci)
|
|||
* DRAM base/limit associated with node_id
|
||||
*/
|
||||
static bool amd64_base_limit_match(struct amd64_pvt *pvt, u64 sys_addr,
|
||||
unsigned nid)
|
||||
u8 nid)
|
||||
{
|
||||
u64 addr;
|
||||
|
||||
|
@ -265,7 +265,7 @@ static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
|
|||
u64 sys_addr)
|
||||
{
|
||||
struct amd64_pvt *pvt;
|
||||
unsigned node_id;
|
||||
u8 node_id;
|
||||
u32 intlv_en, bits;
|
||||
|
||||
/*
|
||||
|
@ -939,7 +939,8 @@ static u64 get_error_address(struct mce *m)
|
|||
struct amd64_pvt *pvt;
|
||||
u64 cc6_base, tmp_addr;
|
||||
u32 tmp;
|
||||
u8 mce_nid, intlv_en;
|
||||
u16 mce_nid;
|
||||
u8 intlv_en;
|
||||
|
||||
if ((addr & GENMASK(24, 47)) >> 24 != 0x00fdf7)
|
||||
return addr;
|
||||
|
@ -979,10 +980,29 @@ static u64 get_error_address(struct mce *m)
|
|||
return addr;
|
||||
}
|
||||
|
||||
static struct pci_dev *pci_get_related_function(unsigned int vendor,
|
||||
unsigned int device,
|
||||
struct pci_dev *related)
|
||||
{
|
||||
struct pci_dev *dev = NULL;
|
||||
|
||||
while ((dev = pci_get_device(vendor, device, dev))) {
|
||||
if (pci_domain_nr(dev->bus) == pci_domain_nr(related->bus) &&
|
||||
(dev->bus->number == related->bus->number) &&
|
||||
(PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
|
||||
break;
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
|
||||
{
|
||||
struct amd_northbridge *nb;
|
||||
struct pci_dev *misc, *f1 = NULL;
|
||||
struct cpuinfo_x86 *c = &boot_cpu_data;
|
||||
int off = range << 3;
|
||||
u32 llim;
|
||||
|
||||
amd64_read_pci_cfg(pvt->F1, DRAM_BASE_LO + off, &pvt->ranges[range].base.lo);
|
||||
amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_LO + off, &pvt->ranges[range].lim.lo);
|
||||
|
@ -996,30 +1016,32 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
|
|||
amd64_read_pci_cfg(pvt->F1, DRAM_BASE_HI + off, &pvt->ranges[range].base.hi);
|
||||
amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi);
|
||||
|
||||
/* Factor in CC6 save area by reading dst node's limit reg */
|
||||
if (c->x86 == 0x15) {
|
||||
struct pci_dev *f1 = NULL;
|
||||
u8 nid = dram_dst_node(pvt, range);
|
||||
u32 llim;
|
||||
/* F15h: factor in CC6 save area by reading dst node's limit reg */
|
||||
if (c->x86 != 0x15)
|
||||
return;
|
||||
|
||||
f1 = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0x18 + nid, 1));
|
||||
if (WARN_ON(!f1))
|
||||
return;
|
||||
nb = node_to_amd_nb(dram_dst_node(pvt, range));
|
||||
if (WARN_ON(!nb))
|
||||
return;
|
||||
|
||||
amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim);
|
||||
misc = nb->misc;
|
||||
f1 = pci_get_related_function(misc->vendor, PCI_DEVICE_ID_AMD_15H_NB_F1, misc);
|
||||
if (WARN_ON(!f1))
|
||||
return;
|
||||
|
||||
pvt->ranges[range].lim.lo &= GENMASK(0, 15);
|
||||
amd64_read_pci_cfg(f1, DRAM_LOCAL_NODE_LIM, &llim);
|
||||
|
||||
/* {[39:27],111b} */
|
||||
pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16;
|
||||
pvt->ranges[range].lim.lo &= GENMASK(0, 15);
|
||||
|
||||
pvt->ranges[range].lim.hi &= GENMASK(0, 7);
|
||||
/* {[39:27],111b} */
|
||||
pvt->ranges[range].lim.lo |= ((llim & 0x1fff) << 3 | 0x7) << 16;
|
||||
|
||||
/* [47:40] */
|
||||
pvt->ranges[range].lim.hi |= llim >> 13;
|
||||
pvt->ranges[range].lim.hi &= GENMASK(0, 7);
|
||||
|
||||
pci_dev_put(f1);
|
||||
}
|
||||
/* [47:40] */
|
||||
pvt->ranges[range].lim.hi |= llim >> 13;
|
||||
|
||||
pci_dev_put(f1);
|
||||
}
|
||||
|
||||
static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
|
||||
|
@ -1305,7 +1327,7 @@ static u8 f1x_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
|
|||
}
|
||||
|
||||
/* Convert the sys_addr to the normalized DCT address */
|
||||
static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, unsigned range,
|
||||
static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, u8 range,
|
||||
u64 sys_addr, bool hi_rng,
|
||||
u32 dct_sel_base_addr)
|
||||
{
|
||||
|
@ -1381,7 +1403,7 @@ static int f10_process_possible_spare(struct amd64_pvt *pvt, u8 dct, int csrow)
|
|||
* -EINVAL: NOT FOUND
|
||||
* 0..csrow = Chip-Select Row
|
||||
*/
|
||||
static int f1x_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct)
|
||||
static int f1x_lookup_addr_in_dct(u64 in_addr, u8 nid, u8 dct)
|
||||
{
|
||||
struct mem_ctl_info *mci;
|
||||
struct amd64_pvt *pvt;
|
||||
|
@ -1672,23 +1694,6 @@ static struct amd64_family_type amd64_family_types[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct pci_dev *pci_get_related_function(unsigned int vendor,
|
||||
unsigned int device,
|
||||
struct pci_dev *related)
|
||||
{
|
||||
struct pci_dev *dev = NULL;
|
||||
|
||||
dev = pci_get_device(vendor, device, dev);
|
||||
while (dev) {
|
||||
if ((dev->bus->number == related->bus->number) &&
|
||||
(PCI_SLOT(dev->devfn) == PCI_SLOT(related->devfn)))
|
||||
break;
|
||||
dev = pci_get_device(vendor, device, dev);
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
/*
|
||||
* These are tables of eigenvectors (one per line) which can be used for the
|
||||
* construction of the syndrome tables. The modified syndrome search algorithm
|
||||
|
@ -1696,7 +1701,7 @@ static struct pci_dev *pci_get_related_function(unsigned int vendor,
|
|||
*
|
||||
* Algorithm courtesy of Ross LaFetra from AMD.
|
||||
*/
|
||||
static u16 x4_vectors[] = {
|
||||
static const u16 x4_vectors[] = {
|
||||
0x2f57, 0x1afe, 0x66cc, 0xdd88,
|
||||
0x11eb, 0x3396, 0x7f4c, 0xeac8,
|
||||
0x0001, 0x0002, 0x0004, 0x0008,
|
||||
|
@ -1735,7 +1740,7 @@ static u16 x4_vectors[] = {
|
|||
0x19a9, 0x2efe, 0xb5cc, 0x6f88,
|
||||
};
|
||||
|
||||
static u16 x8_vectors[] = {
|
||||
static const u16 x8_vectors[] = {
|
||||
0x0145, 0x028a, 0x2374, 0x43c8, 0xa1f0, 0x0520, 0x0a40, 0x1480,
|
||||
0x0211, 0x0422, 0x0844, 0x1088, 0x01b0, 0x44e0, 0x23c0, 0xed80,
|
||||
0x1011, 0x0116, 0x022c, 0x0458, 0x08b0, 0x8c60, 0x2740, 0x4e80,
|
||||
|
@ -1757,7 +1762,7 @@ static u16 x8_vectors[] = {
|
|||
0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000,
|
||||
};
|
||||
|
||||
static int decode_syndrome(u16 syndrome, u16 *vectors, unsigned num_vecs,
|
||||
static int decode_syndrome(u16 syndrome, const u16 *vectors, unsigned num_vecs,
|
||||
unsigned v_dim)
|
||||
{
|
||||
unsigned int i, err_sym;
|
||||
|
@ -2181,7 +2186,7 @@ static int init_csrows(struct mem_ctl_info *mci)
|
|||
}
|
||||
|
||||
/* get all cores on this DCT */
|
||||
static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, unsigned nid)
|
||||
static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, u16 nid)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
|
@ -2191,7 +2196,7 @@ static void get_cpus_on_this_dct_cpumask(struct cpumask *mask, unsigned nid)
|
|||
}
|
||||
|
||||
/* check MCG_CTL on all the cpus on this node */
|
||||
static bool amd64_nb_mce_bank_enabled_on_node(unsigned nid)
|
||||
static bool amd64_nb_mce_bank_enabled_on_node(u16 nid)
|
||||
{
|
||||
cpumask_var_t mask;
|
||||
int cpu, nbe;
|
||||
|
@ -2224,7 +2229,7 @@ static bool amd64_nb_mce_bank_enabled_on_node(unsigned nid)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int toggle_ecc_err_reporting(struct ecc_settings *s, u8 nid, bool on)
|
||||
static int toggle_ecc_err_reporting(struct ecc_settings *s, u16 nid, bool on)
|
||||
{
|
||||
cpumask_var_t cmask;
|
||||
int cpu;
|
||||
|
@ -2262,7 +2267,7 @@ static int toggle_ecc_err_reporting(struct ecc_settings *s, u8 nid, bool on)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,
|
||||
static bool enable_ecc_error_reporting(struct ecc_settings *s, u16 nid,
|
||||
struct pci_dev *F3)
|
||||
{
|
||||
bool ret = true;
|
||||
|
@ -2314,7 +2319,7 @@ static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void restore_ecc_error_reporting(struct ecc_settings *s, u8 nid,
|
||||
static void restore_ecc_error_reporting(struct ecc_settings *s, u16 nid,
|
||||
struct pci_dev *F3)
|
||||
{
|
||||
u32 value, mask = 0x3; /* UECC/CECC enable */
|
||||
|
@ -2353,7 +2358,7 @@ static const char *ecc_msg =
|
|||
"'ecc_enable_override'.\n"
|
||||
" (Note that use of the override may cause unknown side effects.)\n";
|
||||
|
||||
static bool ecc_enabled(struct pci_dev *F3, u8 nid)
|
||||
static bool ecc_enabled(struct pci_dev *F3, u16 nid)
|
||||
{
|
||||
u32 value;
|
||||
u8 ecc_en = 0;
|
||||
|
@ -2474,7 +2479,7 @@ static int amd64_init_one_instance(struct pci_dev *F2)
|
|||
struct mem_ctl_info *mci = NULL;
|
||||
struct edac_mc_layer layers[2];
|
||||
int err = 0, ret;
|
||||
u8 nid = get_node_id(F2);
|
||||
u16 nid = amd_get_node_id(F2);
|
||||
|
||||
ret = -ENOMEM;
|
||||
pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL);
|
||||
|
@ -2566,7 +2571,7 @@ static int amd64_init_one_instance(struct pci_dev *F2)
|
|||
static int amd64_probe_one_instance(struct pci_dev *pdev,
|
||||
const struct pci_device_id *mc_type)
|
||||
{
|
||||
u8 nid = get_node_id(pdev);
|
||||
u16 nid = amd_get_node_id(pdev);
|
||||
struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
|
||||
struct ecc_settings *s;
|
||||
int ret = 0;
|
||||
|
@ -2616,7 +2621,7 @@ static void amd64_remove_one_instance(struct pci_dev *pdev)
|
|||
{
|
||||
struct mem_ctl_info *mci;
|
||||
struct amd64_pvt *pvt;
|
||||
u8 nid = get_node_id(pdev);
|
||||
u16 nid = amd_get_node_id(pdev);
|
||||
struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
|
||||
struct ecc_settings *s = ecc_stngs[nid];
|
||||
|
||||
|
|
|
@ -292,12 +292,6 @@
|
|||
/* MSRs */
|
||||
#define MSR_MCGCTL_NBE BIT(4)
|
||||
|
||||
/* AMD sets the first MC device at device ID 0x18. */
|
||||
static inline u8 get_node_id(struct pci_dev *pdev)
|
||||
{
|
||||
return PCI_SLOT(pdev->devfn) - 0x18;
|
||||
}
|
||||
|
||||
enum amd_families {
|
||||
K8_CPUS = 0,
|
||||
F10_CPUS,
|
||||
|
@ -340,7 +334,7 @@ struct amd64_pvt {
|
|||
/* pci_device handles which we utilize */
|
||||
struct pci_dev *F1, *F2, *F3;
|
||||
|
||||
unsigned mc_node_id; /* MC index of this MC node */
|
||||
u16 mc_node_id; /* MC index of this MC node */
|
||||
int ext_model; /* extended model value of this node */
|
||||
int channel_count;
|
||||
|
||||
|
@ -393,7 +387,7 @@ struct err_info {
|
|||
u32 offset;
|
||||
};
|
||||
|
||||
static inline u64 get_dram_base(struct amd64_pvt *pvt, unsigned i)
|
||||
static inline u64 get_dram_base(struct amd64_pvt *pvt, u8 i)
|
||||
{
|
||||
u64 addr = ((u64)pvt->ranges[i].base.lo & 0xffff0000) << 8;
|
||||
|
||||
|
@ -403,7 +397,7 @@ static inline u64 get_dram_base(struct amd64_pvt *pvt, unsigned i)
|
|||
return (((u64)pvt->ranges[i].base.hi & 0x000000ff) << 40) | addr;
|
||||
}
|
||||
|
||||
static inline u64 get_dram_limit(struct amd64_pvt *pvt, unsigned i)
|
||||
static inline u64 get_dram_limit(struct amd64_pvt *pvt, u8 i)
|
||||
{
|
||||
u64 lim = (((u64)pvt->ranges[i].lim.lo & 0xffff0000) << 8) | 0x00ffffff;
|
||||
|
||||
|
|
Loading…
Reference in a new issue