mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-24 10:11:26 +03:00
Compare commits
3 Commits
IGX_OS-1.1
...
jetson_36.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
564ce2a709 | ||
|
|
0a0a84577b | ||
|
|
eacae28123 |
@@ -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
|
||||
@@ -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 */
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m := rtk_btusb.o
|
||||
rtk_btusb-y = rtk_coex.o rtk_misc.o rtk_bt.o
|
||||
else
|
||||
PWD := $(shell pwd)
|
||||
KVER := $(shell uname -r)
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) modules
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.mod.c *.mod.o *.ko *.symvers *.order *.a
|
||||
|
||||
endif
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
CONFIG_BTUSB_AUTOSUSPEND = n
|
||||
CONFIG_BTUSB_WAKEUP_HOST = n
|
||||
CONFIG_BTCOEX = y
|
||||
|
||||
ifeq ($(CONFIG_BTUSB_AUTOSUSPEND), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_BTUSB_AUTOSUSPEND
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BTUSB_WAKEUP_HOST), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_BTUSB_WAKEUP_HOST
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BTCOEX), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_BTCOEX
|
||||
endif
|
||||
|
||||
obj-m := rtk_btusb.o
|
||||
rtk_btusb-objs := rtk_coex.o \
|
||||
rtk_misc.o \
|
||||
rtk_bt.o
|
||||
|
||||
@@ -1,22 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
*
|
||||
* Realtek Bluetooth USB driver
|
||||
*
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@@ -36,7 +22,7 @@
|
||||
#include "rtk_bt.h"
|
||||
#include "rtk_misc.h"
|
||||
|
||||
#define VERSION "3.1.65ab490.20240531-141726"
|
||||
#define VERSION "3.1.6fd4e69.20220818-105856"
|
||||
|
||||
#ifdef BTCOEX
|
||||
#include "rtk_coex.h"
|
||||
@@ -49,64 +35,95 @@ static DEFINE_SEMAPHORE(switch_sem);
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 7, 1)
|
||||
static bool reset = true;
|
||||
static bool reset = 0;
|
||||
#endif
|
||||
|
||||
static struct usb_driver btusb_driver;
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
static u16 iso_min_conn_handle = 0x1b;
|
||||
#endif
|
||||
|
||||
static const struct usb_device_id btusb_table[] = {
|
||||
/* Generic Bluetooth USB device */
|
||||
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
|
||||
|
||||
/* Generic Bluetooth USB interface */
|
||||
{ USB_INTERFACE_INFO(0xe0, 0x01, 0x01) },
|
||||
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct usb_device_id blacklist_table[] = {
|
||||
static struct usb_device_id btusb_table[] = {
|
||||
{
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x0bda,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x13d3,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x0489,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x1358,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x04ca,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x2ff8,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x0b05,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x0930,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x10ec,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x04c5,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x0cb5,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x0cb8,
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.idVendor = 0x04b8,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, { }
|
||||
};
|
||||
|
||||
@@ -131,6 +148,20 @@ static struct btusb_data *rtk_alloc(struct usb_interface *intf)
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, btusb_table);
|
||||
|
||||
static int inc_tx(struct btusb_data *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
int rv;
|
||||
|
||||
spin_lock_irqsave(&data->txlock, flags);
|
||||
rv = test_bit(BTUSB_SUSPENDING, &data->flags);
|
||||
if (!rv)
|
||||
data->tx_in_flight++;
|
||||
spin_unlock_irqrestore(&data->txlock, flags);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
|
||||
static inline void btusb_free_frags(struct btusb_data *data)
|
||||
{
|
||||
@@ -173,11 +204,7 @@ static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
|
||||
}
|
||||
|
||||
len = min_t(uint, bt_cb(skb)->expect, count);
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
||||
skb_put_data(skb, buffer, len);
|
||||
#else
|
||||
memcpy(skb_put(skb, len), buffer, len);
|
||||
#endif
|
||||
|
||||
count -= len;
|
||||
buffer += len;
|
||||
@@ -232,26 +259,15 @@ static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
|
||||
}
|
||||
|
||||
len = min_t(uint, bt_cb(skb)->expect, count);
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
||||
skb_put_data(skb, buffer, len);
|
||||
#else
|
||||
memcpy(skb_put(skb, len), buffer, len);
|
||||
#endif
|
||||
|
||||
count -= len;
|
||||
buffer += len;
|
||||
bt_cb(skb)->expect -= len;
|
||||
|
||||
if (skb->len == HCI_ACL_HDR_SIZE) {
|
||||
struct hci_acl_hdr *h = hci_acl_hdr(skb);
|
||||
__le16 dlen = h->dlen;
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
__u16 handle = __le16_to_cpu(h->handle) & 0xfff;
|
||||
__le16 dlen = hci_acl_hdr(skb)->dlen;
|
||||
|
||||
if(handle >= iso_min_conn_handle) {
|
||||
bt_cb(skb)->pkt_type = HCI_ISODATA_PKT;
|
||||
}
|
||||
#endif
|
||||
/* Complete ACL header */
|
||||
bt_cb(skb)->expect = __le16_to_cpu(dlen);
|
||||
|
||||
@@ -277,42 +293,10 @@ static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
|
||||
return err;
|
||||
}
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
static int btrtl_usb_recv_isoc(u16 pos, u8 *data, u8 *p, int len,
|
||||
u16 wMaxPacketSize)
|
||||
{
|
||||
u8 *prev;
|
||||
|
||||
if (pos >= HCI_SCO_HDR_SIZE && pos >= wMaxPacketSize &&
|
||||
len == wMaxPacketSize && !(pos % wMaxPacketSize) &&
|
||||
wMaxPacketSize >= 10 && p[0] == data[0] && p[1] == data[1]) {
|
||||
|
||||
prev = data + (pos - wMaxPacketSize);
|
||||
|
||||
/* Detect the sco data of usb isoc pkt duplication. */
|
||||
if (!memcmp(p + 2, prev + 2, 8))
|
||||
return -EILSEQ;
|
||||
|
||||
if (wMaxPacketSize >= 12 &&
|
||||
p[2] == prev[6] && p[3] == prev[7] &&
|
||||
p[4] == prev[4] && p[5] == prev[5] &&
|
||||
p[6] == prev[10] && p[7] == prev[11] &&
|
||||
p[8] == prev[8] && p[9] == prev[9]) {
|
||||
return -EILSEQ;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int err = 0;
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
u16 wMaxPacketSize = le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize);
|
||||
#endif
|
||||
|
||||
spin_lock(&data->rxlock);
|
||||
skb = data->sco_skb;
|
||||
@@ -332,24 +316,7 @@ static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count)
|
||||
}
|
||||
|
||||
len = min_t(uint, bt_cb(skb)->expect, count);
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
/* Gaps in audio could be heard while streaming WBS using USB
|
||||
* alt settings 3 on some platforms.
|
||||
* Add the function to detect it.
|
||||
*/
|
||||
if (test_bit(BTUSB_USE_ALT3_FOR_WBS, &data->flags)) {
|
||||
err = btrtl_usb_recv_isoc(skb->len, skb->data, buffer,
|
||||
len, wMaxPacketSize);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
||||
skb_put_data(skb, buffer, len);
|
||||
#else
|
||||
memcpy(skb_put(skb, len), buffer, len);
|
||||
#endif
|
||||
|
||||
count -= len;
|
||||
buffer += len;
|
||||
@@ -380,21 +347,6 @@ static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count)
|
||||
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
static int inc_tx(struct btusb_data *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
int rv;
|
||||
|
||||
spin_lock_irqsave(&data->txlock, flags);
|
||||
rv = test_bit(BTUSB_SUSPENDING, &data->flags);
|
||||
if (!rv)
|
||||
data->tx_in_flight++;
|
||||
spin_unlock_irqrestore(&data->txlock, flags);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void btusb_intr_complete(struct urb *urb)
|
||||
@@ -674,51 +626,6 @@ retry:
|
||||
}
|
||||
}
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
static inline void __fill_isoc_descriptor_msbc(struct urb *urb, int len,
|
||||
int mtu, struct btusb_data *data)
|
||||
{
|
||||
int i = 0, offset = 0;
|
||||
unsigned int interval;
|
||||
|
||||
BT_DBG("len %d mtu %d", len, mtu);
|
||||
|
||||
/* For mSBC ALT 6 settings some Realtek chips need to transmit the data
|
||||
* continuously without the zero length of USB packets.
|
||||
*/
|
||||
if (btrealtek_test_flag(data->hdev, REALTEK_ALT6_CONTINUOUS_TX_CHIP))
|
||||
goto ignore_usb_alt6_packet_flow;
|
||||
|
||||
/* For mSBC ALT 6 setting the host will send the packet at continuous
|
||||
* flow. As per core spec 5, vol 4, part B, table 2.1. For ALT setting
|
||||
* 6 the HCI PACKET INTERVAL should be 7.5ms for every usb packets.
|
||||
* To maintain the rate we send 63bytes of usb packets alternatively for
|
||||
* 7ms and 8ms to maintain the rate as 7.5ms.
|
||||
*/
|
||||
if (data->usb_alt6_packet_flow) {
|
||||
interval = 7;
|
||||
data->usb_alt6_packet_flow = false;
|
||||
} else {
|
||||
interval = 6;
|
||||
data->usb_alt6_packet_flow = true;
|
||||
}
|
||||
|
||||
for (i = 0; i < interval; i++) {
|
||||
urb->iso_frame_desc[i].offset = offset;
|
||||
urb->iso_frame_desc[i].length = offset;
|
||||
}
|
||||
|
||||
ignore_usb_alt6_packet_flow:
|
||||
if (len && i < BTUSB_MAX_ISOC_FRAMES) {
|
||||
urb->iso_frame_desc[i].offset = offset;
|
||||
urb->iso_frame_desc[i].length = len;
|
||||
i++;
|
||||
}
|
||||
|
||||
urb->number_of_packets = i;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void __fill_isoc_descriptor(struct urb *urb, int len, int mtu)
|
||||
{
|
||||
int i, offset = 0;
|
||||
@@ -768,12 +675,6 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
|
||||
|
||||
pipe = usb_rcvisocpipe(data->udev, data->isoc_rx_ep->bEndpointAddress);
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 2, 14)
|
||||
usb_fill_int_urb(urb, data->udev, pipe, buf, size, btusb_isoc_complete,
|
||||
hdev, data->isoc_rx_ep->bInterval);
|
||||
|
||||
urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP;
|
||||
#else
|
||||
urb->dev = data->udev;
|
||||
urb->pipe = pipe;
|
||||
urb->context = hdev;
|
||||
@@ -783,7 +684,6 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
|
||||
urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP;
|
||||
urb->transfer_buffer = buf;
|
||||
urb->transfer_buffer_length = size;
|
||||
#endif
|
||||
|
||||
__fill_isoc_descriptor(urb, size,
|
||||
le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize));
|
||||
@@ -834,8 +734,8 @@ static void btusb_isoc_tx_complete(struct urb *urb)
|
||||
struct sk_buff *skb = urb->context;
|
||||
struct hci_dev *hdev = (struct hci_dev *)skb->dev;
|
||||
|
||||
RTKBT_DBG("%s: urb %p status %d count %d", __func__,
|
||||
urb, urb->status, urb->actual_length);
|
||||
RTKBT_DBG("%s: urb %p status %d count %d",__func__,
|
||||
urb, urb->status, urb->actual_length);
|
||||
|
||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
||||
goto done;
|
||||
@@ -851,49 +751,6 @@ done:
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
static int rtl_read_iso_handle_range(struct hci_dev *hdev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct __rp {
|
||||
u8 status;
|
||||
u8 min_handle[2];
|
||||
} *rp;
|
||||
int ret = -EIO;
|
||||
|
||||
skb = __hci_cmd_sync(hdev, 0xfdab, 0, NULL, HCI_CMD_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
return PTR_ERR(skb);
|
||||
}
|
||||
|
||||
/* FIXME: if the return status is not zero, __hci_cmd_sync() would
|
||||
* return an error and we would not reach here.
|
||||
*/
|
||||
if (skb->data[0]) {
|
||||
RTKBT_ERR("%s: Read failed, status %0x", hdev->name,
|
||||
skb->data[0]);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (skb->len < sizeof(*rp)) {
|
||||
RTKBT_WARN("%s: The len %u of rp is too short", __func__,
|
||||
skb->len);
|
||||
goto err;
|
||||
}
|
||||
|
||||
rp = (void *)skb->data;
|
||||
iso_min_conn_handle = (u16)rp->min_handle[1] << 8 | rp->min_handle[0];
|
||||
RTKBT_DBG("ISO handle range (handle >= %04x)", iso_min_conn_handle);
|
||||
|
||||
kfree_skb(skb);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int btusb_open(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = GET_DRV_DATA(hdev);
|
||||
@@ -918,10 +775,6 @@ static int btusb_open(struct hci_dev *hdev)
|
||||
goto failed;
|
||||
/*******************************/
|
||||
|
||||
err = setup_btrealtek_flag(data->intf, hdev);
|
||||
if (err < 0)
|
||||
RTKBT_WARN("setup_btrealtek_flag incorrect!");
|
||||
|
||||
RTKBT_INFO("%s set HCI UP RUNNING", __func__);
|
||||
if (test_and_set_bit(HCI_UP, &hdev->flags))
|
||||
goto done;
|
||||
@@ -964,32 +817,6 @@ failed:
|
||||
return err;
|
||||
}
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
static int btusb_setup(struct hci_dev *hdev)
|
||||
{
|
||||
rtl_read_iso_handle_range(hdev);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
|
||||
static int btusb_shutdown(struct hci_dev *hdev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int ret;
|
||||
|
||||
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
ret = PTR_ERR(skb);
|
||||
bt_dev_err(hdev, "HCI reset during shutdown failed");
|
||||
return ret;
|
||||
}
|
||||
kfree_skb(skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void btusb_stop_traffic(struct btusb_data *data)
|
||||
{
|
||||
mdelay(URB_CANCELING_DELAY_MS); // Added by Realtek
|
||||
@@ -1093,152 +920,8 @@ static const char pkt_ind[][8] = {
|
||||
[HCI_COMMAND_PKT] = "cmd",
|
||||
[HCI_ACLDATA_PKT] = "acl",
|
||||
[HCI_SCODATA_PKT] = "sco",
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
[HCI_ISODATA_PKT] = "iso",
|
||||
#endif
|
||||
};
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
|
||||
static struct urb *alloc_ctrl_urb(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct usb_ctrlrequest *dr;
|
||||
struct urb *urb;
|
||||
unsigned int pipe;
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!urb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
dr = kmalloc(sizeof(*dr), GFP_KERNEL);
|
||||
if (!dr) {
|
||||
usb_free_urb(urb);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
dr->bRequestType = data->cmdreq_type;
|
||||
dr->bRequest = 0;
|
||||
dr->wIndex = 0;
|
||||
dr->wValue = 0;
|
||||
dr->wLength = __cpu_to_le16(skb->len);
|
||||
|
||||
pipe = usb_sndctrlpipe(data->udev, 0x00);
|
||||
|
||||
usb_fill_control_urb(urb, data->udev, pipe, (void *)dr,
|
||||
skb->data, skb->len, btusb_tx_complete, skb);
|
||||
|
||||
skb->dev = (void *)hdev;
|
||||
|
||||
return urb;
|
||||
}
|
||||
|
||||
static struct urb *alloc_bulk_urb(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct urb *urb;
|
||||
unsigned int pipe;
|
||||
|
||||
if (!data->bulk_tx_ep)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!urb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pipe = usb_sndbulkpipe(data->udev, data->bulk_tx_ep->bEndpointAddress);
|
||||
|
||||
usb_fill_bulk_urb(urb, data->udev, pipe,
|
||||
skb->data, skb->len, btusb_tx_complete, skb);
|
||||
|
||||
skb->dev = (void *)hdev;
|
||||
|
||||
return urb;
|
||||
}
|
||||
|
||||
static struct urb *alloc_isoc_urb(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct urb *urb;
|
||||
unsigned int pipe;
|
||||
|
||||
if (!data->isoc_tx_ep)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL);
|
||||
if (!urb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pipe = usb_sndisocpipe(data->udev, data->isoc_tx_ep->bEndpointAddress);
|
||||
|
||||
usb_fill_int_urb(urb, data->udev, pipe,
|
||||
skb->data, skb->len, btusb_isoc_tx_complete,
|
||||
skb, data->isoc_tx_ep->bInterval);
|
||||
|
||||
urb->transfer_flags = URB_ISO_ASAP;
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
if (data->isoc_altsetting == 6)
|
||||
__fill_isoc_descriptor_msbc(urb, skb->len,
|
||||
le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize),
|
||||
data);
|
||||
else
|
||||
__fill_isoc_descriptor(urb, skb->len,
|
||||
le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
|
||||
#else
|
||||
__fill_isoc_descriptor(urb, skb->len,
|
||||
le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
|
||||
#endif
|
||||
|
||||
skb->dev = (void *)hdev;
|
||||
|
||||
return urb;
|
||||
}
|
||||
|
||||
static int submit_tx_urb(struct hci_dev *hdev, struct urb *urb)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
int err;
|
||||
|
||||
usb_anchor_urb(urb, &data->tx_anchor);
|
||||
|
||||
err = usb_submit_urb(urb, GFP_KERNEL);
|
||||
if (err < 0) {
|
||||
if (err != -EPERM && err != -ENODEV)
|
||||
RTKBT_ERR("%s urb %p submission failed (%d)",
|
||||
hdev->name, urb, -err);
|
||||
kfree(urb->setup_packet);
|
||||
usb_unanchor_urb(urb);
|
||||
} else {
|
||||
usb_mark_last_busy(data->udev);
|
||||
}
|
||||
|
||||
usb_free_urb(urb);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int submit_or_queue_tx_urb(struct hci_dev *hdev, struct urb *urb)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
unsigned long flags;
|
||||
bool suspending;
|
||||
|
||||
spin_lock_irqsave(&data->txlock, flags);
|
||||
suspending = test_bit(BTUSB_SUSPENDING, &data->flags);
|
||||
if (!suspending)
|
||||
data->tx_in_flight++;
|
||||
spin_unlock_irqrestore(&data->txlock, flags);
|
||||
|
||||
if (!suspending)
|
||||
return submit_tx_urb(hdev, urb);
|
||||
|
||||
usb_anchor_urb(urb, &data->deferred);
|
||||
schedule_work(&data->waker);
|
||||
|
||||
usb_free_urb(urb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
|
||||
int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
@@ -1248,20 +931,14 @@ int btusb_send_frame(struct sk_buff *skb)
|
||||
struct hci_dev *hdev = (struct hci_dev *)skb->dev;
|
||||
#endif
|
||||
|
||||
struct urb *urb;
|
||||
#if HCI_VERSION_CODE < KERNEL_VERSION(3, 18, 0)
|
||||
struct btusb_data *data = GET_DRV_DATA(hdev);
|
||||
struct usb_ctrlrequest *dr;
|
||||
struct urb *urb;
|
||||
unsigned int pipe;
|
||||
int err;
|
||||
#endif
|
||||
|
||||
// RTKBT_DBG("%s", hdev->name);
|
||||
//RTKBT_DBG("%s", hdev->name);
|
||||
|
||||
/* After Kernel version 4.4.0, move the check into the
|
||||
* hci_send_frame function before calling hdev->send
|
||||
*/
|
||||
#if HCI_VERSION_CODE < KERNEL_VERSION(4, 4, 0)
|
||||
if (!test_bit(HCI_RUNNING, &hdev->flags)) {
|
||||
/* If the parameter is wrong, the hdev isn't the correct
|
||||
* one. Then no HCI commands can be sent.
|
||||
@@ -1269,15 +946,13 @@ int btusb_send_frame(struct sk_buff *skb)
|
||||
RTKBT_ERR("HCI is not running");
|
||||
return -EBUSY;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Before kernel/hci version 3.13.0, the skb->dev is set before
|
||||
* entering btusb_send_frame(). So there is no need to set it here.
|
||||
*
|
||||
* The skb->dev will be used in the callbacks when urb transfer
|
||||
* completes. See btusb_tx_complete() and btusb_isoc_tx_complete() */
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) && \
|
||||
HCI_VERSION_CODE < KERNEL_VERSION(3, 18, 0)
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
|
||||
skb->dev = (void *)hdev;
|
||||
#endif
|
||||
|
||||
@@ -1288,14 +963,6 @@ int btusb_send_frame(struct sk_buff *skb)
|
||||
#ifdef BTCOEX
|
||||
rtk_btcoex_parse_cmd(skb->data, skb->len);
|
||||
#endif
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
|
||||
urb = alloc_ctrl_urb(hdev, skb);
|
||||
if (IS_ERR(urb))
|
||||
return PTR_ERR(urb);
|
||||
|
||||
hdev->stat.cmd_tx++;
|
||||
return submit_or_queue_tx_urb(hdev, urb);
|
||||
#else
|
||||
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
if (!urb)
|
||||
return -ENOMEM;
|
||||
@@ -1321,24 +988,11 @@ int btusb_send_frame(struct sk_buff *skb)
|
||||
hdev->stat.cmd_tx++;
|
||||
break;
|
||||
|
||||
#endif
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
case HCI_ISODATA_PKT:
|
||||
#endif
|
||||
case HCI_ACLDATA_PKT:
|
||||
print_acl(skb, 1);
|
||||
#ifdef BTCOEX
|
||||
if(bt_cb(skb)->pkt_type == HCI_ACLDATA_PKT)
|
||||
rtk_btcoex_parse_l2cap_data_tx(skb->data, skb->len);
|
||||
rtk_btcoex_parse_l2cap_data_tx(skb->data, skb->len);
|
||||
#endif
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
|
||||
urb = alloc_bulk_urb(hdev, skb);
|
||||
if (IS_ERR(urb))
|
||||
return PTR_ERR(urb);
|
||||
|
||||
hdev->stat.acl_tx++;
|
||||
return submit_or_queue_tx_urb(hdev, urb);
|
||||
#else
|
||||
if (!data->bulk_tx_ep)
|
||||
return -ENODEV;
|
||||
|
||||
@@ -1355,22 +1009,7 @@ int btusb_send_frame(struct sk_buff *skb)
|
||||
hdev->stat.acl_tx++;
|
||||
break;
|
||||
|
||||
#endif
|
||||
case HCI_SCODATA_PKT:
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
|
||||
if (hci_conn_num(hdev, SCO_LINK) < 1)
|
||||
return -ENODEV;
|
||||
|
||||
urb = alloc_isoc_urb(hdev, skb);
|
||||
if (IS_ERR(urb))
|
||||
return PTR_ERR(urb);
|
||||
|
||||
hdev->stat.sco_tx++;
|
||||
return submit_tx_urb(hdev, urb);
|
||||
}
|
||||
|
||||
return -EILSEQ;
|
||||
#else
|
||||
if (!data->isoc_tx_ep || SCO_NUM < 1)
|
||||
return -ENODEV;
|
||||
|
||||
@@ -1396,7 +1035,6 @@ int btusb_send_frame(struct sk_buff *skb)
|
||||
|
||||
default:
|
||||
return -EILSEQ;
|
||||
|
||||
}
|
||||
|
||||
err = inc_tx(data);
|
||||
@@ -1419,14 +1057,12 @@ skip_waking:
|
||||
} else {
|
||||
usb_mark_last_busy(data->udev);
|
||||
}
|
||||
usb_free_urb(urb);
|
||||
|
||||
done:
|
||||
usb_free_urb(urb);
|
||||
return err;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if HCI_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
|
||||
static void btusb_destruct(struct hci_dev *hdev)
|
||||
{
|
||||
@@ -1545,9 +1181,6 @@ static struct usb_host_interface *btusb_find_altsetting(struct btusb_data *data,
|
||||
|
||||
BT_DBG("Looking for Alt no :%d", alt);
|
||||
|
||||
if (!intf)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < intf->num_altsetting; i++) {
|
||||
if (intf->altsetting[i].desc.bAlternateSetting == alt)
|
||||
return &intf->altsetting[i];
|
||||
@@ -1588,14 +1221,7 @@ static void btusb_work(struct work_struct *work)
|
||||
new_alts = data->sco_num;
|
||||
}
|
||||
} else if (data->air_mode == HCI_NOTIFY_ENABLE_SCO_TRANSP) {
|
||||
if (btusb_find_altsetting(data, 6))
|
||||
new_alts = 6;
|
||||
else if (btusb_find_altsetting(data, 3) &&
|
||||
hdev->sco_mtu >= 72 &&
|
||||
test_bit(BTUSB_USE_ALT3_FOR_WBS, &data->flags))
|
||||
new_alts = 3;
|
||||
else
|
||||
new_alts = 1;
|
||||
new_alts = btusb_find_altsetting(data, 6) ? 6 : 1;
|
||||
}
|
||||
|
||||
if (btusb_switch_alt_setting(hdev, new_alts) < 0)
|
||||
@@ -1795,7 +1421,7 @@ static int rtkbt_pm_notify(struct notifier_block *notifier,
|
||||
result = __rtk_send_hci_cmd(udev, cmd, 3);
|
||||
kfree(cmd);
|
||||
msleep(100); /* From FW colleague's recommendation */
|
||||
result = download_special_patch(intf, "lps_");
|
||||
result = download_lps_patch(intf);
|
||||
#endif
|
||||
|
||||
#ifdef RTKBT_TV_POWERON_WHITELIST
|
||||
@@ -1914,23 +1540,13 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
struct usb_device *udev;
|
||||
udev = interface_to_usbdev(intf);
|
||||
|
||||
RTKBT_INFO("btusb_probe intf->cur_altsetting->desc.bInterfaceNumber %d",
|
||||
RTKBT_DBG("btusb_probe intf->cur_altsetting->desc.bInterfaceNumber %d",
|
||||
intf->cur_altsetting->desc.bInterfaceNumber);
|
||||
|
||||
/* interface numbers are hardcoded in the spec */
|
||||
if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
|
||||
return -ENODEV;
|
||||
|
||||
if (!id->driver_info) {
|
||||
const struct usb_device_id *match;
|
||||
|
||||
match = usb_match_id(intf, blacklist_table);
|
||||
if (match)
|
||||
id = match;
|
||||
else
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
flag1 = device_can_wakeup(&udev->dev);
|
||||
flag2 = device_may_wakeup(&udev->dev);
|
||||
@@ -2020,13 +1636,6 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
hdev->flush = btusb_flush;
|
||||
hdev->send = btusb_send_frame;
|
||||
hdev->notify = btusb_notify;
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
hdev->setup = btusb_setup;
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
|
||||
hdev->shutdown = btusb_shutdown;
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
|
||||
hci_set_drvdata(hdev, data);
|
||||
@@ -2036,14 +1645,10 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
hdev->owner = THIS_MODULE;
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
set_bit(BTUSB_USE_ALT3_FOR_WBS, &data->flags);
|
||||
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 7, 1)
|
||||
if (!reset)
|
||||
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
|
||||
RTKBT_DBG("set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);");
|
||||
#endif
|
||||
|
||||
/* Interface numbers are hardcoded in the specification */
|
||||
|
||||
@@ -1,23 +1,12 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
*
|
||||
* Realtek Bluetooth USB driver
|
||||
*
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#ifndef __RTK_BT_H__
|
||||
#define __RTK_BT_H__
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -41,17 +30,14 @@
|
||||
/* #define HCI_VERSION_CODE KERNEL_VERSION(3, 14, 41) */
|
||||
#define HCI_VERSION_CODE LINUX_VERSION_CODE
|
||||
|
||||
#define CONFIG_BTCOEX 1
|
||||
#define CONFIG_BTUSB_WAKEUP_HOST 0
|
||||
|
||||
#if CONFIG_BTCOEX
|
||||
#ifdef CONFIG_BTCOEX
|
||||
#define BTCOEX
|
||||
#endif
|
||||
|
||||
/***********************************
|
||||
** Realtek - For rtk_btusb driver **
|
||||
***********************************/
|
||||
#if CONFIG_BTUSB_WAKEUP_HOST
|
||||
#ifdef CONFIG_BTUSB_WAKEUP_HOST
|
||||
#define BTUSB_WAKEUP_HOST
|
||||
#endif
|
||||
|
||||
@@ -98,7 +84,6 @@ int btusb_send_frame(struct sk_buff *skb);
|
||||
#define BTUSB_ISOC_RUNNING 2
|
||||
#define BTUSB_SUSPENDING 3
|
||||
#define BTUSB_DID_ISO_RESUME 4
|
||||
#define BTUSB_USE_ALT3_FOR_WBS 15
|
||||
|
||||
struct btusb_data {
|
||||
struct hci_dev *hdev;
|
||||
@@ -140,7 +125,6 @@ struct btusb_data {
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
unsigned int air_mode;
|
||||
bool usb_alt6_packet_flow;
|
||||
#endif
|
||||
int isoc_altsetting;
|
||||
int suspend_count;
|
||||
@@ -152,3 +136,6 @@ struct btusb_data {
|
||||
struct notifier_block shutdown_notifier;
|
||||
void *context;
|
||||
};
|
||||
|
||||
|
||||
#endif /* __RTK_BT_H__ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,23 +1,12 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
*
|
||||
* Realtek Bluetooth USB driver
|
||||
*
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#ifndef __RTK_COEX_H__
|
||||
#define __RTK_COEX_H__
|
||||
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
@@ -49,13 +38,6 @@
|
||||
#define HCI_EV_LE_CONN_UPDATE_COMPLETE 0x03
|
||||
#define HCI_EV_LE_ENHANCED_CONN_COMPLETE 0x0a
|
||||
|
||||
#define HCI_EV_LE_CIS_EST 0x19
|
||||
#define HCI_EV_LE_CREATE_BIG_CPL 0x1b
|
||||
#define HCI_EV_LE_TERM_BIG_CPL 0x1c
|
||||
#define HCI_EV_LE_BIG_SYNC_EST 0x1d
|
||||
#define HCI_EV_LE_BIG_SYNC_LOST 0x1e
|
||||
#define HCI_EV_LE_REMOVE_ISO_DATA_PATH 0x23
|
||||
|
||||
//vendor cmd to fw
|
||||
#define HCI_VENDOR_ENABLE_PROFILE_REPORT_COMMAND 0xfc18
|
||||
#define HCI_VENDOR_SET_PROFILE_REPORT_LEGACY_COMMAND 0xfc19
|
||||
@@ -158,11 +140,7 @@ enum {
|
||||
profile_hogp = 5,
|
||||
profile_voice = 6,
|
||||
profile_sink = 7,
|
||||
profile_lea_src = 8,
|
||||
profile_opprx = 9,
|
||||
profile_lea_snk = 10,
|
||||
profile_a2dpsink = 11,
|
||||
profile_max = 12
|
||||
profile_max = 8
|
||||
};
|
||||
|
||||
#define A2DP_SIGNAL 0x01
|
||||
@@ -181,10 +159,7 @@ typedef struct {
|
||||
//profile info for each connection
|
||||
typedef struct rtl_hci_conn {
|
||||
struct list_head list;
|
||||
u16 big_handle;
|
||||
u16 handle;
|
||||
u8 direction;
|
||||
u8 remove_path;
|
||||
uint16_t handle;
|
||||
struct delayed_work a2dp_count_work;
|
||||
struct delayed_work pan_count_work;
|
||||
struct delayed_work hogp_count_work;
|
||||
@@ -195,7 +170,7 @@ typedef struct rtl_hci_conn {
|
||||
uint8_t type; // 0:l2cap, 1:sco/esco, 2:le
|
||||
uint16_t profile_bitmap;
|
||||
uint16_t profile_status;
|
||||
int8_t profile_refcount[profile_max];
|
||||
int8_t profile_refcount[8];
|
||||
} rtk_conn_prof, *prtk_conn_prof;
|
||||
|
||||
#ifdef RTB_SOFTWARE_MAILBOX
|
||||
@@ -229,40 +204,21 @@ struct rtl_btinfo_ctl {
|
||||
};
|
||||
#endif /* RTB_SOFTWARE_MAILBOX */
|
||||
|
||||
#define HCI_PT_CMD 0x01
|
||||
#define HCI_PT_EVT 0x02
|
||||
#define HCI_PT_L2SIG_RX 0x03
|
||||
#define HCI_PT_L2SIG_TX 0x04
|
||||
#define HCI_PT_L2DATA_RX 0x05
|
||||
#define HCI_PT_L2DATA_TX 0x06
|
||||
|
||||
struct rtl_hci_hdr {
|
||||
struct list_head list;
|
||||
u8 type;
|
||||
u16 len;
|
||||
};
|
||||
|
||||
#define MAX_LEN_OF_HCI_EV 32
|
||||
#define NUM_RTL_HCI_EV 32
|
||||
struct rtl_hci_ev {
|
||||
struct list_head list;
|
||||
u8 type;
|
||||
u16 len;
|
||||
|
||||
/* private */
|
||||
__u8 data[MAX_LEN_OF_HCI_EV];
|
||||
__u16 len;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
#define L2_MAX_SUBSEC_LEN 128
|
||||
#define L2_MAX_PKTS 16
|
||||
struct rtl_l2_buff {
|
||||
struct list_head list;
|
||||
u8 type;
|
||||
u16 len;
|
||||
|
||||
/* private */
|
||||
__u8 data[L2_MAX_SUBSEC_LEN];
|
||||
__u16 len;
|
||||
__u16 out;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct rtl_coex_struct {
|
||||
@@ -280,18 +236,18 @@ struct rtl_coex_struct {
|
||||
struct delayed_work sock_work;
|
||||
#endif
|
||||
struct workqueue_struct *fw_wq;
|
||||
struct workqueue_struct *timer_wq;
|
||||
struct delayed_work fw_work;
|
||||
struct delayed_work cmd_work;
|
||||
struct delayed_work l2_work;
|
||||
#ifdef RTB_SOFTWARE_MAILBOX
|
||||
struct sock *sk;
|
||||
#endif
|
||||
struct urb *urb;
|
||||
spinlock_t spin_lock_sock;
|
||||
struct mutex profile_mutex;
|
||||
struct mutex conn_mutex;
|
||||
spinlock_t spin_lock_profile;
|
||||
uint16_t profile_bitmap;
|
||||
uint16_t profile_status;
|
||||
int8_t profile_refcount[profile_max];
|
||||
int8_t profile_refcount[8];
|
||||
uint8_t ispairing;
|
||||
uint8_t isinquirying;
|
||||
uint8_t ispaging;
|
||||
@@ -310,9 +266,12 @@ struct rtl_coex_struct {
|
||||
uint8_t wifi_on;
|
||||
uint8_t sock_open;
|
||||
#endif
|
||||
|
||||
unsigned long cmd_last_tx;
|
||||
|
||||
/* hci ev buff */
|
||||
struct list_head ev_used_list;
|
||||
struct list_head ev_free_list;
|
||||
|
||||
spinlock_t rxlock;
|
||||
__u8 pkt_type;
|
||||
__u16 expect;
|
||||
@@ -320,18 +279,16 @@ struct rtl_coex_struct {
|
||||
__u16 elen;
|
||||
__u8 back_buff[HCI_MAX_EVENT_SIZE];
|
||||
|
||||
struct list_head ev_free_list;
|
||||
/* l2cap rx buff */
|
||||
struct list_head l2_used_list;
|
||||
struct list_head l2_free_list;
|
||||
struct list_head hci_pkt_list;
|
||||
|
||||
/* buff addr and size */
|
||||
spinlock_t buff_lock;
|
||||
unsigned long pages_addr;
|
||||
unsigned long buff_size;
|
||||
|
||||
#define RTL_COEX_RUNNING 1
|
||||
#define RTL_COEX_PKT_COUNTING 2
|
||||
#define RTL_COEX_CONN_REMOVING 3
|
||||
#define RTL_COEX_RUNNING (1 << 0)
|
||||
unsigned long flags;
|
||||
|
||||
};
|
||||
@@ -406,3 +363,6 @@ void rtk_btcoex_close(void);
|
||||
void rtk_btcoex_probe(struct hci_dev *hdev);
|
||||
void rtk_btcoex_init(void);
|
||||
void rtk_btcoex_exit(void);
|
||||
|
||||
|
||||
#endif /* __RTK_COEX_H__ */
|
||||
@@ -1,22 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
*
|
||||
* Realtek Bluetooth USB download firmware driver
|
||||
*
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@@ -44,7 +30,6 @@
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
@@ -69,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;
|
||||
@@ -99,7 +84,6 @@ static struct list_head list_extracfgs;
|
||||
#define HCI_VENDOR_READ_RTK_ROM_VERISION 0xfc6d
|
||||
#define HCI_VENDOR_READ_LMP_VERISION 0x1001
|
||||
#define HCI_VENDOR_READ_CMD 0xfc61
|
||||
#define HCI_VENDOR_WRITE_CMD 0xfc62
|
||||
|
||||
#define ROM_LMP_NONE 0x0000
|
||||
#define ROM_LMP_8723a 0x1200
|
||||
@@ -108,9 +92,6 @@ static struct list_head list_extracfgs;
|
||||
#define ROM_LMP_8761a 0X8761
|
||||
#define ROM_LMP_8822b 0X8822
|
||||
#define ROM_LMP_8852a 0x8852
|
||||
#define ROM_LMP_8851b 0x8851
|
||||
#define ROM_LMP_8922a 0x8922
|
||||
#define ROM_LMP_8723c 0x8703
|
||||
|
||||
#define PATCH_SNIPPETS 0x01
|
||||
#define PATCH_DUMMY_HEADER 0x02
|
||||
@@ -182,30 +163,41 @@ static const uint8_t RTK_EPATCH_SIGNATURE_NEW[8] =
|
||||
//Extension Section IGNATURE:0x77FD0451
|
||||
static const uint8_t Extension_Section_SIGNATURE[4] = { 0x51, 0x04, 0xFD, 0x77 };
|
||||
|
||||
static const struct {
|
||||
__u16 lmp_subver;
|
||||
__u8 id;
|
||||
} project_id_to_lmp_subver[] = {
|
||||
{ ROM_LMP_8723a, 0 },
|
||||
{ ROM_LMP_8723b, 1 },
|
||||
{ ROM_LMP_8821a, 2 },
|
||||
{ ROM_LMP_8761a, 3 },
|
||||
{ ROM_LMP_8723c, 7 },
|
||||
{ ROM_LMP_8822b, 8 }, /* 8822B */
|
||||
{ ROM_LMP_8723b, 9 }, /* 8723D */
|
||||
{ ROM_LMP_8821a, 10 }, /* 8821C */
|
||||
{ ROM_LMP_8822b, 13 }, /* 8822C */
|
||||
{ ROM_LMP_8761a, 14 }, /* 8761B */
|
||||
{ ROM_LMP_8852a, 18 }, /* 8852A */
|
||||
{ ROM_LMP_8723b, 19 }, /* 8733B */
|
||||
{ ROM_LMP_8852a, 20 }, /* 8852B */
|
||||
{ ROM_LMP_8852a, 25 }, /* 8852C */
|
||||
{ ROM_LMP_8822b, 33 }, /* 8822E */
|
||||
{ ROM_LMP_8851b, 36 }, /* 8851B */
|
||||
{ ROM_LMP_8852a, 42 }, /* 8852D */
|
||||
{ ROM_LMP_8922a, 44 }, /* 8922A */
|
||||
{ ROM_LMP_8852a, 47 }, /* 8852BT */
|
||||
{ ROM_LMP_8761a, 51 }, /* 8761C */
|
||||
static uint16_t project_id[] = {
|
||||
ROM_LMP_8723a,
|
||||
ROM_LMP_8723b,
|
||||
ROM_LMP_8821a,
|
||||
ROM_LMP_8761a,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_8822b,
|
||||
ROM_LMP_8723b, /* RTL8723DU */
|
||||
ROM_LMP_8821a, /* RTL8821CU */
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_8822b, /* RTL8822CU */
|
||||
ROM_LMP_8761a, /* index 14 for 8761BU */
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_8852a, /* index 18 for 8852AU */
|
||||
ROM_LMP_8723b, /* index 19 for 8723FU */
|
||||
ROM_LMP_8852a, /* index 20 for 8852BU */
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_8852a, /* index 25 for 8852CU */
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_8822b, /* index 33 for 8822EU */
|
||||
};
|
||||
|
||||
enum rtk_endpoit {
|
||||
@@ -223,16 +215,10 @@ enum rtk_endpoit {
|
||||
#define RTL8822CU 0x73
|
||||
#define RTL8761BU 0x74
|
||||
#define RTL8852AU 0x75
|
||||
#define RTL8733BU 0x76
|
||||
#define RTL8723FU 0x76
|
||||
#define RTL8852BU 0x77
|
||||
#define RTL8852CU 0x78
|
||||
#define RTL8822EU 0x79
|
||||
#define RTL8851BU 0x7A
|
||||
#define RTL8852DU 0x7B
|
||||
#define RTL8922AU 0x7C
|
||||
#define RTL8852BTU 0x7D
|
||||
#define RTL8761CU 0x80
|
||||
#define RTL8723CU 0x81
|
||||
|
||||
typedef struct {
|
||||
uint16_t prod_id;
|
||||
@@ -293,7 +279,7 @@ static uint8_t g_key_id = 0;
|
||||
|
||||
static dev_data *dev_data_find(struct usb_interface *intf);
|
||||
static patch_info *get_patch_entry(struct usb_device *udev);
|
||||
static int load_firmware(dev_data *dev_entry, xchange_data *xdata);
|
||||
static int load_firmware(dev_data * dev_entry, uint8_t ** buff);
|
||||
static void init_xdata(xchange_data * xdata, dev_data * dev_entry);
|
||||
static int check_fw_version(xchange_data * xdata);
|
||||
static int download_data(xchange_data * xdata);
|
||||
@@ -358,8 +344,6 @@ static patch_info fw_patch_table[] = {
|
||||
{0xb009, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", RTL8723DU}, /* RTL8723DU */
|
||||
{0x0231, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", RTL8723DU}, /* RTL8723DU for LiteOn */
|
||||
|
||||
{0xb703, 0x8703, "mp_rtl8723cu_fw", "rtl8723cu_fw", "rtl8723cu_config", RTL8723CU}, /* RTL8723CU */
|
||||
|
||||
{0xb820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CU */
|
||||
{0xc820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CU */
|
||||
{0xc821, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE */
|
||||
@@ -393,7 +377,6 @@ static patch_info fw_patch_table[] = {
|
||||
{0xc82e, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CU */
|
||||
{0xc81d, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CU */
|
||||
{0xd820, 0x8822, "mp_rtl8821du_fw", "rtl8821du_fw", "rtl8821du_config", RTL8822CU}, /* RTL8821DU */
|
||||
{0x053b, 0x8822, "mp_rtl8821du_fw", "rtl8821du_fw", "rtl8821du_config", RTL8822CU}, /* RTL8821DU for Epson*/
|
||||
|
||||
{0xc822, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
|
||||
{0xc82b, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
|
||||
@@ -422,7 +405,6 @@ static patch_info fw_patch_table[] = {
|
||||
{0xc03f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE-VS */
|
||||
|
||||
{0x8771, 0x8761, "mp_rtl8761b_fw", "rtl8761bu_fw", "rtl8761bu_config", RTL8761BU}, /* RTL8761BU only */
|
||||
{0x876e, 0x8761, "mp_rtl8761b_fw", "rtl8761bu_fw", "rtl8761bu_config", RTL8761BU}, /* RTL8761BUE */
|
||||
{0xa725, 0x8761, "mp_rtl8761b_fw", "rtl8725au_fw", "rtl8725au_config", RTL8761BU}, /* RTL8725AU */
|
||||
{0xa72A, 0x8761, "mp_rtl8761b_fw", "rtl8725au_fw", "rtl8725au_config", RTL8761BU}, /* RTL8725AU BT only */
|
||||
|
||||
@@ -443,13 +425,14 @@ static patch_info fw_patch_table[] = {
|
||||
{0xc125, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
|
||||
{0xe852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
|
||||
{0xb852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
|
||||
{0xc852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
|
||||
{0xc549, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
|
||||
{0xc127, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
|
||||
{0x3565, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
|
||||
|
||||
{0xb733, 0x8723, "mp_rtl8733bu_fw", "rtl8733bu_fw", "rtl8733bu_config", RTL8733BU}, /* RTL8733BU */
|
||||
{0xb73a, 0x8723, "mp_rtl8733bu_fw", "rtl8733bu_fw", "rtl8733bu_config", RTL8733BU}, /* RTL8733BU */
|
||||
{0xf72b, 0x8723, "mp_rtl8733bu_fw", "rtl8733bu_fw", "rtl8733bu_config", RTL8733BU}, /* RTL8733BU */
|
||||
{0xb733, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", RTL8723FU}, /* RTL8723FU */
|
||||
{0xb73a, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", RTL8723FU}, /* RTL8723FU */
|
||||
{0xf72b, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", RTL8723FU}, /* RTL8723FU */
|
||||
|
||||
{0x8851, 0x8852, "mp_rtl8851au_fw", "rtl8851au_fw", "rtl8851au_config", RTL8852BU}, /* RTL8851AU */
|
||||
{0xa85b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", RTL8852BU}, /* RTL8852BU */
|
||||
@@ -470,7 +453,6 @@ static patch_info fw_patch_table[] = {
|
||||
{0x1670, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", RTL8852BU}, /* RTL8852BE */
|
||||
|
||||
{0xc85a, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CU */
|
||||
{0xc85d, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CU */
|
||||
{0x0852, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
|
||||
{0x5852, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
|
||||
{0xc85c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
|
||||
@@ -478,29 +460,10 @@ static patch_info fw_patch_table[] = {
|
||||
{0x886c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
|
||||
{0x887c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
|
||||
{0x4007, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
|
||||
{0x1675, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
|
||||
{0x3586, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
|
||||
|
||||
{0xe822, 0x8822, "mp_rtl8822eu_fw", "rtl8822eu_fw", "rtl8822eu_config", RTL8822EU}, /* RTL8822EU */
|
||||
{0xa82a, 0x8822, "mp_rtl8822eu_fw", "rtl8822eu_fw", "rtl8822eu_config", RTL8822EU}, /* RTL8822EU */
|
||||
|
||||
{0xb851, 0x8851, "mp_rtl8851bu_fw", "rtl8851bu_fw", "rtl8851bu_config", RTL8851BU}, /* RTL8851BU */
|
||||
|
||||
{0xd85a, 0x8852, "mp_rtl8852du_fw", "rtl8852du_fw", "rtl8852du_config", RTL8852DU}, /* RTL8852DU */
|
||||
|
||||
{0x892a, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AU */
|
||||
{0x8922, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
|
||||
{0xa890, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
|
||||
{0xa891, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
|
||||
{0xa892, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
|
||||
{0xd922, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
|
||||
{0xb85f, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
|
||||
|
||||
{0xc852, 0x8852, "mp_rtl8852btu_fw", "rtl8852btu_fw", "rtl8852btu_config", RTL8852BTU}, /* RTL8852BTU */
|
||||
{0x8520, 0x8852, "mp_rtl8852btu_fw", "rtl8852btu_fw", "rtl8852btu_config", RTL8852BTU}, /* RTL8852BTE */
|
||||
|
||||
{0xc761, 0x8761, "mp_rtl8761cu_fw", "rtl8761cu_mx_fw", "rtl8761cu_mx_config", RTL8761CU}, /* RTL8761CU */
|
||||
|
||||
/* NOTE: must append patch entries above the null entry */
|
||||
{0, 0, NULL, NULL, NULL, 0}
|
||||
};
|
||||
@@ -783,7 +746,6 @@ static inline int get_max_patch_size(u8 chip_type)
|
||||
max_patch_size = 25 * 1024;
|
||||
break;
|
||||
case RTL8723DU:
|
||||
case RTL8723CU:
|
||||
case RTL8822CU:
|
||||
case RTL8761BU:
|
||||
case RTL8821CU:
|
||||
@@ -792,11 +754,10 @@ static inline int get_max_patch_size(u8 chip_type)
|
||||
case RTL8852AU:
|
||||
max_patch_size = 0x114D0 + 529; /* 69.2KB */
|
||||
break;
|
||||
case RTL8733BU:
|
||||
case RTL8723FU:
|
||||
max_patch_size = 0xC4Cf + 529; /* 49.2KB */
|
||||
break;
|
||||
case RTL8852BU:
|
||||
case RTL8851BU:
|
||||
max_patch_size = 0x104D0 + 529; /* 65KB */
|
||||
break;
|
||||
case RTL8852CU:
|
||||
@@ -805,18 +766,6 @@ static inline int get_max_patch_size(u8 chip_type)
|
||||
case RTL8822EU:
|
||||
max_patch_size = 0x24620 + 529; /* 145KB */
|
||||
break;
|
||||
case RTL8852DU:
|
||||
max_patch_size = 0x20D90 + 529; /* 131KB */
|
||||
break;
|
||||
case RTL8922AU:
|
||||
max_patch_size = 0x23810 + 529; /* 142KB */
|
||||
break;
|
||||
case RTL8852BTU:
|
||||
max_patch_size = 0x27E00 + 529; /* 159.5KB */
|
||||
break;
|
||||
case RTL8761CU:
|
||||
max_patch_size = 1024 * 1024; /* 1MB */
|
||||
break;
|
||||
default:
|
||||
max_patch_size = 40 * 1024;
|
||||
break;
|
||||
@@ -825,64 +774,11 @@ static inline int get_max_patch_size(u8 chip_type)
|
||||
return max_patch_size;
|
||||
}
|
||||
|
||||
static int rtk_vendor_write(dev_data * dev_entry)
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
xchange_data *xdata = NULL;
|
||||
unsigned char cmd_buf[] = {0x31, 0x90, 0xd0, 0x29, 0x80, 0x00, 0x00,
|
||||
0x00, 0x00};
|
||||
|
||||
xdata = kzalloc(sizeof(xchange_data), GFP_KERNEL);
|
||||
if (NULL == xdata) {
|
||||
ret_val = 0xFE;
|
||||
RTKBT_DBG("NULL == xdata");
|
||||
return -1;
|
||||
}
|
||||
|
||||
init_xdata(xdata, dev_entry);
|
||||
|
||||
xdata->cmd_hdr->opcode = cpu_to_le16(HCI_VENDOR_WRITE_CMD);
|
||||
xdata->cmd_hdr->plen = 9;
|
||||
memcpy(xdata->send_pkt, &(xdata->cmd_hdr->opcode), 2);
|
||||
memcpy(xdata->send_pkt+2, &(xdata->cmd_hdr->plen), 1);
|
||||
|
||||
memcpy(xdata->send_pkt+3, cmd_buf, sizeof(cmd_buf));
|
||||
|
||||
xdata->pkt_len = CMD_HDR_LEN + 9;
|
||||
|
||||
ret_val = send_hci_cmd(xdata);
|
||||
if (ret_val < 0) {
|
||||
RTKBT_ERR("%s: Failed to send HCI command.", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret_val = rcv_hci_evt(xdata);
|
||||
if (ret_val < 0) {
|
||||
RTKBT_ERR("%s: Failed to receive HCI event.", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret_val = 0;
|
||||
end:
|
||||
if (xdata != NULL) {
|
||||
if (xdata->send_pkt)
|
||||
kfree(xdata->send_pkt);
|
||||
if (xdata->rcv_pkt)
|
||||
kfree(xdata->rcv_pkt);
|
||||
kfree(xdata);
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static int check_fw_chip_ver(dev_data * dev_entry, xchange_data * xdata)
|
||||
{
|
||||
int ret_val;
|
||||
uint16_t chip = 0;
|
||||
uint16_t chip_ver = 0;
|
||||
uint16_t lmp_subver, hci_rev;
|
||||
patch_info *patch_entry;
|
||||
struct hci_rp_read_local_version *read_ver_rsp;
|
||||
|
||||
chip = rtk_vendor_read(dev_entry, READ_CHIP_TYPE);
|
||||
if(chip == 0x8822) {
|
||||
@@ -905,16 +801,9 @@ static int check_fw_chip_ver(dev_data * dev_entry, xchange_data * xdata)
|
||||
gEVersion = rtk_get_eversion(dev_entry);
|
||||
}
|
||||
return ret_val;
|
||||
} else {
|
||||
patch_entry = xdata->dev_entry->patch_entry;
|
||||
read_ver_rsp = (struct hci_rp_read_local_version *)(xdata->rsp_para);
|
||||
lmp_subver = le16_to_cpu(read_ver_rsp->lmp_subver);
|
||||
hci_rev = le16_to_cpu(read_ver_rsp->hci_rev);
|
||||
if (lmp_subver == 0x8852 && hci_rev == 0x000d)
|
||||
ret_val = rtk_vendor_write(dev_entry);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int download_patch(struct usb_interface *intf)
|
||||
@@ -947,7 +836,7 @@ int download_patch(struct usb_interface *intf)
|
||||
if (ret_val != 0 )
|
||||
goto patch_end;
|
||||
|
||||
xdata->fw_len = load_firmware(dev_entry, xdata);
|
||||
xdata->fw_len = load_firmware(dev_entry, &xdata->fw_data);
|
||||
if (xdata->fw_len <= 0) {
|
||||
RTKBT_ERR("load firmware failed!");
|
||||
ret_val = -1;
|
||||
@@ -986,7 +875,7 @@ int download_patch(struct usb_interface *intf)
|
||||
|
||||
ret_val = 0;
|
||||
patch_fail:
|
||||
vfree(fw_buf);
|
||||
kfree(fw_buf);
|
||||
patch_end:
|
||||
if (xdata != NULL) {
|
||||
if (xdata->send_pkt)
|
||||
@@ -1004,7 +893,7 @@ patch_end:
|
||||
* -1: error
|
||||
* 0: download patch successfully
|
||||
* >0: patch already exists */
|
||||
int download_special_patch(struct usb_interface *intf, const char *special_name)
|
||||
int download_lps_patch(struct usb_interface *intf)
|
||||
{
|
||||
dev_data *dev_entry;
|
||||
patch_info *pinfo;
|
||||
@@ -1046,18 +935,15 @@ int download_special_patch(struct usb_interface *intf, const char *special_name)
|
||||
}
|
||||
goto patch_end;
|
||||
}
|
||||
memset(name1, 0, sizeof(name1));
|
||||
memset(name2, 0, sizeof(name2));
|
||||
|
||||
origin_name1 = dev_entry->patch_entry->patch_name;
|
||||
origin_name2 = dev_entry->patch_entry->config_name;
|
||||
memcpy(name1, special_name, strlen(special_name));
|
||||
strncat(name1, origin_name1, sizeof(name1) - 1 - strlen(special_name));
|
||||
memcpy(name2, special_name, strlen(special_name));
|
||||
strncat(name2, origin_name2, sizeof(name2) - 1 - strlen(special_name));
|
||||
snprintf(name1, sizeof(name1), "lps_%s", origin_name1);
|
||||
snprintf(name2, sizeof(name2), "lps_%s", origin_name2);
|
||||
dev_entry->patch_entry->patch_name = name1;
|
||||
dev_entry->patch_entry->config_name = name2;
|
||||
RTKBT_INFO("Loading %s and %s", name1, name2);
|
||||
xdata->fw_len = load_firmware(dev_entry, xdata);
|
||||
xdata->fw_len = load_firmware(dev_entry, &xdata->fw_data);
|
||||
dev_entry->patch_entry->patch_name = origin_name1;
|
||||
dev_entry->patch_entry->config_name = origin_name2;
|
||||
if (xdata->fw_len <= 0) {
|
||||
@@ -1069,13 +955,11 @@ int download_special_patch(struct usb_interface *intf, const char *special_name)
|
||||
fw_buf = xdata->fw_data;
|
||||
|
||||
pinfo = dev_entry->patch_entry;
|
||||
/*
|
||||
if (!pinfo) {
|
||||
RTKBT_ERR("%s: No patch entry", __func__);
|
||||
result = -1;
|
||||
goto patch_fail;
|
||||
}
|
||||
*/
|
||||
max_patch_size = get_max_patch_size(pinfo->chip_type);
|
||||
if (xdata->fw_len > max_patch_size) {
|
||||
result = -1;
|
||||
@@ -1114,39 +998,6 @@ patch_end:
|
||||
}
|
||||
#endif
|
||||
|
||||
int setup_btrealtek_flag(struct usb_interface *intf, struct hci_dev *hdev)
|
||||
{
|
||||
dev_data *dev_entry;
|
||||
patch_info *pinfo;
|
||||
int ret_val = 0;
|
||||
|
||||
dev_entry = dev_data_find(intf);
|
||||
if (NULL == dev_entry) {
|
||||
ret_val = -1;
|
||||
RTKBT_ERR("%s: NULL == dev_entry", __func__);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
pinfo = dev_entry->patch_entry;
|
||||
if (!pinfo) {
|
||||
RTKBT_ERR("%s: No patch entry", __func__);
|
||||
ret_val = -1;
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
switch (pinfo->chip_type){
|
||||
case RTL8852CU:
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
btrealtek_set_flag(hdev, REALTEK_ALT6_CONTINUOUS_TX_CHIP);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
#if defined RTKBT_SUSPEND_WAKEUP || defined RTKBT_SHUTDOWN_WAKEUP || defined RTKBT_SWITCH_PATCH
|
||||
int set_scan(struct usb_interface *intf)
|
||||
{
|
||||
@@ -1194,7 +1045,7 @@ end:
|
||||
|
||||
dev_data *dev_data_find(struct usb_interface * intf)
|
||||
{
|
||||
dev_data *dev_entry = NULL;
|
||||
dev_data *dev_entry;
|
||||
|
||||
list_for_each_entry(dev_entry, &dev_data_list, list_node) {
|
||||
if (dev_entry->intf == intf) {
|
||||
@@ -1237,7 +1088,6 @@ static int is_mac(u8 chip_type, u16 offset)
|
||||
switch (chip_type) {
|
||||
case RTL8822BU:
|
||||
case RTL8723DU:
|
||||
case RTL8723CU:
|
||||
case RTL8821CU:
|
||||
if (offset == 0x0044)
|
||||
return 1;
|
||||
@@ -1245,15 +1095,10 @@ static int is_mac(u8 chip_type, u16 offset)
|
||||
case RTL8822CU:
|
||||
case RTL8761BU:
|
||||
case RTL8852AU:
|
||||
case RTL8733BU:
|
||||
case RTL8723FU:
|
||||
case RTL8852BU:
|
||||
case RTL8852CU:
|
||||
case RTL8822EU:
|
||||
case RTL8851BU:
|
||||
case RTL8852DU:
|
||||
case RTL8922AU:
|
||||
case RTL8852BTU:
|
||||
case RTL8761CU:
|
||||
if (offset == 0x0030)
|
||||
return 1;
|
||||
break;
|
||||
@@ -1271,21 +1116,15 @@ static uint16_t get_mac_offset(u8 chip_type)
|
||||
switch (chip_type) {
|
||||
case RTL8822BU:
|
||||
case RTL8723DU:
|
||||
case RTL8723CU:
|
||||
case RTL8821CU:
|
||||
return 0x0044;
|
||||
case RTL8822CU:
|
||||
case RTL8761BU:
|
||||
case RTL8852AU:
|
||||
case RTL8733BU:
|
||||
case RTL8723FU:
|
||||
case RTL8852BU:
|
||||
case RTL8852CU:
|
||||
case RTL8822EU:
|
||||
case RTL8851BU:
|
||||
case RTL8852DU:
|
||||
case RTL8922AU:
|
||||
case RTL8852BTU:
|
||||
case RTL8761CU:
|
||||
return 0x0030;
|
||||
case RTLPREVIOUS:
|
||||
return 0x003c;
|
||||
@@ -1613,12 +1452,14 @@ static uint8_t *rtb_get_patch_header(int *len,
|
||||
}
|
||||
break;
|
||||
default:
|
||||
RTKBT_INFO("Unknown Opcode. Ignore");
|
||||
RTKBT_ERR("Wrong Opcode");
|
||||
goto wrong_opcode;
|
||||
}
|
||||
section_pos += (SECTION_HEADER_SIZE + section_hdr.section_len);
|
||||
}
|
||||
*len = patch_len;
|
||||
|
||||
wrong_opcode:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1902,7 +1743,7 @@ static int rtk_vendor_read(dev_data * dev_entry, uint8_t class)
|
||||
xchange_data *xdata = NULL;
|
||||
unsigned char cmd_ct_buf[] = {0x10, 0x38, 0x04, 0x28, 0x80};
|
||||
unsigned char cmd_cv_buf[] = {0x10, 0x3A, 0x04, 0x28, 0x80};
|
||||
unsigned char cmd_sec_buf[] = {0x10, 0xA4, 0xAD, 0x00, 0xb0};
|
||||
unsigned char cmd_sec_buf[] = {0x10, 0xA4, 0x0D, 0x00, 0xb0};
|
||||
|
||||
xdata = kzalloc(sizeof(xchange_data), GFP_KERNEL);
|
||||
if (NULL == xdata) {
|
||||
@@ -1970,6 +1811,7 @@ static int rtk_vendor_read(dev_data * dev_entry, uint8_t class)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
read_end:
|
||||
if (xdata != NULL) {
|
||||
if (xdata->send_pkt)
|
||||
@@ -1981,57 +1823,7 @@ read_end:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static int needs_hci_upgrade(xchange_data *xdata, u8 *buf, u32 buf_len)
|
||||
{
|
||||
struct {
|
||||
u8 status;
|
||||
u8 subopcode;
|
||||
u8 ota;
|
||||
} __attribute__((packed)) *evt_params;
|
||||
#define UPG_DL_BLOCK_SIZE 128
|
||||
#define UPG_SUBCMD_CODE 0x01
|
||||
u8 len = UPG_DL_BLOCK_SIZE;
|
||||
u8 *cmd_params;
|
||||
int ret;
|
||||
|
||||
cmd_params = xdata->req_para;
|
||||
evt_params = (void *)xdata->rsp_para;
|
||||
xdata->cmd_hdr->opcode = cpu_to_le16(0xfdbb);
|
||||
if (buf_len < len)
|
||||
len = buf_len;
|
||||
xdata->cmd_hdr->plen = 1 + len;
|
||||
xdata->pkt_len = sizeof(*xdata->cmd_hdr) + xdata->cmd_hdr->plen;
|
||||
*cmd_params++ = UPG_SUBCMD_CODE;
|
||||
memcpy(cmd_params, buf, len);
|
||||
|
||||
ret = send_hci_cmd(xdata);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = rcv_hci_evt(xdata);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (evt_params->status) {
|
||||
RTKBT_ERR("needs_hci_upgrade: status %02x", evt_params->status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (evt_params->subopcode != UPG_SUBCMD_CODE) {
|
||||
RTKBT_ERR("needs_hci_upgrade: return subopcode %02x",
|
||||
evt_params->subopcode);
|
||||
return -2;
|
||||
}
|
||||
|
||||
RTKBT_INFO("needs_hci_upgrade: state %02x", evt_params->ota);
|
||||
|
||||
return evt_params->ota;
|
||||
}
|
||||
|
||||
/* buff: points to the allocated buffer that stores extracted fw and config
|
||||
* This function returns the total length of extracted fw and config
|
||||
*/
|
||||
int load_firmware(dev_data *dev_entry, xchange_data *xdata)
|
||||
int load_firmware(dev_data * dev_entry, uint8_t ** buff)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
struct usb_device *udev;
|
||||
@@ -2043,13 +1835,12 @@ int load_firmware(dev_data *dev_entry, xchange_data *xdata)
|
||||
uint8_t need_download_fw = 1;
|
||||
uint16_t lmp_version;
|
||||
struct rtk_epatch_entry current_entry = { 0 };
|
||||
|
||||
struct list_head *pos, *next;
|
||||
struct patch_node *tmp;
|
||||
struct patch_node patch_node_hdr;
|
||||
int i;
|
||||
|
||||
RTKBT_DBG("load_firmware start");
|
||||
|
||||
udev = dev_entry->udev;
|
||||
patch_entry = dev_entry->patch_entry;
|
||||
lmp_version = patch_entry->lmp_sub;
|
||||
@@ -2062,13 +1853,16 @@ int load_firmware(dev_data *dev_entry, xchange_data *xdata)
|
||||
ret_val = request_firmware(&fw, fw_name, &udev->dev);
|
||||
if (ret_val < 0) {
|
||||
RTKBT_ERR("request_firmware error");
|
||||
fw_len = 0;
|
||||
kfree(config_file_buf);
|
||||
config_file_buf = NULL;
|
||||
goto fw_fail;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&patch_node_hdr.list);
|
||||
|
||||
epatch_buf = vzalloc(fw->size);
|
||||
if (!epatch_buf)
|
||||
epatch_buf = kzalloc(fw->size, GFP_KERNEL);
|
||||
if (NULL == epatch_buf)
|
||||
goto alloc_fail;
|
||||
|
||||
memcpy(epatch_buf, fw->data, fw->size);
|
||||
@@ -2080,174 +1874,137 @@ int load_firmware(dev_data *dev_entry, xchange_data *xdata)
|
||||
if (memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8) == 0) {
|
||||
RTKBT_ERR("8723a Check signature error!");
|
||||
need_download_fw = 0;
|
||||
goto sign_err;
|
||||
}
|
||||
buf = vzalloc(buf_len);
|
||||
if (!buf) {
|
||||
RTKBT_ERR("Can't alloc memory for fw&config");
|
||||
buf_len = -1;
|
||||
goto alloc_buf_err;
|
||||
} else {
|
||||
if (!(buf = kzalloc(buf_len, GFP_KERNEL))) {
|
||||
RTKBT_ERR("Can't alloc memory for fw&config");
|
||||
buf_len = -1;
|
||||
} else {
|
||||
RTKBT_DBG("8723a, fw copy direct");
|
||||
memcpy(buf, epatch_buf, fw->size);
|
||||
if (config_len) {
|
||||
memcpy(&buf[buf_len - config_len],
|
||||
config_file_buf, config_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
RTKBT_ERR("This is not 8723a, use new patch style!");
|
||||
|
||||
RTKBT_DBG("8723a, fw copy direct");
|
||||
memcpy(buf, epatch_buf, fw->size);
|
||||
if (config_len)
|
||||
memcpy(&buf[buf_len - config_len], config_file_buf,
|
||||
config_len);
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
RTKBT_ERR("This is not 8723a, use new patch style!");
|
||||
|
||||
/* Get version from ROM */
|
||||
gEVersion = rtk_get_eversion(dev_entry);
|
||||
RTKBT_DBG("%s: New gEVersion %d", __func__, gEVersion);
|
||||
if (gEVersion == 0xFE) {
|
||||
RTKBT_ERR("%s: Read ROM version failure", __func__);
|
||||
need_download_fw = 0;
|
||||
goto alloc_fail;
|
||||
}
|
||||
|
||||
/* check Signature and Extension Section Field */
|
||||
if ((memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8) &&
|
||||
memcmp(epatch_buf, RTK_EPATCH_SIGNATURE_NEW, 8)) ||
|
||||
memcmp(epatch_buf + buf_len - config_len - 4,
|
||||
Extension_Section_SIGNATURE, 4) != 0) {
|
||||
RTKBT_ERR("Check SIGNATURE error! do not download fw");
|
||||
need_download_fw = 0;
|
||||
goto sign_err;
|
||||
}
|
||||
|
||||
proj_id = rtk_get_fw_project_id(epatch_buf + buf_len - config_len - 5);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(project_id_to_lmp_subver); i++) {
|
||||
if (proj_id == project_id_to_lmp_subver[i].id &&
|
||||
lmp_version == project_id_to_lmp_subver[i].lmp_subver) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= ARRAY_SIZE(project_id_to_lmp_subver)) {
|
||||
RTKBT_ERR("lmp_version %04x, project_id %u, does not match!!!",
|
||||
lmp_version, proj_id);
|
||||
need_download_fw = 0;
|
||||
goto proj_id_err;
|
||||
}
|
||||
|
||||
RTKBT_DBG("lmp_version is %04x, project_id is %u, match!",
|
||||
lmp_version, proj_id);
|
||||
|
||||
if (memcmp(epatch_buf, RTK_EPATCH_SIGNATURE_NEW, 8) == 0) {
|
||||
int key_id = rtk_vendor_read(dev_entry, READ_SEC_PROJ);
|
||||
int tmp_len = 0;
|
||||
|
||||
RTKBT_DBG("%s: key id %d", __func__, key_id);
|
||||
if (key_id < 0) {
|
||||
RTKBT_ERR("%s: Read key id failure", __func__);
|
||||
/* Get version from ROM */
|
||||
gEVersion = rtk_get_eversion(dev_entry);
|
||||
RTKBT_DBG("%s: New gEVersion %d", __func__, gEVersion);
|
||||
if (gEVersion == 0xFE) {
|
||||
RTKBT_ERR("%s: Read ROM version failure", __func__);
|
||||
need_download_fw = 0;
|
||||
fw_len = 0;
|
||||
goto extract_err;
|
||||
}
|
||||
rtb_get_patch_header(&buf_len, &patch_node_hdr, epatch_buf,
|
||||
key_id);
|
||||
if (!buf_len)
|
||||
goto extract_err;
|
||||
RTKBT_DBG("buf_len = 0x%x", buf_len);
|
||||
buf_len += config_len;
|
||||
|
||||
buf = vzalloc(buf_len);
|
||||
if (!buf) {
|
||||
RTKBT_ERR("Can't alloc memory for multi fw&config");
|
||||
buf_len = -1;
|
||||
goto alloc_buf_err;
|
||||
goto alloc_fail;
|
||||
}
|
||||
|
||||
list_for_each_safe(pos, next, &patch_node_hdr.list) {
|
||||
tmp = list_entry(pos, struct patch_node, list);
|
||||
RTKBT_DBG("len = 0x%x", tmp->len);
|
||||
memcpy(buf + tmp_len, tmp->payload, tmp->len);
|
||||
tmp_len += tmp->len;
|
||||
list_del_init(pos);
|
||||
kfree(tmp);
|
||||
}
|
||||
if (config_len)
|
||||
memcpy(&buf[buf_len - config_len], config_file_buf,
|
||||
config_len);
|
||||
} else {
|
||||
rtk_get_patch_entry(epatch_buf, ¤t_entry);
|
||||
|
||||
if (current_entry.patch_length == 0)
|
||||
goto extract_err;
|
||||
|
||||
buf_len = current_entry.patch_length + config_len;
|
||||
RTKBT_DBG("buf_len = 0x%x", buf_len);
|
||||
|
||||
buf = vzalloc(buf_len);
|
||||
if (!buf) {
|
||||
RTKBT_ERR("Can't alloc memory for multi fw&config");
|
||||
buf_len = -1;
|
||||
goto alloc_buf_err;
|
||||
}
|
||||
|
||||
memcpy(buf, epatch_buf + current_entry.start_offset,
|
||||
current_entry.patch_length);
|
||||
/* Copy fw version */
|
||||
memcpy(buf + current_entry.patch_length - 4, epatch_buf + 8, 4);
|
||||
if (config_len)
|
||||
memcpy(&buf[buf_len - config_len], config_file_buf,
|
||||
config_len);
|
||||
}
|
||||
|
||||
if (patch_entry->chip_type == RTL8761CU) {
|
||||
if (needs_hci_upgrade(xdata, buf, buf_len) <= 0) {
|
||||
if (config_len > 0) {
|
||||
memmove(buf, buf + buf_len - config_len,
|
||||
config_len);
|
||||
buf_len = config_len;
|
||||
} else {
|
||||
#define FAKE_SEG_LEN 16
|
||||
if (buf_len > FAKE_SEG_LEN)
|
||||
buf_len = FAKE_SEG_LEN;
|
||||
memset(buf, 0, buf_len);
|
||||
}
|
||||
/* check Signature and Extension Section Field */
|
||||
if (((memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8) != 0) && (memcmp(epatch_buf, RTK_EPATCH_SIGNATURE_NEW, 8) != 0))||
|
||||
memcmp(epatch_buf + buf_len - config_len - 4,
|
||||
Extension_Section_SIGNATURE, 4) != 0) {
|
||||
RTKBT_ERR("Check SIGNATURE error! do not download fw");
|
||||
need_download_fw = 0;
|
||||
} else {
|
||||
/* It does not need to download config when upgrading */
|
||||
buf_len -= config_len;
|
||||
proj_id =
|
||||
rtk_get_fw_project_id(epatch_buf + buf_len -
|
||||
config_len - 5);
|
||||
|
||||
if (lmp_version != project_id[proj_id]) {
|
||||
RTKBT_ERR
|
||||
("lmp_version is %x, project_id is %x, does not match!!!",
|
||||
lmp_version, project_id[proj_id]);
|
||||
need_download_fw = 0;
|
||||
} else {
|
||||
RTKBT_DBG
|
||||
("lmp_version is %x, project_id is %x, match!",
|
||||
lmp_version, project_id[proj_id]);
|
||||
|
||||
if(memcmp(epatch_buf, RTK_EPATCH_SIGNATURE_NEW, 8) == 0) {
|
||||
int key_id = rtk_vendor_read(dev_entry, READ_SEC_PROJ);
|
||||
RTKBT_DBG("%s: key id %d", __func__, key_id);
|
||||
if (key_id < 0) {
|
||||
RTKBT_ERR("%s: Read key id failure", __func__);
|
||||
need_download_fw = 0;
|
||||
fw_len = 0;
|
||||
goto alloc_fail;
|
||||
}
|
||||
rtb_get_patch_header(&buf_len, &patch_node_hdr, epatch_buf, key_id);
|
||||
if(buf_len == 0)
|
||||
goto alloc_fail;
|
||||
RTKBT_DBG("buf_len = 0x%x", buf_len);
|
||||
buf_len += config_len;
|
||||
} else {
|
||||
rtk_get_patch_entry(epatch_buf, ¤t_entry);
|
||||
|
||||
if (current_entry.patch_length == 0)
|
||||
goto alloc_fail;
|
||||
|
||||
buf_len = current_entry.patch_length + config_len;
|
||||
RTKBT_DBG("buf_len = 0x%x", buf_len);
|
||||
}
|
||||
|
||||
if (!(buf = kzalloc(buf_len, GFP_KERNEL))) {
|
||||
RTKBT_ERR
|
||||
("Can't alloc memory for multi fw&config");
|
||||
buf_len = -1;
|
||||
} else {
|
||||
if(memcmp(epatch_buf, RTK_EPATCH_SIGNATURE_NEW, 8) == 0) {
|
||||
int tmp_len = 0;
|
||||
list_for_each_safe(pos, next, &patch_node_hdr.list)
|
||||
{
|
||||
tmp = list_entry(pos, struct patch_node, list);
|
||||
RTKBT_DBG("len = 0x%x", tmp->len);
|
||||
memcpy(buf + tmp_len, tmp->payload, tmp->len);
|
||||
tmp_len += tmp->len;
|
||||
list_del_init(pos);
|
||||
kfree(tmp);
|
||||
}
|
||||
if (config_len) {
|
||||
memcpy(&buf
|
||||
[buf_len - config_len],
|
||||
config_file_buf,
|
||||
config_len);
|
||||
}
|
||||
} else {
|
||||
memcpy(buf,
|
||||
epatch_buf +
|
||||
current_entry.start_offset,
|
||||
current_entry.patch_length);
|
||||
memcpy(buf + current_entry.patch_length - 4, epatch_buf + 8, 4); /*fw version */
|
||||
if (config_len) {
|
||||
memcpy(&buf
|
||||
[buf_len - config_len],
|
||||
config_file_buf,
|
||||
config_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
RTKBT_DBG("fw:%s exists, config file:%s exists",
|
||||
buf_len > 0 ? "" : "not", config_len > 0 ? "" : "not");
|
||||
if (buf && buf_len > 0 && need_download_fw) {
|
||||
(buf_len > 0) ? "" : "not", (config_len > 0) ? "" : "not");
|
||||
if (buf && (buf_len > 0) && (need_download_fw)) {
|
||||
fw_len = buf_len;
|
||||
xdata->fw_data = buf;
|
||||
*buff = buf;
|
||||
}
|
||||
|
||||
RTKBT_DBG("load_firmware done");
|
||||
alloc_buf_err:
|
||||
extract_err:
|
||||
/* Make sure all the patch nodes freed */
|
||||
list_for_each_safe(pos, next, &patch_node_hdr.list) {
|
||||
tmp = list_entry(pos, struct patch_node, list);
|
||||
list_del_init(pos);
|
||||
kfree(tmp);
|
||||
}
|
||||
proj_id_err:
|
||||
sign_err:
|
||||
|
||||
alloc_fail:
|
||||
release_firmware(fw);
|
||||
|
||||
if (epatch_buf)
|
||||
vfree(epatch_buf);
|
||||
kfree(epatch_buf);
|
||||
|
||||
fw_fail:
|
||||
if (config_file_buf)
|
||||
kfree(config_file_buf);
|
||||
|
||||
fw_fail:
|
||||
if (fw_len == 0)
|
||||
vfree(buf);
|
||||
kfree(buf);
|
||||
|
||||
return fw_len;
|
||||
}
|
||||
@@ -2392,7 +2149,7 @@ int download_data(xchange_data * xdata)
|
||||
uint8_t *pcur;
|
||||
int pkt_len, frag_num, frag_len;
|
||||
int i, ret_val;
|
||||
int j = 0;
|
||||
int j;
|
||||
|
||||
RTKBT_DBG("download_data start");
|
||||
|
||||
@@ -2404,11 +2161,12 @@ int download_data(xchange_data * xdata)
|
||||
frag_len = PATCH_SEG_MAX;
|
||||
|
||||
for (i = 0; i < frag_num; i++) {
|
||||
cmd_para->index = j++;
|
||||
|
||||
if(cmd_para->index == 0x7f)
|
||||
j = 1;
|
||||
if (i > 0x7f)
|
||||
j = (i & 0x7f) + 1;
|
||||
else
|
||||
j = i;
|
||||
|
||||
cmd_para->index = j;
|
||||
if (i == (frag_num - 1)) {
|
||||
cmd_para->index |= DATA_END;
|
||||
frag_len = xdata->fw_len % PATCH_SEG_MAX;
|
||||
|
||||
@@ -1,23 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
*
|
||||
* Realtek Bluetooth USB download firmware driver
|
||||
*
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#ifndef __RTK_MISC_H__
|
||||
#define __RTK_MISC_H__
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
@@ -26,8 +14,6 @@
|
||||
#include <linux/usb.h>
|
||||
#include <linux/suspend.h>
|
||||
|
||||
#define CONFIG_BTUSB_AUTOSUSPEND 0
|
||||
|
||||
/* Download LPS patch when host suspends or power off
|
||||
* LPS patch name: lps_rtl8xxx_fw
|
||||
* LPS config name: lps_rtl8xxx_config
|
||||
@@ -59,9 +45,7 @@
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 33)
|
||||
#define USB_RPM 1
|
||||
#else
|
||||
#define USB_RPM 0
|
||||
#define USB_RPM
|
||||
#endif
|
||||
|
||||
#define CONFIG_NEEDS_BINDING
|
||||
@@ -72,7 +56,7 @@
|
||||
#endif
|
||||
|
||||
/* USB SS */
|
||||
#if (CONFIG_BTUSB_AUTOSUSPEND && USB_RPM)
|
||||
#if (defined CONFIG_BTUSB_AUTOSUSPEND) && (defined USB_RPM)
|
||||
#define BTUSB_RPM
|
||||
#endif
|
||||
|
||||
@@ -98,41 +82,12 @@ struct api_context {
|
||||
int status;
|
||||
};
|
||||
|
||||
int download_special_patch(struct usb_interface *intf, const char *special_name);
|
||||
int download_lps_patch(struct usb_interface *intf);
|
||||
#endif
|
||||
|
||||
int setup_btrealtek_flag(struct usb_interface *intf, struct hci_dev *hdev);
|
||||
|
||||
enum {
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
REALTEK_ALT6_CONTINUOUS_TX_CHIP,
|
||||
#endif
|
||||
|
||||
__REALTEK_NUM_FLAGS,
|
||||
};
|
||||
|
||||
struct btrealtek_data {
|
||||
DECLARE_BITMAP(flags, __REALTEK_NUM_FLAGS);
|
||||
};
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)
|
||||
static inline void *hci_get_priv(struct hci_dev *hdev)
|
||||
{
|
||||
return (char *)hdev + sizeof(*hdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define btrealtek_set_flag(hdev, nr) \
|
||||
do { \
|
||||
struct btrealtek_data *realtek = hci_get_priv((hdev)); \
|
||||
set_bit((nr), realtek->flags); \
|
||||
} while (0)
|
||||
|
||||
#define btrealtek_get_flag(hdev) \
|
||||
(((struct btrealtek_data *)hci_get_priv(hdev))->flags)
|
||||
|
||||
#define btrealtek_test_flag(hdev, nr) test_bit((nr), btrealtek_get_flag(hdev))
|
||||
|
||||
#if defined RTKBT_SUSPEND_WAKEUP || defined RTKBT_SHUTDOWN_WAKEUP || defined RTKBT_SWITCH_PATCH
|
||||
int set_scan(struct usb_interface *intf);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __RTK_MISC_H__ */
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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, 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,24 +347,15 @@ 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, 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;
|
||||
}
|
||||
|
||||
@@ -660,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;
|
||||
}
|
||||
@@ -693,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",
|
||||
@@ -724,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",
|
||||
@@ -755,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",
|
||||
@@ -786,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",
|
||||
@@ -817,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",
|
||||
@@ -848,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",
|
||||
@@ -879,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",
|
||||
@@ -910,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",
|
||||
@@ -941,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",
|
||||
@@ -974,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",
|
||||
@@ -1007,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",
|
||||
@@ -1040,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",
|
||||
@@ -1073,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",
|
||||
@@ -1128,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:
|
||||
@@ -1163,7 +1108,8 @@ sha_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void tegra_deinit_hash(struct tegra_se *se)
|
||||
|
||||
void tegra_deinit_hash(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
||||
@@ -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.
|
||||
/*
|
||||
* 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,21 +87,15 @@ 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->cmdbuf->addr, size;
|
||||
@@ -122,16 +105,11 @@ static int tegra_key_insert(struct tegra_se *se, const u8 *key,
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -142,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_err(se->dev, "failed to allocate key slot\n");
|
||||
if (!(*keyid))
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
ret = tegra_key_insert(se, key, keylen, *keyid, alg);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -152,7 +153,7 @@ int tegra_se_host1x_submit(struct tegra_se *se, u32 size)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
job->syncpt = host1x_syncpt_get(se->syncpt);
|
||||
job->syncpt = host1x_syncpt_get(se->syncpt);
|
||||
job->syncpt_incrs = 1;
|
||||
job->client = &se->client;
|
||||
job->class = se->client.class;
|
||||
@@ -167,17 +168,17 @@ int tegra_se_host1x_submit(struct tegra_se *se, u32 size)
|
||||
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, u32 size)
|
||||
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,22 +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;
|
||||
goto err_bo;
|
||||
}
|
||||
|
||||
ret = se->hw->init_alg(se);
|
||||
if (ret) {
|
||||
dev_err(se->dev, "failed to register algorithms\n");
|
||||
goto cmdbuf_put;
|
||||
goto err_alg_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
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;
|
||||
@@ -242,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);
|
||||
@@ -255,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;
|
||||
@@ -268,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;
|
||||
@@ -279,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)
|
||||
@@ -328,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;
|
||||
}
|
||||
@@ -374,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,
|
||||
},
|
||||
{ },
|
||||
@@ -436,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");
|
||||
|
||||
@@ -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,6 +355,8 @@
|
||||
#define SE_CRYPTO_CTR_REG_COUNT 4
|
||||
#define SE_MAX_KEYSLOT 15
|
||||
#define SE_MAX_MEM_ALLOC SZ_4M
|
||||
#define SE_AES_BUFLEN 0x8000
|
||||
#define SE_SHA_BUFLEN SZ_4M
|
||||
|
||||
#define SHA_FIRST BIT(0)
|
||||
#define SHA_UPDATE BIT(1)
|
||||
@@ -368,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 */
|
||||
@@ -401,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;
|
||||
};
|
||||
@@ -430,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;
|
||||
@@ -439,17 +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 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;
|
||||
};
|
||||
|
||||
@@ -459,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 {
|
||||
@@ -475,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)"))
|
||||
@@ -517,61 +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);
|
||||
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);
|
||||
|
||||
int tegra_se_host1x_register(struct tegra_se *se);
|
||||
int tegra_se_host1x_submit(struct tegra_se *se, u32 size);
|
||||
|
||||
/* HOST1x OPCODES */
|
||||
static inline void se_writel(struct tegra_se *se, unsigned int val,
|
||||
unsigned int offset)
|
||||
{
|
||||
writel_relaxed(val, se->base + offset);
|
||||
}
|
||||
|
||||
static inline u32 se_readl(struct tegra_se *se, unsigned int offset)
|
||||
{
|
||||
return readl_relaxed(se->base + offset);
|
||||
}
|
||||
|
||||
|
||||
/****
|
||||
*
|
||||
* 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)
|
||||
@@ -590,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*/
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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", ®_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;
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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");
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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, ®_val);
|
||||
*val = reg_val & 0xFF;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int imx390_write_reg(struct camera_common_data *s_data,
|
||||
u16 addr, u8 val)
|
||||
{
|
||||
int err;
|
||||
struct device *dev = s_data->dev;
|
||||
|
||||
err = regmap_write(s_data->regmap, addr, val);
|
||||
if (err)
|
||||
dev_err(dev, "%s:i2c write failed, 0x%x = %x\n",
|
||||
__func__, addr, val);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int imx390_write_table(struct imx390 *priv,
|
||||
const imx390_reg table[])
|
||||
{
|
||||
struct camera_common_data *s_data = priv->s_data;
|
||||
|
||||
return regmap_util_write_table_8(s_data->regmap,
|
||||
table,
|
||||
NULL, 0,
|
||||
IMX390_TABLE_WAIT_MS,
|
||||
IMX390_TABLE_END);
|
||||
}
|
||||
|
||||
static struct mutex serdes_lock__;
|
||||
|
||||
static int imx390_gmsl_serdes_setup(struct imx390 *priv)
|
||||
{
|
||||
int err = 0;
|
||||
int des_err = 0;
|
||||
struct device *dev;
|
||||
|
||||
if (!priv || !priv->ser_dev || !priv->dser_dev || !priv->i2c_client)
|
||||
return -EINVAL;
|
||||
|
||||
dev = &priv->i2c_client->dev;
|
||||
|
||||
mutex_lock(&serdes_lock__);
|
||||
|
||||
/* For now no separate power on required for serializer device */
|
||||
max9296_power_on(priv->dser_dev);
|
||||
|
||||
/* setup serdes addressing and control pipeline */
|
||||
err = max9296_setup_link(priv->dser_dev, &priv->i2c_client->dev);
|
||||
if (err) {
|
||||
dev_err(dev, "gmsl deserializer link config failed\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = max9295_setup_control(priv->ser_dev);
|
||||
|
||||
/* proceed even if ser setup failed, to setup deser correctly */
|
||||
if (err)
|
||||
dev_err(dev, "gmsl serializer setup failed\n");
|
||||
|
||||
des_err = max9296_setup_control(priv->dser_dev, &priv->i2c_client->dev);
|
||||
if (des_err) {
|
||||
dev_err(dev, "gmsl deserializer setup failed\n");
|
||||
/* overwrite err only if deser setup also failed */
|
||||
err = des_err;
|
||||
}
|
||||
|
||||
error:
|
||||
mutex_unlock(&serdes_lock__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void imx390_gmsl_serdes_reset(struct imx390 *priv)
|
||||
{
|
||||
mutex_lock(&serdes_lock__);
|
||||
|
||||
/* reset serdes addressing and control pipeline */
|
||||
max9295_reset_control(priv->ser_dev);
|
||||
max9296_reset_control(priv->dser_dev, &priv->i2c_client->dev);
|
||||
|
||||
max9296_power_off(priv->dser_dev);
|
||||
|
||||
mutex_unlock(&serdes_lock__);
|
||||
}
|
||||
|
||||
static int imx390_power_on(struct camera_common_data *s_data)
|
||||
{
|
||||
int err = 0;
|
||||
struct camera_common_power_rail *pw = s_data->power;
|
||||
struct camera_common_pdata *pdata = s_data->pdata;
|
||||
struct device *dev = s_data->dev;
|
||||
|
||||
dev_dbg(dev, "%s: power on\n", __func__);
|
||||
if (pdata && pdata->power_on) {
|
||||
err = pdata->power_on(pw);
|
||||
if (err)
|
||||
dev_err(dev, "%s failed.\n", __func__);
|
||||
else
|
||||
pw->state = SWITCH_ON;
|
||||
return err;
|
||||
}
|
||||
|
||||
pw->state = SWITCH_ON;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx390_power_off(struct camera_common_data *s_data)
|
||||
{
|
||||
int err = 0;
|
||||
struct camera_common_power_rail *pw = s_data->power;
|
||||
struct camera_common_pdata *pdata = s_data->pdata;
|
||||
struct device *dev = s_data->dev;
|
||||
|
||||
dev_dbg(dev, "%s:\n", __func__);
|
||||
|
||||
if (pdata && pdata->power_off) {
|
||||
err = pdata->power_off(pw);
|
||||
if (!err)
|
||||
goto power_off_done;
|
||||
else
|
||||
dev_err(dev, "%s failed.\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
power_off_done:
|
||||
pw->state = SWITCH_OFF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx390_power_get(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct device *dev = tc_dev->dev;
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
struct camera_common_power_rail *pw = s_data->power;
|
||||
struct camera_common_pdata *pdata = s_data->pdata;
|
||||
const char *mclk_name;
|
||||
const char *parentclk_name;
|
||||
struct clk *parent;
|
||||
int err = 0;
|
||||
|
||||
mclk_name = pdata->mclk_name ?
|
||||
pdata->mclk_name : "cam_mclk1";
|
||||
pw->mclk = devm_clk_get(dev, mclk_name);
|
||||
if (IS_ERR(pw->mclk)) {
|
||||
dev_err(dev, "unable to get clock %s\n", mclk_name);
|
||||
return PTR_ERR(pw->mclk);
|
||||
}
|
||||
|
||||
parentclk_name = pdata->parentclk_name;
|
||||
if (parentclk_name) {
|
||||
parent = devm_clk_get(dev, parentclk_name);
|
||||
if (IS_ERR(parent)) {
|
||||
dev_err(dev, "unable to get parent clcok %s",
|
||||
parentclk_name);
|
||||
} else {
|
||||
err = clk_set_parent(pw->mclk, parent);
|
||||
if (err < 0)
|
||||
dev_dbg(dev,
|
||||
"%s failed to set parent clock %d\n",
|
||||
__func__, err);
|
||||
}
|
||||
}
|
||||
|
||||
pw->state = SWITCH_OFF;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int imx390_power_put(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
struct camera_common_power_rail *pw = s_data->power;
|
||||
|
||||
if (unlikely(!pw))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx390_set_group_hold(struct tegracam_device *tc_dev, bool val)
|
||||
{
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
struct device *dev = tc_dev->dev;
|
||||
int err;
|
||||
|
||||
err = imx390_write_reg(s_data,
|
||||
IMX390_GROUP_HOLD_ADDR, val);
|
||||
if (err) {
|
||||
dev_dbg(dev,
|
||||
"%s: Group hold control error\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx390_set_gain(struct tegracam_device *tc_dev, s64 val)
|
||||
{
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
struct device *dev = tc_dev->dev;
|
||||
const struct sensor_mode_properties *mode =
|
||||
&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];
|
||||
imx390_reg reg_list[4];
|
||||
int err, i;
|
||||
u16 gain;
|
||||
|
||||
gain = (u16)(val / mode->control_properties.step_gain_val);
|
||||
|
||||
dev_dbg(dev, "%s: db: %d\n", __func__, gain);
|
||||
|
||||
if (gain > IMX390_MAX_GAIN_REG)
|
||||
gain = IMX390_MAX_GAIN_REG;
|
||||
|
||||
imx390_get_gain_reg(reg_list, gain);
|
||||
for (i = 0; i < 4; i++) {
|
||||
err = imx390_write_reg(s_data, reg_list[i].addr,
|
||||
reg_list[i].val);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
dev_info(dev, "%s: GAIN control error\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int imx390_set_frame_rate(struct tegracam_device *tc_dev, s64 val)
|
||||
{
|
||||
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
|
||||
|
||||
/* fixed 30fps */
|
||||
priv->frame_length = IMX390_DEFAULT_FRAME_LENGTH;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx390_set_exposure(struct tegracam_device *tc_dev, s64 val)
|
||||
{
|
||||
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
const struct sensor_mode_properties *mode =
|
||||
&s_data->sensor_props.sensor_modes[s_data->mode];
|
||||
imx390_reg reg_list[3];
|
||||
int err;
|
||||
u32 coarse_time;
|
||||
u32 shs1;
|
||||
int i = 0;
|
||||
|
||||
if (priv->frame_length == 0)
|
||||
priv->frame_length = IMX390_DEFAULT_FRAME_LENGTH;
|
||||
|
||||
/* coarse time in lines */
|
||||
coarse_time = (u32) (val * s_data->frmfmt[s_data->mode].framerates[0] *
|
||||
priv->frame_length / mode->control_properties.exposure_factor);
|
||||
|
||||
shs1 = priv->frame_length - coarse_time;
|
||||
/* 0 and 1 are prohibited */
|
||||
if (shs1 < 2)
|
||||
shs1 = 2;
|
||||
|
||||
imx390_get_coarse_time_regs_shs1(reg_list, shs1);
|
||||
for (i = 0; i < 3; i++) {
|
||||
err = imx390_write_reg(priv->s_data, reg_list[i].addr,
|
||||
reg_list[i].val);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
imx390_get_coarse_time_regs_shs2(reg_list, shs1);
|
||||
for (i = 0; i < 3; i++) {
|
||||
err = imx390_write_reg(priv->s_data, reg_list[i].addr,
|
||||
reg_list[i].val);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
dev_dbg(&priv->i2c_client->dev,
|
||||
"%s: set coarse time error\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct tegracam_ctrl_ops imx390_ctrl_ops = {
|
||||
.numctrls = ARRAY_SIZE(ctrl_cid_list),
|
||||
.ctrl_cid_list = ctrl_cid_list,
|
||||
.set_gain = imx390_set_gain,
|
||||
.set_exposure = imx390_set_exposure,
|
||||
.set_exposure_short = imx390_set_exposure,
|
||||
.set_frame_rate = imx390_set_frame_rate,
|
||||
.set_group_hold = imx390_set_group_hold,
|
||||
};
|
||||
|
||||
static struct camera_common_pdata
|
||||
*imx390_parse_dt(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct device *dev = tc_dev->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct camera_common_pdata *board_priv_pdata;
|
||||
const struct of_device_id *match;
|
||||
int err;
|
||||
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
match = of_match_device(imx390_of_match, dev);
|
||||
if (!match) {
|
||||
dev_err(dev, "Failed to find matching dt id\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
board_priv_pdata = devm_kzalloc(dev,
|
||||
sizeof(*board_priv_pdata), GFP_KERNEL);
|
||||
|
||||
err = of_property_read_string(node, "mclk",
|
||||
&board_priv_pdata->mclk_name);
|
||||
if (err)
|
||||
dev_err(dev, "mclk not in DT\n");
|
||||
|
||||
return board_priv_pdata;
|
||||
}
|
||||
|
||||
static int imx390_set_mode(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
struct device *dev = tc_dev->dev;
|
||||
const struct of_device_id *match;
|
||||
|
||||
match = of_match_device(imx390_of_match, dev);
|
||||
if (!match) {
|
||||
dev_err(dev, "Failed to find matching dt id\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (s_data->mode_prop_idx < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return imx390_write_table(priv, mode_table[s_data->mode_prop_idx]);
|
||||
}
|
||||
|
||||
static int imx390_start_streaming(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
|
||||
struct device *dev = tc_dev->dev;
|
||||
int err;
|
||||
|
||||
/* enable serdes streaming */
|
||||
err = max9295_setup_streaming(priv->ser_dev);
|
||||
if (err)
|
||||
goto exit;
|
||||
err = max9296_setup_streaming(priv->dser_dev, dev);
|
||||
if (err)
|
||||
goto exit;
|
||||
err = max9296_start_streaming(priv->dser_dev, dev);
|
||||
if (err)
|
||||
goto exit;
|
||||
|
||||
err = imx390_write_table(priv,
|
||||
mode_table[IMX390_MODE_START_STREAM]);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
msleep(20);
|
||||
|
||||
return 0;
|
||||
|
||||
exit:
|
||||
dev_err(dev, "%s: error setting stream\n", __func__);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int imx390_stop_streaming(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct device *dev = tc_dev->dev;
|
||||
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
|
||||
|
||||
/* disable serdes streaming */
|
||||
max9296_stop_streaming(priv->dser_dev, dev);
|
||||
|
||||
return imx390_write_table(priv, mode_table[IMX390_MODE_STOP_STREAM]);
|
||||
}
|
||||
|
||||
static struct camera_common_sensor_ops imx390_common_ops = {
|
||||
.numfrmfmts = ARRAY_SIZE(imx390_frmfmt),
|
||||
.frmfmt_table = imx390_frmfmt,
|
||||
.power_on = imx390_power_on,
|
||||
.power_off = imx390_power_off,
|
||||
.write_reg = imx390_write_reg,
|
||||
.read_reg = imx390_read_reg,
|
||||
.parse_dt = imx390_parse_dt,
|
||||
.power_get = imx390_power_get,
|
||||
.power_put = imx390_power_put,
|
||||
.set_mode = imx390_set_mode,
|
||||
.start_streaming = imx390_start_streaming,
|
||||
.stop_streaming = imx390_stop_streaming,
|
||||
};
|
||||
|
||||
static int imx390_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
dev_dbg(&client->dev, "%s:\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_internal_ops imx390_subdev_internal_ops = {
|
||||
.open = imx390_open,
|
||||
};
|
||||
|
||||
static int imx390_board_setup(struct imx390 *priv)
|
||||
{
|
||||
struct tegracam_device *tc_dev = priv->tc_dev;
|
||||
struct device *dev = tc_dev->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct device_node *ser_node;
|
||||
struct i2c_client *ser_i2c = NULL;
|
||||
struct device_node *dser_node;
|
||||
struct i2c_client *dser_i2c = NULL;
|
||||
struct device_node *gmsl;
|
||||
int value = 0xFFFF;
|
||||
const char *str_value;
|
||||
const char *str_value1[2];
|
||||
int i;
|
||||
int err;
|
||||
|
||||
err = of_property_read_u32(node, "reg", &priv->g_ctx.sdev_reg);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "reg not found\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = of_property_read_u32(node, "def-addr",
|
||||
&priv->g_ctx.sdev_def);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "def-addr not found\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ser_node = of_parse_phandle(node, "nvidia,gmsl-ser-device", 0);
|
||||
if (ser_node == NULL) {
|
||||
dev_err(dev,
|
||||
"missing %s handle\n",
|
||||
"nvidia,gmsl-ser-device");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = of_property_read_u32(ser_node, "reg", &priv->g_ctx.ser_reg);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "serializer reg not found\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ser_i2c = of_find_i2c_device_by_node(ser_node);
|
||||
of_node_put(ser_node);
|
||||
|
||||
if (ser_i2c == NULL) {
|
||||
err = -EPROBE_DEFER;
|
||||
goto error;
|
||||
}
|
||||
if (ser_i2c->dev.driver == NULL) {
|
||||
dev_err(dev, "missing serializer driver\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
priv->ser_dev = &ser_i2c->dev;
|
||||
|
||||
dser_node = of_parse_phandle(node, "nvidia,gmsl-dser-device", 0);
|
||||
if (dser_node == NULL) {
|
||||
dev_err(dev,
|
||||
"missing %s handle\n",
|
||||
"nvidia,gmsl-dser-device");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
dser_i2c = of_find_i2c_device_by_node(dser_node);
|
||||
of_node_put(dser_node);
|
||||
|
||||
if (dser_i2c == NULL) {
|
||||
err = -EPROBE_DEFER;
|
||||
goto error;
|
||||
}
|
||||
if (dser_i2c->dev.driver == NULL) {
|
||||
dev_err(dev, "missing deserializer driver\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
priv->dser_dev = &dser_i2c->dev;
|
||||
|
||||
/* populate g_ctx from DT */
|
||||
gmsl = of_get_child_by_name(node, "gmsl-link");
|
||||
if (gmsl == NULL) {
|
||||
dev_err(dev, "missing gmsl-link device node\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = of_property_read_string(gmsl, "dst-csi-port", &str_value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No dst-csi-port found\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.dst_csi_port =
|
||||
(!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : GMSL_CSI_PORT_B;
|
||||
|
||||
err = of_property_read_string(gmsl, "src-csi-port", &str_value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No src-csi-port found\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.src_csi_port =
|
||||
(!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : GMSL_CSI_PORT_B;
|
||||
|
||||
err = of_property_read_string(gmsl, "csi-mode", &str_value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No csi-mode found\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!strcmp(str_value, "1x4")) {
|
||||
priv->g_ctx.csi_mode = GMSL_CSI_1X4_MODE;
|
||||
} else if (!strcmp(str_value, "2x4")) {
|
||||
priv->g_ctx.csi_mode = GMSL_CSI_2X4_MODE;
|
||||
} else if (!strcmp(str_value, "4x2")) {
|
||||
priv->g_ctx.csi_mode = GMSL_CSI_4X2_MODE;
|
||||
} else if (!strcmp(str_value, "2x2")) {
|
||||
priv->g_ctx.csi_mode = GMSL_CSI_2X2_MODE;
|
||||
} else {
|
||||
dev_err(dev, "invalid csi mode\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = of_property_read_string(gmsl, "serdes-csi-link", &str_value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No serdes-csi-link found\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.serdes_csi_link =
|
||||
(!strcmp(str_value, "a")) ?
|
||||
GMSL_SERDES_CSI_LINK_A : GMSL_SERDES_CSI_LINK_B;
|
||||
|
||||
err = of_property_read_u32(gmsl, "st-vc", &value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No st-vc info\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.st_vc = value;
|
||||
|
||||
err = of_property_read_u32(gmsl, "vc-id", &value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No vc-id info\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.dst_vc = value;
|
||||
|
||||
err = of_property_read_u32(gmsl, "num-lanes", &value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No num-lanes info\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.num_csi_lanes = value;
|
||||
|
||||
priv->g_ctx.num_streams =
|
||||
of_property_count_strings(gmsl, "streams");
|
||||
if (priv->g_ctx.num_streams <= 0) {
|
||||
dev_err(dev, "No streams found\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < priv->g_ctx.num_streams; i++) {
|
||||
err = of_property_read_string_index(gmsl, "streams", i,
|
||||
&str_value1[i]);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Failed to get streams index\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!str_value1[i]) {
|
||||
dev_err(dev, "invalid stream info\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
if (!strcmp(str_value1[i], "raw12")) {
|
||||
priv->g_ctx.streams[i].st_data_type =
|
||||
GMSL_CSI_DT_RAW_12;
|
||||
} else if (!strcmp(str_value1[i], "embed")) {
|
||||
priv->g_ctx.streams[i].st_data_type =
|
||||
GMSL_CSI_DT_EMBED;
|
||||
} else if (!strcmp(str_value1[i], "ued-u1")) {
|
||||
priv->g_ctx.streams[i].st_data_type =
|
||||
GMSL_CSI_DT_UED_U1;
|
||||
} else {
|
||||
dev_err(dev, "invalid stream data type\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
priv->g_ctx.s_dev = dev;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int imx390_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int imx390_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
#endif
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct tegracam_device *tc_dev;
|
||||
struct imx390 *priv;
|
||||
int err;
|
||||
|
||||
dev_info(dev, "probing v4l2 sensor.\n");
|
||||
|
||||
if (!IS_ENABLED(CONFIG_OF) || !node)
|
||||
return -EINVAL;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(struct imx390), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
tc_dev = devm_kzalloc(dev,
|
||||
sizeof(struct tegracam_device), GFP_KERNEL);
|
||||
if (!tc_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->i2c_client = tc_dev->client = client;
|
||||
tc_dev->dev = dev;
|
||||
strscpy(tc_dev->name, "imx390", sizeof(tc_dev->name));
|
||||
tc_dev->dev_regmap_config = &sensor_regmap_config;
|
||||
tc_dev->sensor_ops = &imx390_common_ops;
|
||||
tc_dev->v4l2sd_internal_ops = &imx390_subdev_internal_ops;
|
||||
tc_dev->tcctrl_ops = &imx390_ctrl_ops;
|
||||
|
||||
err = tegracam_device_register(tc_dev);
|
||||
if (err) {
|
||||
dev_err(dev, "tegra camera driver registration failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
priv->tc_dev = tc_dev;
|
||||
priv->s_data = tc_dev->s_data;
|
||||
priv->subdev = &tc_dev->s_data->subdev;
|
||||
|
||||
tegracam_set_privdata(tc_dev, (void *)priv);
|
||||
|
||||
err = imx390_board_setup(priv);
|
||||
if (err) {
|
||||
tegracam_device_unregister(tc_dev);
|
||||
dev_err(dev, "board setup failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
mutex_init(&serdes_lock__);
|
||||
|
||||
/* Pair sensor to serializer dev */
|
||||
err = max9295_sdev_pair(priv->ser_dev, &priv->g_ctx);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "gmsl ser pairing failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Register sensor to deserializer dev */
|
||||
err = max9296_sdev_register(priv->dser_dev, &priv->g_ctx);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "gmsl deserializer register failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* gmsl serdes setup
|
||||
*
|
||||
* Sensor power on/off should be the right place for serdes
|
||||
* setup/reset. But the problem is, the total required delay
|
||||
* in serdes setup/reset exceeds the frame wait timeout, looks to
|
||||
* be related to multiple channel open and close sequence
|
||||
* issue (#BUG 200477330).
|
||||
* Once this bug is fixed, these may be moved to power on/off.
|
||||
* The delays in serdes is as per guidelines and can't be reduced,
|
||||
* so it is placed in probe/remove, though for that, deserializer
|
||||
* would be powered on always post boot, until 1.2v is supplied
|
||||
* to deserializer from CVB.
|
||||
*/
|
||||
err = imx390_gmsl_serdes_setup(priv);
|
||||
if (err) {
|
||||
dev_err(&client->dev,
|
||||
"%s gmsl serdes setup failed\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = tegracam_v4l2subdev_register(tc_dev, true);
|
||||
if (err) {
|
||||
dev_err(dev, "tegra camera subdev registration failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "Detected IMX390 sensor\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int imx390_remove(struct i2c_client *client)
|
||||
#else
|
||||
static void imx390_remove(struct i2c_client *client)
|
||||
#endif
|
||||
{
|
||||
struct camera_common_data *s_data = to_camera_common_data(&client->dev);
|
||||
struct imx390 *priv;
|
||||
|
||||
if (!s_data)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return -EINVAL;
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
|
||||
priv = (struct imx390 *)s_data->priv;
|
||||
|
||||
imx390_gmsl_serdes_reset(priv);
|
||||
|
||||
mutex_destroy(&serdes_lock__);
|
||||
tegracam_v4l2subdev_unregister(priv->tc_dev);
|
||||
tegracam_device_unregister(priv->tc_dev);
|
||||
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const struct i2c_device_id imx390_id[] = {
|
||||
{ "imx390", 0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, imx390_id);
|
||||
|
||||
static struct i2c_driver imx390_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "imx390",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(imx390_of_match),
|
||||
},
|
||||
.probe = imx390_probe,
|
||||
.remove = imx390_remove,
|
||||
.id_table = imx390_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(imx390_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Media Controller driver for Sony IMX390");
|
||||
MODULE_AUTHOR("NVIDIA Corporation");
|
||||
MODULE_AUTHOR("Sudhir Vyas <svyas@nvidia.com");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -775,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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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 */
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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");
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@
|
||||
# r8168 is the Linux device driver released for Realtek Gigabit Ethernet
|
||||
# controllers with PCI-Express interface.
|
||||
#
|
||||
# Copyright(c) 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
|
||||
@@ -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);
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user