blob: 44136ee015c3a66c0ff3ad27df8f00f71ef19ba4 [file] [log] [blame]
Vivien Didelota935c052016-09-29 12:21:53 -04001/*
2 * Marvell 88E6xxx Switch Global (1) Registers support
3 *
4 * Copyright (c) 2008 Marvell Semiconductor
5 *
6 * Copyright (c) 2016 Vivien Didelot <vivien.didelot@savoirfairelinux.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#include "mv88e6xxx.h"
15#include "global1.h"
16
17int mv88e6xxx_g1_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
18{
19 int addr = chip->info->global1_addr;
20
21 return mv88e6xxx_read(chip, addr, reg, val);
22}
23
24int mv88e6xxx_g1_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
25{
26 int addr = chip->info->global1_addr;
27
28 return mv88e6xxx_write(chip, addr, reg, val);
29}
30
31int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask)
32{
33 return mv88e6xxx_wait(chip, chip->info->global1_addr, reg, mask);
34}
Andrew Lunna605a0f2016-11-21 23:26:58 +010035
Andrew Lunn33641992016-12-03 04:35:17 +010036/* Offset 0x1a: Monitor Control */
37/* Offset 0x1a: Monitor & MGMT Control on some devices */
38
39int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port)
40{
41 u16 reg;
42 int err;
43
44 err = mv88e6xxx_g1_read(chip, GLOBAL_MONITOR_CONTROL, &reg);
45 if (err)
46 return err;
47
48 reg &= ~(GLOBAL_MONITOR_CONTROL_INGRESS_MASK |
49 GLOBAL_MONITOR_CONTROL_EGRESS_MASK);
50
51 reg |= port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT |
52 port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT;
53
54 return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
55}
56
57/* Older generations also call this the ARP destination. It has been
58 * generalized in more modern devices such that more than ARP can
59 * egress it
60 */
61int mv88e6095_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port)
62{
63 u16 reg;
64 int err;
65
66 err = mv88e6xxx_g1_read(chip, GLOBAL_MONITOR_CONTROL, &reg);
67 if (err)
68 return err;
69
70 reg &= ~GLOBAL_MONITOR_CONTROL_ARP_MASK;
71 reg |= port << GLOBAL_MONITOR_CONTROL_ARP_SHIFT;
72
73 return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
74}
75
76static int mv88e6390_g1_monitor_write(struct mv88e6xxx_chip *chip,
77 u16 pointer, u8 data)
78{
79 u16 reg;
80
81 reg = GLOBAL_MONITOR_CONTROL_UPDATE | pointer | data;
82
83 return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg);
84}
85
86int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port)
87{
88 int err;
89
90 err = mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_INGRESS,
91 port);
92 if (err)
93 return err;
94
95 return mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_EGRESS,
96 port);
97}
98
99int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port)
100{
101 return mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_CPU_DEST,
102 port);
103}
104
Andrew Lunn6e55f692016-12-03 04:45:16 +0100105int mv88e6390_g1_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip)
106{
107 int err;
108
109 /* 01:c2:80:00:00:00:00-01:c2:80:00:00:00:07 are Management */
110 err = mv88e6390_g1_monitor_write(
111 chip, GLOBAL_MONITOR_CONTROL_0180C280000000XLO, 0xff);
112 if (err)
113 return err;
114
115 /* 01:c2:80:00:00:00:08-01:c2:80:00:00:00:0f are Management */
116 err = mv88e6390_g1_monitor_write(
117 chip, GLOBAL_MONITOR_CONTROL_0180C280000000XHI, 0xff);
118 if (err)
119 return err;
120
121 /* 01:c2:80:00:00:00:20-01:c2:80:00:00:00:27 are Management */
122 err = mv88e6390_g1_monitor_write(
123 chip, GLOBAL_MONITOR_CONTROL_0180C280000002XLO, 0xff);
124 if (err)
125 return err;
126
127 /* 01:c2:80:00:00:00:28-01:c2:80:00:00:00:2f are Management */
128 return mv88e6390_g1_monitor_write(
129 chip, GLOBAL_MONITOR_CONTROL_0180C280000002XHI, 0xff);
130}
131
Andrew Lunnde2273872016-11-21 23:27:01 +0100132/* Offset 0x1c: Global Control 2 */
133
134int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip)
135{
136 u16 val;
137 int err;
138
139 err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL_2, &val);
140 if (err)
141 return err;
142
143 val |= GLOBAL_CONTROL_2_HIST_RX_TX;
144
145 err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL_2, val);
146
147 return err;
148}
149
150/* Offset 0x1d: Statistics Operation 2 */
151
Andrew Lunn7f9ef3a2016-11-21 23:27:05 +0100152int mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip *chip)
Andrew Lunna605a0f2016-11-21 23:26:58 +0100153{
154 return mv88e6xxx_g1_wait(chip, GLOBAL_STATS_OP, GLOBAL_STATS_OP_BUSY);
155}
156
157int mv88e6xxx_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
158{
159 int err;
160
161 /* Snapshot the hardware statistics counters for this port. */
162 err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
163 GLOBAL_STATS_OP_CAPTURE_PORT |
164 GLOBAL_STATS_OP_HIST_RX_TX | port);
165 if (err)
166 return err;
167
168 /* Wait for the snapshotting to complete. */
169 return mv88e6xxx_g1_stats_wait(chip);
170}
171
172int mv88e6320_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
173{
174 port = (port + 1) << 5;
175
176 return mv88e6xxx_g1_stats_snapshot(chip, port);
177}
Andrew Lunn79523472016-11-21 23:27:00 +0100178
179int mv88e6390_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port)
180{
181 int err;
182
183 port = (port + 1) << 5;
184
185 /* Snapshot the hardware statistics counters for this port. */
186 err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
187 GLOBAL_STATS_OP_CAPTURE_PORT | port);
188 if (err)
189 return err;
190
191 /* Wait for the snapshotting to complete. */
192 return mv88e6xxx_g1_stats_wait(chip);
193}
Andrew Lunn7f9ef3a2016-11-21 23:27:05 +0100194
195void mv88e6xxx_g1_stats_read(struct mv88e6xxx_chip *chip, int stat, u32 *val)
196{
197 u32 value;
198 u16 reg;
199 int err;
200
201 *val = 0;
202
203 err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP,
204 GLOBAL_STATS_OP_READ_CAPTURED | stat);
205 if (err)
206 return;
207
208 err = mv88e6xxx_g1_stats_wait(chip);
209 if (err)
210 return;
211
212 err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_COUNTER_32, &reg);
213 if (err)
214 return;
215
216 value = reg << 16;
217
218 err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_COUNTER_01, &reg);
219 if (err)
220 return;
221
222 *val = value | reg;
223}