in controller/pci-hyperv.c [2685:2823]
static void hv_pci_onchannelcallback(void *context)
{
const int packet_size = 0x100;
int ret;
struct hv_pcibus_device *hbus = context;
u32 bytes_recvd;
u64 req_id;
struct vmpacket_descriptor *desc;
unsigned char *buffer;
int bufferlen = packet_size;
struct pci_packet *comp_packet;
struct pci_response *response;
struct pci_incoming_message *new_message;
struct pci_bus_relations *bus_rel;
struct pci_bus_relations2 *bus_rel2;
struct pci_dev_inval_block *inval;
struct pci_dev_incoming *dev_message;
struct hv_pci_dev *hpdev;
buffer = kmalloc(bufferlen, GFP_ATOMIC);
if (!buffer)
return;
while (1) {
ret = vmbus_recvpacket_raw(hbus->hdev->channel, buffer,
bufferlen, &bytes_recvd, &req_id);
if (ret == -ENOBUFS) {
kfree(buffer);
/* Handle large packet */
bufferlen = bytes_recvd;
buffer = kmalloc(bytes_recvd, GFP_ATOMIC);
if (!buffer)
return;
continue;
}
/* Zero length indicates there are no more packets. */
if (ret || !bytes_recvd)
break;
/*
* All incoming packets must be at least as large as a
* response.
*/
if (bytes_recvd <= sizeof(struct pci_response))
continue;
desc = (struct vmpacket_descriptor *)buffer;
switch (desc->type) {
case VM_PKT_COMP:
/*
* The host is trusted, and thus it's safe to interpret
* this transaction ID as a pointer.
*/
comp_packet = (struct pci_packet *)req_id;
response = (struct pci_response *)buffer;
comp_packet->completion_func(comp_packet->compl_ctxt,
response,
bytes_recvd);
break;
case VM_PKT_DATA_INBAND:
new_message = (struct pci_incoming_message *)buffer;
switch (new_message->message_type.type) {
case PCI_BUS_RELATIONS:
bus_rel = (struct pci_bus_relations *)buffer;
if (bytes_recvd <
struct_size(bus_rel, func,
bus_rel->device_count)) {
dev_err(&hbus->hdev->device,
"bus relations too small\n");
break;
}
hv_pci_devices_present(hbus, bus_rel);
break;
case PCI_BUS_RELATIONS2:
bus_rel2 = (struct pci_bus_relations2 *)buffer;
if (bytes_recvd <
struct_size(bus_rel2, func,
bus_rel2->device_count)) {
dev_err(&hbus->hdev->device,
"bus relations v2 too small\n");
break;
}
hv_pci_devices_present2(hbus, bus_rel2);
break;
case PCI_EJECT:
dev_message = (struct pci_dev_incoming *)buffer;
hpdev = get_pcichild_wslot(hbus,
dev_message->wslot.slot);
if (hpdev) {
hv_pci_eject_device(hpdev);
put_pcichild(hpdev);
}
break;
case PCI_INVALIDATE_BLOCK:
inval = (struct pci_dev_inval_block *)buffer;
hpdev = get_pcichild_wslot(hbus,
inval->wslot.slot);
if (hpdev) {
if (hpdev->block_invalidate) {
hpdev->block_invalidate(
hpdev->invalidate_context,
inval->block_mask);
}
put_pcichild(hpdev);
}
break;
default:
dev_warn(&hbus->hdev->device,
"Unimplemented protocol message %x\n",
new_message->message_type.type);
break;
}
break;
default:
dev_err(&hbus->hdev->device,
"unhandled packet type %d, tid %llx len %d\n",
desc->type, req_id, bytes_recvd);
break;
}
}
kfree(buffer);
}