Compare commits

..

6 Commits

Author SHA1 Message Date
Ketan Patil
1f703af3e0 video: tegra: nvmap: Avoid double updation of RSS counter
The RSS counter is updated during buffer allocation as well as mmap,
which is leading to double updation. Fix this by decrementing the RSS
counter during page fault while increment it back during unmap flow.

Bug 5222690

Change-Id: I77972185f20d9d710571cc07ae1c5188060bfa1f
Signed-off-by: Ketan Patil <ketanp@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3442670
(cherry picked from commit 1c59063ce7)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3453103
(cherry picked from commit b27a1a79ee)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3454644
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
Tested-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
Reviewed-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
2025-09-23 10:55:17 -07:00
Ketan Patil
033c964778 video: tegra: nvmap: Remove use of add_mm_counter
add_mm_counter is not an exported function, so instead use
atomic_long_add_return/percpu_counter_add to directly modify RSS stat
counters.

Bug 5222690

Change-Id: I51a68d932aeb04f96e51a4a3c286ee5c8efc789a
Signed-off-by: Ketan Patil <ketanp@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3446982
(cherry picked from commit 8e1a6b2dd1)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3453099
(cherry picked from commit e488812038)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3454643
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
Tested-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
Reviewed-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
2025-09-23 10:55:05 -07:00
Ketan Patil
3b830eb8a7 video: tegra: nvmap: Account NvMap memory for OOM Decisions
Account NvMap allocated memory into both RSS and CG tracking to make
efficient OOM kill decisions during memory pressure.

NvMap allocates memory via kernel APIs like alloc_pages, the kernel
memory is not accounted on behalf of process who requests the
allocation. Hence in case OOM, the OOM killer never kills the process
who has allocated memory via NvMap even though this process might be
holding most of the memory.

Solve this issue using following approach:
- Use __GFP_ACCOUNT and __GFP_NORETRY flag
-  __GFP_NORETRY will not let the current allocation flow to go into OOM
path, so that it will never trigger OOM.
- __GFP_ACCOUNT causes the allocation to be accounted to kmemcg. So any
allocation done by NvMap will be definitely accounted to kmemcg and
cgroups can be used to define memory limits.
- Add RSS counting for the process which allocates by NvMap, so that OOM
score for that process will get updated and OOM killer can pick this
process based upon the OOM score.
- Every process that has a reference to NvMap Handle would have the
memory size accounted into its RSS. On releasing the reference to
handle, the RSS would be reduced.

Bug 5222690

Change-Id: I3fa9b76ec9fc8d7f805111cb96e11e2ab1db42ce
Signed-off-by: Ketan Patil <ketanp@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3427871
(cherry picked from commit 2ca91098aa)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3453101
(cherry picked from commit cfe6242c8c)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3454642
Reviewed-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
Tested-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
2025-09-23 10:54:56 -07:00
Revanth Kumar Uppala
3ebca7545e rtl8822ce: Remove pr_debug redefinition
Issue: pr_debug is redfined to printk causing unwanted
       log prints in dmesg

Fix: Remove pr_debug redefintion in rtl8822ce driver

Bug 3844473

Change-Id: I4177f8c3fa245a881cd35c206f8d3caa4b811b32
Signed-off-by: Revanth Kumar Uppala <ruppala@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3121450
(cherry picked from commit 564ce2a709)
Reviewed-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
Reviewed-by: Brad Griffis <bgriffis@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3140027
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
2024-05-18 14:55:37 -07:00
Shobek Attupurath
c79de35fb0 rtl8822ce: Add Nvidia changes on v5.14.0.4-217
1. Add custom roam parameters
2. Add path for power file
3. Add source tree path for Makefile
4. Add section in Makefile for TEGRA platform
5. Update permissions from 0755 to 0644 for files
6. Move roaming debug prints to RTW_INFO

Bug 4320751
Bug 4556940
Bug 4568390

Change-Id: I842f150781652b3b54949aef8f982903c8d7991e
Signed-off-by: Revanth Kumar Uppala <ruppala@nvidia.com>
Signed-off-by: Shobek Attupurath <sattupurath@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3108666
(cherry picked from commit 4e544f3b3a)
Reviewed-by: Brad Griffis <bgriffis@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3140025
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
2024-05-18 14:55:29 -07:00
Revanth Kumar Uppala
c5d97870d1 rtl8822ce: Fix TLP/EAPOL/TXFIFO issues
Issue: Observing the EAPOL packet after a second in 1/10 roams

       Observing TLP Malform packets on SC7

       Observing TXFIFO error when connected to serving AP

       Compilation errors for K6.x

Fix:   Add exact base driver released by realtek with EAPOL/TLP/TXFIFO
       fixes and also resolve some compilation errors.

DRIVERVERSION   v5.14.0.4-217-g7a0377e61.20240410_COEX20240327-2727_beta
BTCOEXVERSION   COEX20240327-2727

Bug 4320751
Bug 4556940
Bug 4568390

Change-Id: Ib02056ea388300dab2364b2bd6ceaf0a2096d3f4
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3115032
(cherry picked from commit ed30eb40ff)
Reviewed-by: Revanth Kumar Uppala <ruppala@nvidia.com>
Reviewed-by: Brad Griffis <bgriffis@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3139878
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
Tested-by: Revanth Kumar Uppala <ruppala@nvidia.com>
2024-05-18 14:54:38 -07:00
191 changed files with 5772 additions and 39907 deletions

View File

@@ -1,19 +1,13 @@
# SPDX-License-Identifier: GPL-2.0-only
# SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2022, 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

View File

@@ -1,8 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#include <linux/kernel.h> /* printk() */
#include <linux/vmalloc.h> /* kmalloc() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/fcntl.h> /* O_ACCMODE */

View File

@@ -1,7 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#include <linux/vmalloc.h> /* kmalloc() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/errno.h> /* error codes */
#include <linux/delay.h> /* For msleep and usleep_range */
#include <uapi/scsi/ufs/ioctl.h>

View File

@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#include <nvidia/conftest.h>
@@ -995,11 +997,7 @@ 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);
@@ -1164,9 +1162,7 @@ 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)

View File

@@ -54,7 +54,7 @@ struct cfg_list_item {
struct list_head list;
u16 offset;
u8 len;
u8 data[];
u8 data[0];
};
static struct list_head list_configs;

View File

@@ -5,7 +5,9 @@ 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

View File

