diff options
Diffstat (limited to 'drivers/net')
67 files changed, 11063 insertions, 3795 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 8edb6936fb9..43d14bfb101 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -131,6 +131,8 @@ config NET_SB1000 source "drivers/net/arcnet/Kconfig" +source "drivers/net/phy/Kconfig" + # # Ethernet # @@ -1921,6 +1923,17 @@ config R8169_VLAN If in doubt, say Y. +config SIS190 + tristate "SiS190 gigabit ethernet support" + depends on PCI + select CRC32 + select MII + ---help--- + Say Y here if you have a SiS 190 PCI Gigabit Ethernet adapter. + + To compile this driver as a module, choose M here: the module + will be called sis190. This is recommended. + config SKGE tristate "New SysKonnect GigaEthernet support (EXPERIMENTAL)" depends on PCI && EXPERIMENTAL diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 63c6d1e6d4d..c5c71d70758 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -42,6 +42,7 @@ obj-$(CONFIG_EEPRO100) += eepro100.o obj-$(CONFIG_E100) += e100.o obj-$(CONFIG_TLAN) += tlan.o obj-$(CONFIG_EPIC100) += epic100.o +obj-$(CONFIG_SIS190) += sis190.o obj-$(CONFIG_SIS900) += sis900.o obj-$(CONFIG_YELLOWFIN) += yellowfin.o obj-$(CONFIG_ACENIC) += acenic.o @@ -65,6 +66,7 @@ obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o # obj-$(CONFIG_MII) += mii.o +obj-$(CONFIG_PHYLIB) += phy/ obj-$(CONFIG_SUNDANCE) += sundance.o obj-$(CONFIG_HAMACHI) += hamachi.o diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 3707df6b0cf..60304f7e7e5 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -87,7 +87,6 @@ extern struct net_device *mvme147lance_probe(int unit); extern struct net_device *tc515_probe(int unit); extern struct net_device *lance_probe(int unit); extern struct net_device *mace_probe(int unit); -extern struct net_device *macsonic_probe(int unit); extern struct net_device *mac8390_probe(int unit); extern struct net_device *mac89x0_probe(int unit); extern struct net_device *mc32_probe(int unit); @@ -284,9 +283,6 @@ static struct devprobe2 m68k_probes[] __initdata = { #ifdef CONFIG_MACMACE /* Mac 68k Quadra AV builtin Ethernet */ {mace_probe, 0}, #endif -#ifdef CONFIG_MACSONIC /* Mac SONIC-based Ethernet of all sorts */ - {macsonic_probe, 0}, -#endif #ifdef CONFIG_MAC8390 /* NuBus NS8390-based cards */ {mac8390_probe, 0}, #endif @@ -318,17 +314,9 @@ static void __init ethif_probe2(int unit) #ifdef CONFIG_TR /* Token-ring device probe */ extern int ibmtr_probe_card(struct net_device *); -extern struct net_device *sk_isa_probe(int unit); -extern struct net_device *proteon_probe(int unit); extern struct net_device *smctr_probe(int unit); static struct devprobe2 tr_probes2[] __initdata = { -#ifdef CONFIG_SKISA - {sk_isa_probe, 0}, -#endif -#ifdef CONFIG_PROTEON - {proteon_probe, 0}, -#endif #ifdef CONFIG_SMCTR {smctr_probe, 0}, #endif diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 5ce606d9dc0..19e829b567d 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -1106,18 +1106,13 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav } } - if (found) { - /* a slave was found that is using the mac address - * of the new slave - */ - printk(KERN_ERR DRV_NAME - ": Error: the hw address of slave %s is not " - "unique - cannot enslave it!", - slave->dev->name); - return -EINVAL; - } + if (!found) + return 0; - return 0; + /* Try setting slave mac to bond address and fall-through + to code handling that situation below... */ + alb_set_slave_mac_addr(slave, bond->dev->dev_addr, + bond->alb_info.rlb_enabled); } /* The slave's address is equal to the address of the bond. diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 2c930da90a8..94c9f68dd16 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1604,6 +1604,44 @@ static int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_ return 0; } +#define BOND_INTERSECT_FEATURES \ + (NETIF_F_SG|NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM) + +/* + * Compute the features available to the bonding device by + * intersection of all of the slave devices' BOND_INTERSECT_FEATURES. + * Call this after attaching or detaching a slave to update the + * bond's features. + */ +static int bond_compute_features(struct bonding *bond) +{ + int i; + struct slave *slave; + struct net_device *bond_dev = bond->dev; + int features = bond->bond_features; + + bond_for_each_slave(bond, slave, i) { + struct net_device * slave_dev = slave->dev; + if (i == 0) { + features |= BOND_INTERSECT_FEATURES; + } + features &= + ~(~slave_dev->features & BOND_INTERSECT_FEATURES); + } + + /* turn off NETIF_F_SG if we need a csum and h/w can't do it */ + if ((features & NETIF_F_SG) && + !(features & (NETIF_F_IP_CSUM | + NETIF_F_NO_CSUM | + NETIF_F_HW_CSUM))) { + features &= ~NETIF_F_SG; + } + + bond_dev->features = features; + + return 0; +} + /* enslave device <slave> to bond device <master> */ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) { @@ -1811,6 +1849,8 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de new_slave->delay = 0; new_slave->link_failure_count = 0; + bond_compute_features(bond); + if (bond->params.miimon && !bond->params.use_carrier) { link_reporting = bond_check_dev_link(bond, slave_dev, 1); @@ -2015,7 +2055,7 @@ err_free: err_undo_flags: bond_dev->features = old_features; - + return res; } @@ -2100,6 +2140,8 @@ static int bond_release(struct net_device *bond_dev, struct net_device *slave_de /* release the slave from its bond */ bond_detach_slave(bond, slave); + bond_compute_features(bond); + if (bond->primary_slave == slave) { bond->primary_slave = NULL; } @@ -2243,6 +2285,8 @@ static int bond_release_all(struct net_device *bond_dev) bond_alb_deinit_slave(bond, slave); } + bond_compute_features(bond); + /* now that the slave is detached, unlock and perform * all the undo steps that should not be called from * within a lock. @@ -3588,6 +3632,7 @@ static int bond_master_netdev_event(unsigned long event, struct net_device *bond static int bond_slave_netdev_event(unsigned long event, struct net_device *slave_dev) { struct net_device *bond_dev = slave_dev->master; + struct bonding *bond = bond_dev->priv; switch (event) { case NETDEV_UNREGISTER: @@ -3626,6 +3671,9 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave * TODO: handle changing the primary's name */ break; + case NETDEV_FEAT_CHANGE: + bond_compute_features(bond); + break; default: break; } @@ -4526,6 +4574,11 @@ static inline void bond_set_mode_ops(struct bonding *bond, int mode) } } +static struct ethtool_ops bond_ethtool_ops = { + .get_tx_csum = ethtool_op_get_tx_csum, + .get_sg = ethtool_op_get_sg, +}; + /* * Does not allocate but creates a /proc entry. * Allowed to fail. @@ -4555,6 +4608,7 @@ static int __init bond_init(struct net_device *bond_dev, struct bond_params *par bond_dev->stop = bond_close; bond_dev->get_stats = bond_get_stats; bond_dev->do_ioctl = bond_do_ioctl; + bond_dev->ethtool_ops = &bond_ethtool_ops; bond_dev->set_multicast_list = bond_set_multicast_list; bond_dev->change_mtu = bond_change_mtu; bond_dev->set_mac_address = bond_set_mac_address; @@ -4591,6 +4645,8 @@ static int __init bond_init(struct net_device *bond_dev, struct bond_params *par NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER); + bond->bond_features = bond_dev->features; + #ifdef CONFIG_PROC_FS bond_create_proc_entry(bond); #endif diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index d27f377b3ee..38819698086 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -211,6 +211,9 @@ struct bonding { struct bond_params params; struct list_head vlan_list; struct vlan_group *vlgrp; + /* the features the bonding device supports, independently + * of any slaves */ + int bond_features; }; /** diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index b82fd15d089..9b596e0bbf9 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2767,7 +2767,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) " next_to_use <%x>\n" " next_to_clean <%x>\n" "buffer_info[next_to_clean]\n" - " dma <%zx>\n" + " dma <%llx>\n" " time_stamp <%lx>\n" " next_to_watch <%x>\n" " jiffies <%lx>\n" @@ -2776,7 +2776,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter) E1000_READ_REG(&adapter->hw, TDT), tx_ring->next_to_use, i, - tx_ring->buffer_info[i].dma, + (unsigned long long)tx_ring->buffer_info[i].dma, tx_ring->buffer_info[i].time_stamp, eop, jiffies, diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 1795425f512..8c62ced2c9b 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -1263,8 +1263,8 @@ speedo_init_rx_ring(struct net_device *dev) for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb; skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD)); - /* XXX: do we really want to call this before the NULL check? --hch */ - rx_align(skb); /* Align IP on 16 byte boundary */ + if (skb) + rx_align(skb); /* Align IP on 16 byte boundary */ sp->rx_skbuff[i] = skb; if (skb == NULL) break; /* OK. Just initially short of Rx bufs. */ @@ -1654,8 +1654,8 @@ static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry) struct sk_buff *skb; /* Get a fresh skbuff to replace the consumed one. */ skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD)); - /* XXX: do we really want to call this before the NULL check? --hch */ - rx_align(skb); /* Align IP on 16 byte boundary */ + if (skb) + rx_align(skb); /* Align IP on 16 byte boundary */ sp->rx_skbuff[entry] = skb; if (skb == NULL) { sp->rx_ringp[entry] = NULL; diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 64f0f697c95..7d93948aec8 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -85,6 +85,16 @@ * 0.33: 16 May 2005: Support for MCP51 added. * 0.34: 18 Jun 2005: Add DEV_NEED_LINKTIMER to all nForce nics. * 0.35: 26 Jun 2005: Support for MCP55 added. + * 0.36: 28 Jun 2005: Add jumbo frame support. + * 0.37: 10 Jul 2005: Additional ethtool support, cleanup of pci id list + * 0.38: 16 Jul 2005: tx irq rewrite: Use global flags instead of + * per-packet flags. + * 0.39: 18 Jul 2005: Add 64bit descriptor support. + * 0.40: 19 Jul 2005: Add support for mac address change. + * 0.41: 30 Jul 2005: Write back original MAC in nv_close instead + * of nv_remove + * 0.42: 06 Aug 2005: Fix lack of link speed initialization + * in the second (and later) nv_open call * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -96,7 +106,7 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.35" +#define FORCEDETH_VERSION "0.41" #define DRV_NAME "forcedeth" #include <linux/module.h> @@ -131,11 +141,10 @@ * Hardware access: */ -#define DEV_NEED_LASTPACKET1 0x0001 /* set LASTPACKET1 in tx flags */ -#define DEV_IRQMASK_1 0x0002 /* use NVREG_IRQMASK_WANTED_1 for irq mask */ -#define DEV_IRQMASK_2 0x0004 /* use NVREG_IRQMASK_WANTED_2 for irq mask */ -#define DEV_NEED_TIMERIRQ 0x0008 /* set the timer irq flag in the irq mask */ -#define DEV_NEED_LINKTIMER 0x0010 /* poll link settings. Relies on the timer irq */ +#define DEV_NEED_TIMERIRQ 0x0001 /* set the timer irq flag in the irq mask */ +#define DEV_NEED_LINKTIMER 0x0002 /* poll link settings. Relies on the timer irq */ +#define DEV_HAS_LARGEDESC 0x0004 /* device supports jumbo frames and needs packet format 2 */ +#define DEV_HAS_HIGH_DMA 0x0008 /* device supports 64bit dma */ enum { NvRegIrqStatus = 0x000, @@ -146,13 +155,16 @@ enum { #define NVREG_IRQ_RX 0x0002 #define NVREG_IRQ_RX_NOBUF 0x0004 #define NVREG_IRQ_TX_ERR 0x0008 -#define NVREG_IRQ_TX2 0x0010 +#define NVREG_IRQ_TX_OK 0x0010 #define NVREG_IRQ_TIMER 0x0020 #define NVREG_IRQ_LINK 0x0040 +#define NVREG_IRQ_TX_ERROR 0x0080 #define NVREG_IRQ_TX1 0x0100 -#define NVREG_IRQMASK_WANTED_1 0x005f -#define NVREG_IRQMASK_WANTED_2 0x0147 -#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR|NVREG_IRQ_TX2|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX1)) +#define NVREG_IRQMASK_WANTED 0x00df + +#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR| \ + NVREG_IRQ_TX_OK|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX_ERROR| \ + NVREG_IRQ_TX1)) NvRegUnknownSetupReg6 = 0x008, #define NVREG_UNKSETUP6_VAL 3 @@ -286,6 +298,18 @@ struct ring_desc { u32 FlagLen; }; +struct ring_desc_ex { + u32 PacketBufferHigh; + u32 PacketBufferLow; + u32 Reserved; + u32 FlagLen; +}; + +typedef union _ring_type { + struct ring_desc* orig; + struct ring_desc_ex* ex; +} ring_type; + #define FLAG_MASK_V1 0xffff0000 #define FLAG_MASK_V2 0xffffc000 #define LEN_MASK_V1 (0xffffffff ^ FLAG_MASK_V1) @@ -293,7 +317,7 @@ struct ring_desc { #define NV_TX_LASTPACKET (1<<16) #define NV_TX_RETRYERROR (1<<19) -#define NV_TX_LASTPACKET1 (1<<24) +#define NV_TX_FORCED_INTERRUPT (1<<24) #define NV_TX_DEFERRED (1<<26) #define NV_TX_CARRIERLOST (1<<27) #define NV_TX_LATECOLLISION (1<<28) @@ -303,7 +327,7 @@ struct ring_desc { #define NV_TX2_LASTPACKET (1<<29) #define NV_TX2_RETRYERROR (1<<18) -#define NV_TX2_LASTPACKET1 (1<<23) +#define NV_TX2_FORCED_INTERRUPT (1<<30) #define NV_TX2_DEFERRED (1<<25) #define NV_TX2_CARRIERLOST (1<<26) #define NV_TX2_LATECOLLISION (1<<27) @@ -379,9 +403,13 @@ struct ring_desc { #define TX_LIMIT_START 62 /* rx/tx mac addr + type + vlan + align + slack*/ -#define RX_NIC_BUFSIZE (ETH_DATA_LEN + 64) -/* even more slack */ -#define RX_ALLOC_BUFSIZE (ETH_DATA_LEN + 128) +#define NV_RX_HEADERS (64) +/* even more slack. */ +#define NV_RX_ALLOC_PAD (64) + +/* maximum mtu size */ +#define NV_PKTLIMIT_1 ETH_DATA_LEN /* hard limit not known */ +#define NV_PKTLIMIT_2 9100 /* Actual limit according to NVidia: 9202 */ #define OOM_REFILL (1+HZ/20) #define POLL_WAIT (1+HZ/100) @@ -396,6 +424,7 @@ struct ring_desc { */ #define DESC_VER_1 0x0 #define DESC_VER_2 (0x02100|NVREG_TXRXCTL_RXCHECK) +#define DESC_VER_3 (0x02200|NVREG_TXRXCTL_RXCHECK) /* PHY defines */ #define PHY_OUI_MARVELL 0x5043 @@ -468,11 +497,12 @@ struct fe_priv { /* rx specific fields. * Locking: Within irq hander or disable_irq+spin_lock(&np->lock); */ - struct ring_desc *rx_ring; + ring_type rx_ring; unsigned int cur_rx, refill_rx; struct sk_buff *rx_skbuff[RX_RING]; dma_addr_t rx_dma[RX_RING]; unsigned int rx_buf_sz; + unsigned int pkt_limit; struct timer_list oom_kick; struct timer_list nic_poll; @@ -484,7 +514,7 @@ struct fe_priv { /* * tx specific fields. */ - struct ring_desc *tx_ring; + ring_type tx_ring; unsigned int next_tx, nic_tx; struct sk_buff *tx_skbuff[TX_RING]; dma_addr_t tx_dma[TX_RING]; @@ -519,6 +549,11 @@ static inline u32 nv_descr_getlength(struct ring_desc *prd, u32 v) & ((v == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2); } +static inline u32 nv_descr_getlength_ex(struct ring_desc_ex *prd, u32 v) +{ + return le32_to_cpu(prd->FlagLen) & LEN_MASK_V2; +} + static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target, int delay, int delaymax, const char *msg) { @@ -792,7 +827,7 @@ static int nv_alloc_rx(struct net_device *dev) nr = refill_rx % RX_RING; if (np->rx_skbuff[nr] == NULL) { - skb = dev_alloc_skb(RX_ALLOC_BUFSIZE); + skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD); if (!skb) break; @@ -803,9 +838,16 @@ static int nv_alloc_rx(struct net_device *dev) } np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len, PCI_DMA_FROMDEVICE); - np->rx_ring[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]); - wmb(); - np->rx_ring[nr].FlagLen = cpu_to_le32(RX_NIC_BUFSIZE | NV_RX_AVAIL); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + np->rx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]); + wmb(); + np->rx_ring.orig[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL); + } else { + np->rx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->rx_dma[nr]) >> 32; + np->rx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF; + wmb(); + np->rx_ring.ex[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL); + } dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n", dev->name, refill_rx); refill_rx++; @@ -831,19 +873,37 @@ static void nv_do_rx_refill(unsigned long data) enable_irq(dev->irq); } -static int nv_init_ring(struct net_device *dev) +static void nv_init_rx(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); int i; - np->next_tx = np->nic_tx = 0; - for (i = 0; i < TX_RING; i++) - np->tx_ring[i].FlagLen = 0; - np->cur_rx = RX_RING; np->refill_rx = 0; for (i = 0; i < RX_RING; i++) - np->rx_ring[i].FlagLen = 0; + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + np->rx_ring.orig[i].FlagLen = 0; + else + np->rx_ring.ex[i].FlagLen = 0; +} + +static void nv_init_tx(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + int i; + + np->next_tx = np->nic_tx = 0; + for (i = 0; i < TX_RING; i++) + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + np->tx_ring.orig[i].FlagLen = 0; + else + np->tx_ring.ex[i].FlagLen = 0; +} + +static int nv_init_ring(struct net_device *dev) +{ + nv_init_tx(dev); + nv_init_rx(dev); return nv_alloc_rx(dev); } @@ -852,7 +912,10 @@ static void nv_drain_tx(struct net_device *dev) struct fe_priv *np = get_nvpriv(dev); int i; for (i = 0; i < TX_RING; i++) { - np->tx_ring[i].FlagLen = 0; + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + np->tx_ring.orig[i].FlagLen = 0; + else + np->tx_ring.ex[i].FlagLen = 0; if (np->tx_skbuff[i]) { pci_unmap_single(np->pci_dev, np->tx_dma[i], np->tx_skbuff[i]->len, @@ -869,7 +932,10 @@ static void nv_drain_rx(struct net_device *dev) struct fe_priv *np = get_nvpriv(dev); int i; for (i = 0; i < RX_RING; i++) { - np->rx_ring[i].FlagLen = 0; + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + np->rx_ring.orig[i].FlagLen = 0; + else + np->rx_ring.ex[i].FlagLen = 0; wmb(); if (np->rx_skbuff[i]) { pci_unmap_single(np->pci_dev, np->rx_dma[i], @@ -900,11 +966,19 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data,skb->len, PCI_DMA_TODEVICE); - np->tx_ring[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); + else { + np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; + np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; + } spin_lock_irq(&np->lock); wmb(); - np->tx_ring[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags ); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + np->tx_ring.orig[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags ); + else + np->tx_ring.ex[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags ); dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission.\n", dev->name, np->next_tx); { @@ -942,7 +1016,10 @@ static void nv_tx_done(struct net_device *dev) while (np->nic_tx != np->next_tx) { i = np->nic_tx % TX_RING; - Flags = le32_to_cpu(np->tx_ring[i].FlagLen); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + Flags = le32_to_cpu(np->tx_ring.orig[i].FlagLen); + else + Flags = le32_to_cpu(np->tx_ring.ex[i].FlagLen); dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n", dev->name, np->nic_tx, Flags); @@ -993,9 +1070,56 @@ static void nv_tx_timeout(struct net_device *dev) struct fe_priv *np = get_nvpriv(dev); u8 __iomem *base = get_hwbase(dev); - dprintk(KERN_DEBUG "%s: Got tx_timeout. irq: %08x\n", dev->name, + printk(KERN_INFO "%s: Got tx_timeout. irq: %08x\n", dev->name, readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK); + { + int i; + + printk(KERN_INFO "%s: Ring at %lx: next %d nic %d\n", + dev->name, (unsigned long)np->ring_addr, + np->next_tx, np->nic_tx); + printk(KERN_INFO "%s: Dumping tx registers\n", dev->name); + for (i=0;i<0x400;i+= 32) { + printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n", + i, + readl(base + i + 0), readl(base + i + 4), + readl(base + i + 8), readl(base + i + 12), + readl(base + i + 16), readl(base + i + 20), + readl(base + i + 24), readl(base + i + 28)); + } + printk(KERN_INFO "%s: Dumping tx ring\n", dev->name); + for (i=0;i<TX_RING;i+= 4) { + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + printk(KERN_INFO "%03x: %08x %08x // %08x %08x // %08x %08x // %08x %08x\n", + i, + le32_to_cpu(np->tx_ring.orig[i].PacketBuffer), + le32_to_cpu(np->tx_ring.orig[i].FlagLen), + le32_to_cpu(np->tx_ring.orig[i+1].PacketBuffer), + le32_to_cpu(np->tx_ring.orig[i+1].FlagLen), + le32_to_cpu(np->tx_ring.orig[i+2].PacketBuffer), + le32_to_cpu(np->tx_ring.orig[i+2].FlagLen), + le32_to_cpu(np->tx_ring.orig[i+3].PacketBuffer), + le32_to_cpu(np->tx_ring.orig[i+3].FlagLen)); + } else { + printk(KERN_INFO "%03x: %08x %08x %08x // %08x %08x %08x // %08x %08x %08x // %08x %08x %08x\n", + i, + le32_to_cpu(np->tx_ring.ex[i].PacketBufferHigh), + le32_to_cpu(np->tx_ring.ex[i].PacketBufferLow), + le32_to_cpu(np->tx_ring.ex[i].FlagLen), + le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferHigh), + le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferLow), + le32_to_cpu(np->tx_ring.ex[i+1].FlagLen), + le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferHigh), + le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferLow), + le32_to_cpu(np->tx_ring.ex[i+2].FlagLen), + le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferHigh), + le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferLow), + le32_to_cpu(np->tx_ring.ex[i+3].FlagLen)); + } + } + } + spin_lock_irq(&np->lock); /* 1) stop tx engine */ @@ -1009,7 +1133,10 @@ static void nv_tx_timeout(struct net_device *dev) printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name); nv_drain_tx(dev); np->next_tx = np->nic_tx = 0; - writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + else + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr); netif_wake_queue(dev); } @@ -1084,8 +1211,13 @@ static void nv_rx_process(struct net_device *dev) break; /* we scanned the whole ring - do not continue */ i = np->cur_rx % RX_RING; - Flags = le32_to_cpu(np->rx_ring[i].FlagLen); - len = nv_descr_getlength(&np->rx_ring[i], np->desc_ver); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + Flags = le32_to_cpu(np->rx_ring.orig[i].FlagLen); + len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver); + } else { + Flags = le32_to_cpu(np->rx_ring.ex[i].FlagLen); + len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver); + } dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n", dev->name, np->cur_rx, Flags); @@ -1207,15 +1339,133 @@ next_pkt: } } +static void set_bufsize(struct net_device *dev) +{ + struct fe_priv *np = netdev_priv(dev); + + if (dev->mtu <= ETH_DATA_LEN) + np->rx_buf_sz = ETH_DATA_LEN + NV_RX_HEADERS; + else + np->rx_buf_sz = dev->mtu + NV_RX_HEADERS; +} + /* * nv_change_mtu: dev->change_mtu function * Called with dev_base_lock held for read. */ static int nv_change_mtu(struct net_device *dev, int new_mtu) { - if (new_mtu > ETH_DATA_LEN) + struct fe_priv *np = get_nvpriv(dev); + int old_mtu; + + if (new_mtu < 64 || new_mtu > np->pkt_limit) return -EINVAL; + + old_mtu = dev->mtu; dev->mtu = new_mtu; + + /* return early if the buffer sizes will not change */ + if (old_mtu <= ETH_DATA_LEN && new_mtu <= ETH_DATA_LEN) + return 0; + if (old_mtu == new_mtu) + return 0; + + /* synchronized against open : rtnl_lock() held by caller */ + if (netif_running(dev)) { + u8 *base = get_hwbase(dev); + /* + * It seems that the nic preloads valid ring entries into an + * internal buffer. The procedure for flushing everything is + * guessed, there is probably a simpler approach. + * Changing the MTU is a rare event, it shouldn't matter. + */ + disable_irq(dev->irq); + spin_lock_bh(&dev->xmit_lock); + spin_lock(&np->lock); + /* stop engines */ + nv_stop_rx(dev); + nv_stop_tx(dev); + nv_txrx_reset(dev); + /* drain rx queue */ + nv_drain_rx(dev); + nv_drain_tx(dev); + /* reinit driver view of the rx queue */ + nv_init_rx(dev); + nv_init_tx(dev); + /* alloc new rx buffers */ + set_bufsize(dev); + if (nv_alloc_rx(dev)) { + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + } + /* reinit nic view of the rx queue */ + writel(np->rx_buf_sz, base + NvRegOffloadConfig); + writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + else + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr); + writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT), + base + NvRegRingSizes); + pci_push(base); + writel(NVREG_TXRXCTL_KICK|np->desc_ver, get_hwbase(dev) + NvRegTxRxControl); + pci_push(base); + + /* restart rx engine */ + nv_start_rx(dev); + nv_start_tx(dev); + spin_unlock(&np->lock); + spin_unlock_bh(&dev->xmit_lock); + enable_irq(dev->irq); + } + return 0; +} + +static void nv_copy_mac_to_hw(struct net_device *dev) +{ + u8 *base = get_hwbase(dev); + u32 mac[2]; + + mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) + + (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24); + mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8); + + writel(mac[0], base + NvRegMacAddrA); + writel(mac[1], base + NvRegMacAddrB); +} + +/* + * nv_set_mac_address: dev->set_mac_address function + * Called with rtnl_lock() held. + */ +static int nv_set_mac_address(struct net_device *dev, void *addr) +{ + struct fe_priv *np = get_nvpriv(dev); + struct sockaddr *macaddr = (struct sockaddr*)addr; + + if(!is_valid_ether_addr(macaddr->sa_data)) + return -EADDRNOTAVAIL; + + /* synchronized against open : rtnl_lock() held by caller */ + memcpy(dev->dev_addr, macaddr->sa_data, ETH_ALEN); + + if (netif_running(dev)) { + spin_lock_bh(&dev->xmit_lock); + spin_lock_irq(&np->lock); + + /* stop rx engine */ + nv_stop_rx(dev); + + /* set mac address */ + nv_copy_mac_to_hw(dev); + + /* restart rx engine */ + nv_start_rx(dev); + spin_unlock_irq(&np->lock); + spin_unlock_bh(&dev->xmit_lock); + } else { + nv_copy_mac_to_hw(dev); + } return 0; } @@ -1470,7 +1720,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs) if (!(events & np->irqmask)) break; - if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX2|NVREG_IRQ_TX_ERR)) { + if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX_OK|NVREG_IRQ_TX_ERROR|NVREG_IRQ_TX_ERR)) { spin_lock(&np->lock); nv_tx_done(dev); spin_unlock(&np->lock); @@ -1761,6 +2011,50 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) return 0; } +#define FORCEDETH_REGS_VER 1 +#define FORCEDETH_REGS_SIZE 0x400 /* 256 32-bit registers */ + +static int nv_get_regs_len(struct net_device *dev) +{ + return FORCEDETH_REGS_SIZE; +} + +static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 __iomem *base = get_hwbase(dev); + u32 *rbuf = buf; + int i; + + regs->version = FORCEDETH_REGS_VER; + spin_lock_irq(&np->lock); + for (i=0;i<FORCEDETH_REGS_SIZE/sizeof(u32);i++) + rbuf[i] = readl(base + i*sizeof(u32)); + spin_unlock_irq(&np->lock); +} + +static int nv_nway_reset(struct net_device *dev) +{ + struct fe_priv *np = get_nvpriv(dev); + int ret; + + spin_lock_irq(&np->lock); + if (np->autoneg) { + int bmcr; + + bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); + bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); + mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); + + ret = 0; + } else { + ret = -EINVAL; + } + spin_unlock_irq(&np->lock); + + return ret; +} + static struct ethtool_ops ops = { .get_drvinfo = nv_get_drvinfo, .get_link = ethtool_op_get_link, @@ -1768,6 +2062,9 @@ static struct ethtool_ops ops = { .set_wol = nv_set_wol, .get_settings = nv_get_settings, .set_settings = nv_set_settings, + .get_regs_len = nv_get_regs_len, + .get_regs = nv_get_regs, + .nway_reset = nv_nway_reset, }; static int nv_open(struct net_device *dev) @@ -1792,6 +2089,7 @@ static int nv_open(struct net_device *dev) writel(0, base + NvRegAdapterControl); /* 2) initialize descriptor rings */ + set_bufsize(dev); oom = nv_init_ring(dev); writel(0, base + NvRegLinkSpeed); @@ -1802,20 +2100,14 @@ static int nv_open(struct net_device *dev) np->in_shutdown = 0; /* 3) set mac address */ - { - u32 mac[2]; - - mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) + - (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24); - mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8); - - writel(mac[0], base + NvRegMacAddrA); - writel(mac[1], base + NvRegMacAddrB); - } + nv_copy_mac_to_hw(dev); /* 4) give hw rings */ writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr); - writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + else + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr); writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT), base + NvRegRingSizes); @@ -1837,7 +2129,7 @@ static int nv_open(struct net_device *dev) writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1); writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus); writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags); - writel(NVREG_OFFLOAD_NORMAL, base + NvRegOffloadConfig); + writel(np->rx_buf_sz, base + NvRegOffloadConfig); writel(readl(base + NvRegReceiverStatus), base + NvRegReceiverStatus); get_random_bytes(&i, sizeof(i)); @@ -1888,6 +2180,9 @@ static int nv_open(struct net_device *dev) writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); dprintk(KERN_INFO "startup: got 0x%08x.\n", miistat); } + /* set linkspeed to invalid value, thus force nv_update_linkspeed + * to init hw */ + np->linkspeed = 0; ret = nv_update_linkspeed(dev); nv_start_rx(dev); nv_start_tx(dev); @@ -1942,6 +2237,12 @@ static int nv_close(struct net_device *dev) if (np->wolenabled) nv_start_rx(dev); + /* special op: write back the misordered MAC address - otherwise + * the next nv_probe would see a wrong address. + */ + writel(np->orig_mac[0], base + NvRegMacAddrA); + writel(np->orig_mac[1], base + NvRegMacAddrB); + /* FIXME: power down nic */ return 0; @@ -2006,32 +2307,55 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i } /* handle different descriptor versions */ - if (pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_1 || - pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_2 || - pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_3 || - pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_12 || - pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_13) - np->desc_ver = DESC_VER_1; - else + if (id->driver_data & DEV_HAS_HIGH_DMA) { + /* packet format 3: supports 40-bit addressing */ + np->desc_ver = DESC_VER_3; + if (pci_set_dma_mask(pci_dev, 0x0000007fffffffffULL)) { + printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n", + pci_name(pci_dev)); + } + } else if (id->driver_data & DEV_HAS_LARGEDESC) { + /* packet format 2: supports jumbo frames */ np->desc_ver = DESC_VER_2; + } else { + /* original packet format */ + np->desc_ver = DESC_VER_1; + } + + np->pkt_limit = NV_PKTLIMIT_1; + if (id->driver_data & DEV_HAS_LARGEDESC) + np->pkt_limit = NV_PKTLIMIT_2; err = -ENOMEM; np->base = ioremap(addr, NV_PCI_REGSZ); if (!np->base) goto out_relreg; dev->base_addr = (unsigned long)np->base; + dev->irq = pci_dev->irq; - np->rx_ring = pci_alloc_consistent(pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), - &np->ring_addr); - if (!np->rx_ring) - goto out_unmap; - np->tx_ring = &np->rx_ring[RX_RING]; + + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + np->rx_ring.orig = pci_alloc_consistent(pci_dev, + sizeof(struct ring_desc) * (RX_RING + TX_RING), + &np->ring_addr); + if (!np->rx_ring.orig) + goto out_unmap; + np->tx_ring.orig = &np->rx_ring.orig[RX_RING]; + } else { + np->rx_ring.ex = pci_alloc_consistent(pci_dev, + sizeof(struct ring_desc_ex) * (RX_RING + TX_RING), + &np->ring_addr); + if (!np->rx_ring.ex) + goto out_unmap; + np->tx_ring.ex = &np->rx_ring.ex[RX_RING]; + } dev->open = nv_open; dev->stop = nv_close; dev->hard_start_xmit = nv_start_xmit; dev->get_stats = nv_get_stats; dev->change_mtu = nv_change_mtu; + dev->set_mac_address = nv_set_mac_address; dev->set_multicast_list = nv_set_multicast; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = nv_poll_controller; @@ -2080,17 +2404,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i if (np->desc_ver == DESC_VER_1) { np->tx_flags = NV_TX_LASTPACKET|NV_TX_VALID; - if (id->driver_data & DEV_NEED_LASTPACKET1) - np->tx_flags |= NV_TX_LASTPACKET1; } else { np->tx_flags = NV_TX2_LASTPACKET|NV_TX2_VALID; - if (id->driver_data & DEV_NEED_LASTPACKET1) - np->tx_flags |= NV_TX2_LASTPACKET1; } - if (id->driver_data & DEV_IRQMASK_1) - np->irqmask = NVREG_IRQMASK_WANTED_1; - if (id->driver_data & DEV_IRQMASK_2) - np->irqmask = NVREG_IRQMASK_WANTED_2; + np->irqmask = NVREG_IRQMASK_WANTED; if (id->driver_data & DEV_NEED_TIMERIRQ) np->irqmask |= NVREG_IRQ_TIMER; if (id->driver_data & DEV_NEED_LINKTIMER) { @@ -2155,8 +2472,12 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i return 0; out_freering: - pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), - np->rx_ring, np->ring_addr); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), + np->rx_ring.orig, np->ring_addr); + else + pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (RX_RING + TX_RING), + np->rx_ring.ex, np->ring_addr); pci_set_drvdata(pci_dev, NULL); out_unmap: iounmap(get_hwbase(dev)); @@ -2174,18 +2495,14 @@ static void __devexit nv_remove(struct pci_dev *pci_dev) { struct net_device *dev = pci_get_drvdata(pci_dev); struct fe_priv *np = get_nvpriv(dev); - u8 __iomem *base = get_hwbase(dev); unregister_netdev(dev); - /* special op: write back the misordered MAC address - otherwise - * the next nv_probe would see a wrong address. - */ - writel(np->orig_mac[0], base + NvRegMacAddrA); - writel(np->orig_mac[1], base + NvRegMacAddrB); - /* free all structures */ - pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), np->rx_ring, np->ring_addr); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), np->rx_ring.orig, np->ring_addr); + else + pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (RX_RING + TX_RING), np->rx_ring.ex, np->ring_addr); iounmap(get_hwbase(dev)); pci_release_regions(pci_dev); pci_disable_device(pci_dev); @@ -2195,109 +2512,64 @@ static void __devexit nv_remove(struct pci_dev *pci_dev) static struct pci_device_id pci_tbl[] = { { /* nForce Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_IRQMASK_1|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_1), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce2 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_2), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce3 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_3, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_3), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce3 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_4), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC, }, { /* nForce3 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_5, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_5), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC, }, { /* nForce3 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_6, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_6), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC, }, { /* nForce3 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_7, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_7), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC, }, { /* CK804 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_8, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, }, { /* CK804 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_9, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, }, { /* MCP04 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_10, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, }, { /* MCP04 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_11, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, }, { /* MCP51 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_12, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA, }, { /* MCP51 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_13, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA, }, { /* MCP55 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_14, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, }, { /* MCP55 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_15, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA, }, {0,}, }; diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index f9e3be96963..0b230222bfe 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -308,12 +308,6 @@ static int sp_set_mac_address(struct net_device *dev, void *addr) { struct sockaddr_ax25 *sa = addr; - if (sa->sax25_family != AF_AX25) - return -EINVAL; - - if (!sa->sax25_ndigis) - return -EINVAL; - spin_lock_irq(&dev->xmit_lock); memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN); spin_unlock_irq(&dev->xmit_lock); @@ -668,6 +662,9 @@ static int sixpack_open(struct tty_struct *tty) netif_start_queue(dev); init_timer(&sp->tx_t); + sp->tx_t.function = sp_xmit_on_air; + sp->tx_t.data = (unsigned long) sp; + init_timer(&sp->resync_t); spin_unlock_bh(&sp->lock); diff --git a/drivers/net/hamradio/Kconfig b/drivers/net/hamradio/Kconfig index 0cd54306e63..de087cd609d 100644 --- a/drivers/net/hamradio/Kconfig +++ b/drivers/net/hamradio/Kconfig @@ -1,6 +1,6 @@ config MKISS tristate "Serial port KISS driver" - depends on AX25 && BROKEN_ON_SMP + depends on AX25 ---help--- KISS is a protocol used for the exchange of data between a computer and a Terminal Node Controller (a small embedded system commonly diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index a7f15d9f13e..5298096afbd 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -54,6 +54,7 @@ #include <linux/kmod.h> #include <linux/hdlcdrv.h> #include <linux/baycom.h> +#include <linux/jiffies.h> #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) /* prototypes for ax25_encapsulate and ax25_rebuild_header */ #include <net/ax25.h> @@ -287,7 +288,7 @@ static inline void baycom_int_freq(struct baycom_state *bc) * measure the interrupt frequency */ bc->debug_vals.cur_intcnt++; - if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) { + if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) { bc->debug_vals.last_jiffies = cur_jiffies; bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; bc->debug_vals.cur_intcnt = 0; diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c index 612ad452bee..3b1bef1ee21 100644 --- a/drivers/net/hamradio/baycom_par.c +++ b/drivers/net/hamradio/baycom_par.c @@ -84,6 +84,7 @@ #include <linux/baycom.h> #include <linux/parport.h> #include <linux/bitops.h> +#include <linux/jiffies.h> #include <asm/bug.h> #include <asm/system.h> @@ -165,7 +166,7 @@ static void __inline__ baycom_int_freq(struct baycom_state *bc) * measure the interrupt frequency */ bc->debug_vals.cur_intcnt++; - if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) { + if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) { bc->debug_vals.last_jiffies = cur_jiffies; bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; bc->debug_vals.cur_intcnt = 0; diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c index 25f270b0537..232793d2ce6 100644 --- a/drivers/net/hamradio/baycom_ser_fdx.c +++ b/drivers/net/hamradio/baycom_ser_fdx.c @@ -79,6 +79,7 @@ #include <asm/io.h> #include <linux/hdlcdrv.h> #include <linux/baycom.h> +#include <linux/jiffies.h> /* --------------------------------------------------------------------- */ @@ -159,7 +160,7 @@ static inline void baycom_int_freq(struct baycom_state *bc) * measure the interrupt frequency */ bc->debug_vals.cur_intcnt++; - if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) { + if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) { bc->debug_vals.last_jiffies = cur_jiffies; bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; bc->debug_vals.cur_intcnt = 0; diff --git a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c index eead85d0096..be596a3eb3f 100644 --- a/drivers/net/hamradio/baycom_ser_hdx.c +++ b/drivers/net/hamradio/baycom_ser_hdx.c @@ -69,6 +69,7 @@ #include <asm/io.h> #include <linux/hdlcdrv.h> #include <linux/baycom.h> +#include <linux/jiffies.h> /* --------------------------------------------------------------------- */ @@ -150,7 +151,7 @@ static inline void baycom_int_freq(struct baycom_state *bc) * measure the interrupt frequency */ bc->debug_vals.cur_intcnt++; - if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) { + if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) { bc->debug_vals.last_jiffies = cur_jiffies; bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; bc->debug_vals.cur_intcnt = 0; diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 3035422f5ad..63b1a2b86ac 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -1,30 +1,19 @@ /* - * MKISS Driver + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. * - * This module: - * This module 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 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. * - * This module implements the AX.25 protocol for kernel-based - * devices like TTYs. It interfaces between a raw TTY, and the - * kernel's AX.25 protocol layers, just like slip.c. - * AX.25 needs to be separated from slip.c while slip.c is no - * longer a static kernel device since it is a module. - * This method clears the way to implement other kiss protocols - * like mkiss smack g8bpq ..... so far only mkiss is implemented. + * 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., + * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. * - * Hans Alblas <hans@esrac.ele.tue.nl> - * - * History - * Jonathan (G4KLX) Fixed to match Linux networking changes - 2.1.15. - * Matthias (DG2FEF) Added support for FlexNet CRC (on special request) - * Fixed bug in ax25_close(): dev_lock_wait() was - * called twice, causing a deadlock. - * Jeroen (PE1RXQ) Removed old MKISS_MAGIC stuff and calls to - * MOD_*_USE_COUNT - * Remove cli() and fix rtnl lock usage. + * Copyright (C) Hans Alblas PE1AYX <hans@esrac.ele.tue.nl> + * Copyright (C) 2004, 05 Ralf Baechle DL5RB <ralf@linux-mips.org> */ #include <linux/config.h> @@ -46,177 +35,300 @@ #include <linux/etherdevice.h> #include <linux/skbuff.h> #include <linux/if_arp.h> +#include <linux/jiffies.h> #include <net/ax25.h> -#include "mkiss.h" - #ifdef CONFIG_INET #include <linux/ip.h> #include <linux/tcp.h> #endif -static char banner[] __initdata = KERN_INFO "mkiss: AX.25 Multikiss, Hans Albas PE1AYX\n"; - -typedef struct ax25_ctrl { - struct ax_disp ctrl; /* */ - struct net_device dev; /* the device */ -} ax25_ctrl_t; - -static ax25_ctrl_t **ax25_ctrls; - -int ax25_maxdev = AX25_MAXDEV; /* Can be overridden with insmod! */ - -static struct tty_ldisc ax_ldisc; - -static int ax25_init(struct net_device *); -static int kiss_esc(unsigned char *, unsigned char *, int); -static int kiss_esc_crc(unsigned char *, unsigned char *, unsigned short, int); -static void kiss_unesc(struct ax_disp *, unsigned char); +#define AX_MTU 236 + +/* SLIP/KISS protocol characters. */ +#define END 0300 /* indicates end of frame */ +#define ESC 0333 /* indicates byte stuffing */ +#define ESC_END 0334 /* ESC ESC_END means END 'data' */ +#define ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */ + +struct mkiss { + struct tty_struct *tty; /* ptr to TTY structure */ + struct net_device *dev; /* easy for intr handling */ + + /* These are pointers to the malloc()ed frame buffers. */ + spinlock_t buflock;/* lock for rbuf and xbuf */ + unsigned char *rbuff; /* receiver buffer */ + int rcount; /* received chars counter */ + unsigned char *xbuff; /* transmitter buffer */ + unsigned char *xhead; /* pointer to next byte to XMIT */ + int xleft; /* bytes left in XMIT queue */ + + struct net_device_stats stats; + + /* Detailed SLIP statistics. */ + int mtu; /* Our mtu (to spot changes!) */ + int buffsize; /* Max buffers sizes */ + + unsigned long flags; /* Flag values/ mode etc */ + /* long req'd: used by set_bit --RR */ +#define AXF_INUSE 0 /* Channel in use */ +#define AXF_ESCAPE 1 /* ESC received */ +#define AXF_ERROR 2 /* Parity, etc. error */ +#define AXF_KEEPTEST 3 /* Keepalive test flag */ +#define AXF_OUTWAIT 4 /* is outpacket was flag */ + + int mode; + int crcmode; /* MW: for FlexNet, SMACK etc. */ +#define CRC_MODE_NONE 0 +#define CRC_MODE_FLEX 1 +#define CRC_MODE_SMACK 2 + + atomic_t refcnt; + struct semaphore dead_sem; +}; /*---------------------------------------------------------------------------*/ -static const unsigned short Crc_flex_table[] = { - 0x0f87, 0x1e0e, 0x2c95, 0x3d1c, 0x49a3, 0x582a, 0x6ab1, 0x7b38, - 0x83cf, 0x9246, 0xa0dd, 0xb154, 0xc5eb, 0xd462, 0xe6f9, 0xf770, - 0x1f06, 0x0e8f, 0x3c14, 0x2d9d, 0x5922, 0x48ab, 0x7a30, 0x6bb9, - 0x934e, 0x82c7, 0xb05c, 0xa1d5, 0xd56a, 0xc4e3, 0xf678, 0xe7f1, - 0x2e85, 0x3f0c, 0x0d97, 0x1c1e, 0x68a1, 0x7928, 0x4bb3, 0x5a3a, - 0xa2cd, 0xb344, 0x81df, 0x9056, 0xe4e9, 0xf560, 0xc7fb, 0xd672, - 0x3e04, 0x2f8d, 0x1d16, 0x0c9f, 0x7820, 0x69a9, 0x5b32, 0x4abb, - 0xb24c, 0xa3c5, 0x915e, 0x80d7, 0xf468, 0xe5e1, 0xd77a, 0xc6f3, - 0x4d83, 0x5c0a, 0x6e91, 0x7f18, 0x0ba7, 0x1a2e, 0x28b5, 0x393c, - 0xc1cb, 0xd042, 0xe2d9, 0xf350, 0x87ef, 0x9666, 0xa4fd, 0xb574, - 0x5d02, 0x4c8b, 0x7e10, 0x6f99, 0x1b26, 0x0aaf, 0x3834, 0x29bd, - 0xd14a, 0xc0c3, 0xf258, 0xe3d1, 0x976e, 0x86e7, 0xb47c, 0xa5f5, - 0x6c81, 0x7d08, 0x4f93, 0x5e1a, 0x2aa5, 0x3b2c, 0x09b7, 0x183e, - 0xe0c9, 0xf140, 0xc3db, 0xd252, 0xa6ed, 0xb764, 0x85ff, 0x9476, - 0x7c00, 0x6d89, 0x5f12, 0x4e9b, 0x3a24, 0x2bad, 0x1936, 0x08bf, - 0xf048, 0xe1c1, 0xd35a, 0xc2d3, 0xb66c, 0xa7e5, 0x957e, 0x84f7, - 0x8b8f, 0x9a06, 0xa89d, 0xb914, 0xcdab, 0xdc22, 0xeeb9, 0xff30, - 0x07c7, 0x164e, 0x24d5, 0x355c, 0x41e3, 0x506a, 0x62f1, 0x7378, - 0x9b0e, 0x8a87, 0xb81c, 0xa995, 0xdd2a, 0xcca3, 0xfe38, 0xefb1, - 0x1746, 0x06cf, 0x3454, 0x25dd, 0x5162, 0x40eb, 0x7270, 0x63f9, - 0xaa8d, 0xbb04, 0x899f, 0x9816, 0xeca9, 0xfd20, 0xcfbb, 0xde32, - 0x26c5, 0x374c, 0x05d7, 0x145e, 0x60e1, 0x7168, 0x43f3, 0x527a, - 0xba0c, 0xab85, 0x991e, 0x8897, 0xfc28, 0xeda1, 0xdf3a, 0xceb3, - 0x3644, 0x27cd, 0x1556, 0x04df, 0x7060, 0x61e9, 0x5372, 0x42fb, - 0xc98b, 0xd802, 0xea99, 0xfb10, 0x8faf, 0x9e26, 0xacbd, 0xbd34, - 0x45c3, 0x544a, 0x66d1, 0x7758, 0x03e7, 0x126e, 0x20f5, 0x317c, - 0xd90a, 0xc883, 0xfa18, 0xeb91, 0x9f2e, 0x8ea7, 0xbc3c, 0xadb5, - 0x5542, 0x44cb, 0x7650, 0x67d9, 0x1366, 0x02ef, 0x3074, 0x21fd, - 0xe889, 0xf900, 0xcb9b, 0xda12, 0xaead, 0xbf24, 0x8dbf, 0x9c36, - 0x64c1, 0x7548, 0x47d3, 0x565a, 0x22e5, 0x336c, 0x01f7, 0x107e, - 0xf808, 0xe981, 0xdb1a, 0xca93, 0xbe2c, 0xafa5, 0x9d3e, 0x8cb7, - 0x7440, 0x65c9, 0x5752, 0x46db, 0x3264, 0x23ed, 0x1176, 0x00ff +static const unsigned short crc_flex_table[] = { + 0x0f87, 0x1e0e, 0x2c95, 0x3d1c, 0x49a3, 0x582a, 0x6ab1, 0x7b38, + 0x83cf, 0x9246, 0xa0dd, 0xb154, 0xc5eb, 0xd462, 0xe6f9, 0xf770, + 0x1f06, 0x0e8f, 0x3c14, 0x2d9d, 0x5922, 0x48ab, 0x7a30, 0x6bb9, + 0x934e, 0x82c7, 0xb05c, 0xa1d5, 0xd56a, 0xc4e3, 0xf678, 0xe7f1, + 0x2e85, 0x3f0c, 0x0d97, 0x1c1e, 0x68a1, 0x7928, 0x4bb3, 0x5a3a, + 0xa2cd, 0xb344, 0x81df, 0x9056, 0xe4e9, 0xf560, 0xc7fb, 0xd672, + 0x3e04, 0x2f8d, 0x1d16, 0x0c9f, 0x7820, 0x69a9, 0x5b32, 0x4abb, + 0xb24c, 0xa3c5, 0x915e, 0x80d7, 0xf468, 0xe5e1, 0xd77a, 0xc6f3, + 0x4d83, 0x5c0a, 0x6e91, 0x7f18, 0x0ba7, 0x1a2e, 0x28b5, 0x393c, + 0xc1cb, 0xd042, 0xe2d9, 0xf350, 0x87ef, 0x9666, 0xa4fd, 0xb574, + 0x5d02, 0x4c8b, 0x7e10, 0x6f99, 0x1b26, 0x0aaf, 0x3834, 0x29bd, + 0xd14a, 0xc0c3, 0xf258, 0xe3d1, 0x976e, 0x86e7, 0xb47c, 0xa5f5, + 0x6c81, 0x7d08, 0x4f93, 0x5e1a, 0x2aa5, 0x3b2c, 0x09b7, 0x183e, + 0xe0c9, 0xf140, 0xc3db, 0xd252, 0xa6ed, 0xb764, 0x85ff, 0x9476, + 0x7c00, 0x6d89, 0x5f12, 0x4e9b, 0x3a24, 0x2bad, 0x1936, 0x08bf, + 0xf048, 0xe1c1, 0xd35a, 0xc2d3, 0xb66c, 0xa7e5, 0x957e, 0x84f7, + 0x8b8f, 0x9a06, 0xa89d, 0xb914, 0xcdab, 0xdc22, 0xeeb9, 0xff30, + 0x07c7, 0x164e, 0x24d5, 0x355c, 0x41e3, 0x506a, 0x62f1, 0x7378, + 0x9b0e, 0x8a87, 0xb81c, 0xa995, 0xdd2a, 0xcca3, 0xfe38, 0xefb1, + 0x1746, 0x06cf, 0x3454, 0x25dd, 0x5162, 0x40eb, 0x7270, 0x63f9, + 0xaa8d, 0xbb04, 0x899f, 0x9816, 0xeca9, 0xfd20, 0xcfbb, 0xde32, + 0x26c5, 0x374c, 0x05d7, 0x145e, 0x60e1, 0x7168, 0x43f3, 0x527a, + 0xba0c, 0xab85, 0x991e, 0x8897, 0xfc28, 0xeda1, 0xdf3a, 0xceb3, + 0x3644, 0x27cd, 0x1556, 0x04df, 0x7060, 0x61e9, 0x5372, 0x42fb, + 0xc98b, 0xd802, 0xea99, 0xfb10, 0x8faf, 0x9e26, 0xacbd, 0xbd34, + 0x45c3, 0x544a, 0x66d1, 0x7758, 0x03e7, 0x126e, 0x20f5, 0x317c, + 0xd90a, 0xc883, 0xfa18, 0xeb91, 0x9f2e, 0x8ea7, 0xbc3c, 0xadb5, + 0x5542, 0x44cb, 0x7650, 0x67d9, 0x1366, 0x02ef, 0x3074, 0x21fd, + 0xe889, 0xf900, 0xcb9b, 0xda12, 0xaead, 0xbf24, 0x8dbf, 0x9c36, + 0x64c1, 0x7548, 0x47d3, 0x565a, 0x22e5, 0x336c, 0x01f7, 0x107e, + 0xf808, 0xe981, 0xdb1a, 0xca93, 0xbe2c, 0xafa5, 0x9d3e, 0x8cb7, + 0x7440, 0x65c9, 0x5752, 0x46db, 0x3264, 0x23ed, 0x1176, 0x00ff }; -/*---------------------------------------------------------------------------*/ - static unsigned short calc_crc_flex(unsigned char *cp, int size) { - unsigned short crc = 0xffff; - - while (size--) - crc = (crc << 8) ^ Crc_flex_table[((crc >> 8) ^ *cp++) & 0xff]; + unsigned short crc = 0xffff; - return crc; -} + while (size--) + crc = (crc << 8) ^ crc_flex_table[((crc >> 8) ^ *cp++) & 0xff]; -/*---------------------------------------------------------------------------*/ + return crc; +} static int check_crc_flex(unsigned char *cp, int size) { - unsigned short crc = 0xffff; + unsigned short crc = 0xffff; - if (size < 3) - return -1; + if (size < 3) + return -1; - while (size--) - crc = (crc << 8) ^ Crc_flex_table[((crc >> 8) ^ *cp++) & 0xff]; + while (size--) + crc = (crc << 8) ^ crc_flex_table[((crc >> 8) ^ *cp++) & 0xff]; - if ((crc & 0xffff) != 0x7070) - return -1; + if ((crc & 0xffff) != 0x7070) + return -1; - return 0; + return 0; } -/*---------------------------------------------------------------------------*/ +/* + * Standard encapsulation + */ -/* Find a free channel, and link in this `tty' line. */ -static inline struct ax_disp *ax_alloc(void) +static int kiss_esc(unsigned char *s, unsigned char *d, int len) { - ax25_ctrl_t *axp=NULL; - int i; + unsigned char *ptr = d; + unsigned char c; - for (i = 0; i < ax25_maxdev; i++) { - axp = ax25_ctrls[i]; + /* + * Send an initial END character to flush out any data that may have + * accumulated in the receiver due to line noise. + */ - /* Not allocated ? */ - if (axp == NULL) - break; + *ptr++ = END; - /* Not in use ? */ - if (!test_and_set_bit(AXF_INUSE, &axp->ctrl.flags)) + while (len-- > 0) { + switch (c = *s++) { + case END: + *ptr++ = ESC; + *ptr++ = ESC_END; break; + case ESC: + *ptr++ = ESC; + *ptr++ = ESC_ESC; + break; + default: + *ptr++ = c; + break; + } } - /* Sorry, too many, all slots in use */ - if (i >= ax25_maxdev) - return NULL; + *ptr++ = END; + + return ptr - d; +} + +/* + * MW: + * OK its ugly, but tell me a better solution without copying the + * packet to a temporary buffer :-) + */ +static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc, + int len) +{ + unsigned char *ptr = d; + unsigned char c=0; + + *ptr++ = END; + while (len > 0) { + if (len > 2) + c = *s++; + else if (len > 1) + c = crc >> 8; + else if (len > 0) + c = crc & 0xff; + + len--; - /* If no channels are available, allocate one */ - if (axp == NULL && (ax25_ctrls[i] = kmalloc(sizeof(ax25_ctrl_t), GFP_KERNEL)) != NULL) { - axp = ax25_ctrls[i]; + switch (c) { + case END: + *ptr++ = ESC; + *ptr++ = ESC_END; + break; + case ESC: + *ptr++ = ESC; + *ptr++ = ESC_ESC; + break; + default: + *ptr++ = c; + break; + } } - memset(axp, 0, sizeof(ax25_ctrl_t)); - - /* Initialize channel control data */ - set_bit(AXF_INUSE, &axp->ctrl.flags); - sprintf(axp->dev.name, "ax%d", i++); - axp->ctrl.tty = NULL; - axp->dev.base_addr = i; - axp->dev.priv = (void *)&axp->ctrl; - axp->dev.next = NULL; - axp->dev.init = ax25_init; - - if (axp != NULL) { - /* - * register device so that it can be ifconfig'ed - * ax25_init() will be called as a side-effect - * SIDE-EFFECT WARNING: ax25_init() CLEARS axp->ctrl ! - */ - if (register_netdev(&axp->dev) == 0) { - /* (Re-)Set the INUSE bit. Very Important! */ - set_bit(AXF_INUSE, &axp->ctrl.flags); - axp->ctrl.dev = &axp->dev; - axp->dev.priv = (void *) &axp->ctrl; - - return &axp->ctrl; - } else { - clear_bit(AXF_INUSE,&axp->ctrl.flags); - printk(KERN_ERR "mkiss: ax_alloc() - register_netdev() failure.\n"); + *ptr++ = END; + + return ptr - d; +} + +/* Send one completely decapsulated AX.25 packet to the AX.25 layer. */ +static void ax_bump(struct mkiss *ax) +{ + struct sk_buff *skb; + int count; + + spin_lock_bh(&ax->buflock); + if (ax->rbuff[0] > 0x0f) { + if (ax->rbuff[0] & 0x20) { + ax->crcmode = CRC_MODE_FLEX; + if (check_crc_flex(ax->rbuff, ax->rcount) < 0) { + ax->stats.rx_errors++; + return; + } + ax->rcount -= 2; + /* dl9sau bugfix: the trailling two bytes flexnet crc + * will not be passed to the kernel. thus we have + * to correct the kissparm signature, because it + * indicates a crc but there's none + */ + *ax->rbuff &= ~0x20; } + } + spin_unlock_bh(&ax->buflock); + + count = ax->rcount; + + if ((skb = dev_alloc_skb(count)) == NULL) { + printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n", + ax->dev->name); + ax->stats.rx_dropped++; + return; } - return NULL; + spin_lock_bh(&ax->buflock); + memcpy(skb_put(skb,count), ax->rbuff, count); + spin_unlock_bh(&ax->buflock); + skb->protocol = ax25_type_trans(skb, ax->dev); + netif_rx(skb); + ax->dev->last_rx = jiffies; + ax->stats.rx_packets++; + ax->stats.rx_bytes += count; } -/* Free an AX25 channel. */ -static inline void ax_free(struct ax_disp *ax) +static void kiss_unesc(struct mkiss *ax, unsigned char s) { - /* Free all AX25 frame buffers. */ - if (ax->rbuff) - kfree(ax->rbuff); - ax->rbuff = NULL; - if (ax->xbuff) - kfree(ax->xbuff); - ax->xbuff = NULL; - if (!test_and_clear_bit(AXF_INUSE, &ax->flags)) - printk(KERN_ERR "mkiss: %s: ax_free for already free unit.\n", ax->dev->name); + switch (s) { + case END: + /* drop keeptest bit = VSV */ + if (test_bit(AXF_KEEPTEST, &ax->flags)) + clear_bit(AXF_KEEPTEST, &ax->flags); + + if (!test_and_clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2)) + ax_bump(ax); + + clear_bit(AXF_ESCAPE, &ax->flags); + ax->rcount = 0; + return; + + case ESC: + set_bit(AXF_ESCAPE, &ax->flags); + return; + case ESC_ESC: + if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) + s = ESC; + break; + case ESC_END: + if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) + s = END; + break; + } + + spin_lock_bh(&ax->buflock); + if (!test_bit(AXF_ERROR, &ax->flags)) { + if (ax->rcount < ax->buffsize) { + ax->rbuff[ax->rcount++] = s; + spin_unlock_bh(&ax->buflock); + return; + } + + ax->stats.rx_over_errors++; + set_bit(AXF_ERROR, &ax->flags); + } + spin_unlock_bh(&ax->buflock); +} + +static int ax_set_mac_address(struct net_device *dev, void *addr) +{ + struct sockaddr_ax25 *sa = addr; + + spin_lock_irq(&dev->xmit_lock); + memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN); + spin_unlock_irq(&dev->xmit_lock); + + return 0; } -static void ax_changedmtu(struct ax_disp *ax) +/*---------------------------------------------------------------------------*/ + +static void ax_changedmtu(struct mkiss *ax) { struct net_device *dev = ax->dev; unsigned char *xbuff, *rbuff, *oxbuff, *orbuff; @@ -236,7 +348,8 @@ static void ax_changedmtu(struct ax_disp *ax) rbuff = kmalloc(len + 4, GFP_ATOMIC); if (xbuff == NULL || rbuff == NULL) { - printk(KERN_ERR "mkiss: %s: unable to grow ax25 buffers, MTU change cancelled.\n", + printk(KERN_ERR "mkiss: %s: unable to grow ax25 buffers, " + "MTU change cancelled.\n", ax->dev->name); dev->mtu = ax->mtu; if (xbuff != NULL) @@ -258,7 +371,7 @@ static void ax_changedmtu(struct ax_disp *ax) memcpy(ax->xbuff, ax->xhead, ax->xleft); } else { ax->xleft = 0; - ax->tx_dropped++; + ax->stats.tx_dropped++; } } @@ -269,7 +382,7 @@ static void ax_changedmtu(struct ax_disp *ax) memcpy(ax->rbuff, orbuff, ax->rcount); } else { ax->rcount = 0; - ax->rx_over_errors++; + ax->stats.rx_over_errors++; set_bit(AXF_ERROR, &ax->flags); } } @@ -279,72 +392,14 @@ static void ax_changedmtu(struct ax_disp *ax) spin_unlock_bh(&ax->buflock); - if (oxbuff != NULL) - kfree(oxbuff); - if (orbuff != NULL) - kfree(orbuff); -} - - -/* Set the "sending" flag. This must be atomic. */ -static inline void ax_lock(struct ax_disp *ax) -{ - netif_stop_queue(ax->dev); -} - - -/* Clear the "sending" flag. This must be atomic. */ -static inline void ax_unlock(struct ax_disp *ax) -{ - netif_start_queue(ax->dev); -} - -/* Send one completely decapsulated AX.25 packet to the AX.25 layer. */ -static void ax_bump(struct ax_disp *ax) -{ - struct sk_buff *skb; - int count; - - spin_lock_bh(&ax->buflock); - if (ax->rbuff[0] > 0x0f) { - if (ax->rbuff[0] & 0x20) { - ax->crcmode = CRC_MODE_FLEX; - if (check_crc_flex(ax->rbuff, ax->rcount) < 0) { - ax->rx_errors++; - return; - } - ax->rcount -= 2; - /* dl9sau bugfix: the trailling two bytes flexnet crc - * will not be passed to the kernel. thus we have - * to correct the kissparm signature, because it - * indicates a crc but there's none - */ - *ax->rbuff &= ~0x20; - } - } - spin_unlock_bh(&ax->buflock); - - count = ax->rcount; - - if ((skb = dev_alloc_skb(count)) == NULL) { - printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n", ax->dev->name); - ax->rx_dropped++; - return; - } - - spin_lock_bh(&ax->buflock); - memcpy(skb_put(skb,count), ax->rbuff, count); - spin_unlock_bh(&ax->buflock); - skb->protocol = ax25_type_trans(skb, ax->dev); - netif_rx(skb); - ax->dev->last_rx = jiffies; - ax->rx_packets++; - ax->rx_bytes+=count; + kfree(oxbuff); + kfree(orbuff); } /* Encapsulate one AX.25 packet and stuff into a TTY queue. */ -static void ax_encaps(struct ax_disp *ax, unsigned char *icp, int len) +static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) { + struct mkiss *ax = netdev_priv(dev); unsigned char *p; int actual, count; @@ -354,8 +409,8 @@ static void ax_encaps(struct ax_disp *ax, unsigned char *icp, int len) if (len > ax->mtu) { /* Sigh, shouldn't occur BUT ... */ len = ax->mtu; printk(KERN_ERR "mkiss: %s: truncating oversized transmit packet!\n", ax->dev->name); - ax->tx_dropped++; - ax_unlock(ax); + ax->stats.tx_dropped++; + netif_start_queue(dev); return; } @@ -376,10 +431,11 @@ static void ax_encaps(struct ax_disp *ax, unsigned char *icp, int len) break; } - ax->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags); actual = ax->tty->driver->write(ax->tty, ax->xbuff, count); - ax->tx_packets++; - ax->tx_bytes+=actual; + ax->stats.tx_packets++; + ax->stats.tx_bytes += actual; + ax->dev->trans_start = jiffies; ax->xleft = count - actual; ax->xhead = ax->xbuff + actual; @@ -387,37 +443,10 @@ static void ax_encaps(struct ax_disp *ax, unsigned char *icp, int len) spin_unlock_bh(&ax->buflock); } -/* - * Called by the driver when there's room for more data. If we have - * more packets to send, we send them here. - */ -static void ax25_write_wakeup(struct tty_struct *tty) -{ - int actual; - struct ax_disp *ax = (struct ax_disp *) tty->disc_data; - - /* First make sure we're connected. */ - if (ax == NULL || ax->magic != AX25_MAGIC || !netif_running(ax->dev)) - return; - if (ax->xleft <= 0) { - /* Now serial buffer is almost free & we can start - * transmission of another packet - */ - tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - - netif_wake_queue(ax->dev); - return; - } - - actual = tty->driver->write(tty, ax->xhead, ax->xleft); - ax->xleft -= actual; - ax->xhead += actual; -} - /* Encapsulate an AX.25 packet and kick it into a TTY queue. */ static int ax_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ax_disp *ax = netdev_priv(dev); + struct mkiss *ax = netdev_priv(dev); if (!netif_running(dev)) { printk(KERN_ERR "mkiss: %s: xmit call when iface is down\n", dev->name); @@ -429,7 +458,7 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev) * May be we must check transmitter timeout here ? * 14 Oct 1994 Dmitry Gorodchanin. */ - if (jiffies - dev->trans_start < 20 * HZ) { + if (time_before(jiffies, dev->trans_start + 20 * HZ)) { /* 20 sec timeout not reached */ return 1; } @@ -439,20 +468,30 @@ static int ax_xmit(struct sk_buff *skb, struct net_device *dev) "bad line quality" : "driver error"); ax->xleft = 0; - ax->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - ax_unlock(ax); + clear_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags); + netif_start_queue(dev); } /* We were not busy, so we are now... :-) */ if (skb != NULL) { - ax_lock(ax); - ax_encaps(ax, skb->data, skb->len); + netif_stop_queue(dev); + ax_encaps(dev, skb->data, skb->len); kfree_skb(skb); } return 0; } +static int ax_open_dev(struct net_device *dev) +{ + struct mkiss *ax = netdev_priv(dev); + + if (ax->tty == NULL) + return -ENODEV; + + return 0; +} + #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) /* Return the frame type ID */ @@ -481,7 +520,7 @@ static int ax_rebuild_header(struct sk_buff *skb) /* Open the low-level part of the AX25 channel. Easy! */ static int ax_open(struct net_device *dev) { - struct ax_disp *ax = netdev_priv(dev); + struct mkiss *ax = netdev_priv(dev); unsigned long len; if (ax->tty == NULL) @@ -518,7 +557,6 @@ static int ax_open(struct net_device *dev) spin_lock_init(&ax->buflock); - netif_start_queue(dev); return 0; noxbuff: @@ -532,68 +570,100 @@ norbuff: /* Close the low-level part of the AX25 channel. Easy! */ static int ax_close(struct net_device *dev) { - struct ax_disp *ax = netdev_priv(dev); + struct mkiss *ax = netdev_priv(dev); - if (ax->tty == NULL) - return -EBUSY; - - ax->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + if (ax->tty) + clear_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags); netif_stop_queue(dev); return 0; } -static int ax25_receive_room(struct tty_struct *tty) +static struct net_device_stats *ax_get_stats(struct net_device *dev) { - return 65536; /* We can handle an infinite amount of data. :-) */ + struct mkiss *ax = netdev_priv(dev); + + return &ax->stats; +} + +static void ax_setup(struct net_device *dev) +{ + static char ax25_bcast[AX25_ADDR_LEN] = + {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1}; + static char ax25_test[AX25_ADDR_LEN] = + {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1}; + + /* Finish setting up the DEVICE info. */ + dev->mtu = AX_MTU; + dev->hard_start_xmit = ax_xmit; + dev->open = ax_open_dev; + dev->stop = ax_close; + dev->get_stats = ax_get_stats; + dev->set_mac_address = ax_set_mac_address; + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->type = ARPHRD_AX25; + dev->tx_queue_len = 10; + dev->hard_header = ax_header; + dev->rebuild_header = ax_rebuild_header; + + memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); + memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); + + dev->flags = IFF_BROADCAST | IFF_MULTICAST; } /* - * Handle the 'receiver data ready' interrupt. - * This function is called by the 'tty_io' module in the kernel when - * a block of data has been received, which can now be decapsulated - * and sent on to the AX.25 layer for further processing. + * We have a potential race on dereferencing tty->disc_data, because the tty + * layer provides no locking at all - thus one cpu could be running + * sixpack_receive_buf while another calls sixpack_close, which zeroes + * tty->disc_data and frees the memory that sixpack_receive_buf is using. The + * best way to fix this is to use a rwlock in the tty struct, but for now we + * use a single global rwlock for all ttys in ppp line discipline. */ -static void ax25_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) +static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED; + +static struct mkiss *mkiss_get(struct tty_struct *tty) { - struct ax_disp *ax = (struct ax_disp *) tty->disc_data; + struct mkiss *ax; - if (ax == NULL || ax->magic != AX25_MAGIC || !netif_running(ax->dev)) - return; + read_lock(&disc_data_lock); + ax = tty->disc_data; + if (ax) + atomic_inc(&ax->refcnt); + read_unlock(&disc_data_lock); - /* - * Argh! mtu change time! - costs us the packet part received - * at the change - */ - if (ax->mtu != ax->dev->mtu + 73) - ax_changedmtu(ax); - - /* Read the characters out of the buffer */ - while (count--) { - if (fp != NULL && *fp++) { - if (!test_and_set_bit(AXF_ERROR, &ax->flags)) - ax->rx_errors++; - cp++; - continue; - } + return ax; +} - kiss_unesc(ax, *cp++); - } +static void mkiss_put(struct mkiss *ax) +{ + if (atomic_dec_and_test(&ax->refcnt)) + up(&ax->dead_sem); } -static int ax25_open(struct tty_struct *tty) +static int mkiss_open(struct tty_struct *tty) { - struct ax_disp *ax = (struct ax_disp *) tty->disc_data; + struct net_device *dev; + struct mkiss *ax; int err; - /* First make sure we're not already connected. */ - if (ax && ax->magic == AX25_MAGIC) - return -EEXIST; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; - /* OK. Find a free AX25 channel to use. */ - if ((ax = ax_alloc()) == NULL) - return -ENFILE; + dev = alloc_netdev(sizeof(struct mkiss), "ax%d", ax_setup); + if (!dev) { + err = -ENOMEM; + goto out; + } + + ax = netdev_priv(dev); + ax->dev = dev; + + spin_lock_init(&ax->buflock); + atomic_set(&ax->refcnt, 1); + init_MUTEX_LOCKED(&ax->dead_sem); ax->tty = tty; tty->disc_data = ax; @@ -602,283 +672,212 @@ static int ax25_open(struct tty_struct *tty) tty->driver->flush_buffer(tty); /* Restore default settings */ - ax->dev->type = ARPHRD_AX25; + dev->type = ARPHRD_AX25; /* Perform the low-level AX25 initialization. */ - if ((err = ax_open(ax->dev))) - return err; + if ((err = ax_open(ax->dev))) { + goto out_free_netdev; + } - /* Done. We have linked the TTY line to a channel. */ - return ax->dev->base_addr; -} + if (register_netdev(dev)) + goto out_free_buffers; -static void ax25_close(struct tty_struct *tty) -{ - struct ax_disp *ax = (struct ax_disp *) tty->disc_data; + netif_start_queue(dev); - /* First make sure we're connected. */ - if (ax == NULL || ax->magic != AX25_MAGIC) - return; + /* Done. We have linked the TTY line to a channel. */ + return 0; - unregister_netdev(ax->dev); +out_free_buffers: + kfree(ax->rbuff); + kfree(ax->xbuff); - tty->disc_data = NULL; - ax->tty = NULL; +out_free_netdev: + free_netdev(dev); - ax_free(ax); +out: + return err; } - -static struct net_device_stats *ax_get_stats(struct net_device *dev) +static void mkiss_close(struct tty_struct *tty) { - static struct net_device_stats stats; - struct ax_disp *ax = netdev_priv(dev); - - memset(&stats, 0, sizeof(struct net_device_stats)); - - stats.rx_packets = ax->rx_packets; - stats.tx_packets = ax->tx_packets; - stats.rx_bytes = ax->rx_bytes; - stats.tx_bytes = ax->tx_bytes; - stats.rx_dropped = ax->rx_dropped; - stats.tx_dropped = ax->tx_dropped; - stats.tx_errors = ax->tx_errors; - stats.rx_errors = ax->rx_errors; - stats.rx_over_errors = ax->rx_over_errors; - - return &stats; -} + struct mkiss *ax; + write_lock(&disc_data_lock); + ax = tty->disc_data; + tty->disc_data = NULL; + write_unlock(&disc_data_lock); -/************************************************************************ - * STANDARD ENCAPSULATION * - ************************************************************************/ - -static int kiss_esc(unsigned char *s, unsigned char *d, int len) -{ - unsigned char *ptr = d; - unsigned char c; + if (ax == 0) + return; /* - * Send an initial END character to flush out any - * data that may have accumulated in the receiver - * due to line noise. + * We have now ensured that nobody can start using ap from now on, but + * we have to wait for all existing users to finish. */ + if (!atomic_dec_and_test(&ax->refcnt)) + down(&ax->dead_sem); - *ptr++ = END; - - while (len-- > 0) { - switch (c = *s++) { - case END: - *ptr++ = ESC; - *ptr++ = ESC_END; - break; - case ESC: - *ptr++ = ESC; - *ptr++ = ESC_ESC; - break; - default: - *ptr++ = c; - break; - } - } + unregister_netdev(ax->dev); - *ptr++ = END; + /* Free all AX25 frame buffers. */ + kfree(ax->rbuff); + kfree(ax->xbuff); - return ptr - d; + ax->tty = NULL; } -/* - * MW: - * OK its ugly, but tell me a better solution without copying the - * packet to a temporary buffer :-) - */ -static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc, int len) +/* Perform I/O control on an active ax25 channel. */ +static int mkiss_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) { - unsigned char *ptr = d; - unsigned char c=0; - - *ptr++ = END; - while (len > 0) { - if (len > 2) - c = *s++; - else if (len > 1) - c = crc >> 8; - else if (len > 0) - c = crc & 0xff; + struct mkiss *ax = mkiss_get(tty); + struct net_device *dev = ax->dev; + unsigned int tmp, err; - len--; + /* First make sure we're connected. */ + if (ax == NULL) + return -ENXIO; - switch (c) { - case END: - *ptr++ = ESC; - *ptr++ = ESC_END; - break; - case ESC: - *ptr++ = ESC; - *ptr++ = ESC_ESC; - break; - default: - *ptr++ = c; - break; + switch (cmd) { + case SIOCGIFNAME: + err = copy_to_user((void __user *) arg, ax->dev->name, + strlen(ax->dev->name) + 1) ? -EFAULT : 0; + break; + + case SIOCGIFENCAP: + err = put_user(4, (int __user *) arg); + break; + + case SIOCSIFENCAP: + if (get_user(tmp, (int __user *) arg)) { + err = -EFAULT; + break; } - } - *ptr++ = END; - return ptr - d; -} -static void kiss_unesc(struct ax_disp *ax, unsigned char s) -{ - switch (s) { - case END: - /* drop keeptest bit = VSV */ - if (test_bit(AXF_KEEPTEST, &ax->flags)) - clear_bit(AXF_KEEPTEST, &ax->flags); + ax->mode = tmp; + dev->addr_len = AX25_ADDR_LEN; + dev->hard_header_len = AX25_KISS_HEADER_LEN + + AX25_MAX_HEADER_LEN + 3; + dev->type = ARPHRD_AX25; - if (!test_and_clear_bit(AXF_ERROR, &ax->flags) && (ax->rcount > 2)) - ax_bump(ax); + err = 0; + break; - clear_bit(AXF_ESCAPE, &ax->flags); - ax->rcount = 0; - return; + case SIOCSIFHWADDR: { + char addr[AX25_ADDR_LEN]; +printk(KERN_INFO "In SIOCSIFHWADDR"); - case ESC: - set_bit(AXF_ESCAPE, &ax->flags); - return; - case ESC_ESC: - if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) - s = ESC; + if (copy_from_user(&addr, + (void __user *) arg, AX25_ADDR_LEN)) { + err = -EFAULT; break; - case ESC_END: - if (test_and_clear_bit(AXF_ESCAPE, &ax->flags)) - s = END; - break; - } - - spin_lock_bh(&ax->buflock); - if (!test_bit(AXF_ERROR, &ax->flags)) { - if (ax->rcount < ax->buffsize) { - ax->rbuff[ax->rcount++] = s; - spin_unlock_bh(&ax->buflock); - return; } - ax->rx_over_errors++; - set_bit(AXF_ERROR, &ax->flags); + spin_lock_irq(&dev->xmit_lock); + memcpy(dev->dev_addr, addr, AX25_ADDR_LEN); + spin_unlock_irq(&dev->xmit_lock); + + err = 0; + break; + } + default: + err = -ENOIOCTLCMD; } - spin_unlock_bh(&ax->buflock); -} + mkiss_put(ax); -static int ax_set_mac_address(struct net_device *dev, void __user *addr) -{ - if (copy_from_user(dev->dev_addr, addr, AX25_ADDR_LEN)) - return -EFAULT; - return 0; + return err; } -static int ax_set_dev_mac_address(struct net_device *dev, void *addr) +/* + * Handle the 'receiver data ready' interrupt. + * This function is called by the 'tty_io' module in the kernel when + * a block of data has been received, which can now be decapsulated + * and sent on to the AX.25 layer for further processing. + */ +static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp, + char *fp, int count) { - struct sockaddr *sa = addr; - - memcpy(dev->dev_addr, sa->sa_data, AX25_ADDR_LEN); + struct mkiss *ax = mkiss_get(tty); - return 0; -} - - -/* Perform I/O control on an active ax25 channel. */ -static int ax25_disp_ioctl(struct tty_struct *tty, void *file, int cmd, void __user *arg) -{ - struct ax_disp *ax = (struct ax_disp *) tty->disc_data; - unsigned int tmp; + if (!ax) + return; - /* First make sure we're connected. */ - if (ax == NULL || ax->magic != AX25_MAGIC) - return -EINVAL; + /* + * Argh! mtu change time! - costs us the packet part received + * at the change + */ + if (ax->mtu != ax->dev->mtu + 73) + ax_changedmtu(ax); - switch (cmd) { - case SIOCGIFNAME: - if (copy_to_user(arg, ax->dev->name, strlen(ax->dev->name) + 1)) - return -EFAULT; - return 0; - - case SIOCGIFENCAP: - return put_user(4, (int __user *)arg); - - case SIOCSIFENCAP: - if (get_user(tmp, (int __user *)arg)) - return -EFAULT; - ax->mode = tmp; - ax->dev->addr_len = AX25_ADDR_LEN; /* sizeof an AX.25 addr */ - ax->dev->hard_header_len = AX25_KISS_HEADER_LEN + AX25_MAX_HEADER_LEN + 3; - ax->dev->type = ARPHRD_AX25; - return 0; - - case SIOCSIFHWADDR: - return ax_set_mac_address(ax->dev, arg); + /* Read the characters out of the buffer */ + while (count--) { + if (fp != NULL && *fp++) { + if (!test_and_set_bit(AXF_ERROR, &ax->flags)) + ax->stats.rx_errors++; + cp++; + continue; + } - default: - return -ENOIOCTLCMD; + kiss_unesc(ax, *cp++); } + + mkiss_put(ax); + if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) + && tty->driver->unthrottle) + tty->driver->unthrottle(tty); } -static int ax_open_dev(struct net_device *dev) +static int mkiss_receive_room(struct tty_struct *tty) { - struct ax_disp *ax = netdev_priv(dev); - - if (ax->tty == NULL) - return -ENODEV; - - return 0; + return 65536; /* We can handle an infinite amount of data. :-) */ } - -/* Initialize the driver. Called by network startup. */ -static int ax25_init(struct net_device *dev) +/* + * Called by the driver when there's room for more data. If we have + * more packets to send, we send them here. + */ +static void mkiss_write_wakeup(struct tty_struct *tty) { - struct ax_disp *ax = netdev_priv(dev); - - static char ax25_bcast[AX25_ADDR_LEN] = - {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1}; - static char ax25_test[AX25_ADDR_LEN] = - {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1}; - - if (ax == NULL) /* Allocation failed ?? */ - return -ENODEV; + struct mkiss *ax = mkiss_get(tty); + int actual; - /* Set up the "AX25 Control Block". (And clear statistics) */ - memset(ax, 0, sizeof (struct ax_disp)); - ax->magic = AX25_MAGIC; - ax->dev = dev; + if (!ax) + return; - /* Finish setting up the DEVICE info. */ - dev->mtu = AX_MTU; - dev->hard_start_xmit = ax_xmit; - dev->open = ax_open_dev; - dev->stop = ax_close; - dev->get_stats = ax_get_stats; - dev->set_mac_address = ax_set_dev_mac_address; - dev->hard_header_len = 0; - dev->addr_len = 0; - dev->type = ARPHRD_AX25; - dev->tx_queue_len = 10; - dev->hard_header = ax_header; - dev->rebuild_header = ax_rebuild_header; + if (ax->xleft <= 0) { + /* Now serial buffer is almost free & we can start + * transmission of another packet + */ + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); - memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); + netif_wake_queue(ax->dev); + goto out; + } - /* New-style flags. */ - dev->flags = IFF_BROADCAST | IFF_MULTICAST; + actual = tty->driver->write(tty, ax->xhead, ax->xleft); + ax->xleft -= actual; + ax->xhead += actual; - return 0; +out: + mkiss_put(ax); } +static struct tty_ldisc ax_ldisc = { + .magic = TTY_LDISC_MAGIC, + .name = "mkiss", + .open = mkiss_open, + .close = mkiss_close, + .ioctl = mkiss_ioctl, + .receive_buf = mkiss_receive_buf, + .receive_room = mkiss_receive_room, + .write_wakeup = mkiss_write_wakeup +}; -/* ******************************************************************** */ -/* * Init MKISS driver * */ -/* ******************************************************************** */ +static char banner[] __initdata = KERN_INFO \ + "mkiss: AX.25 Multikiss, Hans Albas PE1AYX\n"; +static char msg_regfail[] __initdata = KERN_ERR \ + "mkiss: can't register line discipline (err = %d)\n"; static int __init mkiss_init_driver(void) { @@ -886,64 +885,27 @@ static int __init mkiss_init_driver(void) printk(banner); - if (ax25_maxdev < 4) - ax25_maxdev = 4; /* Sanity */ + if ((status = tty_register_ldisc(N_AX25, &ax_ldisc)) != 0) + printk(msg_regfail); - if ((ax25_ctrls = kmalloc(sizeof(void *) * ax25_maxdev, GFP_KERNEL)) == NULL) { - printk(KERN_ERR "mkiss: Can't allocate ax25_ctrls[] array!\n"); - return -ENOMEM; - } - - /* Clear the pointer array, we allocate devices when we need them */ - memset(ax25_ctrls, 0, sizeof(void*) * ax25_maxdev); /* Pointers */ - - /* Fill in our line protocol discipline, and register it */ - ax_ldisc.magic = TTY_LDISC_MAGIC; - ax_ldisc.name = "mkiss"; - ax_ldisc.open = ax25_open; - ax_ldisc.close = ax25_close; - ax_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, - unsigned int, unsigned long))ax25_disp_ioctl; - ax_ldisc.receive_buf = ax25_receive_buf; - ax_ldisc.receive_room = ax25_receive_room; - ax_ldisc.write_wakeup = ax25_write_wakeup; - - if ((status = tty_register_ldisc(N_AX25, &ax_ldisc)) != 0) { - printk(KERN_ERR "mkiss: can't register line discipline (err = %d)\n", status); - kfree(ax25_ctrls); - } return status; } +static const char msg_unregfail[] __exitdata = KERN_ERR \ + "mkiss: can't unregister line discipline (err = %d)\n"; + static void __exit mkiss_exit_driver(void) { - int i; - - for (i = 0; i < ax25_maxdev; i++) { - if (ax25_ctrls[i]) { - /* - * VSV = if dev->start==0, then device - * unregistered while close proc. - */ - if (netif_running(&ax25_ctrls[i]->dev)) - unregister_netdev(&ax25_ctrls[i]->dev); - kfree(ax25_ctrls[i]); - } - } + int ret; - kfree(ax25_ctrls); - ax25_ctrls = NULL; - - if ((i = tty_unregister_ldisc(N_AX25))) - printk(KERN_ERR "mkiss: can't unregister line discipline (err = %d)\n", i); + if ((ret = tty_unregister_ldisc(N_AX25))) + printk(msg_unregfail, ret); } -MODULE_AUTHOR("Hans Albas PE1AYX <hans@esrac.ele.tue.nl>"); +MODULE_AUTHOR("Ralf Baechle DL5RB <ralf@linux-mips.org>"); MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs"); -MODULE_PARM(ax25_maxdev, "i"); -MODULE_PARM_DESC(ax25_maxdev, "number of MKISS devices"); MODULE_LICENSE("GPL"); MODULE_ALIAS_LDISC(N_AX25); + module_init(mkiss_init_driver); module_exit(mkiss_exit_driver); - diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index c7fb3675c09..0de3bb90617 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -1253,7 +1253,7 @@ static int emac_init_tah(struct ocp_enet_private *fep) TAH_MR_CVR | TAH_MR_ST_768 | TAH_MR_TFS_10KB | TAH_MR_DTFP | TAH_MR_DIG); - iounmap(&tahp); + iounmap(tahp); return 0; } diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h index f8d3385c784..c83271b3862 100644 --- a/drivers/net/ixgb/ixgb.h +++ b/drivers/net/ixgb/ixgb.h @@ -119,7 +119,7 @@ struct ixgb_adapter; * so a DMA handle can be stored along with the buffer */ struct ixgb_buffer { struct sk_buff *skb; - uint64_t dma; + dma_addr_t dma; unsigned long time_stamp; uint16_t length; uint16_t next_to_watch; diff --git a/drivers/net/ixgb/ixgb_ee.c b/drivers/net/ixgb/ixgb_ee.c index 3aae110c556..661a46b95a6 100644 --- a/drivers/net/ixgb/ixgb_ee.c +++ b/drivers/net/ixgb/ixgb_ee.c @@ -565,24 +565,6 @@ ixgb_get_ee_mac_addr(struct ixgb_hw *hw, } } -/****************************************************************************** - * return the compatibility flags from EEPROM - * - * hw - Struct containing variables accessed by shared code - * - * Returns: - * compatibility flags if EEPROM contents are valid, 0 otherwise - ******************************************************************************/ -uint16_t -ixgb_get_ee_compatibility(struct ixgb_hw *hw) -{ - struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; - - if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return (le16_to_cpu(ee_map->compatibility)); - - return(0); -} /****************************************************************************** * return the Printed Board Assembly number from EEPROM @@ -602,81 +584,6 @@ ixgb_get_ee_pba_number(struct ixgb_hw *hw) return(0); } -/****************************************************************************** - * return the Initialization Control Word 1 from EEPROM - * - * hw - Struct containing variables accessed by shared code - * - * Returns: - * Initialization Control Word 1 if EEPROM contents are valid, 0 otherwise - ******************************************************************************/ -uint16_t -ixgb_get_ee_init_ctrl_reg_1(struct ixgb_hw *hw) -{ - struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; - - if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return (le16_to_cpu(ee_map->init_ctrl_reg_1)); - - return(0); -} - -/****************************************************************************** - * return the Initialization Control Word 2 from EEPROM - * - * hw - Struct containing variables accessed by shared code - * - * Returns: - * Initialization Control Word 2 if EEPROM contents are valid, 0 otherwise - ******************************************************************************/ -uint16_t -ixgb_get_ee_init_ctrl_reg_2(struct ixgb_hw *hw) -{ - struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; - - if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return (le16_to_cpu(ee_map->init_ctrl_reg_2)); - - return(0); -} - -/****************************************************************************** - * return the Subsystem Id from EEPROM - * - * hw - Struct containing variables accessed by shared code - * - * Returns: - * Subsystem Id if EEPROM contents are valid, 0 otherwise - ******************************************************************************/ -uint16_t -ixgb_get_ee_subsystem_id(struct ixgb_hw *hw) -{ - struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; - - if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return (le16_to_cpu(ee_map->subsystem_id)); - - return(0); -} - -/****************************************************************************** - * return the Sub Vendor Id from EEPROM - * - * hw - Struct containing variables accessed by shared code - * - * Returns: - * Sub Vendor Id if EEPROM contents are valid, 0 otherwise - ******************************************************************************/ -uint16_t -ixgb_get_ee_subvendor_id(struct ixgb_hw *hw) -{ - struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; - - if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return (le16_to_cpu(ee_map->subvendor_id)); - - return(0); -} /****************************************************************************** * return the Device Id from EEPROM @@ -694,81 +601,6 @@ ixgb_get_ee_device_id(struct ixgb_hw *hw) if(ixgb_check_and_get_eeprom_data(hw) == TRUE) return (le16_to_cpu(ee_map->device_id)); - return(0); -} - -/****************************************************************************** - * return the Vendor Id from EEPROM - * - * hw - Struct containing variables accessed by shared code - * - * Returns: - * Device Id if EEPROM contents are valid, 0 otherwise - ******************************************************************************/ -uint16_t -ixgb_get_ee_vendor_id(struct ixgb_hw *hw) -{ - struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; - - if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return (le16_to_cpu(ee_map->vendor_id)); - - return(0); -} - -/****************************************************************************** - * return the Software Defined Pins Register from EEPROM - * - * hw - Struct containing variables accessed by shared code - * - * Returns: - * SDP Register if EEPROM contents are valid, 0 otherwise - ******************************************************************************/ -uint16_t -ixgb_get_ee_swdpins_reg(struct ixgb_hw *hw) -{ - struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; - - if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return (le16_to_cpu(ee_map->swdpins_reg)); - - return(0); + return (0); } -/****************************************************************************** - * return the D3 Power Management Bits from EEPROM - * - * hw - Struct containing variables accessed by shared code - * - * Returns: - * D3 Power Management Bits if EEPROM contents are valid, 0 otherwise - ******************************************************************************/ -uint8_t -ixgb_get_ee_d3_power(struct ixgb_hw *hw) -{ - struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; - - if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return (le16_to_cpu(ee_map->d3_power)); - - return(0); -} - -/****************************************************************************** - * return the D0 Power Management Bits from EEPROM - * - * hw - Struct containing variables accessed by shared code - * - * Returns: - * D0 Power Management Bits if EEPROM contents are valid, 0 otherwise - ******************************************************************************/ -uint8_t -ixgb_get_ee_d0_power(struct ixgb_hw *hw) -{ - struct ixgb_ee_map_type *ee_map = (struct ixgb_ee_map_type *)hw->eeprom; - - if(ixgb_check_and_get_eeprom_data(hw) == TRUE) - return (le16_to_cpu(ee_map->d0_power)); - - return(0); -} diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index 3fa113854ee..9d026ed77dd 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -98,10 +98,10 @@ static struct ixgb_stats ixgb_gstrings_stats[] = { static int ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); - ecmd->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); + ecmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE); ecmd->port = PORT_FIBRE; ecmd->transceiver = XCVR_EXTERNAL; @@ -120,7 +120,7 @@ ixgb_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) static int ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); if(ecmd->autoneg == AUTONEG_ENABLE || ecmd->speed + ecmd->duplex != SPEED_10000 + DUPLEX_FULL) @@ -130,6 +130,12 @@ ixgb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) ixgb_down(adapter, TRUE); ixgb_reset(adapter); ixgb_up(adapter); + /* be optimistic about our link, since we were up before */ + adapter->link_speed = 10000; + adapter->link_duplex = FULL_DUPLEX; + netif_carrier_on(netdev); + netif_wake_queue(netdev); + } else ixgb_reset(adapter); @@ -140,7 +146,7 @@ static void ixgb_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_hw *hw = &adapter->hw; pause->autoneg = AUTONEG_DISABLE; @@ -159,7 +165,7 @@ static int ixgb_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_hw *hw = &adapter->hw; if(pause->autoneg == AUTONEG_ENABLE) @@ -177,6 +183,11 @@ ixgb_set_pauseparam(struct net_device *netdev, if(netif_running(adapter->netdev)) { ixgb_down(adapter, TRUE); ixgb_up(adapter); + /* be optimistic about our link, since we were up before */ + adapter->link_speed = 10000; + adapter->link_duplex = FULL_DUPLEX; + netif_carrier_on(netdev); + netif_wake_queue(netdev); } else ixgb_reset(adapter); @@ -186,19 +197,26 @@ ixgb_set_pauseparam(struct net_device *netdev, static uint32_t ixgb_get_rx_csum(struct net_device *netdev) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); + return adapter->rx_csum; } static int ixgb_set_rx_csum(struct net_device *netdev, uint32_t data) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); + adapter->rx_csum = data; if(netif_running(netdev)) { ixgb_down(adapter,TRUE); ixgb_up(adapter); + /* be optimistic about our link, since we were up before */ + adapter->link_speed = 10000; + adapter->link_duplex = FULL_DUPLEX; + netif_carrier_on(netdev); + netif_wake_queue(netdev); } else ixgb_reset(adapter); return 0; @@ -246,14 +264,15 @@ static void ixgb_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_hw *hw = &adapter->hw; uint32_t *reg = p; uint32_t *reg_start = reg; uint8_t i; /* the 1 (one) below indicates an attempt at versioning, if the - * interface in ethtool or the driver this 1 should be incremented */ + * interface in ethtool or the driver changes, this 1 should be + * incremented */ regs->version = (1<<24) | hw->revision_id << 16 | hw->device_id; /* General Registers */ @@ -283,7 +302,8 @@ ixgb_get_regs(struct net_device *netdev, *reg++ = IXGB_READ_REG(hw, RAIDC); /* 19 */ *reg++ = IXGB_READ_REG(hw, RXCSUM); /* 20 */ - for (i = 0; i < IXGB_RAR_ENTRIES; i++) { + /* there are 16 RAR entries in hardware, we only use 3 */ + for(i = 0; i < 16; i++) { *reg++ = IXGB_READ_REG_ARRAY(hw, RAL, (i << 1)); /*21,...,51 */ *reg++ = IXGB_READ_REG_ARRAY(hw, RAH, (i << 1)); /*22,...,52 */ } @@ -391,7 +411,7 @@ static int ixgb_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, uint8_t *bytes) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_hw *hw = &adapter->hw; uint16_t *eeprom_buff; int i, max_len, first_word, last_word; @@ -439,7 +459,7 @@ static int ixgb_set_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, uint8_t *bytes) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_hw *hw = &adapter->hw; uint16_t *eeprom_buff; void *ptr; @@ -497,7 +517,7 @@ static void ixgb_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); strncpy(drvinfo->driver, ixgb_driver_name, 32); strncpy(drvinfo->version, ixgb_driver_version, 32); @@ -512,7 +532,7 @@ static void ixgb_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_desc_ring *txdr = &adapter->tx_ring; struct ixgb_desc_ring *rxdr = &adapter->rx_ring; @@ -530,7 +550,7 @@ static int ixgb_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_desc_ring *txdr = &adapter->tx_ring; struct ixgb_desc_ring *rxdr = &adapter->rx_ring; struct ixgb_desc_ring tx_old, tx_new, rx_old, rx_new; @@ -573,6 +593,11 @@ ixgb_set_ringparam(struct net_device *netdev, adapter->tx_ring = tx_new; if((err = ixgb_up(adapter))) return err; + /* be optimistic about our link, since we were up before */ + adapter->link_speed = 10000; + adapter->link_duplex = FULL_DUPLEX; + netif_carrier_on(netdev); + netif_wake_queue(netdev); } return 0; @@ -607,7 +632,7 @@ ixgb_led_blink_callback(unsigned long data) static int ixgb_phys_id(struct net_device *netdev, uint32_t data) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); if(!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ)) data = (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ); @@ -643,7 +668,7 @@ static void ixgb_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, uint64_t *data) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); int i; ixgb_update_stats(adapter); diff --git a/drivers/net/ixgb/ixgb_hw.h b/drivers/net/ixgb/ixgb_hw.h index 97898efe7cc..8bcf31ed10c 100644 --- a/drivers/net/ixgb/ixgb_hw.h +++ b/drivers/net/ixgb/ixgb_hw.h @@ -822,17 +822,8 @@ extern void ixgb_clear_vfta(struct ixgb_hw *hw); /* Access functions to eeprom data */ void ixgb_get_ee_mac_addr(struct ixgb_hw *hw, uint8_t *mac_addr); -uint16_t ixgb_get_ee_compatibility(struct ixgb_hw *hw); uint32_t ixgb_get_ee_pba_number(struct ixgb_hw *hw); -uint16_t ixgb_get_ee_init_ctrl_reg_1(struct ixgb_hw *hw); -uint16_t ixgb_get_ee_init_ctrl_reg_2(struct ixgb_hw *hw); -uint16_t ixgb_get_ee_subsystem_id(struct ixgb_hw *hw); -uint16_t ixgb_get_ee_subvendor_id(struct ixgb_hw *hw); uint16_t ixgb_get_ee_device_id(struct ixgb_hw *hw); -uint16_t ixgb_get_ee_vendor_id(struct ixgb_hw *hw); -uint16_t ixgb_get_ee_swdpins_reg(struct ixgb_hw *hw); -uint8_t ixgb_get_ee_d3_power(struct ixgb_hw *hw); -uint8_t ixgb_get_ee_d0_power(struct ixgb_hw *hw); boolean_t ixgb_get_eeprom_data(struct ixgb_hw *hw); uint16_t ixgb_get_eeprom_word(struct ixgb_hw *hw, uint16_t index); diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 097b90ccf57..5c555373adb 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -29,6 +29,11 @@ #include "ixgb.h" /* Change Log + * 1.0.96 04/19/05 + * - Make needlessly global code static -- bunk@stusta.de + * - ethtool cleanup -- shemminger@osdl.org + * - Support for MODULE_VERSION -- linville@tuxdriver.com + * - add skb_header_cloned check to the tso path -- herbert@apana.org.au * 1.0.88 01/05/05 * - include fix to the condition that determines when to quit NAPI - Robert Olsson * - use netif_poll_{disable/enable} to synchronize between NAPI and i/f up/down @@ -47,10 +52,9 @@ char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver"; #else #define DRIVERNAPI "-NAPI" #endif - -#define DRV_VERSION "1.0.95-k2"DRIVERNAPI +#define DRV_VERSION "1.0.100-k2"DRIVERNAPI char ixgb_driver_version[] = DRV_VERSION; -char ixgb_copyright[] = "Copyright (c) 1999-2005 Intel Corporation."; +static char ixgb_copyright[] = "Copyright (c) 1999-2005 Intel Corporation."; /* ixgb_pci_tbl - PCI Device ID Table * @@ -145,10 +149,12 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); /* some defines for controlling descriptor fetches in h/w */ -#define RXDCTL_PTHRESH_DEFAULT 128 /* chip considers prefech below this */ -#define RXDCTL_HTHRESH_DEFAULT 16 /* chip will only prefetch if tail is - pushed this many descriptors from head */ #define RXDCTL_WTHRESH_DEFAULT 16 /* chip writes back at this many or RXT0 */ +#define RXDCTL_PTHRESH_DEFAULT 0 /* chip considers prefech below + * this */ +#define RXDCTL_HTHRESH_DEFAULT 0 /* chip will only prefetch if tail + * is pushed this many descriptors + * from head */ /** * ixgb_init_module - Driver Registration Routine @@ -376,7 +382,7 @@ ixgb_probe(struct pci_dev *pdev, SET_NETDEV_DEV(netdev, &pdev->dev); pci_set_drvdata(pdev, netdev); - adapter = netdev->priv; + adapter = netdev_priv(netdev); adapter->netdev = netdev; adapter->pdev = pdev; adapter->hw.back = adapter; @@ -512,7 +518,7 @@ static void __devexit ixgb_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); unregister_netdev(netdev); @@ -583,7 +589,7 @@ ixgb_sw_init(struct ixgb_adapter *adapter) static int ixgb_open(struct net_device *netdev) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); int err; /* allocate transmit descriptors */ @@ -626,7 +632,7 @@ err_setup_tx: static int ixgb_close(struct net_device *netdev) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); ixgb_down(adapter, TRUE); @@ -1017,7 +1023,7 @@ ixgb_clean_rx_ring(struct ixgb_adapter *adapter) static int ixgb_set_mac(struct net_device *netdev, void *p) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); struct sockaddr *addr = p; if(!is_valid_ether_addr(addr->sa_data)) @@ -1043,7 +1049,7 @@ ixgb_set_mac(struct net_device *netdev, void *p) static void ixgb_set_multi(struct net_device *netdev) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_hw *hw = &adapter->hw; struct dev_mc_list *mc_ptr; uint32_t rctl; @@ -1371,7 +1377,7 @@ ixgb_tx_queue(struct ixgb_adapter *adapter, int count, int vlan_id,int tx_flags) static int ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); unsigned int first; unsigned int tx_flags = 0; unsigned long flags; @@ -1425,7 +1431,7 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) static void ixgb_tx_timeout(struct net_device *netdev) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); /* Do the reset outside of interrupt context */ schedule_work(&adapter->tx_timeout_task); @@ -1434,7 +1440,7 @@ ixgb_tx_timeout(struct net_device *netdev) static void ixgb_tx_timeout_task(struct net_device *netdev) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); ixgb_down(adapter, TRUE); ixgb_up(adapter); @@ -1451,7 +1457,7 @@ ixgb_tx_timeout_task(struct net_device *netdev) static struct net_device_stats * ixgb_get_stats(struct net_device *netdev) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); return &adapter->net_stats; } @@ -1467,7 +1473,7 @@ ixgb_get_stats(struct net_device *netdev) static int ixgb_change_mtu(struct net_device *netdev, int new_mtu) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); int max_frame = new_mtu + ENET_HEADER_SIZE + ENET_FCS_LENGTH; int old_max_frame = netdev->mtu + ENET_HEADER_SIZE + ENET_FCS_LENGTH; @@ -1522,7 +1528,8 @@ ixgb_update_stats(struct ixgb_adapter *adapter) multi |= ((u64)IXGB_READ_REG(&adapter->hw, MPRCH) << 32); /* fix up multicast stats by removing broadcasts */ - multi -= bcast; + if(multi >= bcast) + multi -= bcast; adapter->stats.mprcl += (multi & 0xFFFFFFFF); adapter->stats.mprch += (multi >> 32); @@ -1641,7 +1648,7 @@ static irqreturn_t ixgb_intr(int irq, void *data, struct pt_regs *regs) { struct net_device *netdev = data; - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); struct ixgb_hw *hw = &adapter->hw; uint32_t icr = IXGB_READ_REG(hw, ICR); #ifndef CONFIG_IXGB_NAPI @@ -1688,7 +1695,7 @@ ixgb_intr(int irq, void *data, struct pt_regs *regs) static int ixgb_clean(struct net_device *netdev, int *budget) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); int work_to_do = min(*budget, netdev->quota); int tx_cleaned; int work_done = 0; @@ -2017,7 +2024,7 @@ ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter) static void ixgb_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); uint32_t ctrl, rctl; ixgb_irq_disable(adapter); @@ -2055,7 +2062,7 @@ ixgb_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) static void ixgb_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); uint32_t vfta, index; /* add VID to filter table */ @@ -2069,7 +2076,7 @@ ixgb_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid) static void ixgb_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid) { - struct ixgb_adapter *adapter = netdev->priv; + struct ixgb_adapter *adapter = netdev_priv(netdev); uint32_t vfta, index; ixgb_irq_disable(adapter); diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index 7fec613e167..8423cb6875f 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -1,5 +1,10 @@ /* - * sonic.c + * jazzsonic.c + * + * (C) 2005 Finn Thain + * + * Converted to DMA API, and (from the mac68k project) introduced + * dhd's support for 16-bit cards. * * (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de) * @@ -28,8 +33,8 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> -#include <linux/bitops.h> #include <linux/device.h> +#include <linux/dma-mapping.h> #include <asm/bootinfo.h> #include <asm/system.h> @@ -44,22 +49,20 @@ static struct platform_device *jazz_sonic_device; #define SONIC_MEM_SIZE 0x100 -#define SREGS_PAD(n) u16 n; - #include "sonic.h" /* * Macros to access SONIC registers */ -#define SONIC_READ(reg) (*((volatile unsigned int *)base_addr+reg)) +#define SONIC_READ(reg) (*((volatile unsigned int *)dev->base_addr+reg)) #define SONIC_WRITE(reg,val) \ do { \ - *((volatile unsigned int *)base_addr+(reg)) = (val); \ + *((volatile unsigned int *)dev->base_addr+(reg)) = (val); \ } while (0) -/* use 0 for production, 1 for verification, >2 for debug */ +/* use 0 for production, 1 for verification, >1 for debug */ #ifdef SONIC_DEBUG static unsigned int sonic_debug = SONIC_DEBUG; #else @@ -85,18 +88,18 @@ static unsigned short known_revisions[] = 0xffff /* end of list */ }; -static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr, - unsigned int irq) +static int __init sonic_probe1(struct net_device *dev) { static unsigned version_printed; unsigned int silicon_revision; unsigned int val; - struct sonic_local *lp; + struct sonic_local *lp = netdev_priv(dev); int err = -ENODEV; int i; - if (!request_mem_region(base_addr, SONIC_MEM_SIZE, jazz_sonic_string)) + if (!request_mem_region(dev->base_addr, SONIC_MEM_SIZE, jazz_sonic_string)) return -EBUSY; + /* * get the Silicon Revision ID. If this is one of the known * one assume that we found a SONIC ethernet controller at @@ -120,11 +123,7 @@ static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr, if (sonic_debug && version_printed++ == 0) printk(version); - printk("%s: Sonic ethernet found at 0x%08lx, ", dev->name, base_addr); - - /* Fill in the 'dev' fields. */ - dev->base_addr = base_addr; - dev->irq = irq; + printk(KERN_INFO "%s: Sonic ethernet found at 0x%08lx, ", lp->device->bus_id, dev->base_addr); /* * Put the sonic into software reset, then @@ -138,84 +137,44 @@ static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr, dev->dev_addr[i*2+1] = val >> 8; } - printk("HW Address "); - for (i = 0; i < 6; i++) { - printk("%2.2x", dev->dev_addr[i]); - if (i<5) - printk(":"); - } - - printk(" IRQ %d\n", irq); - err = -ENOMEM; /* Initialize the device structure. */ - if (dev->priv == NULL) { - /* - * the memory be located in the same 64kb segment - */ - lp = NULL; - i = 0; - do { - lp = kmalloc(sizeof(*lp), GFP_KERNEL); - if ((unsigned long) lp >> 16 - != ((unsigned long)lp + sizeof(*lp) ) >> 16) { - /* FIXME, free the memory later */ - kfree(lp); - lp = NULL; - } - } while (lp == NULL && i++ < 20); - - if (lp == NULL) { - printk("%s: couldn't allocate memory for descriptors\n", - dev->name); - goto out; - } - memset(lp, 0, sizeof(struct sonic_local)); - - /* get the virtual dma address */ - lp->cda_laddr = vdma_alloc(CPHYSADDR(lp),sizeof(*lp)); - if (lp->cda_laddr == ~0UL) { - printk("%s: couldn't get DMA page entry for " - "descriptors\n", dev->name); - goto out1; - } - - lp->tda_laddr = lp->cda_laddr + sizeof (lp->cda); - lp->rra_laddr = lp->tda_laddr + sizeof (lp->tda); - lp->rda_laddr = lp->rra_laddr + sizeof (lp->rra); - - /* allocate receive buffer area */ - /* FIXME, maybe we should use skbs */ - lp->rba = kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL); - if (!lp->rba) { - printk("%s: couldn't allocate receive buffers\n", - dev->name); - goto out2; - } + lp->dma_bitmode = SONIC_BITMODE32; - /* get virtual dma address */ - lp->rba_laddr = vdma_alloc(CPHYSADDR(lp->rba), - SONIC_NUM_RRS * SONIC_RBSIZE); - if (lp->rba_laddr == ~0UL) { - printk("%s: couldn't get DMA page entry for receive " - "buffers\n",dev->name); - goto out3; - } - - /* now convert pointer to KSEG1 pointer */ - lp->rba = (char *)KSEG1ADDR(lp->rba); - flush_cache_all(); - dev->priv = (struct sonic_local *)KSEG1ADDR(lp); + /* Allocate the entire chunk of memory for the descriptors. + Note that this cannot cross a 64K boundary. */ + if ((lp->descriptors = dma_alloc_coherent(lp->device, + SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), + &lp->descriptors_laddr, GFP_KERNEL)) == NULL) { + printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n", lp->device->bus_id); + goto out; } - lp = (struct sonic_local *)dev->priv; + /* Now set up the pointers to point to the appropriate places */ + lp->cda = lp->descriptors; + lp->tda = lp->cda + (SIZEOF_SONIC_CDA + * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS + * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS + * SONIC_BUS_SCALE(lp->dma_bitmode)); + + lp->cda_laddr = lp->descriptors_laddr; + lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA + * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS + * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS + * SONIC_BUS_SCALE(lp->dma_bitmode)); + dev->open = sonic_open; dev->stop = sonic_close; dev->hard_start_xmit = sonic_send_packet; - dev->get_stats = sonic_get_stats; + dev->get_stats = sonic_get_stats; dev->set_multicast_list = &sonic_multicast_list; + dev->tx_timeout = sonic_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; /* @@ -226,14 +185,8 @@ static int __init sonic_probe1(struct net_device *dev, unsigned long base_addr, SONIC_WRITE(SONIC_MPT,0xffff); return 0; -out3: - kfree(lp->rba); -out2: - vdma_free(lp->cda_laddr); -out1: - kfree(lp); out: - release_region(base_addr, SONIC_MEM_SIZE); + release_region(dev->base_addr, SONIC_MEM_SIZE); return err; } @@ -245,7 +198,6 @@ static int __init jazz_sonic_probe(struct device *device) { struct net_device *dev; struct sonic_local *lp; - unsigned long base_addr; int err = 0; int i; @@ -255,21 +207,26 @@ static int __init jazz_sonic_probe(struct device *device) if (mips_machgroup != MACH_GROUP_JAZZ) return -ENODEV; - dev = alloc_etherdev(0); + dev = alloc_etherdev(sizeof(struct sonic_local)); if (!dev) return -ENOMEM; + lp = netdev_priv(dev); + lp->device = device; + SET_NETDEV_DEV(dev, device); + SET_MODULE_OWNER(dev); + netdev_boot_setup_check(dev); - base_addr = dev->base_addr; - if (base_addr >= KSEG0) { /* Check a single specified location. */ - err = sonic_probe1(dev, base_addr, dev->irq); - } else if (base_addr != 0) { /* Don't probe at all. */ + if (dev->base_addr >= KSEG0) { /* Check a single specified location. */ + err = sonic_probe1(dev); + } else if (dev->base_addr != 0) { /* Don't probe at all. */ err = -ENXIO; } else { for (i = 0; sonic_portlist[i].port; i++) { - int io = sonic_portlist[i].port; - if (sonic_probe1(dev, io, sonic_portlist[i].irq) == 0) + dev->base_addr = sonic_portlist[i].port; + dev->irq = sonic_portlist[i].irq; + if (sonic_probe1(dev) == 0) break; } if (!sonic_portlist[i].port) @@ -281,14 +238,17 @@ static int __init jazz_sonic_probe(struct device *device) if (err) goto out1; + printk("%s: MAC ", dev->name); + for (i = 0; i < 6; i++) { + printk("%2.2x", dev->dev_addr[i]); + if (i < 5) + printk(":"); + } + printk(" IRQ %d\n", dev->irq); + return 0; out1: - lp = dev->priv; - vdma_free(lp->rba_laddr); - kfree(lp->rba); - vdma_free(lp->cda_laddr); - kfree(lp); release_region(dev->base_addr, SONIC_MEM_SIZE); out: free_netdev(dev); @@ -296,21 +256,22 @@ out: return err; } -/* - * SONIC uses a normal IRQ - */ -#define sonic_request_irq request_irq -#define sonic_free_irq free_irq +MODULE_DESCRIPTION("Jazz SONIC ethernet driver"); +module_param(sonic_debug, int, 0); +MODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)"); -#define sonic_chiptomem(x) KSEG1ADDR(vdma_log2phys(x)) +#define SONIC_IRQ_FLAG SA_INTERRUPT #include "sonic.c" static int __devexit jazz_sonic_device_remove (struct device *device) { struct net_device *dev = device->driver_data; + struct sonic_local* lp = netdev_priv(dev); unregister_netdev (dev); + dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), + lp->descriptors, lp->descriptors_laddr); release_region (dev->base_addr, SONIC_MEM_SIZE); free_netdev (dev); @@ -323,7 +284,7 @@ static struct device_driver jazz_sonic_driver = { .probe = jazz_sonic_probe, .remove = __devexit_p(jazz_sonic_device_remove), }; - + static void jazz_sonic_platform_release (struct device *device) { struct platform_device *pldev; @@ -336,10 +297,11 @@ static void jazz_sonic_platform_release (struct device *device) static int __init jazz_sonic_init_module(void) { struct platform_device *pldev; + int err; - if (driver_register(&jazz_sonic_driver)) { + if ((err = driver_register(&jazz_sonic_driver))) { printk(KERN_ERR "Driver registration failed\n"); - return -ENOMEM; + return err; } jazz_sonic_device = NULL; diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 1f61f0cc95d..690a1aae0b3 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -68,6 +68,7 @@ static DEFINE_PER_CPU(struct net_device_stats, loopback_stats); * of largesending device modulo TCP checksum, which is ignored for loopback. */ +#ifdef LOOPBACK_TSO static void emulate_large_send_offload(struct sk_buff *skb) { struct iphdr *iph = skb->nh.iph; @@ -119,6 +120,7 @@ static void emulate_large_send_offload(struct sk_buff *skb) dev_kfree_skb(skb); } +#endif /* LOOPBACK_TSO */ /* * The higher levels take care of making this non-reentrant (it's @@ -130,12 +132,13 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) skb_orphan(skb); - skb->protocol=eth_type_trans(skb,dev); - skb->dev=dev; + skb->protocol = eth_type_trans(skb,dev); + skb->dev = dev; #ifndef LOOPBACK_MUST_CHECKSUM skb->ip_summed = CHECKSUM_UNNECESSARY; #endif +#ifdef LOOPBACK_TSO if (skb_shinfo(skb)->tso_size) { BUG_ON(skb->protocol != htons(ETH_P_IP)); BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP); @@ -143,14 +146,14 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) emulate_large_send_offload(skb); return 0; } - +#endif dev->last_rx = jiffies; lb_stats = &per_cpu(loopback_stats, get_cpu()); lb_stats->rx_bytes += skb->len; - lb_stats->tx_bytes += skb->len; + lb_stats->tx_bytes = lb_stats->rx_bytes; lb_stats->rx_packets++; - lb_stats->tx_packets++; + lb_stats->tx_packets = lb_stats->rx_packets; put_cpu(); netif_rx(skb); @@ -208,9 +211,12 @@ struct net_device loopback_dev = { .type = ARPHRD_LOOPBACK, /* 0x0001*/ .rebuild_header = eth_rebuild_header, .flags = IFF_LOOPBACK, - .features = NETIF_F_SG|NETIF_F_FRAGLIST - |NETIF_F_NO_CSUM|NETIF_F_HIGHDMA - |NETIF_F_LLTX, + .features = NETIF_F_SG | NETIF_F_FRAGLIST +#ifdef LOOPBACK_TSO + | NETIF_F_TSO +#endif + | NETIF_F_NO_CSUM | NETIF_F_HIGHDMA + | NETIF_F_LLTX, .ethtool_ops = &loopback_ethtool_ops, }; diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index be28c65de72..405e18365ed 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -1,6 +1,12 @@ /* * macsonic.c * + * (C) 2005 Finn Thain + * + * Converted to DMA API, converted to unified driver model, made it work as + * a module again, and from the mac68k project, introduced more 32-bit cards + * and dhd's support for 16-bit cards. + * * (C) 1998 Alan Cox * * Debugging Andreas Ehliar, Michael Schmitz @@ -26,8 +32,8 @@ */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/types.h> -#include <linux/ctype.h> #include <linux/fcntl.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -41,8 +47,8 @@ #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/skbuff.h> -#include <linux/module.h> -#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> #include <asm/bootinfo.h> #include <asm/system.h> @@ -54,25 +60,28 @@ #include <asm/macints.h> #include <asm/mac_via.h> -#define SREGS_PAD(n) u16 n; +static char mac_sonic_string[] = "macsonic"; +static struct platform_device *mac_sonic_device; #include "sonic.h" -#define SONIC_READ(reg) \ - nubus_readl(base_addr+(reg)) -#define SONIC_WRITE(reg,val) \ - nubus_writel((val), base_addr+(reg)) -#define sonic_read(dev, reg) \ - nubus_readl((dev)->base_addr+(reg)) -#define sonic_write(dev, reg, val) \ - nubus_writel((val), (dev)->base_addr+(reg)) - +/* These should basically be bus-size and endian independent (since + the SONIC is at least smart enough that it uses the same endianness + as the host, unlike certain less enlightened Macintosh NICs) */ +#define SONIC_READ(reg) (nubus_readw(dev->base_addr + (reg * 4) \ + + lp->reg_offset)) +#define SONIC_WRITE(reg,val) (nubus_writew(val, dev->base_addr + (reg * 4) \ + + lp->reg_offset)) + +/* use 0 for production, 1 for verification, >1 for debug */ +#ifdef SONIC_DEBUG +static unsigned int sonic_debug = SONIC_DEBUG; +#else +static unsigned int sonic_debug = 1; +#endif -static int sonic_debug; static int sonic_version_printed; -static int reg_offset; - extern int mac_onboard_sonic_probe(struct net_device* dev); extern int mac_nubus_sonic_probe(struct net_device* dev); @@ -108,40 +117,6 @@ enum macsonic_type { #define SONIC_READ_PROM(addr) nubus_readb(prom_addr+addr) -struct net_device * __init macsonic_probe(int unit) -{ - struct net_device *dev = alloc_etherdev(0); - int err; - - if (!dev) - return ERR_PTR(-ENOMEM); - - if (unit >= 0) - sprintf(dev->name, "eth%d", unit); - - SET_MODULE_OWNER(dev); - - /* This will catch fatal stuff like -ENOMEM as well as success */ - err = mac_onboard_sonic_probe(dev); - if (err == 0) - goto found; - if (err != -ENODEV) - goto out; - err = mac_nubus_sonic_probe(dev); - if (err) - goto out; -found: - err = register_netdev(dev); - if (err) - goto out1; - return dev; -out1: - kfree(dev->priv); -out: - free_netdev(dev); - return ERR_PTR(err); -} - /* * For reversing the PROM address */ @@ -160,103 +135,55 @@ static inline void bit_reverse_addr(unsigned char addr[6]) int __init macsonic_init(struct net_device* dev) { - struct sonic_local* lp = NULL; - int i; + struct sonic_local* lp = netdev_priv(dev); /* Allocate the entire chunk of memory for the descriptors. Note that this cannot cross a 64K boundary. */ - for (i = 0; i < 20; i++) { - unsigned long desc_base, desc_top; - if((lp = kmalloc(sizeof(struct sonic_local), GFP_KERNEL | GFP_DMA)) == NULL) { - printk(KERN_ERR "%s: couldn't allocate descriptor buffers\n", dev->name); - return -ENOMEM; - } - - desc_base = (unsigned long) lp; - desc_top = desc_base + sizeof(struct sonic_local); - if ((desc_top & 0xffff) >= (desc_base & 0xffff)) - break; - /* Hmm. try again (FIXME: does this actually work?) */ - kfree(lp); - printk(KERN_DEBUG - "%s: didn't get continguous chunk [%08lx - %08lx], trying again\n", - dev->name, desc_base, desc_top); - } - - if (lp == NULL) { - printk(KERN_ERR "%s: tried 20 times to allocate descriptor buffers, giving up.\n", - dev->name); + if ((lp->descriptors = dma_alloc_coherent(lp->device, + SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), + &lp->descriptors_laddr, GFP_KERNEL)) == NULL) { + printk(KERN_ERR "%s: couldn't alloc DMA memory for descriptors.\n", lp->device->bus_id); return -ENOMEM; - } - - dev->priv = lp; - -#if 0 - /* this code is only here as a curiousity... mainly, where the - fuck did SONIC_BUS_SCALE come from, and what was it supposed - to do? the normal allocation works great for 32 bit stuffs.. */ + } /* Now set up the pointers to point to the appropriate places */ - lp->cda = lp->sonic_desc; - lp->tda = lp->cda + (SIZEOF_SONIC_CDA * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->cda = lp->descriptors; + lp->tda = lp->cda + (SIZEOF_SONIC_CDA + * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rda = lp->tda + (SIZEOF_SONIC_TD * SONIC_NUM_TDS - * SONIC_BUS_SCALE(lp->dma_bitmode)); + * SONIC_BUS_SCALE(lp->dma_bitmode)); lp->rra = lp->rda + (SIZEOF_SONIC_RD * SONIC_NUM_RDS - * SONIC_BUS_SCALE(lp->dma_bitmode)); + * SONIC_BUS_SCALE(lp->dma_bitmode)); -#endif - - memset(lp, 0, sizeof(struct sonic_local)); - - lp->cda_laddr = (unsigned int)&(lp->cda); - lp->tda_laddr = (unsigned int)lp->tda; - lp->rra_laddr = (unsigned int)lp->rra; - lp->rda_laddr = (unsigned int)lp->rda; - - /* FIXME, maybe we should use skbs */ - if ((lp->rba = (char *) - kmalloc(SONIC_NUM_RRS * SONIC_RBSIZE, GFP_KERNEL | GFP_DMA)) == NULL) { - printk(KERN_ERR "%s: couldn't allocate receive buffers\n", dev->name); - dev->priv = NULL; - kfree(lp); - return -ENOMEM; - } - - lp->rba_laddr = (unsigned int)lp->rba; - - { - int rs, ds; - - /* almost always 12*4096, but let's not take chances */ - rs = ((SONIC_NUM_RRS * SONIC_RBSIZE + 4095) / 4096) * 4096; - /* almost always under a page, but let's not take chances */ - ds = ((sizeof(struct sonic_local) + 4095) / 4096) * 4096; - kernel_set_cachemode(lp->rba, rs, IOMAP_NOCACHE_SER); - kernel_set_cachemode(lp, ds, IOMAP_NOCACHE_SER); - } - -#if 0 - flush_cache_all(); -#endif + lp->cda_laddr = lp->descriptors_laddr; + lp->tda_laddr = lp->cda_laddr + (SIZEOF_SONIC_CDA + * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->rda_laddr = lp->tda_laddr + (SIZEOF_SONIC_TD * SONIC_NUM_TDS + * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS + * SONIC_BUS_SCALE(lp->dma_bitmode)); dev->open = sonic_open; dev->stop = sonic_close; dev->hard_start_xmit = sonic_send_packet; dev->get_stats = sonic_get_stats; dev->set_multicast_list = &sonic_multicast_list; + dev->tx_timeout = sonic_tx_timeout; + dev->watchdog_timeo = TX_TIMEOUT; /* * clear tally counter */ - sonic_write(dev, SONIC_CRCT, 0xffff); - sonic_write(dev, SONIC_FAET, 0xffff); - sonic_write(dev, SONIC_MPT, 0xffff); + SONIC_WRITE(SONIC_CRCT, 0xffff); + SONIC_WRITE(SONIC_FAET, 0xffff); + SONIC_WRITE(SONIC_MPT, 0xffff); return 0; } int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev) { + struct sonic_local *lp = netdev_priv(dev); const int prom_addr = ONBOARD_SONIC_PROM_BASE; int i; @@ -270,6 +197,7 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev) why this is so. */ if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && memcmp(dev->dev_addr, "\x00\xA0\x40", 3) && + memcmp(dev->dev_addr, "\x00\x80\x19", 3) && memcmp(dev->dev_addr, "\x00\x05\x02", 3)) bit_reverse_addr(dev->dev_addr); else @@ -281,22 +209,23 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev) the card... */ if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && memcmp(dev->dev_addr, "\x00\xA0\x40", 3) && + memcmp(dev->dev_addr, "\x00\x80\x19", 3) && memcmp(dev->dev_addr, "\x00\x05\x02", 3)) { unsigned short val; printk(KERN_INFO "macsonic: PROM seems to be wrong, trying CAM entry 15\n"); - sonic_write(dev, SONIC_CMD, SONIC_CR_RST); - sonic_write(dev, SONIC_CEP, 15); + SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); + SONIC_WRITE(SONIC_CEP, 15); - val = sonic_read(dev, SONIC_CAP2); + val = SONIC_READ(SONIC_CAP2); dev->dev_addr[5] = val >> 8; dev->dev_addr[4] = val & 0xff; - val = sonic_read(dev, SONIC_CAP1); + val = SONIC_READ(SONIC_CAP1); dev->dev_addr[3] = val >> 8; dev->dev_addr[2] = val & 0xff; - val = sonic_read(dev, SONIC_CAP0); + val = SONIC_READ(SONIC_CAP0); dev->dev_addr[1] = val >> 8; dev->dev_addr[0] = val & 0xff; @@ -311,6 +240,7 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev) if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && memcmp(dev->dev_addr, "\x00\xA0\x40", 3) && + memcmp(dev->dev_addr, "\x00\x80\x19", 3) && memcmp(dev->dev_addr, "\x00\x05\x02", 3)) { /* @@ -325,8 +255,9 @@ int __init mac_onboard_sonic_probe(struct net_device* dev) { /* Bwahahaha */ static int once_is_more_than_enough; - int i; - int dma_bitmode; + struct sonic_local* lp = netdev_priv(dev); + int sr; + int commslot = 0; if (once_is_more_than_enough) return -ENODEV; @@ -335,20 +266,18 @@ int __init mac_onboard_sonic_probe(struct net_device* dev) if (!MACH_IS_MAC) return -ENODEV; - printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. "); - if (macintosh_config->ether_type != MAC_ETHER_SONIC) - { - printk("none.\n"); return -ENODEV; - } - + + printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. "); + /* Bogus probing, on the models which may or may not have Ethernet (BTW, the Ethernet *is* always at the same address, and nothing else lives there, at least if Apple's documentation is to be believed) */ if (macintosh_config->ident == MAC_MODEL_Q630 || macintosh_config->ident == MAC_MODEL_P588 || + macintosh_config->ident == MAC_MODEL_P575 || macintosh_config->ident == MAC_MODEL_C610) { unsigned long flags; int card_present; @@ -361,13 +290,13 @@ int __init mac_onboard_sonic_probe(struct net_device* dev) printk("none.\n"); return -ENODEV; } + commslot = 1; } printk("yes\n"); - /* Danger! My arms are flailing wildly! You *must* set this - before using sonic_read() */ - + /* Danger! My arms are flailing wildly! You *must* set lp->reg_offset + * and dev->base_addr before using SONIC_READ() or SONIC_WRITE() */ dev->base_addr = ONBOARD_SONIC_REGISTERS; if (via_alt_mapping) dev->irq = IRQ_AUTO_3; @@ -379,84 +308,66 @@ int __init mac_onboard_sonic_probe(struct net_device* dev) sonic_version_printed = 1; } printk(KERN_INFO "%s: onboard / comm-slot SONIC at 0x%08lx\n", - dev->name, dev->base_addr); - - /* Now do a song and dance routine in an attempt to determine - the bus width */ + lp->device->bus_id, dev->base_addr); /* The PowerBook's SONIC is 16 bit always. */ if (macintosh_config->ident == MAC_MODEL_PB520) { - reg_offset = 0; - dma_bitmode = 0; - } else if (macintosh_config->ident == MAC_MODEL_C610) { - reg_offset = 0; - dma_bitmode = 1; - } else { + lp->reg_offset = 0; + lp->dma_bitmode = SONIC_BITMODE16; + sr = SONIC_READ(SONIC_SR); + } else if (commslot) { /* Some of the comm-slot cards are 16 bit. But some - of them are not. The 32-bit cards use offset 2 and - pad with zeroes or sometimes ones (I think...) - Therefore, if we try offset 0 and get a silicon - revision of 0, we assume 16 bit. */ - int sr; - - /* Technically this is not necessary since we zeroed - it above */ - reg_offset = 0; - dma_bitmode = 0; - sr = sonic_read(dev, SONIC_SR); - if (sr == 0 || sr == 0xffff) { - reg_offset = 2; - /* 83932 is 0x0004, 83934 is 0x0100 or 0x0101 */ - sr = sonic_read(dev, SONIC_SR); - dma_bitmode = 1; - + of them are not. The 32-bit cards use offset 2 and + have known revisions, we try reading the revision + register at offset 2, if we don't get a known revision + we assume 16 bit at offset 0. */ + lp->reg_offset = 2; + lp->dma_bitmode = SONIC_BITMODE16; + + sr = SONIC_READ(SONIC_SR); + if (sr == 0x0004 || sr == 0x0006 || sr == 0x0100 || sr == 0x0101) + /* 83932 is 0x0004 or 0x0006, 83934 is 0x0100 or 0x0101 */ + lp->dma_bitmode = SONIC_BITMODE32; + else { + lp->dma_bitmode = SONIC_BITMODE16; + lp->reg_offset = 0; + sr = SONIC_READ(SONIC_SR); } - printk(KERN_INFO - "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", - dev->name, sr, dma_bitmode?32:16, reg_offset); + } else { + /* All onboard cards are at offset 2 with 32 bit DMA. */ + lp->reg_offset = 2; + lp->dma_bitmode = SONIC_BITMODE32; + sr = SONIC_READ(SONIC_SR); } - + printk(KERN_INFO + "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", + lp->device->bus_id, sr, lp->dma_bitmode?32:16, lp->reg_offset); - /* this carries my sincere apologies -- by the time I got to updating - the driver, support for "reg_offsets" appeares nowhere in the sonic - code, going back for over a year. Fortunately, my Mac does't seem - to use whatever this was. +#if 0 /* This is sometimes useful to find out how MacOS configured the card. */ + printk(KERN_INFO "%s: DCR: 0x%04x, DCR2: 0x%04x\n", lp->device->bus_id, + SONIC_READ(SONIC_DCR) & 0xffff, SONIC_READ(SONIC_DCR2) & 0xffff); +#endif - If you know how this is supposed to be implemented, either fix it, - or contact me (sammy@oh.verio.com) to explain what it is. --Sam */ - - if(reg_offset) { - printk("%s: register offset unsupported. please fix this if you know what it is.\n", dev->name); - return -ENODEV; - } - /* Software reset, then initialize control registers. */ - sonic_write(dev, SONIC_CMD, SONIC_CR_RST); - sonic_write(dev, SONIC_DCR, SONIC_DCR_BMS | - SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_EXBUS | - (dma_bitmode ? SONIC_DCR_DW : 0)); + SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); + + SONIC_WRITE(SONIC_DCR, SONIC_DCR_EXBUS | SONIC_DCR_BMS | + SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | + (lp->dma_bitmode ? SONIC_DCR_DW : 0)); /* This *must* be written back to in order to restore the - extended programmable output bits */ - sonic_write(dev, SONIC_DCR2, 0); + * extended programmable output bits, as it may not have been + * initialised since the hardware reset. */ + SONIC_WRITE(SONIC_DCR2, 0); /* Clear *and* disable interrupts to be on the safe side */ - sonic_write(dev, SONIC_ISR,0x7fff); - sonic_write(dev, SONIC_IMR,0); + SONIC_WRITE(SONIC_IMR, 0); + SONIC_WRITE(SONIC_ISR, 0x7fff); /* Now look for the MAC address. */ if (mac_onboard_sonic_ethernet_addr(dev) != 0) return -ENODEV; - printk(KERN_INFO "MAC "); - for (i = 0; i < 6; i++) { - printk("%2.2x", dev->dev_addr[i]); - if (i < 5) - printk(":"); - } - - printk(" IRQ %d\n", dev->irq); - /* Shared init code */ return macsonic_init(dev); } @@ -468,8 +379,10 @@ int __init mac_nubus_sonic_ethernet_addr(struct net_device* dev, int i; for(i = 0; i < 6; i++) dev->dev_addr[i] = SONIC_READ_PROM(i); - /* For now we are going to assume that they're all bit-reversed */ - bit_reverse_addr(dev->dev_addr); + + /* Some of the addresses are bit-reversed */ + if (id != MACSONIC_DAYNA) + bit_reverse_addr(dev->dev_addr); return 0; } @@ -487,6 +400,15 @@ int __init macsonic_ident(struct nubus_dev* ndev) else return MACSONIC_APPLE; } + + if (ndev->dr_hw == NUBUS_DRHW_SMC9194 && + ndev->dr_sw == NUBUS_DRSW_DAYNA) + return MACSONIC_DAYNA; + + if (ndev->dr_hw == NUBUS_DRHW_SONIC_LC && + ndev->dr_sw == 0) { /* huh? */ + return MACSONIC_APPLE16; + } return -1; } @@ -494,12 +416,12 @@ int __init mac_nubus_sonic_probe(struct net_device* dev) { static int slots; struct nubus_dev* ndev = NULL; + struct sonic_local* lp = netdev_priv(dev); unsigned long base_addr, prom_addr; u16 sonic_dcr; - int id; - int i; - int dma_bitmode; - + int id = -1; + int reg_offset, dma_bitmode; + /* Find the first SONIC that hasn't been initialized already */ while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK, NUBUS_TYPE_ETHERNET, ndev)) != NULL) @@ -521,51 +443,52 @@ int __init mac_nubus_sonic_probe(struct net_device* dev) case MACSONIC_DUODOCK: base_addr = ndev->board->slot_addr + DUODOCK_SONIC_REGISTERS; prom_addr = ndev->board->slot_addr + DUODOCK_SONIC_PROM_BASE; - sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT0 | SONIC_DCR_RFT1 - | SONIC_DCR_TFT0; + sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT0 | SONIC_DCR_RFT1 | + SONIC_DCR_TFT0; reg_offset = 2; - dma_bitmode = 1; + dma_bitmode = SONIC_BITMODE32; break; case MACSONIC_APPLE: base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE; sonic_dcr = SONIC_DCR_BMS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0; reg_offset = 0; - dma_bitmode = 1; + dma_bitmode = SONIC_BITMODE32; break; case MACSONIC_APPLE16: base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE; - sonic_dcr = SONIC_DCR_EXBUS - | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 - | SONIC_DCR_PO1 | SONIC_DCR_BMS; + sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | + SONIC_DCR_PO1 | SONIC_DCR_BMS; reg_offset = 0; - dma_bitmode = 0; + dma_bitmode = SONIC_BITMODE16; break; case MACSONIC_DAYNALINK: base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS; prom_addr = ndev->board->slot_addr + DAYNALINK_PROM_BASE; - sonic_dcr = SONIC_DCR_RFT1 | SONIC_DCR_TFT0 - | SONIC_DCR_PO1 | SONIC_DCR_BMS; + sonic_dcr = SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | + SONIC_DCR_PO1 | SONIC_DCR_BMS; reg_offset = 0; - dma_bitmode = 0; + dma_bitmode = SONIC_BITMODE16; break; case MACSONIC_DAYNA: base_addr = ndev->board->slot_addr + DAYNA_SONIC_REGISTERS; prom_addr = ndev->board->slot_addr + DAYNA_SONIC_MAC_ADDR; - sonic_dcr = SONIC_DCR_BMS - | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1; + sonic_dcr = SONIC_DCR_BMS | + SONIC_DCR_RFT1 | SONIC_DCR_TFT0 | SONIC_DCR_PO1; reg_offset = 0; - dma_bitmode = 0; + dma_bitmode = SONIC_BITMODE16; break; default: printk(KERN_ERR "macsonic: WTF, id is %d\n", id); return -ENODEV; } - /* Danger! My arms are flailing wildly! You *must* set this - before using sonic_read() */ + /* Danger! My arms are flailing wildly! You *must* set lp->reg_offset + * and dev->base_addr before using SONIC_READ() or SONIC_WRITE() */ dev->base_addr = base_addr; + lp->reg_offset = reg_offset; + lp->dma_bitmode = dma_bitmode; dev->irq = SLOT2IRQ(ndev->board->slot); if (!sonic_version_printed) { @@ -573,29 +496,66 @@ int __init mac_nubus_sonic_probe(struct net_device* dev) sonic_version_printed = 1; } printk(KERN_INFO "%s: %s in slot %X\n", - dev->name, ndev->board->name, ndev->board->slot); + lp->device->bus_id, ndev->board->name, ndev->board->slot); printk(KERN_INFO "%s: revision 0x%04x, using %d bit DMA and register offset %d\n", - dev->name, sonic_read(dev, SONIC_SR), dma_bitmode?32:16, reg_offset); + lp->device->bus_id, SONIC_READ(SONIC_SR), dma_bitmode?32:16, reg_offset); - if(reg_offset) { - printk("%s: register offset unsupported. please fix this if you know what it is.\n", dev->name); - return -ENODEV; - } +#if 0 /* This is sometimes useful to find out how MacOS configured the card. */ + printk(KERN_INFO "%s: DCR: 0x%04x, DCR2: 0x%04x\n", lp->device->bus_id, + SONIC_READ(SONIC_DCR) & 0xffff, SONIC_READ(SONIC_DCR2) & 0xffff); +#endif /* Software reset, then initialize control registers. */ - sonic_write(dev, SONIC_CMD, SONIC_CR_RST); - sonic_write(dev, SONIC_DCR, sonic_dcr - | (dma_bitmode ? SONIC_DCR_DW : 0)); + SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); + SONIC_WRITE(SONIC_DCR, sonic_dcr | (dma_bitmode ? SONIC_DCR_DW : 0)); + /* This *must* be written back to in order to restore the + * extended programmable output bits, since it may not have been + * initialised since the hardware reset. */ + SONIC_WRITE(SONIC_DCR2, 0); /* Clear *and* disable interrupts to be on the safe side */ - sonic_write(dev, SONIC_ISR,0x7fff); - sonic_write(dev, SONIC_IMR,0); + SONIC_WRITE(SONIC_IMR, 0); + SONIC_WRITE(SONIC_ISR, 0x7fff); /* Now look for the MAC address. */ if (mac_nubus_sonic_ethernet_addr(dev, prom_addr, id) != 0) return -ENODEV; - printk(KERN_INFO "MAC "); + /* Shared init code */ + return macsonic_init(dev); +} + +static int __init mac_sonic_probe(struct device *device) +{ + struct net_device *dev; + struct sonic_local *lp; + int err; + int i; + + dev = alloc_etherdev(sizeof(struct sonic_local)); + if (!dev) + return -ENOMEM; + + lp = netdev_priv(dev); + lp->device = device; + SET_NETDEV_DEV(dev, device); + SET_MODULE_OWNER(dev); + + /* This will catch fatal stuff like -ENOMEM as well as success */ + err = mac_onboard_sonic_probe(dev); + if (err == 0) + goto found; + if (err != -ENODEV) + goto out; + err = mac_nubus_sonic_probe(dev); + if (err) + goto out; +found: + err = register_netdev(dev); + if (err) + goto out; + + printk("%s: MAC ", dev->name); for (i = 0; i < 6; i++) { printk("%2.2x", dev->dev_addr[i]); if (i < 5) @@ -603,55 +563,95 @@ int __init mac_nubus_sonic_probe(struct net_device* dev) } printk(" IRQ %d\n", dev->irq); - /* Shared init code */ - return macsonic_init(dev); -} + return 0; -#ifdef MODULE -static struct net_device *dev_macsonic; +out: + free_netdev(dev); -MODULE_PARM(sonic_debug, "i"); + return err; +} + +MODULE_DESCRIPTION("Macintosh SONIC ethernet driver"); +module_param(sonic_debug, int, 0); MODULE_PARM_DESC(sonic_debug, "macsonic debug level (1-4)"); -int -init_module(void) +#define SONIC_IRQ_FLAG IRQ_FLG_FAST + +#include "sonic.c" + +static int __devexit mac_sonic_device_remove (struct device *device) { - dev_macsonic = macsonic_probe(-1); - if (IS_ERR(dev_macsonic)) { - printk(KERN_WARNING "macsonic.c: No card found\n"); - return PTR_ERR(dev_macsonic); - } + struct net_device *dev = device->driver_data; + struct sonic_local* lp = netdev_priv(dev); + + unregister_netdev (dev); + dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), + lp->descriptors, lp->descriptors_laddr); + free_netdev (dev); + return 0; } -void -cleanup_module(void) +static struct device_driver mac_sonic_driver = { + .name = mac_sonic_string, + .bus = &platform_bus_type, + .probe = mac_sonic_probe, + .remove = __devexit_p(mac_sonic_device_remove), +}; + +static void mac_sonic_platform_release(struct device *device) { - unregister_netdev(dev_macsonic); - kfree(dev_macsonic->priv); - free_netdev(dev_macsonic); + struct platform_device *pldev; + + /* free device */ + pldev = to_platform_device (device); + kfree (pldev); } -#endif /* MODULE */ +static int __init mac_sonic_init_module(void) +{ + struct platform_device *pldev; + int err; -#define vdma_alloc(foo, bar) ((u32)foo) -#define vdma_free(baz) -#define sonic_chiptomem(bat) (bat) -#define PHYSADDR(quux) (quux) -#define CPHYSADDR(quux) (quux) + if ((err = driver_register(&mac_sonic_driver))) { + printk(KERN_ERR "Driver registration failed\n"); + return err; + } -#define sonic_request_irq request_irq -#define sonic_free_irq free_irq + mac_sonic_device = NULL; -#include "sonic.c" + if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) { + goto out_unregister; + } -/* - * Local variables: - * compile-command: "m68k-linux-gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c -o macsonic.o macsonic.c" - * version-control: t - * kept-new-versions: 5 - * c-indent-level: 8 - * tab-width: 8 - * End: - * - */ + memset(pldev, 0, sizeof (*pldev)); + pldev->name = mac_sonic_string; + pldev->id = 0; + pldev->dev.release = mac_sonic_platform_release; + mac_sonic_device = pldev; + + if (platform_device_register (pldev)) { + kfree(pldev); + mac_sonic_device = NULL; + } + + return 0; + +out_unregister: + platform_device_unregister(pldev); + + return -ENOMEM; +} + +static void __exit mac_sonic_cleanup_module(void) +{ + driver_unregister(&mac_sonic_driver); + + if (mac_sonic_device) { + platform_device_unregister(mac_sonic_device); + mac_sonic_device = NULL; + } +} + +module_init(mac_sonic_init_module); +module_exit(mac_sonic_cleanup_module); diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 0405e1f0d3d..fb6b232069d 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1157,16 +1157,20 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) if (!skb_shinfo(skb)->nr_frags) { linear: if (skb->ip_summed != CHECKSUM_HW) { + /* Errata BTS #50, IHL must be 5 if no HW checksum */ pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | - ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC; + ETH_TX_FIRST_DESC | + ETH_TX_LAST_DESC | + 5 << ETH_TX_IHL_SHIFT; pkt_info.l4i_chk = 0; } else { - u32 ipheader = skb->nh.iph->ihl << 11; pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | - ETH_TX_FIRST_DESC | ETH_TX_LAST_DESC | - ETH_GEN_TCP_UDP_CHECKSUM | - ETH_GEN_IP_V_4_CHECKSUM | ipheader; + ETH_TX_FIRST_DESC | + ETH_TX_LAST_DESC | + ETH_GEN_TCP_UDP_CHECKSUM | + ETH_GEN_IP_V_4_CHECKSUM | + skb->nh.iph->ihl << ETH_TX_IHL_SHIFT; /* CPU already calculated pseudo header checksum. */ if (skb->nh.iph->protocol == IPPROTO_UDP) { pkt_info.cmd_sts |= ETH_UDP_FRAME; @@ -1193,7 +1197,6 @@ linear: stats->tx_bytes += pkt_info.byte_cnt; } else { unsigned int frag; - u32 ipheader; /* Since hardware can't handle unaligned fragments smaller * than 9 bytes, if we find any, we linearize the skb @@ -1222,12 +1225,16 @@ linear: DMA_TO_DEVICE); pkt_info.l4i_chk = 0; pkt_info.return_info = 0; - pkt_info.cmd_sts = ETH_TX_FIRST_DESC; - if (skb->ip_summed == CHECKSUM_HW) { - ipheader = skb->nh.iph->ihl << 11; - pkt_info.cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM | - ETH_GEN_IP_V_4_CHECKSUM | ipheader; + if (skb->ip_summed != CHECKSUM_HW) + /* Errata BTS #50, IHL must be 5 if no HW checksum */ + pkt_info.cmd_sts = ETH_TX_FIRST_DESC | + 5 << ETH_TX_IHL_SHIFT; + else { + pkt_info.cmd_sts = ETH_TX_FIRST_DESC | + ETH_GEN_TCP_UDP_CHECKSUM | + ETH_GEN_IP_V_4_CHECKSUM | + skb->nh.iph->ihl << ETH_TX_IHL_SHIFT; /* CPU already calculated pseudo header checksum. */ if (skb->nh.iph->protocol == IPPROTO_UDP) { pkt_info.cmd_sts |= ETH_UDP_FRAME; diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h index 57c4f8fbfdb..7678b59c295 100644 --- a/drivers/net/mv643xx_eth.h +++ b/drivers/net/mv643xx_eth.h @@ -49,7 +49,7 @@ /* Checksum offload for Tx works for most packets, but * fails if previous packet sent did not use hw csum */ -#undef MV643XX_CHECKSUM_OFFLOAD_TX +#define MV643XX_CHECKSUM_OFFLOAD_TX #define MV643XX_NAPI #define MV643XX_TX_FAST_REFILL #undef MV643XX_RX_QUEUE_FILL_ON_TASK /* Does not work, yet */ @@ -217,6 +217,8 @@ #define ETH_TX_ENABLE_INTERRUPT (BIT23) #define ETH_AUTO_MODE (BIT30) +#define ETH_TX_IHL_SHIFT 11 + /* typedefs */ typedef enum _eth_func_ret_status { diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 4a391ea0f58..a1ac4bd1696 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -486,9 +486,9 @@ struct netdrv_private { MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>"); MODULE_DESCRIPTION ("Skeleton for a PCI Fast Ethernet driver"); MODULE_LICENSE("GPL"); -MODULE_PARM (multicast_filter_limit, "i"); -MODULE_PARM (max_interrupt_work, "i"); -MODULE_PARM (media, "1-" __MODULE_STRING(8) "i"); +module_param(multicast_filter_limit, int, 0); +module_param(max_interrupt_work, int, 0); +module_param_array(media, int, NULL, 0); MODULE_PARM_DESC (multicast_filter_limit, "pci-skeleton maximum number of filtered multicast addresses"); MODULE_PARM_DESC (max_interrupt_work, "pci-skeleton maximum events handled per interrupt"); MODULE_PARM_DESC (media, "pci-skeleton: Bits 0-3: media type, bit 17: full duplex"); diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 9d8197bb293..384a736a0d2 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -134,7 +134,7 @@ typedef struct local_info_t { u_char mc_filter[8]; } local_info_t; -#define MC_FILTERBREAK 64 +#define MC_FILTERBREAK 8 /*====================================================================*/ /* @@ -1012,7 +1012,7 @@ static void fjn_reset(struct net_device *dev) outb(BANK_1U, ioaddr + CONFIG_1); /* set the multicast table to accept none. */ - for (i = 0; i < 6; i++) + for (i = 0; i < 8; i++) outb(0x00, ioaddr + MAR_ADR + i); /* Switch to bank 2 (runtime mode) */ @@ -1269,6 +1269,16 @@ static void set_rx_mode(struct net_device *dev) u_long flags; int i; + int saved_config_0 = inb(ioaddr + CONFIG_0); + + local_irq_save(flags); + + /* Disable Tx and Rx */ + if (sram_config == 0) + outb(CONFIG0_RST, ioaddr + CONFIG_0); + else + outb(CONFIG0_RST_1, ioaddr + CONFIG_0); + if (dev->flags & IFF_PROMISC) { /* Unconditionally log net taps. */ printk("%s: Promiscuous mode enabled.\n", dev->name); @@ -1290,20 +1300,23 @@ static void set_rx_mode(struct net_device *dev) for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; i++, mclist = mclist->next) { unsigned int bit = - ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f; - mc_filter[bit >> 3] |= (1 << bit); + ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 26; + mc_filter[bit >> 3] |= (1 << (bit & 7)); } + outb(2, ioaddr + RX_MODE); /* Use normal mode. */ } - local_irq_save(flags); if (memcmp(mc_filter, lp->mc_filter, sizeof(mc_filter))) { int saved_bank = inb(ioaddr + CONFIG_1); /* Switch to bank 1 and set the multicast table. */ outb(0xe4, ioaddr + CONFIG_1); for (i = 0; i < 8; i++) - outb(mc_filter[i], ioaddr + 8 + i); + outb(mc_filter[i], ioaddr + MAR_ADR + i); memcpy(lp->mc_filter, mc_filter, sizeof(mc_filter)); outb(saved_bank, ioaddr + CONFIG_1); } + + outb(saved_config_0, ioaddr + CONFIG_0); + local_irq_restore(flags); } diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig new file mode 100644 index 00000000000..6a2fe358347 --- /dev/null +++ b/drivers/net/phy/Kconfig @@ -0,0 +1,57 @@ +# +# PHY Layer Configuration +# + +menu "PHY device support" + +config PHYLIB + tristate "PHY Device support and infrastructure" + depends on NET_ETHERNET + help + Ethernet controllers are usually attached to PHY + devices. This option provides infrastructure for + managing PHY devices. + +config PHYCONTROL + bool " Support for automatically handling PHY state changes" + depends on PHYLIB + help + Adds code to perform all the work for keeping PHY link + state (speed/duplex/etc) up-to-date. Also handles + interrupts. + +comment "MII PHY device drivers" + depends on PHYLIB + +config MARVELL_PHY + tristate "Drivers for Marvell PHYs" + depends on PHYLIB + ---help--- + Currently has a driver for the 88E1011S + +config DAVICOM_PHY + tristate "Drivers for Davicom PHYs" + depends on PHYLIB + ---help--- + Currently supports dm9161e and dm9131 + +config QSEMI_PHY + tristate "Drivers for Quality Semiconductor PHYs" + depends on PHYLIB + ---help--- + Currently supports the qs6612 + +config LXT_PHY + tristate "Drivers for the Intel LXT PHYs" + depends on PHYLIB + ---help--- + Currently supports the lxt970, lxt971 + +config CICADA_PHY + tristate "Drivers for the Cicada PHYs" + depends on PHYLIB + ---help--- + Currently supports the cis8204 + +endmenu + diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile new file mode 100644 index 00000000000..e4116a5fbb4 --- /dev/null +++ b/drivers/net/phy/Makefile @@ -0,0 +1,10 @@ +# Makefile for Linux PHY drivers + +libphy-objs := phy.o phy_device.o mdio_bus.o + +obj-$(CONFIG_PHYLIB) += libphy.o +obj-$(CONFIG_MARVELL_PHY) += marvell.o +obj-$(CONFIG_DAVICOM_PHY) += davicom.o +obj-$(CONFIG_CICADA_PHY) += cicada.o +obj-$(CONFIG_LXT_PHY) += lxt.o +obj-$(CONFIG_QSEMI_PHY) += qsemi.o diff --git a/drivers/net/phy/cicada.c b/drivers/net/phy/cicada.c new file mode 100644 index 00000000000..c47fb2ecd14 --- /dev/null +++ b/drivers/net/phy/cicada.c @@ -0,0 +1,134 @@ +/* + * drivers/net/phy/cicada.c + * + * Driver for Cicada PHYs + * + * Author: Andy Fleming + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/phy.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +/* Cicada Extended Control Register 1 */ +#define MII_CIS8201_EXT_CON1 0x17 +#define MII_CIS8201_EXTCON1_INIT 0x0000 + +/* Cicada Interrupt Mask Register */ +#define MII_CIS8201_IMASK 0x19 +#define MII_CIS8201_IMASK_IEN 0x8000 +#define MII_CIS8201_IMASK_SPEED 0x4000 +#define MII_CIS8201_IMASK_LINK 0x2000 +#define MII_CIS8201_IMASK_DUPLEX 0x1000 +#define MII_CIS8201_IMASK_MASK 0xf000 + +/* Cicada Interrupt Status Register */ +#define MII_CIS8201_ISTAT 0x1a +#define MII_CIS8201_ISTAT_STATUS 0x8000 +#define MII_CIS8201_ISTAT_SPEED 0x4000 +#define MII_CIS8201_ISTAT_LINK 0x2000 +#define MII_CIS8201_ISTAT_DUPLEX 0x1000 + +/* Cicada Auxiliary Control/Status Register */ +#define MII_CIS8201_AUX_CONSTAT 0x1c +#define MII_CIS8201_AUXCONSTAT_INIT 0x0004 +#define MII_CIS8201_AUXCONSTAT_DUPLEX 0x0020 +#define MII_CIS8201_AUXCONSTAT_SPEED 0x0018 +#define MII_CIS8201_AUXCONSTAT_GBIT 0x0010 +#define MII_CIS8201_AUXCONSTAT_100 0x0008 + +MODULE_DESCRIPTION("Cicadia PHY driver"); +MODULE_AUTHOR("Andy Fleming"); +MODULE_LICENSE("GPL"); + +static int cis820x_config_init(struct phy_device *phydev) +{ + int err; + + err = phy_write(phydev, MII_CIS8201_AUX_CONSTAT, + MII_CIS8201_AUXCONSTAT_INIT); + + if (err < 0) + return err; + + err = phy_write(phydev, MII_CIS8201_EXT_CON1, + MII_CIS8201_EXTCON1_INIT); + + return err; +} + +static int cis820x_ack_interrupt(struct phy_device *phydev) +{ + int err = phy_read(phydev, MII_CIS8201_ISTAT); + + return (err < 0) ? err : 0; +} + +static int cis820x_config_intr(struct phy_device *phydev) +{ + int err; + + if(phydev->interrupts == PHY_INTERRUPT_ENABLED) + err = phy_write(phydev, MII_CIS8201_IMASK, + MII_CIS8201_IMASK_MASK); + else + err = phy_write(phydev, MII_CIS8201_IMASK, 0); + + return err; +} + +/* Cicada 820x */ +static struct phy_driver cis8204_driver = { + .phy_id = 0x000fc440, + .name = "Cicada Cis8204", + .phy_id_mask = 0x000fffc0, + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_init = &cis820x_config_init, + .config_aneg = &genphy_config_aneg, + .read_status = &genphy_read_status, + .ack_interrupt = &cis820x_ack_interrupt, + .config_intr = &cis820x_config_intr, + .driver = { .owner = THIS_MODULE,}, +}; + +static int __init cis8204_init(void) +{ + return phy_driver_register(&cis8204_driver); +} + +static void __exit cis8204_exit(void) +{ + phy_driver_unregister(&cis8204_driver); +} + +module_init(cis8204_init); +module_exit(cis8204_exit); diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c new file mode 100644 index 00000000000..6caf499fae3 --- /dev/null +++ b/drivers/net/phy/davicom.c @@ -0,0 +1,195 @@ +/* + * drivers/net/phy/davicom.c + * + * Driver for Davicom PHYs + * + * Author: Andy Fleming + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/phy.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +#define MII_DM9161_SCR 0x10 +#define MII_DM9161_SCR_INIT 0x0610 + +/* DM9161 Interrupt Register */ +#define MII_DM9161_INTR 0x15 +#define MII_DM9161_INTR_PEND 0x8000 +#define MII_DM9161_INTR_DPLX_MASK 0x0800 +#define MII_DM9161_INTR_SPD_MASK 0x0400 +#define MII_DM9161_INTR_LINK_MASK 0x0200 +#define MII_DM9161_INTR_MASK 0x0100 +#define MII_DM9161_INTR_DPLX_CHANGE 0x0010 +#define MII_DM9161_INTR_SPD_CHANGE 0x0008 +#define MII_DM9161_INTR_LINK_CHANGE 0x0004 +#define MII_DM9161_INTR_INIT 0x0000 +#define MII_DM9161_INTR_STOP \ +(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \ + | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK) + +/* DM9161 10BT Configuration/Status */ +#define MII_DM9161_10BTCSR 0x12 +#define MII_DM9161_10BTCSR_INIT 0x7800 + +MODULE_DESCRIPTION("Davicom PHY driver"); +MODULE_AUTHOR("Andy Fleming"); +MODULE_LICENSE("GPL"); + + +#define DM9161_DELAY 1 +static int dm9161_config_intr(struct phy_device *phydev) +{ + int temp; + + temp = phy_read(phydev, MII_DM9161_INTR); + + if (temp < 0) + return temp; + + if(PHY_INTERRUPT_ENABLED == phydev->interrupts ) + temp &= ~(MII_DM9161_INTR_STOP); + else + temp |= MII_DM9161_INTR_STOP; + + temp = phy_write(phydev, MII_DM9161_INTR, temp); + + return temp; +} + +static int dm9161_config_aneg(struct phy_device *phydev) +{ + int err; + + /* Isolate the PHY */ + err = phy_write(phydev, MII_BMCR, BMCR_ISOLATE); + + if (err < 0) + return err; + + /* Configure the new settings */ + err = genphy_config_aneg(phydev); + + if (err < 0) + return err; + + return 0; +} + +static int dm9161_config_init(struct phy_device *phydev) +{ + int err; + + /* Isolate the PHY */ + err = phy_write(phydev, MII_BMCR, BMCR_ISOLATE); + + if (err < 0) + return err; + + /* Do not bypass the scrambler/descrambler */ + err = phy_write(phydev, MII_DM9161_SCR, MII_DM9161_SCR_INIT); + + if (err < 0) + return err; + + /* Clear 10BTCSR to default */ + err = phy_write(phydev, MII_DM9161_10BTCSR, MII_DM9161_10BTCSR_INIT); + + if (err < 0) + return err; + + /* Reconnect the PHY, and enable Autonegotiation */ + err = phy_write(phydev, MII_BMCR, BMCR_ANENABLE); + + if (err < 0) + return err; + + return 0; +} + +static int dm9161_ack_interrupt(struct phy_device *phydev) +{ + int err = phy_read(phydev, MII_DM9161_INTR); + + return (err < 0) ? err : 0; +} + +static struct phy_driver dm9161_driver = { + .phy_id = 0x0181b880, + .name = "Davicom DM9161E", + .phy_id_mask = 0x0ffffff0, + .features = PHY_BASIC_FEATURES, + .config_init = dm9161_config_init, + .config_aneg = dm9161_config_aneg, + .read_status = genphy_read_status, + .driver = { .owner = THIS_MODULE,}, +}; + +static struct phy_driver dm9131_driver = { + .phy_id = 0x00181b80, + .name = "Davicom DM9131", + .phy_id_mask = 0x0ffffff0, + .features = PHY_BASIC_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = dm9161_ack_interrupt, + .config_intr = dm9161_config_intr, + .driver = { .owner = THIS_MODULE,}, +}; + +static int __init davicom_init(void) +{ + int ret; + + ret = phy_driver_register(&dm9161_driver); + if (ret) + goto err1; + + ret = phy_driver_register(&dm9131_driver); + if (ret) + goto err2; + return 0; + + err2: + phy_driver_unregister(&dm9161_driver); + err1: + return ret; +} + +static void __exit davicom_exit(void) +{ + phy_driver_unregister(&dm9161_driver); + phy_driver_unregister(&dm9131_driver); +} + +module_init(davicom_init); +module_exit(davicom_exit); diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c new file mode 100644 index 00000000000..4c840448ec8 --- /dev/null +++ b/drivers/net/phy/lxt.c @@ -0,0 +1,179 @@ +/* + * drivers/net/phy/lxt.c + * + * Driver for Intel LXT PHYs + * + * Author: Andy Fleming + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/phy.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +/* The Level one LXT970 is used by many boards */ + +#define MII_LXT970_IER 17 /* Interrupt Enable Register */ + +#define MII_LXT970_IER_IEN 0x0002 + +#define MII_LXT970_ISR 18 /* Interrupt Status Register */ + +#define MII_LXT970_CONFIG 19 /* Configuration Register */ + +/* ------------------------------------------------------------------------- */ +/* The Level one LXT971 is used on some of my custom boards */ + +/* register definitions for the 971 */ +#define MII_LXT971_IER 18 /* Interrupt Enable Register */ +#define MII_LXT971_IER_IEN 0x00f2 + +#define MII_LXT971_ISR 19 /* Interrupt Status Register */ + + +MODULE_DESCRIPTION("Intel LXT PHY driver"); +MODULE_AUTHOR("Andy Fleming"); +MODULE_LICENSE("GPL"); + +static int lxt970_ack_interrupt(struct phy_device *phydev) +{ + int err; + + err = phy_read(phydev, MII_BMSR); + + if (err < 0) + return err; + + err = phy_read(phydev, MII_LXT970_ISR); + + if (err < 0) + return err; + + return 0; +} + +static int lxt970_config_intr(struct phy_device *phydev) +{ + int err; + + if(phydev->interrupts == PHY_INTERRUPT_ENABLED) + err = phy_write(phydev, MII_LXT970_IER, MII_LXT970_IER_IEN); + else + err = phy_write(phydev, MII_LXT970_IER, 0); + + return err; +} + +static int lxt970_config_init(struct phy_device *phydev) +{ + int err; + + err = phy_write(phydev, MII_LXT970_CONFIG, 0); + + return err; +} + + +static int lxt971_ack_interrupt(struct phy_device *phydev) +{ + int err = phy_read(phydev, MII_LXT971_ISR); + + if (err < 0) + return err; + + return 0; +} + +static int lxt971_config_intr(struct phy_device *phydev) +{ + int err; + + if(phydev->interrupts == PHY_INTERRUPT_ENABLED) + err = phy_write(phydev, MII_LXT971_IER, MII_LXT971_IER_IEN); + else + err = phy_write(phydev, MII_LXT971_IER, 0); + + return err; +} + +static struct phy_driver lxt970_driver = { + .phy_id = 0x07810000, + .name = "LXT970", + .phy_id_mask = 0x0fffffff, + .features = PHY_BASIC_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_init = lxt970_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = lxt970_ack_interrupt, + .config_intr = lxt970_config_intr, + .driver = { .owner = THIS_MODULE,}, +}; + +static struct phy_driver lxt971_driver = { + .phy_id = 0x0001378e, + .name = "LXT971", + .phy_id_mask = 0x0fffffff, + .features = PHY_BASIC_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = lxt971_ack_interrupt, + .config_intr = lxt971_config_intr, + .driver = { .owner = THIS_MODULE,}, +}; + +static int __init lxt_init(void) +{ + int ret; + + ret = phy_driver_register(&lxt970_driver); + if (ret) + goto err1; + + ret = phy_driver_register(&lxt971_driver); + if (ret) + goto err2; + return 0; + + err2: + phy_driver_unregister(&lxt970_driver); + err1: + return ret; +} + +static void __exit lxt_exit(void) +{ + phy_driver_unregister(&lxt970_driver); + phy_driver_unregister(&lxt971_driver); +} + +module_init(lxt_init); +module_exit(lxt_exit); diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c new file mode 100644 index 00000000000..4a72b025006 --- /dev/null +++ b/drivers/net/phy/marvell.c @@ -0,0 +1,140 @@ +/* + * drivers/net/phy/marvell.c + * + * Driver for Marvell PHYs + * + * Author: Andy Fleming + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/phy.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +#define MII_M1011_IEVENT 0x13 +#define MII_M1011_IEVENT_CLEAR 0x0000 + +#define MII_M1011_IMASK 0x12 +#define MII_M1011_IMASK_INIT 0x6400 +#define MII_M1011_IMASK_CLEAR 0x0000 + +MODULE_DESCRIPTION("Marvell PHY driver"); +MODULE_AUTHOR("Andy Fleming"); +MODULE_LICENSE("GPL"); + +static int marvell_ack_interrupt(struct phy_device *phydev) +{ + int err; + + /* Clear the interrupts by reading the reg */ + err = phy_read(phydev, MII_M1011_IEVENT); + + if (err < 0) + return err; + + return 0; +} + +static int marvell_config_intr(struct phy_device *phydev) +{ + int err; + + if(phydev->interrupts == PHY_INTERRUPT_ENABLED) + err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT); + else + err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); + + return err; +} + +static int marvell_config_aneg(struct phy_device *phydev) +{ + int err; + + /* The Marvell PHY has an errata which requires + * that certain registers get written in order + * to restart autonegotiation */ + err = phy_write(phydev, MII_BMCR, BMCR_RESET); + + if (err < 0) + return err; + + err = phy_write(phydev, 0x1d, 0x1f); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1e, 0x200c); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1d, 0x5); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1e, 0); + if (err < 0) + return err; + + err = phy_write(phydev, 0x1e, 0x100); + if (err < 0) + return err; + + + err = genphy_config_aneg(phydev); + + return err; +} + + +static struct phy_driver m88e1101_driver = { + .phy_id = 0x01410c00, + .phy_id_mask = 0xffffff00, + .name = "Marvell 88E1101", + .features = PHY_GBIT_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_aneg = &marvell_config_aneg, + .read_status = &genphy_read_status, + .ack_interrupt = &marvell_ack_interrupt, + .config_intr = &marvell_config_intr, + .driver = { .owner = THIS_MODULE,}, +}; + +static int __init marvell_init(void) +{ + return phy_driver_register(&m88e1101_driver); +} + +static void __exit marvell_exit(void) +{ + phy_driver_unregister(&m88e1101_driver); +} + +module_init(marvell_init); +module_exit(marvell_exit); diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c new file mode 100644 index 00000000000..41f62c0c5fc --- /dev/null +++ b/drivers/net/phy/mdio_bus.c @@ -0,0 +1,176 @@ +/* + * drivers/net/phy/mdio_bus.c + * + * MDIO Bus interface + * + * Author: Andy Fleming + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/phy.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +/* mdiobus_register + * + * description: Called by a bus driver to bring up all the PHYs + * on a given bus, and attach them to the bus + */ +int mdiobus_register(struct mii_bus *bus) +{ + int i; + int err = 0; + + spin_lock_init(&bus->mdio_lock); + + if (NULL == bus || NULL == bus->name || + NULL == bus->read || + NULL == bus->write) + return -EINVAL; + + if (bus->reset) + bus->reset(bus); + + for (i = 0; i < PHY_MAX_ADDR; i++) { + struct phy_device *phydev; + + phydev = get_phy_device(bus, i); + + if (IS_ERR(phydev)) + return PTR_ERR(phydev); + + /* There's a PHY at this address + * We need to set: + * 1) IRQ + * 2) bus_id + * 3) parent + * 4) bus + * 5) mii_bus + * And, we need to register it */ + if (phydev) { + phydev->irq = bus->irq[i]; + + phydev->dev.parent = bus->dev; + phydev->dev.bus = &mdio_bus_type; + sprintf(phydev->dev.bus_id, "phy%d:%d", bus->id, i); + + phydev->bus = bus; + + err = device_register(&phydev->dev); + + if (err) + printk(KERN_ERR "phy %d failed to register\n", + i); + } + + bus->phy_map[i] = phydev; + } + + pr_info("%s: probed\n", bus->name); + + return err; +} +EXPORT_SYMBOL(mdiobus_register); + +void mdiobus_unregister(struct mii_bus *bus) +{ + int i; + + for (i = 0; i < PHY_MAX_ADDR; i++) { + if (bus->phy_map[i]) { + device_unregister(&bus->phy_map[i]->dev); + kfree(bus->phy_map[i]); + } + } +} +EXPORT_SYMBOL(mdiobus_unregister); + +/* mdio_bus_match + * + * description: Given a PHY device, and a PHY driver, return 1 if + * the driver supports the device. Otherwise, return 0 + */ +static int mdio_bus_match(struct device *dev, struct device_driver *drv) +{ + struct phy_device *phydev = to_phy_device(dev); + struct phy_driver *phydrv = to_phy_driver(drv); + + return (phydrv->phy_id == (phydev->phy_id & phydrv->phy_id_mask)); +} + +/* Suspend and resume. Copied from platform_suspend and + * platform_resume + */ +static int mdio_bus_suspend(struct device * dev, u32 state) +{ + int ret = 0; + struct device_driver *drv = dev->driver; + + if (drv && drv->suspend) { + ret = drv->suspend(dev, state, SUSPEND_DISABLE); + if (ret == 0) + ret = drv->suspend(dev, state, SUSPEND_SAVE_STATE); + if (ret == 0) + ret = drv->suspend(dev, state, SUSPEND_POWER_DOWN); + } + return ret; +} + +static int mdio_bus_resume(struct device * dev) +{ + int ret = 0; + struct device_driver *drv = dev->driver; + + if (drv && drv->resume) { + ret = drv->resume(dev, RESUME_POWER_ON); + if (ret == 0) + ret = drv->resume(dev, RESUME_RESTORE_STATE); + if (ret == 0) + ret = drv->resume(dev, RESUME_ENABLE); + } + return ret; +} + +struct bus_type mdio_bus_type = { + .name = "mdio_bus", + .match = mdio_bus_match, + .suspend = mdio_bus_suspend, + .resume = mdio_bus_resume, +}; + +int __init mdio_bus_init(void) +{ + return bus_register(&mdio_bus_type); +} + +void __exit mdio_bus_exit(void) +{ + bus_unregister(&mdio_bus_type); +} diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c new file mode 100644 index 00000000000..d9e11f93bf3 --- /dev/null +++ b/drivers/net/phy/phy.c @@ -0,0 +1,871 @@ +/* + * drivers/net/phy/phy.c + * + * Framework for configuring and reading PHY devices + * Based on code in sungem_phy.c and gianfar_phy.c + * + * Author: Andy Fleming + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/phy.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +/* Convenience function to print out the current phy status + */ +void phy_print_status(struct phy_device *phydev) +{ + pr_info("%s: Link is %s", phydev->dev.bus_id, + phydev->link ? "Up" : "Down"); + if (phydev->link) + printk(" - %d/%s", phydev->speed, + DUPLEX_FULL == phydev->duplex ? + "Full" : "Half"); + + printk("\n"); +} +EXPORT_SYMBOL(phy_print_status); + + +/* Convenience functions for reading/writing a given PHY + * register. They MUST NOT be called from interrupt context, + * because the bus read/write functions may wait for an interrupt + * to conclude the operation. */ +int phy_read(struct phy_device *phydev, u16 regnum) +{ + int retval; + struct mii_bus *bus = phydev->bus; + + spin_lock_bh(&bus->mdio_lock); + retval = bus->read(bus, phydev->addr, regnum); + spin_unlock_bh(&bus->mdio_lock); + + return retval; +} +EXPORT_SYMBOL(phy_read); + +int phy_write(struct phy_device *phydev, u16 regnum, u16 val) +{ + int err; + struct mii_bus *bus = phydev->bus; + + spin_lock_bh(&bus->mdio_lock); + err = bus->write(bus, phydev->addr, regnum, val); + spin_unlock_bh(&bus->mdio_lock); + + return err; +} +EXPORT_SYMBOL(phy_write); + + +int phy_clear_interrupt(struct phy_device *phydev) +{ + int err = 0; + + if (phydev->drv->ack_interrupt) + err = phydev->drv->ack_interrupt(phydev); + + return err; +} + + +int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) +{ + int err = 0; + + phydev->interrupts = interrupts; + if (phydev->drv->config_intr) + err = phydev->drv->config_intr(phydev); + + return err; +} + + +/* phy_aneg_done + * + * description: Reads the status register and returns 0 either if + * auto-negotiation is incomplete, or if there was an error. + * Returns BMSR_ANEGCOMPLETE if auto-negotiation is done. + */ +static inline int phy_aneg_done(struct phy_device *phydev) +{ + int retval; + + retval = phy_read(phydev, MII_BMSR); + + return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE); +} + +/* A structure for mapping a particular speed and duplex + * combination to a particular SUPPORTED and ADVERTISED value */ +struct phy_setting { + int speed; + int duplex; + u32 setting; +}; + +/* A mapping of all SUPPORTED settings to speed/duplex */ +static struct phy_setting settings[] = { + { + .speed = 10000, + .duplex = DUPLEX_FULL, + .setting = SUPPORTED_10000baseT_Full, + }, + { + .speed = SPEED_1000, + .duplex = DUPLEX_FULL, + .setting = SUPPORTED_1000baseT_Full, + }, + { + .speed = SPEED_1000, + .duplex = DUPLEX_HALF, + .setting = SUPPORTED_1000baseT_Half, + }, + { + .speed = SPEED_100, + .duplex = DUPLEX_FULL, + .setting = SUPPORTED_100baseT_Full, + }, + { + .speed = SPEED_100, + .duplex = DUPLEX_HALF, + .setting = SUPPORTED_100baseT_Half, + }, + { + .speed = SPEED_10, + .duplex = DUPLEX_FULL, + .setting = SUPPORTED_10baseT_Full, + }, + { + .speed = SPEED_10, + .duplex = DUPLEX_HALF, + .setting = SUPPORTED_10baseT_Half, + }, +}; + +#define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting)) + +/* phy_find_setting + * + * description: Searches the settings array for the setting which + * matches the desired speed and duplex, and returns the index + * of that setting. Returns the index of the last setting if + * none of the others match. + */ +static inline int phy_find_setting(int speed, int duplex) +{ + int idx = 0; + + while (idx < ARRAY_SIZE(settings) && + (settings[idx].speed != speed || + settings[idx].duplex != duplex)) + idx++; + + return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1; +} + +/* phy_find_valid + * idx: The first index in settings[] to search + * features: A mask of the valid settings + * + * description: Returns the index of the first valid setting less + * than or equal to the one pointed to by idx, as determined by + * the mask in features. Returns the index of the last setting + * if nothing else matches. + */ +static inline int phy_find_valid(int idx, u32 features) +{ + while (idx < MAX_NUM_SETTINGS && !(settings[idx].setting & features)) + idx++; + + return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1; +} + +/* phy_sanitize_settings + * + * description: Make sure the PHY is set to supported speeds and + * duplexes. Drop down by one in this order: 1000/FULL, + * 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF + */ +void phy_sanitize_settings(struct phy_device *phydev) +{ + u32 features = phydev->supported; + int idx; + + /* Sanitize settings based on PHY capabilities */ + if ((features & SUPPORTED_Autoneg) == 0) + phydev->autoneg = 0; + + idx = phy_find_valid(phy_find_setting(phydev->speed, phydev->duplex), + features); + + phydev->speed = settings[idx].speed; + phydev->duplex = settings[idx].duplex; +} +EXPORT_SYMBOL(phy_sanitize_settings); + +/* phy_ethtool_sset: + * A generic ethtool sset function. Handles all the details + * + * A few notes about parameter checking: + * - We don't set port or transceiver, so we don't care what they + * were set to. + * - phy_start_aneg() will make sure forced settings are sane, and + * choose the next best ones from the ones selected, so we don't + * care if ethtool tries to give us bad values + * + * A note about the PHYCONTROL Layer. If you turn off + * CONFIG_PHYCONTROL, you will need to read the PHY status + * registers after this function completes, and update your + * controller manually. + */ +int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) +{ + if (cmd->phy_address != phydev->addr) + return -EINVAL; + + /* We make sure that we don't pass unsupported + * values in to the PHY */ + cmd->advertising &= phydev->supported; + + /* Verify the settings we care about. */ + if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE) + return -EINVAL; + + if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0) + return -EINVAL; + + if (cmd->autoneg == AUTONEG_DISABLE + && ((cmd->speed != SPEED_1000 + && cmd->speed != SPEED_100 + && cmd->speed != SPEED_10) + || (cmd->duplex != DUPLEX_HALF + && cmd->duplex != DUPLEX_FULL))) + return -EINVAL; + + phydev->autoneg = cmd->autoneg; + + phydev->speed = cmd->speed; + + phydev->advertising = cmd->advertising; + + if (AUTONEG_ENABLE == cmd->autoneg) + phydev->advertising |= ADVERTISED_Autoneg; + else + phydev->advertising &= ~ADVERTISED_Autoneg; + + phydev->duplex = cmd->duplex; + + /* Restart the PHY */ + phy_start_aneg(phydev); + + return 0; +} + +int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) +{ + cmd->supported = phydev->supported; + + cmd->advertising = phydev->advertising; + + cmd->speed = phydev->speed; + cmd->duplex = phydev->duplex; + cmd->port = PORT_MII; + cmd->phy_address = phydev->addr; + cmd->transceiver = XCVR_EXTERNAL; + cmd->autoneg = phydev->autoneg; + + return 0; +} + + +/* Note that this function is currently incompatible with the + * PHYCONTROL layer. It changes registers without regard to + * current state. Use at own risk + */ +int phy_mii_ioctl(struct phy_device *phydev, + struct mii_ioctl_data *mii_data, int cmd) +{ + u16 val = mii_data->val_in; + + switch (cmd) { + case SIOCGMIIPHY: + mii_data->phy_id = phydev->addr; + break; + case SIOCGMIIREG: + mii_data->val_out = phy_read(phydev, mii_data->reg_num); + break; + + case SIOCSMIIREG: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (mii_data->phy_id == phydev->addr) { + switch(mii_data->reg_num) { + case MII_BMCR: + if (val & (BMCR_RESET|BMCR_ANENABLE)) + phydev->autoneg = AUTONEG_DISABLE; + else + phydev->autoneg = AUTONEG_ENABLE; + if ((!phydev->autoneg) && (val & BMCR_FULLDPLX)) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + break; + case MII_ADVERTISE: + phydev->advertising = val; + break; + default: + /* do nothing */ + break; + } + } + + phy_write(phydev, mii_data->reg_num, val); + + if (mii_data->reg_num == MII_BMCR + && val & BMCR_RESET + && phydev->drv->config_init) + phydev->drv->config_init(phydev); + break; + } + + return 0; +} + +/* phy_start_aneg + * + * description: Sanitizes the settings (if we're not + * autonegotiating them), and then calls the driver's + * config_aneg function. If the PHYCONTROL Layer is operating, + * we change the state to reflect the beginning of + * Auto-negotiation or forcing. + */ +int phy_start_aneg(struct phy_device *phydev) +{ + int err; + + spin_lock(&phydev->lock); + + if (AUTONEG_DISABLE == phydev->autoneg) + phy_sanitize_settings(phydev); + + err = phydev->drv->config_aneg(phydev); + +#ifdef CONFIG_PHYCONTROL + if (err < 0) + goto out_unlock; + + if (phydev->state != PHY_HALTED) { + if (AUTONEG_ENABLE == phydev->autoneg) { + phydev->state = PHY_AN; + phydev->link_timeout = PHY_AN_TIMEOUT; + } else { + phydev->state = PHY_FORCING; + phydev->link_timeout = PHY_FORCE_TIMEOUT; + } + } + +out_unlock: +#endif + spin_unlock(&phydev->lock); + return err; +} +EXPORT_SYMBOL(phy_start_aneg); + + +#ifdef CONFIG_PHYCONTROL +static void phy_change(void *data); +static void phy_timer(unsigned long data); + +/* phy_start_machine: + * + * description: The PHY infrastructure can run a state machine + * which tracks whether the PHY is starting up, negotiating, + * etc. This function starts the timer which tracks the state + * of the PHY. If you want to be notified when the state + * changes, pass in the callback, otherwise, pass NULL. If you + * want to maintain your own state machine, do not call this + * function. */ +void phy_start_machine(struct phy_device *phydev, + void (*handler)(struct net_device *)) +{ + phydev->adjust_state = handler; + + init_timer(&phydev->phy_timer); + phydev->phy_timer.function = &phy_timer; + phydev->phy_timer.data = (unsigned long) phydev; + mod_timer(&phydev->phy_timer, jiffies + HZ); +} + +/* phy_stop_machine + * + * description: Stops the state machine timer, sets the state to + * UP (unless it wasn't up yet), and then frees the interrupt, + * if it is in use. This function must be called BEFORE + * phy_detach. + */ +void phy_stop_machine(struct phy_device *phydev) +{ + del_timer_sync(&phydev->phy_timer); + + spin_lock(&phydev->lock); + if (phydev->state > PHY_UP) + phydev->state = PHY_UP; + spin_unlock(&phydev->lock); + + if (phydev->irq != PHY_POLL) + phy_stop_interrupts(phydev); + + phydev->adjust_state = NULL; +} + +/* phy_force_reduction + * + * description: Reduces the speed/duplex settings by + * one notch. The order is so: + * 1000/FULL, 1000/HALF, 100/FULL, 100/HALF, + * 10/FULL, 10/HALF. The function bottoms out at 10/HALF. + */ +static void phy_force_reduction(struct phy_device *phydev) +{ + int idx; + + idx = phy_find_setting(phydev->speed, phydev->duplex); + + idx++; + + idx = phy_find_valid(idx, phydev->supported); + + phydev->speed = settings[idx].speed; + phydev->duplex = settings[idx].duplex; + + pr_info("Trying %d/%s\n", phydev->speed, + DUPLEX_FULL == phydev->duplex ? + "FULL" : "HALF"); +} + + +/* phy_error: + * + * Moves the PHY to the HALTED state in response to a read + * or write error, and tells the controller the link is down. + * Must not be called from interrupt context, or while the + * phydev->lock is held. + */ +void phy_error(struct phy_device *phydev) +{ + spin_lock(&phydev->lock); + phydev->state = PHY_HALTED; + spin_unlock(&phydev->lock); +} + +/* phy_interrupt + * + * description: When a PHY interrupt occurs, the handler disables + * interrupts, and schedules a work task to clear the interrupt. + */ +static irqreturn_t phy_interrupt(int irq, void *phy_dat, struct pt_regs *regs) +{ + struct phy_device *phydev = phy_dat; + + /* The MDIO bus is not allowed to be written in interrupt + * context, so we need to disable the irq here. A work + * queue will write the PHY to disable and clear the + * interrupt, and then reenable the irq line. */ + disable_irq_nosync(irq); + + schedule_work(&phydev->phy_queue); + + return IRQ_HANDLED; +} + +/* Enable the interrupts from the PHY side */ +int phy_enable_interrupts(struct phy_device *phydev) +{ + int err; + + err = phy_clear_interrupt(phydev); + + if (err < 0) + return err; + + err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED); + + return err; +} +EXPORT_SYMBOL(phy_enable_interrupts); + +/* Disable the PHY interrupts from the PHY side */ +int phy_disable_interrupts(struct phy_device *phydev) +{ + int err; + + /* Disable PHY interrupts */ + err = phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED); + + if (err) + goto phy_err; + + /* Clear the interrupt */ + err = phy_clear_interrupt(phydev); + + if (err) + goto phy_err; + + return 0; + +phy_err: + phy_error(phydev); + + return err; +} +EXPORT_SYMBOL(phy_disable_interrupts); + +/* phy_start_interrupts + * + * description: Request the interrupt for the given PHY. If + * this fails, then we set irq to PHY_POLL. + * Otherwise, we enable the interrupts in the PHY. + * Returns 0 on success. + * This should only be called with a valid IRQ number. + */ +int phy_start_interrupts(struct phy_device *phydev) +{ + int err = 0; + + INIT_WORK(&phydev->phy_queue, phy_change, phydev); + + if (request_irq(phydev->irq, phy_interrupt, + SA_SHIRQ, + "phy_interrupt", + phydev) < 0) { + printk(KERN_WARNING "%s: Can't get IRQ %d (PHY)\n", + phydev->bus->name, + phydev->irq); + phydev->irq = PHY_POLL; + return 0; + } + + err = phy_enable_interrupts(phydev); + + return err; +} +EXPORT_SYMBOL(phy_start_interrupts); + +int phy_stop_interrupts(struct phy_device *phydev) +{ + int err; + + err = phy_disable_interrupts(phydev); + + if (err) + phy_error(phydev); + + free_irq(phydev->irq, phydev); + + return err; +} +EXPORT_SYMBOL(phy_stop_interrupts); + + +/* Scheduled by the phy_interrupt/timer to handle PHY changes */ +static void phy_change(void *data) +{ + int err; + struct phy_device *phydev = data; + + err = phy_disable_interrupts(phydev); + + if (err) + goto phy_err; + + spin_lock(&phydev->lock); + if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state)) + phydev->state = PHY_CHANGELINK; + spin_unlock(&phydev->lock); + + enable_irq(phydev->irq); + + /* Reenable interrupts */ + err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED); + + if (err) + goto irq_enable_err; + + return; + +irq_enable_err: + disable_irq(phydev->irq); +phy_err: + phy_error(phydev); +} + +/* Bring down the PHY link, and stop checking the status. */ +void phy_stop(struct phy_device *phydev) +{ + spin_lock(&phydev->lock); + + if (PHY_HALTED == phydev->state) + goto out_unlock; + + if (phydev->irq != PHY_POLL) { + /* Clear any pending interrupts */ + phy_clear_interrupt(phydev); + + /* Disable PHY Interrupts */ + phy_config_interrupt(phydev, PHY_INTERRUPT_DISABLED); + } + + phydev->state = PHY_HALTED; + +out_unlock: + spin_unlock(&phydev->lock); +} + + +/* phy_start + * + * description: Indicates the attached device's readiness to + * handle PHY-related work. Used during startup to start the + * PHY, and after a call to phy_stop() to resume operation. + * Also used to indicate the MDIO bus has cleared an error + * condition. + */ +void phy_start(struct phy_device *phydev) +{ + spin_lock(&phydev->lock); + + switch (phydev->state) { + case PHY_STARTING: + phydev->state = PHY_PENDING; + break; + case PHY_READY: + phydev->state = PHY_UP; + break; + case PHY_HALTED: + phydev->state = PHY_RESUMING; + default: + break; + } + spin_unlock(&phydev->lock); +} +EXPORT_SYMBOL(phy_stop); +EXPORT_SYMBOL(phy_start); + +/* PHY timer which handles the state machine */ +static void phy_timer(unsigned long data) +{ + struct phy_device *phydev = (struct phy_device *)data; + int needs_aneg = 0; + int err = 0; + + spin_lock(&phydev->lock); + + if (phydev->adjust_state) + phydev->adjust_state(phydev->attached_dev); + + switch(phydev->state) { + case PHY_DOWN: + case PHY_STARTING: + case PHY_READY: + case PHY_PENDING: + break; + case PHY_UP: + needs_aneg = 1; + + phydev->link_timeout = PHY_AN_TIMEOUT; + + break; + case PHY_AN: + /* Check if negotiation is done. Break + * if there's an error */ + err = phy_aneg_done(phydev); + if (err < 0) + break; + + /* If auto-negotiation is done, we change to + * either RUNNING, or NOLINK */ + if (err > 0) { + err = phy_read_status(phydev); + + if (err) + break; + + if (phydev->link) { + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); + } else { + phydev->state = PHY_NOLINK; + netif_carrier_off(phydev->attached_dev); + } + + phydev->adjust_link(phydev->attached_dev); + + } else if (0 == phydev->link_timeout--) { + /* The counter expired, so either we + * switch to forced mode, or the + * magic_aneg bit exists, and we try aneg + * again */ + if (!(phydev->drv->flags & PHY_HAS_MAGICANEG)) { + int idx; + + /* We'll start from the + * fastest speed, and work + * our way down */ + idx = phy_find_valid(0, + phydev->supported); + + phydev->speed = settings[idx].speed; + phydev->duplex = settings[idx].duplex; + + phydev->autoneg = AUTONEG_DISABLE; + phydev->state = PHY_FORCING; + phydev->link_timeout = + PHY_FORCE_TIMEOUT; + + pr_info("Trying %d/%s\n", + phydev->speed, + DUPLEX_FULL == + phydev->duplex ? + "FULL" : "HALF"); + } + + needs_aneg = 1; + } + break; + case PHY_NOLINK: + err = phy_read_status(phydev); + + if (err) + break; + + if (phydev->link) { + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); + } + break; + case PHY_FORCING: + err = phy_read_status(phydev); + + if (err) + break; + + if (phydev->link) { + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); + } else { + if (0 == phydev->link_timeout--) { + phy_force_reduction(phydev); + needs_aneg = 1; + } + } + + phydev->adjust_link(phydev->attached_dev); + break; + case PHY_RUNNING: + /* Only register a CHANGE if we are + * polling */ + if (PHY_POLL == phydev->irq) + phydev->state = PHY_CHANGELINK; + break; + case PHY_CHANGELINK: + err = phy_read_status(phydev); + + if (err) + break; + + if (phydev->link) { + phydev->state = PHY_RUNNING; + netif_carrier_on(phydev->attached_dev); + } else { + phydev->state = PHY_NOLINK; + netif_carrier_off(phydev->attached_dev); + } + + phydev->adjust_link(phydev->attached_dev); + + if (PHY_POLL != phydev->irq) + err = phy_config_interrupt(phydev, + PHY_INTERRUPT_ENABLED); + break; + case PHY_HALTED: + if (phydev->link) { + phydev->link = 0; + netif_carrier_off(phydev->attached_dev); + phydev->adjust_link(phydev->attached_dev); + } + break; + case PHY_RESUMING: + + err = phy_clear_interrupt(phydev); + + if (err) + break; + + err = phy_config_interrupt(phydev, + PHY_INTERRUPT_ENABLED); + + if (err) + break; + + if (AUTONEG_ENABLE == phydev->autoneg) { + err = phy_aneg_done(phydev); + if (err < 0) + break; + + /* err > 0 if AN is done. + * Otherwise, it's 0, and we're + * still waiting for AN */ + if (err > 0) { + phydev->state = PHY_RUNNING; + } else { + phydev->state = PHY_AN; + phydev->link_timeout = PHY_AN_TIMEOUT; + } + } else + phydev->state = PHY_RUNNING; + break; + } + + spin_unlock(&phydev->lock); + + if (needs_aneg) + err = phy_start_aneg(phydev); + + if (err < 0) + phy_error(phydev); + + mod_timer(&phydev->phy_timer, jiffies + PHY_STATE_TIME * HZ); +} + +#endif /* CONFIG_PHYCONTROL */ diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c new file mode 100644 index 00000000000..33f7bdb5857 --- /dev/null +++ b/drivers/net/phy/phy_device.c @@ -0,0 +1,696 @@ +/* + * drivers/net/phy/phy_device.c + * + * Framework for finding and configuring PHYs. + * Also contains generic PHY driver + * + * Author: Andy Fleming + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/phy.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +static struct phy_driver genphy_driver; +extern int mdio_bus_init(void); +extern void mdio_bus_exit(void); + +/* get_phy_device + * + * description: Reads the ID registers of the PHY at addr on the + * bus, then allocates and returns the phy_device to + * represent it. + */ +struct phy_device * get_phy_device(struct mii_bus *bus, int addr) +{ + int phy_reg; + u32 phy_id; + struct phy_device *dev = NULL; + + /* Grab the bits from PHYIR1, and put them + * in the upper half */ + phy_reg = bus->read(bus, addr, MII_PHYSID1); + + if (phy_reg < 0) + return ERR_PTR(phy_reg); + + phy_id = (phy_reg & 0xffff) << 16; + + /* Grab the bits from PHYIR2, and put them in the lower half */ + phy_reg = bus->read(bus, addr, MII_PHYSID2); + + if (phy_reg < 0) + return ERR_PTR(phy_reg); + + phy_id |= (phy_reg & 0xffff); + + /* If the phy_id is all Fs, there is no device there */ + if (0xffffffff == phy_id) + return NULL; + + /* Otherwise, we allocate the device, and initialize the + * default values */ + dev = kcalloc(1, sizeof(*dev), GFP_KERNEL); + + if (NULL == dev) + return ERR_PTR(-ENOMEM); + + dev->speed = 0; + dev->duplex = -1; + dev->pause = dev->asym_pause = 0; + dev->link = 1; + + dev->autoneg = AUTONEG_ENABLE; + + dev->addr = addr; + dev->phy_id = phy_id; + dev->bus = bus; + + dev->state = PHY_DOWN; + + spin_lock_init(&dev->lock); + + return dev; +} + +#ifdef CONFIG_PHYCONTROL +/* phy_prepare_link: + * + * description: Tells the PHY infrastructure to handle the + * gory details on monitoring link status (whether through + * polling or an interrupt), and to call back to the + * connected device driver when the link status changes. + * If you want to monitor your own link state, don't call + * this function */ +void phy_prepare_link(struct phy_device *phydev, + void (*handler)(struct net_device *)) +{ + phydev->adjust_link = handler; +} + +/* phy_connect: + * + * description: Convenience function for connecting ethernet + * devices to PHY devices. The default behavior is for + * the PHY infrastructure to handle everything, and only notify + * the connected driver when the link status changes. If you + * don't want, or can't use the provided functionality, you may + * choose to call only the subset of functions which provide + * the desired functionality. + */ +struct phy_device * phy_connect(struct net_device *dev, const char *phy_id, + void (*handler)(struct net_device *), u32 flags) +{ + struct phy_device *phydev; + + phydev = phy_attach(dev, phy_id, flags); + + if (IS_ERR(phydev)) + return phydev; + + phy_prepare_link(phydev, handler); + + phy_start_machine(phydev, NULL); + + if (phydev->irq > 0) + phy_start_interrupts(phydev); + + return phydev; +} +EXPORT_SYMBOL(phy_connect); + +void phy_disconnect(struct phy_device *phydev) +{ + if (phydev->irq > 0) + phy_stop_interrupts(phydev); + + phy_stop_machine(phydev); + + phydev->adjust_link = NULL; + + phy_detach(phydev); +} +EXPORT_SYMBOL(phy_disconnect); + +#endif /* CONFIG_PHYCONTROL */ + +/* phy_attach: + * + * description: Called by drivers to attach to a particular PHY + * device. The phy_device is found, and properly hooked up + * to the phy_driver. If no driver is attached, then the + * genphy_driver is used. The phy_device is given a ptr to + * the attaching device, and given a callback for link status + * change. The phy_device is returned to the attaching + * driver. + */ +static int phy_compare_id(struct device *dev, void *data) +{ + return strcmp((char *)data, dev->bus_id) ? 0 : 1; +} + +struct phy_device *phy_attach(struct net_device *dev, + const char *phy_id, u32 flags) +{ + struct bus_type *bus = &mdio_bus_type; + struct phy_device *phydev; + struct device *d; + + /* Search the list of PHY devices on the mdio bus for the + * PHY with the requested name */ + d = bus_find_device(bus, NULL, (void *)phy_id, phy_compare_id); + + if (d) { + phydev = to_phy_device(d); + } else { + printk(KERN_ERR "%s not found\n", phy_id); + return ERR_PTR(-ENODEV); + } + + /* Assume that if there is no driver, that it doesn't + * exist, and we should use the genphy driver. */ + if (NULL == d->driver) { + int err; + down_write(&d->bus->subsys.rwsem); + d->driver = &genphy_driver.driver; + + err = d->driver->probe(d); + + if (err < 0) + return ERR_PTR(err); + + device_bind_driver(d); + up_write(&d->bus->subsys.rwsem); + } + + if (phydev->attached_dev) { + printk(KERN_ERR "%s: %s already attached\n", + dev->name, phy_id); + return ERR_PTR(-EBUSY); + } + + phydev->attached_dev = dev; + + phydev->dev_flags = flags; + + return phydev; +} +EXPORT_SYMBOL(phy_attach); + +void phy_detach(struct phy_device *phydev) +{ + phydev->attached_dev = NULL; + + /* If the device had no specific driver before (i.e. - it + * was using the generic driver), we unbind the device + * from the generic driver so that there's a chance a + * real driver could be loaded */ + if (phydev->dev.driver == &genphy_driver.driver) { + down_write(&phydev->dev.bus->subsys.rwsem); + device_release_driver(&phydev->dev); + up_write(&phydev->dev.bus->subsys.rwsem); + } +} +EXPORT_SYMBOL(phy_detach); + + +/* Generic PHY support and helper functions */ + +/* genphy_config_advert + * + * description: Writes MII_ADVERTISE with the appropriate values, + * after sanitizing the values to make sure we only advertise + * what is supported + */ +int genphy_config_advert(struct phy_device *phydev) +{ + u32 advertise; + int adv; + int err; + + /* Only allow advertising what + * this PHY supports */ + phydev->advertising &= phydev->supported; + advertise = phydev->advertising; + + /* Setup standard advertisement */ + adv = phy_read(phydev, MII_ADVERTISE); + + if (adv < 0) + return adv; + + adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | + ADVERTISE_PAUSE_ASYM); + if (advertise & ADVERTISED_10baseT_Half) + adv |= ADVERTISE_10HALF; + if (advertise & ADVERTISED_10baseT_Full) + adv |= ADVERTISE_10FULL; + if (advertise & ADVERTISED_100baseT_Half) + adv |= ADVERTISE_100HALF; + if (advertise & ADVERTISED_100baseT_Full) + adv |= ADVERTISE_100FULL; + if (advertise & ADVERTISED_Pause) + adv |= ADVERTISE_PAUSE_CAP; + if (advertise & ADVERTISED_Asym_Pause) + adv |= ADVERTISE_PAUSE_ASYM; + + err = phy_write(phydev, MII_ADVERTISE, adv); + + if (err < 0) + return err; + + /* Configure gigabit if it's supported */ + if (phydev->supported & (SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full)) { + adv = phy_read(phydev, MII_CTRL1000); + + if (adv < 0) + return adv; + + adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); + if (advertise & SUPPORTED_1000baseT_Half) + adv |= ADVERTISE_1000HALF; + if (advertise & SUPPORTED_1000baseT_Full) + adv |= ADVERTISE_1000FULL; + err = phy_write(phydev, MII_CTRL1000, adv); + + if (err < 0) + return err; + } + + return adv; +} +EXPORT_SYMBOL(genphy_config_advert); + +/* genphy_setup_forced + * + * description: Configures MII_BMCR to force speed/duplex + * to the values in phydev. Assumes that the values are valid. + * Please see phy_sanitize_settings() */ +int genphy_setup_forced(struct phy_device *phydev) +{ + int ctl = BMCR_RESET; + + phydev->pause = phydev->asym_pause = 0; + + if (SPEED_1000 == phydev->speed) + ctl |= BMCR_SPEED1000; + else if (SPEED_100 == phydev->speed) + ctl |= BMCR_SPEED100; + + if (DUPLEX_FULL == phydev->duplex) + ctl |= BMCR_FULLDPLX; + + ctl = phy_write(phydev, MII_BMCR, ctl); + + if (ctl < 0) + return ctl; + + /* We just reset the device, so we'd better configure any + * settings the PHY requires to operate */ + if (phydev->drv->config_init) + ctl = phydev->drv->config_init(phydev); + + return ctl; +} + + +/* Enable and Restart Autonegotiation */ +int genphy_restart_aneg(struct phy_device *phydev) +{ + int ctl; + + ctl = phy_read(phydev, MII_BMCR); + + if (ctl < 0) + return ctl; + + ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); + + /* Don't isolate the PHY if we're negotiating */ + ctl &= ~(BMCR_ISOLATE); + + ctl = phy_write(phydev, MII_BMCR, ctl); + + return ctl; +} + + +/* genphy_config_aneg + * + * description: If auto-negotiation is enabled, we configure the + * advertising, and then restart auto-negotiation. If it is not + * enabled, then we write the BMCR + */ +int genphy_config_aneg(struct phy_device *phydev) +{ + int err = 0; + + if (AUTONEG_ENABLE == phydev->autoneg) { + err = genphy_config_advert(phydev); + + if (err < 0) + return err; + + err = genphy_restart_aneg(phydev); + } else + err = genphy_setup_forced(phydev); + + return err; +} +EXPORT_SYMBOL(genphy_config_aneg); + +/* genphy_update_link + * + * description: Update the value in phydev->link to reflect the + * current link value. In order to do this, we need to read + * the status register twice, keeping the second value + */ +int genphy_update_link(struct phy_device *phydev) +{ + int status; + + /* Do a fake read */ + status = phy_read(phydev, MII_BMSR); + + if (status < 0) + return status; + + /* Read link and autonegotiation status */ + status = phy_read(phydev, MII_BMSR); + + if (status < 0) + return status; + + if ((status & BMSR_LSTATUS) == 0) + phydev->link = 0; + else + phydev->link = 1; + + return 0; +} + +/* genphy_read_status + * + * description: Check the link, then figure out the current state + * by comparing what we advertise with what the link partner + * advertises. Start by checking the gigabit possibilities, + * then move on to 10/100. + */ +int genphy_read_status(struct phy_device *phydev) +{ + int adv; + int err; + int lpa; + int lpagb = 0; + + /* Update the link, but return if there + * was an error */ + err = genphy_update_link(phydev); + if (err) + return err; + + if (AUTONEG_ENABLE == phydev->autoneg) { + if (phydev->supported & (SUPPORTED_1000baseT_Half + | SUPPORTED_1000baseT_Full)) { + lpagb = phy_read(phydev, MII_STAT1000); + + if (lpagb < 0) + return lpagb; + + adv = phy_read(phydev, MII_CTRL1000); + + if (adv < 0) + return adv; + + lpagb &= adv << 2; + } + + lpa = phy_read(phydev, MII_LPA); + + if (lpa < 0) + return lpa; + + adv = phy_read(phydev, MII_ADVERTISE); + + if (adv < 0) + return adv; + + lpa &= adv; + + phydev->speed = SPEED_10; + phydev->duplex = DUPLEX_HALF; + phydev->pause = phydev->asym_pause = 0; + + if (lpagb & (LPA_1000FULL | LPA_1000HALF)) { + phydev->speed = SPEED_1000; + + if (lpagb & LPA_1000FULL) + phydev->duplex = DUPLEX_FULL; + } else if (lpa & (LPA_100FULL | LPA_100HALF)) { + phydev->speed = SPEED_100; + + if (lpa & LPA_100FULL) + phydev->duplex = DUPLEX_FULL; + } else + if (lpa & LPA_10FULL) + phydev->duplex = DUPLEX_FULL; + + if (phydev->duplex == DUPLEX_FULL){ + phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0; + phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0; + } + } else { + int bmcr = phy_read(phydev, MII_BMCR); + if (bmcr < 0) + return bmcr; + + if (bmcr & BMCR_FULLDPLX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + if (bmcr & BMCR_SPEED1000) + phydev->speed = SPEED_1000; + else if (bmcr & BMCR_SPEED100) + phydev->speed = SPEED_100; + else + phydev->speed = SPEED_10; + + phydev->pause = phydev->asym_pause = 0; + } + + return 0; +} +EXPORT_SYMBOL(genphy_read_status); + +static int genphy_config_init(struct phy_device *phydev) +{ + u32 val; + u32 features; + + /* For now, I'll claim that the generic driver supports + * all possible port types */ + features = (SUPPORTED_TP | SUPPORTED_MII + | SUPPORTED_AUI | SUPPORTED_FIBRE | + SUPPORTED_BNC); + + /* Do we support autonegotiation? */ + val = phy_read(phydev, MII_BMSR); + + if (val < 0) + return val; + + if (val & BMSR_ANEGCAPABLE) + features |= SUPPORTED_Autoneg; + + if (val & BMSR_100FULL) + features |= SUPPORTED_100baseT_Full; + if (val & BMSR_100HALF) + features |= SUPPORTED_100baseT_Half; + if (val & BMSR_10FULL) + features |= SUPPORTED_10baseT_Full; + if (val & BMSR_10HALF) + features |= SUPPORTED_10baseT_Half; + + if (val & BMSR_ESTATEN) { + val = phy_read(phydev, MII_ESTATUS); + + if (val < 0) + return val; + + if (val & ESTATUS_1000_TFULL) + features |= SUPPORTED_1000baseT_Full; + if (val & ESTATUS_1000_THALF) + features |= SUPPORTED_1000baseT_Half; + } + + phydev->supported = features; + phydev->advertising = features; + + return 0; +} + + +/* phy_probe + * + * description: Take care of setting up the phy_device structure, + * set the state to READY (the driver's init function should + * set it to STARTING if needed). + */ +static int phy_probe(struct device *dev) +{ + struct phy_device *phydev; + struct phy_driver *phydrv; + struct device_driver *drv; + int err = 0; + + phydev = to_phy_device(dev); + + /* Make sure the driver is held. + * XXX -- Is this correct? */ + drv = get_driver(phydev->dev.driver); + phydrv = to_phy_driver(drv); + phydev->drv = phydrv; + + /* Disable the interrupt if the PHY doesn't support it */ + if (!(phydrv->flags & PHY_HAS_INTERRUPT)) + phydev->irq = PHY_POLL; + + spin_lock(&phydev->lock); + + /* Start out supporting everything. Eventually, + * a controller will attach, and may modify one + * or both of these values */ + phydev->supported = phydrv->features; + phydev->advertising = phydrv->features; + + /* Set the state to READY by default */ + phydev->state = PHY_READY; + + if (phydev->drv->probe) + err = phydev->drv->probe(phydev); + + spin_unlock(&phydev->lock); + + if (err < 0) + return err; + + if (phydev->drv->config_init) + err = phydev->drv->config_init(phydev); + + return err; +} + +static int phy_remove(struct device *dev) +{ + struct phy_device *phydev; + + phydev = to_phy_device(dev); + + spin_lock(&phydev->lock); + phydev->state = PHY_DOWN; + spin_unlock(&phydev->lock); + + if (phydev->drv->remove) + phydev->drv->remove(phydev); + + put_driver(dev->driver); + phydev->drv = NULL; + + return 0; +} + +int phy_driver_register(struct phy_driver *new_driver) +{ + int retval; + + memset(&new_driver->driver, 0, sizeof(new_driver->driver)); + new_driver->driver.name = new_driver->name; + new_driver->driver.bus = &mdio_bus_type; + new_driver->driver.probe = phy_probe; + new_driver->driver.remove = phy_remove; + + retval = driver_register(&new_driver->driver); + + if (retval) { + printk(KERN_ERR "%s: Error %d in registering driver\n", + new_driver->name, retval); + + return retval; + } + + pr_info("%s: Registered new driver\n", new_driver->name); + + return 0; +} +EXPORT_SYMBOL(phy_driver_register); + +void phy_driver_unregister(struct phy_driver *drv) +{ + driver_unregister(&drv->driver); +} +EXPORT_SYMBOL(phy_driver_unregister); + +static struct phy_driver genphy_driver = { + .phy_id = 0xffffffff, + .phy_id_mask = 0xffffffff, + .name = "Generic PHY", + .config_init = genphy_config_init, + .features = 0, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .driver = {.owner= THIS_MODULE, }, +}; + +static int __init phy_init(void) +{ + int rc; + + rc = mdio_bus_init(); + if (rc) + return rc; + + rc = phy_driver_register(&genphy_driver); + if (rc) + mdio_bus_exit(); + + return rc; +} + +static void __exit phy_exit(void) +{ + phy_driver_unregister(&genphy_driver); + mdio_bus_exit(); +} + +subsys_initcall(phy_init); +module_exit(phy_exit); diff --git a/drivers/net/phy/qsemi.c b/drivers/net/phy/qsemi.c new file mode 100644 index 00000000000..d461ba45763 --- /dev/null +++ b/drivers/net/phy/qsemi.c @@ -0,0 +1,143 @@ +/* + * drivers/net/phy/qsemi.c + * + * Driver for Quality Semiconductor PHYs + * + * Author: Andy Fleming + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/spinlock.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/version.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/phy.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> + +/* ------------------------------------------------------------------------- */ +/* The Quality Semiconductor QS6612 is used on the RPX CLLF */ + +/* register definitions */ + +#define MII_QS6612_MCR 17 /* Mode Control Register */ +#define MII_QS6612_FTR 27 /* Factory Test Register */ +#define MII_QS6612_MCO 28 /* Misc. Control Register */ +#define MII_QS6612_ISR 29 /* Interrupt Source Register */ +#define MII_QS6612_IMR 30 /* Interrupt Mask Register */ +#define MII_QS6612_IMR_INIT 0x003a +#define MII_QS6612_PCR 31 /* 100BaseTx PHY Control Reg. */ + +#define QS6612_PCR_AN_COMPLETE 0x1000 +#define QS6612_PCR_RLBEN 0x0200 +#define QS6612_PCR_DCREN 0x0100 +#define QS6612_PCR_4B5BEN 0x0040 +#define QS6612_PCR_TX_ISOLATE 0x0020 +#define QS6612_PCR_MLT3_DIS 0x0002 +#define QS6612_PCR_SCRM_DESCRM 0x0001 + +MODULE_DESCRIPTION("Quality Semiconductor PHY driver"); +MODULE_AUTHOR("Andy Fleming"); +MODULE_LICENSE("GPL"); + +/* Returns 0, unless there's a write error */ +static int qs6612_config_init(struct phy_device *phydev) +{ + /* The PHY powers up isolated on the RPX, + * so send a command to allow operation. + * XXX - My docs indicate this should be 0x0940 + * ...or something. The current value sets three + * reserved bits, bit 11, which specifies it should be + * set to one, bit 10, which specifies it should be set + * to 0, and bit 7, which doesn't specify. However, my + * docs are preliminary, and I will leave it like this + * until someone more knowledgable corrects me or it. + * -- Andy Fleming + */ + return phy_write(phydev, MII_QS6612_PCR, 0x0dc0); +} + +static int qs6612_ack_interrupt(struct phy_device *phydev) +{ + int err; + + err = phy_read(phydev, MII_QS6612_ISR); + + if (err < 0) + return err; + + err = phy_read(phydev, MII_BMSR); + + if (err < 0) + return err; + + err = phy_read(phydev, MII_EXPANSION); + + if (err < 0) + return err; + + return 0; +} + +static int qs6612_config_intr(struct phy_device *phydev) +{ + int err; + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) + err = phy_write(phydev, MII_QS6612_IMR, + MII_QS6612_IMR_INIT); + else + err = phy_write(phydev, MII_QS6612_IMR, 0); + + return err; + +} + +static struct phy_driver qs6612_driver = { + .phy_id = 0x00181440, + .name = "QS6612", + .phy_id_mask = 0xfffffff0, + .features = PHY_BASIC_FEATURES, + .flags = PHY_HAS_INTERRUPT, + .config_init = qs6612_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = qs6612_ack_interrupt, + .config_intr = qs6612_config_intr, + .driver = { .owner = THIS_MODULE,}, +}; + +static int __init qs6612_init(void) +{ + return phy_driver_register(&qs6612_driver); +} + +static void __exit qs6612_exit(void) +{ + phy_driver_unregister(&qs6612_driver); +} + +module_init(qs6612_init); +module_exit(qs6612_exit); diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index d5afe05cd82..f0471d102e3 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -187,6 +187,7 @@ static struct pci_device_id rtl8169_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), }, { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), }, { PCI_DEVICE(0x16ec, 0x0116), }, + { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0024, }, {0,}, }; diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h index 7092ca6b277..2234a8f05eb 100644 --- a/drivers/net/s2io-regs.h +++ b/drivers/net/s2io-regs.h @@ -62,6 +62,7 @@ typedef struct _XENA_dev_config { #define ADAPTER_STATUS_RMAC_REMOTE_FAULT BIT(6) #define ADAPTER_STATUS_RMAC_LOCAL_FAULT BIT(7) #define ADAPTER_STATUS_RMAC_PCC_IDLE vBIT(0xFF,8,8) +#define ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE vBIT(0x0F,8,8) #define ADAPTER_STATUS_RC_PRC_QUIESCENT vBIT(0xFF,16,8) #define ADAPTER_STATUS_MC_DRAM_READY BIT(24) #define ADAPTER_STATUS_MC_QUEUES_READY BIT(25) @@ -77,21 +78,34 @@ typedef struct _XENA_dev_config { #define ADAPTER_ECC_EN BIT(55) u64 serr_source; -#define SERR_SOURCE_PIC BIT(0) -#define SERR_SOURCE_TXDMA BIT(1) -#define SERR_SOURCE_RXDMA BIT(2) +#define SERR_SOURCE_PIC BIT(0) +#define SERR_SOURCE_TXDMA BIT(1) +#define SERR_SOURCE_RXDMA BIT(2) #define SERR_SOURCE_MAC BIT(3) #define SERR_SOURCE_MC BIT(4) #define SERR_SOURCE_XGXS BIT(5) -#define SERR_SOURCE_ANY (SERR_SOURCE_PIC | \ - SERR_SOURCE_TXDMA | \ - SERR_SOURCE_RXDMA | \ - SERR_SOURCE_MAC | \ - SERR_SOURCE_MC | \ - SERR_SOURCE_XGXS) - - - u8 unused_0[0x800 - 0x120]; +#define SERR_SOURCE_ANY (SERR_SOURCE_PIC | \ + SERR_SOURCE_TXDMA | \ + SERR_SOURCE_RXDMA | \ + SERR_SOURCE_MAC | \ + SERR_SOURCE_MC | \ + SERR_SOURCE_XGXS) + + u64 pci_mode; +#define GET_PCI_MODE(val) ((val & vBIT(0xF, 0, 4)) >> 60) +#define PCI_MODE_PCI_33 0 +#define PCI_MODE_PCI_66 0x1 +#define PCI_MODE_PCIX_M1_66 0x2 +#define PCI_MODE_PCIX_M1_100 0x3 +#define PCI_MODE_PCIX_M1_133 0x4 +#define PCI_MODE_PCIX_M2_66 0x5 +#define PCI_MODE_PCIX_M2_100 0x6 +#define PCI_MODE_PCIX_M2_133 0x7 +#define PCI_MODE_UNSUPPORTED BIT(0) +#define PCI_MODE_32_BITS BIT(8) +#define PCI_MODE_UNKNOWN_MODE BIT(9) + + u8 unused_0[0x800 - 0x128]; /* PCI-X Controller registers */ u64 pic_int_status; @@ -153,7 +167,11 @@ typedef struct _XENA_dev_config { u8 unused4[0x08]; u64 gpio_int_reg; +#define GPIO_INT_REG_LINK_DOWN BIT(1) +#define GPIO_INT_REG_LINK_UP BIT(2) u64 gpio_int_mask; +#define GPIO_INT_MASK_LINK_DOWN BIT(1) +#define GPIO_INT_MASK_LINK_UP BIT(2) u64 gpio_alarms; u8 unused5[0x38]; @@ -223,19 +241,16 @@ typedef struct _XENA_dev_config { u64 xmsi_data; u64 rx_mat; +#define RX_MAT_SET(ring, msi) vBIT(msi, (8 * ring), 8) u8 unused6[0x8]; - u64 tx_mat0_7; - u64 tx_mat8_15; - u64 tx_mat16_23; - u64 tx_mat24_31; - u64 tx_mat32_39; - u64 tx_mat40_47; - u64 tx_mat48_55; - u64 tx_mat56_63; + u64 tx_mat0_n[0x8]; +#define TX_MAT_SET(fifo, msi) vBIT(msi, (8 * fifo), 8) - u8 unused_1[0x10]; + u8 unused_1[0x8]; + u64 stat_byte_cnt; +#define STAT_BC(n) vBIT(n,4,12) /* Automated statistics collection */ u64 stat_cfg; @@ -246,6 +261,7 @@ typedef struct _XENA_dev_config { #define STAT_TRSF_PER(n) TBD #define PER_SEC 0x208d5 #define SET_UPDT_PERIOD(n) vBIT((PER_SEC*n),32,32) +#define SET_UPDT_CLICKS(val) vBIT(val, 32, 32) u64 stat_addr; @@ -267,8 +283,15 @@ typedef struct _XENA_dev_config { u64 gpio_control; #define GPIO_CTRL_GPIO_0 BIT(8) + u64 misc_control; +#define MISC_LINK_STABILITY_PRD(val) vBIT(val,29,3) + + u8 unused7_1[0x240 - 0x208]; + + u64 wreq_split_mask; +#define WREQ_SPLIT_MASK_SET_MASK(val) vBIT(val, 52, 12) - u8 unused7[0x600]; + u8 unused7_2[0x800 - 0x248]; /* TxDMA registers */ u64 txdma_int_status; @@ -290,6 +313,7 @@ typedef struct _XENA_dev_config { u64 pcc_err_reg; #define PCC_FB_ECC_DB_ERR vBIT(0xFF, 16, 8) +#define PCC_ENABLE_FOUR vBIT(0x0F,0,8) u64 pcc_err_mask; u64 pcc_err_alarm; @@ -468,6 +492,7 @@ typedef struct _XENA_dev_config { #define PRC_CTRL_NO_SNOOP (BIT(22)|BIT(23)) #define PRC_CTRL_NO_SNOOP_DESC BIT(22) #define PRC_CTRL_NO_SNOOP_BUFF BIT(23) +#define PRC_CTRL_BIMODAL_INTERRUPT BIT(37) #define PRC_CTRL_RXD_BACKOFF_INTERVAL(val) vBIT(val,40,24) u64 prc_alarm_action; @@ -691,6 +716,10 @@ typedef struct _XENA_dev_config { #define MC_ERR_REG_MIRI_CRI_ERR_0 BIT(22) #define MC_ERR_REG_MIRI_CRI_ERR_1 BIT(23) #define MC_ERR_REG_SM_ERR BIT(31) +#define MC_ERR_REG_ECC_ALL_SNG (BIT(6) | \ + BIT(7) | BIT(17) | BIT(19)) +#define MC_ERR_REG_ECC_ALL_DBL (BIT(14) | \ + BIT(15) | BIT(18) | BIT(20)) u64 mc_err_mask; u64 mc_err_alarm; @@ -736,7 +765,19 @@ typedef struct _XENA_dev_config { u64 mc_rldram_test_d1; u8 unused24[0x300 - 0x288]; u64 mc_rldram_test_d2; - u8 unused25[0x700 - 0x308]; + + u8 unused24_1[0x360 - 0x308]; + u64 mc_rldram_ctrl; +#define MC_RLDRAM_ENABLE_ODT BIT(7) + + u8 unused24_2[0x640 - 0x368]; + u64 mc_rldram_ref_per_herc; +#define MC_RLDRAM_SET_REF_PERIOD(val) vBIT(val, 0, 16) + + u8 unused24_3[0x660 - 0x648]; + u64 mc_rldram_mrs_herc; + + u8 unused25[0x700 - 0x668]; u64 mc_debug_ctrl; u8 unused26[0x3000 - 0x2f08]; diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index ea638b162d3..7ca78228b10 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -11,29 +11,28 @@ * See the file COPYING in this distribution for more information. * * Credits: - * Jeff Garzik : For pointing out the improper error condition - * check in the s2io_xmit routine and also some - * issues in the Tx watch dog function. Also for - * patiently answering all those innumerable + * Jeff Garzik : For pointing out the improper error condition + * check in the s2io_xmit routine and also some + * issues in the Tx watch dog function. Also for + * patiently answering all those innumerable * questions regaring the 2.6 porting issues. * Stephen Hemminger : Providing proper 2.6 porting mechanism for some * macros available only in 2.6 Kernel. - * Francois Romieu : For pointing out all code part that were + * Francois Romieu : For pointing out all code part that were * deprecated and also styling related comments. - * Grant Grundler : For helping me get rid of some Architecture + * Grant Grundler : For helping me get rid of some Architecture * dependent code. * Christopher Hellwig : Some more 2.6 specific issues in the driver. - * + * * The module loadable parameters that are supported by the driver and a brief * explaination of all the variables. - * rx_ring_num : This can be used to program the number of receive rings used - * in the driver. - * rx_ring_len: This defines the number of descriptors each ring can have. This + * rx_ring_num : This can be used to program the number of receive rings used + * in the driver. + * rx_ring_len: This defines the number of descriptors each ring can have. This * is also an array of size 8. * tx_fifo_num: This defines the number of Tx FIFOs thats used int the driver. - * tx_fifo_len: This too is an array of 8. Each element defines the number of + * tx_fifo_len: This too is an array of 8. Each element defines the number of * Tx descriptors that can be associated with each corresponding FIFO. - * in PCI Configuration space. ************************************************************************/ #include <linux/config.h> @@ -56,27 +55,39 @@ #include <linux/ethtool.h> #include <linux/version.h> #include <linux/workqueue.h> +#include <linux/if_vlan.h> -#include <asm/io.h> #include <asm/system.h> #include <asm/uaccess.h> +#include <asm/io.h> /* local include */ #include "s2io.h" #include "s2io-regs.h" /* S2io Driver name & version. */ -static char s2io_driver_name[] = "s2io"; -static char s2io_driver_version[] = "Version 1.7.7.1"; +static char s2io_driver_name[] = "Neterion"; +static char s2io_driver_version[] = "Version 2.0.3.1"; + +static inline int RXD_IS_UP2DT(RxD_t *rxdp) +{ + int ret; + + ret = ((!(rxdp->Control_1 & RXD_OWN_XENA)) && + (GET_RXD_MARKER(rxdp->Control_2) != THE_RXD_MARK)); -/* + return ret; +} + +/* * Cards with following subsystem_id have a link state indication * problem, 600B, 600C, 600D, 640B, 640C and 640D. * macro below identifies these cards given the subsystem_id. */ -#define CARDS_WITH_FAULTY_LINK_INDICATORS(subid) \ - (((subid >= 0x600B) && (subid <= 0x600D)) || \ - ((subid >= 0x640B) && (subid <= 0x640D))) ? 1 : 0 +#define CARDS_WITH_FAULTY_LINK_INDICATORS(dev_type, subid) \ + (dev_type == XFRAME_I_DEVICE) ? \ + ((((subid >= 0x600B) && (subid <= 0x600D)) || \ + ((subid >= 0x640B) && (subid <= 0x640D))) ? 1 : 0) : 0 #define LINK_IS_UP(val64) (!(val64 & (ADAPTER_STATUS_RMAC_REMOTE_FAULT | \ ADAPTER_STATUS_RMAC_LOCAL_FAULT))) @@ -86,9 +97,12 @@ static char s2io_driver_version[] = "Version 1.7.7.1"; static inline int rx_buffer_level(nic_t * sp, int rxb_size, int ring) { int level = 0; - if ((sp->pkt_cnt[ring] - rxb_size) > 16) { + mac_info_t *mac_control; + + mac_control = &sp->mac_control; + if ((mac_control->rings[ring].pkt_cnt - rxb_size) > 16) { level = LOW; - if ((sp->pkt_cnt[ring] - rxb_size) < MAX_RXDS_PER_BLOCK) { + if (rxb_size <= MAX_RXDS_PER_BLOCK) { level = PANIC; } } @@ -145,6 +159,9 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = { {"rmac_pause_cnt"}, {"rmac_accepted_ip"}, {"rmac_err_tcp"}, + {"\n DRIVER STATISTICS"}, + {"single_bit_ecc_errs"}, + {"double_bit_ecc_errs"}, }; #define S2IO_STAT_LEN sizeof(ethtool_stats_keys)/ ETH_GSTRING_LEN @@ -153,8 +170,37 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = { #define S2IO_TEST_LEN sizeof(s2io_gstrings) / ETH_GSTRING_LEN #define S2IO_STRINGS_LEN S2IO_TEST_LEN * ETH_GSTRING_LEN +#define S2IO_TIMER_CONF(timer, handle, arg, exp) \ + init_timer(&timer); \ + timer.function = handle; \ + timer.data = (unsigned long) arg; \ + mod_timer(&timer, (jiffies + exp)) \ + +/* Add the vlan */ +static void s2io_vlan_rx_register(struct net_device *dev, + struct vlan_group *grp) +{ + nic_t *nic = dev->priv; + unsigned long flags; + + spin_lock_irqsave(&nic->tx_lock, flags); + nic->vlgrp = grp; + spin_unlock_irqrestore(&nic->tx_lock, flags); +} + +/* Unregister the vlan */ +static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid) +{ + nic_t *nic = dev->priv; + unsigned long flags; + + spin_lock_irqsave(&nic->tx_lock, flags); + if (nic->vlgrp) + nic->vlgrp->vlan_devices[vid] = NULL; + spin_unlock_irqrestore(&nic->tx_lock, flags); +} -/* +/* * Constants to be programmed into the Xena's registers, to configure * the XAUI. */ @@ -162,7 +208,28 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = { #define SWITCH_SIGN 0xA5A5A5A5A5A5A5A5ULL #define END_SIGN 0x0 -static u64 default_mdio_cfg[] = { +static u64 herc_act_dtx_cfg[] = { + /* Set address */ + 0x8000051536750000ULL, 0x80000515367500E0ULL, + /* Write data */ + 0x8000051536750004ULL, 0x80000515367500E4ULL, + /* Set address */ + 0x80010515003F0000ULL, 0x80010515003F00E0ULL, + /* Write data */ + 0x80010515003F0004ULL, 0x80010515003F00E4ULL, + /* Set address */ + 0x801205150D440000ULL, 0x801205150D4400E0ULL, + /* Write data */ + 0x801205150D440004ULL, 0x801205150D4400E4ULL, + /* Set address */ + 0x80020515F2100000ULL, 0x80020515F21000E0ULL, + /* Write data */ + 0x80020515F2100004ULL, 0x80020515F21000E4ULL, + /* Done */ + END_SIGN +}; + +static u64 xena_mdio_cfg[] = { /* Reset PMA PLL */ 0xC001010000000000ULL, 0xC0010100000000E0ULL, 0xC0010100008000E4ULL, @@ -172,7 +239,7 @@ static u64 default_mdio_cfg[] = { END_SIGN }; -static u64 default_dtx_cfg[] = { +static u64 xena_dtx_cfg[] = { 0x8000051500000000ULL, 0x80000515000000E0ULL, 0x80000515D93500E4ULL, 0x8001051500000000ULL, 0x80010515000000E0ULL, 0x80010515001E00E4ULL, @@ -196,8 +263,7 @@ static u64 default_dtx_cfg[] = { END_SIGN }; - -/* +/* * Constants for Fixing the MacAddress problem seen mostly on * Alpha machines. */ @@ -226,20 +292,25 @@ static unsigned int tx_fifo_len[MAX_TX_FIFOS] = static unsigned int rx_ring_num = 1; static unsigned int rx_ring_sz[MAX_RX_RINGS] = {[0 ...(MAX_RX_RINGS - 1)] = 0 }; -static unsigned int Stats_refresh_time = 4; +static unsigned int rts_frm_len[MAX_RX_RINGS] = + {[0 ...(MAX_RX_RINGS - 1)] = 0 }; +static unsigned int use_continuous_tx_intrs = 1; static unsigned int rmac_pause_time = 65535; static unsigned int mc_pause_threshold_q0q3 = 187; static unsigned int mc_pause_threshold_q4q7 = 187; static unsigned int shared_splits; static unsigned int tmac_util_period = 5; static unsigned int rmac_util_period = 5; +static unsigned int bimodal = 0; #ifndef CONFIG_S2IO_NAPI static unsigned int indicate_max_pkts; #endif +/* Frequency of Rx desc syncs expressed as power of 2 */ +static unsigned int rxsync_frequency = 3; -/* +/* * S2IO device table. - * This table lists all the devices that this driver supports. + * This table lists all the devices that this driver supports. */ static struct pci_device_id s2io_tbl[] __devinitdata = { {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_WIN, @@ -247,9 +318,9 @@ static struct pci_device_id s2io_tbl[] __devinitdata = { {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_UNI, PCI_ANY_ID, PCI_ANY_ID}, {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_WIN, - PCI_ANY_ID, PCI_ANY_ID}, - {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_UNI, - PCI_ANY_ID, PCI_ANY_ID}, + PCI_ANY_ID, PCI_ANY_ID}, + {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_UNI, + PCI_ANY_ID, PCI_ANY_ID}, {0,} }; @@ -268,8 +339,8 @@ static struct pci_driver s2io_driver = { /** * init_shared_mem - Allocation and Initialization of Memory * @nic: Device private variable. - * Description: The function allocates all the memory areas shared - * between the NIC and the driver. This includes Tx descriptors, + * Description: The function allocates all the memory areas shared + * between the NIC and the driver. This includes Tx descriptors, * Rx descriptors and the statistics block. */ @@ -279,11 +350,11 @@ static int init_shared_mem(struct s2io_nic *nic) void *tmp_v_addr, *tmp_v_addr_next; dma_addr_t tmp_p_addr, tmp_p_addr_next; RxD_block_t *pre_rxd_blk = NULL; - int i, j, blk_cnt; + int i, j, blk_cnt, rx_sz, tx_sz; int lst_size, lst_per_page; struct net_device *dev = nic->dev; #ifdef CONFIG_2BUFF_MODE - unsigned long tmp; + u64 tmp; buffAdd_t *ba; #endif @@ -300,36 +371,41 @@ static int init_shared_mem(struct s2io_nic *nic) size += config->tx_cfg[i].fifo_len; } if (size > MAX_AVAILABLE_TXDS) { - DBG_PRINT(ERR_DBG, "%s: Total number of Tx FIFOs ", - dev->name); - DBG_PRINT(ERR_DBG, "exceeds the maximum value "); - DBG_PRINT(ERR_DBG, "that can be used\n"); + DBG_PRINT(ERR_DBG, "%s: Requested TxDs too high, ", + __FUNCTION__); + DBG_PRINT(ERR_DBG, "Requested: %d, max supported: 8192\n", size); return FAILURE; } lst_size = (sizeof(TxD_t) * config->max_txds); + tx_sz = lst_size * size; lst_per_page = PAGE_SIZE / lst_size; for (i = 0; i < config->tx_fifo_num; i++) { int fifo_len = config->tx_cfg[i].fifo_len; int list_holder_size = fifo_len * sizeof(list_info_hold_t); - nic->list_info[i] = kmalloc(list_holder_size, GFP_KERNEL); - if (!nic->list_info[i]) { + mac_control->fifos[i].list_info = kmalloc(list_holder_size, + GFP_KERNEL); + if (!mac_control->fifos[i].list_info) { DBG_PRINT(ERR_DBG, "Malloc failed for list_info\n"); return -ENOMEM; } - memset(nic->list_info[i], 0, list_holder_size); + memset(mac_control->fifos[i].list_info, 0, list_holder_size); } for (i = 0; i < config->tx_fifo_num; i++) { int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len, lst_per_page); - mac_control->tx_curr_put_info[i].offset = 0; - mac_control->tx_curr_put_info[i].fifo_len = + mac_control->fifos[i].tx_curr_put_info.offset = 0; + mac_control->fifos[i].tx_curr_put_info.fifo_len = config->tx_cfg[i].fifo_len - 1; - mac_control->tx_curr_get_info[i].offset = 0; - mac_control->tx_curr_get_info[i].fifo_len = + mac_control->fifos[i].tx_curr_get_info.offset = 0; + mac_control->fifos[i].tx_curr_get_info.fifo_len = config->tx_cfg[i].fifo_len - 1; + mac_control->fifos[i].fifo_no = i; + mac_control->fifos[i].nic = nic; + mac_control->fifos[i].max_txds = MAX_SKB_FRAGS; + for (j = 0; j < page_num; j++) { int k = 0; dma_addr_t tmp_p; @@ -345,16 +421,15 @@ static int init_shared_mem(struct s2io_nic *nic) while (k < lst_per_page) { int l = (j * lst_per_page) + k; if (l == config->tx_cfg[i].fifo_len) - goto end_txd_alloc; - nic->list_info[i][l].list_virt_addr = + break; + mac_control->fifos[i].list_info[l].list_virt_addr = tmp_v + (k * lst_size); - nic->list_info[i][l].list_phy_addr = + mac_control->fifos[i].list_info[l].list_phy_addr = tmp_p + (k * lst_size); k++; } } } - end_txd_alloc: /* Allocation and initialization of RXDs in Rings */ size = 0; @@ -367,21 +442,26 @@ static int init_shared_mem(struct s2io_nic *nic) return FAILURE; } size += config->rx_cfg[i].num_rxd; - nic->block_count[i] = + mac_control->rings[i].block_count = config->rx_cfg[i].num_rxd / (MAX_RXDS_PER_BLOCK + 1); - nic->pkt_cnt[i] = - config->rx_cfg[i].num_rxd - nic->block_count[i]; + mac_control->rings[i].pkt_cnt = + config->rx_cfg[i].num_rxd - mac_control->rings[i].block_count; } + size = (size * (sizeof(RxD_t))); + rx_sz = size; for (i = 0; i < config->rx_ring_num; i++) { - mac_control->rx_curr_get_info[i].block_index = 0; - mac_control->rx_curr_get_info[i].offset = 0; - mac_control->rx_curr_get_info[i].ring_len = + mac_control->rings[i].rx_curr_get_info.block_index = 0; + mac_control->rings[i].rx_curr_get_info.offset = 0; + mac_control->rings[i].rx_curr_get_info.ring_len = config->rx_cfg[i].num_rxd - 1; - mac_control->rx_curr_put_info[i].block_index = 0; - mac_control->rx_curr_put_info[i].offset = 0; - mac_control->rx_curr_put_info[i].ring_len = + mac_control->rings[i].rx_curr_put_info.block_index = 0; + mac_control->rings[i].rx_curr_put_info.offset = 0; + mac_control->rings[i].rx_curr_put_info.ring_len = config->rx_cfg[i].num_rxd - 1; + mac_control->rings[i].nic = nic; + mac_control->rings[i].ring_no = i; + blk_cnt = config->rx_cfg[i].num_rxd / (MAX_RXDS_PER_BLOCK + 1); /* Allocating all the Rx blocks */ @@ -395,32 +475,36 @@ static int init_shared_mem(struct s2io_nic *nic) &tmp_p_addr); if (tmp_v_addr == NULL) { /* - * In case of failure, free_shared_mem() - * is called, which should free any - * memory that was alloced till the + * In case of failure, free_shared_mem() + * is called, which should free any + * memory that was alloced till the * failure happened. */ - nic->rx_blocks[i][j].block_virt_addr = + mac_control->rings[i].rx_blocks[j].block_virt_addr = tmp_v_addr; return -ENOMEM; } memset(tmp_v_addr, 0, size); - nic->rx_blocks[i][j].block_virt_addr = tmp_v_addr; - nic->rx_blocks[i][j].block_dma_addr = tmp_p_addr; + mac_control->rings[i].rx_blocks[j].block_virt_addr = + tmp_v_addr; + mac_control->rings[i].rx_blocks[j].block_dma_addr = + tmp_p_addr; } /* Interlinking all Rx Blocks */ for (j = 0; j < blk_cnt; j++) { - tmp_v_addr = nic->rx_blocks[i][j].block_virt_addr; + tmp_v_addr = + mac_control->rings[i].rx_blocks[j].block_virt_addr; tmp_v_addr_next = - nic->rx_blocks[i][(j + 1) % + mac_control->rings[i].rx_blocks[(j + 1) % blk_cnt].block_virt_addr; - tmp_p_addr = nic->rx_blocks[i][j].block_dma_addr; + tmp_p_addr = + mac_control->rings[i].rx_blocks[j].block_dma_addr; tmp_p_addr_next = - nic->rx_blocks[i][(j + 1) % + mac_control->rings[i].rx_blocks[(j + 1) % blk_cnt].block_dma_addr; pre_rxd_blk = (RxD_block_t *) tmp_v_addr; - pre_rxd_blk->reserved_1 = END_OF_BLOCK; /* last RxD + pre_rxd_blk->reserved_1 = END_OF_BLOCK; /* last RxD * marker. */ #ifndef CONFIG_2BUFF_MODE @@ -433,43 +517,43 @@ static int init_shared_mem(struct s2io_nic *nic) } #ifdef CONFIG_2BUFF_MODE - /* + /* * Allocation of Storages for buffer addresses in 2BUFF mode * and the buffers as well. */ for (i = 0; i < config->rx_ring_num; i++) { blk_cnt = config->rx_cfg[i].num_rxd / (MAX_RXDS_PER_BLOCK + 1); - nic->ba[i] = kmalloc((sizeof(buffAdd_t *) * blk_cnt), + mac_control->rings[i].ba = kmalloc((sizeof(buffAdd_t *) * blk_cnt), GFP_KERNEL); - if (!nic->ba[i]) + if (!mac_control->rings[i].ba) return -ENOMEM; for (j = 0; j < blk_cnt; j++) { int k = 0; - nic->ba[i][j] = kmalloc((sizeof(buffAdd_t) * + mac_control->rings[i].ba[j] = kmalloc((sizeof(buffAdd_t) * (MAX_RXDS_PER_BLOCK + 1)), GFP_KERNEL); - if (!nic->ba[i][j]) + if (!mac_control->rings[i].ba[j]) return -ENOMEM; while (k != MAX_RXDS_PER_BLOCK) { - ba = &nic->ba[i][j][k]; + ba = &mac_control->rings[i].ba[j][k]; - ba->ba_0_org = kmalloc + ba->ba_0_org = (void *) kmalloc (BUF0_LEN + ALIGN_SIZE, GFP_KERNEL); if (!ba->ba_0_org) return -ENOMEM; - tmp = (unsigned long) ba->ba_0_org; + tmp = (u64) ba->ba_0_org; tmp += ALIGN_SIZE; - tmp &= ~((unsigned long) ALIGN_SIZE); + tmp &= ~((u64) ALIGN_SIZE); ba->ba_0 = (void *) tmp; - ba->ba_1_org = kmalloc + ba->ba_1_org = (void *) kmalloc (BUF1_LEN + ALIGN_SIZE, GFP_KERNEL); if (!ba->ba_1_org) return -ENOMEM; - tmp = (unsigned long) ba->ba_1_org; + tmp = (u64) ba->ba_1_org; tmp += ALIGN_SIZE; - tmp &= ~((unsigned long) ALIGN_SIZE); + tmp &= ~((u64) ALIGN_SIZE); ba->ba_1 = (void *) tmp; k++; } @@ -483,9 +567,9 @@ static int init_shared_mem(struct s2io_nic *nic) (nic->pdev, size, &mac_control->stats_mem_phy); if (!mac_control->stats_mem) { - /* - * In case of failure, free_shared_mem() is called, which - * should free any memory that was alloced till the + /* + * In case of failure, free_shared_mem() is called, which + * should free any memory that was alloced till the * failure happened. */ return -ENOMEM; @@ -495,15 +579,14 @@ static int init_shared_mem(struct s2io_nic *nic) tmp_v_addr = mac_control->stats_mem; mac_control->stats_info = (StatInfo_t *) tmp_v_addr; memset(tmp_v_addr, 0, size); - DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name, (unsigned long long) tmp_p_addr); return SUCCESS; } -/** - * free_shared_mem - Free the allocated Memory +/** + * free_shared_mem - Free the allocated Memory * @nic: Device private variable. * Description: This function is to free all memory locations allocated by * the init_shared_mem() function and return it to the kernel. @@ -533,15 +616,19 @@ static void free_shared_mem(struct s2io_nic *nic) lst_per_page); for (j = 0; j < page_num; j++) { int mem_blks = (j * lst_per_page); - if (!nic->list_info[i][mem_blks].list_virt_addr) + if ((!mac_control->fifos[i].list_info) || + (!mac_control->fifos[i].list_info[mem_blks]. + list_virt_addr)) break; pci_free_consistent(nic->pdev, PAGE_SIZE, - nic->list_info[i][mem_blks]. + mac_control->fifos[i]. + list_info[mem_blks]. list_virt_addr, - nic->list_info[i][mem_blks]. + mac_control->fifos[i]. + list_info[mem_blks]. list_phy_addr); } - kfree(nic->list_info[i]); + kfree(mac_control->fifos[i].list_info); } #ifndef CONFIG_2BUFF_MODE @@ -550,10 +637,12 @@ static void free_shared_mem(struct s2io_nic *nic) size = SIZE_OF_BLOCK; #endif for (i = 0; i < config->rx_ring_num; i++) { - blk_cnt = nic->block_count[i]; + blk_cnt = mac_control->rings[i].block_count; for (j = 0; j < blk_cnt; j++) { - tmp_v_addr = nic->rx_blocks[i][j].block_virt_addr; - tmp_p_addr = nic->rx_blocks[i][j].block_dma_addr; + tmp_v_addr = mac_control->rings[i].rx_blocks[j]. + block_virt_addr; + tmp_p_addr = mac_control->rings[i].rx_blocks[j]. + block_dma_addr; if (tmp_v_addr == NULL) break; pci_free_consistent(nic->pdev, size, @@ -566,35 +655,21 @@ static void free_shared_mem(struct s2io_nic *nic) for (i = 0; i < config->rx_ring_num; i++) { blk_cnt = config->rx_cfg[i].num_rxd / (MAX_RXDS_PER_BLOCK + 1); - if (!nic->ba[i]) - goto end_free; for (j = 0; j < blk_cnt; j++) { int k = 0; - if (!nic->ba[i][j]) { - kfree(nic->ba[i]); - goto end_free; - } + if (!mac_control->rings[i].ba[j]) + continue; while (k != MAX_RXDS_PER_BLOCK) { - buffAdd_t *ba = &nic->ba[i][j][k]; - if (!ba || !ba->ba_0_org || !ba->ba_1_org) - { - kfree(nic->ba[i]); - kfree(nic->ba[i][j]); - if(ba->ba_0_org) - kfree(ba->ba_0_org); - if(ba->ba_1_org) - kfree(ba->ba_1_org); - goto end_free; - } + buffAdd_t *ba = &mac_control->rings[i].ba[j][k]; kfree(ba->ba_0_org); kfree(ba->ba_1_org); k++; } - kfree(nic->ba[i][j]); + kfree(mac_control->rings[i].ba[j]); } - kfree(nic->ba[i]); + if (mac_control->rings[i].ba) + kfree(mac_control->rings[i].ba); } -end_free: #endif if (mac_control->stats_mem) { @@ -605,12 +680,93 @@ end_free: } } -/** - * init_nic - Initialization of hardware +/** + * s2io_verify_pci_mode - + */ + +static int s2io_verify_pci_mode(nic_t *nic) +{ + XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + register u64 val64 = 0; + int mode; + + val64 = readq(&bar0->pci_mode); + mode = (u8)GET_PCI_MODE(val64); + + if ( val64 & PCI_MODE_UNKNOWN_MODE) + return -1; /* Unknown PCI mode */ + return mode; +} + + +/** + * s2io_print_pci_mode - + */ +static int s2io_print_pci_mode(nic_t *nic) +{ + XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + register u64 val64 = 0; + int mode; + struct config_param *config = &nic->config; + + val64 = readq(&bar0->pci_mode); + mode = (u8)GET_PCI_MODE(val64); + + if ( val64 & PCI_MODE_UNKNOWN_MODE) + return -1; /* Unknown PCI mode */ + + if (val64 & PCI_MODE_32_BITS) { + DBG_PRINT(ERR_DBG, "%s: Device is on 32 bit ", nic->dev->name); + } else { + DBG_PRINT(ERR_DBG, "%s: Device is on 64 bit ", nic->dev->name); + } + + switch(mode) { + case PCI_MODE_PCI_33: + DBG_PRINT(ERR_DBG, "33MHz PCI bus\n"); + config->bus_speed = 33; + break; + case PCI_MODE_PCI_66: + DBG_PRINT(ERR_DBG, "66MHz PCI bus\n"); + config->bus_speed = 133; + break; + case PCI_MODE_PCIX_M1_66: + DBG_PRINT(ERR_DBG, "66MHz PCIX(M1) bus\n"); + config->bus_speed = 133; /* Herc doubles the clock rate */ + break; + case PCI_MODE_PCIX_M1_100: + DBG_PRINT(ERR_DBG, "100MHz PCIX(M1) bus\n"); + config->bus_speed = 200; + break; + case PCI_MODE_PCIX_M1_133: + DBG_PRINT(ERR_DBG, "133MHz PCIX(M1) bus\n"); + config->bus_speed = 266; + break; + case PCI_MODE_PCIX_M2_66: + DBG_PRINT(ERR_DBG, "133MHz PCIX(M2) bus\n"); + config->bus_speed = 133; + break; + case PCI_MODE_PCIX_M2_100: + DBG_PRINT(ERR_DBG, "200MHz PCIX(M2) bus\n"); + config->bus_speed = 200; + break; + case PCI_MODE_PCIX_M2_133: + DBG_PRINT(ERR_DBG, "266MHz PCIX(M2) bus\n"); + config->bus_speed = 266; + break; + default: + return -1; /* Unsupported bus speed */ + } + + return mode; +} + +/** + * init_nic - Initialization of hardware * @nic: device peivate variable - * Description: The function sequentially configures every block - * of the H/W from their reset values. - * Return Value: SUCCESS on success and + * Description: The function sequentially configures every block + * of the H/W from their reset values. + * Return Value: SUCCESS on success and * '-1' on failure (endian settings incorrect). */ @@ -626,21 +782,32 @@ static int init_nic(struct s2io_nic *nic) struct config_param *config; int mdio_cnt = 0, dtx_cnt = 0; unsigned long long mem_share; + int mem_size; mac_control = &nic->mac_control; config = &nic->config; - /* Initialize swapper control register */ - if (s2io_set_swapper(nic)) { + /* to set the swapper controle on the card */ + if(s2io_set_swapper(nic)) { DBG_PRINT(ERR_DBG,"ERROR: Setting Swapper failed\n"); return -1; } + /* + * Herc requires EOI to be removed from reset before XGXS, so.. + */ + if (nic->device_type & XFRAME_II_DEVICE) { + val64 = 0xA500000000ULL; + writeq(val64, &bar0->sw_reset); + msleep(500); + val64 = readq(&bar0->sw_reset); + } + /* Remove XGXS from reset state */ val64 = 0; writeq(val64, &bar0->sw_reset); - val64 = readq(&bar0->sw_reset); msleep(500); + val64 = readq(&bar0->sw_reset); /* Enable Receiving broadcasts */ add = &bar0->mac_cfg; @@ -660,48 +827,58 @@ static int init_nic(struct s2io_nic *nic) val64 = dev->mtu; writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len); - /* - * Configuring the XAUI Interface of Xena. + /* + * Configuring the XAUI Interface of Xena. * *************************************** - * To Configure the Xena's XAUI, one has to write a series - * of 64 bit values into two registers in a particular - * sequence. Hence a macro 'SWITCH_SIGN' has been defined - * which will be defined in the array of configuration values - * (default_dtx_cfg & default_mdio_cfg) at appropriate places - * to switch writing from one regsiter to another. We continue + * To Configure the Xena's XAUI, one has to write a series + * of 64 bit values into two registers in a particular + * sequence. Hence a macro 'SWITCH_SIGN' has been defined + * which will be defined in the array of configuration values + * (xena_dtx_cfg & xena_mdio_cfg) at appropriate places + * to switch writing from one regsiter to another. We continue * writing these values until we encounter the 'END_SIGN' macro. - * For example, After making a series of 21 writes into - * dtx_control register the 'SWITCH_SIGN' appears and hence we + * For example, After making a series of 21 writes into + * dtx_control register the 'SWITCH_SIGN' appears and hence we * start writing into mdio_control until we encounter END_SIGN. */ - while (1) { - dtx_cfg: - while (default_dtx_cfg[dtx_cnt] != END_SIGN) { - if (default_dtx_cfg[dtx_cnt] == SWITCH_SIGN) { - dtx_cnt++; - goto mdio_cfg; - } - SPECIAL_REG_WRITE(default_dtx_cfg[dtx_cnt], + if (nic->device_type & XFRAME_II_DEVICE) { + while (herc_act_dtx_cfg[dtx_cnt] != END_SIGN) { + SPECIAL_REG_WRITE(herc_act_dtx_cfg[dtx_cnt], &bar0->dtx_control, UF); - val64 = readq(&bar0->dtx_control); + if (dtx_cnt & 0x1) + msleep(1); /* Necessary!! */ dtx_cnt++; } - mdio_cfg: - while (default_mdio_cfg[mdio_cnt] != END_SIGN) { - if (default_mdio_cfg[mdio_cnt] == SWITCH_SIGN) { + } else { + while (1) { + dtx_cfg: + while (xena_dtx_cfg[dtx_cnt] != END_SIGN) { + if (xena_dtx_cfg[dtx_cnt] == SWITCH_SIGN) { + dtx_cnt++; + goto mdio_cfg; + } + SPECIAL_REG_WRITE(xena_dtx_cfg[dtx_cnt], + &bar0->dtx_control, UF); + val64 = readq(&bar0->dtx_control); + dtx_cnt++; + } + mdio_cfg: + while (xena_mdio_cfg[mdio_cnt] != END_SIGN) { + if (xena_mdio_cfg[mdio_cnt] == SWITCH_SIGN) { + mdio_cnt++; + goto dtx_cfg; + } + SPECIAL_REG_WRITE(xena_mdio_cfg[mdio_cnt], + &bar0->mdio_control, UF); + val64 = readq(&bar0->mdio_control); mdio_cnt++; + } + if ((xena_dtx_cfg[dtx_cnt] == END_SIGN) && + (xena_mdio_cfg[mdio_cnt] == END_SIGN)) { + break; + } else { goto dtx_cfg; } - SPECIAL_REG_WRITE(default_mdio_cfg[mdio_cnt], - &bar0->mdio_control, UF); - val64 = readq(&bar0->mdio_control); - mdio_cnt++; - } - if ((default_dtx_cfg[dtx_cnt] == END_SIGN) && - (default_mdio_cfg[mdio_cnt] == END_SIGN)) { - break; - } else { - goto dtx_cfg; } } @@ -748,12 +925,20 @@ static int init_nic(struct s2io_nic *nic) val64 |= BIT(0); /* To enable the FIFO partition. */ writeq(val64, &bar0->tx_fifo_partition_0); + /* + * Disable 4 PCCs for Xena1, 2 and 3 as per H/W bug + * SXE-008 TRANSMIT DMA ARBITRATION ISSUE. + */ + if ((nic->device_type == XFRAME_I_DEVICE) && + (get_xena_rev_id(nic->pdev) < 4)) + writeq(PCC_ENABLE_FOUR, &bar0->pcc_enable); + val64 = readq(&bar0->tx_fifo_partition_0); DBG_PRINT(INIT_DBG, "Fifo partition at: 0x%p is: 0x%llx\n", &bar0->tx_fifo_partition_0, (unsigned long long) val64); - /* - * Initialization of Tx_PA_CONFIG register to ignore packet + /* + * Initialization of Tx_PA_CONFIG register to ignore packet * integrity checking. */ val64 = readq(&bar0->tx_pa_cfg); @@ -770,85 +955,304 @@ static int init_nic(struct s2io_nic *nic) } writeq(val64, &bar0->rx_queue_priority); - /* - * Allocating equal share of memory to all the + /* + * Allocating equal share of memory to all the * configured Rings. */ val64 = 0; + if (nic->device_type & XFRAME_II_DEVICE) + mem_size = 32; + else + mem_size = 64; + for (i = 0; i < config->rx_ring_num; i++) { switch (i) { case 0: - mem_share = (64 / config->rx_ring_num + - 64 % config->rx_ring_num); + mem_share = (mem_size / config->rx_ring_num + + mem_size % config->rx_ring_num); val64 |= RX_QUEUE_CFG_Q0_SZ(mem_share); continue; case 1: - mem_share = (64 / config->rx_ring_num); + mem_share = (mem_size / config->rx_ring_num); val64 |= RX_QUEUE_CFG_Q1_SZ(mem_share); continue; case 2: - mem_share = (64 / config->rx_ring_num); + mem_share = (mem_size / config->rx_ring_num); val64 |= RX_QUEUE_CFG_Q2_SZ(mem_share); continue; case 3: - mem_share = (64 / config->rx_ring_num); + mem_share = (mem_size / config->rx_ring_num); val64 |= RX_QUEUE_CFG_Q3_SZ(mem_share); continue; case 4: - mem_share = (64 / config->rx_ring_num); + mem_share = (mem_size / config->rx_ring_num); val64 |= RX_QUEUE_CFG_Q4_SZ(mem_share); continue; case 5: - mem_share = (64 / config->rx_ring_num); + mem_share = (mem_size / config->rx_ring_num); val64 |= RX_QUEUE_CFG_Q5_SZ(mem_share); continue; case 6: - mem_share = (64 / config->rx_ring_num); + mem_share = (mem_size / config->rx_ring_num); val64 |= RX_QUEUE_CFG_Q6_SZ(mem_share); continue; case 7: - mem_share = (64 / config->rx_ring_num); + mem_share = (mem_size / config->rx_ring_num); val64 |= RX_QUEUE_CFG_Q7_SZ(mem_share); continue; } } writeq(val64, &bar0->rx_queue_cfg); - /* - * Initializing the Tx round robin registers to 0. - * Filling Tx and Rx round robin registers as per the - * number of FIFOs and Rings is still TODO. - */ - writeq(0, &bar0->tx_w_round_robin_0); - writeq(0, &bar0->tx_w_round_robin_1); - writeq(0, &bar0->tx_w_round_robin_2); - writeq(0, &bar0->tx_w_round_robin_3); - writeq(0, &bar0->tx_w_round_robin_4); - - /* - * TODO - * Disable Rx steering. Hard coding all packets be steered to - * Queue 0 for now. + /* + * Filling Tx round robin registers + * as per the number of FIFOs */ - val64 = 0x8080808080808080ULL; - writeq(val64, &bar0->rts_qos_steering); + switch (config->tx_fifo_num) { + case 1: + val64 = 0x0000000000000000ULL; + writeq(val64, &bar0->tx_w_round_robin_0); + writeq(val64, &bar0->tx_w_round_robin_1); + writeq(val64, &bar0->tx_w_round_robin_2); + writeq(val64, &bar0->tx_w_round_robin_3); + writeq(val64, &bar0->tx_w_round_robin_4); + break; + case 2: + val64 = 0x0000010000010000ULL; + writeq(val64, &bar0->tx_w_round_robin_0); + val64 = 0x0100000100000100ULL; + writeq(val64, &bar0->tx_w_round_robin_1); + val64 = 0x0001000001000001ULL; + writeq(val64, &bar0->tx_w_round_robin_2); + val64 = 0x0000010000010000ULL; + writeq(val64, &bar0->tx_w_round_robin_3); + val64 = 0x0100000000000000ULL; + writeq(val64, &bar0->tx_w_round_robin_4); + break; + case 3: + val64 = 0x0001000102000001ULL; + writeq(val64, &bar0->tx_w_round_robin_0); + val64 = 0x0001020000010001ULL; + writeq(val64, &bar0->tx_w_round_robin_1); + val64 = 0x0200000100010200ULL; + writeq(val64, &bar0->tx_w_round_robin_2); + val64 = 0x0001000102000001ULL; + writeq(val64, &bar0->tx_w_round_robin_3); + val64 = 0x0001020000000000ULL; + writeq(val64, &bar0->tx_w_round_robin_4); + break; + case 4: + val64 = 0x0001020300010200ULL; + writeq(val64, &bar0->tx_w_round_robin_0); + val64 = 0x0100000102030001ULL; + writeq(val64, &bar0->tx_w_round_robin_1); + val64 = 0x0200010000010203ULL; + writeq(val64, &bar0->tx_w_round_robin_2); + val64 = 0x0001020001000001ULL; + writeq(val64, &bar0->tx_w_round_robin_3); + val64 = 0x0203000100000000ULL; + writeq(val64, &bar0->tx_w_round_robin_4); + break; + case 5: + val64 = 0x0001000203000102ULL; + writeq(val64, &bar0->tx_w_round_robin_0); + val64 = 0x0001020001030004ULL; + writeq(val64, &bar0->tx_w_round_robin_1); + val64 = 0x0001000203000102ULL; + writeq(val64, &bar0->tx_w_round_robin_2); + val64 = 0x0001020001030004ULL; + writeq(val64, &bar0->tx_w_round_robin_3); + val64 = 0x0001000000000000ULL; + writeq(val64, &bar0->tx_w_round_robin_4); + break; + case 6: + val64 = 0x0001020304000102ULL; + writeq(val64, &bar0->tx_w_round_robin_0); + val64 = 0x0304050001020001ULL; + writeq(val64, &bar0->tx_w_round_robin_1); + val64 = 0x0203000100000102ULL; + writeq(val64, &bar0->tx_w_round_robin_2); + val64 = 0x0304000102030405ULL; + writeq(val64, &bar0->tx_w_round_robin_3); + val64 = 0x0001000200000000ULL; + writeq(val64, &bar0->tx_w_round_robin_4); + break; + case 7: + val64 = 0x0001020001020300ULL; + writeq(val64, &bar0->tx_w_round_robin_0); + val64 = 0x0102030400010203ULL; + writeq(val64, &bar0->tx_w_round_robin_1); + val64 = 0x0405060001020001ULL; + writeq(val64, &bar0->tx_w_round_robin_2); + val64 = 0x0304050000010200ULL; + writeq(val64, &bar0->tx_w_round_robin_3); + val64 = 0x0102030000000000ULL; + writeq(val64, &bar0->tx_w_round_robin_4); + break; + case 8: + val64 = 0x0001020300040105ULL; + writeq(val64, &bar0->tx_w_round_robin_0); + val64 = 0x0200030106000204ULL; + writeq(val64, &bar0->tx_w_round_robin_1); + val64 = 0x0103000502010007ULL; + writeq(val64, &bar0->tx_w_round_robin_2); + val64 = 0x0304010002060500ULL; + writeq(val64, &bar0->tx_w_round_robin_3); + val64 = 0x0103020400000000ULL; + writeq(val64, &bar0->tx_w_round_robin_4); + break; + } + + /* Filling the Rx round robin registers as per the + * number of Rings and steering based on QoS. + */ + switch (config->rx_ring_num) { + case 1: + val64 = 0x8080808080808080ULL; + writeq(val64, &bar0->rts_qos_steering); + break; + case 2: + val64 = 0x0000010000010000ULL; + writeq(val64, &bar0->rx_w_round_robin_0); + val64 = 0x0100000100000100ULL; + writeq(val64, &bar0->rx_w_round_robin_1); + val64 = 0x0001000001000001ULL; + writeq(val64, &bar0->rx_w_round_robin_2); + val64 = 0x0000010000010000ULL; + writeq(val64, &bar0->rx_w_round_robin_3); + val64 = 0x0100000000000000ULL; + writeq(val64, &bar0->rx_w_round_robin_4); + + val64 = 0x8080808040404040ULL; + writeq(val64, &bar0->rts_qos_steering); + break; + case 3: + val64 = 0x0001000102000001ULL; + writeq(val64, &bar0->rx_w_round_robin_0); + val64 = 0x0001020000010001ULL; + writeq(val64, &bar0->rx_w_round_robin_1); + val64 = 0x0200000100010200ULL; + writeq(val64, &bar0->rx_w_round_robin_2); + val64 = 0x0001000102000001ULL; + writeq(val64, &bar0->rx_w_round_robin_3); + val64 = 0x0001020000000000ULL; + writeq(val64, &bar0->rx_w_round_robin_4); + + val64 = 0x8080804040402020ULL; + writeq(val64, &bar0->rts_qos_steering); + break; + case 4: + val64 = 0x0001020300010200ULL; + writeq(val64, &bar0->rx_w_round_robin_0); + val64 = 0x0100000102030001ULL; + writeq(val64, &bar0->rx_w_round_robin_1); + val64 = 0x0200010000010203ULL; + writeq(val64, &bar0->rx_w_round_robin_2); + val64 = 0x0001020001000001ULL; + writeq(val64, &bar0->rx_w_round_robin_3); + val64 = 0x0203000100000000ULL; + writeq(val64, &bar0->rx_w_round_robin_4); + + val64 = 0x8080404020201010ULL; + writeq(val64, &bar0->rts_qos_steering); + break; + case 5: + val64 = 0x0001000203000102ULL; + writeq(val64, &bar0->rx_w_round_robin_0); + val64 = 0x0001020001030004ULL; + writeq(val64, &bar0->rx_w_round_robin_1); + val64 = 0x0001000203000102ULL; + writeq(val64, &bar0->rx_w_round_robin_2); + val64 = 0x0001020001030004ULL; + writeq(val64, &bar0->rx_w_round_robin_3); + val64 = 0x0001000000000000ULL; + writeq(val64, &bar0->rx_w_round_robin_4); + + val64 = 0x8080404020201008ULL; + writeq(val64, &bar0->rts_qos_steering); + break; + case 6: + val64 = 0x0001020304000102ULL; + writeq(val64, &bar0->rx_w_round_robin_0); + val64 = 0x0304050001020001ULL; + writeq(val64, &bar0->rx_w_round_robin_1); + val64 = 0x0203000100000102ULL; + writeq(val64, &bar0->rx_w_round_robin_2); + val64 = 0x0304000102030405ULL; + writeq(val64, &bar0->rx_w_round_robin_3); + val64 = 0x0001000200000000ULL; + writeq(val64, &bar0->rx_w_round_robin_4); + + val64 = 0x8080404020100804ULL; + writeq(val64, &bar0->rts_qos_steering); + break; + case 7: + val64 = 0x0001020001020300ULL; + writeq(val64, &bar0->rx_w_round_robin_0); + val64 = 0x0102030400010203ULL; + writeq(val64, &bar0->rx_w_round_robin_1); + val64 = 0x0405060001020001ULL; + writeq(val64, &bar0->rx_w_round_robin_2); + val64 = 0x0304050000010200ULL; + writeq(val64, &bar0->rx_w_round_robin_3); + val64 = 0x0102030000000000ULL; + writeq(val64, &bar0->rx_w_round_robin_4); + + val64 = 0x8080402010080402ULL; + writeq(val64, &bar0->rts_qos_steering); + break; + case 8: + val64 = 0x0001020300040105ULL; + writeq(val64, &bar0->rx_w_round_robin_0); + val64 = 0x0200030106000204ULL; + writeq(val64, &bar0->rx_w_round_robin_1); + val64 = 0x0103000502010007ULL; + writeq(val64, &bar0->rx_w_round_robin_2); + val64 = 0x0304010002060500ULL; + writeq(val64, &bar0->rx_w_round_robin_3); + val64 = 0x0103020400000000ULL; + writeq(val64, &bar0->rx_w_round_robin_4); + + val64 = 0x8040201008040201ULL; + writeq(val64, &bar0->rts_qos_steering); + break; + } /* UDP Fix */ val64 = 0; - for (i = 1; i < 8; i++) + for (i = 0; i < 8; i++) + writeq(val64, &bar0->rts_frm_len_n[i]); + + /* Set the default rts frame length for the rings configured */ + val64 = MAC_RTS_FRM_LEN_SET(dev->mtu+22); + for (i = 0 ; i < config->rx_ring_num ; i++) writeq(val64, &bar0->rts_frm_len_n[i]); - /* Set rts_frm_len register for fifo 0 */ - writeq(MAC_RTS_FRM_LEN_SET(dev->mtu + 22), - &bar0->rts_frm_len_n[0]); + /* Set the frame length for the configured rings + * desired by the user + */ + for (i = 0; i < config->rx_ring_num; i++) { + /* If rts_frm_len[i] == 0 then it is assumed that user not + * specified frame length steering. + * If the user provides the frame length then program + * the rts_frm_len register for those values or else + * leave it as it is. + */ + if (rts_frm_len[i] != 0) { + writeq(MAC_RTS_FRM_LEN_SET(rts_frm_len[i]), + &bar0->rts_frm_len_n[i]); + } + } - /* Enable statistics */ + /* Program statistics memory */ writeq(mac_control->stats_mem_phy, &bar0->stat_addr); - val64 = SET_UPDT_PERIOD(Stats_refresh_time) | - STAT_CFG_STAT_RO | STAT_CFG_STAT_EN; - writeq(val64, &bar0->stat_cfg); - /* + if (nic->device_type == XFRAME_II_DEVICE) { + val64 = STAT_BC(0x320); + writeq(val64, &bar0->stat_byte_cnt); + } + + /* * Initializing the sampling rate for the device to calculate the * bandwidth utilization. */ @@ -857,30 +1261,38 @@ static int init_nic(struct s2io_nic *nic) writeq(val64, &bar0->mac_link_util); - /* - * Initializing the Transmit and Receive Traffic Interrupt + /* + * Initializing the Transmit and Receive Traffic Interrupt * Scheme. */ - /* TTI Initialization. Default Tx timer gets us about + /* + * TTI Initialization. Default Tx timer gets us about * 250 interrupts per sec. Continuous interrupts are enabled * by default. */ - val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078) | - TTI_DATA1_MEM_TX_URNG_A(0xA) | + if (nic->device_type == XFRAME_II_DEVICE) { + int count = (nic->config.bus_speed * 125)/2; + val64 = TTI_DATA1_MEM_TX_TIMER_VAL(count); + } else { + + val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078); + } + val64 |= TTI_DATA1_MEM_TX_URNG_A(0xA) | TTI_DATA1_MEM_TX_URNG_B(0x10) | - TTI_DATA1_MEM_TX_URNG_C(0x30) | TTI_DATA1_MEM_TX_TIMER_AC_EN | - TTI_DATA1_MEM_TX_TIMER_CI_EN; + TTI_DATA1_MEM_TX_URNG_C(0x30) | TTI_DATA1_MEM_TX_TIMER_AC_EN; + if (use_continuous_tx_intrs) + val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN; writeq(val64, &bar0->tti_data1_mem); val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) | TTI_DATA2_MEM_TX_UFC_B(0x20) | - TTI_DATA2_MEM_TX_UFC_C(0x40) | TTI_DATA2_MEM_TX_UFC_D(0x80); + TTI_DATA2_MEM_TX_UFC_C(0x70) | TTI_DATA2_MEM_TX_UFC_D(0x80); writeq(val64, &bar0->tti_data2_mem); val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD; writeq(val64, &bar0->tti_command_mem); - /* + /* * Once the operation completes, the Strobe bit of the command * register will be reset. We poll for this particular condition * We wait for a maximum of 500ms for the operation to complete, @@ -901,52 +1313,97 @@ static int init_nic(struct s2io_nic *nic) time++; } - /* RTI Initialization */ - val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF) | - RTI_DATA1_MEM_RX_URNG_A(0xA) | - RTI_DATA1_MEM_RX_URNG_B(0x10) | - RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN; + if (nic->config.bimodal) { + int k = 0; + for (k = 0; k < config->rx_ring_num; k++) { + val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD; + val64 |= TTI_CMD_MEM_OFFSET(0x38+k); + writeq(val64, &bar0->tti_command_mem); + + /* + * Once the operation completes, the Strobe bit of the command + * register will be reset. We poll for this particular condition + * We wait for a maximum of 500ms for the operation to complete, + * if it's not complete by then we return error. + */ + time = 0; + while (TRUE) { + val64 = readq(&bar0->tti_command_mem); + if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) { + break; + } + if (time > 10) { + DBG_PRINT(ERR_DBG, + "%s: TTI init Failed\n", + dev->name); + return -1; + } + time++; + msleep(50); + } + } + } else { - writeq(val64, &bar0->rti_data1_mem); + /* RTI Initialization */ + if (nic->device_type == XFRAME_II_DEVICE) { + /* + * Programmed to generate Apprx 500 Intrs per + * second + */ + int count = (nic->config.bus_speed * 125)/4; + val64 = RTI_DATA1_MEM_RX_TIMER_VAL(count); + } else { + val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF); + } + val64 |= RTI_DATA1_MEM_RX_URNG_A(0xA) | + RTI_DATA1_MEM_RX_URNG_B(0x10) | + RTI_DATA1_MEM_RX_URNG_C(0x30) | RTI_DATA1_MEM_RX_TIMER_AC_EN; - val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) | - RTI_DATA2_MEM_RX_UFC_B(0x2) | - RTI_DATA2_MEM_RX_UFC_C(0x40) | RTI_DATA2_MEM_RX_UFC_D(0x80); - writeq(val64, &bar0->rti_data2_mem); + writeq(val64, &bar0->rti_data1_mem); - val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD; - writeq(val64, &bar0->rti_command_mem); + val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) | + RTI_DATA2_MEM_RX_UFC_B(0x2) | + RTI_DATA2_MEM_RX_UFC_C(0x40) | RTI_DATA2_MEM_RX_UFC_D(0x80); + writeq(val64, &bar0->rti_data2_mem); - /* - * Once the operation completes, the Strobe bit of the command - * register will be reset. We poll for this particular condition - * We wait for a maximum of 500ms for the operation to complete, - * if it's not complete by then we return error. - */ - time = 0; - while (TRUE) { - val64 = readq(&bar0->rti_command_mem); - if (!(val64 & TTI_CMD_MEM_STROBE_NEW_CMD)) { - break; - } - if (time > 10) { - DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n", - dev->name); - return -1; + for (i = 0; i < config->rx_ring_num; i++) { + val64 = RTI_CMD_MEM_WE | RTI_CMD_MEM_STROBE_NEW_CMD + | RTI_CMD_MEM_OFFSET(i); + writeq(val64, &bar0->rti_command_mem); + + /* + * Once the operation completes, the Strobe bit of the + * command register will be reset. We poll for this + * particular condition. We wait for a maximum of 500ms + * for the operation to complete, if it's not complete + * by then we return error. + */ + time = 0; + while (TRUE) { + val64 = readq(&bar0->rti_command_mem); + if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD)) { + break; + } + if (time > 10) { + DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n", + dev->name); + return -1; + } + time++; + msleep(50); + } } - time++; - msleep(50); } - /* - * Initializing proper values as Pause threshold into all + /* + * Initializing proper values as Pause threshold into all * the 8 Queues on Rx side. */ writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q0q3); writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q4q7); /* Disable RMAC PAD STRIPPING */ - add = &bar0->mac_cfg; + add = (void *) &bar0->mac_cfg; val64 = readq(&bar0->mac_cfg); val64 &= ~(MAC_CFG_RMAC_STRIP_PAD); writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); @@ -955,8 +1412,8 @@ static int init_nic(struct s2io_nic *nic) writel((u32) (val64 >> 32), (add + 4)); val64 = readq(&bar0->mac_cfg); - /* - * Set the time value to be inserted in the pause frame + /* + * Set the time value to be inserted in the pause frame * generated by xena. */ val64 = readq(&bar0->rmac_pause_cfg); @@ -964,7 +1421,7 @@ static int init_nic(struct s2io_nic *nic) val64 |= RMAC_PAUSE_HG_PTIME(nic->mac_control.rmac_pause_time); writeq(val64, &bar0->rmac_pause_cfg); - /* + /* * Set the Threshold Limit for Generating the pause frame * If the amount of data in any Queue exceeds ratio of * (mac_control.mc_pause_threshold_q0q3 or q4q7)/256 @@ -988,25 +1445,54 @@ static int init_nic(struct s2io_nic *nic) } writeq(val64, &bar0->mc_pause_thresh_q4q7); - /* - * TxDMA will stop Read request if the number of read split has + /* + * TxDMA will stop Read request if the number of read split has * exceeded the limit pointed by shared_splits */ val64 = readq(&bar0->pic_control); val64 |= PIC_CNTL_SHARED_SPLITS(shared_splits); writeq(val64, &bar0->pic_control); + /* + * Programming the Herc to split every write transaction + * that does not start on an ADB to reduce disconnects. + */ + if (nic->device_type == XFRAME_II_DEVICE) { + val64 = WREQ_SPLIT_MASK_SET_MASK(255); + writeq(val64, &bar0->wreq_split_mask); + } + + /* Setting Link stability period to 64 ms */ + if (nic->device_type == XFRAME_II_DEVICE) { + val64 = MISC_LINK_STABILITY_PRD(3); + writeq(val64, &bar0->misc_control); + } + return SUCCESS; } +#define LINK_UP_DOWN_INTERRUPT 1 +#define MAC_RMAC_ERR_TIMER 2 -/** - * en_dis_able_nic_intrs - Enable or Disable the interrupts +#if defined(CONFIG_MSI_MODE) || defined(CONFIG_MSIX_MODE) +#define s2io_link_fault_indication(x) MAC_RMAC_ERR_TIMER +#else +int s2io_link_fault_indication(nic_t *nic) +{ + if (nic->device_type == XFRAME_II_DEVICE) + return LINK_UP_DOWN_INTERRUPT; + else + return MAC_RMAC_ERR_TIMER; +} +#endif + +/** + * en_dis_able_nic_intrs - Enable or Disable the interrupts * @nic: device private variable, * @mask: A mask indicating which Intr block must be modified and, * @flag: A flag indicating whether to enable or disable the Intrs. * Description: This function will either disable or enable the interrupts - * depending on the flag argument. The mask argument can be used to - * enable/disable any Intr block. + * depending on the flag argument. The mask argument can be used to + * enable/disable any Intr block. * Return Value: NONE. */ @@ -1024,20 +1510,31 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) temp64 = readq(&bar0->general_int_mask); temp64 &= ~((u64) val64); writeq(temp64, &bar0->general_int_mask); - /* - * Disabled all PCIX, Flash, MDIO, IIC and GPIO - * interrupts for now. - * TODO + /* + * If Hercules adapter enable GPIO otherwise + * disabled all PCIX, Flash, MDIO, IIC and GPIO + * interrupts for now. + * TODO */ - writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask); - /* + if (s2io_link_fault_indication(nic) == + LINK_UP_DOWN_INTERRUPT ) { + temp64 = readq(&bar0->pic_int_mask); + temp64 &= ~((u64) PIC_INT_GPIO); + writeq(temp64, &bar0->pic_int_mask); + temp64 = readq(&bar0->gpio_int_mask); + temp64 &= ~((u64) GPIO_INT_MASK_LINK_UP); + writeq(temp64, &bar0->gpio_int_mask); + } else { + writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask); + } + /* * No MSI Support is available presently, so TTI and * RTI interrupts are also disabled. */ } else if (flag == DISABLE_INTRS) { - /* - * Disable PIC Intrs in the general - * intr mask register + /* + * Disable PIC Intrs in the general + * intr mask register */ writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask); temp64 = readq(&bar0->general_int_mask); @@ -1055,27 +1552,27 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) temp64 = readq(&bar0->general_int_mask); temp64 &= ~((u64) val64); writeq(temp64, &bar0->general_int_mask); - /* - * Keep all interrupts other than PFC interrupt + /* + * Keep all interrupts other than PFC interrupt * and PCC interrupt disabled in DMA level. */ val64 = DISABLE_ALL_INTRS & ~(TXDMA_PFC_INT_M | TXDMA_PCC_INT_M); writeq(val64, &bar0->txdma_int_mask); - /* - * Enable only the MISC error 1 interrupt in PFC block + /* + * Enable only the MISC error 1 interrupt in PFC block */ val64 = DISABLE_ALL_INTRS & (~PFC_MISC_ERR_1); writeq(val64, &bar0->pfc_err_mask); - /* - * Enable only the FB_ECC error interrupt in PCC block + /* + * Enable only the FB_ECC error interrupt in PCC block */ val64 = DISABLE_ALL_INTRS & (~PCC_FB_ECC_ERR); writeq(val64, &bar0->pcc_err_mask); } else if (flag == DISABLE_INTRS) { - /* - * Disable TxDMA Intrs in the general intr mask - * register + /* + * Disable TxDMA Intrs in the general intr mask + * register */ writeq(DISABLE_ALL_INTRS, &bar0->txdma_int_mask); writeq(DISABLE_ALL_INTRS, &bar0->pfc_err_mask); @@ -1093,15 +1590,15 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) temp64 = readq(&bar0->general_int_mask); temp64 &= ~((u64) val64); writeq(temp64, &bar0->general_int_mask); - /* - * All RxDMA block interrupts are disabled for now - * TODO + /* + * All RxDMA block interrupts are disabled for now + * TODO */ writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask); } else if (flag == DISABLE_INTRS) { - /* - * Disable RxDMA Intrs in the general intr mask - * register + /* + * Disable RxDMA Intrs in the general intr mask + * register */ writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask); temp64 = readq(&bar0->general_int_mask); @@ -1118,22 +1615,13 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) temp64 = readq(&bar0->general_int_mask); temp64 &= ~((u64) val64); writeq(temp64, &bar0->general_int_mask); - /* - * All MAC block error interrupts are disabled for now - * except the link status change interrupt. + /* + * All MAC block error interrupts are disabled for now * TODO */ - val64 = MAC_INT_STATUS_RMAC_INT; - temp64 = readq(&bar0->mac_int_mask); - temp64 &= ~((u64) val64); - writeq(temp64, &bar0->mac_int_mask); - - val64 = readq(&bar0->mac_rmac_err_mask); - val64 &= ~((u64) RMAC_LINK_STATE_CHANGE_INT); - writeq(val64, &bar0->mac_rmac_err_mask); } else if (flag == DISABLE_INTRS) { - /* - * Disable MAC Intrs in the general intr mask register + /* + * Disable MAC Intrs in the general intr mask register */ writeq(DISABLE_ALL_INTRS, &bar0->mac_int_mask); writeq(DISABLE_ALL_INTRS, @@ -1152,14 +1640,14 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) temp64 = readq(&bar0->general_int_mask); temp64 &= ~((u64) val64); writeq(temp64, &bar0->general_int_mask); - /* + /* * All XGXS block error interrupts are disabled for now - * TODO + * TODO */ writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask); } else if (flag == DISABLE_INTRS) { - /* - * Disable MC Intrs in the general intr mask register + /* + * Disable MC Intrs in the general intr mask register */ writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask); temp64 = readq(&bar0->general_int_mask); @@ -1175,11 +1663,11 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) temp64 = readq(&bar0->general_int_mask); temp64 &= ~((u64) val64); writeq(temp64, &bar0->general_int_mask); - /* - * All MC block error interrupts are disabled for now - * TODO + /* + * Enable all MC Intrs. */ - writeq(DISABLE_ALL_INTRS, &bar0->mc_int_mask); + writeq(0x0, &bar0->mc_int_mask); + writeq(0x0, &bar0->mc_err_mask); } else if (flag == DISABLE_INTRS) { /* * Disable MC Intrs in the general intr mask register @@ -1199,14 +1687,14 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) temp64 = readq(&bar0->general_int_mask); temp64 &= ~((u64) val64); writeq(temp64, &bar0->general_int_mask); - /* + /* * Enable all the Tx side interrupts - * writing 0 Enables all 64 TX interrupt levels + * writing 0 Enables all 64 TX interrupt levels */ writeq(0x0, &bar0->tx_traffic_mask); } else if (flag == DISABLE_INTRS) { - /* - * Disable Tx Traffic Intrs in the general intr mask + /* + * Disable Tx Traffic Intrs in the general intr mask * register. */ writeq(DISABLE_ALL_INTRS, &bar0->tx_traffic_mask); @@ -1226,8 +1714,8 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) /* writing 0 Enables all 8 RX interrupt levels */ writeq(0x0, &bar0->rx_traffic_mask); } else if (flag == DISABLE_INTRS) { - /* - * Disable Rx Traffic Intrs in the general intr mask + /* + * Disable Rx Traffic Intrs in the general intr mask * register. */ writeq(DISABLE_ALL_INTRS, &bar0->rx_traffic_mask); @@ -1238,24 +1726,66 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) } } -/** - * verify_xena_quiescence - Checks whether the H/W is ready +static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc) +{ + int ret = 0; + + if (flag == FALSE) { + if ((!herc && (rev_id >= 4)) || herc) { + if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) && + ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == + ADAPTER_STATUS_RC_PRC_QUIESCENT)) { + ret = 1; + } + }else { + if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) && + ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == + ADAPTER_STATUS_RC_PRC_QUIESCENT)) { + ret = 1; + } + } + } else { + if ((!herc && (rev_id >= 4)) || herc) { + if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) == + ADAPTER_STATUS_RMAC_PCC_IDLE) && + (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) || + ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == + ADAPTER_STATUS_RC_PRC_QUIESCENT))) { + ret = 1; + } + } else { + if (((val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) == + ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) && + (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) || + ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == + ADAPTER_STATUS_RC_PRC_QUIESCENT))) { + ret = 1; + } + } + } + + return ret; +} +/** + * verify_xena_quiescence - Checks whether the H/W is ready * @val64 : Value read from adapter status register. * @flag : indicates if the adapter enable bit was ever written once * before. * Description: Returns whether the H/W is ready to go or not. Depending - * on whether adapter enable bit was written or not the comparison + * on whether adapter enable bit was written or not the comparison * differs and the calling function passes the input argument flag to * indicate this. - * Return: 1 If xena is quiescence + * Return: 1 If xena is quiescence * 0 If Xena is not quiescence */ -static int verify_xena_quiescence(u64 val64, int flag) +static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag) { - int ret = 0; + int ret = 0, herc; u64 tmp64 = ~((u64) val64); + int rev_id = get_xena_rev_id(sp->pdev); + herc = (sp->device_type == XFRAME_II_DEVICE); if (! (tmp64 & (ADAPTER_STATUS_TDMA_READY | ADAPTER_STATUS_RDMA_READY | @@ -1263,25 +1793,7 @@ static int verify_xena_quiescence(u64 val64, int flag) ADAPTER_STATUS_PIC_QUIESCENT | ADAPTER_STATUS_MC_DRAM_READY | ADAPTER_STATUS_MC_QUEUES_READY | ADAPTER_STATUS_M_PLL_LOCK | ADAPTER_STATUS_P_PLL_LOCK))) { - if (flag == FALSE) { - if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) && - ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == - ADAPTER_STATUS_RC_PRC_QUIESCENT)) { - - ret = 1; - - } - } else { - if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) == - ADAPTER_STATUS_RMAC_PCC_IDLE) && - (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) || - ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == - ADAPTER_STATUS_RC_PRC_QUIESCENT))) { - - ret = 1; - - } - } + ret = check_prc_pcc_state(val64, flag, rev_id, herc); } return ret; @@ -1290,12 +1802,12 @@ static int verify_xena_quiescence(u64 val64, int flag) /** * fix_mac_address - Fix for Mac addr problem on Alpha platforms * @sp: Pointer to device specifc structure - * Description : + * Description : * New procedure to clear mac address reading problems on Alpha platforms * */ -static void fix_mac_address(nic_t * sp) +void fix_mac_address(nic_t * sp) { XENA_dev_config_t __iomem *bar0 = sp->bar0; u64 val64; @@ -1303,20 +1815,21 @@ static void fix_mac_address(nic_t * sp) while (fix_mac[i] != END_SIGN) { writeq(fix_mac[i++], &bar0->gpio_control); + udelay(10); val64 = readq(&bar0->gpio_control); } } /** - * start_nic - Turns the device on + * start_nic - Turns the device on * @nic : device private variable. - * Description: - * This function actually turns the device on. Before this function is - * called,all Registers are configured from their reset states - * and shared memory is allocated but the NIC is still quiescent. On + * Description: + * This function actually turns the device on. Before this function is + * called,all Registers are configured from their reset states + * and shared memory is allocated but the NIC is still quiescent. On * calling this function, the device interrupts are cleared and the NIC is * literally switched on by writing into the adapter control register. - * Return Value: + * Return Value: * SUCCESS on success and -1 on failure. */ @@ -1325,8 +1838,8 @@ static int start_nic(struct s2io_nic *nic) XENA_dev_config_t __iomem *bar0 = nic->bar0; struct net_device *dev = nic->dev; register u64 val64 = 0; - u16 interruptible, i; - u16 subid; + u16 interruptible; + u16 subid, i; mac_info_t *mac_control; struct config_param *config; @@ -1335,10 +1848,12 @@ static int start_nic(struct s2io_nic *nic) /* PRC Initialization and configuration */ for (i = 0; i < config->rx_ring_num; i++) { - writeq((u64) nic->rx_blocks[i][0].block_dma_addr, + writeq((u64) mac_control->rings[i].rx_blocks[0].block_dma_addr, &bar0->prc_rxd0_n[i]); val64 = readq(&bar0->prc_ctrl_n[i]); + if (nic->config.bimodal) + val64 |= PRC_CTRL_BIMODAL_INTERRUPT; #ifndef CONFIG_2BUFF_MODE val64 |= PRC_CTRL_RC_ENABLED; #else @@ -1354,7 +1869,7 @@ static int start_nic(struct s2io_nic *nic) writeq(val64, &bar0->rx_pa_cfg); #endif - /* + /* * Enabling MC-RLDRAM. After enabling the device, we timeout * for around 100ms, which is approximately the time required * for the device to be ready for operation. @@ -1364,27 +1879,27 @@ static int start_nic(struct s2io_nic *nic) SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF); val64 = readq(&bar0->mc_rldram_mrs); - msleep(100); /* Delay by around 100 ms. */ + msleep(100); /* Delay by around 100 ms. */ /* Enabling ECC Protection. */ val64 = readq(&bar0->adapter_control); val64 &= ~ADAPTER_ECC_EN; writeq(val64, &bar0->adapter_control); - /* - * Clearing any possible Link state change interrupts that + /* + * Clearing any possible Link state change interrupts that * could have popped up just before Enabling the card. */ val64 = readq(&bar0->mac_rmac_err_reg); if (val64) writeq(val64, &bar0->mac_rmac_err_reg); - /* - * Verify if the device is ready to be enabled, if so enable + /* + * Verify if the device is ready to be enabled, if so enable * it. */ val64 = readq(&bar0->adapter_status); - if (!verify_xena_quiescence(val64, nic->device_enabled_once)) { + if (!verify_xena_quiescence(nic, val64, nic->device_enabled_once)) { DBG_PRINT(ERR_DBG, "%s: device is not ready, ", dev->name); DBG_PRINT(ERR_DBG, "Adapter status reads: 0x%llx\n", (unsigned long long) val64); @@ -1392,16 +1907,18 @@ static int start_nic(struct s2io_nic *nic) } /* Enable select interrupts */ - interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR | TX_MAC_INTR | - RX_MAC_INTR; + interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR; + interruptible |= TX_PIC_INTR | RX_PIC_INTR; + interruptible |= TX_MAC_INTR | RX_MAC_INTR; + en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS); - /* + /* * With some switches, link might be already up at this point. - * Because of this weird behavior, when we enable laser, - * we may not get link. We need to handle this. We cannot - * figure out which switch is misbehaving. So we are forced to - * make a global change. + * Because of this weird behavior, when we enable laser, + * we may not get link. We need to handle this. We cannot + * figure out which switch is misbehaving. So we are forced to + * make a global change. */ /* Enabling Laser. */ @@ -1411,44 +1928,30 @@ static int start_nic(struct s2io_nic *nic) /* SXE-002: Initialize link and activity LED */ subid = nic->pdev->subsystem_device; - if ((subid & 0xFF) >= 0x07) { + if (((subid & 0xFF) >= 0x07) && + (nic->device_type == XFRAME_I_DEVICE)) { val64 = readq(&bar0->gpio_control); val64 |= 0x0000800000000000ULL; writeq(val64, &bar0->gpio_control); val64 = 0x0411040400000000ULL; - writeq(val64, (void __iomem *) bar0 + 0x2700); + writeq(val64, (void __iomem *) ((u8 *) bar0 + 0x2700)); } - /* - * Don't see link state interrupts on certain switches, so + /* + * Don't see link state interrupts on certain switches, so * directly scheduling a link state task from here. */ schedule_work(&nic->set_link_task); - /* - * Here we are performing soft reset on XGXS to - * force link down. Since link is already up, we will get - * link state change interrupt after this reset - */ - SPECIAL_REG_WRITE(0x80010515001E0000ULL, &bar0->dtx_control, UF); - val64 = readq(&bar0->dtx_control); - udelay(50); - SPECIAL_REG_WRITE(0x80010515001E00E0ULL, &bar0->dtx_control, UF); - val64 = readq(&bar0->dtx_control); - udelay(50); - SPECIAL_REG_WRITE(0x80070515001F00E4ULL, &bar0->dtx_control, UF); - val64 = readq(&bar0->dtx_control); - udelay(50); - return SUCCESS; } -/** - * free_tx_buffers - Free all queued Tx buffers +/** + * free_tx_buffers - Free all queued Tx buffers * @nic : device private variable. - * Description: + * Description: * Free all queued Tx buffers. - * Return Value: void + * Return Value: void */ static void free_tx_buffers(struct s2io_nic *nic) @@ -1459,39 +1962,61 @@ static void free_tx_buffers(struct s2io_nic *nic) int i, j; mac_info_t *mac_control; struct config_param *config; - int cnt = 0; + int cnt = 0, frg_cnt; mac_control = &nic->mac_control; config = &nic->config; for (i = 0; i < config->tx_fifo_num; i++) { for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) { - txdp = (TxD_t *) nic->list_info[i][j]. + txdp = (TxD_t *) mac_control->fifos[i].list_info[j]. list_virt_addr; skb = (struct sk_buff *) ((unsigned long) txdp-> Host_Control); if (skb == NULL) { - memset(txdp, 0, sizeof(TxD_t)); + memset(txdp, 0, sizeof(TxD_t) * + config->max_txds); continue; } + frg_cnt = skb_shinfo(skb)->nr_frags; + pci_unmap_single(nic->pdev, (dma_addr_t) + txdp->Buffer_Pointer, + skb->len - skb->data_len, + PCI_DMA_TODEVICE); + if (frg_cnt) { + TxD_t *temp; + temp = txdp; + txdp++; + for (j = 0; j < frg_cnt; j++, txdp++) { + skb_frag_t *frag = + &skb_shinfo(skb)->frags[j]; + pci_unmap_page(nic->pdev, + (dma_addr_t) + txdp-> + Buffer_Pointer, + frag->size, + PCI_DMA_TODEVICE); + } + txdp = temp; + } dev_kfree_skb(skb); - memset(txdp, 0, sizeof(TxD_t)); + memset(txdp, 0, sizeof(TxD_t) * config->max_txds); cnt++; } DBG_PRINT(INTR_DBG, "%s:forcibly freeing %d skbs on FIFO%d\n", dev->name, cnt, i); - mac_control->tx_curr_get_info[i].offset = 0; - mac_control->tx_curr_put_info[i].offset = 0; + mac_control->fifos[i].tx_curr_get_info.offset = 0; + mac_control->fifos[i].tx_curr_put_info.offset = 0; } } -/** - * stop_nic - To stop the nic +/** + * stop_nic - To stop the nic * @nic ; device private variable. - * Description: - * This function does exactly the opposite of what the start_nic() + * Description: + * This function does exactly the opposite of what the start_nic() * function does. This function is called to stop the device. * Return Value: * void. @@ -1509,8 +2034,9 @@ static void stop_nic(struct s2io_nic *nic) config = &nic->config; /* Disable all interrupts */ - interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR | TX_MAC_INTR | - RX_MAC_INTR; + interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR; + interruptible |= TX_PIC_INTR | RX_PIC_INTR; + interruptible |= TX_MAC_INTR | RX_MAC_INTR; en_dis_able_nic_intrs(nic, interruptible, DISABLE_INTRS); /* Disable PRCs */ @@ -1521,11 +2047,11 @@ static void stop_nic(struct s2io_nic *nic) } } -/** - * fill_rx_buffers - Allocates the Rx side skbs +/** + * fill_rx_buffers - Allocates the Rx side skbs * @nic: device private variable - * @ring_no: ring number - * Description: + * @ring_no: ring number + * Description: * The function allocates Rx side skbs and puts the physical * address of these buffers into the RxD buffer pointers, so that the NIC * can DMA the received frame into these locations. @@ -1533,8 +2059,8 @@ static void stop_nic(struct s2io_nic *nic) * 1. single buffer, * 2. three buffer and * 3. Five buffer modes. - * Each mode defines how many fragments the received frame will be split - * up into by the NIC. The frame is split into L3 header, L4 Header, + * Each mode defines how many fragments the received frame will be split + * up into by the NIC. The frame is split into L3 header, L4 Header, * L4 payload in three buffer mode and in 5 buffer mode, L4 payload itself * is split into 3 fragments. As of now only single buffer mode is * supported. @@ -1542,7 +2068,7 @@ static void stop_nic(struct s2io_nic *nic) * SUCCESS on success or an appropriate -ve value on failure. */ -static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) +int fill_rx_buffers(struct s2io_nic *nic, int ring_no) { struct net_device *dev = nic->dev; struct sk_buff *skb; @@ -1550,34 +2076,35 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) int off, off1, size, block_no, block_no1; int offset, offset1; u32 alloc_tab = 0; - u32 alloc_cnt = nic->pkt_cnt[ring_no] - - atomic_read(&nic->rx_bufs_left[ring_no]); + u32 alloc_cnt; mac_info_t *mac_control; struct config_param *config; #ifdef CONFIG_2BUFF_MODE RxD_t *rxdpnext; int nextblk; - unsigned long tmp; + u64 tmp; buffAdd_t *ba; dma_addr_t rxdpphys; #endif #ifndef CONFIG_S2IO_NAPI unsigned long flags; #endif + RxD_t *first_rxdp = NULL; mac_control = &nic->mac_control; config = &nic->config; - + alloc_cnt = mac_control->rings[ring_no].pkt_cnt - + atomic_read(&nic->rx_bufs_left[ring_no]); size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE + HEADER_802_2_SIZE + HEADER_SNAP_SIZE; while (alloc_tab < alloc_cnt) { - block_no = mac_control->rx_curr_put_info[ring_no]. + block_no = mac_control->rings[ring_no].rx_curr_put_info. block_index; - block_no1 = mac_control->rx_curr_get_info[ring_no]. + block_no1 = mac_control->rings[ring_no].rx_curr_get_info. block_index; - off = mac_control->rx_curr_put_info[ring_no].offset; - off1 = mac_control->rx_curr_get_info[ring_no].offset; + off = mac_control->rings[ring_no].rx_curr_put_info.offset; + off1 = mac_control->rings[ring_no].rx_curr_get_info.offset; #ifndef CONFIG_2BUFF_MODE offset = block_no * (MAX_RXDS_PER_BLOCK + 1) + off; offset1 = block_no1 * (MAX_RXDS_PER_BLOCK + 1) + off1; @@ -1586,7 +2113,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) offset1 = block_no1 * (MAX_RXDS_PER_BLOCK) + off1; #endif - rxdp = nic->rx_blocks[ring_no][block_no]. + rxdp = mac_control->rings[ring_no].rx_blocks[block_no]. block_virt_addr + off; if ((offset == offset1) && (rxdp->Host_Control)) { DBG_PRINT(INTR_DBG, "%s: Get and Put", dev->name); @@ -1595,15 +2122,15 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) } #ifndef CONFIG_2BUFF_MODE if (rxdp->Control_1 == END_OF_BLOCK) { - mac_control->rx_curr_put_info[ring_no]. + mac_control->rings[ring_no].rx_curr_put_info. block_index++; - mac_control->rx_curr_put_info[ring_no]. - block_index %= nic->block_count[ring_no]; - block_no = mac_control->rx_curr_put_info - [ring_no].block_index; + mac_control->rings[ring_no].rx_curr_put_info. + block_index %= mac_control->rings[ring_no].block_count; + block_no = mac_control->rings[ring_no].rx_curr_put_info. + block_index; off++; off %= (MAX_RXDS_PER_BLOCK + 1); - mac_control->rx_curr_put_info[ring_no].offset = + mac_control->rings[ring_no].rx_curr_put_info.offset = off; rxdp = (RxD_t *) ((unsigned long) rxdp->Control_2); DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n", @@ -1611,30 +2138,30 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) } #ifndef CONFIG_S2IO_NAPI spin_lock_irqsave(&nic->put_lock, flags); - nic->put_pos[ring_no] = + mac_control->rings[ring_no].put_pos = (block_no * (MAX_RXDS_PER_BLOCK + 1)) + off; spin_unlock_irqrestore(&nic->put_lock, flags); #endif #else if (rxdp->Host_Control == END_OF_BLOCK) { - mac_control->rx_curr_put_info[ring_no]. + mac_control->rings[ring_no].rx_curr_put_info. block_index++; - mac_control->rx_curr_put_info[ring_no]. - block_index %= nic->block_count[ring_no]; - block_no = mac_control->rx_curr_put_info - [ring_no].block_index; + mac_control->rings[ring_no].rx_curr_put_info.block_index + %= mac_control->rings[ring_no].block_count; + block_no = mac_control->rings[ring_no].rx_curr_put_info + .block_index; off = 0; DBG_PRINT(INTR_DBG, "%s: block%d at: 0x%llx\n", dev->name, block_no, (unsigned long long) rxdp->Control_1); - mac_control->rx_curr_put_info[ring_no].offset = + mac_control->rings[ring_no].rx_curr_put_info.offset = off; - rxdp = nic->rx_blocks[ring_no][block_no]. + rxdp = mac_control->rings[ring_no].rx_blocks[block_no]. block_virt_addr; } #ifndef CONFIG_S2IO_NAPI spin_lock_irqsave(&nic->put_lock, flags); - nic->put_pos[ring_no] = (block_no * + mac_control->rings[ring_no].put_pos = (block_no * (MAX_RXDS_PER_BLOCK + 1)) + off; spin_unlock_irqrestore(&nic->put_lock, flags); #endif @@ -1646,27 +2173,27 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) if (rxdp->Control_2 & BIT(0)) #endif { - mac_control->rx_curr_put_info[ring_no]. + mac_control->rings[ring_no].rx_curr_put_info. offset = off; goto end; } #ifdef CONFIG_2BUFF_MODE - /* - * RxDs Spanning cache lines will be replenished only - * if the succeeding RxD is also owned by Host. It - * will always be the ((8*i)+3) and ((8*i)+6) - * descriptors for the 48 byte descriptor. The offending + /* + * RxDs Spanning cache lines will be replenished only + * if the succeeding RxD is also owned by Host. It + * will always be the ((8*i)+3) and ((8*i)+6) + * descriptors for the 48 byte descriptor. The offending * decsriptor is of-course the 3rd descriptor. */ - rxdpphys = nic->rx_blocks[ring_no][block_no]. + rxdpphys = mac_control->rings[ring_no].rx_blocks[block_no]. block_dma_addr + (off * sizeof(RxD_t)); if (((u64) (rxdpphys)) % 128 > 80) { - rxdpnext = nic->rx_blocks[ring_no][block_no]. + rxdpnext = mac_control->rings[ring_no].rx_blocks[block_no]. block_virt_addr + (off + 1); if (rxdpnext->Host_Control == END_OF_BLOCK) { nextblk = (block_no + 1) % - (nic->block_count[ring_no]); - rxdpnext = nic->rx_blocks[ring_no] + (mac_control->rings[ring_no].block_count); + rxdpnext = mac_control->rings[ring_no].rx_blocks [nextblk].block_virt_addr; } if (rxdpnext->Control_2 & BIT(0)) @@ -1682,6 +2209,10 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) if (!skb) { DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name); DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n"); + if (first_rxdp) { + wmb(); + first_rxdp->Control_1 |= RXD_OWN_XENA; + } return -ENOMEM; } #ifndef CONFIG_2BUFF_MODE @@ -1692,12 +2223,13 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) rxdp->Control_2 &= (~MASK_BUFFER0_SIZE); rxdp->Control_2 |= SET_BUFFER0_SIZE(size); rxdp->Host_Control = (unsigned long) (skb); - rxdp->Control_1 |= RXD_OWN_XENA; + if (alloc_tab & ((1 << rxsync_frequency) - 1)) + rxdp->Control_1 |= RXD_OWN_XENA; off++; off %= (MAX_RXDS_PER_BLOCK + 1); - mac_control->rx_curr_put_info[ring_no].offset = off; + mac_control->rings[ring_no].rx_curr_put_info.offset = off; #else - ba = &nic->ba[ring_no][block_no][off]; + ba = &mac_control->rings[ring_no].ba[block_no][off]; skb_reserve(skb, BUF0_LEN); tmp = ((unsigned long) skb->data & ALIGN_SIZE); if (tmp) @@ -1719,22 +2251,41 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) rxdp->Control_2 |= SET_BUFFER1_SIZE(1); /* dummy. */ rxdp->Control_2 |= BIT(0); /* Set Buffer_Empty bit. */ rxdp->Host_Control = (u64) ((unsigned long) (skb)); - rxdp->Control_1 |= RXD_OWN_XENA; + if (alloc_tab & ((1 << rxsync_frequency) - 1)) + rxdp->Control_1 |= RXD_OWN_XENA; off++; - mac_control->rx_curr_put_info[ring_no].offset = off; + mac_control->rings[ring_no].rx_curr_put_info.offset = off; #endif + rxdp->Control_2 |= SET_RXD_MARKER; + + if (!(alloc_tab & ((1 << rxsync_frequency) - 1))) { + if (first_rxdp) { + wmb(); + first_rxdp->Control_1 |= RXD_OWN_XENA; + } + first_rxdp = rxdp; + } atomic_inc(&nic->rx_bufs_left[ring_no]); alloc_tab++; } end: + /* Transfer ownership of first descriptor to adapter just before + * exiting. Before that, use memory barrier so that ownership + * and other fields are seen by adapter correctly. + */ + if (first_rxdp) { + wmb(); + first_rxdp->Control_1 |= RXD_OWN_XENA; + } + return SUCCESS; } /** - * free_rx_buffers - Frees all Rx buffers + * free_rx_buffers - Frees all Rx buffers * @sp: device private variable. - * Description: + * Description: * This function will free all Rx buffers allocated by host. * Return Value: * NONE. @@ -1758,7 +2309,8 @@ static void free_rx_buffers(struct s2io_nic *sp) for (i = 0; i < config->rx_ring_num; i++) { for (j = 0, blk = 0; j < config->rx_cfg[i].num_rxd; j++) { off = j % (MAX_RXDS_PER_BLOCK + 1); - rxdp = sp->rx_blocks[i][blk].block_virt_addr + off; + rxdp = mac_control->rings[i].rx_blocks[blk]. + block_virt_addr + off; #ifndef CONFIG_2BUFF_MODE if (rxdp->Control_1 == END_OF_BLOCK) { @@ -1793,7 +2345,7 @@ static void free_rx_buffers(struct s2io_nic *sp) HEADER_SNAP_SIZE, PCI_DMA_FROMDEVICE); #else - ba = &sp->ba[i][blk][off]; + ba = &mac_control->rings[i].ba[blk][off]; pci_unmap_single(sp->pdev, (dma_addr_t) rxdp->Buffer0_ptr, BUF0_LEN, @@ -1813,10 +2365,10 @@ static void free_rx_buffers(struct s2io_nic *sp) } memset(rxdp, 0, sizeof(RxD_t)); } - mac_control->rx_curr_put_info[i].block_index = 0; - mac_control->rx_curr_get_info[i].block_index = 0; - mac_control->rx_curr_put_info[i].offset = 0; - mac_control->rx_curr_get_info[i].offset = 0; + mac_control->rings[i].rx_curr_put_info.block_index = 0; + mac_control->rings[i].rx_curr_get_info.block_index = 0; + mac_control->rings[i].rx_curr_put_info.offset = 0; + mac_control->rings[i].rx_curr_get_info.offset = 0; atomic_set(&sp->rx_bufs_left[i], 0); DBG_PRINT(INIT_DBG, "%s:Freed 0x%x Rx Buffers on ring%d\n", dev->name, buf_cnt, i); @@ -1826,7 +2378,7 @@ static void free_rx_buffers(struct s2io_nic *sp) /** * s2io_poll - Rx interrupt handler for NAPI support * @dev : pointer to the device structure. - * @budget : The number of packets that were budgeted to be processed + * @budget : The number of packets that were budgeted to be processed * during one pass through the 'Poll" function. * Description: * Comes into picture only if NAPI support has been incorporated. It does @@ -1836,160 +2388,36 @@ static void free_rx_buffers(struct s2io_nic *sp) * 0 on success and 1 if there are No Rx packets to be processed. */ -#ifdef CONFIG_S2IO_NAPI +#if defined(CONFIG_S2IO_NAPI) static int s2io_poll(struct net_device *dev, int *budget) { nic_t *nic = dev->priv; - XENA_dev_config_t __iomem *bar0 = nic->bar0; - int pkts_to_process = *budget, pkt_cnt = 0; - register u64 val64 = 0; - rx_curr_get_info_t get_info, put_info; - int i, get_block, put_block, get_offset, put_offset, ring_bufs; -#ifndef CONFIG_2BUFF_MODE - u16 val16, cksum; -#endif - struct sk_buff *skb; - RxD_t *rxdp; + int pkt_cnt = 0, org_pkts_to_process; mac_info_t *mac_control; struct config_param *config; -#ifdef CONFIG_2BUFF_MODE - buffAdd_t *ba; -#endif + XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + u64 val64; + int i; + atomic_inc(&nic->isr_cnt); mac_control = &nic->mac_control; config = &nic->config; - if (pkts_to_process > dev->quota) - pkts_to_process = dev->quota; + nic->pkts_to_process = *budget; + if (nic->pkts_to_process > dev->quota) + nic->pkts_to_process = dev->quota; + org_pkts_to_process = nic->pkts_to_process; val64 = readq(&bar0->rx_traffic_int); writeq(val64, &bar0->rx_traffic_int); for (i = 0; i < config->rx_ring_num; i++) { - get_info = mac_control->rx_curr_get_info[i]; - get_block = get_info.block_index; - put_info = mac_control->rx_curr_put_info[i]; - put_block = put_info.block_index; - ring_bufs = config->rx_cfg[i].num_rxd; - rxdp = nic->rx_blocks[i][get_block].block_virt_addr + - get_info.offset; -#ifndef CONFIG_2BUFF_MODE - get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) + - get_info.offset; - put_offset = (put_block * (MAX_RXDS_PER_BLOCK + 1)) + - put_info.offset; - while ((!(rxdp->Control_1 & RXD_OWN_XENA)) && - (((get_offset + 1) % ring_bufs) != put_offset)) { - if (--pkts_to_process < 0) { - goto no_rx; - } - if (rxdp->Control_1 == END_OF_BLOCK) { - rxdp = - (RxD_t *) ((unsigned long) rxdp-> - Control_2); - get_info.offset++; - get_info.offset %= - (MAX_RXDS_PER_BLOCK + 1); - get_block++; - get_block %= nic->block_count[i]; - mac_control->rx_curr_get_info[i]. - offset = get_info.offset; - mac_control->rx_curr_get_info[i]. - block_index = get_block; - continue; - } - get_offset = - (get_block * (MAX_RXDS_PER_BLOCK + 1)) + - get_info.offset; - skb = - (struct sk_buff *) ((unsigned long) rxdp-> - Host_Control); - if (skb == NULL) { - DBG_PRINT(ERR_DBG, "%s: The skb is ", - dev->name); - DBG_PRINT(ERR_DBG, "Null in Rx Intr\n"); - goto no_rx; - } - val64 = RXD_GET_BUFFER0_SIZE(rxdp->Control_2); - val16 = (u16) (val64 >> 48); - cksum = RXD_GET_L4_CKSUM(rxdp->Control_1); - pci_unmap_single(nic->pdev, (dma_addr_t) - rxdp->Buffer0_ptr, - dev->mtu + - HEADER_ETHERNET_II_802_3_SIZE + - HEADER_802_2_SIZE + - HEADER_SNAP_SIZE, - PCI_DMA_FROMDEVICE); - rx_osm_handler(nic, val16, rxdp, i); - pkt_cnt++; - get_info.offset++; - get_info.offset %= (MAX_RXDS_PER_BLOCK + 1); - rxdp = - nic->rx_blocks[i][get_block].block_virt_addr + - get_info.offset; - mac_control->rx_curr_get_info[i].offset = - get_info.offset; + rx_intr_handler(&mac_control->rings[i]); + pkt_cnt = org_pkts_to_process - nic->pkts_to_process; + if (!nic->pkts_to_process) { + /* Quota for the current iteration has been met */ + goto no_rx; } -#else - get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) + - get_info.offset; - put_offset = (put_block * (MAX_RXDS_PER_BLOCK + 1)) + - put_info.offset; - while (((!(rxdp->Control_1 & RXD_OWN_XENA)) && - !(rxdp->Control_2 & BIT(0))) && - (((get_offset + 1) % ring_bufs) != put_offset)) { - if (--pkts_to_process < 0) { - goto no_rx; - } - skb = (struct sk_buff *) ((unsigned long) - rxdp->Host_Control); - if (skb == NULL) { - DBG_PRINT(ERR_DBG, "%s: The skb is ", - dev->name); - DBG_PRINT(ERR_DBG, "Null in Rx Intr\n"); - goto no_rx; - } - - pci_unmap_single(nic->pdev, (dma_addr_t) - rxdp->Buffer0_ptr, - BUF0_LEN, PCI_DMA_FROMDEVICE); - pci_unmap_single(nic->pdev, (dma_addr_t) - rxdp->Buffer1_ptr, - BUF1_LEN, PCI_DMA_FROMDEVICE); - pci_unmap_single(nic->pdev, (dma_addr_t) - rxdp->Buffer2_ptr, - dev->mtu + BUF0_LEN + 4, - PCI_DMA_FROMDEVICE); - ba = &nic->ba[i][get_block][get_info.offset]; - - rx_osm_handler(nic, rxdp, i, ba); - - get_info.offset++; - mac_control->rx_curr_get_info[i].offset = - get_info.offset; - rxdp = - nic->rx_blocks[i][get_block].block_virt_addr + - get_info.offset; - - if (get_info.offset && - (!(get_info.offset % MAX_RXDS_PER_BLOCK))) { - get_info.offset = 0; - mac_control->rx_curr_get_info[i]. - offset = get_info.offset; - get_block++; - get_block %= nic->block_count[i]; - mac_control->rx_curr_get_info[i]. - block_index = get_block; - rxdp = - nic->rx_blocks[i][get_block]. - block_virt_addr; - } - get_offset = - (get_block * (MAX_RXDS_PER_BLOCK + 1)) + - get_info.offset; - pkt_cnt++; - } -#endif } if (!pkt_cnt) pkt_cnt = 1; @@ -2007,9 +2435,10 @@ static int s2io_poll(struct net_device *dev, int *budget) } /* Re enable the Rx interrupts. */ en_dis_able_nic_intrs(nic, RX_TRAFFIC_INTR, ENABLE_INTRS); + atomic_dec(&nic->isr_cnt); return 0; - no_rx: +no_rx: dev->quota -= pkt_cnt; *budget -= pkt_cnt; @@ -2020,279 +2449,204 @@ static int s2io_poll(struct net_device *dev, int *budget) break; } } + atomic_dec(&nic->isr_cnt); return 1; } -#else -/** +#endif + +/** * rx_intr_handler - Rx interrupt handler * @nic: device private variable. - * Description: - * If the interrupt is because of a received frame or if the + * Description: + * If the interrupt is because of a received frame or if the * receive ring contains fresh as yet un-processed frames,this function is - * called. It picks out the RxD at which place the last Rx processing had - * stopped and sends the skb to the OSM's Rx handler and then increments + * called. It picks out the RxD at which place the last Rx processing had + * stopped and sends the skb to the OSM's Rx handler and then increments * the offset. * Return Value: * NONE. */ - -static void rx_intr_handler(struct s2io_nic *nic) +static void rx_intr_handler(ring_info_t *ring_data) { + nic_t *nic = ring_data->nic; struct net_device *dev = (struct net_device *) nic->dev; - XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; + int get_block, get_offset, put_block, put_offset, ring_bufs; rx_curr_get_info_t get_info, put_info; RxD_t *rxdp; struct sk_buff *skb; -#ifndef CONFIG_2BUFF_MODE - u16 val16, cksum; -#endif - register u64 val64 = 0; - int get_block, get_offset, put_block, put_offset, ring_bufs; - int i, pkt_cnt = 0; - mac_info_t *mac_control; - struct config_param *config; -#ifdef CONFIG_2BUFF_MODE - buffAdd_t *ba; +#ifndef CONFIG_S2IO_NAPI + int pkt_cnt = 0; #endif + spin_lock(&nic->rx_lock); + if (atomic_read(&nic->card_state) == CARD_DOWN) { + DBG_PRINT(ERR_DBG, "%s: %s going down for reset\n", + __FUNCTION__, dev->name); + spin_unlock(&nic->rx_lock); + } - mac_control = &nic->mac_control; - config = &nic->config; - - /* - * rx_traffic_int reg is an R1 register, hence we read and write back - * the samevalue in the register to clear it. - */ - val64 = readq(&bar0->rx_traffic_int); - writeq(val64, &bar0->rx_traffic_int); - - for (i = 0; i < config->rx_ring_num; i++) { - get_info = mac_control->rx_curr_get_info[i]; - get_block = get_info.block_index; - put_info = mac_control->rx_curr_put_info[i]; - put_block = put_info.block_index; - ring_bufs = config->rx_cfg[i].num_rxd; - rxdp = nic->rx_blocks[i][get_block].block_virt_addr + - get_info.offset; -#ifndef CONFIG_2BUFF_MODE - get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) + + get_info = ring_data->rx_curr_get_info; + get_block = get_info.block_index; + put_info = ring_data->rx_curr_put_info; + put_block = put_info.block_index; + ring_bufs = get_info.ring_len+1; + rxdp = ring_data->rx_blocks[get_block].block_virt_addr + get_info.offset; - spin_lock(&nic->put_lock); - put_offset = nic->put_pos[i]; - spin_unlock(&nic->put_lock); - while ((!(rxdp->Control_1 & RXD_OWN_XENA)) && - (((get_offset + 1) % ring_bufs) != put_offset)) { - if (rxdp->Control_1 == END_OF_BLOCK) { - rxdp = (RxD_t *) ((unsigned long) - rxdp->Control_2); - get_info.offset++; - get_info.offset %= - (MAX_RXDS_PER_BLOCK + 1); - get_block++; - get_block %= nic->block_count[i]; - mac_control->rx_curr_get_info[i]. - offset = get_info.offset; - mac_control->rx_curr_get_info[i]. - block_index = get_block; - continue; - } - get_offset = - (get_block * (MAX_RXDS_PER_BLOCK + 1)) + - get_info.offset; - skb = (struct sk_buff *) ((unsigned long) - rxdp->Host_Control); - if (skb == NULL) { - DBG_PRINT(ERR_DBG, "%s: The skb is ", - dev->name); - DBG_PRINT(ERR_DBG, "Null in Rx Intr\n"); - return; - } - val64 = RXD_GET_BUFFER0_SIZE(rxdp->Control_2); - val16 = (u16) (val64 >> 48); - cksum = RXD_GET_L4_CKSUM(rxdp->Control_1); - pci_unmap_single(nic->pdev, (dma_addr_t) - rxdp->Buffer0_ptr, - dev->mtu + - HEADER_ETHERNET_II_802_3_SIZE + - HEADER_802_2_SIZE + - HEADER_SNAP_SIZE, - PCI_DMA_FROMDEVICE); - rx_osm_handler(nic, val16, rxdp, i); - get_info.offset++; - get_info.offset %= (MAX_RXDS_PER_BLOCK + 1); - rxdp = - nic->rx_blocks[i][get_block].block_virt_addr + - get_info.offset; - mac_control->rx_curr_get_info[i].offset = - get_info.offset; - pkt_cnt++; - if ((indicate_max_pkts) - && (pkt_cnt > indicate_max_pkts)) - break; + get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) + + get_info.offset; +#ifndef CONFIG_S2IO_NAPI + spin_lock(&nic->put_lock); + put_offset = ring_data->put_pos; + spin_unlock(&nic->put_lock); +#else + put_offset = (put_block * (MAX_RXDS_PER_BLOCK + 1)) + + put_info.offset; +#endif + while (RXD_IS_UP2DT(rxdp) && + (((get_offset + 1) % ring_bufs) != put_offset)) { + skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control); + if (skb == NULL) { + DBG_PRINT(ERR_DBG, "%s: The skb is ", + dev->name); + DBG_PRINT(ERR_DBG, "Null in Rx Intr\n"); + spin_unlock(&nic->rx_lock); + return; } +#ifndef CONFIG_2BUFF_MODE + pci_unmap_single(nic->pdev, (dma_addr_t) + rxdp->Buffer0_ptr, + dev->mtu + + HEADER_ETHERNET_II_802_3_SIZE + + HEADER_802_2_SIZE + + HEADER_SNAP_SIZE, + PCI_DMA_FROMDEVICE); #else - get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) + + pci_unmap_single(nic->pdev, (dma_addr_t) + rxdp->Buffer0_ptr, + BUF0_LEN, PCI_DMA_FROMDEVICE); + pci_unmap_single(nic->pdev, (dma_addr_t) + rxdp->Buffer1_ptr, + BUF1_LEN, PCI_DMA_FROMDEVICE); + pci_unmap_single(nic->pdev, (dma_addr_t) + rxdp->Buffer2_ptr, + dev->mtu + BUF0_LEN + 4, + PCI_DMA_FROMDEVICE); +#endif + rx_osm_handler(ring_data, rxdp); + get_info.offset++; + ring_data->rx_curr_get_info.offset = get_info.offset; - spin_lock(&nic->put_lock); - put_offset = nic->put_pos[i]; - spin_unlock(&nic->put_lock); - while (((!(rxdp->Control_1 & RXD_OWN_XENA)) && - !(rxdp->Control_2 & BIT(0))) && - (((get_offset + 1) % ring_bufs) != put_offset)) { - skb = (struct sk_buff *) ((unsigned long) - rxdp->Host_Control); - if (skb == NULL) { - DBG_PRINT(ERR_DBG, "%s: The skb is ", - dev->name); - DBG_PRINT(ERR_DBG, "Null in Rx Intr\n"); - return; - } - - pci_unmap_single(nic->pdev, (dma_addr_t) - rxdp->Buffer0_ptr, - BUF0_LEN, PCI_DMA_FROMDEVICE); - pci_unmap_single(nic->pdev, (dma_addr_t) - rxdp->Buffer1_ptr, - BUF1_LEN, PCI_DMA_FROMDEVICE); - pci_unmap_single(nic->pdev, (dma_addr_t) - rxdp->Buffer2_ptr, - dev->mtu + BUF0_LEN + 4, - PCI_DMA_FROMDEVICE); - ba = &nic->ba[i][get_block][get_info.offset]; - - rx_osm_handler(nic, rxdp, i, ba); - - get_info.offset++; - mac_control->rx_curr_get_info[i].offset = - get_info.offset; - rxdp = - nic->rx_blocks[i][get_block].block_virt_addr + - get_info.offset; + rxdp = ring_data->rx_blocks[get_block].block_virt_addr + + get_info.offset; + if (get_info.offset && + (!(get_info.offset % MAX_RXDS_PER_BLOCK))) { + get_info.offset = 0; + ring_data->rx_curr_get_info.offset + = get_info.offset; + get_block++; + get_block %= ring_data->block_count; + ring_data->rx_curr_get_info.block_index + = get_block; + rxdp = ring_data->rx_blocks[get_block].block_virt_addr; + } - if (get_info.offset && - (!(get_info.offset % MAX_RXDS_PER_BLOCK))) { - get_info.offset = 0; - mac_control->rx_curr_get_info[i]. - offset = get_info.offset; - get_block++; - get_block %= nic->block_count[i]; - mac_control->rx_curr_get_info[i]. - block_index = get_block; - rxdp = - nic->rx_blocks[i][get_block]. - block_virt_addr; - } - get_offset = - (get_block * (MAX_RXDS_PER_BLOCK + 1)) + + get_offset = (get_block * (MAX_RXDS_PER_BLOCK + 1)) + get_info.offset; - pkt_cnt++; - if ((indicate_max_pkts) - && (pkt_cnt > indicate_max_pkts)) - break; - } -#endif +#ifdef CONFIG_S2IO_NAPI + nic->pkts_to_process -= 1; + if (!nic->pkts_to_process) + break; +#else + pkt_cnt++; if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts)) break; +#endif } + spin_unlock(&nic->rx_lock); } -#endif -/** + +/** * tx_intr_handler - Transmit interrupt handler * @nic : device private variable - * Description: - * If an interrupt was raised to indicate DMA complete of the - * Tx packet, this function is called. It identifies the last TxD - * whose buffer was freed and frees all skbs whose data have already + * Description: + * If an interrupt was raised to indicate DMA complete of the + * Tx packet, this function is called. It identifies the last TxD + * whose buffer was freed and frees all skbs whose data have already * DMA'ed into the NICs internal memory. * Return Value: * NONE */ -static void tx_intr_handler(struct s2io_nic *nic) +static void tx_intr_handler(fifo_info_t *fifo_data) { - XENA_dev_config_t __iomem *bar0 = nic->bar0; + nic_t *nic = fifo_data->nic; struct net_device *dev = (struct net_device *) nic->dev; tx_curr_get_info_t get_info, put_info; struct sk_buff *skb; TxD_t *txdlp; - register u64 val64 = 0; - int i; u16 j, frg_cnt; - mac_info_t *mac_control; - struct config_param *config; - mac_control = &nic->mac_control; - config = &nic->config; - - /* - * tx_traffic_int reg is an R1 register, hence we read and write - * back the samevalue in the register to clear it. - */ - val64 = readq(&bar0->tx_traffic_int); - writeq(val64, &bar0->tx_traffic_int); + get_info = fifo_data->tx_curr_get_info; + put_info = fifo_data->tx_curr_put_info; + txdlp = (TxD_t *) fifo_data->list_info[get_info.offset]. + list_virt_addr; + while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) && + (get_info.offset != put_info.offset) && + (txdlp->Host_Control)) { + /* Check for TxD errors */ + if (txdlp->Control_1 & TXD_T_CODE) { + unsigned long long err; + err = txdlp->Control_1 & TXD_T_CODE; + DBG_PRINT(ERR_DBG, "***TxD error %llx\n", + err); + } - for (i = 0; i < config->tx_fifo_num; i++) { - get_info = mac_control->tx_curr_get_info[i]; - put_info = mac_control->tx_curr_put_info[i]; - txdlp = (TxD_t *) nic->list_info[i][get_info.offset]. - list_virt_addr; - while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) && - (get_info.offset != put_info.offset) && - (txdlp->Host_Control)) { - /* Check for TxD errors */ - if (txdlp->Control_1 & TXD_T_CODE) { - unsigned long long err; - err = txdlp->Control_1 & TXD_T_CODE; - DBG_PRINT(ERR_DBG, "***TxD error %llx\n", - err); - } + skb = (struct sk_buff *) ((unsigned long) + txdlp->Host_Control); + if (skb == NULL) { + DBG_PRINT(ERR_DBG, "%s: Null skb ", + __FUNCTION__); + DBG_PRINT(ERR_DBG, "in Tx Free Intr\n"); + return; + } - skb = (struct sk_buff *) ((unsigned long) - txdlp->Host_Control); - if (skb == NULL) { - DBG_PRINT(ERR_DBG, "%s: Null skb ", - dev->name); - DBG_PRINT(ERR_DBG, "in Tx Free Intr\n"); - return; + frg_cnt = skb_shinfo(skb)->nr_frags; + nic->tx_pkt_count++; + + pci_unmap_single(nic->pdev, (dma_addr_t) + txdlp->Buffer_Pointer, + skb->len - skb->data_len, + PCI_DMA_TODEVICE); + if (frg_cnt) { + TxD_t *temp; + temp = txdlp; + txdlp++; + for (j = 0; j < frg_cnt; j++, txdlp++) { + skb_frag_t *frag = + &skb_shinfo(skb)->frags[j]; + if (!txdlp->Buffer_Pointer) + break; + pci_unmap_page(nic->pdev, + (dma_addr_t) + txdlp-> + Buffer_Pointer, + frag->size, + PCI_DMA_TODEVICE); } - nic->tx_pkt_count++; - - frg_cnt = skb_shinfo(skb)->nr_frags; - - /* For unfragmented skb */ - pci_unmap_single(nic->pdev, (dma_addr_t) - txdlp->Buffer_Pointer, - skb->len - skb->data_len, - PCI_DMA_TODEVICE); - if (frg_cnt) { - TxD_t *temp = txdlp; - txdlp++; - for (j = 0; j < frg_cnt; j++, txdlp++) { - skb_frag_t *frag = - &skb_shinfo(skb)->frags[j]; - pci_unmap_page(nic->pdev, - (dma_addr_t) - txdlp-> - Buffer_Pointer, - frag->size, - PCI_DMA_TODEVICE); - } - txdlp = temp; - } - memset(txdlp, 0, - (sizeof(TxD_t) * config->max_txds)); - - /* Updating the statistics block */ - nic->stats.tx_packets++; - nic->stats.tx_bytes += skb->len; - dev_kfree_skb_irq(skb); - - get_info.offset++; - get_info.offset %= get_info.fifo_len + 1; - txdlp = (TxD_t *) nic->list_info[i] - [get_info.offset].list_virt_addr; - mac_control->tx_curr_get_info[i].offset = - get_info.offset; + txdlp = temp; } + memset(txdlp, 0, + (sizeof(TxD_t) * fifo_data->max_txds)); + + /* Updating the statistics block */ + nic->stats.tx_bytes += skb->len; + dev_kfree_skb_irq(skb); + + get_info.offset++; + get_info.offset %= get_info.fifo_len + 1; + txdlp = (TxD_t *) fifo_data->list_info + [get_info.offset].list_virt_addr; + fifo_data->tx_curr_get_info.offset = + get_info.offset; } spin_lock(&nic->tx_lock); @@ -2301,13 +2655,13 @@ static void tx_intr_handler(struct s2io_nic *nic) spin_unlock(&nic->tx_lock); } -/** +/** * alarm_intr_handler - Alarm Interrrupt handler * @nic: device private variable - * Description: If the interrupt was neither because of Rx packet or Tx + * Description: If the interrupt was neither because of Rx packet or Tx * complete, this function is called. If the interrupt was to indicate - * a loss of link, the OSM link status handler is invoked for any other - * alarm interrupt the block that raised the interrupt is displayed + * a loss of link, the OSM link status handler is invoked for any other + * alarm interrupt the block that raised the interrupt is displayed * and a H/W reset is issued. * Return Value: * NONE @@ -2320,10 +2674,32 @@ static void alarm_intr_handler(struct s2io_nic *nic) register u64 val64 = 0, err_reg = 0; /* Handling link status change error Intr */ - err_reg = readq(&bar0->mac_rmac_err_reg); - writeq(err_reg, &bar0->mac_rmac_err_reg); - if (err_reg & RMAC_LINK_STATE_CHANGE_INT) { - schedule_work(&nic->set_link_task); + if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) { + err_reg = readq(&bar0->mac_rmac_err_reg); + writeq(err_reg, &bar0->mac_rmac_err_reg); + if (err_reg & RMAC_LINK_STATE_CHANGE_INT) { + schedule_work(&nic->set_link_task); + } + } + + /* Handling Ecc errors */ + val64 = readq(&bar0->mc_err_reg); + writeq(val64, &bar0->mc_err_reg); + if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) { + if (val64 & MC_ERR_REG_ECC_ALL_DBL) { + nic->mac_control.stats_info->sw_stat. + double_ecc_errs++; + DBG_PRINT(ERR_DBG, "%s: Device indicates ", + dev->name); + DBG_PRINT(ERR_DBG, "double ECC error!!\n"); + if (nic->device_type != XFRAME_II_DEVICE) { + netif_stop_queue(dev); + schedule_work(&nic->rst_timer_task); + } + } else { + nic->mac_control.stats_info->sw_stat. + single_ecc_errs++; + } } /* In case of a serious error, the device will be Reset. */ @@ -2338,7 +2714,7 @@ static void alarm_intr_handler(struct s2io_nic *nic) /* * Also as mentioned in the latest Errata sheets if the PCC_FB_ECC * Error occurs, the adapter will be recycled by disabling the - * adapter enable bit and enabling it again after the device + * adapter enable bit and enabling it again after the device * becomes Quiescent. */ val64 = readq(&bar0->pcc_err_reg); @@ -2354,18 +2730,18 @@ static void alarm_intr_handler(struct s2io_nic *nic) /* Other type of interrupts are not being handled now, TODO */ } -/** +/** * wait_for_cmd_complete - waits for a command to complete. - * @sp : private member of the device structure, which is a pointer to the + * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. - * Description: Function that waits for a command to Write into RMAC - * ADDR DATA registers to be completed and returns either success or - * error depending on whether the command was complete or not. + * Description: Function that waits for a command to Write into RMAC + * ADDR DATA registers to be completed and returns either success or + * error depending on whether the command was complete or not. * Return value: * SUCCESS on success and FAILURE on failure. */ -static int wait_for_cmd_complete(nic_t * sp) +int wait_for_cmd_complete(nic_t * sp) { XENA_dev_config_t __iomem *bar0 = sp->bar0; int ret = FAILURE, cnt = 0; @@ -2385,29 +2761,32 @@ static int wait_for_cmd_complete(nic_t * sp) return ret; } -/** - * s2io_reset - Resets the card. +/** + * s2io_reset - Resets the card. * @sp : private member of the device structure. * Description: Function to Reset the card. This function then also - * restores the previously saved PCI configuration space registers as + * restores the previously saved PCI configuration space registers as * the card reset also resets the configuration space. * Return value: * void. */ -static void s2io_reset(nic_t * sp) +void s2io_reset(nic_t * sp) { XENA_dev_config_t __iomem *bar0 = sp->bar0; u64 val64; - u16 subid; + u16 subid, pci_cmd; + + /* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */ + pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd)); val64 = SW_RESET_ALL; writeq(val64, &bar0->sw_reset); - /* - * At this stage, if the PCI write is indeed completed, the - * card is reset and so is the PCI Config space of the device. - * So a read cannot be issued at this stage on any of the + /* + * At this stage, if the PCI write is indeed completed, the + * card is reset and so is the PCI Config space of the device. + * So a read cannot be issued at this stage on any of the * registers to ensure the write into "sw_reset" register * has gone through. * Question: Is there any system call that will explicitly force @@ -2418,42 +2797,72 @@ static void s2io_reset(nic_t * sp) */ msleep(250); - /* Restore the PCI state saved during initializarion. */ + /* Restore the PCI state saved during initialization. */ pci_restore_state(sp->pdev); + pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, + pci_cmd); s2io_init_pci(sp); msleep(250); + /* Set swapper to enable I/O register access */ + s2io_set_swapper(sp); + + /* Clear certain PCI/PCI-X fields after reset */ + if (sp->device_type == XFRAME_II_DEVICE) { + /* Clear parity err detect bit */ + pci_write_config_word(sp->pdev, PCI_STATUS, 0x8000); + + /* Clearing PCIX Ecc status register */ + pci_write_config_dword(sp->pdev, 0x68, 0x7C); + + /* Clearing PCI_STATUS error reflected here */ + writeq(BIT(62), &bar0->txpic_int_reg); + } + + /* Reset device statistics maintained by OS */ + memset(&sp->stats, 0, sizeof (struct net_device_stats)); + /* SXE-002: Configure link and activity LED to turn it off */ subid = sp->pdev->subsystem_device; - if ((subid & 0xFF) >= 0x07) { + if (((subid & 0xFF) >= 0x07) && + (sp->device_type == XFRAME_I_DEVICE)) { val64 = readq(&bar0->gpio_control); val64 |= 0x0000800000000000ULL; writeq(val64, &bar0->gpio_control); val64 = 0x0411040400000000ULL; - writeq(val64, (void __iomem *) bar0 + 0x2700); + writeq(val64, (void __iomem *) ((u8 *) bar0 + 0x2700)); + } + + /* + * Clear spurious ECC interrupts that would have occured on + * XFRAME II cards after reset. + */ + if (sp->device_type == XFRAME_II_DEVICE) { + val64 = readq(&bar0->pcc_err_reg); + writeq(val64, &bar0->pcc_err_reg); } sp->device_enabled_once = FALSE; } /** - * s2io_set_swapper - to set the swapper controle on the card - * @sp : private member of the device structure, + * s2io_set_swapper - to set the swapper controle on the card + * @sp : private member of the device structure, * pointer to the s2io_nic structure. - * Description: Function to set the swapper control on the card + * Description: Function to set the swapper control on the card * correctly depending on the 'endianness' of the system. * Return value: * SUCCESS on success and FAILURE on failure. */ -static int s2io_set_swapper(nic_t * sp) +int s2io_set_swapper(nic_t * sp) { struct net_device *dev = sp->dev; XENA_dev_config_t __iomem *bar0 = sp->bar0; u64 val64, valt, valr; - /* + /* * Set proper endian settings and verify the same by reading * the PIF Feed-back register. */ @@ -2505,8 +2914,9 @@ static int s2io_set_swapper(nic_t * sp) i++; } if(i == 4) { + unsigned long long x = val64; DBG_PRINT(ERR_DBG, "Write failed, Xmsi_addr "); - DBG_PRINT(ERR_DBG, "reads:0x%llx\n",val64); + DBG_PRINT(ERR_DBG, "reads:0x%llx\n", x); return FAILURE; } } @@ -2514,8 +2924,8 @@ static int s2io_set_swapper(nic_t * sp) val64 &= 0xFFFF000000000000ULL; #ifdef __BIG_ENDIAN - /* - * The device by default set to a big endian format, so a + /* + * The device by default set to a big endian format, so a * big endian driver need not set anything. */ val64 |= (SWAPPER_CTRL_TXP_FE | @@ -2531,9 +2941,9 @@ static int s2io_set_swapper(nic_t * sp) SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); writeq(val64, &bar0->swapper_ctrl); #else - /* + /* * Initially we enable all bits to make it accessible by the - * driver, then we selectively enable only those bits that + * driver, then we selectively enable only those bits that * we want to set. */ val64 |= (SWAPPER_CTRL_TXP_FE | @@ -2555,8 +2965,8 @@ static int s2io_set_swapper(nic_t * sp) #endif val64 = readq(&bar0->swapper_ctrl); - /* - * Verifying if endian settings are accurate by reading a + /* + * Verifying if endian settings are accurate by reading a * feedback register. */ val64 = readq(&bar0->pif_rd_swapper_fb); @@ -2576,55 +2986,63 @@ static int s2io_set_swapper(nic_t * sp) * Functions defined below concern the OS part of the driver * * ********************************************************* */ -/** +/** * s2io_open - open entry point of the driver * @dev : pointer to the device structure. * Description: * This function is the open entry point of the driver. It mainly calls a * function to allocate Rx buffers and inserts them into the buffer - * descriptors and then enables the Rx part of the NIC. + * descriptors and then enables the Rx part of the NIC. * Return value: * 0 on success and an appropriate (-)ve integer as defined in errno.h * file on failure. */ -static int s2io_open(struct net_device *dev) +int s2io_open(struct net_device *dev) { nic_t *sp = dev->priv; int err = 0; - /* - * Make sure you have link off by default every time + /* + * Make sure you have link off by default every time * Nic is initialized */ netif_carrier_off(dev); - sp->last_link_state = LINK_DOWN; + sp->last_link_state = 0; /* Initialize H/W and enable interrupts */ if (s2io_card_up(sp)) { DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n", dev->name); - return -ENODEV; + err = -ENODEV; + goto hw_init_failed; } /* After proper initialization of H/W, register ISR */ - err = request_irq((int) sp->irq, s2io_isr, SA_SHIRQ, + err = request_irq((int) sp->pdev->irq, s2io_isr, SA_SHIRQ, sp->name, dev); if (err) { - s2io_reset(sp); DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n", dev->name); - return err; + goto isr_registration_failed; } if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) { DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n"); - s2io_reset(sp); - return -ENODEV; + err = -ENODEV; + goto setting_mac_address_failed; } netif_start_queue(dev); return 0; + +setting_mac_address_failed: + free_irq(sp->pdev->irq, dev); +isr_registration_failed: + del_timer_sync(&sp->alarm_timer); + s2io_reset(sp); +hw_init_failed: + return err; } /** @@ -2640,16 +3058,15 @@ static int s2io_open(struct net_device *dev) * file on failure. */ -static int s2io_close(struct net_device *dev) +int s2io_close(struct net_device *dev) { nic_t *sp = dev->priv; - flush_scheduled_work(); netif_stop_queue(dev); /* Reset card, kill tasklet and free Tx and Rx buffers. */ s2io_card_down(sp); - free_irq(dev->irq, dev); + free_irq(sp->pdev->irq, dev); sp->device_close_flag = TRUE; /* Device is shut down. */ return 0; } @@ -2667,7 +3084,7 @@ static int s2io_close(struct net_device *dev) * 0 on success & 1 on failure. */ -static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) +int s2io_xmit(struct sk_buff *skb, struct net_device *dev) { nic_t *sp = dev->priv; u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off; @@ -2678,29 +3095,39 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) #ifdef NETIF_F_TSO int mss; #endif + u16 vlan_tag = 0; + int vlan_priority = 0; mac_info_t *mac_control; struct config_param *config; - XENA_dev_config_t __iomem *bar0 = sp->bar0; mac_control = &sp->mac_control; config = &sp->config; - DBG_PRINT(TX_DBG, "%s: In S2IO Tx routine\n", dev->name); + DBG_PRINT(TX_DBG, "%s: In Neterion Tx routine\n", dev->name); spin_lock_irqsave(&sp->tx_lock, flags); - if (atomic_read(&sp->card_state) == CARD_DOWN) { - DBG_PRINT(ERR_DBG, "%s: Card going down for reset\n", + DBG_PRINT(TX_DBG, "%s: Card going down for reset\n", dev->name); spin_unlock_irqrestore(&sp->tx_lock, flags); - return 1; + dev_kfree_skb(skb); + return 0; } queue = 0; - put_off = (u16) mac_control->tx_curr_put_info[queue].offset; - get_off = (u16) mac_control->tx_curr_get_info[queue].offset; - txdp = (TxD_t *) sp->list_info[queue][put_off].list_virt_addr; - queue_len = mac_control->tx_curr_put_info[queue].fifo_len + 1; + /* Get Fifo number to Transmit based on vlan priority */ + if (sp->vlgrp && vlan_tx_tag_present(skb)) { + vlan_tag = vlan_tx_tag_get(skb); + vlan_priority = vlan_tag >> 13; + queue = config->fifo_mapping[vlan_priority]; + } + + put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset; + get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset; + txdp = (TxD_t *) mac_control->fifos[queue].list_info[put_off]. + list_virt_addr; + + queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1; /* Avoid "put" pointer going beyond "get" pointer */ if (txdp->Host_Control || (((put_off + 1) % queue_len) == get_off)) { DBG_PRINT(ERR_DBG, "Error in xmit, No free TXDs.\n"); @@ -2709,6 +3136,15 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) spin_unlock_irqrestore(&sp->tx_lock, flags); return 0; } + + /* A buffer with no data will be dropped */ + if (!skb->len) { + DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name); + dev_kfree_skb(skb); + spin_unlock_irqrestore(&sp->tx_lock, flags); + return 0; + } + #ifdef NETIF_F_TSO mss = skb_shinfo(skb)->tso_size; if (mss) { @@ -2720,9 +3156,9 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) frg_cnt = skb_shinfo(skb)->nr_frags; frg_len = skb->len - skb->data_len; - txdp->Host_Control = (unsigned long) skb; txdp->Buffer_Pointer = pci_map_single (sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE); + txdp->Host_Control = (unsigned long) skb; if (skb->ip_summed == CHECKSUM_HW) { txdp->Control_2 |= (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN | @@ -2731,6 +3167,11 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) txdp->Control_2 |= config->tx_intr_type; + if (sp->vlgrp && vlan_tx_tag_present(skb)) { + txdp->Control_2 |= TXD_VLAN_ENABLE; + txdp->Control_2 |= TXD_VLAN_TAG(vlan_tag); + } + txdp->Control_1 |= (TXD_BUFFER0_SIZE(frg_len) | TXD_GATHER_CODE_FIRST); txdp->Control_1 |= TXD_LIST_OWN_XENA; @@ -2738,6 +3179,9 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) /* For fragmented SKB. */ for (i = 0; i < frg_cnt; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + /* A '0' length fragment will be ignored */ + if (!frag->size) + continue; txdp++; txdp->Buffer_Pointer = (u64) pci_map_page (sp->pdev, frag->page, frag->page_offset, @@ -2747,23 +3191,23 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) txdp->Control_1 |= TXD_GATHER_CODE_LAST; tx_fifo = mac_control->tx_FIFO_start[queue]; - val64 = sp->list_info[queue][put_off].list_phy_addr; + val64 = mac_control->fifos[queue].list_info[put_off].list_phy_addr; writeq(val64, &tx_fifo->TxDL_Pointer); val64 = (TX_FIFO_LAST_TXD_NUM(frg_cnt) | TX_FIFO_FIRST_LIST | TX_FIFO_LAST_LIST); + #ifdef NETIF_F_TSO if (mss) val64 |= TX_FIFO_SPECIAL_FUNC; #endif writeq(val64, &tx_fifo->List_Control); - /* Perform a PCI read to flush previous writes */ - val64 = readq(&bar0->general_int_status); + mmiowb(); put_off++; - put_off %= mac_control->tx_curr_put_info[queue].fifo_len + 1; - mac_control->tx_curr_put_info[queue].offset = put_off; + put_off %= mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1; + mac_control->fifos[queue].tx_curr_put_info.offset = put_off; /* Avoid "put" pointer going beyond "get" pointer */ if (((put_off + 1) % queue_len) == get_off) { @@ -2779,18 +3223,74 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } +static void +s2io_alarm_handle(unsigned long data) +{ + nic_t *sp = (nic_t *)data; + + alarm_intr_handler(sp); + mod_timer(&sp->alarm_timer, jiffies + HZ / 2); +} + +static void s2io_txpic_intr_handle(nic_t *sp) +{ + XENA_dev_config_t *bar0 = (XENA_dev_config_t *) sp->bar0; + u64 val64; + + val64 = readq(&bar0->pic_int_status); + if (val64 & PIC_INT_GPIO) { + val64 = readq(&bar0->gpio_int_reg); + if ((val64 & GPIO_INT_REG_LINK_DOWN) && + (val64 & GPIO_INT_REG_LINK_UP)) { + val64 |= GPIO_INT_REG_LINK_DOWN; + val64 |= GPIO_INT_REG_LINK_UP; + writeq(val64, &bar0->gpio_int_reg); + goto masking; + } + + if (((sp->last_link_state == LINK_UP) && + (val64 & GPIO_INT_REG_LINK_DOWN)) || + ((sp->last_link_state == LINK_DOWN) && + (val64 & GPIO_INT_REG_LINK_UP))) { + val64 = readq(&bar0->gpio_int_mask); + val64 |= GPIO_INT_MASK_LINK_DOWN; + val64 |= GPIO_INT_MASK_LINK_UP; + writeq(val64, &bar0->gpio_int_mask); + s2io_set_link((unsigned long)sp); + } +masking: + if (sp->last_link_state == LINK_UP) { + /*enable down interrupt */ + val64 = readq(&bar0->gpio_int_mask); + /* unmasks link down intr */ + val64 &= ~GPIO_INT_MASK_LINK_DOWN; + /* masks link up intr */ + val64 |= GPIO_INT_MASK_LINK_UP; + writeq(val64, &bar0->gpio_int_mask); + } else { + /*enable UP Interrupt */ + val64 = readq(&bar0->gpio_int_mask); + /* unmasks link up interrupt */ + val64 &= ~GPIO_INT_MASK_LINK_UP; + /* masks link down interrupt */ + val64 |= GPIO_INT_MASK_LINK_DOWN; + writeq(val64, &bar0->gpio_int_mask); + } + } +} + /** * s2io_isr - ISR handler of the device . * @irq: the irq of the device. * @dev_id: a void pointer to the dev structure of the NIC. * @pt_regs: pointer to the registers pushed on the stack. - * Description: This function is the ISR handler of the device. It - * identifies the reason for the interrupt and calls the relevant - * service routines. As a contongency measure, this ISR allocates the + * Description: This function is the ISR handler of the device. It + * identifies the reason for the interrupt and calls the relevant + * service routines. As a contongency measure, this ISR allocates the * recv buffers, if their numbers are below the panic value which is * presently set to 25% of the original number of rcv buffers allocated. * Return value: - * IRQ_HANDLED: will be returned if IRQ was handled by this routine + * IRQ_HANDLED: will be returned if IRQ was handled by this routine * IRQ_NONE: will be returned if interrupt is not from our device */ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs) @@ -2798,40 +3298,31 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs) struct net_device *dev = (struct net_device *) dev_id; nic_t *sp = dev->priv; XENA_dev_config_t __iomem *bar0 = sp->bar0; -#ifndef CONFIG_S2IO_NAPI - int i, ret; -#endif - u64 reason = 0; + int i; + u64 reason = 0, val64; mac_info_t *mac_control; struct config_param *config; + atomic_inc(&sp->isr_cnt); mac_control = &sp->mac_control; config = &sp->config; - /* + /* * Identify the cause for interrupt and call the appropriate * interrupt handler. Causes for the interrupt could be; * 1. Rx of packet. * 2. Tx complete. * 3. Link down. - * 4. Error in any functional blocks of the NIC. + * 4. Error in any functional blocks of the NIC. */ reason = readq(&bar0->general_int_status); if (!reason) { /* The interrupt was not raised by Xena. */ + atomic_dec(&sp->isr_cnt); return IRQ_NONE; } - /* If Intr is because of Tx Traffic */ - if (reason & GEN_INTR_TXTRAFFIC) { - tx_intr_handler(sp); - } - - /* If Intr is because of an error */ - if (reason & (GEN_ERROR_INTR)) - alarm_intr_handler(sp); - #ifdef CONFIG_S2IO_NAPI if (reason & GEN_INTR_RXTRAFFIC) { if (netif_rx_schedule_prep(dev)) { @@ -2843,17 +3334,43 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs) #else /* If Intr is because of Rx Traffic */ if (reason & GEN_INTR_RXTRAFFIC) { - rx_intr_handler(sp); + /* + * rx_traffic_int reg is an R1 register, writing all 1's + * will ensure that the actual interrupt causing bit get's + * cleared and hence a read can be avoided. + */ + val64 = 0xFFFFFFFFFFFFFFFFULL; + writeq(val64, &bar0->rx_traffic_int); + for (i = 0; i < config->rx_ring_num; i++) { + rx_intr_handler(&mac_control->rings[i]); + } } #endif - /* - * If the Rx buffer count is below the panic threshold then - * reallocate the buffers from the interrupt handler itself, + /* If Intr is because of Tx Traffic */ + if (reason & GEN_INTR_TXTRAFFIC) { + /* + * tx_traffic_int reg is an R1 register, writing all 1's + * will ensure that the actual interrupt causing bit get's + * cleared and hence a read can be avoided. + */ + val64 = 0xFFFFFFFFFFFFFFFFULL; + writeq(val64, &bar0->tx_traffic_int); + + for (i = 0; i < config->tx_fifo_num; i++) + tx_intr_handler(&mac_control->fifos[i]); + } + + if (reason & GEN_INTR_TXPIC) + s2io_txpic_intr_handle(sp); + /* + * If the Rx buffer count is below the panic threshold then + * reallocate the buffers from the interrupt handler itself, * else schedule a tasklet to reallocate the buffers. */ #ifndef CONFIG_S2IO_NAPI for (i = 0; i < config->rx_ring_num; i++) { + int ret; int rxb_size = atomic_read(&sp->rx_bufs_left[i]); int level = rx_buffer_level(sp, rxb_size, i); @@ -2865,6 +3382,7 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs) dev->name); DBG_PRINT(ERR_DBG, " in ISR!!\n"); clear_bit(0, (&sp->tasklet_status)); + atomic_dec(&sp->isr_cnt); return IRQ_HANDLED; } clear_bit(0, (&sp->tasklet_status)); @@ -2874,33 +3392,69 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs) } #endif + atomic_dec(&sp->isr_cnt); return IRQ_HANDLED; } /** - * s2io_get_stats - Updates the device statistics structure. + * s2io_updt_stats - + */ +static void s2io_updt_stats(nic_t *sp) +{ + XENA_dev_config_t __iomem *bar0 = sp->bar0; + u64 val64; + int cnt = 0; + + if (atomic_read(&sp->card_state) == CARD_UP) { + /* Apprx 30us on a 133 MHz bus */ + val64 = SET_UPDT_CLICKS(10) | + STAT_CFG_ONE_SHOT_EN | STAT_CFG_STAT_EN; + writeq(val64, &bar0->stat_cfg); + do { + udelay(100); + val64 = readq(&bar0->stat_cfg); + if (!(val64 & BIT(0))) + break; + cnt++; + if (cnt == 5) + break; /* Updt failed */ + } while(1); + } +} + +/** + * s2io_get_stats - Updates the device statistics structure. * @dev : pointer to the device structure. * Description: - * This function updates the device statistics structure in the s2io_nic + * This function updates the device statistics structure in the s2io_nic * structure and returns a pointer to the same. * Return value: * pointer to the updated net_device_stats structure. */ -static struct net_device_stats *s2io_get_stats(struct net_device *dev) +struct net_device_stats *s2io_get_stats(struct net_device *dev) { nic_t *sp = dev->priv; mac_info_t *mac_control; struct config_param *config; + mac_control = &sp->mac_control; config = &sp->config; - sp->stats.tx_errors = mac_control->stats_info->tmac_any_err_frms; - sp->stats.rx_errors = mac_control->stats_info->rmac_drop_frms; - sp->stats.multicast = mac_control->stats_info->rmac_vld_mcst_frms; + /* Configure Stats for immediate updt */ + s2io_updt_stats(sp); + + sp->stats.tx_packets = + le32_to_cpu(mac_control->stats_info->tmac_frms); + sp->stats.tx_errors = + le32_to_cpu(mac_control->stats_info->tmac_any_err_frms); + sp->stats.rx_errors = + le32_to_cpu(mac_control->stats_info->rmac_drop_frms); + sp->stats.multicast = + le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms); sp->stats.rx_length_errors = - mac_control->stats_info->rmac_long_frms; + le32_to_cpu(mac_control->stats_info->rmac_long_frms); return (&sp->stats); } @@ -2909,8 +3463,8 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev) * s2io_set_multicast - entry point for multicast address enable/disable. * @dev : pointer to the device structure * Description: - * This function is a driver entry point which gets called by the kernel - * whenever multicast addresses must be enabled/disabled. This also gets + * This function is a driver entry point which gets called by the kernel + * whenever multicast addresses must be enabled/disabled. This also gets * called to set/reset promiscuous mode. Depending on the deivce flag, we * determine, if multicast address must be enabled or if promiscuous mode * is to be disabled etc. @@ -2948,6 +3502,8 @@ static void s2io_set_multicast(struct net_device *dev) /* Disable all Multicast addresses */ writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr), &bar0->rmac_addr_data0_mem); + writeq(RMAC_ADDR_DATA1_MEM_MASK(0x0), + &bar0->rmac_addr_data1_mem); val64 = RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | RMAC_ADDR_CMD_MEM_OFFSET(sp->all_multi_pos); @@ -3010,7 +3566,7 @@ static void s2io_set_multicast(struct net_device *dev) writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr), &bar0->rmac_addr_data0_mem); writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL), - &bar0->rmac_addr_data1_mem); + &bar0->rmac_addr_data1_mem); val64 = RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | RMAC_ADDR_CMD_MEM_OFFSET @@ -3039,8 +3595,7 @@ static void s2io_set_multicast(struct net_device *dev) writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr), &bar0->rmac_addr_data0_mem); writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL), - &bar0->rmac_addr_data1_mem); - + &bar0->rmac_addr_data1_mem); val64 = RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | RMAC_ADDR_CMD_MEM_OFFSET @@ -3059,12 +3614,12 @@ static void s2io_set_multicast(struct net_device *dev) } /** - * s2io_set_mac_addr - Programs the Xframe mac address + * s2io_set_mac_addr - Programs the Xframe mac address * @dev : pointer to the device structure. * @addr: a uchar pointer to the new mac address which is to be set. - * Description : This procedure will program the Xframe to receive + * Description : This procedure will program the Xframe to receive * frames with new Mac Address - * Return value: SUCCESS on success and an appropriate (-)ve integer + * Return value: SUCCESS on success and an appropriate (-)ve integer * as defined in errno.h file on failure. */ @@ -3075,10 +3630,10 @@ int s2io_set_mac_addr(struct net_device *dev, u8 * addr) register u64 val64, mac_addr = 0; int i; - /* + /* * Set the new MAC address as the new unicast filter and reflect this * change on the device address registered with the OS. It will be - * at offset 0. + * at offset 0. */ for (i = 0; i < ETH_ALEN; i++) { mac_addr <<= 8; @@ -3102,12 +3657,12 @@ int s2io_set_mac_addr(struct net_device *dev, u8 * addr) } /** - * s2io_ethtool_sset - Sets different link parameters. + * s2io_ethtool_sset - Sets different link parameters. * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * @info: pointer to the structure with parameters given by ethtool to set * link information. * Description: - * The function sets different link parameters provided by the user onto + * The function sets different link parameters provided by the user onto * the NIC. * Return value: * 0 on success. @@ -3129,7 +3684,7 @@ static int s2io_ethtool_sset(struct net_device *dev, } /** - * s2io_ethtol_gset - Return link specific information. + * s2io_ethtol_gset - Return link specific information. * @sp : private member of the device structure, pointer to the * s2io_nic structure. * @info : pointer to the structure with parameters given by ethtool @@ -3161,8 +3716,8 @@ static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info) } /** - * s2io_ethtool_gdrvinfo - Returns driver specific information. - * @sp : private member of the device structure, which is a pointer to the + * s2io_ethtool_gdrvinfo - Returns driver specific information. + * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * @info : pointer to the structure with parameters given by ethtool to * return driver information. @@ -3190,9 +3745,9 @@ static void s2io_ethtool_gdrvinfo(struct net_device *dev, /** * s2io_ethtool_gregs - dumps the entire space of Xfame into the buffer. - * @sp: private member of the device structure, which is a pointer to the + * @sp: private member of the device structure, which is a pointer to the * s2io_nic structure. - * @regs : pointer to the structure with parameters given by ethtool for + * @regs : pointer to the structure with parameters given by ethtool for * dumping the registers. * @reg_space: The input argumnet into which all the registers are dumped. * Description: @@ -3221,11 +3776,11 @@ static void s2io_ethtool_gregs(struct net_device *dev, /** * s2io_phy_id - timer function that alternates adapter LED. - * @data : address of the private member of the device structure, which + * @data : address of the private member of the device structure, which * is a pointer to the s2io_nic structure, provided as an u32. - * Description: This is actually the timer function that alternates the - * adapter LED bit of the adapter control bit to set/reset every time on - * invocation. The timer is set for 1/2 a second, hence tha NIC blinks + * Description: This is actually the timer function that alternates the + * adapter LED bit of the adapter control bit to set/reset every time on + * invocation. The timer is set for 1/2 a second, hence tha NIC blinks * once every second. */ static void s2io_phy_id(unsigned long data) @@ -3236,7 +3791,8 @@ static void s2io_phy_id(unsigned long data) u16 subid; subid = sp->pdev->subsystem_device; - if ((subid & 0xFF) >= 0x07) { + if ((sp->device_type == XFRAME_II_DEVICE) || + ((subid & 0xFF) >= 0x07)) { val64 = readq(&bar0->gpio_control); val64 ^= GPIO_CTRL_GPIO_0; writeq(val64, &bar0->gpio_control); @@ -3253,12 +3809,12 @@ static void s2io_phy_id(unsigned long data) * s2io_ethtool_idnic - To physically identify the nic on the system. * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. - * @id : pointer to the structure with identification parameters given by + * @id : pointer to the structure with identification parameters given by * ethtool. * Description: Used to physically identify the NIC on the system. - * The Link LED will blink for a time specified by the user for + * The Link LED will blink for a time specified by the user for * identification. - * NOTE: The Link has to be Up to be able to blink the LED. Hence + * NOTE: The Link has to be Up to be able to blink the LED. Hence * identification is possible only if it's link is up. * Return value: * int , returns 0 on success @@ -3273,7 +3829,8 @@ static int s2io_ethtool_idnic(struct net_device *dev, u32 data) subid = sp->pdev->subsystem_device; last_gpio_ctrl_val = readq(&bar0->gpio_control); - if ((subid & 0xFF) < 0x07) { + if ((sp->device_type == XFRAME_I_DEVICE) && + ((subid & 0xFF) < 0x07)) { val64 = readq(&bar0->adapter_control); if (!(val64 & ADAPTER_CNTL_EN)) { printk(KERN_ERR @@ -3288,12 +3845,12 @@ static int s2io_ethtool_idnic(struct net_device *dev, u32 data) } mod_timer(&sp->id_timer, jiffies); if (data) - msleep(data * 1000); + msleep_interruptible(data * HZ); else - msleep(0xFFFFFFFF); + msleep_interruptible(MAX_FLICKER_TIME); del_timer_sync(&sp->id_timer); - if (CARDS_WITH_FAULTY_LINK_INDICATORS(subid)) { + if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) { writeq(last_gpio_ctrl_val, &bar0->gpio_control); last_gpio_ctrl_val = readq(&bar0->gpio_control); } @@ -3303,7 +3860,8 @@ static int s2io_ethtool_idnic(struct net_device *dev, u32 data) /** * s2io_ethtool_getpause_data -Pause frame frame generation and reception. - * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. + * @sp : private member of the device structure, which is a pointer to the + * s2io_nic structure. * @ep : pointer to the structure with pause parameters given by ethtool. * Description: * Returns the Pause frame generation and reception capability of the NIC. @@ -3327,7 +3885,7 @@ static void s2io_ethtool_getpause_data(struct net_device *dev, /** * s2io_ethtool_setpause_data - set/reset pause frame generation. - * @sp : private member of the device structure, which is a pointer to the + * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * @ep : pointer to the structure with pause parameters given by ethtool. * Description: @@ -3338,7 +3896,7 @@ static void s2io_ethtool_getpause_data(struct net_device *dev, */ static int s2io_ethtool_setpause_data(struct net_device *dev, - struct ethtool_pauseparam *ep) + struct ethtool_pauseparam *ep) { u64 val64; nic_t *sp = dev->priv; @@ -3359,13 +3917,13 @@ static int s2io_ethtool_setpause_data(struct net_device *dev, /** * read_eeprom - reads 4 bytes of data from user given offset. - * @sp : private member of the device structure, which is a pointer to the + * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * @off : offset at which the data must be written * @data : Its an output parameter where the data read at the given - * offset is stored. + * offset is stored. * Description: - * Will read 4 bytes of data from the user given offset and return the + * Will read 4 bytes of data from the user given offset and return the * read data. * NOTE: Will allow to read only part of the EEPROM visible through the * I2C bus. @@ -3406,7 +3964,7 @@ static int read_eeprom(nic_t * sp, int off, u32 * data) * s2io_nic structure. * @off : offset at which the data must be written * @data : The data that is to be written - * @cnt : Number of bytes of the data that are actually to be written into + * @cnt : Number of bytes of the data that are actually to be written into * the Eeprom. (max of 3) * Description: * Actually writes the relevant part of the data value into the Eeprom @@ -3443,7 +4001,7 @@ static int write_eeprom(nic_t * sp, int off, u32 data, int cnt) /** * s2io_ethtool_geeprom - reads the value stored in the Eeprom. * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. - * @eeprom : pointer to the user level structure provided by ethtool, + * @eeprom : pointer to the user level structure provided by ethtool, * containing all relevant information. * @data_buf : user defined value to be written into Eeprom. * Description: Reads the values stored in the Eeprom at given offset @@ -3454,7 +4012,7 @@ static int write_eeprom(nic_t * sp, int off, u32 data, int cnt) */ static int s2io_ethtool_geeprom(struct net_device *dev, - struct ethtool_eeprom *eeprom, u8 * data_buf) + struct ethtool_eeprom *eeprom, u8 * data_buf) { u32 data, i, valid; nic_t *sp = dev->priv; @@ -3479,7 +4037,7 @@ static int s2io_ethtool_geeprom(struct net_device *dev, * s2io_ethtool_seeprom - tries to write the user provided value in Eeprom * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. - * @eeprom : pointer to the user level structure provided by ethtool, + * @eeprom : pointer to the user level structure provided by ethtool, * containing all relevant information. * @data_buf ; user defined value to be written into Eeprom. * Description: @@ -3527,8 +4085,8 @@ static int s2io_ethtool_seeprom(struct net_device *dev, } /** - * s2io_register_test - reads and writes into all clock domains. - * @sp : private member of the device structure, which is a pointer to the + * s2io_register_test - reads and writes into all clock domains. + * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * @data : variable that returns the result of each of the test conducted b * by the driver. @@ -3545,8 +4103,8 @@ static int s2io_register_test(nic_t * sp, uint64_t * data) u64 val64 = 0; int fail = 0; - val64 = readq(&bar0->pcc_enable); - if (val64 != 0xff00000000000000ULL) { + val64 = readq(&bar0->pif_rd_swapper_fb); + if (val64 != 0x123456789abcdefULL) { fail = 1; DBG_PRINT(INFO_DBG, "Read Test level 1 fails\n"); } @@ -3590,13 +4148,13 @@ static int s2io_register_test(nic_t * sp, uint64_t * data) } /** - * s2io_eeprom_test - to verify that EEprom in the xena can be programmed. + * s2io_eeprom_test - to verify that EEprom in the xena can be programmed. * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * @data:variable that returns the result of each of the test conducted by * the driver. * Description: - * Verify that EEPROM in the xena can be programmed using I2C_CONTROL + * Verify that EEPROM in the xena can be programmed using I2C_CONTROL * register. * Return value: * 0 on success. @@ -3661,14 +4219,14 @@ static int s2io_eeprom_test(nic_t * sp, uint64_t * data) /** * s2io_bist_test - invokes the MemBist test of the card . - * @sp : private member of the device structure, which is a pointer to the + * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. - * @data:variable that returns the result of each of the test conducted by + * @data:variable that returns the result of each of the test conducted by * the driver. * Description: * This invokes the MemBist test of the card. We give around * 2 secs time for the Test to complete. If it's still not complete - * within this peiod, we consider that the test failed. + * within this peiod, we consider that the test failed. * Return value: * 0 on success and -1 on failure. */ @@ -3697,13 +4255,13 @@ static int s2io_bist_test(nic_t * sp, uint64_t * data) } /** - * s2io-link_test - verifies the link state of the nic - * @sp ; private member of the device structure, which is a pointer to the + * s2io-link_test - verifies the link state of the nic + * @sp ; private member of the device structure, which is a pointer to the * s2io_nic structure. * @data: variable that returns the result of each of the test conducted by * the driver. * Description: - * The function verifies the link state of the NIC and updates the input + * The function verifies the link state of the NIC and updates the input * argument 'data' appropriately. * Return value: * 0 on success. @@ -3722,13 +4280,13 @@ static int s2io_link_test(nic_t * sp, uint64_t * data) } /** - * s2io_rldram_test - offline test for access to the RldRam chip on the NIC - * @sp - private member of the device structure, which is a pointer to the + * s2io_rldram_test - offline test for access to the RldRam chip on the NIC + * @sp - private member of the device structure, which is a pointer to the * s2io_nic structure. - * @data - variable that returns the result of each of the test + * @data - variable that returns the result of each of the test * conducted by the driver. * Description: - * This is one of the offline test that tests the read and write + * This is one of the offline test that tests the read and write * access to the RldRam chip on the NIC. * Return value: * 0 on success. @@ -3833,7 +4391,7 @@ static int s2io_rldram_test(nic_t * sp, uint64_t * data) * s2io_nic structure. * @ethtest : pointer to a ethtool command specific structure that will be * returned to the user. - * @data : variable that returns the result of each of the test + * @data : variable that returns the result of each of the test * conducted by the driver. * Description: * This function conducts 6 tests ( 4 offline and 2 online) to determine @@ -3851,23 +4409,18 @@ static void s2io_ethtool_test(struct net_device *dev, if (ethtest->flags == ETH_TEST_FL_OFFLINE) { /* Offline Tests. */ - if (orig_state) { + if (orig_state) s2io_close(sp->dev); - s2io_set_swapper(sp); - } else - s2io_set_swapper(sp); if (s2io_register_test(sp, &data[0])) ethtest->flags |= ETH_TEST_FL_FAILED; s2io_reset(sp); - s2io_set_swapper(sp); if (s2io_rldram_test(sp, &data[3])) ethtest->flags |= ETH_TEST_FL_FAILED; s2io_reset(sp); - s2io_set_swapper(sp); if (s2io_eeprom_test(sp, &data[1])) ethtest->flags |= ETH_TEST_FL_FAILED; @@ -3910,61 +4463,111 @@ static void s2io_get_ethtool_stats(struct net_device *dev, nic_t *sp = dev->priv; StatInfo_t *stat_info = sp->mac_control.stats_info; - tmp_stats[i++] = le32_to_cpu(stat_info->tmac_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->tmac_data_octets); + s2io_updt_stats(sp); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->tmac_frms_oflow) << 32 | + le32_to_cpu(stat_info->tmac_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->tmac_data_octets_oflow) << 32 | + le32_to_cpu(stat_info->tmac_data_octets); tmp_stats[i++] = le64_to_cpu(stat_info->tmac_drop_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->tmac_mcst_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->tmac_bcst_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->tmac_mcst_frms_oflow) << 32 | + le32_to_cpu(stat_info->tmac_mcst_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->tmac_bcst_frms_oflow) << 32 | + le32_to_cpu(stat_info->tmac_bcst_frms); tmp_stats[i++] = le64_to_cpu(stat_info->tmac_pause_ctrl_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->tmac_any_err_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->tmac_any_err_frms_oflow) << 32 | + le32_to_cpu(stat_info->tmac_any_err_frms); tmp_stats[i++] = le64_to_cpu(stat_info->tmac_vld_ip_octets); - tmp_stats[i++] = le32_to_cpu(stat_info->tmac_vld_ip); - tmp_stats[i++] = le32_to_cpu(stat_info->tmac_drop_ip); - tmp_stats[i++] = le32_to_cpu(stat_info->tmac_icmp); - tmp_stats[i++] = le32_to_cpu(stat_info->tmac_rst_tcp); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->tmac_vld_ip_oflow) << 32 | + le32_to_cpu(stat_info->tmac_vld_ip); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->tmac_drop_ip_oflow) << 32 | + le32_to_cpu(stat_info->tmac_drop_ip); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->tmac_icmp_oflow) << 32 | + le32_to_cpu(stat_info->tmac_icmp); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->tmac_rst_tcp_oflow) << 32 | + le32_to_cpu(stat_info->tmac_rst_tcp); tmp_stats[i++] = le64_to_cpu(stat_info->tmac_tcp); - tmp_stats[i++] = le32_to_cpu(stat_info->tmac_udp); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_vld_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_data_octets); + tmp_stats[i++] = (u64)le32_to_cpu(stat_info->tmac_udp_oflow) << 32 | + le32_to_cpu(stat_info->tmac_udp); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_vld_frms_oflow) << 32 | + le32_to_cpu(stat_info->rmac_vld_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_data_octets_oflow) << 32 | + le32_to_cpu(stat_info->rmac_data_octets); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_fcs_err_frms); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_drop_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_vld_mcst_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_vld_bcst_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_vld_mcst_frms_oflow) << 32 | + le32_to_cpu(stat_info->rmac_vld_mcst_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_vld_bcst_frms_oflow) << 32 | + le32_to_cpu(stat_info->rmac_vld_bcst_frms); tmp_stats[i++] = le32_to_cpu(stat_info->rmac_in_rng_len_err_frms); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_long_frms); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_pause_ctrl_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_discarded_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_usized_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_osized_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_frag_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_jabber_frms); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_ip); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_discarded_frms_oflow) << 32 | + le32_to_cpu(stat_info->rmac_discarded_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_usized_frms_oflow) << 32 | + le32_to_cpu(stat_info->rmac_usized_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_osized_frms_oflow) << 32 | + le32_to_cpu(stat_info->rmac_osized_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_frag_frms_oflow) << 32 | + le32_to_cpu(stat_info->rmac_frag_frms); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_jabber_frms_oflow) << 32 | + le32_to_cpu(stat_info->rmac_jabber_frms); + tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_ip_oflow) << 32 | + le32_to_cpu(stat_info->rmac_ip); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_ip_octets); tmp_stats[i++] = le32_to_cpu(stat_info->rmac_hdr_err_ip); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_drop_ip); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_icmp); + tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_drop_ip_oflow) << 32 | + le32_to_cpu(stat_info->rmac_drop_ip); + tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_icmp_oflow) << 32 | + le32_to_cpu(stat_info->rmac_icmp); tmp_stats[i++] = le64_to_cpu(stat_info->rmac_tcp); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_udp); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_drp_udp); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_pause_cnt); - tmp_stats[i++] = le32_to_cpu(stat_info->rmac_accepted_ip); + tmp_stats[i++] = (u64)le32_to_cpu(stat_info->rmac_udp_oflow) << 32 | + le32_to_cpu(stat_info->rmac_udp); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_err_drp_udp_oflow) << 32 | + le32_to_cpu(stat_info->rmac_err_drp_udp); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_pause_cnt_oflow) << 32 | + le32_to_cpu(stat_info->rmac_pause_cnt); + tmp_stats[i++] = + (u64)le32_to_cpu(stat_info->rmac_accepted_ip_oflow) << 32 | + le32_to_cpu(stat_info->rmac_accepted_ip); tmp_stats[i++] = le32_to_cpu(stat_info->rmac_err_tcp); + tmp_stats[i++] = 0; + tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs; + tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs; } -static int s2io_ethtool_get_regs_len(struct net_device *dev) +int s2io_ethtool_get_regs_len(struct net_device *dev) { return (XENA_REG_SPACE); } -static u32 s2io_ethtool_get_rx_csum(struct net_device * dev) +u32 s2io_ethtool_get_rx_csum(struct net_device * dev) { nic_t *sp = dev->priv; return (sp->rx_csum); } - -static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data) +int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data) { nic_t *sp = dev->priv; @@ -3975,19 +4578,17 @@ static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data) return 0; } - -static int s2io_get_eeprom_len(struct net_device *dev) +int s2io_get_eeprom_len(struct net_device *dev) { return (XENA_EEPROM_SPACE); } -static int s2io_ethtool_self_test_count(struct net_device *dev) +int s2io_ethtool_self_test_count(struct net_device *dev) { return (S2IO_TEST_LEN); } - -static void s2io_ethtool_get_strings(struct net_device *dev, - u32 stringset, u8 * data) +void s2io_ethtool_get_strings(struct net_device *dev, + u32 stringset, u8 * data) { switch (stringset) { case ETH_SS_TEST: @@ -3998,13 +4599,12 @@ static void s2io_ethtool_get_strings(struct net_device *dev, sizeof(ethtool_stats_keys)); } } - static int s2io_ethtool_get_stats_count(struct net_device *dev) { return (S2IO_STAT_LEN); } -static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data) +int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data) { if (data) dev->features |= NETIF_F_IP_CSUM; @@ -4046,21 +4646,18 @@ static struct ethtool_ops netdev_ethtool_ops = { }; /** - * s2io_ioctl - Entry point for the Ioctl + * s2io_ioctl - Entry point for the Ioctl * @dev : Device pointer. * @ifr : An IOCTL specefic structure, that can contain a pointer to * a proprietary structure used to pass information to the driver. * @cmd : This is used to distinguish between the different commands that * can be passed to the IOCTL functions. * Description: - * This function has support for ethtool, adding multiple MAC addresses on - * the NIC and some DBG commands for the util tool. - * Return value: - * Currently the IOCTL supports no operations, hence by default this - * function returns OP NOT SUPPORTED value. + * Currently there are no special functionality supported in IOCTL, hence + * function always return EOPNOTSUPPORTED */ -static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { return -EOPNOTSUPP; } @@ -4076,17 +4673,9 @@ static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) * file on failure. */ -static int s2io_change_mtu(struct net_device *dev, int new_mtu) +int s2io_change_mtu(struct net_device *dev, int new_mtu) { nic_t *sp = dev->priv; - XENA_dev_config_t __iomem *bar0 = sp->bar0; - register u64 val64; - - if (netif_running(dev)) { - DBG_PRINT(ERR_DBG, "%s: Must be stopped to ", dev->name); - DBG_PRINT(ERR_DBG, "change its MTU \n"); - return -EBUSY; - } if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) { DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n", @@ -4094,11 +4683,22 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu) return -EPERM; } - /* Set the new MTU into the PYLD register of the NIC */ - val64 = new_mtu; - writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len); - dev->mtu = new_mtu; + if (netif_running(dev)) { + s2io_card_down(sp); + netif_stop_queue(dev); + if (s2io_card_up(sp)) { + DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n", + __FUNCTION__); + } + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); + } else { /* Device is down */ + XENA_dev_config_t __iomem *bar0 = sp->bar0; + u64 val64 = new_mtu; + + writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len); + } return 0; } @@ -4108,9 +4708,9 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu) * @dev_adr : address of the device structure in dma_addr_t format. * Description: * This is the tasklet or the bottom half of the ISR. This is - * an extension of the ISR which is scheduled by the scheduler to be run + * an extension of the ISR which is scheduled by the scheduler to be run * when the load on the CPU is low. All low priority tasks of the ISR can - * be pushed into the tasklet. For now the tasklet is used only to + * be pushed into the tasklet. For now the tasklet is used only to * replenish the Rx buffers in the Rx buffer descriptors. * Return value: * void. @@ -4166,19 +4766,22 @@ static void s2io_set_link(unsigned long data) } subid = nic->pdev->subsystem_device; - /* - * Allow a small delay for the NICs self initiated - * cleanup to complete. - */ - msleep(100); + if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) { + /* + * Allow a small delay for the NICs self initiated + * cleanup to complete. + */ + msleep(100); + } val64 = readq(&bar0->adapter_status); - if (verify_xena_quiescence(val64, nic->device_enabled_once)) { + if (verify_xena_quiescence(nic, val64, nic->device_enabled_once)) { if (LINK_IS_UP(val64)) { val64 = readq(&bar0->adapter_control); val64 |= ADAPTER_CNTL_EN; writeq(val64, &bar0->adapter_control); - if (CARDS_WITH_FAULTY_LINK_INDICATORS(subid)) { + if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type, + subid)) { val64 = readq(&bar0->gpio_control); val64 |= GPIO_CTRL_GPIO_0; writeq(val64, &bar0->gpio_control); @@ -4187,20 +4790,24 @@ static void s2io_set_link(unsigned long data) val64 |= ADAPTER_LED_ON; writeq(val64, &bar0->adapter_control); } - val64 = readq(&bar0->adapter_status); - if (!LINK_IS_UP(val64)) { - DBG_PRINT(ERR_DBG, "%s:", dev->name); - DBG_PRINT(ERR_DBG, " Link down"); - DBG_PRINT(ERR_DBG, "after "); - DBG_PRINT(ERR_DBG, "enabling "); - DBG_PRINT(ERR_DBG, "device \n"); + if (s2io_link_fault_indication(nic) == + MAC_RMAC_ERR_TIMER) { + val64 = readq(&bar0->adapter_status); + if (!LINK_IS_UP(val64)) { + DBG_PRINT(ERR_DBG, "%s:", dev->name); + DBG_PRINT(ERR_DBG, " Link down"); + DBG_PRINT(ERR_DBG, "after "); + DBG_PRINT(ERR_DBG, "enabling "); + DBG_PRINT(ERR_DBG, "device \n"); + } } if (nic->device_enabled_once == FALSE) { nic->device_enabled_once = TRUE; } s2io_link(nic, LINK_UP); } else { - if (CARDS_WITH_FAULTY_LINK_INDICATORS(subid)) { + if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type, + subid)) { val64 = readq(&bar0->gpio_control); val64 &= ~GPIO_CTRL_GPIO_0; writeq(val64, &bar0->gpio_control); @@ -4223,9 +4830,11 @@ static void s2io_card_down(nic_t * sp) unsigned long flags; register u64 val64 = 0; + del_timer_sync(&sp->alarm_timer); /* If s2io_set_link task is executing, wait till it completes. */ - while (test_and_set_bit(0, &(sp->link_state))) + while (test_and_set_bit(0, &(sp->link_state))) { msleep(50); + } atomic_set(&sp->card_state, CARD_DOWN); /* disable Tx and Rx traffic on the NIC */ @@ -4237,7 +4846,7 @@ static void s2io_card_down(nic_t * sp) /* Check if the device is Quiescent and then Reset the NIC */ do { val64 = readq(&bar0->adapter_status); - if (verify_xena_quiescence(val64, sp->device_enabled_once)) { + if (verify_xena_quiescence(sp, val64, sp->device_enabled_once)) { break; } @@ -4251,14 +4860,27 @@ static void s2io_card_down(nic_t * sp) break; } } while (1); - spin_lock_irqsave(&sp->tx_lock, flags); s2io_reset(sp); - /* Free all unused Tx and Rx buffers */ + /* Waiting till all Interrupt handlers are complete */ + cnt = 0; + do { + msleep(10); + if (!atomic_read(&sp->isr_cnt)) + break; + cnt++; + } while(cnt < 5); + + spin_lock_irqsave(&sp->tx_lock, flags); + /* Free all Tx buffers */ free_tx_buffers(sp); + spin_unlock_irqrestore(&sp->tx_lock, flags); + + /* Free all Rx buffers */ + spin_lock_irqsave(&sp->rx_lock, flags); free_rx_buffers(sp); + spin_unlock_irqrestore(&sp->rx_lock, flags); - spin_unlock_irqrestore(&sp->tx_lock, flags); clear_bit(0, &(sp->link_state)); } @@ -4276,8 +4898,8 @@ static int s2io_card_up(nic_t * sp) return -ENODEV; } - /* - * Initializing the Rx buffers. For now we are considering only 1 + /* + * Initializing the Rx buffers. For now we are considering only 1 * Rx ring and initializing buffers into 30 Rx blocks */ mac_control = &sp->mac_control; @@ -4311,16 +4933,18 @@ static int s2io_card_up(nic_t * sp) return -ENODEV; } + S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2)); + atomic_set(&sp->card_state, CARD_UP); return 0; } -/** +/** * s2io_restart_nic - Resets the NIC. * @data : long pointer to the device private structure * Description: * This function is scheduled to be run by the s2io_tx_watchdog - * function after 0.5 secs to reset the NIC. The idea is to reduce + * function after 0.5 secs to reset the NIC. The idea is to reduce * the run time of the watch dog routine which is run holding a * spin lock. */ @@ -4338,10 +4962,11 @@ static void s2io_restart_nic(unsigned long data) netif_wake_queue(dev); DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n", dev->name); + } -/** - * s2io_tx_watchdog - Watchdog for transmit side. +/** + * s2io_tx_watchdog - Watchdog for transmit side. * @dev : Pointer to net device structure * Description: * This function is triggered if the Tx Queue is stopped @@ -4369,7 +4994,7 @@ static void s2io_tx_watchdog(struct net_device *dev) * @len : length of the packet * @cksum : FCS checksum of the frame. * @ring_no : the ring from which this RxD was extracted. - * Description: + * Description: * This function is called by the Tx interrupt serivce routine to perform * some OS related operations on the SKB before passing it to the upper * layers. It mainly checks if the checksum is OK, if so adds it to the @@ -4379,35 +5004,68 @@ static void s2io_tx_watchdog(struct net_device *dev) * Return value: * SUCCESS on success and -1 on failure. */ -#ifndef CONFIG_2BUFF_MODE -static int rx_osm_handler(nic_t * sp, u16 len, RxD_t * rxdp, int ring_no) -#else -static int rx_osm_handler(nic_t * sp, RxD_t * rxdp, int ring_no, - buffAdd_t * ba) -#endif +static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp) { + nic_t *sp = ring_data->nic; struct net_device *dev = (struct net_device *) sp->dev; - struct sk_buff *skb = - (struct sk_buff *) ((unsigned long) rxdp->Host_Control); + struct sk_buff *skb = (struct sk_buff *) + ((unsigned long) rxdp->Host_Control); + int ring_no = ring_data->ring_no; u16 l3_csum, l4_csum; #ifdef CONFIG_2BUFF_MODE - int buf0_len, buf2_len; + int buf0_len = RXD_GET_BUFFER0_SIZE(rxdp->Control_2); + int buf2_len = RXD_GET_BUFFER2_SIZE(rxdp->Control_2); + int get_block = ring_data->rx_curr_get_info.block_index; + int get_off = ring_data->rx_curr_get_info.offset; + buffAdd_t *ba = &ring_data->ba[get_block][get_off]; unsigned char *buff; +#else + u16 len = (u16) ((RXD_GET_BUFFER0_SIZE(rxdp->Control_2)) >> 48);; #endif + skb->dev = dev; + if (rxdp->Control_1 & RXD_T_CODE) { + unsigned long long err = rxdp->Control_1 & RXD_T_CODE; + DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%llx\n", + dev->name, err); + dev_kfree_skb(skb); + sp->stats.rx_crc_errors++; + atomic_dec(&sp->rx_bufs_left[ring_no]); + rxdp->Host_Control = 0; + return 0; + } - l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1); - if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && (sp->rx_csum)) { + /* Updating statistics */ + rxdp->Host_Control = 0; + sp->rx_pkt_count++; + sp->stats.rx_packets++; +#ifndef CONFIG_2BUFF_MODE + sp->stats.rx_bytes += len; +#else + sp->stats.rx_bytes += buf0_len + buf2_len; +#endif + +#ifndef CONFIG_2BUFF_MODE + skb_put(skb, len); +#else + buff = skb_push(skb, buf0_len); + memcpy(buff, ba->ba_0, buf0_len); + skb_put(skb, buf2_len); +#endif + + if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && + (sp->rx_csum)) { + l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1); l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1); if ((l3_csum == L3_CKSUM_OK) && (l4_csum == L4_CKSUM_OK)) { - /* + /* * NIC verifies if the Checksum of the received * frame is Ok or not and accordingly returns * a flag in the RxD. */ skb->ip_summed = CHECKSUM_UNNECESSARY; } else { - /* - * Packet with erroneous checksum, let the + /* + * Packet with erroneous checksum, let the * upper layers deal with it. */ skb->ip_summed = CHECKSUM_NONE; @@ -4416,44 +5074,26 @@ static int rx_osm_handler(nic_t * sp, RxD_t * rxdp, int ring_no, skb->ip_summed = CHECKSUM_NONE; } - if (rxdp->Control_1 & RXD_T_CODE) { - unsigned long long err = rxdp->Control_1 & RXD_T_CODE; - DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%llx\n", - dev->name, err); - } -#ifdef CONFIG_2BUFF_MODE - buf0_len = RXD_GET_BUFFER0_SIZE(rxdp->Control_2); - buf2_len = RXD_GET_BUFFER2_SIZE(rxdp->Control_2); -#endif - - skb->dev = dev; -#ifndef CONFIG_2BUFF_MODE - skb_put(skb, len); - skb->protocol = eth_type_trans(skb, dev); -#else - buff = skb_push(skb, buf0_len); - memcpy(buff, ba->ba_0, buf0_len); - skb_put(skb, buf2_len); skb->protocol = eth_type_trans(skb, dev); -#endif - #ifdef CONFIG_S2IO_NAPI - netif_receive_skb(skb); + if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) { + /* Queueing the vlan frame to the upper layer */ + vlan_hwaccel_receive_skb(skb, sp->vlgrp, + RXD_GET_VLAN_TAG(rxdp->Control_2)); + } else { + netif_receive_skb(skb); + } #else - netif_rx(skb); + if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) { + /* Queueing the vlan frame to the upper layer */ + vlan_hwaccel_rx(skb, sp->vlgrp, + RXD_GET_VLAN_TAG(rxdp->Control_2)); + } else { + netif_rx(skb); + } #endif - dev->last_rx = jiffies; - sp->rx_pkt_count++; - sp->stats.rx_packets++; -#ifndef CONFIG_2BUFF_MODE - sp->stats.rx_bytes += len; -#else - sp->stats.rx_bytes += buf0_len + buf2_len; -#endif - atomic_dec(&sp->rx_bufs_left[ring_no]); - rxdp->Host_Control = 0; return SUCCESS; } @@ -4464,13 +5104,13 @@ static int rx_osm_handler(nic_t * sp, RxD_t * rxdp, int ring_no, * @link : inidicates whether link is UP/DOWN. * Description: * This function stops/starts the Tx queue depending on whether the link - * status of the NIC is is down or up. This is called by the Alarm - * interrupt handler whenever a link change interrupt comes up. + * status of the NIC is is down or up. This is called by the Alarm + * interrupt handler whenever a link change interrupt comes up. * Return value: * void. */ -static void s2io_link(nic_t * sp, int link) +void s2io_link(nic_t * sp, int link) { struct net_device *dev = (struct net_device *) sp->dev; @@ -4487,8 +5127,25 @@ static void s2io_link(nic_t * sp, int link) } /** - * s2io_init_pci -Initialization of PCI and PCI-X configuration registers . - * @sp : private member of the device structure, which is a pointer to the + * get_xena_rev_id - to identify revision ID of xena. + * @pdev : PCI Dev structure + * Description: + * Function to identify the Revision ID of xena. + * Return value: + * returns the revision ID of the device. + */ + +int get_xena_rev_id(struct pci_dev *pdev) +{ + u8 id = 0; + int ret; + ret = pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) & id); + return id; +} + +/** + * s2io_init_pci -Initialization of PCI and PCI-X configuration registers . + * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * Description: * This function initializes a few of the PCI and PCI-X configuration registers @@ -4499,15 +5156,15 @@ static void s2io_link(nic_t * sp, int link) static void s2io_init_pci(nic_t * sp) { - u16 pci_cmd = 0; + u16 pci_cmd = 0, pcix_cmd = 0; /* Enable Data Parity Error Recovery in PCI-X command register. */ pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, - &(sp->pcix_cmd)); + &(pcix_cmd)); pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, - (sp->pcix_cmd | 1)); + (pcix_cmd | 1)); pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, - &(sp->pcix_cmd)); + &(pcix_cmd)); /* Set the PErr Response bit in PCI command register. */ pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd); @@ -4515,53 +5172,43 @@ static void s2io_init_pci(nic_t * sp) (pci_cmd | PCI_COMMAND_PARITY)); pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd); - /* Set MMRB count to 1024 in PCI-X Command register. */ - sp->pcix_cmd &= 0xFFF3; - pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, (sp->pcix_cmd | (0x1 << 2))); /* MMRBC 1K */ - pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, - &(sp->pcix_cmd)); - - /* Setting Maximum outstanding splits based on system type. */ - sp->pcix_cmd &= 0xFF8F; - - sp->pcix_cmd |= XENA_MAX_OUTSTANDING_SPLITS(0x1); /* 2 splits. */ - pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, - sp->pcix_cmd); - pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, - &(sp->pcix_cmd)); /* Forcibly disabling relaxed ordering capability of the card. */ - sp->pcix_cmd &= 0xfffd; + pcix_cmd &= 0xfffd; pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, - sp->pcix_cmd); + pcix_cmd); pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, - &(sp->pcix_cmd)); + &(pcix_cmd)); } MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>"); MODULE_LICENSE("GPL"); module_param(tx_fifo_num, int, 0); -module_param_array(tx_fifo_len, int, NULL, 0); module_param(rx_ring_num, int, 0); -module_param_array(rx_ring_sz, int, NULL, 0); -module_param(Stats_refresh_time, int, 0); +module_param_array(tx_fifo_len, uint, NULL, 0); +module_param_array(rx_ring_sz, uint, NULL, 0); +module_param_array(rts_frm_len, uint, NULL, 0); +module_param(use_continuous_tx_intrs, int, 1); module_param(rmac_pause_time, int, 0); module_param(mc_pause_threshold_q0q3, int, 0); module_param(mc_pause_threshold_q4q7, int, 0); module_param(shared_splits, int, 0); module_param(tmac_util_period, int, 0); module_param(rmac_util_period, int, 0); +module_param(bimodal, bool, 0); #ifndef CONFIG_S2IO_NAPI module_param(indicate_max_pkts, int, 0); #endif +module_param(rxsync_frequency, int, 0); + /** - * s2io_init_nic - Initialization of the adapter . + * s2io_init_nic - Initialization of the adapter . * @pdev : structure containing the PCI related information of the device. * @pre: List of PCI devices supported by the driver listed in s2io_tbl. * Description: * The function initializes an adapter identified by the pci_dec structure. - * All OS related initialization including memory and device structure and - * initlaization of the device private variable is done. Also the swapper - * control register is initialized to enable read and write into the I/O + * All OS related initialization including memory and device structure and + * initlaization of the device private variable is done. Also the swapper + * control register is initialized to enable read and write into the I/O * registers of the device. * Return value: * returns 0 on success and negative on failure. @@ -4572,7 +5219,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) { nic_t *sp; struct net_device *dev; - char *dev_name = "S2IO 10GE NIC"; int i, j, ret; int dma_flag = FALSE; u32 mac_up, mac_down; @@ -4581,10 +5227,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) u16 subid; mac_info_t *mac_control; struct config_param *config; + int mode; - - DBG_PRINT(ERR_DBG, "Loading S2IO driver with %s\n", - s2io_driver_version); +#ifdef CONFIG_S2IO_NAPI + DBG_PRINT(ERR_DBG, "NAPI support has been enabled\n"); +#endif if ((ret = pci_enable_device(pdev))) { DBG_PRINT(ERR_DBG, @@ -4595,7 +5242,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n"); dma_flag = TRUE; - if (pci_set_consistent_dma_mask (pdev, DMA_64BIT_MASK)) { DBG_PRINT(ERR_DBG, @@ -4635,34 +5281,41 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) memset(sp, 0, sizeof(nic_t)); sp->dev = dev; sp->pdev = pdev; - sp->vendor_id = pdev->vendor; - sp->device_id = pdev->device; sp->high_dma_flag = dma_flag; - sp->irq = pdev->irq; sp->device_enabled_once = FALSE; - strcpy(sp->name, dev_name); + + if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) || + (pdev->device == PCI_DEVICE_ID_HERC_UNI)) + sp->device_type = XFRAME_II_DEVICE; + else + sp->device_type = XFRAME_I_DEVICE; /* Initialize some PCI/PCI-X fields of the NIC. */ s2io_init_pci(sp); - /* + /* * Setting the device configuration parameters. - * Most of these parameters can be specified by the user during - * module insertion as they are module loadable parameters. If - * these parameters are not not specified during load time, they + * Most of these parameters can be specified by the user during + * module insertion as they are module loadable parameters. If + * these parameters are not not specified during load time, they * are initialized with default values. */ mac_control = &sp->mac_control; config = &sp->config; /* Tx side parameters. */ - tx_fifo_len[0] = DEFAULT_FIFO_LEN; /* Default value. */ + if (tx_fifo_len[0] == 0) + tx_fifo_len[0] = DEFAULT_FIFO_LEN; /* Default value. */ config->tx_fifo_num = tx_fifo_num; for (i = 0; i < MAX_TX_FIFOS; i++) { config->tx_cfg[i].fifo_len = tx_fifo_len[i]; config->tx_cfg[i].fifo_priority = i; } + /* mapping the QoS priority to the configured fifos */ + for (i = 0; i < MAX_TX_FIFOS; i++) + config->fifo_mapping[i] = fifo_map[config->tx_fifo_num][i]; + config->tx_intr_type = TXD_INT_TYPE_UTILZ; for (i = 0; i < config->tx_fifo_num; i++) { config->tx_cfg[i].f_no_snoop = @@ -4675,7 +5328,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) config->max_txds = MAX_SKB_FRAGS; /* Rx side parameters. */ - rx_ring_sz[0] = SMALL_BLK_CNT; /* Default value. */ + if (rx_ring_sz[0] == 0) + rx_ring_sz[0] = SMALL_BLK_CNT; /* Default value. */ config->rx_ring_num = rx_ring_num; for (i = 0; i < MAX_RX_RINGS; i++) { config->rx_cfg[i].num_rxd = rx_ring_sz[i] * @@ -4699,10 +5353,13 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) for (i = 0; i < config->rx_ring_num; i++) atomic_set(&sp->rx_bufs_left[i], 0); + /* Initialize the number of ISRs currently running */ + atomic_set(&sp->isr_cnt, 0); + /* initialize the shared memory used by the NIC and the host */ if (init_shared_mem(sp)) { DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", - dev->name); + __FUNCTION__); ret = -ENOMEM; goto mem_alloc_failed; } @@ -4743,13 +5400,17 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) dev->do_ioctl = &s2io_ioctl; dev->change_mtu = &s2io_change_mtu; SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); + dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + dev->vlan_rx_register = s2io_vlan_rx_register; + dev->vlan_rx_kill_vid = (void *)s2io_vlan_rx_kill_vid; + /* * will use eth_mac_addr() for dev->set_mac_address * mac address will be set every time dev->open() is called */ -#ifdef CONFIG_S2IO_NAPI +#if defined(CONFIG_S2IO_NAPI) dev->poll = s2io_poll; - dev->weight = 90; + dev->weight = 32; #endif dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; @@ -4776,22 +5437,28 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) goto set_swap_failed; } - /* Fix for all "FFs" MAC address problems observed on Alpha platforms */ - fix_mac_address(sp); - s2io_reset(sp); + /* Verify if the Herc works on the slot its placed into */ + if (sp->device_type & XFRAME_II_DEVICE) { + mode = s2io_verify_pci_mode(sp); + if (mode < 0) { + DBG_PRINT(ERR_DBG, "%s: ", __FUNCTION__); + DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode\n"); + ret = -EBADSLT; + goto set_swap_failed; + } + } - /* - * Setting swapper control on the NIC, so the MAC address can be read. - */ - if (s2io_set_swapper(sp)) { - DBG_PRINT(ERR_DBG, - "%s: S2IO: swapper settings are wrong\n", - dev->name); - ret = -EAGAIN; - goto set_swap_failed; + /* Not needed for Herc */ + if (sp->device_type & XFRAME_I_DEVICE) { + /* + * Fix for all "FFs" MAC address problems observed on + * Alpha platforms + */ + fix_mac_address(sp); + s2io_reset(sp); } - /* + /* * MAC address initialization. * For now only one mac address will be read and used. */ @@ -4814,37 +5481,28 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_down >> 16); sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_down >> 24); - DBG_PRINT(INIT_DBG, - "DEFAULT MAC ADDR:0x%02x-%02x-%02x-%02x-%02x-%02x\n", - sp->def_mac_addr[0].mac_addr[0], - sp->def_mac_addr[0].mac_addr[1], - sp->def_mac_addr[0].mac_addr[2], - sp->def_mac_addr[0].mac_addr[3], - sp->def_mac_addr[0].mac_addr[4], - sp->def_mac_addr[0].mac_addr[5]); - /* Set the factory defined MAC address initially */ dev->addr_len = ETH_ALEN; memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN); /* - * Initialize the tasklet status and link state flags - * and the card statte parameter + * Initialize the tasklet status and link state flags + * and the card state parameter */ atomic_set(&(sp->card_state), 0); sp->tasklet_status = 0; sp->link_state = 0; - /* Initialize spinlocks */ spin_lock_init(&sp->tx_lock); #ifndef CONFIG_S2IO_NAPI spin_lock_init(&sp->put_lock); #endif + spin_lock_init(&sp->rx_lock); - /* - * SXE-002: Configure link and activity LED to init state - * on driver load. + /* + * SXE-002: Configure link and activity LED to init state + * on driver load. */ subid = sp->pdev->subsystem_device; if ((subid & 0xFF) >= 0x07) { @@ -4864,13 +5522,61 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) goto register_failed; } - /* - * Make Link state as off at this point, when the Link change - * interrupt comes the state will be automatically changed to + if (sp->device_type & XFRAME_II_DEVICE) { + DBG_PRINT(ERR_DBG, "%s: Neterion Xframe II 10GbE adapter ", + dev->name); + DBG_PRINT(ERR_DBG, "(rev %d), Driver %s\n", + get_xena_rev_id(sp->pdev), + s2io_driver_version); + DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n", + sp->def_mac_addr[0].mac_addr[0], + sp->def_mac_addr[0].mac_addr[1], + sp->def_mac_addr[0].mac_addr[2], + sp->def_mac_addr[0].mac_addr[3], + sp->def_mac_addr[0].mac_addr[4], + sp->def_mac_addr[0].mac_addr[5]); + mode = s2io_print_pci_mode(sp); + if (mode < 0) { + DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode "); + ret = -EBADSLT; + goto set_swap_failed; + } + } else { + DBG_PRINT(ERR_DBG, "%s: Neterion Xframe I 10GbE adapter ", + dev->name); + DBG_PRINT(ERR_DBG, "(rev %d), Driver %s\n", + get_xena_rev_id(sp->pdev), + s2io_driver_version); + DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n", + sp->def_mac_addr[0].mac_addr[0], + sp->def_mac_addr[0].mac_addr[1], + sp->def_mac_addr[0].mac_addr[2], + sp->def_mac_addr[0].mac_addr[3], + sp->def_mac_addr[0].mac_addr[4], + sp->def_mac_addr[0].mac_addr[5]); + } + + /* Initialize device name */ + strcpy(sp->name, dev->name); + if (sp->device_type & XFRAME_II_DEVICE) + strcat(sp->name, ": Neterion Xframe II 10GbE adapter"); + else + strcat(sp->name, ": Neterion Xframe I 10GbE adapter"); + + /* Initialize bimodal Interrupts */ + sp->config.bimodal = bimodal; + if (!(sp->device_type & XFRAME_II_DEVICE) && bimodal) { + sp->config.bimodal = 0; + DBG_PRINT(ERR_DBG,"%s:Bimodal intr not supported by Xframe I\n", + dev->name); + } + + /* + * Make Link state as off at this point, when the Link change + * interrupt comes the state will be automatically changed to * the right state. */ netif_carrier_off(dev); - sp->last_link_state = LINK_DOWN; return 0; @@ -4891,11 +5597,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) } /** - * s2io_rem_nic - Free the PCI device + * s2io_rem_nic - Free the PCI device * @pdev: structure containing the PCI related information of the device. - * Description: This function is called by the Pci subsystem to release a + * Description: This function is called by the Pci subsystem to release a * PCI device and free up all resource held up by the device. This could - * be in response to a Hot plug event or when the driver is to be removed + * be in response to a Hot plug event or when the driver is to be removed * from memory. */ @@ -4919,7 +5625,6 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev) pci_disable_device(pdev); pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); - free_netdev(dev); } @@ -4935,11 +5640,11 @@ int __init s2io_starter(void) } /** - * s2io_closer - Cleanup routine for the driver + * s2io_closer - Cleanup routine for the driver * Description: This function is the cleanup routine for the driver. It unregist * ers the driver. */ -static void s2io_closer(void) +void s2io_closer(void) { pci_unregister_driver(&s2io_driver); DBG_PRINT(INIT_DBG, "cleanup done\n"); diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 1711c8c3dc9..5d9270730ca 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -31,6 +31,9 @@ #define SUCCESS 0 #define FAILURE -1 +/* Maximum time to flicker LED when asked to identify NIC using ethtool */ +#define MAX_FLICKER_TIME 60000 /* 60 Secs */ + /* Maximum outstanding splits to be configured into xena. */ typedef enum xena_max_outstanding_splits { XENA_ONE_SPLIT_TRANSACTION = 0, @@ -45,10 +48,10 @@ typedef enum xena_max_outstanding_splits { #define XENA_MAX_OUTSTANDING_SPLITS(n) (n << 4) /* OS concerned variables and constants */ -#define WATCH_DOG_TIMEOUT 5*HZ -#define EFILL 0x1234 -#define ALIGN_SIZE 127 -#define PCIX_COMMAND_REGISTER 0x62 +#define WATCH_DOG_TIMEOUT 15*HZ +#define EFILL 0x1234 +#define ALIGN_SIZE 127 +#define PCIX_COMMAND_REGISTER 0x62 /* * Debug related variables. @@ -61,7 +64,7 @@ typedef enum xena_max_outstanding_splits { #define INTR_DBG 4 /* Global variable that defines the present debug level of the driver. */ -static int debug_level = ERR_DBG; /* Default level. */ +int debug_level = ERR_DBG; /* Default level. */ /* DEBUG message print. */ #define DBG_PRINT(dbg_level, args...) if(!(debug_level<dbg_level)) printk(args) @@ -71,6 +74,12 @@ static int debug_level = ERR_DBG; /* Default level. */ #define L4_CKSUM_OK 0xFFFF #define S2IO_JUMBO_SIZE 9600 +/* Driver statistics maintained by driver */ +typedef struct { + unsigned long long single_ecc_errs; + unsigned long long double_ecc_errs; +} swStat_t; + /* The statistics block of Xena */ typedef struct stat_block { /* Tx MAC statistics counters. */ @@ -186,12 +195,90 @@ typedef struct stat_block { u32 rxd_rd_cnt; u32 rxf_wr_cnt; u32 txf_rd_cnt; + +/* Tx MAC statistics overflow counters. */ + u32 tmac_data_octets_oflow; + u32 tmac_frms_oflow; + u32 tmac_bcst_frms_oflow; + u32 tmac_mcst_frms_oflow; + u32 tmac_ucst_frms_oflow; + u32 tmac_ttl_octets_oflow; + u32 tmac_any_err_frms_oflow; + u32 tmac_nucst_frms_oflow; + u64 tmac_vlan_frms; + u32 tmac_drop_ip_oflow; + u32 tmac_vld_ip_oflow; + u32 tmac_rst_tcp_oflow; + u32 tmac_icmp_oflow; + u32 tpa_unknown_protocol; + u32 tmac_udp_oflow; + u32 reserved_10; + u32 tpa_parse_failure; + +/* Rx MAC Statistics overflow counters. */ + u32 rmac_data_octets_oflow; + u32 rmac_vld_frms_oflow; + u32 rmac_vld_bcst_frms_oflow; + u32 rmac_vld_mcst_frms_oflow; + u32 rmac_accepted_ucst_frms_oflow; + u32 rmac_ttl_octets_oflow; + u32 rmac_discarded_frms_oflow; + u32 rmac_accepted_nucst_frms_oflow; + u32 rmac_usized_frms_oflow; + u32 rmac_drop_events_oflow; + u32 rmac_frag_frms_oflow; + u32 rmac_osized_frms_oflow; + u32 rmac_ip_oflow; + u32 rmac_jabber_frms_oflow; + u32 rmac_icmp_oflow; + u32 rmac_drop_ip_oflow; + u32 rmac_err_drp_udp_oflow; + u32 rmac_udp_oflow; + u32 reserved_11; + u32 rmac_pause_cnt_oflow; + u64 rmac_ttl_1519_4095_frms; + u64 rmac_ttl_4096_8191_frms; + u64 rmac_ttl_8192_max_frms; + u64 rmac_ttl_gt_max_frms; + u64 rmac_osized_alt_frms; + u64 rmac_jabber_alt_frms; + u64 rmac_gt_max_alt_frms; + u64 rmac_vlan_frms; + u32 rmac_len_discard; + u32 rmac_fcs_discard; + u32 rmac_pf_discard; + u32 rmac_da_discard; + u32 rmac_red_discard; + u32 rmac_rts_discard; + u32 reserved_12; + u32 rmac_ingm_full_discard; + u32 reserved_13; + u32 rmac_accepted_ip_oflow; + u32 reserved_14; + u32 link_fault_cnt; + swStat_t sw_stat; } StatInfo_t; -/* Structures representing different init time configuration +/* + * Structures representing different init time configuration * parameters of the NIC. */ +#define MAX_TX_FIFOS 8 +#define MAX_RX_RINGS 8 + +/* FIFO mappings for all possible number of fifos configured */ +int fifo_map[][MAX_TX_FIFOS] = { + {0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 1, 1, 1, 1}, + {0, 0, 0, 1, 1, 1, 2, 2}, + {0, 0, 1, 1, 2, 2, 3, 3}, + {0, 0, 1, 1, 2, 2, 3, 4}, + {0, 0, 1, 1, 2, 3, 4, 5}, + {0, 0, 1, 2, 3, 4, 5, 6}, + {0, 1, 2, 3, 4, 5, 6, 7}, +}; + /* Maintains Per FIFO related information. */ typedef struct tx_fifo_config { #define MAX_AVAILABLE_TXDS 8192 @@ -237,14 +324,14 @@ typedef struct rx_ring_config { #define NO_SNOOP_RXD_BUFFER 0x02 } rx_ring_config_t; -/* This structure provides contains values of the tunable parameters - * of the H/W +/* This structure provides contains values of the tunable parameters + * of the H/W */ struct config_param { /* Tx Side */ u32 tx_fifo_num; /*Number of Tx FIFOs */ -#define MAX_TX_FIFOS 8 + u8 fifo_mapping[MAX_TX_FIFOS]; tx_fifo_config_t tx_cfg[MAX_TX_FIFOS]; /*Per-Tx FIFO config */ u32 max_txds; /*Max no. of Tx buffer descriptor per TxDL */ u64 tx_intr_type; @@ -252,10 +339,10 @@ struct config_param { /* Rx Side */ u32 rx_ring_num; /*Number of receive rings */ -#define MAX_RX_RINGS 8 #define MAX_RX_BLOCKS_PER_RING 150 rx_ring_config_t rx_cfg[MAX_RX_RINGS]; /*Per-Rx Ring config */ + u8 bimodal; /*Flag for setting bimodal interrupts*/ #define HEADER_ETHERNET_II_802_3_SIZE 14 #define HEADER_802_2_SIZE 3 @@ -269,6 +356,7 @@ struct config_param { #define MAX_PYLD_JUMBO 9600 #define MAX_MTU_JUMBO (MAX_PYLD_JUMBO+18) #define MAX_MTU_JUMBO_VLAN (MAX_PYLD_JUMBO+22) + u16 bus_speed; }; /* Structure representing MAC Addrs */ @@ -277,7 +365,7 @@ typedef struct mac_addr { } macaddr_t; /* Structure that represent every FIFO element in the BAR1 - * Address location. + * Address location. */ typedef struct _TxFIFO_element { u64 TxDL_Pointer; @@ -339,6 +427,7 @@ typedef struct _RxD_t { #define RXD_FRAME_PROTO vBIT(0xFFFF,24,8) #define RXD_FRAME_PROTO_IPV4 BIT(27) #define RXD_FRAME_PROTO_IPV6 BIT(28) +#define RXD_FRAME_IP_FRAG BIT(29) #define RXD_FRAME_PROTO_TCP BIT(30) #define RXD_FRAME_PROTO_UDP BIT(31) #define TCP_OR_UDP_FRAME (RXD_FRAME_PROTO_TCP | RXD_FRAME_PROTO_UDP) @@ -346,11 +435,15 @@ typedef struct _RxD_t { #define RXD_GET_L4_CKSUM(val) ((u16)(val) & 0xFFFF) u64 Control_2; +#define THE_RXD_MARK 0x3 +#define SET_RXD_MARKER vBIT(THE_RXD_MARK, 0, 2) +#define GET_RXD_MARKER(ctrl) ((ctrl & SET_RXD_MARKER) >> 62) + #ifndef CONFIG_2BUFF_MODE -#define MASK_BUFFER0_SIZE vBIT(0xFFFF,0,16) -#define SET_BUFFER0_SIZE(val) vBIT(val,0,16) +#define MASK_BUFFER0_SIZE vBIT(0x3FFF,2,14) +#define SET_BUFFER0_SIZE(val) vBIT(val,2,14) #else -#define MASK_BUFFER0_SIZE vBIT(0xFF,0,16) +#define MASK_BUFFER0_SIZE vBIT(0xFF,2,14) #define MASK_BUFFER1_SIZE vBIT(0xFFFF,16,16) #define MASK_BUFFER2_SIZE vBIT(0xFFFF,32,16) #define SET_BUFFER0_SIZE(val) vBIT(val,8,8) @@ -363,7 +456,7 @@ typedef struct _RxD_t { #define SET_NUM_TAG(val) vBIT(val,16,32) #ifndef CONFIG_2BUFF_MODE -#define RXD_GET_BUFFER0_SIZE(Control_2) (u64)((Control_2 & vBIT(0xFFFF,0,16))) +#define RXD_GET_BUFFER0_SIZE(Control_2) (u64)((Control_2 & vBIT(0x3FFF,2,14))) #else #define RXD_GET_BUFFER0_SIZE(Control_2) (u8)((Control_2 & MASK_BUFFER0_SIZE) \ >> 48) @@ -382,7 +475,7 @@ typedef struct _RxD_t { #endif } RxD_t; -/* Structure that represents the Rx descriptor block which contains +/* Structure that represents the Rx descriptor block which contains * 128 Rx descriptors. */ #ifndef CONFIG_2BUFF_MODE @@ -392,11 +485,11 @@ typedef struct _RxD_block { u64 reserved_0; #define END_OF_BLOCK 0xFEFFFFFFFFFFFFFFULL - u64 reserved_1; /* 0xFEFFFFFFFFFFFFFF to mark last + u64 reserved_1; /* 0xFEFFFFFFFFFFFFFF to mark last * Rxd in this blk */ u64 reserved_2_pNext_RxD_block; /* Logical ptr to next */ u64 pNext_RxD_Blk_physical; /* Buff0_ptr.In a 32 bit arch - * the upper 32 bits should + * the upper 32 bits should * be 0 */ } RxD_block_t; #else @@ -405,13 +498,13 @@ typedef struct _RxD_block { RxD_t rxd[MAX_RXDS_PER_BLOCK]; #define END_OF_BLOCK 0xFEFFFFFFFFFFFFFFULL - u64 reserved_1; /* 0xFEFFFFFFFFFFFFFF to mark last Rxd + u64 reserved_1; /* 0xFEFFFFFFFFFFFFFF to mark last Rxd * in this blk */ u64 pNext_RxD_Blk_physical; /* Phy ponter to next blk. */ } RxD_block_t; #define SIZE_OF_BLOCK 4096 -/* Structure to hold virtual addresses of Buf0 and Buf1 in +/* Structure to hold virtual addresses of Buf0 and Buf1 in * 2buf mode. */ typedef struct bufAdd { void *ba_0_org; @@ -423,8 +516,8 @@ typedef struct bufAdd { /* Structure which stores all the MAC control parameters */ -/* This structure stores the offset of the RxD in the ring - * from which the Rx Interrupt processor can start picking +/* This structure stores the offset of the RxD in the ring + * from which the Rx Interrupt processor can start picking * up the RxDs for processing. */ typedef struct _rx_curr_get_info_t { @@ -436,7 +529,7 @@ typedef struct _rx_curr_get_info_t { typedef rx_curr_get_info_t rx_curr_put_info_t; /* This structure stores the offset of the TxDl in the FIFO - * from which the Tx Interrupt processor can start picking + * from which the Tx Interrupt processor can start picking * up the TxDLs for send complete interrupt processing. */ typedef struct { @@ -446,32 +539,96 @@ typedef struct { typedef tx_curr_get_info_t tx_curr_put_info_t; -/* Infomation related to the Tx and Rx FIFOs and Rings of Xena - * is maintained in this structure. - */ -typedef struct mac_info { -/* rx side stuff */ - /* Put pointer info which indictes which RxD has to be replenished +/* Structure that holds the Phy and virt addresses of the Blocks */ +typedef struct rx_block_info { + RxD_t *block_virt_addr; + dma_addr_t block_dma_addr; +} rx_block_info_t; + +/* pre declaration of the nic structure */ +typedef struct s2io_nic nic_t; + +/* Ring specific structure */ +typedef struct ring_info { + /* The ring number */ + int ring_no; + + /* + * Place holders for the virtual and physical addresses of + * all the Rx Blocks + */ + rx_block_info_t rx_blocks[MAX_RX_BLOCKS_PER_RING]; + int block_count; + int pkt_cnt; + + /* + * Put pointer info which indictes which RxD has to be replenished * with a new buffer. */ - rx_curr_put_info_t rx_curr_put_info[MAX_RX_RINGS]; + rx_curr_put_info_t rx_curr_put_info; - /* Get pointer info which indictes which is the last RxD that was + /* + * Get pointer info which indictes which is the last RxD that was * processed by the driver. */ - rx_curr_get_info_t rx_curr_get_info[MAX_RX_RINGS]; + rx_curr_get_info_t rx_curr_get_info; - u16 rmac_pause_time; - u16 mc_pause_threshold_q0q3; - u16 mc_pause_threshold_q4q7; +#ifndef CONFIG_S2IO_NAPI + /* Index to the absolute position of the put pointer of Rx ring */ + int put_pos; +#endif + +#ifdef CONFIG_2BUFF_MODE + /* Buffer Address store. */ + buffAdd_t **ba; +#endif + nic_t *nic; +} ring_info_t; +/* Fifo specific structure */ +typedef struct fifo_info { + /* FIFO number */ + int fifo_no; + + /* Maximum TxDs per TxDL */ + int max_txds; + + /* Place holder of all the TX List's Phy and Virt addresses. */ + list_info_hold_t *list_info; + + /* + * Current offset within the tx FIFO where driver would write + * new Tx frame + */ + tx_curr_put_info_t tx_curr_put_info; + + /* + * Current offset within tx FIFO from where the driver would start freeing + * the buffers + */ + tx_curr_get_info_t tx_curr_get_info; + + nic_t *nic; +}fifo_info_t; + +/* Infomation related to the Tx and Rx FIFOs and Rings of Xena + * is maintained in this structure. + */ +typedef struct mac_info { /* tx side stuff */ /* logical pointer of start of each Tx FIFO */ TxFIFO_element_t __iomem *tx_FIFO_start[MAX_TX_FIFOS]; -/* Current offset within tx_FIFO_start, where driver would write new Tx frame*/ - tx_curr_put_info_t tx_curr_put_info[MAX_TX_FIFOS]; - tx_curr_get_info_t tx_curr_get_info[MAX_TX_FIFOS]; + /* Fifo specific structure */ + fifo_info_t fifos[MAX_TX_FIFOS]; + +/* rx side stuff */ + /* Ring specific structure */ + ring_info_t rings[MAX_RX_RINGS]; + + u16 rmac_pause_time; + u16 mc_pause_threshold_q0q3; + u16 mc_pause_threshold_q4q7; void *stats_mem; /* orignal pointer to allocated mem */ dma_addr_t stats_mem_phy; /* Physical address of the stat block */ @@ -485,12 +642,6 @@ typedef struct { int usage_cnt; } usr_addr_t; -/* Structure that holds the Phy and virt addresses of the Blocks */ -typedef struct rx_block_info { - RxD_t *block_virt_addr; - dma_addr_t block_dma_addr; -} rx_block_info_t; - /* Default Tunable parameters of the NIC. */ #define DEFAULT_FIFO_LEN 4096 #define SMALL_RXD_CNT 30 * (MAX_RXDS_PER_BLOCK+1) @@ -499,7 +650,20 @@ typedef struct rx_block_info { #define LARGE_BLK_CNT 100 /* Structure representing one instance of the NIC */ -typedef struct s2io_nic { +struct s2io_nic { +#ifdef CONFIG_S2IO_NAPI + /* + * Count of packets to be processed in a given iteration, it will be indicated + * by the quota field of the device structure when NAPI is enabled. + */ + int pkts_to_process; +#endif + struct net_device *dev; + mac_info_t mac_control; + struct config_param config; + struct pci_dev *pdev; + void __iomem *bar0; + void __iomem *bar1; #define MAX_MAC_SUPPORTED 16 #define MAX_SUPPORTED_MULTICASTS MAX_MAC_SUPPORTED @@ -507,33 +671,20 @@ typedef struct s2io_nic { macaddr_t pre_mac_addr[MAX_MAC_SUPPORTED]; struct net_device_stats stats; - void __iomem *bar0; - void __iomem *bar1; - struct config_param config; - mac_info_t mac_control; int high_dma_flag; int device_close_flag; int device_enabled_once; - char name[32]; + char name[50]; struct tasklet_struct task; volatile unsigned long tasklet_status; - struct timer_list timer; - struct net_device *dev; - struct pci_dev *pdev; - u16 vendor_id; - u16 device_id; - u16 ccmd; - u32 cbar0_1; - u32 cbar0_2; - u32 cbar1_1; - u32 cbar1_2; - u32 cirq; - u8 cache_line; - u32 rom_expansion; - u16 pcix_cmd; - u32 irq; + /* Timer that handles I/O errors/exceptions */ + struct timer_list alarm_timer; + + /* Space to back up the PCI config space */ + u32 config_space[256 / sizeof(u32)]; + atomic_t rx_bufs_left[MAX_RX_RINGS]; spinlock_t tx_lock; @@ -558,27 +709,11 @@ typedef struct s2io_nic { u16 tx_err_count; u16 rx_err_count; -#ifndef CONFIG_S2IO_NAPI - /* Index to the absolute position of the put pointer of Rx ring. */ - int put_pos[MAX_RX_RINGS]; -#endif - - /* - * Place holders for the virtual and physical addresses of - * all the Rx Blocks - */ - rx_block_info_t rx_blocks[MAX_RX_RINGS][MAX_RX_BLOCKS_PER_RING]; - int block_count[MAX_RX_RINGS]; - int pkt_cnt[MAX_RX_RINGS]; - - /* Place holder of all the TX List's Phy and Virt addresses. */ - list_info_hold_t *list_info[MAX_TX_FIFOS]; - /* Id timer, used to blink NIC to physically identify NIC. */ struct timer_list id_timer; /* Restart timer, used to restart NIC if the device is stuck and - * a schedule task that will set the correct Link state once the + * a schedule task that will set the correct Link state once the * NIC's PHY has stabilized after a state change. */ #ifdef INIT_TQUEUE @@ -589,12 +724,12 @@ typedef struct s2io_nic { struct work_struct set_link_task; #endif - /* Flag that can be used to turn on or turn off the Rx checksum + /* Flag that can be used to turn on or turn off the Rx checksum * offload feature. */ int rx_csum; - /* after blink, the adapter must be restored with original + /* after blink, the adapter must be restored with original * values. */ u64 adapt_ctrl_org; @@ -604,16 +739,19 @@ typedef struct s2io_nic { #define LINK_DOWN 1 #define LINK_UP 2 -#ifdef CONFIG_2BUFF_MODE - /* Buffer Address store. */ - buffAdd_t **ba[MAX_RX_RINGS]; -#endif int task_flag; #define CARD_DOWN 1 #define CARD_UP 2 atomic_t card_state; volatile unsigned long link_state; -} nic_t; + struct vlan_group *vlgrp; +#define XFRAME_I_DEVICE 1 +#define XFRAME_II_DEVICE 2 + u8 device_type; + + spinlock_t rx_lock; + atomic_t isr_cnt; +}; #define RESET_ERROR 1; #define CMD_ERROR 2; @@ -622,9 +760,10 @@ typedef struct s2io_nic { #ifndef readq static inline u64 readq(void __iomem *addr) { - u64 ret = readl(addr + 4); - ret <<= 32; - ret |= readl(addr); + u64 ret = 0; + ret = readl(addr + 4); + (u64) ret <<= 32; + (u64) ret |= readl(addr); return ret; } @@ -637,10 +776,10 @@ static inline void writeq(u64 val, void __iomem *addr) writel((u32) (val >> 32), (addr + 4)); } -/* In 32 bit modes, some registers have to be written in a +/* In 32 bit modes, some registers have to be written in a * particular order to expect correct hardware operation. The - * macro SPECIAL_REG_WRITE is used to perform such ordered - * writes. Defines UF (Upper First) and LF (Lower First) will + * macro SPECIAL_REG_WRITE is used to perform such ordered + * writes. Defines UF (Upper First) and LF (Lower First) will * be used to specify the required write order. */ #define UF 1 @@ -716,6 +855,7 @@ static inline void SPECIAL_REG_WRITE(u64 val, void __iomem *addr, int order) #define PCC_FB_ECC_ERR vBIT(0xff, 16, 8) /* Interrupt to indicate PCC_FB_ECC Error. */ +#define RXD_GET_VLAN_TAG(Control_2) (u16)(Control_2 & MASK_VLAN_TAG) /* * Prototype declaration. */ @@ -725,36 +865,30 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev); static int init_shared_mem(struct s2io_nic *sp); static void free_shared_mem(struct s2io_nic *sp); static int init_nic(struct s2io_nic *nic); -#ifndef CONFIG_S2IO_NAPI -static void rx_intr_handler(struct s2io_nic *sp); -#endif -static void tx_intr_handler(struct s2io_nic *sp); +static void rx_intr_handler(ring_info_t *ring_data); +static void tx_intr_handler(fifo_info_t *fifo_data); static void alarm_intr_handler(struct s2io_nic *sp); static int s2io_starter(void); -static void s2io_closer(void); +void s2io_closer(void); static void s2io_tx_watchdog(struct net_device *dev); static void s2io_tasklet(unsigned long dev_addr); static void s2io_set_multicast(struct net_device *dev); -#ifndef CONFIG_2BUFF_MODE -static int rx_osm_handler(nic_t * sp, u16 len, RxD_t * rxdp, int ring_no); -#else -static int rx_osm_handler(nic_t * sp, RxD_t * rxdp, int ring_no, - buffAdd_t * ba); -#endif -static void s2io_link(nic_t * sp, int link); -static void s2io_reset(nic_t * sp); -#ifdef CONFIG_S2IO_NAPI +static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp); +void s2io_link(nic_t * sp, int link); +void s2io_reset(nic_t * sp); +#if defined(CONFIG_S2IO_NAPI) static int s2io_poll(struct net_device *dev, int *budget); #endif static void s2io_init_pci(nic_t * sp); -static int s2io_set_mac_addr(struct net_device *dev, u8 * addr); +int s2io_set_mac_addr(struct net_device *dev, u8 * addr); +static void s2io_alarm_handle(unsigned long data); static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs); -static int verify_xena_quiescence(u64 val64, int flag); +static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag); static struct ethtool_ops netdev_ethtool_ops; static void s2io_set_link(unsigned long data); -static int s2io_set_swapper(nic_t * sp); -static void s2io_card_down(nic_t * nic); -static int s2io_card_up(nic_t * nic); - +int s2io_set_swapper(nic_t * sp); +static void s2io_card_down(nic_t *nic); +static int s2io_card_up(nic_t *nic); +int get_xena_rev_id(struct pci_dev *pdev); #endif /* _S2IO_H */ diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c new file mode 100644 index 00000000000..bf3440aa6c2 --- /dev/null +++ b/drivers/net/sis190.c @@ -0,0 +1,1843 @@ +/* + sis190.c: Silicon Integrated Systems SiS190 ethernet driver + + Copyright (c) 2003 K.M. Liu <kmliu@sis.com> + Copyright (c) 2003, 2004 Jeff Garzik <jgarzik@pobox.com> + Copyright (c) 2003, 2004, 2005 Francois Romieu <romieu@fr.zoreil.com> + + Based on r8169.c, tg3.c, 8139cp.c, skge.c, epic100.c and SiS 190/191 + genuine driver. + + This software may be used and distributed according to the terms of + the GNU General Public License (GPL), incorporated herein by reference. + Drivers based on or derived from this code fall under the GPL and must + retain the authorship, copyright and license notice. This file is not + a complete program and may only be used when the entire operating + system is licensed under the GPL. + + See the file COPYING in this distribution for more information. + + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/netdevice.h> +#include <linux/rtnetlink.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/pci.h> +#include <linux/mii.h> +#include <linux/delay.h> +#include <linux/crc32.h> +#include <linux/dma-mapping.h> +#include <asm/irq.h> + +#define net_drv(p, arg...) if (netif_msg_drv(p)) \ + printk(arg) +#define net_probe(p, arg...) if (netif_msg_probe(p)) \ + printk(arg) +#define net_link(p, arg...) if (netif_msg_link(p)) \ + printk(arg) +#define net_intr(p, arg...) if (netif_msg_intr(p)) \ + printk(arg) +#define net_tx_err(p, arg...) if (netif_msg_tx_err(p)) \ + printk(arg) + +#define PHY_MAX_ADDR 32 +#define PHY_ID_ANY 0x1f +#define MII_REG_ANY 0x1f + +#ifdef CONFIG_SIS190_NAPI +#define NAPI_SUFFIX "-NAPI" +#else +#define NAPI_SUFFIX "" +#endif + +#define DRV_VERSION "1.2" NAPI_SUFFIX +#define DRV_NAME "sis190" +#define SIS190_DRIVER_NAME DRV_NAME " Gigabit Ethernet driver " DRV_VERSION +#define PFX DRV_NAME ": " + +#ifdef CONFIG_SIS190_NAPI +#define sis190_rx_skb netif_receive_skb +#define sis190_rx_quota(count, quota) min(count, quota) +#else +#define sis190_rx_skb netif_rx +#define sis190_rx_quota(count, quota) count +#endif + +#define MAC_ADDR_LEN 6 + +#define NUM_TX_DESC 64 /* [8..1024] */ +#define NUM_RX_DESC 64 /* [8..8192] */ +#define TX_RING_BYTES (NUM_TX_DESC * sizeof(struct TxDesc)) +#define RX_RING_BYTES (NUM_RX_DESC * sizeof(struct RxDesc)) +#define RX_BUF_SIZE 1536 +#define RX_BUF_MASK 0xfff8 + +#define SIS190_REGS_SIZE 0x80 +#define SIS190_TX_TIMEOUT (6*HZ) +#define SIS190_PHY_TIMEOUT (10*HZ) +#define SIS190_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | \ + NETIF_MSG_LINK | NETIF_MSG_IFUP | \ + NETIF_MSG_IFDOWN) + +/* Enhanced PHY access register bit definitions */ +#define EhnMIIread 0x0000 +#define EhnMIIwrite 0x0020 +#define EhnMIIdataShift 16 +#define EhnMIIpmdShift 6 /* 7016 only */ +#define EhnMIIregShift 11 +#define EhnMIIreq 0x0010 +#define EhnMIInotDone 0x0010 + +/* Write/read MMIO register */ +#define SIS_W8(reg, val) writeb ((val), ioaddr + (reg)) +#define SIS_W16(reg, val) writew ((val), ioaddr + (reg)) +#define SIS_W32(reg, val) writel ((val), ioaddr + (reg)) +#define SIS_R8(reg) readb (ioaddr + (reg)) +#define SIS_R16(reg) readw (ioaddr + (reg)) +#define SIS_R32(reg) readl (ioaddr + (reg)) + +#define SIS_PCI_COMMIT() SIS_R32(IntrControl) + +enum sis190_registers { + TxControl = 0x00, + TxDescStartAddr = 0x04, + rsv0 = 0x08, // reserved + TxSts = 0x0c, // unused (Control/Status) + RxControl = 0x10, + RxDescStartAddr = 0x14, + rsv1 = 0x18, // reserved + RxSts = 0x1c, // unused + IntrStatus = 0x20, + IntrMask = 0x24, + IntrControl = 0x28, + IntrTimer = 0x2c, // unused (Interupt Timer) + PMControl = 0x30, // unused (Power Mgmt Control/Status) + rsv2 = 0x34, // reserved + ROMControl = 0x38, + ROMInterface = 0x3c, + StationControl = 0x40, + GMIIControl = 0x44, + GIoCR = 0x48, // unused (GMAC IO Compensation) + GIoCtrl = 0x4c, // unused (GMAC IO Control) + TxMacControl = 0x50, + TxLimit = 0x54, // unused (Tx MAC Timer/TryLimit) + RGDelay = 0x58, // unused (RGMII Tx Internal Delay) + rsv3 = 0x5c, // reserved + RxMacControl = 0x60, + RxMacAddr = 0x62, + RxHashTable = 0x68, + // Undocumented = 0x6c, + RxWolCtrl = 0x70, + RxWolData = 0x74, // unused (Rx WOL Data Access) + RxMPSControl = 0x78, // unused (Rx MPS Control) + rsv4 = 0x7c, // reserved +}; + +enum sis190_register_content { + /* IntrStatus */ + SoftInt = 0x40000000, // unused + Timeup = 0x20000000, // unused + PauseFrame = 0x00080000, // unused + MagicPacket = 0x00040000, // unused + WakeupFrame = 0x00020000, // unused + LinkChange = 0x00010000, + RxQEmpty = 0x00000080, + RxQInt = 0x00000040, + TxQ1Empty = 0x00000020, // unused + TxQ1Int = 0x00000010, + TxQ0Empty = 0x00000008, // unused + TxQ0Int = 0x00000004, + RxHalt = 0x00000002, + TxHalt = 0x00000001, + + /* {Rx/Tx}CmdBits */ + CmdReset = 0x10, + CmdRxEnb = 0x08, // unused + CmdTxEnb = 0x01, + RxBufEmpty = 0x01, // unused + + /* Cfg9346Bits */ + Cfg9346_Lock = 0x00, // unused + Cfg9346_Unlock = 0xc0, // unused + + /* RxMacControl */ + AcceptErr = 0x20, // unused + AcceptRunt = 0x10, // unused + AcceptBroadcast = 0x0800, + AcceptMulticast = 0x0400, + AcceptMyPhys = 0x0200, + AcceptAllPhys = 0x0100, + + /* RxConfigBits */ + RxCfgFIFOShift = 13, + RxCfgDMAShift = 8, // 0x1a in RxControl ? + + /* TxConfigBits */ + TxInterFrameGapShift = 24, + TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */ + + /* StationControl */ + _1000bpsF = 0x1c00, + _1000bpsH = 0x0c00, + _100bpsF = 0x1800, + _100bpsH = 0x0800, + _10bpsF = 0x1400, + _10bpsH = 0x0400, + + LinkStatus = 0x02, // unused + FullDup = 0x01, // unused + + /* TBICSRBit */ + TBILinkOK = 0x02000000, // unused +}; + +struct TxDesc { + __le32 PSize; + __le32 status; + __le32 addr; + __le32 size; +}; + +struct RxDesc { + __le32 PSize; + __le32 status; + __le32 addr; + __le32 size; +}; + +enum _DescStatusBit { + /* _Desc.status */ + OWNbit = 0x80000000, // RXOWN/TXOWN + INTbit = 0x40000000, // RXINT/TXINT + CRCbit = 0x00020000, // CRCOFF/CRCEN + PADbit = 0x00010000, // PREADD/PADEN + /* _Desc.size */ + RingEnd = 0x80000000, + /* TxDesc.status */ + LSEN = 0x08000000, // TSO ? -- FR + IPCS = 0x04000000, + TCPCS = 0x02000000, + UDPCS = 0x01000000, + BSTEN = 0x00800000, + EXTEN = 0x00400000, + DEFEN = 0x00200000, + BKFEN = 0x00100000, + CRSEN = 0x00080000, + COLEN = 0x00040000, + THOL3 = 0x30000000, + THOL2 = 0x20000000, + THOL1 = 0x10000000, + THOL0 = 0x00000000, + /* RxDesc.status */ + IPON = 0x20000000, + TCPON = 0x10000000, + UDPON = 0x08000000, + Wakup = 0x00400000, + Magic = 0x00200000, + Pause = 0x00100000, + DEFbit = 0x00200000, + BCAST = 0x000c0000, + MCAST = 0x00080000, + UCAST = 0x00040000, + /* RxDesc.PSize */ + TAGON = 0x80000000, + RxDescCountMask = 0x7f000000, // multi-desc pkt when > 1 ? -- FR + ABORT = 0x00800000, + SHORT = 0x00400000, + LIMIT = 0x00200000, + MIIER = 0x00100000, + OVRUN = 0x00080000, + NIBON = 0x00040000, + COLON = 0x00020000, + CRCOK = 0x00010000, + RxSizeMask = 0x0000ffff + /* + * The asic could apparently do vlan, TSO, jumbo (sis191 only) and + * provide two (unused with Linux) Tx queues. No publically + * available documentation alas. + */ +}; + +enum sis190_eeprom_access_register_bits { + EECS = 0x00000001, // unused + EECLK = 0x00000002, // unused + EEDO = 0x00000008, // unused + EEDI = 0x00000004, // unused + EEREQ = 0x00000080, + EEROP = 0x00000200, + EEWOP = 0x00000100 // unused +}; + +/* EEPROM Addresses */ +enum sis190_eeprom_address { + EEPROMSignature = 0x00, + EEPROMCLK = 0x01, // unused + EEPROMInfo = 0x02, + EEPROMMACAddr = 0x03 +}; + +struct sis190_private { + void __iomem *mmio_addr; + struct pci_dev *pci_dev; + struct net_device_stats stats; + spinlock_t lock; + u32 rx_buf_sz; + u32 cur_rx; + u32 cur_tx; + u32 dirty_rx; + u32 dirty_tx; + dma_addr_t rx_dma; + dma_addr_t tx_dma; + struct RxDesc *RxDescRing; + struct TxDesc *TxDescRing; + struct sk_buff *Rx_skbuff[NUM_RX_DESC]; + struct sk_buff *Tx_skbuff[NUM_TX_DESC]; + struct work_struct phy_task; + struct timer_list timer; + u32 msg_enable; + struct mii_if_info mii_if; + struct list_head first_phy; +}; + +struct sis190_phy { + struct list_head list; + int phy_id; + u16 id[2]; + u16 status; + u8 type; +}; + +enum sis190_phy_type { + UNKNOWN = 0x00, + HOME = 0x01, + LAN = 0x02, + MIX = 0x03 +}; + +static struct mii_chip_info { + const char *name; + u16 id[2]; + unsigned int type; +} mii_chip_table[] = { + { "Broadcom PHY BCM5461", { 0x0020, 0x60c0 }, LAN }, + { "Agere PHY ET1101B", { 0x0282, 0xf010 }, LAN }, + { "Marvell PHY 88E1111", { 0x0141, 0x0cc0 }, LAN }, + { "Realtek PHY RTL8201", { 0x0000, 0x8200 }, LAN }, + { NULL, } +}; + +const static struct { + const char *name; + u8 version; /* depend on docs */ + u32 RxConfigMask; /* clear the bits supported by this chip */ +} sis_chip_info[] = { + { DRV_NAME, 0x00, 0xff7e1880, }, +}; + +static struct pci_device_id sis190_pci_tbl[] __devinitdata = { + { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x0190), 0, 0, 0 }, + { 0, }, +}; + +MODULE_DEVICE_TABLE(pci, sis190_pci_tbl); + +static int rx_copybreak = 200; + +static struct { + u32 msg_enable; +} debug = { -1 }; + +MODULE_DESCRIPTION("SiS sis190 Gigabit Ethernet driver"); +module_param(rx_copybreak, int, 0); +MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames"); +module_param_named(debug, debug.msg_enable, int, 0); +MODULE_PARM_DESC(debug, "Debug verbosity level (0=none, ..., 16=all)"); +MODULE_AUTHOR("K.M. Liu <kmliu@sis.com>, Ueimor <romieu@fr.zoreil.com>"); +MODULE_VERSION(DRV_VERSION); +MODULE_LICENSE("GPL"); + +static const u32 sis190_intr_mask = + RxQEmpty | RxQInt | TxQ1Int | TxQ0Int | RxHalt | TxHalt; + +/* + * Maximum number of multicast addresses to filter (vs. Rx-all-multicast). + * The chips use a 64 element hash table based on the Ethernet CRC. + */ +static int multicast_filter_limit = 32; + +static void __mdio_cmd(void __iomem *ioaddr, u32 ctl) +{ + unsigned int i; + + SIS_W32(GMIIControl, ctl); + + msleep(1); + + for (i = 0; i < 100; i++) { + if (!(SIS_R32(GMIIControl) & EhnMIInotDone)) + break; + msleep(1); + } + + if (i > 999) + printk(KERN_ERR PFX "PHY command failed !\n"); +} + +static void mdio_write(void __iomem *ioaddr, int phy_id, int reg, int val) +{ + __mdio_cmd(ioaddr, EhnMIIreq | EhnMIIwrite | + (((u32) reg) << EhnMIIregShift) | (phy_id << EhnMIIpmdShift) | + (((u32) val) << EhnMIIdataShift)); +} + +static int mdio_read(void __iomem *ioaddr, int phy_id, int reg) +{ + __mdio_cmd(ioaddr, EhnMIIreq | EhnMIIread | + (((u32) reg) << EhnMIIregShift) | (phy_id << EhnMIIpmdShift)); + + return (u16) (SIS_R32(GMIIControl) >> EhnMIIdataShift); +} + +static void __mdio_write(struct net_device *dev, int phy_id, int reg, int val) +{ + struct sis190_private *tp = netdev_priv(dev); + + mdio_write(tp->mmio_addr, phy_id, reg, val); +} + +static int __mdio_read(struct net_device *dev, int phy_id, int reg) +{ + struct sis190_private *tp = netdev_priv(dev); + + return mdio_read(tp->mmio_addr, phy_id, reg); +} + +static u16 mdio_read_latched(void __iomem *ioaddr, int phy_id, int reg) +{ + mdio_read(ioaddr, phy_id, reg); + return mdio_read(ioaddr, phy_id, reg); +} + +static u16 __devinit sis190_read_eeprom(void __iomem *ioaddr, u32 reg) +{ + u16 data = 0xffff; + unsigned int i; + + if (!(SIS_R32(ROMControl) & 0x0002)) + return 0; + + SIS_W32(ROMInterface, EEREQ | EEROP | (reg << 10)); + + for (i = 0; i < 200; i++) { + if (!(SIS_R32(ROMInterface) & EEREQ)) { + data = (SIS_R32(ROMInterface) & 0xffff0000) >> 16; + break; + } + msleep(1); + } + + return data; +} + +static void sis190_irq_mask_and_ack(void __iomem *ioaddr) +{ + SIS_W32(IntrMask, 0x00); + SIS_W32(IntrStatus, 0xffffffff); + SIS_PCI_COMMIT(); +} + +static void sis190_asic_down(void __iomem *ioaddr) +{ + /* Stop the chip's Tx and Rx DMA processes. */ + + SIS_W32(TxControl, 0x1a00); + SIS_W32(RxControl, 0x1a00); + + sis190_irq_mask_and_ack(ioaddr); +} + +static void sis190_mark_as_last_descriptor(struct RxDesc *desc) +{ + desc->size |= cpu_to_le32(RingEnd); +} + +static inline void sis190_give_to_asic(struct RxDesc *desc, u32 rx_buf_sz) +{ + u32 eor = le32_to_cpu(desc->size) & RingEnd; + + desc->PSize = 0x0; + desc->size = cpu_to_le32((rx_buf_sz & RX_BUF_MASK) | eor); + wmb(); + desc->status = cpu_to_le32(OWNbit | INTbit); +} + +static inline void sis190_map_to_asic(struct RxDesc *desc, dma_addr_t mapping, + u32 rx_buf_sz) +{ + desc->addr = cpu_to_le32(mapping); + sis190_give_to_asic(desc, rx_buf_sz); +} + +static inline void sis190_make_unusable_by_asic(struct RxDesc *desc) +{ + desc->PSize = 0x0; + desc->addr = 0xdeadbeef; + desc->size &= cpu_to_le32(RingEnd); + wmb(); + desc->status = 0x0; +} + +static int sis190_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff, + struct RxDesc *desc, u32 rx_buf_sz) +{ + struct sk_buff *skb; + dma_addr_t mapping; + int ret = 0; + + skb = dev_alloc_skb(rx_buf_sz); + if (!skb) + goto err_out; + + *sk_buff = skb; + + mapping = pci_map_single(pdev, skb->data, rx_buf_sz, + PCI_DMA_FROMDEVICE); + + sis190_map_to_asic(desc, mapping, rx_buf_sz); +out: + return ret; + +err_out: + ret = -ENOMEM; + sis190_make_unusable_by_asic(desc); + goto out; +} + +static u32 sis190_rx_fill(struct sis190_private *tp, struct net_device *dev, + u32 start, u32 end) +{ + u32 cur; + + for (cur = start; cur < end; cur++) { + int ret, i = cur % NUM_RX_DESC; + + if (tp->Rx_skbuff[i]) + continue; + + ret = sis190_alloc_rx_skb(tp->pci_dev, tp->Rx_skbuff + i, + tp->RxDescRing + i, tp->rx_buf_sz); + if (ret < 0) + break; + } + return cur - start; +} + +static inline int sis190_try_rx_copy(struct sk_buff **sk_buff, int pkt_size, + struct RxDesc *desc, int rx_buf_sz) +{ + int ret = -1; + + if (pkt_size < rx_copybreak) { + struct sk_buff *skb; + + skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN); + if (skb) { + skb_reserve(skb, NET_IP_ALIGN); + eth_copy_and_sum(skb, sk_buff[0]->data, pkt_size, 0); + *sk_buff = skb; + sis190_give_to_asic(desc, rx_buf_sz); + ret = 0; + } + } + return ret; +} + +static inline int sis190_rx_pkt_err(u32 status, struct net_device_stats *stats) +{ +#define ErrMask (OVRUN | SHORT | LIMIT | MIIER | NIBON | COLON | ABORT) + + if ((status & CRCOK) && !(status & ErrMask)) + return 0; + + if (!(status & CRCOK)) + stats->rx_crc_errors++; + else if (status & OVRUN) + stats->rx_over_errors++; + else if (status & (SHORT | LIMIT)) + stats->rx_length_errors++; + else if (status & (MIIER | NIBON | COLON)) + stats->rx_frame_errors++; + + stats->rx_errors++; + return -1; +} + +static int sis190_rx_interrupt(struct net_device *dev, + struct sis190_private *tp, void __iomem *ioaddr) +{ + struct net_device_stats *stats = &tp->stats; + u32 rx_left, cur_rx = tp->cur_rx; + u32 delta, count; + + rx_left = NUM_RX_DESC + tp->dirty_rx - cur_rx; + rx_left = sis190_rx_quota(rx_left, (u32) dev->quota); + + for (; rx_left > 0; rx_left--, cur_rx++) { + unsigned int entry = cur_rx % NUM_RX_DESC; + struct RxDesc *desc = tp->RxDescRing + entry; + u32 status; + + if (desc->status & OWNbit) + break; + + status = le32_to_cpu(desc->PSize); + + // net_intr(tp, KERN_INFO "%s: Rx PSize = %08x.\n", dev->name, + // status); + + if (sis190_rx_pkt_err(status, stats) < 0) + sis190_give_to_asic(desc, tp->rx_buf_sz); + else { + struct sk_buff *skb = tp->Rx_skbuff[entry]; + int pkt_size = (status & RxSizeMask) - 4; + void (*pci_action)(struct pci_dev *, dma_addr_t, + size_t, int) = pci_dma_sync_single_for_device; + + if (unlikely(pkt_size > tp->rx_buf_sz)) { + net_intr(tp, KERN_INFO + "%s: (frag) status = %08x.\n", + dev->name, status); + stats->rx_dropped++; + stats->rx_length_errors++; + sis190_give_to_asic(desc, tp->rx_buf_sz); + continue; + } + + pci_dma_sync_single_for_cpu(tp->pci_dev, + le32_to_cpu(desc->addr), tp->rx_buf_sz, + PCI_DMA_FROMDEVICE); + + if (sis190_try_rx_copy(&skb, pkt_size, desc, + tp->rx_buf_sz)) { + pci_action = pci_unmap_single; + tp->Rx_skbuff[entry] = NULL; + sis190_make_unusable_by_asic(desc); + } + + pci_action(tp->pci_dev, le32_to_cpu(desc->addr), + tp->rx_buf_sz, PCI_DMA_FROMDEVICE); + + skb->dev = dev; + skb_put(skb, pkt_size); + skb->protocol = eth_type_trans(skb, dev); + + sis190_rx_skb(skb); + + dev->last_rx = jiffies; + stats->rx_packets++; + stats->rx_bytes += pkt_size; + if ((status & BCAST) == MCAST) + stats->multicast++; + } + } + count = cur_rx - tp->cur_rx; + tp->cur_rx = cur_rx; + + delta = sis190_rx_fill(tp, dev, tp->dirty_rx, tp->cur_rx); + if (!delta && count && netif_msg_intr(tp)) + printk(KERN_INFO "%s: no Rx buffer allocated.\n", dev->name); + tp->dirty_rx += delta; + + if (((tp->dirty_rx + NUM_RX_DESC) == tp->cur_rx) && netif_msg_intr(tp)) + printk(KERN_EMERG "%s: Rx buffers exhausted.\n", dev->name); + + return count; +} + +static void sis190_unmap_tx_skb(struct pci_dev *pdev, struct sk_buff *skb, + struct TxDesc *desc) +{ + unsigned int len; + + len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + + pci_unmap_single(pdev, le32_to_cpu(desc->addr), len, PCI_DMA_TODEVICE); + + memset(desc, 0x00, sizeof(*desc)); +} + +static void sis190_tx_interrupt(struct net_device *dev, + struct sis190_private *tp, void __iomem *ioaddr) +{ + u32 pending, dirty_tx = tp->dirty_tx; + /* + * It would not be needed if queueing was allowed to be enabled + * again too early (hint: think preempt and unclocked smp systems). + */ + unsigned int queue_stopped; + + smp_rmb(); + pending = tp->cur_tx - dirty_tx; + queue_stopped = (pending == NUM_TX_DESC); + + for (; pending; pending--, dirty_tx++) { + unsigned int entry = dirty_tx % NUM_TX_DESC; + struct TxDesc *txd = tp->TxDescRing + entry; + struct sk_buff *skb; + + if (le32_to_cpu(txd->status) & OWNbit) + break; + + skb = tp->Tx_skbuff[entry]; + + tp->stats.tx_packets++; + tp->stats.tx_bytes += skb->len; + + sis190_unmap_tx_skb(tp->pci_dev, skb, txd); + tp->Tx_skbuff[entry] = NULL; + dev_kfree_skb_irq(skb); + } + + if (tp->dirty_tx != dirty_tx) { + tp->dirty_tx = dirty_tx; + smp_wmb(); + if (queue_stopped) + netif_wake_queue(dev); + } +} + +/* + * The interrupt handler does all of the Rx thread work and cleans up after + * the Tx thread. + */ +static irqreturn_t sis190_interrupt(int irq, void *__dev, struct pt_regs *regs) +{ + struct net_device *dev = __dev; + struct sis190_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + unsigned int handled = 0; + u32 status; + + status = SIS_R32(IntrStatus); + + if ((status == 0xffffffff) || !status) + goto out; + + handled = 1; + + if (unlikely(!netif_running(dev))) { + sis190_asic_down(ioaddr); + goto out; + } + + SIS_W32(IntrStatus, status); + + // net_intr(tp, KERN_INFO "%s: status = %08x.\n", dev->name, status); + + if (status & LinkChange) { + net_intr(tp, KERN_INFO "%s: link change.\n", dev->name); + schedule_work(&tp->phy_task); + } + + if (status & RxQInt) + sis190_rx_interrupt(dev, tp, ioaddr); + + if (status & TxQ0Int) + sis190_tx_interrupt(dev, tp, ioaddr); +out: + return IRQ_RETVAL(handled); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void sis190_netpoll(struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + struct pci_dev *pdev = tp->pci_dev; + + disable_irq(pdev->irq); + sis190_interrupt(pdev->irq, dev, NULL); + enable_irq(pdev->irq); +} +#endif + +static void sis190_free_rx_skb(struct sis190_private *tp, + struct sk_buff **sk_buff, struct RxDesc *desc) +{ + struct pci_dev *pdev = tp->pci_dev; + + pci_unmap_single(pdev, le32_to_cpu(desc->addr), tp->rx_buf_sz, + PCI_DMA_FROMDEVICE); + dev_kfree_skb(*sk_buff); + *sk_buff = NULL; + sis190_make_unusable_by_asic(desc); +} + +static void sis190_rx_clear(struct sis190_private *tp) +{ + unsigned int i; + + for (i = 0; i < NUM_RX_DESC; i++) { + if (!tp->Rx_skbuff[i]) + continue; + sis190_free_rx_skb(tp, tp->Rx_skbuff + i, tp->RxDescRing + i); + } +} + +static void sis190_init_ring_indexes(struct sis190_private *tp) +{ + tp->dirty_tx = tp->dirty_rx = tp->cur_tx = tp->cur_rx = 0; +} + +static int sis190_init_ring(struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + + sis190_init_ring_indexes(tp); + + memset(tp->Tx_skbuff, 0x0, NUM_TX_DESC * sizeof(struct sk_buff *)); + memset(tp->Rx_skbuff, 0x0, NUM_RX_DESC * sizeof(struct sk_buff *)); + + if (sis190_rx_fill(tp, dev, 0, NUM_RX_DESC) != NUM_RX_DESC) + goto err_rx_clear; + + sis190_mark_as_last_descriptor(tp->RxDescRing + NUM_RX_DESC - 1); + + return 0; + +err_rx_clear: + sis190_rx_clear(tp); + return -ENOMEM; +} + +static void sis190_set_rx_mode(struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + unsigned long flags; + u32 mc_filter[2]; /* Multicast hash filter */ + u16 rx_mode; + + if (dev->flags & IFF_PROMISC) { + /* Unconditionally log net taps. */ + net_drv(tp, KERN_NOTICE "%s: Promiscuous mode enabled.\n", + dev->name); + rx_mode = + AcceptBroadcast | AcceptMulticast | AcceptMyPhys | + AcceptAllPhys; + mc_filter[1] = mc_filter[0] = 0xffffffff; + } else if ((dev->mc_count > multicast_filter_limit) || + (dev->flags & IFF_ALLMULTI)) { + /* Too many to filter perfectly -- accept all multicasts. */ + rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys; + mc_filter[1] = mc_filter[0] = 0xffffffff; + } else { + struct dev_mc_list *mclist; + unsigned int i; + + rx_mode = AcceptBroadcast | AcceptMyPhys; + mc_filter[1] = mc_filter[0] = 0; + for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count; + i++, mclist = mclist->next) { + int bit_nr = + ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; + mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); + rx_mode |= AcceptMulticast; + } + } + + spin_lock_irqsave(&tp->lock, flags); + + SIS_W16(RxMacControl, rx_mode | 0x2); + SIS_W32(RxHashTable, mc_filter[0]); + SIS_W32(RxHashTable + 4, mc_filter[1]); + + spin_unlock_irqrestore(&tp->lock, flags); +} + +static void sis190_soft_reset(void __iomem *ioaddr) +{ + SIS_W32(IntrControl, 0x8000); + SIS_PCI_COMMIT(); + msleep(1); + SIS_W32(IntrControl, 0x0); + sis190_asic_down(ioaddr); + msleep(1); +} + +static void sis190_hw_start(struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + + sis190_soft_reset(ioaddr); + + SIS_W32(TxDescStartAddr, tp->tx_dma); + SIS_W32(RxDescStartAddr, tp->rx_dma); + + SIS_W32(IntrStatus, 0xffffffff); + SIS_W32(IntrMask, 0x0); + /* + * Default is 100Mbps. + * A bit strange: 100Mbps is 0x1801 elsewhere -- FR 2005/06/09 + */ + SIS_W16(StationControl, 0x1901); + SIS_W32(GMIIControl, 0x0); + SIS_W32(TxMacControl, 0x60); + SIS_W16(RxMacControl, 0x02); + SIS_W32(RxHashTable, 0x0); + SIS_W32(0x6c, 0x0); + SIS_W32(RxWolCtrl, 0x0); + SIS_W32(RxWolData, 0x0); + + SIS_PCI_COMMIT(); + + sis190_set_rx_mode(dev); + + /* Enable all known interrupts by setting the interrupt mask. */ + SIS_W32(IntrMask, sis190_intr_mask); + + SIS_W32(TxControl, 0x1a00 | CmdTxEnb); + SIS_W32(RxControl, 0x1a1d); + + netif_start_queue(dev); +} + +static void sis190_phy_task(void * data) +{ + struct net_device *dev = data; + struct sis190_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + int phy_id = tp->mii_if.phy_id; + u16 val; + + rtnl_lock(); + + val = mdio_read(ioaddr, phy_id, MII_BMCR); + if (val & BMCR_RESET) { + // FIXME: needlessly high ? -- FR 02/07/2005 + mod_timer(&tp->timer, jiffies + HZ/10); + } else if (!(mdio_read_latched(ioaddr, phy_id, MII_BMSR) & + BMSR_ANEGCOMPLETE)) { + net_link(tp, KERN_WARNING "%s: PHY reset until link up.\n", + dev->name); + mdio_write(ioaddr, phy_id, MII_BMCR, val | BMCR_RESET); + mod_timer(&tp->timer, jiffies + SIS190_PHY_TIMEOUT); + } else { + /* Rejoice ! */ + struct { + int val; + const char *msg; + u16 ctl; + } reg31[] = { + { LPA_1000XFULL | LPA_SLCT, + "1000 Mbps Full Duplex", + 0x01 | _1000bpsF }, + { LPA_1000XHALF | LPA_SLCT, + "1000 Mbps Half Duplex", + 0x01 | _1000bpsH }, + { LPA_100FULL, + "100 Mbps Full Duplex", + 0x01 | _100bpsF }, + { LPA_100HALF, + "100 Mbps Half Duplex", + 0x01 | _100bpsH }, + { LPA_10FULL, + "10 Mbps Full Duplex", + 0x01 | _10bpsF }, + { LPA_10HALF, + "10 Mbps Half Duplex", + 0x01 | _10bpsH }, + { 0, "unknown", 0x0000 } + }, *p; + u16 adv; + + val = mdio_read(ioaddr, phy_id, 0x1f); + net_link(tp, KERN_INFO "%s: mii ext = %04x.\n", dev->name, val); + + val = mdio_read(ioaddr, phy_id, MII_LPA); + adv = mdio_read(ioaddr, phy_id, MII_ADVERTISE); + net_link(tp, KERN_INFO "%s: mii lpa = %04x adv = %04x.\n", + dev->name, val, adv); + + val &= adv; + + for (p = reg31; p->ctl; p++) { + if ((val & p->val) == p->val) + break; + } + if (p->ctl) + SIS_W16(StationControl, p->ctl); + net_link(tp, KERN_INFO "%s: link on %s mode.\n", dev->name, + p->msg); + netif_carrier_on(dev); + } + + rtnl_unlock(); +} + +static void sis190_phy_timer(unsigned long __opaque) +{ + struct net_device *dev = (struct net_device *)__opaque; + struct sis190_private *tp = netdev_priv(dev); + + if (likely(netif_running(dev))) + schedule_work(&tp->phy_task); +} + +static inline void sis190_delete_timer(struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + + del_timer_sync(&tp->timer); +} + +static inline void sis190_request_timer(struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + struct timer_list *timer = &tp->timer; + + init_timer(timer); + timer->expires = jiffies + SIS190_PHY_TIMEOUT; + timer->data = (unsigned long)dev; + timer->function = sis190_phy_timer; + add_timer(timer); +} + +static void sis190_set_rxbufsize(struct sis190_private *tp, + struct net_device *dev) +{ + unsigned int mtu = dev->mtu; + + tp->rx_buf_sz = (mtu > RX_BUF_SIZE) ? mtu + ETH_HLEN + 8 : RX_BUF_SIZE; + /* RxDesc->size has a licence to kill the lower bits */ + if (tp->rx_buf_sz & 0x07) { + tp->rx_buf_sz += 8; + tp->rx_buf_sz &= RX_BUF_MASK; + } +} + +static int sis190_open(struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + struct pci_dev *pdev = tp->pci_dev; + int rc = -ENOMEM; + + sis190_set_rxbufsize(tp, dev); + + /* + * Rx and Tx descriptors need 256 bytes alignment. + * pci_alloc_consistent() guarantees a stronger alignment. + */ + tp->TxDescRing = pci_alloc_consistent(pdev, TX_RING_BYTES, &tp->tx_dma); + if (!tp->TxDescRing) + goto out; + + tp->RxDescRing = pci_alloc_consistent(pdev, RX_RING_BYTES, &tp->rx_dma); + if (!tp->RxDescRing) + goto err_free_tx_0; + + rc = sis190_init_ring(dev); + if (rc < 0) + goto err_free_rx_1; + + INIT_WORK(&tp->phy_task, sis190_phy_task, dev); + + sis190_request_timer(dev); + + rc = request_irq(dev->irq, sis190_interrupt, SA_SHIRQ, dev->name, dev); + if (rc < 0) + goto err_release_timer_2; + + sis190_hw_start(dev); +out: + return rc; + +err_release_timer_2: + sis190_delete_timer(dev); + sis190_rx_clear(tp); +err_free_rx_1: + pci_free_consistent(tp->pci_dev, RX_RING_BYTES, tp->RxDescRing, + tp->rx_dma); +err_free_tx_0: + pci_free_consistent(tp->pci_dev, TX_RING_BYTES, tp->TxDescRing, + tp->tx_dma); + goto out; +} + +static void sis190_tx_clear(struct sis190_private *tp) +{ + unsigned int i; + + for (i = 0; i < NUM_TX_DESC; i++) { + struct sk_buff *skb = tp->Tx_skbuff[i]; + + if (!skb) + continue; + + sis190_unmap_tx_skb(tp->pci_dev, skb, tp->TxDescRing + i); + tp->Tx_skbuff[i] = NULL; + dev_kfree_skb(skb); + + tp->stats.tx_dropped++; + } + tp->cur_tx = tp->dirty_tx = 0; +} + +static void sis190_down(struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + unsigned int poll_locked = 0; + + sis190_delete_timer(dev); + + netif_stop_queue(dev); + + flush_scheduled_work(); + + do { + spin_lock_irq(&tp->lock); + + sis190_asic_down(ioaddr); + + spin_unlock_irq(&tp->lock); + + synchronize_irq(dev->irq); + + if (!poll_locked) { + netif_poll_disable(dev); + poll_locked++; + } + + synchronize_sched(); + + } while (SIS_R32(IntrMask)); + + sis190_tx_clear(tp); + sis190_rx_clear(tp); +} + +static int sis190_close(struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + struct pci_dev *pdev = tp->pci_dev; + + sis190_down(dev); + + free_irq(dev->irq, dev); + + netif_poll_enable(dev); + + pci_free_consistent(pdev, TX_RING_BYTES, tp->TxDescRing, tp->tx_dma); + pci_free_consistent(pdev, RX_RING_BYTES, tp->RxDescRing, tp->rx_dma); + + tp->TxDescRing = NULL; + tp->RxDescRing = NULL; + + return 0; +} + +static int sis190_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + u32 len, entry, dirty_tx; + struct TxDesc *desc; + dma_addr_t mapping; + + if (unlikely(skb->len < ETH_ZLEN)) { + skb = skb_padto(skb, ETH_ZLEN); + if (!skb) { + tp->stats.tx_dropped++; + goto out; + } + len = ETH_ZLEN; + } else { + len = skb->len; + } + + entry = tp->cur_tx % NUM_TX_DESC; + desc = tp->TxDescRing + entry; + + if (unlikely(le32_to_cpu(desc->status) & OWNbit)) { + netif_stop_queue(dev); + net_tx_err(tp, KERN_ERR PFX + "%s: BUG! Tx Ring full when queue awake!\n", + dev->name); + return NETDEV_TX_BUSY; + } + + mapping = pci_map_single(tp->pci_dev, skb->data, len, PCI_DMA_TODEVICE); + + tp->Tx_skbuff[entry] = skb; + + desc->PSize = cpu_to_le32(len); + desc->addr = cpu_to_le32(mapping); + + desc->size = cpu_to_le32(len); + if (entry == (NUM_TX_DESC - 1)) + desc->size |= cpu_to_le32(RingEnd); + + wmb(); + + desc->status = cpu_to_le32(OWNbit | INTbit | DEFbit | CRCbit | PADbit); + + tp->cur_tx++; + + smp_wmb(); + + SIS_W32(TxControl, 0x1a00 | CmdReset | CmdTxEnb); + + dev->trans_start = jiffies; + + dirty_tx = tp->dirty_tx; + if ((tp->cur_tx - NUM_TX_DESC) == dirty_tx) { + netif_stop_queue(dev); + smp_rmb(); + if (dirty_tx != tp->dirty_tx) + netif_wake_queue(dev); + } +out: + return NETDEV_TX_OK; +} + +static struct net_device_stats *sis190_get_stats(struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + + return &tp->stats; +} + +static void sis190_free_phy(struct list_head *first_phy) +{ + struct sis190_phy *cur, *next; + + list_for_each_entry_safe(cur, next, first_phy, list) { + kfree(cur); + } +} + +/** + * sis190_default_phy - Select default PHY for sis190 mac. + * @dev: the net device to probe for + * + * Select first detected PHY with link as default. + * If no one is link on, select PHY whose types is HOME as default. + * If HOME doesn't exist, select LAN. + */ +static u16 sis190_default_phy(struct net_device *dev) +{ + struct sis190_phy *phy, *phy_home, *phy_default, *phy_lan; + struct sis190_private *tp = netdev_priv(dev); + struct mii_if_info *mii_if = &tp->mii_if; + void __iomem *ioaddr = tp->mmio_addr; + u16 status; + + phy_home = phy_default = phy_lan = NULL; + + list_for_each_entry(phy, &tp->first_phy, list) { + status = mdio_read_latched(ioaddr, phy->phy_id, MII_BMSR); + + // Link ON & Not select default PHY & not ghost PHY. + if ((status & BMSR_LSTATUS) && + !phy_default && + (phy->type != UNKNOWN)) { + phy_default = phy; + } else { + status = mdio_read(ioaddr, phy->phy_id, MII_BMCR); + mdio_write(ioaddr, phy->phy_id, MII_BMCR, + status | BMCR_ANENABLE | BMCR_ISOLATE); + if (phy->type == HOME) + phy_home = phy; + else if (phy->type == LAN) + phy_lan = phy; + } + } + + if (!phy_default) { + if (phy_home) + phy_default = phy_home; + else if (phy_lan) + phy_default = phy_lan; + else + phy_default = list_entry(&tp->first_phy, + struct sis190_phy, list); + } + + if (mii_if->phy_id != phy_default->phy_id) { + mii_if->phy_id = phy_default->phy_id; + net_probe(tp, KERN_INFO + "%s: Using transceiver at address %d as default.\n", + pci_name(tp->pci_dev), mii_if->phy_id); + } + + status = mdio_read(ioaddr, mii_if->phy_id, MII_BMCR); + status &= (~BMCR_ISOLATE); + + mdio_write(ioaddr, mii_if->phy_id, MII_BMCR, status); + status = mdio_read_latched(ioaddr, mii_if->phy_id, MII_BMSR); + + return status; +} + +static void sis190_init_phy(struct net_device *dev, struct sis190_private *tp, + struct sis190_phy *phy, unsigned int phy_id, + u16 mii_status) +{ + void __iomem *ioaddr = tp->mmio_addr; + struct mii_chip_info *p; + + INIT_LIST_HEAD(&phy->list); + phy->status = mii_status; + phy->phy_id = phy_id; + + phy->id[0] = mdio_read(ioaddr, phy_id, MII_PHYSID1); + phy->id[1] = mdio_read(ioaddr, phy_id, MII_PHYSID2); + + for (p = mii_chip_table; p->type; p++) { + if ((p->id[0] == phy->id[0]) && + (p->id[1] == (phy->id[1] & 0xfff0))) { + break; + } + } + + if (p->id[1]) { + phy->type = (p->type == MIX) ? + ((mii_status & (BMSR_100FULL | BMSR_100HALF)) ? + LAN : HOME) : p->type; + } else + phy->type = UNKNOWN; + + net_probe(tp, KERN_INFO "%s: %s transceiver at address %d.\n", + pci_name(tp->pci_dev), + (phy->type == UNKNOWN) ? "Unknown PHY" : p->name, phy_id); +} + +/** + * sis190_mii_probe - Probe MII PHY for sis190 + * @dev: the net device to probe for + * + * Search for total of 32 possible mii phy addresses. + * Identify and set current phy if found one, + * return error if it failed to found. + */ +static int __devinit sis190_mii_probe(struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + struct mii_if_info *mii_if = &tp->mii_if; + void __iomem *ioaddr = tp->mmio_addr; + int phy_id; + int rc = 0; + + INIT_LIST_HEAD(&tp->first_phy); + + for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) { + struct sis190_phy *phy; + u16 status; + + status = mdio_read_latched(ioaddr, phy_id, MII_BMSR); + + // Try next mii if the current one is not accessible. + if (status == 0xffff || status == 0x0000) + continue; + + phy = kmalloc(sizeof(*phy), GFP_KERNEL); + if (!phy) { + sis190_free_phy(&tp->first_phy); + rc = -ENOMEM; + goto out; + } + + sis190_init_phy(dev, tp, phy, phy_id, status); + + list_add(&tp->first_phy, &phy->list); + } + + if (list_empty(&tp->first_phy)) { + net_probe(tp, KERN_INFO "%s: No MII transceivers found!\n", + pci_name(tp->pci_dev)); + rc = -EIO; + goto out; + } + + /* Select default PHY for mac */ + sis190_default_phy(dev); + + mii_if->dev = dev; + mii_if->mdio_read = __mdio_read; + mii_if->mdio_write = __mdio_write; + mii_if->phy_id_mask = PHY_ID_ANY; + mii_if->reg_num_mask = MII_REG_ANY; +out: + return rc; +} + +static void __devexit sis190_mii_remove(struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + + sis190_free_phy(&tp->first_phy); +} + +static void sis190_release_board(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct sis190_private *tp = netdev_priv(dev); + + iounmap(tp->mmio_addr); + pci_release_regions(pdev); + pci_disable_device(pdev); + free_netdev(dev); +} + +static struct net_device * __devinit sis190_init_board(struct pci_dev *pdev) +{ + struct sis190_private *tp; + struct net_device *dev; + void __iomem *ioaddr; + int rc; + + dev = alloc_etherdev(sizeof(*tp)); + if (!dev) { + net_drv(&debug, KERN_ERR PFX "unable to alloc new ethernet\n"); + rc = -ENOMEM; + goto err_out_0; + } + + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pdev->dev); + + tp = netdev_priv(dev); + tp->msg_enable = netif_msg_init(debug.msg_enable, SIS190_MSG_DEFAULT); + + rc = pci_enable_device(pdev); + if (rc < 0) { + net_probe(tp, KERN_ERR "%s: enable failure\n", pci_name(pdev)); + goto err_free_dev_1; + } + + rc = -ENODEV; + + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + net_probe(tp, KERN_ERR "%s: region #0 is no MMIO resource.\n", + pci_name(pdev)); + goto err_pci_disable_2; + } + if (pci_resource_len(pdev, 0) < SIS190_REGS_SIZE) { + net_probe(tp, KERN_ERR "%s: invalid PCI region size(s).\n", + pci_name(pdev)); + goto err_pci_disable_2; + } + + rc = pci_request_regions(pdev, DRV_NAME); + if (rc < 0) { + net_probe(tp, KERN_ERR PFX "%s: could not request regions.\n", + pci_name(pdev)); + goto err_pci_disable_2; + } + + rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); + if (rc < 0) { + net_probe(tp, KERN_ERR "%s: DMA configuration failed.\n", + pci_name(pdev)); + goto err_free_res_3; + } + + pci_set_master(pdev); + + ioaddr = ioremap(pci_resource_start(pdev, 0), SIS190_REGS_SIZE); + if (!ioaddr) { + net_probe(tp, KERN_ERR "%s: cannot remap MMIO, aborting\n", + pci_name(pdev)); + rc = -EIO; + goto err_free_res_3; + } + + tp->pci_dev = pdev; + tp->mmio_addr = ioaddr; + + sis190_irq_mask_and_ack(ioaddr); + + sis190_soft_reset(ioaddr); +out: + return dev; + +err_free_res_3: + pci_release_regions(pdev); +err_pci_disable_2: + pci_disable_device(pdev); +err_free_dev_1: + free_netdev(dev); +err_out_0: + dev = ERR_PTR(rc); + goto out; +} + +static void sis190_tx_timeout(struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + u8 tmp8; + + /* Disable Tx, if not already */ + tmp8 = SIS_R8(TxControl); + if (tmp8 & CmdTxEnb) + SIS_W8(TxControl, tmp8 & ~CmdTxEnb); + + + net_tx_err(tp, KERN_INFO "%s: Transmit timeout, status %08x %08x.\n", + dev->name, SIS_R32(TxControl), SIS_R32(TxSts)); + + /* Disable interrupts by clearing the interrupt mask. */ + SIS_W32(IntrMask, 0x0000); + + /* Stop a shared interrupt from scavenging while we are. */ + spin_lock_irq(&tp->lock); + sis190_tx_clear(tp); + spin_unlock_irq(&tp->lock); + + /* ...and finally, reset everything. */ + sis190_hw_start(dev); + + netif_wake_queue(dev); +} + +static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev, + struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + u16 sig; + int i; + + net_probe(tp, KERN_INFO "%s: Read MAC address from EEPROM\n", + pci_name(pdev)); + + /* Check to see if there is a sane EEPROM */ + sig = (u16) sis190_read_eeprom(ioaddr, EEPROMSignature); + + if ((sig == 0xffff) || (sig == 0x0000)) { + net_probe(tp, KERN_INFO "%s: Error EEPROM read %x.\n", + pci_name(pdev), sig); + return -EIO; + } + + /* Get MAC address from EEPROM */ + for (i = 0; i < MAC_ADDR_LEN / 2; i++) { + __le16 w = sis190_read_eeprom(ioaddr, EEPROMMACAddr + i); + + ((u16 *)dev->dev_addr)[0] = le16_to_cpu(w); + } + + return 0; +} + +/** + * sis190_get_mac_addr_from_apc - Get MAC address for SiS965 model + * @pdev: PCI device + * @dev: network device to get address for + * + * SiS965 model, use APC CMOS RAM to store MAC address. + * APC CMOS RAM is accessed through ISA bridge. + * MAC address is read into @net_dev->dev_addr. + */ +static int __devinit sis190_get_mac_addr_from_apc(struct pci_dev *pdev, + struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + struct pci_dev *isa_bridge; + u8 reg, tmp8; + int i; + + net_probe(tp, KERN_INFO "%s: Read MAC address from APC.\n", + pci_name(pdev)); + + isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0965, NULL); + if (!isa_bridge) { + net_probe(tp, KERN_INFO "%s: Can not find ISA bridge.\n", + pci_name(pdev)); + return -EIO; + } + + /* Enable port 78h & 79h to access APC Registers. */ + pci_read_config_byte(isa_bridge, 0x48, &tmp8); + reg = (tmp8 & ~0x02); + pci_write_config_byte(isa_bridge, 0x48, reg); + udelay(50); + pci_read_config_byte(isa_bridge, 0x48, ®); + + for (i = 0; i < MAC_ADDR_LEN; i++) { + outb(0x9 + i, 0x78); + dev->dev_addr[i] = inb(0x79); + } + + outb(0x12, 0x78); + reg = inb(0x79); + + /* Restore the value to ISA Bridge */ + pci_write_config_byte(isa_bridge, 0x48, tmp8); + pci_dev_put(isa_bridge); + + return 0; +} + +/** + * sis190_init_rxfilter - Initialize the Rx filter + * @dev: network device to initialize + * + * Set receive filter address to our MAC address + * and enable packet filtering. + */ +static inline void sis190_init_rxfilter(struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + u16 ctl; + int i; + + ctl = SIS_R16(RxMacControl); + /* + * Disable packet filtering before setting filter. + * Note: SiS's driver writes 32 bits but RxMacControl is 16 bits + * only and followed by RxMacAddr (6 bytes). Strange. -- FR + */ + SIS_W16(RxMacControl, ctl & ~0x0f00); + + for (i = 0; i < MAC_ADDR_LEN; i++) + SIS_W8(RxMacAddr + i, dev->dev_addr[i]); + + SIS_W16(RxMacControl, ctl); + SIS_PCI_COMMIT(); +} + +static int sis190_get_mac_addr(struct pci_dev *pdev, struct net_device *dev) +{ + u8 from; + + pci_read_config_byte(pdev, 0x73, &from); + + return (from & 0x00000001) ? + sis190_get_mac_addr_from_apc(pdev, dev) : + sis190_get_mac_addr_from_eeprom(pdev, dev); +} + +static void sis190_set_speed_auto(struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + int phy_id = tp->mii_if.phy_id; + int val; + + net_link(tp, KERN_INFO "%s: Enabling Auto-negotiation.\n", dev->name); + + val = mdio_read(ioaddr, phy_id, MII_ADVERTISE); + + // Enable 10/100 Full/Half Mode, leave MII_ADVERTISE bit4:0 + // unchanged. + mdio_write(ioaddr, phy_id, MII_ADVERTISE, (val & ADVERTISE_SLCT) | + ADVERTISE_100FULL | ADVERTISE_10FULL | + ADVERTISE_100HALF | ADVERTISE_10HALF); + + // Enable 1000 Full Mode. + mdio_write(ioaddr, phy_id, MII_CTRL1000, ADVERTISE_1000FULL); + + // Enable auto-negotiation and restart auto-negotiation. + mdio_write(ioaddr, phy_id, MII_BMCR, + BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET); +} + +static int sis190_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct sis190_private *tp = netdev_priv(dev); + + return mii_ethtool_gset(&tp->mii_if, cmd); +} + +static int sis190_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct sis190_private *tp = netdev_priv(dev); + + return mii_ethtool_sset(&tp->mii_if, cmd); +} + +static void sis190_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct sis190_private *tp = netdev_priv(dev); + + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->bus_info, pci_name(tp->pci_dev)); +} + +static int sis190_get_regs_len(struct net_device *dev) +{ + return SIS190_REGS_SIZE; +} + +static void sis190_get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *p) +{ + struct sis190_private *tp = netdev_priv(dev); + unsigned long flags; + + if (regs->len > SIS190_REGS_SIZE) + regs->len = SIS190_REGS_SIZE; + + spin_lock_irqsave(&tp->lock, flags); + memcpy_fromio(p, tp->mmio_addr, regs->len); + spin_unlock_irqrestore(&tp->lock, flags); +} + +static int sis190_nway_reset(struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + + return mii_nway_restart(&tp->mii_if); +} + +static u32 sis190_get_msglevel(struct net_device *dev) +{ + struct sis190_private *tp = netdev_priv(dev); + + return tp->msg_enable; +} + +static void sis190_set_msglevel(struct net_device *dev, u32 value) +{ + struct sis190_private *tp = netdev_priv(dev); + + tp->msg_enable = value; +} + +static struct ethtool_ops sis190_ethtool_ops = { + .get_settings = sis190_get_settings, + .set_settings = sis190_set_settings, + .get_drvinfo = sis190_get_drvinfo, + .get_regs_len = sis190_get_regs_len, + .get_regs = sis190_get_regs, + .get_link = ethtool_op_get_link, + .get_msglevel = sis190_get_msglevel, + .set_msglevel = sis190_set_msglevel, + .nway_reset = sis190_nway_reset, +}; + +static int sis190_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct sis190_private *tp = netdev_priv(dev); + + return !netif_running(dev) ? -EINVAL : + generic_mii_ioctl(&tp->mii_if, if_mii(ifr), cmd, NULL); +} + +static int __devinit sis190_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + static int printed_version = 0; + struct sis190_private *tp; + struct net_device *dev; + void __iomem *ioaddr; + int rc; + + if (!printed_version) { + net_drv(&debug, KERN_INFO SIS190_DRIVER_NAME " loaded.\n"); + printed_version = 1; + } + + dev = sis190_init_board(pdev); + if (IS_ERR(dev)) { + rc = PTR_ERR(dev); + goto out; + } + + tp = netdev_priv(dev); + ioaddr = tp->mmio_addr; + + rc = sis190_get_mac_addr(pdev, dev); + if (rc < 0) + goto err_release_board; + + sis190_init_rxfilter(dev); + + INIT_WORK(&tp->phy_task, sis190_phy_task, dev); + + dev->open = sis190_open; + dev->stop = sis190_close; + dev->do_ioctl = sis190_ioctl; + dev->get_stats = sis190_get_stats; + dev->tx_timeout = sis190_tx_timeout; + dev->watchdog_timeo = SIS190_TX_TIMEOUT; + dev->hard_start_xmit = sis190_start_xmit; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = sis190_netpoll; +#endif + dev->set_multicast_list = sis190_set_rx_mode; + SET_ETHTOOL_OPS(dev, &sis190_ethtool_ops); + dev->irq = pdev->irq; + dev->base_addr = (unsigned long) 0xdead; + + spin_lock_init(&tp->lock); + + rc = sis190_mii_probe(dev); + if (rc < 0) + goto err_release_board; + + rc = register_netdev(dev); + if (rc < 0) + goto err_remove_mii; + + pci_set_drvdata(pdev, dev); + + net_probe(tp, KERN_INFO "%s: %s at %p (IRQ: %d), " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", + pci_name(pdev), sis_chip_info[ent->driver_data].name, + ioaddr, dev->irq, + dev->dev_addr[0], dev->dev_addr[1], + dev->dev_addr[2], dev->dev_addr[3], + dev->dev_addr[4], dev->dev_addr[5]); + + netif_carrier_off(dev); + + sis190_set_speed_auto(dev); +out: + return rc; + +err_remove_mii: + sis190_mii_remove(dev); +err_release_board: + sis190_release_board(pdev); + goto out; +} + +static void __devexit sis190_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + sis190_mii_remove(dev); + unregister_netdev(dev); + sis190_release_board(pdev); + pci_set_drvdata(pdev, NULL); +} + +static struct pci_driver sis190_pci_driver = { + .name = DRV_NAME, + .id_table = sis190_pci_tbl, + .probe = sis190_init_one, + .remove = __devexit_p(sis190_remove_one), +}; + +static int __init sis190_init_module(void) +{ + return pci_module_init(&sis190_pci_driver); +} + +static void __exit sis190_cleanup_module(void) +{ + pci_unregister_driver(&sis190_pci_driver); +} + +module_init(sis190_init_module); +module_exit(sis190_cleanup_module); diff --git a/drivers/net/skge.c b/drivers/net/skge.c index f15739481d6..d7c98515fdf 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -42,7 +42,7 @@ #include "skge.h" #define DRV_NAME "skge" -#define DRV_VERSION "0.8" +#define DRV_VERSION "0.9" #define PFX DRV_NAME " " #define DEFAULT_TX_RING_SIZE 128 @@ -79,8 +79,8 @@ static const struct pci_device_id skge_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4320) }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5005) }, /* Belkin */ { PCI_DEVICE(PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD) }, - { PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1032) }, { PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1064) }, + { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0015, }, { 0 } }; MODULE_DEVICE_TABLE(pci, skge_id_table); @@ -189,7 +189,7 @@ static u32 skge_supported_modes(const struct skge_hw *hw) { u32 supported; - if (iscopper(hw)) { + if (hw->copper) { supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half @@ -222,7 +222,7 @@ static int skge_get_settings(struct net_device *dev, ecmd->transceiver = XCVR_INTERNAL; ecmd->supported = skge_supported_modes(hw); - if (iscopper(hw)) { + if (hw->copper) { ecmd->port = PORT_TP; ecmd->phy_address = hw->phy_addr; } else @@ -876,6 +876,9 @@ static int skge_rx_fill(struct skge_port *skge) static void skge_link_up(struct skge_port *skge) { + skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), + LED_BLK_OFF|LED_SYNC_OFF|LED_ON); + netif_carrier_on(skge->netdev); if (skge->tx_avail > MAX_SKB_FRAGS + 1) netif_wake_queue(skge->netdev); @@ -894,6 +897,7 @@ static void skge_link_up(struct skge_port *skge) static void skge_link_down(struct skge_port *skge) { + skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF); netif_carrier_off(skge->netdev); netif_stop_queue(skge->netdev); @@ -1599,7 +1603,7 @@ static void yukon_init(struct skge_hw *hw, int port) adv = PHY_AN_CSMA; if (skge->autoneg == AUTONEG_ENABLE) { - if (iscopper(hw)) { + if (hw->copper) { if (skge->advertising & ADVERTISED_1000baseT_Full) ct1000 |= PHY_M_1000C_AFD; if (skge->advertising & ADVERTISED_1000baseT_Half) @@ -1691,7 +1695,7 @@ static void yukon_mac_init(struct skge_hw *hw, int port) /* Set hardware config mode */ reg = GPC_INT_POL_HI | GPC_DIS_FC | GPC_DIS_SLEEP | GPC_ENA_XC | GPC_ANEG_ADV_ALL_M | GPC_ENA_PAUSE; - reg |= iscopper(hw) ? GPC_HWCFG_GMII_COP : GPC_HWCFG_GMII_FIB; + reg |= hw->copper ? GPC_HWCFG_GMII_COP : GPC_HWCFG_GMII_FIB; /* Clear GMC reset */ skge_write32(hw, SK_REG(port, GPHY_CTRL), reg | GPC_RST_SET); @@ -1780,7 +1784,12 @@ static void yukon_mac_init(struct skge_hw *hw, int port) reg &= ~GMF_RX_F_FL_ON; skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR); skge_write16(hw, SK_REG(port, RX_GMF_CTRL_T), reg); - skge_write16(hw, SK_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF); + /* + * because Pause Packet Truncation in GMAC is not working + * we have to increase the Flush Threshold to 64 bytes + * in order to flush pause packets in Rx FIFO on Yukon-1 + */ + skge_write16(hw, SK_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF+1); /* Configure Tx MAC FIFO */ skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR); @@ -2670,18 +2679,6 @@ static void skge_error_irq(struct skge_hw *hw) /* Timestamp (unused) overflow */ if (hwstatus & IS_IRQ_TIST_OV) skge_write8(hw, GMAC_TI_ST_CTRL, GMT_ST_CLR_IRQ); - - if (hwstatus & IS_IRQ_SENSOR) { - /* no sensors on 32-bit Yukon */ - if (!(skge_read16(hw, B0_CTST) & CS_BUS_SLOT_SZ)) { - printk(KERN_ERR PFX "ignoring bogus sensor interrups\n"); - skge_write32(hw, B0_HWE_IMSK, - IS_ERR_MSK & ~IS_IRQ_SENSOR); - } else - printk(KERN_WARNING PFX "sensor interrupt\n"); - } - - } if (hwstatus & IS_RAM_RD_PAR) { @@ -2712,9 +2709,10 @@ static void skge_error_irq(struct skge_hw *hw) skge_pci_clear(hw); + /* if error still set then just ignore it */ hwstatus = skge_read32(hw, B0_HWE_ISRC); if (hwstatus & IS_IRQ_STAT) { - printk(KERN_WARNING PFX "IRQ status %x: still set ignoring hardware errors\n", + pr_debug("IRQ status %x: still set ignoring hardware errors\n", hwstatus); hw->intr_mask &= ~IS_HW_ERR; } @@ -2876,7 +2874,7 @@ static const char *skge_board_name(const struct skge_hw *hw) static int skge_reset(struct skge_hw *hw) { u16 ctst; - u8 t8, mac_cfg; + u8 t8, mac_cfg, pmd_type, phy_type; int i; ctst = skge_read16(hw, B0_CTST); @@ -2895,18 +2893,19 @@ static int skge_reset(struct skge_hw *hw) ctst & (CS_CLK_RUN_HOT|CS_CLK_RUN_RST|CS_CLK_RUN_ENA)); hw->chip_id = skge_read8(hw, B2_CHIP_ID); - hw->phy_type = skge_read8(hw, B2_E_1) & 0xf; - hw->pmd_type = skge_read8(hw, B2_PMD_TYP); + phy_type = skge_read8(hw, B2_E_1) & 0xf; + pmd_type = skge_read8(hw, B2_PMD_TYP); + hw->copper = (pmd_type == 'T' || pmd_type == '1'); switch (hw->chip_id) { case CHIP_ID_GENESIS: - switch (hw->phy_type) { + switch (phy_type) { case SK_PHY_BCOM: hw->phy_addr = PHY_ADDR_BCOM; break; default: printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n", - pci_name(hw->pdev), hw->phy_type); + pci_name(hw->pdev), phy_type); return -EOPNOTSUPP; } break; @@ -2914,13 +2913,10 @@ static int skge_reset(struct skge_hw *hw) case CHIP_ID_YUKON: case CHIP_ID_YUKON_LITE: case CHIP_ID_YUKON_LP: - if (hw->phy_type < SK_PHY_MARV_COPPER && hw->pmd_type != 'S') - hw->phy_type = SK_PHY_MARV_COPPER; + if (phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S') + hw->copper = 1; hw->phy_addr = PHY_ADDR_MARV; - if (!iscopper(hw)) - hw->phy_type = SK_PHY_MARV_FIBER; - break; default: @@ -2948,12 +2944,20 @@ static int skge_reset(struct skge_hw *hw) else hw->ram_size = t8 * 4096; + hw->intr_mask = IS_HW_ERR | IS_EXT_REG; if (hw->chip_id == CHIP_ID_GENESIS) genesis_init(hw); else { /* switch power to VCC (WA for VAUX problem) */ skge_write8(hw, B0_POWER_CTRL, PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON); + /* avoid boards with stuck Hardware error bits */ + if ((skge_read32(hw, B0_ISRC) & IS_HW_ERR) && + (skge_read32(hw, B0_HWE_ISRC) & IS_IRQ_SENSOR)) { + printk(KERN_WARNING PFX "stuck hardware sensor bit\n"); + hw->intr_mask &= ~IS_HW_ERR; + } + for (i = 0; i < hw->ports; i++) { skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET); skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR); @@ -2994,7 +2998,6 @@ static int skge_reset(struct skge_hw *hw) skge_write32(hw, B2_IRQM_INI, skge_usecs2clk(hw, 100)); skge_write32(hw, B2_IRQM_CTRL, TIM_START); - hw->intr_mask = IS_HW_ERR | IS_EXT_REG; skge_write32(hw, B0_IMSK, hw->intr_mask); if (hw->chip_id != CHIP_ID_GENESIS) diff --git a/drivers/net/skge.h b/drivers/net/skge.h index b432f1bb816..f1680beb8e6 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -214,8 +214,6 @@ enum { /* B2_IRQM_HWE_MSK 32 bit IRQ Moderation HW Error Mask */ enum { - IS_ERR_MSK = 0x00003fff,/* All Error bits */ - IS_IRQ_TIST_OV = 1<<13, /* Time Stamp Timer Overflow (YUKON only) */ IS_IRQ_SENSOR = 1<<12, /* IRQ from Sensor (YUKON only) */ IS_IRQ_MST_ERR = 1<<11, /* IRQ master error detected */ @@ -230,6 +228,12 @@ enum { IS_M2_PAR_ERR = 1<<2, /* MAC 2 Parity Error */ IS_R1_PAR_ERR = 1<<1, /* Queue R1 Parity Error */ IS_R2_PAR_ERR = 1<<0, /* Queue R2 Parity Error */ + + IS_ERR_MSK = IS_IRQ_MST_ERR | IS_IRQ_STAT + | IS_NO_STAT_M1 | IS_NO_STAT_M2 + | IS_RAM_RD_PAR | IS_RAM_WR_PAR + | IS_M1_PAR_ERR | IS_M2_PAR_ERR + | IS_R1_PAR_ERR | IS_R2_PAR_ERR, }; /* B2_TST_CTRL1 8 bit Test Control Register 1 */ @@ -2456,24 +2460,17 @@ struct skge_hw { u8 chip_id; u8 chip_rev; - u8 phy_type; - u8 pmd_type; - u16 phy_addr; + u8 copper; u8 ports; u32 ram_size; u32 ram_offset; + u16 phy_addr; struct tasklet_struct ext_tasklet; spinlock_t phy_lock; }; - -static inline int iscopper(const struct skge_hw *hw) -{ - return (hw->pmd_type == 'T'); -} - enum { FLOW_MODE_NONE = 0, /* No Flow-Control */ FLOW_MODE_LOC_SEND = 1, /* Local station sends PAUSE */ diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index 6d9dae60a69..ba8593ac3f8 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -68,6 +68,7 @@ static const char version[] = #include <linux/etherdevice.h> #include <asm/io.h> +#include <asm/irq.h> #include <asm/system.h> #include "8390.h" diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c index cdc9cc873e0..90b818a8de6 100644 --- a/drivers/net/sonic.c +++ b/drivers/net/sonic.c @@ -1,6 +1,11 @@ /* * sonic.c * + * (C) 2005 Finn Thain + * + * Converted to DMA API, added zero-copy buffer handling, and + * (from the mac68k project) introduced dhd's support for 16-bit cards. + * * (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de) * * This driver is based on work from Andreas Busse, but most of @@ -9,12 +14,23 @@ * (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de) * * Core code included by system sonic drivers + * + * And... partially rewritten again by David Huggins-Daines in order + * to cope with screwed up Macintosh NICs that may or may not use + * 16-bit DMA. + * + * (C) 1999 David Huggins-Daines <dhd@debian.org> + * */ /* * Sources: Olivetti M700-10 Risc Personal Computer hardware handbook, * National Semiconductors data sheet for the DP83932B Sonic Ethernet * controller, and the files "8390.c" and "skeleton.c" in this directory. + * + * Additional sources: Nat Semi data sheet for the DP83932C and Nat Semi + * Application Note AN-746, the files "lance.c" and "ibmlana.c". See also + * the NetBSD file "sys/arch/mac68k/dev/if_sn.c". */ @@ -28,6 +44,9 @@ */ static int sonic_open(struct net_device *dev) { + struct sonic_local *lp = netdev_priv(dev); + int i; + if (sonic_debug > 2) printk("sonic_open: initializing sonic driver.\n"); @@ -40,14 +59,59 @@ static int sonic_open(struct net_device *dev) * This means that during execution of the handler interrupt are disabled * covering another bug otherwise corrupting data. This doesn't mean * this glue works ok under all situations. + * + * Note (dhd): this also appears to prevent lockups on the Macintrash + * when more than one Ethernet card is installed (knock on wood) + * + * Note (fthain): whether the above is still true is anyones guess. Certainly + * the buffer handling algorithms will not tolerate re-entrance without some + * mutual exclusion added. Anyway, the memcpy has now been eliminated from the + * rx code to make this a faster "fast interrupt". */ -// if (sonic_request_irq(dev->irq, &sonic_interrupt, 0, "sonic", dev)) { - if (sonic_request_irq(dev->irq, &sonic_interrupt, SA_INTERRUPT, - "sonic", dev)) { - printk("\n%s: unable to get IRQ %d .\n", dev->name, dev->irq); + if (request_irq(dev->irq, &sonic_interrupt, SONIC_IRQ_FLAG, "sonic", dev)) { + printk(KERN_ERR "\n%s: unable to get IRQ %d .\n", dev->name, dev->irq); return -EAGAIN; } + for (i = 0; i < SONIC_NUM_RRS; i++) { + struct sk_buff *skb = dev_alloc_skb(SONIC_RBSIZE + 2); + if (skb == NULL) { + while(i > 0) { /* free any that were allocated successfully */ + i--; + dev_kfree_skb(lp->rx_skb[i]); + lp->rx_skb[i] = NULL; + } + printk(KERN_ERR "%s: couldn't allocate receive buffers\n", + dev->name); + return -ENOMEM; + } + skb->dev = dev; + /* align IP header unless DMA requires otherwise */ + if (SONIC_BUS_SCALE(lp->dma_bitmode) == 2) + skb_reserve(skb, 2); + lp->rx_skb[i] = skb; + } + + for (i = 0; i < SONIC_NUM_RRS; i++) { + dma_addr_t laddr = dma_map_single(lp->device, skb_put(lp->rx_skb[i], SONIC_RBSIZE), + SONIC_RBSIZE, DMA_FROM_DEVICE); + if (!laddr) { + while(i > 0) { /* free any that were mapped successfully */ + i--; + dma_unmap_single(lp->device, lp->rx_laddr[i], SONIC_RBSIZE, DMA_FROM_DEVICE); + lp->rx_laddr[i] = (dma_addr_t)0; + } + for (i = 0; i < SONIC_NUM_RRS; i++) { + dev_kfree_skb(lp->rx_skb[i]); + lp->rx_skb[i] = NULL; + } + printk(KERN_ERR "%s: couldn't map rx DMA buffers\n", + dev->name); + return -ENOMEM; + } + lp->rx_laddr[i] = laddr; + } + /* * Initialize the SONIC */ @@ -67,7 +131,8 @@ static int sonic_open(struct net_device *dev) */ static int sonic_close(struct net_device *dev) { - unsigned int base_addr = dev->base_addr; + struct sonic_local *lp = netdev_priv(dev); + int i; if (sonic_debug > 2) printk("sonic_close\n"); @@ -77,20 +142,56 @@ static int sonic_close(struct net_device *dev) /* * stop the SONIC, disable interrupts */ - SONIC_WRITE(SONIC_ISR, 0x7fff); SONIC_WRITE(SONIC_IMR, 0); + SONIC_WRITE(SONIC_ISR, 0x7fff); SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); - sonic_free_irq(dev->irq, dev); /* release the IRQ */ + /* unmap and free skbs that haven't been transmitted */ + for (i = 0; i < SONIC_NUM_TDS; i++) { + if(lp->tx_laddr[i]) { + dma_unmap_single(lp->device, lp->tx_laddr[i], lp->tx_len[i], DMA_TO_DEVICE); + lp->tx_laddr[i] = (dma_addr_t)0; + } + if(lp->tx_skb[i]) { + dev_kfree_skb(lp->tx_skb[i]); + lp->tx_skb[i] = NULL; + } + } + + /* unmap and free the receive buffers */ + for (i = 0; i < SONIC_NUM_RRS; i++) { + if(lp->rx_laddr[i]) { + dma_unmap_single(lp->device, lp->rx_laddr[i], SONIC_RBSIZE, DMA_FROM_DEVICE); + lp->rx_laddr[i] = (dma_addr_t)0; + } + if(lp->rx_skb[i]) { + dev_kfree_skb(lp->rx_skb[i]); + lp->rx_skb[i] = NULL; + } + } + + free_irq(dev->irq, dev); /* release the IRQ */ return 0; } static void sonic_tx_timeout(struct net_device *dev) { - struct sonic_local *lp = (struct sonic_local *) dev->priv; - printk("%s: transmit timed out.\n", dev->name); - + struct sonic_local *lp = netdev_priv(dev); + int i; + /* Stop the interrupts for this */ + SONIC_WRITE(SONIC_IMR, 0); + /* We could resend the original skbs. Easier to re-initialise. */ + for (i = 0; i < SONIC_NUM_TDS; i++) { + if(lp->tx_laddr[i]) { + dma_unmap_single(lp->device, lp->tx_laddr[i], lp->tx_len[i], DMA_TO_DEVICE); + lp->tx_laddr[i] = (dma_addr_t)0; + } + if(lp->tx_skb[i]) { + dev_kfree_skb(lp->tx_skb[i]); + lp->tx_skb[i] = NULL; + } + } /* Try to restart the adaptor. */ sonic_init(dev); lp->stats.tx_errors++; @@ -100,60 +201,92 @@ static void sonic_tx_timeout(struct net_device *dev) /* * transmit packet + * + * Appends new TD during transmission thus avoiding any TX interrupts + * until we run out of TDs. + * This routine interacts closely with the ISR in that it may, + * set tx_skb[i] + * reset the status flags of the new TD + * set and reset EOL flags + * stop the tx queue + * The ISR interacts with this routine in various ways. It may, + * reset tx_skb[i] + * test the EOL and status flags of the TDs + * wake the tx queue + * Concurrently with all of this, the SONIC is potentially writing to + * the status flags of the TDs. + * Until some mutual exclusion is added, this code will not work with SMP. However, + * MIPS Jazz machines and m68k Macs were all uni-processor machines. */ + static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct sonic_local *lp = (struct sonic_local *) dev->priv; - unsigned int base_addr = dev->base_addr; - unsigned int laddr; - int entry, length; - - netif_stop_queue(dev); + struct sonic_local *lp = netdev_priv(dev); + dma_addr_t laddr; + int length; + int entry = lp->next_tx; if (sonic_debug > 2) printk("sonic_send_packet: skb=%p, dev=%p\n", skb, dev); + length = skb->len; + if (length < ETH_ZLEN) { + skb = skb_padto(skb, ETH_ZLEN); + if (skb == NULL) + return 0; + length = ETH_ZLEN; + } + /* * Map the packet data into the logical DMA address space */ - if ((laddr = vdma_alloc(CPHYSADDR(skb->data), skb->len)) == ~0UL) { - printk("%s: no VDMA entry for transmit available.\n", - dev->name); + + laddr = dma_map_single(lp->device, skb->data, length, DMA_TO_DEVICE); + if (!laddr) { + printk(KERN_ERR "%s: failed to map tx DMA buffer.\n", dev->name); dev_kfree_skb(skb); - netif_start_queue(dev); return 1; } - entry = lp->cur_tx & SONIC_TDS_MASK; + + sonic_tda_put(dev, entry, SONIC_TD_STATUS, 0); /* clear status */ + sonic_tda_put(dev, entry, SONIC_TD_FRAG_COUNT, 1); /* single fragment */ + sonic_tda_put(dev, entry, SONIC_TD_PKTSIZE, length); /* length of packet */ + sonic_tda_put(dev, entry, SONIC_TD_FRAG_PTR_L, laddr & 0xffff); + sonic_tda_put(dev, entry, SONIC_TD_FRAG_PTR_H, laddr >> 16); + sonic_tda_put(dev, entry, SONIC_TD_FRAG_SIZE, length); + sonic_tda_put(dev, entry, SONIC_TD_LINK, + sonic_tda_get(dev, entry, SONIC_TD_LINK) | SONIC_EOL); + + /* + * Must set tx_skb[entry] only after clearing status, and + * before clearing EOL and before stopping queue + */ + wmb(); + lp->tx_len[entry] = length; lp->tx_laddr[entry] = laddr; lp->tx_skb[entry] = skb; - length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; - flush_cache_all(); + wmb(); + sonic_tda_put(dev, lp->eol_tx, SONIC_TD_LINK, + sonic_tda_get(dev, lp->eol_tx, SONIC_TD_LINK) & ~SONIC_EOL); + lp->eol_tx = entry; - /* - * Setup the transmit descriptor and issue the transmit command. - */ - lp->tda[entry].tx_status = 0; /* clear status */ - lp->tda[entry].tx_frag_count = 1; /* single fragment */ - lp->tda[entry].tx_pktsize = length; /* length of packet */ - lp->tda[entry].tx_frag_ptr_l = laddr & 0xffff; - lp->tda[entry].tx_frag_ptr_h = laddr >> 16; - lp->tda[entry].tx_frag_size = length; - lp->cur_tx++; - lp->stats.tx_bytes += length; + lp->next_tx = (entry + 1) & SONIC_TDS_MASK; + if (lp->tx_skb[lp->next_tx] != NULL) { + /* The ring is full, the ISR has yet to process the next TD. */ + if (sonic_debug > 3) + printk("%s: stopping queue\n", dev->name); + netif_stop_queue(dev); + /* after this packet, wait for ISR to free up some TDAs */ + } else netif_start_queue(dev); if (sonic_debug > 2) - printk("sonic_send_packet: issueing Tx command\n"); + printk("sonic_send_packet: issuing Tx command\n"); SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP); dev->trans_start = jiffies; - if (lp->cur_tx < lp->dirty_tx + SONIC_NUM_TDS) - netif_start_queue(dev); - else - lp->tx_full = 1; - return 0; } @@ -164,175 +297,199 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev) static irqreturn_t sonic_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) dev_id; - unsigned int base_addr = dev->base_addr; - struct sonic_local *lp; + struct sonic_local *lp = netdev_priv(dev); int status; if (dev == NULL) { - printk("sonic_interrupt: irq %d for unknown device.\n", irq); + printk(KERN_ERR "sonic_interrupt: irq %d for unknown device.\n", irq); return IRQ_NONE; } - lp = (struct sonic_local *) dev->priv; - - status = SONIC_READ(SONIC_ISR); - SONIC_WRITE(SONIC_ISR, 0x7fff); /* clear all bits */ - - if (sonic_debug > 2) - printk("sonic_interrupt: ISR=%x\n", status); - - if (status & SONIC_INT_PKTRX) { - sonic_rx(dev); /* got packet(s) */ - } - - if (status & SONIC_INT_TXDN) { - int dirty_tx = lp->dirty_tx; - - while (dirty_tx < lp->cur_tx) { - int entry = dirty_tx & SONIC_TDS_MASK; - int status = lp->tda[entry].tx_status; + if (!(status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT)) + return IRQ_NONE; - if (sonic_debug > 3) - printk - ("sonic_interrupt: status %d, cur_tx %d, dirty_tx %d\n", - status, lp->cur_tx, lp->dirty_tx); + do { + if (status & SONIC_INT_PKTRX) { + if (sonic_debug > 2) + printk("%s: packet rx\n", dev->name); + sonic_rx(dev); /* got packet(s) */ + SONIC_WRITE(SONIC_ISR, SONIC_INT_PKTRX); /* clear the interrupt */ + } - if (status == 0) { - /* It still hasn't been Txed, kick the sonic again */ - SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP); - break; - } + if (status & SONIC_INT_TXDN) { + int entry = lp->cur_tx; + int td_status; + int freed_some = 0; - /* put back EOL and free descriptor */ - lp->tda[entry].tx_frag_count = 0; - lp->tda[entry].tx_status = 0; - - if (status & 0x0001) - lp->stats.tx_packets++; - else { - lp->stats.tx_errors++; - if (status & 0x0642) - lp->stats.tx_aborted_errors++; - if (status & 0x0180) - lp->stats.tx_carrier_errors++; - if (status & 0x0020) - lp->stats.tx_window_errors++; - if (status & 0x0004) - lp->stats.tx_fifo_errors++; - } + /* At this point, cur_tx is the index of a TD that is one of: + * unallocated/freed (status set & tx_skb[entry] clear) + * allocated and sent (status set & tx_skb[entry] set ) + * allocated and not yet sent (status clear & tx_skb[entry] set ) + * still being allocated by sonic_send_packet (status clear & tx_skb[entry] clear) + */ - /* We must free the original skb */ - if (lp->tx_skb[entry]) { + if (sonic_debug > 2) + printk("%s: tx done\n", dev->name); + + while (lp->tx_skb[entry] != NULL) { + if ((td_status = sonic_tda_get(dev, entry, SONIC_TD_STATUS)) == 0) + break; + + if (td_status & 0x0001) { + lp->stats.tx_packets++; + lp->stats.tx_bytes += sonic_tda_get(dev, entry, SONIC_TD_PKTSIZE); + } else { + lp->stats.tx_errors++; + if (td_status & 0x0642) + lp->stats.tx_aborted_errors++; + if (td_status & 0x0180) + lp->stats.tx_carrier_errors++; + if (td_status & 0x0020) + lp->stats.tx_window_errors++; + if (td_status & 0x0004) + lp->stats.tx_fifo_errors++; + } + + /* We must free the original skb */ dev_kfree_skb_irq(lp->tx_skb[entry]); - lp->tx_skb[entry] = 0; + lp->tx_skb[entry] = NULL; + /* and unmap DMA buffer */ + dma_unmap_single(lp->device, lp->tx_laddr[entry], lp->tx_len[entry], DMA_TO_DEVICE); + lp->tx_laddr[entry] = (dma_addr_t)0; + freed_some = 1; + + if (sonic_tda_get(dev, entry, SONIC_TD_LINK) & SONIC_EOL) { + entry = (entry + 1) & SONIC_TDS_MASK; + break; + } + entry = (entry + 1) & SONIC_TDS_MASK; } - /* and the VDMA address */ - vdma_free(lp->tx_laddr[entry]); - dirty_tx++; - } - if (lp->tx_full - && dirty_tx + SONIC_NUM_TDS > lp->cur_tx + 2) { - /* The ring is no longer full, clear tbusy. */ - lp->tx_full = 0; - netif_wake_queue(dev); + if (freed_some || lp->tx_skb[entry] == NULL) + netif_wake_queue(dev); /* The ring is no longer full */ + lp->cur_tx = entry; + SONIC_WRITE(SONIC_ISR, SONIC_INT_TXDN); /* clear the interrupt */ } - lp->dirty_tx = dirty_tx; - } + /* + * check error conditions + */ + if (status & SONIC_INT_RFO) { + if (sonic_debug > 1) + printk("%s: rx fifo overrun\n", dev->name); + lp->stats.rx_fifo_errors++; + SONIC_WRITE(SONIC_ISR, SONIC_INT_RFO); /* clear the interrupt */ + } + if (status & SONIC_INT_RDE) { + if (sonic_debug > 1) + printk("%s: rx descriptors exhausted\n", dev->name); + lp->stats.rx_dropped++; + SONIC_WRITE(SONIC_ISR, SONIC_INT_RDE); /* clear the interrupt */ + } + if (status & SONIC_INT_RBAE) { + if (sonic_debug > 1) + printk("%s: rx buffer area exceeded\n", dev->name); + lp->stats.rx_dropped++; + SONIC_WRITE(SONIC_ISR, SONIC_INT_RBAE); /* clear the interrupt */ + } - /* - * check error conditions - */ - if (status & SONIC_INT_RFO) { - printk("%s: receive fifo underrun\n", dev->name); - lp->stats.rx_fifo_errors++; - } - if (status & SONIC_INT_RDE) { - printk("%s: receive descriptors exhausted\n", dev->name); - lp->stats.rx_dropped++; - } - if (status & SONIC_INT_RBE) { - printk("%s: receive buffer exhausted\n", dev->name); - lp->stats.rx_dropped++; - } - if (status & SONIC_INT_RBAE) { - printk("%s: receive buffer area exhausted\n", dev->name); - lp->stats.rx_dropped++; - } + /* counter overruns; all counters are 16bit wide */ + if (status & SONIC_INT_FAE) { + lp->stats.rx_frame_errors += 65536; + SONIC_WRITE(SONIC_ISR, SONIC_INT_FAE); /* clear the interrupt */ + } + if (status & SONIC_INT_CRC) { + lp->stats.rx_crc_errors += 65536; + SONIC_WRITE(SONIC_ISR, SONIC_INT_CRC); /* clear the interrupt */ + } + if (status & SONIC_INT_MP) { + lp->stats.rx_missed_errors += 65536; + SONIC_WRITE(SONIC_ISR, SONIC_INT_MP); /* clear the interrupt */ + } - /* counter overruns; all counters are 16bit wide */ - if (status & SONIC_INT_FAE) - lp->stats.rx_frame_errors += 65536; - if (status & SONIC_INT_CRC) - lp->stats.rx_crc_errors += 65536; - if (status & SONIC_INT_MP) - lp->stats.rx_missed_errors += 65536; + /* transmit error */ + if (status & SONIC_INT_TXER) { + if ((SONIC_READ(SONIC_TCR) & SONIC_TCR_FU) && (sonic_debug > 2)) + printk(KERN_ERR "%s: tx fifo underrun\n", dev->name); + SONIC_WRITE(SONIC_ISR, SONIC_INT_TXER); /* clear the interrupt */ + } - /* transmit error */ - if (status & SONIC_INT_TXER) - lp->stats.tx_errors++; + /* bus retry */ + if (status & SONIC_INT_BR) { + printk(KERN_ERR "%s: Bus retry occurred! Device interrupt disabled.\n", + dev->name); + /* ... to help debug DMA problems causing endless interrupts. */ + /* Bounce the eth interface to turn on the interrupt again. */ + SONIC_WRITE(SONIC_IMR, 0); + SONIC_WRITE(SONIC_ISR, SONIC_INT_BR); /* clear the interrupt */ + } - /* - * clear interrupt bits and return - */ - SONIC_WRITE(SONIC_ISR, status); + /* load CAM done */ + if (status & SONIC_INT_LCD) + SONIC_WRITE(SONIC_ISR, SONIC_INT_LCD); /* clear the interrupt */ + } while((status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT)); return IRQ_HANDLED; } /* - * We have a good packet(s), get it/them out of the buffers. + * We have a good packet(s), pass it/them up the network stack. */ static void sonic_rx(struct net_device *dev) { - unsigned int base_addr = dev->base_addr; - struct sonic_local *lp = (struct sonic_local *) dev->priv; - sonic_rd_t *rd = &lp->rda[lp->cur_rx & SONIC_RDS_MASK]; + struct sonic_local *lp = netdev_priv(dev); int status; - - while (rd->in_use == 0) { - struct sk_buff *skb; + int entry = lp->cur_rx; + + while (sonic_rda_get(dev, entry, SONIC_RD_IN_USE) == 0) { + struct sk_buff *used_skb; + struct sk_buff *new_skb; + dma_addr_t new_laddr; + u16 bufadr_l; + u16 bufadr_h; int pkt_len; - unsigned char *pkt_ptr; - status = rd->rx_status; - if (sonic_debug > 3) - printk("status %x, cur_rx %d, cur_rra %x\n", - status, lp->cur_rx, lp->cur_rra); + status = sonic_rda_get(dev, entry, SONIC_RD_STATUS); if (status & SONIC_RCR_PRX) { - pkt_len = rd->rx_pktlen; - pkt_ptr = - (char *) - sonic_chiptomem((rd->rx_pktptr_h << 16) + - rd->rx_pktptr_l); - - if (sonic_debug > 3) - printk - ("pktptr %p (rba %p) h:%x l:%x, bsize h:%x l:%x\n", - pkt_ptr, lp->rba, rd->rx_pktptr_h, - rd->rx_pktptr_l, - SONIC_READ(SONIC_RBWC1), - SONIC_READ(SONIC_RBWC0)); - /* Malloc up new buffer. */ - skb = dev_alloc_skb(pkt_len + 2); - if (skb == NULL) { - printk - ("%s: Memory squeeze, dropping packet.\n", - dev->name); + new_skb = dev_alloc_skb(SONIC_RBSIZE + 2); + if (new_skb == NULL) { + printk(KERN_ERR "%s: Memory squeeze, dropping packet.\n", dev->name); + lp->stats.rx_dropped++; + break; + } + new_skb->dev = dev; + /* provide 16 byte IP header alignment unless DMA requires otherwise */ + if(SONIC_BUS_SCALE(lp->dma_bitmode) == 2) + skb_reserve(new_skb, 2); + + new_laddr = dma_map_single(lp->device, skb_put(new_skb, SONIC_RBSIZE), + SONIC_RBSIZE, DMA_FROM_DEVICE); + if (!new_laddr) { + dev_kfree_skb(new_skb); + printk(KERN_ERR "%s: Failed to map rx buffer, dropping packet.\n", dev->name); lp->stats.rx_dropped++; break; } - skb->dev = dev; - skb_reserve(skb, 2); /* 16 byte align */ - skb_put(skb, pkt_len); /* Make room */ - eth_copy_and_sum(skb, pkt_ptr, pkt_len, 0); - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); /* pass the packet to upper layers */ + + /* now we have a new skb to replace it, pass the used one up the stack */ + dma_unmap_single(lp->device, lp->rx_laddr[entry], SONIC_RBSIZE, DMA_FROM_DEVICE); + used_skb = lp->rx_skb[entry]; + pkt_len = sonic_rda_get(dev, entry, SONIC_RD_PKTLEN); + skb_trim(used_skb, pkt_len); + used_skb->protocol = eth_type_trans(used_skb, dev); + netif_rx(used_skb); dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; + /* and insert the new skb */ + lp->rx_laddr[entry] = new_laddr; + lp->rx_skb[entry] = new_skb; + + bufadr_l = (unsigned long)new_laddr & 0xffff; + bufadr_h = (unsigned long)new_laddr >> 16; + sonic_rra_put(dev, entry, SONIC_RR_BUFADR_L, bufadr_l); + sonic_rra_put(dev, entry, SONIC_RR_BUFADR_H, bufadr_h); } else { /* This should only happen, if we enable accepting broken packets. */ lp->stats.rx_errors++; @@ -341,29 +498,35 @@ static void sonic_rx(struct net_device *dev) if (status & SONIC_RCR_CRCR) lp->stats.rx_crc_errors++; } - - rd->in_use = 1; - rd = &lp->rda[(++lp->cur_rx) & SONIC_RDS_MASK]; - /* now give back the buffer to the receive buffer area */ if (status & SONIC_RCR_LPKT) { /* - * this was the last packet out of the current receice buffer + * this was the last packet out of the current receive buffer * give the buffer back to the SONIC */ - lp->cur_rra += sizeof(sonic_rr_t); - if (lp->cur_rra > - (lp->rra_laddr + - (SONIC_NUM_RRS - - 1) * sizeof(sonic_rr_t))) lp->cur_rra = - lp->rra_laddr; - SONIC_WRITE(SONIC_RWP, lp->cur_rra & 0xffff); + lp->cur_rwp += SIZEOF_SONIC_RR * SONIC_BUS_SCALE(lp->dma_bitmode); + if (lp->cur_rwp >= lp->rra_end) lp->cur_rwp = lp->rra_laddr & 0xffff; + SONIC_WRITE(SONIC_RWP, lp->cur_rwp); + if (SONIC_READ(SONIC_ISR) & SONIC_INT_RBE) { + if (sonic_debug > 2) + printk("%s: rx buffer exhausted\n", dev->name); + SONIC_WRITE(SONIC_ISR, SONIC_INT_RBE); /* clear the flag */ + } } else - printk - ("%s: rx desc without RCR_LPKT. Shouldn't happen !?\n", + printk(KERN_ERR "%s: rx desc without RCR_LPKT. Shouldn't happen !?\n", dev->name); + /* + * give back the descriptor + */ + sonic_rda_put(dev, entry, SONIC_RD_LINK, + sonic_rda_get(dev, entry, SONIC_RD_LINK) | SONIC_EOL); + sonic_rda_put(dev, entry, SONIC_RD_IN_USE, 1); + sonic_rda_put(dev, lp->eol_rx, SONIC_RD_LINK, + sonic_rda_get(dev, lp->eol_rx, SONIC_RD_LINK) & ~SONIC_EOL); + lp->eol_rx = entry; + lp->cur_rx = entry = (entry + 1) & SONIC_RDS_MASK; } /* - * If any worth-while packets have been received, dev_rint() + * If any worth-while packets have been received, netif_rx() * has done a mark_bh(NET_BH) for us and will work on them * when we get to the bottom-half routine. */ @@ -376,8 +539,7 @@ static void sonic_rx(struct net_device *dev) */ static struct net_device_stats *sonic_get_stats(struct net_device *dev) { - struct sonic_local *lp = (struct sonic_local *) dev->priv; - unsigned int base_addr = dev->base_addr; + struct sonic_local *lp = netdev_priv(dev); /* read the tally counter from the SONIC and reset them */ lp->stats.rx_crc_errors += SONIC_READ(SONIC_CRCT); @@ -396,8 +558,7 @@ static struct net_device_stats *sonic_get_stats(struct net_device *dev) */ static void sonic_multicast_list(struct net_device *dev) { - struct sonic_local *lp = (struct sonic_local *) dev->priv; - unsigned int base_addr = dev->base_addr; + struct sonic_local *lp = netdev_priv(dev); unsigned int rcr; struct dev_mc_list *dmi = dev->mc_list; unsigned char *addr; @@ -413,20 +574,15 @@ static void sonic_multicast_list(struct net_device *dev) rcr |= SONIC_RCR_AMC; } else { if (sonic_debug > 2) - printk - ("sonic_multicast_list: mc_count %d\n", - dev->mc_count); - lp->cda.cam_enable = 1; /* always enable our own address */ + printk("sonic_multicast_list: mc_count %d\n", dev->mc_count); + sonic_set_cam_enable(dev, 1); /* always enable our own address */ for (i = 1; i <= dev->mc_count; i++) { addr = dmi->dmi_addr; dmi = dmi->next; - lp->cda.cam_desc[i].cam_cap0 = - addr[1] << 8 | addr[0]; - lp->cda.cam_desc[i].cam_cap1 = - addr[3] << 8 | addr[2]; - lp->cda.cam_desc[i].cam_cap2 = - addr[5] << 8 | addr[4]; - lp->cda.cam_enable |= (1 << i); + sonic_cda_put(dev, i, SONIC_CD_CAP0, addr[1] << 8 | addr[0]); + sonic_cda_put(dev, i, SONIC_CD_CAP1, addr[3] << 8 | addr[2]); + sonic_cda_put(dev, i, SONIC_CD_CAP2, addr[5] << 8 | addr[4]); + sonic_set_cam_enable(dev, sonic_get_cam_enable(dev) | (1 << i)); } SONIC_WRITE(SONIC_CDC, 16); /* issue Load CAM command */ @@ -447,19 +603,16 @@ static void sonic_multicast_list(struct net_device *dev) */ static int sonic_init(struct net_device *dev) { - unsigned int base_addr = dev->base_addr; unsigned int cmd; - struct sonic_local *lp = (struct sonic_local *) dev->priv; - unsigned int rra_start; - unsigned int rra_end; + struct sonic_local *lp = netdev_priv(dev); int i; /* * put the Sonic into software-reset mode and * disable all interrupts */ - SONIC_WRITE(SONIC_ISR, 0x7fff); SONIC_WRITE(SONIC_IMR, 0); + SONIC_WRITE(SONIC_ISR, 0x7fff); SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); /* @@ -475,34 +628,32 @@ static int sonic_init(struct net_device *dev) if (sonic_debug > 2) printk("sonic_init: initialize receive resource area\n"); - rra_start = lp->rra_laddr & 0xffff; - rra_end = - (rra_start + (SONIC_NUM_RRS * sizeof(sonic_rr_t))) & 0xffff; - for (i = 0; i < SONIC_NUM_RRS; i++) { - lp->rra[i].rx_bufadr_l = - (lp->rba_laddr + i * SONIC_RBSIZE) & 0xffff; - lp->rra[i].rx_bufadr_h = - (lp->rba_laddr + i * SONIC_RBSIZE) >> 16; - lp->rra[i].rx_bufsize_l = SONIC_RBSIZE >> 1; - lp->rra[i].rx_bufsize_h = 0; + u16 bufadr_l = (unsigned long)lp->rx_laddr[i] & 0xffff; + u16 bufadr_h = (unsigned long)lp->rx_laddr[i] >> 16; + sonic_rra_put(dev, i, SONIC_RR_BUFADR_L, bufadr_l); + sonic_rra_put(dev, i, SONIC_RR_BUFADR_H, bufadr_h); + sonic_rra_put(dev, i, SONIC_RR_BUFSIZE_L, SONIC_RBSIZE >> 1); + sonic_rra_put(dev, i, SONIC_RR_BUFSIZE_H, 0); } /* initialize all RRA registers */ - SONIC_WRITE(SONIC_RSA, rra_start); - SONIC_WRITE(SONIC_REA, rra_end); - SONIC_WRITE(SONIC_RRP, rra_start); - SONIC_WRITE(SONIC_RWP, rra_end); + lp->rra_end = (lp->rra_laddr + SONIC_NUM_RRS * SIZEOF_SONIC_RR * + SONIC_BUS_SCALE(lp->dma_bitmode)) & 0xffff; + lp->cur_rwp = (lp->rra_laddr + (SONIC_NUM_RRS - 1) * SIZEOF_SONIC_RR * + SONIC_BUS_SCALE(lp->dma_bitmode)) & 0xffff; + + SONIC_WRITE(SONIC_RSA, lp->rra_laddr & 0xffff); + SONIC_WRITE(SONIC_REA, lp->rra_end); + SONIC_WRITE(SONIC_RRP, lp->rra_laddr & 0xffff); + SONIC_WRITE(SONIC_RWP, lp->cur_rwp); SONIC_WRITE(SONIC_URRA, lp->rra_laddr >> 16); - SONIC_WRITE(SONIC_EOBC, (SONIC_RBSIZE - 2) >> 1); - - lp->cur_rra = - lp->rra_laddr + (SONIC_NUM_RRS - 1) * sizeof(sonic_rr_t); + SONIC_WRITE(SONIC_EOBC, (SONIC_RBSIZE >> 1) - (lp->dma_bitmode ? 2 : 1)); /* load the resource pointers */ if (sonic_debug > 3) - printk("sonic_init: issueing RRRA command\n"); - + printk("sonic_init: issuing RRRA command\n"); + SONIC_WRITE(SONIC_CMD, SONIC_CR_RRRA); i = 0; while (i++ < 100) { @@ -511,27 +662,30 @@ static int sonic_init(struct net_device *dev) } if (sonic_debug > 2) - printk("sonic_init: status=%x\n", SONIC_READ(SONIC_CMD)); - + printk("sonic_init: status=%x i=%d\n", SONIC_READ(SONIC_CMD), i); + /* * Initialize the receive descriptors so that they * become a circular linked list, ie. let the last * descriptor point to the first again. */ if (sonic_debug > 2) - printk("sonic_init: initialize receive descriptors\n"); - for (i = 0; i < SONIC_NUM_RDS; i++) { - lp->rda[i].rx_status = 0; - lp->rda[i].rx_pktlen = 0; - lp->rda[i].rx_pktptr_l = 0; - lp->rda[i].rx_pktptr_h = 0; - lp->rda[i].rx_seqno = 0; - lp->rda[i].in_use = 1; - lp->rda[i].link = - lp->rda_laddr + (i + 1) * sizeof(sonic_rd_t); + printk("sonic_init: initialize receive descriptors\n"); + for (i=0; i<SONIC_NUM_RDS; i++) { + sonic_rda_put(dev, i, SONIC_RD_STATUS, 0); + sonic_rda_put(dev, i, SONIC_RD_PKTLEN, 0); + sonic_rda_put(dev, i, SONIC_RD_PKTPTR_L, 0); + sonic_rda_put(dev, i, SONIC_RD_PKTPTR_H, 0); + sonic_rda_put(dev, i, SONIC_RD_SEQNO, 0); + sonic_rda_put(dev, i, SONIC_RD_IN_USE, 1); + sonic_rda_put(dev, i, SONIC_RD_LINK, + lp->rda_laddr + + ((i+1) * SIZEOF_SONIC_RD * SONIC_BUS_SCALE(lp->dma_bitmode))); } /* fix last descriptor */ - lp->rda[SONIC_NUM_RDS - 1].link = lp->rda_laddr; + sonic_rda_put(dev, SONIC_NUM_RDS - 1, SONIC_RD_LINK, + (lp->rda_laddr & 0xffff) | SONIC_EOL); + lp->eol_rx = SONIC_NUM_RDS - 1; lp->cur_rx = 0; SONIC_WRITE(SONIC_URDA, lp->rda_laddr >> 16); SONIC_WRITE(SONIC_CRDA, lp->rda_laddr & 0xffff); @@ -542,34 +696,34 @@ static int sonic_init(struct net_device *dev) if (sonic_debug > 2) printk("sonic_init: initialize transmit descriptors\n"); for (i = 0; i < SONIC_NUM_TDS; i++) { - lp->tda[i].tx_status = 0; - lp->tda[i].tx_config = 0; - lp->tda[i].tx_pktsize = 0; - lp->tda[i].tx_frag_count = 0; - lp->tda[i].link = - (lp->tda_laddr + - (i + 1) * sizeof(sonic_td_t)) | SONIC_END_OF_LINKS; + sonic_tda_put(dev, i, SONIC_TD_STATUS, 0); + sonic_tda_put(dev, i, SONIC_TD_CONFIG, 0); + sonic_tda_put(dev, i, SONIC_TD_PKTSIZE, 0); + sonic_tda_put(dev, i, SONIC_TD_FRAG_COUNT, 0); + sonic_tda_put(dev, i, SONIC_TD_LINK, + (lp->tda_laddr & 0xffff) + + (i + 1) * SIZEOF_SONIC_TD * SONIC_BUS_SCALE(lp->dma_bitmode)); + lp->tx_skb[i] = NULL; } - lp->tda[SONIC_NUM_TDS - 1].link = - (lp->tda_laddr & 0xffff) | SONIC_END_OF_LINKS; + /* fix last descriptor */ + sonic_tda_put(dev, SONIC_NUM_TDS - 1, SONIC_TD_LINK, + (lp->tda_laddr & 0xffff)); SONIC_WRITE(SONIC_UTDA, lp->tda_laddr >> 16); SONIC_WRITE(SONIC_CTDA, lp->tda_laddr & 0xffff); - lp->cur_tx = lp->dirty_tx = 0; - + lp->cur_tx = lp->next_tx = 0; + lp->eol_tx = SONIC_NUM_TDS - 1; + /* * put our own address to CAM desc[0] */ - lp->cda.cam_desc[0].cam_cap0 = - dev->dev_addr[1] << 8 | dev->dev_addr[0]; - lp->cda.cam_desc[0].cam_cap1 = - dev->dev_addr[3] << 8 | dev->dev_addr[2]; - lp->cda.cam_desc[0].cam_cap2 = - dev->dev_addr[5] << 8 | dev->dev_addr[4]; - lp->cda.cam_enable = 1; + sonic_cda_put(dev, 0, SONIC_CD_CAP0, dev->dev_addr[1] << 8 | dev->dev_addr[0]); + sonic_cda_put(dev, 0, SONIC_CD_CAP1, dev->dev_addr[3] << 8 | dev->dev_addr[2]); + sonic_cda_put(dev, 0, SONIC_CD_CAP2, dev->dev_addr[5] << 8 | dev->dev_addr[4]); + sonic_set_cam_enable(dev, 1); for (i = 0; i < 16; i++) - lp->cda.cam_desc[i].cam_entry_pointer = i; + sonic_cda_put(dev, i, SONIC_CD_ENTRY_POINTER, i); /* * initialize CAM registers @@ -588,8 +742,8 @@ static int sonic_init(struct net_device *dev) break; } if (sonic_debug > 2) { - printk("sonic_init: CMD=%x, ISR=%x\n", - SONIC_READ(SONIC_CMD), SONIC_READ(SONIC_ISR)); + printk("sonic_init: CMD=%x, ISR=%x\n, i=%d", + SONIC_READ(SONIC_CMD), SONIC_READ(SONIC_ISR), i); } /* @@ -604,7 +758,7 @@ static int sonic_init(struct net_device *dev) cmd = SONIC_READ(SONIC_CMD); if ((cmd & SONIC_CR_RXEN) == 0 || (cmd & SONIC_CR_STP) == 0) - printk("sonic_init: failed, status=%x\n", cmd); + printk(KERN_ERR "sonic_init: failed, status=%x\n", cmd); if (sonic_debug > 2) printk("sonic_init: new status=%x\n", diff --git a/drivers/net/sonic.h b/drivers/net/sonic.h index c4a6d58e4af..cede969a8ba 100644 --- a/drivers/net/sonic.h +++ b/drivers/net/sonic.h @@ -1,5 +1,5 @@ /* - * Helpfile for sonic.c + * Header file for sonic.c * * (C) Waldorf Electronics, Germany * Written by Andreas Busse @@ -9,10 +9,16 @@ * and pad structure members must be exchanged. Also, the structures * need to be changed accordingly to the bus size. * - * 981229 MSch: did just that for the 68k Mac port (32 bit, big endian), - * see CONFIG_MACSONIC branch below. + * 981229 MSch: did just that for the 68k Mac port (32 bit, big endian) * + * 990611 David Huggins-Daines <dhd@debian.org>: This machine abstraction + * does not cope with 16-bit bus sizes very well. Therefore I have + * rewritten it with ugly macros and evil inlines. + * + * 050625 Finn Thain: introduced more 32-bit cards and dhd's support + * for 16-bit cards (from the mac68k project). */ + #ifndef SONIC_H #define SONIC_H @@ -83,6 +89,7 @@ /* * Error counters */ + #define SONIC_CRCT 0x2c #define SONIC_FAET 0x2d #define SONIC_MPT 0x2e @@ -182,14 +189,14 @@ #define SONIC_INT_BR 0x4000 #define SONIC_INT_HBL 0x2000 -#define SONIC_INT_LCD 0x1000 -#define SONIC_INT_PINT 0x0800 -#define SONIC_INT_PKTRX 0x0400 -#define SONIC_INT_TXDN 0x0200 -#define SONIC_INT_TXER 0x0100 -#define SONIC_INT_TC 0x0080 -#define SONIC_INT_RDE 0x0040 -#define SONIC_INT_RBE 0x0020 +#define SONIC_INT_LCD 0x1000 +#define SONIC_INT_PINT 0x0800 +#define SONIC_INT_PKTRX 0x0400 +#define SONIC_INT_TXDN 0x0200 +#define SONIC_INT_TXER 0x0100 +#define SONIC_INT_TC 0x0080 +#define SONIC_INT_RDE 0x0040 +#define SONIC_INT_RBE 0x0020 #define SONIC_INT_RBAE 0x0010 #define SONIC_INT_CRC 0x0008 #define SONIC_INT_FAE 0x0004 @@ -201,224 +208,61 @@ * The interrupts we allow. */ -#define SONIC_IMR_DEFAULT (SONIC_INT_BR | \ - SONIC_INT_LCD | \ - SONIC_INT_PINT | \ +#define SONIC_IMR_DEFAULT ( SONIC_INT_BR | \ + SONIC_INT_LCD | \ + SONIC_INT_RFO | \ SONIC_INT_PKTRX | \ SONIC_INT_TXDN | \ SONIC_INT_TXER | \ SONIC_INT_RDE | \ - SONIC_INT_RBE | \ SONIC_INT_RBAE | \ SONIC_INT_CRC | \ SONIC_INT_FAE | \ SONIC_INT_MP) -#define SONIC_END_OF_LINKS 0x0001 - - -#ifdef CONFIG_MACSONIC -/* - * Big endian like structures on 680x0 Macs - */ - -typedef struct { - u32 rx_bufadr_l; /* receive buffer ptr */ - u32 rx_bufadr_h; - - u32 rx_bufsize_l; /* no. of words in the receive buffer */ - u32 rx_bufsize_h; -} sonic_rr_t; - -/* - * Sonic receive descriptor. Receive descriptors are - * kept in a linked list of these structures. - */ - -typedef struct { - SREGS_PAD(pad0); - u16 rx_status; /* status after reception of a packet */ - SREGS_PAD(pad1); - u16 rx_pktlen; /* length of the packet incl. CRC */ - - /* - * Pointers to the location in the receive buffer area (RBA) - * where the packet resides. A packet is always received into - * a contiguous piece of memory. - */ - SREGS_PAD(pad2); - u16 rx_pktptr_l; - SREGS_PAD(pad3); - u16 rx_pktptr_h; - - SREGS_PAD(pad4); - u16 rx_seqno; /* sequence no. */ - - SREGS_PAD(pad5); - u16 link; /* link to next RDD (end if EOL bit set) */ - - /* - * Owner of this descriptor, 0= driver, 1=sonic - */ - - SREGS_PAD(pad6); - u16 in_use; - - caddr_t rda_next; /* pointer to next RD */ -} sonic_rd_t; - - -/* - * Describes a Transmit Descriptor - */ -typedef struct { - SREGS_PAD(pad0); - u16 tx_status; /* status after transmission of a packet */ - SREGS_PAD(pad1); - u16 tx_config; /* transmit configuration for this packet */ - SREGS_PAD(pad2); - u16 tx_pktsize; /* size of the packet to be transmitted */ - SREGS_PAD(pad3); - u16 tx_frag_count; /* no. of fragments */ - - SREGS_PAD(pad4); - u16 tx_frag_ptr_l; - SREGS_PAD(pad5); - u16 tx_frag_ptr_h; - SREGS_PAD(pad6); - u16 tx_frag_size; - - SREGS_PAD(pad7); - u16 link; /* ptr to next descriptor */ -} sonic_td_t; - - -/* - * Describes an entry in the CAM Descriptor Area. - */ - -typedef struct { - SREGS_PAD(pad0); - u16 cam_entry_pointer; - SREGS_PAD(pad1); - u16 cam_cap0; - SREGS_PAD(pad2); - u16 cam_cap1; - SREGS_PAD(pad3); - u16 cam_cap2; -} sonic_cd_t; - +#define SONIC_EOL 0x0001 #define CAM_DESCRIPTORS 16 - -typedef struct { - sonic_cd_t cam_desc[CAM_DESCRIPTORS]; - SREGS_PAD(pad); - u16 cam_enable; -} sonic_cda_t; - -#else /* original declarations, little endian 32 bit */ - -/* - * structure definitions - */ - -typedef struct { - u32 rx_bufadr_l; /* receive buffer ptr */ - u32 rx_bufadr_h; - - u32 rx_bufsize_l; /* no. of words in the receive buffer */ - u32 rx_bufsize_h; -} sonic_rr_t; - -/* - * Sonic receive descriptor. Receive descriptors are - * kept in a linked list of these structures. - */ - -typedef struct { - u16 rx_status; /* status after reception of a packet */ - SREGS_PAD(pad0); - u16 rx_pktlen; /* length of the packet incl. CRC */ - SREGS_PAD(pad1); - - /* - * Pointers to the location in the receive buffer area (RBA) - * where the packet resides. A packet is always received into - * a contiguous piece of memory. - */ - u16 rx_pktptr_l; - SREGS_PAD(pad2); - u16 rx_pktptr_h; - SREGS_PAD(pad3); - - u16 rx_seqno; /* sequence no. */ - SREGS_PAD(pad4); - - u16 link; /* link to next RDD (end if EOL bit set) */ - SREGS_PAD(pad5); - - /* - * Owner of this descriptor, 0= driver, 1=sonic - */ - - u16 in_use; - SREGS_PAD(pad6); - - caddr_t rda_next; /* pointer to next RD */ -} sonic_rd_t; - - -/* - * Describes a Transmit Descriptor - */ -typedef struct { - u16 tx_status; /* status after transmission of a packet */ - SREGS_PAD(pad0); - u16 tx_config; /* transmit configuration for this packet */ - SREGS_PAD(pad1); - u16 tx_pktsize; /* size of the packet to be transmitted */ - SREGS_PAD(pad2); - u16 tx_frag_count; /* no. of fragments */ - SREGS_PAD(pad3); - - u16 tx_frag_ptr_l; - SREGS_PAD(pad4); - u16 tx_frag_ptr_h; - SREGS_PAD(pad5); - u16 tx_frag_size; - SREGS_PAD(pad6); - - u16 link; /* ptr to next descriptor */ - SREGS_PAD(pad7); -} sonic_td_t; - - -/* - * Describes an entry in the CAM Descriptor Area. - */ - -typedef struct { - u16 cam_entry_pointer; - SREGS_PAD(pad0); - u16 cam_cap0; - SREGS_PAD(pad1); - u16 cam_cap1; - SREGS_PAD(pad2); - u16 cam_cap2; - SREGS_PAD(pad3); -} sonic_cd_t; - -#define CAM_DESCRIPTORS 16 - - -typedef struct { - sonic_cd_t cam_desc[CAM_DESCRIPTORS]; - u16 cam_enable; - SREGS_PAD(pad); -} sonic_cda_t; -#endif /* endianness */ +/* Offsets in the various DMA buffers accessed by the SONIC */ + +#define SONIC_BITMODE16 0 +#define SONIC_BITMODE32 1 +#define SONIC_BUS_SCALE(bitmode) ((bitmode) ? 4 : 2) +/* Note! These are all measured in bus-size units, so use SONIC_BUS_SCALE */ +#define SIZEOF_SONIC_RR 4 +#define SONIC_RR_BUFADR_L 0 +#define SONIC_RR_BUFADR_H 1 +#define SONIC_RR_BUFSIZE_L 2 +#define SONIC_RR_BUFSIZE_H 3 + +#define SIZEOF_SONIC_RD 7 +#define SONIC_RD_STATUS 0 +#define SONIC_RD_PKTLEN 1 +#define SONIC_RD_PKTPTR_L 2 +#define SONIC_RD_PKTPTR_H 3 +#define SONIC_RD_SEQNO 4 +#define SONIC_RD_LINK 5 +#define SONIC_RD_IN_USE 6 + +#define SIZEOF_SONIC_TD 8 +#define SONIC_TD_STATUS 0 +#define SONIC_TD_CONFIG 1 +#define SONIC_TD_PKTSIZE 2 +#define SONIC_TD_FRAG_COUNT 3 +#define SONIC_TD_FRAG_PTR_L 4 +#define SONIC_TD_FRAG_PTR_H 5 +#define SONIC_TD_FRAG_SIZE 6 +#define SONIC_TD_LINK 7 + +#define SIZEOF_SONIC_CD 4 +#define SONIC_CD_ENTRY_POINTER 0 +#define SONIC_CD_CAP0 1 +#define SONIC_CD_CAP1 2 +#define SONIC_CD_CAP2 3 + +#define SIZEOF_SONIC_CDA ((CAM_DESCRIPTORS * SIZEOF_SONIC_CD) + 1) +#define SONIC_CDA_CAM_ENABLE (CAM_DESCRIPTORS * SIZEOF_SONIC_CD) /* * Some tunables for the buffer areas. Power of 2 is required @@ -426,44 +270,60 @@ typedef struct { * * MSch: use more buffer space for the slow m68k Macs! */ -#ifdef CONFIG_MACSONIC -#define SONIC_NUM_RRS 32 /* number of receive resources */ -#define SONIC_NUM_RDS SONIC_NUM_RRS /* number of receive descriptors */ -#define SONIC_NUM_TDS 32 /* number of transmit descriptors */ -#else -#define SONIC_NUM_RRS 16 /* number of receive resources */ -#define SONIC_NUM_RDS SONIC_NUM_RRS /* number of receive descriptors */ -#define SONIC_NUM_TDS 16 /* number of transmit descriptors */ -#endif -#define SONIC_RBSIZE 1520 /* size of one resource buffer */ +#define SONIC_NUM_RRS 16 /* number of receive resources */ +#define SONIC_NUM_RDS SONIC_NUM_RRS /* number of receive descriptors */ +#define SONIC_NUM_TDS 16 /* number of transmit descriptors */ -#define SONIC_RDS_MASK (SONIC_NUM_RDS-1) -#define SONIC_TDS_MASK (SONIC_NUM_TDS-1) +#define SONIC_RDS_MASK (SONIC_NUM_RDS-1) +#define SONIC_TDS_MASK (SONIC_NUM_TDS-1) +#define SONIC_RBSIZE 1520 /* size of one resource buffer */ + +/* Again, measured in bus size units! */ +#define SIZEOF_SONIC_DESC (SIZEOF_SONIC_CDA \ + + (SIZEOF_SONIC_TD * SONIC_NUM_TDS) \ + + (SIZEOF_SONIC_RD * SONIC_NUM_RDS) \ + + (SIZEOF_SONIC_RR * SONIC_NUM_RRS)) /* Information that need to be kept for each board. */ struct sonic_local { - sonic_cda_t cda; /* virtual CPU address of CDA */ - sonic_td_t tda[SONIC_NUM_TDS]; /* transmit descriptor area */ - sonic_rr_t rra[SONIC_NUM_RRS]; /* receive resource area */ - sonic_rd_t rda[SONIC_NUM_RDS]; /* receive descriptor area */ - struct sk_buff *tx_skb[SONIC_NUM_TDS]; /* skbuffs for packets to transmit */ - unsigned int tx_laddr[SONIC_NUM_TDS]; /* logical DMA address fro skbuffs */ - unsigned char *rba; /* start of receive buffer areas */ - unsigned int cda_laddr; /* logical DMA address of CDA */ - unsigned int tda_laddr; /* logical DMA address of TDA */ - unsigned int rra_laddr; /* logical DMA address of RRA */ - unsigned int rda_laddr; /* logical DMA address of RDA */ - unsigned int rba_laddr; /* logical DMA address of RBA */ - unsigned int cur_rra; /* current indexes to resource areas */ + /* Bus size. 0 == 16 bits, 1 == 32 bits. */ + int dma_bitmode; + /* Register offset within the longword (independent of endianness, + and varies from one type of Macintosh SONIC to another + (Aarrgh)) */ + int reg_offset; + void *descriptors; + /* Crud. These areas have to be within the same 64K. Therefore + we allocate a desriptors page, and point these to places within it. */ + void *cda; /* CAM descriptor area */ + void *tda; /* Transmit descriptor area */ + void *rra; /* Receive resource area */ + void *rda; /* Receive descriptor area */ + struct sk_buff* volatile rx_skb[SONIC_NUM_RRS]; /* packets to be received */ + struct sk_buff* volatile tx_skb[SONIC_NUM_TDS]; /* packets to be transmitted */ + unsigned int tx_len[SONIC_NUM_TDS]; /* lengths of tx DMA mappings */ + /* Logical DMA addresses on MIPS, bus addresses on m68k + * (so "laddr" is a bit misleading) */ + dma_addr_t descriptors_laddr; + u32 cda_laddr; /* logical DMA address of CDA */ + u32 tda_laddr; /* logical DMA address of TDA */ + u32 rra_laddr; /* logical DMA address of RRA */ + u32 rda_laddr; /* logical DMA address of RDA */ + dma_addr_t rx_laddr[SONIC_NUM_RRS]; /* logical DMA addresses of rx skbuffs */ + dma_addr_t tx_laddr[SONIC_NUM_TDS]; /* logical DMA addresses of tx skbuffs */ + unsigned int rra_end; + unsigned int cur_rwp; unsigned int cur_rx; - unsigned int cur_tx; - unsigned int dirty_tx; /* last unacked transmit packet */ - char tx_full; + unsigned int cur_tx; /* first unacked transmit packet */ + unsigned int eol_rx; + unsigned int eol_tx; /* last unacked transmit packet */ + unsigned int next_tx; /* next free TD */ + struct device *device; /* generic device */ struct net_device_stats stats; }; -#define TX_TIMEOUT 6 +#define TX_TIMEOUT (3 * HZ) /* Index to functions, as function prototypes. */ @@ -477,6 +337,114 @@ static void sonic_multicast_list(struct net_device *dev); static int sonic_init(struct net_device *dev); static void sonic_tx_timeout(struct net_device *dev); +/* Internal inlines for reading/writing DMA buffers. Note that bus + size and endianness matter here, whereas they don't for registers, + as far as we can tell. */ +/* OpenBSD calls this "SWO". I'd like to think that sonic_buf_put() + is a much better name. */ +static inline void sonic_buf_put(void* base, int bitmode, + int offset, __u16 val) +{ + if (bitmode) +#ifdef __BIG_ENDIAN + ((__u16 *) base + (offset*2))[1] = val; +#else + ((__u16 *) base + (offset*2))[0] = val; +#endif + else + ((__u16 *) base)[offset] = val; +} + +static inline __u16 sonic_buf_get(void* base, int bitmode, + int offset) +{ + if (bitmode) +#ifdef __BIG_ENDIAN + return ((volatile __u16 *) base + (offset*2))[1]; +#else + return ((volatile __u16 *) base + (offset*2))[0]; +#endif + else + return ((volatile __u16 *) base)[offset]; +} + +/* Inlines that you should actually use for reading/writing DMA buffers */ +static inline void sonic_cda_put(struct net_device* dev, int entry, + int offset, __u16 val) +{ + struct sonic_local* lp = (struct sonic_local *) dev->priv; + sonic_buf_put(lp->cda, lp->dma_bitmode, + (entry * SIZEOF_SONIC_CD) + offset, val); +} + +static inline __u16 sonic_cda_get(struct net_device* dev, int entry, + int offset) +{ + struct sonic_local* lp = (struct sonic_local *) dev->priv; + return sonic_buf_get(lp->cda, lp->dma_bitmode, + (entry * SIZEOF_SONIC_CD) + offset); +} + +static inline void sonic_set_cam_enable(struct net_device* dev, __u16 val) +{ + struct sonic_local* lp = (struct sonic_local *) dev->priv; + sonic_buf_put(lp->cda, lp->dma_bitmode, SONIC_CDA_CAM_ENABLE, val); +} + +static inline __u16 sonic_get_cam_enable(struct net_device* dev) +{ + struct sonic_local* lp = (struct sonic_local *) dev->priv; + return sonic_buf_get(lp->cda, lp->dma_bitmode, SONIC_CDA_CAM_ENABLE); +} + +static inline void sonic_tda_put(struct net_device* dev, int entry, + int offset, __u16 val) +{ + struct sonic_local* lp = (struct sonic_local *) dev->priv; + sonic_buf_put(lp->tda, lp->dma_bitmode, + (entry * SIZEOF_SONIC_TD) + offset, val); +} + +static inline __u16 sonic_tda_get(struct net_device* dev, int entry, + int offset) +{ + struct sonic_local* lp = (struct sonic_local *) dev->priv; + return sonic_buf_get(lp->tda, lp->dma_bitmode, + (entry * SIZEOF_SONIC_TD) + offset); +} + +static inline void sonic_rda_put(struct net_device* dev, int entry, + int offset, __u16 val) +{ + struct sonic_local* lp = (struct sonic_local *) dev->priv; + sonic_buf_put(lp->rda, lp->dma_bitmode, + (entry * SIZEOF_SONIC_RD) + offset, val); +} + +static inline __u16 sonic_rda_get(struct net_device* dev, int entry, + int offset) +{ + struct sonic_local* lp = (struct sonic_local *) dev->priv; + return sonic_buf_get(lp->rda, lp->dma_bitmode, + (entry * SIZEOF_SONIC_RD) + offset); +} + +static inline void sonic_rra_put(struct net_device* dev, int entry, + int offset, __u16 val) +{ + struct sonic_local* lp = (struct sonic_local *) dev->priv; + sonic_buf_put(lp->rra, lp->dma_bitmode, + (entry * SIZEOF_SONIC_RR) + offset, val); +} + +static inline __u16 sonic_rra_get(struct net_device* dev, int entry, + int offset) +{ + struct sonic_local* lp = (struct sonic_local *) dev->priv; + return sonic_buf_get(lp->rra, lp->dma_bitmode, + (entry * SIZEOF_SONIC_RR) + offset); +} + static const char *version = "sonic.c:v0.92 20.9.98 tsbogend@alpha.franken.de\n"; diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 01419aff333..6d4ab1e333b 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -66,8 +66,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.36" -#define DRV_MODULE_RELDATE "August 19, 2005" +#define DRV_MODULE_VERSION "3.37" +#define DRV_MODULE_RELDATE "August 25, 2005" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -7865,8 +7865,6 @@ static int tg3_test_loopback(struct tg3 *tp) err = -EIO; - tg3_abort_hw(tp, 1); - tg3_reset_hw(tp); mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) | diff --git a/drivers/net/tokenring/Kconfig b/drivers/net/tokenring/Kconfig index 7e99e9f8045..e4cfc80b283 100644 --- a/drivers/net/tokenring/Kconfig +++ b/drivers/net/tokenring/Kconfig @@ -84,7 +84,7 @@ config 3C359 config TMS380TR tristate "Generic TMS380 Token Ring ISA/PCI adapter support" - depends on TR && (PCI || ISA && ISA_DMA_API) + depends on TR && (PCI || ISA && ISA_DMA_API || MCA) select FW_LOADER ---help--- This driver provides generic support for token ring adapters @@ -158,7 +158,7 @@ config ABYSS config MADGEMC tristate "Madge Smart 16/4 Ringnode MicroChannel" - depends on TR && TMS380TR && MCA_LEGACY + depends on TR && TMS380TR && MCA help This tms380 module supports the Madge Smart 16/4 MC16 and MC32 MicroChannel adapters. diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c index 87103c40099..9345e68c451 100644 --- a/drivers/net/tokenring/abyss.c +++ b/drivers/net/tokenring/abyss.c @@ -139,7 +139,7 @@ static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_ */ dev->base_addr += 0x10; - ret = tmsdev_init(dev, PCI_MAX_ADDRESS, pdev); + ret = tmsdev_init(dev, &pdev->dev); if (ret) { printk("%s: unable to get memory for dev->priv.\n", dev->name); diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c index 659cbdbef7f..3a25d191ea4 100644 --- a/drivers/net/tokenring/madgemc.c +++ b/drivers/net/tokenring/madgemc.c @@ -20,7 +20,7 @@ static const char version[] = "madgemc.c: v0.91 23/01/2000 by Adam Fritzler\n"; #include <linux/module.h> -#include <linux/mca-legacy.h> +#include <linux/mca.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/pci.h> @@ -38,9 +38,7 @@ static const char version[] = "madgemc.c: v0.91 23/01/2000 by Adam Fritzler\n"; #define MADGEMC_IO_EXTENT 32 #define MADGEMC_SIF_OFFSET 0x08 -struct madgemc_card { - struct net_device *dev; - +struct card_info { /* * These are read from the BIA ROM. */ @@ -57,16 +55,12 @@ struct madgemc_card { unsigned int arblevel:4; unsigned int ringspeed:2; /* 0 = 4mb, 1 = 16, 2 = Auto/none */ unsigned int cabletype:1; /* 0 = RJ45, 1 = DB9 */ - - struct madgemc_card *next; }; -static struct madgemc_card *madgemc_card_list; - static int madgemc_open(struct net_device *dev); static int madgemc_close(struct net_device *dev); static int madgemc_chipset_init(struct net_device *dev); -static void madgemc_read_rom(struct madgemc_card *card); +static void madgemc_read_rom(struct net_device *dev, struct card_info *card); static unsigned short madgemc_setnselout_pins(struct net_device *dev); static void madgemc_setcabletype(struct net_device *dev, int type); @@ -151,261 +145,237 @@ static void madgemc_sifwritew(struct net_device *dev, unsigned short val, unsign -static int __init madgemc_probe(void) +static int __devinit madgemc_probe(struct device *device) { static int versionprinted; struct net_device *dev; struct net_local *tp; - struct madgemc_card *card; - int i,slot = 0; - __u8 posreg[4]; - - if (!MCA_bus) - return -1; - - while (slot != MCA_NOTFOUND) { - /* - * Currently we only support the MC16/32 (MCA ID 002d) - */ - slot = mca_find_unused_adapter(0x002d, slot); - if (slot == MCA_NOTFOUND) - break; - - /* - * If we get here, we have an adapter. - */ - if (versionprinted++ == 0) - printk("%s", version); - - dev = alloc_trdev(sizeof(struct net_local)); - if (dev == NULL) { - printk("madgemc: unable to allocate dev space\n"); - if (madgemc_card_list) - return 0; - return -1; - } + struct card_info *card; + struct mca_device *mdev = to_mca_device(device); + int ret = 0, i = 0; + + if (versionprinted++ == 0) + printk("%s", version); + + if(mca_device_claimed(mdev)) + return -EBUSY; + mca_device_set_claim(mdev, 1); + + dev = alloc_trdev(sizeof(struct net_local)); + if (!dev) { + printk("madgemc: unable to allocate dev space\n"); + mca_device_set_claim(mdev, 0); + ret = -ENOMEM; + goto getout; + } - SET_MODULE_OWNER(dev); - dev->dma = 0; + SET_MODULE_OWNER(dev); + dev->dma = 0; - /* - * Fetch MCA config registers - */ - for(i=0;i<4;i++) - posreg[i] = mca_read_stored_pos(slot, i+2); - - card = kmalloc(sizeof(struct madgemc_card), GFP_KERNEL); - if (card==NULL) { - printk("madgemc: unable to allocate card struct\n"); - free_netdev(dev); - if (madgemc_card_list) - return 0; - return -1; - } - card->dev = dev; - - /* - * Parse configuration information. This all comes - * directly from the publicly available @002d.ADF. - * Get it from Madge or your local ADF library. - */ - - /* - * Base address - */ - dev->base_addr = 0x0a20 + - ((posreg[2] & MC16_POS2_ADDR2)?0x0400:0) + - ((posreg[0] & MC16_POS0_ADDR1)?0x1000:0) + - ((posreg[3] & MC16_POS3_ADDR3)?0x2000:0); - - /* - * Interrupt line - */ - switch(posreg[0] >> 6) { /* upper two bits */ + card = kmalloc(sizeof(struct card_info), GFP_KERNEL); + if (card==NULL) { + printk("madgemc: unable to allocate card struct\n"); + ret = -ENOMEM; + goto getout1; + } + + /* + * Parse configuration information. This all comes + * directly from the publicly available @002d.ADF. + * Get it from Madge or your local ADF library. + */ + + /* + * Base address + */ + dev->base_addr = 0x0a20 + + ((mdev->pos[2] & MC16_POS2_ADDR2)?0x0400:0) + + ((mdev->pos[0] & MC16_POS0_ADDR1)?0x1000:0) + + ((mdev->pos[3] & MC16_POS3_ADDR3)?0x2000:0); + + /* + * Interrupt line + */ + switch(mdev->pos[0] >> 6) { /* upper two bits */ case 0x1: dev->irq = 3; break; case 0x2: dev->irq = 9; break; /* IRQ 2 = IRQ 9 */ case 0x3: dev->irq = 10; break; default: dev->irq = 0; break; - } + } - if (dev->irq == 0) { - printk("%s: invalid IRQ\n", dev->name); - goto getout1; - } + if (dev->irq == 0) { + printk("%s: invalid IRQ\n", dev->name); + ret = -EBUSY; + goto getout2; + } - if (!request_region(dev->base_addr, MADGEMC_IO_EXTENT, - "madgemc")) { - printk(KERN_INFO "madgemc: unable to setup Smart MC in slot %d because of I/O base conflict at 0x%04lx\n", slot, dev->base_addr); - dev->base_addr += MADGEMC_SIF_OFFSET; - goto getout1; - } + if (!request_region(dev->base_addr, MADGEMC_IO_EXTENT, + "madgemc")) { + printk(KERN_INFO "madgemc: unable to setup Smart MC in slot %d because of I/O base conflict at 0x%04lx\n", mdev->slot, dev->base_addr); dev->base_addr += MADGEMC_SIF_OFFSET; + ret = -EBUSY; + goto getout2; + } + dev->base_addr += MADGEMC_SIF_OFFSET; + + /* + * Arbitration Level + */ + card->arblevel = ((mdev->pos[0] >> 1) & 0x7) + 8; + + /* + * Burst mode and Fairness + */ + card->burstmode = ((mdev->pos[2] >> 6) & 0x3); + card->fairness = ((mdev->pos[2] >> 4) & 0x1); + + /* + * Ring Speed + */ + if ((mdev->pos[1] >> 2)&0x1) + card->ringspeed = 2; /* not selected */ + else if ((mdev->pos[2] >> 5) & 0x1) + card->ringspeed = 1; /* 16Mb */ + else + card->ringspeed = 0; /* 4Mb */ + + /* + * Cable type + */ + if ((mdev->pos[1] >> 6)&0x1) + card->cabletype = 1; /* STP/DB9 */ + else + card->cabletype = 0; /* UTP/RJ-45 */ + + + /* + * ROM Info. This requires us to actually twiddle + * bits on the card, so we must ensure above that + * the base address is free of conflict (request_region above). + */ + madgemc_read_rom(dev, card); - /* - * Arbitration Level - */ - card->arblevel = ((posreg[0] >> 1) & 0x7) + 8; - - /* - * Burst mode and Fairness - */ - card->burstmode = ((posreg[2] >> 6) & 0x3); - card->fairness = ((posreg[2] >> 4) & 0x1); - - /* - * Ring Speed - */ - if ((posreg[1] >> 2)&0x1) - card->ringspeed = 2; /* not selected */ - else if ((posreg[2] >> 5) & 0x1) - card->ringspeed = 1; /* 16Mb */ - else - card->ringspeed = 0; /* 4Mb */ - - /* - * Cable type - */ - if ((posreg[1] >> 6)&0x1) - card->cabletype = 1; /* STP/DB9 */ - else - card->cabletype = 0; /* UTP/RJ-45 */ - - - /* - * ROM Info. This requires us to actually twiddle - * bits on the card, so we must ensure above that - * the base address is free of conflict (request_region above). - */ - madgemc_read_rom(card); - - if (card->manid != 0x4d) { /* something went wrong */ - printk(KERN_INFO "%s: Madge MC ROM read failed (unknown manufacturer ID %02x)\n", dev->name, card->manid); - goto getout; - } + if (card->manid != 0x4d) { /* something went wrong */ + printk(KERN_INFO "%s: Madge MC ROM read failed (unknown manufacturer ID %02x)\n", dev->name, card->manid); + goto getout3; + } - if ((card->cardtype != 0x08) && (card->cardtype != 0x0d)) { - printk(KERN_INFO "%s: Madge MC ROM read failed (unknown card ID %02x)\n", dev->name, card->cardtype); - goto getout; - } + if ((card->cardtype != 0x08) && (card->cardtype != 0x0d)) { + printk(KERN_INFO "%s: Madge MC ROM read failed (unknown card ID %02x)\n", dev->name, card->cardtype); + ret = -EIO; + goto getout3; + } - /* All cards except Rev 0 and 1 MC16's have 256kb of RAM */ - if ((card->cardtype == 0x08) && (card->cardrev <= 0x01)) - card->ramsize = 128; - else - card->ramsize = 256; - - printk("%s: %s Rev %d at 0x%04lx IRQ %d\n", - dev->name, - (card->cardtype == 0x08)?MADGEMC16_CARDNAME: - MADGEMC32_CARDNAME, card->cardrev, - dev->base_addr, dev->irq); - - if (card->cardtype == 0x0d) - printk("%s: Warning: MC32 support is experimental and highly untested\n", dev->name); - - if (card->ringspeed==2) { /* Unknown */ - printk("%s: Warning: Ring speed not set in POS -- Please run the reference disk and set it!\n", dev->name); - card->ringspeed = 1; /* default to 16mb */ - } + /* All cards except Rev 0 and 1 MC16's have 256kb of RAM */ + if ((card->cardtype == 0x08) && (card->cardrev <= 0x01)) + card->ramsize = 128; + else + card->ramsize = 256; + + printk("%s: %s Rev %d at 0x%04lx IRQ %d\n", + dev->name, + (card->cardtype == 0x08)?MADGEMC16_CARDNAME: + MADGEMC32_CARDNAME, card->cardrev, + dev->base_addr, dev->irq); + + if (card->cardtype == 0x0d) + printk("%s: Warning: MC32 support is experimental and highly untested\n", dev->name); + + if (card->ringspeed==2) { /* Unknown */ + printk("%s: Warning: Ring speed not set in POS -- Please run the reference disk and set it!\n", dev->name); + card->ringspeed = 1; /* default to 16mb */ + } - printk("%s: RAM Size: %dKB\n", dev->name, card->ramsize); + printk("%s: RAM Size: %dKB\n", dev->name, card->ramsize); - printk("%s: Ring Speed: %dMb/sec on %s\n", dev->name, - (card->ringspeed)?16:4, - card->cabletype?"STP/DB9":"UTP/RJ-45"); - printk("%s: Arbitration Level: %d\n", dev->name, - card->arblevel); + printk("%s: Ring Speed: %dMb/sec on %s\n", dev->name, + (card->ringspeed)?16:4, + card->cabletype?"STP/DB9":"UTP/RJ-45"); + printk("%s: Arbitration Level: %d\n", dev->name, + card->arblevel); - printk("%s: Burst Mode: ", dev->name); - switch(card->burstmode) { + printk("%s: Burst Mode: ", dev->name); + switch(card->burstmode) { case 0: printk("Cycle steal"); break; case 1: printk("Limited burst"); break; case 2: printk("Delayed release"); break; case 3: printk("Immediate release"); break; - } - printk(" (%s)\n", (card->fairness)?"Unfair":"Fair"); - - - /* - * Enable SIF before we assign the interrupt handler, - * just in case we get spurious interrupts that need - * handling. - */ - outb(0, dev->base_addr + MC_CONTROL_REG0); /* sanity */ - madgemc_setsifsel(dev, 1); - if (request_irq(dev->irq, madgemc_interrupt, SA_SHIRQ, - "madgemc", dev)) - goto getout; - - madgemc_chipset_init(dev); /* enables interrupts! */ - madgemc_setcabletype(dev, card->cabletype); + } + printk(" (%s)\n", (card->fairness)?"Unfair":"Fair"); - /* Setup MCA structures */ - mca_set_adapter_name(slot, (card->cardtype == 0x08)?MADGEMC16_CARDNAME:MADGEMC32_CARDNAME); - mca_set_adapter_procfn(slot, madgemc_mcaproc, dev); - mca_mark_as_used(slot); - printk("%s: Ring Station Address: ", dev->name); - printk("%2.2x", dev->dev_addr[0]); - for (i = 1; i < 6; i++) - printk(":%2.2x", dev->dev_addr[i]); - printk("\n"); - - /* XXX is ISA_MAX_ADDRESS correct here? */ - if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL)) { - printk("%s: unable to get memory for dev->priv.\n", - dev->name); - release_region(dev->base_addr-MADGEMC_SIF_OFFSET, - MADGEMC_IO_EXTENT); - - kfree(card); - tmsdev_term(dev); - free_netdev(dev); - if (madgemc_card_list) - return 0; - return -1; - } - tp = netdev_priv(dev); - - /* - * The MC16 is physically a 32bit card. However, Madge - * insists on calling it 16bit, so I'll assume here that - * they know what they're talking about. Cut off DMA - * at 16mb. - */ - tp->setnselout = madgemc_setnselout_pins; - tp->sifwriteb = madgemc_sifwriteb; - tp->sifreadb = madgemc_sifreadb; - tp->sifwritew = madgemc_sifwritew; - tp->sifreadw = madgemc_sifreadw; - tp->DataRate = (card->ringspeed)?SPEED_16:SPEED_4; - - memcpy(tp->ProductID, "Madge MCA 16/4 ", PROD_ID_SIZE + 1); - - dev->open = madgemc_open; - dev->stop = madgemc_close; - - if (register_netdev(dev) == 0) { - /* Enlist in the card list */ - card->next = madgemc_card_list; - madgemc_card_list = card; - slot++; - continue; /* successful, try to find another */ - } - - free_irq(dev->irq, dev); - getout: - release_region(dev->base_addr-MADGEMC_SIF_OFFSET, - MADGEMC_IO_EXTENT); - getout1: - kfree(card); - free_netdev(dev); - slot++; + /* + * Enable SIF before we assign the interrupt handler, + * just in case we get spurious interrupts that need + * handling. + */ + outb(0, dev->base_addr + MC_CONTROL_REG0); /* sanity */ + madgemc_setsifsel(dev, 1); + if (request_irq(dev->irq, madgemc_interrupt, SA_SHIRQ, + "madgemc", dev)) { + ret = -EBUSY; + goto getout3; } - if (madgemc_card_list) + madgemc_chipset_init(dev); /* enables interrupts! */ + madgemc_setcabletype(dev, card->cabletype); + + /* Setup MCA structures */ + mca_device_set_name(mdev, (card->cardtype == 0x08)?MADGEMC16_CARDNAME:MADGEMC32_CARDNAME); + mca_set_adapter_procfn(mdev->slot, madgemc_mcaproc, dev); + + printk("%s: Ring Station Address: ", dev->name); + printk("%2.2x", dev->dev_addr[0]); + for (i = 1; i < 6; i++) + printk(":%2.2x", dev->dev_addr[i]); + printk("\n"); + + if (tmsdev_init(dev, device)) { + printk("%s: unable to get memory for dev->priv.\n", + dev->name); + ret = -ENOMEM; + goto getout4; + } + tp = netdev_priv(dev); + + /* + * The MC16 is physically a 32bit card. However, Madge + * insists on calling it 16bit, so I'll assume here that + * they know what they're talking about. Cut off DMA + * at 16mb. + */ + tp->setnselout = madgemc_setnselout_pins; + tp->sifwriteb = madgemc_sifwriteb; + tp->sifreadb = madgemc_sifreadb; + tp->sifwritew = madgemc_sifwritew; + tp->sifreadw = madgemc_sifreadw; + tp->DataRate = (card->ringspeed)?SPEED_16:SPEED_4; + + memcpy(tp->ProductID, "Madge MCA 16/4 ", PROD_ID_SIZE + 1); + + dev->open = madgemc_open; + dev->stop = madgemc_close; + + tp->tmspriv = card; + dev_set_drvdata(device, dev); + + if (register_netdev(dev) == 0) return 0; - return -1; + + dev_set_drvdata(device, NULL); + ret = -ENOMEM; +getout4: + free_irq(dev->irq, dev); +getout3: + release_region(dev->base_addr-MADGEMC_SIF_OFFSET, + MADGEMC_IO_EXTENT); +getout2: + kfree(card); +getout1: + free_netdev(dev); +getout: + mca_device_set_claim(mdev, 0); + return ret; } /* @@ -664,12 +634,12 @@ static void madgemc_chipset_close(struct net_device *dev) * is complete. * */ -static void madgemc_read_rom(struct madgemc_card *card) +static void madgemc_read_rom(struct net_device *dev, struct card_info *card) { unsigned long ioaddr; unsigned char reg0, reg1, tmpreg0, i; - ioaddr = card->dev->base_addr; + ioaddr = dev->base_addr; reg0 = inb(ioaddr + MC_CONTROL_REG0); reg1 = inb(ioaddr + MC_CONTROL_REG1); @@ -686,9 +656,9 @@ static void madgemc_read_rom(struct madgemc_card *card) outb(tmpreg0 | MC_CONTROL_REG0_PAGE, ioaddr + MC_CONTROL_REG0); /* Read BIA */ - card->dev->addr_len = 6; + dev->addr_len = 6; for (i = 0; i < 6; i++) - card->dev->dev_addr[i] = inb(ioaddr + MC_ROM_BIA_START + i); + dev->dev_addr[i] = inb(ioaddr + MC_ROM_BIA_START + i); /* Restore original register values */ outb(reg0, ioaddr + MC_CONTROL_REG0); @@ -721,14 +691,10 @@ static int madgemc_close(struct net_device *dev) static int madgemc_mcaproc(char *buf, int slot, void *d) { struct net_device *dev = (struct net_device *)d; - struct madgemc_card *curcard = madgemc_card_list; + struct net_local *tp = dev->priv; + struct card_info *curcard = tp->tmspriv; int len = 0; - while (curcard) { /* search for card struct */ - if (curcard->dev == dev) - break; - curcard = curcard->next; - } len += sprintf(buf+len, "-------\n"); if (curcard) { struct net_local *tp = netdev_priv(dev); @@ -763,25 +729,56 @@ static int madgemc_mcaproc(char *buf, int slot, void *d) return len; } -static void __exit madgemc_exit(void) +static int __devexit madgemc_remove(struct device *device) { - struct net_device *dev; - struct madgemc_card *this_card; - - while (madgemc_card_list) { - dev = madgemc_card_list->dev; - unregister_netdev(dev); - release_region(dev->base_addr-MADGEMC_SIF_OFFSET, MADGEMC_IO_EXTENT); - free_irq(dev->irq, dev); - tmsdev_term(dev); - free_netdev(dev); - this_card = madgemc_card_list; - madgemc_card_list = this_card->next; - kfree(this_card); - } + struct net_device *dev = dev_get_drvdata(device); + struct net_local *tp; + struct card_info *card; + + if (!dev) + BUG(); + + tp = dev->priv; + card = tp->tmspriv; + kfree(card); + tp->tmspriv = NULL; + + unregister_netdev(dev); + release_region(dev->base_addr-MADGEMC_SIF_OFFSET, MADGEMC_IO_EXTENT); + free_irq(dev->irq, dev); + tmsdev_term(dev); + free_netdev(dev); + dev_set_drvdata(device, NULL); + + return 0; +} + +static short madgemc_adapter_ids[] __initdata = { + 0x002d, + 0x0000 +}; + +static struct mca_driver madgemc_driver = { + .id_table = madgemc_adapter_ids, + .driver = { + .name = "madgemc", + .bus = &mca_bus_type, + .probe = madgemc_probe, + .remove = __devexit_p(madgemc_remove), + }, +}; + +static int __init madgemc_init (void) +{ + return mca_register_driver (&madgemc_driver); +} + +static void __exit madgemc_exit (void) +{ + mca_unregister_driver (&madgemc_driver); } -module_init(madgemc_probe); +module_init(madgemc_init); module_exit(madgemc_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c index 40ad0fde28a..eb1423ede75 100644 --- a/drivers/net/tokenring/proteon.c +++ b/drivers/net/tokenring/proteon.c @@ -62,8 +62,7 @@ static int dmalist[] __initdata = { }; static char cardname[] = "Proteon 1392\0"; - -struct net_device *proteon_probe(int unit); +static u64 dma_mask = ISA_MAX_ADDRESS; static int proteon_open(struct net_device *dev); static void proteon_read_eeprom(struct net_device *dev); static unsigned short proteon_setnselout_pins(struct net_device *dev); @@ -116,7 +115,7 @@ nodev: return -ENODEV; } -static int __init setup_card(struct net_device *dev) +static int __init setup_card(struct net_device *dev, struct device *pdev) { struct net_local *tp; static int versionprinted; @@ -137,7 +136,7 @@ static int __init setup_card(struct net_device *dev) } } if (err) - goto out4; + goto out5; /* At this point we have found a valid card. */ @@ -145,14 +144,15 @@ static int __init setup_card(struct net_device *dev) printk(KERN_DEBUG "%s", version); err = -EIO; - if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL)) + pdev->dma_mask = &dma_mask; + if (tmsdev_init(dev, pdev)) goto out4; dev->base_addr &= ~3; proteon_read_eeprom(dev); - printk(KERN_DEBUG "%s: Ring Station Address: ", dev->name); + printk(KERN_DEBUG "proteon.c: Ring Station Address: "); printk("%2.2x", dev->dev_addr[0]); for (j = 1; j < 6; j++) printk(":%2.2x", dev->dev_addr[j]); @@ -185,7 +185,7 @@ static int __init setup_card(struct net_device *dev) if(irqlist[j] == 0) { - printk(KERN_INFO "%s: AutoSelect no IRQ available\n", dev->name); + printk(KERN_INFO "proteon.c: AutoSelect no IRQ available\n"); goto out3; } } @@ -196,15 +196,15 @@ static int __init setup_card(struct net_device *dev) break; if (irqlist[j] == 0) { - printk(KERN_INFO "%s: Illegal IRQ %d specified\n", - dev->name, dev->irq); + printk(KERN_INFO "proteon.c: Illegal IRQ %d specified\n", + dev->irq); goto out3; } if (request_irq(dev->irq, tms380tr_interrupt, 0, cardname, dev)) { - printk(KERN_INFO "%s: Selected IRQ %d not available\n", - dev->name, dev->irq); + printk(KERN_INFO "proteon.c: Selected IRQ %d not available\n", + dev->irq); goto out3; } } @@ -220,7 +220,7 @@ static int __init setup_card(struct net_device *dev) if(dmalist[j] == 0) { - printk(KERN_INFO "%s: AutoSelect no DMA available\n", dev->name); + printk(KERN_INFO "proteon.c: AutoSelect no DMA available\n"); goto out2; } } @@ -231,25 +231,25 @@ static int __init setup_card(struct net_device *dev) break; if (dmalist[j] == 0) { - printk(KERN_INFO "%s: Illegal DMA %d specified\n", - dev->name, dev->dma); + printk(KERN_INFO "proteon.c: Illegal DMA %d specified\n", + dev->dma); goto out2; } if (request_dma(dev->dma, cardname)) { - printk(KERN_INFO "%s: Selected DMA %d not available\n", - dev->name, dev->dma); + printk(KERN_INFO "proteon.c: Selected DMA %d not available\n", + dev->dma); goto out2; } } - printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n", - dev->name, dev->base_addr, dev->irq, dev->dma); - err = register_netdev(dev); if (err) goto out; + printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n", + dev->name, dev->base_addr, dev->irq, dev->dma); + return 0; out: free_dma(dev->dma); @@ -258,34 +258,11 @@ out2: out3: tmsdev_term(dev); out4: - release_region(dev->base_addr, PROTEON_IO_EXTENT); + release_region(dev->base_addr, PROTEON_IO_EXTENT); +out5: return err; } -struct net_device * __init proteon_probe(int unit) -{ - struct net_device *dev = alloc_trdev(sizeof(struct net_local)); - int err = 0; - - if (!dev) - return ERR_PTR(-ENOMEM); - - if (unit >= 0) { - sprintf(dev->name, "tr%d", unit); - netdev_boot_setup_check(dev); - } - - err = setup_card(dev); - if (err) - goto out; - - return dev; - -out: - free_netdev(dev); - return ERR_PTR(err); -} - /* * Reads MAC address from adapter RAM, which should've read it from * the onboard ROM. @@ -352,8 +329,6 @@ static int proteon_open(struct net_device *dev) return tms380tr_open(dev); } -#ifdef MODULE - #define ISATR_MAX_ADAPTERS 3 static int io[ISATR_MAX_ADAPTERS]; @@ -366,13 +341,23 @@ module_param_array(io, int, NULL, 0); module_param_array(irq, int, NULL, 0); module_param_array(dma, int, NULL, 0); -static struct net_device *proteon_dev[ISATR_MAX_ADAPTERS]; +static struct platform_device *proteon_dev[ISATR_MAX_ADAPTERS]; + +static struct device_driver proteon_driver = { + .name = "proteon", + .bus = &platform_bus_type, +}; -int init_module(void) +static int __init proteon_init(void) { struct net_device *dev; + struct platform_device *pdev; int i, num = 0, err = 0; + err = driver_register(&proteon_driver); + if (err) + return err; + for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { dev = alloc_trdev(sizeof(struct net_local)); if (!dev) @@ -381,11 +366,15 @@ int init_module(void) dev->base_addr = io[i]; dev->irq = irq[i]; dev->dma = dma[i]; - err = setup_card(dev); + pdev = platform_device_register_simple("proteon", + i, NULL, 0); + err = setup_card(dev, &pdev->dev); if (!err) { - proteon_dev[i] = dev; + proteon_dev[i] = pdev; + dev_set_drvdata(&pdev->dev, dev); ++num; } else { + platform_device_unregister(pdev); free_netdev(dev); } } @@ -399,23 +388,28 @@ int init_module(void) return (0); } -void cleanup_module(void) +static void __exit proteon_cleanup(void) { + struct net_device *dev; int i; for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { - struct net_device *dev = proteon_dev[i]; + struct platform_device *pdev = proteon_dev[i]; - if (!dev) + if (!pdev) continue; - + dev = dev_get_drvdata(&pdev->dev); unregister_netdev(dev); release_region(dev->base_addr, PROTEON_IO_EXTENT); free_irq(dev->irq, dev); free_dma(dev->dma); tmsdev_term(dev); free_netdev(dev); + dev_set_drvdata(&pdev->dev, NULL); + platform_device_unregister(pdev); } + driver_unregister(&proteon_driver); } -#endif /* MODULE */ +module_init(proteon_init); +module_exit(proteon_cleanup); diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c index f26796e2d0e..3c7c66204f7 100644 --- a/drivers/net/tokenring/skisa.c +++ b/drivers/net/tokenring/skisa.c @@ -68,8 +68,7 @@ static int dmalist[] __initdata = { }; static char isa_cardname[] = "SK NET TR 4/16 ISA\0"; - -struct net_device *sk_isa_probe(int unit); +static u64 dma_mask = ISA_MAX_ADDRESS; static int sk_isa_open(struct net_device *dev); static void sk_isa_read_eeprom(struct net_device *dev); static unsigned short sk_isa_setnselout_pins(struct net_device *dev); @@ -133,7 +132,7 @@ static int __init sk_isa_probe1(struct net_device *dev, int ioaddr) return 0; } -static int __init setup_card(struct net_device *dev) +static int __init setup_card(struct net_device *dev, struct device *pdev) { struct net_local *tp; static int versionprinted; @@ -154,7 +153,7 @@ static int __init setup_card(struct net_device *dev) } } if (err) - goto out4; + goto out5; /* At this point we have found a valid card. */ @@ -162,14 +161,15 @@ static int __init setup_card(struct net_device *dev) printk(KERN_DEBUG "%s", version); err = -EIO; - if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL)) + pdev->dma_mask = &dma_mask; + if (tmsdev_init(dev, pdev)) goto out4; dev->base_addr &= ~3; sk_isa_read_eeprom(dev); - printk(KERN_DEBUG "%s: Ring Station Address: ", dev->name); + printk(KERN_DEBUG "skisa.c: Ring Station Address: "); printk("%2.2x", dev->dev_addr[0]); for (j = 1; j < 6; j++) printk(":%2.2x", dev->dev_addr[j]); @@ -202,7 +202,7 @@ static int __init setup_card(struct net_device *dev) if(irqlist[j] == 0) { - printk(KERN_INFO "%s: AutoSelect no IRQ available\n", dev->name); + printk(KERN_INFO "skisa.c: AutoSelect no IRQ available\n"); goto out3; } } @@ -213,15 +213,15 @@ static int __init setup_card(struct net_device *dev) break; if (irqlist[j] == 0) { - printk(KERN_INFO "%s: Illegal IRQ %d specified\n", - dev->name, dev->irq); + printk(KERN_INFO "skisa.c: Illegal IRQ %d specified\n", + dev->irq); goto out3; } if (request_irq(dev->irq, tms380tr_interrupt, 0, isa_cardname, dev)) { - printk(KERN_INFO "%s: Selected IRQ %d not available\n", - dev->name, dev->irq); + printk(KERN_INFO "skisa.c: Selected IRQ %d not available\n", + dev->irq); goto out3; } } @@ -237,7 +237,7 @@ static int __init setup_card(struct net_device *dev) if(dmalist[j] == 0) { - printk(KERN_INFO "%s: AutoSelect no DMA available\n", dev->name); + printk(KERN_INFO "skisa.c: AutoSelect no DMA available\n"); goto out2; } } @@ -248,25 +248,25 @@ static int __init setup_card(struct net_device *dev) break; if (dmalist[j] == 0) { - printk(KERN_INFO "%s: Illegal DMA %d specified\n", - dev->name, dev->dma); + printk(KERN_INFO "skisa.c: Illegal DMA %d specified\n", + dev->dma); goto out2; } if (request_dma(dev->dma, isa_cardname)) { - printk(KERN_INFO "%s: Selected DMA %d not available\n", - dev->name, dev->dma); + printk(KERN_INFO "skisa.c: Selected DMA %d not available\n", + dev->dma); goto out2; } } - printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n", - dev->name, dev->base_addr, dev->irq, dev->dma); - err = register_netdev(dev); if (err) goto out; + printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n", + dev->name, dev->base_addr, dev->irq, dev->dma); + return 0; out: free_dma(dev->dma); @@ -275,33 +275,11 @@ out2: out3: tmsdev_term(dev); out4: - release_region(dev->base_addr, SK_ISA_IO_EXTENT); + release_region(dev->base_addr, SK_ISA_IO_EXTENT); +out5: return err; } -struct net_device * __init sk_isa_probe(int unit) -{ - struct net_device *dev = alloc_trdev(sizeof(struct net_local)); - int err = 0; - - if (!dev) - return ERR_PTR(-ENOMEM); - - if (unit >= 0) { - sprintf(dev->name, "tr%d", unit); - netdev_boot_setup_check(dev); - } - - err = setup_card(dev); - if (err) - goto out; - - return dev; -out: - free_netdev(dev); - return ERR_PTR(err); -} - /* * Reads MAC address from adapter RAM, which should've read it from * the onboard ROM. @@ -361,8 +339,6 @@ static int sk_isa_open(struct net_device *dev) return tms380tr_open(dev); } -#ifdef MODULE - #define ISATR_MAX_ADAPTERS 3 static int io[ISATR_MAX_ADAPTERS]; @@ -375,13 +351,23 @@ module_param_array(io, int, NULL, 0); module_param_array(irq, int, NULL, 0); module_param_array(dma, int, NULL, 0); -static struct net_device *sk_isa_dev[ISATR_MAX_ADAPTERS]; +static struct platform_device *sk_isa_dev[ISATR_MAX_ADAPTERS]; -int init_module(void) +static struct device_driver sk_isa_driver = { + .name = "skisa", + .bus = &platform_bus_type, +}; + +static int __init sk_isa_init(void) { struct net_device *dev; + struct platform_device *pdev; int i, num = 0, err = 0; + err = driver_register(&sk_isa_driver); + if (err) + return err; + for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { dev = alloc_trdev(sizeof(struct net_local)); if (!dev) @@ -390,12 +376,15 @@ int init_module(void) dev->base_addr = io[i]; dev->irq = irq[i]; dev->dma = dma[i]; - err = setup_card(dev); - + pdev = platform_device_register_simple("skisa", + i, NULL, 0); + err = setup_card(dev, &pdev->dev); if (!err) { - sk_isa_dev[i] = dev; + sk_isa_dev[i] = pdev; + dev_set_drvdata(&sk_isa_dev[i]->dev, dev); ++num; } else { + platform_device_unregister(pdev); free_netdev(dev); } } @@ -409,23 +398,28 @@ int init_module(void) return (0); } -void cleanup_module(void) +static void __exit sk_isa_cleanup(void) { + struct net_device *dev; int i; for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { - struct net_device *dev = sk_isa_dev[i]; + struct platform_device *pdev = sk_isa_dev[i]; - if (!dev) + if (!pdev) continue; - + dev = dev_get_drvdata(&pdev->dev); unregister_netdev(dev); release_region(dev->base_addr, SK_ISA_IO_EXTENT); free_irq(dev->irq, dev); free_dma(dev->dma); tmsdev_term(dev); free_netdev(dev); + dev_set_drvdata(&pdev->dev, NULL); + platform_device_unregister(pdev); } + driver_unregister(&sk_isa_driver); } -#endif /* MODULE */ +module_init(sk_isa_init); +module_exit(sk_isa_cleanup); diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index 5e0b0ce98ed..2e39bf1f746 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -62,6 +62,7 @@ * normal operation. * 30-Dec-02 JF Removed incorrect __init from * tms380tr_init_card. + * 22-Jul-05 JF Converted to dma-mapping. * * To do: * 1. Multi/Broadcast packet handling (this may have fixed itself) @@ -89,7 +90,7 @@ static const char version[] = "tms380tr.c: v1.10 30/12/2002 by Christoph Goos, A #include <linux/time.h> #include <linux/errno.h> #include <linux/init.h> -#include <linux/pci.h> +#include <linux/dma-mapping.h> #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> @@ -114,8 +115,6 @@ static const char version[] = "tms380tr.c: v1.10 30/12/2002 by Christoph Goos, A #endif static unsigned int tms380tr_debug = TMS380TR_DEBUG; -static struct device tms_device; - /* Index to functions, as function prototypes. * Alphabetical by function name. */ @@ -434,7 +433,7 @@ static void tms380tr_init_net_local(struct net_device *dev) skb_put(tp->Rpl[i].Skb, tp->MaxPacketSize); /* data unreachable for DMA ? then use local buffer */ - dmabuf = pci_map_single(tp->pdev, tp->Rpl[i].Skb->data, tp->MaxPacketSize, PCI_DMA_FROMDEVICE); + dmabuf = dma_map_single(tp->pdev, tp->Rpl[i].Skb->data, tp->MaxPacketSize, DMA_FROM_DEVICE); if(tp->dmalimit && (dmabuf + tp->MaxPacketSize > tp->dmalimit)) { tp->Rpl[i].SkbStat = SKB_DATA_COPY; @@ -638,10 +637,10 @@ static int tms380tr_hardware_send_packet(struct sk_buff *skb, struct net_device /* Is buffer reachable for Busmaster-DMA? */ length = skb->len; - dmabuf = pci_map_single(tp->pdev, skb->data, length, PCI_DMA_TODEVICE); + dmabuf = dma_map_single(tp->pdev, skb->data, length, DMA_TO_DEVICE); if(tp->dmalimit && (dmabuf + length > tp->dmalimit)) { /* Copy frame to local buffer */ - pci_unmap_single(tp->pdev, dmabuf, length, PCI_DMA_TODEVICE); + dma_unmap_single(tp->pdev, dmabuf, length, DMA_TO_DEVICE); dmabuf = 0; i = tp->TplFree->TPLIndex; buf = tp->LocalTxBuffers[i]; @@ -1284,9 +1283,7 @@ static int tms380tr_reset_adapter(struct net_device *dev) unsigned short count, c, count2; const struct firmware *fw_entry = NULL; - strncpy(tms_device.bus_id,dev->name, BUS_ID_SIZE); - - if (request_firmware(&fw_entry, "tms380tr.bin", &tms_device) != 0) { + if (request_firmware(&fw_entry, "tms380tr.bin", tp->pdev) != 0) { printk(KERN_ALERT "%s: firmware %s is missing, cannot start.\n", dev->name, "tms380tr.bin"); return (-1); @@ -2021,7 +2018,7 @@ static void tms380tr_cancel_tx_queue(struct net_local* tp) printk(KERN_INFO "Cancel tx (%08lXh).\n", (unsigned long)tpl); if (tpl->DMABuff) - pci_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, PCI_DMA_TODEVICE); + dma_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(tpl->Skb); } @@ -2090,7 +2087,7 @@ static void tms380tr_tx_status_irq(struct net_device *dev) tp->MacStat.tx_packets++; if (tpl->DMABuff) - pci_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, PCI_DMA_TODEVICE); + dma_unmap_single(tp->pdev, tpl->DMABuff, tpl->Skb->len, DMA_TO_DEVICE); dev_kfree_skb_irq(tpl->Skb); tpl->BusyFlag = 0; /* "free" TPL */ } @@ -2209,7 +2206,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev) tp->MacStat.rx_errors++; } if (rpl->DMABuff) - pci_unmap_single(tp->pdev, rpl->DMABuff, tp->MaxPacketSize, PCI_DMA_TODEVICE); + dma_unmap_single(tp->pdev, rpl->DMABuff, tp->MaxPacketSize, DMA_TO_DEVICE); rpl->DMABuff = 0; /* Allocate new skb for rpl */ @@ -2227,7 +2224,7 @@ static void tms380tr_rcv_status_irq(struct net_device *dev) skb_put(rpl->Skb, tp->MaxPacketSize); /* Data unreachable for DMA ? then use local buffer */ - dmabuf = pci_map_single(tp->pdev, rpl->Skb->data, tp->MaxPacketSize, PCI_DMA_FROMDEVICE); + dmabuf = dma_map_single(tp->pdev, rpl->Skb->data, tp->MaxPacketSize, DMA_FROM_DEVICE); if(tp->dmalimit && (dmabuf + tp->MaxPacketSize > tp->dmalimit)) { rpl->SkbStat = SKB_DATA_COPY; @@ -2332,23 +2329,26 @@ void tmsdev_term(struct net_device *dev) struct net_local *tp; tp = netdev_priv(dev); - pci_unmap_single(tp->pdev, tp->dmabuffer, sizeof(struct net_local), - PCI_DMA_BIDIRECTIONAL); + dma_unmap_single(tp->pdev, tp->dmabuffer, sizeof(struct net_local), + DMA_BIDIRECTIONAL); } -int tmsdev_init(struct net_device *dev, unsigned long dmalimit, - struct pci_dev *pdev) +int tmsdev_init(struct net_device *dev, struct device *pdev) { struct net_local *tms_local; memset(dev->priv, 0, sizeof(struct net_local)); tms_local = netdev_priv(dev); init_waitqueue_head(&tms_local->wait_for_tok_int); - tms_local->dmalimit = dmalimit; + if (pdev->dma_mask) + tms_local->dmalimit = *pdev->dma_mask; + else + return -ENOMEM; tms_local->pdev = pdev; - tms_local->dmabuffer = pci_map_single(pdev, (void *)tms_local, - sizeof(struct net_local), PCI_DMA_BIDIRECTIONAL); - if (tms_local->dmabuffer + sizeof(struct net_local) > dmalimit) + tms_local->dmabuffer = dma_map_single(pdev, (void *)tms_local, + sizeof(struct net_local), DMA_BIDIRECTIONAL); + if (tms_local->dmabuffer + sizeof(struct net_local) > + tms_local->dmalimit) { printk(KERN_INFO "%s: Memory not accessible for DMA\n", dev->name); @@ -2370,8 +2370,6 @@ int tmsdev_init(struct net_device *dev, unsigned long dmalimit, return 0; } -#ifdef MODULE - EXPORT_SYMBOL(tms380tr_open); EXPORT_SYMBOL(tms380tr_close); EXPORT_SYMBOL(tms380tr_interrupt); @@ -2379,6 +2377,8 @@ EXPORT_SYMBOL(tmsdev_init); EXPORT_SYMBOL(tmsdev_term); EXPORT_SYMBOL(tms380tr_wait); +#ifdef MODULE + static struct module *TMS380_module = NULL; int init_module(void) diff --git a/drivers/net/tokenring/tms380tr.h b/drivers/net/tokenring/tms380tr.h index f2c5ba0f37a..30452c67bb6 100644 --- a/drivers/net/tokenring/tms380tr.h +++ b/drivers/net/tokenring/tms380tr.h @@ -17,8 +17,7 @@ int tms380tr_open(struct net_device *dev); int tms380tr_close(struct net_device *dev); irqreturn_t tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs); -int tmsdev_init(struct net_device *dev, unsigned long dmalimit, - struct pci_dev *pdev); +int tmsdev_init(struct net_device *dev, struct device *pdev); void tmsdev_term(struct net_device *dev); void tms380tr_wait(unsigned long time); @@ -719,7 +718,7 @@ struct s_TPL { /* Transmit Parameter List (align on even word boundaries) */ struct sk_buff *Skb; unsigned char TPLIndex; volatile unsigned char BusyFlag;/* Flag: TPL busy? */ - dma_addr_t DMABuff; /* DMA IO bus address from pci_map */ + dma_addr_t DMABuff; /* DMA IO bus address from dma_map */ }; /* ---------------------Receive Functions-------------------------------* @@ -1060,7 +1059,7 @@ struct s_RPL { /* Receive Parameter List */ struct sk_buff *Skb; SKB_STAT SkbStat; int RPLIndex; - dma_addr_t DMABuff; /* DMA IO bus address from pci_map */ + dma_addr_t DMABuff; /* DMA IO bus address from dma_map */ }; /* Information that need to be kept for each board. */ @@ -1091,7 +1090,7 @@ typedef struct net_local { RPL *RplTail; unsigned char LocalRxBuffers[RPL_NUM][DEFAULT_PACKET_SIZE]; - struct pci_dev *pdev; + struct device *pdev; int DataRate; unsigned char ScbInUse; unsigned short CMDqueue; diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c index 2e18c0a4648..ab47c0547a3 100644 --- a/drivers/net/tokenring/tmspci.c +++ b/drivers/net/tokenring/tmspci.c @@ -100,7 +100,7 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic unsigned int pci_irq_line; unsigned long pci_ioaddr; struct card_info *cardinfo = &card_info_table[ent->driver_data]; - + if (versionprinted++ == 0) printk("%s", version); @@ -143,7 +143,7 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic printk(":%2.2x", dev->dev_addr[i]); printk("\n"); - ret = tmsdev_init(dev, PCI_MAX_ADDRESS, pdev); + ret = tmsdev_init(dev, &pdev->dev); if (ret) { printk("%s: unable to get memory for dev->priv.\n", dev->name); goto err_out_irq; diff --git a/drivers/net/tulip/Kconfig b/drivers/net/tulip/Kconfig index e2cdaf87620..8c9634a98c1 100644 --- a/drivers/net/tulip/Kconfig +++ b/drivers/net/tulip/Kconfig @@ -135,6 +135,18 @@ config DM9102 <file:Documentation/networking/net-modules.txt>. The module will be called dmfe. +config ULI526X + tristate "ULi M526x controller support" + depends on NET_TULIP && PCI + select CRC32 + ---help--- + This driver is for ULi M5261/M5263 10/100M Ethernet Controller + (<http://www.uli.com.tw/>). + + To compile this driver as a module, choose M here and read + <file:Documentation/networking/net-modules.txt>. The module will + be called uli526x. + config PCMCIA_XIRCOM tristate "Xircom CardBus support (new driver)" depends on NET_TULIP && CARDBUS diff --git a/drivers/net/tulip/Makefile b/drivers/net/tulip/Makefile index 8bb9b468397..451090d6fcc 100644 --- a/drivers/net/tulip/Makefile +++ b/drivers/net/tulip/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_WINBOND_840) += winbond-840.o obj-$(CONFIG_DE2104X) += de2104x.o obj-$(CONFIG_TULIP) += tulip.o obj-$(CONFIG_DE4X5) += de4x5.o +obj-$(CONFIG_ULI526X) += uli526x.o # Declare multi-part drivers. diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c index e26c31f944b..f53396fe79c 100644 --- a/drivers/net/tulip/media.c +++ b/drivers/net/tulip/media.c @@ -81,25 +81,6 @@ int tulip_mdio_read(struct net_device *dev, int phy_id, int location) return retval & 0xffff; } - if(tp->chip_id == ULI526X && tp->revision >= 0x40) { - int value; - int i = 1000; - - value = ioread32(ioaddr + CSR9); - iowrite32(value & 0xFFEFFFFF, ioaddr + CSR9); - - value = (phy_id << 21) | (location << 16) | 0x08000000; - iowrite32(value, ioaddr + CSR10); - - while(--i > 0) { - mdio_delay(); - if(ioread32(ioaddr + CSR10) & 0x10000000) - break; - } - retval = ioread32(ioaddr + CSR10); - spin_unlock_irqrestore(&tp->mii_lock, flags); - return retval & 0xFFFF; - } /* Establish sync by sending at least 32 logic ones. */ for (i = 32; i >= 0; i--) { iowrite32(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr); @@ -159,23 +140,6 @@ void tulip_mdio_write(struct net_device *dev, int phy_id, int location, int val) spin_unlock_irqrestore(&tp->mii_lock, flags); return; } - if (tp->chip_id == ULI526X && tp->revision >= 0x40) { - int value; - int i = 1000; - - value = ioread32(ioaddr + CSR9); - iowrite32(value & 0xFFEFFFFF, ioaddr + CSR9); - - value = (phy_id << 21) | (location << 16) | 0x04000000 | (val & 0xFFFF); - iowrite32(value, ioaddr + CSR10); - - while(--i > 0) { - if (ioread32(ioaddr + CSR10) & 0x10000000) - break; - } - spin_unlock_irqrestore(&tp->mii_lock, flags); - return; - } /* Establish sync by sending 32 logic ones. */ for (i = 32; i >= 0; i--) { diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c index 69156828355..e058a9fbfe8 100644 --- a/drivers/net/tulip/timer.c +++ b/drivers/net/tulip/timer.c @@ -39,7 +39,6 @@ void tulip_timer(unsigned long data) case MX98713: case COMPEX9881: case DM910X: - case ULI526X: default: { struct medialeaf *mleaf; unsigned char *p; diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h index 20346d847d9..05d2d96f7be 100644 --- a/drivers/net/tulip/tulip.h +++ b/drivers/net/tulip/tulip.h @@ -88,7 +88,6 @@ enum chips { I21145, DM910X, CONEXANT, - ULI526X }; @@ -482,11 +481,8 @@ static inline void tulip_stop_rxtx(struct tulip_private *tp) static inline void tulip_restart_rxtx(struct tulip_private *tp) { - if(!(tp->chip_id == ULI526X && - (tp->revision == 0x40 || tp->revision == 0x50))) { - tulip_stop_rxtx(tp); - udelay(5); - } + tulip_stop_rxtx(tp); + udelay(5); tulip_start_rxtx(tp); } diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index d45d8f56e5b..05da5bea564 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -199,9 +199,6 @@ struct tulip_chip_table tulip_tbl[] = { { "Conexant LANfinity", 256, 0x0001ebef, HAS_MII | HAS_ACPI, tulip_timer }, - /* ULi526X */ - { "ULi M5261/M5263", 128, 0x0001ebef, - HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_ACPI, tulip_timer }, }; @@ -239,8 +236,6 @@ static struct pci_device_id tulip_pci_tbl[] = { { 0x1737, 0xAB09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x1737, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, { 0x17B3, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, - { 0x10b9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ULI526X }, /* ALi 1563 integrated ethernet */ - { 0x10b9, 0x5263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ULI526X }, /* ALi 1563 integrated ethernet */ { 0x10b7, 0x9300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* 3Com 3CSOHO100B-TX */ { 0x14ea, 0xab08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* Planex FNW-3602-TX */ { } /* terminate list */ @@ -522,7 +517,7 @@ static void tulip_tx_timeout(struct net_device *dev) dev->name); } else if (tp->chip_id == DC21140 || tp->chip_id == DC21142 || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881 - || tp->chip_id == DM910X || tp->chip_id == ULI526X) { + || tp->chip_id == DM910X) { printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, " "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n", dev->name, ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12), @@ -1103,18 +1098,16 @@ static void set_rx_mode(struct net_device *dev) entry = tp->cur_tx++ % TX_RING_SIZE; if (entry != 0) { - /* Avoid a chip errata by prefixing a dummy entry. Don't do - this on the ULI526X as it triggers a different problem */ - if (!(tp->chip_id == ULI526X && (tp->revision == 0x40 || tp->revision == 0x50))) { - tp->tx_buffers[entry].skb = NULL; - tp->tx_buffers[entry].mapping = 0; - tp->tx_ring[entry].length = - (entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0; - tp->tx_ring[entry].buffer1 = 0; - /* Must set DescOwned later to avoid race with chip */ - dummy = entry; - entry = tp->cur_tx++ % TX_RING_SIZE; - } + /* Avoid a chip errata by prefixing a dummy entry. */ + tp->tx_buffers[entry].skb = NULL; + tp->tx_buffers[entry].mapping = 0; + tp->tx_ring[entry].length = + (entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0; + tp->tx_ring[entry].buffer1 = 0; + /* Must set DescOwned later to avoid race with chip */ + dummy = entry; + entry = tp->cur_tx++ % TX_RING_SIZE; + } tp->tx_buffers[entry].skb = NULL; @@ -1235,10 +1228,6 @@ static int tulip_uli_dm_quirk(struct pci_dev *pdev) { if (pdev->vendor == 0x1282 && pdev->device == 0x9102) return 1; - if (pdev->vendor == 0x10b9 && pdev->device == 0x5261) - return 1; - if (pdev->vendor == 0x10b9 && pdev->device == 0x5263) - return 1; return 0; } @@ -1680,7 +1669,6 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, switch (chip_idx) { case DC21140: case DM910X: - case ULI526X: default: if (tp->mtable) iowrite32(tp->mtable->csr12dir | 0x100, ioaddr + CSR12); diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c new file mode 100644 index 00000000000..5ae22b7bc5c --- /dev/null +++ b/drivers/net/tulip/uli526x.c @@ -0,0 +1,1749 @@ +/* + 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. + + +*/ + +#define DRV_NAME "uli526x" +#define DRV_VERSION "0.9.3" +#define DRV_RELDATE "2005-7-29" + +#include <linux/module.h> + +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/ptrace.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/skbuff.h> +#include <linux/delay.h> +#include <linux/spinlock.h> + +#include <asm/processor.h> +#include <asm/bitops.h> +#include <asm/io.h> +#include <asm/dma.h> +#include <asm/uaccess.h> + + +/* Board/System/Debug information/definition ---------------- */ +#define PCI_ULI5261_ID 0x526110B9 /* ULi M5261 ID*/ +#define PCI_ULI5263_ID 0x526310B9 /* ULi M5263 ID*/ + +#define ULI526X_IO_SIZE 0x100 +#define TX_DESC_CNT 0x20 /* Allocated Tx descriptors */ +#define RX_DESC_CNT 0x30 /* Allocated Rx descriptors */ +#define TX_FREE_DESC_CNT (TX_DESC_CNT - 2) /* Max TX packet count */ +#define TX_WAKE_DESC_CNT (TX_DESC_CNT - 3) /* TX wakeup count */ +#define DESC_ALL_CNT (TX_DESC_CNT + RX_DESC_CNT) +#define TX_BUF_ALLOC 0x600 +#define RX_ALLOC_SIZE 0x620 +#define ULI526X_RESET 1 +#define CR0_DEFAULT 0 +#define CR6_DEFAULT 0x22200000 +#define CR7_DEFAULT 0x180c1 +#define CR15_DEFAULT 0x06 /* TxJabber RxWatchdog */ +#define TDES0_ERR_MASK 0x4302 /* TXJT, LC, EC, FUE */ +#define MAX_PACKET_SIZE 1514 +#define ULI5261_MAX_MULTICAST 14 +#define RX_COPY_SIZE 100 +#define MAX_CHECK_PACKET 0x8000 + +#define ULI526X_10MHF 0 +#define ULI526X_100MHF 1 +#define ULI526X_10MFD 4 +#define ULI526X_100MFD 5 +#define ULI526X_AUTO 8 + +#define ULI526X_TXTH_72 0x400000 /* TX TH 72 byte */ +#define ULI526X_TXTH_96 0x404000 /* TX TH 96 byte */ +#define ULI526X_TXTH_128 0x0000 /* TX TH 128 byte */ +#define ULI526X_TXTH_256 0x4000 /* TX TH 256 byte */ +#define ULI526X_TXTH_512 0x8000 /* TX TH 512 byte */ +#define ULI526X_TXTH_1K 0xC000 /* TX TH 1K byte */ + +#define ULI526X_TIMER_WUT (jiffies + HZ * 1)/* timer wakeup time : 1 second */ +#define ULI526X_TX_TIMEOUT ((16*HZ)/2) /* tx packet time-out time 8 s" */ +#define ULI526X_TX_KICK (4*HZ/2) /* tx packet Kick-out time 2 s" */ + +#define ULI526X_DBUG(dbug_now, msg, value) if (uli526x_debug || (dbug_now)) printk(KERN_ERR DRV_NAME ": %s %lx\n", (msg), (long) (value)) + +#define SHOW_MEDIA_TYPE(mode) printk(KERN_ERR DRV_NAME ": Change Speed to %sMhz %s duplex\n",mode & 1 ?"100":"10", mode & 4 ? "full":"half"); + + +/* CR9 definition: SROM/MII */ +#define CR9_SROM_READ 0x4800 +#define CR9_SRCS 0x1 +#define CR9_SRCLK 0x2 +#define CR9_CRDOUT 0x8 +#define SROM_DATA_0 0x0 +#define SROM_DATA_1 0x4 +#define PHY_DATA_1 0x20000 +#define PHY_DATA_0 0x00000 +#define MDCLKH 0x10000 + +#define PHY_POWER_DOWN 0x800 + +#define SROM_V41_CODE 0x14 + +#define SROM_CLK_WRITE(data, ioaddr) \ + outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr); \ + udelay(5); \ + outl(data|CR9_SROM_READ|CR9_SRCS|CR9_SRCLK,ioaddr); \ + udelay(5); \ + outl(data|CR9_SROM_READ|CR9_SRCS,ioaddr); \ + udelay(5); + +/* Structure/enum declaration ------------------------------- */ +struct tx_desc { + u32 tdes0, tdes1, tdes2, tdes3; /* Data for the card */ + char *tx_buf_ptr; /* Data for us */ + struct tx_desc *next_tx_desc; +} __attribute__(( aligned(32) )); + +struct rx_desc { + u32 rdes0, rdes1, rdes2, rdes3; /* Data for the card */ + struct sk_buff *rx_skb_ptr; /* Data for us */ + struct rx_desc *next_rx_desc; +} __attribute__(( aligned(32) )); + +struct uli526x_board_info { + u32 chip_id; /* Chip vendor/Device ID */ + struct net_device *next_dev; /* next device */ + struct pci_dev *pdev; /* PCI device */ + spinlock_t lock; + + long ioaddr; /* I/O base address */ + u32 cr0_data; + u32 cr5_data; + u32 cr6_data; + u32 cr7_data; + u32 cr15_data; + + /* pointer for memory physical address */ + dma_addr_t buf_pool_dma_ptr; /* Tx buffer pool memory */ + dma_addr_t buf_pool_dma_start; /* Tx buffer pool align dword */ + dma_addr_t desc_pool_dma_ptr; /* descriptor pool memory */ + dma_addr_t first_tx_desc_dma; + dma_addr_t first_rx_desc_dma; + + /* descriptor pointer */ + unsigned char *buf_pool_ptr; /* Tx buffer pool memory */ + unsigned char *buf_pool_start; /* Tx buffer pool align dword */ + unsigned char *desc_pool_ptr; /* descriptor pool memory */ + struct tx_desc *first_tx_desc; + struct tx_desc *tx_insert_ptr; + struct tx_desc *tx_remove_ptr; + struct rx_desc *first_rx_desc; + struct rx_desc *rx_insert_ptr; + struct rx_desc *rx_ready_ptr; /* packet come pointer */ + unsigned long tx_packet_cnt; /* transmitted packet count */ + unsigned long rx_avail_cnt; /* available rx descriptor count */ + unsigned long interval_rx_cnt; /* rx packet count a callback time */ + + u16 dbug_cnt; + u16 NIC_capability; /* NIC media capability */ + u16 PHY_reg4; /* Saved Phyxcer register 4 value */ + + u8 media_mode; /* user specify media mode */ + u8 op_mode; /* real work media mode */ + u8 phy_addr; + u8 link_failed; /* Ever link failed */ + u8 wait_reset; /* Hardware failed, need to reset */ + struct timer_list timer; + + /* System defined statistic counter */ + struct net_device_stats stats; + + /* Driver defined statistic counter */ + unsigned long tx_fifo_underrun; + unsigned long tx_loss_carrier; + unsigned long tx_no_carrier; + unsigned long tx_late_collision; + unsigned long tx_excessive_collision; + unsigned long tx_jabber_timeout; + unsigned long reset_count; + unsigned long reset_cr8; + unsigned long reset_fatal; + unsigned long reset_TXtimeout; + + /* NIC SROM data */ + unsigned char srom[128]; + u8 init; +}; + +enum uli526x_offsets { + DCR0 = 0x00, DCR1 = 0x08, DCR2 = 0x10, DCR3 = 0x18, DCR4 = 0x20, + DCR5 = 0x28, DCR6 = 0x30, DCR7 = 0x38, DCR8 = 0x40, DCR9 = 0x48, + DCR10 = 0x50, DCR11 = 0x58, DCR12 = 0x60, DCR13 = 0x68, DCR14 = 0x70, + DCR15 = 0x78 +}; + +enum uli526x_CR6_bits { + CR6_RXSC = 0x2, CR6_PBF = 0x8, CR6_PM = 0x40, CR6_PAM = 0x80, + CR6_FDM = 0x200, CR6_TXSC = 0x2000, CR6_STI = 0x100000, + CR6_SFT = 0x200000, CR6_RXA = 0x40000000, CR6_NO_PURGE = 0x20000000 +}; + +/* Global variable declaration ----------------------------- */ +static int __devinitdata printed_version; +static char version[] __devinitdata = + KERN_INFO DRV_NAME ": ULi M5261/M5263 net driver, version " + DRV_VERSION " (" DRV_RELDATE ")\n"; + +static int uli526x_debug; +static unsigned char uli526x_media_mode = ULI526X_AUTO; +static u32 uli526x_cr6_user_set; + +/* For module input parameter */ +static int debug; +static u32 cr6set; +static unsigned char mode = 8; + +/* function declaration ------------------------------------- */ +static int uli526x_open(struct net_device *); +static int uli526x_start_xmit(struct sk_buff *, struct net_device *); +static int uli526x_stop(struct net_device *); +static struct net_device_stats * uli526x_get_stats(struct net_device *); +static void uli526x_set_filter_mode(struct net_device *); +static struct ethtool_ops netdev_ethtool_ops; +static u16 read_srom_word(long, int); +static irqreturn_t uli526x_interrupt(int, void *, struct pt_regs *); +static void uli526x_descriptor_init(struct uli526x_board_info *, unsigned long); +static void allocate_rx_buffer(struct uli526x_board_info *); +static void update_cr6(u32, unsigned long); +static void send_filter_frame(struct net_device *, int); +static u16 phy_read(unsigned long, u8, u8, u32); +static u16 phy_readby_cr10(unsigned long, u8, u8); +static void phy_write(unsigned long, u8, u8, u16, u32); +static void phy_writeby_cr10(unsigned long, u8, u8, u16); +static void phy_write_1bit(unsigned long, u32, u32); +static u16 phy_read_1bit(unsigned long, u32); +static u8 uli526x_sense_speed(struct uli526x_board_info *); +static void uli526x_process_mode(struct uli526x_board_info *); +static void uli526x_timer(unsigned long); +static void uli526x_rx_packet(struct net_device *, struct uli526x_board_info *); +static void uli526x_free_tx_pkt(struct net_device *, struct uli526x_board_info *); +static void uli526x_reuse_skb(struct uli526x_board_info *, struct sk_buff *); +static void uli526x_dynamic_reset(struct net_device *); +static void uli526x_free_rxbuffer(struct uli526x_board_info *); +static void uli526x_init(struct net_device *); +static void uli526x_set_phyxcer(struct uli526x_board_info *); + +/* ULI526X network board routine ---------------------------- */ + +/* + * Search ULI526X board, allocate space and register it + */ + +static int __devinit uli526x_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct uli526x_board_info *db; /* board information structure */ + struct net_device *dev; + int i, err; + + ULI526X_DBUG(0, "uli526x_init_one()", 0); + + if (!printed_version++) + printk(version); + + /* Init network device */ + dev = alloc_etherdev(sizeof(*db)); + if (dev == NULL) + return -ENOMEM; + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pdev->dev); + + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { + printk(KERN_WARNING DRV_NAME ": 32-bit PCI DMA not available.\n"); + err = -ENODEV; + goto err_out_free; + } + + /* Enable Master/IO access, Disable memory access */ + err = pci_enable_device(pdev); + if (err) + goto err_out_free; + + if (!pci_resource_start(pdev, 0)) { + printk(KERN_ERR DRV_NAME ": I/O base is zero\n"); + err = -ENODEV; + goto err_out_disable; + } + + if (pci_resource_len(pdev, 0) < (ULI526X_IO_SIZE) ) { + printk(KERN_ERR DRV_NAME ": Allocated I/O size too small\n"); + err = -ENODEV; + goto err_out_disable; + } + + if (pci_request_regions(pdev, DRV_NAME)) { + printk(KERN_ERR DRV_NAME ": Failed to request PCI regions\n"); + err = -ENODEV; + goto err_out_disable; + } + + /* Init system & device */ + db = netdev_priv(dev); + + /* Allocate Tx/Rx descriptor memory */ + db->desc_pool_ptr = pci_alloc_consistent(pdev, sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, &db->desc_pool_dma_ptr); + if(db->desc_pool_ptr == NULL) + { + err = -ENOMEM; + goto err_out_nomem; + } + db->buf_pool_ptr = pci_alloc_consistent(pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4, &db->buf_pool_dma_ptr); + if(db->buf_pool_ptr == NULL) + { + err = -ENOMEM; + goto err_out_nomem; + } + + db->first_tx_desc = (struct tx_desc *) db->desc_pool_ptr; + db->first_tx_desc_dma = db->desc_pool_dma_ptr; + db->buf_pool_start = db->buf_pool_ptr; + db->buf_pool_dma_start = db->buf_pool_dma_ptr; + + db->chip_id = ent->driver_data; + db->ioaddr = pci_resource_start(pdev, 0); + + db->pdev = pdev; + db->init = 1; + + dev->base_addr = db->ioaddr; + dev->irq = pdev->irq; + pci_set_drvdata(pdev, dev); + + /* Register some necessary functions */ + dev->open = &uli526x_open; + dev->hard_start_xmit = &uli526x_start_xmit; + dev->stop = &uli526x_stop; + dev->get_stats = &uli526x_get_stats; + dev->set_multicast_list = &uli526x_set_filter_mode; + dev->ethtool_ops = &netdev_ethtool_ops; + spin_lock_init(&db->lock); + + + /* read 64 word srom data */ + for (i = 0; i < 64; i++) + ((u16 *) db->srom)[i] = cpu_to_le16(read_srom_word(db->ioaddr, i)); + + /* Set Node address */ + if(((u16 *) db->srom)[0] == 0xffff || ((u16 *) db->srom)[0] == 0) /* SROM absent, so read MAC address from ID Table */ + { + outl(0x10000, db->ioaddr + DCR0); //Diagnosis mode + outl(0x1c0, db->ioaddr + DCR13); //Reset dianostic pointer port + outl(0, db->ioaddr + DCR14); //Clear reset port + outl(0x10, db->ioaddr + DCR14); //Reset ID Table pointer + outl(0, db->ioaddr + DCR14); //Clear reset port + outl(0, db->ioaddr + DCR13); //Clear CR13 + outl(0x1b0, db->ioaddr + DCR13); //Select ID Table access port + //Read MAC address from CR14 + for (i = 0; i < 6; i++) + dev->dev_addr[i] = inl(db->ioaddr + DCR14); + //Read end + outl(0, db->ioaddr + DCR13); //Clear CR13 + outl(0, db->ioaddr + DCR0); //Clear CR0 + udelay(10); + } + else /*Exist SROM*/ + { + for (i = 0; i < 6; i++) + dev->dev_addr[i] = db->srom[20 + i]; + } + err = register_netdev (dev); + if (err) + goto err_out_res; + + printk(KERN_INFO "%s: ULi M%04lx at pci%s,",dev->name,ent->driver_data >> 16,pci_name(pdev)); + + for (i = 0; i < 6; i++) + printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); + printk(", irq %d.\n", dev->irq); + + pci_set_master(pdev); + + return 0; + +err_out_res: + pci_release_regions(pdev); +err_out_nomem: + if(db->desc_pool_ptr) + pci_free_consistent(pdev, sizeof(struct tx_desc) * DESC_ALL_CNT + 0x20, + db->desc_pool_ptr, db->desc_pool_dma_ptr); + + if(db->buf_pool_ptr != NULL) + pci_free_consistent(pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4, + db->buf_pool_ptr, db->buf_pool_dma_ptr); +err_out_disable: + pci_disable_device(pdev); +err_out_free: + pci_set_drvdata(pdev, NULL); + free_netdev(dev); + + return err; +} + + +static void __devexit uli526x_remove_one (struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct uli526x_board_info *db = netdev_priv(dev); + + ULI526X_DBUG(0, "uli526x_remove_one()", 0); + + pci_free_consistent(db->pdev, sizeof(struct tx_desc) * + DESC_ALL_CNT + 0x20, db->desc_pool_ptr, + db->desc_pool_dma_ptr); + pci_free_consistent(db->pdev, TX_BUF_ALLOC * TX_DESC_CNT + 4, + db->buf_pool_ptr, db->buf_pool_dma_ptr); + unregister_netdev(dev); + pci_release_regions(pdev); + free_netdev(dev); /* free board information */ + pci_set_drvdata(pdev, NULL); + pci_disable_device(pdev); + ULI526X_DBUG(0, "uli526x_remove_one() exit", 0); +} + + +/* + * Open the interface. + * The interface is opened whenever "ifconfig" activates it. + */ + +static int uli526x_open(struct net_device *dev) +{ + int ret; + struct uli526x_board_info *db = netdev_priv(dev); + + ULI526X_DBUG(0, "uli526x_open", 0); + + ret = request_irq(dev->irq, &uli526x_interrupt, SA_SHIRQ, dev->name, dev); + if (ret) + return ret; + + /* system variable init */ + db->cr6_data = CR6_DEFAULT | uli526x_cr6_user_set; + db->tx_packet_cnt = 0; + db->rx_avail_cnt = 0; + db->link_failed = 1; + netif_carrier_off(dev); + db->wait_reset = 0; + + db->NIC_capability = 0xf; /* All capability*/ + db->PHY_reg4 = 0x1e0; + + /* CR6 operation mode decision */ + db->cr6_data |= ULI526X_TXTH_256; + db->cr0_data = CR0_DEFAULT; + + /* Initialize ULI526X board */ + uli526x_init(dev); + + /* Active System Interface */ + netif_wake_queue(dev); + + /* set and active a timer process */ + init_timer(&db->timer); + db->timer.expires = ULI526X_TIMER_WUT + HZ * 2; + db->timer.data = (unsigned long)dev; + db->timer.function = &uli526x_timer; + add_timer(&db->timer); + + return 0; +} + + +/* Initialize ULI526X board + * Reset ULI526X board + * Initialize TX/Rx descriptor chain structure + * Send the set-up frame + * Enable Tx/Rx machine + */ + +static void uli526x_init(struct net_device *dev) +{ + struct uli526x_board_info *db = netdev_priv(dev); + unsigned long ioaddr = db->ioaddr; + u8 phy_tmp; + u16 phy_value; + u16 phy_reg_reset; + + ULI526X_DBUG(0, "uli526x_init()", 0); + + /* Reset M526x MAC controller */ + outl(ULI526X_RESET, ioaddr + DCR0); /* RESET MAC */ + udelay(100); + outl(db->cr0_data, ioaddr + DCR0); + udelay(5); + + /* Phy addr : In some boards,M5261/M5263 phy address != 1 */ + db->phy_addr = 1; + for(phy_tmp=0;phy_tmp<32;phy_tmp++) + { + phy_value=phy_read(db->ioaddr,phy_tmp,3,db->chip_id);//peer add + if(phy_value != 0xffff&&phy_value!=0) + { + db->phy_addr = phy_tmp; + break; + } + } + if(phy_tmp == 32) + printk(KERN_WARNING "Can not find the phy address!!!"); + /* Parser SROM and media mode */ + db->media_mode = uli526x_media_mode; + + /* Phyxcer capability setting */ + phy_reg_reset = phy_read(db->ioaddr, db->phy_addr, 0, db->chip_id); + phy_reg_reset = (phy_reg_reset | 0x8000); + phy_write(db->ioaddr, db->phy_addr, 0, phy_reg_reset, db->chip_id); + udelay(500); + + /* Process Phyxcer Media Mode */ + uli526x_set_phyxcer(db); + + /* Media Mode Process */ + if ( !(db->media_mode & ULI526X_AUTO) ) + db->op_mode = db->media_mode; /* Force Mode */ + + /* Initialize Transmit/Receive decriptor and CR3/4 */ + uli526x_descriptor_init(db, ioaddr); + + /* Init CR6 to program M526X operation */ + update_cr6(db->cr6_data, ioaddr); + + /* Send setup frame */ + send_filter_frame(dev, dev->mc_count); /* M5261/M5263 */ + + /* Init CR7, interrupt active bit */ + db->cr7_data = CR7_DEFAULT; + outl(db->cr7_data, ioaddr + DCR7); + + /* Init CR15, Tx jabber and Rx watchdog timer */ + outl(db->cr15_data, ioaddr + DCR15); + + /* Enable ULI526X Tx/Rx function */ + db->cr6_data |= CR6_RXSC | CR6_TXSC; + update_cr6(db->cr6_data, ioaddr); +} + + +/* + * Hardware start transmission. + * Send a packet to media from the upper layer. + */ + +static int uli526x_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct uli526x_board_info *db = netdev_priv(dev); + struct tx_desc *txptr; + unsigned long flags; + + ULI526X_DBUG(0, "uli526x_start_xmit", 0); + + /* Resource flag check */ + netif_stop_queue(dev); + + /* Too large packet check */ + if (skb->len > MAX_PACKET_SIZE) { + printk(KERN_ERR DRV_NAME ": big packet = %d\n", (u16)skb->len); + dev_kfree_skb(skb); + return 0; + } + + spin_lock_irqsave(&db->lock, flags); + + /* No Tx resource check, it never happen nromally */ + if (db->tx_packet_cnt >= TX_FREE_DESC_CNT) { + spin_unlock_irqrestore(&db->lock, flags); + printk(KERN_ERR DRV_NAME ": No Tx resource %ld\n", db->tx_packet_cnt); + return 1; + } + + /* Disable NIC interrupt */ + outl(0, dev->base_addr + DCR7); + + /* transmit this packet */ + txptr = db->tx_insert_ptr; + memcpy(txptr->tx_buf_ptr, skb->data, skb->len); + txptr->tdes1 = cpu_to_le32(0xe1000000 | skb->len); + + /* Point to next transmit free descriptor */ + db->tx_insert_ptr = txptr->next_tx_desc; + + /* Transmit Packet Process */ + if ( (db->tx_packet_cnt < TX_DESC_CNT) ) { + txptr->tdes0 = cpu_to_le32(0x80000000); /* Set owner bit */ + db->tx_packet_cnt++; /* Ready to send */ + outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling */ + dev->trans_start = jiffies; /* saved time stamp */ + } + + /* Tx resource check */ + if ( db->tx_packet_cnt < TX_FREE_DESC_CNT ) + netif_wake_queue(dev); + + /* Restore CR7 to enable interrupt */ + spin_unlock_irqrestore(&db->lock, flags); + outl(db->cr7_data, dev->base_addr + DCR7); + + /* free this SKB */ + dev_kfree_skb(skb); + + return 0; +} + + +/* + * Stop the interface. + * The interface is stopped when it is brought. + */ + +static int uli526x_stop(struct net_device *dev) +{ + struct uli526x_board_info *db = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + + ULI526X_DBUG(0, "uli526x_stop", 0); + + /* disable system */ + netif_stop_queue(dev); + + /* deleted timer */ + del_timer_sync(&db->timer); + + /* Reset & stop ULI526X board */ + outl(ULI526X_RESET, ioaddr + DCR0); + udelay(5); + phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id); + + /* free interrupt */ + free_irq(dev->irq, dev); + + /* free allocated rx buffer */ + uli526x_free_rxbuffer(db); + +#if 0 + /* show statistic counter */ + printk(DRV_NAME ": FU:%lx EC:%lx LC:%lx NC:%lx LOC:%lx TXJT:%lx RESET:%lx RCR8:%lx FAL:%lx TT:%lx\n", + db->tx_fifo_underrun, db->tx_excessive_collision, + db->tx_late_collision, db->tx_no_carrier, db->tx_loss_carrier, + db->tx_jabber_timeout, db->reset_count, db->reset_cr8, + db->reset_fatal, db->reset_TXtimeout); +#endif + + return 0; +} + + +/* + * M5261/M5263 insterrupt handler + * receive the packet to upper layer, free the transmitted packet + */ + +static irqreturn_t uli526x_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct uli526x_board_info *db = netdev_priv(dev); + unsigned long ioaddr = dev->base_addr; + unsigned long flags; + + if (!dev) { + ULI526X_DBUG(1, "uli526x_interrupt() without DEVICE arg", 0); + return IRQ_NONE; + } + + spin_lock_irqsave(&db->lock, flags); + outl(0, ioaddr + DCR7); + + /* Got ULI526X status */ + db->cr5_data = inl(ioaddr + DCR5); + outl(db->cr5_data, ioaddr + DCR5); + if ( !(db->cr5_data & 0x180c1) ) { + spin_unlock_irqrestore(&db->lock, flags); + outl(db->cr7_data, ioaddr + DCR7); + return IRQ_HANDLED; + } + + /* Check system status */ + if (db->cr5_data & 0x2000) { + /* system bus error happen */ + ULI526X_DBUG(1, "System bus error happen. CR5=", db->cr5_data); + db->reset_fatal++; + db->wait_reset = 1; /* Need to RESET */ + spin_unlock_irqrestore(&db->lock, flags); + return IRQ_HANDLED; + } + + /* Received the coming packet */ + if ( (db->cr5_data & 0x40) && db->rx_avail_cnt ) + uli526x_rx_packet(dev, db); + + /* reallocate rx descriptor buffer */ + if (db->rx_avail_cnt<RX_DESC_CNT) + allocate_rx_buffer(db); + + /* Free the transmitted descriptor */ + if ( db->cr5_data & 0x01) + uli526x_free_tx_pkt(dev, db); + + /* Restore CR7 to enable interrupt mask */ + outl(db->cr7_data, ioaddr + DCR7); + + spin_unlock_irqrestore(&db->lock, flags); + return IRQ_HANDLED; +} + + +/* + * Free TX resource after TX complete + */ + +static void uli526x_free_tx_pkt(struct net_device *dev, struct uli526x_board_info * db) +{ + struct tx_desc *txptr; + u32 tdes0; + + txptr = db->tx_remove_ptr; + while(db->tx_packet_cnt) { + tdes0 = le32_to_cpu(txptr->tdes0); + /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */ + if (tdes0 & 0x80000000) + break; + + /* A packet sent completed */ + db->tx_packet_cnt--; + db->stats.tx_packets++; + + /* Transmit statistic counter */ + if ( tdes0 != 0x7fffffff ) { + /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */ + db->stats.collisions += (tdes0 >> 3) & 0xf; + db->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff; + if (tdes0 & TDES0_ERR_MASK) { + db->stats.tx_errors++; + if (tdes0 & 0x0002) { /* UnderRun */ + db->tx_fifo_underrun++; + if ( !(db->cr6_data & CR6_SFT) ) { + db->cr6_data = db->cr6_data | CR6_SFT; + update_cr6(db->cr6_data, db->ioaddr); + } + } + if (tdes0 & 0x0100) + db->tx_excessive_collision++; + if (tdes0 & 0x0200) + db->tx_late_collision++; + if (tdes0 & 0x0400) + db->tx_no_carrier++; + if (tdes0 & 0x0800) + db->tx_loss_carrier++; + if (tdes0 & 0x4000) + db->tx_jabber_timeout++; + } + } + + txptr = txptr->next_tx_desc; + }/* End of while */ + + /* Update TX remove pointer to next */ + db->tx_remove_ptr = txptr; + + /* Resource available check */ + if ( db->tx_packet_cnt < TX_WAKE_DESC_CNT ) + netif_wake_queue(dev); /* Active upper layer, send again */ +} + + +/* + * Receive the come packet and pass to upper layer + */ + +static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info * db) +{ + struct rx_desc *rxptr; + struct sk_buff *skb; + int rxlen; + u32 rdes0; + + rxptr = db->rx_ready_ptr; + + while(db->rx_avail_cnt) { + rdes0 = le32_to_cpu(rxptr->rdes0); + if (rdes0 & 0x80000000) /* packet owner check */ + { + break; + } + + db->rx_avail_cnt--; + db->interval_rx_cnt++; + + pci_unmap_single(db->pdev, le32_to_cpu(rxptr->rdes2), RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE); + if ( (rdes0 & 0x300) != 0x300) { + /* A packet without First/Last flag */ + /* reuse this SKB */ + ULI526X_DBUG(0, "Reuse SK buffer, rdes0", rdes0); + uli526x_reuse_skb(db, rxptr->rx_skb_ptr); + } else { + /* A packet with First/Last flag */ + rxlen = ( (rdes0 >> 16) & 0x3fff) - 4; + + /* error summary bit check */ + if (rdes0 & 0x8000) { + /* This is a error packet */ + //printk(DRV_NAME ": rdes0: %lx\n", rdes0); + db->stats.rx_errors++; + if (rdes0 & 1) + db->stats.rx_fifo_errors++; + if (rdes0 & 2) + db->stats.rx_crc_errors++; + if (rdes0 & 0x80) + db->stats.rx_length_errors++; + } + + if ( !(rdes0 & 0x8000) || + ((db->cr6_data & CR6_PM) && (rxlen>6)) ) { + skb = rxptr->rx_skb_ptr; + + /* Good packet, send to upper layer */ + /* Shorst packet used new SKB */ + if ( (rxlen < RX_COPY_SIZE) && + ( (skb = dev_alloc_skb(rxlen + 2) ) + != NULL) ) { + /* size less than COPY_SIZE, allocate a rxlen SKB */ + skb->dev = dev; + skb_reserve(skb, 2); /* 16byte align */ + memcpy(skb_put(skb, rxlen), rxptr->rx_skb_ptr->tail, rxlen); + uli526x_reuse_skb(db, rxptr->rx_skb_ptr); + } else { + skb->dev = dev; + skb_put(skb, rxlen); + } + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + dev->last_rx = jiffies; + db->stats.rx_packets++; + db->stats.rx_bytes += rxlen; + + } else { + /* Reuse SKB buffer when the packet is error */ + ULI526X_DBUG(0, "Reuse SK buffer, rdes0", rdes0); + uli526x_reuse_skb(db, rxptr->rx_skb_ptr); + } + } + + rxptr = rxptr->next_rx_desc; + } + + db->rx_ready_ptr = rxptr; +} + + +/* + * Get statistics from driver. + */ + +static struct net_device_stats * uli526x_get_stats(struct net_device *dev) +{ + struct uli526x_board_info *db = netdev_priv(dev); + + ULI526X_DBUG(0, "uli526x_get_stats", 0); + return &db->stats; +} + + +/* + * Set ULI526X multicast address + */ + +static void uli526x_set_filter_mode(struct net_device * dev) +{ + struct uli526x_board_info *db = dev->priv; + unsigned long flags; + + ULI526X_DBUG(0, "uli526x_set_filter_mode()", 0); + spin_lock_irqsave(&db->lock, flags); + + if (dev->flags & IFF_PROMISC) { + ULI526X_DBUG(0, "Enable PROM Mode", 0); + db->cr6_data |= CR6_PM | CR6_PBF; + update_cr6(db->cr6_data, db->ioaddr); + spin_unlock_irqrestore(&db->lock, flags); + return; + } + + if (dev->flags & IFF_ALLMULTI || dev->mc_count > ULI5261_MAX_MULTICAST) { + ULI526X_DBUG(0, "Pass all multicast address", dev->mc_count); + db->cr6_data &= ~(CR6_PM | CR6_PBF); + db->cr6_data |= CR6_PAM; + spin_unlock_irqrestore(&db->lock, flags); + return; + } + + ULI526X_DBUG(0, "Set multicast address", dev->mc_count); + send_filter_frame(dev, dev->mc_count); /* M5261/M5263 */ + spin_unlock_irqrestore(&db->lock, flags); +} + +static void +ULi_ethtool_gset(struct uli526x_board_info *db, struct ethtool_cmd *ecmd) +{ + ecmd->supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_Autoneg | + SUPPORTED_MII); + + ecmd->advertising = (ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full | + ADVERTISED_Autoneg | + ADVERTISED_MII); + + + ecmd->port = PORT_MII; + ecmd->phy_address = db->phy_addr; + + ecmd->transceiver = XCVR_EXTERNAL; + + ecmd->speed = 10; + ecmd->duplex = DUPLEX_HALF; + + if(db->op_mode==ULI526X_100MHF || db->op_mode==ULI526X_100MFD) + { + ecmd->speed = 100; + } + if(db->op_mode==ULI526X_10MFD || db->op_mode==ULI526X_100MFD) + { + ecmd->duplex = DUPLEX_FULL; + } + if(db->link_failed) + { + ecmd->speed = -1; + ecmd->duplex = -1; + } + + if (db->media_mode & ULI526X_AUTO) + { + ecmd->autoneg = AUTONEG_ENABLE; + } +} + +static void netdev_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct uli526x_board_info *np = netdev_priv(dev); + + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + if (np->pdev) + strcpy(info->bus_info, pci_name(np->pdev)); + else + sprintf(info->bus_info, "EISA 0x%lx %d", + dev->base_addr, dev->irq); +} + +static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { + struct uli526x_board_info *np = netdev_priv(dev); + + ULi_ethtool_gset(np, cmd); + + return 0; +} + +static u32 netdev_get_link(struct net_device *dev) { + struct uli526x_board_info *np = netdev_priv(dev); + + if(np->link_failed) + return 0; + else + return 1; +} + +static void uli526x_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + wol->supported = WAKE_PHY | WAKE_MAGIC; + wol->wolopts = 0; +} + +static struct ethtool_ops netdev_ethtool_ops = { + .get_drvinfo = netdev_get_drvinfo, + .get_settings = netdev_get_settings, + .get_link = netdev_get_link, + .get_wol = uli526x_get_wol, +}; + +/* + * A periodic timer routine + * Dynamic media sense, allocate Rx buffer... + */ + +static void uli526x_timer(unsigned long data) +{ + u32 tmp_cr8; + unsigned char tmp_cr12=0; + struct net_device *dev = (struct net_device *) data; + struct uli526x_board_info *db = netdev_priv(dev); + unsigned long flags; + u8 TmpSpeed=10; + + //ULI526X_DBUG(0, "uli526x_timer()", 0); + spin_lock_irqsave(&db->lock, flags); + + + /* Dynamic reset ULI526X : system error or transmit time-out */ + tmp_cr8 = inl(db->ioaddr + DCR8); + if ( (db->interval_rx_cnt==0) && (tmp_cr8) ) { + db->reset_cr8++; + db->wait_reset = 1; + } + db->interval_rx_cnt = 0; + + /* TX polling kick monitor */ + if ( db->tx_packet_cnt && + time_after(jiffies, dev->trans_start + ULI526X_TX_KICK) ) { + outl(0x1, dev->base_addr + DCR1); // Tx polling again + + // TX Timeout + if ( time_after(jiffies, dev->trans_start + ULI526X_TX_TIMEOUT) ) { + db->reset_TXtimeout++; + db->wait_reset = 1; + printk( "%s: Tx timeout - resetting\n", + dev->name); + } + } + + if (db->wait_reset) { + ULI526X_DBUG(0, "Dynamic Reset device", db->tx_packet_cnt); + db->reset_count++; + uli526x_dynamic_reset(dev); + db->timer.expires = ULI526X_TIMER_WUT; + add_timer(&db->timer); + spin_unlock_irqrestore(&db->lock, flags); + return; + } + + /* Link status check, Dynamic media type change */ + if((phy_read(db->ioaddr, db->phy_addr, 5, db->chip_id) & 0x01e0)!=0) + tmp_cr12 = 3; + + if ( !(tmp_cr12 & 0x3) && !db->link_failed ) { + /* Link Failed */ + ULI526X_DBUG(0, "Link Failed", tmp_cr12); + netif_carrier_off(dev); + printk(KERN_INFO "uli526x: %s NIC Link is Down\n",dev->name); + db->link_failed = 1; + + /* For Force 10/100M Half/Full mode: Enable Auto-Nego mode */ + /* AUTO don't need */ + if ( !(db->media_mode & 0x8) ) + phy_write(db->ioaddr, db->phy_addr, 0, 0x1000, db->chip_id); + + /* AUTO mode, if INT phyxcer link failed, select EXT device */ + if (db->media_mode & ULI526X_AUTO) { + db->cr6_data&=~0x00000200; /* bit9=0, HD mode */ + update_cr6(db->cr6_data, db->ioaddr); + } + } else + if ((tmp_cr12 & 0x3) && db->link_failed) { + ULI526X_DBUG(0, "Link link OK", tmp_cr12); + db->link_failed = 0; + + /* Auto Sense Speed */ + if ( (db->media_mode & ULI526X_AUTO) && + uli526x_sense_speed(db) ) + db->link_failed = 1; + uli526x_process_mode(db); + + if(db->link_failed==0) + { + if(db->op_mode==ULI526X_100MHF || db->op_mode==ULI526X_100MFD) + { + TmpSpeed = 100; + } + if(db->op_mode==ULI526X_10MFD || db->op_mode==ULI526X_100MFD) + { + printk(KERN_INFO "uli526x: %s NIC Link is Up %d Mbps Full duplex\n",dev->name,TmpSpeed); + } + else + { + printk(KERN_INFO "uli526x: %s NIC Link is Up %d Mbps Half duplex\n",dev->name,TmpSpeed); + } + netif_carrier_on(dev); + } + /* SHOW_MEDIA_TYPE(db->op_mode); */ + } + else if(!(tmp_cr12 & 0x3) && db->link_failed) + { + if(db->init==1) + { + printk(KERN_INFO "uli526x: %s NIC Link is Down\n",dev->name); + netif_carrier_off(dev); + } + } + db->init=0; + + /* Timer active again */ + db->timer.expires = ULI526X_TIMER_WUT; + add_timer(&db->timer); + spin_unlock_irqrestore(&db->lock, flags); +} + + +/* + * Dynamic reset the ULI526X board + * Stop ULI526X board + * Free Tx/Rx allocated memory + * Reset ULI526X board + * Re-initialize ULI526X board + */ + +static void uli526x_dynamic_reset(struct net_device *dev) +{ + struct uli526x_board_info *db = netdev_priv(dev); + + ULI526X_DBUG(0, "uli526x_dynamic_reset()", 0); + + /* Sopt MAC controller */ + db->cr6_data &= ~(CR6_RXSC | CR6_TXSC); /* Disable Tx/Rx */ + update_cr6(db->cr6_data, dev->base_addr); + outl(0, dev->base_addr + DCR7); /* Disable Interrupt */ + outl(inl(dev->base_addr + DCR5), dev->base_addr + DCR5); + + /* Disable upper layer interface */ + netif_stop_queue(dev); + + /* Free Rx Allocate buffer */ + uli526x_free_rxbuffer(db); + + /* system variable init */ + db->tx_packet_cnt = 0; + db->rx_avail_cnt = 0; + db->link_failed = 1; + db->init=1; + db->wait_reset = 0; + + /* Re-initialize ULI526X board */ + uli526x_init(dev); + + /* Restart upper layer interface */ + netif_wake_queue(dev); +} + + +/* + * free all allocated rx buffer + */ + +static void uli526x_free_rxbuffer(struct uli526x_board_info * db) +{ + ULI526X_DBUG(0, "uli526x_free_rxbuffer()", 0); + + /* free allocated rx buffer */ + while (db->rx_avail_cnt) { + dev_kfree_skb(db->rx_ready_ptr->rx_skb_ptr); + db->rx_ready_ptr = db->rx_ready_ptr->next_rx_desc; + db->rx_avail_cnt--; + } +} + + +/* + * Reuse the SK buffer + */ + +static void uli526x_reuse_skb(struct uli526x_board_info *db, struct sk_buff * skb) +{ + struct rx_desc *rxptr = db->rx_insert_ptr; + + if (!(rxptr->rdes0 & cpu_to_le32(0x80000000))) { + rxptr->rx_skb_ptr = skb; + rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); + wmb(); + rxptr->rdes0 = cpu_to_le32(0x80000000); + db->rx_avail_cnt++; + db->rx_insert_ptr = rxptr->next_rx_desc; + } else + ULI526X_DBUG(0, "SK Buffer reuse method error", db->rx_avail_cnt); +} + + +/* + * Initialize transmit/Receive descriptor + * Using Chain structure, and allocate Tx/Rx buffer + */ + +static void uli526x_descriptor_init(struct uli526x_board_info *db, unsigned long ioaddr) +{ + struct tx_desc *tmp_tx; + struct rx_desc *tmp_rx; + unsigned char *tmp_buf; + dma_addr_t tmp_tx_dma, tmp_rx_dma; + dma_addr_t tmp_buf_dma; + int i; + + ULI526X_DBUG(0, "uli526x_descriptor_init()", 0); + + /* tx descriptor start pointer */ + db->tx_insert_ptr = db->first_tx_desc; + db->tx_remove_ptr = db->first_tx_desc; + outl(db->first_tx_desc_dma, ioaddr + DCR4); /* TX DESC address */ + + /* rx descriptor start pointer */ + db->first_rx_desc = (void *)db->first_tx_desc + sizeof(struct tx_desc) * TX_DESC_CNT; + db->first_rx_desc_dma = db->first_tx_desc_dma + sizeof(struct tx_desc) * TX_DESC_CNT; + db->rx_insert_ptr = db->first_rx_desc; + db->rx_ready_ptr = db->first_rx_desc; + outl(db->first_rx_desc_dma, ioaddr + DCR3); /* RX DESC address */ + + /* Init Transmit chain */ + tmp_buf = db->buf_pool_start; + tmp_buf_dma = db->buf_pool_dma_start; + tmp_tx_dma = db->first_tx_desc_dma; + for (tmp_tx = db->first_tx_desc, i = 0; i < TX_DESC_CNT; i++, tmp_tx++) { + tmp_tx->tx_buf_ptr = tmp_buf; + tmp_tx->tdes0 = cpu_to_le32(0); + tmp_tx->tdes1 = cpu_to_le32(0x81000000); /* IC, chain */ + tmp_tx->tdes2 = cpu_to_le32(tmp_buf_dma); + tmp_tx_dma += sizeof(struct tx_desc); + tmp_tx->tdes3 = cpu_to_le32(tmp_tx_dma); + tmp_tx->next_tx_desc = tmp_tx + 1; + tmp_buf = tmp_buf + TX_BUF_ALLOC; + tmp_buf_dma = tmp_buf_dma + TX_BUF_ALLOC; + } + (--tmp_tx)->tdes3 = cpu_to_le32(db->first_tx_desc_dma); + tmp_tx->next_tx_desc = db->first_tx_desc; + + /* Init Receive descriptor chain */ + tmp_rx_dma=db->first_rx_desc_dma; + for (tmp_rx = db->first_rx_desc, i = 0; i < RX_DESC_CNT; i++, tmp_rx++) { + tmp_rx->rdes0 = cpu_to_le32(0); + tmp_rx->rdes1 = cpu_to_le32(0x01000600); + tmp_rx_dma += sizeof(struct rx_desc); + tmp_rx->rdes3 = cpu_to_le32(tmp_rx_dma); + tmp_rx->next_rx_desc = tmp_rx + 1; + } + (--tmp_rx)->rdes3 = cpu_to_le32(db->first_rx_desc_dma); + tmp_rx->next_rx_desc = db->first_rx_desc; + + /* pre-allocate Rx buffer */ + allocate_rx_buffer(db); +} + + +/* + * Update CR6 value + * Firstly stop ULI526X, then written value and start + */ + +static void update_cr6(u32 cr6_data, unsigned long ioaddr) +{ + + outl(cr6_data, ioaddr + DCR6); + udelay(5); +} + + +/* + * Send a setup frame for M5261/M5263 + * This setup frame initialize ULI526X address filter mode + */ + +static void send_filter_frame(struct net_device *dev, int mc_cnt) +{ + struct uli526x_board_info *db = netdev_priv(dev); + struct dev_mc_list *mcptr; + struct tx_desc *txptr; + u16 * addrptr; + u32 * suptr; + int i; + + ULI526X_DBUG(0, "send_filter_frame()", 0); + + txptr = db->tx_insert_ptr; + suptr = (u32 *) txptr->tx_buf_ptr; + + /* Node address */ + addrptr = (u16 *) dev->dev_addr; + *suptr++ = addrptr[0]; + *suptr++ = addrptr[1]; + *suptr++ = addrptr[2]; + + /* broadcast address */ + *suptr++ = 0xffff; + *suptr++ = 0xffff; + *suptr++ = 0xffff; + + /* fit the multicast address */ + for (mcptr = dev->mc_list, i = 0; i < mc_cnt; i++, mcptr = mcptr->next) { + addrptr = (u16 *) mcptr->dmi_addr; + *suptr++ = addrptr[0]; + *suptr++ = addrptr[1]; + *suptr++ = addrptr[2]; + } + + for (; i<14; i++) { + *suptr++ = 0xffff; + *suptr++ = 0xffff; + *suptr++ = 0xffff; + } + + /* prepare the setup frame */ + db->tx_insert_ptr = txptr->next_tx_desc; + txptr->tdes1 = cpu_to_le32(0x890000c0); + + /* Resource Check and Send the setup packet */ + if (db->tx_packet_cnt < TX_DESC_CNT) { + /* Resource Empty */ + db->tx_packet_cnt++; + txptr->tdes0 = cpu_to_le32(0x80000000); + update_cr6(db->cr6_data | 0x2000, dev->base_addr); + outl(0x1, dev->base_addr + DCR1); /* Issue Tx polling */ + update_cr6(db->cr6_data, dev->base_addr); + dev->trans_start = jiffies; + } else + printk(KERN_ERR DRV_NAME ": No Tx resource - Send_filter_frame!\n"); +} + + +/* + * Allocate rx buffer, + * As possible as allocate maxiumn Rx buffer + */ + +static void allocate_rx_buffer(struct uli526x_board_info *db) +{ + struct rx_desc *rxptr; + struct sk_buff *skb; + + rxptr = db->rx_insert_ptr; + + while(db->rx_avail_cnt < RX_DESC_CNT) { + if ( ( skb = dev_alloc_skb(RX_ALLOC_SIZE) ) == NULL ) + break; + rxptr->rx_skb_ptr = skb; /* FIXME (?) */ + rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) ); + wmb(); + rxptr->rdes0 = cpu_to_le32(0x80000000); + rxptr = rxptr->next_rx_desc; + db->rx_avail_cnt++; + } + + db->rx_insert_ptr = rxptr; +} + + +/* + * Read one word data from the serial ROM + */ + +static u16 read_srom_word(long ioaddr, int offset) +{ + int i; + u16 srom_data = 0; + long cr9_ioaddr = ioaddr + DCR9; + + outl(CR9_SROM_READ, cr9_ioaddr); + outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr); + + /* Send the Read Command 110b */ + SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr); + SROM_CLK_WRITE(SROM_DATA_1, cr9_ioaddr); + SROM_CLK_WRITE(SROM_DATA_0, cr9_ioaddr); + + /* Send the offset */ + for (i = 5; i >= 0; i--) { + srom_data = (offset & (1 << i)) ? SROM_DATA_1 : SROM_DATA_0; + SROM_CLK_WRITE(srom_data, cr9_ioaddr); + } + + outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr); + + for (i = 16; i > 0; i--) { + outl(CR9_SROM_READ | CR9_SRCS | CR9_SRCLK, cr9_ioaddr); + udelay(5); + srom_data = (srom_data << 1) | ((inl(cr9_ioaddr) & CR9_CRDOUT) ? 1 : 0); + outl(CR9_SROM_READ | CR9_SRCS, cr9_ioaddr); + udelay(5); + } + + outl(CR9_SROM_READ, cr9_ioaddr); + return srom_data; +} + + +/* + * Auto sense the media mode + */ + +static u8 uli526x_sense_speed(struct uli526x_board_info * db) +{ + u8 ErrFlag = 0; + u16 phy_mode; + + phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id); + phy_mode = phy_read(db->ioaddr, db->phy_addr, 1, db->chip_id); + + if ( (phy_mode & 0x24) == 0x24 ) { + + phy_mode = ((phy_read(db->ioaddr, db->phy_addr, 5, db->chip_id) & 0x01e0)<<7); + if(phy_mode&0x8000) + phy_mode = 0x8000; + else if(phy_mode&0x4000) + phy_mode = 0x4000; + else if(phy_mode&0x2000) + phy_mode = 0x2000; + else + phy_mode = 0x1000; + + /* printk(DRV_NAME ": Phy_mode %x ",phy_mode); */ + switch (phy_mode) { + case 0x1000: db->op_mode = ULI526X_10MHF; break; + case 0x2000: db->op_mode = ULI526X_10MFD; break; + case 0x4000: db->op_mode = ULI526X_100MHF; break; + case 0x8000: db->op_mode = ULI526X_100MFD; break; + default: db->op_mode = ULI526X_10MHF; ErrFlag = 1; break; + } + } else { + db->op_mode = ULI526X_10MHF; + ULI526X_DBUG(0, "Link Failed :", phy_mode); + ErrFlag = 1; + } + + return ErrFlag; +} + + +/* + * Set 10/100 phyxcer capability + * AUTO mode : phyxcer register4 is NIC capability + * Force mode: phyxcer register4 is the force media + */ + +static void uli526x_set_phyxcer(struct uli526x_board_info *db) +{ + u16 phy_reg; + + /* Phyxcer capability setting */ + phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0; + + if (db->media_mode & ULI526X_AUTO) { + /* AUTO Mode */ + phy_reg |= db->PHY_reg4; + } else { + /* Force Mode */ + switch(db->media_mode) { + case ULI526X_10MHF: phy_reg |= 0x20; break; + case ULI526X_10MFD: phy_reg |= 0x40; break; + case ULI526X_100MHF: phy_reg |= 0x80; break; + case ULI526X_100MFD: phy_reg |= 0x100; break; + } + + } + + /* Write new capability to Phyxcer Reg4 */ + if ( !(phy_reg & 0x01e0)) { + phy_reg|=db->PHY_reg4; + db->media_mode|=ULI526X_AUTO; + } + phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id); + + /* Restart Auto-Negotiation */ + phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id); + udelay(50); +} + + +/* + * Process op-mode + AUTO mode : PHY controller in Auto-negotiation Mode + * Force mode: PHY controller in force mode with HUB + * N-way force capability with SWITCH + */ + +static void uli526x_process_mode(struct uli526x_board_info *db) +{ + u16 phy_reg; + + /* Full Duplex Mode Check */ + if (db->op_mode & 0x4) + db->cr6_data |= CR6_FDM; /* Set Full Duplex Bit */ + else + db->cr6_data &= ~CR6_FDM; /* Clear Full Duplex Bit */ + + update_cr6(db->cr6_data, db->ioaddr); + + /* 10/100M phyxcer force mode need */ + if ( !(db->media_mode & 0x8)) { + /* Forece Mode */ + phy_reg = phy_read(db->ioaddr, db->phy_addr, 6, db->chip_id); + if ( !(phy_reg & 0x1) ) { + /* parter without N-Way capability */ + phy_reg = 0x0; + switch(db->op_mode) { + case ULI526X_10MHF: phy_reg = 0x0; break; + case ULI526X_10MFD: phy_reg = 0x100; break; + case ULI526X_100MHF: phy_reg = 0x2000; break; + case ULI526X_100MFD: phy_reg = 0x2100; break; + } + phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id); + phy_write(db->ioaddr, db->phy_addr, 0, phy_reg, db->chip_id); + } + } +} + + +/* + * Write a word to Phy register + */ + +static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data, u32 chip_id) +{ + u16 i; + unsigned long ioaddr; + + if(chip_id == PCI_ULI5263_ID) + { + phy_writeby_cr10(iobase, phy_addr, offset, phy_data); + return; + } + /* M5261/M5263 Chip */ + ioaddr = iobase + DCR9; + + /* Send 33 synchronization clock to Phy controller */ + for (i = 0; i < 35; i++) + phy_write_1bit(ioaddr, PHY_DATA_1, chip_id); + + /* Send start command(01) to Phy */ + phy_write_1bit(ioaddr, PHY_DATA_0, chip_id); + phy_write_1bit(ioaddr, PHY_DATA_1, chip_id); + + /* Send write command(01) to Phy */ + phy_write_1bit(ioaddr, PHY_DATA_0, chip_id); + phy_write_1bit(ioaddr, PHY_DATA_1, chip_id); + + /* Send Phy address */ + for (i = 0x10; i > 0; i = i >> 1) + phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0, chip_id); + + /* Send register address */ + for (i = 0x10; i > 0; i = i >> 1) + phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0, chip_id); + + /* written trasnition */ + phy_write_1bit(ioaddr, PHY_DATA_1, chip_id); + phy_write_1bit(ioaddr, PHY_DATA_0, chip_id); + + /* Write a word data to PHY controller */ + for ( i = 0x8000; i > 0; i >>= 1) + phy_write_1bit(ioaddr, phy_data & i ? PHY_DATA_1 : PHY_DATA_0, chip_id); + +} + + +/* + * Read a word data from phy register + */ + +static u16 phy_read(unsigned long iobase, u8 phy_addr, u8 offset, u32 chip_id) +{ + int i; + u16 phy_data; + unsigned long ioaddr; + + if(chip_id == PCI_ULI5263_ID) + return phy_readby_cr10(iobase, phy_addr, offset); + /* M5261/M5263 Chip */ + ioaddr = iobase + DCR9; + + /* Send 33 synchronization clock to Phy controller */ + for (i = 0; i < 35; i++) + phy_write_1bit(ioaddr, PHY_DATA_1, chip_id); + + /* Send start command(01) to Phy */ + phy_write_1bit(ioaddr, PHY_DATA_0, chip_id); + phy_write_1bit(ioaddr, PHY_DATA_1, chip_id); + + /* Send read command(10) to Phy */ + phy_write_1bit(ioaddr, PHY_DATA_1, chip_id); + phy_write_1bit(ioaddr, PHY_DATA_0, chip_id); + + /* Send Phy address */ + for (i = 0x10; i > 0; i = i >> 1) + phy_write_1bit(ioaddr, phy_addr & i ? PHY_DATA_1 : PHY_DATA_0, chip_id); + + /* Send register address */ + for (i = 0x10; i > 0; i = i >> 1) + phy_write_1bit(ioaddr, offset & i ? PHY_DATA_1 : PHY_DATA_0, chip_id); + + /* Skip transition state */ + phy_read_1bit(ioaddr, chip_id); + + /* read 16bit data */ + for (phy_data = 0, i = 0; i < 16; i++) { + phy_data <<= 1; + phy_data |= phy_read_1bit(ioaddr, chip_id); + } + + return phy_data; +} + +static u16 phy_readby_cr10(unsigned long iobase, u8 phy_addr, u8 offset) +{ + unsigned long ioaddr,cr10_value; + + ioaddr = iobase + DCR10; + cr10_value = phy_addr; + cr10_value = (cr10_value<<5) + offset; + cr10_value = (cr10_value<<16) + 0x08000000; + outl(cr10_value,ioaddr); + udelay(1); + while(1) + { + cr10_value = inl(ioaddr); + if(cr10_value&0x10000000) + break; + } + return (cr10_value&0x0ffff); +} + +static void phy_writeby_cr10(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data) +{ + unsigned long ioaddr,cr10_value; + + ioaddr = iobase + DCR10; + cr10_value = phy_addr; + cr10_value = (cr10_value<<5) + offset; + cr10_value = (cr10_value<<16) + 0x04000000 + phy_data; + outl(cr10_value,ioaddr); + udelay(1); +} +/* + * Write one bit data to Phy Controller + */ + +static void phy_write_1bit(unsigned long ioaddr, u32 phy_data, u32 chip_id) +{ + outl(phy_data , ioaddr); /* MII Clock Low */ + udelay(1); + outl(phy_data | MDCLKH, ioaddr); /* MII Clock High */ + udelay(1); + outl(phy_data , ioaddr); /* MII Clock Low */ + udelay(1); +} + + +/* + * Read one bit phy data from PHY controller + */ + +static u16 phy_read_1bit(unsigned long ioaddr, u32 chip_id) +{ + u16 phy_data; + + outl(0x50000 , ioaddr); + udelay(1); + phy_data = ( inl(ioaddr) >> 19 ) & 0x1; + outl(0x40000 , ioaddr); + udelay(1); + + return phy_data; +} + + +static struct pci_device_id uli526x_pci_tbl[] = { + { 0x10B9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_ULI5261_ID }, + { 0x10B9, 0x5263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCI_ULI5263_ID }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, uli526x_pci_tbl); + + +static struct pci_driver uli526x_driver = { + .name = "uli526x", + .id_table = uli526x_pci_tbl, + .probe = uli526x_init_one, + .remove = __devexit_p(uli526x_remove_one), +}; + +MODULE_AUTHOR("Peer Chen, peer.chen@uli.com.tw"); +MODULE_DESCRIPTION("ULi M5261/M5263 fast ethernet driver"); +MODULE_LICENSE("GPL"); + +MODULE_PARM(debug, "i"); +MODULE_PARM(mode, "i"); +MODULE_PARM(cr6set, "i"); +MODULE_PARM_DESC(debug, "ULi M5261/M5263 enable debugging (0-1)"); +MODULE_PARM_DESC(mode, "ULi M5261/M5263: Bit 0: 10/100Mbps, bit 2: duplex, bit 8: HomePNA"); + +/* Description: + * when user used insmod to add module, system invoked init_module() + * to register the services. + */ + +static int __init uli526x_init_module(void) +{ + int rc; + + printk(version); + printed_version = 1; + + ULI526X_DBUG(0, "init_module() ", debug); + + if (debug) + uli526x_debug = debug; /* set debug flag */ + if (cr6set) + uli526x_cr6_user_set = cr6set; + + switch(mode) { + case ULI526X_10MHF: + case ULI526X_100MHF: + case ULI526X_10MFD: + case ULI526X_100MFD: + uli526x_media_mode = mode; + break; + default:uli526x_media_mode = ULI526X_AUTO; + break; + } + + rc = pci_module_init(&uli526x_driver); + if (rc < 0) + return rc; + + return 0; +} + + +/* + * Description: + * when user used rmmod to delete module, system invoked clean_module() + * to un-register all registered services. + */ + +static void __exit uli526x_cleanup_module(void) +{ + ULI526X_DBUG(0, "uli526x_clean_module() ", debug); + pci_unregister_driver(&uli526x_driver); +} + +module_init(uli526x_init_module); +module_exit(uli526x_cleanup_module); diff --git a/drivers/net/wan/cycx_drv.c b/drivers/net/wan/cycx_drv.c index 6e74af62ca0..9e56fc346ba 100644 --- a/drivers/net/wan/cycx_drv.c +++ b/drivers/net/wan/cycx_drv.c @@ -56,7 +56,7 @@ #include <linux/sched.h> /* for jiffies, HZ, etc. */ #include <linux/cycx_drv.h> /* API definitions */ #include <linux/cycx_cfm.h> /* CYCX firmware module definitions */ -#include <linux/delay.h> /* udelay */ +#include <linux/delay.h> /* udelay, msleep_interruptible */ #include <asm/io.h> /* read[wl], write[wl], ioremap, iounmap */ #define MOD_VERSION 0 @@ -74,7 +74,6 @@ static int reset_cyc2x(void __iomem *addr); static int detect_cyc2x(void __iomem *addr); /* Miscellaneous functions */ -static void delay_cycx(int sec); static int get_option_index(long *optlist, long optval); static u16 checksum(u8 *buf, u32 len); @@ -259,7 +258,7 @@ static int memory_exists(void __iomem *addr) if (readw(addr + 0x10) == TEST_PATTERN) return 1; - delay_cycx(1); + msleep_interruptible(1 * 1000); } return 0; @@ -316,7 +315,7 @@ static void cycx_reset_boot(void __iomem *addr, u8 *code, u32 len) /* 80186 was in hold, go */ writeb(0, addr + START_CPU); - delay_cycx(1); + msleep_interruptible(1 * 1000); } /* Load data.bin file through boot (reset) interface. */ @@ -462,13 +461,13 @@ static int load_cyc2x(struct cycx_hw *hw, struct cycx_firmware *cfm, u32 len) cycx_reset_boot(hw->dpmbase, reset_image, img_hdr->reset_size); /* reset is waiting for boot */ writew(GEN_POWER_ON, pt_cycld); - delay_cycx(1); + msleep_interruptible(1 * 1000); for (j = 0 ; j < 3 ; j++) if (!readw(pt_cycld)) goto reset_loaded; else - delay_cycx(1); + msleep_interruptible(1 * 1000); } printk(KERN_ERR "%s: reset not started.\n", modname); @@ -495,7 +494,7 @@ reset_loaded: /* Arthur Ganzert's tip: wait a while after the firmware loading... seg abr 26 17:17:12 EST 1999 - acme */ - delay_cycx(7); + msleep_interruptible(7 * 1000); printk(KERN_INFO "%s: firmware loaded!\n", modname); /* enable interrupts */ @@ -547,20 +546,13 @@ static int get_option_index(long *optlist, long optval) static int reset_cyc2x(void __iomem *addr) { writeb(0, addr + RST_ENABLE); - delay_cycx(2); + msleep_interruptible(2 * 1000); writeb(0, addr + RST_DISABLE); - delay_cycx(2); + msleep_interruptible(2 * 1000); return memory_exists(addr); } -/* Delay */ -static void delay_cycx(int sec) -{ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(sec * HZ); -} - /* Calculate 16-bit CRC using CCITT polynomial. */ static u16 checksum(u8 *buf, u32 len) { diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index aabcdc2be05..9c2d07cde01 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -4322,36 +4322,36 @@ static const struct iw_priv_args orinoco_privtab[] = { */ static const iw_handler orinoco_handler[] = { - [SIOCSIWCOMMIT-SIOCIWFIRST] (iw_handler) orinoco_ioctl_commit, - [SIOCGIWNAME -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getname, - [SIOCSIWFREQ -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfreq, - [SIOCGIWFREQ -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfreq, - [SIOCSIWMODE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setmode, - [SIOCGIWMODE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getmode, - [SIOCSIWSENS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setsens, - [SIOCGIWSENS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getsens, - [SIOCGIWRANGE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwrange, - [SIOCSIWSPY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setspy, - [SIOCGIWSPY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getspy, - [SIOCSIWAP -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setwap, - [SIOCGIWAP -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getwap, - [SIOCSIWSCAN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setscan, - [SIOCGIWSCAN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getscan, - [SIOCSIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setessid, - [SIOCGIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getessid, - [SIOCSIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setnick, - [SIOCGIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getnick, - [SIOCSIWRATE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrate, - [SIOCGIWRATE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrate, - [SIOCSIWRTS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrts, - [SIOCGIWRTS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrts, - [SIOCSIWFRAG -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfrag, - [SIOCGIWFRAG -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfrag, - [SIOCGIWRETRY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getretry, - [SIOCSIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_setiwencode, - [SIOCGIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwencode, - [SIOCSIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setpower, - [SIOCGIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getpower, + [SIOCSIWCOMMIT-SIOCIWFIRST] = (iw_handler) orinoco_ioctl_commit, + [SIOCGIWNAME -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getname, + [SIOCSIWFREQ -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setfreq, + [SIOCGIWFREQ -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getfreq, + [SIOCSIWMODE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setmode, + [SIOCGIWMODE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getmode, + [SIOCSIWSENS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setsens, + [SIOCGIWSENS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getsens, + [SIOCGIWRANGE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getiwrange, + [SIOCSIWSPY -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setspy, + [SIOCGIWSPY -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getspy, + [SIOCSIWAP -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setwap, + [SIOCGIWAP -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getwap, + [SIOCSIWSCAN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setscan, + [SIOCGIWSCAN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getscan, + [SIOCSIWESSID -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setessid, + [SIOCGIWESSID -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getessid, + [SIOCSIWNICKN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setnick, + [SIOCGIWNICKN -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getnick, + [SIOCSIWRATE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setrate, + [SIOCGIWRATE -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getrate, + [SIOCSIWRTS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setrts, + [SIOCGIWRTS -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getrts, + [SIOCSIWFRAG -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setfrag, + [SIOCGIWFRAG -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getfrag, + [SIOCGIWRETRY -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getretry, + [SIOCSIWENCODE-SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setiwencode, + [SIOCGIWENCODE-SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getiwencode, + [SIOCSIWPOWER -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_setpower, + [SIOCGIWPOWER -SIOCIWFIRST] = (iw_handler) orinoco_ioctl_getpower, }; @@ -4359,15 +4359,15 @@ static const iw_handler orinoco_handler[] = { Added typecasting since we no longer use iwreq_data -- Moustafa */ static const iw_handler orinoco_private_handler[] = { - [0] (iw_handler) orinoco_ioctl_reset, - [1] (iw_handler) orinoco_ioctl_reset, - [2] (iw_handler) orinoco_ioctl_setport3, - [3] (iw_handler) orinoco_ioctl_getport3, - [4] (iw_handler) orinoco_ioctl_setpreamble, - [5] (iw_handler) orinoco_ioctl_getpreamble, - [6] (iw_handler) orinoco_ioctl_setibssport, - [7] (iw_handler) orinoco_ioctl_getibssport, - [9] (iw_handler) orinoco_ioctl_getrid, + [0] = (iw_handler) orinoco_ioctl_reset, + [1] = (iw_handler) orinoco_ioctl_reset, + [2] = (iw_handler) orinoco_ioctl_setport3, + [3] = (iw_handler) orinoco_ioctl_getport3, + [4] = (iw_handler) orinoco_ioctl_setpreamble, + [5] = (iw_handler) orinoco_ioctl_getpreamble, + [6] = (iw_handler) orinoco_ioctl_setibssport, + [7] = (iw_handler) orinoco_ioctl_getibssport, + [9] = (iw_handler) orinoco_ioctl_getrid, }; static const struct iw_handler_def orinoco_handler_def = { |