diff options
Diffstat (limited to 'drivers/net')
216 files changed, 5620 insertions, 1573 deletions
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index d84f6e8903a5..554a26c55188 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -49,6 +49,7 @@ static const char version[] = #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/ethtool.h> #include <asm/uaccess.h> diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 5f25889e27ef..44b28b2d7003 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -185,7 +185,7 @@ static int max_interrupt_work = 10; static int nopnp; #endif -static int el3_common_init(struct net_device *dev); +static int __devinit el3_common_init(struct net_device *dev); static void el3_common_remove(struct net_device *dev); static ushort id_read_eeprom(int index); static ushort read_eeprom(int ioaddr, int index); @@ -395,7 +395,7 @@ static struct isa_driver el3_isa_driver = { static int isa_registered; #ifdef CONFIG_PNP -static const struct pnp_device_id el3_pnp_ids[] __devinitconst = { +static struct pnp_device_id el3_pnp_ids[] = { { .id = "TCM5090" }, /* 3Com Etherlink III (TP) */ { .id = "TCM5091" }, /* 3Com Etherlink III */ { .id = "TCM5094" }, /* 3Com Etherlink III (combo) */ @@ -478,7 +478,7 @@ static int pnp_registered; #endif /* CONFIG_PNP */ #ifdef CONFIG_EISA -static const struct eisa_device_id el3_eisa_ids[] __devinitconst = { +static struct eisa_device_id el3_eisa_ids[] = { { "TCM5090" }, { "TCM5091" }, { "TCM5092" }, @@ -508,7 +508,7 @@ static int eisa_registered; #ifdef CONFIG_MCA static int el3_mca_probe(struct device *dev); -static const short el3_mca_adapter_ids[] __devinitconst = { +static short el3_mca_adapter_ids[] __initdata = { 0x627c, 0x627d, 0x62db, @@ -517,7 +517,7 @@ static const short el3_mca_adapter_ids[] __devinitconst = { 0x0000 }; -static const char *const el3_mca_adapter_names[] __devinitconst = { +static char *el3_mca_adapter_names[] __initdata = { "3Com 3c529 EtherLink III (10base2)", "3Com 3c529 EtherLink III (10baseT)", "3Com 3c529 EtherLink III (test mode)", @@ -601,7 +601,7 @@ static void el3_common_remove (struct net_device *dev) } #ifdef CONFIG_MCA -static int __devinit el3_mca_probe(struct device *device) +static int __init el3_mca_probe(struct device *device) { /* Based on Erik Nygren's (nygren@mit.edu) 3c529 patch, * heavily modified by Chris Beauregard @@ -671,7 +671,7 @@ static int __devinit el3_mca_probe(struct device *device) #endif /* CONFIG_MCA */ #ifdef CONFIG_EISA -static int __devinit el3_eisa_probe (struct device *device) +static int __init el3_eisa_probe (struct device *device) { short i; int ioaddr, irq, if_port; diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 99f43d275442..8cc22568ebd3 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -901,14 +901,14 @@ static const struct dev_pm_ops vortex_pm_ops = { #endif /* !CONFIG_PM */ #ifdef CONFIG_EISA -static const struct eisa_device_id vortex_eisa_ids[] __devinitconst = { +static struct eisa_device_id vortex_eisa_ids[] = { { "TCM5920", CH_3C592 }, { "TCM5970", CH_3C597 }, { "" } }; MODULE_DEVICE_TABLE(eisa, vortex_eisa_ids); -static int __devinit vortex_eisa_probe(struct device *device) +static int __init vortex_eisa_probe(struct device *device) { void __iomem *ioaddr; struct eisa_device *edev; diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 10c45051caea..73b10b07f9b5 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -60,6 +60,7 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/pci.h> #include <linux/dma-mapping.h> #include <linux/delay.h> diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 98517a373473..ed6355cc5261 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -100,6 +100,7 @@ #include <linux/compiler.h> #include <linux/pci.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/rtnetlink.h> diff --git a/drivers/net/8390.h b/drivers/net/8390.h index 3d9e8fb4fbee..58a12e4c78f9 100644 --- a/drivers/net/8390.h +++ b/drivers/net/8390.h @@ -9,6 +9,7 @@ #include <linux/if_ether.h> #include <linux/ioport.h> +#include <linux/irqreturn.h> #include <linux/skbuff.h> #define TX_PAGES 12 /* Two Tx slots */ diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 209fbb70619b..776a478e6296 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -31,6 +31,7 @@ obj-$(CONFIG_ATL2) += atlx/ obj-$(CONFIG_ATL1E) += atl1e/ obj-$(CONFIG_ATL1C) += atl1c/ obj-$(CONFIG_GIANFAR) += gianfar_driver.o +obj-$(CONFIG_PTP_1588_CLOCK_GIANFAR) += gianfar_ptp.o obj-$(CONFIG_TEHUTI) += tehuti.o obj-$(CONFIG_ENIC) += enic/ obj-$(CONFIG_JME) += jme.o diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c index 5181e9322119..f07b2e980fbc 100644 --- a/drivers/net/ac3200.c +++ b/drivers/net/ac3200.c @@ -32,6 +32,7 @@ static const char version[] = #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <asm/system.h> #include <asm/io.h> diff --git a/drivers/net/acenic.h b/drivers/net/acenic.h index 0681da7e8753..fd25a3b47fef 100644 --- a/drivers/net/acenic.h +++ b/drivers/net/acenic.h @@ -1,5 +1,6 @@ #ifndef _ACENIC_H_ #define _ACENIC_H_ +#include <linux/interrupt.h> /* diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 241b185e6569..db6d2da5a8f3 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -75,6 +75,7 @@ Revision History: #include <linux/compiler.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/ioport.h> #include <linux/pci.h> #include <linux/netdevice.h> @@ -1958,7 +1959,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, IPG_CONVERGE_JIFFIES; lp->ipg_data.ipg = DEFAULT_IPG; lp->ipg_data.ipg_state = CSTATE; - }; + } /* display driver and device information */ diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c index 9efbbbae47ca..25197b698dd6 100644 --- a/drivers/net/arcnet/arc-rimi.c +++ b/drivers/net/arcnet/arc-rimi.c @@ -32,6 +32,7 @@ #include <linux/netdevice.h> #include <linux/bootmem.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <asm/io.h> #include <linux/arcdevice.h> diff --git a/drivers/net/arcnet/com20020-isa.c b/drivers/net/arcnet/com20020-isa.c index 37272827ee55..45c61a2c5fbd 100644 --- a/drivers/net/arcnet/com20020-isa.c +++ b/drivers/net/arcnet/com20020-isa.c @@ -34,6 +34,7 @@ #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/bootmem.h> #include <linux/arcdevice.h> #include <linux/com20020.h> diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index 48a1dbf01e60..d427493997b6 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -34,6 +34,7 @@ #include <linux/errno.h> #include <linux/netdevice.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/pci.h> #include <linux/arcdevice.h> #include <linux/com20020.h> diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c index c9e459400ff9..7bfb91f32857 100644 --- a/drivers/net/arcnet/com20020.c +++ b/drivers/net/arcnet/com20020.c @@ -33,6 +33,7 @@ #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/arcdevice.h> #include <linux/com20020.h> diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c index eb27976dab37..487d780ebbdf 100644 --- a/drivers/net/arcnet/com90io.c +++ b/drivers/net/arcnet/com90io.c @@ -33,6 +33,7 @@ #include <linux/netdevice.h> #include <linux/bootmem.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <asm/io.h> #include <linux/arcdevice.h> diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c index f3b46f71e293..b80fbe40aa0e 100644 --- a/drivers/net/arcnet/com90xx.c +++ b/drivers/net/arcnet/com90xx.c @@ -27,6 +27,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/ioport.h> #include <linux/delay.h> #include <linux/netdevice.h> diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index e07b314ed8fd..29dc43523cec 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -19,6 +19,7 @@ #include <linux/module.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/mii.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index 5a77001b6d10..a167addd5382 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -19,6 +19,7 @@ #include <linux/etherdevice.h> #include <linux/ethtool.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/moduleparam.h> #include <linux/platform_device.h> #include <linux/delay.h> diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c index 9eb9b98a7ae3..de51e8453c13 100644 --- a/drivers/net/arm/ixp4xx_eth.c +++ b/drivers/net/arm/ixp4xx_eth.c @@ -30,9 +30,12 @@ #include <linux/etherdevice.h> #include <linux/io.h> #include <linux/kernel.h> +#include <linux/net_tstamp.h> #include <linux/phy.h> #include <linux/platform_device.h> +#include <linux/ptp_classify.h> #include <linux/slab.h> +#include <mach/ixp46x_ts.h> #include <mach/npe.h> #include <mach/qmgr.h> @@ -67,6 +70,10 @@ #define RXFREE_QUEUE(port_id) (NPE_ID(port_id) + 26) #define TXDONE_QUEUE 31 +#define PTP_SLAVE_MODE 1 +#define PTP_MASTER_MODE 2 +#define PORT2CHANNEL(p) NPE_ID(p->id) + /* TX Control Registers */ #define TX_CNTRL0_TX_EN 0x01 #define TX_CNTRL0_HALFDUPLEX 0x02 @@ -171,6 +178,8 @@ struct port { int id; /* logical port ID */ int speed, duplex; u8 firmware[4]; + int hwts_tx_en; + int hwts_rx_en; }; /* NPE message structure */ @@ -246,6 +255,172 @@ static int ports_open; static struct port *npe_port_tab[MAX_NPES]; static struct dma_pool *dma_pool; +static struct sock_filter ptp_filter[] = { + PTP_FILTER +}; + +static int ixp_ptp_match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seqid) +{ + u8 *data = skb->data; + unsigned int offset; + u16 *hi, *id; + u32 lo; + + if (sk_run_filter(skb, ptp_filter) != PTP_CLASS_V1_IPV4) + return 0; + + offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN; + + if (skb->len < offset + OFF_PTP_SEQUENCE_ID + sizeof(seqid)) + return 0; + + hi = (u16 *)(data + offset + OFF_PTP_SOURCE_UUID); + id = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID); + + memcpy(&lo, &hi[1], sizeof(lo)); + + return (uid_hi == ntohs(*hi) && + uid_lo == ntohl(lo) && + seqid == ntohs(*id)); +} + +static void ixp_rx_timestamp(struct port *port, struct sk_buff *skb) +{ + struct skb_shared_hwtstamps *shhwtstamps; + struct ixp46x_ts_regs *regs; + u64 ns; + u32 ch, hi, lo, val; + u16 uid, seq; + + if (!port->hwts_rx_en) + return; + + ch = PORT2CHANNEL(port); + + regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT; + + val = __raw_readl(®s->channel[ch].ch_event); + + if (!(val & RX_SNAPSHOT_LOCKED)) + return; + + lo = __raw_readl(®s->channel[ch].src_uuid_lo); + hi = __raw_readl(®s->channel[ch].src_uuid_hi); + + uid = hi & 0xffff; + seq = (hi >> 16) & 0xffff; + + if (!ixp_ptp_match(skb, htons(uid), htonl(lo), htons(seq))) + goto out; + + lo = __raw_readl(®s->channel[ch].rx_snap_lo); + hi = __raw_readl(®s->channel[ch].rx_snap_hi); + ns = ((u64) hi) << 32; + ns |= lo; + ns <<= TICKS_NS_SHIFT; + + shhwtstamps = skb_hwtstamps(skb); + memset(shhwtstamps, 0, sizeof(*shhwtstamps)); + shhwtstamps->hwtstamp = ns_to_ktime(ns); +out: + __raw_writel(RX_SNAPSHOT_LOCKED, ®s->channel[ch].ch_event); +} + +static void ixp_tx_timestamp(struct port *port, struct sk_buff *skb) +{ + struct skb_shared_hwtstamps shhwtstamps; + struct ixp46x_ts_regs *regs; + struct skb_shared_info *shtx; + u64 ns; + u32 ch, cnt, hi, lo, val; + + shtx = skb_shinfo(skb); + if (unlikely(shtx->tx_flags & SKBTX_HW_TSTAMP && port->hwts_tx_en)) + shtx->tx_flags |= SKBTX_IN_PROGRESS; + else + return; + + ch = PORT2CHANNEL(port); + + regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT; + + /* + * This really stinks, but we have to poll for the Tx time stamp. + * Usually, the time stamp is ready after 4 to 6 microseconds. + */ + for (cnt = 0; cnt < 100; cnt++) { + val = __raw_readl(®s->channel[ch].ch_event); + if (val & TX_SNAPSHOT_LOCKED) + break; + udelay(1); + } + if (!(val & TX_SNAPSHOT_LOCKED)) { + shtx->tx_flags &= ~SKBTX_IN_PROGRESS; + return; + } + + lo = __raw_readl(®s->channel[ch].tx_snap_lo); + hi = __raw_readl(®s->channel[ch].tx_snap_hi); + ns = ((u64) hi) << 32; + ns |= lo; + ns <<= TICKS_NS_SHIFT; + + memset(&shhwtstamps, 0, sizeof(shhwtstamps)); + shhwtstamps.hwtstamp = ns_to_ktime(ns); + skb_tstamp_tx(skb, &shhwtstamps); + + __raw_writel(TX_SNAPSHOT_LOCKED, ®s->channel[ch].ch_event); +} + +static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + struct hwtstamp_config cfg; + struct ixp46x_ts_regs *regs; + struct port *port = netdev_priv(netdev); + int ch; + + if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) + return -EFAULT; + + if (cfg.flags) /* reserved for future extensions */ + return -EINVAL; + + ch = PORT2CHANNEL(port); + regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT; + + switch (cfg.tx_type) { + case HWTSTAMP_TX_OFF: + port->hwts_tx_en = 0; + break; + case HWTSTAMP_TX_ON: + port->hwts_tx_en = 1; + break; + default: + return -ERANGE; + } + + switch (cfg.rx_filter) { + case HWTSTAMP_FILTER_NONE: + port->hwts_rx_en = 0; + break; + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: + port->hwts_rx_en = PTP_SLAVE_MODE; + __raw_writel(0, ®s->channel[ch].ch_control); + break; + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + port->hwts_rx_en = PTP_MASTER_MODE; + __raw_writel(MASTER_MODE, ®s->channel[ch].ch_control); + break; + default: + return -ERANGE; + } + + /* Clear out any old time stamps. */ + __raw_writel(TX_SNAPSHOT_LOCKED | RX_SNAPSHOT_LOCKED, + ®s->channel[ch].ch_event); + + return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; +} static int ixp4xx_mdio_cmd(struct mii_bus *bus, int phy_id, int location, int write, u16 cmd) @@ -573,6 +748,7 @@ static int eth_poll(struct napi_struct *napi, int budget) debug_pkt(dev, "eth_poll", skb->data, skb->len); + ixp_rx_timestamp(port, skb); skb->protocol = eth_type_trans(skb, dev); dev->stats.rx_packets++; dev->stats.rx_bytes += skb->len; @@ -679,14 +855,12 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4); - dev_kfree_skb(skb); #endif phys = dma_map_single(&dev->dev, mem, bytes, DMA_TO_DEVICE); if (dma_mapping_error(&dev->dev, phys)) { -#ifdef __ARMEB__ dev_kfree_skb(skb); -#else +#ifndef __ARMEB__ kfree(mem); #endif dev->stats.tx_dropped++; @@ -728,6 +902,13 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev) #if DEBUG_TX printk(KERN_DEBUG "%s: eth_xmit end\n", dev->name); #endif + + ixp_tx_timestamp(port, skb); + skb_tx_timestamp(skb); + +#ifndef __ARMEB__ + dev_kfree_skb(skb); +#endif return NETDEV_TX_OK; } @@ -783,6 +964,9 @@ static int eth_ioctl(struct net_device *dev, struct ifreq *req, int cmd) if (!netif_running(dev)) return -EINVAL; + if (cpu_is_ixp46x() && cmd == SIOCSHWTSTAMP) + return hwtstamp_ioctl(dev, req, cmd); + return phy_mii_ioctl(port->phydev, req, cmd); } @@ -1171,6 +1355,11 @@ static int __devinit eth_init_one(struct platform_device *pdev) char phy_id[MII_BUS_ID_SIZE + 3]; int err; + if (ptp_filter_init(ptp_filter, ARRAY_SIZE(ptp_filter))) { + pr_err("ixp4xx_eth: bad ptp filter\n"); + return -EINVAL; + } + if (!(dev = alloc_etherdev(sizeof(struct port)))) return -ENOMEM; diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c index a7b0caa18179..bb62b3f51837 100644 --- a/drivers/net/arm/ks8695net.c +++ b/drivers/net/arm/ks8695net.c @@ -21,6 +21,7 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/skbuff.h> #include <linux/spinlock.h> #include <linux/crc32.h> diff --git a/drivers/net/atl1c/atl1c.h b/drivers/net/atl1c/atl1c.h index 925929d764ca..dfe4370ccc90 100644 --- a/drivers/net/atl1c/atl1c.h +++ b/drivers/net/atl1c/atl1c.h @@ -24,6 +24,7 @@ #include <linux/version.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/module.h> diff --git a/drivers/net/atl1e/atl1e.h b/drivers/net/atl1e/atl1e.h index 490d3b38e0cb..9ac37e3ec8fb 100644 --- a/drivers/net/atl1e/atl1e.h +++ b/drivers/net/atl1e/atl1e.h @@ -25,6 +25,7 @@ #include <linux/version.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/module.h> diff --git a/drivers/net/b44.c b/drivers/net/b44.c index a69331e06b8d..085560e1d17a 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -25,6 +25,7 @@ #include <linux/pci.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/dma-mapping.h> #include <linux/ssb/ssb.h> #include <linux/slab.h> diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 81654ae16c63..0c12c2d4532a 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -799,12 +799,12 @@ static u32 be_encoded_q_len(int q_len) return len_encoded; } -int be_cmd_mccq_create(struct be_adapter *adapter, +int be_cmd_mccq_ext_create(struct be_adapter *adapter, struct be_queue_info *mccq, struct be_queue_info *cq) { struct be_mcc_wrb *wrb; - struct be_cmd_req_mcc_create *req; + struct be_cmd_req_mcc_ext_create *req; struct be_dma_mem *q_mem = &mccq->dma_mem; void *ctxt; int status; @@ -859,6 +859,67 @@ int be_cmd_mccq_create(struct be_adapter *adapter, return status; } +int be_cmd_mccq_org_create(struct be_adapter *adapter, + struct be_queue_info *mccq, + struct be_queue_info *cq) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_mcc_create *req; + struct be_dma_mem *q_mem = &mccq->dma_mem; + void *ctxt; + int status; + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = wrb_from_mbox(adapter); + req = embedded_payload(wrb); + ctxt = &req->context; + + be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0, + OPCODE_COMMON_MCC_CREATE); + + be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_MCC_CREATE, sizeof(*req)); + + req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); + + AMAP_SET_BITS(struct amap_mcc_context_be, valid, ctxt, 1); + AMAP_SET_BITS(struct amap_mcc_context_be, ring_size, ctxt, + be_encoded_q_len(mccq->len)); + AMAP_SET_BITS(struct amap_mcc_context_be, cq_id, ctxt, cq->id); + + be_dws_cpu_to_le(ctxt, sizeof(req->context)); + + be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); + + status = be_mbox_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb); + mccq->id = le16_to_cpu(resp->id); + mccq->created = true; + } + + mutex_unlock(&adapter->mbox_lock); + return status; +} + +int be_cmd_mccq_create(struct be_adapter *adapter, + struct be_queue_info *mccq, + struct be_queue_info *cq) +{ + int status; + + status = be_cmd_mccq_ext_create(adapter, mccq, cq); + if (status && !lancer_chip(adapter)) { + dev_warn(&adapter->pdev->dev, "Upgrade to F/W ver 2.102.235.0 " + "or newer to avoid conflicting priorities between NIC " + "and FCoE traffic"); + status = be_cmd_mccq_org_create(adapter, mccq, cq); + } + return status; +} + int be_cmd_txq_create(struct be_adapter *adapter, struct be_queue_info *txq, struct be_queue_info *cq) diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index 8148cc66cbe9..d08289e21f61 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h @@ -434,6 +434,14 @@ struct be_cmd_req_mcc_create { struct be_cmd_req_hdr hdr; u16 num_pages; u16 cq_id; + u8 context[sizeof(struct amap_mcc_context_be) / 8]; + struct phys_addr pages[8]; +} __packed; + +struct be_cmd_req_mcc_ext_create { + struct be_cmd_req_hdr hdr; + u16 num_pages; + u16 cq_id; u32 async_event_bitmap[1]; u8 context[sizeof(struct amap_mcc_context_be) / 8]; struct phys_addr pages[8]; diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index a485f7fdaf37..9ba197b09788 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -362,8 +362,8 @@ static void populate_lancer_stats(struct be_adapter *adapter) drvs->rx_priority_pause_frames = 0; drvs->pmem_fifo_overflow_drop = 0; drvs->rx_pause_frames = - make_64bit_val(pport_stats->rx_pause_frames_lo, - pport_stats->rx_pause_frames_hi); + make_64bit_val(pport_stats->rx_pause_frames_hi, + pport_stats->rx_pause_frames_lo); drvs->rx_crc_errors = make_64bit_val(pport_stats->rx_crc_errors_hi, pport_stats->rx_crc_errors_lo); drvs->rx_control_frames = @@ -3396,6 +3396,11 @@ static int __devinit be_probe(struct pci_dev *pdev, } dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num); + /* By default all priorities are enabled. + * Needed in case of no GRP5 evt support + */ + adapter->vlan_prio_bmap = 0xff; + schedule_delayed_work(&adapter->work, msecs_to_jiffies(100)); return 0; diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index a1b8c8b8010b..d2e58e2bea78 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -7,6 +7,7 @@ * May 1999, Al Viro: proper release of /proc/net/bmac entry, switched to * dynamic procfs inode. */ +#include <linux/interrupt.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/netdevice.h> diff --git a/drivers/net/bnx2x/bnx2x.h b/drivers/net/bnx2x/bnx2x.h index 668a578c49e9..480e02df86ee 100644 --- a/drivers/net/bnx2x/bnx2x.h +++ b/drivers/net/bnx2x/bnx2x.h @@ -1492,7 +1492,7 @@ void bnx2x_invalidate_e1h_mc_list(struct bnx2x *bp); void bnx2x_invalidate_uc_list(struct bnx2x *bp); void bnx2x_update_coalesce(struct bnx2x *bp); -int bnx2x_get_link_cfg_idx(struct bnx2x *bp); +int bnx2x_get_cur_phy_idx(struct bnx2x *bp); static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, int wait) diff --git a/drivers/net/bnx2x/bnx2x_cmn.c b/drivers/net/bnx2x/bnx2x_cmn.c index 289044332ed8..831c6ec98eed 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.c +++ b/drivers/net/bnx2x/bnx2x_cmn.c @@ -17,6 +17,7 @@ #include <linux/etherdevice.h> #include <linux/if_vlan.h> +#include <linux/interrupt.h> #include <linux/ip.h> #include <net/ipv6.h> #include <net/ip6_checksum.h> @@ -2803,6 +2804,55 @@ static int bnx2x_reload_if_running(struct net_device *dev) return bnx2x_nic_load(bp, LOAD_NORMAL); } +int bnx2x_get_cur_phy_idx(struct bnx2x *bp) +{ + u32 sel_phy_idx = 0; + if (bp->link_params.num_phys <= 1) + return INT_PHY; + + if (bp->link_vars.link_up) { + sel_phy_idx = EXT_PHY1; + /* In case link is SERDES, check if the EXT_PHY2 is the one */ + if ((bp->link_vars.link_status & LINK_STATUS_SERDES_LINK) && + (bp->link_params.phy[EXT_PHY2].supported & SUPPORTED_FIBRE)) + sel_phy_idx = EXT_PHY2; + } else { + + switch (bnx2x_phy_selection(&bp->link_params)) { + case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT: + case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY: + case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY: + sel_phy_idx = EXT_PHY1; + break; + case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY: + case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY: + sel_phy_idx = EXT_PHY2; + break; + } + } + + return sel_phy_idx; + +} +int bnx2x_get_link_cfg_idx(struct bnx2x *bp) +{ + u32 sel_phy_idx = bnx2x_get_cur_phy_idx(bp); + /* + * The selected actived PHY is always after swapping (in case PHY + * swapping is enabled). So when swapping is enabled, we need to reverse + * the configuration + */ + + if (bp->link_params.multi_phy_config & + PORT_HW_CFG_PHY_SWAPPED_ENABLED) { + if (sel_phy_idx == EXT_PHY1) + sel_phy_idx = EXT_PHY2; + else if (sel_phy_idx == EXT_PHY2) + sel_phy_idx = EXT_PHY1; + } + return LINK_CONFIG_IDX(sel_phy_idx); +} + /* called with rtnl_lock */ int bnx2x_change_mtu(struct net_device *dev, int new_mtu) { diff --git a/drivers/net/bnx2x/bnx2x_cmn.h b/drivers/net/bnx2x/bnx2x_cmn.h index 1a3545bd8a92..19f8638ed516 100644 --- a/drivers/net/bnx2x/bnx2x_cmn.h +++ b/drivers/net/bnx2x/bnx2x_cmn.h @@ -1063,6 +1063,8 @@ static inline void bnx2x_init_fcoe_fp(struct bnx2x *bp) } #endif +int bnx2x_get_link_cfg_idx(struct bnx2x *bp); + static inline void __storm_memset_struct(struct bnx2x *bp, u32 addr, size_t size, u32 *data) { diff --git a/drivers/net/bnx2x/bnx2x_ethtool.c b/drivers/net/bnx2x/bnx2x_ethtool.c index 727fe89ff37f..2957353f7c2c 100644 --- a/drivers/net/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/bnx2x/bnx2x_ethtool.c @@ -162,6 +162,33 @@ static const struct { }; #define BNX2X_NUM_STATS ARRAY_SIZE(bnx2x_stats_arr) +static int bnx2x_get_port_type(struct bnx2x *bp) +{ + int port_type; + u32 phy_idx = bnx2x_get_cur_phy_idx(bp); + switch (bp->link_params.phy[phy_idx].media_type) { + case ETH_PHY_SFP_FIBER: + case ETH_PHY_XFP_FIBER: + case ETH_PHY_KR: + case ETH_PHY_CX4: + port_type = PORT_FIBRE; + break; + case ETH_PHY_DA_TWINAX: + port_type = PORT_DA; + break; + case ETH_PHY_BASE_T: + port_type = PORT_TP; + break; + case ETH_PHY_NOT_PRESENT: + port_type = PORT_NONE; + break; + case ETH_PHY_UNSPECIFIED: + default: + port_type = PORT_OTHER; + break; + } + return port_type; +} static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { @@ -188,12 +215,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (IS_MF(bp)) ethtool_cmd_speed_set(cmd, bnx2x_get_mf_speed(bp)); - if (bp->port.supported[cfg_idx] & SUPPORTED_TP) - cmd->port = PORT_TP; - else if (bp->port.supported[cfg_idx] & SUPPORTED_FIBRE) - cmd->port = PORT_FIBRE; - else - BNX2X_ERR("XGXS PHY Failure detected\n"); + cmd->port = bnx2x_get_port_type(bp); cmd->phy_address = bp->mdio.prtad; cmd->transceiver = XCVR_INTERNAL; diff --git a/drivers/net/bnx2x/bnx2x_hsi.h b/drivers/net/bnx2x/bnx2x_hsi.h index cdf19fe7c7f6..b8b4b2f0b60a 100644 --- a/drivers/net/bnx2x/bnx2x_hsi.h +++ b/drivers/net/bnx2x/bnx2x_hsi.h @@ -263,7 +263,20 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */ #define PORT_HW_CFG_FAULT_MODULE_LED_GPIO2 0x00000200 #define PORT_HW_CFG_FAULT_MODULE_LED_GPIO3 0x00000300 #define PORT_HW_CFG_FAULT_MODULE_LED_DISABLED 0x00000400 - u32 Reserved01[12]; /* 0x158 */ + + u32 Reserved01[10]; /* 0x158 */ + + u32 aeu_int_mask; /* 0x190 */ + + u32 media_type; /* 0x194 */ +#define PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK 0x000000FF +#define PORT_HW_CFG_MEDIA_TYPE_PHY0_SHIFT 0 + +#define PORT_HW_CFG_MEDIA_TYPE_PHY1_MASK 0x0000FF00 +#define PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT 8 + +#define PORT_HW_CFG_MEDIA_TYPE_PHY2_MASK 0x00FF0000 +#define PORT_HW_CFG_MEDIA_TYPE_PHY2_SHIFT 16 /* for external PHY, or forced mode or during AN */ u16 xgxs_config_rx[4]; /* 0x198 */ @@ -417,6 +430,7 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */ #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM84823 0x00000b00 #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM54640 0x00000c00 #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM84833 0x00000d00 +#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8722 0x00000f00 #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_FAILURE 0x0000fd00 #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_NOT_CONN 0x0000ff00 @@ -453,6 +467,7 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */ #define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_SHIFT 24 #define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT 0x00000000 #define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482 0x01000000 +#define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT_SD 0x02000000 #define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN 0xff000000 #define PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK 0x00ff0000 @@ -473,6 +488,7 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */ #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC 0x00000a00 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823 0x00000b00 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833 0x00000d00 +#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722 0x00000f00 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE 0x0000fd00 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN 0x0000ff00 diff --git a/drivers/net/bnx2x/bnx2x_link.c b/drivers/net/bnx2x/bnx2x_link.c index 076e11f5769f..15b5bc174331 100644 --- a/drivers/net/bnx2x/bnx2x_link.c +++ b/drivers/net/bnx2x/bnx2x_link.c @@ -342,7 +342,7 @@ void bnx2x_ets_bw_limit(const struct link_params *params, const u32 cos0_bw, REG_WR(bp, PBF_REG_COS1_WEIGHT, cos1_credit_weight); } -u8 bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos) +int bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos) { /* ETS disabled configuration*/ struct bnx2x *bp = params->bp; @@ -464,6 +464,29 @@ void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars, /******************************************************************/ /* MAC/PBF section */ /******************************************************************/ +static void bnx2x_set_mdio_clk(struct bnx2x *bp, u32 chip_id, u8 port) +{ + u32 mode, emac_base; + /** + * Set clause 45 mode, slow down the MDIO clock to 2.5MHz + * (a value of 49==0x31) and make sure that the AUTO poll is off + */ + + if (CHIP_IS_E2(bp)) + emac_base = GRCBASE_EMAC0; + else + emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + mode = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); + mode &= ~(EMAC_MDIO_MODE_AUTO_POLL | + EMAC_MDIO_MODE_CLOCK_CNT); + mode |= (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT); + + mode |= (EMAC_MDIO_MODE_CLAUSE_45); + REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE, mode); + + udelay(40); +} + static void bnx2x_emac_init(struct link_params *params, struct link_vars *vars) { @@ -495,7 +518,7 @@ static void bnx2x_emac_init(struct link_params *params, } timeout--; } while (val & EMAC_MODE_RESET); - + bnx2x_set_mdio_clk(bp, params->chip_id, port); /* Set mac address */ val = ((params->mac_addr[0] << 8) | params->mac_addr[1]); @@ -508,8 +531,8 @@ static void bnx2x_emac_init(struct link_params *params, EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val); } -static u8 bnx2x_emac_enable(struct link_params *params, - struct link_vars *vars, u8 lb) +static int bnx2x_emac_enable(struct link_params *params, + struct link_vars *vars, u8 lb) { struct bnx2x *bp = params->bp; u8 port = params->port; @@ -1002,9 +1025,9 @@ void bnx2x_update_pfc(struct link_params *params, REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + params->port*4, val); } -static u8 bnx2x_bmac1_enable(struct link_params *params, - struct link_vars *vars, - u8 is_lb) +static int bnx2x_bmac1_enable(struct link_params *params, + struct link_vars *vars, + u8 is_lb) { struct bnx2x *bp = params->bp; u8 port = params->port; @@ -1066,9 +1089,9 @@ static u8 bnx2x_bmac1_enable(struct link_params *params, return 0; } -static u8 bnx2x_bmac2_enable(struct link_params *params, - struct link_vars *vars, - u8 is_lb) +static int bnx2x_bmac2_enable(struct link_params *params, + struct link_vars *vars, + u8 is_lb) { struct bnx2x *bp = params->bp; u8 port = params->port; @@ -1131,11 +1154,12 @@ static u8 bnx2x_bmac2_enable(struct link_params *params, return 0; } -static u8 bnx2x_bmac_enable(struct link_params *params, - struct link_vars *vars, - u8 is_lb) +static int bnx2x_bmac_enable(struct link_params *params, + struct link_vars *vars, + u8 is_lb) { - u8 rc, port = params->port; + int rc = 0; + u8 port = params->port; struct bnx2x *bp = params->bp; u32 val; /* reset and unreset the BigMac */ @@ -1218,8 +1242,8 @@ static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port) } } -static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl, - u32 line_speed) +static int bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl, + u32 line_speed) { struct bnx2x *bp = params->bp; u8 port = params->port; @@ -1351,149 +1375,119 @@ static u32 bnx2x_get_emac_base(struct bnx2x *bp, /******************************************************************/ /* CL45 access functions */ /******************************************************************/ -static u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy, - u8 devad, u16 reg, u16 val) +static int bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy, + u8 devad, u16 reg, u16 *ret_val) { - u32 tmp, saved_mode; - u8 i, rc = 0; - /* - * Set clause 45 mode, slow down the MDIO clock to 2.5MHz - * (a value of 49==0x31) and make sure that the AUTO poll is off - */ - - saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); - tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL | - EMAC_MDIO_MODE_CLOCK_CNT); - tmp |= (EMAC_MDIO_MODE_CLAUSE_45 | - (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT)); - REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp); - REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); - udelay(40); + u32 val; + u16 i; + int rc = 0; /* address */ - - tmp = ((phy->addr << 21) | (devad << 16) | reg | + val = ((phy->addr << 21) | (devad << 16) | reg | EMAC_MDIO_COMM_COMMAND_ADDRESS | EMAC_MDIO_COMM_START_BUSY); - REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp); + REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val); for (i = 0; i < 50; i++) { udelay(10); - tmp = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM); - if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) { + val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM); + if (!(val & EMAC_MDIO_COMM_START_BUSY)) { udelay(5); break; } } - if (tmp & EMAC_MDIO_COMM_START_BUSY) { - DP(NETIF_MSG_LINK, "write phy register failed\n"); + if (val & EMAC_MDIO_COMM_START_BUSY) { + DP(NETIF_MSG_LINK, "read phy register failed\n"); netdev_err(bp->dev, "MDC/MDIO access timeout\n"); + *ret_val = 0; rc = -EFAULT; } else { /* data */ - tmp = ((phy->addr << 21) | (devad << 16) | val | - EMAC_MDIO_COMM_COMMAND_WRITE_45 | + val = ((phy->addr << 21) | (devad << 16) | + EMAC_MDIO_COMM_COMMAND_READ_45 | EMAC_MDIO_COMM_START_BUSY); - REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp); + REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val); for (i = 0; i < 50; i++) { udelay(10); - tmp = REG_RD(bp, phy->mdio_ctrl + + val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM); - if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) { - udelay(5); + if (!(val & EMAC_MDIO_COMM_START_BUSY)) { + *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA); break; } } - if (tmp & EMAC_MDIO_COMM_START_BUSY) { - DP(NETIF_MSG_LINK, "write phy register failed\n"); + if (val & EMAC_MDIO_COMM_START_BUSY) { + DP(NETIF_MSG_LINK, "read phy register failed\n"); netdev_err(bp->dev, "MDC/MDIO access timeout\n"); + *ret_val = 0; rc = -EFAULT; } } - /* Restore the saved mode */ - REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode); - return rc; } -static u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy, - u8 devad, u16 reg, u16 *ret_val) +static int bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy, + u8 devad, u16 reg, u16 val) { - u32 val, saved_mode; - u16 i; - u8 rc = 0; - /* - * Set clause 45 mode, slow down the MDIO clock to 2.5MHz - * (a value of 49==0x31) and make sure that the AUTO poll is off - */ - - saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); - val = saved_mode & ~((EMAC_MDIO_MODE_AUTO_POLL | - EMAC_MDIO_MODE_CLOCK_CNT)); - val |= (EMAC_MDIO_MODE_CLAUSE_45 | - (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT)); - REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val); - REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); - udelay(40); + u32 tmp; + u8 i; + int rc = 0; /* address */ - val = ((phy->addr << 21) | (devad << 16) | reg | + + tmp = ((phy->addr << 21) | (devad << 16) | reg | EMAC_MDIO_COMM_COMMAND_ADDRESS | EMAC_MDIO_COMM_START_BUSY); - REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val); + REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp); for (i = 0; i < 50; i++) { udelay(10); - val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM); - if (!(val & EMAC_MDIO_COMM_START_BUSY)) { + tmp = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM); + if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) { udelay(5); break; } } - if (val & EMAC_MDIO_COMM_START_BUSY) { - DP(NETIF_MSG_LINK, "read phy register failed\n"); + if (tmp & EMAC_MDIO_COMM_START_BUSY) { + DP(NETIF_MSG_LINK, "write phy register failed\n"); netdev_err(bp->dev, "MDC/MDIO access timeout\n"); - *ret_val = 0; rc = -EFAULT; } else { /* data */ - val = ((phy->addr << 21) | (devad << 16) | - EMAC_MDIO_COMM_COMMAND_READ_45 | + tmp = ((phy->addr << 21) | (devad << 16) | val | + EMAC_MDIO_COMM_COMMAND_WRITE_45 | EMAC_MDIO_COMM_START_BUSY); - REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val); + REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp); for (i = 0; i < 50; i++) { udelay(10); - val = REG_RD(bp, phy->mdio_ctrl + + tmp = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM); - if (!(val & EMAC_MDIO_COMM_START_BUSY)) { - *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA); + if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) { + udelay(5); break; } } - if (val & EMAC_MDIO_COMM_START_BUSY) { - DP(NETIF_MSG_LINK, "read phy register failed\n"); + if (tmp & EMAC_MDIO_COMM_START_BUSY) { + DP(NETIF_MSG_LINK, "write phy register failed\n"); netdev_err(bp->dev, "MDC/MDIO access timeout\n"); - *ret_val = 0; rc = -EFAULT; } } - /* Restore the saved mode */ - REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode); return rc; } -u8 bnx2x_phy_read(struct link_params *params, u8 phy_addr, - u8 devad, u16 reg, u16 *ret_val) +int bnx2x_phy_read(struct link_params *params, u8 phy_addr, + u8 devad, u16 reg, u16 *ret_val) { u8 phy_index; /* @@ -1510,8 +1504,8 @@ u8 bnx2x_phy_read(struct link_params *params, u8 phy_addr, return -EINVAL; } -u8 bnx2x_phy_write(struct link_params *params, u8 phy_addr, - u8 devad, u16 reg, u16 val) +int bnx2x_phy_write(struct link_params *params, u8 phy_addr, + u8 devad, u16 reg, u16 val) { u8 phy_index; /* @@ -1528,8 +1522,8 @@ u8 bnx2x_phy_write(struct link_params *params, u8 phy_addr, return -EINVAL; } -static void bnx2x_set_aer_mmd_xgxs(struct link_params *params, - struct bnx2x_phy *phy) +static void bnx2x_set_aer_mmd(struct link_params *params, + struct bnx2x_phy *phy) { u32 ser_lane; u16 offset, aer_val; @@ -1538,20 +1532,17 @@ static void bnx2x_set_aer_mmd_xgxs(struct link_params *params, PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); - offset = phy->addr + ser_lane; + offset = (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ? + (phy->addr + ser_lane) : 0; + if (CHIP_IS_E2(bp)) aer_val = 0x3800 + offset - 1; else aer_val = 0x3800 + offset; + DP(NETIF_MSG_LINK, "Set AER to 0x%x\n", aer_val); CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK, MDIO_AER_BLOCK_AER_REG, aer_val); -} -static void bnx2x_set_aer_mmd_serdes(struct bnx2x *bp, - struct bnx2x_phy *phy) -{ - CL22_WR_OVER_CL45(bp, phy, - MDIO_REG_BANK_AER_BLOCK, - MDIO_AER_BLOCK_AER_REG, 0x3800); + } /******************************************************************/ @@ -1611,20 +1602,188 @@ static void bnx2x_xgxs_deassert(struct link_params *params) params->phy[INT_PHY].def_md_devad); } +static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy, + struct link_params *params, u16 *ieee_fc) +{ + struct bnx2x *bp = params->bp; + *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX; + /** + * resolve pause mode and advertisement Please refer to Table + * 28B-3 of the 802.3ab-1999 spec + */ + switch (phy->req_flow_ctrl) { + case BNX2X_FLOW_CTRL_AUTO: + if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) + *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; + else + *ieee_fc |= + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; + break; + + case BNX2X_FLOW_CTRL_TX: + *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; + break; + + case BNX2X_FLOW_CTRL_RX: + case BNX2X_FLOW_CTRL_BOTH: + *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; + break; + + case BNX2X_FLOW_CTRL_NONE: + default: + *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE; + break; + } + DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc); +} + +static void set_phy_vars(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u8 actual_phy_idx, phy_index, link_cfg_idx; + u8 phy_config_swapped = params->multi_phy_config & + PORT_HW_CFG_PHY_SWAPPED_ENABLED; + for (phy_index = INT_PHY; phy_index < params->num_phys; + phy_index++) { + link_cfg_idx = LINK_CONFIG_IDX(phy_index); + actual_phy_idx = phy_index; + if (phy_config_swapped) { + if (phy_index == EXT_PHY1) + actual_phy_idx = EXT_PHY2; + else if (phy_index == EXT_PHY2) + actual_phy_idx = EXT_PHY1; + } + params->phy[actual_phy_idx].req_flow_ctrl = + params->req_flow_ctrl[link_cfg_idx]; + + params->phy[actual_phy_idx].req_line_speed = + params->req_line_speed[link_cfg_idx]; + + params->phy[actual_phy_idx].speed_cap_mask = + params->speed_cap_mask[link_cfg_idx]; + + params->phy[actual_phy_idx].req_duplex = + params->req_duplex[link_cfg_idx]; + + if (params->req_line_speed[link_cfg_idx] == + SPEED_AUTO_NEG) + vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED; + + DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x," + " speed_cap_mask %x\n", + params->phy[actual_phy_idx].req_flow_ctrl, + params->phy[actual_phy_idx].req_line_speed, + params->phy[actual_phy_idx].speed_cap_mask); + } +} + +static void bnx2x_ext_phy_set_pause(struct link_params *params, + struct bnx2x_phy *phy, + struct link_vars *vars) +{ + u16 val; + struct bnx2x *bp = params->bp; + /* read modify write pause advertizing */ + bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, &val); + + val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH; + + /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */ + bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc); + if ((vars->ieee_fc & + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) == + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) { + val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC; + } + if ((vars->ieee_fc & + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) == + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) { + val |= MDIO_AN_REG_ADV_PAUSE_PAUSE; + } + DP(NETIF_MSG_LINK, "Ext phy AN advertize 0x%x\n", val); + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, val); +} + +static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result) +{ /* LD LP */ + switch (pause_result) { /* ASYM P ASYM P */ + case 0xb: /* 1 0 1 1 */ + vars->flow_ctrl = BNX2X_FLOW_CTRL_TX; + break; + + case 0xe: /* 1 1 1 0 */ + vars->flow_ctrl = BNX2X_FLOW_CTRL_RX; + break; + + case 0x5: /* 0 1 0 1 */ + case 0x7: /* 0 1 1 1 */ + case 0xd: /* 1 1 0 1 */ + case 0xf: /* 1 1 1 1 */ + vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH; + break; + + default: + break; + } + if (pause_result & (1<<0)) + vars->link_status |= LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE; + if (pause_result & (1<<1)) + vars->link_status |= LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE; +} + +static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u16 ld_pause; /* local */ + u16 lp_pause; /* link partner */ + u16 pause_result; + u8 ret = 0; + /* read twice */ + + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; + + if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO) + vars->flow_ctrl = phy->req_flow_ctrl; + else if (phy->req_line_speed != SPEED_AUTO_NEG) + vars->flow_ctrl = params->req_fc_auto_adv; + else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) { + ret = 1; + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, + MDIO_AN_REG_ADV_PAUSE, &ld_pause); + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, + MDIO_AN_REG_LP_AUTO_NEG, &lp_pause); + pause_result = (ld_pause & + MDIO_AN_REG_ADV_PAUSE_MASK) >> 8; + pause_result |= (lp_pause & + MDIO_AN_REG_ADV_PAUSE_MASK) >> 10; + DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n", + pause_result); + bnx2x_pause_resolve(vars, pause_result); + } + return ret; +} void bnx2x_link_status_update(struct link_params *params, struct link_vars *vars) { struct bnx2x *bp = params->bp; u8 link_10g; u8 port = params->port; + u32 sync_offset, media_types; + /* Update PHY configuration */ + set_phy_vars(params, vars); vars->link_status = REG_RD(bp, params->shmem_base + offsetof(struct shmem_region, port_mb[port].link_status)); vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP); - + vars->phy_flags = PHY_XGXS_FLAG; if (vars->link_up) { DP(NETIF_MSG_LINK, "phy link up\n"); @@ -1731,8 +1890,32 @@ void bnx2x_link_status_update(struct link_params *params, vars->mac_type = MAC_TYPE_NONE; } - DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x\n", - vars->link_status, vars->phy_link_up); + /* Sync media type */ + sync_offset = params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].media_type); + media_types = REG_RD(bp, sync_offset); + + params->phy[INT_PHY].media_type = + (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) >> + PORT_HW_CFG_MEDIA_TYPE_PHY0_SHIFT; + params->phy[EXT_PHY1].media_type = + (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY1_MASK) >> + PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT; + params->phy[EXT_PHY2].media_type = + (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY2_MASK) >> + PORT_HW_CFG_MEDIA_TYPE_PHY2_SHIFT; + DP(NETIF_MSG_LINK, "media_types = 0x%x\n", media_types); + + /* Sync AEU offset */ + sync_offset = params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].aeu_int_mask); + + vars->aeu_int_mask = REG_RD(bp, sync_offset); + + DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x int_mask 0x%x\n", + vars->link_status, vars->phy_link_up, vars->aeu_int_mask); DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n", vars->line_speed, vars->duplex, vars->flow_ctrl); } @@ -1759,9 +1942,9 @@ static void bnx2x_set_master_ln(struct link_params *params, (new_master_ln | ser_lane)); } -static u8 bnx2x_reset_unicore(struct link_params *params, - struct bnx2x_phy *phy, - u8 set_serdes) +static int bnx2x_reset_unicore(struct link_params *params, + struct bnx2x_phy *phy, + u8 set_serdes) { struct bnx2x *bp = params->bp; u16 mii_control; @@ -2059,8 +2242,8 @@ static void bnx2x_program_serdes(struct bnx2x_phy *phy, } -static void bnx2x_set_brcm_cl37_advertisment(struct bnx2x_phy *phy, - struct link_params *params) +static void bnx2x_set_brcm_cl37_advertisement(struct bnx2x_phy *phy, + struct link_params *params) { struct bnx2x *bp = params->bp; u16 val = 0; @@ -2081,44 +2264,9 @@ static void bnx2x_set_brcm_cl37_advertisment(struct bnx2x_phy *phy, MDIO_OVER_1G_UP3, 0x400); } -static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy, - struct link_params *params, u16 *ieee_fc) -{ - struct bnx2x *bp = params->bp; - *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX; - /* - * Resolve pause mode and advertisement. - * Please refer to Table 28B-3 of the 802.3ab-1999 spec - */ - - switch (phy->req_flow_ctrl) { - case BNX2X_FLOW_CTRL_AUTO: - if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) - *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; - else - *ieee_fc |= - MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; - break; - case BNX2X_FLOW_CTRL_TX: - *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; - break; - - case BNX2X_FLOW_CTRL_RX: - case BNX2X_FLOW_CTRL_BOTH: - *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; - break; - - case BNX2X_FLOW_CTRL_NONE: - default: - *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE; - break; - } - DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc); -} - -static void bnx2x_set_ieee_aneg_advertisment(struct bnx2x_phy *phy, - struct link_params *params, - u16 ieee_fc) +static void bnx2x_set_ieee_aneg_advertisement(struct bnx2x_phy *phy, + struct link_params *params, + u16 ieee_fc) { struct bnx2x *bp = params->bp; u16 val; @@ -2252,35 +2400,8 @@ static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy, * link management */ -static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result) -{ /* LD LP */ - switch (pause_result) { /* ASYM P ASYM P */ - case 0xb: /* 1 0 1 1 */ - vars->flow_ctrl = BNX2X_FLOW_CTRL_TX; - break; - - case 0xe: /* 1 1 1 0 */ - vars->flow_ctrl = BNX2X_FLOW_CTRL_RX; - break; - - case 0x5: /* 0 1 0 1 */ - case 0x7: /* 0 1 1 1 */ - case 0xd: /* 1 1 0 1 */ - case 0xf: /* 1 1 1 1 */ - vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH; - break; - - default: - break; - } - if (pause_result & (1<<0)) - vars->link_status |= LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE; - if (pause_result & (1<<1)) - vars->link_status |= LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE; -} - -static u8 bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy, - struct link_params *params) +static int bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy, + struct link_params *params) { struct bnx2x *bp = params->bp; u16 pd_10g, status2_1000x; @@ -2383,7 +2504,7 @@ static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy, struct link_params *params) { struct bnx2x *bp = params->bp; - u16 rx_status, ustat_val, cl37_fsm_recieved; + u16 rx_status, ustat_val, cl37_fsm_received; DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n"); /* Step 1: Make sure signal is detected */ CL22_RD_OVER_CL45(bp, phy, @@ -2421,15 +2542,15 @@ static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy, CL22_RD_OVER_CL45(bp, phy, MDIO_REG_BANK_REMOTE_PHY, MDIO_REMOTE_PHY_MISC_RX_STATUS, - &cl37_fsm_recieved); - if ((cl37_fsm_recieved & + &cl37_fsm_received); + if ((cl37_fsm_received & (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG | MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) != (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG | MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) { DP(NETIF_MSG_LINK, "No CL37 FSM were received. " "misc_rx_status(0x8330) = 0x%x\n", - cl37_fsm_recieved); + cl37_fsm_received); return; } /* @@ -2463,13 +2584,13 @@ static void bnx2x_xgxs_an_resolve(struct bnx2x_phy *phy, LINK_STATUS_PARALLEL_DETECTION_USED; } -static u8 bnx2x_link_settings_status(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static int bnx2x_link_settings_status(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { struct bnx2x *bp = params->bp; u16 new_line_speed, gp_status; - u8 rc = 0; + int rc = 0; /* Read gp_status */ CL22_RD_OVER_CL45(bp, phy, @@ -2642,8 +2763,8 @@ static void bnx2x_set_gmii_tx_driver(struct link_params *params) } } -static u8 bnx2x_emac_program(struct link_params *params, - struct link_vars *vars) +static int bnx2x_emac_program(struct link_params *params, + struct link_vars *vars) { struct bnx2x *bp = params->bp; u8 port = params->port; @@ -2713,9 +2834,9 @@ static void bnx2x_set_preemphasis(struct bnx2x_phy *phy, } } -static void bnx2x_init_internal_phy(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static void bnx2x_xgxs_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { struct bnx2x *bp = params->bp; u8 enable_cl73 = (SINGLE_MEDIA_DIRECT(params) || @@ -2742,11 +2863,11 @@ static void bnx2x_init_internal_phy(struct bnx2x_phy *phy, DP(NETIF_MSG_LINK, "not SGMII, AN\n"); /* AN enabled */ - bnx2x_set_brcm_cl37_advertisment(phy, params); + bnx2x_set_brcm_cl37_advertisement(phy, params); /* program duplex & pause advertisement (for aneg) */ - bnx2x_set_ieee_aneg_advertisment(phy, params, - vars->ieee_fc); + bnx2x_set_ieee_aneg_advertisement(phy, params, + vars->ieee_fc); /* enable autoneg */ bnx2x_set_autoneg(phy, params, vars, enable_cl73); @@ -2762,29 +2883,12 @@ static void bnx2x_init_internal_phy(struct bnx2x_phy *phy, } } -static u8 bnx2x_init_serdes(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) -{ - u8 rc; - vars->phy_flags |= PHY_SGMII_FLAG; - bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc); - bnx2x_set_aer_mmd_serdes(params->bp, phy); - rc = bnx2x_reset_unicore(params, phy, 1); - /* reset the SerDes and wait for reset bit return low */ - if (rc != 0) - return rc; - bnx2x_set_aer_mmd_serdes(params->bp, phy); - - return rc; -} - -static u8 bnx2x_init_xgxs(struct bnx2x_phy *phy, +static int bnx2x_prepare_xgxs(struct bnx2x_phy *phy, struct link_params *params, struct link_vars *vars) { - u8 rc; - vars->phy_flags = PHY_XGXS_FLAG; + int rc; + vars->phy_flags |= PHY_XGXS_FLAG; if ((phy->req_line_speed && ((phy->req_line_speed == SPEED_100) || (phy->req_line_speed == SPEED_10))) || @@ -2792,26 +2896,28 @@ static u8 bnx2x_init_xgxs(struct bnx2x_phy *phy, (phy->speed_cap_mask >= PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) && (phy->speed_cap_mask < - PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) - )) + PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) || + (phy->type == PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT_SD)) vars->phy_flags |= PHY_SGMII_FLAG; else vars->phy_flags &= ~PHY_SGMII_FLAG; bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc); - bnx2x_set_aer_mmd_xgxs(params, phy); - bnx2x_set_master_ln(params, phy); + bnx2x_set_aer_mmd(params, phy); + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) + bnx2x_set_master_ln(params, phy); rc = bnx2x_reset_unicore(params, phy, 0); /* reset the SerDes and wait for reset bit return low */ if (rc != 0) return rc; - bnx2x_set_aer_mmd_xgxs(params, phy); - + bnx2x_set_aer_mmd(params, phy); /* setting the masterLn_def again after the reset */ - bnx2x_set_master_ln(params, phy); - bnx2x_set_swap_lanes(params, phy); + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) { + bnx2x_set_master_ln(params, phy); + bnx2x_set_swap_lanes(params, phy); + } return rc; } @@ -2972,7 +3078,7 @@ static void bnx2x_link_int_ack(struct link_params *params, } } -static u8 bnx2x_format_ver(u32 num, u8 *str, u16 *len) +static int bnx2x_format_ver(u32 num, u8 *str, u16 *len) { u8 *str_ptr = str; u32 mask = 0xf0000000; @@ -3011,19 +3117,19 @@ static u8 bnx2x_format_ver(u32 num, u8 *str, u16 *len) } -static u8 bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len) +static int bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len) { str[0] = '\0'; (*len)--; return 0; } -u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, - u8 *version, u16 len) +int bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, + u8 *version, u16 len) { struct bnx2x *bp; u32 spirom_ver = 0; - u8 status = 0; + int status = 0; u8 *ver_p = version; u16 remain_len = len; if (version == NULL || params == NULL) @@ -3088,7 +3194,7 @@ static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy, 0x6041); msleep(200); /* set aer mmd back */ - bnx2x_set_aer_mmd_xgxs(params, phy); + bnx2x_set_aer_mmd(params, phy); /* and md_devad */ REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, md_devad); @@ -3107,12 +3213,13 @@ static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy, } } -u8 bnx2x_set_led(struct link_params *params, - struct link_vars *vars, u8 mode, u32 speed) +int bnx2x_set_led(struct link_params *params, + struct link_vars *vars, u8 mode, u32 speed) { u8 port = params->port; u16 hw_led_mode = params->hw_led_mode; - u8 rc = 0, phy_idx; + int rc = 0; + u8 phy_idx; u32 tmp; u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; struct bnx2x *bp = params->bp; @@ -3146,8 +3253,10 @@ u8 bnx2x_set_led(struct link_params *params, if (!vars->link_up) break; case LED_MODE_ON: - if (params->phy[EXT_PHY1].type == - PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727 && + if (((params->phy[EXT_PHY1].type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) || + (params->phy[EXT_PHY1].type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722)) && CHIP_IS_E2(bp) && params->num_phys == 2) { /* * This is a work-around for E2+8727 Configurations @@ -3214,8 +3323,8 @@ u8 bnx2x_set_led(struct link_params *params, * This function comes to reflect the actual link state read DIRECTLY from the * HW */ -u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars, - u8 is_serdes) +int bnx2x_test_link(struct link_params *params, struct link_vars *vars, + u8 is_serdes) { struct bnx2x *bp = params->bp; u16 gp_status = 0, phy_index = 0; @@ -3245,7 +3354,9 @@ u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars, serdes_phy_type = ((params->phy[phy_index].media_type == ETH_PHY_SFP_FIBER) || (params->phy[phy_index].media_type == - ETH_PHY_XFP_FIBER)); + ETH_PHY_XFP_FIBER) || + (params->phy[phy_index].media_type == + ETH_PHY_DA_TWINAX)); if (is_serdes != serdes_phy_type) continue; @@ -3263,10 +3374,10 @@ u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars, return -ESRCH; } -static u8 bnx2x_link_initialize(struct link_params *params, - struct link_vars *vars) +static int bnx2x_link_initialize(struct link_params *params, + struct link_vars *vars) { - u8 rc = 0; + int rc = 0; u8 phy_index, non_ext_phy; struct bnx2x *bp = params->bp; /* @@ -3283,11 +3394,7 @@ static u8 bnx2x_link_initialize(struct link_params *params, * to first. */ - if (params->phy[INT_PHY].config_init) - params->phy[INT_PHY].config_init( - ¶ms->phy[INT_PHY], - params, vars); - + bnx2x_prepare_xgxs(¶ms->phy[INT_PHY], params, vars); /* init ext phy and enable link state int */ non_ext_phy = (SINGLE_MEDIA_DIRECT(params) || (params->loopback_mode == LOOPBACK_XGXS)); @@ -3298,11 +3405,18 @@ static u8 bnx2x_link_initialize(struct link_params *params, struct bnx2x_phy *phy = ¶ms->phy[INT_PHY]; if (vars->line_speed == SPEED_AUTO_NEG) bnx2x_set_parallel_detection(phy, params); - bnx2x_init_internal_phy(phy, params, vars); + if (params->phy[INT_PHY].config_init) + params->phy[INT_PHY].config_init(phy, + params, + vars); } /* Init external phy*/ - if (!non_ext_phy) + if (non_ext_phy) { + if (params->phy[INT_PHY].supported & + SUPPORTED_FIBRE) + vars->link_status |= LINK_STATUS_SERDES_LINK; + } else { for (phy_index = EXT_PHY1; phy_index < params->num_phys; phy_index++) { /* @@ -3311,17 +3425,22 @@ static u8 bnx2x_link_initialize(struct link_params *params, * need to initialize the first phy, since they are * connected. */ + if (params->phy[phy_index].supported & + SUPPORTED_FIBRE) + vars->link_status |= LINK_STATUS_SERDES_LINK; + if (phy_index == EXT_PHY2 && (bnx2x_phy_selection(params) == PORT_HW_CFG_PHY_SELECTION_FIRST_PHY)) { - DP(NETIF_MSG_LINK, "Ignoring second phy\n"); + DP(NETIF_MSG_LINK, "Not initializing" + " second phy\n"); continue; } params->phy[phy_index].config_init( ¶ms->phy[phy_index], params, vars); } - + } /* Reset the interrupt indication after phy was initialized */ bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + params->port*4, @@ -3329,6 +3448,7 @@ static u8 bnx2x_link_initialize(struct link_params *params, NIG_STATUS_XGXS0_LINK_STATUS | NIG_STATUS_SERDES0_LINK_STATUS | NIG_MASK_MI_INT)); + bnx2x_update_mng(params, vars->link_status); return rc; } @@ -3359,8 +3479,8 @@ static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy, DP(NETIF_MSG_LINK, "reset external PHY\n"); } -static u8 bnx2x_update_link_down(struct link_params *params, - struct link_vars *vars) +static int bnx2x_update_link_down(struct link_params *params, + struct link_vars *vars) { struct bnx2x *bp = params->bp; u8 port = params->port; @@ -3372,7 +3492,12 @@ static u8 bnx2x_update_link_down(struct link_params *params, vars->mac_type = MAC_TYPE_NONE; /* update shared memory */ - vars->link_status = 0; + vars->link_status &= ~(LINK_STATUS_SPEED_AND_DUPLEX_MASK | + LINK_STATUS_LINK_UP | + LINK_STATUS_AUTO_NEGOTIATE_COMPLETE | + LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK | + LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK | + LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK); vars->line_speed = 0; bnx2x_update_mng(params, vars->link_status); @@ -3391,13 +3516,13 @@ static u8 bnx2x_update_link_down(struct link_params *params, return 0; } -static u8 bnx2x_update_link_up(struct link_params *params, - struct link_vars *vars, - u8 link_10g) +static int bnx2x_update_link_up(struct link_params *params, + struct link_vars *vars, + u8 link_10g) { struct bnx2x *bp = params->bp; u8 port = params->port; - u8 rc = 0; + int rc = 0; vars->link_status |= LINK_STATUS_LINK_UP; @@ -3451,17 +3576,18 @@ static u8 bnx2x_update_link_up(struct link_params *params, * external phy needs to be up, and at least one of the 2 * external phy link must be up. */ -u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) +int bnx2x_link_update(struct link_params *params, struct link_vars *vars) { struct bnx2x *bp = params->bp; struct link_vars phy_vars[MAX_PHYS]; u8 port = params->port; u8 link_10g, phy_index; - u8 ext_phy_link_up = 0, cur_link_up, rc = 0; + u8 ext_phy_link_up = 0, cur_link_up; + int rc = 0; u8 is_mi_int = 0; u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed; u8 active_external_phy = INT_PHY; - vars->link_status = 0; + for (phy_index = INT_PHY; phy_index < params->num_phys; phy_index++) { phy_vars[phy_index].flow_ctrl = 0; @@ -3470,6 +3596,7 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) phy_vars[phy_index].duplex = DUPLEX_FULL; phy_vars[phy_index].phy_link_up = 0; phy_vars[phy_index].link_up = 0; + phy_vars[phy_index].fault_detected = 0; } DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n", @@ -3494,7 +3621,7 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) * Step 1: * Check external link change only for external phys, and apply * priority selection between them in case the link on both phys - * is up. Note that the instead of the common vars, a temporary + * is up. Note that instead of the common vars, a temporary * vars argument is used since each phy may have different link/ * speed/duplex result */ @@ -3601,6 +3728,8 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) if (params->phy[active_external_phy].supported & SUPPORTED_FIBRE) vars->link_status |= LINK_STATUS_SERDES_LINK; + else + vars->link_status &= ~LINK_STATUS_SERDES_LINK; DP(NETIF_MSG_LINK, "Active external phy selected: %x\n", active_external_phy); } @@ -3671,18 +3800,21 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars) vars->phy_flags |= PHY_SGMII_FLAG; else vars->phy_flags &= ~PHY_SGMII_FLAG; - bnx2x_init_internal_phy(¶ms->phy[INT_PHY], - params, + + if (params->phy[INT_PHY].config_init) + params->phy[INT_PHY].config_init( + ¶ms->phy[INT_PHY], params, vars); } } /* * Link is up only if both local phy and external phy (in case of - * non-direct board) are up + * non-direct board) are up and no fault detected on active PHY. */ vars->link_up = (vars->phy_link_up && (ext_phy_link_up || - SINGLE_MEDIA_DIRECT(params))); + SINGLE_MEDIA_DIRECT(params)) && + (phy_vars[active_external_phy].fault_detected == 0)); if (vars->link_up) rc = bnx2x_update_link_up(params, vars, link_10g); @@ -3729,69 +3861,6 @@ static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp, phy->ver_addr); } -static void bnx2x_ext_phy_set_pause(struct link_params *params, - struct bnx2x_phy *phy, - struct link_vars *vars) -{ - u16 val; - struct bnx2x *bp = params->bp; - /* read modify write pause advertizing */ - bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, &val); - - val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH; - - /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */ - bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc); - if ((vars->ieee_fc & - MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) == - MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) { - val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC; - } - if ((vars->ieee_fc & - MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) == - MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) { - val |= MDIO_AN_REG_ADV_PAUSE_PAUSE; - } - DP(NETIF_MSG_LINK, "Ext phy AN advertize 0x%x\n", val); - bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, val); -} - -static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) -{ - struct bnx2x *bp = params->bp; - u16 ld_pause; /* local */ - u16 lp_pause; /* link partner */ - u16 pause_result; - u8 ret = 0; - /* read twice */ - - vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; - - if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO) - vars->flow_ctrl = phy->req_flow_ctrl; - else if (phy->req_line_speed != SPEED_AUTO_NEG) - vars->flow_ctrl = params->req_fc_auto_adv; - else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) { - ret = 1; - bnx2x_cl45_read(bp, phy, - MDIO_AN_DEVAD, - MDIO_AN_REG_ADV_PAUSE, &ld_pause); - bnx2x_cl45_read(bp, phy, - MDIO_AN_DEVAD, - MDIO_AN_REG_LP_AUTO_NEG, &lp_pause); - pause_result = (ld_pause & - MDIO_AN_REG_ADV_PAUSE_MASK) >> 8; - pause_result |= (lp_pause & - MDIO_AN_REG_ADV_PAUSE_MASK) >> 10; - DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n", - pause_result); - bnx2x_pause_resolve(vars, pause_result); - } - return ret; -} - static void bnx2x_ext_phy_10G_an_resolve(struct bnx2x *bp, struct bnx2x_phy *phy, struct link_vars *vars) @@ -3845,13 +3914,13 @@ static void bnx2x_8073_resolve_fc(struct bnx2x_phy *phy, pause_result); } } -static u8 bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp, - struct bnx2x_phy *phy, - u8 port) +static int bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp, + struct bnx2x_phy *phy, + u8 port) { u32 count = 0; u16 fw_ver1, fw_msgout; - u8 rc = 0; + int rc = 0; /* Boot port from external ROM */ /* EDC grst */ @@ -3926,7 +3995,7 @@ static u8 bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp, /******************************************************************/ /* BCM8073 PHY SECTION */ /******************************************************************/ -static u8 bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy) +static int bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy) { /* This is only required for 8073A1, version 102 only */ u16 val; @@ -3952,7 +4021,7 @@ static u8 bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy) return 1; } -static u8 bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy) +static int bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy) { u16 val, cnt, cnt1 ; @@ -4059,9 +4128,9 @@ static void bnx2x_8073_set_pause_cl37(struct link_params *params, msleep(500); } -static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static int bnx2x_8073_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { struct bnx2x *bp = params->bp; u16 val = 0, tmp1; @@ -4367,9 +4436,9 @@ static void bnx2x_8073_link_reset(struct bnx2x_phy *phy, /******************************************************************/ /* BCM8705 PHY SECTION */ /******************************************************************/ -static u8 bnx2x_8705_config_init(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static int bnx2x_8705_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { struct bnx2x *bp = params->bp; DP(NETIF_MSG_LINK, "init 8705\n"); @@ -4500,9 +4569,9 @@ static void bnx2x_sfp_set_transmitter(struct link_params *params, } } -static u8 bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy, - struct link_params *params, - u16 addr, u8 byte_cnt, u8 *o_buf) +static int bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy, + struct link_params *params, + u16 addr, u8 byte_cnt, u8 *o_buf) { struct bnx2x *bp = params->bp; u16 val = 0; @@ -4566,9 +4635,9 @@ static u8 bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy, return -EINVAL; } -static u8 bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy, - struct link_params *params, - u16 addr, u8 byte_cnt, u8 *o_buf) +static int bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy, + struct link_params *params, + u16 addr, u8 byte_cnt, u8 *o_buf) { struct bnx2x *bp = params->bp; u16 val, i; @@ -4653,27 +4722,35 @@ static u8 bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy, return -EINVAL; } -u8 bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy, - struct link_params *params, u16 addr, - u8 byte_cnt, u8 *o_buf) +int bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy, + struct link_params *params, u16 addr, + u8 byte_cnt, u8 *o_buf) { - if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) - return bnx2x_8726_read_sfp_module_eeprom(phy, params, addr, - byte_cnt, o_buf); - else if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) - return bnx2x_8727_read_sfp_module_eeprom(phy, params, addr, - byte_cnt, o_buf); - return -EINVAL; + int rc = -EINVAL; + switch (phy->type) { + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: + rc = bnx2x_8726_read_sfp_module_eeprom(phy, params, addr, + byte_cnt, o_buf); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722: + rc = bnx2x_8727_read_sfp_module_eeprom(phy, params, addr, + byte_cnt, o_buf); + break; + } + return rc; } -static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy, - struct link_params *params, - u16 *edc_mode) +static int bnx2x_get_edc_mode(struct bnx2x_phy *phy, + struct link_params *params, + u16 *edc_mode) { struct bnx2x *bp = params->bp; + u32 sync_offset = 0, phy_idx, media_types; u8 val, check_limiting_mode = 0; *edc_mode = EDC_MODE_LIMITING; + phy->media_type = ETH_PHY_UNSPECIFIED; /* First check for copper cable */ if (bnx2x_read_sfp_module_eeprom(phy, params, @@ -4688,7 +4765,7 @@ static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy, case SFP_EEPROM_CON_TYPE_VAL_COPPER: { u8 copper_module_type; - + phy->media_type = ETH_PHY_DA_TWINAX; /* * Check if its active cable (includes SFP+ module) * of passive cable @@ -4697,8 +4774,7 @@ static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy, params, SFP_EEPROM_FC_TX_TECH_ADDR, 1, - &copper_module_type) != - 0) { + &copper_module_type) != 0) { DP(NETIF_MSG_LINK, "Failed to read copper-cable-type" " from SFP+ EEPROM\n"); @@ -4723,6 +4799,7 @@ static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy, break; } case SFP_EEPROM_CON_TYPE_VAL_LC: + phy->media_type = ETH_PHY_SFP_FIBER; DP(NETIF_MSG_LINK, "Optic module detected\n"); check_limiting_mode = 1; break; @@ -4731,7 +4808,22 @@ static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy, val); return -EINVAL; } - + sync_offset = params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[params->port].media_type); + media_types = REG_RD(bp, sync_offset); + /* Update media type for non-PMF sync */ + for (phy_idx = INT_PHY; phy_idx < MAX_PHYS; phy_idx++) { + if (&(params->phy[phy_idx]) == phy) { + media_types &= ~(PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK << + (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * phy_idx)); + media_types |= ((phy->media_type & + PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) << + (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * phy_idx)); + break; + } + } + REG_WR(bp, sync_offset, media_types); if (check_limiting_mode) { u8 options[SFP_EEPROM_OPTIONS_SIZE]; if (bnx2x_read_sfp_module_eeprom(phy, @@ -4755,8 +4847,8 @@ static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy, * This function read the relevant field from the module (SFP+), and verify it * is compliant with this board */ -static u8 bnx2x_verify_sfp_module(struct bnx2x_phy *phy, - struct link_params *params) +static int bnx2x_verify_sfp_module(struct bnx2x_phy *phy, + struct link_params *params) { struct bnx2x *bp = params->bp; u32 val, cmd; @@ -4825,8 +4917,8 @@ static u8 bnx2x_verify_sfp_module(struct bnx2x_phy *phy, return -EINVAL; } -static u8 bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy, - struct link_params *params) +static int bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy, + struct link_params *params) { u8 val; @@ -4868,15 +4960,14 @@ static void bnx2x_8727_power_module(struct bnx2x *bp, */ if (phy->flags & FLAGS_NOC) return; - if (!(phy->flags & - FLAGS_NOC) && is_power_up) + if (is_power_up) val = (1<<4); else /* * Set GPIO control to OUTPUT, and set the power bit * to according to the is_power_up */ - val = ((!(is_power_up)) << 1); + val = (1<<1); bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, @@ -4884,9 +4975,9 @@ static void bnx2x_8727_power_module(struct bnx2x *bp, val); } -static u8 bnx2x_8726_set_limiting_mode(struct bnx2x *bp, - struct bnx2x_phy *phy, - u16 edc_mode) +static int bnx2x_8726_set_limiting_mode(struct bnx2x *bp, + struct bnx2x_phy *phy, + u16 edc_mode) { u16 cur_limiting_mode; @@ -4934,9 +5025,9 @@ static u8 bnx2x_8726_set_limiting_mode(struct bnx2x *bp, return 0; } -static u8 bnx2x_8727_set_limiting_mode(struct bnx2x *bp, - struct bnx2x_phy *phy, - u16 edc_mode) +static int bnx2x_8727_set_limiting_mode(struct bnx2x *bp, + struct bnx2x_phy *phy, + u16 edc_mode) { u16 phy_identifier; u16 rom_ver2_val; @@ -5021,12 +5112,44 @@ static void bnx2x_set_sfp_module_fault_led(struct link_params *params, } } -static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy, - struct link_params *params) +static void bnx2x_power_sfp_module(struct link_params *params, + struct bnx2x_phy *phy, + u8 power) +{ + struct bnx2x *bp = params->bp; + DP(NETIF_MSG_LINK, "Setting SFP+ power to %x\n", power); + + switch (phy->type) { + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722: + bnx2x_8727_power_module(params->bp, phy, power); + break; + default: + break; + } +} + +static void bnx2x_set_limiting_mode(struct link_params *params, + struct bnx2x_phy *phy, + u16 edc_mode) +{ + switch (phy->type) { + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: + bnx2x_8726_set_limiting_mode(params->bp, phy, edc_mode); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722: + bnx2x_8727_set_limiting_mode(params->bp, phy, edc_mode); + break; + } +} + +int bnx2x_sfp_module_detection(struct bnx2x_phy *phy, + struct link_params *params) { struct bnx2x *bp = params->bp; u16 edc_mode; - u8 rc = 0; + int rc = 0; u32 val = REG_RD(bp, params->shmem_base + offsetof(struct shmem_region, dev_info. @@ -5034,7 +5157,8 @@ static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy, DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n", params->port); - + /* Power up module */ + bnx2x_power_sfp_module(params, phy, 1); if (bnx2x_get_edc_mode(phy, params, &edc_mode) != 0) { DP(NETIF_MSG_LINK, "Failed to get valid module type\n"); return -EINVAL; @@ -5046,12 +5170,11 @@ static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy, bnx2x_set_sfp_module_fault_led(params, MISC_REGISTERS_GPIO_HIGH); - if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) && - ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == - PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) { - /* Shutdown SFP+ module */ + /* Check if need to power down the SFP+ module */ + if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN) { DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n"); - bnx2x_8727_power_module(bp, phy, 0); + bnx2x_power_sfp_module(params, phy, 0); return rc; } } else { @@ -5059,18 +5182,12 @@ static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy, bnx2x_set_sfp_module_fault_led(params, MISC_REGISTERS_GPIO_LOW); } - /* power up the SFP module */ - if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) - bnx2x_8727_power_module(bp, phy, 1); - /* * Check and set limiting mode / LRM mode on 8726. On 8727 it * is done automatically */ - if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) - bnx2x_8726_set_limiting_mode(bp, phy, edc_mode); - else - bnx2x_8727_set_limiting_mode(bp, phy, edc_mode); + bnx2x_set_limiting_mode(params, phy, edc_mode); + /* * Enable transmit for this module if the module is approved, or * if unapproved modules should also enable the Tx laser @@ -5100,7 +5217,7 @@ void bnx2x_handle_module_detect_int(struct link_params *params) /* Call the handling function in case module is detected */ if (gpio_val == 0) { - + bnx2x_power_sfp_module(params, phy, 1); bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3, MISC_REGISTERS_GPIO_INT_OUTPUT_CLR, port); @@ -5122,6 +5239,7 @@ void bnx2x_handle_module_detect_int(struct link_params *params) * Module was plugged out. * Disable transmit for this module */ + phy->media_type = ETH_PHY_NOT_PRESENT; if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) bnx2x_sfp_set_transmitter(params, phy, 0); @@ -5129,6 +5247,29 @@ void bnx2x_handle_module_detect_int(struct link_params *params) } /******************************************************************/ +/* Used by 8706 and 8727 */ +/******************************************************************/ +static void bnx2x_sfp_mask_fault(struct bnx2x *bp, + struct bnx2x_phy *phy, + u16 alarm_status_offset, + u16 alarm_ctrl_offset) +{ + u16 alarm_status, val; + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, alarm_status_offset, + &alarm_status); + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, alarm_status_offset, + &alarm_status); + /* Mask or enable the fault event. */ + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, alarm_ctrl_offset, &val); + if (alarm_status & (1<<0)) + val &= ~(1<<0); + else + val |= (1<<0); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, alarm_ctrl_offset, val); +} +/******************************************************************/ /* common BCM8706/BCM8726 PHY SECTION */ /******************************************************************/ static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy, @@ -5142,6 +5283,10 @@ static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy, /* Clear RX Alarm*/ bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2); + + bnx2x_sfp_mask_fault(bp, phy, MDIO_PMA_REG_TX_ALARM, + MDIO_PMA_REG_TX_ALARM_CTRL); + /* clear LASI indication*/ bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1); @@ -5173,6 +5318,17 @@ static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy, bnx2x_ext_phy_resolve_fc(phy, params, vars); vars->duplex = DUPLEX_FULL; } + + /* Capture 10G link fault. Read twice to clear stale value. */ + if (vars->line_speed == SPEED_10000) { + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, + MDIO_PMA_REG_TX_ALARM, &val1); + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, + MDIO_PMA_REG_TX_ALARM, &val1); + if (val1 & (1<<0)) + vars->fault_detected = 1; + } + return link_up; } @@ -5228,7 +5384,11 @@ static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_DIGITAL_CTRL, 0x400); bnx2x_cl45_write(bp, phy, - MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1); + MDIO_PMA_DEVAD, MDIO_PMA_REG_TX_ALARM_CTRL, + 0); + /* Arm LASI for link and Tx fault. */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 3); } else { /* Force 1Gbps using autoneg with 1G advertisement */ @@ -5281,9 +5441,9 @@ static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy, return 0; } -static u8 bnx2x_8706_read_status(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static int bnx2x_8706_read_status(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { return bnx2x_8706_8726_read_status(phy, params, vars); } @@ -5358,13 +5518,11 @@ static u8 bnx2x_8726_read_status(struct bnx2x_phy *phy, } -static u8 bnx2x_8726_config_init(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static int bnx2x_8726_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { struct bnx2x *bp = params->bp; - u32 val; - u32 swap_val, swap_override, aeu_gpio_mask, offset; DP(NETIF_MSG_LINK, "Initializing BCM8726\n"); bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15); @@ -5443,30 +5601,6 @@ static u8 bnx2x_8726_config_init(struct bnx2x_phy *phy, phy->tx_preemphasis[1]); } - /* Set GPIO3 to trigger SFP+ module insertion/removal */ - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3, - MISC_REGISTERS_GPIO_INPUT_HI_Z, params->port); - - /* The GPIO should be swapped if the swap register is set and active */ - swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); - swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); - - /* Select function upon port-swap configuration */ - if (params->port == 0) { - offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0; - aeu_gpio_mask = (swap_val && swap_override) ? - AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1 : - AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0; - } else { - offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0; - aeu_gpio_mask = (swap_val && swap_override) ? - AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 : - AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1; - } - val = REG_RD(bp, offset); - /* add GPIO3 to group */ - val |= aeu_gpio_mask; - REG_WR(bp, offset, val); return 0; } @@ -5548,9 +5682,9 @@ static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy, MISC_REGISTERS_GPIO_OUTPUT_LOW, port); } -static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static int bnx2x_8727_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { u32 tx_en_mode; u16 tmp1, val, mod_abs, tmp2; @@ -5561,14 +5695,17 @@ static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy, bnx2x_wait_reset_complete(bp, phy, params); rx_alarm_ctrl_val = (1<<2) | (1<<5) ; - lasi_ctrl_val = 0x0004; + /* Should be 0x6 to enable XS on Tx side. */ + lasi_ctrl_val = 0x0006; DP(NETIF_MSG_LINK, "Initializing BCM8727\n"); /* enable LASI */ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL, rx_alarm_ctrl_val); - + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_TX_ALARM_CTRL, + 0); bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, lasi_ctrl_val); @@ -5730,7 +5867,7 @@ static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy, /* Module is absent */ DP(NETIF_MSG_LINK, "MOD_ABS indication " "show module is absent\n"); - + phy->media_type = ETH_PHY_NOT_PRESENT; /* * 1. Set mod_abs to detect next module * presence event @@ -5805,7 +5942,7 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy, { struct bnx2x *bp = params->bp; - u8 link_up = 0; + u8 link_up = 0, oc_port = params->port; u16 link_status = 0; u16 rx_alarm_status, lasi_ctrl, val1; @@ -5816,13 +5953,16 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy, if (!lasi_ctrl) return 0; - /* Check the LASI */ + /* Check the LASI on Rx */ bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &rx_alarm_status); vars->line_speed = 0; DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", rx_alarm_status); + bnx2x_sfp_mask_fault(bp, phy, MDIO_PMA_REG_TX_ALARM, + MDIO_PMA_REG_TX_ALARM_CTRL); + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1); @@ -5843,8 +5983,10 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy, &val1); if ((val1 & (1<<8)) == 0) { + if (!CHIP_IS_E1x(bp)) + oc_port = BP_PATH(bp) + (params->port << 1); DP(NETIF_MSG_LINK, "8727 Power fault has been detected" - " on port %d\n", params->port); + " on port %d\n", oc_port); netdev_err(bp->dev, "Error: Power fault on Port %d has" " been detected and the power to " "that SFP+ module has been removed" @@ -5852,7 +5994,7 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy, " Please remove the SFP+ module and" " restart the system to clear this" " error.\n", - params->port); + oc_port); /* Disable all RX_ALARMs except for mod_abs */ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, @@ -5915,6 +6057,20 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy, DP(NETIF_MSG_LINK, "port %x: External link is down\n", params->port); } + + /* Capture 10G link fault. */ + if (vars->line_speed == SPEED_10000) { + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, + MDIO_PMA_REG_TX_ALARM, &val1); + + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, + MDIO_PMA_REG_TX_ALARM, &val1); + + if (val1 & (1<<0)) { + vars->fault_detected = 1; + } + } + if (link_up) { bnx2x_ext_phy_resolve_fc(phy, params, vars); vars->duplex = DUPLEX_FULL; @@ -5958,111 +6114,106 @@ static void bnx2x_8727_link_reset(struct bnx2x_phy *phy, static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy, struct link_params *params) { - u16 val, fw_ver1, fw_ver2, cnt, adj; + u16 val, fw_ver1, fw_ver2, cnt; + u8 port; struct bnx2x *bp = params->bp; - adj = 0; - if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) - adj = -1; + port = params->port; /* For the 32 bits registers in 848xx, access via MDIO2ARM interface.*/ /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */ - bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819 + adj, 0x0014); - bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A + adj, 0xc200); - bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B + adj, 0x0000); - bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C + adj, 0x0300); - bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817 + adj, 0x0009); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0014); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B, 0x0000); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C, 0x0300); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x0009); for (cnt = 0; cnt < 100; cnt++) { - bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818 + adj, &val); + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val); if (val & 1) break; udelay(5); } if (cnt == 100) { DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(1)\n"); - bnx2x_save_spirom_version(bp, params->port, 0, + bnx2x_save_spirom_version(bp, port, 0, phy->ver_addr); return; } /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */ - bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819 + adj, 0x0000); - bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A + adj, 0xc200); - bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817 + adj, 0x000A); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0000); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x000A); for (cnt = 0; cnt < 100; cnt++) { - bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818 + adj, &val); + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val); if (val & 1) break; udelay(5); } if (cnt == 100) { DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(2)\n"); - bnx2x_save_spirom_version(bp, params->port, 0, + bnx2x_save_spirom_version(bp, port, 0, phy->ver_addr); return; } /* lower 16 bits of the register SPI_FW_STATUS */ - bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B + adj, &fw_ver1); + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B, &fw_ver1); /* upper 16 bits of register SPI_FW_STATUS */ - bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C + adj, &fw_ver2); + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C, &fw_ver2); - bnx2x_save_spirom_version(bp, params->port, (fw_ver2<<16) | fw_ver1, + bnx2x_save_spirom_version(bp, port, (fw_ver2<<16) | fw_ver1, phy->ver_addr); } static void bnx2x_848xx_set_led(struct bnx2x *bp, struct bnx2x_phy *phy) { - u16 val, adj; - - adj = 0; - if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) - adj = -1; + u16 val; /* PHYC_CTL_LED_CTL */ bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LINK_SIGNAL + adj, &val); + MDIO_PMA_REG_8481_LINK_SIGNAL, &val); val &= 0xFE00; val |= 0x0092; bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LINK_SIGNAL + adj, val); + MDIO_PMA_REG_8481_LINK_SIGNAL, val); bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LED1_MASK + adj, + MDIO_PMA_REG_8481_LED1_MASK, 0x80); bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LED2_MASK + adj, + MDIO_PMA_REG_8481_LED2_MASK, 0x18); /* Select activity source by Tx and Rx, as suggested by PHY AE */ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LED3_MASK + adj, + MDIO_PMA_REG_8481_LED3_MASK, 0x0006); /* Select the closest activity blink rate to that in 10/100/1000 */ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, - MDIO_PMA_REG_8481_LED3_BLINK + adj, + MDIO_PMA_REG_8481_LED3_BLINK, 0); bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, - MDIO_PMA_REG_84823_CTL_LED_CTL_1 + adj, &val); + MDIO_PMA_REG_84823_CTL_LED_CTL_1, &val); val |= MDIO_PMA_REG_84823_LED3_STRETCH_EN; /* stretch_en for LED3*/ bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, - MDIO_PMA_REG_84823_CTL_LED_CTL_1 + adj, val); + MDIO_PMA_REG_84823_CTL_LED_CTL_1, val); /* 'Interrupt Mask' */ bnx2x_cl45_write(bp, phy, @@ -6070,12 +6221,19 @@ static void bnx2x_848xx_set_led(struct bnx2x *bp, 0xFFFB, 0xFFFD); } -static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { struct bnx2x *bp = params->bp; u16 autoneg_val, an_1000_val, an_10_100_val; + u16 tmp_req_line_speed; + + tmp_req_line_speed = phy->req_line_speed; + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) + if (phy->req_line_speed == SPEED_10000) + phy->req_line_speed = SPEED_AUTO_NEG; + /* * This phy uses the NIG latch mechanism since link indication * arrives through its LED4 and not via its LASI signal, so we @@ -6179,10 +6337,10 @@ static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy, (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) || (phy->req_line_speed == SPEED_10000)) { - DP(NETIF_MSG_LINK, "Advertising 10G\n"); - /* Restart autoneg for 10G*/ + DP(NETIF_MSG_LINK, "Advertising 10G\n"); + /* Restart autoneg for 10G*/ - bnx2x_cl45_write(bp, phy, + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x3200); } else if (phy->req_line_speed != SPEED_10 && @@ -6195,12 +6353,14 @@ static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy, /* Save spirom version */ bnx2x_save_848xx_spirom_version(phy, params); + phy->req_line_speed = tmp_req_line_speed; + return 0; } -static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static int bnx2x_8481_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { struct bnx2x *bp = params->bp; /* Restore normal power mode*/ @@ -6215,33 +6375,109 @@ static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy, return bnx2x_848xx_cmn_config_init(phy, params, vars); } -static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) + +#define PHY84833_HDSHK_WAIT 300 +static int bnx2x_84833_pair_swap_cfg(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + u32 idx; + u16 val; + u16 data = 0x01b1; + struct bnx2x *bp = params->bp; + /* Do pair swap */ + + + /* Write CMD_OPEN_OVERRIDE to STATUS reg */ + bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_SCRATCH_REG2, + PHY84833_CMD_OPEN_OVERRIDE); + for (idx = 0; idx < PHY84833_HDSHK_WAIT; idx++) { + bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_SCRATCH_REG2, &val); + if (val == PHY84833_CMD_OPEN_FOR_CMDS) + break; + msleep(1); + } + if (idx >= PHY84833_HDSHK_WAIT) { + DP(NETIF_MSG_LINK, "Pairswap: FW not ready.\n"); + return -EINVAL; + } + + bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_SCRATCH_REG4, + data); + /* Issue pair swap command */ + bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_SCRATCH_REG0, + PHY84833_DIAG_CMD_PAIR_SWAP_CHANGE); + for (idx = 0; idx < PHY84833_HDSHK_WAIT; idx++) { + bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_SCRATCH_REG2, &val); + if ((val == PHY84833_CMD_COMPLETE_PASS) || + (val == PHY84833_CMD_COMPLETE_ERROR)) + break; + msleep(1); + } + if ((idx >= PHY84833_HDSHK_WAIT) || + (val == PHY84833_CMD_COMPLETE_ERROR)) { + DP(NETIF_MSG_LINK, "Pairswap: override failed.\n"); + return -EINVAL; + } + bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_SCRATCH_REG2, + PHY84833_CMD_CLEAR_COMPLETE); + DP(NETIF_MSG_LINK, "Pairswap OK, val=0x%x\n", data); + return 0; +} + +static int bnx2x_848x3_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { struct bnx2x *bp = params->bp; u8 port, initialize = 1; - u16 val, adj; + u16 val; u16 temp; u32 actual_phy_selection, cms_enable; - u8 rc = 0; - - /* This is just for MDIO_CTL_REG_84823_MEDIA register. */ - adj = 0; - if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) - adj = 3; + int rc = 0; msleep(1); - if (CHIP_IS_E2(bp)) + + if (!(CHIP_IS_E1(bp))) port = BP_PATH(bp); else port = params->port; - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3, - MISC_REGISTERS_GPIO_OUTPUT_HIGH, - port); + + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823) { + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3, + MISC_REGISTERS_GPIO_OUTPUT_HIGH, + port); + } else { + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, 0x8000); + } + bnx2x_wait_reset_complete(bp, phy, params); /* Wait for GPHY to come out of reset */ msleep(50); + + /* Bring PHY out of super isolate mode */ + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) { + bnx2x_cl45_read(bp, phy, + MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_XGPHY_STRAP1, &val); + val &= ~MDIO_84833_SUPER_ISOLATE; + bnx2x_cl45_write(bp, phy, + MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_XGPHY_STRAP1, val); + bnx2x_wait_reset_complete(bp, phy, params); + } + + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) + bnx2x_84833_pair_swap_cfg(phy, params, vars); + /* * BCM84823 requires that XGXS links up first @ 10G for normal behavior */ @@ -6254,7 +6490,7 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy, /* Set dual-media configuration according to configuration */ bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, - MDIO_CTL_REG_84823_MEDIA + adj, &val); + MDIO_CTL_REG_84823_MEDIA, &val); val &= ~(MDIO_CTL_REG_84823_MEDIA_MAC_MASK | MDIO_CTL_REG_84823_MEDIA_LINE_MASK | MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN | @@ -6287,7 +6523,7 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy, val |= MDIO_CTL_REG_84823_MEDIA_FIBER_1G; bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, - MDIO_CTL_REG_84823_MEDIA + adj, val); + MDIO_CTL_REG_84823_MEDIA, val); DP(NETIF_MSG_LINK, "Multi_phy config = 0x%x, Media control = 0x%x\n", params->multi_phy_config, val); @@ -6318,20 +6554,16 @@ static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy, struct link_vars *vars) { struct bnx2x *bp = params->bp; - u16 val, val1, val2, adj; + u16 val, val1, val2; u8 link_up = 0; - /* Reg offset adjustment for 84833 */ - adj = 0; - if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) - adj = -1; /* Check 10G-BaseT link status */ /* Check PMD signal ok */ bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, 0xFFFA, &val1); bnx2x_cl45_read(bp, phy, - MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL + adj, + MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL, &val2); DP(NETIF_MSG_LINK, "BCM848xx: PMD_SIGNAL 1.a811 = 0x%x\n", val2); @@ -6403,9 +6635,10 @@ static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy, return link_up; } -static u8 bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len) + +static int bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len) { - u8 status = 0; + int status = 0; u32 spirom_ver; spirom_ver = ((raw_ver & 0xF80) >> 7) << 16 | (raw_ver & 0x7F); status = bnx2x_format_ver(spirom_ver, str, len); @@ -6435,13 +6668,21 @@ static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy, { struct bnx2x *bp = params->bp; u8 port; - if (CHIP_IS_E2(bp)) + + if (!(CHIP_IS_E1(bp))) port = BP_PATH(bp); else port = params->port; - bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3, - MISC_REGISTERS_GPIO_OUTPUT_LOW, - port); + + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823) { + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3, + MISC_REGISTERS_GPIO_OUTPUT_LOW, + port); + } else { + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, 0x800); + } } static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy, @@ -6449,11 +6690,17 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy, { struct bnx2x *bp = params->bp; u16 val; + u8 port; + + if (!(CHIP_IS_E1(bp))) + port = BP_PATH(bp); + else + port = params->port; switch (mode) { case LED_MODE_OFF: - DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OFF\n", params->port); + DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OFF\n", port); if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) == SHARED_HW_CFG_LED_EXTPHY1) { @@ -6489,7 +6736,7 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy, case LED_MODE_FRONT_PANEL_OFF: DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE FRONT PANEL OFF\n", - params->port); + port); if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) == SHARED_HW_CFG_LED_EXTPHY1) { @@ -6524,7 +6771,7 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy, break; case LED_MODE_ON: - DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE ON\n", params->port); + DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE ON\n", port); if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) == SHARED_HW_CFG_LED_EXTPHY1) { @@ -6571,7 +6818,7 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy, case LED_MODE_OPER: - DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OPER\n", params->port); + DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OPER\n", port); if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) == SHARED_HW_CFG_LED_EXTPHY1) { @@ -6646,9 +6893,9 @@ static void bnx2x_7101_config_loopback(struct bnx2x_phy *phy, MDIO_XS_DEVAD, MDIO_XS_SFX7101_XGXS_TEST1, 0x100); } -static u8 bnx2x_7101_config_init(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static int bnx2x_7101_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { u16 fw_ver1, fw_ver2, val; struct bnx2x *bp = params->bp; @@ -6721,8 +6968,7 @@ static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy, return link_up; } - -static u8 bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len) +static int bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len) { if (*len < 5) return -EINVAL; @@ -6800,9 +7046,8 @@ static void bnx2x_7101_set_link_led(struct bnx2x_phy *phy, static struct bnx2x_phy phy_null = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN, .addr = 0, - .flags = FLAGS_INIT_XGXS_FIRST, .def_md_devad = 0, - .reserved = 0, + .flags = FLAGS_INIT_XGXS_FIRST, .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -6827,9 +7072,8 @@ static struct bnx2x_phy phy_null = { static struct bnx2x_phy phy_serdes = { .type = PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT, .addr = 0xff, - .flags = 0, .def_md_devad = 0, - .reserved = 0, + .flags = 0, .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -6843,14 +7087,14 @@ static struct bnx2x_phy phy_serdes = { SUPPORTED_Autoneg | SUPPORTED_Pause | SUPPORTED_Asym_Pause), - .media_type = ETH_PHY_UNSPECIFIED, + .media_type = ETH_PHY_BASE_T, .ver_addr = 0, .req_flow_ctrl = 0, .req_line_speed = 0, .speed_cap_mask = 0, .req_duplex = 0, .rsrv = 0, - .config_init = (config_init_t)bnx2x_init_serdes, + .config_init = (config_init_t)bnx2x_xgxs_config_init, .read_status = (read_status_t)bnx2x_link_settings_status, .link_reset = (link_reset_t)bnx2x_int_link_reset, .config_loopback = (config_loopback_t)NULL, @@ -6863,9 +7107,8 @@ static struct bnx2x_phy phy_serdes = { static struct bnx2x_phy phy_xgxs = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT, .addr = 0xff, - .flags = 0, .def_md_devad = 0, - .reserved = 0, + .flags = 0, .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -6880,14 +7123,14 @@ static struct bnx2x_phy phy_xgxs = { SUPPORTED_Autoneg | SUPPORTED_Pause | SUPPORTED_Asym_Pause), - .media_type = ETH_PHY_UNSPECIFIED, + .media_type = ETH_PHY_CX4, .ver_addr = 0, .req_flow_ctrl = 0, .req_line_speed = 0, .speed_cap_mask = 0, .req_duplex = 0, .rsrv = 0, - .config_init = (config_init_t)bnx2x_init_xgxs, + .config_init = (config_init_t)bnx2x_xgxs_config_init, .read_status = (read_status_t)bnx2x_link_settings_status, .link_reset = (link_reset_t)bnx2x_int_link_reset, .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback, @@ -6900,9 +7143,8 @@ static struct bnx2x_phy phy_xgxs = { static struct bnx2x_phy phy_7101 = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, .addr = 0xff, - .flags = FLAGS_FAN_FAILURE_DET_REQ, .def_md_devad = 0, - .reserved = 0, + .flags = FLAGS_FAN_FAILURE_DET_REQ, .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -6930,9 +7172,8 @@ static struct bnx2x_phy phy_7101 = { static struct bnx2x_phy phy_8073 = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, .addr = 0xff, - .flags = FLAGS_HW_LOCK_REQUIRED, .def_md_devad = 0, - .reserved = 0, + .flags = FLAGS_HW_LOCK_REQUIRED, .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -6943,7 +7184,7 @@ static struct bnx2x_phy phy_8073 = { SUPPORTED_Autoneg | SUPPORTED_Pause | SUPPORTED_Asym_Pause), - .media_type = ETH_PHY_UNSPECIFIED, + .media_type = ETH_PHY_KR, .ver_addr = 0, .req_flow_ctrl = 0, .req_line_speed = 0, @@ -6962,9 +7203,8 @@ static struct bnx2x_phy phy_8073 = { static struct bnx2x_phy phy_8705 = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705, .addr = 0xff, - .flags = FLAGS_INIT_XGXS_FIRST, .def_md_devad = 0, - .reserved = 0, + .flags = FLAGS_INIT_XGXS_FIRST, .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -6991,9 +7231,8 @@ static struct bnx2x_phy phy_8705 = { static struct bnx2x_phy phy_8706 = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706, .addr = 0xff, - .flags = FLAGS_INIT_XGXS_FIRST, .def_md_devad = 0, - .reserved = 0, + .flags = FLAGS_INIT_XGXS_FIRST, .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -7022,10 +7261,9 @@ static struct bnx2x_phy phy_8706 = { static struct bnx2x_phy phy_8726 = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, .addr = 0xff, + .def_md_devad = 0, .flags = (FLAGS_HW_LOCK_REQUIRED | FLAGS_INIT_XGXS_FIRST), - .def_md_devad = 0, - .reserved = 0, .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -7035,7 +7273,7 @@ static struct bnx2x_phy phy_8726 = { SUPPORTED_FIBRE | SUPPORTED_Pause | SUPPORTED_Asym_Pause), - .media_type = ETH_PHY_SFP_FIBER, + .media_type = ETH_PHY_NOT_PRESENT, .ver_addr = 0, .req_flow_ctrl = 0, .req_line_speed = 0, @@ -7055,9 +7293,8 @@ static struct bnx2x_phy phy_8726 = { static struct bnx2x_phy phy_8727 = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, .addr = 0xff, - .flags = FLAGS_FAN_FAILURE_DET_REQ, .def_md_devad = 0, - .reserved = 0, + .flags = FLAGS_FAN_FAILURE_DET_REQ, .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -7066,7 +7303,7 @@ static struct bnx2x_phy phy_8727 = { SUPPORTED_FIBRE | SUPPORTED_Pause | SUPPORTED_Asym_Pause), - .media_type = ETH_PHY_SFP_FIBER, + .media_type = ETH_PHY_NOT_PRESENT, .ver_addr = 0, .req_flow_ctrl = 0, .req_line_speed = 0, @@ -7085,10 +7322,9 @@ static struct bnx2x_phy phy_8727 = { static struct bnx2x_phy phy_8481 = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, .addr = 0xff, + .def_md_devad = 0, .flags = FLAGS_FAN_FAILURE_DET_REQ | FLAGS_REARM_LATCH_SIGNAL, - .def_md_devad = 0, - .reserved = 0, .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -7122,10 +7358,9 @@ static struct bnx2x_phy phy_8481 = { static struct bnx2x_phy phy_84823 = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823, .addr = 0xff, + .def_md_devad = 0, .flags = FLAGS_FAN_FAILURE_DET_REQ | FLAGS_REARM_LATCH_SIGNAL, - .def_md_devad = 0, - .reserved = 0, .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -7159,10 +7394,9 @@ static struct bnx2x_phy phy_84823 = { static struct bnx2x_phy phy_84833 = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833, .addr = 0xff, + .def_md_devad = 0, .flags = FLAGS_FAN_FAILURE_DET_REQ | FLAGS_REARM_LATCH_SIGNAL, - .def_md_devad = 0, - .reserved = 0, .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, .mdio_ctrl = 0, @@ -7259,8 +7493,8 @@ static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base, return ext_phy_config; } -static u8 bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port, - struct bnx2x_phy *phy) +static int bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port, + struct bnx2x_phy *phy) { u32 phy_addr; u32 chip_id; @@ -7302,12 +7536,12 @@ static u8 bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port, return 0; } -static u8 bnx2x_populate_ext_phy(struct bnx2x *bp, - u8 phy_index, - u32 shmem_base, - u32 shmem2_base, - u8 port, - struct bnx2x_phy *phy) +static int bnx2x_populate_ext_phy(struct bnx2x *bp, + u8 phy_index, + u32 shmem_base, + u32 shmem2_base, + u8 port, + struct bnx2x_phy *phy) { u32 ext_phy_config, phy_type, config2; u32 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH; @@ -7336,6 +7570,7 @@ static u8 bnx2x_populate_ext_phy(struct bnx2x *bp, *phy = phy_8727; phy->flags |= FLAGS_NOC; break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1; *phy = phy_8727; @@ -7410,10 +7645,10 @@ static u8 bnx2x_populate_ext_phy(struct bnx2x *bp, return 0; } -static u8 bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base, - u32 shmem2_base, u8 port, struct bnx2x_phy *phy) +static int bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base, + u32 shmem2_base, u8 port, struct bnx2x_phy *phy) { - u8 status = 0; + int status = 0; phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN; if (phy_index == INT_PHY) return bnx2x_populate_int_phy(bp, shmem_base, port, phy); @@ -7527,10 +7762,10 @@ u32 bnx2x_phy_selection(struct link_params *params) } -u8 bnx2x_phy_probe(struct link_params *params) +int bnx2x_phy_probe(struct link_params *params) { u8 phy_index, actual_phy_idx, link_cfg_idx; - u32 phy_config_swapped; + u32 phy_config_swapped, sync_offset, media_types; struct bnx2x *bp = params->bp; struct bnx2x_phy *phy; params->num_phys = 0; @@ -7567,6 +7802,26 @@ u8 bnx2x_phy_probe(struct link_params *params) if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) break; + sync_offset = params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[params->port].media_type); + media_types = REG_RD(bp, sync_offset); + + /* + * Update media type for non-PMF sync only for the first time + * In case the media type changes afterwards, it will be updated + * using the update_status function + */ + if ((media_types & (PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK << + (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * + actual_phy_idx))) == 0) { + media_types |= ((phy->media_type & + PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) << + (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * + actual_phy_idx)); + } + REG_WR(bp, sync_offset, media_types); + bnx2x_phy_def_cfg(params, phy, phy_index); params->num_phys++; } @@ -7575,77 +7830,10 @@ u8 bnx2x_phy_probe(struct link_params *params) return 0; } -static void set_phy_vars(struct link_params *params) -{ - struct bnx2x *bp = params->bp; - u8 actual_phy_idx, phy_index, link_cfg_idx; - u8 phy_config_swapped = params->multi_phy_config & - PORT_HW_CFG_PHY_SWAPPED_ENABLED; - for (phy_index = INT_PHY; phy_index < params->num_phys; - phy_index++) { - link_cfg_idx = LINK_CONFIG_IDX(phy_index); - actual_phy_idx = phy_index; - if (phy_config_swapped) { - if (phy_index == EXT_PHY1) - actual_phy_idx = EXT_PHY2; - else if (phy_index == EXT_PHY2) - actual_phy_idx = EXT_PHY1; - } - params->phy[actual_phy_idx].req_flow_ctrl = - params->req_flow_ctrl[link_cfg_idx]; - - params->phy[actual_phy_idx].req_line_speed = - params->req_line_speed[link_cfg_idx]; - - params->phy[actual_phy_idx].speed_cap_mask = - params->speed_cap_mask[link_cfg_idx]; - - params->phy[actual_phy_idx].req_duplex = - params->req_duplex[link_cfg_idx]; - - DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x," - " speed_cap_mask %x\n", - params->phy[actual_phy_idx].req_flow_ctrl, - params->phy[actual_phy_idx].req_line_speed, - params->phy[actual_phy_idx].speed_cap_mask); - } -} - -u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) +void bnx2x_init_bmac_loopback(struct link_params *params, + struct link_vars *vars) { struct bnx2x *bp = params->bp; - DP(NETIF_MSG_LINK, "Phy Initialization started\n"); - DP(NETIF_MSG_LINK, "(1) req_speed %d, req_flowctrl %d\n", - params->req_line_speed[0], params->req_flow_ctrl[0]); - DP(NETIF_MSG_LINK, "(2) req_speed %d, req_flowctrl %d\n", - params->req_line_speed[1], params->req_flow_ctrl[1]); - vars->link_status = 0; - vars->phy_link_up = 0; - vars->link_up = 0; - vars->line_speed = 0; - vars->duplex = DUPLEX_FULL; - vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; - vars->mac_type = MAC_TYPE_NONE; - vars->phy_flags = 0; - - /* disable attentions */ - bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4, - (NIG_MASK_XGXS0_LINK_STATUS | - NIG_MASK_XGXS0_LINK10G | - NIG_MASK_SERDES0_LINK_STATUS | - NIG_MASK_MI_INT)); - - bnx2x_emac_init(params, vars); - - if (params->num_phys == 0) { - DP(NETIF_MSG_LINK, "No phy found for initialization !!\n"); - return -EINVAL; - } - set_phy_vars(params); - - DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys); - if (params->loopback_mode == LOOPBACK_BMAC) { - vars->link_up = 1; vars->line_speed = SPEED_10000; vars->duplex = DUPLEX_FULL; @@ -7660,9 +7848,12 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) bnx2x_bmac_enable(params, vars, 1); REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); +} - } else if (params->loopback_mode == LOOPBACK_EMAC) { - +void bnx2x_init_emac_loopback(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; vars->link_up = 1; vars->line_speed = SPEED_1000; vars->duplex = DUPLEX_FULL; @@ -7676,29 +7867,32 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) bnx2x_emac_enable(params, vars, 1); bnx2x_emac_program(params, vars); REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); +} - } else if ((params->loopback_mode == LOOPBACK_XGXS) || - (params->loopback_mode == LOOPBACK_EXT_PHY)) { - +void bnx2x_init_xgxs_loopback(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; vars->link_up = 1; vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; vars->duplex = DUPLEX_FULL; - if (params->req_line_speed[0] == SPEED_1000) { + if (params->req_line_speed[0] == SPEED_1000) vars->line_speed = SPEED_1000; - vars->mac_type = MAC_TYPE_EMAC; - } else { + else vars->line_speed = SPEED_10000; - vars->mac_type = MAC_TYPE_BMAC; - } - bnx2x_xgxs_deassert(params); - bnx2x_link_initialize(params, vars); - if (params->req_line_speed[0] == SPEED_1000) { - bnx2x_emac_program(params, vars); - bnx2x_emac_enable(params, vars, 0); - } else - bnx2x_bmac_enable(params, vars, 0); + bnx2x_xgxs_deassert(params); + bnx2x_link_initialize(params, vars); + + if (params->req_line_speed[0] == SPEED_1000) { + bnx2x_emac_program(params, vars); + bnx2x_emac_enable(params, vars, 0); + + } else + bnx2x_bmac_enable(params, vars, 0); + + if (params->loopback_mode == LOOPBACK_XGXS) { /* set 10G XGXS loopback */ params->phy[INT_PHY].config_loopback( @@ -7718,11 +7912,55 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) } REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); - bnx2x_set_led(params, vars, - LED_MODE_OPER, vars->line_speed); - } else - /* No loopback */ - { + bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed); +} + +int bnx2x_phy_init(struct link_params *params, struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + DP(NETIF_MSG_LINK, "Phy Initialization started\n"); + DP(NETIF_MSG_LINK, "(1) req_speed %d, req_flowctrl %d\n", + params->req_line_speed[0], params->req_flow_ctrl[0]); + DP(NETIF_MSG_LINK, "(2) req_speed %d, req_flowctrl %d\n", + params->req_line_speed[1], params->req_flow_ctrl[1]); + vars->link_status = 0; + vars->phy_link_up = 0; + vars->link_up = 0; + vars->line_speed = 0; + vars->duplex = DUPLEX_FULL; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; + vars->mac_type = MAC_TYPE_NONE; + vars->phy_flags = 0; + + /* disable attentions */ + bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4, + (NIG_MASK_XGXS0_LINK_STATUS | + NIG_MASK_XGXS0_LINK10G | + NIG_MASK_SERDES0_LINK_STATUS | + NIG_MASK_MI_INT)); + + bnx2x_emac_init(params, vars); + + if (params->num_phys == 0) { + DP(NETIF_MSG_LINK, "No phy found for initialization !!\n"); + return -EINVAL; + } + set_phy_vars(params, vars); + + DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys); + switch (params->loopback_mode) { + case LOOPBACK_BMAC: + bnx2x_init_bmac_loopback(params, vars); + break; + case LOOPBACK_EMAC: + bnx2x_init_emac_loopback(params, vars); + break; + case LOOPBACK_XGXS: + case LOOPBACK_EXT_PHY: + bnx2x_init_xgxs_loopback(params, vars); + break; + default: + /* No loopback */ if (params->switch_cfg == SWITCH_CFG_10G) bnx2x_xgxs_deassert(params); else @@ -7731,11 +7969,13 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) bnx2x_link_initialize(params, vars); msleep(30); bnx2x_link_int_enable(params); + break; } return 0; } -u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, - u8 reset_ext_phy) + +int bnx2x_link_reset(struct link_params *params, struct link_vars *vars, + u8 reset_ext_phy) { struct bnx2x *bp = params->bp; u8 phy_index, port = params->port, clear_latch_ind = 0; @@ -7807,10 +8047,10 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, /****************************************************************************/ /* Common function */ /****************************************************************************/ -static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, - u32 shmem_base_path[], - u32 shmem2_base_path[], u8 phy_index, - u32 chip_id) +static int bnx2x_8073_common_init_phy(struct bnx2x *bp, + u32 shmem_base_path[], + u32 shmem2_base_path[], u8 phy_index, + u32 chip_id) { struct bnx2x_phy phy[PORT_MAX]; struct bnx2x_phy *phy_blk[PORT_MAX]; @@ -7933,10 +8173,10 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp, } return 0; } -static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp, - u32 shmem_base_path[], - u32 shmem2_base_path[], u8 phy_index, - u32 chip_id) +static int bnx2x_8726_common_init_phy(struct bnx2x *bp, + u32 shmem_base_path[], + u32 shmem2_base_path[], u8 phy_index, + u32 chip_id) { u32 val; s8 port; @@ -8027,10 +8267,11 @@ static void bnx2x_get_ext_phy_reset_gpio(struct bnx2x *bp, u32 shmem_base, break; } } -static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, - u32 shmem_base_path[], - u32 shmem2_base_path[], u8 phy_index, - u32 chip_id) + +static int bnx2x_8727_common_init_phy(struct bnx2x *bp, + u32 shmem_base_path[], + u32 shmem2_base_path[], u8 phy_index, + u32 chip_id) { s8 port, reset_gpio; u32 swap_val, swap_override; @@ -8123,11 +8364,11 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp, return 0; } -static u8 bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[], - u32 shmem2_base_path[], u8 phy_index, - u32 ext_phy_type, u32 chip_id) +static int bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[], + u32 shmem2_base_path[], u8 phy_index, + u32 ext_phy_type, u32 chip_id) { - u8 rc = 0; + int rc = 0; switch (ext_phy_type) { case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: @@ -8135,7 +8376,7 @@ static u8 bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[], shmem2_base_path, phy_index, chip_id); break; - + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC: rc = bnx2x_8727_common_init_phy(bp, shmem_base_path, @@ -8169,13 +8410,15 @@ static u8 bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[], return rc; } -u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[], - u32 shmem2_base_path[], u32 chip_id) +int bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[], + u32 shmem2_base_path[], u32 chip_id) { - u8 rc = 0; + int rc = 0; u32 phy_ver; u8 phy_index; u32 ext_phy_type, ext_phy_config; + bnx2x_set_mdio_clk(bp, chip_id, PORT_0); + bnx2x_set_mdio_clk(bp, chip_id, PORT_1); DP(NETIF_MSG_LINK, "Begin common phy init\n"); /* Check if common init was already done */ @@ -8255,3 +8498,66 @@ void bnx2x_hw_reset_phy(struct link_params *params) } } } + +void bnx2x_init_mod_abs_int(struct bnx2x *bp, struct link_vars *vars, + u32 chip_id, u32 shmem_base, u32 shmem2_base, + u8 port) +{ + u8 gpio_num = 0xff, gpio_port = 0xff, phy_index; + u32 val; + u32 offset, aeu_mask, swap_val, swap_override, sync_offset; + + { + struct bnx2x_phy phy; + for (phy_index = EXT_PHY1; phy_index < MAX_PHYS; + phy_index++) { + if (bnx2x_populate_phy(bp, phy_index, shmem_base, + shmem2_base, port, &phy) + != 0) { + DP(NETIF_MSG_LINK, "populate phy failed\n"); + return; + } + if (phy.type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) { + gpio_num = MISC_REGISTERS_GPIO_3; + gpio_port = port; + break; + } + } + } + + if (gpio_num == 0xff) + return; + + /* Set GPIO3 to trigger SFP+ module insertion/removal */ + bnx2x_set_gpio(bp, gpio_num, MISC_REGISTERS_GPIO_INPUT_HI_Z, gpio_port); + + swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); + swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); + gpio_port ^= (swap_val && swap_override); + + vars->aeu_int_mask = AEU_INPUTS_ATTN_BITS_GPIO0_FUNCTION_0 << + (gpio_num + (gpio_port << 2)); + + sync_offset = shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].aeu_int_mask); + REG_WR(bp, sync_offset, vars->aeu_int_mask); + + DP(NETIF_MSG_LINK, "Setting MOD_ABS (GPIO%d_P%d) AEU to 0x%x\n", + gpio_num, gpio_port, vars->aeu_int_mask); + + if (port == 0) + offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0; + else + offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0; + + /* Open appropriate AEU for interrupts */ + aeu_mask = REG_RD(bp, offset); + aeu_mask |= vars->aeu_int_mask; + REG_WR(bp, offset, aeu_mask); + + /* Enable the GPIO to trigger interrupt */ + val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN); + val |= 1 << (gpio_num + (gpio_port << 2)); + REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val); +} diff --git a/drivers/net/bnx2x/bnx2x_link.h b/drivers/net/bnx2x/bnx2x_link.h index 92f36b6950dc..a106d8cbd69f 100644 --- a/drivers/net/bnx2x/bnx2x_link.h +++ b/drivers/net/bnx2x/bnx2x_link.h @@ -121,8 +121,8 @@ struct bnx2x_phy { /* Loaded during init */ u8 addr; - - u8 flags; + u8 def_md_devad; + u16 flags; /* Require HW lock */ #define FLAGS_HW_LOCK_REQUIRED (1<<0) /* No Over-Current detection */ @@ -134,8 +134,6 @@ struct bnx2x_phy { #define FLAGS_REARM_LATCH_SIGNAL (1<<6) #define FLAGS_SFP_NOT_APPROVED (1<<7) - u8 def_md_devad; - u8 reserved; /* preemphasis values for the rx side */ u16 rx_preemphasis[4]; @@ -153,6 +151,8 @@ struct bnx2x_phy { #define ETH_PHY_XFP_FIBER 0x2 #define ETH_PHY_DA_TWINAX 0x3 #define ETH_PHY_BASE_T 0x4 +#define ETH_PHY_KR 0xf0 +#define ETH_PHY_CX4 0xf1 #define ETH_PHY_NOT_PRESENT 0xff /* The address in which version is located*/ @@ -274,45 +274,50 @@ struct link_vars { /* The same definitions as the shmem parameter */ u32 link_status; + u8 fault_detected; + u8 rsrv1; + u16 rsrv2; + u32 aeu_int_mask; }; /***********************************************************/ /* Functions */ /***********************************************************/ -u8 bnx2x_phy_init(struct link_params *input, struct link_vars *output); +int bnx2x_phy_init(struct link_params *params, struct link_vars *vars); /* Reset the link. Should be called when driver or interface goes down Before calling phy firmware upgrade, the reset_ext_phy should be set to 0 */ -u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars, - u8 reset_ext_phy); +int bnx2x_link_reset(struct link_params *params, struct link_vars *vars, + u8 reset_ext_phy); /* bnx2x_link_update should be called upon link interrupt */ -u8 bnx2x_link_update(struct link_params *input, struct link_vars *output); +int bnx2x_link_update(struct link_params *params, struct link_vars *vars); /* use the following phy functions to read/write from external_phy In order to use it to read/write internal phy registers, use DEFAULT_PHY_DEV_ADDR as devad, and (_bank + (_addr & 0xf)) as the register */ -u8 bnx2x_phy_read(struct link_params *params, u8 phy_addr, - u8 devad, u16 reg, u16 *ret_val); +int bnx2x_phy_read(struct link_params *params, u8 phy_addr, + u8 devad, u16 reg, u16 *ret_val); + +int bnx2x_phy_write(struct link_params *params, u8 phy_addr, + u8 devad, u16 reg, u16 val); -u8 bnx2x_phy_write(struct link_params *params, u8 phy_addr, - u8 devad, u16 reg, u16 val); /* Reads the link_status from the shmem, and update the link vars accordingly */ void bnx2x_link_status_update(struct link_params *input, struct link_vars *output); /* returns string representing the fw_version of the external phy */ -u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, - u8 *version, u16 len); +int bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, + u8 *version, u16 len); /* Set/Unset the led Basically, the CLC takes care of the led for the link, but in case one needs to set/unset the led unnaturally, set the "mode" to LED_MODE_OPER to blink the led, and LED_MODE_OFF to set the led off.*/ -u8 bnx2x_set_led(struct link_params *params, struct link_vars *vars, - u8 mode, u32 speed); +int bnx2x_set_led(struct link_params *params, + struct link_vars *vars, u8 mode, u32 speed); #define LED_MODE_OFF 0 #define LED_MODE_ON 1 #define LED_MODE_OPER 2 @@ -324,12 +329,12 @@ void bnx2x_handle_module_detect_int(struct link_params *params); /* Get the actual link status. In case it returns 0, link is up, otherwise link is down*/ -u8 bnx2x_test_link(struct link_params *input, struct link_vars *vars, - u8 is_serdes); +int bnx2x_test_link(struct link_params *params, struct link_vars *vars, + u8 is_serdes); /* One-time initialization for external phy after power up */ -u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[], - u32 shmem2_base_path[], u32 chip_id); +int bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[], + u32 shmem2_base_path[], u32 chip_id); /* Reset the external PHY using GPIO */ void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port); @@ -338,9 +343,9 @@ void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port); void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy); /* Read "byte_cnt" bytes from address "addr" from the SFP+ EEPROM */ -u8 bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy, - struct link_params *params, u16 addr, - u8 byte_cnt, u8 *o_buf); +int bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy, + struct link_params *params, u16 addr, + u8 byte_cnt, u8 *o_buf); void bnx2x_hw_reset_phy(struct link_params *params); @@ -352,7 +357,8 @@ u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base, u32 bnx2x_phy_selection(struct link_params *params); /* Probe the phys on board, and populate them in "params" */ -u8 bnx2x_phy_probe(struct link_params *params); +int bnx2x_phy_probe(struct link_params *params); + /* Checks if fan failure detection is required on one of the phys on board */ u8 bnx2x_fan_failure_det_req(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base, u8 port); @@ -390,10 +396,13 @@ void bnx2x_ets_bw_limit(const struct link_params *params, const u32 cos0_bw, const u32 cos1_bw); /* Used to configure the ETS to strict */ -u8 bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos); +int bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos); /* Read pfc statistic*/ void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars, u32 pfc_frames_sent[2], u32 pfc_frames_received[2]); +void bnx2x_init_mod_abs_int(struct bnx2x *bp, struct link_vars *vars, + u32 chip_id, u32 shmem_base, u32 shmem2_base, + u8 port); #endif /* BNX2X_LINK_H */ diff --git a/drivers/net/bnx2x/bnx2x_main.c b/drivers/net/bnx2x/bnx2x_main.c index 4b70311a11ef..2e89b6cf37ae 100644 --- a/drivers/net/bnx2x/bnx2x_main.c +++ b/drivers/net/bnx2x/bnx2x_main.c @@ -1732,45 +1732,6 @@ static int bnx2x_set_spio(struct bnx2x *bp, int spio_num, u32 mode) return 0; } -int bnx2x_get_link_cfg_idx(struct bnx2x *bp) -{ - u32 sel_phy_idx = 0; - if (bp->link_vars.link_up) { - sel_phy_idx = EXT_PHY1; - /* In case link is SERDES, check if the EXT_PHY2 is the one */ - if ((bp->link_vars.link_status & LINK_STATUS_SERDES_LINK) && - (bp->link_params.phy[EXT_PHY2].supported & SUPPORTED_FIBRE)) - sel_phy_idx = EXT_PHY2; - } else { - - switch (bnx2x_phy_selection(&bp->link_params)) { - case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT: - case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY: - case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY: - sel_phy_idx = EXT_PHY1; - break; - case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY: - case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY: - sel_phy_idx = EXT_PHY2; - break; - } - } - /* - * The selected actived PHY is always after swapping (in case PHY - * swapping is enabled). So when swapping is enabled, we need to reverse - * the configuration - */ - - if (bp->link_params.multi_phy_config & - PORT_HW_CFG_PHY_SWAPPED_ENABLED) { - if (sel_phy_idx == EXT_PHY1) - sel_phy_idx = EXT_PHY2; - else if (sel_phy_idx == EXT_PHY2) - sel_phy_idx = EXT_PHY1; - } - return LINK_CONFIG_IDX(sel_phy_idx); -} - void bnx2x_calc_fc_adv(struct bnx2x *bp) { u8 cfg_idx = bnx2x_get_link_cfg_idx(bp); @@ -4491,6 +4452,10 @@ void bnx2x_nic_init(struct bnx2x *bp, u32 load_code) #endif + /* Initialize MOD_ABS interrupts */ + bnx2x_init_mod_abs_int(bp, &bp->link_vars, bp->common.chip_id, + bp->common.shmem_base, bp->common.shmem2_base, + BP_PORT(bp)); /* ensure status block indices were read */ rmb(); diff --git a/drivers/net/bnx2x/bnx2x_reg.h b/drivers/net/bnx2x/bnx2x_reg.h index 86bba25d2d3f..949e8bd73188 100644 --- a/drivers/net/bnx2x/bnx2x_reg.h +++ b/drivers/net/bnx2x/bnx2x_reg.h @@ -5184,6 +5184,7 @@ #define AEU_INPUTS_ATTN_BITS_DMAE_HW_INTERRUPT (1<<11) #define AEU_INPUTS_ATTN_BITS_DOORBELLQ_HW_INTERRUPT (1<<13) #define AEU_INPUTS_ATTN_BITS_DOORBELLQ_PARITY_ERROR (1<<12) +#define AEU_INPUTS_ATTN_BITS_GPIO0_FUNCTION_0 (1<<2) #define AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 (1<<5) #define AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1 (1<<9) #define AEU_INPUTS_ATTN_BITS_IGU_PARITY_ERROR (1<<12) @@ -6037,6 +6038,7 @@ Theotherbitsarereservedandshouldbezero*/ #define MDIO_PMA_REG_BCM_CTRL 0x0096 #define MDIO_PMA_REG_FEC_CTRL 0x00ab #define MDIO_PMA_REG_RX_ALARM_CTRL 0x9000 +#define MDIO_PMA_REG_TX_ALARM_CTRL 0x9001 #define MDIO_PMA_REG_LASI_CTRL 0x9002 #define MDIO_PMA_REG_RX_ALARM 0x9003 #define MDIO_PMA_REG_TX_ALARM 0x9004 @@ -6201,6 +6203,29 @@ Theotherbitsarereservedandshouldbezero*/ #define MDIO_PMA_REG_84823_CTL_LED_CTL_1 0xa8e3 #define MDIO_PMA_REG_84823_LED3_STRETCH_EN 0x0080 +/* BCM84833 only */ +#define MDIO_84833_TOP_CFG_XGPHY_STRAP1 0x401a +#define MDIO_84833_SUPER_ISOLATE 0x8000 +/* These are mailbox register set used by 84833. */ +#define MDIO_84833_TOP_CFG_SCRATCH_REG0 0x4005 +#define MDIO_84833_TOP_CFG_SCRATCH_REG1 0x4006 +#define MDIO_84833_TOP_CFG_SCRATCH_REG2 0x4007 +#define MDIO_84833_TOP_CFG_SCRATCH_REG3 0x4008 +#define MDIO_84833_TOP_CFG_SCRATCH_REG4 0x4009 + +/* Mailbox command set used by 84833. */ +#define PHY84833_DIAG_CMD_PAIR_SWAP_CHANGE 0x2 +/* Mailbox status set used by 84833. */ +#define PHY84833_CMD_RECEIVED 0x0001 +#define PHY84833_CMD_IN_PROGRESS 0x0002 +#define PHY84833_CMD_COMPLETE_PASS 0x0004 +#define PHY84833_CMD_COMPLETE_ERROR 0x0008 +#define PHY84833_CMD_OPEN_FOR_CMDS 0x0010 +#define PHY84833_CMD_SYSTEM_BOOT 0x0020 +#define PHY84833_CMD_NOT_OPEN_FOR_CMDS 0x0040 +#define PHY84833_CMD_CLEAR_COMPLETE 0x0080 +#define PHY84833_CMD_OPEN_OVERRIDE 0xa5a5 + #define IGU_FUNC_BASE 0x0400 #define IGU_ADDR_MSIX 0x0000 diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 17b4dd94da90..716c852a6968 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -629,15 +629,8 @@ static int bond_update_speed_duplex(struct slave *slave) return -1; slave_speed = ethtool_cmd_speed(&etool); - switch (slave_speed) { - case SPEED_10: - case SPEED_100: - case SPEED_1000: - case SPEED_10000: - break; - default: + if (slave_speed == 0 || slave_speed == ((__u32) -1)) return -1; - } switch (etool.duplex) { case DUPLEX_FULL: diff --git a/drivers/net/caif/Kconfig b/drivers/net/caif/Kconfig index 09ed3f42d673..abf4d7a9dcce 100644 --- a/drivers/net/caif/Kconfig +++ b/drivers/net/caif/Kconfig @@ -38,3 +38,12 @@ config CAIF_SHM default n ---help--- The CAIF shared memory protocol driver for the STE UX5500 platform. + +config CAIF_HSI + tristate "CAIF HSI transport driver" + depends on CAIF + default n + ---help--- + The caif low level driver for CAIF over HSI. + Be aware that if you enable this then you also need to + enable a low-level HSI driver. diff --git a/drivers/net/caif/Makefile b/drivers/net/caif/Makefile index 9560b9d624bd..91dff861560f 100644 --- a/drivers/net/caif/Makefile +++ b/drivers/net/caif/Makefile @@ -10,3 +10,6 @@ obj-$(CONFIG_CAIF_SPI_SLAVE) += cfspi_slave.o # Shared memory caif_shm-objs := caif_shmcore.o caif_shm_u5500.o obj-$(CONFIG_CAIF_SHM) += caif_shm.o + +# HSI interface +obj-$(CONFIG_CAIF_HSI) += caif_hsi.o diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c new file mode 100644 index 000000000000..7a8ce61234a7 --- /dev/null +++ b/drivers/net/caif/caif_hsi.c @@ -0,0 +1,1220 @@ +/* + * Copyright (C) ST-Ericsson AB 2010 + * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com + * Author: Daniel Martensson / daniel.martensson@stericsson.com + * Dmitry.Tarnyagin / dmitry.tarnyagin@stericsson.com + * License terms: GNU General Public License (GPL) version 2. + */ + +#include <linux/version.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/netdevice.h> +#include <linux/string.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/sched.h> +#include <linux/if_arp.h> +#include <linux/timer.h> +#include <net/caif/caif_layer.h> +#include <net/caif/caif_hsi.h> + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Daniel Martensson<daniel.martensson@stericsson.com>"); +MODULE_DESCRIPTION("CAIF HSI driver"); + +/* Returns the number of padding bytes for alignment. */ +#define PAD_POW2(x, pow) ((((x)&((pow)-1)) == 0) ? 0 :\ + (((pow)-((x)&((pow)-1))))) + +/* + * HSI padding options. + * Warning: must be a base of 2 (& operation used) and can not be zero ! + */ +static int hsi_head_align = 4; +module_param(hsi_head_align, int, S_IRUGO); +MODULE_PARM_DESC(hsi_head_align, "HSI head alignment."); + +static int hsi_tail_align = 4; +module_param(hsi_tail_align, int, S_IRUGO); +MODULE_PARM_DESC(hsi_tail_align, "HSI tail alignment."); + +/* + * HSI link layer flowcontrol thresholds. + * Warning: A high threshold value migth increase throughput but it will at + * the same time prevent channel prioritization and increase the risk of + * flooding the modem. The high threshold should be above the low. + */ +static int hsi_high_threshold = 100; +module_param(hsi_high_threshold, int, S_IRUGO); +MODULE_PARM_DESC(hsi_high_threshold, "HSI high threshold (FLOW OFF)."); + +static int hsi_low_threshold = 50; +module_param(hsi_low_threshold, int, S_IRUGO); +MODULE_PARM_DESC(hsi_low_threshold, "HSI high threshold (FLOW ON)."); + +#define ON 1 +#define OFF 0 + +/* + * Threshold values for the HSI packet queue. Flowcontrol will be asserted + * when the number of packets exceeds HIGH_WATER_MARK. It will not be + * de-asserted before the number of packets drops below LOW_WATER_MARK. + */ +#define LOW_WATER_MARK hsi_low_threshold +#define HIGH_WATER_MARK hsi_high_threshold + +static LIST_HEAD(cfhsi_list); +static spinlock_t cfhsi_list_lock; + +static void cfhsi_inactivity_tout(unsigned long arg) +{ + struct cfhsi *cfhsi = (struct cfhsi *)arg; + + dev_dbg(&cfhsi->ndev->dev, "%s.\n", + __func__); + + /* Schedule power down work queue. */ + if (!test_bit(CFHSI_SHUTDOWN, &cfhsi->bits)) + queue_work(cfhsi->wq, &cfhsi->wake_down_work); +} + +static void cfhsi_abort_tx(struct cfhsi *cfhsi) +{ + struct sk_buff *skb; + + for (;;) { + spin_lock_bh(&cfhsi->lock); + skb = skb_dequeue(&cfhsi->qhead); + if (!skb) + break; + + cfhsi->ndev->stats.tx_errors++; + cfhsi->ndev->stats.tx_dropped++; + spin_unlock_bh(&cfhsi->lock); + kfree_skb(skb); + } + cfhsi->tx_state = CFHSI_TX_STATE_IDLE; + if (!test_bit(CFHSI_SHUTDOWN, &cfhsi->bits)) + mod_timer(&cfhsi->timer, jiffies + CFHSI_INACTIVITY_TOUT); + spin_unlock_bh(&cfhsi->lock); +} + +static int cfhsi_flush_fifo(struct cfhsi *cfhsi) +{ + char buffer[32]; /* Any reasonable value */ + size_t fifo_occupancy; + int ret; + + dev_dbg(&cfhsi->ndev->dev, "%s.\n", + __func__); + + + ret = cfhsi->dev->cfhsi_wake_up(cfhsi->dev); + if (ret) { + dev_warn(&cfhsi->ndev->dev, + "%s: can't wake up HSI interface: %d.\n", + __func__, ret); + return ret; + } + + do { + ret = cfhsi->dev->cfhsi_fifo_occupancy(cfhsi->dev, + &fifo_occupancy); + if (ret) { + dev_warn(&cfhsi->ndev->dev, + "%s: can't get FIFO occupancy: %d.\n", + __func__, ret); + break; + } else if (!fifo_occupancy) + /* No more data, exitting normally */ + break; + + fifo_occupancy = min(sizeof(buffer), fifo_occupancy); + set_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits); + ret = cfhsi->dev->cfhsi_rx(buffer, fifo_occupancy, + cfhsi->dev); + if (ret) { + clear_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits); + dev_warn(&cfhsi->ndev->dev, + "%s: can't read data: %d.\n", + __func__, ret); + break; + } + + ret = 5 * HZ; + wait_event_interruptible_timeout(cfhsi->flush_fifo_wait, + !test_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits), ret); + + if (ret < 0) { + dev_warn(&cfhsi->ndev->dev, + "%s: can't wait for flush complete: %d.\n", + __func__, ret); + break; + } else if (!ret) { + ret = -ETIMEDOUT; + dev_warn(&cfhsi->ndev->dev, + "%s: timeout waiting for flush complete.\n", + __func__); + break; + } + } while (1); + + cfhsi->dev->cfhsi_wake_down(cfhsi->dev); + + return ret; +} + +static int cfhsi_tx_frm(struct cfhsi_desc *desc, struct cfhsi *cfhsi) +{ + int nfrms = 0; + int pld_len = 0; + struct sk_buff *skb; + u8 *pfrm = desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ; + + skb = skb_dequeue(&cfhsi->qhead); + if (!skb) + return 0; + + /* Check if we can embed a CAIF frame. */ + if (skb->len < CFHSI_MAX_EMB_FRM_SZ) { + struct caif_payload_info *info; + int hpad = 0; + int tpad = 0; + + /* Calculate needed head alignment and tail alignment. */ + info = (struct caif_payload_info *)&skb->cb; + + hpad = 1 + PAD_POW2((info->hdr_len + 1), hsi_head_align); + tpad = PAD_POW2((skb->len + hpad), hsi_tail_align); + + /* Check if frame still fits with added alignment. */ + if ((skb->len + hpad + tpad) <= CFHSI_MAX_EMB_FRM_SZ) { + u8 *pemb = desc->emb_frm; + desc->offset = CFHSI_DESC_SHORT_SZ; + *pemb = (u8)(hpad - 1); + pemb += hpad; + + /* Update network statistics. */ + cfhsi->ndev->stats.tx_packets++; + cfhsi->ndev->stats.tx_bytes += skb->len; + + /* Copy in embedded CAIF frame. */ + skb_copy_bits(skb, 0, pemb, skb->len); + consume_skb(skb); + skb = NULL; + } + } else + /* Clear offset. */ + desc->offset = 0; + + /* Create payload CAIF frames. */ + pfrm = desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ; + while (nfrms < CFHSI_MAX_PKTS) { + struct caif_payload_info *info; + int hpad = 0; + int tpad = 0; + + if (!skb) + skb = skb_dequeue(&cfhsi->qhead); + + if (!skb) + break; + + /* Calculate needed head alignment and tail alignment. */ + info = (struct caif_payload_info *)&skb->cb; + + hpad = 1 + PAD_POW2((info->hdr_len + 1), hsi_head_align); + tpad = PAD_POW2((skb->len + hpad), hsi_tail_align); + + /* Fill in CAIF frame length in descriptor. */ + desc->cffrm_len[nfrms] = hpad + skb->len + tpad; + + /* Fill head padding information. */ + *pfrm = (u8)(hpad - 1); + pfrm += hpad; + + /* Update network statistics. */ + cfhsi->ndev->stats.tx_packets++; + cfhsi->ndev->stats.tx_bytes += skb->len; + + /* Copy in CAIF frame. */ + skb_copy_bits(skb, 0, pfrm, skb->len); + + /* Update payload length. */ + pld_len += desc->cffrm_len[nfrms]; + + /* Update frame pointer. */ + pfrm += skb->len + tpad; + consume_skb(skb); + skb = NULL; + + /* Update number of frames. */ + nfrms++; + } + + /* Unused length fields should be zero-filled (according to SPEC). */ + while (nfrms < CFHSI_MAX_PKTS) { + desc->cffrm_len[nfrms] = 0x0000; + nfrms++; + } + + /* Check if we can piggy-back another descriptor. */ + skb = skb_peek(&cfhsi->qhead); + if (skb) + desc->header |= CFHSI_PIGGY_DESC; + else + desc->header &= ~CFHSI_PIGGY_DESC; + + return CFHSI_DESC_SZ + pld_len; +} + +static void cfhsi_tx_done_work(struct work_struct *work) +{ + struct cfhsi *cfhsi = NULL; + struct cfhsi_desc *desc = NULL; + int len = 0; + int res; + + cfhsi = container_of(work, struct cfhsi, tx_done_work); + dev_dbg(&cfhsi->ndev->dev, "%s.\n", + __func__); + + if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits)) + return; + + desc = (struct cfhsi_desc *)cfhsi->tx_buf; + + do { + /* + * Send flow on if flow off has been previously signalled + * and number of packets is below low water mark. + */ + spin_lock_bh(&cfhsi->lock); + if (cfhsi->flow_off_sent && + cfhsi->qhead.qlen <= cfhsi->q_low_mark && + cfhsi->cfdev.flowctrl) { + + cfhsi->flow_off_sent = 0; + cfhsi->cfdev.flowctrl(cfhsi->ndev, ON); + } + spin_unlock_bh(&cfhsi->lock); + + /* Create HSI frame. */ + len = cfhsi_tx_frm(desc, cfhsi); + if (!len) { + cfhsi->tx_state = CFHSI_TX_STATE_IDLE; + /* Start inactivity timer. */ + mod_timer(&cfhsi->timer, + jiffies + CFHSI_INACTIVITY_TOUT); + break; + } + + /* Set up new transfer. */ + res = cfhsi->dev->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->dev); + if (WARN_ON(res < 0)) { + dev_err(&cfhsi->ndev->dev, "%s: TX error %d.\n", + __func__, res); + } + } while (res < 0); +} + +static void cfhsi_tx_done_cb(struct cfhsi_drv *drv) +{ + struct cfhsi *cfhsi; + + cfhsi = container_of(drv, struct cfhsi, drv); + dev_dbg(&cfhsi->ndev->dev, "%s.\n", + __func__); + + if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits)) + return; + + queue_work(cfhsi->wq, &cfhsi->tx_done_work); +} + +static int cfhsi_rx_desc(struct cfhsi_desc *desc, struct cfhsi *cfhsi) +{ + int xfer_sz = 0; + int nfrms = 0; + u16 *plen = NULL; + u8 *pfrm = NULL; + + if ((desc->header & ~CFHSI_PIGGY_DESC) || + (desc->offset > CFHSI_MAX_EMB_FRM_SZ)) { + dev_err(&cfhsi->ndev->dev, "%s: Invalid descriptor.\n", + __func__); + return 0; + } + + /* Check for embedded CAIF frame. */ + if (desc->offset) { + struct sk_buff *skb; + u8 *dst = NULL; + int len = 0, retries = 0; + pfrm = ((u8 *)desc) + desc->offset; + + /* Remove offset padding. */ + pfrm += *pfrm + 1; + + /* Read length of CAIF frame (little endian). */ + len = *pfrm; + len |= ((*(pfrm+1)) << 8) & 0xFF00; + len += 2; /* Add FCS fields. */ + + + /* Allocate SKB (OK even in IRQ context). */ + skb = alloc_skb(len + 1, GFP_KERNEL); + while (!skb) { + retries++; + schedule_timeout(1); + skb = alloc_skb(len + 1, GFP_KERNEL); + if (skb) { + printk(KERN_WARNING "%s: slept for %u " + "before getting memory\n", + __func__, retries); + break; + } + if (retries > HZ) { + printk(KERN_ERR "%s: slept for 1HZ and " + "did not get memory\n", + __func__); + cfhsi->ndev->stats.rx_dropped++; + goto drop_frame; + } + } + caif_assert(skb != NULL); + + dst = skb_put(skb, len); + memcpy(dst, pfrm, len); + + skb->protocol = htons(ETH_P_CAIF); + skb_reset_mac_header(skb); + skb->dev = cfhsi->ndev; + + /* + * We are called from a arch specific platform device. + * Unfortunately we don't know what context we're + * running in. + */ + if (in_interrupt()) + netif_rx(skb); + else + netif_rx_ni(skb); + + /* Update network statistics. */ + cfhsi->ndev->stats.rx_packets++; + cfhsi->ndev->stats.rx_bytes += len; + } + +drop_frame: + /* Calculate transfer length. */ + plen = desc->cffrm_len; + while (nfrms < CFHSI_MAX_PKTS && *plen) { + xfer_sz += *plen; + plen++; + nfrms++; + } + + /* Check for piggy-backed descriptor. */ + if (desc->header & CFHSI_PIGGY_DESC) + xfer_sz += CFHSI_DESC_SZ; + + if (xfer_sz % 4) { + dev_err(&cfhsi->ndev->dev, + "%s: Invalid payload len: %d, ignored.\n", + __func__, xfer_sz); + xfer_sz = 0; + } + + return xfer_sz; +} + +static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi) +{ + int rx_sz = 0; + int nfrms = 0; + u16 *plen = NULL; + u8 *pfrm = NULL; + + /* Sanity check header and offset. */ + if (WARN_ON((desc->header & ~CFHSI_PIGGY_DESC) || + (desc->offset > CFHSI_MAX_EMB_FRM_SZ))) { + dev_err(&cfhsi->ndev->dev, "%s: Invalid descriptor.\n", + __func__); + return -EINVAL; + } + + /* Set frame pointer to start of payload. */ + pfrm = desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ; + plen = desc->cffrm_len; + while (nfrms < CFHSI_MAX_PKTS && *plen) { + struct sk_buff *skb; + u8 *dst = NULL; + u8 *pcffrm = NULL; + int len = 0, retries = 0; + + if (WARN_ON(desc->cffrm_len[nfrms] > CFHSI_MAX_PAYLOAD_SZ)) { + dev_err(&cfhsi->ndev->dev, "%s: Invalid payload.\n", + __func__); + return -EINVAL; + } + + /* CAIF frame starts after head padding. */ + pcffrm = pfrm + *pfrm + 1; + + /* Read length of CAIF frame (little endian). */ + len = *pcffrm; + len |= ((*(pcffrm + 1)) << 8) & 0xFF00; + len += 2; /* Add FCS fields. */ + + /* Allocate SKB (OK even in IRQ context). */ + skb = alloc_skb(len + 1, GFP_KERNEL); + while (!skb) { + retries++; + schedule_timeout(1); + skb = alloc_skb(len + 1, GFP_KERNEL); + if (skb) { + printk(KERN_WARNING "%s: slept for %u " + "before getting memory\n", + __func__, retries); + break; + } + if (retries > HZ) { + printk(KERN_ERR "%s: slept for 1HZ " + "and did not get memory\n", + __func__); + cfhsi->ndev->stats.rx_dropped++; + goto drop_frame; + } + } + caif_assert(skb != NULL); + + dst = skb_put(skb, len); + memcpy(dst, pcffrm, len); + + skb->protocol = htons(ETH_P_CAIF); + skb_reset_mac_header(skb); + skb->dev = cfhsi->ndev; + + /* + * We're called from a platform device, + * and don't know the context we're running in. + */ + if (in_interrupt()) + netif_rx(skb); + else + netif_rx_ni(skb); + + /* Update network statistics. */ + cfhsi->ndev->stats.rx_packets++; + cfhsi->ndev->stats.rx_bytes += len; + +drop_frame: + pfrm += *plen; + rx_sz += *plen; + plen++; + nfrms++; + } + + return rx_sz; +} + +static void cfhsi_rx_done_work(struct work_struct *work) +{ + int res; + int desc_pld_len = 0; + struct cfhsi *cfhsi = NULL; + struct cfhsi_desc *desc = NULL; + + cfhsi = container_of(work, struct cfhsi, rx_done_work); + desc = (struct cfhsi_desc *)cfhsi->rx_buf; + + dev_dbg(&cfhsi->ndev->dev, "%s: Kick timer if pending.\n", + __func__); + + if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits)) + return; + + /* Update inactivity timer if pending. */ + mod_timer_pending(&cfhsi->timer, jiffies + CFHSI_INACTIVITY_TOUT); + + if (cfhsi->rx_state == CFHSI_RX_STATE_DESC) { + desc_pld_len = cfhsi_rx_desc(desc, cfhsi); + } else { + int pld_len; + + pld_len = cfhsi_rx_pld(desc, cfhsi); + + if ((pld_len > 0) && (desc->header & CFHSI_PIGGY_DESC)) { + struct cfhsi_desc *piggy_desc; + piggy_desc = (struct cfhsi_desc *) + (desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ + + pld_len); + + /* Extract piggy-backed descriptor. */ + desc_pld_len = cfhsi_rx_desc(piggy_desc, cfhsi); + + /* + * Copy needed information from the piggy-backed + * descriptor to the descriptor in the start. + */ + memcpy((u8 *)desc, (u8 *)piggy_desc, + CFHSI_DESC_SHORT_SZ); + } + } + + if (desc_pld_len) { + cfhsi->rx_state = CFHSI_RX_STATE_PAYLOAD; + cfhsi->rx_ptr = cfhsi->rx_buf + CFHSI_DESC_SZ; + cfhsi->rx_len = desc_pld_len; + } else { + cfhsi->rx_state = CFHSI_RX_STATE_DESC; + cfhsi->rx_ptr = cfhsi->rx_buf; + cfhsi->rx_len = CFHSI_DESC_SZ; + } + clear_bit(CFHSI_PENDING_RX, &cfhsi->bits); + + if (test_bit(CFHSI_AWAKE, &cfhsi->bits)) { + /* Set up new transfer. */ + dev_dbg(&cfhsi->ndev->dev, "%s: Start RX.\n", + __func__); + res = cfhsi->dev->cfhsi_rx(cfhsi->rx_ptr, cfhsi->rx_len, + cfhsi->dev); + if (WARN_ON(res < 0)) { + dev_err(&cfhsi->ndev->dev, "%s: RX error %d.\n", + __func__, res); + cfhsi->ndev->stats.rx_errors++; + cfhsi->ndev->stats.rx_dropped++; + } + } +} + +static void cfhsi_rx_done_cb(struct cfhsi_drv *drv) +{ + struct cfhsi *cfhsi; + + cfhsi = container_of(drv, struct cfhsi, drv); + dev_dbg(&cfhsi->ndev->dev, "%s.\n", + __func__); + + if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits)) + return; + + set_bit(CFHSI_PENDING_RX, &cfhsi->bits); + + if (test_and_clear_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits)) + wake_up_interruptible(&cfhsi->flush_fifo_wait); + else + queue_work(cfhsi->wq, &cfhsi->rx_done_work); +} + +static void cfhsi_wake_up(struct work_struct *work) +{ + struct cfhsi *cfhsi = NULL; + int res; + int len; + long ret; + + cfhsi = container_of(work, struct cfhsi, wake_up_work); + + if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits)) + return; + + if (unlikely(test_bit(CFHSI_AWAKE, &cfhsi->bits))) { + /* It happenes when wakeup is requested by + * both ends at the same time. */ + clear_bit(CFHSI_WAKE_UP, &cfhsi->bits); + return; + } + + /* Activate wake line. */ + cfhsi->dev->cfhsi_wake_up(cfhsi->dev); + + dev_dbg(&cfhsi->ndev->dev, "%s: Start waiting.\n", + __func__); + + /* Wait for acknowledge. */ + ret = CFHSI_WAKEUP_TOUT; + wait_event_interruptible_timeout(cfhsi->wake_up_wait, + test_bit(CFHSI_WAKE_UP_ACK, + &cfhsi->bits), ret); + if (unlikely(ret < 0)) { + /* Interrupted by signal. */ + dev_info(&cfhsi->ndev->dev, "%s: Signalled: %ld.\n", + __func__, ret); + clear_bit(CFHSI_WAKE_UP, &cfhsi->bits); + cfhsi->dev->cfhsi_wake_down(cfhsi->dev); + return; + } else if (!ret) { + /* Wakeup timeout */ + dev_err(&cfhsi->ndev->dev, "%s: Timeout.\n", + __func__); + clear_bit(CFHSI_WAKE_UP, &cfhsi->bits); + cfhsi->dev->cfhsi_wake_down(cfhsi->dev); + return; + } + dev_dbg(&cfhsi->ndev->dev, "%s: Woken.\n", + __func__); + + /* Clear power up bit. */ + set_bit(CFHSI_AWAKE, &cfhsi->bits); + clear_bit(CFHSI_WAKE_UP, &cfhsi->bits); + + /* Resume read operation. */ + if (!test_bit(CFHSI_PENDING_RX, &cfhsi->bits)) { + dev_dbg(&cfhsi->ndev->dev, "%s: Start RX.\n", + __func__); + res = cfhsi->dev->cfhsi_rx(cfhsi->rx_ptr, + cfhsi->rx_len, cfhsi->dev); + if (WARN_ON(res < 0)) { + dev_err(&cfhsi->ndev->dev, "%s: RX error %d.\n", + __func__, res); + } + } + + /* Clear power up acknowledment. */ + clear_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits); + + spin_lock_bh(&cfhsi->lock); + + /* Resume transmit if queue is not empty. */ + if (!skb_peek(&cfhsi->qhead)) { + dev_dbg(&cfhsi->ndev->dev, "%s: Peer wake, start timer.\n", + __func__); + /* Start inactivity timer. */ + mod_timer(&cfhsi->timer, + jiffies + CFHSI_INACTIVITY_TOUT); + spin_unlock_bh(&cfhsi->lock); + return; + } + + dev_dbg(&cfhsi->ndev->dev, "%s: Host wake.\n", + __func__); + + spin_unlock_bh(&cfhsi->lock); + + /* Create HSI frame. */ + len = cfhsi_tx_frm((struct cfhsi_desc *)cfhsi->tx_buf, cfhsi); + + if (likely(len > 0)) { + /* Set up new transfer. */ + res = cfhsi->dev->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->dev); + if (WARN_ON(res < 0)) { + dev_err(&cfhsi->ndev->dev, "%s: TX error %d.\n", + __func__, res); + cfhsi_abort_tx(cfhsi); + } + } else { + dev_err(&cfhsi->ndev->dev, + "%s: Failed to create HSI frame: %d.\n", + __func__, len); + } + +} + +static void cfhsi_wake_down(struct work_struct *work) +{ + long ret; + struct cfhsi *cfhsi = NULL; + size_t fifo_occupancy; + + cfhsi = container_of(work, struct cfhsi, wake_down_work); + dev_dbg(&cfhsi->ndev->dev, "%s.\n", + __func__); + + if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits)) + return; + + /* Check if there is something in FIFO. */ + if (WARN_ON(cfhsi->dev->cfhsi_fifo_occupancy(cfhsi->dev, + &fifo_occupancy))) + fifo_occupancy = 0; + + if (fifo_occupancy) { + dev_dbg(&cfhsi->ndev->dev, + "%s: %u words in RX FIFO, restart timer.\n", + __func__, (unsigned) fifo_occupancy); + spin_lock_bh(&cfhsi->lock); + mod_timer(&cfhsi->timer, + jiffies + CFHSI_INACTIVITY_TOUT); + spin_unlock_bh(&cfhsi->lock); + return; + } + + /* Cancel pending RX requests */ + cfhsi->dev->cfhsi_rx_cancel(cfhsi->dev); + + /* Deactivate wake line. */ + cfhsi->dev->cfhsi_wake_down(cfhsi->dev); + + /* Wait for acknowledge. */ + ret = CFHSI_WAKEUP_TOUT; + ret = wait_event_interruptible_timeout(cfhsi->wake_down_wait, + test_bit(CFHSI_WAKE_DOWN_ACK, + &cfhsi->bits), + ret); + if (ret < 0) { + /* Interrupted by signal. */ + dev_info(&cfhsi->ndev->dev, "%s: Signalled: %ld.\n", + __func__, ret); + return; + } else if (!ret) { + /* Timeout */ + dev_err(&cfhsi->ndev->dev, "%s: Timeout.\n", + __func__); + } + + /* Clear power down acknowledment. */ + clear_bit(CFHSI_WAKE_DOWN_ACK, &cfhsi->bits); + clear_bit(CFHSI_AWAKE, &cfhsi->bits); + + /* Check if there is something in FIFO. */ + if (WARN_ON(cfhsi->dev->cfhsi_fifo_occupancy(cfhsi->dev, + &fifo_occupancy))) + fifo_occupancy = 0; + + if (fifo_occupancy) { + dev_dbg(&cfhsi->ndev->dev, + "%s: %u words in RX FIFO, wakeup forced.\n", + __func__, (unsigned) fifo_occupancy); + if (!test_and_set_bit(CFHSI_WAKE_UP, &cfhsi->bits)) + queue_work(cfhsi->wq, &cfhsi->wake_up_work); + } else + dev_dbg(&cfhsi->ndev->dev, "%s: Done.\n", + __func__); +} + +static void cfhsi_wake_up_cb(struct cfhsi_drv *drv) +{ + struct cfhsi *cfhsi = NULL; + + cfhsi = container_of(drv, struct cfhsi, drv); + dev_dbg(&cfhsi->ndev->dev, "%s.\n", + __func__); + + set_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits); + wake_up_interruptible(&cfhsi->wake_up_wait); + + if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits)) + return; + + /* Schedule wake up work queue if the peer initiates. */ + if (!test_and_set_bit(CFHSI_WAKE_UP, &cfhsi->bits)) + queue_work(cfhsi->wq, &cfhsi->wake_up_work); +} + +static void cfhsi_wake_down_cb(struct cfhsi_drv *drv) +{ + struct cfhsi *cfhsi = NULL; + + cfhsi = container_of(drv, struct cfhsi, drv); + dev_dbg(&cfhsi->ndev->dev, "%s.\n", + __func__); + + /* Initiating low power is only permitted by the host (us). */ + set_bit(CFHSI_WAKE_DOWN_ACK, &cfhsi->bits); + wake_up_interruptible(&cfhsi->wake_down_wait); +} + +static int cfhsi_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct cfhsi *cfhsi = NULL; + int start_xfer = 0; + int timer_active; + + if (!dev) + return -EINVAL; + + cfhsi = netdev_priv(dev); + + spin_lock_bh(&cfhsi->lock); + + skb_queue_tail(&cfhsi->qhead, skb); + + /* Sanity check; xmit should not be called after unregister_netdev */ + if (WARN_ON(test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))) { + spin_unlock_bh(&cfhsi->lock); + cfhsi_abort_tx(cfhsi); + return -EINVAL; + } + + /* Send flow off if number of packets is above high water mark. */ + if (!cfhsi->flow_off_sent && + cfhsi->qhead.qlen > cfhsi->q_high_mark && + cfhsi->cfdev.flowctrl) { + cfhsi->flow_off_sent = 1; + cfhsi->cfdev.flowctrl(cfhsi->ndev, OFF); + } + + if (cfhsi->tx_state == CFHSI_TX_STATE_IDLE) { + cfhsi->tx_state = CFHSI_TX_STATE_XFER; + start_xfer = 1; + } + + spin_unlock_bh(&cfhsi->lock); + + if (!start_xfer) + return 0; + + /* Delete inactivity timer if started. */ +#ifdef CONFIG_SMP + timer_active = del_timer_sync(&cfhsi->timer); +#else + timer_active = del_timer(&cfhsi->timer); +#endif /* CONFIG_SMP */ + + if (timer_active) { + struct cfhsi_desc *desc = (struct cfhsi_desc *)cfhsi->tx_buf; + int len; + int res; + + /* Create HSI frame. */ + len = cfhsi_tx_frm(desc, cfhsi); + BUG_ON(!len); + + /* Set up new transfer. */ + res = cfhsi->dev->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->dev); + if (WARN_ON(res < 0)) { + dev_err(&cfhsi->ndev->dev, "%s: TX error %d.\n", + __func__, res); + cfhsi_abort_tx(cfhsi); + } + } else { + /* Schedule wake up work queue if the we initiate. */ + if (!test_and_set_bit(CFHSI_WAKE_UP, &cfhsi->bits)) + queue_work(cfhsi->wq, &cfhsi->wake_up_work); + } + + return 0; +} + +static int cfhsi_open(struct net_device *dev) +{ + netif_wake_queue(dev); + + return 0; +} + +static int cfhsi_close(struct net_device *dev) +{ + netif_stop_queue(dev); + + return 0; +} + +static const struct net_device_ops cfhsi_ops = { + .ndo_open = cfhsi_open, + .ndo_stop = cfhsi_close, + .ndo_start_xmit = cfhsi_xmit +}; + +static void cfhsi_setup(struct net_device *dev) +{ + struct cfhsi *cfhsi = netdev_priv(dev); + dev->features = 0; + dev->netdev_ops = &cfhsi_ops; + dev->type = ARPHRD_CAIF; + dev->flags = IFF_POINTOPOINT | IFF_NOARP; + dev->mtu = CFHSI_MAX_PAYLOAD_SZ; + dev->tx_queue_len = 0; + dev->destructor = free_netdev; + skb_queue_head_init(&cfhsi->qhead); + cfhsi->cfdev.link_select = CAIF_LINK_HIGH_BANDW; + cfhsi->cfdev.use_frag = false; + cfhsi->cfdev.use_stx = false; + cfhsi->cfdev.use_fcs = false; + cfhsi->ndev = dev; +} + +int cfhsi_probe(struct platform_device *pdev) +{ + struct cfhsi *cfhsi = NULL; + struct net_device *ndev; + struct cfhsi_dev *dev; + int res; + + ndev = alloc_netdev(sizeof(struct cfhsi), "cfhsi%d", cfhsi_setup); + if (!ndev) { + dev_err(&pdev->dev, "%s: alloc_netdev failed.\n", + __func__); + return -ENODEV; + } + + cfhsi = netdev_priv(ndev); + cfhsi->ndev = ndev; + cfhsi->pdev = pdev; + + /* Initialize state vaiables. */ + cfhsi->tx_state = CFHSI_TX_STATE_IDLE; + cfhsi->rx_state = CFHSI_RX_STATE_DESC; + + /* Set flow info */ + cfhsi->flow_off_sent = 0; + cfhsi->q_low_mark = LOW_WATER_MARK; + cfhsi->q_high_mark = HIGH_WATER_MARK; + + /* Assign the HSI device. */ + dev = (struct cfhsi_dev *)pdev->dev.platform_data; + cfhsi->dev = dev; + + /* Assign the driver to this HSI device. */ + dev->drv = &cfhsi->drv; + + /* + * Allocate a TX buffer with the size of a HSI packet descriptors + * and the necessary room for CAIF payload frames. + */ + cfhsi->tx_buf = kzalloc(CFHSI_BUF_SZ_TX, GFP_KERNEL); + if (!cfhsi->tx_buf) { + dev_err(&ndev->dev, "%s: Failed to allocate TX buffer.\n", + __func__); + res = -ENODEV; + goto err_alloc_tx; + } + + /* + * Allocate a RX buffer with the size of two HSI packet descriptors and + * the necessary room for CAIF payload frames. + */ + cfhsi->rx_buf = kzalloc(CFHSI_BUF_SZ_RX, GFP_KERNEL); + if (!cfhsi->rx_buf) { + dev_err(&ndev->dev, "%s: Failed to allocate RX buffer.\n", + __func__); + res = -ENODEV; + goto err_alloc_rx; + } + + /* Initialize recieve vaiables. */ + cfhsi->rx_ptr = cfhsi->rx_buf; + cfhsi->rx_len = CFHSI_DESC_SZ; + + /* Initialize spin locks. */ + spin_lock_init(&cfhsi->lock); + + /* Set up the driver. */ + cfhsi->drv.tx_done_cb = cfhsi_tx_done_cb; + cfhsi->drv.rx_done_cb = cfhsi_rx_done_cb; + + /* Initialize the work queues. */ + INIT_WORK(&cfhsi->wake_up_work, cfhsi_wake_up); + INIT_WORK(&cfhsi->wake_down_work, cfhsi_wake_down); + INIT_WORK(&cfhsi->rx_done_work, cfhsi_rx_done_work); + INIT_WORK(&cfhsi->tx_done_work, cfhsi_tx_done_work); + + /* Clear all bit fields. */ + clear_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits); + clear_bit(CFHSI_WAKE_DOWN_ACK, &cfhsi->bits); + clear_bit(CFHSI_WAKE_UP, &cfhsi->bits); + clear_bit(CFHSI_AWAKE, &cfhsi->bits); + clear_bit(CFHSI_PENDING_RX, &cfhsi->bits); + + /* Create work thread. */ + cfhsi->wq = create_singlethread_workqueue(pdev->name); + if (!cfhsi->wq) { + dev_err(&ndev->dev, "%s: Failed to create work queue.\n", + __func__); + res = -ENODEV; + goto err_create_wq; + } + + /* Initialize wait queues. */ + init_waitqueue_head(&cfhsi->wake_up_wait); + init_waitqueue_head(&cfhsi->wake_down_wait); + init_waitqueue_head(&cfhsi->flush_fifo_wait); + + /* Setup the inactivity timer. */ + init_timer(&cfhsi->timer); + cfhsi->timer.data = (unsigned long)cfhsi; + cfhsi->timer.function = cfhsi_inactivity_tout; + + /* Add CAIF HSI device to list. */ + spin_lock(&cfhsi_list_lock); + list_add_tail(&cfhsi->list, &cfhsi_list); + spin_unlock(&cfhsi_list_lock); + + /* Activate HSI interface. */ + res = cfhsi->dev->cfhsi_up(cfhsi->dev); + if (res) { + dev_err(&cfhsi->ndev->dev, + "%s: can't activate HSI interface: %d.\n", + __func__, res); + goto err_activate; + } + + /* Flush FIFO */ + res = cfhsi_flush_fifo(cfhsi); + if (res) { + dev_err(&ndev->dev, "%s: Can't flush FIFO: %d.\n", + __func__, res); + goto err_net_reg; + } + + cfhsi->drv.wake_up_cb = cfhsi_wake_up_cb; + cfhsi->drv.wake_down_cb = cfhsi_wake_down_cb; + + /* Register network device. */ + res = register_netdev(ndev); + if (res) { + dev_err(&ndev->dev, "%s: Registration error: %d.\n", + __func__, res); + goto err_net_reg; + } + + netif_stop_queue(ndev); + + return res; + + err_net_reg: + cfhsi->dev->cfhsi_down(cfhsi->dev); + err_activate: + destroy_workqueue(cfhsi->wq); + err_create_wq: + kfree(cfhsi->rx_buf); + err_alloc_rx: + kfree(cfhsi->tx_buf); + err_alloc_tx: + free_netdev(ndev); + + return res; +} + +static void cfhsi_shutdown(struct cfhsi *cfhsi, bool remove_platform_dev) +{ + u8 *tx_buf, *rx_buf; + + /* Stop TXing */ + netif_tx_stop_all_queues(cfhsi->ndev); + + /* going to shutdown driver */ + set_bit(CFHSI_SHUTDOWN, &cfhsi->bits); + + if (remove_platform_dev) { + /* Flush workqueue */ + flush_workqueue(cfhsi->wq); + + /* Notify device. */ + platform_device_unregister(cfhsi->pdev); + } + + /* Flush workqueue */ + flush_workqueue(cfhsi->wq); + + /* Delete timer if pending */ +#ifdef CONFIG_SMP + del_timer_sync(&cfhsi->timer); +#else + del_timer(&cfhsi->timer); +#endif /* CONFIG_SMP */ + + /* Cancel pending RX request (if any) */ + cfhsi->dev->cfhsi_rx_cancel(cfhsi->dev); + + /* Flush again and destroy workqueue */ + destroy_workqueue(cfhsi->wq); + + /* Store bufferes: will be freed later. */ + tx_buf = cfhsi->tx_buf; + rx_buf = cfhsi->rx_buf; + + /* Flush transmit queues. */ + cfhsi_abort_tx(cfhsi); + + /* Deactivate interface */ + cfhsi->dev->cfhsi_down(cfhsi->dev); + + /* Finally unregister the network device. */ + unregister_netdev(cfhsi->ndev); + + /* Free buffers. */ + kfree(tx_buf); + kfree(rx_buf); +} + +int cfhsi_remove(struct platform_device *pdev) +{ + struct list_head *list_node; + struct list_head *n; + struct cfhsi *cfhsi = NULL; + struct cfhsi_dev *dev; + + dev = (struct cfhsi_dev *)pdev->dev.platform_data; + spin_lock(&cfhsi_list_lock); + list_for_each_safe(list_node, n, &cfhsi_list) { + cfhsi = list_entry(list_node, struct cfhsi, list); + /* Find the corresponding device. */ + if (cfhsi->dev == dev) { + /* Remove from list. */ + list_del(list_node); + spin_unlock(&cfhsi_list_lock); + + /* Shutdown driver. */ + cfhsi_shutdown(cfhsi, false); + + return 0; + } + } + spin_unlock(&cfhsi_list_lock); + return -ENODEV; +} + +struct platform_driver cfhsi_plat_drv = { + .probe = cfhsi_probe, + .remove = cfhsi_remove, + .driver = { + .name = "cfhsi", + .owner = THIS_MODULE, + }, +}; + +static void __exit cfhsi_exit_module(void) +{ + struct list_head *list_node; + struct list_head *n; + struct cfhsi *cfhsi = NULL; + + spin_lock(&cfhsi_list_lock); + list_for_each_safe(list_node, n, &cfhsi_list) { + cfhsi = list_entry(list_node, struct cfhsi, list); + + /* Remove from list. */ + list_del(list_node); + spin_unlock(&cfhsi_list_lock); + + /* Shutdown driver. */ + cfhsi_shutdown(cfhsi, true); + + spin_lock(&cfhsi_list_lock); + } + spin_unlock(&cfhsi_list_lock); + + /* Unregister platform driver. */ + platform_driver_unregister(&cfhsi_plat_drv); +} + +static int __init cfhsi_init_module(void) +{ + int result; + + /* Initialize spin lock. */ + spin_lock_init(&cfhsi_list_lock); + + /* Register platform driver. */ + result = platform_driver_register(&cfhsi_plat_drv); + if (result) { + printk(KERN_ERR "Could not register platform HSI driver: %d.\n", + result); + goto err_dev_register; + } + + return result; + + err_dev_register: + return result; +} + +module_init(cfhsi_init_module); +module_exit(cfhsi_exit_module); diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c index 3df0c0f8b8bf..1cd0b59d13cb 100644 --- a/drivers/net/caif/caif_serial.c +++ b/drivers/net/caif/caif_serial.c @@ -4,6 +4,7 @@ * License terms: GNU General Public License (GPL) version 2 */ +#include <linux/hardirq.h> #include <linux/init.h> #include <linux/version.h> #include <linux/module.h> diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 1d699e3df547..bbf06f77ee8c 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -58,9 +58,10 @@ config CAN_CALC_BITTIMING config CAN_AT91 tristate "Atmel AT91 onchip CAN controller" - depends on CAN_DEV && ARCH_AT91SAM9263 + depends on CAN_DEV && (ARCH_AT91SAM9263 || ARCH_AT91SAM9X5) ---help--- - This is a driver for the SoC CAN controller in Atmel's AT91SAM9263. + This is a driver for the SoC CAN controller in Atmel's AT91SAM9263 + and AT91SAM9X5 processors. config CAN_TI_HECC depends on CAN_DEV && ARCH_OMAP3 diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 74efb5a2ad41..121ede663e20 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -41,32 +41,7 @@ #include <mach/board.h> -#define AT91_NAPI_WEIGHT 11 - -/* - * RX/TX Mailbox split - * don't dare to touch - */ -#define AT91_MB_RX_NUM 11 -#define AT91_MB_TX_SHIFT 2 - -#define AT91_MB_RX_FIRST 1 -#define AT91_MB_RX_LAST (AT91_MB_RX_FIRST + AT91_MB_RX_NUM - 1) - -#define AT91_MB_RX_MASK(i) ((1 << (i)) - 1) -#define AT91_MB_RX_SPLIT 8 -#define AT91_MB_RX_LOW_LAST (AT91_MB_RX_SPLIT - 1) -#define AT91_MB_RX_LOW_MASK (AT91_MB_RX_MASK(AT91_MB_RX_SPLIT) & \ - ~AT91_MB_RX_MASK(AT91_MB_RX_FIRST)) - -#define AT91_MB_TX_NUM (1 << AT91_MB_TX_SHIFT) -#define AT91_MB_TX_FIRST (AT91_MB_RX_LAST + 1) -#define AT91_MB_TX_LAST (AT91_MB_TX_FIRST + AT91_MB_TX_NUM - 1) - -#define AT91_NEXT_PRIO_SHIFT (AT91_MB_TX_SHIFT) -#define AT91_NEXT_PRIO_MASK (0xf << AT91_MB_TX_SHIFT) -#define AT91_NEXT_MB_MASK (AT91_MB_TX_NUM - 1) -#define AT91_NEXT_MASK ((AT91_MB_TX_NUM - 1) | AT91_NEXT_PRIO_MASK) +#define AT91_MB_MASK(i) ((1 << (i)) - 1) /* Common registers */ enum at91_reg { @@ -128,12 +103,6 @@ enum at91_mb_mode { }; /* Interrupt mask bits */ -#define AT91_IRQ_MB_RX ((1 << (AT91_MB_RX_LAST + 1)) \ - - (1 << AT91_MB_RX_FIRST)) -#define AT91_IRQ_MB_TX ((1 << (AT91_MB_TX_LAST + 1)) \ - - (1 << AT91_MB_TX_FIRST)) -#define AT91_IRQ_MB_ALL (AT91_IRQ_MB_RX | AT91_IRQ_MB_TX) - #define AT91_IRQ_ERRA (1 << 16) #define AT91_IRQ_WARN (1 << 17) #define AT91_IRQ_ERRP (1 << 18) @@ -156,22 +125,51 @@ enum at91_mb_mode { #define AT91_IRQ_ALL (0x1fffffff) +enum at91_devtype { + AT91_DEVTYPE_SAM9263, + AT91_DEVTYPE_SAM9X5, +}; + +struct at91_devtype_data { + unsigned int rx_first; + unsigned int rx_split; + unsigned int rx_last; + unsigned int tx_shift; + enum at91_devtype type; +}; + struct at91_priv { - struct can_priv can; /* must be the first member! */ - struct net_device *dev; - struct napi_struct napi; + struct can_priv can; /* must be the first member! */ + struct net_device *dev; + struct napi_struct napi; - void __iomem *reg_base; + void __iomem *reg_base; - u32 reg_sr; - unsigned int tx_next; - unsigned int tx_echo; - unsigned int rx_next; + u32 reg_sr; + unsigned int tx_next; + unsigned int tx_echo; + unsigned int rx_next; + struct at91_devtype_data devtype_data; - struct clk *clk; - struct at91_can_data *pdata; + struct clk *clk; + struct at91_can_data *pdata; - canid_t mb0_id; + canid_t mb0_id; +}; + +static const struct at91_devtype_data at91_devtype_data[] __devinitconst = { + [AT91_DEVTYPE_SAM9263] = { + .rx_first = 1, + .rx_split = 8, + .rx_last = 11, + .tx_shift = 2, + }, + [AT91_DEVTYPE_SAM9X5] = { + .rx_first = 0, + .rx_split = 4, + .rx_last = 5, + .tx_shift = 1, + }, }; static struct can_bittiming_const at91_bittiming_const = { @@ -186,19 +184,111 @@ static struct can_bittiming_const at91_bittiming_const = { .brp_inc = 1, }; -static inline int get_tx_next_mb(const struct at91_priv *priv) +#define AT91_IS(_model) \ +static inline int at91_is_sam##_model(const struct at91_priv *priv) \ +{ \ + return priv->devtype_data.type == AT91_DEVTYPE_SAM##_model; \ +} + +AT91_IS(9263); +AT91_IS(9X5); + +static inline unsigned int get_mb_rx_first(const struct at91_priv *priv) +{ + return priv->devtype_data.rx_first; +} + +static inline unsigned int get_mb_rx_last(const struct at91_priv *priv) +{ + return priv->devtype_data.rx_last; +} + +static inline unsigned int get_mb_rx_split(const struct at91_priv *priv) +{ + return priv->devtype_data.rx_split; +} + +static inline unsigned int get_mb_rx_num(const struct at91_priv *priv) +{ + return get_mb_rx_last(priv) - get_mb_rx_first(priv) + 1; +} + +static inline unsigned int get_mb_rx_low_last(const struct at91_priv *priv) +{ + return get_mb_rx_split(priv) - 1; +} + +static inline unsigned int get_mb_rx_low_mask(const struct at91_priv *priv) +{ + return AT91_MB_MASK(get_mb_rx_split(priv)) & + ~AT91_MB_MASK(get_mb_rx_first(priv)); +} + +static inline unsigned int get_mb_tx_shift(const struct at91_priv *priv) +{ + return priv->devtype_data.tx_shift; +} + +static inline unsigned int get_mb_tx_num(const struct at91_priv *priv) +{ + return 1 << get_mb_tx_shift(priv); +} + +static inline unsigned int get_mb_tx_first(const struct at91_priv *priv) +{ + return get_mb_rx_last(priv) + 1; +} + +static inline unsigned int get_mb_tx_last(const struct at91_priv *priv) +{ + return get_mb_tx_first(priv) + get_mb_tx_num(priv) - 1; +} + +static inline unsigned int get_next_prio_shift(const struct at91_priv *priv) +{ + return get_mb_tx_shift(priv); +} + +static inline unsigned int get_next_prio_mask(const struct at91_priv *priv) +{ + return 0xf << get_mb_tx_shift(priv); +} + +static inline unsigned int get_next_mb_mask(const struct at91_priv *priv) +{ + return AT91_MB_MASK(get_mb_tx_shift(priv)); +} + +static inline unsigned int get_next_mask(const struct at91_priv *priv) +{ + return get_next_mb_mask(priv) | get_next_prio_mask(priv); +} + +static inline unsigned int get_irq_mb_rx(const struct at91_priv *priv) { - return (priv->tx_next & AT91_NEXT_MB_MASK) + AT91_MB_TX_FIRST; + return AT91_MB_MASK(get_mb_rx_last(priv) + 1) & + ~AT91_MB_MASK(get_mb_rx_first(priv)); } -static inline int get_tx_next_prio(const struct at91_priv *priv) +static inline unsigned int get_irq_mb_tx(const struct at91_priv *priv) { - return (priv->tx_next >> AT91_NEXT_PRIO_SHIFT) & 0xf; + return AT91_MB_MASK(get_mb_tx_last(priv) + 1) & + ~AT91_MB_MASK(get_mb_tx_first(priv)); } -static inline int get_tx_echo_mb(const struct at91_priv *priv) +static inline unsigned int get_tx_next_mb(const struct at91_priv *priv) { - return (priv->tx_echo & AT91_NEXT_MB_MASK) + AT91_MB_TX_FIRST; + return (priv->tx_next & get_next_mb_mask(priv)) + get_mb_tx_first(priv); +} + +static inline unsigned int get_tx_next_prio(const struct at91_priv *priv) +{ + return (priv->tx_next >> get_next_prio_shift(priv)) & 0xf; +} + +static inline unsigned int get_tx_echo_mb(const struct at91_priv *priv) +{ + return (priv->tx_echo & get_next_mb_mask(priv)) + get_mb_tx_first(priv); } static inline u32 at91_read(const struct at91_priv *priv, enum at91_reg reg) @@ -259,29 +349,29 @@ static void at91_setup_mailboxes(struct net_device *dev) * overflow. */ reg_mid = at91_can_id_to_reg_mid(priv->mb0_id); - for (i = 0; i < AT91_MB_RX_FIRST; i++) { + for (i = 0; i < get_mb_rx_first(priv); i++) { set_mb_mode(priv, i, AT91_MB_MODE_DISABLED); at91_write(priv, AT91_MID(i), reg_mid); at91_write(priv, AT91_MCR(i), 0x0); /* clear dlc */ } - for (i = AT91_MB_RX_FIRST; i < AT91_MB_RX_LAST; i++) + for (i = get_mb_rx_first(priv); i < get_mb_rx_last(priv); i++) set_mb_mode(priv, i, AT91_MB_MODE_RX); - set_mb_mode(priv, AT91_MB_RX_LAST, AT91_MB_MODE_RX_OVRWR); + set_mb_mode(priv, get_mb_rx_last(priv), AT91_MB_MODE_RX_OVRWR); /* reset acceptance mask and id register */ - for (i = AT91_MB_RX_FIRST; i <= AT91_MB_RX_LAST; i++) { - at91_write(priv, AT91_MAM(i), 0x0 ); + for (i = get_mb_rx_first(priv); i <= get_mb_rx_last(priv); i++) { + at91_write(priv, AT91_MAM(i), 0x0); at91_write(priv, AT91_MID(i), AT91_MID_MIDE); } /* The last 4 mailboxes are used for transmitting. */ - for (i = AT91_MB_TX_FIRST; i <= AT91_MB_TX_LAST; i++) + for (i = get_mb_tx_first(priv); i <= get_mb_tx_last(priv); i++) set_mb_mode_prio(priv, i, AT91_MB_MODE_TX, 0); /* Reset tx and rx helper pointers */ priv->tx_next = priv->tx_echo = 0; - priv->rx_next = AT91_MB_RX_FIRST; + priv->rx_next = get_mb_rx_first(priv); } static int at91_set_bittiming(struct net_device *dev) @@ -336,7 +426,7 @@ static void at91_chip_start(struct net_device *dev) priv->can.state = CAN_STATE_ERROR_ACTIVE; /* Enable interrupts */ - reg_ier = AT91_IRQ_MB_RX | AT91_IRQ_ERRP | AT91_IRQ_ERR_FRAME; + reg_ier = get_irq_mb_rx(priv) | AT91_IRQ_ERRP | AT91_IRQ_ERR_FRAME; at91_write(priv, AT91_IDR, AT91_IRQ_ALL); at91_write(priv, AT91_IER, reg_ier); } @@ -375,8 +465,8 @@ static void at91_chip_stop(struct net_device *dev, enum can_state state) * mailbox, but without the offset AT91_MB_TX_FIRST. The lower bits * encode the mailbox number, the upper 4 bits the mailbox priority: * - * priv->tx_next = (prio << AT91_NEXT_PRIO_SHIFT) || - * (mb - AT91_MB_TX_FIRST); + * priv->tx_next = (prio << get_next_prio_shift(priv)) | + * (mb - get_mb_tx_first(priv)); * */ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev) @@ -417,7 +507,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev) stats->tx_bytes += cf->can_dlc; /* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */ - can_put_echo_skb(skb, dev, mb - AT91_MB_TX_FIRST); + can_put_echo_skb(skb, dev, mb - get_mb_tx_first(priv)); /* * we have to stop the queue and deliver all messages in case @@ -430,7 +520,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev) priv->tx_next++; if (!(at91_read(priv, AT91_MSR(get_tx_next_mb(priv))) & AT91_MSR_MRDY) || - (priv->tx_next & AT91_NEXT_MASK) == 0) + (priv->tx_next & get_next_mask(priv)) == 0) netif_stop_queue(dev); /* Enable interrupt for this mailbox */ @@ -447,7 +537,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev) */ static inline void at91_activate_rx_low(const struct at91_priv *priv) { - u32 mask = AT91_MB_RX_LOW_MASK; + u32 mask = get_mb_rx_low_mask(priv); at91_write(priv, AT91_TCR, mask); } @@ -513,17 +603,19 @@ static void at91_read_mb(struct net_device *dev, unsigned int mb, cf->can_id = (reg_mid >> 18) & CAN_SFF_MASK; reg_msr = at91_read(priv, AT91_MSR(mb)); - if (reg_msr & AT91_MSR_MRTR) - cf->can_id |= CAN_RTR_FLAG; cf->can_dlc = get_can_dlc((reg_msr >> 16) & 0xf); - *(u32 *)(cf->data + 0) = at91_read(priv, AT91_MDL(mb)); - *(u32 *)(cf->data + 4) = at91_read(priv, AT91_MDH(mb)); + if (reg_msr & AT91_MSR_MRTR) + cf->can_id |= CAN_RTR_FLAG; + else { + *(u32 *)(cf->data + 0) = at91_read(priv, AT91_MDL(mb)); + *(u32 *)(cf->data + 4) = at91_read(priv, AT91_MDH(mb)); + } /* allow RX of extended frames */ at91_write(priv, AT91_MID(mb), AT91_MID_MIDE); - if (unlikely(mb == AT91_MB_RX_LAST && reg_msr & AT91_MSR_MMI)) + if (unlikely(mb == get_mb_rx_last(priv) && reg_msr & AT91_MSR_MMI)) at91_rx_overflow_err(dev); } @@ -561,8 +653,9 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb) * * Theory of Operation: * - * 11 of the 16 mailboxes on the chip are reserved for RX. we split - * them into 2 groups. The lower group holds 7 and upper 4 mailboxes. + * About 3/4 of the mailboxes (get_mb_rx_first()...get_mb_rx_last()) + * on the chip are reserved for RX. We split them into 2 groups. The + * lower group ranges from get_mb_rx_first() to get_mb_rx_low_last(). * * Like it or not, but the chip always saves a received CAN message * into the first free mailbox it finds (starting with the @@ -610,23 +703,23 @@ static int at91_poll_rx(struct net_device *dev, int quota) unsigned int mb; int received = 0; - if (priv->rx_next > AT91_MB_RX_LOW_LAST && - reg_sr & AT91_MB_RX_LOW_MASK) + if (priv->rx_next > get_mb_rx_low_last(priv) && + reg_sr & get_mb_rx_low_mask(priv)) netdev_info(dev, "order of incoming frames cannot be guaranteed\n"); again: - for (mb = find_next_bit(addr, AT91_MB_RX_LAST + 1, priv->rx_next); - mb < AT91_MB_RX_LAST + 1 && quota > 0; + for (mb = find_next_bit(addr, get_mb_tx_first(priv), priv->rx_next); + mb < get_mb_tx_first(priv) && quota > 0; reg_sr = at91_read(priv, AT91_SR), - mb = find_next_bit(addr, AT91_MB_RX_LAST + 1, ++priv->rx_next)) { + mb = find_next_bit(addr, get_mb_tx_first(priv), ++priv->rx_next)) { at91_read_msg(dev, mb); /* reactivate mailboxes */ - if (mb == AT91_MB_RX_LOW_LAST) + if (mb == get_mb_rx_low_last(priv)) /* all lower mailboxed, if just finished it */ at91_activate_rx_low(priv); - else if (mb > AT91_MB_RX_LOW_LAST) + else if (mb > get_mb_rx_low_last(priv)) /* only the mailbox we read */ at91_activate_rx_mb(priv, mb); @@ -635,9 +728,9 @@ static int at91_poll_rx(struct net_device *dev, int quota) } /* upper group completed, look again in lower */ - if (priv->rx_next > AT91_MB_RX_LOW_LAST && - quota > 0 && mb > AT91_MB_RX_LAST) { - priv->rx_next = AT91_MB_RX_FIRST; + if (priv->rx_next > get_mb_rx_low_last(priv) && + quota > 0 && mb > get_mb_rx_last(priv)) { + priv->rx_next = get_mb_rx_first(priv); goto again; } @@ -720,7 +813,7 @@ static int at91_poll(struct napi_struct *napi, int quota) u32 reg_sr = at91_read(priv, AT91_SR); int work_done = 0; - if (reg_sr & AT91_IRQ_MB_RX) + if (reg_sr & get_irq_mb_rx(priv)) work_done += at91_poll_rx(dev, quota - work_done); /* @@ -734,7 +827,7 @@ static int at91_poll(struct napi_struct *napi, int quota) if (work_done < quota) { /* enable IRQs for frame errors and all mailboxes >= rx_next */ u32 reg_ier = AT91_IRQ_ERR_FRAME; - reg_ier |= AT91_IRQ_MB_RX & ~AT91_MB_RX_MASK(priv->rx_next); + reg_ier |= get_irq_mb_rx(priv) & ~AT91_MB_MASK(priv->rx_next); napi_complete(napi); at91_write(priv, AT91_IER, reg_ier); @@ -783,7 +876,7 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr) if (likely(reg_msr & AT91_MSR_MRDY && ~reg_msr & AT91_MSR_MABT)) { /* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */ - can_get_echo_skb(dev, mb - AT91_MB_TX_FIRST); + can_get_echo_skb(dev, mb - get_mb_tx_first(priv)); dev->stats.tx_packets++; } } @@ -793,8 +886,8 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr) * we get a TX int for the last can frame directly before a * wrap around. */ - if ((priv->tx_next & AT91_NEXT_MASK) != 0 || - (priv->tx_echo & AT91_NEXT_MASK) == 0) + if ((priv->tx_next & get_next_mask(priv)) != 0 || + (priv->tx_echo & get_next_mask(priv)) == 0) netif_wake_queue(dev); } @@ -906,6 +999,29 @@ static void at91_irq_err_state(struct net_device *dev, at91_write(priv, AT91_IER, reg_ier); } +static int at91_get_state_by_bec(const struct net_device *dev, + enum can_state *state) +{ + struct can_berr_counter bec; + int err; + + err = at91_get_berr_counter(dev, &bec); + if (err) + return err; + + if (bec.txerr < 96 && bec.rxerr < 96) + *state = CAN_STATE_ERROR_ACTIVE; + else if (bec.txerr < 128 && bec.rxerr < 128) + *state = CAN_STATE_ERROR_WARNING; + else if (bec.txerr < 256 && bec.rxerr < 256) + *state = CAN_STATE_ERROR_PASSIVE; + else + *state = CAN_STATE_BUS_OFF; + + return 0; +} + + static void at91_irq_err(struct net_device *dev) { struct at91_priv *priv = netdev_priv(dev); @@ -913,21 +1029,28 @@ static void at91_irq_err(struct net_device *dev) struct can_frame *cf; enum can_state new_state; u32 reg_sr; + int err; - reg_sr = at91_read(priv, AT91_SR); - - /* we need to look at the unmasked reg_sr */ - if (unlikely(reg_sr & AT91_IRQ_BOFF)) - new_state = CAN_STATE_BUS_OFF; - else if (unlikely(reg_sr & AT91_IRQ_ERRP)) - new_state = CAN_STATE_ERROR_PASSIVE; - else if (unlikely(reg_sr & AT91_IRQ_WARN)) - new_state = CAN_STATE_ERROR_WARNING; - else if (likely(reg_sr & AT91_IRQ_ERRA)) - new_state = CAN_STATE_ERROR_ACTIVE; - else { - netdev_err(dev, "BUG! hardware in undefined state\n"); - return; + if (at91_is_sam9263(priv)) { + reg_sr = at91_read(priv, AT91_SR); + + /* we need to look at the unmasked reg_sr */ + if (unlikely(reg_sr & AT91_IRQ_BOFF)) + new_state = CAN_STATE_BUS_OFF; + else if (unlikely(reg_sr & AT91_IRQ_ERRP)) + new_state = CAN_STATE_ERROR_PASSIVE; + else if (unlikely(reg_sr & AT91_IRQ_WARN)) + new_state = CAN_STATE_ERROR_WARNING; + else if (likely(reg_sr & AT91_IRQ_ERRA)) + new_state = CAN_STATE_ERROR_ACTIVE; + else { + netdev_err(dev, "BUG! hardware in undefined state\n"); + return; + } + } else { + err = at91_get_state_by_bec(dev, &new_state); + if (err) + return; } /* state hasn't changed */ @@ -968,19 +1091,19 @@ static irqreturn_t at91_irq(int irq, void *dev_id) handled = IRQ_HANDLED; /* Receive or error interrupt? -> napi */ - if (reg_sr & (AT91_IRQ_MB_RX | AT91_IRQ_ERR_FRAME)) { + if (reg_sr & (get_irq_mb_rx(priv) | AT91_IRQ_ERR_FRAME)) { /* * The error bits are clear on read, * save for later use. */ priv->reg_sr = reg_sr; at91_write(priv, AT91_IDR, - AT91_IRQ_MB_RX | AT91_IRQ_ERR_FRAME); + get_irq_mb_rx(priv) | AT91_IRQ_ERR_FRAME); napi_schedule(&priv->napi); } /* Transmission complete interrupt */ - if (reg_sr & AT91_IRQ_MB_TX) + if (reg_sr & get_irq_mb_tx(priv)) at91_irq_tx(dev, reg_sr); at91_irq_err(dev); @@ -1123,6 +1246,8 @@ static struct attribute_group at91_sysfs_attr_group = { static int __devinit at91_can_probe(struct platform_device *pdev) { + const struct at91_devtype_data *devtype_data; + enum at91_devtype devtype; struct net_device *dev; struct at91_priv *priv; struct resource *res; @@ -1130,6 +1255,9 @@ static int __devinit at91_can_probe(struct platform_device *pdev) void __iomem *addr; int err, irq; + devtype = pdev->id_entry->driver_data; + devtype_data = &at91_devtype_data[devtype]; + clk = clk_get(&pdev->dev, "can_clk"); if (IS_ERR(clk)) { dev_err(&pdev->dev, "no clock defined\n"); @@ -1157,7 +1285,8 @@ static int __devinit at91_can_probe(struct platform_device *pdev) goto exit_release; } - dev = alloc_candev(sizeof(struct at91_priv), AT91_MB_TX_NUM); + dev = alloc_candev(sizeof(struct at91_priv), + 1 << devtype_data->tx_shift); if (!dev) { err = -ENOMEM; goto exit_iounmap; @@ -1166,7 +1295,6 @@ static int __devinit at91_can_probe(struct platform_device *pdev) dev->netdev_ops = &at91_netdev_ops; dev->irq = irq; dev->flags |= IFF_ECHO; - dev->sysfs_groups[0] = &at91_sysfs_attr_group; priv = netdev_priv(dev); priv->can.clock.freq = clk_get_rate(clk); @@ -1174,13 +1302,18 @@ static int __devinit at91_can_probe(struct platform_device *pdev) priv->can.do_set_mode = at91_set_mode; priv->can.do_get_berr_counter = at91_get_berr_counter; priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; - priv->reg_base = addr; priv->dev = dev; + priv->reg_base = addr; + priv->devtype_data = *devtype_data; + priv->devtype_data.type = devtype; priv->clk = clk; priv->pdata = pdev->dev.platform_data; priv->mb0_id = 0x7ff; - netif_napi_add(dev, &priv->napi, at91_poll, AT91_NAPI_WEIGHT); + netif_napi_add(dev, &priv->napi, at91_poll, get_mb_rx_num(priv)); + + if (at91_is_sam9263(priv)) + dev->sysfs_groups[0] = &at91_sysfs_attr_group; dev_set_drvdata(&pdev->dev, dev); SET_NETDEV_DEV(dev, &pdev->dev); @@ -1230,13 +1363,26 @@ static int __devexit at91_can_remove(struct platform_device *pdev) return 0; } +static const struct platform_device_id at91_can_id_table[] = { + { + .name = "at91_can", + .driver_data = AT91_DEVTYPE_SAM9263, + }, { + .name = "at91sam9x5_can", + .driver_data = AT91_DEVTYPE_SAM9X5, + }, { + /* sentinel */ + } +}; + static struct platform_driver at91_can_driver = { - .probe = at91_can_probe, - .remove = __devexit_p(at91_can_remove), - .driver = { - .name = KBUILD_MODNAME, - .owner = THIS_MODULE, + .probe = at91_can_probe, + .remove = __devexit_p(at91_can_remove), + .driver = { + .name = KBUILD_MODNAME, + .owner = THIS_MODULE, }, + .id_table = at91_can_id_table, }; static int __init at91_can_module_init(void) diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index d4990568baee..17678117ed69 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -923,7 +923,7 @@ static int __devinit flexcan_probe(struct platform_device *pdev) mem_size = resource_size(mem); if (!request_mem_region(mem->start, mem_size, pdev->name)) { err = -EBUSY; - goto failed_req; + goto failed_get; } base = ioremap(mem->start, mem_size); @@ -977,9 +977,8 @@ static int __devinit flexcan_probe(struct platform_device *pdev) iounmap(base); failed_map: release_mem_region(mem->start, mem_size); - failed_req: - clk_put(clk); failed_get: + clk_put(clk); failed_clock: return err; } diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c index 587fba48cdd9..f1942cab35f6 100644 --- a/drivers/net/can/janz-ican3.c +++ b/drivers/net/can/janz-ican3.c @@ -15,7 +15,6 @@ #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/platform_device.h> -#include <linux/mfd/core.h> #include <linux/netdevice.h> #include <linux/can.h> @@ -1644,7 +1643,7 @@ static int __devinit ican3_probe(struct platform_device *pdev) struct device *dev; int ret; - pdata = mfd_get_data(pdev); + pdata = pdev->dev.platform_data; if (!pdata) return -ENXIO; diff --git a/drivers/net/can/sja1000/sja1000.h b/drivers/net/can/sja1000/sja1000.h index de8e778f6832..78bd4ecac140 100644 --- a/drivers/net/can/sja1000/sja1000.h +++ b/drivers/net/can/sja1000/sja1000.h @@ -47,6 +47,7 @@ #ifndef SJA1000_DEV_H #define SJA1000_DEV_H +#include <linux/irqreturn.h> #include <linux/can/dev.h> #include <linux/can/platform/sja1000.h> diff --git a/drivers/net/can/softing/softing_cs.c b/drivers/net/can/softing/softing_cs.c index c11bb4de8630..c0e1b1eb87a9 100644 --- a/drivers/net/can/softing/softing_cs.c +++ b/drivers/net/can/softing/softing_cs.c @@ -315,7 +315,7 @@ pcmcia_failed: return ret ?: -ENODEV; } -static /*const*/ struct pcmcia_device_id softingcs_ids[] = { +static const struct pcmcia_device_id softingcs_ids[] = { /* softing */ PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0001), PCMCIA_DEVICE_MANF_CARD(0x0168, 0x0002), diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 22ce03e55b83..b414f5ae0da5 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -75,6 +75,7 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/vmalloc.h> #include <linux/ioport.h> #include <linux/pci.h> diff --git a/drivers/net/cxgb4/cxgb4_main.c b/drivers/net/cxgb4/cxgb4_main.c index 7e3cfbe89e3b..c9957b7f17b5 100644 --- a/drivers/net/cxgb4/cxgb4_main.c +++ b/drivers/net/cxgb4/cxgb4_main.c @@ -3704,7 +3704,7 @@ static int __devinit init_one(struct pci_dev *pdev, if (err) { dev_warn(&pdev->dev, "only %d net devices registered\n", i); err = 0; - }; + } if (cxgb4_debugfs_root) { adapter->debugfs_root = debugfs_create_dir(pci_name(pdev), diff --git a/drivers/net/cxgb4vf/adapter.h b/drivers/net/cxgb4vf/adapter.h index 4fd821aadc8a..6e9a8d9ef592 100644 --- a/drivers/net/cxgb4vf/adapter.h +++ b/drivers/net/cxgb4vf/adapter.h @@ -40,6 +40,7 @@ #ifndef __CXGB4VF_ADAPTER_H__ #define __CXGB4VF_ADAPTER_H__ +#include <linux/interrupt.h> #include <linux/pci.h> #include <linux/spinlock.h> #include <linux/skbuff.h> diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index 29a4f06fbfcf..dcc4a170b0f3 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -1781,8 +1781,8 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev) ndev = alloc_etherdev(sizeof(struct emac_priv)); if (!ndev) { dev_err(&pdev->dev, "error allocating net_device\n"); - clk_put(emac_clk); - return -ENOMEM; + rc = -ENOMEM; + goto free_clk; } platform_set_drvdata(pdev, ndev); @@ -1796,7 +1796,8 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev) pdata = pdev->dev.platform_data; if (!pdata) { dev_err(&pdev->dev, "no platform data\n"); - return -ENODEV; + rc = -ENODEV; + goto probe_quit; } /* MAC addr and PHY mask , RMII enable info from platform_data */ @@ -1929,8 +1930,9 @@ no_dma: iounmap(priv->remap_addr); probe_quit: - clk_put(emac_clk); free_netdev(ndev); +free_clk: + clk_put(emac_clk); return rc; } diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 17654059922d..8b0084d17c8c 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -331,18 +331,18 @@ static struct { "DE422",\ ""} -static const char* const depca_signature[] __devinitconst = DEPCA_SIGNATURE; +static char* __initdata depca_signature[] = DEPCA_SIGNATURE; enum depca_type { DEPCA, de100, de101, de200, de201, de202, de210, de212, de422, unknown }; -static const char depca_string[] = "depca"; +static char depca_string[] = "depca"; static int depca_device_remove (struct device *device); #ifdef CONFIG_EISA -static const struct eisa_device_id depca_eisa_ids[] __devinitconst = { +static struct eisa_device_id depca_eisa_ids[] = { { "DEC4220", de422 }, { "" } }; @@ -367,19 +367,19 @@ static struct eisa_driver depca_eisa_driver = { #define DE210_ID 0x628d #define DE212_ID 0x6def -static const short depca_mca_adapter_ids[] __devinitconst = { +static short depca_mca_adapter_ids[] = { DE210_ID, DE212_ID, 0x0000 }; -static const char *depca_mca_adapter_name[] = { +static char *depca_mca_adapter_name[] = { "DEC EtherWORKS MC Adapter (DE210)", "DEC EtherWORKS MC Adapter (DE212)", NULL }; -static const enum depca_type depca_mca_adapter_type[] = { +static enum depca_type depca_mca_adapter_type[] = { de210, de212, 0 @@ -541,9 +541,10 @@ static void SetMulticastFilter(struct net_device *dev); static int load_packet(struct net_device *dev, struct sk_buff *skb); static void depca_dbg_open(struct net_device *dev); -static const u_char de1xx_irq[] __devinitconst = { 2, 3, 4, 5, 7, 9, 0 }; -static const u_char de2xx_irq[] __devinitconst = { 5, 9, 10, 11, 15, 0 }; -static const u_char de422_irq[] __devinitconst = { 5, 9, 10, 11, 0 }; +static u_char de1xx_irq[] __initdata = { 2, 3, 4, 5, 7, 9, 0 }; +static u_char de2xx_irq[] __initdata = { 5, 9, 10, 11, 15, 0 }; +static u_char de422_irq[] __initdata = { 5, 9, 10, 11, 0 }; +static u_char *depca_irq; static int irq; static int io; @@ -579,7 +580,7 @@ static const struct net_device_ops depca_netdev_ops = { .ndo_validate_addr = eth_validate_addr, }; -static int __devinit depca_hw_init (struct net_device *dev, struct device *device) +static int __init depca_hw_init (struct net_device *dev, struct device *device) { struct depca_private *lp; int i, j, offset, netRAM, mem_len, status = 0; @@ -747,7 +748,6 @@ static int __devinit depca_hw_init (struct net_device *dev, struct device *devic if (dev->irq < 2) { unsigned char irqnum; unsigned long irq_mask, delay; - const u_char *depca_irq; irq_mask = probe_irq_on(); @@ -770,7 +770,6 @@ static int __devinit depca_hw_init (struct net_device *dev, struct device *devic break; default: - depca_irq = NULL; break; /* Not reached */ } @@ -1303,7 +1302,7 @@ static void SetMulticastFilter(struct net_device *dev) } } -static int __devinit depca_common_init (u_long ioaddr, struct net_device **devp) +static int __init depca_common_init (u_long ioaddr, struct net_device **devp) { int status = 0; @@ -1334,7 +1333,7 @@ static int __devinit depca_common_init (u_long ioaddr, struct net_device **devp) /* ** Microchannel bus I/O device probe */ -static int __devinit depca_mca_probe(struct device *device) +static int __init depca_mca_probe(struct device *device) { unsigned char pos[2]; unsigned char where; @@ -1458,7 +1457,7 @@ static int __devinit depca_mca_probe(struct device *device) ** ISA bus I/O device probe */ -static void __devinit depca_platform_probe (void) +static void __init depca_platform_probe (void) { int i; struct platform_device *pldev; @@ -1498,7 +1497,7 @@ static void __devinit depca_platform_probe (void) } } -static enum depca_type __devinit depca_shmem_probe (ulong *mem_start) +static enum depca_type __init depca_shmem_probe (ulong *mem_start) { u_long mem_base[] = DEPCA_RAM_BASE_ADDRESSES; enum depca_type adapter = unknown; @@ -1559,7 +1558,7 @@ static int __devinit depca_isa_probe (struct platform_device *device) */ #ifdef CONFIG_EISA -static int __devinit depca_eisa_probe (struct device *device) +static int __init depca_eisa_probe (struct device *device) { enum depca_type adapter = unknown; struct eisa_device *edev; @@ -1630,7 +1629,7 @@ static int __devexit depca_device_remove (struct device *device) ** and Boot (readb) ROM. This will also give us a clue to the network RAM ** base address. */ -static int __devinit DepcaSignature(char *name, u_long base_addr) +static int __init DepcaSignature(char *name, u_long base_addr) { u_int i, j, k; void __iomem *ptr; diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index fbaff3584bd4..863e9c459e65 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -24,6 +24,7 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/skbuff.h> #include <linux/spinlock.h> #include <linux/crc32.h> @@ -1157,9 +1158,6 @@ dm9000_open(struct net_device *dev) irqflags |= IRQF_SHARED; - if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev)) - return -EAGAIN; - /* GPIO0 on pre-activate PHY, Reg 1F is not set by reset */ iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */ mdelay(1); /* delay needs by DM9000B */ @@ -1168,6 +1166,9 @@ dm9000_open(struct net_device *dev) dm9000_reset(db); dm9000_init_dm9000(dev); + if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev)) + return -EAGAIN; + /* Init driver variable */ db->dbug_cnt = 0; diff --git a/drivers/net/dnet.c b/drivers/net/dnet.c index 8318ea06cb6d..b22691046678 100644 --- a/drivers/net/dnet.c +++ b/drivers/net/dnet.c @@ -16,6 +16,7 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/dma-mapping.h> diff --git a/drivers/net/e100.c b/drivers/net/e100.c index e336c7937f05..c1352c60c299 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -149,6 +149,8 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/hardirq.h> +#include <linux/interrupt.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/kernel.h> diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 859d0d3af6c9..cb1a3623253e 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -28,6 +28,7 @@ /* ethtool support for e1000 */ +#include <linux/interrupt.h> #include <linux/netdevice.h> #include <linux/ethtool.h> #include <linux/pci.h> diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index d9600566a1fc..888bd9cc2710 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -31,6 +31,7 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/pci.h> #include <linux/vmalloc.h> #include <linux/pagemap.h> @@ -5361,7 +5362,7 @@ static void e1000_complete_shutdown(struct pci_dev *pdev, bool sleep, #ifdef CONFIG_PCIEASPM static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state) { - pci_disable_link_state(pdev, state); + pci_disable_link_state_locked(pdev, state); } #else static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state) diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c index 94ec973b2bdc..d50a9998ae77 100644 --- a/drivers/net/e2100.c +++ b/drivers/net/e2100.c @@ -44,6 +44,7 @@ static const char version[] = #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/delay.h> #include <asm/io.h> diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index 38b351c7b979..e0d2ad181bb8 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -32,7 +32,7 @@ #define DRV_NAME "enic" #define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver" -#define DRV_VERSION "2.1.1.13" +#define DRV_VERSION "2.1.1.16" #define DRV_COPYRIGHT "Copyright 2008-2011 Cisco Systems, Inc" #define ENIC_BARS_MAX 6 @@ -74,6 +74,7 @@ struct enic { struct vnic_dev *vdev; struct timer_list notify_timer; struct work_struct reset; + struct work_struct change_mtu_work; struct msix_entry msix_entry[ENIC_INTR_MAX]; struct enic_msix_entry msix[ENIC_INTR_MAX]; u32 msg_enable; diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 2f433fbfca0c..9600f435c0fb 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -23,6 +23,7 @@ #include <linux/errno.h> #include <linux/types.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/workqueue.h> #include <linux/pci.h> #include <linux/netdevice.h> @@ -423,11 +424,18 @@ static void enic_mtu_check(struct enic *enic) if (mtu && mtu != enic->port_mtu) { enic->port_mtu = mtu; - if (mtu < netdev->mtu) - netdev_warn(netdev, - "interface MTU (%d) set higher " - "than switch port MTU (%d)\n", - netdev->mtu, mtu); + if (enic_is_dynamic(enic)) { + mtu = max_t(int, ENIC_MIN_MTU, + min_t(int, ENIC_MAX_MTU, mtu)); + if (mtu != netdev->mtu) + schedule_work(&enic->change_mtu_work); + } else { + if (mtu < netdev->mtu) + netdev_warn(netdev, + "interface MTU (%d) set higher " + "than switch port MTU (%d)\n", + netdev->mtu, mtu); + } } } @@ -1560,7 +1568,7 @@ static void enic_notify_timer_start(struct enic *enic) default: /* Using intr for notification for INTx/MSI-X */ break; - }; + } } /* rtnl lock is held, process context */ @@ -1688,6 +1696,9 @@ static int enic_change_mtu(struct net_device *netdev, int new_mtu) if (new_mtu < ENIC_MIN_MTU || new_mtu > ENIC_MAX_MTU) return -EINVAL; + if (enic_is_dynamic(enic)) + return -EOPNOTSUPP; + if (running) enic_stop(netdev); @@ -1704,6 +1715,55 @@ static int enic_change_mtu(struct net_device *netdev, int new_mtu) return 0; } +static void enic_change_mtu_work(struct work_struct *work) +{ + struct enic *enic = container_of(work, struct enic, change_mtu_work); + struct net_device *netdev = enic->netdev; + int new_mtu = vnic_dev_mtu(enic->vdev); + int err; + unsigned int i; + + new_mtu = max_t(int, ENIC_MIN_MTU, min_t(int, ENIC_MAX_MTU, new_mtu)); + + rtnl_lock(); + + /* Stop RQ */ + del_timer_sync(&enic->notify_timer); + + for (i = 0; i < enic->rq_count; i++) + napi_disable(&enic->napi[i]); + + vnic_intr_mask(&enic->intr[0]); + enic_synchronize_irqs(enic); + err = vnic_rq_disable(&enic->rq[0]); + if (err) { + netdev_err(netdev, "Unable to disable RQ.\n"); + return; + } + vnic_rq_clean(&enic->rq[0], enic_free_rq_buf); + vnic_cq_clean(&enic->cq[0]); + vnic_intr_clean(&enic->intr[0]); + + /* Fill RQ with new_mtu-sized buffers */ + netdev->mtu = new_mtu; + vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf); + /* Need at least one buffer on ring to get going */ + if (vnic_rq_desc_used(&enic->rq[0]) == 0) { + netdev_err(netdev, "Unable to alloc receive buffers.\n"); + return; + } + + /* Start RQ */ + vnic_rq_enable(&enic->rq[0]); + napi_enable(&enic->napi[0]); + vnic_intr_unmask(&enic->intr[0]); + enic_notify_timer_start(enic); + + rtnl_unlock(); + + netdev_info(netdev, "interface MTU set as %d\n", netdev->mtu); +} + #ifdef CONFIG_NET_POLL_CONTROLLER static void enic_poll_controller(struct net_device *netdev) { @@ -2345,6 +2405,7 @@ static int __devinit enic_probe(struct pci_dev *pdev, enic->notify_timer.data = (unsigned long)enic; INIT_WORK(&enic->reset, enic_reset); + INIT_WORK(&enic->change_mtu_work, enic_change_mtu_work); for (i = 0; i < enic->wq_count; i++) spin_lock_init(&enic->wq_lock[i]); @@ -2427,6 +2488,7 @@ static void __devexit enic_remove(struct pci_dev *pdev) struct enic *enic = netdev_priv(netdev); cancel_work_sync(&enic->reset); + cancel_work_sync(&enic->change_mtu_work); unregister_netdev(netdev); enic_dev_deinit(enic); vnic_dev_close(enic->vdev); diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c index 0ba5e7b90584..7a09575ecff0 100644 --- a/drivers/net/es3210.c +++ b/drivers/net/es3210.c @@ -54,6 +54,7 @@ static const char version[] = #include <linux/errno.h> #include <linux/string.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index a83dd312c3ac..9162c705c4fa 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c @@ -13,6 +13,7 @@ #include <linux/etherdevice.h> #include <linux/crc32.h> +#include <linux/interrupt.h> #include <linux/io.h> #include <linux/mii.h> #include <linux/phy.h> diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c index 9f81b1ac130e..eba0f696a51f 100644 --- a/drivers/net/fec_mpc52xx.c +++ b/drivers/net/fec_mpc52xx.c @@ -22,6 +22,7 @@ #include <linux/slab.h> #include <linux/errno.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/crc32.h> #include <linux/hardirq.h> #include <linux/delay.h> diff --git a/drivers/net/gianfar_ptp.c b/drivers/net/gianfar_ptp.c new file mode 100644 index 000000000000..d8e175382d1d --- /dev/null +++ b/drivers/net/gianfar_ptp.c @@ -0,0 +1,588 @@ +/* + * PTP 1588 clock using the eTSEC + * + * Copyright (C) 2010 OMICRON electronics GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <linux/device.h> +#include <linux/hrtimer.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/timex.h> +#include <linux/io.h> + +#include <linux/ptp_clock_kernel.h> + +#include "gianfar.h" + +/* + * gianfar ptp registers + * Generated by regen.tcl on Thu May 13 01:38:57 PM CEST 2010 + */ +struct gianfar_ptp_registers { + u32 tmr_ctrl; /* Timer control register */ + u32 tmr_tevent; /* Timestamp event register */ + u32 tmr_temask; /* Timer event mask register */ + u32 tmr_pevent; /* Timestamp event register */ + u32 tmr_pemask; /* Timer event mask register */ + u32 tmr_stat; /* Timestamp status register */ + u32 tmr_cnt_h; /* Timer counter high register */ + u32 tmr_cnt_l; /* Timer counter low register */ + u32 tmr_add; /* Timer drift compensation addend register */ + u32 tmr_acc; /* Timer accumulator register */ + u32 tmr_prsc; /* Timer prescale */ + u8 res1[4]; + u32 tmroff_h; /* Timer offset high */ + u32 tmroff_l; /* Timer offset low */ + u8 res2[8]; + u32 tmr_alarm1_h; /* Timer alarm 1 high register */ + u32 tmr_alarm1_l; /* Timer alarm 1 high register */ + u32 tmr_alarm2_h; /* Timer alarm 2 high register */ + u32 tmr_alarm2_l; /* Timer alarm 2 high register */ + u8 res3[48]; + u32 tmr_fiper1; /* Timer fixed period interval */ + u32 tmr_fiper2; /* Timer fixed period interval */ + u32 tmr_fiper3; /* Timer fixed period interval */ + u8 res4[20]; + u32 tmr_etts1_h; /* Timestamp of general purpose external trigger */ + u32 tmr_etts1_l; /* Timestamp of general purpose external trigger */ + u32 tmr_etts2_h; /* Timestamp of general purpose external trigger */ + u32 tmr_etts2_l; /* Timestamp of general purpose external trigger */ +}; + +/* Bit definitions for the TMR_CTRL register */ +#define ALM1P (1<<31) /* Alarm1 output polarity */ +#define ALM2P (1<<30) /* Alarm2 output polarity */ +#define FS (1<<28) /* FIPER start indication */ +#define PP1L (1<<27) /* Fiper1 pulse loopback mode enabled. */ +#define PP2L (1<<26) /* Fiper2 pulse loopback mode enabled. */ +#define TCLK_PERIOD_SHIFT (16) /* 1588 timer reference clock period. */ +#define TCLK_PERIOD_MASK (0x3ff) +#define RTPE (1<<15) /* Record Tx Timestamp to PAL Enable. */ +#define FRD (1<<14) /* FIPER Realignment Disable */ +#define ESFDP (1<<11) /* External Tx/Rx SFD Polarity. */ +#define ESFDE (1<<10) /* External Tx/Rx SFD Enable. */ +#define ETEP2 (1<<9) /* External trigger 2 edge polarity */ +#define ETEP1 (1<<8) /* External trigger 1 edge polarity */ +#define COPH (1<<7) /* Generated clock output phase. */ +#define CIPH (1<<6) /* External oscillator input clock phase */ +#define TMSR (1<<5) /* Timer soft reset. */ +#define BYP (1<<3) /* Bypass drift compensated clock */ +#define TE (1<<2) /* 1588 timer enable. */ +#define CKSEL_SHIFT (0) /* 1588 Timer reference clock source */ +#define CKSEL_MASK (0x3) + +/* Bit definitions for the TMR_TEVENT register */ +#define ETS2 (1<<25) /* External trigger 2 timestamp sampled */ +#define ETS1 (1<<24) /* External trigger 1 timestamp sampled */ +#define ALM2 (1<<17) /* Current time = alarm time register 2 */ +#define ALM1 (1<<16) /* Current time = alarm time register 1 */ +#define PP1 (1<<7) /* periodic pulse generated on FIPER1 */ +#define PP2 (1<<6) /* periodic pulse generated on FIPER2 */ +#define PP3 (1<<5) /* periodic pulse generated on FIPER3 */ + +/* Bit definitions for the TMR_TEMASK register */ +#define ETS2EN (1<<25) /* External trigger 2 timestamp enable */ +#define ETS1EN (1<<24) /* External trigger 1 timestamp enable */ +#define ALM2EN (1<<17) /* Timer ALM2 event enable */ +#define ALM1EN (1<<16) /* Timer ALM1 event enable */ +#define PP1EN (1<<7) /* Periodic pulse event 1 enable */ +#define PP2EN (1<<6) /* Periodic pulse event 2 enable */ + +/* Bit definitions for the TMR_PEVENT register */ +#define TXP2 (1<<9) /* PTP transmitted timestamp im TXTS2 */ +#define TXP1 (1<<8) /* PTP transmitted timestamp in TXTS1 */ +#define RXP (1<<0) /* PTP frame has been received */ + +/* Bit definitions for the TMR_PEMASK register */ +#define TXP2EN (1<<9) /* Transmit PTP packet event 2 enable */ +#define TXP1EN (1<<8) /* Transmit PTP packet event 1 enable */ +#define RXPEN (1<<0) /* Receive PTP packet event enable */ + +/* Bit definitions for the TMR_STAT register */ +#define STAT_VEC_SHIFT (0) /* Timer general purpose status vector */ +#define STAT_VEC_MASK (0x3f) + +/* Bit definitions for the TMR_PRSC register */ +#define PRSC_OCK_SHIFT (0) /* Output clock division/prescale factor. */ +#define PRSC_OCK_MASK (0xffff) + + +#define DRIVER "gianfar_ptp" +#define DEFAULT_CKSEL 1 +#define N_ALARM 1 /* first alarm is used internally to reset fipers */ +#define N_EXT_TS 2 +#define REG_SIZE sizeof(struct gianfar_ptp_registers) + +struct etsects { + struct gianfar_ptp_registers *regs; + spinlock_t lock; /* protects regs */ + struct ptp_clock *clock; + struct ptp_clock_info caps; + struct resource *rsrc; + int irq; + u64 alarm_interval; /* for periodic alarm */ + u64 alarm_value; + u32 tclk_period; /* nanoseconds */ + u32 tmr_prsc; + u32 tmr_add; + u32 cksel; + u32 tmr_fiper1; + u32 tmr_fiper2; +}; + +/* + * Register access functions + */ + +/* Caller must hold etsects->lock. */ +static u64 tmr_cnt_read(struct etsects *etsects) +{ + u64 ns; + u32 lo, hi; + + lo = gfar_read(&etsects->regs->tmr_cnt_l); + hi = gfar_read(&etsects->regs->tmr_cnt_h); + ns = ((u64) hi) << 32; + ns |= lo; + return ns; +} + +/* Caller must hold etsects->lock. */ +static void tmr_cnt_write(struct etsects *etsects, u64 ns) +{ + u32 hi = ns >> 32; + u32 lo = ns & 0xffffffff; + + gfar_write(&etsects->regs->tmr_cnt_l, lo); + gfar_write(&etsects->regs->tmr_cnt_h, hi); +} + +/* Caller must hold etsects->lock. */ +static void set_alarm(struct etsects *etsects) +{ + u64 ns; + u32 lo, hi; + + ns = tmr_cnt_read(etsects) + 1500000000ULL; + ns = div_u64(ns, 1000000000UL) * 1000000000ULL; + ns -= etsects->tclk_period; + hi = ns >> 32; + lo = ns & 0xffffffff; + gfar_write(&etsects->regs->tmr_alarm1_l, lo); + gfar_write(&etsects->regs->tmr_alarm1_h, hi); +} + +/* Caller must hold etsects->lock. */ +static void set_fipers(struct etsects *etsects) +{ + u32 tmr_ctrl = gfar_read(&etsects->regs->tmr_ctrl); + + gfar_write(&etsects->regs->tmr_ctrl, tmr_ctrl & (~TE)); + gfar_write(&etsects->regs->tmr_prsc, etsects->tmr_prsc); + gfar_write(&etsects->regs->tmr_fiper1, etsects->tmr_fiper1); + gfar_write(&etsects->regs->tmr_fiper2, etsects->tmr_fiper2); + set_alarm(etsects); + gfar_write(&etsects->regs->tmr_ctrl, tmr_ctrl|TE); +} + +/* + * Interrupt service routine + */ + +static irqreturn_t isr(int irq, void *priv) +{ + struct etsects *etsects = priv; + struct ptp_clock_event event; + u64 ns; + u32 ack = 0, lo, hi, mask, val; + + val = gfar_read(&etsects->regs->tmr_tevent); + + if (val & ETS1) { + ack |= ETS1; + hi = gfar_read(&etsects->regs->tmr_etts1_h); + lo = gfar_read(&etsects->regs->tmr_etts1_l); + event.type = PTP_CLOCK_EXTTS; + event.index = 0; + event.timestamp = ((u64) hi) << 32; + event.timestamp |= lo; + ptp_clock_event(etsects->clock, &event); + } + + if (val & ETS2) { + ack |= ETS2; + hi = gfar_read(&etsects->regs->tmr_etts2_h); + lo = gfar_read(&etsects->regs->tmr_etts2_l); + event.type = PTP_CLOCK_EXTTS; + event.index = 1; + event.timestamp = ((u64) hi) << 32; + event.timestamp |= lo; + ptp_clock_event(etsects->clock, &event); + } + + if (val & ALM2) { + ack |= ALM2; + if (etsects->alarm_value) { + event.type = PTP_CLOCK_ALARM; + event.index = 0; + event.timestamp = etsects->alarm_value; + ptp_clock_event(etsects->clock, &event); + } + if (etsects->alarm_interval) { + ns = etsects->alarm_value + etsects->alarm_interval; + hi = ns >> 32; + lo = ns & 0xffffffff; + spin_lock(&etsects->lock); + gfar_write(&etsects->regs->tmr_alarm2_l, lo); + gfar_write(&etsects->regs->tmr_alarm2_h, hi); + spin_unlock(&etsects->lock); + etsects->alarm_value = ns; + } else { + gfar_write(&etsects->regs->tmr_tevent, ALM2); + spin_lock(&etsects->lock); + mask = gfar_read(&etsects->regs->tmr_temask); + mask &= ~ALM2EN; + gfar_write(&etsects->regs->tmr_temask, mask); + spin_unlock(&etsects->lock); + etsects->alarm_value = 0; + etsects->alarm_interval = 0; + } + } + + if (val & PP1) { + ack |= PP1; + event.type = PTP_CLOCK_PPS; + ptp_clock_event(etsects->clock, &event); + } + + if (ack) { + gfar_write(&etsects->regs->tmr_tevent, ack); + return IRQ_HANDLED; + } else + return IRQ_NONE; +} + +/* + * PTP clock operations + */ + +static int ptp_gianfar_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +{ + u64 adj; + u32 diff, tmr_add; + int neg_adj = 0; + struct etsects *etsects = container_of(ptp, struct etsects, caps); + + if (ppb < 0) { + neg_adj = 1; + ppb = -ppb; + } + tmr_add = etsects->tmr_add; + adj = tmr_add; + adj *= ppb; + diff = div_u64(adj, 1000000000ULL); + + tmr_add = neg_adj ? tmr_add - diff : tmr_add + diff; + + gfar_write(&etsects->regs->tmr_add, tmr_add); + + return 0; +} + +static int ptp_gianfar_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + s64 now; + unsigned long flags; + struct etsects *etsects = container_of(ptp, struct etsects, caps); + + spin_lock_irqsave(&etsects->lock, flags); + + now = tmr_cnt_read(etsects); + now += delta; + tmr_cnt_write(etsects, now); + + spin_unlock_irqrestore(&etsects->lock, flags); + + set_fipers(etsects); + + return 0; +} + +static int ptp_gianfar_gettime(struct ptp_clock_info *ptp, struct timespec *ts) +{ + u64 ns; + u32 remainder; + unsigned long flags; + struct etsects *etsects = container_of(ptp, struct etsects, caps); + + spin_lock_irqsave(&etsects->lock, flags); + + ns = tmr_cnt_read(etsects); + + spin_unlock_irqrestore(&etsects->lock, flags); + + ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder); + ts->tv_nsec = remainder; + return 0; +} + +static int ptp_gianfar_settime(struct ptp_clock_info *ptp, + const struct timespec *ts) +{ + u64 ns; + unsigned long flags; + struct etsects *etsects = container_of(ptp, struct etsects, caps); + + ns = ts->tv_sec * 1000000000ULL; + ns += ts->tv_nsec; + + spin_lock_irqsave(&etsects->lock, flags); + + tmr_cnt_write(etsects, ns); + set_fipers(etsects); + + spin_unlock_irqrestore(&etsects->lock, flags); + + return 0; +} + +static int ptp_gianfar_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + struct etsects *etsects = container_of(ptp, struct etsects, caps); + unsigned long flags; + u32 bit, mask; + + switch (rq->type) { + case PTP_CLK_REQ_EXTTS: + switch (rq->extts.index) { + case 0: + bit = ETS1EN; + break; + case 1: + bit = ETS2EN; + break; + default: + return -EINVAL; + } + spin_lock_irqsave(&etsects->lock, flags); + mask = gfar_read(&etsects->regs->tmr_temask); + if (on) + mask |= bit; + else + mask &= ~bit; + gfar_write(&etsects->regs->tmr_temask, mask); + spin_unlock_irqrestore(&etsects->lock, flags); + return 0; + + case PTP_CLK_REQ_PPS: + spin_lock_irqsave(&etsects->lock, flags); + mask = gfar_read(&etsects->regs->tmr_temask); + if (on) + mask |= PP1EN; + else + mask &= ~PP1EN; + gfar_write(&etsects->regs->tmr_temask, mask); + spin_unlock_irqrestore(&etsects->lock, flags); + return 0; + + default: + break; + } + + return -EOPNOTSUPP; +} + +static struct ptp_clock_info ptp_gianfar_caps = { + .owner = THIS_MODULE, + .name = "gianfar clock", + .max_adj = 512000, + .n_alarm = N_ALARM, + .n_ext_ts = N_EXT_TS, + .n_per_out = 0, + .pps = 1, + .adjfreq = ptp_gianfar_adjfreq, + .adjtime = ptp_gianfar_adjtime, + .gettime = ptp_gianfar_gettime, + .settime = ptp_gianfar_settime, + .enable = ptp_gianfar_enable, +}; + +/* OF device tree */ + +static int get_of_u32(struct device_node *node, char *str, u32 *val) +{ + int plen; + const u32 *prop = of_get_property(node, str, &plen); + + if (!prop || plen != sizeof(*prop)) + return -1; + *val = *prop; + return 0; +} + +static int gianfar_ptp_probe(struct platform_device *dev) +{ + struct device_node *node = dev->dev.of_node; + struct etsects *etsects; + struct timespec now; + int err = -ENOMEM; + u32 tmr_ctrl; + unsigned long flags; + + etsects = kzalloc(sizeof(*etsects), GFP_KERNEL); + if (!etsects) + goto no_memory; + + err = -ENODEV; + + etsects->caps = ptp_gianfar_caps; + etsects->cksel = DEFAULT_CKSEL; + + if (get_of_u32(node, "fsl,tclk-period", &etsects->tclk_period) || + get_of_u32(node, "fsl,tmr-prsc", &etsects->tmr_prsc) || + get_of_u32(node, "fsl,tmr-add", &etsects->tmr_add) || + get_of_u32(node, "fsl,tmr-fiper1", &etsects->tmr_fiper1) || + get_of_u32(node, "fsl,tmr-fiper2", &etsects->tmr_fiper2) || + get_of_u32(node, "fsl,max-adj", &etsects->caps.max_adj)) { + pr_err("device tree node missing required elements\n"); + goto no_node; + } + + etsects->irq = platform_get_irq(dev, 0); + + if (etsects->irq == NO_IRQ) { + pr_err("irq not in device tree\n"); + goto no_node; + } + if (request_irq(etsects->irq, isr, 0, DRIVER, etsects)) { + pr_err("request_irq failed\n"); + goto no_node; + } + + etsects->rsrc = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!etsects->rsrc) { + pr_err("no resource\n"); + goto no_resource; + } + if (request_resource(&ioport_resource, etsects->rsrc)) { + pr_err("resource busy\n"); + goto no_resource; + } + + spin_lock_init(&etsects->lock); + + etsects->regs = ioremap(etsects->rsrc->start, + 1 + etsects->rsrc->end - etsects->rsrc->start); + if (!etsects->regs) { + pr_err("ioremap ptp registers failed\n"); + goto no_ioremap; + } + getnstimeofday(&now); + ptp_gianfar_settime(&etsects->caps, &now); + + tmr_ctrl = + (etsects->tclk_period & TCLK_PERIOD_MASK) << TCLK_PERIOD_SHIFT | + (etsects->cksel & CKSEL_MASK) << CKSEL_SHIFT; + + spin_lock_irqsave(&etsects->lock, flags); + + gfar_write(&etsects->regs->tmr_ctrl, tmr_ctrl); + gfar_write(&etsects->regs->tmr_add, etsects->tmr_add); + gfar_write(&etsects->regs->tmr_prsc, etsects->tmr_prsc); + gfar_write(&etsects->regs->tmr_fiper1, etsects->tmr_fiper1); + gfar_write(&etsects->regs->tmr_fiper2, etsects->tmr_fiper2); + set_alarm(etsects); + gfar_write(&etsects->regs->tmr_ctrl, tmr_ctrl|FS|RTPE|TE); + + spin_unlock_irqrestore(&etsects->lock, flags); + + etsects->clock = ptp_clock_register(&etsects->caps); + if (IS_ERR(etsects->clock)) { + err = PTR_ERR(etsects->clock); + goto no_clock; + } + + dev_set_drvdata(&dev->dev, etsects); + + return 0; + +no_clock: +no_ioremap: + release_resource(etsects->rsrc); +no_resource: + free_irq(etsects->irq, etsects); +no_node: + kfree(etsects); +no_memory: + return err; +} + +static int gianfar_ptp_remove(struct platform_device *dev) +{ + struct etsects *etsects = dev_get_drvdata(&dev->dev); + + gfar_write(&etsects->regs->tmr_temask, 0); + gfar_write(&etsects->regs->tmr_ctrl, 0); + + ptp_clock_unregister(etsects->clock); + iounmap(etsects->regs); + release_resource(etsects->rsrc); + free_irq(etsects->irq, etsects); + kfree(etsects); + + return 0; +} + +static struct of_device_id match_table[] = { + { .compatible = "fsl,etsec-ptp" }, + {}, +}; + +static struct platform_driver gianfar_ptp_driver = { + .driver = { + .name = "gianfar_ptp", + .of_match_table = match_table, + .owner = THIS_MODULE, + }, + .probe = gianfar_ptp_probe, + .remove = gianfar_ptp_remove, +}; + +/* module operations */ + +static int __init ptp_gianfar_init(void) +{ + return platform_driver_register(&gianfar_ptp_driver); +} + +module_init(ptp_gianfar_init); + +static void __exit ptp_gianfar_exit(void) +{ + platform_driver_unregister(&gianfar_ptp_driver); +} + +module_exit(ptp_gianfar_exit); + +MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>"); +MODULE_DESCRIPTION("PTP clock using the eTSEC"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/greth.c b/drivers/net/greth.c index f181304a7ab6..69b86d7fac85 100644 --- a/drivers/net/greth.c +++ b/drivers/net/greth.c @@ -25,6 +25,7 @@ #include <linux/module.h> #include <linux/uaccess.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index a3c0dc9d8b98..9537aaa50c2f 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -69,7 +69,7 @@ static const char paranoia_str[] = KERN_ERR static const char bc_drvname[] = "baycom_epp"; static const char bc_drvinfo[] = KERN_INFO "baycom_epp: (C) 1998-2000 Thomas Sailer, HB9JNX/AE4WA\n" -"baycom_epp: version 0.7 compiled " __TIME__ " " __DATE__ "\n"; +"baycom_epp: version 0.7\n"; /* --------------------------------------------------------------------- */ diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c index 5f5af9a606f8..279d2296290a 100644 --- a/drivers/net/hamradio/baycom_par.c +++ b/drivers/net/hamradio/baycom_par.c @@ -102,7 +102,7 @@ static const char bc_drvname[] = "baycom_par"; static const char bc_drvinfo[] = KERN_INFO "baycom_par: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n" -"baycom_par: version 0.9 compiled " __TIME__ " " __DATE__ "\n"; +"baycom_par: version 0.9\n"; /* --------------------------------------------------------------------- */ diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c index 3e25f10cabd6..a974727dd9a2 100644 --- a/drivers/net/hamradio/baycom_ser_fdx.c +++ b/drivers/net/hamradio/baycom_ser_fdx.c @@ -76,6 +76,7 @@ #include <linux/ioport.h> #include <linux/string.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/hdlcdrv.h> #include <linux/baycom.h> #include <linux/jiffies.h> @@ -92,7 +93,7 @@ static const char bc_drvname[] = "baycom_ser_fdx"; static const char bc_drvinfo[] = KERN_INFO "baycom_ser_fdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n" -"baycom_ser_fdx: version 0.10 compiled " __TIME__ " " __DATE__ "\n"; +"baycom_ser_fdx: version 0.10\n"; /* --------------------------------------------------------------------- */ diff --git a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c index 1686f6dcbbce..e349d867449b 100644 --- a/drivers/net/hamradio/baycom_ser_hdx.c +++ b/drivers/net/hamradio/baycom_ser_hdx.c @@ -66,6 +66,7 @@ #include <linux/ioport.h> #include <linux/string.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <asm/uaccess.h> #include <asm/io.h> #include <linux/hdlcdrv.h> @@ -80,7 +81,7 @@ static const char bc_drvname[] = "baycom_ser_hdx"; static const char bc_drvinfo[] = KERN_INFO "baycom_ser_hdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n" -"baycom_ser_hdx: version 0.10 compiled " __TIME__ " " __DATE__ "\n"; +"baycom_ser_hdx: version 0.10\n"; /* --------------------------------------------------------------------- */ diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c index 5b37579e84b7..a4a3516b6bbf 100644 --- a/drivers/net/hamradio/hdlcdrv.c +++ b/drivers/net/hamradio/hdlcdrv.c @@ -749,7 +749,7 @@ EXPORT_SYMBOL(hdlcdrv_unregister); static int __init hdlcdrv_init_driver(void) { printk(KERN_INFO "hdlcdrv: (C) 1996-2000 Thomas Sailer HB9JNX/AE4WA\n"); - printk(KERN_INFO "hdlcdrv: version 0.8 compiled " __TIME__ " " __DATE__ "\n"); + printk(KERN_INFO "hdlcdrv: version 0.8\n"); return 0; } diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c index 82bffc3cabdf..29917363ebfb 100644 --- a/drivers/net/hp-plus.c +++ b/drivers/net/hp-plus.c @@ -30,6 +30,7 @@ static const char version[] = #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/delay.h> #include <asm/system.h> diff --git a/drivers/net/hp.c b/drivers/net/hp.c index ef2014375e62..18564d4a7c04 100644 --- a/drivers/net/hp.c +++ b/drivers/net/hp.c @@ -30,6 +30,7 @@ static const char version[] = #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/delay.h> #include <asm/system.h> diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index c52a1df5d922..8e10d2f6a5ad 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -188,14 +188,14 @@ struct hp100_private { * variables */ #ifdef CONFIG_ISA -static const char *const hp100_isa_tbl[] __devinitconst = { +static const char *hp100_isa_tbl[] = { "HWPF150", /* HP J2573 rev A */ "HWP1950", /* HP J2573 */ }; #endif #ifdef CONFIG_EISA -static const struct eisa_device_id hp100_eisa_tbl[] __devinitconst = { +static struct eisa_device_id hp100_eisa_tbl[] = { { "HWPF180" }, /* HP J2577 rev A */ { "HWP1920" }, /* HP 27248B */ { "HWP1940" }, /* HP J2577 */ @@ -336,7 +336,7 @@ static __devinit const char *hp100_read_id(int ioaddr) } #ifdef CONFIG_ISA -static __devinit int hp100_isa_probe1(struct net_device *dev, int ioaddr) +static __init int hp100_isa_probe1(struct net_device *dev, int ioaddr) { const char *sig; int i; @@ -372,7 +372,7 @@ static __devinit int hp100_isa_probe1(struct net_device *dev, int ioaddr) * EISA and PCI are handled by device infrastructure. */ -static int __devinit hp100_isa_probe(struct net_device *dev, int addr) +static int __init hp100_isa_probe(struct net_device *dev, int addr) { int err = -ENODEV; @@ -396,7 +396,7 @@ static int __devinit hp100_isa_probe(struct net_device *dev, int addr) #endif /* CONFIG_ISA */ #if !defined(MODULE) && defined(CONFIG_ISA) -struct net_device * __devinit hp100_probe(int unit) +struct net_device * __init hp100_probe(int unit) { struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); int err; @@ -2843,7 +2843,7 @@ static void cleanup_dev(struct net_device *d) } #ifdef CONFIG_EISA -static int __devinit hp100_eisa_probe (struct device *gendev) +static int __init hp100_eisa_probe (struct device *gendev) { struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private)); struct eisa_device *edev = to_eisa_device(gendev); diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index 136d7544cc33..a7d6cad32953 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -895,12 +895,12 @@ static int ibmlana_irq; static int ibmlana_io; static int startslot; /* counts through slots when probing multiple devices */ -static const short ibmlana_adapter_ids[] __devinitconst = { +static short ibmlana_adapter_ids[] __initdata = { IBM_LANA_ID, 0x0000 }; -static const char *const ibmlana_adapter_names[] __devinitconst = { +static char *ibmlana_adapter_names[] __devinitdata = { "IBM LAN Adapter/A", NULL }; diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index b388d782c7c4..838c5b673767 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -34,6 +34,7 @@ #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/mm.h> #include <linux/pm.h> #include <linux/ethtool.h> diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 4fecaed67fc4..ce53f4a23b19 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -32,6 +32,7 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/moduleparam.h> #include <net/pkt_sched.h> #include <net/net_namespace.h> diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index 96c95617195f..32f07f868d89 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -915,7 +915,7 @@ static void ioc3_alloc_rings(struct net_device *dev) skb = ioc3_alloc_skb(RX_BUF_ALLOC_SIZE, GFP_ATOMIC); if (!skb) { - show_free_areas(); + show_free_areas(0); continue; } diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index 58cd3202b48c..d4aa40adf1e9 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -22,6 +22,7 @@ */ #include <linux/crc32.h> #include <linux/ethtool.h> +#include <linux/interrupt.h> #include <linux/gfp.h> #include <linux/mii.h> #include <linux/mutex.h> diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index d532dde5120f..963067d3bda2 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -31,6 +31,7 @@ #include <linux/ioport.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/rtnetlink.h> #include <linux/serial_reg.h> #include <linux/dma-mapping.h> diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 174cafad2c1a..b45b2cc42804 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -152,6 +152,7 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/pci.h> #include <linux/rtnetlink.h> diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 7a963d4e6d06..b56636da6cc3 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -52,6 +52,7 @@ #include <linux/ioport.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/rtnetlink.h> #include <linux/dma-mapping.h> #include <linux/pnp.h> diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c index 001ed0a255f6..b1d1ce3dd8b5 100644 --- a/drivers/net/irda/pxaficp_ir.c +++ b/drivers/net/irda/pxaficp_ir.c @@ -12,6 +12,7 @@ * Infra-red driver (SIR/FIR) for the PXA2xx embedded microprocessor * */ +#include <linux/interrupt.h> #include <linux/module.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index efe05bb34dd8..5039f08f5a5b 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -11,6 +11,7 @@ * ********************************************************************/ +#include <linux/hardirq.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 69b5707db369..d5072af81b2d 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -49,6 +49,7 @@ #include <linux/ioport.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/rtnetlink.h> #include <linux/serial_reg.h> #include <linux/dma-mapping.h> @@ -222,19 +223,19 @@ static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 s static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self); /* Probing */ -static int smsc_ircc_look_for_chips(void); -static const struct smsc_chip * smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type); -static int smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfg_base, char *type); -static int smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type); -static int smsc_superio_fdc(unsigned short cfg_base); -static int smsc_superio_lpc(unsigned short cfg_base); +static int __init smsc_ircc_look_for_chips(void); +static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type); +static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfg_base, char *type); +static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type); +static int __init smsc_superio_fdc(unsigned short cfg_base); +static int __init smsc_superio_lpc(unsigned short cfg_base); #ifdef CONFIG_PCI -static int preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); -static int preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); -static void preconfigure_ali_port(struct pci_dev *dev, +static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf); +static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); +static void __init preconfigure_ali_port(struct pci_dev *dev, unsigned short port); -static int preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); -static int smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, +static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf); +static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, unsigned short ircc_fir, unsigned short ircc_sir, unsigned char ircc_dma, @@ -366,7 +367,7 @@ static inline void register_bank(int iobase, int bank) } /* PNP hotplug support */ -static const struct pnp_device_id smsc_ircc_pnp_table[] __devinitconst = { +static const struct pnp_device_id smsc_ircc_pnp_table[] = { { .id = "SMCf010", .driver_data = 0 }, /* and presumably others */ { } @@ -515,7 +516,7 @@ static const struct net_device_ops smsc_ircc_netdev_ops = { * Try to open driver instance * */ -static int __devinit smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq) +static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq) { struct smsc_ircc_cb *self; struct net_device *dev; @@ -2273,7 +2274,7 @@ static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned sho } -static int __devinit smsc_access(unsigned short cfg_base, unsigned char reg) +static int __init smsc_access(unsigned short cfg_base, unsigned char reg) { IRDA_DEBUG(1, "%s\n", __func__); @@ -2281,7 +2282,7 @@ static int __devinit smsc_access(unsigned short cfg_base, unsigned char reg) return inb(cfg_base) != reg ? -1 : 0; } -static const struct smsc_chip * __devinit smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type) +static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type) { u8 devid, xdevid, rev; @@ -2406,7 +2407,7 @@ static int __init smsc_superio_lpc(unsigned short cfg_base) #ifdef CONFIG_PCI #define PCIID_VENDOR_INTEL 0x8086 #define PCIID_VENDOR_ALI 0x10b9 -static const struct smsc_ircc_subsystem_configuration subsystem_configurations[] __devinitconst = { +static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __initdata = { /* * Subsystems needing entries: * 0x10b9:0x1533 0x103c:0x0850 HP nx9010 family @@ -2532,7 +2533,7 @@ static const struct smsc_ircc_subsystem_configuration subsystem_configurations[] * (FIR port, SIR port, FIR DMA, FIR IRQ) * through the chip configuration port. */ -static int __devinit preconfigure_smsc_chip(struct +static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf) { @@ -2633,7 +2634,7 @@ static int __devinit preconfigure_smsc_chip(struct * or Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge. * They all work the same way! */ -static int __devinit preconfigure_through_82801(struct pci_dev *dev, +static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf) @@ -2786,7 +2787,7 @@ static int __devinit preconfigure_through_82801(struct pci_dev *dev, * This is based on reverse-engineering since ALi does not * provide any data sheet for the 1533 chip. */ -static void __devinit preconfigure_ali_port(struct pci_dev *dev, +static void __init preconfigure_ali_port(struct pci_dev *dev, unsigned short port) { unsigned char reg; @@ -2824,7 +2825,7 @@ static void __devinit preconfigure_ali_port(struct pci_dev *dev, IRDA_MESSAGE("Activated ALi 1533 ISA bridge port 0x%04x.\n", port); } -static int __devinit preconfigure_through_ali(struct pci_dev *dev, +static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf) @@ -2837,7 +2838,7 @@ static int __devinit preconfigure_through_ali(struct pci_dev *dev, return preconfigure_smsc_chip(conf); } -static int __devinit smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, +static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, unsigned short ircc_fir, unsigned short ircc_sir, unsigned char ircc_dma, @@ -2849,7 +2850,7 @@ static int __devinit smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg, int ret = 0; for_each_pci_dev(dev) { - const struct smsc_ircc_subsystem_configuration *conf; + struct smsc_ircc_subsystem_configuration *conf; /* * Cache the subsystem vendor/device: diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index f504b262ba36..6d6479049aa1 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -46,6 +46,7 @@ F02 Oct/28/02: Add SB device ID for 3147 and 3177. #include <linux/ioport.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/rtnetlink.h> #include <linux/pci.h> #include <linux/dma-mapping.h> diff --git a/drivers/net/irda/via-ircc.h b/drivers/net/irda/via-ircc.h index c6f58482b769..f903a6a2dcb7 100644 --- a/drivers/net/irda/via-ircc.h +++ b/drivers/net/irda/via-ircc.h @@ -210,7 +210,7 @@ static void DisableDmaChannel(unsigned int channel) break; default: break; - }; //Switch + } } static unsigned char ReadLPCReg(int iRegNum) diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index c3d07382b7fa..9021d0131727 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -36,6 +36,7 @@ MODULE_LICENSE("GPL"); #include <linux/kernel.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/pci.h> #include <linux/slab.h> #include <linux/netdevice.h> diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index 1f9c3f08d1a3..c4366601b067 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -47,6 +47,7 @@ #include <linux/ioport.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/rtnetlink.h> #include <linux/dma-mapping.h> #include <linux/gfp.h> diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index 9ece1fd9889d..b6c296f4b4d5 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -538,7 +538,7 @@ static void veth_handle_ack(struct veth_lpevent *event) default: veth_error("Unknown ack type %d from LPAR %d.\n", event->base_event.xSubtype, rlp); - }; + } } static void veth_handle_int(struct veth_lpevent *event) @@ -584,7 +584,7 @@ static void veth_handle_int(struct veth_lpevent *event) default: veth_error("Unknown interrupt type %d from LPAR %d.\n", event->base_event.xSubtype, rlp); - }; + } } static void veth_handle_event(struct HvLpEvent *event) diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 8ee661245af3..0d7bc9156353 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -1157,7 +1157,7 @@ s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc) default: /* bad value */ return IXGBE_ERR_CONFIG; - }; + } /* Move the flexible bytes to use the ethertype - shift 6 words */ fdirctrl |= (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT); @@ -1245,7 +1245,7 @@ s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc) default: /* bad value */ return IXGBE_ERR_CONFIG; - }; + } /* Turn perfect match filtering on */ fdirctrl |= IXGBE_FDIRCTRL_PERFECT_MATCH; diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c index b894b42a741c..de65643b79a4 100644 --- a/drivers/net/ixgbe/ixgbe_common.c +++ b/drivers/net/ixgbe/ixgbe_common.c @@ -1292,7 +1292,7 @@ static s32 ixgbe_ready_eeprom(struct ixgbe_hw *hw) udelay(5); ixgbe_standby_eeprom(hw); - }; + } /* * On some parts, SPI write time could vary from 0-20mSec on 3.3V @@ -1374,7 +1374,7 @@ static void ixgbe_shift_out_eeprom_bits(struct ixgbe_hw *hw, u16 data, * EEPROM */ mask = mask >> 1; - }; + } /* We leave the "DI" bit set to "0" when we leave this routine. */ eec &= ~IXGBE_EEC_DI; diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index cb1555bc8548..4950d03d3ef8 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -27,6 +27,7 @@ /* ethtool support for ixgbe */ +#include <linux/interrupt.h> #include <linux/types.h> #include <linux/module.h> #include <linux/slab.h> diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 08e8e25c159d..06cfaf31bcf3 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -32,6 +32,7 @@ #include <linux/vmalloc.h> #include <linux/string.h> #include <linux/in.h> +#include <linux/interrupt.h> #include <linux/ip.h> #include <linux/tcp.h> #include <linux/pkt_sched.h> diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c index 78ddd8b79e7e..e122493ab70e 100644 --- a/drivers/net/ixp2000/ixpdev.c +++ b/drivers/net/ixp2000/ixpdev.c @@ -14,6 +14,7 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/moduleparam.h> #include <linux/gfp.h> #include <asm/hardware/uengine.h> diff --git a/drivers/net/jme.h b/drivers/net/jme.h index e9aaeca96abc..0d5da06489d8 100644 --- a/drivers/net/jme.h +++ b/drivers/net/jme.h @@ -24,6 +24,7 @@ #ifndef __JME_H_INCLUDED__ #define __JME_H_INCLUDED__ +#include <linux/interrupt.h> #define DRV_NAME "jme" #define DRV_VERSION "1.0.8" diff --git a/drivers/net/ks8842.c b/drivers/net/ks8842.c index f0d8346d0fa5..4a6ae057e3b1 100644 --- a/drivers/net/ks8842.c +++ b/drivers/net/ks8842.c @@ -23,10 +23,10 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/mfd/core.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> @@ -662,7 +662,7 @@ static void ks8842_rx_frame(struct net_device *netdev, /* check the status */ if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) { - struct sk_buff *skb = netdev_alloc_skb_ip_align(netdev, len); + struct sk_buff *skb = netdev_alloc_skb_ip_align(netdev, len + 3); if (skb) { @@ -1146,7 +1146,7 @@ static int __devinit ks8842_probe(struct platform_device *pdev) struct resource *iomem; struct net_device *netdev; struct ks8842_adapter *adapter; - struct ks8842_platform_data *pdata = mfd_get_data(pdev); + struct ks8842_platform_data *pdata = pdev->dev.platform_data; u16 id; unsigned i; diff --git a/drivers/net/ks8851.c b/drivers/net/ks8851.c index bcd9ba68c9f2..f56743a28fc0 100644 --- a/drivers/net/ks8851.c +++ b/drivers/net/ks8851.c @@ -13,6 +13,7 @@ #define DEBUG +#include <linux/interrupt.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/netdevice.h> diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c index 61631cace913..aefbdd896d6a 100644 --- a/drivers/net/ks8851_mll.c +++ b/drivers/net/ks8851_mll.c @@ -23,6 +23,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/interrupt.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/netdevice.h> diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c index 41ea5920c158..2ac6c6c984b3 100644 --- a/drivers/net/ksz884x.c +++ b/drivers/net/ksz884x.c @@ -17,6 +17,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/ioport.h> diff --git a/drivers/net/ll_temac_main.c b/drivers/net/ll_temac_main.c index b7948ccfcf7d..e7b8afec73a1 100644 --- a/drivers/net/ll_temac_main.c +++ b/drivers/net/ll_temac_main.c @@ -48,6 +48,7 @@ #include <linux/io.h> #include <linux/ip.h> #include <linux/slab.h> +#include <linux/interrupt.h> #include "ll_temac.h" diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c index 8a1097cf8a83..f9888d20177b 100644 --- a/drivers/net/lne390.c +++ b/drivers/net/lne390.c @@ -41,6 +41,7 @@ static const char *version = #include <linux/string.h> #include <linux/delay.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 6c6a02869dfc..818f0b8c2772 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -15,6 +15,7 @@ #include <linux/types.h> #include <linux/slab.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/dma-mapping.h> diff --git a/drivers/net/mace.c b/drivers/net/mace.c index 1c5221f79d6f..2074e9724ba3 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -13,6 +13,7 @@ #include <linux/string.h> #include <linux/timer.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/crc32.h> #include <linux/spinlock.h> #include <linux/bitrev.h> diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index d6aeaa5f25ea..cc67cbe670cb 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -414,7 +414,8 @@ static struct lock_class_key macvlan_netdev_addr_lock_key; #define MACVLAN_FEATURES \ (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \ NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \ - NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO | NETIF_F_RXCSUM) + NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO | NETIF_F_RXCSUM | \ + NETIF_F_HW_VLAN_FILTER) #define MACVLAN_STATE_MASK \ ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT)) @@ -509,6 +510,39 @@ static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev, return stats; } +static void macvlan_vlan_rx_register(struct net_device *dev, + struct vlan_group *grp) +{ + struct macvlan_dev *vlan = netdev_priv(dev); + struct net_device *lowerdev = vlan->lowerdev; + const struct net_device_ops *ops = lowerdev->netdev_ops; + + if (ops->ndo_vlan_rx_register) + ops->ndo_vlan_rx_register(lowerdev, grp); +} + +static void macvlan_vlan_rx_add_vid(struct net_device *dev, + unsigned short vid) +{ + struct macvlan_dev *vlan = netdev_priv(dev); + struct net_device *lowerdev = vlan->lowerdev; + const struct net_device_ops *ops = lowerdev->netdev_ops; + + if (ops->ndo_vlan_rx_add_vid) + ops->ndo_vlan_rx_add_vid(lowerdev, vid); +} + +static void macvlan_vlan_rx_kill_vid(struct net_device *dev, + unsigned short vid) +{ + struct macvlan_dev *vlan = netdev_priv(dev); + struct net_device *lowerdev = vlan->lowerdev; + const struct net_device_ops *ops = lowerdev->netdev_ops; + + if (ops->ndo_vlan_rx_kill_vid) + ops->ndo_vlan_rx_kill_vid(lowerdev, vid); +} + static void macvlan_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) { @@ -541,6 +575,9 @@ static const struct net_device_ops macvlan_netdev_ops = { .ndo_set_multicast_list = macvlan_set_multicast_list, .ndo_get_stats64 = macvlan_dev_get_stats64, .ndo_validate_addr = eth_validate_addr, + .ndo_vlan_rx_register = macvlan_vlan_rx_register, + .ndo_vlan_rx_add_vid = macvlan_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = macvlan_vlan_rx_kill_vid, }; void macvlan_common_setup(struct net_device *dev) diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index bf84849600ce..3f33870de211 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1013,7 +1013,7 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) cmd.data2 = i; status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_DMA, &cmd, 0); - }; + } status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd, 0); diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c index e8984b0ca521..243ed2aee88e 100644 --- a/drivers/net/ne3210.c +++ b/drivers/net/ne3210.c @@ -80,20 +80,17 @@ static void ne3210_block_output(struct net_device *dev, int count, const unsigne #define NE3210_DEBUG 0x0 -static const unsigned char irq_map[] __devinitconst = - { 15, 12, 11, 10, 9, 7, 5, 3 }; -static const unsigned int shmem_map[] __devinitconst = - { 0xff0, 0xfe0, 0xfff0, 0xd8, 0xffe0, 0xffc0, 0xd0, 0x0 }; -static const char *const ifmap[] __devinitconst = - { "UTP", "?", "BNC", "AUI" }; -static const int ifmap_val[] __devinitconst = { +static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3}; +static unsigned int shmem_map[] __initdata = {0xff0, 0xfe0, 0xfff0, 0xd8, 0xffe0, 0xffc0, 0xd0, 0x0}; +static const char *ifmap[] __initdata = {"UTP", "?", "BNC", "AUI"}; +static int ifmap_val[] __initdata = { IF_PORT_10BASET, IF_PORT_UNKNOWN, IF_PORT_10BASE2, IF_PORT_AUI, }; -static int __devinit ne3210_eisa_probe (struct device *device) +static int __init ne3210_eisa_probe (struct device *device) { unsigned long ioaddr, phys_mem; int i, retval, port_index; @@ -316,7 +313,7 @@ static void ne3210_block_output(struct net_device *dev, int count, memcpy_toio(shmem, buf, count); } -static const struct eisa_device_id ne3210_ids[] __devinitconst = { +static struct eisa_device_id ne3210_ids[] = { { "EGL0101" }, { "NVL1801" }, { "" }, diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c index 2e4b42175f3f..2dfee892d200 100644 --- a/drivers/net/netx-eth.c +++ b/drivers/net/netx-eth.c @@ -18,6 +18,7 @@ */ #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 5cef718fe35f..3f89e57cae50 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -809,6 +809,9 @@ int netxen_config_hw_lro(struct netxen_adapter *adapter, int enable) u64 word; int rv = 0; + if (!test_bit(__NX_FW_ATTACHED, &adapter->state)) + return 0; + memset(&req, 0, sizeof(nx_nic_req_t)); req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23); @@ -959,6 +962,9 @@ int netxen_send_lro_cleanup(struct netxen_adapter *adapter) u64 word; int rv; + if (!test_bit(__NX_FW_ATTACHED, &adapter->state)) + return 0; + memset(&req, 0, sizeof(nx_nic_req_t)); req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23); diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 7f999671c7b2..ca59b4f026f0 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1279,7 +1279,7 @@ void netxen_free_dummy_dma(struct netxen_adapter *adapter) if (--i == 0) break; - }; + } } if (i) { diff --git a/drivers/net/niu.c b/drivers/net/niu.c index cc25bff0bd3b..543eb17acdc5 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -7,6 +7,7 @@ #include <linux/module.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/pci.h> #include <linux/dma-mapping.h> #include <linux/netdevice.h> diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index 3e4040f2f3cb..d3afb458987e 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -106,6 +106,7 @@ #include <linux/delay.h> #include <linux/workqueue.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/ip.h> /* for iph */ #include <linux/in.h> /* for IPPROTO_... */ #include <linux/compiler.h> diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 81ac330f931d..34c5e1cbf65d 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -1150,7 +1150,7 @@ static int el3_close(struct net_device *dev) return 0; } -static struct pcmcia_device_id tc574_ids[] = { +static const struct pcmcia_device_id tc574_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0574), PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0556, "cis/3CCFEM556.cis"), PCMCIA_DEVICE_NULL, diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 79b9ca0dbdb4..4a1a35809807 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -908,7 +908,7 @@ static int el3_close(struct net_device *dev) return 0; } -static struct pcmcia_device_id tc589_ids[] = { +static const struct pcmcia_device_id tc589_ids[] = { PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0101, 0x0562), PCMCIA_MFC_DEVICE_PROD_ID1(0, "Motorola MARQUIS", 0xf03e4e77), PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0589), diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 3077d72e8222..9953db711969 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -687,7 +687,7 @@ static void block_output(struct net_device *dev, int count, outsw(nic_base + AXNET_DATAPORT, buf, count>>1); } -static struct pcmcia_device_id axnet_ids[] = { +static const struct pcmcia_device_id axnet_ids[] = { PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x016c, 0x0081), PCMCIA_DEVICE_MANF_CARD(0x018a, 0x0301), PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x2328), diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index 27bfad76fc40..980e65c14936 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c @@ -316,7 +316,7 @@ static int com20020_resume(struct pcmcia_device *link) return 0; } -static struct pcmcia_device_id com20020_ids[] = { +static const struct pcmcia_device_id com20020_ids[] = { PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.", "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf), PCMCIA_DEVICE_PROD_ID12("SoHard AG", diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 530ab5a10bd3..723815e7a997 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -667,7 +667,7 @@ static int fmvj18x_resume(struct pcmcia_device *link) /*====================================================================*/ -static struct pcmcia_device_id fmvj18x_ids[] = { +static const struct pcmcia_device_id fmvj18x_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x0004, 0x0004), PCMCIA_DEVICE_PROD_ID12("EAGLE Technology", "NE200 ETHERNET LAN MBH10302 04", 0x528c88c4, 0x74f91e59), PCMCIA_DEVICE_PROD_ID12("Eiger Labs,Inc", "EPX-10BT PC Card Ethernet 10BT", 0x53af556e, 0x877f9922), diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c index 15d57f5b6f29..6006d5488fbe 100644 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ b/drivers/net/pcmcia/ibmtr_cs.c @@ -340,7 +340,7 @@ static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase) outb(0x40, dev->base_addr); } -static struct pcmcia_device_id ibmtr_ids[] = { +static const struct pcmcia_device_id ibmtr_ids[] = { PCMCIA_DEVICE_PROD_ID12("3Com", "TokenLink Velocity PC Card", 0x41240e5b, 0x82c3734e), PCMCIA_DEVICE_PROD_ID12("IBM", "TOKEN RING", 0xb569a6e5, 0xbf8eed47), PCMCIA_DEVICE_NULL, diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 76683d97d83b..9d70b6595220 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -1494,7 +1494,7 @@ static void set_multicast_list(struct net_device *dev) } /* set_multicast_list */ -static struct pcmcia_device_id nmclan_ids[] = { +static const struct pcmcia_device_id nmclan_ids[] = { PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "Ethernet", 0x085a850b, 0x00b2e941), PCMCIA_DEVICE_PROD_ID12("Portable Add-ons", "Ethernet+", 0xebf1d60, 0xad673aaf), PCMCIA_DEVICE_NULL, diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index e953793a33ff..b4fd7c3ed077 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1463,7 +1463,7 @@ failed: /*====================================================================*/ -static struct pcmcia_device_id pcnet_ids[] = { +static const struct pcmcia_device_id pcnet_ids[] = { PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0057, 0x0021), PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0104, 0x000a), PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0xea15), diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 288e4f1317ee..1cd9394c3359 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -2014,7 +2014,7 @@ static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) return rc; } -static struct pcmcia_device_id smc91c92_ids[] = { +static const struct pcmcia_device_id smc91c92_ids[] = { PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0109, 0x0501), PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0140, 0x000a), PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63), diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index a46b7fd6c0f5..e33b190d716f 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -1738,7 +1738,7 @@ do_stop(struct net_device *dev) return 0; } -static struct pcmcia_device_id xirc2ps_ids[] = { +static const struct pcmcia_device_id xirc2ps_ids[] = { PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0089, 0x110a), PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0138, 0x110a), PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea), diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 13bebab65d02..2333215bbb32 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_FIXED_PHY) += fixed.o obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o obj-$(CONFIG_NATIONAL_PHY) += national.o +obj-$(CONFIG_DP83640_PHY) += dp83640.o obj-$(CONFIG_STE10XP) += ste10Xp.o obj-$(CONFIG_MICREL_PHY) += micrel.o obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c new file mode 100644 index 000000000000..b0c9522bb535 --- /dev/null +++ b/drivers/net/phy/dp83640.c @@ -0,0 +1,1100 @@ +/* + * Driver for the National Semiconductor DP83640 PHYTER + * + * Copyright (C) 2010 OMICRON electronics GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <linux/ethtool.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/mii.h> +#include <linux/module.h> +#include <linux/net_tstamp.h> +#include <linux/netdevice.h> +#include <linux/phy.h> +#include <linux/ptp_classify.h> +#include <linux/ptp_clock_kernel.h> + +#include "dp83640_reg.h" + +#define DP83640_PHY_ID 0x20005ce1 +#define PAGESEL 0x13 +#define LAYER4 0x02 +#define LAYER2 0x01 +#define MAX_RXTS 4 +#define MAX_TXTS 4 +#define N_EXT_TS 1 +#define PSF_PTPVER 2 +#define PSF_EVNT 0x4000 +#define PSF_RX 0x2000 +#define PSF_TX 0x1000 +#define EXT_EVENT 1 +#define EXT_GPIO 1 +#define CAL_EVENT 2 +#define CAL_GPIO 9 +#define CAL_TRIGGER 2 + +/* phyter seems to miss the mark by 16 ns */ +#define ADJTIME_FIX 16 + +#if defined(__BIG_ENDIAN) +#define ENDIAN_FLAG 0 +#elif defined(__LITTLE_ENDIAN) +#define ENDIAN_FLAG PSF_ENDIAN +#endif + +#define SKB_PTP_TYPE(__skb) (*(unsigned int *)((__skb)->cb)) + +struct phy_rxts { + u16 ns_lo; /* ns[15:0] */ + u16 ns_hi; /* overflow[1:0], ns[29:16] */ + u16 sec_lo; /* sec[15:0] */ + u16 sec_hi; /* sec[31:16] */ + u16 seqid; /* sequenceId[15:0] */ + u16 msgtype; /* messageType[3:0], hash[11:0] */ +}; + +struct phy_txts { + u16 ns_lo; /* ns[15:0] */ + u16 ns_hi; /* overflow[1:0], ns[29:16] */ + u16 sec_lo; /* sec[15:0] */ + u16 sec_hi; /* sec[31:16] */ +}; + +struct rxts { + struct list_head list; + unsigned long tmo; + u64 ns; + u16 seqid; + u8 msgtype; + u16 hash; +}; + +struct dp83640_clock; + +struct dp83640_private { + struct list_head list; + struct dp83640_clock *clock; + struct phy_device *phydev; + struct work_struct ts_work; + int hwts_tx_en; + int hwts_rx_en; + int layer; + int version; + /* remember state of cfg0 during calibration */ + int cfg0; + /* remember the last event time stamp */ + struct phy_txts edata; + /* list of rx timestamps */ + struct list_head rxts; + struct list_head rxpool; + struct rxts rx_pool_data[MAX_RXTS]; + /* protects above three fields from concurrent access */ + spinlock_t rx_lock; + /* queues of incoming and outgoing packets */ + struct sk_buff_head rx_queue; + struct sk_buff_head tx_queue; +}; + +struct dp83640_clock { + /* keeps the instance in the 'phyter_clocks' list */ + struct list_head list; + /* we create one clock instance per MII bus */ + struct mii_bus *bus; + /* protects extended registers from concurrent access */ + struct mutex extreg_lock; + /* remembers which page was last selected */ + int page; + /* our advertised capabilities */ + struct ptp_clock_info caps; + /* protects the three fields below from concurrent access */ + struct mutex clock_lock; + /* the one phyter from which we shall read */ + struct dp83640_private *chosen; + /* list of the other attached phyters, not chosen */ + struct list_head phylist; + /* reference to our PTP hardware clock */ + struct ptp_clock *ptp_clock; +}; + +/* globals */ + +static int chosen_phy = -1; +static ushort cal_gpio = 4; + +module_param(chosen_phy, int, 0444); +module_param(cal_gpio, ushort, 0444); + +MODULE_PARM_DESC(chosen_phy, \ + "The address of the PHY to use for the ancillary clock features"); +MODULE_PARM_DESC(cal_gpio, \ + "Which GPIO line to use for synchronizing multiple PHYs"); + +/* a list of clocks and a mutex to protect it */ +static LIST_HEAD(phyter_clocks); +static DEFINE_MUTEX(phyter_clocks_lock); + +static void rx_timestamp_work(struct work_struct *work); + +/* extended register access functions */ + +#define BROADCAST_ADDR 31 + +static inline int broadcast_write(struct mii_bus *bus, u32 regnum, u16 val) +{ + return mdiobus_write(bus, BROADCAST_ADDR, regnum, val); +} + +/* Caller must hold extreg_lock. */ +static int ext_read(struct phy_device *phydev, int page, u32 regnum) +{ + struct dp83640_private *dp83640 = phydev->priv; + int val; + + if (dp83640->clock->page != page) { + broadcast_write(phydev->bus, PAGESEL, page); + dp83640->clock->page = page; + } + val = phy_read(phydev, regnum); + + return val; +} + +/* Caller must hold extreg_lock. */ +static void ext_write(int broadcast, struct phy_device *phydev, + int page, u32 regnum, u16 val) +{ + struct dp83640_private *dp83640 = phydev->priv; + + if (dp83640->clock->page != page) { + broadcast_write(phydev->bus, PAGESEL, page); + dp83640->clock->page = page; + } + if (broadcast) + broadcast_write(phydev->bus, regnum, val); + else + phy_write(phydev, regnum, val); +} + +/* Caller must hold extreg_lock. */ +static int tdr_write(int bc, struct phy_device *dev, + const struct timespec *ts, u16 cmd) +{ + ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_nsec & 0xffff);/* ns[15:0] */ + ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_nsec >> 16); /* ns[31:16] */ + ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_sec & 0xffff); /* sec[15:0] */ + ext_write(bc, dev, PAGE4, PTP_TDR, ts->tv_sec >> 16); /* sec[31:16]*/ + + ext_write(bc, dev, PAGE4, PTP_CTL, cmd); + + return 0; +} + +/* convert phy timestamps into driver timestamps */ + +static void phy2rxts(struct phy_rxts *p, struct rxts *rxts) +{ + u32 sec; + + sec = p->sec_lo; + sec |= p->sec_hi << 16; + + rxts->ns = p->ns_lo; + rxts->ns |= (p->ns_hi & 0x3fff) << 16; + rxts->ns += ((u64)sec) * 1000000000ULL; + rxts->seqid = p->seqid; + rxts->msgtype = (p->msgtype >> 12) & 0xf; + rxts->hash = p->msgtype & 0x0fff; + rxts->tmo = jiffies + HZ; +} + +static u64 phy2txts(struct phy_txts *p) +{ + u64 ns; + u32 sec; + + sec = p->sec_lo; + sec |= p->sec_hi << 16; + + ns = p->ns_lo; + ns |= (p->ns_hi & 0x3fff) << 16; + ns += ((u64)sec) * 1000000000ULL; + + return ns; +} + +/* ptp clock methods */ + +static int ptp_dp83640_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +{ + struct dp83640_clock *clock = + container_of(ptp, struct dp83640_clock, caps); + struct phy_device *phydev = clock->chosen->phydev; + u64 rate; + int neg_adj = 0; + u16 hi, lo; + + if (ppb < 0) { + neg_adj = 1; + ppb = -ppb; + } + rate = ppb; + rate <<= 26; + rate = div_u64(rate, 1953125); + + hi = (rate >> 16) & PTP_RATE_HI_MASK; + if (neg_adj) + hi |= PTP_RATE_DIR; + + lo = rate & 0xffff; + + mutex_lock(&clock->extreg_lock); + + ext_write(1, phydev, PAGE4, PTP_RATEH, hi); + ext_write(1, phydev, PAGE4, PTP_RATEL, lo); + + mutex_unlock(&clock->extreg_lock); + + return 0; +} + +static int ptp_dp83640_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + struct dp83640_clock *clock = + container_of(ptp, struct dp83640_clock, caps); + struct phy_device *phydev = clock->chosen->phydev; + struct timespec ts; + int err; + + delta += ADJTIME_FIX; + + ts = ns_to_timespec(delta); + + mutex_lock(&clock->extreg_lock); + + err = tdr_write(1, phydev, &ts, PTP_STEP_CLK); + + mutex_unlock(&clock->extreg_lock); + + return err; +} + +static int ptp_dp83640_gettime(struct ptp_clock_info *ptp, struct timespec *ts) +{ + struct dp83640_clock *clock = + container_of(ptp, struct dp83640_clock, caps); + struct phy_device *phydev = clock->chosen->phydev; + unsigned int val[4]; + + mutex_lock(&clock->extreg_lock); + + ext_write(0, phydev, PAGE4, PTP_CTL, PTP_RD_CLK); + + val[0] = ext_read(phydev, PAGE4, PTP_TDR); /* ns[15:0] */ + val[1] = ext_read(phydev, PAGE4, PTP_TDR); /* ns[31:16] */ + val[2] = ext_read(phydev, PAGE4, PTP_TDR); /* sec[15:0] */ + val[3] = ext_read(phydev, PAGE4, PTP_TDR); /* sec[31:16] */ + + mutex_unlock(&clock->extreg_lock); + + ts->tv_nsec = val[0] | (val[1] << 16); + ts->tv_sec = val[2] | (val[3] << 16); + + return 0; +} + +static int ptp_dp83640_settime(struct ptp_clock_info *ptp, + const struct timespec *ts) +{ + struct dp83640_clock *clock = + container_of(ptp, struct dp83640_clock, caps); + struct phy_device *phydev = clock->chosen->phydev; + int err; + + mutex_lock(&clock->extreg_lock); + + err = tdr_write(1, phydev, ts, PTP_LOAD_CLK); + + mutex_unlock(&clock->extreg_lock); + + return err; +} + +static int ptp_dp83640_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + struct dp83640_clock *clock = + container_of(ptp, struct dp83640_clock, caps); + struct phy_device *phydev = clock->chosen->phydev; + u16 evnt; + + switch (rq->type) { + case PTP_CLK_REQ_EXTTS: + if (rq->extts.index != 0) + return -EINVAL; + evnt = EVNT_WR | (EXT_EVENT & EVNT_SEL_MASK) << EVNT_SEL_SHIFT; + if (on) { + evnt |= (EXT_GPIO & EVNT_GPIO_MASK) << EVNT_GPIO_SHIFT; + evnt |= EVNT_RISE; + } + ext_write(0, phydev, PAGE5, PTP_EVNT, evnt); + return 0; + default: + break; + } + + return -EOPNOTSUPP; +} + +static u8 status_frame_dst[6] = { 0x01, 0x1B, 0x19, 0x00, 0x00, 0x00 }; +static u8 status_frame_src[6] = { 0x08, 0x00, 0x17, 0x0B, 0x6B, 0x0F }; + +static void enable_status_frames(struct phy_device *phydev, bool on) +{ + u16 cfg0 = 0, ver; + + if (on) + cfg0 = PSF_EVNT_EN | PSF_RXTS_EN | PSF_TXTS_EN | ENDIAN_FLAG; + + ver = (PSF_PTPVER & VERSIONPTP_MASK) << VERSIONPTP_SHIFT; + + ext_write(0, phydev, PAGE5, PSF_CFG0, cfg0); + ext_write(0, phydev, PAGE6, PSF_CFG1, ver); + + if (!phydev->attached_dev) { + pr_warning("dp83640: expected to find an attached netdevice\n"); + return; + } + + if (on) { + if (dev_mc_add(phydev->attached_dev, status_frame_dst)) + pr_warning("dp83640: failed to add mc address\n"); + } else { + if (dev_mc_del(phydev->attached_dev, status_frame_dst)) + pr_warning("dp83640: failed to delete mc address\n"); + } +} + +static bool is_status_frame(struct sk_buff *skb, int type) +{ + struct ethhdr *h = eth_hdr(skb); + + if (PTP_CLASS_V2_L2 == type && + !memcmp(h->h_source, status_frame_src, sizeof(status_frame_src))) + return true; + else + return false; +} + +static int expired(struct rxts *rxts) +{ + return time_after(jiffies, rxts->tmo); +} + +/* Caller must hold rx_lock. */ +static void prune_rx_ts(struct dp83640_private *dp83640) +{ + struct list_head *this, *next; + struct rxts *rxts; + + list_for_each_safe(this, next, &dp83640->rxts) { + rxts = list_entry(this, struct rxts, list); + if (expired(rxts)) { + list_del_init(&rxts->list); + list_add(&rxts->list, &dp83640->rxpool); + } + } +} + +/* synchronize the phyters so they act as one clock */ + +static void enable_broadcast(struct phy_device *phydev, int init_page, int on) +{ + int val; + phy_write(phydev, PAGESEL, 0); + val = phy_read(phydev, PHYCR2); + if (on) + val |= BC_WRITE; + else + val &= ~BC_WRITE; + phy_write(phydev, PHYCR2, val); + phy_write(phydev, PAGESEL, init_page); +} + +static void recalibrate(struct dp83640_clock *clock) +{ + s64 now, diff; + struct phy_txts event_ts; + struct timespec ts; + struct list_head *this; + struct dp83640_private *tmp; + struct phy_device *master = clock->chosen->phydev; + u16 cfg0, evnt, ptp_trig, trigger, val; + + trigger = CAL_TRIGGER; + + mutex_lock(&clock->extreg_lock); + + /* + * enable broadcast, disable status frames, enable ptp clock + */ + list_for_each(this, &clock->phylist) { + tmp = list_entry(this, struct dp83640_private, list); + enable_broadcast(tmp->phydev, clock->page, 1); + tmp->cfg0 = ext_read(tmp->phydev, PAGE5, PSF_CFG0); + ext_write(0, tmp->phydev, PAGE5, PSF_CFG0, 0); + ext_write(0, tmp->phydev, PAGE4, PTP_CTL, PTP_ENABLE); + } + enable_broadcast(master, clock->page, 1); + cfg0 = ext_read(master, PAGE5, PSF_CFG0); + ext_write(0, master, PAGE5, PSF_CFG0, 0); + ext_write(0, master, PAGE4, PTP_CTL, PTP_ENABLE); + + /* + * enable an event timestamp + */ + evnt = EVNT_WR | EVNT_RISE | EVNT_SINGLE; + evnt |= (CAL_EVENT & EVNT_SEL_MASK) << EVNT_SEL_SHIFT; + evnt |= (cal_gpio & EVNT_GPIO_MASK) << EVNT_GPIO_SHIFT; + + list_for_each(this, &clock->phylist) { + tmp = list_entry(this, struct dp83640_private, list); + ext_write(0, tmp->phydev, PAGE5, PTP_EVNT, evnt); + } + ext_write(0, master, PAGE5, PTP_EVNT, evnt); + + /* + * configure a trigger + */ + ptp_trig = TRIG_WR | TRIG_IF_LATE | TRIG_PULSE; + ptp_trig |= (trigger & TRIG_CSEL_MASK) << TRIG_CSEL_SHIFT; + ptp_trig |= (cal_gpio & TRIG_GPIO_MASK) << TRIG_GPIO_SHIFT; + ext_write(0, master, PAGE5, PTP_TRIG, ptp_trig); + + /* load trigger */ + val = (trigger & TRIG_SEL_MASK) << TRIG_SEL_SHIFT; + val |= TRIG_LOAD; + ext_write(0, master, PAGE4, PTP_CTL, val); + + /* enable trigger */ + val &= ~TRIG_LOAD; + val |= TRIG_EN; + ext_write(0, master, PAGE4, PTP_CTL, val); + + /* disable trigger */ + val = (trigger & TRIG_SEL_MASK) << TRIG_SEL_SHIFT; + val |= TRIG_DIS; + ext_write(0, master, PAGE4, PTP_CTL, val); + + /* + * read out and correct offsets + */ + val = ext_read(master, PAGE4, PTP_STS); + pr_info("master PTP_STS 0x%04hx", val); + val = ext_read(master, PAGE4, PTP_ESTS); + pr_info("master PTP_ESTS 0x%04hx", val); + event_ts.ns_lo = ext_read(master, PAGE4, PTP_EDATA); + event_ts.ns_hi = ext_read(master, PAGE4, PTP_EDATA); + event_ts.sec_lo = ext_read(master, PAGE4, PTP_EDATA); + event_ts.sec_hi = ext_read(master, PAGE4, PTP_EDATA); + now = phy2txts(&event_ts); + + list_for_each(this, &clock->phylist) { + tmp = list_entry(this, struct dp83640_private, list); + val = ext_read(tmp->phydev, PAGE4, PTP_STS); + pr_info("slave PTP_STS 0x%04hx", val); + val = ext_read(tmp->phydev, PAGE4, PTP_ESTS); + pr_info("slave PTP_ESTS 0x%04hx", val); + event_ts.ns_lo = ext_read(tmp->phydev, PAGE4, PTP_EDATA); + event_ts.ns_hi = ext_read(tmp->phydev, PAGE4, PTP_EDATA); + event_ts.sec_lo = ext_read(tmp->phydev, PAGE4, PTP_EDATA); + event_ts.sec_hi = ext_read(tmp->phydev, PAGE4, PTP_EDATA); + diff = now - (s64) phy2txts(&event_ts); + pr_info("slave offset %lld nanoseconds\n", diff); + diff += ADJTIME_FIX; + ts = ns_to_timespec(diff); + tdr_write(0, tmp->phydev, &ts, PTP_STEP_CLK); + } + + /* + * restore status frames + */ + list_for_each(this, &clock->phylist) { + tmp = list_entry(this, struct dp83640_private, list); + ext_write(0, tmp->phydev, PAGE5, PSF_CFG0, tmp->cfg0); + } + ext_write(0, master, PAGE5, PSF_CFG0, cfg0); + + mutex_unlock(&clock->extreg_lock); +} + +/* time stamping methods */ + +static void decode_evnt(struct dp83640_private *dp83640, + struct phy_txts *phy_txts, u16 ests) +{ + struct ptp_clock_event event; + int words = (ests >> EVNT_TS_LEN_SHIFT) & EVNT_TS_LEN_MASK; + + switch (words) { /* fall through in every case */ + case 3: + dp83640->edata.sec_hi = phy_txts->sec_hi; + case 2: + dp83640->edata.sec_lo = phy_txts->sec_lo; + case 1: + dp83640->edata.ns_hi = phy_txts->ns_hi; + case 0: + dp83640->edata.ns_lo = phy_txts->ns_lo; + } + + event.type = PTP_CLOCK_EXTTS; + event.index = 0; + event.timestamp = phy2txts(&dp83640->edata); + + ptp_clock_event(dp83640->clock->ptp_clock, &event); +} + +static void decode_rxts(struct dp83640_private *dp83640, + struct phy_rxts *phy_rxts) +{ + struct rxts *rxts; + unsigned long flags; + + spin_lock_irqsave(&dp83640->rx_lock, flags); + + prune_rx_ts(dp83640); + + if (list_empty(&dp83640->rxpool)) { + pr_warning("dp83640: rx timestamp pool is empty\n"); + goto out; + } + rxts = list_first_entry(&dp83640->rxpool, struct rxts, list); + list_del_init(&rxts->list); + phy2rxts(phy_rxts, rxts); + list_add_tail(&rxts->list, &dp83640->rxts); +out: + spin_unlock_irqrestore(&dp83640->rx_lock, flags); +} + +static void decode_txts(struct dp83640_private *dp83640, + struct phy_txts *phy_txts) +{ + struct skb_shared_hwtstamps shhwtstamps; + struct sk_buff *skb; + u64 ns; + + /* We must already have the skb that triggered this. */ + + skb = skb_dequeue(&dp83640->tx_queue); + + if (!skb) { + pr_warning("dp83640: have timestamp but tx_queue empty\n"); + return; + } + ns = phy2txts(phy_txts); + memset(&shhwtstamps, 0, sizeof(shhwtstamps)); + shhwtstamps.hwtstamp = ns_to_ktime(ns); + skb_complete_tx_timestamp(skb, &shhwtstamps); +} + +static void decode_status_frame(struct dp83640_private *dp83640, + struct sk_buff *skb) +{ + struct phy_rxts *phy_rxts; + struct phy_txts *phy_txts; + u8 *ptr; + int len, size; + u16 ests, type; + + ptr = skb->data + 2; + + for (len = skb_headlen(skb) - 2; len > sizeof(type); len -= size) { + + type = *(u16 *)ptr; + ests = type & 0x0fff; + type = type & 0xf000; + len -= sizeof(type); + ptr += sizeof(type); + + if (PSF_RX == type && len >= sizeof(*phy_rxts)) { + + phy_rxts = (struct phy_rxts *) ptr; + decode_rxts(dp83640, phy_rxts); + size = sizeof(*phy_rxts); + + } else if (PSF_TX == type && len >= sizeof(*phy_txts)) { + + phy_txts = (struct phy_txts *) ptr; + decode_txts(dp83640, phy_txts); + size = sizeof(*phy_txts); + + } else if (PSF_EVNT == type && len >= sizeof(*phy_txts)) { + + phy_txts = (struct phy_txts *) ptr; + decode_evnt(dp83640, phy_txts, ests); + size = sizeof(*phy_txts); + + } else { + size = 0; + break; + } + ptr += size; + } +} + +static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts) +{ + u16 *seqid; + unsigned int offset; + u8 *msgtype, *data = skb_mac_header(skb); + + /* check sequenceID, messageType, 12 bit hash of offset 20-29 */ + + switch (type) { + case PTP_CLASS_V1_IPV4: + case PTP_CLASS_V2_IPV4: + offset = ETH_HLEN + IPV4_HLEN(data) + UDP_HLEN; + break; + case PTP_CLASS_V1_IPV6: + case PTP_CLASS_V2_IPV6: + offset = OFF_PTP6; + break; + case PTP_CLASS_V2_L2: + offset = ETH_HLEN; + break; + case PTP_CLASS_V2_VLAN: + offset = ETH_HLEN + VLAN_HLEN; + break; + default: + return 0; + } + + if (skb->len + ETH_HLEN < offset + OFF_PTP_SEQUENCE_ID + sizeof(*seqid)) + return 0; + + if (unlikely(type & PTP_CLASS_V1)) + msgtype = data + offset + OFF_PTP_CONTROL; + else + msgtype = data + offset; + + seqid = (u16 *)(data + offset + OFF_PTP_SEQUENCE_ID); + + return (rxts->msgtype == (*msgtype & 0xf) && + rxts->seqid == ntohs(*seqid)); +} + +static void dp83640_free_clocks(void) +{ + struct dp83640_clock *clock; + struct list_head *this, *next; + + mutex_lock(&phyter_clocks_lock); + + list_for_each_safe(this, next, &phyter_clocks) { + clock = list_entry(this, struct dp83640_clock, list); + if (!list_empty(&clock->phylist)) { + pr_warning("phy list non-empty while unloading"); + BUG(); + } + list_del(&clock->list); + mutex_destroy(&clock->extreg_lock); + mutex_destroy(&clock->clock_lock); + put_device(&clock->bus->dev); + kfree(clock); + } + + mutex_unlock(&phyter_clocks_lock); +} + +static void dp83640_clock_init(struct dp83640_clock *clock, struct mii_bus *bus) +{ + INIT_LIST_HEAD(&clock->list); + clock->bus = bus; + mutex_init(&clock->extreg_lock); + mutex_init(&clock->clock_lock); + INIT_LIST_HEAD(&clock->phylist); + clock->caps.owner = THIS_MODULE; + sprintf(clock->caps.name, "dp83640 timer"); + clock->caps.max_adj = 1953124; + clock->caps.n_alarm = 0; + clock->caps.n_ext_ts = N_EXT_TS; + clock->caps.n_per_out = 0; + clock->caps.pps = 0; + clock->caps.adjfreq = ptp_dp83640_adjfreq; + clock->caps.adjtime = ptp_dp83640_adjtime; + clock->caps.gettime = ptp_dp83640_gettime; + clock->caps.settime = ptp_dp83640_settime; + clock->caps.enable = ptp_dp83640_enable; + /* + * Get a reference to this bus instance. + */ + get_device(&bus->dev); +} + +static int choose_this_phy(struct dp83640_clock *clock, + struct phy_device *phydev) +{ + if (chosen_phy == -1 && !clock->chosen) + return 1; + + if (chosen_phy == phydev->addr) + return 1; + + return 0; +} + +static struct dp83640_clock *dp83640_clock_get(struct dp83640_clock *clock) +{ + if (clock) + mutex_lock(&clock->clock_lock); + return clock; +} + +/* + * Look up and lock a clock by bus instance. + * If there is no clock for this bus, then create it first. + */ +static struct dp83640_clock *dp83640_clock_get_bus(struct mii_bus *bus) +{ + struct dp83640_clock *clock = NULL, *tmp; + struct list_head *this; + + mutex_lock(&phyter_clocks_lock); + + list_for_each(this, &phyter_clocks) { + tmp = list_entry(this, struct dp83640_clock, list); + if (tmp->bus == bus) { + clock = tmp; + break; + } + } + if (clock) + goto out; + + clock = kzalloc(sizeof(struct dp83640_clock), GFP_KERNEL); + if (!clock) + goto out; + + dp83640_clock_init(clock, bus); + list_add_tail(&phyter_clocks, &clock->list); +out: + mutex_unlock(&phyter_clocks_lock); + + return dp83640_clock_get(clock); +} + +static void dp83640_clock_put(struct dp83640_clock *clock) +{ + mutex_unlock(&clock->clock_lock); +} + +static int dp83640_probe(struct phy_device *phydev) +{ + struct dp83640_clock *clock; + struct dp83640_private *dp83640; + int err = -ENOMEM, i; + + if (phydev->addr == BROADCAST_ADDR) + return 0; + + clock = dp83640_clock_get_bus(phydev->bus); + if (!clock) + goto no_clock; + + dp83640 = kzalloc(sizeof(struct dp83640_private), GFP_KERNEL); + if (!dp83640) + goto no_memory; + + dp83640->phydev = phydev; + INIT_WORK(&dp83640->ts_work, rx_timestamp_work); + + INIT_LIST_HEAD(&dp83640->rxts); + INIT_LIST_HEAD(&dp83640->rxpool); + for (i = 0; i < MAX_RXTS; i++) + list_add(&dp83640->rx_pool_data[i].list, &dp83640->rxpool); + + phydev->priv = dp83640; + + spin_lock_init(&dp83640->rx_lock); + skb_queue_head_init(&dp83640->rx_queue); + skb_queue_head_init(&dp83640->tx_queue); + + dp83640->clock = clock; + + if (choose_this_phy(clock, phydev)) { + clock->chosen = dp83640; + clock->ptp_clock = ptp_clock_register(&clock->caps); + if (IS_ERR(clock->ptp_clock)) { + err = PTR_ERR(clock->ptp_clock); + goto no_register; + } + } else + list_add_tail(&dp83640->list, &clock->phylist); + + if (clock->chosen && !list_empty(&clock->phylist)) + recalibrate(clock); + else + enable_broadcast(dp83640->phydev, clock->page, 1); + + dp83640_clock_put(clock); + return 0; + +no_register: + clock->chosen = NULL; + kfree(dp83640); +no_memory: + dp83640_clock_put(clock); +no_clock: + return err; +} + +static void dp83640_remove(struct phy_device *phydev) +{ + struct dp83640_clock *clock; + struct list_head *this, *next; + struct dp83640_private *tmp, *dp83640 = phydev->priv; + + if (phydev->addr == BROADCAST_ADDR) + return; + + enable_status_frames(phydev, false); + cancel_work_sync(&dp83640->ts_work); + + clock = dp83640_clock_get(dp83640->clock); + + if (dp83640 == clock->chosen) { + ptp_clock_unregister(clock->ptp_clock); + clock->chosen = NULL; + } else { + list_for_each_safe(this, next, &clock->phylist) { + tmp = list_entry(this, struct dp83640_private, list); + if (tmp == dp83640) { + list_del_init(&tmp->list); + break; + } + } + } + + dp83640_clock_put(clock); + kfree(dp83640); +} + +static int dp83640_hwtstamp(struct phy_device *phydev, struct ifreq *ifr) +{ + struct dp83640_private *dp83640 = phydev->priv; + struct hwtstamp_config cfg; + u16 txcfg0, rxcfg0; + + if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) + return -EFAULT; + + if (cfg.flags) /* reserved for future extensions */ + return -EINVAL; + + switch (cfg.tx_type) { + case HWTSTAMP_TX_OFF: + dp83640->hwts_tx_en = 0; + break; + case HWTSTAMP_TX_ON: + dp83640->hwts_tx_en = 1; + break; + default: + return -ERANGE; + } + + switch (cfg.rx_filter) { + case HWTSTAMP_FILTER_NONE: + dp83640->hwts_rx_en = 0; + dp83640->layer = 0; + dp83640->version = 0; + break; + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + dp83640->hwts_rx_en = 1; + dp83640->layer = LAYER4; + dp83640->version = 1; + break; + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + dp83640->hwts_rx_en = 1; + dp83640->layer = LAYER4; + dp83640->version = 2; + break; + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: + dp83640->hwts_rx_en = 1; + dp83640->layer = LAYER2; + dp83640->version = 2; + break; + case HWTSTAMP_FILTER_PTP_V2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + dp83640->hwts_rx_en = 1; + dp83640->layer = LAYER4|LAYER2; + dp83640->version = 2; + break; + default: + return -ERANGE; + } + + txcfg0 = (dp83640->version & TX_PTP_VER_MASK) << TX_PTP_VER_SHIFT; + rxcfg0 = (dp83640->version & TX_PTP_VER_MASK) << TX_PTP_VER_SHIFT; + + if (dp83640->layer & LAYER2) { + txcfg0 |= TX_L2_EN; + rxcfg0 |= RX_L2_EN; + } + if (dp83640->layer & LAYER4) { + txcfg0 |= TX_IPV6_EN | TX_IPV4_EN; + rxcfg0 |= RX_IPV6_EN | RX_IPV4_EN; + } + + if (dp83640->hwts_tx_en) + txcfg0 |= TX_TS_EN; + + if (dp83640->hwts_rx_en) + rxcfg0 |= RX_TS_EN; + + mutex_lock(&dp83640->clock->extreg_lock); + + if (dp83640->hwts_tx_en || dp83640->hwts_rx_en) { + enable_status_frames(phydev, true); + ext_write(0, phydev, PAGE4, PTP_CTL, PTP_ENABLE); + } + + ext_write(0, phydev, PAGE5, PTP_TXCFG0, txcfg0); + ext_write(0, phydev, PAGE5, PTP_RXCFG0, rxcfg0); + + mutex_unlock(&dp83640->clock->extreg_lock); + + return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; +} + +static void rx_timestamp_work(struct work_struct *work) +{ + struct dp83640_private *dp83640 = + container_of(work, struct dp83640_private, ts_work); + struct list_head *this, *next; + struct rxts *rxts; + struct skb_shared_hwtstamps *shhwtstamps; + struct sk_buff *skb; + unsigned int type; + unsigned long flags; + + /* Deliver each deferred packet, with or without a time stamp. */ + + while ((skb = skb_dequeue(&dp83640->rx_queue)) != NULL) { + type = SKB_PTP_TYPE(skb); + spin_lock_irqsave(&dp83640->rx_lock, flags); + list_for_each_safe(this, next, &dp83640->rxts) { + rxts = list_entry(this, struct rxts, list); + if (match(skb, type, rxts)) { + shhwtstamps = skb_hwtstamps(skb); + memset(shhwtstamps, 0, sizeof(*shhwtstamps)); + shhwtstamps->hwtstamp = ns_to_ktime(rxts->ns); + list_del_init(&rxts->list); + list_add(&rxts->list, &dp83640->rxpool); + break; + } + } + spin_unlock_irqrestore(&dp83640->rx_lock, flags); + netif_rx(skb); + } + + /* Clear out expired time stamps. */ + + spin_lock_irqsave(&dp83640->rx_lock, flags); + prune_rx_ts(dp83640); + spin_unlock_irqrestore(&dp83640->rx_lock, flags); +} + +static bool dp83640_rxtstamp(struct phy_device *phydev, + struct sk_buff *skb, int type) +{ + struct dp83640_private *dp83640 = phydev->priv; + + if (!dp83640->hwts_rx_en) + return false; + + if (is_status_frame(skb, type)) { + decode_status_frame(dp83640, skb); + /* Let the stack drop this frame. */ + return false; + } + + SKB_PTP_TYPE(skb) = type; + skb_queue_tail(&dp83640->rx_queue, skb); + schedule_work(&dp83640->ts_work); + + return true; +} + +static void dp83640_txtstamp(struct phy_device *phydev, + struct sk_buff *skb, int type) +{ + struct dp83640_private *dp83640 = phydev->priv; + + if (!dp83640->hwts_tx_en) { + kfree_skb(skb); + return; + } + skb_queue_tail(&dp83640->tx_queue, skb); + schedule_work(&dp83640->ts_work); +} + +static struct phy_driver dp83640_driver = { + .phy_id = DP83640_PHY_ID, + .phy_id_mask = 0xfffffff0, + .name = "NatSemi DP83640", + .features = PHY_BASIC_FEATURES, + .flags = 0, + .probe = dp83640_probe, + .remove = dp83640_remove, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .hwtstamp = dp83640_hwtstamp, + .rxtstamp = dp83640_rxtstamp, + .txtstamp = dp83640_txtstamp, + .driver = {.owner = THIS_MODULE,} +}; + +static int __init dp83640_init(void) +{ + return phy_driver_register(&dp83640_driver); +} + +static void __exit dp83640_exit(void) +{ + dp83640_free_clocks(); + phy_driver_unregister(&dp83640_driver); +} + +MODULE_DESCRIPTION("National Semiconductor DP83640 PHY driver"); +MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>"); +MODULE_LICENSE("GPL"); + +module_init(dp83640_init); +module_exit(dp83640_exit); + +static struct mdio_device_id __maybe_unused dp83640_tbl[] = { + { DP83640_PHY_ID, 0xfffffff0 }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, dp83640_tbl); diff --git a/drivers/net/phy/dp83640_reg.h b/drivers/net/phy/dp83640_reg.h new file mode 100644 index 000000000000..e7fe41117003 --- /dev/null +++ b/drivers/net/phy/dp83640_reg.h @@ -0,0 +1,267 @@ +/* dp83640_reg.h + * Generated by regen.tcl on Thu Feb 17 10:02:48 AM CET 2011 + */ +#ifndef HAVE_DP83640_REGISTERS +#define HAVE_DP83640_REGISTERS + +#define PAGE0 0x0000 +#define PHYCR2 0x001c /* PHY Control Register 2 */ + +#define PAGE4 0x0004 +#define PTP_CTL 0x0014 /* PTP Control Register */ +#define PTP_TDR 0x0015 /* PTP Time Data Register */ +#define PTP_STS 0x0016 /* PTP Status Register */ +#define PTP_TSTS 0x0017 /* PTP Trigger Status Register */ +#define PTP_RATEL 0x0018 /* PTP Rate Low Register */ +#define PTP_RATEH 0x0019 /* PTP Rate High Register */ +#define PTP_RDCKSUM 0x001a /* PTP Read Checksum */ +#define PTP_WRCKSUM 0x001b /* PTP Write Checksum */ +#define PTP_TXTS 0x001c /* PTP Transmit Timestamp Register, in four 16-bit reads */ +#define PTP_RXTS 0x001d /* PTP Receive Timestamp Register, in six? 16-bit reads */ +#define PTP_ESTS 0x001e /* PTP Event Status Register */ +#define PTP_EDATA 0x001f /* PTP Event Data Register */ + +#define PAGE5 0x0005 +#define PTP_TRIG 0x0014 /* PTP Trigger Configuration Register */ +#define PTP_EVNT 0x0015 /* PTP Event Configuration Register */ +#define PTP_TXCFG0 0x0016 /* PTP Transmit Configuration Register 0 */ +#define PTP_TXCFG1 0x0017 /* PTP Transmit Configuration Register 1 */ +#define PSF_CFG0 0x0018 /* PHY Status Frame Configuration Register 0 */ +#define PTP_RXCFG0 0x0019 /* PTP Receive Configuration Register 0 */ +#define PTP_RXCFG1 0x001a /* PTP Receive Configuration Register 1 */ +#define PTP_RXCFG2 0x001b /* PTP Receive Configuration Register 2 */ +#define PTP_RXCFG3 0x001c /* PTP Receive Configuration Register 3 */ +#define PTP_RXCFG4 0x001d /* PTP Receive Configuration Register 4 */ +#define PTP_TRDL 0x001e /* PTP Temporary Rate Duration Low Register */ +#define PTP_TRDH 0x001f /* PTP Temporary Rate Duration High Register */ + +#define PAGE6 0x0006 +#define PTP_COC 0x0014 /* PTP Clock Output Control Register */ +#define PSF_CFG1 0x0015 /* PHY Status Frame Configuration Register 1 */ +#define PSF_CFG2 0x0016 /* PHY Status Frame Configuration Register 2 */ +#define PSF_CFG3 0x0017 /* PHY Status Frame Configuration Register 3 */ +#define PSF_CFG4 0x0018 /* PHY Status Frame Configuration Register 4 */ +#define PTP_SFDCFG 0x0019 /* PTP SFD Configuration Register */ +#define PTP_INTCTL 0x001a /* PTP Interrupt Control Register */ +#define PTP_CLKSRC 0x001b /* PTP Clock Source Register */ +#define PTP_ETR 0x001c /* PTP Ethernet Type Register */ +#define PTP_OFF 0x001d /* PTP Offset Register */ +#define PTP_GPIOMON 0x001e /* PTP GPIO Monitor Register */ +#define PTP_RXHASH 0x001f /* PTP Receive Hash Register */ + +/* Bit definitions for the PHYCR2 register */ +#define BC_WRITE (1<<11) /* Broadcast Write Enable */ + +/* Bit definitions for the PTP_CTL register */ +#define TRIG_SEL_SHIFT (10) /* PTP Trigger Select */ +#define TRIG_SEL_MASK (0x7) +#define TRIG_DIS (1<<9) /* Disable PTP Trigger */ +#define TRIG_EN (1<<8) /* Enable PTP Trigger */ +#define TRIG_READ (1<<7) /* Read PTP Trigger */ +#define TRIG_LOAD (1<<6) /* Load PTP Trigger */ +#define PTP_RD_CLK (1<<5) /* Read PTP Clock */ +#define PTP_LOAD_CLK (1<<4) /* Load PTP Clock */ +#define PTP_STEP_CLK (1<<3) /* Step PTP Clock */ +#define PTP_ENABLE (1<<2) /* Enable PTP Clock */ +#define PTP_DISABLE (1<<1) /* Disable PTP Clock */ +#define PTP_RESET (1<<0) /* Reset PTP Clock */ + +/* Bit definitions for the PTP_STS register */ +#define TXTS_RDY (1<<11) /* Transmit Timestamp Ready */ +#define RXTS_RDY (1<<10) /* Receive Timestamp Ready */ +#define TRIG_DONE (1<<9) /* PTP Trigger Done */ +#define EVENT_RDY (1<<8) /* PTP Event Timestamp Ready */ +#define TXTS_IE (1<<3) /* Transmit Timestamp Interrupt Enable */ +#define RXTS_IE (1<<2) /* Receive Timestamp Interrupt Enable */ +#define TRIG_IE (1<<1) /* Trigger Interrupt Enable */ +#define EVENT_IE (1<<0) /* Event Interrupt Enable */ + +/* Bit definitions for the PTP_TSTS register */ +#define TRIG7_ERROR (1<<15) /* Trigger 7 Error */ +#define TRIG7_ACTIVE (1<<14) /* Trigger 7 Active */ +#define TRIG6_ERROR (1<<13) /* Trigger 6 Error */ +#define TRIG6_ACTIVE (1<<12) /* Trigger 6 Active */ +#define TRIG5_ERROR (1<<11) /* Trigger 5 Error */ +#define TRIG5_ACTIVE (1<<10) /* Trigger 5 Active */ +#define TRIG4_ERROR (1<<9) /* Trigger 4 Error */ +#define TRIG4_ACTIVE (1<<8) /* Trigger 4 Active */ +#define TRIG3_ERROR (1<<7) /* Trigger 3 Error */ +#define TRIG3_ACTIVE (1<<6) /* Trigger 3 Active */ +#define TRIG2_ERROR (1<<5) /* Trigger 2 Error */ +#define TRIG2_ACTIVE (1<<4) /* Trigger 2 Active */ +#define TRIG1_ERROR (1<<3) /* Trigger 1 Error */ +#define TRIG1_ACTIVE (1<<2) /* Trigger 1 Active */ +#define TRIG0_ERROR (1<<1) /* Trigger 0 Error */ +#define TRIG0_ACTIVE (1<<0) /* Trigger 0 Active */ + +/* Bit definitions for the PTP_RATEH register */ +#define PTP_RATE_DIR (1<<15) /* PTP Rate Direction */ +#define PTP_TMP_RATE (1<<14) /* PTP Temporary Rate */ +#define PTP_RATE_HI_SHIFT (0) /* PTP Rate High 10-bits */ +#define PTP_RATE_HI_MASK (0x3ff) + +/* Bit definitions for the PTP_ESTS register */ +#define EVNTS_MISSED_SHIFT (8) /* Indicates number of events missed */ +#define EVNTS_MISSED_MASK (0x7) +#define EVNT_TS_LEN_SHIFT (6) /* Indicates length of the Timestamp field in 16-bit words minus 1 */ +#define EVNT_TS_LEN_MASK (0x3) +#define EVNT_RF (1<<5) /* Indicates whether the event is a rise or falling event */ +#define EVNT_NUM_SHIFT (2) /* Indicates Event Timestamp Unit which detected an event */ +#define EVNT_NUM_MASK (0x7) +#define MULT_EVNT (1<<1) /* Indicates multiple events were detected at the same time */ +#define EVENT_DET (1<<0) /* PTP Event Detected */ + +/* Bit definitions for the PTP_EDATA register */ +#define E7_RISE (1<<15) /* Indicates direction of Event 7 */ +#define E7_DET (1<<14) /* Indicates Event 7 detected */ +#define E6_RISE (1<<13) /* Indicates direction of Event 6 */ +#define E6_DET (1<<12) /* Indicates Event 6 detected */ +#define E5_RISE (1<<11) /* Indicates direction of Event 5 */ +#define E5_DET (1<<10) /* Indicates Event 5 detected */ +#define E4_RISE (1<<9) /* Indicates direction of Event 4 */ +#define E4_DET (1<<8) /* Indicates Event 4 detected */ +#define E3_RISE (1<<7) /* Indicates direction of Event 3 */ +#define E3_DET (1<<6) /* Indicates Event 3 detected */ +#define E2_RISE (1<<5) /* Indicates direction of Event 2 */ +#define E2_DET (1<<4) /* Indicates Event 2 detected */ +#define E1_RISE (1<<3) /* Indicates direction of Event 1 */ +#define E1_DET (1<<2) /* Indicates Event 1 detected */ +#define E0_RISE (1<<1) /* Indicates direction of Event 0 */ +#define E0_DET (1<<0) /* Indicates Event 0 detected */ + +/* Bit definitions for the PTP_TRIG register */ +#define TRIG_PULSE (1<<15) /* generate a Pulse rather than a single edge */ +#define TRIG_PER (1<<14) /* generate a periodic signal */ +#define TRIG_IF_LATE (1<<13) /* trigger immediately if already past */ +#define TRIG_NOTIFY (1<<12) /* Trigger Notification Enable */ +#define TRIG_GPIO_SHIFT (8) /* Trigger GPIO Connection, value 1-12 */ +#define TRIG_GPIO_MASK (0xf) +#define TRIG_TOGGLE (1<<7) /* Trigger Toggle Mode Enable */ +#define TRIG_CSEL_SHIFT (1) /* Trigger Configuration Select */ +#define TRIG_CSEL_MASK (0x7) +#define TRIG_WR (1<<0) /* Trigger Configuration Write */ + +/* Bit definitions for the PTP_EVNT register */ +#define EVNT_RISE (1<<14) /* Event Rise Detect Enable */ +#define EVNT_FALL (1<<13) /* Event Fall Detect Enable */ +#define EVNT_SINGLE (1<<12) /* enable single event capture operation */ +#define EVNT_GPIO_SHIFT (8) /* Event GPIO Connection, value 1-12 */ +#define EVNT_GPIO_MASK (0xf) +#define EVNT_SEL_SHIFT (1) /* Event Select */ +#define EVNT_SEL_MASK (0x7) +#define EVNT_WR (1<<0) /* Event Configuration Write */ + +/* Bit definitions for the PTP_TXCFG0 register */ +#define SYNC_1STEP (1<<15) /* insert timestamp into transmit Sync Messages */ +#define DR_INSERT (1<<13) /* Insert Delay_Req Timestamp in Delay_Resp (dangerous) */ +#define NTP_TS_EN (1<<12) /* Enable Timestamping of NTP Packets */ +#define IGNORE_2STEP (1<<11) /* Ignore Two_Step flag for One-Step operation */ +#define CRC_1STEP (1<<10) /* Disable checking of CRC for One-Step operation */ +#define CHK_1STEP (1<<9) /* Enable UDP Checksum correction for One-Step Operation */ +#define IP1588_EN (1<<8) /* Enable IEEE 1588 defined IP address filter */ +#define TX_L2_EN (1<<7) /* Layer2 Timestamp Enable */ +#define TX_IPV6_EN (1<<6) /* IPv6 Timestamp Enable */ +#define TX_IPV4_EN (1<<5) /* IPv4 Timestamp Enable */ +#define TX_PTP_VER_SHIFT (1) /* Enable Timestamp capture for IEEE 1588 version X */ +#define TX_PTP_VER_MASK (0xf) +#define TX_TS_EN (1<<0) /* Transmit Timestamp Enable */ + +/* Bit definitions for the PTP_TXCFG1 register */ +#define BYTE0_MASK_SHIFT (8) /* Bit mask to be used for matching Byte0 of the PTP Message */ +#define BYTE0_MASK_MASK (0xff) +#define BYTE0_DATA_SHIFT (0) /* Data to be used for matching Byte0 of the PTP Message */ +#define BYTE0_DATA_MASK (0xff) + +/* Bit definitions for the PSF_CFG0 register */ +#define MAC_SRC_ADD_SHIFT (11) /* Status Frame Mac Source Address */ +#define MAC_SRC_ADD_MASK (0x3) +#define MIN_PRE_SHIFT (8) /* Status Frame Minimum Preamble */ +#define MIN_PRE_MASK (0x7) +#define PSF_ENDIAN (1<<7) /* Status Frame Endian Control */ +#define PSF_IPV4 (1<<6) /* Status Frame IPv4 Enable */ +#define PSF_PCF_RD (1<<5) /* Control Frame Read PHY Status Frame Enable */ +#define PSF_ERR_EN (1<<4) /* Error PHY Status Frame Enable */ +#define PSF_TXTS_EN (1<<3) /* Transmit Timestamp PHY Status Frame Enable */ +#define PSF_RXTS_EN (1<<2) /* Receive Timestamp PHY Status Frame Enable */ +#define PSF_TRIG_EN (1<<1) /* Trigger PHY Status Frame Enable */ +#define PSF_EVNT_EN (1<<0) /* Event PHY Status Frame Enable */ + +/* Bit definitions for the PTP_RXCFG0 register */ +#define DOMAIN_EN (1<<15) /* Domain Match Enable */ +#define ALT_MAST_DIS (1<<14) /* Alternate Master Timestamp Disable */ +#define USER_IP_SEL (1<<13) /* Selects portion of IP address accessible thru PTP_RXCFG2 */ +#define USER_IP_EN (1<<12) /* Enable User-programmed IP address filter */ +#define RX_SLAVE (1<<11) /* Receive Slave Only */ +#define IP1588_EN_SHIFT (8) /* Enable IEEE 1588 defined IP address filters */ +#define IP1588_EN_MASK (0xf) +#define RX_L2_EN (1<<7) /* Layer2 Timestamp Enable */ +#define RX_IPV6_EN (1<<6) /* IPv6 Timestamp Enable */ +#define RX_IPV4_EN (1<<5) /* IPv4 Timestamp Enable */ +#define RX_PTP_VER_SHIFT (1) /* Enable Timestamp capture for IEEE 1588 version X */ +#define RX_PTP_VER_MASK (0xf) +#define RX_TS_EN (1<<0) /* Receive Timestamp Enable */ + +/* Bit definitions for the PTP_RXCFG1 register */ +#define BYTE0_MASK_SHIFT (8) /* Bit mask to be used for matching Byte0 of the PTP Message */ +#define BYTE0_MASK_MASK (0xff) +#define BYTE0_DATA_SHIFT (0) /* Data to be used for matching Byte0 of the PTP Message */ +#define BYTE0_DATA_MASK (0xff) + +/* Bit definitions for the PTP_RXCFG3 register */ +#define TS_MIN_IFG_SHIFT (12) /* Minimum Inter-frame Gap */ +#define TS_MIN_IFG_MASK (0xf) +#define ACC_UDP (1<<11) /* Record Timestamp if UDP Checksum Error */ +#define ACC_CRC (1<<10) /* Record Timestamp if CRC Error */ +#define TS_APPEND (1<<9) /* Append Timestamp for L2 */ +#define TS_INSERT (1<<8) /* Enable Timestamp Insertion */ +#define PTP_DOMAIN_SHIFT (0) /* PTP Message domainNumber field */ +#define PTP_DOMAIN_MASK (0xff) + +/* Bit definitions for the PTP_RXCFG4 register */ +#define IPV4_UDP_MOD (1<<15) /* Enable IPV4 UDP Modification */ +#define TS_SEC_EN (1<<14) /* Enable Timestamp Seconds */ +#define TS_SEC_LEN_SHIFT (12) /* Inserted Timestamp Seconds Length */ +#define TS_SEC_LEN_MASK (0x3) +#define RXTS_NS_OFF_SHIFT (6) /* Receive Timestamp Nanoseconds offset */ +#define RXTS_NS_OFF_MASK (0x3f) +#define RXTS_SEC_OFF_SHIFT (0) /* Receive Timestamp Seconds offset */ +#define RXTS_SEC_OFF_MASK (0x3f) + +/* Bit definitions for the PTP_COC register */ +#define PTP_CLKOUT_EN (1<<15) /* PTP Clock Output Enable */ +#define PTP_CLKOUT_SEL (1<<14) /* PTP Clock Output Source Select */ +#define PTP_CLKOUT_SPEEDSEL (1<<13) /* PTP Clock Output I/O Speed Select */ +#define PTP_CLKDIV_SHIFT (0) /* PTP Clock Divide-by Value */ +#define PTP_CLKDIV_MASK (0xff) + +/* Bit definitions for the PSF_CFG1 register */ +#define PTPRESERVED_SHIFT (12) /* PTP v2 reserved field */ +#define PTPRESERVED_MASK (0xf) +#define VERSIONPTP_SHIFT (8) /* PTP v2 versionPTP field */ +#define VERSIONPTP_MASK (0xf) +#define TRANSPORT_SPECIFIC_SHIFT (4) /* PTP v2 Header transportSpecific field */ +#define TRANSPORT_SPECIFIC_MASK (0xf) +#define MESSAGETYPE_SHIFT (0) /* PTP v2 messageType field */ +#define MESSAGETYPE_MASK (0xf) + +/* Bit definitions for the PTP_SFDCFG register */ +#define TX_SFD_GPIO_SHIFT (4) /* TX SFD GPIO Select, value 1-12 */ +#define TX_SFD_GPIO_MASK (0xf) +#define RX_SFD_GPIO_SHIFT (0) /* RX SFD GPIO Select, value 1-12 */ +#define RX_SFD_GPIO_MASK (0xf) + +/* Bit definitions for the PTP_INTCTL register */ +#define PTP_INT_GPIO_SHIFT (0) /* PTP Interrupt GPIO Select */ +#define PTP_INT_GPIO_MASK (0xf) + +/* Bit definitions for the PTP_CLKSRC register */ +#define CLK_SRC_SHIFT (14) /* PTP Clock Source Select */ +#define CLK_SRC_MASK (0x3) +#define CLK_SRC_PER_SHIFT (0) /* PTP Clock Source Period */ +#define CLK_SRC_PER_MASK (0x7f) + +/* Bit definitions for the PTP_OFF register */ +#define PTP_OFFSET_SHIFT (0) /* PTP Message offset from preceding header */ +#define PTP_OFFSET_MASK (0xff) + +#endif diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index a1b82c9c67d2..6436ba916fe4 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c @@ -30,6 +30,7 @@ #include <linux/ppp_channel.h> #include <linux/spinlock.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/jiffies.h> #include <linux/slab.h> #include <asm/unaligned.h> diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c index 2573f525f11c..736a39ee05bb 100644 --- a/drivers/net/ppp_synctty.c +++ b/drivers/net/ppp_synctty.c @@ -44,6 +44,7 @@ #include <linux/spinlock.h> #include <linux/completion.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/slab.h> #include <asm/unaligned.h> #include <asm/uaccess.h> diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index b1f251da1535..35e47c3cab35 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -28,6 +28,7 @@ #undef DEBUG +#include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> @@ -1009,7 +1010,7 @@ static int gelic_card_decode_one_descr(struct gelic_card *card) netdev = card->netdev[i]; break; } - }; + } if (GELIC_PORT_MAX <= i) { pr_info("%s: unknown packet vid=%x\n", __func__, vid); goto refill; diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index d32850715f5c..7d8483f9012e 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -7,6 +7,7 @@ #ifndef _QLGE_H_ #define _QLGE_H_ +#include <linux/interrupt.h> #include <linux/pci.h> #include <linux/netdevice.h> #include <linux/rtnetlink.h> diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c index 19b00fa0eaf0..9b67bfea035f 100644 --- a/drivers/net/qlge/qlge_ethtool.c +++ b/drivers/net/qlge/qlge_ethtool.c @@ -650,8 +650,6 @@ static int ql_set_pauseparam(struct net_device *netdev, return -EINVAL; status = ql_mb_set_port_cfg(qdev); - if (status) - return status; return status; } diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index ef1ce2ebeb4a..73108249462e 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -22,6 +22,7 @@ #include <linux/ip.h> #include <linux/tcp.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/dma-mapping.h> #include <linux/pm_runtime.h> #include <linux/firmware.h> diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c index fa74314ef789..9da47337b7c3 100644 --- a/drivers/net/sc92031.c +++ b/drivers/net/sc92031.c @@ -22,6 +22,7 @@ * matching, so you need to enable IFF_PROMISC when using it. */ +#include <linux/interrupt.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/delay.h> diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c index e646bfce2d84..b6304486f244 100644 --- a/drivers/net/sfc/mtd.c +++ b/drivers/net/sfc/mtd.c @@ -216,7 +216,7 @@ static void efx_mtd_remove_partition(struct efx_mtd_partition *part) int rc; for (;;) { - rc = del_mtd_device(&part->mtd); + rc = mtd_device_unregister(&part->mtd); if (rc != -EBUSY) break; ssleep(1); @@ -268,7 +268,7 @@ static int efx_mtd_probe_device(struct efx_nic *efx, struct efx_mtd *efx_mtd) part->mtd.write = efx_mtd->ops->write; part->mtd.sync = efx_mtd_sync; - if (add_mtd_device(&part->mtd)) + if (mtd_device_register(&part->mtd, NULL, 0)) goto fail; } @@ -280,7 +280,7 @@ fail: --part; efx_mtd_remove_partition(part); } - /* add_mtd_device() returns 1 if the MTD table is full */ + /* mtd_device_register() returns 1 if the MTD table is full */ return -ENOMEM; } diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index f2a2b947f860..bafa23a6874c 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -10,6 +10,7 @@ #include <linux/bitops.h> #include <linux/delay.h> +#include <linux/interrupt.h> #include <linux/pci.h> #include <linux/module.h> #include <linux/seq_file.h> diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index b436e007eea0..8ad7bfbaa3af 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -21,6 +21,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/interrupt.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/netdevice.h> diff --git a/drivers/net/skge.h b/drivers/net/skge.h index 598bf7a1a55e..a2eb34115844 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -3,6 +3,7 @@ */ #ifndef _SKGE_H #define _SKGE_H +#include <linux/interrupt.h> /* PCI config registers */ #define PCI_DEV_REG1 0x40 diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 3ee41da130c2..d252cb123a5f 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -32,6 +32,7 @@ #include <linux/etherdevice.h> #include <linux/ethtool.h> #include <linux/pci.h> +#include <linux/interrupt.h> #include <linux/ip.h> #include <linux/slab.h> #include <net/ip.h> diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c index ab9e3b785b5b..0a0a6643cf3a 100644 --- a/drivers/net/slhc.c +++ b/drivers/net/slhc.c @@ -297,7 +297,7 @@ slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, lcs = cs; cs = cs->next; comp->sls_o_searches++; - }; + } /* * Didn't find it -- re-use oldest cstate. Send an * uncompressed packet that tells the other side what diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index 0f29f261fcfe..34934fb23b97 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -42,6 +42,7 @@ #include <linux/errno.h> #include <linux/string.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -156,7 +157,7 @@ static const struct { { 14, 15 } }; -static const short smc_mca_adapter_ids[] __devinitconst = { +static short smc_mca_adapter_ids[] __initdata = { 0x61c8, 0x61c9, 0x6fc0, @@ -168,7 +169,7 @@ static const short smc_mca_adapter_ids[] __devinitconst = { 0x0000 }; -static const char *const smc_mca_adapter_names[] __devinitconst = { +static char *smc_mca_adapter_names[] __initdata = { "SMC Ethercard PLUS Elite/A BNC/AUI (WD8013EP/A)", "SMC Ethercard PLUS Elite/A UTP/AUI (WD8013WP/A)", "WD Ethercard PLUS/A (WD8003E/A or WD8003ET/A)", @@ -199,7 +200,7 @@ static const struct net_device_ops ultramca_netdev_ops = { #endif }; -static int __devinit ultramca_probe(struct device *gen_dev) +static int __init ultramca_probe(struct device *gen_dev) { unsigned short ioaddr; struct net_device *dev; diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index 235a3c6c9f91..ba44ede29198 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -62,6 +62,7 @@ static const char version[] = #include <linux/errno.h> #include <linux/string.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/isapnp.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index c6d47d10590c..054597625d55 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -37,6 +37,7 @@ #include <linux/etherdevice.h> #include <linux/ethtool.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/ioport.h> #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c index 4c92ad8be765..5e5e64da5cb9 100644 --- a/drivers/net/smsc9420.c +++ b/drivers/net/smsc9420.c @@ -19,6 +19,7 @@ *************************************************************************** */ +#include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/netdevice.h> #include <linux/phy.h> diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 949f124e1278..9bc6c20e8b97 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -31,6 +31,7 @@ #include <linux/if_vlan.h> #include <linux/in.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/gfp.h> #include <linux/ioport.h> #include <linux/ip.h> diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 36045f3b0327..860a50815f84 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -30,6 +30,7 @@ #define DRV_VERSION "2.1" #define DRV_RELDATE "July 6, 2008" +#include <linux/interrupt.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/pci.h> diff --git a/drivers/net/stmmac/stmmac_ethtool.c b/drivers/net/stmmac/stmmac_ethtool.c index ae5213a8c4cd..720c5a1531bc 100644 --- a/drivers/net/stmmac/stmmac_ethtool.c +++ b/drivers/net/stmmac/stmmac_ethtool.c @@ -24,6 +24,7 @@ #include <linux/etherdevice.h> #include <linux/ethtool.h> +#include <linux/interrupt.h> #include <linux/mii.h> #include <linux/phy.h> diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index ab5930099267..71d4a0329d02 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -10,25 +10,6 @@ * NAPI and NETPOLL support * (C) 2004 by Eric Lemoine (eric.lemoine@gmail.com) * - * TODO: - * - Now that the driver was significantly simplified, I need to rework - * the locking. I'm sure we don't need _2_ spinlocks, and we probably - * can avoid taking most of them for so long period of time (and schedule - * instead). The main issues at this point are caused by the netdev layer - * though: - * - * gem_change_mtu() and gem_set_multicast() are called with a read_lock() - * help by net/core/dev.c, thus they can't schedule. That means they can't - * call napi_disable() neither, thus force gem_poll() to keep a spinlock - * where it could have been dropped. change_mtu especially would love also to - * be able to msleep instead of horrid locked delays when resetting the HW, - * but that read_lock() makes it impossible, unless I defer it's action to - * the reset task, which means it'll be asynchronous (won't take effect until - * the system schedules a bit). - * - * Also, it would probably be possible to also remove most of the long-life - * locking in open/resume code path (gem_reinit_chip) by beeing more careful - * about when we can start taking interrupts or get xmit() called... */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -57,7 +38,6 @@ #include <linux/workqueue.h> #include <linux/if_vlan.h> #include <linux/bitops.h> -#include <linux/mutex.h> #include <linux/mm.h> #include <linux/gfp.h> @@ -95,12 +75,11 @@ SUPPORTED_Pause | SUPPORTED_Autoneg) #define DRV_NAME "sungem" -#define DRV_VERSION "0.98" -#define DRV_RELDATE "8/24/03" -#define DRV_AUTHOR "David S. Miller (davem@redhat.com)" +#define DRV_VERSION "1.0" +#define DRV_AUTHOR "David S. Miller <davem@redhat.com>" static char version[] __devinitdata = - DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n"; + DRV_NAME ".c:v" DRV_VERSION " " DRV_AUTHOR "\n"; MODULE_AUTHOR(DRV_AUTHOR); MODULE_DESCRIPTION("Sun GEM Gbit ethernet driver"); @@ -218,6 +197,7 @@ static inline void gem_disable_ints(struct gem *gp) { /* Disable all interrupts, including TXDONE */ writel(GREG_STAT_NAPI | GREG_STAT_TXDONE, gp->regs + GREG_IMASK); + (void)readl(gp->regs + GREG_IMASK); /* write posting */ } static void gem_get_cell(struct gem *gp) @@ -247,6 +227,29 @@ static void gem_put_cell(struct gem *gp) #endif /* CONFIG_PPC_PMAC */ } +static inline void gem_netif_stop(struct gem *gp) +{ + gp->dev->trans_start = jiffies; /* prevent tx timeout */ + napi_disable(&gp->napi); + netif_tx_disable(gp->dev); +} + +static inline void gem_netif_start(struct gem *gp) +{ + /* NOTE: unconditional netif_wake_queue is only + * appropriate so long as all callers are assured to + * have free tx slots. + */ + netif_wake_queue(gp->dev); + napi_enable(&gp->napi); +} + +static void gem_schedule_reset(struct gem *gp) +{ + gp->reset_task_pending = 1; + schedule_work(&gp->reset_task); +} + static void gem_handle_mif_event(struct gem *gp, u32 reg_val, u32 changed_bits) { if (netif_msg_intr(gp)) @@ -604,56 +607,46 @@ static int gem_abnormal_irq(struct net_device *dev, struct gem *gp, u32 gem_stat gp->dev->name); dev->stats.rx_errors++; - goto do_reset; + return 1; } if (gem_status & GREG_STAT_PCS) { if (gem_pcs_interrupt(dev, gp, gem_status)) - goto do_reset; + return 1; } if (gem_status & GREG_STAT_TXMAC) { if (gem_txmac_interrupt(dev, gp, gem_status)) - goto do_reset; + return 1; } if (gem_status & GREG_STAT_RXMAC) { if (gem_rxmac_interrupt(dev, gp, gem_status)) - goto do_reset; + return 1; } if (gem_status & GREG_STAT_MAC) { if (gem_mac_interrupt(dev, gp, gem_status)) - goto do_reset; + return 1; } if (gem_status & GREG_STAT_MIF) { if (gem_mif_interrupt(dev, gp, gem_status)) - goto do_reset; + return 1; } if (gem_status & GREG_STAT_PCIERR) { if (gem_pci_interrupt(dev, gp, gem_status)) - goto do_reset; + return 1; } return 0; - -do_reset: - gp->reset_task_pending = 1; - schedule_work(&gp->reset_task); - - return 1; } static __inline__ void gem_tx(struct net_device *dev, struct gem *gp, u32 gem_status) { int entry, limit; - if (netif_msg_intr(gp)) - printk(KERN_DEBUG "%s: tx interrupt, gem_status: 0x%x\n", - gp->dev->name, gem_status); - entry = gp->tx_old; limit = ((gem_status & GREG_STAT_TXNR) >> GREG_STAT_TXNR_SHIFT); while (entry != limit) { @@ -697,13 +690,27 @@ static __inline__ void gem_tx(struct net_device *dev, struct gem *gp, u32 gem_st } dev->stats.tx_packets++; - dev_kfree_skb_irq(skb); + dev_kfree_skb(skb); } gp->tx_old = entry; - if (netif_queue_stopped(dev) && - TX_BUFFS_AVAIL(gp) > (MAX_SKB_FRAGS + 1)) - netif_wake_queue(dev); + /* Need to make the tx_old update visible to gem_start_xmit() + * before checking for netif_queue_stopped(). Without the + * memory barrier, there is a small possibility that gem_start_xmit() + * will miss it and cause the queue to be stopped forever. + */ + smp_mb(); + + if (unlikely(netif_queue_stopped(dev) && + TX_BUFFS_AVAIL(gp) > (MAX_SKB_FRAGS + 1))) { + struct netdev_queue *txq = netdev_get_tx_queue(dev, 0); + + __netif_tx_lock(txq, smp_processor_id()); + if (netif_queue_stopped(dev) && + TX_BUFFS_AVAIL(gp) > (MAX_SKB_FRAGS + 1)) + netif_wake_queue(dev); + __netif_tx_unlock(txq); + } } static __inline__ void gem_post_rxds(struct gem *gp, int limit) @@ -736,6 +743,21 @@ static __inline__ void gem_post_rxds(struct gem *gp, int limit) } } +#define ALIGNED_RX_SKB_ADDR(addr) \ + ((((unsigned long)(addr) + (64UL - 1UL)) & ~(64UL - 1UL)) - (unsigned long)(addr)) +static __inline__ struct sk_buff *gem_alloc_skb(struct net_device *dev, int size, + gfp_t gfp_flags) +{ + struct sk_buff *skb = alloc_skb(size + 64, gfp_flags); + + if (likely(skb)) { + unsigned long offset = ALIGNED_RX_SKB_ADDR(skb->data); + skb_reserve(skb, offset); + skb->dev = dev; + } + return skb; +} + static int gem_rx(struct gem *gp, int work_to_do) { struct net_device *dev = gp->dev; @@ -799,7 +821,7 @@ static int gem_rx(struct gem *gp, int work_to_do) if (len > RX_COPY_THRESHOLD) { struct sk_buff *new_skb; - new_skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE(gp), GFP_ATOMIC); + new_skb = gem_alloc_skb(dev, RX_BUF_ALLOC_SIZE(gp), GFP_ATOMIC); if (new_skb == NULL) { drops++; goto drop_it; @@ -808,7 +830,6 @@ static int gem_rx(struct gem *gp, int work_to_do) RX_BUF_ALLOC_SIZE(gp), PCI_DMA_FROMDEVICE); gp->rx_skbs[entry] = new_skb; - new_skb->dev = gp->dev; skb_put(new_skb, (gp->rx_buf_sz + RX_OFFSET)); rxd->buffer = cpu_to_le64(pci_map_page(gp->pdev, virt_to_page(new_skb->data), @@ -820,7 +841,7 @@ static int gem_rx(struct gem *gp, int work_to_do) /* Trim the original skb for the netif. */ skb_trim(skb, len); } else { - struct sk_buff *copy_skb = dev_alloc_skb(len + 2); + struct sk_buff *copy_skb = netdev_alloc_skb(dev, len + 2); if (copy_skb == NULL) { drops++; @@ -842,7 +863,7 @@ static int gem_rx(struct gem *gp, int work_to_do) skb->ip_summed = CHECKSUM_COMPLETE; skb->protocol = eth_type_trans(skb, gp->dev); - netif_receive_skb(skb); + napi_gro_receive(&gp->napi, skb); dev->stats.rx_packets++; dev->stats.rx_bytes += len; @@ -865,28 +886,32 @@ static int gem_poll(struct napi_struct *napi, int budget) { struct gem *gp = container_of(napi, struct gem, napi); struct net_device *dev = gp->dev; - unsigned long flags; int work_done; - /* - * NAPI locking nightmare: See comment at head of driver - */ - spin_lock_irqsave(&gp->lock, flags); - work_done = 0; do { /* Handle anomalies */ - if (gp->status & GREG_STAT_ABNORMAL) { - if (gem_abnormal_irq(dev, gp, gp->status)) - break; + if (unlikely(gp->status & GREG_STAT_ABNORMAL)) { + struct netdev_queue *txq = netdev_get_tx_queue(dev, 0); + int reset; + + /* We run the abnormal interrupt handling code with + * the Tx lock. It only resets the Rx portion of the + * chip, but we need to guard it against DMA being + * restarted by the link poll timer + */ + __netif_tx_lock(txq, smp_processor_id()); + reset = gem_abnormal_irq(dev, gp, gp->status); + __netif_tx_unlock(txq); + if (reset) { + gem_schedule_reset(gp); + napi_complete(napi); + return work_done; + } } /* Run TX completion thread */ - spin_lock(&gp->tx_lock); gem_tx(dev, gp, gp->status); - spin_unlock(&gp->tx_lock); - - spin_unlock_irqrestore(&gp->lock, flags); /* Run RX thread. We don't use any locking here, * code willing to do bad things - like cleaning the @@ -898,16 +923,12 @@ static int gem_poll(struct napi_struct *napi, int budget) if (work_done >= budget) return work_done; - spin_lock_irqsave(&gp->lock, flags); - gp->status = readl(gp->regs + GREG_STAT); } while (gp->status & GREG_STAT_NAPI); - __napi_complete(napi); + napi_complete(napi); gem_enable_ints(gp); - spin_unlock_irqrestore(&gp->lock, flags); - return work_done; } @@ -915,32 +936,23 @@ static irqreturn_t gem_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct gem *gp = netdev_priv(dev); - unsigned long flags; - - /* Swallow interrupts when shutting the chip down, though - * that shouldn't happen, we should have done free_irq() at - * this point... - */ - if (!gp->running) - return IRQ_HANDLED; - - spin_lock_irqsave(&gp->lock, flags); if (napi_schedule_prep(&gp->napi)) { u32 gem_status = readl(gp->regs + GREG_STAT); - if (gem_status == 0) { + if (unlikely(gem_status == 0)) { napi_enable(&gp->napi); - spin_unlock_irqrestore(&gp->lock, flags); return IRQ_NONE; } + if (netif_msg_intr(gp)) + printk(KERN_DEBUG "%s: gem_interrupt() gem_status: 0x%x\n", + gp->dev->name, gem_status); + gp->status = gem_status; gem_disable_ints(gp); __napi_schedule(&gp->napi); } - spin_unlock_irqrestore(&gp->lock, flags); - /* If polling was disabled at the time we received that * interrupt, we may return IRQ_HANDLED here while we * should return IRQ_NONE. No big deal... @@ -951,10 +963,11 @@ static irqreturn_t gem_interrupt(int irq, void *dev_id) #ifdef CONFIG_NET_POLL_CONTROLLER static void gem_poll_controller(struct net_device *dev) { - /* gem_interrupt is safe to reentrance so no need - * to disable_irq here. - */ - gem_interrupt(dev->irq, dev); + struct gem *gp = netdev_priv(dev); + + disable_irq(gp->pdev->irq); + gem_interrupt(gp->pdev->irq, dev); + enable_irq(gp->pdev->irq); } #endif @@ -963,10 +976,7 @@ static void gem_tx_timeout(struct net_device *dev) struct gem *gp = netdev_priv(dev); netdev_err(dev, "transmit timed out, resetting\n"); - if (!gp->running) { - netdev_err(dev, "hrm.. hw not running !\n"); - return; - } + netdev_err(dev, "TX_STATE[%08x:%08x:%08x]\n", readl(gp->regs + TXDMA_CFG), readl(gp->regs + MAC_TXSTAT), @@ -976,14 +986,7 @@ static void gem_tx_timeout(struct net_device *dev) readl(gp->regs + MAC_RXSTAT), readl(gp->regs + MAC_RXCFG)); - spin_lock_irq(&gp->lock); - spin_lock(&gp->tx_lock); - - gp->reset_task_pending = 1; - schedule_work(&gp->reset_task); - - spin_unlock(&gp->tx_lock); - spin_unlock_irq(&gp->lock); + gem_schedule_reset(gp); } static __inline__ int gem_intme(int entry) @@ -1001,7 +1004,6 @@ static netdev_tx_t gem_start_xmit(struct sk_buff *skb, struct gem *gp = netdev_priv(dev); int entry; u64 ctrl; - unsigned long flags; ctrl = 0; if (skb->ip_summed == CHECKSUM_PARTIAL) { @@ -1013,21 +1015,12 @@ static netdev_tx_t gem_start_xmit(struct sk_buff *skb, (csum_stuff_off << 21)); } - if (!spin_trylock_irqsave(&gp->tx_lock, flags)) { - /* Tell upper layer to requeue */ - return NETDEV_TX_LOCKED; - } - /* We raced with gem_do_stop() */ - if (!gp->running) { - spin_unlock_irqrestore(&gp->tx_lock, flags); - return NETDEV_TX_BUSY; - } - - /* This is a hard error, log it. */ - if (TX_BUFFS_AVAIL(gp) <= (skb_shinfo(skb)->nr_frags + 1)) { - netif_stop_queue(dev); - spin_unlock_irqrestore(&gp->tx_lock, flags); - netdev_err(dev, "BUG! Tx Ring full when queue awake!\n"); + if (unlikely(TX_BUFFS_AVAIL(gp) <= (skb_shinfo(skb)->nr_frags + 1))) { + /* This is a hard error, log it. */ + if (!netif_queue_stopped(dev)) { + netif_stop_queue(dev); + netdev_err(dev, "BUG! Tx Ring full when queue awake!\n"); + } return NETDEV_TX_BUSY; } @@ -1104,17 +1097,23 @@ static netdev_tx_t gem_start_xmit(struct sk_buff *skb, } gp->tx_new = entry; - if (TX_BUFFS_AVAIL(gp) <= (MAX_SKB_FRAGS + 1)) + if (unlikely(TX_BUFFS_AVAIL(gp) <= (MAX_SKB_FRAGS + 1))) { netif_stop_queue(dev); + /* netif_stop_queue() must be done before checking + * checking tx index in TX_BUFFS_AVAIL() below, because + * in gem_tx(), we update tx_old before checking for + * netif_queue_stopped(). + */ + smp_mb(); + if (TX_BUFFS_AVAIL(gp) > (MAX_SKB_FRAGS + 1)) + netif_wake_queue(dev); + } if (netif_msg_tx_queued(gp)) printk(KERN_DEBUG "%s: tx queued, slot %d, skblen %d\n", dev->name, entry, skb->len); mb(); writel(gp->tx_new, gp->regs + TXDMA_KICK); - spin_unlock_irqrestore(&gp->tx_lock, flags); - - dev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */ return NETDEV_TX_OK; } @@ -1184,7 +1183,6 @@ static void gem_pcs_reinit_adv(struct gem *gp) #define STOP_TRIES 32 -/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_reset(struct gem *gp) { int limit; @@ -1213,7 +1211,6 @@ static void gem_reset(struct gem *gp) gem_pcs_reinit_adv(gp); } -/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_start_dma(struct gem *gp) { u32 val; @@ -1236,8 +1233,7 @@ static void gem_start_dma(struct gem *gp) writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK); } -/* Must be invoked under gp->lock and gp->tx_lock. DMA won't be - * actually stopped before about 4ms tho ... +/* DMA won't be actually stopped before about 4ms tho ... */ static void gem_stop_dma(struct gem *gp) { @@ -1259,7 +1255,6 @@ static void gem_stop_dma(struct gem *gp) } -/* Must be invoked under gp->lock and gp->tx_lock. */ // XXX dbl check what that function should do when called on PCS PHY static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep) { @@ -1319,7 +1314,7 @@ start_aneg: /* If we are asleep, we don't try to actually setup the PHY, we * just store the settings */ - if (gp->asleep) { + if (!netif_device_present(gp->dev)) { gp->phy_mii.autoneg = gp->want_autoneg = autoneg; gp->phy_mii.speed = speed; gp->phy_mii.duplex = duplex; @@ -1345,13 +1340,12 @@ non_mii: /* A link-up condition has occurred, initialize and enable the * rest of the chip. - * - * Must be invoked under gp->lock and gp->tx_lock. */ static int gem_set_link_modes(struct gem *gp) { - u32 val; + struct netdev_queue *txq = netdev_get_tx_queue(gp->dev, 0); int full_duplex, speed, pause; + u32 val; full_duplex = 0; speed = SPEED_10; @@ -1375,8 +1369,11 @@ static int gem_set_link_modes(struct gem *gp) netif_info(gp, link, gp->dev, "Link is up at %d Mbps, %s-duplex\n", speed, (full_duplex ? "full" : "half")); - if (!gp->running) - return 0; + + /* We take the tx queue lock to avoid collisions between + * this code, the tx path and the NAPI-driven error path + */ + __netif_tx_lock(txq, smp_processor_id()); val = (MAC_TXCFG_EIPG0 | MAC_TXCFG_NGU); if (full_duplex) { @@ -1425,18 +1422,6 @@ static int gem_set_link_modes(struct gem *gp) pause = 1; } - if (netif_msg_link(gp)) { - if (pause) { - netdev_info(gp->dev, - "Pause is enabled (rxfifo: %d off: %d on: %d)\n", - gp->rx_fifo_sz, - gp->rx_pause_off, - gp->rx_pause_on); - } else { - netdev_info(gp->dev, "Pause is disabled\n"); - } - } - if (!full_duplex) writel(512, gp->regs + MAC_STIME); else @@ -1450,10 +1435,23 @@ static int gem_set_link_modes(struct gem *gp) gem_start_dma(gp); + __netif_tx_unlock(txq); + + if (netif_msg_link(gp)) { + if (pause) { + netdev_info(gp->dev, + "Pause is enabled (rxfifo: %d off: %d on: %d)\n", + gp->rx_fifo_sz, + gp->rx_pause_off, + gp->rx_pause_on); + } else { + netdev_info(gp->dev, "Pause is disabled\n"); + } + } + return 0; } -/* Must be invoked under gp->lock and gp->tx_lock. */ static int gem_mdio_link_not_up(struct gem *gp) { switch (gp->lstate) { @@ -1501,20 +1499,12 @@ static int gem_mdio_link_not_up(struct gem *gp) static void gem_link_timer(unsigned long data) { struct gem *gp = (struct gem *) data; + struct net_device *dev = gp->dev; int restart_aneg = 0; - if (gp->asleep) - return; - - spin_lock_irq(&gp->lock); - spin_lock(&gp->tx_lock); - gem_get_cell(gp); - - /* If the reset task is still pending, we just - * reschedule the link timer - */ + /* There's no point doing anything if we're going to be reset */ if (gp->reset_task_pending) - goto restart; + return; if (gp->phy_type == phy_serialink || gp->phy_type == phy_serdes) { @@ -1528,7 +1518,7 @@ static void gem_link_timer(unsigned long data) goto restart; gp->lstate = link_up; - netif_carrier_on(gp->dev); + netif_carrier_on(dev); (void)gem_set_link_modes(gp); } goto restart; @@ -1544,12 +1534,12 @@ static void gem_link_timer(unsigned long data) gp->last_forced_speed = gp->phy_mii.speed; gp->timer_ticks = 5; if (netif_msg_link(gp)) - netdev_info(gp->dev, + netdev_info(dev, "Got link after fallback, retrying autoneg once...\n"); gp->phy_mii.def->ops->setup_aneg(&gp->phy_mii, gp->phy_mii.advertising); } else if (gp->lstate != link_up) { gp->lstate = link_up; - netif_carrier_on(gp->dev); + netif_carrier_on(dev); if (gem_set_link_modes(gp)) restart_aneg = 1; } @@ -1559,11 +1549,11 @@ static void gem_link_timer(unsigned long data) */ if (gp->lstate == link_up) { gp->lstate = link_down; - netif_info(gp, link, gp->dev, "Link down\n"); - netif_carrier_off(gp->dev); - gp->reset_task_pending = 1; - schedule_work(&gp->reset_task); - restart_aneg = 1; + netif_info(gp, link, dev, "Link down\n"); + netif_carrier_off(dev); + gem_schedule_reset(gp); + /* The reset task will restart the timer */ + return; } else if (++gp->timer_ticks > 10) { if (found_mii_phy(gp)) restart_aneg = gem_mdio_link_not_up(gp); @@ -1573,17 +1563,12 @@ static void gem_link_timer(unsigned long data) } if (restart_aneg) { gem_begin_auto_negotiation(gp, NULL); - goto out_unlock; + return; } restart: mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10)); -out_unlock: - gem_put_cell(gp); - spin_unlock(&gp->tx_lock); - spin_unlock_irq(&gp->lock); } -/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_clean_rings(struct gem *gp) { struct gem_init_block *gb = gp->init_block; @@ -1634,7 +1619,6 @@ static void gem_clean_rings(struct gem *gp) } } -/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_rings(struct gem *gp) { struct gem_init_block *gb = gp->init_block; @@ -1653,7 +1637,7 @@ static void gem_init_rings(struct gem *gp) struct sk_buff *skb; struct gem_rxd *rxd = &gb->rxd[i]; - skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE(gp), GFP_ATOMIC); + skb = gem_alloc_skb(dev, RX_BUF_ALLOC_SIZE(gp), GFP_KERNEL); if (!skb) { rxd->buffer = 0; rxd->status_word = 0; @@ -1661,7 +1645,6 @@ static void gem_init_rings(struct gem *gp) } gp->rx_skbs[i] = skb; - skb->dev = dev; skb_put(skb, (gp->rx_buf_sz + RX_OFFSET)); dma_addr = pci_map_page(gp->pdev, virt_to_page(skb->data), @@ -1737,7 +1720,7 @@ static void gem_init_phy(struct gem *gp) if (gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) { - // XXX check for errors + /* Reset and detect MII PHY */ mii_phy_probe(&gp->phy_mii, gp->mii_phy_addr); /* Init PHY */ @@ -1753,13 +1736,15 @@ static void gem_init_phy(struct gem *gp) gp->lstate = link_down; netif_carrier_off(gp->dev); - /* Can I advertise gigabit here ? I'd need BCM PHY docs... */ - spin_lock_irq(&gp->lock); + /* Print things out */ + if (gp->phy_type == phy_mii_mdio0 || + gp->phy_type == phy_mii_mdio1) + netdev_info(gp->dev, "Found %s PHY\n", + gp->phy_mii.def ? gp->phy_mii.def->name : "no"); + gem_begin_auto_negotiation(gp, NULL); - spin_unlock_irq(&gp->lock); } -/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_dma(struct gem *gp) { u64 desc_dma = (u64) gp->gblock_dvma; @@ -1797,7 +1782,6 @@ static void gem_init_dma(struct gem *gp) gp->regs + RXDMA_BLANK); } -/* Must be invoked under gp->lock and gp->tx_lock. */ static u32 gem_setup_multicast(struct gem *gp) { u32 rxcfg = 0; @@ -1835,7 +1819,6 @@ static u32 gem_setup_multicast(struct gem *gp) return rxcfg; } -/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_mac(struct gem *gp) { unsigned char *e = &gp->dev->dev_addr[0]; @@ -1918,7 +1901,6 @@ static void gem_init_mac(struct gem *gp) writel(0, gp->regs + WOL_WAKECSR); } -/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_init_pause_thresholds(struct gem *gp) { u32 cfg; @@ -2079,7 +2061,6 @@ static int gem_check_invariants(struct gem *gp) return 0; } -/* Must be invoked under gp->lock and gp->tx_lock. */ static void gem_reinit_chip(struct gem *gp) { /* Reset the chip */ @@ -2100,11 +2081,9 @@ static void gem_reinit_chip(struct gem *gp) } -/* Must be invoked with no lock held. */ static void gem_stop_phy(struct gem *gp, int wol) { u32 mifcfg; - unsigned long flags; /* Let the chip settle down a bit, it seems that helps * for sleep mode on some models @@ -2150,15 +2129,9 @@ static void gem_stop_phy(struct gem *gp, int wol) writel(0, gp->regs + RXDMA_CFG); if (!wol) { - spin_lock_irqsave(&gp->lock, flags); - spin_lock(&gp->tx_lock); gem_reset(gp); writel(MAC_TXRST_CMD, gp->regs + MAC_TXRST); writel(MAC_RXRST_CMD, gp->regs + MAC_RXRST); - spin_unlock(&gp->tx_lock); - spin_unlock_irqrestore(&gp->lock, flags); - - /* No need to take the lock here */ if (found_mii_phy(gp) && gp->phy_mii.def->ops->suspend) gp->phy_mii.def->ops->suspend(&gp->phy_mii); @@ -2175,54 +2148,55 @@ static void gem_stop_phy(struct gem *gp, int wol) } } - static int gem_do_start(struct net_device *dev) { struct gem *gp = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&gp->lock, flags); - spin_lock(&gp->tx_lock); + int rc; /* Enable the cell */ gem_get_cell(gp); - /* Init & setup chip hardware */ - gem_reinit_chip(gp); - - gp->running = 1; - - napi_enable(&gp->napi); + /* Make sure PCI access and bus master are enabled */ + rc = pci_enable_device(gp->pdev); + if (rc) { + netdev_err(dev, "Failed to enable chip on PCI bus !\n"); - if (gp->lstate == link_up) { - netif_carrier_on(gp->dev); - gem_set_link_modes(gp); + /* Put cell and forget it for now, it will be considered as + * still asleep, a new sleep cycle may bring it back + */ + gem_put_cell(gp); + return -ENXIO; } + pci_set_master(gp->pdev); - netif_wake_queue(gp->dev); - - spin_unlock(&gp->tx_lock); - spin_unlock_irqrestore(&gp->lock, flags); + /* Init & setup chip hardware */ + gem_reinit_chip(gp); - if (request_irq(gp->pdev->irq, gem_interrupt, - IRQF_SHARED, dev->name, (void *)dev)) { + /* An interrupt might come in handy */ + rc = request_irq(gp->pdev->irq, gem_interrupt, + IRQF_SHARED, dev->name, (void *)dev); + if (rc) { netdev_err(dev, "failed to request irq !\n"); - spin_lock_irqsave(&gp->lock, flags); - spin_lock(&gp->tx_lock); - - napi_disable(&gp->napi); - - gp->running = 0; gem_reset(gp); gem_clean_rings(gp); gem_put_cell(gp); + return rc; + } + + /* Mark us as attached again if we come from resume(), this has + * no effect if we weren't detatched and needs to be done now. + */ + netif_device_attach(dev); - spin_unlock(&gp->tx_lock); - spin_unlock_irqrestore(&gp->lock, flags); + /* Restart NAPI & queues */ + gem_netif_start(gp); - return -EAGAIN; - } + /* Detect & init PHY, start autoneg etc... this will + * eventually result in starting DMA operations when + * the link is up + */ + gem_init_phy(gp); return 0; } @@ -2230,22 +2204,30 @@ static int gem_do_start(struct net_device *dev) static void gem_do_stop(struct net_device *dev, int wol) { struct gem *gp = netdev_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&gp->lock, flags); - spin_lock(&gp->tx_lock); - gp->running = 0; + /* Stop NAPI and stop tx queue */ + gem_netif_stop(gp); - /* Stop netif queue */ - netif_stop_queue(dev); - - /* Make sure ints are disabled */ + /* Make sure ints are disabled. We don't care about + * synchronizing as NAPI is disabled, thus a stray + * interrupt will do nothing bad (our irq handler + * just schedules NAPI) + */ gem_disable_ints(gp); - /* We can drop the lock now */ - spin_unlock(&gp->tx_lock); - spin_unlock_irqrestore(&gp->lock, flags); + /* Stop the link timer */ + del_timer_sync(&gp->link_timer); + + /* We cannot cancel the reset task while holding the + * rtnl lock, we'd get an A->B / B->A deadlock stituation + * if we did. This is not an issue however as the reset + * task is synchronized vs. us (rtnl_lock) and will do + * nothing if the device is down or suspended. We do + * still clear reset_task_pending to avoid a spurrious + * reset later on in case we do resume before it gets + * scheduled. + */ + gp->reset_task_pending = 0; /* If we are going to sleep with WOL */ gem_stop_dma(gp); @@ -2260,79 +2242,79 @@ static void gem_do_stop(struct net_device *dev, int wol) /* No irq needed anymore */ free_irq(gp->pdev->irq, (void *) dev); + /* Shut the PHY down eventually and setup WOL */ + gem_stop_phy(gp, wol); + + /* Make sure bus master is disabled */ + pci_disable_device(gp->pdev); + /* Cell not needed neither if no WOL */ - if (!wol) { - spin_lock_irqsave(&gp->lock, flags); + if (!wol) gem_put_cell(gp); - spin_unlock_irqrestore(&gp->lock, flags); - } } static void gem_reset_task(struct work_struct *work) { struct gem *gp = container_of(work, struct gem, reset_task); - mutex_lock(&gp->pm_mutex); + /* Lock out the network stack (essentially shield ourselves + * against a racing open, close, control call, or suspend + */ + rtnl_lock(); - if (gp->opened) - napi_disable(&gp->napi); + /* Skip the reset task if suspended or closed, or if it's + * been cancelled by gem_do_stop (see comment there) + */ + if (!netif_device_present(gp->dev) || + !netif_running(gp->dev) || + !gp->reset_task_pending) { + rtnl_unlock(); + return; + } - spin_lock_irq(&gp->lock); - spin_lock(&gp->tx_lock); + /* Stop the link timer */ + del_timer_sync(&gp->link_timer); - if (gp->running) { - netif_stop_queue(gp->dev); + /* Stop NAPI and tx */ + gem_netif_stop(gp); - /* Reset the chip & rings */ - gem_reinit_chip(gp); - if (gp->lstate == link_up) - gem_set_link_modes(gp); - netif_wake_queue(gp->dev); - } + /* Reset the chip & rings */ + gem_reinit_chip(gp); + if (gp->lstate == link_up) + gem_set_link_modes(gp); - gp->reset_task_pending = 0; + /* Restart NAPI and Tx */ + gem_netif_start(gp); - spin_unlock(&gp->tx_lock); - spin_unlock_irq(&gp->lock); + /* We are back ! */ + gp->reset_task_pending = 0; - if (gp->opened) - napi_enable(&gp->napi); + /* If the link is not up, restart autoneg, else restart the + * polling timer + */ + if (gp->lstate != link_up) + gem_begin_auto_negotiation(gp, NULL); + else + mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10)); - mutex_unlock(&gp->pm_mutex); + rtnl_unlock(); } - static int gem_open(struct net_device *dev) { - struct gem *gp = netdev_priv(dev); - int rc = 0; - - mutex_lock(&gp->pm_mutex); - - /* We need the cell enabled */ - if (!gp->asleep) - rc = gem_do_start(dev); - gp->opened = (rc == 0); - - mutex_unlock(&gp->pm_mutex); - - return rc; + /* We allow open while suspended, we just do nothing, + * the chip will be initialized in resume() + */ + if (netif_device_present(dev)) + return gem_do_start(dev); + return 0; } static int gem_close(struct net_device *dev) { - struct gem *gp = netdev_priv(dev); - - mutex_lock(&gp->pm_mutex); - - napi_disable(&gp->napi); - - gp->opened = 0; - if (!gp->asleep) + if (netif_device_present(dev)) gem_do_stop(dev, 0); - mutex_unlock(&gp->pm_mutex); - return 0; } @@ -2341,59 +2323,35 @@ static int gem_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); struct gem *gp = netdev_priv(dev); - unsigned long flags; - - mutex_lock(&gp->pm_mutex); - netdev_info(dev, "suspending, WakeOnLan %s\n", - (gp->wake_on_lan && gp->opened) ? "enabled" : "disabled"); - - /* Keep the cell enabled during the entire operation */ - spin_lock_irqsave(&gp->lock, flags); - spin_lock(&gp->tx_lock); - gem_get_cell(gp); - spin_unlock(&gp->tx_lock); - spin_unlock_irqrestore(&gp->lock, flags); - - /* If the driver is opened, we stop the MAC */ - if (gp->opened) { - napi_disable(&gp->napi); + /* Lock the network stack first to avoid racing with open/close, + * reset task and setting calls + */ + rtnl_lock(); - /* Stop traffic, mark us closed */ + /* Not running, mark ourselves non-present, no need for + * a lock here + */ + if (!netif_running(dev)) { netif_device_detach(dev); + rtnl_unlock(); + return 0; + } + netdev_info(dev, "suspending, WakeOnLan %s\n", + (gp->wake_on_lan && netif_running(dev)) ? + "enabled" : "disabled"); - /* Switch off MAC, remember WOL setting */ - gp->asleep_wol = gp->wake_on_lan; - gem_do_stop(dev, gp->asleep_wol); - } else - gp->asleep_wol = 0; - - /* Mark us asleep */ - gp->asleep = 1; - wmb(); - - /* Stop the link timer */ - del_timer_sync(&gp->link_timer); - - /* Now we release the mutex to not block the reset task who - * can take it too. We are marked asleep, so there will be no - * conflict here + /* Tell the network stack we're gone. gem_do_stop() below will + * synchronize with TX, stop NAPI etc... */ - mutex_unlock(&gp->pm_mutex); + netif_device_detach(dev); - /* Wait for the pending reset task to complete */ - flush_work_sync(&gp->reset_task); - - /* Shut the PHY down eventually and setup WOL */ - gem_stop_phy(gp, gp->asleep_wol); - - /* Make sure bus master is disabled */ - pci_disable_device(gp->pdev); + /* Switch off chip, remember WOL setting */ + gp->asleep_wol = gp->wake_on_lan; + gem_do_stop(dev, gp->asleep_wol); - /* Release the cell, no need to take a lock at this point since - * nothing else can happen now - */ - gem_put_cell(gp); + /* Unlock the network stack */ + rtnl_unlock(); return 0; } @@ -2402,53 +2360,23 @@ static int gem_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); struct gem *gp = netdev_priv(dev); - unsigned long flags; - - netdev_info(dev, "resuming\n"); - mutex_lock(&gp->pm_mutex); + /* See locking comment in gem_suspend */ + rtnl_lock(); - /* Keep the cell enabled during the entire operation, no need to - * take a lock here tho since nothing else can happen while we are - * marked asleep + /* Not running, mark ourselves present, no need for + * a lock here */ - gem_get_cell(gp); - - /* Make sure PCI access and bus master are enabled */ - if (pci_enable_device(gp->pdev)) { - netdev_err(dev, "Can't re-enable chip !\n"); - /* Put cell and forget it for now, it will be considered as - * still asleep, a new sleep cycle may bring it back - */ - gem_put_cell(gp); - mutex_unlock(&gp->pm_mutex); + if (!netif_running(dev)) { + netif_device_attach(dev); + rtnl_unlock(); return 0; } - pci_set_master(gp->pdev); - - /* Reset everything */ - gem_reset(gp); - - /* Mark us woken up */ - gp->asleep = 0; - wmb(); - /* Bring the PHY back. Again, lock is useless at this point as - * nothing can be happening until we restart the whole thing + /* Restart chip. If that fails there isn't much we can do, we + * leave things stopped. */ - gem_init_phy(gp); - - /* If we were opened, bring everything back */ - if (gp->opened) { - /* Restart MAC */ - gem_do_start(dev); - - /* Re-attach net device */ - netif_device_attach(dev); - } - - spin_lock_irqsave(&gp->lock, flags); - spin_lock(&gp->tx_lock); + gem_do_start(dev); /* If we had WOL enabled, the cell clock was never turned off during * sleep, so we end up beeing unbalanced. Fix that here @@ -2456,15 +2384,8 @@ static int gem_resume(struct pci_dev *pdev) if (gp->asleep_wol) gem_put_cell(gp); - /* This function doesn't need to hold the cell, it will be held if the - * driver is open by gem_do_start(). - */ - gem_put_cell(gp); - - spin_unlock(&gp->tx_lock); - spin_unlock_irqrestore(&gp->lock, flags); - - mutex_unlock(&gp->pm_mutex); + /* Unlock the network stack */ + rtnl_unlock(); return 0; } @@ -2474,33 +2395,35 @@ static struct net_device_stats *gem_get_stats(struct net_device *dev) { struct gem *gp = netdev_priv(dev); - spin_lock_irq(&gp->lock); - spin_lock(&gp->tx_lock); - /* I have seen this being called while the PM was in progress, - * so we shield against this + * so we shield against this. Let's also not poke at registers + * while the reset task is going on. + * + * TODO: Move stats collection elsewhere (link timer ?) and + * make this a nop to avoid all those synchro issues */ - if (gp->running) { - dev->stats.rx_crc_errors += readl(gp->regs + MAC_FCSERR); - writel(0, gp->regs + MAC_FCSERR); + if (!netif_device_present(dev) || !netif_running(dev)) + goto bail; - dev->stats.rx_frame_errors += readl(gp->regs + MAC_AERR); - writel(0, gp->regs + MAC_AERR); + /* Better safe than sorry... */ + if (WARN_ON(!gp->cell_enabled)) + goto bail; - dev->stats.rx_length_errors += readl(gp->regs + MAC_LERR); - writel(0, gp->regs + MAC_LERR); + dev->stats.rx_crc_errors += readl(gp->regs + MAC_FCSERR); + writel(0, gp->regs + MAC_FCSERR); - dev->stats.tx_aborted_errors += readl(gp->regs + MAC_ECOLL); - dev->stats.collisions += - (readl(gp->regs + MAC_ECOLL) + - readl(gp->regs + MAC_LCOLL)); - writel(0, gp->regs + MAC_ECOLL); - writel(0, gp->regs + MAC_LCOLL); - } + dev->stats.rx_frame_errors += readl(gp->regs + MAC_AERR); + writel(0, gp->regs + MAC_AERR); - spin_unlock(&gp->tx_lock); - spin_unlock_irq(&gp->lock); + dev->stats.rx_length_errors += readl(gp->regs + MAC_LERR); + writel(0, gp->regs + MAC_LERR); + dev->stats.tx_aborted_errors += readl(gp->regs + MAC_ECOLL); + dev->stats.collisions += + (readl(gp->regs + MAC_ECOLL) + readl(gp->regs + MAC_LCOLL)); + writel(0, gp->regs + MAC_ECOLL); + writel(0, gp->regs + MAC_LCOLL); + bail: return &dev->stats; } @@ -2513,22 +2436,19 @@ static int gem_set_mac_address(struct net_device *dev, void *addr) if (!is_valid_ether_addr(macaddr->sa_data)) return -EADDRNOTAVAIL; - if (!netif_running(dev) || !netif_device_present(dev)) { - /* We'll just catch it later when the - * device is up'd or resumed. - */ - memcpy(dev->dev_addr, macaddr->sa_data, dev->addr_len); + memcpy(dev->dev_addr, macaddr->sa_data, dev->addr_len); + + /* We'll just catch it later when the device is up'd or resumed */ + if (!netif_running(dev) || !netif_device_present(dev)) return 0; - } - mutex_lock(&gp->pm_mutex); - memcpy(dev->dev_addr, macaddr->sa_data, dev->addr_len); - if (gp->running) { - writel((e[4] << 8) | e[5], gp->regs + MAC_ADDR0); - writel((e[2] << 8) | e[3], gp->regs + MAC_ADDR1); - writel((e[0] << 8) | e[1], gp->regs + MAC_ADDR2); - } - mutex_unlock(&gp->pm_mutex); + /* Better safe than sorry... */ + if (WARN_ON(!gp->cell_enabled)) + return 0; + + writel((e[4] << 8) | e[5], gp->regs + MAC_ADDR0); + writel((e[2] << 8) | e[3], gp->regs + MAC_ADDR1); + writel((e[0] << 8) | e[1], gp->regs + MAC_ADDR2); return 0; } @@ -2539,14 +2459,12 @@ static void gem_set_multicast(struct net_device *dev) u32 rxcfg, rxcfg_new; int limit = 10000; + if (!netif_running(dev) || !netif_device_present(dev)) + return; - spin_lock_irq(&gp->lock); - spin_lock(&gp->tx_lock); - - if (!gp->running) - goto bail; - - netif_stop_queue(dev); + /* Better safe than sorry... */ + if (gp->reset_task_pending || WARN_ON(!gp->cell_enabled)) + return; rxcfg = readl(gp->regs + MAC_RXCFG); rxcfg_new = gem_setup_multicast(gp); @@ -2566,12 +2484,6 @@ static void gem_set_multicast(struct net_device *dev) rxcfg |= rxcfg_new; writel(rxcfg, gp->regs + MAC_RXCFG); - - netif_wake_queue(dev); - - bail: - spin_unlock(&gp->tx_lock); - spin_unlock_irq(&gp->lock); } /* Jumbo-grams don't seem to work :-( */ @@ -2589,26 +2501,21 @@ static int gem_change_mtu(struct net_device *dev, int new_mtu) if (new_mtu < GEM_MIN_MTU || new_mtu > GEM_MAX_MTU) return -EINVAL; - if (!netif_running(dev) || !netif_device_present(dev)) { - /* We'll just catch it later when the - * device is up'd or resumed. - */ - dev->mtu = new_mtu; + dev->mtu = new_mtu; + + /* We'll just catch it later when the device is up'd or resumed */ + if (!netif_running(dev) || !netif_device_present(dev)) return 0; - } - mutex_lock(&gp->pm_mutex); - spin_lock_irq(&gp->lock); - spin_lock(&gp->tx_lock); - dev->mtu = new_mtu; - if (gp->running) { - gem_reinit_chip(gp); - if (gp->lstate == link_up) - gem_set_link_modes(gp); - } - spin_unlock(&gp->tx_lock); - spin_unlock_irq(&gp->lock); - mutex_unlock(&gp->pm_mutex); + /* Better safe than sorry... */ + if (WARN_ON(!gp->cell_enabled)) + return 0; + + gem_netif_stop(gp); + gem_reinit_chip(gp); + if (gp->lstate == link_up) + gem_set_link_modes(gp); + gem_netif_start(gp); return 0; } @@ -2640,7 +2547,6 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->phy_address = 0; /* XXX fixed PHYAD */ /* Return current PHY settings */ - spin_lock_irq(&gp->lock); cmd->autoneg = gp->want_autoneg; ethtool_cmd_speed_set(cmd, gp->phy_mii.speed); cmd->duplex = gp->phy_mii.duplex; @@ -2652,7 +2558,6 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) */ if (cmd->advertising == 0) cmd->advertising = cmd->supported; - spin_unlock_irq(&gp->lock); } else { // XXX PCS ? cmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | @@ -2706,11 +2611,10 @@ static int gem_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return -EINVAL; /* Apply settings and restart link process. */ - spin_lock_irq(&gp->lock); - gem_get_cell(gp); - gem_begin_auto_negotiation(gp, cmd); - gem_put_cell(gp); - spin_unlock_irq(&gp->lock); + if (netif_device_present(gp->dev)) { + del_timer_sync(&gp->link_timer); + gem_begin_auto_negotiation(gp, cmd); + } return 0; } @@ -2722,12 +2626,11 @@ static int gem_nway_reset(struct net_device *dev) if (!gp->want_autoneg) return -EINVAL; - /* Restart link process. */ - spin_lock_irq(&gp->lock); - gem_get_cell(gp); - gem_begin_auto_negotiation(gp, NULL); - gem_put_cell(gp); - spin_unlock_irq(&gp->lock); + /* Restart link process */ + if (netif_device_present(gp->dev)) { + del_timer_sync(&gp->link_timer); + gem_begin_auto_negotiation(gp, NULL); + } return 0; } @@ -2791,16 +2694,11 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) struct gem *gp = netdev_priv(dev); struct mii_ioctl_data *data = if_mii(ifr); int rc = -EOPNOTSUPP; - unsigned long flags; - /* Hold the PM mutex while doing ioctl's or we may collide - * with power management. + /* For SIOCGMIIREG and SIOCSMIIREG the core checks for us that + * netif_device_present() is true and holds rtnl_lock for us + * so we have nothing to worry about */ - mutex_lock(&gp->pm_mutex); - - spin_lock_irqsave(&gp->lock, flags); - gem_get_cell(gp); - spin_unlock_irqrestore(&gp->lock, flags); switch (cmd) { case SIOCGMIIPHY: /* Get address of MII PHY in use. */ @@ -2808,32 +2706,17 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /* Fallthrough... */ case SIOCGMIIREG: /* Read MII PHY register. */ - if (!gp->running) - rc = -EAGAIN; - else { - data->val_out = __phy_read(gp, data->phy_id & 0x1f, - data->reg_num & 0x1f); - rc = 0; - } + data->val_out = __phy_read(gp, data->phy_id & 0x1f, + data->reg_num & 0x1f); + rc = 0; break; case SIOCSMIIREG: /* Write MII PHY register. */ - if (!gp->running) - rc = -EAGAIN; - else { - __phy_write(gp, data->phy_id & 0x1f, data->reg_num & 0x1f, - data->val_in); - rc = 0; - } + __phy_write(gp, data->phy_id & 0x1f, data->reg_num & 0x1f, + data->val_in); + rc = 0; break; - }; - - spin_lock_irqsave(&gp->lock, flags); - gem_put_cell(gp); - spin_unlock_irqrestore(&gp->lock, flags); - - mutex_unlock(&gp->pm_mutex); - + } return rc; } @@ -2921,23 +2804,9 @@ static void gem_remove_one(struct pci_dev *pdev) unregister_netdev(dev); - /* Stop the link timer */ - del_timer_sync(&gp->link_timer); - - /* We shouldn't need any locking here */ - gem_get_cell(gp); - - /* Cancel reset task */ + /* Ensure reset task is truely gone */ cancel_work_sync(&gp->reset_task); - /* Shut the PHY down */ - gem_stop_phy(gp, 0); - - gem_put_cell(gp); - - /* Make sure bus master is disabled */ - pci_disable_device(gp->pdev); - /* Free resources */ pci_free_consistent(pdev, sizeof(struct gem_init_block), @@ -3043,10 +2912,6 @@ static int __devinit gem_init_one(struct pci_dev *pdev, gp->msg_enable = DEFAULT_MSG; - spin_lock_init(&gp->lock); - spin_lock_init(&gp->tx_lock); - mutex_init(&gp->pm_mutex); - init_timer(&gp->link_timer); gp->link_timer.function = gem_link_timer; gp->link_timer.data = (unsigned long) gp; @@ -3122,14 +2987,11 @@ static int __devinit gem_init_one(struct pci_dev *pdev, /* Set that now, in case PM kicks in now */ pci_set_drvdata(pdev, dev); - /* Detect & init PHY, start autoneg, we release the cell now - * too, it will be managed by whoever needs it - */ - gem_init_phy(gp); - - spin_lock_irq(&gp->lock); - gem_put_cell(gp); - spin_unlock_irq(&gp->lock); + /* We can do scatter/gather and HW checksum */ + dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; + dev->features |= dev->hw_features | NETIF_F_RXCSUM; + if (pci_using_dac) + dev->features |= NETIF_F_HIGHDMA; /* Register with kernel */ if (register_netdev(dev)) { @@ -3138,20 +3000,15 @@ static int __devinit gem_init_one(struct pci_dev *pdev, goto err_out_free_consistent; } + /* Undo the get_cell with appropriate locking (we could use + * ndo_init/uninit but that would be even more clumsy imho) + */ + rtnl_lock(); + gem_put_cell(gp); + rtnl_unlock(); + netdev_info(dev, "Sun GEM (PCI) 10/100/1000BaseT Ethernet %pM\n", dev->dev_addr); - - if (gp->phy_type == phy_mii_mdio0 || - gp->phy_type == phy_mii_mdio1) - netdev_info(dev, "Found %s PHY\n", - gp->phy_mii.def ? gp->phy_mii.def->name : "no"); - - /* GEM can do it all... */ - dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; - dev->features |= dev->hw_features | NETIF_F_RXCSUM | NETIF_F_LLTX; - if (pci_using_dac) - dev->features |= NETIF_F_HIGHDMA; - return 0; err_out_free_consistent: diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h index d225077964e2..835ce1b3cb9f 100644 --- a/drivers/net/sungem.h +++ b/drivers/net/sungem.h @@ -973,23 +973,14 @@ enum link_state { }; struct gem { - spinlock_t lock; - spinlock_t tx_lock; void __iomem *regs; int rx_new, rx_old; int tx_new, tx_old; unsigned int has_wol : 1; /* chip supports wake-on-lan */ - unsigned int asleep : 1; /* chip asleep, protected by pm_mutex */ unsigned int asleep_wol : 1; /* was asleep with WOL enabled */ - unsigned int opened : 1; /* driver opened, protected by pm_mutex */ - unsigned int running : 1; /* chip running, protected by lock */ - /* cell enable count, protected by lock */ int cell_enabled; - - struct mutex pm_mutex; - u32 msg_enable; u32 status; @@ -1033,20 +1024,4 @@ struct gem { #define found_mii_phy(gp) ((gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) && \ gp->phy_mii.def && gp->phy_mii.def->ops) -#define ALIGNED_RX_SKB_ADDR(addr) \ - ((((unsigned long)(addr) + (64UL - 1UL)) & ~(64UL - 1UL)) - (unsigned long)(addr)) -static __inline__ struct sk_buff *gem_alloc_skb(int size, - gfp_t gfp_flags) -{ - struct sk_buff *skb = alloc_skb(size + 64, gfp_flags); - - if (skb) { - int offset = (int) ALIGNED_RX_SKB_ADDR(skb->data); - if (offset) - skb_reserve(skb, offset); - } - - return skb; -} - #endif /* _SUNGEM_H */ diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f4b01c638a33..c8a145d72f17 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -26,6 +26,7 @@ #include <linux/delay.h> #include <linux/in.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/ioport.h> #include <linux/pci.h> #include <linux/netdevice.h> @@ -5774,7 +5775,7 @@ static void tg3_skb_error_unmap(struct tg3_napi *tnapi, dma_unmap_addr(txb, mapping), skb_headlen(skb), PCI_DMA_TODEVICE); - for (i = 0; i <= last; i++) { + for (i = 0; i < last; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; entry = NEXT_TX(entry); diff --git a/drivers/net/tile/tilepro.c b/drivers/net/tile/tilepro.c index 1e980fdd9d77..1e2af96fc29c 100644 --- a/drivers/net/tile/tilepro.c +++ b/drivers/net/tile/tilepro.c @@ -1658,11 +1658,9 @@ static int tile_net_stop(struct net_device *dev) while (tile_net_lepp_free_comps(dev, true)) /* loop */; - /* Wipe the EPP queue. */ + /* Wipe the EPP queue, and wait till the stores hit the EPP. */ memset(priv->eq, 0, sizeof(lepp_queue_t)); - - /* Evict the EPP queue. */ - finv_buffer(priv->eq, EQ_SIZE); + mb(); return 0; } @@ -2398,7 +2396,7 @@ static void tile_net_cleanup(void) struct net_device *dev = tile_net_devs[i]; struct tile_net_priv *priv = netdev_priv(dev); unregister_netdev(dev); - finv_buffer(priv->eq, EQ_SIZE); + finv_buffer_remote(priv->eq, EQ_SIZE, 0); __free_pages(priv->eq_pages, EQ_ORDER); free_netdev(dev); } diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index ace6404e2fac..145871b3130b 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -29,8 +29,10 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/hardirq.h> #include <linux/module.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/ioport.h> #include <linux/eisa.h> #include <linux/pci.h> diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index ff32befd8443..b6162fe2348e 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -304,7 +304,7 @@ static int __devinit xl_probe(struct pci_dev *pdev, if ((i = pci_request_regions(pdev,"3c359"))) { return i ; - } ; + } /* * Allowing init_trdev to allocate the private data will align @@ -1773,7 +1773,9 @@ static void xl_wait_misr_flags(struct net_device *dev) if (readb(xl_mmio + MMIO_MACDATA) != 0) { /* Misr not clear */ for (i=0; i<6; i++) { writel(MEM_BYTE_READ | 0xDFFE0 | i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; - while (readb(xl_mmio + MMIO_MACDATA) != 0 ) {} ; /* Empty Loop */ + while (readb(xl_mmio + MMIO_MACDATA) != 0) { + ; /* Empty Loop */ + } } } diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index 4786497de03e..e257a00fe14b 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -123,6 +123,7 @@ in the event that chatty debug messages are desired - jjs 12/30/98 */ /* some 95 OS send many non UI frame; this allow removing the warning */ #define TR_FILTERNONUI 1 +#include <linux/interrupt.h> #include <linux/ioport.h> #include <linux/netdevice.h> #include <linux/ip.h> @@ -177,7 +178,7 @@ static char __devinit *adapter_def(char type) case 0xD: return "16/4 Adapter/A (short) | 16/4 ISA-16 Adapter"; case 0xC: return "Auto 16/4 Adapter"; default: return "adapter (unknown type)"; - }; + } }; #define TRC_INIT 0x01 /* Trace initialization & PROBEs */ diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c index 1313aa1315f0..2bedc0ace812 100644 --- a/drivers/net/tokenring/madgemc.c +++ b/drivers/net/tokenring/madgemc.c @@ -727,7 +727,7 @@ static int __devexit madgemc_remove(struct device *device) return 0; } -static const short madgemc_adapter_ids[] __devinitconst = { +static short madgemc_adapter_ids[] __initdata = { 0x002d, 0x0000 }; diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index 5c633a32eaeb..64cb9ac19ed9 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -33,6 +33,7 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/net.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index e2f692351180..ce90efc6ba3c 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -38,6 +38,7 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/pci.h> #include <linux/delay.h> #include <linux/ethtool.h> diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 45144d5bd11b..efaa1d69b720 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -1995,7 +1995,7 @@ SetMulticastFilter(struct net_device *dev) static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST; -static int __devinit de4x5_eisa_probe (struct device *gendev) +static int __init de4x5_eisa_probe (struct device *gendev) { struct eisa_device *edev; u_long iobase; @@ -2097,7 +2097,7 @@ static int __devexit de4x5_eisa_remove (struct device *device) return 0; } -static const struct eisa_device_id de4x5_eisa_ids[] __devinitconst = { +static struct eisa_device_id de4x5_eisa_ids[] = { { "DEC4250", 0 }, /* 0 is the board name index... */ { "" } }; diff --git a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c index aa4d9dad0395..52d898bdbeb4 100644 --- a/drivers/net/tulip/pnic.c +++ b/drivers/net/tulip/pnic.c @@ -13,6 +13,7 @@ Please submit bugs to http://bugzilla.kernel.org/ . */ +#include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/jiffies.h> #include "tulip.h" diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index 82f87647207e..1246998a677c 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -28,6 +28,7 @@ #include <linux/slab.h> #include "tulip.h" #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/etherdevice.h> #include <linux/delay.h> #include <linux/mii.h> diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 74e94054ab1a..8a27cbf19dd6 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -666,7 +666,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, case TUN_TAP_DEV: skb->protocol = eth_type_trans(skb, tun->dev); break; - }; + } if (gso.gso_type != VIRTIO_NET_HDR_GSO_NONE) { pr_debug("GSO!\n"); diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index d7221c4a5dcf..8056f8a27c6a 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -495,7 +495,7 @@ static void catc_ctrl_run(struct catc *catc) if (!q->dir && q->buf && q->len) memcpy(catc->ctrl_buf, q->buf, q->len); - if ((status = usb_submit_urb(catc->ctrl_urb, GFP_KERNEL))) + if ((status = usb_submit_urb(catc->ctrl_urb, GFP_ATOMIC))) err("submit(ctrl_urb) status %d", status); } diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index cdd3ae486109..f33ca6aa29e9 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -54,7 +54,7 @@ #include <linux/usb/usbnet.h> #include <linux/usb/cdc.h> -#define DRIVER_VERSION "24-May-2011" +#define DRIVER_VERSION "01-June-2011" /* CDC NCM subclass 3.2.1 */ #define USB_CDC_NCM_NDP16_LENGTH_MIN 0x10 @@ -1234,6 +1234,7 @@ static struct usb_driver cdc_ncm_driver = { .disconnect = cdc_ncm_disconnect, .suspend = usbnet_suspend, .resume = usbnet_resume, + .reset_resume = usbnet_resume, .supports_autosuspend = 1, }; diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 06daa9d6fee8..f92924283d3b 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -1887,7 +1887,7 @@ static void velocity_error(struct velocity_info *vptr, int status) else netif_wake_queue(vptr->dev); - }; + } if (status & ISR_MIBFI) velocity_update_hw_mibs(vptr); if (status & ISR_LSTEI) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 0cb0b0632672..f6853247a620 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -609,7 +609,7 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) * before it gets out of hand. Naturally, this wastes entries. */ if (capacity < 2+MAX_SKB_FRAGS) { netif_stop_queue(dev); - if (unlikely(!virtqueue_enable_cb(vi->svq))) { + if (unlikely(!virtqueue_enable_cb_delayed(vi->svq))) { /* More just got used, free them then recheck. */ capacity += free_old_xmit_skbs(vi); if (capacity >= 2+MAX_SKB_FRAGS) { diff --git a/drivers/net/vxge/vxge-config.h b/drivers/net/vxge/vxge-config.h index 359b9b9f8041..6219006d9d2e 100644 --- a/drivers/net/vxge/vxge-config.h +++ b/drivers/net/vxge/vxge-config.h @@ -13,6 +13,7 @@ ******************************************************************************/ #ifndef VXGE_CONFIG_H #define VXGE_CONFIG_H +#include <linux/hardirq.h> #include <linux/list.h> #include <linux/slab.h> diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c index 8ab870a2ad02..e658edd1c959 100644 --- a/drivers/net/vxge/vxge-main.c +++ b/drivers/net/vxge/vxge-main.c @@ -44,6 +44,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/if_vlan.h> +#include <linux/interrupt.h> #include <linux/pci.h> #include <linux/slab.h> #include <linux/tcp.h> diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c index 859dba9b972e..a0976d1f97c6 100644 --- a/drivers/net/wan/cycx_main.c +++ b/drivers/net/wan/cycx_main.c @@ -50,6 +50,7 @@ #include <linux/wanrouter.h> /* WAN router definitions */ #include <linux/cyclomx.h> /* cyclomx common user API definitions */ #include <linux/init.h> /* __init (when not using as a module) */ +#include <linux/interrupt.h> unsigned int cycx_debug; diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index acb9ea830628..3590d588327c 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -99,6 +99,7 @@ #include <asm/irq.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/string.h> #include <linux/if_arp.h> diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index e050bd65e037..1eba06f6fa4c 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -25,6 +25,7 @@ #include <linux/slab.h> #include <linux/ioport.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/if.h> #include <linux/hdlc.h> #include <asm/io.h> diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index 737b59f1a8dc..9617d3d0ee39 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c @@ -3242,8 +3242,7 @@ static inline void show_version(void) rcsdate++; tmp = strrchr(rcsdate, ' '); *tmp = '\0'; - printk(KERN_INFO "Cyclades-PC300 driver %s %s (built %s %s)\n", - rcsvers, rcsdate, __DATE__, __TIME__); + printk(KERN_INFO "Cyclades-PC300 driver %s %s\n", rcsvers, rcsdate); } /* show_version */ static const struct net_device_ops cpc_netdev_ops = { diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c index db73a7be199f..4ea89fe0006f 100644 --- a/drivers/net/wan/wanxl.c +++ b/drivers/net/wan/wanxl.c @@ -22,6 +22,7 @@ #include <linux/string.h> #include <linux/errno.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/ioport.h> #include <linux/netdevice.h> #include <linux/hdlc.h> diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index afe2cbc6cb24..43ebc44fc82c 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -16,6 +16,7 @@ */ #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/if.h> #include <linux/skbuff.h> #include <linux/slab.h> diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index df2484d45474..c983c10e0f6a 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -164,7 +164,7 @@ static int airo_resume(struct pcmcia_device *link) return 0; } -static struct pcmcia_device_id airo_ids[] = { +static const struct pcmcia_device_id airo_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x015f, 0x000a), PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0005), PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0007), diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 3bf1d83ab41f..57933db57633 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -19,6 +19,7 @@ #include <linux/etherdevice.h> #include <linux/device.h> +#include <linux/interrupt.h> #include <linux/leds.h> #include <linux/completion.h> diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index 39a11e8af4fa..7e45ca2e78ef 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -40,6 +40,7 @@ ******************************************************************************/ #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/ptrace.h> diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 05263516c113..ec295c4f677d 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -122,7 +122,7 @@ static int atmel_config(struct pcmcia_device *link) { local_info_t *dev; int ret; - struct pcmcia_device_id *did; + const struct pcmcia_device_id *did; dev = link->priv; did = dev_get_drvdata(&link->dev); @@ -211,7 +211,7 @@ static int atmel_resume(struct pcmcia_device *link) .prod_id_hash = { (vh1), (vh2), 0, 0 }, \ .driver_info = (kernel_ulong_t)(info), } -static struct pcmcia_device_id atmel_ids[] = { +static const struct pcmcia_device_id atmel_ids[] = { PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0620, ATMEL_FW_TYPE_502_3COM), PCMCIA_DEVICE_MANF_CARD_INFO(0x0101, 0x0696, ATMEL_FW_TYPE_502_3COM), PCMCIA_DEVICE_MANF_CARD_INFO(0x01bf, 0x3302, ATMEL_FW_TYPE_502E), diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 1d8d98324d15..cae31463ead9 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -4099,7 +4099,7 @@ static int b43_phy_versioning(struct b43_wldev *dev) #endif default: unsupported = 1; - }; + } if (unsupported) { b43err(dev->wl, "FOUND UNSUPPORTED PHY " "(Analog %u, Type %u, Revision %u)\n", diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c index 7dcba5fafdc7..2c8461dcf1b0 100644 --- a/drivers/net/wireless/b43/pcmcia.c +++ b/drivers/net/wireless/b43/pcmcia.c @@ -32,7 +32,7 @@ #include <pcmcia/cisreg.h> -static /*const */ struct pcmcia_device_id b43_pcmcia_tbl[] = { +static const struct pcmcia_device_id b43_pcmcia_tbl[] = { PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448), PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x476), PCMCIA_DEVICE_NULL, diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index ffa46717323e..d6db6c17da4f 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -2970,7 +2970,7 @@ static int b43legacy_phy_versioning(struct b43legacy_wldev *dev) break; default: unsupported = 1; - }; + } if (unsupported) { b43legacyerr(dev->wl, "FOUND UNSUPPORTED PHY " "(Analog %u, Type %u, Revision %u)\n", diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 2176edede39b..c052a0d5cbdd 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -620,7 +620,7 @@ static int hostap_cs_resume(struct pcmcia_device *link) return 0; } -static struct pcmcia_device_id hostap_cs_ids[] = { +static const struct pcmcia_device_id hostap_cs_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index 88dc6a52bdf1..7bb0b4b3f2cb 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -1,6 +1,7 @@ #ifndef HOSTAP_WLAN_H #define HOSTAP_WLAN_H +#include <linux/interrupt.h> #include <linux/wireless.h> #include <linux/netdevice.h> #include <linux/mutex.h> diff --git a/drivers/net/wireless/ipw2x00/ipw2200.h b/drivers/net/wireless/ipw2x00/ipw2200.h index 91795b5a93c5..ecb561d7a7a0 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.h +++ b/drivers/net/wireless/ipw2x00/ipw2200.h @@ -32,6 +32,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/mutex.h> #include <linux/pci.h> diff --git a/drivers/net/wireless/ipw2x00/libipw_wx.c b/drivers/net/wireless/ipw2x00/libipw_wx.c index d7bd6cf00a81..6623e5052254 100644 --- a/drivers/net/wireless/ipw2x00/libipw_wx.c +++ b/drivers/net/wireless/ipw2x00/libipw_wx.c @@ -30,6 +30,7 @@ ******************************************************************************/ +#include <linux/hardirq.h> #include <linux/kmod.h> #include <linux/slab.h> #include <linux/module.h> diff --git a/drivers/net/wireless/iwlegacy/iwl-dev.h b/drivers/net/wireless/iwlegacy/iwl-dev.h index be0106c6a2da..416448acd971 100644 --- a/drivers/net/wireless/iwlegacy/iwl-dev.h +++ b/drivers/net/wireless/iwlegacy/iwl-dev.h @@ -32,6 +32,7 @@ #ifndef __iwl_legacy_dev_h__ #define __iwl_legacy_dev_h__ +#include <linux/interrupt.h> #include <linux/pci.h> /* for struct pci_device_id */ #include <linux/kernel.h> #include <linux/leds.h> diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index c8de236c141b..7ad98d868954 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -31,6 +31,7 @@ #ifndef __iwl_dev_h__ #define __iwl_dev_h__ +#include <linux/interrupt.h> #include <linux/pci.h> /* for struct pci_device_id */ #include <linux/kernel.h> #include <linux/wait.h> diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c index 49067092d336..6f1afe6bbc8c 100644 --- a/drivers/net/wireless/iwmc3200wifi/fw.c +++ b/drivers/net/wireless/iwmc3200wifi/fw.c @@ -187,7 +187,7 @@ static int iwm_load_img(struct iwm_priv *iwm, const char *img_name) if (ret < 0) goto err_release_fw; opcode_idx++; - }; + } /* Read firmware version */ fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_SW_VER, 0); diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index 5d637af2d7c3..b456a53b64b1 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -8,6 +8,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/hardirq.h> #include <linux/sched.h> #include <linux/wait.h> #include <linux/slab.h> diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 71c8f3fccfa1..9dcf967e1ee4 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -3,6 +3,7 @@ * It prepares command and sends it to firmware when it is ready. */ +#include <linux/hardirq.h> #include <linux/kfifo.h> #include <linux/sched.h> #include <linux/slab.h> diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c index 207fc361db84..2ffe5a1ff003 100644 --- a/drivers/net/wireless/libertas/cmdresp.c +++ b/drivers/net/wireless/libertas/cmdresp.c @@ -3,6 +3,7 @@ * responses as well as events generated by firmware. */ +#include <linux/hardirq.h> #include <linux/slab.h> #include <linux/delay.h> #include <linux/sched.h> diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 23250f621761..1af182778844 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -1,6 +1,7 @@ #include <linux/dcache.h> #include <linux/debugfs.h> #include <linux/delay.h> +#include <linux/hardirq.h> #include <linux/mm.h> #include <linux/string.h> #include <linux/slab.h> diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index 29dbce4a9f86..4dfb3bfd2cf3 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -1,3 +1,4 @@ +#include <linux/hardirq.h> #include <linux/netdevice.h> #include <linux/ethtool.h> #include <linux/delay.h> diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c index 63ed5798365c..e26935179861 100644 --- a/drivers/net/wireless/libertas/if_cs.c +++ b/drivers/net/wireless/libertas/if_cs.c @@ -983,7 +983,7 @@ static void if_cs_detach(struct pcmcia_device *p_dev) /* Module initialization */ /********************************************************************/ -static struct pcmcia_device_id if_cs_ids[] = { +static const struct pcmcia_device_id if_cs_ids[] = { PCMCIA_DEVICE_MANF_CARD(CF8305_MANFID, CF8305_CARDID), PCMCIA_DEVICE_MANF_CARD(CF8381_MANFID, CF8381_CARDID), PCMCIA_DEVICE_MANF_CARD(CF8385_MANFID, CF8385_CARDID), diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 463352c890d7..4fa0be9943f9 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -19,6 +19,8 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/hardirq.h> +#include <linux/interrupt.h> #include <linux/moduleparam.h> #include <linux/firmware.h> #include <linux/jiffies.h> diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 8c40949cb076..cf3d2c8e1969 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -9,6 +9,7 @@ #include <linux/moduleparam.h> #include <linux/delay.h> #include <linux/etherdevice.h> +#include <linux/hardirq.h> #include <linux/netdevice.h> #include <linux/if_arp.h> #include <linux/kthread.h> diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c index 24cf06680c6b..7969d104189d 100644 --- a/drivers/net/wireless/libertas/mesh.c +++ b/drivers/net/wireless/libertas/mesh.c @@ -2,6 +2,7 @@ #include <linux/delay.h> #include <linux/etherdevice.h> +#include <linux/hardirq.h> #include <linux/netdevice.h> #include <linux/if_ether.h> #include <linux/if_arp.h> diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c index fdb0448301a0..bfb8898ae518 100644 --- a/drivers/net/wireless/libertas/rx.c +++ b/drivers/net/wireless/libertas/rx.c @@ -5,6 +5,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/etherdevice.h> +#include <linux/hardirq.h> #include <linux/slab.h> #include <linux/types.h> #include <net/cfg80211.h> diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index bbb95f88dc01..f19495b178f6 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -1,6 +1,7 @@ /* * This file contains the handling of TX in wlan driver. */ +#include <linux/hardirq.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/sched.h> diff --git a/drivers/net/wireless/libertas_tf/cmd.c b/drivers/net/wireless/libertas_tf/cmd.c index 8945afd6ce3e..13557fe0bf95 100644 --- a/drivers/net/wireless/libertas_tf/cmd.c +++ b/drivers/net/wireless/libertas_tf/cmd.c @@ -9,6 +9,7 @@ */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/hardirq.h> #include <linux/slab.h> #include "libertas_tf.h" diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index d4005081f1df..5beb58142e97 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -9,6 +9,7 @@ */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/hardirq.h> #include <linux/slab.h> #include <linux/etherdevice.h> diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index 32261189bcef..8ff43c281411 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -10,6 +10,7 @@ */ #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 62c6b2b37dbe..b0f233f1100e 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -1958,7 +1958,7 @@ irqreturn_t orinoco_interrupt(int irq, void *dev_id) evstat = hermes_read_regn(hw, EVSTAT); events = evstat & hw->inten; - }; + } orinoco_unlock(priv, &flags); return IRQ_HANDLED; diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c index 32954c4b243a..88e3c0ebcaad 100644 --- a/drivers/net/wireless/orinoco/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -237,7 +237,7 @@ static int orinoco_cs_resume(struct pcmcia_device *link) /* Module initialization */ /********************************************************************/ -static struct pcmcia_device_id orinoco_cs_ids[] = { +static const struct pcmcia_device_id orinoco_cs_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0777), /* 3Com AirConnect PCI 777A */ PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), /* Lucent Orinoco and old Intersil */ PCMCIA_DEVICE_MANF_CARD(0x016b, 0x0001), /* Ericsson WLAN Card C11 */ diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c index db34c282e59b..81f3673d31d4 100644 --- a/drivers/net/wireless/orinoco/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -301,7 +301,7 @@ spectrum_cs_resume(struct pcmcia_device *link) /* Module initialization */ /********************************************************************/ -static struct pcmcia_device_id spectrum_cs_ids[] = { +static const struct pcmcia_device_id spectrum_cs_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x026c, 0x0001), /* Symbol Spectrum24 LA4137 */ PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0001), /* Socket Communications CF */ PCMCIA_DEVICE_PROD_ID12("Intel", "PRO/Wireless LAN PC Card", 0x816cc815, 0x6fbf459a), /* 2011B, not 2011 */ diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h index ee9bc62a4fa2..7aa509f7e387 100644 --- a/drivers/net/wireless/p54/p54pci.h +++ b/drivers/net/wireless/p54/p54pci.h @@ -1,5 +1,6 @@ #ifndef P54PCI_H #define P54PCI_H +#include <linux/interrupt.h> /* * Defines for PCI based mac80211 Prism54 driver diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c index ec2c75d77cea..5d0f61508a2e 100644 --- a/drivers/net/wireless/prism54/islpci_dev.c +++ b/drivers/net/wireless/prism54/islpci_dev.c @@ -18,6 +18,7 @@ * */ +#include <linux/hardirq.h> #include <linux/module.h> #include <linux/slab.h> diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h index c4d0f19b7cbc..c40403877f97 100644 --- a/drivers/net/wireless/prism54/islpci_dev.h +++ b/drivers/net/wireless/prism54/islpci_dev.h @@ -22,6 +22,7 @@ #ifndef _ISLPCI_DEV_H #define _ISLPCI_DEV_H +#include <linux/irqreturn.h> #include <linux/netdevice.h> #include <linux/wireless.h> #include <net/iw_handler.h> diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c index b5e64d71b7a6..9e68e0cb718e 100644 --- a/drivers/net/wireless/prism54/islpci_hotplug.c +++ b/drivers/net/wireless/prism54/islpci_hotplug.c @@ -17,6 +17,7 @@ * */ +#include <linux/interrupt.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/delay.h> diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 0764d1a30d13..2a06ebcd67c5 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -2781,7 +2781,7 @@ static const struct file_operations int_proc_fops = { }; #endif -static struct pcmcia_device_id ray_ids[] = { +static const struct pcmcia_device_id ray_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x01a6, 0x0000), PCMCIA_DEVICE_NULL, }; diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 75d2c6cc93eb..84ab7d1acb6a 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1274,7 +1274,7 @@ static void rt2800_config_ht_opmode(struct rt2x00_dev *rt2x00dev, gf20_rate = gf40_rate = 0x0003; } break; - }; + } /* check for STAs not supporting greenfield mode */ if (any_sta_nongf) diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 5513edfa952a..9ccc53733bae 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -219,7 +219,7 @@ static void rt2800pci_start_queue(struct data_queue *queue) break; default: break; - }; + } } static void rt2800pci_kick_queue(struct data_queue *queue) diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index c446db69bd3c..4efaf886fb89 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -29,6 +29,7 @@ #define RT2X00_H #include <linux/bitops.h> +#include <linux/interrupt.h> #include <linux/skbuff.h> #include <linux/workqueue.h> #include <linux/firmware.h> diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 80db5cabc9b9..66b29dc07cc3 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -16,6 +16,7 @@ */ #include <linux/init.h> +#include <linux/interrupt.h> #include <linux/pci.h> #include <linux/slab.h> #include <linux/delay.h> diff --git a/drivers/net/wireless/wl1251/sdio.c b/drivers/net/wireless/wl1251/sdio.c index f51a0241a440..f78694295c39 100644 --- a/drivers/net/wireless/wl1251/sdio.c +++ b/drivers/net/wireless/wl1251/sdio.c @@ -19,6 +19,7 @@ * Copyright (C) 2008 Google Inc * Copyright (C) 2009 Bob Copeland (me@bobcopeland.com) */ +#include <linux/interrupt.h> #include <linux/module.h> #include <linux/mod_devicetable.h> #include <linux/mmc/sdio_func.h> diff --git a/drivers/net/wireless/wl1251/spi.c b/drivers/net/wireless/wl1251/spi.c index af6448c4d3e2..eaa5f9556200 100644 --- a/drivers/net/wireless/wl1251/spi.c +++ b/drivers/net/wireless/wl1251/spi.c @@ -19,6 +19,7 @@ * */ +#include <linux/interrupt.h> #include <linux/irq.h> #include <linux/module.h> #include <linux/slab.h> diff --git a/drivers/net/wireless/wl12xx/io.h b/drivers/net/wireless/wl12xx/io.h index beed621a8ae0..20b00319e444 100644 --- a/drivers/net/wireless/wl12xx/io.h +++ b/drivers/net/wireless/wl12xx/io.h @@ -25,6 +25,7 @@ #ifndef __IO_H__ #define __IO_H__ +#include <linux/irqreturn.h> #include "reg.h" #define HW_ACCESS_MEMORY_MAX_RANGE 0x1FFC0 diff --git a/drivers/net/wireless/wl12xx/spi.c b/drivers/net/wireless/wl12xx/spi.c index 51662bb68019..beebf64c5359 100644 --- a/drivers/net/wireless/wl12xx/spi.c +++ b/drivers/net/wireless/wl12xx/spi.c @@ -21,6 +21,7 @@ * */ +#include <linux/interrupt.h> #include <linux/irq.h> #include <linux/module.h> #include <linux/crc7.h> diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index fc08f36fe1f5..6bc7c92fbff7 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -2000,7 +2000,7 @@ static int wl3501_resume(struct pcmcia_device *link) } -static struct pcmcia_device_id wl3501_ids[] = { +static const struct pcmcia_device_id wl3501_ids[] = { PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0001), PCMCIA_DEVICE_NULL }; diff --git a/drivers/net/znet.c b/drivers/net/znet.c index ec2800ff8d42..8b8881718f5e 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -731,7 +731,7 @@ static void znet_rx(struct net_device *dev) cur_frame_end_offset -= ((count + 1)>>1) + 3; if (cur_frame_end_offset < 0) cur_frame_end_offset += RX_BUF_SIZE/2; - }; + } /* Now step forward through the list. */ do { |