summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
authorIan Wisbon <ian.wisbon@timesys.com>2011-02-15 15:53:51 -0500
committerIan Wisbon <ian.wisbon@timesys.com>2011-02-15 15:53:51 -0500
commitdfdbf3f6e2d279f2a46ed95614cb4bf07657394d (patch)
tree2cc05669c5d3e47f7d4b28e31076b6dc6e771f36 /drivers/net
parenteffff5718c380983788fe6c380671c18e15ac7c2 (diff)
Digi del-5.6 Complete2.6.31-digi-201102151558
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/Kconfig7
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/acenic.c3
-rw-r--r--drivers/net/appletalk/ipddp.c3
-rw-r--r--drivers/net/au1000_eth.c15
-rw-r--r--drivers/net/b44.c6
-rw-r--r--drivers/net/bonding/bond_main.c10
-rw-r--r--drivers/net/can/Kconfig4
-rw-r--r--drivers/net/can/flexcan/dev.c112
-rw-r--r--drivers/net/can/flexcan/flexcan.h31
-rw-r--r--drivers/net/can/flexcan/mbm.c74
-rw-r--r--drivers/net/can/vcan.c2
-rw-r--r--drivers/net/e100.c19
-rw-r--r--drivers/net/e1000e/82571.c4
-rw-r--r--drivers/net/enc28j60.c18
-rw-r--r--drivers/net/fec.c17
-rw-r--r--drivers/net/fec_1588.c65
-rw-r--r--drivers/net/fec_1588.h6
-rw-r--r--drivers/net/fec_switch.c4238
-rw-r--r--drivers/net/fec_switch.h1121
-rw-r--r--drivers/net/iseries_veth.c2
-rw-r--r--drivers/net/mlx4/eq.c42
-rw-r--r--drivers/net/mlx4/main.c9
-rw-r--r--drivers/net/mlx4/mlx4.h7
-rw-r--r--drivers/net/phy/mdio_bus.c72
-rw-r--r--drivers/net/phy/phy.c4
-rw-r--r--drivers/net/phy/phy_device.c31
-rw-r--r--drivers/net/sfc/rx.c9
-rw-r--r--drivers/net/sfc/tx.c4
-rw-r--r--drivers/net/sky2.c6
-rw-r--r--drivers/net/smc91x.c2
-rw-r--r--drivers/net/smsc911x.c5
-rw-r--r--drivers/net/smsc9420.c14
-rw-r--r--drivers/net/tun.c4
-rw-r--r--drivers/net/usb/hso.c4
-rw-r--r--drivers/net/usb/kaweth.c18
-rw-r--r--drivers/net/usb/rtl8150.c2
-rw-r--r--drivers/net/usb/smsc95xx.c2
-rw-r--r--drivers/net/usb/usbnet.c2
-rw-r--r--drivers/net/wireless/airo.c34
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h1
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c57
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.c33
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.h8
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c26
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c155
-rw-r--r--drivers/net/wireless/ath6kl/os/linux/ar6000_android.c2
-rw-r--r--drivers/net/wireless/b43/b43.h1
-rw-r--r--drivers/net/wireless/b43/dma.c36
-rw-r--r--drivers/net/wireless/b43/main.c13
-rw-r--r--drivers/net/wireless/b43/rfkill.c3
-rw-r--r--drivers/net/wireless/b43legacy/rfkill.c7
-rw-r--r--drivers/net/wireless/hostap/hostap_main.c3
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.c11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c40
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c39
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c58
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c29
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c9
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c67
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h18
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h43
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.c184
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.h10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c34
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c78
-rw-r--r--drivers/net/wireless/libertas/if_usb.c2
-rw-r--r--drivers/net/wireless/libertas/wext.c2
-rw-r--r--drivers/net/wireless/p54/p54usb.c11
-rw-r--r--drivers/net/wireless/ray_cs.c2
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187_leds.c4
77 files changed, 6570 insertions, 474 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index bd5d0e026b02..28318f4236b1 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1885,6 +1885,13 @@ config FEC_1588
bool "Enable FEC 1588 timestamping"
depends on FEC
+config FEC_L2SWITCH
+ bool "L2 Switch Ethernet Controller (of ColdFire CPUs)"
+ depends on ARCH_MX28 && !FEC
+ help
+ Say Y here if you want to use the built-in 10/100 Ethernet Switch
+ Controller on some Motorola ColdFire processors.
+
config FEC2
bool "Second FEC ethernet controller (on some ColdFire CPUs)"
depends on FEC
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index f3c89fb1b799..11bb1b5623bf 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -115,6 +115,7 @@ obj-$(CONFIG_HP100) += hp100.o
obj-$(CONFIG_SMC9194) += smc9194.o
obj-$(CONFIG_FEC) += fec.o
obj-$(CONFIG_FEC_1588) += fec_1588.o
+obj-$(CONFIG_FEC_L2SWITCH) += fec_switch.o
obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index 08419ee10290..12bfc447a896 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -1209,7 +1209,8 @@ static int __devinit ace_init(struct net_device *dev)
memset(ap->info, 0, sizeof(struct ace_info));
memset(ap->skb, 0, sizeof(struct ace_skb));
- if (ace_load_firmware(dev))
+ ecode = ace_load_firmware(dev);
+ if (ecode)
goto init_error;
ap->fw_running = 0;
diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
index 78cea5e80b1d..bf9ab65d27a4 100644
--- a/drivers/net/appletalk/ipddp.c
+++ b/drivers/net/appletalk/ipddp.c
@@ -176,8 +176,7 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
- if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0)
- dev_kfree_skb(skb);
+ aarp_send_ddp(rt->dev, skb, &rt->at, NULL);
spin_unlock(&ipddp_route_lock);
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index d3c734f4d679..2f6ae784a36f 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -1089,7 +1089,14 @@ static struct net_device * au1000_probe(int port_num)
return NULL;
}
- if ((err = register_netdev(dev)) != 0) {
+ dev->base_addr = base;
+ dev->irq = irq;
+ dev->netdev_ops = &au1000_netdev_ops;
+ SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops);
+ dev->watchdog_timeo = ETH_TX_TIMEOUT;
+
+ err = register_netdev(dev);
+ if (err != 0) {
printk(KERN_ERR "%s: Cannot register net device, error %d\n",
DRV_NAME, err);
free_netdev(dev);
@@ -1207,12 +1214,6 @@ static struct net_device * au1000_probe(int port_num)
aup->tx_db_inuse[i] = pDB;
}
- dev->base_addr = base;
- dev->irq = irq;
- dev->netdev_ops = &au1000_netdev_ops;
- SET_ETHTOOL_OPS(dev, &au1000_ethtool_ops);
- dev->watchdog_timeo = ETH_TX_TIMEOUT;
-
/*
* The boot code uses the ethernet controller, so reset it to start
* fresh. au1000_init() expects that the device is in reset state.
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index bafca672ea7d..351a258dccd6 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -913,9 +913,6 @@ static irqreturn_t b44_interrupt(int irq, void *dev_id)
bp->istat = istat;
__b44_disable_ints(bp);
__napi_schedule(&bp->napi);
- } else {
- printk(KERN_ERR PFX "%s: Error, poll already scheduled\n",
- dev->name);
}
irq_ack:
@@ -1505,8 +1502,7 @@ static int b44_magic_pattern(u8 *macaddr, u8 *ppattern, u8 *pmask, int offset)
for (k = 0; k< ethaddr_bytes; k++) {
ppattern[offset + magicsync +
(j * ETH_ALEN) + k] = macaddr[k];
- len++;
- set_bit(len, (unsigned long *) pmask);
+ set_bit(len++, (unsigned long *) pmask);
}
}
return len - 1;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index aa1be1feceed..bcd8df92dec7 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -691,7 +691,7 @@ static int bond_check_dev_link(struct bonding *bond,
struct net_device *slave_dev, int reporting)
{
const struct net_device_ops *slave_ops = slave_dev->netdev_ops;
- static int (*ioctl)(struct net_device *, struct ifreq *, int);
+ int (*ioctl)(struct net_device *, struct ifreq *, int);
struct ifreq ifr;
struct mii_ioctl_data *mii;
@@ -3707,10 +3707,10 @@ static int bond_xmit_hash_policy_l23(struct sk_buff *skb,
if (skb->protocol == htons(ETH_P_IP)) {
return ((ntohl(iph->saddr ^ iph->daddr) & 0xffff) ^
- (data->h_dest[5] ^ bond_dev->dev_addr[5])) % count;
+ (data->h_dest[5] ^ data->h_source[5])) % count;
}
- return (data->h_dest[5] ^ bond_dev->dev_addr[5]) % count;
+ return (data->h_dest[5] ^ data->h_source[5]) % count;
}
/*
@@ -3737,7 +3737,7 @@ static int bond_xmit_hash_policy_l34(struct sk_buff *skb,
}
- return (data->h_dest[5] ^ bond_dev->dev_addr[5]) % count;
+ return (data->h_dest[5] ^ data->h_source[5]) % count;
}
/*
@@ -3748,7 +3748,7 @@ static int bond_xmit_hash_policy_l2(struct sk_buff *skb,
{
struct ethhdr *data = (struct ethhdr *)skb->data;
- return (data->h_dest[5] ^ bond_dev->dev_addr[5]) % count;
+ return (data->h_dest[5] ^ data->h_source[5]) % count;
}
/*-------------------------- Device entry points ----------------------------*/
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index a6bf9a7fddd9..481990fd3f2b 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -86,8 +86,8 @@ config CAN_DEBUG_DEVICES
config CAN_FLEXCAN
tristate "Freescale FlexCAN"
- depends on CAN && (ARCH_MX25 || ARCH_MX35 || ARCH_MX28)
- default m
+ depends on CAN && (ARCH_MX25 || ARCH_MX35 || ARCH_MX28 || ARCH_MX53)
+ default y
---help---
This select the support of Freescale CAN(FlexCAN).
This driver can also be built as a module.
diff --git a/drivers/net/can/flexcan/dev.c b/drivers/net/can/flexcan/dev.c
index 389f85d75709..404877c33eab 100644
--- a/drivers/net/can/flexcan/dev.c
+++ b/drivers/net/can/flexcan/dev.c
@@ -35,6 +35,74 @@
#endif
#include "flexcan.h"
+#define DEFAULT_BITRATE 500000
+#define TIME_SEGMENT_MIN 8
+#define TIME_SEGMENT_MAX 25
+#define TIME_SEGMENT_MID ((TIME_SEGMENT_MIN + TIME_SEGMENT_MAX)/2)
+
+struct time_segment {
+ char propseg;
+ char pseg1;
+ char pseg2;
+};
+
+struct time_segment time_segments[] = {
+ { /* total 8 timequanta */
+ 1, 2, 1
+ },
+ { /* total 9 timequanta */
+ 1, 2, 2
+ },
+ { /* total 10 timequanta */
+ 2, 2, 2
+ },
+ { /* total 11 timequanta */
+ 2, 2, 3
+ },
+ { /* total 12 timequanta */
+ 2, 3, 3
+ },
+ { /* total 13 timequanta */
+ 3, 3, 3
+ },
+ { /* total 14 timequanta */
+ 3, 3, 4
+ },
+ { /* total 15 timequanta */
+ 3, 4, 4
+ },
+ { /* total 16 timequanta */
+ 4, 4, 4
+ },
+ { /* total 17 timequanta */
+ 4, 4, 5
+ },
+ { /* total 18 timequanta */
+ 4, 5, 5
+ },
+ { /* total 19 timequanta */
+ 5, 5, 5
+ },
+ { /* total 20 timequanta */
+ 5, 5, 6
+ },
+ { /* total 21 timequanta */
+ 5, 6, 6
+ },
+ { /* total 22 timequanta */
+ 6, 6, 6
+ },
+ { /* total 23 timequanta */
+ 6, 6, 7
+ },
+ { /* total 24 timequanta */
+ 6, 7, 7
+ },
+ { /* total 25 timequanta */
+ 7, 7, 7
+ },
+};
+
enum {
FLEXCAN_ATTR_STATE = 0,
FLEXCAN_ATTR_BITRATE,
@@ -138,6 +206,45 @@ static void flexcan_set_bitrate(struct flexcan_device *flexcan, int bitrate)
* based on the bitrate to get the timing of
* presdiv, pseg1, pseg2, propseg
*/
+ int i, rate, div;
+ bool found = false;
+ struct time_segment *segment;
+ rate = clk_get_rate(flexcan->clk);
+
+ if (!bitrate)
+ bitrate = DEFAULT_BITRATE;
+
+ if (rate % bitrate == 0) {
+ div = rate / bitrate;
+ for (i = TIME_SEGMENT_MID; i <= TIME_SEGMENT_MAX; i++) {
+ if (div % i == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ for (i = TIME_SEGMENT_MID - 1;
+ i >= TIME_SEGMENT_MIN; i--) {
+ if (div % i == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ }
+ }
+
+ if (found) {
+ segment = &time_segments[i - TIME_SEGMENT_MIN];
+ flexcan->br_presdiv = div/i - 1;
+ flexcan->br_propseg = segment->propseg;
+ flexcan->br_pseg1 = segment->pseg1;
+ flexcan->br_pseg2 = segment->pseg2;
+ flexcan->bitrate = bitrate;
+ } else {
+ pr_info("The bitrate %d can't supported with clock \
+ rate of %d \n", bitrate, rate);
+ }
}
static void flexcan_update_bitrate(struct flexcan_device *flexcan)
@@ -201,7 +308,7 @@ static int flexcan_dump_xmit_mb(struct flexcan_device *flexcan, char *buf)
ret +=
sprintf(buf + ret,
"mb[%d]::CS:0x%x ID:0x%x DATA[1~2]:0x%02x,0x%02x\n",
- i, flexcan->hwmb[i].mb_cs.data,
+ i, flexcan->hwmb[i].mb_cs,
flexcan->hwmb[i].mb_id, flexcan->hwmb[i].mb_data[1],
flexcan->hwmb[i].mb_data[2]);
return ret;
@@ -214,7 +321,7 @@ static int flexcan_dump_rx_mb(struct flexcan_device *flexcan, char *buf)
ret +=
sprintf(buf + ret,
"mb[%d]::CS:0x%x ID:0x%x DATA[1~2]:0x%02x,0x%02x\n",
- i, flexcan->hwmb[i].mb_cs.data,
+ i, flexcan->hwmb[i].mb_cs,
flexcan->hwmb[i].mb_id, flexcan->hwmb[i].mb_data[1],
flexcan->hwmb[i].mb_data[2]);
return ret;
@@ -575,6 +682,7 @@ struct net_device *flexcan_device_alloc(struct platform_device *pdev,
return NULL;
}
flexcan_device_default(flexcan);
+ flexcan_set_bitrate(flexcan, flexcan->bitrate);
flexcan_update_bitrate(flexcan);
num = ARRAY_SIZE(flexcan_dev_attr);
diff --git a/drivers/net/can/flexcan/flexcan.h b/drivers/net/can/flexcan/flexcan.h
index d19cc1ee0620..51a800bd8e55 100644
--- a/drivers/net/can/flexcan/flexcan.h
+++ b/drivers/net/can/flexcan/flexcan.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -32,17 +32,6 @@
#define FLEXCAN_DEVICE_NAME "FlexCAN"
-struct can_mb_cs {
- unsigned int time_stamp:16;
- unsigned int length:4;
- unsigned int rtr:1;
- unsigned int ide:1;
- unsigned int srr:1;
- unsigned int nouse1:1;
- unsigned int code:4;
- unsigned int nouse2:4;
-};
-
#define CAN_MB_RX_INACTIVE 0x0
#define CAN_MB_RX_EMPTY 0x4
#define CAN_MB_RX_FULL 0x2
@@ -55,14 +44,24 @@ struct can_mb_cs {
#define CAN_MB_TX_REMOTE 0xA
struct can_hw_mb {
- union {
- struct can_mb_cs cs;
- unsigned int data;
- } mb_cs;
+ unsigned int mb_cs;
unsigned int mb_id;
unsigned char mb_data[8];
};
+#define MB_CS_CODE_OFFSET 24
+#define MB_CS_CODE_MASK (0xF << MB_CS_CODE_OFFSET)
+#define MB_CS_SRR_OFFSET 22
+#define MB_CS_SRR_MASK (0x1 << MB_CS_SRR_OFFSET)
+#define MB_CS_IDE_OFFSET 21
+#define MB_CS_IDE_MASK (0x1 << MB_CS_IDE_OFFSET)
+#define MB_CS_RTR_OFFSET 20
+#define MB_CS_RTR_MASK (0x1 << MB_CS_RTR_OFFSET)
+#define MB_CS_LENGTH_OFFSET 16
+#define MB_CS_LENGTH_MASK (0xF << MB_CS_LENGTH_OFFSET)
+#define MB_CS_TIMESTAMP_OFFSET 0
+#define MB_CS_TIMESTAMP_MASK (0xFF << MB_CS_TIMESTAMP_OFFSET)
+
#define CAN_HW_REG_MCR 0x00
#define CAN_HW_REG_CTRL 0x04
#define CAN_HW_REG_TIMER 0x08
diff --git a/drivers/net/can/flexcan/mbm.c b/drivers/net/can/flexcan/mbm.c
index b0341ba9128e..42266e719ce3 100644
--- a/drivers/net/can/flexcan/mbm.c
+++ b/drivers/net/can/flexcan/mbm.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -55,10 +55,13 @@ static void flexcan_mb_bottom(struct net_device *dev, int index)
hwmb = flexcan->hwmb + index;
if (flexcan->fifo || (index >= (flexcan->maxmb - flexcan->xmit_maxmb))) {
- if (hwmb->mb_cs.cs.code == CAN_MB_TX_ABORT)
- hwmb->mb_cs.cs.code = CAN_MB_TX_INACTIVE;
+ if ((hwmb->mb_cs & MB_CS_CODE_MASK) >> MB_CS_CODE_OFFSET ==
+ CAN_MB_TX_ABORT) {
+ hwmb->mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb->mb_cs |= CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET;
+ }
- if (hwmb->mb_cs.cs.code & CAN_MB_TX_INACTIVE) {
+ if (hwmb->mb_cs & (CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET)) {
if (netif_queue_stopped(dev))
netif_start_queue(dev);
return;
@@ -68,16 +71,17 @@ static void flexcan_mb_bottom(struct net_device *dev, int index)
if (skb) {
frame = (struct can_frame *)skb_put(skb, sizeof(*frame));
memset(frame, 0, sizeof(*frame));
- if (hwmb->mb_cs.cs.ide)
+ if (hwmb->mb_cs & MB_CS_IDE_MASK)
frame->can_id =
(hwmb->mb_id & CAN_EFF_MASK) | CAN_EFF_FLAG;
else
frame->can_id = (hwmb->mb_id >> 18) & CAN_SFF_MASK;
- if (hwmb->mb_cs.cs.rtr)
+ if (hwmb->mb_cs & MB_CS_RTR_MASK)
frame->can_id |= CAN_RTR_FLAG;
- frame->can_dlc = hwmb->mb_cs.cs.length;
+ frame->can_dlc =
+ (hwmb->mb_cs & MB_CS_LENGTH_MASK) >> MB_CS_LENGTH_OFFSET;
if (frame->can_dlc && frame->can_dlc)
flexcan_memcpy(frame->data, hwmb->mb_data,
@@ -85,7 +89,8 @@ static void flexcan_mb_bottom(struct net_device *dev, int index)
if (flexcan->fifo
|| (index >= (flexcan->maxmb - flexcan->xmit_maxmb))) {
- hwmb->mb_cs.cs.code = CAN_MB_TX_INACTIVE;
+ hwmb->mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb->mb_cs |= CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET;
if (netif_queue_stopped(dev))
netif_start_queue(dev);
}
@@ -101,13 +106,13 @@ static void flexcan_mb_bottom(struct net_device *dev, int index)
skb->ip_summed = CHECKSUM_UNNECESSARY;
netif_rx(skb);
} else {
- tmp = hwmb->mb_cs.data;
+ tmp = hwmb->mb_cs;
tmp = hwmb->mb_id;
tmp = hwmb->mb_data[0];
if (flexcan->fifo
|| (index >= (flexcan->maxmb - flexcan->xmit_maxmb))) {
-
- hwmb->mb_cs.cs.code = CAN_MB_TX_INACTIVE;
+ hwmb->mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb->mb_cs |= CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET;
if (netif_queue_stopped(dev))
netif_start_queue(dev);
}
@@ -131,17 +136,19 @@ static void flexcan_fifo_isr(struct net_device *dev, unsigned int iflag1)
frame =
(struct can_frame *)skb_put(skb, sizeof(*frame));
memset(frame, 0, sizeof(*frame));
- if (hwmb->mb_cs.cs.ide)
+ if (hwmb->mb_cs & MB_CS_IDE_MASK)
frame->can_id =
(hwmb->mb_id & CAN_EFF_MASK) | CAN_EFF_FLAG;
else
frame->can_id =
(hwmb->mb_id >> 18) & CAN_SFF_MASK;
- if (hwmb->mb_cs.cs.rtr)
+ if (hwmb->mb_cs & MB_CS_RTR_MASK)
frame->can_id |= CAN_RTR_FLAG;
- frame->can_dlc = hwmb->mb_cs.cs.length;
+ frame->can_dlc =
+ (hwmb->mb_cs & MB_CS_LENGTH_MASK) >>
+ MB_CS_LENGTH_OFFSET;
if (frame->can_dlc && (frame->can_dlc <= 8))
flexcan_memcpy(frame->data, hwmb->mb_data,
@@ -158,7 +165,7 @@ static void flexcan_fifo_isr(struct net_device *dev, unsigned int iflag1)
skb->ip_summed = CHECKSUM_UNNECESSARY;
netif_rx(skb);
} else {
- tmp = hwmb->mb_cs.data;
+ tmp = hwmb->mb_cs;
tmp = hwmb->mb_id;
tmp = hwmb->mb_data[0];
tmp = __raw_readl(flexcan->io_base + CAN_HW_REG_TIMER);
@@ -252,7 +259,8 @@ int flexcan_mbm_xmit(struct flexcan_device *flexcan, struct can_frame *frame)
struct can_hw_mb *hwmb = flexcan->hwmb;
do {
- if (hwmb[i].mb_cs.cs.code == CAN_MB_TX_INACTIVE)
+ if ((hwmb[i].mb_cs & MB_CS_CODE_MASK) >> MB_CS_CODE_OFFSET ==
+ CAN_MB_TX_INACTIVE)
break;
if ((++i) > flexcan->maxmb) {
if (flexcan->fifo)
@@ -273,22 +281,24 @@ int flexcan_mbm_xmit(struct flexcan_device *flexcan, struct can_frame *frame)
}
if (frame->can_id & CAN_RTR_FLAG)
- hwmb[i].mb_cs.cs.rtr = 1;
+ hwmb[i].mb_cs |= 1 << MB_CS_RTR_OFFSET;
else
- hwmb[i].mb_cs.cs.rtr = 0;
+ hwmb[i].mb_cs &= ~MB_CS_RTR_MASK;
if (frame->can_id & CAN_EFF_FLAG) {
- hwmb[i].mb_cs.cs.ide = 1;
- hwmb[i].mb_cs.cs.srr = 1;
+ hwmb[i].mb_cs |= 1 << MB_CS_IDE_OFFSET;
+ hwmb[i].mb_cs |= 1 << MB_CS_SRR_OFFSET;
hwmb[i].mb_id = frame->can_id & CAN_EFF_MASK;
} else {
- hwmb[i].mb_cs.cs.ide = 0;
+ hwmb[i].mb_cs &= ~MB_CS_IDE_MASK;
hwmb[i].mb_id = (frame->can_id & CAN_SFF_MASK) << 18;
}
- hwmb[i].mb_cs.cs.length = frame->can_dlc;
+ hwmb[i].mb_cs &= MB_CS_LENGTH_MASK;
+ hwmb[i].mb_cs |= frame->can_dlc << MB_CS_LENGTH_OFFSET;
flexcan_memcpy(hwmb[i].mb_data, frame->data, frame->can_dlc);
- hwmb[i].mb_cs.cs.code = CAN_MB_TX_ONCE;
+ hwmb[i].mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb[i].mb_cs |= CAN_MB_TX_ONCE << MB_CS_CODE_OFFSET;
return 0;
}
@@ -325,23 +335,27 @@ void flexcan_mbm_init(struct flexcan_device *flexcan)
id_table[i] = 0;
} else {
for (i = 0; i < rx_mb; i++) {
- hwmb[i].mb_cs.cs.code = CAN_MB_RX_EMPTY;
+ hwmb[i].mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb[i].mb_cs |= CAN_MB_RX_EMPTY << MB_CS_CODE_OFFSET;
/*
* IDE bit can not control by mask registers
* So set message buffer to receive extend
* or standard message.
*/
- if (flexcan->ext_msg && flexcan->std_msg)
- hwmb[i].mb_cs.cs.ide = i & 1;
- else {
+ if (flexcan->ext_msg && flexcan->std_msg) {
+ hwmb[i].mb_cs &= ~MB_CS_IDE_MASK;
+ hwmb[i].mb_cs |= (i & 1) << MB_CS_IDE_OFFSET;
+ } else {
if (flexcan->ext_msg)
- hwmb[i].mb_cs.cs.ide = 1;
+ hwmb[i].mb_cs |= 1 << MB_CS_IDE_OFFSET;
}
}
}
- for (; i <= flexcan->maxmb; i++)
- hwmb[i].mb_cs.cs.code = CAN_MB_TX_INACTIVE;
+ for (; i <= flexcan->maxmb; i++) {
+ hwmb[i].mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb[i].mb_cs |= CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET;
+ }
flexcan->xmit_mb = rx_mb;
}
diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c
index a10c1d7b3b0a..460bb886fbdf 100644
--- a/drivers/net/can/vcan.c
+++ b/drivers/net/can/vcan.c
@@ -80,7 +80,7 @@ static void vcan_rx(struct sk_buff *skb, struct net_device *dev)
skb->dev = dev;
skb->ip_summed = CHECKSUM_UNNECESSARY;
- netif_rx(skb);
+ netif_rx_ni(skb);
}
static int vcan_tx(struct sk_buff *skb, struct net_device *dev)
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 3a6735dc9f6a..c786e6a96eae 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -156,6 +156,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/mii.h>
@@ -601,6 +602,7 @@ struct nic {
struct mem *mem;
dma_addr_t dma_addr;
+ struct pci_pool *cbs_pool;
dma_addr_t cbs_dma_addr;
u8 adaptive_ifs;
u8 tx_threshold;
@@ -1779,9 +1781,7 @@ static void e100_clean_cbs(struct nic *nic)
nic->cb_to_clean = nic->cb_to_clean->next;
nic->cbs_avail++;
}
- pci_free_consistent(nic->pdev,
- sizeof(struct cb) * nic->params.cbs.count,
- nic->cbs, nic->cbs_dma_addr);
+ pci_pool_free(nic->cbs_pool, nic->cbs, nic->cbs_dma_addr);
nic->cbs = NULL;
nic->cbs_avail = 0;
}
@@ -1799,10 +1799,11 @@ static int e100_alloc_cbs(struct nic *nic)
nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = NULL;
nic->cbs_avail = 0;
- nic->cbs = pci_alloc_consistent(nic->pdev,
- sizeof(struct cb) * count, &nic->cbs_dma_addr);
+ nic->cbs = pci_pool_alloc(nic->cbs_pool, GFP_KERNEL,
+ &nic->cbs_dma_addr);
if (!nic->cbs)
return -ENOMEM;
+ memset(nic->cbs, 0, count * sizeof(struct cb));
for (cb = nic->cbs, i = 0; i < count; cb++, i++) {
cb->next = (i + 1 < count) ? cb + 1 : nic->cbs;
@@ -1811,7 +1812,6 @@ static int e100_alloc_cbs(struct nic *nic)
cb->dma_addr = nic->cbs_dma_addr + i * sizeof(struct cb);
cb->link = cpu_to_le32(nic->cbs_dma_addr +
((i+1) % count) * sizeof(struct cb));
- cb->skb = NULL;
}
nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = nic->cbs;
@@ -2827,7 +2827,11 @@ static int __devinit e100_probe(struct pci_dev *pdev,
DPRINTK(PROBE, ERR, "Cannot register net device, aborting.\n");
goto err_out_free;
}
-
+ nic->cbs_pool = pci_pool_create(netdev->name,
+ nic->pdev,
+ nic->params.cbs.count * sizeof(struct cb),
+ sizeof(u32),
+ 0);
DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %pM\n",
(unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0),
pdev->irq, netdev->dev_addr);
@@ -2857,6 +2861,7 @@ static void __devexit e100_remove(struct pci_dev *pdev)
unregister_netdev(netdev);
e100_free(nic);
pci_iounmap(pdev, nic->csr);
+ pci_pool_destroy(nic->cbs_pool);
free_netdev(netdev);
pci_release_regions(pdev);
pci_disable_device(pdev);
diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c
index b53b40ba88a8..d1e0563a67df 100644
--- a/drivers/net/e1000e/82571.c
+++ b/drivers/net/e1000e/82571.c
@@ -1803,7 +1803,7 @@ struct e1000_info e1000_82574_info = {
| FLAG_HAS_AMT
| FLAG_HAS_CTRLEXT_ON_LOAD,
.pba = 20,
- .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN,
+ .max_hw_frame_size = DEFAULT_JUMBO,
.get_variants = e1000_get_variants_82571,
.mac_ops = &e82571_mac_ops,
.phy_ops = &e82_phy_ops_bm,
@@ -1820,7 +1820,7 @@ struct e1000_info e1000_82583_info = {
| FLAG_HAS_AMT
| FLAG_HAS_CTRLEXT_ON_LOAD,
.pba = 20,
- .max_hw_frame_size = DEFAULT_JUMBO,
+ .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN,
.get_variants = e1000_get_variants_82571,
.mac_ops = &e82571_mac_ops,
.phy_ops = &e82_phy_ops_bm,
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
index 582eb37390ed..8a34f4679fa5 100644
--- a/drivers/net/enc28j60.c
+++ b/drivers/net/enc28j60.c
@@ -30,8 +30,6 @@
#include <linux/delay.h>
#include <linux/spi/spi.h>
-#include <mach/platform.h>
-
#include "enc28j60_hw.h"
#define DRV_NAME "enc28j60"
@@ -53,9 +51,17 @@
#define MAX_TX_RETRYCOUNT 16
#ifdef CONFIG_ARCH_STMP3XXX
+#include <mach/platform.h>
#include <mach/stmp3xxx.h>
#include <mach/regs-ocotp.h>
#endif
+#ifdef CONFIG_ARCH_MXS
+#include <mach/system.h>
+#include <mach/hardware.h>
+#include <mach/regs-ocotp.h>
+#define REGS_OCOTP_BASE IO_ADDRESS(OCOTP_PHYS_ADDR)
+#endif
+
enum {
RXFILTER_NORMAL,
RXFILTER_MULTI,
@@ -104,12 +110,14 @@ static int enc28j60_get_mac(unsigned char *dev_addr, int idx)
return false;
if (!mac[idx]) {
-#ifdef CONFIG_ARCH_STMP3XXX
+#if defined(CONFIG_ARCH_STMP3XXX) || defined(CONFIG_ARCH_MXS)
if (get_evk_board_version() >= 1) {
int mac1 , mac2 , retry = 0;
- stmp3xxx_setl(BM_OCOTP_CTRL_RD_BANK_OPEN, REGS_OCOTP_BASE + HW_OCOTP_CTRL);
- while (__raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CTRL) & BM_OCOTP_CTRL_BUSY) {
+ __raw_writel(BM_OCOTP_CTRL_RD_BANK_OPEN,
+ REGS_OCOTP_BASE + HW_OCOTP_CTRL_SET);
+ while (__raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CTRL) &
+ BM_OCOTP_CTRL_BUSY) {
msleep(10);
retry++;
if (retry > 10)
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 46799e092bc1..d8817aad351f 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -1131,17 +1131,18 @@ fec_set_mac_address(struct net_device *dev, void *p)
{
struct fec_enet_private *fep = netdev_priv(dev);
struct sockaddr *addr = p;
+ u32 temp_mac[2];
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
- writel(dev->dev_addr[3] | (dev->dev_addr[2] << 8) |
- (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24),
- fep->hwp + FEC_ADDR_LOW);
- writel((dev->dev_addr[5] << 16) | (dev->dev_addr[4] << 24),
- fep + FEC_ADDR_HIGH);
+ memcpy(&temp_mac, dev->dev_addr, ETH_ALEN);
+
+ writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW);
+ writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH);
+
return 0;
}
@@ -1277,6 +1278,7 @@ fec_restart(struct net_device *dev, int duplex)
/* Clear any outstanding interrupt. */
writel(0xffc00000, fep->hwp + FEC_IEVENT);
+#if !defined(CONFIG_MACH_CCMX51JS) && !defined(CONFIG_MACH_CCWMX51JS)
/* Reset all multicast. */
writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
@@ -1284,6 +1286,7 @@ fec_restart(struct net_device *dev, int duplex)
writel(0, fep->hwp + FEC_HASH_TABLE_HIGH);
writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
#endif
+#endif /* !defined(CONFIG_MACH_CCMX51JS) && !defined(CONFIG_MACH_CCWMX51JS) */
#ifndef CONFIG_ARCH_MXS
if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) {
@@ -1499,10 +1502,10 @@ fec_probe(struct platform_device *pdev)
fep->mii_bus = fec_mii_bus;
}
- fep->ptp_priv = kmalloc(sizeof(struct fec_ptp_private), GFP_KERNEL);
+ fep->ptp_priv = kzalloc(sizeof(struct fec_ptp_private), GFP_KERNEL);
if (fep->ptp_priv) {
fep->ptp_priv->hwp = fep->hwp;
- ret = fec_ptp_init(fep->ptp_priv);
+ ret = fec_ptp_init(fep->ptp_priv, pdev->id);
if (ret)
printk(KERN_WARNING
"IEEE1588: ptp-timer is unavailable\n");
diff --git a/drivers/net/fec_1588.c b/drivers/net/fec_1588.c
index 5babcc29de78..37b1b01778fd 100644
--- a/drivers/net/fec_1588.c
+++ b/drivers/net/fec_1588.c
@@ -35,7 +35,7 @@
static DECLARE_WAIT_QUEUE_HEAD(ptp_rx_ts_wait);
#define PTP_GET_RX_TIMEOUT (HZ/10)
-static struct fec_ptp_private *ptp_private;
+static struct fec_ptp_private *ptp_private[2];
/* Alloc the ring resource */
static int fec_ptp_init_circ(struct circ_buf *ptp_buf)
@@ -88,14 +88,15 @@ static int fec_ptp_is_full(struct circ_buf *buf)
}
static int fec_ptp_insert(struct circ_buf *ptp_buf,
- struct fec_ptp_data_t *data)
+ struct fec_ptp_data_t *data,
+ struct fec_ptp_private *priv)
{
struct fec_ptp_data_t *tmp;
if (fec_ptp_is_full(ptp_buf))
return 1;
- spin_lock(&ptp_private->ptp_lock);
+ spin_lock(&priv->ptp_lock);
tmp = (struct fec_ptp_data_t *)(ptp_buf->buf) + ptp_buf->tail;
tmp->key = data->key;
@@ -104,13 +105,15 @@ static int fec_ptp_insert(struct circ_buf *ptp_buf,
ptp_buf->tail = fec_ptp_calc_index(DEFAULT_PTP_RX_BUF_SZ,
ptp_buf->tail, 1);
- spin_unlock(&ptp_private->ptp_lock);
+ spin_unlock(&priv->ptp_lock);
return 0;
}
static int fec_ptp_find_and_remove(struct circ_buf *ptp_buf,
- int key, struct fec_ptp_data_t *data)
+ int key,
+ struct fec_ptp_data_t *data,
+ struct fec_ptp_private *priv)
{
int i;
int size = DEFAULT_PTP_RX_BUF_SZ;
@@ -129,10 +132,10 @@ static int fec_ptp_find_and_remove(struct circ_buf *ptp_buf,
i = fec_ptp_calc_index(size, i, 1);
}
- spin_lock_irqsave(&ptp_private->ptp_lock, flags);
+ spin_lock_irqsave(&priv->ptp_lock, flags);
if (i == end) {
ptp_buf->head = end;
- spin_unlock_irqrestore(&ptp_private->ptp_lock, flags);
+ spin_unlock_irqrestore(&priv->ptp_lock, flags);
return 1;
}
@@ -140,7 +143,7 @@ static int fec_ptp_find_and_remove(struct circ_buf *ptp_buf,
data->ts_time.nsec = tmp->ts_time.nsec;
ptp_buf->head = fec_ptp_calc_index(size, i, 1);
- spin_unlock_irqrestore(&ptp_private->ptp_lock, flags);
+ spin_unlock_irqrestore(&priv->ptp_lock, flags);
return 0;
}
@@ -154,9 +157,9 @@ int fec_ptp_start(struct fec_ptp_private *priv)
writel(FEC_T_CTRL_RESTART, fpp->hwp + FEC_ATIME_CTRL);
writel(FEC_T_INC_40MHZ << FEC_T_INC_OFFSET, fpp->hwp + FEC_ATIME_INC);
writel(FEC_T_PERIOD_ONE_SEC, fpp->hwp + FEC_ATIME_EVT_PERIOD);
- writel(FEC_T_CTRL_PERIOD_RST, fpp->hwp + FEC_ATIME_CTRL);
/* start counter */
- writel(FEC_T_CTRL_ENABLE, fpp->hwp + FEC_ATIME_CTRL);
+ writel(FEC_T_CTRL_PERIOD_RST | FEC_T_CTRL_ENABLE,
+ fpp->hwp + FEC_ATIME_CTRL);
return 0;
}
@@ -190,12 +193,12 @@ static void fec_set_1588cnt(struct fec_ptp_private *priv,
u32 tempval;
unsigned long flags;
- spin_lock_irqsave(&ptp_private->cnt_lock, flags);
+ spin_lock_irqsave(&priv->cnt_lock, flags);
priv->prtc = fec_time->rtc_time.sec;
tempval = fec_time->rtc_time.nsec;
writel(tempval, priv->hwp + FEC_ATIME);
- spin_unlock_irqrestore(&ptp_private->cnt_lock, flags);
+ spin_unlock_irqrestore(&priv->cnt_lock, flags);
}
/* Set the BD to ptp */
@@ -207,11 +210,11 @@ int fec_ptp_do_txstamp(struct sk_buff *skb)
if (skb->len > 44) {
/* Check if port is 319 for PTP Event, and check for UDP */
iph = ip_hdr(skb);
- if (iph->protocol != FEC_PACKET_TYPE_UDP)
+ if (iph == NULL || iph->protocol != FEC_PACKET_TYPE_UDP)
return 0;
udph = udp_hdr(skb);
- if (udph->source == 319)
+ if (udph != NULL && udph->source == 319)
return 1;
}
@@ -257,11 +260,11 @@ void fec_ptp_store_rxstamp(struct fec_ptp_private *priv,
switch (control) {
case PTP_MSG_SYNC:
- fec_ptp_insert(&(priv->rx_time_sync), &tmp_rx_time);
+ fec_ptp_insert(&(priv->rx_time_sync), &tmp_rx_time, priv);
break;
case PTP_MSG_DEL_REQ:
- fec_ptp_insert(&(priv->rx_time_del_req), &tmp_rx_time);
+ fec_ptp_insert(&(priv->rx_time_del_req), &tmp_rx_time, priv);
break;
/* clear transportSpecific field*/
@@ -271,11 +274,11 @@ void fec_ptp_store_rxstamp(struct fec_ptp_private *priv,
switch (msg_type) {
case PTP_MSG_P_DEL_REQ:
fec_ptp_insert(&(priv->rx_time_pdel_req),
- &tmp_rx_time);
+ &tmp_rx_time, priv);
break;
case PTP_MSG_P_DEL_RESP:
fec_ptp_insert(&(priv->rx_time_pdel_resp),
- &tmp_rx_time);
+ &tmp_rx_time, priv);
break;
default:
break;
@@ -308,20 +311,20 @@ static uint8_t fec_get_rx_time(struct fec_ptp_private *priv,
switch (mode) {
case PTP_MSG_SYNC:
flag = fec_ptp_find_and_remove(&(priv->rx_time_sync),
- key, &tmp);
+ key, &tmp, priv);
break;
case PTP_MSG_DEL_REQ:
flag = fec_ptp_find_and_remove(&(priv->rx_time_del_req),
- key, &tmp);
+ key, &tmp, priv);
break;
case PTP_MSG_P_DEL_REQ:
flag = fec_ptp_find_and_remove(&(priv->rx_time_pdel_req),
- key, &tmp);
+ key, &tmp, priv);
break;
case PTP_MSG_P_DEL_RESP:
flag = fec_ptp_find_and_remove(&(priv->rx_time_pdel_resp),
- key, &tmp);
+ key, &tmp, priv);
break;
default:
@@ -341,19 +344,19 @@ static uint8_t fec_get_rx_time(struct fec_ptp_private *priv,
switch (mode) {
case PTP_MSG_SYNC:
flag = fec_ptp_find_and_remove(&(priv->rx_time_sync),
- key, &tmp);
+ key, &tmp, priv);
break;
case PTP_MSG_DEL_REQ:
flag = fec_ptp_find_and_remove(
- &(priv->rx_time_del_req), key, &tmp);
+ &(priv->rx_time_del_req), key, &tmp, priv);
break;
case PTP_MSG_P_DEL_REQ:
flag = fec_ptp_find_and_remove(
- &(priv->rx_time_pdel_req), key, &tmp);
+ &(priv->rx_time_pdel_req), key, &tmp, priv);
break;
case PTP_MSG_P_DEL_RESP:
flag = fec_ptp_find_and_remove(
- &(priv->rx_time_pdel_resp), key, &tmp);
+ &(priv->rx_time_pdel_resp), key, &tmp, priv);
break;
}
@@ -388,9 +391,10 @@ static int ptp_ioctl(
struct ptp_time rx_time, tx_time;
struct ptp_ts_data *p_ts;
struct fec_ptp_private *priv;
+ unsigned int minor = MINOR(inode->i_rdev);
int retval = 0;
- priv = (struct fec_ptp_private *) ptp_private;
+ priv = (struct fec_ptp_private *) ptp_private[minor];
switch (cmd) {
case PTP_GET_RX_TIMESTAMP:
p_ts = (struct ptp_ts_data *)arg;
@@ -466,7 +470,7 @@ static void ptp_free(void)
/*
* Resource required for accessing 1588 Timer Registers.
*/
-int fec_ptp_init(struct fec_ptp_private *priv)
+int fec_ptp_init(struct fec_ptp_private *priv, int id)
{
fec_ptp_init_circ(&(priv->rx_time_sync));
fec_ptp_init_circ(&(priv->rx_time_del_req));
@@ -475,8 +479,9 @@ int fec_ptp_init(struct fec_ptp_private *priv)
spin_lock_init(&priv->ptp_lock);
spin_lock_init(&priv->cnt_lock);
- ptp_private = priv;
- init_ptp();
+ ptp_private[id] = priv;
+ if (id == 0)
+ init_ptp();
return 0;
}
EXPORT_SYMBOL(fec_ptp_init);
diff --git a/drivers/net/fec_1588.h b/drivers/net/fec_1588.h
index 55b1a8c995bd..a503527eadbb 100644
--- a/drivers/net/fec_1588.h
+++ b/drivers/net/fec_1588.h
@@ -33,7 +33,7 @@
#define FEC_T_INC_MASK 0x0000007f
#define FEC_T_INC_OFFSET 0
-#define FEC_T_INC_40MHZ 20
+#define FEC_T_INC_40MHZ 25
#define FEC_T_PERIOD_ONE_SEC 0x3B9ACA00
@@ -124,7 +124,7 @@ struct fec_ptp_private {
};
#ifdef CONFIG_FEC_1588
-extern int fec_ptp_init(struct fec_ptp_private *priv);
+extern int fec_ptp_init(struct fec_ptp_private *priv, int id);
extern void fec_ptp_cleanup(struct fec_ptp_private *priv);
extern int fec_ptp_start(struct fec_ptp_private *priv);
extern void fec_ptp_stop(struct fec_ptp_private *priv);
@@ -134,7 +134,7 @@ extern void fec_ptp_store_rxstamp(struct fec_ptp_private *priv,
struct sk_buff *skb,
struct bufdesc *bdp);
#else
-static inline int fec_ptp_init(struct fec_ptp_private *priv)
+static inline int fec_ptp_init(struct fec_ptp_private *priv, int id)
{
return 1;
}
diff --git a/drivers/net/fec_switch.c b/drivers/net/fec_switch.c
new file mode 100644
index 000000000000..f2c78e439278
--- /dev/null
+++ b/drivers/net/fec_switch.c
@@ -0,0 +1,4238 @@
+/*
+ * L2 switch Controller (Etheren switch) driver for Mx28.
+ *
+ * Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Shrek Wu (B16972@freescale.com)
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.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/workqueue.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
+#include <linux/fec.h>
+#include <linux/phy.h>
+
+#include <asm/irq.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <asm/pgtable.h>
+#include <asm/cacheflush.h>
+
+#include "fec_switch.h"
+
+#define SWITCH_MAX_PORTS 1
+
+#if defined(CONFIG_ARCH_MXC) || defined(CONFIG_ARCH_MXS)
+#include <mach/hardware.h>
+#define FEC_ALIGNMENT 0xf
+#else
+#define FEC_ALIGNMENT 0x3
+#endif
+
+/* The number of Tx and Rx buffers. These are allocated from the page
+ * pool. The code may assume these are power of two, so it it best
+ * to keep them that size.
+ * We don't need to allocate pages for the transmitter. We just use
+ * the skbuffer directly.
+ */
+#define FEC_ENET_RX_PAGES 8
+#define FEC_ENET_RX_FRSIZE 2048
+#define FEC_ENET_RX_FRPPG (PAGE_SIZE / FEC_ENET_RX_FRSIZE)
+#define FEC_ENET_TX_FRSIZE 2048
+#define FEC_ENET_TX_FRPPG (PAGE_SIZE / FEC_ENET_TX_FRSIZE)
+#define TX_RING_SIZE 16 /* Must be power of two */
+#define TX_RING_MOD_MASK 15 /* for this to work */
+
+#if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE)
+#error "FEC: descriptor ring size constants too large"
+#endif
+
+/* Interrupt events/masks */
+#define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */
+#define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */
+#define FEC_ENET_BABT ((uint)0x20000000) /* Babbling transmitter */
+#define FEC_ENET_GRA ((uint)0x10000000) /* Graceful stop complete */
+#define FEC_ENET_TXF ((uint)0x08000000) /* Full frame transmitted */
+#define FEC_ENET_TXB ((uint)0x04000000) /* A buffer was transmitted */
+#define FEC_ENET_RXF ((uint)0x02000000) /* Full frame received */
+#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */
+#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */
+#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */
+
+/* FEC MII MMFR bits definition */
+#define FEC_MMFR_ST (1 << 30)
+#define FEC_MMFR_OP_READ (2 << 28)
+#define FEC_MMFR_OP_WRITE (1 << 28)
+#define FEC_MMFR_PA(v) ((v & 0x1f) << 23)
+#define FEC_MMFR_RA(v) ((v & 0x1f) << 18)
+#define FEC_MMFR_TA (2 << 16)
+#define FEC_MMFR_DATA(v) (v & 0xffff)
+
+#ifdef FEC_PHY
+static struct phy_device *g_phy_dev;
+static struct mii_bus *fec_mii_bus;
+#endif
+
+static int switch_enet_open(struct net_device *dev);
+static int switch_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static irqreturn_t switch_enet_interrupt(int irq, void *dev_id);
+static void switch_enet_tx(struct net_device *dev);
+static void switch_enet_rx(struct net_device *dev);
+static int switch_enet_close(struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
+static void switch_restart(struct net_device *dev, int duplex);
+static void switch_stop(struct net_device *dev);
+
+#define NMII 20
+
+/* Make MII read/write commands for the FEC */
+#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18))
+#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | \
+ (VAL & 0xffff))
+
+/* Transmitter timeout */
+#define TX_TIMEOUT (2*HZ)
+#define FEC_MII_TIMEOUT 10
+
+#ifdef CONFIG_ARCH_MXS
+static void *swap_buffer(void *bufaddr, int len)
+{
+ int i;
+ unsigned int *buf = bufaddr;
+
+ for (i = 0; i < (len + 3) / 4; i++, buf++)
+ *buf = __swab32(*buf);
+
+ return bufaddr;
+}
+#endif
+
+/*last read entry from learning interface*/
+struct eswPortInfo g_info;
+
+static unsigned char switch_mac_default[] = {
+ 0x00, 0x08, 0x02, 0x6B, 0xA3, 0x1A,
+};
+
+static void switch_request_intrs(struct net_device *dev,
+ irqreturn_t switch_net_irq_handler(int irq, void *private),
+ void *irq_privatedata)
+{
+ struct switch_enet_private *fep;
+
+ fep = netdev_priv(dev);
+
+ /* Setup interrupt handlers */
+ if (request_irq(dev->irq,
+ switch_net_irq_handler, IRQF_DISABLED,
+ "mxs-l2switch", irq_privatedata) != 0)
+ printk(KERN_ERR "FEC: Could not alloc %s IRQ(%d)!\n",
+ dev->name, dev->irq);
+}
+
+static void switch_set_mii(struct net_device *dev)
+{
+ struct switch_enet_private *fep = netdev_priv(dev);
+ struct switch_t *fecp;
+
+ fecp = (struct switch_t *)fep->hwp;
+
+ writel(MCF_FEC_RCR_PROM | MCF_FEC_RCR_RMII_MODE |
+ MCF_FEC_RCR_MAX_FL(1522),
+ fep->enet_addr + MCF_FEC_RCR0);
+ writel(MCF_FEC_RCR_PROM | MCF_FEC_RCR_RMII_MODE |
+ MCF_FEC_RCR_MAX_FL(1522),
+ fep->enet_addr + MCF_FEC_RCR1);
+ /* TCR */
+ writel(MCF_FEC_TCR_FDEN, fep->enet_addr + MCF_FEC_TCR0);
+ writel(MCF_FEC_TCR_FDEN, fep->enet_addr + MCF_FEC_TCR1);
+
+ /* ECR */
+#ifdef L2SWITCH_ENHANCED_BUFFER
+ writel(MCF_FEC_ECR_ETHER_EN | MCF_FEC_ECR_ENA_1588,
+ fep->enet_addr + MCF_FEC_ECR0);
+ writel(MCF_FEC_ECR_ETHER_EN | MCF_FEC_ECR_ENA_1588,
+ fep->enet_addr + MCF_FEC_ECR1);
+#else /*legac buffer*/
+ writel(MCF_FEC_ECR_ETHER_EN, fep->enet_addr + MCF_FEC_ECR0);
+ writel(MCF_FEC_ECR_ETHER_EN, fep->enet_addr + MCF_FEC_ECR1);
+#endif
+ writel(FEC_ENET_TXF | FEC_ENET_RXF, fep->enet_addr + MCF_FEC_EIMR0);
+ writel(FEC_ENET_TXF | FEC_ENET_RXF, fep->enet_addr + MCF_FEC_EIMR1);
+
+ /*
+ * Set MII speed to 2.5 MHz
+ */
+ writel(DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000) << 1,
+ fep->enet_addr + MCF_FEC_MSCR0);
+ writel(DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000) << 1,
+ fep->enet_addr + MCF_FEC_MSCR1);
+
+#ifdef CONFIG_ARCH_MXS
+ /* Can't get phy(8720) ID when set to 2.5M on MX28, lower it*/
+ fep->phy_speed = readl(fep->enet_addr + MCF_FEC_MSCR0) << 2;
+ writel(fep->phy_speed, fep->enet_addr + MCF_FEC_MSCR0);
+ writel(fep->phy_speed, fep->enet_addr + MCF_FEC_MSCR1);
+#endif
+
+}
+
+static void switch_get_mac(struct net_device *dev)
+{
+ struct switch_enet_private *fep = netdev_priv(dev);
+ unsigned char *iap, tmpaddr[ETH_ALEN];
+ static int index;
+#ifdef CONFIG_M5272
+ if (FEC_FLASHMAC) {
+ /*
+ * Get MAC address from FLASH.
+ * If it is all 1's or 0's, use the default.
+ */
+ iap = (unsigned char *)FEC_FLASHMAC;
+ if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
+ (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
+ iap = switch_mac_default;
+ if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
+ (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
+ iap = switch_mac_default;
+ }
+#else
+ if (is_valid_ether_addr(switch_mac_default))
+ iap = switch_mac_default;
+#endif
+ else {
+ *((unsigned long *) &tmpaddr[0]) =
+ be32_to_cpu(readl(fep->enet_addr
+ + FEC_ADDR_LOW / sizeof(unsigned long)));
+ *((unsigned short *) &tmpaddr[4]) =
+ be16_to_cpu(readl(fep->enet_addr
+ + FEC_ADDR_HIGH / sizeof(unsigned long)) >> 16);
+ iap = &tmpaddr[0];
+ }
+
+ memcpy(dev->dev_addr, iap, ETH_ALEN);
+
+ /* Adjust MAC if using default MAC address */
+ if (iap == switch_mac_default) {
+ dev->dev_addr[ETH_ALEN-1] =
+ switch_mac_default[ETH_ALEN-1] + index;
+ index++;
+ }
+}
+
+static void switch_enable_phy_intr(void)
+{
+}
+
+static void switch_disable_phy_intr(void)
+{
+}
+
+static void switch_phy_ack_intr(void)
+{
+}
+
+static void switch_localhw_setup(void)
+{
+}
+
+static void switch_uncache(unsigned long addr)
+{
+}
+
+static void switch_platform_flush_cache(void)
+{
+}
+
+/*
+ * Calculate Galois Field Arithmetic CRC for Polynom x^8+x^2+x+1.
+ * It omits the final shift in of 8 zeroes a "normal" CRC would do
+ * (getting the remainder).
+ *
+ * Examples (hexadecimal values):<br>
+ * 10-11-12-13-14-15 => CRC=0xc2
+ * 10-11-cc-dd-ee-00 => CRC=0xe6
+ *
+ * param: pmacaddress
+ * A 6-byte array with the MAC address.
+ * The first byte is the first byte transmitted
+ * return The 8-bit CRC in bits 7:0
+ */
+static int crc8_calc(unsigned char *pmacaddress)
+{
+ /* byte index */
+ int byt;
+ /* bit index */
+ int bit;
+ int inval;
+ int crc;
+ /* preset */
+ crc = 0x12;
+ for (byt = 0; byt < 6; byt++) {
+ inval = (((int)pmacaddress[byt]) & 0xff);
+ /*
+ * shift bit 0 to bit 8 so all our bits
+ * travel through bit 8
+ * (simplifies below calc)
+ */
+ inval <<= 8;
+
+ for (bit = 0; bit < 8; bit++) {
+ /* next input bit comes into d7 after shift */
+ crc |= inval & 0x100;
+ if (crc & 0x01)
+ /* before shift */
+ crc ^= 0x1c0;
+
+ crc >>= 1;
+ inval >>= 1;
+ }
+
+ }
+ /* upper bits are clean as we shifted in zeroes! */
+ return crc;
+}
+
+static void read_atable(struct switch_enet_private *fep,
+ int index,
+ unsigned long *read_lo, unsigned long *read_hi)
+{
+ unsigned long atable_base = (unsigned long)fep->hwentry;
+
+ *read_lo = readl(atable_base + (index<<3));
+ *read_hi = readl(atable_base + (index<<3) + 4);
+}
+
+static void write_atable(struct switch_enet_private *fep,
+ int index,
+ unsigned long write_lo, unsigned long write_hi)
+{
+ unsigned long atable_base = (unsigned long)fep->hwentry;
+
+ writel(write_lo, atable_base + (index<<3));
+ writel(write_hi, atable_base + (index<<3) + 4);
+}
+
+/* Read one element from the HW receive FIFO (Queue)
+ * if available and return it.
+ * return ms_HwPortInfo or null if no data is available
+ */
+static struct eswPortInfo *esw_portinfofifo_read(
+ struct switch_enet_private *fep)
+{
+ struct switch_t *fecp;
+ unsigned long tmp;
+
+ fecp = fep->hwp;
+ if (fecp->ESW_LSR == 0) {
+ printk(KERN_ERR "%s: ESW_LSR = %lx\n",
+ __func__, fecp->ESW_LSR);
+ return NULL;
+ }
+ /* read word from FIFO */
+ g_info.maclo = fecp->ESW_LREC0;
+ /* but verify that we actually did so
+ * (0=no data available)
+ */
+ if (g_info.maclo == 0) {
+ printk(KERN_ERR "%s: mac lo %x\n",
+ __func__, g_info.maclo);
+ return NULL;
+ }
+ /* read 2nd word from FIFO */
+ tmp = fecp->ESW_LREC1;
+ g_info.machi = tmp & 0xffff;
+ g_info.hash = (tmp >> 16) & 0xff;
+ g_info.port = (tmp >> 24) & 0xf;
+
+ return &g_info;
+}
+
+
+/*
+ * Clear complete MAC Look Up Table
+ */
+static void esw_clear_atable(struct switch_enet_private *fep)
+{
+ int index;
+ for (index = 0; index < 2048; index++)
+ write_atable(fep, index, 0, 0);
+}
+
+/*
+ * pdates MAC address lookup table with a static entry
+ * Searches if the MAC address is already there in the block and replaces
+ * the older entry with new one. If MAC address is not there then puts a
+ * new entry in the first empty slot available in the block
+ *
+ * mac_addr Pointer to the array containing MAC address to
+ * be put as static entry
+ * port Port bitmask numbers to be added in static entry,
+ * valid values are 1-7
+ * priority Priority for the static entry in table
+ *
+ * return 0 for a successful update else -1 when no slot available
+ */
+static int esw_update_atable_static(unsigned char *mac_addr,
+ unsigned int port, unsigned int priority,
+ struct switch_enet_private *fep)
+{
+ unsigned long block_index, entry, index_end;
+
+ unsigned long read_lo, read_hi;
+ unsigned long write_lo, write_hi;
+
+ write_lo = (unsigned long)((mac_addr[3] << 24) |
+ (mac_addr[2] << 16) |
+ (mac_addr[1] << 8) |
+ mac_addr[0]);
+ write_hi = (unsigned long)(0 |
+ (port << AT_SENTRY_PORTMASK_shift) |
+ (priority << AT_SENTRY_PRIO_shift) |
+ (AT_ENTRY_TYPE_STATIC << AT_ENTRY_TYPE_shift) |
+ (AT_ENTRY_RECORD_VALID << AT_ENTRY_VALID_shift) |
+ (mac_addr[5] << 8) | (mac_addr[4]));
+
+ block_index = GET_BLOCK_PTR(crc8_calc(mac_addr));
+ index_end = block_index + ATABLE_ENTRY_PER_SLOT;
+ /* Now search all the entries in the selected block */
+ for (entry = block_index; entry < index_end; entry++) {
+ read_atable(fep, entry, &read_lo, &read_hi);
+ /*
+ * MAC address matched, so update the
+ * existing entry
+ * even if its a dynamic one
+ */
+ if ((read_lo == write_lo) &&
+ ((read_hi & 0x0000ffff) ==
+ (write_hi & 0x0000ffff))) {
+ write_atable(fep, entry, write_lo, write_hi);
+ return 0;
+ } else if (!(read_hi & (1 << 16))) {
+ /*
+ * Fill this empty slot (valid bit zero),
+ * assuming no holes in the block
+ */
+ write_atable(fep, entry, write_lo, write_hi);
+ fep->atCurrEntries++;
+ return 0;
+ }
+ }
+
+ /* No space available for this static entry */
+ return -1;
+}
+
+static int esw_update_atable_dynamic1(unsigned long write_lo,
+ unsigned long write_hi, int block_index,
+ unsigned int port, unsigned int currTime,
+ struct switch_enet_private *fep)
+{
+ unsigned long entry, index_end;
+ unsigned long read_lo, read_hi;
+ unsigned long tmp;
+ int time, timeold, indexold;
+
+ /* prepare update port and timestamp */
+ tmp = AT_ENTRY_RECORD_VALID << AT_ENTRY_VALID_shift;
+ tmp |= AT_ENTRY_TYPE_DYNAMIC << AT_ENTRY_TYPE_shift;
+ tmp |= currTime << AT_DENTRY_TIME_shift;
+ tmp |= port << AT_DENTRY_PORT_shift;
+ tmp |= write_hi;
+
+ /*
+ * linear search through all slot
+ * entries and update if found
+ */
+ index_end = block_index + ATABLE_ENTRY_PER_SLOT;
+ /* Now search all the entries in the selected block */
+ for (entry = block_index; entry < index_end; entry++) {
+ read_atable(fep, entry, &read_lo, &read_hi);
+ if ((read_lo == write_lo) &&
+ ((read_hi & 0x0000ffff) ==
+ (write_hi & 0x0000ffff))) {
+ /* found correct address,
+ * update timestamp.
+ */
+ write_atable(fep, entry, write_lo, tmp);
+ return 0;
+ } else if (!(read_hi & (1 << 16))) {
+ /* slot is empty, then use it
+ * for new entry
+ * Note: There are no holes,
+ * therefore cannot be any
+ * more that need to be compared.
+ */
+ write_atable(fep, entry, write_lo, tmp);
+ /* statistics (we do it between writing
+ * .hi an .lo due to
+ * hardware limitation...
+ */
+ fep->atCurrEntries++;
+ /* newly inserted */
+ return 1;
+ }
+ }
+
+ /*
+ * no more entry available in block ...
+ * overwrite oldest
+ */
+ timeold = 0;
+ indexold = 0;
+ for (entry = block_index; entry < index_end; entry++) {
+ read_atable(fep, entry, &read_lo, &read_hi);
+ time = AT_EXTRACT_TIMESTAMP(read_hi);
+ printk(KERN_ERR "%s : time %x currtime %x\n",
+ __func__, time, currTime);
+ time = TIMEDELTA(currTime, time);
+ if (time > timeold) {
+ /* is it older ? */
+ timeold = time;
+ indexold = entry;
+ }
+ }
+
+ write_atable(fep, indexold, write_lo, tmp);
+ /*
+ * Statistics (do it inbetween
+ *writing to .lo and .hi
+ */
+ fep->atBlockOverflows++;
+ printk(KERN_ERR "%s update time, atBlockOverflows %x\n",
+ __func__, fep->atBlockOverflows);
+ /* newly inserted */
+ return 1;
+}
+
+/* dynamicms MAC address table learn and migration */
+static int esw_atable_dynamicms_learn_migration(
+ struct switch_enet_private *fep,
+ int currTime)
+{
+ struct eswPortInfo *pESWPortInfo;
+ int index;
+ int inserted = 0;
+
+ pESWPortInfo = esw_portinfofifo_read(fep);
+ /* Anything to learn */
+ if (pESWPortInfo != 0) {
+ /* get block index from lookup table */
+ index = GET_BLOCK_PTR(pESWPortInfo->hash);
+ inserted = esw_update_atable_dynamic1(
+ pESWPortInfo->maclo,
+ pESWPortInfo->machi, index,
+ pESWPortInfo->port, currTime, fep);
+ } else {
+ printk(KERN_ERR "%s:hav invalidate learned data \n", __func__);
+ return -1;
+ }
+
+ return 0;
+
+}
+
+/*
+ * esw_forced_forward
+ * The frame is forwared to the forced destination ports.
+ * It only replace the MAC lookup function,
+ * all other filtering(eg.VLAN verification) act as normal
+ */
+static int esw_forced_forward(struct switch_enet_private *fep,
+ int port1, int port2, int enable)
+{
+ unsigned long tmp = 0;
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+
+ /* Enable Forced forwarding for port num */
+ if ((port1 == 1) && (port2 == 1))
+ tmp |= MCF_ESW_P0FFEN_FD(3);
+ else if (port1 == 1)
+ /* Enable Forced forwarding for port 1 only */
+ tmp |= MCF_ESW_P0FFEN_FD(1);
+ else if (port2 == 1)
+ /* Enable Forced forwarding for port 2 only */
+ tmp |= MCF_ESW_P0FFEN_FD(2);
+ else {
+ printk(KERN_ERR "%s:do not support "
+ "the forced forward mode"
+ "port1 %x port2 %x\n",
+ __func__, port1, port2);
+ return -1;
+ }
+
+ if (enable == 1)
+ tmp |= MCF_ESW_P0FFEN_FEN;
+ else if (enable == 0)
+ tmp &= ~MCF_ESW_P0FFEN_FEN;
+ else {
+ printk(KERN_ERR "%s: the enable %x is error\n",
+ __func__, enable);
+ return -2;
+ }
+
+ fecp->ESW_P0FFEN = tmp;
+ return 0;
+}
+
+static int esw_get_forced_forward(
+ struct switch_enet_private *fep,
+ unsigned long *ulForceForward)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+ *ulForceForward = fecp->ESW_P0FFEN;
+#ifdef DEBUG_FORCED_FORWARD
+ printk(KERN_INFO "%s ESW_P0FFEN %#lx\n",
+ __func__, fecp->ESW_P0FFEN);
+#endif
+ return 0;
+}
+
+static void esw_get_port_enable(
+ struct switch_enet_private *fep,
+ unsigned long *ulPortEnable)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+ *ulPortEnable = fecp->ESW_PER;
+#ifdef DEBUG_PORT_ENABLE
+ printk(KERN_INFO "%s fecp->ESW_PER %#lx\n",
+ __func__, fecp->ESW_PER);
+#endif
+}
+/*
+ * enable or disable port n tx or rx
+ * tx_en 0 disable port n tx
+ * tx_en 1 enable port n tx
+ * rx_en 0 disbale port n rx
+ * rx_en 1 enable port n rx
+ */
+static int esw_port_enable_config(struct switch_enet_private *fep,
+ int port, int tx_en, int rx_en)
+{
+ unsigned long tmp = 0;
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+ tmp = fecp->ESW_PER;
+ if (tx_en == 1) {
+ if (port == 0)
+ tmp |= MCF_ESW_PER_TE0;
+ else if (port == 1)
+ tmp |= MCF_ESW_PER_TE1;
+ else if (port == 2)
+ tmp |= MCF_ESW_PER_TE2;
+ else {
+ printk(KERN_ERR "%s:do not support the"
+ " port %x tx enable %d\n",
+ __func__, port, tx_en);
+ return -1;
+ }
+ } else if (tx_en == 0) {
+ if (port == 0)
+ tmp &= (~MCF_ESW_PER_TE0);
+ else if (port == 1)
+ tmp &= (~MCF_ESW_PER_TE1);
+ else if (port == 2)
+ tmp &= (~MCF_ESW_PER_TE2);
+ else {
+ printk(KERN_ERR "%s:do not support "
+ "the port %x tx disable %d\n",
+ __func__, port, tx_en);
+ return -2;
+ }
+ } else {
+ printk(KERN_ERR "%s:do not support the port %x"
+ " tx op value %x\n",
+ __func__, port, tx_en);
+ return -3;
+ }
+
+ if (rx_en == 1) {
+ if (port == 0)
+ tmp |= MCF_ESW_PER_RE0;
+ else if (port == 1)
+ tmp |= MCF_ESW_PER_RE1;
+ else if (port == 2)
+ tmp |= MCF_ESW_PER_RE2;
+ else {
+ printk(KERN_ERR "%s:do not support the "
+ "port %x rx enable %d\n",
+ __func__, port, tx_en);
+ return -4;
+ }
+ } else if (rx_en == 0) {
+ if (port == 0)
+ tmp &= (~MCF_ESW_PER_RE0);
+ else if (port == 1)
+ tmp &= (~MCF_ESW_PER_RE1);
+ else if (port == 2)
+ tmp &= (~MCF_ESW_PER_RE2);
+ else {
+ printk(KERN_ERR "%s:do not support the "
+ "port %x rx disable %d\n",
+ __func__, port, rx_en);
+ return -5;
+ }
+ } else {
+ printk(KERN_ERR "%s:do not support the port %x"
+ " rx op value %x\n",
+ __func__, port, tx_en);
+ return -6;
+ }
+
+ fecp->ESW_PER = tmp;
+ return 0;
+}
+
+
+static void esw_get_port_broadcast(
+ struct switch_enet_private *fep,
+ unsigned long *ulPortBroadcast)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+ *ulPortBroadcast = fecp->ESW_DBCR;
+#ifdef DEBUG_PORT_BROADCAST
+ printk(KERN_INFO "%s fecp->ESW_DBCR %#lx\n",
+ __func__, fecp->ESW_DBCR);
+#endif
+}
+
+static int esw_port_broadcast_config(
+ struct switch_enet_private *fep,
+ int port, int enable)
+{
+ unsigned long tmp = 0;
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+
+ if ((port > 2) || (port < 0)) {
+ printk(KERN_ERR "%s:do not support the port %x"
+ " default broadcast\n",
+ __func__, port);
+ return -1;
+ }
+
+ tmp = fecp->ESW_DBCR;
+ if (enable == 1) {
+ if (port == 0)
+ tmp |= MCF_ESW_DBCR_P0;
+ else if (port == 1)
+ tmp |= MCF_ESW_DBCR_P1;
+ else if (port == 2)
+ tmp |= MCF_ESW_DBCR_P2;
+ } else if (enable == 0) {
+ if (port == 0)
+ tmp &= ~MCF_ESW_DBCR_P0;
+ else if (port == 1)
+ tmp &= ~MCF_ESW_DBCR_P1;
+ else if (port == 2)
+ tmp &= ~MCF_ESW_DBCR_P2;
+ }
+
+ fecp->ESW_DBCR = tmp;
+ return 0;
+}
+
+
+static void esw_get_port_multicast(
+ struct switch_enet_private *fep,
+ unsigned long *ulPortMulticast)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+ *ulPortMulticast = fecp->ESW_DMCR;
+#ifdef DEBUG_PORT_MULTICAST
+ printk(KERN_INFO "%s fecp->ESW_DMCR %#lx\n",
+ __func__, fecp->ESW_DMCR);
+#endif
+}
+
+static int esw_port_multicast_config(
+ struct switch_enet_private *fep,
+ int port, int enable)
+{
+ unsigned long tmp = 0;
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+
+ if ((port > 2) || (port < 0)) {
+ printk(KERN_ERR "%s:do not support the port %x"
+ " default broadcast\n",
+ __func__, port);
+ return -1;
+ }
+
+ tmp = fecp->ESW_DMCR;
+ if (enable == 1) {
+ if (port == 0)
+ tmp |= MCF_ESW_DMCR_P0;
+ else if (port == 1)
+ tmp |= MCF_ESW_DMCR_P1;
+ else if (port == 2)
+ tmp |= MCF_ESW_DMCR_P2;
+ } else if (enable == 0) {
+ if (port == 0)
+ tmp &= ~MCF_ESW_DMCR_P0;
+ else if (port == 1)
+ tmp &= ~MCF_ESW_DMCR_P1;
+ else if (port == 2)
+ tmp &= ~MCF_ESW_DMCR_P2;
+ }
+
+ fecp->ESW_DMCR = tmp;
+ return 0;
+}
+
+
+static void esw_get_port_blocking(
+ struct switch_enet_private *fep,
+ unsigned long *ulPortBlocking)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+ *ulPortBlocking = (fecp->ESW_BKLR & 0x00ff);
+#ifdef DEBUG_PORT_BLOCKING
+ printk(KERN_INFO "%s fecp->ESW_BKLR %#lx\n",
+ __func__, fecp->ESW_BKLR);
+#endif
+}
+
+static int esw_port_blocking_config(
+ struct switch_enet_private *fep,
+ int port, int enable)
+{
+ unsigned long tmp = 0;
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+
+ if ((port > 2) || (port < 0)) {
+ printk(KERN_ERR "%s:do not support the port %x"
+ " default broadcast\n",
+ __func__, port);
+ return -1;
+ }
+
+ tmp = fecp->ESW_BKLR;
+ if (enable == 1) {
+ if (port == 0)
+ tmp |= MCF_ESW_BKLR_BE0;
+ else if (port == 1)
+ tmp |= MCF_ESW_BKLR_BE1;
+ else if (port == 2)
+ tmp |= MCF_ESW_BKLR_BE2;
+ } else if (enable == 0) {
+ if (port == 0)
+ tmp &= ~MCF_ESW_BKLR_BE0;
+ else if (port == 1)
+ tmp &= ~MCF_ESW_BKLR_BE1;
+ else if (port == 2)
+ tmp &= ~MCF_ESW_BKLR_BE2;
+ }
+
+ fecp->ESW_BKLR = tmp;
+ return 0;
+}
+
+
+static void esw_get_port_learning(
+ struct switch_enet_private *fep,
+ unsigned long *ulPortLearning)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+ *ulPortLearning = (fecp->ESW_BKLR & 0xff00) >> 16;
+#ifdef DEBUG_PORT_LEARNING
+ printk(KERN_INFO "%s fecp->ESW_BKLR %#lx\n",
+ __func__, fecp->ESW_BKLR);
+#endif
+}
+
+static int esw_port_learning_config(
+ struct switch_enet_private *fep,
+ int port, int disable)
+{
+ unsigned long tmp = 0;
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+
+ if ((port > 2) || (port < 0)) {
+ printk(KERN_ERR "%s:do not support the port %x"
+ " default broadcast\n",
+ __func__, port);
+ return -1;
+ }
+
+ tmp = fecp->ESW_BKLR;
+ if (disable == 1) {
+ fep->learning_irqhandle_enable = 0;
+ if (port == 0)
+ tmp |= MCF_ESW_BKLR_LD0;
+ else if (port == 1)
+ tmp |= MCF_ESW_BKLR_LD1;
+ else if (port == 2)
+ tmp |= MCF_ESW_BKLR_LD2;
+ } else if (disable == 0) {
+ fep->learning_irqhandle_enable = 1;
+ fecp->switch_imask |= MCF_ESW_IMR_LRN;
+ if (port == 0)
+ tmp &= ~MCF_ESW_BKLR_LD0;
+ else if (port == 1)
+ tmp &= ~MCF_ESW_BKLR_LD1;
+ else if (port == 2)
+ tmp &= ~MCF_ESW_BKLR_LD2;
+ }
+
+ fecp->ESW_BKLR = tmp;
+#ifdef DEBUG_PORT_LEARNING
+ printk(KERN_INFO "%s ESW_BKLR %#lx, switch_imask %#lx\n",
+ __func__, fecp->ESW_BKLR, fecp->switch_imask);
+#endif
+ return 0;
+}
+
+/*
+ * Checks IP Snoop options of handling the snooped frame.
+ * mode 0 : The snooped frame is forward only to management port
+ * mode 1 : The snooped frame is copy to management port and
+ * normal forwarding is checked.
+ * mode 2 : The snooped frame is discarded.
+ * mode 3 : Disable the ip snoop function
+ * ip_header_protocol : the IP header protocol field
+ */
+static int esw_ip_snoop_config(struct switch_enet_private *fep,
+ int num, int mode, unsigned long ip_header_protocol)
+{
+ struct switch_t *fecp;
+ unsigned long tmp = 0, protocol_type = 0;
+
+ fecp = fep->hwp;
+ /* Config IP Snooping */
+ if (mode == 0) {
+ /* Enable IP Snooping */
+ tmp = MCF_ESW_IPSNP_EN;
+ tmp |= MCF_ESW_IPSNP_MODE(0);/*For Forward*/
+ } else if (mode == 1) {
+ /* Enable IP Snooping */
+ tmp = MCF_ESW_IPSNP_EN;
+ /*For Forward and copy_to_mangmnt_port*/
+ tmp |= MCF_ESW_IPSNP_MODE(1);
+ } else if (mode == 2) {
+ /* Enable IP Snooping */
+ tmp = MCF_ESW_IPSNP_EN;
+ tmp |= MCF_ESW_IPSNP_MODE(2);/*discard*/
+ } else if (mode == 3) {
+ /* disable IP Snooping */
+ tmp = MCF_ESW_IPSNP_EN;
+ tmp &= ~MCF_ESW_IPSNP_EN;
+ } else {
+ printk(KERN_ERR "%s: the mode %x "
+ "we do not support\n", __func__, mode);
+ return -1;
+ }
+
+ protocol_type = ip_header_protocol;
+ fecp->ESW_IPSNP[num] =
+ tmp | MCF_ESW_IPSNP_PROTOCOL(protocol_type);
+ printk(KERN_INFO "%s : ESW_IPSNP[%d] %#lx\n",
+ __func__, num, fecp->ESW_IPSNP[num]);
+ return 0;
+}
+
+static void esw_get_ip_snoop_config(
+ struct switch_enet_private *fep,
+ unsigned long *ulpESW_IPSNP)
+{
+ int i;
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+ for (i = 0; i < 8; i++)
+ *(ulpESW_IPSNP + i) = fecp->ESW_IPSNP[i];
+#ifdef DEBUG_IP_SNOOP
+ printk(KERN_INFO "%s ", __func__);
+ for (i = 0; i < 8; i++)
+ printk(KERN_INFO " reg(%d) %#lx", fecp->ESW_IPSNP[i]);
+ printk(KERN_INFO "\n");
+#endif
+
+}
+/*
+ * Checks TCP/UDP Port Snoop options of handling the snooped frame.
+ * mode 0 : The snooped frame is forward only to management port
+ * mode 1 : The snooped frame is copy to management port and
+ * normal forwarding is checked.
+ * mode 2 : The snooped frame is discarded.
+ * compare_port : port number in the TCP/UDP header
+ * compare_num 1: TCP/UDP source port number is compared
+ * compare_num 2: TCP/UDP destination port number is compared
+ * compare_num 3: TCP/UDP source and destination port number is compared
+ */
+static int esw_tcpudp_port_snoop_config(struct switch_enet_private *fep,
+ int num, int mode, int compare_port, int compare_num)
+{
+ struct switch_t *fecp;
+ unsigned long tmp = 0;
+
+ fecp = fep->hwp;
+
+ /* Enable TCP/UDP port Snooping */
+ tmp = MCF_ESW_PSNP_EN;
+ if (mode == 0)
+ tmp |= MCF_ESW_PSNP_MODE(0);/* For Forward */
+ else if (mode == 1)/*For Forward and copy_to_mangmnt_port*/
+ tmp |= MCF_ESW_PSNP_MODE(1);
+ else if (mode == 2)
+ tmp |= MCF_ESW_PSNP_MODE(2);/* discard */
+ else if (mode == 3) /* disable the port function */
+ tmp &= (~MCF_ESW_PSNP_EN);
+ else {
+ printk(KERN_ERR "%s: the mode %x we do not support\n",
+ __func__, mode);
+ return -1;
+ }
+
+ if (compare_num == 1)
+ tmp |= MCF_ESW_PSNP_CS;
+ else if (compare_num == 2)
+ tmp |= MCF_ESW_PSNP_CD;
+ else if (compare_num == 3)
+ tmp |= MCF_ESW_PSNP_CD | MCF_ESW_PSNP_CS;
+ else {
+ printk(KERN_ERR "%s: the compare port address %x"
+ " we do not support\n",
+ __func__, compare_num);
+ return -1;
+ }
+
+ fecp->ESW_PSNP[num] = tmp |
+ MCF_ESW_PSNP_PORT_COMPARE(compare_port);
+ printk(KERN_INFO "ESW_PSNP[%d] %#lx\n",
+ num, fecp->ESW_PSNP[num]);
+ return 0;
+}
+
+static void esw_get_tcpudp_port_snoop_config(
+ struct switch_enet_private *fep,
+ unsigned long *ulpESW_PSNP)
+{
+ int i;
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+ for (i = 0; i < 8; i++)
+ *(ulpESW_PSNP + i) = fecp->ESW_PSNP[i];
+#ifdef DEBUG_TCPUDP_PORT_SNOOP
+ printk(KERN_INFO "%s ", __func__);
+ for (i = 0; i < 8; i++)
+ printk(KERN_INFO " reg(%d) %#lx", fecp->ESW_PSNP[i]);
+ printk(KERN_INFO "\n");
+#endif
+
+}
+
+static void esw_get_port_mirroring(
+ struct switch_enet_private *fep,
+ struct eswIoctlPortMirrorStatus *pPortMirrorStatus)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+ pPortMirrorStatus->ESW_MCR = fecp->ESW_MCR;
+ pPortMirrorStatus->ESW_EGMAP = fecp->ESW_EGMAP;
+ pPortMirrorStatus->ESW_INGMAP = fecp->ESW_INGMAP;
+ pPortMirrorStatus->ESW_INGSAL = fecp->ESW_INGSAL;
+ pPortMirrorStatus->ESW_INGSAH = fecp->ESW_INGSAH;
+ pPortMirrorStatus->ESW_INGDAL = fecp->ESW_INGDAL;
+ pPortMirrorStatus->ESW_INGDAH = fecp->ESW_INGDAH;
+ pPortMirrorStatus->ESW_ENGSAL = fecp->ESW_ENGSAL;
+ pPortMirrorStatus->ESW_ENGSAH = fecp->ESW_ENGSAH;
+ pPortMirrorStatus->ESW_ENGDAL = fecp->ESW_ENGDAL;
+ pPortMirrorStatus->ESW_ENGDAH = fecp->ESW_ENGDAH;
+ pPortMirrorStatus->ESW_MCVAL = fecp->ESW_MCVAL;
+#ifdef DEBUG_PORT_MIRROR
+ printk(KERN_INFO "%s : ESW_MCR %#lx, ESW_EGMAP %#lx\n"
+ "ESW_INGMAP %#lx, ESW_INGSAL %#lx, "
+ "ESW_INGSAH %#lx ESW_INGDAL %#lx, ESW_INGDAH %#lx\n"
+ "ESW_ENGSAL %#lx, ESW_ENGSAH%#lx, ESW_ENGDAL %#lx,"
+ "ESW_ENGDAH %#lx, ESW_MCVAL %#lx\n",
+ __func__, fecp->ESW_MCR, fecp->ESW_EGMAP, fecp->ESW_INGMAP,
+ fecp->ESW_INGSAL, fecp->ESW_INGSAH, fecp->ESW_INGDAL,
+ fecp->ESW_INGDAH, fecp->ESW_ENGSAL, fecp->ESW_ENGSAH,
+ fecp->ESW_ENGDAL, fecp->ESW_ENGDAH, fecp->ESW_MCVAL);
+#endif
+}
+
+static int esw_port_mirroring_config(struct switch_enet_private *fep,
+ int mirror_port, int port, int mirror_enable,
+ unsigned char *src_mac, unsigned char *des_mac,
+ int egress_en, int ingress_en,
+ int egress_mac_src_en, int egress_mac_des_en,
+ int ingress_mac_src_en, int ingress_mac_des_en)
+{
+ struct switch_t *fecp;
+ unsigned long tmp = 0;
+
+ fecp = fep->hwp;
+
+ /*mirroring config*/
+ tmp = 0;
+ if (egress_en == 1) {
+ tmp |= MCF_ESW_MCR_EGMAP;
+ if (port == 0)
+ fecp->ESW_EGMAP = MCF_ESW_EGMAP_EG0;
+ else if (port == 1)
+ fecp->ESW_EGMAP = MCF_ESW_EGMAP_EG1;
+ else if (port == 2)
+ fecp->ESW_EGMAP = MCF_ESW_EGMAP_EG2;
+ else {
+ printk(KERN_ERR "%s: the port %x we do not support\n",
+ __func__, port);
+ return -1;
+ }
+ } else if (egress_en == 0) {
+ tmp &= (~MCF_ESW_MCR_EGMAP);
+ } else {
+ printk(KERN_ERR "%s: egress_en %x we do not support\n",
+ __func__, egress_en);
+ return -1;
+ }
+
+ if (ingress_en == 1) {
+ tmp |= MCF_ESW_MCR_INGMAP;
+ if (port == 0)
+ fecp->ESW_INGMAP = MCF_ESW_INGMAP_ING0;
+ else if (port == 1)
+ fecp->ESW_INGMAP = MCF_ESW_INGMAP_ING1;
+ else if (port == 2)
+ fecp->ESW_INGMAP = MCF_ESW_INGMAP_ING2;
+ else {
+ printk(KERN_ERR "%s: the port %x we do not support\n",
+ __func__, port);
+ return -1;
+ }
+ } else if (ingress_en == 0) {
+ tmp &= ~MCF_ESW_MCR_INGMAP;
+ } else{
+ printk(KERN_ERR "%s: ingress_en %x we do not support\n",
+ __func__, ingress_en);
+ return -1;
+ }
+
+ if (egress_mac_src_en == 1) {
+ tmp |= MCF_ESW_MCR_EGSA;
+ fecp->ESW_ENGSAH = (src_mac[5] << 8) | (src_mac[4]);
+ fecp->ESW_ENGSAL = (unsigned long)((src_mac[3] << 24) |
+ (src_mac[2] << 16) |
+ (src_mac[1] << 8) |
+ src_mac[0]);
+ } else if (egress_mac_src_en == 0) {
+ tmp &= ~MCF_ESW_MCR_EGSA;
+ } else {
+ printk(KERN_ERR "%s: egress_mac_src_en %x we do not support\n",
+ __func__, egress_mac_src_en);
+ return -1;
+ }
+
+ if (egress_mac_des_en == 1) {
+ tmp |= MCF_ESW_MCR_EGDA;
+ fecp->ESW_ENGDAH = (des_mac[5] << 8) | (des_mac[4]);
+ fecp->ESW_ENGDAL = (unsigned long)((des_mac[3] << 24) |
+ (des_mac[2] << 16) |
+ (des_mac[1] << 8) |
+ des_mac[0]);
+ } else if (egress_mac_des_en == 0) {
+ tmp &= ~MCF_ESW_MCR_EGDA;
+ } else {
+ printk(KERN_ERR "%s: egress_mac_des_en %x we do not support\n",
+ __func__, egress_mac_des_en);
+ return -1;
+ }
+
+ if (ingress_mac_src_en == 1) {
+ tmp |= MCF_ESW_MCR_INGSA;
+ fecp->ESW_INGSAH = (src_mac[5] << 8) | (src_mac[4]);
+ fecp->ESW_INGSAL = (unsigned long)((src_mac[3] << 24) |
+ (src_mac[2] << 16) |
+ (src_mac[1] << 8) |
+ src_mac[0]);
+ } else if (ingress_mac_src_en == 0) {
+ tmp &= ~MCF_ESW_MCR_INGSA;
+ } else {
+ printk(KERN_ERR "%s: ingress_mac_src_en %x we do not support\n",
+ __func__, ingress_mac_src_en);
+ return -1;
+ }
+
+ if (ingress_mac_des_en == 1) {
+ tmp |= MCF_ESW_MCR_INGDA;
+ fecp->ESW_INGDAH = (des_mac[5] << 8) | (des_mac[4]);
+ fecp->ESW_INGDAL = (unsigned long)((des_mac[3] << 24) |
+ (des_mac[2] << 16) |
+ (des_mac[1] << 8) |
+ des_mac[0]);
+ } else if (ingress_mac_des_en == 0) {
+ tmp &= ~MCF_ESW_MCR_INGDA;
+ } else {
+ printk(KERN_ERR "%s: ingress_mac_des_en %x we do not support\n",
+ __func__, ingress_mac_des_en);
+ return -1;
+ }
+
+ /*------------------------------------------------------------------*/
+ if (mirror_enable == 1)
+ tmp |= MCF_ESW_MCR_MEN | MCF_ESW_MCR_PORT(mirror_port);
+ else if (mirror_enable == 0)
+ tmp &= ~MCF_ESW_MCR_MEN;
+ else
+ printk(KERN_ERR "%s: the mirror enable %x is error\n",
+ __func__, mirror_enable);
+
+
+ fecp->ESW_MCR = tmp;
+ printk(KERN_INFO "%s : MCR %#lx, EGMAP %#lx, INGMAP %#lx;\n"
+ "ENGSAH %#lx, ENGSAL %#lx ;ENGDAH %#lx, ENGDAL %#lx;\n"
+ "INGSAH %#lx, INGSAL %#lx\n;INGDAH %#lx, INGDAL %#lx;\n",
+ __func__, fecp->ESW_MCR, fecp->ESW_EGMAP, fecp->ESW_INGMAP,
+ fecp->ESW_ENGSAH, fecp->ESW_ENGSAL,
+ fecp->ESW_ENGDAH, fecp->ESW_ENGDAL,
+ fecp->ESW_INGSAH, fecp->ESW_INGSAL,
+ fecp->ESW_INGDAH, fecp->ESW_INGDAL);
+ return 0;
+}
+
+static void esw_get_vlan_verification(
+ struct switch_enet_private *fep,
+ unsigned long *ulValue)
+{
+ struct switch_t *fecp;
+ fecp = fep->hwp;
+ *ulValue = fecp->ESW_VLANV;
+
+#ifdef DEBUG_VLAN_VERIFICATION_CONFIG
+ printk(KERN_INFO "%s: ESW_VLANV %#lx\n",
+ __func__, fecp->ESW_VLANV);
+#endif
+}
+
+static int esw_set_vlan_verification(
+ struct switch_enet_private *fep, int port,
+ int vlan_domain_verify_en,
+ int vlan_discard_unknown_en)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+ if ((port < 0) || (port > 2)) {
+ printk(KERN_ERR "%s: do not support the port %d\n",
+ __func__, port);
+ return -1;
+ }
+
+ if (vlan_domain_verify_en == 1) {
+ if (port == 0)
+ fecp->ESW_VLANV |= MCF_ESW_VLANV_VV0;
+ else if (port == 1)
+ fecp->ESW_VLANV |= MCF_ESW_VLANV_VV1;
+ else if (port == 2)
+ fecp->ESW_VLANV |= MCF_ESW_VLANV_VV2;
+ } else if (vlan_domain_verify_en == 0) {
+ if (port == 0)
+ fecp->ESW_VLANV &= ~MCF_ESW_VLANV_VV0;
+ else if (port == 1)
+ fecp->ESW_VLANV &= ~MCF_ESW_VLANV_VV1;
+ else if (port == 2)
+ fecp->ESW_VLANV &= ~MCF_ESW_VLANV_VV2;
+ } else {
+ printk(KERN_INFO "%s: donot support "
+ "vlan_domain_verify %x\n",
+ __func__, vlan_domain_verify_en);
+ return -2;
+ }
+
+ if (vlan_discard_unknown_en == 1) {
+ if (port == 0)
+ fecp->ESW_VLANV |= MCF_ESW_VLANV_DU0;
+ else if (port == 1)
+ fecp->ESW_VLANV |= MCF_ESW_VLANV_DU1;
+ else if (port == 2)
+ fecp->ESW_VLANV |= MCF_ESW_VLANV_DU2;
+ } else if (vlan_discard_unknown_en == 0) {
+ if (port == 0)
+ fecp->ESW_VLANV &= ~MCF_ESW_VLANV_DU0;
+ else if (port == 1)
+ fecp->ESW_VLANV &= ~MCF_ESW_VLANV_DU1;
+ else if (port == 2)
+ fecp->ESW_VLANV &= ~MCF_ESW_VLANV_DU2;
+ } else {
+ printk(KERN_INFO "%s: donot support "
+ "vlan_discard_unknown %x\n",
+ __func__, vlan_discard_unknown_en);
+ return -3;
+ }
+
+#ifdef DEBUG_VLAN_VERIFICATION_CONFIG
+ printk(KERN_INFO "%s: ESW_VLANV %#lx\n",
+ __func__, fecp->ESW_VLANV);
+#endif
+ return 0;
+}
+
+static void esw_get_vlan_resolution_table(
+ struct switch_enet_private *fep,
+ int vlan_domain_num,
+ unsigned long *ulValue)
+{
+ struct switch_t *fecp;
+ fecp = fep->hwp;
+
+ *ulValue = fecp->ESW_VRES[vlan_domain_num];
+
+#ifdef DEBUG_VLAN_DOMAIN_TABLE
+ printk(KERN_INFO "%s: ESW_VRES[%d] = %#lx\n",
+ __func__, vlan_domain_num,
+ fecp->ESW_VRES[vlan_domain_num]);
+#endif
+}
+
+int esw_set_vlan_resolution_table(
+ struct switch_enet_private *fep,
+ unsigned short port_vlanid,
+ int vlan_domain_num,
+ int vlan_domain_port)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+ if ((vlan_domain_num < 0)
+ || (vlan_domain_num > 31)) {
+ printk(KERN_ERR "%s: do not support the "
+ "vlan_domain_num %d\n",
+ __func__, vlan_domain_num);
+ return -1;
+ }
+
+ if ((vlan_domain_port < 0)
+ || (vlan_domain_port > 7)) {
+ printk(KERN_ERR "%s: do not support the "
+ "vlan_domain_port %d\n",
+ __func__, vlan_domain_port);
+ return -2;
+ }
+
+ fecp->ESW_VRES[vlan_domain_num] =
+ MCF_ESW_VRES_VLANID(port_vlanid)
+ | vlan_domain_port;
+
+#ifdef DEBUG_VLAN_DOMAIN_TABLE
+ printk(KERN_INFO "%s: ESW_VRES[%d] = %#lx\n",
+ __func__, vlan_domain_num,
+ fecp->ESW_VRES[vlan_domain_num]);
+#endif
+ return 0;
+}
+
+static void esw_get_vlan_input_config(
+ struct switch_enet_private *fep,
+ struct eswIoctlVlanInputStatus *pVlanInputConfig)
+{
+ struct switch_t *fecp;
+ int i;
+
+ fecp = fep->hwp;
+ for (i = 0; i < 3; i++)
+ pVlanInputConfig->ESW_PID[i] = fecp->ESW_PID[i];
+
+ pVlanInputConfig->ESW_VLANV = fecp->ESW_VLANV;
+ pVlanInputConfig->ESW_VIMSEL = fecp->ESW_VIMSEL;
+ pVlanInputConfig->ESW_VIMEN = fecp->ESW_VIMEN;
+
+ for (i = 0; i < 32; i++)
+ pVlanInputConfig->ESW_VRES[i] = fecp->ESW_VRES[i];
+#ifdef DEBUG_VLAN_INTPUT_CONFIG
+ printk(KERN_INFO "%s: ESW_VLANV %#lx, ESW_VIMSEL %#lx, "
+ "ESW_VIMEN %#lx, ESW_PID[0], ESW_PID[1] %#lx, "
+ "ESW_PID[2] %#lx", __func__,
+ fecp->ESW_VLANV, fecp->ESW_VIMSEL, fecp->ESW_VIMEN,
+ fecp->ESW_PID[0], fecp->ESW_PID[1], fecp->ESW_PID[2]);
+#endif
+}
+
+
+static int esw_vlan_input_process(struct switch_enet_private *fep,
+ int port, int mode, unsigned short port_vlanid,
+ int vlan_verify_en, int vlan_domain_num,
+ int vlan_domain_port)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+
+ /*we only support mode1 mode2 mode3 mode4*/
+ if ((mode < 0) || (mode > 3)) {
+ printk(KERN_ERR "%s: do not support the"
+ " VLAN input processing mode %d\n",
+ __func__, mode);
+ return -1;
+ }
+
+ if ((port < 0) || (port > 3)) {
+ printk(KERN_ERR "%s: do not support the port %d\n",
+ __func__, mode);
+ return -2;
+ }
+
+ if ((vlan_verify_en == 1) && ((vlan_domain_num < 0)
+ || (vlan_domain_num > 32))) {
+ printk(KERN_ERR "%s: do not support the port %d\n",
+ __func__, mode);
+ return -3;
+ }
+
+ fecp->ESW_PID[port] = MCF_ESW_PID_VLANID(port_vlanid);
+ if (port == 0) {
+ if (vlan_verify_en == 1)
+ fecp->ESW_VRES[vlan_domain_num] =
+ MCF_ESW_VRES_VLANID(port_vlanid)
+ | MCF_ESW_VRES_P0;
+
+ fecp->ESW_VIMEN |= MCF_ESW_VIMEN_EN0;
+ fecp->ESW_VIMSEL |= MCF_ESW_VIMSEL_IM0(mode);
+ } else if (port == 1) {
+ if (vlan_verify_en == 1)
+ fecp->ESW_VRES[vlan_domain_num] =
+ MCF_ESW_VRES_VLANID(port_vlanid)
+ | MCF_ESW_VRES_P1;
+
+ fecp->ESW_VIMEN |= MCF_ESW_VIMEN_EN1;
+ fecp->ESW_VIMSEL |= MCF_ESW_VIMSEL_IM1(mode);
+ } else if (port == 2) {
+ if (vlan_verify_en == 1)
+ fecp->ESW_VRES[vlan_domain_num] =
+ MCF_ESW_VRES_VLANID(port_vlanid)
+ | MCF_ESW_VRES_P2;
+
+ fecp->ESW_VIMEN |= MCF_ESW_VIMEN_EN2;
+ fecp->ESW_VIMSEL |= MCF_ESW_VIMSEL_IM2(mode);
+ } else {
+ printk(KERN_ERR "%s: do not support the port %d\n",
+ __func__, port);
+ return -2;
+ }
+
+ return 0;
+}
+
+static void esw_get_vlan_output_config(struct switch_enet_private *fep,
+ unsigned long *ulVlanOutputConfig)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+
+ *ulVlanOutputConfig = fecp->ESW_VOMSEL;
+#ifdef DEBUG_VLAN_OUTPUT_CONFIG
+ printk(KERN_INFO "%s: ESW_VOMSEL %#lx", __func__,
+ fecp->ESW_VOMSEL);
+#endif
+}
+
+static int esw_vlan_output_process(struct switch_enet_private *fep,
+ int port, int mode)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+
+ if ((port < 0) || (port > 2)) {
+ printk(KERN_ERR "%s: do not support the port %d\n",
+ __func__, mode);
+ return -1;
+ }
+
+ if (port == 0) {
+ fecp->ESW_VOMSEL |= MCF_ESW_VOMSEL_OM0(mode);
+ } else if (port == 1) {
+ fecp->ESW_VOMSEL |= MCF_ESW_VOMSEL_OM1(mode);
+ } else if (port == 2) {
+ fecp->ESW_VOMSEL |= MCF_ESW_VOMSEL_OM2(mode);
+ } else {
+ printk(KERN_ERR "%s: do not support the port %d\n",
+ __func__, port);
+ return -1;
+ }
+ return 0;
+}
+
+/* frame calssify and priority resolution */
+/* vlan priority lookup */
+static int esw_framecalssify_vlan_priority_lookup(
+ struct switch_enet_private *fep,
+ int port, int func_enable,
+ int vlan_pri_table_num,
+ int vlan_pri_table_value)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+
+ if ((port < 0) || (port > 3)) {
+ printk(KERN_ERR "%s: do not support the port %d\n",
+ __func__, port);
+ return -1;
+ }
+
+ if (func_enable == 0) {
+ fecp->ESW_PRES[port] &= ~MCF_ESW_PRES_VLAN;
+ printk(KERN_ERR "%s: disable port %d VLAN priority "
+ "lookup function\n", __func__, port);
+ return 0;
+ }
+
+ if ((vlan_pri_table_num < 0) || (vlan_pri_table_num > 7)) {
+ printk(KERN_ERR "%s: do not support the priority %d\n",
+ __func__, vlan_pri_table_num);
+ return -1;
+ }
+
+ fecp->ESW_PVRES[port] |= ((vlan_pri_table_value & 0x3)
+ << (vlan_pri_table_num*3));
+ /* enable port VLAN priority lookup function */
+ fecp->ESW_PRES[port] |= MCF_ESW_PRES_VLAN;
+
+ return 0;
+}
+
+static int esw_framecalssify_ip_priority_lookup(
+ struct switch_enet_private *fep,
+ int port, int func_enable, int ipv4_en,
+ int ip_priority_num,
+ int ip_priority_value)
+{
+ struct switch_t *fecp;
+ unsigned long tmp = 0, tmp_prio = 0;
+
+ fecp = fep->hwp;
+
+ if ((port < 0) || (port > 3)) {
+ printk(KERN_ERR "%s: do not support the port %d\n",
+ __func__, port);
+ return -1;
+ }
+
+ if (func_enable == 0) {
+ fecp->ESW_PRES[port] &= ~MCF_ESW_PRES_IP;
+ printk(KERN_ERR "%s: disable port %d ip priority "
+ "lookup function\n", __func__, port);
+ return 0;
+ }
+
+ /* IPV4 priority 64 entry table lookup */
+ /* IPv4 head 6 bit TOS field */
+ if (ipv4_en == 1) {
+ if ((ip_priority_num < 0) || (ip_priority_num > 63)) {
+ printk(KERN_ERR "%s: do not support the table entry %d\n",
+ __func__, ip_priority_num);
+ return -2;
+ }
+ } else { /* IPV6 priority 256 entry table lookup */
+ /* IPv6 head 8 bit COS field */
+ if ((ip_priority_num < 0) || (ip_priority_num > 255)) {
+ printk(KERN_ERR "%s: do not support the table entry %d\n",
+ __func__, ip_priority_num);
+ return -3;
+ }
+ }
+
+ /* IP priority table lookup : address */
+ tmp = MCF_ESW_IPRES_ADDRESS(ip_priority_num);
+ /* IP priority table lookup : ipv4sel */
+ if (ipv4_en == 1)
+ tmp = tmp | MCF_ESW_IPRES_IPV4SEL;
+ /* IP priority table lookup : priority */
+ if (port == 0)
+ tmp |= MCF_ESW_IPRES_PRI0(ip_priority_value);
+ else if (port == 1)
+ tmp |= MCF_ESW_IPRES_PRI1(ip_priority_value);
+ else if (port == 2)
+ tmp |= MCF_ESW_IPRES_PRI2(ip_priority_value);
+
+ /* configure */
+ fecp->ESW_IPRES = MCF_ESW_IPRES_READ |
+ MCF_ESW_IPRES_ADDRESS(ip_priority_num);
+ tmp_prio = fecp->ESW_IPRES;
+
+ fecp->ESW_IPRES = tmp | tmp_prio;
+
+ fecp->ESW_IPRES = MCF_ESW_IPRES_READ |
+ MCF_ESW_IPRES_ADDRESS(ip_priority_num);
+ tmp_prio = fecp->ESW_IPRES;
+
+ /* enable port IP priority lookup function */
+ fecp->ESW_PRES[port] |= MCF_ESW_PRES_IP;
+
+ return 0;
+}
+
+static int esw_framecalssify_mac_priority_lookup(
+ struct switch_enet_private *fep,
+ int port)
+{
+ struct switch_t *fecp;
+
+ if ((port < 0) || (port > 3)) {
+ printk(KERN_ERR "%s: do not support the port %d\n",
+ __func__, port);
+ return -1;
+ }
+
+ fecp = fep->hwp;
+ fecp->ESW_PRES[port] |= MCF_ESW_PRES_MAC;
+
+ return 0;
+}
+
+static int esw_frame_calssify_priority_init(
+ struct switch_enet_private *fep,
+ int port, unsigned char priority_value)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+
+ if ((port < 0) || (port > 3)) {
+ printk(KERN_ERR "%s: do not support the port %d\n",
+ __func__, port);
+ return -1;
+ }
+ /* disable all priority lookup function */
+ fecp->ESW_PRES[port] = 0;
+ fecp->ESW_PRES[port] = MCF_ESW_PRES_DFLT_PRI(priority_value & 0x7);
+
+ return 0;
+}
+
+static int esw_get_statistics_status(
+ struct switch_enet_private *fep,
+ struct esw_statistics_status *pStatistics)
+{
+ struct switch_t *fecp;
+ fecp = fep->hwp;
+
+ pStatistics->ESW_DISCN = fecp->ESW_DISCN;
+ pStatistics->ESW_DISCB = fecp->ESW_DISCB;
+ pStatistics->ESW_NDISCN = fecp->ESW_NDISCN;
+ pStatistics->ESW_NDISCB = fecp->ESW_NDISCB;
+#ifdef DEBUG_STATISTICS
+ printk(KERN_ERR "%s:ESW_DISCN %#lx, ESW_DISCB %#lx,"
+ "ESW_NDISCN %#lx, ESW_NDISCB %#lx\n",
+ __func__, fecp->ESW_DISCN, fecp->ESW_DISCB,
+ fecp->ESW_NDISCN, fecp->ESW_NDISCB);
+#endif
+ return 0;
+}
+
+static int esw_get_port_statistics_status(
+ struct switch_enet_private *fep,
+ int port,
+ struct esw_port_statistics_status *pPortStatistics)
+{
+ struct switch_t *fecp;
+
+ if ((port < 0) || (port > 3)) {
+ printk(KERN_ERR "%s: do not support the port %d\n",
+ __func__, port);
+ return -1;
+ }
+
+ fecp = fep->hwp;
+
+ pPortStatistics->MCF_ESW_POQC =
+ fecp->port_statistics_status[port].MCF_ESW_POQC;
+ pPortStatistics->MCF_ESW_PMVID =
+ fecp->port_statistics_status[port].MCF_ESW_PMVID;
+ pPortStatistics->MCF_ESW_PMVTAG =
+ fecp->port_statistics_status[port].MCF_ESW_PMVTAG;
+ pPortStatistics->MCF_ESW_PBL =
+ fecp->port_statistics_status[port].MCF_ESW_PBL;
+#ifdef DEBUG_PORT_STATISTICS
+ printk(KERN_ERR "%s : port[%d].MCF_ESW_POQC %#lx, MCF_ESW_PMVID %#lx,"
+ " MCF_ESW_PMVTAG %#lx, MCF_ESW_PBL %#lx\n",
+ __func__, port,
+ fecp->port_statistics_status[port].MCF_ESW_POQC,
+ fecp->port_statistics_status[port].MCF_ESW_PMVID,
+ fecp->port_statistics_status[port].MCF_ESW_PMVTAG,
+ fecp->port_statistics_status[port].MCF_ESW_PBL);
+#endif
+ return 0;
+}
+
+static int esw_get_output_queue_status(
+ struct switch_enet_private *fep,
+ struct esw_output_queue_status *pOutputQueue)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+ pOutputQueue->ESW_MMSR = fecp->ESW_MMSR;
+ pOutputQueue->ESW_LMT = fecp->ESW_LMT;
+ pOutputQueue->ESW_LFC = fecp->ESW_LFC;
+ pOutputQueue->ESW_IOSR = fecp->ESW_IOSR;
+ pOutputQueue->ESW_PCSR = fecp->ESW_PCSR;
+ pOutputQueue->ESW_QWT = fecp->ESW_QWT;
+ pOutputQueue->ESW_P0BCT = fecp->ESW_P0BCT;
+#ifdef DEBUG_OUTPUT_QUEUE
+ printk(KERN_ERR "%s:ESW_MMSR %#lx, ESW_LMT %#lx, ESW_LFC %#lx, "
+ "ESW_IOSR %#lx, ESW_PCSR %#lx, ESW_QWT %#lx, ESW_P0BCT %#lx\n",
+ __func__, fecp->ESW_MMSR,
+ fecp->ESW_LMT, fecp->ESW_LFC,
+ fecp->ESW_IOSR, fecp->ESW_PCSR,
+ fecp->ESW_QWT, fecp->ESW_P0BCT);
+#endif
+ return 0;
+}
+
+/* set output queue memory status and configure*/
+static int esw_set_output_queue_memory(
+ struct switch_enet_private *fep,
+ int fun_num,
+ struct esw_output_queue_status *pOutputQueue)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+
+ if (fun_num == 1) {
+ /* memory manager status*/
+ fecp->ESW_MMSR = pOutputQueue->ESW_MMSR;
+ } else if (fun_num == 2) {
+ /*low memory threshold*/
+ fecp->ESW_LMT = pOutputQueue->ESW_LMT;
+ } else if (fun_num == 3) {
+ /*lowest number of free cells*/
+ fecp->ESW_LFC = pOutputQueue->ESW_LFC;
+ } else if (fun_num == 4) {
+ /*queue weights*/
+ fecp->ESW_QWT = pOutputQueue->ESW_QWT;
+ } else if (fun_num == 5) {
+ /*port 0 backpressure congenstion thresled*/
+ fecp->ESW_P0BCT = pOutputQueue->ESW_P0BCT;
+ } else {
+ printk(KERN_INFO "%s: do not support the cmd %x\n",
+ __func__, fun_num);
+ return -1;
+ }
+#ifdef DEBUG_OUTPUT_QUEUE
+ printk(KERN_ERR "%s:ESW_MMSR %#lx, ESW_LMT %#lx, ESW_LFC %#lx, "
+ "ESW_IOSR %#lx, ESW_PCSR %#lx, ESW_QWT %#lx, ESW_P0BCT %#lx\n",
+ __func__, fecp->ESW_MMSR,
+ fecp->ESW_LMT, fecp->ESW_LFC,
+ fecp->ESW_IOSR, fecp->ESW_PCSR,
+ fecp->ESW_QWT, fecp->ESW_P0BCT);
+#endif
+ return 0;
+}
+
+int esw_set_irq_mask(
+ struct switch_enet_private *fep,
+ unsigned long mask, int enable)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+#ifdef DEBUG_IRQ
+ printk(KERN_INFO "%s: irq event %#lx, irq mask %#lx "
+ " mask %x, enable %x\n",
+ __func__, fecp->switch_ievent,
+ fecp->switch_imask, mask, enable);
+#endif
+ if (enable == 1)
+ fecp->switch_imask |= mask;
+ else if (enable == 1)
+ fecp->switch_imask &= (~mask);
+ else {
+ printk(KERN_INFO "%s: enable %x is error value\n",
+ __func__, enable);
+ return -1;
+ }
+#ifdef DEBUG_IRQ
+ printk(KERN_INFO "%s: irq event %#lx, irq mask %#lx, "
+ "rx_des_start %#lx, tx_des_start %#lx, "
+ "rx_buff_size %#lx, rx_des_active %#lx, "
+ "tx_des_active %#lx\n",
+ __func__, fecp->switch_ievent, fecp->switch_imask,
+ fecp->fec_r_des_start, fecp->fec_x_des_start,
+ fecp->fec_r_buff_size, fecp->fec_r_des_active,
+ fecp->fec_x_des_active);
+#endif
+ return 0;
+}
+
+static void esw_get_switch_mode(
+ struct switch_enet_private *fep,
+ unsigned long *ulModeConfig)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+ *ulModeConfig = fecp->ESW_MODE;
+#ifdef DEBUG_SWITCH_MODE
+ printk(KERN_INFO "%s: mode %#lx \n",
+ __func__, fecp->ESW_MODE);
+#endif
+}
+
+static void esw_switch_mode_configure(
+ struct switch_enet_private *fep,
+ unsigned long configure)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+ fecp->ESW_MODE |= configure;
+#ifdef DEBUG_SWITCH_MODE
+ printk(KERN_INFO "%s: mode %#lx \n",
+ __func__, fecp->ESW_MODE);
+#endif
+}
+
+
+static void esw_get_bridge_port(
+ struct switch_enet_private *fep,
+ unsigned long *ulBMPConfig)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+ *ulBMPConfig = fecp->ESW_BMPC;
+#ifdef DEBUG_BRIDGE_PORT
+ printk(KERN_INFO "%s: bridge management port %#lx \n",
+ __func__, fecp->ESW_BMPC);
+#endif
+}
+
+static void esw_bridge_port_configure(
+ struct switch_enet_private *fep,
+ unsigned long configure)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+ fecp->ESW_BMPC |= configure;
+#ifdef DEBUG_BRIDGE_PORT
+ printk(KERN_INFO "%s: bridge management port %#lx \n",
+ __func__, fecp->ESW_BMPC);
+#endif
+}
+
+/* The timer should create an interrupt every 4 seconds*/
+static void l2switch_aging_timer(unsigned long data)
+{
+ struct switch_enet_private *fep;
+
+ fep = (struct switch_enet_private *)data;
+
+ if (fep) {
+ TIMEINCREMENT(fep->currTime);
+ fep->timeChanged++;
+ }
+
+ mod_timer(&fep->timer_aging, jiffies + LEARNING_AGING_TIMER);
+}
+
+void esw_check_rxb_txb_interrupt(struct switch_enet_private *fep)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+
+ /*Enable Forced forwarding for port 1*/
+ fecp->ESW_P0FFEN = MCF_ESW_P0FFEN_FEN |
+ MCF_ESW_P0FFEN_FD(1);
+ /*Disable learning for all ports*/
+
+ fecp->switch_imask = MCF_ESW_IMR_TXB | MCF_ESW_IMR_TXF |
+ MCF_ESW_IMR_LRN | MCF_ESW_IMR_RXB | MCF_ESW_IMR_RXF;
+ printk(KERN_ERR "%s: fecp->ESW_DBCR %#lx, fecp->ESW_P0FFEN %#lx"
+ " fecp->ESW_BKLR %#lx\n", __func__, fecp->ESW_DBCR,
+ fecp->ESW_P0FFEN, fecp->ESW_BKLR);
+}
+
+static int esw_mac_addr_static(struct switch_enet_private *fep)
+{
+ struct switch_t *fecp;
+
+ fecp = fep->hwp;
+ fecp->ESW_DBCR = MCF_ESW_DBCR_P1;
+
+ if (is_valid_ether_addr(fep->netdev->dev_addr))
+ esw_update_atable_static(fep->netdev->dev_addr, 7, 7, fep);
+ else{
+ printk(KERN_ERR "Can not add available mac address"
+ " for switch!!\n");
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static void esw_main(struct switch_enet_private *fep)
+{
+ struct switch_t *fecp;
+ fecp = fep->hwp;
+
+ esw_mac_addr_static(fep);
+ fecp->ESW_BKLR = 0;
+ fecp->switch_imask = MCF_ESW_IMR_TXB | MCF_ESW_IMR_TXF |
+ MCF_ESW_IMR_LRN | MCF_ESW_IMR_RXB | MCF_ESW_IMR_RXF;
+ fecp->ESW_PER = 0x70007;
+ fecp->ESW_DBCR = MCF_ESW_DBCR_P1 | MCF_ESW_DBCR_P2;
+}
+
+static int switch_enet_ioctl(
+ struct net_device *dev,
+ struct ifreq *ifr, int cmd)
+{
+ struct switch_enet_private *fep;
+ struct switch_t *fecp;
+ int ret = 0;
+
+ printk(KERN_INFO "%s cmd %x\n", __func__, cmd);
+ fep = netdev_priv(dev);
+ fecp = (struct switch_t *)dev->base_addr;
+
+ switch (cmd) {
+ case ESW_SET_PORTENABLE_CONF:
+ {
+ struct eswIoctlPortEnableConfig configData;
+ ret = copy_from_user(&configData,
+ ifr->ifr_data,
+ sizeof(struct eswIoctlPortEnableConfig));
+ if (ret)
+ return -EFAULT;
+
+ ret = esw_port_enable_config(fep,
+ configData.port,
+ configData.tx_enable,
+ configData.rx_enable);
+ }
+ break;
+ case ESW_SET_BROADCAST_CONF:
+ {
+ struct eswIoctlPortConfig configData;
+ ret = copy_from_user(&configData,
+ ifr->ifr_data, sizeof(struct eswIoctlPortConfig));
+ if (ret)
+ return -EFAULT;
+
+ ret = esw_port_broadcast_config(fep,
+ configData.port, configData.enable);
+ }
+ break;
+
+ case ESW_SET_MULTICAST_CONF:
+ {
+ struct eswIoctlPortConfig configData;
+ ret = copy_from_user(&configData,
+ ifr->ifr_data, sizeof(struct eswIoctlPortConfig));
+ if (ret)
+ return -EFAULT;
+
+ ret = esw_port_multicast_config(fep,
+ configData.port, configData.enable);
+ }
+ break;
+
+ case ESW_SET_BLOCKING_CONF:
+ {
+ struct eswIoctlPortConfig configData;
+ ret = copy_from_user(&configData,
+ ifr->ifr_data, sizeof(struct eswIoctlPortConfig));
+
+ if (ret)
+ return -EFAULT;
+
+ ret = esw_port_blocking_config(fep,
+ configData.port, configData.enable);
+ }
+ break;
+
+ case ESW_SET_LEARNING_CONF:
+ {
+ struct eswIoctlPortConfig configData;
+ printk(KERN_INFO "ESW_SET_LEARNING_CONF\n");
+ ret = copy_from_user(&configData,
+ ifr->ifr_data, sizeof(struct eswIoctlPortConfig));
+ if (ret)
+ return -EFAULT;
+ printk(KERN_INFO "ESW_SET_LEARNING_CONF: %x %x\n",
+ configData.port, configData.enable);
+ ret = esw_port_learning_config(fep,
+ configData.port, configData.enable);
+ }
+ break;
+
+ case ESW_SET_IP_SNOOP_CONF:
+ {
+ struct eswIoctlIpsnoopConfig configData;
+
+ ret = copy_from_user(&configData,
+ ifr->ifr_data, sizeof(struct eswIoctlIpsnoopConfig));
+ if (ret)
+ return -EFAULT;
+ printk(KERN_INFO "ESW_SET_IP_SNOOP_CONF:: %x %x %x\n",
+ configData.num, configData.mode,
+ configData.ip_header_protocol);
+ ret = esw_ip_snoop_config(fep,
+ configData.num, configData.mode,
+ configData.ip_header_protocol);
+ }
+ break;
+
+ case ESW_SET_PORT_SNOOP_CONF:
+ {
+ struct eswIoctlPortsnoopConfig configData;
+
+ ret = copy_from_user(&configData,
+ ifr->ifr_data, sizeof(struct eswIoctlPortsnoopConfig));
+ if (ret)
+ return -EFAULT;
+ printk(KERN_INFO "ESW_SET_PORT_SNOOP_CONF:: %x %x %x %x\n",
+ configData.num, configData.mode,
+ configData.compare_port, configData.compare_num);
+ ret = esw_tcpudp_port_snoop_config(fep,
+ configData.num, configData.mode,
+ configData.compare_port,
+ configData.compare_num);
+ }
+ break;
+
+ case ESW_SET_PORT_MIRROR_CONF:
+ {
+ struct eswIoctlPortMirrorConfig configData;
+
+ ret = copy_from_user(&configData,
+ ifr->ifr_data, sizeof(struct eswIoctlPortMirrorConfig));
+ if (ret)
+ return -EFAULT;
+ printk(KERN_INFO "ESW_SET_PORT_MIRROR_CONF:: %x %x %x "
+ "%s %s\n %x %x %x %x %x %x\n",
+ configData.mirror_port, configData.port,
+ configData.mirror_enable,
+ configData.src_mac, configData.des_mac,
+ configData.egress_en, configData.ingress_en,
+ configData.egress_mac_src_en,
+ configData.egress_mac_des_en,
+ configData.ingress_mac_src_en,
+ configData.ingress_mac_des_en);
+ ret = esw_port_mirroring_config(fep,
+ configData.mirror_port, configData.port,
+ configData.mirror_enable,
+ configData.src_mac, configData.des_mac,
+ configData.egress_en, configData.ingress_en,
+ configData.egress_mac_src_en,
+ configData.egress_mac_des_en,
+ configData.ingress_mac_src_en,
+ configData.ingress_mac_des_en);
+ }
+ break;
+
+ case ESW_SET_PIRORITY_VLAN:
+ {
+ struct eswIoctlPriorityVlanConfig configData;
+
+ ret = copy_from_user(&configData,
+ ifr->ifr_data,
+ sizeof(struct eswIoctlPriorityVlanConfig));
+ if (ret)
+ return -EFAULT;
+
+ ret = esw_framecalssify_vlan_priority_lookup(fep,
+ configData.port, configData.func_enable,
+ configData.vlan_pri_table_num,
+ configData.vlan_pri_table_value);
+ }
+ break;
+
+ case ESW_SET_PIRORITY_IP:
+ {
+ struct eswIoctlPriorityIPConfig configData;
+
+ ret = copy_from_user(&configData,
+ ifr->ifr_data, sizeof(struct eswIoctlPriorityIPConfig));
+ if (ret)
+ return -EFAULT;
+
+ ret = esw_framecalssify_ip_priority_lookup(fep,
+ configData.port, configData.func_enable,
+ configData.ipv4_en, configData.ip_priority_num,
+ configData.ip_priority_value);
+ }
+ break;
+
+ case ESW_SET_PIRORITY_MAC:
+ {
+ struct eswIoctlPriorityMacConfig configData;
+
+ ret = copy_from_user(&configData,
+ ifr->ifr_data,
+ sizeof(struct eswIoctlPriorityMacConfig));
+ if (ret)
+ return -EFAULT;
+
+ ret = esw_framecalssify_mac_priority_lookup(fep,
+ configData.port);
+ }
+ break;
+
+ case ESW_SET_PIRORITY_DEFAULT:
+ {
+ struct eswIoctlPriorityDefaultConfig configData;
+
+ ret = copy_from_user(&configData,
+ ifr->ifr_data,
+ sizeof(struct eswIoctlPriorityDefaultConfig));
+ if (ret)
+ return -EFAULT;
+
+ ret = esw_frame_calssify_priority_init(fep,
+ configData.port, configData.priority_value);
+ }
+ break;
+
+ case ESW_SET_P0_FORCED_FORWARD:
+ {
+ struct eswIoctlP0ForcedForwardConfig configData;
+
+ ret = copy_from_user(&configData,
+ ifr->ifr_data,
+ sizeof(struct eswIoctlP0ForcedForwardConfig));
+ if (ret)
+ return -EFAULT;
+
+ ret = esw_forced_forward(fep, configData.port1,
+ configData.port2, configData.enable);
+ }
+ break;
+
+ case ESW_SET_BRIDGE_CONFIG:
+ {
+ unsigned long configData;
+
+ ret = copy_from_user(&configData,
+ ifr->ifr_data, sizeof(unsigned long));
+ if (ret)
+ return -EFAULT;
+
+ esw_bridge_port_configure(fep, configData);
+ }
+ break;
+
+ case ESW_SET_SWITCH_MODE:
+ {
+ unsigned long configData;
+
+ ret = copy_from_user(&configData,
+ ifr->ifr_data, sizeof(unsigned long));
+ if (ret)
+ return -EFAULT;
+
+ esw_switch_mode_configure(fep, configData);
+ }
+ break;
+
+ case ESW_SET_OUTPUT_QUEUE_MEMORY:
+ {
+ struct eswIoctlOutputQueue configData;
+
+ ret = copy_from_user(&configData,
+ ifr->ifr_data, sizeof(struct eswIoctlOutputQueue));
+ if (ret)
+ return -EFAULT;
+
+ printk(KERN_INFO "ESW_SET_OUTPUT_QUEUE_MEMORY:: %#x \n"
+ "%#lx %#lx %#lx %#lx\n"
+ "%#lx %#lx %#lx\n",
+ configData.fun_num,
+ configData.sOutputQueue.ESW_MMSR,
+ configData.sOutputQueue.ESW_LMT,
+ configData.sOutputQueue.ESW_LFC,
+ configData.sOutputQueue.ESW_PCSR,
+ configData.sOutputQueue.ESW_IOSR,
+ configData.sOutputQueue.ESW_QWT,
+ configData.sOutputQueue.ESW_P0BCT);
+ ret = esw_set_output_queue_memory(fep,
+ configData.fun_num, &configData.sOutputQueue);
+ }
+ break;
+
+ case ESW_SET_VLAN_OUTPUT_PROCESS:
+ {
+ struct eswIoctlVlanOutputConfig configData;
+
+ ret = copy_from_user(&configData,
+ ifr->ifr_data, sizeof(struct eswIoctlVlanOutputConfig));
+ if (ret)
+ return -EFAULT;
+
+ printk(KERN_INFO "ESW_SET_VLAN_OUTPUT_PROCESS: %x %x\n",
+ configData.port, configData.mode);
+ ret = esw_vlan_output_process(fep,
+ configData.port, configData.mode);
+ }
+ break;
+
+ case ESW_SET_VLAN_INPUT_PROCESS:
+ {
+ struct eswIoctlVlanInputConfig configData;
+
+ ret = copy_from_user(&configData,
+ ifr->ifr_data,
+ sizeof(struct eswIoctlVlanInputConfig));
+ if (ret)
+ return -EFAULT;
+
+ printk(KERN_INFO "ESW_SET_VLAN_INPUT_PROCESS: %x %x"
+ "%x %x %x %x\n",
+ configData.port, configData.mode,
+ configData.port_vlanid,
+ configData.vlan_verify_en,
+ configData.vlan_domain_num,
+ configData.vlan_domain_port);
+ ret = esw_vlan_input_process(fep, configData.port,
+ configData.mode, configData.port_vlanid,
+ configData.vlan_verify_en,
+ configData.vlan_domain_num,
+ configData.vlan_domain_port);
+ }
+ break;
+
+ case ESW_SET_VLAN_DOMAIN_VERIFICATION:
+ {
+ struct eswIoctlVlanVerificationConfig configData;
+
+ ret = copy_from_user(&configData,
+ ifr->ifr_data,
+ sizeof(struct eswIoctlVlanVerificationConfig));
+ if (ret)
+ return -EFAULT;
+
+ printk("ESW_SET_VLAN_DOMAIN_VERIFICATION: "
+ "%x %x %x\n",
+ configData.port,
+ configData.vlan_domain_verify_en,
+ configData.vlan_discard_unknown_en);
+ ret = esw_set_vlan_verification(
+ fep, configData.port,
+ configData.vlan_domain_verify_en,
+ configData.vlan_discard_unknown_en);
+ }
+ break;
+
+ case ESW_SET_VLAN_RESOLUTION_TABLE:
+ {
+ struct eswIoctlVlanResoultionTable configData;
+
+ ret = copy_from_user(&configData,
+ ifr->ifr_data,
+ sizeof(struct eswIoctlVlanResoultionTable));
+ if (ret)
+ return -EFAULT;
+
+ printk(KERN_INFO "ESW_SET_VLAN_RESOLUTION_TABLE: "
+ "%x %x %x\n",
+ configData.port_vlanid,
+ configData.vlan_domain_num,
+ configData.vlan_domain_port);
+
+ ret = esw_set_vlan_resolution_table(
+ fep, configData.port_vlanid,
+ configData.vlan_domain_num,
+ configData.vlan_domain_port);
+
+ }
+ break;
+ case ESW_UPDATE_STATIC_MACTABLE:
+ {
+ struct eswIoctlUpdateStaticMACtable configData;
+
+ ret = copy_from_user(&configData,
+ ifr->ifr_data,
+ sizeof(struct eswIoctlUpdateStaticMACtable));
+ if (ret)
+ return -EFAULT;
+
+ printk(KERN_INFO "%s: ESW_UPDATE_STATIC_MACTABLE: mac %s, "
+ "port %x, priority %x\n", __func__,
+ configData.mac_addr,
+ configData.port,
+ configData.priority);
+ ret = esw_update_atable_static(configData.mac_addr,
+ configData.port, configData.priority, fep);
+ }
+ break;
+
+ case ESW_CLEAR_ALL_MACTABLE:
+ {
+ esw_clear_atable(fep);
+ }
+ break;
+
+ case ESW_GET_STATISTICS_STATUS:
+ {
+ struct esw_statistics_status Statistics;
+ ret = esw_get_statistics_status(fep, &Statistics);
+ if (ret != 0) {
+ printk(KERN_ERR "%s: cmd %x fail\n",
+ __func__, cmd);
+ return -1;
+ }
+
+ ret = copy_to_user(ifr->ifr_data, &Statistics,
+ sizeof(struct esw_statistics_status));
+ if (ret)
+ return -EFAULT;
+ }
+ break;
+
+ case ESW_GET_PORT0_STATISTICS_STATUS:
+ {
+ struct esw_port_statistics_status PortStatistics;
+
+ ret = esw_get_port_statistics_status(fep,
+ 0, &PortStatistics);
+ if (ret != 0) {
+ printk(KERN_ERR "%s: cmd %x fail\n",
+ __func__, cmd);
+ return -1;
+ }
+
+ ret = copy_to_user(ifr->ifr_data, &PortStatistics,
+ sizeof(struct esw_port_statistics_status));
+ if (ret)
+ return -EFAULT;
+ }
+ break;
+
+ case ESW_GET_PORT1_STATISTICS_STATUS:
+ {
+ struct esw_port_statistics_status PortStatistics;
+
+ ret = esw_get_port_statistics_status(fep,
+ 1, &PortStatistics);
+ if (ret != 0) {
+ printk(KERN_ERR "%s: cmd %x fail\n",
+ __func__, cmd);
+ return -1;
+ }
+
+ ret = copy_to_user(ifr->ifr_data, &PortStatistics,
+ sizeof(struct esw_port_statistics_status));
+ if (ret)
+ return -EFAULT;
+ }
+ break;
+
+ case ESW_GET_PORT2_STATISTICS_STATUS:
+ {
+ struct esw_port_statistics_status PortStatistics;
+
+ ret = esw_get_port_statistics_status(fep,
+ 2, &PortStatistics);
+ if (ret != 0) {
+ printk(KERN_ERR "%s: cmd %x fail\n",
+ __func__, cmd);
+ return -1;
+ }
+
+ ret = copy_to_user(ifr->ifr_data, &PortStatistics,
+ sizeof(struct esw_port_statistics_status));
+ if (ret)
+ return -EFAULT;
+ }
+ break;
+
+ case ESW_GET_LEARNING_CONF:
+ {
+ unsigned long PortLearning;
+
+ esw_get_port_learning(fep, &PortLearning);
+ ret = copy_to_user(ifr->ifr_data, &PortLearning,
+ sizeof(unsigned long));
+ if (ret)
+ return -EFAULT;
+ }
+ break;
+
+ case ESW_GET_BLOCKING_CONF:
+ {
+ unsigned long PortBlocking;
+
+ esw_get_port_blocking(fep, &PortBlocking);
+ ret = copy_to_user(ifr->ifr_data, &PortBlocking,
+ sizeof(unsigned long));
+ if (ret)
+ return -EFAULT;
+ }
+ break;
+
+ case ESW_GET_MULTICAST_CONF:
+ {
+ unsigned long PortMulticast;
+
+ esw_get_port_multicast(fep, &PortMulticast);
+ ret = copy_to_user(ifr->ifr_data, &PortMulticast,
+ sizeof(unsigned long));
+ if (ret)
+ return -EFAULT;
+ }
+ break;
+
+ case ESW_GET_BROADCAST_CONF:
+ {
+ unsigned long PortBroadcast;
+
+ esw_get_port_broadcast(fep, &PortBroadcast);
+ ret = copy_to_user(ifr->ifr_data, &PortBroadcast,
+ sizeof(unsigned long));
+ if (ret)
+ return -EFAULT;
+ }
+ break;
+
+ case ESW_GET_PORTENABLE_CONF:
+ {
+ unsigned long PortEnable;
+
+ esw_get_port_enable(fep, &PortEnable);
+ ret = copy_to_user(ifr->ifr_data, &PortEnable,
+ sizeof(unsigned long));
+ if (ret)
+ return -EFAULT;
+ }
+ break;
+
+ case ESW_GET_IP_SNOOP_CONF:
+ {
+ unsigned long ESW_IPSNP[8];
+
+ esw_get_ip_snoop_config(fep, (unsigned long *)ESW_IPSNP);
+ ret = copy_to_user(ifr->ifr_data, ESW_IPSNP,
+ (8 * sizeof(unsigned long)));
+ if (ret)
+ return -EFAULT;
+ }
+ break;
+
+ case ESW_GET_PORT_SNOOP_CONF:
+ {
+ unsigned long ESW_PSNP[8];
+
+ esw_get_tcpudp_port_snoop_config(fep,
+ (unsigned long *)ESW_PSNP);
+ ret = copy_to_user(ifr->ifr_data, ESW_PSNP,
+ (8 * sizeof(unsigned long)));
+ if (ret)
+ return -EFAULT;
+ }
+ break;
+
+ case ESW_GET_PORT_MIRROR_CONF:
+ {
+ struct eswIoctlPortMirrorStatus PortMirrorStatus;
+
+ esw_get_port_mirroring(fep, &PortMirrorStatus);
+ ret = copy_to_user(ifr->ifr_data, &PortMirrorStatus,
+ sizeof(struct eswIoctlPortMirrorStatus));
+ if (ret)
+ return -EFAULT;
+ }
+ break;
+
+ case ESW_GET_P0_FORCED_FORWARD:
+ {
+ unsigned long ForceForward;
+
+ esw_get_forced_forward(fep, &ForceForward);
+ ret = copy_to_user(ifr->ifr_data, &ForceForward,
+ sizeof(unsigned long));
+ if (ret)
+ return -EFAULT;
+ }
+ break;
+
+ case ESW_GET_SWITCH_MODE:
+ {
+ unsigned long Config;
+
+ esw_get_switch_mode(fep, &Config);
+ ret = copy_to_user(ifr->ifr_data, &Config,
+ sizeof(unsigned long));
+ if (ret)
+ return -EFAULT;
+ }
+ break;
+
+ case ESW_GET_BRIDGE_CONFIG:
+ {
+ unsigned long Config;
+
+ esw_get_bridge_port(fep, &Config);
+ ret = copy_to_user(ifr->ifr_data, &Config,
+ sizeof(unsigned long));
+ if (ret)
+ return -EFAULT;
+ }
+ break;
+ case ESW_GET_OUTPUT_QUEUE_STATUS:
+ {
+ struct esw_output_queue_status Config;
+ esw_get_output_queue_status(fep,
+ &Config);
+ ret = copy_to_user(ifr->ifr_data, &Config,
+ sizeof(struct esw_output_queue_status));
+ if (ret)
+ return -EFAULT;
+ }
+ break;
+
+ case ESW_GET_VLAN_OUTPUT_PROCESS:
+ {
+ unsigned long Config;
+
+ esw_get_vlan_output_config(fep, &Config);
+ ret = copy_to_user(ifr->ifr_data, &Config,
+ sizeof(unsigned long));
+ if (ret)
+ return -EFAULT;
+ }
+ break;
+
+ case ESW_GET_VLAN_INPUT_PROCESS:
+ {
+ struct eswIoctlVlanInputStatus Config;
+
+ esw_get_vlan_input_config(fep, &Config);
+ ret = copy_to_user(ifr->ifr_data, &Config,
+ sizeof(struct eswIoctlVlanInputStatus));
+ if (ret)
+ return -EFAULT;
+ }
+ break;
+
+ case ESW_GET_VLAN_RESOLUTION_TABLE:
+ {
+ unsigned long Config;
+ unsigned char ConfigData;
+ ret = copy_from_user(&ConfigData,
+ ifr->ifr_data,
+ sizeof(unsigned char));
+ if (ret)
+ return -EFAULT;
+
+ printk(KERN_INFO "ESW_GET_VLAN_RESOLUTION_TABLE: %x \n",
+ ConfigData);
+
+ esw_get_vlan_resolution_table(fep, ConfigData, &Config);
+
+ ret = copy_to_user(ifr->ifr_data, &Config,
+ sizeof(unsigned long));
+ if (ret)
+ return -EFAULT;
+ }
+ break;
+
+ case ESW_GET_VLAN_DOMAIN_VERIFICATION:
+ {
+ unsigned long Config;
+
+ esw_get_vlan_verification(fep, &Config);
+ ret = copy_to_user(ifr->ifr_data, &Config,
+ sizeof(unsigned long));
+ if (ret)
+ return -EFAULT;
+ }
+ break;
+ /*------------------------------------------------------------------*/
+ default:
+ return -EOPNOTSUPP;
+ }
+
+
+ return ret;
+}
+
+static int
+switch_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct switch_enet_private *fep;
+ struct switch_t *fecp;
+ struct cbd_t *bdp;
+ void *bufaddr;
+ unsigned short status;
+ unsigned long flags;
+
+ fep = netdev_priv(dev);
+ fecp = (struct switch_t *)fep->hwp;
+
+ spin_lock_irqsave(&fep->hw_lock, flags);
+ /* Fill in a Tx ring entry */
+ bdp = fep->cur_tx;
+
+ status = bdp->cbd_sc;
+
+ if (status & BD_ENET_TX_READY) {
+ /*
+ * Ooops. All transmit buffers are full. Bail out.
+ * This should not happen, since dev->tbusy should be set.
+ */
+ printk(KERN_ERR "%s: tx queue full!.\n", dev->name);
+ spin_unlock_irqrestore(&fep->hw_lock, flags);
+ return NETDEV_TX_BUSY;
+ }
+
+ /* Clear all of the status flags */
+ status &= ~BD_ENET_TX_STATS;
+
+ /* Set buffer length and buffer pointer */
+ bufaddr = skb->data;
+ bdp->cbd_datlen = skb->len;
+
+ /*
+ * On some FEC implementations data must be aligned on
+ * 4-byte boundaries. Use bounce buffers to copy data
+ * and get it aligned. Ugh.
+ */
+ if ((unsigned long) bufaddr & FEC_ALIGNMENT) {
+ unsigned int index;
+ index = bdp - fep->tx_bd_base;
+ memcpy(fep->tx_bounce[index],
+ (void *)skb->data, skb->len);
+ bufaddr = fep->tx_bounce[index];
+ }
+
+#ifdef CONFIG_ARCH_MXS
+ swap_buffer(bufaddr, skb->len);
+#endif
+
+ /* Save skb pointer. */
+ fep->tx_skbuff[fep->skb_cur] = skb;
+
+ dev->stats.tx_bytes += skb->len;
+ fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK;
+
+ /*
+ * Push the data cache so the CPM does not get stale memory
+ * data.
+ */
+ bdp->cbd_bufaddr = dma_map_single(&dev->dev, bufaddr,
+ FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE);
+
+ /*
+ * Send it on its way. Tell FEC it's ready, interrupt when done,
+ * it's the last BD of the frame, and to put the CRC on the end.
+ */
+
+ status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
+ | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+ bdp->cbd_sc = status;
+#ifdef L2SWITCH_ENHANCED_BUFFER
+ bdp->bdu = 0x00000000;
+ bdp->ebd_status = TX_BD_INT | TX_BD_TS;
+#endif
+ dev->trans_start = jiffies;
+
+ /* Trigger transmission start */
+ fecp->fec_x_des_active = MCF_ESW_TDAR_X_DES_ACTIVE;
+
+ /* If this was the last BD in the ring,
+ * start at the beginning again.
+ */
+ if (status & BD_ENET_TX_WRAP)
+ bdp = fep->tx_bd_base;
+ else
+ bdp++;
+
+ if (bdp == fep->dirty_tx) {
+ fep->tx_full = 1;
+ netif_stop_queue(dev);
+ printk(KERN_ERR "%s: net stop\n", __func__);
+ }
+
+ fep->cur_tx = bdp;
+
+ spin_unlock_irqrestore(&fep->hw_lock, flags);
+
+ return 0;
+}
+
+static void
+switch_timeout(struct net_device *dev)
+{
+ struct switch_enet_private *fep = netdev_priv(dev);
+
+ printk(KERN_INFO "%s: transmit timed out.\n", dev->name);
+ dev->stats.tx_errors++;
+ {
+ int i;
+ struct cbd_t *bdp;
+
+ printk(KERN_INFO "Ring data dump: cur_tx %lx%s,"
+ "dirty_tx %lx cur_rx: %lx\n",
+ (unsigned long)fep->cur_tx, fep->tx_full ? " (full)" : "",
+ (unsigned long)fep->dirty_tx,
+ (unsigned long)fep->cur_rx);
+
+ bdp = fep->tx_bd_base;
+ printk(KERN_INFO " tx: %u buffers\n", TX_RING_SIZE);
+ for (i = 0 ; i < TX_RING_SIZE; i++) {
+ printk(KERN_INFO " %08x: %04x %04x %08x\n",
+ (uint) bdp,
+ bdp->cbd_sc,
+ bdp->cbd_datlen,
+ (int) bdp->cbd_bufaddr);
+ bdp++;
+ }
+
+ bdp = fep->rx_bd_base;
+ printk(KERN_INFO " rx: %lu buffers\n",
+ (unsigned long) RX_RING_SIZE);
+ for (i = 0 ; i < RX_RING_SIZE; i++) {
+ printk(KERN_INFO " %08x: %04x %04x %08x\n",
+ (uint) bdp,
+ bdp->cbd_sc,
+ bdp->cbd_datlen,
+ (int) bdp->cbd_bufaddr);
+ bdp++;
+ }
+ }
+ switch_restart(dev, fep->full_duplex);
+ netif_wake_queue(dev);
+}
+
+/*
+ * The interrupt handler.
+ * This is called from the MPC core interrupt.
+ */
+static irqreturn_t
+switch_enet_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct switch_enet_private *fep = netdev_priv(dev);
+ struct switch_t *fecp;
+ uint int_events;
+ irqreturn_t ret = IRQ_NONE;
+
+ fecp = (struct switch_t *)dev->base_addr;
+
+ /* Get the interrupt events that caused us to be here */
+ do {
+ int_events = fecp->switch_ievent;
+ fecp->switch_ievent = int_events;
+ /* Handle receive event in its own function. */
+
+ /* Transmit OK, or non-fatal error. Update the buffer
+ * descriptors. FEC handles all errors, we just discover
+ * them as part of the transmit process.
+ */
+ if (int_events & MCF_ESW_ISR_LRN) {
+ if (fep->learning_irqhandle_enable)
+ esw_atable_dynamicms_learn_migration(
+ fep, fep->currTime);
+ ret = IRQ_HANDLED;
+ }
+
+ if (int_events & MCF_ESW_ISR_OD0)
+ ret = IRQ_HANDLED;
+
+ if (int_events & MCF_ESW_ISR_OD1)
+ ret = IRQ_HANDLED;
+
+ if (int_events & MCF_ESW_ISR_OD2)
+ ret = IRQ_HANDLED;
+
+ if (int_events & MCF_ESW_ISR_RXB)
+ ret = IRQ_HANDLED;
+
+ if (int_events & MCF_ESW_ISR_RXF) {
+ ret = IRQ_HANDLED;
+ switch_enet_rx(dev);
+ }
+
+ if (int_events & MCF_ESW_ISR_TXB)
+ ret = IRQ_HANDLED;
+
+ if (int_events & MCF_ESW_ISR_TXF) {
+ ret = IRQ_HANDLED;
+ switch_enet_tx(dev);
+ }
+
+ } while (int_events);
+
+ return ret;
+}
+
+
+static void
+switch_enet_tx(struct net_device *dev)
+{
+ struct switch_enet_private *fep;
+ struct cbd_t *bdp;
+ unsigned short status;
+ struct sk_buff *skb;
+
+ fep = netdev_priv(dev);
+ spin_lock(&fep->hw_lock);
+ bdp = fep->dirty_tx;
+
+ while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
+ if (bdp == fep->cur_tx && fep->tx_full == 0)
+ break;
+
+ dma_unmap_single(&dev->dev, bdp->cbd_bufaddr,
+ FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE);
+ bdp->cbd_bufaddr = 0;
+ skb = fep->tx_skbuff[fep->skb_dirty];
+ /* Check for errors */
+ if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
+ BD_ENET_TX_RL | BD_ENET_TX_UN |
+ BD_ENET_TX_CSL)) {
+ dev->stats.tx_errors++;
+ if (status & BD_ENET_TX_HB) /* No heartbeat */
+ dev->stats.tx_heartbeat_errors++;
+ if (status & BD_ENET_TX_LC) /* Late collision */
+ dev->stats.tx_window_errors++;
+ if (status & BD_ENET_TX_RL) /* Retrans limit */
+ dev->stats.tx_aborted_errors++;
+ if (status & BD_ENET_TX_UN) /* Underrun */
+ dev->stats.tx_fifo_errors++;
+ if (status & BD_ENET_TX_CSL) /* Carrier lost */
+ dev->stats.tx_carrier_errors++;
+ } else {
+ dev->stats.tx_packets++;
+ }
+
+ if (status & BD_ENET_TX_READY)
+ printk(KERN_ERR "HEY! "
+ "Enet xmit interrupt and TX_READY.\n");
+ /*
+ * Deferred means some collisions occurred during transmit,
+ * but we eventually sent the packet OK.
+ */
+ if (status & BD_ENET_TX_DEF)
+ dev->stats.collisions++;
+
+ /* Free the sk buffer associated with this last transmit */
+ dev_kfree_skb_any(skb);
+ fep->tx_skbuff[fep->skb_dirty] = NULL;
+ fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK;
+
+ /* Update pointer to next buffer descriptor to be transmitted */
+ if (status & BD_ENET_TX_WRAP)
+ bdp = fep->tx_bd_base;
+ else
+ bdp++;
+
+ /*
+ * Since we have freed up a buffer, the ring is no longer
+ * full.
+ */
+ if (fep->tx_full) {
+ fep->tx_full = 0;
+ printk(KERN_ERR "%s: tx full is zero\n", __func__);
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+ }
+ }
+ fep->dirty_tx = bdp;
+ spin_unlock(&fep->hw_lock);
+}
+
+
+/*
+ * During a receive, the cur_rx points to the current incoming buffer.
+ * When we update through the ring, if the next incoming buffer has
+ * not been given to the system, we just set the empty indicator,
+ * effectively tossing the packet.
+ */
+static void
+switch_enet_rx(struct net_device *dev)
+{
+ struct switch_enet_private *fep;
+ struct switch_t *fecp;
+ struct cbd_t *bdp;
+ unsigned short status;
+ struct sk_buff *skb;
+ ushort pkt_len;
+ __u8 *data;
+
+#ifdef CONFIG_M532x
+ flush_cache_all();
+#endif
+
+ fep = netdev_priv(dev);
+ fecp = (struct switch_t *)fep->hwp;
+
+ spin_lock(&fep->hw_lock);
+ /*
+ * First, grab all of the stats for the incoming packet.
+ * These get messed up if we get called due to a busy condition.
+ */
+ bdp = fep->cur_rx;
+#ifdef L2SWITCH_ENHANCED_BUFFER
+ printk(KERN_INFO "%s: cbd_sc %x cbd_datlen %x cbd_bufaddr %x "
+ "ebd_status %x bdu %x length_proto_type %x "
+ "payload_checksum %x\n",
+ __func__, bdp->cbd_sc, bdp->cbd_datlen,
+ bdp->cbd_bufaddr, bdp->ebd_status, bdp->bdu,
+ bdp->length_proto_type, bdp->payload_checksum);
+#endif
+
+while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
+ /*
+ * Since we have allocated space to hold a complete frame,
+ * the last indicator should be set.
+ */
+ if ((status & BD_ENET_RX_LAST) == 0)
+ printk(KERN_INFO "SWITCH ENET: rcv is not +last\n");
+
+ if (!fep->opened)
+ goto rx_processing_done;
+
+ /* Check for errors. */
+ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
+ BD_ENET_RX_CR | BD_ENET_RX_OV)) {
+ dev->stats.rx_errors++;
+ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
+ /* Frame too long or too short. */
+ dev->stats.rx_length_errors++;
+ }
+ if (status & BD_ENET_RX_NO) /* Frame alignment */
+ dev->stats.rx_frame_errors++;
+ if (status & BD_ENET_RX_CR) /* CRC Error */
+ dev->stats.rx_crc_errors++;
+ if (status & BD_ENET_RX_OV) /* FIFO overrun */
+ dev->stats.rx_fifo_errors++;
+ }
+
+ /*
+ * Report late collisions as a frame error.
+ * On this error, the BD is closed, but we don't know what we
+ * have in the buffer. So, just drop this frame on the floor.
+ */
+ if (status & BD_ENET_RX_CL) {
+ dev->stats.rx_errors++;
+ dev->stats.rx_frame_errors++;
+ goto rx_processing_done;
+ }
+
+ /* Process the incoming frame */
+ dev->stats.rx_packets++;
+ pkt_len = bdp->cbd_datlen;
+ dev->stats.rx_bytes += pkt_len;
+ data = (__u8 *)__va(bdp->cbd_bufaddr);
+
+ dma_unmap_single(NULL, bdp->cbd_bufaddr, bdp->cbd_datlen,
+ DMA_FROM_DEVICE);
+#ifdef CONFIG_ARCH_MXS
+ swap_buffer(data, pkt_len);
+#endif
+ /*
+ * This does 16 byte alignment, exactly what we need.
+ * The packet length includes FCS, but we don't want to
+ * include that when passing upstream as it messes up
+ * bridging applications.
+ */
+ skb = dev_alloc_skb(pkt_len - 4 + NET_IP_ALIGN);
+ if (unlikely(!skb)) {
+ printk("%s: Memory squeeze, dropping packet.\n",
+ dev->name);
+ dev->stats.rx_dropped++;
+ } else {
+ skb_reserve(skb, NET_IP_ALIGN);
+ skb_put(skb, pkt_len - 4); /* Make room */
+ skb_copy_to_linear_data(skb, data, pkt_len - 4);
+ skb->protocol = eth_type_trans(skb, dev);
+ netif_rx(skb);
+ }
+
+ bdp->cbd_bufaddr = dma_map_single(NULL, data, bdp->cbd_datlen,
+ DMA_FROM_DEVICE);
+
+rx_processing_done:
+
+ /* Clear the status flags for this buffer */
+ status &= ~BD_ENET_RX_STATS;
+
+ /* Mark the buffer empty */
+ status |= BD_ENET_RX_EMPTY;
+ bdp->cbd_sc = status;
+
+ /* Update BD pointer to next entry */
+ if (status & BD_ENET_RX_WRAP)
+ bdp = fep->rx_bd_base;
+ else
+ bdp++;
+
+ /*
+ * Doing this here will keep the FEC running while we process
+ * incoming frames. On a heavily loaded network, we should be
+ * able to keep up at the expense of system resources.
+ */
+ fecp->fec_r_des_active = MCF_ESW_RDAR_R_DES_ACTIVE;
+ } /* while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) */
+ fep->cur_rx = bdp;
+
+ spin_unlock(&fep->hw_lock);
+}
+
+#ifdef FEC_PHY
+static int fec_mdio_transfer(struct mii_bus *bus, int phy_id,
+ int reg, int regval)
+{
+ struct net_device *dev = bus->priv;
+ unsigned long flags;
+ struct switch_enet_private *fep;
+ int tries = 100;
+ int retval = 0;
+
+ fep = netdev_priv(dev);
+ spin_lock_irqsave(&fep->mii_lock, flags);
+
+ regval |= phy_id << 23;
+ writel(regval, fep->enet_addr + MCF_FEC_MMFR0);
+
+ /* wait for it to finish, this takes about 23 us on lite5200b */
+ while (!(readl(fep->enet_addr + MCF_FEC_EIR0) & FEC_ENET_MII)
+ && --tries)
+ udelay(5);
+
+ if (!tries) {
+ printk(KERN_ERR "%s timeout\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ writel(FEC_ENET_MII, fep->enet_addr + MCF_FEC_EIR0);
+ retval = readl(fep->enet_addr + MCF_FEC_MMFR0);
+ spin_unlock_irqrestore(&fep->mii_lock, flags);
+
+ return retval;
+}
+
+/*
+ * Phy section
+ */
+static void switch_adjust_link(struct net_device *dev)
+{
+ struct switch_enet_private *fep = netdev_priv(dev);
+ struct phy_device *phy_dev = fep->phy_dev;
+ unsigned long flags;
+ int status_change = 0;
+
+ phy_dev = g_phy_dev;
+ spin_lock_irqsave(&fep->hw_lock, flags);
+
+ /* Prevent a state halted on mii error */
+ if (fep->mii_timeout && phy_dev->state == PHY_HALTED) {
+ phy_dev->state = PHY_RESUMING;
+ goto spin_unlock;
+ }
+
+ /* Duplex link change */
+ if (phy_dev->link) {
+ if (fep->full_duplex != phy_dev->duplex) {
+ switch_restart(dev, phy_dev->duplex);
+ status_change = 1;
+ }
+ }
+
+ /* Link on or off change */
+ if (phy_dev->link != fep->link) {
+ fep->link = phy_dev->link;
+ if (phy_dev->link)
+ switch_restart(dev, phy_dev->duplex);
+ else
+ switch_stop(dev);
+ status_change = 1;
+ }
+
+spin_unlock:
+ spin_unlock_irqrestore(&fep->hw_lock, flags);
+
+ if (status_change)
+ phy_print_status(phy_dev);
+}
+
+/*
+ * NOTE: a MII transaction is during around 25 us, so polling it...
+ */
+static int fec_enet_mdio_poll(struct switch_enet_private *fep)
+ {
+ int timeout = FEC_MII_TIMEOUT;
+ unsigned int reg = 0;
+
+ fep->mii_timeout = 0;
+
+ /* wait for end of transfer */
+ reg = readl(fep->hwp + FEC_IEVENT);
+ while (!(reg & FEC_ENET_MII)) {
+ msleep(1);
+ if (timeout-- < 0) {
+ fep->mii_timeout = 1;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+ struct switch_enet_private *fep = netdev_priv(bus->priv);
+
+
+ /* clear MII end of transfer bit */
+ writel(FEC_ENET_MII, fep->enet_addr + FEC_IEVENT
+ / sizeof(unsigned long));
+
+ /* start a read op */
+ writel(FEC_MMFR_ST | FEC_MMFR_OP_READ |
+ FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) |
+ FEC_MMFR_TA, fep->enet_addr + FEC_MII_DATA
+ / sizeof(unsigned long));
+
+ fec_enet_mdio_poll(fep);
+
+ /* return value */
+ return FEC_MMFR_DATA(readl(fep->enet_addr + FEC_MII_DATA
+ / sizeof(unsigned long)));
+}
+
+static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
+ u16 value)
+{
+ struct switch_enet_private *fep = netdev_priv(bus->priv);
+
+ /* clear MII end of transfer bit */
+ writel(FEC_ENET_MII, fep->enet_addr + FEC_IEVENT
+ / sizeof(unsigned long));
+
+ /* start a read op */
+ writel(FEC_MMFR_ST | FEC_MMFR_OP_READ |
+ FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) |
+ FEC_MMFR_TA | FEC_MMFR_DATA(value),
+ fep->enet_addr + FEC_MII_DATA / sizeof(unsigned long));
+
+ fec_enet_mdio_poll(fep);
+
+ return 0;
+}
+
+static int fec_enet_mdio_reset(struct mii_bus *bus)
+{
+ return 0;
+}
+
+static struct mii_bus *fec_enet_mii_init(struct net_device *dev)
+{
+ struct switch_enet_private *fep = netdev_priv(dev);
+ int err = -ENXIO, i;
+
+ fep->mii_timeout = 0;
+ /*
+ * Set MII speed to 2.5 MHz (= clk_get_rate() / 2 * phy_speed)
+ */
+ fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000) << 1;
+#ifdef CONFIG_ARCH_MXS
+ /* Can't get phy(8720) ID when set to 2.5M on MX28, lower it */
+ fep->phy_speed <<= 2;
+#endif
+ writel(fep->phy_speed, fep->enet_addr + FEC_MII_SPEED
+ / sizeof(unsigned long));
+
+ fep->mii_bus = mdiobus_alloc();
+ if (fep->mii_bus == NULL) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ fep->mii_bus->name = "fec_enet_mii_bus";
+ fep->mii_bus->read = fec_enet_mdio_read;
+ fep->mii_bus->write = fec_enet_mdio_write;
+ fep->mii_bus->reset = fec_enet_mdio_reset;
+ snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%x", fep->pdev->id);
+ fep->mii_bus->priv = dev;
+
+ fep->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (!fep->mii_bus->irq) {
+ err = -ENOMEM;
+ goto err_out_free_mdiobus;
+ }
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ fep->mii_bus->irq[i] = PHY_POLL;
+
+ if (mdiobus_register(fep->mii_bus)) {
+ goto err_out_free_mdio_irq;
+ }
+
+ return fep->mii_bus;
+
+err_out_free_mdio_irq:
+ kfree(fep->mii_bus->irq);
+err_out_free_mdiobus:
+ mdiobus_free(fep->mii_bus);
+err_out:
+ return ERR_PTR(err);
+}
+#endif
+
+static int fec_enet_get_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
+{
+ struct switch_enet_private *fep = netdev_priv(dev);
+ struct phy_device *phydev = fep->phy_dev;
+
+ if (!phydev)
+ return -ENODEV;
+
+ return phy_ethtool_gset(phydev, cmd);
+}
+
+static int fec_enet_set_settings(struct net_device *dev,
+ struct ethtool_cmd *cmd)
+{
+ struct switch_enet_private *fep = netdev_priv(dev);
+ struct phy_device *phydev = fep->phy_dev;
+
+ if (!phydev)
+ return -ENODEV;
+
+ return phy_ethtool_sset(phydev, cmd);
+}
+
+static void fec_enet_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ struct switch_enet_private *fep = netdev_priv(dev);
+
+ strcpy(info->driver, fep->pdev->dev.driver->name);
+ strcpy(info->version, "Revision: 1.0");
+ strcpy(info->bus_info, dev_name(&dev->dev));
+}
+
+#ifdef FEC_PHY
+static int fec_switch_init_phy(struct net_device *dev)
+{
+ struct switch_enet_private *priv = netdev_priv(dev);
+ struct phy_device *phydev = NULL;
+ int i;
+
+ /* search for connect PHY device */
+ for (i = 0; i < PHY_MAX_ADDR; i++) {
+ struct phy_device *const tmp_phydev =
+ priv->mdio_bus->phy_map[i];
+
+ if (!tmp_phydev) {
+#ifdef FEC_DEBUG
+ printk(KERN_INFO "%s no PHY here at"
+ "mii_bus->phy_map[%d]\n",
+ __func__, i);
+#endif
+ continue; /* no PHY here... */
+ }
+
+#ifdef CONFIG_FEC_SHARED_PHY
+ if (priv->index == 0)
+ phydev = tmp_phydev;
+ else if (priv->index == 1) {
+ if (startnode == 1) {
+ phydev = tmp_phydev;
+ startnode = 0;
+ } else {
+ startnode++;
+ continue;
+ }
+ } else
+ printk(KERN_INFO "%s now we do not"
+ "support (%d) more than"
+ "2 phys shared "
+ "one mdio bus\n",
+ __func__, startnode);
+#else
+ phydev = tmp_phydev;
+#endif
+#ifdef FEC_DEBUG
+ printk(KERN_INFO "%s find PHY here at"
+ "mii_bus->phy_map[%d]\n",
+ __func__, i);
+#endif
+ break; /* found it */
+ }
+
+ /* now we are supposed to have a proper phydev, to attach to... */
+ if (!phydev) {
+ printk(KERN_INFO "%s: Don't found any phy device at all\n",
+ dev->name);
+ return -ENODEV;
+ }
+
+ priv->link = PHY_DOWN;
+ priv->old_link = PHY_DOWN;
+ priv->speed = 0;
+ priv->duplex = -1;
+
+ phydev = phy_connect(dev, dev_name(&phydev->dev),
+ &switch_adjust_link, 0, PHY_INTERFACE_MODE_MII);
+ if (IS_ERR(phydev)) {
+ printk(KERN_ERR " %s phy_connect failed\n", __func__);
+ return PTR_ERR(phydev);
+ }
+
+ printk(KERN_INFO "attached phy %i to driver %s\n",
+ phydev->addr, phydev->drv->name);
+
+ priv->phydev = phydev;
+ g_phy_dev = phydev;
+
+ return 0;
+}
+#endif
+
+static void fec_enet_free_buffers(struct net_device *dev)
+{
+ struct switch_enet_private *fep = netdev_priv(dev);
+ int i;
+ struct sk_buff *skb;
+ struct cbd_t *bdp;
+
+ bdp = fep->rx_bd_base;
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ skb = fep->rx_skbuff[i];
+
+ if (bdp->cbd_bufaddr)
+ dma_unmap_single(&dev->dev, bdp->cbd_bufaddr,
+ FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
+ if (skb)
+ dev_kfree_skb(skb);
+ bdp++;
+ }
+
+ bdp = fep->tx_bd_base;
+ for (i = 0; i < TX_RING_SIZE; i++)
+ kfree(fep->tx_bounce[i]);
+}
+
+static int fec_enet_alloc_buffers(struct net_device *dev)
+{
+ struct switch_enet_private *fep = netdev_priv(dev);
+ int i;
+ struct sk_buff *skb;
+ struct cbd_t *bdp;
+
+ bdp = fep->rx_bd_base;
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ skb = dev_alloc_skb(SWITCH_ENET_RX_FRSIZE);
+ if (!skb) {
+ fec_enet_free_buffers(dev);
+ return -ENOMEM;
+ }
+ fep->rx_skbuff[i] = skb;
+
+ bdp->cbd_bufaddr = dma_map_single(&dev->dev, skb->data,
+ SWITCH_ENET_RX_FRSIZE, DMA_FROM_DEVICE);
+ bdp->cbd_sc = BD_ENET_RX_EMPTY;
+#ifdef L2SWITCH_ENHANCED_BUFFER
+ bdp->bdu = 0x00000000;
+ bdp->ebd_status = RX_BD_INT;
+#endif
+#ifdef CONFIG_FEC_1588
+ bdp->cbd_esc = BD_ENET_RX_INT;
+#endif
+ bdp++;
+ }
+
+ /* Set the last buffer to wrap. */
+ bdp--;
+ bdp->cbd_sc |= BD_SC_WRAP;
+
+ bdp = fep->tx_bd_base;
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ fep->tx_bounce[i] = kmalloc(SWITCH_ENET_TX_FRSIZE, GFP_KERNEL);
+
+ bdp->cbd_sc = 0;
+ bdp->cbd_bufaddr = 0;
+#ifdef CONFIG_FEC_1588
+ bdp->cbd_esc = BD_ENET_TX_INT;
+#endif
+ bdp++;
+ }
+
+ /* Set the last buffer to wrap. */
+ bdp--;
+ bdp->cbd_sc |= BD_SC_WRAP;
+
+ return 0;
+}
+
+static int
+switch_enet_open(struct net_device *dev)
+{
+ int ret;
+ struct switch_enet_private *fep = netdev_priv(dev);
+ /* I should reset the ring buffers here, but I don't yet know
+ * a simple way to do that.
+ */
+ clk_enable(fep->clk);
+ ret = fec_enet_alloc_buffers(dev);
+ if (ret)
+ return ret;
+
+ fep->link = 0;
+#ifdef FEC_PHY
+ clk_enable(fep->clk);
+ fec_switch_init_phy(dev);
+ phy_start(fep->phydev);
+#endif
+ fep->old_link = 0;
+ if (fep->phydev) {
+ /*
+ * Set the initial link state to true. A lot of hardware
+ * based on this device does not implement a PHY interrupt,
+ * so we are never notified of link change.
+ */
+ fep->link = 1;
+ } else {
+ fep->link = 1;
+ /* no phy, go full duplex, it's most likely a hub chip */
+ switch_restart(dev, 1);
+ }
+
+ /*
+ * if the fec is the fist open, we need to do nothing
+ * if the fec is not the fist open, we need to restart the FEC
+ */
+ if (fep->sequence_done == 0)
+ switch_restart(dev, 1);
+ else
+ fep->sequence_done = 0;
+
+ fep->currTime = 0;
+ fep->learning_irqhandle_enable = 0;
+
+ esw_main(fep);
+
+ netif_start_queue(dev);
+ fep->opened = 1;
+
+ return 0; /* Success */
+}
+
+static int
+switch_enet_close(struct net_device *dev)
+{
+ struct switch_enet_private *fep = netdev_priv(dev);
+
+ fep->opened = 0;
+ netif_stop_queue(dev);
+ switch_stop(dev);
+#ifdef FEC_PHY
+ phy_disconnect(fep->phydev);
+ phy_stop(fep->phydev);
+ phy_write(fep->phydev, MII_BMCR, BMCR_PDOWN);
+#endif
+ fec_enet_free_buffers(dev);
+ clk_disable(fep->clk);
+
+ return 0;
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ * Skeleton taken from sunlance driver.
+ * The CPM Ethernet implementation allows Multicast as well as individual
+ * MAC address filtering. Some of the drivers check to make sure it is
+ * a group multicast address, and discard those that are not. I guess I
+ * will do the same for now, but just remove the test if you want
+ * individual filtering as well (do the upper net layers want or support
+ * this kind of feature?).
+ */
+
+/* bits in hash */
+#define HASH_BITS 6
+#define CRC32_POLY 0xEDB88320
+
+static void set_multicast_list(struct net_device *dev)
+{
+ struct switch_enet_private *fep;
+ struct switch_t *ep;
+ struct dev_mc_list *dmi;
+ unsigned int i, j, bit, data, crc;
+
+ fep = netdev_priv(dev);
+ ep = fep->hwp;
+
+ if (dev->flags & IFF_PROMISC) {
+ /* ep->fec_r_cntrl |= 0x0008; */
+ printk(KERN_INFO "%s IFF_PROMISC\n", __func__);
+ } else {
+
+ /* ep->fec_r_cntrl &= ~0x0008; */
+
+ if (dev->flags & IFF_ALLMULTI) {
+ /*
+ * Catch all multicast addresses, so set the
+ * filter to all 1's.
+ */
+ printk(KERN_INFO "%s IFF_ALLMULTI\n", __func__);
+ } else {
+ /*
+ * Clear filter and add the addresses
+ * in hash register
+ */
+ /*
+ * ep->fec_grp_hash_table_high = 0;
+ * ep->fec_grp_hash_table_low = 0;
+ */
+
+ dmi = dev->mc_list;
+
+ for (j = 0; j < dev->mc_count;
+ j++, dmi = dmi->next) {
+ /* Only support group multicast for now */
+ if (!(dmi->dmi_addr[0] & 1))
+ continue;
+
+ /* calculate crc32 value of mac address */
+ crc = 0xffffffff;
+
+ for (i = 0; i < dmi->dmi_addrlen; i++) {
+ data = dmi->dmi_addr[i];
+ for (bit = 0; bit < 8; bit++,
+ data >>= 1) {
+ crc = (crc >> 1) ^
+ (((crc ^ data) & 1) ?
+ CRC32_POLY : 0);
+ }
+ }
+
+ }
+ }
+ }
+}
+
+/* Set a MAC change in hardware */
+static int
+switch_set_mac_address(struct net_device *dev, void *p)
+{
+ struct switch_enet_private *fep = netdev_priv(dev);
+ struct sockaddr *addr = p;
+ struct switch_t *fecp;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ fecp = fep->hwp;
+ fecp->ESW_DBCR = MCF_ESW_DBCR_P1;
+
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ writel(dev->dev_addr[3] | (dev->dev_addr[2] << 8) |
+ (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24),
+ fep->enet_addr + MCF_FEC_PAUR0);
+ writel((dev->dev_addr[5] << 16)
+ | ((dev->dev_addr[4]+(unsigned char)(0)) << 24),
+ fep->enet_addr + MCF_FEC_PAUR0);
+
+ writel(dev->dev_addr[3] | (dev->dev_addr[2] << 8) |
+ (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24),
+ fep->enet_addr + MCF_FEC_PAUR1);
+ writel((dev->dev_addr[5] << 16)
+ | ((dev->dev_addr[4]+(unsigned char)(1)) << 24),
+ fep->enet_addr + MCF_FEC_PAUR1);
+
+ esw_update_atable_static(dev->dev_addr, 7, 7, fep);
+ fecp->ESW_DBCR = MCF_ESW_DBCR_P1 | MCF_ESW_DBCR_P2;
+
+ return 0;
+}
+
+static struct ethtool_ops fec_enet_ethtool_ops = {
+ .get_settings = fec_enet_get_settings,
+ .set_settings = fec_enet_set_settings,
+ .get_drvinfo = fec_enet_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ };
+static const struct net_device_ops fec_netdev_ops = {
+ .ndo_open = switch_enet_open,
+ .ndo_stop = switch_enet_close,
+ .ndo_do_ioctl = switch_enet_ioctl,
+ .ndo_start_xmit = switch_enet_start_xmit,
+ .ndo_set_multicast_list = set_multicast_list,
+ .ndo_tx_timeout = switch_timeout,
+ .ndo_set_mac_address = switch_set_mac_address,
+};
+
+static int switch_mac_addr_setup(char *mac_addr)
+{
+ char *ptr, *p = mac_addr;
+ unsigned long tmp;
+ int i = 0, ret = 0;
+
+ while (p && (*p) && i < 6) {
+ ptr = strchr(p, ':');
+ if (ptr)
+ *ptr++ = '\0';
+ if (strlen(p)) {
+ ret = strict_strtoul(p, 16, &tmp);
+ if (ret < 0 || tmp > 0xff)
+ break;
+ switch_mac_default[i++] = tmp;
+ }
+ p = ptr;
+ }
+
+ return 0;
+}
+
+__setup("fec_mac=", switch_mac_addr_setup);
+
+/* Initialize the FEC Ethernet */
+static int __init switch_enet_init(struct net_device *dev,
+ int slot, struct platform_device *pdev)
+{
+ struct switch_enet_private *fep = netdev_priv(dev);
+ struct resource *r;
+ struct cbd_t *bdp;
+ struct cbd_t *cbd_base;
+ struct switch_t *fecp;
+ int i;
+ struct switch_platform_data *plat = pdev->dev.platform_data;
+
+ /* Only allow us to be probed once. */
+ if (slot >= SWITCH_MAX_PORTS)
+ return -ENXIO;
+
+ /* Allocate memory for buffer descriptors */
+ cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &fep->bd_dma,
+ GFP_KERNEL);
+ if (!cbd_base) {
+ printk(KERN_ERR "FEC: allocate descriptor memory failed?\n");
+ return -ENOMEM;
+ }
+
+ spin_lock_init(&fep->hw_lock);
+ spin_lock_init(&fep->mii_lock);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!r)
+ return -ENXIO;
+
+ r = request_mem_region(r->start, resource_size(r), pdev->name);
+ if (!r)
+ return -EBUSY;
+
+ fep->enet_addr = ioremap(r->start, resource_size(r));
+
+ dev->irq = platform_get_irq(pdev, 0);
+
+ /*
+ * Create an Ethernet device instance.
+ * The switch lookup address memory start 0x800FC000
+ */
+ fecp = (struct switch_t *)(fep->enet_addr + ENET_SWI_PHYS_ADDR_OFFSET
+ / sizeof(unsigned long));
+ plat->switch_hw[1] = (unsigned long)fecp + MCF_ESW_LOOKUP_MEM_OFFSET;
+
+ fep->index = slot;
+ fep->hwp = fecp;
+ fep->hwentry = (struct eswAddrTable_t *)plat->switch_hw[1];
+ fep->netdev = dev;
+#ifdef CONFIG_FEC_SHARED_PHY
+ fep->phy_hwp = (struct switch_t *) plat->switch_hw[slot & ~1];
+#else
+ fep->phy_hwp = fecp;
+#endif
+
+ fep->clk = clk_get(&pdev->dev, "fec_clk");
+ if (IS_ERR(fep->clk))
+ return PTR_ERR(fep->clk);
+ clk_enable(fep->clk);
+
+
+ /* PHY reset should be done during clock on */
+ if (plat) {
+ fep->phy_interface = plat->fec_enet->phy;
+ if (plat->fec_enet->init && plat->fec_enet->init())
+ return -EIO;
+ } else
+ fep->phy_interface = PHY_INTERFACE_MODE_MII;
+
+ /*
+ * SWITCH CONFIGURATION
+ */
+ fecp->ESW_MODE = MCF_ESW_MODE_SW_RST;
+ udelay(10);
+
+ /* enable switch*/
+ fecp->ESW_MODE = MCF_ESW_MODE_STATRST;
+ fecp->ESW_MODE = MCF_ESW_MODE_SW_EN;
+
+ /* Enable transmit/receive on all ports */
+ fecp->ESW_PER = 0xffffffff;
+ /* Management port configuration,
+ * make port 0 as management port
+ */
+ fecp->ESW_BMPC = 0;
+
+ /* clear all switch irq */
+ fecp->switch_ievent = 0xffffffff;
+ fecp->switch_imask = 0;
+ udelay(10);
+
+ plat->request_intrs = switch_request_intrs;
+ plat->set_mii = switch_set_mii;
+ plat->get_mac = switch_get_mac;
+ plat->enable_phy_intr = switch_enable_phy_intr;
+ plat->disable_phy_intr = switch_disable_phy_intr;
+ plat->phy_ack_intr = switch_phy_ack_intr;
+ plat->localhw_setup = switch_localhw_setup;
+ plat->uncache = switch_uncache;
+ plat->platform_flush_cache = switch_platform_flush_cache;
+
+ /*
+ * Set the Ethernet address. If using multiple Enets on the 8xx,
+ * this needs some work to get unique addresses.
+ *
+ * This is our default MAC address unless the user changes
+ * it via eth_mac_addr (our dev->set_mac_addr handler).
+ */
+ if (plat && plat->get_mac)
+ plat->get_mac(dev);
+
+ /* Set receive and transmit descriptor base */
+ fep->rx_bd_base = cbd_base;
+ fep->tx_bd_base = cbd_base + RX_RING_SIZE;
+
+ /* Initialize the receive buffer descriptors */
+ bdp = fep->rx_bd_base;
+ for (i = 0; i < RX_RING_SIZE; i++) {
+ bdp->cbd_sc = 0;
+
+#ifdef L2SWITCH_ENHANCED_BUFFER
+ bdp->bdu = 0x00000000;
+ bdp->ebd_status = RX_BD_INT;
+#endif
+ bdp++;
+ }
+
+ /* Set the last buffer to wrap */
+ bdp--;
+ bdp->cbd_sc |= BD_SC_WRAP;
+
+ /* ...and the same for transmmit */
+ bdp = fep->tx_bd_base;
+ for (i = 0; i < TX_RING_SIZE; i++) {
+ /* Initialize the BD for every fragment in the page */
+ bdp->cbd_sc = 0;
+ bdp->cbd_bufaddr = 0;
+ bdp++;
+ }
+
+ /* Set the last buffer to wrap */
+ bdp--;
+ bdp->cbd_sc |= BD_SC_WRAP;
+
+ /*
+ * Install our interrupt handlers. This varies depending on
+ * the architecture.
+ */
+ if (plat && plat->request_intrs)
+ plat->request_intrs(dev, switch_enet_interrupt, dev);
+
+ dev->base_addr = (unsigned long)fecp;
+
+ /* The FEC Ethernet specific entries in the device structure. */
+ dev->netdev_ops = &fec_netdev_ops;
+ dev->ethtool_ops = &fec_enet_ethtool_ops;
+
+ /* setup MII interface */
+ if (plat && plat->set_mii)
+ plat->set_mii(dev);
+
+
+#ifndef CONFIG_FEC_SHARED_PHY
+ fep->phy_addr = 0;
+#else
+ fep->phy_addr = fep->index;
+#endif
+
+ fep->sequence_done = 1;
+ return 0;
+}
+
+static void enet_reset(struct net_device *dev, int duplex)
+{
+ struct switch_enet_private *fep = netdev_priv(dev);
+
+ /* ECR */
+#ifdef L2SWITCH_ENHANCED_BUFFER
+ writel(MCF_FEC_ECR_ENA_1588
+ | MCF_FEC_ECR_MAGIC_ENA,
+ fep->enet_addr + MCF_FEC_ECR0);
+ writel(MCF_FEC_ECR_ENA_1588,
+ | MCF_FEC_ECR_MAGIC_ENA,
+ fep->enet_addr + MCF_FEC_ECR1);
+#else /*legac buffer*/
+ writel(MCF_FEC_ECR_MAGIC_ENA,
+ fep->enet_addr + MCF_FEC_ECR0);
+ writel(MCF_FEC_ECR_MAGIC_ENA,
+ fep->enet_addr + MCF_FEC_ECR1);
+#endif
+ /* EMRBR */
+ writel(PKT_MAXBLR_SIZE, fep->enet_addr + MCF_FEC_EMRBR0);
+ writel(PKT_MAXBLR_SIZE, fep->enet_addr + MCF_FEC_EMRBR1);
+
+ /*
+ * set the receive and transmit BDs ring base to
+ * hardware registers(ERDSR & ETDSR)
+ */
+ writel(fep->bd_dma, fep->enet_addr + MCF_FEC_ERDSR0);
+ writel(fep->bd_dma, fep->enet_addr + MCF_FEC_ERDSR1);
+ writel((unsigned long)fep->bd_dma + sizeof(struct cbd_t) * RX_RING_SIZE,
+ fep->enet_addr + MCF_FEC_ETDSR0);
+ writel((unsigned long)fep->bd_dma + sizeof(struct cbd_t) * RX_RING_SIZE,
+ fep->enet_addr + MCF_FEC_ETDSR1);
+#ifdef CONFIG_ARCH_MXS
+ /* Can't get phy(8720) ID when set to 2.5M on MX28, lower it */
+ writel(fep->phy_speed,
+ fep->enet_addr + MCF_FEC_MSCR0);
+ writel(fep->phy_speed,
+ fep->enet_addr + MCF_FEC_MSCR1);
+#endif
+ fep->full_duplex = duplex;
+
+ /* EIR */
+ writel(0, fep->enet_addr + MCF_FEC_EIR0);
+ writel(0, fep->enet_addr + MCF_FEC_EIR1);
+
+ /* IAUR */
+ writel(0, fep->enet_addr + MCF_FEC_IAUR0);
+ writel(0, fep->enet_addr + MCF_FEC_IAUR1);
+
+ /* IALR */
+ writel(0, fep->enet_addr + MCF_FEC_IALR0);
+ writel(0, fep->enet_addr + MCF_FEC_IALR1);
+
+ /* GAUR */
+ writel(0, fep->enet_addr + MCF_FEC_GAUR0);
+ writel(0, fep->enet_addr + MCF_FEC_GAUR1);
+
+ /* GALR */
+ writel(0, fep->enet_addr + MCF_FEC_GALR0);
+ writel(0, fep->enet_addr + MCF_FEC_GALR1);
+
+ /* EMRBR */
+ writel(PKT_MAXBLR_SIZE, fep->enet_addr + MCF_FEC_EMRBR0);
+ writel(PKT_MAXBLR_SIZE, fep->enet_addr + MCF_FEC_EMRBR1);
+ msleep(10);
+
+ /* EIMR */
+ writel(FEC_ENET_TXF | FEC_ENET_RXF, fep->enet_addr + MCF_FEC_EIMR0);
+ writel(FEC_ENET_TXF | FEC_ENET_RXF, fep->enet_addr + MCF_FEC_EIMR1);
+
+ /* PALR PAUR */
+ /* Set the station address for the ENET Adapter */
+ writel(dev->dev_addr[3] |
+ dev->dev_addr[2]<<8 |
+ dev->dev_addr[1]<<16 |
+ dev->dev_addr[0]<<24, fep->enet_addr + MCF_FEC_PALR0);
+ writel(dev->dev_addr[5]<<16 |
+ (dev->dev_addr[4]+(unsigned char)(0))<<24,
+ fep->enet_addr + MCF_FEC_PAUR0);
+ writel(dev->dev_addr[3] |
+ dev->dev_addr[2]<<8 |
+ dev->dev_addr[1]<<16 |
+ dev->dev_addr[0]<<24, fep->enet_addr + MCF_FEC_PALR1);
+ writel(dev->dev_addr[5]<<16 |
+ (dev->dev_addr[4]+(unsigned char)(1))<<24,
+ fep->enet_addr + MCF_FEC_PAUR1);
+
+ /* RCR */
+ writel(readl(fep->enet_addr + MCF_FEC_RCR0)
+ | MCF_FEC_RCR_FCE | MCF_FEC_RCR_PROM,
+ fep->enet_addr + MCF_FEC_RCR0);
+ writel(readl(fep->enet_addr + MCF_FEC_RCR1)
+ | MCF_FEC_RCR_FCE | MCF_FEC_RCR_PROM,
+ fep->enet_addr + MCF_FEC_RCR1);
+
+ /* TCR */
+ writel(0x1c, fep->enet_addr + MCF_FEC_TCR0);
+ writel(0x1c, fep->enet_addr + MCF_FEC_TCR1);
+
+ /* ECR */
+ writel(readl(fep->enet_addr + MCF_FEC_ECR0) | MCF_FEC_ECR_ETHER_EN,
+ fep->enet_addr + MCF_FEC_ECR0);
+ writel(readl(fep->enet_addr + MCF_FEC_ECR1) | MCF_FEC_ECR_ETHER_EN,
+ fep->enet_addr + MCF_FEC_ECR1);
+}
+
+/*
+ * This function is called to start or restart the FEC during a link
+ * change. This only happens when switching between half and full
+ * duplex.
+ */
+static void
+switch_restart(struct net_device *dev, int duplex)
+{
+ struct switch_enet_private *fep;
+ struct switch_t *fecp;
+ int i;
+ struct switch_platform_data *plat;
+
+ fep = netdev_priv(dev);
+ fecp = fep->hwp;
+ plat = fep->pdev->dev.platform_data;
+ /*
+ * Whack a reset. We should wait for this.
+ */
+ /* fecp->fec_ecntrl = 1; */
+ fecp->ESW_MODE = MCF_ESW_MODE_SW_RST;
+ udelay(10);
+ fecp->ESW_MODE = MCF_ESW_MODE_STATRST;
+ fecp->ESW_MODE = MCF_ESW_MODE_SW_EN;
+
+ /* Enable transmit/receive on all ports */
+ fecp->ESW_PER = 0xffffffff;
+ /*
+ * Management port configuration,
+ * make port 0 as management port
+ */
+ fecp->ESW_BMPC = 0;
+
+ /* Clear any outstanding interrupt */
+ fecp->switch_ievent = 0xffffffff;
+ /*if (plat && plat->enable_phy_intr)
+ * plat->enable_phy_intr();
+ */
+
+ /* Reset all multicast */
+ /*
+ * fecp->fec_grp_hash_table_high = 0;
+ * fecp->fec_grp_hash_table_low = 0;
+ */
+
+ /* Set maximum receive buffer size */
+ fecp->fec_r_buff_size = PKT_MAXBLR_SIZE;
+
+ if (plat && plat->localhw_setup)
+ plat->localhw_setup();
+
+ /* Set receive and transmit descriptor base */
+ fecp->fec_r_des_start = fep->bd_dma;
+ fecp->fec_x_des_start = (unsigned long)fep->bd_dma
+ + sizeof(struct cbd_t) * RX_RING_SIZE;
+
+ fep->dirty_tx = fep->cur_tx = fep->tx_bd_base;
+ fep->cur_rx = fep->rx_bd_base;
+
+ /* Reset SKB transmit buffers */
+ fep->skb_cur = fep->skb_dirty = 0;
+ for (i = 0; i <= TX_RING_MOD_MASK; i++) {
+ if (fep->tx_skbuff[i] != NULL) {
+ dev_kfree_skb_any(fep->tx_skbuff[i]);
+ fep->tx_skbuff[i] = NULL;
+ }
+ }
+
+ enet_reset(dev, duplex);
+ esw_clear_atable(fep);
+
+ /* And last, enable the transmit and receive processing */
+ fecp->fec_r_des_active = MCF_ESW_RDAR_R_DES_ACTIVE;
+
+ /* Enable interrupts we wish to service */
+ fecp->switch_ievent = 0xffffffff;
+ fecp->switch_imask = MCF_ESW_IMR_RXF | MCF_ESW_IMR_TXF |
+ MCF_ESW_IMR_RXB | MCF_ESW_IMR_TXB;
+
+#ifdef SWITCH_DEBUG
+ printk(KERN_INFO "%s: switch hw init over."
+ "isr %x mask %x rx_addr %x %x tx_addr %x %x."
+ "fec_r_buff_size %x\n", __func__,
+ fecp->switch_ievent, fecp->switch_imask, fecp->fec_r_des_start,
+ &fecp->fec_r_des_start, fecp->fec_x_des_start,
+ &fecp->fec_x_des_start, fecp->fec_r_buff_size);
+ printk(KERN_INFO "%s: fecp->ESW_DBCR %x, fecp->ESW_P0FFEN %x fecp->ESW_BKLR %x\n",
+ __func__, fecp->ESW_DBCR, fecp->ESW_P0FFEN, fecp->ESW_BKLR);
+
+ printk(KERN_INFO "fecp->portstats[0].MCF_ESW_POQC %x,"
+ "fecp->portstats[0].MCF_ESW_PMVID %x,"
+ "fecp->portstats[0].MCF_ESW_PMVTAG %x,"
+ "fecp->portstats[0].MCF_ESW_PBL %x\n",
+ fecp->port_statistics_status[0].MCF_ESW_POQC,
+ fecp->port_statistics_status[0].MCF_ESW_PMVID,
+ fecp->port_statistics_status[0].MCF_ESW_PMVTAG,
+ fecp->port_statistics_status[0].MCF_ESW_PBL);
+
+ printk(KERN_INFO "fecp->portstats[1].MCF_ESW_POQC %x,"
+ "fecp->portstats[1].MCF_ESW_PMVID %x,"
+ "fecp->portstats[1].MCF_ESW_PMVTAG %x,"
+ "fecp->portstats[1].MCF_ESW_PBL %x\n",
+ fecp->port_statistics_status[1].MCF_ESW_POQC,
+ fecp->port_statistics_status[1].MCF_ESW_PMVID,
+ fecp->port_statistics_status[1].MCF_ESW_PMVTAG,
+ fecp->port_statistics_status[1].MCF_ESW_PBL);
+
+ printk(KERN_INFO "fecp->portstats[2].MCF_ESW_POQC %x,"
+ "fecp->portstats[2].MCF_ESW_PMVID %x,"
+ "fecp->portstats[2].MCF_ESW_PMVTAG %x,"
+ "fecp->portstats[2].MCF_ESW_PBL %x\n",
+ fecp->port_statistics_status[2].MCF_ESW_POQC,
+ fecp->port_statistics_status[2].MCF_ESW_PMVID,
+ fecp->port_statistics_status[2].MCF_ESW_PMVTAG,
+ fecp->port_statistics_status[2].MCF_ESW_PBL);
+#endif
+}
+
+static void
+switch_stop(struct net_device *dev)
+{
+ struct switch_t *fecp;
+ struct switch_enet_private *fep;
+ struct switch_platform_data *plat;
+
+#ifdef SWITCH_DEBUG
+ printk(KERN_ERR "%s\n", __func__);
+#endif
+ fep = netdev_priv(dev);
+ fecp = fep->hwp;
+ plat = fep->pdev->dev.platform_data;
+ /* We cannot expect a graceful transmit stop without link !!! */
+ if (fep->link)
+ udelay(10);
+
+ /* Whack a reset. We should wait for this */
+ udelay(10);
+}
+
+#ifdef FEC_PHY
+static int fec_mdio_register(struct net_device *dev,
+ int slot)
+{
+ int err = 0;
+ struct switch_enet_private *fep = netdev_priv(dev);
+
+ fep->mdio_bus = mdiobus_alloc();
+ if (!fep->mdio_bus) {
+ printk(KERN_ERR "ethernet switch mdiobus_alloc fail\n");
+ return -ENOMEM;
+ }
+
+ if (slot == 0) {
+ fep->mdio_bus->name = "FEC switch MII 0 Bus";
+ strcpy(fep->mdio_bus->id, "0");
+ } else if (slot == 1) {
+ fep->mdio_bus->name = "FEC switch MII 1 Bus";
+ strcpy(fep->mdio_bus->id, "1");
+ } else {
+ printk(KERN_ERR "Now Fec switch can not"
+ "support more than 2 mii bus\n");
+ }
+
+ fep->mdio_bus->read = &fec_enet_mdio_read;
+ fep->mdio_bus->write = &fec_enet_mdio_write;
+ fep->mdio_bus->priv = dev;
+ err = mdiobus_register(fep->mdio_bus);
+ if (err) {
+ mdiobus_free(fep->mdio_bus);
+ printk(KERN_ERR "%s: ethernet mdiobus_register fail\n",
+ dev->name);
+ return -EIO;
+ }
+
+ printk(KERN_INFO "mdiobus_register %s ok\n",
+ fep->mdio_bus->name);
+ return err;
+}
+#endif
+
+static int __init eth_switch_probe(struct platform_device *pdev)
+{
+ struct net_device *dev;
+ int i, err;
+ struct switch_enet_private *fep;
+ struct switch_platform_private *chip;
+
+ printk(KERN_INFO "Ethernet Switch Version 1.0\n");
+ chip = kzalloc(sizeof(struct switch_platform_private) +
+ sizeof(struct switch_enet_private *) * SWITCH_MAX_PORTS,
+ GFP_KERNEL);
+ if (!chip) {
+ err = -ENOMEM;
+ printk(KERN_ERR "%s: kzalloc fail %x\n", __func__,
+ (unsigned int)chip);
+ return err;
+ }
+
+ chip->pdev = pdev;
+ chip->num_slots = SWITCH_MAX_PORTS;
+ platform_set_drvdata(pdev, chip);
+
+ for (i = 0; (i < chip->num_slots); i++) {
+ dev = alloc_etherdev(sizeof(struct switch_enet_private));
+ if (!dev) {
+ printk(KERN_ERR "%s: ethernet switch\
+ alloc_etherdev fail\n",
+ dev->name);
+ return -ENOMEM;
+ }
+
+ fep = netdev_priv(dev);
+ fep->pdev = pdev;
+ printk(KERN_ERR "%s: ethernet switch port %d init\n",
+ __func__, i);
+ err = switch_enet_init(dev, i, pdev);
+ if (err) {
+ free_netdev(dev);
+ platform_set_drvdata(pdev, NULL);
+ kfree(chip);
+ continue;
+ }
+
+ chip->fep_host[i] = fep;
+ /* disable mdio */
+#ifdef FEC_PHY
+#ifdef CONFIG_FEC_SHARED_PHY
+ if (i == 0)
+ err = fec_mdio_register(dev, 0);
+ else {
+ fep->mdio_bus = chip->fep_host[0]->mdio_bus;
+ printk(KERN_INFO "FEC%d SHARED the %s ok\n",
+ i, fep->mdio_bus->name);
+ }
+#else
+ err = fec_mdio_register(dev, i);
+#endif
+ if (err) {
+ printk(KERN_ERR "%s: ethernet switch fec_mdio_register\n",
+ dev->name);
+ free_netdev(dev);
+ platform_set_drvdata(pdev, NULL);
+ kfree(chip);
+ return -ENOMEM;
+ }
+#endif
+ /* setup timer for Learning Aging function */
+ /*
+ * setup_timer(&fep->timer_aging,
+ * l2switch_aging_timer, (unsigned long)fep);
+ */
+ init_timer(&fep->timer_aging);
+ fep->timer_aging.function = l2switch_aging_timer;
+ fep->timer_aging.data = (unsigned long) fep;
+ fep->timer_aging.expires = jiffies + LEARNING_AGING_TIMER;
+
+ /* register network device */
+ if (register_netdev(dev) != 0) {
+ free_netdev(dev);
+ platform_set_drvdata(pdev, NULL);
+ kfree(chip);
+ printk(KERN_ERR "%s: ethernet switch register_netdev fail\n",
+ dev->name);
+ return -EIO;
+ }
+ printk(KERN_INFO "%s: ethernet switch %pM\n",
+ dev->name, dev->dev_addr);
+ }
+
+ return 0;
+}
+
+static int eth_switch_remove(struct platform_device *pdev)
+{
+ int i;
+ struct net_device *dev;
+ struct switch_enet_private *fep;
+ struct switch_platform_private *chip;
+
+ chip = platform_get_drvdata(pdev);
+ if (chip) {
+ for (i = 0; i < chip->num_slots; i++) {
+ fep = chip->fep_host[i];
+ dev = fep->netdev;
+ fep->sequence_done = 1;
+ unregister_netdev(dev);
+ free_netdev(dev);
+
+ del_timer_sync(&fep->timer_aging);
+ }
+
+ platform_set_drvdata(pdev, NULL);
+ kfree(chip);
+
+ } else
+ printk(KERN_ERR "%s: can not get the "
+ "switch_platform_private %x\n", __func__,
+ (unsigned int)chip);
+
+ return 0;
+}
+
+static struct platform_driver eth_switch_driver = {
+ .probe = eth_switch_probe,
+ .remove = eth_switch_remove,
+ .driver = {
+ .name = "mxs-l2switch",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init fec_l2switch_init(void)
+{
+ return platform_driver_register(&eth_switch_driver);;
+}
+
+static void __exit fec_l2_switch_exit(void)
+{
+ platform_driver_unregister(&eth_switch_driver);
+}
+
+module_init(fec_l2switch_init);
+module_exit(fec_l2_switch_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/fec_switch.h b/drivers/net/fec_switch.h
new file mode 100644
index 000000000000..7b9f6a180f6a
--- /dev/null
+++ b/drivers/net/fec_switch.h
@@ -0,0 +1,1121 @@
+/****************************************************************************/
+
+/*
+ * mcfswitch -- L2 Switch Controller for Modelo ColdFire SoC
+ * processors.
+ *
+ * Copyright (C) 2010 Freescale Semiconductor,Inc.All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+/****************************************************************************/
+#ifndef SWITCH_H
+#define SWITCH_H
+/****************************************************************************/
+/* The Switch stores dest/src/type, data, and checksum for receive packets.
+ */
+#define PKT_MAXBUF_SIZE 1518
+#define PKT_MINBUF_SIZE 64
+#define PKT_MAXBLR_SIZE 1520
+
+/*
+ * The 5441x RX control register also contains maximum frame
+ * size bits.
+ */
+#define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16)
+
+/*
+ * Some hardware gets it MAC address out of local flash memory.
+ * if this is non-zero then assume it is the address to get MAC from.
+ */
+#define FEC_FLASHMAC 0
+
+/* The number of Tx and Rx buffers. These are allocated from the page
+ * pool. The code may assume these are power of two, so it it best
+ * to keep them that size.
+ * We don't need to allocate pages for the transmitter. We just use
+ * the skbuffer directly.
+ */
+#ifdef CONFIG_SWITCH_DMA_USE_SRAM
+#define SWITCH_ENET_RX_PAGES 6
+#else
+#define SWITCH_ENET_RX_PAGES 8
+#endif
+
+#define SWITCH_ENET_RX_FRSIZE 2048
+#define SWITCH_ENET_RX_FRPPG (PAGE_SIZE / SWITCH_ENET_RX_FRSIZE)
+#define RX_RING_SIZE (SWITCH_ENET_RX_FRPPG * SWITCH_ENET_RX_PAGES)
+#define SWITCH_ENET_TX_FRSIZE 2048
+#define SWITCH_ENET_TX_FRPPG (PAGE_SIZE / SWITCH_ENET_TX_FRSIZE)
+
+#ifdef CONFIG_SWITCH_DMA_USE_SRAM
+#define TX_RING_SIZE 8 /* Must be power of two */
+#define TX_RING_MOD_MASK 7 /* for this to work */
+#else
+#define TX_RING_SIZE 16 /* Must be power of two */
+#define TX_RING_MOD_MASK 15 /* for this to work */
+#endif
+
+#if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE)
+#error "L2SWITCH: descriptor ring size constants too large"
+#endif
+/*-----------------------------------------------------------------------*/
+struct esw_output_queue_status {
+ unsigned long ESW_MMSR;
+ unsigned long ESW_LMT;
+ unsigned long ESW_LFC;
+ unsigned long ESW_PCSR;
+ unsigned long ESW_IOSR;
+ unsigned long ESW_QWT;
+ unsigned long esw_reserved;
+ unsigned long ESW_P0BCT;
+};
+struct esw_statistics_status {
+ /*
+ * Total number of incoming frames processed
+ * but discarded in switch
+ */
+ unsigned long ESW_DISCN;
+ /*Sum of bytes of frames counted in ESW_DISCN*/
+ unsigned long ESW_DISCB;
+ /*
+ * Total number of incoming frames processed
+ * but not discarded in switch
+ */
+ unsigned long ESW_NDISCN;
+ /*Sum of bytes of frames counted in ESW_NDISCN*/
+ unsigned long ESW_NDISCB;
+};
+
+struct esw_port_statistics_status {
+ /*outgoing frames discarded due to transmit queue congestion*/
+ unsigned long MCF_ESW_POQC;
+ /*incoming frames discarded due to VLAN domain mismatch*/
+ unsigned long MCF_ESW_PMVID;
+ /*incoming frames discarded due to untagged discard*/
+ unsigned long MCF_ESW_PMVTAG;
+ /*incoming frames discarded due port is in blocking state*/
+ unsigned long MCF_ESW_PBL;
+};
+
+struct switch_t {
+ unsigned long ESW_REVISION;
+ unsigned long ESW_SCRATCH;
+ unsigned long ESW_PER;
+ unsigned long reserved0[1];
+ unsigned long ESW_VLANV;
+ unsigned long ESW_DBCR;
+ unsigned long ESW_DMCR;
+ unsigned long ESW_BKLR;
+ unsigned long ESW_BMPC;
+ unsigned long ESW_MODE;
+ unsigned long ESW_VIMSEL;
+ unsigned long ESW_VOMSEL;
+ unsigned long ESW_VIMEN;
+ unsigned long ESW_VID;/*0x34*/
+ /*from 0x38 0x3C*/
+ unsigned long esw_reserved0[2];
+ unsigned long ESW_MCR;/*0x40*/
+ unsigned long ESW_EGMAP;
+ unsigned long ESW_INGMAP;
+ unsigned long ESW_INGSAL;
+ unsigned long ESW_INGSAH;
+ unsigned long ESW_INGDAL;
+ unsigned long ESW_INGDAH;
+ unsigned long ESW_ENGSAL;
+ unsigned long ESW_ENGSAH;
+ unsigned long ESW_ENGDAL;
+ unsigned long ESW_ENGDAH;
+ unsigned long ESW_MCVAL;/*0x6C*/
+ /*from 0x70--0x7C*/
+ unsigned long esw_reserved1[4];
+ unsigned long ESW_MMSR;/*0x80*/
+ unsigned long ESW_LMT;
+ unsigned long ESW_LFC;
+ unsigned long ESW_PCSR;
+ unsigned long ESW_IOSR;
+ unsigned long ESW_QWT;/*0x94*/
+ unsigned long esw_reserved2[1];/*0x98*/
+ unsigned long ESW_P0BCT;/*0x9C*/
+ /*from 0xA0-0xB8*/
+ unsigned long esw_reserved3[7];
+ unsigned long ESW_P0FFEN;/*0xBC*/
+ unsigned long ESW_PSNP[8];
+ unsigned long ESW_IPSNP[8];
+ unsigned long ESW_PVRES[3];
+ /*from 0x10C-0x13C*/
+ unsigned long esw_reserved4[13];
+ unsigned long ESW_IPRES;/*0x140*/
+ /*from 0x144-0x17C*/
+ unsigned long esw_reserved5[15];
+ unsigned long ESW_PRES[3];
+ /*from 0x18C-0x1FC*/
+ unsigned long esw_reserved6[29];
+ unsigned long ESW_PID[3];
+ /*from 0x20C-0x27C*/
+ unsigned long esw_reserved7[29];
+ unsigned long ESW_VRES[32];
+ unsigned long ESW_DISCN;/*0x300*/
+ unsigned long ESW_DISCB;
+ unsigned long ESW_NDISCN;
+ unsigned long ESW_NDISCB;/*0xFC0DC30C*/
+ struct esw_port_statistics_status port_statistics_status[3];
+ /*from 0x340-0x400*/
+ unsigned long esw_reserved8[48];
+
+ /*0xFC0DC400---0xFC0DC418*/
+ /*unsigned long MCF_ESW_ISR;*/
+ unsigned long switch_ievent; /* Interrupt event reg */
+ /*unsigned long MCF_ESW_IMR;*/
+ unsigned long switch_imask; /* Interrupt mask reg */
+ /*unsigned long MCF_ESW_RDSR;*/
+ unsigned long fec_r_des_start; /* Receive descriptor ring */
+ /*unsigned long MCF_ESW_TDSR;*/
+ unsigned long fec_x_des_start; /* Transmit descriptor ring */
+ /*unsigned long MCF_ESW_MRBR;*/
+ unsigned long fec_r_buff_size; /* Maximum receive buff size */
+ /*unsigned long MCF_ESW_RDAR;*/
+ unsigned long fec_r_des_active; /* Receive descriptor reg */
+ /*unsigned long MCF_ESW_TDAR;*/
+ unsigned long fec_x_des_active; /* Transmit descriptor reg */
+ /*from 0x420-0x4FC*/
+ unsigned long esw_reserved9[57];
+
+ /*0xFC0DC500---0xFC0DC508*/
+ unsigned long ESW_LREC0;
+ unsigned long ESW_LREC1;
+ unsigned long ESW_LSR;
+};
+
+struct AddrTable64bEntry {
+ unsigned int lo; /* lower 32 bits */
+ unsigned int hi; /* upper 32 bits */
+};
+
+struct eswAddrTable_t {
+ struct AddrTable64bEntry eswTable64bEntry[2048];
+};
+
+#define MCF_ESW_LOOKUP_MEM_OFFSET 0x4000
+#define ENET_SWI_PHYS_ADDR_OFFSET 0x8000
+#define MCF_ESW_PER (0x08 / sizeof(unsigned long))
+#define MCF_ESW_DBCR (0x14 / sizeof(unsigned long))
+#define MCF_ESW_IMR (0x404 / sizeof(unsigned long))
+
+#define MCF_FEC_BASE_ADDR (fep->enet_addr)
+#define MCF_FEC_EIR0 (0x04 / sizeof(unsigned long))
+#define MCF_FEC_EIR1 (0x4004 / sizeof(unsigned long))
+#define MCF_FEC_EIMR0 (0x08 / sizeof(unsigned long))
+#define MCF_FEC_EIMR1 (0x4008 / sizeof(unsigned long))
+#define MCF_FEC_MMFR0 (0x40 / sizeof(unsigned long))
+#define MCF_FEC_MMFR1 (0x4040 / sizeof(unsigned long))
+#define MCF_FEC_MSCR0 (0x44 / sizeof(unsigned long))
+#define MCF_FEC_MSCR1 (0x4044 / sizeof(unsigned long))
+
+#define MCF_FEC_RCR0 (0x84 / sizeof(unsigned long))
+#define MCF_FEC_RCR1 (0x4084 / sizeof(unsigned long))
+#define MCF_FEC_TCR0 (0xC4 / sizeof(unsigned long))
+#define MCF_FEC_TCR1 (0x40C4 / sizeof(unsigned long))
+#define MCF_FEC_ECR0 (0x24 / sizeof(unsigned long))
+#define MCF_FEC_ECR1 (0x4024 / sizeof(unsigned long))
+
+#define MCF_FEC_PALR0 (0xE4 / sizeof(unsigned long))
+#define MCF_FEC_PALR1 (0x40E4 / sizeof(unsigned long))
+#define MCF_FEC_PAUR0 (0xE8 / sizeof(unsigned long))
+#define MCF_FEC_PAUR1 (0x40E8 / sizeof(unsigned long))
+
+#define MCF_FEC_ERDSR0 (0x180 / sizeof(unsigned long))
+#define MCF_FEC_ERDSR1 (0x4180 / sizeof(unsigned long))
+#define MCF_FEC_ETDSR0 (0x184 / sizeof(unsigned long))
+#define MCF_FEC_ETDSR1 (0x4184 / sizeof(unsigned long))
+
+#define MCF_FEC_IAUR0 (0x118 / sizeof(unsigned long))
+#define MCF_FEC_IAUR1 (0x4118 / sizeof(unsigned long))
+#define MCF_FEC_IALR0 (0x11C / sizeof(unsigned long))
+#define MCF_FEC_IALR1 (0x411C / sizeof(unsigned long))
+
+#define MCF_FEC_GAUR0 (0x120 / sizeof(unsigned long))
+#define MCF_FEC_GAUR1 (0x4120 / sizeof(unsigned long))
+#define MCF_FEC_GALR0 (0x124 / sizeof(unsigned long))
+#define MCF_FEC_GALR1 (0x4124 / sizeof(unsigned long))
+
+#define MCF_FEC_EMRBR0 (0x188 / sizeof(unsigned long))
+#define MCF_FEC_EMRBR1 (0x4188 / sizeof(unsigned long))
+
+#define MCF_FEC_RCR_DRT (0x00000002)
+#define MCF_FEC_RCR_PROM (0x00000008)
+#define MCF_FEC_RCR_FCE (0x00000020)
+#define MCF_FEC_RCR_RMII_MODE (0x00000100)
+#define MCF_FEC_RCR_MAX_FL(x) (((x)&0x00003FFF)<<16)
+#define MCF_FEC_RCR_CRC_FWD (0x00004000)
+#define MCF_FEC_RCR_NO_LGTH_CHECK (0x40000000)
+#define MCF_FEC_TCR_FDEN (0x00000004)
+
+#define MCF_FEC_ECR_RESET (0x00000001)
+#define MCF_FEC_ECR_ETHER_EN (0x00000002)
+#define MCF_FEC_ECR_MAGIC_ENA (0x00000004)
+#define MCF_FEC_ECR_ENA_1588 (0x00000010)
+
+#define MCF_FEC_ERDSR(x) ((x) << 2)
+
+/*-------------ioctl command ---------------------------------------*/
+#define ESW_SET_LEARNING_CONF 0x9101
+#define ESW_GET_LEARNING_CONF 0x9201
+#define ESW_SET_BLOCKING_CONF 0x9102
+#define ESW_GET_BLOCKING_CONF 0x9202
+#define ESW_SET_MULTICAST_CONF 0x9103
+#define ESW_GET_MULTICAST_CONF 0x9203
+#define ESW_SET_BROADCAST_CONF 0x9104
+#define ESW_GET_BROADCAST_CONF 0x9204
+#define ESW_SET_PORTENABLE_CONF 0x9105
+#define ESW_GET_PORTENABLE_CONF 0x9205
+#define ESW_SET_IP_SNOOP_CONF 0x9106
+#define ESW_GET_IP_SNOOP_CONF 0x9206
+#define ESW_SET_PORT_SNOOP_CONF 0x9107
+#define ESW_GET_PORT_SNOOP_CONF 0x9207
+#define ESW_SET_PORT_MIRROR_CONF 0x9108
+#define ESW_GET_PORT_MIRROR_CONF 0x9208
+#define ESW_SET_PIRORITY_VLAN 0x9109
+#define ESW_GET_PIRORITY_VLAN 0x9209
+#define ESW_SET_PIRORITY_IP 0x910A
+#define ESW_GET_PIRORITY_IP 0x920A
+#define ESW_SET_PIRORITY_MAC 0x910B
+#define ESW_GET_PIRORITY_MAC 0x920B
+#define ESW_SET_PIRORITY_DEFAULT 0x910C
+#define ESW_GET_PIRORITY_DEFAULT 0x920C
+#define ESW_SET_P0_FORCED_FORWARD 0x910D
+#define ESW_GET_P0_FORCED_FORWARD 0x920D
+#define ESW_SET_SWITCH_MODE 0x910E
+#define ESW_GET_SWITCH_MODE 0x920E
+#define ESW_SET_BRIDGE_CONFIG 0x910F
+#define ESW_GET_BRIDGE_CONFIG 0x920F
+#define ESW_SET_VLAN_OUTPUT_PROCESS 0x9110
+#define ESW_GET_VLAN_OUTPUT_PROCESS 0x9210
+#define ESW_SET_VLAN_INPUT_PROCESS 0x9111
+#define ESW_GET_VLAN_INPUT_PROCESS 0x9211
+#define ESW_SET_VLAN_DOMAIN_VERIFICATION 0x9112
+#define ESW_GET_VLAN_DOMAIN_VERIFICATION 0x9212
+#define ESW_SET_VLAN_RESOLUTION_TABLE 0x9113
+#define ESW_GET_VLAN_RESOLUTION_TABLE 0x9213
+
+
+#define ESW_GET_STATISTICS_STATUS 0x9221
+#define ESW_GET_PORT0_STATISTICS_STATUS 0x9222
+#define ESW_GET_PORT1_STATISTICS_STATUS 0x9223
+#define ESW_GET_PORT2_STATISTICS_STATUS 0x9224
+#define ESW_SET_OUTPUT_QUEUE_MEMORY 0x9125
+#define ESW_GET_OUTPUT_QUEUE_STATUS 0x9225
+#define ESW_UPDATE_STATIC_MACTABLE 0x9226
+#define ESW_CLEAR_ALL_MACTABLE 0x9227
+
+struct eswIoctlPortConfig {
+ int port;
+ int enable;
+};
+
+struct eswIoctlPortEnableConfig {
+ int port;
+ int tx_enable;
+ int rx_enable;
+};
+
+struct eswIoctlIpsnoopConfig {
+ int num;
+ int mode;
+ unsigned char ip_header_protocol;
+};
+
+struct eswIoctlP0ForcedForwardConfig {
+ int port1;
+ int port2;
+ int enable;
+};
+
+struct eswIoctlPortsnoopConfig {
+ int num;
+ int mode;
+ unsigned short compare_port;
+ int compare_num;
+};
+
+struct eswIoctlPortMirrorConfig {
+ int mirror_port;
+ int port;
+ int egress_en;
+ int ingress_en;
+ int egress_mac_src_en;
+ int egress_mac_des_en;
+ int ingress_mac_src_en;
+ int ingress_mac_des_en;
+ unsigned char *src_mac;
+ unsigned char *des_mac;
+ int mirror_enable;
+};
+
+struct eswIoctlPriorityVlanConfig {
+ int port;
+ int func_enable;
+ int vlan_pri_table_num;
+ int vlan_pri_table_value;
+};
+
+struct eswIoctlPriorityIPConfig {
+ int port;
+ int func_enable;
+ int ipv4_en;
+ int ip_priority_num;
+ int ip_priority_value;
+};
+
+struct eswIoctlPriorityMacConfig {
+ int port;
+};
+
+struct eswIoctlPriorityDefaultConfig{
+ int port;
+ unsigned char priority_value;
+};
+
+struct eswIoctlIrqStatus {
+ unsigned long isr;
+ unsigned long imr;
+ unsigned long rx_buf_pointer;
+ unsigned long tx_buf_pointer;
+ unsigned long rx_max_size;
+ unsigned long rx_buf_active;
+ unsigned long tx_buf_active;
+};
+
+struct eswIoctlPortMirrorStatus {
+ unsigned long ESW_MCR;
+ unsigned long ESW_EGMAP;
+ unsigned long ESW_INGMAP;
+ unsigned long ESW_INGSAL;
+ unsigned long ESW_INGSAH;
+ unsigned long ESW_INGDAL;
+ unsigned long ESW_INGDAH;
+ unsigned long ESW_ENGSAL;
+ unsigned long ESW_ENGSAH;
+ unsigned long ESW_ENGDAL;
+ unsigned long ESW_ENGDAH;
+ unsigned long ESW_MCVAL;
+};
+
+struct eswIoctlVlanOutputConfig {
+ int port;
+ int mode;
+};
+
+struct eswIoctlVlanInputConfig {
+ int port;
+ int mode;
+ unsigned short port_vlanid;
+ int vlan_verify_en;
+ int vlan_domain_num;
+ int vlan_domain_port;
+};
+
+struct eswIoctlVlanVerificationConfig {
+ int port;
+ int vlan_domain_verify_en;
+ int vlan_discard_unknown_en;
+};
+
+struct eswIoctlVlanResoultionTable {
+ unsigned short port_vlanid;
+ int vlan_domain_num;
+ int vlan_domain_port;
+};
+
+struct eswIoctlVlanInputStatus {
+ unsigned long ESW_VLANV;
+ unsigned long ESW_PID[3];
+ unsigned long ESW_VIMSEL;
+ unsigned long ESW_VIMEN;
+ unsigned long ESW_VRES[32];
+};
+
+struct eswIoctlUpdateStaticMACtable {
+ unsigned char *mac_addr;
+ int port;
+ int priority;
+};
+
+struct eswIoctlOutputQueue {
+ int fun_num;
+ struct esw_output_queue_status sOutputQueue;
+};
+
+/*=============================================================*/
+#define LEARNING_AGING_TIMER (10 * HZ)
+/*
+ * Info received from Hardware Learning FIFO,
+ * holding MAC address and corresponding Hash Value and
+ * port number where the frame was received (disassembled).
+ */
+struct eswPortInfo {
+ /* MAC lower 32 bits (first byte is 7:0). */
+ unsigned int maclo;
+ /* MAC upper 16 bits (47:32). */
+ unsigned int machi;
+ /* the hash value for this MAC address. */
+ unsigned int hash;
+ /* the port number this MAC address is associated with. */
+ unsigned int port;
+};
+
+/*
+ * Hardware Look up Address Table 64-bit element.
+ */
+struct eswTable64bitEntry {
+ unsigned int lo; /* lower 32 bits */
+ unsigned int hi; /* upper 32 bits */
+};
+
+/*
+ * Disassembled element stored in Address Table.
+ */
+struct eswAddrTableDynamicEntry {
+ /* MAC lower 32 bits (first byte is 7:0). */
+ unsigned int maclo;
+ /* MAC upper 16 bits (47:32). */
+ unsigned int machi;
+ /* timestamp of this entry */
+ unsigned int timestamp;
+ /* the port number this MAC address is associated with */
+ unsigned int port;
+};
+
+struct eswAddrTableStaticEntry {
+ /* MAC lower 32 bits (first byte is 7:0). */
+ unsigned int maclo;
+ /* MAC upper 16 bits (47:32). */
+ unsigned int machi;
+ /* priority of this entry */
+ unsigned int priority;
+ /* the port bitmask this MAC address is associated with */
+ unsigned int portbitmask;
+};
+/*
+ * Define the buffer descriptor structure.
+ */
+struct cbd_t {
+#if defined(CONFIG_ARCH_MXC) || defined(CONFIG_ARCH_MXS)
+ unsigned short cbd_datlen; /* Data length */
+ unsigned short cbd_sc; /* Control and status info */
+#else
+ unsigned short cbd_sc; /* Control and status info */
+ unsigned short cbd_datlen; /* Data length */
+#endif
+ unsigned long cbd_bufaddr; /* Buffer address */
+#ifdef L2SWITCH_ENHANCED_BUFFER
+ unsigned long ebd_status;
+ unsigned short length_proto_type;
+ unsigned short payload_checksum;
+ unsigned long bdu;
+ unsigned long timestamp;
+ unsigned long reserverd_word1;
+ unsigned long reserverd_word2;
+#endif
+};
+
+/* Forward declarations of some structures to support different PHYs
+ */
+struct phy_cmd_t {
+ uint mii_data;
+ void (*funct)(uint mii_reg, struct net_device *dev);
+};
+
+struct phy_info_t {
+ uint id;
+ char *name;
+
+ const struct phy_cmd_t *config;
+ const struct phy_cmd_t *startup;
+ const struct phy_cmd_t *ack_int;
+ const struct phy_cmd_t *shutdown;
+};
+
+/* The switch buffer descriptors track the ring buffers. The rx_bd_base and
+ * tx_bd_base always point to the base of the buffer descriptors. The
+ * cur_rx and cur_tx point to the currently available buffer.
+ * The dirty_tx tracks the current buffer that is being sent by the
+ * controller. The cur_tx and dirty_tx are equal under both completely
+ * empty and completely full conditions. The empty/ready indicator in
+ * the buffer descriptor determines the actual condition.
+ */
+struct switch_enet_private {
+ /* Hardware registers of the switch device */
+ struct switch_t *hwp;
+ struct eswAddrTable_t *hwentry;
+ unsigned long *enet_addr;
+
+ struct net_device *netdev;
+ struct platform_device *pdev;
+ struct clk *clk;
+ /* The saved address of a sent-in-place packet/buffer, for skfree(). */
+ unsigned char *tx_bounce[TX_RING_SIZE];
+ struct sk_buff *tx_skbuff[TX_RING_SIZE];
+ struct sk_buff *rx_skbuff[RX_RING_SIZE];
+ ushort skb_cur;
+ ushort skb_dirty;
+
+ /* CPM dual port RAM relative addresses */
+ dma_addr_t bd_dma;
+ struct cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */
+ struct cbd_t *tx_bd_base;
+ struct cbd_t *cur_rx, *cur_tx; /* The next free ring entry */
+ struct cbd_t *dirty_tx; /* The ring entries to be free()ed. */
+ uint tx_full;
+ /* hold while accessing the HW like ringbuffer for tx/rx but not MAC */
+ spinlock_t hw_lock;
+
+ /* hold while accessing the mii_list_t() elements */
+ spinlock_t mii_lock;
+ struct mii_bus *mdio_bus;
+ struct phy_device *phydev;
+ phy_interface_t phy_interface;
+
+ uint phy_id;
+ uint phy_id_done;
+ uint phy_status;
+ struct phy_info_t const *phy;
+ struct work_struct phy_task;
+ struct switch_t *phy_hwp;
+
+ uint sequence_done;
+ uint mii_phy_task_queued;
+
+ uint phy_addr;
+
+ int opened;
+ int old_link;
+ int duplex;
+ int speed;
+ int msg_enable;
+
+ /* --------------Statistics--------------------------- */
+ /* when a new element deleted a element with in
+ * a block due to lack of space */
+ int atBlockOverflows;
+ /* Peak number of valid entries in the address table */
+ int atMaxEntries;
+ /* current number of valid entries in the address table */
+ int atCurrEntries;
+ /* maximum entries within a block found
+ * (updated within ageing)*/
+ int atMaxEntriesPerBlock;
+
+ /* -------------------ageing function------------------ */
+ /* maximum age allowed for an entry */
+ int ageMax;
+ /* last LUT entry to block that was
+ * inspected by the Ageing task*/
+ int ageLutIdx;
+ /* last element within block inspected by the Ageing task */
+ int ageBlockElemIdx;
+ /* complete table has been processed by ageing process */
+ int ageCompleted;
+ /* delay setting */
+ int ageDelay;
+ /* current delay Counter */
+ int ageDelayCnt;
+
+ /* ----------------timer related---------------------------- */
+ /* current time (for timestamping) */
+ int currTime;
+ /* flag set by timer when currTime changed
+ * and cleared by serving function*/
+ int timeChanged;
+
+ /**/
+ /* Timer for Aging */
+ struct timer_list timer_aging;
+ int learning_irqhandle_enable;
+ /* Phylib and MDIO interface */
+ struct mii_bus *mii_bus;
+ struct phy_device *phy_dev;
+ int mii_timeout;
+ uint phy_speed;
+ int index;
+ int link;
+ int full_duplex;
+};
+
+struct switch_platform_private {
+ struct platform_device *pdev;
+
+ unsigned long quirks;
+ int num_slots; /* Slots on controller */
+ struct switch_enet_private *fep_host[0]; /* Pointers to hosts */
+};
+
+/******************************************************************************/
+#define FEC_IEVENT 0x004 /* Interrupt event reg */
+#define FEC_IMASK 0x008 /* Interrupt mask reg */
+#define FEC_R_DES_ACTIVE 0x010 /* Receive descriptor reg */
+#define FEC_X_DES_ACTIVE 0x014 /* Transmit descriptor reg */
+#define FEC_ECNTRL 0x024 /* Ethernet control reg */
+#define FEC_MII_DATA 0x040 /* MII manage frame reg */
+#define FEC_MII_SPEED 0x044 /* MII speed control reg */
+#define FEC_MIB_CTRLSTAT 0x064 /* MIB control/status reg */
+#define FEC_R_CNTRL 0x084 /* Receive control reg */
+#define FEC_X_CNTRL 0x0c4 /* Transmit Control reg */
+#define FEC_ADDR_LOW 0x0e4 /* Low 32bits MAC address */
+#define FEC_ADDR_HIGH 0x0e8 /* High 16bits MAC address */
+#define FEC_OPD 0x0ec /* Opcode + Pause duration */
+#define FEC_HASH_TABLE_HIGH 0x118 /* High 32bits hash table */
+#define FEC_HASH_TABLE_LOW 0x11c /* Low 32bits hash table */
+#define FEC_GRP_HASH_TABLE_HIGH 0x120 /* High 32bits hash table */
+#define FEC_GRP_HASH_TABLE_LOW 0x124 /* Low 32bits hash table */
+#define FEC_X_WMRK 0x144 /* FIFO transmit water mark */
+#define FEC_R_BOUND 0x14c /* FIFO receive bound reg */
+#define FEC_R_FSTART 0x150 /* FIFO receive start reg */
+#define FEC_R_DES_START 0x180 /* Receive descriptor ring */
+#define FEC_X_DES_START 0x184 /* Transmit descriptor ring */
+#define FEC_R_BUFF_SIZE 0x188 /* Maximum receive buff size */
+#define FEC_MIIGSK_CFGR 0x300 /* MIIGSK config register */
+#define FEC_MIIGSK_ENR 0x308 /* MIIGSK enable register */
+
+/* Recieve is empty */
+#define BD_SC_EMPTY ((unsigned short)0x8000)
+/* Transmit is ready */
+#define BD_SC_READY ((unsigned short)0x8000)
+/* Last buffer descriptor */
+#define BD_SC_WRAP ((unsigned short)0x2000)
+/* Interrupt on change */
+#define BD_SC_INTRPT ((unsigned short)0x1000)
+/* Continous mode */
+#define BD_SC_CM ((unsigned short)0x0200)
+/* Rec'd too many idles */
+#define BD_SC_ID ((unsigned short)0x0100)
+/* xmt preamble */
+#define BD_SC_P ((unsigned short)0x0100)
+/* Break received */
+#define BD_SC_BR ((unsigned short)0x0020)
+/* Framing error */
+#define BD_SC_FR ((unsigned short)0x0010)
+/* Parity error */
+#define BD_SC_PR ((unsigned short)0x0008)
+/* Overrun */
+#define BD_SC_OV ((unsigned short)0x0002)
+#define BD_SC_CD ((unsigned short)0x0001)
+
+/* Buffer descriptor control/status used by Ethernet receive.
+*/
+#define BD_ENET_RX_EMPTY ((unsigned short)0x8000)
+#define BD_ENET_RX_WRAP ((unsigned short)0x2000)
+#define BD_ENET_RX_INTR ((unsigned short)0x1000)
+#define BD_ENET_RX_LAST ((unsigned short)0x0800)
+#define BD_ENET_RX_FIRST ((unsigned short)0x0400)
+#define BD_ENET_RX_MISS ((unsigned short)0x0100)
+#define BD_ENET_RX_LG ((unsigned short)0x0020)
+#define BD_ENET_RX_NO ((unsigned short)0x0010)
+#define BD_ENET_RX_SH ((unsigned short)0x0008)
+#define BD_ENET_RX_CR ((unsigned short)0x0004)
+#define BD_ENET_RX_OV ((unsigned short)0x0002)
+#define BD_ENET_RX_CL ((unsigned short)0x0001)
+/* All status bits */
+#define BD_ENET_RX_STATS ((unsigned short)0x013f)
+
+/* Buffer descriptor control/status used by Ethernet transmit.
+*/
+#define BD_ENET_TX_READY ((unsigned short)0x8000)
+#define BD_ENET_TX_PAD ((unsigned short)0x4000)
+#define BD_ENET_TX_WRAP ((unsigned short)0x2000)
+#define BD_ENET_TX_INTR ((unsigned short)0x1000)
+#define BD_ENET_TX_LAST ((unsigned short)0x0800)
+#define BD_ENET_TX_TC ((unsigned short)0x0400)
+#define BD_ENET_TX_DEF ((unsigned short)0x0200)
+#define BD_ENET_TX_HB ((unsigned short)0x0100)
+#define BD_ENET_TX_LC ((unsigned short)0x0080)
+#define BD_ENET_TX_RL ((unsigned short)0x0040)
+#define BD_ENET_TX_RCMASK ((unsigned short)0x003c)
+#define BD_ENET_TX_UN ((unsigned short)0x0002)
+#define BD_ENET_TX_CSL ((unsigned short)0x0001)
+/* All status bits */
+#define BD_ENET_TX_STATS ((unsigned short)0x03ff)
+
+/*Copy from validation code */
+#define RX_BUFFER_SIZE 256
+#define TX_BUFFER_SIZE 256
+#define NUM_RXBDS 20
+#define NUM_TXBDS 20
+
+#define TX_BD_R 0x8000
+#define TX_BD_TO1 0x4000
+#define TX_BD_W 0x2000
+#define TX_BD_TO2 0x1000
+#define TX_BD_L 0x0800
+#define TX_BD_TC 0x0400
+
+#define TX_BD_INT 0x40000000
+#define TX_BD_TS 0x20000000
+#define TX_BD_PINS 0x10000000
+#define TX_BD_IINS 0x08000000
+#define TX_BD_TXE 0x00008000
+#define TX_BD_UE 0x00002000
+#define TX_BD_EE 0x00001000
+#define TX_BD_FE 0x00000800
+#define TX_BD_LCE 0x00000400
+#define TX_BD_OE 0x00000200
+#define TX_BD_TSE 0x00000100
+#define TX_BD_BDU 0x80000000
+
+#define RX_BD_E 0x8000
+#define RX_BD_R01 0x4000
+#define RX_BD_W 0x2000
+#define RX_BD_R02 0x1000
+#define RX_BD_L 0x0800
+#define RX_BD_M 0x0100
+#define RX_BD_BC 0x0080
+#define RX_BD_MC 0x0040
+#define RX_BD_LG 0x0020
+#define RX_BD_NO 0x0010
+#define RX_BD_CR 0x0004
+#define RX_BD_OV 0x0002
+#define RX_BD_TR 0x0001
+
+#define RX_BD_ME 0x80000000
+#define RX_BD_PE 0x04000000
+#define RX_BD_CE 0x02000000
+#define RX_BD_UC 0x01000000
+#define RX_BD_INT 0x00800000
+#define RX_BD_ICE 0x00000020
+#define RX_BD_PCR 0x00000010
+#define RX_BD_VLAN 0x00000004
+#define RX_BD_IPV6 0x00000002
+#define RX_BD_FRAG 0x00000001
+#define RX_BD_BDU 0x80000000
+/****************************************************************************/
+
+/* Address Table size in bytes(2048 64bit entry ) */
+#define ESW_ATABLE_MEM_SIZE (2048*8)
+/* How many 64-bit elements fit in the address table */
+#define ESW_ATABLE_MEM_NUM_ENTRIES (2048)
+/* Address Table Maximum number of entries in each Slot */
+#define ATABLE_ENTRY_PER_SLOT 8
+/* log2(ATABLE_ENTRY_PER_SLOT)*/
+#define ATABLE_ENTRY_PER_SLOT_bits 3
+/* entry size in byte */
+#define ATABLE_ENTRY_SIZE 8
+/* slot size in byte */
+#define ATABLE_SLOT_SIZE (ATABLE_ENTRY_PER_SLOT * ATABLE_ENTRY_SIZE)
+/* width of timestamp variable (bits) within address table entry */
+#define AT_DENTRY_TIMESTAMP_WIDTH 10
+/* number of bits for port number storage */
+#define AT_DENTRY_PORT_WIDTH 4
+/* number of bits for port bitmask number storage */
+#define AT_SENTRY_PORT_WIDTH 11
+/* address table static entry port bitmask start address bit */
+#define AT_SENTRY_PORTMASK_shift 21
+/* address table static entry priority start address bit */
+#define AT_SENTRY_PRIO_shift 18
+/* address table dynamic entry port start address bit */
+#define AT_DENTRY_PORT_shift 28
+/* address table dynamic entry timestamp start address bit */
+#define AT_DENTRY_TIME_shift 18
+/* address table entry record type start address bit */
+#define AT_ENTRY_TYPE_shift 17
+/* address table entry record type bit: 1 static, 0 dynamic */
+#define AT_ENTRY_TYPE_STATIC 1
+#define AT_ENTRY_TYPE_DYNAMIC 0
+/* address table entry record valid start address bit */
+#define AT_ENTRY_VALID_shift 16
+#define AT_ENTRY_RECORD_VALID 1
+
+
+/* return block corresponding to the 8 bit hash value calculated */
+#define GET_BLOCK_PTR(hash) (hash << 3)
+#define AT_EXTRACT_TIMESTAMP(x) \
+ ((x >> AT_DENTRY_TIME_shift) & ((1 << AT_DENTRY_TIMESTAMP_WIDTH)-1))
+#define AT_EXTRACT_PORT(x) \
+ ((x >> AT_DENTRY_PORT_shift) & ((1 << AT_DENTRY_PORT_WIDTH)-1))
+#define TIMEDELTA(newtime, oldtime) \
+ ((newtime - oldtime) & \
+ ((1 << AT_DENTRY_TIMESTAMP_WIDTH)-1))
+/* increment time value respecting modulo. */
+#define TIMEINCREMENT(time) \
+ ((time) = ((time)+1) & ((1 << AT_DENTRY_TIMESTAMP_WIDTH)-1))
+/* ------------------------------------------------------------------------- */
+/* Bit definitions and macros for MCF_ESW_REVISION */
+#define MCF_ESW_REVISION_CORE_REVISION(x) (((x)&0x0000FFFF)<<0)
+#define MCF_ESW_REVISION_CUSTOMER_REVISION(x) (((x)&0x0000FFFF)<<16)
+
+/* Bit definitions and macros for MCF_ESW_PER */
+#define MCF_ESW_PER_TE0 (0x00000001)
+#define MCF_ESW_PER_TE1 (0x00000002)
+#define MCF_ESW_PER_TE2 (0x00000004)
+#define MCF_ESW_PER_RE0 (0x00010000)
+#define MCF_ESW_PER_RE1 (0x00020000)
+#define MCF_ESW_PER_RE2 (0x00040000)
+
+/* Bit definitions and macros for MCF_ESW_VLANV */
+#define MCF_ESW_VLANV_VV0 (0x00000001)
+#define MCF_ESW_VLANV_VV1 (0x00000002)
+#define MCF_ESW_VLANV_VV2 (0x00000004)
+#define MCF_ESW_VLANV_DU0 (0x00010000)
+#define MCF_ESW_VLANV_DU1 (0x00020000)
+#define MCF_ESW_VLANV_DU2 (0x00040000)
+
+/* Bit definitions and macros for MCF_ESW_DBCR */
+#define MCF_ESW_DBCR_P0 (0x00000001)
+#define MCF_ESW_DBCR_P1 (0x00000002)
+#define MCF_ESW_DBCR_P2 (0x00000004)
+
+/* Bit definitions and macros for MCF_ESW_DMCR */
+#define MCF_ESW_DMCR_P0 (0x00000001)
+#define MCF_ESW_DMCR_P1 (0x00000002)
+#define MCF_ESW_DMCR_P2 (0x00000004)
+
+/* Bit definitions and macros for MCF_ESW_BKLR */
+#define MCF_ESW_BKLR_BE0 (0x00000001)
+#define MCF_ESW_BKLR_BE1 (0x00000002)
+#define MCF_ESW_BKLR_BE2 (0x00000004)
+#define MCF_ESW_BKLR_LD0 (0x00010000)
+#define MCF_ESW_BKLR_LD1 (0x00020000)
+#define MCF_ESW_BKLR_LD2 (0x00040000)
+
+/* Bit definitions and macros for MCF_ESW_BMPC */
+#define MCF_ESW_BMPC_PORT(x) (((x)&0x0000000F)<<0)
+#define MCF_ESW_BMPC_MSG_TX (0x00000020)
+#define MCF_ESW_BMPC_EN (0x00000040)
+#define MCF_ESW_BMPC_DIS (0x00000080)
+#define MCF_ESW_BMPC_PRIORITY(x) (((x)&0x00000007)<<13)
+#define MCF_ESW_BMPC_PORTMASK(x) (((x)&0x00000007)<<16)
+
+/* Bit definitions and macros for MCF_ESW_MODE */
+#define MCF_ESW_MODE_SW_RST (0x00000001)
+#define MCF_ESW_MODE_SW_EN (0x00000002)
+#define MCF_ESW_MODE_STOP (0x00000080)
+#define MCF_ESW_MODE_CRC_TRAN (0x00000100)
+#define MCF_ESW_MODE_P0CT (0x00000200)
+#define MCF_ESW_MODE_STATRST (0x80000000)
+
+/* Bit definitions and macros for MCF_ESW_VIMSEL */
+#define MCF_ESW_VIMSEL_IM0(x) (((x)&0x00000003)<<0)
+#define MCF_ESW_VIMSEL_IM1(x) (((x)&0x00000003)<<2)
+#define MCF_ESW_VIMSEL_IM2(x) (((x)&0x00000003)<<4)
+
+/* Bit definitions and macros for MCF_ESW_VOMSEL */
+#define MCF_ESW_VOMSEL_OM0(x) (((x)&0x00000003)<<0)
+#define MCF_ESW_VOMSEL_OM1(x) (((x)&0x00000003)<<2)
+#define MCF_ESW_VOMSEL_OM2(x) (((x)&0x00000003)<<4)
+
+/* Bit definitions and macros for MCF_ESW_VIMEN */
+#define MCF_ESW_VIMEN_EN0 (0x00000001)
+#define MCF_ESW_VIMEN_EN1 (0x00000002)
+#define MCF_ESW_VIMEN_EN2 (0x00000004)
+
+/* Bit definitions and macros for MCF_ESW_VID */
+#define MCF_ESW_VID_TAG(x) (((x)&0xFFFFFFFF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_MCR */
+#define MCF_ESW_MCR_PORT(x) (((x)&0x0000000F)<<0)
+#define MCF_ESW_MCR_MEN (0x00000010)
+#define MCF_ESW_MCR_INGMAP (0x00000020)
+#define MCF_ESW_MCR_EGMAP (0x00000040)
+#define MCF_ESW_MCR_INGSA (0x00000080)
+#define MCF_ESW_MCR_INGDA (0x00000100)
+#define MCF_ESW_MCR_EGSA (0x00000200)
+#define MCF_ESW_MCR_EGDA (0x00000400)
+
+/* Bit definitions and macros for MCF_ESW_EGMAP */
+#define MCF_ESW_EGMAP_EG0 (0x00000001)
+#define MCF_ESW_EGMAP_EG1 (0x00000002)
+#define MCF_ESW_EGMAP_EG2 (0x00000004)
+
+/* Bit definitions and macros for MCF_ESW_INGMAP */
+#define MCF_ESW_INGMAP_ING0 (0x00000001)
+#define MCF_ESW_INGMAP_ING1 (0x00000002)
+#define MCF_ESW_INGMAP_ING2 (0x00000004)
+
+/* Bit definitions and macros for MCF_ESW_INGSAL */
+#define MCF_ESW_INGSAL_ADDLOW(x) (((x)&0xFFFFFFFF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_INGSAH */
+#define MCF_ESW_INGSAH_ADDHIGH(x) (((x)&0x0000FFFF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_INGDAL */
+#define MCF_ESW_INGDAL_ADDLOW(x) (((x)&0xFFFFFFFF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_INGDAH */
+#define MCF_ESW_INGDAH_ADDHIGH(x) (((x)&0x0000FFFF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_ENGSAL */
+#define MCF_ESW_ENGSAL_ADDLOW(x) (((x)&0xFFFFFFFF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_ENGSAH */
+#define MCF_ESW_ENGSAH_ADDHIGH(x) (((x)&0x0000FFFF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_ENGDAL */
+#define MCF_ESW_ENGDAL_ADDLOW(x) (((x)&0xFFFFFFFF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_ENGDAH */
+#define MCF_ESW_ENGDAH_ADDHIGH(x) (((x)&0x0000FFFF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_MCVAL */
+#define MCF_ESW_MCVAL_COUNT(x) (((x)&0x000000FF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_MMSR */
+#define MCF_ESW_MMSR_BUSY (0x00000001)
+#define MCF_ESW_MMSR_NOCELL (0x00000002)
+#define MCF_ESW_MMSR_MEMFULL (0x00000004)
+#define MCF_ESW_MMSR_MFLATCH (0x00000008)
+#define MCF_ESW_MMSR_DQ_GRNT (0x00000040)
+#define MCF_ESW_MMSR_CELLS_AVAIL(x) (((x)&0x000000FF)<<16)
+
+/* Bit definitions and macros for MCF_ESW_LMT */
+#define MCF_ESW_LMT_THRESH(x) (((x)&0x000000FF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_LFC */
+#define MCF_ESW_LFC_COUNT(x) (((x)&0xFFFFFFFF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_PCSR */
+#define MCF_ESW_PCSR_PC0 (0x00000001)
+#define MCF_ESW_PCSR_PC1 (0x00000002)
+#define MCF_ESW_PCSR_PC2 (0x00000004)
+
+/* Bit definitions and macros for MCF_ESW_IOSR */
+#define MCF_ESW_IOSR_OR0 (0x00000001)
+#define MCF_ESW_IOSR_OR1 (0x00000002)
+#define MCF_ESW_IOSR_OR2 (0x00000004)
+
+/* Bit definitions and macros for MCF_ESW_QWT */
+#define MCF_ESW_QWT_Q0WT(x) (((x)&0x0000001F)<<0)
+#define MCF_ESW_QWT_Q1WT(x) (((x)&0x0000001F)<<8)
+#define MCF_ESW_QWT_Q2WT(x) (((x)&0x0000001F)<<16)
+#define MCF_ESW_QWT_Q3WT(x) (((x)&0x0000001F)<<24)
+
+/* Bit definitions and macros for MCF_ESW_P0BCT */
+#define MCF_ESW_P0BCT_THRESH(x) (((x)&0x000000FF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_P0FFEN */
+#define MCF_ESW_P0FFEN_FEN (0x00000001)
+#define MCF_ESW_P0FFEN_FD(x) (((x)&0x00000003)<<2)
+
+/* Bit definitions and macros for MCF_ESW_PSNP */
+#define MCF_ESW_PSNP_EN (0x00000001)
+#define MCF_ESW_PSNP_MODE(x) (((x)&0x00000003)<<1)
+#define MCF_ESW_PSNP_CD (0x00000008)
+#define MCF_ESW_PSNP_CS (0x00000010)
+#define MCF_ESW_PSNP_PORT_COMPARE(x) (((x)&0x0000FFFF)<<16)
+
+/* Bit definitions and macros for MCF_ESW_IPSNP */
+#define MCF_ESW_IPSNP_EN (0x00000001)
+#define MCF_ESW_IPSNP_MODE(x) (((x)&0x00000003)<<1)
+#define MCF_ESW_IPSNP_PROTOCOL(x) (((x)&0x000000FF)<<8)
+
+/* Bit definitions and macros for MCF_ESW_PVRES */
+#define MCF_ESW_PVRES_PRI0(x) (((x)&0x00000007)<<0)
+#define MCF_ESW_PVRES_PRI1(x) (((x)&0x00000007)<<3)
+#define MCF_ESW_PVRES_PRI2(x) (((x)&0x00000007)<<6)
+#define MCF_ESW_PVRES_PRI3(x) (((x)&0x00000007)<<9)
+#define MCF_ESW_PVRES_PRI4(x) (((x)&0x00000007)<<12)
+#define MCF_ESW_PVRES_PRI5(x) (((x)&0x00000007)<<15)
+#define MCF_ESW_PVRES_PRI6(x) (((x)&0x00000007)<<18)
+#define MCF_ESW_PVRES_PRI7(x) (((x)&0x00000007)<<21)
+
+/* Bit definitions and macros for MCF_ESW_IPRES */
+#define MCF_ESW_IPRES_ADDRESS(x) (((x)&0x000000FF)<<0)
+#define MCF_ESW_IPRES_IPV4SEL (0x00000100)
+#define MCF_ESW_IPRES_PRI0(x) (((x)&0x00000003)<<9)
+#define MCF_ESW_IPRES_PRI1(x) (((x)&0x00000003)<<11)
+#define MCF_ESW_IPRES_PRI2(x) (((x)&0x00000003)<<13)
+#define MCF_ESW_IPRES_READ (0x80000000)
+
+/* Bit definitions and macros for MCF_ESW_PRES */
+#define MCF_ESW_PRES_VLAN (0x00000001)
+#define MCF_ESW_PRES_IP (0x00000002)
+#define MCF_ESW_PRES_MAC (0x00000004)
+#define MCF_ESW_PRES_DFLT_PRI(x) (((x)&0x00000007)<<4)
+
+/* Bit definitions and macros for MCF_ESW_PID */
+#define MCF_ESW_PID_VLANID(x) (((x)&0x0000FFFF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_VRES */
+#define MCF_ESW_VRES_P0 (0x00000001)
+#define MCF_ESW_VRES_P1 (0x00000002)
+#define MCF_ESW_VRES_P2 (0x00000004)
+#define MCF_ESW_VRES_VLANID(x) (((x)&0x00000FFF)<<3)
+
+/* Bit definitions and macros for MCF_ESW_DISCN */
+#define MCF_ESW_DISCN_COUNT(x) (((x)&0xFFFFFFFF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_DISCB */
+#define MCF_ESW_DISCB_COUNT(x) (((x)&0xFFFFFFFF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_NDISCN */
+#define MCF_ESW_NDISCN_COUNT(x) (((x)&0xFFFFFFFF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_NDISCB */
+#define MCF_ESW_NDISCB_COUNT(x) (((x)&0xFFFFFFFF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_POQC */
+#define MCF_ESW_POQC_COUNT(x) (((x)&0xFFFFFFFF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_PMVID */
+#define MCF_ESW_PMVID_COUNT(x) (((x)&0xFFFFFFFF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_PMVTAG */
+#define MCF_ESW_PMVTAG_COUNT(x) (((x)&0xFFFFFFFF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_PBL */
+#define MCF_ESW_PBL_COUNT(x) (((x)&0xFFFFFFFF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_ISR */
+#define MCF_ESW_ISR_EBERR (0x00000001)
+#define MCF_ESW_ISR_RXB (0x00000002)
+#define MCF_ESW_ISR_RXF (0x00000004)
+#define MCF_ESW_ISR_TXB (0x00000008)
+#define MCF_ESW_ISR_TXF (0x00000010)
+#define MCF_ESW_ISR_QM (0x00000020)
+#define MCF_ESW_ISR_OD0 (0x00000040)
+#define MCF_ESW_ISR_OD1 (0x00000080)
+#define MCF_ESW_ISR_OD2 (0x00000100)
+#define MCF_ESW_ISR_LRN (0x00000200)
+
+/* Bit definitions and macros for MCF_ESW_IMR */
+#define MCF_ESW_IMR_EBERR (0x00000001)
+#define MCF_ESW_IMR_RXB (0x00000002)
+#define MCF_ESW_IMR_RXF (0x00000004)
+#define MCF_ESW_IMR_TXB (0x00000008)
+#define MCF_ESW_IMR_TXF (0x00000010)
+#define MCF_ESW_IMR_QM (0x00000020)
+#define MCF_ESW_IMR_OD0 (0x00000040)
+#define MCF_ESW_IMR_OD1 (0x00000080)
+#define MCF_ESW_IMR_OD2 (0x00000100)
+#define MCF_ESW_IMR_LRN (0x00000200)
+
+/* Bit definitions and macros for MCF_ESW_RDSR */
+#define MCF_ESW_RDSR_ADDRESS(x) (((x)&0x3FFFFFFF)<<2)
+
+/* Bit definitions and macros for MCF_ESW_TDSR */
+#define MCF_ESW_TDSR_ADDRESS(x) (((x)&0x3FFFFFFF)<<2)
+
+/* Bit definitions and macros for MCF_ESW_MRBR */
+#define MCF_ESW_MRBR_SIZE(x) (((x)&0x000003FF)<<4)
+
+/* Bit definitions and macros for MCF_ESW_RDAR */
+#define MCF_ESW_RDAR_R_DES_ACTIVE (0x01000000)
+
+/* Bit definitions and macros for MCF_ESW_TDAR */
+#define MCF_ESW_TDAR_X_DES_ACTIVE (0x01000000)
+
+/* Bit definitions and macros for MCF_ESW_LREC0 */
+#define MCF_ESW_LREC0_MACADDR0(x) (((x)&0xFFFFFFFF)<<0)
+
+/* Bit definitions and macros for MCF_ESW_LREC1 */
+#define MCF_ESW_LREC1_MACADDR1(x) (((x)&0x0000FFFF)<<0)
+#define MCF_ESW_LREC1_HASH(x) (((x)&0x000000FF)<<16)
+#define MCF_ESW_LREC1_SWPORT(x) (((x)&0x00000003)<<24)
+
+/* Bit definitions and macros for MCF_ESW_LSR */
+#define MCF_ESW_LSR_DA (0x00000001)
+
+#endif /* SWITCH_H */
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index e44215cb1882..9048718aff1b 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -495,7 +495,7 @@ static void veth_take_cap_ack(struct veth_lpar_connection *cnx,
cnx->remote_lp);
} else {
memcpy(&cnx->cap_ack_event, event,
- sizeof(&cnx->cap_ack_event));
+ sizeof(cnx->cap_ack_event));
cnx->state |= VETH_STATE_GOTCAPACK;
veth_kick_statemachine(cnx);
}
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c
index b9ceddde46c0..4ff665c0f144 100644
--- a/drivers/net/mlx4/eq.c
+++ b/drivers/net/mlx4/eq.c
@@ -526,48 +526,6 @@ static void mlx4_unmap_clr_int(struct mlx4_dev *dev)
iounmap(priv->clr_base);
}
-int mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt)
-{
- struct mlx4_priv *priv = mlx4_priv(dev);
- int ret;
-
- /*
- * We assume that mapping one page is enough for the whole EQ
- * context table. This is fine with all current HCAs, because
- * we only use 32 EQs and each EQ uses 64 bytes of context
- * memory, or 1 KB total.
- */
- priv->eq_table.icm_virt = icm_virt;
- priv->eq_table.icm_page = alloc_page(GFP_HIGHUSER);
- if (!priv->eq_table.icm_page)
- return -ENOMEM;
- priv->eq_table.icm_dma = pci_map_page(dev->pdev, priv->eq_table.icm_page, 0,
- PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
- if (pci_dma_mapping_error(dev->pdev, priv->eq_table.icm_dma)) {
- __free_page(priv->eq_table.icm_page);
- return -ENOMEM;
- }
-
- ret = mlx4_MAP_ICM_page(dev, priv->eq_table.icm_dma, icm_virt);
- if (ret) {
- pci_unmap_page(dev->pdev, priv->eq_table.icm_dma, PAGE_SIZE,
- PCI_DMA_BIDIRECTIONAL);
- __free_page(priv->eq_table.icm_page);
- }
-
- return ret;
-}
-
-void mlx4_unmap_eq_icm(struct mlx4_dev *dev)
-{
- struct mlx4_priv *priv = mlx4_priv(dev);
-
- mlx4_UNMAP_ICM(dev, priv->eq_table.icm_virt, 1);
- pci_unmap_page(dev->pdev, priv->eq_table.icm_dma, PAGE_SIZE,
- PCI_DMA_BIDIRECTIONAL);
- __free_page(priv->eq_table.icm_page);
-}
-
int mlx4_alloc_eq_table(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c
index dac621b1e9fc..8e8b79fed508 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -525,7 +525,10 @@ static int mlx4_init_icm(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap,
goto err_unmap_aux;
}
- err = mlx4_map_eq_icm(dev, init_hca->eqc_base);
+ err = mlx4_init_icm_table(dev, &priv->eq_table.table,
+ init_hca->eqc_base, dev_cap->eqc_entry_sz,
+ dev->caps.num_eqs, dev->caps.num_eqs,
+ 0, 0);
if (err) {
mlx4_err(dev, "Failed to map EQ context memory, aborting.\n");
goto err_unmap_cmpt;
@@ -668,7 +671,7 @@ err_unmap_mtt:
mlx4_cleanup_icm_table(dev, &priv->mr_table.mtt_table);
err_unmap_eq:
- mlx4_unmap_eq_icm(dev);
+ mlx4_cleanup_icm_table(dev, &priv->eq_table.table);
err_unmap_cmpt:
mlx4_cleanup_icm_table(dev, &priv->eq_table.cmpt_table);
@@ -698,11 +701,11 @@ static void mlx4_free_icms(struct mlx4_dev *dev)
mlx4_cleanup_icm_table(dev, &priv->qp_table.qp_table);
mlx4_cleanup_icm_table(dev, &priv->mr_table.dmpt_table);
mlx4_cleanup_icm_table(dev, &priv->mr_table.mtt_table);
+ mlx4_cleanup_icm_table(dev, &priv->eq_table.table);
mlx4_cleanup_icm_table(dev, &priv->eq_table.cmpt_table);
mlx4_cleanup_icm_table(dev, &priv->cq_table.cmpt_table);
mlx4_cleanup_icm_table(dev, &priv->srq_table.cmpt_table);
mlx4_cleanup_icm_table(dev, &priv->qp_table.cmpt_table);
- mlx4_unmap_eq_icm(dev);
mlx4_UNMAP_ICM_AUX(dev);
mlx4_free_icm(dev, priv->fw.aux_icm, 0);
diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h
index 5bd79c2b184f..bc72d6e4919b 100644
--- a/drivers/net/mlx4/mlx4.h
+++ b/drivers/net/mlx4/mlx4.h
@@ -205,9 +205,7 @@ struct mlx4_eq_table {
void __iomem **uar_map;
u32 clr_mask;
struct mlx4_eq *eq;
- u64 icm_virt;
- struct page *icm_page;
- dma_addr_t icm_dma;
+ struct mlx4_icm_table table;
struct mlx4_icm_table cmpt_table;
int have_irq;
u8 inta_pin;
@@ -373,9 +371,6 @@ u64 mlx4_make_profile(struct mlx4_dev *dev,
struct mlx4_dev_cap *dev_cap,
struct mlx4_init_hca_param *init_hca);
-int mlx4_map_eq_icm(struct mlx4_dev *dev, u64 icm_virt);
-void mlx4_unmap_eq_icm(struct mlx4_dev *dev);
-
int mlx4_cmd_init(struct mlx4_dev *dev);
void mlx4_cmd_cleanup(struct mlx4_dev *dev);
void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param);
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index bd4e8d72dc08..e17b70291bbc 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -264,6 +264,8 @@ static int mdio_bus_match(struct device *dev, struct device_driver *drv)
(phydev->phy_id & phydrv->phy_id_mask));
}
+#ifdef CONFIG_PM
+
static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
{
struct device_driver *drv = phydev->dev.driver;
@@ -295,34 +297,88 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
return true;
}
-/* Suspend and resume. Copied from platform_suspend and
- * platform_resume
- */
-static int mdio_bus_suspend(struct device * dev, pm_message_t state)
+static int mdio_bus_suspend(struct device *dev)
{
struct phy_driver *phydrv = to_phy_driver(dev->driver);
struct phy_device *phydev = to_phy_device(dev);
+ /*
+ * We must stop the state machine manually, otherwise it stops out of
+ * control, possibly with the phydev->lock held. Upon resume, netdev
+ * may call phy routines that try to grab the same lock, and that may
+ * lead to a deadlock.
+ */
+ if (phydev->attached_dev)
+ phy_stop_machine(phydev);
+
if (!mdio_bus_phy_may_suspend(phydev))
return 0;
+
return phydrv->suspend(phydev);
}
-static int mdio_bus_resume(struct device * dev)
+static int mdio_bus_resume(struct device *dev)
{
struct phy_driver *phydrv = to_phy_driver(dev->driver);
struct phy_device *phydev = to_phy_device(dev);
+ int ret;
if (!mdio_bus_phy_may_suspend(phydev))
+ goto no_resume;
+
+ ret = phydrv->resume(phydev);
+ if (ret < 0)
+ return ret;
+
+no_resume:
+ if (phydev->attached_dev)
+ phy_start_machine(phydev, NULL);
+
+ return 0;
+}
+
+static int mdio_bus_restore(struct device *dev)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+ struct net_device *netdev = phydev->attached_dev;
+ int ret;
+
+ if (!netdev)
return 0;
- return phydrv->resume(phydev);
+
+ ret = phy_init_hw(phydev);
+ if (ret < 0)
+ return ret;
+
+ /* The PHY needs to renegotiate. */
+ phydev->link = 0;
+ phydev->state = PHY_UP;
+
+ phy_start_machine(phydev, NULL);
+
+ return 0;
}
+static struct dev_pm_ops mdio_bus_pm_ops = {
+ .suspend = mdio_bus_suspend,
+ .resume = mdio_bus_resume,
+ .freeze = mdio_bus_suspend,
+ .thaw = mdio_bus_resume,
+ .restore = mdio_bus_restore,
+};
+
+#define MDIO_BUS_PM_OPS (&mdio_bus_pm_ops)
+
+#else
+
+#define MDIO_BUS_PM_OPS NULL
+
+#endif /* CONFIG_PM */
+
struct bus_type mdio_bus_type = {
.name = "mdio_bus",
.match = mdio_bus_match,
- .suspend = mdio_bus_suspend,
- .resume = mdio_bus_resume,
+ .pm = MDIO_BUS_PM_OPS,
};
EXPORT_SYMBOL(mdio_bus_type);
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index eda94fcd4065..d2df6382e123 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -413,7 +413,6 @@ EXPORT_SYMBOL(phy_start_aneg);
static void phy_change(struct work_struct *work);
-static void phy_state_machine(struct work_struct *work);
/**
* phy_start_machine - start PHY state machine tracking
@@ -433,7 +432,6 @@ void phy_start_machine(struct phy_device *phydev,
{
phydev->adjust_state = handler;
- INIT_DELAYED_WORK(&phydev->state_queue, phy_state_machine);
schedule_delayed_work(&phydev->state_queue, HZ);
}
@@ -764,7 +762,7 @@ EXPORT_SYMBOL(phy_start);
* phy_state_machine - Handle the state machine
* @work: work_struct that describes the work to be done
*/
-static void phy_state_machine(struct work_struct *work)
+void phy_state_machine(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct phy_device *phydev =
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index b10fedd82143..adbc0fded130 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -177,6 +177,7 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
dev->state = PHY_DOWN;
mutex_init(&dev->lock);
+ INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
return dev;
}
@@ -378,6 +379,20 @@ void phy_disconnect(struct phy_device *phydev)
}
EXPORT_SYMBOL(phy_disconnect);
+int phy_init_hw(struct phy_device *phydev)
+{
+ int ret;
+
+ if (!phydev->drv || !phydev->drv->config_init)
+ return 0;
+
+ ret = phy_scan_fixups(phydev);
+ if (ret < 0)
+ return ret;
+
+ return phydev->drv->config_init(phydev);
+}
+
/**
* phy_attach_direct - attach a network device to a given PHY device pointer
* @dev: network device to attach
@@ -425,21 +440,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
/* Do initial configuration here, now that
* we have certain key parameters
* (dev_flags and interface) */
- if (phydev->drv->config_init) {
- int err;
-
- err = phy_scan_fixups(phydev);
-
- if (err < 0)
- return err;
-
- err = phydev->drv->config_init(phydev);
-
- if (err < 0)
- return err;
- }
-
- return 0;
+ return phy_init_hw(phydev);
}
EXPORT_SYMBOL(phy_attach_direct);
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
index 01f9432c31ef..98bff5ada09a 100644
--- a/drivers/net/sfc/rx.c
+++ b/drivers/net/sfc/rx.c
@@ -444,7 +444,8 @@ static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
* the appropriate LRO method
*/
static void efx_rx_packet_lro(struct efx_channel *channel,
- struct efx_rx_buffer *rx_buf)
+ struct efx_rx_buffer *rx_buf,
+ bool checksummed)
{
struct napi_struct *napi = &channel->napi_str;
@@ -466,7 +467,8 @@ static void efx_rx_packet_lro(struct efx_channel *channel,
skb->len = rx_buf->len;
skb->data_len = rx_buf->len;
skb->truesize += rx_buf->len;
- skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->ip_summed =
+ checksummed ? CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
napi_gro_frags(napi);
@@ -475,6 +477,7 @@ out:
rx_buf->page = NULL;
} else {
EFX_BUG_ON_PARANOID(!rx_buf->skb);
+ EFX_BUG_ON_PARANOID(!checksummed);
napi_gro_receive(napi, rx_buf->skb);
rx_buf->skb = NULL;
@@ -570,7 +573,7 @@ void __efx_rx_packet(struct efx_channel *channel,
}
if (likely(checksummed || rx_buf->page)) {
- efx_rx_packet_lro(channel, rx_buf);
+ efx_rx_packet_lro(channel, rx_buf, checksummed);
goto done;
}
diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c
index 14a14788566c..d36a2894f005 100644
--- a/drivers/net/sfc/tx.c
+++ b/drivers/net/sfc/tx.c
@@ -823,8 +823,6 @@ static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue)
tx_queue->efx->type->txd_ring_mask];
efx_tsoh_free(tx_queue, buffer);
EFX_BUG_ON_PARANOID(buffer->skb);
- buffer->len = 0;
- buffer->continuation = true;
if (buffer->unmap_len) {
unmap_addr = (buffer->dma_addr + buffer->len -
buffer->unmap_len);
@@ -838,6 +836,8 @@ static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue)
PCI_DMA_TODEVICE);
buffer->unmap_len = 0;
}
+ buffer->len = 0;
+ buffer->continuation = true;
}
}
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 0a551d8f5d95..329f447f5bf7 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -1455,7 +1455,6 @@ static int sky2_up(struct net_device *dev)
if (ramsize > 0) {
u32 rxspace;
- hw->flags |= SKY2_HW_RAM_BUFFER;
pr_debug(PFX "%s: ram buffer %dK\n", dev->name, ramsize);
if (ramsize < 16)
rxspace = ramsize / 2;
@@ -2942,6 +2941,9 @@ static int __devinit sky2_init(struct sky2_hw *hw)
++hw->ports;
}
+ if (sky2_read8(hw, B2_E_0))
+ hw->flags |= SKY2_HW_RAM_BUFFER;
+
return 0;
}
@@ -4526,6 +4528,8 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
goto err_out_free_netdev;
}
+ netif_carrier_off(dev);
+
netif_napi_add(dev, &hw->napi, sky2_poll, NAPI_WEIGHT);
err = request_irq(pdev->irq, sky2_intr,
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 7567f510eff5..d8ed1b63da78 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -2283,7 +2283,7 @@ static int __devinit smc_drv_probe(struct platform_device *pdev)
ndev->irq = ires->start;
- if (ires->flags & IRQF_TRIGGER_MASK)
+ if (irq_flags == -1 || ires->flags & IRQF_TRIGGER_MASK)
irq_flags = ires->flags & IRQF_TRIGGER_MASK;
ret = smc_request_attrib(pdev, ndev);
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
index d4c82f5fa555..a13d107a412b 100644
--- a/drivers/net/smsc911x.c
+++ b/drivers/net/smsc911x.c
@@ -789,6 +789,7 @@ static void smsc911x_phy_adjust_link(struct net_device *dev)
}
pdata->last_carrier = carrier;
}
+ udelay(10);
}
static int smsc911x_mii_probe(struct net_device *dev)
@@ -1011,7 +1012,7 @@ static int smsc911x_poll(struct napi_struct *napi, int budget)
struct net_device *dev = pdata->dev;
int npackets = 0;
- while (likely(netif_running(dev)) && (npackets < budget)) {
+ while (npackets < budget) {
unsigned int pktlength;
unsigned int pktwords;
struct sk_buff *skb;
@@ -1584,7 +1585,7 @@ static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id)
if (unlikely(intsts & inten & INT_STS_PHY_INT_)) {
smsc911x_reg_write( pdata, INT_STS , INT_STS_PHY_INT_);
temp = smsc911x_mii_read(phy_dev->bus, phy_dev->addr, MII_INTSTS);
- SMSC_TRACE("PHY interrupt, sts 0x%04X", (u16)temp);
+ SMSC_TRACE(DRV,"PHY interrupt, sts 0x%04X", (u16)temp);
smsc911x_phy_adjust_link(dev);
serviced = IRQ_HANDLED;
}
diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c
index 60abdb1081ad..97ababd189c6 100644
--- a/drivers/net/smsc9420.c
+++ b/drivers/net/smsc9420.c
@@ -252,6 +252,9 @@ static int smsc9420_ethtool_get_settings(struct net_device *dev,
{
struct smsc9420_pdata *pd = netdev_priv(dev);
+ if (!pd->phy_dev)
+ return -ENODEV;
+
cmd->maxtxpkt = 1;
cmd->maxrxpkt = 1;
return phy_ethtool_gset(pd->phy_dev, cmd);
@@ -262,6 +265,9 @@ static int smsc9420_ethtool_set_settings(struct net_device *dev,
{
struct smsc9420_pdata *pd = netdev_priv(dev);
+ if (!pd->phy_dev)
+ return -ENODEV;
+
return phy_ethtool_sset(pd->phy_dev, cmd);
}
@@ -290,6 +296,10 @@ static void smsc9420_ethtool_set_msglevel(struct net_device *netdev, u32 data)
static int smsc9420_ethtool_nway_reset(struct net_device *netdev)
{
struct smsc9420_pdata *pd = netdev_priv(netdev);
+
+ if (!pd->phy_dev)
+ return -ENODEV;
+
return phy_start_aneg(pd->phy_dev);
}
@@ -312,6 +322,10 @@ smsc9420_ethtool_getregs(struct net_device *dev, struct ethtool_regs *regs,
for (i = 0; i < 0x100; i += (sizeof(u32)))
data[j++] = smsc9420_reg_read(pd, i);
+ // cannot read phy registers if the net device is down
+ if (!phy_dev)
+ return;
+
for (i = 0; i <= 31; i++)
data[j++] = smsc9420_mii_read(phy_dev->bus, phy_dev->addr, i);
}
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 42b6c6319bc2..156f59b25191 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -943,8 +943,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
char *name;
unsigned long flags = 0;
- err = -EINVAL;
-
if (!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -958,7 +956,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
flags |= TUN_TAP_DEV;
name = "tap%d";
} else
- goto failed;
+ return -EINVAL;
if (*ifr->ifr_name)
name = ifr->ifr_name;
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index f8c6d7ea7264..9e1fc2968cf1 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -1362,7 +1362,7 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
/* reset the rts and dtr */
/* do the actual close */
serial->open_count--;
- kref_put(&serial->parent->ref, hso_serial_ref_free);
+
if (serial->open_count <= 0) {
serial->open_count = 0;
spin_lock_irq(&serial->serial_lock);
@@ -1382,6 +1382,8 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
usb_autopm_put_interface(serial->parent->interface);
mutex_unlock(&serial->parent->mutex);
+
+ kref_put(&serial->parent->ref, hso_serial_ref_free);
}
/* close the requested serial port */
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index 1f9ec29fce50..65a43c8e76b5 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -263,6 +263,7 @@ static int kaweth_control(struct kaweth_device *kaweth,
int timeout)
{
struct usb_ctrlrequest *dr;
+ int retval;
dbg("kaweth_control()");
@@ -278,18 +279,21 @@ static int kaweth_control(struct kaweth_device *kaweth,
return -ENOMEM;
}
- dr->bRequestType= requesttype;
+ dr->bRequestType = requesttype;
dr->bRequest = request;
dr->wValue = cpu_to_le16(value);
dr->wIndex = cpu_to_le16(index);
dr->wLength = cpu_to_le16(size);
- return kaweth_internal_control_msg(kaweth->dev,
- pipe,
- dr,
- data,
- size,
- timeout);
+ retval = kaweth_internal_control_msg(kaweth->dev,
+ pipe,
+ dr,
+ data,
+ size,
+ timeout);
+
+ kfree(dr);
+ return retval;
}
/****************************************************************
diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
index fcc6fa0905d1..18686839cd12 100644
--- a/drivers/net/usb/rtl8150.c
+++ b/drivers/net/usb/rtl8150.c
@@ -324,7 +324,7 @@ static int rtl8150_set_mac_address(struct net_device *netdev, void *p)
dbg("%02X:", netdev->dev_addr[i]);
dbg("%02X\n", netdev->dev_addr[i]);
/* Set the IDR registers. */
- set_registers(dev, IDR, sizeof(netdev->dev_addr), netdev->dev_addr);
+ set_registers(dev, IDR, netdev->addr_len, netdev->dev_addr);
#ifdef EEPROM_WRITE
{
u8 cr;
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index fe045896406b..df49d0daaa16 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -1232,7 +1232,7 @@ static const struct driver_info smsc95xx_info = {
.rx_fixup = smsc95xx_rx_fixup,
.tx_fixup = smsc95xx_tx_fixup,
.status = smsc95xx_status,
- .flags = FLAG_ETHER,
+ .flags = FLAG_ETHER | FLAG_SEND_ZLP,
};
static const struct usb_device_id products[] = {
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index edfd9e10ceba..d49df7352017 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -988,7 +988,7 @@ int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
* NOTE: strictly conforming cdc-ether devices should expect
* the ZLP here, but ignore the one-byte packet.
*/
- if ((length % dev->maxpacket) == 0) {
+ if (!(info->flags & FLAG_SEND_ZLP) && (length % dev->maxpacket) == 0) {
urb->transfer_buffer_length++;
if (skb_tailroom(skb)) {
skb->data[skb->len] = 0;
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 8ce5e4cee168..374f74702156 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -5249,11 +5249,7 @@ static int set_wep_key(struct airo_info *ai, u16 index, const char *key,
WepKeyRid wkr;
int rc;
- if (keylen == 0) {
- airo_print_err(ai->dev->name, "%s: key length to set was zero",
- __func__);
- return -1;
- }
+ WARN_ON(keylen == 0);
memset(&wkr, 0, sizeof(wkr));
wkr.len = cpu_to_le16(sizeof(wkr));
@@ -6399,11 +6395,7 @@ static int airo_set_encode(struct net_device *dev,
if (dwrq->length > MIN_KEY_SIZE)
key.len = MAX_KEY_SIZE;
else
- if (dwrq->length > 0)
- key.len = MIN_KEY_SIZE;
- else
- /* Disable the key */
- key.len = 0;
+ key.len = MIN_KEY_SIZE;
/* Check if the key is not marked as invalid */
if(!(dwrq->flags & IW_ENCODE_NOKEY)) {
/* Cleanup */
@@ -6584,12 +6576,22 @@ static int airo_set_encodeext(struct net_device *dev,
default:
return -EINVAL;
}
- /* Send the key to the card */
- rc = set_wep_key(local, idx, key.key, key.len, perm, 1);
- if (rc < 0) {
- airo_print_err(local->dev->name, "failed to set WEP key"
- " at index %d: %d.", idx, rc);
- return rc;
+ if (key.len == 0) {
+ rc = set_wep_tx_idx(local, idx, perm, 1);
+ if (rc < 0) {
+ airo_print_err(local->dev->name,
+ "failed to set WEP transmit index to %d: %d.",
+ idx, rc);
+ return rc;
+ }
+ } else {
+ rc = set_wep_key(local, idx, key.key, key.len, perm, 1);
+ if (rc < 0) {
+ airo_print_err(local->dev->name,
+ "failed to set WEP key at index %d: %d.",
+ idx, rc);
+ return rc;
+ }
}
}
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c
index 007eb85fc67e..1084ca69835f 100644
--- a/drivers/net/wireless/ath/ar9170/usb.c
+++ b/drivers/net/wireless/ath/ar9170/usb.c
@@ -64,6 +64,8 @@ static struct usb_device_id ar9170_usb_ids[] = {
{ USB_DEVICE(0x0cf3, 0x9170) },
/* Atheros TG121N */
{ USB_DEVICE(0x0cf3, 0x1001) },
+ /* TP-Link TL-WN821N v2 */
+ { USB_DEVICE(0x0cf3, 0x1002) },
/* Cace Airpcap NX */
{ USB_DEVICE(0xcace, 0x0300) },
/* D-Link DWA 160A */
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 6358233bac99..778baf7de231 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -1164,6 +1164,7 @@ extern void ath5k_unregister_leds(struct ath5k_softc *sc);
/* Reset Functions */
extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial);
+extern int ath5k_hw_on_hold(struct ath5k_hw *ah);
extern int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool change_channel);
/* Power management functions */
extern int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode, bool set_chip, u16 sleep_duration);
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index c41ef58393e7..605b8f67dbe0 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -145,7 +145,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
goto err_free;
/* Bring device out of sleep and reset it's units */
- ret = ath5k_hw_nic_wakeup(ah, CHANNEL_B, true);
+ ret = ath5k_hw_nic_wakeup(ah, 0, true);
if (ret)
goto err_free;
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 029c1bc7468f..753f50e8d84f 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -666,7 +666,6 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state)
ath5k_led_off(sc);
- free_irq(pdev->irq, sc);
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
@@ -694,18 +693,8 @@ ath5k_pci_resume(struct pci_dev *pdev)
*/
pci_write_config_byte(pdev, 0x41, 0);
- err = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
- if (err) {
- ATH5K_ERR(sc, "request_irq failed\n");
- goto err_no_irq;
- }
-
ath5k_led_enable(sc);
return 0;
-
-err_no_irq:
- pci_disable_device(pdev);
- return err;
}
#endif /* CONFIG_PM */
@@ -2445,27 +2434,29 @@ ath5k_stop_hw(struct ath5k_softc *sc)
ret = ath5k_stop_locked(sc);
if (ret == 0 && !test_bit(ATH_STAT_INVALID, sc->status)) {
/*
- * Set the chip in full sleep mode. Note that we are
- * careful to do this only when bringing the interface
- * completely to a stop. When the chip is in this state
- * it must be carefully woken up or references to
- * registers in the PCI clock domain may freeze the bus
- * (and system). This varies by chip and is mostly an
- * issue with newer parts that go to sleep more quickly.
- */
- if (sc->ah->ah_mac_srev >= 0x78) {
- /*
- * XXX
- * don't put newer MAC revisions > 7.8 to sleep because
- * of the above mentioned problems
- */
- ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mac version > 7.8, "
- "not putting device to sleep\n");
- } else {
- ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
- "putting device to full sleep\n");
- ath5k_hw_set_power(sc->ah, AR5K_PM_FULL_SLEEP, true, 0);
- }
+ * Don't set the card in full sleep mode!
+ *
+ * a) When the device is in this state it must be carefully
+ * woken up or references to registers in the PCI clock
+ * domain may freeze the bus (and system). This varies
+ * by chip and is mostly an issue with newer parts
+ * (madwifi sources mentioned srev >= 0x78) that go to
+ * sleep more quickly.
+ *
+ * b) On older chips full sleep results a weird behaviour
+ * during wakeup. I tested various cards with srev < 0x78
+ * and they don't wake up after module reload, a second
+ * module reload is needed to bring the card up again.
+ *
+ * Until we figure out what's going on don't enable
+ * full chip reset on any chip (this is what Legacy HAL
+ * and Sam's HAL do anyway). Instead Perform a full reset
+ * on the device (same as initial state after attach) and
+ * leave it idle (keep MAC/BB on warm reset) */
+ ret = ath5k_hw_on_hold(sc->ah);
+
+ ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
+ "putting device to sleep\n");
}
ath5k_txbuf_free(sc, sc->bbuf);
@@ -2676,7 +2667,7 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
sc->curchan = chan;
sc->curband = &sc->sbands[chan->band];
}
- ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, true);
+ ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL);
if (ret) {
ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret);
goto err;
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c
index c56b494d417a..5eded5a0d452 100644
--- a/drivers/net/wireless/ath/ath5k/eeprom.c
+++ b/drivers/net/wireless/ath/ath5k/eeprom.c
@@ -97,6 +97,7 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah)
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
int ret;
u16 val;
+ u32 cksum, offset, eep_max = AR5K_EEPROM_INFO_MAX;
/*
* Read values from EEPROM and store them in the capability structure
@@ -111,20 +112,44 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah)
if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0)
return 0;
-#ifdef notyet
/*
* Validate the checksum of the EEPROM date. There are some
* devices with invalid EEPROMs.
*/
- for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) {
+ AR5K_EEPROM_READ(AR5K_EEPROM_SIZE_UPPER, val);
+ if (val) {
+ eep_max = (val & AR5K_EEPROM_SIZE_UPPER_MASK) <<
+ AR5K_EEPROM_SIZE_ENDLOC_SHIFT;
+ AR5K_EEPROM_READ(AR5K_EEPROM_SIZE_LOWER, val);
+ eep_max = (eep_max | val) - AR5K_EEPROM_INFO_BASE;
+
+ /*
+ * Fail safe check to prevent stupid loops due
+ * to busted EEPROMs. XXX: This value is likely too
+ * big still, waiting on a better value.
+ */
+ if (eep_max > (3 * AR5K_EEPROM_INFO_MAX)) {
+ ATH5K_ERR(ah->ah_sc, "Invalid max custom EEPROM size: "
+ "%d (0x%04x) max expected: %d (0x%04x)\n",
+ eep_max, eep_max,
+ 3 * AR5K_EEPROM_INFO_MAX,
+ 3 * AR5K_EEPROM_INFO_MAX);
+ return -EIO;
+ }
+ }
+
+ for (cksum = 0, offset = 0; offset < eep_max; offset++) {
AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val);
cksum ^= val;
}
if (cksum != AR5K_EEPROM_INFO_CKSUM) {
- ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum);
+ ATH5K_ERR(ah->ah_sc, "Invalid EEPROM "
+ "checksum: 0x%04x eep_max: 0x%04x (%s)\n",
+ cksum, eep_max,
+ eep_max == AR5K_EEPROM_INFO_MAX ?
+ "default size" : "custom size");
return -EIO;
}
-#endif
AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version),
ee_ant_gain);
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.h b/drivers/net/wireless/ath/ath5k/eeprom.h
index 64be73a5edae..020bc4c75ef0 100644
--- a/drivers/net/wireless/ath/ath5k/eeprom.h
+++ b/drivers/net/wireless/ath/ath5k/eeprom.h
@@ -34,6 +34,14 @@
#define AR5K_EEPROM_RFKILL_POLARITY_S 1
#define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */
+
+/* FLASH(EEPROM) Defines for AR531X chips */
+#define AR5K_EEPROM_SIZE_LOWER 0x1b /* size info -- lower */
+#define AR5K_EEPROM_SIZE_UPPER 0x1c /* size info -- upper */
+#define AR5K_EEPROM_SIZE_UPPER_MASK 0xfff0
+#define AR5K_EEPROM_SIZE_UPPER_SHIFT 4
+#define AR5K_EEPROM_SIZE_ENDLOC_SHIFT 12
+
#define AR5K_EEPROM_CHECKSUM 0x00c0 /* EEPROM checksum */
#define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */
#define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE)
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index a876ca8d69ef..5c0e31b197a0 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -740,13 +740,22 @@ int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
AR5K_RF_XPD_GAIN, true);
} else {
- /* TODO: Set high and low gain bits */
- ath5k_hw_rfb_op(ah, rf_regs,
- ee->ee_x_gain[ee_mode],
+ u8 *pdg_curve_to_idx = ee->ee_pdc_to_idx[ee_mode];
+ if (ee->ee_pd_gains[ee_mode] > 1) {
+ ath5k_hw_rfb_op(ah, rf_regs,
+ pdg_curve_to_idx[0],
AR5K_RF_PD_GAIN_LO, true);
- ath5k_hw_rfb_op(ah, rf_regs,
- ee->ee_x_gain[ee_mode],
+ ath5k_hw_rfb_op(ah, rf_regs,
+ pdg_curve_to_idx[1],
AR5K_RF_PD_GAIN_HI, true);
+ } else {
+ ath5k_hw_rfb_op(ah, rf_regs,
+ pdg_curve_to_idx[0],
+ AR5K_RF_PD_GAIN_LO, true);
+ ath5k_hw_rfb_op(ah, rf_regs,
+ pdg_curve_to_idx[0],
+ AR5K_RF_PD_GAIN_HI, true);
+ }
/* Lower synth voltage on Rev 2 */
ath5k_hw_rfb_op(ah, rf_regs, 2,
@@ -1897,8 +1906,9 @@ ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR,
s16 min_pwrL, min_pwrR;
s16 pwr_i;
- if (WARN_ON(stepL[0] == stepL[1] || stepR[0] == stepR[1]))
- return 0;
+ /* Some vendors write the same pcdac value twice !!! */
+ if (stepL[0] == stepL[1] || stepR[0] == stepR[1])
+ return max(pwrL[0], pwrR[0]);
if (pwrL[0] == pwrL[1])
min_pwrL = pwrL[0];
@@ -2921,8 +2931,6 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower);
return -EINVAL;
}
- if (txpower == 0)
- txpower = AR5K_TUNE_DEFAULT_TXPOWER;
/* Reset TX power values */
memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower));
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index bd0a97a38d34..4980621b0239 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -258,29 +258,35 @@ int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
if (!set_chip)
goto commit;
- /* Preserve sleep duration */
data = ath5k_hw_reg_read(ah, AR5K_SLEEP_CTL);
+
+ /* If card is down we 'll get 0xffff... so we
+ * need to clean this up before we write the register
+ */
if (data & 0xffc00000)
data = 0;
else
- data = data & 0xfffcffff;
+ /* Preserve sleep duration etc */
+ data = data & ~AR5K_SLEEP_CTL_SLE;
- ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
+ ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE,
+ AR5K_SLEEP_CTL);
udelay(15);
- for (i = 50; i > 0; i--) {
+ for (i = 200; i > 0; i--) {
/* Check if the chip did wake up */
if ((ath5k_hw_reg_read(ah, AR5K_PCICFG) &
AR5K_PCICFG_SPWR_DN) == 0)
break;
/* Wait a bit and retry */
- udelay(200);
- ath5k_hw_reg_write(ah, data, AR5K_SLEEP_CTL);
+ udelay(50);
+ ath5k_hw_reg_write(ah, data | AR5K_SLEEP_CTL_SLE_WAKE,
+ AR5K_SLEEP_CTL);
}
/* Fail if the chip didn't wake up */
- if (i <= 0)
+ if (i == 0)
return -EIO;
break;
@@ -297,6 +303,64 @@ commit:
}
/*
+ * Put device on hold
+ *
+ * Put MAC and Baseband on warm reset and
+ * keep that state (don't clean sleep control
+ * register). After this MAC and Baseband are
+ * disabled and a full reset is needed to come
+ * back. This way we save as much power as possible
+ * without puting the card on full sleep.
+ */
+int ath5k_hw_on_hold(struct ath5k_hw *ah)
+{
+ struct pci_dev *pdev = ah->ah_sc->pdev;
+ u32 bus_flags;
+ int ret;
+
+ /* Make sure device is awake */
+ ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
+ if (ret) {
+ ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n");
+ return ret;
+ }
+
+ /*
+ * Put chipset on warm reset...
+ *
+ * Note: puting PCI core on warm reset on PCI-E cards
+ * results card to hang and always return 0xffff... so
+ * we ingore that flag for PCI-E cards. On PCI cards
+ * this flag gets cleared after 64 PCI clocks.
+ */
+ bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
+
+ if (ah->ah_version == AR5K_AR5210) {
+ ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
+ AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
+ AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
+ mdelay(2);
+ } else {
+ ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
+ AR5K_RESET_CTL_BASEBAND | bus_flags);
+ }
+
+ if (ret) {
+ ATH5K_ERR(ah->ah_sc, "failed to put device on warm reset\n");
+ return -EIO;
+ }
+
+ /* ...wakeup again!*/
+ ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
+ if (ret) {
+ ATH5K_ERR(ah->ah_sc, "failed to put device on hold\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+/*
* Bring up MAC + PHY Chips and program PLL
* TODO: Half/Quarter rate support
*/
@@ -319,6 +383,50 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
return ret;
}
+ /*
+ * Put chipset on warm reset...
+ *
+ * Note: puting PCI core on warm reset on PCI-E cards
+ * results card to hang and always return 0xffff... so
+ * we ingore that flag for PCI-E cards. On PCI cards
+ * this flag gets cleared after 64 PCI clocks.
+ */
+ bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
+
+ if (ah->ah_version == AR5K_AR5210) {
+ ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
+ AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
+ AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
+ mdelay(2);
+ } else {
+ ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
+ AR5K_RESET_CTL_BASEBAND | bus_flags);
+ }
+
+ if (ret) {
+ ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n");
+ return -EIO;
+ }
+
+ /* ...wakeup again!...*/
+ ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
+ if (ret) {
+ ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n");
+ return ret;
+ }
+
+ /* ...clear reset control register and pull device out of
+ * warm reset */
+ if (ath5k_hw_nic_reset(ah, 0)) {
+ ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n");
+ return -EIO;
+ }
+
+ /* On initialization skip PLL programming since we don't have
+ * a channel / mode set yet */
+ if (initial)
+ return 0;
+
if (ah->ah_version != AR5K_AR5210) {
/*
* Get channel mode flags
@@ -384,39 +492,6 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
AR5K_PHY_TURBO);
}
- /* reseting PCI on PCI-E cards results card to hang
- * and always return 0xffff... so we ingore that flag
- * for PCI-E cards */
- bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
-
- /* Reset chipset */
- if (ah->ah_version == AR5K_AR5210) {
- ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
- AR5K_RESET_CTL_MAC | AR5K_RESET_CTL_DMA |
- AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
- mdelay(2);
- } else {
- ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
- AR5K_RESET_CTL_BASEBAND | bus_flags);
- }
- if (ret) {
- ATH5K_ERR(ah->ah_sc, "failed to reset the MAC Chip\n");
- return -EIO;
- }
-
- /* ...wakeup again!*/
- ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
- if (ret) {
- ATH5K_ERR(ah->ah_sc, "failed to resume the MAC Chip\n");
- return ret;
- }
-
- /* ...final warm reset */
- if (ath5k_hw_nic_reset(ah, 0)) {
- ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n");
- return -EIO;
- }
-
if (ah->ah_version != AR5K_AR5210) {
/* ...update PLL if needed */
diff --git a/drivers/net/wireless/ath6kl/os/linux/ar6000_android.c b/drivers/net/wireless/ath6kl/os/linux/ar6000_android.c
index 1ca77e513493..9d0c3773d4d7 100644
--- a/drivers/net/wireless/ath6kl/os/linux/ar6000_android.c
+++ b/drivers/net/wireless/ath6kl/os/linux/ar6000_android.c
@@ -56,7 +56,7 @@ ATH_DEBUG_INSTANTIATE_MODULE_VAR(android,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-char fwpath[256] = "/system/wifi";
+char fwpath[256] = "/lib/firmware/ath6k/AR6102";
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) */
int buspm = WLAN_PWR_CTRL_CUT_PWR;
int wow2mode = WLAN_PWR_CTRL_CUT_PWR;
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 40448067e4cc..7797166a0cdb 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -117,6 +117,7 @@
#define B43_MMIO_TSF_2 0x636 /* core rev < 3 only */
#define B43_MMIO_TSF_3 0x638 /* core rev < 3 only */
#define B43_MMIO_RNG 0x65A
+#define B43_MMIO_IFSSLOT 0x684 /* Interframe slot time */
#define B43_MMIO_IFSCTL 0x688 /* Interframe space control */
#define B43_MMIO_IFSCTL_USE_EDCF 0x0004
#define B43_MMIO_POWERUP_DELAY 0x6A8
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 7964cc32b258..32e9513bbc0b 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -1158,8 +1158,9 @@ struct b43_dmaring *parse_cookie(struct b43_wldev *dev, u16 cookie, int *slot)
}
static int dma_tx_fragment(struct b43_dmaring *ring,
- struct sk_buff *skb)
+ struct sk_buff **in_skb)
{
+ struct sk_buff *skb = *in_skb;
const struct b43_dma_ops *ops = ring->ops;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
u8 *header;
@@ -1225,8 +1226,14 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
}
memcpy(skb_put(bounce_skb, skb->len), skb->data, skb->len);
+ memcpy(bounce_skb->cb, skb->cb, sizeof(skb->cb));
+ bounce_skb->dev = skb->dev;
+ skb_set_queue_mapping(bounce_skb, skb_get_queue_mapping(skb));
+ info = IEEE80211_SKB_CB(bounce_skb);
+
dev_kfree_skb_any(skb);
skb = bounce_skb;
+ *in_skb = bounce_skb;
meta->skb = skb;
meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {
@@ -1334,13 +1341,22 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
spin_lock_irqsave(&ring->lock, flags);
B43_WARN_ON(!ring->tx);
- /* Check if the queue was stopped in mac80211,
- * but we got called nevertheless.
- * That would be a mac80211 bug. */
- B43_WARN_ON(ring->stopped);
- if (unlikely(free_slots(ring) < TX_SLOTS_PER_FRAME)) {
- b43warn(dev->wl, "DMA queue overflow\n");
+ if (unlikely(ring->stopped)) {
+ /* We get here only because of a bug in mac80211.
+ * Because of a race, one packet may be queued after
+ * the queue is stopped, thus we got called when we shouldn't.
+ * For now, just refuse the transmit. */
+ if (b43_debug(dev, B43_DBG_DMAVERBOSE))
+ b43err(dev->wl, "Packet after queue stopped\n");
+ err = -ENOSPC;
+ goto out_unlock;
+ }
+
+ if (unlikely(WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME))) {
+ /* If we get here, we have a real error with the queue
+ * full, but queues not stopped. */
+ b43err(dev->wl, "DMA queue overflow\n");
err = -ENOSPC;
goto out_unlock;
}
@@ -1350,7 +1366,11 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
* static, so we don't need to store it per frame. */
ring->queue_prio = skb_get_queue_mapping(skb);
- err = dma_tx_fragment(ring, skb);
+ /* dma_tx_fragment might reallocate the skb, so invalidate pointers pointing
+ * into the skb data or cb now. */
+ hdr = NULL;
+ info = NULL;
+ err = dma_tx_fragment(ring, &skb);
if (unlikely(err == -ENOKEY)) {
/* Drop this packet, as we don't have the encryption key
* anymore and must not transmit it unencrypted. */
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index e71c8d9cd706..82fb9d48fa55 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -664,10 +664,17 @@ static void b43_upload_card_macaddress(struct b43_wldev *dev)
static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time)
{
/* slot_time is in usec. */
- if (dev->phy.type != B43_PHYTYPE_G)
+ /* This test used to exit for all but a G PHY. */
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
return;
- b43_write16(dev, 0x684, 510 + slot_time);
- b43_shm_write16(dev, B43_SHM_SHARED, 0x0010, slot_time);
+ b43_write16(dev, B43_MMIO_IFSSLOT, 510 + slot_time);
+ /* Shared memory location 0x0010 is the slot time and should be
+ * set to slot_time; however, this register is initially 0 and changing
+ * the value adversely affects the transmit rate for BCM4311
+ * devices. Until this behavior is unterstood, delete this step
+ *
+ * b43_shm_write16(dev, B43_SHM_SHARED, 0x0010, slot_time);
+ */
}
static void b43_short_slot_timing_enable(struct b43_wldev *dev)
diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c
index 31e55999893f..dcde92d682ce 100644
--- a/drivers/net/wireless/b43/rfkill.c
+++ b/drivers/net/wireless/b43/rfkill.c
@@ -33,7 +33,8 @@ bool b43_is_hw_radio_enabled(struct b43_wldev *dev)
& B43_MMIO_RADIO_HWENABLED_HI_MASK))
return 1;
} else {
- if (b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO)
+ if (b43_status(dev) >= B43_STAT_STARTED &&
+ b43_read16(dev, B43_MMIO_RADIO_HWENABLED_LO)
& B43_MMIO_RADIO_HWENABLED_LO_MASK)
return 1;
}
diff --git a/drivers/net/wireless/b43legacy/rfkill.c b/drivers/net/wireless/b43legacy/rfkill.c
index 8783022db11e..d579df72b783 100644
--- a/drivers/net/wireless/b43legacy/rfkill.c
+++ b/drivers/net/wireless/b43legacy/rfkill.c
@@ -34,6 +34,13 @@ bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
& B43legacy_MMIO_RADIO_HWENABLED_HI_MASK))
return 1;
} else {
+ /* To prevent CPU fault on PPC, do not read a register
+ * unless the interface is started; however, on resume
+ * for hibernation, this routine is entered early. When
+ * that happens, unconditionally return TRUE.
+ */
+ if (b43legacy_status(dev) < B43legacy_STAT_STARTED)
+ return 1;
if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO)
& B43legacy_MMIO_RADIO_HWENABLED_LO_MASK)
return 1;
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 6fe122f18c0d..eb57d1ea361f 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -875,15 +875,16 @@ void hostap_setup_dev(struct net_device *dev, local_info_t *local,
switch(type) {
case HOSTAP_INTERFACE_AP:
+ dev->tx_queue_len = 0; /* use main radio device queue */
dev->netdev_ops = &hostap_mgmt_netdev_ops;
dev->type = ARPHRD_IEEE80211;
dev->header_ops = &hostap_80211_ops;
break;
case HOSTAP_INTERFACE_MASTER:
- dev->tx_queue_len = 0; /* use main radio device queue */
dev->netdev_ops = &hostap_master_ops;
break;
default:
+ dev->tx_queue_len = 0; /* use main radio device queue */
dev->netdev_ops = &hostap_netdev_ops;
}
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index 742432388ca3..d04350b14790 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -6487,6 +6487,16 @@ static int ipw2100_resume(struct pci_dev *pci_dev)
}
#endif
+static void ipw2100_shutdown(struct pci_dev *pci_dev)
+{
+ struct ipw2100_priv *priv = pci_get_drvdata(pci_dev);
+
+ /* Take down the device; powers it off, etc. */
+ ipw2100_down(priv);
+
+ pci_disable_device(pci_dev);
+}
+
#define IPW2100_DEV_ID(x) { PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, x }
static struct pci_device_id ipw2100_pci_id_table[] __devinitdata = {
@@ -6550,6 +6560,7 @@ static struct pci_driver ipw2100_pci_driver = {
.suspend = ipw2100_suspend,
.resume = ipw2100_resume,
#endif
+ .shutdown = ipw2100_shutdown,
};
/**
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 7da52f1cc1d6..44baa60c9fd3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -46,7 +46,7 @@
#include "iwl-5000-hw.h"
/* Highest firmware API version supported */
-#define IWL1000_UCODE_API_MAX 2
+#define IWL1000_UCODE_API_MAX 3
/* Lowest firmware API version supported */
#define IWL1000_UCODE_API_MIN 1
@@ -62,12 +62,15 @@ struct iwl_cfg iwl1000_bgn_cfg = {
.ucode_api_min = IWL1000_UCODE_API_MIN,
.sku = IWL_SKU_G|IWL_SKU_N,
.ops = &iwl5000_ops,
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_A,
.valid_rx_ant = ANT_AB,
.need_pll_cfg = true,
+ .max_ll_items = OTP_MAX_LL_ITEMS_1000,
+ .shadow_ram_support = false,
+ .use_rts_for_ht = true, /* use rts/cts protection */
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 46288e724889..b73ab6c278f3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -2784,11 +2784,50 @@ static int iwl3945_load_bsm(struct iwl_priv *priv)
return 0;
}
+#define IWL3945_UCODE_GET(item) \
+static u32 iwl3945_ucode_get_##item(const struct iwl_ucode_header *ucode,\
+ u32 api_ver) \
+{ \
+ return le32_to_cpu(ucode->u.v1.item); \
+}
+
+static u32 iwl3945_ucode_get_header_size(u32 api_ver)
+{
+ return UCODE_HEADER_SIZE(1);
+}
+static u32 iwl3945_ucode_get_build(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ return 0;
+}
+static u8 *iwl3945_ucode_get_data(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ return (u8 *) ucode->u.v1.data;
+}
+
+IWL3945_UCODE_GET(inst_size);
+IWL3945_UCODE_GET(data_size);
+IWL3945_UCODE_GET(init_size);
+IWL3945_UCODE_GET(init_data_size);
+IWL3945_UCODE_GET(boot_size);
+
static struct iwl_hcmd_ops iwl3945_hcmd = {
.rxon_assoc = iwl3945_send_rxon_assoc,
.commit_rxon = iwl3945_commit_rxon,
};
+static struct iwl_ucode_ops iwl3945_ucode = {
+ .get_header_size = iwl3945_ucode_get_header_size,
+ .get_build = iwl3945_ucode_get_build,
+ .get_inst_size = iwl3945_ucode_get_inst_size,
+ .get_data_size = iwl3945_ucode_get_data_size,
+ .get_init_size = iwl3945_ucode_get_init_size,
+ .get_init_data_size = iwl3945_ucode_get_init_data_size,
+ .get_boot_size = iwl3945_ucode_get_boot_size,
+ .get_data = iwl3945_ucode_get_data,
+};
+
static struct iwl_lib_ops iwl3945_lib = {
.txq_attach_buf_to_tfd = iwl3945_hw_txq_attach_buf_to_tfd,
.txq_free_tfd = iwl3945_hw_txq_free_tfd,
@@ -2829,6 +2868,7 @@ static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
};
static struct iwl_ops iwl3945_ops = {
+ .ucode = &iwl3945_ucode,
.lib = &iwl3945_lib,
.hcmd = &iwl3945_hcmd,
.utils = &iwl3945_hcmd_utils,
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 8f3d4bc6a03f..157ee1506b3c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -2221,12 +2221,50 @@ static void iwl4965_cancel_deferred_work(struct iwl_priv *priv)
cancel_work_sync(&priv->txpower_work);
}
+#define IWL4965_UCODE_GET(item) \
+static u32 iwl4965_ucode_get_##item(const struct iwl_ucode_header *ucode,\
+ u32 api_ver) \
+{ \
+ return le32_to_cpu(ucode->u.v1.item); \
+}
+
+static u32 iwl4965_ucode_get_header_size(u32 api_ver)
+{
+ return UCODE_HEADER_SIZE(1);
+}
+static u32 iwl4965_ucode_get_build(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ return 0;
+}
+static u8 *iwl4965_ucode_get_data(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ return (u8 *) ucode->u.v1.data;
+}
+
+IWL4965_UCODE_GET(inst_size);
+IWL4965_UCODE_GET(data_size);
+IWL4965_UCODE_GET(init_size);
+IWL4965_UCODE_GET(init_data_size);
+IWL4965_UCODE_GET(boot_size);
+
static struct iwl_hcmd_ops iwl4965_hcmd = {
.rxon_assoc = iwl4965_send_rxon_assoc,
.commit_rxon = iwl_commit_rxon,
.set_rxon_chain = iwl_set_rxon_chain,
};
+static struct iwl_ucode_ops iwl4965_ucode = {
+ .get_header_size = iwl4965_ucode_get_header_size,
+ .get_build = iwl4965_ucode_get_build,
+ .get_inst_size = iwl4965_ucode_get_inst_size,
+ .get_data_size = iwl4965_ucode_get_data_size,
+ .get_init_size = iwl4965_ucode_get_init_size,
+ .get_init_data_size = iwl4965_ucode_get_init_data_size,
+ .get_boot_size = iwl4965_ucode_get_boot_size,
+ .get_data = iwl4965_ucode_get_data,
+};
static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = {
.get_hcmd_size = iwl4965_get_hcmd_size,
.build_addsta_hcmd = iwl4965_build_addsta_hcmd,
@@ -2287,6 +2325,7 @@ static struct iwl_lib_ops iwl4965_lib = {
};
static struct iwl_ops iwl4965_ops = {
+ .ucode = &iwl4965_ucode,
.lib = &iwl4965_lib,
.hcmd = &iwl4965_hcmd,
.utils = &iwl4965_hcmd_utils,
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index b3c648ce8c7b..a9ea3b5d49d5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -239,6 +239,13 @@ static void iwl5000_nic_config(struct iwl_priv *priv)
APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
+ if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_1000) {
+ /* Setting digital SVR for 1000 card to 1.32V */
+ iwl_set_bits_mask_prph(priv, APMG_DIGITAL_SVR_REG,
+ APMG_SVR_DIGITAL_VOLTAGE_1_32,
+ ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK);
+ }
+
spin_unlock_irqrestore(&priv->lock, flags);
}
@@ -1426,6 +1433,44 @@ int iwl5000_calc_rssi(struct iwl_priv *priv,
return max_rssi - agc - IWL49_RSSI_OFFSET;
}
+#define IWL5000_UCODE_GET(item) \
+static u32 iwl5000_ucode_get_##item(const struct iwl_ucode_header *ucode,\
+ u32 api_ver) \
+{ \
+ if (api_ver <= 2) \
+ return le32_to_cpu(ucode->u.v1.item); \
+ return le32_to_cpu(ucode->u.v2.item); \
+}
+
+static u32 iwl5000_ucode_get_header_size(u32 api_ver)
+{
+ if (api_ver <= 2)
+ return UCODE_HEADER_SIZE(1);
+ return UCODE_HEADER_SIZE(2);
+}
+
+static u32 iwl5000_ucode_get_build(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ if (api_ver <= 2)
+ return 0;
+ return le32_to_cpu(ucode->u.v2.build);
+}
+
+static u8 *iwl5000_ucode_get_data(const struct iwl_ucode_header *ucode,
+ u32 api_ver)
+{
+ if (api_ver <= 2)
+ return (u8 *) ucode->u.v1.data;
+ return (u8 *) ucode->u.v2.data;
+}
+
+IWL5000_UCODE_GET(inst_size);
+IWL5000_UCODE_GET(data_size);
+IWL5000_UCODE_GET(init_size);
+IWL5000_UCODE_GET(init_data_size);
+IWL5000_UCODE_GET(boot_size);
+
struct iwl_hcmd_ops iwl5000_hcmd = {
.rxon_assoc = iwl5000_send_rxon_assoc,
.commit_rxon = iwl_commit_rxon,
@@ -1441,6 +1486,17 @@ struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = {
.calc_rssi = iwl5000_calc_rssi,
};
+struct iwl_ucode_ops iwl5000_ucode = {
+ .get_header_size = iwl5000_ucode_get_header_size,
+ .get_build = iwl5000_ucode_get_build,
+ .get_inst_size = iwl5000_ucode_get_inst_size,
+ .get_data_size = iwl5000_ucode_get_data_size,
+ .get_init_size = iwl5000_ucode_get_init_size,
+ .get_init_data_size = iwl5000_ucode_get_init_data_size,
+ .get_boot_size = iwl5000_ucode_get_boot_size,
+ .get_data = iwl5000_ucode_get_data,
+};
+
struct iwl_lib_ops iwl5000_lib = {
.set_hw_params = iwl5000_hw_set_hw_params,
.txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl,
@@ -1542,12 +1598,14 @@ static struct iwl_lib_ops iwl5150_lib = {
};
struct iwl_ops iwl5000_ops = {
+ .ucode = &iwl5000_ucode,
.lib = &iwl5000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
};
static struct iwl_ops iwl5150_ops = {
+ .ucode = &iwl5000_ucode,
.lib = &iwl5150_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl5000_hcmd_utils,
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index bd438d8acf55..ee7b48ed3e8b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -46,8 +46,8 @@
#include "iwl-5000-hw.h"
/* Highest firmware API version supported */
-#define IWL6000_UCODE_API_MAX 2
-#define IWL6050_UCODE_API_MAX 2
+#define IWL6000_UCODE_API_MAX 3
+#define IWL6050_UCODE_API_MAX 3
/* Lowest firmware API version supported */
#define IWL6000_UCODE_API_MIN 1
@@ -69,6 +69,7 @@ static struct iwl_hcmd_utils_ops iwl6000_hcmd_utils = {
};
static struct iwl_ops iwl6000_ops = {
+ .ucode = &iwl5000_ucode,
.lib = &iwl5000_lib,
.hcmd = &iwl5000_hcmd,
.utils = &iwl6000_hcmd_utils,
@@ -81,13 +82,15 @@ struct iwl_cfg iwl6000_2ag_cfg = {
.ucode_api_min = IWL6000_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G,
.ops = &iwl6000_ops,
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_BC,
.valid_rx_ant = ANT_BC,
.need_pll_cfg = false,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
};
struct iwl_cfg iwl6000_2agn_cfg = {
@@ -97,13 +100,16 @@ struct iwl_cfg iwl6000_2agn_cfg = {
.ucode_api_min = IWL6000_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_AB,
.need_pll_cfg = false,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .use_rts_for_ht = true, /* use rts/cts protection */
};
struct iwl_cfg iwl6050_2agn_cfg = {
@@ -113,13 +119,16 @@ struct iwl_cfg iwl6050_2agn_cfg = {
.ucode_api_min = IWL6050_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_AB,
.valid_rx_ant = ANT_AB,
.need_pll_cfg = false,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .use_rts_for_ht = true, /* use rts/cts protection */
};
struct iwl_cfg iwl6000_3agn_cfg = {
@@ -129,13 +138,16 @@ struct iwl_cfg iwl6000_3agn_cfg = {
.ucode_api_min = IWL6000_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC,
.need_pll_cfg = false,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .use_rts_for_ht = true, /* use rts/cts protection */
};
struct iwl_cfg iwl6050_3agn_cfg = {
@@ -145,13 +157,16 @@ struct iwl_cfg iwl6050_3agn_cfg = {
.ucode_api_min = IWL6050_UCODE_API_MIN,
.sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
.ops = &iwl6000_ops,
- .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
.eeprom_ver = EEPROM_5000_EEPROM_VERSION,
.eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
.mod_params = &iwl50_mod_params,
.valid_tx_ant = ANT_ABC,
.valid_rx_ant = ANT_ABC,
.need_pll_cfg = false,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .use_rts_for_ht = true, /* use rts/cts protection */
};
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index ff20e5048a55..f5c108be541c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -415,6 +415,15 @@ static void rs_tl_turn_on_agg(struct iwl_priv *priv, u8 tid,
else if (tid == IWL_AGG_ALL_TID)
for (tid = 0; tid < TID_MAX_LOAD_COUNT; tid++)
rs_tl_turn_on_agg_for_tid(priv, lq_data, tid, sta);
+ if (priv->cfg->use_rts_for_ht) {
+ /*
+ * switch to RTS/CTS if it is the prefer protection method
+ * for HT traffic
+ */
+ IWL_DEBUG_HT(priv, "use RTS/CTS protection for HT\n");
+ priv->staging_rxon.flags &= ~RXON_FLG_SELF_CTS_EN;
+ iwlcore_commit_rxon(priv);
+ }
}
static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 355f50ea7fef..fc33b29c58ae 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -115,9 +115,6 @@ int iwl_commit_rxon(struct iwl_priv *priv)
/* always get timestamp with Rx frame */
priv->staging_rxon.flags |= RXON_FLG_TSF2HOST_MSK;
- /* allow CTS-to-self if possible. this is relevant only for
- * 5000, but will not damage 4965 */
- priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
ret = iwl_check_rxon_cmd(priv);
if (ret) {
@@ -217,6 +214,13 @@ int iwl_commit_rxon(struct iwl_priv *priv)
"Could not send WEP static key.\n");
}
+ /*
+ * allow CTS-to-self if possible for new association.
+ * this is relevant only for 5000 series and up,
+ * but will not damage 4965
+ */
+ priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN;
+
/* Apply the new configuration
* RXON assoc doesn't clear the station table in uCode,
*/
@@ -1348,7 +1352,7 @@ static void iwl_nic_start(struct iwl_priv *priv)
*/
static int iwl_read_ucode(struct iwl_priv *priv)
{
- struct iwl_ucode *ucode;
+ struct iwl_ucode_header *ucode;
int ret = -EINVAL, index;
const struct firmware *ucode_raw;
const char *name_pre = priv->cfg->fw_name_pre;
@@ -1357,7 +1361,8 @@ static int iwl_read_ucode(struct iwl_priv *priv)
char buf[25];
u8 *src;
size_t len;
- u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size;
+ u32 api_ver, build;
+ u32 inst_size, data_size, init_size, init_data_size, boot_size;
/* Ask kernel firmware_class module to get the boot firmware off disk.
* request_firmware() is synchronous, file is in memory on return. */
@@ -1387,23 +1392,26 @@ static int iwl_read_ucode(struct iwl_priv *priv)
if (ret < 0)
goto error;
- /* Make sure that we got at least our header! */
- if (ucode_raw->size < sizeof(*ucode)) {
+ /* Make sure that we got at least the v1 header! */
+ if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
IWL_ERR(priv, "File size way too small!\n");
ret = -EINVAL;
goto err_release;
}
/* Data from ucode file: header followed by uCode images */
- ucode = (void *)ucode_raw->data;
+ ucode = (struct iwl_ucode_header *)ucode_raw->data;
priv->ucode_ver = le32_to_cpu(ucode->ver);
api_ver = IWL_UCODE_API(priv->ucode_ver);
- inst_size = le32_to_cpu(ucode->inst_size);
- data_size = le32_to_cpu(ucode->data_size);
- init_size = le32_to_cpu(ucode->init_size);
- init_data_size = le32_to_cpu(ucode->init_data_size);
- boot_size = le32_to_cpu(ucode->boot_size);
+ build = priv->cfg->ops->ucode->get_build(ucode, api_ver);
+ inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
+ data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
+ init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
+ init_data_size =
+ priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
+ boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
+ src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
/* api_ver should match the api version forming part of the
* firmware filename ... but we don't check for that and only rely
@@ -1429,6 +1437,9 @@ static int iwl_read_ucode(struct iwl_priv *priv)
IWL_UCODE_API(priv->ucode_ver),
IWL_UCODE_SERIAL(priv->ucode_ver));
+ if (build)
+ IWL_DEBUG_INFO(priv, "Build %u\n", build);
+
IWL_DEBUG_INFO(priv, "f/w package hdr ucode version raw = 0x%x\n",
priv->ucode_ver);
IWL_DEBUG_INFO(priv, "f/w package hdr runtime inst size = %u\n",
@@ -1443,12 +1454,14 @@ static int iwl_read_ucode(struct iwl_priv *priv)
boot_size);
/* Verify size of file vs. image size info in file's header */
- if (ucode_raw->size < sizeof(*ucode) +
+ if (ucode_raw->size !=
+ priv->cfg->ops->ucode->get_header_size(api_ver) +
inst_size + data_size + init_size +
init_data_size + boot_size) {
- IWL_DEBUG_INFO(priv, "uCode file size %d too small\n",
- (int)ucode_raw->size);
+ IWL_DEBUG_INFO(priv,
+ "uCode file size %d does not match expected size\n",
+ (int)ucode_raw->size);
ret = -EINVAL;
goto err_release;
}
@@ -1528,42 +1541,42 @@ static int iwl_read_ucode(struct iwl_priv *priv)
/* Copy images into buffers for card's bus-master reads ... */
/* Runtime instructions (first block of data in file) */
- src = &ucode->data[0];
- len = priv->ucode_code.len;
+ len = inst_size;
IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode instr len %Zd\n", len);
memcpy(priv->ucode_code.v_addr, src, len);
+ src += len;
+
IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
/* Runtime data (2nd block)
* NOTE: Copy into backup buffer will be done in iwl_up() */
- src = &ucode->data[inst_size];
- len = priv->ucode_data.len;
+ len = data_size;
IWL_DEBUG_INFO(priv, "Copying (but not loading) uCode data len %Zd\n", len);
memcpy(priv->ucode_data.v_addr, src, len);
memcpy(priv->ucode_data_backup.v_addr, src, len);
+ src += len;
/* Initialization instructions (3rd block) */
if (init_size) {
- src = &ucode->data[inst_size + data_size];
- len = priv->ucode_init.len;
+ len = init_size;
IWL_DEBUG_INFO(priv, "Copying (but not loading) init instr len %Zd\n",
len);
memcpy(priv->ucode_init.v_addr, src, len);
+ src += len;
}
/* Initialization data (4th block) */
if (init_data_size) {
- src = &ucode->data[inst_size + data_size + init_size];
- len = priv->ucode_init_data.len;
+ len = init_data_size;
IWL_DEBUG_INFO(priv, "Copying (but not loading) init data len %Zd\n",
len);
memcpy(priv->ucode_init_data.v_addr, src, len);
+ src += len;
}
/* Bootstrap instructions (5th block) */
- src = &ucode->data[inst_size + data_size + init_size + init_data_size];
- len = priv->ucode_boot.len;
+ len = boot_size;
IWL_DEBUG_INFO(priv, "Copying (but not loading) boot instr len %Zd\n", len);
memcpy(priv->ucode_boot.v_addr, src, len);
@@ -2206,7 +2219,7 @@ static void iwl_mac_stop(struct ieee80211_hw *hw)
priv->is_open = 0;
- if (iwl_is_ready_rf(priv)) {
+ if (iwl_is_ready_rf(priv) || test_bit(STATUS_SCAN_HW, &priv->status)) {
/* stop mac, cancel any scan request and clear
* RXON_FILTER_ASSOC_MSK BIT
*/
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index dabf663e36e5..4e616eccebfb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -116,6 +116,17 @@ struct iwl_temp_ops {
void (*set_ct_kill)(struct iwl_priv *priv);
};
+struct iwl_ucode_ops {
+ u32 (*get_header_size)(u32);
+ u32 (*get_build)(const struct iwl_ucode_header *, u32);
+ u32 (*get_inst_size)(const struct iwl_ucode_header *, u32);
+ u32 (*get_data_size)(const struct iwl_ucode_header *, u32);
+ u32 (*get_init_size)(const struct iwl_ucode_header *, u32);
+ u32 (*get_init_data_size)(const struct iwl_ucode_header *, u32);
+ u32 (*get_boot_size)(const struct iwl_ucode_header *, u32);
+ u8 * (*get_data)(const struct iwl_ucode_header *, u32);
+};
+
struct iwl_lib_ops {
/* set hw dependent parameters */
int (*set_hw_params)(struct iwl_priv *priv);
@@ -171,6 +182,7 @@ struct iwl_lib_ops {
};
struct iwl_ops {
+ const struct iwl_ucode_ops *ucode;
const struct iwl_lib_ops *lib;
const struct iwl_hcmd_ops *hcmd;
const struct iwl_hcmd_utils_ops *utils;
@@ -195,6 +207,9 @@ struct iwl_mod_params {
* filename is constructed as fw_name_pre<api>.ucode.
* @ucode_api_max: Highest version of uCode API supported by driver.
* @ucode_api_min: Lowest version of uCode API supported by driver.
+ * @max_ll_items: max number of OTP blocks
+ * @shadow_ram_support: shadow support for OTP memory
+ * @use_rts_for_ht: use rts/cts protection for HT traffic
*
* We enable the driver to be backward compatible wrt API version. The
* driver specifies which APIs it supports (with @ucode_api_max being the
@@ -231,6 +246,9 @@ struct iwl_cfg {
u8 valid_rx_ant;
bool need_pll_cfg;
bool use_isr_legacy;
+ const u16 max_ll_items;
+ const bool shadow_ram_support;
+ bool use_rts_for_ht;
};
/***************************
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 650e20af20fa..e8c86079334a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -66,6 +66,7 @@ extern struct iwl_cfg iwl1000_bgn_cfg;
/* shared structures from iwl-5000.c */
extern struct iwl_mod_params iwl50_mod_params;
extern struct iwl_ops iwl5000_ops;
+extern struct iwl_ucode_ops iwl5000_ucode;
extern struct iwl_lib_ops iwl5000_lib;
extern struct iwl_hcmd_ops iwl5000_hcmd;
extern struct iwl_hcmd_utils_ops iwl5000_hcmd_utils;
@@ -525,15 +526,29 @@ struct fw_desc {
};
/* uCode file layout */
-struct iwl_ucode {
- __le32 ver; /* major/minor/API/serial */
- __le32 inst_size; /* bytes of runtime instructions */
- __le32 data_size; /* bytes of runtime data */
- __le32 init_size; /* bytes of initialization instructions */
- __le32 init_data_size; /* bytes of initialization data */
- __le32 boot_size; /* bytes of bootstrap instructions */
- u8 data[0]; /* data in same order as "size" elements */
+struct iwl_ucode_header {
+ __le32 ver; /* major/minor/API/serial */
+ union {
+ struct {
+ __le32 inst_size; /* bytes of runtime code */
+ __le32 data_size; /* bytes of runtime data */
+ __le32 init_size; /* bytes of init code */
+ __le32 init_data_size; /* bytes of init data */
+ __le32 boot_size; /* bytes of bootstrap code */
+ u8 data[0]; /* in same order as sizes */
+ } v1;
+ struct {
+ __le32 build; /* build number */
+ __le32 inst_size; /* bytes of runtime code */
+ __le32 data_size; /* bytes of runtime data */
+ __le32 init_size; /* bytes of init code */
+ __le32 init_data_size; /* bytes of init data */
+ __le32 boot_size; /* bytes of bootstrap code */
+ u8 data[0]; /* in same order as sizes */
+ } v2;
+ } u;
};
+#define UCODE_HEADER_SIZE(ver) ((ver) == 1 ? 24 : 28)
struct iwl4965_ibss_seq {
u8 mac[ETH_ALEN];
@@ -820,6 +835,18 @@ enum iwl_nvm_type {
NVM_DEVICE_TYPE_OTP,
};
+/*
+ * Two types of OTP memory access modes
+ * IWL_OTP_ACCESS_ABSOLUTE - absolute address mode,
+ * based on physical memory addressing
+ * IWL_OTP_ACCESS_RELATIVE - relative address mode,
+ * based on logical memory addressing
+ */
+enum iwl_access_mode {
+ IWL_OTP_ACCESS_ABSOLUTE,
+ IWL_OTP_ACCESS_RELATIVE,
+};
+
/* interrupt statistics */
struct isr_statistics {
u32 hw;
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
index 7d7554a2f341..eabe48a7ebfe 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c
@@ -152,6 +152,19 @@ int iwlcore_eeprom_verify_signature(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwlcore_eeprom_verify_signature);
+static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode)
+{
+ u32 otpgp;
+
+ otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
+ if (mode == IWL_OTP_ACCESS_ABSOLUTE)
+ iwl_clear_bit(priv, CSR_OTP_GP_REG,
+ CSR_OTP_GP_REG_OTP_ACCESS_MODE);
+ else
+ iwl_set_bit(priv, CSR_OTP_GP_REG,
+ CSR_OTP_GP_REG_OTP_ACCESS_MODE);
+}
+
static int iwlcore_get_nvm_type(struct iwl_priv *priv)
{
u32 otpgp;
@@ -249,6 +262,123 @@ static int iwl_init_otp_access(struct iwl_priv *priv)
return ret;
}
+static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, u16 *eeprom_data)
+{
+ int ret = 0;
+ u32 r;
+ u32 otpgp;
+
+ _iwl_write32(priv, CSR_EEPROM_REG,
+ CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
+ ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
+ CSR_EEPROM_REG_READ_VALID_MSK,
+ IWL_EEPROM_ACCESS_TIMEOUT);
+ if (ret < 0) {
+ IWL_ERR(priv, "Time out reading OTP[%d]\n", addr);
+ return ret;
+ }
+ r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
+ /* check for ECC errors: */
+ otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
+ if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
+ /* stop in this case */
+ /* set the uncorrectable OTP ECC bit for acknowledgement */
+ iwl_set_bit(priv, CSR_OTP_GP_REG,
+ CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
+ IWL_ERR(priv, "Uncorrectable OTP ECC error, abort OTP read\n");
+ return -EINVAL;
+ }
+ if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
+ /* continue in this case */
+ /* set the correctable OTP ECC bit for acknowledgement */
+ iwl_set_bit(priv, CSR_OTP_GP_REG,
+ CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
+ IWL_ERR(priv, "Correctable OTP ECC error, continue read\n");
+ }
+ *eeprom_data = le16_to_cpu((__force __le16)(r >> 16));
+ return 0;
+}
+
+/*
+ * iwl_is_otp_empty: check for empty OTP
+ */
+static bool iwl_is_otp_empty(struct iwl_priv *priv)
+{
+ u16 next_link_addr = 0, link_value;
+ bool is_empty = false;
+
+ /* locate the beginning of OTP link list */
+ if (!iwl_read_otp_word(priv, next_link_addr, &link_value)) {
+ if (!link_value) {
+ IWL_ERR(priv, "OTP is empty\n");
+ is_empty = true;
+ }
+ } else {
+ IWL_ERR(priv, "Unable to read first block of OTP list.\n");
+ is_empty = true;
+ }
+
+ return is_empty;
+}
+
+
+/*
+ * iwl_find_otp_image: find EEPROM image in OTP
+ * finding the OTP block that contains the EEPROM image.
+ * the last valid block on the link list (the block _before_ the last block)
+ * is the block we should read and used to configure the device.
+ * If all the available OTP blocks are full, the last block will be the block
+ * we should read and used to configure the device.
+ * only perform this operation if shadow RAM is disabled
+ */
+static int iwl_find_otp_image(struct iwl_priv *priv,
+ u16 *validblockaddr)
+{
+ u16 next_link_addr = 0, link_value = 0, valid_addr;
+ int usedblocks = 0;
+
+ /* set addressing mode to absolute to traverse the link list */
+ iwl_set_otp_access(priv, IWL_OTP_ACCESS_ABSOLUTE);
+
+ /* checking for empty OTP or error */
+ if (iwl_is_otp_empty(priv))
+ return -EINVAL;
+
+ /*
+ * start traverse link list
+ * until reach the max number of OTP blocks
+ * different devices have different number of OTP blocks
+ */
+ do {
+ /* save current valid block address
+ * check for more block on the link list
+ */
+ valid_addr = next_link_addr;
+ next_link_addr = link_value * sizeof(u16);
+ IWL_DEBUG_INFO(priv, "OTP blocks %d addr 0x%x\n",
+ usedblocks, next_link_addr);
+ if (iwl_read_otp_word(priv, next_link_addr, &link_value))
+ return -EINVAL;
+ if (!link_value) {
+ /*
+ * reach the end of link list, return success and
+ * set address point to the starting address
+ * of the image
+ */
+ *validblockaddr = valid_addr;
+ /* skip first 2 bytes (link list pointer) */
+ *validblockaddr += 2;
+ return 0;
+ }
+ /* more in the link list, continue */
+ usedblocks++;
+ } while (usedblocks <= priv->cfg->max_ll_items);
+
+ /* OTP has no valid blocks */
+ IWL_DEBUG_INFO(priv, "OTP has no valid blocks\n");
+ return -EINVAL;
+}
+
/**
* iwl_eeprom_init - read EEPROM contents
*
@@ -263,14 +393,13 @@ int iwl_eeprom_init(struct iwl_priv *priv)
int sz;
int ret;
u16 addr;
- u32 otpgp;
+ u16 validblockaddr = 0;
+ u16 cache_addr = 0;
priv->nvm_device_type = iwlcore_get_nvm_type(priv);
/* allocate eeprom */
- if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
- priv->cfg->eeprom_size =
- OTP_BLOCK_SIZE * OTP_LOWER_BLOCKS_TOTAL;
+ IWL_DEBUG_INFO(priv, "NVM size = %d\n", priv->cfg->eeprom_size);
sz = priv->cfg->eeprom_size;
priv->eeprom = kzalloc(sz, GFP_KERNEL);
if (!priv->eeprom) {
@@ -298,46 +427,31 @@ int iwl_eeprom_init(struct iwl_priv *priv)
if (ret) {
IWL_ERR(priv, "Failed to initialize OTP access.\n");
ret = -ENOENT;
- goto err;
+ goto done;
}
_iwl_write32(priv, CSR_EEPROM_GP,
iwl_read32(priv, CSR_EEPROM_GP) &
~CSR_EEPROM_GP_IF_OWNER_MSK);
- /* clear */
- _iwl_write32(priv, CSR_OTP_GP_REG,
- iwl_read32(priv, CSR_OTP_GP_REG) |
+
+ iwl_set_bit(priv, CSR_OTP_GP_REG,
CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK |
CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
-
- for (addr = 0; addr < sz; addr += sizeof(u16)) {
- u32 r;
-
- _iwl_write32(priv, CSR_EEPROM_REG,
- CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
-
- ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG,
- CSR_EEPROM_REG_READ_VALID_MSK,
- IWL_EEPROM_ACCESS_TIMEOUT);
- if (ret < 0) {
- IWL_ERR(priv, "Time out reading OTP[%d]\n", addr);
+ /* traversing the linked list if no shadow ram supported */
+ if (!priv->cfg->shadow_ram_support) {
+ if (iwl_find_otp_image(priv, &validblockaddr)) {
+ ret = -ENOENT;
goto done;
}
- r = _iwl_read_direct32(priv, CSR_EEPROM_REG);
- /* check for ECC errors: */
- otpgp = iwl_read32(priv, CSR_OTP_GP_REG);
- if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
- /* stop in this case */
- IWL_ERR(priv, "Uncorrectable OTP ECC error, Abort OTP read\n");
+ }
+ for (addr = validblockaddr; addr < validblockaddr + sz;
+ addr += sizeof(u16)) {
+ u16 eeprom_data;
+
+ ret = iwl_read_otp_word(priv, addr, &eeprom_data);
+ if (ret)
goto done;
- }
- if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
- /* continue in this case */
- _iwl_write32(priv, CSR_OTP_GP_REG,
- iwl_read32(priv, CSR_OTP_GP_REG) |
- CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
- IWL_ERR(priv, "Correctable OTP ECC error, continue read\n");
- }
- e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16));
+ e[cache_addr / 2] = eeprom_data;
+ cache_addr += sizeof(u16);
}
} else {
/* eeprom is an array of 16bit values */
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index 195b4ef12c27..78998854dd99 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -180,8 +180,14 @@ struct iwl_eeprom_channel {
#define EEPROM_5050_EEPROM_VERSION (0x21E)
/* OTP */
-#define OTP_LOWER_BLOCKS_TOTAL (3)
-#define OTP_BLOCK_SIZE (0x400)
+/* lower blocks contain EEPROM image and calibration data */
+#define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16)) /* 2 KB */
+/* high blocks contain PAPD data */
+#define OTP_HIGH_IMAGE_SIZE_6x00 (6 * 512 * sizeof(u16)) /* 6 KB */
+#define OTP_HIGH_IMAGE_SIZE_1000 (0x200 * sizeof(u16)) /* 1024 bytes */
+#define OTP_MAX_LL_ITEMS_1000 (3) /* OTP blocks for 1000 */
+#define OTP_MAX_LL_ITEMS_6x00 (4) /* OTP blocks for 6x00 */
+#define OTP_MAX_LL_ITEMS_6x50 (7) /* OTP blocks for 6x50 */
/* 2.4 GHz */
extern const u8 iwl_eeprom_band_1[14];
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 3b9cac3fd216..d393e8f02102 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -80,6 +80,8 @@
#define APMG_RFKILL_REG (APMG_BASE + 0x0014)
#define APMG_RTC_INT_STT_REG (APMG_BASE + 0x001c)
#define APMG_RTC_INT_MSK_REG (APMG_BASE + 0x0020)
+#define APMG_DIGITAL_SVR_REG (APMG_BASE + 0x0058)
+#define APMG_ANALOG_SVR_REG (APMG_BASE + 0x006C)
#define APMG_CLK_VAL_DMA_CLK_RQT (0x00000200)
#define APMG_CLK_VAL_BSM_CLK_RQT (0x00000800)
@@ -91,7 +93,8 @@
#define APMG_PS_CTRL_VAL_PWR_SRC_VMAIN (0x00000000)
#define APMG_PS_CTRL_VAL_PWR_SRC_MAX (0x01000000) /* 3945 only */
#define APMG_PS_CTRL_VAL_PWR_SRC_VAUX (0x02000000)
-
+#define APMG_SVR_VOLTAGE_CONFIG_BIT_MSK (0x000001E0) /* bit 8:5 */
+#define APMG_SVR_DIGITAL_VOLTAGE_1_32 (0x00000060)
#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800)
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 2b8d40b37a1c..a13f678fe44c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -239,33 +239,51 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
struct iwl_rx_queue *rxq = &priv->rxq;
struct list_head *element;
struct iwl_rx_mem_buffer *rxb;
+ struct sk_buff *skb;
unsigned long flags;
while (1) {
spin_lock_irqsave(&rxq->lock, flags);
-
if (list_empty(&rxq->rx_used)) {
spin_unlock_irqrestore(&rxq->lock, flags);
return;
}
- element = rxq->rx_used.next;
- rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
- list_del(element);
-
spin_unlock_irqrestore(&rxq->lock, flags);
+ if (rxq->free_count > RX_LOW_WATERMARK)
+ priority |= __GFP_NOWARN;
/* Alloc a new receive buffer */
- rxb->skb = alloc_skb(priv->hw_params.rx_buf_size + 256,
+ skb = alloc_skb(priv->hw_params.rx_buf_size + 256,
priority);
- if (!rxb->skb) {
- IWL_CRIT(priv, "Can not allocate SKB buffers\n");
+ if (!skb) {
+ if (net_ratelimit())
+ IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n");
+ if ((rxq->free_count <= RX_LOW_WATERMARK) &&
+ net_ratelimit())
+ IWL_CRIT(priv, "Failed to allocate SKB buffer with %s. Only %u free buffers remaining.\n",
+ priority == GFP_ATOMIC ? "GFP_ATOMIC" : "GFP_KERNEL",
+ rxq->free_count);
/* We don't reschedule replenish work here -- we will
* call the restock method and if it still needs
* more buffers it will schedule replenish */
break;
}
+ spin_lock_irqsave(&rxq->lock, flags);
+
+ if (list_empty(&rxq->rx_used)) {
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ dev_kfree_skb_any(skb);
+ return;
+ }
+ element = rxq->rx_used.next;
+ rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+ list_del(element);
+
+ spin_unlock_irqrestore(&rxq->lock, flags);
+
+ rxb->skb = skb;
/* Get physical address of RB/SKB */
rxb->real_dma_addr = pci_map_single(
priv->pci_dev,
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index e26875dbe859..474fd4982471 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -799,7 +799,8 @@ void iwl_bg_abort_scan(struct work_struct *work)
{
struct iwl_priv *priv = container_of(work, struct iwl_priv, abort_scan);
- if (!iwl_is_ready(priv))
+ if (!test_bit(STATUS_READY, &priv->status) ||
+ !test_bit(STATUS_GEO_CONFIGURED, &priv->status))
return;
mutex_lock(&priv->mutex);
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 2e89040e63be..c17b8f93ad15 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -1233,8 +1233,16 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid)
return -ENXIO;
}
+ if (priv->stations[sta_id].tid[tid].agg.state ==
+ IWL_EMPTYING_HW_QUEUE_ADDBA) {
+ IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
+ ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, ra, tid);
+ priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
+ return 0;
+ }
+
if (priv->stations[sta_id].tid[tid].agg.state != IWL_AGG_ON)
- IWL_WARN(priv, "Stopping AGG while state not IWL_AGG_ON\n");
+ IWL_WARN(priv, "Stopping AGG while state not ON or starting\n");
tid_data = &priv->stations[sta_id].tid[tid];
ssn = (tid_data->seq_number & IEEE80211_SCTL_SEQ) >> 4;
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 523843369ca2..4fac58260001 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -1196,6 +1196,7 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
struct iwl_rx_queue *rxq = &priv->rxq;
struct list_head *element;
struct iwl_rx_mem_buffer *rxb;
+ struct sk_buff *skb;
unsigned long flags;
while (1) {
@@ -1205,25 +1206,39 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
spin_unlock_irqrestore(&rxq->lock, flags);
return;
}
-
- element = rxq->rx_used.next;
- rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
- list_del(element);
spin_unlock_irqrestore(&rxq->lock, flags);
+ if (rxq->free_count > RX_LOW_WATERMARK)
+ priority |= __GFP_NOWARN;
/* Alloc a new receive buffer */
- rxb->skb =
- alloc_skb(priv->hw_params.rx_buf_size,
- priority);
- if (!rxb->skb) {
+ skb = alloc_skb(priv->hw_params.rx_buf_size, priority);
+ if (!skb) {
if (net_ratelimit())
- IWL_CRIT(priv, ": Can not allocate SKB buffers\n");
+ IWL_DEBUG_INFO(priv, "Failed to allocate SKB buffer.\n");
+ if ((rxq->free_count <= RX_LOW_WATERMARK) &&
+ net_ratelimit())
+ IWL_CRIT(priv, "Failed to allocate SKB buffer with %s. Only %u free buffers remaining.\n",
+ priority == GFP_ATOMIC ? "GFP_ATOMIC" : "GFP_KERNEL",
+ rxq->free_count);
/* We don't reschedule replenish work here -- we will
* call the restock method and if it still needs
* more buffers it will schedule replenish */
break;
}
+ spin_lock_irqsave(&rxq->lock, flags);
+ if (list_empty(&rxq->rx_used)) {
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ dev_kfree_skb_any(skb);
+ return;
+ }
+ element = rxq->rx_used.next;
+ rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+ list_del(element);
+ spin_unlock_irqrestore(&rxq->lock, flags);
+
+ rxb->skb = skb;
+
/* If radiotap head is required, reserve some headroom here.
* The physical head count is a variable rx_stats->phy_count.
* We reserve 4 bytes here. Plus these extra bytes, the
@@ -2111,7 +2126,7 @@ static void iwl3945_nic_start(struct iwl_priv *priv)
*/
static int iwl3945_read_ucode(struct iwl_priv *priv)
{
- struct iwl_ucode *ucode;
+ const struct iwl_ucode_header *ucode;
int ret = -EINVAL, index;
const struct firmware *ucode_raw;
/* firmware file name contains uCode/driver compatibility version */
@@ -2152,22 +2167,24 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
goto error;
/* Make sure that we got at least our header! */
- if (ucode_raw->size < sizeof(*ucode)) {
+ if (ucode_raw->size < priv->cfg->ops->ucode->get_header_size(1)) {
IWL_ERR(priv, "File size way too small!\n");
ret = -EINVAL;
goto err_release;
}
/* Data from ucode file: header followed by uCode images */
- ucode = (void *)ucode_raw->data;
+ ucode = (struct iwl_ucode_header *)ucode_raw->data;
priv->ucode_ver = le32_to_cpu(ucode->ver);
api_ver = IWL_UCODE_API(priv->ucode_ver);
- inst_size = le32_to_cpu(ucode->inst_size);
- data_size = le32_to_cpu(ucode->data_size);
- init_size = le32_to_cpu(ucode->init_size);
- init_data_size = le32_to_cpu(ucode->init_data_size);
- boot_size = le32_to_cpu(ucode->boot_size);
+ inst_size = priv->cfg->ops->ucode->get_inst_size(ucode, api_ver);
+ data_size = priv->cfg->ops->ucode->get_data_size(ucode, api_ver);
+ init_size = priv->cfg->ops->ucode->get_init_size(ucode, api_ver);
+ init_data_size =
+ priv->cfg->ops->ucode->get_init_data_size(ucode, api_ver);
+ boot_size = priv->cfg->ops->ucode->get_boot_size(ucode, api_ver);
+ src = priv->cfg->ops->ucode->get_data(ucode, api_ver);
/* api_ver should match the api version forming part of the
* firmware filename ... but we don't check for that and only rely
@@ -2208,12 +2225,13 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
/* Verify size of file vs. image size info in file's header */
- if (ucode_raw->size < sizeof(*ucode) +
+ if (ucode_raw->size != priv->cfg->ops->ucode->get_header_size(api_ver) +
inst_size + data_size + init_size +
init_data_size + boot_size) {
- IWL_DEBUG_INFO(priv, "uCode file size %zd too small\n",
- ucode_raw->size);
+ IWL_DEBUG_INFO(priv,
+ "uCode file size %zd does not match expected size\n",
+ ucode_raw->size);
ret = -EINVAL;
goto err_release;
}
@@ -2296,44 +2314,44 @@ static int iwl3945_read_ucode(struct iwl_priv *priv)
/* Copy images into buffers for card's bus-master reads ... */
/* Runtime instructions (first block of data in file) */
- src = &ucode->data[0];
- len = priv->ucode_code.len;
+ len = inst_size;
IWL_DEBUG_INFO(priv,
"Copying (but not loading) uCode instr len %zd\n", len);
memcpy(priv->ucode_code.v_addr, src, len);
+ src += len;
+
IWL_DEBUG_INFO(priv, "uCode instr buf vaddr = 0x%p, paddr = 0x%08x\n",
priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr);
/* Runtime data (2nd block)
* NOTE: Copy into backup buffer will be done in iwl3945_up() */
- src = &ucode->data[inst_size];
- len = priv->ucode_data.len;
+ len = data_size;
IWL_DEBUG_INFO(priv,
"Copying (but not loading) uCode data len %zd\n", len);
memcpy(priv->ucode_data.v_addr, src, len);
memcpy(priv->ucode_data_backup.v_addr, src, len);
+ src += len;
/* Initialization instructions (3rd block) */
if (init_size) {
- src = &ucode->data[inst_size + data_size];
- len = priv->ucode_init.len;
+ len = init_size;
IWL_DEBUG_INFO(priv,
"Copying (but not loading) init instr len %zd\n", len);
memcpy(priv->ucode_init.v_addr, src, len);
+ src += len;
}
/* Initialization data (4th block) */
if (init_data_size) {
- src = &ucode->data[inst_size + data_size + init_size];
- len = priv->ucode_init_data.len;
+ len = init_data_size;
IWL_DEBUG_INFO(priv,
"Copying (but not loading) init data len %zd\n", len);
memcpy(priv->ucode_init_data.v_addr, src, len);
+ src += len;
}
/* Bootstrap instructions (5th block) */
- src = &ucode->data[inst_size + data_size + init_size + init_data_size];
- len = priv->ucode_boot.len;
+ len = boot_size;
IWL_DEBUG_INFO(priv,
"Copying (but not loading) boot instr len %zd\n", len);
memcpy(priv->ucode_boot.v_addr, src, len);
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index 1844c5adf6e9..3a9a8c13b8a9 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -507,7 +507,7 @@ static int __if_usb_submit_rx_urb(struct if_usb_card *cardp,
/* Fill the receive configuration URB and initialise the Rx call back */
usb_fill_bulk_urb(cardp->rx_urb, cardp->udev,
usb_rcvbulkpipe(cardp->udev, cardp->ep_in),
- (void *) (skb->tail + (size_t) IPFIELD_ALIGN_OFFSET),
+ skb->data + IPFIELD_ALIGN_OFFSET,
MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn,
cardp);
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index 8bc1907458b1..f9c366c6ce4c 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -1951,10 +1951,8 @@ static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info,
if (priv->connect_status == LBS_CONNECTED) {
memcpy(extra, priv->curbssparams.ssid,
priv->curbssparams.ssid_len);
- extra[priv->curbssparams.ssid_len] = '\0';
} else {
memset(extra, 0, 32);
- extra[priv->curbssparams.ssid_len] = '\0';
}
/*
* If none, we may want to get the one that was set
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index 0e877a104a89..b17ec7f24b82 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -66,6 +66,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
{USB_DEVICE(0x0bf8, 0x1009)}, /* FUJITSU E-5400 USB D1700*/
{USB_DEVICE(0x0cde, 0x0006)}, /* Medion MD40900 */
{USB_DEVICE(0x0cde, 0x0008)}, /* Sagem XG703A */
+ {USB_DEVICE(0x0cde, 0x0015)}, /* Zcomax XG-705A */
{USB_DEVICE(0x0d8e, 0x3762)}, /* DLink DWL-G120 Cohiba */
{USB_DEVICE(0x124a, 0x4025)}, /* IOGear GWU513 (GW3887IK chip) */
{USB_DEVICE(0x1260, 0xee22)}, /* SMC 2862W-G version 2 */
@@ -426,12 +427,16 @@ static const char p54u_romboot_3887[] = "~~~~";
static int p54u_firmware_reset_3887(struct ieee80211_hw *dev)
{
struct p54u_priv *priv = dev->priv;
- u8 buf[4];
+ u8 *buf;
int ret;
- memcpy(&buf, p54u_romboot_3887, sizeof(buf));
+ buf = kmalloc(4, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ memcpy(buf, p54u_romboot_3887, 4);
ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
- buf, sizeof(buf));
+ buf, 4);
+ kfree(buf);
if (ret)
dev_err(&priv->udev->dev, "(p54usb) unable to jump to "
"boot ROM (%d)!\n", ret);
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 698b11b1cadb..8c67a488f83b 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -2878,7 +2878,7 @@ static int write_essid(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
static char proc_essid[33];
- int len = count;
+ unsigned int len = count;
if (len > 32)
len = 32;
diff --git a/drivers/net/wireless/rtl818x/rtl8187_leds.c b/drivers/net/wireless/rtl818x/rtl8187_leds.c
index cf9f899fe0e6..75648dd17595 100644
--- a/drivers/net/wireless/rtl818x/rtl8187_leds.c
+++ b/drivers/net/wireless/rtl818x/rtl8187_leds.c
@@ -210,10 +210,10 @@ void rtl8187_leds_exit(struct ieee80211_hw *dev)
/* turn the LED off before exiting */
queue_delayed_work(dev->workqueue, &priv->led_off, 0);
- cancel_delayed_work_sync(&priv->led_off);
- cancel_delayed_work_sync(&priv->led_on);
rtl8187_unregister_led(&priv->led_rx);
rtl8187_unregister_led(&priv->led_tx);
+ cancel_delayed_work_sync(&priv->led_off);
+ cancel_delayed_work_sync(&priv->led_on);
}
#endif /* def CONFIG_RTL8187_LED */