linux-i2c.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] i2c-piix4: support multiple PIIX4 SMBus hosts
@ 2012-06-01 18:16 Andrew Armenia
       [not found] ` <1338574572-10668-1-git-send-email-andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>
  0 siblings, 1 reply; 11+ messages in thread
From: Andrew Armenia @ 2012-06-01 18:16 UTC (permalink / raw)
  To: Jean Delvare, Ben Dooks, Wolfram Sang
  Cc: linux-i2c, linux-kernel, Andrew Armenia

Some AMD chipsets have a second PIIX4-compatible host adapter accessible
through a second set of registers (e.g. SP5100). Moved the global base
address variable to an extension of struct i2c_adapter; added logic
to detect chipset known to have this feature. Tested on ASUS KCMA-D8 board.

Signed-off-by: Andrew Armenia <andrew@asquaredlabs.com>
---
 drivers/i2c/busses/i2c-piix4.c |  242 ++++++++++++++++++++++++++++------------
 1 file changed, 170 insertions(+), 72 deletions(-)

diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index c14d48d..a029a47 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -43,24 +43,25 @@
 
 
 /* PIIX4 SMBus address offsets */
-#define SMBHSTSTS	(0 + piix4_smba)
-#define SMBHSLVSTS	(1 + piix4_smba)
-#define SMBHSTCNT	(2 + piix4_smba)
-#define SMBHSTCMD	(3 + piix4_smba)
-#define SMBHSTADD	(4 + piix4_smba)
-#define SMBHSTDAT0	(5 + piix4_smba)
-#define SMBHSTDAT1	(6 + piix4_smba)
-#define SMBBLKDAT	(7 + piix4_smba)
-#define SMBSLVCNT	(8 + piix4_smba)
-#define SMBSHDWCMD	(9 + piix4_smba)
-#define SMBSLVEVT	(0xA + piix4_smba)
-#define SMBSLVDAT	(0xC + piix4_smba)
+#define SMBHSTSTS	(0 + piix4_adap->smba)
+#define SMBHSLVSTS	(1 + piix4_adap->smba)
+#define SMBHSTCNT	(2 + piix4_adap->smba)
+#define SMBHSTCMD	(3 + piix4_adap->smba)
+#define SMBHSTADD	(4 + piix4_adap->smba)
+#define SMBHSTDAT0	(5 + piix4_adap->smba)
+#define SMBHSTDAT1	(6 + piix4_adap->smba)
+#define SMBBLKDAT	(7 + piix4_adap->smba)
+#define SMBSLVCNT	(8 + piix4_adap->smba)
+#define SMBSHDWCMD	(9 + piix4_adap->smba)
+#define SMBSLVEVT	(0xA + piix4_adap->smba)
+#define SMBSLVDAT	(0xC + piix4_adap->smba)
 
 /* count for request_region */
 #define SMBIOSIZE	8
 
 /* PCI Address Constants */
 #define SMBBA		0x090
+#define SMBAUXBA        0x058
 #define SMBHSTCFG	0x0D2
 #define SMBSLVC		0x0D3
 #define SMBSHDW1	0x0D4
@@ -94,10 +95,16 @@ MODULE_PARM_DESC(force_addr,
 		 "Forcibly enable the PIIX4 at the given address. "
 		 "EXTREMELY DANGEROUS!");
 
-static unsigned short piix4_smba;
 static int srvrworks_csb5_delay;
 static struct pci_driver piix4_driver;
-static struct i2c_adapter piix4_adapter;
+
+struct piix4_adapter {
+	struct i2c_adapter i2c_adapter;
+	unsigned short smba;
+};
+
+static struct piix4_adapter piix4_main_adapter;
+static struct piix4_adapter piix4_aux_adapter;
 
 static struct dmi_system_id __devinitdata piix4_dmi_blacklist[] = {
 	{
@@ -128,7 +135,9 @@ static struct dmi_system_id __devinitdata piix4_dmi_ibm[] = {
 };
 
 static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
-				const struct pci_device_id *id)
+				const struct pci_device_id *id,
+				struct piix4_adapter *adp)
+
 {
 	unsigned char temp;
 
@@ -155,12 +164,12 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
 
 	/* Determine the address of the SMBus areas */
 	if (force_addr) {
-		piix4_smba = force_addr & 0xfff0;
+		adp->smba = force_addr & 0xfff0;
 		force = 0;
 	} else {
-		pci_read_config_word(PIIX4_dev, SMBBA, &piix4_smba);
-		piix4_smba &= 0xfff0;
-		if(piix4_smba == 0) {
+		pci_read_config_word(PIIX4_dev, SMBBA, &adp->smba);
+		adp->smba &= 0xfff0;
+		if (adp->smba == 0) {
 			dev_err(&PIIX4_dev->dev, "SMBus base address "
 				"uninitialized - upgrade BIOS or use "
 				"force_addr=0xaddr\n");
@@ -168,12 +177,12 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
 		}
 	}
 
-	if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
+	if (acpi_check_region(adp->smba, SMBIOSIZE, piix4_driver.name))
 		return -ENODEV;
 
-	if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) {
+	if (!request_region(adp->smba, SMBIOSIZE, piix4_driver.name)) {
 		dev_err(&PIIX4_dev->dev, "SMBus region 0x%x already in use!\n",
-			piix4_smba);
+			adp->smba);
 		return -EBUSY;
 	}
 
@@ -183,10 +192,10 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
 	   sure, we disable the PIIX4 first. */
 	if (force_addr) {
 		pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp & 0xfe);
-		pci_write_config_word(PIIX4_dev, SMBBA, piix4_smba);
+		pci_write_config_word(PIIX4_dev, SMBBA, adp->smba);
 		pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp | 0x01);
 		dev_info(&PIIX4_dev->dev, "WARNING: SMBus interface set to "
-			"new address %04x!\n", piix4_smba);
+			"new address %04x!\n", adp->smba);
 	} else if ((temp & 1) == 0) {
 		if (force) {
 			/* This should never need to be done, but has been
@@ -205,8 +214,8 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
 		} else {
 			dev_err(&PIIX4_dev->dev,
 				"Host SMBus controller not enabled!\n");
-			release_region(piix4_smba, SMBIOSIZE);
-			piix4_smba = 0;
+			release_region(adp->smba, SMBIOSIZE);
+			adp->smba = 0;
 			return -ENODEV;
 		}
 	}
@@ -222,13 +231,46 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
 	pci_read_config_byte(PIIX4_dev, SMBREV, &temp);
 	dev_info(&PIIX4_dev->dev,
 		 "SMBus Host Controller at 0x%x, revision %d\n",
-		 piix4_smba, temp);
+		 adp->smba, temp);
+
+	return 0;
+}
+
+static int __devinit piix4_setup_aux(struct pci_dev *PIIX4_dev,
+				const struct pci_device_id *id,
+				struct piix4_adapter *adp,
+				unsigned short base_reg_addr)
+{
+	/* Read address of auxiliary SMBus controller */
+	pci_read_config_word(PIIX4_dev, base_reg_addr, &adp->smba);
+	adp->smba &= 0xffe0;
+
+	if (adp->smba == 0) {
+		dev_err(&PIIX4_dev->dev, "Aux SMBus base address "
+			"uninitialized - upgrade BIOS\n");
+		return -ENODEV;
+	}
+
+	if (acpi_check_region(adp->smba, SMBIOSIZE, piix4_driver.name))
+		return -ENODEV;
+
+	if (!request_region(adp->smba, SMBIOSIZE, piix4_driver.name)) {
+		dev_err(&PIIX4_dev->dev, "Aux SMBus region 0x%x already"
+			" in use!\n", adp->smba);
+		return -EBUSY;
+	}
+
+	dev_info(&PIIX4_dev->dev,
+		"Auxiliary SMBus Host Controller at 0x%x\n",
+		adp->smba
+	);
 
 	return 0;
 }
 
 static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
-				const struct pci_device_id *id)
+				const struct pci_device_id *id,
+				struct piix4_adapter *adp)
 {
 	unsigned short smba_idx = 0xcd6;
 	u8 smba_en_lo, smba_en_hi, i2ccfg, i2ccfg_offset = 0x10, smb_en = 0x2c;
@@ -258,26 +300,26 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
 		return -ENODEV;
 	}
 
-	piix4_smba = ((smba_en_hi << 8) | smba_en_lo) & 0xffe0;
-	if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
+	adp->smba = ((smba_en_hi << 8) | smba_en_lo) & 0xffe0;
+	if (acpi_check_region(adp->smba, SMBIOSIZE, piix4_driver.name))
 		return -ENODEV;
 
-	if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) {
+	if (!request_region(adp->smba, SMBIOSIZE, piix4_driver.name)) {
 		dev_err(&PIIX4_dev->dev, "SMBus region 0x%x already in use!\n",
-			piix4_smba);
+			adp->smba);
 		return -EBUSY;
 	}
 
 	/* Request the SMBus I2C bus config region */
-	if (!request_region(piix4_smba + i2ccfg_offset, 1, "i2ccfg")) {
+	if (!request_region(adp->smba + i2ccfg_offset, 1, "i2ccfg")) {
 		dev_err(&PIIX4_dev->dev, "SMBus I2C bus config region "
-			"0x%x already in use!\n", piix4_smba + i2ccfg_offset);
-		release_region(piix4_smba, SMBIOSIZE);
-		piix4_smba = 0;
+			"0x%x already in use!\n", adp->smba + i2ccfg_offset);
+		release_region(adp->smba, SMBIOSIZE);
+		adp->smba = 0;
 		return -EBUSY;
 	}
-	i2ccfg = inb_p(piix4_smba + i2ccfg_offset);
-	release_region(piix4_smba + i2ccfg_offset, 1);
+	i2ccfg = inb_p(adp->smba + i2ccfg_offset);
+	release_region(adp->smba + i2ccfg_offset, 1);
 
 	if (i2ccfg & 1)
 		dev_dbg(&PIIX4_dev->dev, "Using IRQ for SMBus.\n");
@@ -286,32 +328,35 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
 
 	dev_info(&PIIX4_dev->dev,
 		 "SMBus Host Controller at 0x%x, revision %d\n",
-		 piix4_smba, i2ccfg >> 4);
+		 adp->smba, i2ccfg >> 4);
 
 	return 0;
 }
 
-static int piix4_transaction(void)
+static int piix4_transaction(struct piix4_adapter *piix4_adap)
 {
 	int temp;
 	int result = 0;
 	int timeout = 0;
 
-	dev_dbg(&piix4_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
+	dev_dbg(&piix4_adap->i2c_adapter.dev,
+		"Transaction (pre): CNT=%02x, CMD=%02x, "
 		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
 		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
 		inb_p(SMBHSTDAT1));
 
 	/* Make sure the SMBus host is ready to start transmitting */
 	if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-		dev_dbg(&piix4_adapter.dev, "SMBus busy (%02x). "
+		dev_dbg(&piix4_adap->i2c_adapter.dev, "SMBus busy (%02x). "
 			"Resetting...\n", temp);
 		outb_p(temp, SMBHSTSTS);
 		if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-			dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp);
+			dev_err(&piix4_adap->i2c_adapter.dev,
+				"Failed! (%02x)\n", temp);
 			return -EBUSY;
 		} else {
-			dev_dbg(&piix4_adapter.dev, "Successful!\n");
+			dev_dbg(&piix4_adap->i2c_adapter.dev,
+				"Successful!\n");
 		}
 	}
 
@@ -330,35 +375,39 @@ static int piix4_transaction(void)
 
 	/* If the SMBus is still busy, we give up */
 	if (timeout == MAX_TIMEOUT) {
-		dev_err(&piix4_adapter.dev, "SMBus Timeout!\n");
+		dev_err(&piix4_adap->i2c_adapter.dev, "SMBus Timeout!\n");
 		result = -ETIMEDOUT;
 	}
 
 	if (temp & 0x10) {
 		result = -EIO;
-		dev_err(&piix4_adapter.dev, "Error: Failed bus transaction\n");
+		dev_err(&piix4_adap->i2c_adapter.dev,
+			"Error: Failed bus transaction\n");
 	}
 
 	if (temp & 0x08) {
 		result = -EIO;
-		dev_dbg(&piix4_adapter.dev, "Bus collision! SMBus may be "
+		dev_dbg(&piix4_adap->i2c_adapter.dev,
+			"Bus collision! SMBus may be "
 			"locked until next hard reset. (sorry!)\n");
 		/* Clock stops and slave is stuck in mid-transmission */
 	}
 
 	if (temp & 0x04) {
 		result = -ENXIO;
-		dev_dbg(&piix4_adapter.dev, "Error: no response!\n");
+		dev_dbg(&piix4_adap->i2c_adapter.dev,
+			"Error: no response!\n");
 	}
 
 	if (inb_p(SMBHSTSTS) != 0x00)
 		outb_p(inb(SMBHSTSTS), SMBHSTSTS);
 
 	if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-		dev_err(&piix4_adapter.dev, "Failed reset at end of "
-			"transaction (%02x)\n", temp);
+		dev_err(&piix4_adap->i2c_adapter.dev,
+			"Failed reset at end of transaction (%02x)\n", temp);
 	}
-	dev_dbg(&piix4_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, "
+	dev_dbg(&piix4_adap->i2c_adapter.dev,
+		"Transaction (post): CNT=%02x, CMD=%02x, "
 		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
 		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
 		inb_p(SMBHSTDAT1));
@@ -373,6 +422,9 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
 	int i, len;
 	int status;
 
+	struct piix4_adapter *piix4_adap = container_of(adap,
+		struct piix4_adapter, i2c_adapter);
+
 	switch (size) {
 	case I2C_SMBUS_QUICK:
 		outb_p((addr << 1) | read_write,
@@ -426,7 +478,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
 
 	outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT);
 
-	status = piix4_transaction();
+	status = piix4_transaction(piix4_adap);
 	if (status)
 		return status;
 
@@ -466,12 +518,6 @@ static const struct i2c_algorithm smbus_algorithm = {
 	.functionality	= piix4_func,
 };
 
-static struct i2c_adapter piix4_adapter = {
-	.owner		= THIS_MODULE,
-	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
-	.algo		= &smbus_algorithm,
-};
-
 static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
@@ -496,45 +542,97 @@ static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
 
 MODULE_DEVICE_TABLE (pci, piix4_ids);
 
+static void piix4_adapter_init(struct piix4_adapter *adap)
+{
+	memset(adap, 0, sizeof(struct piix4_adapter));
+
+	adap->i2c_adapter.owner = THIS_MODULE;
+	adap->i2c_adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	adap->i2c_adapter.algo = &smbus_algorithm;
+}
+
 static int __devinit piix4_probe(struct pci_dev *dev,
 				const struct pci_device_id *id)
 {
 	int retval;
 
+	piix4_adapter_init(&piix4_main_adapter);
+	piix4_adapter_init(&piix4_aux_adapter);
+
 	if ((dev->vendor == PCI_VENDOR_ID_ATI &&
 	     dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
 	     dev->revision >= 0x40) ||
 	    dev->vendor == PCI_VENDOR_ID_AMD)
 		/* base address location etc changed in SB800 */
-		retval = piix4_setup_sb800(dev, id);
+		retval = piix4_setup_sb800(dev, id, &piix4_main_adapter);
 	else
-		retval = piix4_setup(dev, id);
+		retval = piix4_setup(dev, id, &piix4_main_adapter);
 
 	if (retval)
 		return retval;
 
 	/* set up the sysfs linkage to our parent device */
-	piix4_adapter.dev.parent = &dev->dev;
+	piix4_main_adapter.i2c_adapter.dev.parent = &dev->dev;
 
-	snprintf(piix4_adapter.name, sizeof(piix4_adapter.name),
-		"SMBus PIIX4 adapter at %04x", piix4_smba);
+	snprintf(piix4_main_adapter.i2c_adapter.name,
+		sizeof(piix4_main_adapter.i2c_adapter.name),
+		"SMBus PIIX4 adapter at %04x", piix4_main_adapter.smba);
 
-	if ((retval = i2c_add_adapter(&piix4_adapter))) {
+	retval = i2c_add_adapter(&piix4_main_adapter.i2c_adapter);
+	if (retval) {
 		dev_err(&dev->dev, "Couldn't register adapter!\n");
-		release_region(piix4_smba, SMBIOSIZE);
-		piix4_smba = 0;
+		release_region(piix4_main_adapter.smba, SMBIOSIZE);
+		piix4_main_adapter.smba = 0;
+		return retval;
+	}
+
+	if (dev->vendor == PCI_VENDOR_ID_ATI &&
+	    dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
+	    dev->revision == 0x3d) {
+		/* Setup aux SMBus port on certain AMD chipsets e.g. SP5100 */
+		retval = piix4_setup_aux(dev, id,
+			&piix4_aux_adapter, SMBAUXBA);
+
+		if (retval) {
+			dev_err(&dev->dev, "Aux SMBus setup failed!\n");
+			release_region(piix4_main_adapter.smba, SMBIOSIZE);
+			piix4_aux_adapter.smba = 0;
+			goto aux_fail;
+		}
+
+		piix4_aux_adapter.i2c_adapter.dev.parent = &dev->dev;
+		snprintf(piix4_aux_adapter.i2c_adapter.name,
+			sizeof(piix4_aux_adapter.i2c_adapter.name),
+			"SMBus PIIX4 adapter (aux) at %04x",
+			piix4_aux_adapter.smba);
+
+		retval = i2c_add_adapter(&piix4_aux_adapter.i2c_adapter);
+		if (retval) {
+			dev_err(&dev->dev,
+				"Couldn't register aux adapter!\n");
+			release_region(piix4_aux_adapter.smba, SMBIOSIZE);
+			piix4_aux_adapter.smba = 0;
+			goto aux_fail;
+		}
 	}
 
-	return retval;
+aux_fail:
+	return 0;
+}
+
+static void piix4_adapter_remove(struct piix4_adapter *adp)
+{
+	if (adp->smba) {
+		i2c_del_adapter(&adp->i2c_adapter);
+		release_region(adp->smba, SMBIOSIZE);
+		adp->smba = 0;
+	}
 }
 
 static void __devexit piix4_remove(struct pci_dev *dev)
 {
-	if (piix4_smba) {
-		i2c_del_adapter(&piix4_adapter);
-		release_region(piix4_smba, SMBIOSIZE);
-		piix4_smba = 0;
-	}
+	piix4_adapter_remove(&piix4_main_adapter);
+	piix4_adapter_remove(&piix4_aux_adapter);
 }
 
 static struct pci_driver piix4_driver = {
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH] i2c-piix4: support multiple PIIX4 SMBus hosts
       [not found] ` <1338574572-10668-1-git-send-email-andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>
