1a935c052SVivien Didelot /* 2a935c052SVivien Didelot * Marvell 88E6xxx Switch Global (1) Registers support 3a935c052SVivien Didelot * 4a935c052SVivien Didelot * Copyright (c) 2008 Marvell Semiconductor 5a935c052SVivien Didelot * 64333d619SVivien Didelot * Copyright (c) 2016-2017 Savoir-faire Linux Inc. 74333d619SVivien Didelot * Vivien Didelot <vivien.didelot@savoirfairelinux.com> 8a935c052SVivien Didelot * 9a935c052SVivien Didelot * This program is free software; you can redistribute it and/or modify 10a935c052SVivien Didelot * it under the terms of the GNU General Public License as published by 11a935c052SVivien Didelot * the Free Software Foundation; either version 2 of the License, or 12a935c052SVivien Didelot * (at your option) any later version. 13a935c052SVivien Didelot */ 14a935c052SVivien Didelot 154d5f2ba7SVivien Didelot #include "chip.h" 16a935c052SVivien Didelot #include "global1.h" 17a935c052SVivien Didelot 18a935c052SVivien Didelot int mv88e6xxx_g1_read(struct mv88e6xxx_chip *chip, int reg, u16 *val) 19a935c052SVivien Didelot { 20a935c052SVivien Didelot int addr = chip->info->global1_addr; 21a935c052SVivien Didelot 22a935c052SVivien Didelot return mv88e6xxx_read(chip, addr, reg, val); 23a935c052SVivien Didelot } 24a935c052SVivien Didelot 25a935c052SVivien Didelot int mv88e6xxx_g1_write(struct mv88e6xxx_chip *chip, int reg, u16 val) 26a935c052SVivien Didelot { 27a935c052SVivien Didelot int addr = chip->info->global1_addr; 28a935c052SVivien Didelot 29a935c052SVivien Didelot return mv88e6xxx_write(chip, addr, reg, val); 30a935c052SVivien Didelot } 31a935c052SVivien Didelot 32a935c052SVivien Didelot int mv88e6xxx_g1_wait(struct mv88e6xxx_chip *chip, int reg, u16 mask) 33a935c052SVivien Didelot { 34a935c052SVivien Didelot return mv88e6xxx_wait(chip, chip->info->global1_addr, reg, mask); 35a935c052SVivien Didelot } 36a605a0feSAndrew Lunn 3717e708baSVivien Didelot /* Offset 0x00: Switch Global Status Register */ 3817e708baSVivien Didelot 39a199d8b6SVivien Didelot static int mv88e6185_g1_wait_ppu_disabled(struct mv88e6xxx_chip *chip) 40a199d8b6SVivien Didelot { 41a199d8b6SVivien Didelot u16 state; 42a199d8b6SVivien Didelot int i, err; 43a199d8b6SVivien Didelot 44a199d8b6SVivien Didelot for (i = 0; i < 16; i++) { 4582466921SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &state); 46a199d8b6SVivien Didelot if (err) 47a199d8b6SVivien Didelot return err; 48a199d8b6SVivien Didelot 49a199d8b6SVivien Didelot /* Check the value of the PPUState bits 15:14 */ 5082466921SVivien Didelot state &= MV88E6185_G1_STS_PPU_STATE_MASK; 5182466921SVivien Didelot if (state != MV88E6185_G1_STS_PPU_STATE_POLLING) 52a199d8b6SVivien Didelot return 0; 53a199d8b6SVivien Didelot 54a199d8b6SVivien Didelot usleep_range(1000, 2000); 55a199d8b6SVivien Didelot } 56a199d8b6SVivien Didelot 57a199d8b6SVivien Didelot return -ETIMEDOUT; 58a199d8b6SVivien Didelot } 59a199d8b6SVivien Didelot 6017e708baSVivien Didelot static int mv88e6185_g1_wait_ppu_polling(struct mv88e6xxx_chip *chip) 6117e708baSVivien Didelot { 6217e708baSVivien Didelot u16 state; 6317e708baSVivien Didelot int i, err; 6417e708baSVivien Didelot 6517e708baSVivien Didelot for (i = 0; i < 16; ++i) { 6682466921SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &state); 6717e708baSVivien Didelot if (err) 6817e708baSVivien Didelot return err; 6917e708baSVivien Didelot 7017e708baSVivien Didelot /* Check the value of the PPUState bits 15:14 */ 7182466921SVivien Didelot state &= MV88E6185_G1_STS_PPU_STATE_MASK; 7282466921SVivien Didelot if (state == MV88E6185_G1_STS_PPU_STATE_POLLING) 7317e708baSVivien Didelot return 0; 7417e708baSVivien Didelot 7517e708baSVivien Didelot usleep_range(1000, 2000); 7617e708baSVivien Didelot } 7717e708baSVivien Didelot 7817e708baSVivien Didelot return -ETIMEDOUT; 7917e708baSVivien Didelot } 8017e708baSVivien Didelot 8117e708baSVivien Didelot static int mv88e6352_g1_wait_ppu_polling(struct mv88e6xxx_chip *chip) 8217e708baSVivien Didelot { 8317e708baSVivien Didelot u16 state; 8417e708baSVivien Didelot int i, err; 8517e708baSVivien Didelot 8617e708baSVivien Didelot for (i = 0; i < 16; ++i) { 8782466921SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &state); 8817e708baSVivien Didelot if (err) 8917e708baSVivien Didelot return err; 9017e708baSVivien Didelot 9117e708baSVivien Didelot /* Check the value of the PPUState (or InitState) bit 15 */ 9282466921SVivien Didelot if (state & MV88E6352_G1_STS_PPU_STATE) 9317e708baSVivien Didelot return 0; 9417e708baSVivien Didelot 9517e708baSVivien Didelot usleep_range(1000, 2000); 9617e708baSVivien Didelot } 9717e708baSVivien Didelot 9817e708baSVivien Didelot return -ETIMEDOUT; 9917e708baSVivien Didelot } 10017e708baSVivien Didelot 10117e708baSVivien Didelot static int mv88e6xxx_g1_wait_init_ready(struct mv88e6xxx_chip *chip) 10217e708baSVivien Didelot { 10317e708baSVivien Didelot const unsigned long timeout = jiffies + 1 * HZ; 10417e708baSVivien Didelot u16 val; 10517e708baSVivien Didelot int err; 10617e708baSVivien Didelot 10717e708baSVivien Didelot /* Wait up to 1 second for the switch to be ready. The InitReady bit 11 10817e708baSVivien Didelot * is set to a one when all units inside the device (ATU, VTU, etc.) 10917e708baSVivien Didelot * have finished their initialization and are ready to accept frames. 11017e708baSVivien Didelot */ 11117e708baSVivien Didelot while (time_before(jiffies, timeout)) { 11282466921SVivien Didelot err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_STS, &val); 11317e708baSVivien Didelot if (err) 11417e708baSVivien Didelot return err; 11517e708baSVivien Didelot 11682466921SVivien Didelot if (val & MV88E6XXX_G1_STS_INIT_READY) 11717e708baSVivien Didelot break; 11817e708baSVivien Didelot 11917e708baSVivien Didelot usleep_range(1000, 2000); 12017e708baSVivien Didelot } 12117e708baSVivien Didelot 12217e708baSVivien Didelot if (time_after(jiffies, timeout)) 12317e708baSVivien Didelot return -ETIMEDOUT; 12417e708baSVivien Didelot 12517e708baSVivien Didelot return 0; 12617e708baSVivien Didelot } 12717e708baSVivien Didelot 1284b0c4817SVivien Didelot /* Offset 0x01: Switch MAC Address Register Bytes 0 & 1 1294b0c4817SVivien Didelot * Offset 0x02: Switch MAC Address Register Bytes 2 & 3 1304b0c4817SVivien Didelot * Offset 0x03: Switch MAC Address Register Bytes 4 & 5 1314b0c4817SVivien Didelot */ 1324b0c4817SVivien Didelot int mv88e6xxx_g1_set_switch_mac(struct mv88e6xxx_chip *chip, u8 *addr) 1334b0c4817SVivien Didelot { 1344b0c4817SVivien Didelot u16 reg; 1354b0c4817SVivien Didelot int err; 1364b0c4817SVivien Didelot 1374b0c4817SVivien Didelot reg = (addr[0] << 8) | addr[1]; 1384b0c4817SVivien Didelot err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_MAC_01, reg); 1394b0c4817SVivien Didelot if (err) 1404b0c4817SVivien Didelot return err; 1414b0c4817SVivien Didelot 1424b0c4817SVivien Didelot reg = (addr[2] << 8) | addr[3]; 1434b0c4817SVivien Didelot err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_MAC_23, reg); 1444b0c4817SVivien Didelot if (err) 1454b0c4817SVivien Didelot return err; 1464b0c4817SVivien Didelot 1474b0c4817SVivien Didelot reg = (addr[4] << 8) | addr[5]; 1484b0c4817SVivien Didelot err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_MAC_45, reg); 1494b0c4817SVivien Didelot if (err) 1504b0c4817SVivien Didelot return err; 1514b0c4817SVivien Didelot 1524b0c4817SVivien Didelot return 0; 1534b0c4817SVivien Didelot } 1544b0c4817SVivien Didelot 15517e708baSVivien Didelot /* Offset 0x04: Switch Global Control Register */ 15617e708baSVivien Didelot 15717e708baSVivien Didelot int mv88e6185_g1_reset(struct mv88e6xxx_chip *chip) 15817e708baSVivien Didelot { 15917e708baSVivien Didelot u16 val; 16017e708baSVivien Didelot int err; 16117e708baSVivien Didelot 16217e708baSVivien Didelot /* Set the SWReset bit 15 along with the PPUEn bit 14, to also restart 16317e708baSVivien Didelot * the PPU, including re-doing PHY detection and initialization 16417e708baSVivien Didelot */ 16517e708baSVivien Didelot err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val); 16617e708baSVivien Didelot if (err) 16717e708baSVivien Didelot return err; 16817e708baSVivien Didelot 16917e708baSVivien Didelot val |= GLOBAL_CONTROL_SW_RESET; 17017e708baSVivien Didelot val |= GLOBAL_CONTROL_PPU_ENABLE; 17117e708baSVivien Didelot 17217e708baSVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val); 17317e708baSVivien Didelot if (err) 17417e708baSVivien Didelot return err; 17517e708baSVivien Didelot 17617e708baSVivien Didelot err = mv88e6xxx_g1_wait_init_ready(chip); 17717e708baSVivien Didelot if (err) 17817e708baSVivien Didelot return err; 17917e708baSVivien Didelot 18017e708baSVivien Didelot return mv88e6185_g1_wait_ppu_polling(chip); 18117e708baSVivien Didelot } 18217e708baSVivien Didelot 18317e708baSVivien Didelot int mv88e6352_g1_reset(struct mv88e6xxx_chip *chip) 18417e708baSVivien Didelot { 18517e708baSVivien Didelot u16 val; 18617e708baSVivien Didelot int err; 18717e708baSVivien Didelot 18817e708baSVivien Didelot /* Set the SWReset bit 15 */ 18917e708baSVivien Didelot err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val); 19017e708baSVivien Didelot if (err) 19117e708baSVivien Didelot return err; 19217e708baSVivien Didelot 19317e708baSVivien Didelot val |= GLOBAL_CONTROL_SW_RESET; 19417e708baSVivien Didelot 19517e708baSVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val); 19617e708baSVivien Didelot if (err) 19717e708baSVivien Didelot return err; 19817e708baSVivien Didelot 19917e708baSVivien Didelot err = mv88e6xxx_g1_wait_init_ready(chip); 20017e708baSVivien Didelot if (err) 20117e708baSVivien Didelot return err; 20217e708baSVivien Didelot 20317e708baSVivien Didelot return mv88e6352_g1_wait_ppu_polling(chip); 20417e708baSVivien Didelot } 20517e708baSVivien Didelot 206a199d8b6SVivien Didelot int mv88e6185_g1_ppu_enable(struct mv88e6xxx_chip *chip) 207a199d8b6SVivien Didelot { 208a199d8b6SVivien Didelot u16 val; 209a199d8b6SVivien Didelot int err; 210a199d8b6SVivien Didelot 211a199d8b6SVivien Didelot err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val); 212a199d8b6SVivien Didelot if (err) 213a199d8b6SVivien Didelot return err; 214a199d8b6SVivien Didelot 215a199d8b6SVivien Didelot val |= GLOBAL_CONTROL_PPU_ENABLE; 216a199d8b6SVivien Didelot 217a199d8b6SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val); 218a199d8b6SVivien Didelot if (err) 219a199d8b6SVivien Didelot return err; 220a199d8b6SVivien Didelot 221a199d8b6SVivien Didelot return mv88e6185_g1_wait_ppu_polling(chip); 222a199d8b6SVivien Didelot } 223a199d8b6SVivien Didelot 224a199d8b6SVivien Didelot int mv88e6185_g1_ppu_disable(struct mv88e6xxx_chip *chip) 225a199d8b6SVivien Didelot { 226a199d8b6SVivien Didelot u16 val; 227a199d8b6SVivien Didelot int err; 228a199d8b6SVivien Didelot 229a199d8b6SVivien Didelot err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL, &val); 230a199d8b6SVivien Didelot if (err) 231a199d8b6SVivien Didelot return err; 232a199d8b6SVivien Didelot 233a199d8b6SVivien Didelot val &= ~GLOBAL_CONTROL_PPU_ENABLE; 234a199d8b6SVivien Didelot 235a199d8b6SVivien Didelot err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL, val); 236a199d8b6SVivien Didelot if (err) 237a199d8b6SVivien Didelot return err; 238a199d8b6SVivien Didelot 239a199d8b6SVivien Didelot return mv88e6185_g1_wait_ppu_disabled(chip); 240a199d8b6SVivien Didelot } 241a199d8b6SVivien Didelot 24233641994SAndrew Lunn /* Offset 0x1a: Monitor Control */ 24333641994SAndrew Lunn /* Offset 0x1a: Monitor & MGMT Control on some devices */ 24433641994SAndrew Lunn 24533641994SAndrew Lunn int mv88e6095_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port) 24633641994SAndrew Lunn { 24733641994SAndrew Lunn u16 reg; 24833641994SAndrew Lunn int err; 24933641994SAndrew Lunn 25033641994SAndrew Lunn err = mv88e6xxx_g1_read(chip, GLOBAL_MONITOR_CONTROL, ®); 25133641994SAndrew Lunn if (err) 25233641994SAndrew Lunn return err; 25333641994SAndrew Lunn 25433641994SAndrew Lunn reg &= ~(GLOBAL_MONITOR_CONTROL_INGRESS_MASK | 25533641994SAndrew Lunn GLOBAL_MONITOR_CONTROL_EGRESS_MASK); 25633641994SAndrew Lunn 25733641994SAndrew Lunn reg |= port << GLOBAL_MONITOR_CONTROL_INGRESS_SHIFT | 25833641994SAndrew Lunn port << GLOBAL_MONITOR_CONTROL_EGRESS_SHIFT; 25933641994SAndrew Lunn 26033641994SAndrew Lunn return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg); 26133641994SAndrew Lunn } 26233641994SAndrew Lunn 26333641994SAndrew Lunn /* Older generations also call this the ARP destination. It has been 26433641994SAndrew Lunn * generalized in more modern devices such that more than ARP can 26533641994SAndrew Lunn * egress it 26633641994SAndrew Lunn */ 26733641994SAndrew Lunn int mv88e6095_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port) 26833641994SAndrew Lunn { 26933641994SAndrew Lunn u16 reg; 27033641994SAndrew Lunn int err; 27133641994SAndrew Lunn 27233641994SAndrew Lunn err = mv88e6xxx_g1_read(chip, GLOBAL_MONITOR_CONTROL, ®); 27333641994SAndrew Lunn if (err) 27433641994SAndrew Lunn return err; 27533641994SAndrew Lunn 27633641994SAndrew Lunn reg &= ~GLOBAL_MONITOR_CONTROL_ARP_MASK; 27733641994SAndrew Lunn reg |= port << GLOBAL_MONITOR_CONTROL_ARP_SHIFT; 27833641994SAndrew Lunn 27933641994SAndrew Lunn return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg); 28033641994SAndrew Lunn } 28133641994SAndrew Lunn 28233641994SAndrew Lunn static int mv88e6390_g1_monitor_write(struct mv88e6xxx_chip *chip, 28333641994SAndrew Lunn u16 pointer, u8 data) 28433641994SAndrew Lunn { 28533641994SAndrew Lunn u16 reg; 28633641994SAndrew Lunn 28733641994SAndrew Lunn reg = GLOBAL_MONITOR_CONTROL_UPDATE | pointer | data; 28833641994SAndrew Lunn 28933641994SAndrew Lunn return mv88e6xxx_g1_write(chip, GLOBAL_MONITOR_CONTROL, reg); 29033641994SAndrew Lunn } 29133641994SAndrew Lunn 29233641994SAndrew Lunn int mv88e6390_g1_set_egress_port(struct mv88e6xxx_chip *chip, int port) 29333641994SAndrew Lunn { 29433641994SAndrew Lunn int err; 29533641994SAndrew Lunn 29633641994SAndrew Lunn err = mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_INGRESS, 29733641994SAndrew Lunn port); 29833641994SAndrew Lunn if (err) 29933641994SAndrew Lunn return err; 30033641994SAndrew Lunn 30133641994SAndrew Lunn return mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_EGRESS, 30233641994SAndrew Lunn port); 30333641994SAndrew Lunn } 30433641994SAndrew Lunn 30533641994SAndrew Lunn int mv88e6390_g1_set_cpu_port(struct mv88e6xxx_chip *chip, int port) 30633641994SAndrew Lunn { 30733641994SAndrew Lunn return mv88e6390_g1_monitor_write(chip, GLOBAL_MONITOR_CONTROL_CPU_DEST, 30833641994SAndrew Lunn port); 30933641994SAndrew Lunn } 31033641994SAndrew Lunn 3116e55f698SAndrew Lunn int mv88e6390_g1_mgmt_rsvd2cpu(struct mv88e6xxx_chip *chip) 3126e55f698SAndrew Lunn { 3136e55f698SAndrew Lunn int err; 3146e55f698SAndrew Lunn 3156e55f698SAndrew Lunn /* 01:c2:80:00:00:00:00-01:c2:80:00:00:00:07 are Management */ 3166e55f698SAndrew Lunn err = mv88e6390_g1_monitor_write( 3176e55f698SAndrew Lunn chip, GLOBAL_MONITOR_CONTROL_0180C280000000XLO, 0xff); 3186e55f698SAndrew Lunn if (err) 3196e55f698SAndrew Lunn return err; 3206e55f698SAndrew Lunn 3216e55f698SAndrew Lunn /* 01:c2:80:00:00:00:08-01:c2:80:00:00:00:0f are Management */ 3226e55f698SAndrew Lunn err = mv88e6390_g1_monitor_write( 3236e55f698SAndrew Lunn chip, GLOBAL_MONITOR_CONTROL_0180C280000000XHI, 0xff); 3246e55f698SAndrew Lunn if (err) 3256e55f698SAndrew Lunn return err; 3266e55f698SAndrew Lunn 3276e55f698SAndrew Lunn /* 01:c2:80:00:00:00:20-01:c2:80:00:00:00:27 are Management */ 3286e55f698SAndrew Lunn err = mv88e6390_g1_monitor_write( 3296e55f698SAndrew Lunn chip, GLOBAL_MONITOR_CONTROL_0180C280000002XLO, 0xff); 3306e55f698SAndrew Lunn if (err) 3316e55f698SAndrew Lunn return err; 3326e55f698SAndrew Lunn 3336e55f698SAndrew Lunn /* 01:c2:80:00:00:00:28-01:c2:80:00:00:00:2f are Management */ 3346e55f698SAndrew Lunn return mv88e6390_g1_monitor_write( 3356e55f698SAndrew Lunn chip, GLOBAL_MONITOR_CONTROL_0180C280000002XHI, 0xff); 3366e55f698SAndrew Lunn } 3376e55f698SAndrew Lunn 338de227387SAndrew Lunn /* Offset 0x1c: Global Control 2 */ 339de227387SAndrew Lunn 340de227387SAndrew Lunn int mv88e6390_g1_stats_set_histogram(struct mv88e6xxx_chip *chip) 341de227387SAndrew Lunn { 342de227387SAndrew Lunn u16 val; 343de227387SAndrew Lunn int err; 344de227387SAndrew Lunn 345de227387SAndrew Lunn err = mv88e6xxx_g1_read(chip, GLOBAL_CONTROL_2, &val); 346de227387SAndrew Lunn if (err) 347de227387SAndrew Lunn return err; 348de227387SAndrew Lunn 349de227387SAndrew Lunn val |= GLOBAL_CONTROL_2_HIST_RX_TX; 350de227387SAndrew Lunn 351de227387SAndrew Lunn err = mv88e6xxx_g1_write(chip, GLOBAL_CONTROL_2, val); 352de227387SAndrew Lunn 353de227387SAndrew Lunn return err; 354de227387SAndrew Lunn } 355de227387SAndrew Lunn 356de227387SAndrew Lunn /* Offset 0x1d: Statistics Operation 2 */ 357de227387SAndrew Lunn 3587f9ef3afSAndrew Lunn int mv88e6xxx_g1_stats_wait(struct mv88e6xxx_chip *chip) 359a605a0feSAndrew Lunn { 360a605a0feSAndrew Lunn return mv88e6xxx_g1_wait(chip, GLOBAL_STATS_OP, GLOBAL_STATS_OP_BUSY); 361a605a0feSAndrew Lunn } 362a605a0feSAndrew Lunn 363a605a0feSAndrew Lunn int mv88e6xxx_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port) 364a605a0feSAndrew Lunn { 365a605a0feSAndrew Lunn int err; 366a605a0feSAndrew Lunn 367a605a0feSAndrew Lunn /* Snapshot the hardware statistics counters for this port. */ 368a605a0feSAndrew Lunn err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP, 369a605a0feSAndrew Lunn GLOBAL_STATS_OP_CAPTURE_PORT | 370a605a0feSAndrew Lunn GLOBAL_STATS_OP_HIST_RX_TX | port); 371a605a0feSAndrew Lunn if (err) 372a605a0feSAndrew Lunn return err; 373a605a0feSAndrew Lunn 374a605a0feSAndrew Lunn /* Wait for the snapshotting to complete. */ 375a605a0feSAndrew Lunn return mv88e6xxx_g1_stats_wait(chip); 376a605a0feSAndrew Lunn } 377a605a0feSAndrew Lunn 378a605a0feSAndrew Lunn int mv88e6320_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port) 379a605a0feSAndrew Lunn { 380a605a0feSAndrew Lunn port = (port + 1) << 5; 381a605a0feSAndrew Lunn 382a605a0feSAndrew Lunn return mv88e6xxx_g1_stats_snapshot(chip, port); 383a605a0feSAndrew Lunn } 38479523473SAndrew Lunn 38579523473SAndrew Lunn int mv88e6390_g1_stats_snapshot(struct mv88e6xxx_chip *chip, int port) 38679523473SAndrew Lunn { 38779523473SAndrew Lunn int err; 38879523473SAndrew Lunn 38979523473SAndrew Lunn port = (port + 1) << 5; 39079523473SAndrew Lunn 39179523473SAndrew Lunn /* Snapshot the hardware statistics counters for this port. */ 39279523473SAndrew Lunn err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP, 39379523473SAndrew Lunn GLOBAL_STATS_OP_CAPTURE_PORT | port); 39479523473SAndrew Lunn if (err) 39579523473SAndrew Lunn return err; 39679523473SAndrew Lunn 39779523473SAndrew Lunn /* Wait for the snapshotting to complete. */ 39879523473SAndrew Lunn return mv88e6xxx_g1_stats_wait(chip); 39979523473SAndrew Lunn } 4007f9ef3afSAndrew Lunn 4017f9ef3afSAndrew Lunn void mv88e6xxx_g1_stats_read(struct mv88e6xxx_chip *chip, int stat, u32 *val) 4027f9ef3afSAndrew Lunn { 4037f9ef3afSAndrew Lunn u32 value; 4047f9ef3afSAndrew Lunn u16 reg; 4057f9ef3afSAndrew Lunn int err; 4067f9ef3afSAndrew Lunn 4077f9ef3afSAndrew Lunn *val = 0; 4087f9ef3afSAndrew Lunn 4097f9ef3afSAndrew Lunn err = mv88e6xxx_g1_write(chip, GLOBAL_STATS_OP, 4107f9ef3afSAndrew Lunn GLOBAL_STATS_OP_READ_CAPTURED | stat); 4117f9ef3afSAndrew Lunn if (err) 4127f9ef3afSAndrew Lunn return; 4137f9ef3afSAndrew Lunn 4147f9ef3afSAndrew Lunn err = mv88e6xxx_g1_stats_wait(chip); 4157f9ef3afSAndrew Lunn if (err) 4167f9ef3afSAndrew Lunn return; 4177f9ef3afSAndrew Lunn 4187f9ef3afSAndrew Lunn err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_COUNTER_32, ®); 4197f9ef3afSAndrew Lunn if (err) 4207f9ef3afSAndrew Lunn return; 4217f9ef3afSAndrew Lunn 4227f9ef3afSAndrew Lunn value = reg << 16; 4237f9ef3afSAndrew Lunn 4247f9ef3afSAndrew Lunn err = mv88e6xxx_g1_read(chip, GLOBAL_STATS_COUNTER_01, ®); 4257f9ef3afSAndrew Lunn if (err) 4267f9ef3afSAndrew Lunn return; 4277f9ef3afSAndrew Lunn 4287f9ef3afSAndrew Lunn *val = value | reg; 4297f9ef3afSAndrew Lunn } 430