]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - arch/powerpc/platforms/iseries/vio.c
Merge Paulus' tree
[karo-tx-linux.git] / arch / powerpc / platforms / iseries / vio.c
1 /*
2  * IBM PowerPC iSeries Virtual I/O Infrastructure Support.
3  *
4  *    Copyright (c) 2005 Stephen Rothwell, IBM Corp.
5  *
6  *      This program is free software; you can redistribute it and/or
7  *      modify it under the terms of the GNU General Public License
8  *      as published by the Free Software Foundation; either version
9  *      2 of the License, or (at your option) any later version.
10  */
11 #include <linux/types.h>
12 #include <linux/device.h>
13 #include <linux/init.h>
14
15 #include <asm/vio.h>
16 #include <asm/iommu.h>
17 #include <asm/tce.h>
18 #include <asm/abs_addr.h>
19 #include <asm/page.h>
20 #include <asm/iseries/vio.h>
21 #include <asm/iseries/hv_types.h>
22 #include <asm/iseries/hv_lp_config.h>
23 #include <asm/iseries/hv_call_xm.h>
24
25 struct device *iSeries_vio_dev = &vio_bus_device.dev;
26 EXPORT_SYMBOL(iSeries_vio_dev);
27
28 static struct iommu_table veth_iommu_table;
29 static struct iommu_table vio_iommu_table;
30
31 static void __init iommu_vio_init(void)
32 {
33         struct iommu_table *t;
34         struct iommu_table_cb cb;
35         unsigned long cbp;
36         unsigned long itc_entries;
37
38         cb.itc_busno = 255;    /* Bus 255 is the virtual bus */
39         cb.itc_virtbus = 0xff; /* Ask for virtual bus */
40
41         cbp = virt_to_abs(&cb);
42         HvCallXm_getTceTableParms(cbp);
43
44         itc_entries = cb.itc_size * PAGE_SIZE / sizeof(union tce_entry);
45         veth_iommu_table.it_size        = itc_entries / 2;
46         veth_iommu_table.it_busno       = cb.itc_busno;
47         veth_iommu_table.it_offset      = cb.itc_offset;
48         veth_iommu_table.it_index       = cb.itc_index;
49         veth_iommu_table.it_type        = TCE_VB;
50         veth_iommu_table.it_blocksize   = 1;
51
52         t = iommu_init_table(&veth_iommu_table);
53
54         if (!t)
55                 printk("Virtual Bus VETH TCE table failed.\n");
56
57         vio_iommu_table.it_size         = itc_entries - veth_iommu_table.it_size;
58         vio_iommu_table.it_busno        = cb.itc_busno;
59         vio_iommu_table.it_offset       = cb.itc_offset +
60                                           veth_iommu_table.it_size;
61         vio_iommu_table.it_index        = cb.itc_index;
62         vio_iommu_table.it_type         = TCE_VB;
63         vio_iommu_table.it_blocksize    = 1;
64
65         t = iommu_init_table(&vio_iommu_table);
66
67         if (!t)
68                 printk("Virtual Bus VIO TCE table failed.\n");
69 }
70
71 /**
72  * vio_register_device_iseries: - Register a new iSeries vio device.
73  * @voidev:     The device to register.
74  */
75 static struct vio_dev *__init vio_register_device_iseries(char *type,
76                 uint32_t unit_num)
77 {
78         struct vio_dev *viodev;
79
80         /* allocate a vio_dev for this device */
81         viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL);
82         if (!viodev)
83                 return NULL;
84         memset(viodev, 0, sizeof(struct vio_dev));
85
86         snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%s%d", type, unit_num);
87
88         viodev->name = viodev->dev.bus_id;
89         viodev->type = type;
90         viodev->unit_address = unit_num;
91         viodev->iommu_table = &vio_iommu_table;
92         if (vio_register_device(viodev) == NULL) {
93                 kfree(viodev);
94                 return NULL;
95         }
96         return viodev;
97 }
98
99 void __init probe_bus_iseries(void)
100 {
101         HvLpIndexMap vlan_map;
102         struct vio_dev *viodev;
103         int i;
104
105         /* there is only one of each of these */
106         vio_register_device_iseries("viocons", 0);
107         vio_register_device_iseries("vscsi", 0);
108
109         vlan_map = HvLpConfig_getVirtualLanIndexMap();
110         for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) {
111                 if ((vlan_map & (0x8000 >> i)) == 0)
112                         continue;
113                 viodev = vio_register_device_iseries("vlan", i);
114                 /* veth is special and has it own iommu_table */
115                 viodev->iommu_table = &veth_iommu_table;
116         }
117         for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++)
118                 vio_register_device_iseries("viodasd", i);
119         for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++)
120                 vio_register_device_iseries("viocd", i);
121         for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++)
122                 vio_register_device_iseries("viotape", i);
123 }
124
125 /**
126  * vio_match_device_iseries: - Tell if a iSeries VIO device matches a
127  *      vio_device_id
128  */
129 static int vio_match_device_iseries(const struct vio_device_id *id,
130                 const struct vio_dev *dev)
131 {
132         return strncmp(dev->type, id->type, strlen(id->type)) == 0;
133 }
134
135 static struct vio_bus_ops vio_bus_ops_iseries = {
136         .match = vio_match_device_iseries,
137 };
138
139 /**
140  * vio_bus_init_iseries: - Initialize the iSeries virtual IO bus
141  */
142 static int __init vio_bus_init_iseries(void)
143 {
144         int err;
145
146         err = vio_bus_init(&vio_bus_ops_iseries);
147         if (err == 0) {
148                 iommu_vio_init();
149                 vio_bus_device.iommu_table = &vio_iommu_table;
150                 iSeries_vio_dev = &vio_bus_device.dev;
151                 probe_bus_iseries();
152         }
153         return err;
154 }
155
156 __initcall(vio_bus_init_iseries);