@ 2012-06-04  7:16   ` Jean Delvare
       [not found]     ` <20120604091643.208956fe-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org>
  0 siblings, 1 reply; 11+ messages in thread
From: Jean Delvare @ 2012-06-04  7:16 UTC (permalink / raw)
  To: Andrew Armenia
  Cc: Ben Dooks, Wolfram Sang, linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

Hi Andrew,

On Fri,  1 Jun 2012 14:16:12 -0400, Andrew Armenia wrote:
> Some AMD chipsets have a second PIIX4-compatible host adapter accessible
> through a second set of registers (e.g. SP5100). Moved the global base
> address variable to an extension of struct i2c_adapter; added logic
> to detect chipset known to have this feature. Tested on ASUS KCMA-D8 board.

This would be much easier to review if you would split this change into
two patches, one moving the per-adapter settings out of the global
scope, and one adding support for the second base address.

Furthermore, the use of container_of seems inappropriate here, as there
is a proper interface for per-adapter attributes: i2c_set_adapdata() and
i2c_get_adapdata().

-- 
Jean Delvare

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 0/3] Multiple piix4-compatible SMBus support
       [not found]     ` <20120604091643.208956fe-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org>
@ 2012-06-05  1:49       ` Andrew Armenia
       [not found]         ` <1338860964-10803-1-git-send-email-andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>
  2012-06-05  1:49         ` [PATCH 3/3] i2c-piix4: support aux SMBus on AMD chipsets Andrew Armenia
  0 siblings, 2 replies; 11+ messages in thread