@@ -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 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
ccflags-y += -I$(srctree.nvidia)/drivers/gpu/host1x/include

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* Crypto driver to handle HASH algorithms using NVIDIA Security Engine.
*/
@@ -7,6 +7,7 @@
#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>
@@ -26,14 +27,15 @@ 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;
@@ -44,8 +46,6 @@ 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 = rctx->total_len * 8;
msg_left = rctx->datbuf.size * 8;
msg_len = (u64)rctx->total_len * 8;
msg_left = (u64)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++] = se_host1x_opcode_incr_w(SE_SHA_MSG_LENGTH);
cpuvaddr[i++] = 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,15 +246,14 @@ 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++] = se_host1x_opcode_incr_w(SE_SHA_CFG);
cpuvaddr[i++] = 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)) |
@@ -264,47 +263,30 @@ 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++] = se_host1x_opcode_nonincr_w(SE_SHA_CRYPTO_CFG);
cpuvaddr[i++] = 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++] = se_host1x_opcode_nonincr_w(SE_SHA_OPERATION);
cpuvaddr[i++] = host1x_opcode_nonincr_w(SE_SHA_OPERATION);
cpuvaddr[i++] = SE_SHA_OP_WRSTALL |
SE_SHA_OP_START |
SE_SHA_OP_LASTBUF;
cpuvaddr[i++] = se_host1x_opcode_nonincr(host1x_uclass_incr_syncpt_r(), 1);
cpuvaddr[i++] = 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, ret;
unsigned int nblks, nresidue, size;
u32 *cpuvaddr = ctx->se->cmdbuf->addr;
nresidue = (req->nbytes + rctx->residue.size) % rctx->blk_size;
@@ -329,26 +311,21 @@ 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;
@@ -356,30 +333,9 @@ 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);
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;
return tegra_se_host1x_submit(ctx->se, size);
}
static int tegra_sha_do_final(struct ahash_request *req)
@@ -391,25 +347,16 @@ 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;
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;
}
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);
ret = tegra_se_host1x_submit(se, size);
if (ret)
goto out;
@@ -417,14 +364,12 @@ static int tegra_sha_do_final(struct ahash_request *req)
memcpy(req->result, rctx->digest.buf, rctx->digest.size);
out:
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, SE_SHA_BUFLEN,
rctx->datbuf.buf, rctx->datbuf.addr);
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;
}
@@ -435,7 +380,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 = 0;
int ret = -EINVAL;
if (rctx->task & SHA_UPDATE) {
ret = tegra_sha_do_update(req);
@@ -449,43 +394,27 @@ static int tegra_sha_do_one_req(struct crypto_engine *engine, void *areq)
crypto_finalize_hash_request(se->engine, req, ret);
return 0;
return ret;
}
static void tegra_sha_init_fallback(struct crypto_ahash *tfm, struct tegra_sha_ctx *ctx,
const char *algname)
static void tegra_sha_init_fallback(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\n", algname);
dev_warn(ctx->se->dev, "failed to allocate fallback for %s %ld\n",
algname, PTR_ERR(ctx->fallback_tfm));
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
@@ -494,29 +423,22 @@ 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(ahash_tfm, sizeof(struct tegra_sha_reqctx));
crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
sizeof(struct tegra_sha_reqctx));
ctx->se = se_alg->se_dev;
ctx->fallback = false;
ctx->key_id = 0;
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(ahash_tfm, ctx, algname);
ctx->alg = ret;
ctx->alg = se_algname_to_algid(algname);
#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;
ctx->enginectx.op.unprepare_request = NULL;
#endif
if (se_alg->alg_base)
tegra_sha_init_fallback(ctx, algname);
return 0;
}
@@ -527,7 +449,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, ctx->alg);
tegra_key_invalidate(ctx->se, ctx->key_id);
}
static int tegra_sha_init(struct ahash_request *req)
@@ -536,34 +458,45 @@ 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 = ctx->alg;
rctx->alg = se_algname_to_algid(algname);
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, rctx->digest.size, rctx->digest.buf,
rctx->digest.addr);
dma_free_coherent(se->dev, SE_SHA_BUFLEN, rctx->datbuf.buf,
rctx->datbuf.addr);
digbuf_fail:
return -ENOMEM;
}
@@ -572,7 +505,7 @@ static int tegra_hmac_fallback_setkey(struct tegra_sha_ctx *ctx, const u8 *key,
unsigned int keylen)
{
if (!ctx->fallback_tfm) {
dev_dbg(ctx->se->dev, "invalid key length (%d)\n", keylen);
dev_err(ctx->se->dev, "invalid key length\n");
return -EINVAL;
}
@@ -584,18 +517,13 @@ 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;
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;
return tegra_key_submit(ctx->se, key, keylen, ctx->alg, &ctx->key_id);
}
static int tegra_sha_update(struct ahash_request *req)
@@ -665,6 +593,9 @@ 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;
}
@@ -698,6 +629,7 @@ 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",
@@ -729,6 +661,7 @@ 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",
@@ -760,6 +693,7 @@ 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",
@@ -791,6 +725,7 @@ 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",
@@ -822,6 +757,7 @@ 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",
@@ -853,6 +789,7 @@ 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",
@@ -884,6 +821,7 @@ 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",
@@ -915,6 +853,7 @@ 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",
@@ -946,6 +885,7 @@ 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",
@@ -979,6 +919,7 @@ 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",
@@ -1012,6 +953,7 @@ 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",
@@ -1045,6 +987,7 @@ 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",
@@ -1078,6 +1021,7 @@ 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",
@@ -1133,32 +1077,28 @@ 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;
alg = &tegra_hash_algs[i].alg.ahash;
ret = CRYPTO_REGISTER(ahash, alg);
tegra_hash_algs[i].se_dev = se;
ret = CRYPTO_REGISTER(ahash, &tegra_hash_algs[i].alg.ahash);
if (ret) {
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
dev_err(se->dev, "failed to register %s\n",
alg->base.halg.base.cra_name);
tegra_hash_algs[i].alg.ahash.base.halg.base.cra_name);
#else
dev_err(se->dev, "failed to register %s\n",
alg->halg.base.cra_name);
tegra_hash_algs[i].alg.ahash.halg.base.cra_name);
#endif
goto sha_err;
}
}
dev_info(se->dev, "registered HASH algorithms\n");
return 0;
sha_err:
@@ -1168,7 +1108,8 @@ sha_err:
return ret;
}
void tegra_deinit_hash(struct tegra_se *se)
void tegra_deinit_hash(void)
{
int i;

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* Crypto driver file to manage keys of NVIDIA Security Engine.
*/
@@ -16,77 +16,66 @@
#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)) {
mutex_unlock(&kslt_lock);
if (tegra_se_keyslots == GENMASK(SE_MAX_KEYSLOT, 0))
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++] = se_host1x_opcode_incr_w(se->hw->regs->op);
cpuvaddr[i++] = 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++] = se_host1x_opcode_incr_w(se->hw->regs->manifest);
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->manifest);
cpuvaddr[i++] = se->manifest(se->owner, alg, keylen);
cpuvaddr[i++] = host1x_opcode_setpayload(1);
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->key_dst);
cpuvaddr[i++] = 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++] = se_host1x_opcode_incr_w(se->hw->regs->key_addr);
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->key_addr);
cpuvaddr[i++] = j;
/* Set key data */
cpuvaddr[i++] = host1x_opcode_setpayload(1);
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->key_data);
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->key_data);
cpuvaddr[i++] = key[j];
}
cpuvaddr[i++] = host1x_opcode_setpayload(1);
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->config);
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->config);
cpuvaddr[i++] = SE_CFG_INS;
cpuvaddr[i++] = host1x_opcode_setpayload(1);
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->op);
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->op);
cpuvaddr[i++] = SE_AES_OP_WRSTALL | SE_AES_OP_START |
SE_AES_OP_LASTBUF;
cpuvaddr[i++] = se_host1x_opcode_nonincr(host1x_uclass_incr_syncpt_r(), 1);
cpuvaddr[i++] = 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);
@@ -98,44 +87,29 @@ 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;
mutex_lock(&kslt_lock);
ret = ((BIT(keyid) & SE_KEY_VALID_MASK) &&
return ((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->keybuf->addr, size;
int ret;
u32 *addr = se->cmdbuf->addr, size;
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 ret;
return tegra_se_host1x_submit(se, size);
}
void tegra_key_invalidate(struct tegra_se *se, u32 keyid, u32 alg)
void tegra_key_invalidate(struct tegra_se *se, u32 keyid)
{
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);
}
@@ -146,10 +120,8 @@ 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)) {
dev_dbg(se->dev, "failed to allocate key slot\n");
if (!(*keyid))
return -ENOMEM;
}
}
ret = tegra_key_insert(se, key, keylen, *keyid, alg);
@@ -158,20 +130,3 @@ 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);
}

