mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-04-16 14:23:38 +00:00
kernel: refresh 5.15 patches and config
This commit is contained in:
parent
f5307dff2a
commit
e449c765d6
File diff suppressed because it is too large
Load Diff
@ -14,7 +14,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
--- a/include/linux/module.h
|
||||
+++ b/include/linux/module.h
|
||||
@@ -167,6 +167,7 @@ extern void cleanup_module(void);
|
||||
@@ -164,6 +164,7 @@ extern void cleanup_module(void);
|
||||
|
||||
/* Generic info of form tag = "info" */
|
||||
#define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
|
||||
@ -22,7 +22,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
/* For userspace: you can also call me... */
|
||||
#define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias)
|
||||
@@ -236,12 +237,12 @@ extern void cleanup_module(void);
|
||||
@@ -233,12 +234,12 @@ extern void cleanup_module(void);
|
||||
* Author(s), use "Name <email>" or just "Name", for multiple
|
||||
* authors use multiple MODULE_AUTHOR() statements/lines.
|
||||
*/
|
||||
@ -38,7 +38,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
/* Creates an alias so file2alias.c can find device table. */
|
||||
#define MODULE_DEVICE_TABLE(type, name) \
|
||||
extern typeof(name) __mod_##type##__##name##_device_table \
|
||||
@@ -268,7 +269,9 @@ extern typeof(name) __mod_##type##__##na
|
||||
@@ -265,7 +266,9 @@ extern typeof(name) __mod_##type##__##na
|
||||
*/
|
||||
|
||||
#if defined(MODULE) || !defined(CONFIG_SYSFS)
|
||||
@ -49,7 +49,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
#else
|
||||
#define MODULE_VERSION(_version) \
|
||||
MODULE_INFO(version, _version); \
|
||||
@@ -291,7 +294,7 @@ extern typeof(name) __mod_##type##__##na
|
||||
@@ -288,7 +291,7 @@ extern typeof(name) __mod_##type##__##na
|
||||
/* Optional firmware file (or files) needed by the module
|
||||
* format is simply firmware file name. Multiple firmware
|
||||
* files require multiple MODULE_FIRMWARE() specifiers */
|
||||
|
@ -103,23 +103,15 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
__stop_unwind_tab = .; \
|
||||
}
|
||||
|
||||
@@ -126,13 +126,13 @@
|
||||
@@ -126,7 +126,7 @@
|
||||
__vectors_lma = .; \
|
||||
OVERLAY 0xffff0000 : NOCROSSREFS AT(__vectors_lma) { \
|
||||
.vectors { \
|
||||
- *(.vectors) \
|
||||
+ KEEP(*(.vectors)) \
|
||||
+ KEEP(*(.vectors)) \
|
||||
} \
|
||||
.vectors.bhb.loop8 { \
|
||||
- *(.vectors.bhb.loop8) \
|
||||
+ KEEP(*(.vectors.bhb.loop8)) \
|
||||
} \
|
||||
.vectors.bhb.bpiall { \
|
||||
- *(.vectors.bhb.bpiall) \
|
||||
+ KEEP(*(.vectors.bhb.bpiall)) \
|
||||
} \
|
||||
} \
|
||||
ARM_LMA(__vectors, .vectors); \
|
||||
*(.vectors.bhb.loop8) \
|
||||
@@ -144,7 +144,7 @@
|
||||
\
|
||||
__stubs_lma = .; \
|
||||
|
22
target/linux/generic/hack-5.15/253-ksmbd-config.patch
Normal file
22
target/linux/generic/hack-5.15/253-ksmbd-config.patch
Normal file
@ -0,0 +1,22 @@
|
||||
--- a/init/Kconfig
|
||||
+++ b/init/Kconfig
|
||||
@@ -2379,7 +2379,7 @@ config PADATA
|
||||
bool
|
||||
|
||||
config ASN1
|
||||
- tristate
|
||||
+ tristate "ASN1"
|
||||
help
|
||||
Build a simple ASN.1 grammar compiler that produces a bytecode output
|
||||
that can be interpreted by the ASN.1 stream decoder and used to
|
||||
--- a/lib/Kconfig
|
||||
+++ b/lib/Kconfig
|
||||
@@ -609,7 +609,7 @@ config LIBFDT
|
||||
bool
|
||||
|
||||
config OID_REGISTRY
|
||||
- tristate
|
||||
+ tristate "OID"
|
||||
help
|
||||
Enable fast lookup object identifier registry.
|
||||
|
@ -125,7 +125,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/property.h>
|
||||
@@ -3340,3 +3341,5 @@ static int __init regmap_initcall(void)
|
||||
@@ -3341,3 +3342,5 @@ static int __init regmap_initcall(void)
|
||||
return 0;
|
||||
}
|
||||
postcore_initcall(regmap_initcall);
|
||||
|
@ -1,10 +1,11 @@
|
||||
--- a/block/blk.h
|
||||
+++ b/block/blk.h
|
||||
@@ -354,6 +354,7 @@ void blk_free_ext_minor(unsigned int min
|
||||
@@ -354,6 +354,8 @@ void blk_free_ext_minor(unsigned int min
|
||||
#define ADDPART_FLAG_NONE 0
|
||||
#define ADDPART_FLAG_RAID 1
|
||||
#define ADDPART_FLAG_WHOLEDISK 2
|
||||
+#define ADDPART_FLAG_ROOTDEV 4
|
||||
+#define ADDPART_FLAG_READONLY 4
|
||||
+#define ADDPART_FLAG_ROOTDEV 8
|
||||
int bdev_add_partition(struct gendisk *disk, int partno, sector_t start,
|
||||
sector_t length);
|
||||
int bdev_del_partition(struct gendisk *disk, int partno);
|
||||
@ -73,13 +74,25 @@
|
||||
#ifdef CONFIG_SGI_PARTITION
|
||||
sgi_partition,
|
||||
#endif
|
||||
@@ -598,6 +605,11 @@ static bool blk_add_partition(struct gen
|
||||
@@ -408,6 +415,11 @@ static struct block_device *add_partitio
|
||||
goto out_del;
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_FIT_PARTITION
|
||||
+ if (flags & ADDPART_FLAG_READONLY)
|
||||
+ bdev->bd_read_only = true;
|
||||
+#endif
|
||||
+
|
||||
/* everything is up and running, commence */
|
||||
err = xa_insert(&disk->part_tbl, partno, bdev, GFP_KERNEL);
|
||||
if (err)
|
||||
@@ -598,6 +610,11 @@ static bool blk_add_partition(struct gen
|
||||
(state->parts[p].flags & ADDPART_FLAG_RAID))
|
||||
md_autodetect_dev(part->bd_dev);
|
||||
|
||||
+#ifdef CONFIG_FIT_PARTITION
|
||||
+ if ((state->parts[p].flags & ADDPART_FLAG_ROOTDEV) && ROOT_DEV == 0)
|
||||
+ ROOT_DEV = part_to_dev(part)->devt;
|
||||
+ ROOT_DEV = part->bd_dev;
|
||||
+#endif
|
||||
+
|
||||
return true;
|
||||
@ -87,19 +100,7 @@
|
||||
|
||||
--- a/drivers/mtd/ubi/block.c
|
||||
+++ b/drivers/mtd/ubi/block.c
|
||||
@@ -419,7 +419,11 @@ int ubiblock_create(struct ubi_volume_in
|
||||
|
||||
gd->fops = &ubiblock_ops;
|
||||
gd->major = ubiblock_major;
|
||||
+#ifdef CONFIG_FIT_PARTITION
|
||||
+ gd->minors = 0;
|
||||
+#else
|
||||
gd->minors = 1;
|
||||
+#endif
|
||||
gd->first_minor = idr_alloc(&ubiblock_minor_idr, dev, 0, 0, GFP_KERNEL);
|
||||
if (gd->first_minor < 0) {
|
||||
dev_err(disk_to_dev(gd),
|
||||
@@ -428,6 +432,9 @@ int ubiblock_create(struct ubi_volume_in
|
||||
@@ -428,6 +428,9 @@ int ubiblock_create(struct ubi_volume_in
|
||||
goto out_cleanup_disk;
|
||||
}
|
||||
gd->private_data = dev;
|
||||
@ -109,6 +110,18 @@
|
||||
sprintf(gd->disk_name, "ubiblock%d_%d", dev->ubi_num, dev->vol_id);
|
||||
set_capacity(gd, disk_capacity);
|
||||
dev->gd = gd;
|
||||
--- a/drivers/mtd/mtd_blkdevs.c
|
||||
+++ b/drivers/mtd/mtd_blkdevs.c
|
||||
@@ -345,6 +345,9 @@ int add_mtd_blktrans_dev(struct mtd_blkt
|
||||
gd->first_minor = (new->devnum) << tr->part_bits;
|
||||
gd->minors = 1 << tr->part_bits;
|
||||
gd->fops = &mtd_block_ops;
|
||||
+#ifdef CONFIG_FIT_PARTITION
|
||||
+ gd->flags |= GENHD_FL_EXT_DEVT;
|
||||
+#endif
|
||||
|
||||
if (tr->part_bits)
|
||||
if (new->devnum < 26)
|
||||
--- a/block/partitions/efi.c
|
||||
+++ b/block/partitions/efi.c
|
||||
@@ -716,6 +716,9 @@ int efi_partition(struct parsed_partitio
|
||||
@ -145,43 +158,6 @@
|
||||
|
||||
typedef struct _gpt_header {
|
||||
__le64 signature;
|
||||
--- a/drivers/mtd/mtdblock.c
|
||||
+++ b/drivers/mtd/mtdblock.c
|
||||
@@ -338,7 +338,11 @@ static void mtdblock_remove_dev(struct m
|
||||
static struct mtd_blktrans_ops mtdblock_tr = {
|
||||
.name = "mtdblock",
|
||||
.major = MTD_BLOCK_MAJOR,
|
||||
+#ifdef CONFIG_FIT_PARTITION
|
||||
+ .part_bits = 1,
|
||||
+#else
|
||||
.part_bits = 0,
|
||||
+#endif
|
||||
.blksize = 512,
|
||||
.open = mtdblock_open,
|
||||
.flush = mtdblock_flush,
|
||||
--- a/drivers/mtd/mtd_blkdevs.c
|
||||
+++ b/drivers/mtd/mtd_blkdevs.c
|
||||
@@ -346,18 +346,8 @@ int add_mtd_blktrans_dev(struct mtd_blkt
|
||||
gd->minors = 1 << tr->part_bits;
|
||||
gd->fops = &mtd_block_ops;
|
||||
|
||||
- if (tr->part_bits)
|
||||
- if (new->devnum < 26)
|
||||
- snprintf(gd->disk_name, sizeof(gd->disk_name),
|
||||
- "%s%c", tr->name, 'a' + new->devnum);
|
||||
- else
|
||||
- snprintf(gd->disk_name, sizeof(gd->disk_name),
|
||||
- "%s%c%c", tr->name,
|
||||
- 'a' - 1 + new->devnum / 26,
|
||||
- 'a' + new->devnum % 26);
|
||||
- else
|
||||
- snprintf(gd->disk_name, sizeof(gd->disk_name),
|
||||
- "%s%d", tr->name, new->devnum);
|
||||
+ snprintf(gd->disk_name, sizeof(gd->disk_name),
|
||||
+ "%s%d", tr->name, new->devnum);
|
||||
|
||||
set_capacity(gd, ((u64)new->size * tr->blksize) >> 9);
|
||||
|
||||
--- a/block/partitions/msdos.c
|
||||
+++ b/block/partitions/msdos.c
|
||||
@@ -564,6 +564,15 @@ static void parse_minix(struct parsed_pa
|
||||
|
@ -20,7 +20,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
#include <linux/nvmem-provider.h>
|
||||
|
||||
#include <linux/mtd/mtd.h>
|
||||
@@ -697,6 +698,19 @@ int add_mtd_device(struct mtd_info *mtd)
|
||||
@@ -697,6 +698,16 @@ int add_mtd_device(struct mtd_info *mtd)
|
||||
of this try_ nonsense, and no bitching about it
|
||||
either. :) */
|
||||
__module_get(THIS_MODULE);
|
||||
@ -31,9 +31,6 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
+ unsigned int index = mtd->index;
|
||||
+ pr_notice("mtd: device %d (%s) set to be root filesystem\n",
|
||||
+ mtd->index, mtd->name);
|
||||
+#ifdef CONFIG_FIT_PARTITION
|
||||
+ index <<= 1;
|
||||
+#endif
|
||||
+ ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, index);
|
||||
+ }
|
||||
+
|
||||
|
@ -0,0 +1,120 @@
|
||||
From 6fa9e3678eb002246df1280322b6a024853950a5 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Mon, 11 Oct 2021 00:53:14 +0200
|
||||
Subject: [PATCH] drivers: mtd: parsers: add nvmem support to cmdlinepart
|
||||
|
||||
Assuming cmdlinepart is only one level deep partition scheme and that
|
||||
static partition are also defined in DTS, we can assign an of_node for
|
||||
partition declared from bootargs. cmdlinepart have priority than
|
||||
fiexed-partition parser so in this specific case the parser doesn't
|
||||
assign an of_node. Fix this by searching a defined of_node using a
|
||||
similar fixed_partition parser and if a partition is found with the same
|
||||
label, check that it has the same offset and size and return the DT
|
||||
of_node to correctly use NVMEM cells.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
---
|
||||
drivers/mtd/parsers/cmdlinepart.c | 71 +++++++++++++++++++++++++++++++
|
||||
1 file changed, 71 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/parsers/cmdlinepart.c
|
||||
+++ b/drivers/mtd/parsers/cmdlinepart.c
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
+#include <linux/of.h>
|
||||
|
||||
/* debug macro */
|
||||
#if 0
|
||||
@@ -323,6 +324,68 @@ static int mtdpart_setup_real(char *s)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int search_fixed_partition(struct mtd_info *master,
|
||||
+ struct mtd_partition *target_part,
|
||||
+ struct mtd_partition *fixed_part)
|
||||
+{
|
||||
+ struct device_node *mtd_node;
|
||||
+ struct device_node *ofpart_node;
|
||||
+ struct device_node *pp;
|
||||
+ struct mtd_partition part;
|
||||
+ const char *partname;
|
||||
+
|
||||
+ mtd_node = mtd_get_of_node(master);
|
||||
+ if (!mtd_node)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ ofpart_node = of_get_child_by_name(mtd_node, "partitions");
|
||||
+
|
||||
+ for_each_child_of_node(ofpart_node, pp) {
|
||||
+ const __be32 *reg;
|
||||
+ int len;
|
||||
+ int a_cells, s_cells;
|
||||
+
|
||||
+ reg = of_get_property(pp, "reg", &len);
|
||||
+ if (!reg) {
|
||||
+ pr_debug("%s: ofpart partition %pOF (%pOF) missing reg property.\n",
|
||||
+ master->name, pp,
|
||||
+ mtd_node);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ a_cells = of_n_addr_cells(pp);
|
||||
+ s_cells = of_n_size_cells(pp);
|
||||
+ if (len / 4 != a_cells + s_cells) {
|
||||
+ pr_debug("%s: ofpart partition %pOF (%pOF) error parsing reg property.\n",
|
||||
+ master->name, pp,
|
||||
+ mtd_node);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ part.offset = of_read_number(reg, a_cells);
|
||||
+ part.size = of_read_number(reg + a_cells, s_cells);
|
||||
+ part.of_node = pp;
|
||||
+
|
||||
+ partname = of_get_property(pp, "label", &len);
|
||||
+ if (!partname)
|
||||
+ partname = of_get_property(pp, "name", &len);
|
||||
+ part.name = partname;
|
||||
+
|
||||
+ if (!strncmp(target_part->name, part.name, len)) {
|
||||
+ if (part.offset != target_part->offset)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (part.size != target_part->size)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ memcpy(fixed_part, &part, sizeof(struct mtd_partition));
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Main function to be called from the MTD mapping driver/device to
|
||||
* obtain the partitioning information. At this point the command line
|
||||
@@ -338,6 +401,7 @@ static int parse_cmdline_partitions(stru
|
||||
int i, err;
|
||||
struct cmdline_mtd_partition *part;
|
||||
const char *mtd_id = master->name;
|
||||
+ struct mtd_partition fixed_part;
|
||||
|
||||
/* parse command line */
|
||||
if (!cmdline_parsed) {
|
||||
@@ -382,6 +446,13 @@ static int parse_cmdline_partitions(stru
|
||||
sizeof(*part->parts) * (part->num_parts - i));
|
||||
i--;
|
||||
}
|
||||
+
|
||||
+ err = search_fixed_partition(master, &part->parts[i], &fixed_part);
|
||||
+ if (!err) {
|
||||
+ part->parts[i].of_node = fixed_part.of_node;
|
||||
+ pr_info("Found partition defined in DT for %s. Assigning OF node to support nvmem.",
|
||||
+ part->parts[i].name);
|
||||
+ }
|
||||
}
|
||||
|
||||
*pparts = kmemdup(part->parts, sizeof(*part->parts) * part->num_parts,
|
23
target/linux/generic/hack-5.15/430-mtk-bmt-support.patch
Normal file
23
target/linux/generic/hack-5.15/430-mtk-bmt-support.patch
Normal file
@ -0,0 +1,23 @@
|
||||
--- a/drivers/mtd/nand/Kconfig
|
||||
+++ b/drivers/mtd/nand/Kconfig
|
||||
@@ -46,6 +46,10 @@ config MTD_NAND_ECC_SW_BCH
|
||||
ECC codes. They are used with NAND devices requiring more than 1 bit
|
||||
of error correction.
|
||||
|
||||
+config MTD_NAND_MTK_BMT
|
||||
+ bool "Support MediaTek NAND Bad-block Management Table"
|
||||
+ default n
|
||||
+
|
||||
endmenu
|
||||
|
||||
endmenu
|
||||
--- a/drivers/mtd/nand/Makefile
|
||||
+++ b/drivers/mtd/nand/Makefile
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
nandcore-objs := core.o bbt.o
|
||||
obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
|
||||
+obj-$(CONFIG_MTD_NAND_MTK_BMT) += mtk_bmt.o mtk_bmt_v2.o mtk_bmt_bbt.o mtk_bmt_nmbm.o
|
||||
|
||||
obj-y += onenand/
|
||||
obj-y += raw/
|
821
target/linux/generic/hack-5.15/600-bridge_offload.patch
Normal file
821
target/linux/generic/hack-5.15/600-bridge_offload.patch
Normal file
@ -0,0 +1,821 @@
|
||||
--- a/include/linux/if_bridge.h
|
||||
+++ b/include/linux/if_bridge.h
|
||||
@@ -59,6 +59,7 @@ struct br_ip_list {
|
||||
#define BR_MRP_LOST_IN_CONT BIT(19)
|
||||
#define BR_TX_FWD_OFFLOAD BIT(20)
|
||||
#define BR_BPDU_FILTER BIT(21)
|
||||
+#define BR_OFFLOAD BIT(22)
|
||||
|
||||
#define BR_DEFAULT_AGEING_TIME (300 * HZ)
|
||||
|
||||
--- a/net/bridge/Makefile
|
||||
+++ b/net/bridge/Makefile
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
obj-$(CONFIG_BRIDGE) += bridge.o
|
||||
|
||||
-bridge-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o \
|
||||
+bridge-y := br.o br_device.o br_fdb.o br_forward.o br_if.o br_input.o br_offload.o \
|
||||
br_ioctl.o br_stp.o br_stp_bpdu.o \
|
||||
br_stp_if.o br_stp_timer.o br_netlink.o \
|
||||
br_netlink_tunnel.o br_arp_nd_proxy.o
|
||||
--- a/net/bridge/br.c
|
||||
+++ b/net/bridge/br.c
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <net/switchdev.h>
|
||||
|
||||
#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
/*
|
||||
* Handle changes in state of network devices enslaved to a bridge.
|
||||
@@ -381,6 +382,10 @@ static int __init br_init(void)
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
+ err = br_offload_init();
|
||||
+ if (err)
|
||||
+ goto err_out0;
|
||||
+
|
||||
err = register_pernet_subsys(&br_net_ops);
|
||||
if (err)
|
||||
goto err_out1;
|
||||
@@ -430,6 +435,8 @@ err_out3:
|
||||
err_out2:
|
||||
unregister_pernet_subsys(&br_net_ops);
|
||||
err_out1:
|
||||
+ br_offload_fini();
|
||||
+err_out0:
|
||||
br_fdb_fini();
|
||||
err_out:
|
||||
stp_proto_unregister(&br_stp_proto);
|
||||
@@ -452,6 +459,7 @@ static void __exit br_deinit(void)
|
||||
#if IS_ENABLED(CONFIG_ATM_LANE)
|
||||
br_fdb_test_addr_hook = NULL;
|
||||
#endif
|
||||
+ br_offload_fini();
|
||||
br_fdb_fini();
|
||||
}
|
||||
|
||||
--- a/net/bridge/br_device.c
|
||||
+++ b/net/bridge/br_device.c
|
||||
@@ -524,6 +524,8 @@ void br_dev_setup(struct net_device *dev
|
||||
br->bridge_hello_time = br->hello_time = 2 * HZ;
|
||||
br->bridge_forward_delay = br->forward_delay = 15 * HZ;
|
||||
br->bridge_ageing_time = br->ageing_time = BR_DEFAULT_AGEING_TIME;
|
||||
+ br->offload_cache_size = 128;
|
||||
+ br->offload_cache_reserved = 8;
|
||||
dev->max_mtu = ETH_MAX_MTU;
|
||||
|
||||
br_netfilter_rtable_init(br);
|
||||
--- a/net/bridge/br_fdb.c
|
||||
+++ b/net/bridge/br_fdb.c
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <net/switchdev.h>
|
||||
#include <trace/events/bridge.h>
|
||||
#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
static const struct rhashtable_params br_fdb_rht_params = {
|
||||
.head_offset = offsetof(struct net_bridge_fdb_entry, rhnode),
|
||||
@@ -518,6 +519,8 @@ static struct net_bridge_fdb_entry *fdb_
|
||||
fdb->key.vlan_id = vid;
|
||||
fdb->flags = flags;
|
||||
fdb->updated = fdb->used = jiffies;
|
||||
+ INIT_HLIST_HEAD(&fdb->offload_in);
|
||||
+ INIT_HLIST_HEAD(&fdb->offload_out);
|
||||
if (rhashtable_lookup_insert_fast(&br->fdb_hash_tbl,
|
||||
&fdb->rhnode,
|
||||
br_fdb_rht_params)) {
|
||||
@@ -794,6 +797,8 @@ static void fdb_notify(struct net_bridge
|
||||
struct sk_buff *skb;
|
||||
int err = -ENOBUFS;
|
||||
|
||||
+ br_offload_fdb_update(fdb);
|
||||
+
|
||||
if (swdev_notify)
|
||||
br_switchdev_fdb_notify(br, fdb, type);
|
||||
|
||||
--- a/net/bridge/br_forward.c
|
||||
+++ b/net/bridge/br_forward.c
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/netfilter_bridge.h>
|
||||
#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
/* Don't forward packets to originating port or forwarding disabled */
|
||||
static inline int should_deliver(const struct net_bridge_port *p,
|
||||
@@ -32,6 +33,8 @@ static inline int should_deliver(const s
|
||||
|
||||
int br_dev_queue_push_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
+ br_offload_output(skb);
|
||||
+
|
||||
skb_push(skb, ETH_HLEN);
|
||||
if (!is_skb_forwardable(skb->dev, skb))
|
||||
goto drop;
|
||||
--- a/net/bridge/br_if.c
|
||||
+++ b/net/bridge/br_if.c
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <net/net_namespace.h>
|
||||
|
||||
#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
/*
|
||||
* Determine initial path cost based on speed.
|
||||
@@ -428,7 +429,7 @@ static struct net_bridge_port *new_nbp(s
|
||||
p->path_cost = port_cost(dev);
|
||||
p->priority = 0x8000 >> BR_PORT_BITS;
|
||||
p->port_no = index;
|
||||
- p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD;
|
||||
+ p->flags = BR_LEARNING | BR_FLOOD | BR_MCAST_FLOOD | BR_BCAST_FLOOD | BR_OFFLOAD;
|
||||
br_init_port(p);
|
||||
br_set_state(p, BR_STATE_DISABLED);
|
||||
br_stp_port_timer_init(p);
|
||||
@@ -771,6 +772,9 @@ void br_port_flags_change(struct net_bri
|
||||
|
||||
if (mask & BR_NEIGH_SUPPRESS)
|
||||
br_recalculate_neigh_suppress_enabled(br);
|
||||
+
|
||||
+ if (mask & BR_OFFLOAD)
|
||||
+ br_offload_port_state(p);
|
||||
}
|
||||
|
||||
bool br_port_flag_is_set(const struct net_device *dev, unsigned long flag)
|
||||
--- a/net/bridge/br_input.c
|
||||
+++ b/net/bridge/br_input.c
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <linux/rculist.h>
|
||||
#include "br_private.h"
|
||||
#include "br_private_tunnel.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
static int
|
||||
br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
@@ -164,6 +165,7 @@ int br_handle_frame_finish(struct net *n
|
||||
dst->used = now;
|
||||
br_forward(dst->dst, skb, local_rcv, false);
|
||||
} else {
|
||||
+ br_offload_skb_disable(skb);
|
||||
if (!mcast_hit)
|
||||
br_flood(br, skb, pkt_type, local_rcv, false);
|
||||
else
|
||||
@@ -297,6 +299,9 @@ static rx_handler_result_t br_handle_fra
|
||||
memset(skb->cb, 0, sizeof(struct br_input_skb_cb));
|
||||
|
||||
p = br_port_get_rcu(skb->dev);
|
||||
+ if (br_offload_input(p, skb))
|
||||
+ return RX_HANDLER_CONSUMED;
|
||||
+
|
||||
if (p->flags & BR_VLAN_TUNNEL)
|
||||
br_handle_ingress_vlan_tunnel(skb, p, nbp_vlan_group_rcu(p));
|
||||
|
||||
--- /dev/null
|
||||
+++ b/net/bridge/br_offload.c
|
||||
@@ -0,0 +1,438 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-only
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/workqueue.h>
|
||||
+#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
+
|
||||
+static DEFINE_SPINLOCK(offload_lock);
|
||||
+
|
||||
+struct bridge_flow_key {
|
||||
+ u8 dest[ETH_ALEN];
|
||||
+ u8 src[ETH_ALEN];
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ u16 vlan_tag;
|
||||
+ bool vlan_present;
|
||||
+#endif
|
||||
+};
|
||||
+
|
||||
+struct bridge_flow {
|
||||
+ struct net_bridge_port *port;
|
||||
+ struct rhash_head node;
|
||||
+ struct bridge_flow_key key;
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ bool vlan_out_present;
|
||||
+ u16 vlan_out;
|
||||
+#endif
|
||||
+
|
||||
+ unsigned long used;
|
||||
+ struct net_bridge_fdb_entry *fdb_in, *fdb_out;
|
||||
+ struct hlist_node fdb_list_in, fdb_list_out;
|
||||
+
|
||||
+ struct rcu_head rcu;
|
||||
+};
|
||||
+
|
||||
+static const struct rhashtable_params flow_params = {
|
||||
+ .automatic_shrinking = true,
|
||||
+ .head_offset = offsetof(struct bridge_flow, node),
|
||||
+ .key_len = sizeof(struct bridge_flow_key),
|
||||
+ .key_offset = offsetof(struct bridge_flow, key),
|
||||
+};
|
||||
+
|
||||
+static struct kmem_cache *offload_cache __read_mostly;
|
||||
+
|
||||
+static void
|
||||
+flow_rcu_free(struct rcu_head *head)
|
||||
+{
|
||||
+ struct bridge_flow *flow;
|
||||
+
|
||||
+ flow = container_of(head, struct bridge_flow, rcu);
|
||||
+ kmem_cache_free(offload_cache, flow);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+__br_offload_flow_free(struct bridge_flow *flow)
|
||||
+{
|
||||
+ flow->used = 0;
|
||||
+ hlist_del(&flow->fdb_list_in);
|
||||
+ hlist_del(&flow->fdb_list_out);
|
||||
+
|
||||
+ call_rcu(&flow->rcu, flow_rcu_free);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+br_offload_flow_free(struct bridge_flow *flow)
|
||||
+{
|
||||
+ if (rhashtable_remove_fast(&flow->port->offload.rht, &flow->node,
|
||||
+ flow_params) != 0)
|
||||
+ return;
|
||||
+
|
||||
+ __br_offload_flow_free(flow);
|
||||
+}
|
||||
+
|
||||
+static bool
|
||||
+br_offload_flow_fdb_refresh_time(struct bridge_flow *flow,
|
||||
+ struct net_bridge_fdb_entry *fdb)
|
||||
+{
|
||||
+ if (!time_after(flow->used, fdb->updated))
|
||||
+ return false;
|
||||
+
|
||||
+ fdb->updated = flow->used;
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static void
|
||||
+br_offload_flow_refresh_time(struct bridge_flow *flow)
|
||||
+{
|
||||
+ br_offload_flow_fdb_refresh_time(flow, flow->fdb_in);
|
||||
+ br_offload_flow_fdb_refresh_time(flow, flow->fdb_out);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+br_offload_destroy_cb(void *ptr, void *arg)
|
||||
+{
|
||||
+ struct bridge_flow *flow = ptr;
|
||||
+
|
||||
+ __br_offload_flow_free(flow);
|
||||
+}
|
||||
+
|
||||
+static bool
|
||||
+br_offload_need_gc(struct net_bridge_port *p)
|
||||
+{
|
||||
+ return (atomic_read(&p->offload.rht.nelems) +
|
||||
+ p->br->offload_cache_reserved) >= p->br->offload_cache_size;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+br_offload_gc_work(struct work_struct *work)
|
||||
+{
|
||||
+ struct rhashtable_iter hti;
|
||||
+ struct net_bridge_port *p;
|
||||
+ struct bridge_flow *gc_flow = NULL;
|
||||
+ struct bridge_flow *flow;
|
||||
+ unsigned long gc_used;
|
||||
+
|
||||
+ p = container_of(work, struct net_bridge_port, offload.gc_work);
|
||||
+
|
||||
+ if (!br_offload_need_gc(p))
|
||||
+ return;
|
||||
+
|
||||
+ rhashtable_walk_enter(&p->offload.rht, &hti);
|
||||
+ rhashtable_walk_start(&hti);
|
||||
+ while ((flow = rhashtable_walk_next(&hti)) != NULL) {
|
||||
+ unsigned long used;
|
||||
+
|
||||
+ if (IS_ERR(flow))
|
||||
+ continue;
|
||||
+
|
||||
+ used = READ_ONCE(flow->used);
|
||||
+ if (!used)
|
||||
+ continue;
|
||||
+
|
||||
+ if (gc_flow && !time_before(used, gc_used))
|
||||
+ continue;
|
||||
+
|
||||
+ gc_flow = flow;
|
||||
+ gc_used = used;
|
||||
+ }
|
||||
+ rhashtable_walk_stop(&hti);
|
||||
+ rhashtable_walk_exit(&hti);
|
||||
+
|
||||
+ if (!gc_flow)
|
||||
+ return;
|
||||
+
|
||||
+ spin_lock_bh(&offload_lock);
|
||||
+ if (br_offload_need_gc(p) && gc_flow &&
|
||||
+ gc_flow->used == gc_used)
|
||||
+ br_offload_flow_free(gc_flow);
|
||||
+ if (p->offload.enabled && br_offload_need_gc(p))
|
||||
+ queue_work(system_long_wq, work);
|
||||
+ spin_unlock_bh(&offload_lock);
|
||||
+
|
||||
+}
|
||||
+
|
||||
+void br_offload_port_state(struct net_bridge_port *p)
|
||||
+{
|
||||
+ struct net_bridge_port_offload *o = &p->offload;
|
||||
+ bool enabled = true;
|
||||
+ bool flush = false;
|
||||
+
|
||||
+ if (p->state != BR_STATE_FORWARDING ||
|
||||
+ !(p->flags & BR_OFFLOAD))
|
||||
+ enabled = false;
|
||||
+
|
||||
+ spin_lock_bh(&offload_lock);
|
||||
+ if (o->enabled == enabled)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (enabled) {
|
||||
+ if (!o->gc_work.func)
|
||||
+ INIT_WORK(&o->gc_work, br_offload_gc_work);
|
||||
+ rhashtable_init(&o->rht, &flow_params);
|
||||
+ } else {
|
||||
+ flush = true;
|
||||
+ rhashtable_free_and_destroy(&o->rht, br_offload_destroy_cb, o);
|
||||
+ }
|
||||
+
|
||||
+ o->enabled = enabled;
|
||||
+
|
||||
+out:
|
||||
+ spin_unlock_bh(&offload_lock);
|
||||
+
|
||||
+ if (flush)
|
||||
+ flush_work(&o->gc_work);
|
||||
+}
|
||||
+
|
||||
+void br_offload_fdb_update(const struct net_bridge_fdb_entry *fdb)
|
||||
+{
|
||||
+ struct bridge_flow *f;
|
||||
+ struct hlist_node *tmp;
|
||||
+
|
||||
+ spin_lock_bh(&offload_lock);
|
||||
+
|
||||
+ hlist_for_each_entry_safe(f, tmp, &fdb->offload_in, fdb_list_in)
|
||||
+ br_offload_flow_free(f);
|
||||
+
|
||||
+ hlist_for_each_entry_safe(f, tmp, &fdb->offload_out, fdb_list_out)
|
||||
+ br_offload_flow_free(f);
|
||||
+
|
||||
+ spin_unlock_bh(&offload_lock);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+br_offload_prepare_key(struct net_bridge_port *p, struct bridge_flow_key *key,
|
||||
+ struct sk_buff *skb)
|
||||
+{
|
||||
+ memset(key, 0, sizeof(*key));
|
||||
+ memcpy(key, eth_hdr(skb), 2 * ETH_ALEN);
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ if (!br_opt_get(p->br, BROPT_VLAN_ENABLED))
|
||||
+ return;
|
||||
+
|
||||
+ if (!skb_vlan_tag_present(skb) || skb->vlan_proto != p->br->vlan_proto)
|
||||
+ return;
|
||||
+
|
||||
+ key->vlan_present = true;
|
||||
+ key->vlan_tag = skb_vlan_tag_get_id(skb);
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+void br_offload_output(struct sk_buff *skb)
|
||||
+{
|
||||
+ struct net_bridge_port_offload *o;
|
||||
+ struct br_input_skb_cb *cb = (struct br_input_skb_cb *)skb->cb;
|
||||
+ struct net_bridge_port *p, *inp;
|
||||
+ struct net_device *dev;
|
||||
+ struct net_bridge_fdb_entry *fdb_in, *fdb_out;
|
||||
+ struct net_bridge_vlan_group *vg;
|
||||
+ struct bridge_flow_key key;
|
||||
+ struct bridge_flow *flow;
|
||||
+ u16 vlan;
|
||||
+
|
||||
+ if (!cb->offload)
|
||||
+ return;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+
|
||||
+ p = br_port_get_rcu(skb->dev);
|
||||
+ if (!p)
|
||||
+ goto out;
|
||||
+
|
||||
+ o = &p->offload;
|
||||
+ if (!o->enabled)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (atomic_read(&p->offload.rht.nelems) >= p->br->offload_cache_size)
|
||||
+ goto out;
|
||||
+
|
||||
+ dev = dev_get_by_index_rcu(dev_net(p->br->dev), cb->input_ifindex);
|
||||
+ if (!dev)
|
||||
+ goto out;
|
||||
+
|
||||
+ inp = br_port_get_rcu(dev);
|
||||
+ if (!inp)
|
||||
+ goto out;
|
||||
+
|
||||
+ vg = nbp_vlan_group_rcu(inp);
|
||||
+ vlan = cb->input_vlan_present ? cb->input_vlan_tag : br_get_pvid(vg);
|
||||
+ fdb_in = br_fdb_find_rcu(p->br, eth_hdr(skb)->h_source, vlan);
|
||||
+ if (!fdb_in)
|
||||
+ goto out;
|
||||
+
|
||||
+ vg = nbp_vlan_group_rcu(p);
|
||||
+ vlan = skb_vlan_tag_present(skb) ? skb_vlan_tag_get_id(skb) : br_get_pvid(vg);
|
||||
+ fdb_out = br_fdb_find_rcu(p->br, eth_hdr(skb)->h_dest, vlan);
|
||||
+ if (!fdb_out)
|
||||
+ goto out;
|
||||
+
|
||||
+ br_offload_prepare_key(p, &key, skb);
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ key.vlan_present = cb->input_vlan_present;
|
||||
+ key.vlan_tag = cb->input_vlan_tag;
|
||||
+#endif
|
||||
+
|
||||
+ flow = kmem_cache_alloc(offload_cache, GFP_ATOMIC);
|
||||
+ flow->port = fdb_in->dst;
|
||||
+ memcpy(&flow->key, &key, sizeof(key));
|
||||
+
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ flow->vlan_out_present = skb_vlan_tag_present(skb);
|
||||
+ flow->vlan_out = skb_vlan_tag_get(skb);
|
||||
+#endif
|
||||
+
|
||||
+ flow->fdb_in = fdb_in;
|
||||
+ flow->fdb_out = fdb_out;
|
||||
+ flow->used = jiffies;
|
||||
+
|
||||
+ spin_lock_bh(&offload_lock);
|
||||
+ if (!o->enabled ||
|
||||
+ atomic_read(&p->offload.rht.nelems) >= p->br->offload_cache_size ||
|
||||
+ rhashtable_insert_fast(&flow->port->offload.rht, &flow->node, flow_params)) {
|
||||
+ kmem_cache_free(offload_cache, flow);
|
||||
+ goto out_unlock;
|
||||
+ }
|
||||
+
|
||||
+ hlist_add_head(&flow->fdb_list_in, &fdb_in->offload_in);
|
||||
+ hlist_add_head(&flow->fdb_list_out, &fdb_out->offload_out);
|
||||
+
|
||||
+ if (br_offload_need_gc(p))
|
||||
+ queue_work(system_long_wq, &p->offload.gc_work);
|
||||
+
|
||||
+out_unlock:
|
||||
+ spin_unlock_bh(&offload_lock);
|
||||
+
|
||||
+out:
|
||||
+ rcu_read_unlock();
|
||||
+}
|
||||
+
|
||||
+bool br_offload_input(struct net_bridge_port *p, struct sk_buff *skb)
|
||||
+{
|
||||
+ struct net_bridge_port_offload *o = &p->offload;
|
||||
+ struct br_input_skb_cb *cb = (struct br_input_skb_cb *)skb->cb;
|
||||
+ struct bridge_flow_key key;
|
||||
+ struct net_bridge_port *dst;
|
||||
+ struct bridge_flow *flow;
|
||||
+ unsigned long now = jiffies;
|
||||
+ bool ret = false;
|
||||
+
|
||||
+ if (skb->len < sizeof(key))
|
||||
+ return false;
|
||||
+
|
||||
+ if (!o->enabled)
|
||||
+ return false;
|
||||
+
|
||||
+ if (is_multicast_ether_addr(eth_hdr(skb)->h_dest))
|
||||
+ return false;
|
||||
+
|
||||
+ br_offload_prepare_key(p, &key, skb);
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ flow = rhashtable_lookup(&o->rht, &key, flow_params);
|
||||
+ if (!flow) {
|
||||
+ cb->offload = 1;
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ cb->input_vlan_present = key.vlan_present != 0;
|
||||
+ cb->input_vlan_tag = key.vlan_tag;
|
||||
+ cb->input_ifindex = p->dev->ifindex;
|
||||
+#endif
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (flow->fdb_in->dst != p)
|
||||
+ goto out;
|
||||
+
|
||||
+ dst = flow->fdb_out->dst;
|
||||
+ if (!dst)
|
||||
+ goto out;
|
||||
+
|
||||
+ ret = true;
|
||||
+#ifdef CONFIG_BRIDGE_VLAN_FILTERING
|
||||
+ if (!flow->vlan_out_present && key.vlan_present) {
|
||||
+ __vlan_hwaccel_clear_tag(skb);
|
||||
+ } else if (flow->vlan_out_present) {
|
||||
+ if (skb_vlan_tag_present(skb) &&
|
||||
+ skb->vlan_proto != p->br->vlan_proto) {
|
||||
+ /* Protocol-mismatch, empty out vlan_tci for new tag */
|
||||
+ skb_push(skb, ETH_HLEN);
|
||||
+ skb = vlan_insert_tag_set_proto(skb, skb->vlan_proto,
|
||||
+ skb_vlan_tag_get(skb));
|
||||
+ if (unlikely(!skb))
|
||||
+ goto out;
|
||||
+
|
||||
+ skb_pull(skb, ETH_HLEN);
|
||||
+ skb_reset_mac_len(skb);
|
||||
+ }
|
||||
+
|
||||
+ __vlan_hwaccel_put_tag(skb, p->br->vlan_proto,
|
||||
+ flow->vlan_out);
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
+ skb->dev = dst->dev;
|
||||
+ skb_push(skb, ETH_HLEN);
|
||||
+
|
||||
+ if (skb_warn_if_lro(skb) || !is_skb_forwardable(skb->dev, skb)) {
|
||||
+ kfree_skb(skb);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ if (now - flow->used >= HZ) {
|
||||
+ flow->used = now;
|
||||
+ br_offload_flow_refresh_time(flow);
|
||||
+ }
|
||||
+
|
||||
+ skb_forward_csum(skb);
|
||||
+ dev_queue_xmit(skb);
|
||||
+
|
||||
+out:
|
||||
+ rcu_read_unlock();
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+br_offload_check_gc(struct net_bridge *br)
|
||||
+{
|
||||
+ struct net_bridge_port *p;
|
||||
+
|
||||
+ spin_lock_bh(&br->lock);
|
||||
+ list_for_each_entry(p, &br->port_list, list)
|
||||
+ if (br_offload_need_gc(p))
|
||||
+ queue_work(system_long_wq, &p->offload.gc_work);
|
||||
+ spin_unlock_bh(&br->lock);
|
||||
+}
|
||||
+
|
||||
+
|
||||
+int br_offload_set_cache_size(struct net_bridge *br, unsigned long val,
|
||||
+ struct netlink_ext_ack *extack)
|
||||
+{
|
||||
+ br->offload_cache_size = val;
|
||||
+ br_offload_check_gc(br);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int br_offload_set_cache_reserved(struct net_bridge *br, unsigned long val,
|
||||
+ struct netlink_ext_ack *extack)
|
||||
+{
|
||||
+ br->offload_cache_reserved = val;
|
||||
+ br_offload_check_gc(br);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int __init br_offload_init(void)
|
||||
+{
|
||||
+ offload_cache = kmem_cache_create("bridge_offload_cache",
|
||||
+ sizeof(struct bridge_flow),
|
||||
+ 0, SLAB_HWCACHE_ALIGN, NULL);
|
||||
+ if (!offload_cache)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void br_offload_fini(void)
|
||||
+{
|
||||
+ kmem_cache_destroy(offload_cache);
|
||||
+}
|
||||
--- a/net/bridge/br_private.h
|
||||
+++ b/net/bridge/br_private.h
|
||||
@@ -268,7 +268,13 @@ struct net_bridge_fdb_entry {
|
||||
unsigned long updated ____cacheline_aligned_in_smp;
|
||||
unsigned long used;
|
||||
|
||||
- struct rcu_head rcu;
|
||||
+ union {
|
||||
+ struct {
|
||||
+ struct hlist_head offload_in;
|
||||
+ struct hlist_head offload_out;
|
||||
+ };
|
||||
+ struct rcu_head rcu;
|
||||
+ };
|
||||
};
|
||||
|
||||
#define MDB_PG_FLAGS_PERMANENT BIT(0)
|
||||
@@ -343,6 +349,12 @@ struct net_bridge_mdb_entry {
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
+struct net_bridge_port_offload {
|
||||
+ struct rhashtable rht;
|
||||
+ struct work_struct gc_work;
|
||||
+ bool enabled;
|
||||
+};
|
||||
+
|
||||
struct net_bridge_port {
|
||||
struct net_bridge *br;
|
||||
struct net_device *dev;
|
||||
@@ -403,6 +415,7 @@ struct net_bridge_port {
|
||||
u16 backup_redirected_cnt;
|
||||
|
||||
struct bridge_stp_xstats stp_xstats;
|
||||
+ struct net_bridge_port_offload offload;
|
||||
};
|
||||
|
||||
#define kobj_to_brport(obj) container_of(obj, struct net_bridge_port, kobj)
|
||||
@@ -519,6 +532,9 @@ struct net_bridge {
|
||||
struct kobject *ifobj;
|
||||
u32 auto_cnt;
|
||||
|
||||
+ u32 offload_cache_size;
|
||||
+ u32 offload_cache_reserved;
|
||||
+
|
||||
#ifdef CONFIG_NET_SWITCHDEV
|
||||
/* Counter used to make sure that hardware domains get unique
|
||||
* identifiers in case a bridge spans multiple switchdev instances.
|
||||
@@ -553,6 +569,10 @@ struct br_input_skb_cb {
|
||||
#ifdef CONFIG_NETFILTER_FAMILY_BRIDGE
|
||||
u8 br_netfilter_broute:1;
|
||||
#endif
|
||||
+ u8 offload:1;
|
||||
+ u8 input_vlan_present:1;
|
||||
+ u16 input_vlan_tag;
|
||||
+ int input_ifindex;
|
||||
|
||||
#ifdef CONFIG_NET_SWITCHDEV
|
||||
/* Set if TX data plane offloading is used towards at least one
|
||||
--- /dev/null
|
||||
+++ b/net/bridge/br_private_offload.h
|
||||
@@ -0,0 +1,23 @@
|
||||
+#ifndef __BR_OFFLOAD_H
|
||||
+#define __BR_OFFLOAD_H
|
||||
+
|
||||
+bool br_offload_input(struct net_bridge_port *p, struct sk_buff *skb);
|
||||
+void br_offload_output(struct sk_buff *skb);
|
||||
+void br_offload_port_state(struct net_bridge_port *p);
|
||||
+void br_offload_fdb_update(const struct net_bridge_fdb_entry *fdb);
|
||||
+int br_offload_init(void);
|
||||
+void br_offload_fini(void);
|
||||
+int br_offload_set_cache_size(struct net_bridge *br, unsigned long val,
|
||||
+ struct netlink_ext_ack *extack);
|
||||
+int br_offload_set_cache_reserved(struct net_bridge *br, unsigned long val,
|
||||
+ struct netlink_ext_ack *extack);
|
||||
+
|
||||
+static inline void br_offload_skb_disable(struct sk_buff *skb)
|
||||
+{
|
||||
+ struct br_input_skb_cb *cb = (struct br_input_skb_cb *)skb->cb;
|
||||
+
|
||||
+ if (cb->offload)
|
||||
+ cb->offload = 0;
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
--- a/net/bridge/br_stp.c
|
||||
+++ b/net/bridge/br_stp.c
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "br_private.h"
|
||||
#include "br_private_stp.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
/* since time values in bpdu are in jiffies and then scaled (1/256)
|
||||
* before sending, make sure that is at least one STP tick.
|
||||
@@ -52,6 +53,8 @@ void br_set_state(struct net_bridge_port
|
||||
(unsigned int) p->port_no, p->dev->name,
|
||||
br_port_state_names[p->state]);
|
||||
|
||||
+ br_offload_port_state(p);
|
||||
+
|
||||
if (p->br->stp_enabled == BR_KERNEL_STP) {
|
||||
switch (p->state) {
|
||||
case BR_STATE_BLOCKING:
|
||||
--- a/net/bridge/br_sysfs_br.c
|
||||
+++ b/net/bridge/br_sysfs_br.c
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <linux/sched/signal.h>
|
||||
|
||||
#include "br_private.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
/* IMPORTANT: new bridge options must be added with netlink support only
|
||||
* please do not add new sysfs entries
|
||||
@@ -930,6 +931,38 @@ static ssize_t vlan_stats_per_port_store
|
||||
static DEVICE_ATTR_RW(vlan_stats_per_port);
|
||||
#endif
|
||||
|
||||
+static ssize_t offload_cache_size_show(struct device *d,
|
||||
+ struct device_attribute *attr,
|
||||
+ char *buf)
|
||||
+{
|
||||
+ struct net_bridge *br = to_bridge(d);
|
||||
+ return sprintf(buf, "%u\n", br->offload_cache_size);
|
||||
+}
|
||||
+
|
||||
+static ssize_t offload_cache_size_store(struct device *d,
|
||||
+ struct device_attribute *attr,
|
||||
+ const char *buf, size_t len)
|
||||
+{
|
||||
+ return store_bridge_parm(d, buf, len, br_offload_set_cache_size);
|
||||
+}
|
||||
+static DEVICE_ATTR_RW(offload_cache_size);
|
||||
+
|
||||
+static ssize_t offload_cache_reserved_show(struct device *d,
|
||||
+ struct device_attribute *attr,
|
||||
+ char *buf)
|
||||
+{
|
||||
+ struct net_bridge *br = to_bridge(d);
|
||||
+ return sprintf(buf, "%u\n", br->offload_cache_reserved);
|
||||
+}
|
||||
+
|
||||
+static ssize_t offload_cache_reserved_store(struct device *d,
|
||||
+ struct device_attribute *attr,
|
||||
+ const char *buf, size_t len)
|
||||
+{
|
||||
+ return store_bridge_parm(d, buf, len, br_offload_set_cache_reserved);
|
||||
+}
|
||||
+static DEVICE_ATTR_RW(offload_cache_reserved);
|
||||
+
|
||||
static struct attribute *bridge_attrs[] = {
|
||||
&dev_attr_forward_delay.attr,
|
||||
&dev_attr_hello_time.attr,
|
||||
@@ -984,6 +1017,8 @@ static struct attribute *bridge_attrs[]
|
||||
&dev_attr_vlan_stats_enabled.attr,
|
||||
&dev_attr_vlan_stats_per_port.attr,
|
||||
#endif
|
||||
+ &dev_attr_offload_cache_size.attr,
|
||||
+ &dev_attr_offload_cache_reserved.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
--- a/net/bridge/br_sysfs_if.c
|
||||
+++ b/net/bridge/br_sysfs_if.c
|
||||
@@ -241,6 +241,7 @@ BRPORT_ATTR_FLAG(broadcast_flood, BR_BCA
|
||||
BRPORT_ATTR_FLAG(neigh_suppress, BR_NEIGH_SUPPRESS);
|
||||
BRPORT_ATTR_FLAG(isolated, BR_ISOLATED);
|
||||
BRPORT_ATTR_FLAG(bpdu_filter, BR_BPDU_FILTER);
|
||||
+BRPORT_ATTR_FLAG(offload, BR_OFFLOAD);
|
||||
|
||||
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||
static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
|
||||
@@ -295,6 +296,7 @@ static const struct brport_attribute *br
|
||||
&brport_attr_isolated,
|
||||
&brport_attr_bpdu_filter,
|
||||
&brport_attr_backup_port,
|
||||
+ &brport_attr_offload,
|
||||
NULL
|
||||
};
|
||||
|
||||
--- a/net/bridge/br_vlan_tunnel.c
|
||||
+++ b/net/bridge/br_vlan_tunnel.c
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "br_private.h"
|
||||
#include "br_private_tunnel.h"
|
||||
+#include "br_private_offload.h"
|
||||
|
||||
static inline int br_vlan_tunid_cmp(struct rhashtable_compare_arg *arg,
|
||||
const void *ptr)
|
||||
@@ -180,6 +181,7 @@ void br_handle_ingress_vlan_tunnel(struc
|
||||
skb_dst_drop(skb);
|
||||
|
||||
__vlan_hwaccel_put_tag(skb, p->br->vlan_proto, vlan->vid);
|
||||
+ br_offload_skb_disable(skb);
|
||||
}
|
||||
|
||||
int br_handle_egress_vlan_tunnel(struct sk_buff *skb,
|
||||
@@ -201,6 +203,7 @@ int br_handle_egress_vlan_tunnel(struct
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
+ br_offload_skb_disable(skb);
|
||||
tunnel_dst = rcu_dereference(vlan->tinfo.tunnel_dst);
|
||||
if (tunnel_dst && dst_hold_safe(&tunnel_dst->dst))
|
||||
skb_dst_set(skb, &tunnel_dst->dst);
|
@ -98,7 +98,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
|
||||
--- /dev/null
|
||||
+++ b/net/netfilter/xt_FLOWOFFLOAD.c
|
||||
@@ -0,0 +1,656 @@
|
||||
@@ -0,0 +1,657 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2018-2021 Felix Fietkau <nbd@nbd.name>
|
||||
+ *
|
||||
@ -575,16 +575,17 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
+ }
|
||||
+
|
||||
+ table = &flowtable[!!(info->flags & XT_FLOWOFFLOAD_HW)];
|
||||
+
|
||||
+ net = read_pnet(&table->ft.net);
|
||||
+ if (!net)
|
||||
+ write_pnet(&table->ft.net, xt_net(par));
|
||||
+
|
||||
+ if (flow_offload_add(&table->ft, flow) < 0)
|
||||
+ goto err_flow_add;
|
||||
+
|
||||
+ xt_flowoffload_check_device(table, devs[0]);
|
||||
+ xt_flowoffload_check_device(table, devs[1]);
|
||||
+
|
||||
+ net = read_pnet(&table->ft.net);
|
||||
+ if (!net)
|
||||
+ write_pnet(&table->ft.net, xt_net(par));
|
||||
+
|
||||
+ dst_release(route.tuple[dir].dst);
|
||||
+ dst_release(route.tuple[!dir].dst);
|
||||
+
|
||||
|
@ -0,0 +1,25 @@
|
||||
From 804fbb3f2ec9283f7b778e057a68bfff440a0be6 Mon Sep 17 00:00:00 2001
|
||||
From: Rui Salvaterra <rsalvaterra@gmail.com>
|
||||
Date: Wed, 30 Mar 2022 22:51:55 +0100
|
||||
Subject: [PATCH] kernel: ct: size the hashtable more adequately
|
||||
|
||||
To set the default size of the connection tracking hash table, a divider of
|
||||
16384 becomes inadequate for a router handling lots of connections. Divide by
|
||||
2048 instead, making the default size scale better with the available RAM.
|
||||
|
||||
Signed-off-by: Rui Salvaterra <rsalvaterra@gmail.com>
|
||||
---
|
||||
net/netfilter/nf_conntrack_core.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/net/netfilter/nf_conntrack_core.c
|
||||
+++ b/net/netfilter/nf_conntrack_core.c
|
||||
@@ -2676,7 +2676,7 @@ int nf_conntrack_init_start(void)
|
||||
|
||||
if (!nf_conntrack_htable_size) {
|
||||
nf_conntrack_htable_size
|
||||
- = (((nr_pages << PAGE_SHIFT) / 16384)
|
||||
+ = (((nr_pages << PAGE_SHIFT) / 2048)
|
||||
/ sizeof(struct hlist_head));
|
||||
if (BITS_PER_LONG >= 64 &&
|
||||
nr_pages > (4 * (1024 * 1024 * 1024 / PAGE_SIZE)))
|
@ -19,7 +19,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
--- a/include/linux/netdevice.h
|
||||
+++ b/include/linux/netdevice.h
|
||||
@@ -1648,6 +1648,10 @@ enum netdev_priv_flags {
|
||||
@@ -1655,6 +1655,10 @@ enum netdev_priv_flags {
|
||||
IFF_TX_SKB_NO_LINEAR = 1<<31,
|
||||
};
|
||||
|
||||
@ -30,7 +30,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
#define IFF_802_1Q_VLAN IFF_802_1Q_VLAN
|
||||
#define IFF_EBRIDGE IFF_EBRIDGE
|
||||
#define IFF_BONDING IFF_BONDING
|
||||
@@ -1680,6 +1684,7 @@ enum netdev_priv_flags {
|
||||
@@ -1687,6 +1691,7 @@ enum netdev_priv_flags {
|
||||
#define IFF_L3MDEV_RX_HANDLER IFF_L3MDEV_RX_HANDLER
|
||||
#define IFF_LIVE_RENAME_OK IFF_LIVE_RENAME_OK
|
||||
#define IFF_TX_SKB_NO_LINEAR IFF_TX_SKB_NO_LINEAR
|
||||
@ -38,7 +38,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
/* Specifies the type of the struct net_device::ml_priv pointer */
|
||||
enum netdev_ml_priv_type {
|
||||
@@ -1981,6 +1986,7 @@ struct net_device {
|
||||
@@ -1988,6 +1993,7 @@ struct net_device {
|
||||
/* Read-mostly cache-line for fast-path access */
|
||||
unsigned int flags;
|
||||
unsigned int priv_flags;
|
||||
@ -46,7 +46,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
const struct net_device_ops *netdev_ops;
|
||||
int ifindex;
|
||||
unsigned short gflags;
|
||||
@@ -2041,6 +2047,11 @@ struct net_device {
|
||||
@@ -2048,6 +2054,11 @@ struct net_device {
|
||||
const struct tlsdev_ops *tlsdev_ops;
|
||||
#endif
|
||||
|
||||
@ -58,7 +58,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
const struct header_ops *header_ops;
|
||||
|
||||
unsigned char operstate;
|
||||
@@ -2115,6 +2126,10 @@ struct net_device {
|
||||
@@ -2122,6 +2133,10 @@ struct net_device {
|
||||
struct mctp_dev __rcu *mctp_ptr;
|
||||
#endif
|
||||
|
||||
@ -116,7 +116,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
help
|
||||
--- a/net/core/dev.c
|
||||
+++ b/net/core/dev.c
|
||||
@@ -3578,6 +3578,11 @@ static int xmit_one(struct sk_buff *skb,
|
||||
@@ -3582,6 +3582,11 @@ static int xmit_one(struct sk_buff *skb,
|
||||
if (dev_nit_active(dev))
|
||||
dev_queue_xmit_nit(skb, dev);
|
||||
|
||||
|
@ -0,0 +1,154 @@
|
||||
From 5f62951fba63a9f9cfff564209426bdea5fcc371 Mon Sep 17 00:00:00 2001
|
||||
From: Alex Marginean <alexandru.marginean@nxp.com>
|
||||
Date: Tue, 27 Aug 2019 15:16:56 +0300
|
||||
Subject: [PATCH] drivers: net: phy: aquantia: enable AQR112 and AQR412
|
||||
|
||||
Adds support for AQR112 and AQR412 which is mostly based on existing code
|
||||
with the addition of code configuring the protocol on system side.
|
||||
This allows changing the system side protocol without having to deploy a
|
||||
different firmware on the PHY.
|
||||
|
||||
Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
|
||||
---
|
||||
drivers/net/phy/aquantia_main.c | 88 +++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 88 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/aquantia_main.c
|
||||
+++ b/drivers/net/phy/aquantia_main.c
|
||||
@@ -20,9 +20,11 @@
|
||||
#define PHY_ID_AQR105 0x03a1b4a2
|
||||
#define PHY_ID_AQR106 0x03a1b4d0
|
||||
#define PHY_ID_AQR107 0x03a1b4e0
|
||||
+#define PHY_ID_AQR112 0x03a1b662
|
||||
#define PHY_ID_AQR113C 0x31c31c12
|
||||
#define PHY_ID_AQCS109 0x03a1b5c2
|
||||
#define PHY_ID_AQR405 0x03a1b4b0
|
||||
+#define PHY_ID_AQR412 0x03a1b712
|
||||
#define PHY_ID_AQR813 0x31c31cb2
|
||||
|
||||
#define MDIO_PHYXS_VEND_IF_STATUS 0xe812
|
||||
@@ -124,6 +126,29 @@
|
||||
#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2 BIT(1)
|
||||
#define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 BIT(0)
|
||||
|
||||
+/* registers in MDIO_MMD_VEND1 region */
|
||||
+#define AQUANTIA_VND1_GLOBAL_SC 0x000
|
||||
+#define AQUANTIA_VND1_GLOBAL_SC_LP BIT(0xb)
|
||||
+
|
||||
+/* global start rate, the protocol associated with this speed is used by default
|
||||
+ * on SI.
|
||||
+ */
|
||||
+#define AQUANTIA_VND1_GSTART_RATE 0x31a
|
||||
+#define AQUANTIA_VND1_GSTART_RATE_OFF 0
|
||||
+#define AQUANTIA_VND1_GSTART_RATE_100M 1
|
||||
+#define AQUANTIA_VND1_GSTART_RATE_1G 2
|
||||
+#define AQUANTIA_VND1_GSTART_RATE_10G 3
|
||||
+#define AQUANTIA_VND1_GSTART_RATE_2_5G 4
|
||||
+#define AQUANTIA_VND1_GSTART_RATE_5G 5
|
||||
+
|
||||
+/* SYSCFG registers for 100M, 1G, 2.5G, 5G, 10G */
|
||||
+#define AQUANTIA_VND1_GSYSCFG_BASE 0x31b
|
||||
+#define AQUANTIA_VND1_GSYSCFG_100M 0
|
||||
+#define AQUANTIA_VND1_GSYSCFG_1G 1
|
||||
+#define AQUANTIA_VND1_GSYSCFG_2_5G 2
|
||||
+#define AQUANTIA_VND1_GSYSCFG_5G 3
|
||||
+#define AQUANTIA_VND1_GSYSCFG_10G 4
|
||||
+
|
||||
struct aqr107_hw_stat {
|
||||
const char *name;
|
||||
int reg;
|
||||
@@ -244,6 +269,51 @@ static int aqr_config_aneg(struct phy_de
|
||||
return genphy_c45_check_and_restart_aneg(phydev, changed);
|
||||
}
|
||||
|
||||
+static struct {
|
||||
+ u16 syscfg;
|
||||
+ int cnt;
|
||||
+ u16 start_rate;
|
||||
+} aquantia_syscfg[PHY_INTERFACE_MODE_MAX] = {
|
||||
+ [PHY_INTERFACE_MODE_SGMII] = {0x04b, AQUANTIA_VND1_GSYSCFG_1G,
|
||||
+ AQUANTIA_VND1_GSTART_RATE_1G},
|
||||
+ [PHY_INTERFACE_MODE_2500BASEX] = {0x144, AQUANTIA_VND1_GSYSCFG_2_5G,
|
||||
+ AQUANTIA_VND1_GSTART_RATE_2_5G},
|
||||
+ [PHY_INTERFACE_MODE_XGMII] = {0x100, AQUANTIA_VND1_GSYSCFG_10G,
|
||||
+ AQUANTIA_VND1_GSTART_RATE_10G},
|
||||
+ [PHY_INTERFACE_MODE_USXGMII] = {0x080, AQUANTIA_VND1_GSYSCFG_10G,
|
||||
+ AQUANTIA_VND1_GSTART_RATE_10G},
|
||||
+};
|
||||
+
|
||||
+/* Sets up protocol on system side before calling aqr_config_aneg */
|
||||
+static int aqr_config_aneg_set_prot(struct phy_device *phydev)
|
||||
+{
|
||||
+ int if_type = phydev->interface;
|
||||
+ int i;
|
||||
+
|
||||
+ if (!aquantia_syscfg[if_type].cnt)
|
||||
+ return 0;
|
||||
+
|
||||
+ /* set PHY in low power mode so we can configure protocols */
|
||||
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC,
|
||||
+ AQUANTIA_VND1_GLOBAL_SC_LP);
|
||||
+ mdelay(10);
|
||||
+
|
||||
+ /* set the default rate to enable the SI link */
|
||||
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE,
|
||||
+ aquantia_syscfg[if_type].start_rate);
|
||||
+
|
||||
+ for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++)
|
||||
+ phy_write_mmd(phydev, MDIO_MMD_VEND1,
|
||||
+ AQUANTIA_VND1_GSYSCFG_BASE + i,
|
||||
+ aquantia_syscfg[if_type].syscfg);
|
||||
+
|
||||
+ /* wake PHY back up */
|
||||
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0);
|
||||
+ mdelay(10);
|
||||
+
|
||||
+ return aqr_config_aneg(phydev);
|
||||
+}
|
||||
+
|
||||
static int aqr_config_intr(struct phy_device *phydev)
|
||||
{
|
||||
bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED;
|
||||
@@ -767,6 +837,30 @@ static struct phy_driver aqr_driver[] =
|
||||
.get_stats = aqr107_get_stats,
|
||||
.link_change_notify = aqr107_link_change_notify,
|
||||
},
|
||||
+{
|
||||
+ PHY_ID_MATCH_MODEL(PHY_ID_AQR112),
|
||||
+ .name = "Aquantia AQR112",
|
||||
+ .probe = aqr107_probe,
|
||||
+ .config_aneg = aqr_config_aneg_set_prot,
|
||||
+ .config_intr = aqr_config_intr,
|
||||
+ .handle_interrupt = aqr_handle_interrupt,
|
||||
+ .read_status = aqr107_read_status,
|
||||
+ .get_sset_count = aqr107_get_sset_count,
|
||||
+ .get_strings = aqr107_get_strings,
|
||||
+ .get_stats = aqr107_get_stats,
|
||||
+},
|
||||
+{
|
||||
+ PHY_ID_MATCH_MODEL(PHY_ID_AQR412),
|
||||
+ .name = "Aquantia AQR412",
|
||||
+ .probe = aqr107_probe,
|
||||
+ .config_aneg = aqr_config_aneg_set_prot,
|
||||
+ .config_intr = aqr_config_intr,
|
||||
+ .handle_interrupt = aqr_handle_interrupt,
|
||||
+ .read_status = aqr107_read_status,
|
||||
+ .get_sset_count = aqr107_get_sset_count,
|
||||
+ .get_strings = aqr107_get_strings,
|
||||
+ .get_stats = aqr107_get_stats,
|
||||
+},
|
||||
};
|
||||
|
||||
module_phy_driver(aqr_driver);
|
||||
@@ -777,9 +871,11 @@ static struct mdio_device_id __maybe_unu
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR105) },
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR106) },
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR107) },
|
||||
+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR112) },
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) },
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) },
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR405) },
|
||||
+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR412) },
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR813) },
|
||||
{ }
|
||||
};
|
@ -0,0 +1,34 @@
|
||||
From 5f008cb22f60da4e10375f22266c1a4e20b1252e Mon Sep 17 00:00:00 2001
|
||||
From: Alex Marginean <alexandru.marginean@nxp.com>
|
||||
Date: Fri, 20 Sep 2019 18:22:52 +0300
|
||||
Subject: [PATCH] drivers: net: phy: aquantia: fix system side protocol
|
||||
misconfiguration
|
||||
|
||||
Do not set up protocols for speeds that are not supported by FW. Enabling
|
||||
these protocols leads to link issues on system side.
|
||||
|
||||
Signed-off-by: Alex Marginean <alexandru.marginean@nxp.com>
|
||||
---
|
||||
drivers/net/phy/aquantia_main.c | 8 +++++++-
|
||||
1 file changed, 7 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/phy/aquantia_main.c
|
||||
+++ b/drivers/net/phy/aquantia_main.c
|
||||
@@ -302,10 +302,16 @@ static int aqr_config_aneg_set_prot(stru
|
||||
phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE,
|
||||
aquantia_syscfg[if_type].start_rate);
|
||||
|
||||
- for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++)
|
||||
+ for (i = 0; i <= aquantia_syscfg[if_type].cnt; i++) {
|
||||
+ u16 reg = phy_read_mmd(phydev, MDIO_MMD_VEND1,
|
||||
+ AQUANTIA_VND1_GSYSCFG_BASE + i);
|
||||
+ if (!reg)
|
||||
+ continue;
|
||||
+
|
||||
phy_write_mmd(phydev, MDIO_MMD_VEND1,
|
||||
AQUANTIA_VND1_GSYSCFG_BASE + i,
|
||||
aquantia_syscfg[if_type].syscfg);
|
||||
+ }
|
||||
|
||||
/* wake PHY back up */
|
||||
phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GLOBAL_SC, 0);
|
@ -0,0 +1,43 @@
|
||||
From 2e677e4ae8f8330f68013163b060d0fda3a43095 Mon Sep 17 00:00:00 2001
|
||||
From: "Langer, Thomas" <tlanger@maxlinear.com>
|
||||
Date: Fri, 9 Jul 2021 17:36:46 +0200
|
||||
Subject: [PATCH] PONRTSYS-8842: aquantia: Add AQR113 driver support
|
||||
|
||||
Add a new entry for AQR113 PHY_ID
|
||||
---
|
||||
drivers/net/phy/aquantia_main.c | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/aquantia_main.c
|
||||
+++ b/drivers/net/phy/aquantia_main.c
|
||||
@@ -21,6 +21,7 @@
|
||||
#define PHY_ID_AQR106 0x03a1b4d0
|
||||
#define PHY_ID_AQR107 0x03a1b4e0
|
||||
#define PHY_ID_AQR112 0x03a1b662
|
||||
+#define PHY_ID_AQR113 0x31c31c40
|
||||
#define PHY_ID_AQR113C 0x31c31c12
|
||||
#define PHY_ID_AQCS109 0x03a1b5c2
|
||||
#define PHY_ID_AQR405 0x03a1b4b0
|
||||
@@ -856,6 +857,14 @@ static struct phy_driver aqr_driver[] =
|
||||
.get_stats = aqr107_get_stats,
|
||||
},
|
||||
{
|
||||
+ PHY_ID_MATCH_MODEL(PHY_ID_AQR113),
|
||||
+ .name = "Aquantia AQR113",
|
||||
+ .config_aneg = aqr_config_aneg,
|
||||
+ .config_intr = aqr_config_intr,
|
||||
+ .handle_interrupt = aqr_handle_interrupt,
|
||||
+ .read_status = aqr107_read_status,
|
||||
+},
|
||||
+{
|
||||
PHY_ID_MATCH_MODEL(PHY_ID_AQR412),
|
||||
.name = "Aquantia AQR412",
|
||||
.probe = aqr107_probe,
|
||||
@@ -878,6 +887,7 @@ static struct mdio_device_id __maybe_unu
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR106) },
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR107) },
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR112) },
|
||||
+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR113) },
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) },
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) },
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR405) },
|
@ -0,0 +1,63 @@
|
||||
From 3b92ee7b7899b6beffb2b484c58326e36612a873 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Thu, 23 Dec 2021 14:52:56 +0000
|
||||
Subject: [PATCH] net: phy: aquantia: add PHY_ID for AQR112R
|
||||
|
||||
As advised by Ian Chang this PHY is used in Puzzle devices.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/net/phy/aquantia_main.c | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/aquantia_main.c
|
||||
+++ b/drivers/net/phy/aquantia_main.c
|
||||
@@ -21,6 +21,8 @@
|
||||
#define PHY_ID_AQR106 0x03a1b4d0
|
||||
#define PHY_ID_AQR107 0x03a1b4e0
|
||||
#define PHY_ID_AQR112 0x03a1b662
|
||||
+#define PHY_ID_AQR112C 0x03a1b790
|
||||
+#define PHY_ID_AQR112R 0x31c31d12
|
||||
#define PHY_ID_AQR113 0x31c31c40
|
||||
#define PHY_ID_AQR113C 0x31c31c12
|
||||
#define PHY_ID_AQCS109 0x03a1b5c2
|
||||
@@ -857,6 +859,30 @@ static struct phy_driver aqr_driver[] =
|
||||
.get_stats = aqr107_get_stats,
|
||||
},
|
||||
{
|
||||
+ PHY_ID_MATCH_MODEL(PHY_ID_AQR112C),
|
||||
+ .name = "Aquantia AQR112C",
|
||||
+ .probe = aqr107_probe,
|
||||
+ .config_aneg = aqr_config_aneg_set_prot,
|
||||
+ .config_intr = aqr_config_intr,
|
||||
+ .handle_interrupt = aqr_handle_interrupt,
|
||||
+ .read_status = aqr107_read_status,
|
||||
+ .get_sset_count = aqr107_get_sset_count,
|
||||
+ .get_strings = aqr107_get_strings,
|
||||
+ .get_stats = aqr107_get_stats,
|
||||
+},
|
||||
+{
|
||||
+ PHY_ID_MATCH_MODEL(PHY_ID_AQR112R),
|
||||
+ .name = "Aquantia AQR112R",
|
||||
+ .probe = aqr107_probe,
|
||||
+ .config_aneg = aqr_config_aneg_set_prot,
|
||||
+ .config_intr = aqr_config_intr,
|
||||
+ .handle_interrupt = aqr_handle_interrupt,
|
||||
+ .read_status = aqr107_read_status,
|
||||
+ .get_sset_count = aqr107_get_sset_count,
|
||||
+ .get_strings = aqr107_get_strings,
|
||||
+ .get_stats = aqr107_get_stats,
|
||||
+},
|
||||
+{
|
||||
PHY_ID_MATCH_MODEL(PHY_ID_AQR113),
|
||||
.name = "Aquantia AQR113",
|
||||
.config_aneg = aqr_config_aneg,
|
||||
@@ -887,6 +913,8 @@ static struct mdio_device_id __maybe_unu
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR106) },
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR107) },
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR112) },
|
||||
+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR112C) },
|
||||
+ { PHY_ID_MATCH_MODEL(PHY_ID_AQR112R) },
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR113) },
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) },
|
||||
{ PHY_ID_MATCH_MODEL(PHY_ID_AQCS109) },
|
@ -0,0 +1,33 @@
|
||||
--- a/drivers/net/usb/qmi_wwan.c
|
||||
+++ b/drivers/net/usb/qmi_wwan.c
|
||||
@@ -1085,6 +1085,7 @@ static const struct usb_device_id produc
|
||||
{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0512)}, /* Quectel EG12/EM12 */
|
||||
{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0620)}, /* Quectel EM160R-GL */
|
||||
{QMI_MATCH_FF_FF_FF(0x2c7c, 0x0800)}, /* Quectel RM500Q-GL */
|
||||
+ {QMI_MATCH_FF_FF_FF(0x05c6, 0xf601)}, /* MeigLink SLM750 */
|
||||
|
||||
/* 3. Combined interface devices matching on interface number */
|
||||
{QMI_FIXED_INTF(0x0408, 0xea42, 4)}, /* Yota / Megafon M100-1 */
|
||||
--- a/drivers/usb/serial/option.c
|
||||
+++ b/drivers/usb/serial/option.c
|
||||
@@ -243,6 +243,8 @@ static void option_instat_callback(struc
|
||||
#define UBLOX_PRODUCT_R6XX 0x90fa
|
||||
/* These Yuga products use Qualcomm's vendor ID */
|
||||
#define YUGA_PRODUCT_CLM920_NC5 0x9625
|
||||
+/* These MeigLink products use Qualcomm's vendor ID */
|
||||
+#define MEIGLINK_PRODUCT_SLM750 0xf601
|
||||
|
||||
#define QUECTEL_VENDOR_ID 0x2c7c
|
||||
/* These Quectel products use Quectel's vendor ID */
|
||||
@@ -1127,6 +1129,11 @@ static const struct usb_device_id option
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EG95, 0xff, 0, 0) },
|
||||
{ USB_DEVICE(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_BG96),
|
||||
.driver_info = RSVD(4) },
|
||||
+ /* Meiglink products using Qualcomm vendor ID */
|
||||
+ // Works OK. In case of some issues check macros that are used by Quectel Products
|
||||
+ { USB_DEVICE_AND_INTERFACE_INFO(QUALCOMM_VENDOR_ID, MEIGLINK_PRODUCT_SLM750, 0xff, 0xff, 0xff),
|
||||
+ .driver_info = NUMEP2 },
|
||||
+ { USB_DEVICE_AND_INTERFACE_INFO(QUALCOMM_VENDOR_ID, MEIGLINK_PRODUCT_SLM750, 0xff, 0, 0) },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0xff, 0xff),
|
||||
.driver_info = RSVD(1) | RSVD(2) | RSVD(3) | RSVD(4) | NUMEP2 },
|
||||
{ USB_DEVICE_AND_INTERFACE_INFO(QUECTEL_VENDOR_ID, QUECTEL_PRODUCT_EP06, 0xff, 0, 0) },
|
12
target/linux/generic/hack-5.15/920-device_tree_cmdline.patch
Normal file
12
target/linux/generic/hack-5.15/920-device_tree_cmdline.patch
Normal file
@ -0,0 +1,12 @@
|
||||
--- a/drivers/of/fdt.c
|
||||
+++ b/drivers/of/fdt.c
|
||||
@@ -1158,6 +1158,9 @@ int __init early_init_dt_scan_chosen(uns
|
||||
p = of_get_flat_dt_prop(node, "bootargs", &l);
|
||||
if (p != NULL && l > 0)
|
||||
strlcpy(data, p, min(l, COMMAND_LINE_SIZE));
|
||||
+ p = of_get_flat_dt_prop(node, "bootargs-append", &l);
|
||||
+ if (p != NULL && l > 0)
|
||||
+ strlcat(data, p, min_t(int, strlen(data) + (int)l, COMMAND_LINE_SIZE));
|
||||
|
||||
/*
|
||||
* CONFIG_CMDLINE is meant to be a default in case nothing else
|
@ -0,0 +1,389 @@
|
||||
From patchwork Tue Jun 8 04:07:19 2021
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 7bit
|
||||
X-Patchwork-Submitter: John Thomson <git@johnthomson.fastmail.com.au>
|
||||
X-Patchwork-Id: 1489105
|
||||
X-Patchwork-Delegate: tudor.ambarus@gmail.com
|
||||
Return-Path:
|
||||
<linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org>
|
||||
X-Original-To: incoming@patchwork.ozlabs.org
|
||||
Delivered-To: patchwork-incoming@bilbo.ozlabs.org
|
||||
Authentication-Results: ozlabs.org;
|
||||
spf=none (no SPF record) smtp.mailfrom=lists.infradead.org
|
||||
(client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org;
|
||||
envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org;
|
||||
receiver=<UNKNOWN>)
|
||||
Authentication-Results: ozlabs.org;
|
||||
dkim=pass (2048-bit key;
|
||||
secure) header.d=lists.infradead.org header.i=@lists.infradead.org
|
||||
header.a=rsa-sha256 header.s=bombadil.20210309 header.b=EMabhVoR;
|
||||
dkim=fail reason="signature verification failed" (2048-bit key;
|
||||
unprotected) header.d=fastmail.com.au header.i=@fastmail.com.au
|
||||
header.a=rsa-sha256 header.s=fm3 header.b=dLzuZ6dB;
|
||||
dkim=fail reason="signature verification failed" (2048-bit key;
|
||||
unprotected) header.d=messagingengine.com header.i=@messagingengine.com
|
||||
header.a=rsa-sha256 header.s=fm3 header.b=nSRGsW+C;
|
||||
dkim-atps=neutral
|
||||
Received: from bombadil.infradead.org (bombadil.infradead.org
|
||||
[IPv6:2607:7c80:54:e::133])
|
||||
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
|
||||
key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest
|
||||
SHA256)
|
||||
(No client certificate requested)
|
||||
by ozlabs.org (Postfix) with ESMTPS id 4FzcFN1j1nz9sW8
|
||||
for <incoming@patchwork.ozlabs.org>; Tue, 8 Jun 2021 14:09:28 +1000 (AEST)
|
||||
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
|
||||
d=lists.infradead.org; s=bombadil.20210309; h=Sender:
|
||||
Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post:
|
||||
List-Archive:List-Unsubscribe:List-Id:MIME-Version:Message-Id:Date:Subject:Cc
|
||||
:To:From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From:
|
||||
Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:
|
||||
List-Owner; bh=6mUWQd71FwsINycGYY1qOhKz+ecWJVNtwDkTebG3XkA=; b=EMabhVoRE3ad89
|
||||
o3L2AgyKrs+blSofUC3hoSsQe7gi3m4si8S9HW8Z+8SsS5TufUsvGwDl80qSYGlQOytQF+1yRUWvE
|
||||
6FJ/+bqv+TwjqZFibgJ6+9OVsQN9dZ/no1R0bBXIpmrf8ORUmv58QK4ZQquaFKbyXKpFeWOC2MSv4
|
||||
H2MAhyhTU8a3gtooH6G8+KvsJEfVgh6C+aDbwxyh2UY3chHKuw1kvL6AktbfUE2xl4zxi3x3kc70B
|
||||
Wi3LiJBFokxVdgnROXxTU5tI0XboWYkQV64gLuQNV4XKClcuhVpzloDK8Iok6NTd7b32a7TdEFlCS
|
||||
lGKsEKmxtUlW2FpfoduA==;
|
||||
Received: from localhost ([::1] helo=bombadil.infradead.org)
|
||||
by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux))
|
||||
id 1lqT1r-006OAW-DX; Tue, 08 Jun 2021 04:07:51 +0000
|
||||
Received: from new1-smtp.messagingengine.com ([66.111.4.221])
|
||||
by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux))
|
||||
id 1lqT1l-006O9b-Fq
|
||||
for linux-mtd@lists.infradead.org; Tue, 08 Jun 2021 04:07:50 +0000
|
||||
Received: from compute2.internal (compute2.nyi.internal [10.202.2.42])
|
||||
by mailnew.nyi.internal (Postfix) with ESMTP id 4456B580622;
|
||||
Tue, 8 Jun 2021 00:07:42 -0400 (EDT)
|
||||
Received: from mailfrontend2 ([10.202.2.163])
|
||||
by compute2.internal (MEProxy); Tue, 08 Jun 2021 00:07:42 -0400
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fastmail.com.au;
|
||||
h=from:to:cc:subject:date:message-id:mime-version
|
||||
:content-transfer-encoding; s=fm3; bh=ZXRH+YluM1mHCS1EWUiCY/Sg8O
|
||||
LccfHe1oW5iAay6y8=; b=dLzuZ6dBYf7ZA8tWLOBFZYLi7ERsGe/4vnMXG+ovvb
|
||||
dNBO0+SaFGwoqYSFrfq/TeyHfKyvxrA7+LCdopIuT4abpLHxtRwtRiafQcDYCPat
|
||||
qJIqOZO+wCZC5S9Jc1OP7+t1FviGpgevqIMotci37P+RWc5u3AweMzFljZk90E8C
|
||||
uorV6rXagD+OssJQzllRnAIK88+rOAC9ZyXv2gWxy4d1HSCwSWgzx2vnV9CNp918
|
||||
YC/3tiHas9krbrPIaAsdBROr7Bvoe/ShRRzruKRuvZVgg5NN90vX+/5ZjI8u04GM
|
||||
p2bWCbC62CP6wlcgDaz+c/Sgr5ITd2GPENJsHfqmLRBA==
|
||||
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=
|
||||
messagingengine.com; h=cc:content-transfer-encoding:date:from
|
||||
:message-id:mime-version:subject:to:x-me-proxy:x-me-proxy
|
||||
:x-me-sender:x-me-sender:x-sasl-enc; s=fm3; bh=ZXRH+YluM1mHCS1EW
|
||||
UiCY/Sg8OLccfHe1oW5iAay6y8=; b=nSRGsW+CQ2Zx1RVpIUu8W/VD/k5P+32BW
|
||||
5k2ltd+UhI3dfldBPzHrYiOP/IJqGkNW+V+rHASacW/vFygnaZoxNjRYKnOsu+26
|
||||
wb2yK3jpl6lsNTg3N1Z4XJrYY2lf9H29DMFbhC67l0PTc050rcZk4XsKTLAlv14Q
|
||||
VA4WREYSaX/4IN4O+ES4TMq0a/3gKZh6nvbbJXbsXfK0WlSHTGZtZmW3fyrqvbXa
|
||||
t+R7L8vvqWvwls0pV+Sn8LeQqb7+A69w0UOnuznjkcA3sCc2YehcHbxcUEnMH+9N
|
||||
bxOjmIDeg9/4X/829tUWUJiLhE5SFmQZ1P6oFtmbWoLrDz0ZJIVBw==
|
||||
X-ME-Sender: <xms:C-2-YD2uka4HsA6gcdsV2Ia7vebY4Yjp9E8q7KBMb54jnAzGL7-67Q>
|
||||
<xme:C-2-YCEaxASy5VlcrvNO_jLFpMDGkFCRsuVNuZGEQsiRZygk8jPHWq7unPjeT6uYS
|
||||
2pUP6PrTQ2rggjEIg>
|
||||
X-ME-Received:
|
||||
<xmr:C-2-YD4exeK49N_YZWWf2BWDhVyCbCY3wwvjTyDOFxeugx7Jg08pzMUToo9oJjrBpcVTaA3kbfk>
|
||||
X-ME-Proxy-Cause:
|
||||
gggruggvucftvghtrhhoucdtuddrgeduledrfedtkedgjeduucetufdoteggodetrfdotf
|
||||
fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen
|
||||
uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne
|
||||
cujfgurhephffvufffkffoggfgsedtkeertdertddtnecuhfhrohhmpeflohhhnhcuvfhh
|
||||
ohhmshhonhcuoehgihhtsehjohhhnhhthhhomhhsohhnrdhfrghsthhmrghilhdrtghomh
|
||||
drrghuqeenucggtffrrghtthgvrhhnpefffeeihfdukedtuedufeetieeuudfhhefhkefh
|
||||
tefgtdeuffekffelleetveduieenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmh
|
||||
epmhgrihhlfhhrohhmpehgihhtsehjohhhnhhthhhomhhsohhnrdhfrghsthhmrghilhdr
|
||||
tghomhdrrghu
|
||||
X-ME-Proxy: <xmx:C-2-YI0AJZGjcB3wIbI9BoC9X8VNl4i9A7cQnBkvwZ25czWJlkKCLw>
|
||||
<xmx:C-2-YGGufw99T-O81-FeiSyEruv6_Pr0IHFhspQdxjv5k1VFTZ0lzQ>
|
||||
<xmx:C-2-YJ8BW7DhSDSCEAPSJWrwh_hHP79qreTZtWh_kOUwSh1c0MMlAg>
|
||||
<xmx:Du2-YJBeX2Fg9oFZVXGwEJ1ZrZnXHiAqNON8tbpzquYgcm2o_LM48g>
|
||||
Received: by mail.messagingengine.com (Postfix) with ESMTPA; Tue,
|
||||
8 Jun 2021 00:07:35 -0400 (EDT)
|
||||
From: John Thomson <git@johnthomson.fastmail.com.au>
|
||||
To: Miquel Raynal <miquel.raynal@bootlin.com>,
|
||||
Richard Weinberger <richard@nod.at>, Vignesh Raghavendra <vigneshr@ti.com>,
|
||||
Tudor Ambarus <tudor.ambarus@microchip.com>,
|
||||
Michael Walle <michael@walle.cc>, Pratyush Yadav <p.yadav@ti.com>,
|
||||
linux-mtd@lists.infradead.org
|
||||
Cc: linux-kernel@vger.kernel.org,
|
||||
John Thomson <git@johnthomson.fastmail.com.au>,
|
||||
kernel test robot <lkp@intel.com>, Dan Carpenter <dan.carpenter@oracle.com>
|
||||
Subject: [PATCH] mtd: spi-nor: write support for minor aligned partitions
|
||||
Date: Tue, 8 Jun 2021 14:07:19 +1000
|
||||
Message-Id: <20210608040719.14431-1-git@johnthomson.fastmail.com.au>
|
||||
X-Mailer: git-send-email 2.31.1
|
||||
MIME-Version: 1.0
|
||||
X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3
|
||||
X-CRM114-CacheID: sfid-20210607_210745_712053_67A7D864
|
||||
X-CRM114-Status: GOOD ( 26.99 )
|
||||
X-Spam-Score: -0.8 (/)
|
||||
X-Spam-Report: Spam detection software,
|
||||
running on the system "bombadil.infradead.org",
|
||||
has NOT identified this incoming email as spam. The original
|
||||
message has been attached to this so you can view it or label
|
||||
similar future email. If you have any questions, see
|
||||
the administrator of that system for details.
|
||||
Content preview: Do not prevent writing to mtd partitions where a partition
|
||||
boundary sits on a minor erasesize boundary. This addresses a FIXME that
|
||||
has been present since the start of the linux git history: /* Doesn' [...]
|
||||
Content analysis details: (-0.8 points, 5.0 required)
|
||||
pts rule name description
|
||||
---- ----------------------
|
||||
--------------------------------------------------
|
||||
-0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at https://www.dnswl.org/,
|
||||
low trust [66.111.4.221 listed in list.dnswl.org]
|
||||
-0.0 SPF_PASS SPF: sender matches SPF record
|
||||
-0.0 SPF_HELO_PASS SPF: HELO matches SPF record
|
||||
0.0 RCVD_IN_MSPIKE_H3 RBL: Good reputation (+3)
|
||||
[66.111.4.221 listed in wl.mailspike.net]
|
||||
-0.1 DKIM_VALID Message has at least one valid DKIM or DK signature
|
||||
0.1 DKIM_SIGNED Message has a DKIM or DK signature,
|
||||
not necessarily
|
||||
valid
|
||||
-0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from
|
||||
envelope-from domain
|
||||
0.0 RCVD_IN_MSPIKE_WL Mailspike good senders
|
||||
X-BeenThere: linux-mtd@lists.infradead.org
|
||||
X-Mailman-Version: 2.1.34
|
||||
Precedence: list
|
||||
List-Id: Linux MTD discussion mailing list <linux-mtd.lists.infradead.org>
|
||||
List-Unsubscribe: <http://lists.infradead.org/mailman/options/linux-mtd>,
|
||||
<mailto:linux-mtd-request@lists.infradead.org?subject=unsubscribe>
|
||||
List-Archive: <http://lists.infradead.org/pipermail/linux-mtd/>
|
||||
List-Post: <mailto:linux-mtd@lists.infradead.org>
|
||||
List-Help: <mailto:linux-mtd-request@lists.infradead.org?subject=help>
|
||||
List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-mtd>,
|
||||
<mailto:linux-mtd-request@lists.infradead.org?subject=subscribe>
|
||||
Sender: "linux-mtd" <linux-mtd-bounces@lists.infradead.org>
|
||||
Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org
|
||||
|
||||
Do not prevent writing to mtd partitions where a partition boundary sits
|
||||
on a minor erasesize boundary.
|
||||
This addresses a FIXME that has been present since the start of the
|
||||
linux git history:
|
||||
/* Doesn't start on a boundary of major erase size */
|
||||
/* FIXME: Let it be writable if it is on a boundary of
|
||||
* _minor_ erase size though */
|
||||
|
||||
Allow a uniform erase region spi-nor device to be configured
|
||||
to use the non-uniform erase regions code path for an erase with:
|
||||
CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE=y
|
||||
|
||||
On supporting hardware (SECT_4K: majority of current SPI-NOR device)
|
||||
provide the facility for an erase to use the least number
|
||||
of SPI-NOR operations, as well as access to 4K erase without
|
||||
requiring CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
|
||||
|
||||
Introduce erasesize_minor to the mtd struct,
|
||||
the smallest erasesize supported by the device
|
||||
|
||||
On existing devices, this is useful where write support is wanted
|
||||
for data on a 4K partition, such as some u-boot-env partitions,
|
||||
or RouterBoot soft_config, while still netting the performance
|
||||
benefits of using 64K sectors
|
||||
|
||||
Performance:
|
||||
time mtd erase firmware
|
||||
OpenWrt 5.10 ramips MT7621 w25q128jv 0xfc0000 partition length
|
||||
|
||||
Without this patch
|
||||
MTD_SPI_NOR_USE_4K_SECTORS=y |n
|
||||
real 2m 11.66s |0m 50.86s
|
||||
user 0m 0.00s |0m 0.00s
|
||||
sys 1m 56.20s |0m 50.80s
|
||||
|
||||
With this patch
|
||||
MTD_SPI_NOR_USE_VARIABLE_ERASE=n|y |4K_SECTORS=y
|
||||
real 0m 51.68s |0m 50.85s |2m 12.89s
|
||||
user 0m 0.00s |0m 0.00s |0m 0.01s
|
||||
sys 0m 46.94s |0m 50.38s |2m 12.46s
|
||||
|
||||
Signed-off-by: John Thomson <git@johnthomson.fastmail.com.au>
|
||||
---
|
||||
Have not tested on variable erase regions device.
|
||||
|
||||
checkpatch does not like the printk(KERN_WARNING
|
||||
these should be changed separately beforehand?
|
||||
|
||||
Changes RFC -> v1:
|
||||
Fix uninitialized variable smatch warning
|
||||
Reported-by: kernel test robot <lkp@intel.com>
|
||||
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
|
||||
---
|
||||
drivers/mtd/mtdpart.c | 52 ++++++++++++++++++++++++++++---------
|
||||
drivers/mtd/spi-nor/Kconfig | 10 +++++++
|
||||
drivers/mtd/spi-nor/core.c | 10 +++++--
|
||||
include/linux/mtd/mtd.h | 2 ++
|
||||
4 files changed, 60 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/mtdpart.c
|
||||
+++ b/drivers/mtd/mtdpart.c
|
||||
@@ -40,10 +40,11 @@ static struct mtd_info *allocate_partiti
|
||||
struct mtd_info *master = mtd_get_master(parent);
|
||||
int wr_alignment = (parent->flags & MTD_NO_ERASE) ?
|
||||
master->writesize : master->erasesize;
|
||||
+ int wr_alignment_minor = 0;
|
||||
u64 parent_size = mtd_is_partition(parent) ?
|
||||
parent->part.size : parent->size;
|
||||
struct mtd_info *child;
|
||||
- u32 remainder;
|
||||
+ u32 remainder, remainder_minor;
|
||||
char *name;
|
||||
u64 tmp;
|
||||
|
||||
@@ -145,6 +146,7 @@ static struct mtd_info *allocate_partiti
|
||||
int i, max = parent->numeraseregions;
|
||||
u64 end = child->part.offset + child->part.size;
|
||||
struct mtd_erase_region_info *regions = parent->eraseregions;
|
||||
+ uint32_t erasesize_minor = child->erasesize;
|
||||
|
||||
/* Find the first erase regions which is part of this
|
||||
* partition. */
|
||||
@@ -155,15 +157,24 @@ static struct mtd_info *allocate_partiti
|
||||
if (i > 0)
|
||||
i--;
|
||||
|
||||
- /* Pick biggest erasesize */
|
||||
for (; i < max && regions[i].offset < end; i++) {
|
||||
+ /* Pick biggest erasesize */
|
||||
if (child->erasesize < regions[i].erasesize)
|
||||
child->erasesize = regions[i].erasesize;
|
||||
+ /* Pick smallest non-zero erasesize */
|
||||
+ if ((erasesize_minor > regions[i].erasesize) && (regions[i].erasesize > 0))
|
||||
+ erasesize_minor = regions[i].erasesize;
|
||||
}
|
||||
+
|
||||
+ if (erasesize_minor < child->erasesize)
|
||||
+ child->erasesize_minor = erasesize_minor;
|
||||
+
|
||||
BUG_ON(child->erasesize == 0);
|
||||
} else {
|
||||
/* Single erase size */
|
||||
child->erasesize = master->erasesize;
|
||||
+ if (master->erasesize_minor)
|
||||
+ child->erasesize_minor = master->erasesize_minor;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -171,26 +182,43 @@ static struct mtd_info *allocate_partiti
|
||||
* exposes several regions with different erasesize. Adjust
|
||||
* wr_alignment accordingly.
|
||||
*/
|
||||
- if (!(child->flags & MTD_NO_ERASE))
|
||||
+ if (!(child->flags & MTD_NO_ERASE)) {
|
||||
wr_alignment = child->erasesize;
|
||||
+ if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE) && child->erasesize_minor)
|
||||
+ wr_alignment_minor = child->erasesize_minor;
|
||||
+ }
|
||||
|
||||
tmp = mtd_get_master_ofs(child, 0);
|
||||
remainder = do_div(tmp, wr_alignment);
|
||||
if ((child->flags & MTD_WRITEABLE) && remainder) {
|
||||
- /* Doesn't start on a boundary of major erase size */
|
||||
- /* FIXME: Let it be writable if it is on a boundary of
|
||||
- * _minor_ erase size though */
|
||||
- child->flags &= ~MTD_WRITEABLE;
|
||||
- printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n",
|
||||
- part->name);
|
||||
+ if (wr_alignment_minor) {
|
||||
+ tmp = mtd_get_master_ofs(child, 0);
|
||||
+ remainder_minor = do_div(tmp, wr_alignment_minor);
|
||||
+ if (remainder_minor == 0)
|
||||
+ child->erasesize = child->erasesize_minor;
|
||||
+ }
|
||||
+
|
||||
+ if ((!wr_alignment_minor) || (wr_alignment_minor && remainder_minor != 0)) {
|
||||
+ child->flags &= ~MTD_WRITEABLE;
|
||||
+ printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n",
|
||||
+ part->name);
|
||||
+ }
|
||||
}
|
||||
|
||||
tmp = mtd_get_master_ofs(child, 0) + child->part.size;
|
||||
remainder = do_div(tmp, wr_alignment);
|
||||
if ((child->flags & MTD_WRITEABLE) && remainder) {
|
||||
- child->flags &= ~MTD_WRITEABLE;
|
||||
- printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n",
|
||||
- part->name);
|
||||
+ if (wr_alignment_minor) {
|
||||
+ tmp = mtd_get_master_ofs(child, 0) + child->part.size;
|
||||
+ remainder_minor = do_div(tmp, wr_alignment_minor);
|
||||
+ if (remainder_minor == 0)
|
||||
+ child->erasesize = child->erasesize_minor;
|
||||
+ }
|
||||
+ if ((!wr_alignment_minor) || (wr_alignment_minor && remainder_minor != 0)) {
|
||||
+ child->flags &= ~MTD_WRITEABLE;
|
||||
+ printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n",
|
||||
+ part->name);
|
||||
+ }
|
||||
}
|
||||
|
||||
child->size = child->part.size;
|
||||
--- a/drivers/mtd/spi-nor/Kconfig
|
||||
+++ b/drivers/mtd/spi-nor/Kconfig
|
||||
@@ -10,6 +10,16 @@ menuconfig MTD_SPI_NOR
|
||||
|
||||
if MTD_SPI_NOR
|
||||
|
||||
+config MTD_SPI_NOR_USE_VARIABLE_ERASE
|
||||
+ bool "Disable uniform_erase to allow use of all hardware supported erasesizes"
|
||||
+ depends on !MTD_SPI_NOR_USE_4K_SECTORS
|
||||
+ default n
|
||||
+ help
|
||||
+ Allow mixed use of all hardware supported erasesizes,
|
||||
+ by forcing spi_nor to use the multiple eraseregions code path.
|
||||
+ For example: A 68K erase will use one 64K erase, and one 4K erase
|
||||
+ on supporting hardware.
|
||||
+
|
||||
config MTD_SPI_NOR_USE_4K_SECTORS
|
||||
bool "Use small 4096 B erase sectors"
|
||||
default y
|
||||
--- a/drivers/mtd/spi-nor/core.c
|
||||
+++ b/drivers/mtd/spi-nor/core.c
|
||||
@@ -1262,6 +1262,8 @@ static u8 spi_nor_convert_3to4_erase(u8
|
||||
|
||||
static bool spi_nor_has_uniform_erase(const struct spi_nor *nor)
|
||||
{
|
||||
+ if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE))
|
||||
+ return false;
|
||||
return !!nor->params->erase_map.uniform_erase_type;
|
||||
}
|
||||
|
||||
@@ -2379,6 +2381,7 @@ static int spi_nor_select_erase(struct s
|
||||
{
|
||||
struct spi_nor_erase_map *map = &nor->params->erase_map;
|
||||
const struct spi_nor_erase_type *erase = NULL;
|
||||
+ const struct spi_nor_erase_type *erase_minor = NULL;
|
||||
struct mtd_info *mtd = &nor->mtd;
|
||||
u32 wanted_size = nor->info->sector_size;
|
||||
int i;
|
||||
@@ -2411,8 +2414,9 @@ static int spi_nor_select_erase(struct s
|
||||
*/
|
||||
for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) {
|
||||
if (map->erase_type[i].size) {
|
||||
- erase = &map->erase_type[i];
|
||||
- break;
|
||||
+ if (!erase)
|
||||
+ erase = &map->erase_type[i];
|
||||
+ erase_minor = &map->erase_type[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2420,6 +2424,8 @@ static int spi_nor_select_erase(struct s
|
||||
return -EINVAL;
|
||||
|
||||
mtd->erasesize = erase->size;
|
||||
+ if (erase_minor && erase_minor->size < erase->size)
|
||||
+ mtd->erasesize_minor = erase_minor->size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
--- a/include/linux/mtd/mtd.h
|
||||
+++ b/include/linux/mtd/mtd.h
|
||||
@@ -243,6 +243,8 @@ struct mtd_info {
|
||||
* information below if they desire
|
||||
*/
|
||||
uint32_t erasesize;
|
||||
+ /* "Minor" (smallest) erase size supported by the whole device */
|
||||
+ uint32_t erasesize_minor;
|
||||
/* Minimal writable flash unit size. In case of NOR flash it is 1 (even
|
||||
* though individual bits can be cleared), in case of NAND flash it is
|
||||
* one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR
|
@ -19,7 +19,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
--- a/drivers/mtd/spi-nor/Kconfig
|
||||
+++ b/drivers/mtd/spi-nor/Kconfig
|
||||
@@ -68,6 +68,17 @@ config MTD_SPI_NOR_SWP_KEEP
|
||||
@@ -78,6 +78,17 @@ config MTD_SPI_NOR_SWP_KEEP
|
||||
|
||||
endchoice
|
||||
|
||||
@ -39,7 +39,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
endif # MTD_SPI_NOR
|
||||
--- a/drivers/mtd/spi-nor/core.c
|
||||
+++ b/drivers/mtd/spi-nor/core.c
|
||||
@@ -2625,6 +2625,21 @@ static void spi_nor_info_init_params(str
|
||||
@@ -2631,6 +2631,21 @@ static void spi_nor_info_init_params(str
|
||||
*/
|
||||
erase_mask = 0;
|
||||
i = 0;
|
||||
@ -61,7 +61,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
if (info->flags & SECT_4K_PMC) {
|
||||
erase_mask |= BIT(i);
|
||||
spi_nor_set_erase_type(&map->erase_type[i], 4096u,
|
||||
@@ -2636,6 +2651,7 @@ static void spi_nor_info_init_params(str
|
||||
@@ -2642,6 +2657,7 @@ static void spi_nor_info_init_params(str
|
||||
SPINOR_OP_BE_4K);
|
||||
i++;
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
+};
|
||||
--- a/drivers/mtd/spi-nor/core.c
|
||||
+++ b/drivers/mtd/spi-nor/core.c
|
||||
@@ -1846,6 +1846,7 @@ static const struct spi_nor_manufacturer
|
||||
@@ -1848,6 +1848,7 @@ static const struct spi_nor_manufacturer
|
||||
&spi_nor_winbond,
|
||||
&spi_nor_xilinx,
|
||||
&spi_nor_xmc,
|
||||
|
@ -0,0 +1,11 @@
|
||||
--- a/drivers/mtd/spi-nor/xmc.c
|
||||
+++ b/drivers/mtd/spi-nor/xmc.c
|
||||
@@ -14,6 +14,8 @@ static const struct flash_info xmc_parts
|
||||
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
{ "XM25QH128A", INFO(0x207018, 0, 64 * 1024, 256,
|
||||
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
+ { "XM25QH128C", INFO(0x204018, 0, 64 * 1024, 256,
|
||||
+ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
};
|
||||
|
||||
const struct spi_nor_manufacturer spi_nor_xmc = {
|
@ -8,12 +8,13 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
--- a/init/do_mounts.c
|
||||
+++ b/init/do_mounts.c
|
||||
@@ -447,7 +447,28 @@ retry:
|
||||
@@ -447,7 +447,30 @@ retry:
|
||||
out:
|
||||
put_page(page);
|
||||
}
|
||||
-
|
||||
+
|
||||
+#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
|
||||
+static int __init mount_ubi_rootfs(void)
|
||||
+{
|
||||
+ int flags = MS_SILENT;
|
||||
@ -34,11 +35,12 @@ Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
+
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
#ifdef CONFIG_ROOT_NFS
|
||||
|
||||
#define NFSROOT_TIMEOUT_MIN 5
|
||||
@@ -580,6 +601,10 @@ void __init mount_root(void)
|
||||
@@ -580,6 +603,10 @@ void __init mount_root(void)
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
@ -64,7 +64,7 @@ Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
mutex_lock(&mtd_table_mutex);
|
||||
--- a/include/linux/mtd/mtd.h
|
||||
+++ b/include/linux/mtd/mtd.h
|
||||
@@ -703,6 +703,8 @@ extern struct mtd_info *get_mtd_device(s
|
||||
@@ -705,6 +705,8 @@ extern struct mtd_info *get_mtd_device(s
|
||||
extern int __get_mtd_device(struct mtd_info *mtd);
|
||||
extern void __put_mtd_device(struct mtd_info *mtd);
|
||||
extern struct mtd_info *get_mtd_device_nm(const char *name);
|
||||
|
@ -0,0 +1,34 @@
|
||||
From 8bf2ce6ea4ee840b70f55a27f80e1cd308051b13 Mon Sep 17 00:00:00 2001
|
||||
From: Nick Hainke <vincent@systemli.org>
|
||||
Date: Mon, 27 Dec 2021 00:38:13 +0100
|
||||
Subject: [PATCH 1/2] mtd: spi-nor: locking support for MX25L6405D
|
||||
|
||||
Macronix MX25L6405D supports locking with four block-protection bits.
|
||||
Currently, the driver only sets three bits. If the bootloader does not
|
||||
sustain the flash chip in an unlocked state, the flash might be
|
||||
non-writeable. Add the corresponding flag to enable locking support with
|
||||
four bits in the status register.
|
||||
|
||||
Tested on Nanostation M2 XM.
|
||||
|
||||
Similar to commit 7ea40b54e83b ("mtd: spi-nor: enable locking support for
|
||||
MX25L12805D")
|
||||
|
||||
Signed-off-by: David Bauer <mail@david-bauer.net>
|
||||
Signed-off-by: Nick Hainke <vincent@systemli.org>
|
||||
---
|
||||
drivers/mtd/spi-nor/macronix.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/mtd/spi-nor/macronix.c
|
||||
+++ b/drivers/mtd/spi-nor/macronix.c
|
||||
@@ -41,7 +41,8 @@ static const struct flash_info macronix_
|
||||
{ "mx25l1606e", INFO(0xc22015, 0, 64 * 1024, 32, SECT_4K) },
|
||||
{ "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, SECT_4K) },
|
||||
{ "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) },
|
||||
- { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) },
|
||||
+ { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K |
|
||||
+ SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP) },
|
||||
{ "mx25u2033e", INFO(0xc22532, 0, 64 * 1024, 4, SECT_4K) },
|
||||
{ "mx25u3235f", INFO(0xc22536, 0, 64 * 1024, 64,
|
||||
SECT_4K | SPI_NOR_DUAL_READ |
|
@ -0,0 +1,30 @@
|
||||
From 245224608b5368c10407da07557e546743d3c489 Mon Sep 17 00:00:00 2001
|
||||
From: Nick Hainke <vincent@systemli.org>
|
||||
Date: Mon, 27 Dec 2021 09:33:13 +0100
|
||||
Subject: [PATCH 2/2] mtd: spi-nor: disable 16-bit-sr for macronix
|
||||
|
||||
Macronix flash chips seem to consist of only one status register.
|
||||
These chips will not work with the "16-bit Write Status (01h) Command".
|
||||
Disable SNOR_F_HAS_16BIT_SR for all Macronix chips.
|
||||
|
||||
Tested with MX25L6405D.
|
||||
|
||||
Fixes: 39d1e3340c73 ("mtd: spi-nor: Fix clearing of QE bit on
|
||||
lock()/unlock()")
|
||||
|
||||
Signed-off-by: David Bauer <mail@david-bauer.net>
|
||||
Signed-off-by: Nick Hainke <vincent@systemli.org>
|
||||
---
|
||||
drivers/mtd/spi-nor/macronix.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/mtd/spi-nor/macronix.c
|
||||
+++ b/drivers/mtd/spi-nor/macronix.c
|
||||
@@ -94,6 +94,7 @@ static void macronix_default_init(struct
|
||||
{
|
||||
nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable;
|
||||
nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode;
|
||||
+ nor->flags &= ~SNOR_F_HAS_16BIT_SR;
|
||||
nor->flags |= SNOR_F_HAS_LOCK;
|
||||
}
|
||||
|
@ -37,23 +37,21 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
__NF_SYSCTL_CT_LAST_SYSCTL,
|
||||
};
|
||||
|
||||
@@ -1026,6 +1027,15 @@ static struct ctl_table nf_ct_sysctl_tab
|
||||
@@ -1026,6 +1027,13 @@ static struct ctl_table nf_ct_sysctl_tab
|
||||
.proc_handler = nf_hooks_lwtunnel_sysctl_handler,
|
||||
},
|
||||
#endif
|
||||
+ [NF_SYSCTL_CT_PROTO_TCP_NO_WINDOW_CHECK] = {
|
||||
+ .procname = "nf_conntrack_tcp_no_window_check",
|
||||
+ .data = &init_net.ct.sysctl_no_window_check,
|
||||
+ .maxlen = sizeof(u8),
|
||||
+ .maxlen = sizeof(unsigned int),
|
||||
+ .mode = 0644,
|
||||
+ .proc_handler = proc_dou8vec_minmax,
|
||||
+ .extra1 = SYSCTL_ZERO,
|
||||
+ .extra2 = SYSCTL_ONE,
|
||||
+ .proc_handler = proc_dointvec,
|
||||
+ },
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -1153,6 +1163,7 @@ static int nf_conntrack_standalone_init_
|
||||
@@ -1153,6 +1161,7 @@ static int nf_conntrack_standalone_init_
|
||||
#ifdef CONFIG_NF_CONNTRACK_EVENTS
|
||||
table[NF_SYSCTL_CT_EVENTS].data = &net->ct.sysctl_events;
|
||||
#endif
|
||||
@ -61,7 +59,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
|
||||
table[NF_SYSCTL_CT_TIMESTAMP].data = &net->ct.sysctl_tstamp;
|
||||
#endif
|
||||
@@ -1222,6 +1233,7 @@ static int nf_conntrack_pernet_init(stru
|
||||
@@ -1222,6 +1231,7 @@ static int nf_conntrack_pernet_init(stru
|
||||
int ret;
|
||||
|
||||
net->ct.sysctl_checksum = 1;
|
||||
|
@ -0,0 +1,89 @@
|
||||
From 844c273286f328acf0dab5fbd5d864366b4904dc Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Tue, 30 Mar 2021 18:21:14 +0200
|
||||
Subject: [PATCH] of_net: add mac-address-increment support
|
||||
|
||||
Lots of embedded devices use the mac-address of other interface
|
||||
extracted from nvmem cells and increments it by one or two. Add two
|
||||
bindings to integrate this and directly use the right mac-address for
|
||||
the interface. Some example are some routers that use the gmac
|
||||
mac-address stored in the art partition and increments it by one for the
|
||||
wifi. mac-address-increment-byte bindings is used to tell what byte of
|
||||
the mac-address has to be increased (if not defined the last byte is
|
||||
increased) and mac-address-increment tells how much the byte decided
|
||||
early has to be increased.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
---
|
||||
net/core/of_net.c | 43 +++++++++++++++++++++++++++++++++++++++----
|
||||
1 file changed, 39 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/net/core/of_net.c
|
||||
+++ b/net/core/of_net.c
|
||||
@@ -119,27 +119,62 @@ static int of_get_mac_addr_nvmem(struct
|
||||
* this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
|
||||
* but is all zeros.
|
||||
*
|
||||
+ * DT can tell the system to increment the mac-address after is extracted by
|
||||
+ * using:
|
||||
+ * - mac-address-increment-byte to decide what byte to increase
|
||||
+ * (if not defined is increased the last byte)
|
||||
+ * - mac-address-increment to decide how much to increase. The value WILL
|
||||
+ * overflow to other bytes if the increment is over 255 or the total
|
||||
+ * increment will exceed 255 of the current byte.
|
||||
+ * (example 00:01:02:03:04:ff + 1 == 00:01:02:03:05:00)
|
||||
+ * (example 00:01:02:03:04:fe + 5 == 00:01:02:03:05:03)
|
||||
+ *
|
||||
* Return: 0 on success and errno in case of error.
|
||||
*/
|
||||
int of_get_mac_address(struct device_node *np, u8 *addr)
|
||||
{
|
||||
+ u32 inc_idx, mac_inc, mac_val;
|
||||
int ret;
|
||||
|
||||
+ /* Check first if the increment byte is present and valid.
|
||||
+ * If not set assume to increment the last byte if found.
|
||||
+ */
|
||||
+ if (of_property_read_u32(np, "mac-address-increment-byte", &inc_idx))
|
||||
+ inc_idx = 5;
|
||||
+ if (inc_idx < 3 || inc_idx > 5)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
ret = of_get_mac_addr(np, "mac-address", addr);
|
||||
if (!ret)
|
||||
- return 0;
|
||||
+ goto found;
|
||||
|
||||
ret = of_get_mac_addr(np, "local-mac-address", addr);
|
||||
if (!ret)
|
||||
- return 0;
|
||||
+ goto found;
|
||||
|
||||
ret = of_get_mac_addr(np, "address", addr);
|
||||
if (!ret)
|
||||
- return 0;
|
||||
+ goto found;
|
||||
+
|
||||
+ ret = of_get_mac_addr_nvmem(np, addr);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+found:
|
||||
+ if (!of_property_read_u32(np, "mac-address-increment", &mac_inc)) {
|
||||
+ /* Convert to a contiguous value */
|
||||
+ mac_val = (addr[3] << 16) + (addr[4] << 8) + addr[5];
|
||||
+ mac_val += mac_inc << 8 * (5-inc_idx);
|
||||
+
|
||||
+ /* Apply the incremented value handling overflow case */
|
||||
+ addr[3] = (mac_val >> 16) & 0xff;
|
||||
+ addr[4] = (mac_val >> 8) & 0xff;
|
||||
+ addr[5] = (mac_val >> 0) & 0xff;
|
||||
+ }
|
||||
|
||||
- return of_get_mac_addr_nvmem(np, addr);
|
||||
+ return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(of_get_mac_address);
|
@ -0,0 +1,38 @@
|
||||
--- a/net/core/of_net.c
|
||||
+++ b/net/core/of_net.c
|
||||
@@ -95,6 +95,27 @@ static int of_get_mac_addr_nvmem(struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int of_add_mac_address(struct device_node *np, u8* addr)
|
||||
+{
|
||||
+ struct property *prop;
|
||||
+
|
||||
+ prop = kzalloc(sizeof(*prop), GFP_KERNEL);
|
||||
+ if (!prop)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ prop->name = "mac-address";
|
||||
+ prop->length = ETH_ALEN;
|
||||
+ prop->value = kmemdup(addr, ETH_ALEN, GFP_KERNEL);
|
||||
+ if (!prop->value || of_update_property(np, prop))
|
||||
+ goto free;
|
||||
+
|
||||
+ return 0;
|
||||
+free:
|
||||
+ kfree(prop->value);
|
||||
+ kfree(prop);
|
||||
+ return -ENOMEM;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* of_get_mac_address()
|
||||
* @np: Caller's Device Node
|
||||
@@ -175,6 +196,7 @@ found:
|
||||
addr[5] = (mac_val >> 0) & 0xff;
|
||||
}
|
||||
|
||||
+ of_add_mac_address(np, addr);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(of_get_mac_address);
|
@ -0,0 +1,327 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 5 Feb 2022 17:59:07 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: add support for coherent
|
||||
DMA
|
||||
|
||||
It improves performance by eliminating the need for a cache flush on rx and tx
|
||||
In preparation for supporting WED (Wireless Ethernet Dispatch), also add a
|
||||
function for disabling coherent DMA at runtime.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_mdio.h>
|
||||
#include <linux/of_net.h>
|
||||
+#include <linux/of_address.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/clk.h>
|
||||
@@ -828,7 +829,7 @@ static int mtk_init_fq_dma(struct mtk_et
|
||||
dma_addr_t dma_addr;
|
||||
int i;
|
||||
|
||||
- eth->scratch_ring = dma_alloc_coherent(eth->dev,
|
||||
+ eth->scratch_ring = dma_alloc_coherent(eth->dma_dev,
|
||||
cnt * sizeof(struct mtk_tx_dma),
|
||||
ð->phy_scratch_ring,
|
||||
GFP_ATOMIC);
|
||||
@@ -840,10 +841,10 @@ static int mtk_init_fq_dma(struct mtk_et
|
||||
if (unlikely(!eth->scratch_head))
|
||||
return -ENOMEM;
|
||||
|
||||
- dma_addr = dma_map_single(eth->dev,
|
||||
+ dma_addr = dma_map_single(eth->dma_dev,
|
||||
eth->scratch_head, cnt * MTK_QDMA_PAGE_SIZE,
|
||||
DMA_FROM_DEVICE);
|
||||
- if (unlikely(dma_mapping_error(eth->dev, dma_addr)))
|
||||
+ if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr)))
|
||||
return -ENOMEM;
|
||||
|
||||
phy_ring_tail = eth->phy_scratch_ring +
|
||||
@@ -897,26 +898,26 @@ static void mtk_tx_unmap(struct mtk_eth
|
||||
{
|
||||
if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
|
||||
if (tx_buf->flags & MTK_TX_FLAGS_SINGLE0) {
|
||||
- dma_unmap_single(eth->dev,
|
||||
+ dma_unmap_single(eth->dma_dev,
|
||||
dma_unmap_addr(tx_buf, dma_addr0),
|
||||
dma_unmap_len(tx_buf, dma_len0),
|
||||
DMA_TO_DEVICE);
|
||||
} else if (tx_buf->flags & MTK_TX_FLAGS_PAGE0) {
|
||||
- dma_unmap_page(eth->dev,
|
||||
+ dma_unmap_page(eth->dma_dev,
|
||||
dma_unmap_addr(tx_buf, dma_addr0),
|
||||
dma_unmap_len(tx_buf, dma_len0),
|
||||
DMA_TO_DEVICE);
|
||||
}
|
||||
} else {
|
||||
if (dma_unmap_len(tx_buf, dma_len0)) {
|
||||
- dma_unmap_page(eth->dev,
|
||||
+ dma_unmap_page(eth->dma_dev,
|
||||
dma_unmap_addr(tx_buf, dma_addr0),
|
||||
dma_unmap_len(tx_buf, dma_len0),
|
||||
DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
if (dma_unmap_len(tx_buf, dma_len1)) {
|
||||
- dma_unmap_page(eth->dev,
|
||||
+ dma_unmap_page(eth->dma_dev,
|
||||
dma_unmap_addr(tx_buf, dma_addr1),
|
||||
dma_unmap_len(tx_buf, dma_len1),
|
||||
DMA_TO_DEVICE);
|
||||
@@ -994,9 +995,9 @@ static int mtk_tx_map(struct sk_buff *sk
|
||||
if (skb_vlan_tag_present(skb))
|
||||
txd4 |= TX_DMA_INS_VLAN | skb_vlan_tag_get(skb);
|
||||
|
||||
- mapped_addr = dma_map_single(eth->dev, skb->data,
|
||||
+ mapped_addr = dma_map_single(eth->dma_dev, skb->data,
|
||||
skb_headlen(skb), DMA_TO_DEVICE);
|
||||
- if (unlikely(dma_mapping_error(eth->dev, mapped_addr)))
|
||||
+ if (unlikely(dma_mapping_error(eth->dma_dev, mapped_addr)))
|
||||
return -ENOMEM;
|
||||
|
||||
WRITE_ONCE(itxd->txd1, mapped_addr);
|
||||
@@ -1035,10 +1036,10 @@ static int mtk_tx_map(struct sk_buff *sk
|
||||
|
||||
|
||||
frag_map_size = min(frag_size, MTK_TX_DMA_BUF_LEN);
|
||||
- mapped_addr = skb_frag_dma_map(eth->dev, frag, offset,
|
||||
+ mapped_addr = skb_frag_dma_map(eth->dma_dev, frag, offset,
|
||||
frag_map_size,
|
||||
DMA_TO_DEVICE);
|
||||
- if (unlikely(dma_mapping_error(eth->dev, mapped_addr)))
|
||||
+ if (unlikely(dma_mapping_error(eth->dma_dev, mapped_addr)))
|
||||
goto err_dma;
|
||||
|
||||
if (i == nr_frags - 1 &&
|
||||
@@ -1316,18 +1317,18 @@ static int mtk_poll_rx(struct napi_struc
|
||||
netdev->stats.rx_dropped++;
|
||||
goto release_desc;
|
||||
}
|
||||
- dma_addr = dma_map_single(eth->dev,
|
||||
+ dma_addr = dma_map_single(eth->dma_dev,
|
||||
new_data + NET_SKB_PAD +
|
||||
eth->ip_align,
|
||||
ring->buf_size,
|
||||
DMA_FROM_DEVICE);
|
||||
- if (unlikely(dma_mapping_error(eth->dev, dma_addr))) {
|
||||
+ if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) {
|
||||
skb_free_frag(new_data);
|
||||
netdev->stats.rx_dropped++;
|
||||
goto release_desc;
|
||||
}
|
||||
|
||||
- dma_unmap_single(eth->dev, trxd.rxd1,
|
||||
+ dma_unmap_single(eth->dma_dev, trxd.rxd1,
|
||||
ring->buf_size, DMA_FROM_DEVICE);
|
||||
|
||||
/* receive data */
|
||||
@@ -1600,7 +1601,7 @@ static int mtk_tx_alloc(struct mtk_eth *
|
||||
if (!ring->buf)
|
||||
goto no_tx_mem;
|
||||
|
||||
- ring->dma = dma_alloc_coherent(eth->dev, MTK_DMA_SIZE * sz,
|
||||
+ ring->dma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz,
|
||||
&ring->phys, GFP_ATOMIC);
|
||||
if (!ring->dma)
|
||||
goto no_tx_mem;
|
||||
@@ -1618,7 +1619,7 @@ static int mtk_tx_alloc(struct mtk_eth *
|
||||
* descriptors in ring->dma_pdma.
|
||||
*/
|
||||
if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
|
||||
- ring->dma_pdma = dma_alloc_coherent(eth->dev, MTK_DMA_SIZE * sz,
|
||||
+ ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz,
|
||||
&ring->phys_pdma,
|
||||
GFP_ATOMIC);
|
||||
if (!ring->dma_pdma)
|
||||
@@ -1677,7 +1678,7 @@ static void mtk_tx_clean(struct mtk_eth
|
||||
}
|
||||
|
||||
if (ring->dma) {
|
||||
- dma_free_coherent(eth->dev,
|
||||
+ dma_free_coherent(eth->dma_dev,
|
||||
MTK_DMA_SIZE * sizeof(*ring->dma),
|
||||
ring->dma,
|
||||
ring->phys);
|
||||
@@ -1685,7 +1686,7 @@ static void mtk_tx_clean(struct mtk_eth
|
||||
}
|
||||
|
||||
if (ring->dma_pdma) {
|
||||
- dma_free_coherent(eth->dev,
|
||||
+ dma_free_coherent(eth->dma_dev,
|
||||
MTK_DMA_SIZE * sizeof(*ring->dma_pdma),
|
||||
ring->dma_pdma,
|
||||
ring->phys_pdma);
|
||||
@@ -1730,18 +1731,18 @@ static int mtk_rx_alloc(struct mtk_eth *
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
- ring->dma = dma_alloc_coherent(eth->dev,
|
||||
+ ring->dma = dma_alloc_coherent(eth->dma_dev,
|
||||
rx_dma_size * sizeof(*ring->dma),
|
||||
&ring->phys, GFP_ATOMIC);
|
||||
if (!ring->dma)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < rx_dma_size; i++) {
|
||||
- dma_addr_t dma_addr = dma_map_single(eth->dev,
|
||||
+ dma_addr_t dma_addr = dma_map_single(eth->dma_dev,
|
||||
ring->data[i] + NET_SKB_PAD + eth->ip_align,
|
||||
ring->buf_size,
|
||||
DMA_FROM_DEVICE);
|
||||
- if (unlikely(dma_mapping_error(eth->dev, dma_addr)))
|
||||
+ if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr)))
|
||||
return -ENOMEM;
|
||||
ring->dma[i].rxd1 = (unsigned int)dma_addr;
|
||||
|
||||
@@ -1777,7 +1778,7 @@ static void mtk_rx_clean(struct mtk_eth
|
||||
continue;
|
||||
if (!ring->dma[i].rxd1)
|
||||
continue;
|
||||
- dma_unmap_single(eth->dev,
|
||||
+ dma_unmap_single(eth->dma_dev,
|
||||
ring->dma[i].rxd1,
|
||||
ring->buf_size,
|
||||
DMA_FROM_DEVICE);
|
||||
@@ -1788,7 +1789,7 @@ static void mtk_rx_clean(struct mtk_eth
|
||||
}
|
||||
|
||||
if (ring->dma) {
|
||||
- dma_free_coherent(eth->dev,
|
||||
+ dma_free_coherent(eth->dma_dev,
|
||||
ring->dma_size * sizeof(*ring->dma),
|
||||
ring->dma,
|
||||
ring->phys);
|
||||
@@ -2141,7 +2142,7 @@ static void mtk_dma_free(struct mtk_eth
|
||||
if (eth->netdev[i])
|
||||
netdev_reset_queue(eth->netdev[i]);
|
||||
if (eth->scratch_ring) {
|
||||
- dma_free_coherent(eth->dev,
|
||||
+ dma_free_coherent(eth->dma_dev,
|
||||
MTK_DMA_SIZE * sizeof(struct mtk_tx_dma),
|
||||
eth->scratch_ring,
|
||||
eth->phy_scratch_ring);
|
||||
@@ -2491,6 +2492,8 @@ static void mtk_dim_tx(struct work_struc
|
||||
|
||||
static int mtk_hw_init(struct mtk_eth *eth)
|
||||
{
|
||||
+ u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA |
|
||||
+ ETHSYS_DMA_AG_MAP_PPE;
|
||||
int i, val, ret;
|
||||
|
||||
if (test_and_set_bit(MTK_HW_INIT, ð->state))
|
||||
@@ -2503,6 +2506,10 @@ static int mtk_hw_init(struct mtk_eth *e
|
||||
if (ret)
|
||||
goto err_disable_pm;
|
||||
|
||||
+ if (eth->ethsys)
|
||||
+ regmap_update_bits(eth->ethsys, ETHSYS_DMA_AG_MAP, dma_mask,
|
||||
+ of_dma_is_coherent(eth->dma_dev->of_node) * dma_mask);
|
||||
+
|
||||
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) {
|
||||
ret = device_reset(eth->dev);
|
||||
if (ret) {
|
||||
@@ -3056,6 +3063,35 @@ free_netdev:
|
||||
return err;
|
||||
}
|
||||
|
||||
+void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev)
|
||||
+{
|
||||
+ struct net_device *dev, *tmp;
|
||||
+ LIST_HEAD(dev_list);
|
||||
+ int i;
|
||||
+
|
||||
+ rtnl_lock();
|
||||
+
|
||||
+ for (i = 0; i < MTK_MAC_COUNT; i++) {
|
||||
+ dev = eth->netdev[i];
|
||||
+
|
||||
+ if (!dev || !(dev->flags & IFF_UP))
|
||||
+ continue;
|
||||
+
|
||||
+ list_add_tail(&dev->close_list, &dev_list);
|
||||
+ }
|
||||
+
|
||||
+ dev_close_many(&dev_list, false);
|
||||
+
|
||||
+ eth->dma_dev = dma_dev;
|
||||
+
|
||||
+ list_for_each_entry_safe(dev, tmp, &dev_list, close_list) {
|
||||
+ list_del_init(&dev->close_list);
|
||||
+ dev_open(dev, NULL);
|
||||
+ }
|
||||
+
|
||||
+ rtnl_unlock();
|
||||
+}
|
||||
+
|
||||
static int mtk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *mac_np;
|
||||
@@ -3069,6 +3105,7 @@ static int mtk_probe(struct platform_dev
|
||||
eth->soc = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
eth->dev = &pdev->dev;
|
||||
+ eth->dma_dev = &pdev->dev;
|
||||
eth->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(eth->base))
|
||||
return PTR_ERR(eth->base);
|
||||
@@ -3117,6 +3154,16 @@ static int mtk_probe(struct platform_dev
|
||||
}
|
||||
}
|
||||
|
||||
+ if (of_dma_is_coherent(pdev->dev.of_node)) {
|
||||
+ struct regmap *cci;
|
||||
+
|
||||
+ cci = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
|
||||
+ "mediatek,cci-control");
|
||||
+ /* enable CPU/bus coherency */
|
||||
+ if (!IS_ERR(cci))
|
||||
+ regmap_write(cci, 0, 3);
|
||||
+ }
|
||||
+
|
||||
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
|
||||
eth->sgmii = devm_kzalloc(eth->dev, sizeof(*eth->sgmii),
|
||||
GFP_KERNEL);
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
@@ -462,6 +462,12 @@
|
||||
#define RSTCTRL_FE BIT(6)
|
||||
#define RSTCTRL_PPE BIT(31)
|
||||
|
||||
+/* ethernet dma channel agent map */
|
||||
+#define ETHSYS_DMA_AG_MAP 0x408
|
||||
+#define ETHSYS_DMA_AG_MAP_PDMA BIT(0)
|
||||
+#define ETHSYS_DMA_AG_MAP_QDMA BIT(1)
|
||||
+#define ETHSYS_DMA_AG_MAP_PPE BIT(2)
|
||||
+
|
||||
/* SGMII subsystem config registers */
|
||||
/* Register to auto-negotiation restart */
|
||||
#define SGMSYS_PCS_CONTROL_1 0x0
|
||||
@@ -879,6 +885,7 @@ struct mtk_sgmii {
|
||||
/* struct mtk_eth - This is the main datasructure for holding the state
|
||||
* of the driver
|
||||
* @dev: The device pointer
|
||||
+ * @dev: The device pointer used for dma mapping/alloc
|
||||
* @base: The mapped register i/o base
|
||||
* @page_lock: Make sure that register operations are atomic
|
||||
* @tx_irq__lock: Make sure that IRQ register operations are atomic
|
||||
@@ -922,6 +929,7 @@ struct mtk_sgmii {
|
||||
|
||||
struct mtk_eth {
|
||||
struct device *dev;
|
||||
+ struct device *dma_dev;
|
||||
void __iomem *base;
|
||||
spinlock_t page_lock;
|
||||
spinlock_t tx_irq_lock;
|
||||
@@ -1020,6 +1028,7 @@ int mtk_gmac_rgmii_path_setup(struct mtk
|
||||
int mtk_eth_offload_init(struct mtk_eth *eth);
|
||||
int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
|
||||
void *type_data);
|
||||
+void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev);
|
||||
|
||||
|
||||
#endif /* MTK_ETH_H */
|
@ -0,0 +1,30 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 7 Feb 2022 10:27:22 +0100
|
||||
Subject: [PATCH] arm64: dts: mediatek: mt7622: add support for coherent
|
||||
DMA
|
||||
|
||||
It improves performance by eliminating the need for a cache flush on rx and tx
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
|
||||
+++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
|
||||
@@ -357,7 +357,7 @@
|
||||
};
|
||||
|
||||
cci_control2: slave-if@5000 {
|
||||
- compatible = "arm,cci-400-ctrl-if";
|
||||
+ compatible = "arm,cci-400-ctrl-if", "syscon";
|
||||
interface-type = "ace";
|
||||
reg = <0x5000 0x1000>;
|
||||
};
|
||||
@@ -937,6 +937,8 @@
|
||||
power-domains = <&scpsys MT7622_POWER_DOMAIN_ETHSYS>;
|
||||
mediatek,ethsys = <ðsys>;
|
||||
mediatek,sgmiisys = <&sgmiisys>;
|
||||
+ mediatek,cci-control = <&cci_control2>;
|
||||
+ dma-coherent;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,269 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 5 Feb 2022 18:29:22 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: implement flow offloading
|
||||
to WED devices
|
||||
|
||||
This allows hardware flow offloading from Ethernet to WLAN on MT7622 SoC
|
||||
|
||||
Co-developed-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
@@ -329,6 +329,24 @@ int mtk_foe_entry_set_pppoe(struct mtk_f
|
||||
return 0;
|
||||
}
|
||||
|
||||
+int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
|
||||
+ int bss, int wcid)
|
||||
+{
|
||||
+ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry);
|
||||
+ u32 *ib2 = mtk_foe_entry_ib2(entry);
|
||||
+
|
||||
+ *ib2 &= ~MTK_FOE_IB2_PORT_MG;
|
||||
+ *ib2 |= MTK_FOE_IB2_WDMA_WINFO;
|
||||
+ if (wdma_idx)
|
||||
+ *ib2 |= MTK_FOE_IB2_WDMA_DEVIDX;
|
||||
+
|
||||
+ l2->vlan2 = FIELD_PREP(MTK_FOE_VLAN2_WINFO_BSS, bss) |
|
||||
+ FIELD_PREP(MTK_FOE_VLAN2_WINFO_WCID, wcid) |
|
||||
+ FIELD_PREP(MTK_FOE_VLAN2_WINFO_RING, txq);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static inline bool mtk_foe_entry_usable(struct mtk_foe_entry *entry)
|
||||
{
|
||||
return !(entry->ib1 & MTK_FOE_IB1_STATIC) &&
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
|
||||
@@ -48,9 +48,9 @@ enum {
|
||||
#define MTK_FOE_IB2_DEST_PORT GENMASK(7, 5)
|
||||
#define MTK_FOE_IB2_MULTICAST BIT(8)
|
||||
|
||||
-#define MTK_FOE_IB2_WHNAT_QID2 GENMASK(13, 12)
|
||||
-#define MTK_FOE_IB2_WHNAT_DEVIDX BIT(16)
|
||||
-#define MTK_FOE_IB2_WHNAT_NAT BIT(17)
|
||||
+#define MTK_FOE_IB2_WDMA_QID2 GENMASK(13, 12)
|
||||
+#define MTK_FOE_IB2_WDMA_DEVIDX BIT(16)
|
||||
+#define MTK_FOE_IB2_WDMA_WINFO BIT(17)
|
||||
|
||||
#define MTK_FOE_IB2_PORT_MG GENMASK(17, 12)
|
||||
|
||||
@@ -58,9 +58,9 @@ enum {
|
||||
|
||||
#define MTK_FOE_IB2_DSCP GENMASK(31, 24)
|
||||
|
||||
-#define MTK_FOE_VLAN2_WHNAT_BSS GEMMASK(5, 0)
|
||||
-#define MTK_FOE_VLAN2_WHNAT_WCID GENMASK(13, 6)
|
||||
-#define MTK_FOE_VLAN2_WHNAT_RING GENMASK(15, 14)
|
||||
+#define MTK_FOE_VLAN2_WINFO_BSS GENMASK(5, 0)
|
||||
+#define MTK_FOE_VLAN2_WINFO_WCID GENMASK(13, 6)
|
||||
+#define MTK_FOE_VLAN2_WINFO_RING GENMASK(15, 14)
|
||||
|
||||
enum {
|
||||
MTK_FOE_STATE_INVALID,
|
||||
@@ -281,6 +281,8 @@ int mtk_foe_entry_set_ipv6_tuple(struct
|
||||
int mtk_foe_entry_set_dsa(struct mtk_foe_entry *entry, int port);
|
||||
int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid);
|
||||
int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid);
|
||||
+int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
|
||||
+ int bss, int wcid);
|
||||
int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry,
|
||||
u16 timestamp);
|
||||
int mtk_ppe_debugfs_init(struct mtk_ppe *ppe);
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <net/pkt_cls.h>
|
||||
#include <net/dsa.h>
|
||||
#include "mtk_eth_soc.h"
|
||||
+#include "mtk_wed.h"
|
||||
|
||||
struct mtk_flow_data {
|
||||
struct ethhdr eth;
|
||||
@@ -39,6 +40,7 @@ struct mtk_flow_entry {
|
||||
struct rhash_head node;
|
||||
unsigned long cookie;
|
||||
u16 hash;
|
||||
+ s8 wed_index;
|
||||
};
|
||||
|
||||
static const struct rhashtable_params mtk_flow_ht_params = {
|
||||
@@ -80,6 +82,35 @@ mtk_flow_offload_mangle_eth(const struct
|
||||
memcpy(dest, src, act->mangle.mask ? 2 : 4);
|
||||
}
|
||||
|
||||
+static int
|
||||
+mtk_flow_get_wdma_info(struct net_device *dev, const u8 *addr, struct mtk_wdma_info *info)
|
||||
+{
|
||||
+ struct net_device_path_ctx ctx = {
|
||||
+ .dev = dev,
|
||||
+ .daddr = addr,
|
||||
+ };
|
||||
+ struct net_device_path path = {};
|
||||
+
|
||||
+ if (!IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED))
|
||||
+ return -1;
|
||||
+
|
||||
+ if (!dev->netdev_ops->ndo_fill_forward_path)
|
||||
+ return -1;
|
||||
+
|
||||
+ if (dev->netdev_ops->ndo_fill_forward_path(&ctx, &path))
|
||||
+ return -1;
|
||||
+
|
||||
+ if (path.type != DEV_PATH_MTK_WDMA)
|
||||
+ return -1;
|
||||
+
|
||||
+ info->wdma_idx = path.mtk_wdma.wdma_idx;
|
||||
+ info->queue = path.mtk_wdma.queue;
|
||||
+ info->bss = path.mtk_wdma.bss;
|
||||
+ info->wcid = path.mtk_wdma.wcid;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
|
||||
static int
|
||||
mtk_flow_mangle_ports(const struct flow_action_entry *act,
|
||||
@@ -149,10 +180,20 @@ mtk_flow_get_dsa_port(struct net_device
|
||||
|
||||
static int
|
||||
mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
|
||||
- struct net_device *dev)
|
||||
+ struct net_device *dev, const u8 *dest_mac,
|
||||
+ int *wed_index)
|
||||
{
|
||||
+ struct mtk_wdma_info info = {};
|
||||
int pse_port, dsa_port;
|
||||
|
||||
+ if (mtk_flow_get_wdma_info(dev, dest_mac, &info) == 0) {
|
||||
+ mtk_foe_entry_set_wdma(foe, info.wdma_idx, info.queue, info.bss,
|
||||
+ info.wcid);
|
||||
+ pse_port = 3;
|
||||
+ *wed_index = info.wdma_idx;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
dsa_port = mtk_flow_get_dsa_port(&dev);
|
||||
if (dsa_port >= 0)
|
||||
mtk_foe_entry_set_dsa(foe, dsa_port);
|
||||
@@ -164,6 +205,7 @@ mtk_flow_set_output_device(struct mtk_et
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
+out:
|
||||
mtk_foe_entry_set_pse_port(foe, pse_port);
|
||||
|
||||
return 0;
|
||||
@@ -179,6 +221,7 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
struct net_device *odev = NULL;
|
||||
struct mtk_flow_entry *entry;
|
||||
int offload_type = 0;
|
||||
+ int wed_index = -1;
|
||||
u16 addr_type = 0;
|
||||
u32 timestamp;
|
||||
u8 l4proto = 0;
|
||||
@@ -329,10 +372,14 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
if (data.pppoe.num == 1)
|
||||
mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid);
|
||||
|
||||
- err = mtk_flow_set_output_device(eth, &foe, odev);
|
||||
+ err = mtk_flow_set_output_device(eth, &foe, odev, data.eth.h_dest,
|
||||
+ &wed_index);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
+ if (wed_index >= 0 && (err = mtk_wed_flow_add(wed_index)) < 0)
|
||||
+ return err;
|
||||
+
|
||||
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
@@ -346,6 +393,7 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
}
|
||||
|
||||
entry->hash = hash;
|
||||
+ entry->wed_index = wed_index;
|
||||
err = rhashtable_insert_fast(ð->flow_table, &entry->node,
|
||||
mtk_flow_ht_params);
|
||||
if (err < 0)
|
||||
@@ -356,6 +404,8 @@ clear_flow:
|
||||
mtk_foe_entry_clear(ð->ppe, hash);
|
||||
free:
|
||||
kfree(entry);
|
||||
+ if (wed_index >= 0)
|
||||
+ mtk_wed_flow_remove(wed_index);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -372,6 +422,8 @@ mtk_flow_offload_destroy(struct mtk_eth
|
||||
mtk_foe_entry_clear(ð->ppe, entry->hash);
|
||||
rhashtable_remove_fast(ð->flow_table, &entry->node,
|
||||
mtk_flow_ht_params);
|
||||
+ if (entry->wed_index >= 0)
|
||||
+ mtk_wed_flow_remove(entry->wed_index);
|
||||
kfree(entry);
|
||||
|
||||
return 0;
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_wed.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_wed.h
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <linux/soc/mediatek/mtk_wed.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/regmap.h>
|
||||
+#include <linux/netdevice.h>
|
||||
|
||||
struct mtk_eth;
|
||||
|
||||
@@ -27,6 +28,12 @@ struct mtk_wed_hw {
|
||||
int index;
|
||||
};
|
||||
|
||||
+struct mtk_wdma_info {
|
||||
+ u8 wdma_idx;
|
||||
+ u8 queue;
|
||||
+ u16 wcid;
|
||||
+ u8 bss;
|
||||
+};
|
||||
|
||||
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
|
||||
static inline void
|
||||
--- a/include/linux/netdevice.h
|
||||
+++ b/include/linux/netdevice.h
|
||||
@@ -849,6 +849,7 @@ enum net_device_path_type {
|
||||
DEV_PATH_BRIDGE,
|
||||
DEV_PATH_PPPOE,
|
||||
DEV_PATH_DSA,
|
||||
+ DEV_PATH_MTK_WDMA,
|
||||
};
|
||||
|
||||
struct net_device_path {
|
||||
@@ -874,6 +875,12 @@ struct net_device_path {
|
||||
int port;
|
||||
u16 proto;
|
||||
} dsa;
|
||||
+ struct {
|
||||
+ u8 wdma_idx;
|
||||
+ u8 queue;
|
||||
+ u16 wcid;
|
||||
+ u8 bss;
|
||||
+ } mtk_wdma;
|
||||
};
|
||||
};
|
||||
|
||||
--- a/net/core/dev.c
|
||||
+++ b/net/core/dev.c
|
||||
@@ -761,6 +761,10 @@ int dev_fill_forward_path(const struct n
|
||||
if (WARN_ON_ONCE(last_dev == ctx.dev))
|
||||
return -1;
|
||||
}
|
||||
+
|
||||
+ if (!ctx.dev)
|
||||
+ return ret;
|
||||
+
|
||||
path = dev_fwd_path(stack);
|
||||
if (!path)
|
||||
return -1;
|
@ -0,0 +1,62 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 5 Feb 2022 18:36:36 +0100
|
||||
Subject: [PATCH] arm64: dts: mediatek: mt7622: introduce nodes for
|
||||
Wireless Ethernet Dispatch
|
||||
|
||||
Introduce wed0 and wed1 nodes in order to enable offloading forwarding
|
||||
between ethernet and wireless devices on the mt7622 chipset.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
|
||||
+++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
|
||||
@@ -893,6 +893,11 @@
|
||||
};
|
||||
};
|
||||
|
||||
+ hifsys: syscon@1af00000 {
|
||||
+ compatible = "mediatek,mt7622-hifsys", "syscon";
|
||||
+ reg = <0 0x1af00000 0 0x70>;
|
||||
+ };
|
||||
+
|
||||
ethsys: syscon@1b000000 {
|
||||
compatible = "mediatek,mt7622-ethsys",
|
||||
"syscon";
|
||||
@@ -911,6 +916,26 @@
|
||||
#dma-cells = <1>;
|
||||
};
|
||||
|
||||
+ pcie_mirror: pcie-mirror@10000400 {
|
||||
+ compatible = "mediatek,mt7622-pcie-mirror",
|
||||
+ "syscon";
|
||||
+ reg = <0 0x10000400 0 0x10>;
|
||||
+ };
|
||||
+
|
||||
+ wed0: wed@1020a000 {
|
||||
+ compatible = "mediatek,mt7622-wed",
|
||||
+ "syscon";
|
||||
+ reg = <0 0x1020a000 0 0x1000>;
|
||||
+ interrupts = <GIC_SPI 214 IRQ_TYPE_LEVEL_LOW>;
|
||||
+ };
|
||||
+
|
||||
+ wed1: wed@1020b000 {
|
||||
+ compatible = "mediatek,mt7622-wed",
|
||||
+ "syscon";
|
||||
+ reg = <0 0x1020b000 0 0x1000>;
|
||||
+ interrupts = <GIC_SPI 215 IRQ_TYPE_LEVEL_LOW>;
|
||||
+ };
|
||||
+
|
||||
eth: ethernet@1b100000 {
|
||||
compatible = "mediatek,mt7622-eth",
|
||||
"mediatek,mt2701-eth",
|
||||
@@ -938,6 +963,9 @@
|
||||
mediatek,ethsys = <ðsys>;
|
||||
mediatek,sgmiisys = <&sgmiisys>;
|
||||
mediatek,cci-control = <&cci_control2>;
|
||||
+ mediatek,wed = <&wed0>, <&wed1>;
|
||||
+ mediatek,pcie-mirror = <&pcie_mirror>;
|
||||
+ mediatek,hifsys = <&hifsys>;
|
||||
dma-coherent;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
@ -0,0 +1,79 @@
|
||||
From: David Bentham <db260179@gmail.com>
|
||||
Date: Mon, 21 Feb 2022 15:36:16 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: add ipv6 flow offload
|
||||
support
|
||||
|
||||
Add the missing IPv6 flow offloading support for routing only.
|
||||
Hardware flow offloading is done by the packet processing engine (PPE)
|
||||
of the Ethernet MAC and as it doesn't support mangling of IPv6 packets,
|
||||
IPv6 NAT cannot be supported.
|
||||
|
||||
Signed-off-by: David Bentham <db260179@gmail.com>
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/rhashtable.h>
|
||||
#include <linux/ip.h>
|
||||
+#include <linux/ipv6.h>
|
||||
#include <net/flow_offload.h>
|
||||
#include <net/pkt_cls.h>
|
||||
#include <net/dsa.h>
|
||||
@@ -20,6 +21,11 @@ struct mtk_flow_data {
|
||||
__be32 src_addr;
|
||||
__be32 dst_addr;
|
||||
} v4;
|
||||
+
|
||||
+ struct {
|
||||
+ struct in6_addr src_addr;
|
||||
+ struct in6_addr dst_addr;
|
||||
+ } v6;
|
||||
};
|
||||
|
||||
__be16 src_port;
|
||||
@@ -65,6 +71,14 @@ mtk_flow_set_ipv4_addr(struct mtk_foe_en
|
||||
data->v4.dst_addr, data->dst_port);
|
||||
}
|
||||
|
||||
+static int
|
||||
+mtk_flow_set_ipv6_addr(struct mtk_foe_entry *foe, struct mtk_flow_data *data)
|
||||
+{
|
||||
+ return mtk_foe_entry_set_ipv6_tuple(foe,
|
||||
+ data->v6.src_addr.s6_addr32, data->src_port,
|
||||
+ data->v6.dst_addr.s6_addr32, data->dst_port);
|
||||
+}
|
||||
+
|
||||
static void
|
||||
mtk_flow_offload_mangle_eth(const struct flow_action_entry *act, void *eth)
|
||||
{
|
||||
@@ -299,6 +313,9 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
|
||||
offload_type = MTK_PPE_PKT_TYPE_IPV4_HNAPT;
|
||||
break;
|
||||
+ case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
|
||||
+ offload_type = MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T;
|
||||
+ break;
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
@@ -334,6 +351,17 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
mtk_flow_set_ipv4_addr(&foe, &data, false);
|
||||
}
|
||||
|
||||
+ if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
|
||||
+ struct flow_match_ipv6_addrs addrs;
|
||||
+
|
||||
+ flow_rule_match_ipv6_addrs(rule, &addrs);
|
||||
+
|
||||
+ data.v6.src_addr = addrs.key->src;
|
||||
+ data.v6.dst_addr = addrs.key->dst;
|
||||
+
|
||||
+ mtk_flow_set_ipv6_addr(&foe, &data);
|
||||
+ }
|
||||
+
|
||||
flow_action_for_each(i, act, &rule->action) {
|
||||
if (act->id != FLOW_ACTION_MANGLE)
|
||||
continue;
|
@ -0,0 +1,29 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 21 Feb 2022 15:37:21 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: support TC_SETUP_BLOCK for
|
||||
PPE offload
|
||||
|
||||
This allows offload entries to be created from user space
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
@@ -566,10 +566,13 @@ mtk_eth_setup_tc_block(struct net_device
|
||||
int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
|
||||
void *type_data)
|
||||
{
|
||||
- if (type == TC_SETUP_FT)
|
||||
+ switch (type) {
|
||||
+ case TC_SETUP_BLOCK:
|
||||
+ case TC_SETUP_FT:
|
||||
return mtk_eth_setup_tc_block(dev, type_data);
|
||||
-
|
||||
- return -EOPNOTSUPP;
|
||||
+ default:
|
||||
+ return -EOPNOTSUPP;
|
||||
+ }
|
||||
}
|
||||
|
||||
int mtk_eth_offload_init(struct mtk_eth *eth)
|
@ -0,0 +1,159 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 21 Feb 2022 15:38:20 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: allocate struct mtk_ppe
|
||||
separately
|
||||
|
||||
Preparation for adding more data to it, which will increase its size.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -2312,7 +2312,7 @@ static int mtk_open(struct net_device *d
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
- if (eth->soc->offload_version && mtk_ppe_start(ð->ppe) == 0)
|
||||
+ if (eth->soc->offload_version && mtk_ppe_start(eth->ppe) == 0)
|
||||
gdm_config = MTK_GDMA_TO_PPE;
|
||||
|
||||
mtk_gdm_config(eth, gdm_config);
|
||||
@@ -2386,7 +2386,7 @@ static int mtk_stop(struct net_device *d
|
||||
mtk_dma_free(eth);
|
||||
|
||||
if (eth->soc->offload_version)
|
||||
- mtk_ppe_stop(ð->ppe);
|
||||
+ mtk_ppe_stop(eth->ppe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -3278,10 +3278,11 @@ static int mtk_probe(struct platform_dev
|
||||
}
|
||||
|
||||
if (eth->soc->offload_version) {
|
||||
- err = mtk_ppe_init(ð->ppe, eth->dev,
|
||||
- eth->base + MTK_ETH_PPE_BASE, 2);
|
||||
- if (err)
|
||||
+ eth->ppe = mtk_ppe_init(eth->dev, eth->base + MTK_ETH_PPE_BASE, 2);
|
||||
+ if (!eth->ppe) {
|
||||
+ err = -ENOMEM;
|
||||
goto err_free_dev;
|
||||
+ }
|
||||
|
||||
err = mtk_eth_offload_init(eth);
|
||||
if (err)
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
@@ -982,7 +982,7 @@ struct mtk_eth {
|
||||
u32 rx_dma_l4_valid;
|
||||
int ip_align;
|
||||
|
||||
- struct mtk_ppe ppe;
|
||||
+ struct mtk_ppe *ppe;
|
||||
struct rhashtable flow_table;
|
||||
};
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
@@ -384,10 +384,15 @@ int mtk_foe_entry_commit(struct mtk_ppe
|
||||
return hash;
|
||||
}
|
||||
|
||||
-int mtk_ppe_init(struct mtk_ppe *ppe, struct device *dev, void __iomem *base,
|
||||
+struct mtk_ppe *mtk_ppe_init(struct device *dev, void __iomem *base,
|
||||
int version)
|
||||
{
|
||||
struct mtk_foe_entry *foe;
|
||||
+ struct mtk_ppe *ppe;
|
||||
+
|
||||
+ ppe = devm_kzalloc(dev, sizeof(*ppe), GFP_KERNEL);
|
||||
+ if (!ppe)
|
||||
+ return NULL;
|
||||
|
||||
/* need to allocate a separate device, since it PPE DMA access is
|
||||
* not coherent.
|
||||
@@ -399,13 +404,13 @@ int mtk_ppe_init(struct mtk_ppe *ppe, st
|
||||
foe = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*foe),
|
||||
&ppe->foe_phys, GFP_KERNEL);
|
||||
if (!foe)
|
||||
- return -ENOMEM;
|
||||
+ return NULL;
|
||||
|
||||
ppe->foe_table = foe;
|
||||
|
||||
mtk_ppe_debugfs_init(ppe);
|
||||
|
||||
- return 0;
|
||||
+ return ppe;
|
||||
}
|
||||
|
||||
static void mtk_ppe_init_foe_table(struct mtk_ppe *ppe)
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
|
||||
@@ -246,8 +246,7 @@ struct mtk_ppe {
|
||||
void *acct_table;
|
||||
};
|
||||
|
||||
-int mtk_ppe_init(struct mtk_ppe *ppe, struct device *dev, void __iomem *base,
|
||||
- int version);
|
||||
+struct mtk_ppe *mtk_ppe_init(struct device *dev, void __iomem *base, int version);
|
||||
int mtk_ppe_start(struct mtk_ppe *ppe);
|
||||
int mtk_ppe_stop(struct mtk_ppe *ppe);
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
@@ -414,7 +414,7 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
|
||||
entry->cookie = f->cookie;
|
||||
timestamp = mtk_eth_timestamp(eth);
|
||||
- hash = mtk_foe_entry_commit(ð->ppe, &foe, timestamp);
|
||||
+ hash = mtk_foe_entry_commit(eth->ppe, &foe, timestamp);
|
||||
if (hash < 0) {
|
||||
err = hash;
|
||||
goto free;
|
||||
@@ -429,7 +429,7 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
|
||||
return 0;
|
||||
clear_flow:
|
||||
- mtk_foe_entry_clear(ð->ppe, hash);
|
||||
+ mtk_foe_entry_clear(eth->ppe, hash);
|
||||
free:
|
||||
kfree(entry);
|
||||
if (wed_index >= 0)
|
||||
@@ -447,7 +447,7 @@ mtk_flow_offload_destroy(struct mtk_eth
|
||||
if (!entry)
|
||||
return -ENOENT;
|
||||
|
||||
- mtk_foe_entry_clear(ð->ppe, entry->hash);
|
||||
+ mtk_foe_entry_clear(eth->ppe, entry->hash);
|
||||
rhashtable_remove_fast(ð->flow_table, &entry->node,
|
||||
mtk_flow_ht_params);
|
||||
if (entry->wed_index >= 0)
|
||||
@@ -469,7 +469,7 @@ mtk_flow_offload_stats(struct mtk_eth *e
|
||||
if (!entry)
|
||||
return -ENOENT;
|
||||
|
||||
- timestamp = mtk_foe_entry_timestamp(ð->ppe, entry->hash);
|
||||
+ timestamp = mtk_foe_entry_timestamp(eth->ppe, entry->hash);
|
||||
if (timestamp < 0)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
@@ -525,7 +525,7 @@ mtk_eth_setup_tc_block(struct net_device
|
||||
struct flow_block_cb *block_cb;
|
||||
flow_setup_cb_t *cb;
|
||||
|
||||
- if (!eth->ppe.foe_table)
|
||||
+ if (!eth->ppe || !eth->ppe->foe_table)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
|
||||
@@ -577,7 +577,7 @@ int mtk_eth_setup_tc(struct net_device *
|
||||
|
||||
int mtk_eth_offload_init(struct mtk_eth *eth)
|
||||
{
|
||||
- if (!eth->ppe.foe_table)
|
||||
+ if (!eth->ppe || !eth->ppe->foe_table)
|
||||
return 0;
|
||||
|
||||
return rhashtable_init(ð->flow_table, &mtk_flow_ht_params);
|
@ -0,0 +1,424 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 21 Feb 2022 15:39:18 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: rework hardware flow table
|
||||
management
|
||||
|
||||
The hardware was designed to handle flow detection and creation of flow entries
|
||||
by itself, relying on the software primarily for filling in egress routing
|
||||
information.
|
||||
When there is a hash collision between multiple flows, this allows the hardware
|
||||
to maintain the entry for the most active flow.
|
||||
Additionally, the hardware only keeps offloading active for entries with at
|
||||
least 30 packets per second.
|
||||
|
||||
With this rework, the code no longer creates a hardware entries directly.
|
||||
Instead, the hardware entry is only created when the PPE reports a matching
|
||||
unbound flow with the minimum target rate.
|
||||
In order to reduce CPU overhead, looking for flows belonging to a hash entry
|
||||
is rate limited to once every 100ms.
|
||||
|
||||
This rework is also used as preparation for emulating bridge offload by
|
||||
managing L4 offload entries on demand.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <linux/pinctrl/devinfo.h>
|
||||
#include <linux/phylink.h>
|
||||
#include <linux/jhash.h>
|
||||
+#include <linux/bitfield.h>
|
||||
#include <net/dsa.h>
|
||||
|
||||
#include "mtk_eth_soc.h"
|
||||
@@ -1281,7 +1282,7 @@ static int mtk_poll_rx(struct napi_struc
|
||||
struct net_device *netdev;
|
||||
unsigned int pktlen;
|
||||
dma_addr_t dma_addr;
|
||||
- u32 hash;
|
||||
+ u32 hash, reason;
|
||||
int mac;
|
||||
|
||||
ring = mtk_get_rx_ring(eth);
|
||||
@@ -1357,6 +1358,11 @@ static int mtk_poll_rx(struct napi_struc
|
||||
skb_set_hash(skb, hash, PKT_HASH_TYPE_L4);
|
||||
}
|
||||
|
||||
+ reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4);
|
||||
+ if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
|
||||
+ mtk_ppe_check_skb(eth->ppe, skb,
|
||||
+ trxd.rxd4 & MTK_RXD4_FOE_ENTRY);
|
||||
+
|
||||
if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX &&
|
||||
(trxd.rxd2 & RX_DMA_VTAG))
|
||||
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
|
||||
@@ -3278,7 +3284,7 @@ static int mtk_probe(struct platform_dev
|
||||
}
|
||||
|
||||
if (eth->soc->offload_version) {
|
||||
- eth->ppe = mtk_ppe_init(eth->dev, eth->base + MTK_ETH_PPE_BASE, 2);
|
||||
+ eth->ppe = mtk_ppe_init(eth, eth->base + MTK_ETH_PPE_BASE, 2);
|
||||
if (!eth->ppe) {
|
||||
err = -ENOMEM;
|
||||
goto err_free_dev;
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
@@ -6,9 +6,12 @@
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/platform_device.h>
|
||||
+#include "mtk_eth_soc.h"
|
||||
#include "mtk_ppe.h"
|
||||
#include "mtk_ppe_regs.h"
|
||||
|
||||
+static DEFINE_SPINLOCK(ppe_lock);
|
||||
+
|
||||
static void ppe_w32(struct mtk_ppe *ppe, u32 reg, u32 val)
|
||||
{
|
||||
writel(val, ppe->base + reg);
|
||||
@@ -41,6 +44,11 @@ static u32 ppe_clear(struct mtk_ppe *ppe
|
||||
return ppe_m32(ppe, reg, val, 0);
|
||||
}
|
||||
|
||||
+static u32 mtk_eth_timestamp(struct mtk_eth *eth)
|
||||
+{
|
||||
+ return mtk_r32(eth, 0x0010) & MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
+}
|
||||
+
|
||||
static int mtk_ppe_wait_busy(struct mtk_ppe *ppe)
|
||||
{
|
||||
int ret;
|
||||
@@ -353,26 +361,59 @@ static inline bool mtk_foe_entry_usable(
|
||||
FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1) != MTK_FOE_STATE_BIND;
|
||||
}
|
||||
|
||||
-int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry,
|
||||
- u16 timestamp)
|
||||
+static bool
|
||||
+mtk_flow_entry_match(struct mtk_flow_entry *entry, struct mtk_foe_entry *data)
|
||||
+{
|
||||
+ int type, len;
|
||||
+
|
||||
+ if ((data->ib1 ^ entry->data.ib1) & MTK_FOE_IB1_UDP)
|
||||
+ return false;
|
||||
+
|
||||
+ type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->data.ib1);
|
||||
+ if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE)
|
||||
+ len = offsetof(struct mtk_foe_entry, ipv6._rsv);
|
||||
+ else
|
||||
+ len = offsetof(struct mtk_foe_entry, ipv4.ib2);
|
||||
+
|
||||
+ return !memcmp(&entry->data.data, &data->data, len - 4);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
{
|
||||
struct mtk_foe_entry *hwe;
|
||||
- u32 hash;
|
||||
+ struct mtk_foe_entry foe;
|
||||
|
||||
+ spin_lock_bh(&ppe_lock);
|
||||
+ if (entry->hash == 0xffff)
|
||||
+ goto out;
|
||||
+
|
||||
+ hwe = &ppe->foe_table[entry->hash];
|
||||
+ memcpy(&foe, hwe, sizeof(foe));
|
||||
+ if (!mtk_flow_entry_match(entry, &foe)) {
|
||||
+ entry->hash = 0xffff;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ entry->data.ib1 = foe.ib1;
|
||||
+
|
||||
+out:
|
||||
+ spin_unlock_bh(&ppe_lock);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+__mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry,
|
||||
+ u16 hash)
|
||||
+{
|
||||
+ struct mtk_foe_entry *hwe;
|
||||
+ u16 timestamp;
|
||||
+
|
||||
+ timestamp = mtk_eth_timestamp(ppe->eth);
|
||||
timestamp &= MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP, timestamp);
|
||||
|
||||
- hash = mtk_ppe_hash_entry(entry);
|
||||
hwe = &ppe->foe_table[hash];
|
||||
- if (!mtk_foe_entry_usable(hwe)) {
|
||||
- hwe++;
|
||||
- hash++;
|
||||
-
|
||||
- if (!mtk_foe_entry_usable(hwe))
|
||||
- return -ENOSPC;
|
||||
- }
|
||||
-
|
||||
memcpy(&hwe->data, &entry->data, sizeof(hwe->data));
|
||||
wmb();
|
||||
hwe->ib1 = entry->ib1;
|
||||
@@ -380,13 +421,77 @@ int mtk_foe_entry_commit(struct mtk_ppe
|
||||
dma_wmb();
|
||||
|
||||
mtk_ppe_cache_clear(ppe);
|
||||
+}
|
||||
|
||||
- return hash;
|
||||
+void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
+{
|
||||
+ spin_lock_bh(&ppe_lock);
|
||||
+ hlist_del_init(&entry->list);
|
||||
+ if (entry->hash != 0xffff) {
|
||||
+ ppe->foe_table[entry->hash].ib1 &= ~MTK_FOE_IB1_STATE;
|
||||
+ ppe->foe_table[entry->hash].ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE,
|
||||
+ MTK_FOE_STATE_BIND);
|
||||
+ dma_wmb();
|
||||
+ }
|
||||
+ entry->hash = 0xffff;
|
||||
+ spin_unlock_bh(&ppe_lock);
|
||||
+}
|
||||
+
|
||||
+int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
+{
|
||||
+ u32 hash = mtk_ppe_hash_entry(&entry->data);
|
||||
+
|
||||
+ entry->hash = 0xffff;
|
||||
+ spin_lock_bh(&ppe_lock);
|
||||
+ hlist_add_head(&entry->list, &ppe->foe_flow[hash / 2]);
|
||||
+ spin_unlock_bh(&ppe_lock);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
|
||||
+{
|
||||
+ struct hlist_head *head = &ppe->foe_flow[hash / 2];
|
||||
+ struct mtk_flow_entry *entry;
|
||||
+ struct mtk_foe_entry *hwe = &ppe->foe_table[hash];
|
||||
+ bool found = false;
|
||||
+
|
||||
+ if (hlist_empty(head))
|
||||
+ return;
|
||||
+
|
||||
+ spin_lock_bh(&ppe_lock);
|
||||
+ hlist_for_each_entry(entry, head, list) {
|
||||
+ if (found || !mtk_flow_entry_match(entry, hwe)) {
|
||||
+ if (entry->hash != 0xffff)
|
||||
+ entry->hash = 0xffff;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ entry->hash = hash;
|
||||
+ __mtk_foe_entry_commit(ppe, &entry->data, hash);
|
||||
+ found = true;
|
||||
+ }
|
||||
+ spin_unlock_bh(&ppe_lock);
|
||||
+}
|
||||
+
|
||||
+int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
+{
|
||||
+ u16 now = mtk_eth_timestamp(ppe->eth) & MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
+ u16 timestamp;
|
||||
+
|
||||
+ mtk_flow_entry_update(ppe, entry);
|
||||
+ timestamp = entry->data.ib1 & MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
+
|
||||
+ if (timestamp > now)
|
||||
+ return MTK_FOE_IB1_BIND_TIMESTAMP + 1 - timestamp + now;
|
||||
+ else
|
||||
+ return now - timestamp;
|
||||
}
|
||||
|
||||
-struct mtk_ppe *mtk_ppe_init(struct device *dev, void __iomem *base,
|
||||
+struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
|
||||
int version)
|
||||
{
|
||||
+ struct device *dev = eth->dev;
|
||||
struct mtk_foe_entry *foe;
|
||||
struct mtk_ppe *ppe;
|
||||
|
||||
@@ -398,6 +503,7 @@ struct mtk_ppe *mtk_ppe_init(struct devi
|
||||
* not coherent.
|
||||
*/
|
||||
ppe->base = base;
|
||||
+ ppe->eth = eth;
|
||||
ppe->dev = dev;
|
||||
ppe->version = version;
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
|
||||
@@ -235,7 +235,17 @@ enum {
|
||||
MTK_PPE_CPU_REASON_INVALID = 0x1f,
|
||||
};
|
||||
|
||||
+struct mtk_flow_entry {
|
||||
+ struct rhash_head node;
|
||||
+ struct hlist_node list;
|
||||
+ unsigned long cookie;
|
||||
+ struct mtk_foe_entry data;
|
||||
+ u16 hash;
|
||||
+ s8 wed_index;
|
||||
+};
|
||||
+
|
||||
struct mtk_ppe {
|
||||
+ struct mtk_eth *eth;
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
int version;
|
||||
@@ -243,18 +253,33 @@ struct mtk_ppe {
|
||||
struct mtk_foe_entry *foe_table;
|
||||
dma_addr_t foe_phys;
|
||||
|
||||
+ u16 foe_check_time[MTK_PPE_ENTRIES];
|
||||
+ struct hlist_head foe_flow[MTK_PPE_ENTRIES / 2];
|
||||
+
|
||||
void *acct_table;
|
||||
};
|
||||
|
||||
-struct mtk_ppe *mtk_ppe_init(struct device *dev, void __iomem *base, int version);
|
||||
+struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int version);
|
||||
int mtk_ppe_start(struct mtk_ppe *ppe);
|
||||
int mtk_ppe_stop(struct mtk_ppe *ppe);
|
||||
|
||||
+void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash);
|
||||
+
|
||||
static inline void
|
||||
-mtk_foe_entry_clear(struct mtk_ppe *ppe, u16 hash)
|
||||
+mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
|
||||
{
|
||||
- ppe->foe_table[hash].ib1 = 0;
|
||||
- dma_wmb();
|
||||
+ u16 now, diff;
|
||||
+
|
||||
+ if (!ppe)
|
||||
+ return;
|
||||
+
|
||||
+ now = (u16)jiffies;
|
||||
+ diff = now - ppe->foe_check_time[hash];
|
||||
+ if (diff < HZ / 10)
|
||||
+ return;
|
||||
+
|
||||
+ ppe->foe_check_time[hash] = now;
|
||||
+ __mtk_ppe_check_skb(ppe, skb, hash);
|
||||
}
|
||||
|
||||
static inline int
|
||||
@@ -282,8 +307,9 @@ int mtk_foe_entry_set_vlan(struct mtk_fo
|
||||
int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid);
|
||||
int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
|
||||
int bss, int wcid);
|
||||
-int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry,
|
||||
- u16 timestamp);
|
||||
+int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
|
||||
+void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
|
||||
+int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
|
||||
int mtk_ppe_debugfs_init(struct mtk_ppe *ppe);
|
||||
|
||||
#endif
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
@@ -42,13 +42,6 @@ struct mtk_flow_data {
|
||||
} pppoe;
|
||||
};
|
||||
|
||||
-struct mtk_flow_entry {
|
||||
- struct rhash_head node;
|
||||
- unsigned long cookie;
|
||||
- u16 hash;
|
||||
- s8 wed_index;
|
||||
-};
|
||||
-
|
||||
static const struct rhashtable_params mtk_flow_ht_params = {
|
||||
.head_offset = offsetof(struct mtk_flow_entry, node),
|
||||
.key_offset = offsetof(struct mtk_flow_entry, cookie),
|
||||
@@ -56,12 +49,6 @@ static const struct rhashtable_params mt
|
||||
.automatic_shrinking = true,
|
||||
};
|
||||
|
||||
-static u32
|
||||
-mtk_eth_timestamp(struct mtk_eth *eth)
|
||||
-{
|
||||
- return mtk_r32(eth, 0x0010) & MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
-}
|
||||
-
|
||||
static int
|
||||
mtk_flow_set_ipv4_addr(struct mtk_foe_entry *foe, struct mtk_flow_data *data,
|
||||
bool egress)
|
||||
@@ -237,10 +224,8 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
int offload_type = 0;
|
||||
int wed_index = -1;
|
||||
u16 addr_type = 0;
|
||||
- u32 timestamp;
|
||||
u8 l4proto = 0;
|
||||
int err = 0;
|
||||
- int hash;
|
||||
int i;
|
||||
|
||||
if (rhashtable_lookup(ð->flow_table, &f->cookie, mtk_flow_ht_params))
|
||||
@@ -413,23 +398,21 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
return -ENOMEM;
|
||||
|
||||
entry->cookie = f->cookie;
|
||||
- timestamp = mtk_eth_timestamp(eth);
|
||||
- hash = mtk_foe_entry_commit(eth->ppe, &foe, timestamp);
|
||||
- if (hash < 0) {
|
||||
- err = hash;
|
||||
+ memcpy(&entry->data, &foe, sizeof(entry->data));
|
||||
+ entry->wed_index = wed_index;
|
||||
+
|
||||
+ if (mtk_foe_entry_commit(eth->ppe, entry) < 0)
|
||||
goto free;
|
||||
- }
|
||||
|
||||
- entry->hash = hash;
|
||||
- entry->wed_index = wed_index;
|
||||
err = rhashtable_insert_fast(ð->flow_table, &entry->node,
|
||||
mtk_flow_ht_params);
|
||||
if (err < 0)
|
||||
- goto clear_flow;
|
||||
+ goto clear;
|
||||
|
||||
return 0;
|
||||
-clear_flow:
|
||||
- mtk_foe_entry_clear(eth->ppe, hash);
|
||||
+
|
||||
+clear:
|
||||
+ mtk_foe_entry_clear(eth->ppe, entry);
|
||||
free:
|
||||
kfree(entry);
|
||||
if (wed_index >= 0)
|
||||
@@ -447,7 +430,7 @@ mtk_flow_offload_destroy(struct mtk_eth
|
||||
if (!entry)
|
||||
return -ENOENT;
|
||||
|
||||
- mtk_foe_entry_clear(eth->ppe, entry->hash);
|
||||
+ mtk_foe_entry_clear(eth->ppe, entry);
|
||||
rhashtable_remove_fast(ð->flow_table, &entry->node,
|
||||
mtk_flow_ht_params);
|
||||
if (entry->wed_index >= 0)
|
||||
@@ -461,7 +444,6 @@ static int
|
||||
mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f)
|
||||
{
|
||||
struct mtk_flow_entry *entry;
|
||||
- int timestamp;
|
||||
u32 idle;
|
||||
|
||||
entry = rhashtable_lookup(ð->flow_table, &f->cookie,
|
||||
@@ -469,11 +451,7 @@ mtk_flow_offload_stats(struct mtk_eth *e
|
||||
if (!entry)
|
||||
return -ENOENT;
|
||||
|
||||
- timestamp = mtk_foe_entry_timestamp(eth->ppe, entry->hash);
|
||||
- if (timestamp < 0)
|
||||
- return -ETIMEDOUT;
|
||||
-
|
||||
- idle = mtk_eth_timestamp(eth) - timestamp;
|
||||
+ idle = mtk_foe_entry_idle_time(eth->ppe, entry);
|
||||
f->stats.lastused = jiffies - idle * HZ;
|
||||
|
||||
return 0;
|
@ -0,0 +1,44 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 21 Feb 2022 15:55:19 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: remove bridge flow offload
|
||||
type entry support
|
||||
|
||||
According to MediaTek, this feature is not supported in current hardware
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
@@ -84,13 +84,6 @@ static u32 mtk_ppe_hash_entry(struct mtk
|
||||
u32 hash;
|
||||
|
||||
switch (FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, e->ib1)) {
|
||||
- case MTK_PPE_PKT_TYPE_BRIDGE:
|
||||
- hv1 = e->bridge.src_mac_lo;
|
||||
- hv1 ^= ((e->bridge.src_mac_hi & 0xffff) << 16);
|
||||
- hv2 = e->bridge.src_mac_hi >> 16;
|
||||
- hv2 ^= e->bridge.dest_mac_lo;
|
||||
- hv3 = e->bridge.dest_mac_hi;
|
||||
- break;
|
||||
case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
|
||||
case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
|
||||
hv1 = e->ipv4.orig.ports;
|
||||
@@ -572,7 +565,6 @@ int mtk_ppe_start(struct mtk_ppe *ppe)
|
||||
MTK_PPE_FLOW_CFG_IP4_NAT |
|
||||
MTK_PPE_FLOW_CFG_IP4_NAPT |
|
||||
MTK_PPE_FLOW_CFG_IP4_DSLITE |
|
||||
- MTK_PPE_FLOW_CFG_L2_BRIDGE |
|
||||
MTK_PPE_FLOW_CFG_IP4_NAT_FRAG;
|
||||
ppe_w32(ppe, MTK_PPE_FLOW_CFG, val);
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
|
||||
@@ -32,7 +32,6 @@ static const char *mtk_foe_pkt_type_str(
|
||||
static const char * const type_str[] = {
|
||||
[MTK_PPE_PKT_TYPE_IPV4_HNAPT] = "IPv4 5T",
|
||||
[MTK_PPE_PKT_TYPE_IPV4_ROUTE] = "IPv4 3T",
|
||||
- [MTK_PPE_PKT_TYPE_BRIDGE] = "L2",
|
||||
[MTK_PPE_PKT_TYPE_IPV4_DSLITE] = "DS-LITE",
|
||||
[MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T] = "IPv6 3T",
|
||||
[MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T] = "IPv6 5T",
|
@ -0,0 +1,553 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 23 Feb 2022 10:56:34 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: support creating mac
|
||||
address based offload entries
|
||||
|
||||
This will be used to implement a limited form of bridge offloading.
|
||||
Since the hardware does not support flow table entries with just source
|
||||
and destination MAC address, the driver has to emulate it.
|
||||
|
||||
The hardware automatically creates entries entries for incoming flows, even
|
||||
when they are bridged instead of routed, and reports when packets for these
|
||||
flows have reached the minimum PPS rate for offloading.
|
||||
|
||||
After this happens, we look up the L2 flow offload entry based on the MAC
|
||||
header and fill in the output routing information in the flow table.
|
||||
The dynamically created per-flow entries are automatically removed when
|
||||
either the hardware flowtable entry expires, is replaced, or if the offload
|
||||
rule they belong to is removed
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
@@ -6,12 +6,22 @@
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/platform_device.h>
|
||||
+#include <linux/if_ether.h>
|
||||
+#include <linux/if_vlan.h>
|
||||
+#include <net/dsa.h>
|
||||
#include "mtk_eth_soc.h"
|
||||
#include "mtk_ppe.h"
|
||||
#include "mtk_ppe_regs.h"
|
||||
|
||||
static DEFINE_SPINLOCK(ppe_lock);
|
||||
|
||||
+static const struct rhashtable_params mtk_flow_l2_ht_params = {
|
||||
+ .head_offset = offsetof(struct mtk_flow_entry, l2_node),
|
||||
+ .key_offset = offsetof(struct mtk_flow_entry, data.bridge),
|
||||
+ .key_len = offsetof(struct mtk_foe_bridge, key_end),
|
||||
+ .automatic_shrinking = true,
|
||||
+};
|
||||
+
|
||||
static void ppe_w32(struct mtk_ppe *ppe, u32 reg, u32 val)
|
||||
{
|
||||
writel(val, ppe->base + reg);
|
||||
@@ -123,6 +133,9 @@ mtk_foe_entry_l2(struct mtk_foe_entry *e
|
||||
{
|
||||
int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
|
||||
|
||||
+ if (type == MTK_PPE_PKT_TYPE_BRIDGE)
|
||||
+ return &entry->bridge.l2;
|
||||
+
|
||||
if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE)
|
||||
return &entry->ipv6.l2;
|
||||
|
||||
@@ -134,6 +147,9 @@ mtk_foe_entry_ib2(struct mtk_foe_entry *
|
||||
{
|
||||
int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
|
||||
|
||||
+ if (type == MTK_PPE_PKT_TYPE_BRIDGE)
|
||||
+ return &entry->bridge.ib2;
|
||||
+
|
||||
if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE)
|
||||
return &entry->ipv6.ib2;
|
||||
|
||||
@@ -168,7 +184,12 @@ int mtk_foe_entry_prepare(struct mtk_foe
|
||||
if (type == MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T)
|
||||
entry->ipv6.ports = ports_pad;
|
||||
|
||||
- if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) {
|
||||
+ if (type == MTK_PPE_PKT_TYPE_BRIDGE) {
|
||||
+ ether_addr_copy(entry->bridge.src_mac, src_mac);
|
||||
+ ether_addr_copy(entry->bridge.dest_mac, dest_mac);
|
||||
+ entry->bridge.ib2 = val;
|
||||
+ l2 = &entry->bridge.l2;
|
||||
+ } else if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) {
|
||||
entry->ipv6.ib2 = val;
|
||||
l2 = &entry->ipv6.l2;
|
||||
} else {
|
||||
@@ -372,12 +393,96 @@ mtk_flow_entry_match(struct mtk_flow_ent
|
||||
}
|
||||
|
||||
static void
|
||||
+__mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
+{
|
||||
+ struct hlist_head *head;
|
||||
+ struct hlist_node *tmp;
|
||||
+
|
||||
+ if (entry->type == MTK_FLOW_TYPE_L2) {
|
||||
+ rhashtable_remove_fast(&ppe->l2_flows, &entry->l2_node,
|
||||
+ mtk_flow_l2_ht_params);
|
||||
+
|
||||
+ head = &entry->l2_flows;
|
||||
+ hlist_for_each_entry_safe(entry, tmp, head, l2_data.list)
|
||||
+ __mtk_foe_entry_clear(ppe, entry);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ hlist_del_init(&entry->list);
|
||||
+ if (entry->hash != 0xffff) {
|
||||
+ ppe->foe_table[entry->hash].ib1 &= ~MTK_FOE_IB1_STATE;
|
||||
+ ppe->foe_table[entry->hash].ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE,
|
||||
+ MTK_FOE_STATE_BIND);
|
||||
+ dma_wmb();
|
||||
+ }
|
||||
+ entry->hash = 0xffff;
|
||||
+
|
||||
+ if (entry->type != MTK_FLOW_TYPE_L2_SUBFLOW)
|
||||
+ return;
|
||||
+
|
||||
+ hlist_del_init(&entry->l2_data.list);
|
||||
+ kfree(entry);
|
||||
+}
|
||||
+
|
||||
+static int __mtk_foe_entry_idle_time(struct mtk_ppe *ppe, u32 ib1)
|
||||
+{
|
||||
+ u16 timestamp;
|
||||
+ u16 now;
|
||||
+
|
||||
+ now = mtk_eth_timestamp(ppe->eth) & MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
+ timestamp = ib1 & MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
+
|
||||
+ if (timestamp > now)
|
||||
+ return MTK_FOE_IB1_BIND_TIMESTAMP + 1 - timestamp + now;
|
||||
+ else
|
||||
+ return now - timestamp;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
+{
|
||||
+ struct mtk_flow_entry *cur;
|
||||
+ struct mtk_foe_entry *hwe;
|
||||
+ struct hlist_node *tmp;
|
||||
+ int idle;
|
||||
+
|
||||
+ idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1);
|
||||
+ hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_data.list) {
|
||||
+ int cur_idle;
|
||||
+ u32 ib1;
|
||||
+
|
||||
+ hwe = &ppe->foe_table[cur->hash];
|
||||
+ ib1 = READ_ONCE(hwe->ib1);
|
||||
+
|
||||
+ if (FIELD_GET(MTK_FOE_IB1_STATE, ib1) != MTK_FOE_STATE_BIND) {
|
||||
+ cur->hash = 0xffff;
|
||||
+ __mtk_foe_entry_clear(ppe, cur);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ cur_idle = __mtk_foe_entry_idle_time(ppe, ib1);
|
||||
+ if (cur_idle >= idle)
|
||||
+ continue;
|
||||
+
|
||||
+ idle = cur_idle;
|
||||
+ entry->data.ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
+ entry->data.ib1 |= hwe->ib1 & MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
{
|
||||
struct mtk_foe_entry *hwe;
|
||||
struct mtk_foe_entry foe;
|
||||
|
||||
spin_lock_bh(&ppe_lock);
|
||||
+
|
||||
+ if (entry->type == MTK_FLOW_TYPE_L2) {
|
||||
+ mtk_flow_entry_update_l2(ppe, entry);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
if (entry->hash == 0xffff)
|
||||
goto out;
|
||||
|
||||
@@ -419,21 +524,28 @@ __mtk_foe_entry_commit(struct mtk_ppe *p
|
||||
void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
{
|
||||
spin_lock_bh(&ppe_lock);
|
||||
- hlist_del_init(&entry->list);
|
||||
- if (entry->hash != 0xffff) {
|
||||
- ppe->foe_table[entry->hash].ib1 &= ~MTK_FOE_IB1_STATE;
|
||||
- ppe->foe_table[entry->hash].ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE,
|
||||
- MTK_FOE_STATE_BIND);
|
||||
- dma_wmb();
|
||||
- }
|
||||
- entry->hash = 0xffff;
|
||||
+ __mtk_foe_entry_clear(ppe, entry);
|
||||
spin_unlock_bh(&ppe_lock);
|
||||
}
|
||||
|
||||
+static int
|
||||
+mtk_foe_entry_commit_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
+{
|
||||
+ entry->type = MTK_FLOW_TYPE_L2;
|
||||
+
|
||||
+ return rhashtable_insert_fast(&ppe->l2_flows, &entry->l2_node,
|
||||
+ mtk_flow_l2_ht_params);
|
||||
+}
|
||||
+
|
||||
int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
{
|
||||
- u32 hash = mtk_ppe_hash_entry(&entry->data);
|
||||
+ int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->data.ib1);
|
||||
+ u32 hash;
|
||||
+
|
||||
+ if (type == MTK_PPE_PKT_TYPE_BRIDGE)
|
||||
+ return mtk_foe_entry_commit_l2(ppe, entry);
|
||||
|
||||
+ hash = mtk_ppe_hash_entry(&entry->data);
|
||||
entry->hash = 0xffff;
|
||||
spin_lock_bh(&ppe_lock);
|
||||
hlist_add_head(&entry->list, &ppe->foe_flow[hash / 2]);
|
||||
@@ -442,18 +554,72 @@ int mtk_foe_entry_commit(struct mtk_ppe
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void
|
||||
+mtk_foe_entry_commit_subflow(struct mtk_ppe *ppe, struct mtk_flow_entry *entry,
|
||||
+ u16 hash)
|
||||
+{
|
||||
+ struct mtk_flow_entry *flow_info;
|
||||
+ struct mtk_foe_entry foe, *hwe;
|
||||
+ struct mtk_foe_mac_info *l2;
|
||||
+ u32 ib1_mask = MTK_FOE_IB1_PACKET_TYPE | MTK_FOE_IB1_UDP;
|
||||
+ int type;
|
||||
+
|
||||
+ flow_info = kzalloc(offsetof(struct mtk_flow_entry, l2_data.end),
|
||||
+ GFP_ATOMIC);
|
||||
+ if (!flow_info)
|
||||
+ return;
|
||||
+
|
||||
+ flow_info->l2_data.base_flow = entry;
|
||||
+ flow_info->type = MTK_FLOW_TYPE_L2_SUBFLOW;
|
||||
+ flow_info->hash = hash;
|
||||
+ hlist_add_head(&flow_info->list, &ppe->foe_flow[hash / 2]);
|
||||
+ hlist_add_head(&flow_info->l2_data.list, &entry->l2_flows);
|
||||
+
|
||||
+ hwe = &ppe->foe_table[hash];
|
||||
+ memcpy(&foe, hwe, sizeof(foe));
|
||||
+ foe.ib1 &= ib1_mask;
|
||||
+ foe.ib1 |= entry->data.ib1 & ~ib1_mask;
|
||||
+
|
||||
+ l2 = mtk_foe_entry_l2(&foe);
|
||||
+ memcpy(l2, &entry->data.bridge.l2, sizeof(*l2));
|
||||
+
|
||||
+ type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, foe.ib1);
|
||||
+ if (type == MTK_PPE_PKT_TYPE_IPV4_HNAPT)
|
||||
+ memcpy(&foe.ipv4.new, &foe.ipv4.orig, sizeof(foe.ipv4.new));
|
||||
+ else if (type >= MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T && l2->etype == ETH_P_IP)
|
||||
+ l2->etype = ETH_P_IPV6;
|
||||
+
|
||||
+ *mtk_foe_entry_ib2(&foe) = entry->data.bridge.ib2;
|
||||
+
|
||||
+ __mtk_foe_entry_commit(ppe, &foe, hash);
|
||||
+}
|
||||
+
|
||||
void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
|
||||
{
|
||||
struct hlist_head *head = &ppe->foe_flow[hash / 2];
|
||||
- struct mtk_flow_entry *entry;
|
||||
struct mtk_foe_entry *hwe = &ppe->foe_table[hash];
|
||||
+ struct mtk_flow_entry *entry;
|
||||
+ struct mtk_foe_bridge key = {};
|
||||
+ struct ethhdr *eh;
|
||||
bool found = false;
|
||||
-
|
||||
- if (hlist_empty(head))
|
||||
- return;
|
||||
+ u8 *tag;
|
||||
|
||||
spin_lock_bh(&ppe_lock);
|
||||
+
|
||||
+ if (FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == MTK_FOE_STATE_BIND)
|
||||
+ goto out;
|
||||
+
|
||||
hlist_for_each_entry(entry, head, list) {
|
||||
+ if (entry->type == MTK_FLOW_TYPE_L2_SUBFLOW) {
|
||||
+ if (unlikely(FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) ==
|
||||
+ MTK_FOE_STATE_BIND))
|
||||
+ continue;
|
||||
+
|
||||
+ entry->hash = 0xffff;
|
||||
+ __mtk_foe_entry_clear(ppe, entry);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
if (found || !mtk_flow_entry_match(entry, hwe)) {
|
||||
if (entry->hash != 0xffff)
|
||||
entry->hash = 0xffff;
|
||||
@@ -464,21 +630,50 @@ void __mtk_ppe_check_skb(struct mtk_ppe
|
||||
__mtk_foe_entry_commit(ppe, &entry->data, hash);
|
||||
found = true;
|
||||
}
|
||||
+
|
||||
+ if (found)
|
||||
+ goto out;
|
||||
+
|
||||
+ eh = eth_hdr(skb);
|
||||
+ ether_addr_copy(key.dest_mac, eh->h_dest);
|
||||
+ ether_addr_copy(key.src_mac, eh->h_source);
|
||||
+ tag = skb->data - 2;
|
||||
+ key.vlan = 0;
|
||||
+ switch (skb->protocol) {
|
||||
+#if IS_ENABLED(CONFIG_NET_DSA)
|
||||
+ case htons(ETH_P_XDSA):
|
||||
+ if (!netdev_uses_dsa(skb->dev) ||
|
||||
+ skb->dev->dsa_ptr->tag_ops->proto != DSA_TAG_PROTO_MTK)
|
||||
+ goto out;
|
||||
+
|
||||
+ tag += 4;
|
||||
+ if (get_unaligned_be16(tag) != ETH_P_8021Q)
|
||||
+ break;
|
||||
+
|
||||
+ fallthrough;
|
||||
+#endif
|
||||
+ case htons(ETH_P_8021Q):
|
||||
+ key.vlan = get_unaligned_be16(tag + 2) & VLAN_VID_MASK;
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ entry = rhashtable_lookup_fast(&ppe->l2_flows, &key, mtk_flow_l2_ht_params);
|
||||
+ if (!entry)
|
||||
+ goto out;
|
||||
+
|
||||
+ mtk_foe_entry_commit_subflow(ppe, entry, hash);
|
||||
+
|
||||
+out:
|
||||
spin_unlock_bh(&ppe_lock);
|
||||
}
|
||||
|
||||
int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
{
|
||||
- u16 now = mtk_eth_timestamp(ppe->eth) & MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
- u16 timestamp;
|
||||
-
|
||||
mtk_flow_entry_update(ppe, entry);
|
||||
- timestamp = entry->data.ib1 & MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
|
||||
- if (timestamp > now)
|
||||
- return MTK_FOE_IB1_BIND_TIMESTAMP + 1 - timestamp + now;
|
||||
- else
|
||||
- return now - timestamp;
|
||||
+ return __mtk_foe_entry_idle_time(ppe, entry->data.ib1);
|
||||
}
|
||||
|
||||
struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
|
||||
@@ -492,6 +687,8 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_
|
||||
if (!ppe)
|
||||
return NULL;
|
||||
|
||||
+ rhashtable_init(&ppe->l2_flows, &mtk_flow_l2_ht_params);
|
||||
+
|
||||
/* need to allocate a separate device, since it PPE DMA access is
|
||||
* not coherent.
|
||||
*/
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/bitfield.h>
|
||||
+#include <linux/rhashtable.h>
|
||||
|
||||
#define MTK_ETH_PPE_BASE 0xc00
|
||||
|
||||
@@ -84,19 +85,16 @@ struct mtk_foe_mac_info {
|
||||
u16 src_mac_lo;
|
||||
};
|
||||
|
||||
+/* software-only entry type */
|
||||
struct mtk_foe_bridge {
|
||||
- u32 dest_mac_hi;
|
||||
-
|
||||
- u16 src_mac_lo;
|
||||
- u16 dest_mac_lo;
|
||||
+ u8 dest_mac[ETH_ALEN];
|
||||
+ u8 src_mac[ETH_ALEN];
|
||||
+ u16 vlan;
|
||||
|
||||
- u32 src_mac_hi;
|
||||
+ struct {} key_end;
|
||||
|
||||
u32 ib2;
|
||||
|
||||
- u32 _rsv[5];
|
||||
-
|
||||
- u32 udf_tsid;
|
||||
struct mtk_foe_mac_info l2;
|
||||
};
|
||||
|
||||
@@ -235,13 +233,33 @@ enum {
|
||||
MTK_PPE_CPU_REASON_INVALID = 0x1f,
|
||||
};
|
||||
|
||||
+enum {
|
||||
+ MTK_FLOW_TYPE_L4,
|
||||
+ MTK_FLOW_TYPE_L2,
|
||||
+ MTK_FLOW_TYPE_L2_SUBFLOW,
|
||||
+};
|
||||
+
|
||||
struct mtk_flow_entry {
|
||||
+ union {
|
||||
+ struct hlist_node list;
|
||||
+ struct {
|
||||
+ struct rhash_head l2_node;
|
||||
+ struct hlist_head l2_flows;
|
||||
+ };
|
||||
+ };
|
||||
+ u8 type;
|
||||
+ s8 wed_index;
|
||||
+ u16 hash;
|
||||
+ union {
|
||||
+ struct mtk_foe_entry data;
|
||||
+ struct {
|
||||
+ struct mtk_flow_entry *base_flow;
|
||||
+ struct hlist_node list;
|
||||
+ struct {} end;
|
||||
+ } l2_data;
|
||||
+ };
|
||||
struct rhash_head node;
|
||||
- struct hlist_node list;
|
||||
unsigned long cookie;
|
||||
- struct mtk_foe_entry data;
|
||||
- u16 hash;
|
||||
- s8 wed_index;
|
||||
};
|
||||
|
||||
struct mtk_ppe {
|
||||
@@ -256,6 +274,8 @@ struct mtk_ppe {
|
||||
u16 foe_check_time[MTK_PPE_ENTRIES];
|
||||
struct hlist_head foe_flow[MTK_PPE_ENTRIES / 2];
|
||||
|
||||
+ struct rhashtable l2_flows;
|
||||
+
|
||||
void *acct_table;
|
||||
};
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
@@ -31,6 +31,8 @@ struct mtk_flow_data {
|
||||
__be16 src_port;
|
||||
__be16 dst_port;
|
||||
|
||||
+ u16 vlan_in;
|
||||
+
|
||||
struct {
|
||||
u16 id;
|
||||
__be16 proto;
|
||||
@@ -260,9 +262,45 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
+ switch (addr_type) {
|
||||
+ case 0:
|
||||
+ offload_type = MTK_PPE_PKT_TYPE_BRIDGE;
|
||||
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
|
||||
+ struct flow_match_eth_addrs match;
|
||||
+
|
||||
+ flow_rule_match_eth_addrs(rule, &match);
|
||||
+ memcpy(data.eth.h_dest, match.key->dst, ETH_ALEN);
|
||||
+ memcpy(data.eth.h_source, match.key->src, ETH_ALEN);
|
||||
+ } else {
|
||||
+ return -EOPNOTSUPP;
|
||||
+ }
|
||||
+
|
||||
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
|
||||
+ struct flow_match_vlan match;
|
||||
+
|
||||
+ flow_rule_match_vlan(rule, &match);
|
||||
+
|
||||
+ if (match.key->vlan_tpid != cpu_to_be16(ETH_P_8021Q))
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
+ data.vlan_in = match.key->vlan_id;
|
||||
+ }
|
||||
+ break;
|
||||
+ case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
|
||||
+ offload_type = MTK_PPE_PKT_TYPE_IPV4_HNAPT;
|
||||
+ break;
|
||||
+ case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
|
||||
+ offload_type = MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EOPNOTSUPP;
|
||||
+ }
|
||||
+
|
||||
flow_action_for_each(i, act, &rule->action) {
|
||||
switch (act->id) {
|
||||
case FLOW_ACTION_MANGLE:
|
||||
+ if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE)
|
||||
+ return -EOPNOTSUPP;
|
||||
if (act->mangle.htype == FLOW_ACT_MANGLE_HDR_TYPE_ETH)
|
||||
mtk_flow_offload_mangle_eth(act, &data.eth);
|
||||
break;
|
||||
@@ -294,17 +332,6 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
}
|
||||
}
|
||||
|
||||
- switch (addr_type) {
|
||||
- case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
|
||||
- offload_type = MTK_PPE_PKT_TYPE_IPV4_HNAPT;
|
||||
- break;
|
||||
- case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
|
||||
- offload_type = MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T;
|
||||
- break;
|
||||
- default:
|
||||
- return -EOPNOTSUPP;
|
||||
- }
|
||||
-
|
||||
if (!is_valid_ether_addr(data.eth.h_source) ||
|
||||
!is_valid_ether_addr(data.eth.h_dest))
|
||||
return -EINVAL;
|
||||
@@ -318,10 +345,13 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
|
||||
struct flow_match_ports ports;
|
||||
|
||||
+ if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE)
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
flow_rule_match_ports(rule, &ports);
|
||||
data.src_port = ports.key->src;
|
||||
data.dst_port = ports.key->dst;
|
||||
- } else {
|
||||
+ } else if (offload_type != MTK_PPE_PKT_TYPE_BRIDGE) {
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
@@ -351,6 +381,9 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
if (act->id != FLOW_ACTION_MANGLE)
|
||||
continue;
|
||||
|
||||
+ if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE)
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
switch (act->mangle.htype) {
|
||||
case FLOW_ACT_MANGLE_HDR_TYPE_TCP:
|
||||
case FLOW_ACT_MANGLE_HDR_TYPE_UDP:
|
||||
@@ -376,6 +409,9 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
return err;
|
||||
}
|
||||
|
||||
+ if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE)
|
||||
+ foe.bridge.vlan = data.vlan_in;
|
||||
+
|
||||
if (data.vlan.num == 1) {
|
||||
if (data.vlan.proto != htons(ETH_P_8021Q))
|
||||
return -EOPNOTSUPP;
|
@ -0,0 +1,41 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 21 Mar 2022 20:39:59 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: enable threaded NAPI
|
||||
|
||||
This can improve performance under load by ensuring that NAPI processing is
|
||||
not pinned on CPU 0.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -2186,8 +2186,8 @@ static irqreturn_t mtk_handle_irq_rx(int
|
||||
|
||||
eth->rx_events++;
|
||||
if (likely(napi_schedule_prep(ð->rx_napi))) {
|
||||
- __napi_schedule(ð->rx_napi);
|
||||
mtk_rx_irq_disable(eth, MTK_RX_DONE_INT);
|
||||
+ __napi_schedule(ð->rx_napi);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
@@ -2199,8 +2199,8 @@ static irqreturn_t mtk_handle_irq_tx(int
|
||||
|
||||
eth->tx_events++;
|
||||
if (likely(napi_schedule_prep(ð->tx_napi))) {
|
||||
- __napi_schedule(ð->tx_napi);
|
||||
mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
|
||||
+ __napi_schedule(ð->tx_napi);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
@@ -3313,6 +3313,8 @@ static int mtk_probe(struct platform_dev
|
||||
* for NAPI to work
|
||||
*/
|
||||
init_dummy_netdev(ð->dummy_dev);
|
||||
+ eth->dummy_dev.threaded = 1;
|
||||
+ strcpy(eth->dummy_dev.name, "mtk_eth");
|
||||
netif_napi_add(ð->dummy_dev, ð->tx_napi, mtk_napi_tx,
|
||||
MTK_NAPI_WEIGHT);
|
||||
netif_napi_add(ð->dummy_dev, ð->rx_napi, mtk_napi_rx,
|
@ -0,0 +1,222 @@
|
||||
From fc23ea48ba52c24f201fe5ca0132ee1a3de5a70a Mon Sep 17 00:00:00 2001
|
||||
From: Mauri Sandberg <maukka@ext.kapsi.fi>
|
||||
Date: Thu, 25 Mar 2021 11:48:05 +0200
|
||||
Subject: [PATCH 2/2] gpio: gpio-cascade: add generic GPIO cascade
|
||||
|
||||
Adds support for building cascades of GPIO lines. That is, it allows
|
||||
setups when there is one upstream line and multiple cascaded lines, out
|
||||
of which one can be chosen at a time. The status of the upstream line
|
||||
can be conveyed to the selected cascaded line or, vice versa, the status
|
||||
of the cascaded line can be conveyed to the upstream line.
|
||||
|
||||
A multiplexer is being used to select, which cascaded GPIO line is being
|
||||
used at any given time.
|
||||
|
||||
At the moment only input direction is supported. In future it should be
|
||||
possible to add support for output direction, too.
|
||||
|
||||
Signed-off-by: Mauri Sandberg <maukka@ext.kapsi.fi>
|
||||
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
|
||||
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
|
||||
---
|
||||
v7 -> v8:
|
||||
- rearrange members in struct gpio_cascade
|
||||
- cosmetic changes in file header and in one function declaration
|
||||
- added Reviewed-by tags by Linus and Andy
|
||||
v6 -> v7:
|
||||
- In Kconfig add info about module name
|
||||
- adhere to new convention that allows lines longer than 80 chars
|
||||
- use dev_probe_err with upstream gpio line too
|
||||
- refactor for cleaner exit of probe function.
|
||||
v5 -> v6:
|
||||
- In Kconfig, remove dependency to OF_GPIO and select only MULTIPLEXER
|
||||
- refactor code preferring one-liners
|
||||
- clean up prints, removing them from success-path.
|
||||
- don't explicitly set gpio_chip.of_node as it's done in the GPIO library
|
||||
- use devm_gpiochip_add_data instead of gpiochip_add
|
||||
v4 -> v5:
|
||||
- renamed gpio-mux-input -> gpio-cascade. refactored code accordingly
|
||||
here and there and changed to use new bindings and compatible string
|
||||
- ambigious and vague 'pin' was rename to 'upstream_line'
|
||||
- dropped Tested-by and Reviewed-by due to changes in bindings
|
||||
- dropped Reported-by suggested by an automatic bot as it was not really
|
||||
appropriate to begin with
|
||||
- functionally it's the same as v4
|
||||
v3 -> v4:
|
||||
- Changed author email
|
||||
- Included Tested-by and Reviewed-by from Drew
|
||||
v2 -> v3:
|
||||
- use managed device resources
|
||||
- update Kconfig description
|
||||
v1 -> v2:
|
||||
- removed .owner from platform_driver as per test bot's instruction
|
||||
- added MODULE_AUTHOR, MODULE_DESCRIPTION, MODULE_LICENSE
|
||||
- added gpio_mux_input_get_direction as it's recommended for all chips
|
||||
- removed because this is input only chip: gpio_mux_input_set_value
|
||||
- removed because they are not needed for input/output only chips:
|
||||
gpio_mux_input_direction_input
|
||||
gpio_mux_input_direction_output
|
||||
- fixed typo in an error message
|
||||
- added info message about successful registration
|
||||
- removed can_sleep flag as this does not sleep while getting GPIO value
|
||||
like I2C or SPI do
|
||||
- Updated description in Kconfig
|
||||
---
|
||||
drivers/gpio/Kconfig | 15 +++++
|
||||
drivers/gpio/Makefile | 1 +
|
||||
drivers/gpio/gpio-cascade.c | 117 ++++++++++++++++++++++++++++++++++++
|
||||
3 files changed, 133 insertions(+)
|
||||
create mode 100644 drivers/gpio/gpio-cascade.c
|
||||
|
||||
--- a/drivers/gpio/Kconfig
|
||||
+++ b/drivers/gpio/Kconfig
|
||||
@@ -1683,4 +1683,19 @@ config GPIO_VIRTIO
|
||||
|
||||
endmenu
|
||||
|
||||
+comment "Other GPIO expanders"
|
||||
+
|
||||
+config GPIO_CASCADE
|
||||
+ tristate "General GPIO cascade"
|
||||
+ select MULTIPLEXER
|
||||
+ help
|
||||
+ Say yes here to enable support for generic GPIO cascade.
|
||||
+
|
||||
+ This allows building one-to-many cascades of GPIO lines using
|
||||
+ different types of multiplexers readily available. At the
|
||||
+ moment only input lines are supported.
|
||||
+
|
||||
+ To build the driver as a module choose 'm' and the resulting module
|
||||
+ will be called 'gpio-cascade'.
|
||||
+
|
||||
endif
|
||||
--- a/drivers/gpio/Makefile
|
||||
+++ b/drivers/gpio/Makefile
|
||||
@@ -45,6 +45,7 @@ obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd
|
||||
obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o
|
||||
obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
|
||||
obj-$(CONFIG_GPIO_CADENCE) += gpio-cadence.o
|
||||
+obj-$(CONFIG_GPIO_CASCADE) += gpio-cascade.o
|
||||
obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
|
||||
obj-$(CONFIG_GPIO_SNPS_CREG) += gpio-creg-snps.o
|
||||
obj-$(CONFIG_GPIO_CRYSTAL_COVE) += gpio-crystalcove.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/gpio/gpio-cascade.c
|
||||
@@ -0,0 +1,117 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-only
|
||||
+/*
|
||||
+ * A generic GPIO cascade driver
|
||||
+ *
|
||||
+ * Copyright (C) 2021 Mauri Sandberg <maukka@ext.kapsi.fi>
|
||||
+ *
|
||||
+ * This allows building cascades of GPIO lines in a manner illustrated
|
||||
+ * below:
|
||||
+ *
|
||||
+ * /|---- Cascaded GPIO line 0
|
||||
+ * Upstream | |---- Cascaded GPIO line 1
|
||||
+ * GPIO line ----+ | .
|
||||
+ * | | .
|
||||
+ * \|---- Cascaded GPIO line n
|
||||
+ *
|
||||
+ * A multiplexer is being used to select, which cascaded line is being
|
||||
+ * addressed at any given time.
|
||||
+ *
|
||||
+ * At the moment only input mode is supported due to lack of means for
|
||||
+ * testing output functionality. At least theoretically output should be
|
||||
+ * possible with open drain constructions.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/mux/consumer.h>
|
||||
+
|
||||
+#include <linux/gpio/consumer.h>
|
||||
+#include <linux/gpio/driver.h>
|
||||
+
|
||||
+struct gpio_cascade {
|
||||
+ struct gpio_chip gpio_chip;
|
||||
+ struct device *parent;
|
||||
+ struct mux_control *mux_control;
|
||||
+ struct gpio_desc *upstream_line;
|
||||
+};
|
||||
+
|
||||
+static struct gpio_cascade *chip_to_cascade(struct gpio_chip *gc)
|
||||
+{
|
||||
+ return container_of(gc, struct gpio_cascade, gpio_chip);
|
||||
+}
|
||||
+
|
||||
+static int gpio_cascade_get_direction(struct gpio_chip *gc, unsigned int offset)
|
||||
+{
|
||||
+ return GPIO_LINE_DIRECTION_IN;
|
||||
+}
|
||||
+
|
||||
+static int gpio_cascade_get_value(struct gpio_chip *gc, unsigned int offset)
|
||||
+{
|
||||
+ struct gpio_cascade *cas = chip_to_cascade(gc);
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = mux_control_select(cas->mux_control, offset);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = gpiod_get_value(cas->upstream_line);
|
||||
+ mux_control_deselect(cas->mux_control);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int gpio_cascade_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct gpio_cascade *cas;
|
||||
+ struct mux_control *mc;
|
||||
+ struct gpio_desc *upstream;
|
||||
+ struct gpio_chip *gc;
|
||||
+
|
||||
+ cas = devm_kzalloc(dev, sizeof(*cas), GFP_KERNEL);
|
||||
+ if (!cas)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ mc = devm_mux_control_get(dev, NULL);
|
||||
+ if (IS_ERR(mc))
|
||||
+ return dev_err_probe(dev, PTR_ERR(mc), "unable to get mux-control\n");
|
||||
+
|
||||
+ cas->mux_control = mc;
|
||||
+ upstream = devm_gpiod_get(dev, "upstream", GPIOD_IN);
|
||||
+ if (IS_ERR(upstream))
|
||||
+ return dev_err_probe(dev, PTR_ERR(upstream), "unable to claim upstream GPIO line\n");
|
||||
+
|
||||
+ cas->upstream_line = upstream;
|
||||
+ cas->parent = dev;
|
||||
+
|
||||
+ gc = &cas->gpio_chip;
|
||||
+ gc->get = gpio_cascade_get_value;
|
||||
+ gc->get_direction = gpio_cascade_get_direction;
|
||||
+ gc->base = -1;
|
||||
+ gc->ngpio = mux_control_states(mc);
|
||||
+ gc->label = dev_name(cas->parent);
|
||||
+ gc->parent = cas->parent;
|
||||
+ gc->owner = THIS_MODULE;
|
||||
+
|
||||
+ platform_set_drvdata(pdev, cas);
|
||||
+ return devm_gpiochip_add_data(dev, &cas->gpio_chip, NULL);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id gpio_cascade_id[] = {
|
||||
+ { .compatible = "gpio-cascade" },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, gpio_cascade_id);
|
||||
+
|
||||
+static struct platform_driver gpio_cascade_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "gpio-cascade",
|
||||
+ .of_match_table = gpio_cascade_id,
|
||||
+ },
|
||||
+ .probe = gpio_cascade_probe,
|
||||
+};
|
||||
+module_platform_driver(gpio_cascade_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Mauri Sandberg <maukka@ext.kapsi.fi>");
|
||||
+MODULE_DESCRIPTION("Generic GPIO cascade");
|
||||
+MODULE_LICENSE("GPL");
|
@ -0,0 +1,59 @@
|
||||
From 078c6a1cbd4cd7496048786beec2e312577bebbf Mon Sep 17 00:00:00 2001
|
||||
From: Pawel Dembicki <paweldembicki@gmail.com>
|
||||
Date: Tue, 11 Jan 2022 23:11:32 +0100
|
||||
Subject: [PATCH] net: qmi_wwan: add ZTE MF286D modem 19d2:1485
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Modem from ZTE MF286D is an Qualcomm MDM9250 based 3G/4G modem.
|
||||
|
||||
T: Bus=02 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 3 Spd=5000 MxCh= 0
|
||||
D: Ver= 3.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 9 #Cfgs= 1
|
||||
P: Vendor=19d2 ProdID=1485 Rev=52.87
|
||||
S: Manufacturer=ZTE,Incorporated
|
||||
S: Product=ZTE Technologies MSM
|
||||
S: SerialNumber=MF286DZTED000000
|
||||
C:* #Ifs= 7 Cfg#= 1 Atr=80 MxPwr=896mA
|
||||
A: FirstIf#= 0 IfCount= 2 Cls=02(comm.) Sub=06 Prot=00
|
||||
I:* If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=ff Driver=rndis_host
|
||||
E: Ad=82(I) Atr=03(Int.) MxPS= 8 Ivl=32ms
|
||||
I:* If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=rndis_host
|
||||
E: Ad=81(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms
|
||||
E: Ad=01(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms
|
||||
I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option
|
||||
E: Ad=83(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms
|
||||
E: Ad=02(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms
|
||||
I:* If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option
|
||||
E: Ad=85(I) Atr=03(Int.) MxPS= 10 Ivl=32ms
|
||||
E: Ad=84(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms
|
||||
E: Ad=03(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms
|
||||
I:* If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option
|
||||
E: Ad=87(I) Atr=03(Int.) MxPS= 10 Ivl=32ms
|
||||
E: Ad=86(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms
|
||||
E: Ad=04(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms
|
||||
I:* If#= 5 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=qmi_wwan
|
||||
E: Ad=88(I) Atr=03(Int.) MxPS= 8 Ivl=32ms
|
||||
E: Ad=8e(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms
|
||||
E: Ad=0f(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms
|
||||
I:* If#= 6 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=usbfs
|
||||
E: Ad=05(O) Atr=02(Bulk) MxPS=1024 Ivl=0ms
|
||||
E: Ad=89(I) Atr=02(Bulk) MxPS=1024 Ivl=0ms
|
||||
|
||||
Signed-off-by: Pawel Dembicki <paweldembicki@gmail.com>
|
||||
Acked-by: Bjørn Mork <bjorn@mork.no>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/usb/qmi_wwan.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/net/usb/qmi_wwan.c
|
||||
+++ b/drivers/net/usb/qmi_wwan.c
|
||||
@@ -1313,6 +1313,7 @@ static const struct usb_device_id produc
|
||||
{QMI_FIXED_INTF(0x19d2, 0x1426, 2)}, /* ZTE MF91 */
|
||||
{QMI_FIXED_INTF(0x19d2, 0x1428, 2)}, /* Telewell TW-LTE 4G v2 */
|
||||
{QMI_FIXED_INTF(0x19d2, 0x1432, 3)}, /* ZTE ME3620 */
|
||||
+ {QMI_FIXED_INTF(0x19d2, 0x1485, 5)}, /* ZTE MF286D */
|
||||
{QMI_FIXED_INTF(0x19d2, 0x2002, 4)}, /* ZTE (Vodafone) K3765-Z */
|
||||
{QMI_FIXED_INTF(0x2001, 0x7e16, 3)}, /* D-Link DWM-221 */
|
||||
{QMI_FIXED_INTF(0x2001, 0x7e19, 4)}, /* D-Link DWM-221 B1 */
|
@ -0,0 +1,40 @@
|
||||
From 43f3f187e6f62ca40802afe39495c8a3e20b4bfa Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Mon, 10 Jan 2022 01:50:50 +0100
|
||||
Subject: [PATCH] PCI: aardvark: Replace custom PCIE_CORE_INT_* macros with
|
||||
PCI_INTERRUPT_*
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Header file linux/pci.h defines enum pci_interrupt_pin with corresponding
|
||||
PCI_INTERRUPT_* values.
|
||||
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 6 +-----
|
||||
1 file changed, 1 insertion(+), 5 deletions(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -38,10 +38,6 @@
|
||||
#define PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN BIT(6)
|
||||
#define PCIE_CORE_ERR_CAPCTL_ECRC_CHCK BIT(7)
|
||||
#define PCIE_CORE_ERR_CAPCTL_ECRC_CHCK_RCV BIT(8)
|
||||
-#define PCIE_CORE_INT_A_ASSERT_ENABLE 1
|
||||
-#define PCIE_CORE_INT_B_ASSERT_ENABLE 2
|
||||
-#define PCIE_CORE_INT_C_ASSERT_ENABLE 3
|
||||
-#define PCIE_CORE_INT_D_ASSERT_ENABLE 4
|
||||
/* PIO registers base address and register offsets */
|
||||
#define PIO_BASE_ADDR 0x4000
|
||||
#define PIO_CTRL (PIO_BASE_ADDR + 0x0)
|
||||
@@ -959,7 +955,7 @@ static int advk_sw_pci_bridge_init(struc
|
||||
bridge->conf.pref_mem_limit = cpu_to_le16(PCI_PREF_RANGE_TYPE_64);
|
||||
|
||||
/* Support interrupt A for MSI feature */
|
||||
- bridge->conf.intpin = PCIE_CORE_INT_A_ASSERT_ENABLE;
|
||||
+ bridge->conf.intpin = PCI_INTERRUPT_INTA;
|
||||
|
||||
/* Aardvark HW provides PCIe Capability structure in version 2 */
|
||||
bridge->pcie_conf.cap = cpu_to_le16(2);
|
@ -0,0 +1,57 @@
|
||||
From a29a7d01cd778854e08108461cba321a63d98871 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Fri, 2 Jul 2021 16:39:47 +0200
|
||||
Subject: [PATCH] PCI: aardvark: Fix reading MSI interrupt number
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
In advk_pcie_handle_msi() the authors expect that when bit i in the W1C
|
||||
register PCIE_MSI_STATUS_REG is cleared, the PCIE_MSI_PAYLOAD_REG is
|
||||
updated to contain the MSI number corresponding to index i.
|
||||
|
||||
Experiments show that this is not so, and instead PCIE_MSI_PAYLOAD_REG
|
||||
always contains the number of the last received MSI, overall.
|
||||
|
||||
Do not read PCIE_MSI_PAYLOAD_REG register for determining MSI interrupt
|
||||
number. Since Aardvark already forbids more than 32 interrupts and uses
|
||||
own allocated hwirq numbers, the msi_idx already corresponds to the
|
||||
received MSI number.
|
||||
|
||||
Fixes: 8c39d710363c ("PCI: aardvark: Add Aardvark PCI host controller driver")
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 13 ++++++-------
|
||||
1 file changed, 6 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -1386,7 +1386,7 @@ static void advk_pcie_remove_irq_domain(
|
||||
static void advk_pcie_handle_msi(struct advk_pcie *pcie)
|
||||
{
|
||||
u32 msi_val, msi_mask, msi_status, msi_idx;
|
||||
- u16 msi_data;
|
||||
+ int virq;
|
||||
|
||||
msi_mask = advk_readl(pcie, PCIE_MSI_MASK_REG);
|
||||
msi_val = advk_readl(pcie, PCIE_MSI_STATUS_REG);
|
||||
@@ -1396,13 +1396,12 @@ static void advk_pcie_handle_msi(struct
|
||||
if (!(BIT(msi_idx) & msi_status))
|
||||
continue;
|
||||
|
||||
- /*
|
||||
- * msi_idx contains bits [4:0] of the msi_data and msi_data
|
||||
- * contains 16bit MSI interrupt number
|
||||
- */
|
||||
advk_writel(pcie, BIT(msi_idx), PCIE_MSI_STATUS_REG);
|
||||
- msi_data = advk_readl(pcie, PCIE_MSI_PAYLOAD_REG) & PCIE_MSI_DATA_MASK;
|
||||
- generic_handle_irq(msi_data);
|
||||
+ virq = irq_find_mapping(pcie->msi_inner_domain, msi_idx);
|
||||
+ if (virq)
|
||||
+ generic_handle_irq(virq);
|
||||
+ else
|
||||
+ dev_err_ratelimited(&pcie->pdev->dev, "unexpected MSI 0x%02x\n", msi_idx);
|
||||
}
|
||||
|
||||
advk_writel(pcie, PCIE_ISR0_MSI_INT_PENDING,
|
@ -0,0 +1,72 @@
|
||||
From bb03b126ea6c9e57177b537dd022246fa5dbef16 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Fri, 12 Feb 2021 16:24:07 +0100
|
||||
Subject: [PATCH] PCI: aardvark: Fix support for MSI interrupts
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Aardvark hardware supports Multi-MSI and MSI_FLAG_MULTI_PCI_MSI is already
|
||||
set for the MSI chip. But when allocating MSI interrupt numbers for
|
||||
Multi-MSI, the numbers need to be properly aligned, otherwise endpoint
|
||||
devices send MSI interrupt with incorrect numbers.
|
||||
|
||||
Fix this issue by using function bitmap_find_free_region() instead of
|
||||
bitmap_find_next_zero_area().
|
||||
|
||||
To ensure that aligned MSI interrupt numbers are used by endpoint devices,
|
||||
we cannot use Linux virtual irq numbers (as they are random and not
|
||||
properly aligned). Instead we need to use the aligned hwirq numbers.
|
||||
|
||||
This change fixes receiving MSI interrupts on Armada 3720 boards and
|
||||
allows using NVMe disks which use Multi-MSI feature with 3 interrupts.
|
||||
|
||||
Without this NVMe disks freeze booting as linux nvme-core.c is waiting
|
||||
60s for an interrupt.
|
||||
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 16 ++++++----------
|
||||
1 file changed, 6 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -1182,7 +1182,7 @@ static void advk_msi_irq_compose_msi_msg
|
||||
|
||||
msg->address_lo = lower_32_bits(msi_msg);
|
||||
msg->address_hi = upper_32_bits(msi_msg);
|
||||
- msg->data = data->irq;
|
||||
+ msg->data = data->hwirq;
|
||||
}
|
||||
|
||||
static int advk_msi_set_affinity(struct irq_data *irq_data,
|
||||
@@ -1199,15 +1199,11 @@ static int advk_msi_irq_domain_alloc(str
|
||||
int hwirq, i;
|
||||
|
||||
mutex_lock(&pcie->msi_used_lock);
|
||||
- hwirq = bitmap_find_next_zero_area(pcie->msi_used, MSI_IRQ_NUM,
|
||||
- 0, nr_irqs, 0);
|
||||
- if (hwirq >= MSI_IRQ_NUM) {
|
||||
- mutex_unlock(&pcie->msi_used_lock);
|
||||
- return -ENOSPC;
|
||||
- }
|
||||
-
|
||||
- bitmap_set(pcie->msi_used, hwirq, nr_irqs);
|
||||
+ hwirq = bitmap_find_free_region(pcie->msi_used, MSI_IRQ_NUM,
|
||||
+ order_base_2(nr_irqs));
|
||||
mutex_unlock(&pcie->msi_used_lock);
|
||||
+ if (hwirq < 0)
|
||||
+ return -ENOSPC;
|
||||
|
||||
for (i = 0; i < nr_irqs; i++)
|
||||
irq_domain_set_info(domain, virq + i, hwirq + i,
|
||||
@@ -1225,7 +1221,7 @@ static void advk_msi_irq_domain_free(str
|
||||
struct advk_pcie *pcie = domain->host_data;
|
||||
|
||||
mutex_lock(&pcie->msi_used_lock);
|
||||
- bitmap_clear(pcie->msi_used, d->hwirq, nr_irqs);
|
||||
+ bitmap_release_region(pcie->msi_used, d->hwirq, order_base_2(nr_irqs));
|
||||
mutex_unlock(&pcie->msi_used_lock);
|
||||
}
|
||||
|
@ -0,0 +1,125 @@
|
||||
From 0cd5141d1866afb23286fe90cd846441fe7aeb39 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Sat, 27 Mar 2021 14:44:11 +0100
|
||||
Subject: [PATCH] PCI: aardvark: Rewrite IRQ code to chained IRQ handler
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Rewrite the code to use irq_set_chained_handler_and_data() handler with
|
||||
chained_irq_enter() and chained_irq_exit() processing instead of using
|
||||
devm_request_irq().
|
||||
|
||||
advk_pcie_irq_handler() reads IRQ status bits and calls other functions
|
||||
based on which bits are set. These functions then read its own IRQ status
|
||||
bits and calls other aardvark functions based on these bits. Finally
|
||||
generic_handle_domain_irq() with translated linux IRQ numbers are called.
|
||||
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 48 +++++++++++++++------------
|
||||
1 file changed, 26 insertions(+), 22 deletions(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -268,6 +268,7 @@ struct advk_pcie {
|
||||
u32 actions;
|
||||
} wins[OB_WIN_COUNT];
|
||||
u8 wins_count;
|
||||
+ int irq;
|
||||
struct irq_domain *irq_domain;
|
||||
struct irq_chip irq_chip;
|
||||
raw_spinlock_t irq_lock;
|
||||
@@ -1434,21 +1435,26 @@ static void advk_pcie_handle_int(struct
|
||||
}
|
||||
}
|
||||
|
||||
-static irqreturn_t advk_pcie_irq_handler(int irq, void *arg)
|
||||
+static void advk_pcie_irq_handler(struct irq_desc *desc)
|
||||
{
|
||||
- struct advk_pcie *pcie = arg;
|
||||
- u32 status;
|
||||
+ struct advk_pcie *pcie = irq_desc_get_handler_data(desc);
|
||||
+ struct irq_chip *chip = irq_desc_get_chip(desc);
|
||||
+ u32 val, mask, status;
|
||||
|
||||
- status = advk_readl(pcie, HOST_CTRL_INT_STATUS_REG);
|
||||
- if (!(status & PCIE_IRQ_CORE_INT))
|
||||
- return IRQ_NONE;
|
||||
+ chained_irq_enter(chip, desc);
|
||||
|
||||
- advk_pcie_handle_int(pcie);
|
||||
+ val = advk_readl(pcie, HOST_CTRL_INT_STATUS_REG);
|
||||
+ mask = advk_readl(pcie, HOST_CTRL_INT_MASK_REG);
|
||||
+ status = val & ((~mask) & PCIE_IRQ_ALL_MASK);
|
||||
|
||||
- /* Clear interrupt */
|
||||
- advk_writel(pcie, PCIE_IRQ_CORE_INT, HOST_CTRL_INT_STATUS_REG);
|
||||
+ if (status & PCIE_IRQ_CORE_INT) {
|
||||
+ advk_pcie_handle_int(pcie);
|
||||
|
||||
- return IRQ_HANDLED;
|
||||
+ /* Clear interrupt */
|
||||
+ advk_writel(pcie, PCIE_IRQ_CORE_INT, HOST_CTRL_INT_STATUS_REG);
|
||||
+ }
|
||||
+
|
||||
+ chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
static void __maybe_unused advk_pcie_disable_phy(struct advk_pcie *pcie)
|
||||
@@ -1515,7 +1521,7 @@ static int advk_pcie_probe(struct platfo
|
||||
struct advk_pcie *pcie;
|
||||
struct pci_host_bridge *bridge;
|
||||
struct resource_entry *entry;
|
||||
- int ret, irq;
|
||||
+ int ret;
|
||||
|
||||
bridge = devm_pci_alloc_host_bridge(dev, sizeof(struct advk_pcie));
|
||||
if (!bridge)
|
||||
@@ -1601,17 +1607,9 @@ static int advk_pcie_probe(struct platfo
|
||||
if (IS_ERR(pcie->base))
|
||||
return PTR_ERR(pcie->base);
|
||||
|
||||
- irq = platform_get_irq(pdev, 0);
|
||||
- if (irq < 0)
|
||||
- return irq;
|
||||
-
|
||||
- ret = devm_request_irq(dev, irq, advk_pcie_irq_handler,
|
||||
- IRQF_SHARED | IRQF_NO_THREAD, "advk-pcie",
|
||||
- pcie);
|
||||
- if (ret) {
|
||||
- dev_err(dev, "Failed to register interrupt\n");
|
||||
- return ret;
|
||||
- }
|
||||
+ pcie->irq = platform_get_irq(pdev, 0);
|
||||
+ if (pcie->irq < 0)
|
||||
+ return pcie->irq;
|
||||
|
||||
pcie->reset_gpio = devm_gpiod_get_from_of_node(dev, dev->of_node,
|
||||
"reset-gpios", 0,
|
||||
@@ -1660,11 +1658,14 @@ static int advk_pcie_probe(struct platfo
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ irq_set_chained_handler_and_data(pcie->irq, advk_pcie_irq_handler, pcie);
|
||||
+
|
||||
bridge->sysdata = pcie;
|
||||
bridge->ops = &advk_pcie_ops;
|
||||
|
||||
ret = pci_host_probe(bridge);
|
||||
if (ret < 0) {
|
||||
+ irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
|
||||
advk_pcie_remove_msi_irq_domain(pcie);
|
||||
advk_pcie_remove_irq_domain(pcie);
|
||||
return ret;
|
||||
@@ -1712,6 +1713,9 @@ static int advk_pcie_remove(struct platf
|
||||
advk_writel(pcie, PCIE_ISR1_ALL_MASK, PCIE_ISR1_REG);
|
||||
advk_writel(pcie, PCIE_IRQ_ALL_MASK, HOST_CTRL_INT_STATUS_REG);
|
||||
|
||||
+ /* Remove IRQ handler */
|
||||
+ irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
|
||||
+
|
||||
/* Remove IRQ domains */
|
||||
advk_pcie_remove_msi_irq_domain(pcie);
|
||||
advk_pcie_remove_irq_domain(pcie);
|
@ -0,0 +1,31 @@
|
||||
From 69c1f2c6f45a556361fd8e8d2d4eb20e2c8d3d95 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Thu, 18 Mar 2021 17:04:32 +0100
|
||||
Subject: [PATCH] PCI: aardvark: Check return value of
|
||||
generic_handle_domain_irq() when processing INTx IRQ
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
It is possible that we receive spurious INTx interrupt. Check for the
|
||||
return value of generic_handle_domain_irq() when processing INTx IRQ.
|
||||
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -1431,7 +1431,9 @@ static void advk_pcie_handle_int(struct
|
||||
advk_writel(pcie, PCIE_ISR1_INTX_ASSERT(i),
|
||||
PCIE_ISR1_REG);
|
||||
|
||||
- generic_handle_domain_irq(pcie->irq_domain, i);
|
||||
+ if (generic_handle_domain_irq(pcie->irq_domain, i) == -EINVAL)
|
||||
+ dev_err_ratelimited(&pcie->pdev->dev, "unexpected INT%c IRQ\n",
|
||||
+ (char)i + 'A');
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,93 @@
|
||||
From 5eb36a6b9508da442aac80f4df23e3951bbfa7aa Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
|
||||
Date: Mon, 10 Jan 2022 00:03:41 +0100
|
||||
Subject: [PATCH] PCI: aardvark: Make MSI irq_chip structures static driver
|
||||
structures
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Marc Zyngier says [1] that we should use struct irq_chip as a global
|
||||
static struct in the driver. Even though the structure currently
|
||||
contains a dynamic member (parent_device), Marc says [2] that he plans
|
||||
to kill it and make the structure completely static.
|
||||
|
||||
Convert Aardvark's priv->msi_bottom_irq_chip and priv->msi_irq_chip to
|
||||
static driver structure.
|
||||
|
||||
[1] https://lore.kernel.org/linux-pci/877dbcvngf.wl-maz@kernel.org/
|
||||
[2] https://lore.kernel.org/linux-pci/874k6gvkhz.wl-maz@kernel.org/
|
||||
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 26 ++++++++++++--------------
|
||||
1 file changed, 12 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -274,8 +274,6 @@ struct advk_pcie {
|
||||
raw_spinlock_t irq_lock;
|
||||
struct irq_domain *msi_domain;
|
||||
struct irq_domain *msi_inner_domain;
|
||||
- struct irq_chip msi_bottom_irq_chip;
|
||||
- struct irq_chip msi_irq_chip;
|
||||
struct msi_domain_info msi_domain_info;
|
||||
DECLARE_BITMAP(msi_used, MSI_IRQ_NUM);
|
||||
struct mutex msi_used_lock;
|
||||
@@ -1192,6 +1190,12 @@ static int advk_msi_set_affinity(struct
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
+static struct irq_chip advk_msi_bottom_irq_chip = {
|
||||
+ .name = "MSI",
|
||||
+ .irq_compose_msi_msg = advk_msi_irq_compose_msi_msg,
|
||||
+ .irq_set_affinity = advk_msi_set_affinity,
|
||||
+};
|
||||
+
|
||||
static int advk_msi_irq_domain_alloc(struct irq_domain *domain,
|
||||
unsigned int virq,
|
||||
unsigned int nr_irqs, void *args)
|
||||
@@ -1208,7 +1212,7 @@ static int advk_msi_irq_domain_alloc(str
|
||||
|
||||
for (i = 0; i < nr_irqs; i++)
|
||||
irq_domain_set_info(domain, virq + i, hwirq + i,
|
||||
- &pcie->msi_bottom_irq_chip,
|
||||
+ &advk_msi_bottom_irq_chip,
|
||||
domain->host_data, handle_simple_irq,
|
||||
NULL, NULL);
|
||||
|
||||
@@ -1278,29 +1282,23 @@ static const struct irq_domain_ops advk_
|
||||
.xlate = irq_domain_xlate_onecell,
|
||||
};
|
||||
|
||||
+static struct irq_chip advk_msi_irq_chip = {
|
||||
+ .name = "advk-MSI",
|
||||
+};
|
||||
+
|
||||
static int advk_pcie_init_msi_irq_domain(struct advk_pcie *pcie)
|
||||
{
|
||||
struct device *dev = &pcie->pdev->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
- struct irq_chip *bottom_ic, *msi_ic;
|
||||
struct msi_domain_info *msi_di;
|
||||
phys_addr_t msi_msg_phys;
|
||||
|
||||
mutex_init(&pcie->msi_used_lock);
|
||||
|
||||
- bottom_ic = &pcie->msi_bottom_irq_chip;
|
||||
-
|
||||
- bottom_ic->name = "MSI";
|
||||
- bottom_ic->irq_compose_msi_msg = advk_msi_irq_compose_msi_msg;
|
||||
- bottom_ic->irq_set_affinity = advk_msi_set_affinity;
|
||||
-
|
||||
- msi_ic = &pcie->msi_irq_chip;
|
||||
- msi_ic->name = "advk-MSI";
|
||||
-
|
||||
msi_di = &pcie->msi_domain_info;
|
||||
msi_di->flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
MSI_FLAG_MULTI_PCI_MSI;
|
||||
- msi_di->chip = msi_ic;
|
||||
+ msi_di->chip = &advk_msi_irq_chip;
|
||||
|
||||
msi_msg_phys = virt_to_phys(&pcie->msi_msg);
|
||||
|
@ -0,0 +1,64 @@
|
||||
From c092ab8994f1f777054c0179a9deb40b87ee606f Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
|
||||
Date: Mon, 10 Jan 2022 00:10:46 +0100
|
||||
Subject: [PATCH] PCI: aardvark: Make msi_domain_info structure a static driver
|
||||
structure
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Make Aardvark's msi_domain_info structure into a private driver structure.
|
||||
Domain info is same for every potential instatination of a controller.
|
||||
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 16 ++++++++--------
|
||||
1 file changed, 8 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -274,7 +274,6 @@ struct advk_pcie {
|
||||
raw_spinlock_t irq_lock;
|
||||
struct irq_domain *msi_domain;
|
||||
struct irq_domain *msi_inner_domain;
|
||||
- struct msi_domain_info msi_domain_info;
|
||||
DECLARE_BITMAP(msi_used, MSI_IRQ_NUM);
|
||||
struct mutex msi_used_lock;
|
||||
u16 msi_msg;
|
||||
@@ -1286,20 +1285,20 @@ static struct irq_chip advk_msi_irq_chip
|
||||
.name = "advk-MSI",
|
||||
};
|
||||
|
||||
+static struct msi_domain_info advk_msi_domain_info = {
|
||||
+ .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
+ MSI_FLAG_MULTI_PCI_MSI,
|
||||
+ .chip = &advk_msi_irq_chip,
|
||||
+};
|
||||
+
|
||||
static int advk_pcie_init_msi_irq_domain(struct advk_pcie *pcie)
|
||||
{
|
||||
struct device *dev = &pcie->pdev->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
- struct msi_domain_info *msi_di;
|
||||
phys_addr_t msi_msg_phys;
|
||||
|
||||
mutex_init(&pcie->msi_used_lock);
|
||||
|
||||
- msi_di = &pcie->msi_domain_info;
|
||||
- msi_di->flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
- MSI_FLAG_MULTI_PCI_MSI;
|
||||
- msi_di->chip = &advk_msi_irq_chip;
|
||||
-
|
||||
msi_msg_phys = virt_to_phys(&pcie->msi_msg);
|
||||
|
||||
advk_writel(pcie, lower_32_bits(msi_msg_phys),
|
||||
@@ -1315,7 +1314,8 @@ static int advk_pcie_init_msi_irq_domain
|
||||
|
||||
pcie->msi_domain =
|
||||
pci_msi_create_irq_domain(of_node_to_fwnode(node),
|
||||
- msi_di, pcie->msi_inner_domain);
|
||||
+ &advk_msi_domain_info,
|
||||
+ pcie->msi_inner_domain);
|
||||
if (!pcie->msi_domain) {
|
||||
irq_domain_remove(pcie->msi_inner_domain);
|
||||
return -ENOMEM;
|
@ -0,0 +1,40 @@
|
||||
From 59029739d42b439628e2f64f3d8f2db9be97deff Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
|
||||
Date: Mon, 10 Jan 2022 00:15:17 +0100
|
||||
Subject: [PATCH] PCI: aardvark: Use dev_fwnode() instead of
|
||||
of_node_to_fwnode(dev->of_node)
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Use simple
|
||||
dev_fwnode(dev)
|
||||
instead of
|
||||
struct device_node *node = dev->of_node;
|
||||
of_node_to_fwnode(node)
|
||||
especially since the node variable is not used elsewhere in the function.
|
||||
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 3 +--
|
||||
1 file changed, 1 insertion(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -1294,7 +1294,6 @@ static struct msi_domain_info advk_msi_d
|
||||
static int advk_pcie_init_msi_irq_domain(struct advk_pcie *pcie)
|
||||
{
|
||||
struct device *dev = &pcie->pdev->dev;
|
||||
- struct device_node *node = dev->of_node;
|
||||
phys_addr_t msi_msg_phys;
|
||||
|
||||
mutex_init(&pcie->msi_used_lock);
|
||||
@@ -1313,7 +1312,7 @@ static int advk_pcie_init_msi_irq_domain
|
||||
return -ENOMEM;
|
||||
|
||||
pcie->msi_domain =
|
||||
- pci_msi_create_irq_domain(of_node_to_fwnode(node),
|
||||
+ pci_msi_create_irq_domain(dev_fwnode(dev),
|
||||
&advk_msi_domain_info,
|
||||
pcie->msi_inner_domain);
|
||||
if (!pcie->msi_domain) {
|
@ -0,0 +1,44 @@
|
||||
From 98feaf97bc64fc640a6c5b1394cd18fc7cd7dac8 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Sun, 28 Mar 2021 14:34:49 +0200
|
||||
Subject: [PATCH] PCI: aardvark: Refactor unmasking summary MSI interrupt
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Refactor the masking of ISR0/1 Sources and unmasking of summary MSI interrupt
|
||||
so that it corresponds to the comments:
|
||||
- first mask all ISR0/1
|
||||
- then unmask all MSIs
|
||||
- then unmask summary MSI interrupt
|
||||
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 10 ++++++----
|
||||
1 file changed, 6 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -571,15 +571,17 @@ static void advk_pcie_setup_hw(struct ad
|
||||
advk_writel(pcie, PCIE_IRQ_ALL_MASK, HOST_CTRL_INT_STATUS_REG);
|
||||
|
||||
/* Disable All ISR0/1 Sources */
|
||||
- reg = PCIE_ISR0_ALL_MASK;
|
||||
- reg &= ~PCIE_ISR0_MSI_INT_PENDING;
|
||||
- advk_writel(pcie, reg, PCIE_ISR0_MASK_REG);
|
||||
-
|
||||
+ advk_writel(pcie, PCIE_ISR0_ALL_MASK, PCIE_ISR0_MASK_REG);
|
||||
advk_writel(pcie, PCIE_ISR1_ALL_MASK, PCIE_ISR1_MASK_REG);
|
||||
|
||||
/* Unmask all MSIs */
|
||||
advk_writel(pcie, ~(u32)PCIE_MSI_ALL_MASK, PCIE_MSI_MASK_REG);
|
||||
|
||||
+ /* Unmask summary MSI interrupt */
|
||||
+ reg = advk_readl(pcie, PCIE_ISR0_MASK_REG);
|
||||
+ reg &= ~PCIE_ISR0_MSI_INT_PENDING;
|
||||
+ advk_writel(pcie, reg, PCIE_ISR0_MASK_REG);
|
||||
+
|
||||
/* Enable summary interrupt for GIC SPI source */
|
||||
reg = PCIE_IRQ_ALL_MASK & (~PCIE_IRQ_ENABLE_INTS_MASK);
|
||||
advk_writel(pcie, reg, HOST_CTRL_INT_MASK_REG);
|
@ -0,0 +1,117 @@
|
||||
From 7f353accca6e4a3222991c65b1a6801503973bd3 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Fri, 2 Jul 2021 16:44:10 +0200
|
||||
Subject: [PATCH] PCI: aardvark: Add support for masking MSI interrupts
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
We should not unmask MSIs at setup, but only when kernel asks for them
|
||||
to be unmasked.
|
||||
|
||||
At setup, mask all MSIs, and implement IRQ chip callbacks for masking
|
||||
and unmasking particular MSIs.
|
||||
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 54 ++++++++++++++++++++++++---
|
||||
1 file changed, 49 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -274,6 +274,7 @@ struct advk_pcie {
|
||||
raw_spinlock_t irq_lock;
|
||||
struct irq_domain *msi_domain;
|
||||
struct irq_domain *msi_inner_domain;
|
||||
+ raw_spinlock_t msi_irq_lock;
|
||||
DECLARE_BITMAP(msi_used, MSI_IRQ_NUM);
|
||||
struct mutex msi_used_lock;
|
||||
u16 msi_msg;
|
||||
@@ -570,12 +571,10 @@ static void advk_pcie_setup_hw(struct ad
|
||||
advk_writel(pcie, PCIE_ISR1_ALL_MASK, PCIE_ISR1_REG);
|
||||
advk_writel(pcie, PCIE_IRQ_ALL_MASK, HOST_CTRL_INT_STATUS_REG);
|
||||
|
||||
- /* Disable All ISR0/1 Sources */
|
||||
+ /* Disable All ISR0/1 and MSI Sources */
|
||||
advk_writel(pcie, PCIE_ISR0_ALL_MASK, PCIE_ISR0_MASK_REG);
|
||||
advk_writel(pcie, PCIE_ISR1_ALL_MASK, PCIE_ISR1_MASK_REG);
|
||||
-
|
||||
- /* Unmask all MSIs */
|
||||
- advk_writel(pcie, ~(u32)PCIE_MSI_ALL_MASK, PCIE_MSI_MASK_REG);
|
||||
+ advk_writel(pcie, PCIE_MSI_ALL_MASK, PCIE_MSI_MASK_REG);
|
||||
|
||||
/* Unmask summary MSI interrupt */
|
||||
reg = advk_readl(pcie, PCIE_ISR0_MASK_REG);
|
||||
@@ -1191,10 +1190,52 @@ static int advk_msi_set_affinity(struct
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
+static void advk_msi_irq_mask(struct irq_data *d)
|
||||
+{
|
||||
+ struct advk_pcie *pcie = d->domain->host_data;
|
||||
+ irq_hw_number_t hwirq = irqd_to_hwirq(d);
|
||||
+ unsigned long flags;
|
||||
+ u32 mask;
|
||||
+
|
||||
+ raw_spin_lock_irqsave(&pcie->msi_irq_lock, flags);
|
||||
+ mask = advk_readl(pcie, PCIE_MSI_MASK_REG);
|
||||
+ mask |= BIT(hwirq);
|
||||
+ advk_writel(pcie, mask, PCIE_MSI_MASK_REG);
|
||||
+ raw_spin_unlock_irqrestore(&pcie->msi_irq_lock, flags);
|
||||
+}
|
||||
+
|
||||
+static void advk_msi_irq_unmask(struct irq_data *d)
|
||||
+{
|
||||
+ struct advk_pcie *pcie = d->domain->host_data;
|
||||
+ irq_hw_number_t hwirq = irqd_to_hwirq(d);
|
||||
+ unsigned long flags;
|
||||
+ u32 mask;
|
||||
+
|
||||
+ raw_spin_lock_irqsave(&pcie->msi_irq_lock, flags);
|
||||
+ mask = advk_readl(pcie, PCIE_MSI_MASK_REG);
|
||||
+ mask &= ~BIT(hwirq);
|
||||
+ advk_writel(pcie, mask, PCIE_MSI_MASK_REG);
|
||||
+ raw_spin_unlock_irqrestore(&pcie->msi_irq_lock, flags);
|
||||
+}
|
||||
+
|
||||
+static void advk_msi_top_irq_mask(struct irq_data *d)
|
||||
+{
|
||||
+ pci_msi_mask_irq(d);
|
||||
+ irq_chip_mask_parent(d);
|
||||
+}
|
||||
+
|
||||
+static void advk_msi_top_irq_unmask(struct irq_data *d)
|
||||
+{
|
||||
+ pci_msi_unmask_irq(d);
|
||||
+ irq_chip_unmask_parent(d);
|
||||
+}
|
||||
+
|
||||
static struct irq_chip advk_msi_bottom_irq_chip = {
|
||||
.name = "MSI",
|
||||
.irq_compose_msi_msg = advk_msi_irq_compose_msi_msg,
|
||||
.irq_set_affinity = advk_msi_set_affinity,
|
||||
+ .irq_mask = advk_msi_irq_mask,
|
||||
+ .irq_unmask = advk_msi_irq_unmask,
|
||||
};
|
||||
|
||||
static int advk_msi_irq_domain_alloc(struct irq_domain *domain,
|
||||
@@ -1284,7 +1325,9 @@ static const struct irq_domain_ops advk_
|
||||
};
|
||||
|
||||
static struct irq_chip advk_msi_irq_chip = {
|
||||
- .name = "advk-MSI",
|
||||
+ .name = "advk-MSI",
|
||||
+ .irq_mask = advk_msi_top_irq_mask,
|
||||
+ .irq_unmask = advk_msi_top_irq_unmask,
|
||||
};
|
||||
|
||||
static struct msi_domain_info advk_msi_domain_info = {
|
||||
@@ -1298,6 +1341,7 @@ static int advk_pcie_init_msi_irq_domain
|
||||
struct device *dev = &pcie->pdev->dev;
|
||||
phys_addr_t msi_msg_phys;
|
||||
|
||||
+ raw_spin_lock_init(&pcie->msi_irq_lock);
|
||||
mutex_init(&pcie->msi_used_lock);
|
||||
|
||||
msi_msg_phys = virt_to_phys(&pcie->msi_msg);
|
@ -0,0 +1,91 @@
|
||||
From fa73c200f181436eab859374657c53a73778d8ad Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Fri, 26 Mar 2021 17:35:44 +0100
|
||||
Subject: [PATCH] PCI: aardvark: Fix setting MSI address
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
MSI address for receiving MSI interrupts needs to be correctly set before
|
||||
enabling processing of MSI interrupts.
|
||||
|
||||
Move code for setting PCIE_MSI_ADDR_LOW_REG and PCIE_MSI_ADDR_HIGH_REG
|
||||
from advk_pcie_init_msi_irq_domain() to advk_pcie_setup_hw(), before
|
||||
enabling PCIE_CORE_CTRL2_MSI_ENABLE.
|
||||
|
||||
After this we can remove the now unused member msi_msg, which was used
|
||||
only for MSI doorbell address. MSI address can be any address which cannot
|
||||
be used to DMA to. So change it to the address of the main struct advk_pcie.
|
||||
|
||||
Fixes: 8c39d710363c ("PCI: aardvark: Add Aardvark PCI host controller driver")
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Acked-by: Marc Zyngier <maz@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
Cc: stable@vger.kernel.org # f21a8b1b6837 ("PCI: aardvark: Move to MSI handling using generic MSI support")
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 21 +++++++++------------
|
||||
1 file changed, 9 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -277,7 +277,6 @@ struct advk_pcie {
|
||||
raw_spinlock_t msi_irq_lock;
|
||||
DECLARE_BITMAP(msi_used, MSI_IRQ_NUM);
|
||||
struct mutex msi_used_lock;
|
||||
- u16 msi_msg;
|
||||
int link_gen;
|
||||
struct pci_bridge_emul bridge;
|
||||
struct gpio_desc *reset_gpio;
|
||||
@@ -472,6 +471,7 @@ static void advk_pcie_disable_ob_win(str
|
||||
|
||||
static void advk_pcie_setup_hw(struct advk_pcie *pcie)
|
||||
{
|
||||
+ phys_addr_t msi_addr;
|
||||
u32 reg;
|
||||
int i;
|
||||
|
||||
@@ -560,6 +560,11 @@ static void advk_pcie_setup_hw(struct ad
|
||||
reg |= LANE_COUNT_1;
|
||||
advk_writel(pcie, reg, PCIE_CORE_CTRL0_REG);
|
||||
|
||||
+ /* Set MSI address */
|
||||
+ msi_addr = virt_to_phys(pcie);
|
||||
+ advk_writel(pcie, lower_32_bits(msi_addr), PCIE_MSI_ADDR_LOW_REG);
|
||||
+ advk_writel(pcie, upper_32_bits(msi_addr), PCIE_MSI_ADDR_HIGH_REG);
|
||||
+
|
||||
/* Enable MSI */
|
||||
reg = advk_readl(pcie, PCIE_CORE_CTRL2_REG);
|
||||
reg |= PCIE_CORE_CTRL2_MSI_ENABLE;
|
||||
@@ -1177,10 +1182,10 @@ static void advk_msi_irq_compose_msi_msg
|
||||
struct msi_msg *msg)
|
||||
{
|
||||
struct advk_pcie *pcie = irq_data_get_irq_chip_data(data);
|
||||
- phys_addr_t msi_msg = virt_to_phys(&pcie->msi_msg);
|
||||
+ phys_addr_t msi_addr = virt_to_phys(pcie);
|
||||
|
||||
- msg->address_lo = lower_32_bits(msi_msg);
|
||||
- msg->address_hi = upper_32_bits(msi_msg);
|
||||
+ msg->address_lo = lower_32_bits(msi_addr);
|
||||
+ msg->address_hi = upper_32_bits(msi_addr);
|
||||
msg->data = data->hwirq;
|
||||
}
|
||||
|
||||
@@ -1339,18 +1344,10 @@ static struct msi_domain_info advk_msi_d
|
||||
static int advk_pcie_init_msi_irq_domain(struct advk_pcie *pcie)
|
||||
{
|
||||
struct device *dev = &pcie->pdev->dev;
|
||||
- phys_addr_t msi_msg_phys;
|
||||
|
||||
raw_spin_lock_init(&pcie->msi_irq_lock);
|
||||
mutex_init(&pcie->msi_used_lock);
|
||||
|
||||
- msi_msg_phys = virt_to_phys(&pcie->msi_msg);
|
||||
-
|
||||
- advk_writel(pcie, lower_32_bits(msi_msg_phys),
|
||||
- PCIE_MSI_ADDR_LOW_REG);
|
||||
- advk_writel(pcie, upper_32_bits(msi_msg_phys),
|
||||
- PCIE_MSI_ADDR_HIGH_REG);
|
||||
-
|
||||
pcie->msi_inner_domain =
|
||||
irq_domain_add_linear(NULL, MSI_IRQ_NUM,
|
||||
&advk_msi_domain_ops, pcie);
|
@ -0,0 +1,38 @@
|
||||
From 735a4ac9782b96fbe1543c578aa8334364f21abd Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Fri, 2 Apr 2021 14:05:24 +0200
|
||||
Subject: [PATCH] PCI: aardvark: Enable MSI-X support
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
According to PCI 3.0 specification, sending both MSI and MSI-X interrupts
|
||||
is done by DWORD memory write operation to doorbell message address. The
|
||||
write operation for MSI has zero upper 16 bits and the MSI interrupt number
|
||||
in the lower 16 bits, while the write operation for MSI-X contains a 32-bit
|
||||
value from MSI-X table.
|
||||
|
||||
Since the driver only uses interrupt numbers from range 0..31, the upper
|
||||
16 bits of the DWORD memory write operation to doorbell message address
|
||||
are zero even for MSI-X interrupts. Thus we can enable MSI-X interrupts.
|
||||
|
||||
Testing proves that kernel can correctly receive MSI-X interrupts from PCIe
|
||||
cards which supports both MSI and MSI-X interrupts.
|
||||
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -1337,7 +1337,7 @@ static struct irq_chip advk_msi_irq_chip
|
||||
|
||||
static struct msi_domain_info advk_msi_domain_info = {
|
||||
.flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
|
||||
- MSI_FLAG_MULTI_PCI_MSI,
|
||||
+ MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX,
|
||||
.chip = &advk_msi_irq_chip,
|
||||
};
|
||||
|
@ -0,0 +1,100 @@
|
||||
From 7f3e55a3890fa26d15e2e4e90213962d1a7f6df9 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Fri, 12 Feb 2021 20:32:55 +0100
|
||||
Subject: [PATCH] PCI: aardvark: Add support for ERR interrupt on emulated
|
||||
bridge
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
ERR interrupt is triggered when corresponding bit is unmasked in both ISR0
|
||||
and PCI_EXP_DEVCTL registers. Unmasking ERR bits in PCI_EXP_DEVCTL register
|
||||
is not enough. This means that currently the ERR interrupt is never
|
||||
triggered.
|
||||
|
||||
Unmask ERR bits in ISR0 register at driver probe time. ERR interrupt is not
|
||||
triggered until ERR bits are unmasked also in PCI_EXP_DEVCTL register,
|
||||
which is done by AER driver. So it is safe to unconditionally unmask all
|
||||
ERR bits in aardvark probe.
|
||||
|
||||
Aardvark HW sets PCI_ERR_ROOT_AER_IRQ to zero and when corresponding bits
|
||||
in ISR0 and PCI_EXP_DEVCTL are enabled, the HW triggers a generic interrupt
|
||||
on GIC. Chain this interrupt to PCIe interrupt 0 with
|
||||
generic_handle_domain_irq() to allow processing of ERR interrupts.
|
||||
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 36 ++++++++++++++++++++++++++-
|
||||
1 file changed, 35 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -98,6 +98,10 @@
|
||||
#define PCIE_MSG_PM_PME_MASK BIT(7)
|
||||
#define PCIE_ISR0_MASK_REG (CONTROL_BASE_ADDR + 0x44)
|
||||
#define PCIE_ISR0_MSI_INT_PENDING BIT(24)
|
||||
+#define PCIE_ISR0_CORR_ERR BIT(11)
|
||||
+#define PCIE_ISR0_NFAT_ERR BIT(12)
|
||||
+#define PCIE_ISR0_FAT_ERR BIT(13)
|
||||
+#define PCIE_ISR0_ERR_MASK GENMASK(13, 11)
|
||||
#define PCIE_ISR0_INTX_ASSERT(val) BIT(16 + (val))
|
||||
#define PCIE_ISR0_INTX_DEASSERT(val) BIT(20 + (val))
|
||||
#define PCIE_ISR0_ALL_MASK GENMASK(31, 0)
|
||||
@@ -778,11 +782,15 @@ advk_pci_bridge_emul_base_conf_read(stru
|
||||
case PCI_INTERRUPT_LINE: {
|
||||
/*
|
||||
* From the whole 32bit register we support reading from HW only
|
||||
- * one bit: PCI_BRIDGE_CTL_BUS_RESET.
|
||||
+ * two bits: PCI_BRIDGE_CTL_BUS_RESET and PCI_BRIDGE_CTL_SERR.
|
||||
* Other bits are retrieved only from emulated config buffer.
|
||||
*/
|
||||
__le32 *cfgspace = (__le32 *)&bridge->conf;
|
||||
u32 val = le32_to_cpu(cfgspace[PCI_INTERRUPT_LINE / 4]);
|
||||
+ if (advk_readl(pcie, PCIE_ISR0_MASK_REG) & PCIE_ISR0_ERR_MASK)
|
||||
+ val &= ~(PCI_BRIDGE_CTL_SERR << 16);
|
||||
+ else
|
||||
+ val |= PCI_BRIDGE_CTL_SERR << 16;
|
||||
if (advk_readl(pcie, PCIE_CORE_CTRL1_REG) & HOT_RESET_GEN)
|
||||
val |= PCI_BRIDGE_CTL_BUS_RESET << 16;
|
||||
else
|
||||
@@ -808,6 +816,19 @@ advk_pci_bridge_emul_base_conf_write(str
|
||||
break;
|
||||
|
||||
case PCI_INTERRUPT_LINE:
|
||||
+ /*
|
||||
+ * According to Figure 6-3: Pseudo Logic Diagram for Error
|
||||
+ * Message Controls in PCIe base specification, SERR# Enable bit
|
||||
+ * in Bridge Control register enable receiving of ERR_* messages
|
||||
+ */
|
||||
+ if (mask & (PCI_BRIDGE_CTL_SERR << 16)) {
|
||||
+ u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG);
|
||||
+ if (new & (PCI_BRIDGE_CTL_SERR << 16))
|
||||
+ val &= ~PCIE_ISR0_ERR_MASK;
|
||||
+ else
|
||||
+ val |= PCIE_ISR0_ERR_MASK;
|
||||
+ advk_writel(pcie, val, PCIE_ISR0_MASK_REG);
|
||||
+ }
|
||||
if (mask & (PCI_BRIDGE_CTL_BUS_RESET << 16)) {
|
||||
u32 val = advk_readl(pcie, PCIE_CORE_CTRL1_REG);
|
||||
if (new & (PCI_BRIDGE_CTL_BUS_RESET << 16))
|
||||
@@ -1459,6 +1480,19 @@ static void advk_pcie_handle_int(struct
|
||||
isr1_mask = advk_readl(pcie, PCIE_ISR1_MASK_REG);
|
||||
isr1_status = isr1_val & ((~isr1_mask) & PCIE_ISR1_ALL_MASK);
|
||||
|
||||
+ /* Process ERR interrupt */
|
||||
+ if (isr0_status & PCIE_ISR0_ERR_MASK) {
|
||||
+ advk_writel(pcie, PCIE_ISR0_ERR_MASK, PCIE_ISR0_REG);
|
||||
+
|
||||
+ /*
|
||||
+ * Aardvark HW returns zero for PCI_ERR_ROOT_AER_IRQ, so use
|
||||
+ * PCIe interrupt 0
|
||||
+ */
|
||||
+ virq = irq_find_mapping(pcie->irq_domain, 0);
|
||||
+ if (generic_handle_irq(virq) == -EINVAL)
|
||||
+ dev_err_ratelimited(&pcie->pdev->dev, "unhandled ERR IRQ\n");
|
||||
+ }
|
||||
+
|
||||
/* Process MSI interrupts */
|
||||
if (isr0_status & PCIE_ISR0_MSI_INT_PENDING)
|
||||
advk_pcie_handle_msi(pcie);
|
@ -0,0 +1,44 @@
|
||||
From 5f354992eeef9a51c67796dc9f7f578d3584baa2 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Wed, 8 Dec 2021 05:57:54 +0100
|
||||
Subject: [PATCH] PCI: aardvark: Fix reading PCI_EXP_RTSTA_PME bit on emulated
|
||||
bridge
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The emulated bridge returns incorrect value for PCI_EXP_RTSTA register
|
||||
during readout in advk_pci_bridge_emul_pcie_conf_read() function: the
|
||||
correct bit is BIT(16), but we are setting BIT(23), because the code
|
||||
does
|
||||
*value = (isr0 & PCIE_MSG_PM_PME_MASK) << 16
|
||||
where
|
||||
PCIE_MSG_PM_PME_MASK
|
||||
is
|
||||
BIT(7).
|
||||
|
||||
The code should probably have been something like
|
||||
*value = (!!(isr0 & PCIE_MSG_PM_PME_MASK)) << 16,
|
||||
but we are better of using an if() and using the proper macro for this
|
||||
bit.
|
||||
|
||||
Fixes: 8a3ebd8de328 ("PCI: aardvark: Implement emulated root PCI bridge config space")
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -867,7 +867,9 @@ advk_pci_bridge_emul_pcie_conf_read(stru
|
||||
case PCI_EXP_RTSTA: {
|
||||
u32 isr0 = advk_readl(pcie, PCIE_ISR0_REG);
|
||||
u32 msglog = advk_readl(pcie, PCIE_MSG_LOG_REG);
|
||||
- *value = (isr0 & PCIE_MSG_PM_PME_MASK) << 16 | (msglog >> 16);
|
||||
+ *value = msglog >> 16;
|
||||
+ if (isr0 & PCIE_MSG_PM_PME_MASK)
|
||||
+ *value |= PCI_EXP_RTSTA_PME;
|
||||
return PCI_BRIDGE_EMUL_HANDLED;
|
||||
}
|
||||
|
@ -0,0 +1,52 @@
|
||||
From 3fe0073d116d9902df08761c1cf0d733dd4c38fc Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Wed, 8 Dec 2021 06:03:50 +0100
|
||||
Subject: [PATCH] PCI: aardvark: Optimize writing PCI_EXP_RTCTL_PMEIE and
|
||||
PCI_EXP_RTSTA_PME on emulated bridge
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
To optimize advk_pci_bridge_emul_pcie_conf_write() code, touch
|
||||
PCIE_ISR0_REG and PCIE_ISR0_MASK_REG registers only when it is really
|
||||
needed, when processing PCI_EXP_RTCTL_PMEIE and PCI_EXP_RTSTA_PME bits.
|
||||
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 20 +++++++++++---------
|
||||
1 file changed, 11 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -925,19 +925,21 @@ advk_pci_bridge_emul_pcie_conf_write(str
|
||||
advk_pcie_wait_for_retrain(pcie);
|
||||
break;
|
||||
|
||||
- case PCI_EXP_RTCTL: {
|
||||
+ case PCI_EXP_RTCTL:
|
||||
/* Only mask/unmask PME interrupt */
|
||||
- u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG) &
|
||||
- ~PCIE_MSG_PM_PME_MASK;
|
||||
- if ((new & PCI_EXP_RTCTL_PMEIE) == 0)
|
||||
- val |= PCIE_MSG_PM_PME_MASK;
|
||||
- advk_writel(pcie, val, PCIE_ISR0_MASK_REG);
|
||||
+ if (mask & PCI_EXP_RTCTL_PMEIE) {
|
||||
+ u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG);
|
||||
+ if (new & PCI_EXP_RTCTL_PMEIE)
|
||||
+ val &= ~PCIE_MSG_PM_PME_MASK;
|
||||
+ else
|
||||
+ val |= PCIE_MSG_PM_PME_MASK;
|
||||
+ advk_writel(pcie, val, PCIE_ISR0_MASK_REG);
|
||||
+ }
|
||||
break;
|
||||
- }
|
||||
|
||||
case PCI_EXP_RTSTA:
|
||||
- new = (new & PCI_EXP_RTSTA_PME) >> 9;
|
||||
- advk_writel(pcie, new, PCIE_ISR0_REG);
|
||||
+ if (new & PCI_EXP_RTSTA_PME)
|
||||
+ advk_writel(pcie, PCIE_MSG_PM_PME_MASK, PCIE_ISR0_REG);
|
||||
break;
|
||||
|
||||
case PCI_EXP_DEVCTL:
|
@ -0,0 +1,47 @@
|
||||
From 7acd8ef92e8789e10b5d736d73cea3b625087f26 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Wed, 8 Dec 2021 06:07:44 +0100
|
||||
Subject: [PATCH] PCI: aardvark: Add support for PME interrupts
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Currently enabling PCI_EXP_RTSTA_PME bit in PCI_EXP_RTCTL register does
|
||||
nothing. This is because PCIe PME driver expects to receive PCIe interrupt
|
||||
defined in PCI_EXP_FLAGS_IRQ register, but aardvark hardware does not
|
||||
trigger PCIe INTx/MSI interrupt for PME event, rather it triggers custom
|
||||
aardvark interrupt which this driver is not processing yet.
|
||||
|
||||
Fix this issue by handling PME interrupt in advk_pcie_handle_int() and
|
||||
chaining it to PCIe interrupt 0 with generic_handle_domain_irq() (since
|
||||
aardvark sets PCI_EXP_FLAGS_IRQ to zero). With this change PCIe PME driver
|
||||
finally starts receiving PME interrupt.
|
||||
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -1484,6 +1484,19 @@ static void advk_pcie_handle_int(struct
|
||||
isr1_mask = advk_readl(pcie, PCIE_ISR1_MASK_REG);
|
||||
isr1_status = isr1_val & ((~isr1_mask) & PCIE_ISR1_ALL_MASK);
|
||||
|
||||
+ /* Process PME interrupt */
|
||||
+ if (isr0_status & PCIE_MSG_PM_PME_MASK) {
|
||||
+ /*
|
||||
+ * Do not clear PME interrupt bit in ISR0, it is cleared by IRQ
|
||||
+ * receiver by writing to the PCI_EXP_RTSTA register of emulated
|
||||
+ * root bridge. Aardvark HW returns zero for PCI_EXP_FLAGS_IRQ,
|
||||
+ * so use PCIe interrupt 0.
|
||||
+ */
|
||||
+ virq = irq_find_mapping(pcie->irq_domain, 0);
|
||||
+ if (generic_handle_irq(virq) == -EINVAL)
|
||||
+ dev_err_ratelimited(&pcie->pdev->dev, "unhandled PME IRQ\n");
|
||||
+ }
|
||||
+
|
||||
/* Process ERR interrupt */
|
||||
if (isr0_status & PCIE_ISR0_ERR_MASK) {
|
||||
advk_writel(pcie, PCIE_ISR0_ERR_MASK, PCIE_ISR0_REG);
|
@ -0,0 +1,173 @@
|
||||
From 68727b545332327b4c2f9c0f8d006be8970e7832 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Fri, 19 Feb 2021 14:22:22 +0100
|
||||
Subject: [PATCH] PCI: aardvark: Fix support for PME requester on emulated
|
||||
bridge
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Enable aardvark PME interrupt unconditionally by unmasking it and read PME
|
||||
requester ID to emulated bridge config space immediately after receiving
|
||||
interrupt.
|
||||
|
||||
PME requester ID is stored in the PCIE_MSG_LOG_REG register, which contains
|
||||
the last inbound message. So when new inbound message is received by HW
|
||||
(including non-PM), the content in PCIE_MSG_LOG_REG register is replaced by
|
||||
a new value.
|
||||
|
||||
PCIe specification mandates that subsequent PMEs are kept pending until the
|
||||
PME Status Register bit is cleared by software by writing a 1b.
|
||||
|
||||
Support for masking/unmasking PME interrupt on emulated bridge via
|
||||
PCI_EXP_RTCTL_PMEIE bit is now implemented only in emulated bridge config
|
||||
space, to ensure that we do not miss any aardvark PME interrupt.
|
||||
|
||||
Reading of PCI_EXP_RTCAP and PCI_EXP_RTSTA registers is simplified as final
|
||||
value is now always stored into emulated bridge config space by the
|
||||
interrupt handler, so there is no need to implement support for these
|
||||
registers in read_pcie callback.
|
||||
|
||||
Clearing of W1C bit PCI_EXP_RTSTA_PME is now also simplified as it is done
|
||||
by pci-bridge-emul.c code for emulated bridge config space. So there is no
|
||||
need to implement support for clearing this bit in write_pcie callback.
|
||||
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 94 +++++++++++++++------------
|
||||
1 file changed, 52 insertions(+), 42 deletions(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -590,6 +590,11 @@ static void advk_pcie_setup_hw(struct ad
|
||||
reg &= ~PCIE_ISR0_MSI_INT_PENDING;
|
||||
advk_writel(pcie, reg, PCIE_ISR0_MASK_REG);
|
||||
|
||||
+ /* Unmask PME interrupt for processing of PME requester */
|
||||
+ reg = advk_readl(pcie, PCIE_ISR0_MASK_REG);
|
||||
+ reg &= ~PCIE_MSG_PM_PME_MASK;
|
||||
+ advk_writel(pcie, reg, PCIE_ISR0_MASK_REG);
|
||||
+
|
||||
/* Enable summary interrupt for GIC SPI source */
|
||||
reg = PCIE_IRQ_ALL_MASK & (~PCIE_IRQ_ENABLE_INTS_MASK);
|
||||
advk_writel(pcie, reg, HOST_CTRL_INT_MASK_REG);
|
||||
@@ -856,22 +861,11 @@ advk_pci_bridge_emul_pcie_conf_read(stru
|
||||
*value = PCI_EXP_SLTSTA_PDS << 16;
|
||||
return PCI_BRIDGE_EMUL_HANDLED;
|
||||
|
||||
- case PCI_EXP_RTCTL: {
|
||||
- u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG);
|
||||
- *value = (val & PCIE_MSG_PM_PME_MASK) ? 0 : PCI_EXP_RTCTL_PMEIE;
|
||||
- *value |= le16_to_cpu(bridge->pcie_conf.rootctl) & PCI_EXP_RTCTL_CRSSVE;
|
||||
- *value |= PCI_EXP_RTCAP_CRSVIS << 16;
|
||||
- return PCI_BRIDGE_EMUL_HANDLED;
|
||||
- }
|
||||
-
|
||||
- case PCI_EXP_RTSTA: {
|
||||
- u32 isr0 = advk_readl(pcie, PCIE_ISR0_REG);
|
||||
- u32 msglog = advk_readl(pcie, PCIE_MSG_LOG_REG);
|
||||
- *value = msglog >> 16;
|
||||
- if (isr0 & PCIE_MSG_PM_PME_MASK)
|
||||
- *value |= PCI_EXP_RTSTA_PME;
|
||||
- return PCI_BRIDGE_EMUL_HANDLED;
|
||||
- }
|
||||
+ /*
|
||||
+ * PCI_EXP_RTCTL and PCI_EXP_RTSTA are also supported, but do not need
|
||||
+ * to be handled here, because their values are stored in emulated
|
||||
+ * config space buffer, and we read them from there when needed.
|
||||
+ */
|
||||
|
||||
case PCI_EXP_LNKCAP: {
|
||||
u32 val = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg);
|
||||
@@ -925,22 +919,19 @@ advk_pci_bridge_emul_pcie_conf_write(str
|
||||
advk_pcie_wait_for_retrain(pcie);
|
||||
break;
|
||||
|
||||
- case PCI_EXP_RTCTL:
|
||||
- /* Only mask/unmask PME interrupt */
|
||||
- if (mask & PCI_EXP_RTCTL_PMEIE) {
|
||||
- u32 val = advk_readl(pcie, PCIE_ISR0_MASK_REG);
|
||||
- if (new & PCI_EXP_RTCTL_PMEIE)
|
||||
- val &= ~PCIE_MSG_PM_PME_MASK;
|
||||
- else
|
||||
- val |= PCIE_MSG_PM_PME_MASK;
|
||||
- advk_writel(pcie, val, PCIE_ISR0_MASK_REG);
|
||||
- }
|
||||
+ case PCI_EXP_RTCTL: {
|
||||
+ u16 rootctl = le16_to_cpu(bridge->pcie_conf.rootctl);
|
||||
+ /* Only emulation of PMEIE and CRSSVE bits is provided */
|
||||
+ rootctl &= PCI_EXP_RTCTL_PMEIE | PCI_EXP_RTCTL_CRSSVE;
|
||||
+ bridge->pcie_conf.rootctl = cpu_to_le16(rootctl);
|
||||
break;
|
||||
+ }
|
||||
|
||||
- case PCI_EXP_RTSTA:
|
||||
- if (new & PCI_EXP_RTSTA_PME)
|
||||
- advk_writel(pcie, PCIE_MSG_PM_PME_MASK, PCIE_ISR0_REG);
|
||||
- break;
|
||||
+ /*
|
||||
+ * PCI_EXP_RTSTA is also supported, but does not need to be handled
|
||||
+ * here, because its value is stored in emulated config space buffer,
|
||||
+ * and we write it there when needed.
|
||||
+ */
|
||||
|
||||
case PCI_EXP_DEVCTL:
|
||||
case PCI_EXP_DEVCTL2:
|
||||
@@ -1445,6 +1436,34 @@ static void advk_pcie_remove_irq_domain(
|
||||
irq_domain_remove(pcie->irq_domain);
|
||||
}
|
||||
|
||||
+static void advk_pcie_handle_pme(struct advk_pcie *pcie)
|
||||
+{
|
||||
+ u32 requester = advk_readl(pcie, PCIE_MSG_LOG_REG) >> 16;
|
||||
+ int virq;
|
||||
+
|
||||
+ advk_writel(pcie, PCIE_MSG_PM_PME_MASK, PCIE_ISR0_REG);
|
||||
+
|
||||
+ /*
|
||||
+ * PCIE_MSG_LOG_REG contains the last inbound message, so store
|
||||
+ * the requester ID only when PME was not asserted yet.
|
||||
+ * Also do not trigger PME interrupt when PME is still asserted.
|
||||
+ */
|
||||
+ if (!(le32_to_cpu(pcie->bridge.pcie_conf.rootsta) & PCI_EXP_RTSTA_PME)) {
|
||||
+ pcie->bridge.pcie_conf.rootsta = cpu_to_le32(requester | PCI_EXP_RTSTA_PME);
|
||||
+
|
||||
+ /*
|
||||
+ * Trigger PME interrupt only if PMEIE bit in Root Control is set.
|
||||
+ * Aardvark HW returns zero for PCI_EXP_FLAGS_IRQ, so use PCIe interrupt 0.
|
||||
+ */
|
||||
+ if (!(le16_to_cpu(pcie->bridge.pcie_conf.rootctl) & PCI_EXP_RTCTL_PMEIE))
|
||||
+ return;
|
||||
+
|
||||
+ virq = irq_find_mapping(pcie->irq_domain, 0);
|
||||
+ if (generic_handle_irq(virq) == -EINVAL)
|
||||
+ dev_err_ratelimited(&pcie->pdev->dev, "unhandled PME IRQ\n");
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void advk_pcie_handle_msi(struct advk_pcie *pcie)
|
||||
{
|
||||
u32 msi_val, msi_mask, msi_status, msi_idx;
|
||||
@@ -1484,18 +1503,9 @@ static void advk_pcie_handle_int(struct
|
||||
isr1_mask = advk_readl(pcie, PCIE_ISR1_MASK_REG);
|
||||
isr1_status = isr1_val & ((~isr1_mask) & PCIE_ISR1_ALL_MASK);
|
||||
|
||||
- /* Process PME interrupt */
|
||||
- if (isr0_status & PCIE_MSG_PM_PME_MASK) {
|
||||
- /*
|
||||
- * Do not clear PME interrupt bit in ISR0, it is cleared by IRQ
|
||||
- * receiver by writing to the PCI_EXP_RTSTA register of emulated
|
||||
- * root bridge. Aardvark HW returns zero for PCI_EXP_FLAGS_IRQ,
|
||||
- * so use PCIe interrupt 0.
|
||||
- */
|
||||
- virq = irq_find_mapping(pcie->irq_domain, 0);
|
||||
- if (generic_handle_irq(virq) == -EINVAL)
|
||||
- dev_err_ratelimited(&pcie->pdev->dev, "unhandled PME IRQ\n");
|
||||
- }
|
||||
+ /* Process PME interrupt as the first one to do not miss PME requester id */
|
||||
+ if (isr0_status & PCIE_MSG_PM_PME_MASK)
|
||||
+ advk_pcie_handle_pme(pcie);
|
||||
|
||||
/* Process ERR interrupt */
|
||||
if (isr0_status & PCIE_ISR0_ERR_MASK) {
|
@ -0,0 +1,161 @@
|
||||
From db305233136f5aa2444a8287a279384e8458c458 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Thu, 1 Apr 2021 20:12:48 +0200
|
||||
Subject: [PATCH] PCI: aardvark: Use separate INTA interrupt for emulated root
|
||||
bridge
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Emulated root bridge currently provides only one Legacy INTA interrupt
|
||||
which is used for reporting PCIe PME and ERR events and handled by kernel
|
||||
PCIe PME and AER drivers.
|
||||
|
||||
Aardvark HW reports these PME and ERR events separately, so there is no
|
||||
need to mix real INTA interrupt and emulated INTA interrupt for PCIe PME
|
||||
and AER drivers.
|
||||
|
||||
Register a new advk-RP (as in Root Port) irq chip and a new irq domain
|
||||
for emulated root bridge and use this new separate irq domain for
|
||||
providing INTA interrupt from emulated root bridge for PME and ERR events.
|
||||
|
||||
The real INTA interrupt from real devices is now separate.
|
||||
|
||||
A custom map_irq callback function on PCI host bridge structure is used to
|
||||
allocate IRQ mapping for emulated root bridge from new irq domain. Original
|
||||
callback of_irq_parse_and_map_pci() is used for all other devices as before.
|
||||
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 69 ++++++++++++++++++++++++++-
|
||||
1 file changed, 67 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -273,6 +273,7 @@ struct advk_pcie {
|
||||
} wins[OB_WIN_COUNT];
|
||||
u8 wins_count;
|
||||
int irq;
|
||||
+ struct irq_domain *rp_irq_domain;
|
||||
struct irq_domain *irq_domain;
|
||||
struct irq_chip irq_chip;
|
||||
raw_spinlock_t irq_lock;
|
||||
@@ -1436,6 +1437,44 @@ static void advk_pcie_remove_irq_domain(
|
||||
irq_domain_remove(pcie->irq_domain);
|
||||
}
|
||||
|
||||
+static struct irq_chip advk_rp_irq_chip = {
|
||||
+ .name = "advk-RP",
|
||||
+};
|
||||
+
|
||||
+static int advk_pcie_rp_irq_map(struct irq_domain *h,
|
||||
+ unsigned int virq, irq_hw_number_t hwirq)
|
||||
+{
|
||||
+ struct advk_pcie *pcie = h->host_data;
|
||||
+
|
||||
+ irq_set_chip_and_handler(virq, &advk_rp_irq_chip, handle_simple_irq);
|
||||
+ irq_set_chip_data(virq, pcie);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct irq_domain_ops advk_pcie_rp_irq_domain_ops = {
|
||||
+ .map = advk_pcie_rp_irq_map,
|
||||
+ .xlate = irq_domain_xlate_onecell,
|
||||
+};
|
||||
+
|
||||
+static int advk_pcie_init_rp_irq_domain(struct advk_pcie *pcie)
|
||||
+{
|
||||
+ pcie->rp_irq_domain = irq_domain_add_linear(NULL, 1,
|
||||
+ &advk_pcie_rp_irq_domain_ops,
|
||||
+ pcie);
|
||||
+ if (!pcie->rp_irq_domain) {
|
||||
+ dev_err(&pcie->pdev->dev, "Failed to add Root Port IRQ domain\n");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void advk_pcie_remove_rp_irq_domain(struct advk_pcie *pcie)
|
||||
+{
|
||||
+ irq_domain_remove(pcie->rp_irq_domain);
|
||||
+}
|
||||
+
|
||||
static void advk_pcie_handle_pme(struct advk_pcie *pcie)
|
||||
{
|
||||
u32 requester = advk_readl(pcie, PCIE_MSG_LOG_REG) >> 16;
|
||||
@@ -1458,7 +1497,7 @@ static void advk_pcie_handle_pme(struct
|
||||
if (!(le16_to_cpu(pcie->bridge.pcie_conf.rootctl) & PCI_EXP_RTCTL_PMEIE))
|
||||
return;
|
||||
|
||||
- virq = irq_find_mapping(pcie->irq_domain, 0);
|
||||
+ virq = irq_find_mapping(pcie->rp_irq_domain, 0);
|
||||
if (generic_handle_irq(virq) == -EINVAL)
|
||||
dev_err_ratelimited(&pcie->pdev->dev, "unhandled PME IRQ\n");
|
||||
}
|
||||
@@ -1515,7 +1554,7 @@ static void advk_pcie_handle_int(struct
|
||||
* Aardvark HW returns zero for PCI_ERR_ROOT_AER_IRQ, so use
|
||||
* PCIe interrupt 0
|
||||
*/
|
||||
- virq = irq_find_mapping(pcie->irq_domain, 0);
|
||||
+ virq = irq_find_mapping(pcie->rp_irq_domain, 0);
|
||||
if (generic_handle_irq(virq) == -EINVAL)
|
||||
dev_err_ratelimited(&pcie->pdev->dev, "unhandled ERR IRQ\n");
|
||||
}
|
||||
@@ -1560,6 +1599,21 @@ static void advk_pcie_irq_handler(struct
|
||||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
+static int advk_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
+{
|
||||
+ struct advk_pcie *pcie = dev->bus->sysdata;
|
||||
+
|
||||
+ /*
|
||||
+ * Emulated root bridge has its own emulated irq chip and irq domain.
|
||||
+ * Argument pin is the INTx pin (1=INTA, 2=INTB, 3=INTC, 4=INTD) and
|
||||
+ * hwirq for irq_create_mapping() is indexed from zero.
|
||||
+ */
|
||||
+ if (pci_is_root_bus(dev->bus))
|
||||
+ return irq_create_mapping(pcie->rp_irq_domain, pin - 1);
|
||||
+ else
|
||||
+ return of_irq_parse_and_map_pci(dev, slot, pin);
|
||||
+}
|
||||
+
|
||||
static void __maybe_unused advk_pcie_disable_phy(struct advk_pcie *pcie)
|
||||
{
|
||||
phy_power_off(pcie->phy);
|
||||
@@ -1761,14 +1815,24 @@ static int advk_pcie_probe(struct platfo
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ ret = advk_pcie_init_rp_irq_domain(pcie);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "Failed to initialize irq\n");
|
||||
+ advk_pcie_remove_msi_irq_domain(pcie);
|
||||
+ advk_pcie_remove_irq_domain(pcie);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
irq_set_chained_handler_and_data(pcie->irq, advk_pcie_irq_handler, pcie);
|
||||
|
||||
bridge->sysdata = pcie;
|
||||
bridge->ops = &advk_pcie_ops;
|
||||
+ bridge->map_irq = advk_pcie_map_irq;
|
||||
|
||||
ret = pci_host_probe(bridge);
|
||||
if (ret < 0) {
|
||||
irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
|
||||
+ advk_pcie_remove_rp_irq_domain(pcie);
|
||||
advk_pcie_remove_msi_irq_domain(pcie);
|
||||
advk_pcie_remove_irq_domain(pcie);
|
||||
return ret;
|
||||
@@ -1820,6 +1884,7 @@ static int advk_pcie_remove(struct platf
|
||||
irq_set_chained_handler_and_data(pcie->irq, NULL, NULL);
|
||||
|
||||
/* Remove IRQ domains */
|
||||
+ advk_pcie_remove_rp_irq_domain(pcie);
|
||||
advk_pcie_remove_msi_irq_domain(pcie);
|
||||
advk_pcie_remove_irq_domain(pcie);
|
||||
|
@ -0,0 +1,29 @@
|
||||
From 8c9eef96e24f34ff8b62b230700416b822691a37 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Thu, 1 Apr 2021 14:24:12 +0200
|
||||
Subject: [PATCH] PCI: aardvark: Remove irq_mask_ack callback for INTx
|
||||
interrupts
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Callback for irq_mask_ack is the same as for irq_mask. As there is no
|
||||
special handling for irq_ack, there is no need to define irq_mask_ack too.
|
||||
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Acked-by: Marc Zyngier <maz@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -1415,7 +1415,6 @@ static int advk_pcie_init_irq_domain(str
|
||||
}
|
||||
|
||||
irq_chip->irq_mask = advk_pcie_irq_mask;
|
||||
- irq_chip->irq_mask_ack = advk_pcie_irq_mask;
|
||||
irq_chip->irq_unmask = advk_pcie_irq_unmask;
|
||||
|
||||
pcie->irq_domain =
|
@ -0,0 +1,27 @@
|
||||
From dc01fca5a9d9c09ce9a3fb2bc2e7715c37ff3bd9 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Thu, 1 Apr 2021 14:30:06 +0200
|
||||
Subject: [PATCH] PCI: aardvark: Don't mask irq when mapping
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
By default, all Legacy INTx interrupts are masked, so there is no need to
|
||||
mask this interrupt during irq_map callback.
|
||||
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -1332,7 +1332,6 @@ static int advk_pcie_irq_map(struct irq_
|
||||
{
|
||||
struct advk_pcie *pcie = h->host_data;
|
||||
|
||||
- advk_pcie_irq_mask(irq_get_irq_data(virq));
|
||||
irq_set_status_flags(virq, IRQ_LEVEL);
|
||||
irq_set_chip_and_handler(virq, &pcie->irq_chip,
|
||||
handle_level_irq);
|
@ -0,0 +1,28 @@
|
||||
From a511c99262ce19ee06908d27212b39ec4c5aeb17 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
|
||||
Date: Wed, 8 Dec 2021 04:40:29 +0100
|
||||
Subject: [PATCH] PCI: aardvark: Drop __maybe_unused from
|
||||
advk_pcie_disable_phy()
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This function is now always used in driver remove method, drop the
|
||||
__maybe_unused attribute.
|
||||
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -1612,7 +1612,7 @@ static int advk_pcie_map_irq(const struc
|
||||
return of_irq_parse_and_map_pci(dev, slot, pin);
|
||||
}
|
||||
|
||||
-static void __maybe_unused advk_pcie_disable_phy(struct advk_pcie *pcie)
|
||||
+static void advk_pcie_disable_phy(struct advk_pcie *pcie)
|
||||
{
|
||||
phy_power_off(pcie->phy);
|
||||
phy_exit(pcie->phy);
|
@ -0,0 +1,35 @@
|
||||
From bafda858364003a70b9cda84282f9761587f8033 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
|
||||
Date: Mon, 10 Jan 2022 00:47:38 +0100
|
||||
Subject: [PATCH] PCI: aardvark: Update comment about link going down after
|
||||
link-up
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Update the comment about what happens when link goes down after we have
|
||||
checked for link-up. If a PIO request is done while link-down, we have
|
||||
a serious problem.
|
||||
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 8 ++++++--
|
||||
1 file changed, 6 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -998,8 +998,12 @@ static bool advk_pcie_valid_device(struc
|
||||
return false;
|
||||
|
||||
/*
|
||||
- * If the link goes down after we check for link-up, nothing bad
|
||||
- * happens but the config access times out.
|
||||
+ * If the link goes down after we check for link-up, we have a problem:
|
||||
+ * if a PIO request is executed while link-down, the whole controller
|
||||
+ * gets stuck in a non-functional state, and even after link comes up
|
||||
+ * again, PIO requests won't work anymore, and a reset of the whole PCIe
|
||||
+ * controller is needed. Therefore we need to prevent sending PIO
|
||||
+ * requests while the link is down.
|
||||
*/
|
||||
if (!pci_is_root_bus(bus) && !advk_pcie_link_up(pcie))
|
||||
return false;
|
@ -0,0 +1,102 @@
|
||||
From 663b9f99bb35dbc0c7b685f71ee3668a60d31320 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Marek=20Beh=C3=BAn?= <kabel@kernel.org>
|
||||
Date: Mon, 10 Jan 2022 02:02:00 +0100
|
||||
Subject: [PATCH] PCI: aardvark: Make main irq_chip structure a static driver
|
||||
structure
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Marc Zyngier says [1] that we should use struct irq_chip as a global
|
||||
static struct in the driver. Even though the structure currently
|
||||
contains a dynamic member (parent_device), Marc says [2] that he plans
|
||||
to kill it and make the structure completely static.
|
||||
|
||||
We have already converted others irq_chip structures in this driver in
|
||||
this way, but we omitted this one because the .name member is
|
||||
dynamically created from device's name, and the name is displayed in
|
||||
sysfs, so changing it would break sysfs ABI.
|
||||
|
||||
The rationale for changing the name (to "advk-INT") in spite of sysfs
|
||||
ABI, and thus allowing to convert to a static structure, is that after
|
||||
the other changes we made in this series, the IRQ chip is basically
|
||||
something different: it no logner generates ERR and PME interrupts (they
|
||||
are generated by emulated bridge's rp_irq_chip).
|
||||
|
||||
[1] https://lore.kernel.org/linux-pci/877dbcvngf.wl-maz@kernel.org/
|
||||
[2] https://lore.kernel.org/linux-pci/874k6gvkhz.wl-maz@kernel.org/
|
||||
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 25 +++++++------------------
|
||||
1 file changed, 7 insertions(+), 18 deletions(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -275,7 +275,6 @@ struct advk_pcie {
|
||||
int irq;
|
||||
struct irq_domain *rp_irq_domain;
|
||||
struct irq_domain *irq_domain;
|
||||
- struct irq_chip irq_chip;
|
||||
raw_spinlock_t irq_lock;
|
||||
struct irq_domain *msi_domain;
|
||||
struct irq_domain *msi_inner_domain;
|
||||
@@ -1331,14 +1330,19 @@ static void advk_pcie_irq_unmask(struct
|
||||
raw_spin_unlock_irqrestore(&pcie->irq_lock, flags);
|
||||
}
|
||||
|
||||
+static struct irq_chip advk_irq_chip = {
|
||||
+ .name = "advk-INT",
|
||||
+ .irq_mask = advk_pcie_irq_mask,
|
||||
+ .irq_unmask = advk_pcie_irq_unmask,
|
||||
+};
|
||||
+
|
||||
static int advk_pcie_irq_map(struct irq_domain *h,
|
||||
unsigned int virq, irq_hw_number_t hwirq)
|
||||
{
|
||||
struct advk_pcie *pcie = h->host_data;
|
||||
|
||||
irq_set_status_flags(virq, IRQ_LEVEL);
|
||||
- irq_set_chip_and_handler(virq, &pcie->irq_chip,
|
||||
- handle_level_irq);
|
||||
+ irq_set_chip_and_handler(virq, &advk_irq_chip, handle_level_irq);
|
||||
irq_set_chip_data(virq, pcie);
|
||||
|
||||
return 0;
|
||||
@@ -1397,7 +1401,6 @@ static int advk_pcie_init_irq_domain(str
|
||||
struct device *dev = &pcie->pdev->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct device_node *pcie_intc_node;
|
||||
- struct irq_chip *irq_chip;
|
||||
int ret = 0;
|
||||
|
||||
raw_spin_lock_init(&pcie->irq_lock);
|
||||
@@ -1408,28 +1411,14 @@ static int advk_pcie_init_irq_domain(str
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
- irq_chip = &pcie->irq_chip;
|
||||
-
|
||||
- irq_chip->name = devm_kasprintf(dev, GFP_KERNEL, "%s-irq",
|
||||
- dev_name(dev));
|
||||
- if (!irq_chip->name) {
|
||||
- ret = -ENOMEM;
|
||||
- goto out_put_node;
|
||||
- }
|
||||
-
|
||||
- irq_chip->irq_mask = advk_pcie_irq_mask;
|
||||
- irq_chip->irq_unmask = advk_pcie_irq_unmask;
|
||||
-
|
||||
pcie->irq_domain =
|
||||
irq_domain_add_linear(pcie_intc_node, PCI_NUM_INTX,
|
||||
&advk_pcie_irq_domain_ops, pcie);
|
||||
if (!pcie->irq_domain) {
|
||||
dev_err(dev, "Failed to get a INTx IRQ domain\n");
|
||||
ret = -ENOMEM;
|
||||
- goto out_put_node;
|
||||
}
|
||||
|
||||
-out_put_node:
|
||||
of_node_put(pcie_intc_node);
|
||||
return ret;
|
||||
}
|
@ -0,0 +1,217 @@
|
||||
From a719f7ba7fcba05d85801c6f0267f389a21627c1 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Fri, 24 Sep 2021 13:03:02 +0200
|
||||
Subject: [PATCH] phy: marvell: phy-mvebu-a3700-comphy: Remove port from driver
|
||||
configuration
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Port number is encoded into argument for SMC call. It is zero for SATA,
|
||||
PCIe and also both USB 3.0 PHYs. It is non-zero only for Ethernet PHY
|
||||
(incorrectly called SGMII) on lane 0. Ethernet PHY on lane 1 also uses zero
|
||||
port number.
|
||||
|
||||
So construct "port" bits for SMC call argument can be constructed directly
|
||||
from PHY type and lane number.
|
||||
|
||||
Change driver code to always pass zero port number for non-ethernet PHYs
|
||||
and for ethernet PHYs determinate port number from lane number. This
|
||||
simplifies the driver.
|
||||
|
||||
As port number from DT PHY configuration is not used anymore, remove whole
|
||||
driver code which parses it. This also simplifies the driver.
|
||||
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
---
|
||||
drivers/phy/marvell/phy-mvebu-a3700-comphy.c | 62 +++++++++-----------
|
||||
1 file changed, 29 insertions(+), 33 deletions(-)
|
||||
|
||||
--- a/drivers/phy/marvell/phy-mvebu-a3700-comphy.c
|
||||
+++ b/drivers/phy/marvell/phy-mvebu-a3700-comphy.c
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define MVEBU_A3700_COMPHY_LANES 3
|
||||
-#define MVEBU_A3700_COMPHY_PORTS 2
|
||||
|
||||
/* COMPHY Fast SMC function identifiers */
|
||||
#define COMPHY_SIP_POWER_ON 0x82000001
|
||||
@@ -45,51 +44,47 @@
|
||||
#define COMPHY_FW_NET(mode, idx, speed) (COMPHY_FW_MODE(mode) | \
|
||||
((idx) << 8) | \
|
||||
((speed) << 2))
|
||||
-#define COMPHY_FW_PCIE(mode, idx, speed, width) (COMPHY_FW_NET(mode, idx, speed) | \
|
||||
+#define COMPHY_FW_PCIE(mode, speed, width) (COMPHY_FW_NET(mode, 0, speed) | \
|
||||
((width) << 18))
|
||||
|
||||
struct mvebu_a3700_comphy_conf {
|
||||
unsigned int lane;
|
||||
enum phy_mode mode;
|
||||
int submode;
|
||||
- unsigned int port;
|
||||
u32 fw_mode;
|
||||
};
|
||||
|
||||
-#define MVEBU_A3700_COMPHY_CONF(_lane, _mode, _smode, _port, _fw) \
|
||||
+#define MVEBU_A3700_COMPHY_CONF(_lane, _mode, _smode, _fw) \
|
||||
{ \
|
||||
.lane = _lane, \
|
||||
.mode = _mode, \
|
||||
.submode = _smode, \
|
||||
- .port = _port, \
|
||||
.fw_mode = _fw, \
|
||||
}
|
||||
|
||||
-#define MVEBU_A3700_COMPHY_CONF_GEN(_lane, _mode, _port, _fw) \
|
||||
- MVEBU_A3700_COMPHY_CONF(_lane, _mode, PHY_INTERFACE_MODE_NA, _port, _fw)
|
||||
+#define MVEBU_A3700_COMPHY_CONF_GEN(_lane, _mode, _fw) \
|
||||
+ MVEBU_A3700_COMPHY_CONF(_lane, _mode, PHY_INTERFACE_MODE_NA, _fw)
|
||||
|
||||
-#define MVEBU_A3700_COMPHY_CONF_ETH(_lane, _smode, _port, _fw) \
|
||||
- MVEBU_A3700_COMPHY_CONF(_lane, PHY_MODE_ETHERNET, _smode, _port, _fw)
|
||||
+#define MVEBU_A3700_COMPHY_CONF_ETH(_lane, _smode, _fw) \
|
||||
+ MVEBU_A3700_COMPHY_CONF(_lane, PHY_MODE_ETHERNET, _smode, _fw)
|
||||
|
||||
static const struct mvebu_a3700_comphy_conf mvebu_a3700_comphy_modes[] = {
|
||||
/* lane 0 */
|
||||
- MVEBU_A3700_COMPHY_CONF_GEN(0, PHY_MODE_USB_HOST_SS, 0,
|
||||
+ MVEBU_A3700_COMPHY_CONF_GEN(0, PHY_MODE_USB_HOST_SS,
|
||||
COMPHY_FW_MODE_USB3H),
|
||||
- MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_SGMII, 1,
|
||||
+ MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_SGMII,
|
||||
COMPHY_FW_MODE_SGMII),
|
||||
- MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_2500BASEX, 1,
|
||||
+ MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_2500BASEX,
|
||||
COMPHY_FW_MODE_2500BASEX),
|
||||
/* lane 1 */
|
||||
- MVEBU_A3700_COMPHY_CONF_GEN(1, PHY_MODE_PCIE, 0,
|
||||
- COMPHY_FW_MODE_PCIE),
|
||||
- MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_SGMII, 0,
|
||||
+ MVEBU_A3700_COMPHY_CONF_GEN(1, PHY_MODE_PCIE, COMPHY_FW_MODE_PCIE),
|
||||
+ MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_SGMII,
|
||||
COMPHY_FW_MODE_SGMII),
|
||||
- MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_2500BASEX, 0,
|
||||
+ MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_2500BASEX,
|
||||
COMPHY_FW_MODE_2500BASEX),
|
||||
/* lane 2 */
|
||||
- MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_SATA, 0,
|
||||
- COMPHY_FW_MODE_SATA),
|
||||
- MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_USB_HOST_SS, 0,
|
||||
+ MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_SATA, COMPHY_FW_MODE_SATA),
|
||||
+ MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_USB_HOST_SS,
|
||||
COMPHY_FW_MODE_USB3H),
|
||||
};
|
||||
|
||||
@@ -98,7 +93,6 @@ struct mvebu_a3700_comphy_lane {
|
||||
unsigned int id;
|
||||
enum phy_mode mode;
|
||||
int submode;
|
||||
- int port;
|
||||
};
|
||||
|
||||
static int mvebu_a3700_comphy_smc(unsigned long function, unsigned long lane,
|
||||
@@ -120,7 +114,7 @@ static int mvebu_a3700_comphy_smc(unsign
|
||||
}
|
||||
}
|
||||
|
||||
-static int mvebu_a3700_comphy_get_fw_mode(int lane, int port,
|
||||
+static int mvebu_a3700_comphy_get_fw_mode(int lane,
|
||||
enum phy_mode mode,
|
||||
int submode)
|
||||
{
|
||||
@@ -132,7 +126,6 @@ static int mvebu_a3700_comphy_get_fw_mod
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (mvebu_a3700_comphy_modes[i].lane == lane &&
|
||||
- mvebu_a3700_comphy_modes[i].port == port &&
|
||||
mvebu_a3700_comphy_modes[i].mode == mode &&
|
||||
mvebu_a3700_comphy_modes[i].submode == submode)
|
||||
break;
|
||||
@@ -153,7 +146,7 @@ static int mvebu_a3700_comphy_set_mode(s
|
||||
if (submode == PHY_INTERFACE_MODE_1000BASEX)
|
||||
submode = PHY_INTERFACE_MODE_SGMII;
|
||||
|
||||
- fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, lane->port, mode,
|
||||
+ fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, mode,
|
||||
submode);
|
||||
if (fw_mode < 0) {
|
||||
dev_err(lane->dev, "invalid COMPHY mode\n");
|
||||
@@ -172,9 +165,10 @@ static int mvebu_a3700_comphy_power_on(s
|
||||
struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy);
|
||||
u32 fw_param;
|
||||
int fw_mode;
|
||||
+ int fw_port;
|
||||
int ret;
|
||||
|
||||
- fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, lane->port,
|
||||
+ fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id,
|
||||
lane->mode, lane->submode);
|
||||
if (fw_mode < 0) {
|
||||
dev_err(lane->dev, "invalid COMPHY mode\n");
|
||||
@@ -191,17 +185,18 @@ static int mvebu_a3700_comphy_power_on(s
|
||||
fw_param = COMPHY_FW_MODE(fw_mode);
|
||||
break;
|
||||
case PHY_MODE_ETHERNET:
|
||||
+ fw_port = (lane->id == 0) ? 1 : 0;
|
||||
switch (lane->submode) {
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
dev_dbg(lane->dev, "set lane %d to SGMII mode\n",
|
||||
lane->id);
|
||||
- fw_param = COMPHY_FW_NET(fw_mode, lane->port,
|
||||
+ fw_param = COMPHY_FW_NET(fw_mode, fw_port,
|
||||
COMPHY_FW_SPEED_1_25G);
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_2500BASEX:
|
||||
dev_dbg(lane->dev, "set lane %d to 2500BASEX mode\n",
|
||||
lane->id);
|
||||
- fw_param = COMPHY_FW_NET(fw_mode, lane->port,
|
||||
+ fw_param = COMPHY_FW_NET(fw_mode, fw_port,
|
||||
COMPHY_FW_SPEED_3_125G);
|
||||
break;
|
||||
default:
|
||||
@@ -212,8 +207,7 @@ static int mvebu_a3700_comphy_power_on(s
|
||||
break;
|
||||
case PHY_MODE_PCIE:
|
||||
dev_dbg(lane->dev, "set lane %d to PCIe mode\n", lane->id);
|
||||
- fw_param = COMPHY_FW_PCIE(fw_mode, lane->port,
|
||||
- COMPHY_FW_SPEED_5G,
|
||||
+ fw_param = COMPHY_FW_PCIE(fw_mode, COMPHY_FW_SPEED_5G,
|
||||
phy->attrs.bus_width);
|
||||
break;
|
||||
default:
|
||||
@@ -247,17 +241,20 @@ static struct phy *mvebu_a3700_comphy_xl
|
||||
struct of_phandle_args *args)
|
||||
{
|
||||
struct mvebu_a3700_comphy_lane *lane;
|
||||
+ unsigned int port;
|
||||
struct phy *phy;
|
||||
|
||||
- if (WARN_ON(args->args[0] >= MVEBU_A3700_COMPHY_PORTS))
|
||||
- return ERR_PTR(-EINVAL);
|
||||
-
|
||||
phy = of_phy_simple_xlate(dev, args);
|
||||
if (IS_ERR(phy))
|
||||
return phy;
|
||||
|
||||
lane = phy_get_drvdata(phy);
|
||||
- lane->port = args->args[0];
|
||||
+
|
||||
+ port = args->args[0];
|
||||
+ if (port != 0 && (port != 1 || lane->id != 0)) {
|
||||
+ dev_err(lane->dev, "invalid port number %u\n", port);
|
||||
+ return ERR_PTR(-EINVAL);
|
||||
+ }
|
||||
|
||||
return phy;
|
||||
}
|
||||
@@ -302,7 +299,6 @@ static int mvebu_a3700_comphy_probe(stru
|
||||
lane->mode = PHY_MODE_INVALID;
|
||||
lane->submode = PHY_INTERFACE_MODE_NA;
|
||||
lane->id = lane_id;
|
||||
- lane->port = -1;
|
||||
phy_set_drvdata(phy, lane);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,31 @@
|
||||
From 66c51c39fd4bf05e99debf0e71de5704231c57dc Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Thu, 23 Sep 2021 19:26:26 +0200
|
||||
Subject: [PATCH] arm64: dts: marvell: armada-37xx: Add xtal clock to comphy
|
||||
node
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Kernel driver phy-mvebu-a3700-comphy.c needs to know the rate of the
|
||||
reference xtal clock. So add missing xtal clock source into comphy device
|
||||
tree node. If the property is not present, the driver defaults to 25 MHz
|
||||
xtal rate (which, as far as we know, is used by all the existing boards).
|
||||
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
---
|
||||
arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
|
||||
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
|
||||
@@ -265,6 +265,8 @@
|
||||
"lane2_sata_usb3";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
+ clocks = <&xtalclk>;
|
||||
+ clock-names = "xtal";
|
||||
|
||||
comphy0: phy@0 {
|
||||
reg = <0>;
|
@ -0,0 +1,61 @@
|
||||
From 750bb44dbbe9dfb4ba3e1f8a746b831b39ba3cd9 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Thu, 23 Sep 2021 19:35:57 +0200
|
||||
Subject: [PATCH] Revert "ata: ahci: mvebu: Make SATA PHY optional for Armada
|
||||
3720"
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This reverts commit 45aefe3d2251e4e229d7662052739f96ad1d08d9.
|
||||
|
||||
Armada 3720 PHY driver (phy-mvebu-a3700-comphy.c) does not return
|
||||
-EOPNOTSUPP from phy_power_on() callback anymore.
|
||||
|
||||
So remove AHCI_HFLAG_IGN_NOTSUPP_POWER_ON flag from Armada 3720 plat data.
|
||||
|
||||
AHCI_HFLAG_IGN_NOTSUPP_POWER_ON is not used by any other ahci driver, so
|
||||
remove this flag completely.
|
||||
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
Acked-by: Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
---
|
||||
drivers/ata/ahci.h | 2 --
|
||||
drivers/ata/ahci_mvebu.c | 2 +-
|
||||
drivers/ata/libahci_platform.c | 2 +-
|
||||
3 files changed, 2 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/ata/ahci.h
|
||||
+++ b/drivers/ata/ahci.h
|
||||
@@ -240,8 +240,6 @@ enum {
|
||||
as default lpm_policy */
|
||||
AHCI_HFLAG_SUSPEND_PHYS = (1 << 26), /* handle PHYs during
|
||||
suspend/resume */
|
||||
- AHCI_HFLAG_IGN_NOTSUPP_POWER_ON = (1 << 27), /* ignore -EOPNOTSUPP
|
||||
- from phy_power_on() */
|
||||
AHCI_HFLAG_NO_SXS = (1 << 28), /* SXS not supported */
|
||||
|
||||
/* ap->flags bits */
|
||||
--- a/drivers/ata/ahci_mvebu.c
|
||||
+++ b/drivers/ata/ahci_mvebu.c
|
||||
@@ -227,7 +227,7 @@ static const struct ahci_mvebu_plat_data
|
||||
|
||||
static const struct ahci_mvebu_plat_data ahci_mvebu_armada_3700_plat_data = {
|
||||
.plat_config = ahci_mvebu_armada_3700_config,
|
||||
- .flags = AHCI_HFLAG_SUSPEND_PHYS | AHCI_HFLAG_IGN_NOTSUPP_POWER_ON,
|
||||
+ .flags = AHCI_HFLAG_SUSPEND_PHYS,
|
||||
};
|
||||
|
||||
static const struct of_device_id ahci_mvebu_of_match[] = {
|
||||
--- a/drivers/ata/libahci_platform.c
|
||||
+++ b/drivers/ata/libahci_platform.c
|
||||
@@ -59,7 +59,7 @@ int ahci_platform_enable_phys(struct ahc
|
||||
}
|
||||
|
||||
rc = phy_power_on(hpriv->phys[i]);
|
||||
- if (rc && !(rc == -EOPNOTSUPP && (hpriv->flags & AHCI_HFLAG_IGN_NOTSUPP_POWER_ON))) {
|
||||
+ if (rc) {
|
||||
phy_exit(hpriv->phys[i]);
|
||||
goto disable_phys;
|
||||
}
|
@ -0,0 +1,163 @@
|
||||
From 9f0dfb279b1dd505d5e10b10e4a78a62030978d8 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Thu, 23 Sep 2021 19:40:06 +0200
|
||||
Subject: [PATCH] Revert "usb: host: xhci: mvebu: make USB 3.0 PHY optional for
|
||||
Armada 3720"
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This reverts commit 3241929b67d28c83945d3191c6816a3271fd6b85.
|
||||
|
||||
Armada 3720 phy driver (phy-mvebu-a3700-comphy.c) does not return
|
||||
-EOPNOTSUPP from phy_power_on() callback anymore.
|
||||
|
||||
So remove XHCI_SKIP_PHY_INIT flag from xhci_mvebu_a3700_plat_setup() and
|
||||
then also whole xhci_mvebu_a3700_plat_setup() function which is there just
|
||||
to handle -EOPNOTSUPP for XHCI_SKIP_PHY_INIT.
|
||||
|
||||
xhci plat_setup callback is not used by any other xhci plat driver, so
|
||||
remove this callback completely.
|
||||
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
Acked-by: Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
---
|
||||
drivers/usb/host/xhci-mvebu.c | 42 -----------------------------------
|
||||
drivers/usb/host/xhci-mvebu.h | 6 -----
|
||||
drivers/usb/host/xhci-plat.c | 20 +----------------
|
||||
drivers/usb/host/xhci-plat.h | 1 -
|
||||
4 files changed, 1 insertion(+), 68 deletions(-)
|
||||
|
||||
--- a/drivers/usb/host/xhci-mvebu.c
|
||||
+++ b/drivers/usb/host/xhci-mvebu.c
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <linux/mbus.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
-#include <linux/phy/phy.h>
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
@@ -74,47 +73,6 @@ int xhci_mvebu_mbus_init_quirk(struct us
|
||||
|
||||
return 0;
|
||||
}
|
||||
-
|
||||
-int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd)
|
||||
-{
|
||||
- struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
- struct device *dev = hcd->self.controller;
|
||||
- struct phy *phy;
|
||||
- int ret;
|
||||
-
|
||||
- /* Old bindings miss the PHY handle */
|
||||
- phy = of_phy_get(dev->of_node, "usb3-phy");
|
||||
- if (IS_ERR(phy) && PTR_ERR(phy) == -EPROBE_DEFER)
|
||||
- return -EPROBE_DEFER;
|
||||
- else if (IS_ERR(phy))
|
||||
- goto phy_out;
|
||||
-
|
||||
- ret = phy_init(phy);
|
||||
- if (ret)
|
||||
- goto phy_put;
|
||||
-
|
||||
- ret = phy_set_mode(phy, PHY_MODE_USB_HOST_SS);
|
||||
- if (ret)
|
||||
- goto phy_exit;
|
||||
-
|
||||
- ret = phy_power_on(phy);
|
||||
- if (ret == -EOPNOTSUPP) {
|
||||
- /* Skip initializatin of XHCI PHY when it is unsupported by firmware */
|
||||
- dev_warn(dev, "PHY unsupported by firmware\n");
|
||||
- xhci->quirks |= XHCI_SKIP_PHY_INIT;
|
||||
- }
|
||||
- if (ret)
|
||||
- goto phy_exit;
|
||||
-
|
||||
- phy_power_off(phy);
|
||||
-phy_exit:
|
||||
- phy_exit(phy);
|
||||
-phy_put:
|
||||
- of_phy_put(phy);
|
||||
-phy_out:
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
|
||||
int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd)
|
||||
{
|
||||
--- a/drivers/usb/host/xhci-mvebu.h
|
||||
+++ b/drivers/usb/host/xhci-mvebu.h
|
||||
@@ -12,18 +12,12 @@ struct usb_hcd;
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_XHCI_MVEBU)
|
||||
int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd);
|
||||
-int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd);
|
||||
int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd);
|
||||
#else
|
||||
static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
-
|
||||
-static inline int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd)
|
||||
-{
|
||||
- return 0;
|
||||
-}
|
||||
|
||||
static inline int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd)
|
||||
{
|
||||
--- a/drivers/usb/host/xhci-plat.c
|
||||
+++ b/drivers/usb/host/xhci-plat.c
|
||||
@@ -44,16 +44,6 @@ static void xhci_priv_plat_start(struct
|
||||
priv->plat_start(hcd);
|
||||
}
|
||||
|
||||
-static int xhci_priv_plat_setup(struct usb_hcd *hcd)
|
||||
-{
|
||||
- struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
|
||||
-
|
||||
- if (!priv->plat_setup)
|
||||
- return 0;
|
||||
-
|
||||
- return priv->plat_setup(hcd);
|
||||
-}
|
||||
-
|
||||
static int xhci_priv_init_quirk(struct usb_hcd *hcd)
|
||||
{
|
||||
struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
|
||||
@@ -121,7 +111,6 @@ static const struct xhci_plat_priv xhci_
|
||||
};
|
||||
|
||||
static const struct xhci_plat_priv xhci_plat_marvell_armada3700 = {
|
||||
- .plat_setup = xhci_mvebu_a3700_plat_setup,
|
||||
.init_quirk = xhci_mvebu_a3700_init_quirk,
|
||||
};
|
||||
|
||||
@@ -341,14 +330,7 @@ static int xhci_plat_probe(struct platfo
|
||||
|
||||
hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node);
|
||||
xhci->shared_hcd->tpl_support = hcd->tpl_support;
|
||||
-
|
||||
- if (priv) {
|
||||
- ret = xhci_priv_plat_setup(hcd);
|
||||
- if (ret)
|
||||
- goto disable_usb_phy;
|
||||
- }
|
||||
-
|
||||
- if ((xhci->quirks & XHCI_SKIP_PHY_INIT) || (priv && (priv->quirks & XHCI_SKIP_PHY_INIT)))
|
||||
+ if (priv && (priv->quirks & XHCI_SKIP_PHY_INIT))
|
||||
hcd->skip_phy_initialization = 1;
|
||||
|
||||
if (priv && (priv->quirks & XHCI_SG_TRB_CACHE_SIZE_QUIRK))
|
||||
--- a/drivers/usb/host/xhci-plat.h
|
||||
+++ b/drivers/usb/host/xhci-plat.h
|
||||
@@ -13,7 +13,6 @@
|
||||
struct xhci_plat_priv {
|
||||
const char *firmware_name;
|
||||
unsigned long long quirks;
|
||||
- int (*plat_setup)(struct usb_hcd *);
|
||||
void (*plat_start)(struct usb_hcd *);
|
||||
int (*init_quirk)(struct usb_hcd *);
|
||||
int (*suspend_quirk)(struct usb_hcd *);
|
@ -0,0 +1,36 @@
|
||||
From 9a352062b7e3857742389dff6f64393481dc755e Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
|
||||
Date: Thu, 23 Sep 2021 19:37:05 +0200
|
||||
Subject: [PATCH] Revert "PCI: aardvark: Fix initialization with old Marvell's
|
||||
Arm Trusted Firmware"
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This reverts commit b0c6ae0f8948a2be6bf4e8b4bbab9ca1343289b6.
|
||||
|
||||
Armada 3720 phy driver (phy-mvebu-a3700-comphy.c) does not return
|
||||
-EOPNOTSUPP from phy_power_on() callback anymore.
|
||||
|
||||
So remove dead code which handles -EOPNOTSUPP return value.
|
||||
|
||||
Signed-off-by: Pali Rohár <pali@kernel.org>
|
||||
Signed-off-by: Marek Behún <kabel@kernel.org>
|
||||
Acked-by: Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
---
|
||||
drivers/pci/controller/pci-aardvark.c | 4 +---
|
||||
1 file changed, 1 insertion(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/pci/controller/pci-aardvark.c
|
||||
+++ b/drivers/pci/controller/pci-aardvark.c
|
||||
@@ -1629,9 +1629,7 @@ static int advk_pcie_enable_phy(struct a
|
||||
}
|
||||
|
||||
ret = phy_power_on(pcie->phy);
|
||||
- if (ret == -EOPNOTSUPP) {
|
||||
- dev_warn(&pcie->pdev->dev, "PHY unsupported by firmware\n");
|
||||
- } else if (ret) {
|
||||
+ if (ret) {
|
||||
phy_exit(pcie->phy);
|
||||
return ret;
|
||||
}
|
Loading…
Reference in New Issue
Block a user