From: Andrew Armenia @ 2012-06-05  1:49 UTC (permalink / raw)
  To: Jean Delvare, Ben Dooks, Wolfram Sang
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andrew Armenia

These patches make it easier to support multiple SMBus controllers
that may be present within one piix4-compatible PCI device, and
enable support for the secondary SMBus controller found in the AMD
SP5100 chipset.

Andrew Armenia (3):
  i2c-piix4: eliminate global I/O base address
  i2c-piix4: separate registration and probing code
  i2c-piix4: support aux SMBus on AMD chipsets

 drivers/i2c/busses/i2c-piix4.c |  179 +++++++++++++++++++++++++++++++++-------
 1 file changed, 151 insertions(+), 28 deletions(-)

-- 
1.7.10

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/3] i2c-piix4: eliminate global I/O base address
       [not found]         ` <1338860964-10803-1-git-send-email-andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>
@ 2012-06-05  1:49           ` Andrew Armenia
  2012-06-12 11:53             ` Jean Delvare
  2012-06-05  1:49           ` [PATCH 2/3] i2c-piix4: separate registration and probing code Andrew Armenia
  1 sibling, 1 reply; 11+ messages in thread
From: Andrew Armenia @ 2012-06-05  1:49 UTC (permalink / raw)
  To: Jean Delvare, Ben Dooks, Wolfram Sang
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andrew Armenia

The i2c-piix4 driver used a global variable to store the base address
of the piix4 i2c registers. Some chipsets contain multiple sets of
i2c registers; thus it is desirable to eliminate global state.

i2c_get_adapdata()/i2c_set_adapdata() are used to keep track
of the IO base address; this is passed into piix4_transaction() as
an argument, eliminating the global variable.

Signed-off-by: Andrew Armenia <andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>
---
 drivers/i2c/busses/i2c-piix4.c |   61 ++++++++++++++++++++++++++++++----------
 1 file changed, 46 insertions(+), 15 deletions(-)

diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index c14d48d..7a5889c 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -94,7 +94,6 @@ MODULE_PARM_DESC(force_addr,
 		 "Forcibly enable the PIIX4 at the given address. "
 		 "EXTREMELY DANGEROUS!");
 
-static unsigned short piix4_smba;
 static int srvrworks_csb5_delay;
 static struct pci_driver piix4_driver;
 static struct i2c_adapter piix4_adapter;
@@ -127,10 +126,16 @@ static struct dmi_system_id __devinitdata piix4_dmi_ibm[] = {
 	{ },
 };
 
+struct i2c_piix4_adapdata {
+	unsigned short smba;
+};
+
 static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
-				const struct pci_device_id *id)
+				const struct pci_device_id *id,
+				unsigned short *smba)
 {
 	unsigned char temp;
+	unsigned short piix4_smba;
 
 	if ((PIIX4_dev->vendor == PCI_VENDOR_ID_SERVERWORKS) &&
 	    (PIIX4_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5))
@@ -224,12 +229,15 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
 		 "SMBus Host Controller at 0x%x, revision %d\n",
 		 piix4_smba, temp);
 
+	*smba = piix4_smba;
 	return 0;
 }
 
 static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
-				const struct pci_device_id *id)
+				const struct pci_device_id *id,
+				unsigned short *smba)
 {
+	unsigned short piix4_smba;
 	unsigned short smba_idx = 0xcd6;
 	u8 smba_en_lo, smba_en_hi, i2ccfg, i2ccfg_offset = 0x10, smb_en = 0x2c;
 
@@ -288,10 +296,11 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
 		 "SMBus Host Controller at 0x%x, revision %d\n",
 		 piix4_smba, i2ccfg >> 4);
 
+	*smba = piix4_smba;
 	return 0;
 }
 
