Vivien Didelot | a935c05 | 2016-09-29 12:21:53 -0400 | [diff] [blame] | 1 | /* |
| 2 | * Marvell 88E6xxx Switch Global (1) Registers support |
| 3 | * |
| 4 | * Copyright (c) 2008 Marvell Semiconductor |
| 5 | * |
Vivien Didelot | 4333d61 | 2017-03-28 15:10:36 -0400 | [diff] [blame] | 6 | * Copyright (c) 2016-2017 Savoir-faire Linux Inc. |
| 7 | * Vivien Didelot <vivien.didelot@savoirfairelinux.com> |
Vivien Didelot | a935c05 | 2016-09-29 12:21:53 -0400 | [diff] [blame] | 8 | * |
| 9 | * This program is free software; you can redistribute it and/or modify |
| 10 | * it under the terms of the GNU General Public License as published by |
| 11 | * the Free Software Foundation; either version 2 of the License, or |
| 12 | * (at your option) any later version. |
| 13 | */ |
| 14 | |
Vivien Didelot | 101515c | 2017-06-15 12:14:04 -0400 | [diff] [blame] | 15 | #include <linux/bitfield.h> |
| 16 | |
Vivien Didelot | 4d5f2ba7 | 2017-06-02 17:06:15 -0400 | [diff] [blame] | 17 | #include "chip.h" |
Vivien Didelot | a935c05 | 2016-09-29 12:21:53 -0400 | [diff] [blame] | 18 | #include "global1.h" |
| 19 | |
| 20 | int mv88e6xxx_g1_read(struct mv88e6xxx_chip *chip, int reg, u16 *val) |
| 21 | { |
| 22 | int addr = chip->info->global1_addr; |
| 23 | |
| 24 | return mv88e6xxx_read(chip, addr, reg, val); |
| 25 | } |
| 26 | |
| 27 | int mv88e6xxx_g1_write(struct mv88e6xxx_chip *chip, int reg, u16 val) |
| 28 | { |
| 29 | int addr = chip->info->global1_addr; |
| 30 | |
| 31 | return mv88e6xxx_write(chip, addr, reg, val); |
| 32 | } |
| 33 | |
| 34 | int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask) |
| 35 | { |
| 36 | return mv88e6xxx_wait(chip, chip->info->global1_addr, reg, mask); |
| 37 | } |
Andrew Lunn | a605a0f | 2016-11-21 23:26:58 +0100 | [diff] [blame] | 38 | |
Vivien Didelot | 17e708b | 2016-12-05 17:30:27 -0500 | [diff] [blame] | 39 | /* Offset 0x00: Switch Global Status Register */ |
| 40 | |
Vivien Didelot | a199d8b | 2016-12-05 17:30:28 -0500 | [diff] [blame] | 41 | static int mv88e6185_g1_wait_ppu_disabled(struct mv88e6xxx_chip *chip) |
| 42 | { |
| 43 | u16 state; |
| 44 | int i, err; |
| 45 | |
| 46 | for (i = 0; i < 16; i++) { |
Vivien Didelot | 8246692 | 2017-06-15 12:13:59 -0400 | [diff] [blame] | 47 | err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &state); |
Vivien Didelot | a199d8b | 2016-12-05 17:30:28 -0500 | [diff] [blame] | 48 | if (err) |
| 49 | return err; |
| 50 | |
| 51 | /* Check the value of the PPUState bits 15:14 */ |
Vivien Didelot | 8246692 | 2017-06-15 12:13:59 -0400 | [diff] [blame] | 52 | state &= MV88E6185_G1_STS_PPU_STATE_MASK; |
| 53 | if (state != MV88E6185_G1_STS_PPU_STATE_POLLING) |
Vivien Didelot | a199d8b | 2016-12-05 17:30:28 -0500 | [diff] [blame] | 54 | return 0; |
| 55 | |
| 56 | usleep_range(1000, 2000); |
| 57 | } |
| 58 | |
| 59 | return -ETIMEDOUT; |
| 60 | } |
| 61 | |
Vivien Didelot | 17e708b | 2016-12-05 17:30:27 -0500 | [diff] [blame] | 62 | static int mv88e6185_g1_wait_ppu_polling(struct mv88e6xxx_chip *chip) |
| 63 | { |
| 64 | u16 state; |
| 65 | int i, err; |
| 66 | |
| 67 | for (i = 0; i < 16; ++i) { |
Vivien Didelot | 8246692 | 2017-06-15 12:13:59 -0400 | [diff] [blame] | 68 | err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &state); |
Vivien Didelot | 17e708b | 2016-12-05 17:30:27 -0500 | [diff] [blame] | 69 | if (err) |
| 70 | return err; |
| 71 | |
| 72 | /* Check the value of the PPUState bits 15:14 */ |
Vivien Didelot | 8246692 | 2017-06-15 12:13:59 -0400 | [diff] [blame] | 73 | state &= MV88E6185_G1_STS_PPU_STATE_MASK; |
| 74 | if (state == MV88E6185_G1_STS_PPU_STATE_POLLING) |
Vivien Didelot | 17e708b | 2016-12-05 17:30:27 -0500 | [diff] [blame] | 75 | return 0; |
| 76 | |
| 77 | usleep_range(1000, 2000); |
| 78 | } |
| 79 | |
| 80 | return -ETIMEDOUT; |
| 81 | } |
| 82 | |
| 83 | static int mv88e6352_g1_wait_ppu_polling(struct mv88e6xxx_chip *chip) |
| 84 | { |
| 85 | u16 state; |
| 86 | int i, err; |
| 87 | |
| 88 | for (i = 0; i < 16; ++i) { |
Vivien Didelot | 8246692 | 2017-06-15 12:13:59 -0400 | [diff] [blame] | 89 | err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &state); |
Vivien Didelot | 17e708b | 2016-12-05 17:30:27 -0500 | [diff] [blame] | 90 | if (err) |
| 91 | return err; |
| 92 | |
| 93 | /* Check the value of the PPUState (or InitState) bit 15 */ |
Vivien Didelot | 8246692 | 2017-06-15 12:13:59 -0400 | [diff] [blame] | 94 | if (state & MV88E6352_G1_STS_PPU_STATE) |
Vivien Didelot | 17e708b | 2016-12-05 17:30:27 -0500 | [diff] [blame] | 95 | return 0; |
| 96 | |
| 97 | usleep_range(1000, 2000); |
| 98 | } |
| 99 | |
| 100 | return -ETIMEDOUT; |
| 101 | } |
| 102 | |
| 103 | static int mv88e6xxx_g1_wait_init_ready(struct mv88e6xxx_chip *chip) |
| 104 | { |
| 105 | const unsigned long timeout = jiffies + 1 * HZ; |
| 106 | u16 val; |
| 107 | int err; |
| 108 | |
| 109 | /* Wait up to 1 second for the switch to be ready. The InitReady bit 11 |
| 110 | * is set to a one when all units inside the device (ATU, VTU, etc.) |
| 111 | * have finished their initialization and are ready to accept frames. |
| 112 | */ |
| 113 | while (time_before(jiffies, timeout)) { |
Vivien Didelot | 8246692 | 2017-06-15 12:13:59 -0400 | [diff] [blame] | 114 | err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &val); |
Vivien Didelot | 17e708b | 2016-12-05 17:30:27 -0500 | [diff] [blame] | 115 | if (err) |
| 116 | return err; |
| 117 | |
Vivien Didelot | 8246692 | 2017-06-15 12:13:59 -0400 | [diff] [blame] | 118 | if (val & MV88E6XXX_G1_STS_INIT_READY) |
Vivien Didelot | 17e708b | 2016-12-05 17:30:27 -0500 | [diff] [blame] | 119 | break; |
| 120 | |
| 121 | usleep_range(1000, 2000); |
| 122 | } |
| 123 | |
| 124 | if (time_after(jiffies, timeout)) |
| 125 | return -ETIMEDOUT; |
| 126 | |
| 127 | return 0; |
| 128 | } |
| 129 | |
Vivien Didelot | 4b0c481 | 2017-06-15 12:14:00 -0400 | [diff] [blame] | 130 | /* Offset 0x01: Switch MAC Address Register Bytes 0 & 1 |
| 131 | * Offset 0x02: Switch MAC Address Register Bytes 2 & 3 |
| 132 | * Offset 0x03: Switch MAC Address Register Bytes 4 & 5 |
| 133 | */ |
| 134 | int mv88e6xxx_g1_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr) |
| 135 | { |
| 136 | u16 reg; |
| 137 | int err; |
| 138 | |
| 139 | reg = (addr[0] << 8) | addr[1]; |
| 140 | err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_MAC_01, reg); |
| 141 | if (err) |
| 142 | return err; |
| 143 | |
| 144 | reg = (addr[2] << 8) | addr[3]; |
| 145 | err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_MAC_23, reg); |
| 146 | if (err) |
| 147 | return err; |
| 148 | |
| 149 | reg = (addr[4] << 8) | addr[5]; |
| 150 | err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_MAC_45, reg); |
| 151 | if (err) |
| 152 | return err; |
| 153 | |
| 154 | return 0; |
| 155 | } |
| 156 | |
Vivien Didelot | 17e708b | 2016-12-05 17:30:27 -0500 | [diff] [blame] | 157 | /* Offset 0x04: Switch Global Control Register */ |
| 158 | |
| 159 | int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip) |
| 160 | { |
| 161 | u16 val; |
| 162 | int err; |
| 163 | |
| 164 | /* Set the SWReset bit 15 along with the PPUEn bit 14, to also restart |
| 165 | * the PPU, including re-doing PHY detection and initialization |
| 166 | */ |
Vivien Didelot | d77f432 | 2017-06-15 12:14:03 -0400 | [diff] [blame] | 167 | err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &val); |
Vivien Didelot | 17e708b | 2016-12-05 17:30:27 -0500 | [diff] [blame] | 168 | if (err) |
| 169 | return err; |
| 170 | |
Vivien Didelot | d77f432 | 2017-06-15 12:14:03 -0400 | [diff] [blame] | 171 | val |= MV88E6XXX_G1_CTL1_SW_RESET; |
| 172 | val |= MV88E6XXX_G1_CTL1_PPU_ENABLE; |
Vivien Didelot | 17e708b | 2016-12-05 17:30:27 -0500 | [diff] [blame] | 173 | |
Vivien Didelot | d77f432 | 2017-06-15 12:14:03 -0400 | [diff] [blame] | 174 | err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, val); |
Vivien Didelot | 17e708b | 2016-12-05 17:30:27 -0500 | [diff] [blame] | 175 | if (err) |
| 176 | return err; |
| 177 | |
| 178 | err = mv88e6xxx_g1_wait_init_ready(chip); |
| 179 | if (err) |
| 180 | return err; |
| 181 | |
| 182 | return mv88e6185_g1_wait_ppu_polling(chip); |
| 183 | } |
| 184 | |
| 185 | int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip) |
| 186 | { |
| 187 | u16 val; |
| 188 | int err; |
| 189 | |
| 190 | /* Set the SWReset bit 15 */ |
Vivien Didelot | d77f432 | 2017-06-15 12:14:03 -0400 | [diff] [blame] | 191 | err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &val); |
Vivien Didelot | 17e708b | 2016-12-05 17:30:27 -0500 | [diff] [blame] | 192 | if (err) |
| 193 | return err; |
| 194 | |
Vivien Didelot | d77f432 | 2017-06-15 12:14:03 -0400 | [diff] [blame] | 195 | val |= MV88E6XXX_G1_CTL1_SW_RESET; |
Vivien Didelot | 17e708b | 2016-12-05 17:30:27 -0500 | [diff] [blame] | 196 | |
Vivien Didelot | d77f432 | 2017-06-15 12:14:03 -0400 | [diff] [blame] | 197 | err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, val); |
Vivien Didelot | 17e708b | 2016-12-05 17:30:27 -0500 | [diff] [blame] | 198 | if (err) |
| 199 | return err; |
| 200 | |
| 201 | err = mv88e6xxx_g1_wait_init_ready(chip); |
| 202 | if (err) |
| 203 | return err; |
| 204 | |
| 205 | return mv88e6352_g1_wait_ppu_polling(chip); |
| 206 | } |
| 207 | |
Vivien Didelot | a199d8b | 2016-12-05 17:30:28 -0500 | [diff] [blame] | 208 | int mv88e6185_g1_ppu_enable(struct mv88e6xxx_chip *chip) |
| 209 | { |
| 210 | u16 val; |
| 211 | int err; |
| 212 | |
Vivien Didelot | d77f432 | 2017-06-15 12:14:03 -0400 | [diff] [blame] | 213 | err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &val); |
Vivien Didelot | a199d8b | 2016-12-05 17:30:28 -0500 | [diff] [blame] | 214 | if (err) |
| 215 | return err; |
| 216 | |
Vivien Didelot | d77f432 | 2017-06-15 12:14:03 -0400 | [diff] [blame] | 217 | val |= MV88E6XXX_G1_CTL1_PPU_ENABLE; |
Vivien Didelot | a199d8b | 2016-12-05 17:30:28 -0500 | [diff] [blame] | 218 | |
Vivien Didelot | d77f432 | 2017-06-15 12:14:03 -0400 | [diff] [blame] | 219 | err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, val); |
Vivien Didelot | a199d8b | 2016-12-05 17:30:28 -0500 | [diff] [blame] | 220 | if (err) |
| 221 | return err; |
| 222 | |
| 223 | return mv88e6185_g1_wait_ppu_polling(chip); |
| 224 | } |
| 225 | |
| 226 | int mv88e6185_g1_ppu_disable(struct mv88e6xxx_chip *chip) |
| 227 | { |
| 228 | u16 val; |
| 229 | int err; |
| 230 | |
Vivien Didelot | d77f432 | 2017-06-15 12:14:03 -0400 | [diff] [blame] | 231 | err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL1, &val); |
Vivien Didelot | a199d8b | 2016-12-05 17:30:28 -0500 | [diff] [blame] | 232 | if (err) |
| 233 | return err; |
| 234 | |
Vivien Didelot | d77f432 | 2017-06-15 12:14:03 -0400 | [diff] [blame] | 235 | val &= ~MV88E6XXX_G1_CTL1_PPU_ENABLE; |
Vivien Didelot | a199d8b | 2016-12-05 17:30:28 -0500 | [diff] [blame] | 236 | |
Vivien Didelot | d77f432 | 2017-06-15 12:14:03 -0400 | [diff] [blame] | 237 | err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL1, val); |
Vivien Didelot | a199d8b | 2016-12-05 17:30:28 -0500 | [diff] [blame] | 238 | if (err) |
| 239 | return err; |
| 240 | |
| 241 | return mv88e6185_g1_wait_ppu_disabled(chip); |
| 242 | } |
| 243 | |
Andrew Lunn | 3364199 | 2016-12-03 04:35:17 +0100 | [diff] [blame] | 244 | /* Offset 0x1a: Monitor Control */ |
| 245 | /* Offset 0x1a: Monitor & MGMT Control on some devices */ |
| 246 | |
| 247 | int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port) |
| 248 | { |
| 249 | u16 reg; |
| 250 | int err; |
| 251 | |
Vivien Didelot | 101515c | 2017-06-15 12:14:04 -0400 | [diff] [blame] | 252 | err = mv88e6xxx_g1_read(chip, MV88E6185_G1_MONITOR_CTL, ®); |
Andrew Lunn | 3364199 | 2016-12-03 04:35:17 +0100 | [diff] [blame] | 253 | if (err) |
| 254 | return err; |
| 255 | |
Vivien Didelot | 101515c | 2017-06-15 12:14:04 -0400 | [diff] [blame] | 256 | reg &= ~(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK | |
| 257 | MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK); |
Andrew Lunn | 3364199 | 2016-12-03 04:35:17 +0100 | [diff] [blame] | 258 | |
Vivien Didelot | 101515c | 2017-06-15 12:14:04 -0400 | [diff] [blame] | 259 | reg |= port << __bf_shf(MV88E6185_G1_MONITOR_CTL_INGRESS_DEST_MASK) | |
| 260 | port << __bf_shf(MV88E6185_G1_MONITOR_CTL_EGRESS_DEST_MASK); |
Andrew Lunn | 3364199 | 2016-12-03 04:35:17 +0100 | [diff] [blame] | 261 | |
Vivien Didelot | 101515c | 2017-06-15 12:14:04 -0400 | [diff] [blame] | 262 | return mv88e6xxx_g1_write(chip, MV88E6185_G1_MONITOR_CTL, reg); |
Andrew Lunn | 3364199 | 2016-12-03 04:35:17 +0100 | [diff] [blame] | 263 | } |
| 264 | |
| 265 | /* Older generations also call this the ARP destination. It has been |
| 266 | * generalized in more modern devices such that more than ARP can |
| 267 | * egress it |
| 268 | */ |
| 269 | int mv88e6095_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port) |
| 270 | { |
| 271 | u16 reg; |
| 272 | int err; |
| 273 | |
Vivien Didelot | 101515c | 2017-06-15 12:14:04 -0400 | [diff] [blame] | 274 | err = mv88e6xxx_g1_read(chip, MV88E6185_G1_MONITOR_CTL, ®); |
Andrew Lunn | 3364199 | 2016-12-03 04:35:17 +0100 | [diff] [blame] | 275 | if (err) |
| 276 | return err; |
| 277 | |
Vivien Didelot | 101515c | 2017-06-15 12:14:04 -0400 | [diff] [blame] | 278 | reg &= ~MV88E6185_G1_MONITOR_CTL_ARP_DEST_MASK; |
| 279 | reg |= port << __bf_shf(MV88E6185_G1_MONITOR_CTL_ARP_DEST_MASK); |
Andrew Lunn | 3364199 | 2016-12-03 04:35:17 +0100 | [diff] [blame] | 280 | |
Vivien Didelot | 101515c | 2017-06-15 12:14:04 -0400 | [diff] [blame] | 281 | return mv88e6xxx_g1_write(chip, MV88E6185_G1_MONITOR_CTL, reg); |
Andrew Lunn | 3364199 | 2016-12-03 04:35:17 +0100 | [diff] [blame] | 282 | } |
| 283 | |
| 284 | static int mv88e6390_g1_monitor_write(struct mv88e6xxx_chip *chip, |
| 285 | u16 pointer, u8 data) |
| 286 | { |
| 287 | u16 reg; |
| 288 | |
Vivien Didelot | 101515c | 2017-06-15 12:14:04 -0400 | [diff] [blame] | 289 | reg = MV88E6390_G1_MONITOR_MGMT_CTL_UPDATE | pointer | data; |
Andrew Lunn | 3364199 | 2016-12-03 04:35:17 +0100 | [diff] [blame] | 290 | |
Vivien Didelot | 101515c | 2017-06-15 12:14:04 -0400 | [diff] [blame] | 291 | return mv88e6xxx_g1_write(chip, MV88E6390_G1_MONITOR_MGMT_CTL, reg); |
Andrew Lunn | 3364199 | 2016-12-03 04:35:17 +0100 | [diff] [blame] | 292 | } |
| 293 | |
| 294 | int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port) |
| 295 | { |
Vivien Didelot | 101515c | 2017-06-15 12:14:04 -0400 | [diff] [blame] | 296 | u16 ptr; |
Andrew Lunn | 3364199 | 2016-12-03 04:35:17 +0100 | [diff] [blame] | 297 | int err; |
| 298 | |
Vivien Didelot | 101515c | 2017-06-15 12:14:04 -0400 | [diff] [blame] | 299 | ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_INGRESS_DEST; |
| 300 | err = mv88e6390_g1_monitor_write(chip, ptr, port); |
Andrew Lunn | 3364199 | 2016-12-03 04:35:17 +0100 | [diff] [blame] | 301 | if (err) |
| 302 | return err; |
| 303 | |
Vivien Didelot | 101515c | 2017-06-15 12:14:04 -0400 | [diff] [blame] | 304 | ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_EGRESS_DEST; |
| 305 | err = mv88e6390_g1_monitor_write(chip, ptr, port); |
| 306 | if (err) |
| 307 | return err; |
| 308 | |
| 309 | return 0; |
Andrew Lunn | 3364199 | 2016-12-03 04:35:17 +0100 | [diff] [blame] | 310 | } |
| 311 | |
| 312 | int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port) |
| 313 | { |
Vivien Didelot | 101515c | 2017-06-15 12:14:04 -0400 | [diff] [blame] | 314 | u16 ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_CPU_DEST; |
| 315 | |
| 316 | return mv88e6390_g1_monitor_write(chip, ptr, port); |
Andrew Lunn | 3364199 | 2016-12-03 04:35:17 +0100 | [diff] [blame] | 317 | } |
| 318 | |
Andrew Lunn | 6e55f69 | 2016-12-03 04:45:16 +0100 | [diff] [blame] | 319 | int mv88e6390_g1_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip) |
| 320 | { |
Vivien Didelot | 101515c | 2017-06-15 12:14:04 -0400 | [diff] [blame] | 321 | u16 ptr; |
Andrew Lunn | 6e55f69 | 2016-12-03 04:45:16 +0100 | [diff] [blame] | 322 | int err; |
| 323 | |
| 324 | /* 01:c2:80:00:00:00:00-01:c2:80:00:00:00:07 are Management */ |
Vivien Didelot | 101515c | 2017-06-15 12:14:04 -0400 | [diff] [blame] | 325 | ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C280000000XLO; |
| 326 | err = mv88e6390_g1_monitor_write(chip, ptr, 0xff); |
Andrew Lunn | 6e55f69 | 2016-12-03 04:45:16 +0100 | [diff] [blame] | 327 | if (err) |
| 328 | return err; |
| 329 | |
| 330 | /* 01:c2:80:00:00:00:08-01:c2:80:00:00:00:0f are Management */ |
Vivien Didelot | 101515c | 2017-06-15 12:14:04 -0400 | [diff] [blame] | 331 | ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C280000000XHI; |
| 332 | err = mv88e6390_g1_monitor_write(chip, ptr, 0xff); |
Andrew Lunn | 6e55f69 | 2016-12-03 04:45:16 +0100 | [diff] [blame] | 333 | if (err) |
| 334 | return err; |
| 335 | |
| 336 | /* 01:c2:80:00:00:00:20-01:c2:80:00:00:00:27 are Management */ |
Vivien Didelot | 101515c | 2017-06-15 12:14:04 -0400 | [diff] [blame] | 337 | ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C280000002XLO; |
| 338 | err = mv88e6390_g1_monitor_write(chip, ptr, 0xff); |
Andrew Lunn | 6e55f69 | 2016-12-03 04:45:16 +0100 | [diff] [blame] | 339 | if (err) |
| 340 | return err; |
| 341 | |
| 342 | /* 01:c2:80:00:00:00:28-01:c2:80:00:00:00:2f are Management */ |
Vivien Didelot | 101515c | 2017-06-15 12:14:04 -0400 | [diff] [blame] | 343 | ptr = MV88E6390_G1_MONITOR_MGMT_CTL_PTR_0180C280000002XHI; |
| 344 | err = mv88e6390_g1_monitor_write(chip, ptr, 0xff); |
| 345 | if (err) |
| 346 | return err; |
| 347 | |
| 348 | return 0; |
Andrew Lunn | 6e55f69 | 2016-12-03 04:45:16 +0100 | [diff] [blame] | 349 | } |
| 350 | |
Andrew Lunn | de227387 | 2016-11-21 23:27:01 +0100 | [diff] [blame] | 351 | /* Offset 0x1c: Global Control 2 */ |
| 352 | |
| 353 | int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip) |
| 354 | { |
| 355 | u16 val; |
| 356 | int err; |
| 357 | |
Vivien Didelot | d77f432 | 2017-06-15 12:14:03 -0400 | [diff] [blame] | 358 | err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_CTL2, &val); |
Andrew Lunn | de227387 | 2016-11-21 23:27:01 +0100 | [diff] [blame] | 359 | if (err) |
| 360 | return err; |
| 361 | |
Vivien Didelot | d77f432 | 2017-06-15 12:14:03 -0400 | [diff] [blame] | 362 | val |= MV88E6XXX_G1_CTL2_HIST_RX_TX; |
Andrew Lunn | de227387 | 2016-11-21 23:27:01 +0100 | [diff] [blame] | 363 | |
Vivien Didelot | d77f432 | 2017-06-15 12:14:03 -0400 | [diff] [blame] | 364 | err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_CTL2, val); |
Andrew Lunn | de227387 | 2016-11-21 23:27:01 +0100 | [diff] [blame] | 365 | |
| 366 | return err; |
| 367 | } |
| 368 | |
| 369 | /* Offset 0x1d: Statistics Operation 2 */ |
| 370 | |
Andrew Lunn | 7f9ef3a | 2016-11-21 23:27:05 +0100 | [diff] [blame] | 371 | int mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip *chip) |
Andrew Lunn | a605a0f | 2016-11-21 23:26:58 +0100 | [diff] [blame] | 372 | { |
Vivien Didelot | 57d1ef3 | 2017-06-15 12:14:05 -0400 | [diff] [blame] | 373 | return mv88e6xxx_g1_wait(chip, MV88E6XXX_G1_STATS_OP, |
| 374 | MV88E6XXX_G1_STATS_OP_BUSY); |
Andrew Lunn | a605a0f | 2016-11-21 23:26:58 +0100 | [diff] [blame] | 375 | } |
| 376 | |
Andrew Lunn | 40cff8f | 2017-11-10 00:36:41 +0100 | [diff] [blame] | 377 | int mv88e6095_g1_stats_set_histogram(struct mv88e6xxx_chip *chip) |
| 378 | { |
| 379 | u16 val; |
| 380 | int err; |
| 381 | |
| 382 | err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STATS_OP, &val); |
| 383 | if (err) |
| 384 | return err; |
| 385 | |
| 386 | val |= MV88E6XXX_G1_STATS_OP_HIST_RX_TX; |
| 387 | |
| 388 | err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_STATS_OP, val); |
| 389 | |
| 390 | return err; |
| 391 | } |
| 392 | |
Andrew Lunn | a605a0f | 2016-11-21 23:26:58 +0100 | [diff] [blame] | 393 | int mv88e6xxx_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port) |
| 394 | { |
| 395 | int err; |
| 396 | |
| 397 | /* Snapshot the hardware statistics counters for this port. */ |
Vivien Didelot | 57d1ef3 | 2017-06-15 12:14:05 -0400 | [diff] [blame] | 398 | err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_STATS_OP, |
| 399 | MV88E6XXX_G1_STATS_OP_BUSY | |
| 400 | MV88E6XXX_G1_STATS_OP_CAPTURE_PORT | |
| 401 | MV88E6XXX_G1_STATS_OP_HIST_RX_TX | port); |
Andrew Lunn | a605a0f | 2016-11-21 23:26:58 +0100 | [diff] [blame] | 402 | if (err) |
| 403 | return err; |
| 404 | |
| 405 | /* Wait for the snapshotting to complete. */ |
| 406 | return mv88e6xxx_g1_stats_wait(chip); |
| 407 | } |
| 408 | |
| 409 | int mv88e6320_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port) |
| 410 | { |
| 411 | port = (port + 1) << 5; |
| 412 | |
| 413 | return mv88e6xxx_g1_stats_snapshot(chip, port); |
| 414 | } |
Andrew Lunn | 7952347 | 2016-11-21 23:27:00 +0100 | [diff] [blame] | 415 | |
| 416 | int mv88e6390_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port) |
| 417 | { |
| 418 | int err; |
| 419 | |
| 420 | port = (port + 1) << 5; |
| 421 | |
| 422 | /* Snapshot the hardware statistics counters for this port. */ |
Vivien Didelot | 57d1ef3 | 2017-06-15 12:14:05 -0400 | [diff] [blame] | 423 | err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_STATS_OP, |
| 424 | MV88E6XXX_G1_STATS_OP_BUSY | |
| 425 | MV88E6XXX_G1_STATS_OP_CAPTURE_PORT | port); |
Andrew Lunn | 7952347 | 2016-11-21 23:27:00 +0100 | [diff] [blame] | 426 | if (err) |
| 427 | return err; |
| 428 | |
| 429 | /* Wait for the snapshotting to complete. */ |
| 430 | return mv88e6xxx_g1_stats_wait(chip); |
| 431 | } |
Andrew Lunn | 7f9ef3a | 2016-11-21 23:27:05 +0100 | [diff] [blame] | 432 | |
| 433 | void mv88e6xxx_g1_stats_read(struct mv88e6xxx_chip *chip, int stat, u32 *val) |
| 434 | { |
| 435 | u32 value; |
| 436 | u16 reg; |
| 437 | int err; |
| 438 | |
| 439 | *val = 0; |
| 440 | |
Vivien Didelot | 57d1ef3 | 2017-06-15 12:14:05 -0400 | [diff] [blame] | 441 | err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_STATS_OP, |
| 442 | MV88E6XXX_G1_STATS_OP_BUSY | |
| 443 | MV88E6XXX_G1_STATS_OP_READ_CAPTURED | stat); |
Andrew Lunn | 7f9ef3a | 2016-11-21 23:27:05 +0100 | [diff] [blame] | 444 | if (err) |
| 445 | return; |
| 446 | |
| 447 | err = mv88e6xxx_g1_stats_wait(chip); |
| 448 | if (err) |
| 449 | return; |
| 450 | |
Vivien Didelot | 57d1ef3 | 2017-06-15 12:14:05 -0400 | [diff] [blame] | 451 | err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STATS_COUNTER_32, ®); |
Andrew Lunn | 7f9ef3a | 2016-11-21 23:27:05 +0100 | [diff] [blame] | 452 | if (err) |
| 453 | return; |
| 454 | |
| 455 | value = reg << 16; |
| 456 | |
Vivien Didelot | 57d1ef3 | 2017-06-15 12:14:05 -0400 | [diff] [blame] | 457 | err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STATS_COUNTER_01, ®); |
Andrew Lunn | 7f9ef3a | 2016-11-21 23:27:05 +0100 | [diff] [blame] | 458 | if (err) |
| 459 | return; |
| 460 | |
| 461 | *val = value | reg; |
| 462 | } |
Andrew Lunn | 40cff8f | 2017-11-10 00:36:41 +0100 | [diff] [blame] | 463 | |
| 464 | int mv88e6xxx_g1_stats_clear(struct mv88e6xxx_chip *chip) |
| 465 | { |
| 466 | int err; |
| 467 | u16 val; |
| 468 | |
| 469 | err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STATS_OP, &val); |
| 470 | if (err) |
| 471 | return err; |
| 472 | |
| 473 | val |= MV88E6XXX_G1_STATS_OP_BUSY | MV88E6XXX_G1_STATS_OP_FLUSH_ALL; |
| 474 | |
| 475 | err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_STATS_OP, val); |
| 476 | if (err) |
| 477 | return err; |
| 478 | |
| 479 | /* Wait for the flush to complete. */ |
| 480 | return mv88e6xxx_g1_stats_wait(chip); |
| 481 | } |