mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-24 10:11:26 +03:00
Compare commits
108 Commits
rel-36-lws
...
jetson_36.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
efa698bed8 | ||
|
|
e7bf6f1444 | ||
|
|
e228deeef1 | ||
|
|
36a712b801 | ||
|
|
087418781c | ||
|
|
fe0a030fee | ||
|
|
7ad4c09866 | ||
|
|
f41b74b8c3 | ||
|
|
ff0c2e64e9 | ||
|
|
8b2781df07 | ||
|
|
34b2a9887a | ||
|
|
f3b12ead83 | ||
|
|
f73208daa3 | ||
|
|
b4250020cf | ||
|
|
0eb7d29c91 | ||
|
|
a863247bfc | ||
|
|
80c7d7a67b | ||
|
|
0d1196a9f2 | ||
|
|
7373b7bc0b | ||
|
|
06c838e81c | ||
|
|
d4a130e720 | ||
|
|
ae8e0690e8 | ||
|
|
3a4fed381d | ||
|
|
d19626ceee | ||
|
|
42263f1dfe | ||
|
|
1ae45fbaa7 | ||
|
|
97a8781a1b | ||
|
|
8f4ee697f9 | ||
|
|
8fbb56adb6 | ||
|
|
55b09a913f | ||
|
|
386aa2f039 | ||
|
|
3c87c18fcf | ||
|
|
84de937501 | ||
|
|
85be13c709 | ||
|
|
913e17563b | ||
|
|
f2d3ec994c | ||
|
|
20374db85d | ||
|
|
bd0a8befee | ||
|
|
118cd4e0a6 | ||
|
|
87c78ad125 | ||
|
|
408ef72fb9 | ||
|
|
537492a880 | ||
|
|
d99dede530 | ||
|
|
df9e50c808 | ||
|
|
a1658e5ab7 | ||
|
|
523d81ebd5 | ||
|
|
cb5d91e562 | ||
|
|
36b50b7f27 | ||
|
|
98c8d2f1ab | ||
|
|
eb9eb329cb | ||
|
|
f65ba6483d | ||
|
|
e2bb52def5 | ||
|
|
f870a5f9fc | ||
|
|
490c984662 | ||
|
|
928bbd8792 | ||
|
|
954d58f2bc | ||
|
|
91baac051e | ||
|
|
6d4ef6154e | ||
|
|
4643e350da | ||
|
|
b4cc53aa67 | ||
|
|
9cb00122ac | ||
|
|
adc35280cb | ||
|
|
517660e465 | ||
|
|
09b7b63ec4 | ||
|
|
fa9c7418dc | ||
|
|
cb70a7e245 | ||
|
|
716ec492d8 | ||
|
|
5e0562c90d | ||
|
|
1b72d87cce | ||
|
|
0104837e60 | ||
|
|
39e07fb02b | ||
|
|
67b36c62c3 | ||
|
|
57d240e007 | ||
|
|
d259181558 | ||
|
|
70cf7e08f3 | ||
|
|
f902d95962 | ||
|
|
d95c0d0add | ||
|
|
32ed59d81b | ||
|
|
664ca6964c | ||
|
|
e9b64b08d1 | ||
|
|
b0e75c8874 | ||
|
|
28f1253514 | ||
|
|
83238f4563 | ||
|
|
cbac517483 | ||
|
|
4e35e4b067 | ||
|
|
a84ded5d3e | ||
|
|
222eebeb31 | ||
|
|
6ca4e1e64c | ||
|
|
e9cdb435a3 | ||
|
|
ac51641cf1 | ||
|
|
0313251d13 | ||
|
|
8b529ece8f | ||
|
|
315ceb951b | ||
|
|
044cc6adda | ||
|
|
51806fef24 | ||
|
|
6997999d7a | ||
|
|
91ee86eced | ||
|
|
91e87c9346 | ||
|
|
e351ba75c7 | ||
|
|
5ff50fc9ea | ||
|
|
94090ac30e | ||
|
|
f78df7fa59 | ||
|
|
1a5be9188a | ||
|
|
6969153c7c | ||
|
|
4e544f3b3a | ||
|
|
ed30eb40ff | ||
|
|
f107cac72e | ||
|
|
83d8dcc34c |
@@ -1,13 +1,19 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#
|
||||
# Makefile for Virtual Storage Driver
|
||||
#
|
||||
|
||||
LINUX_VERSION := $(shell expr $(VERSION) \* 256 + $(PATCHLEVEL))
|
||||
LINUX_VERSION_6_11 := $(shell expr 6 \* 256 + 11)
|
||||
|
||||
# Use dummy driver for Kernel versions greater than or equal to Linux v6.11
|
||||
ifeq ($(shell test $(LINUX_VERSION) -lt $(LINUX_VERSION_6_11); echo $$?),0)
|
||||
tegra_vblk-y += tegra_hv_vblk.o
|
||||
tegra_vblk-y += tegra_hv_ioctl.o
|
||||
tegra_vblk-y += tegra_hv_mmc.o
|
||||
tegra_vblk-y += tegra_hv_scsi.o
|
||||
tegra_vblk-y += tegra_hv_ufs.o
|
||||
obj-m += tegra_vblk.o
|
||||
endif
|
||||
@@ -1,10 +1,8 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <linux/kernel.h> /* printk() */
|
||||
#include <linux/slab.h> /* kmalloc() */
|
||||
#include <linux/vmalloc.h> /* kmalloc() */
|
||||
#include <linux/fs.h> /* everything... */
|
||||
#include <linux/errno.h> /* error codes */
|
||||
#include <linux/fcntl.h> /* O_ACCMODE */
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <linux/slab.h> /* kmalloc() */
|
||||
#include <linux/vmalloc.h> /* kmalloc() */
|
||||
#include <linux/errno.h> /* error codes */
|
||||
#include <linux/delay.h> /* For msleep and usleep_range */
|
||||
#include <uapi/scsi/ufs/ioctl.h>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
@@ -997,7 +995,11 @@ static void setup_device(struct vblk_dev *vblkdev)
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
#if defined(NV_BLK_MQ_ALLOC_QUEUE_PRESENT)
|
||||
vblkdev->queue = blk_mq_alloc_queue(&vblkdev->tag_set, NULL, NULL);
|
||||
#else
|
||||
vblkdev->queue = blk_mq_init_queue(&vblkdev->tag_set);
|
||||
#endif
|
||||
if (IS_ERR(vblkdev->queue)) {
|
||||
dev_err(vblkdev->device, "failed to init blk queue\n");
|
||||
blk_mq_free_tag_set(&vblkdev->tag_set);
|
||||
@@ -1162,7 +1164,9 @@ static void setup_device(struct vblk_dev *vblkdev)
|
||||
|
||||
vblkdev->max_requests = max_requests;
|
||||
vblkdev->max_ioctl_requests = max_ioctl_requests;
|
||||
#if defined(NV_BLK_QUEUE_MAX_HW_SECTORS_PRESENT) /* Removed in Linux v6.10 */
|
||||
blk_queue_max_hw_sectors(vblkdev->queue, max_io_bytes / SECTOR_SIZE);
|
||||
#endif
|
||||
blk_queue_flag_set(QUEUE_FLAG_NONROT, vblkdev->queue);
|
||||
|
||||
if ((vblkdev->config.blk_config.req_ops_supported & VS_BLK_SECURE_ERASE_OP_F)
|
||||
|
||||
@@ -54,7 +54,7 @@ struct cfg_list_item {
|
||||
struct list_head list;
|
||||
u16 offset;
|
||||
u8 len;
|
||||
u8 data[0];
|
||||
u8 data[];
|
||||
};
|
||||
|
||||
static struct list_head list_configs;
|
||||
|
||||
@@ -5,9 +5,7 @@ ifdef CONFIG_TEGRA_HOST1X
|
||||
obj-m += tegra-hv-vse-safety.o
|
||||
obj-m += tegra-nvvse-cryptodev.o
|
||||
ifdef CONFIG_CRYPTO_ENGINE
|
||||
ifndef CONFIG_SKIP_CRYPTO
|
||||
obj-m += tegra/
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
obj-m += tegra-se-nvrng.o
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
ccflags-y += -I$(srctree.nvidia)/drivers/gpu/host1x/include
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* Crypto driver to handle HASH algorithms using NVIDIA Security Engine.
|
||||
*/
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <nvidia/conftest.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/host1x-next.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
@@ -27,15 +26,14 @@ struct tegra_sha_ctx {
|
||||
#ifndef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
struct crypto_engine_ctx enginectx;
|
||||
#endif
|
||||
struct crypto_ahash *fallback_tfm;
|
||||
struct tegra_se *se;
|
||||
unsigned int alg;
|
||||
bool fallback;
|
||||
u32 key_id;
|
||||
struct crypto_ahash *fallback_tfm;
|
||||
};
|
||||
|
||||
struct tegra_sha_reqctx {
|
||||
struct ahash_request fallback_req;
|
||||
struct scatterlist *src_sg;
|
||||
struct tegra_se_datbuf datbuf;
|
||||
struct tegra_se_datbuf residue;
|
||||
@@ -46,6 +44,8 @@ struct tegra_sha_reqctx {
|
||||
unsigned int blk_size;
|
||||
unsigned int task;
|
||||
u32 key_id;
|
||||
u32 result[HASH_RESULT_REG_COUNT];
|
||||
struct ahash_request fallback_req;
|
||||
};
|
||||
|
||||
static int tegra_sha_get_config(u32 alg)
|
||||
@@ -216,13 +216,13 @@ static int tegra_sha_fallback_export(struct ahash_request *req, void *out)
|
||||
}
|
||||
|
||||
static int tegra_sha_prep_cmd(struct tegra_se *se, u32 *cpuvaddr,
|
||||
struct tegra_sha_reqctx *rctx)
|
||||
struct tegra_sha_reqctx *rctx)
|
||||
{
|
||||
u64 msg_len, msg_left;
|
||||
int i = 0;
|
||||
|
||||
msg_len = (u64)rctx->total_len * 8;
|
||||
msg_left = (u64)rctx->datbuf.size * 8;
|
||||
msg_len = rctx->total_len * 8;
|
||||
msg_left = rctx->datbuf.size * 8;
|
||||
|
||||
/*
|
||||
* If IN_ADDR_HI_0.SZ > SHA_MSG_LEFT_[0-3] to the HASH engine,
|
||||
@@ -236,7 +236,7 @@ static int tegra_sha_prep_cmd(struct tegra_se *se, u32 *cpuvaddr,
|
||||
}
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(8);
|
||||
cpuvaddr[i++] = host1x_opcode_incr_w(SE_SHA_MSG_LENGTH);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(SE_SHA_MSG_LENGTH);
|
||||
cpuvaddr[i++] = lower_32_bits(msg_len);
|
||||
cpuvaddr[i++] = upper_32_bits(msg_len);
|
||||
cpuvaddr[i++] = 0;
|
||||
@@ -246,14 +246,15 @@ static int tegra_sha_prep_cmd(struct tegra_se *se, u32 *cpuvaddr,
|
||||
cpuvaddr[i++] = 0;
|
||||
cpuvaddr[i++] = 0;
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(6);
|
||||
cpuvaddr[i++] = host1x_opcode_incr_w(SE_SHA_CFG);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(SE_SHA_CFG);
|
||||
cpuvaddr[i++] = rctx->config;
|
||||
|
||||
if (rctx->task & SHA_FIRST) {
|
||||
cpuvaddr[i++] = SE_SHA_TASK_HASH_INIT;
|
||||
rctx->task &= ~SHA_FIRST;
|
||||
} else
|
||||
} else {
|
||||
cpuvaddr[i++] = 0;
|
||||
}
|
||||
|
||||
cpuvaddr[i++] = rctx->datbuf.addr;
|
||||
cpuvaddr[i++] = (u32)(SE_ADDR_HI_MSB(upper_32_bits(rctx->datbuf.addr)) |
|
||||
@@ -263,30 +264,47 @@ static int tegra_sha_prep_cmd(struct tegra_se *se, u32 *cpuvaddr,
|
||||
SE_ADDR_HI_SZ(rctx->digest.size));
|
||||
if (rctx->key_id) {
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = host1x_opcode_nonincr_w(SE_SHA_CRYPTO_CFG);
|
||||
cpuvaddr[i++] = se_host1x_opcode_nonincr_w(SE_SHA_CRYPTO_CFG);
|
||||
cpuvaddr[i++] = SE_AES_KEY_INDEX(rctx->key_id);
|
||||
}
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = host1x_opcode_nonincr_w(SE_SHA_OPERATION);
|
||||
cpuvaddr[i++] = se_host1x_opcode_nonincr_w(SE_SHA_OPERATION);
|
||||
cpuvaddr[i++] = SE_SHA_OP_WRSTALL |
|
||||
SE_SHA_OP_START |
|
||||
SE_SHA_OP_LASTBUF;
|
||||
cpuvaddr[i++] = host1x_opcode_nonincr(host1x_uclass_incr_syncpt_r(), 1);
|
||||
cpuvaddr[i++] = se_host1x_opcode_nonincr(host1x_uclass_incr_syncpt_r(), 1);
|
||||
cpuvaddr[i++] = host1x_uclass_incr_syncpt_cond_f(1) |
|
||||
host1x_uclass_incr_syncpt_indx_f(se->syncpt_id);
|
||||
|
||||
dev_dbg(se->dev, "msg len %llu msg left %llu cfg %#x",
|
||||
msg_len, msg_left, rctx->config);
|
||||
msg_len, msg_left, rctx->config);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static void tegra_sha_copy_hash_result(struct tegra_se *se, struct tegra_sha_reqctx *rctx)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < HASH_RESULT_REG_COUNT; i++)
|
||||
rctx->result[i] = readl(se->base + se->hw->regs->result + (i * 4));
|
||||
}
|
||||
|
||||
static void tegra_sha_paste_hash_result(struct tegra_se *se, struct tegra_sha_reqctx *rctx)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < HASH_RESULT_REG_COUNT; i++)
|
||||
writel(rctx->result[i],
|
||||
se->base + se->hw->regs->result + (i * 4));
|
||||
}
|
||||
|
||||
static int tegra_sha_do_update(struct ahash_request *req)
|
||||
{
|
||||
struct tegra_sha_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
|
||||
struct tegra_sha_reqctx *rctx = ahash_request_ctx(req);
|
||||
unsigned int nblks, nresidue, size;
|
||||
unsigned int nblks, nresidue, size, ret;
|
||||
u32 *cpuvaddr = ctx->se->cmdbuf->addr;
|
||||
|
||||
nresidue = (req->nbytes + rctx->residue.size) % rctx->blk_size;
|
||||
@@ -311,21 +329,26 @@ static int tegra_sha_do_update(struct ahash_request *req)
|
||||
*/
|
||||
if (nblks < 1) {
|
||||
scatterwalk_map_and_copy(rctx->residue.buf + rctx->residue.size,
|
||||
rctx->src_sg, 0, req->nbytes, 0);
|
||||
rctx->src_sg, 0, req->nbytes, 0);
|
||||
|
||||
rctx->residue.size += req->nbytes;
|
||||
return 0;
|
||||
}
|
||||
|
||||
rctx->datbuf.buf = dma_alloc_coherent(ctx->se->dev, rctx->datbuf.size,
|
||||
&rctx->datbuf.addr, GFP_KERNEL);
|
||||
if (!rctx->datbuf.buf)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Copy the previous residue first */
|
||||
if (rctx->residue.size)
|
||||
memcpy(rctx->datbuf.buf, rctx->residue.buf, rctx->residue.size);
|
||||
|
||||
scatterwalk_map_and_copy(rctx->datbuf.buf + rctx->residue.size,
|
||||
rctx->src_sg, 0, req->nbytes - nresidue, 0);
|
||||
rctx->src_sg, 0, req->nbytes - nresidue, 0);
|
||||
|
||||
scatterwalk_map_and_copy(rctx->residue.buf, rctx->src_sg,
|
||||
req->nbytes - nresidue, nresidue, 0);
|
||||
req->nbytes - nresidue, nresidue, 0);
|
||||
|
||||
/* Update residue value with the residue after current block */
|
||||
rctx->residue.size = nresidue;
|
||||
@@ -333,9 +356,30 @@ static int tegra_sha_do_update(struct ahash_request *req)
|
||||
rctx->config = tegra_sha_get_config(rctx->alg) |
|
||||
SE_SHA_DST_HASH_REG;
|
||||
|
||||
/*
|
||||
* If this is not the first 'update' call, paste the previous copied
|
||||
* intermediate results to the registers so that it gets picked up.
|
||||
* This is to support the import/export functionality.
|
||||
*/
|
||||
if (!(rctx->task & SHA_FIRST))
|
||||
tegra_sha_paste_hash_result(ctx->se, rctx);
|
||||
|
||||
size = tegra_sha_prep_cmd(ctx->se, cpuvaddr, rctx);
|
||||
|
||||
return tegra_se_host1x_submit(ctx->se, size);
|
||||
ret = tegra_se_host1x_submit(ctx->se, ctx->se->cmdbuf, size);
|
||||
|
||||
/*
|
||||
* If this is not the final update, copy the intermediate results
|
||||
* from the registers so that it can be used in the next 'update'
|
||||
* call. This is to support the import/export functionality.
|
||||
*/
|
||||
if (!(rctx->task & SHA_FINAL))
|
||||
tegra_sha_copy_hash_result(ctx->se, rctx);
|
||||
|
||||
dma_free_coherent(ctx->se->dev, rctx->datbuf.size,
|
||||
rctx->datbuf.buf, rctx->datbuf.addr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tegra_sha_do_final(struct ahash_request *req)
|
||||
@@ -347,16 +391,25 @@ static int tegra_sha_do_final(struct ahash_request *req)
|
||||
u32 *cpuvaddr = se->cmdbuf->addr;
|
||||
int size, ret = 0;
|
||||
|
||||
memcpy(rctx->datbuf.buf, rctx->residue.buf, rctx->residue.size);
|
||||
rctx->datbuf.size = rctx->residue.size;
|
||||
rctx->total_len += rctx->residue.size;
|
||||
|
||||
rctx->config = tegra_sha_get_config(rctx->alg) |
|
||||
SE_SHA_DST_MEMORY;
|
||||
|
||||
size = tegra_sha_prep_cmd(se, cpuvaddr, rctx);
|
||||
if (rctx->residue.size) {
|
||||
rctx->datbuf.buf = dma_alloc_coherent(se->dev, rctx->residue.size,
|
||||
&rctx->datbuf.addr, GFP_KERNEL);
|
||||
if (!rctx->datbuf.buf) {
|
||||
ret = -ENOMEM;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
ret = tegra_se_host1x_submit(se, size);
|
||||
memcpy(rctx->datbuf.buf, rctx->residue.buf, rctx->residue.size);
|
||||
}
|
||||
|
||||
size = tegra_sha_prep_cmd(se, cpuvaddr, rctx);
|
||||
ret = tegra_se_host1x_submit(se, se->cmdbuf, size);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@@ -364,12 +417,14 @@ static int tegra_sha_do_final(struct ahash_request *req)
|
||||
memcpy(req->result, rctx->digest.buf, rctx->digest.size);
|
||||
|
||||
out:
|
||||
dma_free_coherent(se->dev, SE_SHA_BUFLEN,
|
||||
rctx->datbuf.buf, rctx->datbuf.addr);
|
||||
if (rctx->residue.size)
|
||||
dma_free_coherent(se->dev, rctx->datbuf.size,
|
||||
rctx->datbuf.buf, rctx->datbuf.addr);
|
||||
out_free:
|
||||
dma_free_coherent(se->dev, crypto_ahash_blocksize(tfm),
|
||||
rctx->residue.buf, rctx->residue.addr);
|
||||
rctx->residue.buf, rctx->residue.addr);
|
||||
dma_free_coherent(se->dev, rctx->digest.size, rctx->digest.buf,
|
||||
rctx->digest.addr);
|
||||
rctx->digest.addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -380,7 +435,7 @@ static int tegra_sha_do_one_req(struct crypto_engine *engine, void *areq)
|
||||
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
|
||||
struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);
|
||||
struct tegra_se *se = ctx->se;
|
||||
int ret = -EINVAL;
|
||||
int ret = 0;
|
||||
|
||||
if (rctx->task & SHA_UPDATE) {
|
||||
ret = tegra_sha_do_update(req);
|
||||
@@ -394,27 +449,43 @@ static int tegra_sha_do_one_req(struct crypto_engine *engine, void *areq)
|
||||
|
||||
crypto_finalize_hash_request(se->engine, req, ret);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_sha_init_fallback(struct tegra_sha_ctx *ctx, const char *algname)
|
||||
static void tegra_sha_init_fallback(struct crypto_ahash *tfm, struct tegra_sha_ctx *ctx,
|
||||
const char *algname)
|
||||
{
|
||||
unsigned int statesize;
|
||||
|
||||
ctx->fallback_tfm = crypto_alloc_ahash(algname, 0, CRYPTO_ALG_ASYNC |
|
||||
CRYPTO_ALG_NEED_FALLBACK);
|
||||
|
||||
if (IS_ERR(ctx->fallback_tfm)) {
|
||||
dev_warn(ctx->se->dev, "failed to allocate fallback for %s %ld\n",
|
||||
algname, PTR_ERR(ctx->fallback_tfm));
|
||||
dev_warn(ctx->se->dev,
|
||||
"failed to allocate fallback for %s\n", algname);
|
||||
ctx->fallback_tfm = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
statesize = crypto_ahash_statesize(ctx->fallback_tfm);
|
||||
|
||||
if (statesize > sizeof(struct tegra_sha_reqctx))
|
||||
crypto_hash_alg_common(tfm)->statesize = statesize;
|
||||
|
||||
/* Update reqsize if fallback is added */
|
||||
crypto_ahash_set_reqsize(tfm,
|
||||
sizeof(struct tegra_sha_reqctx) +
|
||||
crypto_ahash_reqsize(ctx->fallback_tfm));
|
||||
}
|
||||
|
||||
static int tegra_sha_cra_init(struct crypto_tfm *tfm)
|
||||
{
|
||||
struct tegra_sha_ctx *ctx = crypto_tfm_ctx(tfm);
|
||||
struct crypto_ahash *ahash_tfm = __crypto_ahash_cast(tfm);
|
||||
struct ahash_alg *alg = __crypto_ahash_alg(tfm->__crt_alg);
|
||||
struct tegra_se_alg *se_alg;
|
||||
const char *algname;
|
||||
int ret;
|
||||
|
||||
algname = crypto_tfm_alg_name(tfm);
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
@@ -423,21 +494,28 @@ static int tegra_sha_cra_init(struct crypto_tfm *tfm)
|
||||
se_alg = container_of(alg, struct tegra_se_alg, alg.ahash);
|
||||
#endif
|
||||
|
||||
crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
|
||||
sizeof(struct tegra_sha_reqctx));
|
||||
crypto_ahash_set_reqsize(ahash_tfm, sizeof(struct tegra_sha_reqctx));
|
||||
|
||||
ctx->se = se_alg->se_dev;
|
||||
ctx->fallback = false;
|
||||
ctx->key_id = 0;
|
||||
ctx->alg = se_algname_to_algid(algname);
|
||||
#ifndef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
ctx->enginectx.op.prepare_request = NULL;
|
||||
ctx->enginectx.op.do_one_request = tegra_sha_do_one_req;
|
||||
ctx->enginectx.op.unprepare_request = NULL;
|
||||
#endif
|
||||
|
||||
ret = se_algname_to_algid(algname);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->se->dev, "invalid algorithm\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (se_alg->alg_base)
|
||||
tegra_sha_init_fallback(ctx, algname);
|
||||
tegra_sha_init_fallback(ahash_tfm, ctx, algname);
|
||||
|
||||
ctx->alg = ret;
|
||||
|
||||
#ifndef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
ctx->enginectx.op.prepare_request = NULL;
|
||||
ctx->enginectx.op.unprepare_request = NULL;
|
||||
ctx->enginectx.op.do_one_request = tegra_sha_do_one_req;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -449,7 +527,7 @@ static void tegra_sha_cra_exit(struct crypto_tfm *tfm)
|
||||
if (ctx->fallback_tfm)
|
||||
crypto_free_ahash(ctx->fallback_tfm);
|
||||
|
||||
tegra_key_invalidate(ctx->se, ctx->key_id);
|
||||
tegra_key_invalidate(ctx->se, ctx->key_id, ctx->alg);
|
||||
}
|
||||
|
||||
static int tegra_sha_init(struct ahash_request *req)
|
||||
@@ -458,45 +536,34 @@ static int tegra_sha_init(struct ahash_request *req)
|
||||
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
|
||||
struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);
|
||||
struct tegra_se *se = ctx->se;
|
||||
const char *algname;
|
||||
|
||||
if (ctx->fallback)
|
||||
return tegra_sha_fallback_init(req);
|
||||
|
||||
algname = crypto_tfm_alg_name(&tfm->base);
|
||||
|
||||
rctx->total_len = 0;
|
||||
rctx->datbuf.size = 0;
|
||||
rctx->residue.size = 0;
|
||||
rctx->key_id = ctx->key_id;
|
||||
rctx->task = SHA_FIRST;
|
||||
rctx->alg = se_algname_to_algid(algname);
|
||||
rctx->alg = ctx->alg;
|
||||
rctx->blk_size = crypto_ahash_blocksize(tfm);
|
||||
rctx->digest.size = crypto_ahash_digestsize(tfm);
|
||||
|
||||
rctx->digest.buf = dma_alloc_coherent(se->dev, rctx->digest.size,
|
||||
&rctx->digest.addr, GFP_KERNEL);
|
||||
&rctx->digest.addr, GFP_KERNEL);
|
||||
if (!rctx->digest.buf)
|
||||
goto digbuf_fail;
|
||||
|
||||
rctx->residue.buf = dma_alloc_coherent(se->dev, rctx->blk_size,
|
||||
&rctx->residue.addr, GFP_KERNEL);
|
||||
&rctx->residue.addr, GFP_KERNEL);
|
||||
if (!rctx->residue.buf)
|
||||
goto resbuf_fail;
|
||||
|
||||
rctx->datbuf.buf = dma_alloc_coherent(se->dev, SE_SHA_BUFLEN,
|
||||
&rctx->datbuf.addr, GFP_KERNEL);
|
||||
if (!rctx->datbuf.buf)
|
||||
goto datbuf_fail;
|
||||
|
||||
return 0;
|
||||
|
||||
datbuf_fail:
|
||||
dma_free_coherent(se->dev, rctx->blk_size, rctx->residue.buf,
|
||||
rctx->residue.addr);
|
||||
resbuf_fail:
|
||||
dma_free_coherent(se->dev, SE_SHA_BUFLEN, rctx->datbuf.buf,
|
||||
rctx->datbuf.addr);
|
||||
dma_free_coherent(se->dev, rctx->digest.size, rctx->digest.buf,
|
||||
rctx->digest.addr);
|
||||
digbuf_fail:
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -505,7 +572,7 @@ static int tegra_hmac_fallback_setkey(struct tegra_sha_ctx *ctx, const u8 *key,
|
||||
unsigned int keylen)
|
||||
{
|
||||
if (!ctx->fallback_tfm) {
|
||||
dev_err(ctx->se->dev, "invalid key length\n");
|
||||
dev_dbg(ctx->se->dev, "invalid key length (%d)\n", keylen);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -517,13 +584,18 @@ static int tegra_hmac_setkey(struct crypto_ahash *tfm, const u8 *key,
|
||||
unsigned int keylen)
|
||||
{
|
||||
struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);
|
||||
int ret;
|
||||
|
||||
if (aes_check_keylen(keylen))
|
||||
return tegra_hmac_fallback_setkey(ctx, key, keylen);
|
||||
|
||||
ctx->fallback = false;
|
||||
|
||||
return tegra_key_submit(ctx->se, key, keylen, ctx->alg, &ctx->key_id);
|
||||
ret = tegra_key_submit(ctx->se, key, keylen, ctx->alg, &ctx->key_id);
|
||||
if (ret)
|
||||
return tegra_hmac_fallback_setkey(ctx, key, keylen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_sha_update(struct ahash_request *req)
|
||||
@@ -593,9 +665,6 @@ static int tegra_sha_export(struct ahash_request *req, void *out)
|
||||
return tegra_sha_fallback_export(req, out);
|
||||
|
||||
memcpy(out, rctx, sizeof(*rctx));
|
||||
/*
|
||||
* TODO: Copy HASH_RESULT registers as well.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -629,7 +698,6 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.import = tegra_sha_import,
|
||||
.halg.digestsize = SHA1_DIGEST_SIZE,
|
||||
.halg.statesize = sizeof(struct tegra_sha_reqctx),
|
||||
|
||||
.halg.base = {
|
||||
.cra_name = "sha1",
|
||||
.cra_driver_name = "tegra-se-sha1",
|
||||
@@ -661,7 +729,6 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.import = tegra_sha_import,
|
||||
.halg.digestsize = SHA224_DIGEST_SIZE,
|
||||
.halg.statesize = sizeof(struct tegra_sha_reqctx),
|
||||
|
||||
.halg.base = {
|
||||
.cra_name = "sha224",
|
||||
.cra_driver_name = "tegra-se-sha224",
|
||||
@@ -693,7 +760,6 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.import = tegra_sha_import,
|
||||
.halg.digestsize = SHA256_DIGEST_SIZE,
|
||||
.halg.statesize = sizeof(struct tegra_sha_reqctx),
|
||||
|
||||
.halg.base = {
|
||||
.cra_name = "sha256",
|
||||
.cra_driver_name = "tegra-se-sha256",
|
||||
@@ -725,7 +791,6 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.import = tegra_sha_import,
|
||||
.halg.digestsize = SHA384_DIGEST_SIZE,
|
||||
.halg.statesize = sizeof(struct tegra_sha_reqctx),
|
||||
|
||||
.halg.base = {
|
||||
.cra_name = "sha384",
|
||||
.cra_driver_name = "tegra-se-sha384",
|
||||
@@ -757,7 +822,6 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.import = tegra_sha_import,
|
||||
.halg.digestsize = SHA512_DIGEST_SIZE,
|
||||
.halg.statesize = sizeof(struct tegra_sha_reqctx),
|
||||
|
||||
.halg.base = {
|
||||
.cra_name = "sha512",
|
||||
.cra_driver_name = "tegra-se-sha512",
|
||||
@@ -789,7 +853,6 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.import = tegra_sha_import,
|
||||
.halg.digestsize = SHA3_224_DIGEST_SIZE,
|
||||
.halg.statesize = sizeof(struct tegra_sha_reqctx),
|
||||
|
||||
.halg.base = {
|
||||
.cra_name = "sha3-224",
|
||||
.cra_driver_name = "tegra-se-sha3-224",
|
||||
@@ -821,7 +884,6 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.import = tegra_sha_import,
|
||||
.halg.digestsize = SHA3_256_DIGEST_SIZE,
|
||||
.halg.statesize = sizeof(struct tegra_sha_reqctx),
|
||||
|
||||
.halg.base = {
|
||||
.cra_name = "sha3-256",
|
||||
.cra_driver_name = "tegra-se-sha3-256",
|
||||
@@ -853,7 +915,6 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.import = tegra_sha_import,
|
||||
.halg.digestsize = SHA3_384_DIGEST_SIZE,
|
||||
.halg.statesize = sizeof(struct tegra_sha_reqctx),
|
||||
|
||||
.halg.base = {
|
||||
.cra_name = "sha3-384",
|
||||
.cra_driver_name = "tegra-se-sha3-384",
|
||||
@@ -885,7 +946,6 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.import = tegra_sha_import,
|
||||
.halg.digestsize = SHA3_512_DIGEST_SIZE,
|
||||
.halg.statesize = sizeof(struct tegra_sha_reqctx),
|
||||
|
||||
.halg.base = {
|
||||
.cra_name = "sha3-512",
|
||||
.cra_driver_name = "tegra-se-sha3-512",
|
||||
@@ -919,7 +979,6 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.setkey = tegra_hmac_setkey,
|
||||
.halg.digestsize = SHA224_DIGEST_SIZE,
|
||||
.halg.statesize = sizeof(struct tegra_sha_reqctx),
|
||||
|
||||
.halg.base = {
|
||||
.cra_name = "hmac(sha224)",
|
||||
.cra_driver_name = "tegra-se-hmac-sha224",
|
||||
@@ -953,7 +1012,6 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.setkey = tegra_hmac_setkey,
|
||||
.halg.digestsize = SHA256_DIGEST_SIZE,
|
||||
.halg.statesize = sizeof(struct tegra_sha_reqctx),
|
||||
|
||||
.halg.base = {
|
||||
.cra_name = "hmac(sha256)",
|
||||
.cra_driver_name = "tegra-se-hmac-sha256",
|
||||
@@ -987,7 +1045,6 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.setkey = tegra_hmac_setkey,
|
||||
.halg.digestsize = SHA384_DIGEST_SIZE,
|
||||
.halg.statesize = sizeof(struct tegra_sha_reqctx),
|
||||
|
||||
.halg.base = {
|
||||
.cra_name = "hmac(sha384)",
|
||||
.cra_driver_name = "tegra-se-hmac-sha384",
|
||||
@@ -1021,7 +1078,6 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.setkey = tegra_hmac_setkey,
|
||||
.halg.digestsize = SHA512_DIGEST_SIZE,
|
||||
.halg.statesize = sizeof(struct tegra_sha_reqctx),
|
||||
|
||||
.halg.base = {
|
||||
.cra_name = "hmac(sha512)",
|
||||
.cra_driver_name = "tegra-se-hmac-sha512",
|
||||
@@ -1077,28 +1133,32 @@ static int tegra_hash_kac_manifest(u32 user, u32 alg, u32 keylen)
|
||||
|
||||
int tegra_init_hash(struct tegra_se *se)
|
||||
{
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
struct ahash_engine_alg *alg;
|
||||
#else
|
||||
struct ahash_alg *alg;
|
||||
#endif
|
||||
int i, ret;
|
||||
|
||||
se->manifest = tegra_hash_kac_manifest;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tegra_hash_algs); i++) {
|
||||
|
||||
tegra_hash_algs[i].se_dev = se;
|
||||
ret = CRYPTO_REGISTER(ahash, &tegra_hash_algs[i].alg.ahash);
|
||||
alg = &tegra_hash_algs[i].alg.ahash;
|
||||
|
||||
ret = CRYPTO_REGISTER(ahash, alg);
|
||||
if (ret) {
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
dev_err(se->dev, "failed to register %s\n",
|
||||
tegra_hash_algs[i].alg.ahash.base.halg.base.cra_name);
|
||||
alg->base.halg.base.cra_name);
|
||||
#else
|
||||
dev_err(se->dev, "failed to register %s\n",
|
||||
tegra_hash_algs[i].alg.ahash.halg.base.cra_name);
|
||||
alg->halg.base.cra_name);
|
||||
#endif
|
||||
goto sha_err;
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(se->dev, "registered HASH algorithms\n");
|
||||
|
||||
return 0;
|
||||
|
||||
sha_err:
|
||||
@@ -1108,8 +1168,7 @@ sha_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void tegra_deinit_hash(void)
|
||||
void tegra_deinit_hash(struct tegra_se *se)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* Crypto driver file to manage keys of NVIDIA Security Engine.
|
||||
*/
|
||||
@@ -16,66 +16,77 @@
|
||||
#define SE_KEY_RSVD_MASK (BIT(0) | BIT(14) | BIT(15))
|
||||
#define SE_KEY_VALID_MASK (SE_KEY_FULL_MASK & ~SE_KEY_RSVD_MASK)
|
||||
|
||||
/* Mutex lock to guard keyslots */
|
||||
static DEFINE_MUTEX(kslt_lock);
|
||||
|
||||
/* Keyslot bitmask (0 = available, 1 = in use/not available) */
|
||||
static u16 tegra_se_keyslots = SE_KEY_RSVD_MASK;
|
||||
|
||||
static u16 tegra_keyslot_alloc(void)
|
||||
{
|
||||
u16 keyid;
|
||||
|
||||
mutex_lock(&kslt_lock);
|
||||
/* Check if all key slots are full */
|
||||
if (tegra_se_keyslots == GENMASK(SE_MAX_KEYSLOT, 0))
|
||||
if (tegra_se_keyslots == GENMASK(SE_MAX_KEYSLOT, 0)) {
|
||||
mutex_unlock(&kslt_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
keyid = ffz(tegra_se_keyslots);
|
||||
tegra_se_keyslots |= BIT(keyid);
|
||||
|
||||
mutex_unlock(&kslt_lock);
|
||||
|
||||
return keyid;
|
||||
}
|
||||
|
||||
static void tegra_keyslot_free(u16 slot)
|
||||
{
|
||||
mutex_lock(&kslt_lock);
|
||||
tegra_se_keyslots &= ~(BIT(slot));
|
||||
mutex_unlock(&kslt_lock);
|
||||
}
|
||||
|
||||
static unsigned int tegra_key_prep_ins_cmd(struct tegra_se *se, u32 *cpuvaddr,
|
||||
const u32 *key, u32 keylen, u16 slot, u32 alg)
|
||||
const u32 *key, u32 keylen, u16 slot, u32 alg)
|
||||
{
|
||||
int i = 0, j;
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->op);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->op);
|
||||
cpuvaddr[i++] = SE_AES_OP_WRSTALL | SE_AES_OP_DUMMY;
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->manifest);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->manifest);
|
||||
cpuvaddr[i++] = se->manifest(se->owner, alg, keylen);
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->key_dst);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->key_dst);
|
||||
|
||||
cpuvaddr[i++] = SE_AES_KEY_DST_INDEX(slot);
|
||||
|
||||
for (j = 0; j < keylen / 4; j++) {
|
||||
/* Set key address */
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->key_addr);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->key_addr);
|
||||
cpuvaddr[i++] = j;
|
||||
|
||||
/* Set key data */
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->key_data);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->key_data);
|
||||
cpuvaddr[i++] = key[j];
|
||||
}
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->config);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->config);
|
||||
cpuvaddr[i++] = SE_CFG_INS;
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->op);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->op);
|
||||
cpuvaddr[i++] = SE_AES_OP_WRSTALL | SE_AES_OP_START |
|
||||
SE_AES_OP_LASTBUF;
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_nonincr(host1x_uclass_incr_syncpt_r(), 1);
|
||||
cpuvaddr[i++] = se_host1x_opcode_nonincr(host1x_uclass_incr_syncpt_r(), 1);
|
||||
cpuvaddr[i++] = host1x_uclass_incr_syncpt_cond_f(1) |
|
||||
host1x_uclass_incr_syncpt_indx_f(se->syncpt_id);
|
||||
|
||||
@@ -87,29 +98,44 @@ static unsigned int tegra_key_prep_ins_cmd(struct tegra_se *se, u32 *cpuvaddr,
|
||||
|
||||
static bool tegra_key_in_kslt(u32 keyid)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
if (keyid > SE_MAX_KEYSLOT)
|
||||
return false;
|
||||
|
||||
return ((BIT(keyid) & SE_KEY_VALID_MASK) &&
|
||||
mutex_lock(&kslt_lock);
|
||||
ret = ((BIT(keyid) & SE_KEY_VALID_MASK) &&
|
||||
(BIT(keyid) & tegra_se_keyslots));
|
||||
mutex_unlock(&kslt_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tegra_key_insert(struct tegra_se *se, const u8 *key,
|
||||
u32 keylen, u16 slot, u32 alg)
|
||||
u32 keylen, u16 slot, u32 alg)
|
||||
{
|
||||
const u32 *keyval = (u32 *)key;
|
||||
u32 *addr = se->cmdbuf->addr, size;
|
||||
u32 *addr = se->keybuf->addr, size;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&kslt_lock);
|
||||
size = tegra_key_prep_ins_cmd(se, addr, keyval, keylen, slot, alg);
|
||||
ret = tegra_se_host1x_submit(se, se->keybuf, size);
|
||||
mutex_unlock(&kslt_lock);
|
||||
|
||||
return tegra_se_host1x_submit(se, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void tegra_key_invalidate(struct tegra_se *se, u32 keyid)
|
||||
void tegra_key_invalidate(struct tegra_se *se, u32 keyid, u32 alg)
|
||||
{
|
||||
u8 zkey[AES_MAX_KEY_SIZE] = {0};
|
||||
|
||||
if (!keyid)
|
||||
return;
|
||||
|
||||
/* Overwrite the key with 0s */
|
||||
tegra_key_insert(se, zkey, AES_MAX_KEY_SIZE, keyid, alg);
|
||||
|
||||
tegra_keyslot_free(keyid);
|
||||
}
|
||||
|
||||
@@ -120,8 +146,10 @@ int tegra_key_submit(struct tegra_se *se, const u8 *key, u32 keylen, u32 alg, u3
|
||||
/* Use the existing slot if it is already allocated */
|
||||
if (!tegra_key_in_kslt(*keyid)) {
|
||||
*keyid = tegra_keyslot_alloc();
|
||||
if (!(*keyid))
|
||||
if (!(*keyid)) {
|
||||
dev_dbg(se->dev, "failed to allocate key slot\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
ret = tegra_key_insert(se, key, keylen, *keyid, alg);
|
||||
@@ -130,3 +158,20 @@ int tegra_key_submit(struct tegra_se *se, const u8 *key, u32 keylen, u32 alg, u3
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tegra_key_invalidate_reserved(struct tegra_se *se, u32 keyid, u32 alg)
|
||||
{
|
||||
u8 zkey[AES_MAX_KEY_SIZE] = {0};
|
||||
|
||||
if (!keyid)
|
||||
return;
|
||||
|
||||
/* Overwrite the key with 0s */
|
||||
tegra_key_insert(se, zkey, AES_MAX_KEY_SIZE, keyid, alg);
|
||||
}
|
||||
|
||||
inline int tegra_key_submit_reserved(struct tegra_se *se, const u8 *key,
|
||||
u32 keylen, u32 alg, u32 *keyid)
|
||||
{
|
||||
return tegra_key_insert(se, key, keylen, *keyid, alg);
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* Crypto driver for NVIDIA Security Engine in Tegra Chips
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/host1x-next.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
@@ -124,7 +123,7 @@ static struct tegra_se_cmdbuf *tegra_se_host1x_bo_alloc(struct tegra_se *se, ssi
|
||||
struct tegra_se_cmdbuf *cmdbuf;
|
||||
struct device *dev = se->dev->parent;
|
||||
|
||||
cmdbuf = kzalloc(sizeof(struct tegra_se_cmdbuf), GFP_KERNEL);
|
||||
cmdbuf = kzalloc(sizeof(*cmdbuf), GFP_KERNEL);
|
||||
if (!cmdbuf)
|
||||
return NULL;
|
||||
|
||||
@@ -142,7 +141,7 @@ static struct tegra_se_cmdbuf *tegra_se_host1x_bo_alloc(struct tegra_se *se, ssi
|
||||
return cmdbuf;
|
||||
}
|
||||
|
||||
int tegra_se_host1x_submit(struct tegra_se *se, u32 size)
|
||||
int tegra_se_host1x_submit(struct tegra_se *se, struct tegra_se_cmdbuf *cmdbuf, u32 size)
|
||||
{
|
||||
struct host1x_job *job;
|
||||
int ret;
|
||||
@@ -153,7 +152,7 @@ int tegra_se_host1x_submit(struct tegra_se *se, u32 size)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
job->syncpt = host1x_syncpt_get(se->syncpt);
|
||||
job->syncpt = host1x_syncpt_get(se->syncpt);
|
||||
job->syncpt_incrs = 1;
|
||||
job->client = &se->client;
|
||||
job->class = se->client.class;
|
||||
@@ -161,24 +160,24 @@ int tegra_se_host1x_submit(struct tegra_se *se, u32 size)
|
||||
job->engine_fallback_streamid = se->stream_id;
|
||||
job->engine_streamid_offset = SE_STREAM_ID;
|
||||
|
||||
se->cmdbuf->words = size;
|
||||
cmdbuf->words = size;
|
||||
|
||||
host1x_job_add_gather(job, &se->cmdbuf->bo, size, 0);
|
||||
host1x_job_add_gather(job, &cmdbuf->bo, size, 0);
|
||||
|
||||
ret = host1x_job_pin(job, se->dev);
|
||||
if (ret) {
|
||||
dev_err(se->dev, "failed to pin host1x job\n");
|
||||
goto err_job_pin;
|
||||
goto job_put;
|
||||
}
|
||||
|
||||
ret = host1x_job_submit(job);
|
||||
if (ret) {
|
||||
dev_err(se->dev, "failed to submit host1x job\n");
|
||||
goto err_job_submit;
|
||||
goto job_unpin;
|
||||
}
|
||||
|
||||
ret = host1x_syncpt_wait(job->syncpt, job->syncpt_end,
|
||||
MAX_SCHEDULE_TIMEOUT, NULL);
|
||||
MAX_SCHEDULE_TIMEOUT, NULL);
|
||||
if (ret) {
|
||||
dev_err(se->dev, "host1x job timed out\n");
|
||||
return ret;
|
||||
@@ -187,9 +186,9 @@ int tegra_se_host1x_submit(struct tegra_se *se, u32 size)
|
||||
host1x_job_put(job);
|
||||
return 0;
|
||||
|
||||
err_job_submit:
|
||||
job_unpin:
|
||||
host1x_job_unpin(job);
|
||||
err_job_pin:
|
||||
job_put:
|
||||
host1x_job_put(job);
|
||||
|
||||
return ret;
|
||||
@@ -210,7 +209,7 @@ static int tegra_se_client_init(struct host1x_client *client)
|
||||
if (!se->syncpt) {
|
||||
dev_err(se->dev, "host1x syncpt allocation failed\n");
|
||||
ret = -EINVAL;
|
||||
goto err_syncpt;
|
||||
goto channel_put;
|
||||
}
|
||||
|
||||
se->syncpt_id = host1x_syncpt_id(se->syncpt);
|
||||
@@ -218,22 +217,30 @@ static int tegra_se_client_init(struct host1x_client *client)
|
||||
se->cmdbuf = tegra_se_host1x_bo_alloc(se, SZ_4K);
|
||||
if (!se->cmdbuf) {
|
||||
ret = -ENOMEM;
|
||||
goto err_bo;
|
||||
goto syncpt_put;
|
||||
}
|
||||
|
||||
se->keybuf = tegra_se_host1x_bo_alloc(se, SZ_4K);
|
||||
if (!se->cmdbuf) {
|
||||
ret = -ENOMEM;
|
||||
goto cmdbuf_put;
|
||||
}
|
||||
|
||||
ret = se->hw->init_alg(se);
|
||||
if (ret) {
|
||||
dev_err(se->dev, "failed to register algorithms\n");
|
||||
goto err_alg_reg;
|
||||
goto keybuf_put;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_alg_reg:
|
||||
keybuf_put:
|
||||
tegra_se_cmdbuf_put(&se->keybuf->bo);
|
||||
cmdbuf_put:
|
||||
tegra_se_cmdbuf_put(&se->cmdbuf->bo);
|
||||
err_bo:
|
||||
syncpt_put:
|
||||
host1x_syncpt_put(se->syncpt);
|
||||
err_syncpt:
|
||||
channel_put:
|
||||
host1x_channel_put(se->channel);
|
||||
|
||||
return ret;
|
||||
@@ -243,7 +250,7 @@ static int tegra_se_client_deinit(struct host1x_client *client)
|
||||
{
|
||||
struct tegra_se *se = container_of(client, struct tegra_se, client);
|
||||
|
||||
se->hw->deinit_alg();
|
||||
se->hw->deinit_alg(se);
|
||||
tegra_se_cmdbuf_put(&se->cmdbuf->bo);
|
||||
host1x_syncpt_put(se->syncpt);
|
||||
host1x_channel_put(se->channel);
|
||||
@@ -256,7 +263,7 @@ static const struct host1x_client_ops tegra_se_client_ops = {
|
||||
.exit = tegra_se_client_deinit,
|
||||
};
|
||||
|
||||
int tegra_se_host1x_register(struct tegra_se *se)
|
||||
static int tegra_se_host1x_register(struct tegra_se *se)
|
||||
{
|
||||
INIT_LIST_HEAD(&se->client.list);
|
||||
se->client.dev = se->dev;
|
||||
@@ -269,38 +276,6 @@ int tegra_se_host1x_register(struct tegra_se *se)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_se_clk_init(struct tegra_se *se)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
se->num_clks = devm_clk_bulk_get_all(se->dev, &se->clks);
|
||||
if (se->num_clks < 0) {
|
||||
dev_err(se->dev, "failed to get clocks\n");
|
||||
return se->num_clks;
|
||||
}
|
||||
|
||||
for (i = 0; i < se->num_clks; i++) {
|
||||
ret = clk_set_rate(se->clks[i].clk, ULONG_MAX);
|
||||
if (ret) {
|
||||
dev_err(se->dev, "failed to set %d clock rate", i);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = clk_bulk_prepare_enable(se->num_clks, se->clks);
|
||||
if (ret) {
|
||||
dev_err(se->dev, "failed to enable clocks\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_se_clk_deinit(struct tegra_se *se)
|
||||
{
|
||||
clk_bulk_disable_unprepare(se->num_clks, se->clks);
|
||||
}
|
||||
|
||||
static int tegra_se_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@@ -312,61 +287,45 @@ static int tegra_se_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
se->dev = dev;
|
||||
se->owner = TEGRA_GPSE_ID;
|
||||
se->hw = device_get_match_data(&pdev->dev);
|
||||
|
||||
se->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(se->base))
|
||||
return PTR_ERR(se->base);
|
||||
|
||||
se->owner = TEGRA_GPSE_ID;
|
||||
|
||||
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(39));
|
||||
platform_set_drvdata(pdev, se);
|
||||
|
||||
ret = tegra_se_clk_init(se);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to init clocks\n");
|
||||
return ret;
|
||||
}
|
||||
se->clk = devm_clk_get_enabled(se->dev, NULL);
|
||||
if (IS_ERR(se->clk))
|
||||
return dev_err_probe(dev, PTR_ERR(se->clk),
|
||||
"failed to enable clocks\n");
|
||||
|
||||
if (!tegra_dev_iommu_get_stream_id(dev, &se->stream_id)) {
|
||||
dev_err(dev, "failed to get IOMMU stream ID\n");
|
||||
goto err_iommu_spec;
|
||||
}
|
||||
if (!tegra_dev_iommu_get_stream_id(dev, &se->stream_id))
|
||||
return dev_err_probe(dev, -ENODEV,
|
||||
"failed to get IOMMU stream ID\n");
|
||||
|
||||
se_writel(se, se->stream_id, SE_STREAM_ID);
|
||||
writel(se->stream_id, se->base + SE_STREAM_ID);
|
||||
|
||||
se->engine = crypto_engine_alloc_init(dev, 0);
|
||||
if (!se->engine) {
|
||||
dev_err(dev, "failed to init crypto engine\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_engine_alloc;
|
||||
}
|
||||
if (!se->engine)
|
||||
return dev_err_probe(dev, -ENOMEM, "failed to init crypto engine\n");
|
||||
|
||||
ret = crypto_engine_start(se->engine);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to start crypto engine\n");
|
||||
goto err_engine_start;
|
||||
crypto_engine_exit(se->engine);
|
||||
return dev_err_probe(dev, ret, "failed to start crypto engine\n");
|
||||
}
|
||||
|
||||
ret = tegra_se_host1x_register(se);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to init host1x params\n");
|
||||
goto err_host1x_init;
|
||||
crypto_engine_stop(se->engine);
|
||||
crypto_engine_exit(se->engine);
|
||||
return dev_err_probe(dev, ret, "failed to init host1x params\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_host1x_init:
|
||||
crypto_engine_stop(se->engine);
|
||||
err_engine_start:
|
||||
crypto_engine_exit(se->engine);
|
||||
err_engine_alloc:
|
||||
iommu_fwspec_free(se->dev);
|
||||
err_iommu_spec:
|
||||
tegra_se_clk_deinit(se);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tegra_se_remove(struct platform_device *pdev)
|
||||
@@ -377,7 +336,6 @@ static int tegra_se_remove(struct platform_device *pdev)
|
||||
crypto_engine_exit(se->engine);
|
||||
iommu_fwspec_free(se->dev);
|
||||
host1x_client_unregister(&se->client);
|
||||
tegra_se_clk_deinit(se);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -424,10 +382,10 @@ static const struct tegra_se_hw tegra234_hash_hw = {
|
||||
|
||||
static const struct of_device_id tegra_se_of_match[] = {
|
||||
{
|
||||
.compatible = "nvidia,tegra234-se2-aes",
|
||||
.compatible = "nvidia,tegra234-se-aes",
|
||||
.data = &tegra234_aes_hw
|
||||
}, {
|
||||
.compatible = "nvidia,tegra234-se4-hash",
|
||||
.compatible = "nvidia,tegra234-se-hash",
|
||||
.data = &tegra234_hash_hw,
|
||||
},
|
||||
{ },
|
||||
@@ -486,4 +444,4 @@ module_exit(tegra_se_module_exit);
|
||||
|
||||
MODULE_DESCRIPTION("NVIDIA Tegra Security Engine Driver");
|
||||
MODULE_AUTHOR("Akhil R <akhilrajeev@nvidia.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* Header file for NVIDIA Security Engine driver.
|
||||
*/
|
||||
@@ -7,22 +7,18 @@
|
||||
#ifndef _TEGRA_SE_H
|
||||
#define _TEGRA_SE_H
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/host1x-next.h>
|
||||
#include <linux/version.h>
|
||||
#include <crypto/aead.h>
|
||||
#include <crypto/engine.h>
|
||||
#include <crypto/hash.h>
|
||||
#include <crypto/sha1.h>
|
||||
#include <crypto/sha3.h>
|
||||
#include <crypto/sm3.h>
|
||||
#include <crypto/skcipher.h>
|
||||
#include <nvidia/conftest.h>
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
#include <crypto/engine.h>
|
||||
#endif
|
||||
|
||||
#define SE_MAX_INSTANCES 3
|
||||
#define SE_OWNERSHIP 0x14
|
||||
#define SE_OWNERSHIP_UID(x) FIELD_GET(GENMASK(7, 0), x)
|
||||
#define TEGRA_GPSE_ID 3
|
||||
@@ -67,11 +63,8 @@
|
||||
#define SE_SHA_ENC_ALG_HMAC SE_SHA_CFG_ENC_ALG(7)
|
||||
#define SE_SHA_ENC_ALG_KDF SE_SHA_CFG_ENC_ALG(8)
|
||||
#define SE_SHA_ENC_ALG_KEY_INVLD SE_SHA_CFG_ENC_ALG(10)
|
||||
#define SE_SHA_ENC_ALG_KEY_MOV SE_SHA_CFG_ENC_ALG(11)
|
||||
#define SE_SHA_ENC_ALG_KEY_INQUIRE SE_SHA_CFG_ENC_ALG(12)
|
||||
#define SE_SHA_ENC_ALG_INS SE_SHA_CFG_ENC_ALG(13)
|
||||
#define SE_SHA_ENC_ALG_CLONE SE_SHA_CFG_ENC_ALG(14)
|
||||
#define SE_SHA_ENC_ALG_LOCK SE_SHA_CFG_ENC_ALG(15)
|
||||
|
||||
#define SE_SHA_OP_LASTBUF FIELD_PREP(BIT(16), 1)
|
||||
#define SE_SHA_OP_WRSTALL FIELD_PREP(BIT(15), 1)
|
||||
@@ -311,12 +304,6 @@
|
||||
SE_AES_CORE_SEL_DECRYPT | \
|
||||
SE_AES_IV_SEL_REG)
|
||||
|
||||
#define SE_CRYPTO_CFG_OFB (SE_AES_INPUT_SEL_AESOUT | \
|
||||
SE_AES_VCTRAM_SEL_MEMORY | \
|
||||
SE_AES_XOR_POS_BOTTOM | \
|
||||
SE_AES_CORE_SEL_ENCRYPT | \
|
||||
SE_AES_IV_SEL_REG)
|
||||
|
||||
#define SE_CRYPTO_CFG_CTR (SE_AES_INPUT_SEL_LINEAR_CTR | \
|
||||
SE_AES_VCTRAM_SEL_MEMORY | \
|
||||
SE_AES_XOR_POS_BOTTOM | \
|
||||
@@ -355,8 +342,9 @@
|
||||
#define SE_CRYPTO_CTR_REG_COUNT 4
|
||||
#define SE_MAX_KEYSLOT 15
|
||||
#define SE_MAX_MEM_ALLOC SZ_4M
|
||||
#define SE_AES_BUFLEN 0x8000
|
||||
#define SE_SHA_BUFLEN SZ_4M
|
||||
|
||||
#define TEGRA_AES_RESERVED_KSLT 14
|
||||
#define TEGRA_XTS_RESERVED_KSLT 15
|
||||
|
||||
#define SHA_FIRST BIT(0)
|
||||
#define SHA_UPDATE BIT(1)
|
||||
@@ -383,7 +371,6 @@ enum se_aes_alg {
|
||||
SE_ALG_CBC, /* Cipher Block Chaining (CBC) mode */
|
||||
SE_ALG_ECB, /* Electronic Codebook (ECB) mode */
|
||||
SE_ALG_CTR, /* Counter (CTR) mode */
|
||||
SE_ALG_OFB, /* Output feedback (CFB) mode */
|
||||
SE_ALG_XTS, /* XTS mode */
|
||||
SE_ALG_GMAC, /* GMAC mode */
|
||||
SE_ALG_GCM, /* GCM mode */
|
||||
@@ -417,13 +404,13 @@ struct tegra_se_alg {
|
||||
|
||||
union {
|
||||
#ifndef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
struct skcipher_alg skcipher;
|
||||
struct aead_alg aead;
|
||||
struct ahash_alg ahash;
|
||||
struct skcipher_alg skcipher;
|
||||
struct aead_alg aead;
|
||||
struct ahash_alg ahash;
|
||||
#else
|
||||
struct skcipher_engine_alg skcipher;
|
||||
struct aead_engine_alg aead;
|
||||
struct ahash_engine_alg ahash;
|
||||
struct skcipher_engine_alg skcipher;
|
||||
struct aead_engine_alg aead;
|
||||
struct ahash_engine_alg ahash;
|
||||
#endif
|
||||
} alg;
|
||||
};
|
||||
@@ -446,7 +433,7 @@ struct tegra_se_regs {
|
||||
struct tegra_se_hw {
|
||||
const struct tegra_se_regs *regs;
|
||||
int (*init_alg)(struct tegra_se *se);
|
||||
void (*deinit_alg)(void);
|
||||
void (*deinit_alg)(struct tegra_se *se);
|
||||
bool support_sm_alg;
|
||||
u32 host1x_class;
|
||||
u32 kac_ver;
|
||||
@@ -455,18 +442,18 @@ struct tegra_se_hw {
|
||||
struct tegra_se {
|
||||
int (*manifest)(u32 user, u32 alg, u32 keylen);
|
||||
const struct tegra_se_hw *hw;
|
||||
struct crypto_engine *engine;
|
||||
struct host1x_channel *channel;
|
||||
struct host1x_client client;
|
||||
struct host1x_syncpt *syncpt;
|
||||
struct clk_bulk_data *clks;
|
||||
struct host1x_channel *channel;
|
||||
struct tegra_se_cmdbuf *cmdbuf;
|
||||
struct tegra_se_cmdbuf *keybuf;
|
||||
struct crypto_engine *engine;
|
||||
struct host1x_syncpt *syncpt;
|
||||
struct device *dev;
|
||||
struct clk *clk;
|
||||
unsigned int opcode_addr;
|
||||
unsigned int stream_id;
|
||||
unsigned int syncpt_id;
|
||||
void __iomem *base;
|
||||
int num_clks;
|
||||
u32 owner;
|
||||
};
|
||||
|
||||
@@ -476,8 +463,8 @@ struct tegra_se_cmdbuf {
|
||||
struct device *dev;
|
||||
struct kref ref;
|
||||
struct host1x_bo bo;
|
||||
u32 words;
|
||||
ssize_t size;
|
||||
u32 words;
|
||||
};
|
||||
|
||||
struct tegra_se_datbuf {
|
||||
@@ -492,8 +479,6 @@ static inline int se_algname_to_algid(const char *name)
|
||||
return SE_ALG_CBC;
|
||||
else if (!strcmp(name, "ecb(aes)"))
|
||||
return SE_ALG_ECB;
|
||||
else if (!strcmp(name, "ofb(aes)"))
|
||||
return SE_ALG_OFB;
|
||||
else if (!strcmp(name, "ctr(aes)"))
|
||||
return SE_ALG_CTR;
|
||||
else if (!strcmp(name, "xts(aes)"))
|
||||
@@ -536,87 +521,85 @@ static inline int se_algname_to_algid(const char *name)
|
||||
}
|
||||
|
||||
/* Functions */
|
||||
int tegra_init_aead(struct tegra_se *se);
|
||||
int tegra_init_aes(struct tegra_se *se);
|
||||
int tegra_init_hash(struct tegra_se *se);
|
||||
void tegra_deinit_aead(void);
|
||||
void tegra_deinit_aes(void);
|
||||
void tegra_deinit_hash(void);
|
||||
void tegra_deinit_aes(struct tegra_se *se);
|
||||
void tegra_deinit_hash(struct tegra_se *se);
|
||||
int tegra_key_submit(struct tegra_se *se, const u8 *key,
|
||||
u32 keylen, u32 alg, u32 *keyid);
|
||||
void tegra_key_invalidate(struct tegra_se *se, u32 keyid, u32 alg);
|
||||
int tegra_key_submit_reserved(struct tegra_se *se, const u8 *key,
|
||||
u32 keylen, u32 alg, u32 *keyid);
|
||||
void tegra_key_invalidate_reserved(struct tegra_se *se, u32 keyid, u32 alg);
|
||||
int tegra_se_host1x_submit(struct tegra_se *se, struct tegra_se_cmdbuf *cmdbuf, u32 size);
|
||||
|
||||
int tegra_key_submit(struct tegra_se *se, const u8 *key, u32 keylen, u32 alg, u32 *keyid);
|
||||
unsigned int tegra_key_get_idx(struct tegra_se *se, u32 keyid);
|
||||
void tegra_key_invalidate(struct tegra_se *se, u32 keyid);
|
||||
|
||||
int tegra_se_host1x_register(struct tegra_se *se);
|
||||
int tegra_se_host1x_submit(struct tegra_se *se, u32 size);
|
||||
|
||||
static inline void se_writel(struct tegra_se *se, unsigned int val,
|
||||
unsigned int offset)
|
||||
static inline int tegra_key_submit_reserved_aes(struct tegra_se *se, const u8 *key,
|
||||
u32 keylen, u32 alg, u32 *keyid)
|
||||
{
|
||||
writel_relaxed(val, se->base + offset);
|
||||
*keyid = TEGRA_AES_RESERVED_KSLT;
|
||||
return tegra_key_submit_reserved(se, key, keylen, alg, keyid);
|
||||
}
|
||||
|
||||
static inline u32 se_readl(struct tegra_se *se, unsigned int offset)
|
||||
static inline int tegra_key_submit_reserved_xts(struct tegra_se *se, const u8 *key,
|
||||
u32 keylen, u32 alg, u32 *keyid)
|
||||
{
|
||||
return readl_relaxed(se->base + offset);
|
||||
*keyid = TEGRA_XTS_RESERVED_KSLT;
|
||||
return tegra_key_submit_reserved(se, key, keylen, alg, keyid);
|
||||
}
|
||||
|
||||
static inline bool tegra_key_is_reserved(u32 keyid)
|
||||
{
|
||||
return ((keyid == TEGRA_AES_RESERVED_KSLT) ||
|
||||
(keyid == TEGRA_XTS_RESERVED_KSLT));
|
||||
}
|
||||
|
||||
/****
|
||||
*
|
||||
* HOST1x OPCODES
|
||||
*
|
||||
****/
|
||||
|
||||
/* HOST1x OPCODES */
|
||||
static inline u32 host1x_opcode_setpayload(unsigned int payload)
|
||||
{
|
||||
return (9 << 28) | payload;
|
||||
}
|
||||
|
||||
#define host1x_opcode_incr_w(x) __host1x_opcode_incr_w((x) / 4)
|
||||
static inline u32 __host1x_opcode_incr_w(unsigned int offset)
|
||||
static inline u32 host1x_opcode_incr_w(unsigned int offset)
|
||||
{
|
||||
/* 22-bit offset supported */
|
||||
return (10 << 28) | offset;
|
||||
}
|
||||
|
||||
#define host1x_opcode_nonincr_w(x) __host1x_opcode_nonincr_w((x) / 4)
|
||||
static inline u32 __host1x_opcode_nonincr_w(unsigned int offset)
|
||||
static inline u32 host1x_opcode_nonincr_w(unsigned int offset)
|
||||
{
|
||||
/* 22-bit offset supported */
|
||||
return (11 << 28) | offset;
|
||||
}
|
||||
|
||||
#define host1x_opcode_incr(x, y) __host1x_opcode_incr((x) / 4, y)
|
||||
static inline u32 __host1x_opcode_incr(unsigned int offset, unsigned int count)
|
||||
static inline u32 host1x_opcode_incr(unsigned int offset, unsigned int count)
|
||||
{
|
||||
return (1 << 28) | (offset << 16) | count;
|
||||
return (1 << 28) | (offset << 16) | count;
|
||||
}
|
||||
|
||||
#define host1x_opcode_nonincr(x, y) __host1x_opcode_nonincr((x) / 4, y)
|
||||
static inline u32 __host1x_opcode_nonincr(unsigned int offset, unsigned int count)
|
||||
static inline u32 host1x_opcode_nonincr(unsigned int offset, unsigned int count)
|
||||
{
|
||||
return (2 << 28) | (offset << 16) | count;
|
||||
return (2 << 28) | (offset << 16) | count;
|
||||
}
|
||||
|
||||
static inline u32 host1x_uclass_incr_syncpt_cond_f(u32 v)
|
||||
{
|
||||
return (v & 0xff) << 10;
|
||||
return (v & 0xff) << 10;
|
||||
}
|
||||
|
||||
static inline u32 host1x_uclass_incr_syncpt_indx_f(u32 v)
|
||||
{
|
||||
return (v & 0x3ff) << 0;
|
||||
return (v & 0x3ff) << 0;
|
||||
}
|
||||
|
||||
static inline u32 host1x_uclass_wait_syncpt_r(void)
|
||||
{
|
||||
return 0x8;
|
||||
return 0x8;
|
||||
}
|
||||
|
||||
static inline u32 host1x_uclass_incr_syncpt_r(void)
|
||||
{
|
||||
return 0x0;
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
#if !defined(NV_TEGRA_DEV_IOMMU_GET_STREAM_ID_PRESENT)
|
||||
@@ -635,4 +618,9 @@ static inline bool tegra_dev_iommu_get_stream_id(struct device *dev, u32 *stream
|
||||
}
|
||||
#endif
|
||||
|
||||
#define se_host1x_opcode_incr_w(x) host1x_opcode_incr_w((x) / 4)
|
||||
#define se_host1x_opcode_nonincr_w(x) host1x_opcode_nonincr_w((x) / 4)
|
||||
#define se_host1x_opcode_incr(x, y) host1x_opcode_incr((x) / 4, y)
|
||||
#define se_host1x_opcode_nonincr(x, y) host1x_opcode_nonincr((x) / 4, y)
|
||||
|
||||
#endif /*_TEGRA_SE_H*/
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <linux/console.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/fb.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_prime.h>
|
||||
|
||||
@@ -43,11 +43,37 @@
|
||||
#define NVDEC_TFBIF_ACTMON_ACTIVE_WEIGHT 0x2c54
|
||||
#define NVDEC_AXI_RW_BANDWIDTH 512
|
||||
|
||||
#define NVDEC_CG_SLCG_CTRL 0x297c
|
||||
#define NVDEC_CG_SLCG_CTRL_IDLE_SLCG_DIS BIT(9)
|
||||
#define NVDEC_RISCV_CG 0x4398
|
||||
#define NVDEC_RISCV_CG_SLCG BIT(0)
|
||||
#define NVDEC_RISCV_CG_CORE_SLCG BIT(1)
|
||||
|
||||
#define NVDEC_PG 0x2314
|
||||
#define NVDEC_PG_DEEP_ELPG_EN BIT(18)
|
||||
#define NVDEC_PG1 0x2318
|
||||
#define NVDEC_CG2 0x2328
|
||||
#define NVDEC_CG3 0x232c
|
||||
#define NVDEC_CG4 0x2950
|
||||
#define NVDEC_CG5 0x2954
|
||||
#define NVDEC_CG6 0x2958
|
||||
#define NVDEC_CG7 0x295c
|
||||
#define NVDEC_CG8 0x2960
|
||||
#define NVDEC_CG9 0x2964
|
||||
#define NVDEC_CG10 0x2968
|
||||
#define NVDEC_CG11 0x296c
|
||||
#define NVDEC_CG12 0x2970
|
||||
|
||||
#define NVDEC_TFBIF_ACTMON_ACTIVE_MASK_STARVED BIT(0)
|
||||
#define NVDEC_TFBIF_ACTMON_ACTIVE_MASK_STALLED BIT(1)
|
||||
#define NVDEC_TFBIF_ACTMON_ACTIVE_MASK_DELAYED BIT(2)
|
||||
#define NVDEC_TFBIF_ACTMON_ACTIVE_BORPS_ACTIVE BIT(7)
|
||||
|
||||
struct nvdec_cg_reg {
|
||||
u32 offset;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
struct nvdec_config {
|
||||
const char *firmware;
|
||||
unsigned int version;
|
||||
@@ -55,6 +81,7 @@ struct nvdec_config {
|
||||
bool supports_timestamping;
|
||||
bool has_riscv;
|
||||
bool has_extra_clocks;
|
||||
const struct nvdec_cg_reg *cg_regs;
|
||||
};
|
||||
|
||||
struct nvdec {
|
||||
@@ -91,6 +118,11 @@ static inline void nvdec_writel(struct nvdec *nvdec, u32 value,
|
||||
writel(value, nvdec->regs + offset);
|
||||
}
|
||||
|
||||
static inline u32 nvdec_readl(struct nvdec *nvdec, unsigned int offset)
|
||||
{
|
||||
return readl(nvdec->regs + offset);
|
||||
}
|
||||
|
||||
static int nvdec_set_rate(struct nvdec *nvdec, unsigned long rate)
|
||||
{
|
||||
unsigned long dev_rate;
|
||||
@@ -557,6 +589,29 @@ static void nvdec_count_weight_init(struct nvdec *nvdec, unsigned long rate)
|
||||
}
|
||||
}
|
||||
|
||||
static void nvdec_enable_slcg(struct nvdec *nvdec)
|
||||
{
|
||||
const struct nvdec_cg_reg *cg;
|
||||
u32 val;
|
||||
|
||||
if (!nvdec->config->cg_regs)
|
||||
return;
|
||||
|
||||
/* Enable power gating */
|
||||
nvdec_writel(nvdec, 0xff00a725, NVDEC_PG1);
|
||||
nvdec_writel(nvdec, NVDEC_PG_DEEP_ELPG_EN | (9 << 20) | (2 << 27), NVDEC_PG);
|
||||
|
||||
/* Enable clock gating */
|
||||
for (cg = nvdec->config->cg_regs; cg->offset; cg++)
|
||||
nvdec_writel(nvdec, cg->value, cg->offset);
|
||||
|
||||
val = nvdec_readl(nvdec, NVDEC_CG_SLCG_CTRL);
|
||||
val &= ~NVDEC_CG_SLCG_CTRL_IDLE_SLCG_DIS;
|
||||
nvdec_writel(nvdec, val, NVDEC_CG_SLCG_CTRL);
|
||||
|
||||
nvdec_writel(nvdec, NVDEC_RISCV_CG_SLCG | NVDEC_RISCV_CG_CORE_SLCG, NVDEC_RISCV_CG);
|
||||
}
|
||||
|
||||
static __maybe_unused int nvdec_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct nvdec *nvdec = dev_get_drvdata(dev);
|
||||
@@ -582,6 +637,8 @@ static __maybe_unused int nvdec_runtime_resume(struct device *dev)
|
||||
goto disable;
|
||||
}
|
||||
|
||||
nvdec_enable_slcg(nvdec);
|
||||
|
||||
/* Forcely set frequency as Fmax when device is resumed back */
|
||||
nvdec->devfreq->resume_freq = nvdec->devfreq->scaling_max_freq;
|
||||
err = devfreq_resume_device(nvdec->devfreq);
|
||||
@@ -698,12 +755,28 @@ static const struct nvdec_config nvdec_t194_config = {
|
||||
.supports_timestamping = true,
|
||||
};
|
||||
|
||||
static const struct nvdec_cg_reg nvdec_t234_cg_regs[] = {
|
||||
{ NVDEC_CG2, 0x00000000 },
|
||||
{ NVDEC_CG3, 0xfc800000 },
|
||||
{ NVDEC_CG4, 0xffffffc0 },
|
||||
{ NVDEC_CG5, 0x00000040 },
|
||||
{ NVDEC_CG6, 0x04004000 },
|
||||
{ NVDEC_CG7, 0xfc000000 },
|
||||
{ NVDEC_CG8, 0x00000000 },
|
||||
{ NVDEC_CG9, 0x80000000 },
|
||||
{ NVDEC_CG10, 0xfffffb00 },
|
||||
{ NVDEC_CG11, 0xfff80000 },
|
||||
{ NVDEC_CG12, 0xffffff80 },
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct nvdec_config nvdec_t234_config = {
|
||||
.version = 0x23,
|
||||
.supports_sid = true,
|
||||
.supports_timestamping = true,
|
||||
.has_riscv = true,
|
||||
.has_extra_clocks = true,
|
||||
.cg_regs = nvdec_t234_cg_regs,
|
||||
};
|
||||
|
||||
static const struct of_device_id tegra_nvdec_of_match[] = {
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Host1x fence UAPI
|
||||
*
|
||||
* Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved.
|
||||
*/
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
@@ -205,20 +201,28 @@ struct host1x_pollfd {
|
||||
static int host1x_pollfd_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct host1x_pollfd *pollfd = file->private_data;
|
||||
struct host1x_pollfd_fence *pfd_fence;
|
||||
struct host1x_pollfd_fence *pfd_fence, *pfd_fence_temp;
|
||||
|
||||
mutex_lock(&pollfd->lock);
|
||||
|
||||
list_for_each_entry(pfd_fence, &pollfd->fences, list) {
|
||||
list_for_each_entry_safe(pfd_fence, pfd_fence_temp, &pollfd->fences, list) {
|
||||
if (pfd_fence->callback_set) {
|
||||
if (dma_fence_remove_callback(pfd_fence->fence, &pfd_fence->callback))
|
||||
host1x_fence_cancel(pfd_fence->fence);
|
||||
pfd_fence->callback_set = false;
|
||||
}
|
||||
/*The lock/unlock just ensures that the callback execution has finished*/
|
||||
spin_lock(pfd_fence->fence->lock);
|
||||
spin_unlock(pfd_fence->fence->lock);
|
||||
|
||||
dma_fence_put(pfd_fence->fence);
|
||||
kfree(pfd_fence);
|
||||
}
|
||||
|
||||
mutex_unlock(&pollfd->lock);
|
||||
|
||||
kfree(pollfd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -235,8 +239,20 @@ static unsigned int host1x_pollfd_poll(struct file *file, poll_table *wait)
|
||||
list_for_each_entry_safe(pfd_fence, pfd_fence_temp, &pollfd->fences, list) {
|
||||
if (dma_fence_is_signaled(pfd_fence->fence)) {
|
||||
mask = POLLPRI | POLLIN;
|
||||
|
||||
if (pfd_fence->callback_set) {
|
||||
if (dma_fence_remove_callback(pfd_fence->fence,
|
||||
&pfd_fence->callback))
|
||||
host1x_fence_cancel(pfd_fence->fence);
|
||||
pfd_fence->callback_set = false;
|
||||
}
|
||||
/*The lock/unlock just ensures that the callback execution has finished*/
|
||||
spin_lock(pfd_fence->fence->lock);
|
||||
spin_unlock(pfd_fence->fence->lock);
|
||||
|
||||
dma_fence_put(pfd_fence->fence);
|
||||
list_del(&pfd_fence->list);
|
||||
kfree(pfd_fence);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -335,7 +335,11 @@ static int host1x_del_client(struct host1x *host1x,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#if defined(NV_BUS_TYPE_STRUCT_MATCH_HAS_CONST_DRV_ARG)
|
||||
static int host1x_device_match(struct device *dev, const struct device_driver *drv)
|
||||
#else
|
||||
static int host1x_device_match(struct device *dev, struct device_driver *drv)
|
||||
#endif
|
||||
{
|
||||
return strcmp(dev_name(dev), drv->name) == 0;
|
||||
}
|
||||
|
||||
@@ -35,14 +35,14 @@
|
||||
/*
|
||||
* Typically the commands written into the push buffer are a pair of words. We
|
||||
* use slots to represent each of these pairs and to simplify things. Note the
|
||||
* strange number of slots allocated here. 512 slots will fit exactly within a
|
||||
* single memory page. We also need one additional word at the end of the push
|
||||
* strange number of slots allocated here. 1024 slots will fit exactly within a
|
||||
* two memory pages. We also need one additional word at the end of the push
|
||||
* buffer for the RESTART opcode that will instruct the CDMA to jump back to
|
||||
* the beginning of the push buffer. With 512 slots, this means that we'll use
|
||||
* 2 memory pages and waste 4092 bytes of the second page that will never be
|
||||
* the beginning of the push buffer. With 1024 slots, this means that we'll use
|
||||
* 3 memory pages and waste 4092 bytes of the third page that will never be
|
||||
* used.
|
||||
*/
|
||||
#define HOST1X_PUSHBUFFER_SLOTS 511
|
||||
#define HOST1X_PUSHBUFFER_SLOTS 1023
|
||||
|
||||
/*
|
||||
* Clean up push buffer resources
|
||||
|
||||
@@ -177,7 +177,14 @@ static void show_gather(struct output *o, dma_addr_t phys_addr,
|
||||
|
||||
for (i = 0; i < words; i++) {
|
||||
dma_addr_t addr = phys_addr + i * 4;
|
||||
u32 val = *(map_addr + offset / 4 + i);
|
||||
u32 voffset = offset + i * 4;
|
||||
u32 val;
|
||||
|
||||
/* If we reach the RESTART opcode, continue at the beginning of pushbuffer */
|
||||
if (cdma && voffset >= cdma->push_buffer.size)
|
||||
voffset -= cdma->push_buffer.size;
|
||||
|
||||
val = *(map_addr + voffset / 4);
|
||||
|
||||
if (!data_count) {
|
||||
host1x_debug_output(o, " %pad: %08x: ", &addr, val);
|
||||
@@ -203,7 +210,7 @@ static void show_channel_gathers(struct output *o, struct host1x_cdma *cdma)
|
||||
job->num_slots, job->num_unpins);
|
||||
|
||||
show_gather(o, pb->dma + job->first_get, job->num_slots * 2, cdma,
|
||||
pb->dma + job->first_get, pb->mapped + job->first_get);
|
||||
pb->dma, pb->mapped);
|
||||
|
||||
for (i = 0; i < job->num_cmds; i++) {
|
||||
struct host1x_job_gather *g;
|
||||
@@ -227,7 +234,7 @@ static void show_channel_gathers(struct output *o, struct host1x_cdma *cdma)
|
||||
host1x_debug_output(o, " GATHER at %pad+%#x, %d words\n",
|
||||
&g->base, g->offset, g->words);
|
||||
|
||||
show_gather(o, g->base + g->offset, g->words, cdma,
|
||||
show_gather(o, g->base + g->offset, g->words, NULL,
|
||||
g->base, mapped);
|
||||
|
||||
if (!job->gather_copy_mapped)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
@@ -1093,8 +1093,10 @@ static int f75308_probe_child_from_dt(struct device *dev,
|
||||
u32 reg_idx, seg_idx = 0, seg_val;
|
||||
u8 seg5[F75308_MAX_FAN_SEG_CNT];
|
||||
const char *val_str;
|
||||
#if !defined(NV_OF_PROPERTY_FOR_EACH_REMOVED_INTERNAL_ARGS) /* Linux v6.11 */
|
||||
struct property *prop;
|
||||
const __be32 *p;
|
||||
#endif
|
||||
|
||||
status = of_property_read_u32(child, "reg", ®_idx);
|
||||
if (status) {
|
||||
@@ -1125,7 +1127,11 @@ static int f75308_probe_child_from_dt(struct device *dev,
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
#if defined(NV_OF_PROPERTY_FOR_EACH_REMOVED_INTERNAL_ARGS) /* Linux v6.11 */
|
||||
of_property_for_each_u32(child, "5seg", seg_val) {
|
||||
#else
|
||||
of_property_for_each_u32(child, "5seg", prop, p, seg_val) {
|
||||
#endif
|
||||
dev_dbg(dev, "%s: seg5[%u]: %u\n", __func__, seg_idx, seg_val);
|
||||
if (seg_idx < F75308_MAX_FAN_SEG_CNT)
|
||||
seg5[seg_idx++] = seg_val;
|
||||
|
||||
@@ -20,6 +20,7 @@ obj-m += nv_imx477.o
|
||||
obj-m += nv_ov5693.o
|
||||
obj-m += nv_ar0234.o
|
||||
obj-m += nv_hawk_owl.o
|
||||
obj-m += max929x.o
|
||||
endif
|
||||
|
||||
obj-m += pca9570.o
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
194
drivers/media/i2c/max929x.c
Normal file
194
drivers/media/i2c/max929x.c
Normal file
@@ -0,0 +1,194 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* max929x.c - max929x IO Expander driver
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <media/camera_common.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
#include "max929x.h"
|
||||
|
||||
struct max929x {
|
||||
struct i2c_client *i2c_client;
|
||||
struct regmap *regmap;
|
||||
unsigned int pwdn_gpio;
|
||||
unsigned short ser_addr;
|
||||
};
|
||||
struct max929x *priv;
|
||||
|
||||
static int max929x_write_reg(u8 slave_addr, u16 reg, u8 val)
|
||||
{
|
||||
struct i2c_client *i2c_client = priv->i2c_client;
|
||||
int err;
|
||||
|
||||
i2c_client->addr = slave_addr;
|
||||
err = regmap_write(priv->regmap, reg, val);
|
||||
if (err)
|
||||
dev_err(&i2c_client->dev, "%s:i2c write failed, slave_addr 0x%x, 0x%x = 0x%x\n",
|
||||
__func__, slave_addr, reg, val);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int max929x_write_reg_list(struct max929x_reg *table, int size)
|
||||
{
|
||||
struct device dev = priv->i2c_client->dev;
|
||||
int err = 0;
|
||||
int i;
|
||||
u8 slave_addr;
|
||||
u16 reg;
|
||||
u8 val;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if (table[i].slave_addr == SER_SLAVE2)
|
||||
slave_addr = priv->ser_addr;
|
||||
else
|
||||
slave_addr = table[i].slave_addr;
|
||||
|
||||
reg = table[i].reg;
|
||||
val = table[i].val;
|
||||
|
||||
if (slave_addr == 0xf1) {
|
||||
msleep(val);
|
||||
msleep(2000);
|
||||
continue;
|
||||
}
|
||||
|
||||
dev_dbg(&dev, "%s: size %d, slave_addr 0x%x, reg 0x%x, val 0x%x\n",
|
||||
__func__, size, slave_addr, reg, val);
|
||||
|
||||
err = max929x_write_reg(slave_addr, reg, val);
|
||||
if (err != 0)
|
||||
break;
|
||||
mdelay(5);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct regmap_config max929x_regmap_config = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int max929x_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int max929x_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
#endif
|
||||
{
|
||||
struct device dev = client->dev;
|
||||
struct device_node *np = (&dev)->of_node;
|
||||
unsigned short ser_addr = SER_SLAVE2;
|
||||
int err;
|
||||
|
||||
dev_dbg(&dev, "%s: enter\n", __func__);
|
||||
|
||||
priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
|
||||
priv->i2c_client = client;
|
||||
priv->regmap = devm_regmap_init_i2c(priv->i2c_client, &max929x_regmap_config);
|
||||
if (IS_ERR(priv->regmap)) {
|
||||
dev_err(&client->dev,
|
||||
"regmap init failed: %ld\n", PTR_ERR(priv->regmap));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
priv->pwdn_gpio = of_get_named_gpio(np, "pwdn-gpios", 0);
|
||||
if (priv->pwdn_gpio < 0) {
|
||||
dev_err(&dev, "pwdn-gpios not found\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (priv->pwdn_gpio) {
|
||||
gpio_direction_output(priv->pwdn_gpio, 1);
|
||||
gpio_set_value(priv->pwdn_gpio, 1);
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to find the I2C address of serializer by writting to register
|
||||
* 0x00 at i2c slave address 0x62 and 0x40. When write is successful
|
||||
* the slave address is saved and used when configuring serializer.
|
||||
*/
|
||||
if (max929x_write_reg(SER_SLAVE2, MAX9295_DEV_ADDR, SER_SLAVE2 << 1)) {
|
||||
if (max929x_write_reg(SER_SLAVE1, MAX9295_DEV_ADDR, SER_SLAVE1 << 1)) {
|
||||
dev_err(&dev, "%s: failed to find serializer at 0x%x or 0x%x\n",
|
||||
__func__, SER_SLAVE2, SER_SLAVE1);
|
||||
return -ENODEV;
|
||||
}
|
||||
ser_addr = SER_SLAVE1;
|
||||
}
|
||||
|
||||
msleep(100);
|
||||
priv->ser_addr = ser_addr;
|
||||
|
||||
err = max929x_write_reg_list(max929x_Double_Dser_Ser_init,
|
||||
sizeof(max929x_Double_Dser_Ser_init)/sizeof(struct max929x_reg));
|
||||
if (err == 0)
|
||||
dev_dbg(&dev, "%s: success\n", __func__);
|
||||
else
|
||||
dev_err(&dev, "%s: fail\n", __func__);
|
||||
|
||||
dev_set_drvdata(&client->dev, priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int max929x_remove(struct i2c_client *client)
|
||||
#else
|
||||
static void max929x_remove(struct i2c_client *client)
|
||||
#endif
|
||||
{
|
||||
struct device dev = client->dev;
|
||||
|
||||
gpio_set_value(priv->pwdn_gpio, 0);
|
||||
dev_dbg(&dev, "%s: \n", __func__);
|
||||
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const struct i2c_device_id max929x_id[] = {
|
||||
{ "max929x", 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max929x_id);
|
||||
|
||||
const struct of_device_id max929x_of_match[] = {
|
||||
{ .compatible = "Maxim,max929x", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max929x_of_match);
|
||||
|
||||
static struct i2c_driver max929x_i2c_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "max929x",
|
||||
.of_match_table = of_match_ptr(max929x_of_match),
|
||||
},
|
||||
.probe = max929x_probe,
|
||||
.remove = max929x_remove,
|
||||
.id_table = max929x_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(max929x_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("IO Expander driver max929x");
|
||||
MODULE_AUTHOR("NVIDIA Corporation");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
152
drivers/media/i2c/max929x.h
Normal file
152
drivers/media/i2c/max929x.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* SPDX-FileCopyrightText: Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
|
||||
|
||||
#ifndef __MAX929X_H__
|
||||
#define __MAX929X_H__
|
||||
|
||||
/* TI FPD Link III 954 deser I2C address */
|
||||
#define TI954_ADDR (0x30)
|
||||
/* TI FPD Link III 953 ser I2C address */
|
||||
#define TI953_ADDR (0x18)
|
||||
/* TI 953 alias address */
|
||||
#define TI953_CAM1_ADDR (0x29)
|
||||
#define TI953_CAM2_ADDR (0X2A)
|
||||
|
||||
#define MAX9295_DEV_ADDR 0x00
|
||||
|
||||
#define SENSOR_ADDR (0x1a)
|
||||
/* CAM alias address */
|
||||
#define CAM1_SENSOR_ADDR (0x1b)
|
||||
#define CAM2_SENSOR_ADDR (0x1c)
|
||||
|
||||
#define TI954_RESET_ADDR (0x01)
|
||||
#define TI954_RESET_VAL (0x02)
|
||||
|
||||
#define AFDRV_I2C_ADDR (0x3E)
|
||||
/*AF ctrl*/
|
||||
#define AFDRV1_I2C_ADDR (0x21)
|
||||
#define AFDRV2_I2C_ADDR (0x20)
|
||||
|
||||
#define EEPROM_I2C_ADDR (0x50)
|
||||
/*eeprom ctrl*/
|
||||
#define EEPROM1_I2C_ADDR (0x51)
|
||||
#define EEPROM2_I2C_ADDR (0x52)
|
||||
|
||||
struct max929x_reg {
|
||||
u8 slave_addr;
|
||||
u16 reg;
|
||||
u8 val;
|
||||
};
|
||||
|
||||
/* Serializer slave addresses */
|
||||
#define SER_SLAVE1 0x40
|
||||
#define SER_SLAVE2 0x62
|
||||
|
||||
/* Deserializer slave addresses */
|
||||
#define DESER_SLAVE 0x48
|
||||
|
||||
/*
|
||||
* MAX9296 i2c addr 0x90(8bits) 0x48(7bits)
|
||||
* (MAX9296 link A) MAX9295 i2c addr 0xc4(8bits) 0x62(7bits)
|
||||
*/
|
||||
static struct max929x_reg max929x_Double_Dser_Ser_init[] = {
|
||||
/* set MFP0 low to reset sensor */
|
||||
{0x62, 0x02be, 0x80},
|
||||
/* Set SER to 1x4 mode (phy_config = 0) */
|
||||
{0x62, 0x0330, 0x00},
|
||||
{0x62, 0x0332, 0xe4},
|
||||
/* Additional lane map */
|
||||
{0x62, 0x0333, 0xe4},
|
||||
/* Set 4 lanes for serializer (ctrl1_num_lanes = 3) */
|
||||
{0x62, 0x0331, 0x31},
|
||||
/* Start video from both port A and port B. */
|
||||
{0x62, 0x0311, 0x20},
|
||||
/*
|
||||
* Enable info lines. Additional start bits for Port A and B.
|
||||
* Use data from port B for all pipelines
|
||||
*/
|
||||
{0x62, 0x0308, 0x62},
|
||||
/* Route 16bit DCG (DT = 0x30) to VIDEO_X (Bit 6 enable) */
|
||||
{0x62, 0x0314, 0x22},
|
||||
/* Route 12bit RAW (DT = 0x2C) to VIDEO_Y (Bit 6 enable) */
|
||||
{0x62, 0x0316, 0x6c},
|
||||
/* Route EMBEDDED8 to VIDEO_Z (Bit 6 enable) */
|
||||
{0x62, 0x0318, 0x22},
|
||||
/* Unused VIDEO_U */
|
||||
{0x62, 0x031A, 0x22},
|
||||
/*
|
||||
* Make sure all pipelines start transmission
|
||||
* (VID_TX_EN_X/Y/Z/U = 1)
|
||||
*/
|
||||
{0x62, 0x0002, 0x22},
|
||||
/* Set MIPI Phy Mode: 2x(1x4) mode */
|
||||
{0x48, 0x0330, 0x04},
|
||||
/* lane maps - all 4 ports mapped straight */
|
||||
{0x48, 0x0333, 0x4E},
|
||||
/* Additional lane map */
|
||||
{0x48, 0x0334, 0xE4},
|
||||
/*
|
||||
* lane count - 0 lanes striping on controller 0
|
||||
* (Port A slave in 2x1x4 mode).
|
||||
*/
|
||||
{0x48, 0x040A, 0x00},
|
||||
/*
|
||||
* lane count - 4 lanes striping on controller 1
|
||||
* (Port A master in 2x1x4 mode).
|
||||
*/
|
||||
{0x48, 0x044A, 0xd0},
|
||||
/*
|
||||
* lane count - 4 lanes striping on controller 2
|
||||
* (Port B master in 2x1x4 mode).
|
||||
*/
|
||||
{0x48, 0x048A, 0xd0},
|
||||
/*
|
||||
* lane count - 0 lanes striping on controller 3
|
||||
* (Port B slave in 2x1x4 mode).
|
||||
*/
|
||||
{0x48, 0x04CA, 0x00},
|
||||
/*
|
||||
* MIPI clock rate - 1.5Gbps from controller 0 clock
|
||||
* (Port A slave in 2x1x4 mode).
|
||||
*/
|
||||
{0x48, 0x031D, 0x2f},
|
||||
/*
|
||||
* MIPI clock rate - 1.5Gbps from controller 1 clock
|
||||
* (Port A master in 2x1x4 mode).
|
||||
*/
|
||||
{0x48, 0x0320, 0x2f},
|
||||
/*
|
||||
* MIPI clock rate - 1.5Gbps from controller 2 clock
|
||||
* (Port B master in 2x1x4 mode).
|
||||
*/
|
||||
{0x48, 0x0323, 0x2f},
|
||||
/*
|
||||
* MIPI clock rate - 1.5Gbps from controller 2 clock
|
||||
* (Port B slave in 2x1x4 mode).
|
||||
*/
|
||||
{0x48, 0x0326, 0x2f},
|
||||
/* Route data from stream 0 to pipe X */
|
||||
{0x48, 0x0050, 0x00},
|
||||
/* Route data from stream 0 to pipe Y */
|
||||
{0x48, 0x0051, 0x01},
|
||||
/* Route data from stream 0 to pipe Z */
|
||||
{0x48, 0x0052, 0x02},
|
||||
/* Route data from stream 0 to pipe U */
|
||||
{0x48, 0x0053, 0x03},
|
||||
/* Enable all PHYS. */
|
||||
{0x48, 0x0332, 0xF0},
|
||||
/* Enable sensor power down pin. Put imager in,Active mode */
|
||||
{0x62, 0x02be, 0x90},
|
||||
/* Output RCLK to sensor. */
|
||||
{0x62, 0x03F1, 0x89},
|
||||
/* MFP8 for FSIN */
|
||||
{0x62, 0x02D8, 0x10},
|
||||
{0x62, 0x02D6, 0x04},
|
||||
/* need disable pixel clk out inb order to use MFP1 */
|
||||
{0x48, 0x0005, 0x00},
|
||||
/* GPIO TX compensation */
|
||||
{0x48, 0x02B3, 0x83},
|
||||
{0x48, 0x02B4, 0x10},
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,9 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2015-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* nv_imx219.c - imx219 sensor driver
|
||||
*
|
||||
* Copyright (c) 2015-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
@@ -747,6 +746,7 @@ static int imx219_probe(struct i2c_client *client,
|
||||
|
||||
err = tegracam_v4l2subdev_register(tc_dev, true);
|
||||
if (err) {
|
||||
tegracam_device_unregister(tc_dev);
|
||||
dev_err(dev, "tegra camera subdev registration failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
911
drivers/media/i2c/nv_imx390_archived.c
Normal file
911
drivers/media/i2c/nv_imx390_archived.c
Normal file
@@ -0,0 +1,911 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2018-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
#include <media/max9295.h>
|
||||
#include <media/max9296.h>
|
||||
|
||||
#include <media/tegracam_core.h>
|
||||
#include "imx390_mode_tbls.h"
|
||||
|
||||
#define IMX390_MIN_GAIN (0)
|
||||
#define IMX390_MAX_GAIN (30)
|
||||
#define IMX390_MAX_GAIN_REG ((IMX390_MAX_GAIN - IMX390_MIN_GAIN) * 10 / 3)
|
||||
#define IMX390_DEFAULT_FRAME_LENGTH (1125)
|
||||
#define IMX390_FRAME_LENGTH_ADDR_MSB 0x200A
|
||||
#define IMX390_FRAME_LENGTH_ADDR_MID 0x2009
|
||||
#define IMX390_FRAME_LENGTH_ADDR_LSB 0x2008
|
||||
#define IMX390_COARSE_TIME_SHS1_ADDR_MSB 0x000E
|
||||
#define IMX390_COARSE_TIME_SHS1_ADDR_MID 0x000D
|
||||
#define IMX390_COARSE_TIME_SHS1_ADDR_LSB 0x000C
|
||||
#define IMX390_COARSE_TIME_SHS2_ADDR_MSB 0x0012
|
||||
#define IMX390_COARSE_TIME_SHS2_ADDR_MID 0x0011
|
||||
#define IMX390_COARSE_TIME_SHS2_ADDR_LSB 0x0010
|
||||
#define IMX390_GROUP_HOLD_ADDR 0x0008
|
||||
#define IMX390_ANALOG_GAIN_SP1H_ADDR 0x0018
|
||||
#define IMX390_ANALOG_GAIN_SP1L_ADDR 0x001A
|
||||
|
||||
static const struct of_device_id imx390_of_match[] = {
|
||||
{ .compatible = "sony,imx390",},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imx390_of_match);
|
||||
|
||||
static const u32 ctrl_cid_list[] = {
|
||||
TEGRA_CAMERA_CID_GAIN,
|
||||
TEGRA_CAMERA_CID_EXPOSURE,
|
||||
TEGRA_CAMERA_CID_EXPOSURE_SHORT,
|
||||
TEGRA_CAMERA_CID_FRAME_RATE,
|
||||
TEGRA_CAMERA_CID_HDR_EN,
|
||||
};
|
||||
|
||||
struct imx390 {
|
||||
struct i2c_client *i2c_client;
|
||||
const struct i2c_device_id *id;
|
||||
struct v4l2_subdev *subdev;
|
||||
struct device *ser_dev;
|
||||
struct device *dser_dev;
|
||||
struct gmsl_link_ctx g_ctx;
|
||||
u32 frame_length;
|
||||
struct camera_common_data *s_data;
|
||||
struct tegracam_device *tc_dev;
|
||||
};
|
||||
|
||||
static const struct regmap_config sensor_regmap_config = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static inline void imx390_get_frame_length_regs(imx390_reg *regs,
|
||||
u32 frame_length)
|
||||
{
|
||||
regs->addr = IMX390_FRAME_LENGTH_ADDR_MSB;
|
||||
regs->val = (frame_length >> 16) & 0x01;
|
||||
|
||||
(regs + 1)->addr = IMX390_FRAME_LENGTH_ADDR_MID;
|
||||
(regs + 1)->val = (frame_length >> 8) & 0xff;
|
||||
|
||||
(regs + 2)->addr = IMX390_FRAME_LENGTH_ADDR_LSB;
|
||||
(regs + 2)->val = (frame_length) & 0xff;
|
||||
}
|
||||
|
||||
static inline void imx390_get_coarse_time_regs_shs1(imx390_reg *regs,
|
||||
u32 coarse_time)
|
||||
{
|
||||
regs->addr = IMX390_COARSE_TIME_SHS1_ADDR_MSB;
|
||||
regs->val = (coarse_time >> 16) & 0x0f;
|
||||
|
||||
(regs + 1)->addr = IMX390_COARSE_TIME_SHS1_ADDR_MID;
|
||||
(regs + 1)->val = (coarse_time >> 8) & 0xff;
|
||||
|
||||
(regs + 2)->addr = IMX390_COARSE_TIME_SHS1_ADDR_LSB;
|
||||
(regs + 2)->val = (coarse_time) & 0xff;
|
||||
}
|
||||
|
||||
static inline void imx390_get_coarse_time_regs_shs2(imx390_reg *regs,
|
||||
u32 coarse_time)
|
||||
{
|
||||
regs->addr = IMX390_COARSE_TIME_SHS2_ADDR_MSB;
|
||||
regs->val = (coarse_time >> 16) & 0x0f;
|
||||
|
||||
(regs + 1)->addr = IMX390_COARSE_TIME_SHS2_ADDR_MID;
|
||||
(regs + 1)->val = (coarse_time >> 8) & 0xff;
|
||||
|
||||
(regs + 2)->addr = IMX390_COARSE_TIME_SHS2_ADDR_LSB;
|
||||
(regs + 2)->val = (coarse_time) & 0xff;
|
||||
}
|
||||
|
||||
static inline void imx390_get_gain_reg(imx390_reg *regs,
|
||||
u16 gain)
|
||||
{
|
||||
regs->addr = IMX390_ANALOG_GAIN_SP1H_ADDR;
|
||||
regs->val = (gain) & 0xff;
|
||||
|
||||
(regs + 1)->addr = IMX390_ANALOG_GAIN_SP1H_ADDR + 1;
|
||||
(regs + 1)->val = (gain >> 8) & 0xff;
|
||||
|
||||
(regs + 2)->addr = IMX390_ANALOG_GAIN_SP1L_ADDR;
|
||||
(regs + 2)->val = (gain) & 0xff;
|
||||
|
||||
(regs + 3)->addr = IMX390_ANALOG_GAIN_SP1L_ADDR + 1;
|
||||
(regs + 3)->val = (gain >> 8) & 0xff;
|
||||
}
|
||||
|
||||
|
||||
static int test_mode;
|
||||
module_param(test_mode, int, 0644);
|
||||
|
||||
static inline int imx390_read_reg(struct camera_common_data *s_data,
|
||||
u16 addr, u8 *val)
|
||||
{
|
||||
int err = 0;
|
||||
u32 reg_val = 0;
|
||||
|
||||
err = regmap_read(s_data->regmap, addr, ®_val);
|
||||
*val = reg_val & 0xFF;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int imx390_write_reg(struct camera_common_data *s_data,
|
||||
u16 addr, u8 val)
|
||||
{
|
||||
int err;
|
||||
struct device *dev = s_data->dev;
|
||||
|
||||
err = regmap_write(s_data->regmap, addr, val);
|
||||
if (err)
|
||||
dev_err(dev, "%s:i2c write failed, 0x%x = %x\n",
|
||||
__func__, addr, val);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int imx390_write_table(struct imx390 *priv,
|
||||
const imx390_reg table[])
|
||||
{
|
||||
struct camera_common_data *s_data = priv->s_data;
|
||||
|
||||
return regmap_util_write_table_8(s_data->regmap,
|
||||
table,
|
||||
NULL, 0,
|
||||
IMX390_TABLE_WAIT_MS,
|
||||
IMX390_TABLE_END);
|
||||
}
|
||||
|
||||
static struct mutex serdes_lock__;
|
||||
|
||||
static int imx390_gmsl_serdes_setup(struct imx390 *priv)
|
||||
{
|
||||
int err = 0;
|
||||
int des_err = 0;
|
||||
struct device *dev;
|
||||
|
||||
if (!priv || !priv->ser_dev || !priv->dser_dev || !priv->i2c_client)
|
||||
return -EINVAL;
|
||||
|
||||
dev = &priv->i2c_client->dev;
|
||||
|
||||
mutex_lock(&serdes_lock__);
|
||||
|
||||
/* For now no separate power on required for serializer device */
|
||||
max9296_power_on(priv->dser_dev);
|
||||
|
||||
/* setup serdes addressing and control pipeline */
|
||||
err = max9296_setup_link(priv->dser_dev, &priv->i2c_client->dev);
|
||||
if (err) {
|
||||
dev_err(dev, "gmsl deserializer link config failed\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = max9295_setup_control(priv->ser_dev);
|
||||
|
||||
/* proceed even if ser setup failed, to setup deser correctly */
|
||||
if (err)
|
||||
dev_err(dev, "gmsl serializer setup failed\n");
|
||||
|
||||
des_err = max9296_setup_control(priv->dser_dev, &priv->i2c_client->dev);
|
||||
if (des_err) {
|
||||
dev_err(dev, "gmsl deserializer setup failed\n");
|
||||
/* overwrite err only if deser setup also failed */
|
||||
err = des_err;
|
||||
}
|
||||
|
||||
error:
|
||||
mutex_unlock(&serdes_lock__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void imx390_gmsl_serdes_reset(struct imx390 *priv)
|
||||
{
|
||||
mutex_lock(&serdes_lock__);
|
||||
|
||||
/* reset serdes addressing and control pipeline */
|
||||
max9295_reset_control(priv->ser_dev);
|
||||
max9296_reset_control(priv->dser_dev, &priv->i2c_client->dev);
|
||||
|
||||
max9296_power_off(priv->dser_dev);
|
||||
|
||||
mutex_unlock(&serdes_lock__);
|
||||
}
|
||||
|
||||
static int imx390_power_on(struct camera_common_data *s_data)
|
||||
{
|
||||
int err = 0;
|
||||
struct camera_common_power_rail *pw = s_data->power;
|
||||
struct camera_common_pdata *pdata = s_data->pdata;
|
||||
struct device *dev = s_data->dev;
|
||||
|
||||
dev_dbg(dev, "%s: power on\n", __func__);
|
||||
if (pdata && pdata->power_on) {
|
||||
err = pdata->power_on(pw);
|
||||
if (err)
|
||||
dev_err(dev, "%s failed.\n", __func__);
|
||||
else
|
||||
pw->state = SWITCH_ON;
|
||||
return err;
|
||||
}
|
||||
|
||||
pw->state = SWITCH_ON;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx390_power_off(struct camera_common_data *s_data)
|
||||
{
|
||||
int err = 0;
|
||||
struct camera_common_power_rail *pw = s_data->power;
|
||||
struct camera_common_pdata *pdata = s_data->pdata;
|
||||
struct device *dev = s_data->dev;
|
||||
|
||||
dev_dbg(dev, "%s:\n", __func__);
|
||||
|
||||
if (pdata && pdata->power_off) {
|
||||
err = pdata->power_off(pw);
|
||||
if (!err)
|
||||
goto power_off_done;
|
||||
else
|
||||
dev_err(dev, "%s failed.\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
power_off_done:
|
||||
pw->state = SWITCH_OFF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx390_power_get(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct device *dev = tc_dev->dev;
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
struct camera_common_power_rail *pw = s_data->power;
|
||||
struct camera_common_pdata *pdata = s_data->pdata;
|
||||
const char *mclk_name;
|
||||
const char *parentclk_name;
|
||||
struct clk *parent;
|
||||
int err = 0;
|
||||
|
||||
mclk_name = pdata->mclk_name ?
|
||||
pdata->mclk_name : "cam_mclk1";
|
||||
pw->mclk = devm_clk_get(dev, mclk_name);
|
||||
if (IS_ERR(pw->mclk)) {
|
||||
dev_err(dev, "unable to get clock %s\n", mclk_name);
|
||||
return PTR_ERR(pw->mclk);
|
||||
}
|
||||
|
||||
parentclk_name = pdata->parentclk_name;
|
||||
if (parentclk_name) {
|
||||
parent = devm_clk_get(dev, parentclk_name);
|
||||
if (IS_ERR(parent)) {
|
||||
dev_err(dev, "unable to get parent clcok %s",
|
||||
parentclk_name);
|
||||
} else {
|
||||
err = clk_set_parent(pw->mclk, parent);
|
||||
if (err < 0)
|
||||
dev_dbg(dev,
|
||||
"%s failed to set parent clock %d\n",
|
||||
__func__, err);
|
||||
}
|
||||
}
|
||||
|
||||
pw->state = SWITCH_OFF;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int imx390_power_put(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
struct camera_common_power_rail *pw = s_data->power;
|
||||
|
||||
if (unlikely(!pw))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx390_set_group_hold(struct tegracam_device *tc_dev, bool val)
|
||||
{
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
struct device *dev = tc_dev->dev;
|
||||
int err;
|
||||
|
||||
err = imx390_write_reg(s_data,
|
||||
IMX390_GROUP_HOLD_ADDR, val);
|
||||
if (err) {
|
||||
dev_dbg(dev,
|
||||
"%s: Group hold control error\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx390_set_gain(struct tegracam_device *tc_dev, s64 val)
|
||||
{
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
struct device *dev = tc_dev->dev;
|
||||
const struct sensor_mode_properties *mode =
|
||||
&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];
|
||||
imx390_reg reg_list[4];
|
||||
int err, i;
|
||||
u16 gain;
|
||||
|
||||
gain = (u16)(val / mode->control_properties.step_gain_val);
|
||||
|
||||
dev_dbg(dev, "%s: db: %d\n", __func__, gain);
|
||||
|
||||
if (gain > IMX390_MAX_GAIN_REG)
|
||||
gain = IMX390_MAX_GAIN_REG;
|
||||
|
||||
imx390_get_gain_reg(reg_list, gain);
|
||||
for (i = 0; i < 4; i++) {
|
||||
err = imx390_write_reg(s_data, reg_list[i].addr,
|
||||
reg_list[i].val);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
dev_info(dev, "%s: GAIN control error\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int imx390_set_frame_rate(struct tegracam_device *tc_dev, s64 val)
|
||||
{
|
||||
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
|
||||
|
||||
/* fixed 30fps */
|
||||
priv->frame_length = IMX390_DEFAULT_FRAME_LENGTH;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx390_set_exposure(struct tegracam_device *tc_dev, s64 val)
|
||||
{
|
||||
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
const struct sensor_mode_properties *mode =
|
||||
&s_data->sensor_props.sensor_modes[s_data->mode];
|
||||
imx390_reg reg_list[3];
|
||||
int err;
|
||||
u32 coarse_time;
|
||||
u32 shs1;
|
||||
int i = 0;
|
||||
|
||||
if (priv->frame_length == 0)
|
||||
priv->frame_length = IMX390_DEFAULT_FRAME_LENGTH;
|
||||
|
||||
/* coarse time in lines */
|
||||
coarse_time = (u32) (val * s_data->frmfmt[s_data->mode].framerates[0] *
|
||||
priv->frame_length / mode->control_properties.exposure_factor);
|
||||
|
||||
shs1 = priv->frame_length - coarse_time;
|
||||
/* 0 and 1 are prohibited */
|
||||
if (shs1 < 2)
|
||||
shs1 = 2;
|
||||
|
||||
imx390_get_coarse_time_regs_shs1(reg_list, shs1);
|
||||
for (i = 0; i < 3; i++) {
|
||||
err = imx390_write_reg(priv->s_data, reg_list[i].addr,
|
||||
reg_list[i].val);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
imx390_get_coarse_time_regs_shs2(reg_list, shs1);
|
||||
for (i = 0; i < 3; i++) {
|
||||
err = imx390_write_reg(priv->s_data, reg_list[i].addr,
|
||||
reg_list[i].val);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
dev_dbg(&priv->i2c_client->dev,
|
||||
"%s: set coarse time error\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct tegracam_ctrl_ops imx390_ctrl_ops = {
|
||||
.numctrls = ARRAY_SIZE(ctrl_cid_list),
|
||||
.ctrl_cid_list = ctrl_cid_list,
|
||||
.set_gain = imx390_set_gain,
|
||||
.set_exposure = imx390_set_exposure,
|
||||
.set_exposure_short = imx390_set_exposure,
|
||||
.set_frame_rate = imx390_set_frame_rate,
|
||||
.set_group_hold = imx390_set_group_hold,
|
||||
};
|
||||
|
||||
static struct camera_common_pdata
|
||||
*imx390_parse_dt(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct device *dev = tc_dev->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct camera_common_pdata *board_priv_pdata;
|
||||
const struct of_device_id *match;
|
||||
int err;
|
||||
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
match = of_match_device(imx390_of_match, dev);
|
||||
if (!match) {
|
||||
dev_err(dev, "Failed to find matching dt id\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
board_priv_pdata = devm_kzalloc(dev,
|
||||
sizeof(*board_priv_pdata), GFP_KERNEL);
|
||||
|
||||
err = of_property_read_string(node, "mclk",
|
||||
&board_priv_pdata->mclk_name);
|
||||
if (err)
|
||||
dev_err(dev, "mclk not in DT\n");
|
||||
|
||||
return board_priv_pdata;
|
||||
}
|
||||
|
||||
static int imx390_set_mode(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
struct device *dev = tc_dev->dev;
|
||||
const struct of_device_id *match;
|
||||
|
||||
match = of_match_device(imx390_of_match, dev);
|
||||
if (!match) {
|
||||
dev_err(dev, "Failed to find matching dt id\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (s_data->mode_prop_idx < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return imx390_write_table(priv, mode_table[s_data->mode_prop_idx]);
|
||||
}
|
||||
|
||||
static int imx390_start_streaming(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
|
||||
struct device *dev = tc_dev->dev;
|
||||
int err;
|
||||
|
||||
/* enable serdes streaming */
|
||||
err = max9295_setup_streaming(priv->ser_dev);
|
||||
if (err)
|
||||
goto exit;
|
||||
err = max9296_setup_streaming(priv->dser_dev, dev);
|
||||
if (err)
|
||||
goto exit;
|
||||
err = max9296_start_streaming(priv->dser_dev, dev);
|
||||
if (err)
|
||||
goto exit;
|
||||
|
||||
err = imx390_write_table(priv,
|
||||
mode_table[IMX390_MODE_START_STREAM]);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
msleep(20);
|
||||
|
||||
return 0;
|
||||
|
||||
exit:
|
||||
dev_err(dev, "%s: error setting stream\n", __func__);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int imx390_stop_streaming(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct device *dev = tc_dev->dev;
|
||||
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
|
||||
|
||||
/* disable serdes streaming */
|
||||
max9296_stop_streaming(priv->dser_dev, dev);
|
||||
|
||||
return imx390_write_table(priv, mode_table[IMX390_MODE_STOP_STREAM]);
|
||||
}
|
||||
|
||||
static struct camera_common_sensor_ops imx390_common_ops = {
|
||||
.numfrmfmts = ARRAY_SIZE(imx390_frmfmt),
|
||||
.frmfmt_table = imx390_frmfmt,
|
||||
.power_on = imx390_power_on,
|
||||
.power_off = imx390_power_off,
|
||||
.write_reg = imx390_write_reg,
|
||||
.read_reg = imx390_read_reg,
|
||||
.parse_dt = imx390_parse_dt,
|
||||
.power_get = imx390_power_get,
|
||||
.power_put = imx390_power_put,
|
||||
.set_mode = imx390_set_mode,
|
||||
.start_streaming = imx390_start_streaming,
|
||||
.stop_streaming = imx390_stop_streaming,
|
||||
};
|
||||
|
||||
static int imx390_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
dev_dbg(&client->dev, "%s:\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_internal_ops imx390_subdev_internal_ops = {
|
||||
.open = imx390_open,
|
||||
};
|
||||
|
||||
static int imx390_board_setup(struct imx390 *priv)
|
||||
{
|
||||
struct tegracam_device *tc_dev = priv->tc_dev;
|
||||
struct device *dev = tc_dev->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct device_node *ser_node;
|
||||
struct i2c_client *ser_i2c = NULL;
|
||||
struct device_node *dser_node;
|
||||
struct i2c_client *dser_i2c = NULL;
|
||||
struct device_node *gmsl;
|
||||
int value = 0xFFFF;
|
||||
const char *str_value;
|
||||
const char *str_value1[2];
|
||||
int i;
|
||||
int err;
|
||||
|
||||
err = of_property_read_u32(node, "reg", &priv->g_ctx.sdev_reg);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "reg not found\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = of_property_read_u32(node, "def-addr",
|
||||
&priv->g_ctx.sdev_def);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "def-addr not found\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ser_node = of_parse_phandle(node, "nvidia,gmsl-ser-device", 0);
|
||||
if (ser_node == NULL) {
|
||||
dev_err(dev,
|
||||
"missing %s handle\n",
|
||||
"nvidia,gmsl-ser-device");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = of_property_read_u32(ser_node, "reg", &priv->g_ctx.ser_reg);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "serializer reg not found\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ser_i2c = of_find_i2c_device_by_node(ser_node);
|
||||
of_node_put(ser_node);
|
||||
|
||||
if (ser_i2c == NULL) {
|
||||
err = -EPROBE_DEFER;
|
||||
goto error;
|
||||
}
|
||||
if (ser_i2c->dev.driver == NULL) {
|
||||
dev_err(dev, "missing serializer driver\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
priv->ser_dev = &ser_i2c->dev;
|
||||
|
||||
dser_node = of_parse_phandle(node, "nvidia,gmsl-dser-device", 0);
|
||||
if (dser_node == NULL) {
|
||||
dev_err(dev,
|
||||
"missing %s handle\n",
|
||||
"nvidia,gmsl-dser-device");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
dser_i2c = of_find_i2c_device_by_node(dser_node);
|
||||
of_node_put(dser_node);
|
||||
|
||||
if (dser_i2c == NULL) {
|
||||
err = -EPROBE_DEFER;
|
||||
goto error;
|
||||
}
|
||||
if (dser_i2c->dev.driver == NULL) {
|
||||
dev_err(dev, "missing deserializer driver\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
priv->dser_dev = &dser_i2c->dev;
|
||||
|
||||
/* populate g_ctx from DT */
|
||||
gmsl = of_get_child_by_name(node, "gmsl-link");
|
||||
if (gmsl == NULL) {
|
||||
dev_err(dev, "missing gmsl-link device node\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = of_property_read_string(gmsl, "dst-csi-port", &str_value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No dst-csi-port found\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.dst_csi_port =
|
||||
(!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : GMSL_CSI_PORT_B;
|
||||
|
||||
err = of_property_read_string(gmsl, "src-csi-port", &str_value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No src-csi-port found\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.src_csi_port =
|
||||
(!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : GMSL_CSI_PORT_B;
|
||||
|
||||
err = of_property_read_string(gmsl, "csi-mode", &str_value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No csi-mode found\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!strcmp(str_value, "1x4")) {
|
||||
priv->g_ctx.csi_mode = GMSL_CSI_1X4_MODE;
|
||||
} else if (!strcmp(str_value, "2x4")) {
|
||||
priv->g_ctx.csi_mode = GMSL_CSI_2X4_MODE;
|
||||
} else if (!strcmp(str_value, "4x2")) {
|
||||
priv->g_ctx.csi_mode = GMSL_CSI_4X2_MODE;
|
||||
} else if (!strcmp(str_value, "2x2")) {
|
||||
priv->g_ctx.csi_mode = GMSL_CSI_2X2_MODE;
|
||||
} else {
|
||||
dev_err(dev, "invalid csi mode\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = of_property_read_string(gmsl, "serdes-csi-link", &str_value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No serdes-csi-link found\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.serdes_csi_link =
|
||||
(!strcmp(str_value, "a")) ?
|
||||
GMSL_SERDES_CSI_LINK_A : GMSL_SERDES_CSI_LINK_B;
|
||||
|
||||
err = of_property_read_u32(gmsl, "st-vc", &value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No st-vc info\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.st_vc = value;
|
||||
|
||||
err = of_property_read_u32(gmsl, "vc-id", &value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No vc-id info\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.dst_vc = value;
|
||||
|
||||
err = of_property_read_u32(gmsl, "num-lanes", &value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No num-lanes info\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.num_csi_lanes = value;
|
||||
|
||||
priv->g_ctx.num_streams =
|
||||
of_property_count_strings(gmsl, "streams");
|
||||
if (priv->g_ctx.num_streams <= 0) {
|
||||
dev_err(dev, "No streams found\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < priv->g_ctx.num_streams; i++) {
|
||||
err = of_property_read_string_index(gmsl, "streams", i,
|
||||
&str_value1[i]);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Failed to get streams index\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!str_value1[i]) {
|
||||
dev_err(dev, "invalid stream info\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
if (!strcmp(str_value1[i], "raw12")) {
|
||||
priv->g_ctx.streams[i].st_data_type =
|
||||
GMSL_CSI_DT_RAW_12;
|
||||
} else if (!strcmp(str_value1[i], "embed")) {
|
||||
priv->g_ctx.streams[i].st_data_type =
|
||||
GMSL_CSI_DT_EMBED;
|
||||
} else if (!strcmp(str_value1[i], "ued-u1")) {
|
||||
priv->g_ctx.streams[i].st_data_type =
|
||||
GMSL_CSI_DT_UED_U1;
|
||||
} else {
|
||||
dev_err(dev, "invalid stream data type\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
priv->g_ctx.s_dev = dev;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int imx390_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int imx390_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
#endif
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct tegracam_device *tc_dev;
|
||||
struct imx390 *priv;
|
||||
int err;
|
||||
|
||||
dev_info(dev, "probing v4l2 sensor.\n");
|
||||
|
||||
if (!IS_ENABLED(CONFIG_OF) || !node)
|
||||
return -EINVAL;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(struct imx390), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
tc_dev = devm_kzalloc(dev,
|
||||
sizeof(struct tegracam_device), GFP_KERNEL);
|
||||
if (!tc_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->i2c_client = tc_dev->client = client;
|
||||
tc_dev->dev = dev;
|
||||
strscpy(tc_dev->name, "imx390", sizeof(tc_dev->name));
|
||||
tc_dev->dev_regmap_config = &sensor_regmap_config;
|
||||
tc_dev->sensor_ops = &imx390_common_ops;
|
||||
tc_dev->v4l2sd_internal_ops = &imx390_subdev_internal_ops;
|
||||
tc_dev->tcctrl_ops = &imx390_ctrl_ops;
|
||||
|
||||
err = tegracam_device_register(tc_dev);
|
||||
if (err) {
|
||||
dev_err(dev, "tegra camera driver registration failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
priv->tc_dev = tc_dev;
|
||||
priv->s_data = tc_dev->s_data;
|
||||
priv->subdev = &tc_dev->s_data->subdev;
|
||||
|
||||
tegracam_set_privdata(tc_dev, (void *)priv);
|
||||
|
||||
err = imx390_board_setup(priv);
|
||||
if (err) {
|
||||
tegracam_device_unregister(tc_dev);
|
||||
dev_err(dev, "board setup failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
mutex_init(&serdes_lock__);
|
||||
|
||||
/* Pair sensor to serializer dev */
|
||||
err = max9295_sdev_pair(priv->ser_dev, &priv->g_ctx);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "gmsl ser pairing failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Register sensor to deserializer dev */
|
||||
err = max9296_sdev_register(priv->dser_dev, &priv->g_ctx);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "gmsl deserializer register failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* gmsl serdes setup
|
||||
*
|
||||
* Sensor power on/off should be the right place for serdes
|
||||
* setup/reset. But the problem is, the total required delay
|
||||
* in serdes setup/reset exceeds the frame wait timeout, looks to
|
||||
* be related to multiple channel open and close sequence
|
||||
* issue (#BUG 200477330).
|
||||
* Once this bug is fixed, these may be moved to power on/off.
|
||||
* The delays in serdes is as per guidelines and can't be reduced,
|
||||
* so it is placed in probe/remove, though for that, deserializer
|
||||
* would be powered on always post boot, until 1.2v is supplied
|
||||
* to deserializer from CVB.
|
||||
*/
|
||||
err = imx390_gmsl_serdes_setup(priv);
|
||||
if (err) {
|
||||
dev_err(&client->dev,
|
||||
"%s gmsl serdes setup failed\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = tegracam_v4l2subdev_register(tc_dev, true);
|
||||
if (err) {
|
||||
dev_err(dev, "tegra camera subdev registration failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "Detected IMX390 sensor\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int imx390_remove(struct i2c_client *client)
|
||||
#else
|
||||
static void imx390_remove(struct i2c_client *client)
|
||||
#endif
|
||||
{
|
||||
struct camera_common_data *s_data = to_camera_common_data(&client->dev);
|
||||
struct imx390 *priv;
|
||||
|
||||
if (!s_data)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return -EINVAL;
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
|
||||
priv = (struct imx390 *)s_data->priv;
|
||||
|
||||
imx390_gmsl_serdes_reset(priv);
|
||||
|
||||
mutex_destroy(&serdes_lock__);
|
||||
tegracam_v4l2subdev_unregister(priv->tc_dev);
|
||||
tegracam_device_unregister(priv->tc_dev);
|
||||
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const struct i2c_device_id imx390_id[] = {
|
||||
{ "imx390", 0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, imx390_id);
|
||||
|
||||
static struct i2c_driver imx390_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "imx390",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(imx390_of_match),
|
||||
},
|
||||
.probe = imx390_probe,
|
||||
.remove = imx390_remove,
|
||||
.id_table = imx390_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(imx390_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Media Controller driver for Sony IMX390");
|
||||
MODULE_AUTHOR("NVIDIA Corporation");
|
||||
MODULE_AUTHOR("Sudhir Vyas <svyas@nvidia.com");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -775,6 +775,7 @@ static int imx477_probe(struct i2c_client *client,
|
||||
|
||||
err = tegracam_v4l2subdev_register(tc_dev, true);
|
||||
if (err) {
|
||||
tegracam_device_unregister(tc_dev);
|
||||
dev_err(dev, "tegra camera subdev registration failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. */
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* virtual_i2c_mux.c - virtual i2c mux driver for P3762 & P3783 GMSL boards.
|
||||
*/
|
||||
@@ -87,7 +87,11 @@ static int virtual_i2c_mux_probe(struct i2c_client *client,
|
||||
|
||||
for (chan = 0; chan < children; chan++) {
|
||||
pr_info("%s: chan = %d\n",__func__, chan);
|
||||
#if defined(NV_I2C_MUX_ADD_ADAPTER_HAS_NO_CLASS_ARG)
|
||||
ret = i2c_mux_add_adapter(muxc, 0, chan);
|
||||
#else
|
||||
ret = i2c_mux_add_adapter(muxc, 0, chan, 0);
|
||||
#endif
|
||||
if (ret)
|
||||
goto err_children;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* camera_common.c - utilities for tegra camera driver
|
||||
// SPDX-License-Identifier: GPL-2.0 only
|
||||
/* SPDX-FileCopyrightText: Copyright (c) 2015-2024 NVIDIA CORPORATION & AFFILIATES.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Copyright (c) 2015-2023, NVIDIA CORPORATION. All rights reserved.
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <linux/types.h>
|
||||
#include <media/tegra-v4l2-camera.h>
|
||||
@@ -44,6 +54,11 @@ static const struct camera_common_colorfmt camera_common_color_fmts[] = {
|
||||
V4L2_COLORSPACE_SRGB,
|
||||
V4L2_PIX_FMT_SGBRG12
|
||||
},
|
||||
{
|
||||
MEDIA_BUS_FMT_SBGGR12_1X12,
|
||||
V4L2_COLORSPACE_SRGB,
|
||||
V4L2_PIX_FMT_SBGGR12
|
||||
},
|
||||
{
|
||||
MEDIA_BUS_FMT_SRGGB10_1X10,
|
||||
V4L2_COLORSPACE_SRGB,
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2015-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* NVIDIA Tegra CSI Device
|
||||
*
|
||||
* Copyright (c) 2015-2024, NVIDIA CORPORATION. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
@@ -687,7 +686,7 @@ static int tegra_csi_set_format(struct v4l2_subdev *subdev,
|
||||
}
|
||||
|
||||
static int tegra_csi_g_frame_interval(struct v4l2_subdev *sd,
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_FRAME_INTERVAL)
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_SET_FRAME_INTERVAL)
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
#endif
|
||||
struct v4l2_subdev_frame_interval *vfi)
|
||||
@@ -721,13 +720,13 @@ static int tegra_csi_enum_mbus_code(struct v4l2_subdev *sd,
|
||||
static struct v4l2_subdev_video_ops tegra_csi_video_ops = {
|
||||
.s_stream = tegra_csi_s_stream,
|
||||
.g_input_status = tegra_csi_g_input_status,
|
||||
#if !defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_FRAME_INTERVAL)
|
||||
#if !defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_SET_FRAME_INTERVAL)
|
||||
.g_frame_interval = tegra_csi_g_frame_interval,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_pad_ops tegra_csi_pad_ops = {
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_FRAME_INTERVAL)
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_SET_FRAME_INTERVAL)
|
||||
.get_frame_interval = tegra_csi_g_frame_interval,
|
||||
#endif
|
||||
.get_fmt = tegra_csi_get_format,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2017-2023 NVIDIA Corporation. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
/**
|
||||
* @file drivers/media/platform/tegra/camera/fusa-capture/capture-isp.c
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <linux/nvhost.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/tegra-capture-ivc.h>
|
||||
#include <asm/arch_timer.h>
|
||||
#include <soc/tegra/fuse.h>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/nvhost.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/* SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file drivers/media/platform/tegra/camera/fusa-capture/capture-vi.c
|
||||
@@ -12,7 +24,7 @@
|
||||
#include <linux/nvhost.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/tegra-capture-ivc.h>
|
||||
#include <linux/tegra-camera-rtcpu.h>
|
||||
|
||||
@@ -1438,7 +1450,12 @@ int vi_capture_status(
|
||||
|
||||
/* negative timeout means wait forever */
|
||||
if (timeout_ms < 0) {
|
||||
wait_for_completion(&capture->capture_resp);
|
||||
ret = wait_for_completion_interruptible(&capture->capture_resp);
|
||||
if (ret == -ERESTARTSYS) {
|
||||
dev_dbg(chan->dev,
|
||||
"capture status interrupted\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
} else {
|
||||
ret = wait_for_completion_timeout(
|
||||
&capture->capture_resp,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2016-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* Copyright (c) 2016-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*
|
||||
* Tegra CSI5 device common APIs
|
||||
*/
|
||||
@@ -213,6 +213,7 @@ static int csi5_stream_set_config(struct tegra_csi_channel *chan, u32 stream_id,
|
||||
struct CAPTURE_CONTROL_MSG msg;
|
||||
struct nvcsi_brick_config brick_config;
|
||||
struct nvcsi_cil_config cil_config;
|
||||
struct nvcsi_error_config err_config;
|
||||
u32 phy_mode = read_phy_mode_from_dt(chan);
|
||||
bool is_cphy = (phy_mode == CSI_PHY_MODE_CPHY);
|
||||
dev_dbg(csi->dev, "%s: stream_id=%u, csi_port=%u\n",
|
||||
@@ -285,6 +286,7 @@ static int csi5_stream_set_config(struct tegra_csi_channel *chan, u32 stream_id,
|
||||
else
|
||||
cil_config.mipi_clock_rate = csi->clk_freq / 1000;
|
||||
|
||||
memset(&err_config, 0, sizeof(err_config));
|
||||
/* Set NVCSI stream config */
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.header.msg_id = CAPTURE_CSI_STREAM_SET_CONFIG_REQ;
|
||||
@@ -293,6 +295,9 @@ static int csi5_stream_set_config(struct tegra_csi_channel *chan, u32 stream_id,
|
||||
msg.csi_stream_set_config_req.csi_port = csi_port;
|
||||
msg.csi_stream_set_config_req.brick_config = brick_config;
|
||||
msg.csi_stream_set_config_req.cil_config = cil_config;
|
||||
msg.csi_stream_set_config_req.error_config = err_config;
|
||||
msg.csi_stream_set_config_req.config_flags = NVCSI_CONFIG_FLAG_BRICK |
|
||||
NVCSI_CONFIG_FLAG_CIL | NVCSI_CONFIG_FLAG_ERROR;
|
||||
|
||||
if (tegra_chan->valid_ports > 1)
|
||||
vi_port = (stream_id > 0) ? 1 : 0;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2018-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* tegracam_v4l2 - tegra camera framework for v4l2 support
|
||||
*
|
||||
* Copyright (c) 2018-2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <media/tegra-v4l2-camera.h>
|
||||
#include <media/tegracam_core.h>
|
||||
@@ -112,9 +114,30 @@ static int v4l2sd_g_input_status(struct v4l2_subdev *sd, u32 *status)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cam_g_frame_interval(struct v4l2_subdev *sd,
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_SET_FRAME_INTERVAL)
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
#endif
|
||||
struct v4l2_subdev_frame_interval *ival)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
struct camera_common_data *s_data = to_camera_common_data(&client->dev);
|
||||
|
||||
if (!s_data)
|
||||
return -EINVAL;
|
||||
|
||||
ival->interval.denominator = s_data->frmfmt[s_data->mode_prop_idx].framerates[0];
|
||||
ival->interval.numerator = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct v4l2_subdev_video_ops v4l2sd_video_ops = {
|
||||
.s_stream = v4l2sd_stream,
|
||||
.g_input_status = v4l2sd_g_input_status,
|
||||
#if !defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_SET_FRAME_INTERVAL)
|
||||
.g_frame_interval = cam_g_frame_interval,
|
||||
.s_frame_interval = cam_g_frame_interval,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_core_ops v4l2sd_core_ops = {
|
||||
@@ -161,6 +184,10 @@ static int v4l2sd_set_fmt(struct v4l2_subdev *sd,
|
||||
}
|
||||
|
||||
static struct v4l2_subdev_pad_ops v4l2sd_pad_ops = {
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_SET_FRAME_INTERVAL)
|
||||
.get_frame_interval = cam_g_frame_interval,
|
||||
.set_frame_interval = cam_g_frame_interval,
|
||||
#endif
|
||||
.set_fmt = v4l2sd_set_fmt,
|
||||
.get_fmt = v4l2sd_get_fmt,
|
||||
.enum_mbus_code = camera_common_enum_mbus_code,
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* NVIDIA Tegra Video Input Device
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/clk.h>
|
||||
@@ -23,6 +25,7 @@
|
||||
#include <media/v4l2-dev.h>
|
||||
#include <media/v4l2-fh.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
#include <media/videobuf2-core.h>
|
||||
#include <media/videobuf2-dma-contig.h>
|
||||
#include <media/tegra-v4l2-camera.h>
|
||||
@@ -689,16 +692,33 @@ tegra_channel_queue_setup(struct vb2_queue *vq,
|
||||
{
|
||||
struct tegra_channel *chan = vb2_get_drv_priv(vq);
|
||||
struct tegra_mc_vi *vi = chan->vi;
|
||||
int ret = 0;
|
||||
|
||||
|
||||
/* In some cases, if nplanes is valid
|
||||
* and the requested image size is less than the
|
||||
* actual image size, we need to return EINVAL.
|
||||
* Previously, we were just updating sizes[0] irrespective
|
||||
* of the requested image size. Although this did not harm the
|
||||
* flow, according to "v4l2-compliance", we need to check if
|
||||
* the requested size is invalid.
|
||||
*/
|
||||
if (*nplanes) {
|
||||
if (sizes[0] < chan->format.sizeimage) {
|
||||
pr_err("%s: sizes[0] = %d chan->format.sizeimage = %d ...\n"
|
||||
,__func__,sizes[0],chan->format.sizeimage);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
sizes[0] = chan->format.sizeimage;
|
||||
}
|
||||
|
||||
*nplanes = 1;
|
||||
|
||||
sizes[0] = chan->format.sizeimage;
|
||||
alloc_devs[0] = tegra_channel_get_vi_unit(chan);
|
||||
|
||||
if (vi->fops && vi->fops->vi_setup_queue)
|
||||
return vi->fops->vi_setup_queue(chan, nbuffers);
|
||||
else
|
||||
return -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tegra_channel_alloc_buffer_queue(struct tegra_channel *chan,
|
||||
@@ -1157,11 +1177,19 @@ tegra_channel_g_dv_timings(struct file *file, void *fh,
|
||||
{
|
||||
struct tegra_channel *chan = video_drvdata(file);
|
||||
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_DV_TIMINGS) /* Linux v6.10 */
|
||||
if (!v4l2_subdev_has_op(chan->subdev_on_csi, pad, g_dv_timings))
|
||||
return -ENOTTY;
|
||||
|
||||
return v4l2_device_call_until_err(chan->video->v4l2_dev,
|
||||
chan->grp_id, pad, g_dv_timings, 0, timings);
|
||||
#else
|
||||
if (!v4l2_subdev_has_op(chan->subdev_on_csi, video, g_dv_timings))
|
||||
return -ENOTTY;
|
||||
|
||||
return v4l2_device_call_until_err(chan->video->v4l2_dev,
|
||||
chan->grp_id, video, g_dv_timings, timings);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1173,7 +1201,11 @@ tegra_channel_s_dv_timings(struct file *file, void *fh,
|
||||
struct v4l2_dv_timings curr_timings;
|
||||
int ret;
|
||||
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_DV_TIMINGS) /* Linux v6.10 */
|
||||
if (!v4l2_subdev_has_op(chan->subdev_on_csi, pad, s_dv_timings))
|
||||
#else
|
||||
if (!v4l2_subdev_has_op(chan->subdev_on_csi, video, s_dv_timings))
|
||||
#endif
|
||||
return -ENOTTY;
|
||||
|
||||
ret = tegra_channel_g_dv_timings(file, fh, &curr_timings);
|
||||
@@ -1186,9 +1218,13 @@ tegra_channel_s_dv_timings(struct file *file, void *fh,
|
||||
if (vb2_is_busy(&chan->queue))
|
||||
return -EBUSY;
|
||||
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_DV_TIMINGS) /* Linux v6.10 */
|
||||
ret = v4l2_device_call_until_err(chan->video->v4l2_dev,
|
||||
chan->grp_id, pad, s_dv_timings, 0, timings);
|
||||
#else
|
||||
ret = v4l2_device_call_until_err(chan->video->v4l2_dev,
|
||||
chan->grp_id, video, s_dv_timings, timings);
|
||||
|
||||
#endif
|
||||
if (!ret)
|
||||
tegra_channel_update_format(chan, bt->width, bt->height,
|
||||
chan->fmtinfo->fourcc, &chan->fmtinfo->bpp,
|
||||
@@ -1206,11 +1242,19 @@ tegra_channel_query_dv_timings(struct file *file, void *fh,
|
||||
{
|
||||
struct tegra_channel *chan = video_drvdata(file);
|
||||
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_DV_TIMINGS) /* Linux v6.10 */
|
||||
if (!v4l2_subdev_has_op(chan->subdev_on_csi, pad, query_dv_timings))
|
||||
return -ENOTTY;
|
||||
|
||||
return v4l2_device_call_until_err(chan->video->v4l2_dev,
|
||||
chan->grp_id, pad, query_dv_timings, 0, timings);
|
||||
#else
|
||||
if (!v4l2_subdev_has_op(chan->subdev_on_csi, video, query_dv_timings))
|
||||
return -ENOTTY;
|
||||
|
||||
return v4l2_device_call_until_err(chan->video->v4l2_dev,
|
||||
chan->grp_id, video, query_dv_timings, timings);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1257,6 +1301,10 @@ int tegra_channel_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
}
|
||||
break;
|
||||
case TEGRA_CAMERA_CID_VI_BYPASS_MODE:
|
||||
/* Prevent changing the bypass mode while the device is still streaming */
|
||||
if (vb2_is_busy(&chan->queue))
|
||||
return -EBUSY;
|
||||
|
||||
if (switch_ctrl_qmenu[ctrl->val] == SWITCH_ON)
|
||||
chan->bypass = true;
|
||||
else if (chan->vi->bypass) {
|
||||
@@ -1843,8 +1891,13 @@ static void tegra_channel_populate_dev_info(struct tegra_camera_dev_info *cdev,
|
||||
if (chan->pg_mode) {
|
||||
/* TPG mode */
|
||||
cdev->sensor_type = SENSORTYPE_VIRTUAL;
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_DV_TIMINGS) /* Linux v6.10 */
|
||||
} else if (v4l2_subdev_has_op(chan->subdev_on_csi,
|
||||
pad, g_dv_timings)) {
|
||||
#else
|
||||
} else if (v4l2_subdev_has_op(chan->subdev_on_csi,
|
||||
video, g_dv_timings)) {
|
||||
#endif
|
||||
/* HDMI-IN */
|
||||
cdev->sensor_type = SENSORTYPE_OTHER;
|
||||
pixelclock = tegra_channel_get_max_source_rate();
|
||||
@@ -2171,7 +2224,11 @@ tegra_channel_enum_input(struct file *file, void *fh, struct v4l2_input *inp)
|
||||
return -ENODEV;
|
||||
|
||||
inp->type = V4L2_INPUT_TYPE_CAMERA;
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_DV_TIMINGS) /* Linux v6.10 */
|
||||
if (v4l2_subdev_has_op(sd_on_csi, pad, s_dv_timings)) {
|
||||
#else
|
||||
if (v4l2_subdev_has_op(sd_on_csi, video, s_dv_timings)) {
|
||||
#endif
|
||||
inp->capabilities = V4L2_IN_CAP_DV_TIMINGS;
|
||||
len = snprintf(inp->name,
|
||||
sizeof(inp->name), "HDMI %u",
|
||||
@@ -2216,7 +2273,7 @@ static long tegra_channel_default_ioctl(struct file *file, void *fh,
|
||||
{
|
||||
struct tegra_channel *chan = video_drvdata(file);
|
||||
struct tegra_mc_vi *vi = chan->vi;
|
||||
long ret = 0;
|
||||
long ret = -ENOTTY;
|
||||
|
||||
if (vi->fops && vi->fops->vi_default_ioctl)
|
||||
ret = vi->fops->vi_default_ioctl(file, fh, use_prio, cmd, arg);
|
||||
@@ -2224,10 +2281,32 @@ static long tegra_channel_default_ioctl(struct file *file, void *fh,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Implemented vidioc_s_parm and vidioc_g_parm ioctl to support multiple frame
|
||||
* rates */
|
||||
static int tegra_channel_s_parm(struct file *file, void *fh,
|
||||
struct v4l2_streamparm *a)
|
||||
{
|
||||
struct tegra_channel *chan = video_drvdata(file);
|
||||
struct v4l2_subdev *sd = chan->subdev_on_csi;
|
||||
|
||||
return v4l2_s_parm_cap(chan->video, sd, a);
|
||||
}
|
||||
|
||||
static int tegra_channel_g_parm(struct file *file, void *fh,
|
||||
struct v4l2_streamparm *a)
|
||||
{
|
||||
struct tegra_channel *chan = video_drvdata(file);
|
||||
struct v4l2_subdev *sd = chan->subdev_on_csi;
|
||||
|
||||
return v4l2_g_parm_cap(chan->video, sd, a);
|
||||
}
|
||||
|
||||
static const struct v4l2_ioctl_ops tegra_channel_ioctl_ops = {
|
||||
.vidioc_querycap = tegra_channel_querycap,
|
||||
.vidioc_enum_framesizes = tegra_channel_enum_framesizes,
|
||||
.vidioc_enum_frameintervals = tegra_channel_enum_frameintervals,
|
||||
.vidioc_s_parm = tegra_channel_s_parm,
|
||||
.vidioc_g_parm = tegra_channel_g_parm,
|
||||
.vidioc_enum_fmt_vid_cap = tegra_channel_enum_format,
|
||||
.vidioc_g_fmt_vid_cap = tegra_channel_get_format,
|
||||
.vidioc_s_fmt_vid_cap = tegra_channel_set_format,
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
/* SPDX-FileCopyrightText: Copyright (c) 2016-2024 NVIDIA CORPORATION & AFFILIATES.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Tegra Video Input 5 device common APIs
|
||||
*
|
||||
* Copyright (c) 2016-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* Author: Frank Chen <frank@nvidia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
@@ -134,6 +140,9 @@ static int tegra_vi5_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
case TEGRA_CAMERA_CID_WRITE_ISPFORMAT:
|
||||
chan->write_ispformat = ctrl->val;
|
||||
break;
|
||||
case TEGRA_CAMERA_CID_VI_CAPTURE_TIMEOUT:
|
||||
chan->capture_timeout_ms = ctrl->val;
|
||||
break;
|
||||
default:
|
||||
dev_err(&chan->video->dev, "%s:Not valid ctrl\n", __func__);
|
||||
return -EINVAL;
|
||||
@@ -200,6 +209,16 @@ static const struct v4l2_ctrl_config vi5_custom_ctrls[] = {
|
||||
.step = 1,
|
||||
.dims = { SENSOR_CTRL_BLOB_SIZE },
|
||||
},
|
||||
{
|
||||
.ops = &vi5_ctrl_ops,
|
||||
.id = TEGRA_CAMERA_CID_VI_CAPTURE_TIMEOUT,
|
||||
.name = "Override capture timeout ms",
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.def = CAPTURE_TIMEOUT_MS,
|
||||
.min = -1,
|
||||
.max = 0x7FFFFFFF,
|
||||
.step = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static int vi5_add_ctrls(struct tegra_channel *chan)
|
||||
@@ -497,6 +516,7 @@ static void vi5_capture_dequeue(struct tegra_channel *chan,
|
||||
unsigned long flags;
|
||||
struct tegra_mc_vi *vi = chan->vi;
|
||||
struct vb2_v4l2_buffer *vb = &buf->buf;
|
||||
int timeout_ms = CAPTURE_TIMEOUT_MS;
|
||||
struct timespec64 ts;
|
||||
struct capture_descriptor *descr = NULL;
|
||||
|
||||
@@ -507,12 +527,21 @@ static void vi5_capture_dequeue(struct tegra_channel *chan,
|
||||
goto rel_buf;
|
||||
|
||||
/* Dequeue a frame and check its capture status */
|
||||
err = vi_capture_status(chan->tegra_vi_channel[vi_port], CAPTURE_TIMEOUT_MS);
|
||||
timeout_ms = chan->capture_timeout_ms;
|
||||
err = vi_capture_status(chan->tegra_vi_channel[vi_port], timeout_ms);
|
||||
if (err) {
|
||||
if (err == -ETIMEDOUT) {
|
||||
dev_err(vi->dev,
|
||||
"uncorr_err: request timed out after %d ms\n",
|
||||
CAPTURE_TIMEOUT_MS);
|
||||
if (timeout_ms < 0) {
|
||||
spin_lock_irqsave(&chan->capture_state_lock, flags);
|
||||
chan->capture_state = CAPTURE_ERROR_TIMEOUT;
|
||||
spin_unlock_irqrestore(&chan->capture_state_lock, flags);
|
||||
buf->vb2_state = VB2_BUF_STATE_ERROR;
|
||||
goto rel_buf;
|
||||
} else {
|
||||
dev_err(vi->dev,
|
||||
"uncorr_err: request timed out after %d ms\n",
|
||||
timeout_ms);
|
||||
}
|
||||
} else {
|
||||
dev_err(vi->dev, "uncorr_err: request err %d\n", err);
|
||||
}
|
||||
@@ -702,6 +731,7 @@ static int tegra_channel_kthread_capture_dequeue(void *data)
|
||||
struct tegra_channel_buffer *buf;
|
||||
|
||||
set_freezable();
|
||||
allow_signal(SIGINT);
|
||||
|
||||
while (1) {
|
||||
try_to_freeze();
|
||||
@@ -722,6 +752,12 @@ static int tegra_channel_kthread_capture_dequeue(void *data)
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&chan->capture_state_lock, flags);
|
||||
if (chan->capture_state == CAPTURE_ERROR_TIMEOUT) {
|
||||
spin_unlock_irqrestore(&chan->capture_state_lock,
|
||||
flags);
|
||||
break;
|
||||
}
|
||||
|
||||
if (chan->capture_state == CAPTURE_ERROR) {
|
||||
spin_unlock_irqrestore(&chan->capture_state_lock,
|
||||
flags);
|
||||
@@ -791,6 +827,7 @@ static void vi5_channel_stop_kthreads(struct tegra_channel *chan)
|
||||
|
||||
/* Stop the kthread for capture dequeue */
|
||||
if (chan->kthread_capture_dequeue) {
|
||||
send_sig(SIGINT, chan->kthread_capture_dequeue, 1);
|
||||
kthread_stop(chan->kthread_capture_dequeue);
|
||||
chan->kthread_capture_dequeue = NULL;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. */
|
||||
/* Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. */
|
||||
/*
|
||||
* cam_cdi_tsc.c - tsc driver.
|
||||
*/
|
||||
@@ -147,6 +147,8 @@ struct tsc_signal_controller {
|
||||
} debugfs;
|
||||
const struct tsc_signal_controller_features *features;
|
||||
struct list_head generators;
|
||||
bool opened;
|
||||
|
||||
};
|
||||
|
||||
static const struct tsc_signal_controller_features tegra234_tsc_features = {
|
||||
@@ -458,22 +460,44 @@ static void cdi_tsc_debugfs_remove(struct tsc_signal_controller *controller)
|
||||
|
||||
static int cdi_tsc_chardev_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
pr_info("%s:Device opened\n", __func__);
|
||||
struct tsc_signal_controller *controller = dev_get_drvdata(tsc_charDevice);
|
||||
int err = 0;
|
||||
|
||||
/* Set External Fsync */
|
||||
Hawk_Owl_Fsync_program(EXTERNAL_FSYNC);
|
||||
if (controller->opened)
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
/* Make sure device opened only once */
|
||||
controller->opened = true;
|
||||
|
||||
/* Set External Fsync */
|
||||
err = Hawk_Owl_Fsync_program(EXTERNAL_FSYNC);
|
||||
if (err)
|
||||
controller->opened = false;
|
||||
else
|
||||
dev_dbg(controller->dev, "%s:Device opened successfully!! \n", __func__);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int cdi_tsc_chardev_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
pr_info("%s:Device closed\n", __func__);
|
||||
struct tsc_signal_controller *controller = dev_get_drvdata(tsc_charDevice);
|
||||
int err = -EFAULT;
|
||||
|
||||
/* To make sure whenever the device is closed, tsc is also stopped
|
||||
* to avoid inconsistency behaviour at app level i.e to avoid out of sync.
|
||||
*/
|
||||
err = cdi_tsc_stop_generators(controller);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Set back to Internal Fsync */
|
||||
Hawk_Owl_Fsync_program(INTERNAL_FSYNC);
|
||||
err = Hawk_Owl_Fsync_program(INTERNAL_FSYNC);
|
||||
|
||||
return 0;
|
||||
controller->opened = false;
|
||||
dev_dbg(controller->dev, "%s Device closed ..\n", __func__);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static long cdi_tsc_chardev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
@@ -520,6 +544,7 @@ static int cdi_tsc_probe(struct platform_device *pdev)
|
||||
if (!controller)
|
||||
return -ENOMEM;
|
||||
|
||||
controller->opened = false;
|
||||
controller->dev = &pdev->dev;
|
||||
controller->features = of_device_get_match_data(&pdev->dev);
|
||||
if (controller->features == NULL) {
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2016-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* SPDX-FileCopyrightText: Copyright (c) 2016-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
|
||||
|
||||
#ifndef __CDI_PWM_PRIV_H__
|
||||
#define __CDI_PWM_PRIV_H__
|
||||
|
||||
struct cdi_pwm_info {
|
||||
#if !defined(NV_PWM_CHIP_STRUCT_HAS_STRUCT_DEVICE)
|
||||
struct pwm_chip chip;
|
||||
#endif
|
||||
struct pwm_device *pwm;
|
||||
atomic_t in_use;
|
||||
struct mutex mutex;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2017-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
@@ -33,7 +33,11 @@ static int of_cdi_gpio_pdata(struct platform_device *pdev,
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined(NV_GPIO_DEVICE_FIND_HAS_CONST_DATA_ARG) /* Linux v6.9 */
|
||||
static int cdi_gpio_chip_match(struct gpio_chip *chip, const void *data)
|
||||
#else
|
||||
static int cdi_gpio_chip_match(struct gpio_chip *chip, void *data)
|
||||
#endif
|
||||
{
|
||||
return !strcmp(chip->label, data);
|
||||
}
|
||||
@@ -42,7 +46,8 @@ static struct gpio_chip *cdi_gpio_get_chip(struct platform_device *pdev,
|
||||
struct cdi_gpio_plat_data *pd)
|
||||
{
|
||||
struct gpio_chip *gc = NULL;
|
||||
#if !defined(NV_GPIOCHIP_FIND_PRESENT) /* Linux 6.7 */
|
||||
#if defined(NV_GPIO_DEVICE_FIND_PRESENT) && \
|
||||
defined(NV_GPIO_DEVICE_GET_CHIP_PRESENT) /* Linux 6.7 */
|
||||
struct gpio_device *gdev;
|
||||
#endif
|
||||
char name[MAX_STR_SIZE];
|
||||
@@ -54,14 +59,15 @@ static struct gpio_chip *cdi_gpio_get_chip(struct platform_device *pdev,
|
||||
}
|
||||
strcpy(name, pd->gpio_prnt_chip);
|
||||
|
||||
#if defined(NV_GPIOCHIP_FIND_PRESENT) /* Linux 6.7 */
|
||||
gc = gpiochip_find(name, cdi_gpio_chip_match);
|
||||
#else
|
||||
#if defined(NV_GPIO_DEVICE_FIND_PRESENT) && \
|
||||
defined(NV_GPIO_DEVICE_GET_CHIP_PRESENT) /* Linux 6.7 */
|
||||
gdev = gpio_device_find(name, cdi_gpio_chip_match);
|
||||
if (gdev) {
|
||||
gc = gpio_device_get_chip(gdev);
|
||||
gpio_device_put(gdev);
|
||||
}
|
||||
#else
|
||||
gc = gpiochip_find(name, cdi_gpio_chip_match);
|
||||
#endif
|
||||
if (!gc) {
|
||||
dev_err(&pdev->dev, "%s: unable to find gpio parent chip %s\n",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2016-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2016-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
@@ -30,7 +30,11 @@ static const struct of_device_id cdi_pwm_of_match[] = {
|
||||
|
||||
static inline struct cdi_pwm_info *to_cdi_pwm_info(struct pwm_chip *chip)
|
||||
{
|
||||
#if defined(NV_PWM_CHIP_STRUCT_HAS_STRUCT_DEVICE)
|
||||
return pwmchip_get_drvdata(chip);
|
||||
#else
|
||||
return container_of(chip, struct cdi_pwm_info, chip);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if KERNEL_VERSION(6, 0, 0) > LINUX_VERSION_CODE
|
||||
@@ -95,30 +99,38 @@ static struct pwm_device *of_cdi_pwm_xlate(struct pwm_chip *pc,
|
||||
{
|
||||
struct pwm_device *pwm;
|
||||
struct cdi_pwm_info *info = to_cdi_pwm_info(pc);
|
||||
#if defined(NV_PWM_CHIP_STRUCT_HAS_STRUCT_DEVICE)
|
||||
struct device *dev = &pc->dev;
|
||||
#else
|
||||
struct device *dev = pc->dev;
|
||||
#endif
|
||||
int err = 0;
|
||||
|
||||
pwm = pwm_request_from_chip(pc, args->args[0], NULL);
|
||||
if (!args->args[1]) {
|
||||
dev_err(pc->dev, "Period should be larger than 0\n");
|
||||
pwm = of_pwm_xlate_with_flags(pc, args);
|
||||
if (IS_ERR(pwm))
|
||||
return NULL;
|
||||
|
||||
if (!pwm->args.period) {
|
||||
dev_err(dev, "Period should be larger than 0\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (info->force_on) {
|
||||
err = pwm_config(info->pwm, args->args[1]/4, args->args[1]);
|
||||
if (err) {
|
||||
dev_err(pc->dev, "can't config PWM: %d\n", err);
|
||||
dev_err(dev, "can't config PWM: %d\n", err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = pwm_enable(info->pwm);
|
||||
if (err) {
|
||||
dev_err(pc->dev, "can't enable PWM: %d\n", err);
|
||||
dev_err(dev, "can't enable PWM: %d\n", err);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
err = pwm_config(pwm, args->args[1]/4, args->args[1]);
|
||||
if (err) {
|
||||
dev_err(pc->dev, "can't config PWM: %d\n", err);
|
||||
dev_err(dev, "can't config PWM: %d\n", err);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -140,50 +152,60 @@ static const struct pwm_ops cdi_pwm_ops = {
|
||||
static int cdi_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct cdi_pwm_info *info = NULL;
|
||||
struct pwm_chip *chip;
|
||||
int err = 0, npwm;
|
||||
bool force_on = false;
|
||||
|
||||
dev_info(&pdev->dev, "%sing...\n", __func__);
|
||||
|
||||
info = devm_kzalloc(
|
||||
&pdev->dev, sizeof(struct cdi_pwm_info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
atomic_set(&info->in_use, 0);
|
||||
mutex_init(&info->mutex);
|
||||
|
||||
err = of_property_read_u32(pdev->dev.of_node, "npwm", &npwm);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "npwm is not defined: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined(NV_PWM_CHIP_STRUCT_HAS_STRUCT_DEVICE)
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, npwm, sizeof(*info));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
info = to_cdi_pwm_info(chip);
|
||||
#else
|
||||
info = devm_kzalloc(
|
||||
&pdev->dev, sizeof(struct cdi_pwm_info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
chip = &info->chip;
|
||||
chip->dev = &pdev->dev;
|
||||
chip->npwm = npwm;
|
||||
#endif
|
||||
|
||||
atomic_set(&info->in_use, 0);
|
||||
mutex_init(&info->mutex);
|
||||
|
||||
force_on = of_property_read_bool(pdev->dev.of_node, "force_on");
|
||||
|
||||
info->chip.dev = &pdev->dev;
|
||||
info->chip.ops = &cdi_pwm_ops;
|
||||
chip->ops = &cdi_pwm_ops;
|
||||
#if defined(NV_PWM_CHIP_STRUCT_HAS_BASE_ARG)
|
||||
info->chip.base = -1;
|
||||
chip->base = -1;
|
||||
#endif
|
||||
info->chip.npwm = npwm;
|
||||
info->chip.of_xlate = of_cdi_pwm_xlate;
|
||||
chip->of_xlate = of_cdi_pwm_xlate;
|
||||
info->force_on = force_on;
|
||||
|
||||
err = pwmchip_add(&info->chip);
|
||||
err = pwmchip_add(chip);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, info);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
info->pwm = devm_pwm_get(&pdev->dev, NULL);
|
||||
if (!IS_ERR(info->pwm)) {
|
||||
pwm_disable(info->pwm);
|
||||
dev_info(&pdev->dev, "%s success to get PWM\n", __func__);
|
||||
} else {
|
||||
pwmchip_remove(&info->chip);
|
||||
pwmchip_remove(chip);
|
||||
err = PTR_ERR(info->pwm);
|
||||
if (err != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev,
|
||||
@@ -195,24 +217,24 @@ static int cdi_pwm_probe(struct platform_device *pdev)
|
||||
|
||||
static int cdi_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct cdi_pwm_info *info = platform_get_drvdata(pdev);
|
||||
struct pwm_chip *chip = platform_get_drvdata(pdev);
|
||||
|
||||
pwmchip_remove(&info->chip);
|
||||
pwmchip_remove(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdi_pwm_suspend(struct device *dev)
|
||||
{
|
||||
int err = 0;
|
||||
struct cdi_pwm_info *info = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct cdi_pwm_info *info = to_cdi_pwm_info(chip);
|
||||
|
||||
if (info == NULL) {
|
||||
dev_err(dev, "%s: fail to get info\n", __func__);
|
||||
} else {
|
||||
if (!IS_ERR(info->pwm)) {
|
||||
pwm_disable(info->pwm);
|
||||
err = pwm_config(info->pwm, PWM_SUSPEND_DUTY_RATIO,
|
||||
pwm_config(info->pwm, PWM_SUSPEND_DUTY_RATIO,
|
||||
PWM_SUSPEND_PERIOD);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2016-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
/* SPDX-FileCopyrightText: Copyright (c) 2016-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
|
||||
|
||||
#ifndef __ISC_PWM_PRIV_H__
|
||||
#define __ISC_PWM_PRIV_H__
|
||||
|
||||
struct isc_pwm_info {
|
||||
#if !defined(NV_PWM_CHIP_STRUCT_HAS_STRUCT_DEVICE)
|
||||
struct pwm_chip chip;
|
||||
#endif
|
||||
struct pwm_device *pwm;
|
||||
atomic_t in_use;
|
||||
struct mutex mutex;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2017-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
@@ -33,7 +33,11 @@ static int of_isc_gpio_pdata(struct platform_device *pdev,
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined(NV_GPIO_DEVICE_FIND_HAS_CONST_DATA_ARG) /* Linux v6.9 */
|
||||
static int isc_gpio_chip_match(struct gpio_chip *chip, const void *data)
|
||||
#else
|
||||
static int isc_gpio_chip_match(struct gpio_chip *chip, void *data)
|
||||
#endif
|
||||
{
|
||||
return !strcmp(chip->label, data);
|
||||
}
|
||||
@@ -43,7 +47,8 @@ static struct gpio_chip *isc_gpio_get_chip(struct platform_device *pdev,
|
||||
{
|
||||
struct gpio_chip *gc = NULL;
|
||||
char name[MAX_STR_SIZE];
|
||||
#if !defined(NV_GPIOCHIP_FIND_PRESENT) /* Linux 6.7 */
|
||||
#if defined(NV_GPIO_DEVICE_FIND_PRESENT) && \
|
||||
defined(NV_GPIO_DEVICE_GET_CHIP_PRESENT) /* Linux 6.7 */
|
||||
struct gpio_device *gdev;
|
||||
#endif
|
||||
|
||||
@@ -54,14 +59,15 @@ static struct gpio_chip *isc_gpio_get_chip(struct platform_device *pdev,
|
||||
}
|
||||
strcpy(name, pd->gpio_prnt_chip);
|
||||
|
||||
#if defined(NV_GPIOCHIP_FIND_PRESENT) /* Linux 6.7 */
|
||||
gc = gpiochip_find(name, isc_gpio_chip_match);
|
||||
#else
|
||||
#if defined(NV_GPIO_DEVICE_FIND_PRESENT) && \
|
||||
defined(NV_GPIO_DEVICE_GET_CHIP_PRESENT) /* Linux 6.7 */
|
||||
gdev = gpio_device_find(name, isc_gpio_chip_match);
|
||||
if (gdev) {
|
||||
gc = gpio_device_get_chip(gdev);
|
||||
gpio_device_put(gdev);
|
||||
}
|
||||
#else
|
||||
gc = gpiochip_find(name, isc_gpio_chip_match);
|
||||
#endif
|
||||
if (!gc) {
|
||||
dev_err(&pdev->dev, "%s: unable to find gpio parent chip %s\n",
|
||||
|
||||
@@ -30,7 +30,11 @@ static const struct of_device_id isc_pwm_of_match[] = {
|
||||
|
||||
static inline struct isc_pwm_info *to_isc_pwm_info(struct pwm_chip *chip)
|
||||
{
|
||||
#if defined(NV_PWM_CHIP_STRUCT_HAS_STRUCT_DEVICE)
|
||||
return pwmchip_get_drvdata(chip);
|
||||
#else
|
||||
return container_of(chip, struct isc_pwm_info, chip);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if KERNEL_VERSION(6, 0, 0) > LINUX_VERSION_CODE
|
||||
@@ -95,30 +99,38 @@ static struct pwm_device *of_isc_pwm_xlate(struct pwm_chip *pc,
|
||||
{
|
||||
struct pwm_device *pwm;
|
||||
struct isc_pwm_info *info = to_isc_pwm_info(pc);
|
||||
#if defined(NV_PWM_CHIP_STRUCT_HAS_STRUCT_DEVICE)
|
||||
struct device *dev = &pc->dev;
|
||||
#else
|
||||
struct device *dev = pc->dev;
|
||||
#endif
|
||||
int err = 0;
|
||||
|
||||
pwm = pwm_request_from_chip(pc, args->args[0], NULL);
|
||||
if (!args->args[1]) {
|
||||
dev_err(pc->dev, "Period should be larger than 0\n");
|
||||
pwm = of_pwm_xlate_with_flags(pc, args);
|
||||
if (IS_ERR(pwm))
|
||||
return NULL;
|
||||
|
||||
if (!pwm->args.period) {
|
||||
dev_err(dev, "Period should be larger than 0\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (info->force_on) {
|
||||
err = pwm_config(info->pwm, args->args[1]/4, args->args[1]);
|
||||
if (err) {
|
||||
dev_err(pc->dev, "can't config PWM: %d\n", err);
|
||||
dev_err(dev, "can't config PWM: %d\n", err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = pwm_enable(info->pwm);
|
||||
if (err) {
|
||||
dev_err(pc->dev, "can't enable PWM: %d\n", err);
|
||||
dev_err(dev, "can't enable PWM: %d\n", err);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
err = pwm_config(pwm, args->args[1]/4, args->args[1]);
|
||||
if (err) {
|
||||
dev_err(pc->dev, "can't config PWM: %d\n", err);
|
||||
dev_err(dev, "can't config PWM: %d\n", err);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -140,50 +152,60 @@ static const struct pwm_ops isc_pwm_ops = {
|
||||
static int isc_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct isc_pwm_info *info = NULL;
|
||||
struct pwm_chip *chip;
|
||||
int err = 0, npwm;
|
||||
bool force_on = false;
|
||||
|
||||
dev_info(&pdev->dev, "%sing...\n", __func__);
|
||||
|
||||
info = devm_kzalloc(
|
||||
&pdev->dev, sizeof(struct isc_pwm_info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
atomic_set(&info->in_use, 0);
|
||||
mutex_init(&info->mutex);
|
||||
|
||||
err = of_property_read_u32(pdev->dev.of_node, "npwm", &npwm);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "npwm is not defined: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined(NV_PWM_CHIP_STRUCT_HAS_STRUCT_DEVICE)
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, npwm, sizeof(*info));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
info = to_isc_pwm_info(chip);
|
||||
#else
|
||||
info = devm_kzalloc(
|
||||
&pdev->dev, sizeof(struct isc_pwm_info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
chip = &info->chip;
|
||||
chip->dev = &pdev->dev;
|
||||
chip->npwm = npwm;
|
||||
#endif
|
||||
|
||||
atomic_set(&info->in_use, 0);
|
||||
mutex_init(&info->mutex);
|
||||
|
||||
force_on = of_property_read_bool(pdev->dev.of_node, "force_on");
|
||||
|
||||
info->chip.dev = &pdev->dev;
|
||||
info->chip.ops = &isc_pwm_ops;
|
||||
chip->ops = &isc_pwm_ops;
|
||||
#if defined(NV_PWM_CHIP_STRUCT_HAS_BASE_ARG)
|
||||
info->chip.base = -1;
|
||||
chip->base = -1;
|
||||
#endif
|
||||
info->chip.npwm = npwm;
|
||||
info->chip.of_xlate = of_isc_pwm_xlate;
|
||||
chip->of_xlate = of_isc_pwm_xlate;
|
||||
info->force_on = force_on;
|
||||
|
||||
err = pwmchip_add(&info->chip);
|
||||
err = pwmchip_add(chip);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, info);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
info->pwm = devm_pwm_get(&pdev->dev, NULL);
|
||||
if (!IS_ERR(info->pwm)) {
|
||||
pwm_disable(info->pwm);
|
||||
dev_info(&pdev->dev, "%s success to get PWM\n", __func__);
|
||||
} else {
|
||||
pwmchip_remove(&info->chip);
|
||||
pwmchip_remove(chip);
|
||||
err = PTR_ERR(info->pwm);
|
||||
if (err != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev,
|
||||
@@ -195,24 +217,24 @@ static int isc_pwm_probe(struct platform_device *pdev)
|
||||
|
||||
static int isc_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct isc_pwm_info *info = platform_get_drvdata(pdev);
|
||||
struct pwm_chip *chip = platform_get_drvdata(pdev);
|
||||
|
||||
pwmchip_remove(&info->chip);
|
||||
pwmchip_remove(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int isc_pwm_suspend(struct device *dev)
|
||||
{
|
||||
int err = 0;
|
||||
struct isc_pwm_info *info = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct isc_pwm_info *info = to_isc_pwm_info(chip);
|
||||
|
||||
if (info == NULL) {
|
||||
dev_err(dev, "%s: fail to get info\n", __func__);
|
||||
} else {
|
||||
if (!IS_ERR(info->pwm)) {
|
||||
pwm_disable(info->pwm);
|
||||
err = pwm_config(info->pwm, PWM_SUSPEND_DUTY_RATIO,
|
||||
pwm_config(info->pwm, PWM_SUSPEND_DUTY_RATIO,
|
||||
PWM_SUSPEND_PERIOD);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,7 +297,7 @@ static int __init tpg_probe_t19x(void)
|
||||
return -EINVAL;
|
||||
|
||||
mc_csi->get_tpg_settings = get_tpg_settings_t23x;
|
||||
mc_csi->tpg_gain_ctrl = true;
|
||||
mc_csi->tpg_gain_ctrl = false;
|
||||
mc_csi->tpg_emb_data_config = emb_data;
|
||||
|
||||
dev_info(mc_csi->dev, "%s\n", __func__);
|
||||
@@ -310,7 +310,7 @@ static int __init tpg_probe_t19x(void)
|
||||
|
||||
mc_csi->tpg_frmfmt_table_size = table_size;
|
||||
memcpy(frmfmt_table, tegra19x_csi_tpg_frmfmt,
|
||||
table_size * sizeof(struct tpg_frmfmt));
|
||||
table_size * sizeof(struct tpg_frmfmt));
|
||||
|
||||
if (override_frmfmt) {
|
||||
for (i = 0; i < table_size; i++)
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved.
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
LINUX_VERSION := $(shell expr $(VERSION) \* 256 + $(PATCHLEVEL))
|
||||
LINUX_VERSION_6_11 := $(shell expr 6 \* 256 + 11)
|
||||
|
||||
# MODS is currently broken for Linux v6.11 and later
|
||||
ifeq ($(shell test $(LINUX_VERSION) -lt $(LINUX_VERSION_6_11); echo $$?),0)
|
||||
ifeq ($(findstring ack_src,$(NV_BUILD_KERNEL_OPTIONS)),)
|
||||
obj-m += mods/
|
||||
endif
|
||||
endif
|
||||
obj-m += nvsciipc/
|
||||
ifdef CONFIG_PCI
|
||||
obj-m += tegra-pcie-dma-test.o
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#define pr_fmt(fmt) "nvscic2c-pcie: comm-channel: " fmt
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/dma-fence.h>
|
||||
#include <linux/errno.h>
|
||||
@@ -215,7 +217,11 @@ send_msg(struct comm_channel_ctx_t *comm_ctx, struct comm_msg *msg)
|
||||
|
||||
if (peer_cpu == NVCPU_X86_64) {
|
||||
/* comm-channel irq verctor always take from index 0 */
|
||||
#if defined(PCI_EPC_IRQ_TYPE_ENUM_PRESENT) /* Dropped from Linux 6.8 */
|
||||
ret = pci_client_raise_irq(comm_ctx->pci_client_h, PCI_EPC_IRQ_MSI, 0);
|
||||
#else
|
||||
ret = pci_client_raise_irq(comm_ctx->pci_client_h, PCI_IRQ_MSI, 0);
|
||||
#endif
|
||||
} else {
|
||||
/* notify peer for each write.*/
|
||||
writel(0x1, syncpt->peer_mem.pva);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#define pr_fmt(fmt) "nvscic2c-pcie: endpoint: " fmt
|
||||
|
||||
@@ -501,8 +501,13 @@ ioctl_notify_remote_impl(struct endpoint_t *endpoint)
|
||||
return -ENOLINK;
|
||||
|
||||
if (peer_cpu == NVCPU_X86_64) {
|
||||
#if defined(PCI_EPC_IRQ_TYPE_ENUM_PRESENT) /* Dropped from Linux 6.8 */
|
||||
ret = pci_client_raise_irq(endpoint->pci_client_h, PCI_EPC_IRQ_MSI,
|
||||
endpoint->msi_irq);
|
||||
#else
|
||||
ret = pci_client_raise_irq(endpoint->pci_client_h, PCI_IRQ_MSI,
|
||||
endpoint->msi_irq);
|
||||
#endif
|
||||
} else {
|
||||
/*
|
||||
* Ordering between message/data and host1x syncpoints is not
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#define pr_fmt(fmt) "nvscic2c-pcie: epf: " fmt
|
||||
|
||||
@@ -169,6 +171,7 @@ allocate_outbound_area(struct pci_epf *epf, size_t win_size,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(NV_PCI_EPC_EVENT_OPS_STRUCT_HAS_CORE_DEINIT) /* Nvidia Internal */
|
||||
static void
|
||||
clear_inbound_translation(struct pci_epf *epf)
|
||||
{
|
||||
@@ -178,6 +181,7 @@ clear_inbound_translation(struct pci_epf *epf)
|
||||
|
||||
/* no api to clear epf header.*/
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
set_inbound_translation(struct pci_epf *epf)
|
||||
@@ -490,6 +494,7 @@ deinit_work(struct work_struct *work)
|
||||
* @DRV_MODE_EPC would have already gone then by the time
|
||||
* struct pci_epc_event_ops.core_deinit is called.
|
||||
*/
|
||||
#if defined(NV_PCI_EPC_EVENT_OPS_STRUCT_HAS_CORE_DEINIT) /* Nvidia Internal */
|
||||
static int
|
||||
nvscic2c_pcie_epf_core_deinit(struct pci_epf *epf)
|
||||
{
|
||||
@@ -517,6 +522,7 @@ nvscic2c_pcie_epf_core_deinit(struct pci_epf *epf)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Handle link message from @DRV_MODE_EPC. */
|
||||
static void
|
||||
@@ -729,7 +735,9 @@ get_driverdata(const struct pci_epf_device_id *id,
|
||||
|
||||
static const struct pci_epc_event_ops nvscic2c_event_ops = {
|
||||
.core_init = nvscic2c_pcie_epf_core_init,
|
||||
#if defined(NV_PCI_EPC_EVENT_OPS_STRUCT_HAS_CORE_DEINIT) /* Nvidia Internal */
|
||||
.core_deinit = nvscic2c_pcie_epf_core_deinit,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#define pr_fmt(fmt) "nvscic2c-pcie: pci-client: " fmt
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/dma-map-ops.h>
|
||||
#include <linux/errno.h>
|
||||
@@ -246,7 +248,12 @@ allocate_edma_rx_desc_iova(struct pci_client_t *ctx)
|
||||
goto err;
|
||||
}
|
||||
prot = (IOMMU_CACHE | IOMMU_READ | IOMMU_WRITE);
|
||||
ret = iommu_map(ctx->domain, ctx->edma_ch_desc_iova, phys_addr, EDMA_CH_DESC_SZ, prot);
|
||||
ret = iommu_map(ctx->domain, ctx->edma_ch_desc_iova, phys_addr,
|
||||
#if defined(NV_IOMMU_MAP_HAS_GFP_ARG)
|
||||
EDMA_CH_DESC_SZ, prot, GFP_KERNEL);
|
||||
#else
|
||||
EDMA_CH_DESC_SZ, prot);
|
||||
#endif
|
||||
if (ret) {
|
||||
pr_err("pci client failed to map iova to 60K physical backing\n");
|
||||
goto err;
|
||||
@@ -408,7 +415,12 @@ pci_client_map_addr(void *pci_client_h, u64 to_iova, phys_addr_t paddr,
|
||||
if (WARN_ON(!ctx || !to_iova || !paddr || !size))
|
||||
return -EINVAL;
|
||||
|
||||
return iommu_map(ctx->domain, to_iova, paddr, size, prot);
|
||||
return iommu_map(ctx->domain, to_iova, paddr, size,
|
||||
#if defined(NV_IOMMU_MAP_HAS_GFP_ARG)
|
||||
prot, GFP_KERNEL);
|
||||
#else
|
||||
prot);
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t
|
||||
@@ -751,7 +763,7 @@ pci_client_get_drv_mode(void *pci_client_h)
|
||||
return DRV_MODE_INVALID;
|
||||
drv_ctx = pci_client_ctx->drv_ctx;
|
||||
if (WARN_ON(!drv_ctx))
|
||||
return NVCPU_MAXIMUM;
|
||||
return DRV_MODE_INVALID;
|
||||
return drv_ctx->drv_mode;
|
||||
}
|
||||
|
||||
@@ -800,7 +812,11 @@ pci_client_get_edma_rx_desc_iova(void *pci_client_h)
|
||||
}
|
||||
|
||||
int
|
||||
#if defined(PCI_EPC_IRQ_TYPE_ENUM_PRESENT) /* Dropped from Linux 6.8 */
|
||||
pci_client_raise_irq(void *pci_client_h, enum pci_epc_irq_type type, u16 num)
|
||||
#else
|
||||
pci_client_raise_irq(void *pci_client_h, int type, u16 num)
|
||||
#endif
|
||||
{
|
||||
int ret = 0;
|
||||
struct pci_client_t *pci_client_ctx = (struct pci_client_t *)pci_client_h;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#ifndef __PCI_CLIENT_H__
|
||||
#define __PCI_CLIENT_H__
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <uapi/misc/nvscic2c-pcie-ioctl.h>
|
||||
|
||||
#include "common.h"
|
||||
@@ -133,5 +135,9 @@ pci_client_get_edma_rx_desc_iova(void *pci_client_h);
|
||||
|
||||
/* pci client raise irq to rp */
|
||||
int
|
||||
#if defined(PCI_EPC_IRQ_TYPE_ENUM_PRESENT) /* Dropped from Linux 6.8 */
|
||||
pci_client_raise_irq(void *pci_client_h, enum pci_epc_irq_type type, u16 num);
|
||||
#else
|
||||
pci_client_raise_irq(void *pci_client_h, int type, u16 num);
|
||||
#endif
|
||||
#endif // __PCI_CLIENT_H__
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#define pr_fmt(fmt) "nvscic2c-pcie: stream-ext: " fmt
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/host1x-next.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/tegra-pcie-edma.h>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
@@ -505,7 +505,8 @@ static int mttcan_state_change(struct net_device *dev,
|
||||
*/
|
||||
ttcan_set_intrpts(priv->ttcan, 0);
|
||||
priv->can.can_stats.bus_off++;
|
||||
|
||||
priv->ttcan->tx_object = 0;
|
||||
netif_stop_queue(dev);
|
||||
netif_carrier_off(dev);
|
||||
|
||||
if (priv->can.restart_ms)
|
||||
@@ -1114,6 +1115,7 @@ restart:
|
||||
priv->can.can_stats.restarts++;
|
||||
|
||||
mttcan_start(dev);
|
||||
netif_start_queue(dev);
|
||||
netif_carrier_on(dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
obj-m += nvidia/
|
||||
|
||||
ifdef CONFIG_PCI
|
||||
obj-m += marvell/
|
||||
obj-m += microchip/
|
||||
ifeq ($(VERSION).$(PATCHLEVEL),5.15)
|
||||
obj-m += realtek/
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -3030,15 +3030,15 @@ static int ether_close(struct net_device *ndev)
|
||||
reset_control_assert(pdata->xpcs_rst);
|
||||
}
|
||||
|
||||
/* All MDIO interfaces must be disabled before resetting the MAC */
|
||||
if (pdata->mii)
|
||||
mdiobus_unregister(pdata->mii);
|
||||
|
||||
/* Assert MAC RST gpio */
|
||||
if (pdata->mac_rst) {
|
||||
reset_control_assert(pdata->mac_rst);
|
||||
}
|
||||
|
||||
if (pdata->mii != NULL) {
|
||||
mdiobus_unregister(pdata->mii);
|
||||
}
|
||||
|
||||
/* Disable clock */
|
||||
ether_disable_clks(pdata);
|
||||
|
||||
@@ -3309,10 +3309,10 @@ static int ether_tx_swcx_alloc(struct ether_priv_data *pdata,
|
||||
}
|
||||
|
||||
size = min(len, max_data_len_per_txd);
|
||||
page_idx = (frag->bv_offset + offset) >> PAGE_SHIFT;
|
||||
page_offset = (frag->bv_offset + offset) & ~PAGE_MASK;
|
||||
page_idx = (skb_frag_off(frag) + offset) >> PAGE_SHIFT;
|
||||
page_offset = (skb_frag_off(frag) + offset) & ~PAGE_MASK;
|
||||
tx_swcx->buf_phy_addr = dma_map_page(dev,
|
||||
(frag->bv_page + page_idx),
|
||||
(skb_frag_page(frag) + page_idx),
|
||||
page_offset, size,
|
||||
DMA_TO_DEVICE);
|
||||
if (unlikely(dma_mapping_error(dev,
|
||||
@@ -6666,7 +6666,7 @@ static int ether_probe(struct platform_device *pdev)
|
||||
goto err_macsec;
|
||||
} else if (ret == 1) {
|
||||
/* Nothing to do, macsec is not supported */
|
||||
dev_info(&pdev->dev, "Macsec not supported/Not enabled in DT\n");
|
||||
dev_info(&pdev->dev, "Macsec not supported/Not enabled\n");
|
||||
} else {
|
||||
dev_info(&pdev->dev, "Macsec not enabled\n");
|
||||
/* Macsec is supported, reduce MTU */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright (c) 2019-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2019-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
@@ -863,7 +863,11 @@ static int ether_set_pauseparam(struct net_device *ndev,
|
||||
* @return zero on success
|
||||
*/
|
||||
static int ether_get_ts_info(struct net_device *ndev,
|
||||
#if defined(NV_ETHTOOL_KERNEL_ETHTOOL_TS_INFO_STRUCT_PRESENT) /* Linux v6.11 */
|
||||
struct kernel_ethtool_ts_info *info)
|
||||
#else
|
||||
struct ethtool_ts_info *info)
|
||||
#endif
|
||||
{
|
||||
struct ether_priv_data *pdata = netdev_priv(ndev);
|
||||
|
||||
@@ -1095,7 +1099,11 @@ static int ether_get_coalesce(struct net_device *dev,
|
||||
* @retval -ve on Failure
|
||||
*/
|
||||
static int ether_get_eee(struct net_device *ndev,
|
||||
#if defined(NV_ETHTOOL_KEEE_STRUCT_PRESENT) /* Linux v6.9 */
|
||||
struct ethtool_keee *cur_eee)
|
||||
#else
|
||||
struct ethtool_eee *cur_eee)
|
||||
#endif
|
||||
{
|
||||
int ret;
|
||||
struct ether_priv_data *pdata = netdev_priv(ndev);
|
||||
@@ -1136,8 +1144,13 @@ static int ether_get_eee(struct net_device *ndev,
|
||||
* @retval none
|
||||
*/
|
||||
static inline void validate_eee_conf(struct net_device *ndev,
|
||||
#if defined(NV_ETHTOOL_KEEE_STRUCT_PRESENT) /* Linux v6.9 */
|
||||
struct ethtool_keee *eee_req,
|
||||
struct ethtool_keee cur_eee)
|
||||
#else
|
||||
struct ethtool_eee *eee_req,
|
||||
struct ethtool_eee cur_eee)
|
||||
#endif
|
||||
{
|
||||
/* These are the invalid combinations that can be requested.
|
||||
* EEE | Tx LPI | Rx LPI
|
||||
@@ -1152,10 +1165,18 @@ static inline void validate_eee_conf(struct net_device *ndev,
|
||||
* on whether EEE has toggled or not.
|
||||
*/
|
||||
if (!eee_req->eee_enabled && !eee_req->tx_lpi_enabled &&
|
||||
#if defined(NV_ETHTOOL_KEEE_STRUCT_PRESENT) /* Linux v6.9 */
|
||||
!linkmode_empty(eee_req->advertised)) {
|
||||
#else
|
||||
eee_req->advertised) {
|
||||
#endif
|
||||
if (eee_req->eee_enabled != cur_eee.eee_enabled) {
|
||||
netdev_warn(ndev, "EEE off. Set Rx LPI off\n");
|
||||
#if defined(NV_ETHTOOL_KEEE_STRUCT_PRESENT) /* Linux v6.9 */
|
||||
linkmode_zero(eee_req->advertised);
|
||||
#else
|
||||
eee_req->advertised = OSI_DISABLE;
|
||||
#endif
|
||||
} else {
|
||||
netdev_warn(ndev, "Rx LPI on. Set EEE on\n");
|
||||
eee_req->eee_enabled = OSI_ENABLE;
|
||||
@@ -1163,7 +1184,11 @@ static inline void validate_eee_conf(struct net_device *ndev,
|
||||
}
|
||||
|
||||
if (!eee_req->eee_enabled && eee_req->tx_lpi_enabled &&
|
||||
#if defined(NV_ETHTOOL_KEEE_STRUCT_PRESENT) /* Linux v6.9 */
|
||||
linkmode_empty(eee_req->advertised)) {
|
||||
#else
|
||||
!eee_req->advertised) {
|
||||
#endif
|
||||
if (eee_req->eee_enabled != cur_eee.eee_enabled) {
|
||||
netdev_warn(ndev, "EEE off. Set Tx LPI off\n");
|
||||
eee_req->tx_lpi_enabled = OSI_DISABLE;
|
||||
@@ -1174,16 +1199,28 @@ static inline void validate_eee_conf(struct net_device *ndev,
|
||||
*/
|
||||
netdev_warn(ndev, "Tx LPI on. Set EEE & Rx LPI on\n");
|
||||
eee_req->eee_enabled = OSI_ENABLE;
|
||||
#if defined(NV_ETHTOOL_KEEE_STRUCT_PRESENT) /* Linux v6.9 */
|
||||
linkmode_copy(eee_req->advertised, eee_req->supported);
|
||||
#else
|
||||
eee_req->advertised = eee_req->supported;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (!eee_req->eee_enabled && eee_req->tx_lpi_enabled &&
|
||||
#if defined(NV_ETHTOOL_KEEE_STRUCT_PRESENT) /* Linux v6.9 */
|
||||
!linkmode_empty(eee_req->advertised)) {
|
||||
#else
|
||||
eee_req->advertised) {
|
||||
#endif
|
||||
if (eee_req->eee_enabled != cur_eee.eee_enabled) {
|
||||
netdev_warn(ndev, "EEE off. Set Tx & Rx LPI off\n");
|
||||
eee_req->tx_lpi_enabled = OSI_DISABLE;
|
||||
#if defined(NV_ETHTOOL_KEEE_STRUCT_PRESENT) /* Linux v6.9 */
|
||||
linkmode_zero(eee_req->advertised);
|
||||
#else
|
||||
eee_req->advertised = OSI_DISABLE;
|
||||
#endif
|
||||
} else {
|
||||
netdev_warn(ndev, "Tx & Rx LPI on. Set EEE on\n");
|
||||
eee_req->eee_enabled = OSI_ENABLE;
|
||||
@@ -1191,11 +1228,19 @@ static inline void validate_eee_conf(struct net_device *ndev,
|
||||
}
|
||||
|
||||
if (eee_req->eee_enabled && !eee_req->tx_lpi_enabled &&
|
||||
#if defined(NV_ETHTOOL_KEEE_STRUCT_PRESENT) /* Linux v6.9 */
|
||||
linkmode_empty(eee_req->advertised)) {
|
||||
#else
|
||||
!eee_req->advertised) {
|
||||
#endif
|
||||
if (eee_req->eee_enabled != cur_eee.eee_enabled) {
|
||||
netdev_warn(ndev, "EEE on. Set Tx & Rx LPI on\n");
|
||||
eee_req->tx_lpi_enabled = OSI_ENABLE;
|
||||
#if defined(NV_ETHTOOL_KEEE_STRUCT_PRESENT) /* Linux v6.9 */
|
||||
linkmode_copy(eee_req->advertised, eee_req->supported);
|
||||
#else
|
||||
eee_req->advertised = eee_req->supported;
|
||||
#endif
|
||||
} else {
|
||||
netdev_warn(ndev, "Tx,Rx LPI off. Set EEE off\n");
|
||||
eee_req->eee_enabled = OSI_DISABLE;
|
||||
@@ -1218,11 +1263,19 @@ static inline void validate_eee_conf(struct net_device *ndev,
|
||||
* @retval -ve on Failure
|
||||
*/
|
||||
static int ether_set_eee(struct net_device *ndev,
|
||||
#if defined(NV_ETHTOOL_KEEE_STRUCT_PRESENT) /* Linux v6.9 */
|
||||
struct ethtool_keee *eee_req)
|
||||
#else
|
||||
struct ethtool_eee *eee_req)
|
||||
#endif
|
||||
{
|
||||
struct ether_priv_data *pdata = netdev_priv(ndev);
|
||||
struct phy_device *phydev = pdata->phydev;
|
||||
#if defined(NV_ETHTOOL_KEEE_STRUCT_PRESENT) /* Linux v6.9 */
|
||||
struct ethtool_keee cur_eee;
|
||||
#else
|
||||
struct ethtool_eee cur_eee;
|
||||
#endif
|
||||
|
||||
if (!pdata->hw_feat.eee_sel) {
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
@@ -9,6 +9,11 @@
|
||||
#ifdef HSI_SUPPORT
|
||||
#include <linux/tegra-epl.h>
|
||||
#endif
|
||||
|
||||
static bool macsec_enable = true;
|
||||
module_param(macsec_enable, bool, 0644);
|
||||
MODULE_PARM_DESC(macsec_enable, "Enable Macsec for nvethernet module");
|
||||
|
||||
static int macsec_get_tx_next_pn(struct sk_buff *skb, struct genl_info *info);
|
||||
|
||||
#ifndef MACSEC_KEY_PROGRAM
|
||||
@@ -1365,9 +1370,10 @@ int macsec_probe(struct ether_priv_data *pdata)
|
||||
/* Read if macsec is enabled in DT */
|
||||
ret = of_property_read_u32(np, "nvidia,macsec-enable",
|
||||
&macsec_pdata->is_macsec_enabled_in_dt);
|
||||
if ((ret != 0) || (macsec_pdata->is_macsec_enabled_in_dt == 0U)) {
|
||||
if (ret != 0 || !macsec_enable ||
|
||||
macsec_pdata->is_macsec_enabled_in_dt == 0U) {
|
||||
dev_info(dev,
|
||||
"macsec param in DT is missing or disabled\n");
|
||||
"macsec parameter is missing or disabled\n");
|
||||
ret = 1;
|
||||
goto init_err;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright (c) 2019-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved */
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2019-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <linux/version.h>
|
||||
#include "ether_linux.h"
|
||||
|
||||
/**
|
||||
@@ -130,11 +129,7 @@ static int ether_adjust_time(struct ptp_clock_info *ptp, s64 nsec_delta)
|
||||
* @retval 0 on success
|
||||
* @retval "negative value" on failure.
|
||||
*/
|
||||
#if KERNEL_VERSION(6, 2, 0) > LINUX_VERSION_CODE
|
||||
static int ether_adjust_clock(struct ptp_clock_info *ptp, s32 ppb)
|
||||
#else
|
||||
static int ether_adjust_clock(struct ptp_clock_info *ptp, long scaled_ppm)
|
||||
#endif
|
||||
{
|
||||
struct ether_priv_data *pdata = container_of(ptp,
|
||||
struct ether_priv_data,
|
||||
@@ -143,14 +138,11 @@ static int ether_adjust_clock(struct ptp_clock_info *ptp, long scaled_ppm)
|
||||
struct osi_ioctl ioctl_data = {};
|
||||
unsigned long flags;
|
||||
int ret = -1;
|
||||
#if KERNEL_VERSION(6, 2, 0) <= LINUX_VERSION_CODE
|
||||
s32 ppb = scaled_ppm_to_ppb(scaled_ppm);
|
||||
#endif
|
||||
|
||||
raw_spin_lock_irqsave(&pdata->ptp_lock, flags);
|
||||
|
||||
ioctl_data.cmd = OSI_CMD_ADJ_FREQ;
|
||||
ioctl_data.arg6_32 = ppb;
|
||||
ioctl_data.arg6_32 = scaled_ppm_to_ppb(scaled_ppm);
|
||||
ret = osi_handle_ioctl(osi_core, &ioctl_data);
|
||||
if (ret < 0) {
|
||||
dev_err(pdata->dev,
|
||||
@@ -253,11 +245,7 @@ static struct ptp_clock_info ether_ptp_clock_ops = {
|
||||
.n_ext_ts = 0,
|
||||
.n_per_out = 0,
|
||||
.pps = 0,
|
||||
#if KERNEL_VERSION(6, 2, 0) > LINUX_VERSION_CODE
|
||||
.adjfreq = ether_adjust_clock,
|
||||
#else
|
||||
.adjfine = ether_adjust_clock,
|
||||
#endif
|
||||
.adjtime = ether_adjust_time,
|
||||
.gettime64 = ether_get_time,
|
||||
.settime64 = ether_set_time,
|
||||
|
||||
@@ -183,6 +183,11 @@ static void tvnet_host_alloc_empty_buffers(struct tvnet_priv *tvnet)
|
||||
break;
|
||||
}
|
||||
|
||||
/* The PCIe link is stable and dependable,
|
||||
* so it's not necessary to perform a software checksum.
|
||||
*/
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
|
||||
ep2h_empty_ptr = kmalloc(sizeof(*ep2h_empty_ptr), GFP_ATOMIC);
|
||||
if (!ep2h_empty_ptr) {
|
||||
dma_unmap_single(d, iova, len, DMA_FROM_DEVICE);
|
||||
@@ -651,16 +656,18 @@ static int tvnet_host_process_ep2h_msg(struct tvnet_priv *tvnet)
|
||||
list_for_each_entry(ep2h_empty_ptr, &tvnet->ep2h_empty_list,
|
||||
list) {
|
||||
if (ep2h_empty_ptr->iova == pcie_address) {
|
||||
list_del(&ep2h_empty_ptr->list);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
WARN_ON(!found);
|
||||
list_del(&ep2h_empty_ptr->list);
|
||||
spin_unlock_irqrestore(&tvnet->ep2h_empty_lock, flags);
|
||||
|
||||
/* Advance H2EP full buffer after search in local list */
|
||||
tvnet_ivc_advance_rd(&tvnet->ep2h_full);
|
||||
if (WARN_ON(!found))
|
||||
continue;
|
||||
|
||||
/* If EP2H network queue is stopped due to lack of EP2H_FULL
|
||||
* queue, raising ctrl irq will help.
|
||||
*/
|
||||
|
||||
@@ -1,100 +1,10 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
################################################################################
|
||||
#
|
||||
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2022 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author:
|
||||
# Realtek NIC software team <nicfae@realtek.com>
|
||||
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
|
||||
#
|
||||
################################################################################
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
################################################################################
|
||||
# This product is covered by one or more of the following patents:
|
||||
# US6,570,884, US6,115,776, and US6,327,625.
|
||||
################################################################################
|
||||
|
||||
CONFIG_SOC_LAN = n
|
||||
ENABLE_FIBER_SUPPORT = n
|
||||
ENABLE_REALWOW_SUPPORT = n
|
||||
ENABLE_DASH_SUPPORT = n
|
||||
ENABLE_DASH_PRINTER_SUPPORT = n
|
||||
CONFIG_DOWN_SPEED_100 = n
|
||||
CONFIG_ASPM = y
|
||||
ENABLE_S5WOL = y
|
||||
ENABLE_S5_KEEP_CURR_MAC = n
|
||||
ENABLE_EEE = y
|
||||
ENABLE_S0_MAGIC_PACKET = n
|
||||
CONFIG_DYNAMIC_ASPM = y
|
||||
ENABLE_USE_FIRMWARE_FILE = n
|
||||
CONFIG_CTAP_SHORT_OFF = n
|
||||
|
||||
obj-m += r8168.o
|
||||
|
||||
r8168-objs += r8168_n.o r8168_asf.o rtl_eeprom.o rtltool.o
|
||||
ifeq ($(CONFIG_SOC_LAN), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_SOC_LAN
|
||||
endif
|
||||
ifeq ($(ENABLE_FIBER_SUPPORT), y)
|
||||
r8168-objs += r8168_fiber.o
|
||||
EXTRA_CFLAGS += -DENABLE_FIBER_SUPPORT
|
||||
endif
|
||||
ifeq ($(ENABLE_REALWOW_SUPPORT), y)
|
||||
r8168-objs += r8168_realwow.o
|
||||
EXTRA_CFLAGS += -DENABLE_REALWOW_SUPPORT
|
||||
endif
|
||||
ifeq ($(ENABLE_DASH_SUPPORT), y)
|
||||
r8168-objs += r8168_dash.o
|
||||
EXTRA_CFLAGS += -DENABLE_DASH_SUPPORT
|
||||
endif
|
||||
ifeq ($(ENABLE_DASH_PRINTER_SUPPORT), y)
|
||||
r8168-objs += r8168_dash.o
|
||||
EXTRA_CFLAGS += -DENABLE_DASH_SUPPORT -DENABLE_DASH_PRINTER_SUPPORT
|
||||
endif
|
||||
EXTRA_CFLAGS += -DCONFIG_R8168_NAPI
|
||||
EXTRA_CFLAGS += -DCONFIG_R8168_VLAN
|
||||
ifeq ($(CONFIG_DOWN_SPEED_100), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_DOWN_SPEED_100
|
||||
endif
|
||||
ifeq ($(CONFIG_ASPM), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_ASPM
|
||||
endif
|
||||
ifeq ($(ENABLE_S5WOL), y)
|
||||
EXTRA_CFLAGS += -DENABLE_S5WOL
|
||||
endif
|
||||
ifeq ($(ENABLE_S5_KEEP_CURR_MAC), y)
|
||||
EXTRA_CFLAGS += -DENABLE_S5_KEEP_CURR_MAC
|
||||
endif
|
||||
ifeq ($(ENABLE_EEE), y)
|
||||
EXTRA_CFLAGS += -DENABLE_EEE
|
||||
endif
|
||||
ifeq ($(ENABLE_S0_MAGIC_PACKET), y)
|
||||
EXTRA_CFLAGS += -DENABLE_S0_MAGIC_PACKET
|
||||
endif
|
||||
ifeq ($(CONFIG_DYNAMIC_ASPM), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_DYNAMIC_ASPM
|
||||
endif
|
||||
ifeq ($(ENABLE_USE_FIRMWARE_FILE), y)
|
||||
r8168-objs += r8168_firmware.o
|
||||
EXTRA_CFLAGS += -DENABLE_USE_FIRMWARE_FILE
|
||||
endif
|
||||
ifeq ($(CONFIG_CTAP_SHORT_OFF), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_CTAP_SHORT_OFF
|
||||
ifneq ($(NV_OOT_REALTEK_R8168_SKIP_BUILD),y)
|
||||
obj-m += r8168/
|
||||
endif
|
||||
|
||||
ifneq ($(NV_OOT_REALTEK_R8126_SKIP_BUILD),y)
|
||||
obj-m += r8126/
|
||||
endif
|
||||
|
||||
143
drivers/net/ethernet/realtek/r8126/Makefile
Normal file
143
drivers/net/ethernet/realtek/r8126/Makefile
Normal file
@@ -0,0 +1,143 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
################################################################################
|
||||
#
|
||||
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author:
|
||||
# Realtek NIC software team <nicfae@realtek.com>
|
||||
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
|
||||
#
|
||||
################################################################################
|
||||
|
||||
################################################################################
|
||||
# This product is covered by one or more of the following patents:
|
||||
# US6,570,884, US6,115,776, and US6,327,625.
|
||||
################################################################################
|
||||
|
||||
LINUX_VERSION := $(shell expr $(VERSION) \* 256 + $(PATCHLEVEL))
|
||||
LINUX_VERSION_6_9 := $(shell expr 6 \* 256 + 9)
|
||||
|
||||
# Use dummy R8126 driver for Kernel versions greater that K69
|
||||
ifeq ($(shell test $(LINUX_VERSION) -gt $(LINUX_VERSION_6_9); echo $$?),0)
|
||||
obj-m := r8126.o
|
||||
r8126-objs := r8126_dummy.o
|
||||
else
|
||||
|
||||
CONFIG_SOC_LAN = n
|
||||
ENABLE_REALWOW_SUPPORT = n
|
||||
ENABLE_DASH_SUPPORT = n
|
||||
ENABLE_DASH_PRINTER_SUPPORT = n
|
||||
CONFIG_DOWN_SPEED_100 = n
|
||||
CONFIG_ASPM = y
|
||||
ENABLE_S5WOL = y
|
||||
ENABLE_S5_KEEP_CURR_MAC = n
|
||||
ENABLE_EEE = y
|
||||
ENABLE_S0_MAGIC_PACKET = n
|
||||
ENABLE_TX_NO_CLOSE = y
|
||||
ENABLE_MULTIPLE_TX_QUEUE = y
|
||||
ENABLE_PTP_SUPPORT = y
|
||||
ENABLE_PTP_MASTER_MODE = n
|
||||
ENABLE_RSS_SUPPORT = y
|
||||
ENABLE_LIB_SUPPORT = n
|
||||
ENABLE_USE_FIRMWARE_FILE = n
|
||||
DISABLE_WOL_SUPPORT = n
|
||||
DISABLE_MULTI_MSIX_VECTOR = n
|
||||
ENABLE_DOUBLE_VLAN = n
|
||||
ENABLE_PAGE_REUSE = n
|
||||
ENABLE_RX_PACKET_FRAGMENT = n
|
||||
|
||||
obj-m := r8126.o
|
||||
r8126-objs := r8126_n.o rtl_eeprom.o rtltool.o
|
||||
ifeq ($(CONFIG_SOC_LAN), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_SOC_LAN
|
||||
endif
|
||||
ifeq ($(ENABLE_REALWOW_SUPPORT), y)
|
||||
r8126-objs += r8126_realwow.o
|
||||
EXTRA_CFLAGS += -DENABLE_REALWOW_SUPPORT
|
||||
endif
|
||||
ifeq ($(ENABLE_DASH_SUPPORT), y)
|
||||
r8126-objs += r8126_dash.o
|
||||
EXTRA_CFLAGS += -DENABLE_DASH_SUPPORT
|
||||
endif
|
||||
ifeq ($(ENABLE_DASH_PRINTER_SUPPORT), y)
|
||||
r8126-objs += r8126_dash.o
|
||||
EXTRA_CFLAGS += -DENABLE_DASH_SUPPORT -DENABLE_DASH_PRINTER_SUPPORT
|
||||
endif
|
||||
EXTRA_CFLAGS += -DCONFIG_R8126_NAPI
|
||||
EXTRA_CFLAGS += -DCONFIG_R8126_VLAN
|
||||
ifeq ($(CONFIG_DOWN_SPEED_100), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_DOWN_SPEED_100
|
||||
endif
|
||||
ifeq ($(CONFIG_ASPM), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_ASPM
|
||||
endif
|
||||
ifeq ($(ENABLE_S5WOL), y)
|
||||
EXTRA_CFLAGS += -DENABLE_S5WOL
|
||||
endif
|
||||
ifeq ($(ENABLE_S5_KEEP_CURR_MAC), y)
|
||||
EXTRA_CFLAGS += -DENABLE_S5_KEEP_CURR_MAC
|
||||
endif
|
||||
ifeq ($(ENABLE_EEE), y)
|
||||
EXTRA_CFLAGS += -DENABLE_EEE
|
||||
endif
|
||||
ifeq ($(ENABLE_S0_MAGIC_PACKET), y)
|
||||
EXTRA_CFLAGS += -DENABLE_S0_MAGIC_PACKET
|
||||
endif
|
||||
ifeq ($(ENABLE_TX_NO_CLOSE), y)
|
||||
EXTRA_CFLAGS += -DENABLE_TX_NO_CLOSE
|
||||
endif
|
||||
ifeq ($(ENABLE_MULTIPLE_TX_QUEUE), y)
|
||||
EXTRA_CFLAGS += -DENABLE_MULTIPLE_TX_QUEUE
|
||||
endif
|
||||
ifeq ($(ENABLE_PTP_SUPPORT), y)
|
||||
r8126-objs += r8126_ptp.o
|
||||
EXTRA_CFLAGS += -DENABLE_PTP_SUPPORT
|
||||
endif
|
||||
ifeq ($(ENABLE_PTP_MASTER_MODE), y)
|
||||
EXTRA_CFLAGS += -DENABLE_PTP_MASTER_MODE
|
||||
endif
|
||||
ifeq ($(ENABLE_RSS_SUPPORT), y)
|
||||
r8126-objs += r8126_rss.o
|
||||
EXTRA_CFLAGS += -DENABLE_RSS_SUPPORT
|
||||
endif
|
||||
ifeq ($(ENABLE_LIB_SUPPORT), y)
|
||||
r8126-objs += r8126_lib.o
|
||||
EXTRA_CFLAGS += -DENABLE_LIB_SUPPORT
|
||||
endif
|
||||
ifeq ($(ENABLE_USE_FIRMWARE_FILE), y)
|
||||
r8126-objs += r8126_firmware.o
|
||||
EXTRA_CFLAGS += -DENABLE_USE_FIRMWARE_FILE
|
||||
endif
|
||||
ifeq ($(DISABLE_WOL_SUPPORT), y)
|
||||
EXTRA_CFLAGS += -DDISABLE_WOL_SUPPORT
|
||||
endif
|
||||
ifeq ($(DISABLE_MULTI_MSIX_VECTOR), y)
|
||||
EXTRA_CFLAGS += -DDISABLE_MULTI_MSIX_VECTOR
|
||||
endif
|
||||
ifeq ($(ENABLE_DOUBLE_VLAN), y)
|
||||
EXTRA_CFLAGS += -DENABLE_DOUBLE_VLAN
|
||||
endif
|
||||
ifeq ($(ENABLE_PAGE_REUSE), y)
|
||||
EXTRA_CFLAGS += -DENABLE_PAGE_REUSE
|
||||
endif
|
||||
ifeq ($(ENABLE_RX_PACKET_FRAGMENT), y)
|
||||
EXTRA_CFLAGS += -DENABLE_RX_PACKET_FRAGMENT
|
||||
endif
|
||||
|
||||
endif
|
||||
3026
drivers/net/ethernet/realtek/r8126/r8126.h
Normal file
3026
drivers/net/ethernet/realtek/r8126/r8126.h
Normal file
File diff suppressed because it is too large
Load Diff
261
drivers/net/ethernet/realtek/r8126/r8126_dash.h
Normal file
261
drivers/net/ethernet/realtek/r8126/r8126_dash.h
Normal file
@@ -0,0 +1,261 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
################################################################################
|
||||
#
|
||||
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author:
|
||||
# Realtek NIC software team <nicfae@realtek.com>
|
||||
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
|
||||
#
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
/************************************************************************************
|
||||
* This product is covered by one or more of the following patents:
|
||||
* US6,570,884, US6,115,776, and US6,327,625.
|
||||
***********************************************************************************/
|
||||
|
||||
#ifndef _LINUX_R8126_DASH_H
|
||||
#define _LINUX_R8126_DASH_H
|
||||
|
||||
#include <linux/if.h>
|
||||
|
||||
#define SIOCDEVPRIVATE_RTLDASH SIOCDEVPRIVATE+2
|
||||
|
||||
enum rtl_dash_cmd {
|
||||
RTL_DASH_ARP_NS_OFFLOAD = 0,
|
||||
RTL_DASH_SET_OOB_IPMAC,
|
||||
RTL_DASH_NOTIFY_OOB,
|
||||
|
||||
RTL_DASH_SEND_BUFFER_DATA_TO_DASH_FW,
|
||||
RTL_DASH_CHECK_SEND_BUFFER_TO_DASH_FW_COMPLETE,
|
||||
RTL_DASH_GET_RCV_FROM_FW_BUFFER_DATA,
|
||||
RTL_DASH_OOB_REQ,
|
||||
RTL_DASH_OOB_ACK,
|
||||
RTL_DASH_DETACH_OOB_REQ,
|
||||
RTL_DASH_DETACH_OOB_ACK,
|
||||
|
||||
RTL_FW_SET_IPV4 = 0x10,
|
||||
RTL_FW_GET_IPV4,
|
||||
RTL_FW_SET_IPV6,
|
||||
RTL_FW_GET_IPV6,
|
||||
RTL_FW_SET_EXT_SNMP,
|
||||
RTL_FW_GET_EXT_SNMP,
|
||||
RTL_FW_SET_WAKEUP_PATTERN,
|
||||
RTL_FW_GET_WAKEUP_PATTERN,
|
||||
RTL_FW_DEL_WAKEUP_PATTERN,
|
||||
|
||||
RTLT_DASH_COMMAND_INVALID,
|
||||
};
|
||||
|
||||
struct rtl_dash_ip_mac {
|
||||
struct sockaddr ifru_addr;
|
||||
struct sockaddr ifru_netmask;
|
||||
struct sockaddr ifru_hwaddr;
|
||||
};
|
||||
|
||||
struct rtl_dash_ioctl_struct {
|
||||
__u32 cmd;
|
||||
__u32 offset;
|
||||
__u32 len;
|
||||
union {
|
||||
__u32 data;
|
||||
void *data_buffer;
|
||||
};
|
||||
};
|
||||
|
||||
struct settings_ipv4 {
|
||||
__u32 IPv4addr;
|
||||
__u32 IPv4mask;
|
||||
__u32 IPv4Gateway;
|
||||
};
|
||||
|
||||
struct settings_ipv6 {
|
||||
__u32 reserved;
|
||||
__u32 prefixLen;
|
||||
__u16 IPv6addr[8];
|
||||
__u16 IPv6Gateway[8];
|
||||
};
|
||||
|
||||
struct settings_ext_snmp {
|
||||
__u16 index;
|
||||
__u16 oid_get_len;
|
||||
__u8 oid_for_get[24];
|
||||
__u8 reserved0[26];
|
||||
__u16 value_len;
|
||||
__u8 value[256];
|
||||
__u8 supported;
|
||||
__u8 reserved1[27];
|
||||
};
|
||||
|
||||
struct wakeup_pattern {
|
||||
__u8 index;
|
||||
__u8 valid;
|
||||
__u8 start;
|
||||
__u8 length;
|
||||
__u8 name[36];
|
||||
__u8 mask[16];
|
||||
__u8 pattern[128];
|
||||
__u32 reserved[2];
|
||||
};
|
||||
|
||||
typedef struct _RX_DASH_FROM_FW_DESC {
|
||||
u16 length;
|
||||
u8 statusLowByte;
|
||||
u8 statusHighByte;
|
||||
u32 resv;
|
||||
u64 BufferAddress;
|
||||
}
|
||||
RX_DASH_FROM_FW_DESC, *PRX_DASH_FROM_FW_DESC;
|
||||
|
||||
typedef struct _TX_DASH_SEND_FW_DESC {
|
||||
u16 length;
|
||||
u8 statusLowByte;
|
||||
u8 statusHighByte;
|
||||
u32 resv;
|
||||
u64 BufferAddress;
|
||||
}
|
||||
TX_DASH_SEND_FW_DESC, *PTX_DASH_SEND_FW_DESC;
|
||||
|
||||
typedef struct _OSOOBHdr {
|
||||
u32 len;
|
||||
u8 type;
|
||||
u8 flag;
|
||||
u8 hostReqV;
|
||||
u8 res;
|
||||
}
|
||||
OSOOBHdr, *POSOOBHdr;
|
||||
|
||||
typedef struct _RX_DASH_BUFFER_TYPE_2 {
|
||||
OSOOBHdr oobhdr;
|
||||
u8 RxDataBuffer[0];
|
||||
}
|
||||
RX_DASH_BUFFER_TYPE_2, *PRX_DASH_BUFFER_TYPE_2;
|
||||
|
||||
#define ALIGN_8 (0x7)
|
||||
#define ALIGN_16 (0xf)
|
||||
#define ALIGN_32 (0x1f)
|
||||
#define ALIGN_64 (0x3f)
|
||||
#define ALIGN_256 (0xff)
|
||||
#define ALIGN_4096 (0xfff)
|
||||
|
||||
#define OCP_REG_CONFIG0 (0x10)
|
||||
#define OCP_REG_CONFIG0_REV_F (0xB8)
|
||||
#define OCP_REG_DASH_POLL (0x30)
|
||||
#define OCP_REG_HOST_REQ (0x34)
|
||||
#define OCP_REG_DASH_REQ (0x35)
|
||||
#define OCP_REG_CR (0x36)
|
||||
#define OCP_REG_DMEMSTA (0x38)
|
||||
#define OCP_REG_GPHYAR (0x60)
|
||||
|
||||
|
||||
#define OCP_REG_CONFIG0_DASHEN BIT_15
|
||||
#define OCP_REG_CONFIG0_OOBRESET BIT_14
|
||||
#define OCP_REG_CONFIG0_APRDY BIT_13
|
||||
#define OCP_REG_CONFIG0_FIRMWARERDY BIT_12
|
||||
#define OCP_REG_CONFIG0_DRIVERRDY BIT_11
|
||||
#define OCP_REG_CONFIG0_OOB_WDT BIT_9
|
||||
#define OCP_REG_CONFIG0_DRV_WAIT_OOB BIT_8
|
||||
#define OCP_REG_CONFIG0_TLSEN BIT_7
|
||||
|
||||
#define HW_DASH_SUPPORT_DASH(_M) ((_M)->HwSuppDashVer > 0)
|
||||
#define HW_DASH_SUPPORT_TYPE_1(_M) ((_M)->HwSuppDashVer == 1)
|
||||
#define HW_DASH_SUPPORT_TYPE_2(_M) ((_M)->HwSuppDashVer == 2)
|
||||
#define HW_DASH_SUPPORT_TYPE_3(_M) ((_M)->HwSuppDashVer == 3)
|
||||
|
||||
#define RECV_FROM_FW_BUF_SIZE (1520)
|
||||
#define SEND_TO_FW_BUF_SIZE (1520)
|
||||
|
||||
#define RX_DASH_FROM_FW_OWN BIT_15
|
||||
#define TX_DASH_SEND_FW_OWN BIT_15
|
||||
#define TX_DASH_SEND_FW_OWN_HIGHBYTE BIT_7
|
||||
|
||||
#define TXS_CC3_0 (BIT_0|BIT_1|BIT_2|BIT_3)
|
||||
#define TXS_EXC BIT_4
|
||||
#define TXS_LNKF BIT_5
|
||||
#define TXS_OWC BIT_6
|
||||
#define TXS_TES BIT_7
|
||||
#define TXS_UNF BIT_9
|
||||
#define TXS_LGSEN BIT_11
|
||||
#define TXS_LS BIT_12
|
||||
#define TXS_FS BIT_13
|
||||
#define TXS_EOR BIT_14
|
||||
#define TXS_OWN BIT_15
|
||||
|
||||
#define TPPool_HRDY 0x20
|
||||
|
||||
#define HostReqReg (0xC0)
|
||||
#define SystemMasterDescStartAddrLow (0xF0)
|
||||
#define SystemMasterDescStartAddrHigh (0xF4)
|
||||
#define SystemSlaveDescStartAddrLow (0xF8)
|
||||
#define SystemSlaveDescStartAddrHigh (0xFC)
|
||||
|
||||
//DASH Request Type
|
||||
#define WSMANREG 0x01
|
||||
#define OSPUSHDATA 0x02
|
||||
|
||||
#define RXS_OWN BIT_15
|
||||
#define RXS_EOR BIT_14
|
||||
#define RXS_FS BIT_13
|
||||
#define RXS_LS BIT_12
|
||||
|
||||
#define ISRIMR_DP_DASH_OK BIT_15
|
||||
#define ISRIMR_DP_HOST_OK BIT_13
|
||||
#define ISRIMR_DP_REQSYS_OK BIT_11
|
||||
|
||||
#define ISRIMR_DASH_INTR_EN BIT_12
|
||||
#define ISRIMR_DASH_INTR_CMAC_RESET BIT_15
|
||||
|
||||
#define ISRIMR_DASH_TYPE2_ROK BIT_0
|
||||
#define ISRIMR_DASH_TYPE2_RDU BIT_1
|
||||
#define ISRIMR_DASH_TYPE2_TOK BIT_2
|
||||
#define ISRIMR_DASH_TYPE2_TDU BIT_3
|
||||
#define ISRIMR_DASH_TYPE2_TX_FIFO_FULL BIT_4
|
||||
#define ISRIMR_DASH_TYPE2_TX_DISABLE_IDLE BIT_5
|
||||
#define ISRIMR_DASH_TYPE2_RX_DISABLE_IDLE BIT_6
|
||||
|
||||
#define CMAC_OOB_STOP 0x25
|
||||
#define CMAC_OOB_INIT 0x26
|
||||
#define CMAC_OOB_RESET 0x2a
|
||||
|
||||
#define NO_BASE_ADDRESS 0x00000000
|
||||
#define RTL8168FP_OOBMAC_BASE 0xBAF70000
|
||||
#define RTL8168FP_CMAC_IOBASE 0xBAF20000
|
||||
#define RTL8168FP_KVM_BASE 0xBAF80400
|
||||
#define CMAC_SYNC_REG 0x20
|
||||
#define CMAC_RXDESC_OFFSET 0x90 //RX: 0x90 - 0x98
|
||||
#define CMAC_TXDESC_OFFSET 0x98 //TX: 0x98 - 0x9F
|
||||
|
||||
/* cmac write/read MMIO register */
|
||||
#define RTL_CMAC_W8(tp, reg, val8) writeb ((val8), tp->cmac_ioaddr + (reg))
|
||||
#define RTL_CMAC_W16(tp, reg, val16) writew ((val16), tp->cmac_ioaddr + (reg))
|
||||
#define RTL_CMAC_W32(tp, reg, val32) writel ((val32), tp->cmac_ioaddr + (reg))
|
||||
#define RTL_CMAC_R8(tp, reg) readb (tp->cmac_ioaddr + (reg))
|
||||
#define RTL_CMAC_R16(tp, reg) readw (tp->cmac_ioaddr + (reg))
|
||||
#define RTL_CMAC_R32(tp, reg) ((unsigned long) readl (tp->cmac_ioaddr + (reg)))
|
||||
|
||||
int rtl8126_dash_ioctl(struct net_device *dev, struct ifreq *ifr);
|
||||
void HandleDashInterrupt(struct net_device *dev);
|
||||
int AllocateDashShareMemory(struct net_device *dev);
|
||||
void FreeAllocatedDashShareMemory(struct net_device *dev);
|
||||
void DashHwInit(struct net_device *dev);
|
||||
|
||||
|
||||
#endif /* _LINUX_R8126_DASH_H */
|
||||
16
drivers/net/ethernet/realtek/r8126/r8126_dummy.c
Normal file
16
drivers/net/ethernet/realtek/r8126/r8126_dummy.c
Normal file
@@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
/* Dummy implementation for module */
|
||||
static int __init r8126_dummy_dummy_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
device_initcall(r8126_dummy_dummy_init);
|
||||
|
||||
MODULE_AUTHOR("Revanth Kumar Uppala <ruppala@nvidia.com>");
|
||||
MODULE_DESCRIPTION("Dummy R8126 dummy driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
264
drivers/net/ethernet/realtek/r8126/r8126_firmware.c
Normal file
264
drivers/net/ethernet/realtek/r8126/r8126_firmware.c
Normal file
@@ -0,0 +1,264 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
################################################################################
|
||||
#
|
||||
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author:
|
||||
# Realtek NIC software team <nicfae@realtek.com>
|
||||
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
|
||||
#
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
/************************************************************************************
|
||||
* This product is covered by one or more of the following patents:
|
||||
* US6,570,884, US6,115,776, and US6,327,625.
|
||||
***********************************************************************************/
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/firmware.h>
|
||||
|
||||
#include "r8126_firmware.h"
|
||||
|
||||
enum rtl_fw_opcode {
|
||||
PHY_READ = 0x0,
|
||||
PHY_DATA_OR = 0x1,
|
||||
PHY_DATA_AND = 0x2,
|
||||
PHY_BJMPN = 0x3,
|
||||
PHY_MDIO_CHG = 0x4,
|
||||
PHY_CLEAR_READCOUNT = 0x7,
|
||||
PHY_WRITE = 0x8,
|
||||
PHY_READCOUNT_EQ_SKIP = 0x9,
|
||||
PHY_COMP_EQ_SKIPN = 0xa,
|
||||
PHY_COMP_NEQ_SKIPN = 0xb,
|
||||
PHY_WRITE_PREVIOUS = 0xc,
|
||||
PHY_SKIPN = 0xd,
|
||||
PHY_DELAY_MS = 0xe,
|
||||
};
|
||||
|
||||
struct fw_info {
|
||||
u32 magic;
|
||||
char version[RTL8126_VER_SIZE];
|
||||
__le32 fw_start;
|
||||
__le32 fw_len;
|
||||
u8 chksum;
|
||||
} __packed;
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,16,0)
|
||||
#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER))
|
||||
#endif
|
||||
#define FW_OPCODE_SIZE sizeof_field(struct rtl8126_fw_phy_action, code[0])
|
||||
|
||||
static bool rtl8126_fw_format_ok(struct rtl8126_fw *rtl_fw)
|
||||
{
|
||||
const struct firmware *fw = rtl_fw->fw;
|
||||
struct fw_info *fw_info = (struct fw_info *)fw->data;
|
||||
struct rtl8126_fw_phy_action *pa = &rtl_fw->phy_action;
|
||||
|
||||
if (fw->size < FW_OPCODE_SIZE)
|
||||
return false;
|
||||
|
||||
if (!fw_info->magic) {
|
||||
size_t i, size, start;
|
||||
u8 checksum = 0;
|
||||
|
||||
if (fw->size < sizeof(*fw_info))
|
||||
return false;
|
||||
|
||||
for (i = 0; i < fw->size; i++)
|
||||
checksum += fw->data[i];
|
||||
if (checksum != 0)
|
||||
return false;
|
||||
|
||||
start = le32_to_cpu(fw_info->fw_start);
|
||||
if (start > fw->size)
|
||||
return false;
|
||||
|
||||
size = le32_to_cpu(fw_info->fw_len);
|
||||
if (size > (fw->size - start) / FW_OPCODE_SIZE)
|
||||
return false;
|
||||
|
||||
strscpy(rtl_fw->version, fw_info->version, RTL8126_VER_SIZE);
|
||||
|
||||
pa->code = (__le32 *)(fw->data + start);
|
||||
pa->size = size;
|
||||
} else {
|
||||
if (fw->size % FW_OPCODE_SIZE)
|
||||
return false;
|
||||
|
||||
strscpy(rtl_fw->version, rtl_fw->fw_name, RTL8126_VER_SIZE);
|
||||
|
||||
pa->code = (__le32 *)fw->data;
|
||||
pa->size = fw->size / FW_OPCODE_SIZE;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rtl8126_fw_data_ok(struct rtl8126_fw *rtl_fw)
|
||||
{
|
||||
struct rtl8126_fw_phy_action *pa = &rtl_fw->phy_action;
|
||||
size_t index;
|
||||
|
||||
for (index = 0; index < pa->size; index++) {
|
||||
u32 action = le32_to_cpu(pa->code[index]);
|
||||
u32 val = action & 0x0000ffff;
|
||||
u32 regno = (action & 0x0fff0000) >> 16;
|
||||
|
||||
switch (action >> 28) {
|
||||
case PHY_READ:
|
||||
case PHY_DATA_OR:
|
||||
case PHY_DATA_AND:
|
||||
case PHY_CLEAR_READCOUNT:
|
||||
case PHY_WRITE:
|
||||
case PHY_WRITE_PREVIOUS:
|
||||
case PHY_DELAY_MS:
|
||||
break;
|
||||
|
||||
case PHY_MDIO_CHG:
|
||||
if (val > 1)
|
||||
goto out;
|
||||
break;
|
||||
|
||||
case PHY_BJMPN:
|
||||
if (regno > index)
|
||||
goto out;
|
||||
break;
|
||||
case PHY_READCOUNT_EQ_SKIP:
|
||||
if (index + 2 >= pa->size)
|
||||
goto out;
|
||||
break;
|
||||
case PHY_COMP_EQ_SKIPN:
|
||||
case PHY_COMP_NEQ_SKIPN:
|
||||
case PHY_SKIPN:
|
||||
if (index + 1 + regno >= pa->size)
|
||||
goto out;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(rtl_fw->dev, "Invalid action 0x%08x\n", action);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
out:
|
||||
dev_err(rtl_fw->dev, "Out of range of firmware\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
void rtl8126_fw_write_firmware(struct rtl8126_private *tp, struct rtl8126_fw *rtl_fw)
|
||||
{
|
||||
struct rtl8126_fw_phy_action *pa = &rtl_fw->phy_action;
|
||||
rtl8126_fw_write_t fw_write = rtl_fw->phy_write;
|
||||
rtl8126_fw_read_t fw_read = rtl_fw->phy_read;
|
||||
int predata = 0, count = 0;
|
||||
size_t index;
|
||||
|
||||
for (index = 0; index < pa->size; index++) {
|
||||
u32 action = le32_to_cpu(pa->code[index]);
|
||||
u32 data = action & 0x0000ffff;
|
||||
u32 regno = (action & 0x0fff0000) >> 16;
|
||||
enum rtl_fw_opcode opcode = action >> 28;
|
||||
|
||||
if (!action)
|
||||
break;
|
||||
|
||||
switch (opcode) {
|
||||
case PHY_READ:
|
||||
predata = fw_read(tp, regno);
|
||||
count++;
|
||||
break;
|
||||
case PHY_DATA_OR:
|
||||
predata |= data;
|
||||
break;
|
||||
case PHY_DATA_AND:
|
||||
predata &= data;
|
||||
break;
|
||||
case PHY_BJMPN:
|
||||
index -= (regno + 1);
|
||||
break;
|
||||
case PHY_MDIO_CHG:
|
||||
if (data) {
|
||||
fw_write = rtl_fw->mac_mcu_write;
|
||||
fw_read = rtl_fw->mac_mcu_read;
|
||||
} else {
|
||||
fw_write = rtl_fw->phy_write;
|
||||
fw_read = rtl_fw->phy_read;
|
||||
}
|
||||
|
||||
break;
|
||||
case PHY_CLEAR_READCOUNT:
|
||||
count = 0;
|
||||
break;
|
||||
case PHY_WRITE:
|
||||
fw_write(tp, regno, data);
|
||||
break;
|
||||
case PHY_READCOUNT_EQ_SKIP:
|
||||
if (count == data)
|
||||
index++;
|
||||
break;
|
||||
case PHY_COMP_EQ_SKIPN:
|
||||
if (predata == data)
|
||||
index += regno;
|
||||
break;
|
||||
case PHY_COMP_NEQ_SKIPN:
|
||||
if (predata != data)
|
||||
index += regno;
|
||||
break;
|
||||
case PHY_WRITE_PREVIOUS:
|
||||
fw_write(tp, regno, predata);
|
||||
break;
|
||||
case PHY_SKIPN:
|
||||
index += regno;
|
||||
break;
|
||||
case PHY_DELAY_MS:
|
||||
mdelay(data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void rtl8126_fw_release_firmware(struct rtl8126_fw *rtl_fw)
|
||||
{
|
||||
release_firmware(rtl_fw->fw);
|
||||
}
|
||||
|
||||
int rtl8126_fw_request_firmware(struct rtl8126_fw *rtl_fw)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
||||
if (!rtl8126_fw_format_ok(rtl_fw) || !rtl8126_fw_data_ok(rtl_fw)) {
|
||||
release_firmware(rtl_fw->fw);
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
out:
|
||||
dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n",
|
||||
rtl_fw->fw_name, rc);
|
||||
return rc;
|
||||
}
|
||||
68
drivers/net/ethernet/realtek/r8126/r8126_firmware.h
Normal file
68
drivers/net/ethernet/realtek/r8126/r8126_firmware.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
################################################################################
|
||||
#
|
||||
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author:
|
||||
# Realtek NIC software team <nicfae@realtek.com>
|
||||
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
|
||||
#
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
/************************************************************************************
|
||||
* This product is covered by one or more of the following patents:
|
||||
* US6,570,884, US6,115,776, and US6,327,625.
|
||||
***********************************************************************************/
|
||||
|
||||
#ifndef _LINUX_R8126_FIRMWARE_H
|
||||
#define _LINUX_R8126_FIRMWARE_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/firmware.h>
|
||||
|
||||
struct rtl8126_private;
|
||||
typedef void (*rtl8126_fw_write_t)(struct rtl8126_private *tp, u16 reg, u16 val);
|
||||
typedef u32 (*rtl8126_fw_read_t)(struct rtl8126_private *tp, u16 reg);
|
||||
|
||||
#define RTL8126_VER_SIZE 32
|
||||
|
||||
struct rtl8126_fw {
|
||||
rtl8126_fw_write_t phy_write;
|
||||
rtl8126_fw_read_t phy_read;
|
||||
rtl8126_fw_write_t mac_mcu_write;
|
||||
rtl8126_fw_read_t mac_mcu_read;
|
||||
const struct firmware *fw;
|
||||
const char *fw_name;
|
||||
struct device *dev;
|
||||
|
||||
char version[RTL8126_VER_SIZE];
|
||||
|
||||
struct rtl8126_fw_phy_action {
|
||||
__le32 *code;
|
||||
size_t size;
|
||||
} phy_action;
|
||||
};
|
||||
|
||||
int rtl8126_fw_request_firmware(struct rtl8126_fw *rtl_fw);
|
||||
void rtl8126_fw_release_firmware(struct rtl8126_fw *rtl_fw);
|
||||
void rtl8126_fw_write_firmware(struct rtl8126_private *tp, struct rtl8126_fw *rtl_fw);
|
||||
|
||||
#endif /* _LINUX_R8126_FIRMWARE_H */
|
||||
18029
drivers/net/ethernet/realtek/r8126/r8126_n.c
Normal file
18029
drivers/net/ethernet/realtek/r8126/r8126_n.c
Normal file
File diff suppressed because it is too large
Load Diff
892
drivers/net/ethernet/realtek/r8126/r8126_ptp.c
Normal file
892
drivers/net/ethernet/realtek/r8126/r8126_ptp.c
Normal file
@@ -0,0 +1,892 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
################################################################################
|
||||
#
|
||||
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author:
|
||||
# Realtek NIC software team <nicfae@realtek.com>
|
||||
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
|
||||
#
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
/************************************************************************************
|
||||
* This product is covered by one or more of the following patents:
|
||||
* US6,570,884, US6,115,776, and US6,327,625.
|
||||
***********************************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
#include "r8126.h"
|
||||
#include "r8126_ptp.h"
|
||||
|
||||
static void rtl8126_wait_clkadj_ready(struct rtl8126_private *tp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < R8126_CHANNEL_WAIT_COUNT; i++)
|
||||
if (!(rtl8126_mdio_direct_read_phy_ocp(tp, PTP_CLK_CFG_8126) & CLKADJ_MODE_SET))
|
||||
break;
|
||||
}
|
||||
|
||||
static void rtl8126_set_clkadj_mode(struct rtl8126_private *tp, u16 cmd)
|
||||
{
|
||||
rtl8126_clear_and_set_eth_phy_ocp_bit(tp,
|
||||
PTP_CLK_CFG_8126,
|
||||
BIT_3 | BIT_2 | BIT_1,
|
||||
CLKADJ_MODE_SET | cmd);
|
||||
|
||||
rtl8126_wait_clkadj_ready(tp);
|
||||
}
|
||||
|
||||
static int _rtl8126_phc_gettime(struct rtl8126_private *tp, struct timespec64 *ts64)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&tp->phy_lock, flags);
|
||||
|
||||
//Direct Read
|
||||
rtl8126_set_clkadj_mode(tp, DIRECT_READ);
|
||||
|
||||
/* nanoseconds */
|
||||
//Ns[29:16] E414[13:0]
|
||||
ts64->tv_nsec = rtl8126_mdio_direct_read_phy_ocp(tp, PTP_CFG_NS_HI_8126) & 0x3fff;
|
||||
ts64->tv_nsec <<= 16;
|
||||
//Ns[15:0] E412[15:0]
|
||||
ts64->tv_nsec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_CFG_NS_LO_8126);
|
||||
|
||||
|
||||
/* seconds */
|
||||
//S[47:32] E41A[15:0]
|
||||
ts64->tv_sec = rtl8126_mdio_direct_read_phy_ocp(tp, PTP_CFG_S_HI_8126);
|
||||
ts64->tv_sec <<= 16;
|
||||
//S[31:16] E418[15:0]
|
||||
ts64->tv_sec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_CFG_S_MI_8126);
|
||||
ts64->tv_sec <<= 16;
|
||||
//S[15:0] E416[15:0]
|
||||
ts64->tv_sec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_CFG_S_LO_8126);
|
||||
|
||||
spin_unlock_irqrestore(&tp->phy_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _rtl8126_phc_settime(struct rtl8126_private *tp, const struct timespec64 *ts64)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&tp->phy_lock, flags);
|
||||
|
||||
/* nanoseconds */
|
||||
//Ns[15:0] E412[15:0]
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_NS_LO_8126, ts64->tv_nsec);
|
||||
//Ns[29:16] E414[13:0]
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_NS_HI_8126, (ts64->tv_nsec & 0x3fff0000) >> 16);
|
||||
|
||||
/* seconds */
|
||||
//S[15:0] E416[15:0]
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_S_LO_8126, ts64->tv_sec);
|
||||
//S[31:16] E418[15:0]
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_S_MI_8126, (ts64->tv_sec >> 16));
|
||||
//S[47:32] E41A[15:0]
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_S_HI_8126, (ts64->tv_sec >> 32));
|
||||
|
||||
//Direct Write
|
||||
rtl8126_set_clkadj_mode(tp, DIRECT_WRITE);
|
||||
|
||||
spin_unlock_irqrestore(&tp->phy_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _rtl8126_phc_adjtime(struct rtl8126_private *tp, s64 delta)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct timespec64 d;
|
||||
bool negative;
|
||||
u64 tohw;
|
||||
u32 nsec;
|
||||
u64 sec;
|
||||
|
||||
if (delta < 0) {
|
||||
negative = true;
|
||||
tohw = -delta;
|
||||
} else {
|
||||
negative = false;
|
||||
tohw = delta;
|
||||
}
|
||||
|
||||
d = ns_to_timespec64(tohw);
|
||||
|
||||
nsec = d.tv_nsec;
|
||||
sec = d.tv_sec;
|
||||
|
||||
nsec &= 0x3fffffff;
|
||||
sec &= 0x0000ffffffffffff;
|
||||
|
||||
spin_lock_irqsave(&tp->phy_lock, flags);
|
||||
|
||||
/* nanoseconds */
|
||||
//Ns[15:0] E412[15:0]
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_NS_LO_8126, nsec);
|
||||
//Ns[29:16] E414[13:0]
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_NS_HI_8126, (nsec >> 16));
|
||||
|
||||
/* seconds */
|
||||
//S[15:0] E416[15:0]
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_S_LO_8126, sec);
|
||||
//S[31:16] E418[15:0]
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_S_MI_8126, (sec >> 16));
|
||||
//S[47:32] E41A[15:0]
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_S_HI_8126, (sec >> 32));
|
||||
|
||||
if (negative)
|
||||
rtl8126_set_clkadj_mode(tp, DECREMENT_STEP);
|
||||
else
|
||||
rtl8126_set_clkadj_mode(tp, INCREMENT_STEP);
|
||||
|
||||
spin_unlock_irqrestore(&tp->phy_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtl8126_phc_adjtime(struct ptp_clock_info *ptp, s64 delta)
|
||||
{
|
||||
struct rtl8126_private *tp = container_of(ptp, struct rtl8126_private, ptp_clock_info);
|
||||
int ret;
|
||||
|
||||
//netif_info(tp, drv, tp->dev, "phc adjust time\n");
|
||||
|
||||
ret = _rtl8126_phc_adjtime(tp, delta);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* delta = delta * 10^6 ppm = delta * 10^9 ppb (in this equation ppm and ppb are not variable)
|
||||
*
|
||||
* in adjfreq ppb is a variable
|
||||
* ppb = delta * 10^9
|
||||
* delta = ppb / 10^9
|
||||
* rate_value = |delta| * 2^32 = |ppb| / 10^9 * 2^32 = (|ppb| << 32) / 10^9
|
||||
*/
|
||||
static int _rtl8126_phc_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
|
||||
{
|
||||
struct rtl8126_private *tp = container_of(ptp, struct rtl8126_private, ptp_clock_info);
|
||||
unsigned long flags;
|
||||
u32 rate_value;
|
||||
|
||||
if (ppb < 0) {
|
||||
rate_value = ((u64)-ppb << 32) / 1000000000;
|
||||
rate_value = ~rate_value + 1;
|
||||
} else
|
||||
rate_value = ((u64)ppb << 32) / 1000000000;
|
||||
|
||||
spin_lock_irqsave(&tp->phy_lock, flags);
|
||||
|
||||
/* nanoseconds */
|
||||
//Ns[15:0] E412[15:0]
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_NS_LO_8126, rate_value);
|
||||
//Ns[22:16] E414[13:0]
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CFG_NS_HI_8126, (rate_value & 0x003f0000) >> 16);
|
||||
|
||||
rtl8126_set_clkadj_mode(tp, RATE_WRITE);
|
||||
|
||||
spin_unlock_irqrestore(&tp->phy_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,2,0)
|
||||
static int rtl8126_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
|
||||
{
|
||||
s32 ppb = scaled_ppm_to_ppb(scaled_ppm);
|
||||
|
||||
if (ppb > ptp->max_adj || ppb < -ptp->max_adj)
|
||||
return -EINVAL;
|
||||
|
||||
_rtl8126_phc_adjfreq(ptp, ppb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
static int rtl8126_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
|
||||
{
|
||||
//struct rtl8126_private *tp = container_of(ptp, struct rtl8126_private, ptp_clock_info);
|
||||
|
||||
//netif_info(tp, drv, tp->dev, "phc adjust freq\n");
|
||||
|
||||
if (delta > ptp->max_adj || delta < -ptp->max_adj)
|
||||
return -EINVAL;
|
||||
|
||||
_rtl8126_phc_adjfreq(ptp, delta);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6,2,0) */
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)
|
||||
static int rtl8126_phc_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts64,
|
||||
struct ptp_system_timestamp *sts)
|
||||
{
|
||||
struct rtl8126_private *tp = container_of(ptp, struct rtl8126_private, ptp_clock_info);
|
||||
int ret;
|
||||
|
||||
//netif_info(tp, drv, tp->dev, "phc get ts\n");
|
||||
|
||||
ptp_read_system_prets(sts);
|
||||
ret = _rtl8126_phc_gettime(tp, ts64);
|
||||
ptp_read_system_postts(sts);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static int rtl8126_phc_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts64)
|
||||
{
|
||||
struct rtl8126_private *tp = container_of(ptp, struct rtl8126_private, ptp_clock_info);
|
||||
int ret;
|
||||
|
||||
//netif_info(tp, drv, tp->dev, "phc get ts\n");
|
||||
|
||||
ret = _rtl8126_phc_gettime(tp, ts64);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0) */
|
||||
|
||||
static int rtl8126_phc_settime(struct ptp_clock_info *ptp,
|
||||
const struct timespec64 *ts64)
|
||||
{
|
||||
struct rtl8126_private *tp = container_of(ptp, struct rtl8126_private, ptp_clock_info);
|
||||
int ret;
|
||||
|
||||
//netif_info(tp, drv, tp->dev, "phc set ts\n");
|
||||
|
||||
ret = _rtl8126_phc_settime(tp, ts64);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void _rtl8126_phc_enable(struct ptp_clock_info *ptp,
|
||||
struct ptp_clock_request *rq, int on)
|
||||
{
|
||||
struct rtl8126_private *tp = container_of(ptp, struct rtl8126_private, ptp_clock_info);
|
||||
unsigned long flags;
|
||||
u16 phy_ocp_data;
|
||||
|
||||
if (on) {
|
||||
tp->pps_enable = 1;
|
||||
rtl8126_clear_mac_ocp_bit(tp, 0xDC00, BIT_6);
|
||||
rtl8126_clear_mac_ocp_bit(tp, 0xDC20, BIT_1);
|
||||
|
||||
spin_lock_irqsave(&tp->phy_lock, flags);
|
||||
|
||||
/* Set periodic pulse 1pps */
|
||||
/* E432[8:0] = 0x017d */
|
||||
phy_ocp_data = rtl8126_mdio_direct_read_phy_ocp(tp, 0xE432);
|
||||
phy_ocp_data &= 0xFE00;
|
||||
phy_ocp_data |= 0x017d;
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, 0xE432, phy_ocp_data);
|
||||
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, 0xE434, 0x7840);
|
||||
|
||||
/* E436[8:0] = 0xbe */
|
||||
phy_ocp_data = rtl8126_mdio_direct_read_phy_ocp(tp, 0xE436);
|
||||
phy_ocp_data &= 0xFE00;
|
||||
phy_ocp_data |= 0xbe;
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, 0xE436, phy_ocp_data);
|
||||
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, 0xE438, 0xbc20);
|
||||
|
||||
spin_unlock_irqrestore(&tp->phy_lock, flags);
|
||||
|
||||
/* start hrtimer */
|
||||
hrtimer_start(&tp->pps_timer, 1000000000, HRTIMER_MODE_REL);
|
||||
} else
|
||||
tp->pps_enable = 0;
|
||||
}
|
||||
|
||||
static int rtl8126_phc_enable(struct ptp_clock_info *ptp,
|
||||
struct ptp_clock_request *rq, int on)
|
||||
{
|
||||
switch (rq->type) {
|
||||
case PTP_CLK_REQ_PPS:
|
||||
_rtl8126_phc_enable(ptp, rq, on);
|
||||
return 0;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static void rtl8126_ptp_enable_config(struct rtl8126_private *tp)
|
||||
{
|
||||
u16 ptp_ctrl;
|
||||
|
||||
if (tp->syncE_en)
|
||||
rtl8126_set_eth_phy_ocp_bit(tp, PTP_SYNCE_CTL, BIT_0);
|
||||
else
|
||||
rtl8126_clear_eth_phy_ocp_bit(tp, PTP_SYNCE_CTL, BIT_0);
|
||||
|
||||
ptp_ctrl = BIT_0 | BIT_1 | BIT_2 | BIT_3 | BIT_4 | BIT_5 | BIT_6 | BIT_7 | BIT_12;
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_CTL, ptp_ctrl);
|
||||
|
||||
rtl8126_set_eth_phy_ocp_bit(tp, 0xA640, BIT_15);
|
||||
}
|
||||
|
||||
int rtl8126_get_ts_info(struct net_device *netdev,
|
||||
struct ethtool_ts_info *info)
|
||||
{
|
||||
struct rtl8126_private *tp = netdev_priv(netdev);
|
||||
|
||||
/* we always support timestamping disabled */
|
||||
info->rx_filters = BIT(HWTSTAMP_FILTER_NONE);
|
||||
|
||||
if (tp->HwSuppPtpVer == 0)
|
||||
return ethtool_op_get_ts_info(netdev, info);
|
||||
|
||||
info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_RX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_SOFTWARE |
|
||||
SOF_TIMESTAMPING_TX_HARDWARE |
|
||||
SOF_TIMESTAMPING_RX_HARDWARE |
|
||||
SOF_TIMESTAMPING_RAW_HARDWARE;
|
||||
|
||||
if (tp->ptp_clock)
|
||||
info->phc_index = ptp_clock_index(tp->ptp_clock);
|
||||
else
|
||||
info->phc_index = -1;
|
||||
|
||||
info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON);
|
||||
|
||||
info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
|
||||
BIT(HWTSTAMP_FILTER_PTP_V2_EVENT) |
|
||||
BIT(HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
|
||||
BIT(HWTSTAMP_FILTER_PTP_V2_SYNC) |
|
||||
BIT(HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
|
||||
BIT(HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) |
|
||||
BIT(HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ptp_clock_info rtl_ptp_clock_info = {
|
||||
.owner = THIS_MODULE,
|
||||
.n_alarm = 0,
|
||||
.n_ext_ts = 0,
|
||||
.n_per_out = 0,
|
||||
.n_pins = 0,
|
||||
.pps = 1,
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,2,0)
|
||||
.adjfine = rtl8126_ptp_adjfine,
|
||||
#else
|
||||
.adjfreq = rtl8126_phc_adjfreq,
|
||||
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6,2,0) */
|
||||
.adjtime = rtl8126_phc_adjtime,
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0)
|
||||
.gettimex64 = rtl8126_phc_gettime,
|
||||
#else
|
||||
.gettime64 = rtl8126_phc_gettime,
|
||||
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5,0,0) */
|
||||
|
||||
.settime64 = rtl8126_phc_settime,
|
||||
.enable = rtl8126_phc_enable,
|
||||
};
|
||||
|
||||
static u16 rtl8126_ptp_get_tx_msgtype(struct rtl8126_private *tp)
|
||||
{
|
||||
u16 tx_ts_ready = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < R8126_CHANNEL_WAIT_COUNT; i++) {
|
||||
tx_ts_ready = rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_STA) & 0xF000;
|
||||
if (tx_ts_ready)
|
||||
break;
|
||||
}
|
||||
|
||||
switch (tx_ts_ready) {
|
||||
case TX_TS_PDLYRSP_RDY:
|
||||
return 3;
|
||||
case TX_TS_PDLYREQ_RDY:
|
||||
return 2;
|
||||
case TX_TS_DLYREQ_RDY:
|
||||
return 1;
|
||||
case TX_TS_SYNC_RDY:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static u16 rtl8126_ptp_get_rx_msgtype(struct rtl8126_private *tp)
|
||||
{
|
||||
u16 rx_ts_ready = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < R8126_CHANNEL_WAIT_COUNT; i++) {
|
||||
rx_ts_ready = rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_STA) & 0x0F00;
|
||||
if (rx_ts_ready)
|
||||
break;
|
||||
}
|
||||
|
||||
switch (rx_ts_ready) {
|
||||
case RX_TS_PDLYRSP_RDY:
|
||||
return 3;
|
||||
case RX_TS_PDLYREQ_RDY:
|
||||
return 2;
|
||||
case RX_TS_DLYREQ_RDY:
|
||||
return 1;
|
||||
case RX_TS_SYNC_RDY:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void rtl8126_wait_trx_ts_ready(struct rtl8126_private *tp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < R8126_CHANNEL_WAIT_COUNT; i++)
|
||||
if (!(rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_STA) & TRX_TS_RD))
|
||||
break;
|
||||
}
|
||||
|
||||
static void rtl8126_set_trx_ts_cmd(struct rtl8126_private *tp, u16 cmd)
|
||||
{
|
||||
rtl8126_clear_and_set_eth_phy_ocp_bit(tp,
|
||||
PTP_TRX_TS_STA,
|
||||
TRXTS_SEL | BIT_3 | BIT_2,
|
||||
TRX_TS_RD | cmd);
|
||||
|
||||
rtl8126_wait_trx_ts_ready(tp);
|
||||
}
|
||||
|
||||
static void rtl8126_ptp_egresstime(struct rtl8126_private *tp, struct timespec64 *ts64)
|
||||
{
|
||||
u16 msgtype;
|
||||
|
||||
msgtype = rtl8126_ptp_get_tx_msgtype(tp);
|
||||
|
||||
msgtype <<= 2;
|
||||
|
||||
rtl8126_set_trx_ts_cmd(tp, (msgtype | BIT_4));
|
||||
|
||||
/* nanoseconds */
|
||||
//Ns[29:16] E448[13:0]
|
||||
ts64->tv_nsec = rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_NS_HI) & 0x3fff;
|
||||
ts64->tv_nsec <<= 16;
|
||||
//Ns[15:0] E446[15:0]
|
||||
ts64->tv_nsec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_NS_LO);
|
||||
|
||||
/* seconds */
|
||||
//S[47:32] E44E[15:0]
|
||||
ts64->tv_sec = rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_S_HI);
|
||||
ts64->tv_sec <<= 16;
|
||||
//S[31:16] E44C[15:0]
|
||||
ts64->tv_sec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_S_MI);
|
||||
ts64->tv_sec <<= 16;
|
||||
//S[15:0] E44A[15:0]
|
||||
ts64->tv_sec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_S_LO);
|
||||
}
|
||||
|
||||
static void rtl8126_ptp_ingresstime(struct rtl8126_private *tp, struct timespec64 *ts64)
|
||||
{
|
||||
u16 msgtype;
|
||||
|
||||
msgtype = rtl8126_ptp_get_rx_msgtype(tp);
|
||||
|
||||
msgtype <<= 2;
|
||||
|
||||
rtl8126_set_trx_ts_cmd(tp, (TRXTS_SEL | msgtype | BIT_4));
|
||||
|
||||
/* nanoseconds */
|
||||
//Ns[29:16] E448[13:0]
|
||||
ts64->tv_nsec = rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_NS_HI) & 0x3fff;
|
||||
ts64->tv_nsec <<= 16;
|
||||
//Ns[15:0] E446[15:0]
|
||||
ts64->tv_nsec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_NS_LO);
|
||||
|
||||
/* seconds */
|
||||
//S[47:32] E44E[15:0]
|
||||
ts64->tv_sec = rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_S_HI);
|
||||
ts64->tv_sec <<= 16;
|
||||
//S[31:16] E44C[15:0]
|
||||
ts64->tv_sec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_S_MI);
|
||||
ts64->tv_sec <<= 16;
|
||||
//S[15:0] E44A[15:0]
|
||||
ts64->tv_sec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_TRX_TS_S_LO);
|
||||
}
|
||||
|
||||
static void rtl8126_ptp_tx_hwtstamp(struct rtl8126_private *tp)
|
||||
{
|
||||
struct sk_buff *skb = tp->ptp_tx_skb;
|
||||
struct skb_shared_hwtstamps shhwtstamps = { 0 };
|
||||
struct timespec64 ts64;
|
||||
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_INSR, TX_TX_INTR);
|
||||
|
||||
rtl8126_ptp_egresstime(tp, &ts64);
|
||||
|
||||
/* Upper 32 bits contain s, lower 32 bits contain ns. */
|
||||
shhwtstamps.hwtstamp = ktime_set(ts64.tv_sec,
|
||||
ts64.tv_nsec);
|
||||
|
||||
/* Clear the lock early before calling skb_tstamp_tx so that
|
||||
* applications are not woken up before the lock bit is clear. We use
|
||||
* a copy of the skb pointer to ensure other threads can't change it
|
||||
* while we're notifying the stack.
|
||||
*/
|
||||
tp->ptp_tx_skb = NULL;
|
||||
clear_bit_unlock(__RTL8126_PTP_TX_IN_PROGRESS, &tp->state);
|
||||
|
||||
/* Notify the stack and free the skb after we've unlocked */
|
||||
skb_tstamp_tx(skb, &shhwtstamps);
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
|
||||
#define RTL8126_PTP_TX_TIMEOUT (HZ * 15)
|
||||
static void rtl8126_ptp_tx_work(struct work_struct *work)
|
||||
{
|
||||
struct rtl8126_private *tp = container_of(work, struct rtl8126_private,
|
||||
ptp_tx_work);
|
||||
unsigned long flags;
|
||||
|
||||
if (!tp->ptp_tx_skb)
|
||||
return;
|
||||
|
||||
if (time_is_before_jiffies(tp->ptp_tx_start +
|
||||
RTL8126_PTP_TX_TIMEOUT)) {
|
||||
dev_kfree_skb_any(tp->ptp_tx_skb);
|
||||
tp->ptp_tx_skb = NULL;
|
||||
clear_bit_unlock(__RTL8126_PTP_TX_IN_PROGRESS, &tp->state);
|
||||
tp->tx_hwtstamp_timeouts++;
|
||||
/* Clear the tx valid bit in TSYNCTXCTL register to enable
|
||||
* interrupt
|
||||
*/
|
||||
spin_lock_irqsave(&tp->phy_lock, flags);
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_INSR, TX_TX_INTR);
|
||||
spin_unlock_irqrestore(&tp->phy_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&tp->phy_lock, flags);
|
||||
if (rtl8126_mdio_direct_read_phy_ocp(tp, PTP_INSR) & TX_TX_INTR) {
|
||||
rtl8126_ptp_tx_hwtstamp(tp);
|
||||
spin_unlock_irqrestore(&tp->phy_lock, flags);
|
||||
} else {
|
||||
spin_unlock_irqrestore(&tp->phy_lock, flags);
|
||||
/* reschedule to check later */
|
||||
schedule_work(&tp->ptp_tx_work);
|
||||
}
|
||||
}
|
||||
|
||||
static int rtl8126_hwtstamp_enable(struct rtl8126_private *tp, bool enable)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&tp->phy_lock, flags);
|
||||
|
||||
if (enable) {
|
||||
//trx timestamp interrupt enable
|
||||
rtl8126_set_eth_phy_ocp_bit(tp, PTP_INER, BIT_2 | BIT_3);
|
||||
|
||||
//set isr clear mode
|
||||
rtl8126_set_eth_phy_ocp_bit(tp, PTP_GEN_CFG, BIT_0);
|
||||
|
||||
//clear ptp isr
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_INSR, 0xFFFF);
|
||||
|
||||
//enable ptp
|
||||
rtl8126_ptp_enable_config(tp);
|
||||
|
||||
//rtl8126_set_local_time(tp);
|
||||
} else {
|
||||
/* trx timestamp interrupt disable */
|
||||
rtl8126_clear_eth_phy_ocp_bit(tp, PTP_INER, BIT_2 | BIT_3);
|
||||
|
||||
/* disable ptp */
|
||||
rtl8126_clear_eth_phy_ocp_bit(tp, PTP_SYNCE_CTL, BIT_0);
|
||||
rtl8126_clear_eth_phy_ocp_bit(tp, PTP_CTL, BIT_0);
|
||||
rtl8126_set_eth_phy_ocp_bit(tp, 0xA640, BIT_15);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&tp->phy_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rtl8126_set_local_time(struct rtl8126_private *tp)
|
||||
{
|
||||
struct timespec64 ts64;
|
||||
//set system time
|
||||
ktime_get_real_ts64(&ts64);
|
||||
_rtl8126_phc_settime(tp, &ts64);
|
||||
}
|
||||
|
||||
static long rtl8126_ptp_create_clock(struct rtl8126_private *tp)
|
||||
{
|
||||
struct net_device *netdev = tp->dev;
|
||||
long err;
|
||||
|
||||
if (!IS_ERR_OR_NULL(tp->ptp_clock))
|
||||
return 0;
|
||||
|
||||
if (tp->HwSuppPtpVer == 0) {
|
||||
tp->ptp_clock = NULL;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
tp->ptp_clock_info = rtl_ptp_clock_info;
|
||||
tp->ptp_clock_info.max_adj = 488281;//0x1FFFFF * 10^9 / 2^32
|
||||
|
||||
snprintf(tp->ptp_clock_info.name, sizeof(tp->ptp_clock_info.name),
|
||||
"%pm", tp->dev->dev_addr);
|
||||
tp->ptp_clock = ptp_clock_register(&tp->ptp_clock_info, &tp->pci_dev->dev);
|
||||
if (IS_ERR(tp->ptp_clock)) {
|
||||
err = PTR_ERR(tp->ptp_clock);
|
||||
tp->ptp_clock = NULL;
|
||||
netif_err(tp, drv, tp->dev, "ptp_clock_register failed\n");
|
||||
return err;
|
||||
} else
|
||||
netif_info(tp, drv, tp->dev, "registered PHC device on %s\n", netdev->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum hrtimer_restart
|
||||
rtl8126_hrtimer_for_pps(struct hrtimer *timer) {
|
||||
struct rtl8126_private *tp = container_of(timer, struct rtl8126_private, pps_timer);
|
||||
u16 tai_cfg = BIT_8 | BIT_3 | BIT_1 | BIT_0;
|
||||
s64 pps_sec;
|
||||
|
||||
if (tp->pps_enable)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&tp->phy_lock, flags);
|
||||
|
||||
//Direct Read
|
||||
rtl8126_set_clkadj_mode(tp, DIRECT_READ);
|
||||
|
||||
pps_sec = rtl8126_mdio_direct_read_phy_ocp(tp, PTP_CFG_S_HI_8126);
|
||||
pps_sec <<= 16;
|
||||
pps_sec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_CFG_S_MI_8126);
|
||||
pps_sec <<= 16;
|
||||
pps_sec |= rtl8126_mdio_direct_read_phy_ocp(tp, PTP_CFG_S_LO_8126);
|
||||
pps_sec++;
|
||||
|
||||
//E42A[15:0]
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_TAI_TS_S_LO, pps_sec & 0xffff);
|
||||
//E42C[31:16]
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_TAI_TS_S_HI, (pps_sec & 0xffff0000) >> 16);
|
||||
//Periodic Tai start
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_TAI_CFG, tai_cfg);
|
||||
|
||||
spin_unlock_irqrestore(&tp->phy_lock, flags);
|
||||
|
||||
hrtimer_forward_now(&tp->pps_timer, 1000000000); //rekick
|
||||
return HRTIMER_RESTART;
|
||||
} else
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
void rtl8126_ptp_reset(struct rtl8126_private *tp)
|
||||
{
|
||||
if (!tp->ptp_clock)
|
||||
return;
|
||||
|
||||
netif_info(tp, drv, tp->dev, "reset PHC clock\n");
|
||||
|
||||
rtl8126_hwtstamp_enable(tp, false);
|
||||
}
|
||||
|
||||
void rtl8126_ptp_init(struct rtl8126_private *tp)
|
||||
{
|
||||
/* obtain a PTP device, or re-use an existing device */
|
||||
if (rtl8126_ptp_create_clock(tp))
|
||||
return;
|
||||
|
||||
/* we have a clock so we can initialize work now */
|
||||
INIT_WORK(&tp->ptp_tx_work, rtl8126_ptp_tx_work);
|
||||
|
||||
/* init a hrtimer for pps */
|
||||
tp->pps_enable = 0;
|
||||
hrtimer_init(&tp->pps_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
tp->pps_timer.function = rtl8126_hrtimer_for_pps;
|
||||
|
||||
/* reset the PTP related hardware bits */
|
||||
rtl8126_ptp_reset(tp);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void rtl8126_ptp_suspend(struct rtl8126_private *tp)
|
||||
{
|
||||
if (!tp->ptp_clock)
|
||||
return;
|
||||
|
||||
netif_info(tp, drv, tp->dev, "suspend PHC clock\n");
|
||||
|
||||
rtl8126_hwtstamp_enable(tp, false);
|
||||
|
||||
/* ensure that we cancel any pending PTP Tx work item in progress */
|
||||
cancel_work_sync(&tp->ptp_tx_work);
|
||||
|
||||
hrtimer_cancel(&tp->pps_timer);
|
||||
}
|
||||
|
||||
void rtl8126_ptp_stop(struct rtl8126_private *tp)
|
||||
{
|
||||
struct net_device *netdev = tp->dev;
|
||||
|
||||
netif_info(tp, drv, tp->dev, "stop PHC clock\n");
|
||||
|
||||
/* first, suspend PTP activity */
|
||||
rtl8126_ptp_suspend(tp);
|
||||
|
||||
/* disable the PTP clock device */
|
||||
if (tp->ptp_clock) {
|
||||
ptp_clock_unregister(tp->ptp_clock);
|
||||
tp->ptp_clock = NULL;
|
||||
netif_info(tp, drv, tp->dev, "removed PHC on %s\n",
|
||||
netdev->name);
|
||||
}
|
||||
}
|
||||
|
||||
static int rtl8126_set_tstamp(struct net_device *netdev, struct ifreq *ifr)
|
||||
{
|
||||
struct rtl8126_private *tp = netdev_priv(netdev);
|
||||
struct hwtstamp_config config;
|
||||
bool hwtstamp = 0;
|
||||
|
||||
//netif_info(tp, drv, tp->dev, "ptp set ts\n");
|
||||
|
||||
if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
|
||||
return -EFAULT;
|
||||
|
||||
if (config.flags)
|
||||
return -EINVAL;
|
||||
|
||||
switch (config.tx_type) {
|
||||
case HWTSTAMP_TX_ON:
|
||||
hwtstamp = 1;
|
||||
break;
|
||||
case HWTSTAMP_TX_OFF:
|
||||
break;
|
||||
case HWTSTAMP_TX_ONESTEP_SYNC:
|
||||
default:
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
switch (config.rx_filter) {
|
||||
case HWTSTAMP_FILTER_PTP_V2_EVENT:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
|
||||
case HWTSTAMP_FILTER_PTP_V2_SYNC:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
|
||||
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
|
||||
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
|
||||
config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
|
||||
hwtstamp = 1;
|
||||
tp->flags |= RTL_FLAG_RX_HWTSTAMP_ENABLED;
|
||||
break;
|
||||
case HWTSTAMP_FILTER_NONE:
|
||||
tp->flags &= ~RTL_FLAG_RX_HWTSTAMP_ENABLED;
|
||||
break;
|
||||
default:
|
||||
tp->flags &= ~RTL_FLAG_RX_HWTSTAMP_ENABLED;
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
if (tp->hwtstamp_config.tx_type != config.tx_type ||
|
||||
tp->hwtstamp_config.rx_filter != config.rx_filter) {
|
||||
tp->hwtstamp_config = config;
|
||||
|
||||
rtl8126_hwtstamp_enable(tp, hwtstamp);
|
||||
}
|
||||
|
||||
return copy_to_user(ifr->ifr_data, &config,
|
||||
sizeof(config)) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
static int rtl8126_get_tstamp(struct net_device *netdev, struct ifreq *ifr)
|
||||
{
|
||||
struct rtl8126_private *tp = netdev_priv(netdev);
|
||||
|
||||
//netif_info(tp, drv, tp->dev, "ptp get ts\n");
|
||||
|
||||
return copy_to_user(ifr->ifr_data, &tp->hwtstamp_config,
|
||||
sizeof(tp->hwtstamp_config)) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
int rtl8126_ptp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
//netif_info(tp, drv, tp->dev, "ptp ioctl\n");
|
||||
|
||||
switch (cmd) {
|
||||
#ifdef ENABLE_PTP_SUPPORT
|
||||
case SIOCSHWTSTAMP:
|
||||
ret = rtl8126_set_tstamp(netdev, ifr);
|
||||
break;
|
||||
case SIOCGHWTSTAMP:
|
||||
ret = rtl8126_get_tstamp(netdev, ifr);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rtl8126_rx_ptp_pktstamp(struct rtl8126_private *tp, struct sk_buff *skb)
|
||||
{
|
||||
struct timespec64 ts64;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&tp->phy_lock, flags);
|
||||
|
||||
if (!(rtl8126_mdio_direct_read_phy_ocp(tp, PTP_INSR) & RX_TS_INTR)) {
|
||||
spin_unlock_irqrestore(&tp->phy_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
rtl8126_mdio_direct_write_phy_ocp(tp, PTP_INSR, RX_TS_INTR);
|
||||
|
||||
rtl8126_ptp_ingresstime(tp, &ts64);
|
||||
|
||||
spin_unlock_irqrestore(&tp->phy_lock, flags);
|
||||
|
||||
skb_hwtstamps(skb)->hwtstamp = ktime_set(ts64.tv_sec, ts64.tv_nsec);
|
||||
|
||||
return;
|
||||
}
|
||||
113
drivers/net/ethernet/realtek/r8126/r8126_ptp.h
Normal file
113
drivers/net/ethernet/realtek/r8126/r8126_ptp.h
Normal file
@@ -0,0 +1,113 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
################################################################################
|
||||
#
|
||||
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author:
|
||||
# Realtek NIC software team <nicfae@realtek.com>
|
||||
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
|
||||
#
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
/************************************************************************************
|
||||
* This product is covered by one or more of the following patents:
|
||||
* US6,570,884, US6,115,776, and US6,327,625.
|
||||
***********************************************************************************/
|
||||
|
||||
#ifndef _LINUX_R8126_PTP_H
|
||||
#define _LINUX_R8126_PTP_H
|
||||
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/timecounter.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/ptp_clock_kernel.h>
|
||||
#include <linux/ptp_classify.h>
|
||||
|
||||
struct rtl8126_ptp_info {
|
||||
s64 time_sec;
|
||||
u32 time_ns;
|
||||
u16 ts_info;
|
||||
};
|
||||
|
||||
#ifndef _STRUCT_TIMESPEC
|
||||
#define _STRUCT_TIMESPEC
|
||||
struct timespec {
|
||||
__kernel_old_time_t tv_sec; /* seconds */
|
||||
long tv_nsec; /* nanoseconds */
|
||||
};
|
||||
#endif
|
||||
|
||||
enum PTP_CMD_TYPE {
|
||||
PTP_CMD_SET_LOCAL_TIME = 0,
|
||||
PTP_CMD_DRIFT_LOCAL_TIME,
|
||||
PTP_CMD_LATCHED_LOCAL_TIME,
|
||||
};
|
||||
|
||||
enum PTP_CLKADJ_MOD_TYPE {
|
||||
NO_FUNCTION = 0,
|
||||
CLKADJ_MODE_SET = 1,
|
||||
RESERVED = 2,
|
||||
DIRECT_READ = 4,
|
||||
DIRECT_WRITE = 6,
|
||||
INCREMENT_STEP = 8,
|
||||
DECREMENT_STEP = 10,
|
||||
RATE_READ = 12,
|
||||
RATE_WRITE = 14,
|
||||
};
|
||||
|
||||
enum PTP_INSR_TYPE {
|
||||
EVENT_CAP_INTR = (1 << 0),
|
||||
TRIG_GEN_INTR = (1 << 1),
|
||||
RX_TS_INTR = (1 << 2),
|
||||
TX_TX_INTR = (1 << 3),
|
||||
};
|
||||
|
||||
enum PTP_TRX_TS_STA_REG {
|
||||
TRX_TS_RD = (1 << 0),
|
||||
TRXTS_SEL = (1 << 1),
|
||||
RX_TS_PDLYRSP_RDY = (1 << 8),
|
||||
RX_TS_PDLYREQ_RDY = (1 << 9),
|
||||
RX_TS_DLYREQ_RDY = (1 << 10),
|
||||
RX_TS_SYNC_RDY = (1 << 11),
|
||||
TX_TS_PDLYRSP_RDY = (1 << 12),
|
||||
TX_TS_PDLYREQ_RDY = (1 << 13),
|
||||
TX_TS_DLYREQ_RDY = (1 << 14),
|
||||
TX_TS_SYNC_RDY = (1 << 15),
|
||||
};
|
||||
|
||||
struct rtl8126_private;
|
||||
struct RxDescV3;
|
||||
|
||||
int rtl8126_get_ts_info(struct net_device *netdev,
|
||||
struct ethtool_ts_info *info);
|
||||
|
||||
void rtl8126_ptp_reset(struct rtl8126_private *tp);
|
||||
void rtl8126_ptp_init(struct rtl8126_private *tp);
|
||||
void rtl8126_ptp_suspend(struct rtl8126_private *tp);
|
||||
void rtl8126_ptp_stop(struct rtl8126_private *tp);
|
||||
|
||||
int rtl8126_ptp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
|
||||
|
||||
void rtl8126_rx_ptp_pktstamp(struct rtl8126_private *tp, struct sk_buff *skb);
|
||||
|
||||
void rtl8126_set_local_time(struct rtl8126_private *tp);
|
||||
|
||||
#endif /* _LINUX_R8126_PTP_H */
|
||||
118
drivers/net/ethernet/realtek/r8126/r8126_realwow.h
Normal file
118
drivers/net/ethernet/realtek/r8126/r8126_realwow.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
################################################################################
|
||||
#
|
||||
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author:
|
||||
# Realtek NIC software team <nicfae@realtek.com>
|
||||
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
|
||||
#
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
/************************************************************************************
|
||||
* This product is covered by one or more of the following patents:
|
||||
* US6,570,884, US6,115,776, and US6,327,625.
|
||||
***********************************************************************************/
|
||||
|
||||
#ifndef _LINUX_R8126_REALWOW_H
|
||||
#define _LINUX_R8126_REALWOW_H
|
||||
|
||||
#define SIOCDEVPRIVATE_RTLREALWOW SIOCDEVPRIVATE+3
|
||||
|
||||
#define MAX_RealWoW_KCP_SIZE (100)
|
||||
#define MAX_RealWoW_Payload (64)
|
||||
|
||||
#define KA_TX_PACKET_SIZE (100)
|
||||
#define KA_WAKEUP_PATTERN_SIZE (120)
|
||||
|
||||
//HwSuppKeepAliveOffloadVer
|
||||
#define HW_SUPPORT_KCP_OFFLOAD(_M) ((_M)->HwSuppKCPOffloadVer > 0)
|
||||
|
||||
enum rtl_realwow_cmd {
|
||||
|
||||
RTL_REALWOW_SET_KCP_DISABLE=0,
|
||||
RTL_REALWOW_SET_KCP_INFO,
|
||||
RTL_REALWOW_SET_KCP_CONTENT,
|
||||
|
||||
RTL_REALWOW_SET_KCP_ACKPKTINFO,
|
||||
RTL_REALWOW_SET_KCP_WPINFO,
|
||||
RTL_REALWOW_SET_KCPDHCP_TIMEOUT,
|
||||
|
||||
RTLT_REALWOW_COMMAND_INVALID
|
||||
};
|
||||
|
||||
struct rtl_realwow_ioctl_struct {
|
||||
__u32 cmd;
|
||||
__u32 offset;
|
||||
__u32 len;
|
||||
union {
|
||||
__u32 data;
|
||||
void *data_buffer;
|
||||
};
|
||||
};
|
||||
|
||||
typedef struct _MP_KCPInfo {
|
||||
u8 DIPv4[4];
|
||||
u8 MacID[6];
|
||||
u16 UdpPort[2];
|
||||
u8 PKTLEN[2];
|
||||
|
||||
u16 ackLostCnt;
|
||||
u8 KCP_WakePattern[MAX_RealWoW_Payload];
|
||||
u8 KCP_AckPacket[MAX_RealWoW_Payload];
|
||||
u32 KCP_interval;
|
||||
u8 KCP_WakePattern_Len;
|
||||
u8 KCP_AckPacket_Len;
|
||||
u8 KCP_TxPacket[2][KA_TX_PACKET_SIZE];
|
||||
} MP_KCP_INFO, *PMP_KCP_INFO;
|
||||
|
||||
typedef struct _KCPInfo {
|
||||
u32 nId; // = id
|
||||
u8 DIPv4[4];
|
||||
u8 MacID[6];
|
||||
u16 UdpPort;
|
||||
u16 PKTLEN;
|
||||
} KCPInfo, *PKCPInfo;
|
||||
|
||||
typedef struct _KCPContent {
|
||||
u32 id; // = id
|
||||
u32 mSec; // = msec
|
||||
u32 size; // =size
|
||||
u8 bPacket[MAX_RealWoW_KCP_SIZE]; // put packet here
|
||||
} KCPContent, *PKCPContent;
|
||||
|
||||
typedef struct _RealWoWAckPktInfo {
|
||||
u16 ackLostCnt;
|
||||
u16 patterntSize;
|
||||
u8 pattern[MAX_RealWoW_Payload];
|
||||
} RealWoWAckPktInfo,*PRealWoWAckPktInfo;
|
||||
|
||||
typedef struct _RealWoWWPInfo {
|
||||
u16 patterntSize;
|
||||
u8 pattern[MAX_RealWoW_Payload];
|
||||
} RealWoWWPInfo,*PRealWoWWPInfo;
|
||||
|
||||
int rtl8126_realwow_ioctl(struct net_device *dev, struct ifreq *ifr);
|
||||
void rtl8126_realwow_hw_init(struct net_device *dev);
|
||||
void rtl8126_get_realwow_hw_version(struct net_device *dev);
|
||||
void rtl8126_set_realwow_d3_para(struct net_device *dev);
|
||||
|
||||
#endif /* _LINUX_R8126_REALWOW_H */
|
||||
601
drivers/net/ethernet/realtek/r8126/r8126_rss.c
Normal file
601
drivers/net/ethernet/realtek/r8126/r8126_rss.c
Normal file
@@ -0,0 +1,601 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
################################################################################
|
||||
#
|
||||
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author:
|
||||
# Realtek NIC software team <nicfae@realtek.com>
|
||||
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
|
||||
#
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
/************************************************************************************
|
||||
* This product is covered by one or more of the following patents:
|
||||
* US6,570,884, US6,115,776, and US6,327,625.
|
||||
***********************************************************************************/
|
||||
|
||||
#include <linux/version.h>
|
||||
#include "r8126.h"
|
||||
|
||||
enum rtl8126_rss_register_content {
|
||||
/* RSS */
|
||||
RSS_CTRL_TCP_IPV4_SUPP = (1 << 0),
|
||||
RSS_CTRL_IPV4_SUPP = (1 << 1),
|
||||
RSS_CTRL_TCP_IPV6_SUPP = (1 << 2),
|
||||
RSS_CTRL_IPV6_SUPP = (1 << 3),
|
||||
RSS_CTRL_IPV6_EXT_SUPP = (1 << 4),
|
||||
RSS_CTRL_TCP_IPV6_EXT_SUPP = (1 << 5),
|
||||
RSS_HALF_SUPP = (1 << 7),
|
||||
RSS_CTRL_UDP_IPV4_SUPP = (1 << 11),
|
||||
RSS_CTRL_UDP_IPV6_SUPP = (1 << 12),
|
||||
RSS_CTRL_UDP_IPV6_EXT_SUPP = (1 << 13),
|
||||
RSS_QUAD_CPU_EN = (1 << 16),
|
||||
RSS_HQ_Q_SUP_R = (1 << 31),
|
||||
};
|
||||
|
||||
static int rtl8126_get_rss_hash_opts(struct rtl8126_private *tp,
|
||||
struct ethtool_rxnfc *cmd)
|
||||
{
|
||||
cmd->data = 0;
|
||||
|
||||
/* Report default options for RSS */
|
||||
switch (cmd->flow_type) {
|
||||
case TCP_V4_FLOW:
|
||||
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
||||
fallthrough;
|
||||
case UDP_V4_FLOW:
|
||||
if (tp->rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV4)
|
||||
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
||||
fallthrough;
|
||||
case IPV4_FLOW:
|
||||
cmd->data |= RXH_IP_SRC | RXH_IP_DST;
|
||||
break;
|
||||
case TCP_V6_FLOW:
|
||||
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
||||
fallthrough;
|
||||
case UDP_V6_FLOW:
|
||||
if (tp->rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV6)
|
||||
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
||||
fallthrough;
|
||||
case IPV6_FLOW:
|
||||
cmd->data |= RXH_IP_SRC | RXH_IP_DST;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtl8126_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
|
||||
u32 *rule_locs)
|
||||
{
|
||||
struct rtl8126_private *tp = netdev_priv(dev);
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
netif_info(tp, drv, tp->dev, "rss get rxnfc\n");
|
||||
|
||||
if (!(dev->features & NETIF_F_RXHASH))
|
||||
return ret;
|
||||
|
||||
switch (cmd->cmd) {
|
||||
case ETHTOOL_GRXRINGS:
|
||||
cmd->data = rtl8126_tot_rx_rings(tp);
|
||||
ret = 0;
|
||||
break;
|
||||
case ETHTOOL_GRXFH:
|
||||
ret = rtl8126_get_rss_hash_opts(tp, cmd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 rtl8126_rss_indir_tbl_entries(struct rtl8126_private *tp)
|
||||
{
|
||||
return tp->HwSuppIndirTblEntries;
|
||||
}
|
||||
|
||||
#define RSS_MASK_BITS_OFFSET (8)
|
||||
#define RSS_CPU_NUM_OFFSET (16)
|
||||
#define RTL8126_UDP_RSS_FLAGS (RTL_8125_RSS_FLAG_HASH_UDP_IPV4 | \
|
||||
RTL_8125_RSS_FLAG_HASH_UDP_IPV6)
|
||||
static int _rtl8126_set_rss_hash_opt(struct rtl8126_private *tp)
|
||||
{
|
||||
u32 rss_flags = tp->rss_flags;
|
||||
u32 hash_mask_len;
|
||||
u32 rss_ctrl;
|
||||
|
||||
rss_ctrl = ilog2(rtl8126_tot_rx_rings(tp));
|
||||
rss_ctrl &= (BIT_0 | BIT_1 | BIT_2);
|
||||
rss_ctrl <<= RSS_CPU_NUM_OFFSET;
|
||||
|
||||
/* Perform hash on these packet types */
|
||||
rss_ctrl |= RSS_CTRL_TCP_IPV4_SUPP
|
||||
| RSS_CTRL_IPV4_SUPP
|
||||
| RSS_CTRL_IPV6_SUPP
|
||||
| RSS_CTRL_IPV6_EXT_SUPP
|
||||
| RSS_CTRL_TCP_IPV6_SUPP
|
||||
| RSS_CTRL_TCP_IPV6_EXT_SUPP;
|
||||
|
||||
if (rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV4)
|
||||
rss_ctrl |= RSS_CTRL_UDP_IPV4_SUPP;
|
||||
|
||||
if (rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV6)
|
||||
rss_ctrl |= RSS_CTRL_UDP_IPV6_SUPP |
|
||||
RSS_CTRL_UDP_IPV6_EXT_SUPP;
|
||||
|
||||
hash_mask_len = ilog2(rtl8126_rss_indir_tbl_entries(tp));
|
||||
hash_mask_len &= (BIT_0 | BIT_1 | BIT_2);
|
||||
rss_ctrl |= hash_mask_len << RSS_MASK_BITS_OFFSET;
|
||||
|
||||
RTL_W32(tp, RSS_CTRL_8125, rss_ctrl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtl8126_set_rss_hash_opt(struct rtl8126_private *tp,
|
||||
struct ethtool_rxnfc *nfc)
|
||||
{
|
||||
u32 rss_flags = tp->rss_flags;
|
||||
|
||||
netif_info(tp, drv, tp->dev, "rss set hash\n");
|
||||
|
||||
/*
|
||||
* RSS does not support anything other than hashing
|
||||
* to queues on src and dst IPs and ports
|
||||
*/
|
||||
if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
|
||||
RXH_L4_B_0_1 | RXH_L4_B_2_3))
|
||||
return -EINVAL;
|
||||
|
||||
switch (nfc->flow_type) {
|
||||
case TCP_V4_FLOW:
|
||||
case TCP_V6_FLOW:
|
||||
if (!(nfc->data & RXH_IP_SRC) ||
|
||||
!(nfc->data & RXH_IP_DST) ||
|
||||
!(nfc->data & RXH_L4_B_0_1) ||
|
||||
!(nfc->data & RXH_L4_B_2_3))
|
||||
return -EINVAL;
|
||||
break;
|
||||
case UDP_V4_FLOW:
|
||||
if (!(nfc->data & RXH_IP_SRC) ||
|
||||
!(nfc->data & RXH_IP_DST))
|
||||
return -EINVAL;
|
||||
switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
|
||||
case 0:
|
||||
rss_flags &= ~RTL_8125_RSS_FLAG_HASH_UDP_IPV4;
|
||||
break;
|
||||
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
|
||||
rss_flags |= RTL_8125_RSS_FLAG_HASH_UDP_IPV4;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case UDP_V6_FLOW:
|
||||
if (!(nfc->data & RXH_IP_SRC) ||
|
||||
!(nfc->data & RXH_IP_DST))
|
||||
return -EINVAL;
|
||||
switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
|
||||
case 0:
|
||||
rss_flags &= ~RTL_8125_RSS_FLAG_HASH_UDP_IPV6;
|
||||
break;
|
||||
case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
|
||||
rss_flags |= RTL_8125_RSS_FLAG_HASH_UDP_IPV6;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case SCTP_V4_FLOW:
|
||||
case AH_ESP_V4_FLOW:
|
||||
case AH_V4_FLOW:
|
||||
case ESP_V4_FLOW:
|
||||
case SCTP_V6_FLOW:
|
||||
case AH_ESP_V6_FLOW:
|
||||
case AH_V6_FLOW:
|
||||
case ESP_V6_FLOW:
|
||||
case IP_USER_FLOW:
|
||||
case ETHER_FLOW:
|
||||
/* RSS is not supported for these protocols */
|
||||
if (nfc->data) {
|
||||
netif_err(tp, drv, tp->dev, "Command parameters not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* if we changed something we need to update flags */
|
||||
if (rss_flags != tp->rss_flags) {
|
||||
u32 rss_ctrl = RTL_R32(tp, RSS_CTRL_8125);
|
||||
|
||||
if ((rss_flags & RTL8126_UDP_RSS_FLAGS) &&
|
||||
!(tp->rss_flags & RTL8126_UDP_RSS_FLAGS))
|
||||
netdev_warn(tp->dev,
|
||||
"enabling UDP RSS: fragmented packets may "
|
||||
"arrive out of order to the stack above\n");
|
||||
|
||||
tp->rss_flags = rss_flags;
|
||||
|
||||
/* Perform hash on these packet types */
|
||||
rss_ctrl |= RSS_CTRL_TCP_IPV4_SUPP
|
||||
| RSS_CTRL_IPV4_SUPP
|
||||
| RSS_CTRL_IPV6_SUPP
|
||||
| RSS_CTRL_IPV6_EXT_SUPP
|
||||
| RSS_CTRL_TCP_IPV6_SUPP
|
||||
| RSS_CTRL_TCP_IPV6_EXT_SUPP;
|
||||
|
||||
rss_ctrl &= ~(RSS_CTRL_UDP_IPV4_SUPP |
|
||||
RSS_CTRL_UDP_IPV6_SUPP |
|
||||
RSS_CTRL_UDP_IPV6_EXT_SUPP);
|
||||
|
||||
if (rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV4)
|
||||
rss_ctrl |= RSS_CTRL_UDP_IPV4_SUPP;
|
||||
|
||||
if (rss_flags & RTL_8125_RSS_FLAG_HASH_UDP_IPV6)
|
||||
rss_ctrl |= RSS_CTRL_UDP_IPV6_SUPP |
|
||||
RSS_CTRL_UDP_IPV6_EXT_SUPP;
|
||||
|
||||
RTL_W32(tp, RSS_CTRL_8125, rss_ctrl);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtl8126_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
|
||||
{
|
||||
struct rtl8126_private *tp = netdev_priv(dev);
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
netif_info(tp, drv, tp->dev, "rss set rxnfc\n");
|
||||
|
||||
if (!(dev->features & NETIF_F_RXHASH))
|
||||
return ret;
|
||||
|
||||
switch (cmd->cmd) {
|
||||
case ETHTOOL_SRXFH:
|
||||
ret = rtl8126_set_rss_hash_opt(tp, cmd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 _rtl8126_get_rxfh_key_size(struct rtl8126_private *tp)
|
||||
{
|
||||
return sizeof(tp->rss_key);
|
||||
}
|
||||
|
||||
u32 rtl8126_get_rxfh_key_size(struct net_device *dev)
|
||||
{
|
||||
struct rtl8126_private *tp = netdev_priv(dev);
|
||||
|
||||
netif_info(tp, drv, tp->dev, "rss get key size\n");
|
||||
|
||||
if (!(dev->features & NETIF_F_RXHASH))
|
||||
return 0;
|
||||
|
||||
return _rtl8126_get_rxfh_key_size(tp);
|
||||
}
|
||||
|
||||
u32 rtl8126_rss_indir_size(struct net_device *dev)
|
||||
{
|
||||
struct rtl8126_private *tp = netdev_priv(dev);
|
||||
|
||||
netif_info(tp, drv, tp->dev, "rss get indir tbl size\n");
|
||||
|
||||
if (!(dev->features & NETIF_F_RXHASH))
|
||||
return 0;
|
||||
|
||||
return rtl8126_rss_indir_tbl_entries(tp);
|
||||
}
|
||||
|
||||
static void rtl8126_get_reta(struct rtl8126_private *tp, u32 *indir)
|
||||
{
|
||||
int i, reta_size = rtl8126_rss_indir_tbl_entries(tp);
|
||||
|
||||
for (i = 0; i < reta_size; i++)
|
||||
indir[i] = tp->rss_indir_tbl[i];
|
||||
}
|
||||
|
||||
static u32 rtl8126_rss_key_reg(struct rtl8126_private *tp)
|
||||
{
|
||||
return RSS_KEY_8125;
|
||||
}
|
||||
|
||||
static u32 rtl8126_rss_indir_tbl_reg(struct rtl8126_private *tp)
|
||||
{
|
||||
return RSS_INDIRECTION_TBL_8125_V2;
|
||||
}
|
||||
|
||||
static void rtl8126_store_reta(struct rtl8126_private *tp)
|
||||
{
|
||||
u16 indir_tbl_reg = rtl8126_rss_indir_tbl_reg(tp);
|
||||
u32 i, reta_entries = rtl8126_rss_indir_tbl_entries(tp);
|
||||
u32 reta = 0;
|
||||
u8 *indir_tbl = tp->rss_indir_tbl;
|
||||
|
||||
/* Write redirection table to HW */
|
||||
for (i = 0; i < reta_entries; i++) {
|
||||
reta |= indir_tbl[i] << (i & 0x3) * 8;
|
||||
if ((i & 3) == 3) {
|
||||
RTL_W32(tp, indir_tbl_reg, reta);
|
||||
|
||||
indir_tbl_reg += 4;
|
||||
reta = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rtl8126_store_rss_key(struct rtl8126_private *tp)
|
||||
{
|
||||
const u16 rss_key_reg = rtl8126_rss_key_reg(tp);
|
||||
u32 i, rss_key_size = _rtl8126_get_rxfh_key_size(tp);
|
||||
u32 *rss_key = (u32*)tp->rss_key;
|
||||
|
||||
/* Write redirection table to HW */
|
||||
for (i = 0; i < rss_key_size; i+=4)
|
||||
RTL_W32(tp, rss_key_reg + i, *rss_key++);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,8,0)
|
||||
int rtl8126_get_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh)
|
||||
{
|
||||
struct rtl8126_private *tp = netdev_priv(dev);
|
||||
|
||||
netif_info(tp, drv, tp->dev, "rss get rxfh\n");
|
||||
|
||||
if (!(dev->features & NETIF_F_RXHASH))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
rxfh->hfunc = ETH_RSS_HASH_TOP;
|
||||
|
||||
if (rxfh->indir)
|
||||
rtl8126_get_reta(tp, rxfh->indir);
|
||||
|
||||
if (rxfh->key)
|
||||
memcpy(rxfh->key, tp->rss_key, RTL8126_RSS_KEY_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtl8126_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct rtl8126_private *tp = netdev_priv(dev);
|
||||
int i;
|
||||
u32 reta_entries = rtl8126_rss_indir_tbl_entries(tp);
|
||||
|
||||
netif_info(tp, drv, tp->dev, "rss set rxfh\n");
|
||||
|
||||
/* We require at least one supported parameter to be changed and no
|
||||
* change in any of the unsupported parameters
|
||||
*/
|
||||
if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE && rxfh->hfunc != ETH_RSS_HASH_TOP)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Fill out the redirection table */
|
||||
if (rxfh->indir) {
|
||||
int max_queues = tp->num_rx_rings;
|
||||
|
||||
/* Verify user input. */
|
||||
for (i = 0; i < reta_entries; i++)
|
||||
if (rxfh->indir[i] >= max_queues)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < reta_entries; i++)
|
||||
tp->rss_indir_tbl[i] = rxfh->indir[i];
|
||||
}
|
||||
|
||||
/* Fill out the rss hash key */
|
||||
if (rxfh->key)
|
||||
memcpy(tp->rss_key, rxfh->key, RTL8126_RSS_KEY_SIZE);
|
||||
|
||||
rtl8126_store_reta(tp);
|
||||
|
||||
rtl8126_store_rss_key(tp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int rtl8126_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
|
||||
u8 *hfunc)
|
||||
{
|
||||
struct rtl8126_private *tp = netdev_priv(dev);
|
||||
|
||||
netif_info(tp, drv, tp->dev, "rss get rxfh\n");
|
||||
|
||||
if (!(dev->features & NETIF_F_RXHASH))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (hfunc)
|
||||
*hfunc = ETH_RSS_HASH_TOP;
|
||||
|
||||
if (indir)
|
||||
rtl8126_get_reta(tp, indir);
|
||||
|
||||
if (key)
|
||||
memcpy(key, tp->rss_key, RTL8126_RSS_KEY_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtl8126_set_rxfh(struct net_device *dev, const u32 *indir,
|
||||
const u8 *key, const u8 hfunc)
|
||||
{
|
||||
struct rtl8126_private *tp = netdev_priv(dev);
|
||||
int i;
|
||||
u32 reta_entries = rtl8126_rss_indir_tbl_entries(tp);
|
||||
|
||||
netif_info(tp, drv, tp->dev, "rss set rxfh\n");
|
||||
|
||||
/* We require at least one supported parameter to be changed and no
|
||||
* change in any of the unsupported parameters
|
||||
*/
|
||||
if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Fill out the redirection table */
|
||||
if (indir) {
|
||||
int max_queues = tp->num_rx_rings;
|
||||
|
||||
/* Verify user input. */
|
||||
for (i = 0; i < reta_entries; i++)
|
||||
if (indir[i] >= max_queues)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < reta_entries; i++)
|
||||
tp->rss_indir_tbl[i] = indir[i];
|
||||
}
|
||||
|
||||
/* Fill out the rss hash key */
|
||||
if (key)
|
||||
memcpy(tp->rss_key, key, RTL8126_RSS_KEY_SIZE);
|
||||
|
||||
rtl8126_store_reta(tp);
|
||||
|
||||
rtl8126_store_rss_key(tp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6,8,0) */
|
||||
|
||||
static u32 rtl8126_get_rx_desc_hash(struct rtl8126_private *tp,
|
||||
struct RxDesc *desc)
|
||||
{
|
||||
switch (tp->InitRxDescType) {
|
||||
case RX_DESC_RING_TYPE_3:
|
||||
return le32_to_cpu(((struct RxDescV3 *)desc)->RxDescNormalDDWord2.RSSResult);
|
||||
case RX_DESC_RING_TYPE_4:
|
||||
return le32_to_cpu(((struct RxDescV4 *)desc)->RxDescNormalDDWord1.RSSResult);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define RXS_8125B_RSS_UDP BIT(9)
|
||||
#define RXS_8125_RSS_IPV4 BIT(10)
|
||||
#define RXS_8125_RSS_IPV6 BIT(12)
|
||||
#define RXS_8125_RSS_TCP BIT(13)
|
||||
#define RTL8126_RXS_RSS_L3_TYPE_MASK (RXS_8125_RSS_IPV4 | RXS_8125_RSS_IPV6)
|
||||
#define RTL8126_RXS_RSS_L4_TYPE_MASK (RXS_8125_RSS_TCP | RXS_8125B_RSS_UDP)
|
||||
|
||||
#define RXS_8125B_RSS_UDP_V4 BIT(27)
|
||||
#define RXS_8125_RSS_IPV4_V4 BIT(28)
|
||||
#define RXS_8125_RSS_IPV6_V4 BIT(29)
|
||||
#define RXS_8125_RSS_TCP_V4 BIT(30)
|
||||
#define RTL8126_RXS_RSS_L3_TYPE_MASK_V4 (RXS_8125_RSS_IPV4_V4 | RXS_8125_RSS_IPV6_V4)
|
||||
#define RTL8126_RXS_RSS_L4_TYPE_MASK_V4 (RXS_8125_RSS_TCP_V4 | RXS_8125B_RSS_UDP_V4)
|
||||
static void rtl8126_rx_hash_v3(struct rtl8126_private *tp,
|
||||
struct RxDescV3 *descv3,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
u16 rss_header_info;
|
||||
|
||||
if (!(tp->dev->features & NETIF_F_RXHASH))
|
||||
return;
|
||||
|
||||
rss_header_info = le16_to_cpu(descv3->RxDescNormalDDWord2.HeaderInfo);
|
||||
|
||||
if (!(rss_header_info & RTL8126_RXS_RSS_L3_TYPE_MASK))
|
||||
return;
|
||||
|
||||
skb_set_hash(skb, rtl8126_get_rx_desc_hash(tp, (struct RxDesc *)descv3),
|
||||
(RTL8126_RXS_RSS_L4_TYPE_MASK & rss_header_info) ?
|
||||
PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
|
||||
}
|
||||
|
||||
static void rtl8126_rx_hash_v4(struct rtl8126_private *tp,
|
||||
struct RxDescV4 *descv4,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
u32 rss_header_info;
|
||||
|
||||
if (!(tp->dev->features & NETIF_F_RXHASH))
|
||||
return;
|
||||
|
||||
rss_header_info = le32_to_cpu(descv4->RxDescNormalDDWord1.RSSInfo);
|
||||
|
||||
if (!(rss_header_info & RTL8126_RXS_RSS_L3_TYPE_MASK_V4))
|
||||
return;
|
||||
|
||||
skb_set_hash(skb, rtl8126_get_rx_desc_hash(tp, (struct RxDesc *)descv4),
|
||||
(RTL8126_RXS_RSS_L4_TYPE_MASK_V4 & rss_header_info) ?
|
||||
PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
|
||||
}
|
||||
|
||||
void rtl8126_rx_hash(struct rtl8126_private *tp,
|
||||
struct RxDesc *desc,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
switch (tp->InitRxDescType) {
|
||||
case RX_DESC_RING_TYPE_3:
|
||||
rtl8126_rx_hash_v3(tp, (struct RxDescV3 *)desc, skb);
|
||||
break;
|
||||
case RX_DESC_RING_TYPE_4:
|
||||
rtl8126_rx_hash_v4(tp, (struct RxDescV4 *)desc, skb);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void rtl8126_disable_rss(struct rtl8126_private *tp)
|
||||
{
|
||||
RTL_W32(tp, RSS_CTRL_8125, 0x00);
|
||||
}
|
||||
|
||||
void _rtl8126_config_rss(struct rtl8126_private *tp)
|
||||
{
|
||||
_rtl8126_set_rss_hash_opt(tp);
|
||||
|
||||
rtl8126_store_reta(tp);
|
||||
|
||||
rtl8126_store_rss_key(tp);
|
||||
}
|
||||
|
||||
void rtl8126_config_rss(struct rtl8126_private *tp)
|
||||
{
|
||||
if (!tp->EnableRss) {
|
||||
rtl8126_disable_rss(tp);
|
||||
return;
|
||||
}
|
||||
|
||||
_rtl8126_config_rss(tp);
|
||||
}
|
||||
|
||||
void rtl8126_init_rss(struct rtl8126_private *tp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < rtl8126_rss_indir_tbl_entries(tp); i++)
|
||||
tp->rss_indir_tbl[i] = ethtool_rxfh_indir_default(i, tp->num_rx_rings);
|
||||
|
||||
netdev_rss_key_fill(tp->rss_key, RTL8126_RSS_KEY_SIZE);
|
||||
}
|
||||
76
drivers/net/ethernet/realtek/r8126/r8126_rss.h
Normal file
76
drivers/net/ethernet/realtek/r8126/r8126_rss.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
################################################################################
|
||||
#
|
||||
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author:
|
||||
# Realtek NIC software team <nicfae@realtek.com>
|
||||
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
|
||||
#
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
/************************************************************************************
|
||||
* This product is covered by one or more of the following patents:
|
||||
* US6,570,884, US6,115,776, and US6,327,625.
|
||||
***********************************************************************************/
|
||||
|
||||
#ifndef _LINUX_R8126_RSS_H
|
||||
#define _LINUX_R8126_RSS_H
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define RTL8126_RSS_KEY_SIZE 40 /* size of RSS Hash Key in bytes */
|
||||
#define RTL8126_MAX_INDIRECTION_TABLE_ENTRIES 128
|
||||
|
||||
enum rtl8126_rss_flag {
|
||||
RTL_8125_RSS_FLAG_HASH_UDP_IPV4 = (1 << 0),
|
||||
RTL_8125_RSS_FLAG_HASH_UDP_IPV6 = (1 << 1),
|
||||
};
|
||||
|
||||
struct rtl8126_private;
|
||||
struct RxDesc;
|
||||
|
||||
int rtl8126_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
|
||||
u32 *rule_locs);
|
||||
int rtl8126_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd);
|
||||
u32 rtl8126_get_rxfh_key_size(struct net_device *netdev);
|
||||
u32 rtl8126_rss_indir_size(struct net_device *netdev);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,8,0)
|
||||
int rtl8126_get_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh);
|
||||
int rtl8126_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh,
|
||||
struct netlink_ext_ack *extack);
|
||||
#else
|
||||
int rtl8126_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
|
||||
u8 *hfunc);
|
||||
int rtl8126_set_rxfh(struct net_device *netdev, const u32 *indir,
|
||||
const u8 *key, const u8 hfunc);
|
||||
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6,8,0) */
|
||||
void rtl8126_rx_hash(struct rtl8126_private *tp,
|
||||
struct RxDesc *desc,
|
||||
struct sk_buff *skb);
|
||||
void _rtl8126_config_rss(struct rtl8126_private *tp);
|
||||
void rtl8126_config_rss(struct rtl8126_private *tp);
|
||||
void rtl8126_init_rss(struct rtl8126_private *tp);
|
||||
u32 rtl8126_rss_indir_tbl_entries(struct rtl8126_private *tp);
|
||||
void rtl8126_disable_rss(struct rtl8126_private *tp);
|
||||
|
||||
#endif /* _LINUX_R8126_RSS_H */
|
||||
285
drivers/net/ethernet/realtek/r8126/rtl_eeprom.c
Normal file
285
drivers/net/ethernet/realtek/r8126/rtl_eeprom.c
Normal file
@@ -0,0 +1,285 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
################################################################################
|
||||
#
|
||||
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author:
|
||||
# Realtek NIC software team <nicfae@realtek.com>
|
||||
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
|
||||
#
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
/************************************************************************************
|
||||
* This product is covered by one or more of the following patents:
|
||||
* US6,570,884, US6,115,776, and US6,327,625.
|
||||
***********************************************************************************/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "r8126.h"
|
||||
#include "rtl_eeprom.h"
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//rtl8126_eeprom_type():
|
||||
// tell the eeprom type
|
||||
//return value:
|
||||
// 0: the eeprom type is 93C46
|
||||
// 1: the eeprom type is 93C56 or 93C66
|
||||
//-------------------------------------------------------------------
|
||||
void rtl8126_eeprom_type(struct rtl8126_private *tp)
|
||||
{
|
||||
u16 magic = 0;
|
||||
|
||||
if (tp->mcfg == CFG_METHOD_DEFAULT)
|
||||
goto out_no_eeprom;
|
||||
|
||||
if(RTL_R8(tp, 0xD2)&0x04) {
|
||||
//not support
|
||||
//tp->eeprom_type = EEPROM_TWSI;
|
||||
//tp->eeprom_len = 256;
|
||||
goto out_no_eeprom;
|
||||
} else if(RTL_R32(tp, RxConfig) & RxCfg_9356SEL) {
|
||||
tp->eeprom_type = EEPROM_TYPE_93C56;
|
||||
tp->eeprom_len = 256;
|
||||
} else {
|
||||
tp->eeprom_type = EEPROM_TYPE_93C46;
|
||||
tp->eeprom_len = 128;
|
||||
}
|
||||
|
||||
magic = rtl8126_eeprom_read_sc(tp, 0);
|
||||
|
||||
out_no_eeprom:
|
||||
if ((magic != 0x8129) && (magic != 0x8128)) {
|
||||
tp->eeprom_type = EEPROM_TYPE_NONE;
|
||||
tp->eeprom_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void rtl8126_eeprom_cleanup(struct rtl8126_private *tp)
|
||||
{
|
||||
u8 x;
|
||||
|
||||
x = RTL_R8(tp, Cfg9346);
|
||||
x &= ~(Cfg9346_EEDI | Cfg9346_EECS);
|
||||
|
||||
RTL_W8(tp, Cfg9346, x);
|
||||
|
||||
rtl8126_raise_clock(tp, &x);
|
||||
rtl8126_lower_clock(tp, &x);
|
||||
}
|
||||
|
||||
static int rtl8126_eeprom_cmd_done(struct rtl8126_private *tp)
|
||||
{
|
||||
u8 x;
|
||||
int i;
|
||||
|
||||
rtl8126_stand_by(tp);
|
||||
|
||||
for (i = 0; i < 50000; i++) {
|
||||
x = RTL_R8(tp, Cfg9346);
|
||||
|
||||
if (x & Cfg9346_EEDO) {
|
||||
udelay(RTL_CLOCK_RATE * 2 * 3);
|
||||
return 0;
|
||||
}
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//rtl8126_eeprom_read_sc():
|
||||
// read one word from eeprom
|
||||
//-------------------------------------------------------------------
|
||||
u16 rtl8126_eeprom_read_sc(struct rtl8126_private *tp, u16 reg)
|
||||
{
|
||||
int addr_sz = 6;
|
||||
u8 x;
|
||||
u16 data;
|
||||
|
||||
if(tp->eeprom_type == EEPROM_TYPE_NONE)
|
||||
return -1;
|
||||
|
||||
if (tp->eeprom_type==EEPROM_TYPE_93C46)
|
||||
addr_sz = 6;
|
||||
else if (tp->eeprom_type==EEPROM_TYPE_93C56)
|
||||
addr_sz = 8;
|
||||
|
||||
x = Cfg9346_EEM1 | Cfg9346_EECS;
|
||||
RTL_W8(tp, Cfg9346, x);
|
||||
|
||||
rtl8126_shift_out_bits(tp, RTL_EEPROM_READ_OPCODE, 3);
|
||||
rtl8126_shift_out_bits(tp, reg, addr_sz);
|
||||
|
||||
data = rtl8126_shift_in_bits(tp);
|
||||
|
||||
rtl8126_eeprom_cleanup(tp);
|
||||
|
||||
RTL_W8(tp, Cfg9346, 0);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//rtl8126_eeprom_write_sc():
|
||||
// write one word to a specific address in the eeprom
|
||||
//-------------------------------------------------------------------
|
||||
void rtl8126_eeprom_write_sc(struct rtl8126_private *tp, u16 reg, u16 data)
|
||||
{
|
||||
u8 x;
|
||||
int addr_sz = 6;
|
||||
int w_dummy_addr = 4;
|
||||
|
||||
if(tp->eeprom_type == EEPROM_TYPE_NONE)
|
||||
return;
|
||||
|
||||
if (tp->eeprom_type==EEPROM_TYPE_93C46) {
|
||||
addr_sz = 6;
|
||||
w_dummy_addr = 4;
|
||||
} else if (tp->eeprom_type==EEPROM_TYPE_93C56) {
|
||||
addr_sz = 8;
|
||||
w_dummy_addr = 6;
|
||||
}
|
||||
|
||||
x = Cfg9346_EEM1 | Cfg9346_EECS;
|
||||
RTL_W8(tp, Cfg9346, x);
|
||||
|
||||
rtl8126_shift_out_bits(tp, RTL_EEPROM_EWEN_OPCODE, 5);
|
||||
rtl8126_shift_out_bits(tp, reg, w_dummy_addr);
|
||||
rtl8126_stand_by(tp);
|
||||
|
||||
rtl8126_shift_out_bits(tp, RTL_EEPROM_ERASE_OPCODE, 3);
|
||||
rtl8126_shift_out_bits(tp, reg, addr_sz);
|
||||
if (rtl8126_eeprom_cmd_done(tp) < 0)
|
||||
return;
|
||||
rtl8126_stand_by(tp);
|
||||
|
||||
rtl8126_shift_out_bits(tp, RTL_EEPROM_WRITE_OPCODE, 3);
|
||||
rtl8126_shift_out_bits(tp, reg, addr_sz);
|
||||
rtl8126_shift_out_bits(tp, data, 16);
|
||||
if (rtl8126_eeprom_cmd_done(tp) < 0)
|
||||
return;
|
||||
rtl8126_stand_by(tp);
|
||||
|
||||
rtl8126_shift_out_bits(tp, RTL_EEPROM_EWDS_OPCODE, 5);
|
||||
rtl8126_shift_out_bits(tp, reg, w_dummy_addr);
|
||||
|
||||
rtl8126_eeprom_cleanup(tp);
|
||||
RTL_W8(tp, Cfg9346, 0);
|
||||
}
|
||||
|
||||
void rtl8126_raise_clock(struct rtl8126_private *tp, u8 *x)
|
||||
{
|
||||
*x = *x | Cfg9346_EESK;
|
||||
RTL_W8(tp, Cfg9346, *x);
|
||||
udelay(RTL_CLOCK_RATE);
|
||||
}
|
||||
|
||||
void rtl8126_lower_clock(struct rtl8126_private *tp, u8 *x)
|
||||
{
|
||||
|
||||
*x = *x & ~Cfg9346_EESK;
|
||||
RTL_W8(tp, Cfg9346, *x);
|
||||
udelay(RTL_CLOCK_RATE);
|
||||
}
|
||||
|
||||
void rtl8126_shift_out_bits(struct rtl8126_private *tp, int data, int count)
|
||||
{
|
||||
u8 x;
|
||||
int mask;
|
||||
|
||||
mask = 0x01 << (count - 1);
|
||||
x = RTL_R8(tp, Cfg9346);
|
||||
x &= ~(Cfg9346_EEDI | Cfg9346_EEDO);
|
||||
|
||||
do {
|
||||
if (data & mask)
|
||||
x |= Cfg9346_EEDI;
|
||||
else
|
||||
x &= ~Cfg9346_EEDI;
|
||||
|
||||
RTL_W8(tp, Cfg9346, x);
|
||||
udelay(RTL_CLOCK_RATE);
|
||||
rtl8126_raise_clock(tp, &x);
|
||||
rtl8126_lower_clock(tp, &x);
|
||||
mask = mask >> 1;
|
||||
} while(mask);
|
||||
|
||||
x &= ~Cfg9346_EEDI;
|
||||
RTL_W8(tp, Cfg9346, x);
|
||||
}
|
||||
|
||||
u16 rtl8126_shift_in_bits(struct rtl8126_private *tp)
|
||||
{
|
||||
u8 x;
|
||||
u16 d, i;
|
||||
|
||||
x = RTL_R8(tp, Cfg9346);
|
||||
x &= ~(Cfg9346_EEDI | Cfg9346_EEDO);
|
||||
|
||||
d = 0;
|
||||
|
||||
for (i = 0; i < 16; i++) {
|
||||
d = d << 1;
|
||||
rtl8126_raise_clock(tp, &x);
|
||||
|
||||
x = RTL_R8(tp, Cfg9346);
|
||||
x &= ~Cfg9346_EEDI;
|
||||
|
||||
if (x & Cfg9346_EEDO)
|
||||
d |= 1;
|
||||
|
||||
rtl8126_lower_clock(tp, &x);
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
void rtl8126_stand_by(struct rtl8126_private *tp)
|
||||
{
|
||||
u8 x;
|
||||
|
||||
x = RTL_R8(tp, Cfg9346);
|
||||
x &= ~(Cfg9346_EECS | Cfg9346_EESK);
|
||||
RTL_W8(tp, Cfg9346, x);
|
||||
udelay(RTL_CLOCK_RATE);
|
||||
|
||||
x |= Cfg9346_EECS;
|
||||
RTL_W8(tp, Cfg9346, x);
|
||||
}
|
||||
|
||||
void rtl8126_set_eeprom_sel_low(struct rtl8126_private *tp)
|
||||
{
|
||||
RTL_W8(tp, Cfg9346, Cfg9346_EEM1);
|
||||
RTL_W8(tp, Cfg9346, Cfg9346_EEM1 | Cfg9346_EESK);
|
||||
|
||||
udelay(20);
|
||||
|
||||
RTL_W8(tp, Cfg9346, Cfg9346_EEM1);
|
||||
}
|
||||
58
drivers/net/ethernet/realtek/r8126/rtl_eeprom.h
Normal file
58
drivers/net/ethernet/realtek/r8126/rtl_eeprom.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
################################################################################
|
||||
#
|
||||
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author:
|
||||
# Realtek NIC software team <nicfae@realtek.com>
|
||||
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
|
||||
#
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
/************************************************************************************
|
||||
* This product is covered by one or more of the following patents:
|
||||
* US6,570,884, US6,115,776, and US6,327,625.
|
||||
***********************************************************************************/
|
||||
|
||||
#ifndef _LINUX_RTLEEPROM_H
|
||||
#define _LINUX_RTLEEPROM_H
|
||||
|
||||
//EEPROM opcodes
|
||||
#define RTL_EEPROM_READ_OPCODE 06
|
||||
#define RTL_EEPROM_WRITE_OPCODE 05
|
||||
#define RTL_EEPROM_ERASE_OPCODE 07
|
||||
#define RTL_EEPROM_EWEN_OPCODE 19
|
||||
#define RTL_EEPROM_EWDS_OPCODE 16
|
||||
|
||||
#define RTL_CLOCK_RATE 3
|
||||
|
||||
void rtl8126_eeprom_type(struct rtl8126_private *tp);
|
||||
void rtl8126_eeprom_cleanup(struct rtl8126_private *tp);
|
||||
u16 rtl8126_eeprom_read_sc(struct rtl8126_private *tp, u16 reg);
|
||||
void rtl8126_eeprom_write_sc(struct rtl8126_private *tp, u16 reg, u16 data);
|
||||
void rtl8126_shift_out_bits(struct rtl8126_private *tp, int data, int count);
|
||||
u16 rtl8126_shift_in_bits(struct rtl8126_private *tp);
|
||||
void rtl8126_raise_clock(struct rtl8126_private *tp, u8 *x);
|
||||
void rtl8126_lower_clock(struct rtl8126_private *tp, u8 *x);
|
||||
void rtl8126_stand_by(struct rtl8126_private *tp);
|
||||
void rtl8126_set_eeprom_sel_low(struct rtl8126_private *tp);
|
||||
|
||||
#endif /* _LINUX_RTLEEPROM_H */
|
||||
260
drivers/net/ethernet/realtek/r8126/rtltool.c
Normal file
260
drivers/net/ethernet/realtek/r8126/rtltool.c
Normal file
@@ -0,0 +1,260 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
################################################################################
|
||||
#
|
||||
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author:
|
||||
# Realtek NIC software team <nicfae@realtek.com>
|
||||
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
|
||||
#
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
/************************************************************************************
|
||||
* This product is covered by one or more of the following patents:
|
||||
* US6,570,884, US6,115,776, and US6,327,625.
|
||||
***********************************************************************************/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include "r8126.h"
|
||||
#include "rtl_eeprom.h"
|
||||
#include "rtltool.h"
|
||||
|
||||
int rtl8126_tool_ioctl(struct rtl8126_private *tp, struct ifreq *ifr)
|
||||
{
|
||||
struct rtltool_cmd my_cmd;
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(&my_cmd, ifr->ifr_data, sizeof(my_cmd)))
|
||||
return -EFAULT;
|
||||
|
||||
ret = 0;
|
||||
switch (my_cmd.cmd) {
|
||||
case RTLTOOL_READ_MAC:
|
||||
if (my_cmd.len==1)
|
||||
my_cmd.data = readb(tp->mmio_addr+my_cmd.offset);
|
||||
else if (my_cmd.len==2)
|
||||
my_cmd.data = readw(tp->mmio_addr+(my_cmd.offset&~1));
|
||||
else if (my_cmd.len==4)
|
||||
my_cmd.data = readl(tp->mmio_addr+(my_cmd.offset&~3));
|
||||
else {
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case RTLTOOL_WRITE_MAC:
|
||||
if (my_cmd.len==1)
|
||||
writeb(my_cmd.data, tp->mmio_addr+my_cmd.offset);
|
||||
else if (my_cmd.len==2)
|
||||
writew(my_cmd.data, tp->mmio_addr+(my_cmd.offset&~1));
|
||||
else if (my_cmd.len==4)
|
||||
writel(my_cmd.data, tp->mmio_addr+(my_cmd.offset&~3));
|
||||
else {
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RTLTOOL_READ_PHY:
|
||||
my_cmd.data = rtl8126_mdio_prot_read(tp, my_cmd.offset);
|
||||
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RTLTOOL_WRITE_PHY:
|
||||
rtl8126_mdio_prot_write(tp, my_cmd.offset, my_cmd.data);
|
||||
break;
|
||||
|
||||
case RTLTOOL_READ_EPHY:
|
||||
my_cmd.data = rtl8126_ephy_read(tp, my_cmd.offset);
|
||||
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RTLTOOL_WRITE_EPHY:
|
||||
rtl8126_ephy_write(tp, my_cmd.offset, my_cmd.data);
|
||||
break;
|
||||
|
||||
case RTLTOOL_READ_ERI:
|
||||
my_cmd.data = 0;
|
||||
if (my_cmd.len==1 || my_cmd.len==2 || my_cmd.len==4) {
|
||||
my_cmd.data = rtl8126_eri_read(tp, my_cmd.offset, my_cmd.len, ERIAR_ExGMAC);
|
||||
} else {
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RTLTOOL_WRITE_ERI:
|
||||
if (my_cmd.len==1 || my_cmd.len==2 || my_cmd.len==4) {
|
||||
rtl8126_eri_write(tp, my_cmd.offset, my_cmd.len, my_cmd.data, ERIAR_ExGMAC);
|
||||
} else {
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case RTLTOOL_READ_PCI:
|
||||
my_cmd.data = 0;
|
||||
if (my_cmd.len==1)
|
||||
pci_read_config_byte(tp->pci_dev, my_cmd.offset,
|
||||
(u8 *)&my_cmd.data);
|
||||
else if (my_cmd.len==2)
|
||||
pci_read_config_word(tp->pci_dev, my_cmd.offset,
|
||||
(u16 *)&my_cmd.data);
|
||||
else if (my_cmd.len==4)
|
||||
pci_read_config_dword(tp->pci_dev, my_cmd.offset,
|
||||
&my_cmd.data);
|
||||
else {
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case RTLTOOL_WRITE_PCI:
|
||||
if (my_cmd.len==1)
|
||||
pci_write_config_byte(tp->pci_dev, my_cmd.offset,
|
||||
my_cmd.data);
|
||||
else if (my_cmd.len==2)
|
||||
pci_write_config_word(tp->pci_dev, my_cmd.offset,
|
||||
my_cmd.data);
|
||||
else if (my_cmd.len==4)
|
||||
pci_write_config_dword(tp->pci_dev, my_cmd.offset,
|
||||
my_cmd.data);
|
||||
else {
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RTLTOOL_READ_EEPROM:
|
||||
my_cmd.data = rtl8126_eeprom_read_sc(tp, my_cmd.offset);
|
||||
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RTLTOOL_WRITE_EEPROM:
|
||||
rtl8126_eeprom_write_sc(tp, my_cmd.offset, my_cmd.data);
|
||||
break;
|
||||
|
||||
case RTL_READ_OOB_MAC:
|
||||
rtl8126_oob_mutex_lock(tp);
|
||||
my_cmd.data = rtl8126_ocp_read(tp, my_cmd.offset, 4);
|
||||
rtl8126_oob_mutex_unlock(tp);
|
||||
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case RTL_WRITE_OOB_MAC:
|
||||
if (my_cmd.len == 0 || my_cmd.len > 4)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
rtl8126_oob_mutex_lock(tp);
|
||||
rtl8126_ocp_write(tp, my_cmd.offset, my_cmd.len, my_cmd.data);
|
||||
rtl8126_oob_mutex_unlock(tp);
|
||||
break;
|
||||
|
||||
case RTL_ENABLE_PCI_DIAG:
|
||||
tp->rtk_enable_diag = 1;
|
||||
|
||||
dprintk("enable rtk diag\n");
|
||||
break;
|
||||
|
||||
case RTL_DISABLE_PCI_DIAG:
|
||||
tp->rtk_enable_diag = 0;
|
||||
|
||||
dprintk("disable rtk diag\n");
|
||||
break;
|
||||
|
||||
case RTL_READ_MAC_OCP:
|
||||
if (my_cmd.offset % 2)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
my_cmd.data = rtl8126_mac_ocp_read(tp, my_cmd.offset);
|
||||
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case RTL_WRITE_MAC_OCP:
|
||||
if ((my_cmd.offset % 2) || (my_cmd.len != 2))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
rtl8126_mac_ocp_write(tp, my_cmd.offset, (u16)my_cmd.data);
|
||||
break;
|
||||
|
||||
case RTL_DIRECT_READ_PHY_OCP:
|
||||
my_cmd.data = rtl8126_mdio_prot_direct_read_phy_ocp(tp, my_cmd.offset);
|
||||
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RTL_DIRECT_WRITE_PHY_OCP:
|
||||
rtl8126_mdio_prot_direct_write_phy_ocp(tp, my_cmd.offset, my_cmd.data);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
86
drivers/net/ethernet/realtek/r8126/rtltool.h
Normal file
86
drivers/net/ethernet/realtek/r8126/rtltool.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
################################################################################
|
||||
#
|
||||
# r8126 is the Linux device driver released for Realtek 5 Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author:
|
||||
# Realtek NIC software team <nicfae@realtek.com>
|
||||
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
|
||||
#
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
/************************************************************************************
|
||||
* This product is covered by one or more of the following patents:
|
||||
* US6,570,884, US6,115,776, and US6,327,625.
|
||||
***********************************************************************************/
|
||||
|
||||
#ifndef _LINUX_RTLTOOL_H
|
||||
#define _LINUX_RTLTOOL_H
|
||||
|
||||
#define SIOCRTLTOOL SIOCDEVPRIVATE+1
|
||||
|
||||
enum rtl_cmd {
|
||||
RTLTOOL_READ_MAC=0,
|
||||
RTLTOOL_WRITE_MAC,
|
||||
RTLTOOL_READ_PHY,
|
||||
RTLTOOL_WRITE_PHY,
|
||||
RTLTOOL_READ_EPHY,
|
||||
RTLTOOL_WRITE_EPHY,
|
||||
RTLTOOL_READ_ERI,
|
||||
RTLTOOL_WRITE_ERI,
|
||||
RTLTOOL_READ_PCI,
|
||||
RTLTOOL_WRITE_PCI,
|
||||
RTLTOOL_READ_EEPROM,
|
||||
RTLTOOL_WRITE_EEPROM,
|
||||
|
||||
RTL_READ_OOB_MAC,
|
||||
RTL_WRITE_OOB_MAC,
|
||||
|
||||
RTL_ENABLE_PCI_DIAG,
|
||||
RTL_DISABLE_PCI_DIAG,
|
||||
|
||||
RTL_READ_MAC_OCP,
|
||||
RTL_WRITE_MAC_OCP,
|
||||
|
||||
RTL_DIRECT_READ_PHY_OCP,
|
||||
RTL_DIRECT_WRITE_PHY_OCP,
|
||||
|
||||
RTLTOOL_INVALID
|
||||
};
|
||||
|
||||
struct rtltool_cmd {
|
||||
__u32 cmd;
|
||||
__u32 offset;
|
||||
__u32 len;
|
||||
__u32 data;
|
||||
};
|
||||
|
||||
enum mode_access {
|
||||
MODE_NONE=0,
|
||||
MODE_READ,
|
||||
MODE_WRITE
|
||||
};
|
||||
|
||||
#ifdef __KERNEL__
|
||||
int rtl8126_tool_ioctl(struct rtl8126_private *tp, struct ifreq *ifr);
|
||||
#endif
|
||||
|
||||
#endif /* _LINUX_RTLTOOL_H */
|
||||
205
drivers/net/ethernet/realtek/r8168/Makefile
Normal file
205
drivers/net/ethernet/realtek/r8168/Makefile
Normal file
@@ -0,0 +1,205 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
################################################################################
|
||||
#
|
||||
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author:
|
||||
# Realtek NIC software team <nicfae@realtek.com>
|
||||
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
|
||||
#
|
||||
################################################################################
|
||||
|
||||
################################################################################
|
||||
# This product is covered by one or more of the following patents:
|
||||
# US6,570,884, US6,115,776, and US6,327,625.
|
||||
################################################################################
|
||||
|
||||
LINUX_VERSION := $(shell expr $(VERSION) \* 256 + $(PATCHLEVEL))
|
||||
LINUX_VERSION_6_9 := $(shell expr 6 \* 256 + 9)
|
||||
|
||||
# Use dummy R8168 driver for K69 and later
|
||||
ifeq ($(shell test $(LINUX_VERSION) -ge $(LINUX_VERSION_6_9); echo $$?),0)
|
||||
obj-m := r8168.o
|
||||
r8168-objs := r8168_dummy.o
|
||||
else
|
||||
|
||||
CONFIG_SOC_LAN = n
|
||||
ENABLE_FIBER_SUPPORT = n
|
||||
ENABLE_REALWOW_SUPPORT = n
|
||||
ENABLE_DASH_SUPPORT = n
|
||||
ENABLE_DASH_PRINTER_SUPPORT = n
|
||||
CONFIG_DOWN_SPEED_100 = n
|
||||
CONFIG_ASPM = y
|
||||
ENABLE_S5WOL = y
|
||||
ENABLE_S5_KEEP_CURR_MAC = n
|
||||
ENABLE_EEE = y
|
||||
ENABLE_S0_MAGIC_PACKET = n
|
||||
CONFIG_DYNAMIC_ASPM = y
|
||||
ENABLE_USE_FIRMWARE_FILE = n
|
||||
CONFIG_CTAP_SHORT_OFF = n
|
||||
ENABLE_MULTIPLE_TX_QUEUE = n
|
||||
ENABLE_RSS_SUPPORT = n
|
||||
ENABLE_LIB_SUPPORT = n
|
||||
DISABLE_WOL_SUPPORT = n
|
||||
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m := r8168.o
|
||||
r8168-objs := r8168_n.o r8168_asf.o rtl_eeprom.o rtltool.o
|
||||
ifeq ($(CONFIG_SOC_LAN), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_SOC_LAN
|
||||
endif
|
||||
ifeq ($(ENABLE_FIBER_SUPPORT), y)
|
||||
r8168-objs += r8168_fiber.o
|
||||
EXTRA_CFLAGS += -DENABLE_FIBER_SUPPORT
|
||||
endif
|
||||
ifeq ($(ENABLE_REALWOW_SUPPORT), y)
|
||||
r8168-objs += r8168_realwow.o
|
||||
EXTRA_CFLAGS += -DENABLE_REALWOW_SUPPORT
|
||||
endif
|
||||
ifeq ($(ENABLE_DASH_SUPPORT), y)
|
||||
r8168-objs += r8168_dash.o
|
||||
EXTRA_CFLAGS += -DENABLE_DASH_SUPPORT
|
||||
endif
|
||||
ifeq ($(ENABLE_DASH_PRINTER_SUPPORT), y)
|
||||
r8168-objs += r8168_dash.o
|
||||
EXTRA_CFLAGS += -DENABLE_DASH_SUPPORT -DENABLE_DASH_PRINTER_SUPPORT
|
||||
endif
|
||||
ifneq ($(ENABLE_RSS_SUPPORT), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_R8168_NAPI
|
||||
endif
|
||||
EXTRA_CFLAGS += -DCONFIG_R8168_VLAN
|
||||
ifeq ($(CONFIG_DOWN_SPEED_100), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_DOWN_SPEED_100
|
||||
endif
|
||||
ifeq ($(CONFIG_ASPM), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_ASPM
|
||||
endif
|
||||
ifeq ($(ENABLE_S5WOL), y)
|
||||
EXTRA_CFLAGS += -DENABLE_S5WOL
|
||||
endif
|
||||
ifeq ($(ENABLE_S5_KEEP_CURR_MAC), y)
|
||||
EXTRA_CFLAGS += -DENABLE_S5_KEEP_CURR_MAC
|
||||
endif
|
||||
ifeq ($(ENABLE_EEE), y)
|
||||
EXTRA_CFLAGS += -DENABLE_EEE
|
||||
endif
|
||||
ifeq ($(ENABLE_S0_MAGIC_PACKET), y)
|
||||
EXTRA_CFLAGS += -DENABLE_S0_MAGIC_PACKET
|
||||
endif
|
||||
ifeq ($(CONFIG_DYNAMIC_ASPM), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_DYNAMIC_ASPM
|
||||
endif
|
||||
ifeq ($(ENABLE_USE_FIRMWARE_FILE), y)
|
||||
r8168-objs += r8168_firmware.o
|
||||
EXTRA_CFLAGS += -DENABLE_USE_FIRMWARE_FILE
|
||||
endif
|
||||
ifeq ($(CONFIG_CTAP_SHORT_OFF), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_CTAP_SHORT_OFF
|
||||
endif
|
||||
ifeq ($(ENABLE_MULTIPLE_TX_QUEUE), y)
|
||||
EXTRA_CFLAGS += -DENABLE_MULTIPLE_TX_QUEUE
|
||||
endif
|
||||
ifeq ($(ENABLE_RSS_SUPPORT), y)
|
||||
r8168-objs += r8168_rss.o
|
||||
EXTRA_CFLAGS += -DENABLE_RSS_SUPPORT
|
||||
endif
|
||||
ifeq ($(ENABLE_LIB_SUPPORT), y)
|
||||
r8168-objs += r8168_lib.o
|
||||
EXTRA_CFLAGS += -DENABLE_LIB_SUPPORT
|
||||
endif
|
||||
ifeq ($(DISABLE_WOL_SUPPORT), y)
|
||||
EXTRA_CFLAGS += -DDISABLE_WOL_SUPPORT
|
||||
endif
|
||||
else
|
||||
BASEDIR := /lib/modules/$(shell uname -r)
|
||||
KERNELDIR ?= $(BASEDIR)/build
|
||||
PWD :=$(shell pwd)
|
||||
DRIVERDIR := $(shell find $(BASEDIR)/kernel/drivers/net/ethernet -name realtek -type d)
|
||||
ifeq ($(DRIVERDIR),)
|
||||
DRIVERDIR := $(shell find $(BASEDIR)/kernel/drivers/net -name realtek -type d)
|
||||
endif
|
||||
ifeq ($(DRIVERDIR),)
|
||||
DRIVERDIR := $(BASEDIR)/kernel/drivers/net
|
||||
endif
|
||||
RTKDIR := $(subst $(BASEDIR)/,,$(DRIVERDIR))
|
||||
|
||||
KERNEL_GCC_VERSION := $(shell cat /proc/version | sed -n 's/.*gcc version \([[:digit:]]\.[[:digit:]]\.[[:digit:]]\).*/\1/p')
|
||||
CCVERSION = $(shell $(CC) -dumpversion)
|
||||
|
||||
KVER = $(shell uname -r)
|
||||
KMAJ = $(shell echo $(KVER) | \
|
||||
sed -e 's/^\([0-9][0-9]*\)\.[0-9][0-9]*\.[0-9][0-9]*.*/\1/')
|
||||
KMIN = $(shell echo $(KVER) | \
|
||||
sed -e 's/^[0-9][0-9]*\.\([0-9][0-9]*\)\.[0-9][0-9]*.*/\1/')
|
||||
KREV = $(shell echo $(KVER) | \
|
||||
sed -e 's/^[0-9][0-9]*\.[0-9][0-9]*\.\([0-9][0-9]*\).*/\1/')
|
||||
|
||||
kver_ge = $(shell \
|
||||
echo test | awk '{if($(KMAJ) < $(1)) {print 0} else { \
|
||||
if($(KMAJ) > $(1)) {print 1} else { \
|
||||
if($(KMIN) < $(2)) {print 0} else { \
|
||||
if($(KMIN) > $(2)) {print 1} else { \
|
||||
if($(KREV) < $(3)) {print 0} else { print 1 } \
|
||||
}}}}}' \
|
||||
)
|
||||
|
||||
.PHONY: all
|
||||
all: print_vars clean modules install
|
||||
|
||||
print_vars:
|
||||
@echo
|
||||
@echo "CC: " $(CC)
|
||||
@echo "CCVERSION: " $(CCVERSION)
|
||||
@echo "KERNEL_GCC_VERSION: " $(KERNEL_GCC_VERSION)
|
||||
@echo "KVER: " $(KVER)
|
||||
@echo "KMAJ: " $(KMAJ)
|
||||
@echo "KMIN: " $(KMIN)
|
||||
@echo "KREV: " $(KREV)
|
||||
@echo "BASEDIR: " $(BASEDIR)
|
||||
@echo "DRIVERDIR: " $(DRIVERDIR)
|
||||
@echo "PWD: " $(PWD)
|
||||
@echo "RTKDIR: " $(RTKDIR)
|
||||
@echo
|
||||
|
||||
.PHONY:modules
|
||||
modules:
|
||||
#ifeq ($(call kver_ge,5,0,0),1)
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
|
||||
#else
|
||||
# $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) modules
|
||||
#endif
|
||||
|
||||
.PHONY:clean
|
||||
clean:
|
||||
#ifeq ($(call kver_ge,5,0,0),1)
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
|
||||
#else
|
||||
# $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) clean
|
||||
#endif
|
||||
|
||||
.PHONY:install
|
||||
install:
|
||||
#ifeq ($(call kver_ge,5,0,0),1)
|
||||
$(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_DIR=$(RTKDIR) modules_install
|
||||
#else
|
||||
# $(MAKE) -C $(KERNELDIR) SUBDIRS=$(PWD) INSTALL_MOD_DIR=$(RTKDIR) modules_install
|
||||
#endif
|
||||
|
||||
endif
|
||||
endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@
|
||||
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2022 Realtek Semiconductor Corp. All rights reserved.
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
@@ -60,7 +60,6 @@ int rtl8168_asf_ioctl(struct net_device *dev,
|
||||
struct rtl8168_private *tp = netdev_priv(dev);
|
||||
void *user_data = ifr->ifr_data;
|
||||
struct asf_ioctl_struct asf_usrdata;
|
||||
unsigned long flags;
|
||||
|
||||
if (tp->mcfg != CFG_METHOD_7 && tp->mcfg != CFG_METHOD_8)
|
||||
return -EOPNOTSUPP;
|
||||
@@ -68,8 +67,6 @@ int rtl8168_asf_ioctl(struct net_device *dev,
|
||||
if (copy_from_user(&asf_usrdata, user_data, sizeof(struct asf_ioctl_struct)))
|
||||
return -EFAULT;
|
||||
|
||||
spin_lock_irqsave(&tp->lock, flags);
|
||||
|
||||
switch (asf_usrdata.offset) {
|
||||
case HBPeriod:
|
||||
rtl8168_asf_hbperiod(tp, asf_usrdata.arg, asf_usrdata.u.data);
|
||||
@@ -192,12 +189,9 @@ int rtl8168_asf_ioctl(struct net_device *dev,
|
||||
rtl8168_asf_key_access(tp, asf_usrdata.arg, KR, asf_usrdata.u.data);
|
||||
break;
|
||||
default:
|
||||
spin_unlock_irqrestore(&tp->lock, flags);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&tp->lock, flags);
|
||||
|
||||
if (copy_to_user(user_data, &asf_usrdata, sizeof(struct asf_ioctl_struct)))
|
||||
return -EFAULT;
|
||||
|
||||
@@ -390,10 +384,10 @@ void rtl8168_asf_rw_systemid(struct rtl8168_private *tp, int arg, unsigned int *
|
||||
int i;
|
||||
|
||||
if (arg == ASF_GET)
|
||||
for (i = 0; i < SYSID_LEN ; i++)
|
||||
for (i = 0; i < SYSID_LEN; i++)
|
||||
data[i] = rtl8168_eri_read(tp, SysID + i, RW_ONE_BYTE, ERIAR_ASF);
|
||||
else /* arg == ASF_SET */
|
||||
for (i = 0; i < SYSID_LEN ; i++)
|
||||
for (i = 0; i < SYSID_LEN; i++)
|
||||
rtl8168_eri_write(tp, SysID + i, RW_ONE_BYTE, data[i], ERIAR_ASF);
|
||||
}
|
||||
|
||||
@@ -414,9 +408,9 @@ void rtl8168_asf_rw_uuid(struct rtl8168_private *tp, int arg, unsigned int *data
|
||||
int i, j;
|
||||
|
||||
if (arg == ASF_GET)
|
||||
for (i = UUID_LEN - 1, j = 0; i >= 0 ; i--, j++)
|
||||
for (i = UUID_LEN - 1, j = 0; i >= 0; i--, j++)
|
||||
data[j] = rtl8168_eri_read(tp, UUID + i, RW_ONE_BYTE, ERIAR_ASF);
|
||||
else /* arg == ASF_SET */
|
||||
for (i = UUID_LEN - 1, j = 0; i >= 0 ; i--, j++)
|
||||
for (i = UUID_LEN - 1, j = 0; i >= 0; i--, j++)
|
||||
rtl8168_eri_write(tp, UUID + i, RW_ONE_BYTE, data[j], ERIAR_ASF);
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2022 Realtek Semiconductor Corp. All rights reserved.
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
@@ -5,7 +5,7 @@
|
||||
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2022 Realtek Semiconductor Corp. All rights reserved.
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
@@ -247,6 +247,7 @@ RX_DASH_BUFFER_TYPE_2, *PRX_DASH_BUFFER_TYPE_2;
|
||||
#define RTL_CMAC_R32(tp, reg) ((unsigned long) readl (tp->cmac_ioaddr + (reg)))
|
||||
|
||||
int rtl8168_dash_ioctl(struct net_device *dev, struct ifreq *ifr);
|
||||
bool CheckDashInterrupt(struct net_device *dev, u16 status);
|
||||
void HandleDashInterrupt(struct net_device *dev);
|
||||
int AllocateDashShareMemory(struct net_device *dev);
|
||||
void FreeAllocatedDashShareMemory(struct net_device *dev);
|
||||
16
drivers/net/ethernet/realtek/r8168/r8168_dummy.c
Normal file
16
drivers/net/ethernet/realtek/r8168/r8168_dummy.c
Normal file
@@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
/* Dummy implementation for module */
|
||||
static int __init r8168_dummy_dummy_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
device_initcall(r8168_dummy_dummy_init);
|
||||
|
||||
MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
|
||||
MODULE_DESCRIPTION("Dummy R8168 dummy driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -5,7 +5,7 @@
|
||||
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2022 Realtek Semiconductor Corp. All rights reserved.
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
@@ -5,7 +5,7 @@
|
||||
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2022 Realtek Semiconductor Corp. All rights reserved.
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
@@ -5,7 +5,7 @@
|
||||
# r8168 is the Linux device driver released for Realtek 2.5Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2022 Realtek Semiconductor Corp. All rights reserved.
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@
|
||||
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2022 Realtek Semiconductor Corp. All rights reserved.
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
500
drivers/net/ethernet/realtek/r8168/r8168_rss.c
Normal file
500
drivers/net/ethernet/realtek/r8168/r8168_rss.c
Normal file
@@ -0,0 +1,500 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
################################################################################
|
||||
#
|
||||
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author:
|
||||
# Realtek NIC software team <nicfae@realtek.com>
|
||||
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
|
||||
#
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
/************************************************************************************
|
||||
* This product is covered by one or more of the following patents:
|
||||
* US6,570,884, US6,115,776, and US6,327,625.
|
||||
***********************************************************************************/
|
||||
|
||||
#include <linux/version.h>
|
||||
#include "r8168.h"
|
||||
|
||||
enum rtl8168_rss_register_content {
|
||||
/* RSS */
|
||||
RSS_CTRL_TCP_IPV4_SUPP = (1 << 0),
|
||||
RSS_CTRL_IPV4_SUPP = (1 << 1),
|
||||
RSS_CTRL_TCP_IPV6_SUPP = (1 << 2),
|
||||
RSS_CTRL_IPV6_SUPP = (1 << 3),
|
||||
RSS_CTRL_IPV6_EXT_SUPP = (1 << 4),
|
||||
RSS_CTRL_TCP_IPV6_EXT_SUPP = (1 << 5),
|
||||
RSS_HALF_SUPP = (1 << 7),
|
||||
RSS_QUAD_CPU_EN = (1 << 16),
|
||||
RSS_HQ_Q_SUP_R = (1 << 31),
|
||||
};
|
||||
|
||||
static int rtl8168_get_rss_hash_opts(struct rtl8168_private *tp,
|
||||
struct ethtool_rxnfc *cmd)
|
||||
{
|
||||
cmd->data = 0;
|
||||
|
||||
/* Report default options for RSS */
|
||||
switch (cmd->flow_type) {
|
||||
case TCP_V4_FLOW:
|
||||
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
||||
fallthrough;
|
||||
case IPV4_FLOW:
|
||||
cmd->data |= RXH_IP_SRC | RXH_IP_DST;
|
||||
break;
|
||||
case TCP_V6_FLOW:
|
||||
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
||||
fallthrough;
|
||||
case IPV6_FLOW:
|
||||
cmd->data |= RXH_IP_SRC | RXH_IP_DST;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtl8168_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
|
||||
u32 *rule_locs)
|
||||
{
|
||||
struct rtl8168_private *tp = netdev_priv(dev);
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
netif_info(tp, drv, tp->dev, "rss get rxnfc\n");
|
||||
|
||||
if (!(dev->features & NETIF_F_RXHASH))
|
||||
return ret;
|
||||
|
||||
switch (cmd->cmd) {
|
||||
case ETHTOOL_GRXRINGS:
|
||||
cmd->data = rtl8168_tot_rx_rings(tp);
|
||||
ret = 0;
|
||||
break;
|
||||
case ETHTOOL_GRXFH:
|
||||
ret = rtl8168_get_rss_hash_opts(tp, cmd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 rtl8168_rss_indir_tbl_entries(struct rtl8168_private *tp)
|
||||
{
|
||||
return tp->HwSuppIndirTblEntries;
|
||||
}
|
||||
|
||||
#define RSS_MASK_BITS_OFFSET (8)
|
||||
static int _rtl8168_set_rss_hash_opt(struct rtl8168_private *tp)
|
||||
{
|
||||
u32 hash_mask_len;
|
||||
u32 rss_ctrl;
|
||||
|
||||
/* Perform hash on these packet types */
|
||||
rss_ctrl = RSS_CTRL_TCP_IPV4_SUPP
|
||||
| RSS_CTRL_IPV4_SUPP
|
||||
| RSS_CTRL_IPV6_SUPP
|
||||
| RSS_CTRL_IPV6_EXT_SUPP
|
||||
| RSS_CTRL_TCP_IPV6_SUPP
|
||||
| RSS_CTRL_TCP_IPV6_EXT_SUPP;
|
||||
|
||||
if (R8168_MULTI_RSS_4Q(tp))
|
||||
rss_ctrl |= RSS_QUAD_CPU_EN;
|
||||
|
||||
hash_mask_len = ilog2(rtl8168_rss_indir_tbl_entries(tp));
|
||||
hash_mask_len &= (BIT_0 | BIT_1 | BIT_2);
|
||||
rss_ctrl |= hash_mask_len << RSS_MASK_BITS_OFFSET;
|
||||
|
||||
rtl8168_eri_write(tp, RSS_CTRL_8168, 4, rss_ctrl, ERIAR_ExGMAC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtl8168_set_rss_hash_opt(struct rtl8168_private *tp,
|
||||
struct ethtool_rxnfc *nfc)
|
||||
{
|
||||
u32 rss_flags = tp->rss_flags;
|
||||
|
||||
netif_info(tp, drv, tp->dev, "rss set hash\n");
|
||||
|
||||
/*
|
||||
* RSS does not support anything other than hashing
|
||||
* to queues on src and dst IPs and ports
|
||||
*/
|
||||
if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
|
||||
RXH_L4_B_0_1 | RXH_L4_B_2_3))
|
||||
return -EINVAL;
|
||||
|
||||
switch (nfc->flow_type) {
|
||||
case TCP_V4_FLOW:
|
||||
case TCP_V6_FLOW:
|
||||
if (!(nfc->data & RXH_IP_SRC) ||
|
||||
!(nfc->data & RXH_IP_DST) ||
|
||||
!(nfc->data & RXH_L4_B_0_1) ||
|
||||
!(nfc->data & RXH_L4_B_2_3))
|
||||
return -EINVAL;
|
||||
break;
|
||||
case SCTP_V4_FLOW:
|
||||
case AH_ESP_V4_FLOW:
|
||||
case AH_V4_FLOW:
|
||||
case ESP_V4_FLOW:
|
||||
case SCTP_V6_FLOW:
|
||||
case AH_ESP_V6_FLOW:
|
||||
case AH_V6_FLOW:
|
||||
case ESP_V6_FLOW:
|
||||
case IP_USER_FLOW:
|
||||
case ETHER_FLOW:
|
||||
/* RSS is not supported for these protocols */
|
||||
if (nfc->data) {
|
||||
netif_err(tp, drv, tp->dev, "Command parameters not supported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* if we changed something we need to update flags */
|
||||
if (rss_flags != tp->rss_flags) {
|
||||
u32 rss_ctrl = rtl8168_eri_read(tp, RSS_CTRL_8168, 4, ERIAR_ExGMAC);
|
||||
|
||||
tp->rss_flags = rss_flags;
|
||||
|
||||
/* Perform hash on these packet types */
|
||||
rss_ctrl |= RSS_CTRL_TCP_IPV4_SUPP
|
||||
| RSS_CTRL_IPV4_SUPP
|
||||
| RSS_CTRL_IPV6_SUPP
|
||||
| RSS_CTRL_IPV6_EXT_SUPP
|
||||
| RSS_CTRL_TCP_IPV6_SUPP
|
||||
| RSS_CTRL_TCP_IPV6_EXT_SUPP;
|
||||
|
||||
if (R8168_MULTI_RSS_4Q(tp))
|
||||
rss_ctrl |= RSS_QUAD_CPU_EN;
|
||||
else
|
||||
rss_ctrl &= ~RSS_QUAD_CPU_EN;
|
||||
|
||||
rtl8168_eri_write(tp, RSS_CTRL_8168, 4, rss_ctrl, ERIAR_ExGMAC);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtl8168_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
|
||||
{
|
||||
struct rtl8168_private *tp = netdev_priv(dev);
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
netif_info(tp, drv, tp->dev, "rss set rxnfc\n");
|
||||
|
||||
if (!(dev->features & NETIF_F_RXHASH))
|
||||
return ret;
|
||||
|
||||
switch (cmd->cmd) {
|
||||
case ETHTOOL_SRXFH:
|
||||
ret = rtl8168_set_rss_hash_opt(tp, cmd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 _rtl8168_get_rxfh_key_size(struct rtl8168_private *tp)
|
||||
{
|
||||
return sizeof(tp->rss_key);
|
||||
}
|
||||
|
||||
u32 rtl8168_get_rxfh_key_size(struct net_device *dev)
|
||||
{
|
||||
struct rtl8168_private *tp = netdev_priv(dev);
|
||||
|
||||
netif_info(tp, drv, tp->dev, "rss get key size\n");
|
||||
|
||||
if (!(dev->features & NETIF_F_RXHASH))
|
||||
return 0;
|
||||
|
||||
return _rtl8168_get_rxfh_key_size(tp);
|
||||
}
|
||||
|
||||
u32 rtl8168_rss_indir_size(struct net_device *dev)
|
||||
{
|
||||
struct rtl8168_private *tp = netdev_priv(dev);
|
||||
|
||||
netif_info(tp, drv, tp->dev, "rss get indir tbl size\n");
|
||||
|
||||
if (!(dev->features & NETIF_F_RXHASH))
|
||||
return 0;
|
||||
|
||||
return rtl8168_rss_indir_tbl_entries(tp);
|
||||
}
|
||||
|
||||
static void rtl8168_get_reta(struct rtl8168_private *tp, u32 *indir)
|
||||
{
|
||||
int i, reta_size = rtl8168_rss_indir_tbl_entries(tp);
|
||||
|
||||
for (i = 0; i < reta_size; i++)
|
||||
indir[i] = tp->rss_indir_tbl[i];
|
||||
}
|
||||
|
||||
static u32 rtl8168_rss_key_reg(struct rtl8168_private *tp)
|
||||
{
|
||||
return RSS_KEY_8168;
|
||||
}
|
||||
|
||||
static u32 rtl8168_rss_indir_tbl_reg(struct rtl8168_private *tp)
|
||||
{
|
||||
return Rss_indir_tbl;
|
||||
}
|
||||
|
||||
static void rtl8168_store_reta(struct rtl8168_private *tp)
|
||||
{
|
||||
u32 reta_entries = rtl8168_rss_indir_tbl_entries(tp);
|
||||
u16 indir_tbl_reg = rtl8168_rss_indir_tbl_reg(tp);
|
||||
u32 hw_indir[RTL8168_RSS_INDIR_TBL_SIZE] = {0};
|
||||
u8 *indir = tp->rss_indir_tbl;
|
||||
u32 bit_on_cnt = 0x00000001;
|
||||
u32 i, j;
|
||||
|
||||
/* Mapping redirection table to HW */
|
||||
for (i = 0, j = 0; i < reta_entries; i++) {
|
||||
if ((indir[i] & 2) && R8168_MULTI_RSS_4Q(tp))
|
||||
hw_indir[j + 4] |= bit_on_cnt;
|
||||
if (indir[i] & 1)
|
||||
hw_indir[j] |= bit_on_cnt;
|
||||
|
||||
if (bit_on_cnt == 0x80000000) {
|
||||
bit_on_cnt = 0x00000001;
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
bit_on_cnt <<= 1;
|
||||
}
|
||||
|
||||
/* Write redirection table to HW */
|
||||
for (i = 0; i < RTL8168_RSS_INDIR_TBL_SIZE; i++)
|
||||
RTL_W32(tp, indir_tbl_reg + i*4, hw_indir[i]);
|
||||
}
|
||||
|
||||
static void rtl8168_store_rss_key(struct rtl8168_private *tp)
|
||||
{
|
||||
const u16 rss_key_reg = rtl8168_rss_key_reg(tp);
|
||||
u32 i, rss_key_size = _rtl8168_get_rxfh_key_size(tp);
|
||||
u32 *rss_key = (u32*)tp->rss_key;
|
||||
|
||||
/* Write redirection table to HW */
|
||||
for (i = 0; i < rss_key_size; i+=4)
|
||||
rtl8168_eri_write(tp, rss_key_reg + i, 4, *rss_key++, ERIAR_ExGMAC);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,8,0)
|
||||
int rtl8168_get_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh)
|
||||
{
|
||||
struct rtl8168_private *tp = netdev_priv(dev);
|
||||
|
||||
netif_info(tp, drv, tp->dev, "rss get rxfh\n");
|
||||
|
||||
if (!(dev->features & NETIF_F_RXHASH))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
rxfh->hfunc = ETH_RSS_HASH_TOP;
|
||||
|
||||
if (rxfh->indir)
|
||||
rtl8168_get_reta(tp, rxfh->indir);
|
||||
|
||||
if (rxfh->key)
|
||||
memcpy(rxfh->key, tp->rss_key, RTL8168_RSS_KEY_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtl8168_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct rtl8168_private *tp = netdev_priv(dev);
|
||||
u32 reta_entries = rtl8168_rss_indir_tbl_entries(tp);
|
||||
int i;
|
||||
|
||||
netif_info(tp, drv, tp->dev, "rss set rxfh\n");
|
||||
|
||||
/* We require at least one supported parameter to be changed and no
|
||||
* change in any of the unsupported parameters
|
||||
*/
|
||||
if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE && rxfh->hfunc != ETH_RSS_HASH_TOP)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Fill out the redirection table */
|
||||
if (rxfh->indir) {
|
||||
int max_queues = tp->num_rx_rings;
|
||||
|
||||
/* Verify user input. */
|
||||
for (i = 0; i < reta_entries; i++)
|
||||
if (rxfh->indir[i] >= max_queues)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < reta_entries; i++)
|
||||
tp->rss_indir_tbl[i] = rxfh->indir[i];
|
||||
}
|
||||
|
||||
/* Fill out the rss hash key */
|
||||
if (rxfh->key)
|
||||
memcpy(tp->rss_key, rxfh->key, RTL8168_RSS_KEY_SIZE);
|
||||
|
||||
rtl8168_store_reta(tp);
|
||||
|
||||
rtl8168_store_rss_key(tp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int rtl8168_get_rxfh(struct net_device *dev, u32 *indir, u8 *key,
|
||||
u8 *hfunc)
|
||||
{
|
||||
struct rtl8168_private *tp = netdev_priv(dev);
|
||||
|
||||
netif_info(tp, drv, tp->dev, "rss get rxfh\n");
|
||||
|
||||
if (!(dev->features & NETIF_F_RXHASH))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (hfunc)
|
||||
*hfunc = ETH_RSS_HASH_TOP;
|
||||
|
||||
if (indir)
|
||||
rtl8168_get_reta(tp, indir);
|
||||
|
||||
if (key)
|
||||
memcpy(key, tp->rss_key, RTL8168_RSS_KEY_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtl8168_set_rxfh(struct net_device *dev, const u32 *indir,
|
||||
const u8 *key, const u8 hfunc)
|
||||
{
|
||||
struct rtl8168_private *tp = netdev_priv(dev);
|
||||
u32 reta_entries = rtl8168_rss_indir_tbl_entries(tp);
|
||||
int i;
|
||||
|
||||
netif_info(tp, drv, tp->dev, "rss set rxfh\n");
|
||||
|
||||
/* We require at least one supported parameter to be changed and no
|
||||
* change in any of the unsupported parameters
|
||||
*/
|
||||
if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Fill out the redirection table */
|
||||
if (indir) {
|
||||
int max_queues = tp->num_rx_rings;
|
||||
|
||||
/* Verify user input. */
|
||||
for (i = 0; i < reta_entries; i++)
|
||||
if (indir[i] >= max_queues)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < reta_entries; i++)
|
||||
tp->rss_indir_tbl[i] = indir[i];
|
||||
}
|
||||
|
||||
/* Fill out the rss hash key */
|
||||
if (key)
|
||||
memcpy(tp->rss_key, key, RTL8168_RSS_KEY_SIZE);
|
||||
|
||||
rtl8168_store_reta(tp);
|
||||
|
||||
rtl8168_store_rss_key(tp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6,8,0) */
|
||||
|
||||
static u32 rtl8168_get_rx_desc_hash(struct rtl8168_private *tp,
|
||||
struct RxDescV2 *desc)
|
||||
{
|
||||
if (!desc->RSSResult)
|
||||
udelay(1);
|
||||
return le32_to_cpu(desc->RSSResult);
|
||||
}
|
||||
|
||||
#define RXS_8168_RSS_IPV4 BIT(17)
|
||||
#define RXS_8168_RSS_IPV6 BIT(18)
|
||||
#define RXS_8168_RSS_TCP BIT(19)
|
||||
#define RTL8168_RXS_RSS_L3_TYPE_MASK (RXS_8168_RSS_IPV4 | RXS_8168_RSS_IPV6)
|
||||
#define RTL8168_RXS_RSS_L4_TYPE_MASK (RXS_8168_RSS_TCP)
|
||||
void rtl8168_rx_hash(struct rtl8168_private *tp,
|
||||
struct RxDescV2 *desc,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
u32 rss_header_info;
|
||||
|
||||
if (!(tp->dev->features & NETIF_F_RXHASH))
|
||||
return;
|
||||
|
||||
rss_header_info = le32_to_cpu(desc->opts2);
|
||||
|
||||
if (!(rss_header_info & RTL8168_RXS_RSS_L3_TYPE_MASK))
|
||||
return;
|
||||
|
||||
skb_set_hash(skb, rtl8168_get_rx_desc_hash(tp, desc),
|
||||
(RTL8168_RXS_RSS_L4_TYPE_MASK & rss_header_info) ?
|
||||
PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3);
|
||||
}
|
||||
|
||||
void rtl8168_disable_rss(struct rtl8168_private *tp)
|
||||
{
|
||||
rtl8168_eri_write(tp, RSS_CTRL_8168, 4, 0x00000000, ERIAR_ExGMAC);
|
||||
}
|
||||
|
||||
void _rtl8168_config_rss(struct rtl8168_private *tp)
|
||||
{
|
||||
_rtl8168_set_rss_hash_opt(tp);
|
||||
|
||||
rtl8168_store_reta(tp);
|
||||
|
||||
rtl8168_store_rss_key(tp);
|
||||
}
|
||||
|
||||
void rtl8168_config_rss(struct rtl8168_private *tp)
|
||||
{
|
||||
if (!HW_RSS_SUPPORT_RSS(tp))
|
||||
return;
|
||||
|
||||
if (!tp->EnableRss) {
|
||||
rtl8168_disable_rss(tp);
|
||||
return;
|
||||
}
|
||||
|
||||
_rtl8168_config_rss(tp);
|
||||
}
|
||||
|
||||
void rtl8168_init_rss(struct rtl8168_private *tp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < rtl8168_rss_indir_tbl_entries(tp); i++)
|
||||
tp->rss_indir_tbl[i] = ethtool_rxfh_indir_default(i, tp->num_rx_rings);
|
||||
|
||||
netdev_rss_key_fill(tp->rss_key, RTL8168_RSS_KEY_SIZE);
|
||||
}
|
||||
72
drivers/net/ethernet/realtek/r8168/r8168_rss.h
Normal file
72
drivers/net/ethernet/realtek/r8168/r8168_rss.h
Normal file
@@ -0,0 +1,72 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
################################################################################
|
||||
#
|
||||
# r8125 is the Linux device driver released for Realtek 2.5Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
# more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author:
|
||||
# Realtek NIC software team <nicfae@realtek.com>
|
||||
# No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
|
||||
#
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
/************************************************************************************
|
||||
* This product is covered by one or more of the following patents:
|
||||
* US6,570,884, US6,115,776, and US6,327,625.
|
||||
***********************************************************************************/
|
||||
|
||||
#ifndef _LINUX_RTL8168_RSS_H
|
||||
#define _LINUX_RTL8168_RSS_H
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define RTL8168_RSS_INDIR_TBL_SIZE 8
|
||||
#define RTL8168_RSS_KEY_SIZE 40 /* size of RSS Hash Key in bytes */
|
||||
#define RTL8168_MAX_INDIRECTION_TABLE_ENTRIES 128
|
||||
|
||||
struct rtl8168_private;
|
||||
struct RxDescV2;
|
||||
|
||||
int rtl8168_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
|
||||
u32 *rule_locs);
|
||||
int rtl8168_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd);
|
||||
u32 rtl8168_get_rxfh_key_size(struct net_device *netdev);
|
||||
u32 rtl8168_rss_indir_size(struct net_device *netdev);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,8,0)
|
||||
int rtl8168_get_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh);
|
||||
int rtl8168_set_rxfh(struct net_device *dev, struct ethtool_rxfh_param *rxfh,
|
||||
struct netlink_ext_ack *extack);
|
||||
#else
|
||||
int rtl8168_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key,
|
||||
u8 *hfunc);
|
||||
int rtl8168_set_rxfh(struct net_device *netdev, const u32 *indir,
|
||||
const u8 *key, const u8 hfunc);
|
||||
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(6,8,0) */
|
||||
void rtl8168_rx_hash(struct rtl8168_private *tp,
|
||||
struct RxDescV2 *desc,
|
||||
struct sk_buff *skb);
|
||||
void _rtl8168_config_rss(struct rtl8168_private *tp);
|
||||
void rtl8168_config_rss(struct rtl8168_private *tp);
|
||||
void rtl8168_init_rss(struct rtl8168_private *tp);
|
||||
u32 rtl8168_rss_indir_tbl_entries(struct rtl8168_private *tp);
|
||||
void rtl8168_disable_rss(struct rtl8168_private *tp);
|
||||
|
||||
#endif /* _LINUX_RTL8168_RSS_H */
|
||||
@@ -5,7 +5,7 @@
|
||||
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2022 Realtek Semiconductor Corp. All rights reserved.
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
@@ -157,9 +157,8 @@ void rtl8168_eeprom_write_sc(struct rtl8168_private *tp, u16 reg, u16 data)
|
||||
int addr_sz = 6;
|
||||
int w_dummy_addr = 4;
|
||||
|
||||
if(tp->eeprom_type == EEPROM_TYPE_NONE) {
|
||||
return ;
|
||||
}
|
||||
if(tp->eeprom_type == EEPROM_TYPE_NONE)
|
||||
return;
|
||||
|
||||
if (tp->eeprom_type==EEPROM_TYPE_93C46) {
|
||||
addr_sz = 6;
|
||||
@@ -178,17 +177,15 @@ void rtl8168_eeprom_write_sc(struct rtl8168_private *tp, u16 reg, u16 data)
|
||||
|
||||
rtl8168_shift_out_bits(tp, RTL_EEPROM_ERASE_OPCODE, 3);
|
||||
rtl8168_shift_out_bits(tp, reg, addr_sz);
|
||||
if (rtl8168_eeprom_cmd_done(tp) < 0) {
|
||||
if (rtl8168_eeprom_cmd_done(tp) < 0)
|
||||
return;
|
||||
}
|
||||
rtl8168_stand_by(tp);
|
||||
|
||||
rtl8168_shift_out_bits(tp, RTL_EEPROM_WRITE_OPCODE, 3);
|
||||
rtl8168_shift_out_bits(tp, reg, addr_sz);
|
||||
rtl8168_shift_out_bits(tp, data, 16);
|
||||
if (rtl8168_eeprom_cmd_done(tp) < 0) {
|
||||
if (rtl8168_eeprom_cmd_done(tp) < 0)
|
||||
return;
|
||||
}
|
||||
rtl8168_stand_by(tp);
|
||||
|
||||
rtl8168_shift_out_bits(tp, RTL_EEPROM_EWDS_OPCODE, 5);
|
||||
@@ -5,7 +5,7 @@
|
||||
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2022 Realtek Semiconductor Corp. All rights reserved.
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
@@ -5,7 +5,7 @@
|
||||
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2022 Realtek Semiconductor Corp. All rights reserved.
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
@@ -47,7 +47,6 @@
|
||||
int rtl8168_tool_ioctl(struct rtl8168_private *tp, struct ifreq *ifr)
|
||||
{
|
||||
struct rtltool_cmd my_cmd;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(&my_cmd, ifr->ifr_data, sizeof(my_cmd)))
|
||||
@@ -72,7 +71,6 @@ int rtl8168_tool_ioctl(struct rtl8168_private *tp, struct ifreq *ifr)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case RTLTOOL_WRITE_MAC:
|
||||
if (my_cmd.len==1)
|
||||
writeb(my_cmd.data, tp->mmio_addr+my_cmd.offset);
|
||||
@@ -84,51 +82,31 @@ int rtl8168_tool_ioctl(struct rtl8168_private *tp, struct ifreq *ifr)
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RTLTOOL_READ_PHY:
|
||||
spin_lock_irqsave(&tp->lock, flags);
|
||||
my_cmd.data = rtl8168_mdio_prot_read(tp, my_cmd.offset);
|
||||
spin_unlock_irqrestore(&tp->lock, flags);
|
||||
|
||||
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RTLTOOL_WRITE_PHY:
|
||||
spin_lock_irqsave(&tp->lock, flags);
|
||||
rtl8168_mdio_prot_write(tp, my_cmd.offset, my_cmd.data);
|
||||
spin_unlock_irqrestore(&tp->lock, flags);
|
||||
break;
|
||||
|
||||
case RTLTOOL_READ_EPHY:
|
||||
spin_lock_irqsave(&tp->lock, flags);
|
||||
my_cmd.data = rtl8168_ephy_read(tp, my_cmd.offset);
|
||||
spin_unlock_irqrestore(&tp->lock, flags);
|
||||
|
||||
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RTLTOOL_WRITE_EPHY:
|
||||
spin_lock_irqsave(&tp->lock, flags);
|
||||
rtl8168_ephy_write(tp, my_cmd.offset, my_cmd.data);
|
||||
spin_unlock_irqrestore(&tp->lock, flags);
|
||||
break;
|
||||
|
||||
case RTLTOOL_READ_ERI:
|
||||
my_cmd.data = 0;
|
||||
if (my_cmd.len==1 || my_cmd.len==2 || my_cmd.len==4) {
|
||||
spin_lock_irqsave(&tp->lock, flags);
|
||||
my_cmd.data = rtl8168_eri_read(tp, my_cmd.offset, my_cmd.len, ERIAR_ExGMAC);
|
||||
spin_unlock_irqrestore(&tp->lock, flags);
|
||||
} else {
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
@@ -138,20 +116,15 @@ int rtl8168_tool_ioctl(struct rtl8168_private *tp, struct ifreq *ifr)
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RTLTOOL_WRITE_ERI:
|
||||
if (my_cmd.len==1 || my_cmd.len==2 || my_cmd.len==4) {
|
||||
spin_lock_irqsave(&tp->lock, flags);
|
||||
rtl8168_eri_write(tp, my_cmd.offset, my_cmd.len, my_cmd.data, ERIAR_ExGMAC);
|
||||
spin_unlock_irqrestore(&tp->lock, flags);
|
||||
} else {
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case RTLTOOL_READ_PCI:
|
||||
my_cmd.data = 0;
|
||||
if (my_cmd.len==1)
|
||||
@@ -173,7 +146,6 @@ int rtl8168_tool_ioctl(struct rtl8168_private *tp, struct ifreq *ifr)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case RTLTOOL_WRITE_PCI:
|
||||
if (my_cmd.len==1)
|
||||
pci_write_config_byte(tp->pci_dev, my_cmd.offset,
|
||||
@@ -188,108 +160,69 @@ int rtl8168_tool_ioctl(struct rtl8168_private *tp, struct ifreq *ifr)
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RTLTOOL_READ_EEPROM:
|
||||
spin_lock_irqsave(&tp->lock, flags);
|
||||
my_cmd.data = rtl8168_eeprom_read_sc(tp, my_cmd.offset);
|
||||
spin_unlock_irqrestore(&tp->lock, flags);
|
||||
|
||||
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RTLTOOL_WRITE_EEPROM:
|
||||
spin_lock_irqsave(&tp->lock, flags);
|
||||
rtl8168_eeprom_write_sc(tp, my_cmd.offset, my_cmd.data);
|
||||
spin_unlock_irqrestore(&tp->lock, flags);
|
||||
break;
|
||||
|
||||
case RTL_READ_OOB_MAC:
|
||||
spin_lock_irqsave(&tp->lock, flags);
|
||||
rtl8168_oob_mutex_lock(tp);
|
||||
my_cmd.data = rtl8168_ocp_read(tp, my_cmd.offset, 4);
|
||||
rtl8168_oob_mutex_unlock(tp);
|
||||
spin_unlock_irqrestore(&tp->lock, flags);
|
||||
|
||||
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case RTL_WRITE_OOB_MAC:
|
||||
if (my_cmd.len == 0 || my_cmd.len > 4)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
spin_lock_irqsave(&tp->lock, flags);
|
||||
rtl8168_oob_mutex_lock(tp);
|
||||
rtl8168_ocp_write(tp, my_cmd.offset, my_cmd.len, my_cmd.data);
|
||||
rtl8168_oob_mutex_unlock(tp);
|
||||
spin_unlock_irqrestore(&tp->lock, flags);
|
||||
break;
|
||||
|
||||
case RTL_ENABLE_PCI_DIAG:
|
||||
spin_lock_irqsave(&tp->lock, flags);
|
||||
tp->rtk_enable_diag = 1;
|
||||
spin_unlock_irqrestore(&tp->lock, flags);
|
||||
|
||||
dprintk("enable rtk diag\n");
|
||||
break;
|
||||
|
||||
case RTL_DISABLE_PCI_DIAG:
|
||||
spin_lock_irqsave(&tp->lock, flags);
|
||||
tp->rtk_enable_diag = 0;
|
||||
spin_unlock_irqrestore(&tp->lock, flags);
|
||||
|
||||
dprintk("disable rtk diag\n");
|
||||
break;
|
||||
|
||||
case RTL_READ_MAC_OCP:
|
||||
if (my_cmd.offset % 2)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
spin_lock_irqsave(&tp->lock, flags);
|
||||
my_cmd.data = rtl8168_mac_ocp_read(tp, my_cmd.offset);
|
||||
spin_unlock_irqrestore(&tp->lock, flags);
|
||||
|
||||
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case RTL_WRITE_MAC_OCP:
|
||||
if ((my_cmd.offset % 2) || (my_cmd.len != 2))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
spin_lock_irqsave(&tp->lock, flags);
|
||||
rtl8168_mac_ocp_write(tp, my_cmd.offset, (u16)my_cmd.data);
|
||||
spin_unlock_irqrestore(&tp->lock, flags);
|
||||
break;
|
||||
|
||||
case RTL_DIRECT_READ_PHY_OCP:
|
||||
spin_lock_irqsave(&tp->lock, flags);
|
||||
my_cmd.data = rtl8168_mdio_prot_direct_read_phy_ocp(tp, my_cmd.offset);
|
||||
spin_unlock_irqrestore(&tp->lock, flags);
|
||||
|
||||
if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case RTL_DIRECT_WRITE_PHY_OCP:
|
||||
spin_lock_irqsave(&tp->lock, flags);
|
||||
rtl8168_mdio_prot_direct_write_phy_ocp(tp, my_cmd.offset, my_cmd.data);
|
||||
spin_unlock_irqrestore(&tp->lock, flags);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -EOPNOTSUPP;
|
||||
break;
|
||||
@@ -5,7 +5,7 @@
|
||||
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 2022 Realtek Semiconductor Corp. All rights reserved.
|
||||
# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
@@ -1,8 +1,10 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
ifeq ($(findstring ack_src,$(NV_BUILD_KERNEL_OPTIONS)),)
|
||||
ifeq ($(VERSION).$(PATCHLEVEL),5.15)
|
||||
ifneq ($(NV_OOT_REALTEK_RTL8822CE_SKIP_BUILD),y)
|
||||
obj-m += rtl8822ce/
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
0
drivers/net/wireless/realtek/rtl8822ce/core/mesh/rtw_mesh.c
Normal file → Executable file
0
drivers/net/wireless/realtek/rtl8822ce/core/mesh/rtw_mesh.c
Normal file → Executable file
@@ -1814,9 +1814,12 @@ void rtw_btcoex_connect_notify(PADAPTER padapter, u8 join_type)
|
||||
|
||||
pHalData = GET_HAL_DATA(padapter);
|
||||
|
||||
if (pHalData->EEPROMBluetoothCoexist == _TRUE)
|
||||
if (pHalData->EEPROMBluetoothCoexist == _TRUE) {
|
||||
_rtw_btcoex_connect_notify(padapter, join_type ? _FALSE : _TRUE);
|
||||
else
|
||||
|
||||
if (join_type)
|
||||
rtw_btcoex_SpecialPacketNotify(padapter, PACKET_EAPOL);
|
||||
} else
|
||||
#endif /* CONFIG_BT_COEXIST */
|
||||
rtw_btcoex_wifionly_connect_notify(padapter);
|
||||
}
|
||||
|
||||
@@ -2825,6 +2825,10 @@ int proc_get_trx_info(struct seq_file *m, void *v)
|
||||
struct recv_priv *precvpriv = &padapter->recvpriv;
|
||||
struct hw_xmit *phwxmit;
|
||||
u16 vo_params[4], vi_params[4], be_params[4], bk_params[4];
|
||||
#ifdef CONFIG_LAYER2_ROAMING
|
||||
_list *plist, *phead;
|
||||
_irqL irqL;
|
||||
#endif
|
||||
|
||||
padapter->hal_func.read_wmmedca_reg(padapter, vo_params, vi_params, be_params, bk_params);
|
||||
|
||||
@@ -2854,6 +2858,19 @@ int proc_get_trx_info(struct seq_file *m, void *v)
|
||||
|
||||
rtw_hal_get_hwreg(padapter, HW_VAR_DUMP_MAC_TXFIFO, (u8 *)m);
|
||||
|
||||
#ifdef CONFIG_LAYER2_ROAMING
|
||||
i = 0;
|
||||
_enter_critical_bh(&pxmitpriv->rpkt_queue.lock, &irqL);
|
||||
phead = get_list_head(&pxmitpriv->rpkt_queue);
|
||||
plist = get_next(phead);
|
||||
while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {
|
||||
i++;
|
||||
plist = get_next(plist);
|
||||
}
|
||||
_exit_critical_bh(&pxmitpriv->rpkt_queue.lock, &irqL);
|
||||
RTW_PRINT_SEL(m, "TX: roam_buf_pkt=%d:%d\n", padapter->mlmepriv.roam_buf_pkt, i);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_USB_HCI
|
||||
RTW_PRINT_SEL(m, "rx_urb_pending_cn=%d\n", ATOMIC_READ(&(precvpriv->rx_pending_cnt)));
|
||||
#ifdef CONFIG_USB_PROTECT_RX_CLONED_SKB
|
||||
|
||||
@@ -175,12 +175,25 @@ u8 rtw_do_join(_adapter *padapter)
|
||||
|
||||
pmlmepriv->to_join = _FALSE;
|
||||
#endif /* CONFIG_AP_MODE */
|
||||
|
||||
} else if (pmlmepriv->need_to_roam == _TRUE || rtw_to_roam(padapter) > 0) {
|
||||
/* can't associate ; reset under-linking */
|
||||
_clr_fwstate_(pmlmepriv, WIFI_UNDER_LINKING);
|
||||
/* if all scanned candidates are fail, report to supplicant */
|
||||
rtw_set_to_roam(padapter, 0);
|
||||
rtw_indicate_disconnect(padapter, 0, TRUE);
|
||||
pmlmepriv->to_join = _FALSE;
|
||||
#ifdef CONFIG_LAYER2_ROAMING
|
||||
flush_roam_buf_pkt(padapter, TRUE);
|
||||
#endif
|
||||
ret = _FAIL;
|
||||
|
||||
} else {
|
||||
/* can't associate ; reset under-linking */
|
||||
_clr_fwstate_(pmlmepriv, WIFI_UNDER_LINKING);
|
||||
|
||||
/* when set_ssid/set_bssid for rtw_do_join(), but there are no desired bss in scanning queue */
|
||||
/* we try to issue sitesurvey firstly */
|
||||
|
||||
if (pmlmepriv->LinkDetectInfo.bBusyTraffic == _FALSE
|
||||
|| rtw_to_roam(padapter) > 0
|
||||
) {
|
||||
|
||||
@@ -786,9 +786,7 @@ void rtw_mbo_build_assoc_req_ies(
|
||||
{
|
||||
u32 len = 0;
|
||||
|
||||
#ifndef CONFIG_ECSA
|
||||
rtw_mbo_build_supp_op_class_elem(padapter, pframe, pattrib);
|
||||
#endif
|
||||
|
||||
len += rtw_mbo_attr_sz_get(padapter, RTW_MBO_ATTR_CELL_DATA_CAP_ID);
|
||||
len += rtw_mbo_attr_sz_get(padapter, RTW_MBO_ATTR_NPREF_CH_RPT_ID);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user