Commit ce7ec1b8 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'ptrp-ocp-next'



Jonathan Lemon says:

====================
ptp: ocp: update devlink information

Both of these patches update the information displayed via devlink.

v1 -> v2: remove board.manufacture information
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b57b44f7 b0ca789a
Loading
Loading
Loading
Loading
+138 −91
Original line number Diff line number Diff line
@@ -11,12 +11,14 @@
#include <linux/clkdev.h>
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include <linux/platform_data/i2c-xiic.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/spi/spi.h>
#include <linux/spi/xilinx_spi.h>
#include <net/devlink.h>
#include <linux/i2c.h>
#include <linux/mtd/mtd.h>
#include <linux/nvmem-consumer.h>

#ifndef PCI_VENDOR_ID_FACEBOOK
#define PCI_VENDOR_ID_FACEBOOK 0x1d9b
@@ -204,6 +206,9 @@ struct ptp_ocp_ext_src {
	int			irq_vec;
};

#define OCP_BOARD_ID_LEN		13
#define OCP_SERIAL_LEN			6

struct ptp_ocp {
	struct pci_dev		*pdev;
	struct device		dev;
@@ -230,6 +235,7 @@ struct ptp_ocp {
	struct platform_device	*spi_flash;
	struct clk_hw		*i2c_clk;
	struct timer_list	watchdog;
	const struct ptp_ocp_eeprom_map *eeprom_map;
	struct dentry		*debug_root;
	time64_t		gnss_lost;
	int			id;
@@ -238,8 +244,10 @@ struct ptp_ocp {
	int			gnss2_port;
	int			mac_port;	/* miniature atomic clock */
	int			nmea_port;
	u8			serial[6];
	bool			has_serial;
	u32			fw_version;
	u8			board_id[OCP_BOARD_ID_LEN];
	u8			serial[OCP_SERIAL_LEN];
	bool			has_eeprom_data;
	u32			pps_req_map;
	int			flash_start;
	u32			utc_tai_offset;
@@ -268,6 +276,28 @@ static int ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r);
static irqreturn_t ptp_ocp_ts_irq(int irq, void *priv);
static int ptp_ocp_ts_enable(void *priv, u32 req, bool enable);

struct ptp_ocp_eeprom_map {
	u16	off;
	u16	len;
	u32	bp_offset;
	const void * const tag;
};

#define EEPROM_ENTRY(addr, member)				\
	.off = addr,						\
	.len = sizeof_field(struct ptp_ocp, member),		\
	.bp_offset = offsetof(struct ptp_ocp, member)

#define BP_MAP_ENTRY_ADDR(bp, map) ({				\
	(void *)((uintptr_t)(bp) + (map)->bp_offset);		\
})

static struct ptp_ocp_eeprom_map fb_eeprom_map[] = {
	{ EEPROM_ENTRY(0x43, board_id) },
	{ EEPROM_ENTRY(0x00, serial), .tag = "mac" },
	{ }
};

#define bp_assign_entry(bp, res, val) ({				\
	uintptr_t addr = (uintptr_t)(bp) + (res)->bp_offset;		\
	*(typeof(val) *)addr = val;					\
@@ -396,6 +426,15 @@ static struct ocp_resource ocp_fb_resource[] = {
		.extra = &(struct ptp_ocp_i2c_info) {
			.name = "xiic-i2c",
			.fixed_rate = 50000000,
			.data_size = sizeof(struct xiic_i2c_platform_data),
			.data = &(struct xiic_i2c_platform_data) {
				.num_devices = 2,
				.devices = (struct i2c_board_info[]) {
					{ I2C_BOARD_INFO("24c02", 0x50) },
					{ I2C_BOARD_INFO("24mac402", 0x58),
					  .platform_data = "mac" },
				},
			},
		},
	},
	{
@@ -919,78 +958,88 @@ ptp_ocp_tod_gnss_name(int idx)
	return gnss_name[idx];
}

struct ptp_ocp_nvmem_match_info {
	struct ptp_ocp *bp;
	const void * const tag;
};

static int
ptp_ocp_firstchild(struct device *dev, void *data)
ptp_ocp_nvmem_match(struct device *dev, const void *data)
{
	return 1;
	const struct ptp_ocp_nvmem_match_info *info = data;

	dev = dev->parent;
	if (!i2c_verify_client(dev) || info->tag != dev->platform_data)
		return 0;

	while ((dev = dev->parent))
		if (dev->driver && !strcmp(dev->driver->name, KBUILD_MODNAME))
			return info->bp == dev_get_drvdata(dev);
	return 0;
}

static int
ptp_ocp_read_i2c(struct i2c_adapter *adap, u8 addr, u8 reg, u8 sz, u8 *data)
{
	struct i2c_msg msgs[2] = {
static inline struct nvmem_device *
ptp_ocp_nvmem_device_get(struct ptp_ocp *bp, const void * const tag)
{
			.addr = addr,
			.len = 1,
			.buf = &reg,
		},
	struct ptp_ocp_nvmem_match_info info = { .bp = bp, .tag = tag };

	return nvmem_device_find(&info, ptp_ocp_nvmem_match);
}

static inline void
ptp_ocp_nvmem_device_put(struct nvmem_device **nvmemp)
{
			.addr = addr,
			.flags = I2C_M_RD,
			.len = 2,
			.buf = data,
		},
	};
	int err;
	u8 len;

	/* xiic-i2c for some stupid reason only does 2 byte reads. */
	while (sz) {
		len = min_t(u8, sz, 2);
		msgs[1].len = len;
		err = i2c_transfer(adap, msgs, 2);
		if (err != msgs[1].len)
			return err;
		msgs[1].buf += len;
		reg += len;
		sz -= len;
	if (*nvmemp != NULL) {
		nvmem_device_put(*nvmemp);
		*nvmemp = NULL;
	}
	return 0;
}

