mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-09 06:04:05 +08:00
um: virt-pci: don't do DMA from stack
When enabling VMAP_STACK, SG helpers immediately complained that we were doing DMA from stack. Use per-CPU variables to avoid that. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Richard Weinberger <richard@nod.at>
This commit is contained in:
parent
1568cb0e6d
commit
4a22c4cebd
@ -56,6 +56,13 @@ static unsigned long um_pci_msi_used[BITS_TO_LONGS(MAX_MSI_VECTORS)];
|
|||||||
|
|
||||||
#define UM_VIRT_PCI_MAXDELAY 40000
|
#define UM_VIRT_PCI_MAXDELAY 40000
|
||||||
|
|
||||||
|
struct um_pci_message_buffer {
|
||||||
|
struct virtio_pcidev_msg hdr;
|
||||||
|
u8 data[8];
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct um_pci_message_buffer __percpu *um_pci_msg_bufs;
|
||||||
|
|
||||||
static int um_pci_send_cmd(struct um_pci_device *dev,
|
static int um_pci_send_cmd(struct um_pci_device *dev,
|
||||||
struct virtio_pcidev_msg *cmd,
|
struct virtio_pcidev_msg *cmd,
|
||||||
unsigned int cmd_size,
|
unsigned int cmd_size,
|
||||||
@ -68,11 +75,12 @@ static int um_pci_send_cmd(struct um_pci_device *dev,
|
|||||||
[1] = extra ? &extra_sg : &in_sg,
|
[1] = extra ? &extra_sg : &in_sg,
|
||||||
[2] = extra ? &in_sg : NULL,
|
[2] = extra ? &in_sg : NULL,
|
||||||
};
|
};
|
||||||
|
struct um_pci_message_buffer *buf;
|
||||||
int delay_count = 0;
|
int delay_count = 0;
|
||||||
int ret, len;
|
int ret, len;
|
||||||
bool posted;
|
bool posted;
|
||||||
|
|
||||||
if (WARN_ON(cmd_size < sizeof(*cmd)))
|
if (WARN_ON(cmd_size < sizeof(*cmd) || cmd_size > sizeof(*buf)))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
switch (cmd->op) {
|
switch (cmd->op) {
|
||||||
@ -88,6 +96,9 @@ static int um_pci_send_cmd(struct um_pci_device *dev,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buf = get_cpu_var(um_pci_msg_bufs);
|
||||||
|
memcpy(buf, cmd, cmd_size);
|
||||||
|
|
||||||
if (posted) {
|
if (posted) {
|
||||||
u8 *ncmd = kmalloc(cmd_size + extra_size, GFP_ATOMIC);
|
u8 *ncmd = kmalloc(cmd_size + extra_size, GFP_ATOMIC);
|
||||||
|
|
||||||
@ -102,7 +113,10 @@ static int um_pci_send_cmd(struct um_pci_device *dev,
|
|||||||
} else {
|
} else {
|
||||||
/* try without allocating memory */
|
/* try without allocating memory */
|
||||||
posted = false;
|
posted = false;
|
||||||
|
cmd = (void *)buf;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
cmd = (void *)buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
sg_init_one(&out_sg, cmd, cmd_size);
|
sg_init_one(&out_sg, cmd, cmd_size);
|
||||||
@ -118,11 +132,12 @@ static int um_pci_send_cmd(struct um_pci_device *dev,
|
|||||||
posted ? cmd : HANDLE_NO_FREE(cmd),
|
posted ? cmd : HANDLE_NO_FREE(cmd),
|
||||||
GFP_ATOMIC);
|
GFP_ATOMIC);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
goto out;
|
||||||
|
|
||||||
if (posted) {
|
if (posted) {
|
||||||
virtqueue_kick(dev->cmd_vq);
|
virtqueue_kick(dev->cmd_vq);
|
||||||
return 0;
|
ret = 0;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* kick and poll for getting a response on the queue */
|
/* kick and poll for getting a response on the queue */
|
||||||
@ -148,6 +163,8 @@ static int um_pci_send_cmd(struct um_pci_device *dev,
|
|||||||
}
|
}
|
||||||
clear_bit(UM_PCI_STAT_WAITING, &dev->status);
|
clear_bit(UM_PCI_STAT_WAITING, &dev->status);
|
||||||
|
|
||||||
|
out:
|
||||||
|
put_cpu_var(um_pci_msg_bufs);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,12 +178,17 @@ static unsigned long um_pci_cfgspace_read(void *priv, unsigned int offset,
|
|||||||
.size = size,
|
.size = size,
|
||||||
.addr = offset,
|
.addr = offset,
|
||||||
};
|
};
|
||||||
/* maximum size - we may only use parts of it */
|
/* buf->data is maximum size - we may only use parts of it */
|
||||||
u8 data[8];
|
struct um_pci_message_buffer *buf;
|
||||||
|
u8 *data;
|
||||||
|
unsigned long ret = ~0ULL;
|
||||||
|
|
||||||
if (!dev)
|
if (!dev)
|
||||||
return ~0ULL;
|
return ~0ULL;
|
||||||
|
|
||||||
|
buf = get_cpu_var(um_pci_msg_bufs);
|
||||||
|
data = buf->data;
|
||||||
|
|
||||||
memset(data, 0xff, sizeof(data));
|
memset(data, 0xff, sizeof(data));
|
||||||
|
|
||||||
switch (size) {
|
switch (size) {
|
||||||
@ -179,27 +201,34 @@ static unsigned long um_pci_cfgspace_read(void *priv, unsigned int offset,
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
WARN(1, "invalid config space read size %d\n", size);
|
WARN(1, "invalid config space read size %d\n", size);
|
||||||
return ~0ULL;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (um_pci_send_cmd(dev, &hdr, sizeof(hdr), NULL, 0,
|
if (um_pci_send_cmd(dev, &hdr, sizeof(hdr), NULL, 0, data, 8))
|
||||||
data, sizeof(data)))
|
goto out;
|
||||||
return ~0ULL;
|
|
||||||
|
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 1:
|
case 1:
|
||||||
return data[0];
|
ret = data[0];
|
||||||
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
return le16_to_cpup((void *)data);
|
ret = le16_to_cpup((void *)data);
|
||||||
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
return le32_to_cpup((void *)data);
|
ret = le32_to_cpup((void *)data);
|
||||||
|
break;
|
||||||
#ifdef CONFIG_64BIT
|
#ifdef CONFIG_64BIT
|
||||||
case 8:
|
case 8:
|
||||||
return le64_to_cpup((void *)data);
|
ret = le64_to_cpup((void *)data);
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
return ~0ULL;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
put_cpu_var(um_pci_msg_bufs);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void um_pci_cfgspace_write(void *priv, unsigned int offset, int size,
|
static void um_pci_cfgspace_write(void *priv, unsigned int offset, int size,
|
||||||
@ -272,8 +301,13 @@ static void um_pci_bar_copy_from(void *priv, void *buffer,
|
|||||||
static unsigned long um_pci_bar_read(void *priv, unsigned int offset,
|
static unsigned long um_pci_bar_read(void *priv, unsigned int offset,
|
||||||
int size)
|
int size)
|
||||||
{
|
{
|
||||||
/* maximum size - we may only use parts of it */
|
/* buf->data is maximum size - we may only use parts of it */
|
||||||
u8 data[8];
|
struct um_pci_message_buffer *buf;
|
||||||
|
u8 *data;
|
||||||
|
unsigned long ret = ~0ULL;
|
||||||
|
|
||||||
|
buf = get_cpu_var(um_pci_msg_bufs);
|
||||||
|
data = buf->data;
|
||||||
|
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 1:
|
case 1:
|
||||||
@ -285,25 +319,33 @@ static unsigned long um_pci_bar_read(void *priv, unsigned int offset,
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
WARN(1, "invalid config space read size %d\n", size);
|
WARN(1, "invalid config space read size %d\n", size);
|
||||||
return ~0ULL;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
um_pci_bar_copy_from(priv, data, offset, size);
|
um_pci_bar_copy_from(priv, data, offset, size);
|
||||||
|
|
||||||
switch (size) {
|
switch (size) {
|
||||||
case 1:
|
case 1:
|
||||||
return data[0];
|
ret = data[0];
|
||||||
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
return le16_to_cpup((void *)data);
|
ret = le16_to_cpup((void *)data);
|
||||||
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
return le32_to_cpup((void *)data);
|
ret = le32_to_cpup((void *)data);
|
||||||
|
break;
|
||||||
#ifdef CONFIG_64BIT
|
#ifdef CONFIG_64BIT
|
||||||
case 8:
|
case 8:
|
||||||
return le64_to_cpup((void *)data);
|
ret = le64_to_cpup((void *)data);
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
return ~0ULL;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
put_cpu_var(um_pci_msg_bufs);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void um_pci_bar_copy_to(void *priv, unsigned int offset,
|
static void um_pci_bar_copy_to(void *priv, unsigned int offset,
|
||||||
@ -823,10 +865,16 @@ static int um_pci_init(void)
|
|||||||
"No virtio device ID configured for PCI - no PCI support\n"))
|
"No virtio device ID configured for PCI - no PCI support\n"))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bridge = pci_alloc_host_bridge(0);
|
um_pci_msg_bufs = alloc_percpu(struct um_pci_message_buffer);
|
||||||
if (!bridge)
|
if (!um_pci_msg_bufs)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
bridge = pci_alloc_host_bridge(0);
|
||||||
|
if (!bridge) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto free;
|
||||||
|
}
|
||||||
|
|
||||||
um_pci_fwnode = irq_domain_alloc_named_fwnode("um-pci");
|
um_pci_fwnode = irq_domain_alloc_named_fwnode("um-pci");
|
||||||
if (!um_pci_fwnode) {
|
if (!um_pci_fwnode) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
@ -878,8 +926,11 @@ free:
|
|||||||
irq_domain_remove(um_pci_inner_domain);
|
irq_domain_remove(um_pci_inner_domain);
|
||||||
if (um_pci_fwnode)
|
if (um_pci_fwnode)
|
||||||
irq_domain_free_fwnode(um_pci_fwnode);
|
irq_domain_free_fwnode(um_pci_fwnode);
|
||||||
|
if (bridge) {
|
||||||
pci_free_resource_list(&bridge->windows);
|
pci_free_resource_list(&bridge->windows);
|
||||||
pci_free_host_bridge(bridge);
|
pci_free_host_bridge(bridge);
|
||||||
|
}
|
||||||
|
free_percpu(um_pci_msg_bufs);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
module_init(um_pci_init);
|
module_init(um_pci_init);
|
||||||
@ -891,5 +942,6 @@ static void um_pci_exit(void)
|
|||||||
irq_domain_remove(um_pci_inner_domain);
|
irq_domain_remove(um_pci_inner_domain);
|
||||||
pci_free_resource_list(&bridge->windows);
|
pci_free_resource_list(&bridge->windows);
|
||||||
pci_free_host_bridge(bridge);
|
pci_free_host_bridge(bridge);
|
||||||
|
free_percpu(um_pci_msg_bufs);
|
||||||
}
|
}
|
||||||
module_exit(um_pci_exit);
|
module_exit(um_pci_exit);
|
||||||
|
Loading…
Reference in New Issue
Block a user