summaryrefslogtreecommitdiffstats
path: root/net/dsa/dsa2.c
blob: c66abbed4daf21f650f86e4d073c51657854d9b7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
OC.L10N.register(
    "news",
    {
    "Feed contains invalid XML" : "無効なXMLを含むフィードです。",
    "Could not find a feed" : "フィードが見つかりませんでした。",
    "Detected feed format is not supported" : "検出したフィードのフォーマットはサポートされません。",
    "SSL Certificate is invalid" : "無効なSSL証明書です。",
    "Website not found" : "Webサイトが見つかりませんでした。",
    "More redirects than allowed, aborting" : "リダイレクト数が許可数より多いです、中止します。",
    "Bigger than maximum allowed size" : "最大許容サイズより大きいです。",
    "Request timed out" : "リクエストがタイムアウトしました。",
    "Request failed, network connection unavailable!" : "リクエストに失敗しました。ネットワーク接続が利用できません!",
    "Request unauthorized. Are you logged in?" : "リクエストは認証されていません。ログインしていますか?",
    "Request forbidden. Are you an admin?" : "リクエストは禁止されています。あなたは管理者でしょうか?",
    "Token expired or app not enabled! Reload the page!" : "トークンもしくはアプリが無効になりました!ページを再読込してください!",
    "Internal server error! Please check your " : "内部サーバーエラー! 以下をチェック:",
    "Request failed, ownCloud is in currently " : "リクエストに失敗したので、ownCloudは現在",
    "Can not add feed: Exists already" : "フィードを追加できません: すでに存在します",
    "Articles without feed" : "フィードなし記事",
    "Can not add folder: Exists already" : "フォルダーを追加できません: すでに存在します",
    "Use ownCloud cron for updates" : "ownCloud cronをアップデートに使用",
    "Disable this if you run a custom updater such as the Python updater included in the app" : "アプリに含まれるPython アップデータのようなカスタムアップデータを使用する場合は無効にしてください",
    "Purge interval" : "パージ周期",
    "Minimum amount of seconds after deleted feeds and folders are removed from the database; values below 60 seconds are ignored" : "削除されたフィードとフォルダーがデータベースから削除されるまでの秒数;60秒以下の値は無視されます",
    "Maximum read count per feed" : "フィード当たりの最大閲覧数",
    "Defines the maximum amount of articles that can be read per feed which won't be deleted by the cleanup job; if old articles reappear after being read, increase this value; negative values such as -1 will turn this feature off completely" : "クリーンナップジョブにより削除されないフィードごとに読むことができる記事の最大数を定義します; 既読の古い記事が再び現れた場合に、この値を増やします; -1 のような負の値は完全にこの機能をオフにします",
    "Maximum redirects" : "最大リダイレクト数",
    "How many redirects the feed fetcher should follow" : "フィードフェッチャーに許可するリダイレクト数",
    "Maximum feed page size" : "最大フィードページサイズ",
    "Maximum feed size in bytes. If the RSS/Atom page is bigger than this value, the update will be aborted" : "最大フィードサイズのバイト数。RSS/Atomページが設定値より大きい場合、更新は中止されます。",
    "Feed fetcher timeout" : "フィードフェッチャーのタイムアウト",
    "Maximum number of seconds to wait for an RSS or Atom feed to load; if it takes longer the update will be aborted" : "RSS / Atom フィードの読み込み待機秒数の制限;設定時間より長くかかる場合はアップデートが中止されます。",
    "Explore Service URL" : "サービスURLの探索",
    "If given, this service's URL will be queried for displaying the feeds in the explore feed section. To fall back to the built in explore service, leave this input empty" : "指定された場合は、このサービスのURLは探索フィードセクションでフィードを表示するために照会されます。内蔵の探索サービスへ戻すには、この項目を空欄にしてください",
    "Saved" : "保存されました",
    "Download" : "ダウンロード",
    "Close" : "閉じる",
    "Ajax or webcron cron mode detected! Your feeds will not be updated correctly. It is recommended to either use the operating system cron or a custom updater." : "Ajax または webcron cron モードが検出されました!フィードは正しく更新されません。オペレーティングシステムの cron か、カスタムアップデーターの使用をお勧めします。",
    "How to set up the operating system cron" : "OSのcronのやり方",
    "How to set up a custom updater (faster and no possible deadlock) " : "カストムアップデータのセットアップ(早いと行き詰まりにくい)",
    "Subscribe" : "購読",
    "Refresh" : "同期",
    "No articles available" : "記事がありません",
    "No unread articles available" : "未読記事がありません",
    "Open website" : "ウェブサイトを開く",
    "Star article" : "スター付きの記事",
    "Unstar article" : "スターなしの記事",
    "Keep article unread" : "記事を未読のままにする",
    "Remove keep article unread" : "記事の未読保持を解除",
    "by" : "by",
    "from" : "開始",
    "Play audio" : "音楽を再生",
    "Download video" : "動画をダウンロード",
    "Download audio" : "音楽をダウンロード",
    "Keyboard shortcut" : "キーボードショートカット",
    "Description" : "説明",
    "right" : "右",
    "Jump to next article" : "次の記事へジャンプ",
    "left" : "左",
    "Jump to previous article" : "前の記事へジャンプ",
    "Toggle star article" : "スター付きの記事を切り替え",
    "Star article and jump to next one" : "記事にスターを付けて次へ",
    "Toggle keep current article unread" : "現在の記事の
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * net/dsa/dsa2.c - Hardware switch handling, binding version 2
 * Copyright (c) 2008-2009 Marvell Semiconductor
 * Copyright (c) 2013 Florian Fainelli <florian@openwrt.org>
 * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch>
 */

#include <linux/device.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <linux/slab.h>
#include <linux/rtnetlink.h>
#include <linux/of.h>
#include <linux/of_net.h>
#include <net/devlink.h>

#include "dsa_priv.h"

static LIST_HEAD(dsa_tree_list);
static DEFINE_MUTEX(dsa2_mutex);

static const struct devlink_ops dsa_devlink_ops = {
};

static struct dsa_switch_tree *dsa_tree_find(int index)
{
	struct dsa_switch_tree *dst;

	list_for_each_entry(dst, &dsa_tree_list, list)
		if (dst->index == index)
			return dst;

	return NULL;
}

static struct dsa_switch_tree *dsa_tree_alloc(int index)
{
	struct dsa_switch_tree *dst;

	dst = kzalloc(sizeof(*dst), GFP_KERNEL);
	if (!dst)
		return NULL;

	dst->index = index;

	INIT_LIST_HEAD(&dst->rtable);

	INIT_LIST_HEAD(&dst->ports);

	INIT_LIST_HEAD(&dst->list);
	list_add_tail(&dst->list, &dsa_tree_list);

	kref_init(&dst->refcount);

	return dst;
}

static void dsa_tree_free(struct dsa_switch_tree *dst)
{
	list_del(&dst->list);
	kfree(dst);
}

static struct dsa_switch_tree *dsa_tree_get(struct dsa_switch_tree *dst)
{
	if (dst)
		kref_get(&dst->refcount);

	return dst;
}

static struct dsa_switch_tree *dsa_tree_touch(int index)
{
	struct dsa_switch_tree *dst;

	dst = dsa_tree_find(index);
	if (dst)
		return dsa_tree_get(dst);
	else
		return dsa_tree_alloc(index);
}

static void dsa_tree_release(struct kref *ref)
{
	struct dsa_switch_tree *dst;

	dst = container_of(ref, struct dsa_switch_tree, refcount);

	dsa_tree_free(dst);
}

static void dsa_tree_put(struct dsa_switch_tree *dst)
{
	if (dst)
		kref_put(&dst->refcount, dsa_tree_release);
}

static bool dsa_port_is_dsa(struct dsa_port *port)
{
	return port->type == DSA_PORT_TYPE_DSA;
}

static bool dsa_port_is_cpu(struct dsa_port *port)
{
	return port->type == DSA_PORT_TYPE_CPU;
}

static bool dsa_port_is_user(struct dsa_port *dp)
{
	return dp->type == DSA_PORT_TYPE_USER;
}

static struct dsa_port *dsa_tree_find_port_by_node(struct dsa_switch_tree *dst,
						   struct device_node *dn)
{
	struct dsa_port *dp;

	list_for_each_entry(dp, &dst->ports, list)
		if (dp->dn == dn)
			return dp;

	return NULL;
}

static struct dsa_link *dsa_link_touch(struct dsa_port *dp,
				       struct dsa_port *link_dp)
{
	struct dsa_switch *ds = dp->ds;
	struct dsa_switch_tree *dst;
	struct dsa_link *dl;

	dst = ds->dst;

	list_for_each_entry(dl, &dst->rtable, list)
		if (dl->dp == dp && dl->link_dp == link_dp)
			return dl;

	dl = kzalloc(sizeof(*dl), GFP_KERNEL);
	if (!dl)
		return NULL;

	dl->dp = dp;
	dl->link_dp = link_dp;

	INIT_LIST_HEAD(&dl->list);
	list_add_tail(&dl->list, &dst->rtable);

	return dl;
}

static bool dsa_port_setup_routing_table(struct dsa_port *dp)
{
	struct dsa_switch *ds = dp->ds;
	struct dsa_switch_tree *dst = ds->dst;
	struct device_node *dn = dp->dn;
	struct of_phandle_iterator it;
	struct dsa_port *link_dp;
	struct dsa_link *dl;
	int err;

	of_for_each_phandle(&it, err, dn, "link", NULL, 0) {
		link_dp = dsa_tree_find_port_by_node(dst, it.node);
		if (!link_dp) {
			of_node_put(it.node);
			return false;
		}

		dl = dsa_link_touch(dp, link_dp);
		if (!dl) {
			of_node_put(it.node);
			return false;
		}
	}

	return true;
}

static bool dsa_tree_setup_routing_table(struct dsa_switch_tree *dst)
{
	bool complete = true;
	struct dsa_port *dp;

	list_for_each_entry(dp, &dst->ports, list) {
		if (dsa_port_is_dsa(