[PATCH] ppc64: xics cleanup
[pandora-kernel.git] / arch / ppc64 / kernel / pSeries_vio.c
1 /*
2  * IBM PowerPC pSeries Virtual I/O Infrastructure Support.
3  *
4  *    Copyright (c) 2003-2005 IBM Corp.
5  *     Dave Engebretsen engebret@us.ibm.com
6  *     Santiago Leon santil@us.ibm.com
7  *     Hollis Blanchard <hollisb@us.ibm.com>
8  *     Stephen Rothwell
9  *
10  *      This program is free software; you can redistribute it and/or
11  *      modify it under the terms of the GNU General Public License
12  *      as published by the Free Software Foundation; either version
13  *      2 of the License, or (at your option) any later version.
14  */
15
16 #include <linux/init.h>
17 #include <linux/module.h>
18 #include <linux/mm.h>
19 #include <linux/kobject.h>
20 #include <asm/iommu.h>
21 #include <asm/dma.h>
22 #include <asm/prom.h>
23 #include <asm/vio.h>
24 #include <asm/hvcall.h>
25
26 extern struct subsystem devices_subsys; /* needed for vio_find_name() */
27
28 static void probe_bus_pseries(void)
29 {
30         struct device_node *node_vroot, *of_node;
31
32         node_vroot = find_devices("vdevice");
33         if ((node_vroot == NULL) || (node_vroot->child == NULL))
34                 /* this machine doesn't do virtual IO, and that's ok */
35                 return;
36
37         /*
38          * Create struct vio_devices for each virtual device in the device tree.
39          * Drivers will associate with them later.
40          */
41         for (of_node = node_vroot->child; of_node != NULL;
42                         of_node = of_node->sibling) {
43                 printk(KERN_DEBUG "%s: processing %p\n", __FUNCTION__, of_node);
44                 vio_register_device_node(of_node);
45         }
46 }
47
48 /**
49  * vio_match_device_pseries: - Tell if a pSeries VIO device matches a
50  *      vio_device_id
51  */
52 static int vio_match_device_pseries(const struct vio_device_id *id,
53                 const struct vio_dev *dev)
54 {
55         return (strncmp(dev->type, id->type, strlen(id->type)) == 0) &&
56                         device_is_compatible(dev->dev.platform_data, id->compat);
57 }
58
59 static void vio_release_device_pseries(struct device *dev)
60 {
61         /* XXX free TCE table */
62         of_node_put(dev->platform_data);
63 }
64
65 static ssize_t viodev_show_devspec(struct device *dev,
66                 struct device_attribute *attr, char *buf)
67 {
68         struct device_node *of_node = dev->platform_data;
69
70         return sprintf(buf, "%s\n", of_node->full_name);
71 }
72 DEVICE_ATTR(devspec, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_devspec, NULL);
73
74 static void vio_unregister_device_pseries(struct vio_dev *viodev)
75 {
76         device_remove_file(&viodev->dev, &dev_attr_devspec);
77 }
78
79 static struct vio_bus_ops vio_bus_ops_pseries = {
80         .match = vio_match_device_pseries,
81         .unregister_device = vio_unregister_device_pseries,
82         .release_device = vio_release_device_pseries,
83 };
84
85 /**
86  * vio_bus_init_pseries: - Initialize the pSeries virtual IO bus
87  */
88 static int __init vio_bus_init_pseries(void)
89 {
90         int err;
91
92         err = vio_bus_init(&vio_bus_ops_pseries);
93         if (err == 0)
94                 probe_bus_pseries();
95         return err;
96 }
97
98 __initcall(vio_bus_init_pseries);
99
100 /**
101  * vio_build_iommu_table: - gets the dma information from OF and
102  *      builds the TCE tree.
103  * @dev: the virtual device.
104  *
105  * Returns a pointer to the built tce tree, or NULL if it can't
106  * find property.
107 */
108 static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
109 {
110         unsigned int *dma_window;
111         struct iommu_table *newTceTable;
112         unsigned long offset;
113         int dma_window_property_size;
114
115         dma_window = (unsigned int *) get_property(dev->dev.platform_data, "ibm,my-dma-window", &dma_window_property_size);
116         if(!dma_window) {
117                 return NULL;
118         }
119
120         newTceTable = (struct iommu_table *) kmalloc(sizeof(struct iommu_table), GFP_KERNEL);
121
122         /*  There should be some code to extract the phys-encoded offset
123                 using prom_n_addr_cells(). However, according to a comment
124                 on earlier versions, it's always zero, so we don't bother */
125         offset = dma_window[1] >>  PAGE_SHIFT;
126
127         /* TCE table size - measured in tce entries */
128         newTceTable->it_size            = dma_window[4] >> PAGE_SHIFT;
129         /* offset for VIO should always be 0 */
130         newTceTable->it_offset          = offset;
131         newTceTable->it_busno           = 0;
132         newTceTable->it_index           = (unsigned long)dma_window[0];
133         newTceTable->it_type            = TCE_VB;
134
135         return iommu_init_table(newTceTable);
136 }
137
138 /**
139  * vio_register_device_node: - Register a new vio device.
140  * @of_node:    The OF node for this device.
141  *
142  * Creates and initializes a vio_dev structure from the data in
143  * of_node (dev.platform_data) and adds it to the list of virtual devices.
144  * Returns a pointer to the created vio_dev or NULL if node has
145  * NULL device_type or compatible fields.
146  */
147 struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
148 {
149         struct vio_dev *viodev;
150         unsigned int *unit_address;
151         unsigned int *irq_p;
152
153         /* we need the 'device_type' property, in order to match with drivers */
154         if ((NULL == of_node->type)) {
155                 printk(KERN_WARNING
156                         "%s: node %s missing 'device_type'\n", __FUNCTION__,
157                         of_node->name ? of_node->name : "<unknown>");
158                 return NULL;
159         }
160
161         unit_address = (unsigned int *)get_property(of_node, "reg", NULL);
162         if (!unit_address) {
163                 printk(KERN_WARNING "%s: node %s missing 'reg'\n", __FUNCTION__,
164                         of_node->name ? of_node->name : "<unknown>");
165                 return NULL;
166         }
167
168         /* allocate a vio_dev for this node */
169         viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);
170         if (!viodev) {
171                 return NULL;
172         }
173         memset(viodev, 0, sizeof(struct vio_dev));
174
175         viodev->dev.platform_data = of_node_get(of_node);
176
177         viodev->irq = NO_IRQ;
178         irq_p = (unsigned int *)get_property(of_node, "interrupts", NULL);
179         if (irq_p) {
180                 int virq = virt_irq_create_mapping(*irq_p);
181                 if (virq == NO_IRQ) {
182                         printk(KERN_ERR "Unable to allocate interrupt "
183                                "number for %s\n", of_node->full_name);
184                 } else
185                         viodev->irq = irq_offset_up(virq);
186         }
187
188         snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address);
189         viodev->name = of_node->name;
190         viodev->type = of_node->type;
191         viodev->unit_address = *unit_address;
192         viodev->iommu_table = vio_build_iommu_table(viodev);
193
194         /* register with generic device framework */
195         if (vio_register_device(viodev) == NULL) {
196                 /* XXX free TCE table */
197                 kfree(viodev);
198                 return NULL;
199         }
200         device_create_file(&viodev->dev, &dev_attr_devspec);
201
202         return viodev;
203 }
204 EXPORT_SYMBOL(vio_register_device_node);
205
206 /**
207  * vio_get_attribute: - get attribute for virtual device
208  * @vdev:       The vio device to get property.
209  * @which:      The property/attribute to be extracted.
210  * @length:     Pointer to length of returned data size (unused if NULL).
211  *
212  * Calls prom.c's get_property() to return the value of the
213  * attribute specified by the preprocessor constant @which
214 */
215 const void * vio_get_attribute(struct vio_dev *vdev, void* which, int* length)
216 {
217         return get_property(vdev->dev.platform_data, (char*)which, length);
218 }
219 EXPORT_SYMBOL(vio_get_attribute);
220
221 /* vio_find_name() - internal because only vio.c knows how we formatted the
222  * kobject name
223  * XXX once vio_bus_type.devices is actually used as a kset in
224  * drivers/base/bus.c, this function should be removed in favor of
225  * "device_find(kobj_name, &vio_bus_type)"
226  */
227 static struct vio_dev *vio_find_name(const char *kobj_name)
228 {
229         struct kobject *found;
230
231         found = kset_find_obj(&devices_subsys.kset, kobj_name);
232         if (!found)
233                 return NULL;
234
235         return to_vio_dev(container_of(found, struct device, kobj));
236 }
237
238 /**
239  * vio_find_node - find an already-registered vio_dev
240  * @vnode: device_node of the virtual device we're looking for
241  */
242 struct vio_dev *vio_find_node(struct device_node *vnode)
243 {
244         uint32_t *unit_address;
245         char kobj_name[BUS_ID_SIZE];
246
247         /* construct the kobject name from the device node */
248         unit_address = (uint32_t *)get_property(vnode, "reg", NULL);
249         if (!unit_address)
250                 return NULL;
251         snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address);
252
253         return vio_find_name(kobj_name);
254 }
255 EXPORT_SYMBOL(vio_find_node);
256
257 int vio_enable_interrupts(struct vio_dev *dev)
258 {
259         int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE);
260         if (rc != H_Success)
261                 printk(KERN_ERR "vio: Error 0x%x enabling interrupts\n", rc);
262         return rc;
263 }
264 EXPORT_SYMBOL(vio_enable_interrupts);
265
266 int vio_disable_interrupts(struct vio_dev *dev)
267 {
268         int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE);
269         if (rc != H_Success)
270                 printk(KERN_ERR "vio: Error 0x%x disabling interrupts\n", rc);
271         return rc;
272 }
273 EXPORT_SYMBOL(vio_disable_interrupts);