switch driver cleanup, 4th phase

SVN-Revision: 9340
This commit is contained in:
Gabor Juhos 2007-10-17 08:10:47 +00:00
parent dc0a4f8ff8
commit 49b631d730
5 changed files with 229 additions and 156 deletions

View file

@ -98,6 +98,9 @@ static int __init adm5120_board_setup(void)
amba_device_register(&adm5120_uart0_device, &iomem_resource); amba_device_register(&adm5120_uart0_device, &iomem_resource);
amba_device_register(&adm5120_uart1_device, &iomem_resource); amba_device_register(&adm5120_uart1_device, &iomem_resource);
/* register built-in ethernet switch */
platform_device_register(&adm5120_switch_device);
/* setup PCI irq map */ /* setup PCI irq map */
adm5120_pci_set_irq_map(board->pci_nr_irqs, board->pci_irq_map); adm5120_pci_set_irq_map(board->pci_nr_irqs, board->pci_irq_map);

View file

@ -61,16 +61,30 @@ unsigned char adm5120_eth_vlans[6] = {
0x41, 0x42, 0x44, 0x48, 0x50, 0x60 0x41, 0x42, 0x44, 0x48, 0x50, 0x60
}; };
EXPORT_SYMBOL_GPL(adm5120_eth_vlans); EXPORT_SYMBOL_GPL(adm5120_eth_vlans);
#endif
#else
/* Built-in ethernet switch */ /* Built-in ethernet switch */
struct resource adm5120_switch_resources[] = {
[0] = {
.start = ADM5120_SWITCH_BASE,
.end = ADM5120_SWITCH_BASE+ADM5120_SWITCH_SIZE-1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = ADM5120_IRQ_SWITCH,
.end = ADM5120_IRQ_SWITCH,
.flags = IORESOURCE_IRQ,
},
};
struct adm5120_switch_platform_data adm5120_switch_data; struct adm5120_switch_platform_data adm5120_switch_data;
struct platform_device adm5120_switch_device = { struct platform_device adm5120_switch_device = {
.name = "adm5120-switch", .name = "adm5120-switch",
.id = -1, .id = -1,
.num_resources = ARRAY_SIZE(adm5120_switch_resources),
.resource = adm5120_switch_resources,
.dev.platform_data = &adm5120_switch_data, .dev.platform_data = &adm5120_switch_data,
}; };
#endif
/* USB Host Controller */ /* USB Host Controller */
struct resource adm5120_hcd_resources[] = { struct resource adm5120_hcd_resources[] = {

View file

@ -1,23 +1,29 @@
/* /*
* ADM5120 built in ethernet switch driver * ADM5120 built-in ethernet switch driver
* *
* Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
*
* This code was based on a driver for Linux 2.6.xx by Jeroen Vreeken.
* Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2005 * Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2005
* NAPI extension for the Jeroen's driver
* Copyright Thomas Langer (Thomas.Langer@infineon.com), 2007
* Copyright Friedrich Beckmann (Friedrich.Beckmann@infineon.com), 2007
* Inspiration for the Jeroen's driver came from the ADMtek 2.4 driver.
* Copyright ADMtek Inc.
* *
* Inspiration for this driver came from the original ADMtek 2.4 * This program is free software; you can redistribute it and/or modify it
* driver, Copyright ADMtek Inc. * under the terms of the GNU General Public License version 2 as published
* * by the Free Software Foundation.
* NAPI extensions by Thomas Langer (Thomas.Langer@infineon.com)
* and Friedrich Beckmann (Friedrich.Beckmann@infineon.com), 2007
*
* TODO: Add support of high prio queues (currently disabled)
* *
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
@ -39,14 +45,13 @@
#define DRV_DESC "ADM5120 built-in ethernet switch driver" #define DRV_DESC "ADM5120 built-in ethernet switch driver"
#define DRV_VERSION "0.1.0" #define DRV_VERSION "0.1.0"
MODULE_AUTHOR("Jeroen Vreeken (pe1rxq@amsat.org)"); #define CONFIG_ADM5120_SWITCH_NAPI 1
MODULE_DESCRIPTION("ADM5120 ethernet switch driver"); #undef CONFIG_ADM5120_SWITCH_DEBUG
MODULE_LICENSE("GPL");
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
#if 0 /*def ADM5120_SWITCH_DEBUG*/ #ifdef CONFIG_ADM5120_SWITCH_DEBUG
#define SW_DBG(f, a...) printk(KERN_DEBUG "%s: " f, DRV_NAME , ## a) #define SW_DBG(f, a...) printk(KERN_DBG "%s: " f, DRV_NAME , ## a)
#else #else
#define SW_DBG(f, a...) do {} while (0) #define SW_DBG(f, a...) do {} while (0)
#endif #endif
@ -83,10 +88,15 @@ MODULE_LICENSE("GPL");
SWITCH_INT_MD | SWITCH_INT_PSC) SWITCH_INT_MD | SWITCH_INT_PSC)
#define SWITCH_INTS_USED (SWITCH_INTS_LOW | SWITCH_INT_PSC) #define SWITCH_INTS_USED (SWITCH_INTS_LOW | SWITCH_INT_PSC)
#define SWITCH_INTS_POLL (SWITCH_INT_RLD | SWITCH_INT_LDF) #define SWITCH_INTS_POLL (SWITCH_INT_RLD | SWITCH_INT_LDF | SWITCH_INT_SLD)
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
struct adm5120_if_priv {
unsigned int vlan_no;
unsigned int port_mask;
};
struct dma_desc { struct dma_desc {
__u32 buf1; __u32 buf1;
#define DESC_OWN (1UL << 31) /* Owned by the switch */ #define DESC_OWN (1UL << 31) /* Owned by the switch */
@ -117,28 +127,8 @@ struct dma_desc {
#define DESC_TYPE_PPPoE 0x1 /* PPPoE packet */ #define DESC_TYPE_PPPoE 0x1 /* PPPoE packet */
} __attribute__ ((aligned(16))); } __attribute__ ((aligned(16)));
static inline u32 desc_get_srcport(struct dma_desc *desc)
{
return (desc->misc >> DESC_SRCPORT_SHIFT) & DESC_SRCPORT_MASK;
}
static inline u32 desc_get_pktlen(struct dma_desc *desc)
{
return (desc->misc >> DESC_PKTLEN_SHIFT) & DESC_PKTLEN_MASK;
}
static inline int desc_ipcsum_fail(struct dma_desc *desc)
{
return ((desc->misc & DESC_IPCSUM_FAIL) != 0);
}
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
/* default settings - unlimited TX and RX on all ports, default shaper mode */
static unsigned char bw_matrix[SWITCH_NUM_PORTS] = {
0, 0, 0, 0, 0, 0
};
static int adm5120_nrdevs; static int adm5120_nrdevs;
static struct net_device *adm5120_devs[SWITCH_NUM_PORTS]; static struct net_device *adm5120_devs[SWITCH_NUM_PORTS];
@ -159,10 +149,7 @@ static unsigned int cur_txl, dirty_txl;
static unsigned int sw_used; static unsigned int sw_used;
static spinlock_t sw_lock = SPIN_LOCK_UNLOCKED; static spinlock_t tx_lock = SPIN_LOCK_UNLOCKED;
static spinlock_t poll_lock = SPIN_LOCK_UNLOCKED;
static struct net_device sw_dev;
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
@ -208,6 +195,21 @@ static inline u32 sw_int_status(void)
return t; return t;
} }
static inline u32 desc_get_srcport(struct dma_desc *desc)
{
return (desc->misc >> DESC_SRCPORT_SHIFT) & DESC_SRCPORT_MASK;
}
static inline u32 desc_get_pktlen(struct dma_desc *desc)
{
return (desc->misc >> DESC_PKTLEN_SHIFT) & DESC_PKTLEN_MASK;
}
static inline int desc_ipcsum_fail(struct dma_desc *desc)
{
return ((desc->misc & DESC_IPCSUM_FAIL) != 0);
}
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
static void sw_dump_desc(char *label, struct dma_desc *desc, int tx) static void sw_dump_desc(char *label, struct dma_desc *desc, int tx)
@ -386,8 +388,6 @@ static int adm5120_switch_rx(int limit)
SW_DBG("rx start, limit=%d, cur_rxl=%u, dirty_rxl=%u\n", SW_DBG("rx start, limit=%d, cur_rxl=%u, dirty_rxl=%u\n",
limit, cur_rxl, dirty_rxl); limit, cur_rxl, dirty_rxl);
sw_int_ack(SWITCH_INTS_POLL);
while (done < limit) { while (done < limit) {
int entry = cur_rxl % RX_RING_SIZE; int entry = cur_rxl % RX_RING_SIZE;
struct dma_desc *desc = &rxl_descs[entry]; struct dma_desc *desc = &rxl_descs[entry];
@ -430,7 +430,11 @@ static int adm5120_switch_rx(int limit)
dma_cache_wback_inv((unsigned long)skb->data, dma_cache_wback_inv((unsigned long)skb->data,
skb->len); skb->len);
#ifdef CONFIG_ADM5120_SWITCH_USE_NAPI
netif_receive_skb(skb); netif_receive_skb(skb);
#else
netif_rx(skb);
#endif
rdev->last_rx = jiffies; rdev->last_rx = jiffies;
rdev->stats.rx_packets++; rdev->stats.rx_packets++;
@ -456,12 +460,11 @@ static int adm5120_switch_rx(int limit)
return done; return done;
} }
static void adm5120_switch_tx(void) static void adm5120_switch_tx(void)
{ {
unsigned int entry; unsigned int entry;
/* find and cleanup dirty tx descriptors */ spin_lock(&tx_lock);
entry = dirty_txl % TX_RING_SIZE; entry = dirty_txl % TX_RING_SIZE;
while (dirty_txl != cur_txl) { while (dirty_txl != cur_txl) {
struct dma_desc *desc = &txl_descs[entry]; struct dma_desc *desc = &txl_descs[entry];
@ -481,7 +484,6 @@ static void adm5120_switch_tx(void)
} }
if ((cur_txl - dirty_txl) < TX_QUEUE_LEN - 4) { if ((cur_txl - dirty_txl) < TX_QUEUE_LEN - 4) {
/* wake up queue of all devices */
int i; int i;
for (i = 0; i < SWITCH_NUM_PORTS; i++) { for (i = 0; i < SWITCH_NUM_PORTS; i++) {
if (!adm5120_devs[i]) if (!adm5120_devs[i])
@ -489,14 +491,22 @@ static void adm5120_switch_tx(void)
netif_wake_queue(adm5120_devs[i]); netif_wake_queue(adm5120_devs[i]);
} }
} }
spin_unlock(&tx_lock);
} }
#ifdef CONFIG_ADM5120_SWITCH_NAPI
static int adm5120_if_poll(struct net_device *dev, int *budget) static int adm5120_if_poll(struct net_device *dev, int *budget)
{ {
int limit = min(dev->quota, *budget); int limit = min(dev->quota, *budget);
int done; int done;
u32 status; u32 status;
sw_int_ack(SWITCH_INTS_POLL);
SW_DBG("%s: processing TX ring\n", dev->name);
adm5120_switch_tx();
SW_DBG("%s: processing RX ring\n", dev->name);
done = adm5120_switch_rx(limit); done = adm5120_switch_rx(limit);
*budget -= done; *budget -= done;
@ -504,74 +514,53 @@ static int adm5120_if_poll(struct net_device *dev, int *budget)
status = sw_int_status() & SWITCH_INTS_POLL; status = sw_int_status() & SWITCH_INTS_POLL;
if ((done < limit) && (!status)) { if ((done < limit) && (!status)) {
SW_DBG("disable polling mode for %s\n", poll_dev->name); SW_DBG("disable polling mode for %s\n", dev->name);
netif_rx_complete(dev); netif_rx_complete(dev);
sw_int_unmask(SWITCH_INTS_POLL); sw_int_unmask(SWITCH_INTS_POLL);
return 0; return 0;
} }
SW_DBG("%s still in polling mode, done=%d, status=%x\n",
dev->name, done, status);
return 1; return 1;
} }
#endif /* CONFIG_ADM5120_SWITCH_USE_NAPI */
static irqreturn_t adm5120_poll_irq(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
u32 status;
status = sw_int_status();
status &= SWITCH_INTS_POLL;
if (!status)
return IRQ_NONE;
sw_dump_intr_mask("poll ints", status);
SW_DBG("enable polling mode for %s\n", dev->name);
sw_int_mask(SWITCH_INTS_POLL);
netif_rx_schedule(dev);
return IRQ_HANDLED;
}
static irqreturn_t adm5120_switch_irq(int irq, void *dev_id) static irqreturn_t adm5120_switch_irq(int irq, void *dev_id)
{ {
u32 status; u32 status;
status = sw_int_status(); status = sw_int_status();
status &= SWITCH_INTS_ALL & ~SWITCH_INTS_POLL; status &= SWITCH_INTS_ALL;
if (!status) if (!status)
return IRQ_NONE; return IRQ_NONE;
#ifdef CONFIG_ADM5120_SWITCH_NAPI
sw_int_ack(status & ~SWITCH_INTS_POLL);
if (status & SWITCH_INTS_POLL) {
struct net_device *dev = dev_id;
sw_dump_intr_mask("poll ints", status);
SW_DBG("enable polling mode for %s\n", dev->name);
sw_int_mask(SWITCH_INTS_POLL);
netif_rx_schedule(dev);
}
#else
sw_int_ack(status); sw_int_ack(status);
if (status & SWITCH_INT_SLD) { if (status & (SWITCH_INT_RLD | SWITCH_INT_LDF)) {
spin_lock(&sw_lock); adm5120_switch_rx(RX_RING_SIZE);
adm5120_switch_tx();
spin_unlock(&sw_lock);
} }
if (status & SWITCH_INT_SLD) {
adm5120_switch_tx();
}
#endif
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static void adm5120_set_vlan(char *matrix)
{
unsigned long val;
int vlan_port, port;
val = matrix[0] + (matrix[1]<<8) + (matrix[2]<<16) + (matrix[3]<<24);
sw_write_reg(SWITCH_REG_VLAN_G1, val);
val = matrix[4] + (matrix[5]<<8);
sw_write_reg(SWITCH_REG_VLAN_G2, val);
/* Now set/update the port vs. device lookup table */
for (port=0; port<SWITCH_NUM_PORTS; port++) {
for (vlan_port=0; vlan_port<SWITCH_NUM_PORTS && !(matrix[vlan_port] & (0x00000001 << port)); vlan_port++);
if (vlan_port <SWITCH_NUM_PORTS)
adm5120_port[port] = adm5120_devs[vlan_port];
else
adm5120_port[port] = NULL;
}
}
static void adm5120_set_bw(char *matrix) static void adm5120_set_bw(char *matrix)
{ {
unsigned long val; unsigned long val;
@ -713,6 +702,81 @@ static void adm5120_switch_rx_ring_free(void)
rxl_descs_dma); rxl_descs_dma);
} }
static void adm5120_write_mac(struct net_device *dev)
{
struct adm5120_if_priv *priv = netdev_priv(dev);
unsigned char *mac = dev->dev_addr;
u32 t;
t = mac[2] | (mac[3] << MAC_WT1_MAC3_SHIFT) |
(mac[4] << MAC_WT1_MAC4_SHIFT) | (mac[5] << MAC_WT1_MAC4_SHIFT);
sw_write_reg(SWITCH_REG_MAC_WT1, t);
t = (mac[0] << MAC_WT0_MAC0_SHIFT) | (mac[1] << MAC_WT0_MAC1_SHIFT) |
MAC_WT0_MAWC | MAC_WT0_WVE | (priv->vlan_no<<3);
sw_write_reg(SWITCH_REG_MAC_WT0, t);
while (!(sw_read_reg(SWITCH_REG_MAC_WT0) & MAC_WT0_MWD));
}
static void adm5120_set_vlan(char *matrix)
{
unsigned long val;
int vlan_port, port;
val = matrix[0] + (matrix[1]<<8) + (matrix[2]<<16) + (matrix[3]<<24);
sw_write_reg(SWITCH_REG_VLAN_G1, val);
val = matrix[4] + (matrix[5]<<8);
sw_write_reg(SWITCH_REG_VLAN_G2, val);
/* Now set/update the port vs. device lookup table */
for (port=0; port<SWITCH_NUM_PORTS; port++) {
for (vlan_port=0; vlan_port<SWITCH_NUM_PORTS && !(matrix[vlan_port] & (0x00000001 << port)); vlan_port++);
if (vlan_port <SWITCH_NUM_PORTS)
adm5120_port[port] = adm5120_devs[vlan_port];
else
adm5120_port[port] = NULL;
}
}
static void adm5120_switch_set_vlan_mac(unsigned int vlan, unsigned char *mac)
{
u32 t;
t = mac[2] | (mac[3] << MAC_WT1_MAC3_SHIFT)
| (mac[4] << MAC_WT1_MAC4_SHIFT)
| (mac[5] << MAC_WT1_MAC4_SHIFT);
sw_write_reg(SWITCH_REG_MAC_WT1, t);
t = (mac[0] << MAC_WT0_MAC0_SHIFT) | (mac[1] << MAC_WT0_MAC1_SHIFT) |
MAC_WT0_MAWC | MAC_WT0_WVE | (vlan << MAC_WT0_WVN_SHIFT) |
(MAC_WT0_WAF_STATIC << MAC_WT0_WAF_SHIFT);
sw_write_reg(SWITCH_REG_MAC_WT0, t);
do {
t = sw_read_reg(SWITCH_REG_MAC_WT0);
} while ((t & MAC_WT0_MWD) == 0);
}
static void adm5120_switch_set_vlan_ports(unsigned int vlan, u32 ports)
{
unsigned int reg;
u32 t;
if (vlan < 4)
reg = SWITCH_REG_VLAN_G1;
else {
vlan -= 4;
reg = SWITCH_REG_VLAN_G2;
}
t = sw_read_reg(reg);
t &= ~(0xFF << (vlan*8));
t |= (ports << (vlan*8));
sw_write_reg(reg, t);
}
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
static int adm5120_if_open(struct net_device *dev) static int adm5120_if_open(struct net_device *dev)
@ -721,7 +785,7 @@ static int adm5120_if_open(struct net_device *dev)
int err; int err;
int i; int i;
err = request_irq(dev->irq, adm5120_poll_irq, err = request_irq(dev->irq, adm5120_switch_irq,
(IRQF_SHARED | IRQF_DISABLED), dev->name, dev); (IRQF_SHARED | IRQF_DISABLED), dev->name, dev);
if (err) { if (err) {
SW_ERR("unable to get irq for %s\n", dev->name); SW_ERR("unable to get irq for %s\n", dev->name);
@ -776,12 +840,12 @@ static int adm5120_if_hard_start_xmit(struct sk_buff *skb,
struct net_device *dev) struct net_device *dev)
{ {
struct dma_desc *desc; struct dma_desc *desc;
struct adm5120_sw *priv = netdev_priv(dev); struct adm5120_if_priv *priv = netdev_priv(dev);
unsigned int entry; unsigned int entry;
unsigned long data; unsigned long data;
/* lock switch irq */ /* lock switch irq */
spin_lock_irq(&sw_lock); spin_lock_irq(&tx_lock);
/* calculate the next TX descriptor entry. */ /* calculate the next TX descriptor entry. */
entry = cur_txl % TX_RING_SIZE; entry = cur_txl % TX_RING_SIZE;
@ -790,6 +854,7 @@ static int adm5120_if_hard_start_xmit(struct sk_buff *skb,
if (desc->buf1 & DESC_OWN) { if (desc->buf1 & DESC_OWN) {
/* We want to write a packet but the TX queue is still /* We want to write a packet but the TX queue is still
* occupied by the DMA. We are faster than the DMA... */ * occupied by the DMA. We are faster than the DMA... */
SW_DBG("%s unable to transmit, packet dopped\n", dev->name);
dev_kfree_skb(skb); dev_kfree_skb(skb);
dev->stats.tx_dropped++; dev->stats.tx_dropped++;
return 0; return 0;
@ -801,7 +866,7 @@ static int adm5120_if_hard_start_xmit(struct sk_buff *skb,
desc->misc = desc->misc =
((skb->len<ETH_ZLEN?ETH_ZLEN:skb->len) << DESC_PKTLEN_SHIFT) | ((skb->len<ETH_ZLEN?ETH_ZLEN:skb->len) << DESC_PKTLEN_SHIFT) |
(0x1 << priv->port); (0x1 << priv->vlan_no);
desc->buflen = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; desc->buflen = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
@ -816,7 +881,7 @@ static int adm5120_if_hard_start_xmit(struct sk_buff *skb,
dev->trans_start = jiffies; dev->trans_start = jiffies;
spin_unlock_irq(&sw_lock); spin_unlock_irq(&tx_lock);
return 0; return 0;
} }
@ -826,13 +891,13 @@ static void adm5120_if_tx_timeout(struct net_device *dev)
SW_INFO("TX timeout on %s\n",dev->name); SW_INFO("TX timeout on %s\n",dev->name);
} }
static void adm5120_set_multicast_list(struct net_device *dev) static void adm5120_if_set_multicast_list(struct net_device *dev)
{ {
struct adm5120_sw *priv = netdev_priv(dev); struct adm5120_if_priv *priv = netdev_priv(dev);
u32 ports; u32 ports;
u32 t; u32 t;
ports = adm5120_eth_vlans[priv->port] & SWITCH_PORTS_NOCPU; ports = adm5120_eth_vlans[priv->vlan_no] & SWITCH_PORTS_NOCPU;
t = sw_read_reg(SWITCH_REG_CPUP_CONF); t = sw_read_reg(SWITCH_REG_CPUP_CONF);
if (dev->flags & IFF_PROMISC) if (dev->flags & IFF_PROMISC)
@ -877,24 +942,6 @@ static void adm5120_set_multicast_list(struct net_device *dev)
} }
static void adm5120_write_mac(struct net_device *dev)
{
struct adm5120_sw *priv = netdev_priv(dev);
unsigned char *mac = dev->dev_addr;
u32 t;
t = mac[2] | (mac[3] << MAC_WT1_MAC3_SHIFT) |
(mac[4] << MAC_WT1_MAC4_SHIFT) | (mac[5] << MAC_WT1_MAC4_SHIFT);
sw_write_reg(SWITCH_REG_MAC_WT1, t);
t = (mac[0] << MAC_WT0_MAC0_SHIFT) | (mac[1] << MAC_WT0_MAC1_SHIFT) |
MAC_WT0_MAWC | MAC_WT0_WVE | (priv->port<<3);
sw_write_reg(SWITCH_REG_MAC_WT0, t);
while (!(sw_read_reg(SWITCH_REG_MAC_WT0) & MAC_WT0_MWD));
}
static int adm5120_if_set_mac_address(struct net_device *dev, void *p) static int adm5120_if_set_mac_address(struct net_device *dev, void *p)
{ {
struct sockaddr *addr = p; struct sockaddr *addr = p;
@ -904,17 +951,18 @@ static int adm5120_if_set_mac_address(struct net_device *dev, void *p)
return 0; return 0;
} }
static int adm5120_if_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int adm5120_if_do_ioctl(struct net_device *dev, struct ifreq *rq,
int cmd)
{ {
int err; int err;
struct adm5120_sw_info info; struct adm5120_sw_info info;
struct adm5120_sw *priv = netdev_priv(dev); struct adm5120_if_priv *priv = netdev_priv(dev);
switch(cmd) { switch(cmd) {
case SIOCGADMINFO: case SIOCGADMINFO:
info.magic = 0x5120; info.magic = 0x5120;
info.ports = adm5120_nrdevs; info.ports = adm5120_nrdevs;
info.vlan = priv->port; info.vlan = priv->vlan_no;
err = copy_to_user(rq->ifr_data, &info, sizeof(info)); err = copy_to_user(rq->ifr_data, &info, sizeof(info));
if (err) if (err)
return -EFAULT; return -EFAULT;
@ -934,19 +982,6 @@ static int adm5120_if_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd
if (err) if (err)
return -EFAULT; return -EFAULT;
break; break;
case SIOCGETBW:
err = copy_to_user(rq->ifr_data, bw_matrix, sizeof(bw_matrix));
if (err)
return -EFAULT;
break;
case SIOCSETBW:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
err = copy_from_user(bw_matrix, rq->ifr_data, sizeof(bw_matrix));
if (err)
return -EFAULT;
adm5120_set_bw(bw_matrix);
break;
default: default:
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
@ -956,7 +991,7 @@ static int adm5120_if_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd
static struct net_device *adm5120_if_alloc(void) static struct net_device *adm5120_if_alloc(void)
{ {
struct net_device *dev; struct net_device *dev;
struct adm5120_sw *priv; struct adm5120_if_priv *priv;
dev = alloc_etherdev(sizeof(*priv)); dev = alloc_etherdev(sizeof(*priv));
if (!dev) if (!dev)
@ -966,19 +1001,23 @@ static struct net_device *adm5120_if_alloc(void)
dev->open = adm5120_if_open; dev->open = adm5120_if_open;
dev->hard_start_xmit = adm5120_if_hard_start_xmit; dev->hard_start_xmit = adm5120_if_hard_start_xmit;
dev->stop = adm5120_if_stop; dev->stop = adm5120_if_stop;
dev->set_multicast_list = adm5120_set_multicast_list; dev->set_multicast_list = adm5120_if_set_multicast_list;
dev->do_ioctl = adm5120_if_do_ioctl; dev->do_ioctl = adm5120_if_do_ioctl;
dev->tx_timeout = adm5120_if_tx_timeout; dev->tx_timeout = adm5120_if_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT; dev->watchdog_timeo = TX_TIMEOUT;
dev->set_mac_address = adm5120_if_set_mac_address; dev->set_mac_address = adm5120_if_set_mac_address;
#ifdef CONFIG_ADM5120_SWITCH_NAPI
dev->poll = adm5120_if_poll; dev->poll = adm5120_if_poll;
dev->weight = 64; dev->weight = 64;
#endif
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
return dev; return dev;
} }
/* ------------------------------------------------------------------------ */
static void adm5120_switch_cleanup(void) static void adm5120_switch_cleanup(void)
{ {
int i; int i;
@ -996,22 +1035,13 @@ static void adm5120_switch_cleanup(void)
adm5120_switch_tx_ring_free(); adm5120_switch_tx_ring_free();
adm5120_switch_rx_ring_free(); adm5120_switch_rx_ring_free();
free_irq(ADM5120_IRQ_SWITCH, &sw_dev);
} }
static int __init adm5120_switch_init(void) static int __init adm5120_switch_probe(struct platform_device *pdev)
{ {
u32 t; u32 t;
int i, err; int i, err;
err = request_irq(ADM5120_IRQ_SWITCH, adm5120_switch_irq,
(IRQF_SHARED | IRQF_DISABLED), "switch", &sw_dev);
if (err) {
SW_ERR("request_irq failed with error %d\n", err);
goto err;
}
adm5120_nrdevs = adm5120_eth_num_ports; adm5120_nrdevs = adm5120_eth_num_ports;
t = CPUP_CONF_DCPUP | CPUP_CONF_CRCP | t = CPUP_CONF_DCPUP | CPUP_CONF_CRCP |
@ -1061,7 +1091,7 @@ static int __init adm5120_switch_init(void)
for (i = 0; i < SWITCH_NUM_PORTS; i++) { for (i = 0; i < SWITCH_NUM_PORTS; i++) {
struct net_device *dev; struct net_device *dev;
struct adm5120_sw *priv; struct adm5120_if_priv *priv;
dev = adm5120_if_alloc(); dev = adm5120_if_alloc();
if (!dev) { if (!dev) {
@ -1072,7 +1102,8 @@ static int __init adm5120_switch_init(void)
adm5120_devs[i] = dev; adm5120_devs[i] = dev;
priv = netdev_priv(dev); priv = netdev_priv(dev);
priv->port = i; priv->vlan_no = i;
priv->port_mask = adm5120_eth_vlans[i];
memcpy(dev->dev_addr, adm5120_eth_macs[i], 6); memcpy(dev->dev_addr, adm5120_eth_macs[i], 6);
adm5120_write_mac(dev); adm5120_write_mac(dev);
@ -1102,10 +1133,41 @@ err:
return err; return err;
} }
static void __exit adm5120_switch_exit(void) static int adm5120_switch_remove(struct platform_device *dev)
{ {
adm5120_switch_cleanup(); adm5120_switch_cleanup();
return 0;
} }
module_init(adm5120_switch_init); static struct platform_driver adm5120_switch_driver = {
module_exit(adm5120_switch_exit); .probe = adm5120_switch_probe,
.remove = adm5120_switch_remove,
.driver = {
.name = DRV_NAME,
},
};
/* -------------------------------------------------------------------------- */
static int __init adm5120_switch_mod_init(void)
{
int err;
pr_info(DRV_DESC " version " DRV_VERSION "\n");
err = platform_driver_register(&adm5120_switch_driver);
return err;
}
static void __exit adm5120_switch_mod_exit(void)
{
platform_driver_unregister(&adm5120_switch_driver);
}
module_init(adm5120_switch_mod_init);
module_exit(adm5120_switch_mod_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
MODULE_DESCRIPTION(DRV_DESC);
MODULE_VERSION(DRV_VERSION);

View file

@ -10,15 +10,9 @@
#ifndef _INCLUDE_ADM5120SW_H_ #ifndef _INCLUDE_ADM5120SW_H_
#define _INCLUDE_ADM5120SW_H_ #define _INCLUDE_ADM5120SW_H_
struct adm5120_sw {
int port;
};
#define SIOCSMATRIX SIOCDEVPRIVATE #define SIOCSMATRIX SIOCDEVPRIVATE
#define SIOCGMATRIX SIOCDEVPRIVATE+1 #define SIOCGMATRIX SIOCDEVPRIVATE+1
#define SIOCGADMINFO SIOCDEVPRIVATE+2 #define SIOCGADMINFO SIOCDEVPRIVATE+2
#define SIOCGETBW SIOCDEVPRIVATE+3
#define SIOCSETBW SIOCDEVPRIVATE+4
struct adm5120_sw_info { struct adm5120_sw_info {
u16 magic; u16 magic;

View file

@ -164,12 +164,12 @@
#define MAC_WT0_MWD_SHIFT 1 #define MAC_WT0_MWD_SHIFT 1
#define MAC_WT0_MWD BIT(1) /* MAC write done */ #define MAC_WT0_MWD BIT(1) /* MAC write done */
#define MAC_WT0_WFB BIT(2) /* Write Filter Bit */ #define MAC_WT0_WFB BIT(2) /* Write Filter Bit */
#define MAC_WT0_WVN_SHIFT 3 #define MAC_WT0_WVN_SHIFT 3 /* Write Vlan Number shift */
#define MAC_WT0_WVE BIT(6) /* Write VLAN enable */ #define MAC_WT0_WVE BIT(6) /* Write VLAN enable */
#define MAC_WT0_WPMN_SHIFT 7 #define MAC_WT0_WPMN_SHIFT 7
#define MAC_WT0_WAF_SHIFT 13 /* Write Age Field shift */ #define MAC_WT0_WAF_SHIFT 13 /* Write Age Field shift */
#define MAC_WT0_WAF_EMPTY 0 #define MAC_WT0_WAF_EMPTY 0
#define MAC_WT0_WAF_STATIC 7 #define MAC_WT0_WAF_STATIC 7 /* age: static */
#define MAC_WT0_MAC0_SHIFT 16 #define MAC_WT0_MAC0_SHIFT 16
#define MAC_WT0_MAC1_SHIFT 24 #define MAC_WT0_MAC1_SHIFT 24