linux/net/dsa/mv88e6131.c
<<
>>
Prefs
   1/*
   2 * net/dsa/mv88e6131.c - Marvell 88e6095/6095f/6131 switch chip support
   3 * Copyright (c) 2008-2009 Marvell Semiconductor
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2 of the License, or
   8 * (at your option) any later version.
   9 */
  10
  11#include <linux/list.h>
  12#include <linux/netdevice.h>
  13#include <linux/phy.h>
  14#include "dsa_priv.h"
  15#include "mv88e6xxx.h"
  16
  17static char *mv88e6131_probe(struct mii_bus *bus, int sw_addr)
  18{
  19        int ret;
  20
  21        ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03);
  22        if (ret >= 0) {
  23                ret &= 0xfff0;
  24                if (ret == 0x0950)
  25                        return "Marvell 88E6095/88E6095F";
  26                if (ret == 0x1060)
  27                        return "Marvell 88E6131";
  28        }
  29
  30        return NULL;
  31}
  32
  33static int mv88e6131_switch_reset(struct dsa_switch *ds)
  34{
  35        int i;
  36        int ret;
  37
  38        /*
  39         * Set all ports to the disabled state.
  40         */
  41        for (i = 0; i < 11; i++) {
  42                ret = REG_READ(REG_PORT(i), 0x04);
  43                REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
  44        }
  45
  46        /*
  47         * Wait for transmit queues to drain.
  48         */
  49        msleep(2);
  50
  51        /*
  52         * Reset the switch.
  53         */
  54        REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
  55
  56        /*
  57         * Wait up to one second for reset to complete.
  58         */
  59        for (i = 0; i < 1000; i++) {
  60                ret = REG_READ(REG_GLOBAL, 0x00);
  61                if ((ret & 0xc800) == 0xc800)
  62                        break;
  63
  64                msleep(1);
  65        }
  66        if (i == 1000)
  67                return -ETIMEDOUT;
  68
  69        return 0;
  70}
  71
  72static int mv88e6131_setup_global(struct dsa_switch *ds)
  73{
  74        int ret;
  75        int i;
  76
  77        /*
  78         * Enable the PHY polling unit, don't discard packets with
  79         * excessive collisions, use a weighted fair queueing scheme
  80         * to arbitrate between packet queues, set the maximum frame
  81         * size to 1632, and mask all interrupt sources.
  82         */
  83        REG_WRITE(REG_GLOBAL, 0x04, 0x4400);
  84
  85        /*
  86         * Set the default address aging time to 5 minutes, and
  87         * enable address learn messages to be sent to all message
  88         * ports.
  89         */
  90        REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
  91
  92        /*
  93         * Configure the priority mapping registers.
  94         */
  95        ret = mv88e6xxx_config_prio(ds);
  96        if (ret < 0)
  97                return ret;
  98
  99        /*
 100         * Set the VLAN ethertype to 0x8100.
 101         */
 102        REG_WRITE(REG_GLOBAL, 0x19, 0x8100);
 103
 104        /*
 105         * Disable ARP mirroring, and configure the upstream port as
 106         * the port to which ingress and egress monitor frames are to
 107         * be sent.
 108         */
 109        REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1100) | 0x00f0);
 110
 111        /*
 112         * Disable cascade port functionality, and set the switch's
 113         * DSA device number.
 114         */
 115        REG_WRITE(REG_GLOBAL, 0x1c, 0xe000 | (ds->index & 0x1f));
 116
 117        /*
 118         * Send all frames with destination addresses matching
 119         * 01:80:c2:00:00:0x to the CPU port.
 120         */
 121        REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
 122
 123        /*
 124         * Ignore removed tag data on doubly tagged packets, disable
 125         * flow control messages, force flow control priority to the
 126         * highest, and send all special multicast frames to the CPU
 127         * port at the higest priority.
 128         */
 129        REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
 130
 131        /*
 132         * Program the DSA routing table.
 133         */
 134        for (i = 0; i < 32; i++) {
 135                int nexthop;
 136
 137                nexthop = 0x1f;
 138                if (i != ds->index && i < ds->dst->pd->nr_chips)
 139                        nexthop = ds->pd->rtable[i] & 0x1f;
 140
 141                REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
 142        }
 143
 144        /*
 145         * Clear all trunk masks.
 146         */
 147        for (i = 0; i < 8; i++)
 148                REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0x7ff);
 149
 150        /*
 151         * Clear all trunk mappings.
 152         */
 153        for (i = 0; i < 16; i++)
 154                REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
 155
 156        /*
 157         * Force the priority of IGMP/MLD snoop frames and ARP frames
 158         * to the highest setting.
 159         */
 160        REG_WRITE(REG_GLOBAL2, 0x0f, 0x00ff);
 161
 162        return 0;
 163}
 164
 165static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
 166{
 167        int addr = REG_PORT(p);
 168        u16 val;
 169
 170        /*
 171         * MAC Forcing register: don't force link, speed, duplex
 172         * or flow control state to any particular values on physical
 173         * ports, but force the CPU port and all DSA ports to 1000 Mb/s
 174         * full duplex.
 175         */
 176        if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p))
 177                REG_WRITE(addr, 0x01, 0x003e);
 178        else
 179                REG_WRITE(addr, 0x01, 0x0003);
 180
 181        /*
 182         * Port Control: disable Core Tag, disable Drop-on-Lock,
 183         * transmit frames unmodified, disable Header mode,
 184         * enable IGMP/MLD snoop, disable DoubleTag, disable VLAN
 185         * tunneling, determine priority by looking at 802.1p and
 186         * IP priority fields (IP prio has precedence), and set STP
 187         * state to Forwarding.
 188         *
 189         * If this is the upstream port for this switch, enable
 190         * forwarding of unknown unicasts, and enable DSA tagging
 191         * mode.
 192         *
 193         * If this is the link to another switch, use DSA tagging
 194         * mode, but do not enable forwarding of unknown unicasts.
 195         */
 196        val = 0x0433;
 197        if (p == dsa_upstream_port(ds))
 198                val |= 0x0104;
 199        if (ds->dsa_port_mask & (1 << p))
 200                val |= 0x0100;
 201        REG_WRITE(addr, 0x04, val);
 202
 203        /*
 204         * Port Control 1: disable trunking.  Also, if this is the
 205         * CPU port, enable learn messages to be sent to this port.
 206         */
 207        REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000);
 208
 209        /*
 210         * Port based VLAN map: give each port its own address
 211         * database, allow the CPU port to talk to each of the 'real'
 212         * ports, and allow each of the 'real' ports to only talk to
 213         * the upstream port.
 214         */
 215        val = (p & 0xf) << 12;
 216        if (dsa_is_cpu_port(ds, p))
 217                val |= ds->phys_port_mask;
 218        else
 219                val |= 1 << dsa_upstream_port(ds);
 220        REG_WRITE(addr, 0x06, val);
 221
 222        /*
 223         * Default VLAN ID and priority: don't set a default VLAN
 224         * ID, and set the default packet priority to zero.
 225         */
 226        REG_WRITE(addr, 0x07, 0x0000);
 227
 228        /*
 229         * Port Control 2: don't force a good FCS, don't use
 230         * VLAN-based, source address-based or destination
 231         * address-based priority overrides, don't let the switch
 232         * add or strip 802.1q tags, don't discard tagged or
 233         * untagged frames on this port, do a destination address
 234         * lookup on received packets as usual, don't send a copy
 235         * of all transmitted/received frames on this port to the
 236         * CPU, and configure the upstream port number.
 237         *
 238         * If this is the upstream port for this switch, enable
 239         * forwarding of unknown multicast addresses.
 240         */
 241        val = 0x0080 | dsa_upstream_port(ds);
 242        if (p == dsa_upstream_port(ds))
 243                val |= 0x0040;
 244        REG_WRITE(addr, 0x08, val);
 245
 246        /*
 247         * Rate Control: disable ingress rate limiting.
 248         */
 249        REG_WRITE(addr, 0x09, 0x0000);
 250
 251        /*
 252         * Rate Control 2: disable egress rate limiting.
 253         */
 254        REG_WRITE(addr, 0x0a, 0x0000);
 255
 256        /*
 257         * Port Association Vector: when learning source addresses
 258         * of packets, add the address to the address database using
 259         * a port bitmap that has only the bit for this port set and
 260         * the other bits clear.
 261         */
 262        REG_WRITE(addr, 0x0b, 1 << p);
 263
 264        /*
 265         * Tag Remap: use an identity 802.1p prio -> switch prio
 266         * mapping.
 267         */
 268        REG_WRITE(addr, 0x18, 0x3210);
 269
 270        /*
 271         * Tag Remap 2: use an identity 802.1p prio -> switch prio
 272         * mapping.
 273         */
 274        REG_WRITE(addr, 0x19, 0x7654);
 275
 276        return 0;
 277}
 278
 279static int mv88e6131_setup(struct dsa_switch *ds)
 280{
 281        struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
 282        int i;
 283        int ret;
 284
 285        mutex_init(&ps->smi_mutex);
 286        mv88e6xxx_ppu_state_init(ds);
 287        mutex_init(&ps->stats_mutex);
 288
 289        ret = mv88e6131_switch_reset(ds);
 290        if (ret < 0)
 291                return ret;
 292
 293        /* @@@ initialise vtu and atu */
 294
 295        ret = mv88e6131_setup_global(ds);
 296        if (ret < 0)
 297                return ret;
 298
 299        for (i = 0; i < 11; i++) {
 300                ret = mv88e6131_setup_port(ds, i);
 301                if (ret < 0)
 302                        return ret;
 303        }
 304
 305        return 0;
 306}
 307
 308static int mv88e6131_port_to_phy_addr(int port)
 309{
 310        if (port >= 0 && port <= 11)
 311                return port;
 312        return -1;
 313}
 314
 315static int
 316mv88e6131_phy_read(struct dsa_switch *ds, int port, int regnum)
 317{
 318        int addr = mv88e6131_port_to_phy_addr(port);
 319        return mv88e6xxx_phy_read_ppu(ds, addr, regnum);
 320}
 321
 322static int
 323mv88e6131_phy_write(struct dsa_switch *ds,
 324                              int port, int regnum, u16 val)
 325{
 326        int addr = mv88e6131_port_to_phy_addr(port);
 327        return mv88e6xxx_phy_write_ppu(ds, addr, regnum, val);
 328}
 329
 330static struct mv88e6xxx_hw_stat mv88e6131_hw_stats[] = {
 331        { "in_good_octets", 8, 0x00, },
 332        { "in_bad_octets", 4, 0x02, },
 333        { "in_unicast", 4, 0x04, },
 334        { "in_broadcasts", 4, 0x06, },
 335        { "in_multicasts", 4, 0x07, },
 336        { "in_pause", 4, 0x16, },
 337        { "in_undersize", 4, 0x18, },
 338        { "in_fragments", 4, 0x19, },
 339        { "in_oversize", 4, 0x1a, },
 340        { "in_jabber", 4, 0x1b, },
 341        { "in_rx_error", 4, 0x1c, },
 342        { "in_fcs_error", 4, 0x1d, },
 343        { "out_octets", 8, 0x0e, },
 344        { "out_unicast", 4, 0x10, },
 345        { "out_broadcasts", 4, 0x13, },
 346        { "out_multicasts", 4, 0x12, },
 347        { "out_pause", 4, 0x15, },
 348        { "excessive", 4, 0x11, },
 349        { "collisions", 4, 0x1e, },
 350        { "deferred", 4, 0x05, },
 351        { "single", 4, 0x14, },
 352        { "multiple", 4, 0x17, },
 353        { "out_fcs_error", 4, 0x03, },
 354        { "late", 4, 0x1f, },
 355        { "hist_64bytes", 4, 0x08, },
 356        { "hist_65_127bytes", 4, 0x09, },
 357        { "hist_128_255bytes", 4, 0x0a, },
 358        { "hist_256_511bytes", 4, 0x0b, },
 359        { "hist_512_1023bytes", 4, 0x0c, },
 360        { "hist_1024_max_bytes", 4, 0x0d, },
 361};
 362
 363static void
 364mv88e6131_get_strings(struct dsa_switch *ds, int port, uint8_t *data)
 365{
 366        mv88e6xxx_get_strings(ds, ARRAY_SIZE(mv88e6131_hw_stats),
 367                              mv88e6131_hw_stats, port, data);
 368}
 369
 370static void
 371mv88e6131_get_ethtool_stats(struct dsa_switch *ds,
 372                                  int port, uint64_t *data)
 373{
 374        mv88e6xxx_get_ethtool_stats(ds, ARRAY_SIZE(mv88e6131_hw_stats),
 375                                    mv88e6131_hw_stats, port, data);
 376}
 377
 378static int mv88e6131_get_sset_count(struct dsa_switch *ds)
 379{
 380        return ARRAY_SIZE(mv88e6131_hw_stats);
 381}
 382
 383static struct dsa_switch_driver mv88e6131_switch_driver = {
 384        .tag_protocol           = cpu_to_be16(ETH_P_DSA),
 385        .priv_size              = sizeof(struct mv88e6xxx_priv_state),
 386        .probe                  = mv88e6131_probe,
 387        .setup                  = mv88e6131_setup,
 388        .set_addr               = mv88e6xxx_set_addr_direct,
 389        .phy_read               = mv88e6131_phy_read,
 390        .phy_write              = mv88e6131_phy_write,
 391        .poll_link              = mv88e6xxx_poll_link,
 392        .get_strings            = mv88e6131_get_strings,
 393        .get_ethtool_stats      = mv88e6131_get_ethtool_stats,
 394        .get_sset_count         = mv88e6131_get_sset_count,
 395};
 396
 397static int __init mv88e6131_init(void)
 398{
 399        register_switch_driver(&mv88e6131_switch_driver);
 400        return 0;
 401}
 402module_init(mv88e6131_init);
 403
 404static void __exit mv88e6131_cleanup(void)
 405{
 406        unregister_switch_driver(&mv88e6131_switch_driver);
 407}
 408module_exit(mv88e6131_cleanup);
 409