Path: blob/master/arch/powerpc/platforms/pseries/ibmebus.c
51704 views
/*1* IBM PowerPC IBM eBus Infrastructure Support.2*3* Copyright (c) 2005 IBM Corporation4* Joachim Fenkes <[email protected]>5* Heiko J Schick <[email protected]>6*7* All rights reserved.8*9* This source code is distributed under a dual license of GPL v2.0 and OpenIB10* BSD.11*12* OpenIB BSD License13*14* Redistribution and use in source and binary forms, with or without15* modification, are permitted provided that the following conditions are met:16*17* Redistributions of source code must retain the above copyright notice, this18* list of conditions and the following disclaimer.19*20* Redistributions in binary form must reproduce the above copyright notice,21* this list of conditions and the following disclaimer in the documentation22* and/or other materials23* provided with the distribution.24*25* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"26* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE27* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE28* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE29* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR30* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF31* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR32* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER33* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)34* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE35* POSSIBILITY OF SUCH DAMAGE.36*/3738#include <linux/init.h>39#include <linux/export.h>40#include <linux/console.h>41#include <linux/kobject.h>42#include <linux/dma-map-ops.h>43#include <linux/interrupt.h>44#include <linux/irqdomain.h>45#include <linux/of.h>46#include <linux/slab.h>47#include <linux/stat.h>48#include <linux/of_platform.h>49#include <linux/platform_device.h>50#include <asm/ibmebus.h>51#include <asm/machdep.h>5253static struct device ibmebus_bus_device = { /* fake "parent" device */54.init_name = "ibmebus",55};5657const struct bus_type ibmebus_bus_type;5859/* These devices will automatically be added to the bus during init */60static const struct of_device_id ibmebus_matches[] __initconst = {61{ .compatible = "IBM,lhca" },62{ .compatible = "IBM,lhea" },63{},64};6566static void *ibmebus_alloc_coherent(struct device *dev,67size_t size,68dma_addr_t *dma_handle,69gfp_t flag,70unsigned long attrs)71{72void *mem;7374mem = kmalloc(size, flag);75*dma_handle = (dma_addr_t)mem;7677return mem;78}7980static void ibmebus_free_coherent(struct device *dev,81size_t size, void *vaddr,82dma_addr_t dma_handle,83unsigned long attrs)84{85kfree(vaddr);86}8788static dma_addr_t ibmebus_map_phys(struct device *dev, phys_addr_t phys,89size_t size,90enum dma_data_direction direction,91unsigned long attrs)92{93if (attrs & DMA_ATTR_MMIO)94return DMA_MAPPING_ERROR;9596return (dma_addr_t)(phys_to_virt(phys));97}9899static void ibmebus_unmap_phys(struct device *dev,100dma_addr_t dma_addr,101size_t size,102enum dma_data_direction direction,103unsigned long attrs)104{105return;106}107108static int ibmebus_map_sg(struct device *dev,109struct scatterlist *sgl,110int nents, enum dma_data_direction direction,111unsigned long attrs)112{113struct scatterlist *sg;114int i;115116for_each_sg(sgl, sg, nents, i) {117sg->dma_address = (dma_addr_t) sg_virt(sg);118sg->dma_length = sg->length;119}120121return nents;122}123124static void ibmebus_unmap_sg(struct device *dev,125struct scatterlist *sg,126int nents, enum dma_data_direction direction,127unsigned long attrs)128{129return;130}131132static int ibmebus_dma_supported(struct device *dev, u64 mask)133{134return mask == DMA_BIT_MASK(64);135}136137static u64 ibmebus_dma_get_required_mask(struct device *dev)138{139return DMA_BIT_MASK(64);140}141142static const struct dma_map_ops ibmebus_dma_ops = {143.alloc = ibmebus_alloc_coherent,144.free = ibmebus_free_coherent,145.map_sg = ibmebus_map_sg,146.unmap_sg = ibmebus_unmap_sg,147.dma_supported = ibmebus_dma_supported,148.get_required_mask = ibmebus_dma_get_required_mask,149.map_phys = ibmebus_map_phys,150.unmap_phys = ibmebus_unmap_phys,151};152153static int ibmebus_match_path(struct device *dev, const void *data)154{155struct device_node *dn = to_platform_device(dev)->dev.of_node;156struct device_node *tn = of_find_node_by_path(data);157158of_node_put(tn);159160return (tn == dn);161}162163static int ibmebus_match_node(struct device *dev, const void *data)164{165return to_platform_device(dev)->dev.of_node == data;166}167168static int ibmebus_create_device(struct device_node *dn)169{170struct platform_device *dev;171int ret;172173dev = of_device_alloc(dn, NULL, &ibmebus_bus_device);174if (!dev)175return -ENOMEM;176177dev->dev.bus = &ibmebus_bus_type;178dev->dev.dma_ops = &ibmebus_dma_ops;179180ret = of_device_add(dev);181if (ret)182platform_device_put(dev);183return ret;184}185186static int ibmebus_create_devices(const struct of_device_id *matches)187{188struct device_node *root, *child;189struct device *dev;190int ret = 0;191192root = of_find_node_by_path("/");193194for_each_child_of_node(root, child) {195if (!of_match_node(matches, child))196continue;197198dev = bus_find_device(&ibmebus_bus_type, NULL, child,199ibmebus_match_node);200if (dev) {201put_device(dev);202continue;203}204205ret = ibmebus_create_device(child);206if (ret) {207printk(KERN_ERR "%s: failed to create device (%i)",208__func__, ret);209of_node_put(child);210break;211}212}213214of_node_put(root);215return ret;216}217218int ibmebus_register_driver(struct platform_driver *drv)219{220/* If the driver uses devices that ibmebus doesn't know, add them */221ibmebus_create_devices(drv->driver.of_match_table);222223drv->driver.bus = &ibmebus_bus_type;224return driver_register(&drv->driver);225}226EXPORT_SYMBOL(ibmebus_register_driver);227228void ibmebus_unregister_driver(struct platform_driver *drv)229{230driver_unregister(&drv->driver);231}232EXPORT_SYMBOL(ibmebus_unregister_driver);233234int ibmebus_request_irq(u32 ist, irq_handler_t handler,235unsigned long irq_flags, const char *devname,236void *dev_id)237{238unsigned int irq = irq_create_mapping(NULL, ist);239240if (!irq)241return -EINVAL;242243return request_irq(irq, handler, irq_flags, devname, dev_id);244}245EXPORT_SYMBOL(ibmebus_request_irq);246247void ibmebus_free_irq(u32 ist, void *dev_id)248{249unsigned int irq = irq_find_mapping(NULL, ist);250251free_irq(irq, dev_id);252irq_dispose_mapping(irq);253}254EXPORT_SYMBOL(ibmebus_free_irq);255256static char *ibmebus_chomp(const char *in, size_t count)257{258char *out = kmalloc(count + 1, GFP_KERNEL);259260if (!out)261return NULL;262263memcpy(out, in, count);264out[count] = '\0';265if (out[count - 1] == '\n')266out[count - 1] = '\0';267268return out;269}270271static ssize_t probe_store(const struct bus_type *bus, const char *buf, size_t count)272{273struct device_node *dn = NULL;274struct device *dev;275char *path;276ssize_t rc = 0;277278path = ibmebus_chomp(buf, count);279if (!path)280return -ENOMEM;281282dev = bus_find_device(&ibmebus_bus_type, NULL, path,283ibmebus_match_path);284if (dev) {285put_device(dev);286printk(KERN_WARNING "%s: %s has already been probed\n",287__func__, path);288rc = -EEXIST;289goto out;290}291292if ((dn = of_find_node_by_path(path))) {293rc = ibmebus_create_device(dn);294of_node_put(dn);295} else {296printk(KERN_WARNING "%s: no such device node: %s\n",297__func__, path);298rc = -ENODEV;299}300301out:302kfree(path);303if (rc)304return rc;305return count;306}307static BUS_ATTR_WO(probe);308309static ssize_t remove_store(const struct bus_type *bus, const char *buf, size_t count)310{311struct device *dev;312char *path;313314path = ibmebus_chomp(buf, count);315if (!path)316return -ENOMEM;317318if ((dev = bus_find_device(&ibmebus_bus_type, NULL, path,319ibmebus_match_path))) {320of_device_unregister(to_platform_device(dev));321put_device(dev);322323kfree(path);324return count;325} else {326printk(KERN_WARNING "%s: %s not on the bus\n",327__func__, path);328329kfree(path);330return -ENODEV;331}332}333static BUS_ATTR_WO(remove);334335static struct attribute *ibmbus_bus_attrs[] = {336&bus_attr_probe.attr,337&bus_attr_remove.attr,338NULL,339};340ATTRIBUTE_GROUPS(ibmbus_bus);341342static int ibmebus_bus_bus_match(struct device *dev, const struct device_driver *drv)343{344const struct of_device_id *matches = drv->of_match_table;345346if (!matches)347return 0;348349return of_match_device(matches, dev) != NULL;350}351352static int ibmebus_bus_device_probe(struct device *dev)353{354int error = -ENODEV;355struct platform_driver *drv;356struct platform_device *of_dev;357358drv = to_platform_driver(dev->driver);359of_dev = to_platform_device(dev);360361if (!drv->probe)362return error;363364get_device(dev);365366if (of_driver_match_device(dev, dev->driver))367error = drv->probe(of_dev);368if (error)369put_device(dev);370371return error;372}373374static void ibmebus_bus_device_remove(struct device *dev)375{376struct platform_device *of_dev = to_platform_device(dev);377struct platform_driver *drv = to_platform_driver(dev->driver);378379if (dev->driver && drv->remove)380drv->remove(of_dev);381}382383static void ibmebus_bus_device_shutdown(struct device *dev)384{385struct platform_device *of_dev = to_platform_device(dev);386struct platform_driver *drv = to_platform_driver(dev->driver);387388if (dev->driver && drv->shutdown)389drv->shutdown(of_dev);390}391392/*393* ibmebus_bus_device_attrs394*/395static ssize_t devspec_show(struct device *dev,396struct device_attribute *attr, char *buf)397{398struct platform_device *ofdev;399400ofdev = to_platform_device(dev);401return sprintf(buf, "%pOF\n", ofdev->dev.of_node);402}403static DEVICE_ATTR_RO(devspec);404405static ssize_t name_show(struct device *dev,406struct device_attribute *attr, char *buf)407{408struct platform_device *ofdev;409410ofdev = to_platform_device(dev);411return sprintf(buf, "%pOFn\n", ofdev->dev.of_node);412}413static DEVICE_ATTR_RO(name);414415static ssize_t modalias_show(struct device *dev,416struct device_attribute *attr, char *buf)417{418return of_device_modalias(dev, buf, PAGE_SIZE);419}420static DEVICE_ATTR_RO(modalias);421422static struct attribute *ibmebus_bus_device_attrs[] = {423&dev_attr_devspec.attr,424&dev_attr_name.attr,425&dev_attr_modalias.attr,426NULL,427};428ATTRIBUTE_GROUPS(ibmebus_bus_device);429430static int ibmebus_bus_modalias(const struct device *dev, struct kobj_uevent_env *env)431{432return of_device_uevent_modalias(dev, env);433}434435const struct bus_type ibmebus_bus_type = {436.name = "ibmebus",437.uevent = ibmebus_bus_modalias,438.bus_groups = ibmbus_bus_groups,439.match = ibmebus_bus_bus_match,440.probe = ibmebus_bus_device_probe,441.remove = ibmebus_bus_device_remove,442.shutdown = ibmebus_bus_device_shutdown,443.dev_groups = ibmebus_bus_device_groups,444};445EXPORT_SYMBOL(ibmebus_bus_type);446447static int __init ibmebus_bus_init(void)448{449int err;450451printk(KERN_INFO "IBM eBus Device Driver\n");452453err = bus_register(&ibmebus_bus_type);454if (err) {455printk(KERN_ERR "%s: failed to register IBM eBus.\n",456__func__);457return err;458}459460err = device_register(&ibmebus_bus_device);461if (err) {462printk(KERN_WARNING "%s: device_register returned %i\n",463__func__, err);464put_device(&ibmebus_bus_device);465bus_unregister(&ibmebus_bus_type);466467return err;468}469470err = ibmebus_create_devices(ibmebus_matches);471if (err) {472device_unregister(&ibmebus_bus_device);473bus_unregister(&ibmebus_bus_type);474return err;475}476477return 0;478}479machine_postcore_initcall(pseries, ibmebus_bus_init);480481482