View File

@@ -1,11 +1,12 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-FileCopyrightText: Copyright (c) 2023 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>
@@ -123,7 +124,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(*cmdbuf), GFP_KERNEL);
cmdbuf = kzalloc(sizeof(struct tegra_se_cmdbuf), GFP_KERNEL);
if (!cmdbuf)
return NULL;
@@ -141,7 +142,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, struct tegra_se_cmdbuf *cmdbuf, u32 size)
int tegra_se_host1x_submit(struct tegra_se *se, u32 size)
{
struct host1x_job *job;
int ret;
@@ -152,7 +153,7 @@ int tegra_se_host1x_submit(struct tegra_se *se, struct tegra_se_cmdbuf *cmdbuf,
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;
@@ -160,24 +161,24 @@ int tegra_se_host1x_submit(struct tegra_se *se, struct tegra_se_cmdbuf *cmdbuf,
job->engine_fallback_streamid = se->stream_id;
job->engine_streamid_offset = SE_STREAM_ID;
cmdbuf->words = size;
se->cmdbuf->words = size;
host1x_job_add_gather(job, &cmdbuf->bo, size, 0);
host1x_job_add_gather(job, &se->cmdbuf->bo, size, 0);
ret = host1x_job_pin(job, se->dev);
if (ret) {
dev_err(se->dev, "failed to pin host1x job\n");
goto job_put;
goto err_job_pin;
}
ret = host1x_job_submit(job);
if (ret) {
dev_err(se->dev, "failed to submit host1x job\n");
goto job_unpin;
goto err_job_submit;
}
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;
@@ -186,9 +187,9 @@ int tegra_se_host1x_submit(struct tegra_se *se, struct tegra_se_cmdbuf *cmdbuf,
host1x_job_put(job);
return 0;
job_unpin:
err_job_submit:
host1x_job_unpin(job);
job_put:
err_job_pin:
host1x_job_put(job);
return ret;
@@ -209,7 +210,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 channel_put;
goto err_syncpt;
}
se->syncpt_id = host1x_syncpt_id(se->syncpt);
@@ -217,30 +218,22 @@ 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 syncpt_put;
}
se->keybuf = tegra_se_host1x_bo_alloc(se, SZ_4K);
if (!se->cmdbuf) {
ret = -ENOMEM;
goto cmdbuf_put;
goto err_bo;
}
ret = se->hw->init_alg(se);
if (ret) {
dev_err(se->dev, "failed to register algorithms\n");
goto keybuf_put;
goto err_alg_reg;
}
return 0;
keybuf_put:
tegra_se_cmdbuf_put(&se->keybuf->bo);
cmdbuf_put:
err_alg_reg:
tegra_se_cmdbuf_put(&se->cmdbuf->bo);
syncpt_put:
err_bo:
host1x_syncpt_put(se->syncpt);
channel_put:
err_syncpt:
host1x_channel_put(se->channel);
return ret;
@@ -250,7 +243,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);
se->hw->deinit_alg();
tegra_se_cmdbuf_put(&se->cmdbuf->bo);
host1x_syncpt_put(se->syncpt);
host1x_channel_put(se->channel);
@@ -263,7 +256,7 @@ static const struct host1x_client_ops tegra_se_client_ops = {
.exit = tegra_se_client_deinit,
};
static int tegra_se_host1x_register(struct tegra_se *se)
int tegra_se_host1x_register(struct tegra_se *se)
{
INIT_LIST_HEAD(&se->client.list);
se->client.dev = se->dev;
@@ -276,6 +269,38 @@ static 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;
@@ -287,45 +312,61 @@ 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);
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");
ret = tegra_se_clk_init(se);
if (ret) {
dev_err(dev, "failed to init clocks\n");
return ret;
}
if (!tegra_dev_iommu_get_stream_id(dev, &se->stream_id))
return dev_err_probe(dev, -ENODEV,
"failed to get IOMMU stream ID\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;
}
writel(se->stream_id, se->base + SE_STREAM_ID);
se_writel(se, se->stream_id, SE_STREAM_ID);
se->engine = crypto_engine_alloc_init(dev, 0);
if (!se->engine)
return dev_err_probe(dev, -ENOMEM, "failed to init crypto engine\n");
if (!se->engine) {
dev_err(dev, "failed to init crypto engine\n");
ret = -ENOMEM;
goto err_engine_alloc;
}
ret = crypto_engine_start(se->engine);
if (ret) {
crypto_engine_exit(se->engine);
return dev_err_probe(dev, ret, "failed to start crypto engine\n");
dev_err(dev, "failed to start crypto engine\n");
goto err_engine_start;
}
ret = tegra_se_host1x_register(se);
if (ret) {
crypto_engine_stop(se->engine);
crypto_engine_exit(se->engine);
return dev_err_probe(dev, ret, "failed to init host1x params\n");
dev_err(dev, "failed to init host1x params\n");
goto err_host1x_init;
}
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)
@@ -336,6 +377,7 @@ 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;
}
@@ -382,10 +424,10 @@ static const struct tegra_se_hw tegra234_hash_hw = {
static const struct of_device_id tegra_se_of_match[] = {
{
.compatible = "nvidia,tegra234-se-aes",
.compatible = "nvidia,tegra234-se2-aes",
.data = &tegra234_aes_hw
}, {
.compatible = "nvidia,tegra234-se-hash",
.compatible = "nvidia,tegra234-se4-hash",
.data = &tegra234_hash_hw,
},
{ },
@@ -444,4 +486,4 @@ module_exit(tegra_se_module_exit);
MODULE_DESCRIPTION("NVIDIA Tegra Security Engine Driver");
MODULE_AUTHOR("Akhil R <akhilrajeev@nvidia.com>");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* Header file for NVIDIA Security Engine driver.
*/
@@ -7,18 +7,22 @@
#ifndef _TEGRA_SE_H
#define _TEGRA_SE_H
#include <nvidia/conftest.h>
#include <linux/bitfield.h>
#include <linux/clk.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
@@ -63,8 +67,11 @@
#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)
@@ -304,6 +311,12 @@
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 | \
@@ -342,9 +355,8 @@
#define SE_CRYPTO_CTR_REG_COUNT 4
#define SE_MAX_KEYSLOT 15
#define SE_MAX_MEM_ALLOC SZ_4M
#define TEGRA_AES_RESERVED_KSLT 14
#define TEGRA_XTS_RESERVED_KSLT 15
#define SE_AES_BUFLEN 0x8000
#define SE_SHA_BUFLEN SZ_4M
#define SHA_FIRST BIT(0)
#define SHA_UPDATE BIT(1)
@@ -371,6 +383,7 @@ 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 */
@@ -404,13 +417,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;
};
@@ -433,7 +446,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)(struct tegra_se *se);
void (*deinit_alg)(void);
bool support_sm_alg;
u32 host1x_class;
u32 kac_ver;
@@ -442,18 +455,18 @@ struct tegra_se_hw {
struct tegra_se {
int (*manifest)(u32 user, u32 alg, u32 keylen);
const struct tegra_se_hw *hw;
struct host1x_client client;
struct host1x_channel *channel;
struct tegra_se_cmdbuf *cmdbuf;
struct tegra_se_cmdbuf *keybuf;
struct crypto_engine *engine;
struct host1x_channel *channel;
struct host1x_client client;
struct host1x_syncpt *syncpt;
struct clk_bulk_data *clks;
struct tegra_se_cmdbuf *cmdbuf;
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;
};
@@ -463,8 +476,8 @@ struct tegra_se_cmdbuf {
struct device *dev;
struct kref ref;
struct host1x_bo bo;
ssize_t size;
u32 words;
ssize_t size;
};
struct tegra_se_datbuf {
@@ -479,6 +492,8 @@ 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)"))
@@ -521,85 +536,87 @@ 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_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);
void tegra_deinit_aead(void);
void tegra_deinit_aes(void);
void tegra_deinit_hash(void);
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);
static inline int tegra_key_submit_reserved_aes(struct tegra_se *se, const u8 *key,
u32 keylen, u32 alg, 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)
{
*keyid = TEGRA_AES_RESERVED_KSLT;
return tegra_key_submit_reserved(se, key, keylen, alg, keyid);
writel_relaxed(val, se->base + offset);
}
static inline int tegra_key_submit_reserved_xts(struct tegra_se *se, const u8 *key,
u32 keylen, u32 alg, u32 *keyid)
static inline u32 se_readl(struct tegra_se *se, unsigned int offset)
{
*keyid = TEGRA_XTS_RESERVED_KSLT;
return tegra_key_submit_reserved(se, key, keylen, alg, keyid);
return readl_relaxed(se->base + offset);
}
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;
}
static inline u32 host1x_opcode_incr_w(unsigned int offset)
#define host1x_opcode_incr_w(x) __host1x_opcode_incr_w((x) / 4)
static inline u32 __host1x_opcode_incr_w(unsigned int offset)
{
/* 22-bit offset supported */
return (10 << 28) | offset;
}
static inline u32 host1x_opcode_nonincr_w(unsigned int offset)
#define host1x_opcode_nonincr_w(x) __host1x_opcode_nonincr_w((x) / 4)
static inline u32 __host1x_opcode_nonincr_w(unsigned int offset)
{
/* 22-bit offset supported */
return (11 << 28) | offset;
}
static inline u32 host1x_opcode_incr(unsigned int offset, unsigned int count)
#define host1x_opcode_incr(x, y) __host1x_opcode_incr((x) / 4, y)
static inline u32 __host1x_opcode_incr(unsigned int offset, unsigned int count)
{
return (1 << 28) | (offset << 16) | count;
return (1 << 28) | (offset << 16) | count;
}
static inline u32 host1x_opcode_nonincr(unsigned int offset, unsigned int 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)
{
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)
@@ -618,9 +635,4 @@ 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*/

