mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 16:56:26 +00:00
cdd30ebb1b
Clean up the existing export namespace code along the same lines of
commit 33def8498f
("treewide: Convert macro and uses of __section(foo)
to __section("foo")") and for the same reason, it is not desired for the
namespace argument to be a macro expansion itself.
Scripted using
git grep -l -e MODULE_IMPORT_NS -e EXPORT_SYMBOL_NS | while read file;
do
awk -i inplace '
/^#define EXPORT_SYMBOL_NS/ {
gsub(/__stringify\(ns\)/, "ns");
print;
next;
}
/^#define MODULE_IMPORT_NS/ {
gsub(/__stringify\(ns\)/, "ns");
print;
next;
}
/MODULE_IMPORT_NS/ {
$0 = gensub(/MODULE_IMPORT_NS\(([^)]*)\)/, "MODULE_IMPORT_NS(\"\\1\")", "g");
}
/EXPORT_SYMBOL_NS/ {
if ($0 ~ /(EXPORT_SYMBOL_NS[^(]*)\(([^,]+),/) {
if ($0 !~ /(EXPORT_SYMBOL_NS[^(]*)\(([^,]+), ([^)]+)\)/ &&
$0 !~ /(EXPORT_SYMBOL_NS[^(]*)\(\)/ &&
$0 !~ /^my/) {
getline line;
gsub(/[[:space:]]*\\$/, "");
gsub(/[[:space:]]/, "", line);
$0 = $0 " " line;
}
$0 = gensub(/(EXPORT_SYMBOL_NS[^(]*)\(([^,]+), ([^)]+)\)/,
"\\1(\\2, \"\\3\")", "g");
}
}
{ print }' $file;
done
Requested-by: Masahiro Yamada <masahiroy@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://mail.google.com/mail/u/2/#inbox/FMfcgzQXKWgMmjdFwwdsfgxzKpVHWPlc
Acked-by: Greg KH <gregkh@linuxfoundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
232 lines
5.6 KiB
C
232 lines
5.6 KiB
C
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
|
|
/*
|
|
* SoundWire AMD Manager Initialize routines
|
|
*
|
|
* Initializes and creates SDW devices based on ACPI and Hardware values
|
|
*
|
|
* Copyright 2024 Advanced Micro Devices, Inc.
|
|
*/
|
|
|
|
#include <linux/acpi.h>
|
|
#include <linux/cleanup.h>
|
|
#include <linux/export.h>
|
|
#include <linux/io.h>
|
|
#include <linux/module.h>
|
|
#include <linux/platform_device.h>
|
|
|
|
#include "amd_init.h"
|
|
|
|
#define ACP_PAD_PULLDOWN_CTRL 0x0001448
|
|
#define ACP_SW_PAD_KEEPER_EN 0x0001454
|
|
#define AMD_SDW0_PAD_CTRL_MASK 0x60
|
|
#define AMD_SDW1_PAD_CTRL_MASK 5
|
|
#define AMD_SDW_PAD_CTRL_MASK (AMD_SDW0_PAD_CTRL_MASK | AMD_SDW1_PAD_CTRL_MASK)
|
|
#define AMD_SDW0_PAD_EN 1
|
|
#define AMD_SDW1_PAD_EN 0x10
|
|
#define AMD_SDW_PAD_EN (AMD_SDW0_PAD_EN | AMD_SDW1_PAD_EN)
|
|
|
|
static int amd_enable_sdw_pads(void __iomem *mmio, u32 link_mask, struct device *dev)
|
|
{
|
|
u32 pad_keeper_en, pad_pulldown_ctrl_mask;
|
|
|
|
switch (link_mask) {
|
|
case 1:
|
|
pad_keeper_en = AMD_SDW0_PAD_EN;
|
|
pad_pulldown_ctrl_mask = AMD_SDW0_PAD_CTRL_MASK;
|
|
break;
|
|
case 2:
|
|
pad_keeper_en = AMD_SDW1_PAD_EN;
|
|
pad_pulldown_ctrl_mask = AMD_SDW1_PAD_CTRL_MASK;
|
|
break;
|
|
case 3:
|
|
pad_keeper_en = AMD_SDW_PAD_EN;
|
|
pad_pulldown_ctrl_mask = AMD_SDW_PAD_CTRL_MASK;
|
|
break;
|
|
default:
|
|
dev_err(dev, "No SDW Links are enabled\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
amd_updatel(mmio, ACP_SW_PAD_KEEPER_EN, pad_keeper_en, pad_keeper_en);
|
|
amd_updatel(mmio, ACP_PAD_PULLDOWN_CTRL, pad_pulldown_ctrl_mask, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int sdw_amd_cleanup(struct sdw_amd_ctx *ctx)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ctx->count; i++) {
|
|
if (!(ctx->link_mask & BIT(i)))
|
|
continue;
|
|
platform_device_unregister(ctx->pdev[i]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
|
|
{
|
|
struct sdw_amd_ctx *ctx;
|
|
struct acpi_device *adev;
|
|
struct acp_sdw_pdata sdw_pdata[2];
|
|
struct platform_device_info pdevinfo[2];
|
|
u32 link_mask;
|
|
int count, index;
|
|
int ret;
|
|
|
|
if (!res)
|
|
return NULL;
|
|
|
|
adev = acpi_fetch_acpi_dev(res->handle);
|
|
if (!adev)
|
|
return NULL;
|
|
|
|
if (!res->count)
|
|
return NULL;
|
|
|
|
count = res->count;
|
|
dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count);
|
|
ret = amd_enable_sdw_pads(res->mmio_base, res->link_mask, res->parent);
|
|
if (ret)
|
|
return NULL;
|
|
|
|
/*
|
|
* we need to alloc/free memory manually and can't use devm:
|
|
* this routine may be called from a workqueue, and not from
|
|
* the parent .probe.
|
|
* If devm_ was used, the memory might never be freed on errors.
|
|
*/
|
|
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
|
if (!ctx)
|
|
return NULL;
|
|
|
|
ctx->count = count;
|
|
ctx->link_mask = res->link_mask;
|
|
struct resource *sdw_res __free(kfree) = kzalloc(sizeof(*sdw_res),
|
|
GFP_KERNEL);
|
|
if (!sdw_res) {
|
|
kfree(ctx);
|
|
return NULL;
|
|
}
|
|
sdw_res->flags = IORESOURCE_MEM;
|
|
sdw_res->start = res->addr;
|
|
sdw_res->end = res->addr + res->reg_range;
|
|
memset(&pdevinfo, 0, sizeof(pdevinfo));
|
|
link_mask = ctx->link_mask;
|
|
for (index = 0; index < count; index++) {
|
|
if (!(link_mask & BIT(index)))
|
|
continue;
|
|
|
|
sdw_pdata[index].instance = index;
|
|
sdw_pdata[index].acp_sdw_lock = res->acp_lock;
|
|
sdw_pdata[index].acp_rev = res->acp_rev;
|
|
pdevinfo[index].name = "amd_sdw_manager";
|
|
pdevinfo[index].id = index;
|
|
pdevinfo[index].parent = res->parent;
|
|
pdevinfo[index].num_res = 1;
|
|
pdevinfo[index].res = sdw_res;
|
|
pdevinfo[index].data = &sdw_pdata[index];
|
|
pdevinfo[index].size_data = sizeof(struct acp_sdw_pdata);
|
|
pdevinfo[index].fwnode = acpi_fwnode_handle(adev);
|
|
ctx->pdev[index] = platform_device_register_full(&pdevinfo[index]);
|
|
if (IS_ERR(ctx->pdev[index]))
|
|
goto err;
|
|
}
|
|
return ctx;
|
|
err:
|
|
while (index--) {
|
|
if (!(link_mask & BIT(index)))
|
|
continue;
|
|
|
|
platform_device_unregister(ctx->pdev[index]);
|
|
}
|
|
|
|
kfree(ctx);
|
|
return NULL;
|
|
}
|
|
|
|
static int sdw_amd_startup(struct sdw_amd_ctx *ctx)
|
|
{
|
|
struct amd_sdw_manager *amd_manager;
|
|
int i, ret;
|
|
|
|
/* Startup SDW Manager devices */
|
|
for (i = 0; i < ctx->count; i++) {
|
|
if (!(ctx->link_mask & BIT(i)))
|
|
continue;
|
|
amd_manager = dev_get_drvdata(&ctx->pdev[i]->dev);
|
|
ret = amd_sdw_manager_start(amd_manager);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int sdw_amd_probe(struct sdw_amd_res *res, struct sdw_amd_ctx **sdw_ctx)
|
|
{
|
|
*sdw_ctx = sdw_amd_probe_controller(res);
|
|
if (!*sdw_ctx)
|
|
return -ENODEV;
|
|
|
|
return sdw_amd_startup(*sdw_ctx);
|
|
}
|
|
EXPORT_SYMBOL_NS(sdw_amd_probe, "SOUNDWIRE_AMD_INIT");
|
|
|
|
void sdw_amd_exit(struct sdw_amd_ctx *ctx)
|
|
{
|
|
sdw_amd_cleanup(ctx);
|
|
kfree(ctx->peripherals);
|
|
kfree(ctx);
|
|
}
|
|
EXPORT_SYMBOL_NS(sdw_amd_exit, "SOUNDWIRE_AMD_INIT");
|
|
|
|
int sdw_amd_get_slave_info(struct sdw_amd_ctx *ctx)
|
|
{
|
|
struct amd_sdw_manager *amd_manager;
|
|
struct sdw_bus *bus;
|
|
struct sdw_slave *slave;
|
|
struct list_head *node;
|
|
int index;
|
|
int i = 0;
|
|
int num_slaves = 0;
|
|
|
|
for (index = 0; index < ctx->count; index++) {
|
|
if (!(ctx->link_mask & BIT(index)))
|
|
continue;
|
|
amd_manager = dev_get_drvdata(&ctx->pdev[index]->dev);
|
|
if (!amd_manager)
|
|
return -ENODEV;
|
|
bus = &amd_manager->bus;
|
|
/* Calculate number of slaves */
|
|
list_for_each(node, &bus->slaves)
|
|
num_slaves++;
|
|
}
|
|
|
|
ctx->peripherals = kmalloc(struct_size(ctx->peripherals, array, num_slaves),
|
|
GFP_KERNEL);
|
|
if (!ctx->peripherals)
|
|
return -ENOMEM;
|
|
ctx->peripherals->num_peripherals = num_slaves;
|
|
for (index = 0; index < ctx->count; index++) {
|
|
if (!(ctx->link_mask & BIT(index)))
|
|
continue;
|
|
amd_manager = dev_get_drvdata(&ctx->pdev[index]->dev);
|
|
if (amd_manager) {
|
|
bus = &amd_manager->bus;
|
|
list_for_each_entry(slave, &bus->slaves, node) {
|
|
ctx->peripherals->array[i] = slave;
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL_NS(sdw_amd_get_slave_info, "SOUNDWIRE_AMD_INIT");
|
|
|
|
MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
|
|
MODULE_DESCRIPTION("AMD SoundWire Init Library");
|
|
MODULE_LICENSE("Dual BSD/GPL");
|