Index: sys/dev/switch/switch_iicbus.c =================================================================== --- sys/dev/switch/switch_iicbus.c (revision 0) +++ sys/dev/switch/switch_iicbus.c (revision 0) @@ -0,0 +1,88 @@ +/*- + * Copyright (c) 2011, Aleksandr Rybalko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "iicbus_if.h" + +struct switch_i2c_softc { + device_t sc_dev; +}; + +static int +switch_i2c_probe(device_t dev) +{ + device_set_desc(dev, "Ethernet Switch on I2C"); + return (BUS_PROBE_NOWILDCARD); +} + +static int +switch_i2c_init(device_t dev) +{ + int error = 0; + + return (error); +} + +static int +switch_i2c_attach(device_t dev) +{ + struct switch_i2c_softc *sc = device_get_softc(dev); + int error; + + sc->sc_dev = dev; + + return (error); +} + +static device_method_t switch_i2c_methods[] = { + DEVMETHOD(device_probe, switch_i2c_probe), + DEVMETHOD(device_attach, switch_i2c_attach), + + {0, 0}, +}; + +static driver_t switch_i2c_driver = { + "switch_i2c", + switch_i2c_methods, + sizeof(struct switch_i2c_softc), +}; +static devclass_t switch_i2c_devclass; + +DRIVER_MODULE(switch, iicbus, switch_i2c_driver, switch_i2c_devclass, 0, 0); +MODULE_VERSION(switch, 1); +MODULE_DEPEND(switch, iicbus, 1, 1, 1); Property changes on: sys/dev/switch/switch_iicbus.c ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/dev/switch/switch_mii.c =================================================================== --- sys/dev/switch/switch_mii.c (revision 0) +++ sys/dev/switch/switch_mii.c (revision 0) @@ -0,0 +1,418 @@ +/*- + * Copyright (c) 2009, M. Warner Losh + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +/* Required for struct switch_softc */ +#include + +#include +#include + +/* MII interface */ +#include +#include +#include "miibus_if.h" + +/* Switch interface */ +#include +#include "switch_if.h" +#include "switchb_if.h" + +struct switch_mii_softc { + struct mii_softc sc_mii; /* generic PHY */ + device_t sc_miidev; /* generic PHY dev */ + device_t sc_dev; + struct switch_softc sc_switch; /* switch softc */ +}; + +static int switch_mii_probe(device_t); +static int switch_mii_attach(device_t); +static uint32_t switch_mii_read4(device_t, uint32_t); +static void switch_mii_write4(device_t, uint32_t, uint32_t); + +static device_method_t switch_mii_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, switch_mii_probe), + DEVMETHOD(device_attach, switch_mii_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + + /* switch bus interface */ + DEVMETHOD(switchb_read4, switch_mii_read4), + DEVMETHOD(switchb_write4, switch_mii_write4), + + { 0, 0 } +}; + +static devclass_t switch_mii_devclass; + +static driver_t switch_mii_driver = { + "switch", + switch_mii_methods, + sizeof(struct switch_mii_softc) +}; + +DRIVER_MODULE(switch, miibus, switch_mii_driver, switch_mii_devclass, 0, 0); + +static int switch_mii_service(struct mii_softc *, struct mii_data *, int); +static void switch_mii_status(struct mii_softc *); + + +static const struct mii_phy_funcs switch_mii_funcs = { + switch_mii_service, + switch_mii_status, + mii_phy_reset +}; + +static int +switch_mii_probe(device_t dev) +{ + const char *iface; + const char *pparent; + + /* Get NIC name */ + pparent = device_get_nameunit( + device_get_parent( + device_get_parent(dev))); + + device_printf(dev, "Parent iface is %s\n", pparent); + + /* Get iface name hint */ + if (!resource_string_value(device_get_name(dev), + device_get_unit(dev), + "iface", (const char **)&iface)) { + /* If interface name hinted, check it */ + if (strcmp(pparent, iface) != 0) + /* Skip interface if not matched */ + return (ENXIO); + + /* Attach to interface if matched */ + } else + return (ENXIO); + + return (BUS_PROBE_SPECIFIC); +// return (BUS_PROBE_DEFAULT); +} + +static int +switch_mii_attach(device_t dev) +{ + struct mii_softc *sc; + struct switch_mii_softc *ssc; + device_t *devlist; + int phymask, devs, i, err; + struct mii_attach_args *ma; + struct mii_data *mii; + + phymask = 1; /* 1 is PHY0, PHY0 is me */ + ssc = device_get_softc(dev); + ssc->sc_dev = dev; + ssc->sc_miidev = device_get_parent(dev); + mii = device_get_softc(ssc->sc_miidev); + sc = &ssc->sc_mii; + + + ifmedia_add(&mii->mii_media, + IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), + MII_MEDIA_100_TX, NULL); + ifmedia_add(&mii->mii_media, + IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), + MII_MEDIA_100_TX_FDX, NULL); + ifmedia_add(&mii->mii_media, + IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, sc->mii_inst), + MII_MEDIA_1000_T, NULL); + ifmedia_add(&mii->mii_media, + IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, sc->mii_inst), + MII_MEDIA_1000_T_FDX, NULL); + + ifmedia_add(&mii->mii_media, + IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, sc->mii_inst), + MII_MEDIA_1000_X, NULL); + ifmedia_add(&mii->mii_media, + IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, sc->mii_inst), + MII_MEDIA_1000_X_FDX, NULL); + + + mii_phy_dev_attach(dev, MIIF_NOISOLATE | MIIF_NOMANPAUSE, + &switch_mii_funcs, 0); + + ma = device_get_ivars(dev); + + /* XXXXXX */ + if (device_get_unit(device_get_parent(device_get_parent(dev))) == 0) {// arge0 + sc->mii_capabilities = BMSR_100TXFDX|BMSR_100TXHDX; + sc->mii_extcapabilities = 0; + } else { + sc->mii_capabilities = BMSR_100TXFDX|BMSR_100TXHDX|BMSR_EXTCAP; + sc->mii_extcapabilities = EXTSR_1000TFDX|EXTSR_1000THDX; + } + + device_printf(dev, " "); + mii_phy_add_media(sc); + printf("\n"); + + if (device_get_children(ssc->sc_miidev, &devlist, &devs) == 0) { + for (i = 0; i < devs; i++) { + if (devlist[i] != dev) { + ma = device_get_ivars(devlist[i]); + phymask |= (1 << ma->mii_phyno); + } + } + free(devlist, M_TEMP); + } + if (bootverbose) + device_printf(dev, "phymask of attached PHYs 0x%08x\n", phymask); + + ssc->sc_switch.sc_dev = dev; + ssc->sc_switch.phys = phymask; + SWITCH_LOCK_INIT(&ssc->sc_switch); + err = switch_init(&ssc->sc_switch); + if (err) + return (err); + + MIIBUS_MEDIAINIT(ssc->sc_miidev); + + return (bus_generic_attach(dev)); +} + +static int +switch_mii_service(struct mii_softc *sc, struct mii_data *mii, int cmd) +{ + + switch (cmd) { + case MII_POLLSTAT: + break; + + case MII_MEDIACHG: + /* + * If the interface is not up, don't do anything. + */ + if ((mii->mii_ifp->if_flags & IFF_UP) == 0) + break; + + mii_phy_setmedia(sc); + break; + + case MII_TICK: + //switch_tick(sc); + if (mii_phy_tick(sc) == EJUSTRETURN) + return (0); + break; + } + + /* Update the media status. */ + PHY_STATUS(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} + +static void +switch_mii_status(struct mii_softc *sc) +{ + struct mii_data *mii = sc->mii_pdata; +// struct ifmedia_entry *ife = mii->mii_media.ifm_cur; + + /* XXX: always Up */ + mii->mii_media_status = IFM_AVALID | IFM_ACTIVE; + if (sc->mii_extcapabilities & (EXTSR_1000TFDX|EXTSR_1000THDX)) { + mii->mii_media_active = IFM_ETHER | IFM_1000_T | IFM_FDX; //AR8216 + } else { //arge1 + mii->mii_media_active = IFM_ETHER | IFM_100_TX | IFM_FDX; //RTL8309 + } + +} + + +static uint32_t +switch_mii_read4(device_t dev, uint32_t r) +{ + struct switch_mii_softc *ssc; + int phy, reg; + + ssc = device_get_softc(dev); + phy = (r >> 8) & 0xff; + reg = r & 0xff; + + return (MIIBUS_READREG(ssc->sc_miidev, phy, reg) & 0xffff); +} + +static void +switch_mii_write4(device_t dev, uint32_t r, uint32_t val) +{ + struct switch_mii_softc *ssc; + int phy, reg; + + ssc = device_get_softc(dev); + phy = (r >> 8) & 0xff; + reg = r & 0xff; + + MIIBUS_WRITEREG(ssc->sc_miidev, phy, reg, (val & 0xffff)); +} + + + + + + + + + + + + + + + +static int plumbphy_probe(device_t dev); +static int plumbphy_attach(device_t dev); + +static device_method_t plumbphy_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, plumbphy_probe), + DEVMETHOD(device_attach, plumbphy_attach), + DEVMETHOD(device_detach, mii_phy_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + { 0, 0 } +}; + +static devclass_t plumbphy_devclass; + +static driver_t plumbphy_driver = { + "plumbphy", + plumbphy_methods, + sizeof(struct mii_softc) +}; + +DRIVER_MODULE(plumbphy, miibus, plumbphy_driver, plumbphy_devclass, 0, 0); + +static int plumbphy_service(struct mii_softc *, struct mii_data *, int); +static void plumbphy_status(struct mii_softc *); + + +static const struct mii_phy_funcs plumbphy_funcs = { + plumbphy_service, + plumbphy_status, + mii_phy_reset +}; + +static int +plumbphy_probe(device_t dev) +{ + struct mii_attach_args *ma; + struct mii_softc *sc; + + sc = device_get_softc(dev); + if (!sc) + return (ENXIO); + +// device_printf(dev, "Parent iface is %s\n", +// device_get_name(device_get_parent(device_get_parent(dev)))); + + /* XXX */ + if (strcmp(device_get_name(device_get_parent(device_get_parent(dev))), + "arge") != 0) + return (ENXIO); + + ma = device_get_ivars(dev); + + /* XXXXXXXXXXXXXX */ + if (device_get_unit(device_get_parent(device_get_parent(dev))) == 0) {// arge0 + /* Plumb only PHYs great than 0 */ + if ( ma->mii_phyno > 0 ) + return (BUS_PROBE_GENERIC); + } else { //arge1 + /* Plumb only PHYs great than 0 */ + if ( ma->mii_phyno > 16 ) + return (BUS_PROBE_GENERIC); + } + + return (ENXIO); +} + +static int +plumbphy_attach(device_t dev) +{ + struct mii_attach_args *ma; + struct mii_softc *sc; + + sc = device_get_softc(dev); + ma = device_get_ivars(dev); + mii_phy_dev_attach(dev, 0, &plumbphy_funcs, 0); +// mii_phy_setmedia(sc); + sc->mii_capabilities = BMSR_100TXFDX;// & ma->mii_capmask; + device_printf(dev, " "); + mii_phy_add_media(sc); + printf("\n"); + + return (0); +} + +static int +plumbphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd) +{ + + switch (cmd) { + case MII_POLLSTAT: + case MII_MEDIACHG: + break; + + case MII_TICK: + if (mii_phy_tick(sc) == EJUSTRETURN) + return (0); + break; + } + + /* Update the media status. */ + PHY_STATUS(sc); + + /* Callback if something changed. */ + mii_phy_update(sc, cmd); + return (0); +} + +static void +plumbphy_status(struct mii_softc *sc) +{ + struct mii_data *mii = sc->mii_pdata; + + mii->mii_media_status = IFM_AVALID; + mii->mii_media_active = IFM_ETHER; +// mii->mii_media_active = IFM_ETHER | IFM_100_TX | IFM_FDX; + +} + + Property changes on: sys/dev/switch/switch_mii.c ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/dev/switch/switch_ioctl.h =================================================================== --- sys/dev/switch/switch_ioctl.h (revision 0) +++ sys/dev/switch/switch_ioctl.h (revision 0) @@ -0,0 +1,209 @@ +/*- + * Copyright (c) 2011, Aleksandr Rybalko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * + */ + +#ifndef _SWITCH_IOCTL_H_ +#define _SWITCH_IOCTL_H_ + +#define SWITCH_API_VERSION 0 +#define SWITCH_IOCTL_MAIN_BASE 0x00 + +/* Main switch configuration */ +struct switch_config { + uint32_t phys; /* PHY IDs that switch use */ + uint8_t version; /* Version: Now 0. */ + uint8_t cmd; /* 0 - Get, 1 - Set */ + uint8_t enable; /* switch state, RW */ + uint8_t status; /* Command status */ +}; + +/* Basic switch config */ +#define SWITCH_CONFIG SWITCH_IOCTL_MAIN_BASE+0 +#define IOCTL_SWITCH_CONFIG _IOWR('E', SWITCH_CONFIG, struct switch_config) + +/* Switch capability list */ +struct switch_caps { + + uint8_t version; /* Version: Now 0. */ + uint8_t cmd; /* 0 - Get, 1 - Set */ + uint8_t status; /* Command status */ + uint8_t ports; /* Number of ports */ + uint32_t main; +#define SWITCH_CAPS_MAIN_PORT_POWER (1<<0) +#define SWITCH_CAPS_MAIN_PORT_MIRROR (1<<1) /* Can do port mirror */ +#define SWITCH_CAPS_MAIN_PORT_SECURITY (1<<2) /* Can limit n MACs */ + uint32_t vlan; +#define SWITCH_CAPS_VLAN_PORT (1<<0) /* Support port based */ +#define SWITCH_CAPS_VLAN_DOT1Q (1<<1) /* 802.1q */ +#define SWITCH_CAPS_VLAN_ISL (1<<2) /* ISL */ +#define SWITCH_CAPS_VLAN_GLBL_UNTG (1<<3) /* Global tag/untag */ +#define SWITCH_CAPS_VLAN_LAN_WAN (1<<4) /* LAN/WAN spliting */ +#define SWITCH_CAPS_VLAN_DOUBLE_TAG (1<<5) /* Q-in-Q */ +#define SWITCH_CAPS_VLAN_MAX_SHIFT_MASK 0x0000fff0 /* max VLAN index */ +#define SWITCH_CAPS_VLAN_MAX_SHIFT_SHIFT 4 /* 4096-full support */ + uint32_t qos; +#define SWITCH_CAPS_QOS_QUEUES_MASK 0x00000007 /* 2 - 4 queues */ +#define SWITCH_CAPS_QOS_QUEUES_SHIFT 0 /* 3 - 8 queues */ + uint32_t lacp; + uint32_t stp; + uint32_t acl; + uint32_t stat; +}; + +/* List of switch capability */ +#define SWITCH_CAP SWITCH_IOCTL_MAIN_BASE+1 +#define IOCTL_SWITCH_CAP _IOWR('E', SWITCH_CAP, struct switch_caps) + +struct switch_reg { + uint32_t addr; + uint32_t value; +}; + +#define SWITCH_GETREG SWITCH_IOCTL_MAIN_BASE+2 +#define IOCTL_SWITCH_GETREG _IOWR('E', SWITCH_GETREG, struct switch_reg) +#define SWITCH_SETREG SWITCH_IOCTL_MAIN_BASE+3 +#define IOCTL_SWITCH_SETREG _IOWR('E', SWITCH_SETREG, struct switch_reg) + + +enum vlan_type_e { + VLAN_TYPE_NONE = 0, + VLAN_TYPE_PORT, + VLAN_TYPE_DOT1Q, + VLAN_TYPE_ISL +}; + +struct vlan_config { + uint8_t version; /* Version: Now 0. */ + uint8_t cmd; /* 0 - Get, 1 - Set */ + uint8_t status; /* Command status */ + /* Current VLAN mode, RW (if switch can) */ + enum vlan_type_e vlan_type; + union { + struct { + enum { + VLAN_BASE_TYPE_NONE, /* Device use 12bit */ + VLAN_BASE_TYPE_FREE, /* VID=base+id */ + VLAN_BASE_TYPE_2MASK, /* VID=(base&~3)+id */ + VLAN_BASE_TYPE_3MASK, /* VID=(base&~7)+id */ + VLAN_BASE_TYPE_4MASK, /* VID=(base&~f)+id */ + VLAN_BASE_TYPE_5MASK, /* VID=(base&~1f)+id */ + } vlan_base_type; + /* + * VLAN base, for switches that do not + * support 12 bit tag + */ + uint16_t vlan_base; + } dot1q; + } d; +}; + +struct vlan_vlan_config { + uint8_t version; /* Version: Now 0. */ + uint8_t cmd; /* 0 - Get, 1 - Set */ + uint8_t status; /* Command status */ + /* Resource index (Port for Port based, VLAN index for 802.1q) */ + uint16_t index; + enum vlan_type_e vlan_type; + union { + /* Port based */ + struct { + /* Ports allowed for access with port in `index` */ + uint32_t allowed; + } port; + struct { + /* VLAN ID (12 bit) */ + uint16_t vid; + /* Per port config */ + uint8_t port_config[32]; +#define DOT1Q_PORT_VLAN_CONFIG_VLAN_NONE (0<<0) /* Not a member */ +#define DOT1Q_PORT_VLAN_CONFIG_VLAN_TAGGED (1<<0) /* Tagged member */ +#define DOT1Q_PORT_VLAN_CONFIG_VLAN_UNTAGGED (2<<0) /* Untagged member */ +#define DOT1Q_PORT_VLAN_CONFIG_VLAN_FORBIDDEN (3<<0) /* Filtered if no + * ingress checking */ +#define DOT1Q_PORT_VLAN_CONFIG_VLAN_MASK (7<<0) +#define DOT1Q_PORT_VLAN_CONFIG_VLAN_TXTAG (1<<3) /* Tagging on TX */ + + } dot1q; + } d; +}; + +struct vlan_port_config { + uint8_t version; /* Version: Now 0. */ + uint8_t cmd; /* 0 - Get, 1 - Set */ + uint8_t status; /* Command status */ + /* Port index */ + uint16_t index; + /* 802.1q/ISL */ + enum vlan_type_e vlan_type; + union { + /* 802.1q based */ + struct { + uint32_t flags; +#define DOT1Q_VLAN_PORT_FLAG_INGRESS (1<<0) /* Ingress checking */ +#define DOT1Q_VLAN_PORT_FLAG_DOUBLE_TAG (1<<1) /* Enable Q-in-Q */ +#define DOT1Q_VLAN_PORT_FLAG_LAN (1<<2) /* Marked as LAN port */ +#define DOT1Q_VLAN_PORT_FLAG_WAN (1<<3) /* Marked as WAN port */ +#define DOT1Q_VLAN_PORT_FLAG_TAGGED (1<<4) /* Port tagged in all VLANs */ +#define DOT1Q_VLAN_PORT_FLAG_UNTAGGED (1<<5) /* Port untagged in all VLANs */ +#define DOT1Q_VLAN_PORT_FLAG_FORCE_UNTAGGED (1<<6) /* Remove tag */ +#define DOT1Q_VLAN_PORT_FLAG_FORCE_PVID (1<<7) /* Reassign tag to PVID */ +#define DOT1Q_VLAN_PORT_FLAG_DROP_UNTAGGED (1<<8) /* Drop untagged frames */ + uint16_t vid; + } dot1q; + /* ISL based */ + struct { + uint32_t flags; + uint16_t color; + } isl; + } d; +}; + +#define SWITCH_IOCTL_VLAN_BASE 0x10 +/* get/set switch VLAN basic configuration */ +#define VLAN_CONFIG SWITCH_IOCTL_VLAN_BASE+0 +/* + * get/set switch VLAN configuration for + * one port (Port based) + * one VLAN index (!!!not VID!!!) (802.1Q) + * one ISL index (ISL) + */ +#define VLAN_VLAN_CONFIG SWITCH_IOCTL_VLAN_BASE+1 +/* + * get/set switch port PVID for + * 802.1q or ISL + */ +#define VLAN_PORT_CONFIG SWITCH_IOCTL_VLAN_BASE+2 + +#define IOCTL_VLAN_CONFIG _IOWR('E', VLAN_CONFIG, struct vlan_config) +#define IOCTL_VLAN_VLAN_CONFIG _IOWR('E', VLAN_VLAN_CONFIG, \ + struct vlan_vlan_config) +#define IOCTL_VLAN_PORT_CONFIG _IOWR('E', VLAN_PORT_CONFIG, \ + struct vlan_port_config) + + +#endif /* _SWITCH_IOCTL_H_ */ Property changes on: sys/dev/switch/switch_ioctl.h ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/dev/switch/bcm5325_switch.c =================================================================== --- sys/dev/switch/bcm5325_switch.c (revision 0) +++ sys/dev/switch/bcm5325_switch.c (revision 0) @@ -0,0 +1,828 @@ +/*- + * Copyright (c) 2011 Aleksandr Rybalko. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +//XXX +#include +#include + +#include +#include +#include +#include + +#include "switch_if.h" +#include "switchb_if.h" + +//XXX +#include "miibus_if.h" + +static int bcm5325_switch_probe(device_t dev); +static int bcm5325_switch_attach(device_t dev); +static int bcm5325_switch_detach(device_t dev); + +/* TODO */ +static int find_mac_addr(device_t dev, uint64_t mac); +/* TODO */ +static int mac_table_write(device_t dev, uint64_t mac, int idx, + uint32_t port_map, uint8_t age, int *hash_idx ); + +static int get_reg(device_t dev, uint32_t reg, uint32_t *value); +static int set_reg(device_t dev, uint32_t reg, uint32_t *value); +static int set_port_vid(device_t dev, int port, uint16_t pvid); +static int get_port_vid(device_t dev, int port, uint16_t *pvid); +static int set_vid(device_t dev, int idx, uint16_t vid); +static int get_vid(device_t dev, int idx, uint16_t *vid); +static int set_vlan_ports(device_t dev, int idx, uint32_t memb); +static int get_vlan_ports(device_t dev, int idx, uint32_t *memb); +static int set_vlan_untagged_ports(device_t dev, int idx, uint32_t memb); +static int get_vlan_untagged_ports(device_t dev, int idx, uint32_t *memb); + +static int bcm5325_write(struct bcm5325_switch_softc *sc, uint32_t reg, uint64_t val); +static int bcm5325_read(struct bcm5325_switch_softc *sc, uint32_t reg, uint64_t *val); + +#define PSPHY_WRITE(_sc, _reg, _val) \ + MII_SW_WRITE4((_sc), ((PSEUDOPHY_ADDR << 8) | (_reg)), (_val)) +#define PSPHY_READ(_sc, _reg) \ + MII_SW_READ4((_sc), ((PSEUDOPHY_ADDR << 8) | (_reg))) + +#define WRITE4(_sc, _reg, _val) \ + MII_SW_WRITE4((_sc), ((PSEUDOPHY_ADDR << 8) | (_reg)), (_val)) +//#define READ4(_sc, _reg) +// MII_SW_READ4((_sc), ((PSEUDOPHY_ADDR << 8) | (_reg))) + +#define WRITE(_sc, _reg, _val) bcm5325_write((_sc), (_reg), (_val)) +#define READ(_sc, _reg, _val) bcm5325_read((_sc), (_reg), (_val)) + +static uint32_t +READ4(struct bcm5325_switch_softc *sc, uint32_t reg) +{ + uint64_t val; + int error; + + error = bcm5325_read(sc, reg, &val); + + if (error) + return (0xffffffff); + + return (val & 0xffffffff); +} + +static int +bcm5325_write(struct bcm5325_switch_softc *sc, uint32_t reg, uint64_t val) +{ + int i; + uint8_t len, page; + + len = (reg & 0x00ff0000) >> 16; + page = (reg & 0x0000ff00) >> 8; + reg &= 0x000000ff; + + PSPHY_WRITE(sc, BCM5325_ACCESS_CONTROL_REG, + (((page << ACCESS_CONTROL_PAGE_SHIFT) & + ACCESS_CONTROL_PAGE_MASK) | ACCESS_CONTROL_RW)); + + for (i = 0; i < len; i+=2){ + PSPHY_WRITE(sc, BCM5325_DATA_15_0_REG + (i/2), + (val >> (8*i)) & 0xffff); + } + + PSPHY_WRITE(sc, BCM5325_RW_CONTROL_REG, + ((reg << RW_CONTROL_ADDR_SHIFT) & RW_CONTROL_ADDR_MASK) | + RW_CONTROL_WRITE); + + /* is operation finished? */ + for (i = BCM5325_OP_RETRY; i > 0; i --) { + if ((PSPHY_READ(sc, BCM5325_RW_CONTROL_REG) & + RW_CONTROL_OP_MASK) == RW_CONTROL_NOP) + break; + } + + /* timed out */ + if (!i) { + printf("mii_wreg: timeout"); + return (EBUSY); + } + + i = PSPHY_READ(sc, BCM5325_RW_STATUS_REG); + if (i & 0x0003) + printf("XXX: reg=%08x BCM5325_RW_STATUS_REG=%d\n", reg, i); + + return (0); +} + +static int +bcm5325_read(struct bcm5325_switch_softc *sc, uint32_t reg, uint64_t *val) +{ + int i; + uint8_t len, page; + + *val = 0; + len = (reg & 0x00ff0000) >> 16; + page = (reg & 0x0000ff00) >> 8; + reg &= 0x000000ff; + + PSPHY_WRITE(sc, BCM5325_ACCESS_CONTROL_REG, + (((page << ACCESS_CONTROL_PAGE_SHIFT) & + ACCESS_CONTROL_PAGE_MASK) | ACCESS_CONTROL_RW)); + + PSPHY_WRITE(sc, BCM5325_RW_CONTROL_REG, + ((reg << RW_CONTROL_ADDR_SHIFT) & RW_CONTROL_ADDR_MASK) | + RW_CONTROL_READ); + + /* is operation finished? */ + for (i = BCM5325_OP_RETRY; i > 0; i --) { + if ((PSPHY_READ(sc, BCM5325_RW_CONTROL_REG) & + RW_CONTROL_OP_MASK) == RW_CONTROL_NOP) + break; + } + /* timed out */ + if (!i) { + return (EBUSY); + } + + for (i = 0; i < len; i+=2){ + *val |= PSPHY_READ(sc, BCM5325_DATA_15_0_REG + (i/2)) << (8*i); + } + + i = PSPHY_READ(sc, BCM5325_RW_STATUS_REG); + if (i & 0x0003) + printf("XXX: reg=%08x BCM5325_RW_STATUS_REG=%d\n", reg, i); + + return (0); +} + + + +//XXX +static void +new_mii_statchg(device_t dev) +{ +} + +//XXX +static int +new_ifmedia_upd(struct ifnet *ifp) +{ + + return (0); +} + +/* + * Report current media status. + */ +//XXX +static void +new_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr) +{ +} + + + +static int +bcm5325_switch_probe(device_t dev) +{ + struct child_res_avl *res; + + res = device_get_ivars(dev); + + /* PHY30 will be detected */ + + /* bcm5325 show at leaset 5 PHYs */ + if ((res->phys & 0x1f) != 0x1f) + return (ENXIO); + + device_set_desc(dev, "BCM5325 family ethernet switch"); + return (BUS_PROBE_DEFAULT); +} + +static int +bcm5325_switch_attach(device_t dev) +{ + struct bcm5325_switch_softc *sc; + uint64_t reg; + int i, error = 0; + + sc = device_get_softc(dev); + sc->parent = device_get_parent(dev); + + sc->caps = malloc(sizeof(struct switch_capability), M_DEVBUF, + M_WAITOK | M_ZERO); + + if (!sc->caps) + return (ENXIO); + + sc->caps->ports = sc->ports = 9; + sc->vlans = 9; + sc->sc_dev = dev; + +#define S_C(x) SWITCH_CAPS_ ## x + sc->caps->main = S_C(MAIN_PORT_POWER); + sc->caps->vlan = S_C(VLAN_GLBL_UNTG) | S_C(VLAN_DOT1Q) | + S_C(VLAN_DOUBLE_TAG) | + ((sc->vlans << S_C(VLAN_MAX_SHIFT_SHIFT)) & S_C(VLAN_MAX_SHIFT_MASK)); + sc->caps->qos = (2 << S_C(QOS_QUEUES_SHIFT)) & S_C(QOS_QUEUES_MASK); + sc->caps->lacp = 0; /* No LACP caps */ + sc->caps->stp = 0; /* No STP caps */ + sc->caps->acl = 0; + sc->caps->stat = 0; +#undef S_C + +#define DUMP(_reg) device_printf(dev, #_reg "=%08x\n", READ4(sc, _reg)) + DUMP(PORT_CTL(PORT0)); + DUMP(PORT_CTL(PORT1)); + DUMP(PORT_CTL(PORT2)); + DUMP(PORT_CTL(PORT3)); + DUMP(PORT_CTL(PORT4)); + DUMP(PORT_CTL(PORT5)); + DUMP(PORT_CTL(PORT6)); + DUMP(PORT_CTL(PORT7)); + DUMP(PORT_CTL(PORTMII)); + + DUMP(PORTMII_STATUS_OVERRIDE); + DUMP(SWITCH_DEVICEID); + DUMP(BIST_STATUS_RC); + DUMP(VLAN_GLOBAL_CTL0); + DUMP(VLAN_GLOBAL_CTL1); + DUMP(VLAN_GLOBAL_CTL2); + DUMP(VLAN_DROP_UNTAGGED); + DUMP(VLAN_GLOBAL_CTL4); + DUMP(VLAN_GLOBAL_CTL5); +// DUMP(); +// DUMP(); +#undef DUMP + + /* MII port state override (page 0 register 14) */ + READ(sc, PORTMII_STATUS_OVERRIDE , ®); + + /* Bit 4 enables reverse MII mode */ + if (!(reg & PORTMII_STATUS_REVERSE_MII)) + { + /* Enable RvMII */ + reg |= PORTMII_STATUS_REVERSE_MII; + WRITE(sc, PORTMII_STATUS_OVERRIDE, reg); + /* Read back */ + READ(sc, PORTMII_STATUS_OVERRIDE, ®); + if (!(reg & PORTMII_STATUS_REVERSE_MII)) + { + device_printf(dev, "Unable to set RvMII mode\n"); + bcm5325_switch_detach(dev); + return (ENXIO); + } + } + + /* Reset PHYs */ +// for (i = 1; i < 8; i++) +// WRITE4(sc, PHY_CTL(i), PHY_CTL_RESET); + + /* Set to Auto-Negotiation and reset Auto-Negotiation process */ +// for (i = 1; i < 8; i++) +// WRITE4(sc, PHY_CTL(i), PHY_CTL_ANEG|PHY_CTL_ANEG_RESTART); + + /* Insert tag on ingress packet */ +// for (i = 1; i < 8; i++) +// WRITE4(sc, PHY_CTRL0(i), +// (READ4(sc, PHY_CTRL0(i)) & 0xfffc) | CTRL0_TAG_I_UTG); + +// WRITE4(sc, GCNTRL0, +// (6 << GCNTRL0_LED_MODE_SHIFT) | /* LED Mode 6: Activity,Speed,Link */ +// GCNTRL0_INGRESS_CHECK_DIS | +// GCNTRL0_TAG_ONLY_DIS | +// GCNTRL0_TX_FC | +// GCNTRL0_RX_FC | +// GCNTRL0_AGN_EN); + + /* set_vid(swdev, Idx, VID) */ + set_vid(dev, 0, 1); +// set_vid(dev, 1, 2); +// set_vid(dev, 2, 3); +// set_vid(dev, 3, 4); +// set_vid(dev, 4, 5); +// set_vid(dev, 5, 6); +// set_vid(dev, 6, 7); +// set_vid(dev, 7, 8); +// set_vid(dev, 8, 9); + + /* All ports are members of VLAN0 (VID1) */ + set_vlan_ports(dev, 0, 0x01ff); + /* Other VLANs have no members */ + for (i = 1; i < 9; i++) + set_vlan_ports(dev, i, 0x00); + /* VLAN1 to all ports */ +// for (i = 0; i < 9; i++) +// set_port_vid_idx(sc, i, 0); + + /* Remove isolate flag */ +// for (i = 1; i < 8; i++) +// WRITE4(sc, PHY_CTL(i), READ4(sc, PHY_CTL(i)) & ~PHY_CTL_ISOLATE); + + + struct ifnet *ifp = if_alloc(1); //0x01 - IFT_OTHER //IFT_ETHER); + error = mii_attach(dev, &sc->new_mii, ifp, new_ifmedia_upd, + new_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, + 0); + if (error != 0) { + device_printf(dev, "attaching PHYs failed\n"); + } + + return (0); +} + +static int +bcm5325_switch_detach(device_t dev) +{ + struct bcm5325_switch_softc *sc; + + sc = device_get_softc(dev); + + if (sc->caps) + free(sc->caps, M_DEVBUF); + + return (0); +} + +/* + * Switch capability + */ +static struct switch_capability * +get_caps(device_t dev) +{ + struct bcm5325_switch_softc *sc; + + sc = device_get_softc(dev); + + return (sc->caps); +} + +/* + * Variable holding upper 32bits of get_reg/set_reg requests. + * Accessible with special reg address 0x0fffffff + */ +static uint32_t get_set_upper32 = 0; + +static int +get_reg(device_t dev, uint32_t reg, uint32_t *value) +{ + struct bcm5325_switch_softc *sc; + uint64_t val64; + int error = 0; + + sc = device_get_softc(dev); + + if (reg & 0x80000000ul) { + *value = MII_SW_READ4(sc, reg); + return (0); + } + + if (reg == 0x0ffffffful) { + *value = get_set_upper32; + } else { + error = READ(sc, reg, &val64); + if (((reg & 0x00ff0000) >> 16) > 4) + printf("\t%08x = %016llx\n", reg, val64); + if (error == 0) { + *value = (uint32_t)(val64 & 0xffffffff); + get_set_upper32 = + (uint32_t)((val64 >> 32) & 0xffffffff); + } + } + return (error); +} + +static int +set_reg(device_t dev, uint32_t reg, uint32_t *value) +{ + struct bcm5325_switch_softc *sc; + uint64_t val64; + uint32_t old; + int error = 0; + + sc = device_get_softc(dev); + + if (reg & 0x80000000ul) { + old = MII_SW_READ4(sc, reg); + MII_SW_WRITE4(sc, reg, *value); + *value = old; + return (0); + } + + if (reg == 0x0ffffffful) { + old = get_set_upper32; + get_set_upper32 = *value; + *value = old; + } else { + error = READ(sc, reg, &val64); + if (error == 0) { + /* + * If old value required for 64bits registers, + * use get_reg first + */ + old = (uint32_t)(val64 & 0xffffffff); + } else { + return (error); + } + /* + * When write 64bits value always set 0x0fffffff reg + * to upper 32 bit + */ + val64 = ((uint64_t)get_set_upper32 << 32) | (*value); + error = WRITE(sc, reg, val64); + if (error == 0) + return (error); + + *value = old; + } + return (error); +} + +static int +find_mac_addr(device_t dev, uint64_t mac) +{ + struct bcm5325_switch_softc *sc; + int idx = -1; +// uint32_t reg; + + sc = device_get_softc(dev); + + return (idx); +} + +static int +mac_table_write(device_t dev, uint64_t mac, int idx, uint32_t port_map, + uint8_t age, int *hash_idx ) +{ +// struct bcm5325_switch_softc *sc = device_get_softc(dev); +// uint32_t reg; + + + return (0); +} + +static int +set_port_vid(device_t dev, int port, uint16_t pvid) +{ + struct bcm5325_switch_softc *sc; + int error = 0; + + sc = device_get_softc(dev); + if (port > (sc->ports - 1)) + return (EINVAL); + + if (pvid > 0xfff) + return (EINVAL); + + error = WRITE(sc, VLAN_DEFAULT_PORT_TAG(port), pvid); + + return (error); +} + +static int +get_port_vid(device_t dev, int port, uint16_t *pvid) +{ + struct bcm5325_switch_softc *sc; + uint64_t reg; + int error = 0; + + sc = device_get_softc(dev); + if (port > (sc->ports - 1)) + return (EINVAL); + + error = READ(sc, VLAN_DEFAULT_PORT_TAG(port), ®); + *pvid = reg & 0xfff; + + return (error); +} + +static int +get_port_flags(device_t dev, int port, uint32_t *flags) +{ + struct bcm5325_switch_softc *sc; + uint64_t reg = 0; + int error = 0; + + *flags = 0; + sc = device_get_softc(dev); + if (port > (sc->ports - 1)) + return (EINVAL); + + error = READ(sc, VLAN_DROP_UNTAGGED, ®); + if (error) + return (error); + if (reg & VLAN_DROP_UNTAGGED_ONPORT(port)) + *flags |= DOT1Q_VLAN_PORT_FLAG_DROP_UNTAGGED; + + return (0); +} + +static int +set_port_flags(device_t dev, int port, uint32_t flags) +{ + struct bcm5325_switch_softc *sc; + uint64_t reg; + int error = 0; + + sc = device_get_softc(dev); + if (port > (sc->ports - 1)) + return (EINVAL); + + error = READ(sc, VLAN_DROP_UNTAGGED, ®); + if (error) + return (error); + + if (flags & DOT1Q_VLAN_PORT_FLAG_DROP_UNTAGGED) + reg |= VLAN_DROP_UNTAGGED_ONPORT(port); + else + reg &= ~VLAN_DROP_UNTAGGED_ONPORT(port); + + error = WRITE(sc, VLAN_DROP_UNTAGGED, reg); + + return (error); +} + +static int +bcm5325_vlan_write(struct bcm5325_switch_softc *sc, uint16_t vid, uint8_t tports, uint8_t uports) +{ + uint64_t reg; + int error = 0; + + reg = VLAN_RW_VALID | + ((tports << VLAN_RW_MEMBER_SHIFT) & VLAN_RW_MEMBER_MASK) | + ((uports << VLAN_RW_UNTAGGED_SHIFT) & VLAN_RW_UNTAGGED_MASK); + error = WRITE(sc, VLAN_WRITE, reg); + if (error) + return (error); + reg = VLAN_TABLE_ACCESS_RW_ENABLE | VLAN_TABLE_ACCESS_WRITE | + (vid & VLAN_TABLE_ACCESS_VID_MASK); + error = WRITE(sc, VLAN_TABLE_ACCESS, reg); + + return (error); +} + +static int +bcm5325_vlan_read(struct bcm5325_switch_softc *sc, uint16_t vid, uint8_t *tports, uint8_t *uports) +{ + uint64_t reg; + int error = 0; + + reg = VLAN_TABLE_ACCESS_RW_ENABLE | + (vid & VLAN_TABLE_ACCESS_VID_MASK); + error = WRITE(sc, VLAN_TABLE_ACCESS, reg); + if (error) + return (error); + + error = READ(sc, VLAN_READ, ®); + if (error) + return (error); + if (!(reg & VLAN_RW_VALID)) + return (ENOENT); + if (tports != NULL) + *tports = (reg & VLAN_RW_MEMBER_MASK) >> VLAN_RW_MEMBER_SHIFT; + if (uports != NULL) + *uports = (reg & VLAN_RW_UNTAGGED_MASK) >> VLAN_RW_UNTAGGED_SHIFT; + + return (error); +} + +/* + * set_vid(dev, idx, vid) + * Define a VLAN, since BCM5325 family use only lower 4-8 bits of VID - + * idx parameter ignored. + * VID = base_vlan << 4(or 8, dep on chip) + idx. + * When base_vlan not equal with previouse value, WARNING displayed. + */ + +static int +set_vid(device_t dev, int idx, uint16_t vid) +{ + struct bcm5325_switch_softc *sc; + uint16_t base_vlan_mask; + int error = 0; + //uint32_t reg; + + sc = device_get_softc(dev); + if (idx > (sc->vlans - 1)) + return (EINVAL); + + base_vlan_mask = ~(sc->vlans - 1); + if ((vid & base_vlan_mask) != sc->base_vlan) { + device_printf(sc->sc_dev, "WARNING: Base VLAN changed\n"); + sc->base_vlan = (vid & base_vlan_mask); + } + + error = bcm5325_vlan_read(sc, vid, NULL, NULL); + if (error == ENOENT) { + /* Create empty valid VLAN port set */ + bcm5325_vlan_write(sc, vid, 0, 0); + } + + return (error); +} + +static int +get_vid(device_t dev, int idx, uint16_t *vid) +{ + struct bcm5325_switch_softc *sc = device_get_softc(dev); + + if (idx > (sc->vlans - 1)) + return (EINVAL); + + *vid = sc->base_vlan * sc->vlans + idx; + + return (0); +} + +static int +set_vlan_ports(device_t dev, int idx, uint32_t memb) +{ + struct bcm5325_switch_softc *sc = device_get_softc(dev); + uint8_t umemb; + int error = 0; + + printf("%s: idx=%d, memb=%08x\n", __func__, idx, memb); + + if (idx > (sc->vlans - 1)) + return (EINVAL); + if (memb & (((1 << sc->ports) - 1) << sc->ports)) + return (EINVAL); + + error = bcm5325_vlan_read(sc, idx /* must be vid */, NULL, &umemb); + error = bcm5325_vlan_write(sc, idx /* must be vid */, memb, umemb); + + return (error); +} + +static int +get_vlan_ports(device_t dev, int idx, uint32_t *memb) +{ + struct bcm5325_switch_softc *sc = device_get_softc(dev); + uint8_t reg; + int error; + + if (idx > (sc->vlans - 1)) + return (EINVAL); + + error = bcm5325_vlan_read(sc, idx /* must be vid */, ®, NULL); + if (error) + return (error); + *memb = reg; + + printf("%s: idx=%d, memb=%08x\n", __func__, idx, reg); + return (reg); +} + +static int +set_vlan_untagged_ports(device_t dev, int idx, uint32_t umemb) +{ + struct bcm5325_switch_softc *sc = device_get_softc(dev); + uint8_t memb; + int error = 0; + + printf("%s: idx=%d, memb=%08x\n", __func__, idx, umemb); + + if (idx > (sc->vlans - 1)) + return (EINVAL); + if (memb & ~((1 << sc->ports) - 1)) + return (EINVAL); + + error = bcm5325_vlan_read(sc, idx /* must be vid */, &memb, NULL); + error = bcm5325_vlan_write(sc, idx /* must be vid */, memb, umemb); + + return (error); +} + +static int +get_vlan_untagged_ports(device_t dev, int idx, uint32_t *memb) +{ + struct bcm5325_switch_softc *sc = device_get_softc(dev); + uint8_t reg; + int error; + + if (idx > (sc->vlans - 1)) + return (EINVAL); + + error = bcm5325_vlan_read(sc, idx /* must be vid */, NULL, ®); + if (error) + return (error); + *memb = reg; + + printf("%s: idx=%d, memb=%08x\n", __func__, idx, reg); + return (0); +} + +static int +new_mii_readreg(device_t dev, int phy, int reg) +{ + struct bcm5325_switch_softc *sc = device_get_softc(dev); + uint64_t val; + int error = 0; + + if ((phy > 0x1f) || (reg > 0x1f)) + return (0xffff); + + error = READ(sc, (S2 | PAGE(0x10 + (phy)) | (reg << 1)), &val); + if (error) + return (0xffff); + + return (val & 0xffff); +} + +static int +new_mii_writereg(device_t dev, int phy, int reg, int val16) +{ + struct bcm5325_switch_softc *sc = device_get_softc(dev); + uint64_t val; + + if ((phy > 0x1f) || (reg > 0x1f) || (val16 & 0xffff0000ul)) + return (0); + + val = val16; + WRITE(sc, (S2 | PAGE(0x10 + (phy)) | (reg << 1)), val); + + return (val); +} + +static device_method_t bcm5325_switch_methods[] = { + DEVMETHOD(device_probe, bcm5325_switch_probe), + DEVMETHOD(device_attach, bcm5325_switch_attach), + DEVMETHOD(device_detach, bcm5325_switch_detach), + + /* Capability */ + DEVMETHOD(switch_get_caps, get_caps), + DEVMETHOD(switch_set_reg, set_reg), + DEVMETHOD(switch_get_reg, get_reg), + + /* MAC address table */ + DEVMETHOD(switch_find_mac, find_mac_addr), + DEVMETHOD(switch_mac_write, mac_table_write), + + /* 802.1q */ + DEVMETHOD(switch_set_pvid, set_port_vid), + DEVMETHOD(switch_get_pvid, get_port_vid), + DEVMETHOD(switch_set_pflags, set_port_flags), + DEVMETHOD(switch_get_pflags, get_port_flags), + DEVMETHOD(switch_set_vid, set_vid), + DEVMETHOD(switch_get_vid, get_vid), + DEVMETHOD(switch_set_vlanports, set_vlan_ports), + DEVMETHOD(switch_get_vlanports, get_vlan_ports), + DEVMETHOD(switch_set_vlanutports, set_vlan_untagged_ports), + DEVMETHOD(switch_get_vlanutports, get_vlan_untagged_ports), + + /* MII interface */ + DEVMETHOD(miibus_readreg, new_mii_readreg), + DEVMETHOD(miibus_writereg, new_mii_writereg), + DEVMETHOD(miibus_statchg, new_mii_statchg), + + {0, 0}, +}; + +static driver_t bcm5325_switch_driver = { + "bcm5325_switch", + bcm5325_switch_methods, + sizeof(struct bcm5325_switch_softc), +}; +static devclass_t bcm5325_switch_devclass; + +DRIVER_MODULE(bcm5325_switch, switch, bcm5325_switch_driver, bcm5325_switch_devclass, 0, 0); +MODULE_VERSION(bcm5325_switch, 1); +MODULE_DEPEND(bcm5325_switch, switch, 1, 1, 1); + +DRIVER_MODULE(miibus, bcm5325_switch, miibus_driver, miibus_devclass, 0, 0); +MODULE_DEPEND(bcm5325_switch, miibus, 1, 1, 1); + Property changes on: sys/dev/switch/bcm5325_switch.c ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/dev/switch/switch.c =================================================================== --- sys/dev/switch/switch.c (revision 0) +++ sys/dev/switch/switch.c (revision 0) @@ -0,0 +1,449 @@ +/*- + * Copyright (c) 2011, Aleksandr Rybalko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice unmodified, this list of conditions, and the following + * disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "switch_if.h" +#include "switchb_if.h" + + + +static d_open_t switch_open; +static d_close_t switch_close; +static d_ioctl_t switch_ioctl; + +static int switch_config_sub(struct switch_softc *, struct switch_config *); +static int switch_caps_sub(struct switch_softc *, struct switch_caps *); +static int switch_getreg_sub(struct switch_softc *, struct switch_reg *); +static int switch_setreg_sub(struct switch_softc *, struct switch_reg *); +static int vlan_config_sub(struct switch_softc *, struct vlan_config *); +static int vlan_vlan_config_sub(struct switch_softc *, + struct vlan_vlan_config *); + +static struct cdevsw switch_cdevsw = { + .d_version = D_VERSION, + .d_open = switch_open, + .d_close = switch_close, + .d_ioctl = switch_ioctl, + .d_name = "switch" +}; + +static int +switch_open(struct cdev *dev, int oflags, int devtype, struct thread *td) +{ + + return (0); +} + +static int +switch_close(struct cdev *dev, int fflags, int devtype, struct thread *td) +{ + + return (0); +} + + +static int +switch_config_sub(struct switch_softc *sc, struct switch_config *sw) +{ + + SWITCH_ASSERT_LOCKED(sc); + + if (sw->version != SWITCH_API_VERSION) { + return (EINVAL); + } + + if (sw->cmd == 1) { + /* Set */ + if (sw->enable != sc->enable) + sc->enable = sw->enable; +#ifdef notyet + SWITCHB_ENABLE() +#endif + } else { + /* Get */ + sw->enable = sc->enable; + } + + return (0); +} + +static int +switch_caps_sub(struct switch_softc *sc, struct switch_caps *cap) +{ + + SWITCH_ASSERT_LOCKED(sc); + + if (cap->version != SWITCH_API_VERSION) { + return (EINVAL); + } + + if (cap->cmd == 1) { + /* Set */ + } else { + /* Get */ + cap->ports = sc->caps->ports; + cap->main = sc->caps->main; + cap->vlan = sc->caps->vlan; + cap->qos = sc->caps->qos; + cap->lacp = sc->caps->lacp; + cap->stp = sc->caps->stp; + cap->acl = sc->caps->acl; + cap->stat = sc->caps->stat; + } + return (0); +} + +static int switch_getreg_sub(struct switch_softc *sc, struct switch_reg *reg) +{ + int error = 0; + + SWITCH_ASSERT_LOCKED(sc); + + error = SWITCH_GET_REG(sc->child, reg->addr, ®->value); + + return (error); +} +static int switch_setreg_sub(struct switch_softc *sc, struct switch_reg *reg) +{ + int error = 0; + + SWITCH_ASSERT_LOCKED(sc); + + error = SWITCH_SET_REG(sc->child, reg->addr, ®->value); + + return (error); +} + +static int +vlan_config_sub(struct switch_softc *sc, struct vlan_config *vlan_config) +{ + + SWITCH_ASSERT_LOCKED(sc); + + if (vlan_config->version != SWITCH_API_VERSION) { + return (EINVAL); + } + + if (vlan_config->cmd == 1) { + /* Set */ + } else { + /* Get */ + } + + return (0); +} + +static int +vlan_vlan_config_sub(struct switch_softc *sc, struct vlan_vlan_config *vlan) +{ + int port, error; + uint32_t ports, uports; + + SWITCH_ASSERT_LOCKED(sc); + + if (vlan->version != SWITCH_API_VERSION) { + return (EINVAL); + } + + if (vlan->cmd == 1) { + /* Set */ + if (vlan->vlan_type == VLAN_TYPE_DOT1Q) { + ports = uports = 0; + + for (port = 0; port < sc->caps->ports; port ++) { + switch (vlan->d.dot1q.port_config[port] & + DOT1Q_PORT_VLAN_CONFIG_VLAN_MASK) { + case DOT1Q_PORT_VLAN_CONFIG_VLAN_NONE: + /* FALLTHROUGH */ + case DOT1Q_PORT_VLAN_CONFIG_VLAN_FORBIDDEN: + /* + * Save untagged flag for switches + * with global tagging flag + */ + /* XXX: maybe this wrong, chack later */ + uports |= (1 << port); + break; + case DOT1Q_PORT_VLAN_CONFIG_VLAN_UNTAGGED: + uports |= (1 << port); + /* FALLTHROUGH */ + case DOT1Q_PORT_VLAN_CONFIG_VLAN_TAGGED: + ports |= (1 << port); + break; + default: + device_printf(sc->sc_dev, + "Wrong port member type\n"); + return (EINVAL); + break; + } + } + SWITCH_SET_VID(sc->child, vlan->index, + vlan->d.dot1q.vid); + SWITCH_SET_VLANPORTS(sc->child, vlan->index, ports); + SWITCH_SET_VLANUTPORTS(sc->child, vlan->index, uports); + } + } else { + /* Get */ + if (vlan->vlan_type == VLAN_TYPE_DOT1Q) { + error = SWITCH_GET_VID(sc->child, vlan->index, + &vlan->d.dot1q.vid); + if (error) + return (error); + + error = SWITCH_GET_VLANPORTS(sc->child, vlan->index, + &ports); + if (error) + return (error); + error = SWITCH_GET_VLANUTPORTS(sc->child, vlan->index, + &uports); + if (error) + return (error); + + for (port = 0; port < sc->caps->ports; port ++) { + if (ports & (1 << port)) { + vlan->d.dot1q.port_config[port] = + (uports & (1 << port))? + DOT1Q_PORT_VLAN_CONFIG_VLAN_UNTAGGED: + DOT1Q_PORT_VLAN_CONFIG_VLAN_TAGGED; + } else { + vlan->d.dot1q.port_config[port] = + DOT1Q_PORT_VLAN_CONFIG_VLAN_NONE; + } + } + } + } + + return (0); +} + +static int +vlan_port_config_sub(struct switch_softc *sc, struct vlan_port_config *vlan_port) +{ + int error; + + SWITCH_ASSERT_LOCKED(sc); + + if (vlan_port->version != SWITCH_API_VERSION) { + return (EINVAL); + } + + if (vlan_port->cmd == 1) { + /* Set */ + if (vlan_port->vlan_type == VLAN_TYPE_DOT1Q) { + SWITCH_SET_PVID(sc->child, vlan_port->index, + vlan_port->d.dot1q.vid); + SWITCH_SET_PFLAGS(sc->child, vlan_port->index, + vlan_port->d.dot1q.flags); + printf("%s: SWITCH_SET_PFLAGS(sw, %d, %04x)\n", + __func__, vlan_port->index, + vlan_port->d.dot1q.flags); + } + } else { + /* Get */ + if (vlan_port->vlan_type == VLAN_TYPE_DOT1Q) { + error = SWITCH_GET_PVID(sc->child, vlan_port->index, + &vlan_port->d.dot1q.vid); + if (error) + return (error); + error = SWITCH_GET_PFLAGS(sc->child, vlan_port->index, + &vlan_port->d.dot1q.flags); + if (error) + return (error); + } + + } + + return (0); +} + + +static int +switch_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, + struct thread *td) +{ + struct switch_softc *sc = dev->si_drv1; + int ret = 0; + void * kdata = data; + + SWITCH_LOCK(sc); + switch ( cmd ) { + case IOCTL_SWITCH_CONFIG: + ret = switch_config_sub(sc, (struct switch_config *)kdata); + if (ret) { + device_printf(sc->sc_dev, "switch_config_sub return error\n"); + /* XXX: handle error */ + break; + } + break; + case IOCTL_SWITCH_CAP: + ret = switch_caps_sub(sc, (struct switch_caps *)kdata); + if (ret) { + device_printf(sc->sc_dev, "switch_caps_sub return error\n"); + /* XXX: handle error */ + break; + } + break; + case IOCTL_SWITCH_GETREG: + ret = switch_getreg_sub(sc, (struct switch_reg *)kdata); + if (ret) { + device_printf(sc->sc_dev, "switch_getreg_sub return error\n"); + /* XXX: handle error */ + break; + } + break; + case IOCTL_SWITCH_SETREG: + ret = switch_setreg_sub(sc, (struct switch_reg *)kdata); + if (ret) { + device_printf(sc->sc_dev, "switch_setreg_sub return error\n"); + /* XXX: handle error */ + break; + } + break; + case IOCTL_VLAN_CONFIG: + ret = vlan_config_sub(sc, (struct vlan_config *)kdata); + if (ret) { + device_printf(sc->sc_dev, "vlan_config_sub return error\n"); + /* XXX: handle error */ + break; + } + break; + case IOCTL_VLAN_VLAN_CONFIG: + ret = vlan_vlan_config_sub(sc, (struct vlan_vlan_config *)kdata); + if (ret) { + device_printf(sc->sc_dev, "vlan_vlan_config_sub return error\n"); + /* XXX: handle error */ + break; + } + break; + case IOCTL_VLAN_PORT_CONFIG: + ret = vlan_port_config_sub(sc, (struct vlan_port_config *)kdata); + if (ret) { + device_printf(sc->sc_dev, "vlan_port_config_sub return error\n"); + /* XXX: handle error */ + break; + } + break; + /* default case already checked */ + } + SWITCH_UNLOCK(sc); + + return (ret); +} + +int +switch_init(struct switch_softc *sc) +{ + char *var; + + if (sc->child) { + device_printf(sc->sc_dev, "Only one child allowed\n"); + return (ENXIO); + } + + + sc->args = malloc(sizeof(struct child_res_avl), M_DEVBUF, M_NOWAIT); + if (sc->args == NULL) + return (1); + + /* Hint child that we have some memory */ + if (sc->mem_res) + sc->args->memres_size = rman_get_size(sc->mem_res); + /* Hint child that we have some IRQs */ + if (sc->irq_res) + sc->args->irqs = rman_get_size(sc->irq_res); + /* Hint child that we have some PHY IDs */ + sc->args->phys = sc->phys; + + bus_generic_probe(sc->sc_dev); + + if (!resource_string_value(device_get_name(sc->sc_dev), + device_get_unit(sc->sc_dev), + "driver", (const char **)&var)) { + /* If driver hinted, add this driver */ + sc->child = device_add_child(sc->sc_dev, var, -1); + } else { + /* Else try any driver */ + sc->child = device_add_child(sc->sc_dev, NULL, -1); + } + /* XXX: if add child filed we still continue XXX */ + + if (sc->child == NULL) { + free(sc->args, M_DEVBUF); + return (ENXIO); + } + device_set_ivars(sc->child, (void *)sc->args); + + device_probe_and_attach(sc->child); + + sc->caps = SWITCH_GET_CAPS(sc->child); + + /* Create device node */ + sc->sc_cdev = make_dev(&switch_cdevsw, 0, UID_ROOT, GID_WHEEL, 0644, + "switch%d", device_get_unit(sc->sc_dev)); + sc->sc_cdev->si_drv1 = sc; + + return (0); +} + +int +switch_deinit(struct switch_softc *sc) +{ + + /* Destroy device node */ + if (sc->sc_cdev != NULL) + destroy_dev(sc->sc_cdev); + + return (0); +} + +int +switch_tick(struct switch_softc *sc) +{ + +// SWITCH_TICK(sc->child); + + return (0); +} + + Property changes on: sys/dev/switch/switch.c ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/dev/switch/bcm5325_switchreg.h =================================================================== --- sys/dev/switch/bcm5325_switchreg.h (revision 0) +++ sys/dev/switch/bcm5325_switchreg.h (revision 0) @@ -0,0 +1,446 @@ +/*- + * Copyright (c) 2011 Aleksandr Rybalko. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _BCM5325_SWITCHREG_H_ +#define _BCM5325_SWITCHREG_H_ + +#define PSEUDOPHY_ADDR 0x1e +#define BCM5325_PHYMASK (1 << PSEUDOPHY_ADDR) +#define PAGE_REG 0xff + +#define BCM5325_OP_RETRY 100 + +#define BCM5325_ACCESS_CONTROL_REG 0x10 +#define ACCESS_CONTROL_PAGE_MASK 0xff00 +#define ACCESS_CONTROL_PAGE_SHIFT 8 +#define ACCESS_CONTROL_RW 0x0001 + +#define BCM5325_RW_CONTROL_REG 0x11 +#define RW_CONTROL_ADDR_MASK 0xff00 +#define RW_CONTROL_ADDR_SHIFT 8 +#define RW_CONTROL_NOP 0x0000 +#define RW_CONTROL_WRITE 0x0001 +#define RW_CONTROL_READ 0x0002 +#define RW_CONTROL_OP_MASK 0x0003 + +#define BCM5325_RW_STATUS_REG 0x12 +#define RW_STATUS_ERROR 0x0002 +#define RW_STATUS_PROHIBIT 0x0001 + +#define BCM5325_DATA_15_0_REG 0x18 +#define BCM5325_DATA_31_16_REG 0x19 +#define BCM5325_DATA_47_32_REG 0x1a +#define BCM5325_DATA_63_48_REG 0x1b + +#define PORT0 0 +#define PORT1 1 +#define PORT2 2 +#define PORT3 3 +#define PORT4 4 +#define PORT5 5 +#define PORT6 6 +#define PORT7 7 +#define PORTMII 8 +#define PORTGLB 9 +#define PORT_SERIAL_MGMT 10 + +#define PAGE(_page) ((_page) << 8) +#define S1 (1 << 16) +#define S2 (2 << 16) +#define S3 (3 << 16) +#define S4 (4 << 16) +#define S6 (6 << 16) +#define S8 (8 << 16) + +#define PORT_CTL(_port) (S1 | PAGE(0x00) | ((_port) & 0x0f)) +#define PORT_CTL_STP_STATE_MASK 0xe0 +#define PORT_CTL_STP_STATE_NOSTP 0x00 +#define PORT_CTL_STP_STATE_DISABLED 0x20 +#define PORT_CTL_STP_STATE_BLOCKING 0x40 +#define PORT_CTL_STP_STATE_LISTENING 0x60 +#define PORT_CTL_STP_STATE_LEARNING 0x80 +#define PORT_CTL_STP_STATE_FORWARDING 0xa0 +#define PORTMII_CTL_UCAST_ENABLED 0x10 /* MII port only */ +#define PORTMII_CTL_MCAST_ENABLED 0x08 /* MII port only */ +#define PORTMII_CTL_BCAST_ENABLED 0x04 /* MII port only */ +#define PORT_CTL_TX_DISABLED 0x02 +#define PORT_CTL_RX_DISABLED 0x01 + +#define SWITCH_MODE (S1 | PAGE(0x00) | 0x0b) +#define SWITCH_MODE_HDX_NORETRY_LIMIT 0x04 +#define SWITCH_MODE_FORWARDING_ENABLED 0x02 +#define SWITCH_MODE_MANAGED 0x01 + +#define PORTMII_STATUS_OVERRIDE (S1 | PAGE(0x00) | 0x0e) +#define PORTMII_STATUS_REVERSE_MII 0x10 +#define PORTMII_STATUS_PAUSE_CAPABLE 0x08 +#define PORTMII_STATUS_FORCE_100M 0x04 +#define PORTMII_STATUS_FORCE_FDX 0x02 +#define PORTMII_STATUS_FORCE_LINK 0x01 + +#define POWER_DOWN_MODE (S1 | PAGE(0x00) | 0x0f) +#define PORT7_POWER_DOWN 0x80 +#define PORT6_POWER_DOWN 0x40 +#define PORT5_POWER_DOWN 0x20 +#define PORT4_POWER_DOWN 0x10 +#define PORT3_POWER_DOWN 0x08 +#define PORT2_POWER_DOWN 0x04 +#define PORT1_POWER_DOWN 0x02 +#define PORT0_POWER_DOWN 0x01 /* Do not set bit 0 to 1. + * Doing so will disable + * the PLL power and the + * switch function. */ + +#define IP_MULTICAST_REG (S1 | PAGE(0x00) | 0x21) +#define IP_MULTICAST_ENABLE 0x01 + +#define IO_MUX_CTL (S2 | PAGE(0x00) | 0x22) +#define SWITCH_DEVICEID (S2 | PAGE(0x00) | 0x30) +#define SWITCH_RESET (S2 | PAGE(0x00) | 0x79) + +#define LINK_STATUS_SUMMARY (S2 | PAGE(0x01) | 0x00) +#define LINK_STATUS_CHANGE_RC (S2 | PAGE(0x01) | 0x02) +#define PORT_SPEED_100M (S2 | PAGE(0x01) | 0x04) +#define PORT_DUPLEX_FDX(_x) (S2 | PAGE(0x01) | 0x06) +#define PAUSE_SUMMARY(_x) (S2 | PAGE(0x01) | 0x08) +#define SOURCE_ADDRESS_CHANGE(_x) (S2 | PAGE(0x01) | 0x0c) + +#define LAST_PORT_SOURCE_ADDRESS(_p, _x) \ + (S6 | PAGE(0x01) | (0x10 + (((_p) & 0x07) * 6))) + +#define BIST_STATUS_RC (S1 | PAGE(0x01) | 0x46) +#define BIST_STATUS_VLAN_RAM_ERR 0x10 +#define BIST_STATUS_VID_RAM_ERR 0x08 +#define BIST_STATUS_MIB_RAM_ERR 0x04 +#define BIST_STATUS_MEM_ERR 0x02 +#define BIST_STATUS_BUF_CTL_RAM_ERR 0x01 + +#define GLOBAL_MGMT_CTL (S1 | PAGE(0x02) | 0x00) +#define GLOBAL_MGMT_CTL_MGMT_PORT_MII 0x80 +#define GLOBAL_MGMT_CTL_MGMT_PORT_PHY 0x00 +#define GLOBAL_MGMT_CTL_MIB_AC_EN 0x20 +#define GLOBAL_MGMT_CTL_MIB_AC_HDR 0x10 +#define GLOBAL_MGMT_CTL_IGMP_IP 0x08 +#define GLOBAL_MGMT_CTL_IGMP_MAC 0x04 +#define GLOBAL_MGMT_CTL_RX_BPDU 0x02 +#define GLOBAL_MGMT_CTL_RST_MIB 0x01 + +#define MGMT_PORT (S1 | PAGE(0x02) | 0x02) +#define RMON_MIB_STEERING (S2 | PAGE(0x02) | 0x04) +#define AGE_TIME (S4 | PAGE(0x02) | 0x06) +#define PORT_MIRROR (S2 | PAGE(0x02) | 0x10) +#define PORT_MIRROR_ENABLE 0x8000 +#define PORT_MIRROR_PORT(_p) (1 << (_p)) + +#define PORT_IN_MIRROR_CTL (S2 | PAGE(0x02) | 0x12) +#define PORT_IN_MIRROR_ALL 0x0000 +#define PORT_IN_MIRROR_DA_MATCH 0x4000 +#define PORT_IN_MIRROR_SA_MATCH 0x8000 +#define PORT_IN_MIRROR_DIV_EN 0x2000 +#define PORT_IN_MIRROR_PORT(_p) (1 << (_p)) + +#define PORT_IN_MIRROR_DIV (S2 | PAGE(0x02) | 0x14) +#define PORT_IN_MIRROR_MAC (S6 | PAGE(0x02) | 0x16) +#define PORT_OUT_MIRROR_CTL (S2 | PAGE(0x02) | 0x1c) +#define PORT_OUT_MIRROR_ALL 0x0000 +#define PORT_OUT_MIRROR_DA_MATCH 0x4000 +#define PORT_OUT_MIRROR_SA_MATCH 0x8000 +#define PORT_OUT_MIRROR_DIV_EN 0x2000 +#define PORT_OUT_MIRROR_PORT(_p) (1 << (_p)) + +#define PORT_OUT_MIRROR_DIV (S2 | PAGE(0x02) | 0x1e) +#define PORT_OUT_MIRROR_MAC (S6 | PAGE(0x02) | 0x20) + +#define IGMP_CPU_FWD_CTL (S1 | PAGE(0x02) | 0x26) +#define IGMP_REPLACE_DA (S6 | PAGE(0x02) | 0x27) + +#define MIB_AUTOCAST_PORT (S2 | PAGE(0x03) | 0x00) +#define MIB_AUTOCAST_HDR_PNTR (S2 | PAGE(0x03) | 0x02) +#define MIB_AC_HDR_VALID 0x8000 +#define MIB_AC_HDR_PTR_MASK 0x03ff +#define MIB_AUTOCAST_HDR_LEN (S2 | PAGE(0x03) | 0x04) +#define MIB_AC_HDR_LEN_MASK 0x00ff +#define MIB_AUTOCAST_DA (S6 | PAGE(0x03) | 0x06) +#define MIB_AUTOCAST_SA (S6 | PAGE(0x03) | 0x0C) +#define MIB_AUTOCAST_TYPE (S2 | PAGE(0x03) | 0x12) +#define MIB_AUTOCAST_RATE (S2 | PAGE(0x03) | 0x14) + +#define GLOBAL_ARL_CONFIG (S1 | PAGE(0x04) | 0x00) +#define GLOBAL_ARL_MPORT_ADDR_EN 0x10 +#define GLOBAL_ARL_HASH_DISABLE 0x01 + +#define BPDU_MULTICAST_ADDRESS (S6 | PAGE(0x04) | 0x04) +#define MULTIPORT_ADDRESS_1 (S6 | PAGE(0x04) | 0x10) +#define MULTIPORT_VECTOR_1 (S2 | PAGE(0x04) | 0x16) +#define MULTIPORT_VECTOR_1_PORT(_p) (1 << (_p)) +#define MULTIPORT_ADDRESS_2 (S6 | PAGE(0x04) | 0x20) +#define MULTIPORT_VECTOR_2 (S2 | PAGE(0x04) | 0x26) +#define MULTIPORT_VECTOR_2_PORT(_p) (1 << (_p)) +#define SECURE_SRC_PORT_MASK (S2 | PAGE(0x04) | 0x30) +#define SECURE_SRC_PORT(_p) (1 << (_p)) +#define SECURE_DST_PORT_MASK (S2 | PAGE(0x04) | 0x32) +#define SECURE_DST_PORT(_p) (1 << (_p)) + +#if 0 /* Switch internal usage */ +struct arl_ucast_entry { + uint8_t mac[6]; + uint16_t mixed; +#define MIXED_RXPORT_MASK 0x000f +#define MIXED_DID_MASK 0x0030 +#define MIXED_DID_SHIFT 4 +#define MIXED_BID_MASK 0x0040 +#define MIXED_BID_SHIFT 6 +#define MIXED_VID_LOW_MASK 0x0780 +#define MIXED_VID_LOW_SHIFT 7 +#define MIXED_PRIO_MASK 0x1800 +#define MIXED_PRIO_SHIFT 11 +#define MIXED_AGE_MASK 0x2000 +#define MIXED_AGE_SHIFT 13 +#define MIXED_STATIC_MASK 0x4000 +#define MIXED_STATIC_SHIFT 14 +#define MIXED_VALID_MASK 0x8000 +#define MIXED_VALID_SHIFT 15 + uint8_t vid_high; +}; + +struct arl_mcast_entry { + uint8_t mac[6]; + uint16_t mixed; +/* XXX: how this can be applied to sw w/ 8 PHY ports */ +#define MIXED_MCAST_PORT_MASK 0x007f +#define MIXED_RSVD_MASK 0x2000 +#define MIXED_RSVD_SHIFT 13 + uint8_t vid_high; +}; +#endif + +#define ARL_RW_CTL (S1 | PAGE(0x05) | 0x00) +#define ARL_RW_CTL_START 0x80 +#define ARL_RW_CTL_DONE 0x80 +#define ARL_RW_CTL_READ 0x01 +#define MAC_ADDRESS_INDEX (S6 | PAGE(0x05) | 0x02) +#define VID_TABLE_INDEX (S1 | PAGE(0x05) | 0x08) +#define ARL_ENTRY_0 (S8 | PAGE(0x05) | 0x10) +#define ARL_ENTRY_H32_VALID 0x80000000 +#define ARL_ENTRY_H32_STATIC 0x40000000 +#define ARL_ENTRY_H32_AGE 0x20000000 +/* For Unicast port number */ +#define ARL_ENTRY_H32_UCAST_PORTID_NUM_MASK 0x000f0000 +#define ARL_ENTRY_H32_UCAST_PORTID_NUM_SHIFT 16 +/* For Multicast ports map */ +#define ARL_ENTRY_H32_MCAST_PORTID_MAP_MASK 0x03ff0000 +#define ARL_ENTRY_H32_MCAST_PORTID_MAP_SHIFT 16 +#define ARL_ENTRY_H32_MAC_HIGH_MASK 0x0000ffff +#define ARL_ENTRY_L32_MAC_LOW_MASK 0xffffffff +#define ARL_ENTRY_1 (S8 | PAGE(0x05) | 0x18) +#define ARL_SEARCH_CTL (S1 | PAGE(0x05) | 0x20) +#define ARL_SEARCH_CTL_START 0x80 +#define ARL_SEARCH_CTL_DONE 0x80 +#define ARL_SEARCH_CTL_VALID 0x01 +#define ARL_SEARCH_ADDRESS (S2 | PAGE(0x05) | 0x22) +#define ARL_SEARCH_ADDRESS_VALID 0x8000 +#define ARL_SEARCH_ADDRESS_MASK 0x7fff +#define ARL_SEARCH_RESULT (S8 | PAGE(0x05) | 0x24) /* ARL Entry format */ +#define VID_ENTRY_0 (S1 | PAGE(0x05) | 0x30) +#define VID_ENTRY_1 (S1 | PAGE(0x05) | 0x32) + +#define MEMORY_RW_CTL (S4 | PAGE(0x08) | 0x00) +#define MEMORY_RW_CTL_START 0x00080000 +#define MEMORY_RW_CTL_DONE 0x00080000 +#define MEMORY_RW_CTL_READ 0x00040000 +#define MEMORY_RW_CTL_ADDR_MASK 0x00003fff +#define MEMORY_RW_DATA (S8 | PAGE(0x08) | 0x04) + + +#define PRIORITY_CTL (S2 | PAGE(0x0A) | 0x00) +#define FLOW_CTL (S2 | PAGE(0x0A) | 0x30) +#define LOW_QUEUE_THRESHOLD_CTL (S2 | PAGE(0x0A) | 0x4A) +#define QUEUE2_CTL_1 (S2 | PAGE(0x0A) | 0x66) +#define QUEUE2_CTL_2 (S2 | PAGE(0x0A) | 0x68) +#define QUEUE2_CTL_3 (S2 | PAGE(0x0A) | 0x6A) +#define QUEUE2_CTL_4 (S2 | PAGE(0x0A) | 0x6C) +#define QUEUE3_CTL_1 (S2 | PAGE(0x0A) | 0x74) +#define QUEUE3_CTL_2 (S2 | PAGE(0x0A) | 0x76) +#define QUEUE3_CTL_3 (S2 | PAGE(0x0A) | 0x78) +#define QUEUE3_CTL_4 (S2 | PAGE(0x0A) | 0x7A) +#define QUEUE4_CTL_1 (S2 | PAGE(0x0A) | 0x82) +#define QUEUE4_CTL_2 (S2 | PAGE(0x0A) | 0x84) +#define QUEUE4_CTL_3 (S2 | PAGE(0x0A) | 0x86) +#define QUEUE4_CTL_4 (S2 | PAGE(0x0A) | 0x88) + + +/* Standard MII +PRT = PAGE10 + port +Page PRT, Address 00h-01h Switch Port Control Register +Page PRT, Address 02h-03h Switch Port Status Register +Page PRT, Address 04h-05h PHY Identifier Registers +Page PRT, Address 06h-07h PHY Identifier Registers +Page PRT, Address 08h-09h Auto-Negotiation Advertisement Register +Page PRT, Address 0Ah-0Bh Auto-Negotiation Link Partner Ability Register +Page PRT, Address 0Ch-0Dh Auto-Negotiation Expansion Register +Page PRT, Address 0Eh-0Fh Next Page Transmit Register +Page PRT, Address 10h-11h Link Partner Next Page Register +Page PRT, Address 20h-21h 100BASE-X Auxiliary Control Register +Page PRT, Address 22h-23h 100BASE-X Auxiliary Status Register +Page PRT, Address 24h-25h 100BASE-X Receive Error Counter +Page PRT, Address 26h-27h 100BASE-X False Carrier Sense Counter +Page PRT, Address 30h-31h Auxiliary Control/Status Register +Page PRT, Address 32h-33h Auxiliary Status Summary Register +Page PRT, Address 36h-37h Auxiliary Mode 2 +Page PRT, Address 38h-39h 10BASE-T Auxiliary Error & General Status Register +Page PRT, Address 3Ch-3Dh Auxiliary Multiple PHY Register +Page PRT, Address 3Eh-3Fh Broadcom Test +Page PRT, Address 1Eh-1Fh DPM Register +Page PRT, Address 34h-35h DPM Interrupt Register +*/ + +#define MIB_TX_OCTETS(_p) (S8 | PAGE(0x20 + (_p)) | 0x00) +#define MIB_TX_DROPS(_p) (S4 | PAGE(0x20 + (_p)) | 0x08) +#define MIB_TX_DropPkts(_p) (S4 | PAGE(0x20 + (_p)) | 0x08) +#define MIB_TX_BroadcastPkts(_p) (S4 | PAGE(0x20 + (_p)) | 0x10) +#define MIB_TX_MulticastPkts(_p) (S4 | PAGE(0x20 + (_p)) | 0x14) +#define MIB_TX_UnicastPkts(_p) (S4 | PAGE(0x20 + (_p)) | 0x18) +#define MIB_TX_Collisions(_p) (S4 | PAGE(0x20 + (_p)) | 0x1C) +#define MIB_TX_SingleCollision(_p) (S4 | PAGE(0x20 + (_p)) | 0x20) +#define MIB_TX_Multiple Collision(_p) (S4 | PAGE(0x20 + (_p)) | 0x24) +#define MIB_TX_DeferredTransmit(_p) (S4 | PAGE(0x20 + (_p)) | 0x28) +#define MIB_TX_LateCollision(_p) (S4 | PAGE(0x20 + (_p)) | 0x2C) +#define MIB_TX_ExcessiveCollision(_p) (S4 | PAGE(0x20 + (_p)) | 0x30) +#define MIB_TX_FrameInDisc(_p) (S4 | PAGE(0x20 + (_p)) | 0x34) +#define MIB_TX_PausePkts(_p) (S4 | PAGE(0x20 + (_p)) | 0x38) + +#define MIB_RX_OCTETS(_p) (S8 | PAGE(0x20 + (_p)) | 0x44) +#define MIB_RX_Undersize(_p) (S4 | PAGE(0x20 + (_p)) | 0x4c) +#define MIB_RX_PausePkts(_p) (S4 | PAGE(0x20 + (_p)) | 0x50) +#define MIB_RX_Pkts64Octets(_p) (S4 | PAGE(0x20 + (_p)) | 0x54) +#define MIB_RX_Pkts65to127Octets(_p) (S4 | PAGE(0x20 + (_p)) | 0x58) +#define MIB_RX_Pkts128to255Octets(_p) (S4 | PAGE(0x20 + (_p)) | 0x5C) +#define MIB_RX_Pkts256to511Octets(_p) (S4 | PAGE(0x20 + (_p)) | 0x60) +#define MIB_RX_Pkts512to1023Octets(_p) (S4 | PAGE(0x20 + (_p)) | 0x64) +#define MIB_RX_Pkts1024to1522Octets(_p) (S4 | PAGE(0x20 + (_p)) | 0x68) +#define MIB_RX_OversizePkts(_p) (S4 | PAGE(0x20 + (_p)) | 0x6C) +#define MIB_RX_Jabbers(_p) (S4 | PAGE(0x20 + (_p)) | 0x70) +#define MIB_RX_AlignmentErrors(_p) (S4 | PAGE(0x20 + (_p)) | 0x74) +#define MIB_RX_FCSErrors(_p) (S4 | PAGE(0x20 + (_p)) | 0x78) +#define MIB_RX_GOODOCTETS(_p) (S8 | PAGE(0x20 + (_p)) | 0x7c) +#define MIB_RX_DropPkts(_p) (S4 | PAGE(0x20 + (_p)) | 0x84) +#define MIB_RX_UnicastPkts(_p) (S4 | PAGE(0x20 + (_p)) | 0x88) +#define MIB_RX_MulticastPkts(_p) (S4 | PAGE(0x20 + (_p)) | 0x8C) +#define MIB_RX_BroadcastPkts(_p) (S4 | PAGE(0x20 + (_p)) | 0x90) +#define MIB_RX_SAChanges(_p) (S4 | PAGE(0x20 + (_p)) | 0x94) +#define MIB_RX_Fragments(_p) (S4 | PAGE(0x20 + (_p)) | 0x98) +#define MIB_RX_ExcessSizeDisc(_p) (S4 | PAGE(0x20 + (_p)) | 0x9C) +#define MIB_RX_SymbolError(_p) (S4 | PAGE(0x20 + (_p)) | 0xA0) + +#define QOS_CTL (S2 | PAGE(0x30) | 0x00) +#define QOS_CTL_CPU_EN 0x8000 +#define QOS_CTL_AUTO_SET_QOS_REGS 0x1000 +#define QOS_CTL_NQUEUE_MASK 0x0c00 +#define QOS_CTL_4QUEUE 0x0c00 +#define QOS_CTL_3QUEUE 0x0800 +#define QOS_CTL_2QUEUE 0x0400 +#define QOS_CTL_1QUEUE 0x0000 +#define QOS_CTL_HIPRIO_PORTS_MASK 0x03ff +#define QOS_PRIORITY_QUEUE_CTL (S1 | PAGE(0x30) | 0x02) +#define QOS_802_1P_ENABLE (S2 | PAGE(0x30) | 0x04) +#define QOS_TOS_DIFFSERV_ENABLE (S2 | PAGE(0x30) | 0x06) +#define QOS_PAUSE_ENABLE (S2 | PAGE(0x30) | 0x13) +#define DOT1P_PRIO_THRESHOLD (S2 | PAGE(0x30) | 0x15) +#define DOT1P_PRIO_TAG_QUEUE(_t, _q) ((_q) << ((_t) * 2)) +#define TOS_DIFFSERV_CTL (S1 | PAGE(0x30) | 0x19) +#define TOS_DIFFSERV_CTL_TOS 0x01 +#define TOS_DIFFSERV_CTL_DIFFSERV 0x00 +#define D_TYPE_TOS_PRIORITY (S2 | PAGE(0x30) | 0x1A) +#define D_TYPE_TOS_PREC_QUEUE(_t, _q) ((_q) << ((_t) * 2)) +#define T_TYPE_TOS_PRIORITY (S2 | PAGE(0x30) | 0x1C) +#define T_TYPE_TOS_PREC_QUEUE(_t, _q) ((_q) << ((_t) * 2)) +#define R_TYPE_TOS_PRIORITY (S2 | PAGE(0x30) | 0x1E) +#define R_TYPE_TOS_PREC_QUEUE(_t, _q) ((_q) << ((_t) * 2)) +#define M_TYPE_TOS_PRIORITY (S2 | PAGE(0x30) | 0x20) +#define M_TYPE_TOS_PREC_QUEUE(_t, _q) ((_q) << ((_t) * 2)) +#define DIFFSERV_DSCP_PRIORITYL (S8 | PAGE(0x30) | 0x30) +#define DSCP_TO_QUEUE(_d, _q) ((_q) << (((_d) & 0x3f) * 2)) +#define DIFFSERV_DSCP_PRIORITYH (S8 | PAGE(0x30) | 0x38) +#define DSCP_TO_QUEUE(_d, _q) ((_q) << (((_d) & 0x3f) * 2)) + + +#define VLAN_GLOBAL_CTL0 (S1 | PAGE(0x34) | 0x00) +#define VLAN_GLOBAL_CTL0_1Q_ENABLE 0x80 +#define VLAN_GLOBAL_CTL0_MATCH_VIDMAC 0x40 +#define VLAN_GLOBAL_CTL0_MATCH_ONLYMAC 0x00 +#define VLAN_GLOBAL_CTL0_HASH_VIDADDR 0x20 +#define VLAN_GLOBAL_CTL0_HASH_ONLYADDR 0x00 +#define VLAN_GLOBAL_CTL0_INGRESS_CHECK 0x10 +#define VLAN_GLOBAL_CTL0_NO_CHANGE 0x00 +#define VLAN_GLOBAL_CTL0_CHANGE_P 0x04 +#define VLAN_GLOBAL_CTL0_CHANGE_V 0x08 +#define VLAN_GLOBAL_CTL0_CHANGE_PV 0x0c +#define VLAN_GLOBAL_CTL0_NULV_NO_CHANGE 0x00 +#define VLAN_GLOBAL_CTL0_NULV_CHANGE_P 0x01 +#define VLAN_GLOBAL_CTL0_NULV_CHANGE_V 0x02 +#define VLAN_GLOBAL_CTL0_NULV_CHANGE_PV 0x03 +#define VLAN_GLOBAL_CTL1 (S1 | PAGE(0x34) | 0x01) +#define VLAN_GLOBAL_CTL2 (S1 | PAGE(0x34) | 0x02) +#define VLAN_DROP_UNTAGGED (S1 | PAGE(0x34) | 0x03) +#define VLAN_DROP_UNTAGGED_ONPORT(_p) (1 << (_p)) +#define VLAN_GLOBAL_CTL4 (S1 | PAGE(0x34) | 0x04) +#define VLAN_GLOBAL_CTL5 (S1 | PAGE(0x34) | 0x05) +#define VLAN_TABLE_ACCESS (S2 | PAGE(0x34) | 0x08) +#define VLAN_TABLE_ACCESS_RW_ENABLE 0x2000 +#define VLAN_TABLE_ACCESS_WRITE 0x1000 +#define VLAN_TABLE_ACCESS_VID_MASK 0x0fff +#define VLAN_WRITE (S2 | PAGE(0x34) | 0x0A) +#define VLAN_RW_VALID 0x4000 +/* XXX: how this can be applied to sw w/ 8 PHY ports */ +#define VLAN_RW_MEMBER(_p) (1 << (_p)) +#define VLAN_RW_MEMBER_MASK 0x007f +#define VLAN_RW_MEMBER_SHIFT 0 +#define VLAN_RW_UNTAGGED(_p) (1 << ((_p) + 7)) +#define VLAN_RW_UNTAGGED_MASK 0x03f8 +#define VLAN_RW_UNTAGGED_SHIFT 7 +#define VLAN_READ (S2 | PAGE(0x34) | 0x0C) +#define VLAN_DEFAULT_PORT_TAG(_p) (S2 | PAGE(0x34) | (0x10 + ((_p) * 2))) +#define VLAN_PRIORITY_REMAP (S3 | PAGE(0x34) | 0x20) +#define VLAN_PRIORITY_REMAP_OLD_NEW(_o, _n) ((_n) << ((_o) * 3)) + + +#define PORT_SUPPRESSION_CTL (S1 | PAGE(0x35) | (0x00 + (_p))) +#define PORT_SUPPRESSION_CTL_HAS_DROPS 0x80 +#define PORT_SUPPRESSION_CTL_PASS_MCAST 0x40 +#define PORT_SUPPRESSION_CTL_PASS_BCAST 0x20 +#define PORT_SUPPRESSION_CTL_PASS_DLF 0x10 +#define PORT_SUPPRESSION_CTL_MCAST_BURST_2k 0x00 +#define PORT_SUPPRESSION_CTL_MCAST_BURST_4k 0x04 +#define PORT_SUPPRESSION_CTL_MCAST_BURST_6k 0x08 +#define PORT_SUPPRESSION_CTL_MCAST_BURST_8k 0x0c +#define PORT_SUPPRESSION_CTL_MCAST_RATE_10ps 0x00 +#define PORT_SUPPRESSION_CTL_MCAST_RATE_20ps 0x01 +#define PORT_SUPPRESSION_CTL_MCAST_RATE_30ps 0x02 +#define PORT_SUPPRESSION_CTL_MCAST_RATE_40ps 0x03 + +#endif /* _BCM5325_SWITCHREG_H_ */ Property changes on: sys/dev/switch/bcm5325_switchreg.h ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/dev/switch/rt305x_switchvar.h =================================================================== --- sys/dev/switch/rt305x_switchvar.h (revision 0) +++ sys/dev/switch/rt305x_switchvar.h (revision 0) @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2010 Aleksandr Rybalko. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _RT305X_SWITCHVAR_H_ +#define _RT305X_SWITCHVAR_H_ + +struct rt305x_switch_softc { + device_t sc_dev; + device_t parent; + int ports; + int vlans; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + struct switch_capability *caps; +}; + +#define READ4(_sc, _reg) \ + SWITCHB_READ4(_sc->parent, _reg) + +#define WRITE4(_sc, _reg, _val) \ + SWITCHB_WRITE4(_sc->parent, _reg, _val) + +#endif /* _RT305X_SWITCHVAR_H_ */ + Property changes on: sys/dev/switch/rt305x_switchvar.h ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/dev/switch/rtl830x_switch.c =================================================================== --- sys/dev/switch/rtl830x_switch.c (revision 0) +++ sys/dev/switch/rtl830x_switch.c (revision 0) @@ -0,0 +1,842 @@ +/*- + * Copyright (c) 2011 Aleksandr Rybalko. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include "switch_if.h" +#include "switchb_if.h" + +/* TODO */ +static int find_mac_addr(device_t dev, uint64_t mac); +/* TODO */ +static int mac_table_write(device_t dev, uint64_t mac, int idx, + uint32_t port_map, uint8_t age, int *hash_idx ); + +static int set_port_vid_idx(struct rtl830x_switch_softc *sc, int port, + int idx); +static int get_reg(device_t dev, uint32_t reg, uint32_t *value); +static int set_reg(device_t dev, uint32_t reg, uint32_t *value); +static int set_port_vid(device_t dev, int port, uint16_t pvid); +static int get_port_vid(device_t dev, int port, uint16_t *pvid); +static int set_vid(device_t dev, int idx, uint16_t vid); +static int get_vid(device_t dev, int idx, uint16_t *vid); +static int set_vlan_ports(device_t dev, int idx, uint32_t memb); +static int get_vlan_ports(device_t dev, int idx, uint32_t *memb); + +static int get_port_link(device_t dev, int port); +static int get_port_speed(device_t dev, int port); +static int force_port_mode(device_t dev, int port, uint32_t mode); + +static uint32_t stat_good_in_packet_count(device_t dev, int port); +static uint32_t stat_good_out_packet_count(device_t dev, int port); +static uint32_t stat_bad_in_packet_count(device_t dev, int port); +static uint32_t stat_bad_out_packet_count(device_t dev, int port); + + +static int +rtl830x_switch_probe(device_t dev) +{ + struct child_res_avl *res; + + res = device_get_ivars(dev); + +#define RTL830X_PHYMASK 0x000001ff + + /* rtl830x internal switch require PHYs set */ + if ((res->phys & RTL830X_PHYMASK) != RTL830X_PHYMASK) + return (ENXIO); + + + device_set_desc(dev, "RT305XF internal ethernet switch"); + return (BUS_PROBE_DEFAULT); +} + +static int +rtl830x_switch_attach(device_t dev) +{ + struct rtl830x_switch_softc *sc; + uint32_t reg; + int i; + + sc = device_get_softc(dev); + sc->parent = device_get_parent(dev); + + sc->caps = malloc(sizeof(struct switch_capability), M_DEVBUF, + M_WAITOK | M_ZERO); + + if (!sc->caps) + return (ENXIO); + + sc->caps->ports = sc->ports = 9; + sc->vlans = 9; + sc->sc_dev = dev; + +#define S_C(x) SWITCH_CAPS_ ## x + sc->caps->main = S_C(MAIN_PORT_POWER); + sc->caps->vlan = S_C(VLAN_GLBL_UNTG) | S_C(VLAN_DOT1Q) | + S_C(VLAN_DOUBLE_TAG) | + ((sc->vlans << S_C(VLAN_MAX_SHIFT_SHIFT)) & S_C(VLAN_MAX_SHIFT_MASK)); + sc->caps->qos = (2 << S_C(QOS_QUEUES_SHIFT)) & S_C(QOS_QUEUES_MASK); + sc->caps->lacp = 0; /* No LACP caps */ + sc->caps->stp = 0; /* No STP caps */ + sc->caps->acl = 0x21020304; + sc->caps->stat = 0x31020304; +#undef S_C + reg = READ4(sc, PHY0_CTL); + device_printf(dev, "PHY0_CTL=%08x\n", reg); +#define DUMP(_reg) device_printf(dev, #_reg "=%08x\n", READ4(sc, _reg)) + DUMP(GCNTRL0); + DUMP(GCNTRL1); + DUMP(GCNTRL2); + DUMP(GCNTRL3); + + DUMP(PORT_PVID(0)); + DUMP(PORT_PVID(1)); + DUMP(PORT_PVID(2)); + DUMP(PORT_PVID(3)); + DUMP(PORT_PVID(4)); + DUMP(PORT_PVID(5)); + DUMP(PORT_PVID(6)); + DUMP(PORT_PVID(7)); + DUMP(PORT8_PVID ); + + DUMP(VLAN_A_MEMB); + DUMP(VLAN_A_ID); +#undef DUMP + + /* Reset PHYs */ + for (i = 1; i < 8; i++) + WRITE4(sc, PHY_CTL(i), PHY_CTL_RESET); + + /* Set to Auto-Negotiation and reset Auto-Negotiation process */ + for (i = 1; i < 8; i++) + WRITE4(sc, PHY_CTL(i), PHY_CTL_ANEG|PHY_CTL_ANEG_RESTART); + + /* Insert tag on ingress packet */ + for (i = 1; i < 8; i++) + WRITE4(sc, PHY_CTRL0(i), (READ4(sc, PHY_CTRL0(i)) & 0xfffc) | CTRL0_TAG_I_UTG); + + WRITE4(sc, GCNTRL0, + (6 << GCNTRL0_LED_MODE_SHIFT) | /* LED Mode 6: Activity, Speed, Link */ + GCNTRL0_INGRESS_CHECK_DIS | + GCNTRL0_TAG_ONLY_DIS | + GCNTRL0_TX_FC | + GCNTRL0_RX_FC | + GCNTRL0_AGN_EN); + + /* set_vid(swdev, Idx, VID) */ + set_vid(dev, 0, 1); + set_vid(dev, 1, 2); + set_vid(dev, 2, 3); + set_vid(dev, 3, 4); + set_vid(dev, 4, 5); + set_vid(dev, 5, 6); + set_vid(dev, 6, 7); + set_vid(dev, 7, 8); + set_vid(dev, 8, 9); + + /* All ports are members of VLAN0 (VID1) */ + set_vlan_ports(dev, 0, 0x01ff); + /* Other VLANs have no members */ + for (i = 1; i < 9; i++) + set_vlan_ports(dev, i, 0x00); + /* VLAN1 to all ports */ + for (i = 0; i < 9; i++) + set_port_vid_idx(sc, i, 0); + + /* Remove isolate flag */ + for (i = 1; i < 8; i++) + WRITE4(sc, PHY_CTL(i), READ4(sc, PHY_CTL(i)) & ~PHY_CTL_ISOLATE); + + return (0); +} + +static int +rtl830x_switch_detach(device_t dev) +{ + struct rtl830x_switch_softc *sc; + + sc = device_get_softc(dev); + + if (sc->caps) + free(sc->caps, M_DEVBUF); + + return (0); +} + +/* + * Switch capability + */ +static struct switch_capability * +get_caps(device_t dev) +{ + struct rtl830x_switch_softc *sc; + + sc = device_get_softc(dev); + + return (sc->caps); +} + +static int +get_reg(device_t dev, uint32_t reg, uint32_t *value) +{ + struct rtl830x_switch_softc *sc; + + sc = device_get_softc(dev); + + *value = READ4(sc, reg); + return (0); +} + +static int +set_reg(device_t dev, uint32_t reg, uint32_t *value) +{ + struct rtl830x_switch_softc *sc; + uint32_t old; + + sc = device_get_softc(dev); + old = READ4(sc, reg); + WRITE4(sc, reg, *value); + + *value = old; + return (0); +} + +static int +find_mac_addr(device_t dev, uint64_t mac) +{ + struct rtl830x_switch_softc *sc; + int idx = -1; +// uint32_t reg; + + sc = device_get_softc(dev); + + return (idx); +} + +static int +mac_table_write(device_t dev, uint64_t mac, int idx, uint32_t port_map, + uint8_t age, int *hash_idx ) +{ +// struct rtl830x_switch_softc *sc = device_get_softc(dev); +// uint32_t reg; + + + return (0); +} + +static int +add_vlan(struct rtl830x_switch_softc *sc, int vid) +{ + uint32_t reg; + int i; + + if (vid & ~VLAN_ID_MASK) + return (-1); + + /* Check VLANs A-H for zero VID */ + for (i = 0; i < 8; i++) { + reg = READ4(sc, VLAN_ID(i)) & VLAN_ID_MASK; + if (reg == 0) { + reg |= (vid << VLAN_ID_SHIFT); + WRITE4(sc, VLAN_ID(i), reg); + return (i); + } + } + + /* Check VLAN I for zero VID */ + reg = READ4(sc, VLAN_I_ID) & VLAN_ID_MASK; + if (reg == 0) { + reg |= (vid << VLAN_ID_SHIFT); + WRITE4(sc, VLAN_I_ID, reg); + return (8); + } + + return (-1); +} + +static int +get_vlan_idx(struct rtl830x_switch_softc *sc, int vid) +{ + uint32_t reg; + int i; + + vid <<= VLAN_ID_SHIFT; + + /* Check VLANs A-H for zero VID */ + for (i = 0; i < 8; i++) { + reg = READ4(sc, VLAN_ID(i)) & VLAN_ID_MASK; + if (reg == vid) { + return (i); + } + } + + /* Check VLAN I for zero VID */ + reg = READ4(sc, VLAN_I_ID) & VLAN_ID_MASK; + if (reg == vid) { + return (8); + } + + return (-1); +} + +static int +get_vlan_by_index(struct rtl830x_switch_softc *sc, int idx) +{ + uint32_t reg; + + if (idx > (sc->vlans - 1)) + return (-1); + + reg = READ4(sc, ((idx < 8)?VLAN_ID(idx):VLAN_I_ID)); + reg &= VLAN_ID_MASK; + + return (reg); +} + +static int +set_port_vid_idx(struct rtl830x_switch_softc *sc, int port, int idx) +{ + uint32_t reg; + + if (port > (sc->ports - 1)) + return (EINVAL); + + /* Fetch PVID index reg */ + reg = READ4(sc, ((port < 8)?PORT_PVID(port):PORT8_PVID)); + /* Clear old PVID index */ + reg &= ~((port < 8)?PORT0_PVID_IDX_MASK:PORT8_PVID_IDX_MASK); + + /* Preapre new PVID index */ + idx <<= ((port < 8)?PORT0_PVID_IDX_SHIFT:PORT8_PVID_IDX_SHIFT); + idx &= ((port < 8)?PORT0_PVID_IDX_MASK:PORT8_PVID_IDX_MASK); + + /* Add new PVID index */ + reg |= idx; + + /* Save new value */ + WRITE4(sc, ((port < 8)?PORT_PVID(port):PORT8_PVID), reg); + + return (0); +} + +static int +set_port_vid(device_t dev, int port, uint16_t pvid) +{ + struct rtl830x_switch_softc *sc; + int idx; + + sc = device_get_softc(dev); + if (port > (sc->ports - 1)) + return (EINVAL); + + /* Get index for VID from "VID Table" */ + idx = get_vlan_idx(sc, pvid); + + /* Add VID to "VID Table" */ + if (idx < 0) + idx = add_vlan(sc, pvid); + + /* Can't allocate "VID Table" entry */ + if (idx < 0) + return (EINVAL); + + return (set_port_vid_idx(sc, port, idx)); +} + +static int +get_port_vid(device_t dev, int port, uint16_t *pvid) +{ + struct rtl830x_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (port > (sc->ports - 1)) + return (EINVAL); + + reg = READ4(sc, ((port < 8)?PORT_PVID(port):PORT8_PVID)); + reg &= ((port < 8)?PORT0_PVID_IDX_MASK:PORT8_PVID_IDX_MASK); + reg >>= ((port < 8)?PORT0_PVID_IDX_SHIFT:PORT8_PVID_IDX_SHIFT); + + *pvid = get_vlan_by_index(sc, reg); + return (0); +} + +static int +get_port_flags(device_t dev, int port, uint32_t *flags) +{ + struct rtl830x_switch_softc *sc; + uint32_t reg = 0; + + *flags = 0; + sc = device_get_softc(dev); + if (port > (sc->ports - 1)) + return (EINVAL); + + reg = READ4(sc, PHY_CTRL0(port)); + if (reg & CTRL0_I_CH_EN) + *flags |= DOT1Q_VLAN_PORT_FLAG_INGRESS; + + switch (reg & CTRL0_TAG_MODE_MASK){ + + case CTRL0_TAG_NI_NR: + *flags |= DOT1Q_VLAN_PORT_FLAG_TAGGED; + break; + case CTRL0_TAG_I_UTG: + *flags |= DOT1Q_VLAN_PORT_FLAG_UNTAGGED; + break; + case CTRL0_TAG_R_TG: + *flags |= DOT1Q_VLAN_PORT_FLAG_UNTAGGED| + DOT1Q_VLAN_PORT_FLAG_FORCE_UNTAGGED; + break; + case CTRL0_TAG_IR: + *flags |= DOT1Q_VLAN_PORT_FLAG_FORCE_PVID| + DOT1Q_VLAN_PORT_FLAG_UNTAGGED; + break; + } + + return (0); +} + +static int +set_port_flags(device_t dev, int port, uint32_t flags) +{ + struct rtl830x_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (port > (sc->ports - 1)) + return (EINVAL); + + reg = READ4(sc, PHY_CTRL0(port)); + + if (flags & DOT1Q_VLAN_PORT_FLAG_INGRESS) + reg |= CTRL0_I_CH_EN; + else + reg &= ~CTRL0_I_CH_EN; + + reg &= ~CTRL0_TAG_MODE_MASK; + if (flags & DOT1Q_VLAN_PORT_FLAG_TAGGED) + reg |= CTRL0_TAG_NI_NR; + else if (flags & DOT1Q_VLAN_PORT_FLAG_UNTAGGED) { + if (flags & DOT1Q_VLAN_PORT_FLAG_FORCE_UNTAGGED) { + reg |= CTRL0_TAG_R_TG; + } else if (flags & DOT1Q_VLAN_PORT_FLAG_FORCE_PVID) { + reg |= CTRL0_TAG_IR; + } else { + reg |= CTRL0_TAG_I_UTG; + } + } + + return (0); +} + +static int +set_vid(device_t dev, int idx, uint16_t vid) +{ + struct rtl830x_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (idx > (sc->vlans - 1)) + return (EINVAL); + + reg = READ4(sc, ((idx<8)?VLAN_ID(idx):VLAN_I_ID)) & VLAN_ID_MASK; + reg &= ~VLAN_ID_MASK; + reg |= vid; + WRITE4(sc, ((idx<8)?VLAN_ID(idx):VLAN_I_ID), reg); + + return (0); +} + +static int +get_vid(device_t dev, int idx, uint16_t *vid) +{ + struct rtl830x_switch_softc *sc = device_get_softc(dev); + uint32_t reg; + + if (idx > (sc->vlans - 1)) + return (EINVAL); + + reg = READ4(sc, ((idx < 8)?VLAN_ID(idx):VLAN_I_ID)); + reg &= VLAN_ID_MASK; + + *vid = reg; + return (0); +} + +static int +set_vlan_ports(device_t dev, int idx, uint32_t memb) +{ + struct rtl830x_switch_softc *sc = device_get_softc(dev); + uint32_t reg; + + printf("%s: idx=%d, memb=%08x\n", __func__, idx, memb); + + if (idx > (sc->vlans - 1)) + return (EINVAL); + if (memb & (((1 << sc->ports) - 1) << sc->ports)) + return (EINVAL); + + reg = READ4(sc, ((idx < 8)?VLAN_MEMB(idx):VLAN_I_MEMB)); + reg &= ~(VLAN_A_MEMB_MASK << VLAN_A_MEMB_SHIFT); + reg |= ((memb & VLAN_A_MEMB_MASK) << VLAN_A_MEMB_SHIFT); + WRITE4(sc, ((idx < 8)?VLAN_MEMB(idx):VLAN_I_MEMB), reg); + + return (0); +} + +static int +get_vlan_ports(device_t dev, int idx, uint32_t *memb) +{ + struct rtl830x_switch_softc *sc = device_get_softc(dev); + uint32_t reg; + + if (idx > (sc->vlans - 1)) + return (EINVAL); + + reg = READ4(sc, ((idx < 8)?VLAN_MEMB(idx):VLAN_I_MEMB)); + reg &= VLAN_A_MEMB_MASK; + reg >>= VLAN_A_MEMB_SHIFT; + + printf("%s: idx=%d, memb=%08x\n", __func__, idx, reg); + *memb = reg; + return (0); +} + +#if 0 +/* Use global tagging option */ +static int +set_vlan_untagged_ports(device_t dev, int idx, uint32_t memb) +{ + struct rtl830x_switch_softc *sc = device_get_softc(dev); + uint32_t reg; + + printf("%s: idx=%d, memb=%08x\n", __func__, idx, memb); + + if (idx > (sc->vlans - 1)) + return (EINVAL); + if (memb & ~((1 << sc->ports) - 1)) + return (EINVAL); + + /* RT305XF support only global port untaged flags */ + reg = READ4(sc, PHY0_CTL); + reg &= ~((1 << sc->ports) - 1); + reg |= (((1 << sc->ports) - 1) & memb); + WRITE4(sc, PHY0_CTL, reg); + + return (0); +} + +static uint32_t +get_vlan_untagged_ports(device_t dev, int idx, uint32_t *memb) +{ + struct rtl830x_switch_softc *sc = device_get_softc(dev); + uint32_t reg; + + if (idx > (sc->vlans - 1)) + return (EINVAL); + + /* RT305XF support only global port untaged flags */ + reg = READ4(sc, PHY0_CTL); + reg &= ((1 << sc->ports) - 1); + + printf("%s: idx=%d, memb=%08x\n", __func__, idx, reg); + *memb = reg; + return (0); +} +#endif + +static int +get_port_link(device_t dev, int port) +{ + struct rtl830x_switch_softc *sc = device_get_softc(dev); + int link; + + if (port > (sc->ports - 1)) + return (-1); + + link = READ4(sc, PHY0_CTL) >> 25; + link = (link >> port) & 1; + + return (link); +} + +static int +get_port_speed(device_t dev, int port) +{ + struct rtl830x_switch_softc *sc = device_get_softc(dev); + uint32_t link, fdx; + + link = READ4(sc, PHY0_CTL); + + fdx = (link & (1 << (port + 9)))?IFM_FDX:IFM_HDX; + + if (port < 5) + return ((((link >> port) & 1)?IFM_100_TX:IFM_10_T) | fdx); + + /* GDMA0 */ + if (port == 5) + link = (link >> 5) & 0x03; + + /* GDMA1 */ + if (port == 6) + link = (link >> 7) & 0x03; + + if (link == 2) + return (IFM_1000_T | fdx); + + if (link == 1) + return (IFM_100_TX | fdx); + + return (IFM_10_T | fdx); +} + +static int +force_port_mode(device_t dev, int port, uint32_t mode) +{ + struct rtl830x_switch_softc *sc = device_get_softc(dev); + uint32_t reg = READ4(sc, PHY0_CTL); + + if (port > (sc->ports - 2/* MII */ - 1)) + return (EINVAL); + + reg &= ~(((1 << 27) | (1 << 22) | (1 << 16) | (1 << 8) | 1) << port); + + switch (IFM_SUBTYPE(mode)) { + case IFM_10_T: + /* Already zero */ + break; + case IFM_100_TX: + reg |= (1 << port); + break; + default: + /* error unsupported media */ + return (EINVAL); + } + + switch (mode & IFM_GMASK) { + case IFM_FDX: + reg |= (1 << port) << 8; + break; + case IFM_HDX: + /* Already zero */ + break; + case IFM_FLOW: + reg |= (1 << port) << 16; + break; + case IFM_FLAG0: /* XXX: Used as enable force mode */ + reg |= (1 << port) << 27; + break; + case IFM_FLAG1: /* XXX: Used as force link */ + reg |= (1 << port) << 22; + break; + case IFM_FLAG2: + break; + case IFM_LOOP: + break; + } + + WRITE4(sc, PHY0_CTL, reg); + + return (0); +} + +static uint32_t +stat_good_in_packet_count(device_t dev, int port) +{ + struct rtl830x_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (port < 6) { + reg = READ4(sc, PHY0_CTL); + reg &= 0xffff0000; + reg >>= 16; + return (reg); + } + + if (port < 7) { + reg = READ4(sc, PHY0_CTL); + reg >>= 16; + return (reg & 0xffff); + } + + return (~0); +} + +static uint32_t +stat_good_out_packet_count(device_t dev, int port) +{ + struct rtl830x_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (port < 6) { + /* PHY ports have only sum couters */ + reg = READ4(sc, PHY0_CTL); + reg &= 0xffff0000; + reg >>= 16; + return (reg); + } + + if (port < 7) { + reg = READ4(sc, PHY0_CTL); + reg >>= 16; + return (reg & 0xffff); + } + + return (~0); +} + +static void +rtl830x_tick(device_t dev) +{ + struct rtl830x_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + printf("tick\n"); + reg = READ4(sc, PHY0_CTL); + + return; +} + +static uint32_t +stat_bad_in_packet_count(device_t dev, int port) +{ + struct rtl830x_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (port < 6) { + reg = READ4(sc, PHY0_CTL); + reg &= 0xffff0000; + reg >>= 16; + return (reg); + } + + if (port < 7) { + /* Port 6 always good :) */ + return (0); + } + + return (~0); +} + +static uint32_t +stat_bad_out_packet_count(device_t dev, int port) +{ + struct rtl830x_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (port < 6) { + /* PHY ports have only sum couters */ + reg = READ4(sc, PHY0_CTL); + reg &= 0xffff0000; + reg >>= 16; + return (reg); + } + + if (port < 7) { + /* Port 6 always good :) */ + return (0); + } + + return (~0); +} + +static device_method_t rtl830x_switch_methods[] = { + DEVMETHOD(device_probe, rtl830x_switch_probe), + DEVMETHOD(device_attach, rtl830x_switch_attach), + DEVMETHOD(device_detach, rtl830x_switch_detach), + + /* Capability */ + DEVMETHOD(switch_get_caps, get_caps), + DEVMETHOD(switch_set_reg, set_reg), + DEVMETHOD(switch_get_reg, get_reg), + + /* MAC address table */ + DEVMETHOD(switch_find_mac, find_mac_addr), + DEVMETHOD(switch_mac_write, mac_table_write), + + /* 802.1q */ + DEVMETHOD(switch_set_pvid, set_port_vid), + DEVMETHOD(switch_get_pvid, get_port_vid), + DEVMETHOD(switch_set_pflags, set_port_flags), + DEVMETHOD(switch_get_pflags, get_port_flags), + DEVMETHOD(switch_set_vid, set_vid), + DEVMETHOD(switch_get_vid, get_vid), + DEVMETHOD(switch_set_vlanports, set_vlan_ports), + DEVMETHOD(switch_get_vlanports, get_vlan_ports), +// DEVMETHOD(switch_set_vlanutports, set_vlan_untagged_ports), +// DEVMETHOD(switch_get_vlanutports, get_vlan_untagged_ports), + + /* Port state */ + DEVMETHOD(switch_get_portlink, get_port_link), + DEVMETHOD(switch_get_portspeed, get_port_speed), + DEVMETHOD(switch_force_mode, force_port_mode), + DEVMETHOD(switch_tick, rtl830x_tick), + + /* Statistics */ + DEVMETHOD(switch_good_in_cnt, stat_good_in_packet_count), + DEVMETHOD(switch_good_out_cnt, stat_good_out_packet_count), + DEVMETHOD(switch_bad_in_cnt, stat_bad_in_packet_count), + DEVMETHOD(switch_bad_out_cnt, stat_bad_out_packet_count), + + {0, 0}, +}; + +static driver_t rtl830x_switch_driver = { + "rtl830x_switch", + rtl830x_switch_methods, + sizeof(struct rtl830x_switch_softc), +}; +static devclass_t rtl830x_switch_devclass; + +DRIVER_MODULE(rtl830x_switch, switch, rtl830x_switch_driver, rtl830x_switch_devclass, 0, 0); +MODULE_VERSION(rtl830x_switch, 1); +MODULE_DEPEND(rtl830x_switch, switch, 1, 1, 1); + Property changes on: sys/dev/switch/rtl830x_switch.c ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/dev/switch/rtl830x_switchreg.h =================================================================== --- sys/dev/switch/rtl830x_switchreg.h (revision 0) +++ sys/dev/switch/rtl830x_switchreg.h (revision 0) @@ -0,0 +1,811 @@ + +/* + * RO Read Only + * LH Latch High until clear + * RW Read/Write + * SC Self Clearing + * LL Latch Low until clear + */ + +enum phy_names { + PHY0 = 0, + PHY1, + PHY2, + PHY3, + PHY4, + PHY5, + PHY6, + PHY7, + PHY8, + PHY24 = 24 +}; + +#define ID(_phy, _reg) ((_phy)<<16 | (_reg)) + +/* + + PHY 0 Register 0: Control + 0.15 Reset RW/SC 1: PHY reset. This bit is self-clearing. 0 + 0.14 Loopback RW 1: Enable loopback. This will loopback TXD to RXD and 0 + (digital loopback) ignore all activity on the cable media + 0: Normal operation + 0.13 Speed Select RW 1: 100Mbps 1 + 0: 10Mbps + When NWay is enabled, this bit reflects the result of auto- + negotiation (Read only). + When NWay is disabled, this bit is strap option + ‘Force_Speed’ and can be configured through SMI + (Read/Write). + 0.12 Auto Negotiation RW 1: Enable auto-negotiation process Pin + Enable 0: Disable auto-negotiation process En_ANEG + This bit can be set through SMI (Read/Write). strap option + 0.11 Power Down RW 1: Power down. All functions will be disabled except SMI 0 + function + 0: Normal operation + 0.10 Isolate RW 1: Electrically isolates the PHY from RMII/SMII. 0 + PHY is still able to respond to MDC/MDIO + 0: Normal operation + 0.9 Restart Auto RW/SC 1: Restart Auto-Negotiation process 0 + Negotiation 0: Normal operation + 0.8 Duplex Mode RW 1: Full duplex operation 1 + 0: Half duplex operation + When NWay is enabled, this bit reflects the result of auto- + negotiation (Read only). + When NWay is disabled, this bit is strap option + ‘Force_Duplex’ and can be configured through SMI + (Read/Write). + */ + + +#define PHY_CTL(p) ID(p, 0) +#define PHY0_CTL ID(PHY0, 0) +#define PHY1_CTL ID(PHY1, 0) +#define PHY2_CTL ID(PHY2, 0) +#define PHY3_CTL ID(PHY3, 0) +#define PHY4_CTL ID(PHY4, 0) +#define PHY5_CTL ID(PHY5, 0) +#define PHY6_CTL ID(PHY6, 0) +#define PHY7_CTL ID(PHY7, 0) +#define PHY_CTL_RESET (1<<15) +#define PHY_CTL_LOOPBACK (1<<14) +#define PHY_CTL_100M (1<<13) +#define PHY_CTL_ANEG (1<<12) +#define PHY_CTL_POWERDOWN (1<<11) +#define PHY_CTL_ISOLATE (1<<10) +#define PHY_CTL_ANEG_RESTART (1<< 9) +#define PHY_CTL_FDX (1<< 8) + +/* +7.1.2. PHY 0 Register 1: Status + 1.15 100Base_T4 RO 0: No 100Base-T4 capability 0 + 1.14 100Base_TX_FD RO 1: 100Base-TX full duplex capable 1 + 0: Not 100Base-TX full duplex capable + 1.13 100Base_TX_HD RO 1: 100Base-TX half duplex capable 1 + 0: Not 100Base-TX half duplex capable + 1.12 10Base_T_FD RO 1: 10Base-TX full duplex capable 1 + 0: Not 10Base-TX full duplex capable + 1.11 10Base_T_HD RO 1: 10Base-TX half duplex capable 1 + 0: Not 10Base-TX half duplex capable + 1.6 MF Preamble RO The RTL8309SB will accept management frames with 1 + Suppression preamble suppressed. + The RTL8309SB accepts management frames without + preamble. 32 minimum preamble bits are required for the + first SMI read/write transaction after reset. One idle bit is + required between any two management transactions as + defined in the IEEE 802.3u specifications. + 1.5 Auto-negotiate RO 1: Auto-negotiation process completed. MII Reg.4, 5 are 0 + Complete valid if this bit is set + 0: Auto-negotiation process not completed + 1.4 Remote Fault RO/LH 1: Remote fault condition detected 0 + 0: No remote fault + 1.3 Auto-Negotiation RO 1: NWay auto-negotiation capable (permanently=1) 1 + Ability + 1.2 Link Status RO/LL 1: Link is established. If the link fails, this bit will be 0 until 0 + after reading this bit again + 0: Link has failed + 1.1 Jabber Detect RO/LH 1: Jabber detect enabled 0 + 0: Jabber detect disabled + The jabber function is disabled in 100Base-TX operation. + Jabber occurs when a predefined excessively long packet is + detected for 10Base-T. When the duration of TXEN exceeds + the jabber timer (21ms), the transmission and loopback + function are disabled and the COL LED starts blinking. After + TXEN goes low for more than 500 ms, the transmitter will be + re-enabled and the COL LED will stop blinking. Jabber + detect is supported only in 10Base-T operation. + 1.0 Extended RO 1: Extended register capable (permanently=1) 1 + Capability +*/ + +#define PHY_STS(p) ID(p, 1) +#define PHY0_STS ID(PHY0, 1) +#define PHY1_STS ID(PHY1, 1) +#define PHY2_STS ID(PHY2, 1) +#define PHY3_STS ID(PHY3, 1) +#define PHY4_STS ID(PHY4, 1) +#define PHY5_STS ID(PHY5, 1) +#define PHY6_STS ID(PHY6, 1) +#define PHY7_STS ID(PHY7, 1) +#define PHY_STS_100_T4 (1<<15) +#define PHY_STS_100_F (1<<14) +#define PHY_STS_100_H (1<<13) +#define PHY_STS_10_F (1<<12) +#define PHY_STS_10_H (1<<11) +#define PHY_STS_MF_PRMBL (1<< 6) +#define PHY_STS_ANEG_CMPL (1<< 5) +#define PHY_STS_RMT_FLT (1<< 4) +#define PHY_STS_NW_ANEG (1<< 3) +#define PHY_STS_LINK_UP (1<< 2) +#define PHY_STS_JABBER (1<< 1) +#define PHY_STS_EXT_CAP (1<< 0) + +/* +Note: Whenever the link ability of the RTL8309SB is reconfigured, the auto-negotiation process should be executed again to +allow the configuration to take effect. +7.1.3. PHY 0 Register 4: Auto-Negotiation Advertisement + 4.15 Next Page RO 0: Next Page disabled (Permanently=0) 0 + 4.14 Acknowledge RO Permanently=0. 0 + 4.13 Remote Fault RW 1: Advertises that the RTL8309SB has detected a remote fault 0 + 0: No remote fault detected + 4.10 Pause RW 1: Advertises that the RTL8309SB possesses 802.3x flow Pin + control capability En_FCTRL + 0: No flow control capability strap option + 4.9 100Base-T4 RO Technology not supported (Permanently=0). 0 + 4.8 100Base-TX-FD RW 1: 100Base-TX full duplex capable 1 + 0: Not 100Base-TX full duplex capable + 4.7 100Base-TX RW 1: 100Base-TX half duplex capable 1 + 0: Not 100Base-TX half duplex capable + 4.6 10Base-T-FD RW 1: 10Base-TX full duplex capable 1 + 0: Not 10Base-TX full duplex capable + 4.5 10Base-T RW 1: 10Base-TX half duplex capable 1 + 0: Not 10Base-TX half duplex capable + 4.[4:0] Selector Field RO [00001]=IEEE 802.3. 00001 +*/ + +#define PHY_ANEG_ADV(p) ID(p, 4) +#define PHY0_ANEG_ADV ID(PHY0, 4) +#define PHY1_ANEG_ADV ID(PHY1, 4) +#define PHY2_ANEG_ADV ID(PHY2, 4) +#define PHY3_ANEG_ADV ID(PHY3, 4) +#define PHY4_ANEG_ADV ID(PHY4, 4) +#define PHY5_ANEG_ADV ID(PHY5, 4) +#define PHY6_ANEG_ADV ID(PHY6, 4) +#define PHY7_ANEG_ADV ID(PHY7, 4) +#define PHY_ANEG_ADV_NP_DIS (1<<15) +#define PHY_ANEG_ADV_ACK (1<<14) +#define PHY_ANEG_ADV_FLT_ADV (1<<13) +#define PHY_ANEG_ADV_ADV (1<<10) +#define PHY_ANEG_ADV_100_T4 (1<< 9) +#define PHY_ANEG_ADV_100_F (1<< 8) +#define PHY_ANEG_ADV_100_H (1<< 7) +#define PHY_ANEG_ADV_10_F (1<< 6) +#define PHY_ANEG_ADV_10_H (1<< 5) +#define PHY_ANEG_ADV_SEL_FLD_SHIFT 0 +#define PHY_ANEG_ADV_SEL_FLD_MASK 0x1f + +/* +7.1.4. PHY 0 Register 5: Auto-Negotiation Link Partner Ability + 5.15 Next Page RO 1: Link partner desires Next Page transfer 0 + 0: Link partner does not desire Next Page transfer + 5.14 Acknowledge RO 1: Link Partner acknowledges reception of Fast Link Pulse 0 + (FLP) words + 0: Not acknowledged by Link Partner + 5.13 Remote Fault RO 1: Remote Fault indicated by Link Partner 0 + 0: No remote fault indicated by Link Partner + 5.10 Pause RO 1: Flow control supported by Link Partner 0 + 0: Flow control not supported by Link Partner + 5.9 100Base-T4 RO 1: 100Base-T4 supported by Link Partner 0 + 0: 100Base-T4 not supported by Link Partner + 5.8 100Base-TX-FD RO 1: 100Base-TX full duplex supported by Link Partner 0 + 0: 100Base-TX full duplex not supported by Link Partner + Note: If auto negotiation is disabled and this bit is set, Reg0.13 + and Reg0.8 will be set to 1 after link is established. + 5.7 100Base-TX RO 1: 100Base-TX half duplex supported by Link Partner 0 + 0: 100Base-TX half duplex not supported by Link Partner + Note: If auto negotiation is disabled and this bit is set, Reg0.13 + will be set to 1 and Reg0.8 will be set to 0 after link is + established. + 5.6 10Base-T-FD RO 1: 10Base-TX full duplex supported by Link Partner 0 + 0: 10Base-TX full duplex not supported by Link Partner + Note: If auto negotiation is disabled and this bit is set, Reg0.13 + will be set to 0 and Reg0.8 will be set to 1 after link is + established. + 5.5 10Base-T RO 1: 10Base-TX half duplex supported by Link Partner 0 + 0: 10Base-TX half duplex not supported by Link Partner + Note: If auto negotiation is disabled and this bit is set, Reg0.13 + and Reg0.8 will be set to 0 after a link is established. + 5.[4:0] Selector Field RO [00001]=IEEE802.3. 00001 +*/ + +#define PHY_ANEG_PRTN(p) ID(p, 5) +#define PHY0_ANEG_PRTN ID(PHY0, 5) +#define PHY1_ANEG_PRTN ID(PHY1, 5) +#define PHY2_ANEG_PRTN ID(PHY2, 5) +#define PHY3_ANEG_PRTN ID(PHY3, 5) +#define PHY4_ANEG_PRTN ID(PHY4, 5) +#define PHY5_ANEG_PRTN ID(PHY5, 5) +#define PHY6_ANEG_PRTN ID(PHY6, 5) +#define PHY7_ANEG_PRTN ID(PHY7, 5) +#define PHY_ANEG_PRTN_NP_DIS (1<<15) +#define PHY_ANEG_PRTN_ACK (1<<14) +#define PHY_ANEG_PRTN_RMT_FLT (1<<13) +#define PHY_ANEG_PRTN_FC_ABLE (1<<10) +#define PHY_ANEG_PRTN_100_T4 (1<< 9) +#define PHY_ANEG_PRTN_100_F (1<< 8) +#define PHY_ANEG_PRTN_100_H (1<< 7) +#define PHY_ANEG_PRTN_10_F (1<< 6) +#define PHY_ANEG_PRTN_10_H (1<< 5) +#define PHY_ANEG_PRTN_SEL_FLD_SHIFT 0 +#define PHY_ANEG_PRTN_SEL_FLD_MASK 0x1f + +/* +7.1.5. PHY 0 Register 6: Auto-Negotiation Expansion + 6.4 Parallel RO 1: A fault has been detected via the Parallel Detection function 0 + Detection Fault 0: A fault has not been detected via the Parallel Detection + function + 6.3 Link Partner RO 0: Link Partner is not Next Pageable (permanently=0) 0 + Next Pageable + 6.2 Local Next RO 1: The RTL8309SB is Next Pageable 0 + Pageable 0: The RTL8309SB is not Next Pageable + 6.1 Page Received RO 1: A New Page has been received 0 + 0: A New Page has not been received + 6.0 Link Partner RO If NWay is enabled, this bit means: 0 (NWay) + Auto- 1: Link Partner is Auto-Negotiation able or + Negotiation Able 0: Link Partner is not Auto-Negotiation able 1 (Force) +*/ + +#define PHY_ANEG_EXP(p) ID(p, 6) +#define PHY0_ANEG_EXP ID(PHY0, 6) +#define PHY1_ANEG_EXP ID(PHY1, 6) +#define PHY2_ANEG_EXP ID(PHY2, 6) +#define PHY3_ANEG_EXP ID(PHY3, 6) +#define PHY4_ANEG_EXP ID(PHY4, 6) +#define PHY5_ANEG_EXP ID(PHY5, 6) +#define PHY6_ANEG_EXP ID(PHY6, 6) +#define PHY7_ANEG_EXP ID(PHY7, 6) +#define PHY_ANEG_EXP_PD_FLT (1<< 4) +#define PHY_ANEG_EXP_PRTN_NXTPG (1<< 3) +#define PHY_ANEG_EXP_NXTPG (1<< 2) +#define PHY_ANEG_EXP_PG_RCV (1<< 1) +#define PHY_ANEG_EXP_PRTN_ANEG (1<< 0) + +/* +7.1.6. PHY 0 Register 16: Global Control 0 + 16.[15:13] LED Mode RW 111 -> Mode 7: Speed, Duplex+Collision, Link+Act, SQI + 110 -> Mode 6: Activity, Speed, Link, SQI + 101 -> Mode 5: Speed, Duplex, Link+Act, SQI + 100 -> Mode 4: Collision, Duplex, Link+Act+Speed, SQI + 011 -> Mode 3: SQI, Duplex+Collision, Link+Act+Speed,10/100. + 010 -> Mode 2: RxAct+10/100, TxAct+10/100, Link, SQI + 001 -> Mode 1: Duplex+Collision, 10Link+Act, 100Link+Act, SQI + 000 -> Mode 0: Duplex+Collision, Bi-color Speed, Bi-color Link+Act, SQI. + 16.12 Software Reset RW/ 1: Soft reset. This bit is self-clearing 0 + SC If this bit is set to 1, the RTL8309SB will reset all registers in it + except PHY registers and will not load configurations from + EEPROM or strapping pins. Software reset is designed to + provide a convenient way for users to change the configuration + via SMI. After changing register values in the RTL8309SB + (except PHY registers) via SMI, the external device must + execute a soft reset in order to update the configuration by + setting this bit to 1. + 16.11 Disable VLAN RW 1: Disable VLAN 1 + 0: Enable VLAN. The default VLAN membership configuration + by internal register is MII port overlapped with all the other + ports to form 8 individual VLANs. This default membership + configuration may be modified by setting internal registers via + the SMI interface or EEPROM. + 0 + 16.10 Disable 802.1Q tag RW 1: Disable 802.1Q tagged-VID Aware function. The + aware VLAN RTL8309SB will not check the tagged VID on received frames + to perform tagged-VID VLAN mapping. Under this + configuration, the RTL8309SB only uses the per port VLAN + index register to perform Port-Based VLAN mapping + 0: Enable the Member Set Filtering function of VLAN Ingress + Rule. The RTL8309SB checks the tagged VID on received + frames with the VIDA[11:0]~VIDH[11:0] to index to a member + set, then performs VLAN mapping. The RTL8309SB uses + tagged-VID VLAN mapping for tagged frames but still uses + port-based VLAN mapping for priority-tagged and untagged + frames + 16.9 Disable VLAN RW 1: The switch will not drop a received frame if the ingress port 1 + member set ingress of this packet is not included in the matched VLAN member + filtering set. It will still forward the packet to the VLAN members + specified in the matched member set. This setting works on + both port-based and tag-based VLAN configurations + 0: The switch will drop the received frame if the ingress port of + this packet is not included in the matched VLAN member set + 16.8 Disable VLAN tag RW 1: The switch accepts all frames it receives whether tagged or 1 + admit control untagged + 0: The switch will only accept tagged frames and will drop + untagged frames + 16.7 EEPROM RO 1: EEPROM does not exist (pin EnEEPROM=0 or pin 0 + existence EnEEPROM=1 but EEPROM does not exist) + 0: EEPROM exists (pin EnEEPROM=1 and EEPROM exists) + 16.6 Accept Error RW 1: Filter bad packets in normal operation 1 + disable 0: Switch all packets including bad ones. This bit is intended for + debugging purposes only + 16.5 IEEE 802.3x RW 1: Determines when to invoke flow control based on 1 + transmit flow auto negotiation results + control enable 0: Will not enable transmit flow control no matter what the + auto negotiation result is + 16.4 IEEE 802.3x RW 1: When the RTL8309SB receives a pause control frame, it has 1 + receive flow the ability to stop the next transmission of a normal frame until + control enable the timer is expired based on the auto negotiation result + 0: Will not receive flow control no matter what the + auto negotiation result is + 16.3 Broadcast input or RW 1: Broadcast input drop is selected 1 + output drop 0: Broadcast output drop is selected + 16.2 Aging enable RW 1: Enable aging function 1 + 0: Disable aging function. The addresses learned in the lookup + table will not be aged out. If the table is full, the last entry in the + table will be deleted to make room for the new entry + 16.1 Fast aging enable RW 1: Enable fast aging function. The entry learned in the lookup 0 + table will be aged out if it is not updated within an 800μs period + 0: Disable fast aging function + 16.0 Enable ISP MAC RW 1: Enable ISP MAC Address Translation function 0 + Address 0: Disable ISP MAC Address Translation function + Translation +*/ + +#define GCNTRL0 ID(PHY0, 16) +#define GCNTRL0_LED_MODE_SHIFT 13 +#define GCNTRL0_LED_MODE_MASK 0xe000 +#define GCNTRL0_SOFT_RSET (1<<12) +#define GCNTRL0_VLAN_DIS (1<<11) +#define GCNTRL0_DOT1Q_DIS (1<<10) +#define GCNTRL0_INGRESS_CHECK_DIS (1<<9) +#define GCNTRL0_TAG_ONLY_DIS (1<<8) +#define GCNTRL0_EEPROM (1<<7) +#define GCNTRL0_FILTER_BAD (1<<6) +#define GCNTRL0_TX_FC (1<<5) +#define GCNTRL0_RX_FC (1<<4) +#define GCNTRL0_BCAST_IN_DROP (1<<3) +#define GCNTRL0_AGN_EN (1<<2) +#define GCNTRL0_FAST_AGN (1<<1) +#define GCNTRL0_MACAT (1<<0) + +/* +7.1.7. PHY 0 Register 17: Global Control 1 + 17.[15:13] 802.1p base RW Classifies priority for incoming 802.1Q packets, if 802.1p 100 + priority priority classification is enabled. User priorit is compared + against this value. + >=: Classify as high priority + <: Classify as low priority + 17.12 Trunking port RW 1: Combine port 0 and 1 as one trunking port, if trunking is 1 + assignment enabled via strapping pin Dis_Trun + 0: Combine port 6 and 7 as one trunking port, if trunking is + enabled via strapping pin Dis_Trunk + 17.[11:10] Queue weight RW The frame service ratio between the high priority queue and low 11 + priority queue is: + 11=16:1 + 10=always high priority queue first + 01=8:1 + 00=4:1 + 17.9 Disable IP priority RW 1: Compare both the source and destination IP address of 0 + for IP address [A] incoming packets against the value, IP address [A] AND IP + mask [A], to classify packet priority + 0: Do not compare the source or destination IP address of + incoming packets against the value IP address [A] AND IP + mask [A] + 17.8 Disable IP priority RW 1: Compare both the source and destination IP address of 0 + for IP address [B] incoming packets against the value, IP address [B] AND IP + mask [B], to classify packet priority + 0: Do not compare the source or destination IP address of + incoming packets against the value IP address [B] AND IP + mask [B] + 17.7 Enable default high RW 1: The default DiffServ code point listed below will be 1 + priority DiffServ considered as high priority code point if the DiffServ priority + code point function is enabled. + EF 101110 + AF 001010, 010010, 011010, 100010 + Network Control 111000, 110000 + 0: The default DiffServ code point will be considered low + priority +*/ +#define GCNTRL1 ID(PHY0, 17) + +/* +7.1.8. PHY 0 Register 18: Global Control 2 + 18.15 Enable differential RW 1: If differential service priority is enabled, this bit specifies 0 + service code point differential service code point [A] is high priority + [A] 0: If differential service priority is enabled, this bit specifies + differential services code point [A] is low priority + 18.[13:8] Differential service RW Used to specify the high priority differential service code 111111 + code point [A] point A. For example, if these bits are set to 111111, incoming + packets with a TOS field equal to 111111 will be considered + high priority packets. + 18.7 Enable differential RW 1: If differential service priority is enabled, this bit specifies 0 + service code point differential services code point [B] is high priority + [B] 0: If differential service priority is enabled, this bit specifies + differential services code point [B] is low priority + 18.[5:0] Differential service RW Used to specify a high priority differential service code point B. 111111 + code point [B] For example, if these bits are set to 000000, incoming packets + with a TOS field equal to 000000 will be considered high + priority packets. +*/ +#define GCNTRL2 ID(PHY0, 18) + +/* +7.1.9. PHY 0 Register 19: Global Control 3 + 19.15 Enable drop for 48 RW 1: Enable drop packet after SRAM full for 48 pass 1 1 + pass 1 0: Disable drop packet after SRAM full for 48 pass 1. This will + result in SRAM run out + 19.13 TX IPG RW 1: 90ppm TX IPG (InterPacketGap) compensation 1 + compensation 0: 65ppm TX IPG (InterPacketGap) compensation + 19.12 Disable loop RW 1: Disable loop detection function 1 + detection 0: Enable loop detection function + 19.11 Lookup table RW 1: Lookup table is accessible via indirect access registers 0 + accessible enable 0: Lookup table is not accessible +*/ +#define GCNTRL3 ID(PHY0, 19) + +/* +7.1.10. PHY 0 Register 22: Port 0 Control 0 + 22.13 Local loopback RW 1: Perform local loopback, i.e. loop MACs RX back to TX 0 + 0: Normal operation + 22.12 Null VID RW 1: The switch will replace a NULL VID with a port VID (12 0 + replacement bits) + 0: No replacement for a NULL VID + 22.11 Discard Non PVID RW 1: If the received packets are tagged, the switch will discard 0 + packets packets with a VID that does not match the ingress port default + VID, which is indexed by port 0 Port-based VLAN ind + 0: No packets will be dropped + 22.10 Disable 802.1p RW 1: Disable 802.1p priority classification for ingress packets on Pin + Dis_VLAN_Pri + priority port 0 + strap option + 0: Enable 802.1p priority classification + Default = 1 + 22.9 Disable Diffserv RW 1: Disable Diffserv priority classification for ingress packets on Pin + priority port 0 Dis_DS_Pri + 0: Enable Diffserv priority classification strap option + Default = 1 + 22.8 Disable port-based RW 1: Disable port priority function Pin + priority 0: Enable port priority function. Ingress packets from port 0 will Sel_Port_Pri + be classified as high priority strap option + Default = 1 + 11 + 22[1:0] VLAN tag RW 11=Do not insert or remove VLAN tags to/from packets sent + insertion and out from this port. + removal 10=The switch will add VLAN tags to packets if they are not + tagged. The switch will not add tags to packets already tagged. + The inserted tag is the ingress portsDefault t, which is + indexed by port 0s Port-based VLAN index. + 01=The switch will remove VLAN tags from packets, if they + are tagged when these packets are send out from port 0. The + switch will not modify packets received without tags. + 00=The switch will remove VLAN tags from packets then add + new tags to them. The inserted tag is the ingress ports Default + tag, which is indexed by port 0s Port-based VLAN index. + This is a replacement processing for tagged packets and an + insertion for untagged packets. +*/ + + +#define PHY_CTRL0(p) ID(p, 22) +#define PHY0_CTRL0 ID(PHY0, 22) +#define PHY1_CTRL0 ID(PHY1, 22) +#define PHY2_CTRL0 ID(PHY2, 22) +#define PHY3_CTRL0 ID(PHY3, 22) +#define PHY4_CTRL0 ID(PHY4, 22) +#define PHY5_CTRL0 ID(PHY5, 22) +#define PHY6_CTRL0 ID(PHY6, 22) +#define PHY7_CTRL0 ID(PHY7, 22) + +#define CTRL0_LOOP (1<<13) +#define CTRL0_R_NL_VID (1<<12) +#define CTRL0_I_CH_EN (1<<11) +#define CTRL0_1P_DIS (1<<10) +#define CTRL0_DFSRV_DIS (1<<9) +#define CTRL0_PQOS_DIS (1<<8) +#define CTRL0_TAG_MODE_MASK 3 +#define CTRL0_TAG_NI_NR 3 /* Not insert, not remove */ +#define CTRL0_TAG_I_UTG 2 /* Ingress Insert for untagged */ +#define CTRL0_TAG_R_TG 1 /* Remove Tag on Egress */ +#define CTRL0_TAG_IR 0 /* Insert or Replace Tag */ + + +/* +7.1.11. PHY 0 Register 23: Port 0 Control 1 + 23.11 Transmission RW 1: Enable packet transmission on port 0 1 + enable 0: Disable packet transmission on port 0 + 23.10 Reception enable RW 1: Enable packet reception on port 0 1 + 0: Disable packet reception on port 0 + 23.9 Learning enable RW 1: Enable switch address learning capability 1 + 0: Disable switch address learning capability + 23.8 Loop status RO 1: A loop has been detected on port 0 0 + 0: No loop exists on port 0 + 23[7:4] Link quality RO 4-bit field indicating the link quality of the receive twisted-pair + or fiber link. + 0000: Highest link quality + 1111: Lowest link quality +*/ + +#define PHY_CTRL1(p) ID(p, 23) +#define PHY0_CTRL1 ID(PHY0, 23) +#define PHY1_CTRL1 ID(PHY1, 23) +#define PHY2_CTRL1 ID(PHY2, 23) +#define PHY3_CTRL1 ID(PHY3, 23) +#define PHY4_CTRL1 ID(PHY4, 23) +#define PHY5_CTRL1 ID(PHY5, 23) +#define PHY6_CTRL1 ID(PHY6, 23) +#define PHY7_CTRL1 ID(PHY7, 23) + +#define CTRL1_TX_EN (1<<11) +#define CTRL1_RX_EN (1<<10) +#define CTRL1_LRN_EN (1<<9) +#define CTRL1_LOOP_DET (1<<8) +#define CTRL1_LQ_MASK 0x00f0 +#define CTRL1_LQ_SHIFT 4 + + + + +#define PORT_PVID(p) ID((PHY0+p), 24) +#define VLAN_MEMB(v) ID((PHY0+v), 24) +#define VLAN_ID(v) ID((PHY0+v), 25) +#define VLAN_ID_MASK 0x0fff +#define VLAN_ID_SHIFT 0 + +#define PORT0_PVID ID(PHY0, 24) +#define VLAN_A_MEMB ID(PHY0, 24) +#define VLAN_A_ID ID(PHY0, 25) + +#define PORT8_PVID ID(PHY5, 17) +#define VLAN_I_MEMB ID(PHY5, 17) +#define VLAN_I_ID ID(PHY5, 18) + +#define PORT0_PVID_IDX_SHIFT 12 +#define PORT0_PVID_IDX_MASK 0xf000 +#define PORT8_PVID_IDX_SHIFT 9 +#define PORT8_PVID_IDX_MASK 0x1e00 +#define VLAN_A_MEMB_SHIFT 0 +#define VLAN_A_MEMB_MASK 0x01ff + +/* +7.2.6. PHY 1 Register 16~17: IP Priority Address [A] + 16 IP Address [A] RW The switch will compare both the source and destination IP 0xFFFF + [31:16] addresses of an incoming packet against the value, IP address + [A] AND IP mask [A], to classify priority for the packet. + 17 IP Address [A] RW The switch will both compare the source and destination IP 0xFFFF + [15:0] addresses of an incoming packet against the value, IP address + [A] AND IP mask [A], to classify priority for the packet. +*/ +/* +7.2.7. PHY 1 Register 18~19: IP Priority Address [B] + 18 IP Address [B] RW The switch will compare both the source and destination IP 0xFFFF + [31:16] addresses of an incoming packet against the value, IP address + [B] AND IP mask [B], to classify priority for the packet, if IP + priority for IP address [B] is enabled. + 19 IP Address [B] RW The switch will compare both the source and destination IP 0xFFFF + [15:0] addresses of an incoming packet against the value, IP address + [B] AND IP mask [B], to classify priority for the packet, if IP + priority for IP address [B] is enabled. + +*/ +/* +7.3.6. PHY 2 Register 16~17: IP Priority Mask [A] + 16 IP Mask [A] RW The switch will compare both the source and destination IP 0xFFFF + [31:16] addresses of an incoming packet against the value, IP address + [A] AND IP mask [A], to classify priority for the packet. + 17 IP Mask [A] [15:0] RW The switch will compare both the source and destination IP 0xFFFF + addresses of an incoming packet against the value, IP address + [A] AND IP mask [A], to classify priority for the packet. +*/ +/* +7.3.7. PHY 2 Register 18~19: IP Priority Mask [B] + 18 IP Mask [B] RW The switch will compare both the source and destination IP 0xFFFF + [31:16] addresses of an incoming packet against the value, IP address + [B] AND IP mask [B], to classify priority for the packet, if IP + priority for IP address [B] is enabled. + 19 IP Mask [B] [15:0] RW The switch will compare both the source and destination IP 0xFFFF + addresses of an incoming packet against the value, IP address + [B] AND IP mask [B], to classify priority for the packet, if IP + priority for IP address [B] is enabled. + 0010 +*/ +/* +7.4.6. PHY 3 Register 16~18: Switch MAC Address +The Switch MAC address is used as the source address in MAC pause control frames. + 16 Switch MAC RW 16.[15:8] = Switch MAC Address Byte 4. 0x5452 + Address [47:32] 16.[7:0] = Switch MAC Address Byte 5. + 17 Switch MAC RW 17.[15:8] = Switch MAC Address Byte 2. 0x834C + Address [31:16] 17.[7:0] = Switch MAC Address Byte 3. + 18 Switch MAC RW 18.[15:8] = Switch MAC Address Byte 0. 0xB009 + Address [15:0] 18.[7:0] = Switch MAC Address Byte 1. +*/ +/* +7.5.6. PHY 4 Register 16~18: ISP MAC Address +The ISP’s MAC address is used as the source address in MAC address translation functions. + Reg.bit Name Mode Description Default + 16 ISP MAC Address RW 16.[15:8] = ISP MAC Address Byte 1. 0x4205 + [15:0] 16.[7:0] = ISP MAC Address Byte 0. + 17 ISP MAC Address RW 17.[15:8] = ISP MAC Address Byte 3. 0x212F + [31:16] 17.[7:0] = ISP MAC Address Byte 2. + 18 ISP MAC Address RW 18.[15:8] = ISP MAC Address Byte 5. 0x5C91 + [47:32] 18.[7:0] = ISP MAC Address Byte 4. +*/ +/* +7.6.6. PHY 5 Register 16: MII Port Control 0 + 16.15 Transmission RW 1: Enable packet transmission on MII interface 1 + enable 0: Disable packet transmission on MII interface + 16.14 Reception enable RW 1: Enable packet reception on MII interface 1 + 0: Disable packet reception on MII interface + 16.13 Learning enable RW 1: Enable switch address learning capability 1 + 0: Disable switch address learning capability + 16.12 Enable MII RW 1: Enable local loop back function. The switch will only 0 + loopback forward local and broadcast packets from the input of MII RX + to the output of MII TX, and will drop unicast packets from the + input of MII RX. The other ports still can forward packets to the + MII port + 0: Disable local loop back function + 16.11 Disable 802.1p RW 1: Disable 802.1p priority classification for ingress packets on Pin Dis_VLAN_Pri strap option + priority port 8 + 0: Enable 802.1p priority classification + Default = 1 + 16.10 Disable Diffserv RW 1: Disable Diffserv priority classification for ingress packets on Pin Dis_DS_Pri strap option + priority port 8 + 0: Enable Diffserv priority classification + Default = 1 + 16.9 Disable port-based RW 1: Disable port priority function Pin + priority 0: Enable port priority function. Ingress packets from port 8 will Sel_Port_Pri + be classified as high priority strap option + Default = 1 + 11 + 16.[1:0] VLAN tag RW 11=Do not insert or remove VLAN tags to/from packets sent + insertion and out from this port. + removal 10=The switch will add VLAN tags to packets if they are not + tagged. The switch will not add tags to packets already tagged. + The inserted tag is the ingress port’s ‘Default tag’, which is + indexed by the MII port’s ‘Port-based VLAN index’. + 01=The switch will remove VLAN tags from packets, if they + are tagged when these packets are send out from MII port. The + switch will not modify packets received without tags. + 00=The switch will remove VLAN tags from packets then add + new tags to them. The inserted tag is the ingress port’s ‘Default + tag’, which is indexed by MII port’s ‘Port-based VLAN index’. + This is a replacement processing for tagged packets and an + insertion for untagged packets. +*/ +/* +7.6.7. PHY 5 Register 17: MII Port Control 1 & VLAN Entry [I] + 17.15 Null VID RW 1: The switch will replace a NULL VID with a port VID 0 + replacement (12 bits) + 0: No replacement for a NULL VID + 17.14 Discard Non- RW 1: If the received packets are tagged, the switch will discard 0 + PVID packets packets with a VID that does not match the ingress port default + VID, which is indexed by the MII port’s ‘Port-based VLAN + index’ + 0: No packets will be dropped + 0000 +*/ +/* +7.6.9. PHY 5 Register 19: CPU Port & WAN Port + 19.[7:4] WAN Port RW Specify the WAN port on the RTL8309SB. 0111 + 1000=MII Port is WAN Port + 0111=Port 7 is WAN Port 0110=Port 6 is WAN Port + 0101=Port 5 is WAN Port 0100=Port 4 is WAN Port + 0011=Port 3 is WAN Port 0010=Port 2 is WAN Port + 0001=Port 1 is WAN Port 0000=Port 0 is WAN Port + 19.[3:0] CPU Port RW Specify the CPU port on the RTL8309SB. 0000 + 1000=MII Port is CPU Port + 0111=Port 7 is CPU Port 0110=Port 6 is CPU Port + 0101=Port 5 is CPU Port 0100=Port 4 is CPU Port + 0011=Port 3 is CPU Port 0010=Port 2 is CPU Port + 0001=Port 1 is CPU Port 0000=Port 0 is CPU Port +*/ +/* +7.8.6. PHY 7 Register 16: indirect Access Control +PHY 7 register 16 is used for reading or writing data to the MAC address table. + 16.1 Command RW 1: Trigger a command to read or write the lookup table 0 + execution 0: Indicates this command has completed + 16.0 Read or write RW 1: Read cycle 0 + operation 0: Write cycle +*/ +/* +7.8.7. PHY 7 Register 17~20: Indirect Access Data + 17 Indirect Data RW Bit 63~48 of indirect data. 0x00 + [63:48] Indirect Data [54] = If this bit is 1, indicates this entry is static + and will never be aged out. If this bit is 0, indicates this entry is + dynamically learned, aged, updated, and deleted. + Indirect Data [53:52] = 2-bit counter for internal aging. + Indirect Data [51:48] = The source port of this Source MAC + Address is learned. + 18 Indirect Data RW Bit 47~32 of indirect data. 0x00 + [47:32] Indirect Data [47:40] = Source MAC Address [39:32]. + Indirect Data [39:32] = Source MAC Address [47:40]. + 19 Indirect Data RW Bit 31~16 of indirect data. 0x00 + [31:16] Indirect Data [31:24] = Source MAC Address [23:16]. + Indirect Data [23:16] = Source MAC Address [31:24]. + 0x00 + 20 Indirect Data RW Bit 15~0 of indirect data. + [15:0] Indirect Data [15:8] = Source MAC Address [7:0]. + Indirect Data [7:0] = Source MAC Address [15:8]. + Bits 1~0 and Bits 15~8 of this register also determine the + address of data in the lookup table. + In a write cycle: Bits 1~0 and Bits 15~8 indirectly map to an + entry in the lookup table. The written data should be filled in + Indirect Data [63:0] + In a read cycle: Bits 1~0 and Bits 15~8 indirectly map to an + entry in the lookup table. The read back data will be shown in + Indirect Data [63:0]. + + 0111 +*/ +/* +7.9.1. PHY 8 Register 0: Control +Note: This register only works in MII PHY and SNI PHY mode. In MII MAC mode, these registers have no meaning. + Table 104. PHY 8 Register 0: Control + Reg.bit Name Mode Description Default + 0.15 Reset RO 0: No reset allowed (permanently=0) 0 + 0.14 Loopback RO 0: Normal operation (permanently=0) 0 + (digital loopback) + 0.13 Speed Select RW 1: 100Mbps Pin MII_SPD + 0: 10Mbps _STA strap + When NWay is enabled, this bit reflects the result of auto- option + negotiation (Read only). + When NWay is disabled, this bit can be set through SMI + (Read/Write). + 0.12 Auto Negotiation RW 1: Enable auto-negotiation process 1 + Enable 0: disable auto-negotiation process + This bit can be set through SMI (Read/Write). + 0.11 Power Down RO 0: Normal operation (permanently=0) 0 + 0.10 Isolate RO 0: Normal operation (permanently=0) 0 + 0.9 Restart Auto RO 0: Normal operation (permanently=0) 0 + Negotiation + 0.8 Duplex Mode RW 1: Full duplex operation Pin MII_DUP + 0: Half duplex operation _STA strap + When NWay is enabled, this bit reflects the result of auto- option + negotiation (Read only). + When NWay is disabled, this bit may be set through SMI + (Read/Write). +*/ +/* +7.9.2. PHY 8 Register 1: Status +Note: This register only works in MII PHY and SNI PHY mode. In MII MAC mode, these registers have no meaning. + Table 105. PHY 8 Register 1: Status + Reg.bit Name Mode Description Default + 1.15 100Base_T4 RO 0: No 100Base-T4 capability 0 + 1.14 100Base_TX_FD RO 1: 100Base-TX full duplex capable (permanently=1) 1 + 1.13 100Base_TX_HD RO 1: 100Base-TX half duplex capable (permanently=1) 1 + 1.12 10Base_T_FD RO 1: 10Base-TX full duplex capable (permanently=1) 1 + 1.11 10Base_T_HD RO 1: 10Base-TX half duplex capable (permanently=1) 1 + 1.6 MF Preamble RO The RTL8309SB will accept management frames with 1 + Suppression preamble suppressed (permanently=1) + 1.5 Auto-negotiate RO 1: Auto-negotiation process completed. MII Reg.4, 5 are valid if 1 + Complete this bit is set (permanently=1) + 1.4 Remote Fault RO 0: No remote fault (permanently=0) 0 + 1.3 Auto-Negotiation RO 1: NWay auto-negotiation capable (permanently=1) 1 + Ability + 1.2 Link Status RO 1: Link is established. If the link should ever fail, this bit will be Pin MII_LNK + 0 until after reading this bit again _STA# strap + 0: Link failed option + 1.1 Jabber Detect RO 0: No Jabber detected (permanently=0) 0 + 1.0 Extended RO 1: Extended register capable (permanently=1) 1 + Capability +*/ +/* +7.9.3. PHY 8 Register 4: Auto-Negotiation Advertisement +Note: This register only works in MII PHY and SNI PHY mode. In MII MAC mode, these registers have no meaning. + Table 106. PHY 8 Register 4: Auto-Negotiation Advertisement + Reg.bit Name Mode Description Default + 4.15 Next Page RO 1: Next Page enabled 0 + 0: Next Page disabled (Permanently=0) + 4.14 Acknowledge RO Permanently=0 0 + 4.13 Remote Fault RO 1: Advertises that the RTL8309S has detected a remote fault 0 + 0: No remote fault detected + 4.10 Pause RW 1: Advertises that the RTL8309SB possesses 802.3x flow Pin + control capability MII_FCTRL + 0: No flow control capability _STA strap + option + 4.9 100Base-T4 RO Technology not supported (Permanently=0). 0 + 4.8 100Base-TX-FD RW 1: 100Base-TX full duplex capable 1 + 0: Not 100Base-TX full duplex capable + 4.7 100Base-TX RW 1: 100Base-TX half duplex capable 1 + 0: Not 100Base-TX half duplex capable + 4.6 10Base-T-FD RW 1: 10Base-TX full duplex capable 1 + 0: Not 10Base-TX full duplex capable + 4.5 10Base-T RW 1: 10Base-TX half duplex capable 1 + 0: Not 10Base-TX half duplex capable + 4.[4:0] Selector Field RO [00001]=IEEE 802.3. 00001 +*/ Property changes on: sys/dev/switch/rtl830x_switchreg.h ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/dev/switch/switch_obio.c =================================================================== --- sys/dev/switch/switch_obio.c (revision 0) +++ sys/dev/switch/switch_obio.c (revision 0) @@ -0,0 +1,232 @@ +/*- + * Copyright (c) 2011 Aleksandr Rybalko. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * switch control attached to OBIO bus + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "switch_if.h" +#include "switchb_if.h" + +#define READ4(_sc, _reg) \ + bus_space_read_4(_sc->sc_bst, _sc->sc_bsh, _reg) + +#define WRITE4(_sc, _reg, _val) \ + bus_space_write_4(_sc->sc_bst, _sc->sc_bsh, _reg, _val) + + +static int switch_obio_probe(device_t); +static int switch_obio_attach(device_t); +static int switch_obio_detach(device_t); +static int switch_obio_intr(void *); + +static int +switch_obio_probe(device_t dev) +{ + device_set_desc(dev, "ethernet switch bus"); + return (0); +} + +static int +switch_obio_attach(device_t dev) +{ + struct switch_softc *sc; + int error = 0; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + + /* Map control registers. */ + sc->mem_rid = 0; + sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &sc->mem_rid, RF_ACTIVE); + + if (sc->mem_res == NULL) { + device_printf(dev, "couldn't map memory\n"); + error = ENXIO; + switch_obio_detach(dev); + return(error); + } + + sc->sc_bst = rman_get_bustag(sc->mem_res); + sc->sc_bsh = rman_get_bushandle(sc->mem_res); + + sc->irq_rid = 0; + if ((sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, + &sc->irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { + device_printf(dev, "unable to allocate IRQ resource\n"); + return (ENXIO); + } + + if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC, + switch_obio_intr, NULL, sc, &sc->ihandl))) { + device_printf(dev, + "WARNING: unable to register interrupt handler\n"); + return (ENXIO); + } + SWITCH_LOCK_INIT(sc); +// error = switch_init(&sc->sc_switch); + error = switch_init(sc); + if (error) + return (error); + + return (bus_generic_attach(dev)); +} + +static int +switch_obio_detach(device_t dev) +{ + struct switch_softc *sc; + + sc = device_get_softc(dev); + + SWITCH_LOCK_DESTROY(sc); + + if (sc->irq_res) + bus_teardown_intr(dev, sc->irq_res, &sc->ihandl); + + switch_deinit(sc); + + bus_generic_detach(dev); + + if (sc->irq_res) + bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid, + sc->irq_res); + + if (sc->mem_res) + bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, + sc->mem_res); + + return(0); +} + +static int +switch_obio_intr(void *arg) +{ + struct switch_softc *sc; + + sc = (struct switch_softc *)arg; + + if (sc->sc_isr) + return (*sc->sc_isr)(sc->sc_cookie); + + return (FILTER_HANDLED); +} + +static int +switch_obio_register_isr(device_t dev, driver_filter_t isr, device_t child) +{ + struct switch_softc *sc; + void *child_sc; + + sc = device_get_softc(dev); + + if (!sc->sc_isr) { + child_sc = device_get_softc(child); + sc->sc_isr = isr; + sc->sc_cookie = child_sc; + } + + return (0); +} + +static void +switch_obio_unregister_isr(device_t dev, device_t child) +{ + struct switch_softc *sc; + void *child_sc; + + sc = device_get_softc(dev); + child_sc = device_get_softc(child); + + /* Only registered child can unregister */ + if (sc->sc_cookie == child_sc) { + sc->sc_isr = NULL; + sc->sc_cookie = NULL; + } + + return; +} + +static uint32_t +switch_obio_read4(device_t dev, uint32_t reg) +{ + struct switch_softc *sc; + + sc = device_get_softc(dev); + + return (READ4(sc, reg)); +} + +static void +switch_obio_write4(device_t dev, uint32_t reg, uint32_t val) +{ + struct switch_softc *sc; + + sc = device_get_softc(dev); + + WRITE4(sc, reg, val); +} + +static device_method_t switch_obio_methods[] = { + DEVMETHOD(device_probe, switch_obio_probe), + DEVMETHOD(device_attach, switch_obio_attach), + DEVMETHOD(device_detach, switch_obio_detach), + + + DEVMETHOD(switchb_read4, switch_obio_read4), + DEVMETHOD(switchb_write4, switch_obio_write4), + DEVMETHOD(switchb_register_isr, switch_obio_register_isr), + DEVMETHOD(switchb_unregister_isr, switch_obio_unregister_isr), + {0, 0}, +}; + +static driver_t switch_obio_driver = { + "switch", + switch_obio_methods, + sizeof(struct switch_softc), +}; +static devclass_t switch_obio_devclass; + +DRIVER_MODULE(switch, obio, switch_obio_driver, switch_obio_devclass, 0, 0); +//DRIVER_MODULE(switch, mii, switch_obio_driver, switch_obio_devclass, 0, 0); + Property changes on: sys/dev/switch/switch_obio.c ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/dev/switch/ar8x16_switch.c =================================================================== --- sys/dev/switch/ar8x16_switch.c (revision 0) +++ sys/dev/switch/ar8x16_switch.c (revision 0) @@ -0,0 +1,638 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include "switch_if.h" +#include "switchb_if.h" + +static int get_reg(device_t dev, uint32_t reg, uint32_t *value); +static int set_reg(device_t dev, uint32_t reg, uint32_t *value); + +static __uint32_t +ar8x16_reg_read(struct ar8x16_switch_softc *sc, __uint32_t reg) +{ + __uint16_t lo, hi; + + MII_WRITE(sc, sc->page_phy, sc->page_reg, REG_PAGE(reg)); + /* Wait for the page switch to propagate */ + DELAY(100); + + lo = MII_READ(sc, (0x10 | REG_PHY(reg)), REG_REG(reg)); + hi = MII_READ(sc, (0x10 | REG_PHY(reg)), REG_REG(reg) + 1); + + return ((hi << 16) | lo); +} + +static void +ar8x16_reg_write(struct ar8x16_switch_softc *sc, __uint32_t reg, __uint32_t val) +{ + + MII_WRITE(sc, sc->page_phy, sc->page_reg, REG_PAGE(reg)); + /* Wait for the page switch to propagate */ + DELAY(100); + + MII_WRITE(sc, (0x10 | REG_PHY(reg)), REG_REG(reg) + 1, val >> 16); + MII_WRITE(sc, (0x10 | REG_PHY(reg)), REG_REG(reg), val & 0xffff); +} + +static uint32_t +READ4(struct ar8x16_switch_softc *sc, uint32_t reg_addr) +{ + return (ar8x16_reg_read(sc, reg_addr)); +} + +static void +WRITE4(struct ar8x16_switch_softc *sc, uint32_t reg_addr, uint32_t reg_val) +{ + ar8x16_reg_write(sc, reg_addr, reg_val); +} + +static int +get_reg(device_t dev, uint32_t reg, uint32_t *value) +{ + struct ar8x16_switch_softc *sc; + + sc = device_get_softc(dev); + if (reg & 0x80000000) + *value = READ4(sc, reg); + else + *value = MII_SW_READ4(sc, reg); + return (0); +} + +static int +set_reg(device_t dev, uint32_t reg, uint32_t *value) +{ + struct ar8x16_switch_softc *sc; + uint32_t old; + + sc = device_get_softc(dev); + if (reg & 0x80000000) { + old = READ4(sc, reg); + WRITE4(sc, reg, *value); + } else { + old = MII_SW_READ4(sc, reg); + MII_SW_WRITE4(sc, reg, *value); + } + + *value = old; + return (0); +} + +static int +ar8x16_switch_reset(struct ar8x16_switch_softc *sc) +{ + int ret; + + /* Reset the switch. */ + WRITE4(sc, AR8X16_REG_MASK_CTRL, AR8X16_MASK_CTRL_SOFT_RESET); + + ret = WAIT4(sc, AR8X16_REG_MASK_CTRL, AR8X16_MASK_CTRL_SOFT_RESET, 0, + 1000); + return ret; +} + +#if 0 +static int +ar8x16_set_addr(struct ar8x16_switch_softc *sc, uint8_t *mac) +{ + + WRITE4(sc, AR8X16_REG_MAC_ADDR0, (mac[4] << 8) | mac[5]); + WRITE4(sc, AR8X16_REG_MAC_ADDR1, (mac[0] << 24) | (mac[1] << 16) | + (mac[2] << 8) | mac[3]); + + return 0; +} +#endif + +static int +ar8x16_switch_detect(struct ar8x16_switch_softc *sc, int phy, int reg) +{ + uint32_t rev; + + sc->page_phy = phy; + sc->page_reg = reg; + rev = READ4(sc, AR8X16_REG_MASK_CTRL); + + switch (rev & (AR8X16_MASK_CTRL_VER_MASK|AR8X16_MASK_CTRL_REV_MASK)) { + case 0x0101: + case 0x0102: + sc->devid = 8216; + sc->revid = (rev & AR8X16_MASK_CTRL_REV_MASK); + break; + case 0x0201: + sc->devid = 8226; + sc->revid = (rev & AR8X16_MASK_CTRL_REV_MASK); + break; + case 0x1001: + sc->devid = 8316; + sc->revid = (rev & AR8X16_MASK_CTRL_REV_MASK); + break; + default: + sc->devid = ((rev & AR8X16_MASK_CTRL_VER_MASK) >> + AR8X16_MASK_CTRL_VER_SHIFT); + sc->revid = (rev & AR8X16_MASK_CTRL_REV_MASK); + break; + } + + return (rev & (AR8X16_MASK_CTRL_VER_MASK|AR8X16_MASK_CTRL_REV_MASK)); +} + +static int +ar8x16_switch_probe(device_t dev) +{ + struct child_res_avl *res; + struct ar8x16_switch_softc *sc; + char name[64]; + + + res = device_get_ivars(dev); + + /* ar8x16 use PHYs for access */ + if (!res->phys) + return (ENXIO); + + sc = device_get_softc(dev); + sc->parent = device_get_parent(dev); /* switchX device */ + sc->sc_dev = dev; + + if (ar8x16_switch_detect(sc, 0x18, 0x00) == 0xffff) + if (ar8x16_switch_detect(sc, 0x1f, 0x10) == 0xffff) { + device_printf(dev, "Can't access device regs\n"); + return (ENXIO); + } + + if (sc->devid == 8216 || sc->devid == 8316) { + sprintf(name, "AR%d.%d Ethernet switch", sc->devid, sc->revid); + device_set_desc_copy(dev, name); + return (BUS_PROBE_SPECIFIC); + } + + sprintf(name, "Unknown AR8x16 like Ethernet switch (%02x.%02x)", + sc->devid, sc->revid); + device_set_desc_copy(dev, name); + return (BUS_PROBE_DEFAULT); +} + +static int +ar8316_init(struct ar8x16_switch_softc *sc) +{ + uint32_t mode; + + /* Set the interface type: rgmii, gmii - We only support rgmii atm. */ + mode = READ4(sc, AR8X16_REG_MODE); + + if (mode == AR8X16_MODE_GMII) { + device_printf(sc->sc_dev, "Unsupported MII mode.\n"); + return (ENXIO); + } + if (sc->sc_mii_mode != mode) { + device_printf(sc->sc_dev, "Initializing the Switch.\n"); + if (sc->sc_mii_mode == AR8X16_MODE_RGMII_PORT4_ISO) { + device_printf(sc->sc_dev, + "Switch port 4 is isolated.\n"); + } + WRITE4(sc, AR8X16_REG_MODE, sc->sc_mii_mode); + } + + /* Standard Atheros magic */ + /* XXX, find what magic in those value, + * somewhere I(ray) already seen it, but forget where */ + WRITE4(sc, 0x38, AR8X16_MAGIC); + + return (0); +} + +static int +ar8x16_init(device_t dev) +{ + struct ar8x16_switch_softc *sc; + int port, err; + + sc = device_get_softc(dev); + + /* AR8316 specific init routine */ + if (sc->devid == 8316) { + /* XXX - Default setting for RSPRO */ + /* XXX - Need to "isolate" of isolate bits :), + * seems port1 (first Physical) isolate on set 0x400 bit + */ + sc->sc_mii_mode = AR8X16_MODE_RGMII_PORT4_ISO; + err = ar8316_init(sc); + if (err != 0) + return (err); + } + if ((sc->devid == 8216) && (sc->revid == 2)) { + WRITE4(sc, AR8X16_REG_MODE, AR8X16_MODE_RGMII_PORT4_SWITCH); + } + + /* Reset the switch */ + ar8x16_switch_reset(sc); + + /* Enable CPU port, and disable mirror port */ + WRITE4(sc, AR8X16_REG_CPU_PORT, + AR8X16_CPU_PORT_EN | + (15 << AR8X16_MIRROR_PORT_SHIFT)); + + /* Setup TAG priority mapping */ + WRITE4(sc, AR8X16_REG_TAG_PRIO, 0xfa50); + + /* Enable ARP frame acknowledge */ + SET4(sc, AR8X16_REG_AT_CTRL, 0, AR8X16_AT_CTRL_ARP_EN); + + /* Enable Broadcast frames transmitted to the CPU */ + SET4(sc, AR8X16_REG_FLOOD_MASK, 0, AR8X16_FLOOD_MASK_BCAST_TO_CPU); + + /* setup MTU */ + SET4(sc, AR8X16_REG_GLOBAL_CTRL, AR8X16_GLOBAL_CTRL_MTU_MASK, 1536); + + /* setup Service TAG */ + SET4(sc, AR8X16_REG_SERVICE_TAG, AR8X16_SERVICE_TAG_MASK, 0); + + /* Port0 - CPU */ + /* XXX: goot to know which speed to set */ + WRITE4(sc, AR8X16_REG_PORT_STS(0), + /* TODO: deal with interface link speed */ + /* AR8X16_PORT_STS_SPEED_10 | */ + /* AR8X16_PORT_STS_SPEED_100 | */ + AR8X16_PORT_STS_SPEED_1000 | + AR8X16_PORT_STS_TXMAC | + AR8X16_PORT_STS_RXMAC | + AR8X16_PORT_STS_TXFLOW | + AR8X16_PORT_STS_RXFLOW | + AR8X16_PORT_STS_DUPLEX); + WRITE4(sc, AR8X16_REG_PORT_CTRL(0), + READ4(sc, AR8X16_REG_PORT_CTRL(0)) & ~AR8X16_PORT_CTRL_HEADER); + + for (port = 1; port < AR8X16_NUM_PORTS; port++) { + /* Set ports to autoneg */ + WRITE4(sc, AR8X16_REG_PORT_STS(port), + AR8X16_PORT_STS_LINK_AUTO); + WRITE4(sc, AR8X16_REG_PORT_CTRL(port), + READ4(sc, AR8X16_REG_PORT_CTRL(port)) & + ~AR8X16_PORT_CTRL_HEADER); + } + pause("PhyNeg", hz*3); + + return (0); +} + + +static int +ar8x16_switch_attach(device_t dev) +{ + struct ar8x16_switch_softc *sc; + + sc = device_get_softc(dev); + + if (ar8x16_init(dev) != 0) + return (ENXIO); + + sc->ports = 6; + sc->vlans = 16; + sc->sc_dev = dev; + sc->vlan_idx = malloc(sizeof(uint16_t) * sc->vlans, M_DEVBUF, + M_WAITOK|M_ZERO); + if (!sc->vlan_idx) + return (ENXIO); + + sc->caps = malloc(sizeof(struct switch_capability), M_DEVBUF, + M_WAITOK | M_ZERO); + + if (!sc->caps) { + free(sc->vlan_idx, M_DEVBUF); + return (ENXIO); + } + +#define S_C(x) SWITCH_CAPS_ ## x + sc->caps->ports = sc->ports; + sc->caps->main = S_C(MAIN_PORT_POWER); + sc->caps->vlan = S_C(VLAN_GLBL_UNTG) | S_C(VLAN_DOT1Q) | S_C(VLAN_DOUBLE_TAG) | + ((sc->vlans << S_C(VLAN_MAX_SHIFT_SHIFT)) & S_C(VLAN_MAX_SHIFT_MASK)); + sc->caps->qos = (2 << S_C(QOS_QUEUES_SHIFT)) & S_C(QOS_QUEUES_MASK); + sc->caps->lacp = 0; /* No LACP caps */ + sc->caps->stp = 0; /* No STP caps */ + sc->caps->acl = 0; + sc->caps->stat = 0; +#undef S_C + + return (0); +} + +static int +ar8x16_switch_detach(device_t dev) +{ + struct ar8x16_switch_softc *sc; + + sc = device_get_softc(dev); + +#ifdef AR8X16_USE_INTERRUPT + if (sc->parent) + SWITCHB_UNREGISTER_ISR(sc->parent, dev); +#endif + + if (sc->caps) + free(sc->caps, M_DEVBUF); + + if (sc->vlan_idx); + free(sc->vlan_idx, M_DEVBUF); + + return (0); +} + +/* + * Switch interface methods + */ +static struct switch_capability * +get_caps(device_t dev) +{ + struct ar8x16_switch_softc *sc; + + sc = device_get_softc(dev); + + return (sc->caps); +} + + +static int +find_mac_addr(device_t dev, uint64_t mac) +{ + struct ar8x16_switch_softc *sc; + int idx = -1; + + sc = device_get_softc(dev); + + return (idx); +} + +static int +mac_table_write(device_t dev, uint64_t mac, int idx, uint32_t port_map, + uint8_t age, int *hash_idx ) +{ + return (0); +} + +static int +set_port_vid(device_t dev, int port, uint16_t pvid) +{ + struct ar8x16_switch_softc *sc = device_get_softc(dev); + uint32_t reg; + + if (port > (sc->ports - 1)) + return (EINVAL); + + reg = READ4(sc, AR8X16_REG_PORT_VLAN(port)); + reg &= ~0xfff; + reg |= (0xfff & pvid); + WRITE4(sc, AR8X16_REG_PORT_VLAN(port), reg); + + return (0); +} + +static int +get_port_vid(device_t dev, int port, uint16_t *pvid) +{ + struct ar8x16_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (port > (sc->ports - 1)) + return (EINVAL); + + reg = READ4(sc, AR8X16_REG_PORT_VLAN(port)); + + *pvid = reg & 0xfff; + return (0); +} + +static int +get_port_flags(device_t dev, int port, uint32_t *flags) +{ + struct ar8x16_switch_softc *sc; + uint32_t reg = 0; + + *flags = 0; + sc = device_get_softc(dev); + if (port > (sc->ports - 1)) + return (EINVAL); + + reg = READ4(sc, AR8X16_REG_PORT_CTRL(port)); + *flags |= (reg & AR8X16_PORT_CTRL_DOUBLE_TAG)? + DOT1Q_VLAN_PORT_FLAG_DOUBLE_TAG:0; + + if (((reg & 0x300) >> 8) == AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_ADD) + *flags |= DOT1Q_VLAN_PORT_FLAG_TAGGED; + else if (((reg & 0x300) >> 8) == AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_STRIP) + *flags |= DOT1Q_VLAN_PORT_FLAG_UNTAGGED; + + return (0); +} + +static int +set_port_flags(device_t dev, int port, uint32_t flags) +{ + struct ar8x16_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (port > (sc->ports - 1)) + return (1); + + /* Q-in-Q */ + reg = READ4(sc, AR8X16_REG_PORT_CTRL(port)); + if (flags & DOT1Q_VLAN_PORT_FLAG_DOUBLE_TAG) + reg |= AR8X16_PORT_CTRL_DOUBLE_TAG; + else + reg &= ~AR8X16_PORT_CTRL_DOUBLE_TAG; + + if (flags & DOT1Q_VLAN_PORT_FLAG_TAGGED) { + reg &= ~(3 << 8); + reg |= AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_ADD << 8; + } else if (flags & DOT1Q_VLAN_PORT_FLAG_UNTAGGED) { + reg &= ~(3 << 8); + reg |= AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_STRIP << 8; + } + + WRITE4(sc, AR8X16_REG_PORT_CTRL(port), reg); + + return (0); +} + +static int +set_vid(device_t dev, int idx, uint16_t vid) +{ + struct ar8x16_switch_softc *sc; + + sc = device_get_softc(dev); + if (idx > (sc->vlans - 1)) + return (1); + + sc->vlan_idx[idx] = VLAN_IDX_VALID | vid; + + return (0); +} + +static int +get_vid(device_t dev, int idx, uint16_t *vid) +{ + struct ar8x16_switch_softc *sc = device_get_softc(dev); + uint32_t reg; + + if (idx > (sc->vlans - 1)) + return (EINVAL); + + reg = sc->vlan_idx[idx]; + + if (reg & VLAN_IDX_VALID) { + *vid = reg & 0xfff; + return (0); + } else + return (ENOENT); +} + +static int +set_vlan_ports(device_t dev, int idx, uint32_t memb) +{ + struct ar8x16_switch_softc *sc = device_get_softc(dev); + uint16_t vlan; + int error = 0; + + printf("%s: idx=%d, memb=%08x\n", __func__, idx, memb); + + if (idx > (sc->vlans - 1)) + return (EINVAL); + if (memb & ((1 << sc->ports) - 1)) + return (EINVAL); + + error = get_vid(dev, idx, &vlan); + if (error == ENOENT) { + /* If vid not mapped to vid, try to create it */ + error = set_vid(dev, idx, vlan); + } + if (error) + return (error); + + if (WAIT4(sc, AR8X16_REG_VLAN_CTRL, AR8X16_VLAN_ACTIVE, 0, 5)) + return (EBUSY); + + WRITE4(sc, AR8X16_REG_VLAN_DATA, (memb & AR8X16_VLAN_MEMBER) | + AR8X16_VLAN_VALID); + + WRITE4(sc, AR8X16_REG_VLAN_CTRL, (vlan << AR8X16_VLAN_VID_SHIFT) | + AR8X16_VLAN_ACTIVE | AR8X16_VLAN_OP_LOAD); + + /* Wait for command done */ + if (WAIT4(sc, AR8X16_REG_VLAN_CTRL, AR8X16_VLAN_ACTIVE, 0, 5)) + return (EBUSY); + + if (READ4(sc, AR8X16_REG_VLAN_CTRL) & AR8X16_VLAN_FULL) + return (EINVAL); + + return (0); +} + +static int +get_vlan_ports(device_t dev, int idx, uint32_t *memb) +{ + struct ar8x16_switch_softc *sc = device_get_softc(dev); + uint32_t reg; + uint16_t vlan; + int error = 0; + + if (idx > (sc->vlans - 1)) + return (EINVAL); + + error = get_vid(dev, idx, &vlan); + if (error) + return (error); + + if (WAIT4(sc, AR8X16_REG_VLAN_CTRL, AR8X16_VLAN_ACTIVE, 0, 5)) + return (EBUSY); + + WRITE4(sc, AR8X16_REG_VLAN_CTRL, (vlan << AR8X16_VLAN_VID_SHIFT) | + AR8X16_VLAN_ACTIVE | AR8X16_VLAN_OP_GET); + + /* Wait for data */ + if (WAIT4(sc, AR8X16_REG_VLAN_CTRL, AR8X16_VLAN_ACTIVE, 0, 5)) + return (EBUSY); + + reg = READ4(sc, AR8X16_REG_VLAN_DATA); + if (reg & AR8X16_VLAN_VALID) { + reg &= ((1 << sc->ports) - 1); + } else { + reg = 0; + error = EINVAL; + } + + printf("%s: idx=%d, memb=%08x, error=%d\n", __func__, idx, reg, + error); + *memb = reg; + return (error); +} + +static device_method_t ar8x16_switch_methods[] = { + DEVMETHOD(device_probe, ar8x16_switch_probe), + DEVMETHOD(device_attach, ar8x16_switch_attach), + DEVMETHOD(device_detach, ar8x16_switch_detach), + + /* Capability */ + DEVMETHOD(switch_get_caps, get_caps), + DEVMETHOD(switch_set_reg, set_reg), + DEVMETHOD(switch_get_reg, get_reg), + + /* MAC address table */ + DEVMETHOD(switch_find_mac, find_mac_addr), + DEVMETHOD(switch_mac_write, mac_table_write), + + /* 802.1q */ + DEVMETHOD(switch_set_pvid, set_port_vid), + DEVMETHOD(switch_get_pvid, get_port_vid), + DEVMETHOD(switch_set_pflags, set_port_flags), + DEVMETHOD(switch_get_pflags, get_port_flags), + DEVMETHOD(switch_set_vid, set_vid), + DEVMETHOD(switch_get_vid, get_vid), + DEVMETHOD(switch_set_vlanports, set_vlan_ports), + DEVMETHOD(switch_get_vlanports, get_vlan_ports), +// DEVMETHOD(switch_set_vlanutports, set_vlan_untagged_ports), +// DEVMETHOD(switch_get_vlanutports, get_vlan_untagged_ports), + + /* Port state */ +// DEVMETHOD(switch_get_portlink, get_port_link), +// DEVMETHOD(switch_get_portspeed, get_port_speed), +// DEVMETHOD(switch_force_mode, force_port_mode), + + /* Statistics */ +// DEVMETHOD(switch_good_in_cnt, stat_good_in_packet_count), +// DEVMETHOD(switch_good_out_cnt, stat_good_out_packet_count), +// DEVMETHOD(switch_bad_in_cnt, stat_bad_in_packet_count), +// DEVMETHOD(switch_bad_out_cnt, stat_bad_out_packet_count), + + {0, 0}, +}; + +static driver_t ar8x16_switch_driver = { + "ar8x16_switch", + ar8x16_switch_methods, + sizeof(struct ar8x16_switch_softc), +}; +static devclass_t ar8x16_switch_devclass; + +DRIVER_MODULE(ar8x16_switch, switch, ar8x16_switch_driver, ar8x16_switch_devclass, 0, 0); +MODULE_VERSION(ar8x16_switch, 1); +MODULE_DEPEND(ar8x16_switch, switch, 1, 1, 1); + + Property changes on: sys/dev/switch/ar8x16_switch.c ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/dev/switch/switch_spi.c =================================================================== --- sys/dev/switch/switch_spi.c (revision 0) +++ sys/dev/switch/switch_spi.c (revision 0) @@ -0,0 +1,33 @@ +/*- + * Copyright (c) 2011, Aleksandr Rybalko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * switch control attached to SPI + */ + Property changes on: sys/dev/switch/switch_spi.c ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/dev/switch/ar8x16_switchreg.h =================================================================== --- sys/dev/switch/ar8x16_switchreg.h (revision 0) +++ sys/dev/switch/ar8x16_switchreg.h (revision 0) @@ -0,0 +1,217 @@ +#ifndef __AR8X16_SWITCHREG_H__ +#define __AR8X16_SWITCHREG_H__ + +#define AR8X16_REG_MASK_CTRL 0x0000 +#define AR8X16_MASK_CTRL_REV_MASK 0x000000ff +#define AR8X16_MASK_CTRL_VER_MASK 0x0000ff00 +#define AR8X16_MASK_CTRL_VER_SHIFT 8 +#define AR8X16_MASK_CTRL_SOFT_RESET (1 << 31) + +#define AR8X16_REG_MODE 0x0008 +#define AR8X16_MODE_RGMII_PORT4_ISO 0x81461bea /* From Ubiquiti RSPRO */ +#define AR8X16_MODE_RGMII_PORT4_SWITCH 0x01261be2 /* Unknown */ +#define AR8X16_MODE_GMII 0x010e5b71 /* AVM Fritz!Box 7390 */ + +#define AR8X16_REG_ISR 0x0010 +#define AR8X16_REG_IMR 0x0014 + +#define AR8X16_REG_SW_MAC_ADDR0 0x0020 +#define AR8X16_REG_SW_MAC_ADDR1 0x0024 + +#define AR8X16_REG_FLOOD_MASK 0x002c +#define AR8X16_FLOOD_MASK_BCAST_TO_CPU (1 << 26) + +#define AR8X16_REG_GLOBAL_CTRL 0x0030 +#define AR8X16_GLOBAL_CTRL_MTU_MASK 0x00000fff + +#define AR8X16_REG_VLAN_CTRL 0x0040 +#define AR8X16_VLAN_OP 0x00000007 +#define AR8X16_VLAN_OP_NOOP 0x0 +#define AR8X16_VLAN_OP_FLUSH 0x1 +#define AR8X16_VLAN_OP_LOAD 0x2 +#define AR8X16_VLAN_OP_PURGE 0x3 +#define AR8X16_VLAN_OP_REMOVE_PORT 0x4 +#define AR8X16_VLAN_OP_GET_NEXT 0x5 +#define AR8X16_VLAN_OP_GET 0x6 +#define AR8X16_VLAN_ACTIVE (1 << 3) +#define AR8X16_VLAN_FULL (1 << 4) +#define AR8X16_VLAN_PORT 0x00000f00 +#define AR8X16_VLAN_PORT_SHIFT 8 +#define AR8X16_VLAN_VID 0x0fff0000 +#define AR8X16_VLAN_VID_SHIFT 16 +#define AR8X16_VLAN_PRIO 0x70000000 +#define AR8X16_VLAN_PRIO_SHIFT 28 +#define AR8X16_VLAN_PRIO_EN (1 << 31) + +#define AR8X16_REG_VLAN_DATA 0x0044 +#define AR8X16_VLAN_MEMBER 0x000003ff +#define AR8X16_VLAN_VALID (1 << 11) + +#define AR8X16_REG_ARL_CTRL0 0x0050 +#define AR8X16_REG_ARL_CTRL1 0x0054 +#define AR8X16_REG_ARL_CTRL2 0x0058 + +#define AR8X16_REG_AT_CTRL 0x005c +#define AR8X16_AT_CTRL_ARP_EN (1 << 20) + +#define AR8X16_REG_IP_PRIORITY_1 0x0060 +#define AR8X16_REG_IP_PRIORITY_2 0x0064 +#define AR8X16_REG_IP_PRIORITY_3 0x0068 +#define AR8X16_REG_IP_PRIORITY_4 0x006C + +#define AR8X16_REG_TAG_PRIO 0x0070 + +#define AR8X16_REG_SERVICE_TAG 0x0074 +#define AR8X16_SERVICE_TAG_MASK 0x0000ffff + +#define AR8X16_REG_CPU_PORT 0x0078 +#define AR8X16_MIRROR_PORT_SHIFT 4 +#define AR8X16_CPU_PORT_EN (1 << 8) + +#define AR8X16_REG_MIB_FUNC0 0x0080 +#define AR8X16_MIB_TIMER_MASK 0x0000ffff +#define AR8X16_MIB_AT_HALF_EN (1 << 16) +#define AR8X16_MIB_BUSY (1 << 17) +#define AR8X16_MIB_FUNC_SHIFT 24 +#define AR8X16_MIB_FUNC_NO_OP 0x0 +#define AR8X16_MIB_FUNC_FLUSH 0x1 +#define AR8X16_MIB_FUNC_CAPTURE 0x3 +#define AR8X16_MIB_FUNC_XXX (1 << 30) /* 0x40000000 */ + +#define AR8X16_REG_MDIO_HIGH_ADDR 0x0094 + +#define AR8X16_REG_MDIO_CTRL 0x0098 +#define AR8X16_MDIO_CTRL_DATA_MASK 0x0000ffff +#define AR8X16_MDIO_CTRL_REG_ADDR_SHIFT 16 +#define AR8X16_MDIO_CTRL_PHY_ADDR_SHIFT 21 +#define AR8X16_MDIO_CTRL_CMD_WRITE 0 +#define AR8X16_MDIO_CTRL_CMD_READ (1 << 27) +#define AR8X16_MDIO_CTRL_MASTER_EN (1 << 30) +#define AR8X16_MDIO_CTRL_BUSY (1 << 31) + +#define AR8X16_REG_PORT_BASE(_p) (0x0100 + (_p) * 0x0100) + +#define AR8X16_REG_PORT_STS(_p) (AR8X16_REG_PORT_BASE((_p)) + 0x0000) +#define AR8X16_PORT_STS_SPEED_MASK 0x00000003 +#define AR8X16_PORT_STS_SPEED_10 0 +#define AR8X16_PORT_STS_SPEED_100 1 +#define AR8X16_PORT_STS_SPEED_1000 2 +#define AR8X16_PORT_STS_TXMAC (1 << 2) +#define AR8X16_PORT_STS_RXMAC (1 << 3) +#define AR8X16_PORT_STS_TXFLOW (1 << 4) +#define AR8X16_PORT_STS_RXFLOW (1 << 5) +#define AR8X16_PORT_STS_DUPLEX (1 << 6) +#define AR8X16_PORT_STS_LINK_UP (1 << 8) +#define AR8X16_PORT_STS_LINK_AUTO (1 << 9) +#define AR8X16_PORT_STS_LINK_PAUSE (1 << 10) + +#define AR8X16_REG_PORT_CTRL(_p) (AR8X16_REG_PORT_BASE((_p)) + 0x0004) +#define AR8X16_PORT_CTRL_STATE_MASK 0x00000007 +#define AR8X16_PORT_CTRL_STATE_DISABLED 0 +#define AR8X16_PORT_CTRL_STATE_BLOCK 1 +#define AR8X16_PORT_CTRL_STATE_LISTEN 2 +#define AR8X16_PORT_CTRL_STATE_LEARN 3 +#define AR8X16_PORT_CTRL_STATE_FORWARD 4 +#define AR8X16_PORT_CTRL_LEARN_LOCK (1 << 7) +#define AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_SHIFT 8 +#define AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_KEEP 0 +#define AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_STRIP 1 +#define AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_ADD 2 +#define AR8X16_PORT_CTRL_EGRESS_VLAN_MODE_DOUBLE_TAG 3 +#define AR8X16_PORT_CTRL_IGMP_SNOOP (1 << 10) +#define AR8X16_PORT_CTRL_HEADER (1 << 11) +#define AR8X16_PORT_CTRL_MAC_LOOP (1 << 12) +#define AR8X16_PORT_CTRL_SINGLE_VLAN (1 << 13) +#define AR8X16_PORT_CTRL_LEARN (1 << 14) +#define AR8X16_PORT_CTRL_DOUBLE_TAG (1 << 15) +#define AR8X16_PORT_CTRL_MIRROR_TX (1 << 16) +#define AR8X16_PORT_CTRL_MIRROR_RX (1 << 17) + +#define AR8X16_REG_PORT_VLAN(_p) (AR8X16_REG_PORT_BASE((_p)) + 0x0008) + +#define AR8X16_PORT_VLAN_DEFAULT_ID_SHIFT 0 +#define AR8X16_PORT_VLAN_DEST_PORTS_SHIFT 16 +#define AR8X16_PORT_VLAN_MODE_SHIFT 30 +#define AR8X16_PORT_VLAN_MODE_PORT_ONLY 0 +#define AR8X16_PORT_VLAN_MODE_PORT_FALLBACK 1 +#define AR8X16_PORT_VLAN_MODE_VLAN_ONLY 2 +#define AR8X16_PORT_VLAN_MODE_SECURE 3 + +#define AR8X16_REG_PORT_RATE_LIM(_p) (AR8X16_REG_PORT_BASE((_p)) + 0x000c) +#define AR8X16_PORT_RATE_LIM_128KB 0 +#define AR8X16_PORT_RATE_LIM_256KB 1 +#define AR8X16_PORT_RATE_LIM_512KB 2 +#define AR8X16_PORT_RATE_LIM_1MB 3 +#define AR8X16_PORT_RATE_LIM_2MB 4 +#define AR8X16_PORT_RATE_LIM_4MB 5 +#define AR8X16_PORT_RATE_LIM_8MB 6 +#define AR8X16_PORT_RATE_LIM_16MB 7 +#define AR8X16_PORT_RATE_LIM_32MB 8 +#define AR8X16_PORT_RATE_LIM_64MB 9 +#define AR8X16_PORT_RATE_LIM_IN_EN (1 << 24) +#define AR8X16_PORT_RATE_LIM_OUT_EN (1 << 23) +#define AR8X16_PORT_RATE_LIM_IN_MASK 0x000f0000 +#define AR8X16_PORT_RATE_LIM_IN_SHIFT 16 +#define AR8X16_PORT_RATE_LIM_OUT_MASK 0x0000000f +#define AR8X16_PORT_RATE_LIM_OUT_SHIFT 0 + +#define AR8X16_REG_PORT_PRIORITY(_p) (AR8X16_REG_PORT_BASE((_p)) + 0x0010) + +#define AR8X16_REG_STATS_BASE(_p) (0x20000 + (_p) * 0x100) + +#define AR8X16_STATS_RXBROAD 0x0000 +#define AR8X16_STATS_RXPAUSE 0x0004 +#define AR8X16_STATS_RXMULTI 0x0008 +#define AR8X16_STATS_RXFCSERR 0x000c +#define AR8X16_STATS_RXALIGNERR 0x0010 +#define AR8X16_STATS_RXRUNT 0x0014 +#define AR8X16_STATS_RXFRAGMENT 0x0018 +#define AR8X16_STATS_RX64BYTE 0x001c +#define AR8X16_STATS_RX128BYTE 0x0020 +#define AR8X16_STATS_RX256BYTE 0x0024 +#define AR8X16_STATS_RX512BYTE 0x0028 +#define AR8X16_STATS_RX1024BYTE 0x002c +#define AR8X16_STATS_RX1518BYTE 0x0030 +#define AR8X16_STATS_RXMAXBYTE 0x0034 +#define AR8X16_STATS_RXTOOLONG 0x0038 +#define AR8X16_STATS_RXGOODBYTE 0x003c +#define AR8X16_STATS_RXBADBYTE 0x0044 +#define AR8X16_STATS_RXOVERFLOW 0x004c +#define AR8X16_STATS_FILTERED 0x0050 +#define AR8X16_STATS_TXBROAD 0x0054 +#define AR8X16_STATS_TXPAUSE 0x0058 +#define AR8X16_STATS_TXMULTI 0x005c +#define AR8X16_STATS_TXUNDERRUN 0x0060 +#define AR8X16_STATS_TX64BYTE 0x0064 +#define AR8X16_STATS_TX128BYTE 0x0068 +#define AR8X16_STATS_TX256BYTE 0x006c +#define AR8X16_STATS_TX512BYTE 0x0070 +#define AR8X16_STATS_TX1024BYTE 0x0074 +#define AR8X16_STATS_TX1518BYTE 0x0078 +#define AR8X16_STATS_TXMAXBYTE 0x007c +#define AR8X16_STATS_TXOVERSIZE 0x0080 +#define AR8X16_STATS_TXBYTE 0x0084 +#define AR8X16_STATS_TXCOLLISION 0x008c +#define AR8X16_STATS_TXABORTCOL 0x0090 +#define AR8X16_STATS_TXMULTICOL 0x0094 +#define AR8X16_STATS_TXSINGLECOL 0x0098 +#define AR8X16_STATS_TXEXCDEFER 0x009c +#define AR8X16_STATS_TXDEFER 0x00a0 +#define AR8X16_STATS_TXLATECOL 0x00a4 + +#define AR8X16_PORT_CPU 0 +#define AR8X16_NUM_PORTS 6 +#define AR8X16_NUM_PHYS 5 +#define AR8X16_MAGIC 0xc000050e + +#define AR8X16_PHY_ID1 0x004d +#define AR8X16_PHY_ID2 0xd041 + +#define AR8X16_PORT_MASK(_port) (1 << (_port)) +#define AR8X16_PORT_MASK_ALL ((1<parent, _reg) + +#define MII_SW_WRITE4(_sc, _reg, _val) \ + SWITCHB_WRITE4(_sc->parent, _reg, _val) + +#endif /* _BCM5325_SWITCHVAR_H_ */ Property changes on: sys/dev/switch/bcm5325_switchvar.h ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/dev/switch/switch_gpio.c =================================================================== --- sys/dev/switch/switch_gpio.c (revision 0) +++ sys/dev/switch/switch_gpio.c (revision 0) @@ -0,0 +1,33 @@ +/*- + * Copyright (c) 2011, Aleksandr Rybalko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * switch control attached to GPIO + */ + Property changes on: sys/dev/switch/switch_gpio.c ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/dev/switch/switchvar.h =================================================================== --- sys/dev/switch/switchvar.h (revision 0) +++ sys/dev/switch/switchvar.h (revision 0) @@ -0,0 +1,94 @@ +/*- + * Copyright (c) 2011, Aleksandr Rybalko + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * + */ + +#ifndef _SWITCHVAR_H_ +#define _SWITCHVAR_H_ + +#include +#include +#include + +/* Switch capability list */ +struct switch_capability { + + uint32_t ports; /* Number of ports */ + uint32_t main; + uint32_t vlan; + uint32_t qos; + uint32_t lacp; + uint32_t stp; + uint32_t acl; + uint32_t stat; +}; + +struct child_res_avl { + size_t memres_size; + uint32_t phys; + uint8_t irqs; +}; + +struct switch_softc { + + struct mtx sc_mtx; /* bus mutex */ + struct resource *mem_res; + int mem_rid; + size_t mem_size; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + struct resource *irq_res; + int irq_rid; + uint32_t phys; + void *ihandl; + driver_filter_t *sc_isr; + void *sc_cookie; + + device_t sc_dev; + device_t child; + struct cdev *sc_cdev; + + int enable; + struct switch_capability *caps; + struct child_res_avl *args; +}; + +int switch_init(struct switch_softc *sc); +int switch_deinit(struct switch_softc *sc); +int switch_tick(struct switch_softc *sc); + +#define SWITCH_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) +#define SWITCH_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) +#define SWITCH_LOCK_INIT(_sc) \ + mtx_init(&(_sc)->sc_mtx, device_get_nameunit((_sc)->sc_dev), \ + "etherswitch", MTX_DEF) +#define SWITCH_LOCK_DESTROY(_sc) mtx_destroy(&(_sc)->sc_mtx); +#define SWITCH_ASSERT_LOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED); +#define SWITCH_ASSERT_UNLOCKED(_sc) mtx_assert(&(_sc)->sc_mtx, MA_NOTOWNED); + +#endif /* _SWITCHVAR_H_ */ + Property changes on: sys/dev/switch/switchvar.h ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/dev/switch/rtl830x_switchvar.h =================================================================== --- sys/dev/switch/rtl830x_switchvar.h (revision 0) +++ sys/dev/switch/rtl830x_switchvar.h (revision 0) @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2010 Aleksandr Rybalko. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _RTL830X_SWITCHVAR_H_ +#define _RTL830X_SWITCHVAR_H_ + +struct rtl830x_switch_softc { + device_t sc_dev; + device_t parent; + int ports; + int vlans; + struct switch_capability *caps; +}; + +#define READ4(_sc, _reg) \ + SWITCHB_READ4(_sc->parent, (_reg)) + +#define WRITE4(_sc, _reg, _val) \ + SWITCHB_WRITE4(_sc->parent, (_reg), ((_val) & 0xffff)) + +#endif /* _RTL830X_SWITCHVAR_H_ */ + Property changes on: sys/dev/switch/rtl830x_switchvar.h ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/dev/switch/rt305x_switch.c =================================================================== --- sys/dev/switch/rt305x_switch.c (revision 0) +++ sys/dev/switch/rt305x_switch.c (revision 0) @@ -0,0 +1,829 @@ +/*- + * Copyright (c) 2010 Aleksandr Rybalko. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include "switch_if.h" +#include "switchb_if.h" + +/* TODO */ +static int find_mac_addr(device_t dev, uint64_t mac); +/* TODO */ +static int mac_table_write(device_t dev, uint64_t mac, int idx, + uint32_t port_map, uint8_t age, int *hash_idx ); + +static int set_port_vid(device_t dev, int port, uint16_t pvid); +static int get_port_vid(device_t dev, int port, uint16_t *pvid); +static int set_vid(device_t dev, int idx, uint16_t vid); +static int get_vid(device_t dev, int idx, uint16_t *vid); +static int set_vlan_ports(device_t dev, int idx, uint32_t memb); +static int get_vlan_ports(device_t dev, int idx, uint32_t *memb); + +static int get_port_link(device_t dev, int port); +static int get_port_speed(device_t dev, int port); +static int force_port_mode(device_t dev, int port, uint32_t mode); + +static uint32_t stat_good_in_packet_count(device_t dev, int port); +static uint32_t stat_good_out_packet_count(device_t dev, int port); +static uint32_t stat_bad_in_packet_count(device_t dev, int port); +static uint32_t stat_bad_out_packet_count(device_t dev, int port); + + +static int rt305x_switch_isr(void *arg); + +static int +rt305x_switch_probe(device_t dev) +{ + struct child_res_avl *res; + + res = device_get_ivars(dev); + + /* rt305x internal switch require mem region */ + if (res->memres_size < (RT_SW_P5PC - RT_SW_ISR)) + return (ENXIO); + + /* and can serve IRQ */ + if (res->irqs < 1) + return (ENXIO); + + device_set_desc(dev, "RT305XF internal ethernet switch"); + return (BUS_PROBE_DEFAULT); +} + +static int +rt305x_switch_attach(device_t dev) +{ + struct rt305x_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + sc->parent = device_get_parent(dev); + + reg = READ4(sc, RT_SW_MTI); + if (reg & AT_RAM_TEST_FAIL) { + printf("rt305x_switch: Address Table RAM test failed\n"); + return (ENXIO); + } + if (reg & LK_RAM_TEST_FAIL) { + printf("rt305x_switch: Link RAM test failed\n"); + return (ENXIO); + } + if (reg & DT_RAM_TEST_FAIL) { + printf("rt305x_switch: Data buffer RAM test failed\n"); + return (ENXIO); + } + + if (!(reg & SW_RAM_TEST_DONE)) + printf( + "rt305x_switch: WARNING: Switch memory test not done\n"); + if (!(reg & AT_RAM_TEST_DONE)) + printf( + "rt305x_switch: WARNING: Address Table RAM test not done\n"); + if (!(reg & LK_RAM_TEST_DONE)) + printf( + "rt305x_switch: WARNING: Link RAM test not done\n"); + if (!(reg & DT_RAM_TEST_DONE)) + printf( + "rt305x_switch: WARNING: Data buffer RAM test not done\n"); + + if (!(reg & (SW_RAM_TEST_DONE | AT_RAM_TEST_DONE | + LK_RAM_TEST_DONE | DT_RAM_TEST_DONE))) { + printf( + "rt305x_switch: ERROR: All RAM tests not done or not RT305xF" + " internal switch\n"); + return (ENXIO); + } + + sc->caps = malloc(sizeof(struct switch_capability), M_DEVBUF, + M_WAITOK | M_ZERO); + + if (!sc->caps) + return (ENXIO); + + sc->caps->ports = sc->ports = 7; + sc->vlans = 16; + sc->sc_dev = dev; + SWITCHB_REGISTER_ISR(sc->parent, rt305x_switch_isr, dev); + +#define S_C(x) SWITCH_CAPS_ ## x + sc->caps->main = S_C(MAIN_PORT_POWER); + sc->caps->vlan = S_C(VLAN_GLBL_UNTG) | S_C(VLAN_DOT1Q) | + S_C(VLAN_DOUBLE_TAG) | + ((sc->vlans << S_C(VLAN_MAX_SHIFT_SHIFT)) & S_C(VLAN_MAX_SHIFT_MASK)); + sc->caps->qos = (2 << S_C(QOS_QUEUES_SHIFT)) & S_C(QOS_QUEUES_MASK); + sc->caps->lacp = 0; /* No LACP caps */ + sc->caps->stp = 0; /* No STP caps */ + sc->caps->acl = 0x21020304; + sc->caps->stat = 0x31020304; +#undef S_C + + reg = READ4(sc, RT_SW_IMR); + reg &= ~(HAS_INTRUDER | PORT_ST_CHG | BC_STORM); + WRITE4(sc, RT_SW_IMR, reg); + +#ifdef RT305X_SWITCH_DEBUG + int i; + for (i = 0; i < RT_SW_P5PC; i += 4) { + printf("%08x%c", READ4(sc, i), ((i+4)%16)?' ':'\n'); + } +#endif + + return (0); +} + +static int +rt305x_switch_detach(device_t dev) +{ + struct rt305x_switch_softc *sc; + + sc = device_get_softc(dev); + + if (sc->parent) + SWITCHB_UNREGISTER_ISR(sc->parent, dev); + + if (sc->caps) + free(sc->caps, M_DEVBUF); + + return (0); +} + +static void +rt305x_switch_wdog(struct rt305x_switch_softc *sc, int wdog) +{ + + printf("%s: wdog=%d\n", __func__, wdog); +} + +static void +rt305x_switch_intruder_alert(struct rt305x_switch_softc *sc) +{ + + printf("%s\n", __func__); +} + +static void +rt305x_switch_port_state_change(struct rt305x_switch_softc *sc) +{ + int port; + + printf("%s: Link status:\n", __func__); + for (port = 0; port < sc->ports; port++) + printf("%c ", + get_port_link(sc->sc_dev, port)?'*':' '); + printf("\n"); +} + +static void +rt305x_switch_broadcast_storm(struct rt305x_switch_softc *sc) +{ + + printf("%s\n", __func__); +} + +static void +rt305x_switch_global_queue_full(struct rt305x_switch_softc *sc) +{ + + printf("%s\n", __func__); +} + +static void +rt305x_switch_lan_queue_full(struct rt305x_switch_softc *sc, int port) +{ + + printf("%s: port=%d\n", __func__, port); +} + + +static int +rt305x_switch_isr(void *arg) +{ + struct rt305x_switch_softc *sc; + uint32_t isr; + + sc = (struct rt305x_switch_softc *)arg; + + isr = READ4(sc, RT_SW_ISR); + if (!isr) + return (0); + + if (isr & WATCHDOG1_TMR_EXPIRED) { + /* Handle Watchdog timer 1 */ + rt305x_switch_wdog(sc, 1); + } + + if (isr & WATCHDOG0_TMR_EXPIRED) { + /* Handle Watchdog timer 0 */ + rt305x_switch_wdog(sc, 0); + } + + if (isr & HAS_INTRUDER) { + /* + * Handle detected Intrusion, read bits 0-6 of RT_SW_PTS + * to get port. + */ + rt305x_switch_intruder_alert(sc); + } + + if (isr & PORT_ST_CHG) { + /* Handle port state change */ + rt305x_switch_port_state_change(sc); + } + + if (isr & BC_STORM) { + /* Handle Broadcast Storm */ + rt305x_switch_broadcast_storm(sc); + } + + if (isr & MUST_DROP_LAN) { + /* Handle */ + // XXX: check what is it + } + + if (isr & GLOBAL_QUE_FULL) { + /* Handle global queue full intr */ + rt305x_switch_global_queue_full(sc); + } + + if (isr & LAN_QUE_FULL6) { + /* Handle LAN port 6 queue full intr */ + rt305x_switch_lan_queue_full(sc, 6); + } + + if (isr & LAN_QUE_FULL5) { + /* Handle LAN port 5 queue full intr */ + rt305x_switch_lan_queue_full(sc, 5); + } + + if (isr & LAN_QUE_FULL4) { + /* Handle LAN port 4 queue full intr */ + rt305x_switch_lan_queue_full(sc, 4); + } + + if (isr & LAN_QUE_FULL3) { + /* Handle LAN port 3 queue full intr */ + rt305x_switch_lan_queue_full(sc, 3); + } + + if (isr & LAN_QUE_FULL2) { + /* Handle LAN port 2 queue full intr */ + rt305x_switch_lan_queue_full(sc, 2); + } + + if (isr & LAN_QUE_FULL1) { + /* Handle LAN port 1 queue full intr */ + rt305x_switch_lan_queue_full(sc, 1); + } + + if (isr & LAN_QUE_FULL0) { + /* Handle LAN port 0 queue full intr */ + rt305x_switch_lan_queue_full(sc, 0); + } + + /* Ack interrupts */ + WRITE4(sc, RT_SW_ISR, isr); + return (FILTER_HANDLED); +} + + +/* + * Switch interface methods + */ +static struct switch_capability * +get_caps(device_t dev) +{ + struct rt305x_switch_softc *sc; + + sc = device_get_softc(dev); + + return (sc->caps); +} + + +static int +find_mac_addr(device_t dev, uint64_t mac) +{ + struct rt305x_switch_softc *sc; + int idx = -1; + uint32_t reg; + + sc = device_get_softc(dev); + reg = READ4(sc, RT_SW_ATS); +#ifdef notyet + reg = READ4(sc, RT_SW_ATS0); + reg = READ4(sc, RT_SW_ATS1); + reg = READ4(sc, RT_SW_ATS2); +#endif + + return (idx); +} + +static int +mac_table_write(device_t dev, uint64_t mac, int idx, uint32_t port_map, + uint8_t age, int *hash_idx ) +{ + struct rt305x_switch_softc *sc = device_get_softc(dev); + uint32_t reg; + + WRITE4(sc, RT_SW_WMAD1, (uint32_t)mac & 0xffff); + WRITE4(sc, RT_SW_WMAD2, (uint32_t)(mac >> 16) & 0xffffffff); + + reg = READ4(sc, RT_SW_WMAD0); + +/*XXX test !(reg & W_MAC_CMD)*/ + + WRITE4(sc, RT_SW_WMAD0, + ((port_map << WMAD0_W_PORT_MAP_SHIFT) & WMAD0_W_PORT_MAP_MASK) | + ((idx << WMAD0_W_INDEX_SHIFT) & WMAD0_W_INDEX_MASK) | + ((age << WMAD0_W_AGE_FLD_SHIFT) & WMAD0_W_AGE_FLD_MASK) | + WMAD0_W_MC_INGRESS | WMAD0_W_MAC_CMD); + +/*XXX test !(reg & W_MAC_CMD) && reg & W_MAC_DONE*/ + + return (0); +} + +static int +set_port_vid(device_t dev, int port, uint16_t pvid) +{ + struct rt305x_switch_softc *sc = device_get_softc(dev); + uint32_t reg; + + if (port > (sc->ports - 1)) + return (EINVAL); + + reg = READ4(sc, RT_SW_PVIDC0 + port / 2 * 4); + reg &= ~(0xfff << (12 * (port % 2))); + reg |= (0xfff & pvid) << (12 * (port % 2)); + WRITE4(sc, RT_SW_PVIDC0 + port / 2 * 4, reg); + + return (0); +} + +static int +get_port_vid(device_t dev, int port, uint16_t *pvid) +{ + struct rt305x_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (port > (sc->ports - 1)) + return (EINVAL); + + reg = READ4(sc, RT_SW_PVIDC0 + port / 2 * 4); + + *pvid = (reg >> (12 * (port % 2))) & 0xfff; + return (0); +} + +static int +get_port_flags(device_t dev, int port, uint32_t *flags) +{ + struct rt305x_switch_softc *sc; + uint32_t reg = 0; + + *flags = 0; + sc = device_get_softc(dev); + if (port > (sc->ports - 1)) + return (EINVAL); + + reg = READ4(sc, RT_SW_SGC2); + *flags |= (reg & (1 << port))?DOT1Q_VLAN_PORT_FLAG_DOUBLE_TAG:0; + *flags |= (reg & (1 << (port+24)))? + DOT1Q_VLAN_PORT_FLAG_LAN:DOT1Q_VLAN_PORT_FLAG_WAN; + + reg = READ4(sc, RT_SW_POC2); + *flags |= (reg & (1 << port))?DOT1Q_VLAN_PORT_FLAG_UNTAGGED: + DOT1Q_VLAN_PORT_FLAG_UNTAGGED; + + return (0); +} + +static int +set_port_flags(device_t dev, int port, uint32_t flags) +{ + struct rt305x_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (port > (sc->ports - 1)) + return (EINVAL); + + reg = READ4(sc, RT_SW_POC2); + if (flags & DOT1Q_VLAN_PORT_FLAG_TAGGED) { + reg &= ~(1 << port); + } else if (flags & DOT1Q_VLAN_PORT_FLAG_UNTAGGED) { + reg |= (1 << port); + } + WRITE4(sc, RT_SW_POC2, reg); + + /* Q-in-Q */ + reg = READ4(sc, RT_SW_SGC2); + if (flags & DOT1Q_VLAN_PORT_FLAG_DOUBLE_TAG) + reg |= (1 << port); + else + reg &= ~(1 << port); + + /* LAN/WAN */ + if (flags & DOT1Q_VLAN_PORT_FLAG_LAN) + reg |= (1 << (port+24)); + /* Reset to WAN port type only if WAN specified */ + else if (flags & DOT1Q_VLAN_PORT_FLAG_WAN) + reg &= ~(1 << (port+24)); + + WRITE4(sc, RT_SW_SGC2, reg); + + return (0); +} + +static int +set_vid(device_t dev, int idx, uint16_t vid) +{ + struct rt305x_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (idx > (sc->vlans - 1)) + return (EINVAL); + + reg = READ4(sc, RT_SW_VID0 + idx / 2 * 4); + reg &= ~(0xfff << (12 * (idx % 2))); + reg |= (0xfff & vid) << (12 * (idx % 2)); + WRITE4(sc, RT_SW_VID0 + idx / 2 * 4, reg); + + return (0); +} + +static int +get_vid(device_t dev, int idx, uint16_t *vid) +{ + struct rt305x_switch_softc *sc = device_get_softc(dev); + uint32_t reg; + + if (idx > (sc->vlans - 1)) + return (EINVAL); + + reg = READ4(sc, RT_SW_VID0 + idx / 2 * 4); + + *vid = (reg >> (12 * (idx % 2))) & 0xfff; + return (0); +} + +static int +set_vlan_ports(device_t dev, int idx, uint32_t memb) +{ + struct rt305x_switch_softc *sc = device_get_softc(dev); + uint32_t reg; + + printf("%s: idx=%d, memb=%08x\n", __func__, idx, memb); + + if (idx > (sc->vlans - 1)) + return (EINVAL); + if (memb & (((1 << sc->ports) - 1) << sc->ports)) + return (EINVAL); + + reg = READ4(sc, RT_SW_VMSC0 + (idx & ~0x03)); + reg &= ~(((1 << sc->ports) - 1) << (8 * (idx % 4))); + reg |= (memb & ((1 << sc->ports) - 1)) << (8 * (idx % 4)); + WRITE4(sc, RT_SW_VMSC0 + (idx & ~0x03), reg); + + return (0); +} + +static int +get_vlan_ports(device_t dev, int idx, uint32_t *memb) +{ + struct rt305x_switch_softc *sc = device_get_softc(dev); + uint32_t reg; + + if (idx > (sc->vlans - 1)) + return (EINVAL); + + reg = READ4(sc, RT_SW_VMSC0 + (idx & ~0x03)); + reg = (reg >> (8 * (idx % 4))) & ((1 << sc->ports) - 1); + + printf("%s: idx=%d, memb=%08x\n", __func__, idx, reg); + *memb = reg; + return (0); +} + +#if 0 +/* Use global tagging option */ +static int +set_vlan_untagged_ports(device_t dev, int idx, uint32_t memb) +{ + struct rt305x_switch_softc *sc = device_get_softc(dev); + uint32_t reg; + + printf("%s: idx=%d, memb=%08x\n", __func__, idx, memb); + + if (idx > (sc->vlans - 1)) + return (EINVAL); + if (memb & ~((1 << sc->ports) - 1)) + return (EINVAL); + + /* RT305XF support only global port untaged flags */ + reg = READ4(sc, RT_SW_POC2); + reg &= ~((1 << sc->ports) - 1); + reg |= (((1 << sc->ports) - 1) & memb); + WRITE4(sc, RT_SW_POC2, reg); + + return (0); +} + +static uint32_t +get_vlan_untagged_ports(device_t dev, int idx, uint32_t *memb) +{ + struct rt305x_switch_softc *sc = device_get_softc(dev); + uint32_t reg; + + if (idx > (sc->vlans - 1)) + return (EINVAL); + + /* RT305XF support only global port untaged flags */ + reg = READ4(sc, RT_SW_POC2); + reg &= ((1 << sc->ports) - 1); + + printf("%s: idx=%d, memb=%08x\n", __func__, idx, reg); + *memb = reg; + return (0); +} +#endif + +static int +get_port_link(device_t dev, int port) +{ + struct rt305x_switch_softc *sc = device_get_softc(dev); + int link; + + if (port > (sc->ports - 1)) + return (-1); + + link = READ4(sc, RT_SW_POA) >> 25; + link = (link >> port) & 1; + + return (link); +} + +static int +get_port_speed(device_t dev, int port) +{ + struct rt305x_switch_softc *sc = device_get_softc(dev); + uint32_t link, fdx; + + link = READ4(sc, RT_SW_POA); + + fdx = (link & (1 << (port + 9)))?IFM_FDX:IFM_HDX; + + if (port < 5) + return ((((link >> port) & 1)?IFM_100_TX:IFM_10_T) | fdx); + + /* GDMA0 */ + if (port == 5) + link = (link >> 5) & 0x03; + + /* GDMA1 */ + if (port == 6) + link = (link >> 7) & 0x03; + + if (link == 2) + return (IFM_1000_T | fdx); + + if (link == 1) + return (IFM_100_TX | fdx); + + return (IFM_10_T | fdx); +} + +static int +force_port_mode(device_t dev, int port, uint32_t mode) +{ + struct rt305x_switch_softc *sc = device_get_softc(dev); + uint32_t reg = READ4(sc, RT_SW_FPA); + + if (port > (sc->ports - 2/* MII */ - 1)) + return (1); + + reg &= ~(((1 << 27) | (1 << 22) | (1 << 16) | (1 << 8) | 1) << port); + + switch (IFM_SUBTYPE(mode)) { + case IFM_10_T: + /* Already zero */ + break; + case IFM_100_TX: + reg |= (1 << port); + break; + default: + //error unsupported media + return (1); + } + + switch (mode & IFM_GMASK) { + case IFM_FDX: + reg |= (1 << port) << 8; + break; + case IFM_HDX: + /* Already zero */ + break; + case IFM_FLOW: + reg |= (1 << port) << 16; + break; + case IFM_FLAG0: /* XXX: Used as enable force mode */ + reg |= (1 << port) << 27; + break; + case IFM_FLAG1: /* XXX: Used as force link */ + reg |= (1 << port) << 22; + break; + case IFM_FLAG2: + break; + case IFM_LOOP: + break; + } + + WRITE4(sc, RT_SW_FPA, reg); + + return (0); +} + +static uint32_t +stat_good_in_packet_count(device_t dev, int port) +{ + struct rt305x_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (port < 6) { + reg = READ4(sc, RT_SW_P0PC); + reg &= GOOD_PCOUNT_MASK; + reg >>= GOOD_PCOUNT_SHIFT; + return (reg); + } + + if (port < 7) { + reg = READ4(sc, RT_SW_PPC); + reg >>= SW2FE_CNT_SHIFT; + return (reg & 0xffff); + } + + return (~0); +} + +static uint32_t +stat_good_out_packet_count(device_t dev, int port) +{ + struct rt305x_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (port < 6) { + /* PHY ports have only sum couters */ + reg = READ4(sc, RT_SW_P0PC); + reg &= GOOD_PCOUNT_MASK; + reg >>= GOOD_PCOUNT_SHIFT; + return (reg); + } + + if (port < 7) { + reg = READ4(sc, RT_SW_PPC); + reg >>= FE2SW_CNT_SHIFT; + return (reg & 0xffff); + } + + return (~0); +} + +static uint32_t +stat_bad_in_packet_count(device_t dev, int port) +{ + struct rt305x_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (port < 6) { + reg = READ4(sc, RT_SW_P0PC); + reg &= BAD_PCOUNT_MASK; + reg >>= BAD_PCOUNT_SHIFT; + return (reg); + } + + if (port < 7) { + /* Port 6 always good :) */ + return (0); + } + + return (~0); +} + +static uint32_t +stat_bad_out_packet_count(device_t dev, int port) +{ + struct rt305x_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (port < 6) { + /* PHY ports have only sum couters */ + reg = READ4(sc, RT_SW_P0PC); + reg &= BAD_PCOUNT_MASK; + reg >>= BAD_PCOUNT_SHIFT; + return (reg); + } + + if (port < 7) { + /* Port 6 always good :) */ + return (0); + } + + return (~0); +} + +static device_method_t rt305x_switch_methods[] = { + DEVMETHOD(device_probe, rt305x_switch_probe), + DEVMETHOD(device_attach, rt305x_switch_attach), + DEVMETHOD(device_detach, rt305x_switch_detach), + + /* Capability */ + DEVMETHOD(switch_get_caps, get_caps), + + /* MAC address table */ + DEVMETHOD(switch_find_mac, find_mac_addr), + DEVMETHOD(switch_mac_write, mac_table_write), + + /* 802.1q */ + DEVMETHOD(switch_set_pvid, set_port_vid), + DEVMETHOD(switch_get_pvid, get_port_vid), + DEVMETHOD(switch_set_pflags, set_port_flags), + DEVMETHOD(switch_get_pflags, get_port_flags), + DEVMETHOD(switch_set_vid, set_vid), + DEVMETHOD(switch_get_vid, get_vid), + DEVMETHOD(switch_set_vlanports, set_vlan_ports), + DEVMETHOD(switch_get_vlanports, get_vlan_ports), +// DEVMETHOD(switch_set_vlanutports, set_vlan_untagged_ports), +// DEVMETHOD(switch_get_vlanutports, get_vlan_untagged_ports), + + /* Port state */ + DEVMETHOD(switch_get_portlink, get_port_link), + DEVMETHOD(switch_get_portspeed, get_port_speed), + DEVMETHOD(switch_force_mode, force_port_mode), + + /* Statistics */ + DEVMETHOD(switch_good_in_cnt, stat_good_in_packet_count), + DEVMETHOD(switch_good_out_cnt, stat_good_out_packet_count), + DEVMETHOD(switch_bad_in_cnt, stat_bad_in_packet_count), + DEVMETHOD(switch_bad_out_cnt, stat_bad_out_packet_count), + + {0, 0}, +}; + +static driver_t rt305x_switch_driver = { + "rt305x_switch", + rt305x_switch_methods, + sizeof(struct rt305x_switch_softc), +}; +static devclass_t rt305x_switch_devclass; + +DRIVER_MODULE(rt305x_switch, switch, rt305x_switch_driver, rt305x_switch_devclass, 0, 0); +MODULE_VERSION(rt305x_switch, 1); +MODULE_DEPEND(rt305x_switch, switch, 1, 1, 1); + Property changes on: sys/dev/switch/rt305x_switch.c ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/dev/switch/ar8x16_switchvar.h =================================================================== --- sys/dev/switch/ar8x16_switchvar.h (revision 0) +++ sys/dev/switch/ar8x16_switchvar.h (revision 0) @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 2010 Aleksandr Rybalko. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _AR8X16_SWITCHVAR_H_ +#define _AR8X16_SWITCHVAR_H_ + +struct ar8x16_switch_softc { + device_t sc_dev; + device_t parent; + int ports; + int vlans; + struct switch_capability *caps; + int page_reg; + int page_phy; + int devid; + int revid; + uint32_t sc_mii_mode; + uint16_t *vlan_idx; +}; + +/* Ask switch bus to read/write device registers */ +#define MII_SW_READ4(_sc, _reg) \ + SWITCHB_READ4(_sc->parent, _reg) + +#define MII_SW_WRITE4(_sc, _reg, _val) \ + SWITCHB_WRITE4(_sc->parent, _reg, _val) + +/* Ask switch bus to read/write phy registers */ +#define MII_READ(sc, phy, reg) \ + MII_SW_READ4(sc, (((phy) << 8) | (reg))) +#define MII_WRITE(sc, phy, reg, val) \ + MII_SW_WRITE4(sc, (((phy) << 8) | (reg)), val) + +#define REG_REG(reg) (((reg) >> 1) & 0x01e) +#define REG_PHY(reg) (((reg) >> 6) & 0x007) +#define REG_PAGE(reg) (((reg) >> 9) & 0x1ff) +#define VLAN_IDX_VALID 0x8000 + +#define SET4(sc, reg, mask, val) \ + WRITE4(sc, reg, (READ4(sc, reg) & ~mask) | val) + +#define WAIT4(sc, reg, field, value, timeout_usec) \ + ({int result; \ + do { \ + uint32_t c, timeout = timeout_usec; \ + while (1) { \ + c = (READ4(sc, reg) & field); \ + if (c == (value)) { \ + result = 0; \ + break; \ + } else if (!timeout) { \ + result = -1; \ + break; \ + } else { \ + DELAY(1); timeout--; \ + } \ + } \ + } while (0); \ + result;}) + +#endif /* _AR8X16_SWITCHVAR_H_ */ Property changes on: sys/dev/switch/ar8x16_switchvar.h ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/dev/switch/switch_if.m =================================================================== --- sys/dev/switch/switch_if.m (revision 0) +++ sys/dev/switch/switch_if.m (revision 0) @@ -0,0 +1,345 @@ +#- +# Copyright (c) 2011 Aleksandr Rybalko +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +#include +#include +#include + +INTERFACE switch; + +CODE { + static struct switch_capability * + null_get_caps(device_t dev) + { + return (0); + } + + static int + null_get_reg(device_t dev, uint32_t reg, uint32_t *value) + { + return (0); + } + + static int + null_set_reg(device_t dev, uint32_t reg, uint32_t *value) + { + return (0); + } + + static int + null_find_mac(device_t dev, uint64_t mac) + { + return (0); + } + + static int + null_mac_write (device_t dev, uint64_t mac, int index, uint32_t port_map, uint8_t age, int *hash_idx) + { + return (0); + } + + static int + null_set_port_vid (device_t dev, int port, uint16_t pvid) + { + return (0); + } + + static int + null_get_port_vid (device_t dev, int port, uint16_t *pvid) + { + return (0); + } + + static int + null_set_port_flags (device_t dev, int port, uint32_t flags) + { + return (0); + } + + static int + null_get_port_flags (device_t dev, int port, uint32_t *flags) + { + return (0); + } + + static int + null_set_vid (device_t dev, int index, uint16_t vid) + { + return (0); + } + + static int + null_get_vid (device_t dev, int index, uint16_t *vid) + { + return (0); + } + + static int + null_set_vlanports (device_t dev, int index, uint32_t members) + { + return (0); + } + + static int + null_get_vlanports (device_t dev, int index, uint32_t *members) + { + return (0); + } + + static int + null_get_portlink (device_t dev, int port) + { + return (0); + } + + static int + null_get_portspeed (device_t dev, int port) + { + return (0); + } + + static int + null_force_mode (device_t dev, int port, uint32_t mode) + { + return (0); + } + + static uint32_t + null_stat (device_t dev, int port) + { + return (0); + } + + static void + null_tick (device_t dev) + { + + } + +}; + +# +# Get number of ports on this switch +# +METHOD struct switch_capability * get_caps { + device_t dev; +} DEFAULT null_get_caps; + +# +# Get switch register value +# +METHOD int get_reg { + device_t dev; + uint32_t reg; + uint32_t *value; +} DEFAULT null_get_reg; + +# +# Set switch register value, return old value +# +METHOD int set_reg { + device_t dev; + uint32_t reg; + uint32_t *value; +} DEFAULT null_set_reg; + +# +# Get MAC address table index of this MAC +# +METHOD int find_mac { + device_t dev; + uint64_t mac; +} DEFAULT null_find_mac; + +# +# Write MAC address into table +# +METHOD int mac_write { + device_t dev; + uint64_t mac; + int index; + uint32_t port_map; + uint8_t age; + int *hash_idx; +} DEFAULT null_mac_write; + +# +# Set Port VID +# +METHOD int set_pvid { + device_t dev; + int port; + uint16_t pvid; +} DEFAULT null_set_port_vid; + +# +# Get Port VID +# +METHOD int get_pvid { + device_t dev; + int port; + uint16_t *pvid; +} DEFAULT null_get_port_vid; + +# +# Set Port VLAN flags +# +METHOD int set_pflags { + device_t dev; + int port; + uint32_t flags; +} DEFAULT null_set_port_flags; + +# +# Get Port VLAN flags +# +METHOD int get_pflags { + device_t dev; + int port; + uint32_t *flags; +} DEFAULT null_get_port_flags; + +# +# Set VID for VLAN with that index +# +METHOD int set_vid { + device_t dev; + int index; + uint16_t vid; +} DEFAULT null_set_vid; + +# +# Get VID of VLAN with that index +# +METHOD int get_vid { + device_t dev; + int index; + uint16_t *vid; +} DEFAULT null_get_vid; + +# +# Set VLAN member ports +# +METHOD int set_vlanports { + device_t dev; + int index; + uint32_t members; +} DEFAULT null_set_vlanports; + +# +# Set VLAN member ports +# +METHOD int get_vlanports { + device_t dev; + int index; + uint32_t *members; +} DEFAULT null_get_vlanports; + +# +# Set VLAN untagged member ports +# +METHOD int set_vlanutports { + device_t dev; + int index; + uint32_t members; +} DEFAULT null_set_vlanports; + +# +# Get VLAN untagged member ports +# +METHOD int get_vlanutports { + device_t dev; + int index; + uint32_t *members; +} DEFAULT null_get_vlanports; + +# +# Get port link status +# +METHOD int get_portlink { + device_t dev; + int port; +} DEFAULT null_get_portlink; + +# +# Get port speed +# +METHOD int get_portspeed { + device_t dev; + int port; +} DEFAULT null_get_portspeed; + +# +# Get force required mode +# +METHOD int force_mode { + device_t dev; + int port; + uint32_t mode; +} DEFAULT null_force_mode; + +# +# Get count of good packets on port input +# +METHOD uint32_t good_in_cnt { + device_t dev; + int port; +} DEFAULT null_stat; + +# +# Get count of good packets on port output +# +METHOD uint32_t good_out_cnt { + device_t dev; + int port; +} DEFAULT null_stat; + +# +# Get count of bad packets on port input +# +METHOD uint32_t bad_in_cnt { + device_t dev; + int port; +} DEFAULT null_stat; + +# +# Get count of bad packets on port output +# +METHOD uint32_t bad_out_cnt { + device_t dev; + int port; +} DEFAULT null_stat; + +# +# Give a chance to update something +# +METHOD void tick { + device_t dev; +} DEFAULT null_tick; + + Index: sys/dev/switch/rt305x_switchreg.h =================================================================== --- sys/dev/switch/rt305x_switchreg.h (revision 0) +++ sys/dev/switch/rt305x_switchreg.h (revision 0) @@ -0,0 +1,174 @@ +/*- + * Copyright (c) 2010 Aleksandr Rybalko. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _RT305X_SWITCHREG_H_ +#define _RT305X_SWITCHREG_H_ + +/* XXX: must move to config */ +#define RT3052F + +#define RT_SW_BASE 0x10110000 + +#define RT_SW_ISR 0x00 + +#define WATCHDOG1_TMR_EXPIRED (1<<29) +#define WATCHDOG0_TMR_EXPIRED (1<<28) +#define HAS_INTRUDER (1<<27) +#define PORT_ST_CHG (1<<26) +#define BC_STORM (1<<25) +#define MUST_DROP_LAN (1<<24) +#define GLOBAL_QUE_FULL (1<<23) +#define LAN_QUE_FULL6 (1<<20) +#define LAN_QUE_FULL5 (1<<19) +#define LAN_QUE_FULL4 (1<<18) +#define LAN_QUE_FULL3 (1<<17) +#define LAN_QUE_FULL2 (1<<16) +#define LAN_QUE_FULL1 (1<<15) +#define LAN_QUE_FULL0 (1<<14) + +#define RT_SW_IMR 0x04 + +#define RT_SW_FCT0 0x08 +#define RT_SW_FCT1 0x0c +#define RT_SW_PFC0 0x10 +#define RT_SW_PFC1 0x14 +#define RT_SW_PFC2 0x18 +#define RT_SW_GQS0 0x1c +#define RT_SW_GQS1 0x20 +#define RT_SW_ATS 0x24 +#define RT_SW_ATS0 0x28 +#define RT_SW_ATS1 0x2c +#define RT_SW_ATS2 0x30 +#define RT_SW_WMAD0 0x34 +#define WMAD0_HASH_ADD_CFG_SHIFT 22 +#define WMAD0_HASH_ADD_CFG_MASK 0xffc00000 +#define WMAD0_AT_CFG_IDLE (1<<19) +#define WMAD0_W_PORT_MAP_SHIFT 12 +#define WMAD0_W_PORT_MAP_MASK 0x0007f000 +#define WMAD0_W_INDEX_SHIFT 7 +#define WMAD0_W_INDEX_MASK 0x00000780 +#define WMAD0_W_AGE_FLD_SHIFT 4 +#define WMAD0_W_AGE_FLD_MASK 0x00000070 +#define WMAD0_W_MC_INGRESS (1<<2) +#define WMAD0_W_MAC_DONE (1<<1) +#define WMAD0_W_MAC_CMD (1<<0) + + +#define RT_SW_WMAD1 0x38 +#define RT_SW_WMAD2 0x3c +#define RT_SW_PVIDC0 0x40 +#define RT_SW_PVIDC1 0x44 +#define RT_SW_PVIDC2 0x48 +#define RT_SW_PVIDC3 0x4c +#define RT_SW_VID0 0x50 +#define RT_SW_VID1 0x54 +#define RT_SW_VID2 0x58 +#define RT_SW_VID3 0x5c +#define RT_SW_VID4 0x60 +#define RT_SW_VID5 0x64 +#define RT_SW_VID6 0x68 +#define RT_SW_VID7 0x6c +#define RT_SW_VMSC0 0x70 +#define RT_SW_VMSC1 0x74 +#define RT_SW_VMSC2 0x78 +#define RT_SW_VMSC3 0x7c +#define RT_SW_POA 0x80 +#define RT_SW_FPA 0x84 +#define RT_SW_PTS 0x88 +#define RT_SW_SOCPC 0x8c +#define RT_SW_POC0 0x90 +#define RT_SW_POC1 0x94 +#define RT_SW_POC2 0x98 +#define RT_SW_SGC 0x9c +#define RT_SW_STRT 0xa0 +#define RT_SW_LEDP0 0xa4 +#define RT_SW_LEDP1 0xa8 +#define RT_SW_LEDP2 0xac +#define RT_SW_LEDP3 0xb0 +#define RT_SW_LEDP4 0xb4 +#define RT_SW_WDTR 0xb8 +#define RT_SW_DES 0xbc +#define RT_SW_PCR0 0xc0 +#define RT_SW_PCR1 0xc4 +#define RT_SW_FPA56 0xc8 +#define RT_SW_FCT2 0xcc +#define RT_SW_QSS0 0xd0 + +#define RT_SW_QSS1 0xd4 +#define RT_SW_DEC 0xd8 +#define BRIDGE_IPG_SHIFT 24 +#define DEBUG_SW_PORT_SEL_SHIFT 3 +#define DEBUG_SW_PORT_SEL_MASK 0x00000038 + +#define RT_SW_MTI 0xdc +#define SKIP_BLOCKS_SHIFT 7 +#define SKIP_BLOCKS_MASK 0x0000ff80 +#define SW_RAM_TEST_DONE (1<<6) +#define AT_RAM_TEST_DONE (1<<5) +#define AT_RAM_TEST_FAIL (1<<4) +#define LK_RAM_TEST_DONE (1<<3) +#define LK_RAM_TEST_FAIL (1<<2) +#define DT_RAM_TEST_DONE (1<<1) +#define DT_RAM_TEST_FAIL (1<<0) + +#define RT_SW_PPC 0xe0 +#define SW2FE_CNT_SHIFT 16 +#define FE2SW_CNT_SHIFT 0 + +#define RT_SW_SGC2 0xe4 +#define FE2SW_WL_FC_EN (1<<30) +#define LAN_PMAP_P0_IS_LAN (1<<24) +#define LAN_PMAP_P1_IS_LAN (1<<25) +#define LAN_PMAP_P2_IS_LAN (1<<26) +#define LAN_PMAP_P3_IS_LAN (1<<27) +#define LAN_PMAP_P4_IS_LAN (1<<28) +#define LAN_PMAP_P5_IS_LAN (1<<29) +/* Transmit CPU TPID(810x) port bit map */ +#define TX_CPU_TPID_BIT_MAP_SHIFT 16 +#define TX_CPU_TPID_BIT_MAP_MASK 0x007f0000 +#define ARBITER_LAN_EN (1<<11) +#define CPU_TPID_EN (1<<10) +#define P0_DOUBLE_TAG_EN (1<<0) +#define P1_DOUBLE_TAG_EN (1<<1) +#define P2_DOUBLE_TAG_EN (1<<2) +#define P3_DOUBLE_TAG_EN (1<<3) +#define P4_DOUBLE_TAG_EN (1<<4) +#define P5_DOUBLE_TAG_EN (1<<5) + +#define RT_SW_P0PC 0xe8 +#define RT_SW_P1PC 0xec +#define RT_SW_P2PC 0xf0 +#define RT_SW_P3PC 0xf4 +#define RT_SW_P4PC 0xf8 +#define RT_SW_P5PC 0xfc +#define BAD_PCOUNT_SHIFT 16 +#define BAD_PCOUNT_MASK 0xffff0000 +#define GOOD_PCOUNT_SHIFT 0 +#define GOOD_PCOUNT_MASK 0x0000ffff + +#endif /* _RT305X_SWITCHREG_H_ */ Property changes on: sys/dev/switch/rt305x_switchreg.h ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native Index: sys/dev/switch/switchb_if.m =================================================================== --- sys/dev/switch/switchb_if.m (revision 0) +++ sys/dev/switch/switchb_if.m (revision 0) @@ -0,0 +1,123 @@ +#- +# Copyright (c) 2011 Aleksandr Rybalko +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +#include + +INTERFACE switchb; + +CODE { + static uint16_t + null_reg_get(device_t dev, uint16_t reg) + { + return (0); + } + + static void + null_reg_set(device_t dev, uint16_t reg, uint16_t val) + { + return; + } + + static uint32_t + null_read4(device_t parent, uint32_t reg) + { + return (0); + } + + static void + null_write4(device_t parent, uint32_t reg, uint32_t val) + { + return; + } + + static int + null_register_isr(device_t dev, driver_filter_t isr, device_t child) + { + return (0); + } + + static void + null_unregister_isr(device_t dev, device_t child) + { + return; + } + +}; + +# +# Get switch register value +# +METHOD uint16_t reg_get { + device_t dev; + uint16_t reg; +} DEFAULT null_reg_get; + +# +# Set switch register value +# +METHOD void reg_set { + device_t dev; + uint16_t reg; + uint16_t value; +} DEFAULT null_reg_set; + +# +# Read switch memory mapped reg +# +METHOD uint32_t read4 { + device_t parent; + uint32_t reg; +} DEFAULT null_read4; + +# +# Write switch memory mapped reg +# +METHOD void write4 { + device_t parent; + uint32_t reg; + uint32_t value; +} DEFAULT null_write4; + +# +# Register ISR +# +METHOD int register_isr { + device_t dev; + driver_filter_t isr; + device_t child; +} DEFAULT null_register_isr; + +# +# UnRegister ISR +# +METHOD void unregister_isr { + device_t dev; + device_t child; +} DEFAULT null_unregister_isr; + + Index: sys/dev/switch/template_switch.c =================================================================== --- sys/dev/switch/template_switch.c (revision 0) +++ sys/dev/switch/template_switch.c (revision 0) @@ -0,0 +1,562 @@ +/*- + * Copyright (c) 2010 Aleksandr Rybalko. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include + +#include "switch_if.h" +#include "switchb_if.h" + +/* TODO */ +static int find_mac_addr(device_t dev, uint64_t mac); +/* TODO */ +static int mac_table_write(device_t dev, uint64_t mac, int idx, + uint32_t port_map, uint8_t age, int *hash_idx ); + +static int get_reg(device_t dev, uint32_t reg, uint32_t *value); +static int set_reg(device_t dev, uint32_t reg, uint32_t *value); +static int set_port_vid(device_t dev, int port, uint16_t pvid); +static int get_port_vid(device_t dev, int port, uint16_t *pvid); +static int set_vid(device_t dev, int idx, uint16_t vid); +static int get_vid(device_t dev, int idx, uint16_t *vid); +static int set_vlan_ports(device_t dev, int idx, uint32_t memb); +static int get_vlan_ports(device_t dev, int idx, uint32_t *memb); + +static int get_port_link(device_t dev, int port); +static int get_port_speed(device_t dev, int port); +static int force_port_mode(device_t dev, int port, uint32_t mode); + +static uint32_t stat_good_in_packet_count(device_t dev, int port); +static uint32_t stat_good_out_packet_count(device_t dev, int port); +static uint32_t stat_bad_in_packet_count(device_t dev, int port); +static uint32_t stat_bad_out_packet_count(device_t dev, int port); + + +static int TEMPLATE_switch_isr(void *arg); + +static int +TEMPLATE_switch_probe(device_t dev) +{ + struct child_res_avl *res; + + res = device_get_ivars(dev); + + /* If we use memory window, check size */ + if (res->memres_size < (RT_SW_P5PC - RT_SW_ISR)) + return (ENXIO); + + /* If we use IRQ, get count */ + if (res->irqs < 1) + return (ENXIO); + +#define MY_PHY_MASK 0x01010101 /* PHY0, PHY8, PHY16, PHY24 */ + /* If we use PHYs, check phys bimap */ + if ((res->phys & MY_PHY_MASK) == MY_PHY_MASK) + return (ENXIO); + + device_set_desc(dev, "TEMPLATE ethernet switch"); + return (BUS_PROBE_DEFAULT); +} + +static int +TEMPLATE_switch_attach(device_t dev) +{ + struct TEMPLATE_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + sc->parent = device_get_parent(dev); + + /* Some test, if fail return (ENXIO); */ + + sc->caps = malloc(sizeof(struct switch_capability), M_DEVBUF, + M_WAITOK | M_ZERO); + + if (!sc->caps) + return (ENXIO); + + sc->caps->ports = sc->ports = 7; /* Ports switch have */ + sc->vlans = 16; /* VLANs count */ + sc->sc_dev = dev; + + /* If need IRQ, register to it */ + SWITCHB_REGISTER_ISR(sc->parent, TEMPLATE_switch_isr, dev); + +#define S_C(x) SWITCH_CAPS_ ## x + /* List of caps, see struct switch_caps in switch_ioctl.h*/ + sc->caps->main = S_C(MAIN_PORT_POWER); + sc->caps->vlan = S_C(VLAN_DOT1Q) | + ((sc->vlans << S_C(VLAN_MAX_SHIFT_SHIFT)) & S_C(VLAN_MAX_SHIFT_MASK)); + sc->caps->qos = (2 << S_C(QOS_QUEUES_SHIFT)) & S_C(QOS_QUEUES_MASK); + sc->caps->lacp = 0; /* LACP caps */ + sc->caps->stp = 0; /* STP caps */ + sc->caps->acl = 0; /* ACL caps */ + sc->caps->stat = 0; /* Statistics caps */ +#undef S_C + + /* Initialization */ + +#ifdef TEMPLATE_SWITCH_DEBUG + int i; + for (i = 0; i < 256/* ,ax reg */; i += 4) { + printf("%08x%c", READ4(sc, i), ((i+4)%16)?' ':'\n'); + } +#endif + + return (0); +} + +static int +TEMPLATE_switch_detach(device_t dev) +{ + struct TEMPLATE_switch_softc *sc; + + sc = device_get_softc(dev); + + if (sc->parent) + SWITCHB_UNREGISTER_ISR(sc->parent, dev); + + if (sc->caps) + free(sc->caps, M_DEVBUF); + + return (0); +} + +static int +TEMPLATE_switch_isr(void *arg) +{ + /* Interrup handling */ + return (FILTER_HANDLED); +} + + +/* + * Switch interface methods + */ +static struct switch_capability * +get_caps(device_t dev) +{ + struct TEMPLATE_switch_softc *sc; + + /* Just return capability struct */ + sc = device_get_softc(dev); + + return (sc->caps); +} + +/* TODO */ +static int +find_mac_addr(device_t dev, uint64_t mac) +{ + return (0); +} + +/* TODO */ +static int +mac_table_write(device_t dev, uint64_t mac, int idx, uint32_t port_map, + uint8_t age, int *hash_idx ) +{ + return (0); +} + +static int +get_reg(device_t dev, uint32_t reg, uint32_t *value) +{ + + /* if errors, return (EINVAL) or other errno(2) value */ + /* Upper bit maybe used to decide ask raw register or indirect one */ + if (reg & 0x80000000) { + /* Indirect */ + *value = 0; + else + /* Raw */ + *value = 0; + return (0); +} + +static int +set_reg(device_t dev, uint32_t reg, uint32_t *value) +{ + uint32_t old; + + /* if errors, return (EINVAL) or other errno(2) value */ + /* Upper bit maybe used to decide ask raw register or indirect one */ + if (reg & 0x80000000) { + /* Indirect */ + old = 0; /* save old value */ + /* set new WRITE4(sc, reg, value); */ + } else { + /* Raw */ + old = 0; /* save old value */ + /* set new MII_SW_WRITE4(sc, reg, value); */ + } + + *value = old; + return (0); +} +static int +set_port_vid(device_t dev, int port, uint16_t pvid) +{ + struct TEMPLATE_switch_softc *sc = device_get_softc(dev); + uint32_t reg; + + if (port > (sc->ports - 1)) + return (EINVAL); + + /* Set port VLAN id */ + + return (0); +} + +static int +get_port_vid(device_t dev, int port, uint16_t *pvid) +{ + struct TEMPLATE_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (port > (sc->ports - 1)) + return (EINVAL); + + *pvid = 0; + /* Get port VLAN id */ + return (0); +} + +static int +get_port_flags(device_t dev, int port, uint32_t *flags) +{ + struct TEMPLATE_switch_softc *sc; + uint32_t reg = 0; + + flags = 0; + sc = device_get_softc(dev); + if (port > (sc->ports - 1)) + return (EINVAL); + + /* + * If Q-in-Q enabled + * flags |= DOT1Q_VLAN_PORT_FLAG_DOUBLE_TAG; + * If LAN/WAN mapping enabled + * flags |= DOT1Q_VLAN_PORT_FLAG_LAN or DOT1Q_VLAN_PORT_FLAG_WAN; + * If global tagging + * flags |= DOT1Q_VLAN_PORT_FLAG_UNTAGGED or DOT1Q_VLAN_PORT_FLAG_UNTAGGED; + */ + + return (0); +} + +static int +set_port_flags(device_t dev, int port, uint32_t flags) +{ + struct TEMPLATE_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (port > (sc->ports - 1)) + return (1); + + if (flags & DOT1Q_VLAN_PORT_FLAG_TAGGED) { + /* + * If support global tagging, mark as tagged + * some switch use single tag/untag flag for all VLANS + */ + } else if (flags & DOT1Q_VLAN_PORT_FLAG_UNTAGGED) { + /* untagged */ + } + + if (flags & DOT1Q_VLAN_PORT_FLAG_DOUBLE_TAG) { + /* Enable Q-in-Q on port */ + } else { + /* Disable Q-in-Q on port */ + } + + /* LAN/WAN */ + if (flags & DOT1Q_VLAN_PORT_FLAG_LAN) { + /* If switch support LAN/WAN port mapping, mark as LAN */ + } else if (flags & DOT1Q_VLAN_PORT_FLAG_WAN) { + /* mark as WAN */ + } + + return (0); +} + +static int +set_vid(device_t dev, int idx, uint16_t vid) +{ + struct TEMPLATE_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (idx > (sc->vlans - 1)) + return (1); + + /* Map VID to index `idx` */ + + return (0); +} + +static int +get_vid(device_t dev, int idx, uint16_t *vid) +{ + struct TEMPLATE_switch_softc *sc = device_get_softc(dev); + uint32_t reg; + + if (idx > (sc->vlans - 1)) + return (1); + + /* Get VID of index `idx` */ + + return (0); +} + +static int +set_vlan_ports(device_t dev, int idx, uint32_t memb) +{ + struct TEMPLATE_switch_softc *sc = device_get_softc(dev); + uint32_t reg; + + printf("%s: idx=%d, memb=%08x\n", __func__, idx, memb); + + if (idx > (sc->vlans - 1)) + return (1); + if (memb & (((1 << sc->ports) - 1) << sc->ports)) + return (1); + + /* Set VLAN members */ + + return (0); +} + +static int +get_vlan_ports(device_t dev, int idx, uint32_t *memb) +{ + struct TEMPLATE_switch_softc *sc = device_get_softc(dev); + uint32_t reg; + + if (idx > (sc->vlans - 1)) + return (1); + + /* Get VLAN members */ + + return (0); +} + +/* If switch support per VLAN tagging option */ +static int +set_vlan_untagged_ports(device_t dev, int idx, uint32_t memb) +{ + struct TEMPLATE_switch_softc *sc = device_get_softc(dev); + uint32_t reg; + + printf("%s: idx=%d, memb=%08x\n", __func__, idx, memb); + + if (idx > (sc->vlans - 1)) + return (1); + if (memb & ~((1 << sc->ports) - 1)) + return (1); + + /* Set untagged members */ + + return (0); +} + +static int +get_vlan_untagged_ports(device_t dev, int idx, uint32_t *memb) +{ + struct TEMPLATE_switch_softc *sc = device_get_softc(dev); + uint32_t reg; + + if (idx > (sc->vlans - 1)) + return (1); + + /* Get untagged members */ + + return (0); +} + +static int +get_port_link(device_t dev, int port) +{ + struct TEMPLATE_switch_softc *sc = device_get_softc(dev); + int link; + + if (port > (sc->ports - 1)) + return (-1); + + /* Get port link status */ + + return (link); +} + +static int +get_port_speed(device_t dev, int port) +{ + struct TEMPLATE_switch_softc *sc = device_get_softc(dev); + uint32_t link, fdx; + + /* Get port link info */ + + return (IFM_10_T | IFM_HDX); +} + +static int +force_port_mode(device_t dev, int port, uint32_t mode) +{ + struct TEMPLATE_switch_softc *sc = device_get_softc(dev); + + if (port > (sc->ports - 1)) + return (1); + + /* Force link info */ + + return (0); +} + +static uint32_t +stat_good_in_packet_count(device_t dev, int port) +{ + struct TEMPLATE_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (port > (sc->ports - 1)) + return (~0); + + /* Good packets on input for port */ + + return (0); +} + +static uint32_t +stat_good_out_packet_count(device_t dev, int port) +{ + struct TEMPLATE_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (port > (sc->ports - 1)) + return (~0); + + /* Good packets on output for port */ + + return (~0); +} + +static uint32_t +stat_bad_in_packet_count(device_t dev, int port) +{ + struct TEMPLATE_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (port > (sc->ports - 1)) + return (~0); + + /* Bad packets on input for port */ + + return (~0); +} + +static uint32_t +stat_bad_out_packet_count(device_t dev, int port) +{ + struct TEMPLATE_switch_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + if (port > (sc->ports - 1)) + return (~0); + + /* Bad packets on output for port */ + + return (~0); +} + +static device_method_t TEMPLATE_switch_methods[] = { + DEVMETHOD(device_probe, TEMPLATE_switch_probe), + DEVMETHOD(device_attach, TEMPLATE_switch_attach), + DEVMETHOD(device_detach, TEMPLATE_switch_detach), + + /* Capability */ + DEVMETHOD(switch_get_caps, get_caps), + + /* MAC address table */ + DEVMETHOD(switch_find_mac, find_mac_addr), + DEVMETHOD(switch_mac_write, mac_table_write), + + /* 802.1q */ + DEVMETHOD(switch_set_pvid, set_port_vid), + DEVMETHOD(switch_get_pvid, get_port_vid), + DEVMETHOD(switch_set_pflags, set_port_flags), + DEVMETHOD(switch_get_pflags, get_port_flags), + DEVMETHOD(switch_set_vid, set_vid), + DEVMETHOD(switch_get_vid, get_vid), + DEVMETHOD(switch_set_vlanports, set_vlan_ports), + DEVMETHOD(switch_get_vlanports, get_vlan_ports), + DEVMETHOD(switch_set_vlanutports, set_vlan_untagged_ports), + DEVMETHOD(switch_get_vlanutports, get_vlan_untagged_ports), + + /* Port state */ + DEVMETHOD(switch_get_portlink, get_port_link), + DEVMETHOD(switch_get_portspeed, get_port_speed), + DEVMETHOD(switch_force_mode, force_port_mode), + + /* Statistics */ + DEVMETHOD(switch_good_in_cnt, stat_good_in_packet_count), + DEVMETHOD(switch_good_out_cnt, stat_good_out_packet_count), + DEVMETHOD(switch_bad_in_cnt, stat_bad_in_packet_count), + DEVMETHOD(switch_bad_out_cnt, stat_bad_out_packet_count), + + {0, 0}, +}; + +static driver_t TEMPLATE_switch_driver = { + "TEMPLATE_switch", + TEMPLATE_switch_methods, + sizeof(struct TEMPLATE_switch_softc), +}; +static devclass_t TEMPLATE_switch_devclass; + +DRIVER_MODULE(TEMPLATE_switch, switch, TEMPLATE_switch_driver, TEMPLATE_switch_devclass, 0, 0); +MODULE_VERSION(TEMPLATE_switch, 1); +MODULE_DEPEND(TEMPLATE_switch, switch, 1, 1, 1); + Property changes on: sys/dev/switch/template_switch.c ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + FreeBSD=%H Added: svn:eol-style + native