View File

@@ -12,7 +12,6 @@
#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>

View File

@@ -15,7 +15,6 @@
#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>

View File

@@ -43,37 +43,11 @@
#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;
@@ -81,7 +55,6 @@ struct nvdec_config {
bool supports_timestamping;
bool has_riscv;
bool has_extra_clocks;
const struct nvdec_cg_reg *cg_regs;
};
struct nvdec {
@@ -118,11 +91,6 @@ 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;
@@ -589,29 +557,6 @@ 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);
@@ -637,8 +582,6 @@ 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);
@@ -755,28 +698,12 @@ 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[] = {

View File

@@ -1,5 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* Host1x fence UAPI
*
* Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved.
*/
#include <nvidia/conftest.h>
@@ -201,28 +205,20 @@ 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, *pfd_fence_temp;
struct host1x_pollfd_fence *pfd_fence;
mutex_lock(&pollfd->lock);
list_for_each_entry_safe(pfd_fence, pfd_fence_temp, &pollfd->fences, list) {
list_for_each_entry(pfd_fence, &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;
}
@@ -239,20 +235,8 @@ 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);
}
}

View File

@@ -335,11 +335,7 @@ 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;
}

View File

@@ -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. 1024 slots will fit exactly within a
* two memory pages. We also need one additional word at the end of the push
* 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
* buffer for the RESTART opcode that will instruct the CDMA to jump back to
* 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
* 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
* used.
*/
#define HOST1X_PUSHBUFFER_SLOTS 1023
#define HOST1X_PUSHBUFFER_SLOTS 511
/*
* Clean up push buffer resources

View File

@@ -177,14 +177,7 @@ 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 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);
u32 val = *(map_addr + offset / 4 + i);
if (!data_count) {
host1x_debug_output(o, " %pad: %08x: ", &addr, val);
@@ -210,7 +203,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, pb->mapped);
pb->dma + job->first_get, pb->mapped + job->first_get);
for (i = 0; i < job->num_cmds; i++) {
struct host1x_job_gather *g;
@@ -234,7 +227,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, NULL,
show_gather(o, g->base + g->offset, g->words, cdma,
g->base, mapped);
if (!job->gather_copy_mapped)

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <nvidia/conftest.h>
@@ -1093,10 +1093,8 @@ 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", &reg_idx);
if (status) {
@@ -1127,11 +1125,7 @@ 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;

View File

@@ -20,7 +20,6 @@ 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

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,194 +0,0 @@
// 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");

View File

@@ -1,152 +0,0 @@
/* 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

View File

@@ -1,8 +1,9 @@
// 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>
@@ -746,7 +747,6 @@ 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;
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,911 +0,0 @@
// 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, &reg_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");

View File

@@ -775,7 +775,6 @@ 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;
}

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. */
/*
* virtual_i2c_mux.c - virtual i2c mux driver for P3762 & P3783 GMSL boards.
*/
@@ -87,11 +87,7 @@ 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;
}