static void
ptp_ocp_get_serial_number(struct ptp_ocp *bp)
ptp_ocp_read_eeprom(struct ptp_ocp *bp)
{
	struct i2c_adapter *adap;
	struct device *dev;
	int err;
	const struct ptp_ocp_eeprom_map *map;
	struct nvmem_device *nvmem;
	const void *tag;
	int ret;

	if (!bp->i2c_ctrl)
		return;

	dev = device_find_child(&bp->i2c_ctrl->dev, NULL, ptp_ocp_firstchild);
	if (!dev) {
		dev_err(&bp->pdev->dev, "Can't find I2C adapter\n");
		return;
	}
	tag = NULL;
	nvmem = NULL;

	adap = i2c_verify_adapter(dev);
	if (!adap) {
		dev_err(&bp->pdev->dev, "device '%s' isn't an I2C adapter\n",
			dev_name(dev));
		goto out;
	for (map = bp->eeprom_map; map->len; map++) {
		if (map->tag != tag) {
			tag = map->tag;
			ptp_ocp_nvmem_device_put(&nvmem);
		}

	err = ptp_ocp_read_i2c(adap, 0x58, 0x9A, 6, bp->serial);
	if (err) {
		dev_err(&bp->pdev->dev, "could not read eeprom: %d\n", err);
		if (!nvmem) {
			nvmem = ptp_ocp_nvmem_device_get(bp, tag);
			if (!nvmem)
				goto out;
		}
		ret = nvmem_device_read(nvmem, map->off, map->len,
					BP_MAP_ENTRY_ADDR(bp, map));
		if (ret != map->len)
			goto read_fail;
	}

	bp->has_serial = true;
	bp->has_eeprom_data = true;

out:
	put_device(dev);
	ptp_ocp_nvmem_device_put(&nvmem);
	return;

read_fail:
	dev_err(&bp->pdev->dev, "could not read eeprom: %d\n", ret);
	goto out;
}

static int
ptp_ocp_firstchild(struct device *dev, void *data)
{
	return 1;
}

static struct device *
@@ -1091,33 +1140,32 @@ ptp_ocp_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
	if (err)
		return err;

	if (bp->image) {
		u32 ver = ioread32(&bp->image->version);

		if (ver & 0xffff) {
			sprintf(buf, "%d", ver);
			err = devlink_info_version_running_put(req,
							       "fw",
							       buf);
	if (bp->fw_version & 0xffff) {
		sprintf(buf, "%d", bp->fw_version);
		err = devlink_info_version_running_put(req, "fw", buf);
	} else {
			sprintf(buf, "%d", ver >> 16);
			err = devlink_info_version_running_put(req,
							       "loader",
							       buf);
		sprintf(buf, "%d", bp->fw_version >> 16);
		err = devlink_info_version_running_put(req, "loader", buf);
	}
	if (err)
		return err;
	}

	if (!bp->has_serial)
		ptp_ocp_get_serial_number(bp);
	if (!bp->has_eeprom_data) {
		ptp_ocp_read_eeprom(bp);
		if (!bp->has_eeprom_data)
			return 0;
	}

	if (bp->has_serial) {
	sprintf(buf, "%pM", bp->serial);
	err = devlink_info_serial_number_put(req, buf);
	if (err)
		return err;
	}

	err = devlink_info_version_fixed_put(req,
			DEVLINK_INFO_VERSION_GENERIC_BOARD_ID,
			bp->board_id);
	if (err)
		return err;

	return 0;
}
@@ -1412,6 +1460,8 @@ static int
ptp_ocp_fb_board_init(struct ptp_ocp *bp, struct ocp_resource *r)
{
	bp->flash_start = 1024 * 4096;
	bp->eeprom_map = fb_eeprom_map;
	bp->fw_version = ioread32(&bp->image->version);

	ptp_ocp_tod_init(bp);
	ptp_ocp_nmea_out_init(bp);
@@ -1810,8 +1860,8 @@ serialnum_show(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct ptp_ocp *bp = dev_get_drvdata(dev);

	if (!bp->has_serial)
		ptp_ocp_get_serial_number(bp);
	if (!bp->has_eeprom_data)
		ptp_ocp_read_eeprom(bp);

	return sysfs_emit(buf, "%pM\n", bp->serial);
}
@@ -2520,17 +2570,14 @@ ptp_ocp_info(struct ptp_ocp *bp)

	ptp_ocp_phc_info(bp);

	if (bp->image) {
		u32 ver = ioread32(&bp->image->version);

		dev_info(dev, "version %x\n", ver);
		if (ver & 0xffff)
	dev_info(dev, "version %x\n", bp->fw_version);
	if (bp->fw_version & 0xffff)
		dev_info(dev, "regular image, version %d\n",
				 ver & 0xffff);
			 bp->fw_version & 0xffff);
	else
		dev_info(dev, "golden image, version %d\n",
				 ver >> 16);
	}
			 bp->fw_version >> 16);

	ptp_ocp_serial_info(dev, "GNSS", bp->gnss_port, 115200);
	ptp_ocp_serial_info(dev, "GNSS2", bp->gnss2_port, 115200);
	ptp_ocp_serial_info(dev, "MAC", bp->mac_port, 57600);