~funderscore blog cgit wiki get in touch
aboutsummaryrefslogtreecommitdiff
blob: 9fa9d4e785398326a8f2e83221b53cd273aa32ec (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
/* SPDX-License-Identifier: GPL-2.0+ */
/*
 * Copyright 2019-2021 NXP
 */

#ifndef __DSA_H__
#define __DSA_H__

#include <dm/ofnode.h>
#include <phy.h>
#include <net.h>

/**
 * DSA stands for Distributed Switch Architecture and it is infrastructure
 * intended to support drivers for Switches that rely on an intermediary
 * Ethernet device for I/O.  These switches may support cascading allowing
 * them to be arranged as a tree.
 * DSA is documented in detail in the Linux kernel documentation under
 * Documentation/networking/dsa/dsa.txt
 * The network layout of such a switch is shown below:
 *
 *                      |------|
 *                      | eth0 | <--- master eth device (regular eth driver)
 *                      |------|
 *                        ^  |
 * tag added by switch -->|  |
 *                        |  |
 *                        |  |<-- tag added by DSA driver
 *                        |  v
 *      |--------------------------------------|
 *      |             | CPU port |             | <-- DSA (switch) device
 *      |             ------------             |     (DSA driver)
 *      | _________  _________       _________ |
 *      | | port0 |  | port1 |  ...  | portn | | <-- ports as eth devices
 *      |-+-------+--+-------+-------+-------+-|     ('dsa-port' eth driver)
 *
 * In U-Boot the intent is to allow access to front panel ports (shown at the
 * bottom of the picture) through the master Ethernet dev (eth0 in the picture).
 * Front panel ports are presented as regular Ethernet devices in U-Boot and
 * they are expected to support the typical networking commands.
 * In general DSA switches require the use of tags, extra headers added both by
 * software on Tx and by the switch on Rx.  These tags carry at a minimum port
 * information and switch information for cascaded set-ups.
 * In U-Boot these tags are inserted and parsed by the DSA switch driver, the
 * class code helps with headroom/tailroom for the extra headers.
 *
 * TODO:
 * - handle switch cascading, for now U-Boot only supports stand-alone switches.
 * - Add support to probe DSA switches connected to a MDIO bus, this is needed
 * to convert switch drivers that are now under drivers/net/phy.
 */

#define DSA_PORT_NAME_LENGTH	16

/* Maximum number of ports each DSA device can have */
#define DSA_MAX_PORTS		12

/**
 * struct dsa_ops - DSA operations
 *
 * @port_probe:   Initialize a switch port.
 * @port_enable:  Enable I/O for a port.
 * @port_disable: Disable I/O for a port.
 * @xmit:         Insert the DSA tag for transmission.
 *                DSA drivers receive a copy of the packet with headroom and
 *                tailroom reserved and set to 0. 'packet' points to headroom
 *                and 'length' is updated to include both head and tailroom.
 * @rcv:          Process the DSA tag on reception and return the port index
 *                from the h/w provided tag. Return the index via 'portp'.
 *                'packet' and 'length' describe the frame as received from
 *                master including any additional headers.
 */
struct dsa_ops {
	int (*port_probe)(struct udevice *dev, int port,
			  struct phy_device *phy);
	int (*port_enable)(struct udevice *dev, int port,
			   struct phy_device *phy);
	void (*port_disable)(struct udevice *dev, int port,
			     struct phy_device *phy);
	int (*xmit)(struct udevice *dev, int port, void *packet, int length);
	int (*rcv)(struct udevice *dev, int *portp, void *packet, int length);
};

#define dsa_get_ops(dev) ((struct dsa_ops *)(dev)->driver->ops)

/**
 * struct dsa_port_pdata - DSA port platform data
 *
 * @phy:   PHY device associated with this port.
 *         The uclass code attempts to set this field for all ports except CPU
 *         port, based on DT information.  It may be NULL.
 * @index: Port index in the DSA switch, set by the uclass code.
 * @name:  Name of the port Eth device.  If a label property is present in the
 *         port DT node, it is used as name.
 */
struct dsa_port_pdata {
	struct phy_device *phy;
	u32 index;
	char name[DSA_PORT_NAME_LENGTH];
};

/**
 * struct dsa_pdata - Per-device platform data for DSA DM
 *
 * @num_ports:   Number of ports the device has, must be <= DSA_MAX_PORTS.
 *		 This number is extracted from the DT 'ports' node of this
 *		 DSA device, and it counts the CPU port and all the other
 *		 port subnodes including the disabled ones.
 * @cpu_port:    Index of the switch port linked to the master Ethernet.
 *		 The uclass code sets this based on DT information.
 * @master_node: OF node of the host Ethernet controller.
 * @cpu_port_node: DT node of the switch's CPU port.
 */
struct dsa_pdata {
	int num_ports;
	u32 cpu_port;
	ofnode master_node;
	ofnode cpu_port_node;
};

/**
 * dsa_set_tagging() - Configure the headroom and/or tailroom sizes
 *
 * The DSA class code allocates headroom and tailroom on Tx before
 * calling the DSA driver's xmit function.
 * All drivers must call this at probe time.
 *
 * @dev:	DSA device pointer
 * @headroom:	Size, in bytes, of headroom needed for the DSA tag.
 * @tailroom:	Size, in bytes, of tailroom needed for the DSA tag.
 *		Total headroom and tailroom size should not exceed
 *		DSA_MAX_OVR.
 * Return: 0 if OK, -ve on error
 */
int dsa_set_tagging(struct udevice *dev, ushort headroom, ushort tailroom);

/* DSA helpers */

/**
 * dsa_get_master() - Return a reference to the master Ethernet device
 *
 * Can be called at driver probe time or later.
 *
 * @dev:	DSA device pointer
 * Return: Master Eth 'udevice' pointer if OK, NULL on error
 */
struct udevice *dsa_get_master(struct udevice *dev);

/**
 * dsa_port_get_ofnode() - Return a reference to the given port's OF node
 *
 * Can be called at driver probe time or later.
 *
 * @dev:	DSA switch udevice pointer
 * @port:	Port index
 * Return: OF node reference if OK, NULL on error
 */
ofnode dsa_port_get_ofnode(struct udevice *dev, int port);

/**
 * dsa_port_get_pdata() - Helper that returns the platdata of an active
 *			(non-CPU) DSA port device.
 *
 * Can be called at driver probe time or later.
 *
 * @pdev:	DSA port device pointer
 * Return: 'dsa_port_pdata' pointer if OK, NULL on error
 */
static inline struct dsa_port_pdata *
	dsa_port_get_pdata(struct udevice *pdev)
{
	struct eth_pdata *eth = dev_get_plat(pdev);

	if (!eth)
		return NULL;

	return eth->priv_pdata;
}

#endif /* __DSA_H__ */