* [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; 9+ 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] 9+ messages in thread[parent not found: <1338574572-10668-1-git-send-email-andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>]
* 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; 9+ 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] 9+ messages in thread
[parent not found: <20120604091643.208956fe-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org>]
* [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; 9+ 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] 9+ messages in thread
[parent not found: <1338860964-10803-1-git-send-email-andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>]
* [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; 9+ 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] 9+ 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; 9+ 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] 9+ 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; 9+ 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] 9+ 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; 9+ 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] 9+ 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; 9+ 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] 9+ messages in thread
[parent not found: <1338860964-10803-4-git-send-email-andrew-Lwj1yN59in/Ib2jZbfQ/kQ@public.gmane.org>]
* 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; 9+ 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] 9+ messages in thread
end of thread, other threads:[~2012-06-12 12:47 UTC | newest]
Thread overview: 9+ 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
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).