diff options
Diffstat (limited to 'arch/ppc64/kernel/iSeries_vio.c')
-rw-r--r-- | arch/ppc64/kernel/iSeries_vio.c | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/arch/ppc64/kernel/iSeries_vio.c b/arch/ppc64/kernel/iSeries_vio.c new file mode 100644 index 000000000000..6b754b0c8344 --- /dev/null +++ b/arch/ppc64/kernel/iSeries_vio.c | |||
@@ -0,0 +1,155 @@ | |||
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/abs_addr.h> | ||
18 | #include <asm/page.h> | ||
19 | #include <asm/iSeries/vio.h> | ||
20 | #include <asm/iSeries/HvTypes.h> | ||
21 | #include <asm/iSeries/HvLpConfig.h> | ||
22 | #include <asm/iSeries/HvCallXm.h> | ||
23 | |||
24 | struct device *iSeries_vio_dev = &vio_bus_device.dev; | ||
25 | EXPORT_SYMBOL(iSeries_vio_dev); | ||
26 | |||
27 | static struct iommu_table veth_iommu_table; | ||
28 | static struct iommu_table vio_iommu_table; | ||
29 | |||
30 | static void __init iommu_vio_init(void) | ||
31 | { | ||
32 | struct iommu_table *t; | ||
33 | struct iommu_table_cb cb; | ||
34 | unsigned long cbp; | ||
35 | unsigned long itc_entries; | ||
36 | |||
37 | cb.itc_busno = 255; /* Bus 255 is the virtual bus */ | ||
38 | cb.itc_virtbus = 0xff; /* Ask for virtual bus */ | ||
39 | |||
40 | cbp = virt_to_abs(&cb); | ||
41 | HvCallXm_getTceTableParms(cbp); | ||
42 | |||
43 | itc_entries = cb.itc_size * PAGE_SIZE / sizeof(union tce_entry); | ||
44 | veth_iommu_table.it_size = itc_entries / 2; | ||
45 | veth_iommu_table.it_busno = cb.itc_busno; | ||
46 | veth_iommu_table.it_offset = cb.itc_offset; | ||
47 | veth_iommu_table.it_index = cb.itc_index; | ||
48 | veth_iommu_table.it_type = TCE_VB; | ||
49 | veth_iommu_table.it_blocksize = 1; | ||
50 | |||
51 | t = iommu_init_table(&veth_iommu_table); | ||
52 | |||
53 | if (!t) | ||
54 | printk("Virtual Bus VETH TCE table failed.\n"); | ||
55 | |||
56 | vio_iommu_table.it_size = itc_entries - veth_iommu_table.it_size; | ||
57 | vio_iommu_table.it_busno = cb.itc_busno; | ||
58 | vio_iommu_table.it_offset = cb.itc_offset + | ||
59 | veth_iommu_table.it_size; | ||
60 | vio_iommu_table.it_index = cb.itc_index; | ||
61 | vio_iommu_table.it_type = TCE_VB; | ||
62 | vio_iommu_table.it_blocksize = 1; | ||
63 | |||
64 | t = iommu_init_table(&vio_iommu_table); | ||
65 | |||
66 | if (!t) | ||
67 | printk("Virtual Bus VIO TCE table failed.\n"); | ||
68 | } | ||
69 | |||
70 | /** | ||
71 | * vio_register_device_iseries: - Register a new iSeries vio device. | ||
72 | * @voidev: The device to register. | ||
73 | */ | ||
74 | static struct vio_dev *__init vio_register_device_iseries(char *type, | ||
75 | uint32_t unit_num) | ||
76 | { | ||
77 | struct vio_dev *viodev; | ||
78 | |||
79 | /* allocate a vio_dev for this device */ | ||
80 | viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL); | ||
81 | if (!viodev) | ||
82 | return NULL; | ||
83 | memset(viodev, 0, sizeof(struct vio_dev)); | ||
84 | |||
85 | snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%s%d", type, unit_num); | ||
86 | |||
87 | viodev->name = viodev->dev.bus_id; | ||
88 | viodev->type = type; | ||
89 | viodev->unit_address = unit_num; | ||
90 | viodev->iommu_table = &vio_iommu_table; | ||
91 | if (vio_register_device(viodev) == NULL) { | ||
92 | kfree(viodev); | ||
93 | return NULL; | ||
94 | } | ||
95 | return viodev; | ||
96 | } | ||
97 | |||
98 | void __init probe_bus_iseries(void) | ||
99 | { | ||
100 | HvLpIndexMap vlan_map; | ||
101 | struct vio_dev *viodev; | ||
102 | int i; | ||
103 | |||
104 | /* there is only one of each of these */ | ||
105 | vio_register_device_iseries("viocons", 0); | ||
106 | vio_register_device_iseries("vscsi", 0); | ||
107 | |||
108 | vlan_map = HvLpConfig_getVirtualLanIndexMap(); | ||
109 | for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) { | ||
110 | if ((vlan_map & (0x8000 >> i)) == 0) | ||
111 | continue; | ||
112 | viodev = vio_register_device_iseries("vlan", i); | ||
113 | /* veth is special and has it own iommu_table */ | ||
114 | viodev->iommu_table = &veth_iommu_table; | ||
115 | } | ||
116 | for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++) | ||
117 | vio_register_device_iseries("viodasd", i); | ||
118 | for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++) | ||
119 | vio_register_device_iseries("viocd", i); | ||
120 | for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++) | ||
121 | vio_register_device_iseries("viotape", i); | ||
122 | } | ||
123 | |||
124 | /** | ||
125 | * vio_match_device_iseries: - Tell if a iSeries VIO device matches a | ||
126 | * vio_device_id | ||
127 | */ | ||
128 | static int vio_match_device_iseries(const struct vio_device_id *id, | ||
129 | const struct vio_dev *dev) | ||
130 | { | ||
131 | return strncmp(dev->type, id->type, strlen(id->type)) == 0; | ||
132 | } | ||
133 | |||
134 | static struct vio_bus_ops vio_bus_ops_iseries = { | ||
135 | .match = vio_match_device_iseries, | ||
136 | }; | ||
137 | |||
138 | /** | ||
139 | * vio_bus_init_iseries: - Initialize the iSeries virtual IO bus | ||
140 | */ | ||
141 | static int __init vio_bus_init_iseries(void) | ||
142 | { | ||
143 | int err; | ||
144 | |||
145 | err = vio_bus_init(&vio_bus_ops_iseries); | ||
146 | if (err == 0) { | ||
147 | iommu_vio_init(); | ||
148 | vio_bus_device.iommu_table = &vio_iommu_table; | ||
149 | iSeries_vio_dev = &vio_bus_device.dev; | ||
150 | probe_bus_iseries(); | ||
151 | } | ||
152 | return err; | ||
153 | } | ||
154 | |||
155 | __initcall(vio_bus_init_iseries); | ||