diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/device/nv40.c | 16 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/vm/nv04.c | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/vm/nv04.h | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c | 45 |
4 files changed, 29 insertions, 41 deletions
diff --git a/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c index 320ccc4ae05c..18de4c5b202f 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c +++ b/drivers/gpu/drm/nouveau/core/subdev/device/nv40.c | |||
@@ -218,7 +218,7 @@ nv40_identify(struct nouveau_device *device) | |||
218 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 218 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
219 | device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; | 219 | device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; |
220 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 220 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
221 | device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; | 221 | device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; |
222 | device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; | 222 | device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; |
223 | device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; | 223 | device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; |
224 | device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; | 224 | device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; |
@@ -238,7 +238,7 @@ nv40_identify(struct nouveau_device *device) | |||
238 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 238 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
239 | device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; | 239 | device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; |
240 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 240 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
241 | device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; | 241 | device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; |
242 | device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; | 242 | device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; |
243 | device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; | 243 | device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; |
244 | device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; | 244 | device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; |
@@ -258,7 +258,7 @@ nv40_identify(struct nouveau_device *device) | |||
258 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 258 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
259 | device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; | 259 | device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; |
260 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 260 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
261 | device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; | 261 | device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; |
262 | device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; | 262 | device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; |
263 | device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; | 263 | device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; |
264 | device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; | 264 | device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; |
@@ -278,7 +278,7 @@ nv40_identify(struct nouveau_device *device) | |||
278 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 278 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
279 | device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; | 279 | device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; |
280 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 280 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
281 | device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; | 281 | device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; |
282 | device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; | 282 | device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; |
283 | device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; | 283 | device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; |
284 | device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; | 284 | device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; |
@@ -298,7 +298,7 @@ nv40_identify(struct nouveau_device *device) | |||
298 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 298 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
299 | device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; | 299 | device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; |
300 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 300 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
301 | device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; | 301 | device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; |
302 | device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; | 302 | device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; |
303 | device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; | 303 | device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; |
304 | device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; | 304 | device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; |
@@ -318,7 +318,7 @@ nv40_identify(struct nouveau_device *device) | |||
318 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 318 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
319 | device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; | 319 | device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; |
320 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 320 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
321 | device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; | 321 | device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; |
322 | device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; | 322 | device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; |
323 | device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; | 323 | device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; |
324 | device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; | 324 | device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; |
@@ -338,7 +338,7 @@ nv40_identify(struct nouveau_device *device) | |||
338 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 338 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
339 | device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; | 339 | device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; |
340 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 340 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
341 | device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; | 341 | device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; |
342 | device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; | 342 | device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; |
343 | device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; | 343 | device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; |
344 | device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; | 344 | device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; |
@@ -358,7 +358,7 @@ nv40_identify(struct nouveau_device *device) | |||
358 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; | 358 | device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; |
359 | device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; | 359 | device->oclass[NVDEV_SUBDEV_FB ] = &nv40_fb_oclass; |
360 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; | 360 | device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass; |
361 | device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; | 361 | device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass; |
362 | device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; | 362 | device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; |
363 | device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; | 363 | device->oclass[NVDEV_ENGINE_FIFO ] = &nv40_fifo_oclass; |
364 | device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; | 364 | device->oclass[NVDEV_ENGINE_SW ] = &nv10_software_oclass; |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.c index ad6ad5de51b8..6adbbc9cc361 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.c | |||
@@ -132,10 +132,9 @@ nv04_vmmgr_dtor(struct nouveau_object *object) | |||
132 | nouveau_gpuobj_ref(NULL, &priv->vm->pgt[0].obj[0]); | 132 | nouveau_gpuobj_ref(NULL, &priv->vm->pgt[0].obj[0]); |
133 | nouveau_vm_ref(NULL, &priv->vm, NULL); | 133 | nouveau_vm_ref(NULL, &priv->vm, NULL); |
134 | } | 134 | } |
135 | if (priv->page) { | 135 | if (priv->nullp) { |
136 | pci_unmap_page(nv_device(priv)->pdev, priv->null, | 136 | pci_free_consistent(nv_device(priv)->pdev, 16 * 1024, |
137 | PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); | 137 | priv->nullp, priv->null); |
138 | __free_page(priv->page); | ||
139 | } | 138 | } |
140 | nouveau_vmmgr_destroy(&priv->base); | 139 | nouveau_vmmgr_destroy(&priv->base); |
141 | } | 140 | } |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.h index e21369cd09c0..ec42d4bc86a6 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.h +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.h | |||
@@ -6,8 +6,8 @@ | |||
6 | struct nv04_vmmgr_priv { | 6 | struct nv04_vmmgr_priv { |
7 | struct nouveau_vmmgr base; | 7 | struct nouveau_vmmgr base; |
8 | struct nouveau_vm *vm; | 8 | struct nouveau_vm *vm; |
9 | struct page *page; | ||
10 | dma_addr_t null; | 9 | dma_addr_t null; |
10 | void *nullp; | ||
11 | }; | 11 | }; |
12 | 12 | ||
13 | static inline struct nv04_vmmgr_priv * | 13 | static inline struct nv04_vmmgr_priv * |
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c index 8c9cece25e63..0ac18d05a146 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c +++ b/drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c | |||
@@ -23,6 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <core/gpuobj.h> | 25 | #include <core/gpuobj.h> |
26 | #include <core/option.h> | ||
26 | 27 | ||
27 | #include <subdev/timer.h> | 28 | #include <subdev/timer.h> |
28 | #include <subdev/vm.h> | 29 | #include <subdev/vm.h> |
@@ -37,16 +38,6 @@ | |||
37 | ******************************************************************************/ | 38 | ******************************************************************************/ |
38 | 39 | ||
39 | static void | 40 | static void |
40 | nv44_vm_flush_priv(struct nv04_vmmgr_priv *priv, u32 base, u32 size) | ||
41 | { | ||
42 | nv_wr32(priv, 0x100814, (size - 1) << 12); | ||
43 | nv_wr32(priv, 0x100808, base | 0x20); | ||
44 | if (!nv_wait(priv, 0x100808, 0x00000001, 0x00000001)) | ||
45 | nv_error(priv, "timeout: 0x%08x\n", nv_rd32(priv, 0x100808)); | ||
46 | nv_wr32(priv, 0x100808, 0x00000000); | ||
47 | } | ||
48 | |||
49 | static void | ||
50 | nv44_vm_fill(struct nouveau_gpuobj *pgt, dma_addr_t null, | 41 | nv44_vm_fill(struct nouveau_gpuobj *pgt, dma_addr_t null, |
51 | dma_addr_t *list, u32 pte, u32 cnt) | 42 | dma_addr_t *list, u32 pte, u32 cnt) |
52 | { | 43 | { |
@@ -57,6 +48,7 @@ nv44_vm_fill(struct nouveau_gpuobj *pgt, dma_addr_t null, | |||
57 | tmp[1] = nv_ro32(pgt, base + 0x4); | 48 | tmp[1] = nv_ro32(pgt, base + 0x4); |
58 | tmp[2] = nv_ro32(pgt, base + 0x8); | 49 | tmp[2] = nv_ro32(pgt, base + 0x8); |
59 | tmp[3] = nv_ro32(pgt, base + 0xc); | 50 | tmp[3] = nv_ro32(pgt, base + 0xc); |
51 | |||
60 | while (cnt--) { | 52 | while (cnt--) { |
61 | u32 addr = list ? (*list++ >> 12) : (null >> 12); | 53 | u32 addr = list ? (*list++ >> 12) : (null >> 12); |
62 | switch (pte++ & 0x3) { | 54 | switch (pte++ & 0x3) { |
@@ -96,8 +88,6 @@ nv44_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, | |||
96 | struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) | 88 | struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) |
97 | { | 89 | { |
98 | struct nv04_vmmgr_priv *priv = (void *)vma->vm->vmm; | 90 | struct nv04_vmmgr_priv *priv = (void *)vma->vm->vmm; |
99 | u32 base = pte << 12; | ||
100 | u32 size = cnt; | ||
101 | u32 tmp[4]; | 91 | u32 tmp[4]; |
102 | int i; | 92 | int i; |
103 | 93 | ||
@@ -122,15 +112,12 @@ nv44_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, | |||
122 | 112 | ||
123 | if (cnt) | 113 | if (cnt) |
124 | nv44_vm_fill(pgt, priv->null, list, pte, cnt); | 114 | nv44_vm_fill(pgt, priv->null, list, pte, cnt); |
125 | nv44_vm_flush_priv(priv, base, size); | ||
126 | } | 115 | } |
127 | 116 | ||
128 | static void | 117 | static void |
129 | nv44_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt) | 118 | nv44_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt) |
130 | { | 119 | { |
131 | struct nv04_vmmgr_priv *priv = (void *)nouveau_vmmgr(pgt); | 120 | struct nv04_vmmgr_priv *priv = (void *)nouveau_vmmgr(pgt); |
132 | u32 base = pte << 12; | ||
133 | u32 size = cnt; | ||
134 | 121 | ||
135 | if (pte & 3) { | 122 | if (pte & 3) { |
136 | u32 max = 4 - (pte & 3); | 123 | u32 max = 4 - (pte & 3); |
@@ -150,12 +137,17 @@ nv44_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt) | |||
150 | 137 | ||
151 | if (cnt) | 138 | if (cnt) |
152 | nv44_vm_fill(pgt, priv->null, NULL, pte, cnt); | 139 | nv44_vm_fill(pgt, priv->null, NULL, pte, cnt); |
153 | nv44_vm_flush_priv(priv, base, size); | ||
154 | } | 140 | } |
155 | 141 | ||
156 | static void | 142 | static void |
157 | nv44_vm_flush(struct nouveau_vm *vm) | 143 | nv44_vm_flush(struct nouveau_vm *vm) |
158 | { | 144 | { |
145 | struct nv04_vmmgr_priv *priv = (void *)vm->vmm; | ||
146 | nv_wr32(priv, 0x100814, priv->base.limit - NV44_GART_PAGE); | ||
147 | nv_wr32(priv, 0x100808, 0x00000020); | ||
148 | if (!nv_wait(priv, 0x100808, 0x00000001, 0x00000001)) | ||
149 | nv_error(priv, "timeout: 0x%08x\n", nv_rd32(priv, 0x100808)); | ||
150 | nv_wr32(priv, 0x100808, 0x00000000); | ||
159 | } | 151 | } |
160 | 152 | ||
161 | /******************************************************************************* | 153 | /******************************************************************************* |
@@ -171,6 +163,11 @@ nv44_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
171 | struct nv04_vmmgr_priv *priv; | 163 | struct nv04_vmmgr_priv *priv; |
172 | int ret; | 164 | int ret; |
173 | 165 | ||
166 | if (!nouveau_boolopt(device->cfgopt, "NvPCIE", true)) { | ||
167 | return nouveau_object_ctor(parent, engine, &nv04_vmmgr_oclass, | ||
168 | data, size, pobject); | ||
169 | } | ||
170 | |||
174 | ret = nouveau_vmmgr_create(parent, engine, oclass, "PCIEGART", | 171 | ret = nouveau_vmmgr_create(parent, engine, oclass, "PCIEGART", |
175 | "pciegart", &priv); | 172 | "pciegart", &priv); |
176 | *pobject = nv_object(priv); | 173 | *pobject = nv_object(priv); |
@@ -187,20 +184,12 @@ nv44_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine, | |||
187 | priv->base.unmap = nv44_vm_unmap; | 184 | priv->base.unmap = nv44_vm_unmap; |
188 | priv->base.flush = nv44_vm_flush; | 185 | priv->base.flush = nv44_vm_flush; |
189 | 186 | ||
190 | priv->page = alloc_page(GFP_DMA32 | GFP_KERNEL); | 187 | priv->nullp = pci_alloc_consistent(device->pdev, 16 * 1024, &priv->null); |
191 | if (priv->page) { | 188 | if (!priv->nullp) { |
192 | priv->null = pci_map_page(device->pdev, priv->page, 0, | 189 | nv_error(priv, "unable to allocate dummy pages\n"); |
193 | PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); | 190 | return -ENOMEM; |
194 | if (pci_dma_mapping_error(device->pdev, priv->null)) { | ||
195 | __free_page(priv->page); | ||
196 | priv->page = NULL; | ||
197 | priv->null = 0; | ||
198 | } | ||
199 | } | 191 | } |
200 | 192 | ||
201 | if (!priv->page) | ||
202 | nv_warn(priv, "unable to allocate dummy page\n"); | ||
203 | |||
204 | ret = nouveau_vm_create(&priv->base, 0, NV44_GART_SIZE, 0, 4096, | 193 | ret = nouveau_vm_create(&priv->base, 0, NV44_GART_SIZE, 0, 4096, |
205 | &priv->vm); | 194 | &priv->vm); |
206 | if (ret) | 195 | if (ret) |