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

i2c-viperboard.c (11985B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Nano River Technologies viperboard i2c master driver
      4 *
      5 *  (C) 2012 by Lemonage GmbH
      6 *  Author: Lars Poeschel <poeschel@lemonage.de>
      7 *  All rights reserved.
      8 */
      9
     10#include <linux/kernel.h>
     11#include <linux/errno.h>
     12#include <linux/module.h>
     13#include <linux/slab.h>
     14#include <linux/types.h>
     15#include <linux/mutex.h>
     16#include <linux/platform_device.h>
     17
     18#include <linux/usb.h>
     19#include <linux/i2c.h>
     20
     21#include <linux/mfd/viperboard.h>
     22
     23struct vprbrd_i2c {
     24	struct i2c_adapter i2c;
     25	u8 bus_freq_param;
     26};
     27
     28/* i2c bus frequency module parameter */
     29static u8 i2c_bus_param;
     30static unsigned int i2c_bus_freq = 100;
     31module_param(i2c_bus_freq, int, 0);
     32MODULE_PARM_DESC(i2c_bus_freq,
     33	"i2c bus frequency in khz (default is 100) valid values: 10, 100, 200, 400, 1000, 3000, 6000");
     34
     35static int vprbrd_i2c_status(struct i2c_adapter *i2c,
     36	struct vprbrd_i2c_status *status, bool prev_error)
     37{
     38	u16 bytes_xfer;
     39	int ret;
     40	struct vprbrd *vb = (struct vprbrd *)i2c->algo_data;
     41
     42	/* check for protocol error */
     43	bytes_xfer = sizeof(struct vprbrd_i2c_status);
     44
     45	ret = usb_control_msg(vb->usb_dev, usb_rcvctrlpipe(vb->usb_dev, 0),
     46		VPRBRD_USB_REQUEST_I2C, VPRBRD_USB_TYPE_IN, 0x0000, 0x0000,
     47		status, bytes_xfer, VPRBRD_USB_TIMEOUT_MS);
     48
     49	if (ret != bytes_xfer)
     50		prev_error = true;
     51
     52	if (prev_error) {
     53		dev_err(&i2c->dev, "failure in usb communication\n");
     54		return -EREMOTEIO;
     55	}
     56
     57	dev_dbg(&i2c->dev, "  status = %d\n", status->status);
     58	if (status->status != 0x00) {
     59		dev_err(&i2c->dev, "failure: i2c protocol error\n");
     60		return -EPROTO;
     61	}
     62	return 0;
     63}
     64
     65static int vprbrd_i2c_receive(struct usb_device *usb_dev,
     66	struct vprbrd_i2c_read_msg *rmsg, int bytes_xfer)
     67{
     68	int ret, bytes_actual;
     69	int error = 0;
     70
     71	/* send the read request */
     72	ret = usb_bulk_msg(usb_dev,
     73		usb_sndbulkpipe(usb_dev, VPRBRD_EP_OUT), rmsg,
     74		sizeof(struct vprbrd_i2c_read_hdr), &bytes_actual,
     75		VPRBRD_USB_TIMEOUT_MS);
     76
     77	if ((ret < 0)
     78		|| (bytes_actual != sizeof(struct vprbrd_i2c_read_hdr))) {
     79		dev_err(&usb_dev->dev, "failure transmitting usb\n");
     80		error = -EREMOTEIO;
     81	}
     82
     83	/* read the actual data */
     84	ret = usb_bulk_msg(usb_dev,
     85		usb_rcvbulkpipe(usb_dev, VPRBRD_EP_IN), rmsg,
     86		bytes_xfer, &bytes_actual, VPRBRD_USB_TIMEOUT_MS);
     87
     88	if ((ret < 0) || (bytes_xfer != bytes_actual)) {
     89		dev_err(&usb_dev->dev, "failure receiving usb\n");
     90		error = -EREMOTEIO;
     91	}
     92	return error;
     93}
     94
     95static int vprbrd_i2c_addr(struct usb_device *usb_dev,
     96	struct vprbrd_i2c_addr_msg *amsg)
     97{
     98	int ret, bytes_actual;
     99
    100	ret = usb_bulk_msg(usb_dev,
    101		usb_sndbulkpipe(usb_dev, VPRBRD_EP_OUT), amsg,
    102		sizeof(struct vprbrd_i2c_addr_msg), &bytes_actual,
    103		VPRBRD_USB_TIMEOUT_MS);
    104
    105	if ((ret < 0) ||
    106			(sizeof(struct vprbrd_i2c_addr_msg) != bytes_actual)) {
    107		dev_err(&usb_dev->dev, "failure transmitting usb\n");
    108		return -EREMOTEIO;
    109	}
    110	return 0;
    111}
    112
    113static int vprbrd_i2c_read(struct vprbrd *vb, struct i2c_msg *msg)
    114{
    115	int ret;
    116	u16 remain_len, len1, len2, start = 0x0000;
    117	struct vprbrd_i2c_read_msg *rmsg =
    118		(struct vprbrd_i2c_read_msg *)vb->buf;
    119
    120	remain_len = msg->len;
    121	rmsg->header.cmd = VPRBRD_I2C_CMD_READ;
    122	while (remain_len > 0) {
    123		rmsg->header.addr = cpu_to_le16(start + 0x4000);
    124		if (remain_len <= 255) {
    125			len1 = remain_len;
    126			len2 = 0x00;
    127			rmsg->header.len0 = remain_len;
    128			rmsg->header.len1 = 0x00;
    129			rmsg->header.len2 = 0x00;
    130			rmsg->header.len3 = 0x00;
    131			rmsg->header.len4 = 0x00;
    132			rmsg->header.len5 = 0x00;
    133			remain_len = 0;
    134		} else if (remain_len <= 510) {
    135			len1 = remain_len;
    136			len2 = 0x00;
    137			rmsg->header.len0 = remain_len - 255;
    138			rmsg->header.len1 = 0xff;
    139			rmsg->header.len2 = 0x00;
    140			rmsg->header.len3 = 0x00;
    141			rmsg->header.len4 = 0x00;
    142			rmsg->header.len5 = 0x00;
    143			remain_len = 0;
    144		} else if (remain_len <= 512) {
    145			len1 = remain_len;
    146			len2 = 0x00;
    147			rmsg->header.len0 = remain_len - 510;
    148			rmsg->header.len1 = 0xff;
    149			rmsg->header.len2 = 0xff;
    150			rmsg->header.len3 = 0x00;
    151			rmsg->header.len4 = 0x00;
    152			rmsg->header.len5 = 0x00;
    153			remain_len = 0;
    154		} else if (remain_len <= 767) {
    155			len1 = 512;
    156			len2 = remain_len - 512;
    157			rmsg->header.len0 = 0x02;
    158			rmsg->header.len1 = 0xff;
    159			rmsg->header.len2 = 0xff;
    160			rmsg->header.len3 = remain_len - 512;
    161			rmsg->header.len4 = 0x00;
    162			rmsg->header.len5 = 0x00;
    163			remain_len = 0;
    164		} else if (remain_len <= 1022) {
    165			len1 = 512;
    166			len2 = remain_len - 512;
    167			rmsg->header.len0 = 0x02;
    168			rmsg->header.len1 = 0xff;
    169			rmsg->header.len2 = 0xff;
    170			rmsg->header.len3 = remain_len - 767;
    171			rmsg->header.len4 = 0xff;
    172			rmsg->header.len5 = 0x00;
    173			remain_len = 0;
    174		} else if (remain_len <= 1024) {
    175			len1 = 512;
    176			len2 = remain_len - 512;
    177			rmsg->header.len0 = 0x02;
    178			rmsg->header.len1 = 0xff;
    179			rmsg->header.len2 = 0xff;
    180			rmsg->header.len3 = remain_len - 1022;
    181			rmsg->header.len4 = 0xff;
    182			rmsg->header.len5 = 0xff;
    183			remain_len = 0;
    184		} else {
    185			len1 = 512;
    186			len2 = 512;
    187			rmsg->header.len0 = 0x02;
    188			rmsg->header.len1 = 0xff;
    189			rmsg->header.len2 = 0xff;
    190			rmsg->header.len3 = 0x02;
    191			rmsg->header.len4 = 0xff;
    192			rmsg->header.len5 = 0xff;
    193			remain_len -= 1024;
    194			start += 1024;
    195		}
    196		rmsg->header.tf1 = cpu_to_le16(len1);
    197		rmsg->header.tf2 = cpu_to_le16(len2);
    198
    199		/* first read transfer */
    200		ret = vprbrd_i2c_receive(vb->usb_dev, rmsg, len1);
    201		if (ret < 0)
    202			return ret;
    203		/* copy the received data */
    204		memcpy(msg->buf + start, rmsg, len1);
    205
    206		/* second read transfer if neccessary */
    207		if (len2 > 0) {
    208			ret = vprbrd_i2c_receive(vb->usb_dev, rmsg, len2);
    209			if (ret < 0)
    210				return ret;
    211			/* copy the received data */
    212			memcpy(msg->buf + start + 512, rmsg, len2);
    213		}
    214	}
    215	return 0;
    216}
    217
    218static int vprbrd_i2c_write(struct vprbrd *vb, struct i2c_msg *msg)
    219{
    220	int ret, bytes_actual;
    221	u16 remain_len, bytes_xfer,
    222		start = 0x0000;
    223	struct vprbrd_i2c_write_msg *wmsg =
    224		(struct vprbrd_i2c_write_msg *)vb->buf;
    225
    226	remain_len = msg->len;
    227	wmsg->header.cmd = VPRBRD_I2C_CMD_WRITE;
    228	wmsg->header.last = 0x00;
    229	wmsg->header.chan = 0x00;
    230	wmsg->header.spi = 0x0000;
    231	while (remain_len > 0) {
    232		wmsg->header.addr = cpu_to_le16(start + 0x4000);
    233		if (remain_len > 503) {
    234			wmsg->header.len1 = 0xff;
    235			wmsg->header.len2 = 0xf8;
    236			remain_len -= 503;
    237			bytes_xfer = 503 + sizeof(struct vprbrd_i2c_write_hdr);
    238			start += 503;
    239		} else if (remain_len > 255) {
    240			wmsg->header.len1 = 0xff;
    241			wmsg->header.len2 = (remain_len - 255);
    242			bytes_xfer = remain_len +
    243				sizeof(struct vprbrd_i2c_write_hdr);
    244			remain_len = 0;
    245		} else {
    246			wmsg->header.len1 = remain_len;
    247			wmsg->header.len2 = 0x00;
    248			bytes_xfer = remain_len +
    249				sizeof(struct vprbrd_i2c_write_hdr);
    250			remain_len = 0;
    251		}
    252		memcpy(wmsg->data, msg->buf + start,
    253			bytes_xfer - sizeof(struct vprbrd_i2c_write_hdr));
    254
    255		ret = usb_bulk_msg(vb->usb_dev,
    256			usb_sndbulkpipe(vb->usb_dev,
    257			VPRBRD_EP_OUT), wmsg,
    258			bytes_xfer, &bytes_actual, VPRBRD_USB_TIMEOUT_MS);
    259		if ((ret < 0) || (bytes_xfer != bytes_actual))
    260			return -EREMOTEIO;
    261	}
    262	return 0;
    263}
    264
    265static int vprbrd_i2c_xfer(struct i2c_adapter *i2c, struct i2c_msg *msgs,
    266		int num)
    267{
    268	struct i2c_msg *pmsg;
    269	int i, ret,
    270		error = 0;
    271	struct vprbrd *vb = (struct vprbrd *)i2c->algo_data;
    272	struct vprbrd_i2c_addr_msg *amsg =
    273		(struct vprbrd_i2c_addr_msg *)vb->buf;
    274	struct vprbrd_i2c_status *smsg = (struct vprbrd_i2c_status *)vb->buf;
    275
    276	dev_dbg(&i2c->dev, "master xfer %d messages:\n", num);
    277
    278	for (i = 0 ; i < num ; i++) {
    279		pmsg = &msgs[i];
    280
    281		dev_dbg(&i2c->dev,
    282			"  %d: %s (flags %d) %d bytes to 0x%02x\n",
    283			i, pmsg->flags & I2C_M_RD ? "read" : "write",
    284			pmsg->flags, pmsg->len, pmsg->addr);
    285
    286		mutex_lock(&vb->lock);
    287		/* directly send the message */
    288		if (pmsg->flags & I2C_M_RD) {
    289			/* read data */
    290			amsg->cmd = VPRBRD_I2C_CMD_ADDR;
    291			amsg->unknown2 = 0x00;
    292			amsg->unknown3 = 0x00;
    293			amsg->addr = pmsg->addr;
    294			amsg->unknown1 = 0x01;
    295			amsg->len = cpu_to_le16(pmsg->len);
    296			/* send the addr and len, we're interested to board */
    297			ret = vprbrd_i2c_addr(vb->usb_dev, amsg);
    298			if (ret < 0)
    299				error = ret;
    300
    301			ret = vprbrd_i2c_read(vb, pmsg);
    302			if (ret < 0)
    303				error = ret;
    304
    305			ret = vprbrd_i2c_status(i2c, smsg, error);
    306			if (ret < 0)
    307				error = ret;
    308			/* in case of protocol error, return the error */
    309			if (error < 0)
    310				goto error;
    311		} else {
    312			/* write data */
    313			ret = vprbrd_i2c_write(vb, pmsg);
    314
    315			amsg->cmd = VPRBRD_I2C_CMD_ADDR;
    316			amsg->unknown2 = 0x00;
    317			amsg->unknown3 = 0x00;
    318			amsg->addr = pmsg->addr;
    319			amsg->unknown1 = 0x00;
    320			amsg->len = cpu_to_le16(pmsg->len);
    321			/* send the addr, the data goes to to board */
    322			ret = vprbrd_i2c_addr(vb->usb_dev, amsg);
    323			if (ret < 0)
    324				error = ret;
    325
    326			ret = vprbrd_i2c_status(i2c, smsg, error);
    327			if (ret < 0)
    328				error = ret;
    329
    330			if (error < 0)
    331				goto error;
    332		}
    333		mutex_unlock(&vb->lock);
    334	}
    335	return num;
    336error:
    337	mutex_unlock(&vb->lock);
    338	return error;
    339}
    340
    341static u32 vprbrd_i2c_func(struct i2c_adapter *i2c)
    342{
    343	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
    344}
    345
    346/* This is the actual algorithm we define */
    347static const struct i2c_algorithm vprbrd_algorithm = {
    348	.master_xfer	= vprbrd_i2c_xfer,
    349	.functionality	= vprbrd_i2c_func,
    350};
    351
    352static const struct i2c_adapter_quirks vprbrd_quirks = {
    353	.max_read_len = 2048,
    354	.max_write_len = 2048,
    355};
    356
    357static int vprbrd_i2c_probe(struct platform_device *pdev)
    358{
    359	struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent);
    360	struct vprbrd_i2c *vb_i2c;
    361	int ret;
    362	int pipe;
    363
    364	vb_i2c = devm_kzalloc(&pdev->dev, sizeof(*vb_i2c), GFP_KERNEL);
    365	if (vb_i2c == NULL)
    366		return -ENOMEM;
    367
    368	/* setup i2c adapter description */
    369	vb_i2c->i2c.owner = THIS_MODULE;
    370	vb_i2c->i2c.class = I2C_CLASS_HWMON;
    371	vb_i2c->i2c.algo = &vprbrd_algorithm;
    372	vb_i2c->i2c.quirks = &vprbrd_quirks;
    373	vb_i2c->i2c.algo_data = vb;
    374	/* save the param in usb capabable memory */
    375	vb_i2c->bus_freq_param = i2c_bus_param;
    376
    377	snprintf(vb_i2c->i2c.name, sizeof(vb_i2c->i2c.name),
    378		 "viperboard at bus %03d device %03d",
    379		 vb->usb_dev->bus->busnum, vb->usb_dev->devnum);
    380
    381	/* setting the bus frequency */
    382	if ((i2c_bus_param <= VPRBRD_I2C_FREQ_10KHZ)
    383		&& (i2c_bus_param >= VPRBRD_I2C_FREQ_6MHZ)) {
    384		pipe = usb_sndctrlpipe(vb->usb_dev, 0);
    385		ret = usb_control_msg(vb->usb_dev, pipe,
    386			VPRBRD_USB_REQUEST_I2C_FREQ, VPRBRD_USB_TYPE_OUT,
    387			0x0000, 0x0000, &vb_i2c->bus_freq_param, 1,
    388			VPRBRD_USB_TIMEOUT_MS);
    389		if (ret != 1) {
    390			dev_err(&pdev->dev, "failure setting i2c_bus_freq to %d\n",
    391				i2c_bus_freq);
    392			return -EIO;
    393		}
    394	} else {
    395		dev_err(&pdev->dev,
    396			"invalid i2c_bus_freq setting:%d\n", i2c_bus_freq);
    397		return -EIO;
    398	}
    399
    400	vb_i2c->i2c.dev.parent = &pdev->dev;
    401
    402	/* attach to i2c layer */
    403	i2c_add_adapter(&vb_i2c->i2c);
    404
    405	platform_set_drvdata(pdev, vb_i2c);
    406
    407	return 0;
    408}
    409
    410static int vprbrd_i2c_remove(struct platform_device *pdev)
    411{
    412	struct vprbrd_i2c *vb_i2c = platform_get_drvdata(pdev);
    413
    414	i2c_del_adapter(&vb_i2c->i2c);
    415
    416	return 0;
    417}
    418
    419static struct platform_driver vprbrd_i2c_driver = {
    420	.driver.name	= "viperboard-i2c",
    421	.driver.owner	= THIS_MODULE,
    422	.probe		= vprbrd_i2c_probe,
    423	.remove		= vprbrd_i2c_remove,
    424};
    425
    426static int __init vprbrd_i2c_init(void)
    427{
    428	switch (i2c_bus_freq) {
    429	case 6000:
    430		i2c_bus_param = VPRBRD_I2C_FREQ_6MHZ;
    431		break;
    432	case 3000:
    433		i2c_bus_param = VPRBRD_I2C_FREQ_3MHZ;
    434		break;
    435	case 1000:
    436		i2c_bus_param = VPRBRD_I2C_FREQ_1MHZ;
    437		break;
    438	case 400:
    439		i2c_bus_param = VPRBRD_I2C_FREQ_400KHZ;
    440		break;
    441	case 200:
    442		i2c_bus_param = VPRBRD_I2C_FREQ_200KHZ;
    443		break;
    444	case 100:
    445		i2c_bus_param = VPRBRD_I2C_FREQ_100KHZ;
    446		break;
    447	case 10:
    448		i2c_bus_param = VPRBRD_I2C_FREQ_10KHZ;
    449		break;
    450	default:
    451		pr_warn("invalid i2c_bus_freq (%d)\n", i2c_bus_freq);
    452		i2c_bus_param = VPRBRD_I2C_FREQ_100KHZ;
    453	}
    454
    455	return platform_driver_register(&vprbrd_i2c_driver);
    456}
    457subsys_initcall(vprbrd_i2c_init);
    458
    459static void __exit vprbrd_i2c_exit(void)
    460{
    461	platform_driver_unregister(&vprbrd_i2c_driver);
    462}
    463module_exit(vprbrd_i2c_exit);
    464
    465MODULE_AUTHOR("Lars Poeschel <poeschel@lemonage.de>");
    466MODULE_DESCRIPTION("I2C master driver for Nano River Techs Viperboard");
    467MODULE_LICENSE("GPL");
    468MODULE_ALIAS("platform:viperboard-i2c");