From: Jordan Crouse On the CS5535 and CS5536, the I/O resource is allocated through PCI, so use that instead of using the MSR backdoor. Signed-off-by: Jordan Crouse Cc: Jean Delvare Cc: Greg KH Signed-off-by: Andrew Morton --- drivers/i2c/busses/scx200_acb.c | 111 ++++++++++++++++++++---------- 1 files changed, 75 insertions(+), 36 deletions(-) diff -puN drivers/i2c/busses/scx200_acb.c~scx200_acb-use-pci-i-o-resource-when-appropriate drivers/i2c/busses/scx200_acb.c --- devel/drivers/i2c/busses/scx200_acb.c~scx200_acb-use-pci-i-o-resource-when-appropriate 2006-05-02 00:08:31.000000000 -0700 +++ devel-akpm/drivers/i2c/busses/scx200_acb.c 2006-05-02 00:09:23.000000000 -0700 @@ -33,7 +33,6 @@ #include #include #include -#include #include @@ -85,6 +84,10 @@ struct scx200_acb_iface { u8 *ptr; char needs_reset; unsigned len; + + /* PCI device info */ + struct pci_dev *pdev; + int bar; }; /* Register Definitions */ @@ -417,7 +420,8 @@ static int scx200_acb_probe(struct scx20 return 0; } -static int __init scx200_acb_create(const char *text, int base, int index) +static int __init scx200_acb_create(char *text, unsigned int base, int index, + struct pci_dev *pdev, int bar) { struct scx200_acb_iface *iface; struct i2c_adapter *adapter; @@ -440,13 +444,28 @@ static int __init scx200_acb_create(con mutex_init(&iface->mutex); - if (!request_region(base, 8, adapter->name)) { - printk(KERN_ERR NAME ": can't allocate io 0x%x-0x%x\n", - base, base + 8-1); - rc = -EBUSY; - goto errout_free; + if (pdev != NULL) { + iface->pdev = pdev; + iface->bar = bar; + + pci_enable_device_bars(iface->pdev, 1 << iface->bar); + + if (pci_request_region(iface->pdev, iface->bar, description)) { + printk(KERN_ERR NAME ": can't allocate PCI region %d\n", + iface->bar); + rc = -EBUSY; + goto errout_free; + } + iface->base = pci_resource_start(iface->pdev, iface->bar); + } else { + if (request_region(base, 8, description) == 0) { + printk(KERN_ERR NAME ": can't allocate io 0x%x-0x%x\n", + base, base + 8 - 1); + rc = -EBUSY; + goto errout_free; + } + iface->base = base; } - iface->base = base; rc = scx200_acb_probe(iface); if (rc) { @@ -470,7 +489,11 @@ static int __init scx200_acb_create(con return 0; errout_release: - release_region(iface->base, 8); + if (iface->pdev != NULL) + pci_release_region(iface->pdev, iface->bar); + else + release_region(iface->base, 8); + errout_free: kfree(iface); errout: @@ -483,49 +506,60 @@ static struct pci_device_id scx200[] = { { }, }; -static struct pci_device_id divil_pci[] = { - { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) }, - { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) }, - { } /* NULL entry */ +/* On the CS5535 and CS5536, the SMBUS I/0 base is a PCI resource, so + we should allocate that resource through the PCI + subsystem. rather then going through the MSR back door. +*/ + +static struct { + unsigned int vendor; + unsigned int device; + char *name; + int bar; +} divil_pci[] = { + { + PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA, "CS5535", 0}, { + PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA, "CS5536", 0} }; -#define MSR_LBAR_SMB 0x5140000B +#define DIVIL_LENGTH (sizeof(divil_pci) / sizeof(divil_pci[0])) static int scx200_add_cs553x(void) { - u32 low, hi; - u32 smb_base; - - /* Grab & reserve the SMB I/O range */ - rdmsr(MSR_LBAR_SMB, low, hi); + int dev; + struct pci_dev *pdev; - /* Check the IO mask and whether SMB is enabled */ - if (hi != 0x0000F001) { - printk(KERN_WARNING NAME ": SMBus not enabled\n"); - return -ENODEV; + for (dev = 0; dev < DIVIL_LENGTH; dev++) { + pdev = + pci_find_device(divil_pci[dev].vendor, + divil_pci[dev].device, NULL); + if (pdev != NULL) + break; } - /* SMBus IO size is 8 bytes */ - smb_base = low & 0x0000FFF8; + if (pdev == NULL) + return -ENODEV; - return scx200_acb_create("CS5535", smb_base, 0); + return scx200_acb_create(divil_pci[dev].name, 0, 0, pdev, + divil_pci[dev].bar); } static int __init scx200_acb_init(void) { int i; - int rc = -ENODEV; + int rc = -ENODEV; pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n"); - /* Verify that this really is a SCx200 processor */ - if (pci_dev_present(scx200)) { - for (i = 0; i < MAX_DEVICES; ++i) { - if (base[i] > 0) - rc = scx200_acb_create("SCx200", base[i], i); - } - } else if (pci_dev_present(divil_pci)) - rc = scx200_add_cs553x(); + /* If this is a CS5535 or CS5536, then probe the PCI header */ + + if (!pci_dev_present(scx200)) + return scx200_add_cs553x(); + + for (i = 0; i < MAX_DEVICES; ++i) { + if (base[i] > 0) + rc = scx200_acb_create("SCx200", base[i], i, NULL, 0); + } /* If at least one bus was created, init must succeed */ if (scx200_acb_list) @@ -543,7 +577,12 @@ static void __exit scx200_acb_cleanup(vo up(&scx200_acb_list_mutex); i2c_del_adapter(&iface->adapter); - release_region(iface->base, 8); + + if (iface->pdev != NULL) + pci_release_region(iface->pdev, iface->bar); + else + release_region(iface->base, 8); + kfree(iface); down(&scx200_acb_list_mutex); } _