diff options
Diffstat (limited to 'drivers/gpu/nvgpu')
-rw-r--r-- | drivers/gpu/nvgpu/Makefile | 4 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/module.c | 70 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/module.h | 3 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/pci.c | 16 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/sim.c | 314 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/sim.h | 19 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/sim_pci.c | 326 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/sim_pci.h | 5 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/sim.c | 311 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/common/sim_pci.c | 260 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a.h | 4 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/sim_gk20a.h | 4 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/include/nvgpu/hw_sim.h (renamed from drivers/gpu/nvgpu/include/nvgpu/hw/gk20a/hw_sim_gk20a.h) | 8 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/include/nvgpu/hw_sim_pci.h (renamed from drivers/gpu/nvgpu/common/linux/hw_sim_pci.h) | 0 |
14 files changed, 715 insertions, 629 deletions
diff --git a/drivers/gpu/nvgpu/Makefile b/drivers/gpu/nvgpu/Makefile index fd5e8bb2..32166f31 100644 --- a/drivers/gpu/nvgpu/Makefile +++ b/drivers/gpu/nvgpu/Makefile | |||
@@ -122,7 +122,9 @@ nvgpu-y := \ | |||
122 | boardobj/boardobjgrp.o \ | 122 | boardobj/boardobjgrp.o \ |
123 | boardobj/boardobjgrpmask.o \ | 123 | boardobj/boardobjgrpmask.o \ |
124 | boardobj/boardobjgrp_e255.o \ | 124 | boardobj/boardobjgrp_e255.o \ |
125 | boardobj/boardobjgrp_e32.o | 125 | boardobj/boardobjgrp_e32.o \ |
126 | common/sim.o \ | ||
127 | common/sim_pci.o | ||
126 | 128 | ||
127 | nvgpu-$(CONFIG_GK20A_VIDMEM) += \ | 129 | nvgpu-$(CONFIG_GK20A_VIDMEM) += \ |
128 | common/mm/vidmem.o \ | 130 | common/mm/vidmem.o \ |
diff --git a/drivers/gpu/nvgpu/common/linux/module.c b/drivers/gpu/nvgpu/common/linux/module.c index 015f2bf8..e2b52dad 100644 --- a/drivers/gpu/nvgpu/common/linux/module.c +++ b/drivers/gpu/nvgpu/common/linux/module.c | |||
@@ -601,7 +601,7 @@ static int gk20a_do_unidle(void *_g) | |||
601 | } | 601 | } |
602 | #endif | 602 | #endif |
603 | 603 | ||
604 | static void __iomem *gk20a_ioremap_resource(struct platform_device *dev, int i, | 604 | void __iomem *nvgpu_ioremap_resource(struct platform_device *dev, int i, |
605 | struct resource **out) | 605 | struct resource **out) |
606 | { | 606 | { |
607 | struct resource *r = platform_get_resource(dev, IORESOURCE_MEM, i); | 607 | struct resource *r = platform_get_resource(dev, IORESOURCE_MEM, i); |
@@ -637,6 +637,7 @@ static irqreturn_t gk20a_intr_thread_stall(int irq, void *dev_id) | |||
637 | void gk20a_remove_support(struct gk20a *g) | 637 | void gk20a_remove_support(struct gk20a *g) |
638 | { | 638 | { |
639 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); | 639 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); |
640 | struct sim_nvgpu_linux *sim_linux; | ||
640 | 641 | ||
641 | tegra_unregister_idle_unidle(gk20a_do_idle); | 642 | tegra_unregister_idle_unidle(gk20a_do_idle); |
642 | 643 | ||
@@ -659,8 +660,13 @@ void gk20a_remove_support(struct gk20a *g) | |||
659 | if (g->mm.remove_support) | 660 | if (g->mm.remove_support) |
660 | g->mm.remove_support(&g->mm); | 661 | g->mm.remove_support(&g->mm); |
661 | 662 | ||
662 | if (g->sim && g->sim->remove_support) | 663 | if (g->sim) { |
663 | g->sim->remove_support(g->sim); | 664 | sim_linux = container_of(g->sim, struct sim_nvgpu_linux, sim); |
665 | if (g->sim->remove_support) | ||
666 | g->sim->remove_support(g); | ||
667 | if (sim_linux->remove_support_linux) | ||
668 | sim_linux->remove_support_linux(g); | ||
669 | } | ||
664 | 670 | ||
665 | /* free mappings to registers, etc */ | 671 | /* free mappings to registers, etc */ |
666 | if (l->regs) { | 672 | if (l->regs) { |
@@ -679,18 +685,13 @@ void gk20a_remove_support(struct gk20a *g) | |||
679 | 685 | ||
680 | static int gk20a_init_support(struct platform_device *dev) | 686 | static int gk20a_init_support(struct platform_device *dev) |
681 | { | 687 | { |
682 | int err = 0; | 688 | int err = -ENOMEM; |
683 | struct gk20a *g = get_gk20a(&dev->dev); | 689 | struct gk20a *g = get_gk20a(&dev->dev); |
684 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); | 690 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); |
685 | struct sim_gk20a_linux *sim_linux = nvgpu_kzalloc(g, sizeof(*sim_linux)); | ||
686 | if (!sim_linux) | ||
687 | goto fail; | ||
688 | |||
689 | g->sim = &sim_linux->sim; | ||
690 | 691 | ||
691 | tegra_register_idle_unidle(gk20a_do_idle, gk20a_do_unidle, g); | 692 | tegra_register_idle_unidle(gk20a_do_idle, gk20a_do_unidle, g); |
692 | 693 | ||
693 | l->regs = gk20a_ioremap_resource(dev, GK20A_BAR0_IORESOURCE_MEM, | 694 | l->regs = nvgpu_ioremap_resource(dev, GK20A_BAR0_IORESOURCE_MEM, |
694 | &l->reg_mem); | 695 | &l->reg_mem); |
695 | if (IS_ERR(l->regs)) { | 696 | if (IS_ERR(l->regs)) { |
696 | nvgpu_err(g, "failed to remap gk20a registers"); | 697 | nvgpu_err(g, "failed to remap gk20a registers"); |
@@ -698,7 +699,7 @@ static int gk20a_init_support(struct platform_device *dev) | |||
698 | goto fail; | 699 | goto fail; |
699 | } | 700 | } |
700 | 701 | ||
701 | l->bar1 = gk20a_ioremap_resource(dev, GK20A_BAR1_IORESOURCE_MEM, | 702 | l->bar1 = nvgpu_ioremap_resource(dev, GK20A_BAR1_IORESOURCE_MEM, |
702 | &l->bar1_mem); | 703 | &l->bar1_mem); |
703 | if (IS_ERR(l->bar1)) { | 704 | if (IS_ERR(l->bar1)) { |
704 | nvgpu_err(g, "failed to remap gk20a bar1"); | 705 | nvgpu_err(g, "failed to remap gk20a bar1"); |
@@ -706,29 +707,28 @@ static int gk20a_init_support(struct platform_device *dev) | |||
706 | goto fail; | 707 | goto fail; |
707 | } | 708 | } |
708 | 709 | ||
709 | if (nvgpu_platform_is_simulation(g)) { | 710 | err = nvgpu_init_sim_support_linux(g, dev); |
710 | g->sim->g = g; | 711 | if (err) |
711 | sim_linux->regs = gk20a_ioremap_resource(dev, | 712 | goto fail; |
712 | GK20A_SIM_IORESOURCE_MEM, | 713 | err = nvgpu_init_sim_support(g); |
713 | &sim_linux->reg_mem); | 714 | if (err) |
714 | if (IS_ERR(sim_linux->regs)) { | 715 | goto fail_sim; |
715 | nvgpu_err(g, "failed to remap gk20a sim regs"); | ||
716 | err = PTR_ERR(sim_linux->regs); | ||
717 | goto fail; | ||
718 | } | ||
719 | |||
720 | err = gk20a_init_sim_support(g); | ||
721 | if (err) | ||
722 | goto fail; | ||
723 | } | ||
724 | 716 | ||
725 | nvgpu_init_usermode_support(g); | 717 | nvgpu_init_usermode_support(g); |
726 | |||
727 | return 0; | 718 | return 0; |
728 | 719 | ||
720 | fail_sim: | ||
721 | nvgpu_remove_sim_support_linux(g); | ||
729 | fail: | 722 | fail: |
730 | nvgpu_kfree(g, sim_linux); | 723 | if (l->regs) { |
731 | g->sim = NULL; | 724 | iounmap(l->regs); |
725 | l->regs = NULL; | ||
726 | } | ||
727 | if (l->bar1) { | ||
728 | iounmap(l->bar1); | ||
729 | l->bar1 = NULL; | ||
730 | } | ||
731 | |||
732 | return err; | 732 | return err; |
733 | } | 733 | } |
734 | 734 | ||
@@ -1227,18 +1227,6 @@ static int gk20a_probe(struct platform_device *dev) | |||
1227 | return 0; | 1227 | return 0; |
1228 | 1228 | ||
1229 | return_err: | 1229 | return_err: |
1230 | /* | ||
1231 | * Make sure to clean up any memory allocs made in this function - | ||
1232 | * especially since we can be called many times due to probe deferal. | ||
1233 | */ | ||
1234 | if (gk20a->sim) { | ||
1235 | struct sim_gk20a_linux *sim_linux; | ||
1236 | sim_linux = container_of(gk20a->sim, | ||
1237 | struct sim_gk20a_linux, | ||
1238 | sim); | ||
1239 | nvgpu_kfree(gk20a, sim_linux); | ||
1240 | } | ||
1241 | |||
1242 | nvgpu_free_enabled_flags(gk20a); | 1230 | nvgpu_free_enabled_flags(gk20a); |
1243 | 1231 | ||
1244 | /* | 1232 | /* |
diff --git a/drivers/gpu/nvgpu/common/linux/module.h b/drivers/gpu/nvgpu/common/linux/module.h index e6aa9ef8..ab4bca03 100644 --- a/drivers/gpu/nvgpu/common/linux/module.h +++ b/drivers/gpu/nvgpu/common/linux/module.h | |||
@@ -25,7 +25,8 @@ int nvgpu_quiesce(struct gk20a *g); | |||
25 | int nvgpu_remove(struct device *dev, struct class *class); | 25 | int nvgpu_remove(struct device *dev, struct class *class); |
26 | void nvgpu_free_irq(struct gk20a *g); | 26 | void nvgpu_free_irq(struct gk20a *g); |
27 | struct device_node *nvgpu_get_node(struct gk20a *g); | 27 | struct device_node *nvgpu_get_node(struct gk20a *g); |
28 | 28 | void __iomem *nvgpu_ioremap_resource(struct platform_device *dev, int i, | |
29 | struct resource **out); | ||
29 | extern struct class nvgpu_class; | 30 | extern struct class nvgpu_class; |
30 | 31 | ||
31 | #endif | 32 | #endif |
diff --git a/drivers/gpu/nvgpu/common/linux/pci.c b/drivers/gpu/nvgpu/common/linux/pci.c index 3c7de4ff..a9bcca70 100644 --- a/drivers/gpu/nvgpu/common/linux/pci.c +++ b/drivers/gpu/nvgpu/common/linux/pci.c | |||
@@ -498,15 +498,29 @@ static int nvgpu_pci_init_support(struct pci_dev *pdev) | |||
498 | goto fail; | 498 | goto fail; |
499 | } | 499 | } |
500 | 500 | ||
501 | err = nvgpu_pci_init_sim_support(g); | 501 | err = nvgpu_init_sim_support_linux_pci(g); |
502 | if (err) | 502 | if (err) |
503 | goto fail; | 503 | goto fail; |
504 | err = nvgpu_init_sim_support_pci(g); | ||
505 | if (err) | ||
506 | goto fail_sim; | ||
504 | 507 | ||
505 | nvgpu_pci_init_usermode_support(l); | 508 | nvgpu_pci_init_usermode_support(l); |
506 | 509 | ||
507 | return 0; | 510 | return 0; |
508 | 511 | ||
512 | fail_sim: | ||
513 | nvgpu_remove_sim_support_linux_pci(g); | ||
509 | fail: | 514 | fail: |
515 | if (l->regs) { | ||
516 | iounmap(l->regs); | ||
517 | l->regs = NULL; | ||
518 | } | ||
519 | if (l->bar1) { | ||
520 | iounmap(l->bar1); | ||
521 | l->bar1 = NULL; | ||
522 | } | ||
523 | |||
510 | return err; | 524 | return err; |
511 | } | 525 | } |
512 | 526 | ||
diff --git a/drivers/gpu/nvgpu/common/linux/sim.c b/drivers/gpu/nvgpu/common/linux/sim.c index 8f016e58..5406035b 100644 --- a/drivers/gpu/nvgpu/common/linux/sim.c +++ b/drivers/gpu/nvgpu/common/linux/sim.c | |||
@@ -23,310 +23,74 @@ | |||
23 | #include <nvgpu/bitops.h> | 23 | #include <nvgpu/bitops.h> |
24 | #include <nvgpu/nvgpu_mem.h> | 24 | #include <nvgpu/nvgpu_mem.h> |
25 | #include <nvgpu/dma.h> | 25 | #include <nvgpu/dma.h> |
26 | #include <nvgpu/soc.h> | ||
27 | #include <nvgpu/hw_sim.h> | ||
26 | #include "gk20a/gk20a.h" | 28 | #include "gk20a/gk20a.h" |
27 | #include "sim.h" | 29 | #include "platform_gk20a.h" |
30 | #include "os_linux.h" | ||
31 | #include "module.h" | ||
32 | #include "sim.h" /* will be removed in next patch */ | ||
28 | 33 | ||
29 | #include <nvgpu/hw/gk20a/hw_sim_gk20a.h> | 34 | void sim_writel(struct sim_nvgpu *sim, u32 r, u32 v) |
30 | |||
31 | static inline void sim_writel(struct sim_gk20a *sim, u32 r, u32 v) | ||
32 | { | 35 | { |
33 | struct sim_gk20a_linux *sim_linux = | 36 | struct sim_nvgpu_linux *sim_linux = |
34 | container_of(sim, struct sim_gk20a_linux, sim); | 37 | container_of(sim, struct sim_nvgpu_linux, sim); |
35 | 38 | ||
36 | writel(v, sim_linux->regs + r); | 39 | writel(v, sim_linux->regs + r); |
37 | } | 40 | } |
38 | 41 | ||
39 | static inline u32 sim_readl(struct sim_gk20a *sim, u32 r) | 42 | u32 sim_readl(struct sim_nvgpu *sim, u32 r) |
40 | { | 43 | { |
41 | struct sim_gk20a_linux *sim_linux = | 44 | struct sim_nvgpu_linux *sim_linux = |
42 | container_of(sim, struct sim_gk20a_linux, sim); | 45 | container_of(sim, struct sim_nvgpu_linux, sim); |
43 | 46 | ||
44 | return readl(sim_linux->regs + r); | 47 | return readl(sim_linux->regs + r); |
45 | } | 48 | } |
46 | 49 | ||
47 | static int gk20a_alloc_sim_buffer(struct gk20a *g, struct nvgpu_mem *mem) | 50 | void nvgpu_remove_sim_support_linux(struct gk20a *g) |
48 | { | 51 | { |
49 | int err; | 52 | struct sim_nvgpu_linux *sim_linux; |
50 | |||
51 | err = nvgpu_dma_alloc(g, PAGE_SIZE, mem); | ||
52 | |||
53 | if (err) | ||
54 | return err; | ||
55 | /* | ||
56 | * create a valid cpu_va mapping | ||
57 | */ | ||
58 | nvgpu_mem_begin(g, mem); | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | 53 | ||
63 | static void gk20a_free_sim_buffer(struct gk20a *g, struct nvgpu_mem *mem) | 54 | if (!g->sim) { |
64 | { | 55 | nvgpu_warn(g, "sim not allocated or not in sim_mode"); |
65 | if (nvgpu_mem_is_valid(mem)) { | 56 | return; |
66 | /* | ||
67 | * invalidate the cpu_va mapping | ||
68 | */ | ||
69 | nvgpu_mem_end(g, mem); | ||
70 | nvgpu_dma_free(g, mem); | ||
71 | } | 57 | } |
72 | 58 | sim_linux = container_of(g->sim, struct sim_nvgpu_linux, sim); | |
73 | memset(mem, 0, sizeof(*mem)); | ||
74 | } | ||
75 | |||
76 | static void gk20a_free_sim_support(struct gk20a *g) | ||
77 | { | ||
78 | gk20a_free_sim_buffer(g, &g->sim->send_bfr); | ||
79 | gk20a_free_sim_buffer(g, &g->sim->recv_bfr); | ||
80 | gk20a_free_sim_buffer(g, &g->sim->msg_bfr); | ||
81 | } | ||
82 | |||
83 | static void gk20a_remove_sim_support(struct sim_gk20a *s) | ||
84 | { | ||
85 | struct gk20a *g = s->g; | ||
86 | struct sim_gk20a_linux *sim_linux = | ||
87 | container_of(g->sim, struct sim_gk20a_linux, sim); | ||
88 | |||
89 | if (sim_linux->regs) | ||
90 | sim_writel(s, sim_config_r(), sim_config_mode_disabled_v()); | ||
91 | |||
92 | if (sim_linux->regs) { | 59 | if (sim_linux->regs) { |
60 | sim_writel(g->sim, sim_config_r(), sim_config_mode_disabled_v()); | ||
93 | iounmap(sim_linux->regs); | 61 | iounmap(sim_linux->regs); |
94 | sim_linux->regs = NULL; | 62 | sim_linux->regs = NULL; |
95 | } | 63 | } |
96 | gk20a_free_sim_support(g); | ||
97 | |||
98 | nvgpu_kfree(g, sim_linux); | 64 | nvgpu_kfree(g, sim_linux); |
99 | g->sim = NULL; | 65 | g->sim = NULL; |
100 | } | 66 | } |
101 | 67 | ||
102 | static inline u32 sim_msg_header_size(void) | 68 | int nvgpu_init_sim_support_linux(struct gk20a *g, |
103 | { | 69 | struct platform_device *dev) |
104 | return 24;/*TBD: fix the header to gt this from NV_VGPU_MSG_HEADER*/ | ||
105 | } | ||
106 | |||
107 | static inline u32 *sim_msg_bfr(struct gk20a *g, u32 byte_offset) | ||
108 | { | ||
109 | u8 *cpu_va; | ||
110 | |||
111 | cpu_va = (u8 *)sim_linux->msg_bfr.cpu_va; | ||
112 | |||
113 | return (u32 *)(cpu_va + byte_offset); | ||
114 | } | ||
115 | |||
116 | static inline u32 *sim_msg_hdr(struct gk20a *g, u32 byte_offset) | ||
117 | { | ||
118 | return sim_msg_bfr(g, byte_offset); /*starts at 0*/ | ||
119 | } | ||
120 | |||
121 | static inline u32 *sim_msg_param(struct gk20a *g, u32 byte_offset) | ||
122 | { | ||
123 | /*starts after msg header/cmn*/ | ||
124 | return sim_msg_bfr(g, byte_offset + sim_msg_header_size()); | ||
125 | } | ||
126 | |||
127 | static inline void sim_write_hdr(struct gk20a *g, u32 func, u32 size) | ||
128 | { | ||
129 | /*memset(g->sim->msg_bfr.kvaddr,0,min(PAGE_SIZE,size));*/ | ||
130 | *sim_msg_hdr(g, sim_msg_signature_r()) = sim_msg_signature_valid_v(); | ||
131 | *sim_msg_hdr(g, sim_msg_result_r()) = sim_msg_result_rpc_pending_v(); | ||
132 | *sim_msg_hdr(g, sim_msg_spare_r()) = sim_msg_spare__init_v(); | ||
133 | *sim_msg_hdr(g, sim_msg_function_r()) = func; | ||
134 | *sim_msg_hdr(g, sim_msg_length_r()) = size + sim_msg_header_size(); | ||
135 | } | ||
136 | |||
137 | static inline u32 sim_escape_read_hdr_size(void) | ||
138 | { | ||
139 | return 12; /*TBD: fix NV_VGPU_SIM_ESCAPE_READ_HEADER*/ | ||
140 | } | ||
141 | |||
142 | static u32 *sim_send_ring_bfr(struct gk20a *g, u32 byte_offset) | ||
143 | { | ||
144 | u8 *cpu_va; | ||
145 | |||
146 | cpu_va = (u8 *)sim_linux->send_bfr.cpu_va; | ||
147 | |||
148 | return (u32 *)(cpu_va + byte_offset); | ||
149 | } | ||
150 | |||
151 | static int rpc_send_message(struct gk20a *g) | ||
152 | { | ||
153 | /* calculations done in units of u32s */ | ||
154 | u32 send_base = sim_send_put_pointer_v(g->sim->send_ring_put) * 2; | ||
155 | u32 dma_offset = send_base + sim_dma_r()/sizeof(u32); | ||
156 | u32 dma_hi_offset = send_base + sim_dma_hi_r()/sizeof(u32); | ||
157 | |||
158 | *sim_send_ring_bfr(g, dma_offset*sizeof(u32)) = | ||
159 | sim_dma_target_phys_pci_coherent_f() | | ||
160 | sim_dma_status_valid_f() | | ||
161 | sim_dma_size_4kb_f() | | ||
162 | sim_dma_addr_lo_f(nvgpu_mem_get_addr(g, &sim_linux->msg_bfr) >> PAGE_SHIFT); | ||
163 | |||
164 | *sim_send_ring_bfr(g, dma_hi_offset*sizeof(u32)) = | ||
165 | u64_hi32(nvgpu_mem_get_addr(g, &g->sim->msg_bfr)); | ||
166 | |||
167 | *sim_msg_hdr(g, sim_msg_sequence_r()) = g->sim->sequence_base++; | ||
168 | |||
169 | g->sim->send_ring_put = (g->sim->send_ring_put + 2 * sizeof(u32)) % PAGE_SIZE; | ||
170 | |||
171 | /* Update the put pointer. This will trap into the host. */ | ||
172 | sim_writel(g->sim, sim_send_put_r(), g->sim->send_ring_put); | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static inline u32 *sim_recv_ring_bfr(struct gk20a *g, u32 byte_offset) | ||
178 | { | 70 | { |
179 | u8 *cpu_va; | 71 | struct sim_nvgpu_linux *sim_linux; |
180 | 72 | int err = -ENOMEM; | |
181 | cpu_va = (u8 *)sim_linux->recv_bfr.cpu_va; | ||
182 | |||
183 | return (u32 *)(cpu_va + byte_offset); | ||
184 | } | ||
185 | |||
186 | static int rpc_recv_poll(struct gk20a *g) | ||
187 | { | ||
188 | u64 recv_phys_addr; | ||
189 | |||
190 | /* XXX This read is not required (?) */ | ||
191 | /*pVGpu->recv_ring_get = VGPU_REG_RD32(pGpu, NV_VGPU_RECV_GET);*/ | ||
192 | |||
193 | /* Poll the recv ring get pointer in an infinite loop*/ | ||
194 | do { | ||
195 | g->sim->recv_ring_put = sim_readl(g->sim, sim_recv_put_r()); | ||
196 | } while (g->sim->recv_ring_put == g->sim->recv_ring_get); | ||
197 | |||
198 | /* process all replies */ | ||
199 | while (g->sim->recv_ring_put != g->sim->recv_ring_get) { | ||
200 | /* these are in u32 offsets*/ | ||
201 | u32 dma_lo_offset = | ||
202 | sim_recv_put_pointer_v(g->sim->recv_ring_get)*2 + 0; | ||
203 | u32 dma_hi_offset = dma_lo_offset + 1; | ||
204 | u32 recv_phys_addr_lo = sim_dma_addr_lo_v( | ||
205 | *sim_recv_ring_bfr(g, dma_lo_offset*4)); | ||
206 | u32 recv_phys_addr_hi = sim_dma_hi_addr_v( | ||
207 | *sim_recv_ring_bfr(g, dma_hi_offset*4)); | ||
208 | |||
209 | recv_phys_addr = (u64)recv_phys_addr_hi << 32 | | ||
210 | (u64)recv_phys_addr_lo << PAGE_SHIFT; | ||
211 | 73 | ||
212 | if (recv_phys_addr != | 74 | if (!nvgpu_platform_is_simulation(g)) |
213 | nvgpu_mem_get_addr(g, &g->sim->msg_bfr)) { | 75 | return 0; |
214 | nvgpu_err(g, "%s Error in RPC reply", | ||
215 | __func__); | ||
216 | return -1; | ||
217 | } | ||
218 | |||
219 | /* Update GET pointer */ | ||
220 | g->sim->recv_ring_get = (g->sim->recv_ring_get + 2*sizeof(u32)) % PAGE_SIZE; | ||
221 | |||
222 | sim_writel(g->sim, sim_recv_get_r(), g->sim->recv_ring_get); | ||
223 | |||
224 | g->sim->recv_ring_put = sim_readl(g->sim, sim_recv_put_r()); | ||
225 | } | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static int issue_rpc_and_wait(struct gk20a *g) | ||
231 | { | ||
232 | int err; | ||
233 | |||
234 | err = rpc_send_message(g); | ||
235 | if (err) { | ||
236 | nvgpu_err(g, "%s failed rpc_send_message", | ||
237 | __func__); | ||
238 | return err; | ||
239 | } | ||
240 | 76 | ||
241 | err = rpc_recv_poll(g); | 77 | sim_linux = nvgpu_kzalloc(g, sizeof(*sim_linux)); |
242 | if (err) { | 78 | if (!sim_linux) |
243 | nvgpu_err(g, "%s failed rpc_recv_poll", | ||
244 | __func__); | ||
245 | return err; | 79 | return err; |
246 | } | 80 | g->sim = &sim_linux->sim; |
247 | 81 | g->sim->g = g; | |
248 | /* Now check if RPC really succeeded */ | 82 | sim_linux->regs = nvgpu_ioremap_resource(dev, |
249 | if (*sim_msg_hdr(g, sim_msg_result_r()) != sim_msg_result_success_v()) { | 83 | GK20A_SIM_IORESOURCE_MEM, |
250 | nvgpu_err(g, "%s received failed status!", | 84 | &sim_linux->reg_mem); |
251 | __func__); | 85 | if (IS_ERR(sim_linux->regs)) { |
252 | return -(*sim_msg_hdr(g, sim_msg_result_r())); | 86 | nvgpu_err(g, "failed to remap gk20a sim regs"); |
253 | } | 87 | err = PTR_ERR(sim_linux->regs); |
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static int gk20a_sim_esc_readl(struct gk20a *g, char *path, u32 index, u32 *data) | ||
258 | { | ||
259 | int err; | ||
260 | size_t pathlen = strlen(path); | ||
261 | u32 data_offset; | ||
262 | |||
263 | sim_write_hdr(g, sim_msg_function_sim_escape_read_v(), | ||
264 | sim_escape_read_hdr_size()); | ||
265 | *sim_msg_param(g, 0) = index; | ||
266 | *sim_msg_param(g, 4) = sizeof(u32); | ||
267 | data_offset = roundup(0xc + pathlen + 1, sizeof(u32)); | ||
268 | *sim_msg_param(g, 8) = data_offset; | ||
269 | strcpy((char *)sim_msg_param(g, 0xc), path); | ||
270 | |||
271 | err = issue_rpc_and_wait(g); | ||
272 | |||
273 | if (!err) | ||
274 | memcpy(data, sim_msg_param(g, data_offset), sizeof(u32)); | ||
275 | return err; | ||
276 | } | ||
277 | |||
278 | |||
279 | int gk20a_init_sim_support(struct gk20a *g) | ||
280 | { | ||
281 | int err = 0; | ||
282 | u64 phys; | ||
283 | |||
284 | /* allocate sim event/msg buffers */ | ||
285 | err = gk20a_alloc_sim_buffer(g, &g->sim->send_bfr); | ||
286 | err = err || gk20a_alloc_sim_buffer(g, &g->sim->recv_bfr); | ||
287 | err = err || gk20a_alloc_sim_buffer(g, &g->sim->msg_bfr); | ||
288 | |||
289 | if (err) | ||
290 | goto fail; | 88 | goto fail; |
291 | /*mark send ring invalid*/ | 89 | } |
292 | sim_writel(g->sim, sim_send_ring_r(), sim_send_ring_status_invalid_f()); | 90 | sim_linux->remove_support_linux = nvgpu_remove_sim_support_linux; |
293 | |||
294 | /*read get pointer and make equal to put*/ | ||
295 | g->sim->send_ring_put = sim_readl(g->sim, sim_send_get_r()); | ||
296 | sim_writel(g->sim, sim_send_put_r(), g->sim->send_ring_put); | ||
297 | |||
298 | /*write send ring address and make it valid*/ | ||
299 | phys = nvgpu_mem_get_addr(g, &g->sim->send_bfr); | ||
300 | sim_writel(g->sim, sim_send_ring_hi_r(), | ||
301 | sim_send_ring_hi_addr_f(u64_hi32(phys))); | ||
302 | sim_writel(g->sim, sim_send_ring_r(), | ||
303 | sim_send_ring_status_valid_f() | | ||
304 | sim_send_ring_target_phys_pci_coherent_f() | | ||
305 | sim_send_ring_size_4kb_f() | | ||
306 | sim_send_ring_addr_lo_f(phys >> PAGE_SHIFT)); | ||
307 | |||
308 | /*repeat for recv ring (but swap put,get as roles are opposite) */ | ||
309 | sim_writel(g->sim, sim_recv_ring_r(), sim_recv_ring_status_invalid_f()); | ||
310 | |||
311 | /*read put pointer and make equal to get*/ | ||
312 | g->sim->recv_ring_get = sim_readl(g->sim, sim_recv_put_r()); | ||
313 | sim_writel(g->sim, sim_recv_get_r(), g->sim->recv_ring_get); | ||
314 | |||
315 | /*write send ring address and make it valid*/ | ||
316 | phys = nvgpu_mem_get_addr(g, &g->sim->recv_bfr); | ||
317 | sim_writel(g->sim, sim_recv_ring_hi_r(), | ||
318 | sim_recv_ring_hi_addr_f(u64_hi32(phys))); | ||
319 | sim_writel(g->sim, sim_recv_ring_r(), | ||
320 | sim_recv_ring_status_valid_f() | | ||
321 | sim_recv_ring_target_phys_pci_coherent_f() | | ||
322 | sim_recv_ring_size_4kb_f() | | ||
323 | sim_recv_ring_addr_lo_f(phys >> PAGE_SHIFT)); | ||
324 | |||
325 | g->sim->remove_support = gk20a_remove_sim_support; | ||
326 | g->sim->esc_readl = gk20a_sim_esc_readl; | ||
327 | return 0; | 91 | return 0; |
328 | 92 | ||
329 | fail: | 93 | fail: |
330 | gk20a_free_sim_support(g); | 94 | nvgpu_remove_sim_support_linux(g); |
331 | return err; | 95 | return err; |
332 | } | 96 | } |
diff --git a/drivers/gpu/nvgpu/common/linux/sim.h b/drivers/gpu/nvgpu/common/linux/sim.h index e800728c..12f1a255 100644 --- a/drivers/gpu/nvgpu/common/linux/sim.h +++ b/drivers/gpu/nvgpu/common/linux/sim.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * | 2 | * |
3 | * GK20A sim support | 3 | * nvgpu sim support |
4 | * | 4 | * |
5 | * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. | 5 | * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. |
6 | * | 6 | * |
@@ -23,12 +23,21 @@ | |||
23 | #include <nvgpu/nvgpu_mem.h> | 23 | #include <nvgpu/nvgpu_mem.h> |
24 | #include "gk20a/sim_gk20a.h" | 24 | #include "gk20a/sim_gk20a.h" |
25 | 25 | ||
26 | struct sim_gk20a_linux { | 26 | struct sim_nvgpu_linux { |
27 | struct sim_gk20a sim; | 27 | struct sim_nvgpu sim; |
28 | struct resource *reg_mem; | 28 | struct resource *reg_mem; |
29 | void __iomem *regs; | 29 | void __iomem *regs; |
30 | void (*remove_support_linux)(struct gk20a *g); | ||
30 | }; | 31 | }; |
31 | 32 | ||
32 | int gk20a_init_sim_support(struct gk20a *g); | 33 | void sim_writel(struct sim_nvgpu *sim, u32 r, u32 v); |
33 | 34 | u32 sim_readl(struct sim_nvgpu *sim, u32 r); | |
35 | int nvgpu_init_sim_support(struct gk20a *g); /* will be moved to common in subsequent patch */ | ||
36 | int nvgpu_alloc_sim_buffer(struct gk20a *g, struct nvgpu_mem *mem); /* will be moved to common in subsequent patch */ | ||
37 | void nvgpu_free_sim_buffer(struct gk20a *g, struct nvgpu_mem *mem); /* will be moved to common in subsequent patch */ | ||
38 | void nvgpu_free_sim_support(struct gk20a *g); /* will be moved to common in subsequent patch */ | ||
39 | void nvgpu_remove_sim_support(struct gk20a *g); /* will be moved to common in subsequent patch */ | ||
40 | int nvgpu_init_sim_support_linux(struct gk20a *g, | ||
41 | struct platform_device *dev); | ||
42 | void nvgpu_remove_sim_support_linux(struct gk20a *g); | ||
34 | #endif | 43 | #endif |
diff --git a/drivers/gpu/nvgpu/common/linux/sim_pci.c b/drivers/gpu/nvgpu/common/linux/sim_pci.c index 1ab8c57c..9dac630c 100644 --- a/drivers/gpu/nvgpu/common/linux/sim_pci.c +++ b/drivers/gpu/nvgpu/common/linux/sim_pci.c | |||
@@ -23,276 +23,58 @@ | |||
23 | #include <nvgpu/bitops.h> | 23 | #include <nvgpu/bitops.h> |
24 | #include <nvgpu/nvgpu_mem.h> | 24 | #include <nvgpu/nvgpu_mem.h> |
25 | #include <nvgpu/dma.h> | 25 | #include <nvgpu/dma.h> |
26 | #include <nvgpu/hw_sim_pci.h> | ||
26 | #include "gk20a/gk20a.h" | 27 | #include "gk20a/gk20a.h" |
27 | #include "os_linux.h" | 28 | #include "os_linux.h" |
28 | #include "sim.h" | 29 | #include "module.h" |
29 | #include "hw_sim_pci.h" | 30 | #include "sim.h" /* will be removed in subsequent patches */ |
31 | #include "sim_pci.h"/* will be removed in subsequent patches */ | ||
30 | 32 | ||
31 | static inline void sim_writel(struct sim_gk20a *sim, u32 r, u32 v) | 33 | static bool _nvgpu_pci_is_simulation(struct gk20a *g, u32 sim_base) |
32 | { | 34 | { |
33 | struct sim_gk20a_linux *sim_linux = | 35 | u32 cfg; |
34 | container_of(sim, struct sim_gk20a_linux, sim); | 36 | bool is_simulation = false; |
35 | |||
36 | writel(v, sim_linux->regs + r); | ||
37 | } | ||
38 | 37 | ||
39 | static inline u32 sim_readl(struct sim_gk20a *sim, u32 r) | 38 | cfg = nvgpu_readl(g, sim_base + sim_config_r()); |
40 | { | 39 | if (sim_config_mode_v(cfg) == sim_config_mode_enabled_v()) |
41 | struct sim_gk20a_linux *sim_linux = | 40 | is_simulation = true; |
42 | container_of(sim, struct sim_gk20a_linux, sim); | ||
43 | 41 | ||
44 | return readl(sim_linux->regs + r); | 42 | return is_simulation; |
45 | } | 43 | } |
46 | 44 | ||
47 | static int gk20a_alloc_sim_buffer(struct gk20a *g, struct nvgpu_mem *mem) | 45 | void nvgpu_remove_sim_support_linux_pci(struct gk20a *g) |
48 | { | 46 | { |
49 | int err; | 47 | struct sim_nvgpu_linux *sim_linux; |
50 | 48 | bool is_simulation; | |
51 | err = nvgpu_dma_alloc(g, PAGE_SIZE, mem); | ||
52 | |||
53 | if (err) | ||
54 | return err; | ||
55 | /* | ||
56 | * create a valid cpu_va mapping | ||
57 | */ | ||
58 | nvgpu_mem_begin(g, mem); | ||
59 | 49 | ||
60 | return 0; | 50 | is_simulation = _nvgpu_pci_is_simulation(g, sim_r()); |
61 | } | ||
62 | 51 | ||
63 | static void gk20a_free_sim_buffer(struct gk20a *g, struct nvgpu_mem *mem) | 52 | if (!is_simulation) { |
64 | { | 53 | nvgpu_warn(g, "not in sim_mode"); |
65 | if (nvgpu_mem_is_valid(mem)) { | 54 | return; |
66 | /* | ||
67 | * invalidate the cpu_va mapping | ||
68 | */ | ||
69 | nvgpu_mem_end(g, mem); | ||
70 | nvgpu_dma_free(g, mem); | ||
71 | } | 55 | } |
72 | 56 | ||
73 | memset(mem, 0, sizeof(*mem)); | 57 | if (!g->sim) { |
74 | } | 58 | nvgpu_warn(g, "sim_gk20a not allocated"); |
75 | 59 | return; | |
76 | static void gk20a_free_sim_support(struct gk20a *g) | 60 | } |
77 | { | 61 | sim_linux = container_of(g->sim, struct sim_nvgpu_linux, sim); |
78 | gk20a_free_sim_buffer(g, &g->sim->send_bfr); | ||
79 | gk20a_free_sim_buffer(g, &g->sim->recv_bfr); | ||
80 | gk20a_free_sim_buffer(g, &g->sim->msg_bfr); | ||
81 | } | ||
82 | |||
83 | static void gk20a_remove_sim_support(struct sim_gk20a *s) | ||
84 | { | ||
85 | struct gk20a *g = s->g; | ||
86 | struct sim_gk20a_linux *sim_linux = | ||
87 | container_of(g->sim, struct sim_gk20a_linux, sim); | ||
88 | |||
89 | if (sim_linux->regs) | ||
90 | sim_writel(s, sim_config_r(), sim_config_mode_disabled_v()); | ||
91 | 62 | ||
92 | if (sim_linux->regs) { | 63 | if (sim_linux->regs) { |
93 | iounmap(sim_linux->regs); | 64 | sim_writel(g->sim, sim_config_r(), sim_config_mode_disabled_v()); |
94 | sim_linux->regs = NULL; | 65 | sim_linux->regs = NULL; |
95 | } | 66 | } |
96 | gk20a_free_sim_support(g); | ||
97 | |||
98 | nvgpu_kfree(g, sim_linux); | 67 | nvgpu_kfree(g, sim_linux); |
99 | g->sim = NULL; | 68 | g->sim = NULL; |
100 | } | 69 | } |
101 | 70 | ||
102 | static inline u32 sim_msg_header_size(void) | 71 | int nvgpu_init_sim_support_linux_pci(struct gk20a *g) |
103 | { | ||
104 | return 32U; | ||
105 | } | ||
106 | |||
107 | static inline u32 *sim_msg_bfr(struct gk20a *g, u32 byte_offset) | ||
108 | { | ||
109 | u8 *cpu_va; | ||
110 | |||
111 | cpu_va = (u8 *)sim_linux->msg_bfr.cpu_va; | ||
112 | |||
113 | return (u32 *)(cpu_va + byte_offset); | ||
114 | } | ||
115 | |||
116 | static inline u32 *sim_msg_hdr(struct gk20a *g, u32 byte_offset) | ||
117 | { | ||
118 | return sim_msg_bfr(g, byte_offset); /* starts at 0 */ | ||
119 | } | ||
120 | |||
121 | static inline u32 *sim_msg_param(struct gk20a *g, u32 byte_offset) | ||
122 | { | ||
123 | /* starts after msg header/cmn */ | ||
124 | return sim_msg_bfr(g, byte_offset + sim_msg_header_size()); | ||
125 | } | ||
126 | |||
127 | static inline void sim_write_hdr(struct gk20a *g, u32 func, u32 size) | ||
128 | { | ||
129 | *sim_msg_hdr(g, sim_msg_header_version_r()) = | ||
130 | sim_msg_header_version_major_tot_v() | | ||
131 | sim_msg_header_version_minor_tot_v(); | ||
132 | *sim_msg_hdr(g, sim_msg_signature_r()) = sim_msg_signature_valid_v(); | ||
133 | *sim_msg_hdr(g, sim_msg_result_r()) = sim_msg_result_rpc_pending_v(); | ||
134 | *sim_msg_hdr(g, sim_msg_spare_r()) = sim_msg_spare__init_v(); | ||
135 | *sim_msg_hdr(g, sim_msg_function_r()) = func; | ||
136 | *sim_msg_hdr(g, sim_msg_length_r()) = size + sim_msg_header_size(); | ||
137 | } | ||
138 | |||
139 | static inline u32 sim_escape_read_hdr_size(void) | ||
140 | { | ||
141 | return 12U; | ||
142 | } | ||
143 | |||
144 | static u32 *sim_send_ring_bfr(struct gk20a *g, u32 byte_offset) | ||
145 | { | ||
146 | u8 *cpu_va; | ||
147 | |||
148 | cpu_va = (u8 *)sim_linux->send_bfr.cpu_va; | ||
149 | |||
150 | return (u32 *)(cpu_va + byte_offset); | ||
151 | } | ||
152 | |||
153 | static int rpc_send_message(struct gk20a *g) | ||
154 | { | ||
155 | /* calculations done in units of u32s */ | ||
156 | u32 send_base = sim_send_put_pointer_v(g->sim->send_ring_put) * 2; | ||
157 | u32 dma_offset = send_base + sim_dma_r()/sizeof(u32); | ||
158 | u32 dma_hi_offset = send_base + sim_dma_hi_r()/sizeof(u32); | ||
159 | |||
160 | *sim_send_ring_bfr(g, dma_offset*sizeof(u32)) = | ||
161 | sim_dma_target_phys_pci_coherent_f() | | ||
162 | sim_dma_status_valid_f() | | ||
163 | sim_dma_size_4kb_f() | | ||
164 | sim_dma_addr_lo_f(nvgpu_mem_get_addr(g, &sim_linux->msg_bfr) >> PAGE_SHIFT); | ||
165 | |||
166 | *sim_send_ring_bfr(g, dma_hi_offset*sizeof(u32)) = | ||
167 | u64_hi32(nvgpu_mem_get_addr(g, &g->sim->msg_bfr)); | ||
168 | |||
169 | *sim_msg_hdr(g, sim_msg_sequence_r()) = g->sim->sequence_base++; | ||
170 | |||
171 | g->sim->send_ring_put = (g->sim->send_ring_put + 2 * sizeof(u32)) % | ||
172 | PAGE_SIZE; | ||
173 | |||
174 | /* Update the put pointer. This will trap into the host. */ | ||
175 | sim_writel(g->sim, sim_send_put_r(), g->sim->send_ring_put); | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static inline u32 *sim_recv_ring_bfr(struct gk20a *g, u32 byte_offset) | ||
181 | { | ||
182 | u8 *cpu_va; | ||
183 | |||
184 | cpu_va = (u8 *)sim_linux->recv_bfr.cpu_va; | ||
185 | |||
186 | return (u32 *)(cpu_va + byte_offset); | ||
187 | } | ||
188 | |||
189 | static int rpc_recv_poll(struct gk20a *g) | ||
190 | { | ||
191 | u64 recv_phys_addr; | ||
192 | |||
193 | /* Poll the recv ring get pointer in an infinite loop */ | ||
194 | do { | ||
195 | g->sim->recv_ring_put = sim_readl(g->sim, sim_recv_put_r()); | ||
196 | } while (g->sim->recv_ring_put == g->sim->recv_ring_get); | ||
197 | |||
198 | /* process all replies */ | ||
199 | while (g->sim->recv_ring_put != g->sim->recv_ring_get) { | ||
200 | /* these are in u32 offsets */ | ||
201 | u32 dma_lo_offset = | ||
202 | sim_recv_put_pointer_v(g->sim->recv_ring_get)*2 + 0; | ||
203 | u32 dma_hi_offset = dma_lo_offset + 1; | ||
204 | u32 recv_phys_addr_lo = sim_dma_addr_lo_v( | ||
205 | *sim_recv_ring_bfr(g, dma_lo_offset*4)); | ||
206 | u32 recv_phys_addr_hi = sim_dma_hi_addr_v( | ||
207 | *sim_recv_ring_bfr(g, dma_hi_offset*4)); | ||
208 | |||
209 | recv_phys_addr = (u64)recv_phys_addr_hi << 32 | | ||
210 | (u64)recv_phys_addr_lo << PAGE_SHIFT; | ||
211 | |||
212 | if (recv_phys_addr != | ||
213 | nvgpu_mem_get_addr(g, &g->sim->msg_bfr)) { | ||
214 | nvgpu_err(g, "Error in RPC reply"); | ||
215 | return -EINVAL; | ||
216 | } | ||
217 | |||
218 | /* Update GET pointer */ | ||
219 | g->sim->recv_ring_get = (g->sim->recv_ring_get + 2*sizeof(u32)) | ||
220 | % PAGE_SIZE; | ||
221 | |||
222 | sim_writel(g->sim, sim_recv_get_r(), g->sim->recv_ring_get); | ||
223 | |||
224 | g->sim->recv_ring_put = sim_readl(g->sim, sim_recv_put_r()); | ||
225 | } | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static int issue_rpc_and_wait(struct gk20a *g) | ||
231 | { | ||
232 | int err; | ||
233 | |||
234 | err = rpc_send_message(g); | ||
235 | if (err) { | ||
236 | nvgpu_err(g, "failed rpc_send_message"); | ||
237 | return err; | ||
238 | } | ||
239 | |||
240 | err = rpc_recv_poll(g); | ||
241 | if (err) { | ||
242 | nvgpu_err(g, "failed rpc_recv_poll"); | ||
243 | return err; | ||
244 | } | ||
245 | |||
246 | /* Now check if RPC really succeeded */ | ||
247 | if (*sim_msg_hdr(g, sim_msg_result_r()) != sim_msg_result_success_v()) { | ||
248 | nvgpu_err(g, "received failed status!"); | ||
249 | return -EINVAL; | ||
250 | } | ||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | static int gk20a_sim_esc_readl(struct gk20a *g, char *path, u32 index, u32 *data) | ||
255 | { | 72 | { |
256 | int err; | ||
257 | size_t pathlen = strlen(path); | ||
258 | u32 data_offset; | ||
259 | |||
260 | sim_write_hdr(g, sim_msg_function_sim_escape_read_v(), | ||
261 | sim_escape_read_hdr_size()); | ||
262 | *sim_msg_param(g, 0) = index; | ||
263 | *sim_msg_param(g, 4) = sizeof(u32); | ||
264 | data_offset = roundup(pathlen + 1, sizeof(u32)); | ||
265 | *sim_msg_param(g, 8) = data_offset; | ||
266 | strcpy((char *)sim_msg_param(g, 0xc), path); | ||
267 | |||
268 | err = issue_rpc_and_wait(g); | ||
269 | |||
270 | if (!err) | ||
271 | memcpy(data, sim_msg_param(g, data_offset + 0xc), sizeof(u32)); | ||
272 | return err; | ||
273 | } | ||
274 | |||
275 | static bool _nvgpu_pci_is_simulation(struct gk20a *g, u32 sim_base) | ||
276 | { | ||
277 | u32 cfg; | ||
278 | bool is_simulation = false; | ||
279 | |||
280 | cfg = nvgpu_readl(g, sim_base + sim_config_r()); | ||
281 | if (sim_config_mode_v(cfg) == sim_config_mode_enabled_v()) | ||
282 | is_simulation = true; | ||
283 | |||
284 | return is_simulation; | ||
285 | } | ||
286 | |||
287 | int nvgpu_pci_init_sim_support(struct gk20a *g) | ||
288 | { | ||
289 | int err = 0; | ||
290 | u64 phys; | ||
291 | struct sim_gk20a_linux *sim_linux; | ||
292 | bool is_simulation; | ||
293 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); | 73 | struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g); |
74 | struct sim_nvgpu_linux *sim_linux; | ||
75 | int err = -ENOMEM; | ||
76 | bool is_simulation; | ||
294 | 77 | ||
295 | /* initialize sim aperture */ | ||
296 | is_simulation = _nvgpu_pci_is_simulation(g, sim_r()); | 78 | is_simulation = _nvgpu_pci_is_simulation(g, sim_r()); |
297 | __nvgpu_set_enabled(g, NVGPU_IS_FMODEL, is_simulation); | 79 | __nvgpu_set_enabled(g, NVGPU_IS_FMODEL, is_simulation); |
298 | 80 | ||
@@ -301,57 +83,11 @@ int nvgpu_pci_init_sim_support(struct gk20a *g) | |||
301 | 83 | ||
302 | sim_linux = nvgpu_kzalloc(g, sizeof(*sim_linux)); | 84 | sim_linux = nvgpu_kzalloc(g, sizeof(*sim_linux)); |
303 | if (!sim_linux) | 85 | if (!sim_linux) |
304 | goto fail; | 86 | return err; |
305 | |||
306 | g->sim = &sim_linux->sim; | 87 | g->sim = &sim_linux->sim; |
88 | g->sim->g = g; | ||
307 | sim_linux->regs = l->regs + sim_r(); | 89 | sim_linux->regs = l->regs + sim_r(); |
90 | sim_linux->remove_support_linux = nvgpu_remove_sim_support_linux_pci; | ||
308 | 91 | ||
309 | /* allocate sim event/msg buffers */ | ||
310 | err = gk20a_alloc_sim_buffer(g, &g->sim->send_bfr); | ||
311 | err = err || gk20a_alloc_sim_buffer(g, &g->sim->recv_bfr); | ||
312 | err = err || gk20a_alloc_sim_buffer(g, &g->sim->msg_bfr); | ||
313 | |||
314 | if (err) | ||
315 | goto fail; | ||
316 | /* mark send ring invalid */ | ||
317 | sim_writel(g->sim, sim_send_ring_r(), sim_send_ring_status_invalid_f()); | ||
318 | |||
319 | /* read get pointer and make equal to put */ | ||
320 | g->sim->send_ring_put = sim_readl(g->sim, sim_send_get_r()); | ||
321 | sim_writel(g->sim, sim_send_put_r(), g->sim->send_ring_put); | ||
322 | |||
323 | /* write send ring address and make it valid */ | ||
324 | phys = nvgpu_mem_get_addr(g, &g->sim->send_bfr); | ||
325 | sim_writel(g->sim, sim_send_ring_hi_r(), | ||
326 | sim_send_ring_hi_addr_f(u64_hi32(phys))); | ||
327 | sim_writel(g->sim, sim_send_ring_r(), | ||
328 | sim_send_ring_status_valid_f() | | ||
329 | sim_send_ring_target_phys_pci_coherent_f() | | ||
330 | sim_send_ring_size_4kb_f() | | ||
331 | sim_send_ring_addr_lo_f(phys >> PAGE_SHIFT)); | ||
332 | |||
333 | /* repeat for recv ring (but swap put,get as roles are opposite) */ | ||
334 | sim_writel(g->sim, sim_recv_ring_r(), sim_recv_ring_status_invalid_f()); | ||
335 | |||
336 | /* read put pointer and make equal to get */ | ||
337 | g->sim->recv_ring_get = sim_readl(g->sim, sim_recv_put_r()); | ||
338 | sim_writel(g->sim, sim_recv_get_r(), g->sim->recv_ring_get); | ||
339 | |||
340 | /* write send ring address and make it valid */ | ||
341 | phys = nvgpu_mem_get_addr(g, &g->sim->recv_bfr); | ||
342 | sim_writel(g->sim, sim_recv_ring_hi_r(), | ||
343 | sim_recv_ring_hi_addr_f(u64_hi32(phys))); | ||
344 | sim_writel(g->sim, sim_recv_ring_r(), | ||
345 | sim_recv_ring_status_valid_f() | | ||
346 | sim_recv_ring_target_phys_pci_coherent_f() | | ||
347 | sim_recv_ring_size_4kb_f() | | ||
348 | sim_recv_ring_addr_lo_f(phys >> PAGE_SHIFT)); | ||
349 | |||
350 | g->sim->remove_support = gk20a_remove_sim_support; | ||
351 | g->sim->esc_readl = gk20a_sim_esc_readl; | ||
352 | return 0; | 92 | return 0; |
353 | |||
354 | fail: | ||
355 | gk20a_free_sim_support(g); | ||
356 | return err; | ||
357 | } | 93 | } |
diff --git a/drivers/gpu/nvgpu/common/linux/sim_pci.h b/drivers/gpu/nvgpu/common/linux/sim_pci.h index 22a3169c..645dbdbd 100644 --- a/drivers/gpu/nvgpu/common/linux/sim_pci.h +++ b/drivers/gpu/nvgpu/common/linux/sim_pci.h | |||
@@ -23,6 +23,7 @@ | |||
23 | #include "gk20a/sim_gk20a.h" | 23 | #include "gk20a/sim_gk20a.h" |
24 | #include "sim.h" | 24 | #include "sim.h" |
25 | 25 | ||
26 | int nvgpu_pci_init_sim_support(struct gk20a *g); | 26 | int nvgpu_init_sim_support_pci(struct gk20a *g); /* this will be moved */ |
27 | 27 | int nvgpu_init_sim_support_linux_pci(struct gk20a *g); | |
28 | void nvgpu_remove_sim_support_linux_pci(struct gk20a *g); | ||
28 | #endif | 29 | #endif |
diff --git a/drivers/gpu/nvgpu/common/sim.c b/drivers/gpu/nvgpu/common/sim.c new file mode 100644 index 00000000..0f88ec4d --- /dev/null +++ b/drivers/gpu/nvgpu/common/sim.c | |||
@@ -0,0 +1,311 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | * DEALINGS IN THE SOFTWARE. | ||
21 | */ | ||
22 | |||
23 | #include <nvgpu/log.h> | ||
24 | #include <nvgpu/bitops.h> | ||
25 | #include <nvgpu/nvgpu_mem.h> | ||
26 | #include <nvgpu/dma.h> | ||
27 | #include <nvgpu/io.h> | ||
28 | #include <nvgpu/hw_sim.h> | ||
29 | #include "gk20a/gk20a.h" | ||
30 | #include "linux/sim.h" | ||
31 | |||
32 | |||
33 | int nvgpu_alloc_sim_buffer(struct gk20a *g, struct nvgpu_mem *mem) | ||
34 | { | ||
35 | int err; | ||
36 | |||
37 | err = nvgpu_dma_alloc(g, PAGE_SIZE, mem); | ||
38 | |||
39 | if (err) | ||
40 | return err; | ||
41 | /* | ||
42 | * create a valid cpu_va mapping | ||
43 | */ | ||
44 | nvgpu_mem_begin(g, mem); | ||
45 | |||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | void nvgpu_free_sim_buffer(struct gk20a *g, struct nvgpu_mem *mem) | ||
50 | { | ||
51 | if (nvgpu_mem_is_valid(mem)) { | ||
52 | /* | ||
53 | * invalidate the cpu_va mapping | ||
54 | */ | ||
55 | nvgpu_mem_end(g, mem); | ||
56 | nvgpu_dma_free(g, mem); | ||
57 | } | ||
58 | |||
59 | memset(mem, 0, sizeof(*mem)); | ||
60 | } | ||
61 | |||
62 | void nvgpu_free_sim_support(struct gk20a *g) | ||
63 | { | ||
64 | nvgpu_free_sim_buffer(g, &g->sim->send_bfr); | ||
65 | nvgpu_free_sim_buffer(g, &g->sim->recv_bfr); | ||
66 | nvgpu_free_sim_buffer(g, &g->sim->msg_bfr); | ||
67 | } | ||
68 | |||
69 | void nvgpu_remove_sim_support(struct gk20a *g) | ||
70 | { | ||
71 | if (g->sim) | ||
72 | nvgpu_free_sim_support(g); | ||
73 | } | ||
74 | |||
75 | static inline u32 sim_msg_header_size(void) | ||
76 | { | ||
77 | return 24;/*TBD: fix the header to gt this from NV_VGPU_MSG_HEADER*/ | ||
78 | } | ||
79 | |||
80 | static inline u32 *sim_msg_bfr(struct gk20a *g, u32 byte_offset) | ||
81 | { | ||
82 | u8 *cpu_va; | ||
83 | |||
84 | cpu_va = (u8 *)g->sim->msg_bfr.cpu_va; | ||
85 | |||
86 | return (u32 *)(cpu_va + byte_offset); | ||
87 | } | ||
88 | |||
89 | static inline u32 *sim_msg_hdr(struct gk20a *g, u32 byte_offset) | ||
90 | { | ||
91 | return sim_msg_bfr(g, byte_offset); /*starts at 0*/ | ||
92 | } | ||
93 | |||
94 | static inline u32 *sim_msg_param(struct gk20a *g, u32 byte_offset) | ||
95 | { | ||
96 | /*starts after msg header/cmn*/ | ||
97 | return sim_msg_bfr(g, byte_offset + sim_msg_header_size()); | ||
98 | } | ||
99 | |||
100 | static inline void sim_write_hdr(struct gk20a *g, u32 func, u32 size) | ||
101 | { | ||
102 | /*memset(g->sim->msg_bfr.kvaddr,0,min(PAGE_SIZE,size));*/ | ||
103 | *sim_msg_hdr(g, sim_msg_signature_r()) = sim_msg_signature_valid_v(); | ||
104 | *sim_msg_hdr(g, sim_msg_result_r()) = sim_msg_result_rpc_pending_v(); | ||
105 | *sim_msg_hdr(g, sim_msg_spare_r()) = sim_msg_spare__init_v(); | ||
106 | *sim_msg_hdr(g, sim_msg_function_r()) = func; | ||
107 | *sim_msg_hdr(g, sim_msg_length_r()) = size + sim_msg_header_size(); | ||
108 | } | ||
109 | |||
110 | static inline u32 sim_escape_read_hdr_size(void) | ||
111 | { | ||
112 | return 12; /*TBD: fix NV_VGPU_SIM_ESCAPE_READ_HEADER*/ | ||
113 | } | ||
114 | |||
115 | static u32 *sim_send_ring_bfr(struct gk20a *g, u32 byte_offset) | ||
116 | { | ||
117 | u8 *cpu_va; | ||
118 | |||
119 | cpu_va = (u8 *)g->sim->send_bfr.cpu_va; | ||
120 | |||
121 | return (u32 *)(cpu_va + byte_offset); | ||
122 | } | ||
123 | |||
124 | static int rpc_send_message(struct gk20a *g) | ||
125 | { | ||
126 | /* calculations done in units of u32s */ | ||
127 | u32 send_base = sim_send_put_pointer_v(g->sim->send_ring_put) * 2; | ||
128 | u32 dma_offset = send_base + sim_dma_r()/sizeof(u32); | ||
129 | u32 dma_hi_offset = send_base + sim_dma_hi_r()/sizeof(u32); | ||
130 | |||
131 | *sim_send_ring_bfr(g, dma_offset*sizeof(u32)) = | ||
132 | sim_dma_target_phys_pci_coherent_f() | | ||
133 | sim_dma_status_valid_f() | | ||
134 | sim_dma_size_4kb_f() | | ||
135 | sim_dma_addr_lo_f(nvgpu_mem_get_addr(g, &g->sim->msg_bfr) | ||
136 | >> PAGE_SHIFT); | ||
137 | |||
138 | *sim_send_ring_bfr(g, dma_hi_offset*sizeof(u32)) = | ||
139 | u64_hi32(nvgpu_mem_get_addr(g, &g->sim->msg_bfr)); | ||
140 | |||
141 | *sim_msg_hdr(g, sim_msg_sequence_r()) = g->sim->sequence_base++; | ||
142 | |||
143 | g->sim->send_ring_put = (g->sim->send_ring_put + 2 * sizeof(u32)) | ||
144 | % PAGE_SIZE; | ||
145 | |||
146 | /* Update the put pointer. This will trap into the host. */ | ||
147 | sim_writel(g->sim, sim_send_put_r(), g->sim->send_ring_put); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static inline u32 *sim_recv_ring_bfr(struct gk20a *g, u32 byte_offset) | ||
153 | { | ||
154 | u8 *cpu_va; | ||
155 | |||
156 | cpu_va = (u8 *)g->sim->recv_bfr.cpu_va; | ||
157 | |||
158 | return (u32 *)(cpu_va + byte_offset); | ||
159 | } | ||
160 | |||
161 | static int rpc_recv_poll(struct gk20a *g) | ||
162 | { | ||
163 | u64 recv_phys_addr; | ||
164 | |||
165 | /* XXX This read is not required (?) */ | ||
166 | /*pVGpu->recv_ring_get = VGPU_REG_RD32(pGpu, NV_VGPU_RECV_GET);*/ | ||
167 | |||
168 | /* Poll the recv ring get pointer in an infinite loop*/ | ||
169 | do { | ||
170 | g->sim->recv_ring_put = sim_readl(g->sim, sim_recv_put_r()); | ||
171 | } while (g->sim->recv_ring_put == g->sim->recv_ring_get); | ||
172 | |||
173 | /* process all replies */ | ||
174 | while (g->sim->recv_ring_put != g->sim->recv_ring_get) { | ||
175 | /* these are in u32 offsets*/ | ||
176 | u32 dma_lo_offset = | ||
177 | sim_recv_put_pointer_v(g->sim->recv_ring_get)*2 + 0; | ||
178 | u32 dma_hi_offset = dma_lo_offset + 1; | ||
179 | u32 recv_phys_addr_lo = sim_dma_addr_lo_v( | ||
180 | *sim_recv_ring_bfr(g, dma_lo_offset*4)); | ||
181 | u32 recv_phys_addr_hi = sim_dma_hi_addr_v( | ||
182 | *sim_recv_ring_bfr(g, dma_hi_offset*4)); | ||
183 | |||
184 | recv_phys_addr = (u64)recv_phys_addr_hi << 32 | | ||
185 | (u64)recv_phys_addr_lo << PAGE_SHIFT; | ||
186 | |||
187 | if (recv_phys_addr != | ||
188 | nvgpu_mem_get_addr(g, &g->sim->msg_bfr)) { | ||
189 | nvgpu_err(g, "%s Error in RPC reply", | ||
190 | __func__); | ||
191 | return -1; | ||
192 | } | ||
193 | |||
194 | /* Update GET pointer */ | ||
195 | g->sim->recv_ring_get = (g->sim->recv_ring_get + 2*sizeof(u32)) | ||
196 | % PAGE_SIZE; | ||
197 | |||
198 | sim_writel(g->sim, sim_recv_get_r(), g->sim->recv_ring_get); | ||
199 | |||
200 | g->sim->recv_ring_put = sim_readl(g->sim, sim_recv_put_r()); | ||
201 | } | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static int issue_rpc_and_wait(struct gk20a *g) | ||
207 | { | ||
208 | int err; | ||
209 | |||
210 | err = rpc_send_message(g); | ||
211 | if (err) { | ||
212 | nvgpu_err(g, "%s failed rpc_send_message", | ||
213 | __func__); | ||
214 | return err; | ||
215 | } | ||
216 | |||
217 | err = rpc_recv_poll(g); | ||
218 | if (err) { | ||
219 | nvgpu_err(g, "%s failed rpc_recv_poll", | ||
220 | __func__); | ||
221 | return err; | ||
222 | } | ||
223 | |||
224 | /* Now check if RPC really succeeded */ | ||
225 | if (*sim_msg_hdr(g, sim_msg_result_r()) != sim_msg_result_success_v()) { | ||
226 | nvgpu_err(g, "%s received failed status!", | ||
227 | __func__); | ||
228 | return -(*sim_msg_hdr(g, sim_msg_result_r())); | ||
229 | } | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static int nvgpu_sim_esc_readl(struct gk20a *g, | ||
234 | char *path, u32 index, u32 *data) | ||
235 | { | ||
236 | int err; | ||
237 | size_t pathlen = strlen(path); | ||
238 | u32 data_offset; | ||
239 | |||
240 | sim_write_hdr(g, sim_msg_function_sim_escape_read_v(), | ||
241 | sim_escape_read_hdr_size()); | ||
242 | *sim_msg_param(g, 0) = index; | ||
243 | *sim_msg_param(g, 4) = sizeof(u32); | ||
244 | data_offset = roundup(0xc + pathlen + 1, sizeof(u32)); | ||
245 | *sim_msg_param(g, 8) = data_offset; | ||
246 | strcpy((char *)sim_msg_param(g, 0xc), path); | ||
247 | |||
248 | err = issue_rpc_and_wait(g); | ||
249 | |||
250 | if (!err) | ||
251 | memcpy(data, sim_msg_param(g, data_offset), sizeof(u32)); | ||
252 | return err; | ||
253 | } | ||
254 | |||
255 | int nvgpu_init_sim_support(struct gk20a *g) | ||
256 | { | ||
257 | int err = -ENOMEM; | ||
258 | u64 phys; | ||
259 | |||
260 | if (!g->sim) | ||
261 | return 0; | ||
262 | |||
263 | /* allocate sim event/msg buffers */ | ||
264 | err = nvgpu_alloc_sim_buffer(g, &g->sim->send_bfr); | ||
265 | err = err || nvgpu_alloc_sim_buffer(g, &g->sim->recv_bfr); | ||
266 | err = err || nvgpu_alloc_sim_buffer(g, &g->sim->msg_bfr); | ||
267 | |||
268 | if (err) | ||
269 | goto fail; | ||
270 | /*mark send ring invalid*/ | ||
271 | sim_writel(g->sim, sim_send_ring_r(), sim_send_ring_status_invalid_f()); | ||
272 | |||
273 | /*read get pointer and make equal to put*/ | ||
274 | g->sim->send_ring_put = sim_readl(g->sim, sim_send_get_r()); | ||
275 | sim_writel(g->sim, sim_send_put_r(), g->sim->send_ring_put); | ||
276 | |||
277 | /*write send ring address and make it valid*/ | ||
278 | phys = nvgpu_mem_get_addr(g, &g->sim->send_bfr); | ||
279 | sim_writel(g->sim, sim_send_ring_hi_r(), | ||
280 | sim_send_ring_hi_addr_f(u64_hi32(phys))); | ||
281 | sim_writel(g->sim, sim_send_ring_r(), | ||
282 | sim_send_ring_status_valid_f() | | ||
283 | sim_send_ring_target_phys_pci_coherent_f() | | ||
284 | sim_send_ring_size_4kb_f() | | ||
285 | sim_send_ring_addr_lo_f(phys >> PAGE_SHIFT)); | ||
286 | |||
287 | /*repeat for recv ring (but swap put,get as roles are opposite) */ | ||
288 | sim_writel(g->sim, sim_recv_ring_r(), sim_recv_ring_status_invalid_f()); | ||
289 | |||
290 | /*read put pointer and make equal to get*/ | ||
291 | g->sim->recv_ring_get = sim_readl(g->sim, sim_recv_put_r()); | ||
292 | sim_writel(g->sim, sim_recv_get_r(), g->sim->recv_ring_get); | ||
293 | |||
294 | /*write send ring address and make it valid*/ | ||
295 | phys = nvgpu_mem_get_addr(g, &g->sim->recv_bfr); | ||
296 | sim_writel(g->sim, sim_recv_ring_hi_r(), | ||
297 | sim_recv_ring_hi_addr_f(u64_hi32(phys))); | ||
298 | sim_writel(g->sim, sim_recv_ring_r(), | ||
299 | sim_recv_ring_status_valid_f() | | ||
300 | sim_recv_ring_target_phys_pci_coherent_f() | | ||
301 | sim_recv_ring_size_4kb_f() | | ||
302 | sim_recv_ring_addr_lo_f(phys >> PAGE_SHIFT)); | ||
303 | |||
304 | g->sim->remove_support = nvgpu_remove_sim_support; | ||
305 | g->sim->esc_readl = nvgpu_sim_esc_readl; | ||
306 | return 0; | ||
307 | |||
308 | fail: | ||
309 | nvgpu_free_sim_support(g); | ||
310 | return err; | ||
311 | } | ||
diff --git a/drivers/gpu/nvgpu/common/sim_pci.c b/drivers/gpu/nvgpu/common/sim_pci.c new file mode 100644 index 00000000..b4ca7bad --- /dev/null +++ b/drivers/gpu/nvgpu/common/sim_pci.c | |||
@@ -0,0 +1,260 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
5 | * copy of this software and associated documentation files (the "Software"), | ||
6 | * to deal in the Software without restriction, including without limitation | ||
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
8 | * and/or sell copies of the Software, and to permit persons to whom the | ||
9 | * Software is furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | * DEALINGS IN THE SOFTWARE. | ||
21 | */ | ||
22 | #include <nvgpu/log.h> | ||
23 | #include <nvgpu/bitops.h> | ||
24 | #include <nvgpu/nvgpu_mem.h> | ||
25 | #include <nvgpu/dma.h> | ||
26 | #include <nvgpu/hw_sim_pci.h> | ||
27 | #include "gk20a/gk20a.h" | ||
28 | #include "linux/sim.h" | ||
29 | |||
30 | static inline u32 sim_msg_header_size(void) | ||
31 | { | ||
32 | return 32U; | ||
33 | } | ||
34 | |||
35 | static inline u32 *sim_msg_bfr(struct gk20a *g, u32 byte_offset) | ||
36 | { | ||
37 | u8 *cpu_va; | ||
38 | |||
39 | cpu_va = (u8 *)g->sim->msg_bfr.cpu_va; | ||
40 | |||
41 | return (u32 *)(cpu_va + byte_offset); | ||
42 | } | ||
43 | |||
44 | static inline u32 *sim_msg_hdr(struct gk20a *g, u32 byte_offset) | ||
45 | { | ||
46 | return sim_msg_bfr(g, byte_offset); /* starts at 0 */ | ||
47 | } | ||
48 | |||
49 | static inline u32 *sim_msg_param(struct gk20a *g, u32 byte_offset) | ||
50 | { | ||
51 | /* starts after msg header/cmn */ | ||
52 | return sim_msg_bfr(g, byte_offset + sim_msg_header_size()); | ||
53 | } | ||
54 | |||
55 | static inline void sim_write_hdr(struct gk20a *g, u32 func, u32 size) | ||
56 | { | ||
57 | *sim_msg_hdr(g, sim_msg_header_version_r()) = | ||
58 | sim_msg_header_version_major_tot_v() | | ||
59 | sim_msg_header_version_minor_tot_v(); | ||
60 | *sim_msg_hdr(g, sim_msg_signature_r()) = sim_msg_signature_valid_v(); | ||
61 | *sim_msg_hdr(g, sim_msg_result_r()) = sim_msg_result_rpc_pending_v(); | ||
62 | *sim_msg_hdr(g, sim_msg_spare_r()) = sim_msg_spare__init_v(); | ||
63 | *sim_msg_hdr(g, sim_msg_function_r()) = func; | ||
64 | *sim_msg_hdr(g, sim_msg_length_r()) = size + sim_msg_header_size(); | ||
65 | } | ||
66 | |||
67 | static inline u32 sim_escape_read_hdr_size(void) | ||
68 | { | ||
69 | return 12U; | ||
70 | } | ||
71 | |||
72 | static u32 *sim_send_ring_bfr(struct gk20a *g, u32 byte_offset) | ||
73 | { | ||
74 | u8 *cpu_va; | ||
75 | |||
76 | cpu_va = (u8 *)g->sim->send_bfr.cpu_va; | ||
77 | |||
78 | return (u32 *)(cpu_va + byte_offset); | ||
79 | } | ||
80 | |||
81 | static int rpc_send_message(struct gk20a *g) | ||
82 | { | ||
83 | /* calculations done in units of u32s */ | ||
84 | u32 send_base = sim_send_put_pointer_v(g->sim->send_ring_put) * 2; | ||
85 | u32 dma_offset = send_base + sim_dma_r()/sizeof(u32); | ||
86 | u32 dma_hi_offset = send_base + sim_dma_hi_r()/sizeof(u32); | ||
87 | |||
88 | *sim_send_ring_bfr(g, dma_offset*sizeof(u32)) = | ||
89 | sim_dma_target_phys_pci_coherent_f() | | ||
90 | sim_dma_status_valid_f() | | ||
91 | sim_dma_size_4kb_f() | | ||
92 | sim_dma_addr_lo_f(nvgpu_mem_get_addr(g, &g->sim->msg_bfr) | ||
93 | >> PAGE_SHIFT); | ||
94 | |||
95 | *sim_send_ring_bfr(g, dma_hi_offset*sizeof(u32)) = | ||
96 | u64_hi32(nvgpu_mem_get_addr(g, &g->sim->msg_bfr)); | ||
97 | |||
98 | *sim_msg_hdr(g, sim_msg_sequence_r()) = g->sim->sequence_base++; | ||
99 | |||
100 | g->sim->send_ring_put = (g->sim->send_ring_put + 2 * sizeof(u32)) % | ||
101 | PAGE_SIZE; | ||
102 | |||
103 | /* Update the put pointer. This will trap into the host. */ | ||
104 | sim_writel(g->sim, sim_send_put_r(), g->sim->send_ring_put); | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static inline u32 *sim_recv_ring_bfr(struct gk20a *g, u32 byte_offset) | ||
110 | { | ||
111 | u8 *cpu_va; | ||
112 | |||
113 | cpu_va = (u8 *)g->sim->recv_bfr.cpu_va; | ||
114 | |||
115 | return (u32 *)(cpu_va + byte_offset); | ||
116 | } | ||
117 | |||
118 | static int rpc_recv_poll(struct gk20a *g) | ||
119 | { | ||
120 | u64 recv_phys_addr; | ||
121 | |||
122 | /* Poll the recv ring get pointer in an infinite loop */ | ||
123 | do { | ||
124 | g->sim->recv_ring_put = sim_readl(g->sim, sim_recv_put_r()); | ||
125 | } while (g->sim->recv_ring_put == g->sim->recv_ring_get); | ||
126 | |||
127 | /* process all replies */ | ||
128 | while (g->sim->recv_ring_put != g->sim->recv_ring_get) { | ||
129 | /* these are in u32 offsets */ | ||
130 | u32 dma_lo_offset = | ||
131 | sim_recv_put_pointer_v(g->sim->recv_ring_get)*2 + 0; | ||
132 | u32 dma_hi_offset = dma_lo_offset + 1; | ||
133 | u32 recv_phys_addr_lo = sim_dma_addr_lo_v( | ||
134 | *sim_recv_ring_bfr(g, dma_lo_offset*4)); | ||
135 | u32 recv_phys_addr_hi = sim_dma_hi_addr_v( | ||
136 | *sim_recv_ring_bfr(g, dma_hi_offset*4)); | ||
137 | |||
138 | recv_phys_addr = (u64)recv_phys_addr_hi << 32 | | ||
139 | (u64)recv_phys_addr_lo << PAGE_SHIFT; | ||
140 | |||
141 | if (recv_phys_addr != nvgpu_mem_get_addr(g, &g->sim->msg_bfr)) { | ||
142 | nvgpu_err(g, "Error in RPC reply"); | ||
143 | return -EINVAL; | ||
144 | } | ||
145 | |||
146 | /* Update GET pointer */ | ||
147 | g->sim->recv_ring_get = (g->sim->recv_ring_get + 2*sizeof(u32)) | ||
148 | % PAGE_SIZE; | ||
149 | |||
150 | sim_writel(g->sim, sim_recv_get_r(), g->sim->recv_ring_get); | ||
151 | |||
152 | g->sim->recv_ring_put = sim_readl(g->sim, sim_recv_put_r()); | ||
153 | } | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static int issue_rpc_and_wait(struct gk20a *g) | ||
159 | { | ||
160 | int err; | ||
161 | |||
162 | err = rpc_send_message(g); | ||
163 | if (err) { | ||
164 | nvgpu_err(g, "failed rpc_send_message"); | ||
165 | return err; | ||
166 | } | ||
167 | |||
168 | err = rpc_recv_poll(g); | ||
169 | if (err) { | ||
170 | nvgpu_err(g, "failed rpc_recv_poll"); | ||
171 | return err; | ||
172 | } | ||
173 | |||
174 | /* Now check if RPC really succeeded */ | ||
175 | if (*sim_msg_hdr(g, sim_msg_result_r()) != sim_msg_result_success_v()) { | ||
176 | nvgpu_err(g, "received failed status!"); | ||
177 | return -EINVAL; | ||
178 | } | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static int nvgpu_sim_esc_readl(struct gk20a *g, | ||
183 | char *path, u32 index, u32 *data) | ||
184 | { | ||
185 | int err; | ||
186 | size_t pathlen = strlen(path); | ||
187 | u32 data_offset; | ||
188 | |||
189 | sim_write_hdr(g, sim_msg_function_sim_escape_read_v(), | ||
190 | sim_escape_read_hdr_size()); | ||
191 | *sim_msg_param(g, 0) = index; | ||
192 | *sim_msg_param(g, 4) = sizeof(u32); | ||
193 | data_offset = roundup(pathlen + 1, sizeof(u32)); | ||
194 | *sim_msg_param(g, 8) = data_offset; | ||
195 | strcpy((char *)sim_msg_param(g, 0xc), path); | ||
196 | |||
197 | err = issue_rpc_and_wait(g); | ||
198 | |||
199 | if (!err) | ||
200 | memcpy(data, sim_msg_param(g, data_offset + 0xc), sizeof(u32)); | ||
201 | return err; | ||
202 | } | ||
203 | |||
204 | int nvgpu_init_sim_support_pci(struct gk20a *g) | ||
205 | { | ||
206 | int err = -ENOMEM; | ||
207 | u64 phys; | ||
208 | |||
209 | if (!g->sim) | ||
210 | return 0; | ||
211 | |||
212 | /* allocate sim event/msg buffers */ | ||
213 | err = nvgpu_alloc_sim_buffer(g, &g->sim->send_bfr); | ||
214 | err = err || nvgpu_alloc_sim_buffer(g, &g->sim->recv_bfr); | ||
215 | err = err || nvgpu_alloc_sim_buffer(g, &g->sim->msg_bfr); | ||
216 | |||
217 | if (err) | ||
218 | goto fail; | ||
219 | /* mark send ring invalid */ | ||
220 | sim_writel(g->sim, sim_send_ring_r(), sim_send_ring_status_invalid_f()); | ||
221 | |||
222 | /* read get pointer and make equal to put */ | ||
223 | g->sim->send_ring_put = sim_readl(g->sim, sim_send_get_r()); | ||
224 | sim_writel(g->sim, sim_send_put_r(), g->sim->send_ring_put); | ||
225 | |||
226 | /* write send ring address and make it valid */ | ||
227 | phys = nvgpu_mem_get_addr(g, &g->sim->send_bfr); | ||
228 | sim_writel(g->sim, sim_send_ring_hi_r(), | ||
229 | sim_send_ring_hi_addr_f(u64_hi32(phys))); | ||
230 | sim_writel(g->sim, sim_send_ring_r(), | ||
231 | sim_send_ring_status_valid_f() | | ||
232 | sim_send_ring_target_phys_pci_coherent_f() | | ||
233 | sim_send_ring_size_4kb_f() | | ||
234 | sim_send_ring_addr_lo_f(phys >> PAGE_SHIFT)); | ||
235 | |||
236 | /* repeat for recv ring (but swap put,get as roles are opposite) */ | ||
237 | sim_writel(g->sim, sim_recv_ring_r(), sim_recv_ring_status_invalid_f()); | ||
238 | |||
239 | /* read put pointer and make equal to get */ | ||
240 | g->sim->recv_ring_get = sim_readl(g->sim, sim_recv_put_r()); | ||
241 | sim_writel(g->sim, sim_recv_get_r(), g->sim->recv_ring_get); | ||
242 | |||
243 | /* write send ring address and make it valid */ | ||
244 | phys = nvgpu_mem_get_addr(g, &g->sim->recv_bfr); | ||
245 | sim_writel(g->sim, sim_recv_ring_hi_r(), | ||
246 | sim_recv_ring_hi_addr_f(u64_hi32(phys))); | ||
247 | sim_writel(g->sim, sim_recv_ring_r(), | ||
248 | sim_recv_ring_status_valid_f() | | ||
249 | sim_recv_ring_target_phys_pci_coherent_f() | | ||
250 | sim_recv_ring_size_4kb_f() | | ||
251 | sim_recv_ring_addr_lo_f(phys >> PAGE_SHIFT)); | ||
252 | |||
253 | g->sim->remove_support = nvgpu_remove_sim_support; | ||
254 | g->sim->esc_readl = nvgpu_sim_esc_readl; | ||
255 | return 0; | ||
256 | |||
257 | fail: | ||
258 | nvgpu_free_sim_support(g); | ||
259 | return err; | ||
260 | } | ||
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h index 476c1dd3..7e1e751b 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/gk20a.h | |||
@@ -28,7 +28,7 @@ struct gk20a; | |||
28 | struct fifo_gk20a; | 28 | struct fifo_gk20a; |
29 | struct channel_gk20a; | 29 | struct channel_gk20a; |
30 | struct gr_gk20a; | 30 | struct gr_gk20a; |
31 | struct sim_gk20a; | 31 | struct sim_nvgpu; |
32 | struct gk20a_ctxsw_ucode_segments; | 32 | struct gk20a_ctxsw_ucode_segments; |
33 | struct gk20a_fecs_trace; | 33 | struct gk20a_fecs_trace; |
34 | struct gk20a_ctxsw_trace; | 34 | struct gk20a_ctxsw_trace; |
@@ -1287,7 +1287,7 @@ struct gk20a { | |||
1287 | struct fifo_gk20a fifo; | 1287 | struct fifo_gk20a fifo; |
1288 | struct nvgpu_nvlink_dev nvlink; | 1288 | struct nvgpu_nvlink_dev nvlink; |
1289 | struct gr_gk20a gr; | 1289 | struct gr_gk20a gr; |
1290 | struct sim_gk20a *sim; | 1290 | struct sim_nvgpu *sim; |
1291 | struct mm_gk20a mm; | 1291 | struct mm_gk20a mm; |
1292 | struct nvgpu_pmu pmu; | 1292 | struct nvgpu_pmu pmu; |
1293 | struct acr_desc acr; | 1293 | struct acr_desc acr; |
diff --git a/drivers/gpu/nvgpu/gk20a/sim_gk20a.h b/drivers/gpu/nvgpu/gk20a/sim_gk20a.h index fb64d959..e74d33d5 100644 --- a/drivers/gpu/nvgpu/gk20a/sim_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/sim_gk20a.h | |||
@@ -28,7 +28,7 @@ | |||
28 | 28 | ||
29 | struct gk20a; | 29 | struct gk20a; |
30 | 30 | ||
31 | struct sim_gk20a { | 31 | struct sim_nvgpu { |
32 | struct gk20a *g; | 32 | struct gk20a *g; |
33 | u32 send_ring_put; | 33 | u32 send_ring_put; |
34 | u32 recv_ring_get; | 34 | u32 recv_ring_get; |
@@ -37,7 +37,7 @@ struct sim_gk20a { | |||
37 | struct nvgpu_mem send_bfr; | 37 | struct nvgpu_mem send_bfr; |
38 | struct nvgpu_mem recv_bfr; | 38 | struct nvgpu_mem recv_bfr; |
39 | struct nvgpu_mem msg_bfr; | 39 | struct nvgpu_mem msg_bfr; |
40 | void (*remove_support)(struct sim_gk20a *); | 40 | void (*remove_support)(struct gk20a *); |
41 | int (*esc_readl)( | 41 | int (*esc_readl)( |
42 | struct gk20a *g, char *path, u32 index, u32 *data); | 42 | struct gk20a *g, char *path, u32 index, u32 *data); |
43 | }; | 43 | }; |
diff --git a/drivers/gpu/nvgpu/include/nvgpu/hw/gk20a/hw_sim_gk20a.h b/drivers/gpu/nvgpu/include/nvgpu/hw_sim.h index 9d68b35b..89ce6da9 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/hw/gk20a/hw_sim_gk20a.h +++ b/drivers/gpu/nvgpu/include/nvgpu/hw_sim.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2012-2017, NVIDIA Corporation. | 2 | * Copyright (c) 2012-2018, NVIDIA Corporation. |
3 | * | 3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | 4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * copy of this software and associated documentation files (the "Software"), | 5 | * copy of this software and associated documentation files (the "Software"), |
@@ -53,8 +53,8 @@ | |||
53 | * of register <x>. | 53 | * of register <x>. |
54 | */ | 54 | */ |
55 | 55 | ||
56 | #ifndef __hw_sim_gk20a_h__ | 56 | #ifndef __hw_sim_h__ |
57 | #define __hw_sim_gk20a_h__ | 57 | #define __hw_sim_h__ |
58 | /*This file is autogenerated. Do not edit. */ | 58 | /*This file is autogenerated. Do not edit. */ |
59 | 59 | ||
60 | static inline u32 sim_send_ring_r(void) | 60 | static inline u32 sim_send_ring_r(void) |
@@ -2150,4 +2150,4 @@ static inline u32 sim_msg_spare__init_v(void) | |||
2150 | return 0x00000000; | 2150 | return 0x00000000; |
2151 | } | 2151 | } |
2152 | 2152 | ||
2153 | #endif /* __hw_sim_gk20a_h__ */ | 2153 | #endif /* __hw_sim__ */ |
diff --git a/drivers/gpu/nvgpu/common/linux/hw_sim_pci.h b/drivers/gpu/nvgpu/include/nvgpu/hw_sim_pci.h index 32dbeb4b..32dbeb4b 100644 --- a/drivers/gpu/nvgpu/common/linux/hw_sim_pci.h +++ b/drivers/gpu/nvgpu/include/nvgpu/hw_sim_pci.h | |||