Message ID | 20240904105731.2246235-4-Shyam-sundar.S-k@amd.com |
---|---|
State | Changes Requested |
Delegated to: | Andi Shyti |
Headers | show |
Series | Introduce AMD ASF Controller Support to the i2c-piix4 driver | expand |
On Wed, Sep 04, 2024 at 04:27:29PM +0530, Shyam Sundar S K wrote: > The AMD ASF controller is presented to the operating system as an ACPI > device. The piix4 driver can obtain the ASF handle through ACPI to > retrieve information about the ASF controller's attributes, such as the > ASF address space and interrupt number, and to handle ASF interrupts. > > Currently, the piix4 driver assumes that a specific port address is > designated for AUX operations. However, with the introduction of ASF, the > same port address may also be used by the ASF controller. Therefore, a > check needs to be added to ensure that if ASF is advertised and enabled in > ACPI, the AUX port is not set up. > Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Use --cc parameter when sending, instead of this, or alternatively move this line... > Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com> > Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com> > Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> > --- ...to be somewhere here. It will the same effect for you and me (in case you use `git send-email`). > drivers/i2c/busses/i2c-piix4.c | 166 ++++++++++++++++++++++++++++++++- ... > +struct sb800_asf_data { > + unsigned short addr; > + int irq; > +}; > struct i2c_piix4_adapdata { > struct sb800_mmio_cfg mmio_cfg; > u8 algo_select; > struct i2c_client *slave; > + bool is_asf; > + struct delayed_work work_buf; > }; Side note, always run `pahole` when adding new data structures or modifying existing ones. It might save memory on the running systems. ... > +static void sb800_asf_process_slave(struct work_struct *work) > +{ > + struct i2c_piix4_adapdata *adapdata = container_of(work, struct i2c_piix4_adapdata, > + work_buf.work); Better split is struct i2c_piix4_adapdata *adapdata = container_of(work, struct i2c_piix4_adapdata, work_buf.work); > + unsigned short piix4_smba = adapdata->smba; > + u8 data[SB800_ASF_BLOCK_MAX_BYTES]; > + u8 bank, reg, cmd = 0; > + u8 len, val = 0; > + int i; > + > + /* Read slave status register */ > + reg = inb_p(ASFSLVSTA); > + > + /* Check if no error bits are set in slave status register */ > + if (!(reg & SB800_ASF_ERROR_STATUS)) { Why not use positive conditional? (This will require to swap if/else branches) > + /* Read data bank */ > + reg = inb_p(ASFDATABNKSEL); > + bank = (reg & BIT(3)) >> 3; > + > + /* Set read data bank */ > + if (bank) { > + reg = reg | BIT(4); > + reg = reg & (~BIT(3)); > + } else { > + reg = reg & (~BIT(4)); > + reg = reg & (~BIT(2)); In all these three cases the outer parentheses are redundant. > + } > + > + /* Read command register */ > + outb_p(reg, ASFDATABNKSEL); > + cmd = inb_p(ASFINDEX); > + len = inb_p(ASFDATARWPTR); > + for (i = 0; i < len; i++) > + data[i] = inb_p(ASFINDEX); > + > + /* Clear data bank status */ > + if (bank) { > + reg = reg | BIT(3); > + outb_p(reg, ASFDATABNKSEL); > + } else { > + reg = reg | BIT(2); > + outb_p(reg, ASFDATABNKSEL); > + } > + } else { > + /* Set bank as full */ > + reg = reg | (BIT(3) | BIT(2)); GENMASK() ? > + outb_p(reg, ASFDATABNKSEL); > + } > + > + outb_p(0, ASFSETDATARDPTR); > + if (!(cmd & BIT(0))) { if (cmd & BIT(0)) return; ? > + i2c_slave_event(adapdata->slave, I2C_SLAVE_WRITE_REQUESTED, &val); > + for (i = 0; i < len; i++) { > + val = data[i]; > + i2c_slave_event(adapdata->slave, I2C_SLAVE_WRITE_RECEIVED, &val); > + } > + i2c_slave_event(adapdata->slave, I2C_SLAVE_STOP, &val); > + } > +} ... > +static irqreturn_t sb800_asf_irq_handler(int irq, void *ptr) > +{ > + struct i2c_piix4_adapdata *adapdata = (struct i2c_piix4_adapdata *)ptr; Unneeded explicit casting. > + unsigned short piix4_smba = adapdata->smba; > + u8 slave_int = inb_p(ASFSTA); > + > + if ((slave_int & BIT(6))) { Too many parentheses > + /* Slave Interrupt */ > + outb_p(slave_int | BIT(6), ASFSTA); > + schedule_delayed_work(&adapdata->work_buf, HZ); > + } else { > + /* Master Interrupt */ > + sb800_asf_update_bits(piix4_smba, SB800_ASF_SLV_INTR, SMBHSTSTS, true); > + } > + > + return IRQ_HANDLED; > +} ... > +static int sb800_asf_acpi_resource_cb(struct acpi_resource *resource, void *context) > +{ > + struct sb800_asf_data *data = context; > + > + switch (resource->type) { > + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: > + data->irq = resource->data.extended_irq.interrupts[0]; > + break; > + case ACPI_RESOURCE_TYPE_IO: > + data->addr = resource->data.io.minimum; > + break; > + } > + > + return 0; > +} Why do you still need this callback? What for? ... > +static int sb800_asf_add_adap(struct pci_dev *dev) > +{ > + struct i2c_piix4_adapdata *adapdata; > + struct sb800_asf_data data; > + struct acpi_device *adev; > + LIST_HEAD(res_list); > + acpi_status status; > + acpi_handle handle; > + int ret; > + > + status = acpi_get_handle(NULL, SB800_ASF_ACPI_PATH, &handle); > + if (ACPI_FAILURE(status)) > + return -ENODEV; > + > + adev = acpi_fetch_acpi_dev(handle); > + if (!adev) > + return -ENODEV; > + > + ret = acpi_dev_get_resources(adev, &res_list, sb800_asf_acpi_resource_cb, &data); ..., NULL, NULL): > + if (ret < 0) { > + dev_err(&dev->dev, "Error getting ASF ACPI resource: %d\n", ret); > + return ret; > + } Here iterate over the resources and take the ones you need by their respective types. > + acpi_dev_free_resource_list(&res_list); > + ret = piix4_add_adapter(dev, data.addr, SMBUS_ASF, piix4_adapter_count, false, 0, > + piix4_main_port_names_sb800[piix4_adapter_count], > + &piix4_main_adapters[piix4_adapter_count]); > + if (ret) { > + dev_err(&dev->dev, "Failed to add ASF adapter: %d\n", ret); > + return -ENODEV; > + } > + > + adapdata = i2c_get_adapdata(piix4_main_adapters[piix4_adapter_count]); > + ret = devm_request_irq(&dev->dev, data.irq, sb800_asf_irq_handler, IRQF_SHARED, > + "sb800_smbus_asf", adapdata); > + if (ret) { > + dev_err(&dev->dev, "Unable to request irq: %d for use\n", data.irq); > + return ret; > + } > + > + INIT_DELAYED_WORK(&adapdata->work_buf, sb800_asf_process_slave); > + adapdata->is_asf = true; > + /* Increment the adapter count by 1 as ASF is added to the list */ > + piix4_adapter_count += 1; ++ also suffice. > + return 1; > +}
Hi Shyam, kernel test robot noticed the following build errors: [auto build test ERROR on andi-shyti/i2c/i2c-host] [also build test ERROR on linus/master v6.11-rc6 next-20240904] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Shyam-Sundar-S-K/i2c-piix4-Allow-more-than-two-algo-selection-for-SMBus/20240904-190034 base: https://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux.git i2c/i2c-host patch link: https://lore.kernel.org/r/20240904105731.2246235-4-Shyam-sundar.S-k%40amd.com patch subject: [PATCH v2 3/5] i2c: piix4: Add ACPI support for ASF SMBus device config: arm-randconfig-003-20240905 (https://download.01.org/0day-ci/archive/20240905/202409051719.oja4MkJZ-lkp@intel.com/config) compiler: clang version 20.0.0git (https://github.com/llvm/llvm-project 05f5a91d00b02f4369f46d076411c700755ae041) reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240905/202409051719.oja4MkJZ-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202409051719.oja4MkJZ-lkp@intel.com/ All errors (new ones prefixed by >>): In file included from drivers/i2c/busses/i2c-piix4.c:26: In file included from include/linux/pci.h:1646: In file included from include/linux/dmapool.h:14: In file included from include/linux/scatterlist.h:8: In file included from include/linux/mm.h:2228: include/linux/vmstat.h:517:36: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion] 517 | return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_" | ~~~~~~~~~~~ ^ ~~~ >> drivers/i2c/busses/i2c-piix4.c:1318:9: error: call to undeclared function 'acpi_fetch_acpi_dev'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] 1318 | adev = acpi_fetch_acpi_dev(handle); | ^ drivers/i2c/busses/i2c-piix4.c:1318:9: note: did you mean 'acpi_match_acpi_device'? include/linux/acpi.h:932:44: note: 'acpi_match_acpi_device' declared here 932 | static inline const struct acpi_device_id *acpi_match_acpi_device( | ^ >> drivers/i2c/busses/i2c-piix4.c:1318:7: error: incompatible integer to pointer conversion assigning to 'struct acpi_device *' from 'int' [-Wint-conversion] 1318 | adev = acpi_fetch_acpi_dev(handle); | ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~ >> drivers/i2c/busses/i2c-piix4.c:1322:8: error: call to undeclared function 'acpi_dev_get_resources'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] 1322 | ret = acpi_dev_get_resources(adev, &res_list, sb800_asf_acpi_resource_cb, &data); | ^ drivers/i2c/busses/i2c-piix4.c:1322:8: note: did you mean 'acpi_get_event_resources'? include/acpi/acpixf.h:809:9: note: 'acpi_get_event_resources' declared here 809 | acpi_get_event_resources(acpi_handle device_handle, | ^ include/acpi/platform/aclinux.h:93:21: note: expanded from macro 'ACPI_EXTERNAL_RETURN_STATUS' 93 | static ACPI_INLINE prototype {return(AE_NOT_CONFIGURED);} | ^ >> drivers/i2c/busses/i2c-piix4.c:1328:2: error: call to undeclared function 'acpi_dev_free_resource_list'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration] 1328 | acpi_dev_free_resource_list(&res_list); | ^ drivers/i2c/busses/i2c-piix4.c:1328:2: note: did you mean 'pci_free_resource_list'? include/linux/pci.h:1496:6: note: 'pci_free_resource_list' declared here 1496 | void pci_free_resource_list(struct list_head *resources); | ^ 1 warning and 4 errors generated. vim +/acpi_fetch_acpi_dev +1318 drivers/i2c/busses/i2c-piix4.c 1303 1304 static int sb800_asf_add_adap(struct pci_dev *dev) 1305 { 1306 struct i2c_piix4_adapdata *adapdata; 1307 struct sb800_asf_data data; 1308 struct acpi_device *adev; 1309 LIST_HEAD(res_list); 1310 acpi_status status; 1311 acpi_handle handle; 1312 int ret; 1313 1314 status = acpi_get_handle(NULL, SB800_ASF_ACPI_PATH, &handle); 1315 if (ACPI_FAILURE(status)) 1316 return -ENODEV; 1317 > 1318 adev = acpi_fetch_acpi_dev(handle); 1319 if (!adev) 1320 return -ENODEV; 1321 > 1322 ret = acpi_dev_get_resources(adev, &res_list, sb800_asf_acpi_resource_cb, &data); 1323 if (ret < 0) { 1324 dev_err(&dev->dev, "Error getting ASF ACPI resource: %d\n", ret); 1325 return ret; 1326 } 1327 > 1328 acpi_dev_free_resource_list(&res_list); 1329 ret = piix4_add_adapter(dev, data.addr, SMBUS_ASF, piix4_adapter_count, false, 0, 1330 piix4_main_port_names_sb800[piix4_adapter_count], 1331 &piix4_main_adapters[piix4_adapter_count]); 1332 if (ret) { 1333 dev_err(&dev->dev, "Failed to add ASF adapter: %d\n", ret); 1334 return -ENODEV; 1335 } 1336 1337 adapdata = i2c_get_adapdata(piix4_main_adapters[piix4_adapter_count]); 1338 ret = devm_request_irq(&dev->dev, data.irq, sb800_asf_irq_handler, IRQF_SHARED, 1339 "sb800_smbus_asf", adapdata); 1340 if (ret) { 1341 dev_err(&dev->dev, "Unable to request irq: %d for use\n", data.irq); 1342 return ret; 1343 } 1344 1345 INIT_DELAYED_WORK(&adapdata->work_buf, sb800_asf_process_slave); 1346 adapdata->is_asf = true; 1347 /* Increment the adapter count by 1 as ASF is added to the list */ 1348 piix4_adapter_count += 1; 1349 return 1; 1350 } 1351
Hi Shyam, kernel test robot noticed the following build errors: [auto build test ERROR on andi-shyti/i2c/i2c-host] [also build test ERROR on linus/master v6.11-rc6 next-20240904] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch#_base_tree_information] url: https://github.com/intel-lab-lkp/linux/commits/Shyam-Sundar-S-K/i2c-piix4-Allow-more-than-two-algo-selection-for-SMBus/20240904-190034 base: https://git.kernel.org/pub/scm/linux/kernel/git/andi.shyti/linux.git i2c/i2c-host patch link: https://lore.kernel.org/r/20240904105731.2246235-4-Shyam-sundar.S-k%40amd.com patch subject: [PATCH v2 3/5] i2c: piix4: Add ACPI support for ASF SMBus device config: parisc-allmodconfig (https://download.01.org/0day-ci/archive/20240905/202409051743.1sRmenx6-lkp@intel.com/config) compiler: hppa-linux-gcc (GCC) 14.1.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240905/202409051743.1sRmenx6-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202409051743.1sRmenx6-lkp@intel.com/ All errors (new ones prefixed by >>): drivers/i2c/busses/i2c-piix4.c: In function 'sb800_asf_add_adap': drivers/i2c/busses/i2c-piix4.c:1318:16: error: implicit declaration of function 'acpi_fetch_acpi_dev'; did you mean 'acpi_match_acpi_device'? [-Wimplicit-function-declaration] 1318 | adev = acpi_fetch_acpi_dev(handle); | ^~~~~~~~~~~~~~~~~~~ | acpi_match_acpi_device >> drivers/i2c/busses/i2c-piix4.c:1318:14: error: assignment to 'struct acpi_device *' from 'int' makes pointer from integer without a cast [-Wint-conversion] 1318 | adev = acpi_fetch_acpi_dev(handle); | ^ drivers/i2c/busses/i2c-piix4.c:1322:15: error: implicit declaration of function 'acpi_dev_get_resources'; did you mean 'acpi_get_event_resources'? [-Wimplicit-function-declaration] 1322 | ret = acpi_dev_get_resources(adev, &res_list, sb800_asf_acpi_resource_cb, &data); | ^~~~~~~~~~~~~~~~~~~~~~ | acpi_get_event_resources drivers/i2c/busses/i2c-piix4.c:1328:9: error: implicit declaration of function 'acpi_dev_free_resource_list'; did you mean 'pci_free_resource_list'? [-Wimplicit-function-declaration] 1328 | acpi_dev_free_resource_list(&res_list); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ | pci_free_resource_list vim +1318 drivers/i2c/busses/i2c-piix4.c 1303 1304 static int sb800_asf_add_adap(struct pci_dev *dev) 1305 { 1306 struct i2c_piix4_adapdata *adapdata; 1307 struct sb800_asf_data data; 1308 struct acpi_device *adev; 1309 LIST_HEAD(res_list); 1310 acpi_status status; 1311 acpi_handle handle; 1312 int ret; 1313 1314 status = acpi_get_handle(NULL, SB800_ASF_ACPI_PATH, &handle); 1315 if (ACPI_FAILURE(status)) 1316 return -ENODEV; 1317 > 1318 adev = acpi_fetch_acpi_dev(handle); 1319 if (!adev) 1320 return -ENODEV; 1321 1322 ret = acpi_dev_get_resources(adev, &res_list, sb800_asf_acpi_resource_cb, &data); 1323 if (ret < 0) { 1324 dev_err(&dev->dev, "Error getting ASF ACPI resource: %d\n", ret); 1325 return ret; 1326 } 1327 1328 acpi_dev_free_resource_list(&res_list); 1329 ret = piix4_add_adapter(dev, data.addr, SMBUS_ASF, piix4_adapter_count, false, 0, 1330 piix4_main_port_names_sb800[piix4_adapter_count], 1331 &piix4_main_adapters[piix4_adapter_count]); 1332 if (ret) { 1333 dev_err(&dev->dev, "Failed to add ASF adapter: %d\n", ret); 1334 return -ENODEV; 1335 } 1336 1337 adapdata = i2c_get_adapdata(piix4_main_adapters[piix4_adapter_count]); 1338 ret = devm_request_irq(&dev->dev, data.irq, sb800_asf_irq_handler, IRQF_SHARED, 1339 "sb800_smbus_asf", adapdata); 1340 if (ret) { 1341 dev_err(&dev->dev, "Unable to request irq: %d for use\n", data.irq); 1342 return ret; 1343 } 1344 1345 INIT_DELAYED_WORK(&adapdata->work_buf, sb800_asf_process_slave); 1346 adapdata->is_asf = true; 1347 /* Increment the adapter count by 1 as ASF is added to the list */ 1348 piix4_adapter_count += 1; 1349 return 1; 1350 } 1351
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 003cb04312cf..3bcf2e8b24e7 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -60,9 +60,12 @@ #define SB800_ASF_CLK_EN 17 /* SB800 ASF address offsets */ +#define ASFINDEX (7 + piix4_smba) #define ASFLISADDR (9 + piix4_smba) #define ASFSTA (0xA + piix4_smba) #define ASFSLVSTA (0xD + piix4_smba) +#define ASFDATARWPTR (0x11 + piix4_smba) +#define ASFSETDATARDPTR (0x12 + piix4_smba) #define ASFDATABNKSEL (0x13 + piix4_smba) #define ASFSLVEN (0x15 + piix4_smba) @@ -118,6 +121,8 @@ #define SB800_PIIX4_FCH_PM_ADDR 0xFED80300 #define SB800_PIIX4_FCH_PM_SIZE 8 #define SB800_ASF_BLOCK_MAX_BYTES 72 +#define SB800_ASF_ERROR_STATUS 0xE +#define SB800_ASF_ACPI_PATH "\\_SB.ASFC" /* insmod parameters */ @@ -182,6 +187,11 @@ struct sb800_mmio_cfg { bool use_mmio; }; +struct sb800_asf_data { + unsigned short addr; + int irq; +}; + enum piix4_algo { PIIX4_SB800, PIIX4_SMBUS, @@ -198,6 +208,8 @@ struct i2c_piix4_adapdata { struct sb800_mmio_cfg mmio_cfg; u8 algo_select; struct i2c_client *slave; + bool is_asf; + struct delayed_work work_buf; }; static int piix4_sb800_region_request(struct device *dev, @@ -906,6 +918,66 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr, return retval; } +static void sb800_asf_process_slave(struct work_struct *work) +{ + struct i2c_piix4_adapdata *adapdata = container_of(work, struct i2c_piix4_adapdata, + work_buf.work); + unsigned short piix4_smba = adapdata->smba; + u8 data[SB800_ASF_BLOCK_MAX_BYTES]; + u8 bank, reg, cmd = 0; + u8 len, val = 0; + int i; + + /* Read slave status register */ + reg = inb_p(ASFSLVSTA); + + /* Check if no error bits are set in slave status register */ + if (!(reg & SB800_ASF_ERROR_STATUS)) { + /* Read data bank */ + reg = inb_p(ASFDATABNKSEL); + bank = (reg & BIT(3)) >> 3; + + /* Set read data bank */ + if (bank) { + reg = reg | BIT(4); + reg = reg & (~BIT(3)); + } else { + reg = reg & (~BIT(4)); + reg = reg & (~BIT(2)); + } + + /* Read command register */ + outb_p(reg, ASFDATABNKSEL); + cmd = inb_p(ASFINDEX); + len = inb_p(ASFDATARWPTR); + for (i = 0; i < len; i++) + data[i] = inb_p(ASFINDEX); + + /* Clear data bank status */ + if (bank) { + reg = reg | BIT(3); + outb_p(reg, ASFDATABNKSEL); + } else { + reg = reg | BIT(2); + outb_p(reg, ASFDATABNKSEL); + } + } else { + /* Set bank as full */ + reg = reg | (BIT(3) | BIT(2)); + outb_p(reg, ASFDATABNKSEL); + } + + outb_p(0, ASFSETDATARDPTR); + if (!(cmd & BIT(0))) { + i2c_slave_event(adapdata->slave, I2C_SLAVE_WRITE_REQUESTED, &val); + for (i = 0; i < len; i++) { + val = data[i]; + i2c_slave_event(adapdata->slave, I2C_SLAVE_WRITE_RECEIVED, &val); + } + i2c_slave_event(adapdata->slave, I2C_SLAVE_STOP, &val); + } +} + static void sb800_asf_update_bits(unsigned short piix4_smba, u8 bit, unsigned long offset, bool set) { unsigned long reg; @@ -1195,6 +1267,88 @@ static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba, return 0; } +static irqreturn_t sb800_asf_irq_handler(int irq, void *ptr) +{ + struct i2c_piix4_adapdata *adapdata = (struct i2c_piix4_adapdata *)ptr; + unsigned short piix4_smba = adapdata->smba; + u8 slave_int = inb_p(ASFSTA); + + if ((slave_int & BIT(6))) { + /* Slave Interrupt */ + outb_p(slave_int | BIT(6), ASFSTA); + schedule_delayed_work(&adapdata->work_buf, HZ); + } else { + /* Master Interrupt */ + sb800_asf_update_bits(piix4_smba, SB800_ASF_SLV_INTR, SMBHSTSTS, true); + } + + return IRQ_HANDLED; +} + +static int sb800_asf_acpi_resource_cb(struct acpi_resource *resource, void *context) +{ + struct sb800_asf_data *data = context; + + switch (resource->type) { + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + data->irq = resource->data.extended_irq.interrupts[0]; + break; + case ACPI_RESOURCE_TYPE_IO: + data->addr = resource->data.io.minimum; + break; + } + + return 0; +} + +static int sb800_asf_add_adap(struct pci_dev *dev) +{ + struct i2c_piix4_adapdata *adapdata; + struct sb800_asf_data data; + struct acpi_device *adev; + LIST_HEAD(res_list); + acpi_status status; + acpi_handle handle; + int ret; + + status = acpi_get_handle(NULL, SB800_ASF_ACPI_PATH, &handle); + if (ACPI_FAILURE(status)) + return -ENODEV; + + adev = acpi_fetch_acpi_dev(handle); + if (!adev) + return -ENODEV; + + ret = acpi_dev_get_resources(adev, &res_list, sb800_asf_acpi_resource_cb, &data); + if (ret < 0) { + dev_err(&dev->dev, "Error getting ASF ACPI resource: %d\n", ret); + return ret; + } + + acpi_dev_free_resource_list(&res_list); + ret = piix4_add_adapter(dev, data.addr, SMBUS_ASF, piix4_adapter_count, false, 0, + piix4_main_port_names_sb800[piix4_adapter_count], + &piix4_main_adapters[piix4_adapter_count]); + if (ret) { + dev_err(&dev->dev, "Failed to add ASF adapter: %d\n", ret); + return -ENODEV; + } + + adapdata = i2c_get_adapdata(piix4_main_adapters[piix4_adapter_count]); + ret = devm_request_irq(&dev->dev, data.irq, sb800_asf_irq_handler, IRQF_SHARED, + "sb800_smbus_asf", adapdata); + if (ret) { + dev_err(&dev->dev, "Unable to request irq: %d for use\n", data.irq); + return ret; + } + + INIT_DELAYED_WORK(&adapdata->work_buf, sb800_asf_process_slave); + adapdata->is_asf = true; + /* Increment the adapter count by 1 as ASF is added to the list */ + piix4_adapter_count += 1; + return 1; +} + static int piix4_add_adapters_sb800(struct pci_dev *dev, unsigned short smba, bool notify_imc) { @@ -1243,6 +1397,7 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) { int retval; bool is_sb800 = false; + bool is_asf = false; if ((dev->vendor == PCI_VENDOR_ID_ATI && dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS && @@ -1279,6 +1434,10 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) retval = piix4_add_adapters_sb800(dev, retval, notify_imc); if (retval < 0) return retval; + + /* Check if ASF is enabled in SB800 */ + if (sb800_asf_add_adap(dev)) + is_asf = true; } else { retval = piix4_setup(dev, id); if (retval < 0) @@ -1308,7 +1467,9 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) if (dev->vendor == PCI_VENDOR_ID_AMD && (dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS || dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS)) { - retval = piix4_setup_sb800(dev, id, 1); + /* Do not setup AUX port if ASF is enabled */ + if (!is_asf) + retval = piix4_setup_sb800(dev, id, 1); } if (retval > 0) { @@ -1326,6 +1487,9 @@ static void piix4_adap_remove(struct i2c_adapter *adap) { struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap); + if (adapdata->is_asf) + cancel_delayed_work_sync(&adapdata->work_buf); + if (adapdata->smba) { i2c_del_adapter(adap); if (adapdata->port == (0 << piix4_port_shift_sb800))