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-amd756.c (10651B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3    Copyright (c) 1999-2002 Merlin Hughes <merlin@merlin.org>
      4
      5    Shamelessly ripped from i2c-piix4.c:
      6
      7    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> and
      8    Philip Edelbrock <phil@netroedge.com>
      9
     10*/
     11
     12/*
     13    2002-04-08: Added nForce support. (Csaba Halasz)
     14    2002-10-03: Fixed nForce PnP I/O port. (Michael Steil)
     15    2002-12-28: Rewritten into something that resembles a Linux driver (hch)
     16    2003-11-29: Added back AMD8111 removed by the previous rewrite.
     17                (Philip Pokorny)
     18*/
     19
     20/*
     21   Supports AMD756, AMD766, AMD768, AMD8111 and nVidia nForce
     22   Note: we assume there can only be one device, with one SMBus interface.
     23*/
     24
     25#include <linux/module.h>
     26#include <linux/pci.h>
     27#include <linux/kernel.h>
     28#include <linux/delay.h>
     29#include <linux/stddef.h>
     30#include <linux/ioport.h>
     31#include <linux/i2c.h>
     32#include <linux/acpi.h>
     33#include <linux/io.h>
     34
     35/* AMD756 SMBus address offsets */
     36#define SMB_ADDR_OFFSET		0xE0
     37#define SMB_IOSIZE		16
     38#define SMB_GLOBAL_STATUS	(0x0 + amd756_ioport)
     39#define SMB_GLOBAL_ENABLE	(0x2 + amd756_ioport)
     40#define SMB_HOST_ADDRESS	(0x4 + amd756_ioport)
     41#define SMB_HOST_DATA		(0x6 + amd756_ioport)
     42#define SMB_HOST_COMMAND	(0x8 + amd756_ioport)
     43#define SMB_HOST_BLOCK_DATA	(0x9 + amd756_ioport)
     44#define SMB_HAS_DATA		(0xA + amd756_ioport)
     45#define SMB_HAS_DEVICE_ADDRESS	(0xC + amd756_ioport)
     46#define SMB_HAS_HOST_ADDRESS	(0xE + amd756_ioport)
     47#define SMB_SNOOP_ADDRESS	(0xF + amd756_ioport)
     48
     49/* PCI Address Constants */
     50
     51/* address of I/O space */
     52#define SMBBA		0x058		/* mh */
     53#define SMBBANFORCE	0x014
     54
     55/* general configuration */
     56#define SMBGCFG		0x041		/* mh */
     57
     58/* silicon revision code */
     59#define SMBREV		0x008
     60
     61/* Other settings */
     62#define MAX_TIMEOUT	500
     63
     64/* AMD756 constants */
     65#define AMD756_QUICK		0x00
     66#define AMD756_BYTE		0x01
     67#define AMD756_BYTE_DATA	0x02
     68#define AMD756_WORD_DATA	0x03
     69#define AMD756_PROCESS_CALL	0x04
     70#define AMD756_BLOCK_DATA	0x05
     71
     72static struct pci_driver amd756_driver;
     73static unsigned short amd756_ioport;
     74
     75/* 
     76  SMBUS event = I/O 28-29 bit 11
     77     see E0 for the status bits and enabled in E2
     78     
     79*/
     80#define GS_ABRT_STS	(1 << 0)
     81#define GS_COL_STS	(1 << 1)
     82#define GS_PRERR_STS	(1 << 2)
     83#define GS_HST_STS	(1 << 3)
     84#define GS_HCYC_STS	(1 << 4)
     85#define GS_TO_STS	(1 << 5)
     86#define GS_SMB_STS	(1 << 11)
     87
     88#define GS_CLEAR_STS	(GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \
     89			 GS_HCYC_STS | GS_TO_STS )
     90
     91#define GE_CYC_TYPE_MASK	(7)
     92#define GE_HOST_STC		(1 << 3)
     93#define GE_ABORT		(1 << 5)
     94
     95
     96static int amd756_transaction(struct i2c_adapter *adap)
     97{
     98	int temp;
     99	int result = 0;
    100	int timeout = 0;
    101
    102	dev_dbg(&adap->dev, "Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, "
    103		"DAT=%04x\n", inw_p(SMB_GLOBAL_STATUS),
    104		inw_p(SMB_GLOBAL_ENABLE), inw_p(SMB_HOST_ADDRESS),
    105		inb_p(SMB_HOST_DATA));
    106
    107	/* Make sure the SMBus host is ready to start transmitting */
    108	if ((temp = inw_p(SMB_GLOBAL_STATUS)) & (GS_HST_STS | GS_SMB_STS)) {
    109		dev_dbg(&adap->dev, "SMBus busy (%04x). Waiting...\n", temp);
    110		do {
    111			msleep(1);
    112			temp = inw_p(SMB_GLOBAL_STATUS);
    113		} while ((temp & (GS_HST_STS | GS_SMB_STS)) &&
    114		         (timeout++ < MAX_TIMEOUT));
    115		/* If the SMBus is still busy, we give up */
    116		if (timeout > MAX_TIMEOUT) {
    117			dev_dbg(&adap->dev, "Busy wait timeout (%04x)\n", temp);
    118			goto abort;
    119		}
    120		timeout = 0;
    121	}
    122
    123	/* start the transaction by setting the start bit */
    124	outw_p(inw(SMB_GLOBAL_ENABLE) | GE_HOST_STC, SMB_GLOBAL_ENABLE);
    125
    126	/* We will always wait for a fraction of a second! */
    127	do {
    128		msleep(1);
    129		temp = inw_p(SMB_GLOBAL_STATUS);
    130	} while ((temp & GS_HST_STS) && (timeout++ < MAX_TIMEOUT));
    131
    132	/* If the SMBus is still busy, we give up */
    133	if (timeout > MAX_TIMEOUT) {
    134		dev_dbg(&adap->dev, "Completion timeout!\n");
    135		goto abort;
    136	}
    137
    138	if (temp & GS_PRERR_STS) {
    139		result = -ENXIO;
    140		dev_dbg(&adap->dev, "SMBus Protocol error (no response)!\n");
    141	}
    142
    143	if (temp & GS_COL_STS) {
    144		result = -EIO;
    145		dev_warn(&adap->dev, "SMBus collision!\n");
    146	}
    147
    148	if (temp & GS_TO_STS) {
    149		result = -ETIMEDOUT;
    150		dev_dbg(&adap->dev, "SMBus protocol timeout!\n");
    151	}
    152
    153	if (temp & GS_HCYC_STS)
    154		dev_dbg(&adap->dev, "SMBus protocol success!\n");
    155
    156	outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
    157
    158#ifdef DEBUG
    159	if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_CLEAR_STS) != 0x00) {
    160		dev_dbg(&adap->dev,
    161			"Failed reset at end of transaction (%04x)\n", temp);
    162	}
    163#endif
    164
    165	dev_dbg(&adap->dev,
    166		"Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
    167		inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
    168		inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
    169
    170	return result;
    171
    172 abort:
    173	dev_warn(&adap->dev, "Sending abort\n");
    174	outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE);
    175	msleep(100);
    176	outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
    177	return -EIO;
    178}
    179
    180/* Return negative errno on error. */
    181static s32 amd756_access(struct i2c_adapter * adap, u16 addr,
    182		  unsigned short flags, char read_write,
    183		  u8 command, int size, union i2c_smbus_data * data)
    184{
    185	int i, len;
    186	int status;
    187
    188	switch (size) {
    189	case I2C_SMBUS_QUICK:
    190		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
    191		       SMB_HOST_ADDRESS);
    192		size = AMD756_QUICK;
    193		break;
    194	case I2C_SMBUS_BYTE:
    195		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
    196		       SMB_HOST_ADDRESS);
    197		if (read_write == I2C_SMBUS_WRITE)
    198			outb_p(command, SMB_HOST_DATA);
    199		size = AMD756_BYTE;
    200		break;
    201	case I2C_SMBUS_BYTE_DATA:
    202		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
    203		       SMB_HOST_ADDRESS);
    204		outb_p(command, SMB_HOST_COMMAND);
    205		if (read_write == I2C_SMBUS_WRITE)
    206			outw_p(data->byte, SMB_HOST_DATA);
    207		size = AMD756_BYTE_DATA;
    208		break;
    209	case I2C_SMBUS_WORD_DATA:
    210		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
    211		       SMB_HOST_ADDRESS);
    212		outb_p(command, SMB_HOST_COMMAND);
    213		if (read_write == I2C_SMBUS_WRITE)
    214			outw_p(data->word, SMB_HOST_DATA);	/* TODO: endian???? */
    215		size = AMD756_WORD_DATA;
    216		break;
    217	case I2C_SMBUS_BLOCK_DATA:
    218		outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
    219		       SMB_HOST_ADDRESS);
    220		outb_p(command, SMB_HOST_COMMAND);
    221		if (read_write == I2C_SMBUS_WRITE) {
    222			len = data->block[0];
    223			if (len < 0)
    224				len = 0;
    225			if (len > 32)
    226				len = 32;
    227			outw_p(len, SMB_HOST_DATA);
    228			/* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */
    229			for (i = 1; i <= len; i++)
    230				outb_p(data->block[i],
    231				       SMB_HOST_BLOCK_DATA);
    232		}
    233		size = AMD756_BLOCK_DATA;
    234		break;
    235	default:
    236		dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
    237		return -EOPNOTSUPP;
    238	}
    239
    240	/* How about enabling interrupts... */
    241	outw_p(size & GE_CYC_TYPE_MASK, SMB_GLOBAL_ENABLE);
    242
    243	status = amd756_transaction(adap);
    244	if (status)
    245		return status;
    246
    247	if ((read_write == I2C_SMBUS_WRITE) || (size == AMD756_QUICK))
    248		return 0;
    249
    250
    251	switch (size) {
    252	case AMD756_BYTE:
    253		data->byte = inw_p(SMB_HOST_DATA);
    254		break;
    255	case AMD756_BYTE_DATA:
    256		data->byte = inw_p(SMB_HOST_DATA);
    257		break;
    258	case AMD756_WORD_DATA:
    259		data->word = inw_p(SMB_HOST_DATA);	/* TODO: endian???? */
    260		break;
    261	case AMD756_BLOCK_DATA:
    262		data->block[0] = inw_p(SMB_HOST_DATA) & 0x3f;
    263		if(data->block[0] > 32)
    264			data->block[0] = 32;
    265		/* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */
    266		for (i = 1; i <= data->block[0]; i++)
    267			data->block[i] = inb_p(SMB_HOST_BLOCK_DATA);
    268		break;
    269	}
    270
    271	return 0;
    272}
    273
    274static u32 amd756_func(struct i2c_adapter *adapter)
    275{
    276	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
    277	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
    278	    I2C_FUNC_SMBUS_BLOCK_DATA;
    279}
    280
    281static const struct i2c_algorithm smbus_algorithm = {
    282	.smbus_xfer	= amd756_access,
    283	.functionality	= amd756_func,
    284};
    285
    286struct i2c_adapter amd756_smbus = {
    287	.owner		= THIS_MODULE,
    288	.class          = I2C_CLASS_HWMON | I2C_CLASS_SPD,
    289	.algo		= &smbus_algorithm,
    290};
    291
    292enum chiptype { AMD756, AMD766, AMD768, NFORCE, AMD8111 };
    293static const char* chipname[] = {
    294	"AMD756", "AMD766", "AMD768",
    295	"nVidia nForce", "AMD8111",
    296};
    297
    298static const struct pci_device_id amd756_ids[] = {
    299	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B),
    300	  .driver_data = AMD756 },
    301	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413),
    302	  .driver_data = AMD766 },
    303	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7443),
    304	  .driver_data = AMD768 },
    305	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS),
    306	  .driver_data = AMD8111 },
    307	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS),
    308	  .driver_data = NFORCE },
    309	{ 0, }
    310};
    311
    312MODULE_DEVICE_TABLE (pci, amd756_ids);
    313
    314static int amd756_probe(struct pci_dev *pdev, const struct pci_device_id *id)
    315{
    316	int nforce = (id->driver_data == NFORCE);
    317	int error;
    318	u8 temp;
    319	
    320	if (amd756_ioport) {
    321		dev_err(&pdev->dev, "Only one device supported "
    322		       "(you have a strange motherboard, btw)\n");
    323		return -ENODEV;
    324	}
    325
    326	if (nforce) {
    327		if (PCI_FUNC(pdev->devfn) != 1)
    328			return -ENODEV;
    329
    330		pci_read_config_word(pdev, SMBBANFORCE, &amd756_ioport);
    331		amd756_ioport &= 0xfffc;
    332	} else { /* amd */
    333		if (PCI_FUNC(pdev->devfn) != 3)
    334			return -ENODEV;
    335
    336		pci_read_config_byte(pdev, SMBGCFG, &temp);
    337		if ((temp & 128) == 0) {
    338			dev_err(&pdev->dev,
    339				"Error: SMBus controller I/O not enabled!\n");
    340			return -ENODEV;
    341		}
    342
    343		/* Determine the address of the SMBus areas */
    344		/* Technically it is a dword but... */
    345		pci_read_config_word(pdev, SMBBA, &amd756_ioport);
    346		amd756_ioport &= 0xff00;
    347		amd756_ioport += SMB_ADDR_OFFSET;
    348	}
    349
    350	error = acpi_check_region(amd756_ioport, SMB_IOSIZE,
    351				  amd756_driver.name);
    352	if (error)
    353		return -ENODEV;
    354
    355	if (!request_region(amd756_ioport, SMB_IOSIZE, amd756_driver.name)) {
    356		dev_err(&pdev->dev, "SMB region 0x%x already in use!\n",
    357			amd756_ioport);
    358		return -ENODEV;
    359	}
    360
    361	pci_read_config_byte(pdev, SMBREV, &temp);
    362	dev_dbg(&pdev->dev, "SMBREV = 0x%X\n", temp);
    363	dev_dbg(&pdev->dev, "AMD756_smba = 0x%X\n", amd756_ioport);
    364
    365	/* set up the sysfs linkage to our parent device */
    366	amd756_smbus.dev.parent = &pdev->dev;
    367
    368	snprintf(amd756_smbus.name, sizeof(amd756_smbus.name),
    369		 "SMBus %s adapter at %04x", chipname[id->driver_data],
    370		 amd756_ioport);
    371
    372	error = i2c_add_adapter(&amd756_smbus);
    373	if (error)
    374		goto out_err;
    375
    376	return 0;
    377
    378 out_err:
    379	release_region(amd756_ioport, SMB_IOSIZE);
    380	return error;
    381}
    382
    383static void amd756_remove(struct pci_dev *dev)
    384{
    385	i2c_del_adapter(&amd756_smbus);
    386	release_region(amd756_ioport, SMB_IOSIZE);
    387}
    388
    389static struct pci_driver amd756_driver = {
    390	.name		= "amd756_smbus",
    391	.id_table	= amd756_ids,
    392	.probe		= amd756_probe,
    393	.remove		= amd756_remove,
    394};
    395
    396module_pci_driver(amd756_driver);
    397
    398MODULE_AUTHOR("Merlin Hughes <merlin@merlin.org>");
    399MODULE_DESCRIPTION("AMD756/766/768/8111 and nVidia nForce SMBus driver");
    400MODULE_LICENSE("GPL");
    401
    402EXPORT_SYMBOL(amd756_smbus);