View File

@@ -1,18 +1,8 @@
// SPDX-License-Identifier: GPL-2.0 only
/* SPDX-FileCopyrightText: Copyright (c) 2015-2024 NVIDIA CORPORATION & AFFILIATES.
* All rights reserved.
// SPDX-License-Identifier: GPL-2.0
/*
* camera_common.c - utilities for tegra camera driver
*
* 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/>.
* Copyright (c) 2015-2023, NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/types.h>
#include <media/tegra-v4l2-camera.h>
@@ -54,11 +44,6 @@ 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,

View File

@@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2015-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: GPL-2.0
/*
* NVIDIA Tegra CSI Device
*
* Copyright (c) 2015-2024, NVIDIA CORPORATION. All rights reserved.
*/
#include <nvidia/conftest.h>
@@ -686,7 +687,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_SET_FRAME_INTERVAL)
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_FRAME_INTERVAL)
struct v4l2_subdev_state *sd_state,
#endif
struct v4l2_subdev_frame_interval *vfi)
@@ -720,13 +721,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_SET_FRAME_INTERVAL)
#if !defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_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_SET_FRAME_INTERVAL)
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_FRAME_INTERVAL)
.get_frame_interval = tegra_csi_g_frame_interval,
#endif
.get_fmt = tegra_csi_get_format,

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
// SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// Copyright (c) 2017-2023 NVIDIA Corporation. 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/vmalloc.h>
#include <linux/slab.h>
#include <linux/tegra-capture-ivc.h>
#include <asm/arch_timer.h>
#include <soc/tegra/fuse.h>

View File

@@ -17,7 +17,7 @@
#include <linux/of_platform.h>
#include <linux/nvhost.h>
#include <linux/sched.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/dma-buf.h>
#include <linux/dma-mapping.h>

View File

