1 /* 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 17 int 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 24 int 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 31 int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask) 32 { 33 return mv88e6xxx_wait(chip, chip->info->global1_addr, reg, mask); 34 } 35 36 /* Offset 0x1a: Monitor Control */ 37 /* Offset 0x1a: Monitor & MGMT Control on some devices */ 38 39 int 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, ®); 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 */ 61 int 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, ®); 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 76 static 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 86 int 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 99 int 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 105 int 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 132 /* Offset 0x1c: Global Control 2 */ 133 134 int 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 152 int mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip *chip) 153 { 154 return mv88e6xxx_g1_wait(chip, GLOBAL_STATS_OP, GLOBAL_STATS_OP_BUSY); 155 } 156 157 int 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 172 int 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 } 178 179 int 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 } 194 195 void 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, ®); 213 if (err) 214 return; 215 216 value = reg << 16; 217 218 err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_COUNTER_01, ®); 219 if (err) 220 return; 221 222 *val = value | reg; 223 } 224