ppc32: Update macio_asic, add some resource management

parent f3f367c3
...@@ -23,10 +23,13 @@ ...@@ -23,10 +23,13 @@
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/pci-bridge.h> #include <asm/pci-bridge.h>
#define DEBUG
#define MAX_NODE_NAME_SIZE (BUS_ID_SIZE - 12)
static struct macio_chip *macio_on_hold; static struct macio_chip *macio_on_hold;
static int static int macio_bus_match(struct device *dev, struct device_driver *drv)
macio_bus_match(struct device *dev, struct device_driver *drv)
{ {
struct macio_dev * macio_dev = to_macio_device(dev); struct macio_dev * macio_dev = to_macio_device(dev);
struct macio_driver * macio_drv = to_macio_driver(drv); struct macio_driver * macio_drv = to_macio_driver(drv);
...@@ -85,41 +88,42 @@ static int macio_device_probe(struct device *dev) ...@@ -85,41 +88,42 @@ static int macio_device_probe(struct device *dev)
static int macio_device_remove(struct device *dev) static int macio_device_remove(struct device *dev)
{ {
struct macio_dev * macio_dev = to_macio_device(dev); struct macio_dev * macio_dev = to_macio_device(dev);
struct macio_driver * drv = to_macio_driver(macio_dev->ofdev.dev.driver); struct macio_driver * drv = to_macio_driver(dev->driver);
if (drv && drv->remove) if (dev->driver && drv->remove)
drv->remove(macio_dev); drv->remove(macio_dev);
macio_dev_put(macio_dev); macio_dev_put(macio_dev);
return 0; return 0;
} }
static void macio_device_shutdown(struct device *dev)
{
struct macio_dev * macio_dev = to_macio_device(dev);
struct macio_driver * drv = to_macio_driver(dev->driver);
if (dev->driver && drv->shutdown)
drv->shutdown(macio_dev);
}
static int macio_device_suspend(struct device *dev, u32 state) static int macio_device_suspend(struct device *dev, u32 state)
{ {
struct macio_dev * macio_dev = to_macio_device(dev); struct macio_dev * macio_dev = to_macio_device(dev);
struct macio_driver * drv; struct macio_driver * drv = to_macio_driver(dev->driver);
int error = 0;
if (macio_dev->ofdev.dev.driver == NULL) if (dev->driver && drv->suspend)
return drv->suspend(macio_dev, state);
return 0; return 0;
drv = to_macio_driver(macio_dev->ofdev.dev.driver);
if (drv->suspend)
error = drv->suspend(macio_dev, state);
return error;
} }
static int macio_device_resume(struct device * dev) static int macio_device_resume(struct device * dev)
{ {
struct macio_dev * macio_dev = to_macio_device(dev); struct macio_dev * macio_dev = to_macio_device(dev);
struct macio_driver * drv; struct macio_driver * drv = to_macio_driver(dev->driver);
int error = 0;
if (macio_dev->ofdev.dev.driver == NULL) if (dev->driver && drv->resume)
return drv->resume(macio_dev);
return 0; return 0;
drv = to_macio_driver(macio_dev->ofdev.dev.driver);
if (drv->resume)
error = drv->resume(macio_dev);
return error;
} }
struct bus_type macio_bus_type = { struct bus_type macio_bus_type = {
...@@ -129,8 +133,7 @@ struct bus_type macio_bus_type = { ...@@ -129,8 +133,7 @@ struct bus_type macio_bus_type = {
.resume = macio_device_resume, .resume = macio_device_resume,
}; };
static int __init static int __init macio_bus_driver_init(void)
macio_bus_driver_init(void)
{ {
return bus_register(&macio_bus_type); return bus_register(&macio_bus_type);
} }
...@@ -154,6 +157,58 @@ static void macio_release_dev(struct device *dev) ...@@ -154,6 +157,58 @@ static void macio_release_dev(struct device *dev)
kfree(mdev); kfree(mdev);
} }
/**
* macio_resource_quirks - tweak or skip some resources for a device
* @np: pointer to the device node
* @res: resulting resource
* @index: index of resource in node
*
* If this routine returns non-null, then the resource is completely
* skipped.
*/
static int macio_resource_quirks(struct device_node *np, struct resource *res, int index)
{
if (res->flags & IORESOURCE_MEM) {
/* Grand Central has too large resource 0 on some machines */
if (index == 0 && !strcmp(np->name, "gc")) {
np->addrs[0].size = 0x20000;
res->end = res->start + 0x1ffff;
}
/* Airport has bogus resource 2 */
if (index >= 2 && !strcmp(np->name, "radio"))
return 1;
/* DBDMAs may have bogus sizes */
if ((res->start & 0x0001f000) == 0x00008000) {
np->addrs[index].size = 0x100;
res->end = res->start + 0xff;
}
/* ESCC parent eats child resources. We could have added a level of hierarchy,
* but I don't really feel the need for it */
if (!strcmp(np->name, "escc"))
return 1;
/* ESCC has bogus resources >= 3 */
if (index >= 3 && !(strcmp(np->name, "ch-a") && strcmp(np->name, "ch-b")))
return 1;
/* Media bay has too many resources, keep only first one */
if (index > 0 && !strcmp(np->name, "media-bay"))
return 1;
/* Some older IDE resources have bogus sizes */
if (!(strcmp(np->name, "IDE") && strcmp(np->name, "ATA") &&
strcmp(np->type, "ide") && strcmp(np->type, "ata"))) {
if (index == 0 && np->addrs[0].size > 0x1000) {
np->addrs[0].size = 0x1000;
res->end = res->start + 0xfff;
}
if (index == 1 && np->addrs[1].size > 0x100) {
np->addrs[1].size = 0x100;
res->end = res->start + 0xff;
}
}
}
return 0;
}
/** /**
* macio_add_one_device - Add one device from OF node to the device tree * macio_add_one_device - Add one device from OF node to the device tree
* @chip: pointer to the macio_chip holding the device * @chip: pointer to the macio_chip holding the device
...@@ -164,9 +219,11 @@ static void macio_release_dev(struct device *dev) ...@@ -164,9 +219,11 @@ static void macio_release_dev(struct device *dev)
* be exposed to the bay driver some way... * be exposed to the bay driver some way...
*/ */
static struct macio_dev * macio_add_one_device(struct macio_chip *chip, struct device *parent, static struct macio_dev * macio_add_one_device(struct macio_chip *chip, struct device *parent,
struct device_node *np, struct macio_dev *in_bay) struct device_node *np, struct macio_dev *in_bay,
struct resource *parent_res)
{ {
struct macio_dev *dev; struct macio_dev *dev;
int i, j;
u32 *reg; u32 *reg;
if (np == NULL) if (np == NULL)
...@@ -186,22 +243,76 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip, struct d ...@@ -186,22 +243,76 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip, struct d
dev->ofdev.dev.bus = &macio_bus_type; dev->ofdev.dev.bus = &macio_bus_type;
dev->ofdev.dev.release = macio_release_dev; dev->ofdev.dev.release = macio_release_dev;
#ifdef DEBUG
printk("preparing mdev @%p, ofdev @%p, dev @%p, kobj @%p\n",
dev, &dev->ofdev, &dev->ofdev.dev, &dev->ofdev.dev.kobj);
#endif
/* MacIO itself has a different reg, we use it's PCI base */ /* MacIO itself has a different reg, we use it's PCI base */
if (np == chip->of_node) { if (np == chip->of_node) {
sprintf(dev->ofdev.dev.bus_id, "%1d.%08lx:%.8s", chip->lbus.index, sprintf(dev->ofdev.dev.bus_id, "%1d.%08lx:%.*s", chip->lbus.index,
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
pci_resource_start(chip->lbus.pdev, 0), pci_resource_start(chip->lbus.pdev, 0),
#else #else
0, /* NuBus may want to do something better here */ 0, /* NuBus may want to do something better here */
#endif #endif
np->name); MAX_NODE_NAME_SIZE, np->name);
} else { } else {
reg = (u32 *)get_property(np, "reg", NULL); reg = (u32 *)get_property(np, "reg", NULL);
sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.8s", chip->lbus.index, sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.*s", chip->lbus.index,
reg ? *reg : 0, np->name); reg ? *reg : 0, MAX_NODE_NAME_SIZE, np->name);
} }
/* For now, we use pre-parsed entries in the device-tree for
* interrupt routing and addresses, but we should change that
* to dynamically parsed entries and so get rid of most of the
* clutter in struct device_node
*/
for (i = j = 0; i < np->n_intrs; i++) {
struct resource *res = &dev->interrupt[j];
if (j >= MACIO_DEV_COUNT_IRQS)
break;
res->start = np->intrs[i].line;
res->flags = IORESOURCE_IO;
if (np->intrs[j].sense)
res->flags |= IORESOURCE_IRQ_LOWLEVEL;
else
res->flags |= IORESOURCE_IRQ_HIGHEDGE;
res->name = dev->ofdev.dev.bus_id;
if (macio_resource_quirks(np, res, i))
memset(res, 0, sizeof(struct resource));
else
j++;
}
dev->n_interrupts = j;
for (i = j = 0; i < np->n_addrs; i++) {
struct resource *res = &dev->resource[j];
if (j >= MACIO_DEV_COUNT_RESOURCES)
break;
res->start = np->addrs[i].address;
res->end = np->addrs[i].address + np->addrs[i].size - 1;
res->flags = IORESOURCE_MEM;
res->name = dev->ofdev.dev.bus_id;
if (macio_resource_quirks(np, res, i))
memset(res, 0, sizeof(struct resource));
else {
j++;
/* Currently, we consider failure as harmless, this may
* change in the future, once I've found all the device
* tree bugs in older machines & worked around them
*/
if (insert_resource(parent_res, res))
printk(KERN_WARNING "Can't request resource %d for MacIO"
" device %s\n", i, dev->ofdev.dev.bus_id);
}
}
dev->n_resources = j;
if (of_device_register(&dev->ofdev) != 0) { if (of_device_register(&dev->ofdev) != 0) {
printk(KERN_DEBUG"macio: device registration error for %s!\n",
dev->ofdev.dev.bus_id);
kfree(dev); kfree(dev);
return NULL; return NULL;
} }
...@@ -234,25 +345,30 @@ static void macio_pci_add_devices(struct macio_chip *chip) ...@@ -234,25 +345,30 @@ static void macio_pci_add_devices(struct macio_chip *chip)
struct device_node *np, *pnode; struct device_node *np, *pnode;
struct macio_dev *rdev, *mdev, *mbdev = NULL, *sdev = NULL; struct macio_dev *rdev, *mdev, *mbdev = NULL, *sdev = NULL;
struct device *parent = NULL; struct device *parent = NULL;
struct resource *root_res = &iomem_resource;
/* Add a node for the macio bus itself */ /* Add a node for the macio bus itself */
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
if (chip->lbus.pdev) if (chip->lbus.pdev) {
parent = &chip->lbus.pdev->dev; parent = &chip->lbus.pdev->dev;
root_res = &chip->lbus.pdev->resource[0];
}
#endif #endif
pnode = of_node_get(chip->of_node); pnode = of_node_get(chip->of_node);
if (pnode == NULL) if (pnode == NULL)
return; return;
rdev = macio_add_one_device(chip, parent, pnode, NULL); /* Add macio itself to hierarchy */
rdev = macio_add_one_device(chip, parent, pnode, NULL, root_res);
if (rdev == NULL) if (rdev == NULL)
return; return;
root_res = &rdev->resource[0];
/* First scan 1st level */ /* First scan 1st level */
for (np = NULL; (np = of_get_next_child(pnode, np)) != NULL;) { for (np = NULL; (np = of_get_next_child(pnode, np)) != NULL;) {
if (!macio_skip_device(np)) { if (!macio_skip_device(np)) {
of_node_get(np); of_node_get(np);
mdev = macio_add_one_device(chip, &rdev->ofdev.dev, np, NULL); mdev = macio_add_one_device(chip, &rdev->ofdev.dev, np, NULL, root_res);
if (mdev == NULL) if (mdev == NULL)
of_node_put(np); of_node_put(np);
else if (strncmp(np->name, "media-bay", 9) == 0) else if (strncmp(np->name, "media-bay", 9) == 0)
...@@ -267,17 +383,20 @@ static void macio_pci_add_devices(struct macio_chip *chip) ...@@ -267,17 +383,20 @@ static void macio_pci_add_devices(struct macio_chip *chip)
for (np = NULL; (np = of_get_next_child(mbdev->ofdev.node, np)) != NULL;) for (np = NULL; (np = of_get_next_child(mbdev->ofdev.node, np)) != NULL;)
if (!macio_skip_device(np)) { if (!macio_skip_device(np)) {
of_node_get(np); of_node_get(np);
if (macio_add_one_device(chip, &mbdev->ofdev.dev, np, mbdev) == NULL) if (macio_add_one_device(chip, &mbdev->ofdev.dev, np, mbdev,
root_res) == NULL)
of_node_put(np); of_node_put(np);
} }
/* Add serial ports if any */ /* Add serial ports if any */
if (sdev) if (sdev) {
for (np = NULL; (np = of_get_next_child(sdev->ofdev.node, np)) != NULL;) for (np = NULL; (np = of_get_next_child(sdev->ofdev.node, np)) != NULL;)
if (!macio_skip_device(np)) { if (!macio_skip_device(np)) {
of_node_get(np); of_node_get(np);
if (macio_add_one_device(chip, &sdev->ofdev.dev, np, NULL) == NULL) if (macio_add_one_device(chip, &sdev->ofdev.dev, np, NULL,
root_res) == NULL)
of_node_put(np); of_node_put(np);
} }
}
} }
...@@ -294,6 +413,7 @@ int macio_register_driver(struct macio_driver *drv) ...@@ -294,6 +413,7 @@ int macio_register_driver(struct macio_driver *drv)
drv->driver.bus = &macio_bus_type; drv->driver.bus = &macio_bus_type;
drv->driver.probe = macio_device_probe; drv->driver.probe = macio_device_probe;
drv->driver.remove = macio_device_remove; drv->driver.remove = macio_device_remove;
drv->driver.shutdown = macio_device_shutdown;
/* register with core */ /* register with core */
count = driver_register(&drv->driver); count = driver_register(&drv->driver);
...@@ -309,6 +429,97 @@ void macio_unregister_driver(struct macio_driver *drv) ...@@ -309,6 +429,97 @@ void macio_unregister_driver(struct macio_driver *drv)
driver_unregister(&drv->driver); driver_unregister(&drv->driver);
} }
/**
* macio_request_resource - Request an MMIO resource
* @dev: pointer to the device holding the resource
* @resource_no: resource number to request
* @name: resource name
*
* Mark memory region number @resource_no associated with MacIO
* device @dev as being reserved by owner @name. Do not access
* any address inside the memory regions unless this call returns
* successfully.
*
* Returns 0 on success, or %EBUSY on error. A warning
* message is also printed on failure.
*/
int macio_request_resource(struct macio_dev *dev, int resource_no, const char *name)
{
if (macio_resource_len(dev, resource_no) == 0)
return 0;
if (!request_mem_region(macio_resource_start(dev, resource_no),
macio_resource_len(dev, resource_no),
name))
goto err_out;
return 0;
err_out:
printk (KERN_WARNING "MacIO: Unable to reserve resource #%d:%lx@%lx"
" for device %s\n",
resource_no,
macio_resource_len(dev, resource_no),
macio_resource_start(dev, resource_no),
dev->ofdev.dev.bus_id);
return -EBUSY;
}
/**
* macio_release_resource - Release an MMIO resource
* @dev: pointer to the device holding the resource
* @resource_no: resource number to release
*/
void macio_release_resource(struct macio_dev *dev, int resource_no)
{
if (macio_resource_len(dev, resource_no) == 0)
return;
release_mem_region(macio_resource_start(dev, resource_no),
macio_resource_len(dev, resource_no));
}
/**
* macio_request_resources - Reserve all memory resources
* @dev: MacIO device whose resources are to be reserved
* @name: Name to be associated with resource.
*
* Mark all memory regions associated with MacIO device @dev as
* being reserved by owner @name. Do not access any address inside
* the memory regions unless this call returns successfully.
*
* Returns 0 on success, or %EBUSY on error. A warning
* message is also printed on failure.
*/
int macio_request_resources(struct macio_dev *dev, const char *name)
{
int i;
for (i = 0; i < dev->n_resources; i++)
if (macio_request_resource(dev, i, name))
goto err_out;
return 0;
err_out:
while(--i >= 0)
macio_release_resource(dev, i);
return -EBUSY;
}
/**
* macio_release_resources - Release reserved memory resources
* @dev: MacIO device whose resources were previously reserved
*/
void macio_release_resources(struct macio_dev *dev)
{
int i;
for (i = 0; i < dev->n_resources; i++)
macio_release_resource(dev, i);
}
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
static int __devinit macio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) static int __devinit macio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
...@@ -416,3 +627,7 @@ EXPORT_SYMBOL(macio_register_driver); ...@@ -416,3 +627,7 @@ EXPORT_SYMBOL(macio_register_driver);
EXPORT_SYMBOL(macio_unregister_driver); EXPORT_SYMBOL(macio_unregister_driver);
EXPORT_SYMBOL(macio_dev_get); EXPORT_SYMBOL(macio_dev_get);
EXPORT_SYMBOL(macio_dev_put); EXPORT_SYMBOL(macio_dev_put);
EXPORT_SYMBOL(macio_request_resource);
EXPORT_SYMBOL(macio_release_resource);
EXPORT_SYMBOL(macio_request_resources);
EXPORT_SYMBOL(macio_release_resources);
...@@ -9,7 +9,7 @@ extern struct bus_type macio_bus_type; ...@@ -9,7 +9,7 @@ extern struct bus_type macio_bus_type;
struct macio_driver; struct macio_driver;
struct macio_chip; struct macio_chip;
#define MACIO_DEV_COUNT_RESOURCE 8 #define MACIO_DEV_COUNT_RESOURCES 8
#define MACIO_DEV_COUNT_IRQS 8 #define MACIO_DEV_COUNT_IRQS 8
/* /*
...@@ -38,6 +38,10 @@ struct macio_dev ...@@ -38,6 +38,10 @@ struct macio_dev
struct macio_bus *bus; /* macio bus this device is on */ struct macio_bus *bus; /* macio bus this device is on */
struct macio_dev *media_bay; /* Device is part of a media bay */ struct macio_dev *media_bay; /* Device is part of a media bay */
struct of_device ofdev; struct of_device ofdev;
int n_resources;
struct resource resource[MACIO_DEV_COUNT_RESOURCES];
int n_interrupts;
struct resource interrupt[MACIO_DEV_COUNT_IRQS];
}; };
#define to_macio_device(d) container_of(d, struct macio_dev, ofdev.dev) #define to_macio_device(d) container_of(d, struct macio_dev, ofdev.dev)
#define of_to_macio_device(d) container_of(d, struct macio_dev, ofdev) #define of_to_macio_device(d) container_of(d, struct macio_dev, ofdev)
...@@ -45,6 +49,71 @@ struct macio_dev ...@@ -45,6 +49,71 @@ struct macio_dev
extern struct macio_dev *macio_dev_get(struct macio_dev *dev); extern struct macio_dev *macio_dev_get(struct macio_dev *dev);
extern void macio_dev_put(struct macio_dev *dev); extern void macio_dev_put(struct macio_dev *dev);
/*
* Accessors to resources & interrupts and other device
* fields
*/
static inline int macio_resource_count(struct macio_dev *dev)
{
return dev->n_resources;
}
static inline unsigned long macio_resource_start(struct macio_dev *dev, int resource_no)
{
return dev->resource[resource_no].start;
}
static inline unsigned long macio_resource_end(struct macio_dev *dev, int resource_no)
{
return dev->resource[resource_no].end;
}
static inline unsigned long macio_resource_len(struct macio_dev *dev, int resource_no)
{
struct resource *res = &dev->resource[resource_no];
if (res->start == 0 || res->end == 0 || res->end < res->start)
return 0;
return res->end - res->start + 1;
}
extern int macio_request_resource(struct macio_dev *dev, int resource_no, const char *name);
extern void macio_release_resource(struct macio_dev *dev, int resource_no);
extern int macio_request_resources(struct macio_dev *dev, const char *name);
extern void macio_release_resources(struct macio_dev *dev);
static inline int macio_irq_count(struct macio_dev *dev)
{
return dev->n_interrupts;
}
static inline int macio_irq(struct macio_dev *dev, int irq_no)
{
return dev->interrupt[irq_no].start;
}
static inline void macio_set_drvdata(struct macio_dev *dev, void *data)
{
dev_set_drvdata(&dev->ofdev.dev, data);
}
static inline void* macio_get_drvdata(struct macio_dev *dev)
{
return dev_get_drvdata(&dev->ofdev.dev);
}
static inline struct device_node *macio_get_of_node(struct macio_dev *mdev)
{
return mdev->ofdev.node;
}
#ifdef CONFIG_PCI
static inline struct pci_dev *macio_get_pci_dev(struct macio_dev *mdev)
{
return mdev->bus->pdev;
}
#endif
/* /*
* A driver for a mac-io chip based device * A driver for a mac-io chip based device
*/ */
......
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