@@ -1,17 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
/* 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.
*/
// SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/**
* @file drivers/media/platform/tegra/camera/fusa-capture/capture-vi.c
@@ -24,7 +12,7 @@
#include <linux/nvhost.h>
#include <linux/of_platform.h>
#include <linux/printk.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/tegra-capture-ivc.h>
#include <linux/tegra-camera-rtcpu.h>
@@ -1450,12 +1438,7 @@ int vi_capture_status(
/* negative timeout means wait forever */
if (timeout_ms < 0) {
ret = wait_for_completion_interruptible(&capture->capture_resp);
if (ret == -ERESTARTSYS) {
dev_dbg(chan->dev,
"capture status interrupted\n");
return -ETIMEDOUT;
}
wait_for_completion(&capture->capture_resp);
} else {
ret = wait_for_completion_timeout(
&capture->capture_resp,

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (c) 2016-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*
* Tegra CSI5 device common APIs
*/
@@ -213,7 +213,6 @@ 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",
@@ -286,7 +285,6 @@ 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;
@@ -295,9 +293,6 @@ 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;

View File

@@ -1,11 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2018-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: GPL-2.0
/*
* 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>
@@ -114,30 +112,9 @@ 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 = {
@@ -184,10 +161,6 @@ 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,

View File

@@ -4,8 +4,6 @@
* NVIDIA Tegra Video Input Device
*/
#include <nvidia/conftest.h>
#include <linux/atomic.h>
#include <linux/bitmap.h>
#include <linux/clk.h>
@@ -25,7 +23,6 @@
#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>
@@ -692,33 +689,16 @@ 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);
return ret;
else
return -EINVAL;
}
int tegra_channel_alloc_buffer_queue(struct tegra_channel *chan,
@@ -1177,19 +1157,11 @@ 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
@@ -1201,11 +1173,7 @@ 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);
@@ -1218,13 +1186,9 @@ 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,
@@ -1242,19 +1206,11 @@ 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
@@ -1301,10 +1257,6 @@ 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) {
@@ -1891,13 +1843,8 @@ 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();
@@ -2224,11 +2171,7 @@ 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",
@@ -2273,7 +2216,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 = -ENOTTY;
long ret = 0;
if (vi->fops && vi->fops->vi_default_ioctl)
ret = vi->fops->vi_default_ioctl(file, fh, use_prio, cmd, arg);
@@ -2281,32 +2224,10 @@ 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,

View File

@@ -1,14 +1,8 @@
// 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
*
* 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.
* Copyright (c) 2016-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#include <linux/errno.h>
@@ -140,9 +134,6 @@ 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;
@@ -209,16 +200,6 @@ 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)
@@ -516,7 +497,6 @@ 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;
@@ -527,21 +507,12 @@ static void vi5_capture_dequeue(struct tegra_channel *chan,
goto rel_buf;
/* Dequeue a frame and check its capture status */
timeout_ms = chan->capture_timeout_ms;
err = vi_capture_status(chan->tegra_vi_channel[vi_port], timeout_ms);
err = vi_capture_status(chan->tegra_vi_channel[vi_port], CAPTURE_TIMEOUT_MS);
if (err) {
if (err == -ETIMEDOUT) {
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);
}
dev_err(vi->dev,
"uncorr_err: request timed out after %d ms\n",
CAPTURE_TIMEOUT_MS);
} else {
dev_err(vi->dev, "uncorr_err: request err %d\n", err);
}
@@ -731,7 +702,6 @@ static int tegra_channel_kthread_capture_dequeue(void *data)
struct tegra_channel_buffer *buf;
set_freezable();
allow_signal(SIGINT);
while (1) {
try_to_freeze();
@@ -752,12 +722,6 @@ 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);
@@ -827,7 +791,6 @@ 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;
}

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. */
/* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. */
/*
* cam_cdi_tsc.c - tsc driver.
*/
@@ -147,8 +147,6 @@ 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 = {
@@ -460,44 +458,22 @@ static void cdi_tsc_debugfs_remove(struct tsc_signal_controller *controller)
static int cdi_tsc_chardev_open(struct inode *inode, struct file *file)
{
struct tsc_signal_controller *controller = dev_get_drvdata(tsc_charDevice);
int err = 0;
pr_info("%s:Device opened\n", __func__);
if (controller->opened)
return -EBUSY;
/* Set External Fsync */
Hawk_Owl_Fsync_program(EXTERNAL_FSYNC);
/* 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;
return 0;
}
static int cdi_tsc_chardev_release(struct inode *inode, struct file *file)
{
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;
pr_info("%s:Device closed\n", __func__);
/* Set back to Internal Fsync */
err = Hawk_Owl_Fsync_program(INTERNAL_FSYNC);
Hawk_Owl_Fsync_program(INTERNAL_FSYNC);
controller->opened = false;
dev_dbg(controller->dev, "%s Device closed ..\n", __func__);
return err;
return 0;
}
static long cdi_tsc_chardev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -544,7 +520,6 @@ 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) {

View File

@@ -1,13 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* SPDX-FileCopyrightText: Copyright (c) 2016-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2016-2022, 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;

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <nvidia/conftest.h>
@@ -33,11 +33,7 @@ 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);
}
@@ -46,8 +42,7 @@ 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_GPIO_DEVICE_FIND_PRESENT) && \
defined(NV_GPIO_DEVICE_GET_CHIP_PRESENT) /* Linux 6.7 */
#if !defined(NV_GPIOCHIP_FIND_PRESENT) /* Linux 6.7 */
struct gpio_device *gdev;
#endif
char name[MAX_STR_SIZE];
@@ -59,15 +54,14 @@ static struct gpio_chip *cdi_gpio_get_chip(struct platform_device *pdev,
}
strcpy(name, pd->gpio_prnt_chip);
#if defined(NV_GPIO_DEVICE_FIND_PRESENT) && \
defined(NV_GPIO_DEVICE_GET_CHIP_PRESENT) /* Linux 6.7 */
#if defined(NV_GPIOCHIP_FIND_PRESENT) /* Linux 6.7 */
gc = gpiochip_find(name, cdi_gpio_chip_match);
#else
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",

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2016-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2016-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <nvidia/conftest.h>
@@ -30,11 +30,7 @@ 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
@@ -99,38 +95,30 @@ 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 = 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");
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");
return NULL;
}
if (info->force_on) {
err = pwm_config(info->pwm, args->args[1]/4, args->args[1]);
if (err) {
dev_err(dev, "can't config PWM: %d\n", err);
dev_err(pc->dev, "can't config PWM: %d\n", err);
return NULL;
}
err = pwm_enable(info->pwm);
if (err) {
dev_err(dev, "can't enable PWM: %d\n", err);
dev_err(pc->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(dev, "can't config PWM: %d\n", err);
dev_err(pc->dev, "can't config PWM: %d\n", err);
return NULL;
}
}
@@ -152,60 +140,50 @@ 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");
chip->ops = &cdi_pwm_ops;
info->chip.dev = &pdev->dev;
info->chip.ops = &cdi_pwm_ops;
#if defined(NV_PWM_CHIP_STRUCT_HAS_BASE_ARG)
chip->base = -1;
info->chip.base = -1;
#endif
chip->of_xlate = of_cdi_pwm_xlate;
info->chip.npwm = npwm;
info->chip.of_xlate = of_cdi_pwm_xlate;
info->force_on = force_on;
err = pwmchip_add(chip);
err = pwmchip_add(&info->chip);
if (err < 0) {
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", err);
return err;
}
platform_set_drvdata(pdev, chip);
platform_set_drvdata(pdev, info);
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(chip);
pwmchip_remove(&info->chip);
err = PTR_ERR(info->pwm);
if (err != -EPROBE_DEFER)
dev_err(&pdev->dev,
@@ -217,24 +195,24 @@ static int cdi_pwm_probe(struct platform_device *pdev)
static int cdi_pwm_remove(struct platform_device *pdev)
{
struct pwm_chip *chip = platform_get_drvdata(pdev);
struct cdi_pwm_info *info = platform_get_drvdata(pdev);
pwmchip_remove(chip);
pwmchip_remove(&info->chip);
return 0;
}
static int cdi_pwm_suspend(struct device *dev)
{
struct pwm_chip *chip = dev_get_drvdata(dev);
struct cdi_pwm_info *info = to_cdi_pwm_info(chip);
int err = 0;
struct cdi_pwm_info *info = dev_get_drvdata(dev);
if (info == NULL) {
dev_err(dev, "%s: fail to get info\n", __func__);
} else {
if (!IS_ERR(info->pwm)) {
pwm_disable(info->pwm);
pwm_config(info->pwm, PWM_SUSPEND_DUTY_RATIO,
err = pwm_config(info->pwm, PWM_SUSPEND_DUTY_RATIO,
PWM_SUSPEND_PERIOD);
}
}

View File

@@ -1,13 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* SPDX-FileCopyrightText: Copyright (c) 2016-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
/*
* Copyright (c) 2016-2022, 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;

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <nvidia/conftest.h>
@@ -33,11 +33,7 @@ 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);
}
@@ -47,8 +43,7 @@ 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_GPIO_DEVICE_FIND_PRESENT) && \
defined(NV_GPIO_DEVICE_GET_CHIP_PRESENT) /* Linux 6.7 */
#if !defined(NV_GPIOCHIP_FIND_PRESENT) /* Linux 6.7 */
struct gpio_device *gdev;
#endif
@@ -59,15 +54,14 @@ static struct gpio_chip *isc_gpio_get_chip(struct platform_device *pdev,
}
strcpy(name, pd->gpio_prnt_chip);
#if defined(NV_GPIO_DEVICE_FIND_PRESENT) && \
defined(NV_GPIO_DEVICE_GET_CHIP_PRESENT) /* Linux 6.7 */
#if defined(NV_GPIOCHIP_FIND_PRESENT) /* Linux 6.7 */
gc = gpiochip_find(name, isc_gpio_chip_match);
#else
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",

View File

@@ -30,11 +30,7 @@ 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
@@ -99,38 +95,30 @@ 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 = 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");
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");
return NULL;
}
if (info->force_on) {
err = pwm_config(info->pwm, args->args[1]/4, args->args[1]);
if (err) {
dev_err(dev, "can't config PWM: %d\n", err);
dev_err(pc->dev, "can't config PWM: %d\n", err);
return NULL;
}
err = pwm_enable(info->pwm);
if (err) {
dev_err(dev, "can't enable PWM: %d\n", err);
dev_err(pc->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(dev, "can't config PWM: %d\n", err);
dev_err(pc->dev, "can't config PWM: %d\n", err);
return NULL;
}
}
@@ -152,60 +140,50 @@ 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");
chip->ops = &isc_pwm_ops;
info->chip.dev = &pdev->dev;
info->chip.ops = &isc_pwm_ops;
#if defined(NV_PWM_CHIP_STRUCT_HAS_BASE_ARG)
chip->base = -1;
info->chip.base = -1;
#endif
chip->of_xlate = of_isc_pwm_xlate;
info->chip.npwm = npwm;
info->chip.of_xlate = of_isc_pwm_xlate;
info->force_on = force_on;
err = pwmchip_add(chip);
err = pwmchip_add(&info->chip);
if (err < 0) {
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", err);
return err;
}
platform_set_drvdata(pdev, chip);
platform_set_drvdata(pdev, info);
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(chip);
pwmchip_remove(&info->chip);
err = PTR_ERR(info->pwm);
if (err != -EPROBE_DEFER)
dev_err(&pdev->dev,
@@ -217,24 +195,24 @@ static int isc_pwm_probe(struct platform_device *pdev)
static int isc_pwm_remove(struct platform_device *pdev)
{
struct pwm_chip *chip = platform_get_drvdata(pdev);
struct isc_pwm_info *info = platform_get_drvdata(pdev);
pwmchip_remove(chip);
pwmchip_remove(&info->chip);
return 0;
}
static int isc_pwm_suspend(struct device *dev)
{
struct pwm_chip *chip = dev_get_drvdata(dev);
struct isc_pwm_info *info = to_isc_pwm_info(chip);
int err = 0;
struct isc_pwm_info *info = dev_get_drvdata(dev);
if (info == NULL) {
dev_err(dev, "%s: fail to get info\n", __func__);
} else {
if (!IS_ERR(info->pwm)) {
pwm_disable(info->pwm);
pwm_config(info->pwm, PWM_SUSPEND_DUTY_RATIO,
err = pwm_config(info->pwm, PWM_SUSPEND_DUTY_RATIO,
PWM_SUSPEND_PERIOD);
}
}

View File

@@ -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 = false;
mc_csi->tpg_gain_ctrl = true;
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++)

View File

@@ -1,15 +1,9 @@
# SPDX-License-Identifier: GPL-2.0-only
# SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2022-2024, NVIDIA CORPORATION. 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

View File

@@ -1,10 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// Copyright (c) 2022-2023, 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>
@@ -217,11 +215,7 @@ 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);

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#define pr_fmt(fmt) "nvscic2c-pcie: endpoint: " fmt
@@ -501,13 +501,8 @@ 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

View File

@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <nvidia/conftest.h>
// Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#define pr_fmt(fmt) "nvscic2c-pcie: epf: " fmt
@@ -171,7 +169,6 @@ 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)
{
@@ -181,7 +178,6 @@ clear_inbound_translation(struct pci_epf *epf)
/* no api to clear epf header.*/
}
#endif
static int
set_inbound_translation(struct pci_epf *epf)
@@ -494,7 +490,6 @@ 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)
{
@@ -522,7 +517,6 @@ nvscic2c_pcie_epf_core_deinit(struct pci_epf *epf)
return 0;
}
#endif
/* Handle link message from @DRV_MODE_EPC. */
static void
@@ -735,9 +729,7 @@ 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

View File

@@ -3,8 +3,6 @@
#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>
@@ -248,12 +246,7 @@ 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,
#if defined(NV_IOMMU_MAP_HAS_GFP_ARG)
EDMA_CH_DESC_SZ, prot, GFP_KERNEL);
#else
EDMA_CH_DESC_SZ, prot);
#endif
ret = iommu_map(ctx->domain, ctx->edma_ch_desc_iova, phys_addr, EDMA_CH_DESC_SZ, prot);
if (ret) {
pr_err("pci client failed to map iova to 60K physical backing\n");
goto err;
@@ -415,12 +408,7 @@ 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,
#if defined(NV_IOMMU_MAP_HAS_GFP_ARG)
prot, GFP_KERNEL);
#else
prot);
#endif
return iommu_map(ctx->domain, to_iova, paddr, size, prot);
}
size_t
@@ -763,7 +751,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 DRV_MODE_INVALID;
return NVCPU_MAXIMUM;
return drv_ctx->drv_mode;
}
@@ -812,11 +800,7 @@ 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;

