Introduce a staging driver containing all the bit and
pieces of Juniper's board support infrastructure that don't quite
fit in any other place.
The Juniper series of routers comprise of both x86 and powerpc
platforms that contain similar hardware components necessitating
common support methods.
Note that this is the first submission and we expect things to be
moved around as required.
This patchset is against mainline as of today: v4.8-9431-g3477d16
and is dependent on the "Juniper prerequisites" patchset sent
earlier.
Rajat Jain (1):
jnx: Introduce include/linux/jnx/pci_ids.h
Tom Kavanagh (1):
staging: jnx: Juniper subsystem & board core APIs
Documentation/ABI/testing/sysfs-platform-jnx | 170 +++++++
drivers/staging/Kconfig | 2 +
drivers/staging/Makefile | 1 +
drivers/staging/jnx/Kconfig | 24 +
drivers/staging/jnx/Makefile | 5 +
drivers/staging/jnx/jnx-board-core.c | 247 ++++++++++
drivers/staging/jnx/jnx-subsys-private.h | 35 ++
drivers/staging/jnx/jnx-subsys.c | 655 +++++++++++++++++++++++++++
include/linux/jnx/jnx-board-core.h | 41 ++
include/linux/jnx/jnx-subsys.h | 94 ++++
include/linux/jnx/pci_ids.h | 66 +++
11 files changed, 1340 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-platform-jnx
create mode 100644 drivers/staging/jnx/Kconfig
create mode 100644 drivers/staging/jnx/Makefile
create mode 100644 drivers/staging/jnx/jnx-board-core.c
create mode 100644 drivers/staging/jnx/jnx-subsys-private.h
create mode 100644 drivers/staging/jnx/jnx-subsys.c
create mode 100644 include/linux/jnx/jnx-board-core.h
create mode 100644 include/linux/jnx/jnx-subsys.h
create mode 100644 include/linux/jnx/pci_ids.h
--
1.9.1
From: Tom Kavanagh <[email protected]>
The Juniper System Infrastructure subsystem creates platform devices
for the platform, chassis and cards and provides sysfs attributes for
these devices.
Each board contains I2C ID EEPROMs which contain information about the
chassis, platform, type and assembly IDs.
All Juniper local boards that run Linux contain a CBD (Control Board)
FPGA that provides I2C interfaces (among other things) that the other
boards use to connect their ID EEPROMs to.
A set of APIs for boards/modules is provided. These APIs provide:
- The ability to "listen" for the addition/deletion of any new board
and schedule work to be done upon notification.
- The query of mastership in the dual failover environment these
platform operate in.
- Registering boards and chassis.
A user-space API is provided by sysfs device files and it is described
in the relevant ABI documentation file.
Signed-off-by: Georgi Vlaev <[email protected]>
Signed-off-by: Guenter Roeck <[email protected]>
Signed-off-by: Mohammad Kamil <[email protected]>
Signed-off-by: Rajat Jain <[email protected]>
Signed-off-by: Tom Kavanagh <[email protected]>
Signed-off-by: Pantelis Antoniou <[email protected]>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <[email protected]>
---
Documentation/ABI/testing/sysfs-platform-jnx | 170 +++++++
drivers/staging/Kconfig | 2 +
drivers/staging/Makefile | 1 +
drivers/staging/jnx/Kconfig | 24 +
drivers/staging/jnx/Makefile | 5 +
drivers/staging/jnx/jnx-board-core.c | 247 ++++++++++
drivers/staging/jnx/jnx-subsys-private.h | 35 ++
drivers/staging/jnx/jnx-subsys.c | 655 +++++++++++++++++++++++++++
include/linux/jnx/jnx-board-core.h | 41 ++
include/linux/jnx/jnx-subsys.h | 94 ++++
10 files changed, 1274 insertions(+)
create mode 100644 Documentation/ABI/testing/sysfs-platform-jnx
create mode 100644 drivers/staging/jnx/Kconfig
create mode 100644 drivers/staging/jnx/Makefile
create mode 100644 drivers/staging/jnx/jnx-board-core.c
create mode 100644 drivers/staging/jnx/jnx-subsys-private.h
create mode 100644 drivers/staging/jnx/jnx-subsys.c
create mode 100644 include/linux/jnx/jnx-board-core.h
create mode 100644 include/linux/jnx/jnx-subsys.h
diff --git a/Documentation/ABI/testing/sysfs-platform-jnx b/Documentation/ABI/testing/sysfs-platform-jnx
new file mode 100644
index 0000000..9bc7adc
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-platform-jnx
@@ -0,0 +1,170 @@
+What: /sys/devices/platform/jnx/chassis/platform
+Date: Sep 2016
+KernelVersion: 4.8.0-rc7
+Contact: Georgi Vlaev <[email protected]>
+Description:
+ Read only numeric platform ID of the Juniper platform we're
+ running on. Valid platforms IDs are:
+ SANGRIA 85
+ HENDRICKS 156
+ POLARIS 171
+ OMEGA 181
+
+What: /sys/devices/platform/jnx/chassis/chassis_no
+Date: Sep 2016
+KernelVersion: 4.8.0-rc7
+Contact: Georgi Vlaev <[email protected]>
+Description:
+ Read only chassis number.
+
+What: /sys/devices/platform/jnx/chassis/multichassis
+Date: Sep 2016
+KernelVersion: 4.8.0-rc7
+Contact: Georgi Vlaev <[email protected]>
+Description:
+ Read only multichassis status
+ 1 if we're on a multichassis system
+ 0 otherwise
+
+What: /sys/devices/platform/jnx/chassis/master
+Date: Sep 2016
+KernelVersion: 4.8.0-rc7
+Contact: Georgi Vlaev <[email protected]>
+Description:
+ Read only numeric ID of the master slot.
+
+What: /sys/devices/platform/jnx/chassis/mastership
+Date: Sep 2016
+KernelVersion: 4.8.0-rc7
+Contact: Georgi Vlaev <[email protected]>
+Description:
+ Read for returning non zero if current RE is master
+ Write for relinquishing mastership to other RE
+
+What: /sys/devices/platform/jnx/chassis/mastership_alive
+Date: Sep 2016
+KernelVersion: 4.8.0-rc7
+Contact: Georgi Vlaev <[email protected]>
+Description:
+ Write to update the mastership watchdog alive.
+ The watchdog period is CBD FPGA specific.
+
+What: /sys/devices/platform/jnx/chassis/mastership_alive_cnt
+Date: Sep 2016
+KernelVersion: 4.8.0-rc7
+Contact: Georgi Vlaev <[email protected]>
+Description:
+ Read to return the mastership count number
+ Write to set the mastership count number
+
+What: /sys/devices/platform/jnx/card/foo[n]
+Date: Sep 2016
+KernelVersion: 4.8.0-rc7
+Contact: Georgi Vlaev <[email protected]>
+Description:
+ Symbolic link of the jnx board with the given type
+ foo with an option index number. For instance the
+ first two fan type cards would link like this:
+
+ /sys/devices/platform/jnx/card/fan0 -> ../jnx-09cc.0
+ /sys/devices/platform/jnx/card/fan1 -> ../jnx-09cc.1
+
+What: /sys/devices/platform/jnx/jnx-XXXX.N/id
+Date: Sep 2016
+KernelVersion: 4.8.0-rc7
+Contact: Georgi Vlaev <[email protected]>
+Description:
+ Symbolic link of the jnx board with hexadecimal assembly ID
+ XXXX and platform id index N to it's EEPROM ID device
+
+What: /sys/devices/platform/jnx/jnx-XXXX.N/i2c-adapter
+Date: Sep 2016
+KernelVersion: 4.8.0-rc7
+Contact: Georgi Vlaev <[email protected]>
+Description:
+ Symbolic link of the jnx board with hexadecimal assembly ID
+ XXXX and platform id index N to its i2c-adapter that the
+ EEPROM ID device is located
+
+What: /sys/devices/platform/jnx-XXXX.N/slot
+Date: Sep 2016
+KernelVersion: 4.8.0-rc7
+Contact: Georgi Vlaev <[email protected]>
+Description:
+ Read only number slot ID of the jnx board with hexadecimal
+ assembly ID XXXX and platform id index N
+
+What: /sys/devices/platform/jnx-XXXX.N/type
+Date: Sep 2016
+KernelVersion: 4.8.0-rc7
+Contact: Georgi Vlaev <[email protected]>
+Description:
+ Read only board type ID of the jnx board with hexadecimal
+ assembly ID XXXX and platform id index N.
+ Valid board type IDs:
+ 0 Unknown
+ 1 RE
+ 2 FPC
+ 3 SPMB
+ 4 CB
+ 5 PS
+ 6 FAN
+ 7 FPM
+ 8 CG
+ 9 MIDPLANE
+ 10 PIC
+ 11 SIB
+
+What: /sys/devices/platform/jnx-XXXX.N/assembly_id
+Date: Sep 2016
+KernelVersion: 4.8.0-rc7
+Contact: Georgi Vlaev <[email protected]>
+Description:
+ Read only assembly ID of the local jnx board with hexadecimal
+ assembly ID XXXX and platform id index N which is read from
+ the EEPROM
+
+What: /sys/devices/platform/jnx-XXXX-local/slot
+Date: Sep 2016
+KernelVersion: 4.8.0-rc7
+Contact: Georgi Vlaev <[email protected]>
+Description:
+ Read only number slot ID of the jnx local board with hexadecimal
+ assembly ID XXXX.
+
+What: /sys/devices/platform/jnx-XXXX-local/type
+Date: Sep 2016
+KernelVersion: 4.8.0-rc7
+Contact: Georgi Vlaev <[email protected]>
+Description:
+ Read only board type ID of the jnx local board with hexadecimal
+ assembly ID XXXX.
+ Valid board type IDs:
+ 0 Unknown
+ 1 RE
+ 2 FPC
+ 3 SPMB
+ 4 CB
+ 5 PS
+ 6 FAN
+ 7 FPM
+ 8 CG
+ 9 MIDPLANE
+ 10 PIC
+ 11 SIB
+
+What: /sys/devices/platform/jnx-XXXX-local/assembly_id
+Date: Sep 2016
+KernelVersion: 4.8.0-rc7
+Contact: Georgi Vlaev <[email protected]>
+Description:
+ Read only warmboot status of the jnx local board with
+ hexadecimal assembly ID XXXX.
+
+What: /sys/devices/platform/jnx-XXXX-local/warmboot
+Date: Sep 2016
+KernelVersion: 4.8.0-rc7
+Contact: Georgi Vlaev <[email protected]>
+Description:
+ Read only warmboot status of the jnx local board with
+ hexadecimal assembly ID XXXX.
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 58a7b35..474bc68 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -106,4 +106,6 @@ source "drivers/staging/greybus/Kconfig"
source "drivers/staging/vc04_services/Kconfig"
+source "drivers/staging/jnx/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 2fa9745..e6d7be6 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_VT6655) += vt6655/
obj-$(CONFIG_VT6656) += vt6656/
obj-$(CONFIG_VME_BUS) += vme/
obj-$(CONFIG_IIO) += iio/
+obj-$(CONFIG_JNX_DEVICES) += jnx/
obj-$(CONFIG_FB_SM750) += sm750fb/
obj-$(CONFIG_FB_XGI) += xgifb/
obj-$(CONFIG_USB_EMXX) += emxx_udc/
diff --git a/drivers/staging/jnx/Kconfig b/drivers/staging/jnx/Kconfig
new file mode 100644
index 0000000..5d2b207
--- /dev/null
+++ b/drivers/staging/jnx/Kconfig
@@ -0,0 +1,24 @@
+#
+# Juniper devices
+#
+config JNX_DEVICES
+ bool
+ default n
+
+if JNX_DEVICES
+
+menu "Juniper Devices and Infrastructure"
+
+config JNX_SYSTEM
+ bool "Juniper System Infrastructure"
+ default y
+ help
+ This driver adds support for Juniper System Infrastructure. It creates
+ platform devices for the platform, chassis and cards and provides sysfs
+ attributes for these devices.
+
+ This driver can not be compiled as a module.
+
+endmenu
+
+endif # JNX_DEVICES
diff --git a/drivers/staging/jnx/Makefile b/drivers/staging/jnx/Makefile
new file mode 100644
index 0000000..52b8286
--- /dev/null
+++ b/drivers/staging/jnx/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for Juniper devices that really don't fit anywhere else.
+#
+
+obj-$(CONFIG_JNX_SYSTEM) += jnx-subsys.o jnx-board-core.o
diff --git a/drivers/staging/jnx/jnx-board-core.c b/drivers/staging/jnx/jnx-board-core.c
new file mode 100644
index 0000000..218a8b7
--- /dev/null
+++ b/drivers/staging/jnx/jnx-board-core.c
@@ -0,0 +1,247 @@
+/*
+ * Juniper Generic Board APIs
+ *
+ * Copyright (C) 2012, 2013, 2014 Juniper Networks. All rights reserved.
+ *
+ * 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 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/device.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/platform_data/at24.h>
+#include <linux/slab.h>
+#include <linux/jnx/jnx-subsys.h>
+#include <linux/jnx/jnx-board-core.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/jnx-i2cs-core.h>
+
+#include "jnx-subsys-private.h"
+
+#define DRIVER_VERSION "0.01.0"
+#define DRIVER_DESC "Board Generic HW"
+
+static LIST_HEAD(jnx_i2c_notify_list);
+static DEFINE_MUTEX(jnx_i2c_notify_lock);
+
+static int jnx_i2c_adap_name_match(struct device *dev, void *data)
+{
+ struct i2c_adapter *adap = i2c_verify_adapter(dev);
+ char *name = data;
+
+ if (!adap)
+ return false;
+
+ return !strncmp(adap->name, name, strlen(name));
+}
+
+struct i2c_adapter *jnx_i2c_find_adapter(char *name)
+{
+ struct device *dev;
+ struct i2c_adapter *adap;
+
+ dev = bus_find_device(&i2c_bus_type, NULL, name,
+ jnx_i2c_adap_name_match);
+ if (!dev)
+ return NULL;
+
+ adap = i2c_verify_adapter(dev);
+ if (!adap)
+ put_device(dev);
+
+ return adap;
+}
+EXPORT_SYMBOL(jnx_i2c_find_adapter);
+
+static void jnx_board_ideeprom_callback(struct nvmem_device *nvmem,
+ void *context)
+{
+ struct nvmem_device **pnvmem = context;
+
+ *pnvmem = nvmem;
+}
+
+static struct i2c_client *jnx_add_board_ideeprom(struct i2c_adapter *adap,
+ int slot)
+{
+ struct i2c_board_info binfo = { I2C_BOARD_INFO("24c02", 0x51) };
+ struct nvmem_device *nvmem = NULL;
+ struct at24_platform_data adata = {
+ .byte_len = 256,
+ .page_size = 1,
+ .setup = jnx_board_ideeprom_callback,
+ .context = &nvmem,
+ };
+ struct device *dev = &adap->dev;
+ struct jnx_card_info cinfo = {
+ .type = JNX_BOARD_TYPE_UNKNOWN,
+ .adap = adap,
+ .slot = slot,
+ };
+ struct i2c_client *client;
+ unsigned char buf[2];
+ int err;
+
+ binfo.platform_data = &adata;
+
+ client = i2c_new_device(adap, &binfo);
+ if (!client)
+ return client;
+
+ if (!nvmem || nvmem_device_read(nvmem, 4, 2, buf) != 2)
+ goto error;
+
+ cinfo.assembly_id = (buf[0] << 8) | buf[1];
+ err = jnx_register_board(dev, &client->dev, &cinfo, slot);
+ if (err)
+ goto error;
+
+ return client;
+
+error:
+ i2c_unregister_device(client);
+ return NULL;
+}
+
+/*
+ * The i2cs (cpld) mux driver is instantiated through the i2cs mfd driver.
+ * Provide the necessary information to the mfd driver using platform data.
+ */
+static struct mfd_cell i2cs_cells[] = {
+ {
+ .name = "i2c-mux-i2cs",
+ .of_compatible = "jnx,i2c-mux-i2cs",
+ },
+};
+
+static struct jnx_i2cs_platform_data i2cs_pdata = {
+ .cells = i2cs_cells,
+ .ncells = ARRAY_SIZE(i2cs_cells),
+};
+
+static struct i2c_board_info const jnx_i2cs_board_info = {
+ I2C_BOARD_INFO("jnx_i2cs_fpc", 0x54),
+ .platform_data = &i2cs_pdata,
+};
+
+struct i2c_client *jnx_board_inserted(struct i2c_adapter *adap,
+ int slot, bool has_mux)
+{
+ char name[JNX_BRD_I2C_NAME_LEN];
+ struct i2c_client *mux, *client;
+
+ /*
+ * First add (bus selector) mux adapter if needed
+ *
+ * Devices are connected either to the primary mux
+ * (pca9665 adapter controlled via cbd fpga mux),
+ *
+ * -[pca6996]--[cbd mux]
+ * +----+--- eeprom
+ * | +--- other devices
+ * |
+ * +----
+ * ...
+ *
+ * or through the secondary mux (i2c-mux-cpld).
+ * The secondary mux is a virtual single-channel mux; its purpose
+ * is to enable i2c access to the board in question.
+ *
+ * -[pca6996]--[cbd mux]
+ * +----+--- eeprom
+ * | +--- other devices
+ * |
+ * +----[i2c-mux-cpld]--+--- eeprom
+ * | +--- other devices
+ * ...
+ */
+ if (has_mux) {
+ mux = i2c_new_device(adap, &jnx_i2cs_board_info);
+ if (!mux)
+ return NULL;
+ /* Look for mux adapter */
+ snprintf(name, sizeof(name), "i2c-%d-mux (chan_id 0)",
+ i2c_adapter_id(adap));
+ /*
+ * NOTICE:
+ * The following call will fail if the mux or the mfd driver
+ * are not built into the kernel. Accept this limitation
+ * as the code is expected to be replaced with DT based
+ * instantiation.
+ */
+ adap = jnx_i2c_find_adapter(name);
+ if (!adap)
+ return NULL;
+ }
+
+ /* Add ideeprom either directly or behind mux */
+ client = jnx_add_board_ideeprom(adap, slot);
+ /*
+ * jnx_i2c_find_adapter acquires a hold on the returned adapter.
+ * Time to release it.
+ */
+ if (has_mux)
+ put_device(&adap->dev);
+ if (has_mux && !client) {
+ i2c_unregister_device(mux);
+ return NULL;
+ }
+ return has_mux ? mux : client;
+}
+EXPORT_SYMBOL(jnx_board_inserted);
+
+void jnx_board_removed(struct i2c_adapter *adap, struct i2c_client *client)
+{
+ /*
+ * When removing a board, we have to release the platform driver first.
+ * This is necessary because the platform driver will release the i2c
+ * devices connected to it. The 'client' variable may point to the
+ * secondary mux ('i2c-mux-cpld'). If we release it first, it would
+ * release all downstream clients, which would result in a
+ * double-release, since the platform driver would subsequently
+ * try to release the same clients again.
+ * We can not release every client from here since the platform driver
+ * may be unloaded, which would result in no release, and because
+ * the secondary mux does not exist for all boards.
+ */
+ if (adap)
+ jnx_unregister_board(&adap->dev);
+ if (client)
+ i2c_unregister_device(client);
+}
+EXPORT_SYMBOL(jnx_board_removed);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL v2");
+
+/* Support kexec feature for Juniper boards:
+ * 1. 'warmboot' in the command indicates a warmboot;
+ * 2. jnx_warmboot API is used to check for warmboot.
+ */
+static bool __jnx_warmbooted;
+
+static int __init jnx_warmboot_set(char *str)
+{
+ __jnx_warmbooted = true;
+ return 0;
+}
+
+early_param("warmboot", jnx_warmboot_set);
+
+bool
+jnx_warmboot(void)
+{
+ return __jnx_warmbooted;
+}
+EXPORT_SYMBOL(jnx_warmboot);
diff --git a/drivers/staging/jnx/jnx-subsys-private.h b/drivers/staging/jnx/jnx-subsys-private.h
new file mode 100644
index 0000000..2e83854
--- /dev/null
+++ b/drivers/staging/jnx/jnx-subsys-private.h
@@ -0,0 +1,35 @@
+/*
+ * Juniper Generic APIs for providing chassis and card information
+ * Private API
+ *
+ * Copyright (C) 2012, 2013, 2014 Juniper Networks. All rights reserved.
+ *
+ * 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 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.
+ */
+
+#ifndef _JNX_SUBSYS_PRIVATE_H
+#define _JNX_SUBSYS_PRIVATE_H
+
+#include <linux/jnx/jnx-subsys.h>
+
+/* mastership related */
+int register_mastership_notifier(struct notifier_block *nb);
+int unregister_mastership_notifier(struct notifier_block *nb);
+
+/* returns true is running on master */
+bool jnx_is_master(void);
+
+/* register and unregister a non local juniper board */
+int jnx_register_board(struct device *edev, struct device *ideeprom,
+ struct jnx_card_info *cinfo, int id);
+int jnx_unregister_board(struct device *edev);
+
+#endif /* _JNX_SUBSYS_H */
diff --git a/drivers/staging/jnx/jnx-subsys.c b/drivers/staging/jnx/jnx-subsys.c
new file mode 100644
index 0000000..c49a8e6
--- /dev/null
+++ b/drivers/staging/jnx/jnx-subsys.c
@@ -0,0 +1,655 @@
+/*
+ * Juniper Generic APIs for providing chassis and card information
+ *
+ * Copyright (C) 2012, 2013, 2014 Juniper Networks. All rights reserved.
+ *
+ * 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 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/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/sysfs.h>
+#include <linux/platform_device.h>
+
+#include <linux/jnx/jnx-subsys.h>
+#include <linux/jnx/jnx-board-core.h>
+
+#include "jnx-subsys-private.h"
+
+#define DRIVER_VERSION "0.01.0"
+#define DRIVER_AUTHOR "Thomas Kavanagh"
+#define DRIVER_DESC "JNX Subsystem"
+
+static struct platform_device *jnx_platform_device;
+static struct platform_device *jnx_local_card_device;
+
+static struct jnx_chassis_info chassis_info;
+
+/*
+ * Linked list to hold info on all inserted boards.
+ */
+struct jnx_board_entry {
+ struct platform_device *pdev;
+ struct device *dev;
+ struct list_head list;
+};
+
+static LIST_HEAD(jnx_board_list);
+static DEFINE_SPINLOCK(jnx_board_list_lock);
+
+/*
+ * Chassis Attributes
+ *
+ * platform - identifies the product upon which we are running
+ * chassis_no - the chassis number, used mainly in multi-chassis systems
+ * multichassis - indicates whether or not this chassis is part of a
+ * multichassis system
+ */
+static ssize_t jnx_show_platform(struct device *dev,
+ struct device_attribute *da,
+ char *buf)
+{
+ return sprintf(buf, "%u\n", chassis_info.platform);
+}
+
+static ssize_t jnx_show_chassis_no(struct device *dev,
+ struct device_attribute *da,
+ char *buf)
+{
+ return sprintf(buf, "%u\n", chassis_info.chassis_no);
+}
+
+static ssize_t jnx_show_multichassis(struct device *dev,
+ struct device_attribute *da,
+ char *buf)
+{
+ return sprintf(buf, "%u\n", chassis_info.multichassis);
+}
+
+/* Determine mastership status */
+bool jnx_is_master(void)
+{
+ struct jnx_chassis_info *chinfo = &chassis_info;
+ bool is_master = true;
+
+ /* mastership_get() can be NULL when connector running on fpc */
+ if (chinfo->mastership_get)
+ is_master = chinfo->mastership_get(chinfo->master_data);
+
+ return is_master;
+}
+EXPORT_SYMBOL(jnx_is_master);
+
+/* mastership status notifier list and register/unregister functions */
+static BLOCKING_NOTIFIER_HEAD(mastership_notifier_list);
+
+int register_mastership_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&mastership_notifier_list,
+ nb);
+}
+EXPORT_SYMBOL(register_mastership_notifier);
+
+int unregister_mastership_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&mastership_notifier_list,
+ nb);
+}
+EXPORT_SYMBOL(unregister_mastership_notifier);
+
+static ssize_t jnx_get_master(struct device *dev, struct device_attribute *da,
+ char *buf)
+{
+ struct jnx_chassis_info *chinfo = &chassis_info;
+
+ return sprintf(buf, "%d\n",
+ chinfo->get_master(chinfo->master_data));
+}
+
+static ssize_t jnx_mastership_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct jnx_chassis_info *chinfo = &chassis_info;
+
+ return sprintf(buf, "%d\n",
+ chinfo->mastership_get(chinfo->master_data));
+}
+
+static ssize_t jnx_mastership_set(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct jnx_chassis_info *chinfo = &chassis_info;
+ int val, err;
+ bool mstrship_before_set, mstrship_after_set;
+ char object[JNX_BRD_I2C_NAME_LEN + 8];
+ char subobject[24];
+ char arg0[13]; /* New mastership state */
+ char *envp[4];
+
+ err = kstrtoint(buf, 0, &val);
+ if (err)
+ return err;
+
+ envp[0] = object;
+ envp[1] = subobject;
+ envp[2] = arg0;
+ envp[3] = NULL;
+
+ mstrship_before_set = chinfo->mastership_get(chinfo->master_data);
+ chinfo->mastership_set(chinfo->master_data, val);
+ mstrship_after_set = chinfo->mastership_get(chinfo->master_data);
+
+ /*
+ * Notifier callback should only get called for the valid combinations
+ * once hw switchover has completed successfully. Calling it for the
+ * rest of the combinations is either harmful or redundant.
+ */
+ if (mstrship_before_set != mstrship_after_set) {
+ /* udev notification of mastership change */
+ sprintf(object, "OBJECT=chassis");
+ sprintf(subobject, "SUBOBJECT=mastership");
+ sprintf(arg0, "ARG0=%s", mstrship_after_set ?
+ "master" : "standby");
+ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
+ /* Notifier callback */
+ blocking_notifier_call_chain(&mastership_notifier_list,
+ val, NULL);
+ }
+
+ return count;
+}
+
+static ssize_t jnx_mastership_ping(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct jnx_chassis_info *chinfo = &chassis_info;
+
+ chinfo->mastership_ping(chinfo->master_data);
+
+ return count;
+}
+
+static ssize_t jnx_mastership_alive_cnt_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct jnx_chassis_info *chinfo = &chassis_info;
+
+ return sprintf(buf, "%d\n",
+ chinfo->mastership_count_get(chinfo->master_data));
+}
+
+static ssize_t jnx_mastership_alive_cnt_set(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct jnx_chassis_info *chinfo = &chassis_info;
+ int val, err;
+
+ err = kstrtoint(buf, 0, &val);
+ if (err)
+ return err;
+
+ err = chinfo->mastership_count_set(chinfo->master_data, val);
+ if (err)
+ return err;
+
+ return count;
+}
+
+static DEVICE_ATTR(platform, S_IRUGO, jnx_show_platform, NULL);
+static DEVICE_ATTR(chassis_no, S_IRUGO, jnx_show_chassis_no, NULL);
+static DEVICE_ATTR(multichassis, S_IRUGO, jnx_show_multichassis, NULL);
+static DEVICE_ATTR(master, S_IRUGO, jnx_get_master, NULL);
+static DEVICE_ATTR(mastership, S_IRUGO | S_IWUSR, jnx_mastership_show,
+ jnx_mastership_set);
+static DEVICE_ATTR(mastership_alive, S_IWUSR, NULL, jnx_mastership_ping);
+static DEVICE_ATTR(mastership_alive_cnt, S_IRUGO | S_IWUSR,
+ jnx_mastership_alive_cnt_show, jnx_mastership_alive_cnt_set);
+
+static struct attribute *jnx_chassis_attrs[] = {
+ &dev_attr_platform.attr,
+ &dev_attr_chassis_no.attr,
+ &dev_attr_multichassis.attr,
+ &dev_attr_master.attr, /* 3 */
+ &dev_attr_mastership.attr, /* 4 */
+ &dev_attr_mastership_alive.attr, /* 5 */
+ &dev_attr_mastership_alive_cnt.attr, /* 6 */
+ NULL
+};
+
+static umode_t jnx_chassis_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct jnx_chassis_info *chinfo = &chassis_info;
+
+ if (index == 3 && !chinfo->get_master)
+ return 0;
+ if (index == 4 && (!chinfo->mastership_get || !chinfo->mastership_set))
+ return 0;
+ if (index == 5 && !chinfo->mastership_ping)
+ return 0;
+ if (index == 6 && (!chinfo->mastership_count_get ||
+ !chinfo->mastership_count_set))
+ return 0;
+
+ return attr->mode;
+}
+
+static const struct attribute_group jnx_chassis_group = {
+ .name = "chassis",
+ .attrs = jnx_chassis_attrs,
+ .is_visible = jnx_chassis_is_visible,
+};
+
+/*
+ * Card attributes
+ *
+ * slot - slot number for the given board
+ * type - what type of board is inserted: RE, FPC, FAN, etc
+ */
+static ssize_t jnx_show_slot(struct device *dev,
+ struct device_attribute *da,
+ char *buf)
+{
+ struct jnx_card_info *cinfo = dev_get_platdata(dev);
+
+ return sprintf(buf, "%d\n", cinfo->slot);
+}
+
+static ssize_t jnx_show_type(struct device *dev,
+ struct device_attribute *da,
+ char *buf)
+{
+ struct jnx_card_info *cinfo = dev_get_platdata(dev);
+
+ return sprintf(buf, "%u\n", cinfo->type);
+}
+
+static ssize_t jnx_show_assembly_id(struct device *dev,
+ struct device_attribute *da,
+ char *buf)
+{
+ struct jnx_card_info *cinfo = dev_get_platdata(dev);
+
+ return sprintf(buf, "0x%04x\n", cinfo->assembly_id);
+}
+
+static ssize_t jnx_show_warmboot(struct device *dev,
+ struct device_attribute *da,
+ char *buf)
+{
+ return sprintf(buf, "%u\n", jnx_warmboot());
+}
+
+static DEVICE_ATTR(slot, S_IRUGO, jnx_show_slot, NULL);
+static DEVICE_ATTR(type, S_IRUGO, jnx_show_type, NULL);
+static DEVICE_ATTR(assembly_id, S_IRUGO, jnx_show_assembly_id, NULL);
+static DEVICE_ATTR(warmboot, S_IRUGO, jnx_show_warmboot, NULL);
+
+/* Card attributes */
+static struct attribute *jnx_card_attrs[] = {
+ &dev_attr_slot.attr,
+ &dev_attr_type.attr,
+ &dev_attr_assembly_id.attr,
+ NULL
+};
+
+static const struct attribute_group jnx_card_group = {
+ .attrs = jnx_card_attrs,
+};
+
+static const struct attribute_group *jnx_card_groups[] = {
+ &jnx_card_group,
+ NULL
+};
+
+/* With addtional card attributes for 'local' */
+static struct attribute *jnx_card_local_attrs[] = {
+ &dev_attr_warmboot.attr,
+ NULL
+};
+
+static const struct attribute_group jnx_local_card_group = {
+ .attrs = jnx_card_local_attrs
+};
+
+static const struct attribute_group *jnx_local_card_groups[] = {
+ &jnx_card_group,
+ &jnx_local_card_group,
+ NULL
+};
+
+static struct attribute *jnx_attrs[] = {
+ NULL
+};
+
+static const struct attribute_group jnx_group = {
+ .name = "card",
+ .attrs = jnx_attrs,
+};
+
+static const struct attribute_group *jnx_groups[] = {
+ &jnx_group,
+ NULL
+};
+
+static int jnx_platform_uevent(const char *dir, const char *obj,
+ const char *subobj, int event)
+{
+ struct kobject *kobj = &jnx_platform_device->dev.kobj;
+ char objpath[64];
+ char object[JNX_BRD_I2C_NAME_LEN + 8];
+ char subobject[20];
+ char *envp[4];
+ const char *devpath;
+ int ret;
+
+ devpath = kobject_get_path(kobj, GFP_KERNEL);
+ if (!devpath)
+ return -ENOENT;
+
+ envp[0] = objpath;
+ envp[1] = object;
+ envp[2] = subobject;
+ envp[3] = NULL;
+
+ if (dir)
+ snprintf(objpath, sizeof(objpath), "OBJPATH=%s/%s", devpath,
+ dir);
+ else
+ snprintf(objpath, sizeof(objpath), "OBJPATH=%s", devpath);
+ snprintf(object, sizeof(object), "OBJECT=%s", obj);
+
+ if (subobj)
+ snprintf(subobject, sizeof(subobject), "SUBOBJECT=%s", subobj);
+ else
+ sprintf(subobject, "SUBOBJECT=");
+
+ ret = kobject_uevent_env(kobj, event, envp);
+ kfree(devpath);
+ return ret;
+}
+
+static int jnx_subsystem_init_pdev(void)
+{
+ int err;
+
+ if (jnx_platform_device)
+ return 0; /* already initialized */
+
+ jnx_platform_device = platform_device_alloc("jnx", -1);
+ if (!jnx_platform_device)
+ return -ENOMEM;
+
+ jnx_platform_device->dev.groups = jnx_groups;
+ err = platform_device_add(jnx_platform_device);
+ if (err)
+ goto err_free_device;
+
+ return 0;
+
+err_free_device:
+ platform_device_put(jnx_platform_device);
+
+ return err;
+}
+
+int jnx_register_chassis(struct jnx_chassis_info *chinfo)
+{
+ int ret;
+ char object[JNX_BRD_I2C_NAME_LEN + 8];
+ char subobject[24];
+ char arg0[13];
+ char *envp[4];
+
+ if (!jnx_platform_device) {
+ ret = jnx_subsystem_init_pdev();
+ if (ret)
+ return ret;
+ }
+
+ envp[0] = object;
+ envp[1] = subobject;
+ envp[2] = arg0;
+ envp[3] = NULL;
+
+ chassis_info = *chinfo;
+
+ ret = sysfs_create_group(&jnx_platform_device->dev.kobj,
+ &jnx_chassis_group);
+ if (ret < 0)
+ return ret;
+
+ jnx_platform_uevent(NULL, "chassis", NULL, KOBJ_ADD);
+ if (chinfo->mastership_get) {
+ /* notify udev of mastership sysfs attr creation */
+ sprintf(arg0, "ARG0=%s",
+ chinfo->mastership_get(chinfo->master_data) ? "master" :
+ "standby");
+ sprintf(object, "OBJECT=chassis");
+ sprintf(subobject, "SUBOBJECT=mastership");
+ kobject_uevent_env(&jnx_platform_device->dev.kobj,
+ KOBJ_ADD, envp);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(jnx_register_chassis);
+
+void jnx_unregister_chassis(void)
+{
+ if (jnx_platform_device) {
+ sysfs_remove_group(&jnx_platform_device->dev.kobj,
+ &jnx_chassis_group);
+ jnx_platform_uevent(NULL, "chassis", NULL, KOBJ_REMOVE);
+ }
+}
+EXPORT_SYMBOL(jnx_unregister_chassis);
+
+static
+struct platform_device *jnx_create_card_device(char *name,
+ struct jnx_card_info *cinfo,
+ int id)
+{
+ struct platform_device *pdev;
+ int err;
+
+ pdev = platform_device_alloc(name, id);
+ if (!pdev)
+ return ERR_PTR(-ENOMEM);
+
+ err = platform_device_add_data(pdev, cinfo, sizeof(*cinfo));
+ if (err)
+ goto pdev_failure;
+
+ if (jnx_platform_device)
+ pdev->dev.parent = &jnx_platform_device->dev;
+
+ if (id != -1)
+ pdev->dev.groups = jnx_card_groups;
+ else
+ pdev->dev.groups = jnx_local_card_groups;
+
+ err = platform_device_add(pdev);
+ if (err)
+ goto pdev_failure;
+
+ return pdev;
+
+pdev_failure:
+ platform_device_put(pdev);
+ return ERR_PTR(err);
+}
+
+int jnx_sysfs_create_link(struct device *dev, const char *link)
+{
+ int ret = 0;
+
+ if (jnx_platform_device) {
+ ret = sysfs_add_link_to_group(&jnx_platform_device->dev.kobj,
+ "card", &dev->kobj, link);
+ if (!ret)
+ ret = jnx_platform_uevent("card", link, NULL, KOBJ_ADD);
+ }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(jnx_sysfs_create_link);
+
+void jnx_sysfs_delete_link(struct device *dev, const char *link)
+{
+ if (jnx_platform_device) {
+ sysfs_remove_link_from_group(&jnx_platform_device->dev.kobj,
+ "card", link);
+ jnx_platform_uevent("card", link, NULL, KOBJ_REMOVE);
+ }
+}
+EXPORT_SYMBOL_GPL(jnx_sysfs_delete_link);
+
+/*
+ * Register local card. This is the card we are running on.
+ * Typically this would be the RE or a PMB.
+ * Create a card device similar to other card devices.
+ * Also create the 'local' link in the 'card' directory.
+ */
+int jnx_register_local_card(struct jnx_card_info *cinfo)
+{
+ char name[JNX_BRD_I2C_NAME_LEN];
+
+ if (jnx_local_card_device)
+ return -EEXIST;
+
+ snprintf(name, sizeof(name), "jnx-%04x-local", cinfo->assembly_id);
+ jnx_local_card_device = jnx_create_card_device(name, cinfo, -1);
+ if (IS_ERR(jnx_local_card_device))
+ return PTR_ERR(jnx_local_card_device);
+
+ jnx_sysfs_create_link(&jnx_local_card_device->dev, "local");
+
+ return 0;
+}
+EXPORT_SYMBOL(jnx_register_local_card);
+
+void jnx_unregister_local_card(void)
+{
+ if (jnx_local_card_device) {
+ jnx_sysfs_delete_link(&jnx_local_card_device->dev, "local");
+ platform_device_unregister(jnx_local_card_device);
+ jnx_local_card_device = NULL;
+ }
+}
+EXPORT_SYMBOL(jnx_unregister_local_card);
+
+int jnx_register_board(struct device *dev, struct device *ideeprom,
+ struct jnx_card_info *cinfo, int id)
+{
+ char name[JNX_BRD_I2C_NAME_LEN];
+ struct platform_device *pdev;
+ struct jnx_board_entry *entry;
+ int err;
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ snprintf(name, sizeof(name), "jnx-%04x", cinfo->assembly_id);
+ pdev = jnx_create_card_device(name, cinfo, id);
+ if (IS_ERR(pdev)) {
+ kfree(entry);
+ return PTR_ERR(pdev);
+ }
+
+ if (ideeprom) {
+ err = sysfs_create_link(&pdev->dev.kobj, &ideeprom->kobj, "id");
+ if (err)
+ dev_err(&pdev->dev,
+ "Failed to create link to ID eeprom\n");
+ }
+
+ if (cinfo->adap) {
+ err = sysfs_create_link(&pdev->dev.kobj,
+ &cinfo->adap->dev.kobj, "i2c-adapter");
+ if (err)
+ dev_err(&pdev->dev,
+ "Failed to create link to i2c adapter\n");
+ }
+ entry->pdev = pdev;
+ entry->dev = dev;
+
+ spin_lock(&jnx_board_list_lock);
+ list_add_tail(&entry->list, &jnx_board_list);
+ spin_unlock(&jnx_board_list_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(jnx_register_board);
+
+static struct jnx_board_entry *jnx_find_board_entry_by_dev(struct device *dev)
+{
+ struct jnx_board_entry *brd_entry;
+
+ spin_lock(&jnx_board_list_lock);
+
+ list_for_each_entry(brd_entry, &jnx_board_list, list) {
+ /*
+ * Device is either the device stored in brd_entry,
+ * or its parent (if there is a channel enable mux
+ * on the board).
+ */
+ if (brd_entry->dev == dev || brd_entry->dev->parent == dev)
+ goto found;
+ }
+
+ brd_entry = NULL;
+
+found:
+ spin_unlock(&jnx_board_list_lock);
+
+ return brd_entry;
+}
+
+int jnx_unregister_board(struct device *dev)
+{
+ struct jnx_board_entry *entry;
+
+ entry = jnx_find_board_entry_by_dev(dev);
+ if (!entry)
+ return -ENODEV;
+
+ if (!list_empty(&jnx_board_list)) {
+ spin_lock(&jnx_board_list_lock);
+ list_del(&entry->list);
+ spin_unlock(&jnx_board_list_lock);
+ }
+
+ sysfs_remove_link(&entry->pdev->dev.kobj, "id");
+ sysfs_remove_link(&entry->pdev->dev.kobj, "i2c-adapter");
+ platform_device_unregister(entry->pdev);
+
+ kfree(entry);
+
+ return 0;
+}
+EXPORT_SYMBOL(jnx_unregister_board);
+
+subsys_initcall(jnx_subsystem_init_pdev);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/include/linux/jnx/jnx-board-core.h b/include/linux/jnx/jnx-board-core.h
new file mode 100644
index 0000000..1b4747e
--- /dev/null
+++ b/include/linux/jnx/jnx-board-core.h
@@ -0,0 +1,41 @@
+/*
+ * Juniper Generic Board APIs
+ *
+ * Copyright (C) 2012, 2013 Juniper Networks. All rights reserved.
+ *
+ * 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 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.
+ */
+
+#ifndef _JNX_BOARD_CORE_H
+#define _JNX_BOARD_CORE_H
+
+/*
+ * Generic Juniper board I2C bus notification list handling
+ */
+struct jnx_board_i2c_entry {
+ struct i2c_board_info *board_info;
+ int bi_num;
+ char name[JNX_BRD_I2C_NAME_LEN];
+ struct work_struct work;
+ unsigned long action;
+ struct device *dev;
+ struct list_head list;
+};
+
+struct i2c_adapter *jnx_i2c_find_adapter(char *name);
+struct i2c_client *jnx_board_inserted(struct i2c_adapter *adap, int slot,
+ bool has_mux);
+void jnx_board_removed(struct i2c_adapter *adap, struct i2c_client *client);
+
+/* API testing warmboot: != 0: warmboot, == 0: coldboot */
+bool jnx_warmboot(void);
+
+#endif /* _JNX_BOARD_CORE_H */
diff --git a/include/linux/jnx/jnx-subsys.h b/include/linux/jnx/jnx-subsys.h
new file mode 100644
index 0000000..404304b
--- /dev/null
+++ b/include/linux/jnx/jnx-subsys.h
@@ -0,0 +1,94 @@
+/*
+ * Juniper Generic APIs for providing chassis and card information
+ *
+ * Copyright (C) 2012, 2013, 2014 Juniper Networks. All rights reserved.
+ *
+ * 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 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.
+ */
+
+#ifndef _JNX_SUBSYS_H
+#define _JNX_SUBSYS_H
+
+#include <uapi/linux/jnx/jnx-subsys.h>
+
+/*
+ * Juniper Product Number Definitions
+ */
+#define JNX_PRODUCT_HERCULES 7
+#define JNX_PRODUCT_SANGRIA 85
+#define JNX_PRODUCT_TINY 134
+#define JNX_PRODUCT_HENDRICKS 156
+#define JNX_PRODUCT_POLARIS 171
+#define JNX_PRODUCT_OMEGA 181
+
+#define JNX_BRD_I2C_NAME_LEN 24
+
+/* create and delete a link in jnx/card/<link> pointing to given dev */
+int jnx_sysfs_create_link(struct device *dev, const char *link);
+void jnx_sysfs_delete_link(struct device *dev, const char *link);
+
+/**
+ * struct jnx_card_info - juniper board per card information
+ * @assembly_id: assembly ID read from the EEPROM
+ * @slot: slot number in the chassis
+ * @type: type of card; see uapi jnx-subsys.h
+ * @data: per card user data
+ * @adap: pointer to the i2c_adapter EEPROM is on
+ *
+ * This structure contains information that each juniper board
+ * provides.
+ */
+struct jnx_card_info {
+ u16 assembly_id;
+ int slot;
+ u32 type;
+ void *data;
+ struct i2c_adapter *adap;
+};
+
+/* register and unregister a local jnx card */
+int jnx_register_local_card(struct jnx_card_info *cinfo);
+void jnx_unregister_local_card(void);
+
+/**
+ * struct jnx_chassis_info - juniper chassis info and method callbacks
+ * @platform: platform id of the chassis
+ * @chassis_no: chassis number - 0 if non-multi chassis
+ * @multichassis: non zero if a multichassis system
+ * @master_data: per chassis data
+ * @get_master: get slot number of master
+ * @mastership_get: returns whether we're master
+ * @mastership_set: Relinquish mastership
+ * @mastership_ping: update mastership watchdog
+ * @mastership_count_get: get mastership watchdog counter
+ * @mastership_count_set: set mastership watchdog counter
+ *
+ * This structure contains per chassis information and method callbacks that
+ * handle the per-platform CBD FPGA differences.
+ */
+struct jnx_chassis_info {
+ u32 platform;
+ u32 chassis_no;
+ u32 multichassis;
+ void *master_data;
+ int (*get_master)(void *data);
+ bool (*mastership_get)(void *data);
+ void (*mastership_set)(void *data, bool mastership);
+ void (*mastership_ping)(void *data);
+ int (*mastership_count_get)(void *data);
+ int (*mastership_count_set)(void *data, int val);
+};
+
+/* register and unregsiter a juniper chassis */
+int jnx_register_chassis(struct jnx_chassis_info *chinfo);
+void jnx_unregister_chassis(void);
+
+#endif /* _JNX_SUBSYS_H */
--
1.9.1
From: Rajat Jain <[email protected]>
Add this header to contain the PCI device IDs that we cannot add in
the linux pci_ids.h. This would contain PCI device IDs of
Juniper devices as well as any PCIe switches etc.
Signed-off-by: Rajat Jain <[email protected]>
Signed-off-by: Debjit Ghosh <[email protected]>
Signed-off-by: Georgi Vlaev <[email protected]>
Signed-off-by: Guenter Roeck <[email protected]>
Signed-off-by: Mohammad Kamil <[email protected]>
Signed-off-by: Shyamshankar Dharmarajan <[email protected]>
Signed-off-by: Tom Kavanagh <[email protected]>
[Ported from Juniper kernel]
Signed-off-by: Pantelis Antoniou <[email protected]>
---
include/linux/jnx/pci_ids.h | 66 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
create mode 100644 include/linux/jnx/pci_ids.h
diff --git a/include/linux/jnx/pci_ids.h b/include/linux/jnx/pci_ids.h
new file mode 100644
index 0000000..8c86aa8
--- /dev/null
+++ b/include/linux/jnx/pci_ids.h
@@ -0,0 +1,66 @@
+/*
+ * Juniper PCI ID(s) - for devices on Juniper Boards
+ *
+ * Rajat Jain <[email protected]>
+ * Copyright 2014 Juniper Networks
+ *
+ * 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.
+ */
+
+#ifndef __JNX_PCI_IDS_H__
+#define __JNX_PCI_IDS_H__
+
+#define PCI_VENDOR_ID_JUNIPER 0x1304
+
+/*
+ * PTX SAM FPGA, device ID as present on various Juniper boards, such as
+ * - Sangria FPC
+ * - Hendricks FPC
+ * - Sangria 24x10GE PIC
+ * - Gladiator FPC
+ */
+#define PCI_DEVICE_ID_JNX_SAM 0x0004
+
+/* Juniper Broadway ASIC family */
+#define PCI_DEVICE_ID_JNX_TF 0x003c
+#define PCI_DEVICE_ID_JNX_TL 0x003d
+#define PCI_DEVICE_ID_JNX_TQ 0x003e
+#define PCI_DEVICE_ID_JNX_OTN_FRAMER 0x0055
+#define PCI_DEVICE_ID_JNX_PE 0x005e
+#define PCI_DEVICE_ID_JNX_PF 0x005f /* Juniper Paradise ASIC */
+
+/* Juniper SAM FPGA - Omega SIB, Sochu SHAM, Gladiator SIB */
+#define PCI_DEVICE_ID_JNX_SAM_OMEGA 0x006a
+
+/* Juniper SAM FPGA - present on GLD FPC board */
+#define PCI_DEVICE_ID_JNX_SAM_X 0x006b
+
+/* Juniper PAM FPGA - present on PTX MLC board */
+#define PCI_DEVICE_ID_JNX_PAM 0x006c
+/* Juniper CBC FPGA - present on PTX1K RCB */
+#define PCI_DEVICE_ID_JNX_CBC 0x006e
+#define PCI_DEVICE_ID_JNX_CBC_P2 0x0079
+#define PCI_DEVICE_ID_JNX_OMG_CBC 0x0083
+
+/* Other Vendors' devices */
+#define PCI_DEVICE_ID_IDT_PES12NT3_TRANS_AB 0x8058
+#define PCI_DEVICE_ID_IDT_PES12NT3_TRANS_C 0x8059
+#define PCI_DEVICE_ID_IDT_PES12NT3_INT_NTB_C 0x805a
+#define PCI_DEVICE_ID_IDT_48H12G2 0x807a
+#define PCI_DEVICE_ID_IDT_PES24NT24G2 0x808e
+#define PCI_DEVICE_ID_IDT_PES16NT16G2 0x8090
+
+#define PCI_DEVICE_ID_PLX_8614 0x8614
+#define PCI_DEVICE_ID_PLX_8618 0x8618
+#define PCI_DEVICE_ID_PLX_8713 0x8713
+
+/*
+ * Juniper CBD FPGA Device ID(s)
+ */
+#define JNX_CBD_FPGA_DID_09B3 0x004D
+#define JNX_CBD_FPGA_DID_0BA8 0x005A
+
+#endif /* __JNX_PCI_IDS_H__ */
--
1.9.1
On Fri, Oct 07, 2016 at 06:15:44PM +0300, Pantelis Antoniou wrote:
> Introduce a staging driver containing all the bit and
> pieces of Juniper's board support infrastructure that don't quite
> fit in any other place.
Why staging?
> The Juniper series of routers comprise of both x86 and powerpc
> platforms that contain similar hardware components necessitating
> common support methods.
>
> Note that this is the first submission and we expect things to be
> moved around as required.
>
> This patchset is against mainline as of today: v4.8-9431-g3477d16
> and is dependent on the "Juniper prerequisites" patchset sent
> earlier.
sent where? Why not just make a single patch series?
> Rajat Jain (1):
> jnx: Introduce include/linux/jnx/pci_ids.h
>
> Tom Kavanagh (1):
> staging: jnx: Juniper subsystem & board core APIs
>
> Documentation/ABI/testing/sysfs-platform-jnx | 170 +++++++
> drivers/staging/Kconfig | 2 +
> drivers/staging/Makefile | 1 +
> drivers/staging/jnx/Kconfig | 24 +
> drivers/staging/jnx/Makefile | 5 +
> drivers/staging/jnx/jnx-board-core.c | 247 ++++++++++
> drivers/staging/jnx/jnx-subsys-private.h | 35 ++
> drivers/staging/jnx/jnx-subsys.c | 655 +++++++++++++++++++++++++++
> include/linux/jnx/jnx-board-core.h | 41 ++
> include/linux/jnx/jnx-subsys.h | 94 ++++
> include/linux/jnx/pci_ids.h | 66 +++
staging drivers have to be self-contained, no files outside of your
subdirectory please.
Once they have "passed" proper review, then you can move files out.
Also, I need a TODO file listing what needs to be done, who to contact,
and other info about the code.
And again, why not just submit this to the real part of the kernel?
thanks,
greg k-h
On Fri, Oct 07, 2016 at 06:15:46PM +0300, Pantelis Antoniou wrote:
> From: Rajat Jain <[email protected]>
>
> Add this header to contain the PCI device IDs that we cannot add in
> the linux pci_ids.h.
Why can't you?
> This would contain PCI device IDs of Juniper devices as well as any
> PCIe switches etc.
Why do you need a .h file for this? Is the values in it shared across
drivers? If not, you don't nee a .h file at all. If so, then it
belongs in pci_ids.h as the top of that file describes.
thanks,
greg k-h
On Fri, Oct 07, 2016 at 06:15:45PM +0300, Pantelis Antoniou wrote:
> From: Tom Kavanagh <[email protected]>
Minor nit:
> +config JNX_DEVICES
> + bool
> + default n
n is always the default.
And how about a help entry?
> +if JNX_DEVICES
> +
> +menu "Juniper Devices and Infrastructure"
> +
> +config JNX_SYSTEM
> + bool "Juniper System Infrastructure"
> + default y
Only make something 'y' if you have to boot a bare-bones machine with
it. That means almost no driver fits that category, and a staging
driver should never have this set either.
> + help
> + This driver adds support for Juniper System Infrastructure. It creates
> + platform devices for the platform, chassis and cards and provides sysfs
> + attributes for these devices.
> +
> + This driver can not be compiled as a module.
> +
> +endmenu
> +
> +endif # JNX_DEVICES
> diff --git a/drivers/staging/jnx/Makefile b/drivers/staging/jnx/Makefile
> new file mode 100644
> index 0000000..52b8286
> --- /dev/null
> +++ b/drivers/staging/jnx/Makefile
> @@ -0,0 +1,5 @@
> +#
> +# Makefile for Juniper devices that really don't fit anywhere else.
> +#
> +
> +obj-$(CONFIG_JNX_SYSTEM) += jnx-subsys.o jnx-board-core.o
> diff --git a/drivers/staging/jnx/jnx-board-core.c b/drivers/staging/jnx/jnx-board-core.c
> new file mode 100644
> index 0000000..218a8b7
> --- /dev/null
> +++ b/drivers/staging/jnx/jnx-board-core.c
> @@ -0,0 +1,247 @@
> +/*
> + * Juniper Generic Board APIs
> + *
> + * Copyright (C) 2012, 2013, 2014 Juniper Networks. All rights reserved.
> + *
> + * 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.
Really "any later version"? I have to ask.
> + *
> + * 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/device.h>
> +#include <linux/module.h>
> +#include <linux/i2c.h>
> +#include <linux/err.h>
> +#include <linux/nvmem-consumer.h>
> +#include <linux/platform_data/at24.h>
> +#include <linux/slab.h>
> +#include <linux/jnx/jnx-subsys.h>
> +#include <linux/jnx/jnx-board-core.h>
> +#include <linux/mfd/core.h>
> +#include <linux/mfd/jnx-i2cs-core.h>
> +
> +#include "jnx-subsys-private.h"
> +
> +#define DRIVER_VERSION "0.01.0"
> +#define DRIVER_DESC "Board Generic HW"
> +
> +static LIST_HEAD(jnx_i2c_notify_list);
> +static DEFINE_MUTEX(jnx_i2c_notify_lock);
> +
> +static int jnx_i2c_adap_name_match(struct device *dev, void *data)
> +{
> + struct i2c_adapter *adap = i2c_verify_adapter(dev);
> + char *name = data;
> +
> + if (!adap)
> + return false;
> +
> + return !strncmp(adap->name, name, strlen(name));
> +}
> +
> +struct i2c_adapter *jnx_i2c_find_adapter(char *name)
> +{
> + struct device *dev;
> + struct i2c_adapter *adap;
> +
> + dev = bus_find_device(&i2c_bus_type, NULL, name,
> + jnx_i2c_adap_name_match);
> + if (!dev)
> + return NULL;
> +
> + adap = i2c_verify_adapter(dev);
> + if (!adap)
> + put_device(dev);
> +
> + return adap;
> +}
> +EXPORT_SYMBOL(jnx_i2c_find_adapter);
EXPORT_SYMBOL_GPL()? Same for other exports. I have to ask.
thanks,
greg k-h