1 /* 2 * Copyright 2019 Red Hat Inc. 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 */ 22 #include "priv.h" 23 24 #include <core/firmware.h> 25 26 static struct nvkm_acr_lsf * 27 nvkm_acr_falcon(struct nvkm_device *device) 28 { 29 struct nvkm_acr *acr = device->acr; 30 struct nvkm_acr_lsf *lsf; 31 32 if (acr) { 33 list_for_each_entry(lsf, &acr->lsf, head) { 34 if (lsf->func->bootstrap_falcon) 35 return lsf; 36 } 37 } 38 39 return NULL; 40 } 41 42 int 43 nvkm_acr_bootstrap_falcons(struct nvkm_device *device, unsigned long mask) 44 { 45 struct nvkm_acr_lsf *acrflcn = nvkm_acr_falcon(device); 46 unsigned long id; 47 48 if (!acrflcn) 49 return -ENOSYS; 50 51 if (acrflcn->func->bootstrap_multiple_falcons) { 52 return acrflcn->func-> 53 bootstrap_multiple_falcons(acrflcn->falcon, mask); 54 } 55 56 for_each_set_bit(id, &mask, NVKM_ACR_LSF_NUM) { 57 int ret = acrflcn->func->bootstrap_falcon(acrflcn->falcon, id); 58 if (ret) 59 return ret; 60 } 61 62 return 0; 63 } 64 65 int 66 nvkm_acr_boot_ls_falcons(struct nvkm_device *device) 67 { 68 struct nvkm_acr *acr = device->acr; 69 struct nvkm_acr_lsf *lsf; 70 int ret; 71 72 if (!acr) 73 return -ENOSYS; 74 75 list_for_each_entry(lsf, &acr->lsf, head) { 76 if (lsf->func->boot) { 77 ret = lsf->func->boot(lsf->falcon); 78 if (ret) 79 break; 80 } 81 } 82 83 return ret; 84 } 85 86 static void 87 nvkm_acr_cleanup(struct nvkm_acr *acr) 88 { 89 nvkm_acr_lsfw_del_all(acr); 90 } 91 92 static int 93 nvkm_acr_oneinit(struct nvkm_subdev *subdev) 94 { 95 struct nvkm_acr *acr = nvkm_acr(subdev); 96 struct nvkm_acr_lsfw *lsfw; 97 struct nvkm_acr_lsf *lsf; 98 99 list_for_each_entry(lsfw, &acr->lsfw, head) { 100 if (!(lsf = kmalloc(sizeof(*lsf), GFP_KERNEL))) 101 return -ENOMEM; 102 lsf->func = lsfw->func; 103 lsf->falcon = lsfw->falcon; 104 lsf->id = lsfw->id; 105 list_add_tail(&lsf->head, &acr->lsf); 106 } 107 108 nvkm_acr_cleanup(acr); 109 return 0; 110 } 111 112 static void * 113 nvkm_acr_dtor(struct nvkm_subdev *subdev) 114 { 115 struct nvkm_acr *acr = nvkm_acr(subdev); 116 struct nvkm_acr_lsf *lsf, *lst; 117 118 list_for_each_entry_safe(lsf, lst, &acr->lsf, head) { 119 list_del(&lsf->head); 120 kfree(lsf); 121 } 122 123 nvkm_acr_cleanup(acr); 124 return acr; 125 } 126 127 static const struct nvkm_subdev_func 128 nvkm_acr = { 129 .dtor = nvkm_acr_dtor, 130 .oneinit = nvkm_acr_oneinit, 131 }; 132 133 int 134 nvkm_acr_new_(const struct nvkm_acr_fwif *fwif, struct nvkm_device *device, 135 int index, struct nvkm_acr **pacr) 136 { 137 struct nvkm_acr *acr; 138 139 if (!(acr = *pacr = kzalloc(sizeof(*acr), GFP_KERNEL))) 140 return -ENOMEM; 141 nvkm_subdev_ctor(&nvkm_acr, device, index, &acr->subdev); 142 INIT_LIST_HEAD(&acr->lsfw); 143 INIT_LIST_HEAD(&acr->lsf); 144 145 fwif = nvkm_firmware_load(&acr->subdev, fwif, "Acr", acr); 146 if (IS_ERR(fwif)) 147 return PTR_ERR(fwif); 148 149 acr->func = fwif->func; 150 return 0; 151 } 152