blob: c64741e50cb2b1e43974d8bb30ea61ae3c9b1605 [file] [log] [blame]
Stephen Rothwell3e494c82005-07-12 17:40:17 +10001/*
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>
Olof Johanssonc707ffc2005-09-20 13:45:41 +100017#include <asm/tce.h>
Stephen Rothwell3e494c82005-07-12 17:40:17 +100018#include <asm/abs_addr.h>
19#include <asm/page.h>
20#include <asm/iSeries/vio.h>
21#include <asm/iSeries/HvTypes.h>
22#include <asm/iSeries/HvLpConfig.h>
Kelly Daly8021b8a2005-11-02 11:41:12 +110023#include <asm/iseries/hv_call_xm.h>
Stephen Rothwell3e494c82005-07-12 17:40:17 +100024
25struct device *iSeries_vio_dev = &vio_bus_device.dev;
26EXPORT_SYMBOL(iSeries_vio_dev);
27
28static struct iommu_table veth_iommu_table;
29static struct iommu_table vio_iommu_table;
30
Stephen Rothwell8c65b5c2005-07-12 17:42:49 +100031static void __init iommu_vio_init(void)
Stephen Rothwell3e494c82005-07-12 17:40:17 +100032{
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/**
Stephen Rothwellb877b902005-08-17 16:40:12 +100072 * vio_register_device_iseries: - Register a new iSeries vio device.
Stephen Rothwell3e494c82005-07-12 17:40:17 +100073 * @voidev: The device to register.
74 */
75static struct vio_dev *__init vio_register_device_iseries(char *type,
76 uint32_t unit_num)
77{
78 struct vio_dev *viodev;
79
Stephen Rothwellb877b902005-08-17 16:40:12 +100080 /* allocate a vio_dev for this device */
Stephen Rothwell3e494c82005-07-12 17:40:17 +100081 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
Stephen Rothwellb877b902005-08-17 16:40:12 +100088 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;
Stephen Rothwell3e494c82005-07-12 17:40:17 +100097}
98
99void __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/**
Stephen Rothwell63122362005-07-12 17:45:27 +1000126 * vio_match_device_iseries: - Tell if a iSeries VIO device matches a
127 * vio_device_id
128 */
129static 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
Stephen Rothwell71d276d2005-08-17 16:41:44 +1000135static struct vio_bus_ops vio_bus_ops_iseries = {
136 .match = vio_match_device_iseries,
137};
138
Stephen Rothwell63122362005-07-12 17:45:27 +1000139/**
Stephen Rothwell3e494c82005-07-12 17:40:17 +1000140 * vio_bus_init_iseries: - Initialize the iSeries virtual IO bus
141 */
142static int __init vio_bus_init_iseries(void)
143{
144 int err;
145
Stephen Rothwell71d276d2005-08-17 16:41:44 +1000146 err = vio_bus_init(&vio_bus_ops_iseries);
Stephen Rothwell3e494c82005-07-12 17:40:17 +1000147 if (err == 0) {
Stephen Rothwell8c65b5c2005-07-12 17:42:49 +1000148 iommu_vio_init();
Stephen Rothwell3e494c82005-07-12 17:40:17 +1000149 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);