View File

@@ -4,8 +4,6 @@
#ifndef __PCI_CLIENT_H__
#define __PCI_CLIENT_H__
#include <nvidia/conftest.h>
#include <uapi/misc/nvscic2c-pcie-ioctl.h>
#include "common.h"
@@ -135,9 +133,5 @@ 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__

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#define pr_fmt(fmt) "nvscic2c-pcie: stream-ext: " fmt
@@ -14,7 +14,6 @@
#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>

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#include <nvidia/conftest.h>
@@ -505,8 +505,7 @@ 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)
@@ -1115,7 +1114,6 @@ restart:
priv->can.can_stats.restarts++;
mttcan_start(dev);
netif_start_queue(dev);
netif_carrier_on(dev);
}

View File

@@ -1,12 +1,10 @@
# SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: GPL-2.0-only
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
obj-m += nvidia/
ifdef CONFIG_PCI
obj-m += marvell/
obj-m += microchip/
ifeq ($(VERSION).$(PATCHLEVEL),5.15)
obj-m += realtek/
endif
endif

View File

@@ -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 = (skb_frag_off(frag) + offset) >> PAGE_SHIFT;
page_offset = (skb_frag_off(frag) + offset) & ~PAGE_MASK;
page_idx = (frag->bv_offset + offset) >> PAGE_SHIFT;
page_offset = (frag->bv_offset + offset) & ~PAGE_MASK;
tx_swcx->buf_phy_addr = dma_map_page(dev,
(skb_frag_page(frag) + page_idx),
(frag->bv_page + 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\n");
dev_info(&pdev->dev, "Macsec not supported/Not enabled in DT\n");
} else {
dev_info(&pdev->dev, "Macsec not enabled\n");
/* Macsec is supported, reduce MTU */

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2019-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// Copyright (c) 2019-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <nvidia/conftest.h>
@@ -863,11 +863,7 @@ 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);
@@ -1099,11 +1095,7 @@ 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);
@@ -1144,13 +1136,8 @@ 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
@@ -1165,18 +1152,10 @@ 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;
@@ -1184,11 +1163,7 @@ 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;
@@ -1199,28 +1174,16 @@ 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;
@@ -1228,19 +1191,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 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;
@@ -1263,19 +1218,11 @@ 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;

