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

solo6x10-i2c.c (6988B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com>
      4 *
      5 * Original author:
      6 * Ben Collins <bcollins@ubuntu.com>
      7 *
      8 * Additional work by:
      9 * John Brooks <john.brooks@bluecherry.net>
     10 */
     11
     12/* XXX: The SOLO6x10 i2c does not have separate interrupts for each i2c
     13 * channel. The bus can only handle one i2c event at a time. The below handles
     14 * this all wrong. We should be using the status registers to see if the bus
     15 * is in use, and have a global lock to check the status register. Also,
     16 * the bulk of the work should be handled out-of-interrupt. The ugly loops
     17 * that occur during interrupt scare me. The ISR should merely signal
     18 * thread context, ACK the interrupt, and move on. -- BenC */
     19
     20#include <linux/kernel.h>
     21#include <linux/sched/signal.h>
     22
     23#include "solo6x10.h"
     24
     25u8 solo_i2c_readbyte(struct solo_dev *solo_dev, int id, u8 addr, u8 off)
     26{
     27	struct i2c_msg msgs[2];
     28	u8 data;
     29
     30	msgs[0].flags = 0;
     31	msgs[0].addr = addr;
     32	msgs[0].len = 1;
     33	msgs[0].buf = &off;
     34
     35	msgs[1].flags = I2C_M_RD;
     36	msgs[1].addr = addr;
     37	msgs[1].len = 1;
     38	msgs[1].buf = &data;
     39
     40	i2c_transfer(&solo_dev->i2c_adap[id], msgs, 2);
     41
     42	return data;
     43}
     44
     45void solo_i2c_writebyte(struct solo_dev *solo_dev, int id, u8 addr,
     46			u8 off, u8 data)
     47{
     48	struct i2c_msg msgs;
     49	u8 buf[2];
     50
     51	buf[0] = off;
     52	buf[1] = data;
     53	msgs.flags = 0;
     54	msgs.addr = addr;
     55	msgs.len = 2;
     56	msgs.buf = buf;
     57
     58	i2c_transfer(&solo_dev->i2c_adap[id], &msgs, 1);
     59}
     60
     61static void solo_i2c_flush(struct solo_dev *solo_dev, int wr)
     62{
     63	u32 ctrl;
     64
     65	ctrl = SOLO_IIC_CH_SET(solo_dev->i2c_id);
     66
     67	if (solo_dev->i2c_state == IIC_STATE_START)
     68		ctrl |= SOLO_IIC_START;
     69
     70	if (wr) {
     71		ctrl |= SOLO_IIC_WRITE;
     72	} else {
     73		ctrl |= SOLO_IIC_READ;
     74		if (!(solo_dev->i2c_msg->flags & I2C_M_NO_RD_ACK))
     75			ctrl |= SOLO_IIC_ACK_EN;
     76	}
     77
     78	if (solo_dev->i2c_msg_ptr == solo_dev->i2c_msg->len)
     79		ctrl |= SOLO_IIC_STOP;
     80
     81	solo_reg_write(solo_dev, SOLO_IIC_CTRL, ctrl);
     82}
     83
     84static void solo_i2c_start(struct solo_dev *solo_dev)
     85{
     86	u32 addr = solo_dev->i2c_msg->addr << 1;
     87
     88	if (solo_dev->i2c_msg->flags & I2C_M_RD)
     89		addr |= 1;
     90
     91	solo_dev->i2c_state = IIC_STATE_START;
     92	solo_reg_write(solo_dev, SOLO_IIC_TXD, addr);
     93	solo_i2c_flush(solo_dev, 1);
     94}
     95
     96static void solo_i2c_stop(struct solo_dev *solo_dev)
     97{
     98	solo_irq_off(solo_dev, SOLO_IRQ_IIC);
     99	solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0);
    100	solo_dev->i2c_state = IIC_STATE_STOP;
    101	wake_up(&solo_dev->i2c_wait);
    102}
    103
    104static int solo_i2c_handle_read(struct solo_dev *solo_dev)
    105{
    106prepare_read:
    107	if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) {
    108		solo_i2c_flush(solo_dev, 0);
    109		return 0;
    110	}
    111
    112	solo_dev->i2c_msg_ptr = 0;
    113	solo_dev->i2c_msg++;
    114	solo_dev->i2c_msg_num--;
    115
    116	if (solo_dev->i2c_msg_num == 0) {
    117		solo_i2c_stop(solo_dev);
    118		return 0;
    119	}
    120
    121	if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) {
    122		solo_i2c_start(solo_dev);
    123	} else {
    124		if (solo_dev->i2c_msg->flags & I2C_M_RD)
    125			goto prepare_read;
    126		else
    127			solo_i2c_stop(solo_dev);
    128	}
    129
    130	return 0;
    131}
    132
    133static int solo_i2c_handle_write(struct solo_dev *solo_dev)
    134{
    135retry_write:
    136	if (solo_dev->i2c_msg_ptr != solo_dev->i2c_msg->len) {
    137		solo_reg_write(solo_dev, SOLO_IIC_TXD,
    138			       solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr]);
    139		solo_dev->i2c_msg_ptr++;
    140		solo_i2c_flush(solo_dev, 1);
    141		return 0;
    142	}
    143
    144	solo_dev->i2c_msg_ptr = 0;
    145	solo_dev->i2c_msg++;
    146	solo_dev->i2c_msg_num--;
    147
    148	if (solo_dev->i2c_msg_num == 0) {
    149		solo_i2c_stop(solo_dev);
    150		return 0;
    151	}
    152
    153	if (!(solo_dev->i2c_msg->flags & I2C_M_NOSTART)) {
    154		solo_i2c_start(solo_dev);
    155	} else {
    156		if (solo_dev->i2c_msg->flags & I2C_M_RD)
    157			solo_i2c_stop(solo_dev);
    158		else
    159			goto retry_write;
    160	}
    161
    162	return 0;
    163}
    164
    165int solo_i2c_isr(struct solo_dev *solo_dev)
    166{
    167	u32 status = solo_reg_read(solo_dev, SOLO_IIC_CTRL);
    168	int ret = -EINVAL;
    169
    170
    171	if (CHK_FLAGS(status, SOLO_IIC_STATE_TRNS | SOLO_IIC_STATE_SIG_ERR)
    172	    || solo_dev->i2c_id < 0) {
    173		solo_i2c_stop(solo_dev);
    174		return -ENXIO;
    175	}
    176
    177	switch (solo_dev->i2c_state) {
    178	case IIC_STATE_START:
    179		if (solo_dev->i2c_msg->flags & I2C_M_RD) {
    180			solo_dev->i2c_state = IIC_STATE_READ;
    181			ret = solo_i2c_handle_read(solo_dev);
    182			break;
    183		}
    184
    185		solo_dev->i2c_state = IIC_STATE_WRITE;
    186		fallthrough;
    187	case IIC_STATE_WRITE:
    188		ret = solo_i2c_handle_write(solo_dev);
    189		break;
    190
    191	case IIC_STATE_READ:
    192		solo_dev->i2c_msg->buf[solo_dev->i2c_msg_ptr] =
    193			solo_reg_read(solo_dev, SOLO_IIC_RXD);
    194		solo_dev->i2c_msg_ptr++;
    195
    196		ret = solo_i2c_handle_read(solo_dev);
    197		break;
    198
    199	default:
    200		solo_i2c_stop(solo_dev);
    201	}
    202
    203	return ret;
    204}
    205
    206static int solo_i2c_master_xfer(struct i2c_adapter *adap,
    207				struct i2c_msg msgs[], int num)
    208{
    209	struct solo_dev *solo_dev = adap->algo_data;
    210	unsigned long timeout;
    211	int ret;
    212	int i;
    213	DEFINE_WAIT(wait);
    214
    215	for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
    216		if (&solo_dev->i2c_adap[i] == adap)
    217			break;
    218	}
    219
    220	if (i == SOLO_I2C_ADAPTERS)
    221		return num; /* XXX Right return value for failure? */
    222
    223	mutex_lock(&solo_dev->i2c_mutex);
    224	solo_dev->i2c_id = i;
    225	solo_dev->i2c_msg = msgs;
    226	solo_dev->i2c_msg_num = num;
    227	solo_dev->i2c_msg_ptr = 0;
    228
    229	solo_reg_write(solo_dev, SOLO_IIC_CTRL, 0);
    230	solo_irq_on(solo_dev, SOLO_IRQ_IIC);
    231	solo_i2c_start(solo_dev);
    232
    233	timeout = HZ / 2;
    234
    235	for (;;) {
    236		prepare_to_wait(&solo_dev->i2c_wait, &wait,
    237				TASK_INTERRUPTIBLE);
    238
    239		if (solo_dev->i2c_state == IIC_STATE_STOP)
    240			break;
    241
    242		timeout = schedule_timeout(timeout);
    243		if (!timeout)
    244			break;
    245
    246		if (signal_pending(current))
    247			break;
    248	}
    249
    250	finish_wait(&solo_dev->i2c_wait, &wait);
    251	ret = num - solo_dev->i2c_msg_num;
    252	solo_dev->i2c_state = IIC_STATE_IDLE;
    253	solo_dev->i2c_id = -1;
    254
    255	mutex_unlock(&solo_dev->i2c_mutex);
    256
    257	return ret;
    258}
    259
    260static u32 solo_i2c_functionality(struct i2c_adapter *adap)
    261{
    262	return I2C_FUNC_I2C;
    263}
    264
    265static const struct i2c_algorithm solo_i2c_algo = {
    266	.master_xfer	= solo_i2c_master_xfer,
    267	.functionality	= solo_i2c_functionality,
    268};
    269
    270int solo_i2c_init(struct solo_dev *solo_dev)
    271{
    272	int i;
    273	int ret;
    274
    275	solo_reg_write(solo_dev, SOLO_IIC_CFG,
    276		       SOLO_IIC_PRESCALE(8) | SOLO_IIC_ENABLE);
    277
    278	solo_dev->i2c_id = -1;
    279	solo_dev->i2c_state = IIC_STATE_IDLE;
    280	init_waitqueue_head(&solo_dev->i2c_wait);
    281	mutex_init(&solo_dev->i2c_mutex);
    282
    283	for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
    284		struct i2c_adapter *adap = &solo_dev->i2c_adap[i];
    285
    286		snprintf(adap->name, I2C_NAME_SIZE, "%s I2C %d",
    287			 SOLO6X10_NAME, i);
    288		adap->algo = &solo_i2c_algo;
    289		adap->algo_data = solo_dev;
    290		adap->retries = 1;
    291		adap->dev.parent = &solo_dev->pdev->dev;
    292
    293		ret = i2c_add_adapter(adap);
    294		if (ret) {
    295			adap->algo_data = NULL;
    296			break;
    297		}
    298	}
    299
    300	if (ret) {
    301		for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
    302			if (!solo_dev->i2c_adap[i].algo_data)
    303				break;
    304			i2c_del_adapter(&solo_dev->i2c_adap[i]);
    305			solo_dev->i2c_adap[i].algo_data = NULL;
    306		}
    307		return ret;
    308	}
    309
    310	return 0;
    311}
    312
    313void solo_i2c_exit(struct solo_dev *solo_dev)
    314{
    315	int i;
    316
    317	for (i = 0; i < SOLO_I2C_ADAPTERS; i++) {
    318		if (!solo_dev->i2c_adap[i].algo_data)
    319			continue;
    320		i2c_del_adapter(&solo_dev->i2c_adap[i]);
    321		solo_dev->i2c_adap[i].algo_data = NULL;
    322	}
    323}