-static int piix4_transaction(void)
+static int piix4_transaction(unsigned short piix4_smba)
 {
 	int temp;
 	int result = 0;
@@ -372,6 +381,11 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
 {
 	int i, len;
 	int status;
+	unsigned short piix4_smba;
+	struct i2c_piix4_adapdata *adapdata;
+
+	adapdata = (struct i2c_piix4_adapdata *)i2c_get_adapdata(adap);
+	piix4_smba = adapdata->smba;
 
 	switch (size) {
 	case I2C_SMBUS_QUICK:
@@ -426,7 +440,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
 
 	outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT);
 
-	status = piix4_transaction();
+	status = piix4_transaction(piix4_smba);
 	if (status)
 		return status;
 
@@ -472,6 +486,10 @@ static struct i2c_adapter piix4_adapter = {
 	.algo		= &smbus_algorithm,
 };
 
+static struct i2c_piix4_adapdata piix4_adapter_data = {
+	.smba		= 0,
+};
+
 static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
@@ -500,15 +518,16 @@ static int __devinit piix4_probe(struct pci_dev *dev,
 				const struct pci_device_id *id)
 {
 	int retval;
+	unsigned short smba;
 
 	if ((dev->vendor == PCI_VENDOR_ID_ATI &&
 	     dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
 	     dev->revision >= 0x40) ||
 	    dev->vendor == PCI_VENDOR_ID_AMD)
 		/* base address location etc changed in SB800 */
-		retval = piix4_setup_sb800(dev, id);
+		retval = piix4_setup_sb800(dev, id, &smba);
 	else
-		retval = piix4_setup(dev, id);
+		retval = piix4_setup(dev, id, &smba);
 
 	if (retval)
 		return retval;
@@ -517,26 +536,38 @@ static int __devinit piix4_probe(struct pci_dev *dev,
 	piix4_adapter.dev.parent = &dev->dev;
 
 	snprintf(piix4_adapter.name, sizeof(piix4_adapter.name),
-		"SMBus PIIX4 adapter at %04x", piix4_smba);
+		"SMBus PIIX4 adapter at %04x", smba);
+
+	piix4_adapter_data.smba = smba;
+
+	i2c_set_adapdata(&piix4_adapter, &piix4_adapter_data);
 
 	if ((retval = i2c_add_adapter(&piix4_adapter))) {
 		dev_err(&dev->dev, "Couldn't register adapter!\n");
-		release_region(piix4_smba, SMBIOSIZE);
-		piix4_smba = 0;
+		release_region(smba, SMBIOSIZE);
+		piix4_adapter_data.smba = 0;
 	}
 
 	return retval;
 }
 
-static void __devexit piix4_remove(struct pci_dev *dev)
+static void piix4_adap_remove(struct i2c_adapter *adap)
 {
-	if (piix4_smba) {
-		i2c_del_adapter(&piix4_adapter);
-		release_region(piix4_smba, SMBIOSIZE);
-		piix4_smba = 0;
+	struct i2c_piix4_adapdata *adapdata;
+
+	adapdata = (struct i2c_piix4_adapdata *)i2c_get_adapdata(adap);
+	if (adapdata->smba) {
+		i2c_del_adapter(adap);
+		release_region(adapdata->smba, SMBIOSIZE);
+		adapdata->smba = 0;
 	}
 }
 
+static void __devexit piix4_remove(struct pci_dev *dev)
+{
+	piix4_adap_remove(&piix4_adapter);
+}
+
 static struct pci_driver piix4_driver = {
 	.name		= "piix4_smbus",
 	.id_table	= piix4_ids,
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/3] i2c-piix4: separate registration and probing code
       [not found]         ` <1338860964-10803-1-git-send-email-andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>
  2012-06-05  1:49           ` [PATCH 1/3] i2c-piix4: eliminate global I/O base address Andrew Armenia
@ 2012-06-05  1:49           ` Andrew Armenia
  2012-06-12 12:10             ` Jean Delvare
  1 sibling, 1 reply; 11+ messages in thread
From: Andrew Armenia @ 2012-06-05  1:49 UTC (permalink / raw)
  To: Jean Delvare, Ben Dooks, Wolfram Sang
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andrew Armenia

Some chipsets have multiple sets of SMBus registers each controlling a
separate SMBus. Supporting these chipsets properly will require registering
multiple I2C adapters for one piix4.

The code to initialize and register the i2c_adapter structure has been
separated from piix4_probe and allows registration of a piix4 adapter
given its base address. Note that the i2c_adapter and piix4_adapdata
structures are now dynamically allocated.

Signed-off-by: Andrew Armenia <andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>
---
 drivers/i2c/busses/i2c-piix4.c |   79 ++++++++++++++++++++++++++--------------
 1 file changed, 51 insertions(+), 28 deletions(-)

diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 7a5889c..8a87b3f 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -480,16 +480,6 @@ static const struct i2c_algorithm smbus_algorithm = {
 	.functionality	= piix4_func,
 };
 
-static struct i2c_adapter piix4_adapter = {
-	.owner		= THIS_MODULE,
-	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
-	.algo		= &smbus_algorithm,
-};
-
-static struct i2c_piix4_adapdata piix4_adapter_data = {
-	.smba		= 0,
-};
-
 static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
@@ -514,6 +504,48 @@ static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
 
 MODULE_DEVICE_TABLE (pci, piix4_ids);
 
+static struct i2c_adapter *piix4_main_adapter;
+
+/* register piix4 I2C adapter at the given base address */
+static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba,
+				struct i2c_adapter **padap) {
+	struct i2c_adapter *piix4_adapter;
+	struct i2c_piix4_adapdata *piix4_adapdata;
+	int retval;
+
+	piix4_adapter = kmalloc(sizeof(*piix4_adapter), GFP_KERNEL);
+	memset(piix4_adapter, 0, sizeof(*piix4_adapter));
+	piix4_adapter->owner = THIS_MODULE;
+	piix4_adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	piix4_adapter->algo = &smbus_algorithm;
+
+	piix4_adapdata = kmalloc(sizeof(*piix4_adapdata), GFP_KERNEL);
+	memset(piix4_adapdata, 0, sizeof(*piix4_adapdata));
+	piix4_adapdata->smba = smba;
+
+	/* set up the sysfs linkage to our parent device */
+	piix4_adapter->dev.parent = &dev->dev;
+
+	snprintf(piix4_adapter->name, sizeof(piix4_adapter->name),
+		"SMBus PIIX4 adapter at %04x", smba);
+
+	piix4_adapdata->smba = smba;
+
+	i2c_set_adapdata(piix4_adapter, piix4_adapdata);
+
+	retval = i2c_add_adapter(piix4_adapter);
+	if (retval) {
+		dev_err(&dev->dev, "Couldn't register adapter!\n");
+		release_region(smba, SMBIOSIZE);
+		kfree(piix4_adapdata);
+		kfree(piix4_adapter);
+	}
+
+	*padap = piix4_adapter;
+
+	return retval;
+}
+
 static int __devinit piix4_probe(struct pci_dev *dev,
 				const struct pci_device_id *id)
 {
@@ -532,25 +564,10 @@ static int __devinit piix4_probe(struct pci_dev *dev,
 	if (retval)
 		return retval;
 
-	/* set up the sysfs linkage to our parent device */
-	piix4_adapter.dev.parent = &dev->dev;
-
-	snprintf(piix4_adapter.name, sizeof(piix4_adapter.name),
-		"SMBus PIIX4 adapter at %04x", smba);
-
-	piix4_adapter_data.smba = smba;
-
-	i2c_set_adapdata(&piix4_adapter, &piix4_adapter_data);
-
-	if ((retval = i2c_add_adapter(&piix4_adapter))) {
-		dev_err(&dev->dev, "Couldn't register adapter!\n");
-		release_region(smba, SMBIOSIZE);
-		piix4_adapter_data.smba = 0;
-	}
-
-	return retval;
+	return piix4_add_adapter(dev, smba, &piix4_main_adapter);
 }
 
+/* Remove the adapter and its associated IO region */
 static void piix4_adap_remove(struct i2c_adapter *adap)
 {
 	struct i2c_piix4_adapdata *adapdata;
@@ -561,11 +578,17 @@ static void piix4_adap_remove(struct i2c_adapter *adap)
 		release_region(adapdata->smba, SMBIOSIZE);
 		adapdata->smba = 0;
 	}
+
+	kfree(adapdata);
+	kfree(adap);
 }
 
 static void __devexit piix4_remove(struct pci_dev *dev)
 {
-	piix4_adap_remove(&piix4_adapter);
+	if (piix4_main_adapter) {
+		piix4_adap_remove(piix4_main_adapter);
+		piix4_main_adapter = NULL;
+	}
 }
 
 static struct pci_driver piix4_driver = {
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 3/3] i2c-piix4: support aux SMBus on AMD chipsets
  2012-06-05  1:49       ` [PATCH 0/3] Multiple piix4-compatible SMBus support Andrew Armenia
       [not found]         ` <1338860964-10803-1-git-send-email-andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>
@ 2012-06-05  1:49         ` Andrew Armenia
       [not found]           ` <1338860964-10803-4-git-send-email-andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>
  1 sibling, 1 reply; 11+ messages in thread
From: Andrew Armenia @ 2012-06-05  1:49 UTC (permalink / raw)
  To: Jean Delvare, Ben Dooks, Wolfram Sang
  Cc: linux-i2c, linux-kernel, Andrew Armenia

Some AMD chipsets, such as the SP5100, have an auxiliary SMBus with a second
set of registers. This patch adds support for the SP5100 and should work on
similar chipsets. Tested on ASUS KCMA-D8 motherboard.

Signed-off-by: Andrew Armenia <andrew@asquaredlabs.com>
---
 drivers/i2c/busses/i2c-piix4.c |   83 ++++++++++++++++++++++++++++++++++++----
 1 file changed, 76 insertions(+), 7 deletions(-)

diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 8a87b3f..972b604 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -25,7 +25,8 @@
 	AMD Hudson-2
 	SMSC Victory66
 
-   Note: we assume there can only be one device, with one SMBus interface.
+   Note: we assume there can only be one device, with one or two SMBus
+   interfaces.
 */
 
 #include <linux/module.h>
@@ -66,6 +67,7 @@
 #define SMBSHDW1	0x0D4
 #define SMBSHDW2	0x0D5
 #define SMBREV		0x0D6
+#define SMBAUXBA	0x058
 
 /* Other settings */
 #define MAX_TIMEOUT	500
@@ -130,6 +132,8 @@ struct i2c_piix4_adapdata {
 	unsigned short smba;
 };
 
+static void piix4_adap_remove(struct i2c_adapter *adap);
+
 static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
 				const struct pci_device_id *id,
 				unsigned short *smba)
@@ -300,6 +304,45 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
 	return 0;
 }
 
