Commit 80cd3a87 authored by Jordan Crouse's avatar Jordan Crouse Committed by Greg Kroah-Hartman

[PATCH] scx200_acb: Use PCI I/O resource when appropriate

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: default avatarJordan Crouse <jordan.crouse@amd.com>
Signed-off-by: default avatarJean Delvare <khali@linux-fr.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 46f5ed75
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/msr.h>
#include <linux/scx200.h> #include <linux/scx200.h>
...@@ -85,6 +84,10 @@ struct scx200_acb_iface { ...@@ -85,6 +84,10 @@ struct scx200_acb_iface {
u8 *ptr; u8 *ptr;
char needs_reset; char needs_reset;
unsigned len; unsigned len;
/* PCI device info */
struct pci_dev *pdev;
int bar;
}; };
/* Register Definitions */ /* Register Definitions */
...@@ -417,17 +420,16 @@ static int scx200_acb_probe(struct scx200_acb_iface *iface) ...@@ -417,17 +420,16 @@ static int scx200_acb_probe(struct scx200_acb_iface *iface)
return 0; return 0;
} }
static int __init scx200_acb_create(const char *text, int base, int index) static __init struct scx200_acb_iface *scx200_create_iface(const char *text,
int index)
{ {
struct scx200_acb_iface *iface; struct scx200_acb_iface *iface;
struct i2c_adapter *adapter; struct i2c_adapter *adapter;
int rc;
iface = kzalloc(sizeof(*iface), GFP_KERNEL); iface = kzalloc(sizeof(*iface), GFP_KERNEL);
if (!iface) { if (!iface) {
printk(KERN_ERR NAME ": can't allocate memory\n"); printk(KERN_ERR NAME ": can't allocate memory\n");
rc = -ENOMEM; return NULL;
goto errout;
} }
adapter = &iface->adapter; adapter = &iface->adapter;
...@@ -440,26 +442,27 @@ static int __init scx200_acb_create(const char *text, int base, int index) ...@@ -440,26 +442,27 @@ static int __init scx200_acb_create(const char *text, int base, int index)
mutex_init(&iface->mutex); mutex_init(&iface->mutex);
if (!request_region(base, 8, adapter->name)) { return iface;
printk(KERN_ERR NAME ": can't allocate io 0x%x-0x%x\n", }
base, base + 8-1);
rc = -EBUSY; static int __init scx200_acb_create(struct scx200_acb_iface *iface)
goto errout_free; {
} struct i2c_adapter *adapter;
iface->base = base; int rc;
adapter = &iface->adapter;
rc = scx200_acb_probe(iface); rc = scx200_acb_probe(iface);
if (rc) { if (rc) {
printk(KERN_WARNING NAME ": probe failed\n"); printk(KERN_WARNING NAME ": probe failed\n");
goto errout_release; return rc;
} }
scx200_acb_reset(iface); scx200_acb_reset(iface);
if (i2c_add_adapter(adapter) < 0) { if (i2c_add_adapter(adapter) < 0) {
printk(KERN_ERR NAME ": failed to register\n"); printk(KERN_ERR NAME ": failed to register\n");
rc = -ENODEV; return -ENODEV;
goto errout_release;
} }
down(&scx200_acb_list_mutex); down(&scx200_acb_list_mutex);
...@@ -468,64 +471,148 @@ static int __init scx200_acb_create(const char *text, int base, int index) ...@@ -468,64 +471,148 @@ static int __init scx200_acb_create(const char *text, int base, int index)
up(&scx200_acb_list_mutex); up(&scx200_acb_list_mutex);
return 0; return 0;
}
errout_release: static __init int scx200_create_pci(const char *text, struct pci_dev *pdev,
release_region(iface->base, 8); int bar)
{
struct scx200_acb_iface *iface;
int rc;
iface = scx200_create_iface(text, 0);
if (iface == NULL)
return -ENOMEM;
iface->pdev = pdev;
iface->bar = bar;
pci_enable_device_bars(iface->pdev, 1 << iface->bar);
rc = pci_request_region(iface->pdev, iface->bar, iface->adapter.name);
if (rc != 0) {
printk(KERN_ERR NAME ": can't allocate PCI BAR %d\n",
iface->bar);
goto errout_free;
}
iface->base = pci_resource_start(iface->pdev, iface->bar);
rc = scx200_acb_create(iface);
if (rc == 0)
return 0;
pci_release_region(iface->pdev, iface->bar);
pci_dev_put(iface->pdev);
errout_free: errout_free:
kfree(iface); kfree(iface);
errout:
return rc; return rc;
} }
static struct pci_device_id scx200[] = { static int __init scx200_create_isa(const char *text, unsigned long base,
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) }, int index)
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) }, {
{ }, struct scx200_acb_iface *iface;
}; int rc;
iface = scx200_create_iface(text, index);
if (iface == NULL)
return -ENOMEM;
if (request_region(base, 8, iface->adapter.name) == 0) {
printk(KERN_ERR NAME ": can't allocate io 0x%lx-0x%lx\n",
base, base + 8 - 1);
rc = -EBUSY;
goto errout_free;
}
iface->base = base;
rc = scx200_acb_create(iface);
if (rc == 0)
return 0;
static struct pci_device_id divil_pci[] = { release_region(base, 8);
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA) }, errout_free:
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA) }, kfree(iface);
{ } /* NULL entry */ return rc;
}
/* Driver data is an index into the scx200_data array that indicates
* the name and the BAR where the I/O address resource is located. ISA
* devices are flagged with a bar value of -1 */
static struct pci_device_id scx200_pci[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE),
.driver_data = 0 },
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE),
.driver_data = 0 },
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA),
.driver_data = 1 },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA),
.driver_data = 2 }
}; };
#define MSR_LBAR_SMB 0x5140000B static struct {
const char *name;
int bar;
} scx200_data[] = {
{ "SCx200", -1 },
{ "CS5535", 0 },
{ "CS5536", 0 }
};
static __init int scx200_add_cs553x(void) static __init int scx200_scan_pci(void)
{ {
u32 low, hi; int data, dev;
u32 smb_base; int rc = -ENODEV;
struct pci_dev *pdev;
/* Grab & reserve the SMB I/O range */
rdmsr(MSR_LBAR_SMB, low, hi); for(dev = 0; dev < ARRAY_SIZE(scx200_pci); dev++) {
pdev = pci_get_device(scx200_pci[dev].vendor,
scx200_pci[dev].device, NULL);
if (pdev == NULL)
continue;
data = scx200_pci[dev].driver_data;
/* if .bar is greater or equal to zero, this is a
* PCI device - otherwise, we assume
that the ports are ISA based
*/
if (scx200_data[data].bar >= 0)
rc = scx200_create_pci(scx200_data[data].name, pdev,
scx200_data[data].bar);
else {
int i;
for (i = 0; i < MAX_DEVICES; ++i) {
if (base[i] == 0)
continue;
rc = scx200_create_isa(scx200_data[data].name,
base[i],
i);
}
}
/* Check the IO mask and whether SMB is enabled */ break;
if (hi != 0x0000F001) {
printk(KERN_WARNING NAME ": SMBus not enabled\n");
return -ENODEV;
} }
/* SMBus IO size is 8 bytes */ return rc;
smb_base = low & 0x0000FFF8;
return scx200_acb_create("CS5535", smb_base, 0);
} }
static int __init scx200_acb_init(void) static int __init scx200_acb_init(void)
{ {
int i; int rc;
int rc = -ENODEV;
pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n"); pr_debug(NAME ": NatSemi SCx200 ACCESS.bus Driver\n");
/* Verify that this really is a SCx200 processor */ rc = scx200_scan_pci();
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 at least one bus was created, init must succeed */ /* If at least one bus was created, init must succeed */
if (scx200_acb_list) if (scx200_acb_list)
...@@ -543,7 +630,14 @@ static void __exit scx200_acb_cleanup(void) ...@@ -543,7 +630,14 @@ static void __exit scx200_acb_cleanup(void)
up(&scx200_acb_list_mutex); up(&scx200_acb_list_mutex);
i2c_del_adapter(&iface->adapter); i2c_del_adapter(&iface->adapter);
release_region(iface->base, 8);
if (iface->pdev) {
pci_release_region(iface->pdev, iface->bar);
pci_dev_put(iface->pdev);
}
else
release_region(iface->base, 8);
kfree(iface); kfree(iface);
down(&scx200_acb_list_mutex); down(&scx200_acb_list_mutex);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment