Re: [patch v1] x86/platform/mellanox: introduce support for Mellanox systems platform

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On September 11, 2016 11:29:58 PM PDT, vadimp@xxxxxxxxxxxx wrote:
>From: Vadim Pasternak <vadimp@xxxxxxxxxxxx>
>
>Enable system support for the Mellanox Technologies platform, which
>provides support for the next Mellanox basic systems: "msx6710",
>"msx6720", "msb7700", "msn2700", "msx1410", "msn2410", "msb7800",
>"msn2740", "msn2100" and also various number of derivative systems from
>the above basic types.
>
>The Kconfig currently controlling compilation of this code is:
>arch/x86/platform:config MLX_PLATFORM
>arch/x86/platform:      tristate "Mellanox Technologies platform
>support"
>
>Signed-off-by: Vadim Pasternak <vadimp@xxxxxxxxxxxx>
>---
> MAINTAINERS                               |   7 +
> arch/x86/Kconfig                          |  23 ++
> arch/x86/platform/Makefile                |   1 +
> arch/x86/platform/mellanox/Makefile       |   1 +
>arch/x86/platform/mellanox/mlx-platform.c | 501
>++++++++++++++++++++++++++++++
> 5 files changed, 533 insertions(+)
> create mode 100644 arch/x86/platform/mellanox/Makefile
> create mode 100644 arch/x86/platform/mellanox/mlx-platform.c
>
>diff --git a/MAINTAINERS b/MAINTAINERS
>index 4705c94..8a675de 100644
>--- a/MAINTAINERS
>+++ b/MAINTAINERS
>@@ -7664,6 +7664,13 @@ W:	http://www.mellanox.com
> Q:	http://patchwork.ozlabs.org/project/netdev/list/
> F:	drivers/net/ethernet/mellanox/mlxsw/
> 
>+MELLANOX PLATFORM DRIVER
>+M:      Vadim Pasternak <vadimp@xxxxxxxxxxxx>
>+L:      platform-driver-x86@xxxxxxxxxxxxxxx
>+S:      Supported
>+W:      http://www.mellanox.com
>+F:      arch/x86/platform/mellanox/mlx-platform.c
>+
> SOFT-ROCE DRIVER (rxe)
> M:	Moni Shoua <monis@xxxxxxxxxxxx>
> L:	linux-rdma@xxxxxxxxxxxxxxx
>diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
>index c580d8c..cc7efdd9 100644
>--- a/arch/x86/Kconfig
>+++ b/arch/x86/Kconfig
>@@ -2631,6 +2631,29 @@ config TS5500
> 
> endif # X86_32
> 
>+config MLX_PLATFORM
>+	tristate "Mellanox Technologies platform support"
>+	depends on X86_64
>+	depends on PCI
>+	depends on DMI
>+	depends on I2C_MLXCPLD
>+	depends on I2C_MUX_REG
>+	select HWMON
>+	select PMBUS
>+	select LM75
>+	select NEW_LEDS
>+	select LEDS_CLASS
>+	select LEDS_TRIGGERS
>+	select LEDS_TRIGGER_TIMER
>+	select LEDS_MLXCPLD
>+	---help---
>+	  This option enables system support for the Mellanox Technologies
>+	  platform.
>+
>+	  Say Y here if you are building a kernel for Mellanox system.
>+
>+	  Otherwise, say N.
>+
> config AMD_NB
> 	def_bool y
> 	depends on CPU_SUP_AMD && PCI
>diff --git a/arch/x86/platform/Makefile b/arch/x86/platform/Makefile
>index 184842e..3c3c19e 100644
>--- a/arch/x86/platform/Makefile
>+++ b/arch/x86/platform/Makefile
>@@ -8,6 +8,7 @@ obj-y	+= iris/
> obj-y	+= intel/
> obj-y	+= intel-mid/
> obj-y	+= intel-quark/
>+obj-y	+= mellanox/
> obj-y	+= olpc/
> obj-y	+= scx200/
> obj-y	+= sfi/
>diff --git a/arch/x86/platform/mellanox/Makefile
>b/arch/x86/platform/mellanox/Makefile
>new file mode 100644
>index 0000000..f43c931
>--- /dev/null
>+++ b/arch/x86/platform/mellanox/Makefile
>@@ -0,0 +1 @@
>+obj-$(CONFIG_MLX_PLATFORM)	+= mlx-platform.o
>diff --git a/arch/x86/platform/mellanox/mlx-platform.c
>b/arch/x86/platform/mellanox/mlx-platform.c
>new file mode 100644
>index 0000000..02afa89
>--- /dev/null
>+++ b/arch/x86/platform/mellanox/mlx-platform.c
>@@ -0,0 +1,501 @@
>+/*
>+ * arch/x86/platform/mellanox/mlx-platform.c
>+ * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
>+ * Copyright (c) 2016 Vadim Pasternak <vadimp@xxxxxxxxxxxx>
>+ *
>+ * Redistribution and use in source and binary forms, with or without
>+ * modification, are permitted provided that the following conditions
>are met:
>+ *
>+ * 1. Redistributions of source code must retain the above copyright
>+ *    notice, this list of conditions and the following disclaimer.
>+ * 2. Redistributions in binary form must reproduce the above
>copyright
>+ *    notice, this list of conditions and the following disclaimer in
>the
>+ *    documentation and/or other materials provided with the
>distribution.
>+ * 3. Neither the names of the copyright holders nor the names of its
>+ *    contributors may be used to endorse or promote products derived
>from
>+ *    this software without specific prior written permission.
>+ *
>+ * Alternatively, this software may be distributed under the terms of
>the
>+ * GNU General Public License ("GPL") version 2 as published by the
>Free
>+ * Software Foundation.
>+ *
>+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
>"AS IS"
>+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
>TO, THE
>+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
>PURPOSE
>+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
>CONTRIBUTORS BE
>+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
>+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
>OF
>+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
>BUSINESS
>+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
>WHETHER IN
>+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
>OTHERWISE)
>+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
>OF THE
>+ * POSSIBILITY OF SUCH DAMAGE.
>+ */
>+
>+#include <linux/acpi.h>
>+#include <linux/device.h>
>+#include <linux/i2c.h>
>+#include <linux/i2c-mux.h>
>+#include <linux/module.h>
>+#include <linux/of_platform.h>
>+#include <linux/platform_device.h>
>+#include <linux/platform_data/i2c-mux-reg.h>
>+#include <linux/pci.h>
>+#include <linux/slab.h>
>+#include <linux/version.h>
>+
>+#define MLX_PLAT_DEVICE_NAME		"mlxplat"
>+
>+/* LPC IFC in PCH defines */
>+#define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR		0x2000
>+#define MLXPLAT_CPLD_LPC_REG_BASE_ADRR		0x2500
>+#define MLXPLAT_CPLD_LPC_CTRL_IFC_BUS_ID	0
>+#define MLXPLAT_CPLD_LPC_CTRL_IFC_SLOT_ID	31
>+#define MLXPLAT_CPLD_LPC_CTRL_IFC_FUNC_ID	0
>+#define MLXPLAT_CPLD_LPC_QM67_DEV_ID		0x1c4f
>+#define MLXPLAT_CPLD_LPC_QM77_DEV_ID		0x1e55
>+#define MLXPLAT_CPLD_LPC_RNG_DEV_ID		0x1f38
>+#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF		0xdb
>+#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF		0xda
>+#define MLXPLAT_CPLD_LPC_PIO_OFFSET		0x10000UL
>+#define MLXPLAT_CPLD_LPC_REG1	((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
>+				  MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \
>+				  MLXPLAT_CPLD_LPC_PIO_OFFSET)
>+#define MLXPLAT_CPLD_LPC_REG2	((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
>+				  MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \
>+				  MLXPLAT_CPLD_LPC_PIO_OFFSET)
>+
>+/* Use generic decode range 4 for CPLD LPC */
>+#define MLXPLAT_CPLD_LPC_PCH_GEN_DEC_RANGE4	0x90
>+#define MLXPLAT_CPLD_LPC_PCH_GEN_DEC_BASE	0x84
>+#define MLXPLAT_CPLD_LPC_RNG_CTRL		0x84
>+#define MLXPLAT_CPLD_LPC_PCH_GEN_DEC_RANGES	4
>+#define MLXPLAT_CPLD_LPC_I2C_RANGE		2
>+#define MLXPLAT_CPLD_LPC_RANGE			3
>+#define MLXPLAT_CPLD_LPC_CLKS_EN		0
>+#define MLXPLAT_CPLD_LPC_IO_RANGE		0x100
>+
>+/* Start channel numbers */
>+#define MLXPLAT_CPLD_CH1			2
>+#define MLXPLAT_CPLD_CH2			10
>+
>+/* mlxplat_priv - board private data
>+ * @lpc_reg - register space
>+ * @dev_id - platform device id
>+ * @lpc_i2c_res- lpc cpld i2c resource space
>+ * @lpc_cpld_res - lpc cpld register resource space
>+ * @pdev - platform device
>+ */
>+struct mlxplat_priv {
>+	u32 lpc_reg[MLXPLAT_CPLD_LPC_PCH_GEN_DEC_RANGES];
>+	u16 dev_id;
>+	struct resource *lpc_i2c_res;
>+	struct resource *lpc_cpld_res;
>+	struct platform_device *pdev;
>+	struct platform_device *pdev_i2c;
>+};
>+
>+/* Regions for LPC I2C controller and LPC base register space */
>+static struct resource mlxplat_lpc_resources[] = {
>+	[0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR,
>+			       MLXPLAT_CPLD_LPC_IO_RANGE,
>+			       "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO),
>+	[1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR,
>+			       MLXPLAT_CPLD_LPC_IO_RANGE,
>+			       "mlxplat_cpld_lpc_regs",
>+			       IORESOURCE_IO),
>+};
>+
>+/* Platfform channels */
>+static int mlxplat_channels[][8] = {
>+	{
>+		MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2,
>+		MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 +
>+		5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7
>+	},
>+	{
>+		MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2,
>+		MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 +
>+		+ 5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7
>+	},
>+};
>+
>+/* Platform mux data */
>+struct i2c_mux_reg_platform_data mlxplat_mux_data[] = {
>+	{
>+		.parent = 1,
>+		.base_nr = MLXPLAT_CPLD_CH1,
>+		.write_only = 1,
>+		.values = mlxplat_channels[0],
>+		.n_values = ARRAY_SIZE(mlxplat_channels[0]),
>+		.reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
>+		.reg_size = 1,
>+		.idle_in_use = 1,
>+	},
>+	{
>+		.parent = 1,
>+		.base_nr = MLXPLAT_CPLD_CH2,
>+		.write_only = 1,
>+		.values = mlxplat_channels[1],
>+		.n_values = ARRAY_SIZE(mlxplat_channels[1]),
>+		.reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
>+		.reg_size = 1,
>+		.idle_in_use = 1,
>+	},
>+
>+};
>+
>+/* mlxplat_topology - platform entry data:
>+ * @pdev - platform device
>+ * @name - platform device name
>+ */
>+struct mlxplat_topology {
>+	struct platform_device *pdev;
>+	const char *name;
>+};
>+
>+/* Platform topology */
>+struct mlxplat_topology mlxplat_topo[] = {
>+	{
>+		.name = "i2c-mux-reg",
>+	},
>+	{
>+		.name = "i2c-mux-reg",
>+	},
>+};
>+
>+struct platform_device *mlxplat_dev;
>+
>+static int mlxplat_lpc_i2c_dec_range_config(struct mlxplat_priv *priv,
>+					    struct pci_dev *pdev, u8 range,
>+					    u16 base_addr)
>+{
>+	u16 rng_reg;
>+	u32 val;
>+	int err;
>+
>+	if (range >= MLXPLAT_CPLD_LPC_PCH_GEN_DEC_RANGES) {
>+		dev_err(&priv->pdev->dev, "Incorrect LPC decode range %d > %d\n",
>+			range, MLXPLAT_CPLD_LPC_PCH_GEN_DEC_RANGES);
>+		return -ERANGE;
>+	}
>+
>+	rng_reg = MLXPLAT_CPLD_LPC_PCH_GEN_DEC_BASE + 4 * range;
>+	err = pci_read_config_dword(pdev, rng_reg, &val);
>+	if (err) {
>+		dev_err(&priv->pdev->dev, "Access to LPC_PCH config failed, err
>%d\n",
>+			err);
>+		return -EFAULT;
>+	}
>+	priv->lpc_reg[range] = val;
>+
>+	/* Clean all bits excepted reserved (reserved: 2, 16, 17 , 24 - 31).
>*/
>+	val &= 0xff030002;
>+	/* Set bits 18 - 23 to allow decode range address mask, set bit 1 to
>+	 * enable decode range, clear bit 1,2 in base address.
>+	 */
>+	val |= 0xfc0001 | (base_addr & 0xfff3);
>+	err = pci_write_config_dword(pdev, rng_reg, val);
>+	if (err)
>+		dev_err(&priv->pdev->dev, "Config of LPC_PCH Generic Decode Range %d
>failed, err %d\n",
>+			range, err);
>+
>+	return err;
>+}
>+
>+static void mlxplat_lpc_dec_rng_config_clean(struct pci_dev *pdev, u32
>val,
>+					     u8 range)
>+{
>+	/* Restore old value */
>+	if (pci_write_config_dword(pdev, (MLXPLAT_CPLD_LPC_PCH_GEN_DEC_BASE +
>+				   range * 4), val))
>+		dev_err(&pdev->dev, "Deconfig of LPC_PCH Generic Decode Range %x
>failed\n",
>+			range);
>+
>+}
>+
>+static int mlxplat_lpc_request_region(struct mlxplat_priv *priv,
>+				      struct resource *res)
>+{
>+	resource_size_t size = resource_size(res);
>+
>+	if (!devm_request_region(&priv->pdev->dev, res->start, size,
>+				 res->name)) {
>+		devm_release_region(&priv->pdev->dev, res->start, size);
>+
>+		if (!devm_request_region(&priv->pdev->dev, res->start, size,
>+					 res->name)) {
>+			dev_err(&priv->pdev->dev, "Request ioregion 0x%llx len 0x%llx for
>%s fail\n",
>+				res->start, size, res->name);
>+			return -EIO;
>+		}
>+	}
>+
>+	return 0;
>+}
>+
>+static int mlxplat_lpc_request_regions(struct mlxplat_priv *priv)
>+{
>+	int i;
>+	int err;
>+
>+	for (i = 0; i < ARRAY_SIZE(mlxplat_lpc_resources); i++) {
>+		err = mlxplat_lpc_request_region(priv,
>+						 &mlxplat_lpc_resources[i]);
>+		if (err)
>+			return err;
>+	}
>+
>+	priv->lpc_i2c_res = &mlxplat_lpc_resources[0];
>+	priv->lpc_cpld_res = &mlxplat_lpc_resources[1];
>+
>+	return 0;
>+}
>+
>+static int mlxplat_lpc_ivb_config(struct mlxplat_priv *priv,
>+				  struct pci_dev *pdev)
>+{
>+	int err;
>+
>+	err = mlxplat_lpc_i2c_dec_range_config(priv, pdev,
>+					       MLXPLAT_CPLD_LPC_I2C_RANGE,
>+					       MLXPLAT_CPLD_LPC_I2C_BASE_ADRR);
>+	if (err) {
>+		dev_err(&priv->pdev->dev, "LPC decode range %d config failed, err
>%d\n",
>+			MLXPLAT_CPLD_LPC_I2C_RANGE, err);
>+		pci_dev_put(pdev);
>+		return -EFAULT;
>+	}
>+
>+	err = mlxplat_lpc_i2c_dec_range_config(priv, pdev,
>+					       MLXPLAT_CPLD_LPC_RANGE,
>+					       MLXPLAT_CPLD_LPC_REG_BASE_ADRR);
>+	if (err) {
>+		dev_err(&priv->pdev->dev, "LPC decode range %d config failed, err
>%d\n",
>+			MLXPLAT_CPLD_LPC_I2C_RANGE, err);
>+		return -EFAULT;
>+	}
>+
>+	return err;
>+}
>+
>+static void mlxplat_lpc_ivb_config_clean(struct mlxplat_priv *priv,
>+					 struct pci_dev *pdev)
>+{
>+	mlxplat_lpc_dec_rng_config_clean(pdev,
>+				priv->lpc_reg[MLXPLAT_CPLD_LPC_RANGE],
>+				MLXPLAT_CPLD_LPC_RANGE);
>+	mlxplat_lpc_dec_rng_config_clean(pdev,
>+				priv->lpc_reg[MLXPLAT_CPLD_LPC_I2C_RANGE],
>+				MLXPLAT_CPLD_LPC_I2C_RANGE);
>+
>+}
>+
>+static int mlxplat_lpc_range_config(struct mlxplat_priv *priv,
>+				    struct pci_dev *pdev)
>+{
>+	u32 val, lpc_clks;
>+	int err;
>+
>+	err = pci_read_config_dword(pdev, MLXPLAT_CPLD_LPC_RNG_CTRL, &val);
>+	if (err) {
>+		dev_err(&priv->pdev->dev, "Access to LPC Ctrl reg failed, err %d\n",
>+			err);
>+		return -EFAULT;
>+	}
>+	lpc_clks = val & 0x3;
>+	if (lpc_clks != MLXPLAT_CPLD_LPC_CLKS_EN) {
>+		val &= 0xFFFFFFFC;
>+		err = pci_write_config_dword(pdev, MLXPLAT_CPLD_LPC_RNG_CTRL,
>+					     val);
>+		if (err) {
>+			dev_err(&priv->pdev->dev, "Config LPC CLKS CTRL failed, err %d\n",
>+				err);
>+			return -EFAULT;
>+		}
>+	}
>+
>+	return err;
>+}
>+
>+static int mlxplat_lpc_config(struct mlxplat_priv *priv)
>+{
>+	struct pci_dev *pdev = NULL;
>+	u16 dev_id;
>+	int err;
>+
>+	pdev = pci_get_bus_and_slot(MLXPLAT_CPLD_LPC_CTRL_IFC_BUS_ID,
>+				PCI_DEVFN(MLXPLAT_CPLD_LPC_CTRL_IFC_SLOT_ID,
>+				MLXPLAT_CPLD_LPC_CTRL_IFC_FUNC_ID));
>+
>+	if (!pdev) {
>+		dev_err(&priv->pdev->dev, "LPC controller bus:%d slot:%d func:%d not
>found\n",
>+			MLXPLAT_CPLD_LPC_CTRL_IFC_BUS_ID,
>+			MLXPLAT_CPLD_LPC_CTRL_IFC_SLOT_ID,
>+			MLXPLAT_CPLD_LPC_CTRL_IFC_FUNC_ID);
>+		return -EFAULT;
>+	}
>+
>+	err = pci_read_config_word(pdev, 2, &dev_id);
>+	if (err) {
>+		dev_err(&priv->pdev->dev, "Access PCIe LPC interface failed, err
>%d\n",
>+			err);
>+		goto failure;
>+	}
>+
>+	switch (dev_id) {
>+	case MLXPLAT_CPLD_LPC_QM67_DEV_ID:
>+	case MLXPLAT_CPLD_LPC_QM77_DEV_ID:
>+		err = mlxplat_lpc_ivb_config(priv, pdev);
>+		break;
>+	case MLXPLAT_CPLD_LPC_RNG_DEV_ID:
>+		err = mlxplat_lpc_range_config(priv, pdev);
>+		break;
>+	default:
>+		err = -ENXIO;
>+		dev_err(&priv->pdev->dev, "Unsupported DevId 0x%x bus:%d slot:%d
>func:%d\n",
>+			dev_id, MLXPLAT_CPLD_LPC_CTRL_IFC_BUS_ID,
>+			MLXPLAT_CPLD_LPC_CTRL_IFC_SLOT_ID,
>+			MLXPLAT_CPLD_LPC_CTRL_IFC_FUNC_ID);
>+		goto failure;
>+	}
>+	priv->dev_id = dev_id;
>+
>+failure:
>+	pci_dev_put(pdev);
>+	return err;
>+}
>+
>+static int mlxplat_lpc_config_clean(struct mlxplat_priv *priv)
>+{
>+	struct pci_dev *pdev = NULL;
>+	int err = 0;
>+
>+	pdev = pci_get_bus_and_slot(MLXPLAT_CPLD_LPC_CTRL_IFC_BUS_ID,
>+				PCI_DEVFN(MLXPLAT_CPLD_LPC_CTRL_IFC_SLOT_ID,
>+				MLXPLAT_CPLD_LPC_CTRL_IFC_FUNC_ID));
>+	if (!pdev) {
>+		dev_err(&priv->pdev->dev, "LPC controller bus:%d slot:%d func:%d not
>found\n",
>+			MLXPLAT_CPLD_LPC_CTRL_IFC_BUS_ID,
>+			MLXPLAT_CPLD_LPC_CTRL_IFC_SLOT_ID,
>+			MLXPLAT_CPLD_LPC_CTRL_IFC_FUNC_ID);
>+		return -EFAULT;
>+	}
>+
>+	switch (priv->dev_id) {
>+	case MLXPLAT_CPLD_LPC_QM67_DEV_ID:
>+	case MLXPLAT_CPLD_LPC_QM77_DEV_ID:
>+		mlxplat_lpc_ivb_config_clean(priv, pdev);
>+		break;
>+	case MLXPLAT_CPLD_LPC_RNG_DEV_ID:
>+		break;
>+	default:
>+		err = -ENXIO;
>+		dev_err(&priv->pdev->dev, "Unsupported DevId 0x%x bus:%d slot:%d
>func:%d\n",
>+			priv->dev_id, MLXPLAT_CPLD_LPC_CTRL_IFC_BUS_ID,
>+			MLXPLAT_CPLD_LPC_CTRL_IFC_SLOT_ID,
>+			MLXPLAT_CPLD_LPC_CTRL_IFC_FUNC_ID);
>+		break;
>+	}
>+
>+	pci_dev_put(pdev);
>+
>+	return err;
>+}
>+
>+static int __init mlxplat_init(void)
>+{
>+	struct mlxplat_priv *priv;
>+	struct device *dev;
>+	int i, j;
>+	int err;
>+
>+	mlxplat_dev = platform_device_alloc(MLX_PLAT_DEVICE_NAME, -1);
>+	if (!mlxplat_dev) {
>+		pr_err("Alloc %s platform device failed\n",
>+			MLX_PLAT_DEVICE_NAME);
>+		return -ENOMEM;
>+	}
>+
>+	err = platform_device_add(mlxplat_dev);
>+	if (err) {
>+		pr_err("Add %s platform device failed (%d)\n",
>+			MLX_PLAT_DEVICE_NAME, err);
>+		goto fail_platform_device_add;
>+	}
>+	dev = &mlxplat_dev->dev;
>+
>+	priv = devm_kzalloc(dev, sizeof(struct mlxplat_priv), GFP_KERNEL);
>+	if (!priv) {
>+		err = -ENOMEM;
>+		dev_err(dev, "Failed to allocate mlxplat_priv\n");
>+		goto fail_alloc;
>+	}
>+	platform_set_drvdata(mlxplat_dev, priv);
>+	priv->pdev = mlxplat_dev;
>+
>+	err = mlxplat_lpc_config(priv);
>+	if (err) {
>+		dev_err(dev, "Failed to configure LPC interface\n");
>+		goto fail_alloc;
>+	}
>+
>+	err = mlxplat_lpc_request_regions(priv);
>+	if (err) {
>+		dev_err(dev, "Request ioregion failed (%d)\n", err);
>+		goto fail_alloc;
>+	}
>+
>+	priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1,
>+							 NULL, 0);
>+	if (IS_ERR(priv->pdev_i2c)) {
>+		err = PTR_ERR(priv->pdev_i2c);
>+		goto fail_alloc;
>+	};
>+
>+	for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) {
>+		mlxplat_topo[i].pdev = platform_device_register_resndata(dev,
>+						mlxplat_topo[i].name, i, NULL,
>+						0, &mlxplat_mux_data[i],
>+						sizeof(mlxplat_mux_data[i]));
>+		if (IS_ERR(mlxplat_topo[i].pdev)) {
>+			err = PTR_ERR(mlxplat_topo[i].pdev);
>+			goto fail_platform_mux_register;
>+		}
>+	}
>+
>+	return err;
>+
>+fail_platform_mux_register:
>+	for (j = i; j > 0 ; j--)
>+		platform_device_unregister(mlxplat_topo[j].pdev);
>+	platform_device_unregister(priv->pdev_i2c);
>+fail_alloc:
>+	platform_device_del(mlxplat_dev);
>+fail_platform_device_add:
>+	platform_device_put(mlxplat_dev);
>+
>+	return err;
>+}
>+
>+static void __exit mlxplat_exit(void)
>+{
>+	int i;
>+	struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
>+
>+	for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--)
>+		platform_device_unregister(mlxplat_topo[i].pdev);
>+
>+	platform_device_unregister(priv->pdev_i2c);
>+	mlxplat_lpc_config_clean(priv);
>+	platform_device_del(mlxplat_dev);
>+	platform_device_put(mlxplat_dev);
>+}
>+
>+module_init(mlxplat_init);
>+module_exit(mlxplat_exit);
>+
>+MODULE_AUTHOR("Vadim Pasternak (vadimp@xxxxxxxxxxxx)");
>+MODULE_DESCRIPTION("Mellanox platform driver");
>+MODULE_LICENSE("GPL v2");
>+MODULE_ALIAS("platform:mlx-platform");

This is a horrifically uninformative piece of code.  What does this driver do?  Why is it needed?  What makes it a "platform" in the sense of the way the term is used in the Linux kernel?  How does it affect the overall system, and in what sense does it diverge from a standard x86?
-- 
Sent from my Android device with K-9 Mail. Please excuse brevity and formatting.
--
To unsubscribe from this list: send the line "unsubscribe platform-driver-x86" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Kernel Development]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux