cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

leds-ss4200.c (14373B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * SS4200-E Hardware API
      4 * Copyright (c) 2009, Intel Corporation.
      5 * Copyright IBM Corporation, 2009
      6 *
      7 * Author: Dave Hansen <dave@sr71.net>
      8 */
      9
     10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     11
     12#include <linux/dmi.h>
     13#include <linux/init.h>
     14#include <linux/ioport.h>
     15#include <linux/kernel.h>
     16#include <linux/leds.h>
     17#include <linux/module.h>
     18#include <linux/pci.h>
     19#include <linux/types.h>
     20#include <linux/uaccess.h>
     21
     22MODULE_AUTHOR("Rodney Girod <rgirod@confocus.com>, Dave Hansen <dave@sr71.net>");
     23MODULE_DESCRIPTION("Intel NAS/Home Server ICH7 GPIO Driver");
     24MODULE_LICENSE("GPL");
     25
     26/*
     27 * ICH7 LPC/GPIO PCI Config register offsets
     28 */
     29#define PMBASE		0x040
     30#define GPIO_BASE	0x048
     31#define GPIO_CTRL	0x04c
     32#define GPIO_EN		0x010
     33
     34/*
     35 * The ICH7 GPIO register block is 64 bytes in size.
     36 */
     37#define ICH7_GPIO_SIZE	64
     38
     39/*
     40 * Define register offsets within the ICH7 register block.
     41 */
     42#define GPIO_USE_SEL	0x000
     43#define GP_IO_SEL	0x004
     44#define GP_LVL		0x00c
     45#define GPO_BLINK	0x018
     46#define GPI_INV		0x030
     47#define GPIO_USE_SEL2	0x034
     48#define GP_IO_SEL2	0x038
     49#define GP_LVL2		0x03c
     50
     51/*
     52 * PCI ID of the Intel ICH7 LPC Device within which the GPIO block lives.
     53 */
     54static const struct pci_device_id ich7_lpc_pci_id[] = {
     55	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0) },
     56	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1) },
     57	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_30) },
     58	{ } /* NULL entry */
     59};
     60
     61MODULE_DEVICE_TABLE(pci, ich7_lpc_pci_id);
     62
     63static int __init ss4200_led_dmi_callback(const struct dmi_system_id *id)
     64{
     65	pr_info("detected '%s'\n", id->ident);
     66	return 1;
     67}
     68
     69static bool nodetect;
     70module_param_named(nodetect, nodetect, bool, 0);
     71MODULE_PARM_DESC(nodetect, "Skip DMI-based hardware detection");
     72
     73/*
     74 * struct nas_led_whitelist - List of known good models
     75 *
     76 * Contains the known good models this driver is compatible with.
     77 * When adding a new model try to be as strict as possible. This
     78 * makes it possible to keep the false positives (the model is
     79 * detected as working, but in reality it is not) as low as
     80 * possible.
     81 */
     82static const struct dmi_system_id nas_led_whitelist[] __initconst = {
     83	{
     84		.callback = ss4200_led_dmi_callback,
     85		.ident = "Intel SS4200-E",
     86		.matches = {
     87			DMI_MATCH(DMI_SYS_VENDOR, "Intel"),
     88			DMI_MATCH(DMI_PRODUCT_NAME, "SS4200-E"),
     89			DMI_MATCH(DMI_PRODUCT_VERSION, "1.00.00")
     90		}
     91	},
     92	{
     93		/*
     94		 * FUJITSU SIEMENS SCALEO Home Server/SS4200-E
     95		 * BIOS V090L 12/19/2007
     96		 */
     97		.callback = ss4200_led_dmi_callback,
     98		.ident = "Fujitsu Siemens SCALEO Home Server",
     99		.matches = {
    100			DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
    101			DMI_MATCH(DMI_PRODUCT_NAME, "SCALEO Home Server"),
    102			DMI_MATCH(DMI_PRODUCT_VERSION, "1.00.00")
    103		}
    104	},
    105	{}
    106};
    107
    108/*
    109 * Base I/O address assigned to the Power Management register block
    110 */
    111static u32 g_pm_io_base;
    112
    113/*
    114 * Base I/O address assigned to the ICH7 GPIO register block
    115 */
    116static u32 nas_gpio_io_base;
    117
    118/*
    119 * When we successfully register a region, we are returned a resource.
    120 * We use these to identify which regions we need to release on our way
    121 * back out.
    122 */
    123static struct resource *gp_gpio_resource;
    124
    125struct nasgpio_led {
    126	char *name;
    127	u32 gpio_bit;
    128	struct led_classdev led_cdev;
    129};
    130
    131/*
    132 * gpio_bit(s) are the ICH7 GPIO bit assignments
    133 */
    134static struct nasgpio_led nasgpio_leds[] = {
    135	{ .name = "hdd1:blue:sata",	.gpio_bit = 0 },
    136	{ .name = "hdd1:amber:sata",	.gpio_bit = 1 },
    137	{ .name = "hdd2:blue:sata",	.gpio_bit = 2 },
    138	{ .name = "hdd2:amber:sata",	.gpio_bit = 3 },
    139	{ .name = "hdd3:blue:sata",	.gpio_bit = 4 },
    140	{ .name = "hdd3:amber:sata",	.gpio_bit = 5 },
    141	{ .name = "hdd4:blue:sata",	.gpio_bit = 6 },
    142	{ .name = "hdd4:amber:sata",	.gpio_bit = 7 },
    143	{ .name = "power:blue:power",	.gpio_bit = 27},
    144	{ .name = "power:amber:power",  .gpio_bit = 28},
    145};
    146
    147#define NAS_RECOVERY	0x00000400	/* GPIO10 */
    148
    149static struct nasgpio_led *
    150led_classdev_to_nasgpio_led(struct led_classdev *led_cdev)
    151{
    152	return container_of(led_cdev, struct nasgpio_led, led_cdev);
    153}
    154
    155static struct nasgpio_led *get_led_named(char *name)
    156{
    157	int i;
    158	for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++) {
    159		if (strcmp(nasgpio_leds[i].name, name))
    160			continue;
    161		return &nasgpio_leds[i];
    162	}
    163	return NULL;
    164}
    165
    166/*
    167 * This protects access to the gpio ports.
    168 */
    169static DEFINE_SPINLOCK(nasgpio_gpio_lock);
    170
    171/*
    172 * There are two gpio ports, one for blinking and the other
    173 * for power.  @port tells us if we're doing blinking or
    174 * power control.
    175 *
    176 * Caller must hold nasgpio_gpio_lock
    177 */
    178static void __nasgpio_led_set_attr(struct led_classdev *led_cdev,
    179				   u32 port, u32 value)
    180{
    181	struct nasgpio_led *led = led_classdev_to_nasgpio_led(led_cdev);
    182	u32 gpio_out;
    183
    184	gpio_out = inl(nas_gpio_io_base + port);
    185	if (value)
    186		gpio_out |= (1<<led->gpio_bit);
    187	else
    188		gpio_out &= ~(1<<led->gpio_bit);
    189
    190	outl(gpio_out, nas_gpio_io_base + port);
    191}
    192
    193static void nasgpio_led_set_attr(struct led_classdev *led_cdev,
    194				 u32 port, u32 value)
    195{
    196	spin_lock(&nasgpio_gpio_lock);
    197	__nasgpio_led_set_attr(led_cdev, port, value);
    198	spin_unlock(&nasgpio_gpio_lock);
    199}
    200
    201static u32 nasgpio_led_get_attr(struct led_classdev *led_cdev, u32 port)
    202{
    203	struct nasgpio_led *led = led_classdev_to_nasgpio_led(led_cdev);
    204	u32 gpio_in;
    205
    206	spin_lock(&nasgpio_gpio_lock);
    207	gpio_in = inl(nas_gpio_io_base + port);
    208	spin_unlock(&nasgpio_gpio_lock);
    209	if (gpio_in & (1<<led->gpio_bit))
    210		return 1;
    211	return 0;
    212}
    213
    214/*
    215 * There is actual brightness control in the hardware,
    216 * but it is via smbus commands and not implemented
    217 * in this driver.
    218 */
    219static void nasgpio_led_set_brightness(struct led_classdev *led_cdev,
    220				       enum led_brightness brightness)
    221{
    222	u32 setting = 0;
    223	if (brightness >= LED_HALF)
    224		setting = 1;
    225	/*
    226	 * Hold the lock across both operations.  This ensures
    227	 * consistency so that both the "turn off blinking"
    228	 * and "turn light off" operations complete as a set.
    229	 */
    230	spin_lock(&nasgpio_gpio_lock);
    231	/*
    232	 * LED class documentation asks that past blink state
    233	 * be disabled when brightness is turned to zero.
    234	 */
    235	if (brightness == 0)
    236		__nasgpio_led_set_attr(led_cdev, GPO_BLINK, 0);
    237	__nasgpio_led_set_attr(led_cdev, GP_LVL, setting);
    238	spin_unlock(&nasgpio_gpio_lock);
    239}
    240
    241static int nasgpio_led_set_blink(struct led_classdev *led_cdev,
    242				 unsigned long *delay_on,
    243				 unsigned long *delay_off)
    244{
    245	u32 setting = 1;
    246	if (!(*delay_on == 0 && *delay_off == 0) &&
    247	    !(*delay_on == 500 && *delay_off == 500))
    248		return -EINVAL;
    249	/*
    250	 * These are very approximate.
    251	 */
    252	*delay_on = 500;
    253	*delay_off = 500;
    254
    255	nasgpio_led_set_attr(led_cdev, GPO_BLINK, setting);
    256
    257	return 0;
    258}
    259
    260
    261/*
    262 * Initialize the ICH7 GPIO registers for NAS usage.  The BIOS should have
    263 * already taken care of this, but we will do so in a non destructive manner
    264 * so that we have what we need whether the BIOS did it or not.
    265 */
    266static int ich7_gpio_init(struct device *dev)
    267{
    268	int i;
    269	u32 config_data = 0;
    270	u32 all_nas_led = 0;
    271
    272	for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++)
    273		all_nas_led |= (1<<nasgpio_leds[i].gpio_bit);
    274
    275	spin_lock(&nasgpio_gpio_lock);
    276	/*
    277	 * We need to enable all of the GPIO lines used by the NAS box,
    278	 * so we will read the current Use Selection and add our usage
    279	 * to it.  This should be benign with regard to the original
    280	 * BIOS configuration.
    281	 */
    282	config_data = inl(nas_gpio_io_base + GPIO_USE_SEL);
    283	dev_dbg(dev, ": Data read from GPIO_USE_SEL = 0x%08x\n", config_data);
    284	config_data |= all_nas_led + NAS_RECOVERY;
    285	outl(config_data, nas_gpio_io_base + GPIO_USE_SEL);
    286	config_data = inl(nas_gpio_io_base + GPIO_USE_SEL);
    287	dev_dbg(dev, ": GPIO_USE_SEL = 0x%08x\n\n", config_data);
    288
    289	/*
    290	 * The LED GPIO outputs need to be configured for output, so we
    291	 * will ensure that all LED lines are cleared for output and the
    292	 * RECOVERY line ready for input.  This too should be benign with
    293	 * regard to BIOS configuration.
    294	 */
    295	config_data = inl(nas_gpio_io_base + GP_IO_SEL);
    296	dev_dbg(dev, ": Data read from GP_IO_SEL = 0x%08x\n",
    297					config_data);
    298	config_data &= ~all_nas_led;
    299	config_data |= NAS_RECOVERY;
    300	outl(config_data, nas_gpio_io_base + GP_IO_SEL);
    301	config_data = inl(nas_gpio_io_base + GP_IO_SEL);
    302	dev_dbg(dev, ": GP_IO_SEL = 0x%08x\n", config_data);
    303
    304	/*
    305	 * In our final system, the BIOS will initialize the state of all
    306	 * of the LEDs.  For now, we turn them all off (or Low).
    307	 */
    308	config_data = inl(nas_gpio_io_base + GP_LVL);
    309	dev_dbg(dev, ": Data read from GP_LVL = 0x%08x\n", config_data);
    310	/*
    311	 * In our final system, the BIOS will initialize the blink state of all
    312	 * of the LEDs.  For now, we turn blink off for all of them.
    313	 */
    314	config_data = inl(nas_gpio_io_base + GPO_BLINK);
    315	dev_dbg(dev, ": Data read from GPO_BLINK = 0x%08x\n", config_data);
    316
    317	/*
    318	 * At this moment, I am unsure if anything needs to happen with GPI_INV
    319	 */
    320	config_data = inl(nas_gpio_io_base + GPI_INV);
    321	dev_dbg(dev, ": Data read from GPI_INV = 0x%08x\n", config_data);
    322
    323	spin_unlock(&nasgpio_gpio_lock);
    324	return 0;
    325}
    326
    327static void ich7_lpc_cleanup(struct device *dev)
    328{
    329	/*
    330	 * If we were given exclusive use of the GPIO
    331	 * I/O Address range, we must return it.
    332	 */
    333	if (gp_gpio_resource) {
    334		dev_dbg(dev, ": Releasing GPIO I/O addresses\n");
    335		release_region(nas_gpio_io_base, ICH7_GPIO_SIZE);
    336		gp_gpio_resource = NULL;
    337	}
    338}
    339
    340/*
    341 * The OS has determined that the LPC of the Intel ICH7 Southbridge is present
    342 * so we can retrive the required operational information and prepare the GPIO.
    343 */
    344static struct pci_dev *nas_gpio_pci_dev;
    345static int ich7_lpc_probe(struct pci_dev *dev,
    346				    const struct pci_device_id *id)
    347{
    348	int status;
    349	u32 gc = 0;
    350
    351	status = pci_enable_device(dev);
    352	if (status) {
    353		dev_err(&dev->dev, "pci_enable_device failed\n");
    354		return -EIO;
    355	}
    356
    357	nas_gpio_pci_dev = dev;
    358	status = pci_read_config_dword(dev, PMBASE, &g_pm_io_base);
    359	if (status)
    360		goto out;
    361	g_pm_io_base &= 0x00000ff80;
    362
    363	status = pci_read_config_dword(dev, GPIO_CTRL, &gc);
    364	if (!(GPIO_EN & gc)) {
    365		status = -EEXIST;
    366		dev_info(&dev->dev,
    367			   "ERROR: The LPC GPIO Block has not been enabled.\n");
    368		goto out;
    369	}
    370
    371	status = pci_read_config_dword(dev, GPIO_BASE, &nas_gpio_io_base);
    372	if (0 > status) {
    373		dev_info(&dev->dev, "Unable to read GPIOBASE.\n");
    374		goto out;
    375	}
    376	dev_dbg(&dev->dev, ": GPIOBASE = 0x%08x\n", nas_gpio_io_base);
    377	nas_gpio_io_base &= 0x00000ffc0;
    378
    379	/*
    380	 * Insure that we have exclusive access to the GPIO I/O address range.
    381	 */
    382	gp_gpio_resource = request_region(nas_gpio_io_base, ICH7_GPIO_SIZE,
    383					  KBUILD_MODNAME);
    384	if (NULL == gp_gpio_resource) {
    385		dev_info(&dev->dev,
    386			 "ERROR Unable to register GPIO I/O addresses.\n");
    387		status = -1;
    388		goto out;
    389	}
    390
    391	/*
    392	 * Initialize the GPIO for NAS/Home Server Use
    393	 */
    394	ich7_gpio_init(&dev->dev);
    395
    396out:
    397	if (status) {
    398		ich7_lpc_cleanup(&dev->dev);
    399		pci_disable_device(dev);
    400	}
    401	return status;
    402}
    403
    404static void ich7_lpc_remove(struct pci_dev *dev)
    405{
    406	ich7_lpc_cleanup(&dev->dev);
    407	pci_disable_device(dev);
    408}
    409
    410/*
    411 * pci_driver structure passed to the PCI modules
    412 */
    413static struct pci_driver nas_gpio_pci_driver = {
    414	.name = KBUILD_MODNAME,
    415	.id_table = ich7_lpc_pci_id,
    416	.probe = ich7_lpc_probe,
    417	.remove = ich7_lpc_remove,
    418};
    419
    420static struct led_classdev *get_classdev_for_led_nr(int nr)
    421{
    422	struct nasgpio_led *nas_led = &nasgpio_leds[nr];
    423	struct led_classdev *led = &nas_led->led_cdev;
    424	return led;
    425}
    426
    427
    428static void set_power_light_amber_noblink(void)
    429{
    430	struct nasgpio_led *amber = get_led_named("power:amber:power");
    431	struct nasgpio_led *blue = get_led_named("power:blue:power");
    432
    433	if (!amber || !blue)
    434		return;
    435	/*
    436	 * LED_OFF implies disabling future blinking
    437	 */
    438	pr_debug("setting blue off and amber on\n");
    439
    440	nasgpio_led_set_brightness(&blue->led_cdev, LED_OFF);
    441	nasgpio_led_set_brightness(&amber->led_cdev, LED_FULL);
    442}
    443
    444static ssize_t blink_show(struct device *dev,
    445			  struct device_attribute *attr, char *buf)
    446{
    447	struct led_classdev *led = dev_get_drvdata(dev);
    448	int blinking = 0;
    449	if (nasgpio_led_get_attr(led, GPO_BLINK))
    450		blinking = 1;
    451	return sprintf(buf, "%u\n", blinking);
    452}
    453
    454static ssize_t blink_store(struct device *dev,
    455			   struct device_attribute *attr,
    456			   const char *buf, size_t size)
    457{
    458	int ret;
    459	struct led_classdev *led = dev_get_drvdata(dev);
    460	unsigned long blink_state;
    461
    462	ret = kstrtoul(buf, 10, &blink_state);
    463	if (ret)
    464		return ret;
    465
    466	nasgpio_led_set_attr(led, GPO_BLINK, blink_state);
    467
    468	return size;
    469}
    470
    471static DEVICE_ATTR_RW(blink);
    472
    473static struct attribute *nasgpio_led_attrs[] = {
    474	&dev_attr_blink.attr,
    475	NULL
    476};
    477ATTRIBUTE_GROUPS(nasgpio_led);
    478
    479static int register_nasgpio_led(int led_nr)
    480{
    481	struct nasgpio_led *nas_led = &nasgpio_leds[led_nr];
    482	struct led_classdev *led = get_classdev_for_led_nr(led_nr);
    483
    484	led->name = nas_led->name;
    485	led->brightness = LED_OFF;
    486	if (nasgpio_led_get_attr(led, GP_LVL))
    487		led->brightness = LED_FULL;
    488	led->brightness_set = nasgpio_led_set_brightness;
    489	led->blink_set = nasgpio_led_set_blink;
    490	led->groups = nasgpio_led_groups;
    491
    492	return led_classdev_register(&nas_gpio_pci_dev->dev, led);
    493}
    494
    495static void unregister_nasgpio_led(int led_nr)
    496{
    497	struct led_classdev *led = get_classdev_for_led_nr(led_nr);
    498	led_classdev_unregister(led);
    499}
    500/*
    501 * module load/initialization
    502 */
    503static int __init nas_gpio_init(void)
    504{
    505	int i;
    506	int ret = 0;
    507	int nr_devices = 0;
    508
    509	nr_devices = dmi_check_system(nas_led_whitelist);
    510	if (nodetect) {
    511		pr_info("skipping hardware autodetection\n");
    512		pr_info("Please send 'dmidecode' output to dave@sr71.net\n");
    513		nr_devices++;
    514	}
    515
    516	if (nr_devices <= 0) {
    517		pr_info("no LED devices found\n");
    518		return -ENODEV;
    519	}
    520
    521	pr_info("registering PCI driver\n");
    522	ret = pci_register_driver(&nas_gpio_pci_driver);
    523	if (ret)
    524		return ret;
    525	for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++) {
    526		ret = register_nasgpio_led(i);
    527		if (ret)
    528			goto out_err;
    529	}
    530	/*
    531	 * When the system powers on, the BIOS leaves the power
    532	 * light blue and blinking.  This will turn it solid
    533	 * amber once the driver is loaded.
    534	 */
    535	set_power_light_amber_noblink();
    536	return 0;
    537out_err:
    538	for (i--; i >= 0; i--)
    539		unregister_nasgpio_led(i);
    540	pci_unregister_driver(&nas_gpio_pci_driver);
    541	return ret;
    542}
    543
    544/*
    545 * module unload
    546 */
    547static void __exit nas_gpio_exit(void)
    548{
    549	int i;
    550	pr_info("Unregistering driver\n");
    551	for (i = 0; i < ARRAY_SIZE(nasgpio_leds); i++)
    552		unregister_nasgpio_led(i);
    553	pci_unregister_driver(&nas_gpio_pci_driver);
    554}
    555
    556module_init(nas_gpio_init);
    557module_exit(nas_gpio_exit);