Commit f2db7361 authored by Vishnu DASA's avatar Vishnu DASA Committed by Greg Kroah-Hartman

VMCI: Support upto 64-bit PPNs

Add support in the VMCI driver to handle upto 64-bit PPNs when the VMCI
device exposes the capability for 64-bit PPNs.
Reviewed-by: default avatarAdit Ranadive <aditr@vmware.com>
Reviewed-by: default avatarJorgen Hansen <jhansen@vmware.com>
Signed-off-by: default avatarVishnu Dasa <vdasa@vmware.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent bede03a5
...@@ -330,7 +330,7 @@ int vmci_dbell_host_context_notify(u32 src_cid, struct vmci_handle handle) ...@@ -330,7 +330,7 @@ int vmci_dbell_host_context_notify(u32 src_cid, struct vmci_handle handle)
/* /*
* Register the notification bitmap with the host. * Register the notification bitmap with the host.
*/ */
bool vmci_dbell_register_notification_bitmap(u32 bitmap_ppn) bool vmci_dbell_register_notification_bitmap(u64 bitmap_ppn)
{ {
int result; int result;
struct vmci_notify_bm_set_msg bitmap_set_msg; struct vmci_notify_bm_set_msg bitmap_set_msg;
...@@ -340,11 +340,14 @@ bool vmci_dbell_register_notification_bitmap(u32 bitmap_ppn) ...@@ -340,11 +340,14 @@ bool vmci_dbell_register_notification_bitmap(u32 bitmap_ppn)
bitmap_set_msg.hdr.src = VMCI_ANON_SRC_HANDLE; bitmap_set_msg.hdr.src = VMCI_ANON_SRC_HANDLE;
bitmap_set_msg.hdr.payload_size = sizeof(bitmap_set_msg) - bitmap_set_msg.hdr.payload_size = sizeof(bitmap_set_msg) -
VMCI_DG_HEADERSIZE; VMCI_DG_HEADERSIZE;
bitmap_set_msg.bitmap_ppn = bitmap_ppn; if (vmci_use_ppn64())
bitmap_set_msg.bitmap_ppn64 = bitmap_ppn;
else
bitmap_set_msg.bitmap_ppn32 = (u32) bitmap_ppn;
result = vmci_send_datagram(&bitmap_set_msg.hdr); result = vmci_send_datagram(&bitmap_set_msg.hdr);
if (result != VMCI_SUCCESS) { if (result != VMCI_SUCCESS) {
pr_devel("Failed to register (PPN=%u) as notification bitmap (error=%d)\n", pr_devel("Failed to register (PPN=%llu) as notification bitmap (error=%d)\n",
bitmap_ppn, result); bitmap_ppn, result);
return false; return false;
} }
......
...@@ -45,7 +45,7 @@ struct dbell_cpt_state { ...@@ -45,7 +45,7 @@ struct dbell_cpt_state {
int vmci_dbell_host_context_notify(u32 src_cid, struct vmci_handle handle); int vmci_dbell_host_context_notify(u32 src_cid, struct vmci_handle handle);
int vmci_dbell_get_priv_flags(struct vmci_handle handle, u32 *priv_flags); int vmci_dbell_get_priv_flags(struct vmci_handle handle, u32 *priv_flags);
bool vmci_dbell_register_notification_bitmap(u32 bitmap_ppn); bool vmci_dbell_register_notification_bitmap(u64 bitmap_ppn);
void vmci_dbell_scan_notification_entries(u8 *bitmap); void vmci_dbell_scan_notification_entries(u8 *bitmap);
#endif /* VMCI_DOORBELL_H */ #endif /* VMCI_DOORBELL_H */
...@@ -54,4 +54,6 @@ void vmci_guest_exit(void); ...@@ -54,4 +54,6 @@ void vmci_guest_exit(void);
bool vmci_guest_code_active(void); bool vmci_guest_code_active(void);
u32 vmci_get_vm_context_id(void); u32 vmci_get_vm_context_id(void);
bool vmci_use_ppn64(void);
#endif /* _VMCI_DRIVER_H_ */ #endif /* _VMCI_DRIVER_H_ */
...@@ -64,6 +64,13 @@ struct vmci_guest_device { ...@@ -64,6 +64,13 @@ struct vmci_guest_device {
dma_addr_t notification_base; dma_addr_t notification_base;
}; };
static bool use_ppn64;
bool vmci_use_ppn64(void)
{
return use_ppn64;
}
/* vmci_dev singleton device and supporting data*/ /* vmci_dev singleton device and supporting data*/
struct pci_dev *vmci_pdev; struct pci_dev *vmci_pdev;
static struct vmci_guest_device *vmci_dev_g; static struct vmci_guest_device *vmci_dev_g;
...@@ -432,6 +439,7 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, ...@@ -432,6 +439,7 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
struct vmci_guest_device *vmci_dev; struct vmci_guest_device *vmci_dev;
void __iomem *iobase; void __iomem *iobase;
unsigned int capabilities; unsigned int capabilities;
unsigned int caps_in_use;
unsigned long cmd; unsigned long cmd;
int vmci_err; int vmci_err;
int error; int error;
...@@ -496,6 +504,23 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, ...@@ -496,6 +504,23 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
error = -ENXIO; error = -ENXIO;
goto err_free_data_buffer; goto err_free_data_buffer;
} }
caps_in_use = VMCI_CAPS_DATAGRAM;
/*
* Use 64-bit PPNs if the device supports.
*
* There is no check for the return value of dma_set_mask_and_coherent
* since this driver can handle the default mask values if
* dma_set_mask_and_coherent fails.
*/
if (capabilities & VMCI_CAPS_PPN64) {
dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
use_ppn64 = true;
caps_in_use |= VMCI_CAPS_PPN64;
} else {
dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(44));
use_ppn64 = false;
}
/* /*
* If the hardware supports notifications, we will use that as * If the hardware supports notifications, we will use that as
...@@ -510,14 +535,14 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, ...@@ -510,14 +535,14 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
"Unable to allocate notification bitmap\n"); "Unable to allocate notification bitmap\n");
} else { } else {
memset(vmci_dev->notification_bitmap, 0, PAGE_SIZE); memset(vmci_dev->notification_bitmap, 0, PAGE_SIZE);
capabilities |= VMCI_CAPS_NOTIFICATIONS; caps_in_use |= VMCI_CAPS_NOTIFICATIONS;
} }
} }
dev_info(&pdev->dev, "Using capabilities 0x%x\n", capabilities); dev_info(&pdev->dev, "Using capabilities 0x%x\n", caps_in_use);
/* Let the host know which capabilities we intend to use. */ /* Let the host know which capabilities we intend to use. */
iowrite32(capabilities, vmci_dev->iobase + VMCI_CAPS_ADDR); iowrite32(caps_in_use, vmci_dev->iobase + VMCI_CAPS_ADDR);
/* Set up global device so that we can start sending datagrams */ /* Set up global device so that we can start sending datagrams */
spin_lock_irq(&vmci_dev_spinlock); spin_lock_irq(&vmci_dev_spinlock);
...@@ -529,13 +554,13 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, ...@@ -529,13 +554,13 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
* Register notification bitmap with device if that capability is * Register notification bitmap with device if that capability is
* used. * used.
*/ */
if (capabilities & VMCI_CAPS_NOTIFICATIONS) { if (caps_in_use & VMCI_CAPS_NOTIFICATIONS) {
unsigned long bitmap_ppn = unsigned long bitmap_ppn =
vmci_dev->notification_base >> PAGE_SHIFT; vmci_dev->notification_base >> PAGE_SHIFT;
if (!vmci_dbell_register_notification_bitmap(bitmap_ppn)) { if (!vmci_dbell_register_notification_bitmap(bitmap_ppn)) {
dev_warn(&pdev->dev, dev_warn(&pdev->dev,
"VMCI device unable to register notification bitmap with PPN 0x%x\n", "VMCI device unable to register notification bitmap with PPN 0x%lx\n",
(u32) bitmap_ppn); bitmap_ppn);
error = -ENXIO; error = -ENXIO;
goto err_remove_vmci_dev_g; goto err_remove_vmci_dev_g;
} }
...@@ -611,7 +636,7 @@ static int vmci_guest_probe_device(struct pci_dev *pdev, ...@@ -611,7 +636,7 @@ static int vmci_guest_probe_device(struct pci_dev *pdev,
/* Enable specific interrupt bits. */ /* Enable specific interrupt bits. */
cmd = VMCI_IMR_DATAGRAM; cmd = VMCI_IMR_DATAGRAM;
if (capabilities & VMCI_CAPS_NOTIFICATIONS) if (caps_in_use & VMCI_CAPS_NOTIFICATIONS)
cmd |= VMCI_IMR_NOTIFICATION; cmd |= VMCI_IMR_NOTIFICATION;
iowrite32(cmd, vmci_dev->iobase + VMCI_IMR_ADDR); iowrite32(cmd, vmci_dev->iobase + VMCI_IMR_ADDR);
......
...@@ -435,8 +435,8 @@ static int qp_alloc_ppn_set(void *prod_q, ...@@ -435,8 +435,8 @@ static int qp_alloc_ppn_set(void *prod_q,
void *cons_q, void *cons_q,
u64 num_consume_pages, struct ppn_set *ppn_set) u64 num_consume_pages, struct ppn_set *ppn_set)
{ {
u32 *produce_ppns; u64 *produce_ppns;
u32 *consume_ppns; u64 *consume_ppns;
struct vmci_queue *produce_q = prod_q; struct vmci_queue *produce_q = prod_q;
struct vmci_queue *consume_q = cons_q; struct vmci_queue *consume_q = cons_q;
u64 i; u64 i;
...@@ -462,31 +462,13 @@ static int qp_alloc_ppn_set(void *prod_q, ...@@ -462,31 +462,13 @@ static int qp_alloc_ppn_set(void *prod_q,
return VMCI_ERROR_NO_MEM; return VMCI_ERROR_NO_MEM;
} }
for (i = 0; i < num_produce_pages; i++) { for (i = 0; i < num_produce_pages; i++)
unsigned long pfn;
produce_ppns[i] = produce_ppns[i] =
produce_q->kernel_if->u.g.pas[i] >> PAGE_SHIFT; produce_q->kernel_if->u.g.pas[i] >> PAGE_SHIFT;
pfn = produce_ppns[i];
/* Fail allocation if PFN isn't supported by hypervisor. */
if (sizeof(pfn) > sizeof(*produce_ppns)
&& pfn != produce_ppns[i])
goto ppn_error;
}
for (i = 0; i < num_consume_pages; i++) {
unsigned long pfn;
for (i = 0; i < num_consume_pages; i++)
consume_ppns[i] = consume_ppns[i] =
consume_q->kernel_if->u.g.pas[i] >> PAGE_SHIFT; consume_q->kernel_if->u.g.pas[i] >> PAGE_SHIFT;
pfn = consume_ppns[i];
/* Fail allocation if PFN isn't supported by hypervisor. */
if (sizeof(pfn) > sizeof(*consume_ppns)
&& pfn != consume_ppns[i])
goto ppn_error;
}
ppn_set->num_produce_pages = num_produce_pages; ppn_set->num_produce_pages = num_produce_pages;
ppn_set->num_consume_pages = num_consume_pages; ppn_set->num_consume_pages = num_consume_pages;
...@@ -494,11 +476,6 @@ static int qp_alloc_ppn_set(void *prod_q, ...@@ -494,11 +476,6 @@ static int qp_alloc_ppn_set(void *prod_q,
ppn_set->consume_ppns = consume_ppns; ppn_set->consume_ppns = consume_ppns;
ppn_set->initialized = true; ppn_set->initialized = true;
return VMCI_SUCCESS; return VMCI_SUCCESS;
ppn_error:
kfree(produce_ppns);
kfree(consume_ppns);
return VMCI_ERROR_INVALID_ARGS;
} }
/* /*
...@@ -520,12 +497,28 @@ static void qp_free_ppn_set(struct ppn_set *ppn_set) ...@@ -520,12 +497,28 @@ static void qp_free_ppn_set(struct ppn_set *ppn_set)
*/ */
static int qp_populate_ppn_set(u8 *call_buf, const struct ppn_set *ppn_set) static int qp_populate_ppn_set(u8 *call_buf, const struct ppn_set *ppn_set)
{ {
memcpy(call_buf, ppn_set->produce_ppns, if (vmci_use_ppn64()) {
ppn_set->num_produce_pages * sizeof(*ppn_set->produce_ppns)); memcpy(call_buf, ppn_set->produce_ppns,
memcpy(call_buf + ppn_set->num_produce_pages *
ppn_set->num_produce_pages * sizeof(*ppn_set->produce_ppns), sizeof(*ppn_set->produce_ppns));
ppn_set->consume_ppns, memcpy(call_buf +
ppn_set->num_consume_pages * sizeof(*ppn_set->consume_ppns)); ppn_set->num_produce_pages *
sizeof(*ppn_set->produce_ppns),
ppn_set->consume_ppns,
ppn_set->num_consume_pages *
sizeof(*ppn_set->consume_ppns));
} else {
int i;
u32 *ppns = (u32 *) call_buf;
for (i = 0; i < ppn_set->num_produce_pages; i++)
ppns[i] = (u32) ppn_set->produce_ppns[i];
ppns = &ppns[ppn_set->num_produce_pages];
for (i = 0; i < ppn_set->num_consume_pages; i++)
ppns[i] = (u32) ppn_set->consume_ppns[i];
}
return VMCI_SUCCESS; return VMCI_SUCCESS;
} }
...@@ -951,13 +944,15 @@ static int qp_alloc_hypercall(const struct qp_guest_endpoint *entry) ...@@ -951,13 +944,15 @@ static int qp_alloc_hypercall(const struct qp_guest_endpoint *entry)
{ {
struct vmci_qp_alloc_msg *alloc_msg; struct vmci_qp_alloc_msg *alloc_msg;
size_t msg_size; size_t msg_size;
size_t ppn_size;
int result; int result;
if (!entry || entry->num_ppns <= 2) if (!entry || entry->num_ppns <= 2)
return VMCI_ERROR_INVALID_ARGS; return VMCI_ERROR_INVALID_ARGS;
ppn_size = vmci_use_ppn64() ? sizeof(u64) : sizeof(u32);
msg_size = sizeof(*alloc_msg) + msg_size = sizeof(*alloc_msg) +
(size_t) entry->num_ppns * sizeof(u32); (size_t) entry->num_ppns * ppn_size;
alloc_msg = kmalloc(msg_size, GFP_KERNEL); alloc_msg = kmalloc(msg_size, GFP_KERNEL);
if (!alloc_msg) if (!alloc_msg)
return VMCI_ERROR_NO_MEM; return VMCI_ERROR_NO_MEM;
......
...@@ -28,8 +28,8 @@ typedef int (*vmci_event_release_cb) (void *client_data); ...@@ -28,8 +28,8 @@ typedef int (*vmci_event_release_cb) (void *client_data);
struct ppn_set { struct ppn_set {
u64 num_produce_pages; u64 num_produce_pages;
u64 num_consume_pages; u64 num_consume_pages;
u32 *produce_ppns; u64 *produce_ppns;
u32 *consume_ppns; u64 *consume_ppns;
bool initialized; bool initialized;
}; };
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#define VMCI_CAPS_GUESTCALL 0x2 #define VMCI_CAPS_GUESTCALL 0x2
#define VMCI_CAPS_DATAGRAM 0x4 #define VMCI_CAPS_DATAGRAM 0x4
#define VMCI_CAPS_NOTIFICATIONS 0x8 #define VMCI_CAPS_NOTIFICATIONS 0x8
#define VMCI_CAPS_PPN64 0x10
/* Interrupt Cause register bits. */ /* Interrupt Cause register bits. */
#define VMCI_ICR_DATAGRAM 0x1 #define VMCI_ICR_DATAGRAM 0x1
...@@ -569,8 +570,10 @@ struct vmci_resource_query_msg { ...@@ -569,8 +570,10 @@ struct vmci_resource_query_msg {
*/ */
struct vmci_notify_bm_set_msg { struct vmci_notify_bm_set_msg {
struct vmci_datagram hdr; struct vmci_datagram hdr;
u32 bitmap_ppn; union {
u32 _pad; u32 bitmap_ppn32;
u64 bitmap_ppn64;
};
}; };
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment