Changeset View
Standalone View
sys/compat/linuxkpi/common/src/linux_firmware.c
- This file was added.
/*- | |||||
* SPDX-License-Identifier: BSD-2-Clause | |||||
* | |||||
* Copyright (c) 2020 The FreeBSD Foundation | |||||
* | |||||
* This software was developed by Björn Zeeb under sponsorship from | |||||
* the FreeBSD Foundation. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* 2. Redistributions in binary form must reproduce the above copyright | |||||
* notice, this list of conditions and the following disclaimer in the | |||||
* documentation and/or other materials provided with the distribution. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
* SUCH DAMAGE. | |||||
* | |||||
* $FreeBSD$ | |||||
*/ | |||||
#include <sys/types.h> | |||||
#include <sys/firmware.h> | |||||
#include <linux/types.h> | |||||
#include <linux/device.h> | |||||
/* Keep in sync with linux/firmware.h header file. */ | |||||
manu: What's the point of having the structure in both files ? | |||||
bzAuthorUnsubmitted Done Inline ActionsSee the description of this review. bz: See the description of this review. | |||||
manuUnsubmitted Not Done Inline ActionsI saw after, why not making the same thing as in drm-kmod ? #define/#undef trick ? manu: I saw after, why not making the same thing as in drm-kmod ? #define/#undef trick ?
Heck, why… | |||||
bzAuthorUnsubmitted Done Inline ActionsSorry, I guess same problem as you; hadn't made it into the tree yet and was only in other public code drops. I wrote half of that code outside linuxkpi last year for the first driver and cleaned it up and extended it for iwlwifi and moved it into linuxkpi so it was usable for rtw88 as well and am now looking at a 4th driver which had this kind of code duplicated elsewhere as well by someone else. bz: Sorry, I guess same problem as you; hadn't made it into the tree yet and was only in other… | |||||
struct linux_firmware { | |||||
size_t size; | |||||
const uint8_t *data; | |||||
/* XXX Does Linux expose anything else? */ | |||||
const struct firmware *fbdfw; | |||||
}; | |||||
int request_firmware_nowait(struct module *, bool, const char *, | |||||
struct device *, gfp_t, void *, | |||||
void(*cont)(const struct linux_firmware *, void *)); | |||||
int request_firmware(const struct linux_firmware **, const char *, struct device *); | |||||
void release_firmware(const struct linux_firmware *); | |||||
static int | |||||
_linux_request_firmware(const char *fw_name, const struct linux_firmware **fw, | |||||
gfp_t gfp, bool enoentok) | |||||
{ | |||||
const struct firmware *fbdfw; | |||||
struct linux_firmware *lfw; | |||||
const char *fwimg; | |||||
if (fw == NULL) | |||||
return (-EINVAL); | |||||
lfw = kzalloc(sizeof(*lfw), gfp); | |||||
manuUnsubmitted Not Done Inline ActionsUse bsd function inside linuxkpi, so this can be malloc with M_WAITOK etc ... manu: Use bsd function inside linuxkpi, so this can be malloc with M_WAITOK etc ... | |||||
bzAuthorUnsubmitted Done Inline ActionsWe seem to do both, though malloc() seems to be more dominant. I am happy to change that. bz: We seem to do both, though malloc() seems to be more dominant. I am happy to change that.
I… | |||||
manuUnsubmitted Not Done Inline ActionsWe do WAITOK in drm and never had a problem. manu: We do WAITOK in drm and never had a problem.
Also with bsd func you can have a MALLOC_DEFINE so… | |||||
bzAuthorUnsubmitted Done Inline ActionsI'll check the callers again about NOWAIT. MALLOC_DEFINE Is fine for as long as we are sure (which I think we can assume in this case) that no one in Linux land simply calls "free" on things. As I said I am willing to change that. bz: I'll check the callers again about NOWAIT.
MALLOC_DEFINE Is fine for as long as we are sure… | |||||
if (lfw == NULL) | |||||
return (-ENOMEM); | |||||
/* | |||||
* Linux can have a path in the firmware which is hard to replicate | |||||
* for auto-firmware-module-loading. | |||||
*/ | |||||
fwimg = strrchr(fw_name, '/'); | |||||
if (fwimg != NULL) | |||||
fwimg++; | |||||
if (fwimg == NULL || *fwimg == '\0') | |||||
fwimg = fw_name; | |||||
fbdfw = firmware_get(fwimg); | |||||
manuUnsubmitted Not Done Inline ActionsNot sure this is enough for all the case, please try with drm-devel or drm-current-kmod. manu: Not sure this is enough for all the case, please try with drm-devel or drm-current-kmod. | |||||
bzAuthorUnsubmitted Done Inline ActionsI am not sure either. athp also has a weird scheme in place internally still to map / to _ internally in rewritten code. But by FreeBSD's module conventions is that the names are flat inside a search directory. I can have a look; what's the preferred source URL currently? bz: I am not sure either. athp also has a weird scheme in place internally still to map / to _… | |||||
manuUnsubmitted Not Done Inline Actionsmanu: https://github.com/freebsd/drm-kmod/blob/master/linuxkpi/gplv2/src/linux_firmware.c | |||||
bzAuthorUnsubmitted Done Inline ActionsThanks, will do. bz: Thanks, will do. | |||||
if (fbdfw == NULL) { | |||||
if (enoentok) | |||||
*fw = lfw; | |||||
else | |||||
kfree(lfw); | |||||
return (-ENOENT); | |||||
} | |||||
lfw->fbdfw = fbdfw; | |||||
lfw->data = (const uint8_t *)fbdfw->data; | |||||
lfw->size = fbdfw->datasize; | |||||
*fw = lfw; | |||||
return (0); | |||||
} | |||||
int | |||||
request_firmware_nowait(struct module *mod __unused, bool _t __unused, | |||||
const char *fw_name, struct device *dev __unused, gfp_t gfp, void *drv, | |||||
void(*cont)(const struct linux_firmware *, void *)) | |||||
{ | |||||
const struct linux_firmware *lfw; | |||||
int error; | |||||
/* Linux seems to run the callback if it cannot find the firmware. */ | |||||
error = _linux_request_firmware(fw_name, &lfw, gfp, true); | |||||
if (error == -ENOENT) | |||||
error = 0; | |||||
/* XXX-BZ we do not run this deferred. It's a compat layer. */ | |||||
if (error == 0) | |||||
cont(lfw, drv); | |||||
return (error); | |||||
} | |||||
int | |||||
request_firmware(const struct linux_firmware **fw, const char *fw_name, | |||||
struct device *dev __unused) | |||||
{ | |||||
return (_linux_request_firmware(fw_name, fw, GFP_KERNEL, false)); | |||||
} | |||||
void | |||||
release_firmware(const struct linux_firmware *fw) | |||||
{ | |||||
if (fw == NULL) | |||||
return; | |||||
if (fw->fbdfw) | |||||
firmware_put(fw->fbdfw, FIRMWARE_UNLOAD); | |||||
kfree(fw); | |||||
return; | |||||
} | |||||
/* end */ |
What's the point of having the structure in both files ?