diff options
Diffstat (limited to 'target/linux/generic-2.6/files-2.6.27/drivers/net')
5 files changed, 0 insertions, 1766 deletions
diff --git a/target/linux/generic-2.6/files-2.6.27/drivers/net/phy/adm6996.c b/target/linux/generic-2.6/files-2.6.27/drivers/net/phy/adm6996.c deleted file mode 100644 index 3033813ec0..0000000000 --- a/target/linux/generic-2.6/files-2.6.27/drivers/net/phy/adm6996.c +++ /dev/null @@ -1,170 +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->state = PHY_UP; - return 0; -} - -static int adm6996_config_aneg(struct phy_device *phydev) -{ - 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 bool adm6996_detect(struct mii_bus *bus, int addr) -{ - u16 reg; - - /* we only attach to phy id 0 */ - if (addr != 0) - return false; - - /* look for the switch on the bus */ - reg = bus->read(bus, PHYADDR(ADM_SIG0)) & ADM_SIG0_MASK; - if (reg != ADM_SIG0_VAL) - return false; - - reg = bus->read(bus, PHYADDR(ADM_SIG1)) & ADM_SIG1_MASK; - if (reg != ADM_SIG1_VAL) - return false; - - return true; -} - -static struct phy_driver adm6996_driver = { - .name = "Infineon ADM6996", - .features = PHY_BASIC_FEATURES, - .detect = adm6996_detect, - .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) -{ - 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-2.6.27/drivers/net/phy/adm6996.h b/target/linux/generic-2.6/files-2.6.27/drivers/net/phy/adm6996.h deleted file mode 100644 index e074901517..0000000000 --- a/target/linux/generic-2.6/files-2.6.27/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-2.6.27/drivers/net/phy/mvswitch.c b/target/linux/generic-2.6/files-2.6.27/drivers/net/phy/mvswitch.c deleted file mode 100644 index 78e5afe9bd..0000000000 --- a/target/linux/generic-2.6/files-2.6.27/drivers/net/phy/mvswitch.c +++ /dev/null @@ -1,474 +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"); - -struct mvswitch_priv { - /* the driver's tx function */ - int (*hardstart)(struct sk_buff *skb, struct net_device *dev); - 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->hardstart(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; - - /* initialize default vlans */ - for (i = 0; i < MV_PORTS; i++) - priv->vlans[(i == MV_WANPORT ? 1 : 0)] |= (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->hardstart = dev->hard_start_xmit; - pdev->netif_receive_skb = mvswitch_netif_receive_skb; - pdev->netif_rx = mvswitch_netif_rx; - dev->hard_start_xmit = mvswitch_mangle_tx; - dev->vlan_rx_register = mvswitch_vlan_rx_register; -#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->state = PHY_UP; - - /* 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 xmit handler */ - if (priv->hardstart && dev) - dev->hard_start_xmit = priv->hardstart; - dev->vlan_rx_register = NULL; - dev->vlan_rx_kill_vid = NULL; - dev->phy_ptr = NULL; - dev->features &= ~NETIF_F_HW_VLAN_RX; - kfree(priv); -} - -static bool -mvswitch_detect(struct mii_bus *bus, int addr) -{ - u16 reg; - int i; - - /* we attach to phy id 31 to make sure that the late probe works */ - if (addr != 31) - return false; - - /* look for the switch on the bus */ - reg = bus->read(bus, MV_PORTREG(IDENT, 0)) & MV_IDENT_MASK; - if (reg != MV_IDENT_VALUE) - return false; - - /* - * Now that we've established that the switch actually exists, let's - * get rid of the competition :) - */ - for (i = 0; i < 31; i++) { - if (!bus->phy_map[i]) - continue; - - device_unregister(&bus->phy_map[i]->dev); - kfree(bus->phy_map[i]); - bus->phy_map[i] = NULL; - } - - return true; -} - -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 struct phy_driver mvswitch_driver = { - .name = "Marvell 88E6060", - .features = PHY_BASIC_FEATURES, - .detect = &mvswitch_detect, - .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) -{ - 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-2.6.27/drivers/net/phy/mvswitch.h b/target/linux/generic-2.6/files-2.6.27/drivers/net/phy/mvswitch.h deleted file mode 100644 index 1563eec4d5..0000000000 --- a/target/linux/generic-2.6/files-2.6.27/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-2.6.27/drivers/net/phy/swconfig.c b/target/linux/generic-2.6/files-2.6.27/drivers/net/phy/swconfig.c deleted file mode 100644 index ade28429dc..0000000000 --- a/target/linux/generic-2.6/files-2.6.27/drivers/net/phy/swconfig.c +++ /dev/null @@ -1,872 +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, 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); - printk("SET PORTS %d\n", val->len); - return ret; -} - -static int -swconfig_set_vlan_ports(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val) -{ - int i; - - if (val->port_vlan >= dev->vlans) - return -EINVAL; - - /* validate ports */ - if (val->len > dev->ports) - return -EINVAL; - - for (i = 0; i < val->len; i++) { - if (val->value.ports[i].id >= dev->ports) - return -EINVAL; - } - - if (!dev->set_vlan_ports) - return -EOPNOTSUPP; - - printk("SET PORTS %d\n", val->len); - return dev->set_vlan_ports(dev, val); -} - -static int -swconfig_apply_config(struct switch_dev *dev, 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); -} - - -enum global_defaults { - GLOBAL_APPLY, -}; - -enum vlan_defaults { - VLAN_PORTS, -}; - -enum port_defaults { - PORT_LINK, -}; - -static struct switch_attr default_global[] = { - [GLOBAL_APPLY] = { - .type = SWITCH_TYPE_NOVAL, - .name = "apply", - .description = "Activate changes in the hardware", - .set = swconfig_apply_config, - } -}; - -static struct switch_attr default_port[] = { - [PORT_LINK] = { - .type = SWITCH_TYPE_INT, - .name = "link", - .description = "Current link speed", - } -}; - -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); - - /* always present, can be no-op */ - set_bit(GLOBAL_APPLY, &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, &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, &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 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; - 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]); - 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]); - 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) -{ - 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); - 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_dev; - - 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_dev: - swconfig_put_dev(dev); -error: - 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); - - 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(); -} -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); - |