+static int __devinit piix4_setup_aux(struct pci_dev *PIIX4_dev,
+				const struct pci_device_id *id,
+				unsigned short base_reg_addr,
+				unsigned short *smba)
+{
+	/* Set up auxiliary SMBus controllers found on some AMD
+	 * chipsets e.g. SP5100 */
+	unsigned short piix4_smba;
+
+	/* Read address of auxiliary SMBus controller */
+	pci_read_config_word(PIIX4_dev, base_reg_addr, &piix4_smba);
+	piix4_smba &= 0xffe0;
+
+	if (piix4_smba == 0) {
+		dev_err(&PIIX4_dev->dev, "Aux SMBus base address "
+			"uninitialized - upgrade BIOS\n");
+		return -ENODEV;
+	}
+
+	if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
+		return -ENODEV;
+
+	if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) {
+		dev_err(&PIIX4_dev->dev, "Aux SMBus region 0x%x already"
+			" in use!\n", piix4_smba);
+		return -EBUSY;
+	}
+
+	dev_info(&PIIX4_dev->dev,
+		"Auxiliary SMBus Host Controller at 0x%x\n",
+		piix4_smba
+	);
+
+	*smba = piix4_smba;
+
+	return 0;
+}
+
+
 static int piix4_transaction(unsigned short piix4_smba)
 {
 	int temp;
@@ -505,6 +548,7 @@ static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
 MODULE_DEVICE_TABLE (pci, piix4_ids);
 
 static struct i2c_adapter *piix4_main_adapter;
+static struct i2c_adapter *piix4_aux_adapter;
 
 /* register piix4 I2C adapter at the given base address */
 static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba,
@@ -562,9 +606,33 @@ static int __devinit piix4_probe(struct pci_dev *dev,
 		retval = piix4_setup(dev, id, &smba);
 
 	if (retval)
-		return retval;
+		goto error;
+
+	retval = piix4_add_adapter(dev, smba, &piix4_main_adapter);
+	if (retval)
+		goto error;
 
-	return piix4_add_adapter(dev, smba, &piix4_main_adapter);
+	/* check for AMD SP5100 (maybe others) with aux SMBus port */
+	if (dev->vendor == PCI_VENDOR_ID_ATI &&
+	    dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
+		dev->revision == 0x3d) {
+
+		retval = piix4_setup_aux(dev, id, SMBAUXBA, &smba);
+		if (retval)
+			goto error;
+
+		retval = piix4_add_adapter(dev, smba, &piix4_aux_adapter);
+		if (retval)
+			goto error;
+	}
+
+	return 0;
+
+error:
+	/* clean up any adapters that were already added */
+	piix4_adap_remove(piix4_main_adapter);
+	piix4_adap_remove(piix4_aux_adapter);
+	return retval;
 }
 
 /* Remove the adapter and its associated IO region */
@@ -572,6 +640,9 @@ static void piix4_adap_remove(struct i2c_adapter *adap)
 {
 	struct i2c_piix4_adapdata *adapdata;
 
+	if (adap == NULL)
+		return;
+
 	adapdata = (struct i2c_piix4_adapdata *)i2c_get_adapdata(adap);
 	if (adapdata->smba) {
 		i2c_del_adapter(adap);
@@ -585,10 +656,8 @@ static void piix4_adap_remove(struct i2c_adapter *adap)
 
 static void __devexit piix4_remove(struct pci_dev *dev)
 {
-	if (piix4_main_adapter) {
-		piix4_adap_remove(piix4_main_adapter);
-		piix4_main_adapter = NULL;
-	}
+	piix4_adap_remove(piix4_main_adapter);
+	piix4_adap_remove(piix4_aux_adapter);
 }
 
 static struct pci_driver piix4_driver = {
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/3] i2c-piix4: eliminate global I/O base address
  2012-06-05  1:49           ` [PATCH 1/3] i2c-piix4: eliminate global I/O base address Andrew Armenia
@ 2012-06-12 11:53             ` Jean Delvare
  0 siblings, 0 replies; 11+ messages in thread
From: Jean Delvare @ 2012-06-12 11:53 UTC (permalink / raw)
  To: Andrew Armenia; +Cc: Ben Dooks, Wolfram Sang, linux-i2c, linux-kernel

Hi Andrew,

On Mon,  4 Jun 2012 21:49:22 -0400, Andrew Armenia wrote:
> The i2c-piix4 driver used a global variable to store the base address
> of the piix4 i2c registers. Some chipsets contain multiple sets of
> i2c registers; thus it is desirable to eliminate global state.
> 
> i2c_get_adapdata()/i2c_set_adapdata() are used to keep track
> of the IO base address; this is passed into piix4_transaction() as
> an argument, eliminating the global variable.
> 
> Signed-off-by: Andrew Armenia <andrew@asquaredlabs.com>
> ---
>  drivers/i2c/busses/i2c-piix4.c |   61 ++++++++++++++++++++++++++++++----------
>  1 file changed, 46 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
> index c14d48d..7a5889c 100644
> --- a/drivers/i2c/busses/i2c-piix4.c
> +++ b/drivers/i2c/busses/i2c-piix4.c
> @@ -94,7 +94,6 @@ MODULE_PARM_DESC(force_addr,
>  		 "Forcibly enable the PIIX4 at the given address. "
>  		 "EXTREMELY DANGEROUS!");
>  
> -static unsigned short piix4_smba;
>  static int srvrworks_csb5_delay;
>  static struct pci_driver piix4_driver;
>  static struct i2c_adapter piix4_adapter;
> @@ -127,10 +126,16 @@ static struct dmi_system_id __devinitdata piix4_dmi_ibm[] = {
>  	{ },
>  };
>  
> +struct i2c_piix4_adapdata {
> +	unsigned short smba;
> +};
> +
>  static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
> -				const struct pci_device_id *id)
> +				const struct pci_device_id *id,
> +				unsigned short *smba)

You could instead return the smba value, as the return value is
currently only used for errors. This would avoid the extra parameter
and possibly false-positive compiler warnings.

>  {
>  	unsigned char temp;
> +	unsigned short piix4_smba;
>  
>  	if ((PIIX4_dev->vendor == PCI_VENDOR_ID_SERVERWORKS) &&
>  	    (PIIX4_dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5))
> @@ -224,12 +229,15 @@ static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
>  		 "SMBus Host Controller at 0x%x, revision %d\n",
>  		 piix4_smba, temp);
>  
> +	*smba = piix4_smba;
>  	return 0;
>  }
>  
>  static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
> -				const struct pci_device_id *id)
> +				const struct pci_device_id *id,
> +				unsigned short *smba)
>  {
> +	unsigned short piix4_smba;
>  	unsigned short smba_idx = 0xcd6;
>  	u8 smba_en_lo, smba_en_hi, i2ccfg, i2ccfg_offset = 0x10, smb_en = 0x2c;
>  
> @@ -288,10 +296,11 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
>  		 "SMBus Host Controller at 0x%x, revision %d\n",
>  		 piix4_smba, i2ccfg >> 4);
>  
> +	*smba = piix4_smba;
>  	return 0;
>  }
>  
> -static int piix4_transaction(void)
> +static int piix4_transaction(unsigned short piix4_smba)
>  {
>  	int temp;
>  	int result = 0;
> @@ -372,6 +381,11 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
>  {
>  	int i, len;
>  	int status;
> +	unsigned short piix4_smba;
> +	struct i2c_piix4_adapdata *adapdata;
> +
> +	adapdata = (struct i2c_piix4_adapdata *)i2c_get_adapdata(adap);

Useless cast.

> +	piix4_smba = adapdata->smba;
>  
>  	switch (size) {
>  	case I2C_SMBUS_QUICK:
> @@ -426,7 +440,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
>  
>  	outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT);
>  
> -	status = piix4_transaction();
> +	status = piix4_transaction(piix4_smba);
>  	if (status)
>  		return status;
>  
> @@ -472,6 +486,10 @@ static struct i2c_adapter piix4_adapter = {
>  	.algo		= &smbus_algorithm,
>  };
>  
> +static struct i2c_piix4_adapdata piix4_adapter_data = {
> +	.smba		= 0,
> +};

Useless initialization, 0 is the default.

> +
>  static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
>  	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
>  	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
> @@ -500,15 +518,16 @@ static int __devinit piix4_probe(struct pci_dev *dev,
>  				const struct pci_device_id *id)
>  {
>  	int retval;
> +	unsigned short smba;
>  
>  	if ((dev->vendor == PCI_VENDOR_ID_ATI &&
>  	     dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
>  	     dev->revision >= 0x40) ||
>  	    dev->vendor == PCI_VENDOR_ID_AMD)
>  		/* base address location etc changed in SB800 */
> -		retval = piix4_setup_sb800(dev, id);
> +		retval = piix4_setup_sb800(dev, id, &smba);
>  	else
> -		retval = piix4_setup(dev, id);
> +		retval = piix4_setup(dev, id, &smba);
>  
>  	if (retval)
>  		return retval;
> @@ -517,26 +536,38 @@ static int __devinit piix4_probe(struct pci_dev *dev,
>  	piix4_adapter.dev.parent = &dev->dev;
>  
>  	snprintf(piix4_adapter.name, sizeof(piix4_adapter.name),
> -		"SMBus PIIX4 adapter at %04x", piix4_smba);
> +		"SMBus PIIX4 adapter at %04x", smba);
> +
> +	piix4_adapter_data.smba = smba;
> +
> +	i2c_set_adapdata(&piix4_adapter, &piix4_adapter_data);
>  
>  	if ((retval = i2c_add_adapter(&piix4_adapter))) {
>  		dev_err(&dev->dev, "Couldn't register adapter!\n");
> -		release_region(piix4_smba, SMBIOSIZE);
> -		piix4_smba = 0;
> +		release_region(smba, SMBIOSIZE);
> +		piix4_adapter_data.smba = 0;
>  	}
>  
>  	return retval;
>  }
>  
> -static void __devexit piix4_remove(struct pci_dev *dev)
> +static void piix4_adap_remove(struct i2c_adapter *adap)

Called from a __devinit function so it can be made __devinit too.

>  {
> -	if (piix4_smba) {
> -		i2c_del_adapter(&piix4_adapter);
> -		release_region(piix4_smba, SMBIOSIZE);
> -		piix4_smba = 0;
> +	struct i2c_piix4_adapdata *adapdata;
> +
> +	adapdata = (struct i2c_piix4_adapdata *)i2c_get_adapdata(adap);

Useless cast.

> +	if (adapdata->smba) {
> +		i2c_del_adapter(adap);
> +		release_region(adapdata->smba, SMBIOSIZE);
> +		adapdata->smba = 0;
>  	}
>  }
>  
> +static void __devexit piix4_remove(struct pci_dev *dev)
> +{
> +	piix4_adap_remove(&piix4_adapter);
> +}
> +
>  static struct pci_driver piix4_driver = {
>  	.name		= "piix4_smbus",
>  	.id_table	= piix4_ids,


-- 
Jean Delvare

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/3] i2c-piix4: separate registration and probing code
  2012-06-05  1:49           ` [PATCH 2/3] i2c-piix4: separate registration and probing code Andrew Armenia
@ 2012-06-12 12:10             ` Jean Delvare
  0 siblings, 0 replies; 11+ messages in thread
From: Jean Delvare @ 2012-06-12 12:10 UTC (permalink / raw)
  To: Andrew Armenia; +Cc: Ben Dooks, Wolfram Sang, linux-i2c, linux-kernel

On Mon,  4 Jun 2012 21:49:23 -0400, Andrew Armenia wrote:
> Some chipsets have multiple sets of SMBus registers each controlling a
> separate SMBus. Supporting these chipsets properly will require registering
> multiple I2C adapters for one piix4.
> 
> The code to initialize and register the i2c_adapter structure has been
> separated from piix4_probe and allows registration of a piix4 adapter
> given its base address. Note that the i2c_adapter and piix4_adapdata
> structures are now dynamically allocated.
> 
> Signed-off-by: Andrew Armenia <andrew@asquaredlabs.com>
> ---
>  drivers/i2c/busses/i2c-piix4.c |   79 ++++++++++++++++++++++++++--------------
>  1 file changed, 51 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
> index 7a5889c..8a87b3f 100644
> --- a/drivers/i2c/busses/i2c-piix4.c
> +++ b/drivers/i2c/busses/i2c-piix4.c
> @@ -480,16 +480,6 @@ static const struct i2c_algorithm smbus_algorithm = {
>  	.functionality	= piix4_func,
>  };
>  
> -static struct i2c_adapter piix4_adapter = {
> -	.owner		= THIS_MODULE,
> -	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
> -	.algo		= &smbus_algorithm,
> -};
> -
> -static struct i2c_piix4_adapdata piix4_adapter_data = {
> -	.smba		= 0,
> -};
> -
>  static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
>  	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
>  	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
> @@ -514,6 +504,48 @@ static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
>  
>  MODULE_DEVICE_TABLE (pci, piix4_ids);
>  
> +static struct i2c_adapter *piix4_main_adapter;
> +
> +/* register piix4 I2C adapter at the given base address */
> +static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba,
> +				struct i2c_adapter **padap) {

Called from a __devinit function, could be made __devinit.

> +	struct i2c_adapter *piix4_adapter;
> +	struct i2c_piix4_adapdata *piix4_adapdata;

It would be pleasant to use the same names here and in
piix4_adap_remove(), for consistency.

> +	int retval;
> +
> +	piix4_adapter = kmalloc(sizeof(*piix4_adapter), GFP_KERNEL);
> +	memset(piix4_adapter, 0, sizeof(*piix4_adapter));

Please use kzalloc. Furthermore, k*alloc() can theoretically fail, so
you have to check for this unlikely case and handle it gracefully.

> +	piix4_adapter->owner = THIS_MODULE;
> +	piix4_adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
> +	piix4_adapter->algo = &smbus_algorithm;
> +
> +	piix4_adapdata = kmalloc(sizeof(*piix4_adapdata), GFP_KERNEL);
> +	memset(piix4_adapdata, 0, sizeof(*piix4_adapdata));

Same here.

> +	piix4_adapdata->smba = smba;
> +
> +	/* set up the sysfs linkage to our parent device */
> +	piix4_adapter->dev.parent = &dev->dev;
> +
> +	snprintf(piix4_adapter->name, sizeof(piix4_adapter->name),
> +		"SMBus PIIX4 adapter at %04x", smba);
> +
> +	piix4_adapdata->smba = smba;

You already did that a few lines above.

> +
> +	i2c_set_adapdata(piix4_adapter, piix4_adapdata);
> +
> +	retval = i2c_add_adapter(piix4_adapter);
> +	if (retval) {
> +		dev_err(&dev->dev, "Couldn't register adapter!\n");
> +		release_region(smba, SMBIOSIZE);
> +		kfree(piix4_adapdata);
> +		kfree(piix4_adapter);
> +	}
> +
> +	*padap = piix4_adapter;

It's pointless do to that in the error case.

> +
> +	return retval;
> +}
> +
>  static int __devinit piix4_probe(struct pci_dev *dev,
>  				const struct pci_device_id *id)
>  {
> @@ -532,25 +564,10 @@ static int __devinit piix4_probe(struct pci_dev *dev,
>  	if (retval)
>  		return retval;
>  
> -	/* set up the sysfs linkage to our parent device */
> -	piix4_adapter.dev.parent = &dev->dev;
> -
> -	snprintf(piix4_adapter.name, sizeof(piix4_adapter.name),
> -		"SMBus PIIX4 adapter at %04x", smba);
> -
> -	piix4_adapter_data.smba = smba;
> -
> -	i2c_set_adapdata(&piix4_adapter, &piix4_adapter_data);
> -
> -	if ((retval = i2c_add_adapter(&piix4_adapter))) {
> -		dev_err(&dev->dev, "Couldn't register adapter!\n");
> -		release_region(smba, SMBIOSIZE);
> -		piix4_adapter_data.smba = 0;
> -	}
> -
> -	return retval;
> +	return piix4_add_adapter(dev, smba, &piix4_main_adapter);
>  }
>  
> +/* Remove the adapter and its associated IO region */
>  static void piix4_adap_remove(struct i2c_adapter *adap)
>  {
>  	struct i2c_piix4_adapdata *adapdata;
> @@ -561,11 +578,17 @@ static void piix4_adap_remove(struct i2c_adapter *adap)
>  		release_region(adapdata->smba, SMBIOSIZE);
>  		adapdata->smba = 0;

This one can go away, no point in cleaning up a structure you're about
to free.

>  	}
> +
> +	kfree(adapdata);
> +	kfree(adap);
>  }
>  
>  static void __devexit piix4_remove(struct pci_dev *dev)
>  {
> -	piix4_adap_remove(&piix4_adapter);
> +	if (piix4_main_adapter) {
> +		piix4_adap_remove(piix4_main_adapter);
> +		piix4_main_adapter = NULL;
> +	}
>  }
>  
>  static struct pci_driver piix4_driver = {


-- 
Jean Delvare

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 3/3] i2c-piix4: support aux SMBus on AMD chipsets
       [not found]           ` <1338860964-10803-4-git-send-email-andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>
@ 2012-06-12 12:47             ` Jean Delvare
  0 siblings, 0 replies; 11+ messages in thread
From: Jean Delvare @ 2012-06-12 12:47 UTC (permalink / raw)
  To: Andrew Armenia
  Cc: Ben Dooks, Wolfram Sang, linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

On Mon,  4 Jun 2012 21:49:24 -0400, Andrew Armenia wrote:
> Some AMD chipsets, such as the SP5100, have an auxiliary SMBus with a second
> set of registers. This patch adds support for the SP5100 and should work on
> similar chipsets. Tested on ASUS KCMA-D8 motherboard.

The SP5100 isn't even documented as being supported. Can you please add
it to Documentation/i2c/busses/i2c-piix4, drivers/i2c/busses/Kconfig,
and the header comment? Or is it a different code name for an already
supported south bridge? I admit I stopped following AMD chipsets some
times ago.

> 
> Signed-off-by: Andrew Armenia <andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>
> ---
>  drivers/i2c/busses/i2c-piix4.c |   83 ++++++++++++++++++++++++++++++++++++----
>  1 file changed, 76 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
> index 8a87b3f..972b604 100644
> --- a/drivers/i2c/busses/i2c-piix4.c
> +++ b/drivers/i2c/busses/i2c-piix4.c
> @@ -25,7 +25,8 @@
>  	AMD Hudson-2
>  	SMSC Victory66
>  
> -   Note: we assume there can only be one device, with one SMBus interface.
> +   Note: we assume there can only be one device, with one or two SMBus
> +   interfaces.
>  */
>  
>  #include <linux/module.h>
> @@ -66,6 +67,7 @@
>  #define SMBSHDW1	0x0D4
>  #define SMBSHDW2	0x0D5
>  #define SMBREV		0x0D6
> +#define SMBAUXBA	0x058

Keeping the list sorted by register offset would seem reasonable.

>  
>  /* Other settings */
>  #define MAX_TIMEOUT	500
> @@ -130,6 +132,8 @@ struct i2c_piix4_adapdata {
>  	unsigned short smba;
>  };
>  
> +static void piix4_adap_remove(struct i2c_adapter *adap);
> +

Please just reorder the functions (ideally at the time you introduce
them) so that you don't need this forward declaration.

>  static int __devinit piix4_setup(struct pci_dev *PIIX4_dev,
>  				const struct pci_device_id *id,
>  				unsigned short *smba)
> @@ -300,6 +304,45 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
>  	return 0;
>  }
>  
> +static int __devinit piix4_setup_aux(struct pci_dev *PIIX4_dev,
> +				const struct pci_device_id *id,
> +				unsigned short base_reg_addr,
> +				unsigned short *smba)
> +{
> +	/* Set up auxiliary SMBus controllers found on some AMD
> +	 * chipsets e.g. SP5100 */
> +	unsigned short piix4_smba;
> +
> +	/* Read address of auxiliary SMBus controller */
> +	pci_read_config_word(PIIX4_dev, base_reg_addr, &piix4_smba);
> +	piix4_smba &= 0xffe0;
> +
> +	if (piix4_smba == 0) {
> +		dev_err(&PIIX4_dev->dev, "Aux SMBus base address "
> +			"uninitialized - upgrade BIOS\n");

This case could be OK if the board vendor simply did not need a second
SMBus channel. So we shouldn't spit an error message in this case,
maybe a debug message if you want but that's about it.

> +		return -ENODEV;
> +	}
> +
> +	if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
> +		return -ENODEV;
> +
> +	if (!request_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) {
> +		dev_err(&PIIX4_dev->dev, "Aux SMBus region 0x%x already"
> +			" in use!\n", piix4_smba);

White space at end of first half please, for consistency.

> +		return -EBUSY;
> +	}
> +
> +	dev_info(&PIIX4_dev->dev,
> +		"Auxiliary SMBus Host Controller at 0x%x\n",

You should probably write "Auxiliary" in the previous message messages
too, for consistency and readability.

> +		piix4_smba
> +	);
> +
> +	*smba = piix4_smba;
> +
> +	return 0;
> +}
> +
> +
>  static int piix4_transaction(unsigned short piix4_smba)
>  {
>  	int temp;
> @@ -505,6 +548,7 @@ static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
>  MODULE_DEVICE_TABLE (pci, piix4_ids);
>  
>  static struct i2c_adapter *piix4_main_adapter;
> +static struct i2c_adapter *piix4_aux_adapter;
>  
>  /* register piix4 I2C adapter at the given base address */
>  static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba,
> @@ -562,9 +606,33 @@ static int __devinit piix4_probe(struct pci_dev *dev,
>  		retval = piix4_setup(dev, id, &smba);
>  
>  	if (retval)
> -		return retval;
> +		goto error;
> +
> +	retval = piix4_add_adapter(dev, smba, &piix4_main_adapter);
> +	if (retval)
> +		goto error;
>  
> -	return piix4_add_adapter(dev, smba, &piix4_main_adapter);
> +	/* check for AMD SP5100 (maybe others) with aux SMBus port */
> +	if (dev->vendor == PCI_VENDOR_ID_ATI &&
> +	    dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
> +		dev->revision == 0x3d) {

Hmm, that would be an ATI SB600 or SB700, so not a recent chip? This
strict check on revision is likely to exclude some systems where this
code should run. Given that the SB800 started at revision 0x40 as far
as I know, shouldn't we test for < 0x40 here?

> +
> +		retval = piix4_setup_aux(dev, id, SMBAUXBA, &smba);
> +		if (retval)
> +			goto error;
> +
> +		retval = piix4_add_adapter(dev, smba, &piix4_aux_adapter);
> +		if (retval)
> +			goto error;

I don't get the logic here. If we fail to register the auxiliary SMBus,
it is certainly not a reason to give up the working main SMBus.
Especially with my comment above that the Auxiliary SMBus may have been
disabled by the vendor on purpose.

> +	}
> +
> +	return 0;
> +
> +error:
> +	/* clean up any adapters that were already added */
> +	piix4_adap_remove(piix4_main_adapter);
> +	piix4_adap_remove(piix4_aux_adapter);

You're not clearing the pointers, this could cause trouble on hot-plug.

> +	return retval;
>  }
>  
>  /* Remove the adapter and its associated IO region */
> @@ -572,6 +640,9 @@ static void piix4_adap_remove(struct i2c_adapter *adap)
>  {
>  	struct i2c_piix4_adapdata *adapdata;
>  
> +	if (adap == NULL)
> +		return;
> +

If you want to do that, it would be better done right in patch 2/3, to
avoid changing code back and forth.

>  	adapdata = (struct i2c_piix4_adapdata *)i2c_get_adapdata(adap);
>  	if (adapdata->smba) {
>  		i2c_del_adapter(adap);
> @@ -585,10 +656,8 @@ static void piix4_adap_remove(struct i2c_adapter *adap)
>  
>  static void __devexit piix4_remove(struct pci_dev *dev)
>  {
> -	if (piix4_main_adapter) {
> -		piix4_adap_remove(piix4_main_adapter);
> -		piix4_main_adapter = NULL;
> -	}
> +	piix4_adap_remove(piix4_main_adapter);
> +	piix4_adap_remove(piix4_aux_adapter);

Here again you're no longer clearing the pointers afterward, this could
cause trouble (unlikely, but better safe than sorry.)

>  }
>  
>  static struct pci_driver piix4_driver = {


-- 
Jean Delvare

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 2/3] i2c-piix4: separate registration and probing code
       [not found]   ` <1339606749-4578-1-git-send-email-andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>
@ 2012-06-13 16:59     ` Andrew Armenia
       [not found]       ` <1339606749-4578-3-git-send-email-andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>
  0 siblings, 1 reply; 11+ messages in thread
From: Andrew Armenia @ 2012-06-13 16:59 UTC (permalink / raw)
  To: Jean Delvare, Ben Dooks, Wolfram Sang
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andrew Armenia

Some chipsets have multiple sets of SMBus registers each controlling a
separate SMBus. Supporting these chipsets properly will require registering
multiple I2C adapters for one piix4.

The code to initialize and register the i2c_adapter structure has been
separated from piix4_probe and allows registration of a piix4 adapter
given its base address. Note that the i2c_adapter and i2c_piix4_adapdata
structures are now dynamically allocated.

Signed-off-by: Andrew Armenia <andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>
---
 drivers/i2c/busses/i2c-piix4.c |  113 ++++++++++++++++++++++++++--------------
 1 file changed, 73 insertions(+), 40 deletions(-)

diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 61a85c9..8181963 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -96,7 +96,6 @@ MODULE_PARM_DESC(force_addr,
 
 static int srvrworks_csb5_delay;
 static struct pci_driver piix4_driver;
-static struct i2c_adapter piix4_adapter;
 
 static struct dmi_system_id __devinitdata piix4_dmi_blacklist[] = {
 	{
@@ -294,27 +293,33 @@ static int __devinit piix4_setup_sb800(struct pci_dev *PIIX4_dev,
 	return piix4_smba;
 }
 
-static int piix4_transaction(unsigned short piix4_smba)
+static int piix4_transaction(struct i2c_adapter *piix4_adapter)
 {
 	int temp;
 	int result = 0;
 	int timeout = 0;
 
-	dev_dbg(&piix4_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
+	struct i2c_piix4_adapdata *adapdata;
+	unsigned short piix4_smba;
+
+	adapdata = i2c_get_adapdata(piix4_adapter);
+	piix4_smba = adapdata->smba;
+
+	dev_dbg(&piix4_adapter->dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
 		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
 		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
 		inb_p(SMBHSTDAT1));
 
 	/* Make sure the SMBus host is ready to start transmitting */
 	if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-		dev_dbg(&piix4_adapter.dev, "SMBus busy (%02x). "
+		dev_dbg(&piix4_adapter->dev, "SMBus busy (%02x). "
 			"Resetting...\n", temp);
 		outb_p(temp, SMBHSTSTS);
 		if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-			dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp);
+			dev_err(&piix4_adapter->dev, "Failed! (%02x)\n", temp);
 			return -EBUSY;
 		} else {
-			dev_dbg(&piix4_adapter.dev, "Successful!\n");
+			dev_dbg(&piix4_adapter->dev, "Successful!\n");
 		}
 	}
 
@@ -333,35 +338,35 @@ static int piix4_transaction(unsigned short piix4_smba)
 
 	/* If the SMBus is still busy, we give up */
 	if (timeout == MAX_TIMEOUT) {
-		dev_err(&piix4_adapter.dev, "SMBus Timeout!\n");
+		dev_err(&piix4_adapter->dev, "SMBus Timeout!\n");
 		result = -ETIMEDOUT;
 	}
 
 	if (temp & 0x10) {
 		result = -EIO;
-		dev_err(&piix4_adapter.dev, "Error: Failed bus transaction\n");
+		dev_err(&piix4_adapter->dev, "Error: Failed bus transaction\n");
 	}
 
 	if (temp & 0x08) {
 		result = -EIO;
-		dev_dbg(&piix4_adapter.dev, "Bus collision! SMBus may be "
+		dev_dbg(&piix4_adapter->dev, "Bus collision! SMBus may be "
 			"locked until next hard reset. (sorry!)\n");
 		/* Clock stops and slave is stuck in mid-transmission */
 	}
 
 	if (temp & 0x04) {
 		result = -ENXIO;
-		dev_dbg(&piix4_adapter.dev, "Error: no response!\n");
+		dev_dbg(&piix4_adapter->dev, "Error: no response!\n");
 	}
 
 	if (inb_p(SMBHSTSTS) != 0x00)
 		outb_p(inb(SMBHSTSTS), SMBHSTSTS);
 
 	if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
-		dev_err(&piix4_adapter.dev, "Failed reset at end of "
+		dev_err(&piix4_adapter->dev, "Failed reset at end of "
 			"transaction (%02x)\n", temp);
 	}
-	dev_dbg(&piix4_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, "
+	dev_dbg(&piix4_adapter->dev, "Transaction (post): CNT=%02x, CMD=%02x, "
 		"ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT),
 		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
 		inb_p(SMBHSTDAT1));
@@ -434,7 +439,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr,
 
 	outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT);
 
-	status = piix4_transaction(piix4_smba);
+	status = piix4_transaction(adap);
 	if (status)
 		return status;
 
@@ -474,14 +479,6 @@ static const struct i2c_algorithm smbus_algorithm = {
 	.functionality	= piix4_func,
 };
 
-static struct i2c_adapter piix4_adapter = {
-	.owner		= THIS_MODULE,
-	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
-	.algo		= &smbus_algorithm,
-};
-
-static struct i2c_piix4_adapdata piix4_adapter_data;
-
 static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
 	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
@@ -506,6 +503,54 @@ static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
 
 MODULE_DEVICE_TABLE (pci, piix4_ids);
 
+static struct i2c_adapter *piix4_main_adapter;
+
+static int __devinit piix4_add_adapter(struct pci_dev *dev,
+					unsigned short smba,
+					struct i2c_adapter **padap)
+{
+	struct i2c_adapter *adap;
+	struct i2c_piix4_adapdata *adapdata;
+
+	int retval;
+
+	adap = kzalloc(sizeof(*adap), GFP_KERNEL);
+	if (NULL == adap)
+		return -ENOMEM;
+
+	adap->owner = THIS_MODULE;
+	adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+	adap->algo = &smbus_algorithm;
+
+	adapdata = kzalloc(sizeof(*adapdata), GFP_KERNEL);
+	if (NULL == adapdata) {
+		kfree(adap);
+		return -ENOMEM;
+	}
+
+	adapdata->smba = smba;
+
+	/* set up the sysfs linkage to our parent device */
+	adap->dev.parent = &dev->dev;
+
+	snprintf(adap->name, sizeof(adap->name),
+		"SMBus PIIX4 adapter at %04x", smba);
+
+	i2c_set_adapdata(adap, adapdata);
+
+	retval = i2c_add_adapter(adap);
+	if (retval) {
+		dev_err(&dev->dev, "Couldn't register adapter!\n");
+		release_region(smba, SMBIOSIZE);
+		kfree(adapdata);
+		kfree(adap);
+		return retval;
+	}
+
+	*padap = adap;
+	return 0;
+}
+
 static int __devinit piix4_probe(struct pci_dev *dev,
 				const struct pci_device_id *id)
 {
@@ -523,23 +568,7 @@ static int __devinit piix4_probe(struct pci_dev *dev,
 	if (retval < 0)
 		return retval;
 
-	/* set up the sysfs linkage to our parent device */
-	piix4_adapter.dev.parent = &dev->dev;
-
-	piix4_adapter_data.smba = retval;
-
-	snprintf(piix4_adapter.name, sizeof(piix4_adapter.name),
-		"SMBus PIIX4 adapter at %04x", piix4_adapter_data.smba);
-
-	i2c_set_adapdata(&piix4_adapter, &piix4_adapter_data);
-
-	if ((retval = i2c_add_adapter(&piix4_adapter))) {
-		dev_err(&dev->dev, "Couldn't register adapter!\n");
-		release_region(piix4_adapter_data.smba, SMBIOSIZE);
-		piix4_adapter_data.smba = 0;
-	}
-
-	return retval;
+	return piix4_add_adapter(dev, retval, &piix4_main_adapter);
 }
 
 static void __devinit piix4_adap_remove(struct i2c_adapter *adap)
@@ -550,13 +579,17 @@ static void __devinit piix4_adap_remove(struct i2c_adapter *adap)
 	if (adapdata->smba) {
 		i2c_del_adapter(adap);
 		release_region(adapdata->smba, SMBIOSIZE);
-		adapdata->smba = 0;
+		kfree(adapdata);
+		kfree(adap);
 	}
 }
 
 static void __devexit piix4_remove(struct pci_dev *dev)
 {
-	piix4_adap_remove(&piix4_adapter);
+	if (piix4_main_adapter) {
+		piix4_adap_remove(piix4_main_adapter);
+		piix4_main_adapter = NULL;
+	}
 }
 
 static struct pci_driver piix4_driver = {
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/3] i2c-piix4: separate registration and probing code
       [not found]       ` <1339606749-4578-3-git-send-email-andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>
@ 2012-06-14 19:38         ` Jean Delvare
  0 siblings, 0 replies; 11+ messages in thread
From: Jean Delvare @ 2012-06-14 19:38 UTC (permalink / raw)
  To: Andrew Armenia
  Cc: Ben Dooks, Wolfram Sang, linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA

Hi Andrew,

On Wed, 13 Jun 2012 12:59:08 -0400, Andrew Armenia wrote:
> Some chipsets have multiple sets of SMBus registers each controlling a
> separate SMBus. Supporting these chipsets properly will require registering
> multiple I2C adapters for one piix4.
> 
> The code to initialize and register the i2c_adapter structure has been
> separated from piix4_probe and allows registration of a piix4 adapter
> given its base address. Note that the i2c_adapter and i2c_piix4_adapdata
> structures are now dynamically allocated.
> 
> Signed-off-by: Andrew Armenia <andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>
> ---
>  drivers/i2c/busses/i2c-piix4.c |  113 ++++++++++++++++++++++++++--------------
>  1 file changed, 73 insertions(+), 40 deletions(-)
> (...)

Applied, with the minor changes below:

> -static int piix4_transaction(unsigned short piix4_smba)
> +static int piix4_transaction(struct i2c_adapter *piix4_adapter)
>  {
>  	int temp;
>  	int result = 0;
>  	int timeout = 0;
>  
> -	dev_dbg(&piix4_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, "
> +	struct i2c_piix4_adapdata *adapdata;
> +	unsigned short piix4_smba;
> +
> +	adapdata = i2c_get_adapdata(piix4_adapter);
> +	piix4_smba = adapdata->smba;

It is customary to declare and assign all at once in this case:

	struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(piix4_adapter);
	unsigned short piix4_smba = adapdata->smba;

This makes the code more compact and more readable too. I've fixed it
and everywhere else.

> (...)
> +static int __devinit piix4_add_adapter(struct pci_dev *dev,
> +					unsigned short smba,
> +					struct i2c_adapter **padap)
> +{
> +	struct i2c_adapter *adap;
> +	struct i2c_piix4_adapdata *adapdata;
> +
> +	int retval;
> +
> +	adap = kzalloc(sizeof(*adap), GFP_KERNEL);
> +	if (NULL == adap)

There's no point in inverting comparisons this way. Compilers would let
you know if you had it wrong, they do for at least 10 years now.

-- 
Jean Delvare

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2012-06-14 19:38 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-06-01 18:16 [PATCH] i2c-piix4: support multiple PIIX4 SMBus hosts Andrew Armenia
     [not found] ` <1338574572-10668-1-git-send-email-andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>
2012-06-04  7:16   ` Jean Delvare
     [not found]     ` <20120604091643.208956fe-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org>
2012-06-05  1:49       ` [PATCH 0/3] Multiple piix4-compatible SMBus support Andrew Armenia
     [not found]         ` <1338860964-10803-1-git-send-email-andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>
2012-06-05  1:49           ` [PATCH 1/3] i2c-piix4: eliminate global I/O base address Andrew Armenia
2012-06-12 11:53             ` Jean Delvare
2012-06-05  1:49           ` [PATCH 2/3] i2c-piix4: separate registration and probing code Andrew Armenia
2012-06-12 12:10             ` Jean Delvare
2012-06-05  1:49         ` [PATCH 3/3] i2c-piix4: support aux SMBus on AMD chipsets Andrew Armenia
     [not found]           ` <1338860964-10803-4-git-send-email-andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>
2012-06-12 12:47             ` Jean Delvare
  -- strict thread matches above, loose matches on Subject: below --
2012-06-13  7:47 [PATCH] i2c multiplexer driver for Proliant microserver N36L Jean Delvare
2012-06-13 16:59 ` [PATCH 0/3] i2c-piix4: Multiple piix4-compatible SMBus support (revised) Andrew Armenia
     [not found]   ` <1339606749-4578-1-git-send-email-andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>
2012-06-13 16:59     ` [PATCH 2/3] i2c-piix4: separate registration and probing code Andrew Armenia
     [not found]       ` <1339606749-4578-3-git-send-email-andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>
2012-06-14 19:38         ` Jean Delvare

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).