3 * jacklange@cs.pitt.edu
6 #include <linux/uaccess.h>
8 #include <linux/kernel.h>
9 #include <linux/module.h>
12 #include "linux-exts.h"
15 #include <interfaces/host_pci.h>
17 static struct list_head device_list;
18 static spinlock_t lock;
26 struct host_pci_device {
29 enum {PASSTHROUGH, USER} type;
31 enum {INTX_IRQ, MSI_IRQ, MSIX_IRQ} irq_type;
46 struct msix_entry * msix_entries;
47 struct iommu_domain * iommu_domain;
52 // struct user_dev_state user_dev;
55 struct v3_host_pci_dev v3_dev;
57 struct list_head dev_node;
61 //#include "iface-host-pci-user.h"
62 #include "iface-host-pci-hw.h"
65 static struct host_pci_device * find_dev_by_name(char * name) {
66 struct host_pci_device * dev = NULL;
68 list_for_each_entry(dev, &device_list, dev_node) {
69 if (strncmp(dev->name, name, 128) == 0) {
79 static struct v3_host_pci_dev * request_pci_dev(char * url, void * v3_ctx) {
82 struct host_pci_device * host_dev = NULL;
84 palacios_spinlock_lock_irqsave(&lock, flags);
85 host_dev = find_dev_by_name(url);
86 palacios_spinlock_unlock_irqrestore(&lock, flags);
88 if (host_dev == NULL) {
89 printk("Could not find host device (%s)\n", url);
93 if (host_dev->type == PASSTHROUGH) {
94 if (reserve_hw_pci_dev(host_dev, v3_ctx) == -1) {
95 printk("Could not reserve host device (%s)\n", url);
99 printk("Unsupported Host device type\n");
105 return &(host_dev->v3_dev);
110 static int host_pci_config_write(struct v3_host_pci_dev * v3_dev, unsigned int reg_num,
111 void * src, unsigned int length) {
112 struct host_pci_device * host_dev = v3_dev->host_data;
114 if (host_dev->type == PASSTHROUGH) {
115 return write_hw_pci_config(host_dev, reg_num, src, length);
118 printk("Error in config write handler\n");
122 static int host_pci_config_read(struct v3_host_pci_dev * v3_dev, unsigned int reg_num,
123 void * dst, unsigned int length) {
124 struct host_pci_device * host_dev = v3_dev->host_data;
126 if (host_dev->type == PASSTHROUGH) {
127 return read_hw_pci_config(host_dev, reg_num, dst, length);
130 printk("Error in config read handler\n");
135 static int host_pci_ack_irq(struct v3_host_pci_dev * v3_dev, unsigned int vector) {
136 struct host_pci_device * host_dev = v3_dev->host_data;
138 if (host_dev->type == PASSTHROUGH) {
139 return hw_ack_irq(host_dev, vector);
142 printk("Error in config irq ack handler\n");
148 static int host_pci_cmd(struct v3_host_pci_dev * v3_dev, host_pci_cmd_t cmd, u64 arg) {
149 struct host_pci_device * host_dev = v3_dev->host_data;
151 if (host_dev->type == PASSTHROUGH) {
152 return hw_pci_cmd(host_dev, cmd, arg);
155 printk("Error in config pci cmd handler\n");
160 static struct v3_host_pci_hooks pci_hooks = {
161 .request_device = request_pci_dev,
162 .config_write = host_pci_config_write,
163 .config_read = host_pci_config_read,
164 .ack_irq = host_pci_ack_irq,
165 .pci_cmd = host_pci_cmd,
171 static int register_pci_hw_dev(unsigned int cmd, unsigned long arg) {
172 void __user * argp = (void __user *)arg;
173 struct v3_hw_pci_dev hw_dev_arg ;
174 struct host_pci_device * host_dev = NULL;
178 if (copy_from_user(&hw_dev_arg, argp, sizeof(struct v3_hw_pci_dev))) {
179 printk("%s(%d): copy from user error...\n", __FILE__, __LINE__);
183 host_dev = kzalloc(sizeof(struct host_pci_device), GFP_KERNEL);
186 strncpy(host_dev->name, hw_dev_arg.name, 128);
187 host_dev->name[127] = 0;
188 host_dev->v3_dev.host_data = host_dev;
191 host_dev->type = PASSTHROUGH;
192 host_dev->hw_dev.bus = hw_dev_arg.bus;
193 host_dev->hw_dev.devfn = PCI_DEVFN(hw_dev_arg.dev, hw_dev_arg.func);
196 palacios_spinlock_lock_irqsave(&lock, flags);
197 if (!find_dev_by_name(hw_dev_arg.name)) {
198 list_add(&(host_dev->dev_node), &device_list);
201 palacios_spinlock_unlock_irqrestore(&lock, flags);
204 // Error device already exists
205 palacios_free(host_dev);
210 setup_hw_pci_dev(host_dev);
216 static int register_pci_user_dev(unsigned int cmd, unsigned long arg) {
223 static int host_pci_init( void ) {
224 INIT_LIST_HEAD(&(device_list));
225 palacios_spinlock_init(&lock);
227 V3_Init_Host_PCI(&pci_hooks);
230 add_global_ctrl(V3_ADD_PCI_HW_DEV, register_pci_hw_dev);
231 add_global_ctrl(V3_ADD_PCI_USER_DEV, register_pci_user_dev);
236 static int host_pci_deinit(void) {
237 remove_global_ctrl(V3_ADD_PCI_USER_DEV);
238 remove_global_ctrl(V3_ADD_PCI_HW_DEV);
240 palacios_spinlock_deinit(&lock);
244 static struct linux_ext host_pci_ext = {
246 .init = host_pci_init,
247 .deinit = host_pci_deinit,
252 register_extension(&host_pci_ext);