View File

@@ -9,11 +9,6 @@
#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
@@ -1370,10 +1365,9 @@ 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_enable ||
macsec_pdata->is_macsec_enabled_in_dt == 0U) {
if ((ret != 0) || (macsec_pdata->is_macsec_enabled_in_dt == 0U)) {
dev_info(dev,
"macsec parameter is missing or disabled\n");
"macsec param in DT is missing or disabled\n");
ret = 1;
goto init_err;
}

View File

@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2019-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/* Copyright (c) 2019-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved */
#include <linux/version.h>
#include "ether_linux.h"
/**
@@ -129,7 +130,11 @@ 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,
@@ -138,11 +143,14 @@ 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 = scaled_ppm_to_ppb(scaled_ppm);
ioctl_data.arg6_32 = ppb;
ret = osi_handle_ioctl(osi_core, &ioctl_data);
if (ret < 0) {
dev_err(pdata->dev,
@@ -245,7 +253,11 @@ 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,

View File

@@ -183,11 +183,6 @@ 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);
@@ -656,18 +651,16 @@ 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.
*/

View File

@@ -1,10 +1,100 @@
# SPDX-License-Identifier: GPL-2.0-only
# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
################################################################################
#
# 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
#
################################################################################
ifneq ($(NV_OOT_REALTEK_R8168_SKIP_BUILD),y)
obj-m += r8168/
################################################################################
# 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
endif
ifneq ($(NV_OOT_REALTEK_R8126_SKIP_BUILD),y)
obj-m += r8126/
endif

View File

@@ -1,143 +0,0 @@
# 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

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,261 +0,0 @@
/* 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 */

View File

@@ -1,16 +0,0 @@
// 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");

View File

@@ -1,264 +0,0 @@
// 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;
}

View File

@@ -1,68 +0,0 @@
/* 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 */

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,892 +0,0 @@
// 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;
}

View File

@@ -1,113 +0,0 @@
/* 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 */

View File

@@ -1,118 +0,0 @@
/* 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 */

View File

@@ -1,601 +0,0 @@
// 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);
}

View File

@@ -1,76 +0,0 @@
/* 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 */

View File

@@ -1,285 +0,0 @@
// 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);
}

View File

@@ -1,58 +0,0 @@
/* 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 */

View File

@@ -1,260 +0,0 @@
// 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;
}

View File

@@ -1,86 +0,0 @@
/* 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 */

View File

@@ -1,205 +0,0 @@
# 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

View File

@@ -1,16 +0,0 @@
// 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");

View File

@@ -1,500 +0,0 @@
// 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);
}

View File

@@ -1,72 +0,0 @@
/* 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 */

View File

@@ -5,7 +5,7 @@
# 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.
# 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
@@ -60,6 +60,7 @@ 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;
@@ -67,6 +68,8 @@ 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);
@@ -189,9 +192,12 @@ 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;
@@ -384,10 +390,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);
}
@@ -408,9 +414,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);
}

View File

@@ -5,7 +5,7 @@
# 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.
# 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

View File

@@ -5,7 +5,7 @@
# 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.
# 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
@@ -247,7 +247,6 @@ 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);

View File

@@ -5,7 +5,7 @@
# 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.
# 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

View File

@@ -5,7 +5,7 @@
# 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.
# 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

View File

@@ -5,7 +5,7 @@
# r8168 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.
# 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

View File

@@ -5,7 +5,7 @@
# 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.
# 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

View File

@@ -5,7 +5,7 @@
# 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.
# 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
@@ -157,8 +157,9 @@ 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;
@@ -177,15 +178,17 @@ 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);

View File

@@ -5,7 +5,7 @@
# 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.
# 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

View File

@@ -5,7 +5,7 @@
# 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.
# 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
@@ -47,6 +47,7 @@
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)))
@@ -71,6 +72,7 @@ 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);
@@ -82,31 +84,51 @@ 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;
@@ -116,15 +138,20 @@ 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)
@@ -146,6 +173,7 @@ 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,
@@ -160,69 +188,108 @@ 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;

View File

@@ -5,7 +5,7 @@
# 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.
# 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

View File

@@ -1,10 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only
# SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2022, NVIDIA CORPORATION. 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

View File

View File

@@ -2825,10 +2825,6 @@ 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);
@@ -2858,19 +2854,6 @@ 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

View File

@@ -175,25 +175,12 @@ 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
) {

View File

@@ -786,7 +786,9 @@ 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);

View File

@@ -4295,43 +4295,6 @@ exit:
return ret;
}
void flush_roam_buf_pkt(_adapter *padapter, int clear_roam)
{
struct xmit_frame *rframe;
struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
_list *plist, *phead;
_irqL irqL;
int i = 0;
RTW_INFO(FUNC_ADPT_FMT" - clear_roam = %d, roam_buf_pkt = %d\n",
FUNC_ADPT_ARG(padapter), clear_roam, padapter->mlmepriv.roam_buf_pkt);
if (clear_roam) {
padapter->mlmepriv.roam_network = NULL;
padapter->mlmepriv.candidate_5G = NULL;
}
if (padapter->mlmepriv.roam_buf_pkt) {
padapter->mlmepriv.roam_buf_pkt = 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) {
rframe = LIST_CONTAINOR(plist, struct xmit_frame, list);
plist = get_next(plist);
rtw_list_delete(&rframe->list);
rtw_free_xmitframe(pxmitpriv, rframe);
i++;
}
_exit_critical_bh(&pxmitpriv->rpkt_queue.lock, &irqL);
if (i)
RTW_INFO(FUNC_ADPT_FMT" - drop %d roam_buf_pkt\n",FUNC_ADPT_ARG(padapter), i);
}
}
#endif /* CONFIG_LAYER2_ROAMING */
/*
@@ -5870,11 +5833,7 @@ inline void rtw_set_to_roam(_adapter *adapter, u8 to_roam)
inline u8 rtw_dec_to_roam(_adapter *adapter)
{
if (adapter->mlmepriv.to_roam > 0)
adapter->mlmepriv.to_roam--;
else
adapter->mlmepriv.to_roam = 0;
adapter->mlmepriv.to_roam--;
return adapter->mlmepriv.to_roam;
}

Some files were not shown because too many files have changed in this diff Show More