1
0
Fork 0

Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (53 commits)
  tcp: Overflow bug in Vegas
  [IPv4] UFO: prevent generation of chained skb destined to UFO device
  iwlwifi: move the selects to the tristate drivers
  ipv4: annotate a few functions __init in ipconfig.c
  atm: ambassador: vcc_sf semaphore to mutex
  MAINTAINERS: The socketcan-core list is subscribers-only.
  netfilter: nf_conntrack: padding breaks conntrack hash on ARM
  ipv4: Update MTU to all related cache entries in ip_rt_frag_needed()
  sch_sfq: use del_timer_sync() in sfq_destroy()
  net: Add compat support for getsockopt (MCAST_MSFILTER)
  net: Several cleanups for the setsockopt compat support.
  ipvs: fix oops in backup for fwmark conn templates
  bridge: kernel panic when unloading bridge module
  bridge: fix error handling in br_add_if()
  netfilter: {nfnetlink,ip,ip6}_queue: fix skb_over_panic when enlarging packets
  netfilter: x_tables: fix net namespace leak when reading /proc/net/xxx_tables_names
  netfilter: xt_TCPOPTSTRIP: signed tcphoff for ipv6_skip_exthdr() retval
  tcp: Limit cwnd growth when deferring for GSO
  tcp: Allow send-limited cwnd to grow up to max_burst when gso disabled
  [netdrvr] gianfar: Determine TBIPA value dynamically
  ...
hifive-unleashed-5.1
Linus Torvalds 2008-04-30 08:45:48 -07:00
commit 95dfec6ae1
103 changed files with 15341 additions and 808 deletions

View File

@ -1039,7 +1039,7 @@ P: Urs Thuermann
M: urs.thuermann@volkswagen.de
P: Oliver Hartkopp
M: oliver.hartkopp@volkswagen.de
L: socketcan-core@lists.berlios.de
L: socketcan-core@lists.berlios.de (subscribers-only)
W: http://developer.berlios.de/projects/socketcan/
S: Maintained
@ -3577,6 +3577,13 @@ M: pfg@sgi.com
L: linux-ia64@vger.kernel.org
S: Supported
SFC NETWORK DRIVER
P: Steve Hodgson
P: Ben Hutchings
P: Robert Stonehouse
M: linux-net-drivers@solarflare.com
S: Supported
SGI VISUAL WORKSTATION 320 AND 540
P: Andrey Panin
M: pazke@donpac.ru

View File

@ -448,7 +448,9 @@ int npe_send_message(struct npe *npe, const void *msg, const char *what)
return -ETIMEDOUT;
}
#if DEBUG_MSG > 1
debug_msg(npe, "Sending a message took %i cycles\n", cycles);
#endif
return 0;
}
@ -484,7 +486,9 @@ int npe_recv_message(struct npe *npe, void *msg, const char *what)
return -ETIMEDOUT;
}
#if DEBUG_MSG > 1
debug_msg(npe, "Receiving a message took %i cycles\n", cycles);
#endif
return 0;
}

View File

@ -184,6 +184,8 @@ void qmgr_release_queue(unsigned int queue)
case 3: mask[0] = 0xFF; break;
}
mask[1] = mask[2] = mask[3] = 0;
while (addr--)
shift_mask(mask);

View File

@ -33,6 +33,7 @@
#include <linux/interrupt.h>
#include <linux/poison.h>
#include <linux/bitrev.h>
#include <linux/mutex.h>
#include <asm/atomic.h>
#include <asm/io.h>
@ -1177,7 +1178,7 @@ static int amb_open (struct atm_vcc * atm_vcc)
vcc->tx_frame_bits = tx_frame_bits;
down (&dev->vcc_sf);
mutex_lock(&dev->vcc_sf);
if (dev->rxer[vci]) {
// RXer on the channel already, just modify rate...
cmd.request = cpu_to_be32 (SRB_MODIFY_VC_RATE);
@ -1203,7 +1204,7 @@ static int amb_open (struct atm_vcc * atm_vcc)
schedule();
}
dev->txer[vci].tx_present = 1;
up (&dev->vcc_sf);
mutex_unlock(&dev->vcc_sf);
}
if (rxtp->traffic_class != ATM_NONE) {
@ -1211,7 +1212,7 @@ static int amb_open (struct atm_vcc * atm_vcc)
vcc->rx_info.pool = pool;
down (&dev->vcc_sf);
mutex_lock(&dev->vcc_sf);
/* grow RX buffer pool */
if (!dev->rxq[pool].buffers_wanted)
dev->rxq[pool].buffers_wanted = rx_lats;
@ -1237,7 +1238,7 @@ static int amb_open (struct atm_vcc * atm_vcc)
schedule();
// this link allows RX frames through
dev->rxer[vci] = atm_vcc;
up (&dev->vcc_sf);
mutex_unlock(&dev->vcc_sf);
}
// indicate readiness
@ -1262,7 +1263,7 @@ static void amb_close (struct atm_vcc * atm_vcc) {
if (atm_vcc->qos.txtp.traffic_class != ATM_NONE) {
command cmd;
down (&dev->vcc_sf);
mutex_lock(&dev->vcc_sf);
if (dev->rxer[vci]) {
// RXer still on the channel, just modify rate... XXX not really needed
cmd.request = cpu_to_be32 (SRB_MODIFY_VC_RATE);
@ -1277,7 +1278,7 @@ static void amb_close (struct atm_vcc * atm_vcc) {
dev->txer[vci].tx_present = 0;
while (command_do (dev, &cmd))
schedule();
up (&dev->vcc_sf);
mutex_unlock(&dev->vcc_sf);
}
// disable RXing
@ -1287,7 +1288,7 @@ static void amb_close (struct atm_vcc * atm_vcc) {
// this is (the?) one reason why we need the amb_vcc struct
unsigned char pool = vcc->rx_info.pool;
down (&dev->vcc_sf);
mutex_lock(&dev->vcc_sf);
if (dev->txer[vci].tx_present) {
// TXer still on the channel, just go to pool zero XXX not really needed
cmd.request = cpu_to_be32 (SRB_MODIFY_VC_FLAGS);
@ -1314,7 +1315,7 @@ static void amb_close (struct atm_vcc * atm_vcc) {
dev->rxq[pool].buffers_wanted = 0;
drain_rx_pool (dev, pool);
}
up (&dev->vcc_sf);
mutex_unlock(&dev->vcc_sf);
}
// free our structure
@ -2188,7 +2189,7 @@ static void setup_dev(amb_dev *dev, struct pci_dev *pci_dev)
// semaphore for txer/rxer modifications - we cannot use a
// spinlock as the critical region needs to switch processes
init_MUTEX (&dev->vcc_sf);
mutex_init(&dev->vcc_sf);
// queue manipulation spinlocks; we want atomic reads and
// writes to the queue descriptors (handles IRQ and SMP)
// consider replacing "int pending" -> "atomic_t available"

View File

@ -638,7 +638,7 @@ struct amb_dev {
amb_txq txq;
amb_rxq rxq[NUM_RX_POOLS];
struct semaphore vcc_sf;
struct mutex vcc_sf;
amb_tx_info txer[NUM_VCS];
struct atm_vcc * rxer[NUM_VCS];
unsigned int tx_avail;

View File

@ -670,7 +670,7 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id)
memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length);
}
skb->protocol = eth_type_trans(skb,dev);
adapter->stats.rx_bytes += skb->len;
dev->stats.rx_bytes += skb->len;
netif_rx(skb);
dev->last_rx = jiffies;
}
@ -773,12 +773,12 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id)
* received board statistics
*/
case CMD_NETWORK_STATISTICS_RESPONSE:
adapter->stats.rx_packets += adapter->irx_pcb.data.netstat.tot_recv;
adapter->stats.tx_packets += adapter->irx_pcb.data.netstat.tot_xmit;
adapter->stats.rx_crc_errors += adapter->irx_pcb.data.netstat.err_CRC;
adapter->stats.rx_frame_errors += adapter->irx_pcb.data.netstat.err_align;
adapter->stats.rx_fifo_errors += adapter->irx_pcb.data.netstat.err_ovrrun;
adapter->stats.rx_over_errors += adapter->irx_pcb.data.netstat.err_res;
dev->stats.rx_packets += adapter->irx_pcb.data.netstat.tot_recv;
dev->stats.tx_packets += adapter->irx_pcb.data.netstat.tot_xmit;
dev->stats.rx_crc_errors += adapter->irx_pcb.data.netstat.err_CRC;
dev->stats.rx_frame_errors += adapter->irx_pcb.data.netstat.err_align;
dev->stats.rx_fifo_errors += adapter->irx_pcb.data.netstat.err_ovrrun;
dev->stats.rx_over_errors += adapter->irx_pcb.data.netstat.err_res;
adapter->got[CMD_NETWORK_STATISTICS] = 1;
if (elp_debug >= 3)
printk(KERN_DEBUG "%s: interrupt - statistics response received\n", dev->name);
@ -794,11 +794,11 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id)
break;
switch (adapter->irx_pcb.data.xmit_resp.c_stat) {
case 0xffff:
adapter->stats.tx_aborted_errors++;
dev->stats.tx_aborted_errors++;
printk(KERN_INFO "%s: transmit timed out, network cable problem?\n", dev->name);
break;
case 0xfffe:
adapter->stats.tx_fifo_errors++;
dev->stats.tx_fifo_errors++;
printk(KERN_INFO "%s: transmit timed out, FIFO underrun\n", dev->name);
break;
}
@ -986,7 +986,7 @@ static bool send_packet(struct net_device *dev, struct sk_buff *skb)
return false;
}
adapter->stats.tx_bytes += nlen;
dev->stats.tx_bytes += nlen;
/*
* send the adapter a transmit packet command. Ignore segment and offset
@ -1041,7 +1041,6 @@ static bool send_packet(struct net_device *dev, struct sk_buff *skb)
static void elp_timeout(struct net_device *dev)
{
elp_device *adapter = dev->priv;
int stat;
stat = inb_status(dev->base_addr);
@ -1049,7 +1048,7 @@ static void elp_timeout(struct net_device *dev)
if (elp_debug >= 1)
printk(KERN_DEBUG "%s: status %#02x\n", dev->name, stat);
dev->trans_start = jiffies;
adapter->stats.tx_dropped++;
dev->stats.tx_dropped++;
netif_wake_queue(dev);
}
@ -1113,7 +1112,7 @@ static struct net_device_stats *elp_get_stats(struct net_device *dev)
/* If the device is closed, just return the latest stats we have,
- we cannot ask from the adapter without interrupts */
if (!netif_running(dev))
return &adapter->stats;
return &dev->stats;
/* send a get statistics command to the board */
adapter->tx_pcb.command = CMD_NETWORK_STATISTICS;
@ -1126,12 +1125,12 @@ static struct net_device_stats *elp_get_stats(struct net_device *dev)
while (adapter->got[CMD_NETWORK_STATISTICS] == 0 && time_before(jiffies, timeout));
if (time_after_eq(jiffies, timeout)) {
TIMEOUT_MSG(__LINE__);
return &adapter->stats;
return &dev->stats;
}
}
/* statistics are now up to date */
return &adapter->stats;
return &dev->stats;
}
@ -1571,7 +1570,6 @@ static int __init elplus_setup(struct net_device *dev)
dev->set_multicast_list = elp_set_mc_list; /* local */
dev->ethtool_ops = &netdev_ethtool_ops; /* local */
memset(&(adapter->stats), 0, sizeof(struct net_device_stats));
dev->mem_start = dev->mem_end = 0;
err = register_netdev(dev);

View File

@ -264,7 +264,6 @@ typedef struct {
pcb_struct rx_pcb; /* PCB for foreground receiving */
pcb_struct itx_pcb; /* PCB for background sending */
pcb_struct irx_pcb; /* PCB for background receiving */
struct net_device_stats stats;
void *dma_buffer;

View File

@ -167,7 +167,6 @@ enum RxFilter {
enum el3_cardtype { EL3_ISA, EL3_PNP, EL3_MCA, EL3_EISA };
struct el3_private {
struct net_device_stats stats;
spinlock_t lock;
/* skb send-queue */
int head, size;
@ -794,7 +793,6 @@ el3_open(struct net_device *dev)
static void
el3_tx_timeout (struct net_device *dev)
{
struct el3_private *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
/* Transmitter timeout, serious problems. */
@ -802,7 +800,7 @@ el3_tx_timeout (struct net_device *dev)
"Tx FIFO room %d.\n",
dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS),
inw(ioaddr + TX_FREE));
lp->stats.tx_errors++;
dev->stats.tx_errors++;
dev->trans_start = jiffies;
/* Issue TX_RESET and TX_START commands. */
outw(TxReset, ioaddr + EL3_CMD);
@ -820,7 +818,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue (dev);
lp->stats.tx_bytes += skb->len;
dev->stats.tx_bytes += skb->len;
if (el3_debug > 4) {
printk(KERN_DEBUG "%s: el3_start_xmit(length = %u) called, status %4.4x.\n",
@ -881,7 +879,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
int i = 4;
while (--i > 0 && (tx_status = inb(ioaddr + TX_STATUS)) > 0) {
if (tx_status & 0x38) lp->stats.tx_aborted_errors++;
if (tx_status & 0x38) dev->stats.tx_aborted_errors++;
if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD);
if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD);
outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
@ -931,12 +929,11 @@ el3_interrupt(int irq, void *dev_id)
outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
}
if (status & TxComplete) { /* Really Tx error. */
struct el3_private *lp = netdev_priv(dev);
short tx_status;
int i = 4;
while (--i>0 && (tx_status = inb(ioaddr + TX_STATUS)) > 0) {
if (tx_status & 0x38) lp->stats.tx_aborted_errors++;
if (tx_status & 0x38) dev->stats.tx_aborted_errors++;
if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD);
if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD);
outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
@ -1002,7 +999,7 @@ el3_get_stats(struct net_device *dev)
spin_lock_irqsave(&lp->lock, flags);
update_stats(dev);
spin_unlock_irqrestore(&lp->lock, flags);
return &lp->stats;
return &dev->stats;
}
/* Update statistics. We change to register window 6, so this should be run
@ -1012,7 +1009,6 @@ el3_get_stats(struct net_device *dev)
*/
static void update_stats(struct net_device *dev)
{
struct el3_private *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
if (el3_debug > 5)
@ -1021,13 +1017,13 @@ static void update_stats(struct net_device *dev)
outw(StatsDisable, ioaddr + EL3_CMD);
/* Switch to the stats window, and read everything. */
EL3WINDOW(6);
lp->stats.tx_carrier_errors += inb(ioaddr + 0);
lp->stats.tx_heartbeat_errors += inb(ioaddr + 1);
dev->stats.tx_carrier_errors += inb(ioaddr + 0);
dev->stats.tx_heartbeat_errors += inb(ioaddr + 1);
/* Multiple collisions. */ inb(ioaddr + 2);
lp->stats.collisions += inb(ioaddr + 3);
lp->stats.tx_window_errors += inb(ioaddr + 4);
lp->stats.rx_fifo_errors += inb(ioaddr + 5);
lp->stats.tx_packets += inb(ioaddr + 6);
dev->stats.collisions += inb(ioaddr + 3);
dev->stats.tx_window_errors += inb(ioaddr + 4);
dev->stats.rx_fifo_errors += inb(ioaddr + 5);
dev->stats.tx_packets += inb(ioaddr + 6);
/* Rx packets */ inb(ioaddr + 7);
/* Tx deferrals */ inb(ioaddr + 8);
inw(ioaddr + 10); /* Total Rx and Tx octets. */
@ -1042,7 +1038,6 @@ static void update_stats(struct net_device *dev)
static int
el3_rx(struct net_device *dev)
{
struct el3_private *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
short rx_status;
@ -1054,21 +1049,21 @@ el3_rx(struct net_device *dev)
short error = rx_status & 0x3800;
outw(RxDiscard, ioaddr + EL3_CMD);
lp->stats.rx_errors++;
dev->stats.rx_errors++;
switch (error) {
case 0x0000: lp->stats.rx_over_errors++; break;
case 0x0800: lp->stats.rx_length_errors++; break;
case 0x1000: lp->stats.rx_frame_errors++; break;
case 0x1800: lp->stats.rx_length_errors++; break;
case 0x2000: lp->stats.rx_frame_errors++; break;
case 0x2800: lp->stats.rx_crc_errors++; break;
case 0x0000: dev->stats.rx_over_errors++; break;
case 0x0800: dev->stats.rx_length_errors++; break;
case 0x1000: dev->stats.rx_frame_errors++; break;
case 0x1800: dev->stats.rx_length_errors++; break;
case 0x2000: dev->stats.rx_frame_errors++; break;
case 0x2800: dev->stats.rx_crc_errors++; break;
}
} else {
short pkt_len = rx_status & 0x7ff;
struct sk_buff *skb;
skb = dev_alloc_skb(pkt_len+5);
lp->stats.rx_bytes += pkt_len;
dev->stats.rx_bytes += pkt_len;
if (el3_debug > 4)
printk("Receiving packet size %d status %4.4x.\n",
pkt_len, rx_status);
@ -1083,11 +1078,11 @@ el3_rx(struct net_device *dev)
skb->protocol = eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
lp->stats.rx_packets++;
dev->stats.rx_packets++;
continue;
}
outw(RxDiscard, ioaddr + EL3_CMD);
lp->stats.rx_dropped++;
dev->stats.rx_dropped++;
if (el3_debug)
printk("%s: Couldn't allocate a sk_buff of size %d.\n",
dev->name, pkt_len);

View File

@ -310,7 +310,6 @@ struct corkscrew_private {
struct sk_buff *tx_skbuff[TX_RING_SIZE];
unsigned int cur_rx, cur_tx; /* The next free ring entry */
unsigned int dirty_rx, dirty_tx;/* The ring entries to be free()ed. */
struct net_device_stats stats;
struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */
struct timer_list timer; /* Media selection timer. */
int capabilities ; /* Adapter capabilities word. */
@ -983,8 +982,8 @@ static void corkscrew_timeout(struct net_device *dev)
break;
outw(TxEnable, ioaddr + EL3_CMD);
dev->trans_start = jiffies;
vp->stats.tx_errors++;
vp->stats.tx_dropped++;
dev->stats.tx_errors++;
dev->stats.tx_dropped++;
netif_wake_queue(dev);
}
@ -1050,7 +1049,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
}
/* Put out the doubleword header... */
outl(skb->len, ioaddr + TX_FIFO);
vp->stats.tx_bytes += skb->len;
dev->stats.tx_bytes += skb->len;
#ifdef VORTEX_BUS_MASTER
if (vp->bus_master) {
/* Set the bus-master controller to transfer the packet. */
@ -1094,9 +1093,9 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
printk("%s: Tx error, status %2.2x.\n",
dev->name, tx_status);
if (tx_status & 0x04)
vp->stats.tx_fifo_errors++;
dev->stats.tx_fifo_errors++;
if (tx_status & 0x38)
vp->stats.tx_aborted_errors++;
dev->stats.tx_aborted_errors++;
if (tx_status & 0x30) {
int j;
outw(TxReset, ioaddr + EL3_CMD);
@ -1257,7 +1256,6 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id)
static int corkscrew_rx(struct net_device *dev)
{
struct corkscrew_private *vp = netdev_priv(dev);
int ioaddr = dev->base_addr;
int i;
short rx_status;
@ -1271,17 +1269,17 @@ static int corkscrew_rx(struct net_device *dev)
if (corkscrew_debug > 2)
printk(" Rx error: status %2.2x.\n",
rx_error);
vp->stats.rx_errors++;
dev->stats.rx_errors++;
if (rx_error & 0x01)
vp->stats.rx_over_errors++;
dev->stats.rx_over_errors++;
if (rx_error & 0x02)
vp->stats.rx_length_errors++;
dev->stats.rx_length_errors++;
if (rx_error & 0x04)
vp->stats.rx_frame_errors++;
dev->stats.rx_frame_errors++;
if (rx_error & 0x08)
vp->stats.rx_crc_errors++;
dev->stats.rx_crc_errors++;
if (rx_error & 0x10)
vp->stats.rx_length_errors++;
dev->stats.rx_length_errors++;
} else {
/* The packet length: up to 4.5K!. */
short pkt_len = rx_status & 0x1fff;
@ -1301,8 +1299,8 @@ static int corkscrew_rx(struct net_device *dev)
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
vp->stats.rx_packets++;
vp->stats.rx_bytes += pkt_len;
dev->stats.rx_packets++;
dev->stats.rx_bytes += pkt_len;
/* Wait a limited time to go to next packet. */
for (i = 200; i >= 0; i--)
if (! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
@ -1312,7 +1310,7 @@ static int corkscrew_rx(struct net_device *dev)
printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len);
}
outw(RxDiscard, ioaddr + EL3_CMD);
vp->stats.rx_dropped++;
dev->stats.rx_dropped++;
/* Wait a limited time to skip this packet. */
for (i = 200; i >= 0; i--)
if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
@ -1337,23 +1335,23 @@ static int boomerang_rx(struct net_device *dev)
if (corkscrew_debug > 2)
printk(" Rx error: status %2.2x.\n",
rx_error);
vp->stats.rx_errors++;
dev->stats.rx_errors++;
if (rx_error & 0x01)
vp->stats.rx_over_errors++;
dev->stats.rx_over_errors++;
if (rx_error & 0x02)
vp->stats.rx_length_errors++;
dev->stats.rx_length_errors++;
if (rx_error & 0x04)
vp->stats.rx_frame_errors++;
dev->stats.rx_frame_errors++;
if (rx_error & 0x08)
vp->stats.rx_crc_errors++;
dev->stats.rx_crc_errors++;
if (rx_error & 0x10)
vp->stats.rx_length_errors++;
dev->stats.rx_length_errors++;
} else {
/* The packet length: up to 4.5K!. */
short pkt_len = rx_status & 0x1fff;
struct sk_buff *skb;
vp->stats.rx_bytes += pkt_len;
dev->stats.rx_bytes += pkt_len;
if (corkscrew_debug > 4)
printk("Receiving packet size %d status %4.4x.\n",
pkt_len, rx_status);
@ -1388,7 +1386,7 @@ static int boomerang_rx(struct net_device *dev)
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
vp->stats.rx_packets++;
dev->stats.rx_packets++;
}
entry = (++vp->cur_rx) % RX_RING_SIZE;
}
@ -1475,7 +1473,7 @@ static struct net_device_stats *corkscrew_get_stats(struct net_device *dev)
update_stats(dev->base_addr, dev);
spin_unlock_irqrestore(&vp->lock, flags);
}
return &vp->stats;
return &dev->stats;
}
/* Update statistics.
@ -1487,19 +1485,17 @@ static struct net_device_stats *corkscrew_get_stats(struct net_device *dev)
*/
static void update_stats(int ioaddr, struct net_device *dev)
{
struct corkscrew_private *vp = netdev_priv(dev);
/* Unlike the 3c5x9 we need not turn off stats updates while reading. */
/* Switch to the stats window, and read everything. */
EL3WINDOW(6);
vp->stats.tx_carrier_errors += inb(ioaddr + 0);
vp->stats.tx_heartbeat_errors += inb(ioaddr + 1);
dev->stats.tx_carrier_errors += inb(ioaddr + 0);
dev->stats.tx_heartbeat_errors += inb(ioaddr + 1);
/* Multiple collisions. */ inb(ioaddr + 2);
vp->stats.collisions += inb(ioaddr + 3);
vp->stats.tx_window_errors += inb(ioaddr + 4);
vp->stats.rx_fifo_errors += inb(ioaddr + 5);
vp->stats.tx_packets += inb(ioaddr + 6);
vp->stats.tx_packets += (inb(ioaddr + 9) & 0x30) << 4;
dev->stats.collisions += inb(ioaddr + 3);
dev->stats.tx_window_errors += inb(ioaddr + 4);
dev->stats.rx_fifo_errors += inb(ioaddr + 5);
dev->stats.tx_packets += inb(ioaddr + 6);
dev->stats.tx_packets += (inb(ioaddr + 9) & 0x30) << 4;
/* Rx packets */ inb(ioaddr + 7);
/* Must read to clear */
/* Tx deferrals */ inb(ioaddr + 8);

View File

@ -2593,6 +2593,7 @@ config BNX2X
To compile this driver as a module, choose M here: the module
will be called bnx2x. This is recommended.
source "drivers/net/sfc/Kconfig"
endif # NETDEV_10000

View File

@ -253,3 +253,5 @@ obj-$(CONFIG_FS_ENET) += fs_enet/
obj-$(CONFIG_NETXEN_NIC) += netxen/
obj-$(CONFIG_NIU) += niu.o
obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
obj-$(CONFIG_SFC) += sfc/

View File

@ -47,3 +47,11 @@ config EP93XX_ETH
help
This is a driver for the ethernet hardware included in EP93xx CPUs.
Say Y if you are building a kernel for EP93xx based devices.
config IXP4XX_ETH
tristate "Intel IXP4xx Ethernet support"
depends on ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR
select MII
help
Say Y here if you want to use built-in Ethernet ports
on IXP4xx processor.

View File

@ -9,3 +9,4 @@ obj-$(CONFIG_ARM_ETHER3) += ether3.o
obj-$(CONFIG_ARM_ETHER1) += ether1.o
obj-$(CONFIG_ARM_AT91_ETHER) += at91_ether.o
obj-$(CONFIG_EP93XX_ETH) += ep93xx_eth.o
obj-$(CONFIG_IXP4XX_ETH) += ixp4xx_eth.o

File diff suppressed because it is too large Load Diff

View File

@ -27,6 +27,7 @@
#include <linux/phy.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/skbuff.h>
#include <linux/platform_device.h>
@ -42,7 +43,7 @@
#define DRV_NAME "bfin_mac"
#define DRV_VERSION "1.1"
#define DRV_AUTHOR "Bryan Wu, Luke Yang"
#define DRV_DESC "Blackfin BF53[67] BF527 on-chip Ethernet MAC driver"
#define DRV_DESC "Blackfin on-chip Ethernet MAC driver"
MODULE_AUTHOR(DRV_AUTHOR);
MODULE_LICENSE("GPL");
@ -73,8 +74,14 @@ static struct net_dma_desc_tx *current_tx_ptr;
static struct net_dma_desc_tx *tx_desc;
static struct net_dma_desc_rx *rx_desc;
static void bf537mac_disable(void);
static void bf537mac_enable(void);
#if defined(CONFIG_BFIN_MAC_RMII)
static u16 pin_req[] = P_RMII0;
#else
static u16 pin_req[] = P_MII0;
#endif
static void bfin_mac_disable(void);
static void bfin_mac_enable(void);
static void desc_list_free(void)
{
@ -243,27 +250,6 @@ init_error:
/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/
/* Set FER regs to MUX in Ethernet pins */
static int setup_pin_mux(int action)
{
#if defined(CONFIG_BFIN_MAC_RMII)
u16 pin_req[] = P_RMII0;
#else
u16 pin_req[] = P_MII0;
#endif
if (action) {
if (peripheral_request_list(pin_req, DRV_NAME)) {
printk(KERN_ERR DRV_NAME
": Requesting Peripherals failed\n");
return -EFAULT;
}
} else
peripheral_free_list(pin_req);
return 0;
}
/*
* MII operations
*/
@ -322,9 +308,9 @@ static int mdiobus_reset(struct mii_bus *bus)
return 0;
}
static void bf537_adjust_link(struct net_device *dev)
static void bfin_mac_adjust_link(struct net_device *dev)
{
struct bf537mac_local *lp = netdev_priv(dev);
struct bfin_mac_local *lp = netdev_priv(dev);
struct phy_device *phydev = lp->phydev;
unsigned long flags;
int new_state = 0;
@ -395,7 +381,7 @@ static void bf537_adjust_link(struct net_device *dev)
static int mii_probe(struct net_device *dev)
{
struct bf537mac_local *lp = netdev_priv(dev);
struct bfin_mac_local *lp = netdev_priv(dev);
struct phy_device *phydev = NULL;
unsigned short sysctl;
int i;
@ -431,10 +417,10 @@ static int mii_probe(struct net_device *dev)
}
#if defined(CONFIG_BFIN_MAC_RMII)
phydev = phy_connect(dev, phydev->dev.bus_id, &bf537_adjust_link, 0,
phydev = phy_connect(dev, phydev->dev.bus_id, &bfin_mac_adjust_link, 0,
PHY_INTERFACE_MODE_RMII);
#else
phydev = phy_connect(dev, phydev->dev.bus_id, &bf537_adjust_link, 0,
phydev = phy_connect(dev, phydev->dev.bus_id, &bfin_mac_adjust_link, 0,
PHY_INTERFACE_MODE_MII);
#endif
@ -469,6 +455,51 @@ static int mii_probe(struct net_device *dev)
return 0;
}
/*
* Ethtool support
*/
static int
bfin_mac_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct bfin_mac_local *lp = netdev_priv(dev);
if (lp->phydev)
return phy_ethtool_gset(lp->phydev, cmd);
return -EINVAL;
}
static int
bfin_mac_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct bfin_mac_local *lp = netdev_priv(dev);
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (lp->phydev)
return phy_ethtool_sset(lp->phydev, cmd);
return -EINVAL;
}
static void bfin_mac_ethtool_getdrvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
strcpy(info->driver, DRV_NAME);
strcpy(info->version, DRV_VERSION);
strcpy(info->fw_version, "N/A");
strcpy(info->bus_info, dev->dev.bus_id);
}
static struct ethtool_ops bfin_mac_ethtool_ops = {
.get_settings = bfin_mac_ethtool_getsettings,
.set_settings = bfin_mac_ethtool_setsettings,
.get_link = ethtool_op_get_link,
.get_drvinfo = bfin_mac_ethtool_getdrvinfo,
};
/**************************************************************************/
void setup_system_regs(struct net_device *dev)
{
@ -511,7 +542,7 @@ static void setup_mac_addr(u8 *mac_addr)
bfin_write_EMAC_ADDRHI(addr_hi);
}
static int bf537mac_set_mac_address(struct net_device *dev, void *p)
static int bfin_mac_set_mac_address(struct net_device *dev, void *p)
{
struct sockaddr *addr = p;
if (netif_running(dev))
@ -573,7 +604,7 @@ adjust_head:
}
static int bf537mac_hard_start_xmit(struct sk_buff *skb,
static int bfin_mac_hard_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
unsigned int data;
@ -631,7 +662,7 @@ out:
return 0;
}
static void bf537mac_rx(struct net_device *dev)
static void bfin_mac_rx(struct net_device *dev)
{
struct sk_buff *skb, *new_skb;
unsigned short len;
@ -680,7 +711,7 @@ out:
}
/* interrupt routine to handle rx and error signal */
static irqreturn_t bf537mac_interrupt(int irq, void *dev_id)
static irqreturn_t bfin_mac_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
int number = 0;
@ -700,21 +731,21 @@ get_one_packet:
}
real_rx:
bf537mac_rx(dev);
bfin_mac_rx(dev);
number++;
goto get_one_packet;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
static void bf537mac_poll(struct net_device *dev)
static void bfin_mac_poll(struct net_device *dev)
{
disable_irq(IRQ_MAC_RX);
bf537mac_interrupt(IRQ_MAC_RX, dev);
bfin_mac_interrupt(IRQ_MAC_RX, dev);
enable_irq(IRQ_MAC_RX);
}
#endif /* CONFIG_NET_POLL_CONTROLLER */
static void bf537mac_disable(void)
static void bfin_mac_disable(void)
{
unsigned int opmode;
@ -728,7 +759,7 @@ static void bf537mac_disable(void)
/*
* Enable Interrupts, Receive, and Transmit
*/
static void bf537mac_enable(void)
static void bfin_mac_enable(void)
{
u32 opmode;
@ -766,23 +797,23 @@ static void bf537mac_enable(void)
}
/* Our watchdog timed out. Called by the networking layer */
static void bf537mac_timeout(struct net_device *dev)
static void bfin_mac_timeout(struct net_device *dev)
{
pr_debug("%s: %s\n", dev->name, __FUNCTION__);
bf537mac_disable();
bfin_mac_disable();
/* reset tx queue */
tx_list_tail = tx_list_head->next;
bf537mac_enable();
bfin_mac_enable();
/* We can accept TX packets again */
dev->trans_start = jiffies;
netif_wake_queue(dev);
}
static void bf537mac_multicast_hash(struct net_device *dev)
static void bfin_mac_multicast_hash(struct net_device *dev)
{
u32 emac_hashhi, emac_hashlo;
struct dev_mc_list *dmi = dev->mc_list;
@ -821,7 +852,7 @@ static void bf537mac_multicast_hash(struct net_device *dev)
* promiscuous mode (for TCPDUMP and cousins) or accept
* a select set of multicast packets
*/
static void bf537mac_set_multicast_list(struct net_device *dev)
static void bfin_mac_set_multicast_list(struct net_device *dev)
{
u32 sysctl;
@ -840,7 +871,7 @@ static void bf537mac_set_multicast_list(struct net_device *dev)
sysctl = bfin_read_EMAC_OPMODE();
sysctl |= HM;
bfin_write_EMAC_OPMODE(sysctl);
bf537mac_multicast_hash(dev);
bfin_mac_multicast_hash(dev);
} else {
/* clear promisc or multicast mode */
sysctl = bfin_read_EMAC_OPMODE();
@ -852,7 +883,7 @@ static void bf537mac_set_multicast_list(struct net_device *dev)
/*
* this puts the device in an inactive state
*/
static void bf537mac_shutdown(struct net_device *dev)
static void bfin_mac_shutdown(struct net_device *dev)
{
/* Turn off the EMAC */
bfin_write_EMAC_OPMODE(0x00000000);
@ -866,9 +897,9 @@ static void bf537mac_shutdown(struct net_device *dev)
*
* Set up everything, reset the card, etc..
*/
static int bf537mac_open(struct net_device *dev)
static int bfin_mac_open(struct net_device *dev)
{
struct bf537mac_local *lp = netdev_priv(dev);
struct bfin_mac_local *lp = netdev_priv(dev);
int retval;
pr_debug("%s: %s\n", dev->name, __FUNCTION__);
@ -891,8 +922,8 @@ static int bf537mac_open(struct net_device *dev)
phy_start(lp->phydev);
phy_write(lp->phydev, MII_BMCR, BMCR_RESET);
setup_system_regs(dev);
bf537mac_disable();
bf537mac_enable();
bfin_mac_disable();
bfin_mac_enable();
pr_debug("hardware init finished\n");
netif_start_queue(dev);
netif_carrier_on(dev);
@ -906,9 +937,9 @@ static int bf537mac_open(struct net_device *dev)
* and not talk to the outside world. Caused by
* an 'ifconfig ethX down'
*/
static int bf537mac_close(struct net_device *dev)
static int bfin_mac_close(struct net_device *dev)
{
struct bf537mac_local *lp = netdev_priv(dev);
struct bfin_mac_local *lp = netdev_priv(dev);
pr_debug("%s: %s\n", dev->name, __FUNCTION__);
netif_stop_queue(dev);
@ -918,7 +949,7 @@ static int bf537mac_close(struct net_device *dev)
phy_write(lp->phydev, MII_BMCR, BMCR_PDOWN);
/* clear everything */
bf537mac_shutdown(dev);
bfin_mac_shutdown(dev);
/* free the rx/tx buffers */
desc_list_free();
@ -926,46 +957,59 @@ static int bf537mac_close(struct net_device *dev)
return 0;
}
static int __init bf537mac_probe(struct net_device *dev)
static int __init bfin_mac_probe(struct platform_device *pdev)
{
struct bf537mac_local *lp = netdev_priv(dev);
int retval;
int i;
struct net_device *ndev;
struct bfin_mac_local *lp;
int rc, i;
ndev = alloc_etherdev(sizeof(struct bfin_mac_local));
if (!ndev) {
dev_err(&pdev->dev, "Cannot allocate net device!\n");
return -ENOMEM;
}
SET_NETDEV_DEV(ndev, &pdev->dev);
platform_set_drvdata(pdev, ndev);
lp = netdev_priv(ndev);
/* Grab the MAC address in the MAC */
*(__le32 *) (&(dev->dev_addr[0])) = cpu_to_le32(bfin_read_EMAC_ADDRLO());
*(__le16 *) (&(dev->dev_addr[4])) = cpu_to_le16((u16) bfin_read_EMAC_ADDRHI());
*(__le32 *) (&(ndev->dev_addr[0])) = cpu_to_le32(bfin_read_EMAC_ADDRLO());
*(__le16 *) (&(ndev->dev_addr[4])) = cpu_to_le16((u16) bfin_read_EMAC_ADDRHI());
/* probe mac */
/*todo: how to proble? which is revision_register */
bfin_write_EMAC_ADDRLO(0x12345678);
if (bfin_read_EMAC_ADDRLO() != 0x12345678) {
pr_debug("can't detect bf537 mac!\n");
retval = -ENODEV;
goto err_out;
dev_err(&pdev->dev, "Cannot detect Blackfin on-chip ethernet MAC controller!\n");
rc = -ENODEV;
goto out_err_probe_mac;
}
/* set the GPIO pins to Ethernet mode */
retval = setup_pin_mux(1);
if (retval)
return retval;
/*Is it valid? (Did bootloader initialize it?) */
if (!is_valid_ether_addr(dev->dev_addr)) {
/* Grab the MAC from the board somehow - this is done in the
arch/blackfin/mach-bf537/boards/eth_mac.c */
bfin_get_ether_addr(dev->dev_addr);
rc = peripheral_request_list(pin_req, DRV_NAME);
if (rc) {
dev_err(&pdev->dev, "Requesting peripherals failed!\n");
rc = -EFAULT;
goto out_err_setup_pin_mux;
}
/*
* Is it valid? (Did bootloader initialize it?)
* Grab the MAC from the board somehow
* this is done in the arch/blackfin/mach-bfxxx/boards/eth_mac.c
*/
if (!is_valid_ether_addr(ndev->dev_addr))
bfin_get_ether_addr(ndev->dev_addr);
/* If still not valid, get a random one */
if (!is_valid_ether_addr(dev->dev_addr)) {
random_ether_addr(dev->dev_addr);
}
if (!is_valid_ether_addr(ndev->dev_addr))
random_ether_addr(ndev->dev_addr);
setup_mac_addr(dev->dev_addr);
setup_mac_addr(ndev->dev_addr);
/* MDIO bus initial */
lp->mii_bus.priv = dev;
lp->mii_bus.priv = ndev;
lp->mii_bus.read = mdiobus_read;
lp->mii_bus.write = mdiobus_write;
lp->mii_bus.reset = mdiobus_reset;
@ -975,86 +1019,86 @@ static int __init bf537mac_probe(struct net_device *dev)
for (i = 0; i < PHY_MAX_ADDR; ++i)
lp->mii_bus.irq[i] = PHY_POLL;
mdiobus_register(&lp->mii_bus);
rc = mdiobus_register(&lp->mii_bus);
if (rc) {
dev_err(&pdev->dev, "Cannot register MDIO bus!\n");
goto out_err_mdiobus_register;
}
retval = mii_probe(dev);
if (retval)
return retval;
rc = mii_probe(ndev);
if (rc) {
dev_err(&pdev->dev, "MII Probe failed!\n");
goto out_err_mii_probe;
}
/* Fill in the fields of the device structure with ethernet values. */
ether_setup(dev);
ether_setup(ndev);
dev->open = bf537mac_open;
dev->stop = bf537mac_close;
dev->hard_start_xmit = bf537mac_hard_start_xmit;
dev->set_mac_address = bf537mac_set_mac_address;
dev->tx_timeout = bf537mac_timeout;
dev->set_multicast_list = bf537mac_set_multicast_list;
ndev->open = bfin_mac_open;
ndev->stop = bfin_mac_close;
ndev->hard_start_xmit = bfin_mac_hard_start_xmit;
ndev->set_mac_address = bfin_mac_set_mac_address;
ndev->tx_timeout = bfin_mac_timeout;
ndev->set_multicast_list = bfin_mac_set_multicast_list;
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = bf537mac_poll;
ndev->poll_controller = bfin_mac_poll;
#endif
ndev->ethtool_ops = &bfin_mac_ethtool_ops;
spin_lock_init(&lp->lock);
/* now, enable interrupts */
/* register irq handler */
if (request_irq
(IRQ_MAC_RX, bf537mac_interrupt, IRQF_DISABLED | IRQF_SHARED,
"EMAC_RX", dev)) {
printk(KERN_WARNING DRV_NAME
": Unable to attach BlackFin MAC RX interrupt\n");
return -EBUSY;
rc = request_irq(IRQ_MAC_RX, bfin_mac_interrupt,
IRQF_DISABLED | IRQF_SHARED, "EMAC_RX", ndev);
if (rc) {
dev_err(&pdev->dev, "Cannot request Blackfin MAC RX IRQ!\n");
rc = -EBUSY;
goto out_err_request_irq;
}
retval = register_netdev(dev);
if (retval == 0) {
/* now, print out the card info, in a short format.. */
printk(KERN_INFO "%s: Version %s, %s\n",
DRV_NAME, DRV_VERSION, DRV_DESC);
rc = register_netdev(ndev);
if (rc) {
dev_err(&pdev->dev, "Cannot register net device!\n");
goto out_err_reg_ndev;
}
err_out:
return retval;
}
static int bfin_mac_probe(struct platform_device *pdev)
{
struct net_device *ndev;
ndev = alloc_etherdev(sizeof(struct bf537mac_local));
if (!ndev) {
printk(KERN_WARNING DRV_NAME ": could not allocate device\n");
return -ENOMEM;
}
SET_NETDEV_DEV(ndev, &pdev->dev);
platform_set_drvdata(pdev, ndev);
if (bf537mac_probe(ndev) != 0) {
platform_set_drvdata(pdev, NULL);
free_netdev(ndev);
printk(KERN_WARNING DRV_NAME ": not found\n");
return -ENODEV;
}
/* now, print out the card info, in a short format.. */
dev_info(&pdev->dev, "%s, Version %s\n", DRV_DESC, DRV_VERSION);
return 0;
out_err_reg_ndev:
free_irq(IRQ_MAC_RX, ndev);
out_err_request_irq:
out_err_mii_probe:
mdiobus_unregister(&lp->mii_bus);
out_err_mdiobus_register:
peripheral_free_list(pin_req);
out_err_setup_pin_mux:
out_err_probe_mac:
platform_set_drvdata(pdev, NULL);
free_netdev(ndev);
return rc;
}
static int bfin_mac_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
struct bfin_mac_local *lp = netdev_priv(ndev);
platform_set_drvdata(pdev, NULL);
mdiobus_unregister(&lp->mii_bus);
unregister_netdev(ndev);
free_irq(IRQ_MAC_RX, ndev);
free_netdev(ndev);
setup_pin_mux(0);
peripheral_free_list(pin_req);
return 0;
}
@ -1065,7 +1109,7 @@ static int bfin_mac_suspend(struct platform_device *pdev, pm_message_t mesg)
struct net_device *net_dev = platform_get_drvdata(pdev);
if (netif_running(net_dev))
bf537mac_close(net_dev);
bfin_mac_close(net_dev);
return 0;
}
@ -1075,7 +1119,7 @@ static int bfin_mac_resume(struct platform_device *pdev)
struct net_device *net_dev = platform_get_drvdata(pdev);
if (netif_running(net_dev))
bf537mac_open(net_dev);
bfin_mac_open(net_dev);
return 0;
}

View File

@ -49,7 +49,7 @@ struct net_dma_desc_tx {
struct status_area_tx status;
};
struct bf537mac_local {
struct bfin_mac_local {
/*
* these are things that the kernel wants me to keep, so users
* can find out semi-useless statistics of how well the card is

View File

@ -633,7 +633,7 @@ static void __init printEEPROMInfo(struct net_device *dev)
printk(KERN_DEBUG " PC: %d\n", GetBit(Word,ee_PC));
printk(KERN_DEBUG " TPE/AUI: %d\n", GetBit(Word,ee_TPE_AUI));
printk(KERN_DEBUG " Jabber: %d\n", GetBit(Word,ee_Jabber));
printk(KERN_DEBUG " AutoPort: %d\n", GetBit(!Word,ee_Jabber));
printk(KERN_DEBUG " AutoPort: %d\n", !GetBit(Word,ee_AutoPort));
printk(KERN_DEBUG " Duplex: %d\n", GetBit(Word,ee_Duplex));
}

View File

@ -131,8 +131,6 @@ static void free_skb_resources(struct gfar_private *priv);
static void gfar_set_multi(struct net_device *dev);
static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
static void gfar_configure_serdes(struct net_device *dev);
extern int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id, int regnum, u16 value);
extern int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum);
#ifdef CONFIG_GFAR_NAPI
static int gfar_poll(struct napi_struct *napi, int budget);
#endif
@ -477,24 +475,30 @@ static int init_phy(struct net_device *dev)
return 0;
}
/*
* Initialize TBI PHY interface for communicating with the
* SERDES lynx PHY on the chip. We communicate with this PHY
* through the MDIO bus on each controller, treating it as a
* "normal" PHY at the address found in the TBIPA register. We assume
* that the TBIPA register is valid. Either the MDIO bus code will set
* it to a value that doesn't conflict with other PHYs on the bus, or the
* value doesn't matter, as there are no other PHYs on the bus.
*/
static void gfar_configure_serdes(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
struct gfar_mii __iomem *regs =
(void __iomem *)&priv->regs->gfar_mii_regs;
int tbipa = gfar_read(&priv->regs->tbipa);
/* Initialise TBI i/f to communicate with serdes (lynx phy) */
/* Single clk mode, mii mode off(for serdes communication) */
gfar_local_mdio_write(regs, tbipa, MII_TBICON, TBICON_CLK_SELECT);
/* Single clk mode, mii mode off(for aerdes communication) */
gfar_local_mdio_write(regs, TBIPA_VALUE, MII_TBICON, TBICON_CLK_SELECT);
/* Supported pause and full-duplex, no half-duplex */
gfar_local_mdio_write(regs, TBIPA_VALUE, MII_ADVERTISE,
gfar_local_mdio_write(regs, tbipa, MII_ADVERTISE,
ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE |
ADVERTISE_1000XPSE_ASYM);
/* ANEG enable, restart ANEG, full duplex mode, speed[1] set */
gfar_local_mdio_write(regs, TBIPA_VALUE, MII_BMCR, BMCR_ANENABLE |
gfar_local_mdio_write(regs, tbipa, MII_BMCR, BMCR_ANENABLE |
BMCR_ANRESTART | BMCR_FULLDPLX | BMCR_SPEED1000);
}
@ -541,9 +545,6 @@ static void init_registers(struct net_device *dev)
/* Initialize the Minimum Frame Length Register */
gfar_write(&priv->regs->minflr, MINFLR_INIT_SETTINGS);
/* Assign the TBI an address which won't conflict with the PHYs */
gfar_write(&priv->regs->tbipa, TBIPA_VALUE);
}

View File

@ -137,7 +137,6 @@ extern const char gfar_driver_version[];
#define DEFAULT_RXCOUNT 0
#endif /* CONFIG_GFAR_NAPI */
#define TBIPA_VALUE 0x1f
#define MIIMCFG_INIT_VALUE 0x00000007
#define MIIMCFG_RESET 0x80000000
#define MIIMIND_BUSY 0x00000001

View File

@ -78,7 +78,6 @@ int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id,
* same as system mdio bus, used for controlling the external PHYs, for eg.
*/
int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum)
{
u16 value;
@ -122,7 +121,7 @@ int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
}
/* Reset the MIIM registers, and wait for the bus to free */
int gfar_mdio_reset(struct mii_bus *bus)
static int gfar_mdio_reset(struct mii_bus *bus)
{
struct gfar_mii __iomem *regs = (void __iomem *)bus->priv;
unsigned int timeout = PHY_INIT_TIMEOUT;
@ -152,14 +151,15 @@ int gfar_mdio_reset(struct mii_bus *bus)
}
int gfar_mdio_probe(struct device *dev)
static int gfar_mdio_probe(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gianfar_mdio_data *pdata;
struct gfar_mii __iomem *regs;
struct gfar __iomem *enet_regs;
struct mii_bus *new_bus;
struct resource *r;
int err = 0;
int i, err = 0;
if (NULL == dev)
return -EINVAL;
@ -199,6 +199,34 @@ int gfar_mdio_probe(struct device *dev)
new_bus->dev = dev;
dev_set_drvdata(dev, new_bus);
/*
* This is mildly evil, but so is our hardware for doing this.
* Also, we have to cast back to struct gfar_mii because of
* definition weirdness done in gianfar.h.
*/
enet_regs = (struct gfar __iomem *)
((char *)regs - offsetof(struct gfar, gfar_mii_regs));
/* Scan the bus, looking for an empty spot for TBIPA */
gfar_write(&enet_regs->tbipa, 0);
for (i = PHY_MAX_ADDR; i > 0; i--) {
u32 phy_id;
int r;
r = get_phy_id(new_bus, i, &phy_id);
if (r)
return r;
if (phy_id == 0xffffffff)
break;
}
/* The bus is full. We don't support using 31 PHYs, sorry */
if (i == 0)
return -EBUSY;
gfar_write(&enet_regs->tbipa, i);
err = mdiobus_register(new_bus);
if (0 != err) {
@ -218,7 +246,7 @@ reg_map_fail:
}
int gfar_mdio_remove(struct device *dev)
static int gfar_mdio_remove(struct device *dev)
{
struct mii_bus *bus = dev_get_drvdata(dev);

View File

@ -41,6 +41,9 @@ struct gfar_mii {
int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum);
int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id,
int regnum, u16 value);
int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum);
int __init gfar_mdio_init(void);
void gfar_mdio_exit(void);
#endif /* GIANFAR_PHY_H */

View File

@ -48,7 +48,7 @@ config VITESSE_PHY
config SMSC_PHY
tristate "Drivers for SMSC PHYs"
---help---
Currently supports the LAN83C185 PHY
Currently supports the LAN83C185, LAN8187 and LAN8700 PHYs
config BROADCOM_PHY
tristate "Drivers for Broadcom PHYs"

View File

@ -256,7 +256,7 @@ void phy_prepare_link(struct phy_device *phydev,
/**
* phy_connect - connect an ethernet device to a PHY device
* @dev: the network device to connect
* @phy_id: the PHY device to connect
* @bus_id: the id string of the PHY device to connect
* @handler: callback function for state change notifications
* @flags: PHY device's dev_flags
* @interface: PHY device's interface

View File

@ -12,6 +12,8 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* Support added for SMSC LAN8187 and LAN8700 by steve.glendinning@smsc.com
*
*/
#include <linux/kernel.h>
@ -38,7 +40,7 @@
(MII_LAN83C185_ISF_INT6 | MII_LAN83C185_ISF_INT4)
static int lan83c185_config_intr(struct phy_device *phydev)
static int smsc_phy_config_intr(struct phy_device *phydev)
{
int rc = phy_write (phydev, MII_LAN83C185_IM,
((PHY_INTERRUPT_ENABLED == phydev->interrupts)
@ -48,16 +50,16 @@ static int lan83c185_config_intr(struct phy_device *phydev)
return rc < 0 ? rc : 0;
}
static int lan83c185_ack_interrupt(struct phy_device *phydev)
static int smsc_phy_ack_interrupt(struct phy_device *phydev)
{
int rc = phy_read (phydev, MII_LAN83C185_ISF);
return rc < 0 ? rc : 0;
}
static int lan83c185_config_init(struct phy_device *phydev)
static int smsc_phy_config_init(struct phy_device *phydev)
{
return lan83c185_ack_interrupt (phydev);
return smsc_phy_ack_interrupt (phydev);
}
@ -73,22 +75,87 @@ static struct phy_driver lan83c185_driver = {
/* basic functions */
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
.config_init = lan83c185_config_init,
.config_init = smsc_phy_config_init,
/* IRQ related */
.ack_interrupt = lan83c185_ack_interrupt,
.config_intr = lan83c185_config_intr,
.ack_interrupt = smsc_phy_ack_interrupt,
.config_intr = smsc_phy_config_intr,
.driver = { .owner = THIS_MODULE, }
};
static struct phy_driver lan8187_driver = {
.phy_id = 0x0007c0b0, /* OUI=0x00800f, Model#=0x0b */
.phy_id_mask = 0xfffffff0,
.name = "SMSC LAN8187",
.features = (PHY_BASIC_FEATURES | SUPPORTED_Pause
| SUPPORTED_Asym_Pause),
.flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
/* basic functions */
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
.config_init = smsc_phy_config_init,
/* IRQ related */
.ack_interrupt = smsc_phy_ack_interrupt,
.config_intr = smsc_phy_config_intr,
.driver = { .owner = THIS_MODULE, }
};
static struct phy_driver lan8700_driver = {
.phy_id = 0x0007c0c0, /* OUI=0x00800f, Model#=0x0c */
.phy_id_mask = 0xfffffff0,
.name = "SMSC LAN8700",
.features = (PHY_BASIC_FEATURES | SUPPORTED_Pause
| SUPPORTED_Asym_Pause),
.flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
/* basic functions */
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
.config_init = smsc_phy_config_init,
/* IRQ related */
.ack_interrupt = smsc_phy_ack_interrupt,
.config_intr = smsc_phy_config_intr,
.driver = { .owner = THIS_MODULE, }
};
static int __init smsc_init(void)
{
return phy_driver_register (&lan83c185_driver);
int ret;
ret = phy_driver_register (&lan83c185_driver);
if (ret)
goto err1;
ret = phy_driver_register (&lan8187_driver);
if (ret)
goto err2;
ret = phy_driver_register (&lan8700_driver);
if (ret)
goto err3;
return 0;
err3:
phy_driver_unregister (&lan8187_driver);
err2:
phy_driver_unregister (&lan83c185_driver);
err1:
return ret;
}
static void __exit smsc_exit(void)
{
phy_driver_unregister (&lan8700_driver);
phy_driver_unregister (&lan8187_driver);
phy_driver_unregister (&lan83c185_driver);
}

View File

@ -1617,6 +1617,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
SET_NETDEV_DEV(dev, &pdev->dev);
tp = netdev_priv(dev);
tp->dev = dev;
tp->pci_dev = pdev;
tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT);
/* enable device (incl. PCI PM wakeup and hotplug setup) */
@ -1705,18 +1706,18 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rtl8169_print_mac_version(tp);
for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--) {
for (i = 0; i < ARRAY_SIZE(rtl_chip_info); i++) {
if (tp->mac_version == rtl_chip_info[i].mac_version)
break;
}
if (i < 0) {
if (i == ARRAY_SIZE(rtl_chip_info)) {
/* Unknown chip: assume array element #0, original RTL-8169 */
if (netif_msg_probe(tp)) {
dev_printk(KERN_DEBUG, &pdev->dev,
"unknown chip version, assuming %s\n",
rtl_chip_info[0].name);
}
i++;
i = 0;
}
tp->chipset = i;
@ -1777,7 +1778,6 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
#endif
tp->intr_mask = 0xffff;
tp->pci_dev = pdev;
tp->mmio_addr = ioaddr;
tp->align = cfg->align;
tp->hw_start = cfg->hw_start;

View File

@ -86,7 +86,7 @@
#include "s2io.h"
#include "s2io-regs.h"
#define DRV_VERSION "2.0.26.22"
#define DRV_VERSION "2.0.26.23"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
@ -809,6 +809,7 @@ static int init_shared_mem(struct s2io_nic *nic)
config->rx_cfg[i].num_rxd - 1;
mac_control->rings[i].nic = nic;
mac_control->rings[i].ring_no = i;
mac_control->rings[i].lro = lro_enable;
blk_cnt = config->rx_cfg[i].num_rxd /
(rxd_count[nic->rxd_mode] + 1);
@ -1560,113 +1561,112 @@ static int init_nic(struct s2io_nic *nic)
writeq(val64, &bar0->tx_fifo_partition_0);
/* Filling the Rx round robin registers as per the
* number of Rings and steering based on QoS.
*/
* number of Rings and steering based on QoS with
* equal priority.
*/
switch (config->rx_ring_num) {
case 1:
val64 = 0x0;
writeq(val64, &bar0->rx_w_round_robin_0);
writeq(val64, &bar0->rx_w_round_robin_1);
writeq(val64, &bar0->rx_w_round_robin_2);
writeq(val64, &bar0->rx_w_round_robin_3);
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080808080808080ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 2:
val64 = 0x0000010000010000ULL;
val64 = 0x0001000100010001ULL;
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;
val64 = 0x0001000100000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080808040404040ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 3:
val64 = 0x0001000102000001ULL;
val64 = 0x0001020001020001ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
val64 = 0x0001020000010001ULL;
val64 = 0x0200010200010200ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
val64 = 0x0200000100010200ULL;
val64 = 0x0102000102000102ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
val64 = 0x0001000102000001ULL;
val64 = 0x0001020001020001ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
val64 = 0x0001020000000000ULL;
val64 = 0x0200010200000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080804040402020ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 4:
val64 = 0x0001020300010200ULL;
val64 = 0x0001020300010203ULL;
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;
val64 = 0x0001020300000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080404020201010ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 5:
val64 = 0x0001000203000102ULL;
val64 = 0x0001020304000102ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
val64 = 0x0001020001030004ULL;
val64 = 0x0304000102030400ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
val64 = 0x0001000203000102ULL;
val64 = 0x0102030400010203ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
val64 = 0x0001020001030004ULL;
val64 = 0x0400010203040001ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
val64 = 0x0001000000000000ULL;
val64 = 0x0203040000000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080404020201008ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 6:
val64 = 0x0001020304000102ULL;
val64 = 0x0001020304050001ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
val64 = 0x0304050001020001ULL;
val64 = 0x0203040500010203ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
val64 = 0x0203000100000102ULL;
val64 = 0x0405000102030405ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
val64 = 0x0304000102030405ULL;
val64 = 0x0001020304050001ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
val64 = 0x0001000200000000ULL;
val64 = 0x0203040500000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080404020100804ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 7:
val64 = 0x0001020001020300ULL;
val64 = 0x0001020304050600ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
val64 = 0x0102030400010203ULL;
val64 = 0x0102030405060001ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
val64 = 0x0405060001020001ULL;
val64 = 0x0203040506000102ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
val64 = 0x0304050000010200ULL;
val64 = 0x0304050600010203ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
val64 = 0x0102030000000000ULL;
val64 = 0x0405060000000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080402010080402ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 8:
val64 = 0x0001020300040105ULL;
val64 = 0x0001020304050607ULL;
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;
val64 = 0x0001020300000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8040201008040201ULL;
@ -2499,8 +2499,7 @@ static void stop_nic(struct s2io_nic *nic)
/**
* fill_rx_buffers - Allocates the Rx side skbs
* @nic: device private variable
* @ring_no: ring number
* @ring_info: per ring structure
* Description:
* The function allocates Rx side skbs and puts the physical
* address of these buffers into the RxD buffer pointers, so that the NIC
@ -2518,103 +2517,94 @@ 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)
static int fill_rx_buffers(struct ring_info *ring)
{
struct net_device *dev = nic->dev;
struct sk_buff *skb;
struct RxD_t *rxdp;
int off, off1, size, block_no, block_no1;
int off, size, block_no, block_no1;
u32 alloc_tab = 0;
u32 alloc_cnt;
struct mac_info *mac_control;
struct config_param *config;
u64 tmp;
struct buffAdd *ba;
struct RxD_t *first_rxdp = NULL;
u64 Buffer0_ptr = 0, Buffer1_ptr = 0;
int rxd_index = 0;
struct RxD1 *rxdp1;
struct RxD3 *rxdp3;
struct swStat *stats = &nic->mac_control.stats_info->sw_stat;
struct swStat *stats = &ring->nic->mac_control.stats_info->sw_stat;
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]);
alloc_cnt = ring->pkt_cnt - ring->rx_bufs_left;
block_no1 = mac_control->rings[ring_no].rx_curr_get_info.block_index;
off1 = mac_control->rings[ring_no].rx_curr_get_info.offset;
block_no1 = ring->rx_curr_get_info.block_index;
while (alloc_tab < alloc_cnt) {
block_no = mac_control->rings[ring_no].rx_curr_put_info.
block_index;
off = mac_control->rings[ring_no].rx_curr_put_info.offset;
block_no = ring->rx_curr_put_info.block_index;
rxdp = mac_control->rings[ring_no].
rx_blocks[block_no].rxds[off].virt_addr;
off = ring->rx_curr_put_info.offset;
if ((block_no == block_no1) && (off == off1) &&
(rxdp->Host_Control)) {
rxdp = ring->rx_blocks[block_no].rxds[off].virt_addr;
rxd_index = off + 1;
if (block_no)
rxd_index += (block_no * ring->rxd_count);
if ((block_no == block_no1) &&
(off == ring->rx_curr_get_info.offset) &&
(rxdp->Host_Control)) {
DBG_PRINT(INTR_DBG, "%s: Get and Put",
dev->name);
ring->dev->name);
DBG_PRINT(INTR_DBG, " info equated\n");
goto end;
}
if (off && (off == rxd_count[nic->rxd_mode])) {
mac_control->rings[ring_no].rx_curr_put_info.
block_index++;
if (mac_control->rings[ring_no].rx_curr_put_info.
block_index == mac_control->rings[ring_no].
block_count)
mac_control->rings[ring_no].rx_curr_put_info.
block_index = 0;
block_no = mac_control->rings[ring_no].
rx_curr_put_info.block_index;
if (off == rxd_count[nic->rxd_mode])
off = 0;
mac_control->rings[ring_no].rx_curr_put_info.
offset = off;
rxdp = mac_control->rings[ring_no].
rx_blocks[block_no].block_virt_addr;
if (off && (off == ring->rxd_count)) {
ring->rx_curr_put_info.block_index++;
if (ring->rx_curr_put_info.block_index ==
ring->block_count)
ring->rx_curr_put_info.block_index = 0;
block_no = ring->rx_curr_put_info.block_index;
off = 0;
ring->rx_curr_put_info.offset = off;
rxdp = ring->rx_blocks[block_no].block_virt_addr;
DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
dev->name, rxdp);
ring->dev->name, rxdp);
}
if ((rxdp->Control_1 & RXD_OWN_XENA) &&
((nic->rxd_mode == RXD_MODE_3B) &&
((ring->rxd_mode == RXD_MODE_3B) &&
(rxdp->Control_2 & s2BIT(0)))) {
mac_control->rings[ring_no].rx_curr_put_info.
offset = off;
ring->rx_curr_put_info.offset = off;
goto end;
}
/* calculate size of skb based on ring mode */
size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
size = ring->mtu + HEADER_ETHERNET_II_802_3_SIZE +
HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
if (nic->rxd_mode == RXD_MODE_1)
if (ring->rxd_mode == RXD_MODE_1)
size += NET_IP_ALIGN;
else
size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
size = ring->mtu + ALIGN_SIZE + BUF0_LEN + 4;
/* allocate skb */
skb = dev_alloc_skb(size);
if(!skb) {
DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
DBG_PRINT(INFO_DBG, "%s: Out of ", ring->dev->name);
DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n");
if (first_rxdp) {
wmb();
first_rxdp->Control_1 |= RXD_OWN_XENA;
}
nic->mac_control.stats_info->sw_stat. \
mem_alloc_fail_cnt++;
stats->mem_alloc_fail_cnt++;
return -ENOMEM ;
}
nic->mac_control.stats_info->sw_stat.mem_allocated
+= skb->truesize;
if (nic->rxd_mode == RXD_MODE_1) {
stats->mem_allocated += skb->truesize;
if (ring->rxd_mode == RXD_MODE_1) {
/* 1 buffer mode - normal operation mode */
rxdp1 = (struct RxD1*)rxdp;
memset(rxdp, 0, sizeof(struct RxD1));
skb_reserve(skb, NET_IP_ALIGN);
rxdp1->Buffer0_ptr = pci_map_single
(nic->pdev, skb->data, size - NET_IP_ALIGN,
(ring->pdev, skb->data, size - NET_IP_ALIGN,
PCI_DMA_FROMDEVICE);
if( (rxdp1->Buffer0_ptr == 0) ||
(rxdp1->Buffer0_ptr ==
@ -2623,8 +2613,8 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
rxdp->Control_2 =
SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
} else if (nic->rxd_mode == RXD_MODE_3B) {
rxdp->Host_Control = (unsigned long) (skb);
} else if (ring->rxd_mode == RXD_MODE_3B) {
/*
* 2 buffer mode -
* 2 buffer mode provides 128
@ -2640,7 +2630,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
rxdp3->Buffer0_ptr = Buffer0_ptr;
rxdp3->Buffer1_ptr = Buffer1_ptr;
ba = &mac_control->rings[ring_no].ba[block_no][off];
ba = &ring->ba[block_no][off];
skb_reserve(skb, BUF0_LEN);
tmp = (u64)(unsigned long) skb->data;
tmp += ALIGN_SIZE;
@ -2650,10 +2640,10 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
if (!(rxdp3->Buffer0_ptr))
rxdp3->Buffer0_ptr =
pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
PCI_DMA_FROMDEVICE);
pci_map_single(ring->pdev, ba->ba_0,
BUF0_LEN, PCI_DMA_FROMDEVICE);
else
pci_dma_sync_single_for_device(nic->pdev,
pci_dma_sync_single_for_device(ring->pdev,
(dma_addr_t) rxdp3->Buffer0_ptr,
BUF0_LEN, PCI_DMA_FROMDEVICE);
if( (rxdp3->Buffer0_ptr == 0) ||
@ -2661,7 +2651,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
goto pci_map_failed;
rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
if (nic->rxd_mode == RXD_MODE_3B) {
if (ring->rxd_mode == RXD_MODE_3B) {
/* Two buffer mode */
/*
@ -2669,39 +2659,42 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
* L4 payload
*/
rxdp3->Buffer2_ptr = pci_map_single
(nic->pdev, skb->data, dev->mtu + 4,
(ring->pdev, skb->data, ring->mtu + 4,
PCI_DMA_FROMDEVICE);
if( (rxdp3->Buffer2_ptr == 0) ||
(rxdp3->Buffer2_ptr == DMA_ERROR_CODE))
goto pci_map_failed;
rxdp3->Buffer1_ptr =
pci_map_single(nic->pdev,
if (!rxdp3->Buffer1_ptr)
rxdp3->Buffer1_ptr =
pci_map_single(ring->pdev,
ba->ba_1, BUF1_LEN,
PCI_DMA_FROMDEVICE);
if( (rxdp3->Buffer1_ptr == 0) ||
(rxdp3->Buffer1_ptr == DMA_ERROR_CODE)) {
pci_unmap_single
(nic->pdev,
(dma_addr_t)rxdp3->Buffer2_ptr,
dev->mtu + 4,
(ring->pdev,
(dma_addr_t)(unsigned long)
skb->data,
ring->mtu + 4,
PCI_DMA_FROMDEVICE);
goto pci_map_failed;
}
rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
rxdp->Control_2 |= SET_BUFFER2_SIZE_3
(dev->mtu + 4);
(ring->mtu + 4);
}
rxdp->Control_2 |= s2BIT(0);
rxdp->Host_Control = (unsigned long) (skb);
}
rxdp->Host_Control = (unsigned long) (skb);
if (alloc_tab & ((1 << rxsync_frequency) - 1))
rxdp->Control_1 |= RXD_OWN_XENA;
off++;
if (off == (rxd_count[nic->rxd_mode] + 1))
if (off == (ring->rxd_count + 1))
off = 0;
mac_control->rings[ring_no].rx_curr_put_info.offset = off;
ring->rx_curr_put_info.offset = off;
rxdp->Control_2 |= SET_RXD_MARKER;
if (!(alloc_tab & ((1 << rxsync_frequency) - 1))) {
@ -2711,7 +2704,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
}
first_rxdp = rxdp;
}
atomic_inc(&nic->rx_bufs_left[ring_no]);
ring->rx_bufs_left += 1;
alloc_tab++;
}
@ -2783,7 +2776,7 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
}
sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize;
dev_kfree_skb(skb);
atomic_dec(&sp->rx_bufs_left[ring_no]);
mac_control->rings[ring_no].rx_bufs_left -= 1;
}
}
@ -2814,7 +2807,7 @@ static void free_rx_buffers(struct s2io_nic *sp)
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);
mac_control->rings[i].rx_bufs_left = 0;
DBG_PRINT(INIT_DBG, "%s:Freed 0x%x Rx Buffers on ring%d\n",
dev->name, buf_cnt, i);
}
@ -2864,7 +2857,7 @@ static int s2io_poll(struct napi_struct *napi, int budget)
netif_rx_complete(dev, napi);
for (i = 0; i < config->rx_ring_num; i++) {
if (fill_rx_buffers(nic, i) == -ENOMEM) {
if (fill_rx_buffers(&mac_control->rings[i]) == -ENOMEM) {
DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
break;
@ -2877,7 +2870,7 @@ static int s2io_poll(struct napi_struct *napi, int budget)
no_rx:
for (i = 0; i < config->rx_ring_num; i++) {
if (fill_rx_buffers(nic, i) == -ENOMEM) {
if (fill_rx_buffers(&mac_control->rings[i]) == -ENOMEM) {
DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
break;
@ -2928,7 +2921,7 @@ static void s2io_netpoll(struct net_device *dev)
rx_intr_handler(&mac_control->rings[i]);
for (i = 0; i < config->rx_ring_num; i++) {
if (fill_rx_buffers(nic, i) == -ENOMEM) {
if (fill_rx_buffers(&mac_control->rings[i]) == -ENOMEM) {
DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
DBG_PRINT(INFO_DBG, " in Rx Netpoll!!\n");
break;
@ -2953,8 +2946,6 @@ static void s2io_netpoll(struct net_device *dev)
*/
static void rx_intr_handler(struct ring_info *ring_data)
{
struct s2io_nic *nic = ring_data->nic;
struct net_device *dev = (struct net_device *) nic->dev;
int get_block, put_block;
struct rx_curr_get_info get_info, put_info;
struct RxD_t *rxdp;
@ -2977,33 +2968,34 @@ static void rx_intr_handler(struct ring_info *ring_data)
*/
if ((get_block == put_block) &&
(get_info.offset + 1) == put_info.offset) {
DBG_PRINT(INTR_DBG, "%s: Ring Full\n",dev->name);
DBG_PRINT(INTR_DBG, "%s: Ring Full\n",
ring_data->dev->name);
break;
}
skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control);
if (skb == NULL) {
DBG_PRINT(ERR_DBG, "%s: The skb is ",
dev->name);
ring_data->dev->name);
DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
return;
}
if (nic->rxd_mode == RXD_MODE_1) {
if (ring_data->rxd_mode == RXD_MODE_1) {
rxdp1 = (struct RxD1*)rxdp;
pci_unmap_single(nic->pdev, (dma_addr_t)
pci_unmap_single(ring_data->pdev, (dma_addr_t)
rxdp1->Buffer0_ptr,
dev->mtu +
ring_data->mtu +
HEADER_ETHERNET_II_802_3_SIZE +
HEADER_802_2_SIZE +
HEADER_SNAP_SIZE,
PCI_DMA_FROMDEVICE);
} else if (nic->rxd_mode == RXD_MODE_3B) {
} else if (ring_data->rxd_mode == RXD_MODE_3B) {
rxdp3 = (struct RxD3*)rxdp;
pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
pci_dma_sync_single_for_cpu(ring_data->pdev, (dma_addr_t)
rxdp3->Buffer0_ptr,
BUF0_LEN, PCI_DMA_FROMDEVICE);
pci_unmap_single(nic->pdev, (dma_addr_t)
pci_unmap_single(ring_data->pdev, (dma_addr_t)
rxdp3->Buffer2_ptr,
dev->mtu + 4,
ring_data->mtu + 4,
PCI_DMA_FROMDEVICE);
}
prefetch(skb->data);
@ -3012,7 +3004,7 @@ static void rx_intr_handler(struct ring_info *ring_data)
ring_data->rx_curr_get_info.offset = get_info.offset;
rxdp = ring_data->rx_blocks[get_block].
rxds[get_info.offset].virt_addr;
if (get_info.offset == rxd_count[nic->rxd_mode]) {
if (get_info.offset == rxd_count[ring_data->rxd_mode]) {
get_info.offset = 0;
ring_data->rx_curr_get_info.offset = get_info.offset;
get_block++;
@ -3022,19 +3014,21 @@ static void rx_intr_handler(struct ring_info *ring_data)
rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
}
nic->pkts_to_process -= 1;
if ((napi) && (!nic->pkts_to_process))
break;
if(ring_data->nic->config.napi){
ring_data->nic->pkts_to_process -= 1;
if (!ring_data->nic->pkts_to_process)
break;
}
pkt_cnt++;
if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts))
break;
}
if (nic->lro) {
if (ring_data->lro) {
/* Clear all LRO sessions before exiting */
for (i=0; i<MAX_LRO_SESSIONS; i++) {
struct lro *lro = &nic->lro0_n[i];
struct lro *lro = &ring_data->lro0_n[i];
if (lro->in_use) {
update_L3L4_header(nic, lro);
update_L3L4_header(ring_data->nic, lro);
queue_rx_frame(lro->parent, lro->vlan_tag);
clear_lro_session(lro);
}
@ -4333,10 +4327,10 @@ s2io_alarm_handle(unsigned long data)
mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
}
static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
static int s2io_chk_rx_buffers(struct ring_info *ring)
{
if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
DBG_PRINT(INFO_DBG, "%s:Out of memory", sp->dev->name);
if (fill_rx_buffers(ring) == -ENOMEM) {
DBG_PRINT(INFO_DBG, "%s:Out of memory", ring->dev->name);
DBG_PRINT(INFO_DBG, " in Rx Intr!!\n");
}
return 0;
@ -4351,7 +4345,7 @@ static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
return IRQ_HANDLED;
rx_intr_handler(ring);
s2io_chk_rx_buffers(sp, ring->ring_no);
s2io_chk_rx_buffers(ring);
return IRQ_HANDLED;
}
@ -4809,7 +4803,7 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
*/
if (!config->napi) {
for (i = 0; i < config->rx_ring_num; i++)
s2io_chk_rx_buffers(sp, i);
s2io_chk_rx_buffers(&mac_control->rings[i]);
}
writeq(sp->general_int_mask, &bar0->general_int_mask);
readl(&bar0->general_int_status);
@ -4866,6 +4860,7 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev)
struct s2io_nic *sp = dev->priv;
struct mac_info *mac_control;
struct config_param *config;
int i;
mac_control = &sp->mac_control;
@ -4885,6 +4880,13 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev)
sp->stats.rx_length_errors =
le64_to_cpu(mac_control->stats_info->rmac_long_frms);
/* collect per-ring rx_packets and rx_bytes */
sp->stats.rx_packets = sp->stats.rx_bytes = 0;
for (i = 0; i < config->rx_ring_num; i++) {
sp->stats.rx_packets += mac_control->rings[i].rx_packets;
sp->stats.rx_bytes += mac_control->rings[i].rx_bytes;
}
return (&sp->stats);
}
@ -7157,7 +7159,9 @@ static int s2io_card_up(struct s2io_nic * sp)
config = &sp->config;
for (i = 0; i < config->rx_ring_num; i++) {
if ((ret = fill_rx_buffers(sp, i))) {
mac_control->rings[i].mtu = dev->mtu;
ret = fill_rx_buffers(&mac_control->rings[i]);
if (ret) {
DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n",
dev->name);
s2io_reset(sp);
@ -7165,7 +7169,7 @@ static int s2io_card_up(struct s2io_nic * sp)
return -ENOMEM;
}
DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
atomic_read(&sp->rx_bufs_left[i]));
mac_control->rings[i].rx_bufs_left);
}
/* Initialise napi */
@ -7300,7 +7304,7 @@ static void s2io_tx_watchdog(struct net_device *dev)
static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
{
struct s2io_nic *sp = ring_data->nic;
struct net_device *dev = (struct net_device *) sp->dev;
struct net_device *dev = (struct net_device *) ring_data->dev;
struct sk_buff *skb = (struct sk_buff *)
((unsigned long) rxdp->Host_Control);
int ring_no = ring_data->ring_no;
@ -7377,19 +7381,19 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
sp->mac_control.stats_info->sw_stat.mem_freed
+= skb->truesize;
dev_kfree_skb(skb);
atomic_dec(&sp->rx_bufs_left[ring_no]);
ring_data->rx_bufs_left -= 1;
rxdp->Host_Control = 0;
return 0;
}
}
/* Updating statistics */
sp->stats.rx_packets++;
ring_data->rx_packets++;
rxdp->Host_Control = 0;
if (sp->rxd_mode == RXD_MODE_1) {
int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
sp->stats.rx_bytes += len;
ring_data->rx_bytes += len;
skb_put(skb, len);
} else if (sp->rxd_mode == RXD_MODE_3B) {
@ -7400,13 +7404,13 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
unsigned char *buff = skb_push(skb, buf0_len);
struct buffAdd *ba = &ring_data->ba[get_block][get_off];
sp->stats.rx_bytes += buf0_len + buf2_len;
ring_data->rx_bytes += buf0_len + buf2_len;
memcpy(buff, ba->ba_0, buf0_len);
skb_put(skb, buf2_len);
}
if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!sp->lro) ||
(sp->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) &&
if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!ring_data->lro) ||
(ring_data->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) &&
(sp->rx_csum)) {
l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1);
l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1);
@ -7417,14 +7421,14 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
* a flag in the RxD.
*/
skb->ip_summed = CHECKSUM_UNNECESSARY;
if (sp->lro) {
if (ring_data->lro) {
u32 tcp_len;
u8 *tcp;
int ret = 0;
ret = s2io_club_tcp_session(skb->data, &tcp,
&tcp_len, &lro,
rxdp, sp);
ret = s2io_club_tcp_session(ring_data,
skb->data, &tcp, &tcp_len, &lro,
rxdp, sp);
switch (ret) {
case 3: /* Begin anew */
lro->parent = skb;
@ -7486,7 +7490,7 @@ send_up:
queue_rx_frame(skb, RXD_GET_VLAN_TAG(rxdp->Control_2));
dev->last_rx = jiffies;
aggregate:
atomic_dec(&sp->rx_bufs_left[ring_no]);
sp->mac_control.rings[ring_no].rx_bufs_left -= 1;
return SUCCESS;
}
@ -7603,12 +7607,14 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type,
tx_steering_type = NO_STEERING;
}
if ( rx_ring_num > 8) {
DBG_PRINT(ERR_DBG, "s2io: Requested number of Rx rings not "
if (rx_ring_num > MAX_RX_RINGS) {
DBG_PRINT(ERR_DBG, "s2io: Requested number of rx rings not "
"supported\n");
DBG_PRINT(ERR_DBG, "s2io: Default to 8 Rx rings\n");
rx_ring_num = 8;
DBG_PRINT(ERR_DBG, "s2io: Default to %d rx rings\n",
MAX_RX_RINGS);
rx_ring_num = MAX_RX_RINGS;
}
if (*dev_intr_type != INTA)
napi = 0;
@ -7836,10 +7842,15 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Rx side parameters. */
config->rx_ring_num = rx_ring_num;
for (i = 0; i < MAX_RX_RINGS; i++) {
for (i = 0; i < config->rx_ring_num; i++) {
config->rx_cfg[i].num_rxd = rx_ring_sz[i] *
(rxd_count[sp->rxd_mode] + 1);
config->rx_cfg[i].ring_priority = i;
mac_control->rings[i].rx_bufs_left = 0;
mac_control->rings[i].rxd_mode = sp->rxd_mode;
mac_control->rings[i].rxd_count = rxd_count[sp->rxd_mode];
mac_control->rings[i].pdev = sp->pdev;
mac_control->rings[i].dev = sp->dev;
}
for (i = 0; i < rx_ring_num; i++) {
@ -7854,10 +7865,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
mac_control->mc_pause_threshold_q4q7 = mc_pause_threshold_q4q7;
/* Initialize Ring buffer parameters. */
for (i = 0; i < config->rx_ring_num; i++)
atomic_set(&sp->rx_bufs_left[i], 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",
@ -8077,6 +8084,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
DBG_PRINT(ERR_DBG, "%s: Using %d Tx fifo(s)\n", dev->name,
sp->config.tx_fifo_num);
DBG_PRINT(ERR_DBG, "%s: Using %d Rx ring(s)\n", dev->name,
sp->config.rx_ring_num);
switch(sp->config.intr_type) {
case INTA:
DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
@ -8391,8 +8401,9 @@ static int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip,
}
static int
s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
struct RxD_t *rxdp, struct s2io_nic *sp)
s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, u8 **tcp,
u32 *tcp_len, struct lro **lro, struct RxD_t *rxdp,
struct s2io_nic *sp)
{
struct iphdr *ip;
struct tcphdr *tcph;
@ -8410,7 +8421,7 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
tcph = (struct tcphdr *)*tcp;
*tcp_len = get_l4_pyld_length(ip, tcph);
for (i=0; i<MAX_LRO_SESSIONS; i++) {
struct lro *l_lro = &sp->lro0_n[i];
struct lro *l_lro = &ring_data->lro0_n[i];
if (l_lro->in_use) {
if (check_for_socket_match(l_lro, ip, tcph))
continue;
@ -8448,7 +8459,7 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
}
for (i=0; i<MAX_LRO_SESSIONS; i++) {
struct lro *l_lro = &sp->lro0_n[i];
struct lro *l_lro = &ring_data->lro0_n[i];
if (!(l_lro->in_use)) {
*lro = l_lro;
ret = 3; /* Begin anew */

View File

@ -678,11 +678,53 @@ struct rx_block_info {
struct rxd_info *rxds;
};
/* Data structure to represent a LRO session */
struct lro {
struct sk_buff *parent;
struct sk_buff *last_frag;
u8 *l2h;
struct iphdr *iph;
struct tcphdr *tcph;
u32 tcp_next_seq;
__be32 tcp_ack;
int total_len;
int frags_len;
int sg_num;
int in_use;
__be16 window;
u16 vlan_tag;
u32 cur_tsval;
__be32 cur_tsecr;
u8 saw_ts;
} ____cacheline_aligned;
/* Ring specific structure */
struct ring_info {
/* The ring number */
int ring_no;
/* per-ring buffer counter */
u32 rx_bufs_left;
#define MAX_LRO_SESSIONS 32
struct lro lro0_n[MAX_LRO_SESSIONS];
u8 lro;
/* copy of sp->rxd_mode flag */
int rxd_mode;
/* Number of rxds per block for the rxd_mode */
int rxd_count;
/* copy of sp pointer */
struct s2io_nic *nic;
/* copy of sp->dev pointer */
struct net_device *dev;
/* copy of sp->pdev pointer */
struct pci_dev *pdev;
/*
* Place holders for the virtual and physical addresses of
* all the Rx Blocks
@ -703,10 +745,16 @@ struct ring_info {
*/
struct rx_curr_get_info rx_curr_get_info;
/* interface MTU value */
unsigned mtu;
/* Buffer Address store. */
struct buffAdd **ba;
struct s2io_nic *nic;
};
/* per-Ring statistics */
unsigned long rx_packets;
unsigned long rx_bytes;
} ____cacheline_aligned;
/* Fifo specific structure */
struct fifo_info {
@ -813,26 +861,6 @@ struct msix_info_st {
u64 data;
};
/* Data structure to represent a LRO session */
struct lro {
struct sk_buff *parent;
struct sk_buff *last_frag;
u8 *l2h;
struct iphdr *iph;
struct tcphdr *tcph;
u32 tcp_next_seq;
__be32 tcp_ack;
int total_len;
int frags_len;
int sg_num;
int in_use;
__be16 window;
u16 vlan_tag;
u32 cur_tsval;
__be32 cur_tsecr;
u8 saw_ts;
} ____cacheline_aligned;
/* These flags represent the devices temporary state */
enum s2io_device_state_t
{
@ -872,8 +900,6 @@ struct s2io_nic {
/* Space to back up the PCI config space */
u32 config_space[256 / sizeof(u32)];
atomic_t rx_bufs_left[MAX_RX_RINGS];
#define PROMISC 1
#define ALL_MULTI 2
@ -950,8 +976,6 @@ struct s2io_nic {
#define XFRAME_II_DEVICE 2
u8 device_type;
#define MAX_LRO_SESSIONS 32
struct lro lro0_n[MAX_LRO_SESSIONS];
unsigned long clubbed_frms_cnt;
unsigned long sending_both;
u8 lro;
@ -1118,9 +1142,9 @@ static int do_s2io_add_mc(struct s2io_nic *sp, u8 *addr);
static int do_s2io_add_mac(struct s2io_nic *sp, u64 addr, int offset);
static int do_s2io_delete_unicast_mc(struct s2io_nic *sp, u64 addr);
static int
s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
struct RxD_t *rxdp, struct s2io_nic *sp);
static int s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer,
u8 **tcp, u32 *tcp_len, struct lro **lro, struct RxD_t *rxdp,
struct s2io_nic *sp);
static void clear_lro_session(struct lro *lro);
static void queue_rx_frame(struct sk_buff *skb, u16 vlan_tag);
static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro);

View File

@ -0,0 +1,12 @@
config SFC
tristate "Solarflare Solarstorm SFC4000 support"
depends on PCI && INET
select MII
select INET_LRO
select CRC32
help
This driver supports 10-gigabit Ethernet cards based on
the Solarflare Communications Solarstorm SFC4000 controller.
To compile this driver as a module, choose M here. The module
will be called sfc.

View File

@ -0,0 +1,5 @@
sfc-y += efx.o falcon.o tx.o rx.o falcon_xmac.o \
i2c-direct.o ethtool.o xfp_phy.o mdio_10g.o \
tenxpress.o boards.o sfe4001.o
obj-$(CONFIG_SFC) += sfc.o

View File

@ -0,0 +1,508 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2008 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#ifndef EFX_BITFIELD_H
#define EFX_BITFIELD_H
/*
* Efx bitfield access
*
* Efx NICs make extensive use of bitfields up to 128 bits
* wide. Since there is no native 128-bit datatype on most systems,
* and since 64-bit datatypes are inefficient on 32-bit systems and
* vice versa, we wrap accesses in a way that uses the most efficient
* datatype.
*
* The NICs are PCI devices and therefore little-endian. Since most
* of the quantities that we deal with are DMAed to/from host memory,
* we define our datatypes (efx_oword_t, efx_qword_t and
* efx_dword_t) to be little-endian.
*/
/* Lowest bit numbers and widths */
#define EFX_DUMMY_FIELD_LBN 0
#define EFX_DUMMY_FIELD_WIDTH 0
#define EFX_DWORD_0_LBN 0
#define EFX_DWORD_0_WIDTH 32
#define EFX_DWORD_1_LBN 32
#define EFX_DWORD_1_WIDTH 32
#define EFX_DWORD_2_LBN 64
#define EFX_DWORD_2_WIDTH 32
#define EFX_DWORD_3_LBN 96
#define EFX_DWORD_3_WIDTH 32
/* Specified attribute (e.g. LBN) of the specified field */
#define EFX_VAL(field, attribute) field ## _ ## attribute
/* Low bit number of the specified field */
#define EFX_LOW_BIT(field) EFX_VAL(field, LBN)
/* Bit width of the specified field */
#define EFX_WIDTH(field) EFX_VAL(field, WIDTH)
/* High bit number of the specified field */
#define EFX_HIGH_BIT(field) (EFX_LOW_BIT(field) + EFX_WIDTH(field) - 1)
/* Mask equal in width to the specified field.
*
* For example, a field with width 5 would have a mask of 0x1f.
*
* The maximum width mask that can be generated is 64 bits.
*/
#define EFX_MASK64(field) \
(EFX_WIDTH(field) == 64 ? ~((u64) 0) : \
(((((u64) 1) << EFX_WIDTH(field))) - 1))
/* Mask equal in width to the specified field.
*
* For example, a field with width 5 would have a mask of 0x1f.
*
* The maximum width mask that can be generated is 32 bits. Use
* EFX_MASK64 for higher width fields.
*/
#define EFX_MASK32(field) \
(EFX_WIDTH(field) == 32 ? ~((u32) 0) : \
(((((u32) 1) << EFX_WIDTH(field))) - 1))
/* A doubleword (i.e. 4 byte) datatype - little-endian in HW */
typedef union efx_dword {
__le32 u32[1];
} efx_dword_t;
/* A quadword (i.e. 8 byte) datatype - little-endian in HW */
typedef union efx_qword {
__le64 u64[1];
__le32 u32[2];
efx_dword_t dword[2];
} efx_qword_t;
/* An octword (eight-word, i.e. 16 byte) datatype - little-endian in HW */
typedef union efx_oword {
__le64 u64[2];
efx_qword_t qword[2];
__le32 u32[4];
efx_dword_t dword[4];
} efx_oword_t;
/* Format string and value expanders for printk */
#define EFX_DWORD_FMT "%08x"
#define EFX_QWORD_FMT "%08x:%08x"
#define EFX_OWORD_FMT "%08x:%08x:%08x:%08x"
#define EFX_DWORD_VAL(dword) \
((unsigned int) le32_to_cpu((dword).u32[0]))
#define EFX_QWORD_VAL(qword) \
((unsigned int) le32_to_cpu((qword).u32[1])), \
((unsigned int) le32_to_cpu((qword).u32[0]))
#define EFX_OWORD_VAL(oword) \
((unsigned int) le32_to_cpu((oword).u32[3])), \
((unsigned int) le32_to_cpu((oword).u32[2])), \
((unsigned int) le32_to_cpu((oword).u32[1])), \
((unsigned int) le32_to_cpu((oword).u32[0]))
/*
* Extract bit field portion [low,high) from the native-endian element
* which contains bits [min,max).
*
* For example, suppose "element" represents the high 32 bits of a
* 64-bit value, and we wish to extract the bits belonging to the bit
* field occupying bits 28-45 of this 64-bit value.
*
* Then EFX_EXTRACT ( element, 32, 63, 28, 45 ) would give
*
* ( element ) << 4
*
* The result will contain the relevant bits filled in in the range
* [0,high-low), with garbage in bits [high-low+1,...).
*/
#define EFX_EXTRACT_NATIVE(native_element, min, max, low, high) \
(((low > max) || (high < min)) ? 0 : \
((low > min) ? \
((native_element) >> (low - min)) : \
((native_element) << (min - low))))
/*
* Extract bit field portion [low,high) from the 64-bit little-endian
* element which contains bits [min,max)
*/
#define EFX_EXTRACT64(element, min, max, low, high) \
EFX_EXTRACT_NATIVE(le64_to_cpu(element), min, max, low, high)
/*
* Extract bit field portion [low,high) from the 32-bit little-endian
* element which contains bits [min,max)
*/
#define EFX_EXTRACT32(element, min, max, low, high) \
EFX_EXTRACT_NATIVE(le32_to_cpu(element), min, max, low, high)
#define EFX_EXTRACT_OWORD64(oword, low, high) \
(EFX_EXTRACT64((oword).u64[0], 0, 63, low, high) | \
EFX_EXTRACT64((oword).u64[1], 64, 127, low, high))
#define EFX_EXTRACT_QWORD64(qword, low, high) \
EFX_EXTRACT64((qword).u64[0], 0, 63, low, high)
#define EFX_EXTRACT_OWORD32(oword, low, high) \
(EFX_EXTRACT32((oword).u32[0], 0, 31, low, high) | \
EFX_EXTRACT32((oword).u32[1], 32, 63, low, high) | \
EFX_EXTRACT32((oword).u32[2], 64, 95, low, high) | \
EFX_EXTRACT32((oword).u32[3], 96, 127, low, high))
#define EFX_EXTRACT_QWORD32(qword, low, high) \
(EFX_EXTRACT32((qword).u32[0], 0, 31, low, high) | \
EFX_EXTRACT32((qword).u32[1], 32, 63, low, high))
#define EFX_EXTRACT_DWORD(dword, low, high) \
EFX_EXTRACT32((dword).u32[0], 0, 31, low, high)
#define EFX_OWORD_FIELD64(oword, field) \
(EFX_EXTRACT_OWORD64(oword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
& EFX_MASK64(field))
#define EFX_QWORD_FIELD64(qword, field) \
(EFX_EXTRACT_QWORD64(qword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
& EFX_MASK64(field))
#define EFX_OWORD_FIELD32(oword, field) \
(EFX_EXTRACT_OWORD32(oword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
& EFX_MASK32(field))
#define EFX_QWORD_FIELD32(qword, field) \
(EFX_EXTRACT_QWORD32(qword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
& EFX_MASK32(field))
#define EFX_DWORD_FIELD(dword, field) \
(EFX_EXTRACT_DWORD(dword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
& EFX_MASK32(field))
#define EFX_OWORD_IS_ZERO64(oword) \
(((oword).u64[0] | (oword).u64[1]) == (__force __le64) 0)
#define EFX_QWORD_IS_ZERO64(qword) \
(((qword).u64[0]) == (__force __le64) 0)
#define EFX_OWORD_IS_ZERO32(oword) \
(((oword).u32[0] | (oword).u32[1] | (oword).u32[2] | (oword).u32[3]) \
== (__force __le32) 0)
#define EFX_QWORD_IS_ZERO32(qword) \
(((qword).u32[0] | (qword).u32[1]) == (__force __le32) 0)
#define EFX_DWORD_IS_ZERO(dword) \
(((dword).u32[0]) == (__force __le32) 0)
#define EFX_OWORD_IS_ALL_ONES64(oword) \
(((oword).u64[0] & (oword).u64[1]) == ~((__force __le64) 0))
#define EFX_QWORD_IS_ALL_ONES64(qword) \
((qword).u64[0] == ~((__force __le64) 0))
#define EFX_OWORD_IS_ALL_ONES32(oword) \
(((oword).u32[0] & (oword).u32[1] & (oword).u32[2] & (oword).u32[3]) \
== ~((__force __le32) 0))
#define EFX_QWORD_IS_ALL_ONES32(qword) \
(((qword).u32[0] & (qword).u32[1]) == ~((__force __le32) 0))
#define EFX_DWORD_IS_ALL_ONES(dword) \
((dword).u32[0] == ~((__force __le32) 0))
#if BITS_PER_LONG == 64
#define EFX_OWORD_FIELD EFX_OWORD_FIELD64
#define EFX_QWORD_FIELD EFX_QWORD_FIELD64
#define EFX_OWORD_IS_ZERO EFX_OWORD_IS_ZERO64
#define EFX_QWORD_IS_ZERO EFX_QWORD_IS_ZERO64
#define EFX_OWORD_IS_ALL_ONES EFX_OWORD_IS_ALL_ONES64
#define EFX_QWORD_IS_ALL_ONES EFX_QWORD_IS_ALL_ONES64
#else
#define EFX_OWORD_FIELD EFX_OWORD_FIELD32
#define EFX_QWORD_FIELD EFX_QWORD_FIELD32
#define EFX_OWORD_IS_ZERO EFX_OWORD_IS_ZERO32
#define EFX_QWORD_IS_ZERO EFX_QWORD_IS_ZERO32
#define EFX_OWORD_IS_ALL_ONES EFX_OWORD_IS_ALL_ONES32
#define EFX_QWORD_IS_ALL_ONES EFX_QWORD_IS_ALL_ONES32
#endif
/*
* Construct bit field portion
*
* Creates the portion of the bit field [low,high) that lies within
* the range [min,max).
*/
#define EFX_INSERT_NATIVE64(min, max, low, high, value) \
(((low > max) || (high < min)) ? 0 : \
((low > min) ? \
(((u64) (value)) << (low - min)) : \
(((u64) (value)) >> (min - low))))
#define EFX_INSERT_NATIVE32(min, max, low, high, value) \
(((low > max) || (high < min)) ? 0 : \
((low > min) ? \
(((u32) (value)) << (low - min)) : \
(((u32) (value)) >> (min - low))))
#define EFX_INSERT_NATIVE(min, max, low, high, value) \
((((max - min) >= 32) || ((high - low) >= 32)) ? \
EFX_INSERT_NATIVE64(min, max, low, high, value) : \
EFX_INSERT_NATIVE32(min, max, low, high, value))
/*
* Construct bit field portion
*
* Creates the portion of the named bit field that lies within the
* range [min,max).
*/
#define EFX_INSERT_FIELD_NATIVE(min, max, field, value) \
EFX_INSERT_NATIVE(min, max, EFX_LOW_BIT(field), \
EFX_HIGH_BIT(field), value)
/*
* Construct bit field
*
* Creates the portion of the named bit fields that lie within the
* range [min,max).
*/
#define EFX_INSERT_FIELDS_NATIVE(min, max, \
field1, value1, \
field2, value2, \
field3, value3, \
field4, value4, \
field5, value5, \
field6, value6, \
field7, value7, \
field8, value8, \
field9, value9, \
field10, value10) \
(EFX_INSERT_FIELD_NATIVE((min), (max), field1, (value1)) | \
EFX_INSERT_FIELD_NATIVE((min), (max), field2, (value2)) | \
EFX_INSERT_FIELD_NATIVE((min), (max), field3, (value3)) | \
EFX_INSERT_FIELD_NATIVE((min), (max), field4, (value4)) | \
EFX_INSERT_FIELD_NATIVE((min), (max), field5, (value5)) | \
EFX_INSERT_FIELD_NATIVE((min), (max), field6, (value6)) | \
EFX_INSERT_FIELD_NATIVE((min), (max), field7, (value7)) | \
EFX_INSERT_FIELD_NATIVE((min), (max), field8, (value8)) | \
EFX_INSERT_FIELD_NATIVE((min), (max), field9, (value9)) | \
EFX_INSERT_FIELD_NATIVE((min), (max), field10, (value10)))
#define EFX_INSERT_FIELDS64(...) \
cpu_to_le64(EFX_INSERT_FIELDS_NATIVE(__VA_ARGS__))
#define EFX_INSERT_FIELDS32(...) \
cpu_to_le32(EFX_INSERT_FIELDS_NATIVE(__VA_ARGS__))
#define EFX_POPULATE_OWORD64(oword, ...) do { \
(oword).u64[0] = EFX_INSERT_FIELDS64(0, 63, __VA_ARGS__); \
(oword).u64[1] = EFX_INSERT_FIELDS64(64, 127, __VA_ARGS__); \
} while (0)
#define EFX_POPULATE_QWORD64(qword, ...) do { \
(qword).u64[0] = EFX_INSERT_FIELDS64(0, 63, __VA_ARGS__); \
} while (0)
#define EFX_POPULATE_OWORD32(oword, ...) do { \
(oword).u32[0] = EFX_INSERT_FIELDS32(0, 31, __VA_ARGS__); \
(oword).u32[1] = EFX_INSERT_FIELDS32(32, 63, __VA_ARGS__); \
(oword).u32[2] = EFX_INSERT_FIELDS32(64, 95, __VA_ARGS__); \
(oword).u32[3] = EFX_INSERT_FIELDS32(96, 127, __VA_ARGS__); \
} while (0)
#define EFX_POPULATE_QWORD32(qword, ...) do { \
(qword).u32[0] = EFX_INSERT_FIELDS32(0, 31, __VA_ARGS__); \
(qword).u32[1] = EFX_INSERT_FIELDS32(32, 63, __VA_ARGS__); \
} while (0)
#define EFX_POPULATE_DWORD(dword, ...) do { \
(dword).u32[0] = EFX_INSERT_FIELDS32(0, 31, __VA_ARGS__); \
} while (0)
#if BITS_PER_LONG == 64
#define EFX_POPULATE_OWORD EFX_POPULATE_OWORD64
#define EFX_POPULATE_QWORD EFX_POPULATE_QWORD64
#else
#define EFX_POPULATE_OWORD EFX_POPULATE_OWORD32
#define EFX_POPULATE_QWORD EFX_POPULATE_QWORD32
#endif
/* Populate an octword field with various numbers of arguments */
#define EFX_POPULATE_OWORD_10 EFX_POPULATE_OWORD
#define EFX_POPULATE_OWORD_9(oword, ...) \
EFX_POPULATE_OWORD_10(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_OWORD_8(oword, ...) \
EFX_POPULATE_OWORD_9(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_OWORD_7(oword, ...) \
EFX_POPULATE_OWORD_8(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_OWORD_6(oword, ...) \
EFX_POPULATE_OWORD_7(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_OWORD_5(oword, ...) \
EFX_POPULATE_OWORD_6(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_OWORD_4(oword, ...) \
EFX_POPULATE_OWORD_5(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_OWORD_3(oword, ...) \
EFX_POPULATE_OWORD_4(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_OWORD_2(oword, ...) \
EFX_POPULATE_OWORD_3(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_OWORD_1(oword, ...) \
EFX_POPULATE_OWORD_2(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_ZERO_OWORD(oword) \
EFX_POPULATE_OWORD_1(oword, EFX_DUMMY_FIELD, 0)
#define EFX_SET_OWORD(oword) \
EFX_POPULATE_OWORD_4(oword, \
EFX_DWORD_0, 0xffffffff, \
EFX_DWORD_1, 0xffffffff, \
EFX_DWORD_2, 0xffffffff, \
EFX_DWORD_3, 0xffffffff)
/* Populate a quadword field with various numbers of arguments */
#define EFX_POPULATE_QWORD_10 EFX_POPULATE_QWORD
#define EFX_POPULATE_QWORD_9(qword, ...) \
EFX_POPULATE_QWORD_10(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_QWORD_8(qword, ...) \
EFX_POPULATE_QWORD_9(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_QWORD_7(qword, ...) \
EFX_POPULATE_QWORD_8(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_QWORD_6(qword, ...) \
EFX_POPULATE_QWORD_7(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_QWORD_5(qword, ...) \
EFX_POPULATE_QWORD_6(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_QWORD_4(qword, ...) \
EFX_POPULATE_QWORD_5(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_QWORD_3(qword, ...) \
EFX_POPULATE_QWORD_4(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_QWORD_2(qword, ...) \
EFX_POPULATE_QWORD_3(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_QWORD_1(qword, ...) \
EFX_POPULATE_QWORD_2(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_ZERO_QWORD(qword) \
EFX_POPULATE_QWORD_1(qword, EFX_DUMMY_FIELD, 0)
#define EFX_SET_QWORD(qword) \
EFX_POPULATE_QWORD_2(qword, \
EFX_DWORD_0, 0xffffffff, \
EFX_DWORD_1, 0xffffffff)
/* Populate a dword field with various numbers of arguments */
#define EFX_POPULATE_DWORD_10 EFX_POPULATE_DWORD
#define EFX_POPULATE_DWORD_9(dword, ...) \
EFX_POPULATE_DWORD_10(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_DWORD_8(dword, ...) \
EFX_POPULATE_DWORD_9(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_DWORD_7(dword, ...) \
EFX_POPULATE_DWORD_8(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_DWORD_6(dword, ...) \
EFX_POPULATE_DWORD_7(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_DWORD_5(dword, ...) \
EFX_POPULATE_DWORD_6(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_DWORD_4(dword, ...) \
EFX_POPULATE_DWORD_5(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_DWORD_3(dword, ...) \
EFX_POPULATE_DWORD_4(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_DWORD_2(dword, ...) \
EFX_POPULATE_DWORD_3(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_POPULATE_DWORD_1(dword, ...) \
EFX_POPULATE_DWORD_2(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
#define EFX_ZERO_DWORD(dword) \
EFX_POPULATE_DWORD_1(dword, EFX_DUMMY_FIELD, 0)
#define EFX_SET_DWORD(dword) \
EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 0xffffffff)
/*
* Modify a named field within an already-populated structure. Used
* for read-modify-write operations.
*
*/
#define EFX_INVERT_OWORD(oword) do { \
(oword).u64[0] = ~((oword).u64[0]); \
(oword).u64[1] = ~((oword).u64[1]); \
} while (0)
#define EFX_INSERT_FIELD64(...) \
cpu_to_le64(EFX_INSERT_FIELD_NATIVE(__VA_ARGS__))
#define EFX_INSERT_FIELD32(...) \
cpu_to_le32(EFX_INSERT_FIELD_NATIVE(__VA_ARGS__))
#define EFX_INPLACE_MASK64(min, max, field) \
EFX_INSERT_FIELD64(min, max, field, EFX_MASK64(field))
#define EFX_INPLACE_MASK32(min, max, field) \
EFX_INSERT_FIELD32(min, max, field, EFX_MASK32(field))
#define EFX_SET_OWORD_FIELD64(oword, field, value) do { \
(oword).u64[0] = (((oword).u64[0] \
& ~EFX_INPLACE_MASK64(0, 63, field)) \
| EFX_INSERT_FIELD64(0, 63, field, value)); \
(oword).u64[1] = (((oword).u64[1] \
& ~EFX_INPLACE_MASK64(64, 127, field)) \
| EFX_INSERT_FIELD64(64, 127, field, value)); \
} while (0)
#define EFX_SET_QWORD_FIELD64(qword, field, value) do { \
(qword).u64[0] = (((qword).u64[0] \
& ~EFX_INPLACE_MASK64(0, 63, field)) \
| EFX_INSERT_FIELD64(0, 63, field, value)); \
} while (0)
#define EFX_SET_OWORD_FIELD32(oword, field, value) do { \
(oword).u32[0] = (((oword).u32[0] \
& ~EFX_INPLACE_MASK32(0, 31, field)) \
| EFX_INSERT_FIELD32(0, 31, field, value)); \
(oword).u32[1] = (((oword).u32[1] \
& ~EFX_INPLACE_MASK32(32, 63, field)) \
| EFX_INSERT_FIELD32(32, 63, field, value)); \
(oword).u32[2] = (((oword).u32[2] \
& ~EFX_INPLACE_MASK32(64, 95, field)) \
| EFX_INSERT_FIELD32(64, 95, field, value)); \
(oword).u32[3] = (((oword).u32[3] \
& ~EFX_INPLACE_MASK32(96, 127, field)) \
| EFX_INSERT_FIELD32(96, 127, field, value)); \
} while (0)
#define EFX_SET_QWORD_FIELD32(qword, field, value) do { \
(qword).u32[0] = (((qword).u32[0] \
& ~EFX_INPLACE_MASK32(0, 31, field)) \
| EFX_INSERT_FIELD32(0, 31, field, value)); \
(qword).u32[1] = (((qword).u32[1] \
& ~EFX_INPLACE_MASK32(32, 63, field)) \
| EFX_INSERT_FIELD32(32, 63, field, value)); \
} while (0)
#define EFX_SET_DWORD_FIELD(dword, field, value) do { \
(dword).u32[0] = (((dword).u32[0] \
& ~EFX_INPLACE_MASK32(0, 31, field)) \
| EFX_INSERT_FIELD32(0, 31, field, value)); \
} while (0)
#if BITS_PER_LONG == 64
#define EFX_SET_OWORD_FIELD EFX_SET_OWORD_FIELD64
#define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD64
#else
#define EFX_SET_OWORD_FIELD EFX_SET_OWORD_FIELD32
#define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD32
#endif
#define EFX_SET_OWORD_FIELD_VER(efx, oword, field, value) do { \
if (FALCON_REV(efx) >= FALCON_REV_B0) { \
EFX_SET_OWORD_FIELD((oword), field##_B0, (value)); \
} else { \
EFX_SET_OWORD_FIELD((oword), field##_A1, (value)); \
} \
} while (0)
#define EFX_QWORD_FIELD_VER(efx, qword, field) \
(FALCON_REV(efx) >= FALCON_REV_B0 ? \
EFX_QWORD_FIELD((qword), field##_B0) : \
EFX_QWORD_FIELD((qword), field##_A1))
/* Used to avoid compiler warnings about shift range exceeding width
* of the data types when dma_addr_t is only 32 bits wide.
*/
#define DMA_ADDR_T_WIDTH (8 * sizeof(dma_addr_t))
#define EFX_DMA_TYPE_WIDTH(width) \
(((width) < DMA_ADDR_T_WIDTH) ? (width) : DMA_ADDR_T_WIDTH)
#define EFX_DMA_MAX_MASK ((DMA_ADDR_T_WIDTH == 64) ? \
~((u64) 0) : ~((u32) 0))
#define EFX_DMA_MASK(mask) ((mask) & EFX_DMA_MAX_MASK)
#endif /* EFX_BITFIELD_H */

View File

@ -0,0 +1,167 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2007 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#include "net_driver.h"
#include "phy.h"
#include "boards.h"
#include "efx.h"
/* Macros for unpacking the board revision */
/* The revision info is in host byte order. */
#define BOARD_TYPE(_rev) (_rev >> 8)
#define BOARD_MAJOR(_rev) ((_rev >> 4) & 0xf)
#define BOARD_MINOR(_rev) (_rev & 0xf)
/* Blink support. If the PHY has no auto-blink mode so we hang it off a timer */
#define BLINK_INTERVAL (HZ/2)
static void blink_led_timer(unsigned long context)
{
struct efx_nic *efx = (struct efx_nic *)context;
struct efx_blinker *bl = &efx->board_info.blinker;
efx->board_info.set_fault_led(efx, bl->state);
bl->state = !bl->state;
if (bl->resubmit) {
bl->timer.expires = jiffies + BLINK_INTERVAL;
add_timer(&bl->timer);
}
}
static void board_blink(struct efx_nic *efx, int blink)
{
struct efx_blinker *blinker = &efx->board_info.blinker;
/* The rtnl mutex serialises all ethtool ioctls, so
* nothing special needs doing here. */
if (blink) {
blinker->resubmit = 1;
blinker->state = 0;
setup_timer(&blinker->timer, blink_led_timer,
(unsigned long)efx);
blinker->timer.expires = jiffies + BLINK_INTERVAL;
add_timer(&blinker->timer);
} else {
blinker->resubmit = 0;
if (blinker->timer.function)
del_timer_sync(&blinker->timer);
efx->board_info.set_fault_led(efx, 0);
}
}
/*****************************************************************************
* Support for the SFE4002
*
*/
/****************************************************************************/
/* LED allocations. Note that on rev A0 boards the schematic and the reality
* differ: red and green are swapped. Below is the fixed (A1) layout (there
* are only 3 A0 boards in existence, so no real reason to make this
* conditional).
*/
#define SFE4002_FAULT_LED (2) /* Red */
#define SFE4002_RX_LED (0) /* Green */
#define SFE4002_TX_LED (1) /* Amber */
static int sfe4002_init_leds(struct efx_nic *efx)
{
/* Set the TX and RX LEDs to reflect status and activity, and the
* fault LED off */
xfp_set_led(efx, SFE4002_TX_LED,
QUAKE_LED_TXLINK | QUAKE_LED_LINK_ACTSTAT);
xfp_set_led(efx, SFE4002_RX_LED,
QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT);
xfp_set_led(efx, SFE4002_FAULT_LED, QUAKE_LED_OFF);
efx->board_info.blinker.led_num = SFE4002_FAULT_LED;
return 0;
}
static void sfe4002_fault_led(struct efx_nic *efx, int state)
{
xfp_set_led(efx, SFE4002_FAULT_LED, state ? QUAKE_LED_ON :
QUAKE_LED_OFF);
}
static int sfe4002_init(struct efx_nic *efx)
{
efx->board_info.init_leds = sfe4002_init_leds;
efx->board_info.set_fault_led = sfe4002_fault_led;
efx->board_info.blink = board_blink;
return 0;
}
/* This will get expanded as board-specific details get moved out of the
* PHY drivers. */
struct efx_board_data {
const char *ref_model;
const char *gen_type;
int (*init) (struct efx_nic *nic);
};
static int dummy_init(struct efx_nic *nic)
{
return 0;
}
static struct efx_board_data board_data[] = {
[EFX_BOARD_INVALID] =
{NULL, NULL, dummy_init},
[EFX_BOARD_SFE4001] =
{"SFE4001", "10GBASE-T adapter", sfe4001_poweron},
[EFX_BOARD_SFE4002] =
{"SFE4002", "XFP adapter", sfe4002_init},
};
int efx_set_board_info(struct efx_nic *efx, u16 revision_info)
{
int rc = 0;
struct efx_board_data *data;
if (BOARD_TYPE(revision_info) >= EFX_BOARD_MAX) {
EFX_ERR(efx, "squashing unknown board type %d\n",
BOARD_TYPE(revision_info));
revision_info = 0;
}
if (BOARD_TYPE(revision_info) == 0) {
efx->board_info.major = 0;
efx->board_info.minor = 0;
/* For early boards that don't have revision info. there is
* only 1 board for each PHY type, so we can work it out, with
* the exception of the PHY-less boards. */
switch (efx->phy_type) {
case PHY_TYPE_10XPRESS:
efx->board_info.type = EFX_BOARD_SFE4001;
break;
case PHY_TYPE_XFP:
efx->board_info.type = EFX_BOARD_SFE4002;
break;
default:
efx->board_info.type = 0;
break;
}
} else {
efx->board_info.type = BOARD_TYPE(revision_info);
efx->board_info.major = BOARD_MAJOR(revision_info);
efx->board_info.minor = BOARD_MINOR(revision_info);
}
data = &board_data[efx->board_info.type];
/* Report the board model number or generic type for recognisable
* boards. */
if (efx->board_info.type != 0)
EFX_INFO(efx, "board is %s rev %c%d\n",
(efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC)
? data->ref_model : data->gen_type,
'A' + efx->board_info.major, efx->board_info.minor);
efx->board_info.init = data->init;
return rc;
}

View File

@ -0,0 +1,26 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2007 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#ifndef EFX_BOARDS_H
#define EFX_BOARDS_H
/* Board IDs (must fit in 8 bits) */
enum efx_board_type {
EFX_BOARD_INVALID = 0,
EFX_BOARD_SFE4001 = 1, /* SFE4001 (10GBASE-T) */
EFX_BOARD_SFE4002 = 2,
/* Insert new types before here */
EFX_BOARD_MAX
};
extern int efx_set_board_info(struct efx_nic *efx, u16 revision_info);
extern int sfe4001_poweron(struct efx_nic *efx);
extern void sfe4001_poweroff(struct efx_nic *efx);
#endif

2208
drivers/net/sfc/efx.c 100644

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,67 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2008 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#ifndef EFX_EFX_H
#define EFX_EFX_H
#include "net_driver.h"
/* PCI IDs */
#define EFX_VENDID_SFC 0x1924
#define FALCON_A_P_DEVID 0x0703
#define FALCON_A_S_DEVID 0x6703
#define FALCON_B_P_DEVID 0x0710
/* TX */
extern int efx_xmit(struct efx_nic *efx,
struct efx_tx_queue *tx_queue, struct sk_buff *skb);
extern void efx_stop_queue(struct efx_nic *efx);
extern void efx_wake_queue(struct efx_nic *efx);
/* RX */
extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
extern void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
unsigned int len, int checksummed, int discard);
extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay);
/* Channels */
extern void efx_process_channel_now(struct efx_channel *channel);
extern int efx_flush_queues(struct efx_nic *efx);
/* Ports */
extern void efx_reconfigure_port(struct efx_nic *efx);
/* Global */
extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type);
extern void efx_suspend(struct efx_nic *efx);
extern void efx_resume(struct efx_nic *efx);
extern void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs,
int rx_usecs);
extern int efx_request_power(struct efx_nic *efx, int mw, const char *name);
extern void efx_hex_dump(const u8 *, unsigned int, const char *);
/* Dummy PHY ops for PHY drivers */
extern int efx_port_dummy_op_int(struct efx_nic *efx);
extern void efx_port_dummy_op_void(struct efx_nic *efx);
extern void efx_port_dummy_op_blink(struct efx_nic *efx, int blink);
extern unsigned int efx_monitor_interval;
static inline void efx_schedule_channel(struct efx_channel *channel)
{
EFX_TRACE(channel->efx, "channel %d scheduling NAPI poll on CPU%d\n",
channel->channel, raw_smp_processor_id());
channel->work_pending = 1;
netif_rx_schedule(channel->napi_dev, &channel->napi_str);
}
#endif /* EFX_EFX_H */

View File

@ -0,0 +1,50 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2007 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#ifndef EFX_ENUM_H
#define EFX_ENUM_H
/*****************************************************************************/
/**
* enum reset_type - reset types
*
* %RESET_TYPE_INVSIBLE, %RESET_TYPE_ALL, %RESET_TYPE_WORLD and
* %RESET_TYPE_DISABLE specify the method/scope of the reset. The
* other valuesspecify reasons, which efx_schedule_reset() will choose
* a method for.
*
* @RESET_TYPE_INVISIBLE: don't reset the PHYs or interrupts
* @RESET_TYPE_ALL: reset everything but PCI core blocks
* @RESET_TYPE_WORLD: reset everything, save & restore PCI config
* @RESET_TYPE_DISABLE: disable NIC
* @RESET_TYPE_MONITOR: reset due to hardware monitor
* @RESET_TYPE_INT_ERROR: reset due to internal error
* @RESET_TYPE_RX_RECOVERY: reset to recover from RX datapath errors
* @RESET_TYPE_RX_DESC_FETCH: pcie error during rx descriptor fetch
* @RESET_TYPE_TX_DESC_FETCH: pcie error during tx descriptor fetch
* @RESET_TYPE_TX_SKIP: hardware completed empty tx descriptors
*/
enum reset_type {
RESET_TYPE_NONE = -1,
RESET_TYPE_INVISIBLE = 0,
RESET_TYPE_ALL = 1,
RESET_TYPE_WORLD = 2,
RESET_TYPE_DISABLE = 3,
RESET_TYPE_MAX_METHOD,
RESET_TYPE_MONITOR,
RESET_TYPE_INT_ERROR,
RESET_TYPE_RX_RECOVERY,
RESET_TYPE_RX_DESC_FETCH,
RESET_TYPE_TX_DESC_FETCH,
RESET_TYPE_TX_SKIP,
RESET_TYPE_MAX,
};
#endif /* EFX_ENUM_H */

View File

@ -0,0 +1,460 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2008 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include <linux/rtnetlink.h>
#include "net_driver.h"
#include "efx.h"
#include "ethtool.h"
#include "falcon.h"
#include "gmii.h"
#include "mac.h"
static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable);
struct ethtool_string {
char name[ETH_GSTRING_LEN];
};
struct efx_ethtool_stat {
const char *name;
enum {
EFX_ETHTOOL_STAT_SOURCE_mac_stats,
EFX_ETHTOOL_STAT_SOURCE_nic,
EFX_ETHTOOL_STAT_SOURCE_channel
} source;
unsigned offset;
u64(*get_stat) (void *field); /* Reader function */
};
/* Initialiser for a struct #efx_ethtool_stat with type-checking */
#define EFX_ETHTOOL_STAT(stat_name, source_name, field, field_type, \
get_stat_function) { \
.name = #stat_name, \
.source = EFX_ETHTOOL_STAT_SOURCE_##source_name, \
.offset = ((((field_type *) 0) == \
&((struct efx_##source_name *)0)->field) ? \
offsetof(struct efx_##source_name, field) : \
offsetof(struct efx_##source_name, field)), \
.get_stat = get_stat_function, \
}
static u64 efx_get_uint_stat(void *field)
{
return *(unsigned int *)field;
}
static u64 efx_get_ulong_stat(void *field)
{
return *(unsigned long *)field;
}
static u64 efx_get_u64_stat(void *field)
{
return *(u64 *) field;
}
static u64 efx_get_atomic_stat(void *field)
{
return atomic_read((atomic_t *) field);
}
#define EFX_ETHTOOL_ULONG_MAC_STAT(field) \
EFX_ETHTOOL_STAT(field, mac_stats, field, \
unsigned long, efx_get_ulong_stat)
#define EFX_ETHTOOL_U64_MAC_STAT(field) \
EFX_ETHTOOL_STAT(field, mac_stats, field, \
u64, efx_get_u64_stat)
#define EFX_ETHTOOL_UINT_NIC_STAT(name) \
EFX_ETHTOOL_STAT(name, nic, n_##name, \
unsigned int, efx_get_uint_stat)
#define EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(field) \
EFX_ETHTOOL_STAT(field, nic, field, \
atomic_t, efx_get_atomic_stat)
#define EFX_ETHTOOL_UINT_CHANNEL_STAT(field) \
EFX_ETHTOOL_STAT(field, channel, n_##field, \
unsigned int, efx_get_uint_stat)
static struct efx_ethtool_stat efx_ethtool_stats[] = {
EFX_ETHTOOL_U64_MAC_STAT(tx_bytes),
EFX_ETHTOOL_U64_MAC_STAT(tx_good_bytes),
EFX_ETHTOOL_U64_MAC_STAT(tx_bad_bytes),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_packets),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_bad),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_pause),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_control),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_unicast),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_multicast),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_broadcast),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_lt64),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_64),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_65_to_127),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_128_to_255),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_256_to_511),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_512_to_1023),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_1024_to_15xx),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_15xx_to_jumbo),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_gtjumbo),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_collision),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_single_collision),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_multiple_collision),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_excessive_collision),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_deferred),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_late_collision),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_excessive_deferred),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_non_tcpudp),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_mac_src_error),
EFX_ETHTOOL_ULONG_MAC_STAT(tx_ip_src_error),
EFX_ETHTOOL_U64_MAC_STAT(rx_bytes),
EFX_ETHTOOL_U64_MAC_STAT(rx_good_bytes),
EFX_ETHTOOL_U64_MAC_STAT(rx_bad_bytes),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_packets),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_good),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_pause),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_control),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_unicast),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_multicast),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_broadcast),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_lt64),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_64),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_65_to_127),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_128_to_255),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_256_to_511),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_512_to_1023),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_1024_to_15xx),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_15xx_to_jumbo),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_gtjumbo),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_lt64),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_64_to_15xx),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_15xx_to_jumbo),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_gtjumbo),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_overflow),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_missed),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_false_carrier),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_symbol_error),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_align_error),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_length_error),
EFX_ETHTOOL_ULONG_MAC_STAT(rx_internal_error),
EFX_ETHTOOL_UINT_NIC_STAT(rx_nodesc_drop_cnt),
EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(rx_reset),
EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tobe_disc),
EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_ip_hdr_chksum_err),
EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tcp_udp_chksum_err),
EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_frm_trunc),
};
/* Number of ethtool statistics */
#define EFX_ETHTOOL_NUM_STATS ARRAY_SIZE(efx_ethtool_stats)
/**************************************************************************
*
* Ethtool operations
*
**************************************************************************
*/
/* Identify device by flashing LEDs */
static int efx_ethtool_phys_id(struct net_device *net_dev, u32 seconds)
{
struct efx_nic *efx = net_dev->priv;
efx->board_info.blink(efx, 1);
schedule_timeout_interruptible(seconds * HZ);
efx->board_info.blink(efx, 0);
return 0;
}
/* This must be called with rtnl_lock held. */
int efx_ethtool_get_settings(struct net_device *net_dev,
struct ethtool_cmd *ecmd)
{
struct efx_nic *efx = net_dev->priv;
int rc;
mutex_lock(&efx->mac_lock);
rc = falcon_xmac_get_settings(efx, ecmd);
mutex_unlock(&efx->mac_lock);
return rc;
}
/* This must be called with rtnl_lock held. */
int efx_ethtool_set_settings(struct net_device *net_dev,
struct ethtool_cmd *ecmd)
{
struct efx_nic *efx = net_dev->priv;
int rc;
mutex_lock(&efx->mac_lock);
rc = falcon_xmac_set_settings(efx, ecmd);
mutex_unlock(&efx->mac_lock);
if (!rc)
efx_reconfigure_port(efx);
return rc;
}
static void efx_ethtool_get_drvinfo(struct net_device *net_dev,
struct ethtool_drvinfo *info)
{
struct efx_nic *efx = net_dev->priv;
strlcpy(info->driver, EFX_DRIVER_NAME, sizeof(info->driver));
strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version));
strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info));
}
static int efx_ethtool_get_stats_count(struct net_device *net_dev)
{
return EFX_ETHTOOL_NUM_STATS;
}
static void efx_ethtool_get_strings(struct net_device *net_dev,
u32 string_set, u8 *strings)
{
struct ethtool_string *ethtool_strings =
(struct ethtool_string *)strings;
int i;
if (string_set == ETH_SS_STATS)
for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++)
strncpy(ethtool_strings[i].name,
efx_ethtool_stats[i].name,
sizeof(ethtool_strings[i].name));
}
static void efx_ethtool_get_stats(struct net_device *net_dev,
struct ethtool_stats *stats,
u64 *data)
{
struct efx_nic *efx = net_dev->priv;
struct efx_mac_stats *mac_stats = &efx->mac_stats;
struct efx_ethtool_stat *stat;
struct efx_channel *channel;
int i;
EFX_BUG_ON_PARANOID(stats->n_stats != EFX_ETHTOOL_NUM_STATS);
/* Update MAC and NIC statistics */
net_dev->get_stats(net_dev);
/* Fill detailed statistics buffer */
for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) {
stat = &efx_ethtool_stats[i];
switch (stat->source) {
case EFX_ETHTOOL_STAT_SOURCE_mac_stats:
data[i] = stat->get_stat((void *)mac_stats +
stat->offset);
break;
case EFX_ETHTOOL_STAT_SOURCE_nic:
data[i] = stat->get_stat((void *)efx + stat->offset);
break;
case EFX_ETHTOOL_STAT_SOURCE_channel:
data[i] = 0;
efx_for_each_channel(channel, efx)
data[i] += stat->get_stat((void *)channel +
stat->offset);
break;
}
}
}
static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable)
{
struct efx_nic *efx = net_dev->priv;
int rc;
rc = ethtool_op_set_tx_csum(net_dev, enable);
if (rc)
return rc;
efx_flush_queues(efx);
return 0;
}
static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable)
{
struct efx_nic *efx = net_dev->priv;
/* No way to stop the hardware doing the checks; we just
* ignore the result.
*/
efx->rx_checksum_enabled = (enable ? 1 : 0);
return 0;
}
static u32 efx_ethtool_get_rx_csum(struct net_device *net_dev)
{
struct efx_nic *efx = net_dev->priv;
return efx->rx_checksum_enabled;
}
/* Restart autonegotiation */
static int efx_ethtool_nway_reset(struct net_device *net_dev)
{
struct efx_nic *efx = net_dev->priv;
return mii_nway_restart(&efx->mii);
}
static u32 efx_ethtool_get_link(struct net_device *net_dev)
{
struct efx_nic *efx = net_dev->priv;
return efx->link_up;
}
static int efx_ethtool_get_coalesce(struct net_device *net_dev,
struct ethtool_coalesce *coalesce)
{
struct efx_nic *efx = net_dev->priv;
struct efx_tx_queue *tx_queue;
struct efx_rx_queue *rx_queue;
struct efx_channel *channel;
memset(coalesce, 0, sizeof(*coalesce));
/* Find lowest IRQ moderation across all used TX queues */
coalesce->tx_coalesce_usecs_irq = ~((u32) 0);
efx_for_each_tx_queue(tx_queue, efx) {
channel = tx_queue->channel;
if (channel->irq_moderation < coalesce->tx_coalesce_usecs_irq) {
if (channel->used_flags != EFX_USED_BY_RX_TX)
coalesce->tx_coalesce_usecs_irq =
channel->irq_moderation;
else
coalesce->tx_coalesce_usecs_irq = 0;
}
}
/* Find lowest IRQ moderation across all used RX queues */
coalesce->rx_coalesce_usecs_irq = ~((u32) 0);
efx_for_each_rx_queue(rx_queue, efx) {
channel = rx_queue->channel;
if (channel->irq_moderation < coalesce->rx_coalesce_usecs_irq)
coalesce->rx_coalesce_usecs_irq =
channel->irq_moderation;
}
return 0;
}
/* Set coalescing parameters
* The difficulties occur for shared channels
*/
static int efx_ethtool_set_coalesce(struct net_device *net_dev,
struct ethtool_coalesce *coalesce)
{
struct efx_nic *efx = net_dev->priv;
struct efx_channel *channel;
struct efx_tx_queue *tx_queue;
unsigned tx_usecs, rx_usecs;
if (coalesce->use_adaptive_rx_coalesce ||
coalesce->use_adaptive_tx_coalesce)
return -EOPNOTSUPP;
if (coalesce->rx_coalesce_usecs || coalesce->tx_coalesce_usecs) {
EFX_ERR(efx, "invalid coalescing setting. "
"Only rx/tx_coalesce_usecs_irq are supported\n");
return -EOPNOTSUPP;
}
rx_usecs = coalesce->rx_coalesce_usecs_irq;
tx_usecs = coalesce->tx_coalesce_usecs_irq;
/* If the channel is shared only allow RX parameters to be set */
efx_for_each_tx_queue(tx_queue, efx) {
if ((tx_queue->channel->used_flags == EFX_USED_BY_RX_TX) &&
tx_usecs) {
EFX_ERR(efx, "Channel is shared. "
"Only RX coalescing may be set\n");
return -EOPNOTSUPP;
}
}
efx_init_irq_moderation(efx, tx_usecs, rx_usecs);
/* Reset channel to pick up new moderation value. Note that
* this may change the value of the irq_moderation field
* (e.g. to allow for hardware timer granularity).
*/
efx_for_each_channel(channel, efx)
falcon_set_int_moderation(channel);
return 0;
}
static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
struct ethtool_pauseparam *pause)
{
struct efx_nic *efx = net_dev->priv;
enum efx_fc_type flow_control = efx->flow_control;
int rc;
flow_control &= ~(EFX_FC_RX | EFX_FC_TX | EFX_FC_AUTO);
flow_control |= pause->rx_pause ? EFX_FC_RX : 0;
flow_control |= pause->tx_pause ? EFX_FC_TX : 0;
flow_control |= pause->autoneg ? EFX_FC_AUTO : 0;
/* Try to push the pause parameters */
mutex_lock(&efx->mac_lock);
rc = falcon_xmac_set_pause(efx, flow_control);
mutex_unlock(&efx->mac_lock);
if (!rc)
efx_reconfigure_port(efx);
return rc;
}
static void efx_ethtool_get_pauseparam(struct net_device *net_dev,
struct ethtool_pauseparam *pause)
{
struct efx_nic *efx = net_dev->priv;
pause->rx_pause = (efx->flow_control & EFX_FC_RX) ? 1 : 0;
pause->tx_pause = (efx->flow_control & EFX_FC_TX) ? 1 : 0;
pause->autoneg = (efx->flow_control & EFX_FC_AUTO) ? 1 : 0;
}
struct ethtool_ops efx_ethtool_ops = {
.get_settings = efx_ethtool_get_settings,
.set_settings = efx_ethtool_set_settings,
.get_drvinfo = efx_ethtool_get_drvinfo,
.nway_reset = efx_ethtool_nway_reset,
.get_link = efx_ethtool_get_link,
.get_coalesce = efx_ethtool_get_coalesce,
.set_coalesce = efx_ethtool_set_coalesce,
.get_pauseparam = efx_ethtool_get_pauseparam,
.set_pauseparam = efx_ethtool_set_pauseparam,
.get_rx_csum = efx_ethtool_get_rx_csum,
.set_rx_csum = efx_ethtool_set_rx_csum,
.get_tx_csum = ethtool_op_get_tx_csum,
.set_tx_csum = efx_ethtool_set_tx_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_flags = ethtool_op_get_flags,
.set_flags = ethtool_op_set_flags,
.get_strings = efx_ethtool_get_strings,
.phys_id = efx_ethtool_phys_id,
.get_stats_count = efx_ethtool_get_stats_count,
.get_ethtool_stats = efx_ethtool_get_stats,
};

View File

@ -0,0 +1,27 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005 Fen Systems Ltd.
* Copyright 2006 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#ifndef EFX_ETHTOOL_H
#define EFX_ETHTOOL_H
#include "net_driver.h"
/*
* Ethtool support
*/
extern int efx_ethtool_get_settings(struct net_device *net_dev,
struct ethtool_cmd *ecmd);
extern int efx_ethtool_set_settings(struct net_device *net_dev,
struct ethtool_cmd *ecmd);
extern struct ethtool_ops efx_ethtool_ops;
#endif /* EFX_ETHTOOL_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,130 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2008 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#ifndef EFX_FALCON_H
#define EFX_FALCON_H
#include "net_driver.h"
/*
* Falcon hardware control
*/
enum falcon_revision {
FALCON_REV_A0 = 0,
FALCON_REV_A1 = 1,
FALCON_REV_B0 = 2,
};
#define FALCON_REV(efx) ((efx)->pci_dev->revision)
extern struct efx_nic_type falcon_a_nic_type;
extern struct efx_nic_type falcon_b_nic_type;
/**************************************************************************
*
* Externs
*
**************************************************************************
*/
/* TX data path */
extern int falcon_probe_tx(struct efx_tx_queue *tx_queue);
extern int falcon_init_tx(struct efx_tx_queue *tx_queue);
extern void falcon_fini_tx(struct efx_tx_queue *tx_queue);
extern void falcon_remove_tx(struct efx_tx_queue *tx_queue);
extern void falcon_push_buffers(struct efx_tx_queue *tx_queue);
/* RX data path */
extern int falcon_probe_rx(struct efx_rx_queue *rx_queue);
extern int falcon_init_rx(struct efx_rx_queue *rx_queue);
extern void falcon_fini_rx(struct efx_rx_queue *rx_queue);
extern void falcon_remove_rx(struct efx_rx_queue *rx_queue);
extern void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue);
/* Event data path */
extern int falcon_probe_eventq(struct efx_channel *channel);
extern int falcon_init_eventq(struct efx_channel *channel);
extern void falcon_fini_eventq(struct efx_channel *channel);
extern void falcon_remove_eventq(struct efx_channel *channel);
extern int falcon_process_eventq(struct efx_channel *channel, int *rx_quota);
extern void falcon_eventq_read_ack(struct efx_channel *channel);
/* Ports */
extern int falcon_probe_port(struct efx_nic *efx);
extern void falcon_remove_port(struct efx_nic *efx);
/* MAC/PHY */
extern int falcon_xaui_link_ok(struct efx_nic *efx);
extern int falcon_dma_stats(struct efx_nic *efx,
unsigned int done_offset);
extern void falcon_drain_tx_fifo(struct efx_nic *efx);
extern void falcon_deconfigure_mac_wrapper(struct efx_nic *efx);
extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx);
/* Interrupts and test events */
extern int falcon_init_interrupt(struct efx_nic *efx);
extern void falcon_enable_interrupts(struct efx_nic *efx);
extern void falcon_generate_test_event(struct efx_channel *channel,
unsigned int magic);
extern void falcon_generate_interrupt(struct efx_nic *efx);
extern void falcon_set_int_moderation(struct efx_channel *channel);
extern void falcon_disable_interrupts(struct efx_nic *efx);
extern void falcon_fini_interrupt(struct efx_nic *efx);
/* Global Resources */
extern int falcon_probe_nic(struct efx_nic *efx);
extern int falcon_probe_resources(struct efx_nic *efx);
extern int falcon_init_nic(struct efx_nic *efx);
extern int falcon_reset_hw(struct efx_nic *efx, enum reset_type method);
extern void falcon_remove_resources(struct efx_nic *efx);
extern void falcon_remove_nic(struct efx_nic *efx);
extern void falcon_update_nic_stats(struct efx_nic *efx);
extern void falcon_set_multicast_hash(struct efx_nic *efx);
extern int falcon_reset_xaui(struct efx_nic *efx);
/**************************************************************************
*
* Falcon MAC stats
*
**************************************************************************
*/
#define FALCON_STAT_OFFSET(falcon_stat) EFX_VAL(falcon_stat, offset)
#define FALCON_STAT_WIDTH(falcon_stat) EFX_VAL(falcon_stat, WIDTH)
/* Retrieve statistic from statistics block */
#define FALCON_STAT(efx, falcon_stat, efx_stat) do { \
if (FALCON_STAT_WIDTH(falcon_stat) == 16) \
(efx)->mac_stats.efx_stat += le16_to_cpu( \
*((__force __le16 *) \
(efx->stats_buffer.addr + \
FALCON_STAT_OFFSET(falcon_stat)))); \
else if (FALCON_STAT_WIDTH(falcon_stat) == 32) \
(efx)->mac_stats.efx_stat += le32_to_cpu( \
*((__force __le32 *) \
(efx->stats_buffer.addr + \
FALCON_STAT_OFFSET(falcon_stat)))); \
else \
(efx)->mac_stats.efx_stat += le64_to_cpu( \
*((__force __le64 *) \
(efx->stats_buffer.addr + \
FALCON_STAT_OFFSET(falcon_stat)))); \
} while (0)
#define FALCON_MAC_STATS_SIZE 0x100
#define MAC_DATA_LBN 0
#define MAC_DATA_WIDTH 32
extern void falcon_generate_event(struct efx_channel *channel,
efx_qword_t *event);
#endif /* EFX_FALCON_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,243 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2008 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#ifndef EFX_FALCON_IO_H
#define EFX_FALCON_IO_H
#include <linux/io.h>
#include <linux/spinlock.h>
#include "net_driver.h"
/**************************************************************************
*
* Falcon hardware access
*
**************************************************************************
*
* Notes on locking strategy:
*
* Most Falcon registers require 16-byte (or 8-byte, for SRAM
* registers) atomic writes which necessitates locking.
* Under normal operation few writes to the Falcon BAR are made and these
* registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and TX_DESC_UPD_REG) are special
* cased to allow 4-byte (hence lockless) accesses.
*
* It *is* safe to write to these 4-byte registers in the middle of an
* access to an 8-byte or 16-byte register. We therefore use a
* spinlock to protect accesses to the larger registers, but no locks
* for the 4-byte registers.
*
* A write barrier is needed to ensure that DW3 is written after DW0/1/2
* due to the way the 16byte registers are "collected" in the Falcon BIU
*
* We also lock when carrying out reads, to ensure consistency of the
* data (made possible since the BIU reads all 128 bits into a cache).
* Reads are very rare, so this isn't a significant performance
* impact. (Most data transferred from NIC to host is DMAed directly
* into host memory).
*
* I/O BAR access uses locks for both reads and writes (but is only provided
* for testing purposes).
*/
/* Special buffer descriptors (Falcon SRAM) */
#define BUF_TBL_KER_A1 0x18000
#define BUF_TBL_KER_B0 0x800000
#if BITS_PER_LONG == 64
#define FALCON_USE_QWORD_IO 1
#endif
#define _falcon_writeq(efx, value, reg) \
__raw_writeq((__force u64) (value), (efx)->membase + (reg))
#define _falcon_writel(efx, value, reg) \
__raw_writel((__force u32) (value), (efx)->membase + (reg))
#define _falcon_readq(efx, reg) \
((__force __le64) __raw_readq((efx)->membase + (reg)))
#define _falcon_readl(efx, reg) \
((__force __le32) __raw_readl((efx)->membase + (reg)))
/* Writes to a normal 16-byte Falcon register, locking as appropriate. */
static inline void falcon_write(struct efx_nic *efx, efx_oword_t *value,
unsigned int reg)
{
unsigned long flags;
EFX_REGDUMP(efx, "writing register %x with " EFX_OWORD_FMT "\n", reg,
EFX_OWORD_VAL(*value));
spin_lock_irqsave(&efx->biu_lock, flags);
#ifdef FALCON_USE_QWORD_IO
_falcon_writeq(efx, value->u64[0], reg + 0);
wmb();
_falcon_writeq(efx, value->u64[1], reg + 8);
#else
_falcon_writel(efx, value->u32[0], reg + 0);
_falcon_writel(efx, value->u32[1], reg + 4);
_falcon_writel(efx, value->u32[2], reg + 8);
wmb();
_falcon_writel(efx, value->u32[3], reg + 12);
#endif
mmiowb();
spin_unlock_irqrestore(&efx->biu_lock, flags);
}
/* Writes to an 8-byte Falcon SRAM register, locking as appropriate. */
static inline void falcon_write_sram(struct efx_nic *efx, efx_qword_t *value,
unsigned int index)
{
unsigned int reg = efx->type->buf_tbl_base + (index * sizeof(*value));
unsigned long flags;
EFX_REGDUMP(efx, "writing SRAM register %x with " EFX_QWORD_FMT "\n",
reg, EFX_QWORD_VAL(*value));
spin_lock_irqsave(&efx->biu_lock, flags);
#ifdef FALCON_USE_QWORD_IO
_falcon_writeq(efx, value->u64[0], reg + 0);
#else
_falcon_writel(efx, value->u32[0], reg + 0);
wmb();
_falcon_writel(efx, value->u32[1], reg + 4);
#endif
mmiowb();
spin_unlock_irqrestore(&efx->biu_lock, flags);
}
/* Write dword to Falcon register that allows partial writes
*
* Some Falcon registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and
* TX_DESC_UPD_REG) can be written to as a single dword. This allows
* for lockless writes.
*/
static inline void falcon_writel(struct efx_nic *efx, efx_dword_t *value,
unsigned int reg)
{
EFX_REGDUMP(efx, "writing partial register %x with "EFX_DWORD_FMT"\n",
reg, EFX_DWORD_VAL(*value));
/* No lock required */
_falcon_writel(efx, value->u32[0], reg);
}
/* Read from a Falcon register
*
* This reads an entire 16-byte Falcon register in one go, locking as
* appropriate. It is essential to read the first dword first, as this
* prompts Falcon to load the current value into the shadow register.
*/
static inline void falcon_read(struct efx_nic *efx, efx_oword_t *value,
unsigned int reg)
{
unsigned long flags;
spin_lock_irqsave(&efx->biu_lock, flags);
value->u32[0] = _falcon_readl(efx, reg + 0);
rmb();
value->u32[1] = _falcon_readl(efx, reg + 4);
value->u32[2] = _falcon_readl(efx, reg + 8);
value->u32[3] = _falcon_readl(efx, reg + 12);
spin_unlock_irqrestore(&efx->biu_lock, flags);
EFX_REGDUMP(efx, "read from register %x, got " EFX_OWORD_FMT "\n", reg,
EFX_OWORD_VAL(*value));
}
/* This reads an 8-byte Falcon SRAM entry in one go. */
static inline void falcon_read_sram(struct efx_nic *efx, efx_qword_t *value,
unsigned int index)
{
unsigned int reg = efx->type->buf_tbl_base + (index * sizeof(*value));
unsigned long flags;
spin_lock_irqsave(&efx->biu_lock, flags);
#ifdef FALCON_USE_QWORD_IO
value->u64[0] = _falcon_readq(efx, reg + 0);
#else
value->u32[0] = _falcon_readl(efx, reg + 0);
rmb();
value->u32[1] = _falcon_readl(efx, reg + 4);
#endif
spin_unlock_irqrestore(&efx->biu_lock, flags);
EFX_REGDUMP(efx, "read from SRAM register %x, got "EFX_QWORD_FMT"\n",
reg, EFX_QWORD_VAL(*value));
}
/* Read dword from Falcon register that allows partial writes (sic) */
static inline void falcon_readl(struct efx_nic *efx, efx_dword_t *value,
unsigned int reg)
{
value->u32[0] = _falcon_readl(efx, reg);
EFX_REGDUMP(efx, "read from register %x, got "EFX_DWORD_FMT"\n",
reg, EFX_DWORD_VAL(*value));
}
/* Write to a register forming part of a table */
static inline void falcon_write_table(struct efx_nic *efx, efx_oword_t *value,
unsigned int reg, unsigned int index)
{
falcon_write(efx, value, reg + index * sizeof(efx_oword_t));
}
/* Read to a register forming part of a table */
static inline void falcon_read_table(struct efx_nic *efx, efx_oword_t *value,
unsigned int reg, unsigned int index)
{
falcon_read(efx, value, reg + index * sizeof(efx_oword_t));
}
/* Write to a dword register forming part of a table */
static inline void falcon_writel_table(struct efx_nic *efx, efx_dword_t *value,
unsigned int reg, unsigned int index)
{
falcon_writel(efx, value, reg + index * sizeof(efx_oword_t));
}
/* Page-mapped register block size */
#define FALCON_PAGE_BLOCK_SIZE 0x2000
/* Calculate offset to page-mapped register block */
#define FALCON_PAGED_REG(page, reg) \
((page) * FALCON_PAGE_BLOCK_SIZE + (reg))
/* As for falcon_write(), but for a page-mapped register. */
static inline void falcon_write_page(struct efx_nic *efx, efx_oword_t *value,
unsigned int reg, unsigned int page)
{
falcon_write(efx, value, FALCON_PAGED_REG(page, reg));
}
/* As for falcon_writel(), but for a page-mapped register. */
static inline void falcon_writel_page(struct efx_nic *efx, efx_dword_t *value,
unsigned int reg, unsigned int page)
{
falcon_writel(efx, value, FALCON_PAGED_REG(page, reg));
}
/* Write dword to Falcon page-mapped register with an extra lock.
*
* As for falcon_writel_page(), but for a register that suffers from
* SFC bug 3181. Take out a lock so the BIU collector cannot be
* confused. */
static inline void falcon_writel_page_locked(struct efx_nic *efx,
efx_dword_t *value,
unsigned int reg,
unsigned int page)
{
unsigned long flags;
spin_lock_irqsave(&efx->biu_lock, flags);
falcon_writel(efx, value, FALCON_PAGED_REG(page, reg));
spin_unlock_irqrestore(&efx->biu_lock, flags);
}
#endif /* EFX_FALCON_IO_H */

View File

@ -0,0 +1,585 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2008 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#include <linux/delay.h>
#include "net_driver.h"
#include "efx.h"
#include "falcon.h"
#include "falcon_hwdefs.h"
#include "falcon_io.h"
#include "mac.h"
#include "gmii.h"
#include "mdio_10g.h"
#include "phy.h"
#include "boards.h"
#include "workarounds.h"
/**************************************************************************
*
* MAC register access
*
**************************************************************************/
/* Offset of an XMAC register within Falcon */
#define FALCON_XMAC_REG(mac_reg) \
(FALCON_XMAC_REGBANK + ((mac_reg) * FALCON_XMAC_REG_SIZE))
void falcon_xmac_writel(struct efx_nic *efx,
efx_dword_t *value, unsigned int mac_reg)
{
efx_oword_t temp;
EFX_POPULATE_OWORD_1(temp, MAC_DATA, EFX_DWORD_FIELD(*value, MAC_DATA));
falcon_write(efx, &temp, FALCON_XMAC_REG(mac_reg));
}
void falcon_xmac_readl(struct efx_nic *efx,
efx_dword_t *value, unsigned int mac_reg)
{
efx_oword_t temp;
falcon_read(efx, &temp, FALCON_XMAC_REG(mac_reg));
EFX_POPULATE_DWORD_1(*value, MAC_DATA, EFX_OWORD_FIELD(temp, MAC_DATA));
}
/**************************************************************************
*
* MAC operations
*
*************************************************************************/
static int falcon_reset_xmac(struct efx_nic *efx)
{
efx_dword_t reg;
int count;
EFX_POPULATE_DWORD_1(reg, XM_CORE_RST, 1);
falcon_xmac_writel(efx, &reg, XM_GLB_CFG_REG_MAC);
for (count = 0; count < 10000; count++) { /* wait upto 100ms */
falcon_xmac_readl(efx, &reg, XM_GLB_CFG_REG_MAC);
if (EFX_DWORD_FIELD(reg, XM_CORE_RST) == 0)
return 0;
udelay(10);
}
EFX_ERR(efx, "timed out waiting for XMAC core reset\n");
return -ETIMEDOUT;
}
/* Configure the XAUI driver that is an output from Falcon */
static void falcon_setup_xaui(struct efx_nic *efx)
{
efx_dword_t sdctl, txdrv;
/* Move the XAUI into low power, unless there is no PHY, in
* which case the XAUI will have to drive a cable. */
if (efx->phy_type == PHY_TYPE_NONE)
return;
falcon_xmac_readl(efx, &sdctl, XX_SD_CTL_REG_MAC);
EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT);
EFX_SET_DWORD_FIELD(sdctl, XX_LODRVD, XX_SD_CTL_DRV_DEFAULT);
EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT);
EFX_SET_DWORD_FIELD(sdctl, XX_LODRVC, XX_SD_CTL_DRV_DEFAULT);
EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT);
EFX_SET_DWORD_FIELD(sdctl, XX_LODRVB, XX_SD_CTL_DRV_DEFAULT);
EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT);
EFX_SET_DWORD_FIELD(sdctl, XX_LODRVA, XX_SD_CTL_DRV_DEFAULT);
falcon_xmac_writel(efx, &sdctl, XX_SD_CTL_REG_MAC);
EFX_POPULATE_DWORD_8(txdrv,
XX_DEQD, XX_TXDRV_DEQ_DEFAULT,
XX_DEQC, XX_TXDRV_DEQ_DEFAULT,
XX_DEQB, XX_TXDRV_DEQ_DEFAULT,
XX_DEQA, XX_TXDRV_DEQ_DEFAULT,
XX_DTXD, XX_TXDRV_DTX_DEFAULT,
XX_DTXC, XX_TXDRV_DTX_DEFAULT,
XX_DTXB, XX_TXDRV_DTX_DEFAULT,
XX_DTXA, XX_TXDRV_DTX_DEFAULT);
falcon_xmac_writel(efx, &txdrv, XX_TXDRV_CTL_REG_MAC);
}
static void falcon_hold_xaui_in_rst(struct efx_nic *efx)
{
efx_dword_t reg;
EFX_ZERO_DWORD(reg);
EFX_SET_DWORD_FIELD(reg, XX_PWRDNA_EN, 1);
EFX_SET_DWORD_FIELD(reg, XX_PWRDNB_EN, 1);
EFX_SET_DWORD_FIELD(reg, XX_PWRDNC_EN, 1);
EFX_SET_DWORD_FIELD(reg, XX_PWRDND_EN, 1);
EFX_SET_DWORD_FIELD(reg, XX_RSTPLLAB_EN, 1);
EFX_SET_DWORD_FIELD(reg, XX_RSTPLLCD_EN, 1);
EFX_SET_DWORD_FIELD(reg, XX_RESETA_EN, 1);
EFX_SET_DWORD_FIELD(reg, XX_RESETB_EN, 1);
EFX_SET_DWORD_FIELD(reg, XX_RESETC_EN, 1);
EFX_SET_DWORD_FIELD(reg, XX_RESETD_EN, 1);
EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSRX_EN, 1);
EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSTX_EN, 1);
falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
udelay(10);
}
static int _falcon_reset_xaui_a(struct efx_nic *efx)
{
efx_dword_t reg;
falcon_hold_xaui_in_rst(efx);
falcon_xmac_readl(efx, &reg, XX_PWR_RST_REG_MAC);
/* Follow the RAMBUS XAUI data reset sequencing
* Channels A and B first: power down, reset PLL, reset, clear
*/
EFX_SET_DWORD_FIELD(reg, XX_PWRDNA_EN, 0);
EFX_SET_DWORD_FIELD(reg, XX_PWRDNB_EN, 0);
falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
udelay(10);
EFX_SET_DWORD_FIELD(reg, XX_RSTPLLAB_EN, 0);
falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
udelay(10);
EFX_SET_DWORD_FIELD(reg, XX_RESETA_EN, 0);
EFX_SET_DWORD_FIELD(reg, XX_RESETB_EN, 0);
falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
udelay(10);
/* Channels C and D: power down, reset PLL, reset, clear */
EFX_SET_DWORD_FIELD(reg, XX_PWRDNC_EN, 0);
EFX_SET_DWORD_FIELD(reg, XX_PWRDND_EN, 0);
falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
udelay(10);
EFX_SET_DWORD_FIELD(reg, XX_RSTPLLCD_EN, 0);
falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
udelay(10);
EFX_SET_DWORD_FIELD(reg, XX_RESETC_EN, 0);
EFX_SET_DWORD_FIELD(reg, XX_RESETD_EN, 0);
falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
udelay(10);
/* Setup XAUI */
falcon_setup_xaui(efx);
udelay(10);
/* Take XGXS out of reset */
EFX_ZERO_DWORD(reg);
falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
udelay(10);
return 0;
}
static int _falcon_reset_xaui_b(struct efx_nic *efx)
{
efx_dword_t reg;
int count;
EFX_POPULATE_DWORD_1(reg, XX_RST_XX_EN, 1);
falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
/* Give some time for the link to establish */
for (count = 0; count < 1000; count++) { /* wait upto 10ms */
falcon_xmac_readl(efx, &reg, XX_PWR_RST_REG_MAC);
if (EFX_DWORD_FIELD(reg, XX_RST_XX_EN) == 0) {
falcon_setup_xaui(efx);
return 0;
}
udelay(10);
}
EFX_ERR(efx, "timed out waiting for XAUI/XGXS reset\n");
return -ETIMEDOUT;
}
int falcon_reset_xaui(struct efx_nic *efx)
{
int rc;
if (EFX_WORKAROUND_9388(efx)) {
falcon_hold_xaui_in_rst(efx);
efx->phy_op->reset_xaui(efx);
rc = _falcon_reset_xaui_a(efx);
} else {
rc = _falcon_reset_xaui_b(efx);
}
return rc;
}
static int falcon_xgmii_status(struct efx_nic *efx)
{
efx_dword_t reg;
if (FALCON_REV(efx) < FALCON_REV_B0)
return 1;
/* The ISR latches, so clear it and re-read */
falcon_xmac_readl(efx, &reg, XM_MGT_INT_REG_MAC_B0);
falcon_xmac_readl(efx, &reg, XM_MGT_INT_REG_MAC_B0);
if (EFX_DWORD_FIELD(reg, XM_LCLFLT) ||
EFX_DWORD_FIELD(reg, XM_RMTFLT)) {
EFX_INFO(efx, "MGT_INT: "EFX_DWORD_FMT"\n", EFX_DWORD_VAL(reg));
return 0;
}
return 1;
}
static void falcon_mask_status_intr(struct efx_nic *efx, int enable)
{
efx_dword_t reg;
if (FALCON_REV(efx) < FALCON_REV_B0)
return;
/* Flush the ISR */
if (enable)
falcon_xmac_readl(efx, &reg, XM_MGT_INT_REG_MAC_B0);
EFX_POPULATE_DWORD_2(reg,
XM_MSK_RMTFLT, !enable,
XM_MSK_LCLFLT, !enable);
falcon_xmac_writel(efx, &reg, XM_MGT_INT_MSK_REG_MAC_B0);
}
int falcon_init_xmac(struct efx_nic *efx)
{
int rc;
/* Initialize the PHY first so the clock is around */
rc = efx->phy_op->init(efx);
if (rc)
goto fail1;
rc = falcon_reset_xaui(efx);
if (rc)
goto fail2;
/* Wait again. Give the PHY and MAC time to come back */
schedule_timeout_uninterruptible(HZ / 10);
rc = falcon_reset_xmac(efx);
if (rc)
goto fail2;
falcon_mask_status_intr(efx, 1);
return 0;
fail2:
efx->phy_op->fini(efx);
fail1:
return rc;
}
int falcon_xaui_link_ok(struct efx_nic *efx)
{
efx_dword_t reg;
int align_done, sync_status, link_ok = 0;
/* Read link status */
falcon_xmac_readl(efx, &reg, XX_CORE_STAT_REG_MAC);
align_done = EFX_DWORD_FIELD(reg, XX_ALIGN_DONE);
sync_status = EFX_DWORD_FIELD(reg, XX_SYNC_STAT);
if (align_done && (sync_status == XX_SYNC_STAT_DECODE_SYNCED))
link_ok = 1;
/* Clear link status ready for next read */
EFX_SET_DWORD_FIELD(reg, XX_COMMA_DET, XX_COMMA_DET_RESET);
EFX_SET_DWORD_FIELD(reg, XX_CHARERR, XX_CHARERR_RESET);
EFX_SET_DWORD_FIELD(reg, XX_DISPERR, XX_DISPERR_RESET);
falcon_xmac_writel(efx, &reg, XX_CORE_STAT_REG_MAC);
/* If the link is up, then check the phy side of the xaui link
* (error conditions from the wire side propoagate back through
* the phy to the xaui side). */
if (efx->link_up && link_ok) {
int has_phyxs = efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS);
if (has_phyxs)
link_ok = mdio_clause45_phyxgxs_lane_sync(efx);
}
/* If the PHY and XAUI links are up, then check the mac's xgmii
* fault state */
if (efx->link_up && link_ok)
link_ok = falcon_xgmii_status(efx);
return link_ok;
}
static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
{
unsigned int max_frame_len;
efx_dword_t reg;
int rx_fc = (efx->flow_control & EFX_FC_RX) ? 1 : 0;
/* Configure MAC - cut-thru mode is hard wired on */
EFX_POPULATE_DWORD_3(reg,
XM_RX_JUMBO_MODE, 1,
XM_TX_STAT_EN, 1,
XM_RX_STAT_EN, 1);
falcon_xmac_writel(efx, &reg, XM_GLB_CFG_REG_MAC);
/* Configure TX */
EFX_POPULATE_DWORD_6(reg,
XM_TXEN, 1,
XM_TX_PRMBL, 1,
XM_AUTO_PAD, 1,
XM_TXCRC, 1,
XM_FCNTL, 1,
XM_IPG, 0x3);
falcon_xmac_writel(efx, &reg, XM_TX_CFG_REG_MAC);
/* Configure RX */
EFX_POPULATE_DWORD_5(reg,
XM_RXEN, 1,
XM_AUTO_DEPAD, 0,
XM_ACPT_ALL_MCAST, 1,
XM_ACPT_ALL_UCAST, efx->promiscuous,
XM_PASS_CRC_ERR, 1);
falcon_xmac_writel(efx, &reg, XM_RX_CFG_REG_MAC);
/* Set frame length */
max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu);
EFX_POPULATE_DWORD_1(reg, XM_MAX_RX_FRM_SIZE, max_frame_len);
falcon_xmac_writel(efx, &reg, XM_RX_PARAM_REG_MAC);
EFX_POPULATE_DWORD_2(reg,
XM_MAX_TX_FRM_SIZE, max_frame_len,
XM_TX_JUMBO_MODE, 1);
falcon_xmac_writel(efx, &reg, XM_TX_PARAM_REG_MAC);
EFX_POPULATE_DWORD_2(reg,
XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */
XM_DIS_FCNTL, rx_fc ? 0 : 1);
falcon_xmac_writel(efx, &reg, XM_FC_REG_MAC);
/* Set MAC address */
EFX_POPULATE_DWORD_4(reg,
XM_ADR_0, efx->net_dev->dev_addr[0],
XM_ADR_1, efx->net_dev->dev_addr[1],
XM_ADR_2, efx->net_dev->dev_addr[2],
XM_ADR_3, efx->net_dev->dev_addr[3]);
falcon_xmac_writel(efx, &reg, XM_ADR_LO_REG_MAC);
EFX_POPULATE_DWORD_2(reg,
XM_ADR_4, efx->net_dev->dev_addr[4],
XM_ADR_5, efx->net_dev->dev_addr[5]);
falcon_xmac_writel(efx, &reg, XM_ADR_HI_REG_MAC);
}
/* Try and bring the Falcon side of the Falcon-Phy XAUI link fails
* to come back up. Bash it until it comes back up */
static int falcon_check_xaui_link_up(struct efx_nic *efx)
{
int max_tries, tries;
tries = EFX_WORKAROUND_5147(efx) ? 5 : 1;
max_tries = tries;
if (efx->phy_type == PHY_TYPE_NONE)
return 0;
while (tries) {
if (falcon_xaui_link_ok(efx))
return 1;
EFX_LOG(efx, "%s Clobbering XAUI (%d tries left).\n",
__func__, tries);
(void) falcon_reset_xaui(efx);
udelay(200);
tries--;
}
EFX_ERR(efx, "Failed to bring XAUI link back up in %d tries!\n",
max_tries);
return 0;
}
void falcon_reconfigure_xmac(struct efx_nic *efx)
{
int xaui_link_ok;
falcon_mask_status_intr(efx, 0);
falcon_deconfigure_mac_wrapper(efx);
efx->phy_op->reconfigure(efx);
falcon_reconfigure_xmac_core(efx);
falcon_reconfigure_mac_wrapper(efx);
/* Ensure XAUI link is up */
xaui_link_ok = falcon_check_xaui_link_up(efx);
if (xaui_link_ok && efx->link_up)
falcon_mask_status_intr(efx, 1);
}
void falcon_fini_xmac(struct efx_nic *efx)
{
/* Isolate the MAC - PHY */
falcon_deconfigure_mac_wrapper(efx);
/* Potentially power down the PHY */
efx->phy_op->fini(efx);
}
void falcon_update_stats_xmac(struct efx_nic *efx)
{
struct efx_mac_stats *mac_stats = &efx->mac_stats;
int rc;
rc = falcon_dma_stats(efx, XgDmaDone_offset);
if (rc)
return;
/* Update MAC stats from DMAed values */
FALCON_STAT(efx, XgRxOctets, rx_bytes);
FALCON_STAT(efx, XgRxOctetsOK, rx_good_bytes);
FALCON_STAT(efx, XgRxPkts, rx_packets);
FALCON_STAT(efx, XgRxPktsOK, rx_good);
FALCON_STAT(efx, XgRxBroadcastPkts, rx_broadcast);
FALCON_STAT(efx, XgRxMulticastPkts, rx_multicast);
FALCON_STAT(efx, XgRxUnicastPkts, rx_unicast);
FALCON_STAT(efx, XgRxUndersizePkts, rx_lt64);
FALCON_STAT(efx, XgRxOversizePkts, rx_gtjumbo);
FALCON_STAT(efx, XgRxJabberPkts, rx_bad_gtjumbo);
FALCON_STAT(efx, XgRxUndersizeFCSerrorPkts, rx_bad_lt64);
FALCON_STAT(efx, XgRxDropEvents, rx_overflow);
FALCON_STAT(efx, XgRxFCSerrorPkts, rx_bad);
FALCON_STAT(efx, XgRxAlignError, rx_align_error);
FALCON_STAT(efx, XgRxSymbolError, rx_symbol_error);
FALCON_STAT(efx, XgRxInternalMACError, rx_internal_error);
FALCON_STAT(efx, XgRxControlPkts, rx_control);
FALCON_STAT(efx, XgRxPausePkts, rx_pause);
FALCON_STAT(efx, XgRxPkts64Octets, rx_64);
FALCON_STAT(efx, XgRxPkts65to127Octets, rx_65_to_127);
FALCON_STAT(efx, XgRxPkts128to255Octets, rx_128_to_255);
FALCON_STAT(efx, XgRxPkts256to511Octets, rx_256_to_511);
FALCON_STAT(efx, XgRxPkts512to1023Octets, rx_512_to_1023);
FALCON_STAT(efx, XgRxPkts1024to15xxOctets, rx_1024_to_15xx);
FALCON_STAT(efx, XgRxPkts15xxtoMaxOctets, rx_15xx_to_jumbo);
FALCON_STAT(efx, XgRxLengthError, rx_length_error);
FALCON_STAT(efx, XgTxPkts, tx_packets);
FALCON_STAT(efx, XgTxOctets, tx_bytes);
FALCON_STAT(efx, XgTxMulticastPkts, tx_multicast);
FALCON_STAT(efx, XgTxBroadcastPkts, tx_broadcast);
FALCON_STAT(efx, XgTxUnicastPkts, tx_unicast);
FALCON_STAT(efx, XgTxControlPkts, tx_control);
FALCON_STAT(efx, XgTxPausePkts, tx_pause);
FALCON_STAT(efx, XgTxPkts64Octets, tx_64);
FALCON_STAT(efx, XgTxPkts65to127Octets, tx_65_to_127);
FALCON_STAT(efx, XgTxPkts128to255Octets, tx_128_to_255);
FALCON_STAT(efx, XgTxPkts256to511Octets, tx_256_to_511);
FALCON_STAT(efx, XgTxPkts512to1023Octets, tx_512_to_1023);
FALCON_STAT(efx, XgTxPkts1024to15xxOctets, tx_1024_to_15xx);
FALCON_STAT(efx, XgTxPkts1519toMaxOctets, tx_15xx_to_jumbo);
FALCON_STAT(efx, XgTxUndersizePkts, tx_lt64);
FALCON_STAT(efx, XgTxOversizePkts, tx_gtjumbo);
FALCON_STAT(efx, XgTxNonTcpUdpPkt, tx_non_tcpudp);
FALCON_STAT(efx, XgTxMacSrcErrPkt, tx_mac_src_error);
FALCON_STAT(efx, XgTxIpSrcErrPkt, tx_ip_src_error);
/* Update derived statistics */
mac_stats->tx_good_bytes =
(mac_stats->tx_bytes - mac_stats->tx_bad_bytes);
mac_stats->rx_bad_bytes =
(mac_stats->rx_bytes - mac_stats->rx_good_bytes);
}
#define EFX_XAUI_RETRAIN_MAX 8
int falcon_check_xmac(struct efx_nic *efx)
{
unsigned xaui_link_ok;
int rc;
falcon_mask_status_intr(efx, 0);
xaui_link_ok = falcon_xaui_link_ok(efx);
if (EFX_WORKAROUND_5147(efx) && !xaui_link_ok)
(void) falcon_reset_xaui(efx);
/* Call the PHY check_hw routine */
rc = efx->phy_op->check_hw(efx);
/* Unmask interrupt if everything was (and still is) ok */
if (xaui_link_ok && efx->link_up)
falcon_mask_status_intr(efx, 1);
return rc;
}
/* Simulate a PHY event */
void falcon_xmac_sim_phy_event(struct efx_nic *efx)
{
efx_qword_t phy_event;
EFX_POPULATE_QWORD_2(phy_event,
EV_CODE, GLOBAL_EV_DECODE,
XG_PHY_INTR, 1);
falcon_generate_event(&efx->channel[0], &phy_event);
}
int falcon_xmac_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
{
mdio_clause45_get_settings(efx, ecmd);
ecmd->transceiver = XCVR_INTERNAL;
ecmd->phy_address = efx->mii.phy_id;
ecmd->autoneg = AUTONEG_DISABLE;
ecmd->duplex = DUPLEX_FULL;
return 0;
}
int falcon_xmac_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
{
if (ecmd->transceiver != XCVR_INTERNAL)
return -EINVAL;
if (ecmd->autoneg != AUTONEG_DISABLE)
return -EINVAL;
if (ecmd->duplex != DUPLEX_FULL)
return -EINVAL;
return mdio_clause45_set_settings(efx, ecmd);
}
int falcon_xmac_set_pause(struct efx_nic *efx, enum efx_fc_type flow_control)
{
int reset;
if (flow_control & EFX_FC_AUTO) {
EFX_LOG(efx, "10G does not support flow control "
"autonegotiation\n");
return -EINVAL;
}
if ((flow_control & EFX_FC_TX) && !(flow_control & EFX_FC_RX))
return -EINVAL;
/* TX flow control may automatically turn itself off if the
* link partner (intermittently) stops responding to pause
* frames. There isn't any indication that this has happened,
* so the best we do is leave it up to the user to spot this
* and fix it be cycling transmit flow control on this end. */
reset = ((flow_control & EFX_FC_TX) &&
!(efx->flow_control & EFX_FC_TX));
if (EFX_WORKAROUND_11482(efx) && reset) {
if (FALCON_REV(efx) >= FALCON_REV_B0) {
/* Recover by resetting the EM block */
if (efx->link_up)
falcon_drain_tx_fifo(efx);
} else {
/* Schedule a reset to recover */
efx_schedule_reset(efx, RESET_TYPE_INVISIBLE);
}
}
efx->flow_control = flow_control;
return 0;
}

View File

@ -0,0 +1,195 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#ifndef EFX_GMII_H
#define EFX_GMII_H
/*
* GMII interface
*/
#include <linux/mii.h>
/* GMII registers, excluding registers already defined as MII
* registers in mii.h
*/
#define GMII_IER 0x12 /* Interrupt enable register */
#define GMII_ISR 0x13 /* Interrupt status register */
/* Interrupt enable register */
#define IER_ANEG_ERR 0x8000 /* Bit 15 - autonegotiation error */
#define IER_SPEED_CHG 0x4000 /* Bit 14 - speed changed */
#define IER_DUPLEX_CHG 0x2000 /* Bit 13 - duplex changed */
#define IER_PAGE_RCVD 0x1000 /* Bit 12 - page received */
#define IER_ANEG_DONE 0x0800 /* Bit 11 - autonegotiation complete */
#define IER_LINK_CHG 0x0400 /* Bit 10 - link status changed */
#define IER_SYM_ERR 0x0200 /* Bit 9 - symbol error */
#define IER_FALSE_CARRIER 0x0100 /* Bit 8 - false carrier */
#define IER_FIFO_ERR 0x0080 /* Bit 7 - FIFO over/underflow */
#define IER_MDIX_CHG 0x0040 /* Bit 6 - MDI crossover changed */
#define IER_DOWNSHIFT 0x0020 /* Bit 5 - downshift */
#define IER_ENERGY 0x0010 /* Bit 4 - energy detect */
#define IER_DTE_POWER 0x0004 /* Bit 2 - DTE power detect */
#define IER_POLARITY_CHG 0x0002 /* Bit 1 - polarity changed */
#define IER_JABBER 0x0001 /* Bit 0 - jabber */
/* Interrupt status register */
#define ISR_ANEG_ERR 0x8000 /* Bit 15 - autonegotiation error */
#define ISR_SPEED_CHG 0x4000 /* Bit 14 - speed changed */
#define ISR_DUPLEX_CHG 0x2000 /* Bit 13 - duplex changed */
#define ISR_PAGE_RCVD 0x1000 /* Bit 12 - page received */
#define ISR_ANEG_DONE 0x0800 /* Bit 11 - autonegotiation complete */
#define ISR_LINK_CHG 0x0400 /* Bit 10 - link status changed */
#define ISR_SYM_ERR 0x0200 /* Bit 9 - symbol error */
#define ISR_FALSE_CARRIER 0x0100 /* Bit 8 - false carrier */
#define ISR_FIFO_ERR 0x0080 /* Bit 7 - FIFO over/underflow */
#define ISR_MDIX_CHG 0x0040 /* Bit 6 - MDI crossover changed */
#define ISR_DOWNSHIFT 0x0020 /* Bit 5 - downshift */
#define ISR_ENERGY 0x0010 /* Bit 4 - energy detect */
#define ISR_DTE_POWER 0x0004 /* Bit 2 - DTE power detect */
#define ISR_POLARITY_CHG 0x0002 /* Bit 1 - polarity changed */
#define ISR_JABBER 0x0001 /* Bit 0 - jabber */
/* Logically extended advertisement register */
#define GM_ADVERTISE_SLCT ADVERTISE_SLCT
#define GM_ADVERTISE_CSMA ADVERTISE_CSMA
#define GM_ADVERTISE_10HALF ADVERTISE_10HALF
#define GM_ADVERTISE_1000XFULL ADVERTISE_1000XFULL
#define GM_ADVERTISE_10FULL ADVERTISE_10FULL
#define GM_ADVERTISE_1000XHALF ADVERTISE_1000XHALF
#define GM_ADVERTISE_100HALF ADVERTISE_100HALF
#define GM_ADVERTISE_1000XPAUSE ADVERTISE_1000XPAUSE
#define GM_ADVERTISE_100FULL ADVERTISE_100FULL
#define GM_ADVERTISE_1000XPSE_ASYM ADVERTISE_1000XPSE_ASYM
#define GM_ADVERTISE_100BASE4 ADVERTISE_100BASE4
#define GM_ADVERTISE_PAUSE_CAP ADVERTISE_PAUSE_CAP
#define GM_ADVERTISE_PAUSE_ASYM ADVERTISE_PAUSE_ASYM
#define GM_ADVERTISE_RESV ADVERTISE_RESV
#define GM_ADVERTISE_RFAULT ADVERTISE_RFAULT
#define GM_ADVERTISE_LPACK ADVERTISE_LPACK
#define GM_ADVERTISE_NPAGE ADVERTISE_NPAGE
#define GM_ADVERTISE_1000FULL (ADVERTISE_1000FULL << 8)
#define GM_ADVERTISE_1000HALF (ADVERTISE_1000HALF << 8)
#define GM_ADVERTISE_1000 (GM_ADVERTISE_1000FULL | \
GM_ADVERTISE_1000HALF)
#define GM_ADVERTISE_FULL (GM_ADVERTISE_1000FULL | \
ADVERTISE_FULL)
#define GM_ADVERTISE_ALL (GM_ADVERTISE_1000FULL | \
GM_ADVERTISE_1000HALF | \
ADVERTISE_ALL)
/* Logically extended link partner ability register */
#define GM_LPA_SLCT LPA_SLCT
#define GM_LPA_10HALF LPA_10HALF
#define GM_LPA_1000XFULL LPA_1000XFULL
#define GM_LPA_10FULL LPA_10FULL
#define GM_LPA_1000XHALF LPA_1000XHALF
#define GM_LPA_100HALF LPA_100HALF
#define GM_LPA_1000XPAUSE LPA_1000XPAUSE
#define GM_LPA_100FULL LPA_100FULL
#define GM_LPA_1000XPAUSE_ASYM LPA_1000XPAUSE_ASYM
#define GM_LPA_100BASE4 LPA_100BASE4
#define GM_LPA_PAUSE_CAP LPA_PAUSE_CAP
#define GM_LPA_PAUSE_ASYM LPA_PAUSE_ASYM
#define GM_LPA_RESV LPA_RESV
#define GM_LPA_RFAULT LPA_RFAULT
#define GM_LPA_LPACK LPA_LPACK
#define GM_LPA_NPAGE LPA_NPAGE
#define GM_LPA_1000FULL (LPA_1000FULL << 6)
#define GM_LPA_1000HALF (LPA_1000HALF << 6)
#define GM_LPA_10000FULL 0x00040000
#define GM_LPA_10000HALF 0x00080000
#define GM_LPA_DUPLEX (GM_LPA_1000FULL | GM_LPA_10000FULL \
| LPA_DUPLEX)
#define GM_LPA_10 (LPA_10FULL | LPA_10HALF)
#define GM_LPA_100 LPA_100
#define GM_LPA_1000 (GM_LPA_1000FULL | GM_LPA_1000HALF)
#define GM_LPA_10000 (GM_LPA_10000FULL | GM_LPA_10000HALF)
/* Retrieve GMII autonegotiation advertised abilities
*
* The MII advertisment register (MII_ADVERTISE) is logically extended
* to include advertisement bits ADVERTISE_1000FULL and
* ADVERTISE_1000HALF from MII_CTRL1000. The result can be tested
* against the GM_ADVERTISE_xxx constants.
*/
static inline unsigned int gmii_advertised(struct mii_if_info *gmii)
{
unsigned int advertise;
unsigned int ctrl1000;
advertise = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_ADVERTISE);
ctrl1000 = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_CTRL1000);
return (((ctrl1000 << 8) & GM_ADVERTISE_1000) | advertise);
}
/* Retrieve GMII autonegotiation link partner abilities
*
* The MII link partner ability register (MII_LPA) is logically
* extended by adding bits LPA_1000HALF and LPA_1000FULL from
* MII_STAT1000. The result can be tested against the GM_LPA_xxx
* constants.
*/
static inline unsigned int gmii_lpa(struct mii_if_info *gmii)
{
unsigned int lpa;
unsigned int stat1000;
lpa = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_LPA);
stat1000 = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_STAT1000);
return (((stat1000 << 6) & GM_LPA_1000) | lpa);
}
/* Calculate GMII autonegotiated link technology
*
* "negotiated" should be the result of gmii_advertised() logically
* ANDed with the result of gmii_lpa().
*
* "tech" will be negotiated with the unused bits masked out. For
* example, if both ends of the link are capable of both
* GM_LPA_1000FULL and GM_LPA_100FULL, GM_LPA_100FULL will be masked
* out.
*/
static inline unsigned int gmii_nway_result(unsigned int negotiated)
{
unsigned int other_bits;
/* Mask out the speed and duplexity bits */
other_bits = negotiated & ~(GM_LPA_10 | GM_LPA_100 | GM_LPA_1000);
if (negotiated & GM_LPA_1000FULL)
return (other_bits | GM_LPA_1000FULL);
else if (negotiated & GM_LPA_1000HALF)
return (other_bits | GM_LPA_1000HALF);
else
return (other_bits | mii_nway_result(negotiated));
}
/* Calculate GMII non-autonegotiated link technology
*
* This provides an equivalent to gmii_nway_result for the case when
* autonegotiation is disabled.
*/
static inline unsigned int gmii_forced_result(unsigned int bmcr)
{
unsigned int result;
int full_duplex;
full_duplex = bmcr & BMCR_FULLDPLX;
if (bmcr & BMCR_SPEED1000)
result = full_duplex ? GM_LPA_1000FULL : GM_LPA_1000HALF;
else if (bmcr & BMCR_SPEED100)
result = full_duplex ? GM_LPA_100FULL : GM_LPA_100HALF;
else
result = full_duplex ? GM_LPA_10FULL : GM_LPA_10HALF;
return result;
}
#endif /* EFX_GMII_H */

View File

@ -0,0 +1,381 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005 Fen Systems Ltd.
* Copyright 2006-2008 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#include <linux/delay.h>
#include "net_driver.h"
#include "i2c-direct.h"
/*
* I2C data (SDA) and clock (SCL) line read/writes with appropriate
* delays.
*/
static inline void setsda(struct efx_i2c_interface *i2c, int state)
{
udelay(i2c->op->udelay);
i2c->sda = state;
i2c->op->setsda(i2c);
udelay(i2c->op->udelay);
}
static inline void setscl(struct efx_i2c_interface *i2c, int state)
{
udelay(i2c->op->udelay);
i2c->scl = state;
i2c->op->setscl(i2c);
udelay(i2c->op->udelay);
}
static inline int getsda(struct efx_i2c_interface *i2c)
{
int sda;
udelay(i2c->op->udelay);
sda = i2c->op->getsda(i2c);
udelay(i2c->op->udelay);
return sda;
}
static inline int getscl(struct efx_i2c_interface *i2c)
{
int scl;
udelay(i2c->op->udelay);
scl = i2c->op->getscl(i2c);
udelay(i2c->op->udelay);
return scl;
}
/*
* I2C low-level protocol operations
*
*/
static inline void i2c_release(struct efx_i2c_interface *i2c)
{
EFX_WARN_ON_PARANOID(!i2c->scl);
EFX_WARN_ON_PARANOID(!i2c->sda);
/* Devices may time out if operations do not end */
setscl(i2c, 1);
setsda(i2c, 1);
EFX_BUG_ON_PARANOID(getsda(i2c) != 1);
EFX_BUG_ON_PARANOID(getscl(i2c) != 1);
}
static inline void i2c_start(struct efx_i2c_interface *i2c)
{
/* We may be restarting immediately after a {send,recv}_bit,
* so SCL will not necessarily already be high.
*/
EFX_WARN_ON_PARANOID(!i2c->sda);
setscl(i2c, 1);
setsda(i2c, 0);
setscl(i2c, 0);
setsda(i2c, 1);
}
static inline void i2c_send_bit(struct efx_i2c_interface *i2c, int bit)
{
EFX_WARN_ON_PARANOID(i2c->scl != 0);
setsda(i2c, bit);
setscl(i2c, 1);
setscl(i2c, 0);
setsda(i2c, 1);
}
static inline int i2c_recv_bit(struct efx_i2c_interface *i2c)
{
int bit;
EFX_WARN_ON_PARANOID(i2c->scl != 0);
EFX_WARN_ON_PARANOID(!i2c->sda);
setscl(i2c, 1);
bit = getsda(i2c);
setscl(i2c, 0);
return bit;
}
static inline void i2c_stop(struct efx_i2c_interface *i2c)
{
EFX_WARN_ON_PARANOID(i2c->scl != 0);
setsda(i2c, 0);
setscl(i2c, 1);
setsda(i2c, 1);
}
/*
* I2C mid-level protocol operations
*
*/
/* Sends a byte via the I2C bus and checks for an acknowledgement from
* the slave device.
*/
static int i2c_send_byte(struct efx_i2c_interface *i2c, u8 byte)
{
int i;
/* Send byte */
for (i = 0; i < 8; i++) {
i2c_send_bit(i2c, !!(byte & 0x80));
byte <<= 1;
}
/* Check for acknowledgement from slave */
return (i2c_recv_bit(i2c) == 0 ? 0 : -EIO);
}
/* Receives a byte via the I2C bus and sends ACK/NACK to the slave device. */
static u8 i2c_recv_byte(struct efx_i2c_interface *i2c, int ack)
{
u8 value = 0;
int i;
/* Receive byte */
for (i = 0; i < 8; i++)
value = (value << 1) | i2c_recv_bit(i2c);
/* Send ACK/NACK */
i2c_send_bit(i2c, (ack ? 0 : 1));
return value;
}
/* Calculate command byte for a read operation */
static inline u8 i2c_read_cmd(u8 device_id)
{
return ((device_id << 1) | 1);
}
/* Calculate command byte for a write operation */
static inline u8 i2c_write_cmd(u8 device_id)
{
return ((device_id << 1) | 0);
}
int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id)
{
int rc;
/* If someone is driving the bus low we just give up. */
if (getsda(i2c) == 0 || getscl(i2c) == 0) {
EFX_ERR(i2c->efx, "%s someone is holding the I2C bus low."
" Giving up.\n", __func__);
return -EFAULT;
}
/* Pretend to initiate a device write */
i2c_start(i2c);
rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
if (rc)
goto out;
out:
i2c_stop(i2c);
i2c_release(i2c);
return rc;
}
/* This performs a fast read of one or more consecutive bytes from an
* I2C device. Not all devices support consecutive reads of more than
* one byte; for these devices use efx_i2c_read() instead.
*/
int efx_i2c_fast_read(struct efx_i2c_interface *i2c,
u8 device_id, u8 offset, u8 *data, unsigned int len)
{
int i;
int rc;
EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
EFX_WARN_ON_PARANOID(data == NULL);
EFX_WARN_ON_PARANOID(len < 1);
/* Select device and starting offset */
i2c_start(i2c);
rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
if (rc)
goto out;
rc = i2c_send_byte(i2c, offset);
if (rc)
goto out;
/* Read data from device */
i2c_start(i2c);
rc = i2c_send_byte(i2c, i2c_read_cmd(device_id));
if (rc)
goto out;
for (i = 0; i < (len - 1); i++)
/* Read and acknowledge all but the last byte */
data[i] = i2c_recv_byte(i2c, 1);
/* Read last byte with no acknowledgement */
data[i] = i2c_recv_byte(i2c, 0);
out:
i2c_stop(i2c);
i2c_release(i2c);
return rc;
}
/* This performs a fast write of one or more consecutive bytes to an
* I2C device. Not all devices support consecutive writes of more
* than one byte; for these devices use efx_i2c_write() instead.
*/
int efx_i2c_fast_write(struct efx_i2c_interface *i2c,
u8 device_id, u8 offset,
const u8 *data, unsigned int len)
{
int i;
int rc;
EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
EFX_WARN_ON_PARANOID(len < 1);
/* Select device and starting offset */
i2c_start(i2c);
rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
if (rc)
goto out;
rc = i2c_send_byte(i2c, offset);
if (rc)
goto out;
/* Write data to device */
for (i = 0; i < len; i++) {
rc = i2c_send_byte(i2c, data[i]);
if (rc)
goto out;
}
out:
i2c_stop(i2c);
i2c_release(i2c);
return rc;
}
/* I2C byte-by-byte read */
int efx_i2c_read(struct efx_i2c_interface *i2c,
u8 device_id, u8 offset, u8 *data, unsigned int len)
{
int rc;
/* i2c_fast_read with length 1 is a single byte read */
for (; len > 0; offset++, data++, len--) {
rc = efx_i2c_fast_read(i2c, device_id, offset, data, 1);
if (rc)
return rc;
}
return 0;
}
/* I2C byte-by-byte write */
int efx_i2c_write(struct efx_i2c_interface *i2c,
u8 device_id, u8 offset, const u8 *data, unsigned int len)
{
int rc;
/* i2c_fast_write with length 1 is a single byte write */
for (; len > 0; offset++, data++, len--) {
rc = efx_i2c_fast_write(i2c, device_id, offset, data, 1);
if (rc)
return rc;
mdelay(i2c->op->mdelay);
}
return 0;
}
/* This is just a slightly neater wrapper round efx_i2c_fast_write
* in the case where the target doesn't take an offset
*/
int efx_i2c_send_bytes(struct efx_i2c_interface *i2c,
u8 device_id, const u8 *data, unsigned int len)
{
return efx_i2c_fast_write(i2c, device_id, data[0], data + 1, len - 1);
}
/* I2C receiving of bytes - does not send an offset byte */
int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id,
u8 *bytes, unsigned int len)
{
int i;
int rc;
EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
EFX_WARN_ON_PARANOID(len < 1);
/* Select device */
i2c_start(i2c);
/* Read data from device */
rc = i2c_send_byte(i2c, i2c_read_cmd(device_id));
if (rc)
goto out;
for (i = 0; i < (len - 1); i++)
/* Read and acknowledge all but the last byte */
bytes[i] = i2c_recv_byte(i2c, 1);
/* Read last byte with no acknowledgement */
bytes[i] = i2c_recv_byte(i2c, 0);
out:
i2c_stop(i2c);
i2c_release(i2c);
return rc;
}
/* SMBus and some I2C devices will time out if the I2C clock is
* held low for too long. This is most likely to happen in virtualised
* systems (when the entire domain is descheduled) but could in
* principle happen due to preemption on any busy system (and given the
* potential length of an I2C operation turning preemption off is not
* a sensible option). The following functions deal with the failure by
* retrying up to a fixed number of times.
*/
#define I2C_MAX_RETRIES (10)
/* The timeout problem will result in -EIO. If the wrapped function
* returns any other error, pass this up and do not retry. */
#define RETRY_WRAPPER(_f) \
int retries = I2C_MAX_RETRIES; \
int rc; \
while (retries) { \
rc = _f; \
if (rc != -EIO) \
return rc; \
retries--; \
} \
return rc; \
int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c, u8 device_id)
{
RETRY_WRAPPER(efx_i2c_check_presence(i2c, device_id))
}
int efx_i2c_read_retry(struct efx_i2c_interface *i2c,
u8 device_id, u8 offset, u8 *data, unsigned int len)
{
RETRY_WRAPPER(efx_i2c_read(i2c, device_id, offset, data, len))
}
int efx_i2c_write_retry(struct efx_i2c_interface *i2c,
u8 device_id, u8 offset, const u8 *data, unsigned int len)
{
RETRY_WRAPPER(efx_i2c_write(i2c, device_id, offset, data, len))
}

View File

@ -0,0 +1,91 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005 Fen Systems Ltd.
* Copyright 2006 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#ifndef EFX_I2C_DIRECT_H
#define EFX_I2C_DIRECT_H
#include "net_driver.h"
/*
* Direct control of an I2C bus
*/
struct efx_i2c_interface;
/**
* struct efx_i2c_bit_operations - I2C bus direct control methods
*
* I2C bus direct control methods.
*
* @setsda: Set state of SDA line
* @setscl: Set state of SCL line
* @getsda: Get state of SDA line
* @getscl: Get state of SCL line
* @udelay: Delay between each bit operation
* @mdelay: Delay between each byte write
*/
struct efx_i2c_bit_operations {
void (*setsda) (struct efx_i2c_interface *i2c);
void (*setscl) (struct efx_i2c_interface *i2c);
int (*getsda) (struct efx_i2c_interface *i2c);
int (*getscl) (struct efx_i2c_interface *i2c);
unsigned int udelay;
unsigned int mdelay;
};
/**
* struct efx_i2c_interface - an I2C interface
*
* An I2C interface.
*
* @efx: Attached Efx NIC
* @op: I2C bus control methods
* @sda: Current output state of SDA line
* @scl: Current output state of SCL line
*/
struct efx_i2c_interface {
struct efx_nic *efx;
struct efx_i2c_bit_operations *op;
unsigned int sda:1;
unsigned int scl:1;
};
extern int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id);
extern int efx_i2c_fast_read(struct efx_i2c_interface *i2c,
u8 device_id, u8 offset,
u8 *data, unsigned int len);
extern int efx_i2c_fast_write(struct efx_i2c_interface *i2c,
u8 device_id, u8 offset,
const u8 *data, unsigned int len);
extern int efx_i2c_read(struct efx_i2c_interface *i2c,
u8 device_id, u8 offset, u8 *data, unsigned int len);
extern int efx_i2c_write(struct efx_i2c_interface *i2c,
u8 device_id, u8 offset,
const u8 *data, unsigned int len);
extern int efx_i2c_send_bytes(struct efx_i2c_interface *i2c, u8 device_id,
const u8 *bytes, unsigned int len);
extern int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id,
u8 *bytes, unsigned int len);
/* Versions of the API that retry on failure. */
extern int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c,
u8 device_id);
extern int efx_i2c_read_retry(struct efx_i2c_interface *i2c,
u8 device_id, u8 offset, u8 *data, unsigned int len);
extern int efx_i2c_write_retry(struct efx_i2c_interface *i2c,
u8 device_id, u8 offset,
const u8 *data, unsigned int len);
#endif /* EFX_I2C_DIRECT_H */

View File

@ -0,0 +1,33 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2006-2007 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#ifndef EFX_MAC_H
#define EFX_MAC_H
#include "net_driver.h"
extern void falcon_xmac_writel(struct efx_nic *efx,
efx_dword_t *value, unsigned int mac_reg);
extern void falcon_xmac_readl(struct efx_nic *efx,
efx_dword_t *value, unsigned int mac_reg);
extern int falcon_init_xmac(struct efx_nic *efx);
extern void falcon_reconfigure_xmac(struct efx_nic *efx);
extern void falcon_update_stats_xmac(struct efx_nic *efx);
extern void falcon_fini_xmac(struct efx_nic *efx);
extern int falcon_check_xmac(struct efx_nic *efx);
extern void falcon_xmac_sim_phy_event(struct efx_nic *efx);
extern int falcon_xmac_get_settings(struct efx_nic *efx,
struct ethtool_cmd *ecmd);
extern int falcon_xmac_set_settings(struct efx_nic *efx,
struct ethtool_cmd *ecmd);
extern int falcon_xmac_set_pause(struct efx_nic *efx,
enum efx_fc_type pause_params);
#endif

View File

@ -0,0 +1,282 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2006-2008 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
/*
* Useful functions for working with MDIO clause 45 PHYs
*/
#include <linux/types.h>
#include <linux/ethtool.h>
#include <linux/delay.h>
#include "net_driver.h"
#include "mdio_10g.h"
#include "boards.h"
int mdio_clause45_reset_mmd(struct efx_nic *port, int mmd,
int spins, int spintime)
{
u32 ctrl;
int phy_id = port->mii.phy_id;
/* Catch callers passing values in the wrong units (or just silly) */
EFX_BUG_ON_PARANOID(spins * spintime >= 5000);
mdio_clause45_write(port, phy_id, mmd, MDIO_MMDREG_CTRL1,
(1 << MDIO_MMDREG_CTRL1_RESET_LBN));
/* Wait for the reset bit to clear. */
do {
msleep(spintime);
ctrl = mdio_clause45_read(port, phy_id, mmd, MDIO_MMDREG_CTRL1);
spins--;
} while (spins && (ctrl & (1 << MDIO_MMDREG_CTRL1_RESET_LBN)));
return spins ? spins : -ETIMEDOUT;
}
static int mdio_clause45_check_mmd(struct efx_nic *efx, int mmd,
int fault_fatal)
{
int status;
int phy_id = efx->mii.phy_id;
/* Read MMD STATUS2 to check it is responding. */
status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT2);
if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) &
((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) !=
MDIO_MMDREG_STAT2_PRESENT_VAL) {
EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd);
return -EIO;
}
/* Read MMD STATUS 1 to check for fault. */
status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT1);
if ((status & (1 << MDIO_MMDREG_STAT1_FAULT_LBN)) != 0) {
if (fault_fatal) {
EFX_ERR(efx, "PHY MMD %d reporting fatal"
" fault: status %x\n", mmd, status);
return -EIO;
} else {
EFX_LOG(efx, "PHY MMD %d reporting status"
" %x (expected)\n", mmd, status);
}
}
return 0;
}
/* This ought to be ridiculous overkill. We expect it to fail rarely */
#define MDIO45_RESET_TIME 1000 /* ms */
#define MDIO45_RESET_ITERS 100
int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
unsigned int mmd_mask)
{
const int spintime = MDIO45_RESET_TIME / MDIO45_RESET_ITERS;
int tries = MDIO45_RESET_ITERS;
int rc = 0;
int in_reset;
while (tries) {
int mask = mmd_mask;
int mmd = 0;
int stat;
in_reset = 0;
while (mask) {
if (mask & 1) {
stat = mdio_clause45_read(efx,
efx->mii.phy_id,
mmd,
MDIO_MMDREG_CTRL1);
if (stat < 0) {
EFX_ERR(efx, "failed to read status of"
" MMD %d\n", mmd);
return -EIO;
}
if (stat & (1 << MDIO_MMDREG_CTRL1_RESET_LBN))
in_reset |= (1 << mmd);
}
mask = mask >> 1;
mmd++;
}
if (!in_reset)
break;
tries--;
msleep(spintime);
}
if (in_reset != 0) {
EFX_ERR(efx, "not all MMDs came out of reset in time."
" MMDs still in reset: %x\n", in_reset);
rc = -ETIMEDOUT;
}
return rc;
}
int mdio_clause45_check_mmds(struct efx_nic *efx,
unsigned int mmd_mask, unsigned int fatal_mask)
{
int devices, mmd = 0;
int probe_mmd;
/* Historically we have probed the PHYXS to find out what devices are
* present,but that doesn't work so well if the PHYXS isn't expected
* to exist, if so just find the first item in the list supplied. */
probe_mmd = (mmd_mask & MDIO_MMDREG_DEVS0_PHYXS) ? MDIO_MMD_PHYXS :
__ffs(mmd_mask);
devices = mdio_clause45_read(efx, efx->mii.phy_id,
probe_mmd, MDIO_MMDREG_DEVS0);
/* Check all the expected MMDs are present */
if (devices < 0) {
EFX_ERR(efx, "failed to read devices present\n");
return -EIO;
}
if ((devices & mmd_mask) != mmd_mask) {
EFX_ERR(efx, "required MMDs not present: got %x, "
"wanted %x\n", devices, mmd_mask);
return -ENODEV;
}
EFX_TRACE(efx, "Devices present: %x\n", devices);
/* Check all required MMDs are responding and happy. */
while (mmd_mask) {
if (mmd_mask & 1) {
int fault_fatal = fatal_mask & 1;
if (mdio_clause45_check_mmd(efx, mmd, fault_fatal))
return -EIO;
}
mmd_mask = mmd_mask >> 1;
fatal_mask = fatal_mask >> 1;
mmd++;
}
return 0;
}
int mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask)
{
int phy_id = efx->mii.phy_id;
int status;
int ok = 1;
int mmd = 0;
int good;
while (mmd_mask) {
if (mmd_mask & 1) {
/* Double reads because link state is latched, and a
* read moves the current state into the register */
status = mdio_clause45_read(efx, phy_id,
mmd, MDIO_MMDREG_STAT1);
status = mdio_clause45_read(efx, phy_id,
mmd, MDIO_MMDREG_STAT1);
good = status & (1 << MDIO_MMDREG_STAT1_LINK_LBN);
ok = ok && good;
}
mmd_mask = (mmd_mask >> 1);
mmd++;
}
return ok;
}
/**
* mdio_clause45_get_settings - Read (some of) the PHY settings over MDIO.
* @efx: Efx NIC
* @ecmd: Buffer for settings
*
* On return the 'port', 'speed', 'supported' and 'advertising' fields of
* ecmd have been filled out based on the PMA type.
*/
void mdio_clause45_get_settings(struct efx_nic *efx,
struct ethtool_cmd *ecmd)
{
int pma_type;
/* If no PMA is present we are presumably talking something XAUI-ish
* like CX4. Which we report as FIBRE (see below) */
if ((efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)) == 0) {
ecmd->speed = SPEED_10000;
ecmd->port = PORT_FIBRE;
ecmd->supported = SUPPORTED_FIBRE;
ecmd->advertising = ADVERTISED_FIBRE;
return;
}
pma_type = mdio_clause45_read(efx, efx->mii.phy_id,
MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL2);
pma_type &= MDIO_PMAPMD_CTRL2_TYPE_MASK;
switch (pma_type) {
/* We represent CX4 as fibre in the absence of anything
better. */
case MDIO_PMAPMD_CTRL2_10G_CX4:
ecmd->speed = SPEED_10000;
ecmd->port = PORT_FIBRE;
ecmd->supported = SUPPORTED_FIBRE;
ecmd->advertising = ADVERTISED_FIBRE;
break;
/* 10G Base-T */
case MDIO_PMAPMD_CTRL2_10G_BT:
ecmd->speed = SPEED_10000;
ecmd->port = PORT_TP;
ecmd->supported = SUPPORTED_TP | SUPPORTED_10000baseT_Full;
ecmd->advertising = (ADVERTISED_FIBRE
| ADVERTISED_10000baseT_Full);
break;
case MDIO_PMAPMD_CTRL2_1G_BT:
ecmd->speed = SPEED_1000;
ecmd->port = PORT_TP;
ecmd->supported = SUPPORTED_TP | SUPPORTED_1000baseT_Full;
ecmd->advertising = (ADVERTISED_FIBRE
| ADVERTISED_1000baseT_Full);
break;
case MDIO_PMAPMD_CTRL2_100_BT:
ecmd->speed = SPEED_100;
ecmd->port = PORT_TP;
ecmd->supported = SUPPORTED_TP | SUPPORTED_100baseT_Full;
ecmd->advertising = (ADVERTISED_FIBRE
| ADVERTISED_100baseT_Full);
break;
case MDIO_PMAPMD_CTRL2_10_BT:
ecmd->speed = SPEED_10;
ecmd->port = PORT_TP;
ecmd->supported = SUPPORTED_TP | SUPPORTED_10baseT_Full;
ecmd->advertising = ADVERTISED_FIBRE | ADVERTISED_10baseT_Full;
break;
/* All the other defined modes are flavours of
* 10G optical */
default:
ecmd->speed = SPEED_10000;
ecmd->port = PORT_FIBRE;
ecmd->supported = SUPPORTED_FIBRE;
ecmd->advertising = ADVERTISED_FIBRE;
break;
}
}
/**
* mdio_clause45_set_settings - Set (some of) the PHY settings over MDIO.
* @efx: Efx NIC
* @ecmd: New settings
*
* Currently this just enforces that we are _not_ changing the
* 'port', 'speed', 'supported' or 'advertising' settings as these
* cannot be changed on any currently supported PHY.
*/
int mdio_clause45_set_settings(struct efx_nic *efx,
struct ethtool_cmd *ecmd)
{
struct ethtool_cmd tmpcmd;
mdio_clause45_get_settings(efx, &tmpcmd);
/* None of the current PHYs support more than one mode
* of operation (and only 10GBT ever will), so keep things
* simple for now */
if ((ecmd->speed == tmpcmd.speed) && (ecmd->port == tmpcmd.port) &&
(ecmd->supported == tmpcmd.supported) &&
(ecmd->advertising == tmpcmd.advertising))
return 0;
return -EOPNOTSUPP;
}

View File

@ -0,0 +1,232 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2006-2008 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#ifndef EFX_MDIO_10G_H
#define EFX_MDIO_10G_H
/*
* Definitions needed for doing 10G MDIO as specified in clause 45
* MDIO, which do not appear in Linux yet. Also some helper functions.
*/
#include "efx.h"
#include "boards.h"
/* Numbering of the MDIO Manageable Devices (MMDs) */
/* Physical Medium Attachment/ Physical Medium Dependent sublayer */
#define MDIO_MMD_PMAPMD (1)
/* WAN Interface Sublayer */
#define MDIO_MMD_WIS (2)
/* Physical Coding Sublayer */
#define MDIO_MMD_PCS (3)
/* PHY Extender Sublayer */
#define MDIO_MMD_PHYXS (4)
/* Extender Sublayer */
#define MDIO_MMD_DTEXS (5)
/* Transmission convergence */
#define MDIO_MMD_TC (6)
/* Auto negotiation */
#define MDIO_MMD_AN (7)
/* Generic register locations */
#define MDIO_MMDREG_CTRL1 (0)
#define MDIO_MMDREG_STAT1 (1)
#define MDIO_MMDREG_IDHI (2)
#define MDIO_MMDREG_IDLOW (3)
#define MDIO_MMDREG_SPEED (4)
#define MDIO_MMDREG_DEVS0 (5)
#define MDIO_MMDREG_DEVS1 (6)
#define MDIO_MMDREG_CTRL2 (7)
#define MDIO_MMDREG_STAT2 (8)
/* Bits in MMDREG_CTRL1 */
/* Reset */
#define MDIO_MMDREG_CTRL1_RESET_LBN (15)
#define MDIO_MMDREG_CTRL1_RESET_WIDTH (1)
/* Bits in MMDREG_STAT1 */
#define MDIO_MMDREG_STAT1_FAULT_LBN (7)
#define MDIO_MMDREG_STAT1_FAULT_WIDTH (1)
/* Link state */
#define MDIO_MMDREG_STAT1_LINK_LBN (2)
#define MDIO_MMDREG_STAT1_LINK_WIDTH (1)
/* Bits in ID reg */
#define MDIO_ID_REV(_id32) (_id32 & 0xf)
#define MDIO_ID_MODEL(_id32) ((_id32 >> 4) & 0x3f)
#define MDIO_ID_OUI(_id32) (_id32 >> 10)
/* Bits in MMDREG_DEVS0. Someone thoughtfully layed things out
* so the 'bit present' bit number of an MMD is the number of
* that MMD */
#define DEV_PRESENT_BIT(_b) (1 << _b)
#define MDIO_MMDREG_DEVS0_PHYXS DEV_PRESENT_BIT(MDIO_MMD_PHYXS)
#define MDIO_MMDREG_DEVS0_PCS DEV_PRESENT_BIT(MDIO_MMD_PCS)
#define MDIO_MMDREG_DEVS0_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)
/* Bits in MMDREG_STAT2 */
#define MDIO_MMDREG_STAT2_PRESENT_VAL (2)
#define MDIO_MMDREG_STAT2_PRESENT_LBN (14)
#define MDIO_MMDREG_STAT2_PRESENT_WIDTH (2)
/* PMA type (4 bits) */
#define MDIO_PMAPMD_CTRL2_10G_CX4 (0x0)
#define MDIO_PMAPMD_CTRL2_10G_EW (0x1)
#define MDIO_PMAPMD_CTRL2_10G_LW (0x2)
#define MDIO_PMAPMD_CTRL2_10G_SW (0x3)
#define MDIO_PMAPMD_CTRL2_10G_LX4 (0x4)
#define MDIO_PMAPMD_CTRL2_10G_ER (0x5)
#define MDIO_PMAPMD_CTRL2_10G_LR (0x6)
#define MDIO_PMAPMD_CTRL2_10G_SR (0x7)
/* Reserved */
#define MDIO_PMAPMD_CTRL2_10G_BT (0x9)
/* Reserved */
/* Reserved */
#define MDIO_PMAPMD_CTRL2_1G_BT (0xc)
/* Reserved */
#define MDIO_PMAPMD_CTRL2_100_BT (0xe)
#define MDIO_PMAPMD_CTRL2_10_BT (0xf)
#define MDIO_PMAPMD_CTRL2_TYPE_MASK (0xf)
/* /\* PHY XGXS lane state *\/ */
#define MDIO_PHYXS_LANE_STATE (0x18)
#define MDIO_PHYXS_LANE_ALIGNED_LBN (12)
/* AN registers */
#define MDIO_AN_STATUS (1)
#define MDIO_AN_STATUS_XNP_LBN (7)
#define MDIO_AN_STATUS_PAGE_LBN (6)
#define MDIO_AN_STATUS_AN_DONE_LBN (5)
#define MDIO_AN_STATUS_LP_AN_CAP_LBN (0)
#define MDIO_AN_10GBT_STATUS (33)
#define MDIO_AN_10GBT_STATUS_MS_FLT_LBN (15) /* MASTER/SLAVE config fault */
#define MDIO_AN_10GBT_STATUS_MS_LBN (14) /* MASTER/SLAVE config */
#define MDIO_AN_10GBT_STATUS_LOC_OK_LBN (13) /* Local OK */
#define MDIO_AN_10GBT_STATUS_REM_OK_LBN (12) /* Remote OK */
#define MDIO_AN_10GBT_STATUS_LP_10G_LBN (11) /* Link partner is 10GBT capable */
#define MDIO_AN_10GBT_STATUS_LP_LTA_LBN (10) /* LP loop timing ability */
#define MDIO_AN_10GBT_STATUS_LP_TRR_LBN (9) /* LP Training Reset Request */
/* Packing of the prt and dev arguments of clause 45 style MDIO into a
* single int so they can be passed into the mdio_read/write functions
* that currently exist. Note that as Falcon is the only current user,
* the packed form is chosen to match what Falcon needs to write into
* a register. This is checked at compile-time so do not change it. If
* your target chip needs things layed out differently you will need
* to unpack the arguments in your chip-specific mdio functions.
*/
/* These are defined by the standard. */
#define MDIO45_PRT_ID_WIDTH (5)
#define MDIO45_DEV_ID_WIDTH (5)
/* The prt ID is just packed in immediately to the left of the dev ID */
#define MDIO45_PRT_DEV_WIDTH (MDIO45_PRT_ID_WIDTH + MDIO45_DEV_ID_WIDTH)
#define MDIO45_PRT_ID_MASK ((1 << MDIO45_PRT_DEV_WIDTH) - 1)
/* This is the prt + dev extended by 1 bit to hold the 'is clause 45' flag. */
#define MDIO45_XPRT_ID_WIDTH (MDIO45_PRT_DEV_WIDTH + 1)
#define MDIO45_XPRT_ID_MASK ((1 << MDIO45_XPRT_ID_WIDTH) - 1)
#define MDIO45_XPRT_ID_IS10G (1 << (MDIO45_XPRT_ID_WIDTH - 1))
#define MDIO45_PRT_ID_COMP_LBN MDIO45_DEV_ID_WIDTH
#define MDIO45_PRT_ID_COMP_WIDTH MDIO45_PRT_ID_WIDTH
#define MDIO45_DEV_ID_COMP_LBN 0
#define MDIO45_DEV_ID_COMP_WIDTH MDIO45_DEV_ID_WIDTH
/* Compose port and device into a phy_id */
static inline int mdio_clause45_pack(u8 prt, u8 dev)
{
efx_dword_t phy_id;
EFX_POPULATE_DWORD_2(phy_id, MDIO45_PRT_ID_COMP, prt,
MDIO45_DEV_ID_COMP, dev);
return MDIO45_XPRT_ID_IS10G | EFX_DWORD_VAL(phy_id);
}
static inline void mdio_clause45_unpack(u32 val, u8 *prt, u8 *dev)
{
efx_dword_t phy_id;
EFX_POPULATE_DWORD_1(phy_id, EFX_DWORD_0, val);
*prt = EFX_DWORD_FIELD(phy_id, MDIO45_PRT_ID_COMP);
*dev = EFX_DWORD_FIELD(phy_id, MDIO45_DEV_ID_COMP);
}
static inline int mdio_clause45_read(struct efx_nic *efx,
u8 prt, u8 dev, u16 addr)
{
return efx->mii.mdio_read(efx->net_dev,
mdio_clause45_pack(prt, dev), addr);
}
static inline void mdio_clause45_write(struct efx_nic *efx,
u8 prt, u8 dev, u16 addr, int value)
{
efx->mii.mdio_write(efx->net_dev,
mdio_clause45_pack(prt, dev), addr, value);
}
static inline u32 mdio_clause45_read_id(struct efx_nic *efx, int mmd)
{
int phy_id = efx->mii.phy_id;
u16 id_low = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_IDLOW);
u16 id_hi = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_IDHI);
return (id_hi << 16) | (id_low);
}
static inline int mdio_clause45_phyxgxs_lane_sync(struct efx_nic *efx)
{
int i, sync, lane_status;
for (i = 0; i < 2; ++i)
lane_status = mdio_clause45_read(efx, efx->mii.phy_id,
MDIO_MMD_PHYXS,
MDIO_PHYXS_LANE_STATE);
sync = (lane_status & (1 << MDIO_PHYXS_LANE_ALIGNED_LBN)) != 0;
if (!sync)
EFX_INFO(efx, "XGXS lane status: %x\n", lane_status);
return sync;
}
extern const char *mdio_clause45_mmd_name(int mmd);
/*
* Reset a specific MMD and wait for reset to clear.
* Return number of spins left (>0) on success, -%ETIMEDOUT on failure.
*
* This function will sleep
*/
extern int mdio_clause45_reset_mmd(struct efx_nic *efx, int mmd,
int spins, int spintime);
/* As mdio_clause45_check_mmd but for multiple MMDs */
int mdio_clause45_check_mmds(struct efx_nic *efx,
unsigned int mmd_mask, unsigned int fatal_mask);
/* Check the link status of specified mmds in bit mask */
extern int mdio_clause45_links_ok(struct efx_nic *efx,
unsigned int mmd_mask);
/* Read (some of) the PHY settings over MDIO */
extern void mdio_clause45_get_settings(struct efx_nic *efx,
struct ethtool_cmd *ecmd);
/* Set (some of) the PHY settings over MDIO */
extern int mdio_clause45_set_settings(struct efx_nic *efx,
struct ethtool_cmd *ecmd);
/* Wait for specified MMDs to exit reset within a timeout */
extern int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
unsigned int mmd_mask);
#endif /* EFX_MDIO_10G_H */

View File

@ -0,0 +1,883 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2005-2008 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
/* Common definitions for all Efx net driver code */
#ifndef EFX_NET_DRIVER_H
#define EFX_NET_DRIVER_H
#include <linux/version.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
#include <linux/timer.h>
#include <linux/mii.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/device.h>
#include <linux/highmem.h>
#include <linux/workqueue.h>
#include <linux/inet_lro.h>
#include "enum.h"
#include "bitfield.h"
#include "i2c-direct.h"
#define EFX_MAX_LRO_DESCRIPTORS 8
#define EFX_MAX_LRO_AGGR MAX_SKB_FRAGS
/**************************************************************************
*
* Build definitions
*
**************************************************************************/
#ifndef EFX_DRIVER_NAME
#define EFX_DRIVER_NAME "sfc"
#endif
#define EFX_DRIVER_VERSION "2.2.0136"
#ifdef EFX_ENABLE_DEBUG
#define EFX_BUG_ON_PARANOID(x) BUG_ON(x)
#define EFX_WARN_ON_PARANOID(x) WARN_ON(x)
#else
#define EFX_BUG_ON_PARANOID(x) do {} while (0)
#define EFX_WARN_ON_PARANOID(x) do {} while (0)
#endif
#define NET_DEV_REGISTERED(efx) \
((efx)->net_dev->reg_state == NETREG_REGISTERED)
/* Include net device name in log messages if it has been registered.
* Use efx->name not efx->net_dev->name so that races with (un)registration
* are harmless.
*/
#define NET_DEV_NAME(efx) (NET_DEV_REGISTERED(efx) ? (efx)->name : "")
/* Un-rate-limited logging */
#define EFX_ERR(efx, fmt, args...) \
dev_err(&((efx)->pci_dev->dev), "ERR: %s " fmt, NET_DEV_NAME(efx), ##args)
#define EFX_INFO(efx, fmt, args...) \
dev_info(&((efx)->pci_dev->dev), "INFO: %s " fmt, NET_DEV_NAME(efx), ##args)
#ifdef EFX_ENABLE_DEBUG
#define EFX_LOG(efx, fmt, args...) \
dev_info(&((efx)->pci_dev->dev), "DBG: %s " fmt, NET_DEV_NAME(efx), ##args)
#else
#define EFX_LOG(efx, fmt, args...) \
dev_dbg(&((efx)->pci_dev->dev), "DBG: %s " fmt, NET_DEV_NAME(efx), ##args)
#endif
#define EFX_TRACE(efx, fmt, args...) do {} while (0)
#define EFX_REGDUMP(efx, fmt, args...) do {} while (0)
/* Rate-limited logging */
#define EFX_ERR_RL(efx, fmt, args...) \
do {if (net_ratelimit()) EFX_ERR(efx, fmt, ##args); } while (0)
#define EFX_INFO_RL(efx, fmt, args...) \
do {if (net_ratelimit()) EFX_INFO(efx, fmt, ##args); } while (0)
#define EFX_LOG_RL(efx, fmt, args...) \
do {if (net_ratelimit()) EFX_LOG(efx, fmt, ##args); } while (0)
/* Kernel headers may redefine inline anyway */
#ifndef inline
#define inline inline __attribute__ ((always_inline))
#endif
/**************************************************************************
*
* Efx data structures
*
**************************************************************************/
#define EFX_MAX_CHANNELS 32
#define EFX_MAX_TX_QUEUES 1
#define EFX_MAX_RX_QUEUES EFX_MAX_CHANNELS
/**
* struct efx_special_buffer - An Efx special buffer
* @addr: CPU base address of the buffer
* @dma_addr: DMA base address of the buffer
* @len: Buffer length, in bytes
* @index: Buffer index within controller;s buffer table
* @entries: Number of buffer table entries
*
* Special buffers are used for the event queues and the TX and RX
* descriptor queues for each channel. They are *not* used for the
* actual transmit and receive buffers.
*
* Note that for Falcon, TX and RX descriptor queues live in host memory.
* Allocation and freeing procedures must take this into account.
*/
struct efx_special_buffer {
void *addr;
dma_addr_t dma_addr;
unsigned int len;
int index;
int entries;
};
/**
* struct efx_tx_buffer - An Efx TX buffer
* @skb: The associated socket buffer.
* Set only on the final fragment of a packet; %NULL for all other
* fragments. When this fragment completes, then we can free this
* skb.
* @dma_addr: DMA address of the fragment.
* @len: Length of this fragment.
* This field is zero when the queue slot is empty.
* @continuation: True if this fragment is not the end of a packet.
* @unmap_single: True if pci_unmap_single should be used.
* @unmap_addr: DMA address to unmap
* @unmap_len: Length of this fragment to unmap
*/
struct efx_tx_buffer {
const struct sk_buff *skb;
dma_addr_t dma_addr;
unsigned short len;
unsigned char continuation;
unsigned char unmap_single;
dma_addr_t unmap_addr;
unsigned short unmap_len;
};
/**
* struct efx_tx_queue - An Efx TX queue
*
* This is a ring buffer of TX fragments.
* Since the TX completion path always executes on the same
* CPU and the xmit path can operate on different CPUs,
* performance is increased by ensuring that the completion
* path and the xmit path operate on different cache lines.
* This is particularly important if the xmit path is always
* executing on one CPU which is different from the completion
* path. There is also a cache line for members which are
* read but not written on the fast path.
*
* @efx: The associated Efx NIC
* @queue: DMA queue number
* @used: Queue is used by net driver
* @channel: The associated channel
* @buffer: The software buffer ring
* @txd: The hardware descriptor ring
* @read_count: Current read pointer.
* This is the number of buffers that have been removed from both rings.
* @stopped: Stopped flag.
* Set if this TX queue is currently stopping its port.
* @insert_count: Current insert pointer
* This is the number of buffers that have been added to the
* software ring.
* @write_count: Current write pointer
* This is the number of buffers that have been added to the
* hardware ring.
* @old_read_count: The value of read_count when last checked.
* This is here for performance reasons. The xmit path will
* only get the up-to-date value of read_count if this
* variable indicates that the queue is full. This is to
* avoid cache-line ping-pong between the xmit path and the
* completion path.
*/
struct efx_tx_queue {
/* Members which don't change on the fast path */
struct efx_nic *efx ____cacheline_aligned_in_smp;
int queue;
int used;
struct efx_channel *channel;
struct efx_nic *nic;
struct efx_tx_buffer *buffer;
struct efx_special_buffer txd;
/* Members used mainly on the completion path */
unsigned int read_count ____cacheline_aligned_in_smp;
int stopped;
/* Members used only on the xmit path */
unsigned int insert_count ____cacheline_aligned_in_smp;
unsigned int write_count;
unsigned int old_read_count;
};
/**
* struct efx_rx_buffer - An Efx RX data buffer
* @dma_addr: DMA base address of the buffer
* @skb: The associated socket buffer, if any.
* If both this and page are %NULL, the buffer slot is currently free.
* @page: The associated page buffer, if any.
* If both this and skb are %NULL, the buffer slot is currently free.
* @data: Pointer to ethernet header
* @len: Buffer length, in bytes.
* @unmap_addr: DMA address to unmap
*/
struct efx_rx_buffer {
dma_addr_t dma_addr;
struct sk_buff *skb;
struct page *page;
char *data;
unsigned int len;
dma_addr_t unmap_addr;
};
/**
* struct efx_rx_queue - An Efx RX queue
* @efx: The associated Efx NIC
* @queue: DMA queue number
* @used: Queue is used by net driver
* @channel: The associated channel
* @buffer: The software buffer ring
* @rxd: The hardware descriptor ring
* @added_count: Number of buffers added to the receive queue.
* @notified_count: Number of buffers given to NIC (<= @added_count).
* @removed_count: Number of buffers removed from the receive queue.
* @add_lock: Receive queue descriptor add spin lock.
* This lock must be held in order to add buffers to the RX
* descriptor ring (rxd and buffer) and to update added_count (but
* not removed_count).
* @max_fill: RX descriptor maximum fill level (<= ring size)
* @fast_fill_trigger: RX descriptor fill level that will trigger a fast fill
* (<= @max_fill)
* @fast_fill_limit: The level to which a fast fill will fill
* (@fast_fill_trigger <= @fast_fill_limit <= @max_fill)
* @min_fill: RX descriptor minimum non-zero fill level.
* This records the minimum fill level observed when a ring
* refill was triggered.
* @min_overfill: RX descriptor minimum overflow fill level.
* This records the minimum fill level at which RX queue
* overflow was observed. It should never be set.
* @alloc_page_count: RX allocation strategy counter.
* @alloc_skb_count: RX allocation strategy counter.
* @work: Descriptor push work thread
* @buf_page: Page for next RX buffer.
* We can use a single page for multiple RX buffers. This tracks
* the remaining space in the allocation.
* @buf_dma_addr: Page's DMA address.
* @buf_data: Page's host address.
*/
struct efx_rx_queue {
struct efx_nic *efx;
int queue;
int used;
struct efx_channel *channel;
struct efx_rx_buffer *buffer;
struct efx_special_buffer rxd;
int added_count;
int notified_count;
int removed_count;
spinlock_t add_lock;
unsigned int max_fill;
unsigned int fast_fill_trigger;
unsigned int fast_fill_limit;
unsigned int min_fill;
unsigned int min_overfill;
unsigned int alloc_page_count;
unsigned int alloc_skb_count;
struct delayed_work work;
unsigned int slow_fill_count;
struct page *buf_page;
dma_addr_t buf_dma_addr;
char *buf_data;
};
/**
* struct efx_buffer - An Efx general-purpose buffer
* @addr: host base address of the buffer
* @dma_addr: DMA base address of the buffer
* @len: Buffer length, in bytes
*
* Falcon uses these buffers for its interrupt status registers and
* MAC stats dumps.
*/
struct efx_buffer {
void *addr;
dma_addr_t dma_addr;
unsigned int len;
};
/* Flags for channel->used_flags */
#define EFX_USED_BY_RX 1
#define EFX_USED_BY_TX 2
#define EFX_USED_BY_RX_TX (EFX_USED_BY_RX | EFX_USED_BY_TX)
enum efx_rx_alloc_method {
RX_ALLOC_METHOD_AUTO = 0,
RX_ALLOC_METHOD_SKB = 1,
RX_ALLOC_METHOD_PAGE = 2,
};
/**
* struct efx_channel - An Efx channel
*
* A channel comprises an event queue, at least one TX queue, at least
* one RX queue, and an associated tasklet for processing the event
* queue.
*
* @efx: Associated Efx NIC
* @evqnum: Event queue number
* @channel: Channel instance number
* @used_flags: Channel is used by net driver
* @enabled: Channel enabled indicator
* @irq: IRQ number (MSI and MSI-X only)
* @has_interrupt: Channel has an interrupt
* @irq_moderation: IRQ moderation value (in us)
* @napi_dev: Net device used with NAPI
* @napi_str: NAPI control structure
* @reset_work: Scheduled reset work thread
* @work_pending: Is work pending via NAPI?
* @eventq: Event queue buffer
* @eventq_read_ptr: Event queue read pointer
* @last_eventq_read_ptr: Last event queue read pointer value.
* @eventq_magic: Event queue magic value for driver-generated test events
* @lro_mgr: LRO state
* @rx_alloc_level: Watermark based heuristic counter for pushing descriptors
* and diagnostic counters
* @rx_alloc_push_pages: RX allocation method currently in use for pushing
* descriptors
* @rx_alloc_pop_pages: RX allocation method currently in use for popping
* descriptors
* @n_rx_tobe_disc: Count of RX_TOBE_DISC errors
* @n_rx_ip_frag_err: Count of RX IP fragment errors
* @n_rx_ip_hdr_chksum_err: Count of RX IP header checksum errors
* @n_rx_tcp_udp_chksum_err: Count of RX TCP and UDP checksum errors
* @n_rx_frm_trunc: Count of RX_FRM_TRUNC errors
* @n_rx_overlength: Count of RX_OVERLENGTH errors
* @n_skbuff_leaks: Count of skbuffs leaked due to RX overrun
*/
struct efx_channel {
struct efx_nic *efx;
int evqnum;
int channel;
int used_flags;
int enabled;
int irq;
unsigned int has_interrupt;
unsigned int irq_moderation;
struct net_device *napi_dev;
struct napi_struct napi_str;
struct work_struct reset_work;
int work_pending;
struct efx_special_buffer eventq;
unsigned int eventq_read_ptr;
unsigned int last_eventq_read_ptr;
unsigned int eventq_magic;
struct net_lro_mgr lro_mgr;
int rx_alloc_level;
int rx_alloc_push_pages;
int rx_alloc_pop_pages;
unsigned n_rx_tobe_disc;
unsigned n_rx_ip_frag_err;
unsigned n_rx_ip_hdr_chksum_err;
unsigned n_rx_tcp_udp_chksum_err;
unsigned n_rx_frm_trunc;
unsigned n_rx_overlength;
unsigned n_skbuff_leaks;
/* Used to pipeline received packets in order to optimise memory
* access with prefetches.
*/
struct efx_rx_buffer *rx_pkt;
int rx_pkt_csummed;
};
/**
* struct efx_blinker - S/W LED blinking context
* @led_num: LED ID (board-specific meaning)
* @state: Current state - on or off
* @resubmit: Timer resubmission flag
* @timer: Control timer for blinking
*/
struct efx_blinker {
int led_num;
int state;
int resubmit;
struct timer_list timer;
};
/**
* struct efx_board - board information
* @type: Board model type
* @major: Major rev. ('A', 'B' ...)
* @minor: Minor rev. (0, 1, ...)
* @init: Initialisation function
* @init_leds: Sets up board LEDs
* @set_fault_led: Turns the fault LED on or off
* @blink: Starts/stops blinking
* @blinker: used to blink LEDs in software
*/
struct efx_board {
int type;
int major;
int minor;
int (*init) (struct efx_nic *nic);
/* As the LEDs are typically attached to the PHY, LEDs
* have a separate init callback that happens later than
* board init. */
int (*init_leds)(struct efx_nic *efx);
void (*set_fault_led) (struct efx_nic *efx, int state);
void (*blink) (struct efx_nic *efx, int start);
struct efx_blinker blinker;
};
enum efx_int_mode {
/* Be careful if altering to correct macro below */
EFX_INT_MODE_MSIX = 0,
EFX_INT_MODE_MSI = 1,
EFX_INT_MODE_LEGACY = 2,
EFX_INT_MODE_MAX /* Insert any new items before this */
};
#define EFX_INT_MODE_USE_MSI(x) (((x)->interrupt_mode) <= EFX_INT_MODE_MSI)
enum phy_type {
PHY_TYPE_NONE = 0,
PHY_TYPE_CX4_RTMR = 1,
PHY_TYPE_1G_ALASKA = 2,
PHY_TYPE_10XPRESS = 3,
PHY_TYPE_XFP = 4,
PHY_TYPE_PM8358 = 6,
PHY_TYPE_MAX /* Insert any new items before this */
};
#define PHY_ADDR_INVALID 0xff
enum nic_state {
STATE_INIT = 0,
STATE_RUNNING = 1,
STATE_FINI = 2,
STATE_RESETTING = 3, /* rtnl_lock always held */
STATE_DISABLED = 4,
STATE_MAX,
};
/*
* Alignment of page-allocated RX buffers
*
* Controls the number of bytes inserted at the start of an RX buffer.
* This is the equivalent of NET_IP_ALIGN [which controls the alignment
* of the skb->head for hardware DMA].
*/
#if defined(__i386__) || defined(__x86_64__)
#define EFX_PAGE_IP_ALIGN 0
#else
#define EFX_PAGE_IP_ALIGN NET_IP_ALIGN
#endif
/*
* Alignment of the skb->head which wraps a page-allocated RX buffer
*
* The skb allocated to wrap an rx_buffer can have this alignment. Since
* the data is memcpy'd from the rx_buf, it does not need to be equal to
* EFX_PAGE_IP_ALIGN.
*/
#define EFX_PAGE_SKB_ALIGN 2
/* Forward declaration */
struct efx_nic;
/* Pseudo bit-mask flow control field */
enum efx_fc_type {
EFX_FC_RX = 1,
EFX_FC_TX = 2,
EFX_FC_AUTO = 4,
};
/**
* struct efx_phy_operations - Efx PHY operations table
* @init: Initialise PHY
* @fini: Shut down PHY
* @reconfigure: Reconfigure PHY (e.g. for new link parameters)
* @clear_interrupt: Clear down interrupt
* @blink: Blink LEDs
* @check_hw: Check hardware
* @reset_xaui: Reset XAUI side of PHY for (software sequenced reset)
* @mmds: MMD presence mask
*/
struct efx_phy_operations {
int (*init) (struct efx_nic *efx);
void (*fini) (struct efx_nic *efx);
void (*reconfigure) (struct efx_nic *efx);
void (*clear_interrupt) (struct efx_nic *efx);
int (*check_hw) (struct efx_nic *efx);
void (*reset_xaui) (struct efx_nic *efx);
int mmds;
};
/*
* Efx extended statistics
*
* Not all statistics are provided by all supported MACs. The purpose
* is this structure is to contain the raw statistics provided by each
* MAC.
*/
struct efx_mac_stats {
u64 tx_bytes;
u64 tx_good_bytes;
u64 tx_bad_bytes;
unsigned long tx_packets;
unsigned long tx_bad;
unsigned long tx_pause;
unsigned long tx_control;
unsigned long tx_unicast;
unsigned long tx_multicast;
unsigned long tx_broadcast;
unsigned long tx_lt64;
unsigned long tx_64;
unsigned long tx_65_to_127;
unsigned long tx_128_to_255;
unsigned long tx_256_to_511;
unsigned long tx_512_to_1023;
unsigned long tx_1024_to_15xx;
unsigned long tx_15xx_to_jumbo;
unsigned long tx_gtjumbo;
unsigned long tx_collision;
unsigned long tx_single_collision;
unsigned long tx_multiple_collision;
unsigned long tx_excessive_collision;
unsigned long tx_deferred;
unsigned long tx_late_collision;
unsigned long tx_excessive_deferred;
unsigned long tx_non_tcpudp;
unsigned long tx_mac_src_error;
unsigned long tx_ip_src_error;
u64 rx_bytes;
u64 rx_good_bytes;
u64 rx_bad_bytes;
unsigned long rx_packets;
unsigned long rx_good;
unsigned long rx_bad;
unsigned long rx_pause;
unsigned long rx_control;
unsigned long rx_unicast;
unsigned long rx_multicast;
unsigned long rx_broadcast;
unsigned long rx_lt64;
unsigned long rx_64;
unsigned long rx_65_to_127;
unsigned long rx_128_to_255;
unsigned long rx_256_to_511;
unsigned long rx_512_to_1023;
unsigned long rx_1024_to_15xx;
unsigned long rx_15xx_to_jumbo;
unsigned long rx_gtjumbo;
unsigned long rx_bad_lt64;
unsigned long rx_bad_64_to_15xx;
unsigned long rx_bad_15xx_to_jumbo;
unsigned long rx_bad_gtjumbo;
unsigned long rx_overflow;
unsigned long rx_missed;
unsigned long rx_false_carrier;
unsigned long rx_symbol_error;
unsigned long rx_align_error;
unsigned long rx_length_error;
unsigned long rx_internal_error;
unsigned long rx_good_lt64;
};
/* Number of bits used in a multicast filter hash address */
#define EFX_MCAST_HASH_BITS 8
/* Number of (single-bit) entries in a multicast filter hash */
#define EFX_MCAST_HASH_ENTRIES (1 << EFX_MCAST_HASH_BITS)
/* An Efx multicast filter hash */
union efx_multicast_hash {
u8 byte[EFX_MCAST_HASH_ENTRIES / 8];
efx_oword_t oword[EFX_MCAST_HASH_ENTRIES / sizeof(efx_oword_t) / 8];
};
/**
* struct efx_nic - an Efx NIC
* @name: Device name (net device name or bus id before net device registered)
* @pci_dev: The PCI device
* @type: Controller type attributes
* @legacy_irq: IRQ number
* @workqueue: Workqueue for resets, port reconfigures and the HW monitor
* @reset_work: Scheduled reset workitem
* @monitor_work: Hardware monitor workitem
* @membase_phys: Memory BAR value as physical address
* @membase: Memory BAR value
* @biu_lock: BIU (bus interface unit) lock
* @interrupt_mode: Interrupt mode
* @i2c: I2C interface
* @board_info: Board-level information
* @state: Device state flag. Serialised by the rtnl_lock.
* @reset_pending: Pending reset method (normally RESET_TYPE_NONE)
* @tx_queue: TX DMA queues
* @rx_queue: RX DMA queues
* @channel: Channels
* @rss_queues: Number of RSS queues
* @rx_buffer_len: RX buffer length
* @rx_buffer_order: Order (log2) of number of pages for each RX buffer
* @irq_status: Interrupt status buffer
* @last_irq_cpu: Last CPU to handle interrupt.
* This register is written with the SMP processor ID whenever an
* interrupt is handled. It is used by falcon_test_interrupt()
* to verify that an interrupt has occurred.
* @n_rx_nodesc_drop_cnt: RX no descriptor drop count
* @nic_data: Hardware dependant state
* @mac_lock: MAC access lock. Protects @port_enabled, efx_monitor() and
* efx_reconfigure_port()
* @port_enabled: Port enabled indicator.
* Serialises efx_stop_all(), efx_start_all() and efx_monitor() and
* efx_reconfigure_work with kernel interfaces. Safe to read under any
* one of the rtnl_lock, mac_lock, or netif_tx_lock, but all three must
* be held to modify it.
* @port_initialized: Port initialized?
* @net_dev: Operating system network device. Consider holding the rtnl lock
* @rx_checksum_enabled: RX checksumming enabled
* @netif_stop_count: Port stop count
* @netif_stop_lock: Port stop lock
* @mac_stats: MAC statistics. These include all statistics the MACs
* can provide. Generic code converts these into a standard
* &struct net_device_stats.
* @stats_buffer: DMA buffer for statistics
* @stats_lock: Statistics update lock
* @mac_address: Permanent MAC address
* @phy_type: PHY type
* @phy_lock: PHY access lock
* @phy_op: PHY interface
* @phy_data: PHY private data (including PHY-specific stats)
* @mii: PHY interface
* @phy_powered: PHY power state
* @tx_disabled: PHY transmitter turned off
* @link_up: Link status
* @link_options: Link options (MII/GMII format)
* @n_link_state_changes: Number of times the link has changed state
* @promiscuous: Promiscuous flag. Protected by netif_tx_lock.
* @multicast_hash: Multicast hash table
* @flow_control: Flow control flags - separate RX/TX so can't use link_options
* @reconfigure_work: work item for dealing with PHY events
*
* The @priv field of the corresponding &struct net_device points to
* this.
*/
struct efx_nic {
char name[IFNAMSIZ];
struct pci_dev *pci_dev;
const struct efx_nic_type *type;
int legacy_irq;
struct workqueue_struct *workqueue;
struct work_struct reset_work;
struct delayed_work monitor_work;
unsigned long membase_phys;
void __iomem *membase;
spinlock_t biu_lock;
enum efx_int_mode interrupt_mode;
struct efx_i2c_interface i2c;
struct efx_board board_info;
enum nic_state state;
enum reset_type reset_pending;
struct efx_tx_queue tx_queue[EFX_MAX_TX_QUEUES];
struct efx_rx_queue rx_queue[EFX_MAX_RX_QUEUES];
struct efx_channel channel[EFX_MAX_CHANNELS];
int rss_queues;
unsigned int rx_buffer_len;
unsigned int rx_buffer_order;
struct efx_buffer irq_status;
volatile signed int last_irq_cpu;
unsigned n_rx_nodesc_drop_cnt;
void *nic_data;
struct mutex mac_lock;
int port_enabled;
int port_initialized;
struct net_device *net_dev;
int rx_checksum_enabled;
atomic_t netif_stop_count;
spinlock_t netif_stop_lock;
struct efx_mac_stats mac_stats;
struct efx_buffer stats_buffer;
spinlock_t stats_lock;
unsigned char mac_address[ETH_ALEN];
enum phy_type phy_type;
spinlock_t phy_lock;
struct efx_phy_operations *phy_op;
void *phy_data;
struct mii_if_info mii;
int link_up;
unsigned int link_options;
unsigned int n_link_state_changes;
int promiscuous;
union efx_multicast_hash multicast_hash;
enum efx_fc_type flow_control;
struct work_struct reconfigure_work;
atomic_t rx_reset;
};
/**
* struct efx_nic_type - Efx device type definition
* @mem_bar: Memory BAR number
* @mem_map_size: Memory BAR mapped size
* @txd_ptr_tbl_base: TX descriptor ring base address
* @rxd_ptr_tbl_base: RX descriptor ring base address
* @buf_tbl_base: Buffer table base address
* @evq_ptr_tbl_base: Event queue pointer table base address
* @evq_rptr_tbl_base: Event queue read-pointer table base address
* @txd_ring_mask: TX descriptor ring size - 1 (must be a power of two - 1)
* @rxd_ring_mask: RX descriptor ring size - 1 (must be a power of two - 1)
* @evq_size: Event queue size (must be a power of two)
* @max_dma_mask: Maximum possible DMA mask
* @tx_dma_mask: TX DMA mask
* @bug5391_mask: Address mask for bug 5391 workaround
* @rx_xoff_thresh: RX FIFO XOFF watermark (bytes)
* @rx_xon_thresh: RX FIFO XON watermark (bytes)
* @rx_buffer_padding: Padding added to each RX buffer
* @max_interrupt_mode: Highest capability interrupt mode supported
* from &enum efx_init_mode.
* @phys_addr_channels: Number of channels with physically addressed
* descriptors
*/
struct efx_nic_type {
unsigned int mem_bar;
unsigned int mem_map_size;
unsigned int txd_ptr_tbl_base;
unsigned int rxd_ptr_tbl_base;
unsigned int buf_tbl_base;
unsigned int evq_ptr_tbl_base;
unsigned int evq_rptr_tbl_base;
unsigned int txd_ring_mask;
unsigned int rxd_ring_mask;
unsigned int evq_size;
dma_addr_t max_dma_mask;
unsigned int tx_dma_mask;
unsigned bug5391_mask;
int rx_xoff_thresh;
int rx_xon_thresh;
unsigned int rx_buffer_padding;
unsigned int max_interrupt_mode;
unsigned int phys_addr_channels;
};
/**************************************************************************
*
* Prototypes and inline functions
*
*************************************************************************/
/* Iterate over all used channels */
#define efx_for_each_channel(_channel, _efx) \
for (_channel = &_efx->channel[0]; \
_channel < &_efx->channel[EFX_MAX_CHANNELS]; \
_channel++) \
if (!_channel->used_flags) \
continue; \
else
/* Iterate over all used channels with interrupts */
#define efx_for_each_channel_with_interrupt(_channel, _efx) \
for (_channel = &_efx->channel[0]; \
_channel < &_efx->channel[EFX_MAX_CHANNELS]; \
_channel++) \
if (!(_channel->used_flags && _channel->has_interrupt)) \
continue; \
else
/* Iterate over all used TX queues */
#define efx_for_each_tx_queue(_tx_queue, _efx) \
for (_tx_queue = &_efx->tx_queue[0]; \
_tx_queue < &_efx->tx_queue[EFX_MAX_TX_QUEUES]; \
_tx_queue++) \
if (!_tx_queue->used) \
continue; \
else
/* Iterate over all TX queues belonging to a channel */
#define efx_for_each_channel_tx_queue(_tx_queue, _channel) \
for (_tx_queue = &_channel->efx->tx_queue[0]; \
_tx_queue < &_channel->efx->tx_queue[EFX_MAX_TX_QUEUES]; \
_tx_queue++) \
if ((!_tx_queue->used) || \
(_tx_queue->channel != _channel)) \
continue; \
else
/* Iterate over all used RX queues */
#define efx_for_each_rx_queue(_rx_queue, _efx) \
for (_rx_queue = &_efx->rx_queue[0]; \
_rx_queue < &_efx->rx_queue[EFX_MAX_RX_QUEUES]; \
_rx_queue++) \
if (!_rx_queue->used) \
continue; \
else
/* Iterate over all RX queues belonging to a channel */
#define efx_for_each_channel_rx_queue(_rx_queue, _channel) \
for (_rx_queue = &_channel->efx->rx_queue[0]; \
_rx_queue < &_channel->efx->rx_queue[EFX_MAX_RX_QUEUES]; \
_rx_queue++) \
if ((!_rx_queue->used) || \
(_rx_queue->channel != _channel)) \
continue; \
else
/* Returns a pointer to the specified receive buffer in the RX
* descriptor queue.
*/
static inline struct efx_rx_buffer *efx_rx_buffer(struct efx_rx_queue *rx_queue,
unsigned int index)
{
return (&rx_queue->buffer[index]);
}
/* Set bit in a little-endian bitfield */
static inline void set_bit_le(int nr, unsigned char *addr)
{
addr[nr / 8] |= (1 << (nr % 8));
}
/* Clear bit in a little-endian bitfield */
static inline void clear_bit_le(int nr, unsigned char *addr)
{
addr[nr / 8] &= ~(1 << (nr % 8));
}
/**
* EFX_MAX_FRAME_LEN - calculate maximum frame length
*
* This calculates the maximum frame length that will be used for a
* given MTU. The frame length will be equal to the MTU plus a
* constant amount of header space and padding. This is the quantity
* that the net driver will program into the MAC as the maximum frame
* length.
*
* The 10G MAC used in Falcon requires 8-byte alignment on the frame
* length, so we round up to the nearest 8.
*/
#define EFX_MAX_FRAME_LEN(mtu) \
((((mtu) + ETH_HLEN + VLAN_HLEN + 4/* FCS */) + 7) & ~7)
#endif /* EFX_NET_DRIVER_H */

View File

@ -0,0 +1,48 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2007 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#ifndef EFX_PHY_H
#define EFX_PHY_H
/****************************************************************************
* 10Xpress (SFX7101) PHY
*/
extern struct efx_phy_operations falcon_tenxpress_phy_ops;
enum tenxpress_state {
TENXPRESS_STATUS_OFF = 0,
TENXPRESS_STATUS_OTEMP = 1,
TENXPRESS_STATUS_NORMAL = 2,
};
extern void tenxpress_set_state(struct efx_nic *efx,
enum tenxpress_state state);
extern void tenxpress_phy_blink(struct efx_nic *efx, int blink);
extern void tenxpress_crc_err(struct efx_nic *efx);
/****************************************************************************
* Exported functions from the driver for XFP optical PHYs
*/
extern struct efx_phy_operations falcon_xfp_phy_ops;
/* The QUAKE XFP PHY provides various H/W control states for LEDs */
#define QUAKE_LED_LINK_INVAL (0)
#define QUAKE_LED_LINK_STAT (1)
#define QUAKE_LED_LINK_ACT (2)
#define QUAKE_LED_LINK_ACTSTAT (3)
#define QUAKE_LED_OFF (4)
#define QUAKE_LED_ON (5)
#define QUAKE_LED_LINK_INPUT (6) /* Pin is an input. */
/* What link the LED tracks */
#define QUAKE_LED_TXLINK (0)
#define QUAKE_LED_RXLINK (8)
extern void xfp_set_led(struct efx_nic *p, int led, int state);
#endif

View File

@ -0,0 +1,875 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2005-2008 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <net/ip.h>
#include <net/checksum.h>
#include "net_driver.h"
#include "rx.h"
#include "efx.h"
#include "falcon.h"
#include "workarounds.h"
/* Number of RX descriptors pushed at once. */
#define EFX_RX_BATCH 8
/* Size of buffer allocated for skb header area. */
#define EFX_SKB_HEADERS 64u
/*
* rx_alloc_method - RX buffer allocation method
*
* This driver supports two methods for allocating and using RX buffers:
* each RX buffer may be backed by an skb or by an order-n page.
*
* When LRO is in use then the second method has a lower overhead,
* since we don't have to allocate then free skbs on reassembled frames.
*
* Values:
* - RX_ALLOC_METHOD_AUTO = 0
* - RX_ALLOC_METHOD_SKB = 1
* - RX_ALLOC_METHOD_PAGE = 2
*
* The heuristic for %RX_ALLOC_METHOD_AUTO is a simple hysteresis count
* controlled by the parameters below.
*
* - Since pushing and popping descriptors are separated by the rx_queue
* size, so the watermarks should be ~rxd_size.
* - The performance win by using page-based allocation for LRO is less
* than the performance hit of using page-based allocation of non-LRO,
* so the watermarks should reflect this.
*
* Per channel we maintain a single variable, updated by each channel:
*
* rx_alloc_level += (lro_performed ? RX_ALLOC_FACTOR_LRO :
* RX_ALLOC_FACTOR_SKB)
* Per NAPI poll interval, we constrain rx_alloc_level to 0..MAX (which
* limits the hysteresis), and update the allocation strategy:
*
* rx_alloc_method = (rx_alloc_level > RX_ALLOC_LEVEL_LRO ?
* RX_ALLOC_METHOD_PAGE : RX_ALLOC_METHOD_SKB)
*/
static int rx_alloc_method = RX_ALLOC_METHOD_PAGE;
#define RX_ALLOC_LEVEL_LRO 0x2000
#define RX_ALLOC_LEVEL_MAX 0x3000
#define RX_ALLOC_FACTOR_LRO 1
#define RX_ALLOC_FACTOR_SKB (-2)
/* This is the percentage fill level below which new RX descriptors
* will be added to the RX descriptor ring.
*/
static unsigned int rx_refill_threshold = 90;
/* This is the percentage fill level to which an RX queue will be refilled
* when the "RX refill threshold" is reached.
*/
static unsigned int rx_refill_limit = 95;
/*
* RX maximum head room required.
*
* This must be at least 1 to prevent overflow and at least 2 to allow
* pipelined receives.
*/
#define EFX_RXD_HEAD_ROOM 2
/* Macros for zero-order pages (potentially) containing multiple RX buffers */
#define RX_DATA_OFFSET(_data) \
(((unsigned long) (_data)) & (PAGE_SIZE-1))
#define RX_BUF_OFFSET(_rx_buf) \
RX_DATA_OFFSET((_rx_buf)->data)
#define RX_PAGE_SIZE(_efx) \
(PAGE_SIZE * (1u << (_efx)->rx_buffer_order))
/**************************************************************************
*
* Linux generic LRO handling
*
**************************************************************************
*/
static int efx_lro_get_skb_hdr(struct sk_buff *skb, void **ip_hdr,
void **tcpudp_hdr, u64 *hdr_flags, void *priv)
{
struct efx_channel *channel = (struct efx_channel *)priv;
struct iphdr *iph;
struct tcphdr *th;
iph = (struct iphdr *)skb->data;
if (skb->protocol != htons(ETH_P_IP) || iph->protocol != IPPROTO_TCP)
goto fail;
th = (struct tcphdr *)(skb->data + iph->ihl * 4);
*tcpudp_hdr = th;
*ip_hdr = iph;
*hdr_flags = LRO_IPV4 | LRO_TCP;
channel->rx_alloc_level += RX_ALLOC_FACTOR_LRO;
return 0;
fail:
channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
return -1;
}
static int efx_get_frag_hdr(struct skb_frag_struct *frag, void **mac_hdr,
void **ip_hdr, void **tcpudp_hdr, u64 *hdr_flags,
void *priv)
{
struct efx_channel *channel = (struct efx_channel *)priv;
struct ethhdr *eh;
struct iphdr *iph;
/* We support EtherII and VLAN encapsulated IPv4 */
eh = (struct ethhdr *)(page_address(frag->page) + frag->page_offset);
*mac_hdr = eh;
if (eh->h_proto == htons(ETH_P_IP)) {
iph = (struct iphdr *)(eh + 1);
} else {
struct vlan_ethhdr *veh = (struct vlan_ethhdr *)eh;
if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP))
goto fail;
iph = (struct iphdr *)(veh + 1);
}
*ip_hdr = iph;
/* We can only do LRO over TCP */
if (iph->protocol != IPPROTO_TCP)
goto fail;
*hdr_flags = LRO_IPV4 | LRO_TCP;
*tcpudp_hdr = (struct tcphdr *)((u8 *) iph + iph->ihl * 4);
channel->rx_alloc_level += RX_ALLOC_FACTOR_LRO;
return 0;
fail:
channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
return -1;
}
int efx_lro_init(struct net_lro_mgr *lro_mgr, struct efx_nic *efx)
{
size_t s = sizeof(struct net_lro_desc) * EFX_MAX_LRO_DESCRIPTORS;
struct net_lro_desc *lro_arr;
/* Allocate the LRO descriptors structure */
lro_arr = kzalloc(s, GFP_KERNEL);
if (lro_arr == NULL)
return -ENOMEM;
lro_mgr->lro_arr = lro_arr;
lro_mgr->max_desc = EFX_MAX_LRO_DESCRIPTORS;
lro_mgr->max_aggr = EFX_MAX_LRO_AGGR;
lro_mgr->frag_align_pad = EFX_PAGE_SKB_ALIGN;
lro_mgr->get_skb_header = efx_lro_get_skb_hdr;
lro_mgr->get_frag_header = efx_get_frag_hdr;
lro_mgr->dev = efx->net_dev;
lro_mgr->features = LRO_F_NAPI;
/* We can pass packets up with the checksum intact */
lro_mgr->ip_summed = CHECKSUM_UNNECESSARY;
lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
return 0;
}
void efx_lro_fini(struct net_lro_mgr *lro_mgr)
{
kfree(lro_mgr->lro_arr);
lro_mgr->lro_arr = NULL;
}
/**
* efx_init_rx_buffer_skb - create new RX buffer using skb-based allocation
*
* @rx_queue: Efx RX queue
* @rx_buf: RX buffer structure to populate
*
* This allocates memory for a new receive buffer, maps it for DMA,
* and populates a struct efx_rx_buffer with the relevant
* information. Return a negative error code or 0 on success.
*/
static inline int efx_init_rx_buffer_skb(struct efx_rx_queue *rx_queue,
struct efx_rx_buffer *rx_buf)
{
struct efx_nic *efx = rx_queue->efx;
struct net_device *net_dev = efx->net_dev;
int skb_len = efx->rx_buffer_len;
rx_buf->skb = netdev_alloc_skb(net_dev, skb_len);
if (unlikely(!rx_buf->skb))
return -ENOMEM;
/* Adjust the SKB for padding and checksum */
skb_reserve(rx_buf->skb, NET_IP_ALIGN);
rx_buf->len = skb_len - NET_IP_ALIGN;
rx_buf->data = (char *)rx_buf->skb->data;
rx_buf->skb->ip_summed = CHECKSUM_UNNECESSARY;
rx_buf->dma_addr = pci_map_single(efx->pci_dev,
rx_buf->data, rx_buf->len,
PCI_DMA_FROMDEVICE);
if (unlikely(pci_dma_mapping_error(rx_buf->dma_addr))) {
dev_kfree_skb_any(rx_buf->skb);
rx_buf->skb = NULL;
return -EIO;
}
return 0;
}
/**
* efx_init_rx_buffer_page - create new RX buffer using page-based allocation
*
* @rx_queue: Efx RX queue
* @rx_buf: RX buffer structure to populate
*
* This allocates memory for a new receive buffer, maps it for DMA,
* and populates a struct efx_rx_buffer with the relevant
* information. Return a negative error code or 0 on success.
*/
static inline int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue,
struct efx_rx_buffer *rx_buf)
{
struct efx_nic *efx = rx_queue->efx;
int bytes, space, offset;
bytes = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN;
/* If there is space left in the previously allocated page,
* then use it. Otherwise allocate a new one */
rx_buf->page = rx_queue->buf_page;
if (rx_buf->page == NULL) {
dma_addr_t dma_addr;
rx_buf->page = alloc_pages(__GFP_COLD | __GFP_COMP | GFP_ATOMIC,
efx->rx_buffer_order);
if (unlikely(rx_buf->page == NULL))
return -ENOMEM;
dma_addr = pci_map_page(efx->pci_dev, rx_buf->page,
0, RX_PAGE_SIZE(efx),
PCI_DMA_FROMDEVICE);
if (unlikely(pci_dma_mapping_error(dma_addr))) {
__free_pages(rx_buf->page, efx->rx_buffer_order);
rx_buf->page = NULL;
return -EIO;
}
rx_queue->buf_page = rx_buf->page;
rx_queue->buf_dma_addr = dma_addr;
rx_queue->buf_data = ((char *) page_address(rx_buf->page) +
EFX_PAGE_IP_ALIGN);
}
offset = RX_DATA_OFFSET(rx_queue->buf_data);
rx_buf->len = bytes;
rx_buf->dma_addr = rx_queue->buf_dma_addr + offset;
rx_buf->data = rx_queue->buf_data;
/* Try to pack multiple buffers per page */
if (efx->rx_buffer_order == 0) {
/* The next buffer starts on the next 512 byte boundary */
rx_queue->buf_data += ((bytes + 0x1ff) & ~0x1ff);
offset += ((bytes + 0x1ff) & ~0x1ff);
space = RX_PAGE_SIZE(efx) - offset;
if (space >= bytes) {
/* Refs dropped on kernel releasing each skb */
get_page(rx_queue->buf_page);
goto out;
}
}
/* This is the final RX buffer for this page, so mark it for
* unmapping */
rx_queue->buf_page = NULL;
rx_buf->unmap_addr = rx_queue->buf_dma_addr;
out:
return 0;
}
/* This allocates memory for a new receive buffer, maps it for DMA,
* and populates a struct efx_rx_buffer with the relevant
* information.
*/
static inline int efx_init_rx_buffer(struct efx_rx_queue *rx_queue,
struct efx_rx_buffer *new_rx_buf)
{
int rc = 0;
if (rx_queue->channel->rx_alloc_push_pages) {
new_rx_buf->skb = NULL;
rc = efx_init_rx_buffer_page(rx_queue, new_rx_buf);
rx_queue->alloc_page_count++;
} else {
new_rx_buf->page = NULL;
rc = efx_init_rx_buffer_skb(rx_queue, new_rx_buf);
rx_queue->alloc_skb_count++;
}
if (unlikely(rc < 0))
EFX_LOG_RL(rx_queue->efx, "%s RXQ[%d] =%d\n", __func__,
rx_queue->queue, rc);
return rc;
}
static inline void efx_unmap_rx_buffer(struct efx_nic *efx,
struct efx_rx_buffer *rx_buf)
{
if (rx_buf->page) {
EFX_BUG_ON_PARANOID(rx_buf->skb);
if (rx_buf->unmap_addr) {
pci_unmap_page(efx->pci_dev, rx_buf->unmap_addr,
RX_PAGE_SIZE(efx), PCI_DMA_FROMDEVICE);
rx_buf->unmap_addr = 0;
}
} else if (likely(rx_buf->skb)) {
pci_unmap_single(efx->pci_dev, rx_buf->dma_addr,
rx_buf->len, PCI_DMA_FROMDEVICE);
}
}
static inline void efx_free_rx_buffer(struct efx_nic *efx,
struct efx_rx_buffer *rx_buf)
{
if (rx_buf->page) {
__free_pages(rx_buf->page, efx->rx_buffer_order);
rx_buf->page = NULL;
} else if (likely(rx_buf->skb)) {
dev_kfree_skb_any(rx_buf->skb);
rx_buf->skb = NULL;
}
}
static inline void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
struct efx_rx_buffer *rx_buf)
{
efx_unmap_rx_buffer(rx_queue->efx, rx_buf);
efx_free_rx_buffer(rx_queue->efx, rx_buf);
}
/**
* efx_fast_push_rx_descriptors - push new RX descriptors quickly
* @rx_queue: RX descriptor queue
* @retry: Recheck the fill level
* This will aim to fill the RX descriptor queue up to
* @rx_queue->@fast_fill_limit. If there is insufficient atomic
* memory to do so, the caller should retry.
*/
static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
int retry)
{
struct efx_rx_buffer *rx_buf;
unsigned fill_level, index;
int i, space, rc = 0;
/* Calculate current fill level. Do this outside the lock,
* because most of the time we'll end up not wanting to do the
* fill anyway.
*/
fill_level = (rx_queue->added_count - rx_queue->removed_count);
EFX_BUG_ON_PARANOID(fill_level >
rx_queue->efx->type->rxd_ring_mask + 1);
/* Don't fill if we don't need to */
if (fill_level >= rx_queue->fast_fill_trigger)
return 0;
/* Record minimum fill level */
if (unlikely(fill_level < rx_queue->min_fill))
if (fill_level)
rx_queue->min_fill = fill_level;
/* Acquire RX add lock. If this lock is contended, then a fast
* fill must already be in progress (e.g. in the refill
* tasklet), so we don't need to do anything
*/
if (!spin_trylock_bh(&rx_queue->add_lock))
return -1;
retry:
/* Recalculate current fill level now that we have the lock */
fill_level = (rx_queue->added_count - rx_queue->removed_count);
EFX_BUG_ON_PARANOID(fill_level >
rx_queue->efx->type->rxd_ring_mask + 1);
space = rx_queue->fast_fill_limit - fill_level;
if (space < EFX_RX_BATCH)
goto out_unlock;
EFX_TRACE(rx_queue->efx, "RX queue %d fast-filling descriptor ring from"
" level %d to level %d using %s allocation\n",
rx_queue->queue, fill_level, rx_queue->fast_fill_limit,
rx_queue->channel->rx_alloc_push_pages ? "page" : "skb");
do {
for (i = 0; i < EFX_RX_BATCH; ++i) {
index = (rx_queue->added_count &
rx_queue->efx->type->rxd_ring_mask);
rx_buf = efx_rx_buffer(rx_queue, index);
rc = efx_init_rx_buffer(rx_queue, rx_buf);
if (unlikely(rc))
goto out;
++rx_queue->added_count;
}
} while ((space -= EFX_RX_BATCH) >= EFX_RX_BATCH);
EFX_TRACE(rx_queue->efx, "RX queue %d fast-filled descriptor ring "
"to level %d\n", rx_queue->queue,
rx_queue->added_count - rx_queue->removed_count);
out:
/* Send write pointer to card. */
falcon_notify_rx_desc(rx_queue);
/* If the fast fill is running inside from the refill tasklet, then
* for SMP systems it may be running on a different CPU to
* RX event processing, which means that the fill level may now be
* out of date. */
if (unlikely(retry && (rc == 0)))
goto retry;
out_unlock:
spin_unlock_bh(&rx_queue->add_lock);
return rc;
}
/**
* efx_fast_push_rx_descriptors - push new RX descriptors quickly
* @rx_queue: RX descriptor queue
*
* This will aim to fill the RX descriptor queue up to
* @rx_queue->@fast_fill_limit. If there is insufficient memory to do so,
* it will schedule a work item to immediately continue the fast fill
*/
void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
{
int rc;
rc = __efx_fast_push_rx_descriptors(rx_queue, 0);
if (unlikely(rc)) {
/* Schedule the work item to run immediately. The hope is
* that work is immediately pending to free some memory
* (e.g. an RX event or TX completion)
*/
efx_schedule_slow_fill(rx_queue, 0);
}
}
void efx_rx_work(struct work_struct *data)
{
struct efx_rx_queue *rx_queue;
int rc;
rx_queue = container_of(data, struct efx_rx_queue, work.work);
if (unlikely(!rx_queue->channel->enabled))
return;
EFX_TRACE(rx_queue->efx, "RX queue %d worker thread executing on CPU "
"%d\n", rx_queue->queue, raw_smp_processor_id());
++rx_queue->slow_fill_count;
/* Push new RX descriptors, allowing at least 1 jiffy for
* the kernel to free some more memory. */
rc = __efx_fast_push_rx_descriptors(rx_queue, 1);
if (rc)
efx_schedule_slow_fill(rx_queue, 1);
}
static inline void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
struct efx_rx_buffer *rx_buf,
int len, int *discard,
int *leak_packet)
{
struct efx_nic *efx = rx_queue->efx;
unsigned max_len = rx_buf->len - efx->type->rx_buffer_padding;
if (likely(len <= max_len))
return;
/* The packet must be discarded, but this is only a fatal error
* if the caller indicated it was
*/
*discard = 1;
if ((len > rx_buf->len) && EFX_WORKAROUND_8071(efx)) {
EFX_ERR_RL(efx, " RX queue %d seriously overlength "
"RX event (0x%x > 0x%x+0x%x). Leaking\n",
rx_queue->queue, len, max_len,
efx->type->rx_buffer_padding);
/* If this buffer was skb-allocated, then the meta
* data at the end of the skb will be trashed. So
* we have no choice but to leak the fragment.
*/
*leak_packet = (rx_buf->skb != NULL);
efx_schedule_reset(efx, RESET_TYPE_RX_RECOVERY);
} else {
EFX_ERR_RL(efx, " RX queue %d overlength RX event "
"(0x%x > 0x%x)\n", rx_queue->queue, len, max_len);
}
rx_queue->channel->n_rx_overlength++;
}
/* Pass a received packet up through the generic LRO stack
*
* Handles driverlink veto, and passes the fragment up via
* the appropriate LRO method
*/
static inline void efx_rx_packet_lro(struct efx_channel *channel,
struct efx_rx_buffer *rx_buf)
{
struct net_lro_mgr *lro_mgr = &channel->lro_mgr;
void *priv = channel;
/* Pass the skb/page into the LRO engine */
if (rx_buf->page) {
struct skb_frag_struct frags;
frags.page = rx_buf->page;
frags.page_offset = RX_BUF_OFFSET(rx_buf);
frags.size = rx_buf->len;
lro_receive_frags(lro_mgr, &frags, rx_buf->len,
rx_buf->len, priv, 0);
EFX_BUG_ON_PARANOID(rx_buf->skb);
rx_buf->page = NULL;
} else {
EFX_BUG_ON_PARANOID(!rx_buf->skb);
lro_receive_skb(lro_mgr, rx_buf->skb, priv);
rx_buf->skb = NULL;
}
}
/* Allocate and construct an SKB around a struct page.*/
static inline struct sk_buff *efx_rx_mk_skb(struct efx_rx_buffer *rx_buf,
struct efx_nic *efx,
int hdr_len)
{
struct sk_buff *skb;
/* Allocate an SKB to store the headers */
skb = netdev_alloc_skb(efx->net_dev, hdr_len + EFX_PAGE_SKB_ALIGN);
if (unlikely(skb == NULL)) {
EFX_ERR_RL(efx, "RX out of memory for skb\n");
return NULL;
}
EFX_BUG_ON_PARANOID(skb_shinfo(skb)->nr_frags);
EFX_BUG_ON_PARANOID(rx_buf->len < hdr_len);
skb->ip_summed = CHECKSUM_UNNECESSARY;
skb_reserve(skb, EFX_PAGE_SKB_ALIGN);
skb->len = rx_buf->len;
skb->truesize = rx_buf->len + sizeof(struct sk_buff);
memcpy(skb->data, rx_buf->data, hdr_len);
skb->tail += hdr_len;
/* Append the remaining page onto the frag list */
if (unlikely(rx_buf->len > hdr_len)) {
struct skb_frag_struct *frag = skb_shinfo(skb)->frags;
frag->page = rx_buf->page;
frag->page_offset = RX_BUF_OFFSET(rx_buf) + hdr_len;
frag->size = skb->len - hdr_len;
skb_shinfo(skb)->nr_frags = 1;
skb->data_len = frag->size;
} else {
__free_pages(rx_buf->page, efx->rx_buffer_order);
skb->data_len = 0;
}
/* Ownership has transferred from the rx_buf to skb */
rx_buf->page = NULL;
/* Move past the ethernet header */
skb->protocol = eth_type_trans(skb, efx->net_dev);
return skb;
}
void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
unsigned int len, int checksummed, int discard)
{
struct efx_nic *efx = rx_queue->efx;
struct efx_rx_buffer *rx_buf;
int leak_packet = 0;
rx_buf = efx_rx_buffer(rx_queue, index);
EFX_BUG_ON_PARANOID(!rx_buf->data);
EFX_BUG_ON_PARANOID(rx_buf->skb && rx_buf->page);
EFX_BUG_ON_PARANOID(!(rx_buf->skb || rx_buf->page));
/* This allows the refill path to post another buffer.
* EFX_RXD_HEAD_ROOM ensures that the slot we are using
* isn't overwritten yet.
*/
rx_queue->removed_count++;
/* Validate the length encoded in the event vs the descriptor pushed */
efx_rx_packet__check_len(rx_queue, rx_buf, len,
&discard, &leak_packet);
EFX_TRACE(efx, "RX queue %d received id %x at %llx+%x %s%s\n",
rx_queue->queue, index,
(unsigned long long)rx_buf->dma_addr, len,
(checksummed ? " [SUMMED]" : ""),
(discard ? " [DISCARD]" : ""));
/* Discard packet, if instructed to do so */
if (unlikely(discard)) {
if (unlikely(leak_packet))
rx_queue->channel->n_skbuff_leaks++;
else
/* We haven't called efx_unmap_rx_buffer yet,
* so fini the entire rx_buffer here */
efx_fini_rx_buffer(rx_queue, rx_buf);
return;
}
/* Release card resources - assumes all RX buffers consumed in-order
* per RX queue
*/
efx_unmap_rx_buffer(efx, rx_buf);
/* Prefetch nice and early so data will (hopefully) be in cache by
* the time we look at it.
*/
prefetch(rx_buf->data);
/* Pipeline receives so that we give time for packet headers to be
* prefetched into cache.
*/
rx_buf->len = len;
if (rx_queue->channel->rx_pkt)
__efx_rx_packet(rx_queue->channel,
rx_queue->channel->rx_pkt,
rx_queue->channel->rx_pkt_csummed);
rx_queue->channel->rx_pkt = rx_buf;
rx_queue->channel->rx_pkt_csummed = checksummed;
}
/* Handle a received packet. Second half: Touches packet payload. */
void __efx_rx_packet(struct efx_channel *channel,
struct efx_rx_buffer *rx_buf, int checksummed)
{
struct efx_nic *efx = channel->efx;
struct sk_buff *skb;
int lro = efx->net_dev->features & NETIF_F_LRO;
if (rx_buf->skb) {
prefetch(skb_shinfo(rx_buf->skb));
skb_put(rx_buf->skb, rx_buf->len);
/* Move past the ethernet header. rx_buf->data still points
* at the ethernet header */
rx_buf->skb->protocol = eth_type_trans(rx_buf->skb,
efx->net_dev);
}
/* Both our generic-LRO and SFC-SSR support skb and page based
* allocation, but neither support switching from one to the
* other on the fly. If we spot that the allocation mode has
* changed, then flush the LRO state.
*/
if (unlikely(channel->rx_alloc_pop_pages != (rx_buf->page != NULL))) {
efx_flush_lro(channel);
channel->rx_alloc_pop_pages = (rx_buf->page != NULL);
}
if (likely(checksummed && lro)) {
efx_rx_packet_lro(channel, rx_buf);
goto done;
}
/* Form an skb if required */
if (rx_buf->page) {
int hdr_len = min(rx_buf->len, EFX_SKB_HEADERS);
skb = efx_rx_mk_skb(rx_buf, efx, hdr_len);
if (unlikely(skb == NULL)) {
efx_free_rx_buffer(efx, rx_buf);
goto done;
}
} else {
/* We now own the SKB */
skb = rx_buf->skb;
rx_buf->skb = NULL;
}
EFX_BUG_ON_PARANOID(rx_buf->page);
EFX_BUG_ON_PARANOID(rx_buf->skb);
EFX_BUG_ON_PARANOID(!skb);
/* Set the SKB flags */
if (unlikely(!checksummed || !efx->rx_checksum_enabled))
skb->ip_summed = CHECKSUM_NONE;
/* Pass the packet up */
netif_receive_skb(skb);
/* Update allocation strategy method */
channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
/* fall-thru */
done:
efx->net_dev->last_rx = jiffies;
}
void efx_rx_strategy(struct efx_channel *channel)
{
enum efx_rx_alloc_method method = rx_alloc_method;
/* Only makes sense to use page based allocation if LRO is enabled */
if (!(channel->efx->net_dev->features & NETIF_F_LRO)) {
method = RX_ALLOC_METHOD_SKB;
} else if (method == RX_ALLOC_METHOD_AUTO) {
/* Constrain the rx_alloc_level */
if (channel->rx_alloc_level < 0)
channel->rx_alloc_level = 0;
else if (channel->rx_alloc_level > RX_ALLOC_LEVEL_MAX)
channel->rx_alloc_level = RX_ALLOC_LEVEL_MAX;
/* Decide on the allocation method */
method = ((channel->rx_alloc_level > RX_ALLOC_LEVEL_LRO) ?
RX_ALLOC_METHOD_PAGE : RX_ALLOC_METHOD_SKB);
}
/* Push the option */
channel->rx_alloc_push_pages = (method == RX_ALLOC_METHOD_PAGE);
}
int efx_probe_rx_queue(struct efx_rx_queue *rx_queue)
{
struct efx_nic *efx = rx_queue->efx;
unsigned int rxq_size;
int rc;
EFX_LOG(efx, "creating RX queue %d\n", rx_queue->queue);
/* Allocate RX buffers */
rxq_size = (efx->type->rxd_ring_mask + 1) * sizeof(*rx_queue->buffer);
rx_queue->buffer = kzalloc(rxq_size, GFP_KERNEL);
if (!rx_queue->buffer) {
rc = -ENOMEM;
goto fail1;
}
rc = falcon_probe_rx(rx_queue);
if (rc)
goto fail2;
return 0;
fail2:
kfree(rx_queue->buffer);
rx_queue->buffer = NULL;
fail1:
rx_queue->used = 0;
return rc;
}
int efx_init_rx_queue(struct efx_rx_queue *rx_queue)
{
struct efx_nic *efx = rx_queue->efx;
unsigned int max_fill, trigger, limit;
EFX_LOG(rx_queue->efx, "initialising RX queue %d\n", rx_queue->queue);
/* Initialise ptr fields */
rx_queue->added_count = 0;
rx_queue->notified_count = 0;
rx_queue->removed_count = 0;
rx_queue->min_fill = -1U;
rx_queue->min_overfill = -1U;
/* Initialise limit fields */
max_fill = efx->type->rxd_ring_mask + 1 - EFX_RXD_HEAD_ROOM;
trigger = max_fill * min(rx_refill_threshold, 100U) / 100U;
limit = max_fill * min(rx_refill_limit, 100U) / 100U;
rx_queue->max_fill = max_fill;
rx_queue->fast_fill_trigger = trigger;
rx_queue->fast_fill_limit = limit;
/* Set up RX descriptor ring */
return falcon_init_rx(rx_queue);
}
void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
{
int i;
struct efx_rx_buffer *rx_buf;
EFX_LOG(rx_queue->efx, "shutting down RX queue %d\n", rx_queue->queue);
falcon_fini_rx(rx_queue);
/* Release RX buffers NB start at index 0 not current HW ptr */
if (rx_queue->buffer) {
for (i = 0; i <= rx_queue->efx->type->rxd_ring_mask; i++) {
rx_buf = efx_rx_buffer(rx_queue, i);
efx_fini_rx_buffer(rx_queue, rx_buf);
}
}
/* For a page that is part-way through splitting into RX buffers */
if (rx_queue->buf_page != NULL) {
pci_unmap_page(rx_queue->efx->pci_dev, rx_queue->buf_dma_addr,
RX_PAGE_SIZE(rx_queue->efx), PCI_DMA_FROMDEVICE);
__free_pages(rx_queue->buf_page,
rx_queue->efx->rx_buffer_order);
rx_queue->buf_page = NULL;
}
}
void efx_remove_rx_queue(struct efx_rx_queue *rx_queue)
{
EFX_LOG(rx_queue->efx, "destroying RX queue %d\n", rx_queue->queue);
falcon_remove_rx(rx_queue);
kfree(rx_queue->buffer);
rx_queue->buffer = NULL;
rx_queue->used = 0;
}
void efx_flush_lro(struct efx_channel *channel)
{
lro_flush_all(&channel->lro_mgr);
}
module_param(rx_alloc_method, int, 0644);
MODULE_PARM_DESC(rx_alloc_method, "Allocation method used for RX buffers");
module_param(rx_refill_threshold, uint, 0444);
MODULE_PARM_DESC(rx_refill_threshold,
"RX descriptor ring fast/slow fill threshold (%)");

View File

@ -0,0 +1,29 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2006 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#ifndef EFX_RX_H
#define EFX_RX_H
#include "net_driver.h"
int efx_probe_rx_queue(struct efx_rx_queue *rx_queue);
void efx_remove_rx_queue(struct efx_rx_queue *rx_queue);
int efx_init_rx_queue(struct efx_rx_queue *rx_queue);
void efx_fini_rx_queue(struct efx_rx_queue *rx_queue);
int efx_lro_init(struct net_lro_mgr *lro_mgr, struct efx_nic *efx);
void efx_lro_fini(struct net_lro_mgr *lro_mgr);
void efx_flush_lro(struct efx_channel *channel);
void efx_rx_strategy(struct efx_channel *channel);
void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue);
void efx_rx_work(struct work_struct *data);
void __efx_rx_packet(struct efx_channel *channel,
struct efx_rx_buffer *rx_buf, int checksummed);
#endif /* EFX_RX_H */

View File

@ -0,0 +1,252 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2007 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
/*****************************************************************************
* Support for the SFE4001 NIC: driver code for the PCA9539 I/O expander that
* controls the PHY power rails, and for the MAX6647 temp. sensor used to check
* the PHY
*/
#include <linux/delay.h>
#include "efx.h"
#include "phy.h"
#include "boards.h"
#include "falcon.h"
#include "falcon_hwdefs.h"
#include "mac.h"
/**************************************************************************
*
* I2C IO Expander device
*
**************************************************************************/
#define PCA9539 0x74
#define P0_IN 0x00
#define P0_OUT 0x02
#define P0_INVERT 0x04
#define P0_CONFIG 0x06
#define P0_EN_1V0X_LBN 0
#define P0_EN_1V0X_WIDTH 1
#define P0_EN_1V2_LBN 1
#define P0_EN_1V2_WIDTH 1
#define P0_EN_2V5_LBN 2
#define P0_EN_2V5_WIDTH 1
#define P0_EN_3V3X_LBN 3
#define P0_EN_3V3X_WIDTH 1
#define P0_EN_5V_LBN 4
#define P0_EN_5V_WIDTH 1
#define P0_SHORTEN_JTAG_LBN 5
#define P0_SHORTEN_JTAG_WIDTH 1
#define P0_X_TRST_LBN 6
#define P0_X_TRST_WIDTH 1
#define P0_DSP_RESET_LBN 7
#define P0_DSP_RESET_WIDTH 1
#define P1_IN 0x01
#define P1_OUT 0x03
#define P1_INVERT 0x05
#define P1_CONFIG 0x07
#define P1_AFE_PWD_LBN 0
#define P1_AFE_PWD_WIDTH 1
#define P1_DSP_PWD25_LBN 1
#define P1_DSP_PWD25_WIDTH 1
#define P1_RESERVED_LBN 2
#define P1_RESERVED_WIDTH 2
#define P1_SPARE_LBN 4
#define P1_SPARE_WIDTH 4
/**************************************************************************
*
* Temperature Sensor
*
**************************************************************************/
#define MAX6647 0x4e
#define RLTS 0x00
#define RLTE 0x01
#define RSL 0x02
#define RCL 0x03
#define RCRA 0x04
#define RLHN 0x05
#define RLLI 0x06
#define RRHI 0x07
#define RRLS 0x08
#define WCRW 0x0a
#define WLHO 0x0b
#define WRHA 0x0c
#define WRLN 0x0e
#define OSHT 0x0f
#define REET 0x10
#define RIET 0x11
#define RWOE 0x19
#define RWOI 0x20
#define HYS 0x21
#define QUEUE 0x22
#define MFID 0xfe
#define REVID 0xff
/* Status bits */
#define MAX6647_BUSY (1 << 7) /* ADC is converting */
#define MAX6647_LHIGH (1 << 6) /* Local high temp. alarm */
#define MAX6647_LLOW (1 << 5) /* Local low temp. alarm */
#define MAX6647_RHIGH (1 << 4) /* Remote high temp. alarm */
#define MAX6647_RLOW (1 << 3) /* Remote low temp. alarm */
#define MAX6647_FAULT (1 << 2) /* DXN/DXP short/open circuit */
#define MAX6647_EOT (1 << 1) /* Remote junction overtemp. */
#define MAX6647_IOT (1 << 0) /* Local junction overtemp. */
static const u8 xgphy_max_temperature = 90;
void sfe4001_poweroff(struct efx_nic *efx)
{
struct efx_i2c_interface *i2c = &efx->i2c;
u8 cfg, out, in;
EFX_INFO(efx, "%s\n", __func__);
/* Turn off all power rails */
out = 0xff;
(void) efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
/* Disable port 1 outputs on IO expander */
cfg = 0xff;
(void) efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1);
/* Disable port 0 outputs on IO expander */
cfg = 0xff;
(void) efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1);
/* Clear any over-temperature alert */
(void) efx_i2c_read(i2c, MAX6647, RSL, &in, 1);
}
/* This board uses an I2C expander to provider power to the PHY, which needs to
* be turned on before the PHY can be used.
* Context: Process context, rtnl lock held
*/
int sfe4001_poweron(struct efx_nic *efx)
{
struct efx_i2c_interface *i2c = &efx->i2c;
unsigned int count;
int rc;
u8 out, in, cfg;
efx_dword_t reg;
/* 10Xpress has fixed-function LED pins, so there is no board-specific
* blink code. */
efx->board_info.blink = tenxpress_phy_blink;
/* Ensure that XGXS and XAUI SerDes are held in reset */
EFX_POPULATE_DWORD_7(reg, XX_PWRDNA_EN, 1,
XX_PWRDNB_EN, 1,
XX_RSTPLLAB_EN, 1,
XX_RESETA_EN, 1,
XX_RESETB_EN, 1,
XX_RSTXGXSRX_EN, 1,
XX_RSTXGXSTX_EN, 1);
falcon_xmac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
udelay(10);
/* Set DSP over-temperature alert threshold */
EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature);
rc = efx_i2c_write(i2c, MAX6647, WLHO,
&xgphy_max_temperature, 1);
if (rc)
goto fail1;
/* Read it back and verify */
rc = efx_i2c_read(i2c, MAX6647, RLHN, &in, 1);
if (rc)
goto fail1;
if (in != xgphy_max_temperature) {
rc = -EFAULT;
goto fail1;
}
/* Clear any previous over-temperature alert */
rc = efx_i2c_read(i2c, MAX6647, RSL, &in, 1);
if (rc)
goto fail1;
/* Enable port 0 and port 1 outputs on IO expander */
cfg = 0x00;
rc = efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1);
if (rc)
goto fail1;
cfg = 0xff & ~(1 << P1_SPARE_LBN);
rc = efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1);
if (rc)
goto fail2;
/* Turn all power off then wait 1 sec. This ensures PHY is reset */
out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) |
(0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) |
(0 << P0_EN_1V0X_LBN));
rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
if (rc)
goto fail3;
schedule_timeout_uninterruptible(HZ);
count = 0;
do {
/* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */
out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) |
(1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) |
(1 << P0_X_TRST_LBN));
rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
if (rc)
goto fail3;
msleep(10);
/* Turn on 1V power rail */
out &= ~(1 << P0_EN_1V0X_LBN);
rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
if (rc)
goto fail3;
EFX_INFO(efx, "waiting for power (attempt %d)...\n", count);
schedule_timeout_uninterruptible(HZ);
/* Check DSP is powered */
rc = efx_i2c_read(i2c, PCA9539, P1_IN, &in, 1);
if (rc)
goto fail3;
if (in & (1 << P1_AFE_PWD_LBN))
goto done;
} while (++count < 20);
EFX_INFO(efx, "timed out waiting for power\n");
rc = -ETIMEDOUT;
goto fail3;
done:
EFX_INFO(efx, "PHY is powered on\n");
return 0;
fail3:
/* Turn off all power rails */
out = 0xff;
(void) efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
/* Disable port 1 outputs on IO expander */
out = 0xff;
(void) efx_i2c_write(i2c, PCA9539, P1_CONFIG, &out, 1);
fail2:
/* Disable port 0 outputs on IO expander */
out = 0xff;
(void) efx_i2c_write(i2c, PCA9539, P0_CONFIG, &out, 1);
fail1:
return rc;
}

View File

@ -0,0 +1,71 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005 Fen Systems Ltd.
* Copyright 2006 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#ifndef EFX_SPI_H
#define EFX_SPI_H
#include "net_driver.h"
/**************************************************************************
*
* Basic SPI command set and bit definitions
*
*************************************************************************/
/*
* Commands common to all known devices.
*
*/
/* Write status register */
#define SPI_WRSR 0x01
/* Write data to memory array */
#define SPI_WRITE 0x02
/* Read data from memory array */
#define SPI_READ 0x03
/* Reset write enable latch */
#define SPI_WRDI 0x04
/* Read status register */
#define SPI_RDSR 0x05
/* Set write enable latch */
#define SPI_WREN 0x06
/* SST: Enable write to status register */
#define SPI_SST_EWSR 0x50
/*
* Status register bits. Not all bits are supported on all devices.
*
*/
/* Write-protect pin enabled */
#define SPI_STATUS_WPEN 0x80
/* Block protection bit 2 */
#define SPI_STATUS_BP2 0x10
/* Block protection bit 1 */
#define SPI_STATUS_BP1 0x08
/* Block protection bit 0 */
#define SPI_STATUS_BP0 0x04
/* State of the write enable latch */
#define SPI_STATUS_WEN 0x02
/* Device busy flag */
#define SPI_STATUS_NRDY 0x01
#endif /* EFX_SPI_H */

View File

@ -0,0 +1,434 @@
/****************************************************************************
* Driver for Solarflare 802.3an compliant PHY
* Copyright 2007 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#include <linux/delay.h>
#include <linux/seq_file.h>
#include "efx.h"
#include "gmii.h"
#include "mdio_10g.h"
#include "falcon.h"
#include "phy.h"
#include "falcon_hwdefs.h"
#include "boards.h"
#include "mac.h"
/* We expect these MMDs to be in the package */
/* AN not here as mdio_check_mmds() requires STAT2 support */
#define TENXPRESS_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_PMAPMD | \
MDIO_MMDREG_DEVS0_PCS | \
MDIO_MMDREG_DEVS0_PHYXS)
/* We complain if we fail to see the link partner as 10G capable this many
* times in a row (must be > 1 as sampling the autoneg. registers is racy)
*/
#define MAX_BAD_LP_TRIES (5)
/* Extended control register */
#define PMA_PMD_XCONTROL_REG 0xc000
#define PMA_PMD_LNPGA_POWERDOWN_LBN 8
#define PMA_PMD_LNPGA_POWERDOWN_WIDTH 1
/* extended status register */
#define PMA_PMD_XSTATUS_REG 0xc001
#define PMA_PMD_XSTAT_FLP_LBN (12)
/* LED control register */
#define PMA_PMD_LED_CTRL_REG (0xc007)
#define PMA_PMA_LED_ACTIVITY_LBN (3)
/* LED function override register */
#define PMA_PMD_LED_OVERR_REG (0xc009)
/* Bit positions for different LEDs (there are more but not wired on SFE4001)*/
#define PMA_PMD_LED_LINK_LBN (0)
#define PMA_PMD_LED_SPEED_LBN (2)
#define PMA_PMD_LED_TX_LBN (4)
#define PMA_PMD_LED_RX_LBN (6)
/* Override settings */
#define PMA_PMD_LED_AUTO (0) /* H/W control */
#define PMA_PMD_LED_ON (1)
#define PMA_PMD_LED_OFF (2)
#define PMA_PMD_LED_FLASH (3)
/* All LEDs under hardware control */
#define PMA_PMD_LED_FULL_AUTO (0)
/* Green and Amber under hardware control, Red off */
#define PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN)
/* Self test (BIST) control register */
#define PMA_PMD_BIST_CTRL_REG (0xc014)
#define PMA_PMD_BIST_BER_LBN (2) /* Run BER test */
#define PMA_PMD_BIST_CONT_LBN (1) /* Run continuous BIST until cleared */
#define PMA_PMD_BIST_SINGLE_LBN (0) /* Run 1 BIST iteration (self clears) */
/* Self test status register */
#define PMA_PMD_BIST_STAT_REG (0xc015)
#define PMA_PMD_BIST_ENX_LBN (3)
#define PMA_PMD_BIST_PMA_LBN (2)
#define PMA_PMD_BIST_RXD_LBN (1)
#define PMA_PMD_BIST_AFE_LBN (0)
#define BIST_MAX_DELAY (1000)
#define BIST_POLL_DELAY (10)
/* Misc register defines */
#define PCS_CLOCK_CTRL_REG 0xd801
#define PLL312_RST_N_LBN 2
#define PCS_SOFT_RST2_REG 0xd806
#define SERDES_RST_N_LBN 13
#define XGXS_RST_N_LBN 12
#define PCS_TEST_SELECT_REG 0xd807 /* PRM 10.5.8 */
#define CLK312_EN_LBN 3
/* Boot status register */
#define PCS_BOOT_STATUS_REG (0xd000)
#define PCS_BOOT_FATAL_ERR_LBN (0)
#define PCS_BOOT_PROGRESS_LBN (1)
#define PCS_BOOT_PROGRESS_WIDTH (2)
#define PCS_BOOT_COMPLETE_LBN (3)
#define PCS_BOOT_MAX_DELAY (100)
#define PCS_BOOT_POLL_DELAY (10)
/* Time to wait between powering down the LNPGA and turning off the power
* rails */
#define LNPGA_PDOWN_WAIT (HZ / 5)
static int crc_error_reset_threshold = 100;
module_param(crc_error_reset_threshold, int, 0644);
MODULE_PARM_DESC(crc_error_reset_threshold,
"Max number of CRC errors before XAUI reset");
struct tenxpress_phy_data {
enum tenxpress_state state;
atomic_t bad_crc_count;
int bad_lp_tries;
};
static int tenxpress_state_is(struct efx_nic *efx, int state)
{
struct tenxpress_phy_data *phy_data = efx->phy_data;
return (phy_data != NULL) && (state == phy_data->state);
}
void tenxpress_set_state(struct efx_nic *efx,
enum tenxpress_state state)
{
struct tenxpress_phy_data *phy_data = efx->phy_data;
if (phy_data != NULL)
phy_data->state = state;
}
void tenxpress_crc_err(struct efx_nic *efx)
{
struct tenxpress_phy_data *phy_data = efx->phy_data;
if (phy_data != NULL)
atomic_inc(&phy_data->bad_crc_count);
}
/* Check that the C166 has booted successfully */
static int tenxpress_phy_check(struct efx_nic *efx)
{
int phy_id = efx->mii.phy_id;
int count = PCS_BOOT_MAX_DELAY / PCS_BOOT_POLL_DELAY;
int boot_stat;
/* Wait for the boot to complete (or not) */
while (count) {
boot_stat = mdio_clause45_read(efx, phy_id,
MDIO_MMD_PCS,
PCS_BOOT_STATUS_REG);
if (boot_stat & (1 << PCS_BOOT_COMPLETE_LBN))
break;
count--;
udelay(PCS_BOOT_POLL_DELAY);
}
if (!count) {
EFX_ERR(efx, "%s: PHY boot timed out. Last status "
"%x\n", __func__,
(boot_stat >> PCS_BOOT_PROGRESS_LBN) &
((1 << PCS_BOOT_PROGRESS_WIDTH) - 1));
return -ETIMEDOUT;
}
return 0;
}
static void tenxpress_reset_xaui(struct efx_nic *efx);
static int tenxpress_init(struct efx_nic *efx)
{
int rc, reg;
/* Turn on the clock */
reg = (1 << CLK312_EN_LBN);
mdio_clause45_write(efx, efx->mii.phy_id,
MDIO_MMD_PCS, PCS_TEST_SELECT_REG, reg);
rc = tenxpress_phy_check(efx);
if (rc < 0)
return rc;
/* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */
reg = mdio_clause45_read(efx, efx->mii.phy_id,
MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG);
reg |= (1 << PMA_PMA_LED_ACTIVITY_LBN);
mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
PMA_PMD_LED_CTRL_REG, reg);
reg = PMA_PMD_LED_DEFAULT;
mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
PMA_PMD_LED_OVERR_REG, reg);
return rc;
}
static int tenxpress_phy_init(struct efx_nic *efx)
{
struct tenxpress_phy_data *phy_data;
int rc = 0;
phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
efx->phy_data = phy_data;
tenxpress_set_state(efx, TENXPRESS_STATUS_NORMAL);
rc = mdio_clause45_wait_reset_mmds(efx,
TENXPRESS_REQUIRED_DEVS);
if (rc < 0)
goto fail;
rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0);
if (rc < 0)
goto fail;
rc = tenxpress_init(efx);
if (rc < 0)
goto fail;
schedule_timeout_uninterruptible(HZ / 5); /* 200ms */
/* Let XGXS and SerDes out of reset and resets 10XPress */
falcon_reset_xaui(efx);
return 0;
fail:
kfree(efx->phy_data);
efx->phy_data = NULL;
return rc;
}
static void tenxpress_set_bad_lp(struct efx_nic *efx, int bad_lp)
{
struct tenxpress_phy_data *pd = efx->phy_data;
int reg;
/* Nothing to do if all is well and was previously so. */
if (!(bad_lp || pd->bad_lp_tries))
return;
reg = mdio_clause45_read(efx, efx->mii.phy_id,
MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG);
if (bad_lp)
pd->bad_lp_tries++;
else
pd->bad_lp_tries = 0;
if (pd->bad_lp_tries == MAX_BAD_LP_TRIES) {
pd->bad_lp_tries = 0; /* Restart count */
reg &= ~(PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN);
reg |= (PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN);
EFX_ERR(efx, "This NIC appears to be plugged into"
" a port that is not 10GBASE-T capable.\n"
" This PHY is 10GBASE-T ONLY, so no link can"
" be established.\n");
} else {
reg |= (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN);
}
mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
PMA_PMD_LED_OVERR_REG, reg);
}
/* Check link status and return a boolean OK value. If the link is NOT
* OK we have a quick rummage round to see if we appear to be plugged
* into a non-10GBT port and if so warn the user that they won't get
* link any time soon as we are 10GBT only, unless caller specified
* not to do this check (it isn't useful in loopback) */
static int tenxpress_link_ok(struct efx_nic *efx, int check_lp)
{
int ok = mdio_clause45_links_ok(efx, TENXPRESS_REQUIRED_DEVS);
if (ok) {
tenxpress_set_bad_lp(efx, 0);
} else if (check_lp) {
/* Are we plugged into the wrong sort of link? */
int bad_lp = 0;
int phy_id = efx->mii.phy_id;
int an_stat = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
MDIO_AN_STATUS);
int xphy_stat = mdio_clause45_read(efx, phy_id,
MDIO_MMD_PMAPMD,
PMA_PMD_XSTATUS_REG);
/* Are we plugged into anything that sends FLPs? If
* not we can't distinguish between not being plugged
* in and being plugged into a non-AN antique. The FLP
* bit has the advantage of not clearing when autoneg
* restarts. */
if (!(xphy_stat & (1 << PMA_PMD_XSTAT_FLP_LBN))) {
tenxpress_set_bad_lp(efx, 0);
return ok;
}
/* If it can do 10GBT it must be XNP capable */
bad_lp = !(an_stat & (1 << MDIO_AN_STATUS_XNP_LBN));
if (!bad_lp && (an_stat & (1 << MDIO_AN_STATUS_PAGE_LBN))) {
bad_lp = !(mdio_clause45_read(efx, phy_id,
MDIO_MMD_AN, MDIO_AN_10GBT_STATUS) &
(1 << MDIO_AN_10GBT_STATUS_LP_10G_LBN));
}
tenxpress_set_bad_lp(efx, bad_lp);
}
return ok;
}
static void tenxpress_phy_reconfigure(struct efx_nic *efx)
{
if (!tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL))
return;
efx->link_up = tenxpress_link_ok(efx, 0);
efx->link_options = GM_LPA_10000FULL;
}
static void tenxpress_phy_clear_interrupt(struct efx_nic *efx)
{
/* Nothing done here - LASI interrupts aren't reliable so poll */
}
/* Poll PHY for interrupt */
static int tenxpress_phy_check_hw(struct efx_nic *efx)
{
struct tenxpress_phy_data *phy_data = efx->phy_data;
int phy_up = tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL);
int link_ok;
link_ok = phy_up && tenxpress_link_ok(efx, 1);
if (link_ok != efx->link_up)
falcon_xmac_sim_phy_event(efx);
/* Nothing to check if we've already shut down the PHY */
if (!phy_up)
return 0;
if (atomic_read(&phy_data->bad_crc_count) > crc_error_reset_threshold) {
EFX_ERR(efx, "Resetting XAUI due to too many CRC errors\n");
falcon_reset_xaui(efx);
atomic_set(&phy_data->bad_crc_count, 0);
}
return 0;
}
static void tenxpress_phy_fini(struct efx_nic *efx)
{
int reg;
/* Power down the LNPGA */
reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN);
mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
PMA_PMD_XCONTROL_REG, reg);
/* Waiting here ensures that the board fini, which can turn off the
* power to the PHY, won't get run until the LNPGA powerdown has been
* given long enough to complete. */
schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */
kfree(efx->phy_data);
efx->phy_data = NULL;
}
/* Set the RX and TX LEDs and Link LED flashing. The other LEDs
* (which probably aren't wired anyway) are left in AUTO mode */
void tenxpress_phy_blink(struct efx_nic *efx, int blink)
{
int reg;
if (blink)
reg = (PMA_PMD_LED_FLASH << PMA_PMD_LED_TX_LBN) |
(PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN) |
(PMA_PMD_LED_FLASH << PMA_PMD_LED_LINK_LBN);
else
reg = PMA_PMD_LED_DEFAULT;
mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
PMA_PMD_LED_OVERR_REG, reg);
}
static void tenxpress_reset_xaui(struct efx_nic *efx)
{
int phy = efx->mii.phy_id;
int clk_ctrl, test_select, soft_rst2;
/* Real work is done on clock_ctrl other resets are thought to be
* optional but make the reset more reliable
*/
/* Read */
clk_ctrl = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
PCS_CLOCK_CTRL_REG);
test_select = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
PCS_TEST_SELECT_REG);
soft_rst2 = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
PCS_SOFT_RST2_REG);
/* Put in reset */
test_select &= ~(1 << CLK312_EN_LBN);
mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
PCS_TEST_SELECT_REG, test_select);
soft_rst2 &= ~((1 << XGXS_RST_N_LBN) | (1 << SERDES_RST_N_LBN));
mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
PCS_SOFT_RST2_REG, soft_rst2);
clk_ctrl &= ~(1 << PLL312_RST_N_LBN);
mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
PCS_CLOCK_CTRL_REG, clk_ctrl);
udelay(10);
/* Remove reset */
clk_ctrl |= (1 << PLL312_RST_N_LBN);
mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
PCS_CLOCK_CTRL_REG, clk_ctrl);
udelay(10);
soft_rst2 |= ((1 << XGXS_RST_N_LBN) | (1 << SERDES_RST_N_LBN));
mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
PCS_SOFT_RST2_REG, soft_rst2);
udelay(10);
test_select |= (1 << CLK312_EN_LBN);
mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
PCS_TEST_SELECT_REG, test_select);
udelay(10);
}
struct efx_phy_operations falcon_tenxpress_phy_ops = {
.init = tenxpress_phy_init,
.reconfigure = tenxpress_phy_reconfigure,
.check_hw = tenxpress_phy_check_hw,
.fini = tenxpress_phy_fini,
.clear_interrupt = tenxpress_phy_clear_interrupt,
.reset_xaui = tenxpress_reset_xaui,
.mmds = TENXPRESS_REQUIRED_DEVS,
};

View File

@ -0,0 +1,452 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2005-2006 Fen Systems Ltd.
* Copyright 2005-2008 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#include <linux/pci.h>
#include <linux/tcp.h>
#include <linux/ip.h>
#include <linux/in.h>
#include <linux/if_ether.h>
#include <linux/highmem.h>
#include "net_driver.h"
#include "tx.h"
#include "efx.h"
#include "falcon.h"
#include "workarounds.h"
/*
* TX descriptor ring full threshold
*
* The tx_queue descriptor ring fill-level must fall below this value
* before we restart the netif queue
*/
#define EFX_NETDEV_TX_THRESHOLD(_tx_queue) \
(_tx_queue->efx->type->txd_ring_mask / 2u)
/* We want to be able to nest calls to netif_stop_queue(), since each
* channel can have an individual stop on the queue.
*/
void efx_stop_queue(struct efx_nic *efx)
{
spin_lock_bh(&efx->netif_stop_lock);
EFX_TRACE(efx, "stop TX queue\n");
atomic_inc(&efx->netif_stop_count);
netif_stop_queue(efx->net_dev);
spin_unlock_bh(&efx->netif_stop_lock);
}
/* Wake netif's TX queue
* We want to be able to nest calls to netif_stop_queue(), since each
* channel can have an individual stop on the queue.
*/
inline void efx_wake_queue(struct efx_nic *efx)
{
local_bh_disable();
if (atomic_dec_and_lock(&efx->netif_stop_count,
&efx->netif_stop_lock)) {
EFX_TRACE(efx, "waking TX queue\n");
netif_wake_queue(efx->net_dev);
spin_unlock(&efx->netif_stop_lock);
}
local_bh_enable();
}
static inline void efx_dequeue_buffer(struct efx_tx_queue *tx_queue,
struct efx_tx_buffer *buffer)
{
if (buffer->unmap_len) {
struct pci_dev *pci_dev = tx_queue->efx->pci_dev;
if (buffer->unmap_single)
pci_unmap_single(pci_dev, buffer->unmap_addr,
buffer->unmap_len, PCI_DMA_TODEVICE);
else
pci_unmap_page(pci_dev, buffer->unmap_addr,
buffer->unmap_len, PCI_DMA_TODEVICE);
buffer->unmap_len = 0;
buffer->unmap_single = 0;
}
if (buffer->skb) {
dev_kfree_skb_any((struct sk_buff *) buffer->skb);
buffer->skb = NULL;
EFX_TRACE(tx_queue->efx, "TX queue %d transmission id %x "
"complete\n", tx_queue->queue, read_ptr);
}
}
/*
* Add a socket buffer to a TX queue
*
* This maps all fragments of a socket buffer for DMA and adds them to
* the TX queue. The queue's insert pointer will be incremented by
* the number of fragments in the socket buffer.
*
* If any DMA mapping fails, any mapped fragments will be unmapped,
* the queue's insert pointer will be restored to its original value.
*
* Returns NETDEV_TX_OK or NETDEV_TX_BUSY
* You must hold netif_tx_lock() to call this function.
*/
static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue,
const struct sk_buff *skb)
{
struct efx_nic *efx = tx_queue->efx;
struct pci_dev *pci_dev = efx->pci_dev;
struct efx_tx_buffer *buffer;
skb_frag_t *fragment;
struct page *page;
int page_offset;
unsigned int len, unmap_len = 0, fill_level, insert_ptr, misalign;
dma_addr_t dma_addr, unmap_addr = 0;
unsigned int dma_len;
unsigned unmap_single;
int q_space, i = 0;
int rc = NETDEV_TX_OK;
EFX_BUG_ON_PARANOID(tx_queue->write_count != tx_queue->insert_count);
/* Get size of the initial fragment */
len = skb_headlen(skb);
fill_level = tx_queue->insert_count - tx_queue->old_read_count;
q_space = efx->type->txd_ring_mask - 1 - fill_level;
/* Map for DMA. Use pci_map_single rather than pci_map_page
* since this is more efficient on machines with sparse
* memory.
*/
unmap_single = 1;
dma_addr = pci_map_single(pci_dev, skb->data, len, PCI_DMA_TODEVICE);
/* Process all fragments */
while (1) {
if (unlikely(pci_dma_mapping_error(dma_addr)))
goto pci_err;
/* Store fields for marking in the per-fragment final
* descriptor */
unmap_len = len;
unmap_addr = dma_addr;
/* Add to TX queue, splitting across DMA boundaries */
do {
if (unlikely(q_space-- <= 0)) {
/* It might be that completions have
* happened since the xmit path last
* checked. Update the xmit path's
* copy of read_count.
*/
++tx_queue->stopped;
/* This memory barrier protects the
* change of stopped from the access
* of read_count. */
smp_mb();
tx_queue->old_read_count =
*(volatile unsigned *)
&tx_queue->read_count;
fill_level = (tx_queue->insert_count
- tx_queue->old_read_count);
q_space = (efx->type->txd_ring_mask - 1 -
fill_level);
if (unlikely(q_space-- <= 0))
goto stop;
smp_mb();
--tx_queue->stopped;
}
insert_ptr = (tx_queue->insert_count &
efx->type->txd_ring_mask);
buffer = &tx_queue->buffer[insert_ptr];
EFX_BUG_ON_PARANOID(buffer->skb);
EFX_BUG_ON_PARANOID(buffer->len);
EFX_BUG_ON_PARANOID(buffer->continuation != 1);
EFX_BUG_ON_PARANOID(buffer->unmap_len);
dma_len = (((~dma_addr) & efx->type->tx_dma_mask) + 1);
if (likely(dma_len > len))
dma_len = len;
misalign = (unsigned)dma_addr & efx->type->bug5391_mask;
if (misalign && dma_len + misalign > 512)
dma_len = 512 - misalign;
/* Fill out per descriptor fields */
buffer->len = dma_len;
buffer->dma_addr = dma_addr;
len -= dma_len;
dma_addr += dma_len;
++tx_queue->insert_count;
} while (len);
/* Transfer ownership of the unmapping to the final buffer */
buffer->unmap_addr = unmap_addr;
buffer->unmap_single = unmap_single;
buffer->unmap_len = unmap_len;
unmap_len = 0;
/* Get address and size of next fragment */
if (i >= skb_shinfo(skb)->nr_frags)
break;
fragment = &skb_shinfo(skb)->frags[i];
len = fragment->size;
page = fragment->page;
page_offset = fragment->page_offset;
i++;
/* Map for DMA */
unmap_single = 0;
dma_addr = pci_map_page(pci_dev, page, page_offset, len,
PCI_DMA_TODEVICE);
}
/* Transfer ownership of the skb to the final buffer */
buffer->skb = skb;
buffer->continuation = 0;
/* Pass off to hardware */
falcon_push_buffers(tx_queue);
return NETDEV_TX_OK;
pci_err:
EFX_ERR_RL(efx, " TX queue %d could not map skb with %d bytes %d "
"fragments for DMA\n", tx_queue->queue, skb->len,
skb_shinfo(skb)->nr_frags + 1);
/* Mark the packet as transmitted, and free the SKB ourselves */
dev_kfree_skb_any((struct sk_buff *)skb);
goto unwind;
stop:
rc = NETDEV_TX_BUSY;
if (tx_queue->stopped == 1)
efx_stop_queue(efx);
unwind:
/* Work backwards until we hit the original insert pointer value */
while (tx_queue->insert_count != tx_queue->write_count) {
--tx_queue->insert_count;
insert_ptr = tx_queue->insert_count & efx->type->txd_ring_mask;
buffer = &tx_queue->buffer[insert_ptr];
efx_dequeue_buffer(tx_queue, buffer);
buffer->len = 0;
}
/* Free the fragment we were mid-way through pushing */
if (unmap_len)
pci_unmap_page(pci_dev, unmap_addr, unmap_len,
PCI_DMA_TODEVICE);
return rc;
}
/* Remove packets from the TX queue
*
* This removes packets from the TX queue, up to and including the
* specified index.
*/
static inline void efx_dequeue_buffers(struct efx_tx_queue *tx_queue,
unsigned int index)
{
struct efx_nic *efx = tx_queue->efx;
unsigned int stop_index, read_ptr;
unsigned int mask = tx_queue->efx->type->txd_ring_mask;
stop_index = (index + 1) & mask;
read_ptr = tx_queue->read_count & mask;
while (read_ptr != stop_index) {
struct efx_tx_buffer *buffer = &tx_queue->buffer[read_ptr];
if (unlikely(buffer->len == 0)) {
EFX_ERR(tx_queue->efx, "TX queue %d spurious TX "
"completion id %x\n", tx_queue->queue,
read_ptr);
efx_schedule_reset(efx, RESET_TYPE_TX_SKIP);
return;
}
efx_dequeue_buffer(tx_queue, buffer);
buffer->continuation = 1;
buffer->len = 0;
++tx_queue->read_count;
read_ptr = tx_queue->read_count & mask;
}
}
/* Initiate a packet transmission on the specified TX queue.
* Note that returning anything other than NETDEV_TX_OK will cause the
* OS to free the skb.
*
* This function is split out from efx_hard_start_xmit to allow the
* loopback test to direct packets via specific TX queues. It is
* therefore a non-static inline, so as not to penalise performance
* for non-loopback transmissions.
*
* Context: netif_tx_lock held
*/
inline int efx_xmit(struct efx_nic *efx,
struct efx_tx_queue *tx_queue, struct sk_buff *skb)
{
int rc;
/* Map fragments for DMA and add to TX queue */
rc = efx_enqueue_skb(tx_queue, skb);
if (unlikely(rc != NETDEV_TX_OK))
goto out;
/* Update last TX timer */
efx->net_dev->trans_start = jiffies;
out:
return rc;
}
/* Initiate a packet transmission. We use one channel per CPU
* (sharing when we have more CPUs than channels). On Falcon, the TX
* completion events will be directed back to the CPU that transmitted
* the packet, which should be cache-efficient.
*
* Context: non-blocking.
* Note that returning anything other than NETDEV_TX_OK will cause the
* OS to free the skb.
*/
int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
{
struct efx_nic *efx = net_dev->priv;
return efx_xmit(efx, &efx->tx_queue[0], skb);
}
void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
{
unsigned fill_level;
struct efx_nic *efx = tx_queue->efx;
EFX_BUG_ON_PARANOID(index > efx->type->txd_ring_mask);
efx_dequeue_buffers(tx_queue, index);
/* See if we need to restart the netif queue. This barrier
* separates the update of read_count from the test of
* stopped. */
smp_mb();
if (unlikely(tx_queue->stopped)) {
fill_level = tx_queue->insert_count - tx_queue->read_count;
if (fill_level < EFX_NETDEV_TX_THRESHOLD(tx_queue)) {
EFX_BUG_ON_PARANOID(!NET_DEV_REGISTERED(efx));
/* Do this under netif_tx_lock(), to avoid racing
* with efx_xmit(). */
netif_tx_lock(efx->net_dev);
if (tx_queue->stopped) {
tx_queue->stopped = 0;
efx_wake_queue(efx);
}
netif_tx_unlock(efx->net_dev);
}
}
}
int efx_probe_tx_queue(struct efx_tx_queue *tx_queue)
{
struct efx_nic *efx = tx_queue->efx;
unsigned int txq_size;
int i, rc;
EFX_LOG(efx, "creating TX queue %d\n", tx_queue->queue);
/* Allocate software ring */
txq_size = (efx->type->txd_ring_mask + 1) * sizeof(*tx_queue->buffer);
tx_queue->buffer = kzalloc(txq_size, GFP_KERNEL);
if (!tx_queue->buffer) {
rc = -ENOMEM;
goto fail1;
}
for (i = 0; i <= efx->type->txd_ring_mask; ++i)
tx_queue->buffer[i].continuation = 1;
/* Allocate hardware ring */
rc = falcon_probe_tx(tx_queue);
if (rc)
goto fail2;
return 0;
fail2:
kfree(tx_queue->buffer);
tx_queue->buffer = NULL;
fail1:
tx_queue->used = 0;
return rc;
}
int efx_init_tx_queue(struct efx_tx_queue *tx_queue)
{
EFX_LOG(tx_queue->efx, "initialising TX queue %d\n", tx_queue->queue);
tx_queue->insert_count = 0;
tx_queue->write_count = 0;
tx_queue->read_count = 0;
tx_queue->old_read_count = 0;
BUG_ON(tx_queue->stopped);
/* Set up TX descriptor ring */
return falcon_init_tx(tx_queue);
}
void efx_release_tx_buffers(struct efx_tx_queue *tx_queue)
{
struct efx_tx_buffer *buffer;
if (!tx_queue->buffer)
return;
/* Free any buffers left in the ring */
while (tx_queue->read_count != tx_queue->write_count) {
buffer = &tx_queue->buffer[tx_queue->read_count &
tx_queue->efx->type->txd_ring_mask];
efx_dequeue_buffer(tx_queue, buffer);
buffer->continuation = 1;
buffer->len = 0;
++tx_queue->read_count;
}
}
void efx_fini_tx_queue(struct efx_tx_queue *tx_queue)
{
EFX_LOG(tx_queue->efx, "shutting down TX queue %d\n", tx_queue->queue);
/* Flush TX queue, remove descriptor ring */
falcon_fini_tx(tx_queue);
efx_release_tx_buffers(tx_queue);
/* Release queue's stop on port, if any */
if (tx_queue->stopped) {
tx_queue->stopped = 0;
efx_wake_queue(tx_queue->efx);
}
}
void efx_remove_tx_queue(struct efx_tx_queue *tx_queue)
{
EFX_LOG(tx_queue->efx, "destroying TX queue %d\n", tx_queue->queue);
falcon_remove_tx(tx_queue);
kfree(tx_queue->buffer);
tx_queue->buffer = NULL;
tx_queue->used = 0;
}

View File

@ -0,0 +1,24 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2006 Fen Systems Ltd.
* Copyright 2006-2008 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#ifndef EFX_TX_H
#define EFX_TX_H
#include "net_driver.h"
int efx_probe_tx_queue(struct efx_tx_queue *tx_queue);
void efx_remove_tx_queue(struct efx_tx_queue *tx_queue);
int efx_init_tx_queue(struct efx_tx_queue *tx_queue);
void efx_fini_tx_queue(struct efx_tx_queue *tx_queue);
int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev);
void efx_release_tx_buffers(struct efx_tx_queue *tx_queue);
#endif /* EFX_TX_H */

View File

@ -0,0 +1,56 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2006-2008 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#ifndef EFX_WORKAROUNDS_H
#define EFX_WORKAROUNDS_H
/*
* Hardware workarounds.
* Bug numbers are from Solarflare's Bugzilla.
*/
#define EFX_WORKAROUND_ALWAYS(efx) 1
#define EFX_WORKAROUND_FALCON_A(efx) (FALCON_REV(efx) <= FALCON_REV_A1)
/* XAUI resets if link not detected */
#define EFX_WORKAROUND_5147 EFX_WORKAROUND_ALWAYS
/* SNAP frames have TOBE_DISC set */
#define EFX_WORKAROUND_5475 EFX_WORKAROUND_ALWAYS
/* RX PCIe double split performance issue */
#define EFX_WORKAROUND_7575 EFX_WORKAROUND_ALWAYS
/* TX pkt parser problem with <= 16 byte TXes */
#define EFX_WORKAROUND_9141 EFX_WORKAROUND_ALWAYS
/* XGXS and XAUI reset sequencing in SW */
#define EFX_WORKAROUND_9388 EFX_WORKAROUND_ALWAYS
/* Low rate CRC errors require XAUI reset */
#define EFX_WORKAROUND_10750 EFX_WORKAROUND_ALWAYS
/* TX_EV_PKT_ERR can be caused by a dangling TX descriptor
* or a PCIe error (bug 11028) */
#define EFX_WORKAROUND_10727 EFX_WORKAROUND_ALWAYS
/* Transmit flow control may get disabled */
#define EFX_WORKAROUND_11482 EFX_WORKAROUND_ALWAYS
/* Flush events can take a very long time to appear */
#define EFX_WORKAROUND_11557 EFX_WORKAROUND_ALWAYS
/* Spurious parity errors in TSORT buffers */
#define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A
/* iSCSI parsing errors */
#define EFX_WORKAROUND_5583 EFX_WORKAROUND_FALCON_A
/* RX events go missing */
#define EFX_WORKAROUND_5676 EFX_WORKAROUND_FALCON_A
/* RX_RESET on A1 */
#define EFX_WORKAROUND_6555 EFX_WORKAROUND_FALCON_A
/* Increase filter depth to avoid RX_RESET */
#define EFX_WORKAROUND_7244 EFX_WORKAROUND_FALCON_A
/* Flushes may never complete */
#define EFX_WORKAROUND_7803 EFX_WORKAROUND_FALCON_A
/* Leak overlength packets rather than free */
#define EFX_WORKAROUND_8071 EFX_WORKAROUND_FALCON_A
#endif /* EFX_WORKAROUNDS_H */

View File

@ -0,0 +1,62 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2006 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
#ifndef EFX_XENPACK_H
#define EFX_XENPACK_H
/* Exported functions from Xenpack standard PHY control */
#include "mdio_10g.h"
/****************************************************************************/
/* XENPACK MDIO register extensions */
#define MDIO_XP_LASI_RX_CTRL (0x9000)
#define MDIO_XP_LASI_TX_CTRL (0x9001)
#define MDIO_XP_LASI_CTRL (0x9002)
#define MDIO_XP_LASI_RX_STAT (0x9003)
#define MDIO_XP_LASI_TX_STAT (0x9004)
#define MDIO_XP_LASI_STAT (0x9005)
/* Control/Status bits */
#define XP_LASI_LS_ALARM (1 << 0)
#define XP_LASI_TX_ALARM (1 << 1)
#define XP_LASI_RX_ALARM (1 << 2)
/* These two are Quake vendor extensions to the standard XENPACK defines */
#define XP_LASI_LS_INTB (1 << 3)
#define XP_LASI_TEST (1 << 7)
/* Enable LASI interrupts for PHY */
static inline void xenpack_enable_lasi_irqs(struct efx_nic *efx)
{
int reg;
int phy_id = efx->mii.phy_id;
/* Read to clear LASI status register */
reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
MDIO_XP_LASI_STAT);
mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
MDIO_XP_LASI_CTRL, XP_LASI_LS_ALARM);
}
/* Read the LASI interrupt status to clear the interrupt. */
static inline int xenpack_clear_lasi_irqs(struct efx_nic *efx)
{
/* Read to clear link status alarm */
return mdio_clause45_read(efx, efx->mii.phy_id,
MDIO_MMD_PMAPMD, MDIO_XP_LASI_STAT);
}
/* Turn off LASI interrupts */
static inline void xenpack_disable_lasi_irqs(struct efx_nic *efx)
{
mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
MDIO_XP_LASI_CTRL, 0);
}
#endif /* EFX_XENPACK_H */

View File

@ -0,0 +1,132 @@
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2006-2008 Solarflare Communications Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, incorporated herein by reference.
*/
/*
* Driver for XFP optical PHYs (plus some support specific to the Quake 2032)
* See www.amcc.com for details (search for qt2032)
*/
#include <linux/timer.h>
#include <linux/delay.h>
#include "efx.h"
#include "gmii.h"
#include "mdio_10g.h"
#include "xenpack.h"
#include "phy.h"
#include "mac.h"
#define XFP_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_PCS | \
MDIO_MMDREG_DEVS0_PMAPMD | \
MDIO_MMDREG_DEVS0_PHYXS)
/****************************************************************************/
/* Quake-specific MDIO registers */
#define MDIO_QUAKE_LED0_REG (0xD006)
void xfp_set_led(struct efx_nic *p, int led, int mode)
{
int addr = MDIO_QUAKE_LED0_REG + led;
mdio_clause45_write(p, p->mii.phy_id, MDIO_MMD_PMAPMD, addr,
mode);
}
#define XFP_MAX_RESET_TIME 500
#define XFP_RESET_WAIT 10
/* Reset the PHYXS MMD. This is documented (for the Quake PHY) as doing
* a complete soft reset.
*/
static int xfp_reset_phy(struct efx_nic *efx)
{
int rc;
rc = mdio_clause45_reset_mmd(efx, MDIO_MMD_PHYXS,
XFP_MAX_RESET_TIME / XFP_RESET_WAIT,
XFP_RESET_WAIT);
if (rc < 0)
goto fail;
/* Wait 250ms for the PHY to complete bootup */
msleep(250);
/* Check that all the MMDs we expect are present and responding. We
* expect faults on some if the link is down, but not on the PHY XS */
rc = mdio_clause45_check_mmds(efx, XFP_REQUIRED_DEVS,
MDIO_MMDREG_DEVS0_PHYXS);
if (rc < 0)
goto fail;
efx->board_info.init_leds(efx);
return rc;
fail:
EFX_ERR(efx, "XFP: reset timed out!\n");
return rc;
}
static int xfp_phy_init(struct efx_nic *efx)
{
u32 devid = mdio_clause45_read_id(efx, MDIO_MMD_PHYXS);
int rc;
EFX_INFO(efx, "XFP: PHY ID reg %x (OUI %x model %x revision"
" %x)\n", devid, MDIO_ID_OUI(devid), MDIO_ID_MODEL(devid),
MDIO_ID_REV(devid));
rc = xfp_reset_phy(efx);
EFX_INFO(efx, "XFP: PHY init %s.\n",
rc ? "failed" : "successful");
return rc;
}
static void xfp_phy_clear_interrupt(struct efx_nic *efx)
{
xenpack_clear_lasi_irqs(efx);
}
static int xfp_link_ok(struct efx_nic *efx)
{
return mdio_clause45_links_ok(efx, XFP_REQUIRED_DEVS);
}
static int xfp_phy_check_hw(struct efx_nic *efx)
{
int rc = 0;
int link_up = xfp_link_ok(efx);
/* Simulate a PHY event if link state has changed */
if (link_up != efx->link_up)
falcon_xmac_sim_phy_event(efx);
return rc;
}
static void xfp_phy_reconfigure(struct efx_nic *efx)
{
efx->link_up = xfp_link_ok(efx);
efx->link_options = GM_LPA_10000FULL;
}
static void xfp_phy_fini(struct efx_nic *efx)
{
/* Clobber the LED if it was blinking */
efx->board_info.blink(efx, 0);
}
struct efx_phy_operations falcon_xfp_phy_ops = {
.init = xfp_phy_init,
.reconfigure = xfp_phy_reconfigure,
.check_hw = xfp_phy_check_hw,
.fini = xfp_phy_fini,
.clear_interrupt = xfp_phy_clear_interrupt,
.reset_xaui = efx_port_dummy_op_void,
.mmds = XFP_REQUIRED_DEVS,
};

View File

@ -212,6 +212,12 @@ enum _DescStatusBit {
THOL2 = 0x20000000,
THOL1 = 0x10000000,
THOL0 = 0x00000000,
WND = 0x00080000,
TABRT = 0x00040000,
FIFO = 0x00020000,
LINK = 0x00010000,
ColCountMask = 0x0000ffff,
/* RxDesc.status */
IPON = 0x20000000,
TCPON = 0x10000000,
@ -480,30 +486,23 @@ static inline void sis190_make_unusable_by_asic(struct RxDesc *desc)
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)
static struct sk_buff *sis190_alloc_rx_skb(struct sis190_private *tp,
struct RxDesc *desc)
{
u32 rx_buf_sz = tp->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;
skb = netdev_alloc_skb(tp->dev, rx_buf_sz);
if (likely(skb)) {
dma_addr_t mapping;
*sk_buff = skb;
mapping = pci_map_single(tp->pci_dev, skb->data, tp->rx_buf_sz,
PCI_DMA_FROMDEVICE);
sis190_map_to_asic(desc, mapping, rx_buf_sz);
} else
sis190_make_unusable_by_asic(desc);
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;
return skb;
}
static u32 sis190_rx_fill(struct sis190_private *tp, struct net_device *dev,
@ -512,37 +511,41 @@ static u32 sis190_rx_fill(struct sis190_private *tp, struct net_device *dev,
u32 cur;
for (cur = start; cur < end; cur++) {
int ret, i = cur % NUM_RX_DESC;
unsigned int 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)
tp->Rx_skbuff[i] = sis190_alloc_rx_skb(tp, tp->RxDescRing + i);
if (!tp->Rx_skbuff[i])
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)
static bool sis190_try_rx_copy(struct sis190_private *tp,
struct sk_buff **sk_buff, int pkt_size,
dma_addr_t addr)
{
int ret = -1;
struct sk_buff *skb;
bool done = false;
if (pkt_size < rx_copybreak) {
struct sk_buff *skb;
if (pkt_size >= rx_copybreak)
goto out;
skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN);
if (skb) {
skb_reserve(skb, NET_IP_ALIGN);
skb_copy_to_linear_data(skb, sk_buff[0]->data, pkt_size);
*sk_buff = skb;
sis190_give_to_asic(desc, rx_buf_sz);
ret = 0;
}
}
return ret;
skb = netdev_alloc_skb(tp->dev, pkt_size + 2);
if (!skb)
goto out;
pci_dma_sync_single_for_device(tp->pci_dev, addr, pkt_size,
PCI_DMA_FROMDEVICE);
skb_reserve(skb, 2);
skb_copy_to_linear_data(skb, sk_buff[0]->data, pkt_size);
*sk_buff = skb;
done = true;
out:
return done;
}
static inline int sis190_rx_pkt_err(u32 status, struct net_device_stats *stats)
@ -592,9 +595,9 @@ static int sis190_rx_interrupt(struct net_device *dev,
sis190_give_to_asic(desc, tp->rx_buf_sz);
else {
struct sk_buff *skb = tp->Rx_skbuff[entry];
dma_addr_t addr = le32_to_cpu(desc->addr);
int pkt_size = (status & RxSizeMask) - 4;
void (*pci_action)(struct pci_dev *, dma_addr_t,
size_t, int) = pci_dma_sync_single_for_device;
struct pci_dev *pdev = tp->pci_dev;
if (unlikely(pkt_size > tp->rx_buf_sz)) {
net_intr(tp, KERN_INFO
@ -606,20 +609,18 @@ static int sis190_rx_interrupt(struct net_device *dev,
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;
if (sis190_try_rx_copy(tp, &skb, pkt_size, addr)) {
pci_dma_sync_single_for_device(pdev, addr,
tp->rx_buf_sz, PCI_DMA_FROMDEVICE);
sis190_give_to_asic(desc, tp->rx_buf_sz);
} else {
pci_unmap_single(pdev, addr, tp->rx_buf_sz,
PCI_DMA_FROMDEVICE);
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_put(skb, pkt_size);
skb->protocol = eth_type_trans(skb, dev);
@ -658,9 +659,31 @@ static void sis190_unmap_tx_skb(struct pci_dev *pdev, struct sk_buff *skb,
memset(desc, 0x00, sizeof(*desc));
}
static inline int sis190_tx_pkt_err(u32 status, struct net_device_stats *stats)
{
#define TxErrMask (WND | TABRT | FIFO | LINK)
if (!unlikely(status & TxErrMask))
return 0;
if (status & WND)
stats->tx_window_errors++;
if (status & TABRT)
stats->tx_aborted_errors++;
if (status & FIFO)
stats->tx_fifo_errors++;
if (status & LINK)
stats->tx_carrier_errors++;
stats->tx_errors++;
return -1;
}
static void sis190_tx_interrupt(struct net_device *dev,
struct sis190_private *tp, void __iomem *ioaddr)
{
struct net_device_stats *stats = &dev->stats;
u32 pending, dirty_tx = tp->dirty_tx;
/*
* It would not be needed if queueing was allowed to be enabled
@ -675,15 +698,19 @@ static void sis190_tx_interrupt(struct net_device *dev,
for (; pending; pending--, dirty_tx++) {
unsigned int entry = dirty_tx % NUM_TX_DESC;
struct TxDesc *txd = tp->TxDescRing + entry;
u32 status = le32_to_cpu(txd->status);
struct sk_buff *skb;
if (le32_to_cpu(txd->status) & OWNbit)
if (status & OWNbit)
break;
skb = tp->Tx_skbuff[entry];
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
if (likely(sis190_tx_pkt_err(status, stats) == 0)) {
stats->tx_packets++;
stats->tx_bytes += skb->len;
stats->collisions += ((status & ColCountMask) - 1);
}
sis190_unmap_tx_skb(tp->pci_dev, skb, txd);
tp->Tx_skbuff[entry] = NULL;
@ -904,10 +931,9 @@ static void sis190_phy_task(struct work_struct *work)
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);
netif_carrier_off(dev);
mdio_write(ioaddr, phy_id, MII_BMCR, val | BMCR_RESET);
net_link(tp, KERN_WARNING "%s: auto-negotiating...\n",
dev->name);
mod_timer(&tp->timer, jiffies + SIS190_PHY_TIMEOUT);
} else {
/* Rejoice ! */

View File

@ -6,6 +6,10 @@ config IWLCORE
tristate "Intel Wireless Wifi Core"
depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
select IWLWIFI
select MAC80211_LEDS if IWLWIFI_LEDS
select LEDS_CLASS if IWLWIFI_LEDS
select RFKILL if IWLWIFI_RFKILL
select RFKILL_INPUT if IWLWIFI_RFKILL
config IWLWIFI_LEDS
bool
@ -14,8 +18,6 @@ config IWLWIFI_LEDS
config IWLWIFI_RFKILL
boolean "IWLWIFI RF kill support"
depends on IWLCORE
select RFKILL
select RFKILL_INPUT
config IWL4965
tristate "Intel Wireless WiFi 4965AGN"
@ -55,8 +57,6 @@ config IWL4965_HT
config IWL4965_LEDS
bool "Enable LEDS features in iwl4965 driver"
depends on IWL4965
select MAC80211_LEDS
select LEDS_CLASS
select IWLWIFI_LEDS
---help---
This option enables LEDS for the iwlwifi drivers
@ -112,6 +112,8 @@ config IWL3945
depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
select FW_LOADER
select IWLWIFI
select MAC80211_LEDS if IWL3945_LEDS
select LEDS_CLASS if IWL3945_LEDS
---help---
Select to build the driver supporting the:
@ -143,8 +145,6 @@ config IWL3945_SPECTRUM_MEASUREMENT
config IWL3945_LEDS
bool "Enable LEDS features in iwl3945 driver"
depends on IWL3945
select MAC80211_LEDS
select LEDS_CLASS
---help---
This option enables LEDS for the iwl3945 driver.

View File

@ -152,44 +152,89 @@ __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
return 0;
}
static int __get_next_bus_id(const char **buf, char *bus_id)
{
int rc, len;
char *start, *end;
start = (char *)*buf;
end = strchr(start, ',');
if (!end) {
/* Last entry. Strip trailing newline, if applicable. */
end = strchr(start, '\n');
if (end)
*end = '\0';
len = strlen(start) + 1;
} else {
len = end - start + 1;
end++;
}
if (len < BUS_ID_SIZE) {
strlcpy(bus_id, start, len);
rc = 0;
} else
rc = -EINVAL;
*buf = end;
return rc;
}
static int __is_valid_bus_id(char bus_id[BUS_ID_SIZE])
{
int cssid, ssid, devno;
/* Must be of form %x.%x.%04x */
if (sscanf(bus_id, "%x.%1x.%04x", &cssid, &ssid, &devno) != 3)
return 0;
return 1;
}
/**
* ccwgroup_create() - create and register a ccw group device
* ccwgroup_create_from_string() - create and register a ccw group device
* @root: parent device for the new device
* @creator_id: identifier of creating driver
* @cdrv: ccw driver of slave devices
* @argc: number of slave devices
* @argv: bus ids of slave devices
* @num_devices: number of slave devices
* @buf: buffer containing comma separated bus ids of slave devices
*
* Create and register a new ccw group device as a child of @root. Slave
* devices are obtained from the list of bus ids given in @argv[] and must all
* devices are obtained from the list of bus ids given in @buf and must all
* belong to @cdrv.
* Returns:
* %0 on success and an error code on failure.
* Context:
* non-atomic
*/
int ccwgroup_create(struct device *root, unsigned int creator_id,
struct ccw_driver *cdrv, int argc, char *argv[])
int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
struct ccw_driver *cdrv, int num_devices,
const char *buf)
{
struct ccwgroup_device *gdev;
int i;
int rc;
int rc, i;
char tmp_bus_id[BUS_ID_SIZE];
const char *curr_buf;
if (argc > 256) /* disallow dumb users */
return -EINVAL;
gdev = kzalloc(sizeof(*gdev) + argc*sizeof(gdev->cdev[0]), GFP_KERNEL);
gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]),
GFP_KERNEL);
if (!gdev)
return -ENOMEM;
atomic_set(&gdev->onoff, 0);
mutex_init(&gdev->reg_mutex);
mutex_lock(&gdev->reg_mutex);
for (i = 0; i < argc; i++) {
gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]);
/* all devices have to be of the same type in
* order to be grouped */
curr_buf = buf;
for (i = 0; i < num_devices && curr_buf; i++) {
rc = __get_next_bus_id(&curr_buf, tmp_bus_id);
if (rc != 0)
goto error;
if (!__is_valid_bus_id(tmp_bus_id)) {
rc = -EINVAL;
goto error;
}
gdev->cdev[i] = get_ccwdev_by_busid(cdrv, tmp_bus_id);
/*
* All devices have to be of the same type in
* order to be grouped.
*/
if (!gdev->cdev[i]
|| gdev->cdev[i]->id.driver_info !=
gdev->cdev[0]->id.driver_info) {
@ -203,9 +248,18 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
}
dev_set_drvdata(&gdev->cdev[i]->dev, gdev);
}
/* Check for sufficient number of bus ids. */
if (i < num_devices && !curr_buf) {
rc = -EINVAL;
goto error;
}
/* Check for trailing stuff. */
if (i == num_devices && strlen(curr_buf) > 0) {
rc = -EINVAL;
goto error;
}
gdev->creator_id = creator_id;
gdev->count = argc;
gdev->count = num_devices;
gdev->dev.bus = &ccwgroup_bus_type;
gdev->dev.parent = root;
gdev->dev.release = ccwgroup_release;
@ -233,7 +287,7 @@ int ccwgroup_create(struct device *root, unsigned int creator_id,
device_remove_file(&gdev->dev, &dev_attr_ungroup);
device_unregister(&gdev->dev);
error:
for (i = 0; i < argc; i++)
for (i = 0; i < num_devices; i++)
if (gdev->cdev[i]) {
if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
@ -243,6 +297,7 @@ error:
put_device(&gdev->dev);
return rc;
}
EXPORT_SYMBOL(ccwgroup_create_from_string);
static int __init
init_ccwgroup (void)
@ -521,6 +576,5 @@ void ccwgroup_remove_ccwdev(struct ccw_device *cdev)
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(ccwgroup_driver_register);
EXPORT_SYMBOL(ccwgroup_driver_unregister);
EXPORT_SYMBOL(ccwgroup_create);
EXPORT_SYMBOL(ccwgroup_probe_ccwdev);
EXPORT_SYMBOL(ccwgroup_remove_ccwdev);

View File

@ -62,30 +62,14 @@ static struct device *cu3088_root_dev;
static ssize_t
group_write(struct device_driver *drv, const char *buf, size_t count)
{
const char *start, *end;
char bus_ids[2][BUS_ID_SIZE], *argv[2];
int i;
int ret;
struct ccwgroup_driver *cdrv;
cdrv = to_ccwgroupdrv(drv);
if (!cdrv)
return -EINVAL;
start = buf;
for (i=0; i<2; i++) {
static const char delim[] = {',', '\n'};
int len;
if (!(end = strchr(start, delim[i])))
return -EINVAL;
len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start + 1);
strlcpy (bus_ids[i], start, len);
argv[i] = bus_ids[i];
start = end + 1;
}
ret = ccwgroup_create(cu3088_root_dev, cdrv->driver_id,
&cu3088_driver, 2, argv);
ret = ccwgroup_create_from_string(cu3088_root_dev, cdrv->driver_id,
&cu3088_driver, 2, buf);
return (ret == 0) ? count : ret;
}

View File

@ -1793,7 +1793,8 @@ lcs_get_skb(struct lcs_card *card, char *skb_data, unsigned int skb_len)
skb->protocol = card->lan_type_trans(skb, card->dev);
card->stats.rx_bytes += skb_len;
card->stats.rx_packets++;
*((__u32 *)skb->cb) = ++card->pkt_seq;
if (skb->protocol == htons(ETH_P_802_2))
*((__u32 *)skb->cb) = ++card->pkt_seq;
netif_rx(skb);
}

View File

@ -1313,8 +1313,6 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev)
* and throw away packet.
*/
if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) {
if (!in_atomic())
fsm_event(privptr->fsm, DEV_EVENT_START, dev);
dev_kfree_skb(skb);
privptr->stats.tx_dropped++;
privptr->stats.tx_errors++;
@ -2147,6 +2145,7 @@ static int __init netiucv_init(void)
if (rc)
goto out_dbf;
IUCV_DBF_TEXT(trace, 3, __func__);
netiucv_driver.groups = netiucv_drv_attr_groups;
rc = driver_register(&netiucv_driver);
if (rc) {
PRINT_ERR("NETIUCV: failed to register driver.\n");

View File

@ -72,22 +72,7 @@ struct qeth_dbf_info {
debug_sprintf_event(qeth_dbf[QETH_DBF_MSG].id, level, text)
#define QETH_DBF_TEXT_(name, level, text...) \
do { \
if (qeth_dbf_passes(qeth_dbf[QETH_DBF_##name].id, level)) { \
char *dbf_txt_buf = \
get_cpu_var(QETH_DBF_TXT_BUF); \
sprintf(dbf_txt_buf, text); \
debug_text_event(qeth_dbf[QETH_DBF_##name].id, \
level, dbf_txt_buf); \
put_cpu_var(QETH_DBF_TXT_BUF); \
} \
} while (0)
/* Allow to sort out low debug levels early to avoid wasted sprints */
static inline int qeth_dbf_passes(debug_info_t *dbf_grp, int level)
{
return (level <= dbf_grp->level);
}
qeth_dbf_longtext(QETH_DBF_##name, level, text)
/**
* some more debug stuff
@ -773,27 +758,6 @@ static inline int qeth_get_micros(void)
return (int) (get_clock() >> 12);
}
static inline void *qeth_push_skb(struct qeth_card *card, struct sk_buff *skb,
int size)
{
void *hdr;
hdr = (void *) skb_push(skb, size);
/*
* sanity check, the Linux memory allocation scheme should
* never present us cases like this one (the qdio header size plus
* the first 40 bytes of the paket cross a 4k boundary)
*/
if ((((unsigned long) hdr) & (~(PAGE_SIZE - 1))) !=
(((unsigned long) hdr + size +
QETH_IP_HEADER_SIZE) & (~(PAGE_SIZE - 1)))) {
PRINT_ERR("Misaligned packet on interface %s. Discarded.",
QETH_CARD_IFNAME(card));
return NULL;
}
return hdr;
}
static inline int qeth_get_ip_version(struct sk_buff *skb)
{
switch (skb->protocol) {
@ -806,6 +770,12 @@ static inline int qeth_get_ip_version(struct sk_buff *skb)
}
}
static inline void qeth_put_buffer_pool_entry(struct qeth_card *card,
struct qeth_buffer_pool_entry *entry)
{
list_add_tail(&entry->list, &card->qdio.in_buf_pool.entry_list);
}
struct qeth_eddp_context;
extern struct ccwgroup_driver qeth_l2_ccwgroup_driver;
extern struct ccwgroup_driver qeth_l3_ccwgroup_driver;
@ -843,8 +813,6 @@ struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *,
int qeth_query_setadapterparms(struct qeth_card *);
int qeth_check_qdio_errors(struct qdio_buffer *, unsigned int,
unsigned int, const char *);
void qeth_put_buffer_pool_entry(struct qeth_card *,
struct qeth_buffer_pool_entry *);
void qeth_queue_input_buffer(struct qeth_card *, int);
struct sk_buff *qeth_core_get_next_skb(struct qeth_card *,
struct qdio_buffer *, struct qdio_buffer_element **, int *,
@ -880,8 +848,6 @@ int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *,
void *reply_param);
int qeth_get_cast_type(struct qeth_card *, struct sk_buff *);
int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int);
struct sk_buff *qeth_prepare_skb(struct qeth_card *, struct sk_buff *,
struct qeth_hdr **);
int qeth_get_elements_no(struct qeth_card *, void *, struct sk_buff *, int);
int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *,
struct sk_buff *, struct qeth_hdr *, int,
@ -894,6 +860,8 @@ void qeth_core_get_ethtool_stats(struct net_device *,
struct ethtool_stats *, u64 *);
void qeth_core_get_strings(struct net_device *, u32, u8 *);
void qeth_core_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
void qeth_dbf_longtext(enum qeth_dbf_names dbf_nix, int level, char *text, ...);
int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *);
/* exports for OSN */
int qeth_osn_assist(struct net_device *, void *, int);

View File

@ -26,9 +26,6 @@
#include "qeth_core.h"
#include "qeth_core_offl.h"
static DEFINE_PER_CPU(char[256], qeth_core_dbf_txt_buf);
#define QETH_DBF_TXT_BUF qeth_core_dbf_txt_buf
struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS] = {
/* define dbf - Name, Pages, Areas, Maxlen, Level, View, Handle */
/* N P A M L V H */
@ -2255,14 +2252,6 @@ void qeth_print_status_message(struct qeth_card *card)
}
EXPORT_SYMBOL_GPL(qeth_print_status_message);
void qeth_put_buffer_pool_entry(struct qeth_card *card,
struct qeth_buffer_pool_entry *entry)
{
QETH_DBF_TEXT(TRACE, 6, "ptbfplen");
list_add_tail(&entry->list, &card->qdio.in_buf_pool.entry_list);
}
EXPORT_SYMBOL_GPL(qeth_put_buffer_pool_entry);
static void qeth_initialize_working_pool_list(struct qeth_card *card)
{
struct qeth_buffer_pool_entry *entry;
@ -2603,7 +2592,6 @@ void qeth_queue_input_buffer(struct qeth_card *card, int index)
int rc;
int newcount = 0;
QETH_DBF_TEXT(TRACE, 6, "queinbuf");
count = (index < queue->next_buf_to_init)?
card->qdio.in_buf_pool.buf_count -
(queue->next_buf_to_init - index) :
@ -2792,8 +2780,6 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
int i;
unsigned int qdio_flags;
QETH_DBF_TEXT(TRACE, 6, "flushbuf");
for (i = index; i < index + count; ++i) {
buf = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q];
buf->buffer->element[buf->next_element_to_fill - 1].flags |=
@ -3037,49 +3023,6 @@ int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
}
EXPORT_SYMBOL_GPL(qeth_get_priority_queue);
static void __qeth_free_new_skb(struct sk_buff *orig_skb,
struct sk_buff *new_skb)
{
if (orig_skb != new_skb)
dev_kfree_skb_any(new_skb);
}
static inline struct sk_buff *qeth_realloc_headroom(struct qeth_card *card,
struct sk_buff *skb, int size)
{
struct sk_buff *new_skb = skb;
if (skb_headroom(skb) >= size)
return skb;
new_skb = skb_realloc_headroom(skb, size);
if (!new_skb)
PRINT_ERR("Could not realloc headroom for qeth_hdr "
"on interface %s", QETH_CARD_IFNAME(card));
return new_skb;
}
struct sk_buff *qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr **hdr)
{
struct sk_buff *new_skb;
QETH_DBF_TEXT(TRACE, 6, "prepskb");
new_skb = qeth_realloc_headroom(card, skb,
sizeof(struct qeth_hdr));
if (!new_skb)
return NULL;
*hdr = ((struct qeth_hdr *)qeth_push_skb(card, new_skb,
sizeof(struct qeth_hdr)));
if (*hdr == NULL) {
__qeth_free_new_skb(skb, new_skb);
return NULL;
}
return new_skb;
}
EXPORT_SYMBOL_GPL(qeth_prepare_skb);
int qeth_get_elements_no(struct qeth_card *card, void *hdr,
struct sk_buff *skb, int elems)
{
@ -3100,8 +3043,8 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr,
}
EXPORT_SYMBOL_GPL(qeth_get_elements_no);
static void __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
int is_tso, int *next_element_to_fill)
static inline void __qeth_fill_buffer(struct sk_buff *skb,
struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill)
{
int length = skb->len;
int length_here;
@ -3143,15 +3086,13 @@ static void __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
*next_element_to_fill = element;
}
static int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
struct qeth_qdio_out_buffer *buf, struct sk_buff *skb)
{
struct qdio_buffer *buffer;
struct qeth_hdr_tso *hdr;
int flush_cnt = 0, hdr_len, large_send = 0;
QETH_DBF_TEXT(TRACE, 6, "qdfillbf");
buffer = buf->buffer;
atomic_inc(&skb->users);
skb_queue_tail(&buf->skb_list, skb);
@ -3210,8 +3151,6 @@ int qeth_do_send_packet_fast(struct qeth_card *card,
int flush_cnt = 0;
int index;
QETH_DBF_TEXT(TRACE, 6, "dosndpfa");
/* spin until we get the queue ... */
while (atomic_cmpxchg(&queue->state, QETH_OUT_Q_UNLOCKED,
QETH_OUT_Q_LOCKED) != QETH_OUT_Q_UNLOCKED);
@ -3263,8 +3202,6 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
int tmp;
int rc = 0;
QETH_DBF_TEXT(TRACE, 6, "dosndpkt");
/* spin until we get the queue ... */
while (atomic_cmpxchg(&queue->state, QETH_OUT_Q_UNLOCKED,
QETH_OUT_Q_LOCKED) != QETH_OUT_Q_UNLOCKED);
@ -3827,27 +3764,8 @@ static struct ccw_driver qeth_ccw_driver = {
static int qeth_core_driver_group(const char *buf, struct device *root_dev,
unsigned long driver_id)
{
const char *start, *end;
char bus_ids[3][BUS_ID_SIZE], *argv[3];
int i;
start = buf;
for (i = 0; i < 3; i++) {
static const char delim[] = { ',', ',', '\n' };
int len;
end = strchr(start, delim[i]);
if (!end)
return -EINVAL;
len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start);
strncpy(bus_ids[i], start, len);
bus_ids[i][len] = '\0';
start = end + 1;
argv[i] = bus_ids[i];
}
return (ccwgroup_create(root_dev, driver_id,
&qeth_ccw_driver, 3, argv));
return ccwgroup_create_from_string(root_dev, driver_id,
&qeth_ccw_driver, 3, buf);
}
int qeth_core_hardsetup_card(struct qeth_card *card)
@ -3885,8 +3803,9 @@ retry:
QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
return rc;
}
mpno = QETH_MAX_PORTNO;
mpno = qdio_get_ssqd_pct(CARD_DDEV(card));
if (mpno)
mpno = min(mpno - 1, QETH_MAX_PORTNO);
if (card->info.portno > mpno) {
PRINT_ERR("Device %s does not offer port number %d \n.",
CARD_BUS_ID(card), card->info.portno);
@ -3980,7 +3899,6 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
int use_rx_sg = 0;
int frag = 0;
QETH_DBF_TEXT(TRACE, 6, "nextskb");
/* qeth_hdr must not cross element boundaries */
if (element->length < offset + sizeof(struct qeth_hdr)) {
if (qeth_is_last_sbale(element))
@ -4086,6 +4004,18 @@ static void qeth_unregister_dbf_views(void)
}
}
void qeth_dbf_longtext(enum qeth_dbf_names dbf_nix, int level, char *text, ...)
{
char dbf_txt_buf[32];
if (level > (qeth_dbf[dbf_nix].id)->level)
return;
snprintf(dbf_txt_buf, sizeof(dbf_txt_buf), text);
debug_text_event(qeth_dbf[dbf_nix].id, level, dbf_txt_buf);
}
EXPORT_SYMBOL_GPL(qeth_dbf_longtext);
static int qeth_register_dbf_views(void)
{
int ret;
@ -4433,6 +4363,96 @@ void qeth_core_get_drvinfo(struct net_device *dev,
}
EXPORT_SYMBOL_GPL(qeth_core_get_drvinfo);
int qeth_core_ethtool_get_settings(struct net_device *netdev,
struct ethtool_cmd *ecmd)
{
struct qeth_card *card = netdev_priv(netdev);
enum qeth_link_types link_type;
if ((card->info.type == QETH_CARD_TYPE_IQD) || (card->info.guestlan))
link_type = QETH_LINK_TYPE_10GBIT_ETH;
else
link_type = card->info.link_type;
ecmd->transceiver = XCVR_INTERNAL;
ecmd->supported = SUPPORTED_Autoneg;
ecmd->advertising = ADVERTISED_Autoneg;
ecmd->duplex = DUPLEX_FULL;
ecmd->autoneg = AUTONEG_ENABLE;
switch (link_type) {
case QETH_LINK_TYPE_FAST_ETH:
case QETH_LINK_TYPE_LANE_ETH100:
ecmd->supported |= SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_TP;
ecmd->advertising |= ADVERTISED_10baseT_Half |
ADVERTISED_10baseT_Full |
ADVERTISED_100baseT_Half |
ADVERTISED_100baseT_Full |
ADVERTISED_TP;
ecmd->speed = SPEED_100;
ecmd->port = PORT_TP;
break;
case QETH_LINK_TYPE_GBIT_ETH:
case QETH_LINK_TYPE_LANE_ETH1000:
ecmd->supported |= SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full |
SUPPORTED_FIBRE;
ecmd->advertising |= ADVERTISED_10baseT_Half |
ADVERTISED_10baseT_Full |
ADVERTISED_100baseT_Half |
ADVERTISED_100baseT_Full |
ADVERTISED_1000baseT_Half |
ADVERTISED_1000baseT_Full |
ADVERTISED_FIBRE;
ecmd->speed = SPEED_1000;
ecmd->port = PORT_FIBRE;
break;
case QETH_LINK_TYPE_10GBIT_ETH:
ecmd->supported |= SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Half |
SUPPORTED_1000baseT_Full |
SUPPORTED_10000baseT_Full |
SUPPORTED_FIBRE;
ecmd->advertising |= ADVERTISED_10baseT_Half |
ADVERTISED_10baseT_Full |
ADVERTISED_100baseT_Half |
ADVERTISED_100baseT_Full |
ADVERTISED_1000baseT_Half |
ADVERTISED_1000baseT_Full |
ADVERTISED_10000baseT_Full |
ADVERTISED_FIBRE;
ecmd->speed = SPEED_10000;
ecmd->port = PORT_FIBRE;
break;
default:
ecmd->supported |= SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_TP;
ecmd->advertising |= ADVERTISED_10baseT_Half |
ADVERTISED_10baseT_Full |
ADVERTISED_TP;
ecmd->speed = SPEED_10;
ecmd->port = PORT_TP;
}
return 0;
}
EXPORT_SYMBOL_GPL(qeth_core_ethtool_get_settings);
static int __init qeth_core_init(void)
{
int rc;

View File

@ -22,9 +22,6 @@
#include "qeth_core.h"
#include "qeth_core_offl.h"
#define QETH_DBF_TXT_BUF qeth_l2_dbf_txt_buf
static DEFINE_PER_CPU(char[256], qeth_l2_dbf_txt_buf);
static int qeth_l2_set_offline(struct ccwgroup_device *);
static int qeth_l2_stop(struct net_device *);
static int qeth_l2_send_delmac(struct qeth_card *, __u8 *);
@ -635,8 +632,6 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO;
struct qeth_eddp_context *ctx = NULL;
QETH_DBF_TEXT(TRACE, 6, "l2xmit");
if ((card->state != CARD_STATE_UP) || !card->lan_online) {
card->stats.tx_carrier_errors++;
goto tx_drop;
@ -658,9 +653,12 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (card->info.type == QETH_CARD_TYPE_OSN)
hdr = (struct qeth_hdr *)skb->data;
else {
new_skb = qeth_prepare_skb(card, skb, &hdr);
/* create a clone with writeable headroom */
new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr));
if (!new_skb)
goto tx_drop;
hdr = (struct qeth_hdr *)skb_push(new_skb,
sizeof(struct qeth_hdr));
qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type);
}
@ -747,7 +745,6 @@ static void qeth_l2_qdio_input_handler(struct ccw_device *ccwdev,
int index;
int i;
QETH_DBF_TEXT(TRACE, 6, "qdinput");
card = (struct qeth_card *) card_ptr;
net_dev = card->dev;
if (card->options.performance_stats) {
@ -852,6 +849,22 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev)
return;
}
static int qeth_l2_ethtool_set_tso(struct net_device *dev, u32 data)
{
struct qeth_card *card = netdev_priv(dev);
if (data) {
if (card->options.large_send == QETH_LARGE_SEND_NO) {
card->options.large_send = QETH_LARGE_SEND_EDDP;
dev->features |= NETIF_F_TSO;
}
} else {
dev->features &= ~NETIF_F_TSO;
card->options.large_send = QETH_LARGE_SEND_NO;
}
return 0;
}
static struct ethtool_ops qeth_l2_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_tx_csum = ethtool_op_get_tx_csum,
@ -859,11 +872,12 @@ static struct ethtool_ops qeth_l2_ethtool_ops = {
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
.set_tso = qeth_l2_ethtool_set_tso,
.get_strings = qeth_core_get_strings,
.get_ethtool_stats = qeth_core_get_ethtool_stats,
.get_stats_count = qeth_core_get_stats_count,
.get_drvinfo = qeth_core_get_drvinfo,
.get_settings = qeth_core_ethtool_get_settings,
};
static struct ethtool_ops qeth_l2_osn_ops = {

View File

@ -13,9 +13,6 @@
#include "qeth_core.h"
#define QETH_DBF_TXT_BUF qeth_l3_dbf_txt_buf
DECLARE_PER_CPU(char[256], qeth_l3_dbf_txt_buf);
struct qeth_ipaddr {
struct list_head entry;
enum qeth_ip_types type;

View File

@ -28,8 +28,6 @@
#include "qeth_l3.h"
#include "qeth_core_offl.h"
DEFINE_PER_CPU(char[256], qeth_l3_dbf_txt_buf);
static int qeth_l3_set_offline(struct ccwgroup_device *);
static int qeth_l3_recover(void *);
static int qeth_l3_stop(struct net_device *);
@ -2093,6 +2091,11 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode)
(card->state == CARD_STATE_UP)) {
if (recovery_mode)
qeth_l3_stop(card->dev);
else {
rtnl_lock();
dev_close(card->dev);
rtnl_unlock();
}
if (!card->use_hard_stop) {
rc = qeth_send_stoplan(card);
if (rc)
@ -2559,8 +2562,6 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
struct sk_buff *skb, int ipv, int cast_type)
{
QETH_DBF_TEXT(TRACE, 6, "fillhdr");
memset(hdr, 0, sizeof(struct qeth_hdr));
hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3;
hdr->hdr.l3.ext_flags = 0;
@ -2570,9 +2571,10 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
* v6 uses passthrough, v4 sets the tag in the QDIO header.
*/
if (card->vlangrp && vlan_tx_tag_present(skb)) {
hdr->hdr.l3.ext_flags = (ipv == 4) ?
QETH_HDR_EXT_VLAN_FRAME :
QETH_HDR_EXT_INCLUDE_VLAN_TAG;
if ((ipv == 4) || (card->info.type == QETH_CARD_TYPE_IQD))
hdr->hdr.l3.ext_flags = QETH_HDR_EXT_VLAN_FRAME;
else
hdr->hdr.l3.ext_flags = QETH_HDR_EXT_INCLUDE_VLAN_TAG;
hdr->hdr.l3.vlan_id = vlan_tx_tag_get(skb);
}
@ -2638,8 +2640,6 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO;
struct qeth_eddp_context *ctx = NULL;
QETH_DBF_TEXT(TRACE, 6, "l3xmit");
if ((card->info.type == QETH_CARD_TYPE_IQD) &&
(skb->protocol != htons(ETH_P_IPV6)) &&
(skb->protocol != htons(ETH_P_IP)))
@ -2890,6 +2890,7 @@ static struct ethtool_ops qeth_l3_ethtool_ops = {
.get_ethtool_stats = qeth_core_get_ethtool_stats,
.get_stats_count = qeth_core_get_stats_count,
.get_drvinfo = qeth_core_get_drvinfo,
.get_settings = qeth_core_ethtool_get_settings,
};
/*
@ -2982,7 +2983,6 @@ static void qeth_l3_qdio_input_handler(struct ccw_device *ccwdev,
int index;
int i;
QETH_DBF_TEXT(TRACE, 6, "qdinput");
card = (struct qeth_card *) card_ptr;
net_dev = card->dev;
if (card->options.performance_stats) {
@ -3140,9 +3140,15 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode)
netif_carrier_on(card->dev);
qeth_set_allowed_threads(card, 0xffffffff, 0);
if ((recover_flag == CARD_STATE_RECOVER) && recovery_mode) {
if (recover_flag == CARD_STATE_RECOVER) {
if (recovery_mode)
qeth_l3_open(card->dev);
qeth_l3_set_multicast_list(card->dev);
else {
rtnl_lock();
dev_open(card->dev);
rtnl_unlock();
}
qeth_l3_set_multicast_list(card->dev);
}
/* let user_space know that device is online */
kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE);

View File

@ -57,10 +57,9 @@ struct ccwgroup_driver {
extern int ccwgroup_driver_register (struct ccwgroup_driver *cdriver);
extern void ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver);
extern int ccwgroup_create (struct device *root,
unsigned int creator_id,
struct ccw_driver *gdrv,
int argc, char *argv[]);
int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
struct ccw_driver *cdrv, int num_devices,
const char *buf);
extern int ccwgroup_probe_ccwdev(struct ccw_device *cdev);
extern void ccwgroup_remove_ccwdev(struct ccw_device *cdev);

View File

@ -127,6 +127,7 @@ extern int do_QDIO(struct ccw_device*, unsigned int flags,
unsigned int qidx,unsigned int count,
struct qdio_buffer *buffers);
extern int qdio_get_ssqd_pct(struct ccw_device*);
extern int qdio_synchronize(struct ccw_device*, unsigned int flags,
unsigned int queue_number);

View File

@ -42,5 +42,8 @@ extern int cmsghdr_from_user_compat_to_kern(struct msghdr *, struct sock *, unsi
extern int compat_mc_setsockopt(struct sock *, int, int, char __user *, int,
int (*)(struct sock *, int, int, char __user *, int));
extern int compat_mc_getsockopt(struct sock *, int, int, char __user *,
int __user *, int (*)(struct sock *, int, int, char __user *,
int __user *));
#endif /* NET_COMPAT_H */

View File

@ -405,7 +405,8 @@ struct sk_buff;
struct ip_vs_protocol {
struct ip_vs_protocol *next;
char *name;
__u16 protocol;
u16 protocol;
u16 num_states;
int dont_defrag;
atomic_t appcnt; /* counter of proto app incs */
int *timeout_table; /* protocol timeout table */

View File

@ -107,16 +107,6 @@ struct nf_conntrack_tuple_mask
} src;
};
/* This is optimized opposed to a memset of the whole structure. Everything we
* really care about is the source/destination unions */
#define NF_CT_TUPLE_U_BLANK(tuple) \
do { \
(tuple)->src.u.all = 0; \
(tuple)->dst.u.all = 0; \
memset(&(tuple)->src.u3, 0, sizeof((tuple)->src.u3)); \
memset(&(tuple)->dst.u3, 0, sizeof((tuple)->dst.u3)); \
} while (0)
#ifdef __KERNEL__
static inline void nf_ct_dump_tuple_ip(const struct nf_conntrack_tuple *t)

View File

@ -116,7 +116,7 @@ extern int __ip_route_output_key(struct net *, struct rtable **, const struct f
extern int ip_route_output_key(struct net *, struct rtable **, struct flowi *flp);
extern int ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk, int flags);
extern int ip_route_input(struct sk_buff*, __be32 dst, __be32 src, u8 tos, struct net_device *devin);
extern unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, unsigned short new_mtu);
extern unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, unsigned short new_mtu, struct net_device *dev);
extern void ip_rt_send_redirect(struct sk_buff *skb);
extern unsigned inet_addr_type(struct net *net, __be32 addr);

View File

@ -76,7 +76,6 @@ static void __exit br_deinit(void)
rcu_assign_pointer(br_stp_sap->rcv_func, NULL);
br_netlink_fini();
br_netfilter_fini();
unregister_netdevice_notifier(&br_device_notifier);
brioctl_set(NULL);
@ -84,6 +83,7 @@ static void __exit br_deinit(void)
synchronize_net();
br_netfilter_fini();
llc_sap_put(br_stp_sap);
br_fdb_get_hook = NULL;
br_fdb_put_hook = NULL;

View File

@ -411,9 +411,12 @@ err2:
br_fdb_delete_by_port(br, p, 1);
err1:
kobject_del(&p->kobj);
return err;
goto put_back;
err0:
kobject_put(&p->kobj);
put_back:
dev_put(dev);
return err;
}

View File

@ -548,6 +548,9 @@ struct compat_group_filter {
__attribute__ ((aligned(4)));
} __attribute__ ((packed));
#define __COMPAT_GF0_SIZE (sizeof(struct compat_group_filter) - \
sizeof(struct __kernel_sockaddr_storage))
int compat_mc_setsockopt(struct sock *sock, int level, int optname,
char __user *optval, int optlen,
@ -582,7 +585,7 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname,
case MCAST_UNBLOCK_SOURCE:
{
struct compat_group_source_req __user *gsr32 = (void *)optval;
struct group_source_req *kgsr = compat_alloc_user_space(
struct group_source_req __user *kgsr = compat_alloc_user_space(
sizeof(struct group_source_req));
u32 interface;
@ -603,10 +606,10 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname,
case MCAST_MSFILTER:
{
struct compat_group_filter __user *gf32 = (void *)optval;
struct group_filter *kgf;
struct group_filter __user *kgf;
u32 interface, fmode, numsrc;
if (!access_ok(VERIFY_READ, gf32, sizeof(*gf32)) ||
if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) ||
__get_user(interface, &gf32->gf_interface) ||
__get_user(fmode, &gf32->gf_fmode) ||
__get_user(numsrc, &gf32->gf_numsrc))
@ -622,7 +625,7 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname,
__put_user(numsrc, &kgf->gf_numsrc) ||
copy_in_user(&kgf->gf_group, &gf32->gf_group,
sizeof(kgf->gf_group)) ||
(numsrc && copy_in_user(&kgf->gf_slist, &gf32->gf_slist,
(numsrc && copy_in_user(kgf->gf_slist, gf32->gf_slist,
numsrc * sizeof(kgf->gf_slist[0]))))
return -EFAULT;
koptval = (char __user *)kgf;
@ -637,6 +640,85 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname,
EXPORT_SYMBOL(compat_mc_setsockopt);
int compat_mc_getsockopt(struct sock *sock, int level, int optname,
char __user *optval, int __user *optlen,
int (*getsockopt)(struct sock *,int,int,char __user *,int __user *))
{
struct compat_group_filter __user *gf32 = (void *)optval;
struct group_filter __user *kgf;
int __user *koptlen;
u32 interface, fmode, numsrc;
int klen, ulen, err;
if (optname != MCAST_MSFILTER)
return getsockopt(sock, level, optname, optval, optlen);
koptlen = compat_alloc_user_space(sizeof(*koptlen));
if (!access_ok(VERIFY_READ, optlen, sizeof(*optlen)) ||
__get_user(ulen, optlen))
return -EFAULT;
/* adjust len for pad */
klen = ulen + sizeof(*kgf) - sizeof(*gf32);
if (klen < GROUP_FILTER_SIZE(0))
return -EINVAL;
if (!access_ok(VERIFY_WRITE, koptlen, sizeof(*koptlen)) ||
__put_user(klen, koptlen))
return -EFAULT;
/* have to allow space for previous compat_alloc_user_space, too */
kgf = compat_alloc_user_space(klen+sizeof(*optlen));
if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) ||
__get_user(interface, &gf32->gf_interface) ||
__get_user(fmode, &gf32->gf_fmode) ||
__get_user(numsrc, &gf32->gf_numsrc) ||
__put_user(interface, &kgf->gf_interface) ||
__put_user(fmode, &kgf->gf_fmode) ||
__put_user(numsrc, &kgf->gf_numsrc) ||
copy_in_user(&kgf->gf_group,&gf32->gf_group,sizeof(kgf->gf_group)))
return -EFAULT;
err = getsockopt(sock, level, optname, (char __user *)kgf, koptlen);
if (err)
return err;
if (!access_ok(VERIFY_READ, koptlen, sizeof(*koptlen)) ||
__get_user(klen, koptlen))
return -EFAULT;
ulen = klen - (sizeof(*kgf)-sizeof(*gf32));
if (!access_ok(VERIFY_WRITE, optlen, sizeof(*optlen)) ||
__put_user(ulen, optlen))
return -EFAULT;
if (!access_ok(VERIFY_READ, kgf, klen) ||
!access_ok(VERIFY_WRITE, gf32, ulen) ||
__get_user(interface, &kgf->gf_interface) ||
__get_user(fmode, &kgf->gf_fmode) ||
__get_user(numsrc, &kgf->gf_numsrc) ||
__put_user(interface, &gf32->gf_interface) ||
__put_user(fmode, &gf32->gf_fmode) ||
__put_user(numsrc, &gf32->gf_numsrc))
return -EFAULT;
if (numsrc) {
int copylen;
klen -= GROUP_FILTER_SIZE(0);
copylen = numsrc * sizeof(gf32->gf_slist[0]);
if (copylen > klen)
copylen = klen;
if (copy_in_user(gf32->gf_slist, kgf->gf_slist, copylen))
return -EFAULT;
}
return err;
}
EXPORT_SYMBOL(compat_mc_getsockopt);
/* Argument list sizes for compat_sys_socketcall */
#define AL(x) ((x) * sizeof(u32))

View File

@ -691,7 +691,8 @@ static void icmp_unreach(struct sk_buff *skb)
NIPQUAD(iph->daddr));
} else {
info = ip_rt_frag_needed(net, iph,
ntohs(icmph->un.frag.mtu));
ntohs(icmph->un.frag.mtu),
skb->dev);
if (!info)
goto out;
}

View File

@ -753,23 +753,15 @@ static inline int ip_ufo_append_data(struct sock *sk,
skb->ip_summed = CHECKSUM_PARTIAL;
skb->csum = 0;
sk->sk_sndmsg_off = 0;
}
err = skb_append_datato_frags(sk,skb, getfrag, from,
(length - transhdrlen));
if (!err) {
/* specify the length of each IP datagram fragment*/
/* specify the length of each IP datagram fragment */
skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
__skb_queue_tail(&sk->sk_write_queue, skb);
return 0;
}
/* There is not enough support do UFO ,
* so follow normal path
*/
kfree_skb(skb);
return err;
return skb_append_datato_frags(sk, skb, getfrag, from,
(length - transhdrlen));
}
/*
@ -863,9 +855,9 @@ int ip_append_data(struct sock *sk,
csummode = CHECKSUM_PARTIAL;
inet->cork.length += length;
if (((length > mtu) && (sk->sk_protocol == IPPROTO_UDP)) &&
(rt->u.dst.dev->features & NETIF_F_UFO)) {
if (((length> mtu) || !skb_queue_empty(&sk->sk_write_queue)) &&
(sk->sk_protocol == IPPROTO_UDP) &&
(rt->u.dst.dev->features & NETIF_F_UFO)) {
err = ip_ufo_append_data(sk, getfrag, from, length, hh_len,
fragheaderlen, transhdrlen, mtu,
flags);

View File

@ -1186,7 +1186,14 @@ int ip_getsockopt(struct sock *sk, int level,
int compat_ip_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
int err = do_ip_getsockopt(sk, level, optname, optval, optlen);
int err;
if (optname == MCAST_MSFILTER)
return compat_mc_getsockopt(sk, level, optname, optval, optlen,
ip_getsockopt);
err = do_ip_getsockopt(sk, level, optname, optval, optlen);
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS &&

View File

@ -412,12 +412,12 @@ static struct packet_type rarp_packet_type __initdata = {
.func = ic_rarp_recv,
};
static inline void ic_rarp_init(void)
static inline void __init ic_rarp_init(void)
{
dev_add_pack(&rarp_packet_type);
}
static inline void ic_rarp_cleanup(void)
static inline void __init ic_rarp_cleanup(void)
{
dev_remove_pack(&rarp_packet_type);
}
@ -682,7 +682,7 @@ static void __init ic_bootp_init_ext(u8 *e)
/*
* Initialize the DHCP/BOOTP mechanism.
*/
static inline void ic_bootp_init(void)
static inline void __init ic_bootp_init(void)
{
int i;
@ -696,7 +696,7 @@ static inline void ic_bootp_init(void)
/*
* DHCP/BOOTP cleanup.
*/
static inline void ic_bootp_cleanup(void)
static inline void __init ic_bootp_cleanup(void)
{
dev_remove_pack(&bootp_packet_type);
}

View File

@ -148,7 +148,7 @@ const char * ip_vs_state_name(__u16 proto, int state)
struct ip_vs_protocol *pp = ip_vs_proto_get(proto);
if (pp == NULL || pp->state_name == NULL)
return "ERR!";
return (IPPROTO_IP == proto) ? "NONE" : "ERR!";
return pp->state_name(state);
}

View File

@ -160,6 +160,7 @@ static void ah_exit(struct ip_vs_protocol *pp)
struct ip_vs_protocol ip_vs_protocol_ah = {
.name = "AH",
.protocol = IPPROTO_AH,
.num_states = 1,
.dont_defrag = 1,
.init = ah_init,
.exit = ah_exit,

View File

@ -159,6 +159,7 @@ static void esp_exit(struct ip_vs_protocol *pp)
struct ip_vs_protocol ip_vs_protocol_esp = {
.name = "ESP",
.protocol = IPPROTO_ESP,
.num_states = 1,
.dont_defrag = 1,
.init = esp_init,
.exit = esp_exit,

View File

@ -594,6 +594,7 @@ static void ip_vs_tcp_exit(struct ip_vs_protocol *pp)
struct ip_vs_protocol ip_vs_protocol_tcp = {
.name = "TCP",
.protocol = IPPROTO_TCP,
.num_states = IP_VS_TCP_S_LAST,
.dont_defrag = 0,
.appcnt = ATOMIC_INIT(0),
.init = ip_vs_tcp_init,

View File

@ -409,6 +409,7 @@ static void udp_exit(struct ip_vs_protocol *pp)
struct ip_vs_protocol ip_vs_protocol_udp = {
.name = "UDP",
.protocol = IPPROTO_UDP,
.num_states = IP_VS_UDP_S_LAST,
.dont_defrag = 0,
.init = udp_init,
.exit = udp_exit,

View File

@ -288,11 +288,16 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
char *p;
int i;
if (buflen < sizeof(struct ip_vs_sync_mesg)) {
IP_VS_ERR_RL("sync message header too short\n");
return;
}
/* Convert size back to host byte order */
m->size = ntohs(m->size);
if (buflen != m->size) {
IP_VS_ERR("bogus message\n");
IP_VS_ERR_RL("bogus sync message size\n");
return;
}
@ -307,9 +312,48 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
for (i=0; i<m->nr_conns; i++) {
unsigned flags, state;
s = (struct ip_vs_sync_conn *)p;
if (p + SIMPLE_CONN_SIZE > buffer+buflen) {
IP_VS_ERR_RL("bogus conn in sync message\n");
return;
}
s = (struct ip_vs_sync_conn *) p;
flags = ntohs(s->flags) | IP_VS_CONN_F_SYNC;
flags &= ~IP_VS_CONN_F_HASHED;
if (flags & IP_VS_CONN_F_SEQ_MASK) {
opt = (struct ip_vs_sync_conn_options *)&s[1];
p += FULL_CONN_SIZE;
if (p > buffer+buflen) {
IP_VS_ERR_RL("bogus conn options in sync message\n");
return;
}
} else {
opt = NULL;
p += SIMPLE_CONN_SIZE;
}
state = ntohs(s->state);
if (!(flags & IP_VS_CONN_F_TEMPLATE)) {
pp = ip_vs_proto_get(s->protocol);
if (!pp) {
IP_VS_ERR_RL("Unsupported protocol %u in sync msg\n",
s->protocol);
continue;
}
if (state >= pp->num_states) {
IP_VS_DBG(2, "Invalid %s state %u in sync msg\n",
pp->name, state);
continue;
}
} else {
/* protocol in templates is not used for state/timeout */
pp = NULL;
if (state > 0) {
IP_VS_DBG(2, "Invalid template state %u in sync msg\n",
state);
state = 0;
}
}
if (!(flags & IP_VS_CONN_F_TEMPLATE))
cp = ip_vs_conn_in_get(s->protocol,
s->caddr, s->cport,
@ -345,14 +389,9 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
IP_VS_ERR("ip_vs_conn_new failed\n");
return;
}
cp->state = state;
} else if (!cp->dest) {
dest = ip_vs_try_bind_dest(cp);
if (!dest) {
/* it is an unbound entry created by
* synchronization */
cp->flags = flags | IP_VS_CONN_F_HASHED;
} else
if (dest)
atomic_dec(&dest->refcnt);
} else if ((cp->dest) && (cp->protocol == IPPROTO_TCP) &&
(cp->state != state)) {
@ -371,23 +410,22 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen)
}
}
if (flags & IP_VS_CONN_F_SEQ_MASK) {
opt = (struct ip_vs_sync_conn_options *)&s[1];
if (opt)
memcpy(&cp->in_seq, opt, sizeof(*opt));
p += FULL_CONN_SIZE;
} else
p += SIMPLE_CONN_SIZE;
atomic_set(&cp->in_pkts, sysctl_ip_vs_sync_threshold[0]);
cp->state = state;
pp = ip_vs_proto_get(s->protocol);
cp->timeout = pp->timeout_table[cp->state];
cp->old_state = cp->state;
/*
* We can not recover the right timeout for templates
* in all cases, we can not find the right fwmark
* virtual service. If needed, we can do it for
* non-fwmark persistent services.
*/
if (!(flags & IP_VS_CONN_F_TEMPLATE) && pp->timeout_table)
cp->timeout = pp->timeout_table[state];
else
cp->timeout = (3*60*HZ);
ip_vs_conn_put(cp);
if (p > buffer+buflen) {
IP_VS_ERR("bogus message\n");
return;
}
}
}

View File

@ -296,9 +296,8 @@ ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct nf_queue_entry *e)
if (v->data_len > 0xFFFF)
return -EINVAL;
if (diff > skb_tailroom(e->skb)) {
nskb = skb_copy_expand(e->skb, 0,
diff - skb_tailroom(e->skb),
GFP_ATOMIC);
nskb = skb_copy_expand(e->skb, skb_headroom(e->skb),
diff, GFP_ATOMIC);
if (!nskb) {
printk(KERN_WARNING "ip_queue: error "
"in mangle, dropping packet\n");

View File

@ -303,7 +303,7 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len)
const struct nf_conntrack_tuple_hash *h;
struct nf_conntrack_tuple tuple;
NF_CT_TUPLE_U_BLANK(&tuple);
memset(&tuple, 0, sizeof(tuple));
tuple.src.u3.ip = inet->rcv_saddr;
tuple.src.u.tcp.port = inet->sport;
tuple.dst.u3.ip = inet->daddr;

View File

@ -1430,11 +1430,13 @@ static inline unsigned short guess_mtu(unsigned short old_mtu)
}
unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
unsigned short new_mtu)
unsigned short new_mtu,
struct net_device *dev)
{
int i;
int i, k;
unsigned short old_mtu = ntohs(iph->tot_len);
struct rtable *rth;
int ikeys[2] = { dev->ifindex, 0 };
__be32 skeys[2] = { iph->saddr, 0, };
__be32 daddr = iph->daddr;
unsigned short est_mtu = 0;
@ -1442,22 +1444,26 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
if (ipv4_config.no_pmtu_disc)
return 0;
for (i = 0; i < 2; i++) {
unsigned hash = rt_hash(daddr, skeys[i], 0);
for (k = 0; k < 2; k++) {
for (i = 0; i < 2; i++) {
unsigned hash = rt_hash(daddr, skeys[i], ikeys[k]);
rcu_read_lock();
for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
rth = rcu_dereference(rth->u.dst.rt_next)) {
if (rth->fl.fl4_dst == daddr &&
rth->fl.fl4_src == skeys[i] &&
rth->rt_dst == daddr &&
rth->rt_src == iph->saddr &&
rth->fl.iif == 0 &&
!(dst_metric_locked(&rth->u.dst, RTAX_MTU)) &&
net_eq(dev_net(rth->u.dst.dev), net) &&
rth->rt_genid == atomic_read(&rt_genid)) {
rcu_read_lock();
for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
rth = rcu_dereference(rth->u.dst.rt_next)) {
unsigned short mtu = new_mtu;
if (rth->fl.fl4_dst != daddr ||
rth->fl.fl4_src != skeys[i] ||
rth->rt_dst != daddr ||
rth->rt_src != iph->saddr ||
rth->fl.oif != ikeys[k] ||
rth->fl.iif != 0 ||
dst_metric_locked(&rth->u.dst, RTAX_MTU) ||
!net_eq(dev_net(rth->u.dst.dev), net) ||
rth->rt_genid != atomic_read(&rt_genid))
continue;
if (new_mtu < 68 || new_mtu >= old_mtu) {
/* BSD 4.2 compatibility hack :-( */
@ -1483,8 +1489,8 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
est_mtu = mtu;
}
}
rcu_read_unlock();
}
rcu_read_unlock();
}
return est_mtu ? : new_mtu;
}

View File

@ -285,14 +285,12 @@ int tcp_is_cwnd_limited(const struct sock *sk, u32 in_flight)
if (in_flight >= tp->snd_cwnd)
return 1;
if (!sk_can_gso(sk))
return 0;
left = tp->snd_cwnd - in_flight;
if (sysctl_tcp_tso_win_divisor)
return left * sysctl_tcp_tso_win_divisor < tp->snd_cwnd;
else
return left <= tcp_max_burst(tp);
if (sk_can_gso(sk) &&
left * sysctl_tcp_tso_win_divisor < tp->snd_cwnd &&
left * tp->mss_cache < sk->sk_gso_max_size)
return 1;
return left <= tcp_max_burst(tp);
}
EXPORT_SYMBOL_GPL(tcp_is_cwnd_limited);

View File

@ -229,7 +229,8 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
*/
tcp_reno_cong_avoid(sk, ack, in_flight);
} else {
u32 rtt, target_cwnd, diff;
u32 rtt, diff;
u64 target_cwnd;
/* We have enough RTT samples, so, using the Vegas
* algorithm, we determine if we should increase or
@ -252,8 +253,9 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
* We keep it as a fixed point number with
* V_PARAM_SHIFT bits to the right of the binary point.
*/
target_cwnd = ((old_wnd * vegas->baseRTT)
<< V_PARAM_SHIFT) / rtt;
target_cwnd = ((u64)old_wnd * vegas->baseRTT);
target_cwnd <<= V_PARAM_SHIFT;
do_div(target_cwnd, rtt);
/* Calculate the difference between the window we had,
* and the window we would like to have. This quantity
@ -279,7 +281,7 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
* utilization.
*/
tp->snd_cwnd = min(tp->snd_cwnd,
(target_cwnd >>
((u32)target_cwnd >>
V_PARAM_SHIFT)+1);
} else if (tp->snd_cwnd <= tp->snd_ssthresh) {

View File

@ -133,7 +133,8 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
*/
tcp_reno_cong_avoid(sk, ack, in_flight);
} else {
u32 rtt, target_cwnd;
u64 target_cwnd;
u32 rtt;
/* We have enough rtt samples, so, using the Veno
* algorithm, we determine the state of the network.
@ -141,8 +142,9 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
rtt = veno->minrtt;
target_cwnd = ((tp->snd_cwnd * veno->basertt)
<< V_PARAM_SHIFT) / rtt;
target_cwnd = (tp->snd_cwnd * veno->basertt);
target_cwnd <<= V_PARAM_SHIFT;
do_div(target_cwnd, rtt);
veno->diff = (tp->snd_cwnd << V_PARAM_SHIFT) - target_cwnd;

View File

@ -1089,6 +1089,10 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname,
if(level != SOL_IPV6)
return -ENOPROTOOPT;
if (optname == MCAST_MSFILTER)
return compat_mc_getsockopt(sk, level, optname, optval, optlen,
ipv6_getsockopt);
err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */

View File

@ -298,9 +298,8 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct nf_queue_entry *e)
if (v->data_len > 0xFFFF)
return -EINVAL;
if (diff > skb_tailroom(e->skb)) {
nskb = skb_copy_expand(e->skb, 0,
diff - skb_tailroom(e->skb),
GFP_ATOMIC);
nskb = skb_copy_expand(e->skb, skb_headroom(e->skb),
diff, GFP_ATOMIC);
if (!nskb) {
printk(KERN_WARNING "ip6_queue: OOM "
"in mangle, dropping packet\n");

View File

@ -104,7 +104,7 @@ nf_ct_get_tuple(const struct sk_buff *skb,
const struct nf_conntrack_l3proto *l3proto,
const struct nf_conntrack_l4proto *l4proto)
{
NF_CT_TUPLE_U_BLANK(tuple);
memset(tuple, 0, sizeof(*tuple));
tuple->src.l3num = l3num;
if (l3proto->pkt_to_tuple(skb, nhoff, tuple) == 0)
@ -151,7 +151,7 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
const struct nf_conntrack_l3proto *l3proto,
const struct nf_conntrack_l4proto *l4proto)
{
NF_CT_TUPLE_U_BLANK(inverse);
memset(inverse, 0, sizeof(*inverse));
inverse->src.l3num = orig->src.l3num;
if (l3proto->invert_tuple(inverse, orig) == 0)

View File

@ -454,9 +454,8 @@ nfqnl_mangle(void *data, int data_len, struct nf_queue_entry *e)
if (data_len > 0xFFFF)
return -EINVAL;
if (diff > skb_tailroom(e->skb)) {
nskb = skb_copy_expand(e->skb, 0,
diff - skb_tailroom(e->skb),
GFP_ATOMIC);
nskb = skb_copy_expand(e->skb, skb_headroom(e->skb),
diff, GFP_ATOMIC);
if (!nskb) {
printk(KERN_WARNING "nf_queue: OOM "
"in mangle, dropping packet\n");

Some files were not shown because too many files have changed in this diff Show More