1248dd603SAdrian Chadd /*- 2*718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*718cf2ccSPedro F. Giffuni * 4248dd603SAdrian Chadd * Copyright (c) 2013 Luiz Otavio O Souza. 5248dd603SAdrian Chadd * Copyright (c) 2011-2012 Stefan Bethke. 6248dd603SAdrian Chadd * Copyright (c) 2012 Adrian Chadd. 7248dd603SAdrian Chadd * All rights reserved. 8248dd603SAdrian Chadd * 9248dd603SAdrian Chadd * Redistribution and use in source and binary forms, with or without 10248dd603SAdrian Chadd * modification, are permitted provided that the following conditions 11248dd603SAdrian Chadd * are met: 12248dd603SAdrian Chadd * 1. Redistributions of source code must retain the above copyright 13248dd603SAdrian Chadd * notice, this list of conditions and the following disclaimer. 14248dd603SAdrian Chadd * 2. Redistributions in binary form must reproduce the above copyright 15248dd603SAdrian Chadd * notice, this list of conditions and the following disclaimer in the 16248dd603SAdrian Chadd * documentation and/or other materials provided with the distribution. 17248dd603SAdrian Chadd * 18248dd603SAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19248dd603SAdrian Chadd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20248dd603SAdrian Chadd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21248dd603SAdrian Chadd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22248dd603SAdrian Chadd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23248dd603SAdrian Chadd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24248dd603SAdrian Chadd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25248dd603SAdrian Chadd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26248dd603SAdrian Chadd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27248dd603SAdrian Chadd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28248dd603SAdrian Chadd * SUCH DAMAGE. 29248dd603SAdrian Chadd * 30248dd603SAdrian Chadd * $FreeBSD$ 31248dd603SAdrian Chadd */ 32248dd603SAdrian Chadd 33248dd603SAdrian Chadd #include <sys/param.h> 34248dd603SAdrian Chadd #include <sys/bus.h> 35248dd603SAdrian Chadd #include <sys/errno.h> 36248dd603SAdrian Chadd #include <sys/kernel.h> 374170452dSChristian Brueffer #include <sys/lock.h> 384170452dSChristian Brueffer #include <sys/mutex.h> 39248dd603SAdrian Chadd #include <sys/systm.h> 40248dd603SAdrian Chadd #include <sys/socket.h> 41248dd603SAdrian Chadd 42248dd603SAdrian Chadd #include <net/if.h> 43248dd603SAdrian Chadd 44248dd603SAdrian Chadd #include <dev/mii/mii.h> 45248dd603SAdrian Chadd 46248dd603SAdrian Chadd #include <dev/etherswitch/etherswitch.h> 47248dd603SAdrian Chadd #include <dev/etherswitch/ip17x/ip17x_phy.h> 48248dd603SAdrian Chadd #include <dev/etherswitch/ip17x/ip17x_reg.h> 49248dd603SAdrian Chadd #include <dev/etherswitch/ip17x/ip17x_var.h> 50248dd603SAdrian Chadd #include <dev/etherswitch/ip17x/ip17x_vlans.h> 51248dd603SAdrian Chadd #include <dev/etherswitch/ip17x/ip175c.h> 52248dd603SAdrian Chadd 53248dd603SAdrian Chadd #include "mdio_if.h" 54248dd603SAdrian Chadd #include "miibus_if.h" 55248dd603SAdrian Chadd #include "etherswitch_if.h" 56248dd603SAdrian Chadd 57248dd603SAdrian Chadd /* 58248dd603SAdrian Chadd * Reset vlans to default state. 59248dd603SAdrian Chadd */ 60248dd603SAdrian Chadd int 61248dd603SAdrian Chadd ip17x_reset_vlans(struct ip17x_softc *sc, uint32_t vlan_mode) 62248dd603SAdrian Chadd { 63248dd603SAdrian Chadd struct ip17x_vlan *v; 64248dd603SAdrian Chadd int i, j, phy; 65248dd603SAdrian Chadd 66248dd603SAdrian Chadd /* Do not add or strip vlan tags on any port. */ 67248dd603SAdrian Chadd sc->addtag = 0; 68248dd603SAdrian Chadd sc->striptag = 0; 69248dd603SAdrian Chadd 70248dd603SAdrian Chadd /* Reset all vlan data. */ 71248dd603SAdrian Chadd memset(sc->vlan, 0, sizeof(sc->vlan)); 72248dd603SAdrian Chadd memset(sc->pvid, 0, sizeof(uint32_t) * sc->numports); 73248dd603SAdrian Chadd 74248dd603SAdrian Chadd if (vlan_mode == ETHERSWITCH_VLAN_PORT) { 75248dd603SAdrian Chadd 76248dd603SAdrian Chadd /* Initialize port based vlans. */ 77248dd603SAdrian Chadd for (i = 0, phy = 0; phy < MII_NPHY; phy++) { 78248dd603SAdrian Chadd if (((1 << phy) & sc->phymask) == 0) 79248dd603SAdrian Chadd continue; 80248dd603SAdrian Chadd v = &sc->vlan[i]; 81cc320e37SLuiz Otavio O Souza v->vlanid = i++ | ETHERSWITCH_VID_VALID; 82248dd603SAdrian Chadd v->ports = (1 << sc->cpuport); 83248dd603SAdrian Chadd for (j = 0; j < MII_NPHY; j++) { 84248dd603SAdrian Chadd if (((1 << j) & sc->phymask) == 0) 85248dd603SAdrian Chadd continue; 86248dd603SAdrian Chadd v->ports |= (1 << j); 87248dd603SAdrian Chadd } 88248dd603SAdrian Chadd } 89248dd603SAdrian Chadd 90248dd603SAdrian Chadd } else if (vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 91248dd603SAdrian Chadd 92248dd603SAdrian Chadd /* 93248dd603SAdrian Chadd * Setup vlan 1 as PVID for all switch ports. Add all ports as 94248dd603SAdrian Chadd * members of vlan 1. 95248dd603SAdrian Chadd */ 96248dd603SAdrian Chadd v = &sc->vlan[0]; 97cc320e37SLuiz Otavio O Souza v->vlanid = 1 | ETHERSWITCH_VID_VALID; 98cc320e37SLuiz Otavio O Souza /* Set PVID to 1 for everyone. */ 99248dd603SAdrian Chadd for (i = 0; i < sc->numports; i++) 100cc320e37SLuiz Otavio O Souza sc->pvid[i] = 1; 101248dd603SAdrian Chadd for (i = 0; i < MII_NPHY; i++) { 102248dd603SAdrian Chadd if ((sc->phymask & (1 << i)) == 0) 103248dd603SAdrian Chadd continue; 104248dd603SAdrian Chadd v->ports |= (1 << i); 105248dd603SAdrian Chadd } 106248dd603SAdrian Chadd } 107248dd603SAdrian Chadd 108248dd603SAdrian Chadd return (0); 109248dd603SAdrian Chadd } 110248dd603SAdrian Chadd 111248dd603SAdrian Chadd int 112248dd603SAdrian Chadd ip17x_getvgroup(device_t dev, etherswitch_vlangroup_t *vg) 113248dd603SAdrian Chadd { 114248dd603SAdrian Chadd struct ip17x_softc *sc; 115248dd603SAdrian Chadd uint32_t port; 116248dd603SAdrian Chadd int i; 117248dd603SAdrian Chadd 118248dd603SAdrian Chadd sc = device_get_softc(dev); 119248dd603SAdrian Chadd 120248dd603SAdrian Chadd /* Vlan ID. */ 121248dd603SAdrian Chadd vg->es_vid = sc->vlan[vg->es_vlangroup].vlanid; 122248dd603SAdrian Chadd 123248dd603SAdrian Chadd /* Member Ports. */ 124248dd603SAdrian Chadd vg->es_member_ports = 0; 125248dd603SAdrian Chadd for (i = 0; i < MII_NPHY; i++) { 126248dd603SAdrian Chadd if ((sc->phymask & (1 << i)) == 0) 127248dd603SAdrian Chadd continue; 128248dd603SAdrian Chadd if ((sc->vlan[vg->es_vlangroup].ports & (1 << i)) == 0) 129248dd603SAdrian Chadd continue; 130248dd603SAdrian Chadd port = sc->phyport[i]; 131248dd603SAdrian Chadd vg->es_member_ports |= (1 << port); 132248dd603SAdrian Chadd } 133248dd603SAdrian Chadd 134248dd603SAdrian Chadd /* Not supported. */ 135248dd603SAdrian Chadd vg->es_untagged_ports = vg->es_member_ports; 136248dd603SAdrian Chadd vg->es_fid = 0; 137248dd603SAdrian Chadd 138248dd603SAdrian Chadd return (0); 139248dd603SAdrian Chadd } 140248dd603SAdrian Chadd 141248dd603SAdrian Chadd int 142248dd603SAdrian Chadd ip17x_setvgroup(device_t dev, etherswitch_vlangroup_t *vg) 143248dd603SAdrian Chadd { 144248dd603SAdrian Chadd struct ip17x_softc *sc; 145248dd603SAdrian Chadd uint32_t phy; 146248dd603SAdrian Chadd int i; 147248dd603SAdrian Chadd 148248dd603SAdrian Chadd sc = device_get_softc(dev); 149248dd603SAdrian Chadd 150248dd603SAdrian Chadd /* Check VLAN mode. */ 151248dd603SAdrian Chadd if (sc->vlan_mode == 0) 152248dd603SAdrian Chadd return (EINVAL); 153248dd603SAdrian Chadd 154248dd603SAdrian Chadd /* IP175C don't support VLAN IDs > 15. */ 155cc320e37SLuiz Otavio O Souza if (IP17X_IS_SWITCH(sc, IP175C) && 156cc320e37SLuiz Otavio O Souza (vg->es_vid & ETHERSWITCH_VID_MASK) > IP175C_LAST_VLAN) 157248dd603SAdrian Chadd return (EINVAL); 158248dd603SAdrian Chadd 159248dd603SAdrian Chadd /* Vlan ID. */ 160cc320e37SLuiz Otavio O Souza if (sc->vlan_mode == ETHERSWITCH_VLAN_DOT1Q) { 161cc320e37SLuiz Otavio O Souza for (i = 0; i < sc->info.es_nvlangroups; i++) { 162cc320e37SLuiz Otavio O Souza /* Is this Vlan ID already set in another vlangroup ? */ 163cc320e37SLuiz Otavio O Souza if (i != vg->es_vlangroup && 164cc320e37SLuiz Otavio O Souza sc->vlan[i].vlanid & ETHERSWITCH_VID_VALID && 165cc320e37SLuiz Otavio O Souza (sc->vlan[i].vlanid & ETHERSWITCH_VID_MASK) == 166cc320e37SLuiz Otavio O Souza (vg->es_vid & ETHERSWITCH_VID_MASK)) 167cc320e37SLuiz Otavio O Souza return (EINVAL); 168cc320e37SLuiz Otavio O Souza } 169cc320e37SLuiz Otavio O Souza sc->vlan[vg->es_vlangroup].vlanid = vg->es_vid & 170cc320e37SLuiz Otavio O Souza ETHERSWITCH_VID_MASK; 171cc320e37SLuiz Otavio O Souza /* Setting the vlanid to zero disables the vlangroup. */ 172cc320e37SLuiz Otavio O Souza if (sc->vlan[vg->es_vlangroup].vlanid == 0) { 173cc320e37SLuiz Otavio O Souza sc->vlan[vg->es_vlangroup].ports = 0; 174cc320e37SLuiz Otavio O Souza return (sc->hal.ip17x_hw_setup(sc)); 175cc320e37SLuiz Otavio O Souza } 176cc320e37SLuiz Otavio O Souza sc->vlan[vg->es_vlangroup].vlanid |= ETHERSWITCH_VID_VALID; 177cc320e37SLuiz Otavio O Souza } 178248dd603SAdrian Chadd 179248dd603SAdrian Chadd /* Member Ports. */ 180248dd603SAdrian Chadd sc->vlan[vg->es_vlangroup].ports = 0; 181248dd603SAdrian Chadd for (i = 0; i < sc->numports; i++) { 182248dd603SAdrian Chadd if ((vg->es_member_ports & (1 << i)) == 0) 183248dd603SAdrian Chadd continue; 184248dd603SAdrian Chadd phy = sc->portphy[i]; 185248dd603SAdrian Chadd sc->vlan[vg->es_vlangroup].ports |= (1 << phy); 186248dd603SAdrian Chadd } 187248dd603SAdrian Chadd 188248dd603SAdrian Chadd return (sc->hal.ip17x_hw_setup(sc)); 189248dd603SAdrian Chadd } 190