|
|
1.1 ! root 1: /* ! 2: * QEMU PCI hotplug support ! 3: * ! 4: * Copyright (c) 2004 Fabrice Bellard ! 5: * ! 6: * Permission is hereby granted, free of charge, to any person obtaining a copy ! 7: * of this software and associated documentation files (the "Software"), to deal ! 8: * in the Software without restriction, including without limitation the rights ! 9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ! 10: * copies of the Software, and to permit persons to whom the Software is ! 11: * furnished to do so, subject to the following conditions: ! 12: * ! 13: * The above copyright notice and this permission notice shall be included in ! 14: * all copies or substantial portions of the Software. ! 15: * ! 16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ! 17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ! 19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ! 20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ! 21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ! 22: * THE SOFTWARE. ! 23: */ ! 24: ! 25: #include "hw.h" ! 26: #include "boards.h" ! 27: #include "pci.h" ! 28: #include "net.h" ! 29: #include "sysemu.h" ! 30: #include "pc.h" ! 31: #include "console.h" ! 32: #include "block_int.h" ! 33: #include "virtio-blk.h" ! 34: ! 35: #if defined(TARGET_I386) || defined(TARGET_X86_64) ! 36: static PCIDevice *qemu_pci_hot_add_nic(PCIBus *pci_bus, const char *opts) ! 37: { ! 38: int ret; ! 39: ! 40: ret = net_client_init ("nic", opts); ! 41: if (ret < 0 || !nd_table[ret].model) ! 42: return NULL; ! 43: return pci_nic_init (pci_bus, &nd_table[ret], -1, "rtl8139"); ! 44: } ! 45: ! 46: void drive_hot_add(const char *pci_addr, const char *opts) ! 47: { ! 48: int dom, pci_bus; ! 49: unsigned slot; ! 50: int drive_idx, type, bus; ! 51: int success = 0; ! 52: PCIDevice *dev; ! 53: ! 54: if (pci_read_devaddr(pci_addr, &dom, &pci_bus, &slot)) { ! 55: term_printf("Invalid pci address\n"); ! 56: return; ! 57: } ! 58: ! 59: dev = pci_find_device(pci_bus, slot, 0); ! 60: if (!dev) { ! 61: term_printf("no pci device with address %s\n", pci_addr); ! 62: return; ! 63: } ! 64: ! 65: drive_idx = add_init_drive(opts); ! 66: if (drive_idx < 0) ! 67: return; ! 68: type = drives_table[drive_idx].type; ! 69: bus = drive_get_max_bus (type); ! 70: ! 71: switch (type) { ! 72: case IF_SCSI: ! 73: success = 1; ! 74: lsi_scsi_attach (dev, drives_table[drive_idx].bdrv, ! 75: drives_table[drive_idx].unit); ! 76: break; ! 77: default: ! 78: term_printf("Can't hot-add drive to type %d\n", type); ! 79: } ! 80: ! 81: if (success) ! 82: term_printf("OK bus %d, unit %d\n", drives_table[drive_idx].bus, ! 83: drives_table[drive_idx].unit); ! 84: return; ! 85: } ! 86: ! 87: static PCIDevice *qemu_pci_hot_add_storage(PCIBus *pci_bus, const char *opts) ! 88: { ! 89: void *opaque = NULL; ! 90: int type = -1, drive_idx = -1; ! 91: char buf[128]; ! 92: ! 93: if (get_param_value(buf, sizeof(buf), "if", opts)) { ! 94: if (!strcmp(buf, "scsi")) ! 95: type = IF_SCSI; ! 96: else if (!strcmp(buf, "virtio")) { ! 97: type = IF_VIRTIO; ! 98: } ! 99: } else { ! 100: term_printf("no if= specified\n"); ! 101: return NULL; ! 102: } ! 103: ! 104: if (get_param_value(buf, sizeof(buf), "file", opts)) { ! 105: drive_idx = add_init_drive(opts); ! 106: if (drive_idx < 0) ! 107: return NULL; ! 108: } else if (type == IF_VIRTIO) { ! 109: term_printf("virtio requires a backing file/device.\n"); ! 110: return NULL; ! 111: } ! 112: ! 113: switch (type) { ! 114: case IF_SCSI: ! 115: opaque = lsi_scsi_init (pci_bus, -1); ! 116: if (opaque && drive_idx >= 0) ! 117: lsi_scsi_attach (opaque, drives_table[drive_idx].bdrv, ! 118: drives_table[drive_idx].unit); ! 119: break; ! 120: case IF_VIRTIO: ! 121: opaque = virtio_blk_init (pci_bus, drives_table[drive_idx].bdrv); ! 122: break; ! 123: default: ! 124: term_printf ("type %s not a hotpluggable PCI device.\n", buf); ! 125: } ! 126: ! 127: return opaque; ! 128: } ! 129: ! 130: void pci_device_hot_add(const char *pci_addr, const char *type, const char *opts) ! 131: { ! 132: PCIDevice *dev = NULL; ! 133: PCIBus *pci_bus; ! 134: int dom, bus; ! 135: unsigned slot; ! 136: ! 137: if (pci_assign_devaddr(pci_addr, &dom, &bus, &slot)) { ! 138: term_printf("Invalid pci address\n"); ! 139: return; ! 140: } ! 141: ! 142: pci_bus = pci_find_bus(bus); ! 143: if (!pci_bus) { ! 144: term_printf("Can't find pci_bus %d\n", bus); ! 145: return; ! 146: } ! 147: ! 148: if (strcmp(type, "nic") == 0) ! 149: dev = qemu_pci_hot_add_nic(pci_bus, opts); ! 150: else if (strcmp(type, "storage") == 0) ! 151: dev = qemu_pci_hot_add_storage(pci_bus, opts); ! 152: else ! 153: term_printf("invalid type: %s\n", type); ! 154: ! 155: if (dev) { ! 156: qemu_system_device_hot_add(bus, PCI_SLOT(dev->devfn), 1); ! 157: term_printf("OK domain %d, bus %d, slot %d, function %d\n", ! 158: 0, pci_bus_num(dev->bus), PCI_SLOT(dev->devfn), ! 159: PCI_FUNC(dev->devfn)); ! 160: } else ! 161: term_printf("failed to add %s\n", opts); ! 162: } ! 163: #endif ! 164: ! 165: void pci_device_hot_remove(const char *pci_addr) ! 166: { ! 167: PCIDevice *d; ! 168: int dom, bus; ! 169: unsigned slot; ! 170: ! 171: if (pci_read_devaddr(pci_addr, &dom, &bus, &slot)) { ! 172: term_printf("Invalid pci address\n"); ! 173: return; ! 174: } ! 175: ! 176: d = pci_find_device(bus, slot, 0); ! 177: if (!d) { ! 178: term_printf("slot %d empty\n", slot); ! 179: return; ! 180: } ! 181: ! 182: qemu_system_device_hot_add(bus, slot, 0); ! 183: } ! 184: ! 185: static int pci_match_fn(void *dev_private, void *arg) ! 186: { ! 187: PCIDevice *dev = dev_private; ! 188: PCIDevice *match = arg; ! 189: ! 190: return (dev == match); ! 191: } ! 192: ! 193: /* ! 194: * OS has executed _EJ0 method, we now can remove the device ! 195: */ ! 196: void pci_device_hot_remove_success(int pcibus, int slot) ! 197: { ! 198: PCIDevice *d = pci_find_device(pcibus, slot, 0); ! 199: int class_code; ! 200: ! 201: if (!d) { ! 202: term_printf("invalid slot %d\n", slot); ! 203: return; ! 204: } ! 205: ! 206: class_code = d->config_read(d, PCI_CLASS_DEVICE+1, 1); ! 207: ! 208: switch(class_code) { ! 209: case PCI_BASE_CLASS_STORAGE: ! 210: destroy_bdrvs(pci_match_fn, d); ! 211: break; ! 212: case PCI_BASE_CLASS_NETWORK: ! 213: destroy_nic(pci_match_fn, d); ! 214: break; ! 215: } ! 216: ! 217: pci_unregister_device(d); ! 218: } ! 219:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.