695652c9d1
This is a 1RU switch with 32 QSFP28 (40G/100G) ports on Broadcom Tomahawk I chipset. CPU used in QFX5200-32C-S is Intel Ivy Bridge. The machine has Redundant and hot-swappable Power Supply (1+1) and also has Redundant and hot swappable fans (5). Signed-off-by: Ciju Rajan K <crajank@juniper.net> Signed-off-by: Ashish Bhensdadia <bashish@juniper.net>
174 lines
3.9 KiB
C
174 lines
3.9 KiB
C
/*
|
|
* Juniper Networks TMC fpga PSU driver
|
|
*
|
|
* This driver is for detecting if the PSU is present or not
|
|
*
|
|
* Copyright (C) 2020 Juniper Networks
|
|
* Author: Ciju Rajan K <crajank@juniper.net>
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/device.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/io.h>
|
|
#include <linux/hwmon.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/hwmon-sysfs.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/string.h>
|
|
|
|
/* Max PSUs supported by this driver */
|
|
#define NUM_PSU 2
|
|
|
|
struct tmc_psu_data {
|
|
int num_psu;
|
|
void __iomem *tmc_membase;
|
|
};
|
|
|
|
enum sysfs_psu_attributes {
|
|
PSU0_PRESENT,
|
|
PSU1_PRESENT,
|
|
};
|
|
|
|
static bool get_psu_presense(void *addr, u8 idx)
|
|
{
|
|
bool ret = 0;
|
|
u32 value = ~(-1);
|
|
|
|
value = ioread32(addr);
|
|
/*
|
|
* BIT(6) is for PSU 0
|
|
* BIT(7) is for PSU 1
|
|
* idx will be either 0 (PSU0) or 1 (PSU1)
|
|
*/
|
|
value &= BIT(idx+6);
|
|
|
|
if (value)
|
|
ret = 1;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* Sysfs files are present in this path
|
|
* /sys/devices/pci0000:00/0000:00:1c.0/0000:0f:00.0/psu-tmc.15/psu*_present
|
|
*/
|
|
|
|
#define DECLARE_PSU_PRESENT_SENSOR_DEV_ATTR(index) \
|
|
static SENSOR_DEVICE_ATTR(psu##index##_present, S_IRUGO, tmc_psu_presense_show, NULL, PSU##index##_PRESENT)
|
|
#define DECLARE_PSU_PRESENT_ATTR(index) &sensor_dev_attr_psu##index##_present.dev_attr.attr
|
|
|
|
static ssize_t tmc_psu_presense_show(struct device *dev, struct device_attribute *attr, char *buf)
|
|
{
|
|
struct sensor_device_attribute *s_attr = to_sensor_dev_attr(attr);
|
|
struct platform_device *pdev = to_platform_device(dev);
|
|
struct tmc_psu_data *psu = platform_get_drvdata(pdev);
|
|
|
|
return sprintf(buf, "%d\n", get_psu_presense(psu->tmc_membase, s_attr->index));
|
|
|
|
}
|
|
|
|
DECLARE_PSU_PRESENT_SENSOR_DEV_ATTR(0);
|
|
DECLARE_PSU_PRESENT_SENSOR_DEV_ATTR(1);
|
|
|
|
static struct attribute *tmc_psu_attrs[] = {
|
|
DECLARE_PSU_PRESENT_ATTR(0),
|
|
DECLARE_PSU_PRESENT_ATTR(1),
|
|
NULL
|
|
};
|
|
|
|
static struct attribute_group tmc_psu_attr_group = {
|
|
.attrs = tmc_psu_attrs,
|
|
};
|
|
|
|
static int tmc_psu_probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
struct tmc_psu_data *psu;
|
|
int ret;
|
|
struct resource *res;
|
|
void __iomem *addr;
|
|
|
|
psu = devm_kzalloc(dev, sizeof(*psu), GFP_KERNEL);
|
|
if (!psu) {
|
|
dev_err(dev, "psu structure allocation failed\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
if (!res) {
|
|
dev_err(dev, "res allocation failed\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
addr = devm_ioremap_nocache(dev, res->start, resource_size(res));
|
|
if (!addr) {
|
|
dev_err(dev, "ioremap failed\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
psu->tmc_membase = addr;
|
|
psu->num_psu = NUM_PSU;
|
|
|
|
platform_set_drvdata(pdev, psu);
|
|
|
|
ret = sysfs_create_group(&dev->kobj, &tmc_psu_attr_group);
|
|
if (ret != 0) {
|
|
dev_err(dev, "jnx-tmc-psu: sysfs_create_group failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int tmc_psu_remove(struct platform_device *pdev)
|
|
{
|
|
struct tmc_psu_data *psu = platform_get_drvdata(pdev);
|
|
|
|
if (psu) {
|
|
devm_kfree(&pdev->dev, psu);
|
|
}
|
|
sysfs_remove_group(&pdev->dev.kobj, &tmc_psu_attr_group);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct platform_driver jnx_tmc_psu_driver = {
|
|
.driver = {
|
|
.name = "psu-tmc",
|
|
.owner = THIS_MODULE,
|
|
},
|
|
.probe = tmc_psu_probe,
|
|
.remove = tmc_psu_remove,
|
|
};
|
|
|
|
static int __init jnx_tmc_psu_driver_init(void)
|
|
{
|
|
int ret = -1;
|
|
|
|
ret = platform_driver_register(&jnx_tmc_psu_driver);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
static void __exit jnx_tmc_psu_driver_exit(void)
|
|
{
|
|
platform_driver_unregister(&jnx_tmc_psu_driver);
|
|
}
|
|
|
|
module_init(jnx_tmc_psu_driver_init);
|
|
module_exit(jnx_tmc_psu_driver_exit);
|
|
|
|
MODULE_DESCRIPTION("Juniper Networks TMC PSU driver");
|
|
MODULE_AUTHOR("Ciju Rajan K <crajank@juniper.net>");
|
|
MODULE_LICENSE("GPL");
|