diff options
author | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2010-06-26 20:42:58 +0000 |
---|---|---|
committer | nbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2010-06-26 20:42:58 +0000 |
commit | c5552ad03973839d83d32d7108f20c00f192633b (patch) | |
tree | de32e4def600e56134cd085a7447cb6620542078 /target/linux/generic-2.6/files/drivers/net/phy | |
parent | 7ec88f88f4c65a22b3b7e32ef87cb42dcb32a6fb (diff) |
rename target/linux/generic-2.6 to generic
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@21952 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/generic-2.6/files/drivers/net/phy')
13 files changed, 0 insertions, 9322 deletions
diff --git a/target/linux/generic-2.6/files/drivers/net/phy/adm6996.c b/target/linux/generic-2.6/files/drivers/net/phy/adm6996.c deleted file mode 100644 index bc40be067..000000000 --- a/target/linux/generic-2.6/files/drivers/net/phy/adm6996.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * ADM6996 switch driver - * - * Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License v2 as published by the - * Free Software Foundation - */ -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/unistd.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/spinlock.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/mii.h> -#include <linux/ethtool.h> -#include <linux/phy.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/uaccess.h> -#include "adm6996.h" - -MODULE_DESCRIPTION("Infineon ADM6996 Switch"); -MODULE_AUTHOR("Felix Fietkau"); -MODULE_LICENSE("GPL"); - -struct adm6996_priv { - /* use abstraction for regops, we want to add gpio support in the future */ - u16 (*read)(struct phy_device *phydev, enum admreg reg); - void (*write)(struct phy_device *phydev, enum admreg reg, u16 val); -}; - -#define to_adm(_phy) ((struct adm6996_priv *) (_phy)->priv) - - -static inline u16 -r16(struct phy_device *pdev, enum admreg reg) -{ - return to_adm(pdev)->read(pdev, reg); -} - -static inline void -w16(struct phy_device *pdev, enum admreg reg, u16 val) -{ - to_adm(pdev)->write(pdev, reg, val); -} - - -static u16 -adm6996_read_mii_reg(struct phy_device *phydev, enum admreg reg) -{ - return phydev->bus->read(phydev->bus, PHYADDR(reg)); -} - -static void -adm6996_write_mii_reg(struct phy_device *phydev, enum admreg reg, u16 val) -{ - phydev->bus->write(phydev->bus, PHYADDR(reg), val); -} - - -static int adm6996_config_init(struct phy_device *pdev) -{ - int i; - - printk("%s: ADM6996 PHY driver attached.\n", pdev->attached_dev->name); - pdev->supported = ADVERTISED_100baseT_Full; - pdev->advertising = ADVERTISED_100baseT_Full; - - /* initialize port and vlan settings */ - for (i = 0; i < ADM_PHY_PORTS; i++) { - w16(pdev, adm_portcfg[i], ADM_PORTCFG_INIT | - ADM_PORTCFG_PVID((i == ADM_WAN_PORT) ? 1 : 0)); - } - w16(pdev, adm_portcfg[5], ADM_PORTCFG_CPU); - - /* reset all ports */ - for (i = 0; i < ADM_PHY_PORTS; i++) { - w16(pdev, ADM_PHY_PORT(i), ADM_PHYCFG_INIT); - } - - return 0; -} - -static int adm6996_read_status(struct phy_device *phydev) -{ - phydev->speed = SPEED_100; - phydev->duplex = DUPLEX_FULL; - phydev->link = 1; - return 0; -} - -static int adm6996_config_aneg(struct phy_device *phydev) -{ - return 0; -} - -static int adm6996_fixup(struct phy_device *dev) -{ - struct mii_bus *bus = dev->bus; - u16 reg; - - /* look for the switch on the bus */ - reg = bus->read(bus, PHYADDR(ADM_SIG0)) & ADM_SIG0_MASK; - if (reg != ADM_SIG0_VAL) - return 0; - - reg = bus->read(bus, PHYADDR(ADM_SIG1)) & ADM_SIG1_MASK; - if (reg != ADM_SIG1_VAL) - return 0; - - dev->phy_id = (ADM_SIG0_VAL << 16) | ADM_SIG1_VAL; - return 0; -} - -static int adm6996_probe(struct phy_device *pdev) -{ - struct adm6996_priv *priv; - - priv = kzalloc(sizeof(struct adm6996_priv), GFP_KERNEL); - if (priv == NULL) - return -ENOMEM; - - priv->read = adm6996_read_mii_reg; - priv->write = adm6996_write_mii_reg; - pdev->priv = priv; - return 0; -} - -static void adm6996_remove(struct phy_device *pdev) -{ - kfree(pdev->priv); -} - - -static struct phy_driver adm6996_driver = { - .name = "Infineon ADM6996", - .phy_id = (ADM_SIG0_VAL << 16) | ADM_SIG1_VAL, - .phy_id_mask = 0xffffffff, - .features = PHY_BASIC_FEATURES, - .probe = adm6996_probe, - .remove = adm6996_remove, - .config_init = &adm6996_config_init, - .config_aneg = &adm6996_config_aneg, - .read_status = &adm6996_read_status, - .driver = { .owner = THIS_MODULE,}, -}; - -static int __init adm6996_init(void) -{ - phy_register_fixup_for_id(PHY_ANY_ID, adm6996_fixup); - return phy_driver_register(&adm6996_driver); -} - -static void __exit adm6996_exit(void) -{ - phy_driver_unregister(&adm6996_driver); -} - -module_init(adm6996_init); -module_exit(adm6996_exit); diff --git a/target/linux/generic-2.6/files/drivers/net/phy/adm6996.h b/target/linux/generic-2.6/files/drivers/net/phy/adm6996.h deleted file mode 100644 index e07490151..000000000 --- a/target/linux/generic-2.6/files/drivers/net/phy/adm6996.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * ADM6996 switch driver - * - * Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License v2 as published by the - * Free Software Foundation - */ -#ifndef __ADM6996_H -#define __ADM6996_H - -#define ADM_PHY_PORTS 5 -#define ADM_CPU_PORT 5 -#define ADM_WAN_PORT 0 /* FIXME: dynamic ? */ - -enum admreg { - ADM_EEPROM_BASE = 0x0, - ADM_P0_CFG = ADM_EEPROM_BASE + 1, - ADM_P1_CFG = ADM_EEPROM_BASE + 3, - ADM_P2_CFG = ADM_EEPROM_BASE + 5, - ADM_P3_CFG = ADM_EEPROM_BASE + 7, - ADM_P4_CFG = ADM_EEPROM_BASE + 8, - ADM_P5_CFG = ADM_EEPROM_BASE + 9, - ADM_EEPROM_EXT_BASE = 0x40, - ADM_COUNTER_BASE = 0xa0, - ADM_SIG0 = ADM_COUNTER_BASE + 0, - ADM_SIG1 = ADM_COUNTER_BASE + 1, - ADM_PHY_BASE = 0x200, -#define ADM_PHY_PORT(n) (ADM_PHY_BASE + (0x20 * n)) -}; - -/* Chip identification patterns */ -#define ADM_SIG0_MASK 0xfff0 -#define ADM_SIG0_VAL 0x1020 -#define ADM_SIG1_MASK 0xffff -#define ADM_SIG1_VAL 0x0007 - -enum { - ADM_PHYCFG_COLTST = (1 << 7), /* Enable collision test */ - ADM_PHYCFG_DPLX = (1 << 8), /* Enable full duplex */ - ADM_PHYCFG_ANEN_RST = (1 << 9), /* Restart auto negotiation (self clear) */ - ADM_PHYCFG_ISO = (1 << 10), /* Isolate PHY */ - ADM_PHYCFG_PDN = (1 << 11), /* Power down PHY */ - ADM_PHYCFG_ANEN = (1 << 12), /* Enable auto negotiation */ - ADM_PHYCFG_SPEED_100 = (1 << 13), /* Enable 100 Mbit/s */ - ADM_PHYCFG_LPBK = (1 << 14), /* Enable loopback operation */ - ADM_PHYCFG_RST = (1 << 15), /* Reset the port (self clear) */ - ADM_PHYCFG_INIT = ( - ADM_PHYCFG_RST | - ADM_PHYCFG_SPEED_100 | - ADM_PHYCFG_ANEN | - ADM_PHYCFG_ANEN_RST - ) -}; - -enum { - ADM_PORTCFG_FC = (1 << 0), /* Enable 802.x flow control */ - ADM_PORTCFG_AN = (1 << 1), /* Enable auto-negotiation */ - ADM_PORTCFG_SPEED_100 = (1 << 2), /* Enable 100 Mbit/s */ - ADM_PORTCFG_DPLX = (1 << 3), /* Enable full duplex */ - ADM_PORTCFG_OT = (1 << 4), /* Output tagged packets */ - ADM_PORTCFG_PD = (1 << 5), /* Port disable */ - ADM_PORTCFG_TV_PRIO = (1 << 6), /* 0 = VLAN based priority - * 1 = TOS based priority */ - ADM_PORTCFG_PPE = (1 << 7), /* Port based priority enable */ - ADM_PORTCFG_PP_S = (1 << 8), /* Port based priority, 2 bits */ - ADM_PORTCFG_PVID_BASE = (1 << 10), /* Primary VLAN id, 4 bits */ - ADM_PORTCFG_FSE = (1 << 14), /* Fx select enable */ - ADM_PORTCFG_CAM = (1 << 15), /* Crossover Auto MDIX */ - - ADM_PORTCFG_INIT = ( - ADM_PORTCFG_FC | - ADM_PORTCFG_AN | - ADM_PORTCFG_SPEED_100 | - ADM_PORTCFG_DPLX | - ADM_PORTCFG_CAM - ), - ADM_PORTCFG_CPU = ( - ADM_PORTCFG_FC | - ADM_PORTCFG_SPEED_100 | - ADM_PORTCFG_OT | - ADM_PORTCFG_DPLX - ), -}; - -#define ADM_PORTCFG_PPID(N) ((n & 0x3) << 8) -#define ADM_PORTCFG_PVID(n) ((n & 0xf) << 10) - -static const u8 adm_portcfg[] = { - [0] = ADM_P0_CFG, - [1] = ADM_P1_CFG, - [2] = ADM_P2_CFG, - [3] = ADM_P3_CFG, - [4] = ADM_P4_CFG, - [5] = ADM_P5_CFG, -}; - -/* - * Split the register address in phy id and register - * it will get combined again by the mdio bus op - */ -#define PHYADDR(_reg) ((_reg >> 5) & 0xff), (_reg & 0x1f) - -#endif diff --git a/target/linux/generic-2.6/files/drivers/net/phy/ar8216.c b/target/linux/generic-2.6/files/drivers/net/phy/ar8216.c deleted file mode 100644 index 4ae61da23..000000000 --- a/target/linux/generic-2.6/files/drivers/net/phy/ar8216.c +++ /dev/null @@ -1,839 +0,0 @@ -/* - * ar8216.c: AR8216 switch driver - * - * Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/if.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/list.h> -#include <linux/if_ether.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/netlink.h> -#include <linux/bitops.h> -#include <net/genetlink.h> -#include <linux/switch.h> -#include <linux/delay.h> -#include <linux/phy.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include "ar8216.h" - -/* size of the vlan table */ -#define AR8X16_MAX_VLANS 128 -#define AR8X16_PROBE_RETRIES 10 - -struct ar8216_priv { - struct switch_dev dev; - struct phy_device *phy; - u32 (*read)(struct ar8216_priv *priv, int reg); - void (*write)(struct ar8216_priv *priv, int reg, u32 val); - const struct net_device_ops *ndo_old; - struct net_device_ops ndo; - struct mutex reg_mutex; - int chip; - - /* all fields below are cleared on reset */ - bool vlan; - u16 vlan_id[AR8X16_MAX_VLANS]; - u8 vlan_table[AR8X16_MAX_VLANS]; - u8 vlan_tagged; - u16 pvid[AR8216_NUM_PORTS]; -}; -static struct switch_dev athdev; - -#define to_ar8216(_dev) container_of(_dev, struct ar8216_priv, dev) - -static inline void -split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) -{ - regaddr >>= 1; - *r1 = regaddr & 0x1e; - - regaddr >>= 5; - *r2 = regaddr & 0x7; - - regaddr >>= 3; - *page = regaddr & 0x1ff; -} - -static u32 -ar8216_mii_read(struct ar8216_priv *priv, int reg) -{ - struct phy_device *phy = priv->phy; - u16 r1, r2, page; - u16 lo, hi; - - split_addr((u32) reg, &r1, &r2, &page); - phy->bus->write(phy->bus, 0x18, 0, page); - msleep(1); /* wait for the page switch to propagate */ - lo = phy->bus->read(phy->bus, 0x10 | r2, r1); - hi = phy->bus->read(phy->bus, 0x10 | r2, r1 + 1); - - return (hi << 16) | lo; -} - -static void -ar8216_mii_write(struct ar8216_priv *priv, int reg, u32 val) -{ - struct phy_device *phy = priv->phy; - u16 r1, r2, r3; - u16 lo, hi; - - split_addr((u32) reg, &r1, &r2, &r3); - phy->bus->write(phy->bus, 0x18, 0, r3); - msleep(1); /* wait for the page switch to propagate */ - - lo = val & 0xffff; - hi = (u16) (val >> 16); - phy->bus->write(phy->bus, 0x10 | r2, r1 + 1, hi); - phy->bus->write(phy->bus, 0x10 | r2, r1, lo); -} - -static u32 -ar8216_rmw(struct ar8216_priv *priv, int reg, u32 mask, u32 val) -{ - u32 v; - - v = priv->read(priv, reg); - v &= ~mask; - v |= val; - priv->write(priv, reg, v); - - return v; -} - -static inline int -ar8216_id_chip(struct ar8216_priv *priv) -{ - u32 val; - u16 id; - int i; - - val = ar8216_mii_read(priv, AR8216_REG_CTRL); - if (val == ~0) - return UNKNOWN; - - id = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION); - for (i = 0; i < AR8X16_PROBE_RETRIES; i++) { - u16 t; - - val = ar8216_mii_read(priv, AR8216_REG_CTRL); - if (val == ~0) - return UNKNOWN; - - t = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION); - if (t != id) - return UNKNOWN; - } - - switch (id) { - case 0x0101: - return AR8216; - case 0x1001: - return AR8316; - default: - printk(KERN_DEBUG - "ar8216: Unknown Atheros device [ver=%d, rev=%d, phy_id=%04x%04x]\n", - (int)(id >> AR8216_CTRL_VERSION_S), - (int)(id & AR8216_CTRL_REVISION), - priv->phy->bus->read(priv->phy->bus, priv->phy->addr, 2), - priv->phy->bus->read(priv->phy->bus, priv->phy->addr, 3)); - - return UNKNOWN; - } -} - -static int -ar8216_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, - struct switch_val *val) -{ - struct ar8216_priv *priv = to_ar8216(dev); - priv->vlan = !!val->value.i; - return 0; -} - -static int -ar8216_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, - struct switch_val *val) -{ - struct ar8216_priv *priv = to_ar8216(dev); - val->value.i = priv->vlan; - return 0; -} - - -static int -ar8216_set_pvid(struct switch_dev *dev, int port, int vlan) -{ - struct ar8216_priv *priv = to_ar8216(dev); - - /* make sure no invalid PVIDs get set */ - - if (vlan >= dev->vlans) - return -EINVAL; - - priv->pvid[port] = vlan; - return 0; -} - -static int -ar8216_get_pvid(struct switch_dev *dev, int port, int *vlan) -{ - struct ar8216_priv *priv = to_ar8216(dev); - *vlan = priv->pvid[port]; - return 0; -} - -static int -ar8216_set_vid(struct switch_dev *dev, const struct switch_attr *attr, - struct switch_val *val) -{ - struct ar8216_priv *priv = to_ar8216(dev); - priv->vlan_id[val->port_vlan] = val->value.i; - return 0; -} - -static int -ar8216_get_vid(struct switch_dev *dev, const struct switch_attr *attr, - struct switch_val *val) -{ - struct ar8216_priv *priv = to_ar8216(dev); - val->value.i = priv->vlan_id[val->port_vlan]; - return 0; -} - - -static int -ar8216_mangle_tx(struct sk_buff *skb, struct net_device *dev) -{ - struct ar8216_priv *priv = dev->phy_ptr; - unsigned char *buf; - - if (unlikely(!priv)) - goto error; - - if (!priv->vlan) - goto send; - - if (unlikely(skb_headroom(skb) < 2)) { - if (pskb_expand_head(skb, 2, 0, GFP_ATOMIC) < 0) - goto error; - } - - buf = skb_push(skb, 2); - buf[0] = 0x10; - buf[1] = 0x80; - -send: - return priv->ndo_old->ndo_start_xmit(skb, dev); - -error: - dev_kfree_skb_any(skb); - return 0; -} - -static int -ar8216_mangle_rx(struct sk_buff *skb, int napi) -{ - struct ar8216_priv *priv; - struct net_device *dev; - unsigned char *buf; - int port, vlan; - - dev = skb->dev; - if (!dev) - goto error; - - priv = dev->phy_ptr; - if (!priv) - goto error; - - /* don't strip the header if vlan mode is disabled */ - if (!priv->vlan) - goto recv; - - /* strip header, get vlan id */ - buf = skb->data; - skb_pull(skb, 2); - - /* check for vlan header presence */ - if ((buf[12 + 2] != 0x81) || (buf[13 + 2] != 0x00)) - goto recv; - - port = buf[0] & 0xf; - - /* no need to fix up packets coming from a tagged source */ - if (priv->vlan_tagged & (1 << port)) - goto recv; - - /* lookup port vid from local table, the switch passes an invalid vlan id */ - vlan = priv->vlan_id[priv->pvid[port]]; - - buf[14 + 2] &= 0xf0; - buf[14 + 2] |= vlan >> 8; - buf[15 + 2] = vlan & 0xff; - -recv: - skb->protocol = eth_type_trans(skb, skb->dev); - - if (napi) - return netif_receive_skb(skb); - else - return netif_rx(skb); - -error: - /* no vlan? eat the packet! */ - dev_kfree_skb_any(skb); - return NET_RX_DROP; -} - -static int -ar8216_netif_rx(struct sk_buff *skb) -{ - return ar8216_mangle_rx(skb, 0); -} - -static int -ar8216_netif_receive_skb(struct sk_buff *skb) -{ - return ar8216_mangle_rx(skb, 1); -} - - -static struct switch_attr ar8216_globals[] = { - { - .type = SWITCH_TYPE_INT, - .name = "enable_vlan", - .description = "Enable VLAN mode", - .set = ar8216_set_vlan, - .get = ar8216_get_vlan, - .max = 1 - }, -}; - -static struct switch_attr ar8216_port[] = { -}; - -static struct switch_attr ar8216_vlan[] = { - { - .type = SWITCH_TYPE_INT, - .name = "pvid", - .description = "VLAN ID", - .set = ar8216_set_vid, - .get = ar8216_get_vid, - .max = 4094, - }, -}; - - -static int -ar8216_get_ports(struct switch_dev *dev, struct switch_val *val) -{ - struct ar8216_priv *priv = to_ar8216(dev); - u8 ports = priv->vlan_table[val->port_vlan]; - int i; - - val->len = 0; - for (i = 0; i < AR8216_NUM_PORTS; i++) { - struct switch_port *p; - - if (!(ports & (1 << i))) - continue; - - p = &val->value.ports[val->len++]; - p->id = i; - if (priv->vlan_tagged & (1 << i)) - p->flags = (1 << SWITCH_PORT_FLAG_TAGGED); - else - p->flags = 0; - } - return 0; -} - -static int -ar8216_set_ports(struct switch_dev *dev, struct switch_val *val) -{ - struct ar8216_priv *priv = to_ar8216(dev); - u8 *vt = &priv->vlan_table[val->port_vlan]; - int i, j; - - *vt = 0; - for (i = 0; i < val->len; i++) { - struct switch_port *p = &val->value.ports[i]; - - if (p->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) - priv->vlan_tagged |= (1 << p->id); - else { - priv->vlan_tagged &= ~(1 << p->id); - priv->pvid[p->id] = val->port_vlan; - - /* make sure that an untagged port does not - * appear in other vlans */ - for (j = 0; j < AR8X16_MAX_VLANS; j++) { - if (j == val->port_vlan) - continue; - priv->vlan_table[j] &= ~(1 << p->id); - } - } - - *vt |= 1 << p->id; - } - return 0; -} - -static int -ar8216_wait_bit(struct ar8216_priv *priv, int reg, u32 mask, u32 val) -{ - int timeout = 20; - - while ((priv->read(priv, reg) & mask) != val) { - if (timeout-- <= 0) { - printk(KERN_ERR "ar8216: timeout waiting for operation to complete\n"); - return 1; - } - } - return 0; -} - -static void -ar8216_vtu_op(struct ar8216_priv *priv, u32 op, u32 val) -{ - if (ar8216_wait_bit(priv, AR8216_REG_VTU, AR8216_VTU_ACTIVE, 0)) - return; - if ((op & AR8216_VTU_OP) == AR8216_VTU_OP_LOAD) { - val &= AR8216_VTUDATA_MEMBER; - val |= AR8216_VTUDATA_VALID; - priv->write(priv, AR8216_REG_VTU_DATA, val); - } - op |= AR8216_VTU_ACTIVE; - priv->write(priv, AR8216_REG_VTU, op); -} - -static int -ar8216_hw_apply(struct switch_dev *dev) -{ - struct ar8216_priv *priv = to_ar8216(dev); - u8 portmask[AR8216_NUM_PORTS]; - int i, j; - - mutex_lock(&priv->reg_mutex); - /* flush all vlan translation unit entries */ - ar8216_vtu_op(priv, AR8216_VTU_OP_FLUSH, 0); - - memset(portmask, 0, sizeof(portmask)); - if (priv->vlan) { - /* calculate the port destination masks and load vlans - * into the vlan translation unit */ - for (j = 0; j < AR8X16_MAX_VLANS; j++) { - u8 vp = priv->vlan_table[j]; - - if (!vp) - continue; - - for (i = 0; i < AR8216_NUM_PORTS; i++) { - u8 mask = (1 << i); - if (vp & mask) - portmask[i] |= vp & ~mask; - } - - ar8216_vtu_op(priv, - AR8216_VTU_OP_LOAD | - (priv->vlan_id[j] << AR8216_VTU_VID_S), - priv->vlan_table[j]); - } - } else { - /* vlan disabled: - * isolate all ports, but connect them to the cpu port */ - for (i = 0; i < AR8216_NUM_PORTS; i++) { - if (i == AR8216_PORT_CPU) - continue; - - portmask[i] = 1 << AR8216_PORT_CPU; - portmask[AR8216_PORT_CPU] |= (1 << i); - } - } - - /* update the port destination mask registers and tag settings */ - for (i = 0; i < AR8216_NUM_PORTS; i++) { - int egress, ingress; - int pvid; - - if (priv->vlan) { - pvid = priv->vlan_id[priv->pvid[i]]; - } else { - pvid = i; - } - - if (priv->vlan && (priv->vlan_tagged & (1 << i))) { - egress = AR8216_OUT_ADD_VLAN; - } else { - egress = AR8216_OUT_STRIP_VLAN; - } - if (priv->vlan) { - ingress = AR8216_IN_SECURE; - } else { - ingress = AR8216_IN_PORT_ONLY; - } - - ar8216_rmw(priv, AR8216_REG_PORT_CTRL(i), - AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE | - AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE | - AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK, - AR8216_PORT_CTRL_LEARN | - (priv->vlan && i == AR8216_PORT_CPU && (priv->chip == AR8216) ? - AR8216_PORT_CTRL_HEADER : 0) | - (egress << AR8216_PORT_CTRL_VLAN_MODE_S) | - (AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S)); - - ar8216_rmw(priv, AR8216_REG_PORT_VLAN(i), - AR8216_PORT_VLAN_DEST_PORTS | AR8216_PORT_VLAN_MODE | - AR8216_PORT_VLAN_DEFAULT_ID, - (portmask[i] << AR8216_PORT_VLAN_DEST_PORTS_S) | - (ingress << AR8216_PORT_VLAN_MODE_S) | - (pvid << AR8216_PORT_VLAN_DEFAULT_ID_S)); - } - mutex_unlock(&priv->reg_mutex); - return 0; -} - -static int -ar8316_hw_init(struct ar8216_priv *priv) { - static int initialized; - int i; - u32 val; - struct mii_bus *bus; - - if (initialized) - return 0; - - val = priv->read(priv, 0x8); - - if (priv->phy->interface == PHY_INTERFACE_MODE_RGMII) { - /* value taken from Ubiquiti RouterStation Pro */ - if (val == 0x81461bea) { - /* switch already intialized by bootloader */ - initialized = true; - return 0; - } - priv->write(priv, 0x8, 0x81461bea); - } else if (priv->phy->interface == PHY_INTERFACE_MODE_GMII) { - /* value taken from AVM Fritz!Box 7390 sources */ - if (val == 0x010e5b71) { - /* switch already initialized by bootloader */ - initialized = true; - return 0; - } - priv->write(priv, 0x8, 0x010e5b71); - } else { - /* no known value for phy interface */ - printk(KERN_ERR "ar8316: unsupported mii mode: %d.\n", - priv->phy->interface); - return -EINVAL; - } - - /* standard atheros magic */ - priv->write(priv, 0x38, 0xc000050e); - - /* Initialize the ports */ - bus = priv->phy->bus; - for (i = 0; i < 5; i++) { - if ((i == 4) && - priv->phy->interface == PHY_INTERFACE_MODE_RGMII) { - /* work around for phy4 rgmii mode */ - bus->write(bus, i, MII_ATH_DBG_ADDR, 0x12); - bus->write(bus, i, MII_ATH_DBG_DATA, 0x480c); - /* rx delay */ - bus->write(bus, i, MII_ATH_DBG_ADDR, 0x0); - bus->write(bus, i, MII_ATH_DBG_DATA, 0x824e); - /* tx delay */ - bus->write(bus, i, MII_ATH_DBG_ADDR, 0x5); - bus->write(bus, i, MII_ATH_DBG_DATA, 0x3d47); - msleep(1000); - } - - /* initialize the port itself */ - bus->write(bus, i, MII_ADVERTISE, - ADVERTISE_ALL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); - bus->write(bus, i, MII_CTRL1000, ADVERTISE_1000FULL); - bus->write(bus, i, MII_BMCR, BMCR_RESET | BMCR_ANENABLE); - msleep(1000); - } - initialized = true; - return 0; -} - -static int -ar8216_reset_switch(struct switch_dev *dev) -{ - struct ar8216_priv *priv = to_ar8216(dev); - int i; - - mutex_lock(&priv->reg_mutex); - memset(&priv->vlan, 0, sizeof(struct ar8216_priv) - - offsetof(struct ar8216_priv, vlan)); - for (i = 0; i < AR8X16_MAX_VLANS; i++) { - priv->vlan_id[i] = i; - } - for (i = 0; i < AR8216_NUM_PORTS; i++) { - /* Enable port learning and tx */ - priv->write(priv, AR8216_REG_PORT_CTRL(i), - AR8216_PORT_CTRL_LEARN | - (4 << AR8216_PORT_CTRL_STATE_S)); - - priv->write(priv, AR8216_REG_PORT_VLAN(i), 0); - - /* Configure all PHYs */ - if (i == AR8216_PORT_CPU) { - priv->write(priv, AR8216_REG_PORT_STATUS(i), - AR8216_PORT_STATUS_LINK_UP | - ((priv->chip == AR8316) ? - AR8216_PORT_SPEED_1000M : AR8216_PORT_SPEED_100M) | - AR8216_PORT_STATUS_TXMAC | - AR8216_PORT_STATUS_RXMAC | - ((priv->chip == AR8316) ? AR8216_PORT_STATUS_RXFLOW : 0) | - ((priv->chip == AR8316) ? AR8216_PORT_STATUS_TXFLOW : 0) | - AR8216_PORT_STATUS_DUPLEX); - } else { - priv->write(priv, AR8216_REG_PORT_STATUS(i), - AR8216_PORT_STATUS_LINK_AUTO); - } - } - /* XXX: undocumented magic from atheros, required! */ - priv->write(priv, 0x38, 0xc000050e); - - if (priv->chip == AR8216) { - ar8216_rmw(priv, AR8216_REG_GLOBAL_CTRL, - AR8216_GCTRL_MTU, 1518 + 8 + 2); - } else if (priv->chip == AR8316) { - /* enable jumbo frames */ - ar8216_rmw(priv, AR8216_REG_GLOBAL_CTRL, - AR8316_GCTRL_MTU, 9018 + 8 + 2); - } - - if (priv->chip == AR8316) { - /* enable cpu port to receive multicast and broadcast frames */ - priv->write(priv, AR8216_REG_FLOOD_MASK, 0x003f003f); - } - mutex_unlock(&priv->reg_mutex); - return ar8216_hw_apply(dev); -} - -static int -ar8216_config_init(struct phy_device *pdev) -{ - struct ar8216_priv *priv; - struct net_device *dev = pdev->attached_dev; - int ret; - - priv = kzalloc(sizeof(struct ar8216_priv), GFP_KERNEL); - if (priv == NULL) - return -ENOMEM; - - priv->phy = pdev; - - priv->chip = ar8216_id_chip(priv); - - if (pdev->addr == 0) - printk(KERN_INFO "%s: AR%d switch driver attached.\n", - pdev->attached_dev->name, priv->chip); - - - if (pdev->addr != 0) { - if (priv->chip == AR8316) { - pdev->supported |= SUPPORTED_1000baseT_Full; - pdev->advertising |= ADVERTISED_1000baseT_Full; - } - kfree(priv); - return 0; - } - - pdev->supported = priv->chip == AR8316 ? - SUPPORTED_1000baseT_Full : SUPPORTED_100baseT_Full; - pdev->advertising = pdev->supported; - - mutex_init(&priv->reg_mutex); - priv->read = ar8216_mii_read; - priv->write = ar8216_mii_write; - memcpy(&priv->dev, &athdev, sizeof(struct switch_dev)); - pdev->priv = priv; - - if (priv->chip == AR8316) { - priv->dev.name = "Atheros AR8316"; - priv->dev.vlans = AR8X16_MAX_VLANS; - /* port 5 connected to the other mac, therefore unusable */ - priv->dev.ports = (AR8216_NUM_PORTS - 1); - } - - if ((ret = register_switch(&priv->dev, pdev->attached_dev)) < 0) { - kfree(priv); - goto done; - } - - if (priv->chip == AR8316) { - ret = ar8316_hw_init(priv); - if (ret) { - kfree(priv); - goto done; - } - } - - ret = ar8216_reset_switch(&priv->dev); - if (ret) { - kfree(priv); - goto done; - } - - dev->phy_ptr = priv; - - /* VID fixup only needed on ar8216 */ - if (pdev->addr == 0 && priv->chip == AR8216) { - pdev->pkt_align = 2; - pdev->netif_receive_skb = ar8216_netif_receive_skb; - pdev->netif_rx = ar8216_netif_rx; - priv->ndo_old = dev->netdev_ops; - memcpy(&priv->ndo, priv->ndo_old, sizeof(struct net_device_ops)); - priv->ndo.ndo_start_xmit = ar8216_mangle_tx; - dev->netdev_ops = &priv->ndo; - } - -done: - return ret; -} - -static int -ar8216_read_status(struct phy_device *phydev) -{ - struct ar8216_priv *priv = phydev->priv; - int ret; - if (phydev->addr != 0) { - return genphy_read_status(phydev); - } - - phydev->speed = priv->chip == AR8316 ? SPEED_1000 : SPEED_100; - phydev->duplex = DUPLEX_FULL; - phydev->link = 1; - - /* flush the address translation unit */ - mutex_lock(&priv->reg_mutex); - ret = ar8216_wait_bit(priv, AR8216_REG_ATU, AR8216_ATU_ACTIVE, 0); - - if (!ret) - priv->write(priv, AR8216_REG_ATU, AR8216_ATU_OP_FLUSH); - else - ret = -ETIMEDOUT; - mutex_unlock(&priv->reg_mutex); - - phydev->state = PHY_RUNNING; - netif_carrier_on(phydev->attached_dev); - phydev->adjust_link(phydev->attached_dev); - - return ret; -} - -static int -ar8216_config_aneg(struct phy_device *phydev) -{ - if (phydev->addr == 0) - return 0; - - return genphy_config_aneg(phydev); -} - -static int -ar8216_probe(struct phy_device *pdev) -{ - struct ar8216_priv priv; - u16 chip; - - priv.phy = pdev; - chip = ar8216_id_chip(&priv); - if (chip == UNKNOWN) - return -ENODEV; - - return 0; -} - -static void -ar8216_remove(struct phy_device *pdev) -{ - struct ar8216_priv *priv = pdev->priv; - struct net_device *dev = pdev->attached_dev; - - if (!priv) - return; - - if (priv->ndo_old && dev) - dev->netdev_ops = priv->ndo_old; - if (pdev->addr == 0) - unregister_switch(&priv->dev); - kfree(priv); -} - -/* template */ -static struct switch_dev athdev = { - .name = "Atheros AR8216", - .cpu_port = AR8216_PORT_CPU, - .ports = AR8216_NUM_PORTS, - .vlans = AR8216_NUM_VLANS, - .attr_global = { - .attr = ar8216_globals, - .n_attr = ARRAY_SIZE(ar8216_globals), - }, - .attr_port = { - .attr = ar8216_port, - .n_attr = ARRAY_SIZE(ar8216_port), - }, - .attr_vlan = { - .attr = ar8216_vlan, - .n_attr = ARRAY_SIZE(ar8216_vlan), - }, - .get_port_pvid = ar8216_get_pvid, - .set_port_pvid = ar8216_set_pvid, - .get_vlan_ports = ar8216_get_ports, - .set_vlan_ports = ar8216_set_ports, - .apply_config = ar8216_hw_apply, - .reset_switch = ar8216_reset_switch, -}; - -static struct phy_driver ar8216_driver = { - .phy_id = 0x004d0000, - .name = "Atheros AR8216/AR8316", - .phy_id_mask = 0xffff0000, - .features = PHY_BASIC_FEATURES, - .probe = ar8216_probe, - .remove = ar8216_remove, - .config_init = &ar8216_config_init, - .config_aneg = &ar8216_config_aneg, - .read_status = &ar8216_read_status, - .driver = { .owner = THIS_MODULE }, -}; - -int __init -ar8216_init(void) -{ - return phy_driver_register(&ar8216_driver); -} - -void __exit -ar8216_exit(void) -{ - phy_driver_unregister(&ar8216_driver); -} - -module_init(ar8216_init); -module_exit(ar8216_exit); -MODULE_LICENSE("GPL"); - diff --git a/target/linux/generic-2.6/files/drivers/net/phy/ar8216.h b/target/linux/generic-2.6/files/drivers/net/phy/ar8216.h deleted file mode 100644 index 5a8fa3c00..000000000 --- a/target/linux/generic-2.6/files/drivers/net/phy/ar8216.h +++ /dev/null @@ -1,187 +0,0 @@ -/* - * ar8216.h: AR8216 switch driver - * - * Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef __AR8216_H -#define __AR8216_H - -#define BITS(_s, _n) (((1UL << (_n)) - 1) << _s) - -#define AR8216_PORT_CPU 0 -#define AR8216_NUM_PORTS 6 -#define AR8216_NUM_VLANS 16 -#define AR8316_NUM_VLANS 4096 - -/* Atheros specific MII registers */ -#define MII_ATH_DBG_ADDR 0x1d -#define MII_ATH_DBG_DATA 0x1e - -#define AR8216_REG_CTRL 0x0000 -#define AR8216_CTRL_REVISION BITS(0, 8) -#define AR8216_CTRL_REVISION_S 0 -#define AR8216_CTRL_VERSION BITS(8, 8) -#define AR8216_CTRL_VERSION_S 8 -#define AR8216_CTRL_RESET BIT(31) - -#define AR8216_REG_FLOOD_MASK 0x002C -#define AR8216_FM_UNI_DEST_PORTS BITS(0, 6) -#define AR8216_FM_MULTI_DEST_PORTS BITS(16, 6) - -#define AR8216_REG_GLOBAL_CTRL 0x0030 -#define AR8216_GCTRL_MTU BITS(0, 11) -#define AR8316_GCTRL_MTU BITS(0, 14) - -#define AR8216_REG_VTU 0x0040 -#define AR8216_VTU_OP BITS(0, 3) -#define AR8216_VTU_OP_NOOP 0x0 -#define AR8216_VTU_OP_FLUSH 0x1 -#define AR8216_VTU_OP_LOAD 0x2 -#define AR8216_VTU_OP_PURGE 0x3 -#define AR8216_VTU_OP_REMOVE_PORT 0x4 -#define AR8216_VTU_ACTIVE BIT(3) -#define AR8216_VTU_FULL BIT(4) -#define AR8216_VTU_PORT BITS(8, 4) -#define AR8216_VTU_PORT_S 8 -#define AR8216_VTU_VID BITS(16, 12) -#define AR8216_VTU_VID_S 16 -#define AR8216_VTU_PRIO BITS(28, 3) -#define AR8216_VTU_PRIO_S 28 -#define AR8216_VTU_PRIO_EN BIT(31) - -#define AR8216_REG_VTU_DATA 0x0044 -#define AR8216_VTUDATA_MEMBER BITS(0, 10) -#define AR8216_VTUDATA_VALID BIT(11) - -#define AR8216_REG_ATU 0x0050 -#define AR8216_ATU_OP BITS(0, 3) -#define AR8216_ATU_OP_NOOP 0x0 -#define AR8216_ATU_OP_FLUSH 0x1 -#define AR8216_ATU_OP_LOAD 0x2 -#define AR8216_ATU_OP_PURGE 0x3 -#define AR8216_ATU_OP_FLUSH_LOCKED 0x4 -#define AR8216_ATU_OP_FLUSH_UNICAST 0x5 -#define AR8216_ATU_OP_GET_NEXT 0x6 -#define AR8216_ATU_ACTIVE BIT(3) -#define AR8216_ATU_PORT_NUM BITS(8, 4) -#define AR8216_ATU_FULL_VIO BIT(12) -#define AR8216_ATU_ADDR4 BITS(16, 8) -#define AR8216_ATU_ADDR5 BITS(24, 8) - -#define AR8216_REG_ATU_DATA 0x0054 -#define AR8216_ATU_ADDR3 BITS(0, 8) -#define AR8216_ATU_ADDR2 BITS(8, 8) -#define AR8216_ATU_ADDR1 BITS(16, 8) -#define AR8216_ATU_ADDR0 BITS(24, 8) - -#define AR8216_REG_ATU_CTRL 0x005C -#define AR8216_ATU_CTRL_AGE_EN BIT(17) -#define AR8216_ATU_CTRL_AGE_TIME BITS(0, 16) -#define AR8216_ATU_CTRL_AGE_TIME_S 0 - -#define AR8216_PORT_OFFSET(_i) (0x0100 * (_i + 1)) -#define AR8216_REG_PORT_STATUS(_i) (AR8216_PORT_OFFSET(_i) + 0x0000) -#define AR8216_PORT_STATUS_SPEED BITS(0,2) -#define AR8216_PORT_STATUS_SPEED_S 0 -#define AR8216_PORT_STATUS_TXMAC BIT(2) -#define AR8216_PORT_STATUS_RXMAC BIT(3) -#define AR8216_PORT_STATUS_TXFLOW BIT(4) -#define AR8216_PORT_STATUS_RXFLOW BIT(5) -#define AR8216_PORT_STATUS_DUPLEX BIT(6) -#define AR8216_PORT_STATUS_LINK_UP BIT(8) -#define AR8216_PORT_STATUS_LINK_AUTO BIT(9) -#define AR8216_PORT_STATUS_LINK_PAUSE BIT(10) - -#define AR8216_REG_PORT_CTRL(_i) (AR8216_PORT_OFFSET(_i) + 0x0004) - -/* port forwarding state */ -#define AR8216_PORT_CTRL_STATE BITS(0, 3) -#define AR8216_PORT_CTRL_STATE_S 0 - -#define AR8216_PORT_CTRL_LEARN_LOCK BIT(7) - -/* egress 802.1q mode */ -#define AR8216_PORT_CTRL_VLAN_MODE BITS(8, 2) -#define AR8216_PORT_CTRL_VLAN_MODE_S 8 - -#define AR8216_PORT_CTRL_IGMP_SNOOP BIT(10) -#define AR8216_PORT_CTRL_HEADER BIT(11) -#define AR8216_PORT_CTRL_MAC_LOOP BIT(12) -#define AR8216_PORT_CTRL_SINGLE_VLAN BIT(13) -#define AR8216_PORT_CTRL_LEARN BIT(14) -#define AR8216_PORT_CTRL_MIRROR_TX BIT(16) -#define AR8216_PORT_CTRL_MIRROR_RX BIT(17) - -#define AR8216_REG_PORT_VLAN(_i) (AR8216_PORT_OFFSET(_i) + 0x0008) - -#define AR8216_PORT_VLAN_DEFAULT_ID BITS(0, 12) -#define AR8216_PORT_VLAN_DEFAULT_ID_S 0 - -#define AR8216_PORT_VLAN_DEST_PORTS BITS(16, 9) -#define AR8216_PORT_VLAN_DEST_PORTS_S 16 - -/* bit0 added to the priority field of egress frames */ -#define AR8216_PORT_VLAN_TX_PRIO BIT(27) - -/* port default priority */ -#define AR8216_PORT_VLAN_PRIORITY BITS(28, 2) -#define AR8216_PORT_VLAN_PRIORITY_S 28 - -/* ingress 802.1q mode */ -#define AR8216_PORT_VLAN_MODE BITS(30, 2) -#define AR8216_PORT_VLAN_MODE_S 30 - -#define AR8216_REG_PORT_RATE(_i) (AR8216_PORT_OFFSET(_i) + 0x000c) -#define AR8216_REG_PORT_PRIO(_i) (AR8216_PORT_OFFSET(_i) + 0x0010) - -/* port speed */ -enum { - AR8216_PORT_SPEED_10M = 0, - AR8216_PORT_SPEED_100M = 1, - AR8216_PORT_SPEED_1000M = 2, - AR8216_PORT_SPEED_ERR = 3, -}; - -/* ingress 802.1q mode */ -enum { - AR8216_IN_PORT_ONLY = 0, - AR8216_IN_PORT_FALLBACK = 1, - AR8216_IN_VLAN_ONLY = 2, - AR8216_IN_SECURE = 3 -}; - -/* egress 802.1q mode */ -enum { - AR8216_OUT_KEEP = 0, - AR8216_OUT_STRIP_VLAN = 1, - AR8216_OUT_ADD_VLAN = 2 -}; - -/* port forwarding state */ -enum { - AR8216_PORT_STATE_DISABLED = 0, - AR8216_PORT_STATE_BLOCK = 1, - AR8216_PORT_STATE_LISTEN = 2, - AR8216_PORT_STATE_LEARN = 3, - AR8216_PORT_STATE_FORWARD = 4 -}; - -/* device */ -enum { - UNKNOWN = 0, - AR8216 = 8216, - AR8316 = 8316 -}; - -#endif diff --git a/target/linux/generic-2.6/files/drivers/net/phy/ip17xx.c b/target/linux/generic-2.6/files/drivers/net/phy/ip17xx.c deleted file mode 100644 index 262123a57..000000000 --- a/target/linux/generic-2.6/files/drivers/net/phy/ip17xx.c +++ /dev/null @@ -1,1399 +0,0 @@ -/* - * ip17xx.c: Swconfig configuration for IC+ IP17xx switch family - * - * Copyright (C) 2008 Patrick Horn <patrick.horn@gmail.com> - * Copyright (C) 2008, 2010 Martin Mares <mj@ucw.cz> - * Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/list.h> -#include <linux/skbuff.h> -#include <linux/mii.h> -#include <linux/phy.h> -#include <linux/delay.h> -#include <linux/switch.h> -#include <linux/device.h> - -#define MAX_VLANS 16 -#define MAX_PORTS 9 -#undef DUMP_MII_IO - -typedef struct ip17xx_reg { - u16 p; // phy - u16 m; // mii -} reg; -typedef char bitnum; - -#define NOTSUPPORTED {-1,-1} - -#define REG_SUPP(x) (((x).m != ((u16)-1)) && ((x).p != (u16)-1)) - -struct ip17xx_state; - -/*********** CONSTANTS ***********/ -struct register_mappings { - char *NAME; - u16 MODEL_NO; // Compare to bits 4-9 of MII register 0,3. - bitnum NUM_PORTS; - bitnum CPU_PORT; - -/* The default VLAN for each port. - Default: 0x0001 for Ports 0,1,2,3 - 0x0002 for Ports 4,5 */ - reg VLAN_DEFAULT_TAG_REG[MAX_PORTS]; - -/* These ports are tagged. - Default: 0x00 */ - reg ADD_TAG_REG; - reg REMOVE_TAG_REG; - bitnum ADD_TAG_BIT[MAX_PORTS]; -/* These ports are untagged. - Default: 0x00 (i.e. do not alter any VLAN tags...) - Maybe set to 0 if user disables VLANs. */ - bitnum REMOVE_TAG_BIT[MAX_PORTS]; - -/* Port M and Port N are on the same VLAN. - Default: All ports on all VLANs. */ -// Use register {29, 19+N/2} - reg VLAN_LOOKUP_REG; -// Port 5 uses register {30, 18} but same as odd bits. - reg VLAN_LOOKUP_REG_5; // in a different register on IP175C. - bitnum VLAN_LOOKUP_EVEN_BIT[MAX_PORTS]; - bitnum VLAN_LOOKUP_ODD_BIT[MAX_PORTS]; - -/* This VLAN corresponds to which ports. - Default: 0x2f,0x30,0x3f,0x3f... */ - reg TAG_VLAN_MASK_REG; - bitnum TAG_VLAN_MASK_EVEN_BIT[MAX_PORTS]; - bitnum TAG_VLAN_MASK_ODD_BIT[MAX_PORTS]; - - int RESET_VAL; - reg RESET_REG; - - reg MODE_REG; - int MODE_VAL; - -/* General flags */ - reg ROUTER_CONTROL_REG; - reg VLAN_CONTROL_REG; - bitnum TAG_VLAN_BIT; - bitnum ROUTER_EN_BIT; - bitnum NUMLAN_GROUPS_MAX; - bitnum NUMLAN_GROUPS_BIT; - - reg MII_REGISTER_EN; - bitnum MII_REGISTER_EN_BIT; - - // set to 1 for 178C, 0 for 175C. - bitnum SIMPLE_VLAN_REGISTERS; // 175C has two vlans per register but 178C has only one. - - // Pointers to functions which manipulate hardware state - int (*update_state)(struct ip17xx_state *state); - int (*set_vlan_mode)(struct ip17xx_state *state); - int (*reset)(struct ip17xx_state *state); -}; - -static int ip175c_update_state(struct ip17xx_state *state); -static int ip175c_set_vlan_mode(struct ip17xx_state *state); -static int ip175c_reset(struct ip17xx_state *state); - -static const struct register_mappings IP178C = { - .NAME = "IP178C", - .MODEL_NO = 0x18, - .VLAN_DEFAULT_TAG_REG = { - {30,3},{30,4},{30,5},{30,6},{30,7},{30,8}, - {30,9},{30,10},{30,11}, - }, - - .ADD_TAG_REG = {30,12}, - .ADD_TAG_BIT = {0,1,2,3,4,5,6,7,8}, - .REMOVE_TAG_REG = {30,13}, - .REMOVE_TAG_BIT = {4,5,6,7,8,9,10,11,12}, - - .SIMPLE_VLAN_REGISTERS = 1, - - .VLAN_LOOKUP_REG = {31,0},// +N - .VLAN_LOOKUP_REG_5 = NOTSUPPORTED, // not used with SIMPLE_VLAN_REGISTERS - .VLAN_LOOKUP_EVEN_BIT = {0,1,2,3,4,5,6,7,8}, - .VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,5,6,7,8}, - - .TAG_VLAN_MASK_REG = {30,14}, // +N - .TAG_VLAN_MASK_EVEN_BIT = {0,1,2,3,4,5,6,7,8}, - .TAG_VLAN_MASK_ODD_BIT = {0,1,2,3,4,5,6,7,8}, - - .RESET_VAL = 0x55AA, - .RESET_REG = {30,0}, - .MODE_VAL = 0, - .MODE_REG = NOTSUPPORTED, - - .ROUTER_CONTROL_REG = {30,30}, - .ROUTER_EN_BIT = 11, - .NUMLAN_GROUPS_MAX = 8, - .NUMLAN_GROUPS_BIT = 8, // {0-2} - - .VLAN_CONTROL_REG = {30,13}, - .TAG_VLAN_BIT = 3, - - .CPU_PORT = 8, - .NUM_PORTS = 9, - - .MII_REGISTER_EN = NOTSUPPORTED, - - .update_state = ip175c_update_state, - .set_vlan_mode = ip175c_set_vlan_mode, - .reset = ip175c_reset, -}; - -static const struct register_mappings IP175C = { - .NAME = "IP175C", - .MODEL_NO = 0x18, - .VLAN_DEFAULT_TAG_REG = { - {29,24},{29,25},{29,26},{29,27},{29,28},{29,30}, - NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED - }, - - .ADD_TAG_REG = {29,23}, - .REMOVE_TAG_REG = {29,23}, - .ADD_TAG_BIT = {11,12,13,14,15,1,-1,-1,-1}, - .REMOVE_TAG_BIT = {6,7,8,9,10,0,-1,-1,-1}, - - .SIMPLE_VLAN_REGISTERS = 0, - - .VLAN_LOOKUP_REG = {29,19},// +N/2 - .VLAN_LOOKUP_REG_5 = {30,18}, - .VLAN_LOOKUP_EVEN_BIT = {8,9,10,11,12,15,-1,-1,-1}, - .VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,7,-1,-1,-1}, - - .TAG_VLAN_MASK_REG = {30,1}, // +N/2 - .TAG_VLAN_MASK_EVEN_BIT = {0,1,2,3,4,5,-1,-1,-1}, - .TAG_VLAN_MASK_ODD_BIT = {8,9,10,11,12,13,-1,-1,-1}, - - .RESET_VAL = 0x175C, - .RESET_REG = {30,0}, - .MODE_VAL = 0x175C, - .MODE_REG = {29,31}, - - .ROUTER_CONTROL_REG = {30,9}, - .ROUTER_EN_BIT = 3, - .NUMLAN_GROUPS_MAX = 8, - .NUMLAN_GROUPS_BIT = 0, // {0-2} - - .VLAN_CONTROL_REG = {30,9}, - .TAG_VLAN_BIT = 7, - - .NUM_PORTS = 6, - .CPU_PORT = 5, - - .MII_REGISTER_EN = NOTSUPPORTED, - - .update_state = ip175c_update_state, - .set_vlan_mode = ip175c_set_vlan_mode, - .reset = ip175c_reset, -}; - -static const struct register_mappings IP175A = { - .NAME = "IP175A", - .MODEL_NO = 0x05, - .VLAN_DEFAULT_TAG_REG = { - {0,24},{0,25},{0,26},{0,27},{0,28},NOTSUPPORTED, - NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED - }, - - .ADD_TAG_REG = {0,23}, - .REMOVE_TAG_REG = {0,23}, - .ADD_TAG_BIT = {11,12,13,14,15,-1,-1,-1,-1}, - .REMOVE_TAG_BIT = {6,7,8,9,10,-1,-1,-1,-1}, - - .SIMPLE_VLAN_REGISTERS = 0, - - // Only programmable via EEPROM - .VLAN_LOOKUP_REG = NOTSUPPORTED,// +N/2 - .VLAN_LOOKUP_REG_5 = NOTSUPPORTED, - .VLAN_LOOKUP_EVEN_BIT = {8,9,10,11,12,-1,-1,-1,-1}, - .VLAN_LOOKUP_ODD_BIT = {0,1,2,3,4,-1,-1,-1,-1}, - - .TAG_VLAN_MASK_REG = NOTSUPPORTED, // +N/2, - .TAG_VLAN_MASK_EVEN_BIT = {-1,-1,-1,-1,-1,-1,-1,-1,-1}, - .TAG_VLAN_MASK_ODD_BIT = {-1,-1,-1,-1,-1,-1,-1,-1,-1}, - - .RESET_VAL = -1, - .RESET_REG = NOTSUPPORTED, - .MODE_VAL = 0, - .MODE_REG = NOTSUPPORTED, - - .ROUTER_CONTROL_REG = NOTSUPPORTED, - .VLAN_CONTROL_REG = NOTSUPPORTED, - .TAG_VLAN_BIT = -1, - .ROUTER_EN_BIT = -1, - .NUMLAN_GROUPS_MAX = -1, - .NUMLAN_GROUPS_BIT = -1, // {0-2} - - .NUM_PORTS = 5, - .CPU_PORT = 4, - - .MII_REGISTER_EN = {0, 18}, - .MII_REGISTER_EN_BIT = 7, - - .update_state = ip175c_update_state, - .set_vlan_mode = ip175c_set_vlan_mode, - .reset = ip175c_reset, -}; - - -static int ip175d_update_state(struct ip17xx_state *state); -static int ip175d_set_vlan_mode(struct ip17xx_state *state); -static int ip175d_reset(struct ip17xx_state *state); - -static const struct register_mappings IP175D = { - .NAME = "IP175D", - .MODEL_NO = 0x18, - - // The IP175D has a completely different interface, so we leave most - // of the registers undefined and switch to different code paths. - - .VLAN_DEFAULT_TAG_REG = { - NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED, - NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED, - }, - - .ADD_TAG_REG = NOTSUPPORTED, - .REMOVE_TAG_REG = NOTSUPPORTED, - - .SIMPLE_VLAN_REGISTERS = 0, - - .VLAN_LOOKUP_REG = NOTSUPPORTED, - .VLAN_LOOKUP_REG_5 = NOTSUPPORTED, - .TAG_VLAN_MASK_REG = NOTSUPPORTED, - - .RESET_VAL = 0x175D, - .RESET_REG = {20,2}, - .MODE_REG = NOTSUPPORTED, - - .ROUTER_CONTROL_REG = NOTSUPPORTED, - .ROUTER_EN_BIT = -1, - .NUMLAN_GROUPS_BIT = -1, - - .VLAN_CONTROL_REG = NOTSUPPORTED, - .TAG_VLAN_BIT = -1, - - .NUM_PORTS = 6, - .CPU_PORT = 5, - - .MII_REGISTER_EN = NOTSUPPORTED, - - .update_state = ip175d_update_state, - .set_vlan_mode = ip175d_set_vlan_mode, - .reset = ip175d_reset, -}; - -struct ip17xx_state { - struct switch_dev dev; - struct mii_bus *mii_bus; - bool registered; - - int router_mode; // ROUTER_EN - int vlan_enabled; // TAG_VLAN_EN - struct port_state { - u16 pvid; - unsigned int shareports; - } ports[MAX_PORTS]; - unsigned int add_tag; - unsigned int remove_tag; - int num_vlans; - struct vlan_state { - unsigned int ports; - unsigned int tag; // VLAN tag (IP175D only) - } vlans[MAX_VLANS]; - const struct register_mappings *regs; - reg proc_mii; // phy/reg for the low level register access via swconfig - - char buf[80]; -}; - - -static int ip_phy_read(struct ip17xx_state *state, int port, int reg) -{ - int val = mdiobus_read(state->mii_bus, port, reg); - if (val < 0) - pr_warning("IP17xx: Unable to get MII register %d,%d: error %d\n", port, reg, -val); -#ifdef DUMP_MII_IO - else - pr_debug("IP17xx: Read MII(%d,%d) -> %04x\n", port, reg, val); -#endif - return val; -} - -static int ip_phy_write(struct ip17xx_state *state, int port, int reg, u16 val) -{ - int err; - -#ifdef DUMP_MII_IO - pr_debug("IP17xx: Write MII(%d,%d) <- %04x\n", port, reg, val); -#endif - err = mdiobus_write(state->mii_bus, port, reg, val); - if (err < 0) - pr_warning("IP17xx: Unable to write MII register %d,%d: error %d\n", port, reg, -err); - return err; -} - -static int ip_phy_write_masked(struct ip17xx_state *state, int port, int reg, unsigned int mask, unsigned int data) -{ - int val = ip_phy_read(state, port, reg); - if (val < 0) - return 0; - return ip_phy_write(state, port, reg, (val & ~mask) | data); -} - -static int getPhy(struct ip17xx_state *state, reg mii) -{ - if (!REG_SUPP(mii)) - return -EFAULT; - return ip_phy_read(state, mii.p, mii.m); -} - -static int setPhy(struct ip17xx_state *state, reg mii, u16 value) -{ - int err; - - if (!REG_SUPP(mii)) - return -EFAULT; - err = ip_phy_write(state, mii.p, mii.m, value); - if (err < 0) - return err; - getPhy(state, mii); - return 0; -} - - -/** - * These two macros are to simplify the mapping of logical bits to the bits in hardware. - * NOTE: these macros will return if there is an error! - */ - -#define GET_PORT_BITS(state, bits, addr, bit_lookup) \ - do { \ - int i, val = getPhy((state), (addr)); \ - if (val < 0) \ - return val; \ - (bits) = 0; \ - for (i = 0; i < MAX_PORTS; i++) { \ - if ((bit_lookup)[i] == -1) continue; \ - if (val & (1<<(bit_lookup)[i])) \ - (bits) |= (1<<i); \ - } \ - } while (0) - -#define SET_PORT_BITS(state, bits, addr, bit_lookup) \ - do { \ - int i, val = getPhy((state), (addr)); \ - if (val < 0) \ - return val; \ - for (i = 0; i < MAX_PORTS; i++) { \ - unsigned int newmask = ((bits)&(1<<i)); \ - if ((bit_lookup)[i] == -1) continue; \ - val &= ~(1<<(bit_lookup)[i]); \ - val |= ((newmask>>i)<<(bit_lookup)[i]); \ - } \ - val = setPhy((state), (addr), val); \ - if (val < 0) \ - return val; \ - } while (0) - - -static int get_model(struct ip17xx_state *state) -{ - int id1, id2; - int oui_id, model_no, rev_no, chip_no; - - id1 = ip_phy_read(state, 0, 2); - id2 = ip_phy_read(state, 0, 3); - oui_id = (id1 << 6) | ((id2 >> 10) & 0x3f); - model_no = (id2 >> 4) & 0x3f; - rev_no = id2 & 0xf; - pr_debug("IP17xx: Identified oui=%06x model=%02x rev=%X\n", oui_id, model_no, rev_no); - - if (oui_id != 0x0090c3) // No other oui_id should have reached us anyway - return -ENODEV; - - if (model_no == IP175A.MODEL_NO) { - state->regs = &IP175A; - } else if (model_no == IP175C.MODEL_NO) { - /* - * Several models share the same model_no: - * 178C has more PHYs, so we try whether the device responds to a read from PHY5 - * 175D has a new chip ID register - * 175C has neither - */ - if (ip_phy_read(state, 5, 2) == 0x0243) { - state->regs = &IP178C; - } else { - chip_no = ip_phy_read(state, 20, 0); - pr_debug("IP17xx: Chip ID register reads %04x\n", chip_no); - if (chip_no == 0x175d) { - state->regs = &IP175D; - } else { - state->regs = &IP175C; - } - } - } else { - pr_warning("IP17xx: Found an unknown IC+ switch with model number %02x, revision %X.\n", model_no, rev_no); - return -EPERM; - } - return 0; -} - -/*** Low-level functions for the older models ***/ - -/** Only set vlan and router flags in the switch **/ -static int ip175c_set_flags(struct ip17xx_state *state) -{ - int val; - - if (!REG_SUPP(state->regs->ROUTER_CONTROL_REG)) { - return 0; - } - - val = getPhy(state, state->regs->ROUTER_CONTROL_REG); - if (val < 0) { - return val; - } - if (state->regs->ROUTER_EN_BIT >= 0) { - if (state->router_mode) { - val |= (1<<state->regs->ROUTER_EN_BIT); - } else { - val &= (~(1<<state->regs->ROUTER_EN_BIT)); - } - } - if (state->regs->TAG_VLAN_BIT >= 0) { - if (state->vlan_enabled) { - val |= (1<<state->regs->TAG_VLAN_BIT); - } else { - val &= (~(1<<state->regs->TAG_VLAN_BIT)); - } - } - if (state->regs->NUMLAN_GROUPS_BIT >= 0) { - val &= (~((state->regs->NUMLAN_GROUPS_MAX-1)<<state->regs->NUMLAN_GROUPS_BIT)); - if (state->num_vlans > state->regs->NUMLAN_GROUPS_MAX) { - val |= state->regs->NUMLAN_GROUPS_MAX << state->regs->NUMLAN_GROUPS_BIT; - } else if (state->num_vlans >= 1) { - val |= (state->num_vlans-1) << state->regs->NUMLAN_GROUPS_BIT; - } - } - return setPhy(state, state->regs->ROUTER_CONTROL_REG, val); -} - -/** Set all VLAN and port state. Usually you should call "correct_vlan_state" first. **/ -static int ip175c_set_state(struct ip17xx_state *state) -{ - int j; - int i; - SET_PORT_BITS(state, state->add_tag, - state->regs->ADD_TAG_REG, state->regs->ADD_TAG_BIT); - SET_PORT_BITS(state, state->remove_tag, - state->regs->REMOVE_TAG_REG, state->regs->REMOVE_TAG_BIT); - - if (REG_SUPP(state->regs->VLAN_LOOKUP_REG)) { - for (j=0; j<state->regs->NUM_PORTS; j++) { - reg addr; - const bitnum *bit_lookup = (j%2==0)? - state->regs->VLAN_LOOKUP_EVEN_BIT: - state->regs->VLAN_LOOKUP_ODD_BIT; - - addr = state->regs->VLAN_LOOKUP_REG; - if (state->regs->SIMPLE_VLAN_REGISTERS) { - addr.m += j; - } else { - switch (j) { - case 0: - case 1: - break; - case 2: - case 3: - addr.m+=1; - break; - case 4: - addr.m+=2; - break; - case 5: - addr = state->regs->VLAN_LOOKUP_REG_5; - break; - default: - addr.m = -1; // shouldn't get here, but... - break; - } - } - //printf("shareports for %d is %02X\n",j,state->ports[j].shareports); - if (REG_SUPP(addr)) { - SET_PORT_BITS(state, state->ports[j].shareports, addr, bit_lookup); - } - } - } - if (REG_SUPP(state->regs->TAG_VLAN_MASK_REG)) { - for (j=0; j<MAX_VLANS; j++) { - reg addr = state->regs->TAG_VLAN_MASK_REG; - const bitnum *bit_lookup = (j%2==0)? - state->regs->TAG_VLAN_MASK_EVEN_BIT: - state->regs->TAG_VLAN_MASK_ODD_BIT; - unsigned int vlan_mask; - if (state->regs->SIMPLE_VLAN_REGISTERS) { - addr.m += j; - } else { - addr.m += j/2; - } - vlan_mask = state->vlans[j].ports; - SET_PORT_BITS(state, vlan_mask, addr, bit_lookup); - } - } - - for (i=0; i<MAX_PORTS; i++) { - if (REG_SUPP(state->regs->VLAN_DEFAULT_TAG_REG[i])) { - int err = setPhy(state, state->regs->VLAN_DEFAULT_TAG_REG[i], - state->ports[i].pvid); - if (err < 0) { - return err; - } - } - } - - return ip175c_set_flags(state); -} - -/** - * Uses only the VLAN port mask and the add tag mask to generate the other fields: - * which ports are part of the same VLAN, removing vlan tags, and VLAN tag ids. - */ -static void ip175c_correct_vlan_state(struct ip17xx_state *state) -{ - int i, j; - state->num_vlans = 0; - for (i=0; i<MAX_VLANS; i++) { - if (state->vlans[i].ports != 0) { - state->num_vlans = i+1; // Hack -- we need to store the "set" vlans somewhere... - } - } - - for (i=0; i<state->regs->NUM_PORTS; i++) { - unsigned int portmask = (1<<i); - if (!state->vlan_enabled) { - // Share with everybody! - state->ports[i].shareports = (1<<state->regs->NUM_PORTS)-1; - continue; - } - state->ports[i].shareports = portmask; - for (j=0; j<MAX_VLANS; j++) { - if (state->vlans[j].ports & portmask) - state->ports[i].shareports |= state->vlans[j].ports; - } - } -} - -static int ip175c_update_state(struct ip17xx_state *state) -{ - ip175c_correct_vlan_state(state); - return ip175c_set_state(state); -} - -static int ip175c_set_vlan_mode(struct ip17xx_state *state) -{ - return ip175c_update_state(state); -} - -static int ip175c_reset(struct ip17xx_state *state) -{ - int err; - - if (REG_SUPP(state->regs->MODE_REG)) { - err = setPhy(state, state->regs->MODE_REG, state->regs->MODE_VAL); - if (err < 0) - return err; - err = getPhy(state, state->regs->MODE_REG); - if (err < 0) - return err; - } - - return ip175c_update_state(state); -} - -/*** Low-level functions for IP175D ***/ - -static int ip175d_update_state(struct ip17xx_state *state) -{ - unsigned int filter_mask = 0; - unsigned int ports[16], add[16], rem[16]; - int i, j; - int err = 0; - - for (i = 0; i < 16; i++) { - ports[i] = 0; - add[i] = 0; - rem[i] = 0; - if (!state->vlan_enabled) { - err |= ip_phy_write(state, 22, 14+i, i+1); // default tags - ports[i] = 0x3f; - continue; - } - if (!state->vlans[i].tag) { - // Reset the filter - err |= ip_phy_write(state, 22, 14+i, 0); // tag - continue; - } - filter_mask |= 1 << i; - err |= ip_phy_write(state, 22, 14+i, state->vlans[i].tag); - ports[i] = state->vlans[i].ports; - for (j = 0; j < 6; j++) { - if (ports[i] & (1 << j)) { - if (state->add_tag & (1 << j)) - add[i] |= 1 << j; - if (state->remove_tag & (1 << j)) - rem[i] |= 1 << j; - } - } - } - - // Port masks, tag adds and removals - for (i = 0; i < 8; i++) { - err |= ip_phy_write(state, 23, i, ports[2*i] | (ports[2*i+1] << 8)); - err |= ip_phy_write(state, 23, 8+i, add[2*i] | (add[2*i+1] << 8)); - err |= ip_phy_write(state, 23, 16+i, rem[2*i] | (rem[2*i+1] << 8)); - } - err |= ip_phy_write(state, 22, 10, filter_mask); - - // Default VLAN tag for each port - for (i = 0; i < 6; i++) - err |= ip_phy_write(state, 22, 4+i, state->vlans[state->ports[i].pvid].tag); - - return (err ? -EIO : 0); -} - -static int ip175d_set_vlan_mode(struct ip17xx_state *state) -{ - int i; - int err = 0; - - if (state->vlan_enabled) { - // VLAN classification rules: tag-based VLANs, use VID to classify, - // drop packets that cannot be classified. - err |= ip_phy_write_masked(state, 22, 0, 0x3fff, 0x003f); - - // Ingress rules: CFI=1 dropped, null VID is untagged, VID=1 passed, - // VID=0xfff discarded, admin both tagged and untagged, ingress - // filters enabled. - err |= ip_phy_write_masked(state, 22, 1, 0x0fff, 0x0c3f); - - // Egress rules: IGMP processing off, keep VLAN header off - err |= ip_phy_write_masked(state, 22, 2, 0x0fff, 0x0000); - } else { - // VLAN classification rules: everything off & clear table - err |= ip_phy_write_masked(state, 22, 0, 0xbfff, 0x8000); - - // Ingress and egress rules: set to defaults - err |= ip_phy_write_masked(state, 22, 1, 0x0fff, 0x0c3f); - err |= ip_phy_write_masked(state, 22, 2, 0x0fff, 0x0000); - } - - // Reset default VLAN for each port to 0 - for (i = 0; i < 6; i++) - state->ports[i].pvid = 0; - - err |= ip175d_update_state(state); - - return (err ? -EIO : 0); -} - -static int ip175d_reset(struct ip17xx_state *state) -{ - int err = 0; - - // Disable the special tagging mode - err |= ip_phy_write_masked(state, 21, 22, 0x0003, 0x0000); - - // Set 802.1q protocol type - err |= ip_phy_write(state, 22, 3, 0x8100); - - state->vlan_enabled = 0; - err |= ip175d_set_vlan_mode(state); - - return (err ? -EIO : 0); -} - -/*** High-level functions ***/ - -static int ip17xx_get_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - struct ip17xx_state *state = dev->priv; - - val->value.i = state->vlan_enabled; - return 0; -} - -static void ip17xx_reset_vlan_config(struct ip17xx_state *state) -{ - int i; - - state->remove_tag = (state->vlan_enabled ? ((1<<state->regs->NUM_PORTS)-1) : 0x0000); - state->add_tag = 0x0000; - for (i = 0; i < MAX_VLANS; i++) { - state->vlans[i].ports = 0x0000; - state->vlans[i].tag = (i ? i : 16); - } - for (i = 0; i < MAX_PORTS; i++) - state->ports[i].pvid = 0; -} - -static int ip17xx_set_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - struct ip17xx_state *state = dev->priv; - int enable; - - enable = val->value.i; - if (state->vlan_enabled == enable) { - // Do not change any state. - return 0; - } - state->vlan_enabled = enable; - - // Otherwise, if we are switching state, set fields to a known default. - ip17xx_reset_vlan_config(state); - - return state->regs->set_vlan_mode(state); -} - -static int ip17xx_get_ports(struct switch_dev *dev, struct switch_val *val) -{ - struct ip17xx_state *state = dev->priv; - int b; - int ind; - unsigned int ports; - - if (val->port_vlan >= dev->vlans || val->port_vlan < 0) - return -EINVAL; - - ports = state->vlans[val->port_vlan].ports; - b = 0; - ind = 0; - while (b < MAX_PORTS) { - if (ports&1) { - int istagged = ((state->add_tag >> b) & 1); - val->value.ports[ind].id = b; - val->value.ports[ind].flags = (istagged << SWITCH_PORT_FLAG_TAGGED); - ind++; - } - b++; - ports >>= 1; - } - val->len = ind; - - return 0; -} - -static int ip17xx_set_ports(struct switch_dev *dev, struct switch_val *val) -{ - struct ip17xx_state *state = dev->priv; - int i; - - if (val->port_vlan >= dev->vlans || val->port_vlan < 0) - return -EINVAL; - - state->vlans[val->port_vlan].ports = 0; - for (i = 0; i < val->len; i++) { - unsigned int bitmask = (1<<val->value.ports[i].id); - state->vlans[val->port_vlan].ports |= bitmask; - if (val->value.ports[i].flags & (1<<SWITCH_PORT_FLAG_TAGGED)) { - state->add_tag |= bitmask; - state->remove_tag &= (~bitmask); - } else { - state->add_tag &= (~bitmask); - state->remove_tag |= bitmask; - } - } - - return state->regs->update_state(state); -} - -static int ip17xx_apply(struct switch_dev *dev) -{ - struct ip17xx_state *state = dev->priv; - - if (REG_SUPP(state->regs->MII_REGISTER_EN)) { - int val = getPhy(state, state->regs->MII_REGISTER_EN); - if (val < 0) { - return val; - } - val |= (1<<state->regs->MII_REGISTER_EN_BIT); - return setPhy(state, state->regs->MII_REGISTER_EN, val); - } - return 0; -} - -static int ip17xx_reset(struct switch_dev *dev) -{ - struct ip17xx_state *state = dev->priv; - int i, err; - - if (REG_SUPP(state->regs->RESET_REG)) { - err = setPhy(state, state->regs->RESET_REG, state->regs->RESET_VAL); - if (err < 0) - return err; - err = getPhy(state, state->regs->RESET_REG); - - /* - * Data sheet specifies reset period to be 2 msec. - * (I don't see any mention of the 2ms delay in the IP178C spec, only - * in IP175C, but it can't hurt.) - */ - mdelay(2); - } - - /* reset switch ports */ - for (i = 0; i < state->regs->NUM_PORTS-1; i++) { - err = ip_phy_write(state, i, MII_BMCR, BMCR_RESET); - if (err < 0) - return err; - } - - state->router_mode = 0; - state->vlan_enabled = 0; - ip17xx_reset_vlan_config(state); - - return state->regs->reset(state); -} - -static int ip17xx_get_tagged(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - struct ip17xx_state *state = dev->priv; - - if (state->add_tag & (1<<val->port_vlan)) { - if (state->remove_tag & (1<<val->port_vlan)) - val->value.i = 3; // shouldn't ever happen. - else - val->value.i = 1; - } else { - if (state->remove_tag & (1<<val->port_vlan)) - val->value.i = 0; - else - val->value.i = 2; - } - return 0; -} - -static int ip17xx_set_tagged(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - struct ip17xx_state *state = dev->priv; - - state->add_tag &= ~(1<<val->port_vlan); - state->remove_tag &= ~(1<<val->port_vlan); - - if (val->value.i == 0) - state->remove_tag |= (1<<val->port_vlan); - if (val->value.i == 1) - state->add_tag |= (1<<val->port_vlan); - - return state->regs->update_state(state); -} - -/** Get the current phy address */ -static int ip17xx_get_phy(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - struct ip17xx_state *state = dev->priv; - - val->value.i = state->proc_mii.p; - return 0; -} - -/** Set a new phy address for low level access to registers */ -static int ip17xx_set_phy(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - struct ip17xx_state *state = dev->priv; - int new_reg = val->value.i; - - if (new_reg < 0 || new_reg > 31) - state->proc_mii.p = (u16)-1; - else - state->proc_mii.p = (u16)new_reg; - return 0; -} - -/** Get the current register number */ -static int ip17xx_get_reg(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - struct ip17xx_state *state = dev->priv; - - val->value.i = state->proc_mii.m; - return 0; -} - -/** Set a new register address for low level access to registers */ -static int ip17xx_set_reg(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - struct ip17xx_state *state = dev->priv; - int new_reg = val->value.i; - - if (new_reg < 0 || new_reg > 31) - state->proc_mii.m = (u16)-1; - else - state->proc_mii.m = (u16)new_reg; - return 0; -} - -/** Get the register content of state->proc_mii */ -static int ip17xx_get_val(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - struct ip17xx_state *state = dev->priv; - int retval = -EINVAL; - if (REG_SUPP(state->proc_mii)) - retval = getPhy(state, state->proc_mii); - - if (retval < 0) { - return retval; - } else { - val->value.i = retval; - return 0; - } -} - -/** Write a value to the register defined by phy/reg above */ -static int ip17xx_set_val(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - struct ip17xx_state *state = dev->priv; - int myval, err = -EINVAL; - - myval = val->value.i; - if (myval <= 0xffff && myval >= 0 && REG_SUPP(state->proc_mii)) { - err = setPhy(state, state->proc_mii, (u16)myval); - } - return err; -} - -static int ip17xx_read_name(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - struct ip17xx_state *state = dev->priv; - val->value.s = state->regs->NAME; // Just a const pointer, won't be freed by swconfig. - return 0; -} - -static int ip17xx_get_tag(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - struct ip17xx_state *state = dev->priv; - int vlan = val->port_vlan; - - if (vlan < 0 || vlan >= MAX_VLANS) - return -EINVAL; - - val->value.i = state->vlans[vlan].tag; - return 0; -} - -static int ip17xx_set_tag(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - struct ip17xx_state *state = dev->priv; - int vlan = val->port_vlan; - int tag = val->value.i; - - if (vlan < 0 || vlan >= MAX_VLANS) - return -EINVAL; - - if (tag < 0 || tag > 4095) - return -EINVAL; - - state->vlans[vlan].tag = tag; - return state->regs->update_state(state); -} - -static int ip17xx_set_port_speed(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - struct ip17xx_state *state = dev->priv; - int nr = val->port_vlan; - int ctrl; - int autoneg; - int speed; - if (val->value.i == 100) { - speed = 1; - autoneg = 0; - } else if (val->value.i == 10) { - speed = 0; - autoneg = 0; - } else { - autoneg = 1; - speed = 1; - } - - /* Can't set speed for cpu port */ - if (nr == state->regs->CPU_PORT) - return -EINVAL; - - if (nr >= dev->ports || nr < 0) - return -EINVAL; - - ctrl = ip_phy_read(state, nr, 0); - if (ctrl < 0) - return -EIO; - - ctrl &= (~(1<<12)); - ctrl &= (~(1<<13)); - ctrl |= (autoneg<<12); - ctrl |= (speed<<13); - - return ip_phy_write(state, nr, 0, ctrl); -} - -static int ip17xx_get_port_speed(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - struct ip17xx_state *state = dev->priv; - int nr = val->port_vlan; - int speed, status; - - if (nr == state->regs->CPU_PORT) { - val->value.i = 100; - return 0; - } - - if (nr >= dev->ports || nr < 0) - return -EINVAL; - - status = ip_phy_read(state, nr, 1); - speed = ip_phy_read(state, nr, 18); - if (status < 0 || speed < 0) - return -EIO; - - if (status & 4) - val->value.i = ((speed & (1<<11)) ? 100 : 10); - else - val->value.i = 0; - - return 0; -} - -static int ip17xx_get_port_status(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - struct ip17xx_state *state = dev->priv; - int ctrl, speed, status; - int nr = val->port_vlan; - int len; - char *buf = state->buf; // fixed-length at 80. - - if (nr == state->regs->CPU_PORT) { - sprintf(buf, "up, 100 Mbps, cpu port"); - val->value.s = buf; - return 0; - } - - if (nr >= dev->ports || nr < 0) - return -EINVAL; - - ctrl = ip_phy_read(state, nr, 0); - status = ip_phy_read(state, nr, 1); - speed = ip_phy_read(state, nr, 18); - if (ctrl < 0 || status < 0 || speed < 0) - return -EIO; - - if (status & 4) - len = sprintf(buf, "up, %d Mbps, %s duplex", - ((speed & (1<<11)) ? 100 : 10), - ((speed & (1<<10)) ? "full" : "half")); - else - len = sprintf(buf, "down"); - - if (ctrl & (1<<12)) { - len += sprintf(buf+len, ", auto-negotiate"); - if (!(status & (1<<5))) - len += sprintf(buf+len, " (in progress)"); - } else { - len += sprintf(buf+len, ", fixed speed (%d)", - ((ctrl & (1<<13)) ? 100 : 10)); - } - - buf[len] = '\0'; - val->value.s = buf; - return 0; -} - -static int ip17xx_get_pvid(struct switch_dev *dev, int port, int *val) -{ - struct ip17xx_state *state = dev->priv; - - *val = state->ports[port].pvid; - return 0; -} - -static int ip17xx_set_pvid(struct switch_dev *dev, int port, int val) -{ - struct ip17xx_state *state = dev->priv; - - if (val < 0 || val >= MAX_VLANS) - return -EINVAL; - - state->ports[port].pvid = val; - return state->regs->update_state(state); -} - - -enum Ports { - IP17XX_PORT_STATUS, - IP17XX_PORT_LINK, - IP17XX_PORT_TAGGED, - IP17XX_PORT_PVID, -}; - -enum Globals { - IP17XX_ENABLE_VLAN, - IP17XX_GET_NAME, - IP17XX_REGISTER_PHY, - IP17XX_REGISTER_MII, - IP17XX_REGISTER_VALUE, - IP17XX_REGISTER_ERRNO, -}; - -enum Vlans { - IP17XX_VLAN_TAG, -}; - -static const struct switch_attr ip17xx_global[] = { - [IP17XX_ENABLE_VLAN] = { - .id = IP17XX_ENABLE_VLAN, - .type = SWITCH_TYPE_INT, - .name = "enable_vlan", - .description = "Flag to enable or disable VLANs and tagging", - .get = ip17xx_get_enable_vlan, - .set = ip17xx_set_enable_vlan, - }, - [IP17XX_GET_NAME] = { - .id = IP17XX_GET_NAME, - .type = SWITCH_TYPE_STRING, - .description = "Returns the type of IC+ chip.", - .name = "name", - .get = ip17xx_read_name, - .set = NULL, - }, - /* jal: added for low level debugging etc. */ - [IP17XX_REGISTER_PHY] = { - .id = IP17XX_REGISTER_PHY, - .type = SWITCH_TYPE_INT, - .description = "Direct register access: set PHY (0-4, or 29,30,31)", - .name = "phy", - .get = ip17xx_get_phy, - .set = ip17xx_set_phy, - }, - [IP17XX_REGISTER_MII] = { - .id = IP17XX_REGISTER_MII, - .type = SWITCH_TYPE_INT, - .description = "Direct register access: set MII register number (0-31)", - .name = "reg", - .get = ip17xx_get_reg, - .set = ip17xx_set_reg, - }, - [IP17XX_REGISTER_VALUE] = { - .id = IP17XX_REGISTER_VALUE, - .type = SWITCH_TYPE_INT, - .description = "Direct register access: read/write to register (0-65535)", - .name = "val", - .get = ip17xx_get_val, - .set = ip17xx_set_val, - }, -}; - -static const struct switch_attr ip17xx_vlan[] = { - [IP17XX_VLAN_TAG] = { - .id = IP17XX_VLAN_TAG, - .type = SWITCH_TYPE_INT, - .description = "VLAN tag (0-4095) [IP175D only]", - .name = "tag", - .get = ip17xx_get_tag, - .set = ip17xx_set_tag, - } -}; - -static const struct switch_attr ip17xx_port[] = { - [IP17XX_PORT_STATUS] = { - .id = IP17XX_PORT_STATUS, - .type = SWITCH_TYPE_STRING, - .description = "Returns Detailed port status", - .name = "status", - .get = ip17xx_get_port_status, - .set = NULL, - }, - [IP17XX_PORT_LINK] = { - .id = IP17XX_PORT_LINK, - .type = SWITCH_TYPE_INT, - .description = "Link speed. Can write 0 for auto-negotiate, or 10 or 100", - .name = "link", - .get = ip17xx_get_port_speed, - .set = ip17xx_set_port_speed, - }, - [IP17XX_PORT_TAGGED] = { - .id = IP17XX_PORT_LINK, - .type = SWITCH_TYPE_INT, - .description = "0 = untag, 1 = add tags, 2 = do not alter (This value is reset if vlans are altered)", - .name = "tagged", - .get = ip17xx_get_tagged, - .set = ip17xx_set_tagged, - }, -}; - -static int ip17xx_probe(struct phy_device *pdev) -{ - struct ip17xx_state *state; - struct switch_dev *dev; - int err; - - /* We only attach to PHY 0, but use all available PHYs */ - if (pdev->addr != 0) - return -ENODEV; - - state = kzalloc(sizeof(*state), GFP_KERNEL); - if (!state) - return -ENOMEM; - - dev = &state->dev; - dev->attr_global.attr = ip17xx_global; - dev->attr_global.n_attr = ARRAY_SIZE(ip17xx_global); - dev->attr_port.attr = ip17xx_port; - dev->attr_port.n_attr = ARRAY_SIZE(ip17xx_port); - dev->attr_vlan.attr = ip17xx_vlan; - dev->attr_vlan.n_attr = ARRAY_SIZE(ip17xx_vlan); - - dev->get_port_pvid = ip17xx_get_pvid; - dev->set_port_pvid = ip17xx_set_pvid; - dev->get_vlan_ports = ip17xx_get_ports; - dev->set_vlan_ports = ip17xx_set_ports; - dev->apply_config = ip17xx_apply; - dev->reset_switch = ip17xx_reset; - - dev->priv = state; - pdev->priv = state; - state->mii_bus = pdev->bus; - - err = get_model(state); - if (err < 0) - goto error; - - dev->vlans = MAX_VLANS; - dev->cpu_port = state->regs->CPU_PORT; - dev->ports = state->regs->NUM_PORTS; - dev->name = state->regs->NAME; - - pr_info("IP17xx: Found %s at %s\n", dev->name, dev_name(&pdev->dev)); - return 0; - -error: - kfree(state); - return err; -} - -static int ip17xx_config_init(struct phy_device *pdev) -{ - struct ip17xx_state *state = pdev->priv; - struct net_device *dev = pdev->attached_dev; - int err; - - err = register_switch(&state->dev, dev); - if (err < 0) - return err; - - state->registered = true; - ip17xx_reset(&state->dev); - return 0; -} - -static void ip17xx_remove(struct phy_device *pdev) -{ - struct ip17xx_state *state = pdev->priv; - - if (state->registered) - unregister_switch(&state->dev); - kfree(state); -} - -static int ip17xx_config_aneg(struct phy_device *pdev) -{ - return 0; -} - -static int ip17xx_aneg_done(struct phy_device *pdev) -{ - return BMSR_ANEGCOMPLETE; -} - -static int ip17xx_update_link(struct phy_device *pdev) -{ - pdev->link = 1; - return 0; -} - -static int ip17xx_read_status(struct phy_device *pdev) -{ - pdev->speed = SPEED_100; - pdev->duplex = DUPLEX_FULL; - pdev->pause = pdev->asym_pause = 0; - pdev->link = 1; - - return 0; -} - -static struct phy_driver ip17xx_driver = { - .name = "IC+ IP17xx", - .phy_id = 0x02430c00, - .phy_id_mask = 0x0ffffc00, - .features = PHY_BASIC_FEATURES, - .probe = ip17xx_probe, - .remove = ip17xx_remove, - .config_init = ip17xx_config_init, - .config_aneg = ip17xx_config_aneg, - .aneg_done = ip17xx_aneg_done, - .update_link = ip17xx_update_link, - .read_status = ip17xx_read_status, - .driver = { .owner = THIS_MODULE }, -}; - -static struct phy_driver ip175a_driver = { - .name = "IC+ IP175A", - .phy_id = 0x02430c50, - .phy_id_mask = 0x0ffffff0, - .features = PHY_BASIC_FEATURES, - .probe = ip17xx_probe, - .remove = ip17xx_remove, - .config_init = ip17xx_config_init, - .config_aneg = ip17xx_config_aneg, - .aneg_done = ip17xx_aneg_done, - .update_link = ip17xx_update_link, - .read_status = ip17xx_read_status, - .driver = { .owner = THIS_MODULE }, -}; - - -int __init ip17xx_init(void) -{ - int ret; - - ret = phy_driver_register(&ip175a_driver); - if (ret < 0) - return ret; - - return phy_driver_register(&ip17xx_driver); -} - -void __exit ip17xx_exit(void) -{ - phy_driver_unregister(&ip17xx_driver); - phy_driver_unregister(&ip175a_driver); -} - -MODULE_AUTHOR("Patrick Horn <patrick.horn@gmail.com>"); -MODULE_AUTHOR("Felix Fietkau <nbd@openwrt.org>"); -MODULE_AUTHOR("Martin Mares <mj@ucw.cz>"); -MODULE_LICENSE("GPL"); - -module_init(ip17xx_init); -module_exit(ip17xx_exit); diff --git a/target/linux/generic-2.6/files/drivers/net/phy/mvswitch.c b/target/linux/generic-2.6/files/drivers/net/phy/mvswitch.c deleted file mode 100644 index c2f324572..000000000 --- a/target/linux/generic-2.6/files/drivers/net/phy/mvswitch.c +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Marvell 88E6060 switch driver - * Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License v2 as published by the - * Free Software Foundation - */ -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/unistd.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/spinlock.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/mii.h> -#include <linux/ethtool.h> -#include <linux/phy.h> -#include <linux/if_vlan.h> - -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/uaccess.h> -#include "mvswitch.h" - -/* Undefine this to use trailer mode instead. - * I don't know if header mode works with all chips */ -#define HEADER_MODE 1 - -MODULE_DESCRIPTION("Marvell 88E6060 Switch driver"); -MODULE_AUTHOR("Felix Fietkau"); -MODULE_LICENSE("GPL"); - -#define MVSWITCH_MAGIC 0x88E6060 - -struct mvswitch_priv { - const struct net_device_ops *ndo_old; - struct net_device_ops ndo; - struct vlan_group *grp; - u8 vlans[16]; -}; - -#define to_mvsw(_phy) ((struct mvswitch_priv *) (_phy)->priv) - -static inline u16 -r16(struct phy_device *phydev, int addr, int reg) -{ - return phydev->bus->read(phydev->bus, addr, reg); -} - -static inline void -w16(struct phy_device *phydev, int addr, int reg, u16 val) -{ - phydev->bus->write(phydev->bus, addr, reg, val); -} - - -static int -mvswitch_mangle_tx(struct sk_buff *skb, struct net_device *dev) -{ - struct mvswitch_priv *priv; - char *buf = NULL; - u16 vid; - - priv = dev->phy_ptr; - if (unlikely(!priv)) - goto error; - - if (unlikely(skb->len < 16)) - goto error; - -#ifdef HEADER_MODE - if (__vlan_hwaccel_get_tag(skb, &vid)) - goto error; - - if (skb_cloned(skb) || (skb->len <= 62) || (skb_headroom(skb) < MV_HEADER_SIZE)) { - if (pskb_expand_head(skb, MV_HEADER_SIZE, (skb->len < 62 ? 62 - skb->len : 0), GFP_ATOMIC)) - goto error_expand; - if (skb->len < 62) - skb->len = 62; - } - buf = skb_push(skb, MV_HEADER_SIZE); -#else - if (__vlan_get_tag(skb, &vid)) - goto error; - - if (unlikely((vid > 15 || !priv->vlans[vid]))) - goto error; - - if (skb->len <= 64) { - if (pskb_expand_head(skb, 0, 64 + MV_TRAILER_SIZE - skb->len, GFP_ATOMIC)) - goto error_expand; - - buf = skb->data + 64; - skb->len = 64 + MV_TRAILER_SIZE; - } else { - if (skb_cloned(skb) || unlikely(skb_tailroom(skb) < 4)) { - if (pskb_expand_head(skb, 0, 4, GFP_ATOMIC)) - goto error_expand; - } - buf = skb_put(skb, 4); - } - - /* move the ethernet header 4 bytes forward, overwriting the vlan tag */ - memmove(skb->data + 4, skb->data, 12); - skb->data += 4; - skb->len -= 4; - skb->mac_header += 4; -#endif - - if (!buf) - goto error; - - -#ifdef HEADER_MODE - /* prepend the tag */ - *((__be16 *) buf) = cpu_to_be16( - ((vid << MV_HEADER_VLAN_S) & MV_HEADER_VLAN_M) | - ((priv->vlans[vid] << MV_HEADER_PORTS_S) & MV_HEADER_PORTS_M) - ); -#else - /* append the tag */ - *((__be32 *) buf) = cpu_to_be32(( - (MV_TRAILER_OVERRIDE << MV_TRAILER_FLAGS_S) | - ((priv->vlans[vid] & MV_TRAILER_PORTS_M) << MV_TRAILER_PORTS_S) - )); -#endif - - return priv->ndo_old->ndo_start_xmit(skb, dev); - -error_expand: - if (net_ratelimit()) - printk("%s: failed to expand/update skb for the switch\n", dev->name); - -error: - /* any errors? drop the packet! */ - dev_kfree_skb_any(skb); - return 0; -} - -static int -mvswitch_mangle_rx(struct sk_buff *skb, int napi) -{ - struct mvswitch_priv *priv; - struct net_device *dev; - int vlan = -1; - unsigned char *buf; - int i; - - dev = skb->dev; - if (!dev) - goto error; - - priv = dev->phy_ptr; - if (!priv) - goto error; - - if (!priv->grp) - goto error; - -#ifdef HEADER_MODE - buf = skb->data; - skb_pull(skb, MV_HEADER_SIZE); -#else - buf = skb->data + skb->len - MV_TRAILER_SIZE; - if (buf[0] != 0x80) - goto error; -#endif - - /* look for the vlan matching the incoming port */ - for (i = 0; i < ARRAY_SIZE(priv->vlans); i++) { - if ((1 << buf[1]) & priv->vlans[i]) - vlan = i; - } - - if (vlan == -1) - goto error; - - skb->protocol = eth_type_trans(skb, skb->dev); - - if (napi) - return vlan_hwaccel_receive_skb(skb, priv->grp, vlan); - else - return vlan_hwaccel_rx(skb, priv->grp, vlan); - -error: - /* no vlan? eat the packet! */ - dev_kfree_skb_any(skb); - return 0; -} - - -static int -mvswitch_netif_rx(struct sk_buff *skb) -{ - return mvswitch_mangle_rx(skb, 0); -} - -static int -mvswitch_netif_receive_skb(struct sk_buff *skb) -{ - return mvswitch_mangle_rx(skb, 1); -} - - -static void -mvswitch_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) -{ - struct mvswitch_priv *priv = dev->phy_ptr; - priv->grp = grp; -} - - -static int -mvswitch_wait_mask(struct phy_device *pdev, int addr, int reg, u16 mask, u16 val) -{ - int i = 100; - u16 r; - - do { - r = r16(pdev, addr, reg) & mask; - if (r == val) - return 0; - } while(--i > 0); - return -ETIMEDOUT; -} - -static int -mvswitch_config_init(struct phy_device *pdev) -{ - struct mvswitch_priv *priv = to_mvsw(pdev); - struct net_device *dev = pdev->attached_dev; - u8 vlmap = 0; - int i; - - if (!dev) - return -EINVAL; - - printk("%s: Marvell 88E6060 PHY driver attached.\n", dev->name); - pdev->supported = ADVERTISED_100baseT_Full; - pdev->advertising = ADVERTISED_100baseT_Full; - dev->phy_ptr = priv; - dev->irq = PHY_POLL; -#ifdef HEADER_MODE - dev->flags |= IFF_PROMISC; -#endif - - /* initialize default vlans */ - for (i = 0; i < MV_PORTS; i++) - priv->vlans[(i == MV_WANPORT ? 2 : 1)] |= (1 << i); - - /* before entering reset, disable all ports */ - for (i = 0; i < MV_PORTS; i++) - w16(pdev, MV_PORTREG(CONTROL, i), 0x00); - - msleep(2); /* wait for the status change to settle in */ - - /* put the ATU in reset */ - w16(pdev, MV_SWITCHREG(ATU_CTRL), MV_ATUCTL_RESET); - - i = mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_CTRL), MV_ATUCTL_RESET, 0); - if (i < 0) { - printk("%s: Timeout waiting for the switch to reset.\n", dev->name); - return i; - } - - /* set the ATU flags */ - w16(pdev, MV_SWITCHREG(ATU_CTRL), - MV_ATUCTL_NO_LEARN | - MV_ATUCTL_ATU_1K | - MV_ATUCTL_AGETIME(MV_ATUCTL_AGETIME_MIN) /* minimum without disabling ageing */ - ); - - /* initialize the cpu port */ - w16(pdev, MV_PORTREG(CONTROL, MV_CPUPORT), -#ifdef HEADER_MODE - MV_PORTCTRL_HEADER | -#else - MV_PORTCTRL_RXTR | - MV_PORTCTRL_TXTR | -#endif - MV_PORTCTRL_ENABLED - ); - /* wait for the phy change to settle in */ - msleep(2); - for (i = 0; i < MV_PORTS; i++) { - u8 pvid = 0; - int j; - - vlmap = 0; - - /* look for the matching vlan */ - for (j = 0; j < ARRAY_SIZE(priv->vlans); j++) { - if (priv->vlans[j] & (1 << i)) { - vlmap = priv->vlans[j]; - pvid = j; - } - } - /* leave port unconfigured if it's not part of a vlan */ - if (!vlmap) - continue; - - /* add the cpu port to the allowed destinations list */ - vlmap |= (1 << MV_CPUPORT); - - /* take port out of its own vlan destination map */ - vlmap &= ~(1 << i); - - /* apply vlan settings */ - w16(pdev, MV_PORTREG(VLANMAP, i), - MV_PORTVLAN_PORTS(vlmap) | - MV_PORTVLAN_ID(i) - ); - - /* re-enable port */ - w16(pdev, MV_PORTREG(CONTROL, i), - MV_PORTCTRL_ENABLED - ); - } - - w16(pdev, MV_PORTREG(VLANMAP, MV_CPUPORT), - MV_PORTVLAN_ID(MV_CPUPORT) - ); - - /* set the port association vector */ - for (i = 0; i <= MV_PORTS; i++) { - w16(pdev, MV_PORTREG(ASSOC, i), - MV_PORTASSOC_PORTS(1 << i) - ); - } - - /* init switch control */ - w16(pdev, MV_SWITCHREG(CTRL), - MV_SWITCHCTL_MSIZE | - MV_SWITCHCTL_DROP - ); - - /* hook into the tx function */ - priv->ndo_old = dev->netdev_ops; - memcpy(&priv->ndo, priv->ndo_old, sizeof(struct net_device_ops)); - priv->ndo.ndo_start_xmit = mvswitch_mangle_tx; - priv->ndo.ndo_vlan_rx_register = mvswitch_vlan_rx_register; - dev->netdev_ops = &priv->ndo; - - pdev->pkt_align = 2; - pdev->netif_receive_skb = mvswitch_netif_receive_skb; - pdev->netif_rx = mvswitch_netif_rx; -#ifdef HEADER_MODE - dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX; -#else - dev->features |= NETIF_F_HW_VLAN_RX; -#endif - - return 0; -} - -static int -mvswitch_read_status(struct phy_device *pdev) -{ - pdev->speed = SPEED_100; - pdev->duplex = DUPLEX_FULL; - pdev->link = 1; - - /* XXX ugly workaround: we can't force the switch - * to gracefully handle hosts moving from one port to another, - * so we have to regularly clear the ATU database */ - - /* wait for the ATU to become available */ - mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_OP), MV_ATUOP_INPROGRESS, 0); - - /* flush the ATU */ - w16(pdev, MV_SWITCHREG(ATU_OP), - MV_ATUOP_INPROGRESS | - MV_ATUOP_FLUSH_ALL - ); - - /* wait for operation to complete */ - mvswitch_wait_mask(pdev, MV_SWITCHREG(ATU_OP), MV_ATUOP_INPROGRESS, 0); - - return 0; -} - -static int -mvswitch_config_aneg(struct phy_device *phydev) -{ - return 0; -} - -static void -mvswitch_remove(struct phy_device *pdev) -{ - struct mvswitch_priv *priv = to_mvsw(pdev); - struct net_device *dev = pdev->attached_dev; - - /* restore old netdev ops */ - if (priv->ndo_old && dev) - dev->netdev_ops = priv->ndo_old; - dev->phy_ptr = NULL; - dev->features &= ~NETIF_F_HW_VLAN_RX; - kfree(priv); -} - -static int -mvswitch_probe(struct phy_device *pdev) -{ - struct mvswitch_priv *priv; - - priv = kzalloc(sizeof(struct mvswitch_priv), GFP_KERNEL); - if (priv == NULL) - return -ENOMEM; - - pdev->priv = priv; - - return 0; -} - -static int -mvswitch_fixup(struct phy_device *dev) -{ - u16 reg; - - if (dev->addr != 0x10) - return 0; - - reg = dev->bus->read(dev->bus, MV_PORTREG(IDENT, 0)) & MV_IDENT_MASK; - if (reg != MV_IDENT_VALUE) - return 0; - - dev->phy_id = MVSWITCH_MAGIC; - return 0; -} - - -static struct phy_driver mvswitch_driver = { - .name = "Marvell 88E6060", - .phy_id = MVSWITCH_MAGIC, - .phy_id_mask = 0xffffffff, - .features = PHY_BASIC_FEATURES, - .probe = &mvswitch_probe, - .remove = &mvswitch_remove, - .config_init = &mvswitch_config_init, - .config_aneg = &mvswitch_config_aneg, - .read_status = &mvswitch_read_status, - .driver = { .owner = THIS_MODULE,}, -}; - -static int __init -mvswitch_init(void) -{ - phy_register_fixup_for_id(PHY_ANY_ID, mvswitch_fixup); - return phy_driver_register(&mvswitch_driver); -} - -static void __exit -mvswitch_exit(void) -{ - phy_driver_unregister(&mvswitch_driver); -} - -module_init(mvswitch_init); -module_exit(mvswitch_exit); diff --git a/target/linux/generic-2.6/files/drivers/net/phy/mvswitch.h b/target/linux/generic-2.6/files/drivers/net/phy/mvswitch.h deleted file mode 100644 index 1563eec4d..000000000 --- a/target/linux/generic-2.6/files/drivers/net/phy/mvswitch.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Marvell 88E6060 switch driver - * Copyright (c) 2008 Felix Fietkau <nbd@openwrt.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License v2 as published by the - * Free Software Foundation - */ -#ifndef __MVSWITCH_H -#define __MVSWITCH_H - -#define MV_HEADER_SIZE 2 -#define MV_HEADER_PORTS_M 0x001f -#define MV_HEADER_PORTS_S 0 -#define MV_HEADER_VLAN_M 0xf000 -#define MV_HEADER_VLAN_S 12 - -#define MV_TRAILER_SIZE 4 -#define MV_TRAILER_PORTS_M 0x1f -#define MV_TRAILER_PORTS_S 16 -#define MV_TRAILER_FLAGS_S 24 -#define MV_TRAILER_OVERRIDE 0x80 - - -#define MV_PORTS 5 -#define MV_WANPORT 4 -#define MV_CPUPORT 5 - -#define MV_BASE 0x10 - -#define MV_PHYPORT_BASE (MV_BASE + 0x0) -#define MV_PHYPORT(_n) (MV_PHYPORT_BASE + (_n)) -#define MV_SWITCHPORT_BASE (MV_BASE + 0x8) -#define MV_SWITCHPORT(_n) (MV_SWITCHPORT_BASE + (_n)) -#define MV_SWITCHREGS (MV_BASE + 0xf) - -enum { - MV_PHY_CONTROL = 0x00, - MV_PHY_STATUS = 0x01, - MV_PHY_IDENT0 = 0x02, - MV_PHY_IDENT1 = 0x03, - MV_PHY_ANEG = 0x04, - MV_PHY_LINK_ABILITY = 0x05, - MV_PHY_ANEG_EXPAND = 0x06, - MV_PHY_XMIT_NEXTP = 0x07, - MV_PHY_LINK_NEXTP = 0x08, - MV_PHY_CONTROL1 = 0x10, - MV_PHY_STATUS1 = 0x11, - MV_PHY_INTR_EN = 0x12, - MV_PHY_INTR_STATUS = 0x13, - MV_PHY_INTR_PORT = 0x14, - MV_PHY_RECV_COUNTER = 0x16, - MV_PHY_LED_PARALLEL = 0x16, - MV_PHY_LED_STREAM = 0x17, - MV_PHY_LED_CTRL = 0x18, - MV_PHY_LED_OVERRIDE = 0x19, - MV_PHY_VCT_CTRL = 0x1a, - MV_PHY_VCT_STATUS = 0x1b, - MV_PHY_CONTROL2 = 0x1e -}; -#define MV_PHYREG(_type, _port) MV_PHYPORT(_port), MV_PHY_##_type - -enum { - MV_PORT_STATUS = 0x00, - MV_PORT_IDENT = 0x03, - MV_PORT_CONTROL = 0x04, - MV_PORT_VLANMAP = 0x06, - MV_PORT_ASSOC = 0x0b, - MV_PORT_RXCOUNT = 0x10, - MV_PORT_TXCOUNT = 0x11, -}; -#define MV_PORTREG(_type, _port) MV_SWITCHPORT(_port), MV_PORT_##_type - -enum { - MV_PORTCTRL_BLOCK = (1 << 0), - MV_PORTCTRL_LEARN = (2 << 0), - MV_PORTCTRL_ENABLED = (3 << 0), - MV_PORTCTRL_VLANTUN = (1 << 7), /* Enforce VLANs on packets */ - MV_PORTCTRL_RXTR = (1 << 8), /* Enable Marvell packet trailer for ingress */ - MV_PORTCTRL_HEADER = (1 << 11), /* Enable Marvell packet header mode for port */ - MV_PORTCTRL_TXTR = (1 << 14), /* Enable Marvell packet trailer for egress */ - MV_PORTCTRL_FORCEFL = (1 << 15), /* force flow control */ -}; - -#define MV_PORTVLAN_ID(_n) (((_n) & 0xf) << 12) -#define MV_PORTVLAN_PORTS(_n) ((_n) & 0x3f) - -#define MV_PORTASSOC_PORTS(_n) ((_n) & 0x1f) -#define MV_PORTASSOC_MONITOR (1 << 15) - -enum { - MV_SWITCH_MAC0 = 0x01, - MV_SWITCH_MAC1 = 0x02, - MV_SWITCH_MAC2 = 0x03, - MV_SWITCH_CTRL = 0x04, - MV_SWITCH_ATU_CTRL = 0x0a, - MV_SWITCH_ATU_OP = 0x0b, - MV_SWITCH_ATU_DATA = 0x0c, - MV_SWITCH_ATU_MAC0 = 0x0d, - MV_SWITCH_ATU_MAC1 = 0x0e, - MV_SWITCH_ATU_MAC2 = 0x0f, -}; -#define MV_SWITCHREG(_type) MV_SWITCHREGS, MV_SWITCH_##_type - -enum { - MV_SWITCHCTL_EEIE = (1 << 0), /* EEPROM interrupt enable */ - MV_SWITCHCTL_PHYIE = (1 << 1), /* PHY interrupt enable */ - MV_SWITCHCTL_ATUDONE= (1 << 2), /* ATU done interrupt enable */ - MV_SWITCHCTL_ATUIE = (1 << 3), /* ATU interrupt enable */ - MV_SWITCHCTL_CTRMODE= (1 << 8), /* statistics for rx and tx errors */ - MV_SWITCHCTL_RELOAD = (1 << 9), /* reload registers from eeprom */ - MV_SWITCHCTL_MSIZE = (1 << 10), /* increase maximum frame size */ - MV_SWITCHCTL_DROP = (1 << 13), /* discard frames with excessive collisions */ -}; - -enum { -#define MV_ATUCTL_AGETIME_MIN 16 -#define MV_ATUCTL_AGETIME_MAX 4080 -#define MV_ATUCTL_AGETIME(_n) ((((_n) / 16) & 0xff) << 4) - MV_ATUCTL_ATU_256 = (0 << 12), - MV_ATUCTL_ATU_512 = (1 << 12), - MV_ATUCTL_ATU_1K = (2 << 12), - MV_ATUCTL_ATUMASK = (3 << 12), - MV_ATUCTL_NO_LEARN = (1 << 14), - MV_ATUCTL_RESET = (1 << 15), -}; - -enum { -#define MV_ATUOP_DBNUM(_n) ((_n) & 0x0f) - - MV_ATUOP_NOOP = (0 << 12), - MV_ATUOP_FLUSH_ALL = (1 << 12), - MV_ATUOP_FLUSH_U = (2 << 12), - MV_ATUOP_LOAD_DB = (3 << 12), - MV_ATUOP_GET_NEXT = (4 << 12), - MV_ATUOP_FLUSH_DB = (5 << 12), - MV_ATUOP_FLUSH_DB_UU= (6 << 12), - - MV_ATUOP_INPROGRESS = (1 << 15), -}; - -#define MV_IDENT_MASK 0xfff0 -#define MV_IDENT_VALUE 0x0600 - -#endif diff --git a/target/linux/generic-2.6/files/drivers/net/phy/rtl8306.c b/target/linux/generic-2.6/files/drivers/net/phy/rtl8306.c deleted file mode 100644 index 901b5b2f8..000000000 --- a/target/linux/generic-2.6/files/drivers/net/phy/rtl8306.c +++ /dev/null @@ -1,1058 +0,0 @@ -/* - * rtl8306.c: RTL8306S switch driver - * - * Copyright (C) 2009 Felix Fietkau <nbd@openwrt.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/if.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/list.h> -#include <linux/if_ether.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/netlink.h> -#include <net/genetlink.h> -#include <linux/switch.h> -#include <linux/delay.h> -#include <linux/phy.h> - -//#define DEBUG 1 - -/* Global (PHY0) */ -#define RTL8306_REG_PAGE 16 -#define RTL8306_REG_PAGE_LO (1 << 15) -#define RTL8306_REG_PAGE_HI (1 << 1) /* inverted */ - -#define RTL8306_NUM_VLANS 16 -#define RTL8306_NUM_PORTS 6 -#define RTL8306_PORT_CPU 5 -#define RTL8306_NUM_PAGES 4 -#define RTL8306_NUM_REGS 32 - -#define RTL_NAME_S "RTL8306S" -#define RTL_NAME_SD "RTL8306SD" -#define RTL_NAME_SDM "RTL8306SDM" -#define RTL_NAME_UNKNOWN "RTL8306(unknown)" - -#define RTL8306_MAGIC 0x8306 - -static LIST_HEAD(phydevs); - -struct rtl_priv { - struct list_head list; - struct switch_dev dev; - int page; - int type; - int do_cpu; - struct mii_bus *bus; - char hwname[sizeof(RTL_NAME_UNKNOWN)]; -}; - -struct rtl_phyregs { - int nway; - int speed; - int duplex; -}; - -#define to_rtl(_dev) container_of(_dev, struct rtl_priv, dev) - -enum { - RTL_TYPE_S, - RTL_TYPE_SD, - RTL_TYPE_SDM, -}; - -struct rtl_reg { - int page; - int phy; - int reg; - int bits; - int shift; - int inverted; -}; - -#define RTL_VLAN_REGOFS(name) \ - (RTL_REG_VLAN1_##name - RTL_REG_VLAN0_##name) - -#define RTL_PORT_REGOFS(name) \ - (RTL_REG_PORT1_##name - RTL_REG_PORT0_##name) - -#define RTL_PORT_REG(id, reg) \ - (RTL_REG_PORT0_##reg + (id * RTL_PORT_REGOFS(reg))) - -#define RTL_VLAN_REG(id, reg) \ - (RTL_REG_VLAN0_##reg + (id * RTL_VLAN_REGOFS(reg))) - -#define RTL_GLOBAL_REGATTR(reg) \ - .id = RTL_REG_##reg, \ - .type = SWITCH_TYPE_INT, \ - .ofs = 0, \ - .set = rtl_attr_set_int, \ - .get = rtl_attr_get_int - -#define RTL_PORT_REGATTR(reg) \ - .id = RTL_REG_PORT0_##reg, \ - .type = SWITCH_TYPE_INT, \ - .ofs = RTL_PORT_REGOFS(reg), \ - .set = rtl_attr_set_port_int, \ - .get = rtl_attr_get_port_int - -#define RTL_VLAN_REGATTR(reg) \ - .id = RTL_REG_VLAN0_##reg, \ - .type = SWITCH_TYPE_INT, \ - .ofs = RTL_VLAN_REGOFS(reg), \ - .set = rtl_attr_set_vlan_int, \ - .get = rtl_attr_get_vlan_int - -enum rtl_regidx { - RTL_REG_CHIPID, - RTL_REG_CHIPVER, - RTL_REG_CHIPTYPE, - RTL_REG_CPUPORT, - - RTL_REG_EN_CPUPORT, - RTL_REG_EN_TAG_OUT, - RTL_REG_EN_TAG_CLR, - RTL_REG_EN_TAG_IN, - RTL_REG_TRAP_CPU, - RTL_REG_TRUNK_PORTSEL, - RTL_REG_EN_TRUNK, - RTL_REG_RESET, - - RTL_REG_VLAN_ENABLE, - RTL_REG_VLAN_FILTER, - RTL_REG_VLAN_TAG_ONLY, - RTL_REG_VLAN_TAG_AWARE, -#define RTL_VLAN_ENUM(id) \ - RTL_REG_VLAN##id##_VID, \ - RTL_REG_VLAN##id##_PORTMASK - RTL_VLAN_ENUM(0), - RTL_VLAN_ENUM(1), - RTL_VLAN_ENUM(2), - RTL_VLAN_ENUM(3), - RTL_VLAN_ENUM(4), - RTL_VLAN_ENUM(5), - RTL_VLAN_ENUM(6), - RTL_VLAN_ENUM(7), - RTL_VLAN_ENUM(8), - RTL_VLAN_ENUM(9), - RTL_VLAN_ENUM(10), - RTL_VLAN_ENUM(11), - RTL_VLAN_ENUM(12), - RTL_VLAN_ENUM(13), - RTL_VLAN_ENUM(14), - RTL_VLAN_ENUM(15), -#define RTL_PORT_ENUM(id) \ - RTL_REG_PORT##id##_PVID, \ - RTL_REG_PORT##id##_NULL_VID_REPLACE, \ - RTL_REG_PORT##id##_NON_PVID_DISCARD, \ - RTL_REG_PORT##id##_VID_INSERT, \ - RTL_REG_PORT##id##_TAG_INSERT, \ - RTL_REG_PORT##id##_LINK, \ - RTL_REG_PORT##id##_SPEED, \ - RTL_REG_PORT##id##_NWAY, \ - RTL_REG_PORT##id##_NRESTART, \ - RTL_REG_PORT##id##_DUPLEX, \ - RTL_REG_PORT##id##_RXEN, \ - RTL_REG_PORT##id##_TXEN - RTL_PORT_ENUM(0), - RTL_PORT_ENUM(1), - RTL_PORT_ENUM(2), - RTL_PORT_ENUM(3), - RTL_PORT_ENUM(4), - RTL_PORT_ENUM(5), -}; - -static const struct rtl_reg rtl_regs[] = { - [RTL_REG_CHIPID] = { 0, 4, 30, 16, 0, 0 }, - [RTL_REG_CHIPVER] = { 0, 4, 31, 8, 0, 0 }, - [RTL_REG_CHIPTYPE] = { 0, 4, 31, 2, 8, 0 }, - - /* CPU port number */ - [RTL_REG_CPUPORT] = { 2, 4, 21, 3, 0, 0 }, - /* Enable CPU port function */ - [RTL_REG_EN_CPUPORT] = { 3, 2, 21, 1, 15, 1 }, - /* Enable CPU port tag insertion */ - [RTL_REG_EN_TAG_OUT] = { 3, 2, 21, 1, 12, 0 }, - /* Enable CPU port tag removal */ - [RTL_REG_EN_TAG_CLR] = { 3, 2, 21, 1, 11, 0 }, - /* Enable CPU port tag checking */ - [RTL_REG_EN_TAG_IN] = { 0, 4, 21, 1, 7, 0 }, - [RTL_REG_EN_TRUNK] = { 0, 0, 19, 1, 11, 1 }, - [RTL_REG_TRUNK_PORTSEL] = { 0, 0, 16, 1, 6, 1 }, - [RTL_REG_RESET] = { 0, 0, 16, 1, 12, 0 }, - - [RTL_REG_TRAP_CPU] = { 3, 2, 22, 1, 6, 0 }, - - [RTL_REG_VLAN_TAG_ONLY] = { 0, 0, 16, 1, 8, 1 }, - [RTL_REG_VLAN_FILTER] = { 0, 0, 16, 1, 9, 1 }, - [RTL_REG_VLAN_TAG_AWARE] = { 0, 0, 16, 1, 10, 1 }, - [RTL_REG_VLAN_ENABLE] = { 0, 0, 18, 1, 8, 1 }, - -#define RTL_VLAN_REGS(id, phy, page, regofs) \ - [RTL_REG_VLAN##id##_VID] = { page, phy, 25 + regofs, 12, 0, 0 }, \ - [RTL_REG_VLAN##id##_PORTMASK] = { page, phy, 24 + regofs, 6, 0, 0 } - RTL_VLAN_REGS( 0, 0, 0, 0), - RTL_VLAN_REGS( 1, 1, 0, 0), - RTL_VLAN_REGS( 2, 2, 0, 0), - RTL_VLAN_REGS( 3, 3, 0, 0), - RTL_VLAN_REGS( 4, 4, 0, 0), - RTL_VLAN_REGS( 5, 0, 1, 2), - RTL_VLAN_REGS( 6, 1, 1, 2), - RTL_VLAN_REGS( 7, 2, 1, 2), - RTL_VLAN_REGS( 8, 3, 1, 2), - RTL_VLAN_REGS( 9, 4, 1, 2), - RTL_VLAN_REGS(10, 0, 1, 4), - RTL_VLAN_REGS(11, 1, 1, 4), - RTL_VLAN_REGS(12, 2, 1, 4), - RTL_VLAN_REGS(13, 3, 1, 4), - RTL_VLAN_REGS(14, 4, 1, 4), - RTL_VLAN_REGS(15, 0, 1, 6), - -#define REG_PORT_SETTING(port, phy) \ - [RTL_REG_PORT##port##_SPEED] = { 0, phy, 0, 1, 13, 0 }, \ - [RTL_REG_PORT##port##_NWAY] = { 0, phy, 0, 1, 12, 0 }, \ - [RTL_REG_PORT##port##_NRESTART] = { 0, phy, 0, 1, 9, 0 }, \ - [RTL_REG_PORT##port##_DUPLEX] = { 0, phy, 0, 1, 8, 0 }, \ - [RTL_REG_PORT##port##_TXEN] = { 0, phy, 24, 1, 11, 0 }, \ - [RTL_REG_PORT##port##_RXEN] = { 0, phy, 24, 1, 10, 0 }, \ - [RTL_REG_PORT##port##_LINK] = { 0, phy, 1, 1, 2, 0 }, \ - [RTL_REG_PORT##port##_NULL_VID_REPLACE] = { 0, phy, 22, 1, 12, 0 }, \ - [RTL_REG_PORT##port##_NON_PVID_DISCARD] = { 0, phy, 22, 1, 11, 0 }, \ - [RTL_REG_PORT##port##_VID_INSERT] = { 0, phy, 22, 2, 9, 0 }, \ - [RTL_REG_PORT##port##_TAG_INSERT] = { 0, phy, 22, 2, 0, 0 } - - REG_PORT_SETTING(0, 0), - REG_PORT_SETTING(1, 1), - REG_PORT_SETTING(2, 2), - REG_PORT_SETTING(3, 3), - REG_PORT_SETTING(4, 4), - REG_PORT_SETTING(5, 6), - -#define REG_PORT_PVID(phy, page, regofs) \ - { page, phy, 24 + regofs, 4, 12, 0 } - [RTL_REG_PORT0_PVID] = REG_PORT_PVID(0, 0, 0), - [RTL_REG_PORT1_PVID] = REG_PORT_PVID(1, 0, 0), - [RTL_REG_PORT2_PVID] = REG_PORT_PVID(2, 0, 0), - [RTL_REG_PORT3_PVID] = REG_PORT_PVID(3, 0, 0), - [RTL_REG_PORT4_PVID] = REG_PORT_PVID(4, 0, 0), - [RTL_REG_PORT5_PVID] = REG_PORT_PVID(0, 1, 2), -}; - - -/* IFXMIPS compat stuff - remove after PHY layer migration */ -static struct switch_dev rtldev; -/* END IFXMIPS compat stuff */ - - -static inline void -rtl_set_page(struct rtl_priv *priv, unsigned int page) -{ - struct mii_bus *bus = priv->bus; - u16 pgsel; - - if (priv->page == page) - return; - - BUG_ON(page > RTL8306_NUM_PAGES); - pgsel = bus->read(bus, 0, RTL8306_REG_PAGE); - pgsel &= ~(RTL8306_REG_PAGE_LO | RTL8306_REG_PAGE_HI); - if (page & (1 << 0)) - pgsel |= RTL8306_REG_PAGE_LO; - if (!(page & (1 << 1))) /* bit is inverted */ - pgsel |= RTL8306_REG_PAGE_HI; - bus->write(bus, 0, RTL8306_REG_PAGE, pgsel); -} - -static inline int -rtl_w16(struct switch_dev *dev, unsigned int page, unsigned int phy, unsigned int reg, u16 val) -{ - struct rtl_priv *priv = to_rtl(dev); - struct mii_bus *bus = priv->bus; - - rtl_set_page(priv, page); - bus->write(bus, phy, reg, val); - bus->read(bus, phy, reg); /* flush */ - return 0; -} - -static inline int -rtl_r16(struct switch_dev *dev, unsigned int page, unsigned int phy, unsigned int reg) -{ - struct rtl_priv *priv = to_rtl(dev); - struct mii_bus *bus = priv->bus; - - rtl_set_page(priv, page); - return bus->read(bus, phy, reg); -} - -static inline u16 -rtl_rmw(struct switch_dev *dev, unsigned int page, unsigned int phy, unsigned int reg, u16 mask, u16 val) -{ - struct rtl_priv *priv = to_rtl(dev); - struct mii_bus *bus = priv->bus; - u16 r; - - rtl_set_page(priv, page); - r = bus->read(bus, phy, reg); - r &= ~mask; - r |= val; - bus->write(bus, phy, reg, r); - return bus->read(bus, phy, reg); /* flush */ -} - - -static inline int -rtl_get(struct switch_dev *dev, enum rtl_regidx s) -{ - const struct rtl_reg *r = &rtl_regs[s]; - u16 val; - - BUG_ON(s >= ARRAY_SIZE(rtl_regs)); - if (r->bits == 0) /* unimplemented */ - return 0; - - val = rtl_r16(dev, r->page, r->phy, r->reg); - - if (r->shift > 0) - val >>= r->shift; - - if (r->inverted) - val = ~val; - - val &= (1 << r->bits) - 1; - - return val; -} - -static int -rtl_set(struct switch_dev *dev, enum rtl_regidx s, unsigned int val) -{ - const struct rtl_reg *r = &rtl_regs[s]; - u16 mask = 0xffff; - - BUG_ON(s >= ARRAY_SIZE(rtl_regs)); - - if (r->bits == 0) /* unimplemented */ - return 0; - - if (r->shift > 0) - val <<= r->shift; - - if (r->inverted) - val = ~val; - - if (r->bits != 16) { - mask = (1 << r->bits) - 1; - mask <<= r->shift; - } - val &= mask; - return rtl_rmw(dev, r->page, r->phy, r->reg, mask, val); -} - -static void -rtl_phy_save(struct switch_dev *dev, int port, struct rtl_phyregs *regs) -{ - regs->nway = rtl_get(dev, RTL_PORT_REG(port, NWAY)); - regs->speed = rtl_get(dev, RTL_PORT_REG(port, SPEED)); - regs->duplex = rtl_get(dev, RTL_PORT_REG(port, DUPLEX)); -} - -static void -rtl_phy_restore(struct switch_dev *dev, int port, struct rtl_phyregs *regs) -{ - rtl_set(dev, RTL_PORT_REG(port, NWAY), regs->nway); - rtl_set(dev, RTL_PORT_REG(port, SPEED), regs->speed); - rtl_set(dev, RTL_PORT_REG(port, DUPLEX), regs->duplex); -} - -static void -rtl_port_set_enable(struct switch_dev *dev, int port, int enabled) -{ - rtl_set(dev, RTL_PORT_REG(port, RXEN), enabled); - rtl_set(dev, RTL_PORT_REG(port, TXEN), enabled); - - if ((port >= 5) || !enabled) - return; - - /* restart autonegotiation if enabled */ - rtl_set(dev, RTL_PORT_REG(port, NRESTART), 1); -} - -static int -rtl_hw_apply(struct switch_dev *dev) -{ - int i; - int trunk_en, trunk_psel; - struct rtl_phyregs port5; - - rtl_phy_save(dev, 5, &port5); - - /* disable rx/tx from PHYs */ - for (i = 0; i < RTL8306_NUM_PORTS - 1; i++) { - rtl_port_set_enable(dev, i, 0); - } - - /* save trunking status */ - trunk_en = rtl_get(dev, RTL_REG_EN_TRUNK); - trunk_psel = rtl_get(dev, RTL_REG_TRUNK_PORTSEL); - - /* trunk port 3 and 4 - * XXX: Big WTF, but RealTek seems to do it */ - rtl_set(dev, RTL_REG_EN_TRUNK, 1); - rtl_set(dev, RTL_REG_TRUNK_PORTSEL, 1); - - /* execute the software reset */ - rtl_set(dev, RTL_REG_RESET, 1); - - /* wait for the reset to complete, - * but don't wait for too long */ - for (i = 0; i < 10; i++) { - if (rtl_get(dev, RTL_REG_RESET) == 0) - break; - - msleep(1); - } - - /* enable rx/tx from PHYs */ - for (i = 0; i < RTL8306_NUM_PORTS - 1; i++) { - rtl_port_set_enable(dev, i, 1); - } - - /* restore trunking settings */ - rtl_set(dev, RTL_REG_EN_TRUNK, trunk_en); - rtl_set(dev, RTL_REG_TRUNK_PORTSEL, trunk_psel); - rtl_phy_restore(dev, 5, &port5); - - return 0; -} - -static void -rtl_hw_init(struct switch_dev *dev) -{ - struct rtl_priv *priv = to_rtl(dev); - int cpu_mask = 1 << dev->cpu_port; - int i; - - rtl_set(dev, RTL_REG_VLAN_ENABLE, 0); - rtl_set(dev, RTL_REG_VLAN_FILTER, 0); - rtl_set(dev, RTL_REG_EN_TRUNK, 0); - rtl_set(dev, RTL_REG_TRUNK_PORTSEL, 0); - - /* initialize cpu port settings */ - if (priv->do_cpu) { - rtl_set(dev, RTL_REG_CPUPORT, dev->cpu_port); - rtl_set(dev, RTL_REG_EN_CPUPORT, 1); - } else { - rtl_set(dev, RTL_REG_CPUPORT, 7); - rtl_set(dev, RTL_REG_EN_CPUPORT, 0); - } - rtl_set(dev, RTL_REG_EN_TAG_OUT, 0); - rtl_set(dev, RTL_REG_EN_TAG_IN, 0); - rtl_set(dev, RTL_REG_EN_TAG_CLR, 0); - - /* reset all vlans */ - for (i = 0; i < RTL8306_NUM_VLANS; i++) { - rtl_set(dev, RTL_VLAN_REG(i, VID), i); - rtl_set(dev, RTL_VLAN_REG(i, PORTMASK), 0); - } - - /* default to port isolation */ - for (i = 0; i < RTL8306_NUM_PORTS; i++) { - unsigned long mask; - - if ((1 << i) == cpu_mask) - mask = ((1 << RTL8306_NUM_PORTS) - 1) & ~cpu_mask; /* all bits set */ - else - mask = cpu_mask | (1 << i); - - rtl_set(dev, RTL_VLAN_REG(i, PORTMASK), mask); - rtl_set(dev, RTL_PORT_REG(i, PVID), i); - rtl_set(dev, RTL_PORT_REG(i, NULL_VID_REPLACE), 1); - rtl_set(dev, RTL_PORT_REG(i, VID_INSERT), 1); - rtl_set(dev, RTL_PORT_REG(i, TAG_INSERT), 3); - } - rtl_hw_apply(dev); -} - -#ifdef DEBUG -static int -rtl_set_use_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - struct rtl_priv *priv = to_rtl(dev); - priv->do_cpu = val->value.i; - rtl_hw_init(dev); - return 0; -} - -static int -rtl_get_use_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - struct rtl_priv *priv = to_rtl(dev); - val->value.i = priv->do_cpu; - return 0; -} - -static int -rtl_set_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - dev->cpu_port = val->value.i; - rtl_hw_init(dev); - return 0; -} - -static int -rtl_get_cpuport(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - val->value.i = dev->cpu_port; - return 0; -} -#endif - -static int -rtl_reset(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - rtl_hw_init(dev); - return 0; -} - -static int -rtl_attr_set_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - int idx = attr->id + (val->port_vlan * attr->ofs); - struct rtl_phyregs port; - - if (attr->id >= ARRAY_SIZE(rtl_regs)) - return -EINVAL; - - if ((attr->max > 0) && (val->value.i > attr->max)) - return -EINVAL; - - /* access to phy register 22 on port 4/5 - * needs phy status save/restore */ - if ((val->port_vlan > 3) && - (rtl_regs[idx].reg == 22) && - (rtl_regs[idx].page == 0)) { - - rtl_phy_save(dev, val->port_vlan, &port); - rtl_set(dev, idx, val->value.i); - rtl_phy_restore(dev, val->port_vlan, &port); - } else { - rtl_set(dev, idx, val->value.i); - } - - return 0; -} - -static int -rtl_attr_get_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - int idx = attr->id + (val->port_vlan * attr->ofs); - - if (idx >= ARRAY_SIZE(rtl_regs)) - return -EINVAL; - - val->value.i = rtl_get(dev, idx); - return 0; -} - -static int -rtl_attr_set_port_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - if (val->port_vlan >= RTL8306_NUM_PORTS) - return -EINVAL; - - return rtl_attr_set_int(dev, attr, val); -} - -static int -rtl_attr_get_port_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - if (val->port_vlan >= RTL8306_NUM_PORTS) - return -EINVAL; - return rtl_attr_get_int(dev, attr, val); -} - -static int -rtl_attr_set_vlan_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - if (val->port_vlan >= dev->vlans) - return -EINVAL; - - return rtl_attr_set_int(dev, attr, val); -} - -static int -rtl_attr_get_vlan_int(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - if (val->port_vlan >= dev->vlans) - return -EINVAL; - - return rtl_attr_get_int(dev, attr, val); -} - -static int -rtl_get_ports(struct switch_dev *dev, struct switch_val *val) -{ - unsigned int i, mask; - - mask = rtl_get(dev, RTL_VLAN_REG(val->port_vlan, PORTMASK)); - for (i = 0; i < RTL8306_NUM_PORTS; i++) { - struct switch_port *port; - - if (!(mask & (1 << i))) - continue; - - port = &val->value.ports[val->len]; - port->id = i; - port->flags = 0; - val->len++; - } - - return 0; -} - -static int -rtl_set_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - struct rtl_priv *priv = to_rtl(dev); - struct rtl_phyregs port; - int en = val->value.i; - int i; - - rtl_set(dev, RTL_REG_EN_TAG_OUT, en && priv->do_cpu); - rtl_set(dev, RTL_REG_EN_TAG_IN, en && priv->do_cpu); - rtl_set(dev, RTL_REG_EN_TAG_CLR, en && priv->do_cpu); - rtl_set(dev, RTL_REG_VLAN_TAG_AWARE, en); - if (en) - rtl_set(dev, RTL_REG_VLAN_FILTER, en); - - for (i = 0; i < RTL8306_NUM_PORTS; i++) { - if (i > 3) - rtl_phy_save(dev, val->port_vlan, &port); - rtl_set(dev, RTL_PORT_REG(i, NULL_VID_REPLACE), 1); - rtl_set(dev, RTL_PORT_REG(i, VID_INSERT), (en ? (i == dev->cpu_port ? 0 : 1) : 1)); - rtl_set(dev, RTL_PORT_REG(i, TAG_INSERT), (en ? (i == dev->cpu_port ? 2 : 1) : 3)); - if (i > 3) - rtl_phy_restore(dev, val->port_vlan, &port); - } - rtl_set(dev, RTL_REG_VLAN_ENABLE, en); - - return 0; -} - -static int -rtl_get_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - return rtl_get(dev, RTL_REG_VLAN_ENABLE); -} - -static int -rtl_set_ports(struct switch_dev *dev, struct switch_val *val) -{ - unsigned int mask = 0; - unsigned int oldmask; - int i; - - for(i = 0; i < val->len; i++) - { - struct switch_port *port = &val->value.ports[i]; - bool tagged = false; - - mask |= (1 << port->id); - - if (port->id == dev->cpu_port) - continue; - - if ((i == dev->cpu_port) || - (port->flags & (1 << SWITCH_PORT_FLAG_TAGGED))) - tagged = true; - - /* fix up PVIDs for added ports */ - if (!tagged) - rtl_set(dev, RTL_PORT_REG(port->id, PVID), val->port_vlan); - - rtl_set(dev, RTL_PORT_REG(port->id, NON_PVID_DISCARD), (tagged ? 0 : 1)); - rtl_set(dev, RTL_PORT_REG(port->id, VID_INSERT), (tagged ? 0 : 1)); - rtl_set(dev, RTL_PORT_REG(port->id, TAG_INSERT), (tagged ? 2 : 1)); - } - - oldmask = rtl_get(dev, RTL_VLAN_REG(val->port_vlan, PORTMASK)); - rtl_set(dev, RTL_VLAN_REG(val->port_vlan, PORTMASK), mask); - - /* fix up PVIDs for removed ports, default to last vlan */ - oldmask &= ~mask; - for (i = 0; i < RTL8306_NUM_PORTS; i++) { - if (!(oldmask & (1 << i))) - continue; - - if (i == dev->cpu_port) - continue; - - if (rtl_get(dev, RTL_PORT_REG(i, PVID)) == val->port_vlan) - rtl_set(dev, RTL_PORT_REG(i, PVID), dev->vlans - 1); - } - - return 0; -} - -static int -rtl8306_config_init(struct phy_device *pdev) -{ - struct net_device *netdev = pdev->attached_dev; - struct rtl_priv *priv = pdev->priv; - struct switch_dev *dev = &priv->dev; - struct switch_val val; - unsigned int chipid, chipver, chiptype; - int err; - - /* Only init the switch for the primary PHY */ - if (pdev->addr != 0) - return 0; - - val.value.i = 1; - memcpy(&priv->dev, &rtldev, sizeof(struct switch_dev)); - priv->do_cpu = 0; - priv->page = -1; - priv->bus = pdev->bus; - - dev->priv = priv; - - chipid = rtl_get(dev, RTL_REG_CHIPID); - chipver = rtl_get(dev, RTL_REG_CHIPVER); - chiptype = rtl_get(dev, RTL_REG_CHIPTYPE); - switch(chiptype) { - case 0: - case 2: - strncpy(priv->hwname, RTL_NAME_S, sizeof(priv->hwname)); - priv->type = RTL_TYPE_S; - break; - case 1: - strncpy(priv->hwname, RTL_NAME_SD, sizeof(priv->hwname)); - priv->type = RTL_TYPE_SD; - break; - case 3: - strncpy(priv->hwname, RTL_NAME_SDM, sizeof(priv->hwname)); - priv->type = RTL_TYPE_SDM; - break; - default: - strncpy(priv->hwname, RTL_NAME_UNKNOWN, sizeof(priv->hwname)); - break; - } - - dev->name = priv->hwname; - rtl_hw_init(dev); - - printk(KERN_INFO "Registering %s switch with Chip ID: 0x%04x, version: 0x%04x\n", priv->hwname, chipid, chipver); - - err = register_switch(dev, netdev); - if (err < 0) { - kfree(priv); - return err; - } - - return 0; -} - -static struct switch_attr rtl_globals[] = { - { - .type = SWITCH_TYPE_INT, - .name = "reset", - .description = "Reset the switch", - .set = rtl_reset, - }, - { - .type = SWITCH_TYPE_INT, - .name = "enable_vlan", - .description = "Enable VLAN mode", - .max = 1, - .set = rtl_set_vlan, - .get = rtl_get_vlan, - }, - { - RTL_GLOBAL_REGATTR(EN_TRUNK), - .name = "trunk", - .description = "Enable port trunking", - .max = 1, - }, - { - RTL_GLOBAL_REGATTR(TRUNK_PORTSEL), - .name = "trunk_sel", - .description = "Select ports for trunking (0: 0,1 - 1: 3,4)", - .max = 1, - }, -#ifdef DEBUG - { - RTL_GLOBAL_REGATTR(VLAN_FILTER), - .name = "vlan_filter", - .description = "Filter incoming packets for allowed VLANS", - .max = 1, - }, - { - .type = SWITCH_TYPE_INT, - .name = "cpuport", - .description = "CPU Port", - .set = rtl_set_cpuport, - .get = rtl_get_cpuport, - .max = RTL8306_NUM_PORTS, - }, - { - .type = SWITCH_TYPE_INT, - .name = "use_cpuport", - .description = "CPU Port handling flag", - .set = rtl_set_use_cpuport, - .get = rtl_get_use_cpuport, - .max = RTL8306_NUM_PORTS, - }, - { - RTL_GLOBAL_REGATTR(TRAP_CPU), - .name = "trap_cpu", - .description = "VLAN trap to CPU", - .max = 1, - }, - { - RTL_GLOBAL_REGATTR(VLAN_TAG_AWARE), - .name = "vlan_tag_aware", - .description = "Enable VLAN tag awareness", - .max = 1, - }, - { - RTL_GLOBAL_REGATTR(VLAN_TAG_ONLY), - .name = "tag_only", - .description = "Only accept tagged packets", - .max = 1, - }, -#endif -}; -static struct switch_attr rtl_port[] = { - { - RTL_PORT_REGATTR(PVID), - .name = "pvid", - .description = "Port VLAN ID", - .max = RTL8306_NUM_VLANS - 1, - }, - { - RTL_PORT_REGATTR(LINK), - .name = "link", - .description = "get the current link state", - .max = 1, - .set = NULL, - }, -#ifdef DEBUG - { - RTL_PORT_REGATTR(NULL_VID_REPLACE), - .name = "null_vid", - .description = "NULL VID gets replaced by port default vid", - .max = 1, - }, - { - RTL_PORT_REGATTR(NON_PVID_DISCARD), - .name = "non_pvid_discard", - .description = "discard packets with VID != PVID", - .max = 1, - }, - { - RTL_PORT_REGATTR(VID_INSERT), - .name = "vid_insert_remove", - .description = "how should the switch insert and remove vids ?", - .max = 3, - }, - { - RTL_PORT_REGATTR(TAG_INSERT), - .name = "tag_insert", - .description = "tag insertion handling", - .max = 3, - }, -#endif - { - RTL_PORT_REGATTR(SPEED), - .name = "speed", - .description = "current link speed", - .max = 1, - }, - { - RTL_PORT_REGATTR(NWAY), - .name = "nway", - .description = "enable autonegotiation", - .max = 1, - }, -}; - -static struct switch_attr rtl_vlan[] = { - { - RTL_VLAN_REGATTR(VID), - .name = "vid", - .description = "VLAN ID", - .max = 4095, - }, -}; - -/* template */ -static struct switch_dev rtldev = { - .cpu_port = RTL8306_PORT_CPU, - .ports = RTL8306_NUM_PORTS, - .vlans = RTL8306_NUM_VLANS, - .attr_global = { - .attr = rtl_globals, - .n_attr = ARRAY_SIZE(rtl_globals), - }, - .attr_port = { - .attr = rtl_port, - .n_attr = ARRAY_SIZE(rtl_port), - }, - .attr_vlan = { - .attr = rtl_vlan, - .n_attr = ARRAY_SIZE(rtl_vlan), - }, - - .get_vlan_ports = rtl_get_ports, - .set_vlan_ports = rtl_set_ports, - .apply_config = rtl_hw_apply, -}; - - -static int -rtl8306_fixup(struct phy_device *pdev) -{ - struct rtl_priv priv; - u16 chipid; - - /* Attach to primary LAN port and WAN port */ - if (pdev->addr != 0 && pdev->addr != 4) - return 0; - - priv.page = -1; - priv.bus = pdev->bus; - chipid = rtl_get(&priv.dev, RTL_REG_CHIPID); - if (chipid == 0x5988) - pdev->phy_id = RTL8306_MAGIC; - - return 0; -} - -static int -rtl8306_probe(struct phy_device *pdev) -{ - struct rtl_priv *priv; - - list_for_each_entry(priv, &phydevs, list) { - /* - * share one rtl_priv instance between virtual phy - * devices on the same bus - */ - if (priv->bus == pdev->bus) - goto found; - } - priv = kzalloc(sizeof(struct rtl_priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->bus = pdev->bus; - -found: - pdev->priv = priv; - return 0; -} - -static void -rtl8306_remove(struct phy_device *pdev) -{ - struct rtl_priv *priv = pdev->priv; - unregister_switch(&priv->dev); - kfree(priv); -} - -static int -rtl8306_config_aneg(struct phy_device *pdev) -{ - struct rtl_priv *priv = pdev->priv; - - /* Only for WAN */ - if (pdev->addr == 0) - return 0; - - /* Restart autonegotiation */ - rtl_set(&priv->dev, RTL_PORT_REG(4, NWAY), 1); - rtl_set(&priv->dev, RTL_PORT_REG(4, NRESTART), 1); - - return 0; -} - -static int -rtl8306_read_status(struct phy_device *pdev) -{ - struct rtl_priv *priv = pdev->priv; - struct switch_dev *dev = &priv->dev; - - if (pdev->addr == 4) { - /* WAN */ - pdev->speed = rtl_get(dev, RTL_PORT_REG(4, SPEED)) ? SPEED_100 : SPEED_10; - pdev->duplex = rtl_get(dev, RTL_PORT_REG(4, DUPLEX)) ? DUPLEX_FULL : DUPLEX_HALF; - pdev->link = !!rtl_get(dev, RTL_PORT_REG(4, LINK)); - } else { - /* LAN */ - pdev->speed = SPEED_100; - pdev->duplex = DUPLEX_FULL; - pdev->link = 1; - } - - /* - * Bypass generic PHY status read, - * it doesn't work with this switch - */ - if (pdev->link) { - pdev->state = PHY_RUNNING; - netif_carrier_on(pdev->attached_dev); - pdev->adjust_link(pdev->attached_dev); - } else { - pdev->state = PHY_NOLINK; - netif_carrier_off(pdev->attached_dev); - pdev->adjust_link(pdev->attached_dev); - } - - return 0; -} - - -static struct phy_driver rtl8306_driver = { - .name = "Realtek RTL8306S", - .flags = PHY_HAS_MAGICANEG, - .phy_id = RTL8306_MAGIC, - .phy_id_mask = 0xffffffff, - .features = PHY_BASIC_FEATURES, - .probe = &rtl8306_probe, - .remove = &rtl8306_remove, - .config_init = &rtl8306_config_init, - .config_aneg = &rtl8306_config_aneg, - .read_status = &rtl8306_read_status, - .driver = { .owner = THIS_MODULE,}, -}; - - -static int __init -rtl_init(void) -{ - phy_register_fixup_for_id(PHY_ANY_ID, rtl8306_fixup); - return phy_driver_register(&rtl8306_driver); -} - -static void __exit -rtl_exit(void) -{ - phy_driver_unregister(&rtl8306_driver); -} - -module_init(rtl_init); -module_exit(rtl_exit); -MODULE_LICENSE("GPL"); - diff --git a/target/linux/generic-2.6/files/drivers/net/phy/rtl8366_smi.c b/target/linux/generic-2.6/files/drivers/net/phy/rtl8366_smi.c deleted file mode 100644 index bb2e3ba68..000000000 --- a/target/linux/generic-2.6/files/drivers/net/phy/rtl8366_smi.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Realtek RTL8366 SMI interface driver - * - * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/device.h> -#include <linux/delay.h> -#include <linux/gpio.h> -#include <linux/spinlock.h> -#include <linux/skbuff.h> - -#include "rtl8366_smi.h" - -#define RTL8366_SMI_ACK_RETRY_COUNT 5 -#define RTL8366_SMI_CLK_DELAY 10 /* nsec */ - -static inline void rtl8366_smi_clk_delay(struct rtl8366_smi *smi) -{ - ndelay(RTL8366_SMI_CLK_DELAY); -} - -static void rtl8366_smi_start(struct rtl8366_smi *smi) -{ - unsigned int sda = smi->gpio_sda; - unsigned int sck = smi->gpio_sck; - - /* - * Set GPIO pins to output mode, with initial state: - * SCK = 0, SDA = 1 - */ - gpio_direction_output(sck, 0); - gpio_direction_output(sda, 1); - rtl8366_smi_clk_delay(smi); - - /* CLK 1: 0 -> 1, 1 -> 0 */ - gpio_set_value(sck, 1); - rtl8366_smi_clk_delay(smi); - gpio_set_value(sck, 0); - rtl8366_smi_clk_delay(smi); - - /* CLK 2: */ - gpio_set_value(sck, 1); - rtl8366_smi_clk_delay(smi); - gpio_set_value(sda, 0); - rtl8366_smi_clk_delay(smi); - gpio_set_value(sck, 0); - rtl8366_smi_clk_delay(smi); - gpio_set_value(sda, 1); -} - -static void rtl8366_smi_stop(struct rtl8366_smi *smi) -{ - unsigned int sda = smi->gpio_sda; - unsigned int sck = smi->gpio_sck; - - rtl8366_smi_clk_delay(smi); - gpio_set_value(sda, 0); - gpio_set_value(sck, 1); - rtl8366_smi_clk_delay(smi); - gpio_set_value(sda, 1); - rtl8366_smi_clk_delay(smi); - gpio_set_value(sck, 1); - rtl8366_smi_clk_delay(smi); - gpio_set_value(sck, 0); - rtl8366_smi_clk_delay(smi); - gpio_set_value(sck, 1); - - /* add a click */ - rtl8366_smi_clk_delay(smi); - gpio_set_value(sck, 0); - rtl8366_smi_clk_delay(smi); - gpio_set_value(sck, 1); - - /* set GPIO pins to input mode */ - gpio_direction_input(sda); - gpio_direction_input(sck); -} - -static void rtl8366_smi_write_bits(struct rtl8366_smi *smi, u32 data, u32 len) -{ - unsigned int sda = smi->gpio_sda; - unsigned int sck = smi->gpio_sck; - - for (; len > 0; len--) { - rtl8366_smi_clk_delay(smi); - - /* prepare data */ - gpio_set_value(sda, !!(data & ( 1 << (len - 1)))); - rtl8366_smi_clk_delay(smi); - - /* clocking */ - gpio_set_value(sck, 1); - rtl8366_smi_clk_delay(smi); - gpio_set_value(sck, 0); - } -} - -static void rtl8366_smi_read_bits(struct rtl8366_smi *smi, u32 len, u32 *data) -{ - unsigned int sda = smi->gpio_sda; - unsigned int sck = smi->gpio_sck; - - gpio_direction_input(sda); - - for (*data = 0; len > 0; len--) { - u32 u; - - rtl8366_smi_clk_delay(smi); - - /* clocking */ - gpio_set_value(sck, 1); - rtl8366_smi_clk_delay(smi); - u = !!gpio_get_value(sda); - gpio_set_value(sck, 0); - - *data |= (u << (len - 1)); - } - - gpio_direction_output(sda, 0); -} - -static int rtl8366_smi_wait_for_ack(struct rtl8366_smi *smi) -{ - int retry_cnt; - - retry_cnt = 0; - do { - u32 ack; - - rtl8366_smi_read_bits(smi, 1, &ack); - if (ack == 0) - break; - - if (++retry_cnt > RTL8366_SMI_ACK_RETRY_COUNT) - return -EIO; - } while (1); - - return 0; -} - -static int rtl8366_smi_write_byte(struct rtl8366_smi *smi, u8 data) -{ - rtl8366_smi_write_bits(smi, data, 8); - return rtl8366_smi_wait_for_ack(smi); -} - -static int rtl8366_smi_read_byte0(struct rtl8366_smi *smi, u8 *data) -{ - u32 t; - - /* read data */ - rtl8366_smi_read_bits(smi, 8, &t); - *data = (t & 0xff); - - /* send an ACK */ - rtl8366_smi_write_bits(smi, 0x00, 1); - - return 0; -} - -static int rtl8366_smi_read_byte1(struct rtl8366_smi *smi, u8 *data) -{ - u32 t; - - /* read data */ - rtl8366_smi_read_bits(smi, 8, &t); - *data = (t & 0xff); - - /* send an ACK */ - rtl8366_smi_write_bits(smi, 0x01, 1); - - return 0; -} - -int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data) -{ - unsigned long flags; - u8 lo = 0; - u8 hi = 0; - int ret; - - spin_lock_irqsave(&smi->lock, flags); - - rtl8366_smi_start(smi); - - /* send READ command */ - ret = rtl8366_smi_write_byte(smi, 0x0a << 4 | 0x04 << 1 | 0x01); - if (ret) - goto out; - - /* set ADDR[7:0] */ - ret = rtl8366_smi_write_byte(smi, addr & 0xff); - if (ret) - goto out; - - /* set ADDR[15:8] */ - ret = rtl8366_smi_write_byte(smi, addr >> 8); - if (ret) - goto out; - - /* read DATA[7:0] */ - rtl8366_smi_read_byte0(smi, &lo); - /* read DATA[15:8] */ - rtl8366_smi_read_byte1(smi, &hi); - - *data = ((u32) lo) | (((u32) hi) << 8); - - ret = 0; - - out: - rtl8366_smi_stop(smi); - spin_unlock_irqrestore(&smi->lock, flags); - - return ret; -} -EXPORT_SYMBOL_GPL(rtl8366_smi_read_reg); - -int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&smi->lock, flags); - - rtl8366_smi_start(smi); - - /* send WRITE command */ - ret = rtl8366_smi_write_byte(smi, 0x0a << 4 | 0x04 << 1 | 0x00); - if (ret) - goto out; - - /* set ADDR[7:0] */ - ret = rtl8366_smi_write_byte(smi, addr & 0xff); - if (ret) - goto out; - - /* set ADDR[15:8] */ - ret = rtl8366_smi_write_byte(smi, addr >> 8); - if (ret) - goto out; - - /* write DATA[7:0] */ - ret = rtl8366_smi_write_byte(smi, data & 0xff); - if (ret) - goto out; - - /* write DATA[15:8] */ - ret = rtl8366_smi_write_byte(smi, data >> 8); - if (ret) - goto out; - - ret = 0; - - out: - rtl8366_smi_stop(smi); - spin_unlock_irqrestore(&smi->lock, flags); - - return ret; -} -EXPORT_SYMBOL_GPL(rtl8366_smi_write_reg); - -int rtl8366_smi_rmwr(struct rtl8366_smi *smi, u32 addr, u32 mask, u32 data) -{ - u32 t; - int err; - - err = rtl8366_smi_read_reg(smi, addr, &t); - if (err) - return err; - - err = rtl8366_smi_write_reg(smi, addr, (t & ~mask) | data); - return err; - -} -EXPORT_SYMBOL_GPL(rtl8366_smi_rmwr); - -static int rtl8366_smi_mii_init(struct rtl8366_smi *smi) -{ - int ret; - int i; - - smi->mii_bus = mdiobus_alloc(); - if (smi->mii_bus == NULL) { - ret = -ENOMEM; - goto err; - } - - smi->mii_bus->priv = (void *) smi; - smi->mii_bus->name = dev_name(smi->parent); - smi->mii_bus->read = smi->ops->mii_read; - smi->mii_bus->write = smi->ops->mii_write; - snprintf(smi->mii_bus->id, MII_BUS_ID_SIZE, "%s", - dev_name(smi->parent)); - smi->mii_bus->parent = smi->parent; - smi->mii_bus->phy_mask = ~(0x1f); - smi->mii_bus->irq = smi->mii_irq; - for (i = 0; i < PHY_MAX_ADDR; i++) - smi->mii_irq[i] = PHY_POLL; - - ret = mdiobus_register(smi->mii_bus); - if (ret) - goto err_free; - - return 0; - - err_free: - mdiobus_free(smi->mii_bus); - err: - return ret; -} - -static void rtl8366_smi_mii_cleanup(struct rtl8366_smi *smi) -{ - mdiobus_unregister(smi->mii_bus); - mdiobus_free(smi->mii_bus); -} - -int rtl8366_smi_init(struct rtl8366_smi *smi) -{ - int err; - - if (!smi->parent) - return -EINVAL; - - if (!smi->ops) - return -EINVAL; - - err = gpio_request(smi->gpio_sda, dev_name(smi->parent)); - if (err) { - dev_err(smi->parent, "gpio_request failed for %u, err=%d\n", - smi->gpio_sda, err); - goto err_out; - } - - err = gpio_request(smi->gpio_sck, dev_name(smi->parent)); - if (err) { - dev_err(smi->parent, "gpio_request failed for %u, err=%d\n", - smi->gpio_sck, err); - goto err_free_sda; - } - - spin_lock_init(&smi->lock); - - dev_info(smi->parent, "using GPIO pins %u (SDA) and %u (SCK)\n", - smi->gpio_sda, smi->gpio_sck); - - err = smi->ops->detect(smi); - if (err) { - dev_err(smi->parent, "chip detection failed, err=%d\n", err); - goto err_free_sck; - } - - err = rtl8366_smi_mii_init(smi); - if (err) - goto err_free_sck; - - return 0; - - err_free_sck: - gpio_free(smi->gpio_sck); - err_free_sda: - gpio_free(smi->gpio_sda); - err_out: - return err; -} -EXPORT_SYMBOL_GPL(rtl8366_smi_init); - -void rtl8366_smi_cleanup(struct rtl8366_smi *smi) -{ - rtl8366_smi_mii_cleanup(smi); - gpio_free(smi->gpio_sck); - gpio_free(smi->gpio_sda); -} -EXPORT_SYMBOL_GPL(rtl8366_smi_cleanup); - -MODULE_DESCRIPTION("Realtek RTL8366 SMI interface driver"); -MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); -MODULE_LICENSE("GPL v2"); diff --git a/target/linux/generic-2.6/files/drivers/net/phy/rtl8366_smi.h b/target/linux/generic-2.6/files/drivers/net/phy/rtl8366_smi.h deleted file mode 100644 index 1afee9b73..000000000 --- a/target/linux/generic-2.6/files/drivers/net/phy/rtl8366_smi.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Realtek RTL8366 SMI interface driver defines - * - * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ - -#ifndef _RTL8366_SMI_H -#define _RTL8366_SMI_H - -#include <linux/phy.h> - -struct rtl8366_smi_ops; -struct mii_bus; - -struct rtl8366_smi { - struct device *parent; - unsigned int gpio_sda; - unsigned int gpio_sck; - spinlock_t lock; - struct mii_bus *mii_bus; - int mii_irq[PHY_MAX_ADDR]; - - struct rtl8366_smi_ops *ops; -}; - -struct rtl8366_smi_ops { - int (*detect)(struct rtl8366_smi *smi); - - int (*mii_read)(struct mii_bus *bus, int addr, int reg); - int (*mii_write)(struct mii_bus *bus, int addr, int reg, u16 val); -}; - -struct rtl8366_vlan_mc { - u16 vid; - u8 priority; - u8 untag; - u8 member; - u8 fid; -}; - -struct rtl8366_vlan_4k { - u16 vid; - u8 untag; - u8 member; - u8 fid; -}; - -int rtl8366_smi_init(struct rtl8366_smi *smi); -void rtl8366_smi_cleanup(struct rtl8366_smi *smi); -int rtl8366_smi_write_reg(struct rtl8366_smi *smi, u32 addr, u32 data); -int rtl8366_smi_read_reg(struct rtl8366_smi *smi, u32 addr, u32 *data); -int rtl8366_smi_rmwr(struct rtl8366_smi *smi, u32 addr, u32 mask, u32 data); - -#endif /* _RTL8366_SMI_H */ diff --git a/target/linux/generic-2.6/files/drivers/net/phy/rtl8366rb.c b/target/linux/generic-2.6/files/drivers/net/phy/rtl8366rb.c deleted file mode 100644 index 2105b2bd4..000000000 --- a/target/linux/generic-2.6/files/drivers/net/phy/rtl8366rb.c +++ /dev/null @@ -1,1797 +0,0 @@ -/* - * Platform driver for the Realtek RTL8366S ethernet switch - * - * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org> - * Copyright (C) 2010 Antti Seppälä <a.seppala@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/delay.h> -#include <linux/skbuff.h> -#include <linux/switch.h> -#include <linux/rtl8366rb.h> - -#include "rtl8366_smi.h" - -#ifdef CONFIG_RTL8366S_PHY_DEBUG_FS -#include <linux/debugfs.h> -#endif - -#define RTL8366S_DRIVER_DESC "Realtek RTL8366RB ethernet switch driver" -#define RTL8366S_DRIVER_VER "0.2.2" - -#define RTL8366S_PHY_NO_MAX 4 -#define RTL8366S_PHY_PAGE_MAX 7 -#define RTL8366S_PHY_ADDR_MAX 31 - -#define RTL8366_CHIP_GLOBAL_CTRL_REG 0x0000 -#define RTL8366_CHIP_CTRL_VLAN (1 << 13) -#define RTL8366_CHIP_CTRL_VLAN_4KTB (1 << 14) - -/* Switch Global Configuration register */ -#define RTL8366_SGCR 0x0000 -#define RTL8366_SGCR_EN_BC_STORM_CTRL BIT(0) -#define RTL8366_SGCR_MAX_LENGTH(_x) (_x << 4) -#define RTL8366_SGCR_MAX_LENGTH_MASK RTL8366_SGCR_MAX_LENGTH(0x3) -#define RTL8366_SGCR_MAX_LENGTH_1522 RTL8366_SGCR_MAX_LENGTH(0x0) -#define RTL8366_SGCR_MAX_LENGTH_1536 RTL8366_SGCR_MAX_LENGTH(0x1) -#define RTL8366_SGCR_MAX_LENGTH_1552 RTL8366_SGCR_MAX_LENGTH(0x2) -#define RTL8366_SGCR_MAX_LENGTH_9216 RTL8366_SGCR_MAX_LENGTH(0x3) - -/* Port Enable Control register */ -#define RTL8366_PECR 0x0001 - -/* Switch Security Control registers */ -#define RTL8366_SSCR0 0x0002 -#define RTL8366_SSCR1 0x0003 -#define RTL8366_SSCR2 0x0004 -#define RTL8366_SSCR2_DROP_UNKNOWN_DA BIT(0) - -#define RTL8366_RESET_CTRL_REG 0x0100 -#define RTL8366_CHIP_CTRL_RESET_HW 1 -#define RTL8366_CHIP_CTRL_RESET_SW (1 << 1) - -#define RTL8366S_CHIP_VERSION_CTRL_REG 0x050A -#define RTL8366S_CHIP_VERSION_MASK 0xf -#define RTL8366S_CHIP_ID_REG 0x0509 -#define RTL8366S_CHIP_ID_8366 0x5937 - -/* PHY registers control */ -#define RTL8366S_PHY_ACCESS_CTRL_REG 0x8000 -#define RTL8366S_PHY_ACCESS_DATA_REG 0x8002 - -#define RTL8366S_PHY_CTRL_READ 1 -#define RTL8366S_PHY_CTRL_WRITE 0 - -#define RTL8366S_PHY_REG_MASK 0x1f -#define RTL8366S_PHY_PAGE_OFFSET 5 -#define RTL8366S_PHY_PAGE_MASK (0xf << 5) -#define RTL8366S_PHY_NO_OFFSET 9 -#define RTL8366S_PHY_NO_MASK (0x1f << 9) - -/* LED control registers */ -#define RTL8366_LED_BLINKRATE_REG 0x0430 -#define RTL8366_LED_BLINKRATE_BIT 0 -#define RTL8366_LED_BLINKRATE_MASK 0x0007 - -#define RTL8366_LED_CTRL_REG 0x0431 -#define RTL8366_LED_0_1_CTRL_REG 0x0432 -#define RTL8366_LED_2_3_CTRL_REG 0x0433 - -#define RTL8366S_MIB_COUNT 33 -#define RTL8366S_GLOBAL_MIB_COUNT 1 -#define RTL8366S_MIB_COUNTER_PORT_OFFSET 0x0050 -#define RTL8366S_MIB_COUNTER_BASE 0x1000 -#define RTL8366S_MIB_CTRL_REG 0x13F0 -#define RTL8366S_MIB_CTRL_USER_MASK 0x0FFC -#define RTL8366S_MIB_CTRL_BUSY_MASK 0x0001 -#define RTL8366S_MIB_CTRL_RESET_MASK 0x0001 - -#define RTL8366S_MIB_CTRL_GLOBAL_RESET_MASK 0x0004 -#define RTL8366S_MIB_CTRL_PORT_RESET_BIT 0x0003 -#define RTL8366S_MIB_CTRL_PORT_RESET_MASK 0x01FC - - -#define RTL8366S_PORT_VLAN_CTRL_BASE 0x0063 -#define RTL8366S_PORT_VLAN_CTRL_REG(_p) \ - (RTL8366S_PORT_VLAN_CTRL_BASE + (_p) / 4) -#define RTL8366S_PORT_VLAN_CTRL_MASK 0xf -#define RTL8366S_PORT_VLAN_CTRL_SHIFT(_p) (4 * ((_p) % 4)) - - -#define RTL8366S_VLAN_TABLE_READ_BASE 0x018C -#define RTL8366S_VLAN_TABLE_WRITE_BASE 0x0185 - - -#define RTL8366S_TABLE_ACCESS_CTRL_REG 0x0180 -#define RTL8366S_TABLE_VLAN_READ_CTRL 0x0E01 -#define RTL8366S_TABLE_VLAN_WRITE_CTRL 0x0F01 - -#define RTL8366S_VLAN_MEMCONF_BASE 0x0020 - - -#define RTL8366S_PORT_LINK_STATUS_BASE 0x0014 -#define RTL8366S_PORT_STATUS_SPEED_MASK 0x0003 -#define RTL8366S_PORT_STATUS_DUPLEX_MASK 0x0004 -#define RTL8366S_PORT_STATUS_LINK_MASK 0x0010 -#define RTL8366S_PORT_STATUS_TXPAUSE_MASK 0x0020 -#define RTL8366S_PORT_STATUS_RXPAUSE_MASK 0x0040 -#define RTL8366S_PORT_STATUS_AN_MASK 0x0080 - - -#define RTL8366_PORT_NUM_CPU 5 -#define RTL8366_NUM_PORTS 6 -#define RTL8366_NUM_VLANS 16 -#define RTL8366_NUM_LEDGROUPS 4 -#define RTL8366_NUM_VIDS 4096 -#define RTL8366S_PRIORITYMAX 7 -#define RTL8366S_FIDMAX 7 - - -#define RTL8366_PORT_1 (1 << 0) /* In userspace port 0 */ -#define RTL8366_PORT_2 (1 << 1) /* In userspace port 1 */ -#define RTL8366_PORT_3 (1 << 2) /* In userspace port 2 */ -#define RTL8366_PORT_4 (1 << 3) /* In userspace port 3 */ -#define RTL8366_PORT_5 (1 << 4) /* In userspace port 4 */ - -#define RTL8366_PORT_CPU (1 << 5) /* CPU port */ - -#define RTL8366_PORT_ALL (RTL8366_PORT_1 | \ - RTL8366_PORT_2 | \ - RTL8366_PORT_3 | \ - RTL8366_PORT_4 | \ - RTL8366_PORT_5 | \ - RTL8366_PORT_CPU) - -#define RTL8366_PORT_ALL_BUT_CPU (RTL8366_PORT_1 | \ - RTL8366_PORT_2 | \ - RTL8366_PORT_3 | \ - RTL8366_PORT_4 | \ - RTL8366_PORT_5) - -#define RTL8366_PORT_ALL_EXTERNAL (RTL8366_PORT_1 | \ - RTL8366_PORT_2 | \ - RTL8366_PORT_3 | \ - RTL8366_PORT_4) - -#define RTL8366_PORT_ALL_INTERNAL RTL8366_PORT_CPU - -struct rtl8366rb { - struct device *parent; - struct rtl8366_smi smi; - struct switch_dev dev; - char buf[4096]; -#ifdef CONFIG_RTL8366S_PHY_DEBUG_FS - struct dentry *debugfs_root; -#endif -}; - -struct rtl8366rb_vlan_mc { - u16 reserved2:1; - u16 priority:3; - u16 vid:12; - u16 untag:8; - u16 member:8; - u16 stag_mbr:8; - u16 stag_idx:3; - u16 reserved1:2; - u16 fid:3; -}; - -struct rtl8366rb_vlan_4k { - u16 reserved1:4; - u16 vid:12; - u16 untag:8; - u16 member:8; - u16 reserved2:13; - u16 fid:3; -}; - -#ifdef CONFIG_RTL8366S_PHY_DEBUG_FS -u16 gl_dbg_reg; -#endif - -struct mib_counter { - unsigned offset; - unsigned length; - const char *name; -}; - -static struct mib_counter rtl8366rb_mib_counters[RTL8366S_MIB_COUNT] = { - { 0, 4, "IfInOctets" }, - { 4, 4, "EtherStatsOctets" }, - { 8, 2, "EtherStatsUnderSizePkts" }, - { 10, 2, "EtherFragments" }, - { 12, 2, "EtherStatsPkts64Octets" }, - { 14, 2, "EtherStatsPkts65to127Octets" }, - { 16, 2, "EtherStatsPkts128to255Octets" }, - { 18, 2, "EtherStatsPkts256to511Octets" }, - { 20, 2, "EtherStatsPkts512to1023Octets" }, - { 22, 2, "EtherStatsPkts1024to1518Octets" }, - { 24, 2, "EtherOversizeStats" }, - { 26, 2, "EtherStatsJabbers" }, - { 28, 2, "IfInUcastPkts" }, - { 30, 2, "EtherStatsMulticastPkts" }, - { 32, 2, "EtherStatsBroadcastPkts" }, - { 34, 2, "EtherStatsDropEvents" }, - { 36, 2, "Dot3StatsFCSErrors" }, - { 38, 2, "Dot3StatsSymbolErrors" }, - { 40, 2, "Dot3InPauseFrames" }, - { 42, 2, "Dot3ControlInUnknownOpcodes" }, - { 44, 4, "IfOutOctets" }, - { 48, 2, "Dot3StatsSingleCollisionFrames" }, - { 50, 2, "Dot3StatMultipleCollisionFrames" }, - { 52, 2, "Dot3sDeferredTransmissions" }, - { 54, 2, "Dot3StatsLateCollisions" }, - { 56, 2, "EtherStatsCollisions" }, - { 58, 2, "Dot3StatsExcessiveCollisions" }, - { 60, 2, "Dot3OutPauseFrames" }, - { 62, 2, "Dot1dBasePortDelayExceededDiscards" }, - { 64, 2, "Dot1dTpPortInDiscards" }, - { 66, 2, "IfOutUcastPkts" }, - { 68, 2, "IfOutMulticastPkts" }, - { 70, 2, "IfOutBroadcastPkts" }, -}; - -#define REG_WR(_smi, _reg, _val) \ - do { \ - err = rtl8366_smi_write_reg(_smi, _reg, _val); \ - if (err) \ - return err; \ - } while (0) - -#define REG_RMW(_smi, _reg, _mask, _val) \ - do { \ - err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val); \ - if (err) \ - return err; \ - } while (0) - -static inline struct rtl8366rb *smi_to_rtl8366rb(struct rtl8366_smi *smi) -{ - return container_of(smi, struct rtl8366rb, smi); -} - -static inline struct rtl8366rb *sw_to_rtl8366rb(struct switch_dev *sw) -{ - return container_of(sw, struct rtl8366rb, dev); -} - -static inline struct rtl8366_smi *sw_to_rtl8366_smi(struct switch_dev *sw) -{ - struct rtl8366rb *rtl = sw_to_rtl8366rb(sw); - return &rtl->smi; -} - -static int rtl8366rb_reset_chip(struct rtl8366_smi *smi) -{ - int timeout = 10; - u32 data; - - rtl8366_smi_write_reg(smi, RTL8366_RESET_CTRL_REG, - RTL8366_CHIP_CTRL_RESET_HW); - do { - msleep(1); - if (rtl8366_smi_read_reg(smi, RTL8366_RESET_CTRL_REG, &data)) - return -EIO; - - if (!(data & RTL8366_CHIP_CTRL_RESET_HW)) - break; - } while (--timeout); - - if (!timeout) { - printk("Timeout waiting for the switch to reset\n"); - return -EIO; - } - - return 0; -} - -static int rtl8366rb_hw_init(struct rtl8366_smi *smi) -{ - int err; - - /* set maximum packet length to 1536 bytes */ - REG_RMW(smi, RTL8366_SGCR, RTL8366_SGCR_MAX_LENGTH_MASK, - RTL8366_SGCR_MAX_LENGTH_1536); - - /* enable all ports */ - REG_WR(smi, RTL8366_PECR, 0); - - /* disable learning for all ports */ - REG_WR(smi, RTL8366_SSCR0, RTL8366_PORT_ALL); - - /* disable auto ageing for all ports */ - REG_WR(smi, RTL8366_SSCR1, RTL8366_PORT_ALL); - - /* don't drop packets whose DA has not been learned */ - REG_RMW(smi, RTL8366_SSCR2, RTL8366_SSCR2_DROP_UNKNOWN_DA, 0); - - return 0; -} - -static int rtl8366rb_read_phy_reg(struct rtl8366_smi *smi, - u32 phy_no, u32 page, u32 addr, u32 *data) -{ - u32 reg; - int ret; - - if (phy_no > RTL8366S_PHY_NO_MAX) - return -EINVAL; - - if (page > RTL8366S_PHY_PAGE_MAX) - return -EINVAL; - - if (addr > RTL8366S_PHY_ADDR_MAX) - return -EINVAL; - - ret = rtl8366_smi_write_reg(smi, RTL8366S_PHY_ACCESS_CTRL_REG, - RTL8366S_PHY_CTRL_READ); - if (ret) - return ret; - - reg = 0x8000 | (1 << (phy_no + RTL8366S_PHY_NO_OFFSET)) | - ((page << RTL8366S_PHY_PAGE_OFFSET) & RTL8366S_PHY_PAGE_MASK) | - (addr & RTL8366S_PHY_REG_MASK); - - ret = rtl8366_smi_write_reg(smi, reg, 0); - if (ret) - return ret; - - ret = rtl8366_smi_read_reg(smi, RTL8366S_PHY_ACCESS_DATA_REG, data); - if (ret) - return ret; - - return 0; -} - -static int rtl8366rb_write_phy_reg(struct rtl8366_smi *smi, - u32 phy_no, u32 page, u32 addr, u32 data) -{ - u32 reg; - int ret; - - if (phy_no > RTL8366S_PHY_NO_MAX) - return -EINVAL; - - if (page > RTL8366S_PHY_PAGE_MAX) - return -EINVAL; - - if (addr > RTL8366S_PHY_ADDR_MAX) - return -EINVAL; - - ret = rtl8366_smi_write_reg(smi, RTL8366S_PHY_ACCESS_CTRL_REG, - RTL8366S_PHY_CTRL_WRITE); - if (ret) - return ret; - - reg = 0x8000 | (1 << (phy_no + RTL8366S_PHY_NO_OFFSET)) | - ((page << RTL8366S_PHY_PAGE_OFFSET) & RTL8366S_PHY_PAGE_MASK) | - (addr & RTL8366S_PHY_REG_MASK); - - ret = rtl8366_smi_write_reg(smi, reg, data); - if (ret) - return ret; - - return 0; -} - -static int rtl8366_get_mib_counter(struct rtl8366_smi *smi, int counter, - int port, unsigned long long *val) -{ - int i; - int err; - u32 addr, data; - u64 mibvalue; - - if (port > RTL8366_NUM_PORTS || counter >= RTL8366S_MIB_COUNT) - return -EINVAL; - - addr = RTL8366S_MIB_COUNTER_BASE + - RTL8366S_MIB_COUNTER_PORT_OFFSET * (port) + - rtl8366rb_mib_counters[counter].offset; - - /* - * Writing access counter address first - * then ASIC will prepare 64bits counter wait for being retrived - */ - data = 0; /* writing data will be discard by ASIC */ - err = rtl8366_smi_write_reg(smi, addr, data); - if (err) - return err; - - /* read MIB control register */ - err = rtl8366_smi_read_reg(smi, RTL8366S_MIB_CTRL_REG, &data); - if (err) - return err; - - if (data & RTL8366S_MIB_CTRL_BUSY_MASK) - return -EBUSY; - - if (data & RTL8366S_MIB_CTRL_RESET_MASK) - return -EIO; - - mibvalue = 0; - for (i = rtl8366rb_mib_counters[counter].length; i > 0; i--) { - err = rtl8366_smi_read_reg(smi, addr + (i - 1), &data); - if (err) - return err; - - mibvalue = (mibvalue << 16) | (data & 0xFFFF); - } - - *val = mibvalue; - return 0; -} - -static int rtl8366rb_get_vlan_4k(struct rtl8366_smi *smi, u32 vid, - struct rtl8366_vlan_4k *vlan4k) -{ - struct rtl8366rb_vlan_4k vlan4k_priv; - int err; - u32 data; - u16 *tableaddr; - - memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k)); - vlan4k_priv.vid = vid; - - if (vid >= RTL8366_NUM_VIDS) - return -EINVAL; - - tableaddr = (u16 *)&vlan4k_priv; - - /* write VID */ - data = *tableaddr; - err = rtl8366_smi_write_reg(smi, RTL8366S_VLAN_TABLE_WRITE_BASE, data); - if (err) - return err; - - /* write table access control word */ - err = rtl8366_smi_write_reg(smi, RTL8366S_TABLE_ACCESS_CTRL_REG, - RTL8366S_TABLE_VLAN_READ_CTRL); - if (err) - return err; - - err = rtl8366_smi_read_reg(smi, RTL8366S_VLAN_TABLE_READ_BASE, &data); - if (err) - return err; - - *tableaddr = data; - tableaddr++; - - err = rtl8366_smi_read_reg(smi, RTL8366S_VLAN_TABLE_READ_BASE + 1, - &data); - if (err) - return err; - - *tableaddr = data; - tableaddr++; - - err = rtl8366_smi_read_reg(smi, RTL8366S_VLAN_TABLE_READ_BASE + 2, - &data); - if (err) - return err; - *tableaddr = data; - - vlan4k->vid = vid; - vlan4k->untag = vlan4k_priv.untag; - vlan4k->member = vlan4k_priv.member; - vlan4k->fid = vlan4k_priv.fid; - - return 0; -} - -static int rtl8366rb_set_vlan_4k(struct rtl8366_smi *smi, - const struct rtl8366_vlan_4k *vlan4k) -{ - struct rtl8366rb_vlan_4k vlan4k_priv; - int err; - u32 data; - u16 *tableaddr; - - if (vlan4k->vid >= RTL8366_NUM_VIDS || - vlan4k->member > RTL8366_PORT_ALL || - vlan4k->untag > RTL8366_PORT_ALL || - vlan4k->fid > RTL8366S_FIDMAX) - return -EINVAL; - - vlan4k_priv.vid = vlan4k->vid; - vlan4k_priv.untag = vlan4k->untag; - vlan4k_priv.member = vlan4k->member; - vlan4k_priv.fid = vlan4k->fid; - - tableaddr = (u16 *)&vlan4k_priv; - - data = *tableaddr; - - err = rtl8366_smi_write_reg(smi, RTL8366S_VLAN_TABLE_WRITE_BASE, data); - if (err) - return err; - - tableaddr++; - - data = *tableaddr; - - err = rtl8366_smi_write_reg(smi, RTL8366S_VLAN_TABLE_WRITE_BASE + 1, - data); - if (err) - return err; - - tableaddr++; - - data = *tableaddr; - - err = rtl8366_smi_write_reg(smi, RTL8366S_VLAN_TABLE_WRITE_BASE + 2, - data); - if (err) - return err; - - /* write table access control word */ - err = rtl8366_smi_write_reg(smi, RTL8366S_TABLE_ACCESS_CTRL_REG, - RTL8366S_TABLE_VLAN_WRITE_CTRL); - - return err; -} - -static int rtl8366rb_get_vlan_mc(struct rtl8366_smi *smi, u32 index, - struct rtl8366_vlan_mc *vlanmc) -{ - struct rtl8366rb_vlan_mc vlanmc_priv; - int err; - u32 addr; - u32 data; - u16 *tableaddr; - - memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc)); - - if (index >= RTL8366_NUM_VLANS) - return -EINVAL; - - tableaddr = (u16 *)&vlanmc_priv; - - addr = RTL8366S_VLAN_MEMCONF_BASE + (index * 3); - err = rtl8366_smi_read_reg(smi, addr, &data); - if (err) - return err; - - *tableaddr = data; - tableaddr++; - - addr = RTL8366S_VLAN_MEMCONF_BASE + 1 + (index * 3); - err = rtl8366_smi_read_reg(smi, addr, &data); - if (err) - return err; - - *tableaddr = data; - tableaddr++; - - addr = RTL8366S_VLAN_MEMCONF_BASE + 2 + (index * 3); - err = rtl8366_smi_read_reg(smi, addr, &data); - if (err) - return err; - - *tableaddr = data; - - vlanmc->vid = vlanmc_priv.vid; - vlanmc->priority = vlanmc_priv.priority; - vlanmc->untag = vlanmc_priv.untag; - vlanmc->member = vlanmc_priv.member; - vlanmc->fid = vlanmc_priv.fid; - - return 0; -} - -static int rtl8366rb_set_vlan_mc(struct rtl8366_smi *smi, u32 index, - const struct rtl8366_vlan_mc *vlanmc) -{ - struct rtl8366rb_vlan_mc vlanmc_priv; - int err; - u32 addr; - u32 data; - u16 *tableaddr; - - if (index >= RTL8366_NUM_VLANS || - vlanmc->vid >= RTL8366_NUM_VIDS || - vlanmc->priority > RTL8366S_PRIORITYMAX || - vlanmc->member > RTL8366_PORT_ALL || - vlanmc->untag > RTL8366_PORT_ALL || - vlanmc->fid > RTL8366S_FIDMAX) - return -EINVAL; - - vlanmc_priv.vid = vlanmc->vid; - vlanmc_priv.priority = vlanmc->priority; - vlanmc_priv.untag = vlanmc->untag; - vlanmc_priv.member = vlanmc->member; - vlanmc_priv.stag_mbr = 0; - vlanmc_priv.stag_idx = 0; - vlanmc_priv.fid = vlanmc->fid; - - addr = RTL8366S_VLAN_MEMCONF_BASE + (index * 3); - - tableaddr = (u16 *)&vlanmc_priv; - data = *tableaddr; - - err = rtl8366_smi_write_reg(smi, addr, data); - if (err) - return err; - - addr = RTL8366S_VLAN_MEMCONF_BASE + 1 + (index * 3); - - tableaddr++; - data = *tableaddr; - - err = rtl8366_smi_write_reg(smi, addr, data); - if (err) - return err; - - addr = RTL8366S_VLAN_MEMCONF_BASE + 2 + (index * 3); - - tableaddr++; - data = *tableaddr; - - err = rtl8366_smi_write_reg(smi, addr, data); - if (err) - return err; - return 0; -} - -static int rtl8366rb_get_mc_index(struct rtl8366_smi *smi, int port, int *val) -{ - u32 data; - int err; - - if (port >= RTL8366_NUM_PORTS) - return -EINVAL; - - err = rtl8366_smi_read_reg(smi, RTL8366S_PORT_VLAN_CTRL_REG(port), - &data); - if (err) - return err; - - *val = (data >> RTL8366S_PORT_VLAN_CTRL_SHIFT(port)) & - RTL8366S_PORT_VLAN_CTRL_MASK; - - return 0; - -} - -static int rtl8366rb_set_mc_index(struct rtl8366_smi *smi, int port, int index) -{ - if (port >= RTL8366_NUM_PORTS || index >= RTL8366_NUM_VLANS) - return -EINVAL; - - return rtl8366_smi_rmwr(smi, RTL8366S_PORT_VLAN_CTRL_REG(port), - RTL8366S_PORT_VLAN_CTRL_MASK << - RTL8366S_PORT_VLAN_CTRL_SHIFT(port), - (index & RTL8366S_PORT_VLAN_CTRL_MASK) << - RTL8366S_PORT_VLAN_CTRL_SHIFT(port)); -} - -static int rtl8366rb_set_vlan(struct rtl8366_smi *smi, int vid, u32 member, - u32 untag, u32 fid) -{ - struct rtl8366_vlan_4k vlan4k; - int err; - int i; - - /* Update the 4K table */ - err = rtl8366rb_get_vlan_4k(smi, vid, &vlan4k); - if (err) - return err; - - vlan4k.member = member; - vlan4k.untag = untag; - vlan4k.fid = fid; - err = rtl8366rb_set_vlan_4k(smi, &vlan4k); - if (err) - return err; - - /* Try to find an existing MC entry for this VID */ - for (i = 0; i < RTL8366_NUM_VLANS; i++) { - struct rtl8366_vlan_mc vlanmc; - - err = rtl8366rb_get_vlan_mc(smi, i, &vlanmc); - if (err) - return err; - - if (vid == vlanmc.vid) { - /* update the MC entry */ - vlanmc.member = member; - vlanmc.untag = untag; - vlanmc.fid = fid; - - err = rtl8366rb_set_vlan_mc(smi, i, &vlanmc); - break; - } - } - - return err; -} - -static int rtl8366rb_get_pvid(struct rtl8366_smi *smi, int port, int *val) -{ - struct rtl8366_vlan_mc vlanmc; - int err; - int index; - - err = rtl8366rb_get_mc_index(smi, port, &index); - if (err) - return err; - - err = rtl8366rb_get_vlan_mc(smi, index, &vlanmc); - if (err) - return err; - - *val = vlanmc.vid; - return 0; -} - -static int rtl8366rb_mc_is_used(struct rtl8366_smi *smi, int mc_index, - int *used) -{ - int err; - int i; - - *used = 0; - for (i = 0; i < RTL8366_NUM_PORTS; i++) { - int index = 0; - - err = rtl8366rb_get_mc_index(smi, i, &index); - if (err) - return err; - - if (mc_index == index) { - *used = 1; - break; - } - } - - return 0; -} - -static int rtl8366rb_set_pvid(struct rtl8366_smi *smi, unsigned port, - unsigned vid) -{ - struct rtl8366_vlan_mc vlanmc; - struct rtl8366_vlan_4k vlan4k; - int err; - int i; - - /* Try to find an existing MC entry for this VID */ - for (i = 0; i < RTL8366_NUM_VLANS; i++) { - err = rtl8366rb_get_vlan_mc(smi, i, &vlanmc); - if (err) - return err; - - if (vid == vlanmc.vid) { - err = rtl8366rb_set_vlan_mc(smi, i, &vlanmc); - if (err) - return err; - - err = rtl8366rb_set_mc_index(smi, port, i); - return err; - } - } - - /* We have no MC entry for this VID, try to find an empty one */ - for (i = 0; i < RTL8366_NUM_VLANS; i++) { - err = rtl8366rb_get_vlan_mc(smi, i, &vlanmc); - if (err) - return err; - - if (vlanmc.vid == 0 && vlanmc.member == 0) { - /* Update the entry from the 4K table */ - err = rtl8366rb_get_vlan_4k(smi, vid, &vlan4k); - if (err) - return err; - - vlanmc.vid = vid; - vlanmc.member = vlan4k.member; - vlanmc.untag = vlan4k.untag; - vlanmc.fid = vlan4k.fid; - err = rtl8366rb_set_vlan_mc(smi, i, &vlanmc); - if (err) - return err; - - err = rtl8366rb_set_mc_index(smi, port, i); - return err; - } - } - - /* MC table is full, try to find an unused entry and replace it */ - for (i = 0; i < RTL8366_NUM_VLANS; i++) { - int used; - - err = rtl8366rb_mc_is_used(smi, i, &used); - if (err) - return err; - - if (!used) { - /* Update the entry from the 4K table */ - err = rtl8366rb_get_vlan_4k(smi, vid, &vlan4k); - if (err) - return err; - - vlanmc.vid = vid; - vlanmc.member = vlan4k.member; - vlanmc.untag = vlan4k.untag; - vlanmc.fid = vlan4k.fid; - err = rtl8366rb_set_vlan_mc(smi, i, &vlanmc); - if (err) - return err; - - err = rtl8366rb_set_mc_index(smi, port, i); - return err; - } - } - - dev_err(smi->parent, - "all VLAN member configurations are in use\n"); - - return -ENOSPC; -} - -static int rtl8366rb_vlan_set_vlan(struct rtl8366_smi *smi, int enable) -{ - return rtl8366_smi_rmwr(smi, RTL8366_CHIP_GLOBAL_CTRL_REG, - RTL8366_CHIP_CTRL_VLAN, - (enable) ? RTL8366_CHIP_CTRL_VLAN : 0); -} - -static int rtl8366rb_vlan_set_4ktable(struct rtl8366_smi *smi, int enable) -{ - return rtl8366_smi_rmwr(smi, RTL8366_CHIP_GLOBAL_CTRL_REG, - RTL8366_CHIP_CTRL_VLAN_4KTB, - (enable) ? RTL8366_CHIP_CTRL_VLAN_4KTB : 0); -} - -static int rtl8366rb_reset_vlan(struct rtl8366_smi *smi) -{ - struct rtl8366_vlan_mc vlanmc; - int err; - int i; - - /* clear VLAN member configurations */ - vlanmc.vid = 0; - vlanmc.priority = 0; - vlanmc.member = 0; - vlanmc.untag = 0; - vlanmc.fid = 0; - for (i = 0; i < RTL8366_NUM_VLANS; i++) { - err = rtl8366rb_set_vlan_mc(smi, i, &vlanmc); - if (err) - return err; - } - - for (i = 0; i < RTL8366_NUM_PORTS; i++) { - if (i == RTL8366_PORT_CPU) - continue; - - err = rtl8366rb_set_vlan(smi, (i + 1), - (1 << i) | RTL8366_PORT_CPU, - (1 << i) | RTL8366_PORT_CPU, - 0); - if (err) - return err; - - err = rtl8366rb_set_pvid(smi, i, (i + 1)); - if (err) - return err; - } - - return 0; -} - -#ifdef CONFIG_RTL8366S_PHY_DEBUG_FS -static int rtl8366rb_debugfs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t rtl8366rb_read_debugfs_mibs(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct rtl8366rb *rtl = (struct rtl8366rb *)file->private_data; - struct rtl8366_smi *smi = &rtl->smi; - int i, j, len = 0; - char *buf = rtl->buf; - - len += snprintf(buf + len, sizeof(rtl->buf) - len, - "%-36s %12s %12s %12s %12s %12s %12s\n", - "Counter", - "Port 0", "Port 1", "Port 2", - "Port 3", "Port 4", "Port 5"); - - for (i = 0; i < ARRAY_SIZE(rtl8366rb_mib_counters); ++i) { - len += snprintf(buf + len, sizeof(rtl->buf) - len, "%-36s ", - rtl8366rb_mib_counters[i].name); - for (j = 0; j < RTL8366_NUM_PORTS; ++j) { - unsigned long long counter = 0; - - if (!rtl8366_get_mib_counter(smi, i, j, &counter)) - len += snprintf(buf + len, - sizeof(rtl->buf) - len, - "%12llu ", counter); - else - len += snprintf(buf + len, - sizeof(rtl->buf) - len, - "%12s ", "error"); - } - len += snprintf(buf + len, sizeof(rtl->buf) - len, "\n"); - } - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t rtl8366rb_read_debugfs_vlan_mc(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct rtl8366rb *rtl = (struct rtl8366rb *)file->private_data; - struct rtl8366_smi *smi = &rtl->smi; - int i, len = 0; - char *buf = rtl->buf; - - len += snprintf(buf + len, sizeof(rtl->buf) - len, - "%2s %6s %4s %6s %6s %3s\n", - "id", "vid","prio", "member", "untag", "fid"); - - for (i = 0; i < RTL8366_NUM_VLANS; ++i) { - struct rtl8366_vlan_mc vlanmc; - - rtl8366rb_get_vlan_mc(smi, i, &vlanmc); - - len += snprintf(buf + len, sizeof(rtl->buf) - len, - "%2d %6d %4d 0x%04x 0x%04x %3d\n", - i, vlanmc.vid, vlanmc.priority, - vlanmc.member, vlanmc.untag, vlanmc.fid); - } - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t rtl8366rb_read_debugfs_reg(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct rtl8366rb *rtl = (struct rtl8366rb *)file->private_data; - struct rtl8366_smi *smi = &rtl->smi; - u32 t, reg = gl_dbg_reg; - int err, len = 0; - char *buf = rtl->buf; - - memset(buf, '\0', sizeof(rtl->buf)); - - err = rtl8366_smi_read_reg(smi, reg, &t); - if (err) { - len += snprintf(buf, sizeof(rtl->buf), - "Read failed (reg: 0x%04x)\n", reg); - return simple_read_from_buffer(user_buf, count, ppos, buf, len); - } - - len += snprintf(buf, sizeof(rtl->buf), "reg = 0x%04x, val = 0x%04x\n", - reg, t); - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t rtl8366rb_write_debugfs_reg(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct rtl8366rb *rtl = (struct rtl8366rb *)file->private_data; - struct rtl8366_smi *smi = &rtl->smi; - unsigned long data; - u32 reg = gl_dbg_reg; - int err; - size_t len; - char *buf = rtl->buf; - - len = min(count, sizeof(rtl->buf) - 1); - if (copy_from_user(buf, user_buf, len)) { - dev_err(rtl->parent, "copy from user failed\n"); - return -EFAULT; - } - - buf[len] = '\0'; - if (len > 0 && buf[len - 1] == '\n') - buf[len - 1] = '\0'; - - - if (strict_strtoul(buf, 16, &data)) { - dev_err(rtl->parent, "Invalid reg value %s\n", buf); - } else { - err = rtl8366_smi_write_reg(smi, reg, data); - if (err) { - dev_err(rtl->parent, - "writing reg 0x%04x val 0x%04lx failed\n", - reg, data); - } - } - - return count; -} - -static const struct file_operations fops_rtl8366rb_regs = { - .read = rtl8366rb_read_debugfs_reg, - .write = rtl8366rb_write_debugfs_reg, - .open = rtl8366rb_debugfs_open, - .owner = THIS_MODULE -}; - -static const struct file_operations fops_rtl8366rb_vlan_mc = { - .read = rtl8366rb_read_debugfs_vlan_mc, - .open = rtl8366rb_debugfs_open, - .owner = THIS_MODULE -}; - -static const struct file_operations fops_rtl8366rb_mibs = { - .read = rtl8366rb_read_debugfs_mibs, - .open = rtl8366rb_debugfs_open, - .owner = THIS_MODULE -}; - -static void rtl8366rb_debugfs_init(struct rtl8366rb *rtl) -{ - struct dentry *node; - struct dentry *root; - - if (!rtl->debugfs_root) - rtl->debugfs_root = debugfs_create_dir("rtl8366rb", NULL); - - if (!rtl->debugfs_root) { - dev_err(rtl->parent, "Unable to create debugfs dir\n"); - return; - } - root = rtl->debugfs_root; - - node = debugfs_create_x16("reg", S_IRUGO | S_IWUSR, root, &gl_dbg_reg); - if (!node) { - dev_err(rtl->parent, "Creating debugfs file '%s' failed\n", - "reg"); - return; - } - - node = debugfs_create_file("val", S_IRUGO | S_IWUSR, root, rtl, - &fops_rtl8366rb_regs); - if (!node) { - dev_err(rtl->parent, "Creating debugfs file '%s' failed\n", - "val"); - return; - } - - node = debugfs_create_file("vlan_mc", S_IRUSR, root, rtl, - &fops_rtl8366rb_vlan_mc); - if (!node) { - dev_err(rtl->parent, "Creating debugfs file '%s' failed\n", - "vlan_mc"); - return; - } - - node = debugfs_create_file("mibs", S_IRUSR, root, rtl, - &fops_rtl8366rb_mibs); - if (!node) { - dev_err(rtl->parent, "Creating debugfs file '%s' failed\n", - "mibs"); - return; - } -} - -static void rtl8366rb_debugfs_remove(struct rtl8366rb *rtl) -{ - if (rtl->debugfs_root) { - debugfs_remove_recursive(rtl->debugfs_root); - rtl->debugfs_root = NULL; - } -} - -#else -static inline void rtl8366rb_debugfs_init(struct rtl8366rb *rtl) {} -static inline void rtl8366rb_debugfs_remove(struct rtl8366rb *rtl) {} -#endif /* CONFIG_RTL8366S_PHY_DEBUG_FS */ - -static int rtl8366rb_sw_reset_mibs(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - int err = 0; - - if (val->value.i == 1) - err = rtl8366_smi_rmwr(smi, RTL8366S_MIB_CTRL_REG, 0, (1 << 2)); - - return err; -} - -static int rtl8366rb_sw_get_vlan_enable(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - u32 data; - - if (attr->ofs == 1) { - rtl8366_smi_read_reg(smi, RTL8366_CHIP_GLOBAL_CTRL_REG, &data); - - if (data & RTL8366_CHIP_CTRL_VLAN) - val->value.i = 1; - else - val->value.i = 0; - } else if (attr->ofs == 2) { - rtl8366_smi_read_reg(smi, RTL8366_CHIP_GLOBAL_CTRL_REG, &data); - - if (data & RTL8366_CHIP_CTRL_VLAN_4KTB) - val->value.i = 1; - else - val->value.i = 0; - } - - return 0; -} - -static int rtl8366rb_sw_get_blinkrate(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - u32 data; - - rtl8366_smi_read_reg(smi, RTL8366_LED_BLINKRATE_REG, &data); - - val->value.i = (data & (RTL8366_LED_BLINKRATE_MASK)); - - return 0; -} - -static int rtl8366rb_sw_set_blinkrate(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - - if (val->value.i >= 6) - return -EINVAL; - - return rtl8366_smi_rmwr(smi, RTL8366_LED_BLINKRATE_REG, - RTL8366_LED_BLINKRATE_MASK, - val->value.i); -} - -static int rtl8366rb_sw_set_vlan_enable(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - - if (attr->ofs == 1) - return rtl8366rb_vlan_set_vlan(smi, val->value.i); - else - return rtl8366rb_vlan_set_4ktable(smi, val->value.i); -} - -static const char *rtl8366rb_speed_str(unsigned speed) -{ - switch (speed) { - case 0: - return "10baseT"; - case 1: - return "100baseT"; - case 2: - return "1000baseT"; - } - - return "unknown"; -} - -static int rtl8366rb_sw_get_port_link(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - struct rtl8366rb *rtl = sw_to_rtl8366rb(dev); - struct rtl8366_smi *smi = &rtl->smi; - u32 len = 0, data = 0; - - if (val->port_vlan >= RTL8366_NUM_PORTS) - return -EINVAL; - - memset(rtl->buf, '\0', sizeof(rtl->buf)); - rtl8366_smi_read_reg(smi, RTL8366S_PORT_LINK_STATUS_BASE + - (val->port_vlan / 2), &data); - - if (val->port_vlan % 2) - data = data >> 8; - - if (data & RTL8366S_PORT_STATUS_LINK_MASK) { - len = snprintf(rtl->buf, sizeof(rtl->buf), - "port:%d link:up speed:%s %s-duplex %s%s%s", - val->port_vlan, - rtl8366rb_speed_str(data & - RTL8366S_PORT_STATUS_SPEED_MASK), - (data & RTL8366S_PORT_STATUS_DUPLEX_MASK) ? - "full" : "half", - (data & RTL8366S_PORT_STATUS_TXPAUSE_MASK) ? - "tx-pause ": "", - (data & RTL8366S_PORT_STATUS_RXPAUSE_MASK) ? - "rx-pause " : "", - (data & RTL8366S_PORT_STATUS_AN_MASK) ? - "nway ": ""); - } else { - len = snprintf(rtl->buf, sizeof(rtl->buf), "port:%d link: down", - val->port_vlan); - } - - val->value.s = rtl->buf; - val->len = len; - - return 0; -} - -static int rtl8366rb_sw_get_vlan_info(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - int i; - u32 len = 0; - struct rtl8366_vlan_4k vlan4k; - struct rtl8366rb *rtl = sw_to_rtl8366rb(dev); - struct rtl8366_smi *smi = &rtl->smi; - char *buf = rtl->buf; - int err; - - if (val->port_vlan == 0 || val->port_vlan >= RTL8366_NUM_VLANS) - return -EINVAL; - - memset(buf, '\0', sizeof(rtl->buf)); - - err = rtl8366rb_get_vlan_4k(smi, val->port_vlan, &vlan4k); - if (err) - return err; - - len += snprintf(buf + len, sizeof(rtl->buf) - len, - "VLAN %d: Ports: '", vlan4k.vid); - - for (i = 0; i < RTL8366_NUM_PORTS; i++) { - if (!(vlan4k.member & (1 << i))) - continue; - - len += snprintf(buf + len, sizeof(rtl->buf) - len, "%d%s", i, - (vlan4k.untag & (1 << i)) ? "" : "t"); - } - - len += snprintf(buf + len, sizeof(rtl->buf) - len, - "', members=%04x, untag=%04x, fid=%u", - vlan4k.member, vlan4k.untag, vlan4k.fid); - - val->value.s = buf; - val->len = len; - - return 0; -} - -static int rtl8366rb_sw_set_port_led(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - u32 data; - u32 mask; - u32 reg; - - if (val->port_vlan >= RTL8366_NUM_PORTS) - return -EINVAL; - - if (val->port_vlan == RTL8366_PORT_NUM_CPU) { - reg = RTL8366_LED_BLINKRATE_REG; - mask = 0xF << 4; - data = val->value.i << 4; - } else { - reg = RTL8366_LED_CTRL_REG; - mask = 0xF << (val->port_vlan * 4), - data = val->value.i << (val->port_vlan * 4); - } - - return rtl8366_smi_rmwr(smi, RTL8366_LED_BLINKRATE_REG, mask, data); -} - -static int rtl8366rb_sw_get_port_led(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - u32 data = 0; - - if (val->port_vlan >= RTL8366_NUM_LEDGROUPS) - return -EINVAL; - - rtl8366_smi_read_reg(smi, RTL8366_LED_CTRL_REG, &data); - val->value.i = (data >> (val->port_vlan * 4)) & 0x000F; - - return 0; -} - -static int rtl8366rb_sw_reset_port_mibs(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - - if (val->port_vlan >= RTL8366_NUM_PORTS) - return -EINVAL; - - return rtl8366_smi_rmwr(smi, RTL8366S_MIB_CTRL_REG, - 0, (1 << (val->port_vlan + 3))); -} - -static int rtl8366rb_sw_get_port_mib(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - struct rtl8366rb *rtl = sw_to_rtl8366rb(dev); - struct rtl8366_smi *smi = &rtl->smi; - int i, len = 0; - unsigned long long counter = 0; - char *buf = rtl->buf; - - if (val->port_vlan >= RTL8366_NUM_PORTS) - return -EINVAL; - - len += snprintf(buf + len, sizeof(rtl->buf) - len, - "Port %d MIB counters\n", - val->port_vlan); - - for (i = 0; i < ARRAY_SIZE(rtl8366rb_mib_counters); ++i) { - len += snprintf(buf + len, sizeof(rtl->buf) - len, - "%-36s: ", rtl8366rb_mib_counters[i].name); - if (!rtl8366_get_mib_counter(smi, i, val->port_vlan, &counter)) - len += snprintf(buf + len, sizeof(rtl->buf) - len, - "%llu\n", counter); - else - len += snprintf(buf + len, sizeof(rtl->buf) - len, - "%s\n", "error"); - } - - val->value.s = buf; - val->len = len; - return 0; -} - -static int rtl8366rb_sw_get_vlan_ports(struct switch_dev *dev, - struct switch_val *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - struct switch_port *port; - struct rtl8366_vlan_4k vlan4k; - int i; - - if (val->port_vlan == 0 || val->port_vlan >= RTL8366_NUM_VLANS) - return -EINVAL; - - rtl8366rb_get_vlan_4k(smi, val->port_vlan, &vlan4k); - - port = &val->value.ports[0]; - val->len = 0; - for (i = 0; i < RTL8366_NUM_PORTS; i++) { - if (!(vlan4k.member & BIT(i))) - continue; - - port->id = i; - port->flags = (vlan4k.untag & BIT(i)) ? - 0 : BIT(SWITCH_PORT_FLAG_TAGGED); - val->len++; - port++; - } - return 0; -} - -static int rtl8366rb_sw_set_vlan_ports(struct switch_dev *dev, - struct switch_val *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - struct switch_port *port; - u32 member = 0; - u32 untag = 0; - int i; - - if (val->port_vlan == 0 || val->port_vlan >= RTL8366_NUM_VLANS) - return -EINVAL; - - port = &val->value.ports[0]; - for (i = 0; i < val->len; i++, port++) { - member |= BIT(port->id); - - if (!(port->flags & BIT(SWITCH_PORT_FLAG_TAGGED))) - untag |= BIT(port->id); - } - - return rtl8366rb_set_vlan(smi, val->port_vlan, member, untag, 0); -} - -static int rtl8366rb_sw_get_port_pvid(struct switch_dev *dev, int port, int *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - return rtl8366rb_get_pvid(smi, port, val); -} - -static int rtl8366rb_sw_set_port_pvid(struct switch_dev *dev, int port, int val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - return rtl8366rb_set_pvid(smi, port, val); -} - -static int rtl8366rb_sw_reset_switch(struct switch_dev *dev) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - int err; - - err = rtl8366rb_reset_chip(smi); - if (err) - return err; - - err = rtl8366rb_hw_init(smi); - if (err) - return err; - - return rtl8366rb_reset_vlan(smi); -} - -static struct switch_attr rtl8366rb_globals[] = { - { - .type = SWITCH_TYPE_INT, - .name = "enable_vlan", - .description = "Enable VLAN mode", - .set = rtl8366rb_sw_set_vlan_enable, - .get = rtl8366rb_sw_get_vlan_enable, - .max = 1, - .ofs = 1 - }, { - .type = SWITCH_TYPE_INT, - .name = "enable_vlan4k", - .description = "Enable VLAN 4K mode", - .set = rtl8366rb_sw_set_vlan_enable, - .get = rtl8366rb_sw_get_vlan_enable, - .max = 1, - .ofs = 2 - }, { - .type = SWITCH_TYPE_INT, - .name = "reset_mibs", - .description = "Reset all MIB counters", - .set = rtl8366rb_sw_reset_mibs, - .get = NULL, - .max = 1 - }, { - .type = SWITCH_TYPE_INT, - .name = "blinkrate", - .description = "Get/Set LED blinking rate (0 = 43ms, 1 = 84ms," - " 2 = 120ms, 3 = 170ms, 4 = 340ms, 5 = 670ms)", - .set = rtl8366rb_sw_set_blinkrate, - .get = rtl8366rb_sw_get_blinkrate, - .max = 5 - }, -}; - -static struct switch_attr rtl8366rb_port[] = { - { - .type = SWITCH_TYPE_STRING, - .name = "link", - .description = "Get port link information", - .max = 1, - .set = NULL, - .get = rtl8366rb_sw_get_port_link, - }, { - .type = SWITCH_TYPE_INT, - .name = "reset_mib", - .description = "Reset single port MIB counters", - .max = 1, - .set = rtl8366rb_sw_reset_port_mibs, - .get = NULL, - }, { - .type = SWITCH_TYPE_STRING, - .name = "mib", - .description = "Get MIB counters for port", - .max = 33, - .set = NULL, - .get = rtl8366rb_sw_get_port_mib, - }, { - .type = SWITCH_TYPE_INT, - .name = "led", - .description = "Get/Set port group (0 - 3) led mode (0 - 15)", - .max = 15, - .set = rtl8366rb_sw_set_port_led, - .get = rtl8366rb_sw_get_port_led, - }, -}; - -static struct switch_attr rtl8366rb_vlan[] = { - { - .type = SWITCH_TYPE_STRING, - .name = "info", - .description = "Get vlan information", - .max = 1, - .set = NULL, - .get = rtl8366rb_sw_get_vlan_info, - }, -}; - -/* template */ -static struct switch_dev rtl8366_switch_dev = { - .name = "RTL8366S", - .cpu_port = RTL8366_PORT_NUM_CPU, - .ports = RTL8366_NUM_PORTS, - .vlans = RTL8366_NUM_VLANS, - .attr_global = { - .attr = rtl8366rb_globals, - .n_attr = ARRAY_SIZE(rtl8366rb_globals), - }, - .attr_port = { - .attr = rtl8366rb_port, - .n_attr = ARRAY_SIZE(rtl8366rb_port), - }, - .attr_vlan = { - .attr = rtl8366rb_vlan, - .n_attr = ARRAY_SIZE(rtl8366rb_vlan), - }, - - .get_vlan_ports = rtl8366rb_sw_get_vlan_ports, - .set_vlan_ports = rtl8366rb_sw_set_vlan_ports, - .get_port_pvid = rtl8366rb_sw_get_port_pvid, - .set_port_pvid = rtl8366rb_sw_set_port_pvid, - .reset_switch = rtl8366rb_sw_reset_switch, -}; - -static int rtl8366rb_switch_init(struct rtl8366rb *rtl) -{ - struct switch_dev *dev = &rtl->dev; - int err; - - memcpy(dev, &rtl8366_switch_dev, sizeof(struct switch_dev)); - dev->priv = rtl; - dev->devname = dev_name(rtl->parent); - - err = register_switch(dev, NULL); - if (err) - dev_err(rtl->parent, "switch registration failed\n"); - - return err; -} - -static void rtl8366rb_switch_cleanup(struct rtl8366rb *rtl) -{ - unregister_switch(&rtl->dev); -} - -static int rtl8366rb_mii_read(struct mii_bus *bus, int addr, int reg) -{ - struct rtl8366_smi *smi = bus->priv; - u32 val = 0; - int err; - - err = rtl8366rb_read_phy_reg(smi, addr, 0, reg, &val); - if (err) - return 0xffff; - - return val; -} - -static int rtl8366rb_mii_write(struct mii_bus *bus, int addr, int reg, u16 val) -{ - struct rtl8366_smi *smi = bus->priv; - u32 t; - int err; - - err = rtl8366rb_write_phy_reg(smi, addr, 0, reg, val); - /* flush write */ - (void) rtl8366rb_read_phy_reg(smi, addr, 0, reg, &t); - - return err; -} - -static int rtl8366rb_mii_bus_match(struct mii_bus *bus) -{ - return (bus->read == rtl8366rb_mii_read && - bus->write == rtl8366rb_mii_write); -} - -static int rtl8366rb_setup(struct rtl8366rb *rtl) -{ - struct rtl8366_smi *smi = &rtl->smi; - int ret; - - rtl8366rb_debugfs_init(rtl); - - ret = rtl8366rb_reset_chip(smi); - if (ret) - return ret; - - ret = rtl8366rb_hw_init(smi); - return ret; -} - -static int rtl8366rb_detect(struct rtl8366_smi *smi) -{ - u32 chip_id = 0; - u32 chip_ver = 0; - int ret; - - ret = rtl8366_smi_read_reg(smi, RTL8366S_CHIP_ID_REG, &chip_id); - if (ret) { - dev_err(smi->parent, "unable to read chip id\n"); - return ret; - } - - switch (chip_id) { - case RTL8366S_CHIP_ID_8366: - break; - default: - dev_err(smi->parent, "unknown chip id (%04x)\n", chip_id); - return -ENODEV; - } - - ret = rtl8366_smi_read_reg(smi, RTL8366S_CHIP_VERSION_CTRL_REG, - &chip_ver); - if (ret) { - dev_err(smi->parent, "unable to read chip version\n"); - return ret; - } - - dev_info(smi->parent, "RTL%04x ver. %u chip found\n", - chip_id, chip_ver & RTL8366S_CHIP_VERSION_MASK); - - return 0; -} - -static struct rtl8366_smi_ops rtl8366rb_smi_ops = { - .detect = rtl8366rb_detect, - .mii_read = rtl8366rb_mii_read, - .mii_write = rtl8366rb_mii_write, -}; - -static int __init rtl8366rb_probe(struct platform_device *pdev) -{ - static int rtl8366_smi_version_printed; - struct rtl8366rb_platform_data *pdata; - struct rtl8366rb *rtl; - struct rtl8366_smi *smi; - int err; - - if (!rtl8366_smi_version_printed++) - printk(KERN_NOTICE RTL8366S_DRIVER_DESC - " version " RTL8366S_DRIVER_VER"\n"); - - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "no platform data specified\n"); - err = -EINVAL; - goto err_out; - } - - rtl = kzalloc(sizeof(*rtl), GFP_KERNEL); - if (!rtl) { - dev_err(&pdev->dev, "no memory for private data\n"); - err = -ENOMEM; - goto err_out; - } - - rtl->parent = &pdev->dev; - - smi = &rtl->smi; - smi->parent = &pdev->dev; - smi->gpio_sda = pdata->gpio_sda; - smi->gpio_sck = pdata->gpio_sck; - smi->ops = &rtl8366rb_smi_ops; - - err = rtl8366_smi_init(smi); - if (err) - goto err_free_rtl; - - platform_set_drvdata(pdev, rtl); - - err = rtl8366rb_setup(rtl); - if (err) - goto err_clear_drvdata; - - err = rtl8366rb_switch_init(rtl); - if (err) - goto err_clear_drvdata; - - return 0; - - err_clear_drvdata: - platform_set_drvdata(pdev, NULL); - rtl8366_smi_cleanup(smi); - err_free_rtl: - kfree(rtl); - err_out: - return err; -} - -static int rtl8366rb_phy_config_init(struct phy_device *phydev) -{ - if (!rtl8366rb_mii_bus_match(phydev->bus)) - return -EINVAL; - - return 0; -} - -static int rtl8366rb_phy_config_aneg(struct phy_device *phydev) -{ - return 0; -} - -static struct phy_driver rtl8366rb_phy_driver = { - .phy_id = 0x001cc960, - .name = "Realtek RTL8366RB", - .phy_id_mask = 0x1ffffff0, - .features = PHY_GBIT_FEATURES, - .config_aneg = rtl8366rb_phy_config_aneg, - .config_init = rtl8366rb_phy_config_init, - .read_status = genphy_read_status, - .driver = { - .owner = THIS_MODULE, - }, -}; - -static int __devexit rtl8366rb_remove(struct platform_device *pdev) -{ - struct rtl8366rb *rtl = platform_get_drvdata(pdev); - - if (rtl) { - rtl8366rb_switch_cleanup(rtl); - rtl8366rb_debugfs_remove(rtl); - platform_set_drvdata(pdev, NULL); - rtl8366_smi_cleanup(&rtl->smi); - kfree(rtl); - } - - return 0; -} - -static struct platform_driver rtl8366rb_driver = { - .driver = { - .name = RTL8366RB_DRIVER_NAME, - .owner = THIS_MODULE, - }, - .probe = rtl8366rb_probe, - .remove = __devexit_p(rtl8366rb_remove), -}; - -static int __init rtl8366rb_module_init(void) -{ - int ret; - ret = platform_driver_register(&rtl8366rb_driver); - if (ret) - return ret; - - ret = phy_driver_register(&rtl8366rb_phy_driver); - if (ret) - goto err_platform_unregister; - - return 0; - - err_platform_unregister: - platform_driver_unregister(&rtl8366rb_driver); - return ret; -} -module_init(rtl8366rb_module_init); - -static void __exit rtl8366rb_module_exit(void) -{ - phy_driver_unregister(&rtl8366rb_phy_driver); - platform_driver_unregister(&rtl8366rb_driver); -} -module_exit(rtl8366rb_module_exit); - -MODULE_DESCRIPTION(RTL8366S_DRIVER_DESC); -MODULE_VERSION(RTL8366S_DRIVER_VER); -MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); -MODULE_AUTHOR("Antti Seppälä <a.seppala@gmail.com>"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" RTL8366RB_DRIVER_NAME); diff --git a/target/linux/generic-2.6/files/drivers/net/phy/rtl8366s.c b/target/linux/generic-2.6/files/drivers/net/phy/rtl8366s.c deleted file mode 100644 index da8fe556c..000000000 --- a/target/linux/generic-2.6/files/drivers/net/phy/rtl8366s.c +++ /dev/null @@ -1,1785 +0,0 @@ -/* - * Platform driver for the Realtek RTL8366S ethernet switch - * - * Copyright (C) 2009-2010 Gabor Juhos <juhosg@openwrt.org> - * Copyright (C) 2010 Antti Seppälä <a.seppala@gmail.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/delay.h> -#include <linux/skbuff.h> -#include <linux/switch.h> -#include <linux/rtl8366s.h> - -#include "rtl8366_smi.h" - -#ifdef CONFIG_RTL8366S_PHY_DEBUG_FS -#include <linux/debugfs.h> -#endif - -#define RTL8366S_DRIVER_DESC "Realtek RTL8366S ethernet switch driver" -#define RTL8366S_DRIVER_VER "0.2.2" - -#define RTL8366S_PHY_NO_MAX 4 -#define RTL8366S_PHY_PAGE_MAX 7 -#define RTL8366S_PHY_ADDR_MAX 31 - -#define RTL8366_CHIP_GLOBAL_CTRL_REG 0x0000 -#define RTL8366_CHIP_CTRL_VLAN (1 << 13) - -/* Switch Global Configuration register */ -#define RTL8366_SGCR 0x0000 -#define RTL8366_SGCR_EN_BC_STORM_CTRL BIT(0) -#define RTL8366_SGCR_MAX_LENGTH(_x) (_x << 4) -#define RTL8366_SGCR_MAX_LENGTH_MASK RTL8366_SGCR_MAX_LENGTH(0x3) -#define RTL8366_SGCR_MAX_LENGTH_1522 RTL8366_SGCR_MAX_LENGTH(0x0) -#define RTL8366_SGCR_MAX_LENGTH_1536 RTL8366_SGCR_MAX_LENGTH(0x1) -#define RTL8366_SGCR_MAX_LENGTH_1552 RTL8366_SGCR_MAX_LENGTH(0x2) -#define RTL8366_SGCR_MAX_LENGTH_16000 RTL8366_SGCR_MAX_LENGTH(0x3) - -/* Port Enable Control register */ -#define RTL8366_PECR 0x0001 - -/* Switch Security Control registers */ -#define RTL8366_SSCR0 0x0002 -#define RTL8366_SSCR1 0x0003 -#define RTL8366_SSCR2 0x0004 -#define RTL8366_SSCR2_DROP_UNKNOWN_DA BIT(0) - -#define RTL8366_RESET_CTRL_REG 0x0100 -#define RTL8366_CHIP_CTRL_RESET_HW 1 -#define RTL8366_CHIP_CTRL_RESET_SW (1 << 1) - -#define RTL8366S_CHIP_VERSION_CTRL_REG 0x0104 -#define RTL8366S_CHIP_VERSION_MASK 0xf -#define RTL8366S_CHIP_ID_REG 0x0105 -#define RTL8366S_CHIP_ID_8366 0x8366 - -/* PHY registers control */ -#define RTL8366S_PHY_ACCESS_CTRL_REG 0x8028 -#define RTL8366S_PHY_ACCESS_DATA_REG 0x8029 - -#define RTL8366S_PHY_CTRL_READ 1 -#define RTL8366S_PHY_CTRL_WRITE 0 - -#define RTL8366S_PHY_REG_MASK 0x1f -#define RTL8366S_PHY_PAGE_OFFSET 5 -#define RTL8366S_PHY_PAGE_MASK (0x7 << 5) -#define RTL8366S_PHY_NO_OFFSET 9 -#define RTL8366S_PHY_NO_MASK (0x1f << 9) - -/* LED control registers */ -#define RTL8366_LED_BLINKRATE_REG 0x0420 -#define RTL8366_LED_BLINKRATE_BIT 0 -#define RTL8366_LED_BLINKRATE_MASK 0x0007 - -#define RTL8366_LED_CTRL_REG 0x0421 -#define RTL8366_LED_0_1_CTRL_REG 0x0422 -#define RTL8366_LED_2_3_CTRL_REG 0x0423 - -#define RTL8366S_MIB_COUNT 33 -#define RTL8366S_GLOBAL_MIB_COUNT 1 -#define RTL8366S_MIB_COUNTER_PORT_OFFSET 0x0040 -#define RTL8366S_MIB_COUNTER_BASE 0x1000 -#define RTL8366S_MIB_COUNTER_PORT_OFFSET2 0x0008 -#define RTL8366S_MIB_COUNTER_BASE2 0x1180 -#define RTL8366S_MIB_CTRL_REG 0x11F0 -#define RTL8366S_MIB_CTRL_USER_MASK 0x01FF -#define RTL8366S_MIB_CTRL_BUSY_MASK 0x0001 -#define RTL8366S_MIB_CTRL_RESET_MASK 0x0002 - -#define RTL8366S_MIB_CTRL_GLOBAL_RESET_MASK 0x0004 -#define RTL8366S_MIB_CTRL_PORT_RESET_BIT 0x0003 -#define RTL8366S_MIB_CTRL_PORT_RESET_MASK 0x01FC - - -#define RTL8366S_PORT_VLAN_CTRL_BASE 0x0058 -#define RTL8366S_PORT_VLAN_CTRL_REG(_p) \ - (RTL8366S_PORT_VLAN_CTRL_BASE + (_p) / 4) -#define RTL8366S_PORT_VLAN_CTRL_MASK 0xf -#define RTL8366S_PORT_VLAN_CTRL_SHIFT(_p) (4 * ((_p) % 4)) - - -#define RTL8366S_VLAN_TABLE_READ_BASE 0x018B -#define RTL8366S_VLAN_TABLE_WRITE_BASE 0x0185 - -#define RTL8366S_VLAN_TB_CTRL_REG 0x010F - -#define RTL8366S_TABLE_ACCESS_CTRL_REG 0x0180 -#define RTL8366S_TABLE_VLAN_READ_CTRL 0x0E01 -#define RTL8366S_TABLE_VLAN_WRITE_CTRL 0x0F01 - -#define RTL8366S_VLAN_MEMCONF_BASE 0x0016 - - -#define RTL8366S_PORT_LINK_STATUS_BASE 0x0060 -#define RTL8366S_PORT_STATUS_SPEED_MASK 0x0003 -#define RTL8366S_PORT_STATUS_DUPLEX_MASK 0x0004 -#define RTL8366S_PORT_STATUS_LINK_MASK 0x0010 -#define RTL8366S_PORT_STATUS_TXPAUSE_MASK 0x0020 -#define RTL8366S_PORT_STATUS_RXPAUSE_MASK 0x0040 -#define RTL8366S_PORT_STATUS_AN_MASK 0x0080 - - -#define RTL8366_PORT_NUM_CPU 5 -#define RTL8366_NUM_PORTS 6 -#define RTL8366_NUM_VLANS 16 -#define RTL8366_NUM_LEDGROUPS 4 -#define RTL8366_NUM_VIDS 4096 -#define RTL8366S_PRIORITYMAX 7 -#define RTL8366S_FIDMAX 7 - - -#define RTL8366_PORT_1 (1 << 0) /* In userspace port 0 */ -#define RTL8366_PORT_2 (1 << 1) /* In userspace port 1 */ -#define RTL8366_PORT_3 (1 << 2) /* In userspace port 2 */ -#define RTL8366_PORT_4 (1 << 3) /* In userspace port 3 */ - -#define RTL8366_PORT_UNKNOWN (1 << 4) /* No known connection */ -#define RTL8366_PORT_CPU (1 << 5) /* CPU port */ - -#define RTL8366_PORT_ALL (RTL8366_PORT_1 | \ - RTL8366_PORT_2 | \ - RTL8366_PORT_3 | \ - RTL8366_PORT_4 | \ - RTL8366_PORT_UNKNOWN | \ - RTL8366_PORT_CPU) - -#define RTL8366_PORT_ALL_BUT_CPU (RTL8366_PORT_1 | \ - RTL8366_PORT_2 | \ - RTL8366_PORT_3 | \ - RTL8366_PORT_4 | \ - RTL8366_PORT_UNKNOWN) - -#define RTL8366_PORT_ALL_EXTERNAL (RTL8366_PORT_1 | \ - RTL8366_PORT_2 | \ - RTL8366_PORT_3 | \ - RTL8366_PORT_4) - -#define RTL8366_PORT_ALL_INTERNAL (RTL8366_PORT_UNKNOWN | \ - RTL8366_PORT_CPU) - -struct rtl8366s { - struct device *parent; - struct rtl8366_smi smi; - struct switch_dev dev; - char buf[4096]; -#ifdef CONFIG_RTL8366S_PHY_DEBUG_FS - struct dentry *debugfs_root; -#endif -}; - -struct rtl8366s_vlan_mc { - u16 reserved2:1; - u16 priority:3; - u16 vid:12; - - u16 reserved1:1; - u16 fid:3; - u16 untag:6; - u16 member:6; -}; - -struct rtl8366s_vlan_4k { - u16 reserved1:4; - u16 vid:12; - - u16 reserved2:1; - u16 fid:3; - u16 untag:6; - u16 member:6; -}; - -#ifdef CONFIG_RTL8366S_PHY_DEBUG_FS -u16 g_dbg_reg; -#endif - -struct mib_counter { - unsigned base; - unsigned offset; - unsigned length; - const char *name; -}; - -static struct mib_counter rtl8366s_mib_counters[RTL8366S_MIB_COUNT] = { - { 0, 0, 4, "IfInOctets" }, - { 0, 4, 4, "EtherStatsOctets" }, - { 0, 8, 2, "EtherStatsUnderSizePkts" }, - { 0, 10, 2, "EtherFragments" }, - { 0, 12, 2, "EtherStatsPkts64Octets" }, - { 0, 14, 2, "EtherStatsPkts65to127Octets" }, - { 0, 16, 2, "EtherStatsPkts128to255Octets" }, - { 0, 18, 2, "EtherStatsPkts256to511Octets" }, - { 0, 20, 2, "EtherStatsPkts512to1023Octets" }, - { 0, 22, 2, "EtherStatsPkts1024to1518Octets" }, - { 0, 24, 2, "EtherOversizeStats" }, - { 0, 26, 2, "EtherStatsJabbers" }, - { 0, 28, 2, "IfInUcastPkts" }, - { 0, 30, 2, "EtherStatsMulticastPkts" }, - { 0, 32, 2, "EtherStatsBroadcastPkts" }, - { 0, 34, 2, "EtherStatsDropEvents" }, - { 0, 36, 2, "Dot3StatsFCSErrors" }, - { 0, 38, 2, "Dot3StatsSymbolErrors" }, - { 0, 40, 2, "Dot3InPauseFrames" }, - { 0, 42, 2, "Dot3ControlInUnknownOpcodes" }, - { 0, 44, 4, "IfOutOctets" }, - { 0, 48, 2, "Dot3StatsSingleCollisionFrames" }, - { 0, 50, 2, "Dot3StatMultipleCollisionFrames" }, - { 0, 52, 2, "Dot3sDeferredTransmissions" }, - { 0, 54, 2, "Dot3StatsLateCollisions" }, - { 0, 56, 2, "EtherStatsCollisions" }, - { 0, 58, 2, "Dot3StatsExcessiveCollisions" }, - { 0, 60, 2, "Dot3OutPauseFrames" }, - { 0, 62, 2, "Dot1dBasePortDelayExceededDiscards" }, - - /* - * The following counters are accessible at a different - * base address. - */ - { 1, 0, 2, "Dot1dTpPortInDiscards" }, - { 1, 2, 2, "IfOutUcastPkts" }, - { 1, 4, 2, "IfOutMulticastPkts" }, - { 1, 6, 2, "IfOutBroadcastPkts" }, -}; - -#define REG_WR(_smi, _reg, _val) \ - do { \ - err = rtl8366_smi_write_reg(_smi, _reg, _val); \ - if (err) \ - return err; \ - } while (0) - -#define REG_RMW(_smi, _reg, _mask, _val) \ - do { \ - err = rtl8366_smi_rmwr(_smi, _reg, _mask, _val); \ - if (err) \ - return err; \ - } while (0) - -static inline struct rtl8366s *smi_to_rtl8366s(struct rtl8366_smi *smi) -{ - return container_of(smi, struct rtl8366s, smi); -} - -static inline struct rtl8366s *sw_to_rtl8366s(struct switch_dev *sw) -{ - return container_of(sw, struct rtl8366s, dev); -} - -static inline struct rtl8366_smi *sw_to_rtl8366_smi(struct switch_dev *sw) -{ - struct rtl8366s *rtl = sw_to_rtl8366s(sw); - return &rtl->smi; -} - -static int rtl8366s_reset_chip(struct rtl8366_smi *smi) -{ - int timeout = 10; - u32 data; - - rtl8366_smi_write_reg(smi, RTL8366_RESET_CTRL_REG, - RTL8366_CHIP_CTRL_RESET_HW); - do { - msleep(1); - if (rtl8366_smi_read_reg(smi, RTL8366_RESET_CTRL_REG, &data)) - return -EIO; - - if (!(data & RTL8366_CHIP_CTRL_RESET_HW)) - break; - } while (--timeout); - - if (!timeout) { - printk("Timeout waiting for the switch to reset\n"); - return -EIO; - } - - return 0; -} - -static int rtl8366s_hw_init(struct rtl8366_smi *smi) -{ - int err; - - /* set maximum packet length to 1536 bytes */ - REG_RMW(smi, RTL8366_SGCR, RTL8366_SGCR_MAX_LENGTH_MASK, - RTL8366_SGCR_MAX_LENGTH_1536); - - /* enable all ports */ - REG_WR(smi, RTL8366_PECR, 0); - - /* disable learning for all ports */ - REG_WR(smi, RTL8366_SSCR0, RTL8366_PORT_ALL); - - /* disable auto ageing for all ports */ - REG_WR(smi, RTL8366_SSCR1, RTL8366_PORT_ALL); - - /* don't drop packets whose DA has not been learned */ - REG_RMW(smi, RTL8366_SSCR2, RTL8366_SSCR2_DROP_UNKNOWN_DA, 0); - - return 0; -} - -static int rtl8366s_read_phy_reg(struct rtl8366_smi *smi, - u32 phy_no, u32 page, u32 addr, u32 *data) -{ - u32 reg; - int ret; - - if (phy_no > RTL8366S_PHY_NO_MAX) - return -EINVAL; - - if (page > RTL8366S_PHY_PAGE_MAX) - return -EINVAL; - - if (addr > RTL8366S_PHY_ADDR_MAX) - return -EINVAL; - - ret = rtl8366_smi_write_reg(smi, RTL8366S_PHY_ACCESS_CTRL_REG, - RTL8366S_PHY_CTRL_READ); - if (ret) - return ret; - - reg = 0x8000 | (1 << (phy_no + RTL8366S_PHY_NO_OFFSET)) | - ((page << RTL8366S_PHY_PAGE_OFFSET) & RTL8366S_PHY_PAGE_MASK) | - (addr & RTL8366S_PHY_REG_MASK); - - ret = rtl8366_smi_write_reg(smi, reg, 0); - if (ret) - return ret; - - ret = rtl8366_smi_read_reg(smi, RTL8366S_PHY_ACCESS_DATA_REG, data); - if (ret) - return ret; - - return 0; -} - -static int rtl8366s_write_phy_reg(struct rtl8366_smi *smi, - u32 phy_no, u32 page, u32 addr, u32 data) -{ - u32 reg; - int ret; - - if (phy_no > RTL8366S_PHY_NO_MAX) - return -EINVAL; - - if (page > RTL8366S_PHY_PAGE_MAX) - return -EINVAL; - - if (addr > RTL8366S_PHY_ADDR_MAX) - return -EINVAL; - - ret = rtl8366_smi_write_reg(smi, RTL8366S_PHY_ACCESS_CTRL_REG, - RTL8366S_PHY_CTRL_WRITE); - if (ret) - return ret; - - reg = 0x8000 | (1 << (phy_no + RTL8366S_PHY_NO_OFFSET)) | - ((page << RTL8366S_PHY_PAGE_OFFSET) & RTL8366S_PHY_PAGE_MASK) | - (addr & RTL8366S_PHY_REG_MASK); - - ret = rtl8366_smi_write_reg(smi, reg, data); - if (ret) - return ret; - - return 0; -} - -static int rtl8366_get_mib_counter(struct rtl8366_smi *smi, int counter, - int port, unsigned long long *val) -{ - int i; - int err; - u32 addr, data; - u64 mibvalue; - - if (port > RTL8366_NUM_PORTS || counter >= RTL8366S_MIB_COUNT) - return -EINVAL; - - switch (rtl8366s_mib_counters[counter].base) { - case 0: - addr = RTL8366S_MIB_COUNTER_BASE + - RTL8366S_MIB_COUNTER_PORT_OFFSET * port; - break; - - case 1: - addr = RTL8366S_MIB_COUNTER_BASE2 + - RTL8366S_MIB_COUNTER_PORT_OFFSET2 * port; - break; - - default: - return -EINVAL; - } - - addr += rtl8366s_mib_counters[counter].offset; - - /* - * Writing access counter address first - * then ASIC will prepare 64bits counter wait for being retrived - */ - data = 0; /* writing data will be discard by ASIC */ - err = rtl8366_smi_write_reg(smi, addr, data); - if (err) - return err; - - /* read MIB control register */ - err = rtl8366_smi_read_reg(smi, RTL8366S_MIB_CTRL_REG, &data); - if (err) - return err; - - if (data & RTL8366S_MIB_CTRL_BUSY_MASK) - return -EBUSY; - - if (data & RTL8366S_MIB_CTRL_RESET_MASK) - return -EIO; - - mibvalue = 0; - for (i = rtl8366s_mib_counters[counter].length; i > 0; i--) { - err = rtl8366_smi_read_reg(smi, addr + (i - 1), &data); - if (err) - return err; - - mibvalue = (mibvalue << 16) | (data & 0xFFFF); - } - - *val = mibvalue; - return 0; -} - -static int rtl8366s_get_vlan_4k(struct rtl8366_smi *smi, u32 vid, - struct rtl8366_vlan_4k *vlan4k) -{ - struct rtl8366s_vlan_4k vlan4k_priv; - int err; - u32 data; - u16 *tableaddr; - - memset(vlan4k, '\0', sizeof(struct rtl8366_vlan_4k)); - vlan4k_priv.vid = vid; - - if (vid >= RTL8366_NUM_VIDS) - return -EINVAL; - - tableaddr = (u16 *)&vlan4k_priv; - - /* write VID */ - data = *tableaddr; - err = rtl8366_smi_write_reg(smi, RTL8366S_VLAN_TABLE_WRITE_BASE, data); - if (err) - return err; - - /* write table access control word */ - err = rtl8366_smi_write_reg(smi, RTL8366S_TABLE_ACCESS_CTRL_REG, - RTL8366S_TABLE_VLAN_READ_CTRL); - if (err) - return err; - - err = rtl8366_smi_read_reg(smi, RTL8366S_VLAN_TABLE_READ_BASE, &data); - if (err) - return err; - - *tableaddr = data; - tableaddr++; - - err = rtl8366_smi_read_reg(smi, RTL8366S_VLAN_TABLE_READ_BASE + 1, - &data); - if (err) - return err; - - *tableaddr = data; - - vlan4k->vid = vid; - vlan4k->untag = vlan4k_priv.untag; - vlan4k->member = vlan4k_priv.member; - vlan4k->fid = vlan4k_priv.fid; - - return 0; -} - -static int rtl8366s_set_vlan_4k(struct rtl8366_smi *smi, - const struct rtl8366_vlan_4k *vlan4k) -{ - struct rtl8366s_vlan_4k vlan4k_priv; - int err; - u32 data; - u16 *tableaddr; - - if (vlan4k->vid >= RTL8366_NUM_VIDS || - vlan4k->member > RTL8366_PORT_ALL || - vlan4k->untag > RTL8366_PORT_ALL || - vlan4k->fid > RTL8366S_FIDMAX) - return -EINVAL; - - vlan4k_priv.vid = vlan4k->vid; - vlan4k_priv.untag = vlan4k->untag; - vlan4k_priv.member = vlan4k->member; - vlan4k_priv.fid = vlan4k->fid; - - tableaddr = (u16 *)&vlan4k_priv; - - data = *tableaddr; - - err = rtl8366_smi_write_reg(smi, RTL8366S_VLAN_TABLE_WRITE_BASE, data); - if (err) - return err; - - tableaddr++; - - data = *tableaddr; - - err = rtl8366_smi_write_reg(smi, RTL8366S_VLAN_TABLE_WRITE_BASE + 1, - data); - if (err) - return err; - - /* write table access control word */ - err = rtl8366_smi_write_reg(smi, RTL8366S_TABLE_ACCESS_CTRL_REG, - RTL8366S_TABLE_VLAN_WRITE_CTRL); - - return err; -} - -static int rtl8366s_get_vlan_mc(struct rtl8366_smi *smi, u32 index, - struct rtl8366_vlan_mc *vlanmc) -{ - struct rtl8366s_vlan_mc vlanmc_priv; - int err; - u32 addr; - u32 data; - u16 *tableaddr; - - memset(vlanmc, '\0', sizeof(struct rtl8366_vlan_mc)); - - if (index >= RTL8366_NUM_VLANS) - return -EINVAL; - - tableaddr = (u16 *)&vlanmc_priv; - - addr = RTL8366S_VLAN_MEMCONF_BASE + (index << 1); - err = rtl8366_smi_read_reg(smi, addr, &data); - if (err) - return err; - - *tableaddr = data; - tableaddr++; - - addr = RTL8366S_VLAN_MEMCONF_BASE + 1 + (index << 1); - err = rtl8366_smi_read_reg(smi, addr, &data); - if (err) - return err; - - *tableaddr = data; - - vlanmc->vid = vlanmc_priv.vid; - vlanmc->priority = vlanmc_priv.priority; - vlanmc->untag = vlanmc_priv.untag; - vlanmc->member = vlanmc_priv.member; - vlanmc->fid = vlanmc_priv.fid; - - return 0; -} - -static int rtl8366s_set_vlan_mc(struct rtl8366_smi *smi, u32 index, - const struct rtl8366_vlan_mc *vlanmc) -{ - struct rtl8366s_vlan_mc vlanmc_priv; - int err; - u32 addr; - u32 data; - u16 *tableaddr; - - if (index >= RTL8366_NUM_VLANS || - vlanmc->vid >= RTL8366_NUM_VIDS || - vlanmc->priority > RTL8366S_PRIORITYMAX || - vlanmc->member > RTL8366_PORT_ALL || - vlanmc->untag > RTL8366_PORT_ALL || - vlanmc->fid > RTL8366S_FIDMAX) - return -EINVAL; - - vlanmc_priv.vid = vlanmc->vid; - vlanmc_priv.priority = vlanmc->priority; - vlanmc_priv.untag = vlanmc->untag; - vlanmc_priv.member = vlanmc->member; - vlanmc_priv.fid = vlanmc->fid; - - addr = RTL8366S_VLAN_MEMCONF_BASE + (index << 1); - - tableaddr = (u16 *)&vlanmc_priv; - data = *tableaddr; - - err = rtl8366_smi_write_reg(smi, addr, data); - if (err) - return err; - - addr = RTL8366S_VLAN_MEMCONF_BASE + 1 + (index << 1); - - tableaddr++; - data = *tableaddr; - - err = rtl8366_smi_write_reg(smi, addr, data); - if (err) - return err; - - return 0; -} - -static int rtl8366s_get_mc_index(struct rtl8366_smi *smi, int port, int *val) -{ - u32 data; - int err; - - if (port >= RTL8366_NUM_PORTS) - return -EINVAL; - - err = rtl8366_smi_read_reg(smi, RTL8366S_PORT_VLAN_CTRL_REG(port), - &data); - if (err) - return err; - - *val = (data >> RTL8366S_PORT_VLAN_CTRL_SHIFT(port)) & - RTL8366S_PORT_VLAN_CTRL_MASK; - - return 0; -} - -static int rtl8366s_set_mc_index(struct rtl8366_smi *smi, int port, int index) -{ - if (port >= RTL8366_NUM_PORTS || index >= RTL8366_NUM_VLANS) - return -EINVAL; - - return rtl8366_smi_rmwr(smi, RTL8366S_PORT_VLAN_CTRL_REG(port), - RTL8366S_PORT_VLAN_CTRL_MASK << - RTL8366S_PORT_VLAN_CTRL_SHIFT(port), - (index & RTL8366S_PORT_VLAN_CTRL_MASK) << - RTL8366S_PORT_VLAN_CTRL_SHIFT(port)); -} - -static int rtl8366s_set_vlan(struct rtl8366_smi *smi, int vid, u32 member, - u32 untag, u32 fid) -{ - struct rtl8366_vlan_4k vlan4k; - int err; - int i; - - /* Update the 4K table */ - err = rtl8366s_get_vlan_4k(smi, vid, &vlan4k); - if (err) - return err; - - vlan4k.member = member; - vlan4k.untag = untag; - vlan4k.fid = fid; - err = rtl8366s_set_vlan_4k(smi, &vlan4k); - if (err) - return err; - - /* Try to find an existing MC entry for this VID */ - for (i = 0; i < RTL8366_NUM_VLANS; i++) { - struct rtl8366_vlan_mc vlanmc; - - err = rtl8366s_get_vlan_mc(smi, i, &vlanmc); - if (err) - return err; - - if (vid == vlanmc.vid) { - /* update the MC entry */ - vlanmc.member = member; - vlanmc.untag = untag; - vlanmc.fid = fid; - - err = rtl8366s_set_vlan_mc(smi, i, &vlanmc); - break; - } - } - - return err; -} - -static int rtl8366s_get_pvid(struct rtl8366_smi *smi, int port, int *val) -{ - struct rtl8366_vlan_mc vlanmc; - int err; - int index; - - err = rtl8366s_get_mc_index(smi, port, &index); - if (err) - return err; - - err = rtl8366s_get_vlan_mc(smi, index, &vlanmc); - if (err) - return err; - - *val = vlanmc.vid; - return 0; -} - -static int rtl8366s_mc_is_used(struct rtl8366_smi *smi, int mc_index, - int *used) -{ - int err; - int i; - - *used = 0; - for (i = 0; i < RTL8366_NUM_PORTS; i++) { - int index = 0; - - err = rtl8366s_get_mc_index(smi, i, &index); - if (err) - return err; - - if (mc_index == index) { - *used = 1; - break; - } - } - - return 0; -} - -static int rtl8366s_set_pvid(struct rtl8366_smi *smi, unsigned port, - unsigned vid) -{ - struct rtl8366_vlan_mc vlanmc; - struct rtl8366_vlan_4k vlan4k; - int err; - int i; - - /* Try to find an existing MC entry for this VID */ - for (i = 0; i < RTL8366_NUM_VLANS; i++) { - err = rtl8366s_get_vlan_mc(smi, i, &vlanmc); - if (err) - return err; - - if (vid == vlanmc.vid) { - err = rtl8366s_set_vlan_mc(smi, i, &vlanmc); - if (err) - return err; - - err = rtl8366s_set_mc_index(smi, port, i); - return err; - } - } - - /* We have no MC entry for this VID, try to find an empty one */ - for (i = 0; i < RTL8366_NUM_VLANS; i++) { - err = rtl8366s_get_vlan_mc(smi, i, &vlanmc); - if (err) - return err; - - if (vlanmc.vid == 0 && vlanmc.member == 0) { - /* Update the entry from the 4K table */ - err = rtl8366s_get_vlan_4k(smi, vid, &vlan4k); - if (err) - return err; - - vlanmc.vid = vid; - vlanmc.member = vlan4k.member; - vlanmc.untag = vlan4k.untag; - vlanmc.fid = vlan4k.fid; - err = rtl8366s_set_vlan_mc(smi, i, &vlanmc); - if (err) - return err; - - err = rtl8366s_set_mc_index(smi, port, i); - return err; - } - } - - /* MC table is full, try to find an unused entry and replace it */ - for (i = 0; i < RTL8366_NUM_VLANS; i++) { - int used; - - err = rtl8366s_mc_is_used(smi, i, &used); - if (err) - return err; - - if (!used) { - /* Update the entry from the 4K table */ - err = rtl8366s_get_vlan_4k(smi, vid, &vlan4k); - if (err) - return err; - - vlanmc.vid = vid; - vlanmc.member = vlan4k.member; - vlanmc.untag = vlan4k.untag; - vlanmc.fid = vlan4k.fid; - err = rtl8366s_set_vlan_mc(smi, i, &vlanmc); - if (err) - return err; - - err = rtl8366s_set_mc_index(smi, port, i); - return err; - } - } - - dev_err(smi->parent, - "all VLAN member configurations are in use\n"); - - return -ENOSPC; -} - -static int rtl8366s_vlan_set_vlan(struct rtl8366_smi *smi, int enable) -{ - return rtl8366_smi_rmwr(smi, RTL8366_CHIP_GLOBAL_CTRL_REG, - RTL8366_CHIP_CTRL_VLAN, - (enable) ? RTL8366_CHIP_CTRL_VLAN : 0); -} - -static int rtl8366s_vlan_set_4ktable(struct rtl8366_smi *smi, int enable) -{ - return rtl8366_smi_rmwr(smi, RTL8366S_VLAN_TB_CTRL_REG, - 1, (enable) ? 1 : 0); -} - -static int rtl8366s_reset_vlan(struct rtl8366_smi *smi) -{ - struct rtl8366_vlan_mc vlanmc; - int err; - int i; - - /* clear VLAN member configurations */ - vlanmc.vid = 0; - vlanmc.priority = 0; - vlanmc.member = 0; - vlanmc.untag = 0; - vlanmc.fid = 0; - for (i = 0; i < RTL8366_NUM_VLANS; i++) { - err = rtl8366s_set_vlan_mc(smi, i, &vlanmc); - if (err) - return err; - } - - for (i = 0; i < RTL8366_NUM_PORTS; i++) { - if (i == RTL8366_PORT_CPU) - continue; - - err = rtl8366s_set_vlan(smi, (i + 1), - (1 << i) | RTL8366_PORT_CPU, - (1 << i) | RTL8366_PORT_CPU, - 0); - if (err) - return err; - - err = rtl8366s_set_pvid(smi, i, (i + 1)); - if (err) - return err; - } - - return 0; -} - -#ifdef CONFIG_RTL8366S_PHY_DEBUG_FS -static int rtl8366s_debugfs_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t rtl8366s_read_debugfs_mibs(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct rtl8366s *rtl = (struct rtl8366s *)file->private_data; - struct rtl8366_smi *smi = &rtl->smi; - int i, j, len = 0; - char *buf = rtl->buf; - - len += snprintf(buf + len, sizeof(rtl->buf) - len, - "%-36s %12s %12s %12s %12s %12s %12s\n", - "Counter", - "Port 0", "Port 1", "Port 2", - "Port 3", "Port 4", "Port 5"); - - for (i = 0; i < ARRAY_SIZE(rtl8366s_mib_counters); ++i) { - len += snprintf(buf + len, sizeof(rtl->buf) - len, "%-36s ", - rtl8366s_mib_counters[i].name); - for (j = 0; j < RTL8366_NUM_PORTS; ++j) { - unsigned long long counter = 0; - - if (!rtl8366_get_mib_counter(smi, i, j, &counter)) - len += snprintf(buf + len, - sizeof(rtl->buf) - len, - "%12llu ", counter); - else - len += snprintf(buf + len, - sizeof(rtl->buf) - len, - "%12s ", "error"); - } - len += snprintf(buf + len, sizeof(rtl->buf) - len, "\n"); - } - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t rtl8366s_read_debugfs_vlan_mc(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct rtl8366s *rtl = (struct rtl8366s *)file->private_data; - struct rtl8366_smi *smi = &rtl->smi; - int i, len = 0; - char *buf = rtl->buf; - - len += snprintf(buf + len, sizeof(rtl->buf) - len, - "%2s %6s %4s %6s %6s %3s\n", - "id", "vid","prio", "member", "untag", "fid"); - - for (i = 0; i < RTL8366_NUM_VLANS; ++i) { - struct rtl8366_vlan_mc vlanmc; - - rtl8366s_get_vlan_mc(smi, i, &vlanmc); - - len += snprintf(buf + len, sizeof(rtl->buf) - len, - "%2d %6d %4d 0x%04x 0x%04x %3d\n", - i, vlanmc.vid, vlanmc.priority, - vlanmc.member, vlanmc.untag, vlanmc.fid); - } - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t rtl8366s_read_debugfs_reg(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct rtl8366s *rtl = (struct rtl8366s *)file->private_data; - struct rtl8366_smi *smi = &rtl->smi; - u32 t, reg = g_dbg_reg; - int err, len = 0; - char *buf = rtl->buf; - - memset(buf, '\0', sizeof(rtl->buf)); - - err = rtl8366_smi_read_reg(smi, reg, &t); - if (err) { - len += snprintf(buf, sizeof(rtl->buf), - "Read failed (reg: 0x%04x)\n", reg); - return simple_read_from_buffer(user_buf, count, ppos, buf, len); - } - - len += snprintf(buf, sizeof(rtl->buf), "reg = 0x%04x, val = 0x%04x\n", - reg, t); - - return simple_read_from_buffer(user_buf, count, ppos, buf, len); -} - -static ssize_t rtl8366s_write_debugfs_reg(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct rtl8366s *rtl = (struct rtl8366s *)file->private_data; - struct rtl8366_smi *smi = &rtl->smi; - unsigned long data; - u32 reg = g_dbg_reg; - int err; - size_t len; - char *buf = rtl->buf; - - len = min(count, sizeof(rtl->buf) - 1); - if (copy_from_user(buf, user_buf, len)) { - dev_err(rtl->parent, "copy from user failed\n"); - return -EFAULT; - } - - buf[len] = '\0'; - if (len > 0 && buf[len - 1] == '\n') - buf[len - 1] = '\0'; - - - if (strict_strtoul(buf, 16, &data)) { - dev_err(rtl->parent, "Invalid reg value %s\n", buf); - } else { - err = rtl8366_smi_write_reg(smi, reg, data); - if (err) { - dev_err(rtl->parent, - "writing reg 0x%04x val 0x%04lx failed\n", - reg, data); - } - } - - return count; -} - -static const struct file_operations fops_rtl8366s_regs = { - .read = rtl8366s_read_debugfs_reg, - .write = rtl8366s_write_debugfs_reg, - .open = rtl8366s_debugfs_open, - .owner = THIS_MODULE -}; - -static const struct file_operations fops_rtl8366s_vlan_mc = { - .read = rtl8366s_read_debugfs_vlan_mc, - .open = rtl8366s_debugfs_open, - .owner = THIS_MODULE -}; - -static const struct file_operations fops_rtl8366s_mibs = { - .read = rtl8366s_read_debugfs_mibs, - .open = rtl8366s_debugfs_open, - .owner = THIS_MODULE -}; - -static void rtl8366s_debugfs_init(struct rtl8366s *rtl) -{ - struct dentry *node; - struct dentry *root; - - if (!rtl->debugfs_root) - rtl->debugfs_root = debugfs_create_dir("rtl8366s", NULL); - - if (!rtl->debugfs_root) { - dev_err(rtl->parent, "Unable to create debugfs dir\n"); - return; - } - root = rtl->debugfs_root; - - node = debugfs_create_x16("reg", S_IRUGO | S_IWUSR, root, &g_dbg_reg); - if (!node) { - dev_err(rtl->parent, "Creating debugfs file '%s' failed\n", - "reg"); - return; - } - - node = debugfs_create_file("val", S_IRUGO | S_IWUSR, root, rtl, - &fops_rtl8366s_regs); - if (!node) { - dev_err(rtl->parent, "Creating debugfs file '%s' failed\n", - "val"); - return; - } - - node = debugfs_create_file("vlan_mc", S_IRUSR, root, rtl, - &fops_rtl8366s_vlan_mc); - if (!node) { - dev_err(rtl->parent, "Creating debugfs file '%s' failed\n", - "vlan_mc"); - return; - } - - node = debugfs_create_file("mibs", S_IRUSR, root, rtl, - &fops_rtl8366s_mibs); - if (!node) { - dev_err(rtl->parent, "Creating debugfs file '%s' failed\n", - "mibs"); - return; - } -} - -static void rtl8366s_debugfs_remove(struct rtl8366s *rtl) -{ - if (rtl->debugfs_root) { - debugfs_remove_recursive(rtl->debugfs_root); - rtl->debugfs_root = NULL; - } -} - -#else -static inline void rtl8366s_debugfs_init(struct rtl8366s *rtl) {} -static inline void rtl8366s_debugfs_remove(struct rtl8366s *rtl) {} -#endif /* CONFIG_RTL8366S_PHY_DEBUG_FS */ - -static int rtl8366s_sw_reset_mibs(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - int err = 0; - - if (val->value.i == 1) - err = rtl8366_smi_rmwr(smi, RTL8366S_MIB_CTRL_REG, 0, (1 << 2)); - - return err; -} - -static int rtl8366s_sw_get_vlan_enable(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - u32 data; - - if (attr->ofs == 1) { - rtl8366_smi_read_reg(smi, RTL8366_CHIP_GLOBAL_CTRL_REG, &data); - - if (data & RTL8366_CHIP_CTRL_VLAN) - val->value.i = 1; - else - val->value.i = 0; - } else if (attr->ofs == 2) { - rtl8366_smi_read_reg(smi, RTL8366S_VLAN_TB_CTRL_REG, &data); - - if (data & 0x0001) - val->value.i = 1; - else - val->value.i = 0; - } - - return 0; -} - -static int rtl8366s_sw_get_blinkrate(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - u32 data; - - rtl8366_smi_read_reg(smi, RTL8366_LED_BLINKRATE_REG, &data); - - val->value.i = (data & (RTL8366_LED_BLINKRATE_MASK)); - - return 0; -} - -static int rtl8366s_sw_set_blinkrate(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - - if (val->value.i >= 6) - return -EINVAL; - - return rtl8366_smi_rmwr(smi, RTL8366_LED_BLINKRATE_REG, - RTL8366_LED_BLINKRATE_MASK, - val->value.i); -} - -static int rtl8366s_sw_set_vlan_enable(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - - if (attr->ofs == 1) - return rtl8366s_vlan_set_vlan(smi, val->value.i); - else - return rtl8366s_vlan_set_4ktable(smi, val->value.i); -} - -static const char *rtl8366s_speed_str(unsigned speed) -{ - switch (speed) { - case 0: - return "10baseT"; - case 1: - return "100baseT"; - case 2: - return "1000baseT"; - } - - return "unknown"; -} - -static int rtl8366s_sw_get_port_link(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - struct rtl8366s *rtl = sw_to_rtl8366s(dev); - struct rtl8366_smi *smi = &rtl->smi; - u32 len = 0, data = 0; - - if (val->port_vlan >= RTL8366_NUM_PORTS) - return -EINVAL; - - memset(rtl->buf, '\0', sizeof(rtl->buf)); - rtl8366_smi_read_reg(smi, RTL8366S_PORT_LINK_STATUS_BASE + - (val->port_vlan / 2), &data); - - if (val->port_vlan % 2) - data = data >> 8; - - if (data & RTL8366S_PORT_STATUS_LINK_MASK) { - len = snprintf(rtl->buf, sizeof(rtl->buf), - "port:%d link:up speed:%s %s-duplex %s%s%s", - val->port_vlan, - rtl8366s_speed_str(data & - RTL8366S_PORT_STATUS_SPEED_MASK), - (data & RTL8366S_PORT_STATUS_DUPLEX_MASK) ? - "full" : "half", - (data & RTL8366S_PORT_STATUS_TXPAUSE_MASK) ? - "tx-pause ": "", - (data & RTL8366S_PORT_STATUS_RXPAUSE_MASK) ? - "rx-pause " : "", - (data & RTL8366S_PORT_STATUS_AN_MASK) ? - "nway ": ""); - } else { - len = snprintf(rtl->buf, sizeof(rtl->buf), "port:%d link: down", - val->port_vlan); - } - - val->value.s = rtl->buf; - val->len = len; - - return 0; -} - -static int rtl8366s_sw_get_vlan_info(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - int i; - u32 len = 0; - struct rtl8366_vlan_4k vlan4k; - struct rtl8366s *rtl = sw_to_rtl8366s(dev); - struct rtl8366_smi *smi = &rtl->smi; - char *buf = rtl->buf; - int err; - - if (val->port_vlan == 0 || val->port_vlan >= RTL8366_NUM_VLANS) - return -EINVAL; - - memset(buf, '\0', sizeof(rtl->buf)); - - err = rtl8366s_get_vlan_4k(smi, val->port_vlan, &vlan4k); - if (err) - return err; - - len += snprintf(buf + len, sizeof(rtl->buf) - len, - "VLAN %d: Ports: '", vlan4k.vid); - - for (i = 0; i < RTL8366_NUM_PORTS; i++) { - if (!(vlan4k.member & (1 << i))) - continue; - - len += snprintf(buf + len, sizeof(rtl->buf) - len, "%d%s", i, - (vlan4k.untag & (1 << i)) ? "" : "t"); - } - - len += snprintf(buf + len, sizeof(rtl->buf) - len, - "', members=%04x, untag=%04x, fid=%u", - vlan4k.member, vlan4k.untag, vlan4k.fid); - - val->value.s = buf; - val->len = len; - - return 0; -} - -static int rtl8366s_sw_set_port_led(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - u32 data; - u32 mask; - u32 reg; - - if (val->port_vlan >= RTL8366_NUM_PORTS || - (1 << val->port_vlan) == RTL8366_PORT_UNKNOWN) - return -EINVAL; - - if (val->port_vlan == RTL8366_PORT_NUM_CPU) { - reg = RTL8366_LED_BLINKRATE_REG; - mask = 0xF << 4; - data = val->value.i << 4; - } else { - reg = RTL8366_LED_CTRL_REG; - mask = 0xF << (val->port_vlan * 4), - data = val->value.i << (val->port_vlan * 4); - } - - return rtl8366_smi_rmwr(smi, RTL8366_LED_BLINKRATE_REG, mask, data); -} - -static int rtl8366s_sw_get_port_led(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - u32 data = 0; - - if (val->port_vlan >= RTL8366_NUM_LEDGROUPS) - return -EINVAL; - - rtl8366_smi_read_reg(smi, RTL8366_LED_CTRL_REG, &data); - val->value.i = (data >> (val->port_vlan * 4)) & 0x000F; - - return 0; -} - -static int rtl8366s_sw_reset_port_mibs(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - - if (val->port_vlan >= RTL8366_NUM_PORTS) - return -EINVAL; - - - return rtl8366_smi_rmwr(smi, RTL8366S_MIB_CTRL_REG, - 0, (1 << (val->port_vlan + 3))); -} - -static int rtl8366s_sw_get_port_mib(struct switch_dev *dev, - const struct switch_attr *attr, - struct switch_val *val) -{ - struct rtl8366s *rtl = sw_to_rtl8366s(dev); - struct rtl8366_smi *smi = &rtl->smi; - int i, len = 0; - unsigned long long counter = 0; - char *buf = rtl->buf; - - if (val->port_vlan >= RTL8366_NUM_PORTS) - return -EINVAL; - - len += snprintf(buf + len, sizeof(rtl->buf) - len, - "Port %d MIB counters\n", - val->port_vlan); - - for (i = 0; i < ARRAY_SIZE(rtl8366s_mib_counters); ++i) { - len += snprintf(buf + len, sizeof(rtl->buf) - len, - "%-36s: ", rtl8366s_mib_counters[i].name); - if (!rtl8366_get_mib_counter(smi, i, val->port_vlan, &counter)) - len += snprintf(buf + len, sizeof(rtl->buf) - len, - "%llu\n", counter); - else - len += snprintf(buf + len, sizeof(rtl->buf) - len, - "%s\n", "error"); - } - - val->value.s = buf; - val->len = len; - return 0; -} - -static int rtl8366s_sw_get_vlan_ports(struct switch_dev *dev, - struct switch_val *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - struct switch_port *port; - struct rtl8366_vlan_4k vlan4k; - int i; - - if (val->port_vlan == 0 || val->port_vlan >= RTL8366_NUM_VLANS) - return -EINVAL; - - rtl8366s_get_vlan_4k(smi, val->port_vlan, &vlan4k); - - port = &val->value.ports[0]; - val->len = 0; - for (i = 0; i < RTL8366_NUM_PORTS; i++) { - if (!(vlan4k.member & BIT(i))) - continue; - - port->id = i; - port->flags = (vlan4k.untag & BIT(i)) ? - 0 : BIT(SWITCH_PORT_FLAG_TAGGED); - val->len++; - port++; - } - return 0; -} - -static int rtl8366s_sw_set_vlan_ports(struct switch_dev *dev, - struct switch_val *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - struct switch_port *port; - u32 member = 0; - u32 untag = 0; - int i; - - if (val->port_vlan == 0 || val->port_vlan >= RTL8366_NUM_VLANS) - return -EINVAL; - - port = &val->value.ports[0]; - for (i = 0; i < val->len; i++, port++) { - member |= BIT(port->id); - - if (!(port->flags & BIT(SWITCH_PORT_FLAG_TAGGED))) - untag |= BIT(port->id); - } - - return rtl8366s_set_vlan(smi, val->port_vlan, member, untag, 0); -} - -static int rtl8366s_sw_get_port_pvid(struct switch_dev *dev, int port, int *val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - return rtl8366s_get_pvid(smi, port, val); -} - -static int rtl8366s_sw_set_port_pvid(struct switch_dev *dev, int port, int val) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - return rtl8366s_set_pvid(smi, port, val); -} - -static int rtl8366s_sw_reset_switch(struct switch_dev *dev) -{ - struct rtl8366_smi *smi = sw_to_rtl8366_smi(dev); - int err; - - err = rtl8366s_reset_chip(smi); - if (err) - return err; - - err = rtl8366s_hw_init(smi); - if (err) - return err; - - return rtl8366s_reset_vlan(smi); -} - -static struct switch_attr rtl8366s_globals[] = { - { - .type = SWITCH_TYPE_INT, - .name = "enable_vlan", - .description = "Enable VLAN mode", - .set = rtl8366s_sw_set_vlan_enable, - .get = rtl8366s_sw_get_vlan_enable, - .max = 1, - .ofs = 1 - }, { - .type = SWITCH_TYPE_INT, - .name = "enable_vlan4k", - .description = "Enable VLAN 4K mode", - .set = rtl8366s_sw_set_vlan_enable, - .get = rtl8366s_sw_get_vlan_enable, - .max = 1, - .ofs = 2 - }, { - .type = SWITCH_TYPE_INT, - .name = "reset_mibs", - .description = "Reset all MIB counters", - .set = rtl8366s_sw_reset_mibs, - .get = NULL, - .max = 1 - }, { - .type = SWITCH_TYPE_INT, - .name = "blinkrate", - .description = "Get/Set LED blinking rate (0 = 43ms, 1 = 84ms," - " 2 = 120ms, 3 = 170ms, 4 = 340ms, 5 = 670ms)", - .set = rtl8366s_sw_set_blinkrate, - .get = rtl8366s_sw_get_blinkrate, - .max = 5 - }, -}; - -static struct switch_attr rtl8366s_port[] = { - { - .type = SWITCH_TYPE_STRING, - .name = "link", - .description = "Get port link information", - .max = 1, - .set = NULL, - .get = rtl8366s_sw_get_port_link, - }, { - .type = SWITCH_TYPE_INT, - .name = "reset_mib", - .description = "Reset single port MIB counters", - .max = 1, - .set = rtl8366s_sw_reset_port_mibs, - .get = NULL, - }, { - .type = SWITCH_TYPE_STRING, - .name = "mib", - .description = "Get MIB counters for port", - .max = 33, - .set = NULL, - .get = rtl8366s_sw_get_port_mib, - }, { - .type = SWITCH_TYPE_INT, - .name = "led", - .description = "Get/Set port group (0 - 3) led mode (0 - 15)", - .max = 15, - .set = rtl8366s_sw_set_port_led, - .get = rtl8366s_sw_get_port_led, - }, -}; - -static struct switch_attr rtl8366s_vlan[] = { - { - .type = SWITCH_TYPE_STRING, - .name = "info", - .description = "Get vlan information", - .max = 1, - .set = NULL, - .get = rtl8366s_sw_get_vlan_info, - }, -}; - -/* template */ -static struct switch_dev rtl8366_switch_dev = { - .name = "RTL8366S", - .cpu_port = RTL8366_PORT_NUM_CPU, - .ports = RTL8366_NUM_PORTS, - .vlans = RTL8366_NUM_VLANS, - .attr_global = { - .attr = rtl8366s_globals, - .n_attr = ARRAY_SIZE(rtl8366s_globals), - }, - .attr_port = { - .attr = rtl8366s_port, - .n_attr = ARRAY_SIZE(rtl8366s_port), - }, - .attr_vlan = { - .attr = rtl8366s_vlan, - .n_attr = ARRAY_SIZE(rtl8366s_vlan), - }, - - .get_vlan_ports = rtl8366s_sw_get_vlan_ports, - .set_vlan_ports = rtl8366s_sw_set_vlan_ports, - .get_port_pvid = rtl8366s_sw_get_port_pvid, - .set_port_pvid = rtl8366s_sw_set_port_pvid, - .reset_switch = rtl8366s_sw_reset_switch, -}; - -static int rtl8366s_switch_init(struct rtl8366s *rtl) -{ - struct switch_dev *dev = &rtl->dev; - int err; - - memcpy(dev, &rtl8366_switch_dev, sizeof(struct switch_dev)); - dev->priv = rtl; - dev->devname = dev_name(rtl->parent); - - err = register_switch(dev, NULL); - if (err) - dev_err(rtl->parent, "switch registration failed\n"); - - return err; -} - -static void rtl8366s_switch_cleanup(struct rtl8366s *rtl) -{ - unregister_switch(&rtl->dev); -} - -static int rtl8366s_mii_read(struct mii_bus *bus, int addr, int reg) -{ - struct rtl8366_smi *smi = bus->priv; - u32 val = 0; - int err; - - err = rtl8366s_read_phy_reg(smi, addr, 0, reg, &val); - if (err) - return 0xffff; - - return val; -} - -static int rtl8366s_mii_write(struct mii_bus *bus, int addr, int reg, u16 val) -{ - struct rtl8366_smi *smi = bus->priv; - u32 t; - int err; - - err = rtl8366s_write_phy_reg(smi, addr, 0, reg, val); - /* flush write */ - (void) rtl8366s_read_phy_reg(smi, addr, 0, reg, &t); - - return err; -} - -static int rtl8366s_mii_bus_match(struct mii_bus *bus) -{ - return (bus->read == rtl8366s_mii_read && - bus->write == rtl8366s_mii_write); -} - -static int rtl8366s_setup(struct rtl8366s *rtl) -{ - struct rtl8366_smi *smi = &rtl->smi; - int ret; - - rtl8366s_debugfs_init(rtl); - - ret = rtl8366s_reset_chip(smi); - if (ret) - return ret; - - ret = rtl8366s_hw_init(smi); - return ret; -} - -static int rtl8366s_detect(struct rtl8366_smi *smi) -{ - u32 chip_id = 0; - u32 chip_ver = 0; - int ret; - - ret = rtl8366_smi_read_reg(smi, RTL8366S_CHIP_ID_REG, &chip_id); - if (ret) { - dev_err(smi->parent, "unable to read chip id\n"); - return ret; - } - - switch (chip_id) { - case RTL8366S_CHIP_ID_8366: - break; - default: - dev_err(smi->parent, "unknown chip id (%04x)\n", chip_id); - return -ENODEV; - } - - ret = rtl8366_smi_read_reg(smi, RTL8366S_CHIP_VERSION_CTRL_REG, - &chip_ver); - if (ret) { - dev_err(smi->parent, "unable to read chip version\n"); - return ret; - } - - dev_info(smi->parent, "RTL%04x ver. %u chip found\n", - chip_id, chip_ver & RTL8366S_CHIP_VERSION_MASK); - - return 0; -} - -static struct rtl8366_smi_ops rtl8366s_smi_ops = { - .detect = rtl8366s_detect, - .mii_read = rtl8366s_mii_read, - .mii_write = rtl8366s_mii_write, -}; - -static int __init rtl8366s_probe(struct platform_device *pdev) -{ - static int rtl8366_smi_version_printed; - struct rtl8366s_platform_data *pdata; - struct rtl8366s *rtl; - struct rtl8366_smi *smi; - int err; - - if (!rtl8366_smi_version_printed++) - printk(KERN_NOTICE RTL8366S_DRIVER_DESC - " version " RTL8366S_DRIVER_VER"\n"); - - pdata = pdev->dev.platform_data; - if (!pdata) { - dev_err(&pdev->dev, "no platform data specified\n"); - err = -EINVAL; - goto err_out; - } - - rtl = kzalloc(sizeof(*rtl), GFP_KERNEL); - if (!rtl) { - dev_err(&pdev->dev, "no memory for private data\n"); - err = -ENOMEM; - goto err_out; - } - - rtl->parent = &pdev->dev; - - smi = &rtl->smi; - smi->parent = &pdev->dev; - smi->gpio_sda = pdata->gpio_sda; - smi->gpio_sck = pdata->gpio_sck; - smi->ops = &rtl8366s_smi_ops; - - err = rtl8366_smi_init(smi); - if (err) - goto err_free_rtl; - - platform_set_drvdata(pdev, rtl); - - err = rtl8366s_setup(rtl); - if (err) - goto err_clear_drvdata; - - err = rtl8366s_switch_init(rtl); - if (err) - goto err_clear_drvdata; - - return 0; - - err_clear_drvdata: - platform_set_drvdata(pdev, NULL); - rtl8366_smi_cleanup(smi); - err_free_rtl: - kfree(rtl); - err_out: - return err; -} - -static int rtl8366s_phy_config_init(struct phy_device *phydev) -{ - if (!rtl8366s_mii_bus_match(phydev->bus)) - return -EINVAL; - - return 0; -} - -static int rtl8366s_phy_config_aneg(struct phy_device *phydev) -{ - return 0; -} - -static struct phy_driver rtl8366s_phy_driver = { - .phy_id = 0x001cc960, - .name = "Realtek RTL8366S", - .phy_id_mask = 0x1ffffff0, - .features = PHY_GBIT_FEATURES, - .config_aneg = rtl8366s_phy_config_aneg, - .config_init = rtl8366s_phy_config_init, - .read_status = genphy_read_status, - .driver = { - .owner = THIS_MODULE, - }, -}; - -static int __devexit rtl8366s_remove(struct platform_device *pdev) -{ - struct rtl8366s *rtl = platform_get_drvdata(pdev); - - if (rtl) { - rtl8366s_switch_cleanup(rtl); - rtl8366s_debugfs_remove(rtl); - platform_set_drvdata(pdev, NULL); - rtl8366_smi_cleanup(&rtl->smi); - kfree(rtl); - } - - return 0; -} - -static struct platform_driver rtl8366s_driver = { - .driver = { - .name = RTL8366S_DRIVER_NAME, - .owner = THIS_MODULE, - }, - .probe = rtl8366s_probe, - .remove = __devexit_p(rtl8366s_remove), -}; - -static int __init rtl8366s_module_init(void) -{ - int ret; - ret = platform_driver_register(&rtl8366s_driver); - if (ret) - return ret; - - ret = phy_driver_register(&rtl8366s_phy_driver); - if (ret) - goto err_platform_unregister; - - return 0; - - err_platform_unregister: - platform_driver_unregister(&rtl8366s_driver); - return ret; -} -module_init(rtl8366s_module_init); - -static void __exit rtl8366s_module_exit(void) -{ - phy_driver_unregister(&rtl8366s_phy_driver); - platform_driver_unregister(&rtl8366s_driver); -} -module_exit(rtl8366s_module_exit); - -MODULE_DESCRIPTION(RTL8366S_DRIVER_DESC); -MODULE_VERSION(RTL8366S_DRIVER_VER); -MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); -MODULE_AUTHOR("Antti Seppälä <a.seppala@gmail.com>"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" RTL8366S_DRIVER_NAME); diff --git a/target/linux/generic-2.6/files/drivers/net/phy/swconfig.c b/target/linux/generic-2.6/files/drivers/net/phy/swconfig.c deleted file mode 100644 index dea8e78b7..000000000 --- a/target/linux/generic-2.6/files/drivers/net/phy/swconfig.c +++ /dev/null @@ -1,925 +0,0 @@ -/* - * swconfig.c: Switch configuration API - * - * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/types.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/list.h> -#include <linux/if.h> -#include <linux/if_ether.h> -#include <linux/capability.h> -#include <linux/skbuff.h> -#include <linux/switch.h> - -//#define DEBUG 1 -#ifdef DEBUG -#define DPRINTF(format, ...) printk("%s: " format, __func__, ##__VA_ARGS__) -#else -#define DPRINTF(...) do {} while(0) -#endif - -MODULE_AUTHOR("Felix Fietkau <nbd@openwrt.org>"); -MODULE_LICENSE("GPL"); - -static int swdev_id = 0; -static struct list_head swdevs; -static spinlock_t swdevs_lock = SPIN_LOCK_UNLOCKED; -struct swconfig_callback; - -struct swconfig_callback -{ - struct sk_buff *msg; - struct genlmsghdr *hdr; - struct genl_info *info; - int cmd; - - /* callback for filling in the message data */ - int (*fill)(struct swconfig_callback *cb, void *arg); - - /* callback for closing the message before sending it */ - int (*close)(struct swconfig_callback *cb, void *arg); - - struct nlattr *nest[4]; - int args[4]; -}; - -/* defaults */ - -static int -swconfig_get_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - int ret; - if (val->port_vlan >= dev->vlans) - return -EINVAL; - - if (!dev->get_vlan_ports) - return -EOPNOTSUPP; - - ret = dev->get_vlan_ports(dev, val); - return ret; -} - -static int -swconfig_set_vlan_ports(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - struct switch_port *ports = val->value.ports; - int i; - - if (val->port_vlan >= dev->vlans) - return -EINVAL; - - /* validate ports */ - if (val->len > dev->ports) - return -EINVAL; - - if (!dev->set_vlan_ports) - return -EOPNOTSUPP; - - for (i = 0; i < val->len; i++) { - if (ports[i].id >= dev->ports) - return -EINVAL; - - if (dev->set_port_pvid && !(ports[i].flags & (1 << SWITCH_PORT_FLAG_TAGGED))) - dev->set_port_pvid(dev, ports[i].id, val->port_vlan); - } - - return dev->set_vlan_ports(dev, val); -} - -static int -swconfig_set_pvid(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - if (val->port_vlan >= dev->ports) - return -EINVAL; - - if (!dev->set_port_pvid) - return -EOPNOTSUPP; - - return dev->set_port_pvid(dev, val->port_vlan, val->value.i); -} - -static int -swconfig_get_pvid(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - if (val->port_vlan >= dev->ports) - return -EINVAL; - - if (!dev->get_port_pvid) - return -EOPNOTSUPP; - - return dev->get_port_pvid(dev, val->port_vlan, &val->value.i); -} - -static int -swconfig_apply_config(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - /* don't complain if not supported by the switch driver */ - if (!dev->apply_config) - return 0; - - return dev->apply_config(dev); -} - -static int -swconfig_reset_switch(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val) -{ - /* don't complain if not supported by the switch driver */ - if (!dev->reset_switch) - return 0; - - return dev->reset_switch(dev); -} - -enum global_defaults { - GLOBAL_APPLY, - GLOBAL_RESET, -}; - -enum vlan_defaults { - VLAN_PORTS, -}; - -enum port_defaults { - PORT_PVID, -}; - -static struct switch_attr default_global[] = { - [GLOBAL_APPLY] = { - .type = SWITCH_TYPE_NOVAL, - .name = "apply", - .description = "Activate changes in the hardware", - .set = swconfig_apply_config, - }, - [GLOBAL_RESET] = { - .type = SWITCH_TYPE_NOVAL, - .name = "reset", - .description = "Reset the switch", - .set = swconfig_reset_switch, - } -}; - -static struct switch_attr default_port[] = { - [PORT_PVID] = { - .type = SWITCH_TYPE_INT, - .name = "pvid", - .description = "Primary VLAN ID", - .set = swconfig_set_pvid, - .get = swconfig_get_pvid, - } -}; - -static struct switch_attr default_vlan[] = { - [VLAN_PORTS] = { - .type = SWITCH_TYPE_PORTS, - .name = "ports", - .description = "VLAN port mapping", - .set = swconfig_set_vlan_ports, - .get = swconfig_get_vlan_ports, - }, -}; - - -static void swconfig_defaults_init(struct switch_dev *dev) -{ - dev->def_global = 0; - dev->def_vlan = 0; - dev->def_port = 0; - - if (dev->get_vlan_ports || dev->set_vlan_ports) - set_bit(VLAN_PORTS, &dev->def_vlan); - - if (dev->get_port_pvid || dev->set_port_pvid) - set_bit(PORT_PVID, &dev->def_port); - - /* always present, can be no-op */ - set_bit(GLOBAL_APPLY, &dev->def_global); - set_bit(GLOBAL_RESET, &dev->def_global); -} - - -static struct genl_family switch_fam = { - .id = GENL_ID_GENERATE, - .name = "switch", - .hdrsize = 0, - .version = 1, - .maxattr = SWITCH_ATTR_MAX, -}; - -static const struct nla_policy switch_policy[SWITCH_ATTR_MAX+1] = { - [SWITCH_ATTR_ID] = { .type = NLA_U32 }, - [SWITCH_ATTR_OP_ID] = { .type = NLA_U32 }, - [SWITCH_ATTR_OP_PORT] = { .type = NLA_U32 }, - [SWITCH_ATTR_OP_VLAN] = { .type = NLA_U32 }, - [SWITCH_ATTR_OP_VALUE_INT] = { .type = NLA_U32 }, - [SWITCH_ATTR_OP_VALUE_STR] = { .type = NLA_NUL_STRING }, - [SWITCH_ATTR_OP_VALUE_PORTS] = { .type = NLA_NESTED }, - [SWITCH_ATTR_TYPE] = { .type = NLA_U32 }, -}; - -static const struct nla_policy port_policy[SWITCH_PORT_ATTR_MAX+1] = { - [SWITCH_PORT_ID] = { .type = NLA_U32 }, - [SWITCH_PORT_FLAG_TAGGED] = { .type = NLA_FLAG }, -}; - -static inline void -swconfig_lock(void) -{ - spin_lock(&swdevs_lock); -} - -static inline void -swconfig_unlock(void) -{ - spin_unlock(&swdevs_lock); -} - -static struct switch_dev * -swconfig_get_dev(struct genl_info *info) -{ - struct switch_dev *dev = NULL; - struct switch_dev *p; - int id; - - if (!info->attrs[SWITCH_ATTR_ID]) - goto done; - - id = nla_get_u32(info->attrs[SWITCH_ATTR_ID]); - swconfig_lock(); - list_for_each_entry(p, &swdevs, dev_list) { - if (id != p->id) - continue; - - dev = p; - break; - } - if (dev) - spin_lock(&dev->lock); - else - DPRINTF("device %d not found\n", id); - swconfig_unlock(); -done: - return dev; -} - -static inline void -swconfig_put_dev(struct switch_dev *dev) -{ - spin_unlock(&dev->lock); -} - -static int -swconfig_dump_attr(struct swconfig_callback *cb, void *arg) -{ - struct switch_attr *op = arg; - struct genl_info *info = cb->info; - struct sk_buff *msg = cb->msg; - int id = cb->args[0]; - void *hdr; - - hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, &switch_fam, - NLM_F_MULTI, SWITCH_CMD_NEW_ATTR); - if (IS_ERR(hdr)) - return -1; - - NLA_PUT_U32(msg, SWITCH_ATTR_OP_ID, id); - NLA_PUT_U32(msg, SWITCH_ATTR_OP_TYPE, op->type); - NLA_PUT_STRING(msg, SWITCH_ATTR_OP_NAME, op->name); - if (op->description) - NLA_PUT_STRING(msg, SWITCH_ATTR_OP_DESCRIPTION, - op->description); - - return genlmsg_end(msg, hdr); -nla_put_failure: - genlmsg_cancel(msg, hdr); - return -EMSGSIZE; -} - -/* spread multipart messages across multiple message buffers */ -static int -swconfig_send_multipart(struct swconfig_callback *cb, void *arg) -{ - struct genl_info *info = cb->info; - int restart = 0; - int err; - - do { - if (!cb->msg) { - cb->msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); - if (cb->msg == NULL) - goto error; - } - - if (!(cb->fill(cb, arg) < 0)) - break; - - /* fill failed, check if this was already the second attempt */ - if (restart) - goto error; - - /* try again in a new message, send the current one */ - restart = 1; - if (cb->close) { - if (cb->close(cb, arg) < 0) - goto error; - } - err = genlmsg_unicast(cb->msg, info->snd_pid); - cb->msg = NULL; - if (err < 0) - goto error; - - } while (restart); - - return 0; - -error: - if (cb->msg) - nlmsg_free(cb->msg); - return -1; -} - -static int -swconfig_list_attrs(struct sk_buff *skb, struct genl_info *info) -{ - struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); - const struct switch_attrlist *alist; - struct switch_dev *dev; - struct swconfig_callback cb; - int err = -EINVAL; - int i; - - /* defaults */ - struct switch_attr *def_list; - unsigned long *def_active; - int n_def; - - dev = swconfig_get_dev(info); - if (!dev) - return -EINVAL; - - switch(hdr->cmd) { - case SWITCH_CMD_LIST_GLOBAL: - alist = &dev->attr_global; - def_list = default_global; - def_active = &dev->def_global; - n_def = ARRAY_SIZE(default_global); - break; - case SWITCH_CMD_LIST_VLAN: - alist = &dev->attr_vlan; - def_list = default_vlan; - def_active = &dev->def_vlan; - n_def = ARRAY_SIZE(default_vlan); - break; - case SWITCH_CMD_LIST_PORT: - alist = &dev->attr_port; - def_list = default_port; - def_active = &dev->def_port; - n_def = ARRAY_SIZE(default_port); - break; - default: - WARN_ON(1); - goto out; - } - - memset(&cb, 0, sizeof(cb)); - cb.info = info; - cb.fill = swconfig_dump_attr; - for (i = 0; i < alist->n_attr; i++) { - if (alist->attr[i].disabled) - continue; - cb.args[0] = i; - err = swconfig_send_multipart(&cb, (void *) &alist->attr[i]); - if (err < 0) - goto error; - } - - /* defaults */ - for (i = 0; i < n_def; i++) { - if (!test_bit(i, def_active)) - continue; - cb.args[0] = SWITCH_ATTR_DEFAULTS_OFFSET + i; - err = swconfig_send_multipart(&cb, (void *) &def_list[i]); - if (err < 0) - goto error; - } - swconfig_put_dev(dev); - - if (!cb.msg) - return 0; - - return genlmsg_unicast(cb.msg, info->snd_pid); - -error: - if (cb.msg) - nlmsg_free(cb.msg); -out: - swconfig_put_dev(dev); - return err; -} - -static const struct switch_attr * -swconfig_lookup_attr(struct switch_dev *dev, struct genl_info *info, - struct switch_val *val) -{ - struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); - const struct switch_attrlist *alist; - const struct switch_attr *attr = NULL; - int attr_id; - - /* defaults */ - struct switch_attr *def_list; - unsigned long *def_active; - int n_def; - - if (!info->attrs[SWITCH_ATTR_OP_ID]) - goto done; - - switch(hdr->cmd) { - case SWITCH_CMD_SET_GLOBAL: - case SWITCH_CMD_GET_GLOBAL: - alist = &dev->attr_global; - def_list = default_global; - def_active = &dev->def_global; - n_def = ARRAY_SIZE(default_global); - break; - case SWITCH_CMD_SET_VLAN: - case SWITCH_CMD_GET_VLAN: - alist = &dev->attr_vlan; - def_list = default_vlan; - def_active = &dev->def_vlan; - n_def = ARRAY_SIZE(default_vlan); - if (!info->attrs[SWITCH_ATTR_OP_VLAN]) - goto done; - val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_VLAN]); - if (val->port_vlan >= dev->vlans) - goto done; - break; - case SWITCH_CMD_SET_PORT: - case SWITCH_CMD_GET_PORT: - alist = &dev->attr_port; - def_list = default_port; - def_active = &dev->def_port; - n_def = ARRAY_SIZE(default_port); - if (!info->attrs[SWITCH_ATTR_OP_PORT]) - goto done; - val->port_vlan = nla_get_u32(info->attrs[SWITCH_ATTR_OP_PORT]); - if (val->port_vlan >= dev->ports) - goto done; - break; - default: - WARN_ON(1); - goto done; - } - - if (!alist) - goto done; - - attr_id = nla_get_u32(info->attrs[SWITCH_ATTR_OP_ID]); - if (attr_id >= SWITCH_ATTR_DEFAULTS_OFFSET) { - attr_id -= SWITCH_ATTR_DEFAULTS_OFFSET; - if (attr_id >= n_def) - goto done; - if (!test_bit(attr_id, def_active)) - goto done; - attr = &def_list[attr_id]; - } else { - if (attr_id >= alist->n_attr) - goto done; - attr = &alist->attr[attr_id]; - } - - if (attr->disabled) - attr = NULL; - -done: - if (!attr) - DPRINTF("attribute lookup failed\n"); - val->attr = attr; - return attr; -} - -static int -swconfig_parse_ports(struct sk_buff *msg, struct nlattr *head, - struct switch_val *val, int max) -{ - struct nlattr *nla; - int rem; - - val->len = 0; - nla_for_each_nested(nla, head, rem) { - struct nlattr *tb[SWITCH_PORT_ATTR_MAX+1]; - struct switch_port *port = &val->value.ports[val->len]; - - if (val->len >= max) - return -EINVAL; - - if (nla_parse_nested(tb, SWITCH_PORT_ATTR_MAX, nla, - port_policy)) - return -EINVAL; - - if (!tb[SWITCH_PORT_ID]) - return -EINVAL; - - port->id = nla_get_u32(tb[SWITCH_PORT_ID]); - if (tb[SWITCH_PORT_FLAG_TAGGED]) - port->flags |= (1 << SWITCH_PORT_FLAG_TAGGED); - val->len++; - } - - return 0; -} - -static int -swconfig_set_attr(struct sk_buff *skb, struct genl_info *info) -{ - const struct switch_attr *attr; - struct switch_dev *dev; - struct switch_val val; - int err = -EINVAL; - - dev = swconfig_get_dev(info); - if (!dev) - return -EINVAL; - - memset(&val, 0, sizeof(val)); - attr = swconfig_lookup_attr(dev, info, &val); - if (!attr || !attr->set) - goto error; - - val.attr = attr; - switch(attr->type) { - case SWITCH_TYPE_NOVAL: - break; - case SWITCH_TYPE_INT: - if (!info->attrs[SWITCH_ATTR_OP_VALUE_INT]) - goto error; - val.value.i = - nla_get_u32(info->attrs[SWITCH_ATTR_OP_VALUE_INT]); - break; - case SWITCH_TYPE_STRING: - if (!info->attrs[SWITCH_ATTR_OP_VALUE_STR]) - goto error; - val.value.s = - nla_data(info->attrs[SWITCH_ATTR_OP_VALUE_STR]); - break; - case SWITCH_TYPE_PORTS: - val.value.ports = dev->portbuf; - memset(dev->portbuf, 0, - sizeof(struct switch_port) * dev->ports); - - /* TODO: implement multipart? */ - if (info->attrs[SWITCH_ATTR_OP_VALUE_PORTS]) { - err = swconfig_parse_ports(skb, - info->attrs[SWITCH_ATTR_OP_VALUE_PORTS], &val, dev->ports); - if (err < 0) - goto error; - } else { - val.len = 0; - err = 0; - } - break; - default: - goto error; - } - - err = attr->set(dev, attr, &val); -error: - swconfig_put_dev(dev); - return err; -} - -static int -swconfig_close_portlist(struct swconfig_callback *cb, void *arg) -{ - if (cb->nest[0]) - nla_nest_end(cb->msg, cb->nest[0]); - return 0; -} - -static int -swconfig_send_port(struct swconfig_callback *cb, void *arg) -{ - const struct switch_port *port = arg; - struct nlattr *p = NULL; - - if (!cb->nest[0]) { - cb->nest[0] = nla_nest_start(cb->msg, cb->cmd); - if (!cb->nest[0]) - return -1; - } - - p = nla_nest_start(cb->msg, SWITCH_ATTR_PORT); - if (!p) - goto error; - - NLA_PUT_U32(cb->msg, SWITCH_PORT_ID, port->id); - if (port->flags & (1 << SWITCH_PORT_FLAG_TAGGED)) - NLA_PUT_FLAG(cb->msg, SWITCH_PORT_FLAG_TAGGED); - - nla_nest_end(cb->msg, p); - return 0; - -nla_put_failure: - nla_nest_cancel(cb->msg, p); -error: - nla_nest_cancel(cb->msg, cb->nest[0]); - return -1; -} - -static int -swconfig_send_ports(struct sk_buff **msg, struct genl_info *info, int attr, - const struct switch_val *val) -{ - struct swconfig_callback cb; - int err = 0; - int i; - - if (!val->value.ports) - return -EINVAL; - - memset(&cb, 0, sizeof(cb)); - cb.cmd = attr; - cb.msg = *msg; - cb.info = info; - cb.fill = swconfig_send_port; - cb.close = swconfig_close_portlist; - - cb.nest[0] = nla_nest_start(cb.msg, cb.cmd); - for (i = 0; i < val->len; i++) { - err = swconfig_send_multipart(&cb, &val->value.ports[i]); - if (err) - goto done; - } - err = val->len; - swconfig_close_portlist(&cb, NULL); - *msg = cb.msg; - -done: - return err; -} - -static int -swconfig_get_attr(struct sk_buff *skb, struct genl_info *info) -{ - struct genlmsghdr *hdr = nlmsg_data(info->nlhdr); - const struct switch_attr *attr; - struct switch_dev *dev; - struct sk_buff *msg = NULL; - struct switch_val val; - int err = -EINVAL; - int cmd = hdr->cmd; - - dev = swconfig_get_dev(info); - if (!dev) - return -EINVAL; - - memset(&val, 0, sizeof(val)); - attr = swconfig_lookup_attr(dev, info, &val); - if (!attr || !attr->get) - goto error; - - if (attr->type == SWITCH_TYPE_PORTS) { - val.value.ports = dev->portbuf; - memset(dev->portbuf, 0, - sizeof(struct switch_port) * dev->ports); - } - - err = attr->get(dev, attr, &val); - if (err) - goto error; - - msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); - if (!msg) - goto error; - - hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, &switch_fam, - 0, cmd); - if (IS_ERR(hdr)) - goto nla_put_failure; - - switch(attr->type) { - case SWITCH_TYPE_INT: - NLA_PUT_U32(msg, SWITCH_ATTR_OP_VALUE_INT, val.value.i); - break; - case SWITCH_TYPE_STRING: - NLA_PUT_STRING(msg, SWITCH_ATTR_OP_VALUE_STR, val.value.s); - break; - case SWITCH_TYPE_PORTS: - err = swconfig_send_ports(&msg, info, - SWITCH_ATTR_OP_VALUE_PORTS, &val); - if (err < 0) - goto nla_put_failure; - break; - default: - DPRINTF("invalid type in attribute\n"); - err = -EINVAL; - goto error; - } - err = genlmsg_end(msg, hdr); - if (err < 0) - goto nla_put_failure; - - swconfig_put_dev(dev); - return genlmsg_unicast(msg, info->snd_pid); - -nla_put_failure: - if (msg) - nlmsg_free(msg); -error: - swconfig_put_dev(dev); - if (!err) - err = -ENOMEM; - return err; -} - -static int -swconfig_send_switch(struct sk_buff *msg, u32 pid, u32 seq, int flags, - const struct switch_dev *dev) -{ - void *hdr; - - hdr = genlmsg_put(msg, pid, seq, &switch_fam, flags, - SWITCH_CMD_NEW_ATTR); - if (IS_ERR(hdr)) - return -1; - - NLA_PUT_U32(msg, SWITCH_ATTR_ID, dev->id); - NLA_PUT_STRING(msg, SWITCH_ATTR_NAME, dev->name); - NLA_PUT_STRING(msg, SWITCH_ATTR_DEV_NAME, dev->devname); - NLA_PUT_U32(msg, SWITCH_ATTR_VLANS, dev->vlans); - NLA_PUT_U32(msg, SWITCH_ATTR_PORTS, dev->ports); - NLA_PUT_U32(msg, SWITCH_ATTR_CPU_PORT, dev->cpu_port); - - return genlmsg_end(msg, hdr); -nla_put_failure: - genlmsg_cancel(msg, hdr); - return -EMSGSIZE; -} - -static int swconfig_dump_switches(struct sk_buff *skb, - struct netlink_callback *cb) -{ - struct switch_dev *dev; - int start = cb->args[0]; - int idx = 0; - - swconfig_lock(); - list_for_each_entry(dev, &swdevs, dev_list) { - if (++idx <= start) - continue; - if (swconfig_send_switch(skb, NETLINK_CB(cb->skb).pid, - cb->nlh->nlmsg_seq, NLM_F_MULTI, - dev) < 0) - break; - } - swconfig_unlock(); - cb->args[0] = idx; - - return skb->len; -} - -static int -swconfig_done(struct netlink_callback *cb) -{ - return 0; -} - -static struct genl_ops swconfig_ops[] = { - { - .cmd = SWITCH_CMD_LIST_GLOBAL, - .doit = swconfig_list_attrs, - .policy = switch_policy, - }, - { - .cmd = SWITCH_CMD_LIST_VLAN, - .doit = swconfig_list_attrs, - .policy = switch_policy, - }, - { - .cmd = SWITCH_CMD_LIST_PORT, - .doit = swconfig_list_attrs, - .policy = switch_policy, - }, - { - .cmd = SWITCH_CMD_GET_GLOBAL, - .doit = swconfig_get_attr, - .policy = switch_policy, - }, - { - .cmd = SWITCH_CMD_GET_VLAN, - .doit = swconfig_get_attr, - .policy = switch_policy, - }, - { - .cmd = SWITCH_CMD_GET_PORT, - .doit = swconfig_get_attr, - .policy = switch_policy, - }, - { - .cmd = SWITCH_CMD_SET_GLOBAL, - .doit = swconfig_set_attr, - .policy = switch_policy, - }, - { - .cmd = SWITCH_CMD_SET_VLAN, - .doit = swconfig_set_attr, - .policy = switch_policy, - }, - { - .cmd = SWITCH_CMD_SET_PORT, - .doit = swconfig_set_attr, - .policy = switch_policy, - }, - { - .cmd = SWITCH_CMD_GET_SWITCH, - .dumpit = swconfig_dump_switches, - .policy = switch_policy, - .done = swconfig_done, - } -}; - -int -register_switch(struct switch_dev *dev, struct net_device *netdev) -{ - INIT_LIST_HEAD(&dev->dev_list); - if (netdev) { - dev->netdev = netdev; - if (!dev->devname) - dev->devname = netdev->name; - } - BUG_ON(!dev->devname); - - if (dev->ports > 0) { - dev->portbuf = kzalloc(sizeof(struct switch_port) * dev->ports, - GFP_KERNEL); - if (!dev->portbuf) - return -ENOMEM; - } - dev->id = ++swdev_id; - swconfig_defaults_init(dev); - spin_lock_init(&dev->lock); - swconfig_lock(); - list_add(&dev->dev_list, &swdevs); - swconfig_unlock(); - - return 0; -} -EXPORT_SYMBOL_GPL(register_switch); - -void -unregister_switch(struct switch_dev *dev) -{ - kfree(dev->portbuf); - spin_lock(&dev->lock); - swconfig_lock(); - list_del(&dev->dev_list); - swconfig_unlock(); - spin_unlock(&dev->lock); -} -EXPORT_SYMBOL_GPL(unregister_switch); - - -static int __init -swconfig_init(void) -{ - int i, err; - - INIT_LIST_HEAD(&swdevs); - err = genl_register_family(&switch_fam); - if (err) - return err; - - for (i = 0; i < ARRAY_SIZE(swconfig_ops); i++) { - err = genl_register_ops(&switch_fam, &swconfig_ops[i]); - if (err) - goto unregister; - } - - return 0; - -unregister: - genl_unregister_family(&switch_fam); - return err; -} - -static void __exit -swconfig_exit(void) -{ - genl_unregister_family(&switch_fam); -} - -module_init(swconfig_init); -module_exit(swconfig_exit); - |